-
Notifications
You must be signed in to change notification settings - Fork 106
Add lucide icons to avatar #2266
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
base: v12
Are you sure you want to change the base?
Conversation
|
e4f70ef to
44fece3
Compare
8b5e111 to
1c11f12
Compare
1c11f12 to
f75d05f
Compare
| <Avatar size="large" color="ai" name="AI Assistant" renderIcon={IconAiSolid} /> | ||
| <Avatar size="x-large" color="ai" name="AI Assistant" renderIcon={IconAiSolid} /> | ||
| <Avatar size="xx-large" color="ai" name="AI Assistant" renderIcon={IconAiSolid} /> | ||
| <Avatar size="xx-small" color="ai" name="AI Assistant" renderIcon={IconAiSolid} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has to be replaced later to the appropriate Lucide equivalent icon. (Alex is still working on the mapping)
f75d05f to
2bc3b92
Compare
matyasf
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see my comments
|
@matyasf I answered the comments and did changes where they were needed, please check the PR again. |
e7c9af6 to
52e6819
Compare
| color: iconColor | ||
| }) | ||
| return ( | ||
| <IconPropsProvider size={iconSize} color={iconColor}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed renderLucideIconWithProps since it was too complex to understand and added IconPropsProvider instead. Lucide icons consume size and color through it.
This works with all the wanted patterns:
renderIcon={AlarmClockInstUIIcon}
renderIcon={<AlarmClockInstUIIcon />}
renderIcon={()=><AlarmClockInstUIIcon />}
| * When using Lucide icons, Avatar will automatically pass the appropriate size and color props based on the Avatar's size and color. | ||
| */ | ||
| renderIcon?: Renderable<{ size?: string | number; color?: string }> | ||
| renderIcon?: Renderable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed unnecessarily complex typing
| const contextProps = useIconProps() | ||
|
|
||
| // Merge props: direct props take precedence over context props | ||
| const finalSize = size ?? contextProps?.size |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Followed the React best practice here, component props always override context values by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general I would agree, but this code design explicitly wants to force props if applicable. For example we don't want to have misconfigured Avatars with incorrects sizes or colors. I'd default to context here and if the need arises, we could have a prop like "forceSize" or something later
| */ | ||
|
|
||
| import React from 'react' | ||
| import type { IconPropsContextValue } from './IconPropsProvider' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I followed the same file structuring I saw with DeterministicIdProvider
52e6819 to
8aae67a
Compare
| | 'inverseColor' | ||
| | 'disabledBaseColor' | ||
| | 'disabledOnColor' | ||
| | 'dark' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Designers confirmed that dark is a valid color, they will use it in the future.
8aae67a to
543b72a
Compare
| import { IconPropsProvider, useIconProps } from '../IconPropsProvider' | ||
|
|
||
| // Test component that exposes context values | ||
| const TestComponentWithHook = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mocks are perfectly valid here, since these are unit tests.
matyasf
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks much better now! see my comments
| /** | ||
| * Icon theme color token or CSS color value | ||
| */ | ||
| color?: 'inherit' | IconColorToken | string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The old icons use other values ('inherit', 'primary', 'secondary',... How do we handle the migration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add these to the props too, ask for a mapping from design, and do it in the code in index.ts/styles.ts
| <code>color</code>: CSS color - e.g.,{' '} | ||
| <code>"currentColor"</code> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currentColor is not valid AFAIK, a better example would be successColor
| <code>"currentColor"</code> | ||
| </li> | ||
| <li> | ||
| <code>strokeWidth</code>: Number - e.g., <code>2</code> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a better example is sm
| </Heading> | ||
| <ul> | ||
| <li> | ||
| <code>size</code>: Number (pixels) - e.g., <code>24</code> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here a semantic example would be better
| > & | ||
| InstUIIconOwnProps & { | ||
| themeOverride?: ThemeOverrideValue | ||
| } & OtherHTMLAttributes<InstUIIconOwnProps> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here you could omit the props removed by passtroughProps, I think the syntax is `Omit<OtherHTMLAttributes, 'children', ...>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
e.g.
type LucideIconWrapperProps = Omit<LucideProps, 'size' | 'color' | 'strokeWidth' | 'rotate' | 'children' | 'style' | others> &
InstUIIconOwnProps & {
themeOverride?: ThemeOverrideValue
}
packages/ui-avatar/package.json
Outdated
| "@babel/runtime": "^7.27.6", | ||
| "@instructure/emotion": "workspace:*", | ||
| "@instructure/shared-types": "workspace:*", | ||
| "@instructure/ui-icons": "workspace:*", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is ui-icons still needed?
| size?: string | number | ||
| color?: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These have the same type as the props with the same name from wrapLucideIcon/props.ts I think. But in this case we will have to pull in the icons package as a dependency, which might create an impossible build graph... So it might be better to move these where the icons are, we will use them with icons anyway
…w plus add AI gradient coloring
27b73ca to
7e5aaeb
Compare
matyasf
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
I've found just one small visual bug: In the themeOverride prop example the examples are not aligned vertically.
According to AI its because "The children elements all have display: inline-flex and vertical-align: baseline. While they all have the same height (48px), vertical-align: baseline aligns the baselines of the elements. If there is text content or different line-height values within the inline-flex items, or if the parent div has a specific line-height or font-size that interacts with the baseline, it can cause vertical misalignment"
and the fix is pretty simple, just add verticalAlign:'middle to the avatar CSS class
HerrTopi
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comments. After fixing them, I'd go through it again to check new logic.
I think for the big changes, design needs to be brought in to discuss
| const contextProps = useIconProps() | ||
|
|
||
| // Merge props: direct props take precedence over context props | ||
| const finalSize = size ?? contextProps?.size |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general I would agree, but this code design explicitly wants to force props if applicable. For example we don't want to have misconfigured Avatars with incorrects sizes or colors. I'd default to context here and if the need arises, we could have a prop like "forceSize" or something later
| } | ||
|
|
||
| const styles = useStyle({ | ||
| componentId: 'Icon' as const, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpic but this const doesn't do anything here, remove it please so it wont clutter the code
| params: { | ||
| size: semanticSize as InstUIIconOwnProps['size'], | ||
| color: colorValue, | ||
| size: finalSize as LucideIconWrapperProps['size'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cast isnt't needed
| color: colorValue, | ||
| size: finalSize as LucideIconWrapperProps['size'], | ||
| strokeWidth, | ||
| color: finalColor, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason behind displayName: LucideIcon(${Icon.displayName || Icon.name}) ` aremt't we sure that displayName (or name) will be available?
Line 83. For some reason I can't comment there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 86: const accessibilityProps: Record<string, string | boolean> = {}
| boolean is not needed
| ) | ||
| } | ||
|
|
||
| WrappedIcon.displayName = `wrapLucideIcon(${Icon.displayName || Icon.name})` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this displayname different from the one in line 83? It should be the same for consistency and theme override's sake
| return WrappedIcon | ||
| } | ||
|
|
||
| export type { LucideIconWrapperProps, InstUIIconOwnProps } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this part. Why re-export these from here? These are already exported from their respected files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same for export { default as generateStyle } from './styles'
| | 'actionDestructiveSecondaryActiveColor' | ||
|
|
||
| type InstUIIconOwnProps = { | ||
| /** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I can't comment on unchanged parts, but:
StorkeWidth is a not allowed prop, all stroke width have to be calculated from size and are not changable.
Size van not be number, only the preset tokens.
Same for color. No inherit, no string, only the presets
Ask about these from desing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calculations and logic are tied to these things in styles.ts, so I won'r review it in depth because it needs to be drastically changed before.
Closes INSTUI-4864
Test:
Try all these icon adding options with Avatar and check whether size and color passed to the icon correctly. Also check how changing theme impact the rendered component.