Skip to content

generate frozen themes for a component version - #2708

Open
HerrTopi wants to merge 1 commit into
masterfrom
freeze
Open

HerrTopi wants to merge 1 commit into
masterfrom
freeze

Conversation

@HerrTopi

@HerrTopi HerrTopi commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

INSTUI-5188

Adds a generator that freezes theme tokens for one component version, so an older
version keeps rendering the same way while the shared semantics and
sharedTokens trees keep changing.

Run pnpm run build:frozen-themes. It prompts for the themes, package, component,
and version, then writes a frozenThemes folder into that component version.
Each file is narrowed to what the component actually reads — for Alert v2 that's
82 lines of semantics instead of 1600+.

What's in here.

  • ui-scripts: the build-frozen-themes command, the prompt, and the extraction
    itself — a recording proxy for the component's own token reads, plus a
    TypeScript AST pass for the sharedTokens reads in styles.ts.
  • emotion: useStyleNew and withStyleNew map a frozen theme's component
    onto newTheme.components[componentId], so a frozen component resolves its own
    tokens.
  • ui-avatar, ui-badge: wire Avatar v2 and Badge v2 to their frozen themes.
  • Docs: docs/contributing/frozen-themes.md.

Reads that can't be resolved at build time, such as sharedTokens[variant], throw
with the file, line, and column rather than silently dropping tokens.

Note: seTokensFrom is not handled currently.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

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

Built to branch gh-pages at 2026-09-11 12:39 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Visual regression report

Cypress suite: ✅ Passing

Visual diff: ⚠️ Changes detected.

Status Count
Unchanged 93
Changed 3
New 0
Removed 0

Accessibility (axe): ✅ No violations.

📊 View full report — click a screenshot's ⚠ badge to see each violation boxed on the image, with the offending element named and contrast failures shown as color swatches.

Diff images (3)

badge-canvas.png — 1573 pixels differ

tooltip-dark.png — 881 pixels differ

tooltip-light.png — 956 pixels differ

Baselines come from the visual-baselines branch. They refresh on every merge to master. The Cypress suite line covers the a11y and console-error assertions — a ❌ there means the suite found real issues even if the visual diff is clean.

github-actions Bot pushed a commit that referenced this pull request Sep 6, 2026
github-actions Bot pushed a commit that referenced this pull request Sep 7, 2026
github-actions Bot pushed a commit that referenced this pull request Sep 8, 2026
@HerrTopi
HerrTopi force-pushed the freeze branch 2 times, most recently from bd1d01a to f8b9b51 Compare September 10, 2026 14:58
@HerrTopi HerrTopi changed the title asd generate narrowed frozen themes for a component version Sep 10, 2026
@HerrTopi HerrTopi self-assigned this Sep 10, 2026
@HerrTopi
HerrTopi requested review from balzss and matyasf September 10, 2026 15:00
@HerrTopi HerrTopi changed the title generate narrowed frozen themes for a component version generate frozen themes for a component version Sep 10, 2026
@HerrTopi
HerrTopi force-pushed the freeze branch 3 times, most recently from b9a0642 to 29c4c87 Compare September 11, 2026 12:35
github-actions Bot pushed a commit that referenced this pull request Sep 11, 2026

@matyasf matyasf left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  • for theme lookup theme.key is used in withStyleNew and useStyleNew, but this writes canvasHighContrast, when it needs canvas-high-contrast

See my other comments

components: { [componentId]: frozenTheme[themeKey].component }
}
}
: themeInContext

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I would throw an error if useTokensFrom is used with frozenTheme, so we dont accidentally use it when its not implemented

Comment thread packages/emotion/src/withStyleNew.tsx Outdated
...frozenTheme[themeKey],
components: { [componentId]: frozenTheme[themeKey].component }
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I would throw an error if useTokensFrom is used with frozenTheme, so we dont accidentally use it when its not implemented

* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import promptThemeInput from './promptThemeInput.ts'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think this should be merged to this file, we're not extracting code in other commands either


const buildFrozenThemes = async (data: any) => {
for (let i = 0; i < data.themes.length; i++) {
const frozen = await resolveUsedThemeElements(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

As I see this code only extracts the top component from a multi-component package, isnt this an issue? e.g. I extracted Menu, and it failed to add semantic.color.background.interactive.action.tertiary.hover from MenuItem

version,
'styles.ts'
),
2

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this is just called with "2", lets not make it a parameter

(ts.isArrowFunction(node) || ts.isFunctionDeclaration(node)) &&
node.parameters.length > paramIndex
) {
param = node.parameters[paramIndex]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

As I see this finds the first function with >2 parameters. it should find the default export, now it craches e.g. in FormFieldLayout

}
}

const extractPaths = (filePath: string, paramIndex: number) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This fails to extract symbols from View's helper functions like getBorderStyle, getSpacingStyle`` getOffsetStyle`

…onent version

Add a prompt-driven generator that snapshots only the theme tokens one component version
reads, so an older version keeps its tokens as the shared trees keep evolving.

`pnpm run build:frozen-themes` asks for themes, package, component and version, then writes
a frozenThemes folder into that component version. The package and component lists only
offer components that are versioned, have a styles.ts, and are not frozen yet.

Narrowing runs in three passes: call the component token function against a recording proxy,
trace the sharedTokens parameter of generateStyle through the TypeScript AST, then map those
shared tokens back to the semantics they read. The union drives what semantics and primitives
keep. Emitted files are sliced out of the original source, so token references survive as
written. For Alert v2 the semantics file comes out at 82 lines against more than 1600.

Reads that cannot be resolved at build time, such as indexing tokens with a runtime value,
throw rather than being treated as unused, which would strip tokens the component needs.

withStyleNew now nests a frozen theme's component function under components[componentId] so
the existing lookup path resolves it.

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

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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