@joewinke/jatui 0.1.25 → 0.1.27

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 (242) hide show
  1. package/dist/actions/collapse.d.ts +80 -0
  2. package/dist/actions/collapse.js +134 -0
  3. package/dist/actions/railNav.d.ts +167 -0
  4. package/dist/actions/railNav.js +351 -0
  5. package/dist/components/AnnotationLayer.svelte +108 -0
  6. package/dist/components/AnnotationLayer.svelte.d.ts +12 -0
  7. package/dist/components/AnnotationPanel.svelte +319 -0
  8. package/dist/components/AnnotationPanel.svelte.d.ts +13 -0
  9. package/dist/components/AudioWaveform.svelte +701 -0
  10. package/dist/components/AudioWaveform.svelte.d.ts +19 -0
  11. package/dist/components/AvailabilityModal.svelte +177 -0
  12. package/dist/components/AvailabilityModal.svelte.d.ts +14 -0
  13. package/dist/components/AvatarUpload.svelte +234 -0
  14. package/dist/components/AvatarUpload.svelte.d.ts +23 -0
  15. package/dist/components/Badge.svelte +38 -0
  16. package/dist/components/Badge.svelte.d.ts +14 -0
  17. package/dist/components/BookingForm.svelte +278 -0
  18. package/dist/components/BookingForm.svelte.d.ts +37 -0
  19. package/dist/components/BurndownChart.svelte +778 -0
  20. package/dist/components/BurndownChart.svelte.d.ts +17 -0
  21. package/dist/components/Button.svelte +81 -0
  22. package/dist/components/Button.svelte.d.ts +21 -0
  23. package/dist/components/CalendarPicker.svelte +284 -0
  24. package/dist/components/CalendarPicker.svelte.d.ts +22 -0
  25. package/dist/components/Card.svelte +67 -0
  26. package/dist/components/Card.svelte.d.ts +17 -0
  27. package/dist/components/CharacterCounter.svelte +82 -0
  28. package/dist/components/CharacterCounter.svelte.d.ts +10 -0
  29. package/dist/components/ChipInput.svelte +609 -0
  30. package/dist/components/ChipInput.svelte.d.ts +55 -0
  31. package/dist/components/Collapse.svelte +91 -0
  32. package/dist/components/Collapse.svelte.d.ts +18 -0
  33. package/dist/components/ColorSelector.svelte +167 -0
  34. package/dist/components/ColorSelector.svelte.d.ts +9 -0
  35. package/dist/components/CommentThread.svelte +773 -0
  36. package/dist/components/CommentThread.svelte.d.ts +32 -0
  37. package/dist/components/ConfirmDialog.svelte +348 -0
  38. package/dist/components/ConfirmDialog.svelte.d.ts +3 -0
  39. package/dist/components/ConfirmModal.svelte +142 -0
  40. package/dist/components/ConfirmModal.svelte.d.ts +15 -0
  41. package/dist/components/ContextMenu.svelte +188 -0
  42. package/dist/components/ContextMenu.svelte.d.ts +31 -0
  43. package/dist/components/CountdownTimer.svelte +94 -0
  44. package/dist/components/CountdownTimer.svelte.d.ts +10 -0
  45. package/dist/components/DateRangePicker.svelte +194 -0
  46. package/dist/components/DateRangePicker.svelte.d.ts +10 -0
  47. package/dist/components/Drawer.svelte +143 -0
  48. package/dist/components/Drawer.svelte.d.ts +33 -0
  49. package/dist/components/EmojiPicker.svelte +159 -0
  50. package/dist/components/EmojiPicker.svelte.d.ts +8 -0
  51. package/dist/components/EntityPreviewCard.svelte +104 -0
  52. package/dist/components/EntityPreviewCard.svelte.d.ts +9 -0
  53. package/dist/components/FileDropzone.svelte +493 -0
  54. package/dist/components/FileDropzone.svelte.d.ts +40 -0
  55. package/dist/components/FilePicker.svelte +488 -0
  56. package/dist/components/FilePicker.svelte.d.ts +20 -0
  57. package/dist/components/FileThumbnail.svelte +80 -0
  58. package/dist/components/FileThumbnail.svelte.d.ts +12 -0
  59. package/dist/components/FilterDropdown.svelte +203 -0
  60. package/dist/components/FilterDropdown.svelte.d.ts +48 -0
  61. package/dist/components/FloatingActionBar.svelte +354 -0
  62. package/dist/components/FloatingActionBar.svelte.d.ts +51 -0
  63. package/dist/components/GPSTracker.svelte +202 -0
  64. package/dist/components/GPSTracker.svelte.d.ts +34 -0
  65. package/dist/components/HunkDiffView.svelte +348 -0
  66. package/dist/components/HunkDiffView.svelte.d.ts +9 -0
  67. package/dist/components/ImageLightbox.svelte +274 -0
  68. package/dist/components/ImageLightbox.svelte.d.ts +25 -0
  69. package/dist/components/ImageUpload.svelte +147 -0
  70. package/dist/components/ImageUpload.svelte.d.ts +10 -0
  71. package/dist/components/InlineEdit.svelte +291 -0
  72. package/dist/components/InlineEdit.svelte.d.ts +45 -0
  73. package/dist/components/InputDialog.svelte +327 -0
  74. package/dist/components/InputDialog.svelte.d.ts +3 -0
  75. package/dist/components/KeyboardShortcutsOverlay.svelte +296 -0
  76. package/dist/components/KeyboardShortcutsOverlay.svelte.d.ts +42 -0
  77. package/dist/components/LazyImage.svelte +123 -0
  78. package/dist/components/LazyImage.svelte.d.ts +14 -0
  79. package/dist/components/LinkShortener.svelte +274 -0
  80. package/dist/components/LinkShortener.svelte.d.ts +27 -0
  81. package/dist/components/LoadingSpinner.svelte +106 -0
  82. package/dist/components/LoadingSpinner.svelte.d.ts +21 -0
  83. package/dist/components/LocationMap.svelte +186 -0
  84. package/dist/components/LocationMap.svelte.d.ts +11 -0
  85. package/dist/components/MapView.svelte +341 -0
  86. package/dist/components/MapView.svelte.d.ts +20 -0
  87. package/dist/components/MarkupEditor.svelte +485 -0
  88. package/dist/components/MarkupEditor.svelte.d.ts +10 -0
  89. package/dist/components/MarkupOverlay.svelte +55 -0
  90. package/dist/components/MarkupOverlay.svelte.d.ts +8 -0
  91. package/dist/components/MediaWorkbench.svelte +871 -0
  92. package/dist/components/MediaWorkbench.svelte.d.ts +9 -0
  93. package/dist/components/MilestoneCard.svelte +98 -0
  94. package/dist/components/MilestoneCard.svelte.d.ts +16 -0
  95. package/dist/components/MilestoneTimeline.svelte +91 -0
  96. package/dist/components/MilestoneTimeline.svelte.d.ts +15 -0
  97. package/dist/components/Modal.svelte +244 -0
  98. package/dist/components/Modal.svelte.d.ts +35 -0
  99. package/dist/components/PDFViewer.svelte +105 -0
  100. package/dist/components/PDFViewer.svelte.d.ts +9 -0
  101. package/dist/components/PdfThumbnail.svelte +63 -0
  102. package/dist/components/PdfThumbnail.svelte.d.ts +9 -0
  103. package/dist/components/PhoneInput.svelte +212 -0
  104. package/dist/components/PhoneInput.svelte.d.ts +25 -0
  105. package/dist/components/ResizableDivider.svelte +307 -0
  106. package/dist/components/ResizableDivider.svelte.d.ts +26 -0
  107. package/dist/components/ResizablePanel.svelte +305 -0
  108. package/dist/components/ResizablePanel.svelte.d.ts +18 -0
  109. package/dist/components/SearchDropdown.svelte +686 -0
  110. package/dist/components/SearchDropdown.svelte.d.ts +40 -0
  111. package/dist/components/SelectInput.svelte +237 -0
  112. package/dist/components/SelectInput.svelte.d.ts +26 -0
  113. package/dist/components/SidebarUserFooter.svelte +34 -0
  114. package/dist/components/SidebarUserFooter.svelte.d.ts +16 -0
  115. package/dist/components/SignaturePad.svelte +175 -0
  116. package/dist/components/SignaturePad.svelte.d.ts +17 -0
  117. package/dist/components/SmartImageEditor.svelte +720 -0
  118. package/dist/components/SmartImageEditor.svelte.d.ts +24 -0
  119. package/dist/components/SortDropdown.svelte +156 -0
  120. package/dist/components/SortDropdown.svelte.d.ts +40 -0
  121. package/dist/components/Sparkline.svelte +116 -0
  122. package/dist/components/Sparkline.svelte.d.ts +12 -0
  123. package/dist/components/SpeechForm.svelte +114 -0
  124. package/dist/components/SpeechForm.svelte.d.ts +17 -0
  125. package/dist/components/StatusBadge.svelte +157 -0
  126. package/dist/components/StatusBadge.svelte.d.ts +24 -0
  127. package/dist/components/TaskTypeIcon.svelte +54 -0
  128. package/dist/components/TaskTypeIcon.svelte.d.ts +17 -0
  129. package/dist/components/TextArea.svelte +162 -0
  130. package/dist/components/TextArea.svelte.d.ts +30 -0
  131. package/dist/components/TextInput.svelte +131 -0
  132. package/dist/components/TextInput.svelte.d.ts +29 -0
  133. package/dist/components/ThemeSelector.svelte +206 -0
  134. package/dist/components/ThemeSelector.svelte.d.ts +14 -0
  135. package/dist/components/TimeSlotPicker.svelte +162 -0
  136. package/dist/components/TimeSlotPicker.svelte.d.ts +18 -0
  137. package/dist/components/UserAvatar.svelte +72 -0
  138. package/dist/components/UserAvatar.svelte.d.ts +11 -0
  139. package/dist/components/VariablePicker.svelte +170 -0
  140. package/dist/components/VariablePicker.svelte.d.ts +40 -0
  141. package/dist/components/VoicePlayer.svelte +422 -0
  142. package/dist/components/VoicePlayer.svelte.d.ts +18 -0
  143. package/dist/components/linked-columns/LinkedColumns.svelte +526 -0
  144. package/dist/components/linked-columns/LinkedColumns.svelte.d.ts +130 -0
  145. package/dist/components/markup.d.ts +47 -0
  146. package/dist/components/markup.js +201 -0
  147. package/dist/components/messaging/Avatar.svelte +81 -0
  148. package/dist/components/messaging/Avatar.svelte.d.ts +11 -0
  149. package/dist/components/messaging/ChannelInfoModal.svelte +163 -0
  150. package/dist/components/messaging/ChannelInfoModal.svelte.d.ts +18 -0
  151. package/dist/components/messaging/ChannelList.svelte +107 -0
  152. package/dist/components/messaging/ChannelList.svelte.d.ts +11 -0
  153. package/dist/components/messaging/ChannelMemberAvatarStack.svelte +69 -0
  154. package/dist/components/messaging/ChannelMemberAvatarStack.svelte.d.ts +11 -0
  155. package/dist/components/messaging/ChannelMembersModal.svelte +182 -0
  156. package/dist/components/messaging/ChannelMembersModal.svelte.d.ts +16 -0
  157. package/dist/components/messaging/CreateChannelModal.svelte +190 -0
  158. package/dist/components/messaging/CreateChannelModal.svelte.d.ts +14 -0
  159. package/dist/components/messaging/DirectMessageList.svelte +145 -0
  160. package/dist/components/messaging/DirectMessageList.svelte.d.ts +12 -0
  161. package/dist/components/messaging/EmojiSelector.svelte +261 -0
  162. package/dist/components/messaging/EmojiSelector.svelte.d.ts +19 -0
  163. package/dist/components/messaging/MentionAutocomplete.svelte +193 -0
  164. package/dist/components/messaging/MentionAutocomplete.svelte.d.ts +17 -0
  165. package/dist/components/messaging/MessageAttachment.svelte +273 -0
  166. package/dist/components/messaging/MessageAttachment.svelte.d.ts +13 -0
  167. package/dist/components/messaging/MessageAttachmentUpload.svelte +243 -0
  168. package/dist/components/messaging/MessageAttachmentUpload.svelte.d.ts +19 -0
  169. package/dist/components/messaging/MessageInput.svelte +452 -0
  170. package/dist/components/messaging/MessageInput.svelte.d.ts +28 -0
  171. package/dist/components/messaging/MessageItem.svelte +341 -0
  172. package/dist/components/messaging/MessageItem.svelte.d.ts +41 -0
  173. package/dist/components/messaging/MessageThread.svelte +306 -0
  174. package/dist/components/messaging/MessageThread.svelte.d.ts +30 -0
  175. package/dist/components/messaging/NotificationSettingsModal.svelte +234 -0
  176. package/dist/components/messaging/NotificationSettingsModal.svelte.d.ts +13 -0
  177. package/dist/components/messaging/QuotedMessageDisplay.svelte +123 -0
  178. package/dist/components/messaging/QuotedMessageDisplay.svelte.d.ts +10 -0
  179. package/dist/components/messaging/StartDMModal.svelte +100 -0
  180. package/dist/components/messaging/StartDMModal.svelte.d.ts +14 -0
  181. package/dist/components/messaging/ThreadPanel.svelte +153 -0
  182. package/dist/components/messaging/ThreadPanel.svelte.d.ts +16 -0
  183. package/dist/components/pipeline/DESIGN.md +361 -0
  184. package/dist/components/pipeline/Pipeline.svelte +391 -0
  185. package/dist/components/pipeline/Pipeline.svelte.d.ts +28 -0
  186. package/dist/components/pipeline/PipelineCard.svelte +94 -0
  187. package/dist/components/pipeline/PipelineCard.svelte.d.ts +13 -0
  188. package/dist/components/pipeline/PipelineColumn.svelte +163 -0
  189. package/dist/components/pipeline/PipelineColumn.svelte.d.ts +30 -0
  190. package/dist/components/replay/ChapterTimeline.svelte +326 -0
  191. package/dist/components/replay/ChapterTimeline.svelte.d.ts +39 -0
  192. package/dist/components/session-nav/transcriptModel.d.ts +132 -0
  193. package/dist/components/session-nav/transcriptModel.js +285 -0
  194. package/dist/data/emojis.d.ts +18 -0
  195. package/dist/data/emojis.js +1196 -0
  196. package/dist/index.d.ts +142 -0
  197. package/dist/index.js +142 -0
  198. package/dist/stores/confirmDialog.svelte.d.ts +21 -0
  199. package/dist/stores/confirmDialog.svelte.js +31 -0
  200. package/dist/stores/inputDialog.svelte.d.ts +24 -0
  201. package/dist/stores/inputDialog.svelte.js +32 -0
  202. package/dist/styles/rail.css +63 -0
  203. package/dist/types/annotation.d.ts +32 -0
  204. package/dist/types/annotation.js +3 -0
  205. package/dist/types/booking.d.ts +115 -0
  206. package/dist/types/booking.js +24 -0
  207. package/dist/types/comments.d.ts +65 -0
  208. package/dist/types/comments.js +22 -0
  209. package/dist/types/entityPreview.d.ts +42 -0
  210. package/dist/types/entityPreview.js +10 -0
  211. package/dist/types/filePicker.d.ts +15 -0
  212. package/dist/types/filePicker.js +1 -0
  213. package/dist/types/googleMaps.d.ts +51 -0
  214. package/dist/types/maps.d.ts +43 -0
  215. package/dist/types/maps.js +4 -0
  216. package/dist/types/messaging.d.ts +282 -0
  217. package/dist/types/messaging.js +100 -0
  218. package/dist/types/milestone.d.ts +20 -0
  219. package/dist/types/milestone.js +7 -0
  220. package/dist/types/pipeline.d.ts +115 -0
  221. package/dist/types/pipeline.js +15 -0
  222. package/dist/types/smartImageEditor.d.ts +42 -0
  223. package/dist/types/smartImageEditor.js +1 -0
  224. package/dist/types/templateVars.d.ts +34 -0
  225. package/dist/types/templateVars.js +12 -0
  226. package/dist/utils/currency.d.ts +8 -0
  227. package/dist/utils/currency.js +17 -0
  228. package/dist/utils/daisyuiColors.d.ts +37 -0
  229. package/dist/utils/daisyuiColors.js +152 -0
  230. package/dist/utils/dateFormatters.d.ts +69 -0
  231. package/dist/utils/dateFormatters.js +199 -0
  232. package/dist/utils/googleMapsLoader.d.ts +19 -0
  233. package/dist/utils/googleMapsLoader.js +121 -0
  234. package/dist/utils/mentionParser.d.ts +67 -0
  235. package/dist/utils/mentionParser.js +132 -0
  236. package/dist/utils/phone.d.ts +13 -0
  237. package/dist/utils/phone.js +67 -0
  238. package/dist/utils/phoneFormat.d.ts +26 -0
  239. package/dist/utils/phoneFormat.js +69 -0
  240. package/dist/utils/taskUtils.d.ts +37 -0
  241. package/dist/utils/taskUtils.js +71 -0
  242. package/package.json +3 -2
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Tall-content collapse — Svelte action.
3
+ *
4
+ * Caps an arbitrarily-tall block at a max height with a fade-out gradient so it
5
+ * shows a preview instead of overflowing its container. The consumer renders the
6
+ * "Show more / Show less" toggle and owns the `expanded` boolean; the action does
7
+ * the measuring and applies the collapse styling.
8
+ *
9
+ * Why an action (not a wrapper-only component): most adoption sites are existing
10
+ * elements (`<p>`, a `prose` div, a `<ul>`, a `<pre>`), and an action attaches
11
+ * with zero DOM restructuring. A batteries-included `<Collapse>` wrapper that
12
+ * uses this action is also provided for greenfield use.
13
+ *
14
+ * ─── Why inline styles, not a CSS class ───────────────────────────────────────
15
+ *
16
+ * The action writes `max-height` / `overflow` / `mask-image` directly on the node
17
+ * when collapsed. That means it needs NO accompanying stylesheet — it works
18
+ * identically in Tailwind-utility components and scoped-CSS components, and
19
+ * consumers don't have to copy a `.collapse-*` rule into their app.css (the same
20
+ * trap rail.css has). Expanding clears the inline styles.
21
+ *
22
+ * ─── Why ResizeObserver, not a one-shot rAF ───────────────────────────────────
23
+ *
24
+ * Streaming chat answers and `{@html}` markdown bodies grow AFTER mount. A
25
+ * one-shot measurement on mount would miss them (and would wrongly hide the
26
+ * toggle on content that hasn't streamed in yet). A ResizeObserver re-measures
27
+ * whenever the content's natural height changes, so `collapsible` stays correct.
28
+ *
29
+ * `scrollHeight` reports the FULL content height even while `max-height` +
30
+ * `overflow:hidden` are applied, so the action can keep measuring without ever
31
+ * having to un-collapse first.
32
+ *
33
+ * ─── Usage — action form (most sites) ─────────────────────────────────────────
34
+ *
35
+ * <script>
36
+ * import { collapse } from 'jatui'
37
+ * let collapsible = $state(false)
38
+ * let expanded = $state(false)
39
+ * const bodyId = `collapse-${$props.id()}`
40
+ * </script>
41
+ *
42
+ * <div id={bodyId} use:collapse={{ expanded, onCollapsible: (c) => (collapsible = c) }}>
43
+ * {content}
44
+ * </div>
45
+ * {#if collapsible}
46
+ * <button
47
+ * aria-expanded={expanded}
48
+ * aria-controls={bodyId}
49
+ * onclick={() => (expanded = !expanded)}
50
+ * >
51
+ * {expanded ? 'Show less ↑' : 'Show more ↓'}
52
+ * </button>
53
+ * {/if}
54
+ *
55
+ * The `id`/`aria-expanded`/`aria-controls` trio is not optional — without it the
56
+ * toggle is keyboard-operable but invisible to screen readers as a disclosure
57
+ * control. For mapped lists, give each row its own `id`/`expanded`/`collapsible`
58
+ * state (e.g. a `SvelteSet` of ids, with the id interpolating the row's own id) —
59
+ * one action instance attaches per row element.
60
+ */
61
+ export interface CollapseOptions {
62
+ /** Max collapsed height in px. Content taller than this collapses. Default 120. */
63
+ threshold?: number;
64
+ /** Controlled expand state. When true, the node is never collapsed. Default false. */
65
+ expanded?: boolean;
66
+ /** Where the fade-to-transparent begins, as a %. Default 55. */
67
+ fadeStart?: number;
68
+ /** Slack (px) added to the threshold so a near-fit doesn't toggle. Default 4. */
69
+ epsilon?: number;
70
+ /**
71
+ * Called whenever collapsibility changes (content crosses the threshold).
72
+ * Drive the toggle button's visibility from this — it self-hides when the
73
+ * content is shorter than the threshold.
74
+ */
75
+ onCollapsible?: (collapsible: boolean) => void;
76
+ }
77
+ export declare function collapse(node: HTMLElement, options?: CollapseOptions): {
78
+ update(next?: CollapseOptions): void;
79
+ destroy(): void;
80
+ };
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Tall-content collapse — Svelte action.
3
+ *
4
+ * Caps an arbitrarily-tall block at a max height with a fade-out gradient so it
5
+ * shows a preview instead of overflowing its container. The consumer renders the
6
+ * "Show more / Show less" toggle and owns the `expanded` boolean; the action does
7
+ * the measuring and applies the collapse styling.
8
+ *
9
+ * Why an action (not a wrapper-only component): most adoption sites are existing
10
+ * elements (`<p>`, a `prose` div, a `<ul>`, a `<pre>`), and an action attaches
11
+ * with zero DOM restructuring. A batteries-included `<Collapse>` wrapper that
12
+ * uses this action is also provided for greenfield use.
13
+ *
14
+ * ─── Why inline styles, not a CSS class ───────────────────────────────────────
15
+ *
16
+ * The action writes `max-height` / `overflow` / `mask-image` directly on the node
17
+ * when collapsed. That means it needs NO accompanying stylesheet — it works
18
+ * identically in Tailwind-utility components and scoped-CSS components, and
19
+ * consumers don't have to copy a `.collapse-*` rule into their app.css (the same
20
+ * trap rail.css has). Expanding clears the inline styles.
21
+ *
22
+ * ─── Why ResizeObserver, not a one-shot rAF ───────────────────────────────────
23
+ *
24
+ * Streaming chat answers and `{@html}` markdown bodies grow AFTER mount. A
25
+ * one-shot measurement on mount would miss them (and would wrongly hide the
26
+ * toggle on content that hasn't streamed in yet). A ResizeObserver re-measures
27
+ * whenever the content's natural height changes, so `collapsible` stays correct.
28
+ *
29
+ * `scrollHeight` reports the FULL content height even while `max-height` +
30
+ * `overflow:hidden` are applied, so the action can keep measuring without ever
31
+ * having to un-collapse first.
32
+ *
33
+ * ─── Usage — action form (most sites) ─────────────────────────────────────────
34
+ *
35
+ * <script>
36
+ * import { collapse } from 'jatui'
37
+ * let collapsible = $state(false)
38
+ * let expanded = $state(false)
39
+ * const bodyId = `collapse-${$props.id()}`
40
+ * </script>
41
+ *
42
+ * <div id={bodyId} use:collapse={{ expanded, onCollapsible: (c) => (collapsible = c) }}>
43
+ * {content}
44
+ * </div>
45
+ * {#if collapsible}
46
+ * <button
47
+ * aria-expanded={expanded}
48
+ * aria-controls={bodyId}
49
+ * onclick={() => (expanded = !expanded)}
50
+ * >
51
+ * {expanded ? 'Show less ↑' : 'Show more ↓'}
52
+ * </button>
53
+ * {/if}
54
+ *
55
+ * The `id`/`aria-expanded`/`aria-controls` trio is not optional — without it the
56
+ * toggle is keyboard-operable but invisible to screen readers as a disclosure
57
+ * control. For mapped lists, give each row its own `id`/`expanded`/`collapsible`
58
+ * state (e.g. a `SvelteSet` of ids, with the id interpolating the row's own id) —
59
+ * one action instance attaches per row element.
60
+ */
61
+ var __assign = (this && this.__assign) || function () {
62
+ __assign = Object.assign || function(t) {
63
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
64
+ s = arguments[i];
65
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
66
+ t[p] = s[p];
67
+ }
68
+ return t;
69
+ };
70
+ return __assign.apply(this, arguments);
71
+ };
72
+ var DEFAULTS = { threshold: 120, expanded: false, fadeStart: 55, epsilon: 4 };
73
+ export function collapse(node, options) {
74
+ if (options === void 0) { options = {}; }
75
+ var opts = __assign(__assign({}, DEFAULTS), options);
76
+ var collapsible = false;
77
+ var rafId = 0;
78
+ var applied = false;
79
+ function gradient() {
80
+ return "linear-gradient(to bottom, black ".concat(opts.fadeStart, "%, transparent 100%)");
81
+ }
82
+ function apply() {
83
+ var shouldCollapse = collapsible && !opts.expanded;
84
+ if (shouldCollapse === applied)
85
+ return; // idempotent — avoids RO feedback loops
86
+ applied = shouldCollapse;
87
+ if (shouldCollapse) {
88
+ node.style.maxHeight = "".concat(opts.threshold, "px");
89
+ node.style.overflow = 'hidden';
90
+ node.style.maskImage = gradient();
91
+ node.style.webkitMaskImage = gradient();
92
+ }
93
+ else {
94
+ node.style.maxHeight = '';
95
+ node.style.overflow = '';
96
+ node.style.maskImage = '';
97
+ node.style.webkitMaskImage = '';
98
+ }
99
+ }
100
+ function measure() {
101
+ var _a;
102
+ // scrollHeight is the full content height even while collapsed.
103
+ var next = node.scrollHeight > opts.threshold + opts.epsilon;
104
+ if (next !== collapsible) {
105
+ collapsible = next;
106
+ (_a = opts.onCollapsible) === null || _a === void 0 ? void 0 : _a.call(opts, collapsible);
107
+ }
108
+ apply();
109
+ }
110
+ function scheduleMeasure() {
111
+ cancelAnimationFrame(rafId);
112
+ rafId = requestAnimationFrame(measure);
113
+ }
114
+ // Re-measure when the content's natural size changes (streaming, {@html}, lazy images).
115
+ var ro = new ResizeObserver(scheduleMeasure);
116
+ ro.observe(node);
117
+ scheduleMeasure();
118
+ return {
119
+ update: function (next) {
120
+ if (next === void 0) { next = {}; }
121
+ opts = __assign(__assign({}, DEFAULTS), next);
122
+ // expanded/threshold/fade may have changed — re-measure and let
123
+ // apply() compare the freshly computed shouldCollapse against the
124
+ // real last-applied state. (Force-flipping `applied` here used to make
125
+ // that comparison spuriously match on a plain expand/collapse toggle,
126
+ // silently skipping the style update.)
127
+ scheduleMeasure();
128
+ },
129
+ destroy: function () {
130
+ cancelAnimationFrame(rafId);
131
+ ro.disconnect();
132
+ },
133
+ };
134
+ }
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Keyboard-rail navigation primitive — action + composable.
3
+ *
4
+ * A drawer / form is a vertical sequence of "rungs". Focus starts in the first
5
+ * field. Up / Down (and j / k when NOT typing) step between rungs. Left / Right
6
+ * acts on the focused rung (cycle a value, switch a tab, open a picker). Escape
7
+ * pops focus out of a field back to the container, then fires `onEscape`.
8
+ *
9
+ * Rungs are ordinary HTML elements tagged with a `data-rail-id` attribute (or
10
+ * whatever attribute `attr` specifies). The consumer supplies an `order` array
11
+ * of ids that defines traversal; ids whose element is not currently rendered
12
+ * in the container are skipped at move time.
13
+ *
14
+ * ─── CSS contract ─────────────────────────────────────────────────────────────
15
+ *
16
+ * The controller applies two classes to rung host elements. Style them in your
17
+ * stylesheet (or in a parent scope):
18
+ *
19
+ * .rail-focus — persistent: applied to the currently active rung host. Use
20
+ * `:focus-visible` / `:has(:focus-visible)` inside the rule so
21
+ * only keyboard-driven focus shows a visible ring.
22
+ *
23
+ * .rail-cycled — transient (~280ms): applied when Left / Right changes a
24
+ * rung's value via `rail.bump(host)`. Use for a brief pulse
25
+ * that confirms the value changed.
26
+ *
27
+ * ─── Usage — action form (simplest) ──────────────────────────────────────────
28
+ *
29
+ * <div use:railNav={{
30
+ * order: () => ['title', 'type', 'priority'],
31
+ * onAction: (id, dir, host) => cycleField(id, dir),
32
+ * onEscape: () => closeDrawer(),
33
+ * }}>
34
+ * <input data-rail-id="title" />
35
+ * <div data-rail-id="type" tabindex="-1">…</div>
36
+ * <div data-rail-id="priority" tabindex="-1">…</div>
37
+ * </div>
38
+ *
39
+ * ─── Usage — composable form ──────────────────────────────────────────────────
40
+ *
41
+ * const rail = createRailNav({
42
+ * container: panelEl,
43
+ * order: () => currentOrder,
44
+ * onAction: (id, dir, host) => { rail.bump(host); cycleField(id, dir); },
45
+ * onEscape: () => closeDrawer(),
46
+ * });
47
+ *
48
+ * // Wire both listeners on the container:
49
+ * panelEl.addEventListener('keydown', (e) => rail.handleKeydown(e));
50
+ * panelEl.addEventListener('focusin', (e) => rail.handleFocusin(e));
51
+ *
52
+ * ─── How to wire a drawer to railNav ──────────────────────────────────────────
53
+ *
54
+ * 1. Tag each rung host with `data-rail-id`:
55
+ * <div data-rail-id="type" tabindex="-1">…</div>
56
+ *
57
+ * 2. Apply the action (or composable) to the drawer panel:
58
+ * <div bind:this={panel} use:railNav={{ order, onAction, onEscape }} …>
59
+ *
60
+ * 3. Handle Left/Right in `onAction` and call `rail.bump(host)` on change:
61
+ * onAction: (id, dir, host) => { formData[id] = cycle(opts[id], …, dir); rail.bump(host); }
62
+ */
63
+ import type { Action } from 'svelte/action';
64
+ export interface RailNavOptions {
65
+ /**
66
+ * Rung id order, top → bottom. May be a plain array or a getter (called on
67
+ * every navigation event so reactive lists stay in sync).
68
+ */
69
+ order: string[] | (() => string[]);
70
+ /**
71
+ * Called when Left / Right is pressed on a non-text rung.
72
+ * `dir` is `1` for Right and `-1` for Left.
73
+ * Call `rail.bump(host)` inside this handler if you want the pulse effect.
74
+ */
75
+ onAction?: (rungId: string, dir: 1 | -1, host: HTMLElement) => void;
76
+ /**
77
+ * Called when Escape is pressed while focus is already on (or has been
78
+ * popped back to) the container itself. Typically closes the drawer / modal.
79
+ */
80
+ onEscape?: () => void;
81
+ /**
82
+ * Optional: when a child popover currently owns keyboard focus, return `true`
83
+ * here to suppress rail navigation. Escape will call `onPopoverEscape` first.
84
+ */
85
+ isPopoverOpen?: () => boolean;
86
+ /** Called on Escape when `isPopoverOpen()` returns true. */
87
+ onPopoverEscape?: () => void;
88
+ /**
89
+ * When `true` (default), keystrokes on non-text rungs are stopped from
90
+ * bubbling to window-level listeners behind a modal.
91
+ */
92
+ trap?: boolean;
93
+ /**
94
+ * Attribute used as the rung identifier. Default: `'data-rail-id'`.
95
+ * The controller looks for elements matching `[<attr>="<id>"]`.
96
+ */
97
+ attr?: string;
98
+ /**
99
+ * The container element to search for rung hosts.
100
+ *
101
+ * Required for `createRailNav`. The `railNav` action fills this automatically
102
+ * from the action's `node`.
103
+ */
104
+ container?: HTMLElement;
105
+ }
106
+ export interface RailNavController {
107
+ /**
108
+ * Feed a keydown event. Returns `true` if the event was consumed.
109
+ * Attach to the container's `keydown` listener (or `onkeydown` in Svelte).
110
+ */
111
+ handleKeydown(event: KeyboardEvent): boolean;
112
+ /**
113
+ * Feed a focusin event so the controller can track which rung the user
114
+ * Tabbed into. Attach to the container's `focusin` listener.
115
+ */
116
+ handleFocusin(event: FocusEvent): void;
117
+ /** Step one rung in direction `1` (down) or `-1` (up). Wraps around. */
118
+ moveRung(dir: 1 | -1): void;
119
+ /** Focus the rung with the given id. No-op if the element is not rendered. */
120
+ focus(id: string): void;
121
+ /**
122
+ * Re-derive the current rung list after a conditional rung appears or
123
+ * disappears. The action calls this automatically in its `update` hook.
124
+ * Call manually in the composable form after reactive state changes.
125
+ */
126
+ refresh(): void;
127
+ /** The id of the last rung that received focus, or `''` if none. */
128
+ currentId(): string;
129
+ /**
130
+ * Applies the transient `rail-cycled` class to `host` for ~280ms.
131
+ * Call this inside `onAction` when a Left / Right key changes a value.
132
+ */
133
+ bump(host: HTMLElement | null): void;
134
+ }
135
+ /**
136
+ * Cycle through `list`, returning the item `dir` steps from `current`.
137
+ * Wraps around. Returns `current` unchanged when the list is empty.
138
+ *
139
+ * @example
140
+ * cycle(['bug', 'feature', 'task'], 'feature', 1) // → 'task'
141
+ * cycle(['bug', 'feature', 'task'], 'bug', -1) // → 'task'
142
+ * cycle(['a', 'b'], 'z', 1) // → 'a' (not found → start)
143
+ */
144
+ export declare function cycle<T>(list: readonly T[], current: T, dir: 1 | -1): T;
145
+ /**
146
+ * Imperative composable — use when you already own keydown / focusin handlers
147
+ * and want `railNav` to decide whether to consume the event.
148
+ *
149
+ * You **must** supply `options.container` and wire both events:
150
+ *
151
+ * const rail = createRailNav({ container: panel, order, onAction, onEscape });
152
+ * panel.addEventListener('keydown', (e) => rail.handleKeydown(e));
153
+ * panel.addEventListener('focusin', (e) => rail.handleFocusin(e));
154
+ */
155
+ export declare function createRailNav(options: RailNavOptions): RailNavController;
156
+ /**
157
+ * Svelte action — attaches `keydown` and `focusin` listeners to `node` and
158
+ * handles rung stepping, horizontal action dispatch, and Escape cascade.
159
+ *
160
+ * @example
161
+ * <div use:railNav={{ order, onAction, onEscape }}>
162
+ * <input data-rail-id="title" />
163
+ * <div data-rail-id="type" tabindex="-1">…</div>
164
+ * <div data-rail-id="priority" tabindex="-1">…</div>
165
+ * </div>
166
+ */
167
+ export declare const railNav: Action<HTMLElement, RailNavOptions | undefined>;