@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.
- package/CHANGELOG.md +441 -0
- package/README.md +617 -14
- package/catalog/editor.html +45 -25
- package/catalog/index.html +5522 -1448
- package/gemboss-ui.css +3 -3
- package/package.json +11 -2
- package/parts/components.css +2 -2
- package/parts/core.css +1 -1
- package/parts/shell.css +2 -2
- package/src/assistant/chat-markdown.ts +7 -4
- package/src/assistant.css +1 -1
- package/src/auth-field.css +1 -0
- package/src/auth-field.tsx +74 -0
- package/src/auth-sso-plain.js +1 -0
- package/src/auth.css +1 -1
- package/src/auth.tsx +64 -1
- package/src/brand-gem.tsx +19 -0
- package/src/brand.tsx +4 -7
- package/src/chat-plain.js +2 -2
- package/src/editor/controls.tsx +148 -11
- package/src/editor/frame.tsx +8 -4
- package/src/editor/index.ts +8 -4
- package/src/editor/panel.tsx +44 -14
- package/src/editor/repeater.tsx +322 -0
- package/src/editor/sortable.tsx +50 -24
- package/src/editor/swatch.ts +20 -0
- package/src/editor/tiles.tsx +51 -0
- package/src/editor-plain.js +1 -1
- package/src/editor-repeater.css +1 -0
- package/src/editor-tiles.css +1 -0
- package/src/editor.css +1 -1
- package/src/gemboss-field.css +1 -1
- package/src/icons.tsx +11 -0
- package/src/index.ts +14 -2
- package/src/kit-plain.js +1 -1
- package/src/service-switcher-plain.js +1 -1
- package/src/service-switcher.css +1 -1
- package/src/service-switcher.tsx +119 -35
- package/src/services.ts +4 -2
- package/src/shell.css +1 -1
- package/src/site.css +1 -0
- package/src/site.tsx +50 -0
- package/src/team-chat-data.ts +79 -0
- package/src/team-chat.css +1 -0
- package/src/team-chat.tsx +825 -0
- package/src/toggle-bar.tsx +60 -0
- 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
|