@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.
- package/package.json +21 -23
- package/.DS_Store +0 -0
- package/@types/clickOutside.d.ts +0 -15
- package/Button.svelte +0 -25
- package/Button.svelte.d.ts +0 -9
- package/Callout.svelte +0 -177
- package/Callout.svelte.d.ts +0 -15
- package/Callout.types.d.ts +0 -11
- package/Callout.types.js +0 -1
- package/Checkbox.svelte +0 -43
- package/Checkbox.svelte.d.ts +0 -10
- package/Dialog.svelte +0 -151
- package/Dialog.svelte.d.ts +0 -14
- package/Dropdown.svelte +0 -109
- package/Dropdown.svelte.d.ts +0 -18
- package/Input.svelte +0 -55
- package/Input.svelte.d.ts +0 -12
- package/Label.constants.d.ts +0 -2
- package/Label.constants.js +0 -2
- package/Label.svelte +0 -91
- package/Label.svelte.d.ts +0 -17
- package/Link.svelte +0 -25
- package/Link.svelte.d.ts +0 -12
- package/List.constants.d.ts +0 -1
- package/List.constants.js +0 -1
- package/List.svelte +0 -203
- package/List.svelte.d.ts +0 -20
- package/List.types.d.ts +0 -5
- package/List.types.js +0 -1
- package/ListItem.svelte +0 -49
- package/ListItem.svelte.d.ts +0 -13
- package/Menu.svelte +0 -83
- package/Menu.svelte.d.ts +0 -13
- package/MenuBar.constants.d.ts +0 -1
- package/MenuBar.constants.js +0 -1
- package/MenuBar.svelte +0 -113
- package/MenuBar.svelte.d.ts +0 -13
- package/MenuBar.types.d.ts +0 -4
- package/MenuBar.types.js +0 -1
- package/MenuButton.svelte +0 -116
- package/MenuButton.svelte.d.ts +0 -20
- package/MenuItem.constants.d.ts +0 -2
- package/MenuItem.constants.js +0 -2
- package/MenuItem.svelte +0 -342
- package/MenuItem.svelte.d.ts +0 -22
- package/MenuItem.types.d.ts +0 -20
- package/MenuItem.types.js +0 -1
- package/MenuItem.utils.d.ts +0 -7
- package/MenuItem.utils.js +0 -36
- package/MenuSeparator.svelte +0 -11
- package/MenuSeparator.svelte.d.ts +0 -6
- package/Popover.constants.d.ts +0 -1
- package/Popover.constants.js +0 -14
- package/Popover.svelte +0 -121
- package/Popover.svelte.d.ts +0 -15
- package/Popover.types.d.ts +0 -4
- package/Popover.types.js +0 -1
- package/Portal.constants.d.ts +0 -2
- package/Portal.constants.js +0 -2
- package/Portal.types.d.ts +0 -6
- package/Portal.types.js +0 -1
- package/Progress.constants.d.ts +0 -1
- package/Progress.constants.js +0 -1
- package/Progress.svelte +0 -36
- package/Progress.svelte.d.ts +0 -12
- package/Progress.types.d.ts +0 -4
- package/Progress.types.js +0 -1
- package/Radio.svelte +0 -53
- package/Radio.svelte.d.ts +0 -13
- package/Select.svelte +0 -196
- package/Select.svelte.d.ts +0 -20
- package/Slider.svelte +0 -133
- package/Slider.svelte.d.ts +0 -19
- package/Switch.svelte +0 -61
- package/Switch.svelte.d.ts +0 -21
- package/Tab.svelte +0 -51
- package/Tab.svelte.d.ts +0 -12
- package/TabList.constants.d.ts +0 -1
- package/TabList.constants.js +0 -1
- package/TabList.svelte +0 -202
- package/TabList.svelte.d.ts +0 -18
- package/TabList.types.d.ts +0 -5
- package/TabList.types.js +0 -1
- package/TextArea.constants.d.ts +0 -1
- package/TextArea.constants.js +0 -1
- package/TextArea.svelte +0 -74
- package/TextArea.svelte.d.ts +0 -19
- package/TextArea.types.d.ts +0 -4
- package/TextArea.types.js +0 -1
- package/Tooltip.svelte +0 -63
- package/Tooltip.svelte.d.ts +0 -10
- package/Tree.constants.d.ts +0 -1
- package/Tree.constants.js +0 -1
- package/Tree.svelte +0 -53
- package/Tree.svelte.d.ts +0 -15
- package/Tree.types.d.ts +0 -5
- package/Tree.types.js +0 -1
- package/TreeChevron.svelte +0 -27
- package/TreeChevron.svelte.d.ts +0 -9
- package/TreeItem.constants.d.ts +0 -1
- package/TreeItem.constants.js +0 -1
- package/TreeItem.svelte +0 -329
- package/TreeItem.svelte.d.ts +0 -22
- package/TreeItem.types.d.ts +0 -4
- package/TreeItem.types.js +0 -1
- package/actions/applyLightDarkMode.d.ts +0 -10
- package/actions/applyLightDarkMode.js +0 -36
- package/actions/clickOutside.d.ts +0 -15
- package/actions/clickOutside.js +0 -28
- package/actions/extraClass.d.ts +0 -8
- package/actions/extraClass.js +0 -14
- package/actions/forwardEvents.d.ts +0 -12
- package/actions/forwardEvents.js +0 -32
- package/actions/portal.d.ts +0 -8
- package/actions/portal.js +0 -19
- package/actions/trapKeyboardFocus.d.ts +0 -3
- package/actions/trapKeyboardFocus.js +0 -52
- package/idGenerator.d.ts +0 -4
- package/idGenerator.js +0 -10
- package/index.d.ts +0 -59
- package/index.js +0 -54
- package/mediaQueries/prefersColorSchemeDark.d.ts +0 -2
- package/mediaQueries/prefersColorSchemeDark.js +0 -14
- package/mediaQueries/prefersReducedMotion.d.ts +0 -2
- package/mediaQueries/prefersReducedMotion.js +0 -14
- package/mediaQueries/usingKeyboard.d.ts +0 -2
- package/mediaQueries/usingKeyboard.js +0 -17
package/MenuItem.utils.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export const focusPreviousChild = (children, currentValue) => {
|
|
2
|
-
const index = children?.findIndex((menuItem) => menuItem.value === currentValue);
|
|
3
|
-
if (index !== -1) {
|
|
4
|
-
const focusIndex = index === 0 ? children.length - 1 : index - 1;
|
|
5
|
-
children[focusIndex].focus();
|
|
6
|
-
}
|
|
7
|
-
};
|
|
8
|
-
export const focusNextChild = (children, currentValue) => {
|
|
9
|
-
const index = children?.findIndex((menuItem) => menuItem.value === currentValue);
|
|
10
|
-
if (index !== -1) {
|
|
11
|
-
const focusIndex = (index + 1) % children.length;
|
|
12
|
-
children[focusIndex].focus();
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
export const focusFirstChild = (children) => {
|
|
16
|
-
children?.[0]?.focus();
|
|
17
|
-
};
|
|
18
|
-
export const focusLastChild = (children) => {
|
|
19
|
-
children?.[children.length - 1]?.focus();
|
|
20
|
-
};
|
|
21
|
-
export const isElementMenuItem = (candidate) => {
|
|
22
|
-
if (!candidate)
|
|
23
|
-
return false;
|
|
24
|
-
const dataValue = candidate?.getAttribute('data-value');
|
|
25
|
-
const role = candidate?.getAttribute('role');
|
|
26
|
-
return ((role === 'menuitem' || role === 'menuitemcheckbox' || role === 'menuitemradio') &&
|
|
27
|
-
dataValue !== null &&
|
|
28
|
-
dataValue !== undefined);
|
|
29
|
-
};
|
|
30
|
-
export const isElementEnabledMenuItem = (candidate) => {
|
|
31
|
-
if (!isElementMenuItem(candidate)) {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
const disabled = candidate?.getAttribute('disabled');
|
|
35
|
-
return disabled === null || disabled === 'false';
|
|
36
|
-
};
|
package/MenuSeparator.svelte
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
type Props = HTMLAttributes<HTMLDivElement>;
|
|
4
|
-
declare const MenuSeparator: import("svelte").Component<Props, {}, "">;
|
|
5
|
-
type MenuSeparator = ReturnType<typeof MenuSeparator>;
|
|
6
|
-
export default MenuSeparator;
|
package/Popover.constants.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const POPOVER_PLACEMENTS: string[];
|
package/Popover.constants.js
DELETED
package/Popover.svelte
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
<svelte:options runes={true} />
|
|
2
|
-
|
|
3
|
-
<script lang="ts">import { getContext, onMount, tick } from 'svelte';
|
|
4
|
-
import { autoUpdate, computePosition, flip, offset } from '@floating-ui/dom';
|
|
5
|
-
import { portal } from './actions/portal';
|
|
6
|
-
import { STERLING_PORTAL_HOST_ID, STERLING_PORTAL_CONTEXT_ID } from './Portal.constants';
|
|
7
|
-
let { children, conditionalRender = $bindable(true), crossAxisOffset = $bindable(0), mainAxisOffset = $bindable(0), open = $bindable(false), placement = $bindable('top-start'), portalHost, reference, class: _class, ...rest } = $props();
|
|
8
|
-
let popupRef = $state(undefined);
|
|
9
|
-
let popupPosition = $state({ x: 0, y: 0 });
|
|
10
|
-
let floatingUIPlacement = $derived(placement);
|
|
11
|
-
let bodyHeight = $state(0);
|
|
12
|
-
let resizeObserver = undefined;
|
|
13
|
-
const { portalHost: contextPortalHost } = getContext(STERLING_PORTAL_CONTEXT_ID) || {
|
|
14
|
-
portalHost: undefined
|
|
15
|
-
};
|
|
16
|
-
// ----- Portal Host ----- //
|
|
17
|
-
const ensurePortalHost = async () => {
|
|
18
|
-
await tick();
|
|
19
|
-
// use the host set from context, usually set from a Dialog
|
|
20
|
-
let host = $contextPortalHost;
|
|
21
|
-
// use or create the sterling portal host
|
|
22
|
-
if (!host && globalThis?.document) {
|
|
23
|
-
host = globalThis.document.querySelector(`#${STERLING_PORTAL_HOST_ID}`);
|
|
24
|
-
// fallback to creating the sterling portal host
|
|
25
|
-
if (!host) {
|
|
26
|
-
host = globalThis.document.createElement('div');
|
|
27
|
-
host.id = STERLING_PORTAL_HOST_ID;
|
|
28
|
-
host.style.overflow = 'visible';
|
|
29
|
-
globalThis.document.body.append(host);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
portalHost = host;
|
|
33
|
-
};
|
|
34
|
-
// ----- Position ----- //
|
|
35
|
-
let middleware = $derived([
|
|
36
|
-
offset({ mainAxis: mainAxisOffset, crossAxis: crossAxisOffset }),
|
|
37
|
-
flip()
|
|
38
|
-
]);
|
|
39
|
-
const computePopoverPosition = async () => {
|
|
40
|
-
if (reference && popupRef) {
|
|
41
|
-
popupPosition = await computePosition(reference, popupRef, {
|
|
42
|
-
placement: floatingUIPlacement,
|
|
43
|
-
middleware
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
popupPosition = { x: 0, y: 0 };
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
// whenever a positioned element is portaled it needs resubscription to auto-update
|
|
51
|
-
let cleanupAutoUpdate = () => { };
|
|
52
|
-
const autoUpdatePopoverPosition = () => {
|
|
53
|
-
cleanupAutoUpdate();
|
|
54
|
-
if (reference && popupRef) {
|
|
55
|
-
cleanupAutoUpdate = autoUpdate(reference, popupRef, computePopoverPosition);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
$effect(() => {
|
|
59
|
-
autoUpdatePopoverPosition();
|
|
60
|
-
return () => {
|
|
61
|
-
cleanupAutoUpdate();
|
|
62
|
-
cleanupAutoUpdate = () => { };
|
|
63
|
-
};
|
|
64
|
-
});
|
|
65
|
-
$effect(() => {
|
|
66
|
-
bodyHeight;
|
|
67
|
-
computePopoverPosition();
|
|
68
|
-
});
|
|
69
|
-
// ----- EventHandlers ----- //
|
|
70
|
-
$effect(() => {
|
|
71
|
-
ensurePortalHost();
|
|
72
|
-
resizeObserver = new ResizeObserver((entries) => {
|
|
73
|
-
bodyHeight = entries[0].target.clientHeight;
|
|
74
|
-
});
|
|
75
|
-
// start observing a DOM node
|
|
76
|
-
resizeObserver.observe(document.body);
|
|
77
|
-
return () => {
|
|
78
|
-
resizeObserver?.unobserve(document.body);
|
|
79
|
-
resizeObserver?.disconnect();
|
|
80
|
-
resizeObserver = undefined;
|
|
81
|
-
};
|
|
82
|
-
});
|
|
83
|
-
const onKeydown = (event) => {
|
|
84
|
-
if (event.key === 'Escape') {
|
|
85
|
-
open = false;
|
|
86
|
-
}
|
|
87
|
-
rest.onkeydown?.(event);
|
|
88
|
-
};
|
|
89
|
-
//TODO: Is this necessary?
|
|
90
|
-
ensurePortalHost();
|
|
91
|
-
</script>
|
|
92
|
-
|
|
93
|
-
{#if open || !conditionalRender}
|
|
94
|
-
<div use:portal={{ target: portalHost }} class="sterling-popover-portal">
|
|
95
|
-
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
96
|
-
<div
|
|
97
|
-
bind:this={popupRef}
|
|
98
|
-
class={['sterling-popover', _class].filter(Boolean).join(' ')}
|
|
99
|
-
class:open
|
|
100
|
-
class:top={popupPosition.placement === 'top'}
|
|
101
|
-
class:top-start={popupPosition.placement === 'top-start'}
|
|
102
|
-
class:top-end={popupPosition.placement === 'top-end'}
|
|
103
|
-
class:right={popupPosition.placement === 'right'}
|
|
104
|
-
class:right-start={popupPosition.placement === 'right-start'}
|
|
105
|
-
class:right-end={popupPosition.placement === 'right-end'}
|
|
106
|
-
class:bottom={popupPosition.placement === 'bottom'}
|
|
107
|
-
class:bottom-start={popupPosition.placement === 'bottom-start'}
|
|
108
|
-
class:bottom-end={popupPosition.placement === 'bottom-end'}
|
|
109
|
-
class:left={popupPosition.placement === 'left'}
|
|
110
|
-
class:left-start={popupPosition.placement === 'left-start'}
|
|
111
|
-
class:left-end={popupPosition.placement === 'left-end'}
|
|
112
|
-
{...rest}
|
|
113
|
-
onkeydown={onKeydown}
|
|
114
|
-
style="left:{popupPosition.x}px; top:{popupPosition.y}px"
|
|
115
|
-
>
|
|
116
|
-
{#if children}
|
|
117
|
-
{@render children()}
|
|
118
|
-
{/if}
|
|
119
|
-
</div>
|
|
120
|
-
</div>
|
|
121
|
-
{/if}
|
package/Popover.svelte.d.ts
DELETED
|
@@ -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;
|
|
6
|
-
crossAxisOffset?: number;
|
|
7
|
-
mainAxisOffset?: number;
|
|
8
|
-
open?: boolean | null;
|
|
9
|
-
placement?: PopoverPlacement;
|
|
10
|
-
portalHost?: HTMLElement;
|
|
11
|
-
reference?: HTMLElement;
|
|
12
|
-
};
|
|
13
|
-
declare const Popover: import("svelte").Component<Props, {}, "conditionalRender" | "crossAxisOffset" | "mainAxisOffset" | "open" | "placement">;
|
|
14
|
-
type Popover = ReturnType<typeof Popover>;
|
|
15
|
-
export default Popover;
|
package/Popover.types.d.ts
DELETED
package/Popover.types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/Portal.constants.d.ts
DELETED
package/Portal.constants.js
DELETED
package/Portal.types.d.ts
DELETED
package/Portal.types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/Progress.constants.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const PROGRESS_ORIENTATIONS: string[];
|
package/Progress.constants.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export const PROGRESS_ORIENTATIONS = ['horizontal', 'vertical'];
|
package/Progress.svelte
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
<svelte:options runes={true} />
|
|
2
|
-
|
|
3
|
-
<script lang="ts">let { class: _class, disabled = false, max = 100, percent = $bindable(0), //readonly
|
|
4
|
-
value = $bindable(0), vertical, ...rest } = $props();
|
|
5
|
-
//----- State ----- //
|
|
6
|
-
let clientHeight = $state(0);
|
|
7
|
-
let clientWidth = $state(0);
|
|
8
|
-
let clampMax = $derived(Math.max(1, max));
|
|
9
|
-
let clampValue = $derived(Math.max(0, Math.min(value, clampMax)));
|
|
10
|
-
let ratio = $derived(clampValue / clampMax);
|
|
11
|
-
$effect(() => {
|
|
12
|
-
percent = Math.round(ratio * 100);
|
|
13
|
-
});
|
|
14
|
-
let percentHeight = $derived(clientHeight * ratio);
|
|
15
|
-
let percentWidth = $derived(clientWidth * ratio);
|
|
16
|
-
let indicatorStyle = $derived(vertical ? `height: ${percentHeight}px` : `width: ${percentWidth}px`);
|
|
17
|
-
export {};
|
|
18
|
-
</script>
|
|
19
|
-
|
|
20
|
-
<!-- svelte-ignore a11y_role_supports_aria_props -->
|
|
21
|
-
<div
|
|
22
|
-
aria-orientation={vertical ? 'vertical' : 'horizontal'}
|
|
23
|
-
class={['sterling-progress', _class].filter(Boolean).join(' ')}
|
|
24
|
-
class:disabled
|
|
25
|
-
class:horizontal={!vertical}
|
|
26
|
-
class:vertical
|
|
27
|
-
data-progress-percent={percent}
|
|
28
|
-
data-progress-max={max}
|
|
29
|
-
data-progress-value={value}
|
|
30
|
-
role="progressbar"
|
|
31
|
-
{...rest}
|
|
32
|
-
>
|
|
33
|
-
<div class="container" bind:clientWidth bind:clientHeight>
|
|
34
|
-
<div class="indicator" style={indicatorStyle}></div>
|
|
35
|
-
</div>
|
|
36
|
-
</div>
|
package/Progress.svelte.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
4
|
-
disabled?: boolean | null;
|
|
5
|
-
max?: number;
|
|
6
|
-
percent?: number;
|
|
7
|
-
value?: number;
|
|
8
|
-
vertical?: boolean | null;
|
|
9
|
-
};
|
|
10
|
-
declare const Progress: import("svelte").Component<Props, {}, "value" | "percent">;
|
|
11
|
-
type Progress = ReturnType<typeof Progress>;
|
|
12
|
-
export default Progress;
|
package/Progress.types.d.ts
DELETED
package/Progress.types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/Radio.svelte
DELETED
|
@@ -1,53 +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 = false, group = $bindable(), ...rest } = $props();
|
|
6
|
-
let inputRef;
|
|
7
|
-
$effect(() => {
|
|
8
|
-
if (children && id === undefined) {
|
|
9
|
-
id = idGenerator.nextId('Radio');
|
|
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
|
-
// ----- Event Handlers ----- //
|
|
23
|
-
const onChange = (e) => {
|
|
24
|
-
console.log('onChange', e);
|
|
25
|
-
// if ((e.currentTarget && e.currentTarget.checked) || (e.target && e.target.checked)) {
|
|
26
|
-
// group = value;
|
|
27
|
-
// }
|
|
28
|
-
};
|
|
29
|
-
$effect(() => {
|
|
30
|
-
console.log(id, '-checked', checked);
|
|
31
|
-
});
|
|
32
|
-
</script>
|
|
33
|
-
|
|
34
|
-
<!--
|
|
35
|
-
@component
|
|
36
|
-
A styled HTML input type=radio element with optional label.
|
|
37
|
-
-->
|
|
38
|
-
<div
|
|
39
|
-
class={`sterling-radio ${_class}`}
|
|
40
|
-
class:checked
|
|
41
|
-
class:disabled
|
|
42
|
-
class:using-keyboard={$usingKeyboard}
|
|
43
|
-
>
|
|
44
|
-
<div class="container">
|
|
45
|
-
<input bind:this={inputRef} checked {disabled} bind:group {id} type="radio" {...rest} />
|
|
46
|
-
<div class="indicator"></div>
|
|
47
|
-
</div>
|
|
48
|
-
{#if children}
|
|
49
|
-
<label for={id}>
|
|
50
|
-
{@render children()}
|
|
51
|
-
</label>
|
|
52
|
-
{/if}
|
|
53
|
-
</div>
|
package/Radio.svelte.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
-
type Props = HTMLInputAttributes & {
|
|
4
|
-
group?: any | null;
|
|
5
|
-
};
|
|
6
|
-
/** A styled HTML input type=radio element with optional label. */
|
|
7
|
-
declare const Radio: import("svelte").Component<Props, {
|
|
8
|
-
blur: () => void;
|
|
9
|
-
click: () => void;
|
|
10
|
-
focus: (options?: FocusOptions) => void;
|
|
11
|
-
}, "group" | "checked">;
|
|
12
|
-
type Radio = ReturnType<typeof Radio>;
|
|
13
|
-
export default Radio;
|
package/Select.svelte
DELETED
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
<svelte:options runes={true} />
|
|
2
|
-
|
|
3
|
-
<script lang="ts">import { tick } from 'svelte';
|
|
4
|
-
import { clickOutside } from './actions/clickOutside';
|
|
5
|
-
import { idGenerator } from './idGenerator';
|
|
6
|
-
import List from './List.svelte';
|
|
7
|
-
import Popover from './Popover.svelte';
|
|
8
|
-
let { buttonSnippet, children, class: _class, disabled = false, open = $bindable(false), onSelect, onPending, selectedValue = $bindable(), listClass, valueSnippet, ...rest } = $props();
|
|
9
|
-
const popupId = idGenerator.nextId('Select-popup');
|
|
10
|
-
// ----- State ----- //
|
|
11
|
-
// Tracks the pending selected index
|
|
12
|
-
let pendingSelectedValue = $state(selectedValue);
|
|
13
|
-
// svelte-ignore non_reactive_update
|
|
14
|
-
let selectRef = $state(undefined);
|
|
15
|
-
let listRef;
|
|
16
|
-
// ----- Reactions ----- //
|
|
17
|
-
$effect(() => {
|
|
18
|
-
pendingSelectedValue = selectedValue;
|
|
19
|
-
});
|
|
20
|
-
$effect(() => {
|
|
21
|
-
onSelect?.(selectedValue);
|
|
22
|
-
});
|
|
23
|
-
$effect(() => {
|
|
24
|
-
if (open) {
|
|
25
|
-
onPending?.(pendingSelectedValue);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
$effect(() => {
|
|
29
|
-
if (open) {
|
|
30
|
-
tick().then(() => {
|
|
31
|
-
setTimeout(() => {
|
|
32
|
-
listRef?.focus();
|
|
33
|
-
listRef?.scrollToSelectedItem();
|
|
34
|
-
}, 10);
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
$effect(() => {
|
|
39
|
-
if (!open) {
|
|
40
|
-
tick().then(() => selectRef?.focus());
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
// ----- Methods ----- //
|
|
44
|
-
export const blur = () => {
|
|
45
|
-
selectRef?.blur();
|
|
46
|
-
};
|
|
47
|
-
export const click = () => {
|
|
48
|
-
selectRef?.click();
|
|
49
|
-
};
|
|
50
|
-
export const focus = (options) => {
|
|
51
|
-
selectRef?.focus();
|
|
52
|
-
};
|
|
53
|
-
export const scrollToSelectedItem = () => {
|
|
54
|
-
if (open) {
|
|
55
|
-
listRef?.scrollToSelectedItem();
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
// ----- Event Handlers ----- //
|
|
59
|
-
const onSelectClick = (event) => {
|
|
60
|
-
if (!disabled) {
|
|
61
|
-
open = !open;
|
|
62
|
-
event.preventDefault();
|
|
63
|
-
event.stopPropagation();
|
|
64
|
-
}
|
|
65
|
-
rest.onclick?.(event);
|
|
66
|
-
};
|
|
67
|
-
const onSelectKeydown = (event) => {
|
|
68
|
-
if (!disabled && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) {
|
|
69
|
-
switch (event.key) {
|
|
70
|
-
case ' ':
|
|
71
|
-
{
|
|
72
|
-
if (!open) {
|
|
73
|
-
open = true;
|
|
74
|
-
}
|
|
75
|
-
event.preventDefault();
|
|
76
|
-
event.stopPropagation();
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
break;
|
|
80
|
-
case 'ArrowUp':
|
|
81
|
-
{
|
|
82
|
-
if (selectedValue) {
|
|
83
|
-
listRef?.selectPreviousItem();
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
listRef?.selectLastItem();
|
|
87
|
-
}
|
|
88
|
-
event.preventDefault();
|
|
89
|
-
event.stopPropagation();
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
break;
|
|
93
|
-
case 'ArrowDown':
|
|
94
|
-
{
|
|
95
|
-
if (selectedValue) {
|
|
96
|
-
listRef?.selectNextItem();
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
listRef?.selectFirstItem();
|
|
100
|
-
}
|
|
101
|
-
event.preventDefault();
|
|
102
|
-
event.stopPropagation();
|
|
103
|
-
return false;
|
|
104
|
-
}
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
rest.onkeydown?.(event);
|
|
109
|
-
};
|
|
110
|
-
const onListKeydown = (event) => {
|
|
111
|
-
if (!disabled && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) {
|
|
112
|
-
switch (event.key) {
|
|
113
|
-
case 'Enter':
|
|
114
|
-
{
|
|
115
|
-
selectedValue = pendingSelectedValue;
|
|
116
|
-
open = !open;
|
|
117
|
-
event.preventDefault();
|
|
118
|
-
event.stopPropagation();
|
|
119
|
-
return false;
|
|
120
|
-
}
|
|
121
|
-
break;
|
|
122
|
-
case 'Escape':
|
|
123
|
-
{
|
|
124
|
-
pendingSelectedValue = selectedValue;
|
|
125
|
-
open = !open;
|
|
126
|
-
event.preventDefault();
|
|
127
|
-
event.stopPropagation();
|
|
128
|
-
return false;
|
|
129
|
-
}
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
const onListClick = (event) => {
|
|
135
|
-
open = false;
|
|
136
|
-
event.preventDefault();
|
|
137
|
-
event.stopPropagation();
|
|
138
|
-
return false;
|
|
139
|
-
};
|
|
140
|
-
const onListSelect = (value) => {
|
|
141
|
-
pendingSelectedValue = value;
|
|
142
|
-
if (!open) {
|
|
143
|
-
selectedValue = pendingSelectedValue;
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
</script>
|
|
147
|
-
|
|
148
|
-
<div
|
|
149
|
-
bind:this={selectRef}
|
|
150
|
-
aria-controls={popupId}
|
|
151
|
-
aria-haspopup="listbox"
|
|
152
|
-
aria-expanded={open}
|
|
153
|
-
class={['sterling-select', _class].filter(Boolean).join(' ')}
|
|
154
|
-
class:disabled
|
|
155
|
-
role="combobox"
|
|
156
|
-
tabindex="0"
|
|
157
|
-
use:clickOutside={{ onclickoutside: () => (open = false) }}
|
|
158
|
-
{...rest}
|
|
159
|
-
onclick={onSelectClick}
|
|
160
|
-
onkeydown={onSelectKeydown}
|
|
161
|
-
>
|
|
162
|
-
<div class="value">
|
|
163
|
-
{#if valueSnippet}
|
|
164
|
-
{@render valueSnippet(selectedValue)}
|
|
165
|
-
{:else if selectedValue}
|
|
166
|
-
{selectedValue}
|
|
167
|
-
{:else}
|
|
168
|
-
<span> </span>
|
|
169
|
-
{/if}
|
|
170
|
-
</div>
|
|
171
|
-
<div class="button">
|
|
172
|
-
{#if buttonSnippet}
|
|
173
|
-
{@render buttonSnippet()}
|
|
174
|
-
{:else}
|
|
175
|
-
<div class="chevron"></div>
|
|
176
|
-
{/if}
|
|
177
|
-
</div>
|
|
178
|
-
<Popover reference={selectRef} bind:open id={popupId} conditionalRender={false}>
|
|
179
|
-
<div class={['sterling-select-popup-content', _class].filter(Boolean).join(' ')}>
|
|
180
|
-
<List
|
|
181
|
-
bind:this={listRef}
|
|
182
|
-
{disabled}
|
|
183
|
-
selectedValue={pendingSelectedValue}
|
|
184
|
-
onclick={onListClick}
|
|
185
|
-
onkeydown={onListKeydown}
|
|
186
|
-
onSelect={onListSelect}
|
|
187
|
-
tabindex={open ? 0 : -1}
|
|
188
|
-
class={`composed ${listClass}`}
|
|
189
|
-
>
|
|
190
|
-
{#if children}
|
|
191
|
-
{@render children()}
|
|
192
|
-
{/if}
|
|
193
|
-
</List>
|
|
194
|
-
</div>
|
|
195
|
-
</Popover>
|
|
196
|
-
</div>
|
package/Select.svelte.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { type Snippet } from 'svelte';
|
|
2
|
-
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
type Props = HTMLAttributes<HTMLDivElement> & {
|
|
4
|
-
buttonSnippet?: Snippet;
|
|
5
|
-
disabled?: boolean | null;
|
|
6
|
-
listClass?: string;
|
|
7
|
-
onPending?: (value?: string) => void;
|
|
8
|
-
onSelect?: (value?: string) => void;
|
|
9
|
-
open?: boolean | null;
|
|
10
|
-
selectedValue?: string;
|
|
11
|
-
valueSnippet?: Snippet<[string | undefined]>;
|
|
12
|
-
};
|
|
13
|
-
declare const Select: import("svelte").Component<Props, {
|
|
14
|
-
blur: () => void;
|
|
15
|
-
click: () => void;
|
|
16
|
-
focus: (options?: FocusOptions) => void;
|
|
17
|
-
scrollToSelectedItem: () => void;
|
|
18
|
-
}, "open" | "selectedValue">;
|
|
19
|
-
type Select = ReturnType<typeof Select>;
|
|
20
|
-
export default Select;
|