Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PLAY-1627] Fix Height Prop for HtmlOptions Support #3873

Merged
merged 20 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions playbook/app/pb_kits/playbook/pb_card/_card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { get } from 'lodash'
import classnames from 'classnames'

import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
import { GlobalProps, globalProps } from '../utilities/globalProps'
import { GlobalProps, globalProps, globalInlineProps } from '../utilities/globalProps'
import type { ProductColors, CategoryColors, BackgroundColors } from '../types/colors'

import Icon from '../pb_icon/_icon'
Expand Down Expand Up @@ -49,6 +49,7 @@ type CardBodyProps = {
padding?: string,
} & GlobalProps


// Header component
const Header = (props: CardHeaderProps) => {
const { children, className, headerColor = 'category_1', headerColorStriped = false } = props
Expand Down Expand Up @@ -107,6 +108,10 @@ const Card = (props: CardPropTypes): React.ReactElement => {

// coerce to array
const cardChildren = React.Children.toArray(children)
const dynamicInlineProps = globalInlineProps(props);
const { style: htmlStyle = {}, ...restHtmlProps } = htmlProps as { style?: React.CSSProperties };
const mergedStyles: React.CSSProperties = { ...htmlStyle, ...dynamicInlineProps };


const subComponentTags = (tagName: string) => {
return cardChildren.filter((c: string) => (
Expand All @@ -122,7 +127,7 @@ const Card = (props: CardPropTypes): React.ReactElement => {

const tagOptions = ['div', 'section', 'footer', 'header', 'article', 'aside', 'main', 'nav']
const Tag = tagOptions.includes(tag) ? tag : 'div'

return (
<>
{
Expand All @@ -133,8 +138,9 @@ const Card = (props: CardPropTypes): React.ReactElement => {
<Tag
{...ariaProps}
{...dataProps}
{...htmlProps}
className={classnames(cardCss, globalProps(props), className)}
{...restHtmlProps}
style={mergedStyles}
>
{subComponentTags('Header')}
{
Expand All @@ -161,8 +167,9 @@ const Card = (props: CardPropTypes): React.ReactElement => {
<Tag
{...ariaProps}
{...dataProps}
{...htmlProps}
className={classnames(cardCss, globalProps(props), className)}
{...restHtmlProps}
style={mergedStyles}
>
{subComponentTags('Header')}
{nonHeaderChildren}
Expand Down
6 changes: 5 additions & 1 deletion playbook/app/pb_kits/playbook/pb_dialog/_dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import classnames from "classnames";
import Modal from "react-modal";

import { buildAriaProps, buildCss, buildDataProps, buildHtmlProps } from "../utilities/props";
import { globalProps } from "../utilities/globalProps";
import { globalProps, globalInlineProps } from "../utilities/globalProps";

import Body from "../pb_body/_body";
import Button from "../pb_button/_button";
Expand Down Expand Up @@ -91,6 +91,8 @@ const Dialog = (props: DialogProps): React.ReactElement => {
beforeClose: "pb_dialog_overlay_before_close",
};

const dynamicInlineProps = globalInlineProps(props);

const classes = classnames(
buildCss("pb_dialog_wrapper"),
globalProps(props),
Expand Down Expand Up @@ -184,6 +186,7 @@ const Dialog = (props: DialogProps): React.ReactElement => {
overlayClassName={overlayClassNames}
portalClassName={portalClassName}
shouldCloseOnOverlayClick={shouldCloseOnOverlayClick && !loading}
style={{ content: dynamicInlineProps }}
>
<>
{title && !status ? <Dialog.Header>{title}</Dialog.Header> : null}
Expand All @@ -192,6 +195,7 @@ const Dialog = (props: DialogProps): React.ReactElement => {
<Dialog.Body
className="dialog_status_text_align"
padding="md"

>
<Flex align="center"
orientation="column"
Expand Down
4 changes: 3 additions & 1 deletion playbook/app/pb_kits/playbook/pb_flex/_flex.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import classnames from 'classnames'
import { buildCss, buildDataProps, buildHtmlProps } from '../utilities/props'
import { GlobalProps, globalProps } from '../utilities/globalProps'
import { GlobalProps, globalProps, globalInlineProps } from '../utilities/globalProps'
import { GenericObject, Sizes } from '../types'

type FlexProps = {
Expand Down Expand Up @@ -61,6 +61,7 @@ const Flex = (props: FlexProps): React.ReactElement => {
const alignSelfClass = alignSelf !== 'none' ? `align_self_${alignSelf}` : ''
const dataProps = buildDataProps(data)
const htmlProps = buildHtmlProps(htmlOptions)
const dynamicInlineProps = globalInlineProps(props)


return (
Expand All @@ -83,6 +84,7 @@ const Flex = (props: FlexProps): React.ReactElement => {
globalProps(props),
className
)}
style={dynamicInlineProps}
{...dataProps}
{...htmlProps}
>
Expand Down
10 changes: 8 additions & 2 deletions playbook/app/pb_kits/playbook/pb_flex/_flex_item.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import classnames from 'classnames'
import { buildCss, buildHtmlProps } from '../utilities/props'
import { globalProps, GlobalProps } from '../utilities/globalProps'
import { globalProps, GlobalProps, globalInlineProps} from '../utilities/globalProps'
type FlexItemPropTypes = {
children: React.ReactNode[] | React.ReactNode,
fixedSize?: string,
Expand Down Expand Up @@ -35,14 +35,20 @@ const FlexItem = (props: FlexItemPropTypes): React.ReactElement => {
const fixedStyle =
fixedSize !== undefined ? { flexBasis: `${fixedSize}` } : null
const orderClass = order !== 'none' ? `order_${order}` : null
const dynamicInlineProps = globalInlineProps(props)
const combinedStyles = {
...fixedStyle,
...dynamicInlineProps
}

const htmlProps = buildHtmlProps(htmlOptions)


return (
<div
{...htmlProps}
className={classnames(buildCss('pb_flex_item_kit', growClass, shrinkClass, flexClass, displayFlexClass), orderClass, alignSelfClass, globalProps(props), className)}
style={fixedStyle}
style={combinedStyles}
>
{children}
</div>
Expand Down
9 changes: 3 additions & 6 deletions playbook/app/pb_kits/playbook/pb_flex/flex_item.html.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<%= content_tag(:div,
id: object.id,
data: object.data,
class: object.classname,
style: object.style_value,
**combined_html_options) do %>
<%= pb_content_tag(:div,
style: object.inline_styles
) do %>
<%= content.presence %>
<% end %>
9 changes: 7 additions & 2 deletions playbook/app/pb_kits/playbook/pb_flex/flex_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@ def classname
generate_classname("pb_flex_item_kit", fixed_size_class, grow_class, shrink_class, display_flex_class) + align_self_class
end

def style_value
"flex-basis: #{fixed_size};" if fixed_size.present?
def inline_styles
styles = []
styles << "flex-basis: #{fixed_size};" if fixed_size.present?
styles << "height: #{height};" if height.present?
styles << "min-height: #{min_height};" if min_height.present?
styles << "max-height: #{max_height};" if max_height.present?
styles.join(" ")
end

private
Expand Down
2 changes: 1 addition & 1 deletion playbook/app/pb_kits/playbook/pb_popover/_popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import classnames from "classnames";
import { globalProps, GlobalProps } from "../utilities/globalProps";
import { uniqueId } from 'lodash';

type ModifiedGlobalProps = Omit<GlobalProps, 'minWidth'>
type ModifiedGlobalProps = Omit<GlobalProps, 'minWidth' | 'maxHeight' | 'minHeight'>

type PbPopoverProps = {
aria?: { [key: string]: string };
Expand Down
3 changes: 3 additions & 0 deletions playbook/app/pb_kits/playbook/utilities/globalPropNames.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
export default [
"minHeight",
"maxHeight",
"height",
"left",
"bottom",
"right",
Expand Down
41 changes: 39 additions & 2 deletions playbook/app/pb_kits/playbook/utilities/globalProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,24 @@ type ZIndex = {
zIndex?: ZIndexType,
} | ZIndexResponsiveType

type Height = {
height?: string
}

type MaxHeight = {
maxHeight?: string
}

type MinHeight = {
minHeight?: string
}

// keep this as the last type definition
export type GlobalProps = AlignContent & AlignItems & AlignSelf &
BorderRadius & Cursor & Dark & Display & DisplaySizes & Flex & FlexDirection &
FlexGrow & FlexShrink & FlexWrap & JustifyContent & JustifySelf &
LineHeight & Margin & MinWidth & MaxWidth & NumberSpacing & Order & Overflow & Padding &
Position & Shadow & TextAlign & Truncate & VerticalAlign & ZIndex & GroupHover & { hover?: string } & Top & Right & Bottom & Left;
Position & Shadow & TextAlign & Truncate & VerticalAlign & ZIndex & { hover?: string } & Top & Right & Bottom & Left & Height & MaxHeight & MinHeight;

const getResponsivePropClasses = (prop: {[key: string]: string}, classPrefix: string) => {
const keys: string[] = Object.keys(prop)
Expand Down Expand Up @@ -503,7 +515,22 @@ const PROP_CATEGORIES: {[key:string]: (props: {[key: string]: any}) => string} =
} else {
return verticalAlign ? `vertical_align_${verticalAlign} ` : ''
}
}
},

}

const PROP_INLINE_CATEGORIES: {[key:string]: (props: {[key: string]: any}) => {[key: string]: any}} = {
heightProps: ({ height }: Height) => {
return height ? { height } : {};
},

maxHeightProps: ({ maxHeight }: MaxHeight) => {
return maxHeight ? { maxHeight } : {};
},

minHeightProps: ({ minHeight }: MinHeight) => {
return minHeight ? { minHeight } : {};
},
}

type DefaultProps = {[key: string]: string} | Record<string, unknown>
Expand All @@ -515,6 +542,16 @@ export const globalProps = (props: GlobalProps, defaultProps: DefaultProps = {})
}).filter((value) => value?.length > 0).join(" ")
}

// New function for inline styles
export const globalInlineProps = (props: GlobalProps): React.CSSProperties => {
const styles = Object.keys(PROP_INLINE_CATEGORIES).reduce((acc, key) => {
const result = PROP_INLINE_CATEGORIES[key](props);
return { ...acc, ...(typeof result === 'object' ? result : {}) }; // Ensure result is an object before spreading
}, {});

return styles; // Return the styles object directly
}


export const deprecatedProps = (): void => {
// if (process.env.NODE_ENV === 'development') {
Expand Down
48 changes: 43 additions & 5 deletions playbook/lib/playbook/kit_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ class KitBase < ViewComponent::Base
prop :aria, type: Playbook::Props::HashProp, default: {}
prop :html_options, type: Playbook::Props::HashProp, default: {}
prop :children, type: Playbook::Props::Proc
prop :style, type: Playbook::Props::HashProp, default: {}
prop :height
prop :min_height
prop :max_height

def object
self
end

def combined_html_options
default_html_options.merge(html_options.deep_merge(data_attributes))
end

# rubocop:disable Layout/CommentIndentation
# pb_content_tag information (potentially to be abstracted into its own dev doc in the future)
# The pb_content_tag generates HTML content tags for rails kits with flexible options.
Expand Down Expand Up @@ -110,15 +110,48 @@ def pb_content_tag(name = :div, content_or_options_with_block = {}, options = {}
end
# rubocop:enable Style/OptionalBooleanParameter

def combined_html_options
merged = default_html_options.dup

html_options.each do |key, value|
if key == :style && value.is_a?(Hash)
# Convert style hash to CSS string
merged[:style] = value.map { |k, v| "#{k.to_s.gsub('_', '-')}: #{v}" }.join("; ")
else
merged[key] = value
end
end

inline_styles = dynamic_inline_props
merged[:style] = if inline_styles.present?
merged[:style].present? ? "#{merged[:style]}; #{inline_styles}" : inline_styles
end

merged.deep_merge(data_attributes)
end

def global_inline_props
{
height: height,
min_height: min_height,
max_height: max_height,
}.compact
end

private

def default_options
{
options = {
id: id,
data: data,
class: classname,
aria: aria,
}

inline_styles = dynamic_inline_props
options[:style] = inline_styles if inline_styles.present? && !html_options.key?(:style)

options
end

def default_html_options
Expand All @@ -131,5 +164,10 @@ def data_attributes
aria: aria,
}.transform_keys { |key| key.to_s.tr("_", "-").to_sym }
end

def dynamic_inline_props
styles = global_inline_props.map { |key, value| "#{key.to_s.gsub('_', '-')}: #{value}" if value.present? }.compact
styles.join("; ").presence
end
end
end
Loading