@geoffcox/sterling-svelte 0.0.15 → 0.0.17

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 (110) hide show
  1. package/@types/clickOutside.d.ts +9 -3
  2. package/{buttons/Button.svelte → Button.svelte} +27 -27
  3. package/{inputs/Checkbox.svelte → Checkbox.svelte} +16 -16
  4. package/{surfaces/Dialog.svelte → Dialog.svelte} +34 -21
  5. package/{inputs/Input.svelte → Input.svelte} +22 -22
  6. package/Label.svelte +52 -0
  7. package/Label.svelte.d.ts +42 -0
  8. package/List.constants.d.ts +1 -0
  9. package/List.constants.js +1 -0
  10. package/List.svelte +324 -0
  11. package/List.svelte.d.ts +69 -0
  12. package/List.types.d.ts +6 -0
  13. package/ListItem.svelte +90 -0
  14. package/ListItem.svelte.d.ts +51 -0
  15. package/Menu.svelte +115 -0
  16. package/Menu.svelte.d.ts +20 -0
  17. package/MenuBar.svelte +97 -0
  18. package/MenuBar.svelte.d.ts +43 -0
  19. package/MenuButton.svelte +102 -0
  20. package/MenuButton.svelte.d.ts +54 -0
  21. package/MenuItem.svelte +338 -0
  22. package/MenuItem.svelte.d.ts +61 -0
  23. package/MenuItemDisplay.svelte +97 -0
  24. package/MenuItemDisplay.svelte.d.ts +21 -0
  25. package/MenuSeparator.svelte +42 -0
  26. package/MenuSeparator.svelte.d.ts +76 -0
  27. package/Menus.constants.d.ts +2 -0
  28. package/Menus.constants.js +2 -0
  29. package/Menus.types.d.ts +22 -0
  30. package/Menus.utils.d.ts +5 -0
  31. package/Menus.utils.js +20 -0
  32. package/Portal.svelte +14 -0
  33. package/Portal.svelte.d.ts +21 -0
  34. package/{display/Progress.svelte → Progress.svelte} +14 -14
  35. package/{inputs/Radio.svelte → Radio.svelte} +15 -15
  36. package/{inputs/Select.svelte → Select.svelte} +96 -102
  37. package/{inputs/Select.svelte.d.ts → Select.svelte.d.ts} +20 -25
  38. package/{inputs/Slider.svelte → Slider.svelte} +49 -24
  39. package/{inputs/Slider.svelte.d.ts → Slider.svelte.d.ts} +25 -0
  40. package/{inputs/Switch.svelte → Switch.svelte} +38 -38
  41. package/Tab.svelte +181 -0
  42. package/{containers/Tab.svelte.d.ts → Tab.svelte.d.ts} +12 -15
  43. package/TabList.svelte +247 -0
  44. package/{containers/TabList.svelte.d.ts → TabList.svelte.d.ts} +21 -21
  45. package/TabList.types.d.ts +7 -0
  46. package/{inputs/TextArea.svelte → TextArea.svelte} +23 -23
  47. package/TextArea.types.js +1 -0
  48. package/Tooltip.svelte +182 -0
  49. package/Tooltip.svelte.d.ts +24 -0
  50. package/Tooltip.types.d.ts +3 -0
  51. package/Tooltip.types.js +1 -0
  52. package/Tree.constants.d.ts +2 -0
  53. package/Tree.constants.js +2 -0
  54. package/Tree.svelte +142 -0
  55. package/Tree.svelte.d.ts +25 -0
  56. package/Tree.types.d.ts +28 -0
  57. package/Tree.types.js +1 -0
  58. package/{containers/TreeChevron.svelte → TreeChevron.svelte} +3 -3
  59. package/TreeItem.svelte +276 -0
  60. package/TreeItem.svelte.d.ts +65 -0
  61. package/{containers/TreeItem.svelte → TreeItemDisplay.svelte} +18 -18
  62. package/{containers/TreeItem.svelte.d.ts → TreeItemDisplay.svelte.d.ts} +11 -14
  63. package/{clickOutside.js → actions/clickOutside.js} +3 -1
  64. package/actions/forwardEvents.d.ts +12 -0
  65. package/actions/forwardEvents.js +32 -0
  66. package/actions/portal.d.ts +8 -0
  67. package/actions/portal.js +19 -0
  68. package/index.d.ts +42 -24
  69. package/index.js +39 -19
  70. package/package.json +45 -29
  71. package/theme/darkTheme.js +66 -74
  72. package/theme/lightTheme.js +66 -74
  73. package/containers/List.svelte +0 -249
  74. package/containers/List.svelte.d.ts +0 -68
  75. package/containers/ListItem.svelte +0 -48
  76. package/containers/ListItem.svelte.d.ts +0 -26
  77. package/containers/Tab.svelte +0 -327
  78. package/containers/TabList.svelte +0 -126
  79. package/containers/Tabs.types.d.ts +0 -12
  80. package/containers/Tree.constants.d.ts +0 -2
  81. package/containers/Tree.constants.js +0 -2
  82. package/containers/Tree.svelte +0 -222
  83. package/containers/Tree.svelte.d.ts +0 -50
  84. package/containers/Tree.types.d.ts +0 -47
  85. package/containers/TreeNode.svelte +0 -267
  86. package/containers/TreeNode.svelte.d.ts +0 -43
  87. package/display/Label.svelte +0 -27
  88. package/display/Label.svelte.d.ts +0 -20
  89. package/surfaces/CloseX.svelte +0 -5
  90. package/surfaces/CloseX.svelte.d.ts +0 -23
  91. /package/{buttons/Button.svelte.d.ts → Button.svelte.d.ts} +0 -0
  92. /package/{buttons/Button.types.d.ts → Button.types.d.ts} +0 -0
  93. /package/{buttons/Button.types.js → Button.types.js} +0 -0
  94. /package/{inputs/Checkbox.svelte.d.ts → Checkbox.svelte.d.ts} +0 -0
  95. /package/{surfaces/Dialog.svelte.d.ts → Dialog.svelte.d.ts} +0 -0
  96. /package/{inputs/Input.svelte.d.ts → Input.svelte.d.ts} +0 -0
  97. /package/{containers/Tabs.types.js → List.types.js} +0 -0
  98. /package/{containers/Tree.types.js → Menus.types.js} +0 -0
  99. /package/{display/Progress.svelte.d.ts → Progress.svelte.d.ts} +0 -0
  100. /package/{display/Progress.types.d.ts → Progress.types.d.ts} +0 -0
  101. /package/{display/Progress.types.js → Progress.types.js} +0 -0
  102. /package/{inputs/Radio.svelte.d.ts → Radio.svelte.d.ts} +0 -0
  103. /package/{inputs/Switch.svelte.d.ts → Switch.svelte.d.ts} +0 -0
  104. /package/{containers/Tabs.constants.d.ts → TabList.constants.d.ts} +0 -0
  105. /package/{containers/Tabs.constants.js → TabList.constants.js} +0 -0
  106. /package/{inputs/TextArea.types.js → TabList.types.js} +0 -0
  107. /package/{inputs/TextArea.svelte.d.ts → TextArea.svelte.d.ts} +0 -0
  108. /package/{inputs/TextArea.types.d.ts → TextArea.types.d.ts} +0 -0
  109. /package/{containers/TreeChevron.svelte.d.ts → TreeChevron.svelte.d.ts} +0 -0
  110. /package/{clickOutside.d.ts → actions/clickOutside.d.ts} +0 -0
package/List.svelte ADDED
@@ -0,0 +1,324 @@
1
+ <script>import { createKeyborg } from "keyborg";
2
+ import { createEventDispatcher, onMount, setContext } from "svelte";
3
+ import { writable } from "svelte/store";
4
+ import { v4 as uuid } from "uuid";
5
+ import Label from "./Label.svelte";
6
+ import { listContextKey } from "./List.constants";
7
+ export let composed = false;
8
+ export let disabled = false;
9
+ export let horizontal = false;
10
+ export let selectedValue = void 0;
11
+ const listId = `list-${uuid()}`;
12
+ let listRef;
13
+ let lastSelectedItemRef;
14
+ const disabledStore = writable(disabled);
15
+ const horizontalStore = writable(horizontal);
16
+ const selectedValueStore = writable(selectedValue);
17
+ $: {
18
+ disabledStore.set(disabled);
19
+ }
20
+ $: {
21
+ horizontalStore.set(horizontal);
22
+ }
23
+ $: {
24
+ selectedValueStore.set(selectedValue);
25
+ }
26
+ $: {
27
+ selectedValue = $selectedValueStore;
28
+ }
29
+ const dispatch = createEventDispatcher();
30
+ const raiseSelect = (value) => {
31
+ dispatch("select", { value });
32
+ };
33
+ $: {
34
+ raiseSelect(selectedValue);
35
+ }
36
+ let keyborg = createKeyborg(window);
37
+ let usingKeyboard = keyborg.isNavigatingWithKeyboard();
38
+ const keyborgHandler = (value) => {
39
+ usingKeyboard = value;
40
+ };
41
+ export const focus = () => {
42
+ listRef?.focus();
43
+ };
44
+ export const scrollToSelectedItem = () => {
45
+ const element = getSelectedItemElement();
46
+ element?.scrollIntoView({ block: "nearest", inline: "nearest" });
47
+ };
48
+ const isElementListItem = (candidate) => {
49
+ return candidate && candidate.getAttribute("data-value") !== null && candidate.getAttribute("data-value") !== void 0 && candidate.getAttribute("role") === "listitem";
50
+ };
51
+ const getSelectedItemElement = () => {
52
+ if (isElementListItem(lastSelectedItemRef) && lastSelectedItemRef?.getAttribute("data-value") === selectedValue && lastSelectedItemRef?.closest('[role="list"]') === listRef) {
53
+ return lastSelectedItemRef;
54
+ } else {
55
+ return listRef?.querySelector("[data-value][aria-selected=true]");
56
+ }
57
+ };
58
+ const selectItem = (value, element) => {
59
+ selectedValueStore.set(value);
60
+ lastSelectedItemRef = element;
61
+ element.scrollIntoView({ block: "nearest", inline: "nearest" });
62
+ };
63
+ export const selectFirstItem = () => {
64
+ let candidate = listRef?.firstElementChild;
65
+ while (candidate && !isElementListItem(candidate)) {
66
+ candidate = candidate.nextElementSibling;
67
+ }
68
+ let candidateValue = candidate?.getAttribute("data-value");
69
+ if (candidateValue && candidate) {
70
+ selectItem(candidateValue, candidate);
71
+ return true;
72
+ }
73
+ return false;
74
+ };
75
+ export const selectPreviousItem = () => {
76
+ let selectedItem = getSelectedItemElement();
77
+ let candidate = selectedItem?.previousElementSibling;
78
+ while (candidate && !isElementListItem(candidate)) {
79
+ candidate = candidate.previousElementSibling;
80
+ }
81
+ let candidateValue = candidate?.getAttribute("data-value");
82
+ if (candidateValue && candidate) {
83
+ selectItem(candidateValue, candidate);
84
+ return true;
85
+ }
86
+ return false;
87
+ };
88
+ export const selectNextItem = () => {
89
+ let selectedItem = getSelectedItemElement();
90
+ let candidate = selectedItem?.nextElementSibling;
91
+ while (candidate && !isElementListItem(candidate)) {
92
+ candidate = candidate.nextElementSibling;
93
+ }
94
+ let candidateValue = candidate?.getAttribute("data-value");
95
+ if (candidateValue && candidate) {
96
+ selectItem(candidateValue, candidate);
97
+ return true;
98
+ }
99
+ return false;
100
+ };
101
+ export const selectLastItem = () => {
102
+ let candidate = listRef?.lastElementChild;
103
+ while (candidate && !isElementListItem(candidate)) {
104
+ candidate = candidate.previousElementSibling;
105
+ }
106
+ let candidateValue = candidate?.getAttribute("data-value");
107
+ if (candidateValue && candidate) {
108
+ selectItem(candidateValue, candidate);
109
+ return true;
110
+ }
111
+ return false;
112
+ };
113
+ onMount(() => {
114
+ keyborg.subscribe(keyborgHandler);
115
+ return () => {
116
+ keyborg.unsubscribe(keyborgHandler);
117
+ };
118
+ });
119
+ const onClick = (event) => {
120
+ if (!disabled) {
121
+ let candidate = event.target;
122
+ let candidateValue = candidate?.getAttribute("data-value");
123
+ if (candidateValue === void 0 || candidateValue === null) {
124
+ candidate = candidate?.closest("[data-value]");
125
+ candidateValue = candidate?.getAttribute("data-value");
126
+ }
127
+ if (candidateValue && candidate) {
128
+ selectItem(candidateValue, candidate);
129
+ }
130
+ }
131
+ };
132
+ const onKeydown = (event) => {
133
+ if (!disabled && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) {
134
+ switch (event.key) {
135
+ case "Home":
136
+ selectFirstItem();
137
+ event.preventDefault();
138
+ event.stopPropagation();
139
+ return false;
140
+ case "End":
141
+ selectLastItem();
142
+ event.preventDefault();
143
+ event.stopPropagation();
144
+ return false;
145
+ case "ArrowLeft":
146
+ if (horizontal) {
147
+ selectedValue !== void 0 ? selectPreviousItem() : selectLastItem();
148
+ }
149
+ event.preventDefault();
150
+ event.stopPropagation();
151
+ return false;
152
+ case "ArrowRight":
153
+ if (horizontal) {
154
+ selectedValue !== void 0 ? selectNextItem() : selectFirstItem();
155
+ }
156
+ event.preventDefault();
157
+ event.stopPropagation();
158
+ return false;
159
+ case "ArrowUp":
160
+ if (!horizontal) {
161
+ selectedValue !== void 0 ? selectPreviousItem() : selectLastItem();
162
+ }
163
+ event.preventDefault();
164
+ event.stopPropagation();
165
+ return false;
166
+ case "ArrowDown":
167
+ if (!horizontal) {
168
+ selectedValue !== void 0 ? selectNextItem() : selectFirstItem();
169
+ }
170
+ event.preventDefault();
171
+ event.stopPropagation();
172
+ return false;
173
+ }
174
+ }
175
+ };
176
+ setContext(listContextKey, {
177
+ disabled: disabledStore,
178
+ selectedValue: selectedValueStore,
179
+ horizontal: horizontalStore
180
+ });
181
+ </script>
182
+
183
+ <!--
184
+ @component
185
+ A list of items where a single item can be selected.
186
+ -->
187
+ <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
188
+ <div
189
+ class="sterling-list"
190
+ class:horizontal
191
+ class:disabled
192
+ class:composed
193
+ class:using-keyboard={usingKeyboard}
194
+ >
195
+ {#if $$slots.label}
196
+ <Label {disabled} for={listId}>
197
+ <slot name="label" {composed} {disabled} {horizontal} {selectedValue} />
198
+ </Label>
199
+ {/if}
200
+ <div
201
+ aria-activedescendant={selectedValue}
202
+ aria-orientation={horizontal ? 'horizontal' : 'vertical'}
203
+ bind:this={listRef}
204
+ class="list"
205
+ class:disabled
206
+ class:horizontal
207
+ id={listId}
208
+ role="list"
209
+ tabindex={0}
210
+ on:blur
211
+ on:click
212
+ on:click={onClick}
213
+ on:copy
214
+ on:cut
215
+ on:dblclick
216
+ on:focus
217
+ on:focusin
218
+ on:focusout
219
+ on:keydown
220
+ on:keydown={onKeydown}
221
+ on:keypress
222
+ on:keyup
223
+ on:mousedown
224
+ on:mouseenter
225
+ on:mouseleave
226
+ on:mousemove
227
+ on:mouseover
228
+ on:mouseout
229
+ on:mouseup
230
+ on:scroll
231
+ on:wheel
232
+ on:paste
233
+ {...$$restProps}
234
+ >
235
+ <slot {composed} {disabled} {horizontal} {selectedValue} />
236
+ </div>
237
+ </div>
238
+
239
+ <style>
240
+ .sterling-list {
241
+ background-color: var(--stsv-Common__background-color);
242
+ border-color: var(--stsv-Common__border-color);
243
+ border-radius: var(--stsv-Common__border-radius);
244
+ border-style: var(--stsv-Common__border-style);
245
+ border-width: var(--stsv-Common__border-width);
246
+ box-sizing: border-box;
247
+ color: var(--stsv-Common__color);
248
+ display: grid;
249
+ grid-template-columns: 1fr;
250
+ grid-template-rows: auto 1fr;
251
+ height: 100%;
252
+ margin: 0;
253
+ overflow: hidden;
254
+ padding: 0;
255
+ transition: background-color 250ms, color 250ms, border-color 250ms;
256
+ }
257
+
258
+ .sterling-list.horizontal {
259
+ height: unset;
260
+ width: 100%;
261
+ }
262
+
263
+ .sterling-list:hover {
264
+ border-color: var(--stsv-Common__border-color--hover);
265
+ color: var(--stsv-Common__color--hover);
266
+ }
267
+
268
+ .sterling-list.using-keyboard:focus-within {
269
+ border-color: var(--stsv-Common__border-color--focus);
270
+ color: var(--stsv-Common__color--focus);
271
+ outline-color: var(--stsv-Common__outline-color);
272
+ outline-offset: var(--stsv-Common__outline-offset);
273
+ outline-style: var(--stsv-Common__outline-style);
274
+ outline-width: var(--stsv-Common__outline-width);
275
+ }
276
+
277
+ .sterling-list.disabled {
278
+ background-color: var(--stsv-Common__background-color--disabled);
279
+ border-color: var(--stsv--Common__border-color--disabled);
280
+ color: var(--stsv-Common__color--disabled);
281
+ cursor: not-allowed;
282
+ }
283
+
284
+ .sterling-list.composed,
285
+ .sterling-list:hover.composed,
286
+ .sterling-list:focus-visible.composed,
287
+ .sterling-list.disabled.composed {
288
+ background: none;
289
+ border: none;
290
+ outline: none;
291
+ }
292
+
293
+ .list {
294
+ display: flex;
295
+ flex-direction: column;
296
+ flex-wrap: nowrap;
297
+ grid-row: 2 / span 1;
298
+ overflow-x: hidden;
299
+ overflow-y: scroll;
300
+ outline: none;
301
+ position: relative;
302
+ }
303
+
304
+ .list.horizontal {
305
+ flex-direction: row;
306
+ overflow-x: scroll;
307
+ overflow-y: hidden;
308
+ }
309
+
310
+ .sterling-list > :global(label) {
311
+ font-size: 0.7em;
312
+ margin: 0.5em 0.7em;
313
+ }
314
+
315
+ .sterling-list > :global(label):empty {
316
+ margin: 0;
317
+ }
318
+
319
+ @media (prefers-reduced-motion) {
320
+ .sterling-list {
321
+ transition: none;
322
+ }
323
+ }
324
+ </style>
@@ -0,0 +1,69 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ [x: string]: any;
5
+ composed?: boolean | undefined;
6
+ disabled?: boolean | undefined;
7
+ horizontal?: boolean | undefined;
8
+ selectedValue?: string | undefined;
9
+ focus?: (() => void) | undefined;
10
+ scrollToSelectedItem?: (() => void) | undefined;
11
+ selectFirstItem?: (() => boolean) | undefined;
12
+ selectPreviousItem?: (() => boolean) | undefined;
13
+ selectNextItem?: (() => boolean) | undefined;
14
+ selectLastItem?: (() => boolean) | undefined;
15
+ };
16
+ events: {
17
+ blur: FocusEvent;
18
+ click: MouseEvent;
19
+ copy: ClipboardEvent;
20
+ cut: ClipboardEvent;
21
+ dblclick: MouseEvent;
22
+ focus: FocusEvent;
23
+ focusin: FocusEvent;
24
+ focusout: FocusEvent;
25
+ keydown: KeyboardEvent;
26
+ keypress: KeyboardEvent;
27
+ keyup: KeyboardEvent;
28
+ mousedown: MouseEvent;
29
+ mouseenter: MouseEvent;
30
+ mouseleave: MouseEvent;
31
+ mousemove: MouseEvent;
32
+ mouseover: MouseEvent;
33
+ mouseout: MouseEvent;
34
+ mouseup: MouseEvent;
35
+ scroll: Event;
36
+ wheel: WheelEvent;
37
+ paste: ClipboardEvent;
38
+ select: CustomEvent<any>;
39
+ } & {
40
+ [evt: string]: CustomEvent<any>;
41
+ };
42
+ slots: {
43
+ label: {
44
+ composed: boolean;
45
+ disabled: boolean;
46
+ horizontal: boolean;
47
+ selectedValue: string | undefined;
48
+ };
49
+ default: {
50
+ composed: boolean;
51
+ disabled: boolean;
52
+ horizontal: boolean;
53
+ selectedValue: string | undefined;
54
+ };
55
+ };
56
+ };
57
+ export type ListProps = typeof __propDef.props;
58
+ export type ListEvents = typeof __propDef.events;
59
+ export type ListSlots = typeof __propDef.slots;
60
+ /** A list of items where a single item can be selected. */
61
+ export default class List extends SvelteComponentTyped<ListProps, ListEvents, ListSlots> {
62
+ get focus(): () => void;
63
+ get scrollToSelectedItem(): () => void;
64
+ get selectFirstItem(): () => boolean;
65
+ get selectPreviousItem(): () => boolean;
66
+ get selectNextItem(): () => boolean;
67
+ get selectLastItem(): () => boolean;
68
+ }
69
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { Readable, Writable } from 'svelte/store';
2
+ export type ListContext = {
3
+ disabled: Readable<boolean>;
4
+ selectedValue: Writable<string | undefined>;
5
+ horizontal: Readable<boolean>;
6
+ };
@@ -0,0 +1,90 @@
1
+ <script>import { getContext } from "svelte";
2
+ import { v4 as uuid } from "uuid";
3
+ import { listContextKey } from "./List.constants";
4
+ export let disabled = false;
5
+ export let value;
6
+ const {
7
+ disabled: listDisabled,
8
+ selectedValue,
9
+ horizontal
10
+ } = getContext(listContextKey);
11
+ let itemRef;
12
+ $:
13
+ _disabled = disabled || $listDisabled;
14
+ $:
15
+ selected = $selectedValue === value;
16
+ </script>
17
+
18
+ <div
19
+ aria-selected={selected}
20
+ bind:this={itemRef}
21
+ class="sterling-list-item"
22
+ class:disabled={_disabled}
23
+ class:selected
24
+ data-value={value}
25
+ role="listitem"
26
+ on:blur
27
+ on:click
28
+ on:dblclick
29
+ on:focus
30
+ on:focusin
31
+ on:focusout
32
+ on:keydown
33
+ on:keypress
34
+ on:keyup
35
+ on:mousedown
36
+ on:mouseenter
37
+ on:mouseleave
38
+ on:mousemove
39
+ on:mouseover
40
+ on:mouseout
41
+ on:mouseup
42
+ on:pointercancel
43
+ on:pointerdown
44
+ on:pointerenter
45
+ on:pointerleave
46
+ on:pointermove
47
+ on:pointerover
48
+ on:pointerout
49
+ on:pointerup
50
+ on:wheel
51
+ {...$$restProps}
52
+ >
53
+ <slot {disabled} {horizontal} {selected} {value}>{value}</slot>
54
+ </div>
55
+
56
+ <style>
57
+ .sterling-list-item {
58
+ background-color: transparent;
59
+ box-sizing: border-box;
60
+ color: var(--stsv-Input__color);
61
+ cursor: pointer;
62
+ margin: 0;
63
+ padding: 0.5em;
64
+ outline: none;
65
+ text-overflow: ellipsis;
66
+ transition: background-color 250ms, color 250ms, border-color 250ms;
67
+ white-space: nowrap;
68
+ }
69
+
70
+ .sterling-list-item:not(.disabled):hover {
71
+ background-color: var(--stsv-Button__background-color--hover);
72
+ color: var(--stsv-Button__color--hover);
73
+ }
74
+
75
+ .sterling-list-item.selected {
76
+ background-color: var(--stsv-Input__background-color--selected);
77
+ color: var(--stsv-Input__color--selected);
78
+ }
79
+
80
+ .sterling-list-item.disabled {
81
+ color: var(--stsv-Common__color--disabled);
82
+ cursor: not-allowed;
83
+ }
84
+
85
+ @media (prefers-reduced-motion) {
86
+ .sterling-list-item {
87
+ transition: none;
88
+ }
89
+ }
90
+ </style>
@@ -0,0 +1,51 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ [x: string]: any;
5
+ disabled?: boolean | undefined;
6
+ value: string;
7
+ };
8
+ events: {
9
+ blur: FocusEvent;
10
+ click: MouseEvent;
11
+ dblclick: MouseEvent;
12
+ focus: FocusEvent;
13
+ focusin: FocusEvent;
14
+ focusout: FocusEvent;
15
+ keydown: KeyboardEvent;
16
+ keypress: KeyboardEvent;
17
+ keyup: KeyboardEvent;
18
+ mousedown: MouseEvent;
19
+ mouseenter: MouseEvent;
20
+ mouseleave: MouseEvent;
21
+ mousemove: MouseEvent;
22
+ mouseover: MouseEvent;
23
+ mouseout: MouseEvent;
24
+ mouseup: MouseEvent;
25
+ pointercancel: PointerEvent;
26
+ pointerdown: PointerEvent;
27
+ pointerenter: PointerEvent;
28
+ pointerleave: PointerEvent;
29
+ pointermove: PointerEvent;
30
+ pointerover: PointerEvent;
31
+ pointerout: PointerEvent;
32
+ pointerup: PointerEvent;
33
+ wheel: WheelEvent;
34
+ } & {
35
+ [evt: string]: CustomEvent<any>;
36
+ };
37
+ slots: {
38
+ default: {
39
+ disabled: boolean;
40
+ horizontal: import("svelte/store").Readable<boolean>;
41
+ selected: boolean;
42
+ value: string;
43
+ };
44
+ };
45
+ };
46
+ export type ListItemProps = typeof __propDef.props;
47
+ export type ListItemEvents = typeof __propDef.events;
48
+ export type ListItemSlots = typeof __propDef.slots;
49
+ export default class ListItem extends SvelteComponentTyped<ListItemProps, ListItemEvents, ListItemSlots> {
50
+ }
51
+ export {};
package/Menu.svelte ADDED
@@ -0,0 +1,115 @@
1
+ <script>import { getContext, onMount } from "svelte";
2
+ import { autoUpdate, computePosition, flip, offset, shift } from "@floating-ui/dom";
3
+ import { portal } from "./actions/portal";
4
+ import { menuItemContextKey } from "./Menus.constants";
5
+ export let reference;
6
+ export let open = false;
7
+ let menuRef;
8
+ let menuPosition = { x: 0, y: 0 };
9
+ const { rootValue, depth = 0 } = getContext(menuItemContextKey) || {};
10
+ const ensurePortalHost = () => {
11
+ let host = document.querySelector("#SterlingMenuPortal");
12
+ if (!host) {
13
+ host = document.createElement("div");
14
+ host.id = "SterlingMenuPortal";
15
+ host.style.overflow = "visible";
16
+ document.body.append(host);
17
+ }
18
+ return host;
19
+ };
20
+ const portalTarget = ensurePortalHost();
21
+ let bodyHeight = 0;
22
+ const resizeObserver = new ResizeObserver((entries) => {
23
+ bodyHeight = entries[0].target.clientHeight;
24
+ });
25
+ const menuPlacement = depth > 1 ? "right-start" : "bottom-start";
26
+ const middleware = [
27
+ offset({ mainAxis: -2 }),
28
+ flip(),
29
+ shift({ padding: 0, mainAxis: true, crossAxis: true })
30
+ ];
31
+ const computeMenuPosition = async () => {
32
+ if (reference && menuRef) {
33
+ menuPosition = await computePosition(reference, menuRef, {
34
+ placement: menuPlacement,
35
+ middleware
36
+ });
37
+ } else {
38
+ menuPosition = { x: 0, y: 0 };
39
+ }
40
+ };
41
+ let cleanupAutoUpdate = () => {
42
+ };
43
+ const autoUpdateMenuPosition = () => {
44
+ cleanupAutoUpdate();
45
+ if (reference && menuRef) {
46
+ cleanupAutoUpdate = autoUpdate(reference, menuRef, computeMenuPosition);
47
+ }
48
+ };
49
+ $:
50
+ menuRef, reference, autoUpdateMenuPosition();
51
+ $:
52
+ open, bodyHeight, computeMenuPosition();
53
+ onMount(() => {
54
+ resizeObserver.observe(document.body);
55
+ return () => {
56
+ resizeObserver.unobserve(document.body);
57
+ };
58
+ });
59
+ </script>
60
+
61
+ {#if open}
62
+ <div
63
+ class="sterling-menu-portal"
64
+ data-root-value={rootValue}
65
+ use:portal={{ target: portalTarget }}
66
+ >
67
+ <div
68
+ bind:this={menuRef}
69
+ class="sterling-menu"
70
+ role="menu"
71
+ class:open
72
+ {...$$restProps}
73
+ style="left:{menuPosition.x}px; top:{menuPosition.y}px"
74
+ >
75
+ <slot />
76
+ </div>
77
+ </div>
78
+ {/if}
79
+
80
+ <style>
81
+ .sterling-menu-portal {
82
+ position: relative;
83
+ overflow: visible;
84
+ background: rgba(255, 0, 0, 0.1);
85
+ }
86
+
87
+ .sterling-menu {
88
+ background-color: var(--stsv-Common__background-color);
89
+ border-color: var(--stsv-Common__border-color);
90
+ border-radius: var(--stsv-Common__border-radius);
91
+ border-style: var(--stsv-Common__border-style);
92
+ border-width: var(--stsv-Common__border-width);
93
+ box-sizing: border-box;
94
+ position: absolute;
95
+ box-shadow: rgba(0, 0, 0, 0.4) 2px 2px 4px -1px;
96
+ overflow: hidden;
97
+ width: max-content;
98
+ height: fit-content;
99
+ z-index: 1;
100
+ top: 0;
101
+ left: 0;
102
+
103
+ display: grid;
104
+ grid-template-columns: 1fr;
105
+ grid-template-rows: auto;
106
+ row-gap: calc(2 * var(--stsv-Common__outline-width));
107
+ padding: 0.25em;
108
+ }
109
+
110
+ .sterling-menu.open {
111
+ display: grid;
112
+ grid-template-columns: 1fr;
113
+ grid-template-rows: 1fr;
114
+ }
115
+ </style>
@@ -0,0 +1,20 @@
1
+ import { SvelteComponentTyped } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ [x: string]: any;
5
+ reference: HTMLElement;
6
+ open?: boolean | undefined;
7
+ };
8
+ events: {
9
+ [evt: string]: CustomEvent<any>;
10
+ };
11
+ slots: {
12
+ default: {};
13
+ };
14
+ };
15
+ export type MenuProps = typeof __propDef.props;
16
+ export type MenuEvents = typeof __propDef.events;
17
+ export type MenuSlots = typeof __propDef.slots;
18
+ export default class Menu extends SvelteComponentTyped<MenuProps, MenuEvents, MenuSlots> {
19
+ }
20
+ export {};