@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.
- package/README.md +18 -0
- package/dist/@types/clickOutside.d.ts +15 -0
- package/dist/Button.svelte +29 -0
- package/dist/Button.svelte.d.ts +8 -0
- package/dist/Callout.svelte +243 -0
- package/dist/Callout.svelte.d.ts +14 -0
- package/dist/Callout.types.d.ts +11 -0
- package/dist/Callout.types.js +1 -0
- package/dist/Checkbox.svelte +62 -0
- package/dist/Checkbox.svelte.d.ts +9 -0
- package/dist/Dialog.svelte +201 -0
- package/dist/Dialog.svelte.d.ts +14 -0
- package/dist/Dropdown.svelte +159 -0
- package/dist/Dropdown.svelte.d.ts +23 -0
- package/dist/Input.svelte +80 -0
- package/dist/Input.svelte.d.ts +11 -0
- package/dist/Label.constants.d.ts +2 -0
- package/dist/Label.constants.js +2 -0
- package/dist/Label.svelte +135 -0
- package/dist/Label.svelte.d.ts +17 -0
- package/dist/Link.svelte +31 -0
- package/dist/Link.svelte.d.ts +11 -0
- package/dist/List.constants.d.ts +1 -0
- package/dist/List.constants.js +1 -0
- package/dist/List.svelte +258 -0
- package/dist/List.svelte.d.ts +19 -0
- package/dist/List.types.d.ts +5 -0
- package/dist/List.types.js +1 -0
- package/dist/ListItem.svelte +64 -0
- package/dist/ListItem.svelte.d.ts +12 -0
- package/dist/Menu.svelte +105 -0
- package/dist/Menu.svelte.d.ts +12 -0
- package/dist/MenuBar.constants.d.ts +1 -0
- package/dist/MenuBar.constants.js +1 -0
- package/dist/MenuBar.svelte +144 -0
- package/dist/MenuBar.svelte.d.ts +12 -0
- package/dist/MenuBar.types.d.ts +4 -0
- package/dist/MenuBar.types.js +1 -0
- package/dist/MenuButton.svelte +156 -0
- package/dist/MenuButton.svelte.d.ts +20 -0
- package/dist/MenuItem.constants.d.ts +2 -0
- package/dist/MenuItem.constants.js +2 -0
- package/dist/MenuItem.svelte +431 -0
- package/dist/MenuItem.svelte.d.ts +22 -0
- package/dist/MenuItem.types.d.ts +20 -0
- package/dist/MenuItem.types.js +1 -0
- package/dist/MenuItem.utils.d.ts +7 -0
- package/dist/MenuItem.utils.js +36 -0
- package/dist/MenuSeparator.svelte +11 -0
- package/dist/MenuSeparator.svelte.d.ts +5 -0
- package/dist/Pagination.svelte +267 -0
- package/dist/Pagination.svelte.d.ts +4 -0
- package/dist/Pagination.types.d.ts +24 -0
- package/dist/Pagination.types.js +1 -0
- package/dist/Popover.constants.d.ts +1 -0
- package/dist/Popover.constants.js +14 -0
- package/dist/Popover.svelte +175 -0
- package/dist/Popover.svelte.d.ts +14 -0
- package/dist/Popover.types.d.ts +4 -0
- package/dist/Popover.types.js +1 -0
- package/dist/Portal.constants.d.ts +2 -0
- package/dist/Portal.constants.js +2 -0
- package/dist/Portal.types.d.ts +3 -0
- package/dist/Portal.types.js +1 -0
- package/dist/Progress.constants.d.ts +1 -0
- package/dist/Progress.constants.js +1 -0
- package/dist/Progress.svelte +61 -0
- package/dist/Progress.svelte.d.ts +11 -0
- package/dist/Progress.types.d.ts +4 -0
- package/dist/Progress.types.js +1 -0
- package/dist/Radio.svelte +65 -0
- package/dist/Radio.svelte.d.ts +12 -0
- package/dist/Select.svelte +262 -0
- package/dist/Select.svelte.d.ts +26 -0
- package/dist/Slider.svelte +182 -0
- package/dist/Slider.svelte.d.ts +18 -0
- package/dist/Switch.svelte +92 -0
- package/dist/Switch.svelte.d.ts +21 -0
- package/dist/Tab.svelte +66 -0
- package/dist/Tab.svelte.d.ts +11 -0
- package/dist/TabList.constants.d.ts +1 -0
- package/dist/TabList.constants.js +1 -0
- package/dist/TabList.svelte +253 -0
- package/dist/TabList.svelte.d.ts +17 -0
- package/dist/TabList.types.d.ts +5 -0
- package/dist/TabList.types.js +1 -0
- package/dist/TextArea.constants.d.ts +1 -0
- package/dist/TextArea.constants.js +1 -0
- package/dist/TextArea.svelte +116 -0
- package/dist/TextArea.svelte.d.ts +18 -0
- package/dist/TextArea.types.d.ts +4 -0
- package/dist/TextArea.types.js +1 -0
- package/dist/Tooltip.svelte +95 -0
- package/dist/Tooltip.svelte.d.ts +10 -0
- package/dist/Tree.constants.d.ts +1 -0
- package/dist/Tree.constants.js +1 -0
- package/dist/Tree.svelte +81 -0
- package/dist/Tree.svelte.d.ts +14 -0
- package/dist/Tree.types.d.ts +5 -0
- package/dist/Tree.types.js +1 -0
- package/dist/TreeChevron.svelte +39 -0
- package/dist/TreeChevron.svelte.d.ts +8 -0
- package/dist/TreeItem.constants.d.ts +1 -0
- package/dist/TreeItem.constants.js +1 -0
- package/dist/TreeItem.svelte +396 -0
- package/dist/TreeItem.svelte.d.ts +22 -0
- package/dist/TreeItem.types.d.ts +4 -0
- package/dist/TreeItem.types.js +1 -0
- package/dist/actions/applyLightDarkMode.d.ts +10 -0
- package/dist/actions/applyLightDarkMode.js +36 -0
- package/dist/actions/clickOutside.d.ts +15 -0
- package/dist/actions/clickOutside.js +28 -0
- package/dist/actions/extraClass.d.ts +9 -0
- package/dist/actions/extraClass.js +15 -0
- package/dist/actions/forwardEvents.d.ts +12 -0
- package/dist/actions/forwardEvents.js +32 -0
- package/dist/actions/portal.d.ts +8 -0
- package/dist/actions/portal.js +19 -0
- package/dist/actions/trapKeyboardFocus.d.ts +3 -0
- package/dist/actions/trapKeyboardFocus.js +52 -0
- package/dist/idGenerator.d.ts +5 -0
- package/dist/idGenerator.js +11 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +55 -0
- package/dist/mediaQueries/prefersColorSchemeDark.d.ts +1 -0
- package/dist/mediaQueries/prefersColorSchemeDark.js +14 -0
- package/dist/mediaQueries/prefersReducedMotion.d.ts +1 -0
- package/dist/mediaQueries/prefersReducedMotion.js +14 -0
- package/dist/mediaQueries/usingKeyboard.d.ts +1 -0
- package/dist/mediaQueries/usingKeyboard.js +17 -0
- 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,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
|
+
<<
|
|
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
|
+
>>
|
|
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,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,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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|