@joewinke/jatui 0.1.24 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/collapse.d.ts +80 -0
- package/dist/actions/collapse.js +134 -0
- package/dist/actions/railNav.d.ts +167 -0
- package/dist/actions/railNav.js +351 -0
- package/dist/components/AnnotationLayer.svelte +108 -0
- package/dist/components/AnnotationLayer.svelte.d.ts +12 -0
- package/dist/components/AnnotationPanel.svelte +319 -0
- package/dist/components/AnnotationPanel.svelte.d.ts +13 -0
- package/dist/components/AudioWaveform.svelte +701 -0
- package/dist/components/AudioWaveform.svelte.d.ts +19 -0
- package/dist/components/AvailabilityModal.svelte +177 -0
- package/dist/components/AvailabilityModal.svelte.d.ts +14 -0
- package/dist/components/AvatarUpload.svelte +234 -0
- package/dist/components/AvatarUpload.svelte.d.ts +23 -0
- package/dist/components/Badge.svelte +38 -0
- package/dist/components/Badge.svelte.d.ts +14 -0
- package/dist/components/BookingForm.svelte +278 -0
- package/dist/components/BookingForm.svelte.d.ts +37 -0
- package/dist/components/BurndownChart.svelte +778 -0
- package/dist/components/BurndownChart.svelte.d.ts +17 -0
- package/dist/components/Button.svelte +81 -0
- package/dist/components/Button.svelte.d.ts +21 -0
- package/dist/components/CalendarPicker.svelte +284 -0
- package/dist/components/CalendarPicker.svelte.d.ts +22 -0
- package/dist/components/Card.svelte +67 -0
- package/dist/components/Card.svelte.d.ts +17 -0
- package/dist/components/CharacterCounter.svelte +82 -0
- package/dist/components/CharacterCounter.svelte.d.ts +10 -0
- package/dist/components/ChipInput.svelte +609 -0
- package/dist/components/ChipInput.svelte.d.ts +55 -0
- package/dist/components/Collapse.svelte +91 -0
- package/dist/components/Collapse.svelte.d.ts +18 -0
- package/dist/components/ColorSelector.svelte +167 -0
- package/dist/components/ColorSelector.svelte.d.ts +9 -0
- package/dist/components/CommentThread.svelte +773 -0
- package/dist/components/CommentThread.svelte.d.ts +32 -0
- package/dist/components/ConfirmDialog.svelte +348 -0
- package/dist/components/ConfirmDialog.svelte.d.ts +3 -0
- package/dist/components/ConfirmModal.svelte +142 -0
- package/dist/components/ConfirmModal.svelte.d.ts +15 -0
- package/dist/components/ContextMenu.svelte +188 -0
- package/dist/components/ContextMenu.svelte.d.ts +31 -0
- package/dist/components/CountdownTimer.svelte +94 -0
- package/dist/components/CountdownTimer.svelte.d.ts +10 -0
- package/dist/components/DateRangePicker.svelte +194 -0
- package/dist/components/DateRangePicker.svelte.d.ts +10 -0
- package/dist/components/Drawer.svelte +143 -0
- package/dist/components/Drawer.svelte.d.ts +33 -0
- package/dist/components/EmojiPicker.svelte +159 -0
- package/dist/components/EmojiPicker.svelte.d.ts +8 -0
- package/dist/components/EntityPreviewCard.svelte +104 -0
- package/dist/components/EntityPreviewCard.svelte.d.ts +9 -0
- package/dist/components/FileDropzone.svelte +493 -0
- package/dist/components/FileDropzone.svelte.d.ts +40 -0
- package/dist/components/FilePicker.svelte +488 -0
- package/dist/components/FilePicker.svelte.d.ts +20 -0
- package/dist/components/FileThumbnail.svelte +80 -0
- package/dist/components/FileThumbnail.svelte.d.ts +12 -0
- package/dist/components/FilterDropdown.svelte +203 -0
- package/dist/components/FilterDropdown.svelte.d.ts +48 -0
- package/dist/components/FloatingActionBar.svelte +354 -0
- package/dist/components/FloatingActionBar.svelte.d.ts +51 -0
- package/dist/components/GPSTracker.svelte +202 -0
- package/dist/components/GPSTracker.svelte.d.ts +34 -0
- package/dist/components/HunkDiffView.svelte +348 -0
- package/dist/components/HunkDiffView.svelte.d.ts +9 -0
- package/dist/components/ImageLightbox.svelte +274 -0
- package/dist/components/ImageLightbox.svelte.d.ts +25 -0
- package/dist/components/ImageUpload.svelte +147 -0
- package/dist/components/ImageUpload.svelte.d.ts +10 -0
- package/dist/components/InlineEdit.svelte +291 -0
- package/dist/components/InlineEdit.svelte.d.ts +45 -0
- package/dist/components/InputDialog.svelte +327 -0
- package/dist/components/InputDialog.svelte.d.ts +3 -0
- package/dist/components/KeyboardShortcutsOverlay.svelte +296 -0
- package/dist/components/KeyboardShortcutsOverlay.svelte.d.ts +42 -0
- package/dist/components/LazyImage.svelte +123 -0
- package/dist/components/LazyImage.svelte.d.ts +14 -0
- package/dist/components/LinkShortener.svelte +274 -0
- package/dist/components/LinkShortener.svelte.d.ts +27 -0
- package/dist/components/LoadingSpinner.svelte +106 -0
- package/dist/components/LoadingSpinner.svelte.d.ts +21 -0
- package/dist/components/LocationMap.svelte +186 -0
- package/dist/components/LocationMap.svelte.d.ts +11 -0
- package/dist/components/MapView.svelte +341 -0
- package/dist/components/MapView.svelte.d.ts +20 -0
- package/dist/components/MarkupEditor.svelte +485 -0
- package/dist/components/MarkupEditor.svelte.d.ts +10 -0
- package/dist/components/MarkupOverlay.svelte +55 -0
- package/dist/components/MarkupOverlay.svelte.d.ts +8 -0
- package/dist/components/MediaWorkbench.svelte +871 -0
- package/dist/components/MediaWorkbench.svelte.d.ts +9 -0
- package/dist/components/MilestoneCard.svelte +98 -0
- package/dist/components/MilestoneCard.svelte.d.ts +16 -0
- package/dist/components/MilestoneTimeline.svelte +91 -0
- package/dist/components/MilestoneTimeline.svelte.d.ts +15 -0
- package/dist/components/Modal.svelte +244 -0
- package/dist/components/Modal.svelte.d.ts +35 -0
- package/dist/components/PDFViewer.svelte +105 -0
- package/dist/components/PDFViewer.svelte.d.ts +9 -0
- package/dist/components/PdfThumbnail.svelte +63 -0
- package/dist/components/PdfThumbnail.svelte.d.ts +9 -0
- package/dist/components/PhoneInput.svelte +212 -0
- package/dist/components/PhoneInput.svelte.d.ts +25 -0
- package/dist/components/ResizableDivider.svelte +307 -0
- package/dist/components/ResizableDivider.svelte.d.ts +26 -0
- package/dist/components/ResizablePanel.svelte +305 -0
- package/dist/components/ResizablePanel.svelte.d.ts +18 -0
- package/dist/components/SearchDropdown.svelte +421 -0
- package/dist/components/SearchDropdown.svelte.d.ts +24 -0
- package/dist/components/SelectInput.svelte +237 -0
- package/dist/components/SelectInput.svelte.d.ts +26 -0
- package/dist/components/SidebarUserFooter.svelte +34 -0
- package/dist/components/SidebarUserFooter.svelte.d.ts +16 -0
- package/dist/components/SignaturePad.svelte +175 -0
- package/dist/components/SignaturePad.svelte.d.ts +17 -0
- package/dist/components/SmartImageEditor.svelte +720 -0
- package/dist/components/SmartImageEditor.svelte.d.ts +24 -0
- package/dist/components/SortDropdown.svelte +156 -0
- package/dist/components/SortDropdown.svelte.d.ts +40 -0
- package/dist/components/Sparkline.svelte +116 -0
- package/dist/components/Sparkline.svelte.d.ts +12 -0
- package/dist/components/SpeechForm.svelte +114 -0
- package/dist/components/SpeechForm.svelte.d.ts +17 -0
- package/dist/components/StatusBadge.svelte +157 -0
- package/dist/components/StatusBadge.svelte.d.ts +24 -0
- package/dist/components/TaskTypeIcon.svelte +54 -0
- package/dist/components/TaskTypeIcon.svelte.d.ts +17 -0
- package/dist/components/TextArea.svelte +162 -0
- package/dist/components/TextArea.svelte.d.ts +30 -0
- package/dist/components/TextInput.svelte +131 -0
- package/dist/components/TextInput.svelte.d.ts +29 -0
- package/dist/components/ThemeSelector.svelte +206 -0
- package/dist/components/ThemeSelector.svelte.d.ts +14 -0
- package/dist/components/TimeSlotPicker.svelte +162 -0
- package/dist/components/TimeSlotPicker.svelte.d.ts +18 -0
- package/dist/components/UserAvatar.svelte +72 -0
- package/dist/components/UserAvatar.svelte.d.ts +11 -0
- package/dist/components/VariablePicker.svelte +170 -0
- package/dist/components/VariablePicker.svelte.d.ts +40 -0
- package/dist/components/VoicePlayer.svelte +422 -0
- package/dist/components/VoicePlayer.svelte.d.ts +18 -0
- package/dist/components/linked-columns/LinkedColumns.svelte +526 -0
- package/dist/components/linked-columns/LinkedColumns.svelte.d.ts +130 -0
- package/dist/components/markup.d.ts +47 -0
- package/dist/components/markup.js +201 -0
- package/dist/components/messaging/Avatar.svelte +81 -0
- package/dist/components/messaging/Avatar.svelte.d.ts +11 -0
- package/dist/components/messaging/ChannelInfoModal.svelte +163 -0
- package/dist/components/messaging/ChannelInfoModal.svelte.d.ts +18 -0
- package/dist/components/messaging/ChannelList.svelte +107 -0
- package/dist/components/messaging/ChannelList.svelte.d.ts +11 -0
- package/dist/components/messaging/ChannelMemberAvatarStack.svelte +69 -0
- package/dist/components/messaging/ChannelMemberAvatarStack.svelte.d.ts +11 -0
- package/dist/components/messaging/ChannelMembersModal.svelte +182 -0
- package/dist/components/messaging/ChannelMembersModal.svelte.d.ts +16 -0
- package/dist/components/messaging/CreateChannelModal.svelte +190 -0
- package/dist/components/messaging/CreateChannelModal.svelte.d.ts +14 -0
- package/dist/components/messaging/DirectMessageList.svelte +145 -0
- package/dist/components/messaging/DirectMessageList.svelte.d.ts +12 -0
- package/dist/components/messaging/EmojiSelector.svelte +261 -0
- package/dist/components/messaging/EmojiSelector.svelte.d.ts +19 -0
- package/dist/components/messaging/MentionAutocomplete.svelte +193 -0
- package/dist/components/messaging/MentionAutocomplete.svelte.d.ts +17 -0
- package/dist/components/messaging/MessageAttachment.svelte +273 -0
- package/dist/components/messaging/MessageAttachment.svelte.d.ts +13 -0
- package/dist/components/messaging/MessageAttachmentUpload.svelte +243 -0
- package/dist/components/messaging/MessageAttachmentUpload.svelte.d.ts +19 -0
- package/dist/components/messaging/MessageInput.svelte +452 -0
- package/dist/components/messaging/MessageInput.svelte.d.ts +28 -0
- package/dist/components/messaging/MessageItem.svelte +341 -0
- package/dist/components/messaging/MessageItem.svelte.d.ts +41 -0
- package/dist/components/messaging/MessageThread.svelte +306 -0
- package/dist/components/messaging/MessageThread.svelte.d.ts +30 -0
- package/dist/components/messaging/NotificationSettingsModal.svelte +234 -0
- package/dist/components/messaging/NotificationSettingsModal.svelte.d.ts +13 -0
- package/dist/components/messaging/QuotedMessageDisplay.svelte +123 -0
- package/dist/components/messaging/QuotedMessageDisplay.svelte.d.ts +10 -0
- package/dist/components/messaging/StartDMModal.svelte +100 -0
- package/dist/components/messaging/StartDMModal.svelte.d.ts +14 -0
- package/dist/components/messaging/ThreadPanel.svelte +153 -0
- package/dist/components/messaging/ThreadPanel.svelte.d.ts +16 -0
- package/dist/components/pipeline/DESIGN.md +361 -0
- package/dist/components/pipeline/Pipeline.svelte +391 -0
- package/dist/components/pipeline/Pipeline.svelte.d.ts +28 -0
- package/dist/components/pipeline/PipelineCard.svelte +94 -0
- package/dist/components/pipeline/PipelineCard.svelte.d.ts +13 -0
- package/dist/components/pipeline/PipelineColumn.svelte +163 -0
- package/dist/components/pipeline/PipelineColumn.svelte.d.ts +30 -0
- package/dist/components/replay/ChapterTimeline.svelte +326 -0
- package/dist/components/replay/ChapterTimeline.svelte.d.ts +39 -0
- package/dist/components/session-nav/transcriptModel.d.ts +132 -0
- package/dist/components/session-nav/transcriptModel.js +285 -0
- package/dist/data/emojis.d.ts +18 -0
- package/dist/data/emojis.js +1196 -0
- package/dist/index.d.ts +142 -0
- package/dist/index.js +142 -0
- package/dist/stores/confirmDialog.svelte.d.ts +21 -0
- package/dist/stores/confirmDialog.svelte.js +31 -0
- package/dist/stores/inputDialog.svelte.d.ts +24 -0
- package/dist/stores/inputDialog.svelte.js +32 -0
- package/dist/styles/rail.css +63 -0
- package/dist/types/annotation.d.ts +32 -0
- package/dist/types/annotation.js +3 -0
- package/dist/types/booking.d.ts +115 -0
- package/dist/types/booking.js +24 -0
- package/dist/types/comments.d.ts +65 -0
- package/dist/types/comments.js +22 -0
- package/dist/types/entityPreview.d.ts +42 -0
- package/dist/types/entityPreview.js +10 -0
- package/dist/types/filePicker.d.ts +15 -0
- package/dist/types/filePicker.js +1 -0
- package/dist/types/googleMaps.d.ts +51 -0
- package/dist/types/maps.d.ts +43 -0
- package/dist/types/maps.js +4 -0
- package/dist/types/messaging.d.ts +282 -0
- package/dist/types/messaging.js +100 -0
- package/dist/types/milestone.d.ts +20 -0
- package/dist/types/milestone.js +7 -0
- package/dist/types/pipeline.d.ts +115 -0
- package/dist/types/pipeline.js +15 -0
- package/dist/types/smartImageEditor.d.ts +42 -0
- package/dist/types/smartImageEditor.js +1 -0
- package/dist/types/templateVars.d.ts +34 -0
- package/dist/types/templateVars.js +12 -0
- package/dist/utils/currency.d.ts +8 -0
- package/dist/utils/currency.js +17 -0
- package/dist/utils/daisyuiColors.d.ts +37 -0
- package/dist/utils/daisyuiColors.js +152 -0
- package/dist/utils/dateFormatters.d.ts +69 -0
- package/dist/utils/dateFormatters.js +199 -0
- package/dist/utils/googleMapsLoader.d.ts +19 -0
- package/dist/utils/googleMapsLoader.js +121 -0
- package/dist/utils/mentionParser.d.ts +67 -0
- package/dist/utils/mentionParser.js +132 -0
- package/dist/utils/phone.d.ts +13 -0
- package/dist/utils/phone.js +67 -0
- package/dist/utils/phoneFormat.d.ts +26 -0
- package/dist/utils/phoneFormat.js +69 -0
- package/dist/utils/taskUtils.d.ts +37 -0
- package/dist/utils/taskUtils.js +71 -0
- 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>;
|