@geoffcox/sterling-svelte 2.0.2 → 2.0.3

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 (131) hide show
  1. package/README.md +18 -0
  2. package/dist/@types/clickOutside.d.ts +15 -0
  3. package/dist/Button.svelte +29 -0
  4. package/dist/Button.svelte.d.ts +8 -0
  5. package/dist/Callout.svelte +243 -0
  6. package/dist/Callout.svelte.d.ts +14 -0
  7. package/dist/Callout.types.d.ts +11 -0
  8. package/dist/Callout.types.js +1 -0
  9. package/dist/Checkbox.svelte +62 -0
  10. package/dist/Checkbox.svelte.d.ts +9 -0
  11. package/dist/Dialog.svelte +201 -0
  12. package/dist/Dialog.svelte.d.ts +14 -0
  13. package/dist/Dropdown.svelte +159 -0
  14. package/dist/Dropdown.svelte.d.ts +23 -0
  15. package/dist/Input.svelte +80 -0
  16. package/dist/Input.svelte.d.ts +11 -0
  17. package/dist/Label.constants.d.ts +2 -0
  18. package/dist/Label.constants.js +2 -0
  19. package/dist/Label.svelte +135 -0
  20. package/dist/Label.svelte.d.ts +17 -0
  21. package/dist/Link.svelte +31 -0
  22. package/dist/Link.svelte.d.ts +11 -0
  23. package/dist/List.constants.d.ts +1 -0
  24. package/dist/List.constants.js +1 -0
  25. package/dist/List.svelte +258 -0
  26. package/dist/List.svelte.d.ts +19 -0
  27. package/dist/List.types.d.ts +5 -0
  28. package/dist/List.types.js +1 -0
  29. package/dist/ListItem.svelte +64 -0
  30. package/dist/ListItem.svelte.d.ts +12 -0
  31. package/dist/Menu.svelte +105 -0
  32. package/dist/Menu.svelte.d.ts +12 -0
  33. package/dist/MenuBar.constants.d.ts +1 -0
  34. package/dist/MenuBar.constants.js +1 -0
  35. package/dist/MenuBar.svelte +144 -0
  36. package/dist/MenuBar.svelte.d.ts +12 -0
  37. package/dist/MenuBar.types.d.ts +4 -0
  38. package/dist/MenuBar.types.js +1 -0
  39. package/dist/MenuButton.svelte +156 -0
  40. package/dist/MenuButton.svelte.d.ts +20 -0
  41. package/dist/MenuItem.constants.d.ts +2 -0
  42. package/dist/MenuItem.constants.js +2 -0
  43. package/dist/MenuItem.svelte +431 -0
  44. package/dist/MenuItem.svelte.d.ts +22 -0
  45. package/dist/MenuItem.types.d.ts +20 -0
  46. package/dist/MenuItem.types.js +1 -0
  47. package/dist/MenuItem.utils.d.ts +7 -0
  48. package/dist/MenuItem.utils.js +36 -0
  49. package/dist/MenuSeparator.svelte +11 -0
  50. package/dist/MenuSeparator.svelte.d.ts +5 -0
  51. package/dist/Pagination.svelte +267 -0
  52. package/dist/Pagination.svelte.d.ts +4 -0
  53. package/dist/Pagination.types.d.ts +24 -0
  54. package/dist/Pagination.types.js +1 -0
  55. package/dist/Popover.constants.d.ts +1 -0
  56. package/dist/Popover.constants.js +14 -0
  57. package/dist/Popover.svelte +175 -0
  58. package/dist/Popover.svelte.d.ts +14 -0
  59. package/dist/Popover.types.d.ts +4 -0
  60. package/dist/Popover.types.js +1 -0
  61. package/dist/Portal.constants.d.ts +2 -0
  62. package/dist/Portal.constants.js +2 -0
  63. package/dist/Portal.types.d.ts +3 -0
  64. package/dist/Portal.types.js +1 -0
  65. package/dist/Progress.constants.d.ts +1 -0
  66. package/dist/Progress.constants.js +1 -0
  67. package/dist/Progress.svelte +61 -0
  68. package/dist/Progress.svelte.d.ts +11 -0
  69. package/dist/Progress.types.d.ts +4 -0
  70. package/dist/Progress.types.js +1 -0
  71. package/dist/Radio.svelte +65 -0
  72. package/dist/Radio.svelte.d.ts +12 -0
  73. package/dist/Select.svelte +262 -0
  74. package/dist/Select.svelte.d.ts +26 -0
  75. package/dist/Slider.svelte +182 -0
  76. package/dist/Slider.svelte.d.ts +18 -0
  77. package/dist/Switch.svelte +92 -0
  78. package/dist/Switch.svelte.d.ts +21 -0
  79. package/dist/Tab.svelte +66 -0
  80. package/dist/Tab.svelte.d.ts +11 -0
  81. package/dist/TabList.constants.d.ts +1 -0
  82. package/dist/TabList.constants.js +1 -0
  83. package/dist/TabList.svelte +253 -0
  84. package/dist/TabList.svelte.d.ts +17 -0
  85. package/dist/TabList.types.d.ts +5 -0
  86. package/dist/TabList.types.js +1 -0
  87. package/dist/TextArea.constants.d.ts +1 -0
  88. package/dist/TextArea.constants.js +1 -0
  89. package/dist/TextArea.svelte +116 -0
  90. package/dist/TextArea.svelte.d.ts +18 -0
  91. package/dist/TextArea.types.d.ts +4 -0
  92. package/dist/TextArea.types.js +1 -0
  93. package/dist/Tooltip.svelte +95 -0
  94. package/dist/Tooltip.svelte.d.ts +10 -0
  95. package/dist/Tree.constants.d.ts +1 -0
  96. package/dist/Tree.constants.js +1 -0
  97. package/dist/Tree.svelte +81 -0
  98. package/dist/Tree.svelte.d.ts +14 -0
  99. package/dist/Tree.types.d.ts +5 -0
  100. package/dist/Tree.types.js +1 -0
  101. package/dist/TreeChevron.svelte +39 -0
  102. package/dist/TreeChevron.svelte.d.ts +8 -0
  103. package/dist/TreeItem.constants.d.ts +1 -0
  104. package/dist/TreeItem.constants.js +1 -0
  105. package/dist/TreeItem.svelte +396 -0
  106. package/dist/TreeItem.svelte.d.ts +22 -0
  107. package/dist/TreeItem.types.d.ts +4 -0
  108. package/dist/TreeItem.types.js +1 -0
  109. package/dist/actions/applyLightDarkMode.d.ts +10 -0
  110. package/dist/actions/applyLightDarkMode.js +36 -0
  111. package/dist/actions/clickOutside.d.ts +15 -0
  112. package/dist/actions/clickOutside.js +28 -0
  113. package/dist/actions/extraClass.d.ts +9 -0
  114. package/dist/actions/extraClass.js +15 -0
  115. package/dist/actions/forwardEvents.d.ts +12 -0
  116. package/dist/actions/forwardEvents.js +32 -0
  117. package/dist/actions/portal.d.ts +8 -0
  118. package/dist/actions/portal.js +19 -0
  119. package/dist/actions/trapKeyboardFocus.d.ts +3 -0
  120. package/dist/actions/trapKeyboardFocus.js +52 -0
  121. package/dist/idGenerator.d.ts +5 -0
  122. package/dist/idGenerator.js +11 -0
  123. package/dist/index.d.ts +60 -0
  124. package/dist/index.js +55 -0
  125. package/dist/mediaQueries/prefersColorSchemeDark.d.ts +1 -0
  126. package/dist/mediaQueries/prefersColorSchemeDark.js +14 -0
  127. package/dist/mediaQueries/prefersReducedMotion.d.ts +1 -0
  128. package/dist/mediaQueries/prefersReducedMotion.js +14 -0
  129. package/dist/mediaQueries/usingKeyboard.d.ts +1 -0
  130. package/dist/mediaQueries/usingKeyboard.js +17 -0
  131. package/package.json +8 -7
@@ -0,0 +1,11 @@
1
+ <svelte:options runes={true} />
2
+
3
+ <script lang="ts">
4
+ import type { HTMLAttributes } from 'svelte/elements';
5
+
6
+ type Props = HTMLAttributes<HTMLDivElement>;
7
+
8
+ let { class: _class, ...rest }: Props = $props();
9
+ </script>
10
+
11
+ <div class={['sterling-menu-separator', _class]} role="separator" {...rest}></div>
@@ -0,0 +1,5 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ type Props = HTMLAttributes<HTMLDivElement>;
3
+ declare const MenuSeparator: import("svelte").Component<Props, {}, "">;
4
+ type MenuSeparator = ReturnType<typeof MenuSeparator>;
5
+ export default MenuSeparator;
@@ -0,0 +1,267 @@
1
+ <script lang="ts">
2
+ import type { ChangeEventHandler } from 'svelte/elements';
3
+ import type { PaginationProps } from './Pagination.types';
4
+
5
+ let {
6
+ class: _class,
7
+ itemCount,
8
+ itemRange = $bindable(), //readonly
9
+ page = $bindable(),
10
+ pageCount = $bindable(), //readonly
11
+ pageSize = 1,
12
+ pageStep = 10,
13
+ onChange,
14
+ firstNumber,
15
+ stepPreviousNumber,
16
+ previousNumber,
17
+ currentNumber,
18
+ nextNumber,
19
+ stepNextNumber,
20
+ lastNumber
21
+ }: PaginationProps = $props();
22
+
23
+ let _pageCount = $derived(
24
+ itemCount > 0 && pageSize > 0 ? Math.ceil(itemCount / pageSize) : undefined
25
+ );
26
+
27
+ // 1 time update of pageCount when loaded because effect runs too late
28
+ // svelte-ignore state_referenced_locally
29
+ pageCount = _pageCount;
30
+
31
+ // readonly props cannot be assigned $derived values
32
+ $effect(() => {
33
+ pageCount = _pageCount;
34
+ });
35
+
36
+ // clamp the page internally
37
+ let _page = $derived(_pageCount && page ? Math.max(1, Math.min(page, _pageCount)) : undefined);
38
+
39
+ let _itemRange = $derived(
40
+ _pageCount && _page
41
+ ? {
42
+ index: _page ? Math.max(0, (_page - 1) * pageSize) : 0,
43
+ count: _page ? Math.max(0, Math.min(pageSize, itemCount - (_page - 1) * pageSize)) : 0
44
+ }
45
+ : undefined
46
+ );
47
+
48
+ // 1 time update of itemRange when loaded because effect runs too late
49
+ // svelte-ignore state_referenced_locally
50
+ itemRange = _itemRange;
51
+
52
+ // readonly props cannot be assigned $derived values yet
53
+ $effect(() => {
54
+ itemRange = _itemRange;
55
+ });
56
+
57
+ $effect(() => {
58
+ onChange?.(_page, _itemRange);
59
+ });
60
+
61
+ let firstValue = $derived(_pageCount && _page && _page >= 3 ? 1 : undefined);
62
+ let stepPreviousValue = $derived(_pageCount && _page ? Math.max(1, _page - pageStep) : undefined);
63
+ let previousValue = $derived(_pageCount && _page && _page >= 2 ? _page - 1 : undefined);
64
+ // _page acts as the currentValue;
65
+ let nextValue = $derived(_pageCount && _page && _page <= _pageCount - 1 ? _page + 1 : undefined);
66
+ let stepNextValue = $derived(
67
+ _pageCount && _page ? Math.min(_pageCount, _page + pageStep) : undefined
68
+ );
69
+ let lastValue = $derived(_pageCount && _page && _page <= _pageCount - 2 ? _pageCount : undefined);
70
+
71
+ let numberOfDigits = $derived(_pageCount ? _pageCount.toString().length : 1);
72
+
73
+ // clamp page when the value changes
74
+ const setPage = (newPage?: number) => {
75
+ page = _pageCount && newPage ? Math.max(1, Math.min(newPage, _pageCount)) : undefined;
76
+ };
77
+
78
+ const onFirst = () => {
79
+ setPage(1);
80
+ };
81
+
82
+ const onStepPrevious = () => {
83
+ _page && setPage(_page - Math.abs(pageStep));
84
+ };
85
+
86
+ const onPrevious = () => {
87
+ _page && setPage(_page - 1);
88
+ };
89
+
90
+ const onNext = () => {
91
+ _page && setPage(_page + 1);
92
+ };
93
+
94
+ const onStepNext = () => {
95
+ _page && setPage(_page + Math.abs(pageStep));
96
+ };
97
+
98
+ const onLast = () => {
99
+ _pageCount && setPage(_pageCount);
100
+ };
101
+
102
+ const onInputChange: ChangeEventHandler<HTMLInputElement> = (event) => {
103
+ const inputValue = event.currentTarget.value;
104
+ if (inputValue.length > 0) {
105
+ const value = parseInt(inputValue, 10);
106
+ value && setPage(value);
107
+ }
108
+ };
109
+
110
+ let holdTimeout: NodeJS.Timeout | undefined = undefined;
111
+ let holdInterval: NodeJS.Timeout | undefined = undefined;
112
+
113
+ const startHoldButton = (
114
+ event: MouseEvent,
115
+ action: () => void,
116
+ delayMs: number = 500,
117
+ repeatMs: number = 100
118
+ ) => {
119
+ clearInterval(holdTimeout);
120
+ clearInterval(holdInterval);
121
+ if (event.button !== 0) {
122
+ return;
123
+ }
124
+ action();
125
+ holdTimeout = setTimeout(() => {
126
+ holdInterval = setInterval(action, repeatMs);
127
+ }, delayMs);
128
+ };
129
+
130
+ const stopHoldButton = (event: MouseEvent) => {
131
+ clearInterval(holdTimeout);
132
+ clearInterval(holdInterval);
133
+ };
134
+
135
+ const onKeydown = (event: KeyboardEvent, action: () => void) => {
136
+ if (event.key === ' ') {
137
+ event.preventDefault();
138
+ event.stopPropagation();
139
+ action();
140
+ return false;
141
+ }
142
+ };
143
+ </script>
144
+
145
+ <div class="sterling-pagination" style={`--page-number-width: ${numberOfDigits}ch`}>
146
+ <div class="page-number first">
147
+ <button
148
+ disabled={firstValue === undefined}
149
+ type="button"
150
+ onclick={onFirst}
151
+ onkeydown={(event) => onKeydown(event, onFirst)}
152
+ data-value={firstValue}
153
+ >
154
+ {#if firstNumber}
155
+ {@render firstNumber(firstValue)}
156
+ {:else if firstValue}
157
+ {firstValue}
158
+ {:else}
159
+ -
160
+ {/if}</button
161
+ >
162
+ </div>
163
+ <div class="page-number step-previous">
164
+ <button
165
+ disabled={stepPreviousValue === undefined}
166
+ type="button"
167
+ onmousedown={(event) => startHoldButton(event, onStepPrevious)}
168
+ onmouseup={stopHoldButton}
169
+ onmouseleave={stopHoldButton}
170
+ onkeydown={(event) => onKeydown(event, onStepPrevious)}
171
+ data-value={stepPreviousValue}
172
+ >
173
+ {#if stepPreviousNumber}
174
+ {@render stepPreviousNumber(stepPreviousValue)}
175
+ {:else if stepPreviousValue}
176
+ &lt;&lt;
177
+ {:else}
178
+ -
179
+ {/if}
180
+ </button>
181
+ </div>
182
+ <div class="page-number previous">
183
+ <button
184
+ disabled={previousValue === undefined}
185
+ type="button"
186
+ onmousedown={(event) => startHoldButton(event, onPrevious)}
187
+ onmouseup={stopHoldButton}
188
+ onmouseleave={stopHoldButton}
189
+ onkeydown={(event) => onKeydown(event, onPrevious)}
190
+ data-value={previousValue}
191
+ >
192
+ {#if previousNumber}
193
+ {@render previousNumber(previousValue)}
194
+ {:else if previousValue}
195
+ {previousValue}
196
+ {:else}
197
+ -
198
+ {/if}
199
+ </button>
200
+ </div>
201
+ <div class="page-number current">
202
+ {#if _page}
203
+ {#if currentNumber}
204
+ {@render currentNumber(_page)}
205
+ {:else}
206
+ <input disabled={_page === undefined} value={_page} onchange={onInputChange} />
207
+ {/if}
208
+ {:else}
209
+ -
210
+ {/if}
211
+ </div>
212
+ <div class="page-number next">
213
+ <button
214
+ disabled={nextValue === undefined}
215
+ type="button"
216
+ onmousedown={(event) => startHoldButton(event, onNext)}
217
+ onmouseup={stopHoldButton}
218
+ onmouseleave={stopHoldButton}
219
+ onkeydown={(event) => onKeydown(event, onNext)}
220
+ data-value={nextValue}
221
+ >
222
+ {#if nextNumber}
223
+ {@render nextNumber(nextValue)}
224
+ {:else if nextValue}
225
+ {nextValue}
226
+ {:else}
227
+ -
228
+ {/if}
229
+ </button>
230
+ </div>
231
+ <div class="page-number step-next">
232
+ <button
233
+ disabled={stepNextValue === undefined}
234
+ type="button"
235
+ onmousedown={(event) => startHoldButton(event, onStepNext)}
236
+ onmouseup={stopHoldButton}
237
+ onmouseleave={stopHoldButton}
238
+ onkeydown={(event) => onKeydown(event, onStepNext)}
239
+ data-value={stepNextValue}
240
+ >
241
+ {#if stepNextNumber}
242
+ {@render stepNextNumber(stepNextValue)}
243
+ {:else if stepNextValue}
244
+ &gt;&gt;
245
+ {:else}
246
+ -
247
+ {/if}
248
+ </button>
249
+ </div>
250
+ <div class="page-number last">
251
+ <button
252
+ disabled={lastValue === undefined}
253
+ type="button"
254
+ onclick={() => onLast()}
255
+ onkeydown={(event) => onKeydown(event, onLast)}
256
+ data-value={lastValue}
257
+ >
258
+ {#if lastNumber}
259
+ {@render lastNumber(lastValue)}
260
+ {:else if lastValue}
261
+ {lastValue}
262
+ {:else}
263
+ -
264
+ {/if}
265
+ </button>
266
+ </div>
267
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { PaginationProps } from './Pagination.types';
2
+ declare const Pagination: import("svelte").Component<PaginationProps, {}, "page" | "itemRange" | "pageCount">;
3
+ type Pagination = ReturnType<typeof Pagination>;
4
+ export default Pagination;
@@ -0,0 +1,24 @@
1
+ import { type Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ export type PaginationProps = HTMLAttributes<HTMLDivElement> & {
4
+ itemCount: number;
5
+ itemRange?: {
6
+ index: number;
7
+ count: number;
8
+ };
9
+ page?: number;
10
+ pageCount?: number;
11
+ pageSize?: number;
12
+ pageStep?: number;
13
+ onChange?: (page?: number, itemRange?: {
14
+ index: number;
15
+ count: number;
16
+ }) => void;
17
+ firstNumber?: Snippet<[number | undefined]>;
18
+ stepPreviousNumber?: Snippet<[number | undefined]>;
19
+ previousNumber?: Snippet<[number | undefined]>;
20
+ currentNumber?: Snippet<[number | undefined]>;
21
+ nextNumber?: Snippet<[number | undefined]>;
22
+ stepNextNumber?: Snippet<[number | undefined]>;
23
+ lastNumber?: Snippet<[number | undefined]>;
24
+ };
@@ -0,0 +1 @@
1
+ import {} from 'svelte';
@@ -0,0 +1 @@
1
+ export declare const POPOVER_PLACEMENTS: string[];
@@ -0,0 +1,14 @@
1
+ export const POPOVER_PLACEMENTS = [
2
+ 'top-start',
3
+ 'top',
4
+ 'top-end',
5
+ 'right-start',
6
+ 'right',
7
+ 'right-end',
8
+ 'bottom-end',
9
+ 'bottom',
10
+ 'bottom-start',
11
+ 'left-end',
12
+ 'left',
13
+ 'left-start'
14
+ ];
@@ -0,0 +1,175 @@
1
+ <svelte:options runes={true} />
2
+
3
+ <script lang="ts">
4
+ import {
5
+ autoUpdate,
6
+ computePosition,
7
+ flip,
8
+ offset,
9
+ type ComputePositionReturn,
10
+ type Placement
11
+ } from '@floating-ui/dom';
12
+ import { getContext, tick } from 'svelte';
13
+ import type { HTMLAttributes, KeyboardEventHandler } from 'svelte/elements';
14
+ import { portal } from './actions/portal';
15
+ import type { PopoverPlacement } from './Popover.types';
16
+ import { STERLING_PORTAL_CONTEXT_ID, STERLING_PORTAL_HOST_ID } from './Portal.constants';
17
+ import type { PortalContext } from './Portal.types';
18
+
19
+ // ----- Props ----- //
20
+
21
+ type Props = HTMLAttributes<HTMLDivElement> & {
22
+ conditionalRender?: boolean;
23
+ crossAxisOffset?: number;
24
+ mainAxisOffset?: number;
25
+ open?: boolean | null;
26
+ placement?: PopoverPlacement;
27
+ portalHost?: HTMLElement;
28
+ reference?: HTMLElement;
29
+ };
30
+
31
+ let {
32
+ children,
33
+ conditionalRender = $bindable(true),
34
+ crossAxisOffset = $bindable(0),
35
+ mainAxisOffset = $bindable(0),
36
+ open = $bindable(false),
37
+ placement = $bindable('top-start'),
38
+ portalHost,
39
+ reference,
40
+ class: _class,
41
+ ...rest
42
+ }: Props = $props();
43
+
44
+ let popupRef: HTMLDivElement | undefined = $state(undefined);
45
+ let popupPosition: Partial<ComputePositionReturn> = $state({ x: 0, y: 0 });
46
+ let floatingUIPlacement = $derived(placement as Placement);
47
+ let bodyHeight = $state(0);
48
+ let resizeObserver: ResizeObserver | undefined = undefined;
49
+
50
+ const portalContext = getContext<PortalContext>(STERLING_PORTAL_CONTEXT_ID) || {
51
+ portalHost: undefined
52
+ };
53
+
54
+ // ----- Portal Host ----- //
55
+
56
+ const ensurePortalHost = async () => {
57
+ await tick();
58
+
59
+ // use the host set from context, usually set from a Dialog
60
+ let host = portalContext.portalHost;
61
+
62
+ // use or create the sterling portal host
63
+ if (!host && globalThis?.document) {
64
+ host = globalThis.document.querySelector(`#${STERLING_PORTAL_HOST_ID}`) as HTMLElement;
65
+
66
+ // fallback to creating the sterling portal host
67
+ if (!host) {
68
+ host = globalThis.document.createElement('div');
69
+ host.id = STERLING_PORTAL_HOST_ID;
70
+ host.style.overflow = 'visible';
71
+ globalThis.document.body.append(host);
72
+ }
73
+ }
74
+
75
+ portalHost = host;
76
+ };
77
+
78
+ // ----- Position ----- //
79
+
80
+ let middleware = $derived([
81
+ offset({ mainAxis: mainAxisOffset, crossAxis: crossAxisOffset }),
82
+ flip()
83
+ ]);
84
+
85
+ const computePopoverPosition = async () => {
86
+ if (reference && popupRef) {
87
+ popupPosition = await computePosition(reference, popupRef, {
88
+ placement: floatingUIPlacement,
89
+ middleware
90
+ });
91
+ } else {
92
+ popupPosition = { x: 0, y: 0 };
93
+ }
94
+ };
95
+
96
+ // whenever a positioned element is portaled it needs resubscription to auto-update
97
+ let cleanupAutoUpdate = () => {};
98
+ const autoUpdatePopoverPosition = () => {
99
+ cleanupAutoUpdate();
100
+ if (reference && popupRef) {
101
+ cleanupAutoUpdate = autoUpdate(reference, popupRef, computePopoverPosition);
102
+ }
103
+ };
104
+
105
+ $effect(() => {
106
+ autoUpdatePopoverPosition();
107
+ return () => {
108
+ cleanupAutoUpdate();
109
+ cleanupAutoUpdate = () => {};
110
+ };
111
+ });
112
+
113
+ $effect(() => {
114
+ bodyHeight;
115
+ computePopoverPosition();
116
+ });
117
+
118
+ // ----- EventHandlers ----- //
119
+ $effect(() => {
120
+ ensurePortalHost();
121
+
122
+ resizeObserver = new ResizeObserver((entries) => {
123
+ bodyHeight = entries[0].target.clientHeight;
124
+ });
125
+
126
+ // start observing a DOM node
127
+ resizeObserver.observe(document.body);
128
+
129
+ return () => {
130
+ resizeObserver?.unobserve(document.body);
131
+ resizeObserver?.disconnect();
132
+ resizeObserver = undefined;
133
+ };
134
+ });
135
+
136
+ const onKeydown: KeyboardEventHandler<HTMLDivElement> = (event) => {
137
+ if (event.key === 'Escape') {
138
+ open = false;
139
+ }
140
+ rest.onkeydown?.(event);
141
+ };
142
+
143
+ //TODO: Is this necessary?
144
+ ensurePortalHost();
145
+ </script>
146
+
147
+ {#if open || !conditionalRender}
148
+ <div use:portal={{ target: portalHost }} class="sterling-popover-portal">
149
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
150
+ <div
151
+ bind:this={popupRef}
152
+ class={['sterling-popover', _class]}
153
+ class:open
154
+ class:top={popupPosition.placement === 'top'}
155
+ class:top-start={popupPosition.placement === 'top-start'}
156
+ class:top-end={popupPosition.placement === 'top-end'}
157
+ class:right={popupPosition.placement === 'right'}
158
+ class:right-start={popupPosition.placement === 'right-start'}
159
+ class:right-end={popupPosition.placement === 'right-end'}
160
+ class:bottom={popupPosition.placement === 'bottom'}
161
+ class:bottom-start={popupPosition.placement === 'bottom-start'}
162
+ class:bottom-end={popupPosition.placement === 'bottom-end'}
163
+ class:left={popupPosition.placement === 'left'}
164
+ class:left-start={popupPosition.placement === 'left-start'}
165
+ class:left-end={popupPosition.placement === 'left-end'}
166
+ {...rest}
167
+ onkeydown={onKeydown}
168
+ style="left:{popupPosition.x}px; top:{popupPosition.y}px"
169
+ >
170
+ {#if children}
171
+ {@render children()}
172
+ {/if}
173
+ </div>
174
+ </div>
175
+ {/if}
@@ -0,0 +1,14 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ import type { PopoverPlacement } from './Popover.types';
3
+ type Props = HTMLAttributes<HTMLDivElement> & {
4
+ conditionalRender?: boolean;
5
+ crossAxisOffset?: number;
6
+ mainAxisOffset?: number;
7
+ open?: boolean | null;
8
+ placement?: PopoverPlacement;
9
+ portalHost?: HTMLElement;
10
+ reference?: HTMLElement;
11
+ };
12
+ declare const Popover: import("svelte").Component<Props, {}, "conditionalRender" | "crossAxisOffset" | "mainAxisOffset" | "open" | "placement">;
13
+ type Popover = ReturnType<typeof Popover>;
14
+ export default Popover;
@@ -0,0 +1,4 @@
1
+ import type { POPOVER_PLACEMENTS } from './Popover.constants';
2
+ type PopoverPlacementTuple = typeof POPOVER_PLACEMENTS;
3
+ export type PopoverPlacement = PopoverPlacementTuple[number];
4
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare const STERLING_PORTAL_HOST_ID = "SterlingPortalHost";
2
+ export declare const STERLING_PORTAL_CONTEXT_ID = "SterlingPortalContext";
@@ -0,0 +1,2 @@
1
+ export const STERLING_PORTAL_HOST_ID = 'SterlingPortalHost';
2
+ export const STERLING_PORTAL_CONTEXT_ID = 'SterlingPortalContext';
@@ -0,0 +1,3 @@
1
+ export type PortalContext = {
2
+ portalHost: HTMLElement | undefined;
3
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export declare const PROGRESS_ORIENTATIONS: string[];
@@ -0,0 +1 @@
1
+ export const PROGRESS_ORIENTATIONS = ['horizontal', 'vertical'];
@@ -0,0 +1,61 @@
1
+ <svelte:options runes={true} />
2
+
3
+ <script lang="ts">
4
+ import type { HTMLAttributes } from 'svelte/elements';
5
+
6
+ type Props = HTMLAttributes<HTMLDivElement> & {
7
+ disabled?: boolean | null;
8
+ max?: number;
9
+ percent?: number;
10
+ value?: number;
11
+ vertical?: boolean | null;
12
+ };
13
+
14
+ let {
15
+ class: _class,
16
+ disabled = false,
17
+ max = 100,
18
+ percent = $bindable(0), //readonly
19
+ value = $bindable(0),
20
+ vertical,
21
+ ...rest
22
+ }: Props = $props();
23
+
24
+ //----- State ----- //
25
+
26
+ let clientHeight: number = $state(0);
27
+ let clientWidth: number = $state(0);
28
+
29
+ let clampMax = $derived(Math.max(1, max));
30
+ let clampValue = $derived(Math.max(0, Math.min(value, clampMax)));
31
+ let ratio = $derived(clampValue / clampMax);
32
+
33
+ $effect(() => {
34
+ percent = Math.round(ratio * 100);
35
+ });
36
+
37
+ let percentHeight = $derived(clientHeight * ratio);
38
+ let percentWidth = $derived(clientWidth * ratio);
39
+
40
+ let indicatorStyle = $derived(
41
+ vertical ? `height: ${percentHeight}px` : `width: ${percentWidth}px`
42
+ );
43
+ </script>
44
+
45
+ <!-- svelte-ignore a11y_role_supports_aria_props -->
46
+ <div
47
+ aria-orientation={vertical ? 'vertical' : 'horizontal'}
48
+ class={['sterling-progress', _class]}
49
+ class:disabled
50
+ class:horizontal={!vertical}
51
+ class:vertical
52
+ data-progress-percent={percent}
53
+ data-progress-max={max}
54
+ data-progress-value={value}
55
+ role="progressbar"
56
+ {...rest}
57
+ >
58
+ <div class="container" bind:clientWidth bind:clientHeight>
59
+ <div class="indicator" style={indicatorStyle}></div>
60
+ </div>
61
+ </div>
@@ -0,0 +1,11 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ type Props = HTMLAttributes<HTMLDivElement> & {
3
+ disabled?: boolean | null;
4
+ max?: number;
5
+ percent?: number;
6
+ value?: number;
7
+ vertical?: boolean | null;
8
+ };
9
+ declare const Progress: import("svelte").Component<Props, {}, "value" | "percent">;
10
+ type Progress = ReturnType<typeof Progress>;
11
+ export default Progress;
@@ -0,0 +1,4 @@
1
+ import type { PROGRESS_ORIENTATIONS } from './Progress.constants';
2
+ type ProgressOrientationTuple = typeof PROGRESS_ORIENTATIONS;
3
+ export type ProgressOrientation = ProgressOrientationTuple[number];
4
+ export {};
@@ -0,0 +1 @@
1
+ export {};