feat(ui-scripts,ui-themes): generate theme tokens as css custom properties - #2690

Open
HerrTopi wants to merge 1 commit into
masterfrom
css-themes
Open

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties#2690
HerrTopi wants to merge 1 commit into
masterfrom
css-themes

Conversation

@HerrTopi

@HerrTopiHerrTopi commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/.
  • Emit cssThemesWithMediaQueries.css, mapping the light and dark themes to prefers-color-scheme.
  • Register the malva CSS plugin in dprint.json so the generated stylesheets go through the existing dprint pass.
  • Mark *.css as side-effectful in ui-themes so bundlers don't tree-shake stylesheet imports.

Test Plan

  • Run pnpm run build:themes and check the 5 files under packages/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/ — the directory is gitignored, so none of the generated CSS appears in this diff.
  • With cssThemesWithMediaQueries.css loaded, toggle the OS colour scheme and confirm the :root values and color-scheme switch.

Open questions for the reviewer

  • The 188 custom properties are unprefixed (--background-*, --spacing-md). The existing style-dictionary emitter uses instui-<theme>. Adding a prefix later is breaking, so this should be settled before release.

Fixes INSTUI-5153

🤖 Generated with Claude Code

@HerrTopiHerrTopi self-assigned this Aug 17, 2026
@HerrTopi
HerrTopi requested a review from matyasfAugust 17, 2026 14:14
@github-actions

github-actionsBot commented Aug 17, 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-2690/

Built to branch gh-pages at 2026-08-27 22:30 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Visual regression report

Cypress suite: ✅ Passing

Visual diff:⚠️Changes detected.

StatusCount
Unchanged94
Changed2
New0
Removed0

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 (2)

badge-canvas.png — 1573 pixels differ

tooltip-light.png — 14438 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.

@matyasfmatyasf 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.

While the CSS is exported, the users can only pull it in with an export statement from the src folder, which is not nice.
When I import it this way:
import "@instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css"
I get an error TS2882: Cannot find module or type declarations for side-effect import of @instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

I've released version 11.7.5-pr-snapshot-1787571141446 from this PR, so its easier to test

(res, key) => `${res}--${key}:${flatResult[key]};`,
''
)
sharedTokensByThemes[theme] = cssVariables

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 makes a CSS class called light/dark/legacyCanvas/legacyCanvasHighContrast. Arent the light and dark keywords too generic that it could cause hard to track down bugs because something overrides it? I'd prefix these with something like InstUITheme-{name}

@matyasf
matyasf self-requested a review August 24, 2026 14:04

@matyasfmatyasf 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.

see my comment

@HouseOfHawks
HouseOfHawks self-requested a review August 24, 2026 14:10
@HouseOfHawks

Copy link
Copy Markdown
Collaborator

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

Agreed! If we can truncate to a simple import '@instructure/ui-themes/cssThemesWithMediaQueries.css'; then the DX would be fantastic.

Outside of that, testing a Next.js app router with that import in layout.tsx, throttling to 3G and stopping the page load before hydration - dark theme is correctly active (I'm in dark mode OS preference). Note that none of this page is currently using any of those tokens; just inspecting in dev-tools:

Screenshot 2026-08-24 at 11 49 26 AM

And light mode is correctly overridden:

Screenshot 2026-08-24 at 11 52 01 AM

Great stuff!

…rties
Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and
emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/, plus a
cssThemesWithMediaQueries.css that maps the light and dark themes to prefers-color-scheme.
Register the malva plugin in dprint.json so the generated stylesheets are formatted by the
existing dprint pass, and mark *.css as side-effectful in ui-themes so bundlers do not drop
the stylesheet imports.
Also emit SharedTokens as a type-only import in the generated component templates.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@HerrTopi@HouseOfHawks@matyasf
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties - #2690

Open
HerrTopi wants to merge 1 commit into
masterfrom
css-themes
Open

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties#2690
HerrTopi wants to merge 1 commit into
masterfrom
css-themes

Conversation

@HerrTopi

@HerrTopiHerrTopi commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/.
  • Emit cssThemesWithMediaQueries.css, mapping the light and dark themes to prefers-color-scheme.
  • Register the malva CSS plugin in dprint.json so the generated stylesheets go through the existing dprint pass.
  • Mark *.css as side-effectful in ui-themes so bundlers don't tree-shake stylesheet imports.

Test Plan

  • Run pnpm run build:themes and check the 5 files under packages/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/ — the directory is gitignored, so none of the generated CSS appears in this diff.
  • With cssThemesWithMediaQueries.css loaded, toggle the OS colour scheme and confirm the :root values and color-scheme switch.

Open questions for the reviewer

  • The 188 custom properties are unprefixed (--background-*, --spacing-md). The existing style-dictionary emitter uses instui-<theme>. Adding a prefix later is breaking, so this should be settled before release.

Fixes INSTUI-5153

🤖 Generated with Claude Code

@HerrTopiHerrTopi self-assigned this Aug 17, 2026
@HerrTopi
HerrTopi requested a review from matyasfAugust 17, 2026 14:14
@github-actions

github-actionsBot commented Aug 17, 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-2690/

Built to branch gh-pages at 2026-08-27 22:30 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Visual regression report

Cypress suite: ✅ Passing

Visual diff:⚠️Changes detected.

StatusCount
Unchanged94
Changed2
New0
Removed0

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 (2)

badge-canvas.png — 1573 pixels differ

tooltip-light.png — 14438 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.

@matyasfmatyasf 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.

While the CSS is exported, the users can only pull it in with an export statement from the src folder, which is not nice.
When I import it this way:
import "@instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css"
I get an error TS2882: Cannot find module or type declarations for side-effect import of @instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

I've released version 11.7.5-pr-snapshot-1787571141446 from this PR, so its easier to test

(res, key) => `${res}--${key}:${flatResult[key]};`,
''
)
sharedTokensByThemes[theme] = cssVariables

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 makes a CSS class called light/dark/legacyCanvas/legacyCanvasHighContrast. Arent the light and dark keywords too generic that it could cause hard to track down bugs because something overrides it? I'd prefix these with something like InstUITheme-{name}

@matyasf
matyasf self-requested a review August 24, 2026 14:04

@matyasfmatyasf 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.

see my comment

@HouseOfHawks
HouseOfHawks self-requested a review August 24, 2026 14:10
@HouseOfHawks

Copy link
Copy Markdown
Collaborator

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

Agreed! If we can truncate to a simple import '@instructure/ui-themes/cssThemesWithMediaQueries.css'; then the DX would be fantastic.

Outside of that, testing a Next.js app router with that import in layout.tsx, throttling to 3G and stopping the page load before hydration - dark theme is correctly active (I'm in dark mode OS preference). Note that none of this page is currently using any of those tokens; just inspecting in dev-tools:

Screenshot 2026-08-24 at 11 49 26 AM

And light mode is correctly overridden:

Screenshot 2026-08-24 at 11 52 01 AM

Great stuff!

…rties
Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and
emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/, plus a
cssThemesWithMediaQueries.css that maps the light and dark themes to prefers-color-scheme.
Register the malva plugin in dprint.json so the generated stylesheets are formatted by the
existing dprint pass, and mark *.css as side-effectful in ui-themes so bundlers do not drop
the stylesheet imports.
Also emit SharedTokens as a type-only import in the generated component templates.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@HerrTopi@HouseOfHawks@matyasf
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties - #2690

Open
HerrTopi wants to merge 1 commit into
masterfrom
css-themes
Open

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties#2690
HerrTopi wants to merge 1 commit into
masterfrom
css-themes

Conversation

@HerrTopi

@HerrTopiHerrTopi commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/.
  • Emit cssThemesWithMediaQueries.css, mapping the light and dark themes to prefers-color-scheme.
  • Register the malva CSS plugin in dprint.json so the generated stylesheets go through the existing dprint pass.
  • Mark *.css as side-effectful in ui-themes so bundlers don't tree-shake stylesheet imports.

Test Plan

  • Run pnpm run build:themes and check the 5 files under packages/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/ — the directory is gitignored, so none of the generated CSS appears in this diff.
  • With cssThemesWithMediaQueries.css loaded, toggle the OS colour scheme and confirm the :root values and color-scheme switch.

Open questions for the reviewer

  • The 188 custom properties are unprefixed (--background-*, --spacing-md). The existing style-dictionary emitter uses instui-<theme>. Adding a prefix later is breaking, so this should be settled before release.

Fixes INSTUI-5153

🤖 Generated with Claude Code

@HerrTopiHerrTopi self-assigned this Aug 17, 2026
@HerrTopi
HerrTopi requested a review from matyasfAugust 17, 2026 14:14
@github-actions

github-actionsBot commented Aug 17, 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-2690/

Built to branch gh-pages at 2026-08-27 22:30 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Visual regression report

Cypress suite: ✅ Passing

Visual diff:⚠️Changes detected.

StatusCount
Unchanged94
Changed2
New0
Removed0

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 (2)

badge-canvas.png — 1573 pixels differ

tooltip-light.png — 14438 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.

@matyasfmatyasf 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.

While the CSS is exported, the users can only pull it in with an export statement from the src folder, which is not nice.
When I import it this way:
import "@instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css"
I get an error TS2882: Cannot find module or type declarations for side-effect import of @instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

I've released version 11.7.5-pr-snapshot-1787571141446 from this PR, so its easier to test

(res, key) => `${res}--${key}:${flatResult[key]};`,
''
)
sharedTokensByThemes[theme] = cssVariables

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 makes a CSS class called light/dark/legacyCanvas/legacyCanvasHighContrast. Arent the light and dark keywords too generic that it could cause hard to track down bugs because something overrides it? I'd prefix these with something like InstUITheme-{name}

@matyasf
matyasf self-requested a review August 24, 2026 14:04

@matyasfmatyasf 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.

see my comment

@HouseOfHawks
HouseOfHawks self-requested a review August 24, 2026 14:10
@HouseOfHawks

Copy link
Copy Markdown
Collaborator

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

Agreed! If we can truncate to a simple import '@instructure/ui-themes/cssThemesWithMediaQueries.css'; then the DX would be fantastic.

Outside of that, testing a Next.js app router with that import in layout.tsx, throttling to 3G and stopping the page load before hydration - dark theme is correctly active (I'm in dark mode OS preference). Note that none of this page is currently using any of those tokens; just inspecting in dev-tools:

Screenshot 2026-08-24 at 11 49 26 AM

And light mode is correctly overridden:

Screenshot 2026-08-24 at 11 52 01 AM

Great stuff!

…rties
Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and
emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/, plus a
cssThemesWithMediaQueries.css that maps the light and dark themes to prefers-color-scheme.
Register the malva plugin in dprint.json so the generated stylesheets are formatted by the
existing dprint pass, and mark *.css as side-effectful in ui-themes so bundlers do not drop
the stylesheet imports.
Also emit SharedTokens as a type-only import in the generated component templates.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@HerrTopi@HouseOfHawks@matyasf
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties - #2690

Open
HerrTopi wants to merge 1 commit into
masterfrom
css-themes
Open

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties#2690
HerrTopi wants to merge 1 commit into
masterfrom
css-themes

Conversation

@HerrTopi

@HerrTopiHerrTopi commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/.
  • Emit cssThemesWithMediaQueries.css, mapping the light and dark themes to prefers-color-scheme.
  • Register the malva CSS plugin in dprint.json so the generated stylesheets go through the existing dprint pass.
  • Mark *.css as side-effectful in ui-themes so bundlers don't tree-shake stylesheet imports.

Test Plan

  • Run pnpm run build:themes and check the 5 files under packages/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/ — the directory is gitignored, so none of the generated CSS appears in this diff.
  • With cssThemesWithMediaQueries.css loaded, toggle the OS colour scheme and confirm the :root values and color-scheme switch.

Open questions for the reviewer

  • The 188 custom properties are unprefixed (--background-*, --spacing-md). The existing style-dictionary emitter uses instui-<theme>. Adding a prefix later is breaking, so this should be settled before release.

Fixes INSTUI-5153

🤖 Generated with Claude Code

@HerrTopiHerrTopi self-assigned this Aug 17, 2026
@HerrTopi
HerrTopi requested a review from matyasfAugust 17, 2026 14:14
@github-actions

github-actionsBot commented Aug 17, 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-2690/

Built to branch gh-pages at 2026-08-27 22:30 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Visual regression report

Cypress suite: ✅ Passing

Visual diff:⚠️Changes detected.

StatusCount
Unchanged94
Changed2
New0
Removed0

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 (2)

badge-canvas.png — 1573 pixels differ

tooltip-light.png — 14438 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.

@matyasfmatyasf 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.

While the CSS is exported, the users can only pull it in with an export statement from the src folder, which is not nice.
When I import it this way:
import "@instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css"
I get an error TS2882: Cannot find module or type declarations for side-effect import of @instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

I've released version 11.7.5-pr-snapshot-1787571141446 from this PR, so its easier to test

(res, key) => `${res}--${key}:${flatResult[key]};`,
''
)
sharedTokensByThemes[theme] = cssVariables

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 makes a CSS class called light/dark/legacyCanvas/legacyCanvasHighContrast. Arent the light and dark keywords too generic that it could cause hard to track down bugs because something overrides it? I'd prefix these with something like InstUITheme-{name}

@matyasf
matyasf self-requested a review August 24, 2026 14:04

@matyasfmatyasf 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.

see my comment

@HouseOfHawks
HouseOfHawks self-requested a review August 24, 2026 14:10
@HouseOfHawks

Copy link
Copy Markdown
Collaborator

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

Agreed! If we can truncate to a simple import '@instructure/ui-themes/cssThemesWithMediaQueries.css'; then the DX would be fantastic.

Outside of that, testing a Next.js app router with that import in layout.tsx, throttling to 3G and stopping the page load before hydration - dark theme is correctly active (I'm in dark mode OS preference). Note that none of this page is currently using any of those tokens; just inspecting in dev-tools:

Screenshot 2026-08-24 at 11 49 26 AM

And light mode is correctly overridden:

Screenshot 2026-08-24 at 11 52 01 AM

Great stuff!

…rties
Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and
emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/, plus a
cssThemesWithMediaQueries.css that maps the light and dark themes to prefers-color-scheme.
Register the malva plugin in dprint.json so the generated stylesheets are formatted by the
existing dprint pass, and mark *.css as side-effectful in ui-themes so bundlers do not drop
the stylesheet imports.
Also emit SharedTokens as a type-only import in the generated component templates.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@HerrTopi@HouseOfHawks@matyasf
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties - #2690

Open
HerrTopi wants to merge 1 commit into
masterfrom
css-themes
Open

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties#2690
HerrTopi wants to merge 1 commit into
masterfrom
css-themes

Conversation

@HerrTopi

@HerrTopiHerrTopi commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/.
  • Emit cssThemesWithMediaQueries.css, mapping the light and dark themes to prefers-color-scheme.
  • Register the malva CSS plugin in dprint.json so the generated stylesheets go through the existing dprint pass.
  • Mark *.css as side-effectful in ui-themes so bundlers don't tree-shake stylesheet imports.

Test Plan

  • Run pnpm run build:themes and check the 5 files under packages/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/ — the directory is gitignored, so none of the generated CSS appears in this diff.
  • With cssThemesWithMediaQueries.css loaded, toggle the OS colour scheme and confirm the :root values and color-scheme switch.

Open questions for the reviewer

  • The 188 custom properties are unprefixed (--background-*, --spacing-md). The existing style-dictionary emitter uses instui-<theme>. Adding a prefix later is breaking, so this should be settled before release.

Fixes INSTUI-5153

🤖 Generated with Claude Code

@HerrTopiHerrTopi self-assigned this Aug 17, 2026
@HerrTopi
HerrTopi requested a review from matyasfAugust 17, 2026 14:14
@github-actions

github-actionsBot commented Aug 17, 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-2690/

Built to branch gh-pages at 2026-08-27 22:30 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Visual regression report

Cypress suite: ✅ Passing

Visual diff:⚠️Changes detected.

StatusCount
Unchanged94
Changed2
New0
Removed0

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 (2)

badge-canvas.png — 1573 pixels differ

tooltip-light.png — 14438 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.

@matyasfmatyasf 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.

While the CSS is exported, the users can only pull it in with an export statement from the src folder, which is not nice.
When I import it this way:
import "@instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css"
I get an error TS2882: Cannot find module or type declarations for side-effect import of @instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

I've released version 11.7.5-pr-snapshot-1787571141446 from this PR, so its easier to test

(res, key) => `${res}--${key}:${flatResult[key]};`,
''
)
sharedTokensByThemes[theme] = cssVariables

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 makes a CSS class called light/dark/legacyCanvas/legacyCanvasHighContrast. Arent the light and dark keywords too generic that it could cause hard to track down bugs because something overrides it? I'd prefix these with something like InstUITheme-{name}

@matyasf
matyasf self-requested a review August 24, 2026 14:04

@matyasfmatyasf 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.

see my comment

@HouseOfHawks
HouseOfHawks self-requested a review August 24, 2026 14:10
@HouseOfHawks

Copy link
Copy Markdown
Collaborator

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

Agreed! If we can truncate to a simple import '@instructure/ui-themes/cssThemesWithMediaQueries.css'; then the DX would be fantastic.

Outside of that, testing a Next.js app router with that import in layout.tsx, throttling to 3G and stopping the page load before hydration - dark theme is correctly active (I'm in dark mode OS preference). Note that none of this page is currently using any of those tokens; just inspecting in dev-tools:

Screenshot 2026-08-24 at 11 49 26 AM

And light mode is correctly overridden:

Screenshot 2026-08-24 at 11 52 01 AM

Great stuff!

…rties
Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and
emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/, plus a
cssThemesWithMediaQueries.css that maps the light and dark themes to prefers-color-scheme.
Register the malva plugin in dprint.json so the generated stylesheets are formatted by the
existing dprint pass, and mark *.css as side-effectful in ui-themes so bundlers do not drop
the stylesheet imports.
Also emit SharedTokens as a type-only import in the generated component templates.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@HerrTopi@HouseOfHawks@matyasf
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties - #2690

Open
HerrTopi wants to merge 1 commit into
masterfrom
css-themes
Open

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties#2690
HerrTopi wants to merge 1 commit into
masterfrom
css-themes

Conversation

@HerrTopi

@HerrTopiHerrTopi commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/.
  • Emit cssThemesWithMediaQueries.css, mapping the light and dark themes to prefers-color-scheme.
  • Register the malva CSS plugin in dprint.json so the generated stylesheets go through the existing dprint pass.
  • Mark *.css as side-effectful in ui-themes so bundlers don't tree-shake stylesheet imports.

Test Plan

  • Run pnpm run build:themes and check the 5 files under packages/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/ — the directory is gitignored, so none of the generated CSS appears in this diff.
  • With cssThemesWithMediaQueries.css loaded, toggle the OS colour scheme and confirm the :root values and color-scheme switch.

Open questions for the reviewer

  • The 188 custom properties are unprefixed (--background-*, --spacing-md). The existing style-dictionary emitter uses instui-<theme>. Adding a prefix later is breaking, so this should be settled before release.

Fixes INSTUI-5153

🤖 Generated with Claude Code

@HerrTopiHerrTopi self-assigned this Aug 17, 2026
@HerrTopi
HerrTopi requested a review from matyasfAugust 17, 2026 14:14
@github-actions

github-actionsBot commented Aug 17, 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-2690/

Built to branch gh-pages at 2026-08-27 22:30 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Visual regression report

Cypress suite: ✅ Passing

Visual diff:⚠️Changes detected.

StatusCount
Unchanged94
Changed2
New0
Removed0

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 (2)

badge-canvas.png — 1573 pixels differ

tooltip-light.png — 14438 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.

@matyasfmatyasf 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.

While the CSS is exported, the users can only pull it in with an export statement from the src folder, which is not nice.
When I import it this way:
import "@instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css"
I get an error TS2882: Cannot find module or type declarations for side-effect import of @instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

I've released version 11.7.5-pr-snapshot-1787571141446 from this PR, so its easier to test

(res, key) => `${res}--${key}:${flatResult[key]};`,
''
)
sharedTokensByThemes[theme] = cssVariables

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 makes a CSS class called light/dark/legacyCanvas/legacyCanvasHighContrast. Arent the light and dark keywords too generic that it could cause hard to track down bugs because something overrides it? I'd prefix these with something like InstUITheme-{name}

@matyasf
matyasf self-requested a review August 24, 2026 14:04

@matyasfmatyasf 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.

see my comment

@HouseOfHawks
HouseOfHawks self-requested a review August 24, 2026 14:10
@HouseOfHawks

Copy link
Copy Markdown
Collaborator

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

Agreed! If we can truncate to a simple import '@instructure/ui-themes/cssThemesWithMediaQueries.css'; then the DX would be fantastic.

Outside of that, testing a Next.js app router with that import in layout.tsx, throttling to 3G and stopping the page load before hydration - dark theme is correctly active (I'm in dark mode OS preference). Note that none of this page is currently using any of those tokens; just inspecting in dev-tools:

Screenshot 2026-08-24 at 11 49 26 AM

And light mode is correctly overridden:

Screenshot 2026-08-24 at 11 52 01 AM

Great stuff!

…rties
Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and
emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/, plus a
cssThemesWithMediaQueries.css that maps the light and dark themes to prefers-color-scheme.
Register the malva plugin in dprint.json so the generated stylesheets are formatted by the
existing dprint pass, and mark *.css as side-effectful in ui-themes so bundlers do not drop
the stylesheet imports.
Also emit SharedTokens as a type-only import in the generated component templates.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@HerrTopi@HouseOfHawks@matyasf
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties - #2690

Open
HerrTopi wants to merge 1 commit into
masterfrom
css-themes
Open

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties#2690
HerrTopi wants to merge 1 commit into
masterfrom
css-themes

Conversation

@HerrTopi

@HerrTopiHerrTopi commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/.
  • Emit cssThemesWithMediaQueries.css, mapping the light and dark themes to prefers-color-scheme.
  • Register the malva CSS plugin in dprint.json so the generated stylesheets go through the existing dprint pass.
  • Mark *.css as side-effectful in ui-themes so bundlers don't tree-shake stylesheet imports.

Test Plan

  • Run pnpm run build:themes and check the 5 files under packages/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/ — the directory is gitignored, so none of the generated CSS appears in this diff.
  • With cssThemesWithMediaQueries.css loaded, toggle the OS colour scheme and confirm the :root values and color-scheme switch.

Open questions for the reviewer

  • The 188 custom properties are unprefixed (--background-*, --spacing-md). The existing style-dictionary emitter uses instui-<theme>. Adding a prefix later is breaking, so this should be settled before release.

Fixes INSTUI-5153

🤖 Generated with Claude Code

@HerrTopiHerrTopi self-assigned this Aug 17, 2026
@HerrTopi
HerrTopi requested a review from matyasfAugust 17, 2026 14:14
@github-actions

github-actionsBot commented Aug 17, 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-2690/

Built to branch gh-pages at 2026-08-27 22:30 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Visual regression report

Cypress suite: ✅ Passing

Visual diff:⚠️Changes detected.

StatusCount
Unchanged94
Changed2
New0
Removed0

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 (2)

badge-canvas.png — 1573 pixels differ

tooltip-light.png — 14438 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.

@matyasfmatyasf 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.

While the CSS is exported, the users can only pull it in with an export statement from the src folder, which is not nice.
When I import it this way:
import "@instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css"
I get an error TS2882: Cannot find module or type declarations for side-effect import of @instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

I've released version 11.7.5-pr-snapshot-1787571141446 from this PR, so its easier to test

(res, key) => `${res}--${key}:${flatResult[key]};`,
''
)
sharedTokensByThemes[theme] = cssVariables

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 makes a CSS class called light/dark/legacyCanvas/legacyCanvasHighContrast. Arent the light and dark keywords too generic that it could cause hard to track down bugs because something overrides it? I'd prefix these with something like InstUITheme-{name}

@matyasf
matyasf self-requested a review August 24, 2026 14:04

@matyasfmatyasf 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.

see my comment

@HouseOfHawks
HouseOfHawks self-requested a review August 24, 2026 14:10
@HouseOfHawks

Copy link
Copy Markdown
Collaborator

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

Agreed! If we can truncate to a simple import '@instructure/ui-themes/cssThemesWithMediaQueries.css'; then the DX would be fantastic.

Outside of that, testing a Next.js app router with that import in layout.tsx, throttling to 3G and stopping the page load before hydration - dark theme is correctly active (I'm in dark mode OS preference). Note that none of this page is currently using any of those tokens; just inspecting in dev-tools:

Screenshot 2026-08-24 at 11 49 26 AM

And light mode is correctly overridden:

Screenshot 2026-08-24 at 11 52 01 AM

Great stuff!

…rties
Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and
emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/, plus a
cssThemesWithMediaQueries.css that maps the light and dark themes to prefers-color-scheme.
Register the malva plugin in dprint.json so the generated stylesheets are formatted by the
existing dprint pass, and mark *.css as side-effectful in ui-themes so bundlers do not drop
the stylesheet imports.
Also emit SharedTokens as a type-only import in the generated component templates.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@HerrTopi@HouseOfHawks@matyasf
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties - #2690

Open
HerrTopi wants to merge 1 commit into
masterfrom
css-themes
Open

feat(ui-scripts,ui-themes): generate theme tokens as css custom properties#2690
HerrTopi wants to merge 1 commit into
masterfrom
css-themes

Conversation

@HerrTopi

@HerrTopiHerrTopi commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/.
  • Emit cssThemesWithMediaQueries.css, mapping the light and dark themes to prefers-color-scheme.
  • Register the malva CSS plugin in dprint.json so the generated stylesheets go through the existing dprint pass.
  • Mark *.css as side-effectful in ui-themes so bundlers don't tree-shake stylesheet imports.

Test Plan

  • Run pnpm run build:themes and check the 5 files under packages/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/ — the directory is gitignored, so none of the generated CSS appears in this diff.
  • With cssThemesWithMediaQueries.css loaded, toggle the OS colour scheme and confirm the :root values and color-scheme switch.

Open questions for the reviewer

  • The 188 custom properties are unprefixed (--background-*, --spacing-md). The existing style-dictionary emitter uses instui-<theme>. Adding a prefix later is breaking, so this should be settled before release.

Fixes INSTUI-5153

🤖 Generated with Claude Code

@HerrTopiHerrTopi self-assigned this Aug 17, 2026
@HerrTopi
HerrTopi requested a review from matyasfAugust 17, 2026 14:14
@github-actions

github-actionsBot commented Aug 17, 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-2690/

Built to branch gh-pages at 2026-08-27 22:30 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Visual regression report

Cypress suite: ✅ Passing

Visual diff:⚠️Changes detected.

StatusCount
Unchanged94
Changed2
New0
Removed0

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 (2)

badge-canvas.png — 1573 pixels differ

tooltip-light.png — 14438 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.

@matyasfmatyasf 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.

While the CSS is exported, the users can only pull it in with an export statement from the src folder, which is not nice.
When I import it this way:
import "@instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css"
I get an error TS2882: Cannot find module or type declarations for side-effect import of @instructure/ui-themes/src/themes/newThemeTokens/themesAsCSSVariables/cssThemesWithMediaQueries.css

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

I've released version 11.7.5-pr-snapshot-1787571141446 from this PR, so its easier to test

(res, key) => `${res}--${key}:${flatResult[key]};`,
''
)
sharedTokensByThemes[theme] = cssVariables

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 makes a CSS class called light/dark/legacyCanvas/legacyCanvasHighContrast. Arent the light and dark keywords too generic that it could cause hard to track down bugs because something overrides it? I'd prefix these with something like InstUITheme-{name}

@matyasf
matyasf self-requested a review August 24, 2026 14:04

@matyasfmatyasf 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.

see my comment

@HouseOfHawks
HouseOfHawks self-requested a review August 24, 2026 14:10
@HouseOfHawks

Copy link
Copy Markdown
Collaborator

Can you please look into this? First I think we should add it to the exports in the package.json, then AI recommended me to add also a d.ts file.

Agreed! If we can truncate to a simple import '@instructure/ui-themes/cssThemesWithMediaQueries.css'; then the DX would be fantastic.

Outside of that, testing a Next.js app router with that import in layout.tsx, throttling to 3G and stopping the page load before hydration - dark theme is correctly active (I'm in dark mode OS preference). Note that none of this page is currently using any of those tokens; just inspecting in dev-tools:

Screenshot 2026-08-24 at 11 49 26 AM

And light mode is correctly overridden:

Screenshot 2026-08-24 at 11 52 01 AM

Great stuff!

…rties
Add a buildCSSVariables step to build-themes that flattens each theme's shared tokens and
emits one stylesheet per theme under src/themes/newThemeTokens/themesAsCSSVariables/, plus a
cssThemesWithMediaQueries.css that maps the light and dark themes to prefers-color-scheme.
Register the malva plugin in dprint.json so the generated stylesheets are formatted by the
existing dprint pass, and mark *.css as side-effectful in ui-themes so bundlers do not drop
the stylesheet imports.
Also emit SharedTokens as a type-only import in the generated component templates.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

3 participants

@HerrTopi@HouseOfHawks@matyasf