@gemboss/ui 0.13.0 → 0.25.0
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.
- package/CHANGELOG.md +512 -1
- package/README.md +426 -14
- package/catalog/editor.html +1027 -0
- package/catalog/index.html +1215 -90
- package/gemboss-ui.css +3 -4698
- package/package.json +24 -5
- package/parts/components.css +5 -0
- package/parts/core.css +5 -0
- package/parts/shell.css +5 -0
- package/src/app-shell.css +1 -256
- package/src/assistant/engine.tsx +607 -0
- package/src/assistant/host.tsx +1 -0
- package/src/assistant/index.ts +1 -0
- package/src/assistant-engine.css +1 -0
- package/src/assistant.css +1 -558
- package/src/auth.css +1 -606
- package/src/auth.tsx +1 -0
- package/src/board-move.ts +194 -0
- package/src/chat-composer.css +1 -110
- package/src/chat.css +1 -432
- package/src/collections.css +1 -350
- package/src/collections.tsx +170 -40
- package/src/dialog.tsx +3 -135
- package/src/editor/controls.tsx +207 -0
- package/src/editor/css-url.ts +11 -0
- package/src/editor/frame.tsx +243 -0
- package/src/editor/index.ts +52 -0
- package/src/editor/layers.tsx +136 -0
- package/src/editor/panel.tsx +189 -0
- package/src/editor/panes.tsx +45 -0
- package/src/editor/sortable.tsx +79 -0
- package/src/editor/swatch.ts +45 -0
- package/src/editor/tree.tsx +61 -0
- package/src/editor-layers-plain.js +1 -0
- package/src/editor-plain.js +1 -0
- package/src/editor.css +1 -1099
- package/src/gemboss-field.css +1 -112
- package/src/gemboss-tokens.css +1 -164
- package/src/icons.tsx +2 -0
- package/src/index-table.tsx +20 -56
- package/src/index.ts +16 -6
- package/src/kit-plain.css +1 -499
- package/src/kit-plain.js +1 -575
- package/src/launcher.tsx +1 -0
- package/src/menu-layer.ts +94 -0
- package/src/menu.tsx +28 -2
- package/src/portal.css +1 -139
- package/src/portal.tsx +1 -0
- package/src/reactions-data.ts +59 -0
- package/src/reactions.css +1 -0
- package/src/reactions.tsx +140 -0
- package/src/resource-list-select.tsx +73 -0
- package/src/search-dialog.tsx +146 -0
- package/src/segmented-click.ts +20 -0
- package/src/segmented.tsx +98 -0
- package/src/selection.tsx +79 -0
- package/src/shell.css +1 -1079
- package/src/theme-dark.css +1 -66
- package/src/theme-script.ts +10 -0
- package/src/theme.tsx +5 -5
- package/src/ui.css +1 -610
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,516 @@
|
|
|
2
2
|
|
|
3
3
|
Versions up to 0.9.0 are described in the README, each in the section that introduced it.
|
|
4
4
|
|
|
5
|
+
## 0.25.0 (07/10/2026)
|
|
6
|
+
|
|
7
|
+
**The assistant's engine picker** (Chris 07/10/2026): a chip in the composer row, as in the admin, that opens a popup
|
|
8
|
+
with Engine · Setup · Status tabs. Engine, model, effort, the bridge's status and its install command leave the chat.
|
|
9
|
+
|
|
10
|
+
Added
|
|
11
|
+
- `EnginePicker`, `EnginePanel`, `BridgeNotice`, `useEnginePicker` (+ types `EngineChoice`, `Choice`, `BridgeStatus`,
|
|
12
|
+
`BridgeSetup`, `BridgeState`, `EnginePickerTab`) in `@gemboss/ui/assistant`. README "The engine picker".
|
|
13
|
+
- `assistant-engine.css`, a new entry (1.9 KB gzip), imported by the component; not in `gemboss-ui.css`.
|
|
14
|
+
- `placeFloating(layer, anchor, end)` in `menu-layer.ts`: the menus' placement, now shared with the picker's panel
|
|
15
|
+
(`floatMenu` calls it; same geometry).
|
|
16
|
+
|
|
17
|
+
## 0.24.0 (07/10/2026)
|
|
18
|
+
|
|
19
|
+
**The Studio canvas in the editors' frame** (gemboss #3856): the pieces the admin's Studio needed from the editor kit.
|
|
20
|
+
|
|
21
|
+
Added
|
|
22
|
+
- `EditorChatToggle` takes a `name` ("Hide <name>"; default "chat panel"): a column that is not a chat says so.
|
|
23
|
+
|
|
24
|
+
Changed
|
|
25
|
+
- A folded editor column (`.is-chat-collapsed`) is `visibility: hidden`: at width 0 its fields stayed in the Tab order.
|
|
26
|
+
|
|
27
|
+
Removed
|
|
28
|
+
- `.gemboss-pageedit-status` and `.gemboss-pageedit-kind` looks: the page editor draws Polaris' Badge, as the funnel beside it does
|
|
29
|
+
(`.gemboss-pageedit-status` stays on a wrapper as a hook, `data-status`, with no look).
|
|
30
|
+
|
|
31
|
+
## 0.23.0 (07/10/2026)
|
|
32
|
+
|
|
33
|
+
**The CSS comes in parts: a core every surface loads, and entries that come with the components that draw them.**
|
|
34
|
+
README "Load only what you use" has the table and the imports for Next and for plain HTML.
|
|
35
|
+
|
|
36
|
+
Added
|
|
37
|
+
- `@gemboss/ui/core.css` (reset + tokens, 1.0 KB gzip), `@gemboss/ui/components.css` (the kit, the field look,
|
|
38
|
+
kit-plain.css; 8.2 KB), `@gemboss/ui/shell.css` (the shell + app-shell.css; 5.5 KB): built into `parts/` from the
|
|
39
|
+
same sections as `gemboss-ui.css`, each opening with a header that names the gemboss commit (kept through minify).
|
|
40
|
+
The core is 14.7 KB against 21.7 for the bundle. Like `gemboss-ui.css`, the parts exist after `build-css.mjs` (the
|
|
41
|
+
tarball has them; in this repo, build first).
|
|
42
|
+
- Components import their own entry: `AuthLayout` & co. → `auth.css`; `AssistantHost`, the launcher → `assistant.css`;
|
|
43
|
+
`TopbarNav`, `SearchDialog`, `Avatar`, `Leaderboard`, `Podium`, `ThemeToggle` → `portal.css`; `ThemeToggle` /
|
|
44
|
+
`themeScript` (now in `theme-script.ts`, so a root layout with only the script does not take portal.css) → `theme-dark.css`; the collections components → `collections.css`; the editor components → `editor.css`.
|
|
45
|
+
A component a surface never imports takes its CSS out of the build with it (`sideEffects`).
|
|
46
|
+
- The editor kit's step 4 (#3850: `LayerList`, `SortableLayerList`, `LayerTree` in `layers.tsx`, `sortable.tsx`, `tree.tsx`)
|
|
47
|
+
imports `editor.css` like the rest of the editor; `editor-layers-plain.js` is minified and weighed like the other plain
|
|
48
|
+
scripts (1.8 KB gzip).
|
|
49
|
+
- `Reactions` (#3861, born an entry) imports `reactions.css` itself too; the parts gate found it unclassified on the
|
|
50
|
+
rebase, which is the gate doing its job.
|
|
51
|
+
|
|
52
|
+
Changed
|
|
53
|
+
- `@gemboss/ui/shell.css` is the built shell PART (was `packages/ui/src/shell.css`, which only the admin imported). The source is
|
|
54
|
+
`@gemboss/ui/shell-source.css`; the admin's `gemboss-shell.css` imports that, same file as before.
|
|
55
|
+
- `SearchDialog` moved to its own module (`search-dialog.tsx`, same export from `@gemboss/ui`), so a surface that only
|
|
56
|
+
opens a `Dialog` does not get `portal.css`.
|
|
57
|
+
- kit-plain.css → app-shell.css: `.ui-menu__item { display: flex … }` and the thread rail's 44px buttons at phone width
|
|
58
|
+
(`.gemboss-assistant-collapse`, `-newchat`). Both override a shell.css rule by coming after it; kit-plain.css sat
|
|
59
|
+
after shell.css in `gemboss-ui.css` but is in `components.css` now, which loads before it. Same rules, same weight.
|
|
60
|
+
- `gemboss-ui.css` holds the same parts as 0.19.0, in the parts' order (kit-plain.css now sits before the shell).
|
|
61
|
+
Computed style of every element of both catalogs at 1280 and 390, 0.19.0 bundle vs 0.23.0 bundle: 0 differences.
|
|
62
|
+
|
|
63
|
+
Measured on surfaces (tarball installed locally, nothing committed there), gzip of the package's CSS a page loads:
|
|
64
|
+
- content-radar (Next 16): `/v2` 38.5 KB on 0.19.0 → 32.3 with the core; `/login` 31.2 → 25.4; `/v2/accounts` 43.1 →
|
|
65
|
+
36.9. Keeping `gemboss-ui.css` on 0.23.0 instead costs +1.9 KB (`/v2` 40.4): the launcher brings assistant.css twice.
|
|
66
|
+
- taskdesk (plain HTML): 22.2 KB (the minified bundle) → 15.0 with the core; every element's computed style the same and
|
|
67
|
+
screenshots byte-identical at 1280 and 390.
|
|
68
|
+
- GemFactory sign-in (plain HTML): 22.2 KB → 17.7 with the core + auth.css; screenshots byte-identical at 1280 and 390.
|
|
69
|
+
|
|
70
|
+
Upgrading
|
|
71
|
+
- A surface that bundles the package with esbuild needs a CSS loader (`loader: { ".css": "empty" }` if it links the CSS
|
|
72
|
+
itself): esbuild stops at a component's own `import "./auth.css"` without one. GemFactory's gbui.mjs has it already.
|
|
73
|
+
|
|
74
|
+
The compatibility bundle, and the road out
|
|
75
|
+
- `gemboss-ui.css` stays, minified, FROZEN at the 0.19.0 set: a surface that links it does not break, and a new
|
|
76
|
+
component never goes into it (`parts-gate.mjs`, CI).
|
|
77
|
+
- 1. Now: every surface moves to the core + entries on its next bump (Next and Vite: three imports in the root layout and
|
|
78
|
+
drop `gemboss-ui.css` in the same bump; plain HTML: link the core and the entries each page draws).
|
|
79
|
+
2. A search across the fleet's repos for `gemboss-ui.css` shows who still loads it (06/10/2026: content-radar,
|
|
80
|
+
partner-radar, search-radar, talent-radar, GemCommunity admin, GemFeedback, gemwatcher, GemFactory, taskdesk).
|
|
81
|
+
3. When nobody does, it is removed in its own release, with this note pointing at it. Not before.
|
|
82
|
+
|
|
83
|
+
Checks
|
|
84
|
+
- `packages/ui/scripts/parts-gate.mjs` (CI, with `--selftest`): the core and the bundle frozen; every stylesheet in `src/`
|
|
85
|
+
classified; every entry exported; a component that draws an entry's class imports it; the built bundle holds exactly
|
|
86
|
+
the frozen sections.
|
|
87
|
+
- `parts-cascade.test.ts` (`test:ui-browser`): the catalog with the parts (the core first, then the entries in order and
|
|
88
|
+
reversed, collections.css and editor.css included) paints what the bundle paints, element for element, at 1280 and
|
|
89
|
+
390; two planted entries that only agree by order turn it red. The core loads first by contract (README "Order"):
|
|
90
|
+
an entry before it loses its modifiers (`.ui-empty--no-match`), measured.
|
|
91
|
+
- Ceilings for the three parts in `weight-budget.json`.
|
|
92
|
+
|
|
93
|
+
## 0.22.0 (07/10/2026)
|
|
94
|
+
|
|
95
|
+
**The layers, the element outline and the drawer as components (editor kit, step 4 of 5).** Nothing changes on screen
|
|
96
|
+
or in behaviour in the admin: its page editor's Layers, Page settings and Edit content drawers and its element
|
|
97
|
+
inspector's Elements outline now render these, measured equal on a production build (below). README "Layers and
|
|
98
|
+
drawer".
|
|
99
|
+
|
|
100
|
+
Added
|
|
101
|
+
- `@gemboss/ui/editor`, three more modules behind the entry: `layers` (`LayerList`, `EditorDrawer`), `sortable`
|
|
102
|
+
("use client": `SortableLayerList`) and `tree` (`LayerTree`).
|
|
103
|
+
- `LayerList`: the page's sections as rows (34px, 50 with a subtitle); select (`aria-current`), the caller's actions,
|
|
104
|
+
an empty line; off until asked: an eye to hide / show (`onToggleHidden`, `aria-pressed`), indent per `depth`.
|
|
105
|
+
- `SortableLayerList`: the same rows, reordered by drag (a grip, the dragged row faded, a drop line) and Alt+↑ / Alt+↓
|
|
106
|
+
(the focus kept on the moved row, also when `onMove` answers after a server write); the drag is kept by id. Its own
|
|
107
|
+
module, so the admin's Layers (no reordering) do not carry it. For GemFactory's Builder (step 5).
|
|
108
|
+
- `LayerTree`: an indented outline, `role="tree"` of `treeitem`s with level, position and selection.
|
|
109
|
+
- `EditorDrawer`: backdrop + a side panel (`right`: `.gemboss-settings`, `left`: `.gemboss-layers`), head with ✕,
|
|
110
|
+
`before`, body, `footer`.
|
|
111
|
+
- `editor-layers-plain.js` (its own file and its own weight ceiling, 2,315 B gzip; editor-plain.js is unchanged):
|
|
112
|
+
`gembossUI.initEditorLayers()`: select, hide, drag and Alt+↑/↓ (the row moves in the document),
|
|
113
|
+
outline select / clear, drawers opened by `data-gb-drawer` and closed by ✕ and the backdrop; an event for each.
|
|
114
|
+
- editor.css: the optional pieces (`.gemboss-layer-grip`, `.is-dragging`, `[data-drop]`, `.is-hidden`,
|
|
115
|
+
`.gemboss-layer-eye`) and `[hidden]` for a drawer a plain page keeps in the document.
|
|
116
|
+
- `catalog/editor.html`: Layers (drag, hide, select, indent), Page settings and the outline, running, at 1280 and 390.
|
|
117
|
+
|
|
118
|
+
Measured in the admin (two production builds, before = main f23a60729 with the #3848 fixes (0.20.1) and after, pinned SENTRY_RELEASE /
|
|
119
|
+
GIT_COMMIT_SHA / GEMBOSS_BUILD_STAMP, served by `next start` on the same local data; every write the harness could cause
|
|
120
|
+
was held)
|
|
121
|
+
- DOM and computed style (+ ::before / ::after, box, control values) of every element, and :hover / :focus-visible /
|
|
122
|
+
:active forced on every control of the editor's columns and drawers, for 13 states (page editor: Layers open, a layer
|
|
123
|
+
selected, focus on a row's actions, closed with ✕, closed from the backdrop, ↓ pressed with the write held; Edit
|
|
124
|
+
content drawer; Page settings drawer, typing in it; theme editor inspector, Elements: the outline, a node picked, "Add
|
|
125
|
+
inside" open, a node picked and cleared) at 320, 390, 768 (touch), 1280, 1366, 1920: 78 captures, 22,888 element
|
|
126
|
+
renders, 10,620 forced-state checks. 0 differences in computed style or box. In markup, the intended ones only (720):
|
|
127
|
+
`data-id` on each layer row and outline node, `type="button"` on the buttons the components draw (no form around
|
|
128
|
+
them), `aria-current="true"` on the selected layer's button. Not the change: inline styles serialised by the server or
|
|
129
|
+
by the client (computed equal), the logo's per-port URL, the canvas's loading spinner (four states re-captured with
|
|
130
|
+
the canvas settled: equal), and the forced states of the chat column's work-mode select, which differ between two
|
|
131
|
+
captures of the SAME base build too. Negative controls (one declaration laid over the after build: the layer button's
|
|
132
|
+
padding, the outline name's, the drawer head's) are reported in 3 of 3 states.
|
|
133
|
+
- Re-checked after rebasing onto main with 0.20.0 (#3846) and 0.20.1 (#3848): the 13 states at 1280 and 390, 26 captures,
|
|
134
|
+
7,612 element renders, 3,540 forced-state checks: again 0 differences in computed style or box, markup as above.
|
|
135
|
+
- First load (brotli), against main with 0.20.1: the shell 239,674 → 239,655 B (−19); page editor +693 (LayerList and
|
|
136
|
+
EditorDrawer; SortableLayerList is not in it), campaign editor +327, theme editor +314, product studio +198, section
|
|
137
|
+
editor +125, plugin editor −12. Package weight gate: editor.css 8.1 / 8.4 KB gzip, editor-plain.js unchanged,
|
|
138
|
+
editor-layers-plain.js 1.8 / 2.3 KB.
|
|
139
|
+
- Behaviour the admin does not use (drag, Alt+↑/↓, the eye, indent) and the plain-HTML side are asserted in Chromium:
|
|
140
|
+
editor-layers-browser.test.tsx (React and `initEditorLayers()`, with negative controls).
|
|
141
|
+
|
|
142
|
+
Known, kept as it was (this step moves markup, not behaviour)
|
|
143
|
+
- The admin's Layers do not drag and have no eye: they move with ↑ / ↓ buttons, which also work on touch (HTML drag and
|
|
144
|
+
drop does not start from a touch). Using `onMove` there is a change of its own.
|
|
145
|
+
- The drawers have no Escape, and do not move the focus into themselves or back to their opener.
|
|
146
|
+
- `DesignControls` (the inspector's Design tab body) is not moved: moving it changes how it looks.
|
|
147
|
+
- The theme editor's "Sections on this page" list (ThemeSectionList) keeps its own bordered rows (inline styles); drawn
|
|
148
|
+
as a LayerList it would look different.
|
|
149
|
+
|
|
150
|
+
## 0.21.0 (07/10/2026)
|
|
151
|
+
|
|
152
|
+
**Reactions: one emoji set and one chip for the fleet.** GemCare's team chat reactions, moved into the kit so GemFeedback
|
|
153
|
+
(requests, comments) and GemCare draw and accept the same thing (Chris 06/10/2026). README "Reactions".
|
|
154
|
+
|
|
155
|
+
Added
|
|
156
|
+
- `@gemboss/ui/reactions-data`: `REACTION_GROUPS` (137 emoji, GemCare's set unchanged), `REACTION_EMOJI`,
|
|
157
|
+
`isReactionEmoji`, `searchReactions`, `reactionLabel`, `toggleReaction`, `QUICK_REACTIONS`, type `Reaction`.
|
|
158
|
+
- `Reactions` and `ReactionPicker` (client components), `reactions.css` (its own entry `./reactions.css`, not inside `gemboss-ui.css`: the shared sheet stays as it was).
|
|
159
|
+
- Icon `reaction` (a face with a plus).
|
|
160
|
+
- Catalog section "Reactions".
|
|
161
|
+
- `packages/ui/weight-budget.json`: a ceiling for `packages/ui/src/reactions.css`; `gemboss-ui.css` unchanged.
|
|
162
|
+
|
|
163
|
+
## 0.20.1 (07/10/2026)
|
|
164
|
+
|
|
165
|
+
**Two faults the admin's settings panel had before step 3, fixed.** Nothing else changes on screen. (The third listed
|
|
166
|
+
under 0.17.0, Show / Hide and On / Off rows without `aria-pressed`, went with 0.20.0, #3846.)
|
|
167
|
+
|
|
168
|
+
Fixed
|
|
169
|
+
- The inspector's groups that arrive folded (the shared frame's: Motion, …) opened on the SECOND click: the admin's
|
|
170
|
+
toggle flipped the stored value, and a flip of "unset" is "closed", where the group already was. It now stores what
|
|
171
|
+
the click asks for (`InspectorGroup`'s `onOpenChange(next)`). Reproduced on a production build first (theme editor,
|
|
172
|
+
Hero banner, Motion: `aria-expanded` false after one click, true after two), the same steps open it in one click after.
|
|
173
|
+
- The image thumbnail's `url()` is quoted (`cssUrl`, new export, plain TypeScript, also `./editor/css-url`), in
|
|
174
|
+
`ImageControl` and in the admin's library grid: unquoted, a URL holding ")" or a space ended the token, the
|
|
175
|
+
declaration was dropped and the thumbnail stayed empty. `"` and `\` get a backslash and a control character a CSS hex
|
|
176
|
+
escape; `initEditorPanel()` used JSON.stringify, whose `\n` CSS reads as the letter n, and now writes the same as
|
|
177
|
+
`cssUrl` (`gembossUI.cssUrl`).
|
|
178
|
+
|
|
179
|
+
Known, kept as it was
|
|
180
|
+
- The inspector remembers open / closed per group TITLE, so two groups with the same title (the Design tab's
|
|
181
|
+
Typography and an element frame's Typography) share it.
|
|
182
|
+
|
|
183
|
+
## 0.20.0 (07/10/2026)
|
|
184
|
+
|
|
185
|
+
**One switch, one component.** The admin drew "pick one of these" nine ways: a dark 44px pill (the Studio's
|
|
186
|
+
Funnel · Canvas · Page and the funnel lens copied from it), a dark joined group (the canvas's device, the campaign
|
|
187
|
+
editor's mode), a grey track with a raised white tab (the inspector's `.gemboss-ei-seg`, which 0.17.0 moved here as
|
|
188
|
+
`Seg`), a brand-fill joined group (post-purchase, twice), separate tinted boxes (`DeviceToggle`), and this package's own
|
|
189
|
+
`.ui-seg`, which no editor used. Two of them sat side by side in one bar (Chris 06/10: "switch canvas mode page mode đó
|
|
190
|
+
cũng dùng khác nhau là không được"). Now there is one look, `.ui-seg`, and one component.
|
|
191
|
+
|
|
192
|
+
Added
|
|
193
|
+
- `Segmented` / `IconSegmented` (`@gemboss/ui/segmented`, also from `@gemboss/ui`): moved from the admin
|
|
194
|
+
(`components/ui/Segmented.tsx` re-exports it). Options take a ReactNode label, `title`, `ariaLabel`, `disabled`; the group
|
|
195
|
+
takes `fill`, a hook `className` and `style`; each button carries `data-value`. Its own plain module: a surface that draws
|
|
196
|
+
a switch does not load the shell.
|
|
197
|
+
- `.ui-seg--fill` (the row's width, segments equal), `.ui-seg-n` (a count inside a segment, read by eye; the segment's
|
|
198
|
+
`aria-label` says the sentence), a disabled segment (.45, `not-allowed`).
|
|
199
|
+
|
|
200
|
+
Changed
|
|
201
|
+
- `Seg` (editor/controls) is `Segmented` stretched to its row. `gemboss-ei-seg` stays on the group as the hook
|
|
202
|
+
`editor-plain.js` finds; the pressed button is `.active` (the driver toggles `.active` and, for markup written before,
|
|
203
|
+
`.on`).
|
|
204
|
+
- `DeviceToggle` is a `.ui-seg` (28px under a mouse, 44px under a finger). `.gemboss-pv-devices` / `.gemboss-pv-device`
|
|
205
|
+
stay as hooks; inside the switch the segment's size wins over the icon-button sizes those classes carry elsewhere
|
|
206
|
+
(undo, redo, layers, ⋯). Each device button has an `aria-label`.
|
|
207
|
+
- `.is-text` segments lay their children in a row: a label and its count, or two icons, stacked in the grid.
|
|
208
|
+
- A disabled segment keeps the picked one's fill (a switch that is saving still says which option is on; review #3846).
|
|
209
|
+
- `.ui-seg--fill` outranks kit-plain.css's `.is-text { flex: none }` (gemboss-ui.css carries it after ui.css): at equal
|
|
210
|
+
weight the segments kept their own widths outside the admin (review #3846).
|
|
211
|
+
|
|
212
|
+
Fixed
|
|
213
|
+
- `.ui-seg svg` filled a stroke icon solid (`fill: currentColor` over `fill="none"`): the monitor and phone glyphs drew
|
|
214
|
+
as blocks. A `fill="none"` svg keeps its outline.
|
|
215
|
+
|
|
216
|
+
- A folded editor column (`.is-chat-collapsed`) is `visibility: hidden`: at width 0 its fields stayed in the Tab order.
|
|
217
|
+
- `EditorChatToggle` takes a `name` ("Hide <name>"; default "chat panel"): a column that is not a chat says so.
|
|
218
|
+
|
|
219
|
+
Removed
|
|
220
|
+
- The `.gemboss-ei-seg` look from `editor.css`.
|
|
221
|
+
- `.gemboss-pageedit-status` and `.gemboss-pageedit-kind` (the page editor draws Polaris' Badge, as the funnel beside it does).
|
|
222
|
+
|
|
223
|
+
## 0.19.0 (06/10/2026)
|
|
224
|
+
|
|
225
|
+
**The published CSS and plain scripts are minified, and each file has a wire-weight ceiling.** README "Minified on
|
|
226
|
+
publish, weighed per file".
|
|
227
|
+
|
|
228
|
+
Changed
|
|
229
|
+
- The tarball carries every stylesheet and `kit-plain.js` / `editor-plain.js` minified (esbuild, comments out; the
|
|
230
|
+
sources keep them). `gemboss-ui.css` keeps its generated header. gzip, as measured on this change:
|
|
231
|
+
`gemboss-ui.css` 78.1 → 21.9 KB, `kit-plain.js` 17.8 → 8.5 KB, `editor.css` 25.8 → 7.9 KB, `collections.css`
|
|
232
|
+
12.4 → 4.6 KB, `editor-plain.js` 7.5 → 3.6 KB. A surface that serves the files from `node_modules` as they are
|
|
233
|
+
(GemFactory, taskdesk, gemcare, gempress) sends the smaller file on its next bump with no change of its own; Next and
|
|
234
|
+
Vite surfaces minified already and see no difference.
|
|
235
|
+
- Release: `npm run stage` then `npm publish .pack --auth-type=web`. `npm pack` / `npm publish` straight in
|
|
236
|
+
`packages/ui` are refused (they would ship the unminified sources).
|
|
237
|
+
- Computed style is unchanged: every element and `::before` / `::after` of `catalog/index.html` and
|
|
238
|
+
`catalog/editor.html`, all frames, at 1280 and 390, compared source vs minified copy. The only text that differs is in
|
|
239
|
+
custom properties (`0.18` → `.18`, `'Inter'` → `"Inter"`), whose computed value is their token text; every property
|
|
240
|
+
that reads them computes the same.
|
|
241
|
+
|
|
242
|
+
Checks
|
|
243
|
+
- `packages/ui/scripts/weight-gate.mjs` (CI: `--ci`) replaces the export test's raw 90 KB cap: gzip of each minified file against
|
|
244
|
+
`weight-budget.json` (measured + 512 B); red over the ceiling, more than 1 KB under it, with comments left, or without
|
|
245
|
+
a ceiling. Negative controls run with it in CI. `fleet.mjs` compares main and npm minified on both sides.
|
|
246
|
+
- `esbuild` is a pinned root devDependency (0.21.5, the version already installed): the minifier decides the bytes.
|
|
247
|
+
|
|
248
|
+
## 0.18.0 (06/10/2026)
|
|
249
|
+
|
|
250
|
+
**Five collections gaps surface migrations found** (GemFactory Members #197 and its board, content-radar ideas,
|
|
251
|
+
GemCommunity admin Content #270). README "Collections" has the rules.
|
|
252
|
+
|
|
253
|
+
Fixed
|
|
254
|
+
- A sort button (IndexTable / DataTable header, `button|a.ui-table__sort`) is 44 WIDE under a finger and at phone width,
|
|
255
|
+
not only 44 tall: "ID" and "Views" were ~30 wide on an iPad in landscape (GemCommunity admin Content #270). Under a
|
|
256
|
+
mouse above 768 nothing changes. The sort chips below 768 already had it (`ui-chip`).
|
|
257
|
+
- An open ⋯ menu (`Menu`, `details.ui-menu`) is no longer cut by a scrolling frame. Its list floats in the top layer
|
|
258
|
+
(`popover="manual"`, `position: fixed` against the button): below it, or above when the room below is short and the
|
|
259
|
+
room above is larger; 8px from the viewport's edges; scrolls inside when taller than the room; closes when a scroll
|
|
260
|
+
moves its button (the page, or a frame around it; not a scroll inside the list or of something elsewhere) or the
|
|
261
|
+
window resizes. One page-wide pair of listeners, however many menus; a menu already open when the script loads is
|
|
262
|
+
floated, not hidden. Tab order, Escape and row clicks are unchanged (the list is still the details' child).
|
|
263
|
+
React `Menu` (new `menu-layer.ts`, floats in its own summary click, sets nothing page-wide) and kit-plain.js
|
|
264
|
+
(`initMenuLayer()`, runs by itself) carry the same code. No popover
|
|
265
|
+
API or no script: the 0.17 absolute list. GemFactory Members at 820 / 900 / 1280 showed half of the last rows' menus
|
|
266
|
+
and asked for a scroll inside the table.
|
|
267
|
+
|
|
268
|
+
Added
|
|
269
|
+
- `MediaCard ratio="1/1"` (`data-ratio="1/1"`) beside 16:10 and 4:3, for square pictures (content-radar's moodboard).
|
|
270
|
+
No free ratio; an unknown value draws 16:10.
|
|
271
|
+
- Board server paging: `BoardColumn.hasMore` (default: true when `moreHref` is set), `moreHref`, `loading`,
|
|
272
|
+
`Board onLoadMore(columnId)`, `linkAs`, `moreLinkProps`, `fetchMore` (plain HTML only), `boardShown(page)` (12, then 24
|
|
273
|
+
a page; a missing or non-numeric page is page 1). A server-paged column renders the cards it was given and
|
|
274
|
+
ONE `ui-more` "Show N more" (`a[data-gb-more]`), not the nested `<details>` that need every card in the HTML.
|
|
275
|
+
With `fetchMore` (`a[data-gb-more]`) kit-plain.js fetches the link and appends the cards not yet on the board (by
|
|
276
|
+
`data-id`), takes the next link, the count and the URL, announces and focuses the first new card; "Couldn't load." +
|
|
277
|
+
Try again on failure. A paged column whose loaded cards all moved away keeps its list and its link.
|
|
278
|
+
- Board moves, optional: `Board onMove(cardId, toColumn, toIndex)`; plain HTML `.ui-board[data-gb-move]` with
|
|
279
|
+
`li[data-id][tabindex="0"][draggable="true"]` and the `gb:move` event (cancelable; not cancelled, the `li` moves).
|
|
280
|
+
Drag, or Space / arrows / Space / Escape on a focused card, every step said in `[data-gb-live]`; the held card is
|
|
281
|
+
`data-gb-lifted="key|drag"` (no `aria-pressed`: a list item does not take it). `board-move.ts`
|
|
282
|
+
(React, through a callback ref: `collections.tsx` stays a plain module) and kit-plain.js carry the same code; a page
|
|
283
|
+
with both drives a React board once.
|
|
284
|
+
- `BoardColumn.items` (`{ id, card, name? }`): cards with ids, needed by moves and server paging. `cards` still works.
|
|
285
|
+
`Board id` is now the root's DOM id too (kit-plain.js reads a fetched page's column from the board with the same id).
|
|
286
|
+
- Review #3845 (before merge): a drag that left the board and came back to the same slot was cancelled; kit-plain.js
|
|
287
|
+
would have fetched into a board React owns; a menu closed on any scroll on the page. Each has a test that fails on the
|
|
288
|
+
first commit of this PR.
|
|
289
|
+
- collections-gate counts boards (`seen.boards`): a page that is only a board (content-radar ideas) read "NOT MEASURED".
|
|
290
|
+
- Catalog: a movable board (live with kit-plain.js), a server-paged board, a 1:1 card grid, a table to open the last
|
|
291
|
+
row's ⋯ in.
|
|
292
|
+
|
|
293
|
+
Checks
|
|
294
|
+
- `collections-board.test.ts` (new, in `test:ui-browser`): the last row's menu whole in the viewport at 820 / 900 /
|
|
295
|
+
1280 / 390, plain HTML and React, above its button near the bottom of the screen, keyboard (Enter, Tab, Escape back
|
|
296
|
+
to ⋯), closes on page scroll and resize but not on its own scroll, an item click does not open the row; negative:
|
|
297
|
+
without the popover API the same menus are cut (plain and React). Ratios 1.6 / 1.33 / 1 / fallback 1.6; negative:
|
|
298
|
+
without the 1/1 rule the square card is 16:10. A 2,000-card column server-rendered = 12 `li` + one link (the
|
|
299
|
+
client-paged board: 2,000 `li`); kit-plain fetch in place to the last page (36 → 60 → 80, no reload, URL, count,
|
|
300
|
+
focus, live text), failure + Try again, no-script link navigates, React `onLoadMore`. Moves: keyboard and drag on
|
|
301
|
+
plain HTML (`gb:move` detail, DOM, counts, focus), Escape and a drop in place report nothing, a cancelled `gb:move`
|
|
302
|
+
leaves the DOM to the page, React `onMove` (keyboard + drag), React + kit-plain on one page fire once; negative: a
|
|
303
|
+
board without `onMove` has no tab stops or drag and moves nothing. collections-gate clean on all three.
|
|
304
|
+
|
|
305
|
+
## 0.17.0 (06/10/2026)
|
|
306
|
+
|
|
307
|
+
**The settings panel and its controls as components (editor kit, step 3 of 5).** Nothing changes on screen or in
|
|
308
|
+
behaviour in the admin: its Configure column, element inspector and schema form now render these, measured equal on a
|
|
309
|
+
production build (below). README "Settings panel (0.17.0)".
|
|
310
|
+
|
|
311
|
+
Added
|
|
312
|
+
- `@gemboss/ui/editor`, two more modules behind the entry (`panel`, `controls`, both `"use client"`):
|
|
313
|
+
`PanelTabs` (`column`: Configure · Chat; `inspector`: Content · Design · …; roving ←/→ by default, `roving={false}`
|
|
314
|
+
for a row of plain Tab stops; `controls` per tab for `aria-controls`), `PanelHeader` + `PanelAction`, `InspectorGroup` (collapsible, controlled or not;
|
|
315
|
+
`collapsible={false}` is the schema form's static group), `Field` (label, `labelValue`, hint), `Seg`, `ColorControl`,
|
|
316
|
+
`RangeControl`, `EdgeBox`, `ImageControl` + `ChipButton`, and `swatchState` (moved from the admin, which re-exports it;
|
|
317
|
+
also `@gemboss/ui/editor/swatch`, plain TypeScript).
|
|
318
|
+
- `editor-plain.js`: `gembossUI.initEditorPanel()`: tabs (+ arrows on a roving row, `aria-controls` panels), group
|
|
319
|
+
fold, Seg, colour (swatch and box kept in step, swatch off for a non-hex), range (label value + `data-suffix`), edges
|
|
320
|
+
(all four on blur), image (thumbnail, `data-gb-image-clear`); an event for each.
|
|
321
|
+
- editor.css: `.gemboss-ei-gh-note`, the group header's aside (the declarations the inspector had inline).
|
|
322
|
+
- `catalog/editor.html`: the panel with every control, rendered from the components and running, at 1280 and 390.
|
|
323
|
+
|
|
324
|
+
Measured in the admin (two production builds, before = main 23644fabb and after, pinned SENTRY_RELEASE / GIT_COMMIT_SHA /
|
|
325
|
+
GEMBOSS_BUILD_STAMP, served by `next start` on the same local data; every write the harness could cause was held)
|
|
326
|
+
- DOM and computed style (+ ::before / ::after, box, control values) of every element, and :hover / :focus-visible /
|
|
327
|
+
:active forced on every control of the panel, for 19 states (theme editor inspector: Design, groups folded, Content,
|
|
328
|
+
Advanced, ←/→ on the tabs, typing in an edge box, mobile breakpoint, busy with every control disabled; Global styles:
|
|
329
|
+
default, slider dragged, colour typed, swatch clicked; page editor Configure, edge committed with Enter; section editor:
|
|
330
|
+
hero, image slot, slider, slider moved with the keys, image URL committed) at 320, 390, 768 (touch), 1280, 1366,
|
|
331
|
+
1920: 114 captures, 41,506 element renders, 18,018 forced-state checks. 0 differences in computed style or box. In
|
|
332
|
+
markup, the intended ones: the inspector's tabs gain `type="button"` (no form around them), the group note's inline
|
|
333
|
+
style became `.gemboss-ei-gh-note` (computed equal), and (after review) every tab and Seg button carries
|
|
334
|
+
`data-value`, which no stylesheet selects; re-captured at 1280 and 390 after it, the same. Two more that are not the change: the brand mark's
|
|
335
|
+
`url()` resolves to each server's own port, and one forced `:active` in Global styles differs between two captures of
|
|
336
|
+
the SAME build too. A negative control (one declaration laid over the after build) is reported in 10 of 19 states.
|
|
337
|
+
- Server-rendered markup of the admin's controls before and after with the same props (FieldControl of every kind,
|
|
338
|
+
FieldRenderer schemas, the inspector's Seg, EdgeBox, ImageField, ElementPropField; disabled, values, hints): 330
|
|
339
|
+
renders: 282 byte-identical, 20 identical but for attribute order (the element edge box), 28 identical but for the
|
|
340
|
+
added `data-value`, 0 different. A changed aria-label laid over one render is caught.
|
|
341
|
+
- First load (brotli): the shell 239,475 → 239,439 B (−36); theme editor +659, page editor +875, section editor +991,
|
|
342
|
+
campaign editor +653, product studio +644; plugin editor −32. Budget gate: shell 233.8 / 237 KB.
|
|
343
|
+
|
|
344
|
+
Known, kept as it was (this step moves markup, not behaviour)
|
|
345
|
+
- The inspector's groups that arrive folded (the shared frame's) stay folded on the first click and open on the second:
|
|
346
|
+
the toggle flips the stored value from "unset" to "closed".
|
|
347
|
+
- The schema form's Show / Hide rows and the inspector's Visibility rows have no `aria-pressed`, so they are not `Seg`.
|
|
348
|
+
- The image thumbnail's `url(…)` is unquoted in the React control, as in the admin (a URL with ")" or a space shows no
|
|
349
|
+
thumbnail); `initEditorPanel()` quotes it.
|
|
350
|
+
- `InspectorGroup collapsible={false}` (schema form) and the inspector's group differ a little (letter-spacing .08em vs
|
|
351
|
+
.1em, divider above vs below), as in the admin.
|
|
352
|
+
|
|
353
|
+
## 0.16.0 (06/10/2026)
|
|
354
|
+
**Four collections fixes a surface migration asked for**, each patched by hand on a surface until now (partner-radar
|
|
355
|
+
`SortNav` + `cells.js`, search-radar `SortNav`, talent-radar's bar apart from its list). README "Collections" has the
|
|
356
|
+
rules.
|
|
357
|
+
|
|
358
|
+
Fixed
|
|
359
|
+
- Sort links are `linkAs` (IndexTable header and the sort chips below 768; DataTable header), the element the row
|
|
360
|
+
titles already used. 0.13.0 drew them as plain `<a>`, so on a Next surface every sort reloaded the whole page (frame,
|
|
361
|
+
open filters, scroll): partner-radar /apps and search-radar /keywords wrapped the table in a `SortNav` that caught the
|
|
362
|
+
click. New `sortLinkProps` (plain data) go to the sort links only: `{ scroll: false }` for a Next `Link` keeps the
|
|
363
|
+
scroll position, while opening a row still scrolls.
|
|
364
|
+
- Data table cells sit at the TOP of their row (`vertical-align: top`), as Polaris DataTable (its `verticalAlign`
|
|
365
|
+
defaults to "top", Polaris 13.9.5 Cell.js). A 24px cell link is pulled up by `calc((1lh - 24px) / 2)` so its text is on
|
|
366
|
+
the line of the cells beside it (top-aligned, the 24px box put it 2-4px low). The index table keeps `middle`.
|
|
367
|
+
In collections.css, not ui.css: the admin loads ui.css on every screen and draws no ui-table.
|
|
368
|
+
- The row header (`th.ui-table__rowhead`) wraps (Polaris `firstColumn`), with Polaris's first-column width as a floor
|
|
369
|
+
(9.0625rem) so a narrow frame scrolls instead of squeezing it to a word a line; `truncate` / `ui-clamp-2` cut it when
|
|
370
|
+
it must stay short. A link alone on its line is 24px in the row header and in a list inside a cell (`li > a`), as
|
|
371
|
+
`td > a` was. 0.13.0 kept ui.css's `nowrap` and matched `td > a` only: partner-radar wrapped 17 cells on five pages in a
|
|
372
|
+
`CELL()` box and set 24px by hand on 12 links (`cells.js`).
|
|
373
|
+
- `ResourceItem selected` no longer puts `aria-selected` on the `li` (a listitem does not take it; jsx-a11y
|
|
374
|
+
`role-supports-aria-props`): with a checkbox the box says it, without one (an item open beside the list) it is
|
|
375
|
+
`aria-current="true"`. kit-plain.js sets aria-selected on table rows only.
|
|
376
|
+
- Escape clears a selection unless a menu or dialog in the table / list is OPEN and shown: a closed `<dialog>` or a
|
|
377
|
+
hidden `role=menu` kept in a row used to swallow every Escape (IndexTable, kit-plain.js, and the new list; review
|
|
378
|
+
#3831).
|
|
379
|
+
|
|
380
|
+
Added
|
|
381
|
+
- `SelectableResourceList` (client module `resource-list-select.tsx`): a resource list with selection and bulk actions,
|
|
382
|
+
the IndexTable's rules: a checkbox first in each item's media slot, Shift+click range (anchor by id), Escape clears
|
|
383
|
+
(an open ⋯ menu or dialog takes it first), the actions get the ids in the list's order, the whole row still opens
|
|
384
|
+
the item. The bar is the list's header from the start ("0 selected", actions disabled): a list has no header to cover,
|
|
385
|
+
and a bar that appears on the first check pushed talent-radar /pool's rows 74px (1280) / 194px (390) under the finger.
|
|
386
|
+
`ResourceList` stays plain (server). `ResourceItem.check` is the slot it fills; an item's `id` is the selection key
|
|
387
|
+
only, never the `li`'s DOM id. Loading keeps each row's box (`CollectionSkeleton check` for a list), so the media
|
|
388
|
+
does not move when rows arrive. The selection rules and the bar are one module (`selection.tsx`) that IndexTable now
|
|
389
|
+
uses too.
|
|
390
|
+
- `CollectionColumn.minWidth` (DataTable): the column's floor, for cells that wrap (Polaris `firstColumnMinWidth`, any
|
|
391
|
+
column); replaces the row header's floor, and `0` removes it for a row header that is always short (a date, an id).
|
|
392
|
+
- Plain HTML: `div.ui-resource > div.ui-bulkbar + ul.ui-list`, `label.ui-list__check > input[data-gb-select]`;
|
|
393
|
+
kit-plain.js drives a `.ui-resource` like a `.ui-index` (action buttons enabled from 1 instead of the bar shown;
|
|
394
|
+
`gb:selection` fires after, for an action with a rule of its own).
|
|
395
|
+
- collections-gate: `select-without-bulk` also reports a resource list with selection boxes (in `__media`, or
|
|
396
|
+
`data-gb-select`) and no bar; a checklist's done box or a switch is not a selection box.
|
|
397
|
+
- Catalog: a multi-line job table at the catalog width and at 390, a selectable list (two selected) and at 390.
|
|
398
|
+
|
|
399
|
+
Measured (gemlabs partner-radar on the local proof DB, `next dev`, published 0.13.0 vs the 0.16.0 tarball with
|
|
400
|
+
`SortNav` and `cells.js` deleted, `CELL(n)` floors moved to `minWidth: n`, `style={LINK24}` removed from 12 links; same
|
|
401
|
+
rows; 320 / 390 / 768 / 1280)
|
|
402
|
+
| Page | rows whose cells' first lines differ > 1.5px | links < 24 outside a sentence | gate | page overflow |
|
|
403
|
+
|---|---|---|---|---|
|
|
404
|
+
| /ops (24 rows) | 24 → 3 (the 3: a status pill, its text 4px into its own padding) | 0 → 0 | 0 → 0 | none |
|
|
405
|
+
| /sources (193) | 183 → 3 (same pill) at 320-768, 175 → 3 at 1280 | 0 → 0 | 0 → 0 | none |
|
|
406
|
+
| /feed (27) | 26 → 0 | 0 → 0 | 0 → 0 | none |
|
|
407
|
+
| /competitors (93) | 80 → 0 | 0 → 0 | 0 → 0 | none |
|
|
408
|
+
| /search?q=shop (60) | 60 / 53 → 0 | 0 → 0 | 0 → 0 | none |
|
|
409
|
+
|
|
410
|
+
Total row height: /search 7,318 → 5,448 at 320, /sources 18,426 → 15,440 at 320-768; /feed +2% and /competitors +4% at
|
|
411
|
+
320 / 390 (a row header now wraps at its 145 floor instead of running one line wide). No table wider than its frame at
|
|
412
|
+
1280. Density gate: same count of differences or fewer on every page (competitors 48 → 36 at 1280).
|
|
413
|
+
Sort: /apps (partner-radar) and /keywords (search-radar) without `SortNav`, a header link at 1280 and a chip at 390:
|
|
414
|
+
0 document requests, the page's state kept, scroll 120 → 120. Negative: published 0.13.0 without `SortNav`: 1 document
|
|
415
|
+
request, state lost, scroll 120 → 0.
|
|
416
|
+
|
|
417
|
+
Checks
|
|
418
|
+
- `collections.test.ts`: sort links go through `linkAs` with `sortLinkProps` (header, chip, DataTable; the row title
|
|
419
|
+
keeps linkAs without them), negative: no `linkAs` = the browser navigates; first lines of a three-line row header, a
|
|
420
|
+
plain cell, a link cell and a number on one line, negatives with the top rule or the link rule cut out; the row header
|
|
421
|
+
wraps in a 560 frame, keeps its 145 floor at 390 (the frame scrolls), `minWidth` replaces it, a `truncate` column stays
|
|
422
|
+
one line, negative: the 0.15.0 nowrap overflows the frame and its link is a bare inline box; SelectableResourceList:
|
|
423
|
+
bar from the start, rows do not move on the first check, Shift range, ids to the action, select-all + Escape, a row
|
|
424
|
+
click opens the item through linkAs, Escape with a menu open keeps the selection, boxes 24 / 44 aligned with the
|
|
425
|
+
bar's, rows stay 64; kit-plain on `.ui-resource`; the gate on a list with and without its bar.
|
|
426
|
+
- Admin first load: the names the admin imports from `@gemboss/ui` bundle to the same bytes (7,967 minified, 2,685
|
|
427
|
+
gzip) before and after; ui.css, gemboss-ui.css and the admin's other stylesheets unchanged (this release touches
|
|
428
|
+
collections.css, the collections modules and kit-plain.js, none of which the admin loads).
|
|
429
|
+
|
|
430
|
+
## 0.15.0 (06/10/2026)
|
|
431
|
+
|
|
432
|
+
**Resource list in a narrow frame, and a body + wrap for the compact list.** Two package bugs a surface migration
|
|
433
|
+
(partner-radar, gemlabs #895) found in the 0.13.0 collections. README "Collections" has the rules.
|
|
434
|
+
|
|
435
|
+
Fixed
|
|
436
|
+
- Resource list when the LIST's frame is 400 or less. 0.13.0 wrapped the flex row, so the body's max-content (a long
|
|
437
|
+
subtitle) pushed it under the media, and the aside and the actions took a line each: partner-radar /hot rows went
|
|
438
|
+
from 221 (its old table) to 284 at 390. Now a grid with one rule for every row: the body stays beside the media
|
|
439
|
+
with all the width right of it; the aside and the actions share one line under the body (aside left, actions
|
|
440
|
+
right); the media spans both lines; without media the body takes the whole row. The `flex: 1 1 0` patch tried on
|
|
441
|
+
partner-radar fixed /hot but made /ugc-operators taller (308 → 332 at 320), because the actions sat beside the
|
|
442
|
+
body and narrowed it; the grid does neither. A body that is only its title keeps its aside and actions on that line
|
|
443
|
+
(one band, never taller than 0.13.0). Gaps are margins, so a row without media needs no `:has()`. The row's direct
|
|
444
|
+
children are the four slots (a selection checkbox goes inside `__media`); the loading skeleton keeps its own row.
|
|
445
|
+
Frames wider than 400 are unchanged.
|
|
446
|
+
|
|
447
|
+
Added
|
|
448
|
+
- `CompactItem.body` (activity): the event's own text under the label and the detail, `.ui-list__content` (body
|
|
449
|
+
size, wraps, never cut; `<p>` margins reset).
|
|
450
|
+
- `CompactList wrap` (`ui-list--wrap`, either variant): the label and the detail wrap instead of ending in "…". For a
|
|
451
|
+
list whose label carries data a finger must read (the cut text's `title` is mouse-only).
|
|
452
|
+
Under a finger the wrapped row is padded 12 + 20 + 12, so a one-line label stays centred in its 44px row.
|
|
453
|
+
- `CompactItem.labelText`: the full label in `title` (left out under `wrap`, where nothing is cut). `CompactListProps`
|
|
454
|
+
is exported.
|
|
455
|
+
- Catalog: the two row shapes at 390, and a timeline with body + wrap at 390.
|
|
456
|
+
|
|
457
|
+
Measured (gemlabs partner-radar on a local proof DB, `next dev`, 0.13.0 vs the 0.15.0 tarball, same rows; median /
|
|
458
|
+
total of all rows, px)
|
|
459
|
+
| Page | 320 | 390 | 768 | 1280 |
|
|
460
|
+
|---|---|---|---|---|
|
|
461
|
+
| /hot (100 rows) | 284 → **191** (28,747 → 20,123) | 284 → **191** (28,003 → 19,187) | 143 = 143 | 107 = 107 |
|
|
462
|
+
| /ugc-operators (40 rows) | 308 → **267** (12,067 → 10,427) | 284 → **243** (11,243 → 9,603) | 199 = 199 | 159 = 159 |
|
|
463
|
+
|
|
464
|
+
Row by row: 0 rows taller at any width; every row lower at 320 and 390; identical at 768 and 1280. collections-gate:
|
|
465
|
+
0 broken, page overflow 0, at every width. The four partner-radar timelines on `CompactList variant="activity" wrap`
|
|
466
|
+
with `body` instead of its own `.pr-tl-*` (profile with 4 events, profile with 15 jobs, an organization): every item
|
|
467
|
+
the same height as before at all four widths, 0 labels or details cut, 0 `.pr-tl-*` left.
|
|
468
|
+
|
|
469
|
+
Checks
|
|
470
|
+
- `collections.test.ts`: geometry of both row shapes (avatar + long subtitle + score + 44px link; no media + many meta
|
|
471
|
+
lines + badges + score + button + ⋯) at 320 / 390 / 768: body beside the media and as wide as the room, aside and
|
|
472
|
+
actions on one line under the body, the row exactly as tall as that layout asks, nothing sideways; no taller than
|
|
473
|
+
0.13.0 at any width and lower at 390; a title-only row stays one band; the skeleton keeps its block beside the bars.
|
|
474
|
+
Negative controls: the 0.13.0 rule and the `flex: 1 1 0` patch, planted in the
|
|
475
|
+
same CSS, break the checks. Compact list: with `wrap` nothing is cut at 320 / 390 / 768, the body follows the detail
|
|
476
|
+
at 13px, the time stays top right; without `wrap` the same label is one line and cut (control).
|
|
477
|
+
- Admin first load: the names the admin imports from `@gemboss/ui` bundle to the same bytes (7,967 minified,
|
|
478
|
+
2,685 gzip) before and after; `gemboss-ui.css`, `ui.css` and the other admin stylesheets are unchanged (this release
|
|
479
|
+
touches `collections.css` and `collections.tsx` only, which the admin does not load).
|
|
480
|
+
|
|
481
|
+
## 0.14.0 (06/10/2026)
|
|
482
|
+
|
|
483
|
+
**The editor frame as components (editor kit, step 2 of 5).** Nothing changes on screen in the admin: its theme, page and
|
|
484
|
+
section editors now render these, measured equal on a production build (below). README "Editor frame (0.14.0)".
|
|
485
|
+
|
|
486
|
+
Added
|
|
487
|
+
- `@gemboss/ui/editor` (its own entry; two modules, `frame` and `panes`, see README): `EditorFrame` (top · body with left column, seam and preview
|
|
488
|
+
pane · children; `split`, `right` docked over the preview, `mobilePane`, `embedded`), `EditorPaneTabs`, `EditorTopbar`
|
|
489
|
+
(`theme` / `page` / `guest`; back, chat toggle, title, three clusters, status line), `EditorBack`, `EditorChatToggle`,
|
|
490
|
+
`EditorSaveState`, and `DeviceToggle` / `MonitorGlyph` / `PhoneGlyph` (moved from the admin unchanged).
|
|
491
|
+
- `editor-plain.js`: `gembossUI.initEditorFrame()` for plain HTML (seam drag + keys clamped to the box, chat toggle,
|
|
492
|
+
device, phone pane, ⋯ / Publish ▾ menus; an event for each). Load after `kit-plain.js`.
|
|
493
|
+
- `catalog/editor.html`: the frame rendered from the components and running; `catalog/index.html` links it.
|
|
494
|
+
- editor.css: `.gemboss-editor-dock` (the right column; the declarations the theme editor's Global styles dock had
|
|
495
|
+
inline), its pane as containing block, and the frame's base geometry as zero-specificity `:where(…)` rules (left
|
|
496
|
+
column sized by `--gemboss-chat-w`, stacked at 1000px and below; preview takes the rest) so a page with only the
|
|
497
|
+
package lays out. In the admin every one of those properties is set more specifically, so none applies there.
|
|
498
|
+
|
|
499
|
+
Measured in the admin (two production builds of e3f3f92ec, before and after, pinned SENTRY_RELEASE / GIT_COMMIT_SHA /
|
|
500
|
+
GEMBOSS_BUILD_STAMP, served by `next start`)
|
|
501
|
+
- DOM and computed style (+ ::before / ::after and box) of every element on the page, and :hover / :focus-visible /
|
|
502
|
+
:active forced on every frame control, for 122 states of the three editors (default, Configure, chat collapsed,
|
|
503
|
+
device mobile / tablet, ⋯ open, Publish ▾ open, page picker open, status line, Global styles, phone Preview pane,
|
|
504
|
+
Layers, page settings, section insert menu) at 320, 390, 768 (touch), 1280, 1366, 1920: 27,606 element renders,
|
|
505
|
+
4,080 forced-state checks, 0 differences in computed style or box. The one markup change is the intended one (the
|
|
506
|
+
Global styles dock's inline style became its class, 6 states, computed style equal). Two states differed by the
|
|
507
|
+
canvas still loading at the moment of capture, one in each direction; re-captured, 0. A negative control (one
|
|
508
|
+
declaration laid over the after build) is reported (52 differences on one screen).
|
|
509
|
+
- The theme top bar and the try door's bar rendered on the server before and after with the same props (662
|
|
510
|
+
combinations of save state, chat toggle, status line, tools, device): byte-identical markup.
|
|
511
|
+
- First load: the shell's raw bytes are unchanged (the webpack runtime 7,981 to 7,979 bytes; brotli +1 B from four
|
|
512
|
+
lazy-chunk hashes). Editor routes: theme +684 B, page +681 B, section +625 B, A/B campaign editor +680 B brotli
|
|
513
|
+
(CSS +106 B of each, the dock and the `:where` geometry); product studio +107 B (the same CSS).
|
|
514
|
+
|
|
5
515
|
## 0.13.0 (06/10/2026)
|
|
6
516
|
|
|
7
517
|
**Collections: six patterns for tables, lists, grids and boards** (Chris 05/10/2026), each with its states. The CSS is
|
|
@@ -46,7 +556,8 @@ Changed (under a mouse, at 768px and wider)
|
|
|
46
556
|
- `ui-btn`: 28px tall (was 32), padding 0 12 (was 16), 12px (was 13). New `--ui-btn-h: 28px`; `--ui-control-h` stays 32
|
|
47
557
|
for `gemboss-field` and `ui-select` (Polaris TextField / Select). `ui-btn--icon` is 28 wide. The popup's own 28px rule
|
|
48
558
|
is gone (every button is 28). **A surface that raised `--ui-control-h` to grow its buttons must now set `--ui-btn-h`
|
|
49
|
-
as well
|
|
559
|
+
as well**. (This line used to name gemcare's `inbox.css` as such a surface: that rule was removed on 03/10/2026, and
|
|
560
|
+
gemcare takes 0.12.0 with no override, 28 under a mouse and 44 under a finger, measured on its inbox 06/10/2026, gemcare #312.)
|
|
50
561
|
- ui.css (what the admin loads): buttons and segments are 44 at phone width with a mouse too (`max-width: 47.9975em`),
|
|
51
562
|
as they already were under a finger; they were 32 there.
|
|
52
563
|
- `ui-seg`: 28px group, labels 12px/550. `ui-tabs`: 28px (was 44 under every pointer), 12px/550 selected or not, 8px
|