@joewinke/jatui 0.26.0 → 0.27.1

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 (73) hide show
  1. package/CLAUDE.md +106 -1
  2. package/dist/actions/keyboardScope.d.ts +58 -0
  3. package/dist/actions/keyboardScope.js +110 -0
  4. package/dist/actions/listNav.d.ts +48 -3
  5. package/dist/actions/listNav.js +267 -77
  6. package/dist/actions/longpress.d.ts +37 -0
  7. package/dist/actions/longpress.js +105 -0
  8. package/dist/actions/stickToBottom.d.ts +66 -0
  9. package/dist/actions/stickToBottom.js +155 -0
  10. package/dist/actions/swipe.d.ts +64 -0
  11. package/dist/actions/swipe.js +179 -0
  12. package/dist/components/BottomSheet.svelte +280 -0
  13. package/dist/components/BottomSheet.svelte.d.ts +27 -0
  14. package/dist/components/ConfirmDialog.svelte +21 -0
  15. package/dist/components/ConfirmDialog.svelte.d.ts +11 -1
  16. package/dist/components/ConfirmModal.svelte +15 -0
  17. package/dist/components/ConfirmModal.svelte.d.ts +5 -0
  18. package/dist/components/Drawer.svelte +18 -1
  19. package/dist/components/Drawer.svelte.d.ts +9 -1
  20. package/dist/components/InputDialog.svelte +21 -0
  21. package/dist/components/InputDialog.svelte.d.ts +11 -1
  22. package/dist/components/Modal.svelte +18 -1
  23. package/dist/components/Modal.svelte.d.ts +8 -0
  24. package/dist/components/basic/Empty.svelte +173 -9
  25. package/dist/components/basic/Empty.svelte.d.ts +50 -1
  26. package/dist/components/basic/ErrorState.svelte +128 -0
  27. package/dist/components/basic/ErrorState.svelte.d.ts +46 -0
  28. package/dist/components/basic/JumpToLatest.svelte +60 -0
  29. package/dist/components/basic/JumpToLatest.svelte.d.ts +9 -0
  30. package/dist/components/basic/PageHeader.svelte +216 -0
  31. package/dist/components/basic/PageHeader.svelte.d.ts +52 -0
  32. package/dist/components/basic/ProgressButton.svelte +221 -0
  33. package/dist/components/basic/ProgressButton.svelte.d.ts +63 -0
  34. package/dist/components/graph/GraphApiBridge.svelte +36 -0
  35. package/dist/components/graph/GraphApiBridge.svelte.d.ts +9 -0
  36. package/dist/components/graph/GraphCanvas.svelte +212 -27
  37. package/dist/components/graph/GraphCanvas.svelte.d.ts +113 -19
  38. package/dist/components/graph/api.d.ts +52 -0
  39. package/dist/components/graph/api.js +66 -0
  40. package/dist/components/graph/index.d.ts +2 -0
  41. package/dist/components/graph/index.js +1 -0
  42. package/dist/components/graph/theme.js +13 -0
  43. package/dist/components/messaging/MessageItem.svelte +5 -0
  44. package/dist/components/messaging/MessageItem.svelte.d.ts +7 -0
  45. package/dist/components/table/DataTable.svelte +452 -78
  46. package/dist/components/table/DataTable.svelte.d.ts +2 -2
  47. package/dist/components/table/ManageColumnsDropdown.svelte +466 -0
  48. package/dist/components/table/ManageColumnsDropdown.svelte.d.ts +26 -0
  49. package/dist/components/table/columnStorage.d.ts +29 -0
  50. package/dist/components/table/columnStorage.js +61 -0
  51. package/dist/components/table/groupRows.d.ts +72 -0
  52. package/dist/components/table/groupRows.js +118 -0
  53. package/dist/components/table/index.d.ts +7 -1
  54. package/dist/components/table/index.js +3 -0
  55. package/dist/components/table/types.d.ts +121 -20
  56. package/dist/index.d.ts +24 -2
  57. package/dist/index.js +36 -1
  58. package/dist/utils/ansiToHtml.d.ts +83 -0
  59. package/dist/utils/ansiToHtml.js +543 -0
  60. package/dist/utils/keyboardShortcutRegistry.d.ts +332 -11
  61. package/dist/utils/keyboardShortcutRegistry.js +1070 -76
  62. package/dist/utils/pollBackoff.d.ts +83 -0
  63. package/dist/utils/pollBackoff.js +151 -0
  64. package/dist/utils/snapFlick.d.ts +59 -0
  65. package/dist/utils/snapFlick.js +66 -0
  66. package/dist/video/advisors/qr.d.ts +1 -1
  67. package/dist/virtual/createRowWindow.d.ts +75 -0
  68. package/dist/virtual/createRowWindow.js +129 -0
  69. package/dist/virtual/index.d.ts +4 -0
  70. package/dist/virtual/index.js +5 -0
  71. package/dist/virtual/rowWindowCore.d.ts +202 -0
  72. package/dist/virtual/rowWindowCore.js +510 -0
  73. package/package.json +12 -2
@@ -0,0 +1,118 @@
1
+ /**
2
+ * groupRows — grouped render-list flattening (jatui-u6d4e.2).
3
+ *
4
+ * Spec: jat `docs/design/datatable-virtualisation-group-rows.md` §3.2.
5
+ *
6
+ * Turns an already filtered + sorted row array into the flat list a table (or a
7
+ * row window) renders: group header items interleaved with row items, nested to
8
+ * any number of levels. Pure, DOM-free and framework-free so it runs under
9
+ * node:test and can feed a virtualiser directly (one item = one rendered line).
10
+ *
11
+ * - Rows inside a group keep the order the caller passed in — the page's sort
12
+ * comparator and tiebreakers survive untouched. Only GROUPS are reordered,
13
+ * by `level.compare` (default: first-seen order).
14
+ * - A collapsed group still emits its header (with `collapsed: true` and the
15
+ * full `rows`/`count`) but nothing beneath it.
16
+ * - `showHeader` returning false hides that header: its rows (and subgroups)
17
+ * still render, one visual level shallower. A hidden header cannot be
18
+ * toggled, so `collapsed` is ignored for it.
19
+ * - `depth` is the VISUAL nesting level — the number of visible headers above
20
+ * the item — so hidden headers never leave an indentation gap. `path` /
21
+ * `groupPath` always carry the full key path.
22
+ * - `position` (first/middle/last/only) is computed over each contiguous run of
23
+ * rows under the same visible parent, which is what ├ / └ tree glyphs need.
24
+ */
25
+ /** Separator joining a group path into the key used by `collapsed`. */
26
+ export const GROUP_PATH_SEPARATOR = '::';
27
+ /** The `collapsed`-set key for a group path: ["jat", "jat-vte6e"] → "jat::jat-vte6e". */
28
+ export function groupPathKey(path) {
29
+ return path.join(GROUP_PATH_SEPARATOR);
30
+ }
31
+ /** Bucket rows by key, preserving first-seen key order and in-bucket row order. */
32
+ function bucket(rows, key) {
33
+ const out = new Map();
34
+ for (const row of rows) {
35
+ const k = key(row);
36
+ const list = out.get(k);
37
+ if (list)
38
+ list.push(row);
39
+ else
40
+ out.set(k, [row]);
41
+ }
42
+ return out;
43
+ }
44
+ export function groupRows(rows, levels, opts) {
45
+ const { getRowId, collapsed, label } = opts;
46
+ const items = [];
47
+ // Parallel to `items`: identity of the visible parent of each row item, so
48
+ // the position pass can tell a run of siblings from two adjacent runs.
49
+ const parents = [];
50
+ const walk = (groupRowsIn, levelIndex, path, depth, visibleParent) => {
51
+ if (levelIndex >= levels.length) {
52
+ for (const row of groupRowsIn) {
53
+ items.push({
54
+ kind: 'row',
55
+ row,
56
+ id: getRowId(row),
57
+ depth,
58
+ groupPath: path,
59
+ position: 'only'
60
+ });
61
+ parents.push(visibleParent);
62
+ }
63
+ return;
64
+ }
65
+ const level = levels[levelIndex];
66
+ const buckets = bucket(groupRowsIn, level.key);
67
+ const keys = [...buckets.keys()];
68
+ // Array.prototype.sort is stable, so equal keys keep first-seen order.
69
+ if (level.compare)
70
+ keys.sort(level.compare);
71
+ for (const key of keys) {
72
+ const members = buckets.get(key);
73
+ const groupPath = [...path, key];
74
+ const shown = level.showHeader ? level.showHeader(key, members) : true;
75
+ if (!shown) {
76
+ walk(members, levelIndex + 1, groupPath, depth, visibleParent);
77
+ continue;
78
+ }
79
+ const pathKey = groupPathKey(groupPath);
80
+ const isCollapsed = collapsed.has(pathKey);
81
+ items.push({
82
+ kind: 'group',
83
+ key,
84
+ path: groupPath,
85
+ depth,
86
+ label: label ? label(groupPath) : key,
87
+ rows: members,
88
+ count: members.length,
89
+ collapsed: isCollapsed
90
+ });
91
+ parents.push(null);
92
+ if (!isCollapsed)
93
+ walk(members, levelIndex + 1, groupPath, depth + 1, pathKey);
94
+ }
95
+ };
96
+ // The root parent can't collide with a real path key: those are all built
97
+ // from keys at least one level deep, and the root is only used at depth 0.
98
+ walk(rows, 0, [], 0, '\u0000root');
99
+ // Position pass: a run is consecutive row items sharing one visible parent.
100
+ let i = 0;
101
+ while (i < items.length) {
102
+ if (items[i].kind !== 'row') {
103
+ i++;
104
+ continue;
105
+ }
106
+ let j = i;
107
+ while (j + 1 < items.length && items[j + 1].kind === 'row' && parents[j + 1] === parents[i])
108
+ j++;
109
+ if (j > i) {
110
+ items[i].position = 'first';
111
+ for (let k = i + 1; k < j; k++)
112
+ items[k].position = 'middle';
113
+ items[j].position = 'last';
114
+ }
115
+ i = j + 1;
116
+ }
117
+ return items;
118
+ }
@@ -1,5 +1,11 @@
1
1
  export { default as DataTable } from './DataTable.svelte';
2
+ export { default as ManageColumnsDropdown } from './ManageColumnsDropdown.svelte';
3
+ export type { ManageColumnsProps } from './ManageColumnsDropdown.svelte';
4
+ export { saveColumnSettings, loadColumnSettings } from './columnStorage.js';
5
+ export type { ColumnSettings } from './columnStorage.js';
2
6
  export { flexRender } from './flexRender';
3
7
  export { columnResize } from './columnResize';
4
8
  export type { ColumnResizeOptions } from './columnResize';
5
- export type { DataTableProps, DataTableApi, DataTableRowProps, DataTableHeaderProps, DataTableSortEvent, DataTableVariant, GroupedItem, SelectionEvent, ColumnDef, Row, SortingState } from './types';
9
+ export type { DataTableProps, DataTableApi, DataTableRowProps, DataTableHeaderProps, DataTableSortEvent, DataTableVariant, DataTableVirtualOptions, DataTableRowWindow, DataTableRowWindowOptions, DataTableRenderItem, DataTableGroupHeaderContext, SelectionEvent, ColumnDef, Row, SortingState } from './types';
10
+ export { groupRows, groupPathKey, GROUP_PATH_SEPARATOR } from './groupRows';
11
+ export type { GroupLevel, GroupedItem, GroupedGroupItem, GroupedRowItem, GroupedRowPosition, GroupRowsOptions } from './groupRows';
@@ -1,4 +1,7 @@
1
1
  // Subpath entry: @joewinke/jatui/table — requires peer @tanstack/table-core.
2
2
  export { default as DataTable } from './DataTable.svelte';
3
+ export { default as ManageColumnsDropdown } from './ManageColumnsDropdown.svelte';
4
+ export { saveColumnSettings, loadColumnSettings } from './columnStorage.js';
3
5
  export { flexRender } from './flexRender';
4
6
  export { columnResize } from './columnResize';
7
+ export { groupRows, groupPathKey, GROUP_PATH_SEPARATOR } from './groupRows';
@@ -2,29 +2,88 @@ import type { Snippet } from 'svelte';
2
2
  import type { ColumnDef, Row, SortingState } from '@tanstack/table-core';
3
3
  export type { ColumnDef, Row, SortingState };
4
4
  /**
5
- * One entry in the table's render list. Today DataTable renders flat rows, so
6
- * every item is `kind: 'row'` with `depth: 0`; the `group` variant is the shape
7
- * the grouped render list (`groupRows`, design doc
8
- * jat/docs/design/datatable-virtualisation-group-rows.md §3.2) will produce, so
9
- * `rowProps` callers written now keep working when grouping lands.
5
+ * One entry in the table's render list. Flat tables render `kind: 'row'` items
6
+ * with `depth: 0`; with `groupBy`, `groupRows` interleaves `kind: 'group'`
7
+ * header items. Defined in ./groupRows.
10
8
  */
11
- export type GroupedItem<T = any> = {
12
- kind: 'group';
13
- key: string;
14
- path: string[];
15
- depth: number;
16
- label: string;
17
- rows: T[];
18
- count: number;
19
- collapsed: boolean;
20
- } | {
21
- kind: 'row';
22
- row: T;
9
+ import type { GroupedItem, GroupedGroupItem, GroupLevel } from './groupRows';
10
+ export type { GroupedItem };
11
+ /**
12
+ * An item of the windowed render list, as `virtual.estimateRowSize` sees it: a
13
+ * group header, a data row, or the detail row under an expanded row.
14
+ */
15
+ export type DataTableRenderItem<TData = any> = GroupedItem<TData> | {
16
+ kind: 'detail';
17
+ row: TData;
23
18
  id: string;
24
- depth: number;
25
- groupPath: string[];
26
- position: 'first' | 'middle' | 'last' | 'only';
27
19
  };
20
+ /**
21
+ * The slice of `createRowWindow`'s options DataTable drives. Declared
22
+ * structurally here so `@joewinke/jatui/table` never imports the
23
+ * `@tanstack/virtual-core` peer — the caller hands the factory in.
24
+ */
25
+ export interface DataTableRowWindowOptions {
26
+ count: () => number;
27
+ getKey: (index: number) => string;
28
+ estimateSize: (index: number) => number;
29
+ scrollRoot?: HTMLElement | Window | 'auto';
30
+ overscan?: number;
31
+ pinned?: () => Iterable<string>;
32
+ threshold?: number;
33
+ stickyIndices?: () => readonly (readonly number[])[];
34
+ scrollPaddingStart?: number;
35
+ scrollPaddingEnd?: number;
36
+ initialViewportSize?: number;
37
+ }
38
+ /** The slice of `createRowWindow`'s return value DataTable reads. */
39
+ export interface DataTableRowWindow {
40
+ readonly items: ReadonlyArray<{
41
+ index: number;
42
+ key: string;
43
+ gapBefore: number;
44
+ }>;
45
+ readonly paddingTop: number;
46
+ readonly paddingBottom: number;
47
+ readonly windowed: boolean;
48
+ measure: (node: HTMLElement, key: string) => {
49
+ update?(key: string): void;
50
+ destroy(): void;
51
+ };
52
+ anchor: (node: HTMLElement) => {
53
+ destroy(): void;
54
+ };
55
+ scrollToKey(key: string, opts?: {
56
+ align?: 'auto' | 'start' | 'center' | 'end';
57
+ }): void;
58
+ }
59
+ /**
60
+ * Windowed body (grid mode). Pass `createRowWindow` from
61
+ * `@joewinke/jatui/virtual` — DataTable never imports it itself, so tables
62
+ * that don't window need not install the optional `@tanstack/virtual-core`.
63
+ * Read once at mount: toggling windowing on an existing table is not supported.
64
+ */
65
+ export interface DataTableVirtualOptions<TData = any> {
66
+ createRowWindow: (opts: DataTableRowWindowOptions) => DataTableRowWindow;
67
+ /** First-paint height guess, px. Default: 40 rows, 36 group headers, 120 detail rows. */
68
+ estimateRowSize?: number | ((item: DataTableRenderItem<TData>) => number);
69
+ /** Extra items rendered above and below the viewport. Default 6. */
70
+ overscan?: number;
71
+ /** Below this many render items, draw everything (keeps enter animations). Default 0. */
72
+ threshold?: number;
73
+ /** The element that scrolls. Default `'auto'` = nearest ancestor that really scrolls. */
74
+ scrollRoot?: HTMLElement | Window | 'auto';
75
+ /** Height a sticky header covers at the top, px — `scrollToRow` keeps targets below it. */
76
+ scrollPaddingStart?: number;
77
+ }
78
+ /** Context handed to the `groupHeader` snippet. */
79
+ export interface DataTableGroupHeaderContext {
80
+ /** Collapse / expand this group (updates `collapsed`). */
81
+ toggle(): void;
82
+ /** Number of columns — give your header cell `colspan={colspan}`. */
83
+ colspan: number;
84
+ collapsed: boolean;
85
+ }
86
+ export type { GroupedGroupItem, GroupLevel };
28
87
  /** What `rowProps` may put on a body `<tr>`. */
29
88
  export interface DataTableRowProps {
30
89
  class?: string;
@@ -124,6 +183,48 @@ export interface DataTableProps<TData = any> {
124
183
  tableClass?: string;
125
184
  /** Imperative handle — `bind:api`. */
126
185
  api?: DataTableApi;
186
+ /**
187
+ * Group levels, outermost first (0 levels = flat). Rows keep the table's
188
+ * order inside each group; groups are ordered by `level.compare`. With
189
+ * `paginated`, each page is grouped on its own.
190
+ */
191
+ groupBy?: GroupLevel<TData>[];
192
+ /** Collapsed group path keys (see `groupPathKey`) — `bind:collapsed`. Unbound, the table owns it. */
193
+ collapsed?: Set<string>;
194
+ /** Fires whenever a group is collapsed or expanded — persist it here. */
195
+ onCollapsedChange?: (next: Set<string>) => void;
196
+ /** Header label for a group path. Default: the group's own key. */
197
+ groupLabel?: (path: string[]) => string;
198
+ /**
199
+ * Renders the CELLS of a group header row (the `<tr>` is the table's). Give
200
+ * the cell `colspan={ctx.colspan}`. Default: one full-width cell with a
201
+ * collapse toggle, the label and the row count.
202
+ */
203
+ groupHeader?: Snippet<[GroupedGroupItem<TData>, DataTableGroupHeaderContext]>;
204
+ /** Group header rows stick below the (sticky) thead while their rows scroll past. */
205
+ stickyGroupHeaders?: boolean;
206
+ /** The thead sticks to the top of the scroll container. */
207
+ stickyHeader?: boolean;
208
+ /**
209
+ * Make the table its own vertical scroller (`max-height` + overflow auto),
210
+ * e.g. `'70vh'`. Without it, sticky headers stick against the page's
211
+ * scroller and horizontal overflow is clipped rather than scrolled.
212
+ */
213
+ maxHeight?: string;
214
+ /** Windowed body via `createRowWindow` — see DataTableVirtualOptions. */
215
+ virtual?: DataTableVirtualOptions<TData>;
216
+ /** Row ids that stay rendered while windowed (focused row, open editor, exit animation). */
217
+ pinnedRowIds?: Iterable<string>;
218
+ /**
219
+ * Expose ARIA grid semantics: `role="grid"` (`"treegrid"` with `groupBy`),
220
+ * `aria-selected` on rows when `selectable`, `aria-level` / `aria-expanded`
221
+ * on grouped rows, `aria-rowindex` / `aria-rowcount`. The host supplies row
222
+ * focus movement (e.g. `listNav`). Windowed tables always get the
223
+ * rowindex / rowcount pair so assistive tech knows rows are missing.
224
+ */
225
+ ariaGrid?: boolean;
226
+ /** Accessible name for the `<table>`. */
227
+ ariaLabel?: string;
127
228
  }
128
229
  export interface SelectionEvent<TData> {
129
230
  rows: TData[];
package/dist/index.d.ts CHANGED
@@ -5,6 +5,12 @@ export type { ListNavOptions, ListNavController } from './actions/listNav';
5
5
  export { collapse } from './actions/collapse';
6
6
  export type { CollapseOptions } from './actions/collapse';
7
7
  export { default as Collapse } from './components/Collapse.svelte';
8
+ export { keyboardScope, createKeyboardScope, comboFor } from './actions/keyboardScope';
9
+ export type { KeyboardScope, KeyboardScopeHandlers } from './actions/keyboardScope';
10
+ export { PollBackoff, createPollLoop, computeBackoffDelayMs } from './utils/pollBackoff';
11
+ export type { PollBackoffOptions } from './utils/pollBackoff';
12
+ export { default as PageHeader } from './components/basic/PageHeader.svelte';
13
+ export { default as ProgressButton } from './components/basic/ProgressButton.svelte';
8
14
  export { default as LinkedColumns } from './components/linked-columns/LinkedColumns.svelte';
9
15
  export type { ColumnLink } from './components/linked-columns/types.js';
10
16
  export { default as ChapterTimeline } from './components/replay/ChapterTimeline.svelte';
@@ -176,8 +182,8 @@ export type { MarkupTool, Point, MarkupShape, ArrowShape, RectangleShape, Ellips
176
182
  export type { Annotation, AnnotationProfile, AnnotationThread, AnnotationCallbacks, } from './types/annotation';
177
183
  export { default as KeyboardShortcutsOverlay } from './components/KeyboardShortcutsOverlay.svelte';
178
184
  export type { KeyboardShortcut, SectionEntry as KeyboardShortcutSectionEntry, ShortcutSection as KeyboardShortcutSection, } from './components/KeyboardShortcutsOverlay.svelte';
179
- export { createShortcutRegistry, getShortcutRegistry, formatShortcut, parseCombo as parseShortcutCombo, isTypingTarget, detectPlatform as detectShortcutPlatform, SIDEBAR_TOGGLE_KEY, } from './utils/keyboardShortcutRegistry';
180
- export type { ShortcutRegistry, ShortcutDefinition, ShortcutModifier, ShortcutPlatform, PushContextOptions as ShortcutContextOptions, RegistrySection as ShortcutRegistrySection, ToSectionsOptions as ShortcutSectionsOptions, ShortcutRegistryOptions, ShortcutEventTarget, } from './utils/keyboardShortcutRegistry';
185
+ export { createShortcutRegistry, getShortcutRegistry, formatShortcut, parseCombo as parseShortcutCombo, isTypingTarget, detectPlatform as detectShortcutPlatform, SIDEBAR_TOGGLE_KEY, normalizeCombo, comboFromEvent, validateCombo, localStorageBindingStore, BROWSER_RESERVED_COMBOS, } from './utils/keyboardShortcutRegistry';
186
+ export type { ShortcutRegistry, ShortcutDefinition, ShortcutModifier, ShortcutPlatform, PushContextOptions as ShortcutContextOptions, RegistrySection as ShortcutRegistrySection, ToSectionsOptions as ShortcutSectionsOptions, ShortcutRegistryOptions, ShortcutEventTarget, ShortcutDeclaration, BindingOverrides, BindingStore, BindingInfo, ShortcutConflict, ShortcutConflictSeverity, FindConflictsTarget, AllConflictsOptions as ShortcutAllConflictsOptions, ReservedCombo, RebindResult, RebindOptions as ShortcutRebindOptions, RejectedBinding, RawShortcutHandler, ModifierState as ShortcutModifierState, } from './utils/keyboardShortcutRegistry';
181
187
  export { default as MapView } from './components/MapView.svelte';
182
188
  export { default as LocationMap } from './components/LocationMap.svelte';
183
189
  export { default as GPSTracker } from './components/GPSTracker.svelte';
@@ -227,8 +233,17 @@ export { default as SidebarItem } from './components/shell/SidebarItem.svelte';
227
233
  export { default as NavigationMenu } from './components/shell/NavigationMenu.svelte';
228
234
  export { createSidebarState } from './components/shell/shell';
229
235
  export type { SidebarMode, SidebarState } from './components/shell/shell';
236
+ export { groupRows, groupPathKey, GROUP_PATH_SEPARATOR } from './components/table/groupRows';
237
+ export type { GroupLevel, GroupedItem, GroupedGroupItem, GroupedRowItem, GroupedRowPosition, GroupRowsOptions } from './components/table/groupRows';
230
238
  export { default as Kbd } from './components/basic/Kbd.svelte';
231
239
  export { default as Empty } from './components/basic/Empty.svelte';
240
+ export { default as ErrorState } from './components/basic/ErrorState.svelte';
241
+ export type { EmptyGlyph } from './components/basic/Empty.svelte';
242
+ export { default as JumpToLatest } from './components/basic/JumpToLatest.svelte';
243
+ export { createStickToBottom } from './actions/stickToBottom';
244
+ export type { StickState, StickToBottomOptions, StickController } from './actions/stickToBottom';
245
+ export { ansiToHtml, ansiToHtmlStateful, ansiToHtmlWithLinks, ansiToHtmlWithHierarchy, linkifyUrls, stripAnsi, classifyLine, parseOutputLines, createDefaultAnsiState } from './utils/ansiToHtml';
246
+ export type { AnsiState, ParsedLine } from './utils/ansiToHtml';
232
247
  export { default as Breadcrumb } from './components/basic/Breadcrumb.svelte';
233
248
  export { default as Alert } from './components/basic/Alert.svelte';
234
249
  export { default as ButtonGroup } from './components/basic/ButtonGroup.svelte';
@@ -255,6 +270,13 @@ export { useElapsedEstimate } from './components/batch/useElapsedEstimate';
255
270
  export type { ElapsedEstimate } from './components/batch/useElapsedEstimate';
256
271
  export { pollOperation, PollTimeoutError } from './components/batch/pollOperation';
257
272
  export type { PollStep, PollContext, PollOptions } from './components/batch/pollOperation';
273
+ export { swipe } from './actions/swipe';
274
+ export type { SwipeOptions } from './actions/swipe';
275
+ export { longpress } from './actions/longpress';
276
+ export type { LongPressOptions, LongPressDetail } from './actions/longpress';
277
+ export { resolveSnapTarget, keyboardInsetPx, clampSnapHeight, FLICK_VELOCITY_PX_MS } from './utils/snapFlick';
278
+ export type { SnapName, SnapHeight, SnapInput, SnapResult } from './utils/snapFlick';
279
+ export { default as BottomSheet } from './components/BottomSheet.svelte';
258
280
  export { default as VariantMatrixPicker } from './components/variant/VariantMatrixPicker.svelte';
259
281
  export { countCombinations, generateCombinations, generateVariantFilename, findVariantOption, variantCategoryMode } from './components/variant/variantCombinations';
260
282
  export type { VariantCategory, VariantOption, VariantSelection, VariantSelectionMode, VariantCombination } from './components/variant/variantCombinations';
package/dist/index.js CHANGED
@@ -3,6 +3,26 @@ export { railNav, createRailNav, cycle } from './actions/railNav';
3
3
  export { listNav, createListNav } from './actions/listNav';
4
4
  export { collapse } from './actions/collapse';
5
5
  export { default as Collapse } from './components/Collapse.svelte';
6
+ // Keyboard scope (upstreamed from the JAT IDE — jatui-rl7w6.5, audit U6):
7
+ // embed-safe shortcuts for a self-contained widget living in a busy host
8
+ // page — ownership decided from DOM engagement (what was last clicked/focused),
9
+ // the container-local complement to the shortcut registry's context stack.
10
+ export { keyboardScope, createKeyboardScope, comboFor } from './actions/keyboardScope';
11
+ // Poll loop with coordinated exponential backoff (upstreamed from the JAT IDE
12
+ // — jatui-rl7w6.5, audit U12): the recurring-poll companion to pollOperation.
13
+ // Framework-free; skips ticks while the document is hidden, never overlaps
14
+ // ticks, backs off exponentially with jitter capped at maxIntervalMs.
15
+ export { PollBackoff, createPollLoop, computeBackoffDelayMs } from './utils/pollBackoff';
16
+ // Page chrome (upstreamed from the JAT IDE — jatui-rl7w6.5, audit U7):
17
+ // PageHeader, the standard route header, and ProgressButton, the
18
+ // phase-narrating async submit button.
19
+ export { default as PageHeader } from './components/basic/PageHeader.svelte';
20
+ export { default as ProgressButton } from './components/basic/ProgressButton.svelte';
21
+ // NOTE: ContextMenuTrigger is exported ONCE — grouped with ContextMenu further
22
+ // down. 0.27.0 shipped it twice here and in the ContextMenu section, and the
23
+ // duplicated `export` in dist/index.js / index.d.ts hard-failed every
24
+ // rolldown/vite consumer build ('[PARSE_ERROR] Duplicated export'). Guarded by
25
+ // tests/unit/indexBarrelExports.test.ts + scripts/verify-dist.mjs (check 4).
6
26
  // Components — Session primitives (from JAT IDE, jat-jj79f.16 G1)
7
27
  export { default as LinkedColumns } from './components/linked-columns/LinkedColumns.svelte';
8
28
  export { default as ChapterTimeline } from './components/replay/ChapterTimeline.svelte';
@@ -193,7 +213,7 @@ export { default as AnnotationPanel } from './components/AnnotationPanel.svelte'
193
213
  export { MARKUP_COLORS, DEFAULT_STROKE_WIDTH, renderShape, renderAllShapes, nextShapeId, } from './components/markup';
194
214
  // Components — Keyboard Navigation
195
215
  export { default as KeyboardShortcutsOverlay } from './components/KeyboardShortcutsOverlay.svelte';
196
- export { createShortcutRegistry, getShortcutRegistry, formatShortcut, parseCombo as parseShortcutCombo, isTypingTarget, detectPlatform as detectShortcutPlatform, SIDEBAR_TOGGLE_KEY, } from './utils/keyboardShortcutRegistry';
216
+ export { createShortcutRegistry, getShortcutRegistry, formatShortcut, parseCombo as parseShortcutCombo, isTypingTarget, detectPlatform as detectShortcutPlatform, SIDEBAR_TOGGLE_KEY, normalizeCombo, comboFromEvent, validateCombo, localStorageBindingStore, BROWSER_RESERVED_COMBOS, } from './utils/keyboardShortcutRegistry';
197
217
  // Components — Google Maps (DispatchMap fork + location primitives)
198
218
  export { default as MapView } from './components/MapView.svelte';
199
219
  export { default as LocationMap } from './components/LocationMap.svelte';
@@ -265,9 +285,18 @@ export { createSidebarState } from './components/shell/shell';
265
285
  // import { DataTable, flexRender } from '@joewinke/jatui/table'; (@tanstack/table-core)
266
286
  // import { GraphCanvas } from '@joewinke/jatui/graph'; (@xyflow/svelte)
267
287
  // import { Carousel } from '@joewinke/jatui/carousel'; (embla-carousel-svelte)
288
+ // groupRows is pure (no @tanstack peer), so it is also safe on the barrel —
289
+ // same function as '@joewinke/jatui/table' exports (jatui-u6d4e.2).
290
+ export { groupRows, groupPathKey, GROUP_PATH_SEPARATOR } from './components/table/groupRows';
268
291
  // Basic primitives (thin DaisyUI wraps — layering policy)
269
292
  export { default as Kbd } from './components/basic/Kbd.svelte';
270
293
  export { default as Empty } from './components/basic/Empty.svelte';
294
+ export { default as ErrorState } from './components/basic/ErrorState.svelte';
295
+ export { default as JumpToLatest } from './components/basic/JumpToLatest.svelte';
296
+ // Streaming-transcript auto-scroll (upstreamed from the JAT IDE, U3 — jatui-rl7w6.3).
297
+ export { createStickToBottom } from './actions/stickToBottom';
298
+ // ANSI terminal output → HTML (upstreamed from the JAT IDE, U5 — jatui-rl7w6.3).
299
+ export { ansiToHtml, ansiToHtmlStateful, ansiToHtmlWithLinks, ansiToHtmlWithHierarchy, linkifyUrls, stripAnsi, classifyLine, parseOutputLines, createDefaultAnsiState } from './utils/ansiToHtml';
271
300
  export { default as Breadcrumb } from './components/basic/Breadcrumb.svelte';
272
301
  export { default as Alert } from './components/basic/Alert.svelte';
273
302
  export { default as ButtonGroup } from './components/basic/ButtonGroup.svelte';
@@ -289,6 +318,12 @@ export { toJobRows, nextJobsToStart, isProcessLimitReached, moveJob, summarizeJo
289
318
  export { rollingAverage, estimateRemainingMs } from './components/batch/elapsedEstimate';
290
319
  export { useElapsedEstimate } from './components/batch/useElapsedEstimate';
291
320
  export { pollOperation, PollTimeoutError } from './components/batch/pollOperation';
321
+ // Mobile gesture kit (upstreamed from the JAT IDE — jatui-rl7w6.2):
322
+ // swipe + longpress actions, snapFlick math and the BottomSheet primitive.
323
+ export { swipe } from './actions/swipe';
324
+ export { longpress } from './actions/longpress';
325
+ export { resolveSnapTarget, keyboardInsetPx, clampSnapHeight, FLICK_VELOCITY_PX_MS } from './utils/snapFlick';
326
+ export { default as BottomSheet } from './components/BottomSheet.svelte';
292
327
  // Variant matrix picker + combination algebra (harvested from vid-gen FrameVariantGenerator — jatui-m4uz3.8).
293
328
  export { default as VariantMatrixPicker } from './components/variant/VariantMatrixPicker.svelte';
294
329
  export { countCombinations, generateCombinations, generateVariantFilename, findVariantOption, variantCategoryMode } from './components/variant/variantCombinations';
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Convert ANSI escape codes to HTML spans with inline styles
3
+ * Supports common color codes used by Claude Code / terminal output
4
+ * Includes automatic contrast adjustment for background colors
5
+ */
6
+ export interface AnsiState {
7
+ bold: boolean;
8
+ dim: boolean;
9
+ italic: boolean;
10
+ underline: boolean;
11
+ reverse: boolean;
12
+ color: string | null;
13
+ bgColor: string | null;
14
+ }
15
+ export declare function createDefaultAnsiState(): AnsiState;
16
+ /**
17
+ * Convert a string containing ANSI escape codes to HTML
18
+ */
19
+ export declare function ansiToHtml(input: string): string;
20
+ /** Strip ANSI codes from a string (for plain text).
21
+ *
22
+ * THE one ANSI stripper for the IDE (jat-69f8v dedup): every consumer that
23
+ * needs plain text without escape codes imports this — do not write a local
24
+ * copy (scripts/grep-gate-helper-dedup.sh refuses new definitions).
25
+ *
26
+ * Bare-escape handling is a strict ECMA-48 parse (jat-ybwwn): the old rule
27
+ * \x1b[^\[]\S* ate the escape AND every following non-space character, so
28
+ * "\x1b7hello" (DECSC + text) lost "hello". Escapes are now matched
29
+ * sequence-by-sequence; text after a two-byte escape survives.
30
+ */
31
+ export declare function stripAnsi(input: string): string;
32
+ /**
33
+ * Convert URLs in HTML to clickable links
34
+ * Must be called AFTER ansiToHtml to avoid breaking span tags
35
+ */
36
+ export declare function linkifyUrls(html: string): string;
37
+ /**
38
+ * Convert ANSI to HTML and make URLs clickable
39
+ */
40
+ export declare function ansiToHtmlWithLinks(input: string): string;
41
+ /**
42
+ * Convert ANSI multi-line output to HTML with per-line hierarchy classes.
43
+ * Wraps each line in <span class="tl-{kind}"> so CSS can mute tool calls
44
+ * and brighten prose without per-line DOM nodes.
45
+ *
46
+ * Intended for <pre>-based surfaces that render the whole output string
47
+ * at once (OverlayTerminal) where individual div wrappers aren't available.
48
+ */
49
+ export declare function ansiToHtmlWithHierarchy(input: string): string;
50
+ /**
51
+ * Convert ANSI to HTML starting from a given ANSI state, returning the end state.
52
+ * Enables incremental parsing: call with the end state of the previous segment to
53
+ * continue rendering without re-processing already-seen content.
54
+ */
55
+ export declare function ansiToHtmlStateful(input: string, startState: AnsiState): {
56
+ html: string;
57
+ endState: AnsiState;
58
+ };
59
+ export interface ParsedLine {
60
+ content: string;
61
+ html: string;
62
+ endState: AnsiState;
63
+ /** Visual hierarchy class: 'tc' = tool-call header, 'tr' = tool-result, 'td' = tool-detail, '' = prose */
64
+ lineClass: string;
65
+ }
66
+ /**
67
+ * Classify a raw terminal line for visual hierarchy rendering.
68
+ *
69
+ * Claude Code tool calls follow a predictable ANSI pattern:
70
+ * - Tool call header: ANSI-colored ● (U+25CF) or ⏺ (U+23FA) followed by bold tool name
71
+ * - Tool result: " ⎿ " prefix (2 spaces + U+23BF)
72
+ * - Tool detail: 5-space indent + dim content (folded result body)
73
+ * - Separator: Line of ─ or ━ box-drawing characters
74
+ *
75
+ * Returns a short CSS class suffix: 'tc' | 'tr' | 'td' | 'sep' | '' (prose)
76
+ */
77
+ export declare function classifyLine(raw: string): string;
78
+ /**
79
+ * Parse an array of raw line strings into ParsedLine records.
80
+ * Each line's ANSI end state is passed as the start state for the next line,
81
+ * so color/bold/etc. carry across line boundaries correctly.
82
+ */
83
+ export declare function parseOutputLines(rawLines: string[], startState: AnsiState): ParsedLine[];