@synopackageland/ui 0.20.5 → 0.20.7

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 (47) hide show
  1. package/CHANGELOG.md +27 -3
  2. package/LICENSES/source-notices.md +110 -0
  3. package/README.md +1 -1
  4. package/dist/components/composite/file-picker/FilePicker.vue.d.ts +1 -0
  5. package/dist/components/composite/form/FormItem.vue.d.ts +1 -1
  6. package/dist/components/composite/record-panel/recordPanelWidth.d.ts +4 -25
  7. package/dist/components/primitives/context-menu/ContextMenu.vue.d.ts +2 -2
  8. package/dist/components/primitives/date-picker/DatePicker.vue.d.ts +1 -1
  9. package/dist/components/rich-text-editor/extensions.d.ts +2 -0
  10. package/dist/composables/collisionBoundary.d.ts +7 -1
  11. package/dist/composables/elementWidth.d.ts +8 -2
  12. package/dist/dnd/autoScroll.d.ts +3 -22
  13. package/dist/dnd/dragKit.d.ts +1 -1
  14. package/dist/grid/cells/number.d.ts +1 -1
  15. package/dist/grid/cells/types.d.ts +1 -1
  16. package/dist/grid/clipboard/tsv.d.ts +1 -2
  17. package/dist/grid/contracts.d.ts +1 -1
  18. package/dist/grid/focus/editor-style.d.ts +1 -1
  19. package/dist/grid/host/controller.d.ts +11 -11
  20. package/dist/grid/range/block.d.ts +1 -1
  21. package/dist/grid-core/auto-scroll.d.ts +7 -7
  22. package/dist/grid-core/column-resize.d.ts +1 -1
  23. package/dist/grid-core/config.d.ts +1 -1
  24. package/dist/grid-core/keys.d.ts +2 -2
  25. package/dist/grid-core/renderer/layout.d.ts +1 -1
  26. package/dist/grid-core/selection-controller.d.ts +2 -2
  27. package/dist/grid-core/theme.d.ts +5 -5
  28. package/dist/grid.js +13 -13
  29. package/dist/index.js +11215 -11172
  30. package/dist/interaction/ime.d.ts +3 -22
  31. package/dist/json-preview/preview.js +8655 -8622
  32. package/dist/lib/adaptiveLayout.d.ts +7 -0
  33. package/dist/lib/fieldWidth.d.ts +2 -2
  34. package/dist/reka-runtime.json +1 -1
  35. package/dist/rich-text.js +259 -255
  36. package/dist/theme.css +1 -1
  37. package/dist/themes/dsm7-embedded-theme.css +1 -1
  38. package/dist/themes/dsm7-embedded.css +1 -1
  39. package/dist/themes/dsm7.css +1 -1
  40. package/docs/layout-rules.md +1 -1
  41. package/docs/mobile-native.md +2 -2
  42. package/docs/ux-grid.md +6 -8
  43. package/package.json +1 -89
  44. package/LICENSES/ux-foundation.md +0 -83
  45. package/LICENSES/ux-grid-baserow.md +0 -35
  46. package/LICENSES/ux-grid-teable.md +0 -48
  47. package/docs/ux-foundation.md +0 -133
@@ -28,7 +28,7 @@ These rules keep pages built from `@synopackageland/ui` consistent. The componen
28
28
 
29
29
  - Labels sit above their controls (`Form direction="vertical"`), except in short DSM-style dialogs and in side sheets (drawers).
30
30
  - In a dialog or a side `Sheet`, keep the default `direction="auto"`: as in DSM, the labels sit in a left column whenever the form is at least 400px wide (a 420–480px sheet) and stack above their controls only below that (a phone). Size the column with `Form label-width` (about 120px for short labels); a long label wraps inside it and stays level with its control's first line, whether that is a field, a select, a switch, a toggle group or a segment control.
31
- - Size a field by its content: number fields are 128px; text fields use `fieldWidth`. Put two short fields side by side rather than stretching one across the page.
31
+ - Size a field by its content: number fields are 128px; text fields use `fieldWidth`; in a narrow row that stacks its label (a phone), `md` and `lg` fill the column. Put two short fields side by side rather than stretching one across the page.
32
32
  - A checkbox's text sits on the same line as its box. Do not apply `display: grid` to `label` in App CSS; `Checkbox` renders its own label.
33
33
  - For 2–4 mutually exclusive settings, use `RadioGroup` (vertical by default, `orientation="horizontal"` when labels fit). In a wizard step, `variant="card"` draws the options as choice cards with an optional `icon` each. A checkbox enables an independent option; a switch turns a feature on or off immediately. Keep the circular radio with a dot, square checkbox with a tick, and pill switch with a moving thumb.
34
34
  - Reserve `SegmentControl` for toolbar view switching: its selected item is a primary-filled capsule. `variant="sheet"` and `SectionTabs` are navigation tabs. Do not use either as a form value selector.
@@ -469,8 +469,8 @@ unchanged.
469
469
 
470
470
  **DataGrid and DataTable.** `mobile-view="auto"` (the default) shows a list
471
471
  instead of the table. Each row is at least `--ui-list-row-height` (48px on a
472
- phone): the title column on the first line, up to two columns joined with `·`
473
- on the second, and trailing columns at the end. Columns place themselves with
472
+ phone): the title column on the first line, up to two columns on the second
473
+ with a small gap between them, and trailing columns at the end. Columns place themselves with
474
474
  `list`:
475
475
 
476
476
  | `list` | Place |
package/docs/ux-grid.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Grid range, fill and clipboard
2
2
 
3
- `@synopackageland/ui/grid` draws a canvas grid (a Vue port of Teable's MIT
4
- grid core) and owns geometry, scroll, selection, focus and pointer feedback.
3
+ `@synopackageland/ui/grid` draws a canvas grid on `src/grid-core` and owns
4
+ geometry, scroll, selection, focus and pointer feedback.
5
5
  It never writes data. Every change a user asks for (an edit, a clear, a fill,
6
6
  a paste, a reorder, a width) comes out as an event; the caller applies it to
7
7
  its row model as one undoable change and saves in the background.
@@ -124,8 +124,7 @@ from text the caller read itself.
124
124
 
125
125
  ## Touch and phone
126
126
 
127
- Interaction-spec §14, adapted to Teable's touch grid. Two switches, kept
128
- apart:
127
+ Interaction-spec §14, adapted for touch. Two switches, kept apart:
129
128
 
130
129
  - **Touch UI**: `(pointer: coarse)`. No fill handle and no column resize
131
130
  handle are drawn or hit (a 5 px edge is no finger target).
@@ -162,7 +161,7 @@ Android's own long-press `contextmenu`, are ignored for 800 ms after a finger.
162
161
  - The gutter is 50 px with row numbers only: `rowControls` are not drawn and
163
162
  not hit; a row-header tap opens the record.
164
163
  - Wider screens, touch or not, cap frozen columns so the scrolling part keeps
165
- at least 240 px (Teable's `getMaxFreezeColumnCount`).
164
+ at least 240 px.
166
165
  - Row and header height follow the density tokens: the DSM 7 theme gives
167
166
  36 px on a coarse pointer unless the app sets `data-ui-density`.
168
167
  - The grid draws no append row; the host offers its own add button.
@@ -209,9 +208,8 @@ Before a release that changes `@synopackageland/ui/grid`:
209
208
  the record, a tablet second tap does not edit, a finger edit keeps focus,
210
209
  or a long press does not open exactly one context menu.
211
210
  5. `node scripts/check-package-content.mjs`: `dist/grid.js` imports only
212
- `vue` and `./index.js` and keeps the Teable notice.
213
- 6. Notices: `LICENSES/ux-grid-teable.md` and `LICENSES/ux-grid-baserow.md`
214
- ship in the package.
211
+ `vue` and `./index.js` and keeps the MIT notice.
212
+ 6. Notices: `LICENSES/source-notices.md` ships in the package.
215
213
  7. Manual, not covered headless: IME first character in Safari, native
216
214
  macOS Cmd+C/X/V into Excel, Numbers and Google Sheets, and on a real
217
215
  iPhone that a second tap brings up the keyboard and Return puts it away.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synopackageland/ui",
3
- "version": "0.20.5",
3
+ "version": "0.20.7",
4
4
  "description": "Shared Vue 3 UI component library with a DSM 7 inspired application theme",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -26,7 +26,6 @@
26
26
  "docs/release-checks.md",
27
27
  "docs/size-and-split.md",
28
28
  "docs/theme-hooks.md",
29
- "docs/ux-foundation.md",
30
29
  "docs/ux-grid.md",
31
30
  "docs/wizard.md"
32
31
  ],
@@ -61,58 +60,6 @@
61
60
  "./themes/dsm7-embedded-reset.css": "./dist/themes/dsm7-embedded-reset.css",
62
61
  "./themes/dsm7-embedded-theme.css": "./dist/themes/dsm7-embedded-theme.css"
63
62
  },
64
- "scripts": {
65
- "check:docs": "node --test scripts/check-doc-versions.test.mjs && node scripts/check-doc-versions.mjs",
66
- "dev": "vite build --watch",
67
- "build": "vite build && vite build --mode json && vite build --mode rich-text && vite build --mode grid && vite build --mode cli && vite build --mode preview && vite build --mode embedded && node scripts/postbuild.mjs",
68
- "lint": "eslint .",
69
- "typecheck": "vue-tsc --noEmit -p tsconfig.json",
70
- "test": "vitest run",
71
- "test:watch": "vitest",
72
- "test:changed": "echo \"test:changed skips the tests the changes since ${SYNOPKGLAND_GATE_BASE:-origin/master} do not reach (vitest --changed); pnpm check runs them all\" && vitest run --changed ${SYNOPKGLAND_GATE_BASE:-origin/master}",
73
- "story": "histoire dev",
74
- "story:build": "histoire build",
75
- "check:host": "node scripts/dsm-host-shots.mjs",
76
- "check:switch": "node scripts/check-switch.mjs",
77
- "check:tabs": "node scripts/check-tabs.mjs",
78
- "check:mobile": "node scripts/check-mobile-overflow.mjs",
79
- "check:narrow": "node scripts/check-narrow-controls.mjs",
80
- "check:drawer-form": "node scripts/check-drawer-form.mjs",
81
- "check:responsive": "node scripts/check-responsive.mjs",
82
- "check:adaptive": "node scripts/check-adaptive.mjs",
83
- "check:sidebar-focus": "node scripts/check-sidebar-focus.mjs",
84
- "check:json-render": "node scripts/check-json-render.mjs",
85
- "check:motion": "node scripts/check-motion.mjs",
86
- "check:topology": "node scripts/check-topology.mjs",
87
- "check:wizard": "node scripts/check-wizard.mjs",
88
- "check:edges": "node scripts/check-edges.mjs",
89
- "check:data-grid": "node scripts/check-data-grid.mjs",
90
- "check:truncation": "node scripts/check-truncation.mjs",
91
- "check:link": "node scripts/check-link.mjs",
92
- "check:text-select": "node scripts/check-text-select.mjs",
93
- "check:date-picker": "node scripts/check-date-picker.mjs",
94
- "check:full-page": "node scripts/check-full-page.mjs",
95
- "check:detail-surface": "node scripts/check-detail-surface.mjs",
96
- "check:internal": "node --test scripts/check-internal-content.test.mjs scripts/check-npm-metadata.test.mjs && node scripts/check-internal-content.mjs --repo .",
97
- "check:npm-metadata": "node scripts/check-npm-metadata.mjs",
98
- "check:package": "node scripts/check-package-content.mjs",
99
- "check:ux-foundation-consumer": "node scripts/check-ux-foundation-consumer.mjs",
100
- "notices:update": "node scripts/third-party-notices.mjs --write",
101
- "notices:check": "node scripts/third-party-notices.mjs --check",
102
- "check": "bash scripts/docker-check.sh \"npm run gates\"",
103
- "check:fast": "bash scripts/docker-check.sh \"npm run gates\"",
104
- "check:local-browser": "node scripts/app-local-browser.mjs",
105
- "check:infotip": "node scripts/check-infotip.mjs",
106
- "release:stage": "node scripts/stage-release.mjs",
107
- "check:polish": "bash scripts/docker-check.sh --build --out .polish-shots 'node scripts/check-polish.mjs'",
108
- "check:acceptance": "node scripts/check-acceptance.mjs",
109
- "check:palette": "node scripts/check-palette.mjs",
110
- "gates": "node scripts/gates.mjs",
111
- "gates:full": "node scripts/gates.mjs --full",
112
- "check:layout": "node scripts/check-layout.mjs",
113
- "release:smoke": "node scripts/release-smoke.mjs",
114
- "check:browser-install": "playwright install chromium"
115
- },
116
63
  "peerDependencies": {
117
64
  "vue": "^3.5.0"
118
65
  },
@@ -132,44 +79,9 @@
132
79
  "@tiptap/vue-3": "3.32.1",
133
80
  "zod": "^4.6.5"
134
81
  },
135
- "devDependencies": {
136
- "@eslint/js": "10.0.1",
137
- "@histoire/plugin-vue": "1.0.0-beta.1",
138
- "@tailwindcss/vite": "4.3.3",
139
- "@tanstack/vue-virtual": "3.13.39",
140
- "@vitejs/plugin-vue": "6.0.9",
141
- "@vue/test-utils": "2.5.1",
142
- "@vueuse/core": "14.4.0",
143
- "eslint": "10.11.0",
144
- "eslint-plugin-vue": "10.11.1",
145
- "flexsearch": "0.8.212",
146
- "globals": "17.12.0",
147
- "histoire": "1.0.0-beta.1",
148
- "jsdom": "30.1.1",
149
- "playwright": "1.58.2",
150
- "reka-ui": "2.11.0",
151
- "tailwindcss": "4.3.3",
152
- "typescript": "5.9.3",
153
- "typescript-eslint": "8.71.0",
154
- "vite": "7.3.6",
155
- "vite-plugin-dts": "5.1.1",
156
- "vitest": "5.0.2",
157
- "vscode-oniguruma": "2.0.1",
158
- "vscode-textmate": "9.3.2",
159
- "vue": "3.5.43",
160
- "vue-eslint-parser": "10.4.1",
161
- "vue-tsc": "3.3.11"
162
- },
163
82
  "engines": {
164
83
  "node": ">=20"
165
84
  },
166
- "packageManager": "pnpm@10.33.2",
167
- "pnpm": {
168
- "onlyBuiltDependencies": [
169
- "esbuild",
170
- "vue-demi"
171
- ]
172
- },
173
85
  "config": {
174
86
  "bundledRuntime": {
175
87
  "@tanstack/vue-virtual": "3.13.39",
@@ -1,83 +0,0 @@
1
- # @synopackageland/ui UX foundation: third-party notices
2
-
3
- `dist/index.js` contains small ports of MIT-licensed code from Teable and
4
- Baserow in the interaction core, drag kit, panels and virtual cards. Each
5
- ported source file keeps the notice below in its header; the built file drops
6
- those comments and starts with a one-line notice pointing here instead. The
7
- canvas grid in `dist/grid.js` has its own notices in
8
- [ux-grid-teable.md](ux-grid-teable.md) and [ux-grid-baserow.md](ux-grid-baserow.md).
9
-
10
- Nothing is taken from Teable `apps/*` (AGPL-3.0), Baserow `premium/` or
11
- `enterprise/` (proprietary) or NocoDB (Sustainable Use License); where those
12
- projects informed a behaviour, only the technique was used. No Teable or
13
- Baserow name, logo or icon asset is shipped.
14
-
15
- ## Ported files
16
-
17
- | Source file in this package | Ported from | Upstream commit |
18
- | --- | --- | --- |
19
- | `src/interaction/ime.ts` (`isPrintableKey`) | Teable `packages/sdk/src/components/grid/utils/hotkey.ts` | `f8be01fad` |
20
- | `src/interaction/gesture.ts` (5px threshold, half-item drop rule) | Teable `packages/sdk/src/components/grid/hooks/useDrag.ts:8-119` | `f8be01fad` |
21
- | `src/components/primitives/popover/overlay.ts` (`skipAutoFocusOnTouch`) | Teable `packages/ui-lib/src/shadcn/ui/popover.tsx:30-45` | `f8be01fad` |
22
- | `src/components/composite/record-panel/recordPanelWidth.ts` (width rule) | Teable `packages/sdk/src/components/expand-record/Panel.tsx:20-26, 83-88` | `f8be01fad` |
23
- | `src/components/composite/record-panel/RecordPanel.vue` (sash, clip layer, drag-to-width) | Teable `packages/sdk/src/components/expand-record/Panel.tsx:100-171`, `packages/ui-lib/src/base/resize-handle/ResizeHandleBar.tsx:1-35` | `f8be01fad` |
24
- | `src/interaction/outside.ts` (outside-press snapshot and ignore list) | Baserow `web-frontend/modules/core/utils/dom.js` `onClickOutside` | `98f727dc2` |
25
- | `src/dnd/dragKit.ts` (buffered-rows drag and drop, 100ms swap lock) | Baserow `web-frontend/modules/database/mixins/bufferedRowsDragAndDrop.js:64-235`, `store/view/bufferedRows.js` | `98f727dc2` |
26
- | `src/dnd/autoScroll.ts` (edge zone and speed ramp) | Baserow `web-frontend/modules/core/directives/autoScroll.js:30-99` | `98f727dc2` |
27
- | `src/virtual/cardHeight.ts` (`cardHeight`) | Baserow `web-frontend/modules/database/utils/card.js:1-24` | `aa2402b7c716c3eadc5a382af3e880756e026d9c` |
28
-
29
- ## Teable licence
30
-
31
- Teable `packages/*` is MIT licensed.
32
-
33
- ```text
34
- MIT License
35
-
36
- Copyright (c) 2023-2025 Teable, Inc.
37
-
38
- Permission is hereby granted, free of charge, to any person obtaining a copy
39
- of this software and associated documentation files (the "Software"), to deal
40
- in the Software without restriction, including without limitation the rights
41
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42
- copies of the Software, and to permit persons to whom the Software is
43
- furnished to do so, subject to the following conditions:
44
-
45
- The above copyright notice and this permission notice shall be included in all
46
- copies or substantial portions of the Software.
47
-
48
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
51
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
52
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
53
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
54
- SOFTWARE.
55
- ```
56
-
57
- ## Baserow licence
58
-
59
- Baserow Open Source Edition (outside `premium/` and `enterprise/`) is MIT
60
- (Expat) licensed.
61
-
62
- ```text
63
- MIT License
64
-
65
- Copyright (c) 2019-present Baserow B.V.
66
-
67
- Permission is hereby granted, free of charge, to any person obtaining a copy of this
68
- software and associated documentation files (the "Software"), to deal in the Software
69
- without restriction, including without limitation the rights to use, copy, modify,
70
- merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
71
- permit persons to whom the Software is furnished to do so, subject to the following
72
- conditions:
73
-
74
- The above copyright notice and this permission notice shall be included in all copies
75
- or substantial portions of the Software.
76
-
77
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
78
- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
79
- PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
80
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
81
- CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
82
- OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
83
- ```
@@ -1,35 +0,0 @@
1
- # @synopackageland/ui/grid: Baserow notice
2
-
3
- `dist/grid.js` (source `src/grid/clipboard/write.ts`, `writeClipboardAsync`)
4
- contains a TypeScript port of `copySelectionToClipboard` and
5
- `writeToClipboard` from Baserow's
6
- `web-frontend/modules/database/mixins/copyPasteHelper.js:147-218` (commit
7
- `98f727dc2ed8140fe44e3e797eedb05339562659`). The HTML-table rule in
8
- `src/grid/clipboard/tsv.ts` (`toHtmlTable`: no table for a single cell) follows
9
- `prepareHTMLData` in the same file. Baserow licenses all client-side
10
- JavaScript, including that file, under the MIT (Expat) licence below. Nothing
11
- from Baserow's `premium/` or `enterprise/` directories is included, and no
12
- Baserow name, logo or other asset is shipped.
13
-
14
- ## Baserow licence
15
-
16
- ```text
17
- Copyright (c) 2019-present Baserow B.V.
18
-
19
- Permission is hereby granted, free of charge, to any person obtaining a copy of this
20
- software and associated documentation files (the "Software"), to deal in the Software
21
- without restriction, including without limitation the rights to use, copy, modify,
22
- merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
23
- permit persons to whom the Software is furnished to do so, subject to the following
24
- conditions:
25
-
26
- The above copyright notice and this permission notice shall be included in all copies
27
- or substantial portions of the Software.
28
-
29
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
30
- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
31
- PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
32
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
33
- CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
34
- OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
- ```
@@ -1,48 +0,0 @@
1
- # @synopackageland/ui/grid: third-party notice
2
-
3
- `dist/grid.js` (source `src/grid/` and `src/grid-core/`) contains a TypeScript
4
- port, without React, of the canvas grid in Teable's SDK package
5
- (`packages/sdk/src/components/grid/`, commit
6
- `f8be01fadb86790d3d3a878bedd10cf949f9a8f8`, 2026-11-03). That package is MIT
7
- licensed (`packages/sdk/LICENSE` and `"license": "MIT"` in
8
- `packages/sdk/package.json` at that commit). Nothing from Teable's `apps/*`
9
- (AGPL-3.0) is included, and no Teable name, logo or icon asset is shipped.
10
-
11
- The Vue host in `src/grid/host/` is new code that follows the coordinate set-up
12
- in `Grid.tsx` and the pointer flow of `InteractionLayer.tsx`; it calls the
13
- ported modules and copies no React code. Default theme colours that fill
14
- missing tokens are Tailwind CSS palette values (MIT, Copyright (c) Tailwind
15
- Labs, Inc.), as Teable uses them.
16
-
17
- The fill-handle gesture in `src/grid/host/controller.ts` and `src/grid/range/`
18
- follows the fill flow of `InteractionLayer.tsx` (preview over the target rows,
19
- selection grows on release). The fill value rules, the clipboard TSV
20
- parser/writer and the paste proposal are new code; Teable's fill and
21
- copy/paste rules live in AGPL `apps/*` code and were not copied. The async
22
- clipboard write is ported from Baserow (MIT); see `ux-grid-baserow.md`.
23
-
24
- ## Teable licence
25
-
26
- ```text
27
- MIT License
28
-
29
- Copyright (c) 2023-2025 Teable, Inc.
30
-
31
- Permission is hereby granted, free of charge, to any person obtaining a copy
32
- of this software and associated documentation files (the "Software"), to deal
33
- in the Software without restriction, including without limitation the rights
34
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
35
- copies of the Software, and to permit persons to whom the Software is
36
- furnished to do so, subject to the following conditions:
37
-
38
- The above copyright notice and this permission notice shall be included in all
39
- copies or substantial portions of the Software.
40
-
41
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
47
- SOFTWARE.
48
- ```
@@ -1,133 +0,0 @@
1
- # UX foundation: public contract
2
-
3
- The building blocks for app views that settle once and do not move again:
4
- interaction core, drag kit, side regions and panels, virtual cards, feedback
5
- and motion. Everything here is imported from a package entry; an App never
6
- imports a source path.
7
-
8
- | Entry | What it holds | Load |
9
- | --- | --- | --- |
10
- | `@synopackageland/ui` | every name on this page except the grid | normally |
11
- | `@synopackageland/ui/grid` | `GridHost`, cell renderers, cell theme, save-status store | lazily, when a grid view first opens |
12
- | `@synopackageland/ui/theme.css` | tokens, chrome and motion | once, at startup |
13
-
14
- ```ts
15
- import {
16
- AsidePanel, RecordPanel, AdaptivePanel, StatusSlot, VirtualCardGrid, CardCover, CardField,
17
- cardHeight, createDragKit, useDragKit, registerOutsideLayer, createEditSession, motionMs,
18
- } from '@synopackageland/ui'
19
-
20
- const GridHost = defineAsyncComponent(() => import('@synopackageland/ui/grid').then(module => module.GridHost))
21
- ```
22
-
23
- A consumer fixture that type-checks and imports every name below from the
24
- packed tarball is in `tests/ux-foundation-consumer/`
25
- (`node scripts/check-ux-foundation-consumer.mjs`, after `pnpm build`).
26
-
27
- ## Defaults and opt-in
28
-
29
- Nothing here needs a flag. The compact chrome is the only density.
30
-
31
- | What | Default | Opt in or change |
32
- | --- | --- | --- |
33
- | Web chrome rows (page header, toolbar, sidebar head and footer) | 48px; window and phone keep 44px | none |
34
- | Chrome controls / header actions / web nav rows / icons | 28px / 32px / 32px / 16px; icon buttons 4px apart | `--ui-nav-row-height`, `--ui-icon-size` ([theme hooks](theme-hooks.md#layout-and-theme-tokens)) |
35
- | Full-page (`web`) presentation | off; DSM windows stay `window` at any width | `AppLayout wide-layout="web"`: from a 960px container, sidebar starts as the 48px rail below 1200px |
36
- | Font | system font stack in the `web` presentation | `--ui-font-sans` |
37
- | Right side region | none | put an `AsidePanel` in `AppLayout`'s `aside` slot; `v-model:aside`, `v-model:aside-width` |
38
- | Motion | on, with the tokens in [theme hooks](theme-hooks.md#motion) | `data-ui-motion="off"` on any ancestor; reduced motion reads every duration as 0ms |
39
- | Popup motion inside a grid editor | 150ms in, 100ms out | `provideOverlayMotion('none')` or `motion="none"` |
40
- | Canvas grid | not loaded | import `@synopackageland/ui/grid` |
41
-
42
- ## Copy and accessibility
43
-
44
- Built-in labels come from the library's nine locales (en, zh-TW, zh-CN, ja,
45
- ko, de, fr, es, it) and follow `AppRoot locale` (else its `lang`). Names that only the App
46
- knows are props, already translated: `AsidePanel title`, `RecordPanel label`,
47
- `AdaptivePanel title`, `VirtualCardGrid label`, `CardField label`,
48
- `CardCover alt`, `StatusSlot message`. Every built-in label can be replaced
49
- (`openLabel`, `collapseLabel`, `expandLabel`, `restoreLabel`, `closeLabel`,
50
- `resizeLabel`, `retryLabel`). No label ends with a period.
51
-
52
- ## Side regions and panels
53
-
54
- | Component | Use | Main props and events |
55
- | --- | --- | --- |
56
- | `AppLayout` `aside` slot | the right side region beside the page | `v-model:aside` (`open` / `collapsed` / `expanded`), `v-model:aside-width` (380, 320–560). The slot gets `{ state, overlay, width, presentation }`. An open aside that would leave the page under 480px floats over it; a phone has no region width |
57
- | `AsidePanel` | the region's content: 48px rail, docked panel, floating panel, phone sheet | `title`, `icon`, `unread`, `fab`, `expandable`, `initialFocus`, `shortcut`; slots `tabs`, `actions`, default. Never unmounted, so scroll and drafts survive a collapse |
58
- | `useAsidePreference(key, scope)` | the stored state and width, read before first paint | `readAsidePreference`, `writeAsidePreference`, `clampAsideWidth` |
59
- | `RecordPanel` | a non-modal record panel docked over the view; the view never changes width | `v-model:open`, `v-model:width`, `storageKey`, `secondaryOpen`, `container`, `compactBelow`, `returnFocus`, `initialFocus`, `flush`; `close(reason)`, `resizeEnd`; slots `header`, default, `secondary` |
60
- | `AdaptivePanel` | a popover in a wide host, a bottom sheet at 640px and narrower; the content is mounted once | `v-model:open`, `title`, `side`, `align`, `width`, `sheetSide`, `sheetSize`, `compactBelow`, `container`, `motion` |
61
-
62
- `APP_ASIDE_KEY` and `APP_SIDE_MOTION_KEY` are injection keys for content that
63
- must react to the region; `WEB_ASIDE_DEFAULT`, `WEB_ASIDE_MIN`,
64
- `WEB_ASIDE_MAX`, `WEB_RAIL_WIDTH`, `WEB_RAIL_BELOW`, `WEB_LAYOUT_MIN` and
65
- `MOBILE_LAYOUT_MAX` are the sizes.
66
-
67
- ## Feedback
68
-
69
- | Name | Contract |
70
- | --- | --- |
71
- | `SectionSkeleton` `variant="grid" \| "cards" \| "fields"` | the final geometry from the first frame; shapes show after 300ms |
72
- | `useToast()` | success 3s, info and warning 5s (at least 5s with an action), danger stays; `pending()` shows after 300ms and becomes its result through `update(id)` |
73
- | `StatusSlot` | a fixed box for `pending` / `saved` / `error` (with Retry); empty while idle, so nothing moves |
74
- | `useShowAfter(active, { delay })` | true only once `active` has held for the delay (300ms, `PENDING_DELAY_MS`) |
75
- | `TOAST_DURATION_MS` | the toast durations by tone |
76
-
77
- ## Virtual cards
78
-
79
- `VirtualCardGrid` renders only the rows on screen. Every card has the height
80
- `cardHeight({ fields, cover, title })` returns, so nothing is measured, and
81
- the column count (`galleryColumns(width)`, breakpoints `GALLERY_BREAKPOINTS`)
82
- is known before the first card renders. The grid emits `range(start, end)` for
83
- the window to load; an unloaded card is a placeholder of the same size. Put
84
- `CardCover` in the `cover` slot and `CardField` rows in the body, with the same
85
- value heights you passed to `cardHeight` (`CARD_VALUE_HEIGHT`, `CARD_METRICS`).
86
-
87
- While a side region changes width, the column count holds and settles once at
88
- the end. `AppLayout` drives this for its sidebar and aside. Anything else that
89
- moves the width of the main area on purpose calls `useLayoutMotion().track(el)`
90
- right after it changes the width, or `begin()` and the returned end; a layout
91
- that only moves its own region gives its children `provideLayoutMotion()`.
92
-
93
- ## Interaction core
94
-
95
- | Name | Contract |
96
- | --- | --- |
97
- | `registerOutsideLayer` / `useOutsideLayer` | one window-capture listener; layers are walked from the top, everything above the pressed layer gets `onOutside` once; `'veto'` blocks the press and its click; Escape goes to the topmost layer only |
98
- | `IGNORE_OUTSIDE_ATTR` (`data-ui-ignore-outside`) | put it on every portal root that belongs to an interactive surface |
99
- | `createCompositionGuard`, `isComposingKey`, `isPrintableKey` | Enter, Escape and Tab belong to an IME while it composes and for 50ms after (`COMPOSITION_END_GRACE_MS`) |
100
- | `focusSync`, `createFocusOwner`, `isInForeignDialog` | focus synchronously in the input handler, never out of a dialog the surface does not own |
101
- | `trackPointerGesture` / `usePointerGesture`, `dropIndexAt` | 5px threshold (`DRAG_THRESHOLD_PX`), pointer capture, release on cancel, blur or dispose |
102
- | `createEditSession` / `useEditSession`, `editSessionOutside` | `start` / `setDraft` / `setComposing` / `commit` / `cancel`; a validation veto keeps the editor; a commit waits for the composition to end |
103
-
104
- ## Drag kit
105
-
106
- `createDragKit` (Vue: `useDragKit`) runs one drag across registered lanes:
107
- 5px mouse threshold, 250ms touch hold (`TOUCH_HOLD_MS`), Space and arrow keys,
108
- edge auto-scroll, Escape rollback. Register a lane with
109
- `kit.lane({ id, element, count, layout })`: give a virtual lane a fixed
110
- `dragListGeometry` or `dragGridGeometry`; a rendered lane can use
111
- `dragMeasuredGeometry`. Spread `kit.item(lane, index, key)` on each item.
112
- `onDrop({ key, from, to })` runs in the release frame: change the local data
113
- there and return the server write's promise; a rejection calls `onRestore` and
114
- the item slides home. The geometry types are exported as `DragRect`,
115
- `DragAxis`, `DragArrangement`, `DragLaneGeometry` and `DragLaneLayout`.
116
- `createAutoScroll` and `edgeSpeed` give the same edge scrolling to other
117
- surfaces.
118
-
119
- ## Motion helpers
120
-
121
- `motionMs(token, el?)` reads a duration token (`MotionToken`) as it resolves
122
- on `el`, 0 when motion is off for it (`motionOff`, `MOTION_OFF_SELECTOR`).
123
- `transitionMs(el)` is the longest transition on an element.
124
- `useSwapMotion(target, source)` plays the switched-content rise-in when
125
- `source` changes; `useInsertedKeys(keys, options)` returns the keys of rows
126
- that were just added, so only those animate in.
127
-
128
- ## Third-party code
129
-
130
- Parts of this foundation are ports of MIT code from Teable and Baserow. The
131
- notices are kept in each ported file and collected in
132
- `LICENSES/ux-foundation.md`; the grid entry's notices are
133
- `LICENSES/ux-grid-teable.md` and `LICENSES/ux-grid-baserow.md`; its contract is [ux-grid](ux-grid.md).