@gemboss/ui 0.47.0 → 0.50.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 +315 -0
- package/README.md +162 -18
- package/catalog/editor.html +1 -1
- package/catalog/index.html +53 -49
- package/gemboss-ui.css +4 -4
- package/package.json +23 -2
- package/parts/components.css +3 -3
- package/parts/core.css +1 -1
- package/parts/shell.css +2 -2
- package/src/app-shell.css +1 -1
- package/src/assistant/chat.tsx +50 -6
- package/src/assistant/host.tsx +19 -7
- package/src/assistant/index.ts +1 -1
- package/src/assistant/sessions.tsx +2 -1
- package/src/assistant-chat.css +1 -1
- package/src/assistant.css +1 -1
- package/src/auth-signin-plain.js +1 -0
- package/src/auth-sso-plain.js +1 -1
- package/src/auth.tsx +105 -8
- package/src/briefing-card.css +1 -1
- package/src/collections.css +1 -1
- package/src/create-shell.css +1 -0
- package/src/create-shell.tsx +221 -0
- package/src/editor-insert.css +1 -0
- package/src/editor.css +1 -1
- package/src/empty-stage.css +1 -0
- package/src/empty-stage.tsx +31 -0
- package/src/icons.tsx +2 -0
- package/src/index-table.tsx +7 -4
- package/src/index.ts +16 -2
- package/src/kit-plain.css +1 -1
- package/src/kit-plain.js +1 -1
- package/src/language-switcher-plain.js +1 -1
- package/src/language-switcher.css +1 -1
- package/src/language-switcher.tsx +10 -41
- package/src/list-page.css +1 -0
- package/src/list-page.tsx +239 -0
- package/src/menu-extras.css +1 -0
- package/src/menu-keys.ts +199 -0
- package/src/menu-layer.ts +2 -1
- package/src/menu-plain.js +1 -0
- package/src/menu.css +1 -0
- package/src/menu.tsx +83 -35
- package/src/pager-extras.css +1 -0
- package/src/pager.css +1 -0
- package/src/pager.tsx +88 -0
- package/src/portal.css +1 -1
- package/src/portal.tsx +19 -4
- package/src/segmented.tsx +12 -2
- package/src/selection.tsx +3 -1
- package/src/session-rail-plain.js +1 -1
- package/src/settings-dialog.tsx +29 -2
- package/src/shell.css +1 -1
- package/src/stage-path.css +1 -0
- package/src/stage-path.tsx +89 -0
- package/src/stage.css +1 -0
- package/src/stage.tsx +52 -0
- package/src/starting-point.css +1 -0
- package/src/starting-point.tsx +93 -0
- package/src/status-list.css +1 -0
- package/src/status-list.tsx +65 -0
- package/src/status-matrix.css +1 -0
- package/src/status-matrix.tsx +131 -0
- package/src/team-chat.css +1 -1
- package/src/topnav-fold.css +1 -0
- package/src/translation-row.css +1 -0
- package/src/translation-row.tsx +113 -0
- package/src/ui.css +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,8 +2,323 @@
|
|
|
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
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
## 0.50.0 (24/10/2026)
|
|
8
|
+
|
|
9
|
+
**Continue with GemBoss says which name the page is on** (24/10/2026). Every internal tool answers to a flat name and an .ops
|
|
10
|
+
name; GemBoss sent the token to the one registered URL, so a person on the other name signed in there and the name they used
|
|
11
|
+
kept asking (review of gemlabs #1163).
|
|
12
|
+
|
|
13
|
+
Changed
|
|
14
|
+
- `gemBossSignInUrl(service, next, issuer, host?)` adds `&host=`; `AuthContinueWithGemBoss` passes the browser's
|
|
15
|
+
`location.host` once mounted (the server-rendered first paint links without it), and auth-sso-plain.js always does.
|
|
16
|
+
GemBoss only CHOOSES among the tool's registered URLs with it (`FLEET_SSO_SERVICES[...].alias`, apps/admin).
|
|
17
|
+
- `AuthSignIn` renders `method="post"` always and takes `action`: on a server-rendered page a press before React loaded was a
|
|
18
|
+
native GET, with the password in the URL, history and server logs (measured 24/10/2026: 8 Next sign-in pages in gemlabs).
|
|
19
|
+
- `?sso=not_member` now reads "Your GemBoss account is not a member here. Ask an admin to add your email." It said "Use the
|
|
20
|
+
password", but since 23/10/2026 both doors check the same member list, so the password door refuses that person too.
|
|
21
|
+
|
|
22
|
+
**StartingPoint: a chat door where the person asks** (24/10/2026). The chat door's picture always drew Gem asking, the person
|
|
23
|
+
answering and a "Drafting" tile, so a door that asks Gem a question (the empty Funnels page's "Which funnel should I build?")
|
|
24
|
+
read as Gem drafting pages. `chat.from: "me"` puts the person's question first and Gem's answer under it; `chat.step` names the
|
|
25
|
+
tile. Both optional: a door that passes neither draws as before.
|
|
26
|
+
|
|
27
|
+
**AuthSignIn: the whole sign-in form of a fleet tool** (23/10/2026). Every tool wrote its own form around the kit's pieces, and
|
|
28
|
+
the words drifted: "Your lark email", "Team password", "Access password", placeholders of dots, buttons saying `Enter →`, `Vào`,
|
|
29
|
+
`Continue`, `Log in` (measured on the live sign-in pages of 60 services, 23/10/2026: one of them, GemPress's, had the whole
|
|
30
|
+
standard). Chris: "cái này chắc phải đưa vào gemboss ui".
|
|
31
|
+
|
|
32
|
+
Added
|
|
33
|
+
- `AuthSignIn` (auth.tsx): Continue with GemBoss (with `service`), then Email, Password with its eye, the error and Sign in, in
|
|
34
|
+
the kit's words and with no placeholder. The tool passes `service`, `next`, `onSignIn({ email, password })` (returns the
|
|
35
|
+
server's sentence on a refusal, nothing once it has moved the browser on; a throw reads as the network) and an optional `foot`.
|
|
36
|
+
`SIGN_IN_OFFLINE` is that network sentence.
|
|
37
|
+
- `auth-signin-plain.js` (`@gemboss/ui/auth-signin-plain.js`), its own weight entry: `gembossUI.initSignIn()` fills an empty
|
|
38
|
+
`<form data-gb-signin>` with the same markup, for a page with no React. Loaded after auth-sso-plain.js. `data-submit="json"`
|
|
39
|
+
posts `{email, password}` and follows `data-next`; otherwise the browser posts the form and the server's sentence comes back
|
|
40
|
+
in `data-error`. A form written without `method` is posted (a GET would put the password in the URL). A redirect the server
|
|
41
|
+
answers with is followed as a page, never read as success. With `data-sso` but no auth-sso-plain.js it draws no button and
|
|
42
|
+
says so in the console. Its eye stops its click at the button, so kit-plain.js's delegated `initPasswordFields()` does not flip
|
|
43
|
+
it a second time.
|
|
44
|
+
- `initContinueWithGemBoss()` (auth-sso-plain.js) can be called again: a link it already set up gets no second click handler.
|
|
45
|
+
- `auth-signin-browser.test.ts`: the React and the plain form compared element by element in Chromium (a word changed on one
|
|
46
|
+
side is red), what each does on submit, the eye with kit-plain.js on the page; two negative controls.
|
|
47
|
+
|
|
48
|
+
**ListPage: the frame of a list page** (23/10/2026, step 3 of the list standard, Gems/CLAUDE.md §13). Every admin list page
|
|
49
|
+
drew its own frame on Polaris `Page`, and its states its own way: five kinds of empty state, four labels on a retry, a skeleton
|
|
50
|
+
of 3 or 4 lines or a spinner or nothing (survey of 14 pages, 23/10/2026).
|
|
51
|
+
|
|
52
|
+
Added
|
|
53
|
+
- `ListPage` (+ `ListPageAction`, `ListPageState`): the header (a way back, the title and its badge, one line under it, the page's
|
|
54
|
+
primary button, secondary actions), notices, a toolbar, and ONE card holding the list or the state it is in (`state`:
|
|
55
|
+
`loading` placeholder rows, `empty` the page's own empty state, `no-match` with Clear filters, `error` with Try again).
|
|
56
|
+
Polaris Page's numbers as the admin draws it, measured at the six widths. From a page column of 560px two secondary actions
|
|
57
|
+
are buttons and the rest are behind ⋯; under it, and below 768px, all of them. Below 768 the header is two rows and its
|
|
58
|
+
controls 44px. Its CSS is an entry, `list-page.css` (`@gemboss/ui/list-page.css`, imported by list-page.tsx).
|
|
59
|
+
`list-page-browser.test.ts`, four cases with negative controls.
|
|
60
|
+
- `Icon` `arrowLeft` (ListPage's way back, the arrow Polaris' Page draws there).
|
|
61
|
+
- ListPage, steps 3c and 3d (Pages, Themes, Plugins, Media, Offers, Funnels): `card={false}` for a list that draws its own cards
|
|
62
|
+
(its own empty stands on the page; loading, no match and error are still boxed), `cardProps` (stay on the card in every
|
|
63
|
+
state: a drop zone), `cardMeta` (beside the card's heading), and `cardLead`: rows at the top of the card in every state, the
|
|
64
|
+
state's body after them (Funnels' Website row, which does not wait for the list's read); a page with a lead always has its
|
|
65
|
+
card, so the lead stays the same element. Notices or a toolbar that draw nothing take no gap. The page's status region
|
|
66
|
+
("Loading…") is one element in every state and only its words change (one added with its words in it is often not read out).
|
|
67
|
+
`list-page-browser.test.ts` cases 6–8, with negative controls.
|
|
68
|
+
- ListPage, step 3e (Tests): an `external` action (a new tab, a download) is a plain link, as a button and as a ⋯ row, not the
|
|
69
|
+
app's `linkAs`: Next prefetches its Link, so the Tests page's Export CSV built its file on every visit. Case 5.
|
|
70
|
+
- ListPage, step 3f (Products): `actionGroups` (Polaris Page's name), choices of one kind always behind ⋯ at every width, a
|
|
71
|
+
title and the one that is on marked `active` (Products' Auto-refresh: Every day, Off). Case 9, with a negative control.
|
|
72
|
+
- `MenuItem` `checked`: a choice (`menuitemradio`, `aria-checked`) with a check before the one that is on and the same space
|
|
73
|
+
before the others; `MenuGroup`: a titled `role="group"` of such rows. Their CSS is in the `menu-extras.css` entry (the core
|
|
74
|
+
is frozen). list-page-browser.test.ts now loads menu-extras.css, as the admin does through menu.tsx.
|
|
75
|
+
- A closed ⋯ has no layout (`menu-extras.css`: `.ui-menu:not([open]) > .ui-menu__list { display: none }`). A closed <details>
|
|
76
|
+
only skips painting: asked for geometry, its rows were laid out, so the admin's phone-width gate read a closed ListPage ⋯ at
|
|
77
|
+
320px as rows cut by the left edge, and find-in-page matched them and opened the menu. menu-browser.test.ts case 23.
|
|
78
|
+
- `Pager` (+ `pageWindow`): the numbered pager (`ui-pager`, README "Long lists") as a React component, links (`href`, through
|
|
79
|
+
`linkAs`) or, for a list paged in state, buttons (`onPage`), `busy` while a page is on its way. With Chris's OK (24/10/2026)
|
|
80
|
+
the pager's rules moved out of kit-plain.css into `pager.css`, just before it in the core (same rules, same order, no new
|
|
81
|
+
weight; the cascade check paints 0 boxes differently); the buttons' look is the new `pager-extras.css` entry.
|
|
82
|
+
`pager-browser.test.ts`, four cases with negative controls. The admin's Products list uses it.
|
|
83
|
+
|
|
84
|
+
### Before: the row ⋯ (step 2)
|
|
85
|
+
|
|
86
|
+
**The admin's row ⋯ is the kit's Menu** (23/10/2026, step 2 of 3: `RowMenu` in apps/admin swaps Polaris's Popover + ActionList for
|
|
87
|
+
`Menu`; step 3 is the "list page" component).
|
|
88
|
+
|
|
89
|
+
Added
|
|
90
|
+
- `Menu` takes `disabled` and `loading`: the ⋯ takes no click and no key and leaves the Tab order (`aria-disabled`, drawn by
|
|
91
|
+
ui.css); `loading` puts a ring in place of the dots and `aria-busy`. The ring (`.ui-menu__busy`) is in a new entry,
|
|
92
|
+
`menu-extras.css` (`@gemboss/ui/menu-extras.css`, imported by menu.tsx): menu.css is in the core and the frozen
|
|
93
|
+
gemboss-ui.css had no bytes left (+24 B gzip over), and the admin loads no kit-plain.css (its `.ui-spinner`). Turned off
|
|
94
|
+
while open, it closes, with focus that was in it back on ⋯; opened while off by anything but its button (find-in-page, a
|
|
95
|
+
script), it closes again. `menu-browser.test.ts` case 20, with a negative control.
|
|
96
|
+
- A long hint wraps (`menu-extras.css`): in a column of at most 32ch, under the label when the row has no room beside it, and
|
|
97
|
+
the list is never wider than the screen less 16px. One nowrap line of 80 characters made the list ~600px wide and ran it
|
|
98
|
+
past a phone screen. A short hint stays on one line right of the label. `menu-browser.test.ts` case 21.
|
|
99
|
+
|
|
100
|
+
Changed
|
|
101
|
+
- Escape that closes an open React menu from the page-wide listener (focus on the ⋯, or nowhere in the menu) is taken
|
|
102
|
+
(default prevented), as kit-plain.js already takes it, so a dialog listening after it does not close on the same Escape.
|
|
103
|
+
`menu-browser.test.ts` case 22.
|
|
104
|
+
|
|
105
|
+
**The ⋯ menu is ready to be the admin's row menu** (23/10/2026, step 1 of 3: the kit only; the admin's `RowMenu` moves onto it next).
|
|
106
|
+
|
|
107
|
+
Added
|
|
108
|
+
- `menu.css`, its own file (`@gemboss/ui/menu.css`), imported by `menu.tsx`: the `.ui-menu` rules (placement, the floated list,
|
|
109
|
+
the summary marker, `--end`), the hint, the separator, the disabled row and the icon button (`ui-btn--icon`, with its 44px
|
|
110
|
+
rules under a finger), moved out of `kit-plain.css` unchanged. The admin loads `ui.css` and the shell, never `kit-plain.css`,
|
|
111
|
+
so a `Menu` there had no placement and no square ⋯. The core carries the file where the rules stood, just before
|
|
112
|
+
`kit-plain.css` (`packages/ui/scripts/parts.mjs` CORE and the frozen copy in `packages/ui/scripts/parts-gate.mjs`: a split, not new weight), so
|
|
113
|
+
`parts/components.css` and `gemboss-ui.css` hold the same rules in the same order.
|
|
114
|
+
- A menu's semantics and keys, `menu-keys.ts`, shared by `Menu` and `LanguageSwitcher` (whose own key handler and `openMenu`
|
|
115
|
+
it replaces). The list is `role="menu"` named by the trigger's label, rows `menuitem` with `tabindex="-1"`, the trigger
|
|
116
|
+
`aria-haspopup`. An opening by a click, Enter or Space lands on the first row that can act (↓ on ⋯ the first, ↑ the last;
|
|
117
|
+
a script's `open` moves no focus), with or without the popover API. On a row (a field in the list keeps its own keys):
|
|
118
|
+
↑ ↓ wrap and skip disabled rows; Home End; Space acts on a link row; Escape closes with focus back on ⋯ and is taken; Tab
|
|
119
|
+
closes and goes on. A chosen row runs with focus already back on ⋯ (a popup it opens returns there), then the menu
|
|
120
|
+
closes, link rows too. One menu open at a time, whatever opened the next one (a key is not a click outside); a menu that
|
|
121
|
+
holds the one opening stays open.
|
|
122
|
+
- `menu-plain.js` (`@gemboss/ui/menu-plain.js`), the same for plain markup: a SECOND script after `kit-plain.js`, which has no
|
|
123
|
+
room for it under its weight ceiling. It adds the roles the markup leaves out and runs by itself. **A plain surface that
|
|
124
|
+
wants a menu's keys adds this script** (or `import "@gemboss/ui/menu-plain.js"` after the kit-plain.js import); without it
|
|
125
|
+
a plain menu works as before.
|
|
126
|
+
- `menu-browser.test.ts` (`test:ui-browser`): 19 cases on `Menu` and on plain markup, each with a negative control: roles,
|
|
127
|
+
keys, where an opening lands, choosing a row, one open, a menu in a table row that opens on click, the last row of a
|
|
128
|
+
scrolling table, Escape and a selection, the admin's own sheets + `menu.css` against the core, a field in the list, a menu
|
|
129
|
+
in a menu or the account menu, a menu with no list, a popup's Tab trap, a prevented opening, no popover API, and a React
|
|
130
|
+
Menu on a page that also runs kit-plain.js + menu-plain.js, Tab from an open menu's ⋯, an Escape something else took, and
|
|
131
|
+
the plain LanguageSwitcher beside menu-plain.js. `plain-ssr.test.ts` (`test:packages`): every `*-plain.js` loads in Node
|
|
132
|
+
without throwing.
|
|
133
|
+
- Review of #5179: Tab from the ⋯ of an open menu closes it and focus goes on (its rows are out of the Tab order, so the list
|
|
134
|
+
stayed open over the page); the page-wide Escape leaves an Escape something else took (`defaultPrevented`: a dialog, a
|
|
135
|
+
combobox) alone; a close clears the one-open mark an opening left (an opening closed before its toggle let the next one skip
|
|
136
|
+
the rule); menu-plain.js leaves the plain LanguageSwitcher (`.gb-lang`, its own keys and checked-row focus) to
|
|
137
|
+
language-switcher-plain.js and only closes it with the others (two scripts put focus twice).
|
|
138
|
+
- editor-insert.css: the insert menu's "Ask AI: …" row (E2), in the accent colour, highlighted with the accent wash when
|
|
139
|
+
selected, and one line however long the request.
|
|
140
|
+
- Four pieces GemPress's redesign (approved by Chris 23/10/2026) drew with its own CSS, each its own entry, presentational
|
|
141
|
+
(no state, no inline style) and written by hand from plain HTML with the classes listed at the top of its file (README "Review
|
|
142
|
+
pieces"):
|
|
143
|
+
- `StagePath` (`stage-path.css`): stages that unlock in order, an `<ol>` of cards with a number (a green ✓ when
|
|
144
|
+
`done >= total`), the name, "3 / 35 pages approved" and a `<progress>` bar; the current stage (default the first not done)
|
|
145
|
+
has an ink outline and an ink number, `aria-current="step"`. `stagePathDone`.
|
|
146
|
+
- `StatusMatrix` (`status-matrix.css`): rows × columns on the kit table, each cell "live / total" with what waits under it
|
|
147
|
+
("5 draft · 2 changed"), toned all live (green) or has drafts (amber), "—" where there is nothing to count.
|
|
148
|
+
`statusMatrixTone`.
|
|
149
|
+
- `TranslationRow` (`translation-row.css`): one string under review, key + state badge + who, source beside target (one
|
|
150
|
+
column under 900px or in a row narrower than 600px), the checks and the surface's action; `current` draws an ink border
|
|
151
|
+
and a 3px ink bar; focusable (`tabIndex={-1}`) for a J / K list. The editable control is the surface's (`target`, a node or
|
|
152
|
+
a function given the ids for `aria-describedby`). `TRANSLATION_STATE_LABELS`, `translationRowId`.
|
|
153
|
+
- `StatusList` (`status-list.css`): a quiet system-health strip, a dot (success / warning / danger, or an empty ring for
|
|
154
|
+
muted), a bold name and one muted sentence, a link when it has `href`.
|
|
155
|
+
- `CreateIcon`, `CreateStepper`, `CreateRail`, `CreateDoors`, `CreateFilter`, `CreateGrid`, `CreateCard`, `CreateParts`,
|
|
156
|
+
`CreatePath` (`create-shell.css`, its own entry): the create shell, one shape for making a page, a funnel or a section inside
|
|
157
|
+
the frame each already opens in: an icon tile and "Choose → Make it yours → Gem builds it" in the header, a rail with the doors
|
|
158
|
+
(ask the assistant, the library, blank: at most three) and chip questions ("Who it is for": cold, warm, ready, each with its
|
|
159
|
+
colour's dot; "What it does"), cards with a Stage picture, who it is for, a name, one line and what is inside. `CREATE_AUDIENCE`
|
|
160
|
+
holds the words for the three temperatures (23/10/2026, drawings A1/A3/A4).
|
|
161
|
+
|
|
162
|
+
Changed
|
|
163
|
+
- shell.css is the one owner of the menu row: `.gemboss-account-menu-item, .ui-menu__item` keep their shared declarations,
|
|
164
|
+
the account row stays `display: block`, and `.ui-menu__item` is the flex row (label, then the hint on the right; `gap: 8px`,
|
|
165
|
+
nowrap, the small radius) that app-shell.css used to lay over it. app-shell.css drops its `.ui-menu__item` rule. A plain
|
|
166
|
+
`details.ui-menu` on the core: 0 differences in 2.3 million computed values against main (bundle and parts, built and
|
|
167
|
+
minified; 1280 and 390, mouse and finger, light, dark, the `data-gb-menus` flag). In the admin, which loads shell.css and
|
|
168
|
+
not app-shell.css, the assistant dock's ⋯ rows become that flex row too (their boxes unchanged); the account menu's rows
|
|
169
|
+
do not change.
|
|
170
|
+
- `initMenus()` (kit-plain.js) puts focus back on a menu's button BEFORE a chosen row's own handler, then closes the menu as
|
|
171
|
+
before. Still opt-in: a page that never calls it keeps its menus open on a chosen row. `closeMenus(except)` leaves open a
|
|
172
|
+
menu that holds `except` (a kit menu in an open account menu).
|
|
173
|
+
- kit-plain.js: a popup's Tab trap leaves `tabindex="-1"` out (a menu's rows): counted as its last control, Tab from the real
|
|
174
|
+
last one left the popup.
|
|
175
|
+
- `escapeTaken` (selection.tsx, kit-plain.js): a menu or a dialog takes Escape when it is SHOWN (`checkVisibility`), not when
|
|
176
|
+
it has a box. A closed `<details>`' content keeps its boxes, so with every row's ⋯ list `role="menu"` the box test would
|
|
177
|
+
have handed every Escape in a selectable table to its closed menus.
|
|
178
|
+
- `Menu`: one page-wide set of listeners for every mounted menu (`registerMenu`: outside click, Escape, the float, one open),
|
|
179
|
+
not a click and a keydown listener per menu; the summary opens the menu itself with or without the popover API.
|
|
180
|
+
- kit-plain.js stays under its ceiling (8 784 B gzip of 9 189); menu-plain.js weighs 1 047 B (ceiling 1 559).
|
|
181
|
+
- collections-board.test.ts: the keyboard case loads menu-plain.js and walks the rows with ↓ (it walked them with Tab); the
|
|
182
|
+
two "no popover API" negatives open the menu by script, since a click now focuses its first row and, without the top
|
|
183
|
+
layer, that focus scrolls the table's frame to it (menu-browser.test.ts case 15 holds the click).
|
|
184
|
+
|
|
185
|
+
## 0.49.0 (23/10/2026)
|
|
186
|
+
|
|
187
|
+
Fixed
|
|
188
|
+
- collections.css: a folded index row's primary cell wraps, as the fold always meant to. Its `white-space: normal` was
|
|
189
|
+
(0,2,1) and lost to the fold's own nowrap on every cell (0,2,2), so free text under a title (GemPress's "missing: …"
|
|
190
|
+
note) and an unlinked title stayed on one line, widened the row and scrolled the list sideways (384px at 320 on
|
|
191
|
+
GemPress). A linked title (`.ui-table__title`) and its second line keep their own nowrap and are cut as before; a token
|
|
192
|
+
too long for the row (a URL, a slug) breaks anywhere. A cell whose content fits is unchanged (gemcare People at
|
|
193
|
+
320/390/768, 50 rows: no row taller).
|
|
194
|
+
- ui.css: `.ui-sr-only` is pinned on the inline axis (`left: 0`; also portal.css `.gb-sr-only`, team-chat.css
|
|
195
|
+
`.gb-tc-sr`, shell.css `.gemboss-assistant-sronly`, assistant.css `.gb-dock-sr`). It stood where it would have been in the
|
|
196
|
+
flow, so inside a frame that scrolls sideways (a table, a board, a segmented row) it could stand far past the frame and push
|
|
197
|
+
the PAGE sideways: the "Actions" header of a 2105px IndexTable, 792px at 1280; search-radar /aeo 428px; a bare
|
|
198
|
+
`ui-table-wrap` on a page with ui.css only, 1109px. It keeps its line, so a screen reader's cursor stays by the row.
|
|
199
|
+
(#5176 had made `.ui-table-wrap` `position: relative` instead and put `noreferrer` on a row's Cmd-click; both are withdrawn
|
|
200
|
+
before release: a positioned frame paints over an earlier dropdown or sticky bar with no z-index, and the referrer is the
|
|
201
|
+
page's to set, see the README's collection rules.)
|
|
202
|
+
- shell.css: the topbar's actions column never goes narrower than what it holds (`minmax(max-content, 1fr)`, and
|
|
203
|
+
`max-content` under 1120px), and the search column gives way instead (`minmax(0, …)`). With a 200px minimum the admin's
|
|
204
|
+
right-hand chips (~512px) spilled left over the search: 160px at 1280, 239 at 1121 (22/10/2026). The brand column is
|
|
205
|
+
unchanged (a surface's tabs there keep their scroller); with room to spare the search is centred as before. The
|
|
206
|
+
`max-width: 1040px` topbar rule, which the base rule after it always overrode, is removed.
|
|
207
|
+
|
|
208
|
+
Added
|
|
209
|
+
- `@gemboss/ui/editor-insert.css` (23/10/2026), its own entry: the page editor's insert menu, the + on a picked element (admin
|
|
210
|
+
`InsertElementMenu`). It is a list to search, with the row in focus described beside it, 32px rows (44px under a finger), and a
|
|
211
|
+
sheet along the bottom under 640px. It's not in editor.css because every editor surface loads that.
|
|
212
|
+
- IndexTable `flush` (root `.ui-index--flush`): inside a card that is already the frame, as DataTable's and ResourceList's. The
|
|
213
|
+
table drops its own border, radius and shadow; the bulk bar covers the 37px header and draws its rule; folded, the bar sits on
|
|
214
|
+
the first row and the sort chips are inset 12px like the rows. partner-radar and talent-radar drew two frames (23/10/2026).
|
|
215
|
+
- `Segmented` takes `scroll`: text tabs keep one line and the group scrolls sideways inside itself when it is wider than its
|
|
216
|
+
room, what kit-plain.css already does for plain surfaces. Set as layout styles on the component (gemboss-ui.css had no
|
|
217
|
+
bytes left under its weight ceiling); opt-in; first user the admin's Plugins filter (five tabs broke to three lines each at
|
|
218
|
+
390, 22/10/2026).
|
|
219
|
+
- `AssistantHost` takes `waiting`: the chat's last answer ends on choices only the person can make. The status bar and the
|
|
220
|
+
header say "Waiting on you" with an amber dot (`--gemboss-warning`, set on the dot: the bundle is at its gzip ceiling), ahead of "Done" and "Ready". It is a prop, not dock
|
|
221
|
+
state, so the plain frame's reducer copy is unchanged. New label `waiting`.
|
|
222
|
+
- assistant-chat.css `.gemboss-ec-decide` / `-decide-label`: the box that holds a waiting question's choices over the message box
|
|
223
|
+
(22/10/2026).
|
|
224
|
+
- `Stage`, `StageWindow`, `StageTile`, `StageBubble`, `StageLine` (`stage.css`, its own entry): the one way the app draws a
|
|
225
|
+
picture, taken from gemboss.ai's mega menu: a night-blue stage lit with iris, a dot grid fading out, glass tiles (one picked,
|
|
226
|
+
white and glowing), white windows lifted off it showing a real screenshot. Its colours are named once on `.ui-stage`
|
|
227
|
+
(an illustration may light itself, website/DESIGN-LANGUAGE.md §3). A stage is hidden from screen readers unless
|
|
228
|
+
`decorative={false}` (a panel holding words a reader needs); `StageWindow` then takes `alt` for its screenshot.
|
|
229
|
+
- `EmptyStage` (`empty-stage.css`, its own entry): an area with nothing in it yet, centred like an admin empty state: a
|
|
230
|
+
Stage picture drawn from the area's own nouns, a name, one line, the page's own buttons (`.ui-empty-stage__row` lays tiles
|
|
231
|
+
side by side). Replaces the picture-less empty states (22/10/2026).
|
|
232
|
+
- `StartingPoint` (`starting-point.css`, its own entry): "Choose your starting point", the same three doors wherever something new
|
|
233
|
+
is made: ask the assistant (a two-line chat on the stage), a template (two real pages fanned on the stage, `images`), blank (an
|
|
234
|
+
empty window with "+ Add a section"). Each door is a picture, a name, one line and a button; at most three. Learned from
|
|
235
|
+
Replo's Plans, Tasks, Skills and reports (22/10/2026).
|
|
236
|
+
- `ChatStarter` takes `sub` (one line under the label) and `icon`; a list where any starter has either is drawn as a column
|
|
237
|
+
of cards (`.gb-chat-starters-cards`: icon in an iris tile, label, the line under it). Pills are unchanged.
|
|
238
|
+
- `firstBlank(text)` and `selectBlank(textarea, text)`: a starter with `fill` now selects the first `[…]` in its prompt, so
|
|
239
|
+
typing replaces it ("Build a funnel for [which product?]"); with no blank the caret goes to the end (22/10/2026).
|
|
240
|
+
|
|
241
|
+
Changed
|
|
242
|
+
- collections.css: an index table's header is the data table's (the surface, 13px regular, 12px above and below: 45 tall,
|
|
243
|
+
opaque) and its cells 8px 6px (a one-line row 37), taken from the data table's rules in ui.css rather than restated. It was Polaris IndexTable's grey band, 12px / 550, 36 tall, over 6px cells: two
|
|
244
|
+
looks for one thing, the heavier one on the lists people open (Chris 23/10/2026: "GemPress's table reads lighter than
|
|
245
|
+
Funnels"). Its bulk bar is 46 (the wrap's top line + the header), 45 flush, 38 folded below 768, wherever in the index
|
|
246
|
+
it sits; a resource list's stays 38. The admin's unselectable Polaris IndexTables take the same (gemboss #5185).
|
|
247
|
+
- `SessionRail` (and `sessionRail` in session-rail-plain.js): a conversation's `preview` follows its time on the same line,
|
|
248
|
+
"3 hr ago · Nothing is published yet…", one line cut with an ellipsis (`.gemboss-assistant-thread-meta`, shell.css). The
|
|
249
|
+
admin now sends the answer's closing sentence as `preview`, how the conversation ended (23/10/2026, learned from Replo).
|
|
250
|
+
- editor.css: the page editor's column (`.gemboss-pageedit .gemboss-ec-dock-body`: its section list and the element settings) is
|
|
251
|
+
44px tall under a finger and at a phone's width only; under a mouse from 48em its buttons, fields and selects are the kit's own
|
|
252
|
+
sizes, as the same settings panel on the canvas (they were 44 at every width: 44 against 32 for the same panel, 22/10/2026).
|
|
253
|
+
- editor.css: the page editor's icon buttons (`.gemboss-pageedit .gemboss-pv-device`: ↶ ↷, ⋯) are 44 × 44 under a finger and
|
|
254
|
+
at a phone's width only; under a mouse from 48em they are the kit's 28 × 28, as on every other editor bar (they were 44 at
|
|
255
|
+
every width, 21/10/2026).
|
|
256
|
+
|
|
257
|
+
**The briefing card leaves its picture out when the card is too narrow to hold it** (Market, 22/10/2026: with the assistant pinned beside the page the
|
|
258
|
+
card was 693px wide and 510px tall, the gem under the buttons).
|
|
259
|
+
|
|
260
|
+
Changed
|
|
261
|
+
- `.ui-briefing` is a size container (`container-type: inline-size`) and `@container (max-width: 631px)` hides `.ui-briefing__art`. 631 is the
|
|
262
|
+
content width the picture's row needs (380 text + 32 gap + 220 picture = 632) less one: a container query measures the content box, so it
|
|
263
|
+
is the card's 720px at the desktop padding. It is the CARD that is measured, not the screen: the same card is wide on a desktop and
|
|
264
|
+
narrow beside a pinned panel. Measured in Chromium at a 1440px window: picture beside the text at 720px and wider, none at 719px and
|
|
265
|
+
narrower, and the card 258px tall at 693px instead of about 430. `briefing-card.test.tsx` holds the rule.
|
|
266
|
+
|
|
267
|
+
## 0.48.0 (21/10/2026)
|
|
268
|
+
|
|
269
|
+
**LanguageSwitcher: what its first three surfaces had to work around** (21/10/2026; GemCommunity #333, GemNews #2,
|
|
270
|
+
GemFeedback #82).
|
|
271
|
+
|
|
272
|
+
Added
|
|
273
|
+
- `gembossUI.languageSwitcher()` (plain JS) returns `update({ value, labels, suggested, languages })` and
|
|
274
|
+
`setLabels(labels)`: the switcher changes where it is, no new element. The button's name and label, the menu's name and
|
|
275
|
+
the suggested hint change in place; the rows are drawn again only when `languages` or `suggested` change, and the row
|
|
276
|
+
that had focus has it again. An open menu stays open (placed again), focus stays where it was. `labels` given replace
|
|
277
|
+
those words only; `suggested: null` takes the row away. GemNews's `paintLang()` rebuilt the switcher (destroy + new,
|
|
278
|
+
focus carried by hand) every time its language changed. `set()`, `value()`, `open()`, `close()`, `destroy()` unchanged.
|
|
279
|
+
- `TopbarNav` `foot`: the app's own section at the foot of the FOLDED tab list, under a line (`.gb-topnav-foot`), and the
|
|
280
|
+
class `gb-topnav-unfolded` for its copy in the topbar's end, shown only while the tabs are unfolded. A portal topbar
|
|
281
|
+
(brand, tab menu, search, theme, Sign in) has no room for a 55px language button at 320–390: GemFeedback hid it and
|
|
282
|
+
printed links at the foot of the page. Now `foot={<LanguageSwitcher variant="inline" end={false} …/>}` plus
|
|
283
|
+
`<LanguageSwitcher className="gb-topnav-unfolded" …/>` in the end slot: one language control in the bar at every width.
|
|
284
|
+
- `TopbarNav` `foldAt={760}`: the tabs fold over the whole phone topbar (≤760px) instead of under 600px, for a bar whose end
|
|
285
|
+
holds more (GemFeedback's three tabs ran under the switcher at 601–687). Default 600, unchanged.
|
|
286
|
+
- `topnav-fold.css` (`@gemboss/ui/topnav-fold.css`), a new entry `TopbarNav` imports after `portal.css`: the rules for `foot`,
|
|
287
|
+
`foldAt`, `gb-topnav-unfolded` and the ellipsis below. `portal.css` is in the frozen `gemboss-ui.css`, which had 24 bytes
|
|
288
|
+
left under its ceiling. 0.3 KB gzip minified (ceiling 789 in `weight-budget.json`).
|
|
289
|
+
|
|
290
|
+
Changed
|
|
291
|
+
- The LanguageSwitcher's rows, hint and separator are one class (0,1,0) instead of zero specificity (`:where`), with the
|
|
292
|
+
core's values: an app's `button { font: inherit }` (0,0,1) beat the 13px rows (GemCommunity 14 / 16px, GemNews 16px; both
|
|
293
|
+
restated 13px). An app restyles them on purpose with one class of its own. The surface and the box stay `:where`.
|
|
294
|
+
- Every `--gemboss-*` token `language-switcher.css` reads has its light value as a fallback: a page with neither the core nor
|
|
295
|
+
`gemboss-tokens.css` draws the switcher right (light).
|
|
296
|
+
- `TopbarNav`'s folded button: the open tab's name sits in `span.gb-topnav-fold-label` and gives way with an ellipsis before
|
|
297
|
+
it runs under the topbar's end ("Changelog" at 320 overlapped the search button by 40px, with or without a switcher).
|
|
298
|
+
|
|
299
|
+
Fixed
|
|
300
|
+
- The switcher's tick touched the language's name on a page with app-shell.css and no core (GemCommunity's /welcome, for the
|
|
301
|
+
brand): app-shell.css's `.ui-menu__item` (0,1,0) reads `--ui-space-2` / `--ui-radius-sm`, unset there, and beat the row's
|
|
302
|
+
gap. The row's gap and corners are at two classes (`.gb-lang__item.ui-menu__item`, 8px / 6px). app-shell.css itself is
|
|
303
|
+
unchanged: the frozen gemboss-ui.css has 5 bytes left under its ceiling, and two fallbacks there cost 3.
|
|
304
|
+
- README: "the switcher fits the phone bar at 320–390" is AppShell's bar; a portal Topbar + TopbarNav puts it in the tab
|
|
305
|
+
menu (`foot`).
|
|
306
|
+
|
|
5
307
|
## 0.47.0 (21/10/2026)
|
|
6
308
|
|
|
309
|
+
**The kit's menu rows at the admin's density** (Chris 21/10/2026, of a menu drawn 44px tall: "nó đang to hơn bình thường";
|
|
310
|
+
0.43.0 did this for the editor's menus).
|
|
311
|
+
|
|
312
|
+
Changed
|
|
313
|
+
- `.ui-menu__item` (`Menu` / `MenuItem`, kit-plain menus, the assistant header's ⋯) and `.gemboss-account-menu-item`
|
|
314
|
+
(`AccountMenu`, the admin's account corner included) under a mouse: a Polaris ActionList item, 32px tall with 4px padding
|
|
315
|
+
above and below (were 44px with 12px, for every pointer). A kit menu's rows sit 6px in from a list padded 6
|
|
316
|
+
(`.ui-menu__list`, `.gb-dock-menu-list`: were 4), as an ActionList item in its section; the account menu's rows keep 16px at
|
|
317
|
+
the sides, under its head. Under a finger or on a screen 767px or narrower: 44px with 12px 16px, as before. The row states
|
|
318
|
+
`box-sizing: border-box` itself. `language-switcher.css` repeats the core's row for a page without the core (gemboss.ai), so it
|
|
319
|
+
follows: list padded 6, rows 32 / 4px 6px under a mouse, 44 / 12px 16px under a finger. The density gate measures both (`menuItem`, `menuSurface` in polaris-reference.json), red
|
|
320
|
+
on 0.46's rows. Measured on the admin (local): the account menu's four rows 176px → 128px, the assistant's ⋯ rows 44 → 32.
|
|
321
|
+
|
|
7
322
|
**A choice made by looking, and a logo sheet** (GemBoss Brand › Logo, 21/10/2026: the seller picks one of three AI logos from
|
|
8
323
|
GemMedia, sees each the way it will be used, and confirms one).
|
|
9
324
|
|