@zeyos/zx 4.3.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +111 -1
  2. package/README.md +0 -3
  3. package/dist/types/components/calendar/calendar-model.d.ts +22 -0
  4. package/dist/types/components/card-view/card-view.d.ts +1 -1
  5. package/dist/types/components/card-view/record-card.d.ts +47 -5
  6. package/dist/types/components/kanban-view/kanban-policy.d.ts +268 -0
  7. package/dist/types/components/kanban-view/kanban-view.d.ts +669 -24
  8. package/dist/types/core/component.d.ts +6 -1
  9. package/dist/types/index.d.ts +2 -1
  10. package/dist/zx-zeyos.esm.js +35 -11
  11. package/dist/zx-zeyos.esm.min.js +1 -1
  12. package/dist/zx.css +597 -78
  13. package/dist/zx.esm.js +1758 -238
  14. package/dist/zx.esm.min.js +3 -3
  15. package/dist/zx.global.js +1758 -238
  16. package/dist/zx.global.min.js +3 -3
  17. package/dist/zx.min.css +1 -1
  18. package/docs/api.json +214 -2
  19. package/docs/llms.md +30 -30
  20. package/docs/llms.txt +0 -2
  21. package/package.json +1 -2
  22. package/src/components/calendar/calendar-model.js +45 -0
  23. package/src/components/calendar/calendar.css +30 -10
  24. package/src/components/calendar/calendar.js +8 -10
  25. package/src/components/card-view/card-view.css +211 -9
  26. package/src/components/card-view/card-view.js +7 -7
  27. package/src/components/card-view/record-card.js +92 -19
  28. package/src/components/kanban-view/kanban-policy.js +412 -0
  29. package/src/components/kanban-view/kanban-view.css +480 -36
  30. package/src/components/kanban-view/kanban-view.js +1514 -235
  31. package/src/components/message/message.css +9 -10
  32. package/src/core/component.js +8 -3
  33. package/src/index.js +8 -3
  34. package/DESIGN-SYSTEM.md +0 -182
package/CHANGELOG.md CHANGED
@@ -8,6 +8,116 @@ 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
+
11
121
  ## 4.3.0 — 2026-08-26
12
122
 
13
123
  ### Added
@@ -67,7 +177,7 @@ and friends remain the complete record.
67
177
  - **Aurora surfaces.** `Aurora` adds a dependency-free, one- to four-colour ambient-light layer
68
178
  with six geometries, bounded palettes and intensity, CSS-only composition, and deterministic
69
179
  reduced-motion, reduced-transparency, and forced-colour fallbacks. The documentation includes a
70
- live application composition and an earlier-studies comparison page.
180
+ live application composition and examples for all six supported geometries.
71
181
 
72
182
  ### Changed
73
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:
@@ -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.
@@ -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='18rem'] Responsive minimum card width.
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 it carries
204
- * `aria-selected`; multi-selection adds a native checkbox. It deliberately retains list-item
205
- * semantics rather than becoming an ARIA option because cards may contain native links and
206
- * buttons, which the listbox pattern does not permit inside an option. Preview images are paired
207
- * with a stable fallback. The owning component listens for image `error` and marks the fallback.
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.
@@ -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;