Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
5a7f907
fix(sideEffects): unblock tree-shaking on variance, gamut-styles, gam…
dreamwasp Sep 16, 2026
f891914
build(tsdown): migrate variance, gamut-styles, gamut to the hybrid build
dreamwasp Sep 16, 2026
e18c7fa
build(tsdown): migrate gamut-icons, gamut-patterns, gamut-illustratio…
dreamwasp Sep 16, 2026
45a9f16
build(tsdown): add packaging verification (publint, attw, exports res…
dreamwasp Sep 16, 2026
37e28f5
build(tsdown): replace Babel with tsdown across all gamut packages
dreamwasp Sep 17, 2026
a41e396
Merge branch 'main' into cass-gmt-1741
dreamwasp Sep 17, 2026
501ac4d
less words
dreamwasp Sep 17, 2026
fdea41b
more changes
dreamwasp Sep 17, 2026
1010384
Merge branch 'cass-gmt-1741' of github.com:Codecademy/skillsoft-gamut…
dreamwasp Sep 17, 2026
30bf346
video
dreamwasp Sep 18, 2026
7c5df2c
fix(tsconfig): fix TS5097 in editors on tsdown.config.ts files
dreamwasp Sep 18, 2026
8cdda2e
Merge branch 'main' into cass-gmt-1741
dreamwasp Sep 18, 2026
862eb02
build(babel): DRY up per-package babel configs, drop dead styleguide …
dreamwasp Sep 18, 2026
c410e14
merged in main + dedupd
dreamwasp Sep 18, 2026
cca5dad
build(storybook): swap Emotion's Babel transform for @swc/plugin-emotion
dreamwasp Sep 18, 2026
7a9912b
comment format
dreamwasp Sep 21, 2026
a0318bf
fix node versions
dreamwasp Sep 21, 2026
c8828b5
Merge branch 'cass-gmt-1741' into cass-gmt-1795
dreamwasp Sep 21, 2026
402fa61
start swapping out babel;
dreamwasp Sep 21, 2026
8878514
Merge branch 'cass-gmt-1795' of github.com:Codecademy/skillsoft-gamut…
dreamwasp Sep 21, 2026
092bf53
resolution needed
dreamwasp Sep 21, 2026
eb61930
remove cirucular deps
dreamwasp Sep 21, 2026
e413ae1
Merge origin/main into cass-gmt-1795
dreamwasp Sep 22, 2026
1b18917
yarned
dreamwasp Sep 22, 2026
e56a6e7
prettier
dreamwasp Sep 22, 2026
3afabd1
Merge branch 'main' into cass-gmt-1795
dreamwasp Sep 23, 2026
e3c1513
make type exports explicit
dreamwasp Sep 23, 2026
bc15e63
Merge branch 'cass-gmt-1795' of github.com:Codecademy/skillsoft-gamut…
dreamwasp Sep 23, 2026
8bcd341
Merge remote-tracking branch 'origin/main' into cass-gmt-1795
dreamwasp Sep 23, 2026
5c278d5
formatting
dreamwasp Sep 24, 2026
d88076a
feat(gamut-codemods): add codemods package with a scope-swap preset
dreamwasp Sep 24, 2026
b1b91a7
ci(preview): TEMPORARY publish previews for PRs stacked on cass-gmt-1795
dreamwasp Sep 24, 2026
d0693b1
feat(gamut)!: export Menu list elements and IconOptionComponent from …
dreamwasp Sep 24, 2026
8f6f3ee
fix(gamut-codemods): keep existing @skillsoft versions; handle .mdx a…
dreamwasp Sep 24, 2026
1bebf43
feat(gamut): export formFieldStyles, formFieldPaddingStyles, conditio…
dreamwasp Sep 24, 2026
658a4df
fix: Video under node10 resolution; codemod only rewrites names the t…
dreamwasp Sep 24, 2026
46ad288
build(deps): make @skillsoft packages easier to install
dreamwasp Sep 24, 2026
ece8df7
Merge branch 'main' into cass-gmt-1795
dreamwasp Oct 5, 2026
aaa5505
dedupe
dreamwasp Oct 5, 2026
943f007
merge in dev
dreamwasp Oct 5, 2026
9b21a6f
change set
dreamwasp Oct 5, 2026
c4ba27a
add to readme
dreamwasp Oct 8, 2026
cdc14a8
leftovers + video
dreamwasp Oct 8, 2026
33176c8
update
dreamwasp Oct 9, 2026
2cef815
changeset
dreamwasp Oct 9, 2026
03edab5
merge in develop
dreamwasp Oct 14, 2026
899e538
merge dev
dreamwasp Oct 14, 2026
f0892d8
Merge branch 'cass-gmt-1795' into cass-gmt-1790
dreamwasp Oct 14, 2026
8f19a34
merge main
dreamwasp Oct 14, 2026
7910df6
feat(gamut-codemods): skip ESLint directive rewrites under flat confi…
dreamwasp Oct 16, 2026
98fe229
add markdown scope
dreamwasp Oct 16, 2026
325d76f
add tests
dreamwasp Oct 16, 2026
288c08b
fix(gamut-codemods): merge rewritten deep imports into existing imports
dreamwasp Oct 16, 2026
4a8a4a4
fix(gamut-codemods): skip markdown-video-overrides on upstream 74+
dreamwasp Oct 16, 2026
05df78b
fix(gamut-codemods): list stale scoped ESLint directives under flat c…
dreamwasp Oct 16, 2026
a3bab4d
feat(gamut-codemods): rename package names in comments
dreamwasp Oct 16, 2026
b45cb57
docs(gamut-scope-swap): cover flat-config directives, re-runs, and ne…
dreamwasp Oct 16, 2026
2a4801a
fix(eslint-plugin-gamut): type recommended severities as literals
dreamwasp Oct 16, 2026
078cc96
fix(gamut-styles): depend on csstype
dreamwasp Oct 16, 2026
6c5d4f0
fix(gamut): restore ^ ranges on sibling @skillsoft packages
dreamwasp Oct 16, 2026
dbfcd1e
docs(gamut-scope-swap): explain stale pkg.pr.new previews
dreamwasp Oct 16, 2026
6409a14
Merge branch 'main' into cass-gmt-1790
dreamwasp Oct 16, 2026
2433af1
build(gamut): keep @types/marked as a dependency only
dreamwasp Oct 16, 2026
23a045c
fix markdown nan
dreamwasp Oct 16, 2026
dd93685
fix(gamut-styles): make @emotion/cache and stylis peer dependencies a…
dreamwasp Oct 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
"fixed": [
[
"@skillsoft/gamut-agent-tools",
"@skillsoft/gamut-codemods",
"@skillsoft/gamut-icons",
"@skillsoft/gamut-illustrations",
"@skillsoft/gamut-patterns",
"@skillsoft/gamut-styles",
"@skillsoft/gamut-tests",
"@skillsoft/gamut",
"@skillsoft/variance"
]
Expand Down
17 changes: 17 additions & 0 deletions .changeset/consumer-friendly-deps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
'@skillsoft/gamut': patch
'@skillsoft/gamut-styles': patch
'@skillsoft/gamut-icons': patch
'@skillsoft/gamut-illustrations': patch
'@skillsoft/gamut-patterns': patch
'@skillsoft/gamut-tests': patch
'@skillsoft/variance': patch
---

Fewer packages to install by hand. `@skillsoft/gamut` now needs only `react`, `react-dom`, `@emotion/react`, and `@emotion/styled` alongside it.

- `@skillsoft/gamut-styles`: `stylis`, `lodash`, and `@emotion/cache` are now regular dependencies instead of peer dependencies.
- `@skillsoft/gamut-icons`: dropped an unused `lodash` peer dependency.
- `@skillsoft/variance`: the `typescript` peer dependency is now optional.
- `@skillsoft/*` packages depend on each other with `^` ranges instead of exact versions, so installs share one copy of `gamut-styles` and `variance`.
- `@skillsoft/gamut-tests`: `component-test-setup` is now `^0.3.1` instead of `*`.
5 changes: 5 additions & 0 deletions .changeset/eslint-plugin-gamut-config-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@skillsoft/eslint-plugin-gamut': patch
---

`configs.recommended` uses literal `'error'` severities, so the plugin type-checks as an ESLint `Plugin` in a typed flat config (`plugins: { gamut }`).
5 changes: 5 additions & 0 deletions .changeset/gamut-codemods-markdown-video-overrides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@skillsoft/gamut-codemods': minor
---

`scope-swap` now covers the Markdown video changes. `<Markdown>` no longer renders `<iframe>` and `<video>` through `Video` by default, and `skipDefaultOverrides.iframe` / `.video` are gone. The new `markdown-video-overrides` migration adds `iframeOverride` / `videoOverride` (with `Iframe` and `MarkdownVideo` imported from `/Video`) to each `<Markdown>` that didn't opt out, so rendering is unchanged. Where a skip was `true`, it writes `iframeOverride={undefined}` so a second run stays a no-op. Video moves also print a checklist item for the `@vidstack/react` and `react-player` peer dependencies.
5 changes: 5 additions & 0 deletions .changeset/gamut-codemods-scope-swap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@skillsoft/gamut-codemods': minor
---

Add `@skillsoft/gamut-codemods` with a `scope-swap` preset for moving a repo from `@codecademy/gamut*` to `@skillsoft/gamut*`. Run `npx @skillsoft/gamut-codemods scope-swap .` from a clean working tree. It renames imports, mocks, and dependencies, moves `Video` imports to `@skillsoft/gamut/Video`, rewrites `/dist/` deep imports, replaces `@codecademy/gamut-kit`, and finishes with a list of what's left to fix by hand.
5 changes: 5 additions & 0 deletions .changeset/gamut-form-field-styles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@skillsoft/gamut': minor
---

Export `formFieldStyles`, `formFieldPaddingStyles`, and `conditionalStyles` from the package root, for custom inputs that should look like `Input`, such as third-party hosted payment fields. The rest of `Form/styles` stays internal. Coming from `@codecademy/gamut/dist/Form/styles`, `npx @skillsoft/gamut-codemods scope-swap .` rewrites imports of these three.
15 changes: 15 additions & 0 deletions .changeset/gamut-menu-selectdropdown-renames.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
'@skillsoft/gamut': minor
---

**Breaking:** export Menu's list elements and SelectDropdown's option component from the package root, under new names that don't collide with the public `List` component and `IconOption` type.

| Old (`dist/Menu/elements`, `dist/Form/SelectDropdown/elements`) | New (`@skillsoft/gamut`) |
| --------------------------------------------------------------- | ----------------------------------- |
| `List`, `ListProps` | `MenuList`, `MenuListProps` |
| `ListItem`, `ListItemProps` | `MenuListItem`, `MenuListItemProps` |
| `ListLink`, `ListLinkProps` | `MenuListLink`, `MenuListLinkProps` |
| `ListButton` | `MenuListButton` |
| `IconOption` (the component) | `IconOptionComponent` |

`MenuToolTipWrapper` is now exported from the root too. The `IconOption` type is unchanged. Coming from `@codecademy/gamut`, `npx @skillsoft/gamut-codemods scope-swap .` rewrites these imports for you.
6 changes: 6 additions & 0 deletions .changeset/gamut-scope-swap-skill.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@skillsoft/gamut-agent-tools': minor
'@skillsoft/gamut-codemods': patch
---

Add the `gamut-scope-swap` agent skill. It helps with the `@codecademy/gamut*` to `@skillsoft/gamut*` move alongside the `scope-swap` codemod: it reads the warnings and leftovers, and fixes what the codemod can't rewrite. The codemod README now points to it.
5 changes: 5 additions & 0 deletions .changeset/gamut-styles-csstype.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@skillsoft/gamut-styles': patch
---

Add `csstype` as a dependency. The published types import from it, and it only resolved before because `@skillsoft/variance` depends on it.
6 changes: 6 additions & 0 deletions .changeset/gamut-video-node10-and-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@skillsoft/gamut': patch
---

- `@skillsoft/gamut/Video` now resolves under TypeScript's `moduleResolution: "node"` (node10) and in bundlers that ignore `package.json#exports`, through a `Video/package.json` stub.
- Export the `HTMLToReactNode` and `ButtonBaseProps` types from the package root.
12 changes: 12 additions & 0 deletions .changeset/nice-peaches-hear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@skillsoft/eslint-plugin-gamut': patch
'@skillsoft/gamut': patch
'@skillsoft/gamut-icons': patch
'@skillsoft/gamut-illustrations': patch
'@skillsoft/gamut-patterns': patch
'@skillsoft/gamut-styles': patch
'@skillsoft/gamut-tests': patch
'@skillsoft/variance': patch
---

Swap Emotion's transform to swc/plugin and explicit type exporting
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ packages/gamut-patterns/src/patterns
packages/code-connect
.nx
packages/gamut-agent-tools/skills/*-workspace
packages/gamut-codemods/**/__testfixtures__
5 changes: 4 additions & 1 deletion .github/workflows/preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ name: Preview

on:
pull_request:
branches: [main]
# TEMPORARY: cass-gmt-1795 is here so PRs stacked on it (the
# @skillsoft/gamut-codemods PR) publish previews. Revert this before
# either branch ships to main.
branches: [main, cass-gmt-1795]

env:
NODE_OPTIONS: '--max_old_space_size=8196'
Expand Down
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ packages/gamut-patterns/src/patterns
packages/gamut-styles/**/*.d.ts
packages/styleguide/stories/Core/Atoms/Markdown/*.md
packages/code-connect/**/*
# Codemod fixtures are exact expected output, formatting included.
packages/gamut-codemods/**/__testfixtures__

/.nx/cache
/.nx/workspace-data
6 changes: 5 additions & 1 deletion packages/eslint-plugin-gamut/src/recommended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ export default {
'@skillsoft/gamut/import-paths': 'error',
'@skillsoft/gamut/require-styled-target-for-selector': 'error',
},
};
/*
Literal severities, so the export fits ESLint's Plugin type. As `string`,
`plugins: { gamut }` in a typed flat config doesn't type-check.
*/
} as const;
6 changes: 6 additions & 0 deletions packages/gamut-agent-tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ The first time you run `gamut plugin install` or `update`, it installs `@skillso

Before large PRs, or when onboarding an existing codebase, run the `gamut-review` skill to audit for Gamut usage — dependencies, setup, import patterns, `styled()` wrapping that bypasses system props, hardcoded colors, bespoke component duplication, and test conventions.

### Moving from `@codecademy/gamut`

If your app still depends on `@codecademy/gamut*`, the `gamut-scope-swap` skill helps with the move to `@skillsoft/gamut*`. It works alongside the [`@skillsoft/gamut-codemods`](../gamut-codemods/README.md) `scope-swap` preset. The codemod does the mechanical rewrite. The skill reads what it reports, including warnings, leftovers, and next steps, and helps with the parts it can't rewrite: deep imports, `Video`, renamed Menu exports, tsconfig `dom`, jest mocks, ESLint plugin keys, Module Federation config, and preview builds. It doesn't run the codemod unless you ask it to.

Install the plugin after the swap. The `gamut` CLI comes from `@skillsoft/gamut`, so that package has to be in the app first.

## The CLI lives here, not in `@skillsoft/gamut`

`@skillsoft/gamut`'s `bin/gamut.mjs` is a thin bootstrap shim: it only knows how to check whether `@skillsoft/gamut-agent-tools` is installed, auto-install it if not (for `install`/`update`), and print help. Once that's resolved, it dynamically imports the actual `install`/`update`/`list`/`remove` command bodies from `cli/commands/plugin/` in *this* package and hands off execution to them.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Breaking changes: `@codecademy/gamut*` → `@skillsoft/gamut*`

Short list of what changed. The codemod handles most of these. Entries marked **manual** need a person. Source: `packages/gamut-codemods/src/presets/scope-swap/manifest.ts`.

## Packages

- Every `@codecademy/*` Gamut package is now `@skillsoft/*`: `gamut`, `gamut-styles`, `gamut-icons`, `gamut-illustrations`, `gamut-patterns`, `gamut-tests`, and `variance`.
- `eslint-plugin-gamut` is now `@skillsoft/eslint-plugin-gamut`.
- `@codecademy/gamut-kit` is removed, with no replacement. Depend on the individual packages it bundled.

## Imports

- `Video` and `VideoProps` moved off the root. Import them from `@skillsoft/gamut/Video`. **Manual** for namespace imports and `export *`.
- Menu's `List`, `ListProps`, `ListItem`, `ListItemProps`, `ListLink`, `ListLinkProps`, and `ListButton` are renamed `MenuList*` and `MenuListButton`. The codemod keeps local names with an alias, e.g. `MenuList as List`.
- SelectDropdown's `IconOption` is renamed `IconOptionComponent`.
- `ButtonBase` is not public. Use `FillButton`, `StrokeButton`, `TextButton`, `IconButton`, or `CTAButton`. **Manual.**
- From `Form/styles`, only `formFieldStyles`, `formFieldPaddingStyles`, and `conditionalStyles` are public. Anything else there is internal. **Manual.**
- Deep `/dist/` imports for these are promoted to the package root: form and select types, `Box`, `Tip`, `Button`, `Markdown` overrides, `AssetProvider`, the icon `types` and `props`, and the variance config types. Any `dist` path not on that list is unmapped. **Manual.**

## Runtime

- Gamut is now a real singleton. Module Federation host and remotes must share the same version, so update each remote's `shared` config and deploy them together. **Manual.**
- Next.js apps that set `experimental.esmExternals: false` can fail to build or prerender on `@emotion/*` or `react-select` default imports. Remove `esmExternals: false` and any `@emotion/*` aliases. If you can't yet, see `NEXT_EMOTION_INTEROP.md` for the fallback. **Manual.**

## Build and tooling

- `Video` used to bring DOM types in through the root import. Add `"dom"` to a tsconfig's `lib` if type-checking fails after the move. **Manual.**
- ESLint rule prefix `gamut/` becomes `@skillsoft/gamut/` in directives and legacy configs. Rule names don't change. Flat configs need the plugin registered under the matching key. **Manual** for flat configs.
- Jest mocks of the root package that stub `Video` should mock `@skillsoft/gamut/Video`. **Manual.**
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Next.js and Emotion default imports

Use this if a Next.js app fails after moving to `@skillsoft/gamut*`.

## Symptoms

- Production build or prerender fails with `Element type is invalid: expected a string ... but got: object`. This often comes from `SelectDropdown`, which uses `react-select`.
- The server fails in `_app` with `c(...) is not a function`.

## Cause

With `experimental.esmExternals: false`, Next `require()`s every server external package. `@skillsoft/gamut` and `@skillsoft/gamut-styles` ship strict ESM `.mjs` files. A default import of a CJS package that sets `__esModule` (`react-select`, `@emotion/styled`, `@emotion/cache`, `@emotion/is-prop-valid`) gets the whole module object instead of the default export.

## Fix: use native ESM externals

1. Remove `experimental.esmExternals: false` from `next.config.js`.
2. Remove any `resolve.alias` entries for `@emotion/is-prop-valid`, `@emotion/styled`, or `@emotion/cache`.
3. Remove `@emotion/*` and `react-select` from `transpilePackages`. Keep `@skillsoft/*` packages there if they ship CSS imports.

Next then loads externals with `import()`, so Node resolves each package's `import` entry and default imports work. To confirm, check that the server bundle emits `import("react-select")` instead of `require("react-select")`.

## Fallback: keep `esmExternals: false`

If the app can't drop `esmExternals: false` yet, point the Emotion packages at their ESM builds and transpile them:

```js
const path = require('path');

const emotionEsm = (pkg, file) =>
path.join(path.dirname(require.resolve(`${pkg}/package.json`)), 'dist', file);

// Inside webpack(config, { isServer }), merge into resolve.alias:
'@emotion/is-prop-valid$': emotionEsm(
'@emotion/is-prop-valid',
'emotion-is-prop-valid.esm.js'
),
'@emotion/styled$': emotionEsm(
'@emotion/styled',
isServer ? 'emotion-styled.esm.js' : 'emotion-styled.browser.esm.js'
),
'@emotion/cache$': emotionEsm(
'@emotion/cache',
isServer ? 'emotion-cache.esm.js' : 'emotion-cache.browser.esm.js'
),
```

Add `@emotion/is-prop-valid`, `@emotion/styled`, `@emotion/cache`, and `react-select` to `transpilePackages`.

Plan to remove this fallback. It only exists to work around the `esmExternals` setting.
Loading
Loading