@gemboss/ui 0.36.1 → 0.40.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +441 -0
  2. package/README.md +617 -14
  3. package/catalog/editor.html +45 -25
  4. package/catalog/index.html +5522 -1448
  5. package/gemboss-ui.css +3 -3
  6. package/package.json +11 -2
  7. package/parts/components.css +2 -2
  8. package/parts/core.css +1 -1
  9. package/parts/shell.css +2 -2
  10. package/src/assistant/chat-markdown.ts +7 -4
  11. package/src/assistant.css +1 -1
  12. package/src/auth-field.css +1 -0
  13. package/src/auth-field.tsx +74 -0
  14. package/src/auth-sso-plain.js +1 -0
  15. package/src/auth.css +1 -1
  16. package/src/auth.tsx +64 -1
  17. package/src/brand-gem.tsx +19 -0
  18. package/src/brand.tsx +4 -7
  19. package/src/chat-plain.js +2 -2
  20. package/src/editor/controls.tsx +148 -11
  21. package/src/editor/frame.tsx +8 -4
  22. package/src/editor/index.ts +8 -4
  23. package/src/editor/panel.tsx +44 -14
  24. package/src/editor/repeater.tsx +322 -0
  25. package/src/editor/sortable.tsx +50 -24
  26. package/src/editor/swatch.ts +20 -0
  27. package/src/editor/tiles.tsx +51 -0
  28. package/src/editor-plain.js +1 -1
  29. package/src/editor-repeater.css +1 -0
  30. package/src/editor-tiles.css +1 -0
  31. package/src/editor.css +1 -1
  32. package/src/gemboss-field.css +1 -1
  33. package/src/icons.tsx +11 -0
  34. package/src/index.ts +14 -2
  35. package/src/kit-plain.js +1 -1
  36. package/src/service-switcher-plain.js +1 -1
  37. package/src/service-switcher.css +1 -1
  38. package/src/service-switcher.tsx +119 -35
  39. package/src/services.ts +4 -2
  40. package/src/shell.css +1 -1
  41. package/src/site.css +1 -0
  42. package/src/site.tsx +50 -0
  43. package/src/team-chat-data.ts +79 -0
  44. package/src/team-chat.css +1 -0
  45. package/src/team-chat.tsx +825 -0
  46. package/src/toggle-bar.tsx +60 -0
  47. package/src/ui.css +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,447 @@
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.40.0 (20/10/2026)
6
+
7
+ **A list's item edits in a popover** (item management IM1a, Chris 20/10/2026; GemPages 7.5's "Item management" read in its code).
8
+
9
+ Added
10
+ - `RepeaterList` `editIn="popover"`: the list stays one line per row; the row picked shows its controls in a layer under the list
11
+ (top layer, placed by `menu-layer.ts` `placeFloating`, as wide as the list), one row at a time. ✕, Escape (focus back on the
12
+ row) or the row clicked again close it; a click elsewhere does not (a row's controls open pickers and dialogs of their own).
13
+ A list of one row shows it in place, open (nothing to choose between). Without the popover API the row picked opens in
14
+ place. Default stays `inline`.
15
+ - `thumb(index)`: a 20px picture before the row's name (the admin passes the row's first image field).
16
+ - `onActive(index | null)`: the host hears the row picked, to show that item on the canvas.
17
+ - `packages/ui/src/editor-repeater.css`: the popover's placement and header, the picked row's outline, the picture (+220 B gzip,
18
+ 1,096 of its 1,384 B ceiling). The surface is the fleet's `gemboss-popover-surface`.
19
+
20
+ **A phone pays for the topbar once, and the full-screen assistant gets the whole width** (measured on the admin at 390×844,
21
+ 19/10/2026).
22
+
23
+ Fixed
24
+ - `.gemboss-platform-main` at ≤760px: `padding-top` is the 16px gutter (it was 56px). `margin-top: 56px` already clears the fixed
25
+ bar at every width, so a phone had 74px between the bar and a page's title.
26
+ - Full screen at ≤560px: the thread rail (`SessionRail`, one New chat button at that width) sits in the empty left of the
27
+ `.gb-dock-fullchrome` strip, a 44px circle at the strip's 8px/12px inset, instead of a 60px column beside the chat (330 of
28
+ 390px). CSS only: a surface that passes its own New chat through `fullActions` gets no second one. Above 560px nothing moves.
29
+
30
+ **`Switcher`: the nine-dot panel for any list, with illustrated tiles (GemCommunity's groups).**
31
+
32
+ Added
33
+ - `Switcher` (`SwitcherItem`, `SwitcherProps`): the dialog, search, groups, keys and phone sheet of `ServiceSwitcher`, for
34
+ items an app gives (`id`, `name`, `description`, `href`, `group`, `tint`, `badge`). A tile with `media` (`{ src }` an
35
+ image, `{ glyph }` an emoji drawn on its tint) is a card with the picture on top (`gb-svc__tile--media`,
36
+ `gb-svc__media`, 16:9); the groups holding cards lay out in 208px columns, two a row on a phone. `foot` puts the app's
37
+ own actions in the foot. Chris 20/10/2026: GemCommunity's group switcher "kèm hình ảnh minh hoạ, tên và description …
38
+ như các dịch vụ gemboss, gemcapture bấm vào icon lưới 9 chấm".
39
+
40
+ Changed
41
+ - `ServiceSwitcher` is now `Switcher` with the Gem services: the same markup as before (tests pin it).
42
+
43
+ **A competitor page's picture in the chat comes from the GemBoss admin, not from the market archive** (Chris 20/10/2026).
44
+
45
+ Changed
46
+ - `FLEET_IMAGE_HOSTS` (and chat-plain.js's copy) draws `https://admin.gemboss.ai/api/gemboss/market-image/…`, the admin's
47
+ signed picture door, and no longer lists the market archive's own host. GemBoss's tools now hand out admin URLs for
48
+ these pictures; the archive's host in this list put its name in every surface's bundle. A surface that draws the
49
+ archive's own pictures (its own dashboard) passes that host in `imageHosts`. An older answer that still holds an
50
+ archive URL shows the picture as a link, the rule for every host not on the list.
51
+
52
+ **The public site layer: one bar, one lockup size, one set of buttons for every public page** (Chris 20/10/2026: "có gemboss ui
53
+ thì có gemboss website ui"; two lockup sizes, site 18px and app 13.3px). Measured the same day: the logo name 18px on gemboss.ai
54
+ and the docs, 16px on news, 13.3px on the community home; the bar 65 / 57 / 69 / 56px.
55
+
56
+ Added
57
+ - `@gemboss/ui/site.css`, a new entry (1.0 KB gzip): `gb-site-header` (sticky, 64px, the 1132px column), `gb-brand--site` (the
58
+ lockup with an 18px name), `gb-site-nav` / `gb-site-link`, `gb-site-actions`, `gb-site-btn` `--primary` / `--secondary` (40px,
59
+ 36px in the bar, 44px under a finger), and the footer (`gb-site-footer`, `__grid`, `__col`, `__bottom`, `gb-site-wrap`). Values
60
+ are gemboss.ai's own; every colour a token, so the dark palette applies. README "The public site layer".
61
+ It stands alone: with only the tokens and site.css (no core), the site lockup is whole, for plain-HTML pages.
62
+ - `SiteHeader` and `SiteBrand` (`site.tsx`), which bring it. `SiteBrand` draws the same gem as `BrandLockup` and does not import
63
+ brand.tsx, so a public page never carries the ServiceSwitcher.
64
+ - Catalog section "Trang công khai"; `site.test.tsx` (markup, same gem, no rule on :root/html/body, no colour literal) and
65
+ `site-browser.test.tsx` (64px bar, 18px vs 13.3px, 44px controls at 390, no sideways scroll at 1280/390/320).
66
+
67
+ Changed
68
+ - The lockup's gem moved to `brand-gem.tsx` (`BrandGem`), shared by `BrandLockup` and `SiteBrand`. `BrandLockup` renders the
69
+ same markup as before.
70
+
71
+ **A colour not set is not black** (control standard §13b U7, Chris 20/10/2026). An empty colour drew a black swatch beside "Not set",
72
+ so a seller read a colour nobody chose.
73
+
74
+ Changed
75
+ - `ColorControl`: an empty value marks its swatch `data-empty` and opens it on white; `editor.css` draws the slash a picker draws for
76
+ "none" over it (`.gemboss-ei-swatch[data-empty]::-webkit-color-swatch`). A value the swatch cannot show is unchanged (black, off,
77
+ with the reason under it).
78
+ - `packages/ui/weight-budget.json`: `packages/ui/src/editor.css` 8,615 → 8,690 B gzip, Chris's OK on 20/10/2026. This rule is +45 B (8,665 measured); main
79
+ was already at 8,620, over the old ceiling, after two PRs that each passed it alone (#4701, #4648).
80
+
81
+ **The ? beside a label stays a 16px circle inside the page editor.**
82
+
83
+ Fixed
84
+ - `.gemboss-pageedit .gemboss-ec-dock-body`, `.gemboss-page-section-content` and `.gemboss-bundle-look .gemboss-ei-body` set every
85
+ button to 44px; the ? (`.gemboss-ei-help`) is now left out, as the inspector field's own 44px rule already left it out. It drew
86
+ 16x44, an oval beside every label in the page editor's Settings (measured 19/10/2026). Its target is its ring (::after).
87
+
88
+ **The team chat layer: GemCare's channel chat for every surface** (Chris 20/10/2026: bring GemCare's Slack-like channel chat to
89
+ GemCommunity, and make the two inherit the same UI so the next upgrade happens once). GemCare's look and behaviour (origin/main
90
+ 20/10/2026: public/assets/inbox.{html,css,js}) moved into the package; GemCare (plain HTML) and GemCommunity (React) draw the same thing.
91
+
92
+ Added
93
+ - `@gemboss/ui/team-chat.css`, a new entry (3.6 KB gzip, ceiling 4174): the screen (`gb-tc`, rail | conversation | right panel), the
94
+ rail (`gb-tc-rail`, `gb-tc-channel` with a kind glyph, `gb-tc-badge` and `--mention`), the head (`gb-tc-head`, back button, members
95
+ toggle), the list (`gb-tc-log` role=log, `gb-tc-day` sticky, `gb-tc-new`, `gb-tc-jump`), the message (`gb-tc-msg`, `--grouped`,
96
+ `--mention`, `--highlight`, `--sending`, `--failed`, `--active`, `--editing`; `gb-tc-quote`, `gb-tc-threadprev`, `gb-tc-receipt`, the action
97
+ bar `gb-tc-acts`), the composer (`gb-tc-composer`, one box: paperclip, a field that grows, send; "Replying to", files and mention
98
+ picker slots, "Also send to"), the thread panel (`gb-tc-thread`) and the people panel (`gb-tc-people`, sections "Online — n", rows
99
+ with a presence dot and a role chip, a 56px collapsed strip; usable on its own in an app shell's right column). Every colour a
100
+ `--gemboss-*` token (dark applies unchanged); no rule on :root/html/body. Reused, not redrawn: `Avatar` (portal.css), `Reactions`
101
+ (reactions.css), the kit's `ui-btn` / `ui-check`.
102
+ - The screen decides by its OWN width (container queries, not the viewport): > 1100px the right panel is a column (thread 380, people
103
+ 260 / 56); ≤ 1100px a drawer over the conversation with a scrim (the conversation keeps its width); ≤ 760px the channel list OR the
104
+ conversation (`data-view`), a back button, the panel a sheet over the chat. Under a finger every control is 44px; under a mouse the
105
+ rail and the action bar are 32px. The action bar is one tap away under a finger (the row takes focus) instead of a row of 44px
106
+ buttons under every message as in GemCare; the message list's own container query drops the quick reactions where it is narrow.
107
+ - React, props only (`team-chat.tsx`): `TeamChat`, `ChannelRail`, `ChannelSection`, `ChannelItem`, `ChatHeader`, `MessageList`,
108
+ `DaySeparator`, `NewMessagesLine`, `JumpToLatest`, `Message`, `ReadReceipt`, `Composer`, `ThreadPanel`, `PeoplePanel`, `PeopleSection`,
109
+ `PersonRow`; `TEAM_CHAT_LABELS` (every word, `labels` to translate). `TeamChat` holds focus in a drawer (focus in, the rest `inert`,
110
+ Escape / the scrim close it, focus back to the opener). `Composer`: Enter sends, Shift+Enter a new line, an IME composition is never cut.
111
+ - `teamChatRows`, `chatDayKey`, `chatDayWord` (`team-chat-data.ts`, plain TS): GemCare's rules for turns (same author, same day, < 5 min,
112
+ not a reply), day separators and the "New messages" line.
113
+ - Icons `hash`, `lock`, `reply`, `thread`, `paperclip`, `send`, `chevronLeft`, `chevronsDown`, `panelRight`.
114
+ - README "The team chat layer": the plain-HTML markup of every part, held to the React components by `team-chat-contract.test.tsx`.
115
+ Catalog section "Chat đội" (desktop with a thread, dark with people, the 1024 drawer, phone conversation and list, the people
116
+ panel alone). `team-chat.test.tsx` (markup, ARIA, states, the row rules, the stylesheet's rules) and `team-chat-browser.test.tsx`
117
+ (Chromium at 1366 / 1024 / 390 / 320: columns vs drawer, the screen's own width, list or conversation, no sideways scroll, 44px under
118
+ a finger, a tap shows the bar, Enter sends, contrast in light and dark; negative controls without the drawer and the finger blocks).
119
+
120
+ **A colour swatch that cannot show its value says why, under it** (Claude Design: a disabled control says why).
121
+
122
+ Added
123
+ - `swatchWhy(value)` (`@gemboss/ui/editor/swatch`): the reason, or null when the swatch shows the value. A theme token says which
124
+ one ("Theme color: Accent. Type a hex to use your own."), any other value that is not a 6-digit hex says it is kept as written.
125
+
126
+ Changed
127
+ - `ColorControl` draws that reason as a line under the swatch and its box (`.gemboss-ei-color-why`, 12/16 muted) and points the
128
+ swatch at it (`aria-describedby`); the swatch's title is the same sentence. It was a tooltip only, which a finger and the keys
129
+ never reach, and every colour the editors' toolbar picks is a token, so the swatch was grey after each one.
130
+
131
+ **Room between the settings, and one inset for the column** (Chris 20/10/2026: "khoảng cách giữa các dòng settings … dính tịt vào nhau",
132
+ "section settings padding 2 bên lại không đồng bộ với element settings", "chia cụm và các khoảng nghỉ"). Measured on the Canvas at 1280:
133
+ neighbouring fields of the element panel 0px apart (1,831 of 1,831 on the 71 kinds: the panel wraps each setting in a `<div>`, so each
134
+ field was a `:last-child` and lost its 12px); a section's settings 36px in from the column's edges where the element panel's are 16.
135
+
136
+ Changed
137
+ - Inside a collapsible group (`.gemboss-ei-grp`) the gap is the group's, between its items, whatever wraps a field: 12px, 8px under
138
+ the header, none above a hint. A `.gemboss-ei-group` holds its fields bare, and their own 12px applies.
139
+ - `.gemboss-ei-grp`, `.gemboss-ei-group`: 16px above and below (12): a pause between clusters, larger than the one between fields.
140
+ - `.gemboss-settings-body`: fields 12px apart (20), the label 6px above the box (4), as in a group. Docked in the Canvas's column it
141
+ drops its own 16px 20px, so the column's inset is the one: that rule is the Canvas's (admin `funnel-canvas.css`), as this file
142
+ is at its weight ceiling.
143
+
144
+ Removed
145
+ - `.gemboss-ei-group > .gemboss-ei-fld:last-child`: the same as `.gemboss-ei-fld:last-child`.
146
+
147
+ **The editor's frame at the kit's size under a mouse** (Chris 19/10/2026: "những cái button vẫn bị to hơn chuẩn của gemboss ui"). Every
148
+ control of the element panel was already on the standard (measured on all 71 kinds); the frame around it was not. Measured on the Canvas
149
+ at 1280: Publish 33px, 14 / 600, 20px in; Undo, Redo and ⋯ 32 × 36; ← and the panel toggle 30 × 30; the Settings · Chat tabs 38px, 12 / 600.
150
+
151
+ Changed
152
+ - `.gemboss-editor-tb-publish`: 28px (`--ui-btn-h`), 12 / 550 / 16, 12px in, as the kit's button; its caret 8px in. A narrow bar and a
153
+ finger keep their own rules.
154
+ - `.gemboss-pv-device` (the bar's icon buttons), `.gemboss-editor-back`, `.gemboss-editor-chat-toggle`: 28 × 28.
155
+ - `.gemboss-ec-tabs > [role="tab"]`: 28px, 12 / 550 / 16, 12px in (Polaris Tabs); 44px at 767 and below as before.
156
+
157
+ Removed
158
+ - The 36 × 32 box and 44px overlay the theme and page editors' icon buttons wore above 1000px: on 28px boxes 8px apart the overlays
159
+ would cross, and under a mouse the kit asks 28.
160
+
161
+ **A popup opened from a link draws no ring around itself.**
162
+
163
+ Fixed
164
+ - `.ui-modal:focus` has no outline. The panel takes focus on open and is never a Tab stop; Chrome drew its own ring
165
+ around the whole dialog when that focus came from a script with no click before it (every admin settings door, 19/10).
166
+
167
+ **Tabs, row buttons and the trail at Polaris sizes** (control standard U3b).
168
+
169
+ Changed
170
+ - `.gemboss-ei-tab` (an inspector's Settings / Advanced): 12px / 550 on a 16px line, 28px tall (it was 27px / 600).
171
+ - `RepeaterList`: a row's ↑ ↓ duplicate ✕ and its toggle at radius 8 (6); "+ Add item" is the kit's `.ui-btn` at full width (it
172
+ was a dashed box, 13px / 450).
173
+
174
+ **A field's buttons are Polaris buttons, and one touch rule** (control standard U3, research pickers-2026-10-16 §13b).
175
+
176
+ Changed
177
+ - `ChipButton` (Choose, Remove, Select image, Library, Clear, + Add…) is the kit's `.ui-btn`, a Polaris secondary button: 28px,
178
+ 12px / 550, radius 8, 44px under a finger. It was `.gemboss-ei-addchip`, a dashed pill (27px, 11px / 600, radius 999).
179
+ - The inspector's tabs, group heads, swatches and field controls grow to 44px on the kit's rule, `(pointer: coarse), (max-width:
180
+ 47.9975em)`, not on `(pointer: coarse)` alone: at 390px with a mouse the fields were 44px and the heads 20px.
181
+ - The "?" keeps its 16px circle under a finger and is pressed in a 44px ring (it grew into a 44px circle that pushed its label).
182
+
183
+ Removed
184
+ - `.gemboss-ei-addchip`: use `ChipButton` (or `.ui-btn`).
185
+
186
+ **A number box with its unit stays one line inside a field** (fix of U1). The admin's FieldRenderer puts `UnitField` straight
187
+ inside `.gemboss-ei-fld`, and its box is a `<label>`: the field's label rule (`.gemboss-ei-fld>label`, 0,1,1) beat the group's
188
+ `display:flex` (0,1,0), so the box was a block, 42px high with the unit under the value, a 6px label margin and the label's type
189
+ on the value. Measured on the section panel at 1280: 7 of 7 such boxes.
190
+
191
+ Fixed
192
+ - The label rules leave a field group out: `.gemboss-ei-fld>label:where(:not(.gemboss-field))`, same weight as before, in the
193
+ plain rule and the quiet one inside a group.
194
+
195
+ Changed
196
+ - `editor.css` 8.580 → 8.571 B gzip: two rules that repeated a selector (`.gemboss-pagepicker-list`, `.gemboss-platform-main:has(.gemboss-editor)`)
197
+ are one each, and `.gemboss-ei-gh:hover` is gone (it set the colour the header already has).
198
+
199
+ **Type at Polaris sizes in the panel** (control standard U2, research pickers-2026-10-16 §13b). Measured on the element panel at 1280:
200
+ 130 hints at 11px, and 215 "?" buttons drawn in the browser's 13.33px / 400.
201
+
202
+ Changed
203
+ - `.gemboss-ei-hint` 11px → Polaris bodySm **12px / 16px**, 4px under its control (Polaris help text's gap; it was 8).
204
+ - `.gemboss-ei-help` (the "?"): its `font` shorthand ended in `inherit`, which is not valid there, so the whole declaration was
205
+ dropped; now `650 10px/16px var(--gemboss-font-sans)`.
206
+ - `.gemboss-ei-gh-note` (a group header's aside) 10px / 500 → 12px / 450.
207
+ - `.gemboss-settings-field > span` (the section panel's and the page-settings sheet's field labels) 13px / 700, full colour → the
208
+ inspector's quiet label, 13px / 450 in `--gemboss-text-muted`, 4px above its control (it was 6).
209
+
210
+ **The panel's edges line up** (control standard U1, research pickers-2026-10-16 §13b; Chris 19/10/2026: "giờ méo, kích thước chưa
211
+ chuẩn polaris"). Measured on the element panel at 1280 before: 71 rows whose number box stopped short of the panel's right edge
212
+ because the unit sat outside it, swatches 34px beside 32px boxes, group titles 16px right of the labels under them.
213
+
214
+ Added
215
+ - **`UnitField`** (`editor/controls.tsx`): a number box with its unit INSIDE, as Polaris TextField's `suffix`. A
216
+ `label.gemboss-field.gemboss-field--group` around `.gemboss-field__bare` and `.gemboss-field__suffix`, so a click anywhere in the
217
+ box, the unit included, focuses it. Props: every `<input>` prop, plus `unit`, `className` and `style` for the box.
218
+ - `.gemboss-field__suffix` (`gemboss-field.css`): the unit's place in a field group, Polaris secondary text, 6px after the value.
219
+
220
+ Changed
221
+ - `ValueControl`'s box is a `UnitField` (`.gemboss-ei-value-box`, 7em: 91px at 13px, 112px at the phone's 16px), the unit inside.
222
+ - `.gemboss-ei-swatch` 34 → 32px, the height of the box beside it.
223
+ - `InspectorGroup`'s header: the disclosure mark sits at the END of the line, drawn as a chevron (two borders; down open, right
224
+ closed), so the title starts on the labels' edge. The ▾ / ▸ glyph stays in the markup for `editor-plain.js`, hidden.
225
+ - A field group whose text field is disabled is drawn disabled (50%, not-allowed) and does not react to hover; a disabled colour
226
+ swatch beside an editable box does not dim the box.
227
+
228
+ Removed
229
+ - `.gemboss-ei-suffix` (the unit beside the box): use `UnitField`.
230
+
231
+ **The section panel's groups are the inspector's** (control standard §13b U5). The band panel listed each element's options and
232
+ lists in native `<details>` (the browser's triangle, no divider); they are `InspectorGroup`s now.
233
+
234
+ Added
235
+ - `InspectorGroup`'s `attrs`: `data-*` attributes on the group itself (`.gemboss-ei-grp` / the static `section`), so a page that
236
+ finds a group by an attribute needs no wrapper. A wrapper made each group the `:last-child` of its own parent, and the divider
237
+ between groups (`.gemboss-ei-grp:last-child{border-bottom:none}`) never drew.
238
+
239
+ ## 0.39.0 (19/10/2026)
240
+
241
+ **A field of real pages for the sign-in panel, and an entrance for the screen.** Chris, on admin.gemboss.ai/login:
242
+ "animation ko quá lố nhưng thể hiện được những kỹ thuật, có chiều sâu như ở ngoài website". gemboss.ai opens on a
243
+ tilted field of real pages; the sign-in panel can now do the same, quieter.
244
+
245
+ Added
246
+ - **`AuthPageField`** (`auth-field.tsx`, its own entry `auth-field.css`, 1.1 KB gzipped): five columns of page thumbnails
247
+ the surface serves (portrait, 3:4) on a plane tipped back in perspective, drifting 100 to 130 seconds a lap, neighbours
248
+ the other way; a veil of the panel's ink keeps the words readable; a fine pointer leans the plane by at most 3 degrees.
249
+ Each column is dealt at least five pages so a lap never shows a gap. Images are lazy and live inside the panel, so a
250
+ screen without the panel (under 900 wide or 520 tall) never fetches them.
251
+ - **`AuthLayout` `art`**: anything drawn on the panel under its words. Pair it with `backdrop="none"`.
252
+ - **`className="gb-auth--alive"`** (with `AuthPageField` loaded): the mark, the name and the tagline, then each field,
253
+ then the panel's words rise 12px as they fade in, 0.7s each, all done by 1.1s; one light passes over the mark.
254
+
255
+ Nothing changes for a surface that does not opt in. Under `prefers-reduced-motion: reduce` the field is a still picture
256
+ and nothing rises.
257
+
258
+ **And "Continue with GemBoss" for the internal tools** (Chris, 16/10/2026: one sign-in for the fleet, "có cả continue
259
+ với gemboss hoặc nhập mật khẩu"; protocol in gemboss docs/fleet-sso.md).
260
+
261
+ Added
262
+ - **`AuthContinueWithGemBoss`** `{ service, next }`: put it first inside `AuthLayout`, above the form. An outline button
263
+ with the gem (the password form keeps the one dark button), then "or use the password". It links to GemBoss's door
264
+ for this tool; once the tool has set `gb_sso=1` (a browser that came in this way) the page continues by itself,
265
+ except over a reason the tool sent back (`?sso=not_member|invalid|off`, shown under the button) or `?password=1`.
266
+ - **`gemBossSignInUrl(service, next)`**, **`continuesByItself(cookie, search)`**: the same two rules, for a page that
267
+ writes the markup itself.
268
+ - **`auth-sso-plain.js`** (`@gemboss/ui/auth-sso-plain.js`, 1.1 KB gzipped, its own entry: kit-plain.js had no room
269
+ under its ceiling): `gembossUI.initContinueWithGemBoss()` for a sign-in page with no React. The page writes
270
+ `<a class="gb-auth-sso-btn" data-gb-sso="<tool>" data-next="/admin">` inside a `.gb-auth-sso`; the script points it at
271
+ GemBoss, fills in the gem, the label, the reason and "or use the password", and continues by itself under the same rules.
272
+ - auth.css: `.gb-auth-sso-btn`, `.gb-auth-sso-why`, `.gb-auth-sso .gb-auth-or` (auth.css 3,013 B gzip, under its ceiling).
273
+
274
+ **The save pill reads on the light bar.** `EditorSaveState`'s colours were the old dark topbar's: measured on the page editor's
275
+ bar (white) 19/10/2026, "✓ Draft saved" read 1.35:1 and "Saving…" 1:1, white on white. They are on the tokens now:
276
+ "Saving…" in `--gemboss-text-muted` on the bar (5.3:1), "✓ Draft saved" in `--gemboss-success-strong` on
277
+ `--gemboss-success-soft` (5.6:1), the spinner `--gemboss-divider` with a `currentColor` arc. The idle words ("Autosaves", the
278
+ page editor's "Draft saved · <when>") were the text at opacity .55, 3.31:1: they are `is-idle` now, the muted token (5.3:1), and
279
+ the inline `style` is gone from the markup. The theme and section editors' pills change with it.
280
+
281
+ **`EditorSaveState` can be unannounced.** `live` (default `true`, so every editor reads as before): `live={false}` draws the same
282
+ words and title without `role=status` / `aria-live`, for a surface that speaks through a live region of its own, in the page
283
+ from its first render and saying only what changed (the admin's page editor: "Saving…", "Saved just now", "Your last change
284
+ was not saved."). Two live regions for one pill announced it twice, and a region mounted with its first words is not read.
285
+
286
+ **The page and section editors' bar keeps its free space beside its centre.** Above 1000px `.gemboss-pageedit-top` is
287
+ `auto fit-content(100%) auto` with the default `justify-content` (it was `auto auto auto` with `space-between`, which the theme
288
+ editor keeps): the free space goes into the left and right tracks, half each, instead of between the three clusters. The
289
+ centre and the right sit exactly where they were (measured 19/10/2026 at 1024-1920 on the page editor's bar, the Studio's and
290
+ the section editor's). What changes is the left track: it has room past its content, which is where the admin's page editor
291
+ draws its save pill (in its own sheet, adding no width to any track). The page editor's left cluster declares its gap as
292
+ `--gemboss-tb-gap` (12px), so a child can hand it back; a bar with another gap sets the property.
293
+
294
+ **Toggles that are each on or off.** `ToggleBar` (from `@gemboss/ui` and `@gemboss/ui/toggle-bar`, 17/10/2026, Chris: the panel
295
+ was missing pickers; research `_local/gemboss/research/pickers-2026-10-16/pickers.md` §13 slice 8): a row of buttons drawn as
296
+ `.ui-seg`, any number pressed at once (`aria-pressed`), `role="toolbar"` with one Tab stop and ← → Home End along it. `keepFocus`
297
+ leaves the focus where it is on a press, so a text box keeps its selection. The admin's text toolbar (Bold, Italic, Underline,
298
+ Highlight, Accent color, Warning color, Link) draws through it. Not a switch: "pick one of these" stays `Segmented`.
299
+
300
+ Added
301
+ - `ToggleBar` (`toggle-bar.tsx`, a client module of its own: `segmented.tsx` stays free of hooks for the server components that
302
+ import `Segmented`).
303
+
304
+ **A segmented option can be a glyph with a name.** `Seg` options take `name` (17/10/2026): the button's accessible name and
305
+ its hover title, for a label that is an arrow (the admin's gradient direction: ↓ → ↘ ↗, named Down, Right, Down right, Up right).
306
+
307
+ **A choice of shapes is picture tiles.** `ChoiceTiles` (from `@gemboss/ui/editor`, 16/10/2026, Chris: the panel was missing
308
+ pickers; research `_local/gemboss/research/pickers-2026-10-16/pickers.md` §4, pattern P9): each option a tile with its picture
309
+ (`picture`, or a rectangle `shape` of w×h drawn to fit 26px) and its name, 4 to a row, the lit one `aria-pressed`; 56px tall,
310
+ past 44px under a finger. The admin draws an image's ratio with it (Original, 1:1, 4:5, 4:3, 3:2, 16:9, 9:16 + a Custom box).
311
+
312
+ Added
313
+ - `ChoiceTiles` (`editor/tiles.tsx`) and its own part `@gemboss/ui/editor-tiles.css` (parts.mjs, export, weight ceiling 1,000 B).
314
+ - `ChoiceTiles` sizes its tiles to fit (as many to a row as fit at 72px: 4 in a 350px panel, 3 on a phone, 2 wide ones for a choice of two) and a
315
+ name wraps to two lines instead of being cut ("Main image and thumbnails"): the admin's layout tiles (17/10/2026).
316
+
317
+ **A setting that is a list reads as rows.** `RepeaterList` + `useKeyedRows` (from `@gemboss/ui/editor`, 16/10/2026, Chris: the
318
+ panel was missing pickers; research `_local/gemboss/research/pickers-2026-10-16/pickers.md` §9). Each row: a grip to drag, its
319
+ name (folds it), ↑ ↓, duplicate, ✕; more than one row opens folded and a row added or duplicated opens; the count beside the
320
+ list's name; Alt+↑/↓ moves a row and keeps the focus. Rows are kept by key, so a row's typing follows it when it moves.
321
+
322
+ Added
323
+ - `RepeaterList` (`touch`: 44px buttons with a mouse too), `useKeyedRows` (`patch(key, fn)` writes a field by the row's key onto its
324
+ latest version; a refused write, `commit` answering false, puts the stored list back; the stored list is read by content),
325
+ `useRowDrag`, `dropIndex` (`editor/repeater.tsx`, `editor/sortable.tsx`).
326
+ - `@gemboss/ui/editor-repeater.css`: its own part, imported by `RepeaterList`.
327
+
328
+ Changed
329
+ - `SortableLayerList` drags through `useRowDrag`, the same rule as `RepeaterList` (behaviour unchanged; its browser tests pass).
330
+
331
+ Moved
332
+ - `.gemboss-ei-rep*` out of `editor.css` into `editor-repeater.css` (editor.css 8.4 → 8.2 KB gzip).
333
+
334
+ **The settings panel reads like the rest of the admin.** Chris 16/10/2026: the panel's controls looked bigger than the kit's
335
+ and Polaris's. Measured (a countdown's Settings tab, 1280, a mouse): every control was Polaris-sized already (field 32/13,
336
+ chips 26-28/12, buttons 28); the panel was long, 3,363px, because each setting was a label line over its control (70px a
337
+ setting) and 22% of the height was help lines. Research of GemPages, PageFly and Replo:
338
+ `_local/gemboss/research/inspector-density-2026-10-16.md`.
339
+
340
+ Changed, inside an inspector group (`InspectorGroup`) only; a plugin's settings form is unchanged:
341
+ - `Field` takes `row`: label left (2 parts), control right (3 parts), for a one-value setting. GemPages draws a setting in 52px
342
+ this way. The admin sets it on toggles, selects, chip sets of up to three, numbers (the unit beside the box), ranges and
343
+ colours. Value controls (chips + box + slider), longer chip sets, text, dates, spacing, images and lists keep the label
344
+ above: their parts need the panel's width (measured: "None 1 2 3 4" was cut in the control column). A countdown's
345
+ Settings tab went from 3,363px to 2,197px.
346
+ - `Field`'s `hint` with a label is behind a ? beside the label (`button.gemboss-ei-help`, named "About <label>", described by
347
+ the help line): a click, Enter or a tap shows it as the line under the control, again hides it. Outside a group the
348
+ ? is not drawn and the line shows, as before. The line is still one node (`p.gemboss-ei-hint.gemboss-ei-help-text`).
349
+ - Labels are quiet: 13px / 450, secondary (Polaris bodyMd).
350
+ - Group titles (`.gemboss-ei-gh`) are Polaris headingSm everywhere: 13px / 650, sentence case, the text colour. They were
351
+ 10-11px uppercase with letter spacing, the old vault look.
352
+
353
+ Removed
354
+ - `.gemboss-pageedit-modes`: no source in the fleet draws it.
355
+ - `.gemboss-ei-img-grid` / `.gemboss-ei-img-cell`: the image field's inline library grid. The admin's image field opens the
356
+ media picker since gemboss #4474 (16/10/2026) and nothing in the fleet draws the grid any more.
357
+
358
+ ## 0.38.0 (15/10/2026)
359
+
360
+ **A setting you can click as well as type.** `ValueControl` (from `@gemboss/ui/editor`): a number's named values as chips, then
361
+ its box with the unit and, for a bounded range, a slider. Chris 15/10/2026: "có option để vừa bấm được vừa nhập được, lười thì bấm".
362
+ Research of GemPages, PageFly, Replo and Shopify: Shopify's reference themes never show a bare number box for a style; GemPages and
363
+ PageFly both left border width one.
364
+
365
+ Added
366
+ - `ValueControl`: props `presets` (`{ value, label }`, smallest first), `text` (what the box holds), `suffix`, `slider`
367
+ (`{ min, max, step, value }`), `note`, and `onPreset` / `onText` / `onCommit` / `onSlide` / `onKeyDown`. The chips are the kit's
368
+ segmented control (`Seg`): the one whose value the box holds lights, a value of its own lights none. The caller owns the value.
369
+ - `.gemboss-ei-value`, `.gemboss-ei-value-row`, `.gemboss-ei-value-box`: chips on top, then the 72px box with its unit and the
370
+ slider filling the rest of the row.
371
+
372
+ ## 0.37.1 (16/10/2026)
373
+
374
+ **Three things the ServiceSwitcher rollout found on the 16 services.** A sliver of the search's first letter at 320
375
+ (GemMedia), the panel opening 6px over a header of the surface's own (GemNews's admin), and a React hydration warning
376
+ about `<html>` on the Next surfaces that import `kit-plain.js` (talent-radar, post-studio: 1 load in 3).
377
+
378
+ Fixed
379
+ - **The search under its floor is its icon.** In a bar with the switcher, under 360px, the search goes below its 96px
380
+ floor (0.36.0), and its words did not fit: measured in Chromium with the switcher, the assistant and the account, the box
381
+ is 56 / 58 / 78 wide at 300 / 320 / 340 and showed 0 / 2 / 22px of its words (a cut letter). Below 96 wide it is now the
382
+ search icon alone, centred (a container query on the centre slot, `gb-svc-search`, set only in that bar under 360).
383
+ Both topbar searches: `TopbarSearch`'s input covers the box, placeholder unpainted, name still its `aria-label`, the
384
+ icon stepping aside while it is focused or holds words; `SearchDialog trigger="field"`'s words stay the link's name,
385
+ visually hidden. At 359 and up, and in a bar without the switcher, every number is unchanged (30 of 36 measured rows
386
+ identical; the 6 that change are those three widths, both searches).
387
+ - **…and the box is a target again there.** `TopbarSearch`'s input had the 0-2px left of the box at 300 / 320, so a tap at
388
+ the box's centre landed on the icon and focused nothing (typing went nowhere). It now lands in the input.
389
+ - **The panel hangs under the bar that holds the button**, the closest `.gemboss-platform-topbar`, `header` or
390
+ `[role="banner"]` around it (never above the button's own bottom), else under the button. Only the kit's topbar was
391
+ looked for, so on GemNews's admin (its own 56px `<header>`, the plain script) the panel was placed from the 32px button
392
+ and opened at y=50, over the header's last 6px; now 62. The kit's topbar is unchanged: 62 at 1280. The GemBoss admin's
393
+ `/admin` console draws its own 56px `<header class="gemboss-admin-topbar">` too, so it moves the same way (50 → 62,
394
+ read off its CSS, not measured); the seller shell's bar is the kit's topbar, unchanged. The React component and
395
+ `service-switcher-plain.js` share the selector (`BAR`) and the rule, held equal by a test.
396
+ - **`kit-plain.js` writes nothing on `<html>` as it loads.** The `data-gb-menus="float"` flag (kit-plain.css: an open
397
+ list nobody has floated yet stays unpainted, 0.18.0) now goes on in the capture phase of the click that opens a menu,
398
+ which runs before the browser opens the details (Enter and Space on a summary are that click too), and on any opening
399
+ after; it is put back if something took it off. A client module that imports the script can run before React hydrates
400
+ `<html>`, and React then reported the attribute. Measured on a Next 16.2.6 / React 19.2.6 app (`next dev`) with the
401
+ script made to run before hydration (`next/script` `beforeInteractive`, the order an import lands in 1 load in 3 on
402
+ post-studio; imported from a client module alone it ran after hydration 30 of 30 loads there): 0.36.1 warned on 20 of 20 loads ("A tree hydrated but some attributes of the server rendered HTML
403
+ didn't match"), 0.37.1 on 0 of 20; a click on its menu then sets the flag and floats it, 20 of 20. Plain pages keep
404
+ what the flag is for: the first frame after the opening click paints the list hidden, never inside its frame (20 of 20
405
+ by mouse and by Enter; without the flag it is inside its frame 20 of 20). post-studio's `suppressHydrationWarning` on
406
+ `<html>` is not needed for this any more.
407
+
408
+ Added
409
+ - Two services in the catalogue (`GEM_SERVICES`, `ServiceId`, the plain-HTML copy), both live since 15/10/2026: **GemX**
410
+ (`gemx`, https://x.gemboss.ai, "Tests and personalization across every store.", Build the store, after GemForm, icon
411
+ `sliders`, tint amber) and **GemPixel** (`gempixel`, https://pixel.gemboss.ai, "Events every store sends, and whether they
412
+ add up.", Read the market, after GemMarket, icon `activity`, tint blue). The panel now has 18 tiles. Their own admins can
413
+ pass `switcher={{ current: "gemx" }}` / `"gempixel"` once they are on this version.
414
+
415
+ Changed
416
+ - A menu opened by code (`details.open = true`) before any menu has been clicked may show inside its frame for one frame
417
+ before it floats, as every menu did before 0.18.0. A menu served open is floated as the script loads, as before.
418
+ - Weight (gzip of the minified file): `service-switcher.css` 1815 → 2040, `service-switcher-plain.js` 4559 → 4583,
419
+ `kit-plain.js` 8704 → 8742. No ceiling raised.
420
+
421
+ Tests: `service-switcher-browser.test.tsx` (Chromium): both searches at 300 / 320 / 340 in a bar with the switcher (no
422
+ words painted, icon centred within 1px, the centre of the box its target, the name kept, nothing wider than the screen),
423
+ a tap at 320 types into `TopbarSearch`, and 359 / 390 / 320-without-the-switcher unchanged; negative control: 0.36.1's
424
+ sheet paints 2px of the words at 320 and the centre tap lands on the icon. `service-switcher-plain-browser.test.ts`: the
425
+ panel 6px under GemNews's header, plain and React on the same pixel; 62 on the kit's topbar, both; 6px under the button in
426
+ no bar, both; negative control: 0.36.1's selector opens it at the button's bottom + 6, over the header.
427
+ `service-switcher-plain-data.test.ts`: one `BAR` in both files. `collections-board.test.ts`: no `data-gb-menus` until a
428
+ menu opens, the first frame after a mouse / Enter / Space opening never inside the frame (negative control: a kit that
429
+ never sets the flag paints it there); a React development build hydrating the whole document after kit-plain.js ran logs
430
+ no hydration warning and its menu floats with the flag (negative control: the flag set at load, 0.36.1, warns).
431
+
432
+ Also in this release: 0.37.0 (#4425), merged and not published until now (npm has 0.36.1).
433
+
434
+ ## 0.37.0 (15/10/2026)
435
+
436
+ **A spacing box's side can be dragged.** `EdgeBox` takes `onScrub(side, dx, keys)` and `onScrubEnd(side, moved)`: with them,
437
+ each side's letter (T · R · B · L) is a drag row, as Figma's and Webflow's number labels are. The package reports how far the
438
+ pointer moved and which keys are held; the caller turns that into a value and saves once when the drag lets go.
439
+
440
+ Added
441
+ - `.gemboss-ei-edge-scrub`: the letter as a 24px row the box's width (WCAG 2.5.8), `cursor: ew-resize`, hover fill
442
+ `--gemboss-hover`. A mouse or a pen drags; a finger scrolls the panel (`touch-action: pan-y`) and types in the box, which is
443
+ 44px under a finger. A press that moves under 2px is a click (`moved: false`).
444
+ - Without `onScrub` the letter is the plain `<span>` it was: nothing changes for other callers.
445
+
5
446
  ## 0.36.1 (15/10/2026)
6
447
 
7
448
  **The package reads only tokens it declares.** It read eight `--gemboss-*` tokens it never declared, each with a