@synopackageland/ui 0.20.3 → 0.20.5
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 +35 -0
- package/LICENSES/THIRD_PARTY.md +2 -32
- package/LICENSES/ux-foundation.md +83 -0
- package/LICENSES/ux-grid-baserow.md +35 -0
- package/LICENSES/ux-grid-teable.md +48 -0
- package/README.md +3 -0
- package/dist/components/app/app-layout/AppLayout.vue.d.ts +52 -5
- package/dist/components/app/app-layout/pageTitle.d.ts +24 -0
- package/dist/components/app/app-root/AppRoot.vue.d.ts +9 -0
- package/dist/components/app/app-tab-bar/AppTabBar.vue.d.ts +1 -1
- package/dist/components/app/aside-panel/AsidePanel.vue.d.ts +69 -0
- package/dist/components/app/aside-panel/asidePreference.d.ts +28 -0
- package/dist/components/app/section-tabs/SectionTabs.vue.d.ts +22 -4
- package/dist/components/composite/about-dialog/AboutDialog.vue.d.ts +1 -1
- package/dist/components/composite/adaptive-panel/AdaptivePanel.vue.d.ts +61 -0
- package/dist/components/composite/connection-topology/ConnectionTopology.vue.d.ts +1 -1
- package/dist/components/composite/data-grid/DataGrid.vue.d.ts +19 -1
- package/dist/components/composite/data-grid/labels.d.ts +15 -0
- package/dist/components/composite/data-grid/listLayout.d.ts +26 -0
- package/dist/components/composite/data-table/DataTable.vue.d.ts +33 -7
- package/dist/components/composite/file-picker/FilePicker.vue.d.ts +2 -2
- package/dist/components/composite/form/FormGroup.vue.d.ts +1 -1
- package/dist/components/composite/form/context.d.ts +13 -0
- package/dist/components/composite/form-actions/FormActions.vue.d.ts +6 -2
- package/dist/components/composite/mention-list/MentionList.vue.d.ts +2 -2
- package/dist/components/composite/overflow-toolbar/OverflowToolbar.vue.d.ts +2 -2
- package/dist/components/composite/record-panel/RecordPanel.vue.d.ts +91 -0
- package/dist/components/composite/record-panel/recordPanelWidth.d.ts +54 -0
- package/dist/components/composite/settings-section/SettingsSection.vue.d.ts +1 -1
- package/dist/components/composite/summary-card/SummaryCard.vue.d.ts +1 -1
- package/dist/components/composite/tag-editor/TagEditor.vue.d.ts +4 -4
- package/dist/components/composite/tree-view/TreeView.vue.d.ts +4 -4
- package/dist/components/composite/wizard/Wizard.vue.d.ts +2 -2
- package/dist/components/composite/wizard/WizardDialog.vue.d.ts +4 -4
- package/dist/components/containers/card/Card.vue.d.ts +1 -1
- package/dist/components/containers/card/CardField.vue.d.ts +26 -0
- package/dist/components/containers/card-grid/CardCover.vue.d.ts +16 -0
- package/dist/components/containers/card-grid/CardGrid.vue.d.ts +1 -1
- package/dist/components/containers/card-grid/VirtualCardGrid.vue.d.ts +71 -0
- package/dist/components/containers/expandable-item/ExpandableItem.vue.d.ts +1 -1
- package/dist/components/containers/fieldset/Fieldset.vue.d.ts +1 -1
- package/dist/components/containers/list-detail/ListDetail.vue.d.ts +6 -4
- package/dist/components/containers/split-pane/SplitPane.vue.d.ts +1 -1
- package/dist/components/feedback/notification/Notification.vue.d.ts +1 -1
- package/dist/components/feedback/notification/NotificationProvider.vue.d.ts +1 -1
- package/dist/components/feedback/validation-popup/ValidationPopup.vue.d.ts +1 -1
- package/dist/components/primitives/breadcrumb/Breadcrumb.vue.d.ts +2 -2
- package/dist/components/primitives/color-picker/ColorPicker.vue.d.ts +4 -4
- package/dist/components/primitives/combobox/Combobox.vue.d.ts +4 -4
- package/dist/components/primitives/context-menu/ContextMenu.vue.d.ts +5 -2
- package/dist/components/primitives/context-menu/ContextMenuItems.vue.d.ts +4 -5
- package/dist/components/primitives/dialog/Dialog.vue.d.ts +16 -8
- package/dist/components/primitives/dropdown-menu/DropdownMenu.vue.d.ts +7 -3
- package/dist/components/primitives/dropdown-menu/DropdownMenuItems.vue.d.ts +6 -3
- package/dist/components/primitives/dropdown-menu/DropdownMenuSheet.vue.d.ts +28 -0
- package/dist/components/primitives/input/Input.vue.d.ts +8 -1
- package/dist/components/primitives/input/Textarea.vue.d.ts +1 -1
- package/dist/components/primitives/input-steppers/InputSteppers.vue.d.ts +1 -1
- package/dist/components/primitives/motion/PushTransition.vue.d.ts +38 -0
- package/dist/components/primitives/multiple-select/MultipleSelect.vue.d.ts +4 -4
- package/dist/components/primitives/pagination/Pagination.vue.d.ts +22 -9
- package/dist/components/primitives/pagination/PaginationSheet.vue.d.ts +27 -0
- package/dist/components/primitives/pagination/labels.d.ts +6 -0
- package/dist/components/primitives/popover/Popover.vue.d.ts +11 -3
- package/dist/components/primitives/popover/floating.d.ts +27 -0
- package/dist/components/primitives/popover/overlay.d.ts +36 -0
- package/dist/components/primitives/segment-control/SegmentControl.vue.d.ts +4 -1
- package/dist/components/primitives/segment-control/context.d.ts +3 -0
- package/dist/components/primitives/select/Select.vue.d.ts +4 -0
- package/dist/components/primitives/select/internal/ComboboxField.vue.d.ts +6 -5
- package/dist/components/primitives/select/internal/SelectSheet.vue.d.ts +42 -0
- package/dist/components/primitives/select/internal/types.d.ts +2 -0
- package/dist/components/primitives/sheet/BottomSheet.vue.d.ts +69 -0
- package/dist/components/primitives/sheet/Sheet.vue.d.ts +13 -5
- package/dist/components/primitives/sheet/phone.d.ts +7 -0
- package/dist/components/primitives/skeleton/SectionSkeleton.vue.d.ts +25 -4
- package/dist/components/primitives/skeleton/Skeleton.vue.d.ts +3 -0
- package/dist/components/primitives/superbox-select/SuperboxSelect.vue.d.ts +4 -4
- package/dist/components/primitives/tag/Tag.vue.d.ts +2 -2
- package/dist/components/primitives/toast/ToastProvider.vue.d.ts +0 -2
- package/dist/components/primitives/toast/toast.d.ts +21 -1
- package/dist/components/primitives/tooltip/Tooltip.vue.d.ts +8 -3
- package/dist/components/primitives/tooltip/tooltipStyle.d.ts +11 -1
- package/dist/components/rich-text-editor/RichTextEditor.vue.d.ts +1 -1
- package/dist/composables/backDismiss.d.ts +19 -0
- package/dist/composables/formControl.d.ts +18 -0
- package/dist/composables/phone.d.ts +8 -0
- package/dist/composables/phoneSurface.d.ts +35 -0
- package/dist/composables/softKeyboard.d.ts +26 -4
- package/dist/composables/visualViewport.d.ts +31 -0
- package/dist/dnd/autoScroll.d.ts +57 -0
- package/dist/dnd/dragKit.d.ts +111 -0
- package/dist/dnd/index.d.ts +4 -0
- package/dist/dnd/layout.d.ts +57 -0
- package/dist/dnd/vue.d.ts +16 -0
- package/dist/feedback/StatusSlot.vue.d.ts +24 -0
- package/dist/feedback/showAfter.d.ts +15 -0
- package/dist/feedback/stackMotion.d.ts +13 -0
- package/dist/feedback/timing.d.ts +23 -0
- package/dist/grid/cells/draw.d.ts +57 -0
- package/dist/grid/cells/images.d.ts +5 -0
- package/dist/grid/cells/index.d.ts +7 -0
- package/dist/grid/cells/number.d.ts +5 -0
- package/dist/grid/cells/registry.d.ts +56 -0
- package/dist/grid/cells/renderers.d.ts +8 -0
- package/dist/grid/cells/status.d.ts +6 -0
- package/dist/grid/cells/types.d.ts +200 -0
- package/dist/grid/cells/use.d.ts +7 -0
- package/dist/grid/clipboard/copy.d.ts +17 -0
- package/dist/grid/clipboard/index.d.ts +4 -0
- package/dist/grid/clipboard/proposal.d.ts +35 -0
- package/dist/grid/clipboard/tsv.d.ts +14 -0
- package/dist/grid/clipboard/write.d.ts +21 -0
- package/dist/grid/contracts.d.ts +200 -0
- package/dist/grid/edit/cell-status.d.ts +33 -0
- package/dist/grid/edit/edit-session.d.ts +97 -0
- package/dist/grid/edit/use-grid-edit.d.ts +48 -0
- package/dist/grid/focus/editor-style.d.ts +67 -0
- package/dist/grid/host/GridHost.vue.d.ts +137 -0
- package/dist/grid/host/controller.d.ts +219 -0
- package/dist/grid/host/dom.d.ts +10 -0
- package/dist/grid/index.d.ts +8 -0
- package/dist/grid/range/block.d.ts +30 -0
- package/dist/grid/range/fill.d.ts +27 -0
- package/dist/grid/range/index.d.ts +2 -0
- package/dist/grid/theme.d.ts +61 -0
- package/dist/grid-core/auto-scroll.d.ts +67 -0
- package/dist/grid-core/column-resize.d.ts +43 -0
- package/dist/grid-core/config.d.ts +39 -0
- package/dist/grid-core/coordinate.d.ts +64 -0
- package/dist/grid-core/drag.d.ts +46 -0
- package/dist/grid-core/freeze.d.ts +11 -0
- package/dist/grid-core/index.d.ts +17 -0
- package/dist/grid-core/keyboard.d.ts +34 -0
- package/dist/grid-core/keys.d.ts +38 -0
- package/dist/grid-core/lru.d.ts +10 -0
- package/dist/grid-core/range.d.ts +28 -0
- package/dist/grid-core/region.d.ts +73 -0
- package/dist/grid-core/renderer/base.d.ts +92 -0
- package/dist/grid-core/renderer/layout.d.ts +129 -0
- package/dist/grid-core/selection-controller.d.ts +62 -0
- package/dist/grid-core/selection.d.ts +35 -0
- package/dist/grid-core/theme.d.ts +81 -0
- package/dist/grid-core/types.d.ts +178 -0
- package/dist/grid.js +6272 -0
- package/dist/i18n/text.d.ts +17 -0
- package/dist/index.d.ts +39 -4
- package/dist/index.js +23037 -14390
- package/dist/interaction/editSession.d.ts +49 -0
- package/dist/interaction/focus.d.ts +28 -0
- package/dist/interaction/gesture.d.ts +49 -0
- package/dist/interaction/ime.d.ts +55 -0
- package/dist/interaction/index.d.ts +6 -0
- package/dist/interaction/outside.d.ts +40 -0
- package/dist/interaction/vue.d.ts +21 -0
- package/dist/json-ai-prompt.md +1 -1
- package/dist/json-preview/preview.js +16780 -11595
- package/dist/json.js +10 -10
- package/dist/lib/adaptiveLayout.d.ts +32 -2
- package/dist/lib/deviceViewport.d.ts +2 -1
- package/dist/lib/motion.d.ts +12 -0
- package/dist/reka-runtime.json +15 -12
- package/dist/rich-text.js +1 -1
- package/dist/theme.css +1 -1
- package/dist/themes/dsm7-embedded-reset.css +1 -1
- package/dist/themes/dsm7-embedded-theme.css +1 -1
- package/dist/themes/dsm7-embedded.css +1 -1
- package/dist/themes/dsm7.css +1 -1
- package/dist/virtual/cardHeight.d.ts +39 -0
- package/dist/virtual/galleryColumns.d.ts +11 -0
- package/dist/virtual/layoutMotion.d.ts +30 -0
- package/docs/adaptive-layout.md +148 -25
- package/docs/app-local-modal.md +1 -1
- package/docs/callout.md +22 -1
- package/docs/layout-rules.md +14 -0
- package/docs/list-detail.md +60 -0
- package/docs/mobile-native.md +502 -0
- package/docs/release-checks.md +28 -0
- package/docs/theme-hooks.md +28 -7
- package/docs/ux-foundation.md +133 -0
- package/docs/ux-grid.md +217 -0
- package/package.json +100 -2
|
@@ -0,0 +1,133 @@
|
|
|
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).
|
package/docs/ux-grid.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Grid range, fill and clipboard
|
|
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.
|
|
5
|
+
It never writes data. Every change a user asks for (an edit, a clear, a fill,
|
|
6
|
+
a paste, a reorder, a width) comes out as an event; the caller applies it to
|
|
7
|
+
its row model as one undoable change and saves in the background.
|
|
8
|
+
|
|
9
|
+
This page covers range selection, the fill handle, edge auto-scroll, column
|
|
10
|
+
and row drag, column width and the clipboard. Editing is in the `GridHost`
|
|
11
|
+
props (`getEditText`, `cell-commit`); cell painters are in `useGridCells`.
|
|
12
|
+
|
|
13
|
+
## Range selection
|
|
14
|
+
|
|
15
|
+
| Gesture | Result |
|
|
16
|
+
|---|---|
|
|
17
|
+
| Press a cell and drag | The range follows every head change and paints in the same task (no frame hop) |
|
|
18
|
+
| Drag past an edge | Auto-scroll: 30 px zone at every edge, also past the grid; speed ramps from 0 to 2000 px/s over 1.2 s; the head is re-derived from the last pointer on every tick, so the range keeps growing while the pointer rests |
|
|
19
|
+
| Over a frozen column | No horizontal scroll, so frozen columns stay targets |
|
|
20
|
+
| Shift+click, Shift+arrow | Keep the anchor, move the head; Cmd/Ctrl+Shift+arrow jumps to the edge |
|
|
21
|
+
| Cmd/Ctrl+A | All cells |
|
|
22
|
+
| Column header click / Shift / Cmd | Select columns, extend, toggle |
|
|
23
|
+
| Row checkbox / Shift, corner checkbox | Select rows, a run of rows, all rows |
|
|
24
|
+
| Esc | Keeps the selection; cancels a drag, a resize or a fill in progress |
|
|
25
|
+
|
|
26
|
+
Hit-testing is arithmetic over cached column offsets and row heights: a
|
|
27
|
+
pointer move reads nothing from the DOM. Past the last column or row, over a
|
|
28
|
+
header or over blank space, a drag head clamps to the nearest data cell.
|
|
29
|
+
|
|
30
|
+
`selectionBlock(state, { rowCount, columnCount })` gives the rows and columns
|
|
31
|
+
a selection covers (a row selection covers every column, a column selection
|
|
32
|
+
every row); `cellRange` gives the rectangle of a cell selection.
|
|
33
|
+
|
|
34
|
+
## Fill handle
|
|
35
|
+
|
|
36
|
+
Set `fillable`. A cell range shows a 7 px handle at its bottom-right corner
|
|
37
|
+
(21 px hit area, crosshair cursor). Dragging it is vertical only; the preview
|
|
38
|
+
tints the target rows and leaves their values visible; auto-scroll works as
|
|
39
|
+
for a range. On release outside the source rows the grid grows the selection
|
|
40
|
+
to source plus target and emits one `fill-request`:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
interface GridFillRequest {
|
|
44
|
+
source: GridCellRange // the selected block
|
|
45
|
+
target: GridCellRange // the new rows only, same columns
|
|
46
|
+
direction: 'down' | 'up'
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`fillSeries(values, count, direction)` builds one column's values: with two
|
|
51
|
+
or more different numbers the steps repeat (dates as epoch milliseconds step
|
|
52
|
+
the same way); anything else repeats the source block. The caller decides the
|
|
53
|
+
field rules (a read-only or computed column is skipped), writes the target as
|
|
54
|
+
one undo entry and may show a "filled N cells" toast with its own text.
|
|
55
|
+
|
|
56
|
+
Read-only grids and `selectable="none"` show no handle.
|
|
57
|
+
|
|
58
|
+
## Column and row drag
|
|
59
|
+
|
|
60
|
+
`draggable` turns on column reorder (drag a header) and row reorder (the row
|
|
61
|
+
drag handle, with the `drag` row control). The drag starts after 5 px; a ghost
|
|
62
|
+
and a 2 px drop line follow the pointer directly. Esc cancels and the release
|
|
63
|
+
does nothing. A drop emits `column-reorder` or `row-reorder` with the dragged
|
|
64
|
+
runs and the drop index counted before they are removed.
|
|
65
|
+
|
|
66
|
+
## Column width
|
|
67
|
+
|
|
68
|
+
While a resize is dragged, the width follows the pointer and `column-resize`
|
|
69
|
+
fires on every change. On release `column-resize-end` fires once.
|
|
70
|
+
`column-width-save` fires 300 ms after the last finished resize of a column:
|
|
71
|
+
persist the width there. Esc during a resize restores the width and saves
|
|
72
|
+
nothing. A pending save is sent when the grid unmounts.
|
|
73
|
+
|
|
74
|
+
## Clipboard
|
|
75
|
+
|
|
76
|
+
The grid's focus owner (a hidden textarea over the active cell) receives the
|
|
77
|
+
browser's native `copy`, `cut` and `paste` events, so Cmd/Ctrl+C, X and V work
|
|
78
|
+
without permissions, including Safari.
|
|
79
|
+
|
|
80
|
+
**Copy** writes the selected block as tab-separated text (cells with a tab,
|
|
81
|
+
a line break or a quote are quoted, quotes doubled) plus an HTML table for
|
|
82
|
+
more than one cell. Text comes from `getCopyText`, else `getCellText`. If a
|
|
83
|
+
row of the block is not loaded (`isRowLoaded` false), `resolveCopy(block)`
|
|
84
|
+
must return the text; the write then goes through the async clipboard API
|
|
85
|
+
with promise-valued items, so the user gesture still counts. Without
|
|
86
|
+
`resolveCopy` such a copy fails. `clipboard-copy` reports the block, its cell
|
|
87
|
+
count and `ok`; a successful copy outlines the block with a dashed accent line
|
|
88
|
+
until the next edit, paste, fill or Esc.
|
|
89
|
+
|
|
90
|
+
**Cut** is a copy that, only when it succeeded, also emits `clear-request` for
|
|
91
|
+
the cut block. A failed or refused write clears nothing.
|
|
92
|
+
|
|
93
|
+
**Paste** parses `text/plain` into rows and emits `paste-request` with a
|
|
94
|
+
proposal. The grid applies nothing:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
interface GridPasteProposal {
|
|
98
|
+
start: GridCell // top-left of the selection
|
|
99
|
+
values: string[][] // fitted to the grid's columns
|
|
100
|
+
target: GridCellRange // may reach past the last row
|
|
101
|
+
cellCount: number
|
|
102
|
+
extraRows: number // rows past the last row ("Add N rows")
|
|
103
|
+
droppedColumns: number // clipboard columns past the last column
|
|
104
|
+
readonlyColumns: number[] // target columns to skip
|
|
105
|
+
repeated: boolean // one copied cell filled the selected range
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The paste policy is the caller's. Studio applies 50 cells or fewer with no
|
|
110
|
+
type errors directly, as one undo entry, and previews larger pastes or pastes
|
|
111
|
+
with errors.
|
|
112
|
+
|
|
113
|
+
Everything is data: text that starts with `=`, `+`, `-` or `@` is copied and
|
|
114
|
+
pasted as plain text and never evaluated or rewritten.
|
|
115
|
+
|
|
116
|
+
A paste goes to the grid only when no built-in editor is open and the event
|
|
117
|
+
target is the focus owner or a hidden element; a visible input, textarea or
|
|
118
|
+
contenteditable in a caller's editor keeps its native paste. A read-only grid
|
|
119
|
+
ignores pastes.
|
|
120
|
+
|
|
121
|
+
For menu commands, `ref.copy(cut?)` copies through the async clipboard API
|
|
122
|
+
(call it inside the click handler) and `ref.paste(text)` builds a proposal
|
|
123
|
+
from text the caller read itself.
|
|
124
|
+
|
|
125
|
+
## Touch and phone
|
|
126
|
+
|
|
127
|
+
Interaction-spec §14, adapted to Teable's touch grid. Two switches, kept
|
|
128
|
+
apart:
|
|
129
|
+
|
|
130
|
+
- **Touch UI**: `(pointer: coarse)`. No fill handle and no column resize
|
|
131
|
+
handle are drawn or hit (a 5 px edge is no finger target).
|
|
132
|
+
- **Phone**: touch UI and a grid no wider than 640 px (the container, not
|
|
133
|
+
the window; `PHONE_MAX_WIDTH`).
|
|
134
|
+
|
|
135
|
+
Each gesture follows its own `pointerType`: a mouse or pen on a touch-capable
|
|
136
|
+
device keeps every mouse gesture above, and a finger on a desktop gets the
|
|
137
|
+
finger path below.
|
|
138
|
+
|
|
139
|
+
### Finger gestures
|
|
140
|
+
|
|
141
|
+
| Gesture | Phone (≤640 px) | Touch tablet (>640 px) |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| Swipe, any direction | Native pan with momentum (`touch-action: pan-x pan-y`). Never selects, never drags | Same |
|
|
144
|
+
| A press that stops a fling (within 100 ms of a scroll frame) | Only stops it | Same |
|
|
145
|
+
| Tap a cell (released within 6 px and before 250 ms) | Selects the cell and emits `row-expand(row, column)`: open the record sheet scrolled to that field. No editor | Selects the cell. No focus, so no keyboard |
|
|
146
|
+
| Tap the selected cell again | `row-expand` again | Edits: `text` and `number` open in place, take focus and bring up the keyboard. `long-text` and `custom` emit `edit-request` with `trigger: 'tap'`. Read-only cells open the read-only view |
|
|
147
|
+
| Return in a finger-opened editor | — | Commits, moves down, and drops focus so the keyboard goes away |
|
|
148
|
+
| Long press 250 ms (cancelled by a 6 px move) | `context-menu` at the press point, selecting the cell unless it is inside the selection. The release is not a tap | Same |
|
|
149
|
+
| Tap a column header | `header-menu` when the column has a menu, else selects the column | Same |
|
|
150
|
+
| Tap the row header | `row-expand(row)` | `row-expand(row)` with the `expand` control, else toggles the row checkbox. The whole header is one target |
|
|
151
|
+
| Second finger | Cancels the tap and the long press (pinch, two-finger pan) | Same |
|
|
152
|
+
| Range drag, fill, column resize, column or row reorder | None | None |
|
|
153
|
+
|
|
154
|
+
The pointer is cancelled by the browser when it starts panning; selection
|
|
155
|
+
happens on `pointerup` only. The tapped row or header keeps a pressed tint for
|
|
156
|
+
300 ms. A double tap never edits twice: the compatibility `dblclick`, and
|
|
157
|
+
Android's own long-press `contextmenu`, are ignored for 800 ms after a finger.
|
|
158
|
+
|
|
159
|
+
### Phone layout
|
|
160
|
+
|
|
161
|
+
- No frozen data column (the row-number gutter still stays).
|
|
162
|
+
- The gutter is 50 px with row numbers only: `rowControls` are not drawn and
|
|
163
|
+
not hit; a row-header tap opens the record.
|
|
164
|
+
- Wider screens, touch or not, cap frozen columns so the scrolling part keeps
|
|
165
|
+
at least 240 px (Teable's `getMaxFreezeColumnCount`).
|
|
166
|
+
- Row and header height follow the density tokens: the DSM 7 theme gives
|
|
167
|
+
36 px on a coarse pointer unless the app sets `data-ui-density`.
|
|
168
|
+
- The grid draws no append row; the host offers its own add button.
|
|
169
|
+
|
|
170
|
+
### What the host does
|
|
171
|
+
|
|
172
|
+
- `row-expand(row, column?)`: open the record. On a phone it is a bottom
|
|
173
|
+
sheet; when `column` is set, scroll the sheet to that field. Do not focus a
|
|
174
|
+
field on open.
|
|
175
|
+
- `highlightedRow`: pass the row whose record is open so it stays tinted while
|
|
176
|
+
the sheet or panel is open; `null` when closed.
|
|
177
|
+
- `edit-request` with `trigger: 'tap'`: the editor must fit the screen;
|
|
178
|
+
otherwise open the record sheet at that field.
|
|
179
|
+
- `context-menu` from a long press: show the row menu as a bottom sheet on a
|
|
180
|
+
phone (`AdaptivePanel`), a popover elsewhere. Copy, cut and paste go through
|
|
181
|
+
`ref.copy(cut?)` and `ref.paste(text)` from that menu: a finger never gives
|
|
182
|
+
the grid focus, so the keyboard clipboard events do not reach it.
|
|
183
|
+
- `header-menu` from a tap: same sheet-or-popover rule.
|
|
184
|
+
|
|
185
|
+
## Accessibility
|
|
186
|
+
|
|
187
|
+
The grid is `role="grid"` with `aria-multiselectable="true"`. One element
|
|
188
|
+
takes focus: the focus owner, labelled by its column header, row header and
|
|
189
|
+
cell text. Selection changes do not move focus out of the grid. Toasts for
|
|
190
|
+
copy, fill and paste come from the caller, translated.
|
|
191
|
+
|
|
192
|
+
## Release checklist (grid entry)
|
|
193
|
+
|
|
194
|
+
Before a release that changes `@synopackageland/ui/grid`:
|
|
195
|
+
|
|
196
|
+
1. `pnpm exec vitest run tests/ux-28-grid-range-clipboard.test.ts tests/ux-grid-touch.test.ts tests/grid tests/grid-core`.
|
|
197
|
+
2. `pnpm typecheck` and `pnpm build`.
|
|
198
|
+
3. Browser checks on the built entry: `node tests/grid/browser-check.mjs`,
|
|
199
|
+
`node tests/grid/edit-browser-check.mjs`,
|
|
200
|
+
`node tests/grid/cells-browser-check.mjs`, and
|
|
201
|
+
`node tests/grid/range-browser-check.mjs <out> chromium` and `... webkit`.
|
|
202
|
+
The range check fails on any DOM read in pointermove, a range that does
|
|
203
|
+
not paint in the same task, auto-scroll that stops while the pointer
|
|
204
|
+
rests past the edge, a moved element between +100 ms and +1500 ms, or
|
|
205
|
+
scroll frames slower than 50 ms at p95; it records the `dist/grid.js` size.
|
|
206
|
+
4. Touch: `node tests/grid/touch-browser-check.mjs <out>` (Chromium touch
|
|
207
|
+
emulation at 390x844 and 768x1024, real CDP touch input). It fails when a
|
|
208
|
+
swipe selects or has no momentum, a tap focuses, a phone tap does not open
|
|
209
|
+
the record, a tablet second tap does not edit, a finger edit keeps focus,
|
|
210
|
+
or a long press does not open exactly one context menu.
|
|
211
|
+
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.
|
|
215
|
+
7. Manual, not covered headless: IME first character in Safari, native
|
|
216
|
+
macOS Cmd+C/X/V into Excel, Numbers and Google Sheets, and on a real
|
|
217
|
+
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.
|
|
3
|
+
"version": "0.20.5",
|
|
4
4
|
"description": "Shared Vue 3 UI component library with a DSM 7 inspired application theme",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -21,8 +21,13 @@
|
|
|
21
21
|
"docs/component-defaults.md",
|
|
22
22
|
"docs/json-ui.md",
|
|
23
23
|
"docs/layout-rules.md",
|
|
24
|
+
"docs/list-detail.md",
|
|
25
|
+
"docs/mobile-native.md",
|
|
26
|
+
"docs/release-checks.md",
|
|
24
27
|
"docs/size-and-split.md",
|
|
25
28
|
"docs/theme-hooks.md",
|
|
29
|
+
"docs/ux-foundation.md",
|
|
30
|
+
"docs/ux-grid.md",
|
|
26
31
|
"docs/wizard.md"
|
|
27
32
|
],
|
|
28
33
|
"bin": {
|
|
@@ -44,6 +49,10 @@
|
|
|
44
49
|
"types": "./dist/rich-text.d.ts",
|
|
45
50
|
"import": "./dist/rich-text.js"
|
|
46
51
|
},
|
|
52
|
+
"./grid": {
|
|
53
|
+
"types": "./dist/grid/index.d.ts",
|
|
54
|
+
"import": "./dist/grid.js"
|
|
55
|
+
},
|
|
47
56
|
"./json-catalog.schema.json": "./dist/json-catalog.schema.json",
|
|
48
57
|
"./json-ai-prompt.md": "./dist/json-ai-prompt.md",
|
|
49
58
|
"./theme.css": "./dist/theme.css",
|
|
@@ -52,6 +61,58 @@
|
|
|
52
61
|
"./themes/dsm7-embedded-reset.css": "./dist/themes/dsm7-embedded-reset.css",
|
|
53
62
|
"./themes/dsm7-embedded-theme.css": "./dist/themes/dsm7-embedded-theme.css"
|
|
54
63
|
},
|
|
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
|
+
},
|
|
55
116
|
"peerDependencies": {
|
|
56
117
|
"vue": "^3.5.0"
|
|
57
118
|
},
|
|
@@ -71,12 +132,49 @@
|
|
|
71
132
|
"@tiptap/vue-3": "3.32.1",
|
|
72
133
|
"zod": "^4.6.5"
|
|
73
134
|
},
|
|
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
|
+
},
|
|
74
163
|
"engines": {
|
|
75
164
|
"node": ">=20"
|
|
76
165
|
},
|
|
166
|
+
"packageManager": "pnpm@10.33.2",
|
|
167
|
+
"pnpm": {
|
|
168
|
+
"onlyBuiltDependencies": [
|
|
169
|
+
"esbuild",
|
|
170
|
+
"vue-demi"
|
|
171
|
+
]
|
|
172
|
+
},
|
|
77
173
|
"config": {
|
|
78
174
|
"bundledRuntime": {
|
|
79
|
-
"
|
|
175
|
+
"@tanstack/vue-virtual": "3.13.39",
|
|
176
|
+
"@vueuse/core": "14.4.0",
|
|
177
|
+
"reka-ui": "2.11.0"
|
|
80
178
|
}
|
|
81
179
|
},
|
|
82
180
|
"homepage": "https://www.varvis.me/docs/"
|