@mdbase-dev/ui 0.1.0-beta.125 → 0.1.0-beta.147

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.
Files changed (77) hide show
  1. package/README.md +159 -0
  2. package/css/brand.css +10 -10
  3. package/css/collections.css +978 -0
  4. package/css/controls.css +220 -43
  5. package/css/feedback.css +20 -20
  6. package/css/fonts.css +2 -3
  7. package/css/palette.css +10 -10
  8. package/css/screens.css +58 -16
  9. package/css/tokens.css +43 -3
  10. package/dist/AppSwitcher.js +187 -33
  11. package/dist/Checkbox.d.ts +14 -0
  12. package/dist/Checkbox.js +32 -0
  13. package/dist/CommandPalette.d.ts +4 -2
  14. package/dist/CommandPalette.js +275 -103
  15. package/dist/Dialog.js +72 -25
  16. package/dist/Feedback.js +763 -229
  17. package/dist/FeedbackMarkup.d.ts +1 -1
  18. package/dist/FeedbackMarkup.js +326 -125
  19. package/dist/FeedbackVerification.js +115 -68
  20. package/dist/SaveNotice.js +71 -28
  21. package/dist/Select.js +183 -135
  22. package/dist/SelectList.js +59 -14
  23. package/dist/ThemeSelect.js +55 -4
  24. package/dist/apps.d.ts +1 -0
  25. package/dist/apps.js +50 -29
  26. package/dist/brand.js +251 -68
  27. package/dist/codemirror.js +116 -87
  28. package/dist/collections/CollectionGate.d.ts +52 -0
  29. package/dist/collections/CollectionGate.js +456 -0
  30. package/dist/collections/CollectionSaveWarning.d.ts +10 -0
  31. package/dist/collections/CollectionSaveWarning.js +28 -0
  32. package/dist/collections/CollectionSwitcher.d.ts +26 -0
  33. package/dist/collections/CollectionSwitcher.js +579 -0
  34. package/dist/collections/SetupReview.d.ts +9 -0
  35. package/dist/collections/SetupReview.js +175 -0
  36. package/dist/collections/copy.d.ts +100 -0
  37. package/dist/collections/copy.js +937 -0
  38. package/dist/collections/dialogs.d.ts +27 -0
  39. package/dist/collections/dialogs.js +169 -0
  40. package/dist/collections/model.d.ts +146 -0
  41. package/dist/collections/model.js +337 -0
  42. package/dist/collections/mount.d.ts +18 -0
  43. package/dist/collections/mount.js +56 -0
  44. package/dist/collections/parts.d.ts +86 -0
  45. package/dist/collections/parts.js +439 -0
  46. package/dist/collections/testing.d.ts +19 -0
  47. package/dist/collections/testing.js +39 -0
  48. package/dist/collections/use-collection-ui.d.ts +140 -0
  49. package/dist/collections/use-collection-ui.js +236 -0
  50. package/dist/collections.d.ts +19 -0
  51. package/dist/collections.js +13 -0
  52. package/dist/feedback-data.d.ts +13 -12
  53. package/dist/feedback-data.js +365 -168
  54. package/dist/flock.d.ts +63 -0
  55. package/dist/flock.js +140 -0
  56. package/dist/i18n.d.ts +6 -0
  57. package/dist/i18n.js +71 -0
  58. package/dist/locales/de/messages.json +1 -0
  59. package/dist/locales/en/messages.json +1 -0
  60. package/dist/locales/es/messages.json +1 -0
  61. package/dist/locales/fr/messages.json +1 -0
  62. package/dist/locales/it/messages.json +1 -0
  63. package/dist/locales/ja/messages.json +1 -0
  64. package/dist/locales/ko/messages.json +1 -0
  65. package/dist/locales/pt/messages.json +1 -0
  66. package/dist/locales/ru/messages.json +1 -0
  67. package/dist/locales/zh/messages.json +1 -0
  68. package/dist/mark-activity.js +82 -75
  69. package/dist/permission-selection.js +27 -17
  70. package/dist/popover.js +138 -130
  71. package/dist/screens.d.ts +20 -3
  72. package/dist/screens.js +275 -6
  73. package/dist/select-model.js +34 -28
  74. package/dist/text-diff.d.ts +1 -0
  75. package/dist/text-diff.js +106 -74
  76. package/dist/theme.js +34 -40
  77. package/package.json +53 -8
package/README.md CHANGED
@@ -36,6 +36,165 @@ applyThemePreference(loadThemePreference());
36
36
  collection in another app. Lab and local builds pass their own URLs to
37
37
  `withAppUrls`.
38
38
 
39
+ ## Languages
40
+
41
+ The `/i18n` entry exports `uiCatalogues: CatalogueSource` with synchronous
42
+ English and lazy local-deployment JSON for `fr de es ja ko pt ru zh`.
43
+ Compose it once with the app's catalogue using `@mdbase-dev/i18n`:
44
+
45
+ ```tsx
46
+ import { i18n, uiCatalogues } from "@mdbase-dev/ui/i18n";
47
+ const runtime = createI18nRuntime({ i18n, english: appEnglish, loadLocale, libraries: [uiCatalogues] });
48
+ // Wrap the app once in LocaleProvider with this runtime.
49
+ ```
50
+
51
+ Core-macro presentation helpers use the shared Lingui singleton; do not compose
52
+ into an unrelated isolated instance. Keep React and Lingui deduplicated in app
53
+ bundlers. No form is remounted on a locale switch. Build output includes all
54
+ ten catalogues and transformed macros; consumers do not compile library source.
55
+ PO files are the only authoring format. Builds use the kit CLI to prune obsolete PO
56
+ entries before compilation, including English fallback; `prepack` runs strict catalogue
57
+ checks and rebuilds so stale compiled messages cannot enter a fresh tarball.
58
+ Run strict `i18n:check` before release: a fallback-capable development build does
59
+ not prove a language is complete.
60
+ Reviewed identical terms are Esc/ID, the literal example email, and French
61
+ Collection/Collections (allowlisted per generated ID).
62
+
63
+ ## Command palette
64
+
65
+ `CommandPalette` from `@mdbase-dev/ui/command-palette` accepts an optional
66
+ `groupLabel(groupId: string): string` callback for localized group headings.
67
+ For example, pass `groupLabel={readerCommandGroupLabel}`. Without it, the heading
68
+ remains the command's `group` string. This is presentation only: keep `Command.group`
69
+ and `showAll` values as stable IDs. Group order, browsing limits and search matching
70
+ still use those IDs; translated headings do not change matching or merge groups.
71
+ Re-render with the current locale's callback to update the presentation.
72
+
73
+ ## Collections
74
+
75
+ Import `@mdbase-dev/ui/collections` and `@mdbase-dev/ui/collections.css`.
76
+ `tokens.css` is optional: without it every value falls back to a built-in one.
77
+ Every component takes the SDK front door from `createMdbase` (an optional peer
78
+ dependency) and `app: { name, mark? }`.
79
+
80
+ ```tsx
81
+ import { CollectionGate, CollectionSwitcher } from "@mdbase-dev/ui/collections";
82
+ import "@mdbase-dev/ui/collections.css";
83
+
84
+ <CollectionGate mdbase={mdbase} app={{ name: "Reader" }} extraActions={<TrySample />}>
85
+ {(connection) => <Shell header={<CollectionSwitcher mdbase={mdbase} app={app} />} />}
86
+ </CollectionGate>;
87
+ ```
88
+
89
+ - `CollectionGate` covers sign-in, choosing, approval, setup review and
90
+ problems, and renders its children once the phase is `ready`. A live problem
91
+ then shows as a banner above them. `layout="panel"` fits inside a shell or a
92
+ dialog.
93
+ - The gate calls `mdbase.start()` itself while the front door hasn't started
94
+ (`autoStart`, default `true`). It makes one call however many gates render,
95
+ and none once the app has started it, so apps can drop their own `start()`.
96
+ Pass `autoStart={false}` to start it yourself. `CollectionPanel` does the same.
97
+ - `extraActions` holds the app's own actions. On the signed-out screen they sit
98
+ beside Sign in. On every other gate screen they lead the footer, never under
99
+ a problem. Pass a function `(view) => node` to vary them by `view.kind`, or
100
+ return `null` to hide them.
101
+ - `CollectionSwitcher` (`variant` `full`, `compact` or `icon`) is the header
102
+ switcher: a popover, and a bottom sheet below 640px. `icon` puts the app's
103
+ icon before the name, or `icon="mark"` the open collection's initials. In
104
+ the `icon` variant it replaces the folder glyph.
105
+ - `rowDetail(row)` adds a second line to each collection row, such as where it
106
+ lives or which account it belongs to. `row.entry` is the SDK's entry.
107
+ - `sections` lists collections the app knows about and the SDK doesn't (local
108
+ or private ones). Each section is `{ id, title, items, onSelect, onClose?,
109
+ empty? }`, and each item is `{ id, name, detail?, current?, disabled? }`.
110
+ Sections appear after "Your collections" on the gate's choosing and
111
+ signed-out screens and in the switcher. Selecting an item asks
112
+ `onBeforeLeave("switch")` when something is open, closes any other open
113
+ item, then calls `onSelect` from the click. Mark the open item `current`.
114
+ The gate then renders `renderAppCollection(item, { section, chooseAnother })`
115
+ instead of its screens, and `chooseAnother()` (or "Choose a different
116
+ collection" in the switcher) calls `onClose` to return to the list. Choosing
117
+ an SDK collection also calls `onClose` first.
118
+ - A section item's `actions` fill its row menu, the same "…" menu SDK
119
+ collections have: `{ id, label, onSelect(item, context), danger?, disabled? }`.
120
+ `danger` actions show in the danger colour; confirm before acting.
121
+ `context.confirmDelete(onClose?)` opens `DeleteCollectionDialog` for the
122
+ item (the person types its name; the SDK deletes it by the item's `id`), and
123
+ `onClose(outcome)` reports how it ended:
124
+
125
+ ```tsx
126
+ actions: isOwner ? [{ id: "delete", label: "Delete collection…", danger: true,
127
+ onSelect: (_item, { confirmDelete }) => confirmDelete((outcome) => { if (outcome === "deleted") reload(); }) }] : []
128
+ ```
129
+ - `CollectionPanel` combines the gate screens with the switcher list, for
130
+ settings dialogs. `CollectionProblem` shows one problem with its fix, either
131
+ the current one or an error the app passes in.
132
+ - `onBeforeLeave(intent)` lets the app confirm before a switch, an add, choosing
133
+ another collection or signing out. Return `true` or a promise. The Connect
134
+ window opens straight after it, with no other await in between.
135
+ - `allowDelete` enables "Delete collection…" for owners. `copy` overrides
136
+ strings from `defaultCollectionCopy`. `DeleteCollectionDialog`'s
137
+ `onClose(outcome)` reports `"deleted"`, `"cancelled"` (closed without trying)
138
+ or `"failed"` (closed after a refused delete).
139
+ - `collectionView(snapshot)` is the headless model behind the components:
140
+ heading, rows and a notice with its control.
141
+ - Hosts that don't use React call
142
+ `mountCollectionUi(element, { part: "panel" | "switcher" | "problem", ...options })`,
143
+ which returns `{ update, unmount }`. React and react-dom must be installed.
144
+
145
+ ### Testing
146
+
147
+ The focus and popover code reads the global `window` and `document`, not the
148
+ rendered element's document. Test files that use a jsdom environment
149
+ (`// @vitest-environment jsdom`) already have them. A Node test that creates
150
+ its own window has to make it global before rendering:
151
+
152
+ ```ts
153
+ import { shareTestDocument } from "@mdbase-dev/ui/collections/testing";
154
+ import { JSDOM } from "jsdom";
155
+
156
+ const restore = shareTestDocument(new JSDOM("<!doctype html><body></body>").window);
157
+ afterAll(restore);
158
+ ```
159
+
160
+ ### Restyling
161
+
162
+ Map these properties anywhere up the tree (`:root` is fine) instead of
163
+ overriding internals. Each one falls back to the app-ui token, then to the
164
+ built-in value.
165
+
166
+ | Property (`--mdbase-collections-…`) | Used for | app-ui token | Built-in |
167
+ | --- | --- | --- | --- |
168
+ | `accent` | filled actions, focus, the current row | `--color-accent` | blue |
169
+ | `on-accent` | text on the accent | `--color-on-accent` | near white |
170
+ | `surface` | popovers, sheets, dialogs, rows | `--color-surface` | near white |
171
+ | `canvas` | the gate page background | `--color-canvas` | near white |
172
+ | `text` | primary text | `--color-text` | near black |
173
+ | `text-soft` | secondary text | `--color-text-soft` | grey |
174
+ | `border` | hairlines | `--color-border-strong` | light grey |
175
+ | `danger` | errors and destructive actions | `--color-danger` | red |
176
+ | `warning` | warning text | `--color-warning-text` | amber |
177
+ | `warning-edge` | the warning notice's edge | `--color-warning` | amber |
178
+ | `scrim` | behind dialogs and sheets | `--color-scrim` | `rgb(0 0 0 / 0.3)` |
179
+ | `current-bg` | the open collection's row | (none) | accent 9% into surface, mixed in oklab |
180
+ | `font` | font family | `--sans` | `system-ui, sans-serif` |
181
+ | `font-size` | body text | `--font-size-ui` | `0.8125rem` |
182
+ | `font-size-caption` | row details, chips, labels | `--font-size-caption` | `0.75rem` |
183
+ | `font-size-section` | leads, panel headings | `--font-size-section` | `0.9375rem` |
184
+ | `font-size-heading` | the gate heading | `--font-size-heading` | `1.5rem` |
185
+ | `font-weight-strong` | names, headings, buttons | `--font-weight-semibold` | `600` |
186
+ | `radius-sm` | rows, buttons, fields | `--radius-sm` | `4px` |
187
+ | `radius` | lists and cards | `--radius-md` | `8px` |
188
+ | `radius-lg` | popovers, dialogs, sheets | `--radius-lg` | `12px` |
189
+ | `elevation-low` | menus | `--elevation-low` | soft shadow |
190
+ | `elevation-high` | popovers and dialogs | `--elevation-high` | deeper shadow |
191
+ | `control-height` | button and row height | (none) | `36px`, `44px` on touch |
192
+
193
+ Motion reads `--ease-standard`, `--motion-quick` and `--motion-spin`
194
+ (`150ms` and `700ms` built in), and reduced motion slows the spinner. The
195
+ built-in colours are light-theme values: an app with a dark theme and no
196
+ `tokens.css` maps the colour properties.
197
+
39
198
  ## Shared feedback
40
199
 
41
200
  Import `@mdbase-dev/ui/feedback` and `@mdbase-dev/ui/feedback.css`, alongside
package/css/brand.css CHANGED
@@ -38,7 +38,7 @@
38
38
  }
39
39
 
40
40
  .mdbase-mark .mdbase-mark-progress-fill {
41
- transition: width 240ms cubic-bezier(0.22, 1, 0.36, 1);
41
+ transition: width var(--motion-slow) var(--ease-out);
42
42
  }
43
43
 
44
44
  @media (prefers-reduced-motion: reduce) {
@@ -53,8 +53,8 @@
53
53
  gap: 8px;
54
54
  color: var(--color-text);
55
55
  font-family: var(--mono);
56
- font-size: 12px;
57
- font-weight: 500;
56
+ font-size: var(--font-size-caption);
57
+ font-weight: var(--font-weight-medium);
58
58
  line-height: 1;
59
59
  letter-spacing: -0.02em;
60
60
  }
@@ -72,19 +72,19 @@
72
72
  gap: 0.65ch;
73
73
  white-space: nowrap;
74
74
  transition:
75
- opacity 140ms cubic-bezier(0.22, 1, 0.36, 1),
76
- transform 140ms cubic-bezier(0.22, 1, 0.36, 1),
77
- display 140ms allow-discrete;
75
+ opacity var(--motion-quick) var(--ease-out),
76
+ transform var(--motion-quick) var(--ease-out),
77
+ display var(--motion-quick) allow-discrete;
78
78
  }
79
79
 
80
80
  .wordmark strong {
81
81
  display: inline-block;
82
82
  color: var(--color-text-muted);
83
- font-weight: 500;
83
+ font-weight: var(--font-weight-medium);
84
84
  transition:
85
- opacity 140ms cubic-bezier(0.22, 1, 0.36, 1),
86
- transform 140ms cubic-bezier(0.22, 1, 0.36, 1),
87
- display 140ms allow-discrete;
85
+ opacity var(--motion-quick) var(--ease-out),
86
+ transform var(--motion-quick) var(--ease-out),
87
+ display var(--motion-quick) allow-discrete;
88
88
  }
89
89
 
90
90
  @starting-style {