@geoffcox/sterling-svelte 0.0.25 → 0.0.26
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/Dropdown.svelte +9 -0
- package/Field.svelte +3 -15
- package/List.svelte +3 -14
- package/Menu.svelte +86 -115
- package/Menu.svelte.d.ts +8 -2
- package/MenuBar.svelte +76 -31
- package/MenuBar.types.d.ts +2 -2
- package/MenuButton.svelte +50 -28
- package/MenuItem.constants.d.ts +1 -0
- package/MenuItem.constants.js +1 -0
- package/MenuItem.svelte +169 -128
- package/MenuItem.svelte.d.ts +6 -3
- package/MenuItem.types.d.ts +14 -5
- package/MenuItem.utils.d.ts +2 -0
- package/MenuItem.utils.js +16 -0
- package/MenuItemDisplay.svelte +2 -1
- package/MenuItemDisplay.svelte.d.ts +1 -0
- package/Popover.svelte +3 -14
- package/Select.svelte +25 -13
- package/Tab.svelte +1 -1
- package/TabList.svelte +2 -18
- package/TabList.types.d.ts +0 -1
- package/Tree.svelte +3 -14
- package/TreeItem.svelte +7 -1
- package/index.d.ts +2 -2
- package/index.js +1 -1
- package/package.json +3 -1
- package/stores/prefersReducedMotion.d.ts +1 -0
- package/stores/prefersReducedMotion.js +10 -0
- package/stores/usingKeyboard.d.ts +1 -0
- package/stores/usingKeyboard.js +13 -0
package/MenuItem.svelte
CHANGED
|
@@ -1,50 +1,60 @@
|
|
|
1
|
-
<script>import {
|
|
2
|
-
|
|
1
|
+
<script>import {
|
|
2
|
+
getContext,
|
|
3
|
+
afterUpdate,
|
|
4
|
+
createEventDispatcher,
|
|
5
|
+
onMount,
|
|
6
|
+
setContext,
|
|
7
|
+
tick
|
|
8
|
+
} from "svelte";
|
|
3
9
|
import { writable } from "svelte/store";
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import MenuItemDisplay from "./MenuItemDisplay.svelte";
|
|
10
|
+
import { idGenerator } from "./idGenerator";
|
|
11
|
+
import Menu from "./Menu.svelte";
|
|
7
12
|
import { MENU_BAR_CONTEXT_KEY } from "./MenuBar.constants";
|
|
8
13
|
import { MENU_ITEM_CONTEXT_KEY } from "./MenuItem.constants";
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
focusNextChild,
|
|
14
|
-
focusPreviousChild
|
|
15
|
-
} from "./MenuItem.utils";
|
|
16
|
-
import { idGenerator } from "./idGenerator";
|
|
14
|
+
import { isElementEnabledMenuItem } from "./MenuItem.utils";
|
|
15
|
+
import MenuItemDisplay from "./MenuItemDisplay.svelte";
|
|
16
|
+
import Popover from "./Popover.svelte";
|
|
17
|
+
import { usingKeyboard } from "./stores/usingKeyboard";
|
|
17
18
|
export let checked = false;
|
|
18
19
|
export let composed = false;
|
|
19
20
|
export let disabled = false;
|
|
20
|
-
export let open = false;
|
|
21
21
|
export let value;
|
|
22
22
|
export let role = "menuitem";
|
|
23
23
|
export let text = void 0;
|
|
24
24
|
const {
|
|
25
|
+
isMenuBarItem,
|
|
26
|
+
openValues = writable([]),
|
|
25
27
|
rootValue = value,
|
|
26
28
|
depth = 0,
|
|
27
|
-
|
|
28
|
-
unregister = void 0,
|
|
29
|
-
closeMenu = void 0,
|
|
30
|
-
focusPrevious = void 0,
|
|
31
|
-
focusNext = void 0,
|
|
29
|
+
closeContainingMenu = void 0,
|
|
32
30
|
onOpen = void 0,
|
|
33
31
|
onClose = void 0,
|
|
34
32
|
onSelect = void 0
|
|
35
33
|
} = getContext(MENU_ITEM_CONTEXT_KEY) || {};
|
|
36
|
-
const {
|
|
34
|
+
const { openPreviousMenuBarItem = void 0, openNextMenuBarItem = void 0 } = getContext(MENU_BAR_CONTEXT_KEY) || {};
|
|
37
35
|
const instanceId = idGenerator.nextId("MenuItem");
|
|
38
36
|
$:
|
|
39
37
|
displayId = `${value}-display-${instanceId}`;
|
|
38
|
+
$:
|
|
39
|
+
open = $openValues.includes(value);
|
|
40
40
|
$:
|
|
41
41
|
menuId = `${value}-menu-${instanceId}`;
|
|
42
42
|
let menuItemRef;
|
|
43
|
+
let menuRef;
|
|
43
44
|
const children = writable([]);
|
|
44
45
|
let mounted = false;
|
|
45
46
|
let prevOpen = open;
|
|
46
47
|
$:
|
|
47
48
|
hasChildren = $$slots.default;
|
|
49
|
+
export const blur = () => {
|
|
50
|
+
menuItemRef?.blur();
|
|
51
|
+
};
|
|
52
|
+
export const click = () => {
|
|
53
|
+
menuItemRef?.click();
|
|
54
|
+
};
|
|
55
|
+
export const focus = (options) => {
|
|
56
|
+
menuItemRef?.focus(options);
|
|
57
|
+
};
|
|
48
58
|
const dispatch = createEventDispatcher();
|
|
49
59
|
const raiseClose = (value2) => {
|
|
50
60
|
dispatch("close", { value: value2 });
|
|
@@ -64,157 +74,176 @@ const raiseSelect = (value2) => {
|
|
|
64
74
|
dispatch("select", { value: value2 });
|
|
65
75
|
onSelect?.(value2);
|
|
66
76
|
};
|
|
67
|
-
|
|
68
|
-
let
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
const focusPreviousMenuItem = () => {
|
|
78
|
+
let candidate = menuItemRef?.previousElementSibling || menuItemRef?.parentElement?.lastElementChild;
|
|
79
|
+
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
80
|
+
candidate = candidate.previousElementSibling || menuItemRef?.parentElement?.lastElementChild;
|
|
81
|
+
if (candidate === menuItemRef) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
candidate?.focus();
|
|
86
|
+
return !!candidate;
|
|
71
87
|
};
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
88
|
+
const focusNextMenuItem = () => {
|
|
89
|
+
let candidate = menuItemRef?.nextElementSibling || menuItemRef?.parentElement?.firstElementChild;
|
|
90
|
+
while (candidate && !isElementEnabledMenuItem(candidate)) {
|
|
91
|
+
candidate = candidate.nextElementSibling || menuItemRef?.parentElement?.firstElementChild;
|
|
92
|
+
if (candidate === menuItemRef) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
75
95
|
}
|
|
96
|
+
candidate?.focus();
|
|
97
|
+
return !!candidate;
|
|
76
98
|
};
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
99
|
+
const openMenu = () => {
|
|
100
|
+
if (!$openValues.includes(value)) {
|
|
101
|
+
openValues.set([...$openValues.slice(0, depth), value]);
|
|
102
|
+
}
|
|
81
103
|
};
|
|
82
|
-
|
|
83
|
-
|
|
104
|
+
const closeMenu = async () => {
|
|
105
|
+
const index = $openValues.indexOf(value);
|
|
106
|
+
if (index !== -1) {
|
|
107
|
+
openValues.set([...$openValues.slice(0, index)]);
|
|
108
|
+
await tick();
|
|
109
|
+
menuItemRef?.focus();
|
|
110
|
+
}
|
|
84
111
|
};
|
|
85
|
-
|
|
86
|
-
|
|
112
|
+
const closeAllMenus = () => {
|
|
113
|
+
openValues.set([]);
|
|
87
114
|
};
|
|
88
115
|
onMount(() => {
|
|
89
116
|
mounted = true;
|
|
90
|
-
keyborg.subscribe(keyborgHandler);
|
|
91
|
-
const menuItemSelf = {
|
|
92
|
-
value,
|
|
93
|
-
open: () => {
|
|
94
|
-
open = true;
|
|
95
|
-
},
|
|
96
|
-
close: () => {
|
|
97
|
-
open = false;
|
|
98
|
-
},
|
|
99
|
-
focus: () => {
|
|
100
|
-
menuItemRef?.focus();
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
register?.(menuItemSelf);
|
|
104
|
-
return () => {
|
|
105
|
-
keyborg.unsubscribe(keyborgHandler);
|
|
106
|
-
unregister?.(menuItemSelf);
|
|
107
|
-
};
|
|
108
117
|
});
|
|
109
118
|
afterUpdate(() => {
|
|
110
119
|
prevOpen = open;
|
|
111
120
|
});
|
|
112
|
-
const onKeyDown = (event) => {
|
|
121
|
+
const onKeyDown = async (event) => {
|
|
113
122
|
if (!disabled && !event.altKey && !event.ctrlKey && !event.shiftKey) {
|
|
114
123
|
switch (event.key) {
|
|
115
124
|
case "ArrowDown":
|
|
116
|
-
if (
|
|
117
|
-
|
|
118
|
-
setTimeout(() =>
|
|
125
|
+
if (isMenuBarItem && hasChildren) {
|
|
126
|
+
openMenu();
|
|
127
|
+
setTimeout(async () => {
|
|
128
|
+
await tick();
|
|
129
|
+
menuRef?.focusFirstMenuItem();
|
|
130
|
+
}, 10);
|
|
119
131
|
event.preventDefault();
|
|
132
|
+
event.stopPropagation();
|
|
120
133
|
return false;
|
|
121
|
-
}
|
|
122
|
-
|
|
134
|
+
}
|
|
135
|
+
if (!isMenuBarItem) {
|
|
136
|
+
focusNextMenuItem();
|
|
123
137
|
event.preventDefault();
|
|
138
|
+
event.stopPropagation();
|
|
124
139
|
return false;
|
|
125
140
|
}
|
|
126
141
|
break;
|
|
127
142
|
case "ArrowLeft":
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
143
|
+
if (isMenuBarItem) {
|
|
144
|
+
focusPreviousMenuItem();
|
|
145
|
+
event.preventDefault();
|
|
146
|
+
event.stopPropagation();
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
if (depth > 1) {
|
|
150
|
+
closeContainingMenu?.();
|
|
151
|
+
event.preventDefault();
|
|
152
|
+
event.stopPropagation();
|
|
153
|
+
return false;
|
|
134
154
|
}
|
|
155
|
+
openPreviousMenuBarItem?.();
|
|
135
156
|
event.preventDefault();
|
|
157
|
+
event.stopPropagation();
|
|
136
158
|
return false;
|
|
137
159
|
case "ArrowRight":
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
closeMenu?.(true);
|
|
144
|
-
openNextMenu?.(rootValue);
|
|
160
|
+
if (isMenuBarItem) {
|
|
161
|
+
focusNextMenuItem();
|
|
162
|
+
event.preventDefault();
|
|
163
|
+
event.stopPropagation();
|
|
164
|
+
return false;
|
|
145
165
|
}
|
|
146
|
-
|
|
147
|
-
|
|
166
|
+
if (hasChildren) {
|
|
167
|
+
openMenu();
|
|
168
|
+
setTimeout(async () => {
|
|
169
|
+
await tick();
|
|
170
|
+
menuRef?.focusFirstMenuItem();
|
|
171
|
+
}, 10);
|
|
172
|
+
event.preventDefault();
|
|
173
|
+
event.stopPropagation();
|
|
174
|
+
return false;
|
|
175
|
+
}
|
|
176
|
+
if (openNextMenuBarItem) {
|
|
177
|
+
openNextMenuBarItem();
|
|
178
|
+
event.preventDefault();
|
|
179
|
+
event.stopPropagation();
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
148
183
|
case "ArrowUp":
|
|
149
|
-
if (
|
|
150
|
-
|
|
151
|
-
setTimeout(() =>
|
|
184
|
+
if (isMenuBarItem && hasChildren) {
|
|
185
|
+
openMenu();
|
|
186
|
+
setTimeout(async () => {
|
|
187
|
+
await tick();
|
|
188
|
+
menuRef?.focusLastMenuItem();
|
|
189
|
+
}, 10);
|
|
152
190
|
event.preventDefault();
|
|
191
|
+
event.stopPropagation();
|
|
153
192
|
return false;
|
|
154
|
-
}
|
|
155
|
-
|
|
193
|
+
}
|
|
194
|
+
if (!isMenuBarItem) {
|
|
195
|
+
focusPreviousMenuItem();
|
|
156
196
|
event.preventDefault();
|
|
197
|
+
event.stopPropagation();
|
|
157
198
|
return false;
|
|
158
199
|
}
|
|
200
|
+
break;
|
|
159
201
|
case "Escape":
|
|
160
202
|
open = false;
|
|
161
|
-
|
|
203
|
+
closeAllMenus();
|
|
162
204
|
event.preventDefault();
|
|
205
|
+
event.stopPropagation();
|
|
163
206
|
return false;
|
|
164
207
|
}
|
|
165
208
|
}
|
|
166
209
|
};
|
|
167
210
|
const onMouseEnter = (event) => {
|
|
168
|
-
|
|
169
|
-
menuItemRef?.focus();
|
|
170
|
-
}, 10);
|
|
211
|
+
menuItemRef?.focus();
|
|
171
212
|
};
|
|
172
|
-
const
|
|
213
|
+
const onClick = (event) => {
|
|
173
214
|
if (!disabled) {
|
|
174
215
|
if (hasChildren) {
|
|
175
|
-
|
|
216
|
+
if (!$openValues.includes(value)) {
|
|
217
|
+
openMenu();
|
|
218
|
+
if ($usingKeyboard) {
|
|
219
|
+
setTimeout(async () => {
|
|
220
|
+
await tick();
|
|
221
|
+
menuRef?.focusFirstMenuItem();
|
|
222
|
+
}, 10);
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
closeMenu();
|
|
226
|
+
}
|
|
176
227
|
event.preventDefault();
|
|
177
228
|
event.stopPropagation();
|
|
178
229
|
return false;
|
|
179
230
|
} else {
|
|
180
231
|
raiseSelect(value);
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const onClickOutside = (event) => {
|
|
186
|
-
const {
|
|
187
|
-
detail: { mouseEvent }
|
|
188
|
-
} = event;
|
|
189
|
-
let element = mouseEvent.target;
|
|
190
|
-
while (element) {
|
|
191
|
-
if (element.getAttribute("data-root-value") === rootValue) {
|
|
192
|
-
return;
|
|
232
|
+
closeAllMenus();
|
|
233
|
+
event.preventDefault();
|
|
234
|
+
event.stopPropagation();
|
|
235
|
+
return false;
|
|
193
236
|
}
|
|
194
|
-
element = element.parentElement;
|
|
195
237
|
}
|
|
196
|
-
closeMenu?.(true);
|
|
197
238
|
};
|
|
198
239
|
setContext(MENU_ITEM_CONTEXT_KEY, {
|
|
240
|
+
isMenuBarItem: false,
|
|
241
|
+
openValues,
|
|
199
242
|
rootValue,
|
|
200
243
|
depth: depth + 1,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
},
|
|
204
|
-
unregister: (menuItem) => {
|
|
205
|
-
children.set($children.filter((x) => x.value !== menuItem.value));
|
|
206
|
-
},
|
|
207
|
-
closeMenu: (recursive) => {
|
|
208
|
-
open = false;
|
|
209
|
-
if (recursive) {
|
|
210
|
-
closeMenu?.(recursive);
|
|
211
|
-
}
|
|
212
|
-
if (!recursive || depth === 0) {
|
|
213
|
-
menuItemRef?.focus();
|
|
214
|
-
}
|
|
244
|
+
closeContainingMenu: () => {
|
|
245
|
+
closeMenu();
|
|
215
246
|
},
|
|
216
|
-
focusPrevious: (currentValue) => focusPreviousChild($children, currentValue),
|
|
217
|
-
focusNext: (currentValue) => focusNextChild($children, currentValue),
|
|
218
247
|
onOpen: raiseOpen,
|
|
219
248
|
onClose: raiseClose,
|
|
220
249
|
onSelect: raiseSelect
|
|
@@ -230,14 +259,13 @@ setContext(MENU_ITEM_CONTEXT_KEY, {
|
|
|
230
259
|
bind:this={menuItemRef}
|
|
231
260
|
class="sterling-menu-item"
|
|
232
261
|
class:composed
|
|
233
|
-
class:disabled
|
|
234
262
|
class:using-keyboard={usingKeyboard}
|
|
235
263
|
data-value={value}
|
|
236
264
|
data-root-value={rootValue}
|
|
265
|
+
{disabled}
|
|
237
266
|
{role}
|
|
238
267
|
tabindex={0}
|
|
239
268
|
type="button"
|
|
240
|
-
use:clickOutside
|
|
241
269
|
on:blur
|
|
242
270
|
on:click
|
|
243
271
|
on:dblclick
|
|
@@ -269,26 +297,39 @@ setContext(MENU_ITEM_CONTEXT_KEY, {
|
|
|
269
297
|
on:pointerout
|
|
270
298
|
on:pointerup
|
|
271
299
|
on:wheel
|
|
272
|
-
on:click={
|
|
273
|
-
on:click_outside={onClickOutside}
|
|
300
|
+
on:click={onClick}
|
|
274
301
|
on:keydown={onKeyDown}
|
|
275
302
|
on:mouseenter={onMouseEnter}
|
|
276
303
|
{...$$restProps}
|
|
277
304
|
>
|
|
278
305
|
<div class="item" id={displayId}>
|
|
279
|
-
<slot
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
306
|
+
<slot
|
|
307
|
+
name="item"
|
|
308
|
+
{checked}
|
|
309
|
+
{depth}
|
|
310
|
+
{disabled}
|
|
311
|
+
{hasChildren}
|
|
312
|
+
{isMenuBarItem}
|
|
313
|
+
{open}
|
|
314
|
+
{role}
|
|
315
|
+
{text}
|
|
316
|
+
{value}
|
|
317
|
+
>
|
|
318
|
+
<MenuItemDisplay {checked} {disabled} {hasChildren} {isMenuBarItem} menuItemRole={role}
|
|
319
|
+
>{text}</MenuItemDisplay
|
|
285
320
|
>
|
|
286
321
|
</slot>
|
|
287
322
|
</div>
|
|
288
323
|
{#if menuItemRef && open && hasChildren}
|
|
289
|
-
<
|
|
290
|
-
|
|
291
|
-
|
|
324
|
+
<Popover
|
|
325
|
+
reference={menuItemRef}
|
|
326
|
+
placement={isMenuBarItem ? 'bottom-start' : 'right-start'}
|
|
327
|
+
{open}
|
|
328
|
+
>
|
|
329
|
+
<Menu bind:this={menuRef} id={menuId}>
|
|
330
|
+
<slot {depth} {disabled} />
|
|
331
|
+
</Menu>
|
|
332
|
+
</Popover>
|
|
292
333
|
{/if}
|
|
293
334
|
</button>
|
|
294
335
|
|
package/MenuItem.svelte.d.ts
CHANGED
|
@@ -5,12 +5,11 @@ declare const __propDef: {
|
|
|
5
5
|
checked?: boolean | undefined;
|
|
6
6
|
composed?: boolean | undefined;
|
|
7
7
|
disabled?: boolean | undefined;
|
|
8
|
-
open?: boolean | undefined;
|
|
9
8
|
value: string;
|
|
10
9
|
role?: "menuitem" | "menuitemcheckbox" | "menuitemradio" | undefined;
|
|
11
10
|
text?: string | undefined;
|
|
12
|
-
click?: (() => void) | undefined;
|
|
13
11
|
blur?: (() => void) | undefined;
|
|
12
|
+
click?: (() => void) | undefined;
|
|
14
13
|
focus?: ((options?: FocusOptions) => void) | undefined;
|
|
15
14
|
};
|
|
16
15
|
events: {
|
|
@@ -45,6 +44,9 @@ declare const __propDef: {
|
|
|
45
44
|
pointerout: PointerEvent;
|
|
46
45
|
pointerup: PointerEvent;
|
|
47
46
|
wheel: WheelEvent;
|
|
47
|
+
close: CustomEvent<any>;
|
|
48
|
+
open: CustomEvent<any>;
|
|
49
|
+
select: CustomEvent<any>;
|
|
48
50
|
} & {
|
|
49
51
|
[evt: string]: CustomEvent<any>;
|
|
50
52
|
};
|
|
@@ -54,6 +56,7 @@ declare const __propDef: {
|
|
|
54
56
|
depth: number;
|
|
55
57
|
disabled: boolean;
|
|
56
58
|
hasChildren: boolean;
|
|
59
|
+
isMenuBarItem: boolean | undefined;
|
|
57
60
|
open: boolean;
|
|
58
61
|
role: "menuitem" | "menuitemcheckbox" | "menuitemradio";
|
|
59
62
|
text: string | undefined;
|
|
@@ -69,8 +72,8 @@ export type MenuItemProps = typeof __propDef.props;
|
|
|
69
72
|
export type MenuItemEvents = typeof __propDef.events;
|
|
70
73
|
export type MenuItemSlots = typeof __propDef.slots;
|
|
71
74
|
export default class MenuItem extends SvelteComponentTyped<MenuItemProps, MenuItemEvents, MenuItemSlots> {
|
|
72
|
-
get click(): () => void;
|
|
73
75
|
get blur(): () => void;
|
|
76
|
+
get click(): () => void;
|
|
74
77
|
get focus(): (options?: FocusOptions | undefined) => void;
|
|
75
78
|
}
|
|
76
79
|
export {};
|
package/MenuItem.types.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import type { Writable } from 'svelte/store';
|
|
2
|
+
import type { MENU_ITEM_ROLES } from './MenuItem.constants';
|
|
3
|
+
type MenuItemRoleTuple = typeof MENU_ITEM_ROLES;
|
|
4
|
+
export type MenuItemRole = MenuItemRoleTuple[number];
|
|
1
5
|
export type MenuItemRegistration = {
|
|
2
6
|
value: string;
|
|
3
7
|
open: () => void;
|
|
@@ -5,14 +9,19 @@ export type MenuItemRegistration = {
|
|
|
5
9
|
focus: () => void;
|
|
6
10
|
};
|
|
7
11
|
export type MenuItemContext = {
|
|
12
|
+
/**
|
|
13
|
+
* If the menu item is a top-elvel item in a menu bar
|
|
14
|
+
*/
|
|
15
|
+
isMenuBarItem?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* The menu item values for the chain of open menus.
|
|
18
|
+
*/
|
|
19
|
+
openValues: Writable<string[]>;
|
|
8
20
|
rootValue?: string;
|
|
9
21
|
depth?: number;
|
|
10
|
-
|
|
11
|
-
unregister?: (menuItem: MenuItemRegistration) => void;
|
|
12
|
-
focusPrevious?: (currentValue: string) => void;
|
|
13
|
-
focusNext?: (currentValue: string) => void;
|
|
14
|
-
closeMenu?: (recursive?: boolean) => void;
|
|
22
|
+
closeContainingMenu?: () => void;
|
|
15
23
|
onOpen?: (value: string) => void;
|
|
16
24
|
onClose?: (value: string) => void;
|
|
17
25
|
onSelect?: (value: string) => void;
|
|
18
26
|
};
|
|
27
|
+
export {};
|
package/MenuItem.utils.d.ts
CHANGED
|
@@ -3,3 +3,5 @@ export declare const focusPreviousChild: (children: MenuItemRegistration[], curr
|
|
|
3
3
|
export declare const focusNextChild: (children: MenuItemRegistration[], currentValue: string) => void;
|
|
4
4
|
export declare const focusFirstChild: (children: MenuItemRegistration[]) => void;
|
|
5
5
|
export declare const focusLastChild: (children: MenuItemRegistration[]) => void;
|
|
6
|
+
export declare const isElementMenuItem: (candidate: Element | null | undefined) => boolean;
|
|
7
|
+
export declare const isElementEnabledMenuItem: (candidate: Element | null | undefined) => boolean;
|
package/MenuItem.utils.js
CHANGED
|
@@ -18,3 +18,19 @@ export const focusFirstChild = (children) => {
|
|
|
18
18
|
export const focusLastChild = (children) => {
|
|
19
19
|
children?.[children.length - 1]?.focus();
|
|
20
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/MenuItemDisplay.svelte
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script>export let checked = false;
|
|
2
2
|
export let disabled = false;
|
|
3
3
|
export let hasChildren = false;
|
|
4
|
+
export let isMenuBarItem = false;
|
|
4
5
|
export let menuItemRole = "menuitem";
|
|
5
6
|
</script>
|
|
6
7
|
|
|
@@ -19,7 +20,7 @@ export let menuItemRole = "menuitem";
|
|
|
19
20
|
<slot name="shortcut" />
|
|
20
21
|
</div>
|
|
21
22
|
{:else}
|
|
22
|
-
<div class="chevron" class:has-children={hasChildren} />
|
|
23
|
+
<div class="chevron" class:has-children={!isMenuBarItem && hasChildren} />
|
|
23
24
|
{/if}
|
|
24
25
|
</div>
|
|
25
26
|
|
package/Popover.svelte
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script>import { onMount } from "svelte";
|
|
2
|
-
import { autoUpdate, computePosition, flip, offset
|
|
2
|
+
import { autoUpdate, computePosition, flip, offset } from "@floating-ui/dom";
|
|
3
3
|
import { portal } from "./actions/portal";
|
|
4
4
|
export let placement = "bottom-start";
|
|
5
5
|
export let open = false;
|
|
@@ -25,11 +25,7 @@ let bodyHeight = 0;
|
|
|
25
25
|
const resizeObserver = new ResizeObserver((entries) => {
|
|
26
26
|
bodyHeight = entries[0].target.clientHeight;
|
|
27
27
|
});
|
|
28
|
-
const middleware = [
|
|
29
|
-
offset({ mainAxis: -2 }),
|
|
30
|
-
flip(),
|
|
31
|
-
shift({ padding: 0, mainAxis: true, crossAxis: true })
|
|
32
|
-
];
|
|
28
|
+
const middleware = [offset({ mainAxis: -2 }), flip()];
|
|
33
29
|
const computePopupPosition = async () => {
|
|
34
30
|
if (reference && popupRef) {
|
|
35
31
|
popupPosition = await computePosition(reference, popupRef, {
|
|
@@ -108,11 +104,6 @@ onMount(() => {
|
|
|
108
104
|
}
|
|
109
105
|
|
|
110
106
|
.sterling-popover {
|
|
111
|
-
background-color: var(--stsv-Common__background-color);
|
|
112
|
-
border-color: var(--stsv-Common__border-color);
|
|
113
|
-
border-radius: var(--stsv-Common__border-radius);
|
|
114
|
-
border-style: var(--stsv-Common__border-style);
|
|
115
|
-
border-width: var(--stsv-Common__border-width);
|
|
116
107
|
box-shadow: rgba(0, 0, 0, 0.4) 2px 2px 4px -1px;
|
|
117
108
|
box-sizing: border-box;
|
|
118
109
|
display: none;
|
|
@@ -120,9 +111,7 @@ onMount(() => {
|
|
|
120
111
|
grid-template-rows: 1fr;
|
|
121
112
|
height: fit-content;
|
|
122
113
|
left: 0;
|
|
123
|
-
|
|
124
|
-
overflow: auto;
|
|
125
|
-
overscroll-behavior: contain;
|
|
114
|
+
overflow: hidden;
|
|
126
115
|
position: absolute;
|
|
127
116
|
top: 0;
|
|
128
117
|
width: max-content;
|
package/Select.svelte
CHANGED
|
@@ -200,18 +200,20 @@ const onListSelect = (event) => {
|
|
|
200
200
|
</slot>
|
|
201
201
|
</div>
|
|
202
202
|
<Popup reference={selectRef} bind:open id={popupId}>
|
|
203
|
-
<
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
203
|
+
<div class="popup-content">
|
|
204
|
+
<List
|
|
205
|
+
bind:this={listRef}
|
|
206
|
+
composed
|
|
207
|
+
{disabled}
|
|
208
|
+
selectedValue={pendingSelectedValue}
|
|
209
|
+
on:click={onListClick}
|
|
210
|
+
on:keydown={onListKeydown}
|
|
211
|
+
on:select={onListSelect}
|
|
212
|
+
tabIndex={open ? 0 : -1}
|
|
213
|
+
>
|
|
214
|
+
<slot />
|
|
215
|
+
</List>
|
|
216
|
+
</div>
|
|
215
217
|
</Popup>
|
|
216
218
|
</div>
|
|
217
219
|
|
|
@@ -327,7 +329,17 @@ const onListSelect = (event) => {
|
|
|
327
329
|
}
|
|
328
330
|
|
|
329
331
|
.popup-content {
|
|
330
|
-
|
|
332
|
+
background-color: var(--stsv-Common__background-color);
|
|
333
|
+
border-color: var(--stsv-Common__border-color);
|
|
334
|
+
border-radius: var(--stsv-Common__border-radius);
|
|
335
|
+
border-style: var(--stsv-Common__border-style);
|
|
336
|
+
border-width: var(--stsv-Common__border-width);
|
|
337
|
+
padding: 0.25em;
|
|
338
|
+
display: grid;
|
|
339
|
+
grid-template-columns: 1fr;
|
|
340
|
+
grid-template-rows: 1fr;
|
|
341
|
+
overflow: hidden;
|
|
342
|
+
max-height: 20em;
|
|
331
343
|
}
|
|
332
344
|
|
|
333
345
|
@media (prefers-reduced-motion) {
|
package/Tab.svelte
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script>import { getContext } from "svelte";
|
|
2
2
|
import { TAB_LIST_CONTEXT_KEY } from "./TabList.constants";
|
|
3
|
+
import { usingKeyboard } from "./stores/usingKeyboard";
|
|
3
4
|
export let disabled = false;
|
|
4
5
|
export let selected = false;
|
|
5
6
|
export let text = void 0;
|
|
@@ -8,7 +9,6 @@ let tabRef;
|
|
|
8
9
|
const {
|
|
9
10
|
disabled: tabListDisabled,
|
|
10
11
|
selectedValue,
|
|
11
|
-
usingKeyboard,
|
|
12
12
|
vertical
|
|
13
13
|
} = getContext(TAB_LIST_CONTEXT_KEY);
|
|
14
14
|
$:
|