@joewinke/jatui 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/CLAUDE.md +47 -1
  2. package/dist/actions/reveal.d.ts +37 -0
  3. package/dist/actions/reveal.js +42 -0
  4. package/dist/components/AudioRecorder.svelte +749 -0
  5. package/dist/components/AudioRecorder.svelte.d.ts +36 -0
  6. package/dist/components/IconSelector.svelte +417 -0
  7. package/dist/components/IconSelector.svelte.d.ts +55 -0
  8. package/dist/components/InfiniteGrid.svelte +305 -0
  9. package/dist/components/InfiniteGrid.svelte.d.ts +71 -0
  10. package/dist/components/InfiniteSearchGrid.svelte +131 -0
  11. package/dist/components/InfiniteSearchGrid.svelte.d.ts +67 -0
  12. package/dist/components/KeyboardShortcutsOverlay.svelte +40 -3
  13. package/dist/components/KeyboardShortcutsOverlay.svelte.d.ts +31 -16
  14. package/dist/components/MediaCaptureIcon.svelte +23 -0
  15. package/dist/components/MediaCaptureIcon.svelte.d.ts +1 -1
  16. package/dist/components/ThumbnailGrid.svelte +137 -0
  17. package/dist/components/ThumbnailGrid.svelte.d.ts +42 -0
  18. package/dist/components/batch/BatchJobTable.svelte +549 -0
  19. package/dist/components/batch/BatchJobTable.svelte.d.ts +114 -0
  20. package/dist/components/batch/QuotaMeter.svelte +78 -0
  21. package/dist/components/batch/QuotaMeter.svelte.d.ts +16 -0
  22. package/dist/components/batch/batchQueue.d.ts +56 -0
  23. package/dist/components/batch/batchQueue.js +81 -0
  24. package/dist/components/batch/elapsedEstimate.d.ts +24 -0
  25. package/dist/components/batch/elapsedEstimate.js +25 -0
  26. package/dist/components/batch/pollOperation.d.ts +45 -0
  27. package/dist/components/batch/pollOperation.js +80 -0
  28. package/dist/components/batch/useElapsedEstimate.d.ts +10 -0
  29. package/dist/components/batch/useElapsedEstimate.js +38 -0
  30. package/dist/components/infiniteGridLoader.d.ts +70 -0
  31. package/dist/components/infiniteGridLoader.js +141 -0
  32. package/dist/components/table/columnResize.d.ts +38 -0
  33. package/dist/components/table/columnResize.js +117 -0
  34. package/dist/components/table/index.d.ts +2 -0
  35. package/dist/components/table/index.js +1 -0
  36. package/dist/components/variant/VariantMatrixPicker.svelte +181 -0
  37. package/dist/components/variant/VariantMatrixPicker.svelte.d.ts +37 -0
  38. package/dist/components/variant/variantCombinations.d.ts +75 -0
  39. package/dist/components/variant/variantCombinations.js +100 -0
  40. package/dist/history.d.ts +44 -0
  41. package/dist/history.js +87 -0
  42. package/dist/index.d.ts +30 -0
  43. package/dist/index.js +27 -0
  44. package/dist/styles/motion.css +100 -0
  45. package/dist/utils/keyboardShortcutRegistry.d.ts +152 -0
  46. package/dist/utils/keyboardShortcutRegistry.js +365 -0
  47. package/package.json +5 -1
@@ -1,20 +1,30 @@
1
1
  /**
2
- * KeyboardShortcutsOverlay — press `?` to toggle a modal listing the
3
- * keyboard shortcuts available on the current page. Press `?` again or
4
- * `Escape` to dismiss. Input/contenteditable fields and Ctrl/Meta/Alt
5
- * combos are ignored so the shortcut never interferes with typing.
6
- *
7
- * While open, physical keydown events depress the matching on-screen keycap
8
- * with a brief translateY(1px) + tint (var(--motion-instant)).
9
- *
10
- * Usage:
11
- *
12
- * <KeyboardShortcutsOverlay shortcuts={[
13
- * { key: 'j / ↓', description: 'Focus next item' },
14
- * { key: 'k / ↑', description: 'Focus previous item' },
15
- * { key: 'Enter', description: 'Open detail' },
16
- * ]} />
17
- */
2
+ * KeyboardShortcutsOverlay — press `?` to toggle a modal listing the
3
+ * keyboard shortcuts available on the current page. Press `?` again or
4
+ * `Escape` to dismiss. Input/contenteditable fields and Ctrl/Meta/Alt
5
+ * combos are ignored so the shortcut never interferes with typing.
6
+ *
7
+ * While open, physical keydown events depress the matching on-screen keycap
8
+ * with a brief translateY(1px) + tint (var(--motion-instant)).
9
+ *
10
+ * Usage:
11
+ *
12
+ * <KeyboardShortcutsOverlay shortcuts={[
13
+ * { key: 'j / ↓', description: 'Focus next item' },
14
+ * { key: 'k / ↑', description: 'Focus previous item' },
15
+ * { key: 'Enter', description: 'Open detail' },
16
+ * ]} />
17
+ *
18
+ * Or feed it from a shortcut registry (createShortcutRegistry) — the
19
+ * overlay lists whatever can fire right now, grouped by context, and
20
+ * pushes a modal context while open so page shortcuts don't fire behind it:
21
+ *
22
+ * <KeyboardShortcutsOverlay {registry} />
23
+ *
24
+ * Precedence: `sections` > `registry` > `shortcuts`. The overlay owns `?` —
25
+ * don't register it in the registry too.
26
+ */
27
+ import type { ShortcutRegistry } from '../utils/keyboardShortcutRegistry';
18
28
  export interface KeyboardShortcut {
19
29
  key: string;
20
30
  description: string;
@@ -37,6 +47,11 @@ type $$ComponentProps = {
37
47
  * precedence over the flat `shortcuts` prop.
38
48
  */
39
49
  sections?: ShortcutSection[];
50
+ /**
51
+ * Shortcut registry to read sections from (active contexts, top of
52
+ * the stack first). Ignored when `sections` is given.
53
+ */
54
+ registry?: ShortcutRegistry;
40
55
  title?: string;
41
56
  open?: boolean;
42
57
  };
@@ -21,6 +21,8 @@
21
21
  | 'trash'
22
22
  | 'plus'
23
23
  | 'type'
24
+ | 'pause'
25
+ | 'play'
24
26
  size?: number
25
27
  class?: string
26
28
  } = $props()
@@ -83,6 +85,27 @@
83
85
  >
84
86
  <rect width="18" height="18" x="3" y="3" rx="2" />
85
87
  </svg>
88
+ {:else if name === 'pause'}
89
+ <svg
90
+ width={size}
91
+ height={size}
92
+ viewBox="0 0 24 24"
93
+ fill="currentColor"
94
+ class={className}
95
+ >
96
+ <rect x="6" y="4" width="4" height="16" rx="1" />
97
+ <rect x="14" y="4" width="4" height="16" rx="1" />
98
+ </svg>
99
+ {:else if name === 'play'}
100
+ <svg
101
+ width={size}
102
+ height={size}
103
+ viewBox="0 0 24 24"
104
+ fill="currentColor"
105
+ class={className}
106
+ >
107
+ <path d="M8 5.14v13.72a1 1 0 0 0 1.5.87l11-6.86a1 1 0 0 0 0-1.74l-11-6.86a1 1 0 0 0-1.5.87Z" />
108
+ </svg>
86
109
  {:else if name === 'loader'}
87
110
  <svg
88
111
  width={size}
@@ -1,5 +1,5 @@
1
1
  type $$ComponentProps = {
2
- name: 'mic' | 'video' | 'monitor' | 'square' | 'loader' | 'x' | 'file' | 'trash' | 'plus' | 'type';
2
+ name: 'mic' | 'video' | 'monitor' | 'square' | 'loader' | 'x' | 'file' | 'trash' | 'plus' | 'type' | 'pause' | 'play';
3
3
  size?: number;
4
4
  class?: string;
5
5
  };
@@ -0,0 +1,137 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ /**
5
+ * Generic thumbnail item — the decoupled chimaro shape. Unlike chimaro's
6
+ * UnifiedMediaItem this carries only what a thumbnail needs; callers with
7
+ * richer records pass a projection ({ id, url, alt }) or render a `cell`
8
+ * snippet for full control.
9
+ */
10
+ export interface ThumbnailItem {
11
+ id: string;
12
+ /** Image URL; when absent the alt text renders as a text tile. */
13
+ url?: string | null;
14
+ /** Alt text / display label. */
15
+ alt: string;
16
+ }
17
+
18
+ interface Props {
19
+ items: ThumbnailItem[];
20
+ /** How many thumbnails to show before collapsing the rest into a +N counter. Default 8. */
21
+ max?: number;
22
+ /** Tile size. Default 'md'. */
23
+ size?: 'xs' | 'sm' | 'md' | 'lg';
24
+ /** Show remove (×) buttons on hover; requires `onRemove`. */
25
+ removable?: boolean;
26
+ /** Show the dashed add tile at the end; requires `onAdd`. */
27
+ addable?: boolean;
28
+ /** Tooltip / aria-label for the add tile. Default 'Add items'. */
29
+ addLabel?: string;
30
+ /** Fired when a thumbnail is clicked. */
31
+ onSelect?: (item: ThumbnailItem) => void;
32
+ /** Fired when a remove (×) button is clicked. */
33
+ onRemove?: (item: ThumbnailItem) => void;
34
+ /** Fired when the add tile is clicked. */
35
+ onAdd?: () => void;
36
+ /**
37
+ * Replace the default image/text tile rendering for each item — e.g. a
38
+ * video poster, an initials avatar, a FileThumbnail. The snippet renders
39
+ * inside the clickable tile, so it should fill it (`h-full w-full`).
40
+ */
41
+ cell?: Snippet<[ThumbnailItem]>;
42
+ }
43
+
44
+ let {
45
+ items,
46
+ max = 8,
47
+ size = 'md',
48
+ removable = false,
49
+ addable = false,
50
+ addLabel = 'Add items',
51
+ onSelect,
52
+ onRemove,
53
+ onAdd,
54
+ cell
55
+ }: Props = $props();
56
+
57
+ const sizeClasses: Record<NonNullable<Props['size']>, string> = {
58
+ xs: 'h-8 w-8',
59
+ sm: 'h-12 w-12',
60
+ md: 'h-16 w-16',
61
+ lg: 'h-20 w-20'
62
+ };
63
+
64
+ const visible = $derived(items.slice(0, max));
65
+ const overflow = $derived(Math.max(0, items.length - max));
66
+
67
+ function shortLabel(alt: string): string {
68
+ return alt.length > 14 ? `${alt.slice(0, 14)}…` : alt;
69
+ }
70
+ </script>
71
+
72
+ <div class="flex flex-wrap items-center gap-2">
73
+ {#each visible as item (item.id)}
74
+ <div class="group relative">
75
+ <button
76
+ type="button"
77
+ class="{sizeClasses[size]} cursor-pointer overflow-hidden rounded border transition-all duration-200
78
+ {removable ? 'border-2 border-accent' : 'border-base-300 hover:border-primary'}"
79
+ onclick={() => onSelect?.(item)}
80
+ title={item.alt}
81
+ aria-label={item.alt}
82
+ >
83
+ {#if cell}
84
+ {@render cell(item)}
85
+ {:else if item.url}
86
+ <img src={item.url} alt={item.alt} class="h-full w-full object-cover" loading="lazy" />
87
+ {:else}
88
+ <div class="flex h-full w-full items-center justify-center bg-base-200 p-1">
89
+ <span class="text-2xs text-center font-semibold leading-tight break-all text-base-content/80">
90
+ {shortLabel(item.alt)}
91
+ </span>
92
+ </div>
93
+ {/if}
94
+ </button>
95
+
96
+ {#if removable && onRemove}
97
+ <button
98
+ type="button"
99
+ class="absolute -top-1 -right-1 z-10 flex h-4 w-4 items-center justify-center rounded-full bg-error text-error-content opacity-0 transition-opacity group-hover:opacity-100"
100
+ onclick={(e) => {
101
+ e.stopPropagation();
102
+ onRemove(item);
103
+ }}
104
+ title="Remove"
105
+ aria-label="Remove {item.alt}"
106
+ >
107
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" class="h-2.5 w-2.5">
108
+ <path d="M18 6 6 18M6 6l12 12" />
109
+ </svg>
110
+ </button>
111
+ {/if}
112
+ </div>
113
+ {/each}
114
+
115
+ {#if overflow > 0}
116
+ <div
117
+ class="{sizeClasses[size]} flex items-center justify-center rounded border border-base-300 bg-base-200"
118
+ title="{overflow} more item{overflow === 1 ? '' : 's'}"
119
+ >
120
+ <span class="text-xs opacity-70">+{overflow}</span>
121
+ </div>
122
+ {/if}
123
+
124
+ {#if addable && onAdd}
125
+ <button
126
+ type="button"
127
+ class="{sizeClasses[size]} flex scale-90 cursor-pointer items-center justify-center rounded border-2 border-dashed border-primary/30 bg-primary/5 transition-all duration-200 hover:border-primary/50 hover:bg-primary/10"
128
+ onclick={onAdd}
129
+ title={addLabel}
130
+ aria-label={addLabel}
131
+ >
132
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" class="h-4 w-4 text-primary/70">
133
+ <path d="M12 5v14M5 12h14" />
134
+ </svg>
135
+ </button>
136
+ {/if}
137
+ </div>
@@ -0,0 +1,42 @@
1
+ import type { Snippet } from 'svelte';
2
+ /**
3
+ * Generic thumbnail item — the decoupled chimaro shape. Unlike chimaro's
4
+ * UnifiedMediaItem this carries only what a thumbnail needs; callers with
5
+ * richer records pass a projection ({ id, url, alt }) or render a `cell`
6
+ * snippet for full control.
7
+ */
8
+ export interface ThumbnailItem {
9
+ id: string;
10
+ /** Image URL; when absent the alt text renders as a text tile. */
11
+ url?: string | null;
12
+ /** Alt text / display label. */
13
+ alt: string;
14
+ }
15
+ interface Props {
16
+ items: ThumbnailItem[];
17
+ /** How many thumbnails to show before collapsing the rest into a +N counter. Default 8. */
18
+ max?: number;
19
+ /** Tile size. Default 'md'. */
20
+ size?: 'xs' | 'sm' | 'md' | 'lg';
21
+ /** Show remove (×) buttons on hover; requires `onRemove`. */
22
+ removable?: boolean;
23
+ /** Show the dashed add tile at the end; requires `onAdd`. */
24
+ addable?: boolean;
25
+ /** Tooltip / aria-label for the add tile. Default 'Add items'. */
26
+ addLabel?: string;
27
+ /** Fired when a thumbnail is clicked. */
28
+ onSelect?: (item: ThumbnailItem) => void;
29
+ /** Fired when a remove (×) button is clicked. */
30
+ onRemove?: (item: ThumbnailItem) => void;
31
+ /** Fired when the add tile is clicked. */
32
+ onAdd?: () => void;
33
+ /**
34
+ * Replace the default image/text tile rendering for each item — e.g. a
35
+ * video poster, an initials avatar, a FileThumbnail. The snippet renders
36
+ * inside the clickable tile, so it should fill it (`h-full w-full`).
37
+ */
38
+ cell?: Snippet<[ThumbnailItem]>;
39
+ }
40
+ declare const ThumbnailGrid: import("svelte").Component<Props, {}, "">;
41
+ type ThumbnailGrid = ReturnType<typeof ThumbnailGrid>;
42
+ export default ThumbnailGrid;