fluentui-svelte 0.1.0
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/LICENSE +21 -0
- package/README.md +201 -0
- package/dist/components/auto-suggest-box/auto-suggest-box.d.ts +2 -0
- package/dist/components/auto-suggest-box/auto-suggest-box.js +2 -0
- package/dist/components/auto-suggest-box/auto-suggest-box.svelte +457 -0
- package/dist/components/auto-suggest-box/auto-suggest-box.svelte.d.ts +4 -0
- package/dist/components/auto-suggest-box/docs/llms.md +73 -0
- package/dist/components/auto-suggest-box/option.svelte +82 -0
- package/dist/components/auto-suggest-box/option.svelte.d.ts +4 -0
- package/dist/components/auto-suggest-box/types.d.ts +140 -0
- package/dist/components/auto-suggest-box/types.js +1 -0
- package/dist/components/avatar/avatar.svelte +269 -0
- package/dist/components/avatar/avatar.svelte.d.ts +20 -0
- package/dist/components/avatar/docs/llms.md +92 -0
- package/dist/components/avatar/type.d.ts +63 -0
- package/dist/components/avatar/type.js +1 -0
- package/dist/components/badge/badge-icon.svelte +103 -0
- package/dist/components/badge/badge-icon.svelte.d.ts +25 -0
- package/dist/components/badge/badge.svelte +163 -0
- package/dist/components/badge/badge.svelte.d.ts +20 -0
- package/dist/components/badge/docs/llms.md +133 -0
- package/dist/components/badge/types.d.ts +70 -0
- package/dist/components/badge/types.js +1 -0
- package/dist/components/badge/utils.svelte.d.ts +16 -0
- package/dist/components/badge/utils.svelte.js +35 -0
- package/dist/components/button/button.svelte +203 -0
- package/dist/components/button/button.svelte.d.ts +38 -0
- package/dist/components/button/docs/llms.md +102 -0
- package/dist/components/button/split-button.svelte +66 -0
- package/dist/components/button/split-button.svelte.d.ts +4 -0
- package/dist/components/button/types.d.ts +84 -0
- package/dist/components/button/types.js +1 -0
- package/dist/components/calendar-date-picker/calendar-date-picker.svelte +119 -0
- package/dist/components/calendar-date-picker/calendar-date-picker.svelte.d.ts +4 -0
- package/dist/components/calendar-date-picker/docs/llms.md +33 -0
- package/dist/components/calendar-date-picker/types.d.ts +36 -0
- package/dist/components/calendar-date-picker/types.js +1 -0
- package/dist/components/calendar-view/calendar-view-controls.svelte +115 -0
- package/dist/components/calendar-view/calendar-view-controls.svelte.d.ts +3 -0
- package/dist/components/calendar-view/calendar-view-days.svelte +210 -0
- package/dist/components/calendar-view/calendar-view-days.svelte.d.ts +3 -0
- package/dist/components/calendar-view/calendar-view-grid.d.ts +38 -0
- package/dist/components/calendar-view/calendar-view-grid.js +140 -0
- package/dist/components/calendar-view/calendar-view-header.svelte +66 -0
- package/dist/components/calendar-view/calendar-view-header.svelte.d.ts +18 -0
- package/dist/components/calendar-view/calendar-view-item.svelte +181 -0
- package/dist/components/calendar-view/calendar-view-item.svelte.d.ts +4 -0
- package/dist/components/calendar-view/calendar-view-months.svelte +165 -0
- package/dist/components/calendar-view/calendar-view-months.svelte.d.ts +3 -0
- package/dist/components/calendar-view/calendar-view-years.svelte +161 -0
- package/dist/components/calendar-view/calendar-view-years.svelte.d.ts +3 -0
- package/dist/components/calendar-view/calendar-view.svelte +451 -0
- package/dist/components/calendar-view/calendar-view.svelte.d.ts +9 -0
- package/dist/components/calendar-view/calendar-view.svelte.js +196 -0
- package/dist/components/calendar-view/docs/llms.md +121 -0
- package/dist/components/calendar-view/index.d.ts +1 -0
- package/dist/components/calendar-view/index.js +1 -0
- package/dist/components/calendar-view/types.d.ts +174 -0
- package/dist/components/calendar-view/types.js +1 -0
- package/dist/components/checkbox/checkbox.svelte +171 -0
- package/dist/components/checkbox/checkbox.svelte.d.ts +40 -0
- package/dist/components/checkbox/docs/llms.md +78 -0
- package/dist/components/checkbox/types.d.ts +50 -0
- package/dist/components/checkbox/types.js +1 -0
- package/dist/components/date-picker/date-picker.svelte +381 -0
- package/dist/components/date-picker/date-picker.svelte.d.ts +4 -0
- package/dist/components/date-picker/docs/llms.md +52 -0
- package/dist/components/date-picker/index.d.ts +1 -0
- package/dist/components/date-picker/index.js +1 -0
- package/dist/components/date-picker/types.d.ts +74 -0
- package/dist/components/date-picker/types.js +1 -0
- package/dist/components/dialog/dialog-actions.svelte +37 -0
- package/dist/components/dialog/dialog-actions.svelte.d.ts +4 -0
- package/dist/components/dialog/dialog-content.svelte +17 -0
- package/dist/components/dialog/dialog-content.svelte.d.ts +4 -0
- package/dist/components/dialog/dialog-surface.svelte +95 -0
- package/dist/components/dialog/dialog-surface.svelte.d.ts +4 -0
- package/dist/components/dialog/dialog-title.svelte +33 -0
- package/dist/components/dialog/dialog-title.svelte.d.ts +25 -0
- package/dist/components/dialog/dialog-trigger.svelte +23 -0
- package/dist/components/dialog/dialog-trigger.svelte.d.ts +4 -0
- package/dist/components/dialog/dialog.svelte +64 -0
- package/dist/components/dialog/dialog.svelte.d.ts +7 -0
- package/dist/components/dialog/dialog.svelte.js +2 -0
- package/dist/components/dialog/docs/llms.md +131 -0
- package/dist/components/dialog/types.d.ts +92 -0
- package/dist/components/dialog/types.js +1 -0
- package/dist/components/divider/divider.svelte +120 -0
- package/dist/components/divider/divider.svelte.d.ts +39 -0
- package/dist/components/divider/docs/llms.md +83 -0
- package/dist/components/divider/types.d.ts +32 -0
- package/dist/components/divider/types.js +1 -0
- package/dist/components/dropdown/docs/llms.md +70 -0
- package/dist/components/dropdown/dropdown-context.d.ts +2 -0
- package/dist/components/dropdown/dropdown-context.js +2 -0
- package/dist/components/dropdown/dropdown-option.svelte +31 -0
- package/dist/components/dropdown/dropdown-option.svelte.d.ts +4 -0
- package/dist/components/dropdown/dropdown.svelte +309 -0
- package/dist/components/dropdown/dropdown.svelte.d.ts +4 -0
- package/dist/components/dropdown/types.d.ts +82 -0
- package/dist/components/dropdown/types.js +1 -0
- package/dist/components/dropdown-select/docs/llms.md +72 -0
- package/dist/components/dropdown-select/dropdown-select-option.svelte +87 -0
- package/dist/components/dropdown-select/dropdown-select-option.svelte.d.ts +4 -0
- package/dist/components/dropdown-select/dropdown-select.svelte +165 -0
- package/dist/components/dropdown-select/dropdown-select.svelte.d.ts +4 -0
- package/dist/components/dropdown-select/dropdown-select.svelte.js +48 -0
- package/dist/components/dropdown-select/index.d.ts +2 -0
- package/dist/components/dropdown-select/index.js +2 -0
- package/dist/components/dropdown-select/types.d.ts +46 -0
- package/dist/components/dropdown-select/types.js +1 -0
- package/dist/components/expander/docs/llms.md +88 -0
- package/dist/components/expander/expander.svelte +249 -0
- package/dist/components/expander/expander.svelte.d.ts +21 -0
- package/dist/components/expander/types.d.ts +47 -0
- package/dist/components/expander/types.js +1 -0
- package/dist/components/flyout/docs/llms.md +31 -0
- package/dist/components/flyout/flyout.svelte +148 -0
- package/dist/components/flyout/flyout.svelte.d.ts +19 -0
- package/dist/components/flyout/types.d.ts +36 -0
- package/dist/components/flyout/types.js +1 -0
- package/dist/components/hyperlink/docs/llms.md +33 -0
- package/dist/components/hyperlink/hyperlink.svelte +66 -0
- package/dist/components/hyperlink/hyperlink.svelte.d.ts +16 -0
- package/dist/components/hyperlink/types.d.ts +14 -0
- package/dist/components/hyperlink/types.js +1 -0
- package/dist/components/info-bar/docs/llms.md +81 -0
- package/dist/components/info-bar/info-bar.svelte +140 -0
- package/dist/components/info-bar/info-bar.svelte.d.ts +19 -0
- package/dist/components/info-bar/types.d.ts +27 -0
- package/dist/components/info-bar/types.js +1 -0
- package/dist/components/label/docs/llms.md +67 -0
- package/dist/components/label/label.svelte +95 -0
- package/dist/components/label/label.svelte.d.ts +4 -0
- package/dist/components/label/types.d.ts +32 -0
- package/dist/components/label/types.js +1 -0
- package/dist/components/list-view/docs/llms.md +110 -0
- package/dist/components/list-view/list-view-item.svelte +168 -0
- package/dist/components/list-view/list-view-item.svelte.d.ts +25 -0
- package/dist/components/list-view/list-view.svelte +137 -0
- package/dist/components/list-view/list-view.svelte.d.ts +25 -0
- package/dist/components/list-view/types.d.ts +95 -0
- package/dist/components/list-view/types.js +1 -0
- package/dist/components/list-view/utils.d.ts +6 -0
- package/dist/components/list-view/utils.js +12 -0
- package/dist/components/menu/context-menu-trigger.svelte +84 -0
- package/dist/components/menu/context-menu-trigger.svelte.d.ts +9 -0
- package/dist/components/menu/docs/llms.md +169 -0
- package/dist/components/menu/menu-divider.svelte +9 -0
- package/dist/components/menu/menu-divider.svelte.d.ts +26 -0
- package/dist/components/menu/menu-group.svelte +31 -0
- package/dist/components/menu/menu-group.svelte.d.ts +4 -0
- package/dist/components/menu/menu-item-checkbox.svelte +143 -0
- package/dist/components/menu/menu-item-checkbox.svelte.d.ts +15 -0
- package/dist/components/menu/menu-item-radio.svelte +147 -0
- package/dist/components/menu/menu-item-radio.svelte.d.ts +15 -0
- package/dist/components/menu/menu-item-switch.svelte +194 -0
- package/dist/components/menu/menu-item-switch.svelte.d.ts +15 -0
- package/dist/components/menu/menu-item.svelte +124 -0
- package/dist/components/menu/menu-item.svelte.d.ts +18 -0
- package/dist/components/menu/menu-list.svelte +38 -0
- package/dist/components/menu/menu-list.svelte.d.ts +5 -0
- package/dist/components/menu/menu-popover.svelte +125 -0
- package/dist/components/menu/menu-popover.svelte.d.ts +12 -0
- package/dist/components/menu/menu-trigger.svelte +121 -0
- package/dist/components/menu/menu-trigger.svelte.d.ts +4 -0
- package/dist/components/menu/menu.svelte +124 -0
- package/dist/components/menu/menu.svelte.d.ts +4 -0
- package/dist/components/menu/menu.svelte.js +77 -0
- package/dist/components/menu/types.d.ts +127 -0
- package/dist/components/menu/types.js +1 -0
- package/dist/components/number-box/docs/llms.md +37 -0
- package/dist/components/number-box/number-box.svelte +115 -0
- package/dist/components/number-box/number-box.svelte.d.ts +15 -0
- package/dist/components/number-box/types.d.ts +16 -0
- package/dist/components/number-box/types.js +1 -0
- package/dist/components/persona/docs/llms.md +107 -0
- package/dist/components/persona/persona.svelte +79 -0
- package/dist/components/persona/persona.svelte.d.ts +4 -0
- package/dist/components/persona/types.d.ts +42 -0
- package/dist/components/persona/types.js +1 -0
- package/dist/components/progress-bar/docs/llms.md +67 -0
- package/dist/components/progress-bar/progress-bar.svelte +167 -0
- package/dist/components/progress-bar/progress-bar.svelte.d.ts +15 -0
- package/dist/components/progress-bar/types.d.ts +39 -0
- package/dist/components/progress-bar/types.js +1 -0
- package/dist/components/progress-ring/docs/llms.md +76 -0
- package/dist/components/progress-ring/progress-ring.svelte +145 -0
- package/dist/components/progress-ring/progress-ring.svelte.d.ts +15 -0
- package/dist/components/progress-ring/types.d.ts +42 -0
- package/dist/components/progress-ring/types.js +1 -0
- package/dist/components/radio-button/docs/llms.md +64 -0
- package/dist/components/radio-button/radio-button.svelte +129 -0
- package/dist/components/radio-button/radio-button.svelte.d.ts +19 -0
- package/dist/components/radio-button/types.d.ts +24 -0
- package/dist/components/radio-button/types.js +1 -0
- package/dist/components/skeleton/docs/llms.md +67 -0
- package/dist/components/skeleton/skeleton.svelte +106 -0
- package/dist/components/skeleton/skeleton.svelte.d.ts +39 -0
- package/dist/components/skeleton/types.d.ts +24 -0
- package/dist/components/skeleton/types.js +1 -0
- package/dist/components/slider/docs/llms.md +75 -0
- package/dist/components/slider/slider.svelte +486 -0
- package/dist/components/slider/slider.svelte.d.ts +19 -0
- package/dist/components/slider/types.d.ts +102 -0
- package/dist/components/slider/types.js +1 -0
- package/dist/components/text-box/docs/llms.md +86 -0
- package/dist/components/text-box/text-box-button.svelte +65 -0
- package/dist/components/text-box/text-box-button.svelte.d.ts +9 -0
- package/dist/components/text-box/text-box.svelte +299 -0
- package/dist/components/text-box/text-box.svelte.d.ts +16 -0
- package/dist/components/text-box/types.d.ts +60 -0
- package/dist/components/text-box/types.js +1 -0
- package/dist/components/textarea/docs/llms.md +55 -0
- package/dist/components/textarea/textarea.svelte +151 -0
- package/dist/components/textarea/textarea.svelte.d.ts +17 -0
- package/dist/components/textarea/types.d.ts +33 -0
- package/dist/components/textarea/types.js +1 -0
- package/dist/components/time-picker/docs/llms.md +47 -0
- package/dist/components/time-picker/index.d.ts +1 -0
- package/dist/components/time-picker/index.js +1 -0
- package/dist/components/time-picker/time-picker.svelte +336 -0
- package/dist/components/time-picker/time-picker.svelte.d.ts +4 -0
- package/dist/components/time-picker/types.d.ts +54 -0
- package/dist/components/time-picker/types.js +1 -0
- package/dist/components/toggle-switch/docs/llms.md +39 -0
- package/dist/components/toggle-switch/toggle-switch.svelte +151 -0
- package/dist/components/toggle-switch/toggle-switch.svelte.d.ts +17 -0
- package/dist/components/toggle-switch/types.d.ts +20 -0
- package/dist/components/toggle-switch/types.js +1 -0
- package/dist/components/tooltip/docs/llms.md +74 -0
- package/dist/components/tooltip/tooltip.svelte +246 -0
- package/dist/components/tooltip/tooltip.svelte.d.ts +18 -0
- package/dist/components/tooltip/types.d.ts +67 -0
- package/dist/components/tooltip/types.js +1 -0
- package/dist/components/tree-view/docs/llms.md +117 -0
- package/dist/components/tree-view/tree-view-item-content.svelte +158 -0
- package/dist/components/tree-view/tree-view-item-content.svelte.d.ts +4 -0
- package/dist/components/tree-view/tree-view-item.svelte +197 -0
- package/dist/components/tree-view/tree-view-item.svelte.d.ts +4 -0
- package/dist/components/tree-view/tree-view.svelte +220 -0
- package/dist/components/tree-view/tree-view.svelte.d.ts +4 -0
- package/dist/components/tree-view/tree-view.svelte.js +111 -0
- package/dist/components/tree-view/types.d.ts +185 -0
- package/dist/components/tree-view/types.js +1 -0
- package/dist/css/class-darkmode.css +186 -0
- package/dist/css/media-darkmode.css +189 -0
- package/dist/css/reset.css +53 -0
- package/dist/css/theme.css +276 -0
- package/dist/css/typography.css +67 -0
- package/dist/css/utils.d.ts +1 -0
- package/dist/css/utils.js +153 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +129 -0
- package/dist/internal/components/dynamic-carousel/dynamic-carousel.svelte +449 -0
- package/dist/internal/components/dynamic-carousel/dynamic-carousel.svelte.d.ts +22 -0
- package/dist/internal/components/render-soc/render-soc.svelte +29 -0
- package/dist/internal/components/render-soc/render-soc.svelte.d.ts +30 -0
- package/dist/internal/constants.d.ts +26 -0
- package/dist/internal/constants.js +4036 -0
- package/dist/internal/context.d.ts +14 -0
- package/dist/internal/context.js +13 -0
- package/dist/internal/dom-utils.svelte.d.ts +6 -0
- package/dist/internal/dom-utils.svelte.js +46 -0
- package/dist/internal/floating-ui/floating.svelte.d.ts +15 -0
- package/dist/internal/floating-ui/floating.svelte.js +26 -0
- package/dist/internal/floating-ui/utils.d.ts +3 -0
- package/dist/internal/floating-ui/utils.js +30 -0
- package/dist/internal/index.d.ts +9 -0
- package/dist/internal/index.js +9 -0
- package/dist/internal/polyfills/expander.svelte.d.ts +21 -0
- package/dist/internal/polyfills/expander.svelte.js +96 -0
- package/dist/internal/transitions.d.ts +32 -0
- package/dist/internal/transitions.js +37 -0
- package/dist/internal/utils.d.ts +22 -0
- package/dist/internal/utils.js +63 -0
- package/dist/providers/fluentui-svelte/fluentui-svelte.d.ts +19 -0
- package/dist/providers/fluentui-svelte/fluentui-svelte.js +11 -0
- package/dist/providers/fluentui-svelte/fluentui-svelte.svelte +68 -0
- package/dist/providers/fluentui-svelte/fluentui-svelte.svelte.d.ts +9 -0
- package/dist/types/index.d.ts +117 -0
- package/dist/types/index.js +1 -0
- package/package.json +142 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { watch } from 'runed';
|
|
3
|
+
import CheckmarkFilled from 'fluentui-icons-svelte/CheckmarkFilled.svelte';
|
|
4
|
+
import { Button } from '../../index.js';
|
|
5
|
+
import { PREFIX } from '../../internal/constants.js';
|
|
6
|
+
import { invokeHandlers, RenderSoC } from '../../internal/index.js';
|
|
7
|
+
import { getMenuContext, COMPONENT_NAME as MENU_COMPONENT_NAME } from './menu.svelte.js';
|
|
8
|
+
import type { MenuItemActionableProps } from './types.js';
|
|
9
|
+
|
|
10
|
+
const FALLBACK_ID = $props.id();
|
|
11
|
+
const COMPONENT_NAME = 'menu-item-radio';
|
|
12
|
+
const ID = `${PREFIX}${COMPONENT_NAME}-${FALLBACK_ID}`;
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
ref = $bindable(),
|
|
16
|
+
icon: Icon,
|
|
17
|
+
secondaryContent,
|
|
18
|
+
children,
|
|
19
|
+
checked = $bindable(),
|
|
20
|
+
disabled,
|
|
21
|
+
class: classes,
|
|
22
|
+
id = ID,
|
|
23
|
+
name = id as string,
|
|
24
|
+
value = id as string,
|
|
25
|
+
onclick,
|
|
26
|
+
subText,
|
|
27
|
+
...attributes
|
|
28
|
+
}: MenuItemActionableProps = $props();
|
|
29
|
+
|
|
30
|
+
const context = getMenuContext();
|
|
31
|
+
|
|
32
|
+
if (!context) throw new Error(`No MenuContext found for ${MENU_COMPONENT_NAME}.`);
|
|
33
|
+
|
|
34
|
+
const { hasIcons, persistOnItemActivation } = context.config;
|
|
35
|
+
|
|
36
|
+
const { toggleRadio, toggle } = context.methods;
|
|
37
|
+
|
|
38
|
+
const { state: _state } = context;
|
|
39
|
+
|
|
40
|
+
watch(
|
|
41
|
+
() => _state.checkedValues?.[name]?.includes(value),
|
|
42
|
+
() => {
|
|
43
|
+
checked = _state.checkedValues?.[name]?.includes(value) || false;
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<!--
|
|
49
|
+
@component
|
|
50
|
+
|
|
51
|
+
- Usage:
|
|
52
|
+
```tsx
|
|
53
|
+
<Menu hasIcons>
|
|
54
|
+
<MenuGroup name="Inputs">
|
|
55
|
+
<MenuItemRadio secondaryContent="Item 1" hint="Ctrl + 1" {Icon}>Item 1</MenuItemRadio>
|
|
56
|
+
<MenuItemRadio secondaryContent="Item 2" hint="Ctrl + 2">Item 2</MenuItemRadio>
|
|
57
|
+
</MenuGroup>
|
|
58
|
+
</Menu>
|
|
59
|
+
```
|
|
60
|
+
-->
|
|
61
|
+
<Button
|
|
62
|
+
{disabled}
|
|
63
|
+
appearance="subtle"
|
|
64
|
+
onclick={(e: MouseEvent) =>
|
|
65
|
+
invokeHandlers(e, !!disabled, [onclick, () => toggleRadio(e, value, name), !!persistOnItemActivation && toggle])}
|
|
66
|
+
onkeydown={(e: KeyboardEvent) =>
|
|
67
|
+
invokeHandlers(
|
|
68
|
+
e,
|
|
69
|
+
[e.key !== 'Enter', !!disabled],
|
|
70
|
+
[onkeydown, () => toggleRadio(e, value, name), !!persistOnItemActivation && toggle]
|
|
71
|
+
)}
|
|
72
|
+
aria-checked={checked}
|
|
73
|
+
role="menuitemradio"
|
|
74
|
+
style={`--margin-left: ${hasIcons && !Icon ? 1.5 : 0}rem;}`}
|
|
75
|
+
aria-label={secondaryContent ? `${secondaryContent}, Use ${secondaryContent}` : undefined}
|
|
76
|
+
class="fs-menu-item-radio {hasIcons ? 'align' : ''} {checked ? 'checked' : ''} {classes}"
|
|
77
|
+
bind:ref
|
|
78
|
+
{...attributes}
|
|
79
|
+
>
|
|
80
|
+
<span class="label" aria-label="{secondaryContent}, Use {secondaryContent}">
|
|
81
|
+
<CheckmarkFilled class="indicator" />
|
|
82
|
+
{#if Icon}
|
|
83
|
+
<RenderSoC SoC={Icon} class="menu-item-icon" args={[{ class: 'menu-item-icon' }]} />
|
|
84
|
+
{/if}
|
|
85
|
+
{#if subText}
|
|
86
|
+
<span class="sub-text">
|
|
87
|
+
{@render children?.()}
|
|
88
|
+
<small>{subText}</small>
|
|
89
|
+
</span>
|
|
90
|
+
{:else}
|
|
91
|
+
{@render children?.()}
|
|
92
|
+
{/if}
|
|
93
|
+
</span>
|
|
94
|
+
{#if secondaryContent}
|
|
95
|
+
<span class="secondary-content" aria-hidden="true">{secondaryContent}</span>
|
|
96
|
+
{/if}
|
|
97
|
+
</Button>
|
|
98
|
+
|
|
99
|
+
<style>
|
|
100
|
+
:global(.fs-menu-item-radio.fs-button) {
|
|
101
|
+
width: 100%;
|
|
102
|
+
padding: 0.375rem 0.45rem;
|
|
103
|
+
border-radius: var(--fs-control-inner-border-radius);
|
|
104
|
+
justify-content: space-between;
|
|
105
|
+
font-size: var(--fs-body2-font-size);
|
|
106
|
+
line-height: var(--fs-caption-line-height);
|
|
107
|
+
& :global(svg) {
|
|
108
|
+
width: 1.25rem;
|
|
109
|
+
fill: currentColor;
|
|
110
|
+
& > :global(path) {
|
|
111
|
+
fill: currentColor;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
& .label {
|
|
115
|
+
display: flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
gap: 0.25rem;
|
|
118
|
+
font-size: inherit;
|
|
119
|
+
}
|
|
120
|
+
& .secondary-content {
|
|
121
|
+
font-size: var(--fs-caption-font-size);
|
|
122
|
+
color: var(--fs-text-secondary);
|
|
123
|
+
margin-left: 0.6rem;
|
|
124
|
+
}
|
|
125
|
+
&:global(.align .label:not(:has(.menu-item-icon))) {
|
|
126
|
+
margin-left: var(--margin-left) !important;
|
|
127
|
+
}
|
|
128
|
+
& .sub-text {
|
|
129
|
+
display: flex;
|
|
130
|
+
flex-direction: column;
|
|
131
|
+
align-items: flex-start;
|
|
132
|
+
text-align: left;
|
|
133
|
+
font-size: inherit;
|
|
134
|
+
& small {
|
|
135
|
+
font-size: var(--fs-caption2-font-size);
|
|
136
|
+
color: var(--fs-text-secondary);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
& :global(svg.indicator) {
|
|
140
|
+
width: 20px;
|
|
141
|
+
opacity: 0;
|
|
142
|
+
}
|
|
143
|
+
&.checked :global(svg.indicator) {
|
|
144
|
+
opacity: 1;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MenuItemActionableProps } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* - Usage:
|
|
4
|
+
* ```tsx
|
|
5
|
+
* <Menu hasIcons>
|
|
6
|
+
* <MenuGroup name="Inputs">
|
|
7
|
+
* <MenuItemRadio secondaryContent="Item 1" hint="Ctrl + 1" {Icon}>Item 1</MenuItemRadio>
|
|
8
|
+
* <MenuItemRadio secondaryContent="Item 2" hint="Ctrl + 2">Item 2</MenuItemRadio>
|
|
9
|
+
* </MenuGroup>
|
|
10
|
+
* </Menu>
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
declare const MenuItemRadio: import("svelte").Component<MenuItemActionableProps, {}, "ref" | "checked">;
|
|
14
|
+
type MenuItemRadio = ReturnType<typeof MenuItemRadio>;
|
|
15
|
+
export default MenuItemRadio;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { watch } from 'runed';
|
|
3
|
+
import { PREFIX } from '../../internal/constants.js';
|
|
4
|
+
import { Button } from '../../index.js';
|
|
5
|
+
import { invokeHandlers, RenderSoC } from '../../internal/index.js';
|
|
6
|
+
import { getMenuContext, COMPONENT_NAME as MENU_COMPONENT_NAME } from './menu.svelte.js';
|
|
7
|
+
import type { MenuItemActionableProps } from './types.js';
|
|
8
|
+
|
|
9
|
+
const FALLBACK_ID = $props.id();
|
|
10
|
+
const COMPONENT_NAME = 'menu-item-switch';
|
|
11
|
+
const ID = `${PREFIX}${COMPONENT_NAME}-${FALLBACK_ID}`;
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
ref = $bindable(),
|
|
15
|
+
icon: Icon,
|
|
16
|
+
secondaryContent,
|
|
17
|
+
children,
|
|
18
|
+
checked = $bindable(),
|
|
19
|
+
disabled,
|
|
20
|
+
id = ID,
|
|
21
|
+
class: classes,
|
|
22
|
+
name = id as string,
|
|
23
|
+
value = id as string,
|
|
24
|
+
subText,
|
|
25
|
+
onclick,
|
|
26
|
+
...attributes
|
|
27
|
+
}: MenuItemActionableProps = $props();
|
|
28
|
+
|
|
29
|
+
const context = getMenuContext();
|
|
30
|
+
|
|
31
|
+
if (!context) throw new Error(`No MenuContext found for ${MENU_COMPONENT_NAME}.`);
|
|
32
|
+
|
|
33
|
+
const { hasIcons, hasCheckmarks } = context.config;
|
|
34
|
+
|
|
35
|
+
const { toggleCheckbox } = context.methods;
|
|
36
|
+
|
|
37
|
+
const { state: _state } = context;
|
|
38
|
+
|
|
39
|
+
const marginLeft = $derived(1.5 * (+!!(hasIcons && !Icon) + +!!hasCheckmarks));
|
|
40
|
+
|
|
41
|
+
watch(
|
|
42
|
+
() => _state.checkedValues?.[name]?.includes(value),
|
|
43
|
+
() => {
|
|
44
|
+
checked = _state.checkedValues?.[name]?.includes(value) || false;
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<!--
|
|
50
|
+
@component
|
|
51
|
+
|
|
52
|
+
- Usage:
|
|
53
|
+
```tsx
|
|
54
|
+
<Menu hasIcons>
|
|
55
|
+
<MenuGroup name="Inputs">
|
|
56
|
+
<MenuItemSwitch secondaryContent="Item 1" hint="Ctrl + 1" {Icon}>Item 1</MenuItemSwitch>
|
|
57
|
+
<MenuItemSwitch secondaryContent="Item 2" hint="Ctrl + 2">Item 2</MenuItemSwitch>
|
|
58
|
+
</MenuGroup>
|
|
59
|
+
</Menu>
|
|
60
|
+
```
|
|
61
|
+
-->
|
|
62
|
+
<Button
|
|
63
|
+
{disabled}
|
|
64
|
+
{id}
|
|
65
|
+
appearance="subtle"
|
|
66
|
+
onclick={(e: MouseEvent) => invokeHandlers(e, disabled, [onclick, () => toggleCheckbox(e, value, name)])}
|
|
67
|
+
onkeydown={(e: KeyboardEvent) =>
|
|
68
|
+
invokeHandlers(e, [e.key !== 'Enter', !!disabled], [onkeydown, () => toggleCheckbox(e, value, name)])}
|
|
69
|
+
aria-checked={checked}
|
|
70
|
+
role="menuitemcheckbox"
|
|
71
|
+
style={`--margin-left: ${marginLeft}rem;}`}
|
|
72
|
+
aria-label={secondaryContent ? `${secondaryContent}, Use ${secondaryContent}` : undefined}
|
|
73
|
+
class="fs-menu-item-switch {hasIcons || hasCheckmarks ? 'align' : ''} {checked ? 'checked' : ''} {classes}"
|
|
74
|
+
bind:ref
|
|
75
|
+
{...attributes}
|
|
76
|
+
>
|
|
77
|
+
<span class="label" aria-label="{secondaryContent}, Use {secondaryContent}">
|
|
78
|
+
{#if Icon}
|
|
79
|
+
<RenderSoC SoC={Icon} class="menu-item-icon" args={[{ class: 'menu-item-icon' }]} />
|
|
80
|
+
{/if}
|
|
81
|
+
{#if subText}
|
|
82
|
+
<span class="sub-text">
|
|
83
|
+
{@render children?.()}
|
|
84
|
+
<small>{subText}</small>
|
|
85
|
+
</span>
|
|
86
|
+
{:else}
|
|
87
|
+
{@render children?.()}
|
|
88
|
+
{/if}
|
|
89
|
+
<span class={['item-switch', { on: checked, disabled }]} aria-hidden="true"></span>
|
|
90
|
+
</span>
|
|
91
|
+
{#if secondaryContent}
|
|
92
|
+
<span class="secondary-content" aria-hidden="true">{secondaryContent}</span>
|
|
93
|
+
{/if}
|
|
94
|
+
</Button>
|
|
95
|
+
|
|
96
|
+
<style>
|
|
97
|
+
:global(.fs-menu-item-switch.fs-button) {
|
|
98
|
+
width: 100%;
|
|
99
|
+
padding: 0.375rem 0.45rem;
|
|
100
|
+
border-radius: var(--fs-control-inner-border-radius);
|
|
101
|
+
justify-content: space-between;
|
|
102
|
+
font-size: var(--fs-body2-font-size);
|
|
103
|
+
line-height: var(--fs-caption-line-height);
|
|
104
|
+
& :global(svg) {
|
|
105
|
+
width: 1.25rem;
|
|
106
|
+
fill: currentColor;
|
|
107
|
+
& > :global(path) {
|
|
108
|
+
fill: currentColor;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
& .label {
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
gap: 0.5rem;
|
|
115
|
+
font-size: inherit;
|
|
116
|
+
justify-content: space-between;
|
|
117
|
+
flex: 1;
|
|
118
|
+
/* Mirrors the ToggleSwitch track and thumb, driven by `.checked` on the item. */
|
|
119
|
+
& .item-switch {
|
|
120
|
+
margin-left: 1rem;
|
|
121
|
+
pointer-events: none;
|
|
122
|
+
position: relative;
|
|
123
|
+
display: inline-flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
box-sizing: border-box;
|
|
126
|
+
width: 2.5rem;
|
|
127
|
+
min-width: 2.5rem;
|
|
128
|
+
height: 1.25rem;
|
|
129
|
+
padding: 0.063rem;
|
|
130
|
+
border: 0.063rem solid var(--fs-control-strong-stroke-default);
|
|
131
|
+
border-radius: 1.125rem;
|
|
132
|
+
background-color: var(--fs-control-alt-fill-secondary);
|
|
133
|
+
&::after {
|
|
134
|
+
content: '';
|
|
135
|
+
position: absolute;
|
|
136
|
+
left: 0.22rem;
|
|
137
|
+
width: 0.75rem;
|
|
138
|
+
height: 0.75rem;
|
|
139
|
+
border-radius: 0.75rem;
|
|
140
|
+
background-color: var(--fs-text-secondary);
|
|
141
|
+
transition: transform var(--fs-fast-duration) var(--fs-point-to-point);
|
|
142
|
+
}
|
|
143
|
+
&.on {
|
|
144
|
+
background-color: var(--fs-accent-fill-default);
|
|
145
|
+
border-color: var(--fs-accent-fill-default);
|
|
146
|
+
&::after {
|
|
147
|
+
transform: translateX(1.25rem);
|
|
148
|
+
background-color: var(--fs-text-on-accent-primary);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
&.disabled {
|
|
152
|
+
background-color: var(--fs-control-alt-fill-disabled);
|
|
153
|
+
border-color: var(--fs-control-strong-stroke-disabled);
|
|
154
|
+
&::after {
|
|
155
|
+
background-color: var(--fs-text-disabled);
|
|
156
|
+
}
|
|
157
|
+
&.on {
|
|
158
|
+
background-color: var(--fs-accent-fill-disabled);
|
|
159
|
+
border-color: var(--fs-accent-fill-disabled);
|
|
160
|
+
&::after {
|
|
161
|
+
background-color: var(--fs-text-on-accent-disabled);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
& .secondary-content {
|
|
168
|
+
font-size: var(--fs-caption-font-size);
|
|
169
|
+
color: var(--fs-text-secondary);
|
|
170
|
+
margin-left: 0.6rem;
|
|
171
|
+
}
|
|
172
|
+
&:global(.align .label:not(:has(.menu-item-icon))) {
|
|
173
|
+
margin-left: var(--margin-left) !important;
|
|
174
|
+
}
|
|
175
|
+
& .sub-text {
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-direction: column;
|
|
178
|
+
align-items: flex-start;
|
|
179
|
+
text-align: left;
|
|
180
|
+
font-size: inherit;
|
|
181
|
+
& small {
|
|
182
|
+
font-size: var(--fs-caption2-font-size);
|
|
183
|
+
color: var(--fs-text-secondary);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
& :global(svg.indicator) {
|
|
187
|
+
width: 20px;
|
|
188
|
+
opacity: 0;
|
|
189
|
+
}
|
|
190
|
+
&.checked :global(svg.indicator) {
|
|
191
|
+
opacity: 1;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MenuItemActionableProps } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* - Usage:
|
|
4
|
+
* ```tsx
|
|
5
|
+
* <Menu hasIcons>
|
|
6
|
+
* <MenuGroup name="Inputs">
|
|
7
|
+
* <MenuItemSwitch secondaryContent="Item 1" hint="Ctrl + 1" {Icon}>Item 1</MenuItemSwitch>
|
|
8
|
+
* <MenuItemSwitch secondaryContent="Item 2" hint="Ctrl + 2">Item 2</MenuItemSwitch>
|
|
9
|
+
* </MenuGroup>
|
|
10
|
+
* </Menu>
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
declare const MenuItemSwitch: import("svelte").Component<MenuItemActionableProps, {}, "ref" | "checked">;
|
|
14
|
+
type MenuItemSwitch = ReturnType<typeof MenuItemSwitch>;
|
|
15
|
+
export default MenuItemSwitch;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Button } from '../../index.js';
|
|
3
|
+
import { getMenuContext, COMPONENT_NAME as MENU_COMPONENT_NAME } from './menu.svelte.js';
|
|
4
|
+
import { PREFIX } from '../../internal/constants.js';
|
|
5
|
+
import { invokeHandlers, RenderSoC } from '../../internal/index.js';
|
|
6
|
+
import type { MenuItemProps } from './types.js';
|
|
7
|
+
import type { ComponentProps } from 'svelte';
|
|
8
|
+
|
|
9
|
+
const FALLBACK_ID = $props.id();
|
|
10
|
+
const COMPONENT_NAME = 'menu-item';
|
|
11
|
+
const ID = `${PREFIX}${COMPONENT_NAME}-${FALLBACK_ID}`;
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
ref = $bindable(),
|
|
15
|
+
icon: Icon,
|
|
16
|
+
secondaryContent,
|
|
17
|
+
children,
|
|
18
|
+
href,
|
|
19
|
+
id = ID,
|
|
20
|
+
disabled,
|
|
21
|
+
class: classes,
|
|
22
|
+
onclick,
|
|
23
|
+
onkeydown,
|
|
24
|
+
subText,
|
|
25
|
+
...attributes
|
|
26
|
+
}: MenuItemProps & ComponentProps<typeof Button> = $props();
|
|
27
|
+
|
|
28
|
+
const context = getMenuContext();
|
|
29
|
+
|
|
30
|
+
if (!context) throw new Error(`No MenuContext found for ${MENU_COMPONENT_NAME}.`);
|
|
31
|
+
|
|
32
|
+
const { hasIcons, hasCheckmarks, persistOnItemActivation } = context.config;
|
|
33
|
+
|
|
34
|
+
const { toggle } = context.methods;
|
|
35
|
+
|
|
36
|
+
const marginLeft = $derived(1.5 * (+!!(hasIcons && !Icon) + +!!hasCheckmarks));
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<!--
|
|
40
|
+
@component
|
|
41
|
+
|
|
42
|
+
- Usage:
|
|
43
|
+
```tsx
|
|
44
|
+
<Menu hasIcons>
|
|
45
|
+
<MenuGroup name="Inputs">
|
|
46
|
+
<MenuItem secondaryContent="Item 1" hint="Ctrl + 1" {Icon}>Item 1</MenuItem>
|
|
47
|
+
<MenuItem secondaryContent="Item 2" hint="Ctrl + 2">Item 2</MenuItem>
|
|
48
|
+
</MenuGroup>
|
|
49
|
+
</Menu>
|
|
50
|
+
```
|
|
51
|
+
-->
|
|
52
|
+
<Button
|
|
53
|
+
{href}
|
|
54
|
+
{disabled}
|
|
55
|
+
{id}
|
|
56
|
+
role="menuitem"
|
|
57
|
+
appearance="subtle"
|
|
58
|
+
onclick={(e: MouseEvent) => invokeHandlers(e, [persistOnItemActivation, disabled], [onclick, toggle])}
|
|
59
|
+
onkeydown={(e: KeyboardEvent) =>
|
|
60
|
+
invokeHandlers(e, [e.key !== 'Enter', persistOnItemActivation, disabled], [onkeydown, toggle])}
|
|
61
|
+
as={href ? 'a' : 'button'}
|
|
62
|
+
style={`--margin-left: ${marginLeft}rem;`}
|
|
63
|
+
class="fs-menu-item {hasIcons || hasCheckmarks ? 'align' : ''} {classes}"
|
|
64
|
+
bind:ref
|
|
65
|
+
{...attributes}
|
|
66
|
+
>
|
|
67
|
+
<span class="label" aria-label={secondaryContent ? `${secondaryContent}, Use ${secondaryContent}` : undefined}>
|
|
68
|
+
{#if Icon}
|
|
69
|
+
<RenderSoC SoC={Icon} args={[{ class: 'menu-item-icon' }]} class="menu-item-icon" />
|
|
70
|
+
{/if}
|
|
71
|
+
{#if subText}
|
|
72
|
+
<span class="sub-text">
|
|
73
|
+
{@render children?.()}
|
|
74
|
+
<small>{subText}</small>
|
|
75
|
+
</span>
|
|
76
|
+
{:else}
|
|
77
|
+
{@render children?.()}
|
|
78
|
+
{/if}
|
|
79
|
+
</span>
|
|
80
|
+
{#if secondaryContent}
|
|
81
|
+
<span class="secondary-content" aria-hidden="true">{secondaryContent}</span>
|
|
82
|
+
{/if}
|
|
83
|
+
</Button>
|
|
84
|
+
|
|
85
|
+
<style>
|
|
86
|
+
:global(.fs-menu-item.fs-button) {
|
|
87
|
+
width: 100%;
|
|
88
|
+
padding: 0.375rem 0.45rem;
|
|
89
|
+
border-radius: var(--fs-control-inner-border-radius);
|
|
90
|
+
justify-content: space-between;
|
|
91
|
+
font-size: var(--fs-body2-font-size);
|
|
92
|
+
line-height: var(--fs-caption-line-height);
|
|
93
|
+
|
|
94
|
+
& .label {
|
|
95
|
+
display: flex;
|
|
96
|
+
align-items: center;
|
|
97
|
+
gap: 0.25rem;
|
|
98
|
+
font-size: inherit;
|
|
99
|
+
line-height: inherit;
|
|
100
|
+
}
|
|
101
|
+
& .secondary-content {
|
|
102
|
+
font-size: var(--fs-caption-font-size);
|
|
103
|
+
color: var(--fs-text-secondary);
|
|
104
|
+
margin-left: 0.6rem;
|
|
105
|
+
}
|
|
106
|
+
&:global(.align) {
|
|
107
|
+
& .label:not(:has(.menu-item-icon)),
|
|
108
|
+
& .label:not(:has(.fs-menu-item-checkmark, .fs-menu-item-radio, .fs-menu-item-switch)) {
|
|
109
|
+
margin-left: var(--margin-left) !important;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
& .sub-text {
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
align-items: flex-start;
|
|
116
|
+
text-align: left;
|
|
117
|
+
font-size: inherit;
|
|
118
|
+
& small {
|
|
119
|
+
font-size: var(--fs-caption2-font-size);
|
|
120
|
+
color: var(--fs-text-secondary);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Button } from '../../index.js';
|
|
2
|
+
import type { MenuItemProps } from './types.ts';
|
|
3
|
+
import type { ComponentProps } from 'svelte';
|
|
4
|
+
type $$ComponentProps = MenuItemProps & ComponentProps<typeof Button>;
|
|
5
|
+
/**
|
|
6
|
+
* - Usage:
|
|
7
|
+
* ```tsx
|
|
8
|
+
* <Menu hasIcons>
|
|
9
|
+
* <MenuGroup name="Inputs">
|
|
10
|
+
* <MenuItem secondaryContent="Item 1" hint="Ctrl + 1" {Icon}>Item 1</MenuItem>
|
|
11
|
+
* <MenuItem secondaryContent="Item 2" hint="Ctrl + 2">Item 2</MenuItem>
|
|
12
|
+
* </MenuGroup>
|
|
13
|
+
* </Menu>
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare const MenuItem: import("svelte").Component<$$ComponentProps, {}, "ref">;
|
|
17
|
+
type MenuItem = ReturnType<typeof MenuItem>;
|
|
18
|
+
export default MenuItem;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getTabspotAttributes } from 'tabspot';
|
|
3
|
+
import { getMenuContext } from './menu.svelte.js';
|
|
4
|
+
|
|
5
|
+
let { children } = $props();
|
|
6
|
+
|
|
7
|
+
const context = getMenuContext();
|
|
8
|
+
|
|
9
|
+
let isSubMenu = $derived(context?.config.isSubMenu);
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<div
|
|
13
|
+
class="fs-menu-list"
|
|
14
|
+
role="menu"
|
|
15
|
+
{...getTabspotAttributes({
|
|
16
|
+
mover: { axis: 'vertical' },
|
|
17
|
+
grouper: isSubMenu
|
|
18
|
+
? {
|
|
19
|
+
enterDirection: 'right',
|
|
20
|
+
exitDirection: 'left'
|
|
21
|
+
}
|
|
22
|
+
: undefined
|
|
23
|
+
})}
|
|
24
|
+
>
|
|
25
|
+
{@render children()}
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<style>
|
|
29
|
+
.fs-menu-list {
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
padding: 0;
|
|
33
|
+
margin: 0;
|
|
34
|
+
list-style: none;
|
|
35
|
+
padding: 0.25rem;
|
|
36
|
+
flex-grow: 1;
|
|
37
|
+
}
|
|
38
|
+
</style>
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { circOut } from 'svelte/easing';
|
|
3
|
+
import { Flyout } from '../../index.js';
|
|
4
|
+
import { COMPONENT_NAME, getIntroTransition, getMenuContext } from './menu.svelte.js';
|
|
5
|
+
import { flip, hide, offset, shift } from '@floating-ui/dom';
|
|
6
|
+
import { useDebounce } from 'runed';
|
|
7
|
+
import { floating, flyToOffset, getCSSDuration, reactiveBoundingRect } from '../../internal/index.js';
|
|
8
|
+
import { getReducedMotion } from '../../providers/fluentui-svelte/fluentui-svelte.js';
|
|
9
|
+
import type { Snippet } from 'svelte';
|
|
10
|
+
import type { ComputePositionConfig } from '@floating-ui/dom';
|
|
11
|
+
|
|
12
|
+
let {
|
|
13
|
+
ref: _ref,
|
|
14
|
+
open: _open = $bindable(),
|
|
15
|
+
placement,
|
|
16
|
+
positionConfig: floatingPosition = {
|
|
17
|
+
placement,
|
|
18
|
+
middleware: [offset(-2), flip({ crossAxis: true, padding: 0 }), shift({ crossAxis: true, padding: 0 }), hide()],
|
|
19
|
+
strategy: 'fixed'
|
|
20
|
+
},
|
|
21
|
+
children
|
|
22
|
+
}: {
|
|
23
|
+
ref?: HTMLElement;
|
|
24
|
+
open?: boolean;
|
|
25
|
+
placement?: ComputePositionConfig['placement'];
|
|
26
|
+
positionConfig?: Partial<ComputePositionConfig>;
|
|
27
|
+
children: Snippet;
|
|
28
|
+
} = $props();
|
|
29
|
+
|
|
30
|
+
const context = getMenuContext();
|
|
31
|
+
|
|
32
|
+
if (!context) throw new Error(`No MenuContext found for ${COMPONENT_NAME}.`);
|
|
33
|
+
|
|
34
|
+
const reducedMotion = getReducedMotion();
|
|
35
|
+
|
|
36
|
+
const { positionConfig, id, isSubMenu, openOnHover, openingDelay } = context.config;
|
|
37
|
+
|
|
38
|
+
const { close } = context.methods;
|
|
39
|
+
|
|
40
|
+
let opened = $derived(_open ?? context.state.open);
|
|
41
|
+
|
|
42
|
+
let ref = $derived(_ref ?? context.state.ref);
|
|
43
|
+
|
|
44
|
+
let { state: _state } = context;
|
|
45
|
+
|
|
46
|
+
// The `placement` prop wins over the one coming from the config
|
|
47
|
+
let config = $derived.by(() => {
|
|
48
|
+
const base = positionConfig ?? floatingPosition;
|
|
49
|
+
|
|
50
|
+
return { ...base, placement: placement ?? base.placement ?? (isSubMenu ? 'right-start' : 'bottom-start') };
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
let boundingElement = reactiveBoundingRect();
|
|
54
|
+
|
|
55
|
+
let duration = $state(333);
|
|
56
|
+
|
|
57
|
+
let element: HTMLElement | null = $state(null);
|
|
58
|
+
|
|
59
|
+
const debounced = useDebounce((e: MouseEvent) => {
|
|
60
|
+
// Where the mouse is moving to
|
|
61
|
+
const to = e.relatedTarget as HTMLElement | null;
|
|
62
|
+
const isPopover = to?.id === `fs-menu-popover-${id}` || to?.closest(`#fs-menu-popover-${id}`);
|
|
63
|
+
const isTrigger =
|
|
64
|
+
to?.id === `fs-${isSubMenu ? 'submenu' : 'menu'}-trigger-${id}` ||
|
|
65
|
+
to?.closest(`#fs-${isSubMenu ? 'submenu' : 'menu'}-trigger-${id}`);
|
|
66
|
+
|
|
67
|
+
if (to && !isPopover && !isTrigger && !_state.locked) close(e);
|
|
68
|
+
}, openingDelay || 0);
|
|
69
|
+
|
|
70
|
+
$effect.pre(() => {
|
|
71
|
+
duration = getCSSDuration('--fs-normal-duration') || 333;
|
|
72
|
+
|
|
73
|
+
if (isSubMenu) floatingPosition.placement ??= 'right-start';
|
|
74
|
+
|
|
75
|
+
if (ref && ref instanceof HTMLElement) boundingElement.ref = ref;
|
|
76
|
+
|
|
77
|
+
// Make sure to update the position of boundingElement before the popover is shown
|
|
78
|
+
if (opened) boundingElement.update();
|
|
79
|
+
});
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
{#if opened && ref}
|
|
83
|
+
{@const isRefAnElement = ref instanceof HTMLElement}
|
|
84
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
85
|
+
<div
|
|
86
|
+
bind:this={element}
|
|
87
|
+
class="fs-menu-popover"
|
|
88
|
+
onmouseleave={openOnHover ? (e: MouseEvent) => debounced(e) : undefined}
|
|
89
|
+
{@attach ref ? floating(ref, config) : undefined}
|
|
90
|
+
style={`--position=${isSubMenu ? 'absolute' : 'fixed'} --min-width=${isRefAnElement && !isSubMenu ? `${boundingElement.rect.width}px` : 'max-content'}`}
|
|
91
|
+
in:flyToOffset={isRefAnElement
|
|
92
|
+
? {
|
|
93
|
+
...getIntroTransition({ config, anchor: boundingElement.rect, element, ref, isSubMenu }),
|
|
94
|
+
duration: duration,
|
|
95
|
+
easing: circOut,
|
|
96
|
+
reducedMotion: reducedMotion()
|
|
97
|
+
}
|
|
98
|
+
: undefined}
|
|
99
|
+
>
|
|
100
|
+
<Flyout class="fs-menu-popover" id="fs-menu-popover-{id}" role="menu">
|
|
101
|
+
{@render children()}
|
|
102
|
+
</Flyout>
|
|
103
|
+
</div>
|
|
104
|
+
{/if}
|
|
105
|
+
|
|
106
|
+
<style>
|
|
107
|
+
.fs-menu-popover {
|
|
108
|
+
position: var(--position, fixed);
|
|
109
|
+
top: 0;
|
|
110
|
+
left: 0;
|
|
111
|
+
width: max-content;
|
|
112
|
+
min-width: var(--min-width);
|
|
113
|
+
z-index: 110;
|
|
114
|
+
& :global(.fs-flyout),
|
|
115
|
+
& :global(.fs-flyout::before) {
|
|
116
|
+
border-radius: var(--fs-control-border-radius);
|
|
117
|
+
}
|
|
118
|
+
& :global(.fs-flyout) {
|
|
119
|
+
padding: 0;
|
|
120
|
+
& :global(> .wrapper) {
|
|
121
|
+
width: 100% !important;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { ComputePositionConfig } from '@floating-ui/dom';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
ref?: HTMLElement;
|
|
5
|
+
open?: boolean;
|
|
6
|
+
placement?: ComputePositionConfig['placement'];
|
|
7
|
+
positionConfig?: Partial<ComputePositionConfig>;
|
|
8
|
+
children: Snippet;
|
|
9
|
+
};
|
|
10
|
+
declare const MenuPopover: import("svelte").Component<$$ComponentProps, {}, "open">;
|
|
11
|
+
type MenuPopover = ReturnType<typeof MenuPopover>;
|
|
12
|
+
export default MenuPopover;
|