Skip to content

feat(emotion,ui-scripts): resolve tokens studio color modifiers and emit hex#2626

Open
HerrTopi wants to merge 2 commits into
masterfrom
theming-touchups
Open

feat(emotion,ui-scripts): resolve tokens studio color modifiers and emit hex#2626
HerrTopi wants to merge 2 commits into
masterfrom
theming-touchups

Conversation

@HerrTopi

@HerrTopi HerrTopi commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Forward Tokens Studio color modifiers ($extensions.studio.tokens.modify) through the theme build scripts and resolve them at theme-apply time so semantic and component tokens can chain darken/lighten/alpha.

  • generateSemantics: emit the { value, modify } payload for semantic tokens and recurse into it in resolveReferences (drop the .value/.type guard that serialized the payload to "[object Object]").
  • generateComponents: only forward $extensions when studio.tokens.modify is present, so tokens carrying unrelated metadata no longer emit modify: undefined.
  • applyColorModifiers: serialize the resolved color to hex (#RRGGBBAA when alpha < 1, #RRGGBB otherwise) so modifier-derived values match every other token.
  • useComputedTheme/useStyleNew/withStyleNew: resolve modifiers on semantics before building component and shared tokens, so component-level modifiers chain on top of already-resolved semantic values; key component overrides by the component's own id rather than the token-source id.
  • Bump @instructure/instructure-design-tokens to v1.4.0.

🤖 Generated with Claude Code

@HerrTopi HerrTopi self-assigned this Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://instructure.design/pr-preview/pr-2626/

Built to branch gh-pages at 2026-07-09 15:17 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

github-actions Bot pushed a commit that referenced this pull request Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Visual regression report

⚠️ Changes detected.

Status Count
Unchanged 31
Changed 1
New 0
Removed 0

📊 View full report

Diff images (1)

button-and-derivatives.png — 440 pixels differ

Baselines come from the visual-baselines branch. They refresh on every merge to master.

@HerrTopi HerrTopi requested a review from ToMESSKa July 7, 2026 07:07
@ToMESSKa ToMESSKa requested review from ToMESSKa and joyenjoyer July 7, 2026 11:26

@ToMESSKa ToMESSKa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type of override does not not work unless you change both keys (Button and IconButton) to BaseButton, but that results in not being able to override the two components separately.

<InstUISettingsProvider
    themeOverride={{
      components: {
        Button: { primaryBackground: 'red', smallPaddingTop: '1px' },
        IconButton: { primaryBackground: 'blue', secondaryBackground: 'green' }
      }
    }}

  >
    <Button color="primary">x</Button>
  <IconButton color="primary">x</IconButton>
  </InstUISettingsProvider>

@ToMESSKa

ToMESSKa commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Also a similar example, this only works if both key is TreeBrowserTreeButton.

const renderNode = () => (
  <TreeBrowser.Node itemIcon={<IconPlusLine />}>More</TreeBrowser.Node>
)

const Example = () => (
  <InstUISettingsProvider
    themeOverride={{
      components: {
        'TreeBrowser.Button': { hoverBackgroundColor: 'red' },
        'TreeBrowser.Node': { hoverBackgroundColor: 'blue' }
      }
    }}
  >
    <TreeBrowser
      rootId={1}
      defaultExpanded={[1]}
      collections={{
        1: {
          id: 1,
          name: 'Assignments',
          collections: [],
          items: [1, 2],
          renderAfterItems: renderNode()
        }
      }}
      items={{
        1: { id: 1, name: 'Addition Worksheet' },
        2: { id: 2, name: 'Subtraction Worksheet' }
      }}
    />
  </InstUISettingsProvider>
)

render(<Example />)

Also in some cases the component key used in the InstUISettingsProvider changed:

v1 key v2 key
TreeBrowser.Collection TreeBrowserTreeCollection
ColorMixer.Palette Palette
ColorMixer.Slider Slider
ColorMixer.RGBAInput RgbaInput
TopNavBar.DesktopLayout TopNavBarLayout
TopNavBar.SmallViewportLayout TopNavBarLayout

For example here only the Palette key can be used instead of ColorMixer.Palette (v1). The question is: should my codemod I'm working on handle these key changes or should we change something in the InstUI code?

const Example = () => {
     const [value, setValue] = useState('#328826')

     return (
       <InstUISettingsProvider
         themeOverride={{
           components: {
             'Palette': {
               paletteBorderRadius: '1rem',
               paletteBorderWidth: '0.25rem'
             }
           }
         }}
       >
         <ColorMixer
           value={value}
           onChange={(value) => setValue(value)}
           rgbRedInputScreenReaderLabel="Input field for red"
           rgbGreenInputScreenReaderLabel="Input field for green"
           rgbBlueInputScreenReaderLabel="Input field for blue"
           rgbAlphaInputScreenReaderLabel="Input field for alpha"
           colorSliderNavigationExplanationScreenReaderLabel="Use arrow keys to adjust hue"
           alphaSliderNavigationExplanationScreenReaderLabel="Use arrow keys to adjust alpha"
           colorPaletteNavigationExplanationScreenReaderLabel="Use arrow keys to move the picker"
         />
       </InstUISettingsProvider>
     )
   }

   render(<Example />)

…mit hex

Forward Tokens Studio color modifiers (`$extensions.studio.tokens.modify`) through
the theme build scripts and resolve them at theme-apply time so semantic and
component tokens can chain darken/lighten/alpha.

- generateSemantics: emit the `{ value, modify }` payload for semantic tokens and
  recurse into it in resolveReferences (drop the `.value`/`.type` guard that
  serialized the payload to "[object Object]").
- generateComponents: only forward `$extensions` when `studio.tokens.modify` is
  present, so tokens carrying unrelated metadata no longer emit `modify: undefined`.
- applyColorModifiers: serialize the resolved color to hex (`#RRGGBBAA` when alpha
  < 1, `#RRGGBB` otherwise) so modifier-derived values match every other token.
- useComputedTheme/useStyleNew/withStyleNew: resolve modifiers on semantics before
  building component and shared tokens, so component-level modifiers chain on top
  of already-resolved semantic values; key component overrides by the component's
  own id rather than the token-source id.
- Bump @instructure/instructure-design-tokens to v1.4.0.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@HerrTopi HerrTopi force-pushed the theming-touchups branch from a17a4e0 to 699c2d8 Compare July 9, 2026 11:01
…component

Merge the SettingsProvider component overrides with the resolved
themeOverride prop and pass the result down as `themeOverride`, so nested
components receive the effective overrides. Default missing overrides to
an empty object to avoid merging undefined.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@HerrTopi HerrTopi force-pushed the theming-touchups branch from 699c2d8 to c6a0526 Compare July 9, 2026 15:13
@HerrTopi HerrTopi requested a review from ToMESSKa July 9, 2026 15:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants