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

chore: Expandable component style refactor #3128

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9883acf
chore(ExpandableTarget): Style refactoring for new tokens
Jan 22, 2025
e8ce2c5
chore(Expandable): Style refactoring
Jan 23, 2025
8ce91e5
chore(ExpandableTarget): Cleanup style refactor
Jan 23, 2025
4a3c277
chore(ExpandableTitle): Style refactor
Jan 23, 2025
064ba46
fix(Avatar): ARIA roles and properties
Jan 23, 2025
3565dc2
chore(ExpandableAvatar): Style refactor
Jan 23, 2025
eda5718
chore(ExpandableContent): Style refactor
Jan 24, 2025
146c618
fix: Removing Box component from return statement
Jan 24, 2025
11b04ff
chore(ExpandableIcon): Creating new compound stencil
Feb 6, 2025
06bb04c
Merge remote-tracking branch 'upstream/master' into william-issue-295…
Feb 6, 2025
1d39ec8
chore(ExpandableIcon): Style token refactor
Feb 8, 2025
bc8fde2
Merge remote-tracking branch 'upstream/master' into william-issue-295…
Feb 8, 2025
c920f16
chore(ExpandableIcon): Fixing type errors
Feb 9, 2025
77df747
chore(ExpandableTarget): Removed import for base tokens
Feb 10, 2025
9432308
fix(ExpandableIcon): Fixing styles for RTL support
williamjstanton Mar 2, 2025
3bede3f
fix: Extending avatarStencil in ExpandableAvatar
Mar 2, 2025
4f91a29
Merge branch 'william-issue-2954-expandable-style-refactor' of https:…
Mar 2, 2025
afbd10b
fix: Update merge conflicts and remove gap
Mar 4, 2025
4bb2f4b
fix: Add info to ugprade guide
Mar 4, 2025
1de0587
fix: Update cursor and remove extra element
Mar 4, 2025
7419eb6
fix: Remove extra import
Mar 4, 2025
da44a62
Merge branch 'prerelease/major' into william-issue-2954-expandable-st…
mannycarrera4 Mar 4, 2025
8694202
fix: Ensure class names
Mar 4, 2025
1a7e2b1
fix(ExpandableAvatar): Replace marginRight with marginInlineEnd
williamjstanton Mar 7, 2025
9b0cf6b
fix: Remove border width
Mar 10, 2025
bab4eda
fix: Update rotation based on content direction
Mar 10, 2025
4ea7038
fix: Update and fix types in stencil
Mar 10, 2025
4a4ad0c
fix: Update merge conflicts
Mar 10, 2025
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
5 changes: 3 additions & 2 deletions modules/docs/mdx/13.0-UPGRADE-GUIDE.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ yarn remove @workday/canvas-kit-codemod

### Styling API and CSS Tokens

**PRs:** [#3101](https://github.com/Workday/canvas-kit/pull/3101), [#3088](https://github.com/Workday/canvas-kit/pull/3088), [#3114](https://github.com/Workday/canvas-kit/pull/3114), [#3119](https://github.com/Workday/canvas-kit/pull/3119), [#3120](https://github.com/Workday/canvas-kit/pull/3120), [#3164](https://github.com/Workday/canvas-kit/pull/3164)
**PRs:** [#3101](https://github.com/Workday/canvas-kit/pull/3101), [#3088](https://github.com/Workday/canvas-kit/pull/3088), [#3114](https://github.com/Workday/canvas-kit/pull/3114), [#3119](https://github.com/Workday/canvas-kit/pull/3119), [#3120](https://github.com/Workday/canvas-kit/pull/3120), [#3164](https://github.com/Workday/canvas-kit/pull/3164), [#3128](https://github.com/Workday/canvas-kit/pull/3128)

Several components have been refactored to use our
[Canvas Tokens](https://workday.github.io/canvas-tokens/?path=/docs/docs-getting-started--docs) and
Expand All @@ -106,6 +106,7 @@ The React interface **has not changed**, but CSS variables are now used for dyna

The following components are affected:

- `Expandable`
- `ExternalHyperlink`
- `LoadingSparkles`
- `Menu`
Expand Down Expand Up @@ -135,7 +136,7 @@ The following components are affected:

**PR:** [#3119](https://github.com/Workday/canvas-kit/pull/3119)

- The `disabled` icon color has been updated to use `system.color.fg.disabled`. This has made the icon darker for better contrast.
- The `disabled` icon color has been updated to use `system.color.fg.disabled`. This has made the icon darker for better contrast.

**Note:** There should be no developer impact and the visual changes are safe to accept.

Expand Down
17 changes: 13 additions & 4 deletions modules/labs-react/expandable/lib/Expandable.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react';

import {createContainer, ExtractProps} from '@workday/canvas-kit-react/common';
import {Flex} from '@workday/canvas-kit-react/layout';
import {Flex, mergeStyles} from '@workday/canvas-kit-react/layout';

import {ExpandableContent} from './ExpandableContent';
import {ExpandableTarget} from './ExpandableTarget';
import {ExpandableIcon} from './ExpandableIcon';
import {ExpandableTitle} from './ExpandableTitle';
import {ExpandableAvatar} from './ExpandableAvatar';
import {useExpandableModel} from './hooks/useExpandableModel';
import {createStencil} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';

export interface ExpandableProps extends ExtractProps<typeof Flex, never> {
/**
Expand All @@ -18,11 +20,20 @@ export interface ExpandableProps extends ExtractProps<typeof Flex, never> {
children?: React.ReactNode;
}

export const expandableContainerStencil = createStencil({
base: {
display: 'flex',
flexDirection: 'column',
padding: system.space.x2,
},
});

/**
* `Expandable` wraps an `Expandable.Target` and an `Expandable.Content`. By default, it provides a
* `DisclosureModel` for its subcomponents. Alternatively, a model may be passed in using the
* hoisted model pattern.
*/

export const Expandable = createContainer('div')({
displayName: 'Expandable',
modelHook: useExpandableModel,
Expand Down Expand Up @@ -62,7 +73,5 @@ export const Expandable = createContainer('div')({
Content: ExpandableContent,
},
})<ExpandableProps>(({children, ...elementProps}, Element) => (
<Flex as={Element} flexDirection={'column'} padding={'xxs'} {...elementProps}>
{children}
</Flex>
<Element {...mergeStyles(elementProps, expandableContainerStencil())}>{children}</Element>
));
20 changes: 12 additions & 8 deletions modules/labs-react/expandable/lib/ExpandableAvatar.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
import React from 'react';

import {createComponent} from '@workday/canvas-kit-react/common';
import {Avatar, AvatarProps} from '@workday/canvas-kit-react/avatar';
import {Avatar, AvatarProps, avatarStencil} from '@workday/canvas-kit-react/avatar';
import {system} from '@workday/canvas-tokens-web';
import {createStyles} from '@workday/canvas-kit-styling';
import {createStencil} from '@workday/canvas-kit-styling';
import {mergeStyles} from '@workday/canvas-kit-react/layout';

export interface ExpandableAvatarProps extends AvatarProps {}

const expandableAvatarStyles = createStyles({
marginRight: system.space.x2,
flexShrink: 0,
export const expandableAvatarStencil = createStencil({
extends: avatarStencil,
base: {
marginInlineEnd: system.space.x2,
flexShrink: 0,
},
});

// When the component is created, it needs to be a button element to match AvatarProps.
// Once Avatar becomes a `createComponent` we can default the element type to a `div`
// and the types should be properly extracted
// Setting altText prop to a default empty string for decorative purposes
export const ExpandableAvatar = createComponent('div')({
displayName: 'Expandable.Avatar',
Component: ({altText, ...elemProps}: ExpandableAvatarProps, ref, Element) => {
Component: ({altText = '', ...elemProps}: ExpandableAvatarProps, ref, Element) => {
return (
<Avatar
cs={expandableAvatarStyles}
as={Element}
altText={altText}
ref={ref}
size="medium"
{...elemProps}
{...mergeStyles(elemProps, expandableAvatarStencil())}
/>
);
},
Expand Down
23 changes: 11 additions & 12 deletions modules/labs-react/expandable/lib/ExpandableContent.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from 'react';

import {space} from '@workday/canvas-kit-react/tokens';
import {createSubcomponent, ExtractProps} from '@workday/canvas-kit-react/common';
import {Box} from '@workday/canvas-kit-react/layout';
import {Box, mergeStyles} from '@workday/canvas-kit-react/layout';

import {useExpandableContent} from './hooks/useExpandableContent';
import {useExpandableModel} from './hooks/useExpandableModel';
import {createStencil} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';

export interface ExpandableContentProps extends ExtractProps<typeof Box, never> {
/**
Expand All @@ -15,18 +16,16 @@ export interface ExpandableContentProps extends ExtractProps<typeof Box, never>
children?: React.ReactNode;
}

export const expandableContentStencil = createStencil({
base: {
background: system.color.bg.transparent,
padding: `${system.space.x4} ${system.space.x2} ${system.space.x2}`,
},
});

export const ExpandableContent = createSubcomponent('div')({
modelHook: useExpandableModel,
elemPropsHook: useExpandableContent,
})<ExpandableContentProps>(({children, ...elementProps}, Element) => {
return (
<Box
as={Element}
background="none"
padding={`${space.s} ${space.xxs} ${space.xxs}`}
{...elementProps}
>
{children}
</Box>
);
return <Element {...mergeStyles(elementProps, expandableContentStencil())}>{children}</Element>;
});
114 changes: 64 additions & 50 deletions modules/labs-react/expandable/lib/ExpandableIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
import React from 'react';

import {
createSubcomponent,
ExtractProps,
filterOutProps,
styled,
StyledType,
} from '@workday/canvas-kit-react/common';
import {chevronUpIcon, chevronDownIcon} from '@workday/canvas-system-icons-web';
import {createSubcomponent, ExtractProps} from '@workday/canvas-kit-react/common';
import {chevronUpIcon} from '@workday/canvas-system-icons-web';
import {CanvasSystemIcon} from '@workday/design-assets-types';
import {useExpandableIcon} from './hooks/useExpandableIcon';
import {SystemIcon} from '@workday/canvas-kit-react/icon';
import {SystemIcon, systemIconStencil} from '@workday/canvas-kit-react/icon';
import {IconPositions} from '@workday/canvas-kit-react/button';
import {colors, space} from '@workday/canvas-kit-react/tokens';

import {useExpandableModel} from './hooks/useExpandableModel';
import {createStencil} from '@workday/canvas-kit-styling';
import {mergeStyles} from '@workday/canvas-kit-react/layout';
import {system} from '@workday/canvas-tokens-web';

export interface ExpandableIconProps extends Omit<ExtractProps<typeof SystemIcon, never>, 'icon'> {
/**
Expand All @@ -30,51 +25,70 @@ export interface ExpandableIconProps extends Omit<ExtractProps<typeof SystemIcon
iconPosition?: IconPositions;
}

const StyledEndIcon = styled(SystemIcon, {
shouldForwardProp: filterOutProps(['visible']),
})<{visible: boolean} & StyledType>(
{
marginLeft: 'auto',
export const expandableIconStencil = createStencil({
extends: systemIconStencil,
base: {
padding: system.space.x1,
},
({visible}) => ({
transform: !visible ? 'rotate(-180deg)' : undefined,
padding: !visible
? `${space.xxxs} ${space.xs} ${space.xxxs} ${space.xxxs}`
: `${space.xxxs} ${space.xxxs} ${space.xxxs} ${space.xs}`,
})
);

const StyledStartIcon = styled(SystemIcon, {
shouldForwardProp: filterOutProps(['visible']),
})<{visible: boolean} & StyledType>(
{
margin: `0 ${space.xxs} 0 0`,
padding: space.xxxs,
modifiers: {
isExpanded: {
true: {},
false: {},
},
position: {
start: {},
end: {},
only: {},
},
},
({visible}) => ({
transform: !visible ? 'rotate(-90deg)' : undefined,
})
);
compound: [
{
modifiers: {position: 'end', isExpanded: false},
styles: {
marginInlineStart: 'auto',
transform: 'rotate(180deg)',
paddingInlineEnd: system.space.x3,
},
},
{
modifiers: {position: 'end', isExpanded: true},
styles: {
marginInlineStart: 'auto',
paddingInlineStart: system.space.x3,
},
},
{
modifiers: {position: 'start', isExpanded: false},
styles: {
marginInlineEnd: system.space.x2,
transform: 'rotate(90deg)',
':dir(rtl)': {
transform: 'rotate(-90deg)',
},
},
},
{
modifiers: {position: 'start', isExpanded: true},
styles: {
marginInlineEnd: system.space.x2,
transform: 'rotate(180deg)',
},
},
],
});

export const ExpandableIcon = createSubcomponent('span')({
modelHook: useExpandableModel,
elemPropsHook: useExpandableIcon,
})<ExpandableIconProps>(({icon, visible, iconPosition = 'start', ...elementProps}, Element) =>
iconPosition === 'end' ? (
<StyledEndIcon
})<ExpandableIconProps>(({icon, visible, iconPosition = 'start', ...elementProps}, Element) => {
return (
<SystemIcon
as={Element}
fill={colors.licorice200}
icon={icon || chevronUpIcon}
visible={visible}
{...elementProps}
/>
) : (
<StyledStartIcon
as={Element}
fill={colors.licorice200}
icon={icon || chevronDownIcon}
visible={visible}
{...elementProps}
{...mergeStyles(
elementProps,
expandableIconStencil({position: iconPosition, isExpanded: visible})
)}
/>
)
);
);
});
63 changes: 29 additions & 34 deletions modules/labs-react/expandable/lib/ExpandableTarget.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import React from 'react';

import {
createSubcomponent,
ExtractProps,
focusRing,
styled,
StyledType,
} from '@workday/canvas-kit-react/common';
import {Flex} from '@workday/canvas-kit-react/layout';
import {colors} from '@workday/canvas-kit-react/tokens';

import {createSubcomponent, ExtractProps} from '@workday/canvas-kit-react/common';
import {Flex, mergeStyles} from '@workday/canvas-kit-react/layout';
import {Heading} from '@workday/canvas-kit-react/text';
import {createStencil} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';
import {useExpandableTarget} from './hooks/useExpandableTarget';
import {useExpandableModel} from './hooks/useExpandableModel';

Expand All @@ -28,38 +23,38 @@ export interface ExpandableTargetProps extends ExtractProps<typeof Flex, never>
headingLevel?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
}

const StyledButton = styled(Flex.as('button'))<StyledType>({
cursor: 'pointer',
'&:focus-visible, &.focus': {
...focusRing(),
},
'&:hover': {
background: colors.soap300,
export const expandableTargetStencil = createStencil({
base: {
background: system.color.bg.transparent,
borderColor: system.color.bg.transparent,
borderRadius: system.shape.x1,
borderWidth: 0,
display: 'flex',
alignItems: 'flex-start',
flexDirection: 'row',
justifyContent: 'start',
padding: system.space.x2,
cursor: 'pointer',
width: '100%',
'&:hover, &.hover': {
backgroundColor: system.color.bg.alt.default,
},
},
});

const Heading = styled('h1')<StyledType>({
margin: 0,
});

export const ExpandableTarget = createSubcomponent('button')({
modelHook: useExpandableModel,
elemPropsHook: useExpandableTarget,
})<ExpandableTargetProps>(({children, headingLevel, ...elementProps}, Element) => {
const button = (
<StyledButton
as={Element}
background="none"
border="none"
borderRadius="m"
flexDirection="row"
padding="xxs"
width="100%"
{...elementProps}
>
{children}
</StyledButton>
<Element {...mergeStyles(elementProps, expandableTargetStencil())}>{children}</Element>
);

return !!headingLevel ? <Heading as={headingLevel}>{button}</Heading> : button;
return headingLevel ? (
<Heading size="small" as={headingLevel} margin="0">
{button}
</Heading>
) : (
button
);
});
Loading
Loading