@gemboss/ui 0.40.0 → 0.41.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 +51 -0
- package/README.md +92 -0
- package/catalog/editor.html +1 -1
- package/catalog/index.html +384 -232
- package/gemboss-ui.css +3 -3
- package/package.json +6 -2
- package/parts/components.css +1 -1
- package/parts/core.css +1 -1
- package/parts/shell.css +2 -2
- package/src/editor/repeater.tsx +27 -19
- package/src/editor.css +1 -1
- package/src/index.ts +1 -0
- package/src/reader-dialog.css +1 -0
- package/src/reader-dialog.tsx +26 -0
- package/src/shell.css +1 -1
- package/src/team-chat-plain.js +1 -0
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.41.0 (20/10/2026)
|
|
6
|
+
|
|
7
|
+
**A document read over its list** (Chris 20/10/2026, after GemMedia's and partner-radar's Docs drew the same popup with
|
|
8
|
+
their own CSS: "làm đi").
|
|
9
|
+
|
|
10
|
+
Added
|
|
11
|
+
- `ReaderDialog`: the kit popup sized for reading, `min(1440px, 94vw)` × `min(92dvh, 1200px)`, the whole screen under
|
|
12
|
+
768px with the head's actions on their own line. It is `Dialog` with `ui-reader` (same props, less `wide`). The body has
|
|
13
|
+
no padding and is a column the document fills: `ui-reader__frame` (an iframe) or `ui-reader__scroll` (a padded scroller
|
|
14
|
+
of the surface's own). README "ReaderDialog", catalog "Hộp đọc tài liệu".
|
|
15
|
+
- `packages/ui/src/reader-dialog.css` (`@gemboss/ui/reader-dialog.css`): its own entry, imported by the component; every
|
|
16
|
+
selector `dialog.ui-modal.ui-reader…`. Nothing moves into the core or the bundle.
|
|
17
|
+
- `reader-dialog.test.tsx` (markup, every class styled, selectors), `reader-dialog-browser.test.tsx` (Chromium: size,
|
|
18
|
+
fill, scroll, phone head, page lock, Escape; negative control without the entry finds the 460px popup).
|
|
19
|
+
|
|
20
|
+
**The team chat's rows for a plain page, from the package: `gembossUI.teamChat`** (Chris 20/10/2026: the markup in ONE place,
|
|
21
|
+
so GemCare stops writing it by hand and a change to it is made once).
|
|
22
|
+
|
|
23
|
+
Added
|
|
24
|
+
- `packages/ui/src/team-chat-plain.js` (`@gemboss/ui/team-chat-plain.js`, its own entry): builders that RETURN elements with
|
|
25
|
+
the components' markup for the same props: `message` (`Message`, every prop; plus `picking` / `reactionsPicking` /
|
|
26
|
+
`onPickingChange` for a page that redraws its list), `daySeparator`, `newMessagesLine`, `jumpToLatest` + `updateJump`,
|
|
27
|
+
`readReceipt`, `channelSection`, `channelItem`, `peopleSection`, `personRow`, `reactions`, `reactionPicker` (the package's
|
|
28
|
+
picker and its keys, "Frequently used" under the React picker's storage key), `avatar`, `icon`, and `rows` / `dayKey` /
|
|
29
|
+
`dayWord` (`teamChatRows`, `chatDayKey`, `chatDayWord`). Labels are `TEAM_CHAT_LABELS` (`LABELS`), any subset overridable.
|
|
30
|
+
Strings are text; callbacks are click listeners. A classic script, ES5, after `kit-plain.js` when the page has it.
|
|
31
|
+
8,208 B gzip minified (ceiling 8,714 in `weight-budget.json`; a page that draws no team chat never loads it).
|
|
32
|
+
- `team-chat-plain-browser.test.ts` (Chromium, `test:ui-browser`): every builder, in every state, against
|
|
33
|
+
`renderToStaticMarkup` of its component as one tree (attributes, classes, text, SVG in full); the same clicks and keys on
|
|
34
|
+
the mounted components and on the plain rows leave the same DOM (the pickers, search, Escape and focus); callbacks,
|
|
35
|
+
escaping, toolbar and picker keys, `updateJump`, the load-order warning. `team-chat-plain-data.test.ts` (node): the
|
|
36
|
+
generated block (icons, emoji set; `UPDATE_PLAIN_TEAM_CHAT=1` writes it) and the ES5 copies (labels, initials, tone,
|
|
37
|
+
reaction helpers, row rules) held to the TypeScript.
|
|
38
|
+
- `team-chat.test.fixtures.tsx`: the contract test's data, now shared with the plain parity test (the README is unchanged).
|
|
39
|
+
- The catalog's "Chat đội" section has a live plain-HTML frame built with `gembossUI.teamChat`.
|
|
40
|
+
|
|
41
|
+
**A list whose items come from elsewhere** (item management IM2, 21/10/2026: a list that shows a content type).
|
|
42
|
+
|
|
43
|
+
Changed
|
|
44
|
+
- `RepeaterList` `onMove` and `onRemove` are optional. Without `onMove` the rows keep their order: no grip, no ↑ ↓, no
|
|
45
|
+
Alt+arrows, no drop. Without `onRemove`, no ✕. A row still opens (inline or in the popover) and still says it was picked
|
|
46
|
+
(`onActive`). The admin draws a list read from Content this way: its order and its rows are Content's. No CSS change.
|
|
47
|
+
|
|
5
48
|
## 0.40.0 (20/10/2026)
|
|
6
49
|
|
|
7
50
|
**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).
|
|
@@ -17,6 +60,14 @@ Added
|
|
|
17
60
|
- `packages/ui/src/editor-repeater.css`: the popover's placement and header, the picked row's outline, the picture (+220 B gzip,
|
|
18
61
|
1,096 of its 1,384 B ceiling). The surface is the fleet's `gemboss-popover-surface`.
|
|
19
62
|
|
|
63
|
+
**An inspector's tabs stand on the fields' edge** (Chris 20/10/2026: "cùng là tabs mà chỗ to chỗ nhỏ").
|
|
64
|
+
|
|
65
|
+
Fixed
|
|
66
|
+
- `packages/ui/src/editor.css`: `.gemboss-ei-tabs` inside a settings body or the column's dock drop their 12px side margin
|
|
67
|
+
(`:is(.gemboss-settings-body,.gemboss-ec-dock-body)`), so the Settings · Advanced track lines up with the fields under it (the
|
|
68
|
+
canvas's element and section panels measured 34–360 and 316px over fields at 22–372). A docked inspector keeps its own, more
|
|
69
|
+
specific rule; a floating inspector keeps 12px. +15 B gzip (8,680 of 8,690).
|
|
70
|
+
|
|
20
71
|
**A phone pays for the topbar once, and the full-screen assistant gets the whole width** (measured on the admin at 390×844,
|
|
21
72
|
19/10/2026).
|
|
22
73
|
|
package/README.md
CHANGED
|
@@ -71,6 +71,7 @@ its CSS out of the build with it (`sideEffects`). gzip of the minified file, as
|
|
|
71
71
|
| assistant-chat | `@gemboss/ui/assistant-chat.css` | `packages/ui/src/assistant-chat.css` | the chat pieces the package draws (0.29.0): column, starters that wrap, meta, errors, notes, paperclip | 0.9 KB | `AssistantChat` and its pieces import it |
|
|
72
72
|
| minichart | `@gemboss/ui/minichart.css` | `packages/ui/src/minichart.css` | `Sparkline`, `ShareBar` (0.30.0) | 0.5 KB | those components import it |
|
|
73
73
|
| setup-guide | `@gemboss/ui/setup-guide.css` | `packages/ui/src/setup-guide.css` | `SetupGuide` (0.30.0) | 0.9 KB | `SetupGuide` imports it |
|
|
74
|
+
| reader-dialog | `@gemboss/ui/reader-dialog.css` | `packages/ui/src/reader-dialog.css` | `ReaderDialog`: the popup sized for reading a document (0.41.0) | 0.4 KB | `ReaderDialog` imports it |
|
|
74
75
|
| service-switcher | `@gemboss/ui/service-switcher.css` | `packages/ui/src/service-switcher.css` | `ServiceSwitcher` and `Switcher`: the button after the brand and its panel (0.36.0; any list, illustrated tiles 0.40.0) | 2.2 KB | `ServiceSwitcher` imports it, and `BrandLockup` through it (README "ServiceSwitcher") |
|
|
75
76
|
| team-chat | `@gemboss/ui/team-chat.css` | `packages/ui/src/team-chat.css` | the team chat layer (20/10/2026): rail, messages, composer, thread and people panels, the screen's layout | 3.6 KB | `TeamChat` and its pieces import it (with `Avatar`'s portal.css and `Reactions`' reactions.css); a plain-HTML page links it (README "The team chat layer") |
|
|
76
77
|
| bundle | `@gemboss/ui/gemboss-ui.css` | `gemboss-ui.css` | core + components + shell + auth + assistant + chat + portal + theme-dark | 21.9 KB | compatibility only (see CHANGELOG 0.23.0) |
|
|
@@ -1177,6 +1178,40 @@ The body scrolls under a head that stays, and scrolling past its end does not sc
|
|
|
1177
1178
|
contain`). `packages/ui/src/sheet-browser.test.tsx` measures it in Chromium; its negative control runs the same probe
|
|
1178
1179
|
without `sheet.css` and finds the centred popup. Catalog section "Ngăn trượt cạnh phải".
|
|
1179
1180
|
|
|
1181
|
+
## ReaderDialog (0.41.0): a document read over its list
|
|
1182
|
+
|
|
1183
|
+
Two surfaces drew the same popup with their own CSS the same week, because `Dialog`'s widths (460, `wide` 620) are a
|
|
1184
|
+
form's: GemMedia's admin Docs (gemmedia #76) and partner-radar's Docs (gemlabs #1122) open a long document over the list
|
|
1185
|
+
of documents, nearly the whole window, the whole screen on a phone. Chris 20/10/2026: put it in the kit. `ReaderDialog`
|
|
1186
|
+
is that popup:
|
|
1187
|
+
|
|
1188
|
+
```tsx
|
|
1189
|
+
import { ReaderDialog } from "@gemboss/ui";
|
|
1190
|
+
|
|
1191
|
+
<ReaderDialog open onClose={close} title={doc.title} subtitle={`v${doc.version} · updated ${doc.updated}`}
|
|
1192
|
+
actions={<><CopyLink slug={doc.slug} /><a className="ui-btn ui-btn--sm" href={doc.src} target="_blank">Open in a new tab</a></>}>
|
|
1193
|
+
<iframe className="ui-reader__frame" src={doc.src} title={doc.title} />
|
|
1194
|
+
</ReaderDialog>
|
|
1195
|
+
```
|
|
1196
|
+
|
|
1197
|
+
The body is the document's. Give it one child that fills it: `iframe.ui-reader__frame` for a self-contained HTML
|
|
1198
|
+
document, or a scroller of your own with `ui-reader__scroll` (padded 24/32/48, 16/16/40 on a phone; it scrolls, keeps
|
|
1199
|
+
its overscroll, and takes `tabIndex={-1}` and focus so the arrow keys and Space read the document). Keys pressed inside
|
|
1200
|
+
an iframe do not reach the `<dialog>`: a surface that wants Escape there forwards it (`frame.contentWindow` keydown →
|
|
1201
|
+
`dialog.close()`, same-origin). A route that draws it (Next's intercepting route) leaves `open` true and goes back in
|
|
1202
|
+
`onClose`, as with `Sheet`.
|
|
1203
|
+
|
|
1204
|
+
| | |
|
|
1205
|
+
| --- | --- |
|
|
1206
|
+
| Markup | `<dialog class="ui-modal ui-reader">` with the popup's own `ui-modal__head` (title, `__subtitle`, `__actions`, ✕), `__body`, `__foot` |
|
|
1207
|
+
| Behaviour | It is `Dialog` with `ui-reader` on it (one render tree, one hook, `useModalDialog`): Escape, ✕ and a press that started on the backdrop close it, `onClose` hears each once, the page behind is inert and holds still (`html:has(dialog.ui-modal:modal)`), focus goes back to the opener. On open focus goes to the first control, as `Dialog`'s; move it to your document |
|
|
1208
|
+
| Size | `min(1440px, 94vw)` × `min(92dvh, 1200px)`, centred, from 768px up; the whole screen below that, where the actions take their own line under the title and ✕ stays beside it |
|
|
1209
|
+
| CSS | `reader-dialog.css`, its own entry, loaded by the component. Every selector is `dialog.ui-modal.ui-reader…` ((0,2,1)). It lays itself out (no padding, border-box, a column the document fills), so it works on a surface that loads `ui.css` alone. A plain-HTML surface links `@gemboss/ui/reader-dialog.css` beside `gemboss-ui.css` and opens the markup with `showModal()` |
|
|
1210
|
+
|
|
1211
|
+
`packages/ui/src/reader-dialog-browser.test.tsx` measures it in Chromium (size at four windows and three phones, the
|
|
1212
|
+
iframe flush under the head, the scroller scrolling under a head that stays, the phone's head, the page lock, Escape);
|
|
1213
|
+
its negative control runs without `reader-dialog.css` and finds the 460px popup. Catalog section "Hộp đọc tài liệu".
|
|
1214
|
+
|
|
1180
1215
|
## SettingsDialog (0.35.0): settings as one popup
|
|
1181
1216
|
|
|
1182
1217
|
The admin's Settings (apps/admin `SettingsDialog`): one popup over the app, the sections in a rail on the left with a
|
|
@@ -2101,6 +2136,62 @@ closes a drawer, focus moves into it and back, the rail and the conversation are
|
|
|
2101
2136
|
open state (`gb-tc-msg--active`, `aria-expanded` on its button); arrow keys along `div.gb-tc-acts[role=toolbar]`; when to
|
|
2102
2137
|
show `.gb-tc-jump` and its count.
|
|
2103
2138
|
|
|
2139
|
+
### Plain HTML: `gembossUI.teamChat` (20/10/2026)
|
|
2140
|
+
|
|
2141
|
+
So a plain page does not write the markup above by hand. `team-chat-plain.js` builds the rows from data and RETURNS
|
|
2142
|
+
elements whose markup is the component's for the same props: tags, classes, every attribute, the text, the icons' SVG.
|
|
2143
|
+
`team-chat-plain-browser.test.ts` draws every piece in every state both ways in Chromium (the contract's data,
|
|
2144
|
+
`team-chat.test.fixtures.tsx`, and the states beyond it) and holds them to one tree, so the markup is written once, in
|
|
2145
|
+
`team-chat.tsx`, and a plain page follows a change to it with a version bump. A classic script, no imports, inlinable:
|
|
2146
|
+
after `kit-plain.js` when the page has it (it adds `gembossUI.teamChat`; loaded first it says so in the console).
|
|
2147
|
+
|
|
2148
|
+
| Builder | Draws what this draws |
|
|
2149
|
+
|---|---|
|
|
2150
|
+
| `message(props)` | `Message`, every prop by the same name; plus `picking` / `reactionsPicking` (a picker drawn open) and `onPickingChange(which, open)` (`"bar"` or `"reactions"`) for a page that redraws its whole list |
|
|
2151
|
+
| `daySeparator(label, dateTime)`, `newMessagesLine(labels)` | `DaySeparator`, `NewMessagesLine` |
|
|
2152
|
+
| `jumpToLatest({ count, visible, onJump, labels })`, `updateJump(button, { count, visible, labels })` | `JumpToLatest`; `updateJump` redraws the same button (a scroll handler keeps its focus) |
|
|
2153
|
+
| `readReceipt({ read, of, label })` | `ReadReceipt` (`null` when `of` ≤ 0) |
|
|
2154
|
+
| `channelSection({ label, id, items })`, `channelItem(props)` | `ChannelSection`, `ChannelItem` (`href`: a link, else a button); `items` are rows or their props |
|
|
2155
|
+
| `peopleSection({ label, count, id, items })`, `personRow(props)` | `PeopleSection`, `PersonRow` (a link, a button with `onSelect`, else a `div`) |
|
|
2156
|
+
| `reactions(props)`, `reactionPicker(props)` | `Reactions` (plus `open` / `onOpenChange`), `ReactionPicker` |
|
|
2157
|
+
| `avatar({ name, src, size, className })`, `icon(name, size)` | `Avatar` (portal.tsx's initials and tone), `Icon` (the icons the builders draw, and `more`) |
|
|
2158
|
+
| `rows(messages, opts)`, `dayKey(at)`, `dayWord(at, now)` | `teamChatRows`, `chatDayKey`, `chatDayWord` |
|
|
2159
|
+
| `LABELS` | `TEAM_CHAT_LABELS`; `labels` (any subset) translates, functions included |
|
|
2160
|
+
|
|
2161
|
+
```html
|
|
2162
|
+
<link rel="stylesheet" href="/ui/portal.css"><link rel="stylesheet" href="/ui/reactions.css"><link rel="stylesheet" href="/ui/team-chat.css">
|
|
2163
|
+
<script src="/ui/kit-plain.js"></script><script src="/ui/team-chat-plain.js"></script>
|
|
2164
|
+
```
|
|
2165
|
+
|
|
2166
|
+
```js
|
|
2167
|
+
const tc = gembossUI.teamChat;
|
|
2168
|
+
list.replaceChildren(...tc.rows(messages, { meId: me.id, isUnread: (m) => m.id > readUpTo }).map((r) =>
|
|
2169
|
+
r.kind === "day" ? tc.daySeparator(dayLabel(r.date), isoDay(r.date))
|
|
2170
|
+
: r.kind === "new" ? tc.newMessagesLine()
|
|
2171
|
+
: tc.message({ author: r.message.authorName, time: hhmm(r.message.at), dateTime: r.message.at, body: r.message.text,
|
|
2172
|
+
grouped: r.grouped, messageId: r.message.id, reactions: r.message.reactions, edited: Boolean(r.message.editedAt),
|
|
2173
|
+
receipt: tc.readReceipt({ read: 2, of: 3, label: "Read by Linh, Quan. Not yet: Bo" }),
|
|
2174
|
+
onReact: (emoji) => react(r.message.id, emoji), onReply: () => startReply(r.message), onOpenThread: (e) => openThread(r.message.id, e.currentTarget),
|
|
2175
|
+
moreActions: myMoreButton(r.message), picking: view.picking === r.message.id,
|
|
2176
|
+
onPickingChange: (which, open) => { if (which === "bar") view.picking = open ? r.message.id : null; } })));
|
|
2177
|
+
```
|
|
2178
|
+
|
|
2179
|
+
Strings are TEXT (a body `"<img onerror=…>"` shows those characters); a slot that takes a node (`avatar`, `badges`,
|
|
2180
|
+
`attachments`, `extra`, `receipt`, `moreActions`, `editor`, a rich `time` or `body`) takes a DOM node as given. Callbacks are
|
|
2181
|
+
click listeners and get what React's `onClick` gets (the event; `onReact` the emoji). The behaviour is the components': the
|
|
2182
|
+
action bar is a toolbar (arrows, Home / End), "More reactions" opens the package's picker under the body and the reaction
|
|
2183
|
+
row's "Add reaction" one under the row (search, this browser's "Frequently used" under the React picker's own storage key,
|
|
2184
|
+
arrows, Enter picks the first match, Escape closes and gives focus back), a chip's click remembers its emoji. A row drawn
|
|
2185
|
+
with `picking` takes no focus: after a redraw the page puts focus back, as it does for anything it redraws.
|
|
2186
|
+
|
|
2187
|
+
Not built here: the screen's shell (`TeamChat`, `ChannelRail`, `ChatHeader`, `MessageList`, `Composer`, `ThreadPanel`,
|
|
2188
|
+
`PeoplePanel`) is markup a page writes once (the blocks above), with the behaviour listed just above.
|
|
2189
|
+
|
|
2190
|
+
The script carries two kinds of copy, both held by `team-chat-plain-data.test.ts`: the icons' drawing (icons.tsx) and the
|
|
2191
|
+
emoji set (reactions-data.ts) as a generated block (`UPDATE_PLAIN_TEAM_CHAT=1` on that test writes it), and the labels, the
|
|
2192
|
+
avatar's initials and tone, the reaction helpers and `teamChatRows` in ES5, called with the TypeScript's inputs and held to
|
|
2193
|
+
its answers.
|
|
2194
|
+
|
|
2104
2195
|
## Action card (0.28.0): an assistant proposes, a person applies
|
|
2105
2196
|
|
|
2106
2197
|
Chris 08/10/2026: the Feedback Assistant lists likely duplicates and merges them, and carries out status, owner, label
|
|
@@ -2405,6 +2496,7 @@ something the base cannot express, add a token or a prop here, and every surface
|
|
|
2405
2496
|
| `packages/ui/src/editor-plain.js` | 0.14.0: `gembossUI.initEditorFrame()`, the frame's behaviour for plain HTML; 0.17.0: `gembossUI.initEditorPanel()`, the settings panel's. Load after `kit-plain.js`. |
|
|
2406
2497
|
| `packages/ui/src/editor-layers-plain.js` | 0.22.0: `gembossUI.initEditorLayers()`, the layers', the outline's and the drawers' behaviour for plain HTML. Load after `kit-plain.js`. |
|
|
2407
2498
|
| `packages/ui/src/service-switcher-plain.js` | 0.36.0: `gembossUI.initServiceSwitcher()`, the ServiceSwitcher drawn and driven for plain HTML (`@gemboss/ui/service-switcher-plain.js`). After `kit-plain.js` when the page has it; works alone. See "ServiceSwitcher". |
|
|
2499
|
+
| `packages/ui/src/team-chat-plain.js` | 20/10/2026: `gembossUI.teamChat`, builders that return the team chat's rows (messages, day separators, "New messages", jump, receipt, rail rows, people rows, reactions and the picker) with the components' markup, for plain HTML (`@gemboss/ui/team-chat-plain.js`). After `kit-plain.js` when the page has it; works alone. See "The team chat layer". |
|
|
2408
2500
|
| `catalog/editor.html` | 0.14.0: the frame rendered from the components and running (`packages/ui/scripts/build-catalog-editor.mjs`), linked from `catalog/index.html`. |
|
|
2409
2501
|
| `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. |
|
|
2410
2502
|
| `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. |
|
package/catalog/editor.html
CHANGED
|
@@ -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.
|
|
11
|
+
<h1>@gemboss/ui 0.41.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 "@gemboss/ui/editor.css";
|
|
14
14
|
import { EditorFrame, EditorTopbar, EditorBack, EditorChatToggle, EditorPaneTabs, EditorSaveState, DeviceToggle } from "@gemboss/ui/editor";
|