@brightspot/ui 3.0.1-cms-ui-migration.3 → 3.0.1-cms-ui-migration.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +5 -5
  2. package/dist/custom-elements.json +2543 -2543
  3. package/dist/storybook/assets/{ActionBar.stories-CSxtZl7v.js → ActionBar.stories-BZAVK1QG.js} +1 -1
  4. package/dist/storybook/assets/{ActionItem.stories-BWcMRMP3.js → ActionItem.stories-BqiWvlWi.js} +1 -1
  5. package/dist/storybook/assets/{Avatar.stories-CYTUGXzH.js → Avatar.stories-DkdB6hd_.js} +1 -1
  6. package/dist/storybook/assets/{AvatarGroup.stories-CSYBYo_5.js → AvatarGroup.stories-DODqaIix.js} +1 -1
  7. package/dist/storybook/assets/{Badge.stories-LuF4BuVr.js → Badge.stories-DZoum08S.js} +1 -1
  8. package/dist/storybook/assets/{Button-CrXCMxHb.js → Button-BkmBgNO-.js} +1 -1
  9. package/dist/storybook/assets/{Button.stories-JVwxdrdM.js → Button.stories-BFhCL2dp.js} +1 -1
  10. package/dist/storybook/assets/{ButtonGroup.stories-qtq64a1H.js → ButtonGroup.stories-DlTGTvkq.js} +1 -1
  11. package/dist/storybook/assets/{Celebrate.stories-DjTtaSd6.js → Celebrate.stories-m4d4zTEz.js} +1 -1
  12. package/dist/storybook/assets/{Checkbox.stories-v1Pr5mL6.js → Checkbox.stories-Y253YeU7.js} +1 -1
  13. package/dist/storybook/assets/{CircularProgress.stories-DkV7PJ4D.js → CircularProgress.stories-6BD8uV5G.js} +1 -1
  14. package/dist/storybook/assets/{ClipboardMixin.stories-Dh5c7uSM.js → ClipboardMixin.stories-BkH66rIU.js} +1 -1
  15. package/dist/storybook/assets/{Color-6BZIO3FS-B1gcREt6.js → Color-6BZIO3FS-iG0OjPBU.js} +1 -1
  16. package/dist/storybook/assets/{Colors.stories-DnubtRqn.js → Colors.stories-BxiyQnEg.js} +1 -1
  17. package/dist/storybook/assets/{CombinedEffects.stories-By6akSve.js → CombinedEffects.stories-Bs3U7qRl.js} +1 -1
  18. package/dist/storybook/assets/{ComponentStatesMixin-CPLGv3h-.js → ComponentStatesMixin-DampYb5c.js} +1 -1
  19. package/dist/storybook/assets/{ComponentStatesMixin.stories-CiQ_lyhm.js → ComponentStatesMixin.stories-CZ2OW7as.js} +1 -1
  20. package/dist/storybook/assets/{CopyToClipboard.stories-cJ7rl3mj.js → CopyToClipboard.stories-CdlghjaE.js} +1 -1
  21. package/dist/storybook/assets/{Debounce.stories-Bw-goobU.js → Debounce.stories-CymT8PnT.js} +1 -1
  22. package/dist/storybook/assets/{DocsRenderer-LL677BLK-CNW57dGQ.js → DocsRenderer-LL677BLK-dqHCo-GE.js} +3 -3
  23. package/dist/storybook/assets/{Dropdown.stories-CwC3HXXd.js → Dropdown.stories-B6JwKg-I.js} +1 -1
  24. package/dist/storybook/assets/{EmptyState.stories-BUEJwuhP.js → EmptyState.stories-Bk229lPH.js} +1 -1
  25. package/dist/storybook/assets/{Events.stories-D1mf9buv.js → Events.stories-C8-k9cx8.js} +1 -1
  26. package/dist/storybook/assets/{Heading.stories-DO906G4P.js → Heading.stories-DIdnAQRG.js} +1 -1
  27. package/dist/storybook/assets/{HueRipple.stories-BOySRSZB.js → HueRipple.stories-B1gXAEaH.js} +1 -1
  28. package/dist/storybook/assets/{Icon.stories-BsqgTbdG.js → Icon.stories--1VJ0_yt.js} +1 -1
  29. package/dist/storybook/assets/{IconButton.stories-aza1AAKk.js → IconButton.stories-CS2rEIir.js} +1 -1
  30. package/dist/storybook/assets/{LinearProgress.stories-CDYmiiex.js → LinearProgress.stories-Bx0CQQls.js} +1 -1
  31. package/dist/storybook/assets/{Pagination.stories-LXB-x7YB.js → Pagination.stories-B4AogTXB.js} +1 -1
  32. package/dist/storybook/assets/{Popover.stories-DY1HesPJ.js → Popover.stories-BR88DPgU.js} +1 -1
  33. package/dist/storybook/assets/{ReadyMixin-DmOC67IJ.js → ReadyMixin-n6qZO39Y.js} +1 -1
  34. package/dist/storybook/assets/{RovingTabindexMixin.stories-BWy0Rq8d.js → RovingTabindexMixin.stories-1xTJSMSv.js} +1 -1
  35. package/dist/storybook/assets/{Rtc.stories-DrmdqqbI.js → Rtc.stories-Rt0A_rUZ.js} +1 -1
  36. package/dist/storybook/assets/{ScrollShadow.stories-DiKFPazh.js → ScrollShadow.stories-CjLdJyYu.js} +1 -1
  37. package/dist/storybook/assets/{Switch.stories-BgFnw8_z.js → Switch.stories-CF8wO4v2.js} +1 -1
  38. package/dist/storybook/assets/{Tab.stories-c2wLMooF.js → Tab.stories-C8XNshog.js} +1 -1
  39. package/dist/storybook/assets/{Tabs.stories-CjH8seNP.js → Tabs.stories-B01l4rQx.js} +1 -1
  40. package/dist/storybook/assets/{Throttle.stories-CXysc_QE.js → Throttle.stories-Bpi0K5j9.js} +1 -1
  41. package/dist/storybook/assets/{Tooltip.stories-6qzyByPm.js → Tooltip.stories-BC4zMiZ1.js} +1 -1
  42. package/dist/storybook/assets/{Upload.stories-BLxykydQ.js → Upload.stories-2pWv_fZ1.js} +1 -1
  43. package/dist/storybook/assets/{UploadItem.stories-CcfcqdJW.js → UploadItem.stories-aLeAUM7y.js} +1 -1
  44. package/dist/storybook/assets/{Welcome.stories-CzYS_3fH.js → Welcome.stories-DJV83eb7.js} +1 -1
  45. package/dist/storybook/assets/{Widget.stories-Du7T4LAI.js → Widget.stories-Cz0i2o6L.js} +1 -1
  46. package/dist/storybook/assets/{WithTooltip-65CFNBJE-D4LfXdYt.js → WithTooltip-65CFNBJE-D8QwVYG8.js} +1 -1
  47. package/dist/storybook/assets/{blocks-DR3fGePu.js → blocks-BFmpEZRy.js} +5 -5
  48. package/dist/storybook/assets/{formatter-EIJCOSYU-Cf01216O.js → formatter-EIJCOSYU-CdwdJOPy.js} +1 -1
  49. package/dist/storybook/assets/if-defined-gbJXriW-.js +1 -0
  50. package/dist/storybook/assets/{iframe-CQArUhO8.js → iframe-CyssRDCd.js} +4 -4
  51. package/dist/storybook/assets/{index-B1uI_67G.js → index-B82i8dhg.js} +1 -1
  52. package/dist/storybook/assets/{onFind-BpFkN2Rh.js → onFind-BFI1uIxr.js} +1 -1
  53. package/dist/storybook/assets/{onFind.stories-Cxdeg69X.js → onFind.stories-zZjQs_Gn.js} +1 -1
  54. package/dist/storybook/assets/{onRemove.stories-BHEWpNrE.js → onRemove.stories-pFBwAIex.js} +1 -1
  55. package/dist/storybook/assets/{onVisible.stories-DFJ3S_ZS.js → onVisible.stories-5dErOVRq.js} +1 -1
  56. package/dist/storybook/assets/{style-map-DJ83UC3V.js → style-map-D0EcLEWO.js} +1 -1
  57. package/dist/storybook/assets/{syntaxhighlighter-ED5Y7EFY-zYN83mxK.js → syntaxhighlighter-ED5Y7EFY--2h_dVga.js} +1 -1
  58. package/dist/storybook/iframe.html +1 -1
  59. package/dist/storybook/project.json +1 -1
  60. package/package.json +1 -1
  61. package/src/legacy/tool-ui/src/AnalyticsWidget.css +1 -1
  62. package/src/legacy/tool-ui/src/Board.css +1 -1
  63. package/src/legacy/tool-ui/src/BulkUpload.css +1 -1
  64. package/src/legacy/tool-ui/src/ComboInput.css +1 -1
  65. package/src/legacy/tool-ui/src/Compat.css +5 -5
  66. package/src/legacy/tool-ui/src/ContentEditDrawer.css +1 -1
  67. package/src/legacy/tool-ui/src/Dialog.css +1 -1
  68. package/src/legacy/tool-ui/src/FormFilter.css +1 -1
  69. package/src/legacy/tool-ui/src/Icon/index.css +1 -1
  70. package/src/legacy/tool-ui/src/ImageEditor.css +1 -1
  71. package/src/legacy/tool-ui/src/Incompatible.css +2 -2
  72. package/src/legacy/tool-ui/src/LinkCarousel.css +1 -1
  73. package/src/legacy/tool-ui/src/Page.css +1 -1
  74. package/src/legacy/tool-ui/src/RepeatableContentInputGroup.css +1 -1
  75. package/src/legacy/tool-ui/src/RichText.css +1 -1
  76. package/src/legacy/tool-ui/src/SearchWidget.css +2 -2
  77. package/src/legacy/tool-ui/src/SearchWidgetAdvanced.css +1 -1
  78. package/src/legacy/tool-ui/src/Widget.css +1 -1
  79. package/src/legacy/tool-ui/src/main/webapp/dist/v5.5e5d7f655e174ddd85f5.css +5 -0
  80. package/dist/storybook/assets/if-defined-DaMmbcIU.js +0 -1
  81. package/docs/adr/0001-retire-cms-ui-package-fold-under-src-legacy.md +0 -78
  82. package/docs/adr/0002-yarn-workspaces-preserve-cms-ui-deps.md +0 -130
  83. package/docs/adr/0003-bundle-equivalence-as-fold-acceptance-criterion.md +0 -286
  84. package/src/legacy/tool-ui/src/main/webapp/dist/v5.5e3fdf0f0b20b4e3c170.css +0 -5
@@ -1 +0,0 @@
1
- import{E as r}from"./iframe-CQArUhO8.js";const m=o=>o??r;export{m as o};
@@ -1,78 +0,0 @@
1
- # 1. Retire `@brightspot/cms-ui`; fold cms-ui under `@brightspot/ui` `src/legacy/tool-ui/`
2
-
3
- Date: 2026-05-18
4
- Status: Accepted
5
-
6
- ## Context
7
-
8
- The earlier migration plan (Phases 0–2, committed on branch `feat/cms-ui-migration`)
9
- extracted brightspot's `cms/tool-ui/` frontend into a new npm sub-package
10
- `@brightspot/cms-ui` at `cms/`, registered with release-please as a separate
11
- track, with brightspot's gradle wrapper consuming it via `yarn link`. Phase 4
12
- (Vite swap) was attempted then reverted on 2026-05-13. `@brightspot/cms-ui@0.1.0`
13
- was scaffolded in-repo but was **never published to npm**.
14
-
15
- Maintaining two npm packages for two related code surfaces has cost: separate
16
- release-please track, separate `cms-ui/v*` tag stream, separate CI publish
17
- flow, separate `package.json` to maintain, separate `yarn link` target for the
18
- brightspot consumer. The cms-ui surface is also slated for retirement
19
- short-term (cms-ui's v4 entry is on a removal path; v5 will eventually follow
20
- or be rewritten in the modern stack).
21
-
22
- ## Decision
23
-
24
- - Retire the `@brightspot/cms-ui` npm package name. Drop its release-please
25
- track. Never publish it.
26
- - Move the cms-ui source tree to `src/legacy/tool-ui/` inside the
27
- `@brightspot/ui` repo.
28
- - `@brightspot/ui` becomes the single published npm package for both the
29
- modern design-system surface (`dist/`) and the legacy cms-ui webpack output
30
- (`src/legacy/tool-ui/src/main/webapp/dist/`).
31
- - The directory marker `legacy` is load-bearing — tooling carve-outs (tsc,
32
- storybook, conventions, prettier, root eslint) scope around `src/legacy/**`.
33
-
34
- ## Consequences
35
-
36
- ### Positive
37
-
38
- - One published artifact. Consumers pull one tarball. The brightspot consumer's
39
- `yarn link` target changes from `@brightspot/cms-ui` to `@brightspot/ui`,
40
- but the file paths it reads stay structurally similar.
41
- - One release-please track. No more `cms-ui/v*` tag stream, no separate
42
- publish step.
43
- - `@brightspot/cms-ui` was never on npm, so retirement is free —
44
- no deprecation, no migration period.
45
- - `cms-ui/` retirement when v4 (and eventually v5) leaves becomes a directory
46
- delete, not a package deprecation.
47
-
48
- ### Negative
49
-
50
- - `@brightspot/ui` 3.x consumers who never touch cms-ui still pull a tarball
51
- with the legacy webpack output. Bloat is temporary — disappears as v4/v5
52
- retire.
53
- - Any commit touching `src/legacy/tool-ui/` drives `@brightspot/ui` version
54
- bumps. CHANGELOG includes cms-ui entries during the retirement window.
55
- Acceptable given the limited duration.
56
- - Forced dep convergence at install time for some packages
57
- (TypeScript, prettier, tailwindcss, Lit) — addressed by ADR-0002 via yarn
58
- workspaces.
59
-
60
- ### Cross-repo follow-on
61
-
62
- - `brightspot/cms/tool-ui/build-css.mjs` updates its file-read path from
63
- `node_modules/@brightspot/cms-ui/legacy/tool-ui/src/main/webapp/dist/`
64
- to `node_modules/@brightspot/ui/src/legacy/tool-ui/src/main/webapp/dist/`.
65
- - `brightspot/cms/tool-ui/package.json` declares `@brightspot/ui` as the
66
- consumer dep (yarn-linked during HITL, registry dep at publish time).
67
-
68
- ## Alternatives considered
69
-
70
- 1. **Keep two packages, source under one repo.** Source moves but release-please
71
- still cuts both. Rejected — preserves two release streams and two CHANGELOGs
72
- for code on a retirement path; the cost we want to remove stays.
73
- 2. **Subpath export (`@brightspot/ui/cms`).** Rejected — the brightspot
74
- consumer reads files via filesystem in `build-css.mjs`, not via ESM imports.
75
- `exports` subpaths don't add value for this consumption pattern.
76
- 3. **Leave cms-ui at `cms/` as today.** Rejected — the user wants the source
77
- under `src/` for navigability and as a step toward eventual integration with
78
- the modern surface.
@@ -1,130 +0,0 @@
1
- # 2. Use a postinstall hook (not yarn workspaces, not dep convergence) to preserve cms-ui's pin set
2
-
3
- Date: 2026-05-18
4
- Status: Accepted
5
-
6
- > **Revision note (2026-05-18, mid-fold)**: Originally accepted as
7
- > "use yarn workspaces." Reversed during commit #3 implementation after
8
- > discovering yarn 1's workspaces require `"private": true` on the host
9
- > project, which would block `npm publish` on `@brightspot/ui` without
10
- > a publish-pipeline overhaul (clean-publish swap or
11
- > prepack/postpack lifecycle gymnastics). The independent-install
12
- > approach below achieves the same goal (preserve cms-ui's pin set with
13
- > zero cross-contamination) without touching the publish pipeline.
14
-
15
- ## Context
16
-
17
- ADR-0001 folds cms-ui under `@brightspot/ui`'s `src/legacy/tool-ui/`. The two
18
- codebases have meaningfully different dep stacks:
19
-
20
- | Dep | `@brightspot/ui` root | cms-ui (today's `cms/`) |
21
- |---|---|---|
22
- | TypeScript | 5.9.3 | ^4.7.3 |
23
- | Lit | ^3.3.0 | ^2.2.6 |
24
- | Prettier | ^3.2.5 (8.x in practice) | 3.2.5 (pinned via `resolutions`) |
25
- | Tailwindcss | peer ^3.4.x (19.x in practice) | 3.4.13 (pinned via `resolutions`) |
26
- | `@brightspot/ui` | n/a (self) | 1.2.0 (legacy tailwind preset source) |
27
- | Module type | `"type": "module"` (ESM) | unset (commonjs default) |
28
-
29
- These cannot share a single hoisted `node_modules` without breaking either the
30
- modern surface (downgrading Lit/TS) or bundle equivalence with brightspot's
31
- production tool-ui build (the acceptance criterion in ADR-0003 requires
32
- byte-identical webpack inputs).
33
-
34
- ## Decision
35
-
36
- - `src/legacy/tool-ui/` is a **standalone yarn-1 subproject** with its own
37
- `package.json` (`"private": true`), `yarn.lock`, and `node_modules` tree.
38
- - The workspace `package.json` mirrors today's `cms/package.json` (same deps,
39
- same `resolutions`, no `"type"` field so it defaults to commonjs).
40
- - Root `package.json` has a `postinstall` script that runs
41
- `cd src/legacy/tool-ui && yarn install`, so a single root `yarn install`
42
- produces both installs in sequence.
43
- - The published `@brightspot/ui` tarball includes the workspace's webpack
44
- output via the root `files` field; the workspace `package.json` itself
45
- is not in the tarball.
46
- - Build orchestration: root `yarn build` stays modern-only (preserves design-
47
- system iteration speed). `prepack` extends to also invoke
48
- `cd src/legacy/tool-ui && yarn build`, so any `npm pack` / publish always
49
- contains both surfaces.
50
- - Local cms-ui dev story is preserved: `cd src/legacy/tool-ui && yarn build`
51
- works identically to today's `cd cms/legacy/tool-ui && yarn build`, minus
52
- the `cd` shim Phase 1 had to add.
53
-
54
- ## Consequences
55
-
56
- ### Positive
57
-
58
- - Bundle equivalence is achievable (see ADR-0003) because cms-ui's exact
59
- toolchain (TS 4.7, Lit 2.2.6, babel, webpack 5, loaders) is preserved at
60
- install time. Module resolution from `src/legacy/tool-ui/` walks the local
61
- `node_modules` first and finds the pinned versions.
62
- - ESM/commonjs isolation comes for free: each project has its own
63
- `package.json` and `node_modules`.
64
- - No publish-pipeline changes needed. `@brightspot/ui` stays unprivate; CI's
65
- bare `npm publish` continues to work.
66
- - `@brightspot/ui@1.2.0` (the legacy tailwind preset source) installs cleanly
67
- into the workspace's `node_modules/@brightspot/ui/` from the npm registry —
68
- no self-reference conflict with the host project, since yarn workspace
69
- semantics aren't engaged.
70
- - cms-ui's local-dev workflow is unchanged (slightly cleaner — drops the
71
- Phase 1 `cd legacy/tool-ui &&` script prefix once commit #4 lands).
72
- - Future retirement is a directory delete + remove the postinstall hook,
73
- not a complex unwind.
74
-
75
- ### Negative
76
-
77
- - Two `package.json` files in the repo (root + workspace). Slight cognitive
78
- overhead vs a single converged manifest. Mitigation: workspace `package.json`
79
- is structurally a near-copy of today's `cms/package.json`, so it's not new
80
- surface.
81
- - Two `yarn.lock` files (root + workspace). Same arrangement as Phase 1 had
82
- pre-fold; no new burden.
83
- - Two `node_modules` trees. The ~12 deps that genuinely overlap between root
84
- and workspace (loglevel, tabbable, broadcast-channel, uuid, webpack,
85
- ts-node, css-loader, mini-css-extract-plugin, postcss-import, postcss-loader,
86
- style-loader, webpack-cli, webpack-merge) install in both. Disk overhead
87
- ~100MB, dwarfed by cms-ui's own heavy deps.
88
- - Root `yarn install` becomes slower (cms-ui's heavy install runs too).
89
- Mitigation: matches Phase 1's pre-fold total cost; design-system contributors
90
- who never edit cms-ui still incur it. Acceptable for the retirement window.
91
- - Workspace deps aren't visible to `yarn workspace <name> <cmd>` ergonomics
92
- (those commands need yarn workspaces). Mitigation: `cd src/legacy/tool-ui &&
93
- yarn <cmd>` works fine — matches Phase 1.
94
- - The webpack `nodeModulesPath` in `src/legacy/tool-ui/webpack.common.ts` —
95
- used to resolve vendored static assets like `lucide-static` and
96
- `iframe-resizer` — must point at `src/legacy/tool-ui/node_modules`.
97
- Verified empirically in commit #4.
98
-
99
- ## Alternatives considered
100
-
101
- 1. **Yarn 1 workspaces (originally accepted, then reversed).**
102
- Hits the `"private": true` constraint on the host project. Would require:
103
- - Adding `"private": true` to `@brightspot/ui`'s root, AND
104
- - Reworking CI's `npm publish` step (clean-publish, prepack swap, or
105
- two-file `package.json` / `package.publish.json` pattern).
106
-
107
- Yarn 1 workspaces' main benefit — hoisting deps shared by root and
108
- workspace — would save ~100MB of disk for ~12 deps. The cost of the
109
- publish-pipeline rework outweighs that gain for retirement-pending code.
110
- Rejected.
111
-
112
- 2. **Yarn 4 / Yarn Berry / pnpm workspaces.**
113
- Yarn 4 doesn't require host-project `"private": true` for workspaces.
114
- Migrating the repo away from yarn 1 is a worthwhile initiative but
115
- explicitly out of scope for this fold. Tracked separately if cms-ui
116
- retirement timeline extends.
117
-
118
- 3. **Converge to brightspot-ui's modern pins; fix what breaks.**
119
- Rejected. Lit 2 → Lit 3 emit-byte differences would cascade through
120
- every v5 module. Bundle equivalence becomes unachievable; confidence
121
- relies on functional/Playwright testing only.
122
-
123
- 4. **Aliased dual install (`lit` + `lit-2`).**
124
- Rejected. Requires rewriting hundreds of `import … from 'lit'` statements
125
- in cms-ui source to `'lit-2'`. Bytes diverge anyway because import
126
- specifiers differ. Cost without the benefit.
127
-
128
- 5. **cms-ui's pins win at root (no subproject).**
129
- Rejected. Downgrades `@brightspot/ui`'s modern stack (Storybook 10,
130
- vitest 4, Lit 3 features in use today) — regression on the stable surface.
@@ -1,286 +0,0 @@
1
- # 3. Bundle equivalence as the fold's acceptance criterion
2
-
3
- Date: 2026-05-18
4
- Status: Accepted (with near-equivalence revision)
5
-
6
- > **Revision note (2026-05-18, end of fold):** Strict 100% bundle
7
- > equivalence is **not achievable** without reverting Phase 1's
8
- > package.json deviations (which would re-break the workspace as a
9
- > standalone subproject). Final state after commit #6's verify run
10
- > shows targeted, harmless divergences:
11
- >
12
- > - `core-js`: workspace 3.49.0 vs golden 3.36.0 (workspace's fresh
13
- > `yarn install` resolved this transitive differently from brightspot's
14
- > lockfile). Causes ~150 extra/missing core-js polyfill modules in the
15
- > stats diff and downstream license-sidecar content drift on `v4.js`
16
- > and `v5.js`. Polyfill semantics are identical for the
17
- > browsers cms-ui targets; the diff is purely byte-level.
18
- > - `iframeResizer.contentWindow.min.js`: byte diff between the two
19
- > `iframe-resizer@4.3.8` installations. Same functional content.
20
- > - `v5.css`: ~5 KB diff (~0.1%) downstream of the core-js shift through
21
- > babel polyfill inclusion. The brightspot Java content extraction
22
- > (commit #5) closed the original 153 `\!frame` selectors gap that was
23
- > the headline Phase 1 divergence.
24
- >
25
- > The verify script (commit #6) ships as a one-shot diagnostic, not a
26
- > CI gate. Future cms-ui changes will drift further; bundle equivalence
27
- > stops being a useful signal once intentional changes accumulate. The
28
- > brightspot consumer's correctness depends on the same v3-era babel +
29
- > webpack toolchain and the same runtime semantics, both preserved.
30
-
31
- ## Context
32
-
33
- The fold (ADR-0001) relocates cms-ui from `cms/legacy/tool-ui/` to
34
- `src/legacy/tool-ui/` and replaces the separate `@brightspot/cms-ui` npm
35
- package with a yarn-workspace surface inside `@brightspot/ui` (ADR-0002).
36
-
37
- The cms-ui webpack output is consumed downstream by brightspot's gradle
38
- wrapper (`brightspot/cms/tool-ui/build-css.mjs`), which reads JS bundles
39
- off disk, passes them through to the running CMS, and regenerates CSS
40
- locally with brightspot's Java content paths visible (Phase 2 commit
41
- `afa31ba572a`). The browser runs whatever webpack emitted.
42
-
43
- The user's stated top concern for the fold is confidence that the post-fold
44
- build is **backward-compatible with brightspot's currently-running production
45
- tool-ui build**. The most trustworthy signal for that, available without
46
- standing up a Playwright matrix, is byte-equivalence of the emitted webpack
47
- bundles.
48
-
49
- Phase 1's `verify-bundle-equivalence.mjs` measured cms-ui (built from `cms/`)
50
- against brightspot's pre-migration tool-ui at SHA `28876f4e9f6` and reported
51
- 99.96% module-source match: **2450/2451 module sources byte-identical,
52
- 1/4 CSS chunks byte-identical**. Both divergences (1 module + 3 CSS chunks)
53
- trace to the same cause: tailwind's `content:` paths in
54
- `tailwind.config.ts` point at 16 brightspot Java sources via `../../cms/db/.../CmsTool.java`-
55
- style relative paths. From brightspot's own `cms/tool-ui/` those files resolve;
56
- from cms-ui's location in brightspot-ui they don't, so tailwind silently
57
- skips them, fewer utilities are generated, and the entry module that
58
- imports the resulting CSS chunk diverges.
59
-
60
- ## Stale-dist self-perpetuation (2026-05-18 finding)
61
-
62
- During initial golden generation we discovered that cms-ui's webpack build
63
- emits **different `v5.css` bytes depending on prior `dist/` state**, even with
64
- identical source, lockfile, and node_modules.
65
-
66
- Root cause: `clean-webpack-plugin` v4 runs its `cleanOnceBeforeBuildPatterns`
67
- in webpack's `emit` hook — **after** tailwind's PostCSS pass has already
68
- scanned content. Tailwind's `content:` glob `./src/**/*.css` matches
69
- `src/main/webapp/dist/*.css`, so the *previous* build's emitted CSS gets
70
- re-scanned, and class candidates inside it (orphan selectors like
71
- `.btu-button-current` that no source file references anymore) get re-emitted
72
- into the new build. The cycle is self-perpetuating: once a class enters
73
- `v5.css`, it stays.
74
-
75
- Two stable build modes result:
76
-
77
- | Mode | Hash at SHA `28876f4e9f6` | What it represents |
78
- |---|---|---|
79
- | **Cold** | `v5.8acae93faec68b445941.css` | Fresh build with empty `dist/`. What clean CI runs produce. |
80
- | **Warm** | `v5.b665f7f237580883575e.css` | Build with prior `dist/` present. What ran locally during ongoing development. Includes ~12+ orphan rules (~5KB). |
81
-
82
- Both are deterministic given their starting state. JS bundles (`v4.js`, `v5.js`,
83
- `preview.js`) and `v4.css` are byte-identical across modes — only `v5.css`
84
- differs. Orphans don't affect rendering (no DOM uses them) but they
85
- materially affect bundle-equivalence comparisons.
86
-
87
- This is **a latent bug in cms-ui's webpack pipeline**, independent of the
88
- fold. A clean fix (e.g., switching CleanWebpackPlugin to run in `beforeRun`,
89
- or excluding `dist/` from tailwind's content glob) is tracked as a follow-on
90
- to the fold itself.
91
-
92
- For the fold we **capture both goldens** and defer the cold-vs-warm
93
- selection to comparison time, once we have evidence on what brightspot's
94
- production CI actually emits.
95
-
96
- ## Decision
97
-
98
- The fold is "done" when **the post-fold build matches the chosen golden
99
- (cold or warm — see "Stale-dist self-perpetuation" above) at 100%** across
100
- the script's gated buckets:
101
-
102
- | Bucket | Target |
103
- |---|---|
104
- | Module source bodies | 100% (after path normalization) |
105
- | Static-copy assets | 100% byte (`lucide.woff2`, `iframeResizer.contentWindow.min.js`, `iframeResizer.contentWindow.map`) |
106
- | License sidecars — named-entry | 100% content (v4/v5/preview) |
107
- | License sidecars — chunk-numbered | content set equal (renumbering tolerated) |
108
- | CSS chunks | 100% byte (after hash strip) |
109
-
110
- The script's overall pass criterion is **all of the above with zero
111
- mismatches** — the same `ok = …` predicate Phase 1's script already
112
- enforces. We are no longer accepting Phase 1's "1 module + 3 CSS chunks"
113
- as documented exceptions; we resolve them.
114
-
115
- ### Resolving the Java content visibility
116
-
117
- Both Phase 1 divergences resolve when tailwind sees the 16 Java content
118
- paths. The fold uses **pre-extraction into the existing
119
- `src/legacy/tool-ui/src/additional-tailwind-classes.txt`** (currently 62
120
- lines, listing utilities tailwind's content scanner can't otherwise detect).
121
-
122
- Process during the fold:
123
-
124
- 1. From brightspot at SHA `28876f4e9f6`, run tailwind against the 16 Java
125
- files in isolation and capture the set of utilities generated.
126
- Equivalent procedure: scan the 16 Java files with the same regex tailwind
127
- uses for content extraction and capture the candidate class strings.
128
- 2. Append the resulting class list to
129
- `src/legacy/tool-ui/src/additional-tailwind-classes.txt`, deduplicated.
130
- 3. Delete the 16 Java content paths from
131
- `src/legacy/tool-ui/tailwind.config.ts` (they don't resolve from the new
132
- location anyway). The text file is now the single source of truth.
133
- 4. Re-run the fold's webpack build. Diff against the brightspot golden via
134
- `verify-bundle-equivalence.mjs`. Expect 100%.
135
-
136
- Drift management: if the brightspot platform team adds a new tailwind
137
- utility in those Java files, the cms-ui side must regenerate. A
138
- regeneration script (one of the fold's deliverables) supports this.
139
-
140
- ### Golden workflow — dual capture
141
-
142
- Both goldens are captured during fold validation. The cold-vs-warm
143
- selection happens at comparison time, informed by what brightspot's CI
144
- actually emits.
145
-
146
- ```bash
147
- # 1. Cold golden — fresh worktree, no prior dist
148
- cd ~/work/brightspot
149
- git worktree add .worktrees/cms-ui-golden 28876f4e9f6
150
- cd .worktrees/cms-ui-golden/cms/tool-ui && yarn install
151
- npx webpack --config webpack.build.ts --json > /tmp/build-stats-source-cold.json
152
- cp -R src/main/webapp/dist /tmp/cms-ui-golden-cold
153
-
154
- # 2. Warm golden — same worktree, the cold dist now seeds tailwind's
155
- # scan for the next build
156
- npx webpack --config webpack.build.ts --json > /tmp/build-stats-source-warm.json
157
- cp -R src/main/webapp/dist /tmp/cms-ui-golden-warm
158
-
159
- # 3. Build the fold candidate
160
- cd ~/work/brightspot-ui
161
- git checkout <fold-branch>
162
- yarn install
163
- yarn workspace <legacy-workspace-name> build --json > /tmp/build-stats-target.json
164
-
165
- # 4. Compare against COLD first
166
- node scripts/verify-bundle-equivalence.mjs \
167
- /tmp/build-stats-source-cold.json \
168
- /tmp/build-stats-target.json \
169
- /tmp/cms-ui-golden-cold \
170
- src/legacy/tool-ui/src/main/webapp/dist
171
-
172
- # 5. If cold passes: done. If cold fails and brightspot CI builds warm,
173
- # rerun against warm:
174
- node scripts/verify-bundle-equivalence.mjs \
175
- /tmp/build-stats-source-warm.json \
176
- /tmp/build-stats-target.json \
177
- /tmp/cms-ui-golden-warm \
178
- src/legacy/tool-ui/src/main/webapp/dist
179
- ```
180
-
181
- Acceptance: script exits 0 against the **chosen golden** (cold or warm).
182
- Any non-zero exit is investigated and root-caused before merge.
183
-
184
- ### CI build state — investigated 2026-05-18
185
-
186
- **Brightspot CI builds COLD.** The cold golden is production-faithful.
187
-
188
- Evidence from brightspot's `.github/workflows/ci.yml`:
189
-
190
- - `actions/checkout@v4` with `fetch-depth: 0` (line 28–30): every CI run
191
- starts from a fresh git working tree. No persistence of `cms/tool-ui/src/main/webapp/dist/`
192
- between runs.
193
- - `gradle/actions/setup-gradle@v4` with `cache-read-only` flag (line 38–41):
194
- caches `~/.gradle/caches`, not the project working tree. Read-write on
195
- `release/*`, read-only on PRs.
196
- - `./gradlew build` (line 49): drives `:cms-tool-ui:yarnBuild`.
197
-
198
- `cms/tool-ui/build.gradle` at SHA `28876f4e9f6`:
199
-
200
- ```
201
- task yarnBuild(type: YarnTask) {
202
- outputs.dir 'src/main/webapp/dist'
203
- outputs.cacheIf { true }
204
- args = ['build']
205
- }
206
- ```
207
-
208
- Behavior:
209
-
210
- - **Cache hit** — gradle restores `src/main/webapp/dist/` from the gradle
211
- build cache and **skips** the yarn build entirely. Webpack does not run.
212
- The restored bytes are whatever the most recent cache-pushing run emitted.
213
- - **Cache miss** — gradle invokes the task. `yarn build` runs against a
214
- fresh checkout's empty `src/main/webapp/dist/`. **Cold build.**
215
-
216
- The cache is populated by builds on `release/*` branches (the only ones with
217
- write access). The first build at any given input-hash set is a cache miss
218
- on a fresh checkout — therefore cold. Subsequent cache hits restore that
219
- cold output. Cold propagates; warm cannot enter the cache without manual
220
- intervention (which would require pre-existing `dist/` in a fresh checkout,
221
- impossible by construction).
222
-
223
- **Implication for the fold:** the cold golden (`v5.8acae93faec68b445941.css`)
224
- is the production-faithful baseline. The warm golden's orphan classes are a
225
- local-dev quirk and do not reach production. We retain the warm capture for
226
- diagnostic purposes only.
227
-
228
- **Stale-dist follow-on:** the underlying tailwind/clean-webpack-plugin
229
- ordering bug should be fixed independently of the fold, so future cms-ui
230
- builds become deterministic regardless of prior `dist/` state.
231
-
232
- ### Ongoing CI gate
233
-
234
- **Bundle equivalence is a one-time fold validation, not an ongoing CI
235
- gate.** Once the fold lands, intentional cms-ui changes will drift from
236
- brightspot's pinned SHA, and the comparison becomes stale. Future
237
- correctness depends on workspace-local Playwright tests and brightspot
238
- consumer smoke.
239
-
240
- ### Adjacent acceptance criteria (non-bundle)
241
-
242
- 1. **Modern surface integrity** — root `yarn build`, `yarn check:conventions`,
243
- `yarn build-storybook`, `yarn test:storybook` all pass; `npm pack --dry-run`
244
- from root contains both `dist/**` and `src/legacy/tool-ui/src/main/webapp/dist/**`.
245
- 2. **Consumer end-to-end** — `yarn link @brightspot/ui` from brightspot's
246
- `cms/tool-ui/` succeeds; `./gradlew :cms-tool-ui:yarnBuild` runs cleanly;
247
- docker at `https://localhost:8080/cms/` serves v4 + v5 with zero console
248
- errors; ProseMirror RTE loads; manual smoke (login → dashboard → create
249
- content) passes.
250
- 3. **Workspace-local dev** — `cd src/legacy/tool-ui && yarn build|server:local|test|lint:*`
251
- all succeed.
252
-
253
- ## Consequences
254
-
255
- ### Positive
256
-
257
- - Production-faithful confidence: the fold output matches what brightspot
258
- ships today, byte for byte across all gated buckets.
259
- - Single source of truth for tailwind-classes-not-in-source moves to the
260
- text file; eliminates dead-weight Java content paths in `tailwind.config.ts`.
261
- - Phase 1's verify machinery is reusable — restored from history, pointed at
262
- the brightspot-built golden.
263
-
264
- ### Negative
265
-
266
- - Drift maintenance: if brightspot's Java files gain new tailwind utilities,
267
- someone has to regenerate the text file. Mitigation: a regeneration script
268
- ships with the fold; platform-team awareness needed for new utility usage.
269
- - Heavier golden generation: requires a brightspot checkout and build, not
270
- just an in-repo build. One-time per validator.
271
-
272
- ## Alternatives considered
273
-
274
- 1. **Build golden in brightspot-ui (Option Y).** Both pre-fold and post-fold
275
- built in brightspot-ui's repo, where Java paths don't resolve. 100%
276
- achievable trivially, but the bar is "match the package we're retiring"
277
- rather than "match brightspot's actual production output." Rejected on
278
- production-fidelity grounds.
279
- 2. **Accept Phase 1's 99.96% as the bar.** Rejected — the user explicitly
280
- asked for 100%. Resolvable via the Java-extraction step at one-time cost.
281
- 3. **Build-time extraction via `BRIGHTSPOT_REPO_PATH` env var.** Higher
282
- fidelity (always in sync with brightspot's current Java) but adds a
283
- build-step dependency. Rejected for fold-time simplicity in favor of
284
- pre-extraction; can revisit if drift becomes painful.
285
- 4. **Build cms-ui from inside brightspot (invert Phase 2).** Most faithful
286
- but heavy coupling. Rejected.