@gemboss/ui 0.10.0 → 0.13.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 +113 -0
- package/README.md +155 -2
- package/catalog/index.html +2156 -15
- package/gemboss-ui.css +126 -66
- package/package.json +2 -1
- package/src/app-shell.css +13 -0
- package/src/collections.css +350 -0
- package/src/collections.tsx +414 -0
- package/src/editor.css +22 -19
- package/src/gemboss-tokens.css +1 -1
- package/src/index-table.tsx +216 -0
- package/src/index.ts +11 -0
- package/src/kit-plain.css +42 -9
- package/src/kit-plain.js +136 -1
- package/src/theme-dark.css +1 -0
- package/src/ui.css +67 -54
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,119 @@
|
|
|
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.13.0 (06/10/2026)
|
|
6
|
+
|
|
7
|
+
**Collections: six patterns for tables, lists, grids and boards** (Chris 05/10/2026), each with its states. The CSS is
|
|
8
|
+
a NEW entry, `@gemboss/ui/collections.css`, outside `gemboss-ui.css` and outside the admin's sheets. One part did go
|
|
9
|
+
into `gemboss-ui.css`: the media card's own pieces (below, kit-plain.css), because the card has one owner. README
|
|
10
|
+
"Collections".
|
|
11
|
+
|
|
12
|
+
Changed
|
|
13
|
+
- `ui-card--media` (kit-plain.css) is `position: relative`, and gains `__link` (the title, its overlay covers the card),
|
|
14
|
+
`__menu` (⋯ in the picture's corner; the card stops clipping so the menu is not cut off), `__meta`, `data-ratio="4/3"`.
|
|
15
|
+
Admin not affected (it does not load kit-plain.css).
|
|
16
|
+
- `ui-chip[aria-current="true"]` draws like a current chip (a sort chip is not a page).
|
|
17
|
+
|
|
18
|
+
Added
|
|
19
|
+
- `collections.css`: Data table modifiers (`ui-table--sticky-first`, `--compact`, totals, footer, sort with
|
|
20
|
+
`aria-sort`), Index table (`ui-index`, `ui-table--index`: Polaris IndexTable's 12/550 header on #f7f7f7, 6px cells;
|
|
21
|
+
selected #f1f1f1; the bulk bar over the header; folds into a list below 768 of its container), Resource list
|
|
22
|
+
(`ui-list`, 12px padding, a 64px two-line row, the title link covers the row), Compact list (`ui-list--compact`,
|
|
23
|
+
36 / 44 under a finger) and `ui-list--activity` (one timeline), Card grid (`ui-cardgrid`, auto-fill at 200 / 240 /
|
|
24
|
+
320, gap 16, `ui-card__link`), Board (`ui-board`, 12 a column then nested "Show 24 more"), thumbnails (`ui-thumb`),
|
|
25
|
+
states (`ui-empty--no-match`, `ui-coll-error`, `aria-busy`, skeletons per pattern, `ui-trunc`, `ui-clamp-2`).
|
|
26
|
+
- React: `DataTable`, `ResourceList`, `ResourceItem`, `CompactList`, `CardGrid`, `MediaCard`, `Board`,
|
|
27
|
+
`CollectionState`, `CollectionSkeleton` (plain module, server-safe) and `IndexTable` (client: whole-row links,
|
|
28
|
+
selection + bulk actions, Shift range, Escape, sort links or `onSort`).
|
|
29
|
+
- `kit-plain.js` `initCollections()` (runs by itself): `[data-href]` rows open on a click that is not on a control;
|
|
30
|
+
`.ui-index` selection, bulk bar, `gembossUI.selection()`, `gb:selection`; client sort and `gb:sort`, only in a table marked `data-gb-sort` (a React table owns its own sort buttons).
|
|
31
|
+
- `packages/ui/scripts/collections-gate.mjs`: the ruled-out combinations (uppercase header, zebra, card per row, more than one
|
|
32
|
+
visible button, hover-only actions, checkboxes without bulk actions, a linked row over two editors, media cards in a
|
|
33
|
+
per-viewport grid, a table scrolling at 1280), with a page that breaks each rule in `collections.test.ts`.
|
|
34
|
+
- Density gate: eleven new roles from Polaris 13.9.5 rendered (`polaris-reference.json`); `tableHead` / `tableCell`
|
|
35
|
+
now leave the index table to its own roles.
|
|
36
|
+
- Catalog: section "Bảng, list, lưới, board", every pattern and state, with 390px frames where the shape changes.
|
|
37
|
+
|
|
38
|
+
## 0.12.0 (05/10/2026)
|
|
39
|
+
|
|
40
|
+
**A change you SEE on every surface, and on the admin's /admin console.** The kit now draws the admin's (Polaris')
|
|
41
|
+
density under a mouse; under a finger or below 768px every control keeps its 44px floor. Measured on admin.gemboss.ai,
|
|
42
|
+
the catalog drew 25 values the admin does not; it now draws 3, all colour (see "Not changed"). README "Admin density
|
|
43
|
+
(0.12.0)".
|
|
44
|
+
|
|
45
|
+
Changed (under a mouse, at 768px and wider)
|
|
46
|
+
- `ui-btn`: 28px tall (was 32), padding 0 12 (was 16), 12px (was 13). New `--ui-btn-h: 28px`; `--ui-control-h` stays 32
|
|
47
|
+
for `gemboss-field` and `ui-select` (Polaris TextField / Select). `ui-btn--icon` is 28 wide. The popup's own 28px rule
|
|
48
|
+
is gone (every button is 28). **A surface that raised `--ui-control-h` to grow its buttons must now set `--ui-btn-h`
|
|
49
|
+
as well** (gemcare `public/assets/inbox.css` sets `--ui-control-h: 44px` for that reason).
|
|
50
|
+
- ui.css (what the admin loads): buttons and segments are 44 at phone width with a mouse too (`max-width: 47.9975em`),
|
|
51
|
+
as they already were under a finger; they were 32 there.
|
|
52
|
+
- `ui-seg`: 28px group, labels 12px/550. `ui-tabs`: 28px (was 44 under every pointer), 12px/550 selected or not, 8px
|
|
53
|
+
apart (was 4); 44px under a finger or at phone width (in ui.css, so the plain export keeps it).
|
|
54
|
+
- `ui-page-head h1`: 20px/24px/700 (was 22/28/650).
|
|
55
|
+
- `ui-card`, `ui-table-wrap`: Polaris' drop under the card, `--ui-card-shadow` (shadow-100, `0 1px 0 rgba(26,26,26,.07)`).
|
|
56
|
+
The edge stays one 1px `--ui-border` line: Polaris paints a bevel inset on a ::before, which a full-bleed child would
|
|
57
|
+
cover in an inset shadow and which would not follow a surface's dark `--ui-border`. The admin console
|
|
58
|
+
(`.gemboss-admin-shell`) and `theme-dark.css` set the shadow to none.
|
|
59
|
+
- `ui-card__title`, `ui-section-head > h2`, `ui-empty__title`: 14px/20px/650 (were 14/18.2/600, 16/650, 16/600).
|
|
60
|
+
- `ui-table`: Polaris DataTable, measured on /app/analytics and Polaris 13.9.5 rendered: cells 8px 6px (a one-line row
|
|
61
|
+
36), header 12px 6px at 13px/450 (45; was 12/600), the first column 12px from the edge (was 8 x 12 everywhere).
|
|
62
|
+
- `ui-select` weight 450 (was 500); `ui-badge` weight 450 (was 550).
|
|
63
|
+
- `ui-tag`: Polaris Tag, 12px/450 on a 20px line, padding 0 6, radius 8 (was 11px/600 uppercase, letter-spaced).
|
|
64
|
+
`ui-tag--chip` keeps its 11px mono and its height (it already sat on the body's 20px line); its corner is 8 (was 6).
|
|
65
|
+
- `ui-metric--lg`: value 24/32 (was 24/1.1), label 13 (was 14). `ui-funnel__val` 20/24.
|
|
66
|
+
- The kit stops reading `--gemboss-fs-body`, `--gemboss-fs-h1/h2/h3` (the admin seller app's prose sizes, 14/24/20/16);
|
|
67
|
+
ui.css reads `--ui-fs-caption` where it read `--gemboss-fs-caption` (same 12px).
|
|
68
|
+
- `app-shell.css`: Polaris' heading reset (`h1…h6, p`: 1em, inherited weight, margin 0) INSIDE `.gemboss-platform-shell`,
|
|
69
|
+
for elements WITHOUT a class, never inside an article: `.ui-prose`, `[data-content]`, and the wrappers the fleet uses
|
|
70
|
+
for rendered HTML today, by name (`.md-body`, `.recap-md`, `.asst-md`, `.article-body`, any class containing
|
|
71
|
+
`prose` or `markdown` in any case). A new wrapper: mark it `ui-prose` or `data-content`. A bare `<h2>` or `<p>` in the shell becomes body text (13/20/450) with no margin, as in the
|
|
72
|
+
admin; `ui-page-head h1` / `p` lose the browser's margins the same way (the admin never had them). A heading with a
|
|
73
|
+
class keeps what it had.
|
|
74
|
+
|
|
75
|
+
Added
|
|
76
|
+
- `ui-chip` (filter chip: Polaris FilterPill's shape at 28px, `aria-pressed` / `aria-current`) and `ui-stack` (cards
|
|
77
|
+
16px apart, `--tight` 8) in kit-plain.css. For a new filter row use `ui-chip`; the older `.ui-chips > .ui-tag--chip`
|
|
78
|
+
(link and toggle) still draws as before and moves to `ui-chip` with each surface's PR.
|
|
79
|
+
- `ui-btn--sm` is the default size under a mouse now (both 28); its own size rule is gone. It still means "compact" in
|
|
80
|
+
one place: under a finger the admin (ui.css only) keeps it 28, as before; every other surface gets 44 from kit-plain.css.
|
|
81
|
+
- `ui-table`: the last column is 12px from the edge too (Polaris DataTable `:last-child`).
|
|
82
|
+
- visual-gate `--density` (scripts/visual-gate): one `density` check per width, `skip` when the page has no kit element
|
|
83
|
+
or was redirected; its selftest has the 28 / 32 control.
|
|
84
|
+
- `polaris-reference.json` + `packages/ui/scripts/density.mjs`: the density gate (README). `packages/ui/src/density.test.ts` runs it in
|
|
85
|
+
Chromium on the catalog and on the admin's own sheets, with negative controls (32px button, 44px under a mouse, bare
|
|
86
|
+
`<h2>`) and positive ones (sr-only, an article's headings, the 44px floor under a finger).
|
|
87
|
+
|
|
88
|
+
Not changed
|
|
89
|
+
- Colour: ink and primary `#1b1c1e` (Polaris `#303030`), the secondary button's fill. A separate change.
|
|
90
|
+
|
|
91
|
+
Surfaces: upgrade, then run `packages/ui/scripts/density.mjs` on your pages; what it still lists is your own CSS (GemFactory
|
|
92
|
+
`server/ui.mjs`, content-radar `v2.css`, taskdesk's segmented buttons are known).
|
|
93
|
+
|
|
94
|
+
## 0.10.1 (05/10/2026)
|
|
95
|
+
|
|
96
|
+
Editor kit step 1b (gemboss #3781): the visible fixes left over from the verbatim move of `editor.css` in 0.9.0. Each one
|
|
97
|
+
changes what the admin's three editors show; nothing else moves (computed style compared on 99 editor states at six
|
|
98
|
+
widths). README "Editor CSS (0.9.x)".
|
|
99
|
+
|
|
100
|
+
Changed
|
|
101
|
+
- `editor.css`, the Configure | Chat tab row: on the space scale. Row padding `var(--ui-space-2) var(--ui-space-3)`
|
|
102
|
+
(was 8px 10px), tab padding `var(--ui-space-2)` (was 7px). The temporary variables `--gemboss-ec-tabs-pad-x` and
|
|
103
|
+
`--gemboss-ec-tab-pad` are gone. Under a mouse a tab is 2px taller and the row 4px narrower inside.
|
|
104
|
+
- No iris for selection: `.gemboss-layer.is-sel` and `.gemboss-pageedit-chip` use `--gemboss-active-bg` /
|
|
105
|
+
`--gemboss-active-fg` / `--gemboss-divider`; `.gemboss-guest-keep` (the try door's Keep) is `--gemboss-primary`, hover
|
|
106
|
+
`--gemboss-primary-dark`, text `--gemboss-on-primary`. Iris (`--gemboss-accent`) stays for focus and links.
|
|
107
|
+
|
|
108
|
+
Added
|
|
109
|
+
- `@keyframes gemboss-flyout-in`, which `.gemboss-editor-menu` has named since before 0.9.0 and no sheet defined: the
|
|
110
|
+
⋯ More and Publish menus fade in with a 4px drop like the page picker, no fill mode, `animation: none` under
|
|
111
|
+
`prefers-reduced-motion`.
|
|
112
|
+
- `editor-css.test.ts`: no literal colour between 228° and 300° hue in `editor.css`.
|
|
113
|
+
|
|
114
|
+
Admin, same PR (not in the package): the theme editor's tabs wear `.gemboss-ec-tab` (36px to 44px under touch, as the
|
|
115
|
+
page and section editors), the Section Library loses its lilac borders, `SectionOutline.tsx` and `.gemboss-ec-panel`
|
|
116
|
+
(unreachable / unused) are deleted.
|
|
117
|
+
|
|
5
118
|
## 0.10.0 (05/10/2026)
|
|
6
119
|
|
|
7
120
|
Navigation pending: a click on a menu item answers on the first frame, and a page is fetched while the pointer rests on
|
package/README.md
CHANGED
|
@@ -246,6 +246,17 @@ resizer. The behaviour (resizing, tabs, menus, the inspector's writes) belongs t
|
|
|
246
246
|
components come in steps 2 to 4 (`EditorFrame` + `EditorTopbar`; `PanelTabs`, `PanelHeader`, `InspectorGroup`, `Field`
|
|
247
247
|
and the controls; `LayerList`, `EditorDrawer`). Step 5 moves GemFactory's Builder onto them.
|
|
248
248
|
|
|
249
|
+
Changes since the verbatim move, in 0.10.1 (05/10/2026, step 1b, the only ones that change what the admin shows; CHANGELOG):
|
|
250
|
+
|
|
251
|
+
- Tab row on the space scale: `padding: var(--ui-space-2) var(--ui-space-3)` on the row, `var(--ui-space-2)` on each
|
|
252
|
+
tab (were 8px 10px and 7px; the temporary `--gemboss-ec-tabs-pad-x` / `--gemboss-ec-tab-pad` are gone). Under a
|
|
253
|
+
mouse a tab is 2px taller; under touch the 44px floor decides.
|
|
254
|
+
- No iris for selection: Layers' selected row and the page editor's "Editing:" chip use `--gemboss-active-bg` /
|
|
255
|
+
`--gemboss-active-fg` / `--gemboss-divider`; the try door's Keep button is `--gemboss-primary` (hover
|
|
256
|
+
`--gemboss-primary-dark`) like Publish. Iris (`--gemboss-accent`) stays for focus and links.
|
|
257
|
+
- `gemboss-flyout-in` is defined (fade + 4px drop, as the page picker), so `.gemboss-editor-menu` animates; `none`
|
|
258
|
+
under `prefers-reduced-motion`.
|
|
259
|
+
|
|
249
260
|
## Plain-HTML behaviour: `kit-plain.js` (0.3.0)
|
|
250
261
|
|
|
251
262
|
Surfaces without React (GemFactory, gemcare, gempress, partner-radar) render the kit's markup on the server and need
|
|
@@ -385,8 +396,8 @@ surfaces on the package, the same gaps were filled six ways. What 0.5.0 settles,
|
|
|
385
396
|
|
|
386
397
|
| | Under a mouse | Under a thumb / ≤ 767px wide |
|
|
387
398
|
|---|---|---|
|
|
388
|
-
| Control height: `gemboss-field`, `ui-select
|
|
389
|
-
| `ui-btn--sm` | 28px | 44px |
|
|
399
|
+
| Control height: `gemboss-field`, `ui-select` | **32px** (Polaris TextField / Select), `--ui-control-h` | **44px** |
|
|
400
|
+
| `ui-btn`, `ui-btn--sm`, `ui-seg`, `ui-tabs` (0.12.0, was 32 / 28 / 32 / 44) | **28px** (Polaris Button), `--ui-btn-h` | **44px**, `ui-btn--sm` included |
|
|
390
401
|
| `ui-btn` inside a popup's head or foot (0.7.3) | 28px, 12px | 44px |
|
|
391
402
|
| Focus ring, every control | 2px iris `--ui-focus` (= `--gemboss-accent`, the admin's `--p-color-border-focus`) | same |
|
|
392
403
|
| Body text (`html`, `body`, at zero specificity) | 13px / 20px, weight 450, `--gemboss-text`, antialiased (Polaris bodyMd) | same |
|
|
@@ -436,6 +447,74 @@ If your surface still sets any of these itself (a `body { font-size }`, a `min-h
|
|
|
436
447
|
cascade over the package's zero-specificity base. `packages/ui/src/kit-look.test.ts` measures the table above in
|
|
437
448
|
Chromium on the built CSS.
|
|
438
449
|
|
|
450
|
+
## Admin density (0.12.0)
|
|
451
|
+
|
|
452
|
+
05/10/2026, Chris: "UI GemFactory hình như mọi thứ to hơn bên gemboss". Measured the same day on admin.gemboss.ai, the
|
|
453
|
+
catalog and nine surfaces (raw data and matrix: `Gems/_local/fleet/ui-density-2026-10/`): about 94% of the gaps came from
|
|
454
|
+
the PACKAGE, not from the surfaces. It drew a 32px button at 13px where Polaris draws 28 at 12, a 22/28/650 page title
|
|
455
|
+
where Polaris draws 20/24/700, table cells padded 8 where Polaris pads 12, a bordered card where Polaris draws a shadow,
|
|
456
|
+
and an uppercase 11px tag. 0.12.0 draws the admin's numbers under a mouse and keeps the 44px floor under a finger or at
|
|
457
|
+
phone width (`(pointer: coarse), (max-width: 47.9975em)`, the topbar search's rule since 0.6.5), which is how a surface
|
|
458
|
+
both looks like the admin and passes Gems/CLAUDE.md §9.1.
|
|
459
|
+
|
|
460
|
+
| | Under a mouse, ≥ 768px | Under a finger / < 768px |
|
|
461
|
+
|---|---|---|
|
|
462
|
+
| `ui-btn` (every variant), `ui-btn--icon` | 28px, padding 0 12, 12px/550 (`--ui-btn-h`) | 44px |
|
|
463
|
+
| `ui-seg` group, `.is-text` label | 28px, 12px/550 | 44px |
|
|
464
|
+
| `ui-tabs` | 28px, padding 0 12, 12px/550 selected or not, 8px apart | 44px |
|
|
465
|
+
| `ui-page-head h1` | 20px / 24px / 700 (Polaris headingLg) | same |
|
|
466
|
+
| `ui-card`, `ui-table-wrap` | Polaris' shadow-100 under it (`--ui-card-shadow`), one 1px `--ui-border` edge, radius 12, padding 16 | same |
|
|
467
|
+
| `ui-card__title`, `ui-section-head > h2`, `ui-empty__title` | 14px / 20px / 650 (headingMd) | same |
|
|
468
|
+
| `ui-table` | Polaris DataTable: cells 8px 6px (row 36), `th` 12px 6px at 13px/450 (45), first and last column 12 from the edge | same |
|
|
469
|
+
| `ui-select` | weight 450 | 44px |
|
|
470
|
+
| `ui-badge` | 12px / 450 (its text span; 550 was the box) | same |
|
|
471
|
+
| `ui-tag` | Polaris Tag: 12px/450 on a 20px line, padding 0 6, radius 8, not uppercase | same |
|
|
472
|
+
| `ui-metric--lg` value / label, `ui-funnel__val` | 24/32/700 · 13px · 20/24/700 | same |
|
|
473
|
+
|
|
474
|
+
New in `kit-plain.css` (surfaces drew both by hand):
|
|
475
|
+
|
|
476
|
+
| Need | Markup |
|
|
477
|
+
|---|---|
|
|
478
|
+
| Filter chip (Polaris FilterPill's shape at the Button's density: dashed until applied) | `<div class="ui-chips"><button type="button" class="ui-chip" aria-pressed="true">Plus</button><a class="ui-chip" href="?c=us" aria-current="page">US</a></div>` |
|
|
479
|
+
| Cards on a page, 16px apart (Polaris BlockStack gap 400) | `<div class="ui-stack">…cards…</div>`, `ui-stack--tight` for 8 |
|
|
480
|
+
|
|
481
|
+
**Headings inside the shell.** In the admin a bare `<h2>` or `<p>` is body text with no margin: Polaris' global sheet
|
|
482
|
+
resets `h1…h6, p` (size 1em, regular weight, margin 0), and every heading that looks like one is a Text variant. `app-shell.css`
|
|
483
|
+
now does the same INSIDE `.gemboss-platform-shell` only, to elements without a class (a surface's `h2.x-title` keeps
|
|
484
|
+
what it had), and never inside an article the surface shows: mark post bodies, rendered markdown and previews with `ui-prose` or `data-content` (the wrappers already in the fleet are recognised by name too: `.md-body`, `.recap-md`, `.asst-md`, `.article-body`, and any class containing `prose` or `markdown`; the gate skips the same list) and they keep the browser's
|
|
485
|
+
heading scale and margins. A page heading is `ui-page-head`, a card or section heading `ui-card__title` /
|
|
486
|
+
`ui-section-head`. The kit no longer reads `--gemboss-fs-body` (14), `--gemboss-fs-h1/h2/h3`: those are the admin seller
|
|
487
|
+
app's own prose sizes; the kit is on Polaris' scale (`--ui-fs-body` 13, `--ui-fs-caption` 12, headings 14 / 20 / 24).
|
|
488
|
+
|
|
489
|
+
Not in 0.12.0 (a separate change): colour. The kit's ink and primary fill are `#1b1c1e`, Polaris' `#303030`; Polaris'
|
|
490
|
+
secondary button is a grey fill, the kit's a white one with a line.
|
|
491
|
+
|
|
492
|
+
### The density gate: `packages/ui/scripts/density.mjs` + `polaris-reference.json`
|
|
493
|
+
|
|
494
|
+
`polaris-reference.json` pins what the admin draws, role by role, with where each number was measured (admin.gemboss.ai
|
|
495
|
+
05/10/2026, Polaris 13.9.5 for Tag and the card bevel). `packages/ui/scripts/density.mjs` opens a page in Chromium, finds every
|
|
496
|
+
visible element of each role (the kit's selectors), reads computed style (text from the element that paints the first
|
|
497
|
+
glyph, as Polaris wraps its labels) and lists every value that is not the admin's. Two modes: `fine` (mouse, ≥ 768px)
|
|
498
|
+
is exact; `touch` (`--touch`, or narrower than 768) keeps typography and asks every control for ≥ 44px. Any `h1`–`h6`
|
|
499
|
+
that is not one of the admin's heading styles (20/24/700, 14/20/650, 13/20/650) is reported: that is a bare heading.
|
|
500
|
+
Not measured: sr-only text (1px), anything inside `.ui-prose` / `[data-content]`, closed `<details>`.
|
|
501
|
+
|
|
502
|
+
```
|
|
503
|
+
node scripts/visual-gate/visual-gate.mjs --url https://factory.gemboss.ai/ --density # in the official gate, every width
|
|
504
|
+
node packages/ui/scripts/density.mjs --catalog # the package's own catalog
|
|
505
|
+
node packages/ui/scripts/density.mjs --url https://factory.gemboss.ai/ --width 1280
|
|
506
|
+
node packages/ui/scripts/density.mjs --url https://factory.gemboss.ai/ --width 390 --touch
|
|
507
|
+
DENSITY_COOKIE='session=…' node packages/ui/scripts/density.mjs --url … --scope main --json
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
Exit 1 when anything differs, 3 when nothing was measured; "not on this page" lists roles the page does not show
|
|
511
|
+
(never read that as a pass). In visual-gate, `--density` adds a `density` check per width (touch mode at <= 768, as the
|
|
512
|
+
gate's own tap checks) that is `skip`, not pass, when the page has no kit element. On a
|
|
513
|
+
surface page, run it after upgrading the package: what it still lists is the surface's own CSS. `packages/ui/src/density.test.ts`
|
|
514
|
+
runs it on the catalog (1280 mouse, 390 finger, 390 mouse) and on the admin's own sheets, with its controls: a
|
|
515
|
+
`.ui-btn{height:32px}` or `min-height:44px` under a mouse and a bare `<h2>` turn it red; sr-only text, an article's
|
|
516
|
+
heading and the 44px floor under a finger do not.
|
|
517
|
+
|
|
439
518
|
## Popup density (0.7.3)
|
|
440
519
|
|
|
441
520
|
The kit popup (`.ui-overlay > .ui-modal`, `<dialog class="ui-modal">`, `openModal`, `Dialog`) is drawn at Polaris
|
|
@@ -652,6 +731,79 @@ surface computes every number and ratio; the kit only draws. Markup for each is
|
|
|
652
731
|
- `ui-grid--2` / `--3`: card grid that drops to one column; `ui-section-head`: an `h2` + note between page head and
|
|
653
732
|
card titles.
|
|
654
733
|
|
|
734
|
+
## Collections (0.13.0): tables, lists, grids, boards
|
|
735
|
+
|
|
736
|
+
Chris settled these on 05/10/2026 after an inventory of 136 hand-made collections on 11 surfaces (86 tables scrolling
|
|
737
|
+
sideways, 7 of them at 1280; 0 sticky first columns; 12 kinds of empty state; checkboxes that selected nothing). Load
|
|
738
|
+
`@gemboss/ui/collections.css` beside `gemboss-ui.css` (its own entry, like `editor.css`: the export had ~1.4 KB of room
|
|
739
|
+
left under its 90 KB, and the admin, which draws tables with Polaris, never loads it). Plain-HTML surfaces also load
|
|
740
|
+
`kit-plain.js` (row links, selection, client sort). Every pattern is in the catalog with its states, at 1280 and 390.
|
|
741
|
+
|
|
742
|
+
### Which pattern
|
|
743
|
+
|
|
744
|
+
```
|
|
745
|
+
Is the picture what people look at to choose? → 5 Card grid
|
|
746
|
+
Do items move through states, and do people move them? → 6 Board
|
|
747
|
+
Is the frame narrower than 480 (a rail, a popup, a drawer)? → 4 Compact list (3 if it needs media)
|
|
748
|
+
Are there 3+ attributes to compare across items?
|
|
749
|
+
├─ each row is an entity to open / select in bulk? → 2 Index table
|
|
750
|
+
└─ read-only figures → 1 Data table
|
|
751
|
+
One line per item? → 4 Compact list
|
|
752
|
+
Otherwise → 3 Resource list
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
More than 50 items: paginate (`ui-pager`, position in the URL; a feed or a board column: `ui-more`). Never cut a list
|
|
756
|
+
silently: a `slice` prints "+N more" or "See all N". A table renders at most 100 rows at a time.
|
|
757
|
+
|
|
758
|
+
| # | Pattern | React | HTML | Polaris |
|
|
759
|
+
|---|---|---|---|---|
|
|
760
|
+
| 1 | Data table | `DataTable` | `ui-table-wrap > table.ui-table(.ui-table--sticky-first, --compact)`; `tfoot.ui-table__totals`, `.ui-table__footer` | DataTable |
|
|
761
|
+
| 2 | Index table | `IndexTable` (client) | `div.ui-index > [div.ui-index__sortbar] + [div.ui-bulkbar] + ui-table-wrap > table.ui-table.ui-table--index`; `tr[data-href]`, `td.ui-table__check`, `td.ui-table__primary > a.ui-table__title + span.ui-sub`, `td.ui-table__actions` | IndexTable |
|
|
762
|
+
| 3 | Resource list | `ResourceList` + `ResourceItem` | `ul.ui-list > li.ui-list__item > .ui-list__media + .ui-list__body(a.ui-list__title, p.ui-list__sub, p.ui-list__meta, .ui-list__badges) + .ui-list__aside + .ui-list__actions` | ResourceList |
|
|
763
|
+
| 4 | Compact list | `CompactList` (`variant="activity"`) | `ul.ui-list.ui-list--compact > li.ui-list__item > a/button/div.ui-list__row`; timeline: `ui-list--activity`, `.ui-list__dot(--tone)`, `.ui-list__detail`, `time` | ActionList |
|
|
764
|
+
| 5 | Card grid | `CardGrid min={200 \| 240 \| 320}` + `MediaCard` | `div.ui-cardgrid[data-min] > article.ui-card.ui-card--media > a.ui-card__media + .ui-card__menu + .ui-card__body > a.ui-card__link` | InlineGrid + Card |
|
|
765
|
+
| 6 | Board | `Board` | `div.ui-board > section.ui-board__col > header.ui-board__head + ol.ui-board__list + details.ui-board__more` | none |
|
|
766
|
+
| | States | `CollectionState kind="empty \| no-match \| error"`, `CollectionSkeleton pattern=…`, `state="busy"` | `ui-empty(--no-match)`, `ui-coll-error`, `ui-skeleton--table/--list/--compact/--grid/--board`, `aria-busy="true"` | EmptyState, EmptySearchResult |
|
|
767
|
+
|
|
768
|
+
`./collections` is a plain module (a server component renders it, render functions and all); `IndexTable` is a client
|
|
769
|
+
module. Its props are plain data (rows of rendered cells, `sortHref` strings) so a server page can still render it;
|
|
770
|
+
the callbacks (`onSort`, `onSelectionChange`, a bulk action's `onAction`) need a client parent. Neither module reaches
|
|
771
|
+
the admin's first load (`kit-plain-bundles.test.ts` checks the shell import carries none of their code).
|
|
772
|
+
|
|
773
|
+
### The rules, and what checks them
|
|
774
|
+
|
|
775
|
+
- **The whole row opens the item; the title stays a real link** (Cmd-click, a screen reader). A click on a checkbox, a
|
|
776
|
+
button, the ⋯ menu, a select or a second link does only that; so does a click that ends a text selection. A row with
|
|
777
|
+
two or more in-place editors is not linked (only its title is). HTML: `tr[data-href]` + kit-plain.js; React:
|
|
778
|
+
`IndexTable` rows with `href`; a resource list's title link covers its row (no script).
|
|
779
|
+
- **One visible button per row at most**, the rest in the ⋯ menu (`ui-menu`). **Never shown only on hover.**
|
|
780
|
+
- **Below 768 of its container an index table becomes a list** (title line; the other cells on one caption line,
|
|
781
|
+
`data-label` prefixes, `data-condensed="hide"` drops; checkbox and actions kept; rows ≥ 44); sort moves to the chips
|
|
782
|
+
of `ui-index__sortbar`. **A data table never folds:** it scrolls in its frame with `--sticky-first`.
|
|
783
|
+
- **At 1280 a table fits its page frame.** Fix in this order: a `canvas` page if the content really is wide; move
|
|
784
|
+
low-priority columns to the detail page; fold attributes into the `ui-sub` line.
|
|
785
|
+
- **No zebra, no uppercase header, no card per row, no grid that changes its column count per viewport** (auto-fill
|
|
786
|
+
with one of 200 / 240 / 320).
|
|
787
|
+
- **A checkbox column only with bulk actions.** The bulk bar covers the header (the table does not move), carries its
|
|
788
|
+
own select-all, Shift+click takes a range, Escape clears. HTML: `input[data-gb-select]` / `[data-gb-select-all]`,
|
|
789
|
+
`gembossUI.selection(root)`, event `gb:selection`.
|
|
790
|
+
- **Sort lives in the URL** (`th[aria-sort] > a.ui-table__sort`); `button.ui-table__sort` sorts a small table in place
|
|
791
|
+
(`table[data-gb-sort="client"]`, by `data-sort-value`) or fires `gb:sort` for the page (`data-gb-sort="event"`); a React table owns its buttons and kit-plain.js leaves them alone.
|
|
792
|
+
- **States** (Gems/CLAUDE.md 9.2): empty (one main action) · no match (filters and header stay, "Clear filters") ·
|
|
793
|
+
loading (a skeleton in the pattern's shape: a table keeps its real header, rows keep their height) · reloading
|
|
794
|
+
(`aria-busy`: the old rows stay, dimmed) · error (a banner in the frame + Retry, "as of HH:MM" with old data; never an
|
|
795
|
+
empty list) · selected · sort · filter (`ui-toolbar` + `ui-chip` + `ui-coll-count`) · pagination · long content
|
|
796
|
+
(`ui-trunc`, `ui-clamp-2`, the full text in `title`) · hover · focus-visible (a ring on the row) · reduced motion.
|
|
797
|
+
|
|
798
|
+
Checks: `packages/ui/src/collections.test.ts` (behaviour in Chromium, both the HTML and the React table), the density gate
|
|
799
|
+
(`polaris-reference.json` roles `dataRow`, `indexHead`, `indexCell`, `indexRow`, `bulkBar`, `resourceItem`,
|
|
800
|
+
`resourceItemTwoLine`, `resourceTitle`, `compactRow`, `skeletonBar`, `thumbnail`) and `packages/ui/scripts/collections-gate.mjs`,
|
|
801
|
+
which reports the ruled-out combinations on any page (each rule has a page built to break it in the test):
|
|
802
|
+
|
|
803
|
+
```bash
|
|
804
|
+
node packages/ui/scripts/collections-gate.mjs --url https://partner-radar.ops.gemboss.ai/companies --width 1280
|
|
805
|
+
```
|
|
806
|
+
|
|
655
807
|
## Long lists: pages or "load more" (0.7.3)
|
|
656
808
|
|
|
657
809
|
*Recommendation, not a rule: Claude, 04/10/2026, after Chris asked it to decide for GemFactory.*
|
|
@@ -724,6 +876,7 @@ something the base cannot express, add a token or a prop here, and every surface
|
|
|
724
876
|
| `packages/ui/src/shell.css` | the SHARED SHELL (rail, topbar, main, mobile drawer, the assistant's thread rail, popover surface, account chip). The admin's `gemboss-shell.css` @imports it on line 2; the export refuses a shared-shell rule in the admin's sheet or an admin-only rule here (one owner). |
|
|
725
877
|
| `packages/ui/src/kit-plain.css` | primitives for surfaces that render plain HTML, not React (0.2.1): menu, key/value list, icon button; 0.3.0 adds `ui-link` / `ui-prose`, the media card (`ui-card--media`, `__media`, `__body`, `__foot`) and the popup's `ui-modal__body` / `__foot`. Shipped inside `gemboss-ui.css`; the admin does not import it (its first-load CSS budget has ~0.1 KB headroom).; (0.4.0) report pages: delta, large KPI grid, bar list, column chart, legend, funnel, card grid, section head. |
|
|
726
878
|
| `packages/ui/src/kit-plain.js` | 0.3.0: the behaviour those surfaces each wrote by hand: `gembossUI.openModal` (Escape, backdrop, Tab trap, stacking, ask-before-close, focus back), `toast` (text, error tone), `initMenus` (outside click, item, blur, Escape closes the menu before the popup); 0.5.0: `confirm`, `initShell`, `initPasswordFields` / `resetPasswordFields`. A classic script: inline it or `<script src>`; see "Plain-HTML behaviour" above. |
|
|
879
|
+
| `packages/ui/src/collections.css` | 0.13.0: tables, lists, grids, boards and their states (see "Collections"). A separate entry, NOT inside `gemboss-ui.css`; the admin does not load it. |
|
|
727
880
|
| `packages/ui/src/editor.css` | 0.9.0: the editors (frame, top bar, preview, Configure dock, inspector and controls, Layers, settings drawer, page picker, menus). A separate entry, NOT inside `gemboss-ui.css`; the admin imports it from the editor components, never from a layout. See "Editor CSS" above. |
|
|
728
881
|
| `packages/ui/src/chat.css`, `chat-composer.css`, `assistant.css`, `auth.css`, `app-shell.css` | the chat body, the composer, the assistant frame, the sign-in screen, the topbar slots + base text + the page width tiers (`ui-page`, 0.8.1). All inside `gemboss-ui.css`; the admin @imports `chat.css` and `chat-composer.css` itself. |
|
|
729
882
|
| `packages/ui/src/icon.svg` | 0.5.0: the GemBoss app icon, for `<link rel="icon" type="image/svg+xml">`. Must stay byte-identical to `apps/admin/src/app/icon.svg` (`kit-look.test.ts` checks). |
|