@placeholderco/placeholder-ui 1.0.11 → 2.0.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.
- package/LICENSE +1 -1
- package/README.md +134 -130
- package/dist/app.css +178 -0
- package/dist/bootstrap.min.css +3600 -0
- package/dist/cards/GitCard.svelte +115 -0
- package/dist/cards/GitCard.svelte.d.ts +22 -0
- package/dist/display/Avatar.svelte +29 -17
- package/dist/display/Avatar.svelte.d.ts +12 -2
- package/dist/display/LinkCollection.svelte +40 -18
- package/dist/display/LinkCollection.svelte.d.ts +9 -2
- package/dist/display/Paper.svelte +31 -19
- package/dist/display/Paper.svelte.d.ts +12 -3
- package/dist/display/alert/Alert.svelte +129 -0
- package/dist/display/alert/Alert.svelte.d.ts +15 -0
- package/dist/display/alert/AlertVariant.d.ts +1 -0
- package/dist/display/alert/AlertVariant.js +1 -0
- package/dist/display/filetree/FileTree.svelte +259 -0
- package/dist/display/filetree/FileTree.svelte.d.ts +76 -0
- package/dist/display/filetree/FileTreeItem.svelte +396 -0
- package/dist/display/filetree/FileTreeItem.svelte.d.ts +40 -0
- package/dist/display/filetree/FileTreeNode.d.ts +46 -0
- package/dist/display/filetree/FileTreeNode.js +115 -0
- package/dist/display/filetree/index.d.ts +5 -0
- package/dist/display/filetree/index.js +3 -0
- package/dist/editors/CodeMirror.svelte +306 -0
- package/dist/editors/CodeMirror.svelte.d.ts +31 -0
- package/dist/editors/tiptap/LinkActionMenu.svelte +307 -0
- package/dist/editors/tiptap/LinkActionMenu.svelte.d.ts +8 -0
- package/dist/editors/tiptap/TipTap.svelte +856 -0
- package/dist/editors/tiptap/TipTap.svelte.d.ts +54 -0
- package/dist/editors/tiptap/TipTapBubble.svelte +790 -0
- package/dist/editors/tiptap/TipTapBubble.svelte.d.ts +44 -0
- package/dist/editors/tiptap/collaboration.d.ts +55 -0
- package/dist/editors/tiptap/collaboration.js +1 -0
- package/dist/editors/tiptap/extensions/Alert.d.ts +18 -0
- package/dist/editors/tiptap/extensions/Alert.js +72 -0
- package/dist/editors/tiptap/extensions/CodeBlockEditor.d.ts +21 -0
- package/dist/editors/tiptap/extensions/CodeBlockEditor.js +326 -0
- package/dist/editors/tiptap/extensions/Div.d.ts +19 -0
- package/dist/editors/tiptap/extensions/Div.js +89 -0
- package/dist/editors/tiptap/extensions/Span.d.ts +5 -0
- package/dist/editors/tiptap/extensions/Span.js +56 -0
- package/dist/editors/tiptap/extensions/codeBlockEditor.css +236 -0
- package/dist/editors/tiptap/extensions/codeBlockLanguages.d.ts +17 -0
- package/dist/editors/tiptap/extensions/codeBlockLanguages.js +124 -0
- package/dist/editors/tiptap/extensions/index.d.ts +7 -0
- package/dist/editors/tiptap/extensions/index.js +5 -0
- package/dist/editors/tiptap/toolbar/AlertButton.svelte +261 -0
- package/dist/editors/tiptap/toolbar/AlertButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/AlignRightButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/AlignRightButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/BoldButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/BoldButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/BulletListButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/BulletListButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/CodeBlockButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/CodeBlockButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/CodeButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/CodeButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/ColorButton.svelte +299 -0
- package/dist/editors/tiptap/toolbar/ColorButton.svelte.d.ts +20 -0
- package/dist/editors/tiptap/toolbar/DocumentButton.svelte +58 -0
- package/dist/editors/tiptap/toolbar/DocumentButton.svelte.d.ts +9 -0
- package/dist/editors/tiptap/toolbar/HeadingButton.svelte +30 -0
- package/dist/editors/tiptap/toolbar/HeadingButton.svelte.d.ts +8 -0
- package/dist/editors/tiptap/toolbar/HtmlButton.svelte +68 -0
- package/dist/editors/tiptap/toolbar/HtmlButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/ImageButton.svelte +54 -0
- package/dist/editors/tiptap/toolbar/ImageButton.svelte.d.ts +8 -0
- package/dist/editors/tiptap/toolbar/ItalicButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/ItalicButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/LinkButton.svelte +257 -0
- package/dist/editors/tiptap/toolbar/LinkButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/OrderedListButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/OrderedListButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/RedoButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/RedoButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/SubscriptButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/SubscriptButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/TableButton.svelte +258 -0
- package/dist/editors/tiptap/toolbar/TableButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/ToolbarButton.svelte +84 -0
- package/dist/editors/tiptap/toolbar/ToolbarButton.svelte.d.ts +10 -0
- package/dist/editors/tiptap/toolbar/UnderlineButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/UnderlineButton.svelte.d.ts +7 -0
- package/dist/editors/tiptap/toolbar/UndoButton.svelte +18 -0
- package/dist/editors/tiptap/toolbar/UndoButton.svelte.d.ts +7 -0
- package/dist/form/Autocomplete.svelte +270 -137
- package/dist/form/Autocomplete.svelte.d.ts +58 -10
- package/dist/form/AutocompleteMulti.svelte +385 -227
- package/dist/form/AutocompleteMulti.svelte.d.ts +59 -10
- package/dist/form/Checkbox.svelte +124 -43
- package/dist/form/Checkbox.svelte.d.ts +26 -2
- package/dist/form/Chips.svelte +47 -17
- package/dist/form/Chips.svelte.d.ts +24 -3
- package/dist/form/ComboBox.svelte +30 -20
- package/dist/form/ComboBox.svelte.d.ts +1 -1
- package/dist/form/ComboBoxItemBuilder.svelte +161 -188
- package/dist/form/ComboBoxItemBuilder.svelte.d.ts +19 -2
- package/dist/form/ComboBoxMulti.svelte +38 -24
- package/dist/form/ComboBoxMulti.svelte.d.ts +1 -1
- package/dist/form/CronBuilder.svelte +84 -67
- package/dist/form/CronBuilder.svelte.d.ts +16 -3
- package/dist/form/DatePicker.svelte +177 -191
- package/dist/form/DatePicker.svelte.d.ts +17 -2
- package/dist/form/DateRangePicker.svelte +775 -0
- package/dist/form/DateRangePicker.svelte.d.ts +23 -0
- package/dist/form/DateTimePicker.svelte +168 -209
- package/dist/form/DateTimePicker.svelte.d.ts +10 -2
- package/dist/form/FormGroup.svelte +33 -10
- package/dist/form/FormGroup.svelte.d.ts +12 -2
- package/dist/form/Number.svelte +71 -29
- package/dist/form/Number.svelte.d.ts +39 -6
- package/dist/form/Radio.svelte +174 -0
- package/dist/form/Radio.svelte.d.ts +21 -0
- package/dist/form/RadioGroup.svelte +52 -138
- package/dist/form/RadioGroup.svelte.d.ts +19 -2
- package/dist/form/SegmentedControl.svelte +103 -57
- package/dist/form/SegmentedControl.svelte.d.ts +12 -2
- package/dist/form/Select.svelte +160 -229
- package/dist/form/Select.svelte.d.ts +35 -6
- package/dist/form/SelectMulti.svelte +166 -277
- package/dist/form/SelectMulti.svelte.d.ts +37 -6
- package/dist/form/Slider.svelte +185 -268
- package/dist/form/Slider.svelte.d.ts +33 -16
- package/dist/form/StringArrayBuilder.svelte +249 -0
- package/dist/form/StringArrayBuilder.svelte.d.ts +15 -0
- package/dist/form/Switch.svelte +164 -106
- package/dist/form/Switch.svelte.d.ts +22 -3
- package/dist/form/TextArea.svelte +80 -45
- package/dist/form/TextArea.svelte.d.ts +35 -10
- package/dist/form/Textbox.svelte +80 -47
- package/dist/form/Textbox.svelte.d.ts +41 -8
- package/dist/form/TimePicker.svelte +42 -47
- package/dist/form/TimePicker.svelte.d.ts +12 -2
- package/dist/form/comboBoxCore.svelte.d.ts +99 -0
- package/dist/form/comboBoxCore.svelte.js +243 -0
- package/dist/icon/Icon.svelte +8 -3
- package/dist/icon/Icon.svelte.d.ts +8 -3
- package/dist/icon/cube-send.svg +1 -0
- package/dist/icon/file-type-bmp.svg +1 -0
- package/dist/icon/file-type-csv.svg +1 -0
- package/dist/icon/file-type-doc.svg +1 -0
- package/dist/icon/file-type-docx.svg +1 -0
- package/dist/icon/file-type-jpg.svg +1 -0
- package/dist/icon/file-type-pdf.svg +1 -0
- package/dist/icon/file-type-png.svg +1 -0
- package/dist/icon/file-type-ppt.svg +1 -0
- package/dist/icon/file-type-svg.svg +1 -0
- package/dist/icon/file-type-txt.svg +1 -0
- package/dist/icon/file-type-xls.svg +1 -0
- package/dist/icon/file-type-zip.svg +1 -0
- package/dist/icon/index.d.ts +166 -145
- package/dist/icon/index.js +166 -146
- package/dist/icon/layout-sidebar-left-collapse.svg +1 -0
- package/dist/icon/layout-sidebar-left-expand.svg +1 -0
- package/dist/icon/logo-placeholder.svg +6 -0
- package/dist/icon/paperclip.svg +1 -0
- package/dist/icon/source-code.svg +1 -0
- package/dist/icon/sun-moon.svg +1 -0
- package/dist/icon/table.svg +6 -0
- package/dist/icon/thumb-down.svg +1 -0
- package/dist/icon/thumb-up.svg +1 -0
- package/dist/index.d.ts +93 -22
- package/dist/index.js +28 -27
- package/dist/layout/AppShell.svelte +12 -162
- package/dist/layout/AppShell.svelte.d.ts +6 -27
- package/dist/layout/CustomNavbar.svelte +9 -7
- package/dist/layout/CustomNavbar.svelte.d.ts +4 -2
- package/dist/layout/Navbar.svelte +158 -110
- package/dist/layout/Navbar.svelte.d.ts +26 -12
- package/dist/layout/NavbarItemDisplay.svelte +2 -2
- package/dist/layout/NavbarItemView.svelte +182 -0
- package/dist/layout/NavbarItemView.svelte.d.ts +10 -0
- package/dist/layout/Sidenav.svelte +280 -341
- package/dist/layout/Sidenav.svelte.d.ts +36 -4
- package/dist/models/ComboBoxItem.d.ts +2 -0
- package/dist/models/Employee.d.ts +53 -0
- package/dist/models/Employee.js +23 -0
- package/dist/models/Hyperlink.d.ts +3 -1
- package/dist/models/LinkCollectionItem.d.ts +3 -1
- package/dist/models/NavbarItem.d.ts +6 -2
- package/dist/theme.svelte.d.ts +0 -1
- package/dist/theme.svelte.js +46 -58
- package/dist/ui/Accordion.svelte +81 -242
- package/dist/ui/Accordion.svelte.d.ts +37 -14
- package/dist/ui/AccordionItem.svelte +303 -0
- package/dist/ui/AccordionItem.svelte.d.ts +21 -0
- package/dist/ui/ActionIcon.svelte +25 -21
- package/dist/ui/ActionIcon.svelte.d.ts +15 -2
- package/dist/ui/Badge.svelte +170 -161
- package/dist/ui/Badge.svelte.d.ts +16 -4
- package/dist/ui/Button.svelte +178 -205
- package/dist/ui/Button.svelte.d.ts +19 -2
- package/dist/ui/ButtonVariant.d.ts +15 -1
- package/dist/ui/ContextMenu.svelte +146 -0
- package/dist/ui/ContextMenu.svelte.d.ts +37 -0
- package/dist/ui/ContextMenuList.svelte +188 -0
- package/dist/ui/ContextMenuList.svelte.d.ts +12 -0
- package/dist/ui/Dialog.svelte +183 -104
- package/dist/ui/Dialog.svelte.d.ts +21 -2
- package/dist/ui/Drawer.svelte +237 -184
- package/dist/ui/Drawer.svelte.d.ts +20 -2
- package/dist/ui/Dropdown.svelte +24 -14
- package/dist/ui/Dropdown.svelte.d.ts +11 -2
- package/dist/ui/Dropzone.svelte +159 -57
- package/dist/ui/Dropzone.svelte.d.ts +29 -2
- package/dist/ui/Link.svelte +12 -4
- package/dist/ui/Link.svelte.d.ts +8 -2
- package/dist/ui/Loader.svelte +23 -18
- package/dist/ui/Loader.svelte.d.ts +5 -2
- package/dist/ui/Logo.svelte +37 -0
- package/dist/ui/Logo.svelte.d.ts +16 -0
- package/dist/ui/MultiSortable.svelte +287 -0
- package/dist/ui/MultiSortable.svelte.d.ts +50 -0
- package/dist/ui/Pagination.svelte +12 -6
- package/dist/ui/Pagination.svelte.d.ts +6 -2
- package/dist/ui/Popover.svelte +43 -65
- package/dist/ui/Popover.svelte.d.ts +14 -5
- package/dist/ui/ProgressBar.svelte +169 -0
- package/dist/ui/ProgressBar.svelte.d.ts +30 -0
- package/dist/ui/ProgressBarVariant.d.ts +7 -0
- package/dist/ui/ProgressBarVariant.js +1 -0
- package/dist/ui/SegmentedControl.svelte +0 -0
- package/dist/ui/SegmentedControl.svelte.d.ts +26 -0
- package/dist/ui/Sortable.svelte +163 -0
- package/dist/ui/Sortable.svelte.d.ts +47 -0
- package/dist/ui/Table.svelte +497 -56
- package/dist/ui/Table.svelte.d.ts +64 -2
- package/dist/ui/Tabs.svelte +22 -18
- package/dist/ui/Tabs.svelte.d.ts +6 -2
- package/dist/ui/ThemeSwitcher.svelte +26 -7
- package/dist/ui/ThemeSwitcher.svelte.d.ts +4 -2
- package/dist/ui/Tooltip.svelte +312 -180
- package/dist/ui/Tooltip.svelte.d.ts +4 -3
- package/dist/uiTheme.svelte.d.ts +86 -0
- package/dist/uiTheme.svelte.js +214 -0
- package/dist/util/DateFunctions.js +1 -1
- package/dist/util/DragDrop.d.ts +50 -0
- package/dist/util/DragDrop.js +154 -0
- package/dist/util/NavigateTo.js +2 -2
- package/dist/util/dayjs.d.ts +4 -0
- package/dist/util/dayjs.js +15 -0
- package/dist/util/interceptLinkClick.d.ts +13 -0
- package/dist/util/interceptLinkClick.js +33 -0
- package/package.json +66 -26
- package/dist/display/Alert.svelte +0 -179
- package/dist/display/Alert.svelte.d.ts +0 -13
- package/dist/form/FileInput.svelte +0 -235
- package/dist/form/FileInput.svelte.d.ts +0 -23
- package/dist/form/PasswordInput.svelte +0 -252
- package/dist/form/PasswordInput.svelte.d.ts +0 -33
- package/dist/form/Rating.svelte +0 -235
- package/dist/form/Rating.svelte.d.ts +0 -21
- package/dist/styles/components.css +0 -199
- package/dist/styles/dark.css +0 -146
- package/dist/styles/index.css +0 -116
- package/dist/styles/reset.css +0 -110
- package/dist/styles/semantic.css +0 -86
- package/dist/styles/tokens.css +0 -203
- package/dist/styles/utilities.css +0 -523
- package/dist/ui/Breadcrumbs.svelte +0 -131
- package/dist/ui/Breadcrumbs.svelte.d.ts +0 -16
- package/dist/ui/LoadingOverlay.svelte +0 -53
- package/dist/ui/LoadingOverlay.svelte.d.ts +0 -11
- package/dist/ui/Progress.svelte +0 -191
- package/dist/ui/Progress.svelte.d.ts +0 -15
- package/dist/ui/RingProgress.svelte +0 -141
- package/dist/ui/RingProgress.svelte.d.ts +0 -18
- package/dist/ui/Skeleton.svelte +0 -85
- package/dist/ui/Skeleton.svelte.d.ts +0 -12
- package/dist/ui/Stepper.svelte +0 -355
- package/dist/ui/Stepper.svelte.d.ts +0 -24
- package/dist/ui/Timeline.svelte +0 -225
- package/dist/ui/Timeline.svelte.d.ts +0 -23
- /package/dist/{actions → util}/ClickOutside.d.ts +0 -0
- /package/dist/{actions → util}/ClickOutside.js +0 -0
- /package/dist/{transitions → util}/Transitions.d.ts +0 -0
- /package/dist/{transitions → util}/Transitions.js +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** Brand colours. Accepts `#rgb`, `#rrggbb` or `rgb(r, g, b)` strings. */
|
|
2
|
+
export interface ThemeColors {
|
|
3
|
+
/** Dark brand colour. Used for solid buttons, headings and active states. */
|
|
4
|
+
primary: string;
|
|
5
|
+
/** Darker shade of `primary` for pressed states. Derived from `primary` when omitted. */
|
|
6
|
+
primaryDark?: string;
|
|
7
|
+
/** Text colour on top of `primary`. Defaults to white. */
|
|
8
|
+
primaryContrast?: string;
|
|
9
|
+
/** Light brand colour. Used for highlights, hovers and as the dark-mode accent. */
|
|
10
|
+
accent: string;
|
|
11
|
+
/** Darker shade of `accent`, used for hover text on light surfaces. Derived when omitted. */
|
|
12
|
+
accentDark?: string;
|
|
13
|
+
/** Text colour on top of `accent`. Defaults to `primary`. */
|
|
14
|
+
accentContrast?: string;
|
|
15
|
+
/** Light supporting colour. Defaults to `accent` when omitted. */
|
|
16
|
+
tertiary?: string;
|
|
17
|
+
/** Darker shade of `tertiary`, used for links and subtle text. Derived when omitted. */
|
|
18
|
+
tertiaryDark?: string;
|
|
19
|
+
/** Lighter shade of `tertiary`, used for pressed states on light buttons. Derived when omitted. */
|
|
20
|
+
tertiaryLight?: string;
|
|
21
|
+
/** Link colour. Defaults to `tertiaryDark`. */
|
|
22
|
+
link?: string;
|
|
23
|
+
/** Link hover colour. Defaults to `accentDark`. */
|
|
24
|
+
linkHover?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Settings that can be given per colour mode. Used as the base (light) config and,
|
|
28
|
+
* with every field optional, as the `dark` override block.
|
|
29
|
+
*/
|
|
30
|
+
export interface ThemeModeConfig {
|
|
31
|
+
/** Brand colours. In the `dark` block any subset may be given; shades are derived per colour. */
|
|
32
|
+
colors?: Partial<ThemeColors>;
|
|
33
|
+
/**
|
|
34
|
+
* CSS `font-family` value applied to the whole UI, e.g. `"'Inter', system-ui, sans-serif"`.
|
|
35
|
+
* Loading the font itself (`@font-face` or a `<link>`) is up to the consuming app.
|
|
36
|
+
*/
|
|
37
|
+
fontFamily?: string;
|
|
38
|
+
/** Raw SVG markup for the `Logo` component. Use `fill="currentColor"` so it follows the theme. */
|
|
39
|
+
logo?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Any additional custom properties to set, e.g. `{ '--page-bg': '#fff' }`.
|
|
42
|
+
* Useful for the surface tokens that are not part of `ThemeColors`.
|
|
43
|
+
*/
|
|
44
|
+
variables?: Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
export interface ThemeConfig extends ThemeModeConfig {
|
|
47
|
+
/** Brand colours for light mode (and dark mode unless overridden in `dark`). */
|
|
48
|
+
colors?: ThemeColors;
|
|
49
|
+
/**
|
|
50
|
+
* Overrides applied while dark mode is active (`.dark` on `<html>`). Anything not
|
|
51
|
+
* given here falls back to the light-mode value.
|
|
52
|
+
*/
|
|
53
|
+
dark?: ThemeModeConfig;
|
|
54
|
+
}
|
|
55
|
+
/** Reactive brand state consumed by components such as `Logo`. */
|
|
56
|
+
export declare const brandState: {
|
|
57
|
+
/** Logo for the active colour mode: the dark logo when set and dark mode is on, else the light one. */
|
|
58
|
+
readonly logo: string | undefined;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Set (or clear) the logo used by the `Logo` component. Pass a second argument to
|
|
62
|
+
* register a different logo for dark mode.
|
|
63
|
+
*/
|
|
64
|
+
export declare function setLogo(svg: string | undefined, darkSvg?: string): void;
|
|
65
|
+
/**
|
|
66
|
+
* Build the `--ui-*` custom property map for one colour mode. Only the groups whose
|
|
67
|
+
* base colour is present are emitted, so a partial `dark` block overrides just what
|
|
68
|
+
* it names. Unknown colour formats are passed through unchanged (their `-rgb`
|
|
69
|
+
* variants are skipped).
|
|
70
|
+
*/
|
|
71
|
+
export declare function themeToVariables(config: ThemeModeConfig): Record<string, string>;
|
|
72
|
+
/**
|
|
73
|
+
* Render a theme config as CSS: a light-mode rule on `selector` (default `:root`)
|
|
74
|
+
* and, when `dark` overrides are given, a second rule scoped to the `.dark` class.
|
|
75
|
+
* Put the result in a `<style>` tag in `app.html` so the brand is present before
|
|
76
|
+
* JavaScript runs.
|
|
77
|
+
*/
|
|
78
|
+
export declare function themeToCss(config: ThemeConfig, selector?: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* Apply a theme config at runtime. Injects (or replaces) a `<style>` element in
|
|
81
|
+
* `<head>` containing the light and dark rules, and registers the logo(s).
|
|
82
|
+
* Safe to call during SSR (the style injection is skipped).
|
|
83
|
+
*/
|
|
84
|
+
export declare function applyTheme(config: ThemeConfig): void;
|
|
85
|
+
/** Remove the theme rules injected by `applyTheme` and clear the logos. */
|
|
86
|
+
export declare function resetTheme(): void;
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brand / theme configuration for PlaceholderUI.
|
|
3
|
+
*
|
|
4
|
+
* The library is styled entirely through `--ui-*` CSS custom properties (see
|
|
5
|
+
* `app.css`). You can override those in your own stylesheet, or describe your
|
|
6
|
+
* brand once as a {@link ThemeConfig} and let the library generate them:
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { applyTheme } from '@placeholderco/placeholder-ui';
|
|
10
|
+
* import logo from './logo.svg?raw';
|
|
11
|
+
*
|
|
12
|
+
* applyTheme({
|
|
13
|
+
* colors: { primary: '#1e3a5f', accent: '#93c5fd', tertiary: '#a5f3fc' },
|
|
14
|
+
* fontFamily: "'Inter', system-ui, sans-serif",
|
|
15
|
+
* logo,
|
|
16
|
+
* // optional overrides used while the `.dark` class is on <html>
|
|
17
|
+
* dark: { colors: { accent: '#bfdbfe' } }
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* For server-side rendering (and to avoid a flash of the default palette) put
|
|
22
|
+
* `themeToCss(config)` into a `<style>` tag in your `app.html` / root layout.
|
|
23
|
+
*/
|
|
24
|
+
import { themeState } from './theme.svelte.js';
|
|
25
|
+
// ============================================
|
|
26
|
+
// Brand state (logo)
|
|
27
|
+
// ============================================
|
|
28
|
+
let lightLogo = $state(undefined);
|
|
29
|
+
let darkLogo = $state(undefined);
|
|
30
|
+
/** Reactive brand state consumed by components such as `Logo`. */
|
|
31
|
+
export const brandState = {
|
|
32
|
+
/** Logo for the active colour mode: the dark logo when set and dark mode is on, else the light one. */
|
|
33
|
+
get logo() {
|
|
34
|
+
return themeState.isDarkMode ? (darkLogo ?? lightLogo) : lightLogo;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Set (or clear) the logo used by the `Logo` component. Pass a second argument to
|
|
39
|
+
* register a different logo for dark mode.
|
|
40
|
+
*/
|
|
41
|
+
export function setLogo(svg, darkSvg) {
|
|
42
|
+
lightLogo = svg;
|
|
43
|
+
darkLogo = darkSvg;
|
|
44
|
+
}
|
|
45
|
+
function parseColor(input) {
|
|
46
|
+
const value = input.trim();
|
|
47
|
+
const hex = value.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
|
|
48
|
+
if (hex) {
|
|
49
|
+
let h = hex[1];
|
|
50
|
+
if (h.length === 3)
|
|
51
|
+
h = h
|
|
52
|
+
.split('')
|
|
53
|
+
.map((c) => c + c)
|
|
54
|
+
.join('');
|
|
55
|
+
const n = parseInt(h, 16);
|
|
56
|
+
return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
|
|
57
|
+
}
|
|
58
|
+
const rgb = value.match(/^rgba?\(\s*(\d+)[\s,]+(\d+)[\s,]+(\d+)/i);
|
|
59
|
+
if (rgb)
|
|
60
|
+
return [Number(rgb[1]), Number(rgb[2]), Number(rgb[3])];
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
function toHex([r, g, b]) {
|
|
64
|
+
return '#' + [r, g, b].map((c) => Math.round(clamp(c)).toString(16).padStart(2, '0')).join('');
|
|
65
|
+
}
|
|
66
|
+
function clamp(n) {
|
|
67
|
+
return Math.min(255, Math.max(0, n));
|
|
68
|
+
}
|
|
69
|
+
/** Mix a colour towards black (`amount` 0..1). */
|
|
70
|
+
function darken(rgb, amount) {
|
|
71
|
+
return rgb.map((c) => c * (1 - amount));
|
|
72
|
+
}
|
|
73
|
+
/** Mix a colour towards white (`amount` 0..1). */
|
|
74
|
+
function lighten(rgb, amount) {
|
|
75
|
+
return rgb.map((c) => c + (255 - c) * amount);
|
|
76
|
+
}
|
|
77
|
+
// ============================================
|
|
78
|
+
// Config -> CSS variables
|
|
79
|
+
// ============================================
|
|
80
|
+
/**
|
|
81
|
+
* Build the `--ui-*` custom property map for one colour mode. Only the groups whose
|
|
82
|
+
* base colour is present are emitted, so a partial `dark` block overrides just what
|
|
83
|
+
* it names. Unknown colour formats are passed through unchanged (their `-rgb`
|
|
84
|
+
* variants are skipped).
|
|
85
|
+
*/
|
|
86
|
+
export function themeToVariables(config) {
|
|
87
|
+
const vars = {};
|
|
88
|
+
const c = config.colors;
|
|
89
|
+
if (c) {
|
|
90
|
+
if (c.primary) {
|
|
91
|
+
const primary = parseColor(c.primary);
|
|
92
|
+
setColor(vars, 'primary', c.primary, primary);
|
|
93
|
+
vars['--ui-primary-dark'] =
|
|
94
|
+
c.primaryDark ?? (primary ? toHex(darken(primary, 0.35)) : c.primary);
|
|
95
|
+
vars['--ui-primary-contrast'] = c.primaryContrast ?? '#ffffff';
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
if (c.primaryDark)
|
|
99
|
+
vars['--ui-primary-dark'] = c.primaryDark;
|
|
100
|
+
if (c.primaryContrast)
|
|
101
|
+
vars['--ui-primary-contrast'] = c.primaryContrast;
|
|
102
|
+
}
|
|
103
|
+
if (c.accent) {
|
|
104
|
+
const accent = parseColor(c.accent);
|
|
105
|
+
setColor(vars, 'accent', c.accent, accent);
|
|
106
|
+
vars['--ui-accent-dark'] = c.accentDark ?? (accent ? toHex(darken(accent, 0.5)) : c.accent);
|
|
107
|
+
vars['--ui-accent-contrast'] = c.accentContrast ?? 'var(--ui-primary)';
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
if (c.accentDark)
|
|
111
|
+
vars['--ui-accent-dark'] = c.accentDark;
|
|
112
|
+
if (c.accentContrast)
|
|
113
|
+
vars['--ui-accent-contrast'] = c.accentContrast;
|
|
114
|
+
}
|
|
115
|
+
const tertiarySource = c.tertiary ?? c.accent;
|
|
116
|
+
if (tertiarySource) {
|
|
117
|
+
const tertiary = parseColor(tertiarySource);
|
|
118
|
+
setColor(vars, 'tertiary', tertiarySource, tertiary);
|
|
119
|
+
setTertiaryDark(vars, c.tertiaryDark ?? (tertiary ? toHex(darken(tertiary, 0.45)) : tertiarySource));
|
|
120
|
+
vars['--ui-tertiary-light'] =
|
|
121
|
+
c.tertiaryLight ?? (tertiary ? toHex(lighten(tertiary, 0.5)) : tertiarySource);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
if (c.tertiaryDark)
|
|
125
|
+
setTertiaryDark(vars, c.tertiaryDark);
|
|
126
|
+
if (c.tertiaryLight)
|
|
127
|
+
vars['--ui-tertiary-light'] = c.tertiaryLight;
|
|
128
|
+
}
|
|
129
|
+
if (c.link)
|
|
130
|
+
vars['--ui-link-color'] = c.link;
|
|
131
|
+
if (c.linkHover)
|
|
132
|
+
vars['--ui-link-hover-color'] = c.linkHover;
|
|
133
|
+
}
|
|
134
|
+
if (config.fontFamily)
|
|
135
|
+
vars['--ui-font-family'] = config.fontFamily;
|
|
136
|
+
if (config.variables)
|
|
137
|
+
Object.assign(vars, config.variables);
|
|
138
|
+
return vars;
|
|
139
|
+
}
|
|
140
|
+
function setColor(vars, name, raw, rgb) {
|
|
141
|
+
if (rgb) {
|
|
142
|
+
vars[`--ui-${name}-rgb`] = rgb.join(' ');
|
|
143
|
+
vars[`--ui-${name}-rgbc`] = rgb.join(', ');
|
|
144
|
+
vars[`--ui-${name}`] = `rgb(var(--ui-${name}-rgb))`;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
vars[`--ui-${name}`] = raw;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function setTertiaryDark(vars, value) {
|
|
151
|
+
const rgb = parseColor(value);
|
|
152
|
+
if (rgb) {
|
|
153
|
+
vars['--ui-tertiary-dark-rgbc'] = rgb.join(', ');
|
|
154
|
+
vars['--ui-tertiary-dark'] = 'rgb(var(--ui-tertiary-dark-rgbc))';
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
vars['--ui-tertiary-dark'] = value;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function toRule(selector, vars) {
|
|
161
|
+
const body = Object.entries(vars)
|
|
162
|
+
.map(([k, v]) => `\t${k}: ${v};`)
|
|
163
|
+
.join('\n');
|
|
164
|
+
return `${selector} {\n${body}\n}`;
|
|
165
|
+
}
|
|
166
|
+
/** Selector for the dark-mode block: `.dark` sits on `<html>`, so root selectors get it appended. */
|
|
167
|
+
function darkSelector(selector) {
|
|
168
|
+
return /^(html|:root)/.test(selector) ? `${selector}.dark` : `.dark ${selector}`;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Render a theme config as CSS: a light-mode rule on `selector` (default `:root`)
|
|
172
|
+
* and, when `dark` overrides are given, a second rule scoped to the `.dark` class.
|
|
173
|
+
* Put the result in a `<style>` tag in `app.html` so the brand is present before
|
|
174
|
+
* JavaScript runs.
|
|
175
|
+
*/
|
|
176
|
+
export function themeToCss(config, selector = ':root') {
|
|
177
|
+
const rules = [toRule(selector, themeToVariables(config))];
|
|
178
|
+
if (config.dark) {
|
|
179
|
+
const darkVars = themeToVariables(config.dark);
|
|
180
|
+
if (Object.keys(darkVars).length)
|
|
181
|
+
rules.push(toRule(darkSelector(selector), darkVars));
|
|
182
|
+
}
|
|
183
|
+
return rules.join('\n\n');
|
|
184
|
+
}
|
|
185
|
+
// ============================================
|
|
186
|
+
// Runtime application
|
|
187
|
+
// ============================================
|
|
188
|
+
const STYLE_ID = 'placeholderui-theme';
|
|
189
|
+
/**
|
|
190
|
+
* Apply a theme config at runtime. Injects (or replaces) a `<style>` element in
|
|
191
|
+
* `<head>` containing the light and dark rules, and registers the logo(s).
|
|
192
|
+
* Safe to call during SSR (the style injection is skipped).
|
|
193
|
+
*/
|
|
194
|
+
export function applyTheme(config) {
|
|
195
|
+
if (config.logo !== undefined || config.dark?.logo !== undefined) {
|
|
196
|
+
setLogo(config.logo, config.dark?.logo);
|
|
197
|
+
}
|
|
198
|
+
if (typeof document === 'undefined')
|
|
199
|
+
return;
|
|
200
|
+
let style = document.getElementById(STYLE_ID);
|
|
201
|
+
if (!style) {
|
|
202
|
+
style = document.createElement('style');
|
|
203
|
+
style.id = STYLE_ID;
|
|
204
|
+
document.head.appendChild(style);
|
|
205
|
+
}
|
|
206
|
+
style.textContent = themeToCss(config);
|
|
207
|
+
}
|
|
208
|
+
/** Remove the theme rules injected by `applyTheme` and clear the logos. */
|
|
209
|
+
export function resetTheme() {
|
|
210
|
+
setLogo(undefined);
|
|
211
|
+
if (typeof document === 'undefined')
|
|
212
|
+
return;
|
|
213
|
+
document.getElementById(STYLE_ID)?.remove();
|
|
214
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level drag/drop primitives for the UI library.
|
|
3
|
+
*
|
|
4
|
+
* Two Svelte actions — `draggable` and `droppable` — communicate via a shared
|
|
5
|
+
* in-memory drag context. The HTML5 DnD API's dataTransfer is intentionally NOT
|
|
6
|
+
* used to carry rich payloads (it stringifies and is unreadable during dragover),
|
|
7
|
+
* so the context lives in module scope and any droppable can inspect it.
|
|
8
|
+
*/
|
|
9
|
+
export interface DragContext<T = unknown> {
|
|
10
|
+
/** Identifier of the source widget — e.g. the Sortable instance id */
|
|
11
|
+
source: string;
|
|
12
|
+
/** Application payload (item, index, ids, etc.) */
|
|
13
|
+
payload: T;
|
|
14
|
+
/** Logical type used by droppables to filter what they accept */
|
|
15
|
+
type: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function getActiveDrag(): DragContext | null;
|
|
18
|
+
export interface DraggableOptions<T = unknown> {
|
|
19
|
+
/** Application payload to carry */
|
|
20
|
+
payload: T;
|
|
21
|
+
/** Logical type — droppables filter by this */
|
|
22
|
+
type?: string;
|
|
23
|
+
/** Source widget identifier */
|
|
24
|
+
source?: string;
|
|
25
|
+
/** When true, drag is suppressed */
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
/** Optional CSS selector — drag only initiates if pointerdown hit this element inside the node */
|
|
28
|
+
handle?: string;
|
|
29
|
+
onDragStart?: (ctx: DragContext<T>, event: DragEvent) => void;
|
|
30
|
+
onDragEnd?: (event: DragEvent) => void;
|
|
31
|
+
}
|
|
32
|
+
export declare function draggable<T>(node: HTMLElement, opts: DraggableOptions<T>): {
|
|
33
|
+
update(next: DraggableOptions<T>): void;
|
|
34
|
+
destroy(): void;
|
|
35
|
+
};
|
|
36
|
+
export interface DroppableOptions<T = unknown> {
|
|
37
|
+
/** Accept only these logical types. Omit to accept any active drag. */
|
|
38
|
+
accepts?: string | string[];
|
|
39
|
+
/** Custom predicate — return false to ignore the active drag */
|
|
40
|
+
canDrop?: (ctx: DragContext<T>) => boolean;
|
|
41
|
+
disabled?: boolean;
|
|
42
|
+
onDragEnter?: (ctx: DragContext<T>, event: DragEvent) => void;
|
|
43
|
+
onDragOver?: (ctx: DragContext<T>, event: DragEvent) => void;
|
|
44
|
+
onDragLeave?: (ctx: DragContext<T>, event: DragEvent) => void;
|
|
45
|
+
onDrop?: (ctx: DragContext<T>, event: DragEvent) => void;
|
|
46
|
+
}
|
|
47
|
+
export declare function droppable<T>(node: HTMLElement, opts: DroppableOptions<T>): {
|
|
48
|
+
update(next: DroppableOptions<T>): void;
|
|
49
|
+
destroy(): void;
|
|
50
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level drag/drop primitives for the UI library.
|
|
3
|
+
*
|
|
4
|
+
* Two Svelte actions — `draggable` and `droppable` — communicate via a shared
|
|
5
|
+
* in-memory drag context. The HTML5 DnD API's dataTransfer is intentionally NOT
|
|
6
|
+
* used to carry rich payloads (it stringifies and is unreadable during dragover),
|
|
7
|
+
* so the context lives in module scope and any droppable can inspect it.
|
|
8
|
+
*/
|
|
9
|
+
let activeDrag = null;
|
|
10
|
+
export function getActiveDrag() {
|
|
11
|
+
return activeDrag;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The element the browser chose as the drag source: the nearest draggable ancestor
|
|
15
|
+
* of the event target. Drag events bubble, so a draggable's listeners also receive
|
|
16
|
+
* events from drags that started on a nested draggable — those are not ours to
|
|
17
|
+
* claim (that would overwrite the shared drag context) or cancel via preventDefault.
|
|
18
|
+
* Native draggables without the attribute (img, a[href]) resolve to their host node,
|
|
19
|
+
* so dragging those still starts the host item's drag.
|
|
20
|
+
*/
|
|
21
|
+
function dragSourceOf(e) {
|
|
22
|
+
const target = e.target;
|
|
23
|
+
return target?.closest?.('[draggable="true"]') ?? null;
|
|
24
|
+
}
|
|
25
|
+
export function draggable(node, opts) {
|
|
26
|
+
let options = opts;
|
|
27
|
+
let handleActive = !options.handle;
|
|
28
|
+
function onPointerDown(e) {
|
|
29
|
+
if (!options.handle) {
|
|
30
|
+
handleActive = true;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const target = e.target;
|
|
34
|
+
handleActive = !!target?.closest(options.handle);
|
|
35
|
+
}
|
|
36
|
+
function onDragStart(e) {
|
|
37
|
+
if (dragSourceOf(e) !== node)
|
|
38
|
+
return;
|
|
39
|
+
if (options.disabled || !handleActive) {
|
|
40
|
+
e.preventDefault();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const ctx = {
|
|
44
|
+
source: options.source ?? '',
|
|
45
|
+
payload: options.payload,
|
|
46
|
+
type: options.type ?? 'default'
|
|
47
|
+
};
|
|
48
|
+
activeDrag = ctx;
|
|
49
|
+
if (e.dataTransfer) {
|
|
50
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
51
|
+
// Firefox requires data to be set to initiate drag
|
|
52
|
+
try {
|
|
53
|
+
e.dataTransfer.setData('text/plain', '');
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
/* ignore */
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
node.classList.add('pui-dragging');
|
|
60
|
+
options.onDragStart?.(ctx, e);
|
|
61
|
+
}
|
|
62
|
+
function onDragEnd(e) {
|
|
63
|
+
if (dragSourceOf(e) !== node)
|
|
64
|
+
return;
|
|
65
|
+
node.classList.remove('pui-dragging');
|
|
66
|
+
options.onDragEnd?.(e);
|
|
67
|
+
activeDrag = null;
|
|
68
|
+
}
|
|
69
|
+
node.setAttribute('draggable', 'true');
|
|
70
|
+
node.addEventListener('pointerdown', onPointerDown);
|
|
71
|
+
node.addEventListener('dragstart', onDragStart);
|
|
72
|
+
node.addEventListener('dragend', onDragEnd);
|
|
73
|
+
return {
|
|
74
|
+
update(next) {
|
|
75
|
+
options = next;
|
|
76
|
+
if (!options.handle)
|
|
77
|
+
handleActive = true;
|
|
78
|
+
},
|
|
79
|
+
destroy() {
|
|
80
|
+
node.removeEventListener('pointerdown', onPointerDown);
|
|
81
|
+
node.removeEventListener('dragstart', onDragStart);
|
|
82
|
+
node.removeEventListener('dragend', onDragEnd);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export function droppable(node, opts) {
|
|
87
|
+
let options = opts;
|
|
88
|
+
let depth = 0;
|
|
89
|
+
function shouldAccept() {
|
|
90
|
+
if (!activeDrag || options.disabled)
|
|
91
|
+
return false;
|
|
92
|
+
if (options.accepts) {
|
|
93
|
+
const list = Array.isArray(options.accepts) ? options.accepts : [options.accepts];
|
|
94
|
+
if (!list.includes(activeDrag.type))
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
if (options.canDrop && !options.canDrop(activeDrag))
|
|
98
|
+
return false;
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
function onDragEnter(e) {
|
|
102
|
+
if (!shouldAccept())
|
|
103
|
+
return;
|
|
104
|
+
depth++;
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
if (depth === 1) {
|
|
107
|
+
node.classList.add('pui-drop-over');
|
|
108
|
+
options.onDragEnter?.(activeDrag, e);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function onDragOver(e) {
|
|
112
|
+
if (!shouldAccept())
|
|
113
|
+
return;
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
if (e.dataTransfer)
|
|
116
|
+
e.dataTransfer.dropEffect = 'move';
|
|
117
|
+
options.onDragOver?.(activeDrag, e);
|
|
118
|
+
}
|
|
119
|
+
function onDragLeave(e) {
|
|
120
|
+
if (!shouldAccept())
|
|
121
|
+
return;
|
|
122
|
+
depth--;
|
|
123
|
+
if (depth <= 0) {
|
|
124
|
+
depth = 0;
|
|
125
|
+
node.classList.remove('pui-drop-over');
|
|
126
|
+
options.onDragLeave?.(activeDrag, e);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function onDrop(e) {
|
|
130
|
+
if (!shouldAccept())
|
|
131
|
+
return;
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
e.stopPropagation();
|
|
134
|
+
depth = 0;
|
|
135
|
+
node.classList.remove('pui-drop-over');
|
|
136
|
+
const ctx = activeDrag;
|
|
137
|
+
options.onDrop?.(ctx, e);
|
|
138
|
+
}
|
|
139
|
+
node.addEventListener('dragenter', onDragEnter);
|
|
140
|
+
node.addEventListener('dragover', onDragOver);
|
|
141
|
+
node.addEventListener('dragleave', onDragLeave);
|
|
142
|
+
node.addEventListener('drop', onDrop);
|
|
143
|
+
return {
|
|
144
|
+
update(next) {
|
|
145
|
+
options = next;
|
|
146
|
+
},
|
|
147
|
+
destroy() {
|
|
148
|
+
node.removeEventListener('dragenter', onDragEnter);
|
|
149
|
+
node.removeEventListener('dragover', onDragOver);
|
|
150
|
+
node.removeEventListener('dragleave', onDragLeave);
|
|
151
|
+
node.removeEventListener('drop', onDrop);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
package/dist/util/NavigateTo.js
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import advancedFormat from 'dayjs/plugin/advancedFormat.js';
|
|
3
|
+
import customParseFormat from 'dayjs/plugin/customParseFormat.js';
|
|
4
|
+
// Configure the shared dayjs singleton. dayjs is a singleton, so extending it
|
|
5
|
+
// here applies globally wherever this module is loaded: every date component
|
|
6
|
+
// gets the same setup, and consumers can import a ready-to-use instance instead
|
|
7
|
+
// of installing and configuring dayjs themselves.
|
|
8
|
+
// - customParseFormat: used internally — the date/time pickers parse input
|
|
9
|
+
// against format arrays such as ['D MMMM YYYY', 'DD/MM/YYYY'].
|
|
10
|
+
// - advancedFormat: not used by this library's own components; bundled as a
|
|
11
|
+
// convenience so consumers get tokens like Do / Q / X out of the box.
|
|
12
|
+
dayjs.extend(advancedFormat);
|
|
13
|
+
dayjs.extend(customParseFormat);
|
|
14
|
+
export { dayjs };
|
|
15
|
+
export default dayjs;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface InterceptLinkClickOptions {
|
|
2
|
+
/** URL to navigate to */
|
|
3
|
+
href?: string;
|
|
4
|
+
/** Link target attribute */
|
|
5
|
+
target?: '_self' | '_blank' | undefined;
|
|
6
|
+
/** Additional click handler to run before navigation */
|
|
7
|
+
onclick?: (event: MouseEvent) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Intercepts link clicks to use client-side navigation for internal links.
|
|
11
|
+
* Preserves standard browser behavior for external links, modifier keys, and middle clicks.
|
|
12
|
+
*/
|
|
13
|
+
export declare function interceptLinkClick(event: MouseEvent, options: InterceptLinkClickOptions): void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { navigateTo } from './NavigateTo.js';
|
|
2
|
+
/**
|
|
3
|
+
* Intercepts link clicks to use client-side navigation for internal links.
|
|
4
|
+
* Preserves standard browser behavior for external links, modifier keys, and middle clicks.
|
|
5
|
+
*/
|
|
6
|
+
export function interceptLinkClick(event, options) {
|
|
7
|
+
const { href, target, onclick } = options;
|
|
8
|
+
// Call user-provided onclick handler first
|
|
9
|
+
if (onclick) {
|
|
10
|
+
onclick(event);
|
|
11
|
+
}
|
|
12
|
+
// Don't intercept if event was prevented by user handler
|
|
13
|
+
if (event.defaultPrevented) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
// Don't intercept external links
|
|
17
|
+
if (!href?.startsWith('/')) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
// Don't intercept if target is _blank or modifier keys are pressed
|
|
21
|
+
// This preserves standard browser behavior for opening in new tabs
|
|
22
|
+
if (target === '_blank' || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Don't intercept middle mouse button clicks
|
|
26
|
+
if (event.button !== 0) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// Prevent default navigation and use SvelteKit's client-side navigation
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
if (href)
|
|
32
|
+
navigateTo(href);
|
|
33
|
+
}
|