Skip to content

chore: color stack preview (do not merge) - #60

Draft
dreamwasp wants to merge 135 commits into
mainfrom
cass-gmt-1825-color-preview
Draft

dreamwasp wants to merge 135 commits into
mainfrom
cass-gmt-1825-color-preview

Conversation

@dreamwasp

@dreamwasp dreamwasp commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Do not merge or review. This PR exists so pkg.pr.new builds installable previews of the whole color stack. Previews only build for PRs into main, and the color PRs are stacked.

It merges:

Two conflicts with main were resolved here: Card.stories.tsx takes #57's generated controls, and SelectDropdown/core/styles.ts fixes import paths after #47 moved it under Form/inputs.

Used by the color test branch, which runs the codemod on a front-style prototype page. Close this once the stack lands.

🤖 Generated with Claude Code

dreamwasp and others added 30 commits October 20, 2026 10:07
…eset

Adds @skillsoft/gamut-codemods: the CLI (clean-tree guard, --dry, --only,
--no-report, --force), the runner for ast, splice, and file migrations,
the shared helpers (module-string finder, leftovers report, version-range
checks, flat ESLint config detection), the preset registry, and the
fixture harness.

The scope-swap preset has its package map but no migrations yet, so a run
only reports the lines that still name an old package. Each breaking
change lands its migration in its own PR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…swap

scope-rename swaps @Codecademy/gamut* and eslint-plugin-gamut for their
@SkillSoft names in every module position and in comments. package-json,
mdx-imports, and yarnrc cover dependencies, MDX ESM blocks, and
.yarnrc.yml lists.

@codecademy/gamut-kit has no replacement, so package-json and mf-shared
expand it into the packages it bundled. In Module Federation config that
makes Gamut a real singleton, which the checklist calls out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ides

moved-exports moves Video and VideoProps from the root to
@Codecademy/gamut/Video (scope-rename then swaps the scope).
markdown-video-overrides adds explicit iframeOverride/videoOverride to
each <Markdown>, since it no longer renders video through Video by
default, and drops the removed skipDefaultOverrides keys. tsconfig-dom
warns about tsconfigs without "dom", which Video used to supply.

On the Gamut side, a Video/package.json stub makes the subpath resolve
under node10, MarkdownVideo no longer passes NaN sizes, and a one-line
<video> is no longer wrapped in a <p>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ectDropdown elements

Exports formFieldStyles, formFieldPaddingStyles, conditionalStyles,
ButtonBaseProps, HTMLToReactNode, MenuToolTipWrapper, and Menu's list
elements from the root. The list elements and SelectDropdown's option
component are renamed (MenuList*, MenuListButton, IconOptionComponent) so
they don't collide with the public List component and IconOption type.

The deep-imports codemod rewrites known /dist/ paths to the root, keeps
local names across renames, merges into existing imports, and warns on
paths with no public replacement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
eslint-comments rewrites gamut/ directives to @skillsoft/gamut/, and
eslint-config updates the plugin name, plugin: extends, and rule keys in
legacy .eslintrc files. Under a flat config the prefix is the plugins key,
so eslint-comments skips itself and the checklist explains why.

Also types eslint-plugin-gamut's recommended severities as literals, so the
plugin fits ESLint's Plugin type in a typed flat config.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@skillsoft/gamut ships strict-ESM .mjs. With experimental.esmExternals
off, Next require()s server externals and default imports from
@emotion/styled and react-select break while it collects page data.
next-config is report-only: dropping the flag can take other config with
it, so it warns and adds a checklist item instead of rewriting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ap-skill

# Conflicts:
#	packages/gamut-codemods/README.md
#	packages/gamut-codemods/src/presets/scope-swap/index.ts
# Conflicts:
#	packages/gamut-codemods/README.md
#	packages/gamut-codemods/src/__tests__/lib.test.ts
#	packages/gamut-codemods/src/presets/scope-swap/index.ts
…p-skill

# Conflicts:
#	packages/gamut-codemods/README.md
#	packages/gamut-codemods/src/__tests__/cli.test.ts
#	packages/gamut-codemods/src/presets/scope-swap/index.ts
The skill works alongside the scope-swap codemod: it reads the warnings,
leftovers, and next steps, and helps with what the codemod can't rewrite.
BREAKING_CHANGES.md lists every change in the move, and
NEXT_EMOTION_INTEROP.md covers the Next.js esmExternals fallback.

Also restores the end-to-end and MDX fixtures that run every migration
together, and fixes the cli.test merge between the sibling branches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CodeQL read `migration.match(file)` in cli.ts as String.prototype.match
on a command-line argument and flagged js/regex-injection. Nothing builds
a regex from the path; the method just had the same name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…migrations

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…migrations

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…migrations

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…migrations

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The package-json warning already names each range that's newer than the
fork point, so the extra next step only repeated it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rkdown

# Conflicts:
#	packages/gamut-codemods/src/presets/scope-swap/index.ts
# Conflicts:
#	packages/gamut-codemods/src/presets/scope-swap/index.ts
# Conflicts:
#	packages/gamut-codemods/src/presets/scope-swap/index.ts
…swap-skill

# Conflicts:
#	packages/gamut-codemods/src/presets/scope-swap/index.ts
dreamwasp and others added 26 commits November 4, 2026 14:56
Each brand theme now carries and injects only its own brand's CSS (about
21 KB, down from 56 KB for every brand at once). The CSS puts the brand's
palette and initial mode on :root, and folds its role overrides into its
mode blocks. Every brand resolves to the same values as before in both modes.

The generator, role table, checks, sandbox fixture and gamut's brand inputs
move from gamut-styles' src/colorSystem to a new build-time package,
@skillsoft/gamut-brand. Its `gamut-brand build` CLI writes a brand's
values.ts, tokens.css and DTCG JSON (--watch, --check), and refuses a brand
that fails a check, including on its own tokens.css read back.
gamut-styles' build:tokens uses the same writeBrand on gamut's five brands.

- createBrandTheme, BrandBase and BrandValues are exported. A team's theme
  has the same type as gamut's, so system props stay typed.
- BREAKING: generated files move to one folder per brand
  (tokens/<brand>.css, tokens/<brand>/*.tokens.json; tokens.css stays the
  default brand). initialMode moves from the theme onto the brand.
- DTCG mode files include each brand's role overrides.
- Role names in brand overrides are typed (ROLE_TOKENS).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… your own brand

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The generator, and design's migration map with it, moved from gamut-styles'
src/colorSystem to @skillsoft/gamut-brand. aliases.ts is regenerated from
the moved map; only its header comments change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sandbox parity only matters while the port is in development. The
generator is now held to its own rules for any hue (fixed lightness per
grade, chroma inside sRGB, the separation guarantee, one role mapping
for every brand, every check passing) instead of a saved copy of the
sandbox's output. The checked-in generated files still catch value drift.

Drops the sandbox fixture, dump script and comments that pointed at
sandbox commits and files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…or-components

# Conflicts:
#	packages/gamut/src/Alert/elements.tsx
…mmits

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
css: string,
source: ColorSystem
): ColorSystem => {
const blocks = [...css.matchAll(/([^{};]+)\{([^{}]*)\}/g)].map((m) => ({
const blocks = [...css.matchAll(/([^{};]+)\{([^{}]*)\}/g)].map((m) => ({
selectors: m[1].trim().split('\n').pop()!.trim().split(/,\s*/),
decls: Object.fromEntries(
[...m[2].matchAll(/(--[\w-]+):\s*([^;]+);/g)].map((d) => [d[1], d[2]])
The older color pages (color modes, design tokens, themes, supporting
dark mode, theming your app, creating a custom theme) described the old
aliases and Core theme. They now cover roles, the five brand themes and
building a brand with @skillsoft/gamut-brand. Code samples on other pages
use roles instead of old color names, Card documents its two variants,
and the site's own Starlight colors come from the Skillsoft brand's
tokens.css instead of a hand-copied Core palette.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

3 participants