@zeyos/zx 4.2.0 → 4.3.4
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 +148 -1
- package/README.md +5 -3
- package/dist/types/components/calendar/calendar-model.d.ts +22 -0
- package/dist/types/components/calendar/calendar.d.ts +19 -2
- package/dist/types/components/card-view/card-view.d.ts +1 -1
- package/dist/types/components/card-view/record-card.d.ts +47 -5
- package/dist/types/components/dialog/dialog.d.ts +6 -1
- package/dist/types/components/dropdown/dropdown.d.ts +5 -0
- package/dist/types/components/kanban-view/kanban-policy.d.ts +268 -0
- package/dist/types/components/kanban-view/kanban-view.d.ts +669 -24
- package/dist/types/components/launcher/launcher.d.ts +5 -0
- package/dist/types/components/message/message.d.ts +9 -1
- package/dist/types/components/modal/modal.d.ts +44 -7
- package/dist/types/components/sheet/sheet.d.ts +22 -12
- package/dist/types/core/component.d.ts +6 -1
- package/dist/types/core/overlay-host.d.ts +12 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/zx-zeyos.esm.js +173 -43
- package/dist/zx-zeyos.esm.min.js +1 -1
- package/dist/zx.css +876 -230
- package/dist/zx.esm.js +2053 -338
- package/dist/zx.esm.min.js +3 -3
- package/dist/zx.global.js +2053 -338
- package/dist/zx.global.min.js +3 -3
- package/dist/zx.min.css +1 -1
- package/docs/api.json +250 -2
- package/docs/llms.md +67 -48
- package/docs/llms.txt +1 -3
- package/package.json +1 -2
- package/src/components/account-menu/account-menu.css +1 -1
- package/src/components/app-rail/app-rail.css +1 -1
- package/src/components/calendar/calendar-model.js +45 -0
- package/src/components/calendar/calendar.css +96 -34
- package/src/components/calendar/calendar.js +122 -29
- package/src/components/card-view/card-view.css +211 -9
- package/src/components/card-view/card-view.js +7 -7
- package/src/components/card-view/record-card.js +92 -19
- package/src/components/context-menu/context-menu.css +2 -2
- package/src/components/context-menu/context-menu.js +5 -1
- package/src/components/date-picker/date-picker.css +18 -11
- package/src/components/datebox/date-range-box.css +4 -2
- package/src/components/datebox/datebox.css +4 -2
- package/src/components/dialog/dialog.css +4 -3
- package/src/components/dialog/dialog.js +2 -1
- package/src/components/dropdown/dropdown.css +4 -2
- package/src/components/dropdown/dropdown.js +7 -2
- package/src/components/kanban-view/kanban-policy.js +412 -0
- package/src/components/kanban-view/kanban-view.css +480 -36
- package/src/components/kanban-view/kanban-view.js +1514 -235
- package/src/components/launcher/launcher.css +10 -8
- package/src/components/launcher/launcher.js +9 -2
- package/src/components/menu-button/menu-button.css +2 -2
- package/src/components/message/message.css +15 -25
- package/src/components/message/message.js +17 -11
- package/src/components/modal/modal.css +6 -4
- package/src/components/modal/modal.js +99 -25
- package/src/components/select/select.css +9 -7
- package/src/components/sheet/sheet.css +25 -7
- package/src/components/sheet/sheet.js +43 -23
- package/src/components/table/table.css +5 -3
- package/src/components/tag-picker/tag-picker.css +5 -3
- package/src/components/tooltip/tooltip.css +4 -2
- package/src/components/tooltip/tooltip.js +4 -1
- package/src/core/component.js +8 -3
- package/src/core/overlay-host.js +23 -0
- package/src/index.js +8 -3
- package/styles/tokens/dark.css +4 -0
- package/styles/tokens/semantic.css +83 -8
- package/DESIGN-SYSTEM.md +0 -182
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,153 @@ and friends remain the complete record.
|
|
|
8
8
|
|
|
9
9
|
## Unreleased
|
|
10
10
|
|
|
11
|
+
## 4.3.4 — 2026-08-31
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **Kanban boards became workflow boards.** `KanbanView` now moves cards by pointer, touch,
|
|
16
|
+
keyboard, context menu, and public API through one policy and one commit path.
|
|
17
|
+
- **Pointer and touch dragging.** Native HTML5 drag-and-drop is replaced by Pointer Events, so
|
|
18
|
+
the same code path serves mouse, pen, and touch. A drag from the card body needs a small
|
|
19
|
+
travel (or a long press on touch, so the board still scrolls); a drag from the move handle
|
|
20
|
+
starts immediately. A floating drag preview follows the pointer, the board and any scrollable
|
|
21
|
+
column auto-scroll near their edges, and Escape aborts without moving anything.
|
|
22
|
+
`dragFrom: 'card' | 'handle'` chooses the drag source.
|
|
23
|
+
- **Atomic multi-card moves.** Picking up a card that belongs to the current multi-selection
|
|
24
|
+
moves the whole selection as one step, preserving relative order — one `recordmove`, one
|
|
25
|
+
policy decision, one history entry. `moveRecords(ids, destination)` is the public form.
|
|
26
|
+
- **Enforceable workflow policy.** Columns gain `laneLimits`, `wipPolicy`, and a `from`
|
|
27
|
+
transition allow-list; lanes gain `limit` and `from`. The board-level `wipPolicy` still
|
|
28
|
+
defaults to `'warn'`, and `'block'` refuses a move before the cancelable event. Every refusal
|
|
29
|
+
announces its reason and emits the new cancel-free `movereject` event.
|
|
30
|
+
- **Ordered card rules.** `rules` marks cards with an inline tone marker, badges, and an
|
|
31
|
+
accessible description, so a rule is never communicated by colour alone.
|
|
32
|
+
- **Undo and redo** of committed local moves, with `undo()`, `redo()`, `canUndo()`, `canRedo()`,
|
|
33
|
+
`clearHistory()`, a bounded `historyLimit`, the `historychange` event, optional toolbar
|
|
34
|
+
controls, and Ctrl/Cmd+Z and Ctrl/Cmd+Shift+Z on the board.
|
|
35
|
+
- **Board search and filtering.** `search`, `searchFields`, `filter`, `setSearch`, `setFilter`,
|
|
36
|
+
an optional built-in search control, and the `searchchange` event. Hidden records keep their
|
|
37
|
+
position in the data, so a card dropped between two visible cards lands between them.
|
|
38
|
+
- **Replaceable presentation.** `renderCard`, `renderColumnHeader`, `renderSwimlaneHeader`,
|
|
39
|
+
`renderColumnEmpty`, and `renderDragPreview` replace content while the board keeps the managed
|
|
40
|
+
shell: list item, selection control, action group, move handle, drop targets, and collapse
|
|
41
|
+
control never change hands.
|
|
42
|
+
- **Card context menu, per-column scroll regions, and an add affordance.** `contextMenu` offers
|
|
43
|
+
move commands filtered by the same policy path, `columnHeight` turns each column into its own
|
|
44
|
+
scroll region, and `allowAdd` emits `recordadd` for the application to act on.
|
|
45
|
+
- **A complete `labels` map**, so every visible and announced string can be translated without
|
|
46
|
+
patching the component.
|
|
47
|
+
|
|
48
|
+
## 4.3.3 — 2026-08-26
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- **Kanban boards use a lighter rail hierarchy.** The board and columns no longer stack filled,
|
|
53
|
+
bordered panels around every lane. Compact headers, quiet semantic WIP counts, wider rail gaps,
|
|
54
|
+
and restrained card radii make record cards the primary surfaces while preserving horizontal
|
|
55
|
+
scrolling, empty drop targets, swim lanes, and every existing interaction.
|
|
56
|
+
- **Calendar grids use square structural edges.** The outer calendar, day headings, and time slots
|
|
57
|
+
align as one continuous grid, while the view picker becomes a compact segmented control with a
|
|
58
|
+
raised active view.
|
|
59
|
+
- **Floating messages keep severity visible on glass.** Toasts use a coloured leading inset over
|
|
60
|
+
the shared overlay material and retain deterministic severity backgrounds when transparency is
|
|
61
|
+
reduced or unsupported.
|
|
62
|
+
- The public landing page and Theme Studio no longer duplicate documentation search in their
|
|
63
|
+
headers. Dated 4.3 promotional sections were removed from the landing page and documentation
|
|
64
|
+
introduction, and the landing hero typography was rebalanced around the simplified header.
|
|
65
|
+
|
|
66
|
+
## 4.3.2 — 2026-08-26
|
|
67
|
+
|
|
68
|
+
### Added
|
|
69
|
+
|
|
70
|
+
- **Shared card field slots.** A visible field may opt into the shared record-card anatomy with
|
|
71
|
+
`view.card.slot: 'eyebrow-start' | 'eyebrow-end' | 'title-prefix'`, producing a semantic eyebrow
|
|
72
|
+
row or labelled content immediately before — but outside — the title heading and primary link.
|
|
73
|
+
Absent, malformed, and unknown slots fall back to ordinary labelled metadata, and field
|
|
74
|
+
visibility and order remain authoritative.
|
|
75
|
+
|
|
76
|
+
### Changed
|
|
77
|
+
|
|
78
|
+
- **CardView and KanbanView read as collections, not documents.** CardView clamps titles to two
|
|
79
|
+
lines, keeps previews at thumbnail scale, and renders visible fields as compact metadata chips.
|
|
80
|
+
Kanban columns use a stable 20rem rail with native horizontal overflow, compact headings and
|
|
81
|
+
counts, tighter card padding, an optional square thumbnail, and move/action controls that reveal
|
|
82
|
+
on hover, focus, selection, or grab while staying visible on touch. Both views keep the same
|
|
83
|
+
markup, semantics, and delegated interaction hooks.
|
|
84
|
+
- The landing page hero is lit by the shipped `Aurora` component rather than a bespoke gradient,
|
|
85
|
+
and gains a "Latest release" band covering Calendar, the record views, Aurora, Sheet and Dock,
|
|
86
|
+
the glass materials, and application identity.
|
|
87
|
+
- The documentation Introduction gains a "New in 4.3" section linking the newest component pages.
|
|
88
|
+
Aurora stays documented through its supported component examples and API reference; the
|
|
89
|
+
standalone showcase route is no longer part of the public site.
|
|
90
|
+
- The landing page now carries documentation search, restores the ZeyOS copyright identity in the
|
|
91
|
+
shared footer, and transitions its initially transparent navigation to the established glass
|
|
92
|
+
material after scrolling, with reduced-motion and reduced-transparency fallbacks.
|
|
93
|
+
- Public site and package assembly now exclude non-product contributor material and design audits,
|
|
94
|
+
with release checks that reject private paths in deployable output.
|
|
95
|
+
|
|
96
|
+
### Fixed
|
|
97
|
+
|
|
98
|
+
- **Calendar month and year paging no longer overflows a month-end anchor.** From 31 January,
|
|
99
|
+
`next()` reached 3 March and skipped February entirely; from 31 March, `prev()` landed back
|
|
100
|
+
inside March, so the button appeared dead. Both steps now clamp the day of month into the target
|
|
101
|
+
month via the new `calendarPageDate()` / `addCalendarMonths()` model helpers.
|
|
102
|
+
- `Calendar.updateEvent()` honours the configured `dateUnit` again. It normalized without it, so a
|
|
103
|
+
numeric `start`/`end` change was read as milliseconds on a calendar configured for Unix seconds.
|
|
104
|
+
- The Calendar toolbar no longer overlaps itself. The end-justified view/new controls kept their
|
|
105
|
+
min-content width inside a narrower `1fr` track and bled back over the centred heading, hiding
|
|
106
|
+
the first view button; the heading is now the only elastic track and ellipsizes instead.
|
|
107
|
+
- Kanban announces a reached or exceeded work-in-progress limit with the move it belongs to, and
|
|
108
|
+
keeps focus on a collapse control across a board refresh — including when a programmatic
|
|
109
|
+
collapse hides the card that had focus.
|
|
110
|
+
- Kanban preserves saved order and collapse preferences for data-derived columns and swim lanes
|
|
111
|
+
when state is restored before asynchronous records arrive. Canceling the bubbling
|
|
112
|
+
`zx-recordmove` event now vetoes the move, and a manual local move clears a conflicting local
|
|
113
|
+
sort so serialized state matches visible order.
|
|
114
|
+
- Selectable record cards retain valid list-item semantics with a global selection description,
|
|
115
|
+
and preview media no longer accepts local `file:` URLs.
|
|
116
|
+
- The four system-architecture cards on the landing page align their links again, and ~60 lines of
|
|
117
|
+
dead `.release-band`/`.release-notes` site CSS with no remaining markup were removed.
|
|
118
|
+
- Documentation search no longer collides with primary navigation: responsive headers move the
|
|
119
|
+
centered field to its own row before their chrome can overlap.
|
|
120
|
+
|
|
121
|
+
## 4.3.0 — 2026-08-26
|
|
122
|
+
|
|
123
|
+
### Added
|
|
124
|
+
|
|
125
|
+
- **Scoped top-layer ownership.** Dropdown, Modal, Dialog, Sheet, Launcher, and floating Message
|
|
126
|
+
regions accept an optional `scope` context and otherwise resolve the opener's nearest Zx theme
|
|
127
|
+
scope. Native popovers and dialogs still use the browser top layer, while material, density,
|
|
128
|
+
product-token, and nested-theme inheritance remain intact.
|
|
129
|
+
|
|
130
|
+
### Changed
|
|
131
|
+
|
|
132
|
+
- **Liquid glass is now a real overlay material.** Compact overlays and reading panels use
|
|
133
|
+
separate translucent bases, restrained specular and Aurora-response layers, blur/saturation,
|
|
134
|
+
shadows, borders, dividers, and interaction-state tokens. Menus, Select, TagPicker, date
|
|
135
|
+
popovers, tooltips, table column controls, and Toast use compact glass; Launcher, Modal, Dialog,
|
|
136
|
+
and floating Sheets use the calmer reading material. Docked Sheets remain opaque.
|
|
137
|
+
- **Theme Studio makes optical differences visible.** Its overlay specimen now sits on a
|
|
138
|
+
multicolour Aurora field, while Flat, Glass, and Deep glass expose materially different alpha,
|
|
139
|
+
refraction, and elevation in both light and dark themes.
|
|
140
|
+
- **Accessible material fallbacks are deterministic.** Reduced-transparency, increased-contrast,
|
|
141
|
+
forced-colour, and unsupported-filter environments remove reflection and backdrop effects and
|
|
142
|
+
restore solid surfaces; blurred Sheet backdrops follow the same rule.
|
|
143
|
+
|
|
144
|
+
### Fixed
|
|
145
|
+
|
|
146
|
+
- Toast intent colours no longer turn the surface effectively opaque, modal backdrops no longer
|
|
147
|
+
erase the content meant to refract through the panel, scoped modals lock page scrolling again,
|
|
148
|
+
and DatePicker controls no longer tile the owning surface's reflection gradient.
|
|
149
|
+
- Floating non-modal Sheets now remain viewport-anchored inside transformed or clipped theme
|
|
150
|
+
scopes, and generation-aware lifecycle handling prevents queued close events from invalidating
|
|
151
|
+
a reopened Sheet during rapid dock/release handoffs.
|
|
152
|
+
- Documentation search now consumes the same compact overlay material, interaction states, and
|
|
153
|
+
accessibility fallbacks as library popovers; fallback tokens cover every supported theme scope.
|
|
154
|
+
- Calendar drag operations preserve the grabbed time/day offset, resize previews track their
|
|
155
|
+
proposed duration, pointer capture is resilient, and agenda/month layouts keep their event and
|
|
156
|
+
day controls aligned across desktop and mobile views.
|
|
157
|
+
|
|
11
158
|
## 4.2.0 — 2026-08-26
|
|
12
159
|
|
|
13
160
|
### Added
|
|
@@ -30,7 +177,7 @@ and friends remain the complete record.
|
|
|
30
177
|
- **Aurora surfaces.** `Aurora` adds a dependency-free, one- to four-colour ambient-light layer
|
|
31
178
|
with six geometries, bounded palettes and intensity, CSS-only composition, and deterministic
|
|
32
179
|
reduced-motion, reduced-transparency, and forced-colour fallbacks. The documentation includes a
|
|
33
|
-
live application composition and
|
|
180
|
+
live application composition and examples for all six supported geometries.
|
|
34
181
|
|
|
35
182
|
### Changed
|
|
36
183
|
|
package/README.md
CHANGED
|
@@ -6,9 +6,6 @@ and application layouts in plain ES2022 modules. Source modules run directly in
|
|
|
6
6
|
distribution also provides ESM and classic-script bundles. Xenon originated at ZeyOS, while its
|
|
7
7
|
components and contracts remain product- and framework-agnostic.
|
|
8
8
|
|
|
9
|
-
The [design-system audit](./DESIGN-SYSTEM.md) records current ZeyOS coverage, missing shell
|
|
10
|
-
patterns, the adoption boundary, transaction-grid follow-ups, and chart-engine candidates.
|
|
11
|
-
|
|
12
9
|
## Quick start
|
|
13
10
|
|
|
14
11
|
Use the ESM bundle when the application already uses modules:
|
|
@@ -238,6 +235,11 @@ the document. Select a built-in theme and density on any ancestor (normally `<ht
|
|
|
238
235
|
<html data-zx-theme="dark" data-zx-density="compact">
|
|
239
236
|
```
|
|
240
237
|
|
|
238
|
+
Top-layer menus, dialogs, tooltips, launchers, and toast regions stay under the nearest Zx theme
|
|
239
|
+
scope in the DOM, so a theme or product-token override on a nested application shell also applies
|
|
240
|
+
to its overlays. Pass the optional `scope` context to Modal, Dialog, Sheet, Launcher, or static
|
|
241
|
+
Message calls when the opener is not inside the intended scope.
|
|
242
|
+
|
|
241
243
|
Theme values are `light`, `dark`, and `auto`; density values are `cozy` and `compact`. `auto`
|
|
242
244
|
follows the operating-system color preference.
|
|
243
245
|
|
|
@@ -128,6 +128,28 @@ export declare function calendarRange(view: CalendarView, anchor: Date, options?
|
|
|
128
128
|
start: Date;
|
|
129
129
|
end: Date;
|
|
130
130
|
};
|
|
131
|
+
/**
|
|
132
|
+
* Returns the anchor date one visible period away from `anchor`.
|
|
133
|
+
*
|
|
134
|
+
* Month and year steps clamp the day of month into the target month instead of letting it
|
|
135
|
+
* overflow: `setMonth()` alone turns 31 January into 3 March, which makes February unreachable
|
|
136
|
+
* from a month-end anchor and leaves `prev()` on 31 March landing back inside March.
|
|
137
|
+
* @param {CalendarView} view Current view.
|
|
138
|
+
* @param {Date} anchor Current anchor date.
|
|
139
|
+
* @param {number} direction -1 for the previous period, 1 for the next.
|
|
140
|
+
* @param {{agendaDays?: number}} [options={}] Paging options.
|
|
141
|
+
* @returns {Date}
|
|
142
|
+
*/
|
|
143
|
+
export declare function calendarPageDate(view: CalendarView, anchor: Date, direction: number, options?: {
|
|
144
|
+
agendaDays?: number;
|
|
145
|
+
}): Date;
|
|
146
|
+
/**
|
|
147
|
+
* Adds whole months, clamping the day of month to the last day the target month actually has.
|
|
148
|
+
* @param {Date} value Local date.
|
|
149
|
+
* @param {number} months Months to add.
|
|
150
|
+
* @returns {Date}
|
|
151
|
+
*/
|
|
152
|
+
export declare function addCalendarMonths(value: Date, months: number): Date;
|
|
131
153
|
/**
|
|
132
154
|
* Normalizes caller records atomically into the Calendar event contract.
|
|
133
155
|
* @param {Record<string, any>[]} records Source records.
|
|
@@ -283,6 +283,8 @@ export declare class Calendar extends Component<CalendarOptions> {
|
|
|
283
283
|
event: import("./calendar-model.js").CalendarEvent;
|
|
284
284
|
action: string;
|
|
285
285
|
control: any;
|
|
286
|
+
timeOffsetMinutes: number;
|
|
287
|
+
dayOffset: number;
|
|
286
288
|
moved: boolean;
|
|
287
289
|
start?: undefined;
|
|
288
290
|
end?: undefined;
|
|
@@ -290,6 +292,8 @@ export declare class Calendar extends Component<CalendarOptions> {
|
|
|
290
292
|
oldEvent?: undefined;
|
|
291
293
|
event?: undefined;
|
|
292
294
|
action?: undefined;
|
|
295
|
+
timeOffsetMinutes?: undefined;
|
|
296
|
+
dayOffset?: undefined;
|
|
293
297
|
type: string;
|
|
294
298
|
pointerId: number;
|
|
295
299
|
startX: number;
|
|
@@ -424,10 +428,23 @@ export declare class Calendar extends Component<CalendarOptions> {
|
|
|
424
428
|
_cancelPointer(event: PointerEvent): void;
|
|
425
429
|
/** @param {CalendarEvent} event @param {'move'|'resize'} action @param {number} x @param {number} y @returns {CalendarEvent|null} */
|
|
426
430
|
_proposalAtPoint(event: CalendarEvent, action: 'move' | 'resize', x: number, y: number): CalendarEvent | null;
|
|
427
|
-
/** @param {number} x @param {number} y @returns {Date|null} */
|
|
428
|
-
_timeAtPoint(x: number, y: number): Date | null;
|
|
431
|
+
/** @param {number} x @param {number} y @param {Date|null} [fixedDay=null] @returns {Date|null} */
|
|
432
|
+
_timeAtPoint(x: number, y: number, fixedDay?: Date | null): Date | null;
|
|
429
433
|
/** @param {number} x @param {number} y @returns {Date|null} */
|
|
430
434
|
_dayAtPoint(x: number, y: number): Date | null;
|
|
435
|
+
/** @param {CalendarEvent} event @param {number} x @param {number} y @returns {{minutes: number, days: number}} */
|
|
436
|
+
_dragOffsetForEvent(event: CalendarEvent, x: number, y: number): {
|
|
437
|
+
minutes: number;
|
|
438
|
+
days: number;
|
|
439
|
+
};
|
|
440
|
+
/** @param {Date} day @returns {number} */
|
|
441
|
+
_timeGridDayIndex(day: Date): number;
|
|
442
|
+
/** @param {CalendarEvent} event @returns {string|null} */
|
|
443
|
+
_timedPreviewHeight(event: CalendarEvent): string | null;
|
|
444
|
+
/** @param {number} pointerId @returns {void} */
|
|
445
|
+
_capturePointer(pointerId: number): void;
|
|
446
|
+
/** @param {number} pointerId @returns {void} */
|
|
447
|
+
_releasePointerCapture(pointerId: number): void;
|
|
431
448
|
/** @param {Date} start @param {Date} end @returns {void} */
|
|
432
449
|
_previewSelection(start: Date, end: Date): void;
|
|
433
450
|
/** @returns {void} */
|
|
@@ -190,7 +190,7 @@ export type CardRecordGroup = {
|
|
|
190
190
|
* @property {string|((record:ViewRecord,index:number)=>unknown)|null} [groupBy=null]
|
|
191
191
|
* Field id or local group resolver.
|
|
192
192
|
* @property {unknown[]} [groupOrder=[]] Preferred group ids; missing ids render as empty groups.
|
|
193
|
-
* @property {number|string} [minCardWidth='
|
|
193
|
+
* @property {number|string} [minCardWidth='15rem'] Responsive minimum card width.
|
|
194
194
|
* @property {number|null} [maxColumns=null] Maximum cards per row; null is unconstrained.
|
|
195
195
|
* @property {'outlined'|'raised'|'filled'} [variant='outlined'] Card surface treatment.
|
|
196
196
|
* @property {number} [loadingCount=6] Skeleton cards shown while loading.
|
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
export type ViewRecord = Record<string, any>;
|
|
2
2
|
export type ViewField = import('../view/record-view.js').ViewField;
|
|
3
3
|
export type RecordCardValueSource = string | ((record: ViewRecord, index: number) => unknown) | null;
|
|
4
|
+
export type RecordCardFieldSlot = 'eyebrow-start' | 'eyebrow-end' | 'title-prefix';
|
|
5
|
+
export type RecordCardFieldGroups = {
|
|
6
|
+
/**
|
|
7
|
+
* Fields shown at the logical start of the eyebrow row.
|
|
8
|
+
*/
|
|
9
|
+
eyebrowStart: ViewField[];
|
|
10
|
+
/**
|
|
11
|
+
* Fields shown at the logical end of the eyebrow row.
|
|
12
|
+
*/
|
|
13
|
+
eyebrowEnd: ViewField[];
|
|
14
|
+
/**
|
|
15
|
+
* Fields shown immediately before, but outside, the heading.
|
|
16
|
+
*/
|
|
17
|
+
titlePrefix: ViewField[];
|
|
18
|
+
/**
|
|
19
|
+
* Remaining labelled metadata fields.
|
|
20
|
+
*/
|
|
21
|
+
metadata: ViewField[];
|
|
22
|
+
};
|
|
4
23
|
export type RecordCardPreviewDescriptor = {
|
|
5
24
|
/**
|
|
6
25
|
* Image URL.
|
|
@@ -142,6 +161,14 @@ export type ResolvedRecordPreview = {
|
|
|
142
161
|
/** @typedef {Record<string, any>} ViewRecord */
|
|
143
162
|
/** @typedef {import('../view/record-view.js').ViewField} ViewField */
|
|
144
163
|
/** @typedef {string|((record:ViewRecord,index:number)=>unknown)|null} RecordCardValueSource */
|
|
164
|
+
/** @typedef {'eyebrow-start'|'eyebrow-end'|'title-prefix'} RecordCardFieldSlot */
|
|
165
|
+
/**
|
|
166
|
+
* @typedef {Object} RecordCardFieldGroups
|
|
167
|
+
* @property {ViewField[]} eyebrowStart Fields shown at the logical start of the eyebrow row.
|
|
168
|
+
* @property {ViewField[]} eyebrowEnd Fields shown at the logical end of the eyebrow row.
|
|
169
|
+
* @property {ViewField[]} titlePrefix Fields shown immediately before, but outside, the heading.
|
|
170
|
+
* @property {ViewField[]} metadata Remaining labelled metadata fields.
|
|
171
|
+
*/
|
|
145
172
|
/**
|
|
146
173
|
* @typedef {Object} RecordCardPreviewDescriptor
|
|
147
174
|
* @property {string} src Image URL.
|
|
@@ -200,11 +227,12 @@ export type ResolvedRecordPreview = {
|
|
|
200
227
|
* becomes text, URLs are normalized before reaching native attributes, and actions expose stable
|
|
201
228
|
* data attributes for a component-owned delegated listener.
|
|
202
229
|
*
|
|
203
|
-
* The returned `<li>` belongs in a semantic `<ul>`/`<ol>`. When selectable
|
|
204
|
-
* `aria-
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
*
|
|
230
|
+
* The returned `<li>` belongs in a semantic `<ul>`/`<ol>`. When selectable its global
|
|
231
|
+
* `aria-description` announces selection without applying the unsupported `aria-selected` state
|
|
232
|
+
* to a listitem; multi-selection also adds a native checkbox. It deliberately remains a listitem
|
|
233
|
+
* rather than becoming an ARIA option because cards may contain native links and buttons, which
|
|
234
|
+
* the listbox pattern does not permit inside an option. Preview images are paired with a stable
|
|
235
|
+
* fallback. The owning component listens for image `error` and marks the fallback.
|
|
208
236
|
*
|
|
209
237
|
* @param {ViewRecord} record Record to render.
|
|
210
238
|
* @param {number} index Current display index.
|
|
@@ -212,6 +240,20 @@ export type ResolvedRecordPreview = {
|
|
|
212
240
|
* @returns {HTMLLIElement} Semantic record card list item.
|
|
213
241
|
*/
|
|
214
242
|
export declare function createRecordCard(record: ViewRecord, index: number, options?: RecordCardOptions): HTMLLIElement;
|
|
243
|
+
/**
|
|
244
|
+
* Partitions ordered visible fields into the shared record-card slots. A recognized
|
|
245
|
+
* `field.view.card.slot` moves the field to that semantic region; absent or unknown values remain
|
|
246
|
+
* ordinary metadata. Title and subtitle fields retain the existing no-duplication rule.
|
|
247
|
+
*
|
|
248
|
+
* The input array and descriptors are never mutated. Each field appears in at most one result
|
|
249
|
+
* array, and the order within every result follows the supplied visible-field order.
|
|
250
|
+
*
|
|
251
|
+
* @param {ViewField[]} fields Ordered visible fields.
|
|
252
|
+
* @param {RecordCardValueSource} [titleSource=null] Active title field or resolver.
|
|
253
|
+
* @param {RecordCardValueSource} [subtitleSource=null] Active subtitle field or resolver.
|
|
254
|
+
* @returns {RecordCardFieldGroups} Partitioned fields.
|
|
255
|
+
*/
|
|
256
|
+
export declare function partitionRecordCardFields(fields: ViewField[], titleSource?: RecordCardValueSource, subtitleSource?: RecordCardValueSource): RecordCardFieldGroups;
|
|
215
257
|
/**
|
|
216
258
|
* Resolves a preview without touching the DOM. Unsafe, malformed, and non-image URL schemes are
|
|
217
259
|
* rejected into the same descriptor shape so callers can still render the stable fallback.
|
|
@@ -41,6 +41,10 @@ export type DialogOptions = {
|
|
|
41
41
|
content?: Node | string | number | {
|
|
42
42
|
toElement: () => Node | null;
|
|
43
43
|
} | null;
|
|
44
|
+
/**
|
|
45
|
+
* Element whose nearest Zx theme scope owns the overlay; defaults to the opener.
|
|
46
|
+
*/
|
|
47
|
+
scope?: Element | string | null;
|
|
44
48
|
/**
|
|
45
49
|
* Open event listener.
|
|
46
50
|
*/
|
|
@@ -159,6 +163,7 @@ export type PromptOptions = {
|
|
|
159
163
|
* @property {DialogButton[]} [buttons=[]] Footer buttons.
|
|
160
164
|
* @property {boolean} [closable=true] Whether Escape and the header button may close the dialog.
|
|
161
165
|
* @property {Node|string|number|{toElement: () => Node|null}|null} [content=null] Body content.
|
|
166
|
+
* @property {Element|string|null} [scope=null] Element whose nearest Zx theme scope owns the overlay; defaults to the opener.
|
|
162
167
|
* @property {(event: CustomEvent<Record<string, never>>) => void} [onopen] Open event listener.
|
|
163
168
|
* @property {(event: CustomEvent<{result: unknown}>) => void} [onclose] Close event listener.
|
|
164
169
|
* @property {(event: CustomEvent<Record<string, never>>) => void} [oncancel] Cancel event listener.
|
|
@@ -209,7 +214,7 @@ export declare class Dialog extends Modal {
|
|
|
209
214
|
/** @type {Readonly<DialogOptions>} */
|
|
210
215
|
static defaults: Readonly<DialogOptions>;
|
|
211
216
|
/**
|
|
212
|
-
* Creates a structured dialog
|
|
217
|
+
* Creates a structured dialog in the configured theme scope, or at document level when unscoped.
|
|
213
218
|
* @param {Element|string|null} [_target=null] Ignored; Dialog always owns its root.
|
|
214
219
|
* @param {DialogOptions} [options={}] Dialog options.
|
|
215
220
|
*/
|
|
@@ -28,6 +28,10 @@ export type DropdownOptions = {
|
|
|
28
28
|
* Whether a click within the panel closes it.
|
|
29
29
|
*/
|
|
30
30
|
closeOnSelect?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Element whose nearest Zx theme scope owns the panel; defaults to the anchor.
|
|
33
|
+
*/
|
|
34
|
+
scope?: Element | string | null;
|
|
31
35
|
/**
|
|
32
36
|
* Open event listener.
|
|
33
37
|
*/
|
|
@@ -45,6 +49,7 @@ export type DropdownOptions = {
|
|
|
45
49
|
* @property {boolean} [matchWidth=false] Whether the panel matches the anchor width.
|
|
46
50
|
* @property {'click'|'manual'} [openOn='click'] Trigger behavior.
|
|
47
51
|
* @property {boolean} [closeOnSelect=false] Whether a click within the panel closes it.
|
|
52
|
+
* @property {Element|string|null} [scope=null] Element whose nearest Zx theme scope owns the panel; defaults to the anchor.
|
|
48
53
|
* @property {(event: CustomEvent<Record<string, never>>) => void} [onopen] Open event listener.
|
|
49
54
|
* @property {(event: CustomEvent<Record<string, never>>) => void} [onclose] Close event listener.
|
|
50
55
|
*/
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
export type KanbanRecord = Record<string, any>;
|
|
2
|
+
export type KanbanColumn = import('./kanban-view.js').KanbanColumn;
|
|
3
|
+
export type KanbanSwimlane = import('./kanban-view.js').KanbanSwimlane;
|
|
4
|
+
export type KanbanMovePoint = import('./kanban-view.js').KanbanMovePoint;
|
|
5
|
+
export type KanbanAccessor = import('./kanban-view.js').KanbanAccessor;
|
|
6
|
+
export type KanbanRule = {
|
|
7
|
+
/**
|
|
8
|
+
* Stable rule id, written to the card's `data-rule` list.
|
|
9
|
+
*/
|
|
10
|
+
id: string;
|
|
11
|
+
/**
|
|
12
|
+
* Predicate deciding whether the rule applies to one record.
|
|
13
|
+
*/
|
|
14
|
+
when: (record: KanbanRecord, context: {
|
|
15
|
+
index: number;
|
|
16
|
+
column: string;
|
|
17
|
+
lane: string | null;
|
|
18
|
+
}) => boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Visual intent.
|
|
21
|
+
* The first matching rule paints the card marker; later matches only contribute badges.
|
|
22
|
+
*/
|
|
23
|
+
tone?: 'neutral' | 'accent' | 'success' | 'warning' | 'danger' | 'info';
|
|
24
|
+
/**
|
|
25
|
+
* Badge text. A rule without a label is marker-only.
|
|
26
|
+
*/
|
|
27
|
+
label?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Optional badge icon name.
|
|
30
|
+
*/
|
|
31
|
+
icon?: string | null;
|
|
32
|
+
/**
|
|
33
|
+
* Text joined into the card's accessible description so a
|
|
34
|
+
* rule is never communicated by colour alone.
|
|
35
|
+
*/
|
|
36
|
+
description?: string;
|
|
37
|
+
};
|
|
38
|
+
export type KanbanMoveEvaluation = {
|
|
39
|
+
/**
|
|
40
|
+
* Whether the move may proceed to the cancelable event.
|
|
41
|
+
*/
|
|
42
|
+
allowed: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Refusal reason, or null when allowed.
|
|
45
|
+
*/
|
|
46
|
+
reason: KanbanRejectReason | null;
|
|
47
|
+
/**
|
|
48
|
+
* The limit the destination count was measured against.
|
|
49
|
+
*/
|
|
50
|
+
limit: number | null;
|
|
51
|
+
/**
|
|
52
|
+
* Resulting record count in the constrained scope.
|
|
53
|
+
*/
|
|
54
|
+
count: number;
|
|
55
|
+
/**
|
|
56
|
+
* Whether an applicable limit would be exceeded.
|
|
57
|
+
*/
|
|
58
|
+
limitExceeded: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Whether an applicable limit would be met exactly.
|
|
61
|
+
*/
|
|
62
|
+
limitReached: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Effective work-in-progress policy.
|
|
65
|
+
*/
|
|
66
|
+
policy: 'warn' | 'block';
|
|
67
|
+
};
|
|
68
|
+
export type KanbanRejectReason = 'accept' | 'transition' | 'wip' | 'lane-accept' | 'lane-transition' | 'lane-wip' | 'destination' | 'grouping';
|
|
69
|
+
export type KanbanHistoryEntry = {
|
|
70
|
+
/**
|
|
71
|
+
* Record order before or after one committed move.
|
|
72
|
+
*/
|
|
73
|
+
records: KanbanRecord[];
|
|
74
|
+
/**
|
|
75
|
+
* Selected record ids at that moment.
|
|
76
|
+
*/
|
|
77
|
+
selection: unknown[];
|
|
78
|
+
/**
|
|
79
|
+
* Human-readable description of the step.
|
|
80
|
+
*/
|
|
81
|
+
label?: string;
|
|
82
|
+
};
|
|
83
|
+
export type KanbanHistory = {
|
|
84
|
+
/**
|
|
85
|
+
* Records a step and drops the redo stack.
|
|
86
|
+
*/
|
|
87
|
+
push: (entry: KanbanHistoryEntry) => void;
|
|
88
|
+
/**
|
|
89
|
+
* Steps back.
|
|
90
|
+
*/
|
|
91
|
+
undo: (current: KanbanHistoryEntry) => KanbanHistoryEntry | null;
|
|
92
|
+
/**
|
|
93
|
+
* Steps forward.
|
|
94
|
+
*/
|
|
95
|
+
redo: (current: KanbanHistoryEntry) => KanbanHistoryEntry | null;
|
|
96
|
+
/**
|
|
97
|
+
* Whether a step back exists.
|
|
98
|
+
*/
|
|
99
|
+
canUndo: () => boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Whether a step forward exists.
|
|
102
|
+
*/
|
|
103
|
+
canRedo: () => boolean;
|
|
104
|
+
/**
|
|
105
|
+
* Empties both stacks.
|
|
106
|
+
*/
|
|
107
|
+
clear: () => void;
|
|
108
|
+
/**
|
|
109
|
+
* Current stack depths.
|
|
110
|
+
*/
|
|
111
|
+
depth: () => {
|
|
112
|
+
undo: number;
|
|
113
|
+
redo: number;
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Validates and clones ordered card rules. Rules are pure presentation: they never change a
|
|
118
|
+
* record, a move, or a policy decision.
|
|
119
|
+
* @param {unknown} rules Configured rules.
|
|
120
|
+
* @returns {KanbanRule[]} Normalized rules.
|
|
121
|
+
*/
|
|
122
|
+
export declare function normalizeKanbanRules(rules: unknown): KanbanRule[];
|
|
123
|
+
/**
|
|
124
|
+
* Returns the rules matching one record, in configured order. A predicate that throws is treated
|
|
125
|
+
* as "does not apply" so one broken rule cannot take the board down.
|
|
126
|
+
* @param {KanbanRule[]} rules Normalized rules.
|
|
127
|
+
* @param {KanbanRecord} record Record.
|
|
128
|
+
* @param {{index:number,column:string,lane:string|null}} context Position context.
|
|
129
|
+
* @returns {KanbanRule[]} Matching rules.
|
|
130
|
+
*/
|
|
131
|
+
export declare function resolveKanbanRules(rules: KanbanRule[], record: KanbanRecord, context: {
|
|
132
|
+
index: number;
|
|
133
|
+
column: string;
|
|
134
|
+
lane: string | null;
|
|
135
|
+
}): KanbanRule[];
|
|
136
|
+
/**
|
|
137
|
+
* Decides whether a proposed move may proceed, and reports the work-in-progress consequence either
|
|
138
|
+
* way. Checks run in a fixed order — transition, eligibility, then capacity — so a refusal always
|
|
139
|
+
* names the first constraint the move violates rather than an arbitrary one.
|
|
140
|
+
*
|
|
141
|
+
* Counts exclude the moving records, so a reorder inside one column is measured against the column
|
|
142
|
+
* it is already in rather than being told it doubles the load.
|
|
143
|
+
*
|
|
144
|
+
* @param {Object} input Evaluation input.
|
|
145
|
+
* @param {KanbanRecord[]} input.records Records being moved together.
|
|
146
|
+
* @param {KanbanColumn} input.column Destination column descriptor.
|
|
147
|
+
* @param {KanbanSwimlane|null} input.swimlane Destination lane descriptor, or null.
|
|
148
|
+
* @param {import('./kanban-view.js').KanbanMoveContext} input.context Context passed to `accept`.
|
|
149
|
+
* @param {KanbanMovePoint} input.from Origin of the primary record.
|
|
150
|
+
* @param {number} input.columnCount Records already in the destination column, movers excluded.
|
|
151
|
+
* @param {number} input.laneCount Records already in the destination lane, movers excluded.
|
|
152
|
+
* @param {number} input.cellCount Records already in the destination column and lane, movers excluded.
|
|
153
|
+
* @param {'warn'|'block'} [input.policy='warn'] Board work-in-progress policy.
|
|
154
|
+
* @returns {KanbanMoveEvaluation} Decision and capacity report.
|
|
155
|
+
*/
|
|
156
|
+
export declare function evaluateKanbanMove(input: {
|
|
157
|
+
records: KanbanRecord[];
|
|
158
|
+
column: KanbanColumn;
|
|
159
|
+
swimlane: KanbanSwimlane | null;
|
|
160
|
+
context: import('./kanban-view.js').KanbanMoveContext;
|
|
161
|
+
from: KanbanMovePoint;
|
|
162
|
+
columnCount: number;
|
|
163
|
+
laneCount: number;
|
|
164
|
+
cellCount: number;
|
|
165
|
+
policy?: 'warn' | 'block';
|
|
166
|
+
}): KanbanMoveEvaluation;
|
|
167
|
+
/**
|
|
168
|
+
* Reports which transition allow-list, if any, refuses one origin. A move that stays on an axis is
|
|
169
|
+
* never judged by that axis's rule: reordering inside a column is not a transition into it.
|
|
170
|
+
* @param {KanbanColumn} column Destination column.
|
|
171
|
+
* @param {KanbanSwimlane|null} swimlane Destination lane, or null.
|
|
172
|
+
* @param {KanbanMovePoint} from Origin.
|
|
173
|
+
* @returns {'transition'|'lane-transition'|null} Refusing rule, or null when the origin is admitted.
|
|
174
|
+
*/
|
|
175
|
+
export declare function allowsKanbanTransition(column: KanbanColumn, swimlane: KanbanSwimlane | null, from: KanbanMovePoint): 'transition' | 'lane-transition' | null;
|
|
176
|
+
/**
|
|
177
|
+
* Splits a search string into lowercase terms. Quoted groups stay together so `"needs review"`
|
|
178
|
+
* matches a phrase rather than two independent words.
|
|
179
|
+
* @param {unknown} search Raw search string.
|
|
180
|
+
* @returns {string[]} Lowercase terms.
|
|
181
|
+
*/
|
|
182
|
+
export declare function kanbanSearchTerms(search: unknown): string[];
|
|
183
|
+
/**
|
|
184
|
+
* Reports whether searchable text contains every term.
|
|
185
|
+
* @param {string} text Concatenated searchable text.
|
|
186
|
+
* @param {string[]} terms Lowercase terms.
|
|
187
|
+
* @returns {boolean} Whether the record matches.
|
|
188
|
+
*/
|
|
189
|
+
export declare function matchesKanbanSearch(text: string, terms: string[]): boolean;
|
|
190
|
+
/**
|
|
191
|
+
* Bounded undo/redo stack over whole record-order snapshots. Snapshots are shallow arrays of the
|
|
192
|
+
* very record objects the board already holds, so a step costs one array rather than a deep clone;
|
|
193
|
+
* this is safe precisely because a Kanban move clones the record it changes and never mutates one.
|
|
194
|
+
* @param {number} [limit=50] Maximum remembered steps.
|
|
195
|
+
* @returns {KanbanHistory} History controller.
|
|
196
|
+
*/
|
|
197
|
+
export declare function createKanbanHistory(limit?: number): KanbanHistory;
|
|
198
|
+
/**
|
|
199
|
+
* Reorders records around one or more already-cloned moved records. The input array and every
|
|
200
|
+
* input record remain untouched. Movers keep their relative order and land contiguously, so a
|
|
201
|
+
* multi-card move reads on the board exactly as it read before it was picked up.
|
|
202
|
+
*
|
|
203
|
+
* The destination index is relative to the records remaining in the destination column and lane
|
|
204
|
+
* after the movers are lifted out — the same frame of reference a user sees while dragging.
|
|
205
|
+
*
|
|
206
|
+
* @param {KanbanRecord[]} records Current records.
|
|
207
|
+
* @param {{id:unknown,record:KanbanRecord}[]} entries Moving ids paired with their cloned records.
|
|
208
|
+
* @param {{recordId:string|((record:KanbanRecord)=>unknown),columnBy:KanbanAccessor,swimlaneBy:KanbanAccessor,destination:KanbanMovePoint}} options Accessors and destination.
|
|
209
|
+
* @returns {{records:KanbanRecord[],moves:{id:unknown,from:KanbanMovePoint}[],to:KanbanMovePoint}|null}
|
|
210
|
+
*/
|
|
211
|
+
export declare function reorderKanbanRecords(records: KanbanRecord[], entries: {
|
|
212
|
+
id: unknown;
|
|
213
|
+
record: KanbanRecord;
|
|
214
|
+
}[], options: {
|
|
215
|
+
recordId: string | ((record: KanbanRecord) => unknown);
|
|
216
|
+
columnBy: KanbanAccessor;
|
|
217
|
+
swimlaneBy: KanbanAccessor;
|
|
218
|
+
destination: KanbanMovePoint;
|
|
219
|
+
}): {
|
|
220
|
+
records: KanbanRecord[];
|
|
221
|
+
moves: {
|
|
222
|
+
id: unknown;
|
|
223
|
+
from: KanbanMovePoint;
|
|
224
|
+
}[];
|
|
225
|
+
to: KanbanMovePoint;
|
|
226
|
+
} | null;
|
|
227
|
+
/**
|
|
228
|
+
* Resolves one record's column, lane, and position within its bucket.
|
|
229
|
+
* @param {KanbanRecord[]} records Records.
|
|
230
|
+
* @param {number} index Position in `records`.
|
|
231
|
+
* @param {{recordId:string|((record:KanbanRecord)=>unknown),columnBy:KanbanAccessor,swimlaneBy:KanbanAccessor}} options Accessors.
|
|
232
|
+
* @returns {KanbanMovePoint} Location.
|
|
233
|
+
*/
|
|
234
|
+
export declare function locateKanbanRecord(records: KanbanRecord[], index: number, options: {
|
|
235
|
+
recordId: string | ((record: KanbanRecord) => unknown);
|
|
236
|
+
columnBy: KanbanAccessor;
|
|
237
|
+
swimlaneBy: KanbanAccessor;
|
|
238
|
+
}): KanbanMovePoint;
|
|
239
|
+
/**
|
|
240
|
+
* Translates a position among *rendered* cards into a position among all records in the same
|
|
241
|
+
* column and lane. Search and filters hide records without removing them, and a drop between two
|
|
242
|
+
* visible cards must land between them in the underlying data rather than at the same ordinal.
|
|
243
|
+
* @param {boolean[]} visibility Per-record visibility inside the bucket, in record order.
|
|
244
|
+
* @param {number} visibleIndex Zero-based position among the visible records.
|
|
245
|
+
* @returns {number} Zero-based position among all records in the bucket.
|
|
246
|
+
*/
|
|
247
|
+
export declare function absoluteKanbanIndex(visibility: boolean[], visibleIndex: number): number;
|
|
248
|
+
/**
|
|
249
|
+
* Reads a grouping accessor without touching field descriptors.
|
|
250
|
+
* @param {KanbanRecord} record Record.
|
|
251
|
+
* @param {number} index Display index.
|
|
252
|
+
* @param {KanbanAccessor} accessor Accessor.
|
|
253
|
+
* @returns {unknown} Raw value.
|
|
254
|
+
*/
|
|
255
|
+
export declare function readKanbanAccessor(record: KanbanRecord, index: number, accessor: KanbanAccessor): unknown;
|
|
256
|
+
/**
|
|
257
|
+
* Normalizes any grouping value to its stable string id.
|
|
258
|
+
* @param {unknown} value Raw value.
|
|
259
|
+
* @returns {string} Axis id.
|
|
260
|
+
*/
|
|
261
|
+
export declare function normalizeAxisId(value: unknown): string;
|
|
262
|
+
/**
|
|
263
|
+
* Clamps a requested position into an insertable range, treating anything unusable as "append".
|
|
264
|
+
* @param {unknown} value Requested index.
|
|
265
|
+
* @param {number} maximum Highest insertable position.
|
|
266
|
+
* @returns {number} Clamped index.
|
|
267
|
+
*/
|
|
268
|
+
export declare function clampKanbanIndex(value: unknown, maximum: number): number;
|