@geoffcox/sterling-svelte 2.0.0 → 2.0.2

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 (127) hide show
  1. package/package.json +21 -23
  2. package/.DS_Store +0 -0
  3. package/@types/clickOutside.d.ts +0 -15
  4. package/Button.svelte +0 -25
  5. package/Button.svelte.d.ts +0 -9
  6. package/Callout.svelte +0 -177
  7. package/Callout.svelte.d.ts +0 -15
  8. package/Callout.types.d.ts +0 -11
  9. package/Callout.types.js +0 -1
  10. package/Checkbox.svelte +0 -43
  11. package/Checkbox.svelte.d.ts +0 -10
  12. package/Dialog.svelte +0 -151
  13. package/Dialog.svelte.d.ts +0 -14
  14. package/Dropdown.svelte +0 -109
  15. package/Dropdown.svelte.d.ts +0 -18
  16. package/Input.svelte +0 -55
  17. package/Input.svelte.d.ts +0 -12
  18. package/Label.constants.d.ts +0 -2
  19. package/Label.constants.js +0 -2
  20. package/Label.svelte +0 -91
  21. package/Label.svelte.d.ts +0 -17
  22. package/Link.svelte +0 -25
  23. package/Link.svelte.d.ts +0 -12
  24. package/List.constants.d.ts +0 -1
  25. package/List.constants.js +0 -1
  26. package/List.svelte +0 -203
  27. package/List.svelte.d.ts +0 -20
  28. package/List.types.d.ts +0 -5
  29. package/List.types.js +0 -1
  30. package/ListItem.svelte +0 -49
  31. package/ListItem.svelte.d.ts +0 -13
  32. package/Menu.svelte +0 -83
  33. package/Menu.svelte.d.ts +0 -13
  34. package/MenuBar.constants.d.ts +0 -1
  35. package/MenuBar.constants.js +0 -1
  36. package/MenuBar.svelte +0 -113
  37. package/MenuBar.svelte.d.ts +0 -13
  38. package/MenuBar.types.d.ts +0 -4
  39. package/MenuBar.types.js +0 -1
  40. package/MenuButton.svelte +0 -116
  41. package/MenuButton.svelte.d.ts +0 -20
  42. package/MenuItem.constants.d.ts +0 -2
  43. package/MenuItem.constants.js +0 -2
  44. package/MenuItem.svelte +0 -342
  45. package/MenuItem.svelte.d.ts +0 -22
  46. package/MenuItem.types.d.ts +0 -20
  47. package/MenuItem.types.js +0 -1
  48. package/MenuItem.utils.d.ts +0 -7
  49. package/MenuItem.utils.js +0 -36
  50. package/MenuSeparator.svelte +0 -11
  51. package/MenuSeparator.svelte.d.ts +0 -6
  52. package/Popover.constants.d.ts +0 -1
  53. package/Popover.constants.js +0 -14
  54. package/Popover.svelte +0 -121
  55. package/Popover.svelte.d.ts +0 -15
  56. package/Popover.types.d.ts +0 -4
  57. package/Popover.types.js +0 -1
  58. package/Portal.constants.d.ts +0 -2
  59. package/Portal.constants.js +0 -2
  60. package/Portal.types.d.ts +0 -6
  61. package/Portal.types.js +0 -1
  62. package/Progress.constants.d.ts +0 -1
  63. package/Progress.constants.js +0 -1
  64. package/Progress.svelte +0 -36
  65. package/Progress.svelte.d.ts +0 -12
  66. package/Progress.types.d.ts +0 -4
  67. package/Progress.types.js +0 -1
  68. package/Radio.svelte +0 -53
  69. package/Radio.svelte.d.ts +0 -13
  70. package/Select.svelte +0 -196
  71. package/Select.svelte.d.ts +0 -20
  72. package/Slider.svelte +0 -133
  73. package/Slider.svelte.d.ts +0 -19
  74. package/Switch.svelte +0 -61
  75. package/Switch.svelte.d.ts +0 -21
  76. package/Tab.svelte +0 -51
  77. package/Tab.svelte.d.ts +0 -12
  78. package/TabList.constants.d.ts +0 -1
  79. package/TabList.constants.js +0 -1
  80. package/TabList.svelte +0 -202
  81. package/TabList.svelte.d.ts +0 -18
  82. package/TabList.types.d.ts +0 -5
  83. package/TabList.types.js +0 -1
  84. package/TextArea.constants.d.ts +0 -1
  85. package/TextArea.constants.js +0 -1
  86. package/TextArea.svelte +0 -74
  87. package/TextArea.svelte.d.ts +0 -19
  88. package/TextArea.types.d.ts +0 -4
  89. package/TextArea.types.js +0 -1
  90. package/Tooltip.svelte +0 -63
  91. package/Tooltip.svelte.d.ts +0 -10
  92. package/Tree.constants.d.ts +0 -1
  93. package/Tree.constants.js +0 -1
  94. package/Tree.svelte +0 -53
  95. package/Tree.svelte.d.ts +0 -15
  96. package/Tree.types.d.ts +0 -5
  97. package/Tree.types.js +0 -1
  98. package/TreeChevron.svelte +0 -27
  99. package/TreeChevron.svelte.d.ts +0 -9
  100. package/TreeItem.constants.d.ts +0 -1
  101. package/TreeItem.constants.js +0 -1
  102. package/TreeItem.svelte +0 -329
  103. package/TreeItem.svelte.d.ts +0 -22
  104. package/TreeItem.types.d.ts +0 -4
  105. package/TreeItem.types.js +0 -1
  106. package/actions/applyLightDarkMode.d.ts +0 -10
  107. package/actions/applyLightDarkMode.js +0 -36
  108. package/actions/clickOutside.d.ts +0 -15
  109. package/actions/clickOutside.js +0 -28
  110. package/actions/extraClass.d.ts +0 -8
  111. package/actions/extraClass.js +0 -14
  112. package/actions/forwardEvents.d.ts +0 -12
  113. package/actions/forwardEvents.js +0 -32
  114. package/actions/portal.d.ts +0 -8
  115. package/actions/portal.js +0 -19
  116. package/actions/trapKeyboardFocus.d.ts +0 -3
  117. package/actions/trapKeyboardFocus.js +0 -52
  118. package/idGenerator.d.ts +0 -4
  119. package/idGenerator.js +0 -10
  120. package/index.d.ts +0 -59
  121. package/index.js +0 -54
  122. package/mediaQueries/prefersColorSchemeDark.d.ts +0 -2
  123. package/mediaQueries/prefersColorSchemeDark.js +0 -14
  124. package/mediaQueries/prefersReducedMotion.d.ts +0 -2
  125. package/mediaQueries/prefersReducedMotion.js +0 -14
  126. package/mediaQueries/usingKeyboard.d.ts +0 -2
  127. package/mediaQueries/usingKeyboard.js +0 -17
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geoffcox/sterling-svelte",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "author": "Geoff Cox",
5
5
  "description": "A modern, accessible, and lightweight UI component library for Svelte.",
6
6
  "license": "MIT",
@@ -46,7 +46,7 @@
46
46
  }
47
47
  },
48
48
  "files": [
49
- "**/*",
49
+ "dist",
50
50
  "!**/*.test.*",
51
51
  "!**/*.spec.*"
52
52
  ],
@@ -60,40 +60,38 @@
60
60
  "package": "svelte-kit sync && svelte-package && publint",
61
61
  "preview": "vite preview",
62
62
  "test": "npm run test:integration && npm run test:unit",
63
- "test:integration": "playwright test",
64
63
  "test:unit": "vitest"
65
64
  },
66
65
  "peerDependencies": {
67
66
  "svelte": "^5.0.0"
68
67
  },
69
68
  "devDependencies": {
69
+ "@eslint/compat": "^1.2.5",
70
+ "@eslint/js": "^9.18.0",
70
71
  "@fontsource/atkinson-hyperlegible": "^5.1.1",
71
- "@fontsource/open-sans": "^4.5.14",
72
72
  "@fontsource/source-code-pro": "^4.5.14",
73
- "@geoffcox/sterling-svelte-themes": "^1.0.2",
74
- "@eslint/compat": "^1.2.3",
75
- "@playwright/test": "^1.45.3",
76
- "@sveltejs/adapter-auto": "^3.0.0",
77
- "@sveltejs/adapter-static": "^3.0.0",
78
- "@sveltejs/kit": "^2.0.0",
73
+ "@geoffcox/sterling-svelte-themes": "^1.0.4",
74
+ "@sveltejs/adapter-static": "^3.0.8",
75
+ "@sveltejs/kit": "^2.16.0",
79
76
  "@sveltejs/package": "^2.0.0",
80
- "@sveltejs/vite-plugin-svelte": "^4.0.0",
81
- "@types/eslint": "^8.56.7",
77
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
78
+ "@testing-library/jest-dom": "^6.6.3",
79
+ "@testing-library/svelte": "^5.2.4",
82
80
  "@types/lodash-es": "^4.17.6",
83
- "eslint": "^9.7.0",
84
- "eslint-config-prettier": "^9.1.0",
85
- "eslint-plugin-svelte": "^2.36.0",
86
- "globals": "^15.0.0",
87
- "prettier": "^3.3.2",
88
- "prettier-plugin-svelte": "^3.2.6",
89
- "publint": "^0.2.0",
81
+ "eslint": "^9.18.0",
82
+ "eslint-config-prettier": "^10.0.1",
83
+ "eslint-plugin-svelte": "^3.0.0",
84
+ "globals": "^16.0.0",
85
+ "jsdom": "^26.0.0",
86
+ "prettier": "^3.4.2",
87
+ "prettier-plugin-svelte": "^3.3.3",
88
+ "publint": "^0.3.2",
90
89
  "svelte": "^5.0.0",
91
90
  "svelte-check": "^4.0.0",
92
- "svelte-preprocess": "^6.0.3",
93
91
  "typescript": "^5.0.0",
94
- "typescript-eslint": "^8.0.0",
95
- "vite": "^5.4.11",
96
- "vitest": "^2.1.4"
92
+ "typescript-eslint": "^8.20.0",
93
+ "vite": "^6.0.0",
94
+ "vitest": "^3.0.0"
97
95
  },
98
96
  "dependencies": {
99
97
  "@floating-ui/dom": "^1.1.0",
package/.DS_Store DELETED
Binary file
@@ -1,15 +0,0 @@
1
- import type { EventHandler } from 'svelte/elements';
2
-
3
- export type ClickOutsideEventDetail = {
4
- mouseEvent: MouseEvent;
5
- };
6
-
7
- export type ClickOutsideEvent = CustomEvent<ClickOutsideEventDetail>;
8
-
9
- declare module 'svelte/elements' {
10
- export interface DOMAttributes<T extends EventTarget> {
11
- 'on:click_outside'?: EventHandler<ClickOutsideEvent, T>;
12
- }
13
- }
14
-
15
- export {}; // ensure this is not an ambient module, else types will be overridden instead of augmented
package/Button.svelte DELETED
@@ -1,25 +0,0 @@
1
- <svelte:options runes={true} />
2
-
3
- <script lang="ts">let { children, class: _class, ...rest } = $props();
4
- let buttonRef;
5
- export const click = () => {
6
- buttonRef?.click();
7
- };
8
- export const blur = () => {
9
- buttonRef?.blur();
10
- };
11
- export const focus = (options) => {
12
- buttonRef?.focus(options);
13
- };
14
- </script>
15
-
16
- <button
17
- bind:this={buttonRef}
18
- class={['sterling-button', _class].filter(Boolean).join(' ')}
19
- type="button"
20
- {...rest}
21
- >
22
- {#if children}
23
- {@render children()}
24
- {/if}
25
- </button>
@@ -1,9 +0,0 @@
1
- /// <reference types="svelte" />
2
- import type { HTMLButtonAttributes } from 'svelte/elements';
3
- declare const Button: import("svelte").Component<HTMLButtonAttributes, {
4
- click: () => void;
5
- blur: () => void;
6
- focus: (options?: FocusOptions) => void;
7
- }, "">;
8
- type Button = ReturnType<typeof Button>;
9
- export default Button;
package/Callout.svelte DELETED
@@ -1,177 +0,0 @@
1
- <svelte:options runes={true} />
2
-
3
- <script lang="ts">import { getContext, tick } from 'svelte';
4
- import { arrow, autoUpdate, computePosition, flip, offset } from '@floating-ui/dom';
5
- import { portal } from './actions/portal';
6
- import { fade } from 'svelte/transition';
7
- import { prefersReducedMotion } from './mediaQueries/prefersReducedMotion';
8
- import { STERLING_PORTAL_HOST_ID, STERLING_PORTAL_CONTEXT_ID } from './Portal.constants';
9
- let { children, conditionalRender = $bindable(true), crossAxisOffset = $bindable(0), mainAxisOffset = $bindable(0), open = $bindable(false), placement = $bindable('top-start'), portalHost, reference, class: _class, ...rest } = $props();
10
- let popupRef = $state(undefined);
11
- let arrowRef = $state(undefined);
12
- let popupPosition = $state({ x: 0, y: 0 });
13
- let floatingUIPlacement = $derived(placement);
14
- let bodyHeight = $state(0);
15
- let resizeObserver = undefined;
16
- const { portalHost: contextPortalHost } = getContext(STERLING_PORTAL_CONTEXT_ID) || {
17
- portalHost: undefined
18
- };
19
- const ensurePortalHost = async () => {
20
- await tick();
21
- // use the host set from context, usually set from a Dialog
22
- let host = $contextPortalHost;
23
- // use or create the sterling portal host
24
- if (!host && globalThis?.document) {
25
- host = globalThis.document.querySelector(`#${STERLING_PORTAL_HOST_ID}`);
26
- // fallback to creating the sterling portal host
27
- if (!host) {
28
- host = globalThis.document.createElement('div');
29
- host.id = STERLING_PORTAL_HOST_ID;
30
- host.style.overflow = 'visible';
31
- globalThis.document.body.append(host);
32
- }
33
- }
34
- portalHost = host;
35
- };
36
- let middleware = $derived([
37
- offset({ mainAxis: mainAxisOffset, crossAxis: crossAxisOffset }),
38
- flip(),
39
- arrowRef && arrow({ element: arrowRef, padding: 8 })
40
- ]);
41
- const computeCalloutPosition = async () => {
42
- if (reference && popupRef) {
43
- popupPosition = await computePosition(reference, popupRef, {
44
- placement: floatingUIPlacement,
45
- middleware
46
- });
47
- console.log('popupPosition', popupPosition);
48
- }
49
- else {
50
- popupPosition = { x: 0, y: 0 };
51
- }
52
- };
53
- // whenever a positioned element is portaled it needs resubscription to auto-update
54
- let cleanupAutoUpdate = () => { };
55
- const autoUpdateCalloutPosition = () => {
56
- cleanupAutoUpdate();
57
- cleanupAutoUpdate = () => { };
58
- if (reference && popupRef) {
59
- cleanupAutoUpdate = autoUpdate(reference, popupRef, computeCalloutPosition);
60
- }
61
- };
62
- $effect(() => {
63
- autoUpdateCalloutPosition();
64
- return () => {
65
- cleanupAutoUpdate();
66
- cleanupAutoUpdate = () => { };
67
- };
68
- });
69
- $effect(() => {
70
- bodyHeight;
71
- reference;
72
- computeCalloutPosition();
73
- });
74
- // ----- Arrow ----- //
75
- const getArrowPlacementStyle = (position) => {
76
- if (position?.placement && arrowRef) {
77
- switch (position.placement) {
78
- case 'top':
79
- case 'top-start':
80
- case 'top-end':
81
- return (`bottom: -${arrowRef.offsetWidth}px;` + `transform:translate(0, -50%) rotate(135deg);`);
82
- case 'right':
83
- case 'right-start':
84
- case 'right-end':
85
- return (`left: -${arrowRef.offsetWidth}px;` + `transform:translate(50%, 0) rotate(225deg);`);
86
- case 'bottom':
87
- case 'bottom-start':
88
- case 'bottom-end':
89
- return `top: -${arrowRef.offsetWidth}px;` + `transform:translate(0, 50%) rotate(-45deg);`;
90
- case 'left':
91
- case 'left-start':
92
- case 'left-end':
93
- return (`right: -${arrowRef.offsetWidth}px;` + `transform:translate(-50%, 0) rotate(45deg);`);
94
- }
95
- }
96
- return '';
97
- };
98
- const getArrowOffsetStyle = (position) => {
99
- const arrow = position?.middlewareData?.arrow;
100
- if (arrow) {
101
- if (arrow.x !== null && arrow.x !== undefined) {
102
- return `left: ${arrow.x}px;`;
103
- }
104
- else if (arrow.y !== null && arrow.y !== undefined) {
105
- return `top: ${arrow.y}px;`;
106
- }
107
- }
108
- return '';
109
- };
110
- let arrowStyle = $derived(getArrowPlacementStyle(popupPosition) + getArrowOffsetStyle(popupPosition));
111
- // ----- Animation ----- //
112
- const fadeNoOp = (node, params) => {
113
- return { delay: 0, duration: 0 };
114
- };
115
- let fadeMotion = $derived(!$prefersReducedMotion ? fade : fadeNoOp);
116
- // ----- EventHandlers ----- //
117
- const onKeydown = (event) => {
118
- if (event.key === 'Escape') {
119
- open = false;
120
- }
121
- rest.onkeydown?.(event);
122
- };
123
- $effect(() => {
124
- ensurePortalHost();
125
- resizeObserver = new ResizeObserver((entries) => {
126
- bodyHeight = entries[0].target.clientHeight;
127
- });
128
- // start observing a DOM node
129
- resizeObserver.observe(document.body);
130
- return () => {
131
- resizeObserver?.unobserve(document.body);
132
- resizeObserver?.disconnect();
133
- resizeObserver = undefined;
134
- };
135
- });
136
- ensurePortalHost();
137
- </script>
138
-
139
- {#if open || !conditionalRender}
140
- <div
141
- use:portal={{ target: portalHost }}
142
- class="sterling-callout-portal"
143
- transition:fadeMotion|global={{ duration: 250 }}
144
- >
145
- <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
146
- <div
147
- bind:this={popupRef}
148
- class={['sterling-callout', _class].filter(Boolean).join(' ')}
149
- class:open
150
- class:top={popupPosition.placement === 'top'}
151
- class:top-start={popupPosition.placement === 'top-start'}
152
- class:top-end={popupPosition.placement === 'top-end'}
153
- class:right={popupPosition.placement === 'right'}
154
- class:right-start={popupPosition.placement === 'right-start'}
155
- class:right-end={popupPosition.placement === 'right-end'}
156
- class:bottom={popupPosition.placement === 'bottom'}
157
- class:bottom-start={popupPosition.placement === 'bottom-start'}
158
- class:bottom-end={popupPosition.placement === 'bottom-end'}
159
- class:left={popupPosition.placement === 'left'}
160
- class:left-start={popupPosition.placement === 'left-start'}
161
- class:left-end={popupPosition.placement === 'left-end'}
162
- role="tooltip"
163
- {...rest}
164
- onkeydown={onKeydown}
165
- style="left:{popupPosition.x}px; top:{popupPosition.y}px"
166
- >
167
- {#if children}
168
- {#if typeof children === 'string'}
169
- <div class="callout-text">{children}</div>
170
- {:else}
171
- {@render children()}
172
- {/if}
173
- {/if}
174
- <div class="arrow" bind:this={arrowRef} style={arrowStyle}></div>
175
- </div>
176
- </div>
177
- {/if}
@@ -1,15 +0,0 @@
1
- /// <reference types="svelte" />
2
- import type { PopoverPlacement } from './Popover.types';
3
- import type { HTMLAttributes } from 'svelte/elements';
4
- type Props = HTMLAttributes<HTMLDivElement> & {
5
- conditionalRender?: boolean | null;
6
- crossAxisOffset?: number;
7
- mainAxisOffset?: number;
8
- open?: boolean | null;
9
- placement?: PopoverPlacement;
10
- portalHost?: HTMLElement;
11
- reference?: HTMLElement | null;
12
- };
13
- declare const Callout: import("svelte").Component<Props, {}, "conditionalRender" | "crossAxisOffset" | "mainAxisOffset" | "open" | "placement">;
14
- type Callout = ReturnType<typeof Callout>;
15
- export default Callout;
@@ -1,11 +0,0 @@
1
- import type { HTMLAttributes } from 'svelte/elements';
2
- import type { PopoverPlacement } from './Popover.types';
3
- export type CalloutProps = HTMLAttributes<HTMLDivElement> & {
4
- conditionalRender?: boolean | null;
5
- crossAxisOffset?: number;
6
- mainAxisOffset?: number;
7
- open?: boolean | null;
8
- placement?: PopoverPlacement;
9
- portalHost?: HTMLElement;
10
- reference?: HTMLElement | null;
11
- };
package/Callout.types.js DELETED
@@ -1 +0,0 @@
1
- export {};
package/Checkbox.svelte DELETED
@@ -1,43 +0,0 @@
1
- <svelte:options runes={true} />
2
-
3
- <script lang="ts">import { idGenerator } from './idGenerator';
4
- import { usingKeyboard } from './mediaQueries/usingKeyboard';
5
- let { id, children, checked = $bindable(false), class: _class, disabled = $bindable(false), ...rest } = $props();
6
- let inputRef;
7
- $effect(() => {
8
- if (children && id === undefined) {
9
- id = idGenerator.nextId('Checkbox');
10
- }
11
- });
12
- // ----- Methods ----- //
13
- export const blur = () => {
14
- inputRef?.blur();
15
- };
16
- export const click = () => {
17
- inputRef?.click();
18
- };
19
- export const focus = (options) => {
20
- inputRef?.focus(options);
21
- };
22
- </script>
23
-
24
- <!--
25
- @component
26
- A styled HTML input type=checkbox element.
27
- -->
28
- <div
29
- class={['sterling-checkbox', _class].filter(Boolean).join(' ')}
30
- class:checked
31
- class:disabled
32
- class:using-keyboard={$usingKeyboard}
33
- >
34
- <div class="container">
35
- <input bind:this={inputRef} bind:checked {disabled} {id} type="checkbox" {...rest} />
36
- <div class="indicator"></div>
37
- </div>
38
- {#if children}
39
- <label for={id}>
40
- {@render children()}
41
- </label>
42
- {/if}
43
- </div>
@@ -1,10 +0,0 @@
1
- /// <reference types="svelte" />
2
- import type { HTMLInputAttributes } from 'svelte/elements';
3
- /** A styled HTML input type=checkbox element. */
4
- declare const Checkbox: import("svelte").Component<HTMLInputAttributes, {
5
- blur: () => void;
6
- click: () => void;
7
- focus: (options?: FocusOptions) => void;
8
- }, "disabled" | "checked">;
9
- type Checkbox = ReturnType<typeof Checkbox>;
10
- export default Checkbox;
package/Dialog.svelte DELETED
@@ -1,151 +0,0 @@
1
- <svelte:options runes={true} />
2
-
3
- <script lang="ts">import { onMount, setContext, tick } from 'svelte';
4
- import Button from './Button.svelte';
5
- import { STERLING_PORTAL_CONTEXT_ID } from './Portal.constants';
6
- import { writable } from 'svelte/store';
7
- const dialogFadeDuration = 250;
8
- let { backdropCloses = false, open = $bindable(false), body, class: _class, content, footer, header, returnValue = $bindable(''), headerTitle, ...rest } = $props();
9
- let dialogRef;
10
- let contentRef;
11
- let formRef;
12
- // svelte-ignore non_reactive_update
13
- let closing = false;
14
- const portalHostStore = writable(undefined);
15
- // ----- Context ----- //
16
- setContext(STERLING_PORTAL_CONTEXT_ID, { portalHost: portalHostStore });
17
- // ----- Event Handlers ----- //
18
- const onDocumentClick = (event) => {
19
- // as tracking clicks outside the dialog is only active while the dialog is open
20
- // the clickOutside action is not used and reimplemented here.
21
- const targetNode = event?.target;
22
- // the content must be used as the container because dialog::backdrop is considered
23
- // part of the HTMLDialogElement
24
- if (targetNode && !contentRef?.contains(targetNode) && backdropCloses) {
25
- open = false;
26
- }
27
- };
28
- const showDialog = () => {
29
- if (dialogRef?.open === false) {
30
- // when open, track clicks outside the dialog (use capture = true)
31
- document.addEventListener('click', onDocumentClick, true);
32
- returnValue = '';
33
- dialogRef.showModal();
34
- }
35
- open = true;
36
- };
37
- const closeDialog = async () => {
38
- if (dialogRef?.open === true) {
39
- // when closed, stop tracking clicks outside the dialog
40
- document.removeEventListener('click', onDocumentClick);
41
- // to allow time for the CSS transition animation, closing the dialog is delayed
42
- closing = true;
43
- await tick();
44
- setTimeout(() => {
45
- dialogRef.close(returnValue);
46
- open = false;
47
- closing = false;
48
- }, dialogFadeDuration);
49
- }
50
- else {
51
- open = false;
52
- }
53
- };
54
- const updateDialog = (open) => {
55
- if (open) {
56
- showDialog();
57
- }
58
- else {
59
- closeDialog();
60
- }
61
- };
62
- const onCancel = (event) => {
63
- // Cancelling a dialog instantly hides the dialog.
64
- // To allow animation with closeDialog, this event is canceled.
65
- event.preventDefault();
66
- event.stopPropagation();
67
- returnValue = '';
68
- closeDialog();
69
- return false;
70
- };
71
- const onSubmit = (event) => {
72
- // Submitting a form instantly hides the dialog.
73
- // The dialog.close event is not cancellable, but form.submit is.
74
- // To allow animation with closeDialog, this event is canceled.
75
- // The form is resubmitted after the dialog closes to ensure the form is in the correct state.
76
- const anyEvent = event;
77
- if (anyEvent?.submitter.type === 'submit') {
78
- if (dialogRef.open) {
79
- const eventSubmitter = anyEvent?.submitter;
80
- returnValue = eventSubmitter?.value ?? '';
81
- closeDialog();
82
- setTimeout(() => {
83
- formRef.requestSubmit(eventSubmitter);
84
- }, dialogFadeDuration);
85
- event.preventDefault();
86
- return false;
87
- }
88
- }
89
- else {
90
- event.preventDefault();
91
- return false;
92
- }
93
- };
94
- $effect(() => {
95
- updateDialog(open);
96
- });
97
- onMount(() => {
98
- updateDialog(open);
99
- // Use the dialog for any element portals
100
- portalHostStore.set(dialogRef);
101
- dialogRef.addEventListener('cancel', onCancel);
102
- return () => {
103
- dialogRef?.removeEventListener('cancel', onCancel);
104
- portalHostStore.set(undefined);
105
- };
106
- });
107
- </script>
108
-
109
- <dialog
110
- bind:this={dialogRef}
111
- class={`sterling-dialog ${_class}`}
112
- class:open
113
- class:closing
114
- {...rest}
115
- >
116
- <form method="dialog" bind:this={formRef} onsubmit={onSubmit}>
117
- <div class="content" bind:this={contentRef}>
118
- {#if content}
119
- {@render content()}
120
- {:else}
121
- <div class="header">
122
- {#if header}
123
- {@render header()}
124
- {:else}
125
- <div class="title">
126
- {#if headerTitle}
127
- {#if typeof headerTitle === 'string'}
128
- {headerTitle}
129
- {:else}
130
- {@render headerTitle()}
131
- {/if}
132
- {/if}
133
- </div>
134
- <div class="close">
135
- <Button class={`circular tool`} onclick={() => closeDialog()}>
136
- <div class="close-x"></div>
137
- </Button>
138
- </div>
139
- {/if}
140
- </div>
141
- <div class="body">
142
- {@render body?.()}
143
- </div>
144
- <div class="separator"></div>
145
- <div class="footer">
146
- {@render footer?.()}
147
- </div>
148
- {/if}
149
- </div>
150
- </form>
151
- </dialog>
@@ -1,14 +0,0 @@
1
- import type { HTMLDialogAttributes } from 'svelte/elements';
2
- import { type Snippet } from 'svelte';
3
- type Props = HTMLDialogAttributes & {
4
- backdropCloses?: boolean | null | undefined;
5
- body?: Snippet;
6
- content?: Snippet;
7
- footer?: Snippet;
8
- header?: Snippet;
9
- returnValue?: string;
10
- headerTitle?: string | Snippet;
11
- };
12
- declare const Dialog: import("svelte").Component<Props, {}, "open" | "returnValue">;
13
- type Dialog = ReturnType<typeof Dialog>;
14
- export default Dialog;
package/Dropdown.svelte DELETED
@@ -1,109 +0,0 @@
1
- <svelte:options runes={true} />
2
-
3
- <script lang="ts">import {} from 'svelte';
4
- import Popover from './Popover.svelte';
5
- import { clickOutside } from './actions/clickOutside';
6
- import { idGenerator } from './idGenerator';
7
- import { prefersReducedMotion } from './mediaQueries/prefersReducedMotion';
8
- import { slide } from 'svelte/transition';
9
- import { usingKeyboard } from './mediaQueries/usingKeyboard';
10
- const popupId = idGenerator.nextId('Dropdown-popup');
11
- let { class: _class, children, disabled = false, open = $bindable(false), onOpen, stayOpenOnClickAway = false, button, buttonIcon, value, ...rest } = $props();
12
- // svelte-ignore non_reactive_update
13
- let dropdownRef = $state(undefined);
14
- // svelte-ignore non_reactive_update
15
- let popupContentRef = $state(undefined);
16
- // ----- Reactions ----- //
17
- $effect(() => {
18
- onOpen?.(open);
19
- });
20
- // ----- Methods ----- //
21
- export const click = () => {
22
- dropdownRef?.click();
23
- };
24
- export const blur = () => {
25
- dropdownRef?.blur();
26
- };
27
- export const focus = (options) => {
28
- dropdownRef?.focus(options);
29
- };
30
- const onClick = (event) => {
31
- if (!disabled) {
32
- open = !open;
33
- event.preventDefault();
34
- event.stopPropagation();
35
- }
36
- rest.onclick?.(event);
37
- };
38
- const onKeydown = (event) => {
39
- if (!event.altKey && !event.ctrlKey && !event.shiftKey) {
40
- switch (event.key) {
41
- case ' ':
42
- open = !open;
43
- event.preventDefault();
44
- event.stopPropagation();
45
- case 'Escape':
46
- open = false;
47
- event.preventDefault();
48
- event.stopPropagation();
49
- }
50
- }
51
- rest.onkeydown?.(event);
52
- };
53
- const onClickOutside = (event) => {
54
- if (!stayOpenOnClickAway) {
55
- open = false;
56
- }
57
- };
58
- // ----- Animation ----- //
59
- const slideNoOp = (node, params) => {
60
- return { delay: 0, duration: 0 };
61
- };
62
- let slideMotion = $derived(!$prefersReducedMotion ? slide : slideNoOp);
63
- </script>
64
-
65
- <div
66
- bind:this={dropdownRef}
67
- aria-controls={popupId}
68
- aria-haspopup={true}
69
- aria-expanded={open}
70
- class={`sterling-dropdown ${_class}`}
71
- class:disabled
72
- class:open
73
- class:using-keyboard={$usingKeyboard}
74
- role="combobox"
75
- tabindex="0"
76
- use:clickOutside={{ ignoreOthers: [popupContentRef!], onclickoutside: onClickOutside }}
77
- {...rest}
78
- onclick={onClick}
79
- onkeydown={onKeydown}
80
- >
81
- <div class="value">
82
- {#if value}
83
- {#if typeof value === 'string'}
84
- {value}
85
- {:else}
86
- {@render value()}
87
- {/if}
88
- {/if}
89
- </div>
90
- <div class="button">
91
- {#if button}
92
- {@render button()}
93
- {:else if buttonIcon}
94
- {@render buttonIcon()}
95
- {:else}
96
- <div class="chevron"></div>
97
- {/if}
98
- </div>
99
-
100
- <Popover reference={dropdownRef} open={!disabled && open} placement="bottom-start">
101
- <div
102
- class={`sterling-dropdown-popup-content ${_class}`}
103
- transition:slideMotion|global={{ duration: 200 }}
104
- bind:this={popupContentRef}
105
- >
106
- {@render children?.()}
107
- </div>
108
- </Popover>
109
- </div>