@gemboss/ui 0.34.2 → 0.35.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 CHANGED
@@ -2,6 +2,49 @@
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.35.0 (12/10/2026)
6
+
7
+ **Sheet: a record opened beside its list.** The kit popup docked to the right edge (Chris 12/10/2026, partner-radar: "bấm
8
+ vào people của từng người nên trượt ra side popup"). README "Sheet".
9
+
10
+ **SettingsDialog: settings as one popup.** The admin's settings shape (rail of sections with a search box, the section on
11
+ the right), moved here from the admin's module CSS so GemWatcher and partner-radar stop copying it (Chris 12/10/2026,
12
+ "settings thì bật popup theo chuẩn của gemboss ui"). README "SettingsDialog".
13
+
14
+ Added
15
+ - `Sheet` (client), `sheet.css` (its own entry `./sheet.css`, loaded by the component; `gemboss-ui.css` unchanged).
16
+ - `SettingsDialog` (client), `settings-dialog.css` (its own entry `./settings-dialog.css`, loaded by the component).
17
+ - Catalog sections "Ngăn trượt cạnh phải" and "Hộp cài đặt".
18
+ - `packages/ui/weight-budget.json`: ceilings for `packages/ui/src/sheet.css` and `packages/ui/src/settings-dialog.css`.
19
+
20
+ Changed
21
+ - `Sheet` is `Dialog` with `ui-sheet` on it: one render tree and one hook (`useModalDialog`, dialog.tsx).
22
+ - `Dialog`: optional `subtitle` (its own `aria-describedby`, not part of the name) and `actions` (beside the title,
23
+ before ✕), the kit head's `.ui-modal__subtitle` / `.ui-modal__actions`; `focusPanel` (the popup takes focus on open).
24
+ Without them it renders exactly as before.
25
+ - Every modal kit popup holds the page behind still: `html:has(dialog.ui-modal:modal) { overflow: hidden }` (kit-plain.css),
26
+ one rule instead of one per component; `:modal`, so a dialog drawn open with the attribute (the catalog) does not lock.
27
+ - `useModalDialog` takes `returnFocusTo`: a selector focused on close when the opener left the screen (`<body>` counts as
28
+ gone).
29
+ - `Dialog`: a click on the backdrop closes it only when the press started there too (a text selection dragged out of the
30
+ panel and released over the scrim closed it); focus goes back to the opener without scrolling the page, also when the
31
+ popup is unmounted while open; `onClose` is read from a ref, so the listener is attached once.
32
+
33
+ ## 0.34.3 (11/10/2026)
34
+
35
+ Fixed
36
+ - `DisclosureItem` read `process.env.NODE_ENV` for its two development warnings: the package ships its TypeScript
37
+ source, so a surface whose tsconfig has no @types/node (GemWatcher, Vite) failed `tsc -b` on 0.34.2 ("Cannot find name
38
+ 'process'"). The warnings now run in every build; they speak only on a misuse (`open` without `onOpenChange`, a link
39
+ or button inside the summary). `no-node-globals.test.ts` fails on any `process` / `Buffer` / `__dirname` /
40
+ `__filename` / `require` in the shipped source.
41
+ - A text link in a row's `aside` or `actions` ("Profile →", "Live page ↗") is 24px tall (WCAG 2.5.8, a link in a list),
42
+ and in a `DisclosureItem`'s ≤400 two-band layout the second band sits 8px under the body, not 4 (§9.1: two targets 8
43
+ apart when one is under 44; its body is a button). GemWatcher's Feed: "Profile →" was 20px tall, 4px under the row's
44
+ toggle (review #437). A ResourceItem keeps 4: its body is no target of its own (the title's link covers the row).
45
+ - `disclosure-item.test.ts` lays its page out at the device width (viewport meta): its "390" and "320" cases had run at
46
+ 980px, so they never saw the two-band layout.
47
+
5
48
  ## 0.34.2 (11/10/2026)
6
49
 
7
50
  Fixed
package/README.md CHANGED
@@ -1134,6 +1134,75 @@ A large popup can keep its subtitle and its own actions in the kit head instead
1134
1134
  `gemboss-ui.css` and on the admin's sheets alone. `UI_MODAL_ROOT=<a 0.7.1 tree>` runs it against the old CSS, where
1135
1135
  it is red.
1136
1136
 
1137
+ ## Sheet (0.35.0): a record opened beside its list
1138
+
1139
+ Chris 12/10/2026 on partner-radar: a click on a person in a list should slide their profile out at the side, not
1140
+ leave the list. The package had a centred popup (`Dialog`), a command popup (`SearchDialog`), menus, the editor's
1141
+ `EditorDrawer` (the right shape, but no Escape, focus left behind, and it brings `editor.css`) and the assistant's side
1142
+ panel (the assistant's). `Sheet` is the kit popup docked to the right edge:
1143
+
1144
+ ```tsx
1145
+ import { Sheet } from "@gemboss/ui";
1146
+
1147
+ <Sheet open={!!person} onClose={() => setPerson(null)} title={person?.name} subtitle="CRO agency · Plus"
1148
+ actions={person && <a className="ui-btn" href={`/partners/${person.id}`}>Open full profile</a>}>
1149
+ …the record's summary…
1150
+ </Sheet>
1151
+ ```
1152
+
1153
+ It stays mounted while closed, so read the record with `?.` (or render it only while there is one: unmounted while
1154
+ open, focus still goes back to the row). `onClose` runs on every close, `open` turning false included, as `Dialog`'s
1155
+ does: keep it idempotent. A route that draws the sheet (Next's intercepting route) leaves `open` true and goes back in
1156
+ `onClose`; one that derives `open` from the URL must not navigate again in `onClose`.
1157
+
1158
+ | | |
1159
+ | --- | --- |
1160
+ | Markup | `<dialog class="ui-modal ui-sheet">` with the popup's own `ui-modal__head` (title, `__subtitle`, `__actions`, ✕), `__body`, `__foot` |
1161
+ | Behaviour | It is `Dialog` with `ui-sheet` on it (one render tree, one hook, `useModalDialog`): Escape, ✕ and a click on the backdrop close it (a press that STARTED on the backdrop: a selection dragged out of the panel does not), `onClose` hears each once, the page behind is inert and holds still (`html:has(dialog.ui-modal:modal) { overflow: hidden }` in kit-plain.css, one rule for every modal kit popup), the panel itself takes focus on open (not the head's first link), focus goes back to the row. The subtitle describes the popup (`aria-describedby`); the name is the title alone |
1162
+ | Size | the full height; 560 wide, `wide` 760, from 768px up; the whole screen below that; head, ✕ and buttons at the popup's density (README "Popup density") |
1163
+ | Motion | slides in from the right (200 ms); none under `prefers-reduced-motion` |
1164
+ | Scrim | `rgba(0,0,0,.3)`, lighter than the centred popup's `.5`: the list stays readable beside it |
1165
+ | CSS | `sheet.css`, its own entry, loaded by the component. Every selector is `dialog.ui-modal.ui-sheet…` ((0,2,1), so it holds whatever order the sheets load in) or the page lock. It lays itself out (no padding, border-box, a column whose body scrolls), so it works on a surface that loads `ui.css` alone; the head's subtitle and actions are styled by `kit-plain.css`. A plain-HTML surface links `@gemboss/ui/sheet.css` beside `gemboss-ui.css` and opens the markup with `showModal()`, never the `open` attribute (no scrim, page not inert) |
1166
+
1167
+ The body scrolls under a head that stays, and scrolling past its end does not scroll the list (`overscroll-behavior:
1168
+ contain`). `packages/ui/src/sheet-browser.test.tsx` measures it in Chromium; its negative control runs the same probe
1169
+ without `sheet.css` and finds the centred popup. Catalog section "Ngăn trượt cạnh phải".
1170
+
1171
+ ## SettingsDialog (0.35.0): settings as one popup
1172
+
1173
+ The admin's Settings (apps/admin `SettingsDialog`): one popup over the app, the sections in a rail on the left with a
1174
+ search box, the chosen section on the right, the close button in the corner; under 861px the rail becomes one scrolling
1175
+ strip above the section and the popup is the whole screen. GemWatcher copied the admin's module CSS (#400) and
1176
+ partner-radar needed it too (Chris 12/10/2026, "settings thì bật popup theo chuẩn của gemboss ui"), so it lives here.
1177
+
1178
+ ```tsx
1179
+ import { Icon, SettingsDialog } from "@gemboss/ui";
1180
+
1181
+ <SettingsDialog open={open} onClose={() => setOpen(false)} activeId={id} onSelect={setId}
1182
+ sections={[
1183
+ { id: "general", group: "Workspace", title: "General", description: "Name and time zone.", icon: <Icon name="settings" size={16} /> },
1184
+ { id: "members", group: "Account", title: "Members", href: "/settings/members", icon: <Icon name="users" size={16} /> },
1185
+ ]}
1186
+ linkAs={Link} footLinks={[{ href: "/ops", title: "Jobs", icon: <Icon name="activity" size={16} /> }]}>
1187
+ {pane}
1188
+ </SettingsDialog>
1189
+ ```
1190
+
1191
+ | | |
1192
+ | --- | --- |
1193
+ | What it owns | the shell only: the rail (search, groups, sections, foot links), the pane head (the active section's `title` and `description`, which is also the popup's name), the scrolling body, the corner ✕ |
1194
+ | What the surface owns | the sections and the active one's content (`children`): no settings, data or fetching here |
1195
+ | A section | a button (`onSelect(id)`, required by the types when any section has no `href`) or, with `href`, a link drawn with `linkAs` (a surface whose sections are routes; the active one carries `aria-current="page"`). An `activeId` that matches no section highlights and names nothing (no silent first section) |
1196
+ | Content | `children` in a measure: `measure="default"` 900px, `"form"` 662px (one column of fields), `"full"` the pane. A new section opens at its top |
1197
+ | Foot links | pages outside settings; following one closes the popup |
1198
+ | Search | matches title, description, `keywords` and group; "No setting matches “…”." when nothing does (`noMatch`) |
1199
+ | Behaviour | `<dialog class="ui-modal ui-modal--lg ui-settings">` opened through `useModalDialog` like `Dialog` and `Sheet`: Escape (one press, also with words in the search box), a press that starts on the backdrop, the inert page that holds still (`position: fixed`: `ui-modal--lg` alone made it absolute and jumped a scrolled page to the top), the popup takes focus on open and ✕ is last in the order; focus goes back to the opener, or to `returnFocusTo` (default `[data-settings-trigger]`) when the opener left the screen (a menu item). Each opening starts with an empty search |
1200
+ | Size | the workspace popup: `--gem-popup-workspace-w / -max / -h` (the admin's tokens; 96vw, 1680px, the height less 48 without them); 280px rail; sections 44px; under 861px the whole screen, the rail a strip |
1201
+ | CSS | `settings-dialog.css`, its own entry, loaded by the component. The search box is the kit's field made of parts (`gemboss-field gemboss-field--group` + `gemboss-field__bare`), the ✕ the kit popup's (`ui-modal__close`) |
1202
+
1203
+ `packages/ui/src/settings-dialog-browser.test.tsx` measures it in Chromium; its negative control runs without
1204
+ `settings-dialog.css` and finds no 280px rail. Catalog section "Hộp cài đặt".
1205
+
1137
1206
  ## Resizable panels
1138
1207
 
1139
1208
  `ui-resizer` is the seam a person drags between two panels; `ui-resizing` on `<body>` is the drag in
@@ -8,7 +8,7 @@
8
8
  .cat-code summary{padding:10px 16px;font-size:13px;cursor:pointer;color:var(--gemboss-text-muted);border-top:1px solid var(--gemboss-divider);min-height:24px}
9
9
  .cat-code pre,.cat-api{margin:0;padding:12px 16px;overflow:auto;background:#0f1012;color:#e8e8e6;font-size:12px;line-height:1.5;border-radius:0}
10
10
  .cat-api{border-radius:12px;margin:0 0 16px}</style></head><body><div class="cat">
11
- <h1>@gemboss/ui 0.34.2 · Editor</h1>
11
+ <h1>@gemboss/ui 0.35.0 · Editor</h1>
12
12
  <p>Khung của mọi editor: <code>EditorFrame</code> (cột trái · khe kéo · preview · cột phải dock trên mép phải preview) và <code>EditorTopbar</code> (← · tiêu đề · cụm giữa · cụm phải · dòng trạng thái). Là đúng khung của theme / page / section editor trong admin. Gói chỉ vẽ KHUNG; chat, Configure, canvas, page picker, menu, Publish là của editor, đi vào bằng slot. Trang HTML thuần nạp <code>editor.css</code> + <code>editor-plain.js</code> rồi gọi <code>gembossUI.initEditorFrame()</code>: kéo khe (chuột, chạm, phím mũi tên / Home / End), đổi thiết bị, mở ⋯ và Publish ▾, ẩn cột trái, Chat | Preview trên điện thoại. <a href="index.html">← Catalog</a></p>
13
13
  <h2>React</h2><pre class="cat-api"><code>import &quot;@gemboss/ui/editor.css&quot;;
14
14
  import { EditorFrame, EditorTopbar, EditorBack, EditorChatToggle, EditorPaneTabs, EditorSaveState, DeviceToggle } from &quot;@gemboss/ui/editor&quot;;