@geoffcox/sterling-svelte 2.0.1 → 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 +1 -1
- package/dist/Button.svelte +18 -14
- package/dist/Button.svelte.d.ts +0 -1
- package/dist/Callout.svelte +162 -96
- package/dist/Callout.svelte.d.ts +1 -2
- package/dist/Checkbox.svelte +34 -15
- package/dist/Checkbox.svelte.d.ts +0 -1
- package/dist/Dialog.svelte +121 -71
- package/dist/Dialog.svelte.d.ts +1 -1
- package/dist/Dropdown.svelte +106 -56
- package/dist/Dropdown.svelte.d.ts +8 -3
- package/dist/Input.svelte +54 -29
- package/dist/Input.svelte.d.ts +1 -2
- package/dist/Label.svelte +99 -55
- package/dist/Label.svelte.d.ts +4 -4
- package/dist/Link.svelte +20 -14
- package/dist/Link.svelte.d.ts +0 -1
- package/dist/List.svelte +181 -126
- package/dist/List.svelte.d.ts +0 -1
- package/dist/ListItem.svelte +36 -21
- package/dist/ListItem.svelte.d.ts +0 -1
- package/dist/Menu.svelte +67 -45
- package/dist/Menu.svelte.d.ts +0 -1
- package/dist/MenuBar.svelte +96 -65
- package/dist/MenuBar.svelte.d.ts +0 -1
- package/dist/MenuButton.svelte +102 -62
- package/dist/MenuButton.svelte.d.ts +1 -1
- package/dist/MenuItem.svelte +332 -243
- package/dist/MenuItem.svelte.d.ts +3 -3
- package/dist/MenuSeparator.svelte +7 -7
- package/dist/MenuSeparator.svelte.d.ts +0 -1
- 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.svelte +114 -60
- package/dist/Popover.svelte.d.ts +1 -2
- package/dist/Portal.types.d.ts +1 -4
- package/dist/Progress.svelte +40 -15
- package/dist/Progress.svelte.d.ts +0 -1
- package/dist/Radio.svelte +37 -25
- package/dist/Radio.svelte.d.ts +0 -1
- package/dist/Select.svelte +191 -125
- package/dist/Select.svelte.d.ts +8 -2
- package/dist/Slider.svelte +120 -71
- package/dist/Slider.svelte.d.ts +0 -1
- package/dist/Switch.svelte +51 -20
- package/dist/Switch.svelte.d.ts +1 -1
- package/dist/Tab.svelte +39 -24
- package/dist/Tab.svelte.d.ts +0 -1
- package/dist/TabList.svelte +176 -125
- package/dist/TabList.svelte.d.ts +0 -1
- package/dist/TextArea.svelte +83 -41
- package/dist/TextArea.svelte.d.ts +2 -3
- package/dist/Tooltip.svelte +68 -36
- package/dist/Tree.svelte +52 -24
- package/dist/Tree.svelte.d.ts +0 -1
- package/dist/TreeChevron.svelte +24 -12
- package/dist/TreeChevron.svelte.d.ts +0 -1
- package/dist/TreeItem.svelte +292 -225
- package/dist/TreeItem.svelte.d.ts +1 -1
- package/dist/actions/extraClass.d.ts +1 -0
- package/dist/actions/extraClass.js +1 -0
- package/dist/idGenerator.d.ts +1 -0
- package/dist/idGenerator.js +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/mediaQueries/prefersColorSchemeDark.d.ts +0 -1
- package/dist/mediaQueries/prefersReducedMotion.d.ts +0 -1
- package/dist/mediaQueries/usingKeyboard.d.ts +0 -1
- package/package.json +21 -22
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ npm install @geoffcox/sterling-svelte
|
|
|
11
11
|
## Documentation
|
|
12
12
|
|
|
13
13
|
The project builds the documentation for the library as a SvelteKit application.
|
|
14
|
-
See the published version of the [documentation](https://geoffcox.github.io/
|
|
14
|
+
See the published version of the [documentation](https://geoffcox.github.io/docs/sterling-svelte/).
|
|
15
15
|
|
|
16
16
|
## Repository
|
|
17
17
|
|
package/dist/Button.svelte
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
<svelte:options runes={true} />
|
|
2
2
|
|
|
3
|
-
<script lang="ts">
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
<script lang="ts">
|
|
4
|
+
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
5
|
+
|
|
6
|
+
type Props = HTMLButtonAttributes;
|
|
7
|
+
|
|
8
|
+
let { children, class: _class, ...rest }: Props = $props();
|
|
9
|
+
|
|
10
|
+
let buttonRef: HTMLButtonElement;
|
|
11
|
+
|
|
12
|
+
export const click = () => {
|
|
6
13
|
buttonRef?.click();
|
|
7
|
-
};
|
|
8
|
-
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const blur = () => {
|
|
9
17
|
buttonRef?.blur();
|
|
10
|
-
};
|
|
11
|
-
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const focus = (options?: FocusOptions) => {
|
|
12
21
|
buttonRef?.focus(options);
|
|
13
|
-
};
|
|
22
|
+
};
|
|
14
23
|
</script>
|
|
15
24
|
|
|
16
|
-
<button
|
|
17
|
-
bind:this={buttonRef}
|
|
18
|
-
class={['sterling-button', _class].filter(Boolean).join(' ')}
|
|
19
|
-
type="button"
|
|
20
|
-
{...rest}
|
|
21
|
-
>
|
|
25
|
+
<button bind:this={buttonRef} class={['sterling-button', _class]} type="button" {...rest}>
|
|
22
26
|
{#if children}
|
|
23
27
|
{@render children()}
|
|
24
28
|
{/if}
|
package/dist/Button.svelte.d.ts
CHANGED
package/dist/Callout.svelte
CHANGED
|
@@ -1,139 +1,205 @@
|
|
|
1
1
|
<svelte:options runes={true} />
|
|
2
2
|
|
|
3
|
-
<script lang="ts">
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
<script lang="ts">
|
|
4
|
+
import {
|
|
5
|
+
arrow,
|
|
6
|
+
autoUpdate,
|
|
7
|
+
computePosition,
|
|
8
|
+
flip,
|
|
9
|
+
offset,
|
|
10
|
+
type ComputePositionReturn,
|
|
11
|
+
type Placement
|
|
12
|
+
} from '@floating-ui/dom';
|
|
13
|
+
import { getContext, tick } from 'svelte';
|
|
14
|
+
import type { HTMLAttributes, KeyboardEventHandler } from 'svelte/elements';
|
|
15
|
+
import { fade, type FadeParams, type TransitionConfig } from 'svelte/transition';
|
|
16
|
+
import { portal } from './actions/portal';
|
|
17
|
+
import { prefersReducedMotion } from './mediaQueries/prefersReducedMotion';
|
|
18
|
+
import type { PopoverPlacement } from './Popover.types';
|
|
19
|
+
import { STERLING_PORTAL_CONTEXT_ID, STERLING_PORTAL_HOST_ID } from './Portal.constants';
|
|
20
|
+
import type { PortalContext } from './Portal.types';
|
|
21
|
+
|
|
22
|
+
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
23
|
+
conditionalRender?: boolean | null;
|
|
24
|
+
crossAxisOffset?: number;
|
|
25
|
+
mainAxisOffset?: number;
|
|
26
|
+
open?: boolean | null;
|
|
27
|
+
placement?: PopoverPlacement;
|
|
28
|
+
portalHost?: HTMLElement;
|
|
29
|
+
reference?: HTMLElement | null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
let {
|
|
33
|
+
children,
|
|
34
|
+
conditionalRender = $bindable(true),
|
|
35
|
+
crossAxisOffset = $bindable(0),
|
|
36
|
+
mainAxisOffset = $bindable(0),
|
|
37
|
+
open = $bindable(false),
|
|
38
|
+
placement = $bindable('top-start'),
|
|
39
|
+
portalHost,
|
|
40
|
+
reference,
|
|
41
|
+
class: _class,
|
|
42
|
+
...rest
|
|
43
|
+
}: Props = $props();
|
|
44
|
+
|
|
45
|
+
let popupRef: HTMLDivElement | undefined = $state(undefined);
|
|
46
|
+
let arrowRef: HTMLDivElement | undefined = $state(undefined);
|
|
47
|
+
let popupPosition: Partial<ComputePositionReturn> = $state({ x: 0, y: 0 });
|
|
48
|
+
let floatingUIPlacement = $derived(placement as Placement);
|
|
49
|
+
let bodyHeight = $state(0);
|
|
50
|
+
let resizeObserver: ResizeObserver | undefined = undefined;
|
|
51
|
+
|
|
52
|
+
const portalContext = getContext<PortalContext>(STERLING_PORTAL_CONTEXT_ID) || {
|
|
17
53
|
portalHost: undefined
|
|
18
|
-
};
|
|
19
|
-
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const ensurePortalHost = async () => {
|
|
20
57
|
await tick();
|
|
58
|
+
|
|
21
59
|
// use the host set from context, usually set from a Dialog
|
|
22
|
-
let host =
|
|
60
|
+
let host = portalContext.portalHost;
|
|
61
|
+
|
|
23
62
|
// use or create the sterling portal host
|
|
24
63
|
if (!host && globalThis?.document) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
}
|
|
33
73
|
}
|
|
74
|
+
|
|
34
75
|
portalHost = host;
|
|
35
|
-
};
|
|
36
|
-
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
let middleware = $derived([
|
|
37
79
|
offset({ mainAxis: mainAxisOffset, crossAxis: crossAxisOffset }),
|
|
38
80
|
flip(),
|
|
39
81
|
arrowRef && arrow({ element: arrowRef, padding: 8 })
|
|
40
|
-
]);
|
|
41
|
-
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
const computeCalloutPosition = async () => {
|
|
42
85
|
if (reference && popupRef) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
else {
|
|
50
|
-
popupPosition = { x: 0, y: 0 };
|
|
86
|
+
popupPosition = await computePosition(reference, popupRef, {
|
|
87
|
+
placement: floatingUIPlacement,
|
|
88
|
+
middleware
|
|
89
|
+
});
|
|
90
|
+
} else {
|
|
91
|
+
popupPosition = { x: 0, y: 0 };
|
|
51
92
|
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// whenever a positioned element is portaled it needs resubscription to auto-update
|
|
96
|
+
let cleanupAutoUpdate = () => {};
|
|
97
|
+
|
|
98
|
+
const autoUpdateCalloutPosition = () => {
|
|
56
99
|
cleanupAutoUpdate();
|
|
57
|
-
cleanupAutoUpdate = () => {
|
|
100
|
+
cleanupAutoUpdate = () => {};
|
|
58
101
|
if (reference && popupRef) {
|
|
59
|
-
|
|
102
|
+
cleanupAutoUpdate = autoUpdate(reference, popupRef, computeCalloutPosition);
|
|
60
103
|
}
|
|
61
|
-
};
|
|
62
|
-
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
$effect(() => {
|
|
63
107
|
autoUpdateCalloutPosition();
|
|
64
108
|
return () => {
|
|
65
|
-
|
|
66
|
-
|
|
109
|
+
cleanupAutoUpdate();
|
|
110
|
+
cleanupAutoUpdate = () => {};
|
|
67
111
|
};
|
|
68
|
-
});
|
|
69
|
-
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
$effect(() => {
|
|
70
115
|
bodyHeight;
|
|
71
116
|
reference;
|
|
72
117
|
computeCalloutPosition();
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// ----- Arrow ----- //
|
|
121
|
+
|
|
122
|
+
const getArrowPlacementStyle = (position?: Partial<ComputePositionReturn>) => {
|
|
76
123
|
if (position?.placement && arrowRef) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
124
|
+
switch (position.placement) {
|
|
125
|
+
case 'top':
|
|
126
|
+
case 'top-start':
|
|
127
|
+
case 'top-end':
|
|
128
|
+
return (
|
|
129
|
+
`bottom: -${arrowRef.offsetWidth}px;` + `transform:translate(0, -50%) rotate(135deg);`
|
|
130
|
+
);
|
|
131
|
+
case 'right':
|
|
132
|
+
case 'right-start':
|
|
133
|
+
case 'right-end':
|
|
134
|
+
return (
|
|
135
|
+
`left: -${arrowRef.offsetWidth}px;` + `transform:translate(50%, 0) rotate(225deg);`
|
|
136
|
+
);
|
|
137
|
+
case 'bottom':
|
|
138
|
+
case 'bottom-start':
|
|
139
|
+
case 'bottom-end':
|
|
140
|
+
return `top: -${arrowRef.offsetWidth}px;` + `transform:translate(0, 50%) rotate(-45deg);`;
|
|
141
|
+
case 'left':
|
|
142
|
+
case 'left-start':
|
|
143
|
+
case 'left-end':
|
|
144
|
+
return (
|
|
145
|
+
`right: -${arrowRef.offsetWidth}px;` + `transform:translate(-50%, 0) rotate(45deg);`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
95
148
|
}
|
|
96
149
|
return '';
|
|
97
|
-
};
|
|
98
|
-
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const getArrowOffsetStyle = (position?: Partial<ComputePositionReturn>) => {
|
|
99
153
|
const arrow = position?.middlewareData?.arrow;
|
|
100
154
|
if (arrow) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
155
|
+
if (arrow.x !== null && arrow.x !== undefined) {
|
|
156
|
+
return `left: ${arrow.x}px;`;
|
|
157
|
+
} else if (arrow.y !== null && arrow.y !== undefined) {
|
|
158
|
+
return `top: ${arrow.y}px;`;
|
|
159
|
+
}
|
|
107
160
|
}
|
|
108
161
|
return '';
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
let arrowStyle = $derived(
|
|
165
|
+
getArrowPlacementStyle(popupPosition) + getArrowOffsetStyle(popupPosition)
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// ----- Animation ----- //
|
|
169
|
+
|
|
170
|
+
const fadeNoOp = (node: Element, params?: FadeParams): TransitionConfig => {
|
|
113
171
|
return { delay: 0, duration: 0 };
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
let fadeMotion = $derived(!$prefersReducedMotion ? fade : fadeNoOp);
|
|
175
|
+
|
|
176
|
+
// ----- EventHandlers ----- //
|
|
177
|
+
|
|
178
|
+
const onKeydown: KeyboardEventHandler<HTMLDivElement> = (event) => {
|
|
118
179
|
if (event.key === 'Escape') {
|
|
119
|
-
|
|
180
|
+
open = false;
|
|
120
181
|
}
|
|
121
182
|
rest.onkeydown?.(event);
|
|
122
|
-
};
|
|
123
|
-
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
$effect(() => {
|
|
124
186
|
ensurePortalHost();
|
|
187
|
+
|
|
125
188
|
resizeObserver = new ResizeObserver((entries) => {
|
|
126
|
-
|
|
189
|
+
bodyHeight = entries[0].target.clientHeight;
|
|
127
190
|
});
|
|
191
|
+
|
|
128
192
|
// start observing a DOM node
|
|
129
193
|
resizeObserver.observe(document.body);
|
|
194
|
+
|
|
130
195
|
return () => {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
196
|
+
resizeObserver?.unobserve(document.body);
|
|
197
|
+
resizeObserver?.disconnect();
|
|
198
|
+
resizeObserver = undefined;
|
|
134
199
|
};
|
|
135
|
-
});
|
|
136
|
-
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
ensurePortalHost();
|
|
137
203
|
</script>
|
|
138
204
|
|
|
139
205
|
{#if open || !conditionalRender}
|
|
@@ -145,7 +211,7 @@ ensurePortalHost();
|
|
|
145
211
|
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
146
212
|
<div
|
|
147
213
|
bind:this={popupRef}
|
|
148
|
-
class={['sterling-callout', _class]
|
|
214
|
+
class={['sterling-callout', _class]}
|
|
149
215
|
class:open
|
|
150
216
|
class:top={popupPosition.placement === 'top'}
|
|
151
217
|
class:top-start={popupPosition.placement === 'top-start'}
|
package/dist/Callout.svelte.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { PopoverPlacement } from './Popover.types';
|
|
3
1
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
import type { PopoverPlacement } from './Popover.types';
|
|
4
3
|
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
5
4
|
conditionalRender?: boolean | null;
|
|
6
5
|
crossAxisOffset?: number;
|
package/dist/Checkbox.svelte
CHANGED
|
@@ -1,24 +1,43 @@
|
|
|
1
1
|
<svelte:options runes={true} />
|
|
2
2
|
|
|
3
|
-
<script lang="ts">
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
$
|
|
3
|
+
<script lang="ts">
|
|
4
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
5
|
+
import { usingKeyboard } from './mediaQueries/usingKeyboard';
|
|
6
|
+
|
|
7
|
+
const uuid = $props.id();
|
|
8
|
+
|
|
9
|
+
type Props = HTMLInputAttributes;
|
|
10
|
+
|
|
11
|
+
let {
|
|
12
|
+
id,
|
|
13
|
+
children,
|
|
14
|
+
checked = $bindable(false),
|
|
15
|
+
class: _class,
|
|
16
|
+
disabled = $bindable(false),
|
|
17
|
+
...rest
|
|
18
|
+
}: Props = $props();
|
|
19
|
+
|
|
20
|
+
let inputRef: HTMLInputElement;
|
|
21
|
+
|
|
22
|
+
$effect(() => {
|
|
8
23
|
if (children && id === undefined) {
|
|
9
|
-
|
|
24
|
+
id = `Checkbox-${uuid}`;
|
|
10
25
|
}
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// ----- Methods ----- //
|
|
29
|
+
|
|
30
|
+
export const blur = () => {
|
|
14
31
|
inputRef?.blur();
|
|
15
|
-
};
|
|
16
|
-
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const click = () => {
|
|
17
35
|
inputRef?.click();
|
|
18
|
-
};
|
|
19
|
-
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const focus = (options?: FocusOptions) => {
|
|
20
39
|
inputRef?.focus(options);
|
|
21
|
-
};
|
|
40
|
+
};
|
|
22
41
|
</script>
|
|
23
42
|
|
|
24
43
|
<!--
|
|
@@ -26,7 +45,7 @@ export const focus = (options) => {
|
|
|
26
45
|
A styled HTML input type=checkbox element.
|
|
27
46
|
-->
|
|
28
47
|
<div
|
|
29
|
-
class={['sterling-checkbox', _class]
|
|
48
|
+
class={['sterling-checkbox', _class]}
|
|
30
49
|
class:checked
|
|
31
50
|
class:disabled
|
|
32
51
|
class:using-keyboard={$usingKeyboard}
|