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,121 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { on } from 'svelte/events';
|
|
3
|
+
import { useDebounce } from 'runed';
|
|
4
|
+
import { onMount, tick } from 'svelte';
|
|
5
|
+
import { COMPONENT_NAME, getMenuContext } from './menu.svelte.js';
|
|
6
|
+
import ChevronRightFilled from 'fluentui-icons-svelte/ChevronRightFilled.svelte';
|
|
7
|
+
import type { MenuTriggerProps } from './types.js';
|
|
8
|
+
import type { ButtonProps } from '../button/types.js';
|
|
9
|
+
|
|
10
|
+
let FALLBACK_ID = $props.id();
|
|
11
|
+
|
|
12
|
+
let { disabled, shape, icon: Icon, children }: MenuTriggerProps = $props();
|
|
13
|
+
|
|
14
|
+
const context = getMenuContext();
|
|
15
|
+
|
|
16
|
+
if (!context) throw new Error(`No MenuContext found for ${COMPONENT_NAME}.`);
|
|
17
|
+
|
|
18
|
+
const { state: _state } = context;
|
|
19
|
+
|
|
20
|
+
const { toggle, open, close } = context.methods;
|
|
21
|
+
|
|
22
|
+
const { id, isSubMenu, openOnHover, openingDelay, parentHasCheckmarks, parentHasIcons } = context.config;
|
|
23
|
+
|
|
24
|
+
const paddingLeft = $derived(1.25 * (+!!(parentHasIcons && !Icon) + +!!parentHasCheckmarks) + 0.9);
|
|
25
|
+
|
|
26
|
+
const debounced = useDebounce((e: MouseEvent) => {
|
|
27
|
+
if (e.type === 'mouseover' && !_state.open) {
|
|
28
|
+
return open(e);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Where the mouse is moving to
|
|
32
|
+
const to = e.relatedTarget as HTMLElement | null;
|
|
33
|
+
|
|
34
|
+
if (to && !to.closest(`#fs-menu-popover-${id}`) && to.parentElement !== _state.ref && !_state.locked) close(e);
|
|
35
|
+
}, openingDelay || 0);
|
|
36
|
+
|
|
37
|
+
onMount(() => {
|
|
38
|
+
const off = on(document, 'click', async (e: MouseEvent) => {
|
|
39
|
+
const target = e.target as HTMLElement;
|
|
40
|
+
|
|
41
|
+
if (target.closest(`#fs-menu-popover-${id}`)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (target === _state.ref) {
|
|
46
|
+
_state.locked = !_state.locked;
|
|
47
|
+
toggle(e);
|
|
48
|
+
// Focus the first button in the popover when opening
|
|
49
|
+
if (_state.open) {
|
|
50
|
+
await tick();
|
|
51
|
+
(document.querySelector(`#fs-menu-popover-${id} .fs-button:first-of-type`) as HTMLElement)?.focus();
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!target.closest(`#fs-menu-popover-${id}`)) {
|
|
57
|
+
_state.locked = false;
|
|
58
|
+
close(e);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return () => off();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const menuTriggerProps: Omit<ButtonProps<'button'>, 'ref'> = $derived({
|
|
66
|
+
disabled,
|
|
67
|
+
shape,
|
|
68
|
+
'aria-controls': `fs-menu-popover-${id}`,
|
|
69
|
+
id: `fs-${isSubMenu ? 'submenu' : 'menu'}-trigger-${id}`,
|
|
70
|
+
class: `fs-${isSubMenu ? 'submenu' : 'menu'}-trigger ${
|
|
71
|
+
(parentHasIcons || parentHasCheckmarks) && isSubMenu ? 'align' : ''
|
|
72
|
+
} trigger-id-${FALLBACK_ID}`,
|
|
73
|
+
style: `--padding-left: ${paddingLeft}rem;`,
|
|
74
|
+
onmouseover: openOnHover && !disabled ? (e: MouseEvent) => debounced(e) : undefined,
|
|
75
|
+
onmouseleave: openOnHover && !disabled ? (e: MouseEvent) => debounced(e) : undefined,
|
|
76
|
+
'aria-haspopup': 'menu',
|
|
77
|
+
'aria-expanded': _state.open ? 'true' : 'false',
|
|
78
|
+
role: isSubMenu ? 'menuitem' : undefined,
|
|
79
|
+
appearance: isSubMenu ? 'subtle' : undefined,
|
|
80
|
+
isMenuButton: isSubMenu,
|
|
81
|
+
indicatorIcon: isSubMenu ? ChevronRightFilled : undefined
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// svelte-ignore state_referenced_locally
|
|
85
|
+
const primaryButtonProps: ButtonProps<'button'> = $state.raw({
|
|
86
|
+
disabled,
|
|
87
|
+
shape
|
|
88
|
+
});
|
|
89
|
+
</script>
|
|
90
|
+
|
|
91
|
+
{@render children?.({ state: context.state, menuTriggerProps, primaryButtonProps })}
|
|
92
|
+
|
|
93
|
+
<style>
|
|
94
|
+
:global(.fs-button.fs-submenu-trigger) {
|
|
95
|
+
width: 100%;
|
|
96
|
+
padding: 0.375rem 0.45rem;
|
|
97
|
+
border-radius: var(--fs-control-inner-border-radius);
|
|
98
|
+
justify-content: space-between;
|
|
99
|
+
font-size: var(--fs-body2-font-size);
|
|
100
|
+
line-height: var(--fs-body2-line-height);
|
|
101
|
+
& :global(svg) {
|
|
102
|
+
width: 1rem;
|
|
103
|
+
height: 1rem;
|
|
104
|
+
height: auto;
|
|
105
|
+
fill: currentColor;
|
|
106
|
+
}
|
|
107
|
+
& :global(svg.indicator) {
|
|
108
|
+
width: 1rem;
|
|
109
|
+
height: auto;
|
|
110
|
+
margin-left: 0.6rem;
|
|
111
|
+
margin-right: 0.2rem;
|
|
112
|
+
pointer-events: none;
|
|
113
|
+
}
|
|
114
|
+
&:global(:is(:disabled, [disabled]) :is(svg, .indicator)) {
|
|
115
|
+
color: var(--fs-text-disabled);
|
|
116
|
+
}
|
|
117
|
+
&:global(.align) {
|
|
118
|
+
padding-left: var(--padding-left) !important;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getMenuContext, setMenuContext } from './menu.svelte.js';
|
|
3
|
+
import type { MenuContext, MenuProps, MenuState } from './types.js';
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
checkedValues = {} as Record<string, string[]>,
|
|
7
|
+
onCheckedValueChange,
|
|
8
|
+
hasCheckmarks,
|
|
9
|
+
hasIcons,
|
|
10
|
+
openingDelay = 0,
|
|
11
|
+
open,
|
|
12
|
+
onOpenChange,
|
|
13
|
+
openOnHover = false,
|
|
14
|
+
persistOnItemActivation = false,
|
|
15
|
+
positionConfig,
|
|
16
|
+
children
|
|
17
|
+
}: MenuProps = $props();
|
|
18
|
+
|
|
19
|
+
const id = $props.id();
|
|
20
|
+
|
|
21
|
+
// Check if is being used as submenu
|
|
22
|
+
const PARENT_CONTEXT = getMenuContext();
|
|
23
|
+
|
|
24
|
+
let ref: HTMLElement | null = $state(null);
|
|
25
|
+
|
|
26
|
+
let locked = $state(false);
|
|
27
|
+
|
|
28
|
+
let config: MenuContext['config'] = $derived.by(() => {
|
|
29
|
+
if (!PARENT_CONTEXT) {
|
|
30
|
+
return {
|
|
31
|
+
id,
|
|
32
|
+
isSubMenu: false,
|
|
33
|
+
hasCheckmarks,
|
|
34
|
+
hasIcons,
|
|
35
|
+
openingDelay,
|
|
36
|
+
openOnHover,
|
|
37
|
+
persistOnItemActivation,
|
|
38
|
+
positionConfig,
|
|
39
|
+
parentHasCheckmarks: false,
|
|
40
|
+
parentHasIcons: false
|
|
41
|
+
};
|
|
42
|
+
} else {
|
|
43
|
+
return {
|
|
44
|
+
...PARENT_CONTEXT.config,
|
|
45
|
+
isSubMenu: true,
|
|
46
|
+
id,
|
|
47
|
+
hasCheckmarks,
|
|
48
|
+
hasIcons,
|
|
49
|
+
parentHasCheckmarks: !!PARENT_CONTEXT.config.hasCheckmarks,
|
|
50
|
+
parentHasIcons: !!PARENT_CONTEXT.config.hasIcons
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const _state: MenuState = {
|
|
56
|
+
get open() {
|
|
57
|
+
return open;
|
|
58
|
+
},
|
|
59
|
+
set open(v) {
|
|
60
|
+
open = v;
|
|
61
|
+
},
|
|
62
|
+
get ref() {
|
|
63
|
+
return ref;
|
|
64
|
+
},
|
|
65
|
+
set ref(v) {
|
|
66
|
+
ref = v;
|
|
67
|
+
},
|
|
68
|
+
get locked() {
|
|
69
|
+
return locked;
|
|
70
|
+
},
|
|
71
|
+
set locked(v) {
|
|
72
|
+
locked = v;
|
|
73
|
+
},
|
|
74
|
+
get checkedValues() {
|
|
75
|
+
return checkedValues;
|
|
76
|
+
},
|
|
77
|
+
set checkedValues(v) {
|
|
78
|
+
checkedValues = v;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
let events: MenuContext['events'] = $derived.by(() => {
|
|
83
|
+
if (!PARENT_CONTEXT) {
|
|
84
|
+
return {
|
|
85
|
+
onCheckedValueChange: (e, value) => onCheckedValueChange?.(e, value),
|
|
86
|
+
onOpenChange: (e, opened) => onOpenChange?.(e, opened)
|
|
87
|
+
};
|
|
88
|
+
} else {
|
|
89
|
+
return PARENT_CONTEXT.events;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
let methods: MenuContext['methods'] = $derived({
|
|
94
|
+
toggle: (e: Event) => {
|
|
95
|
+
_state.open = !_state.open;
|
|
96
|
+
events.onOpenChange?.(e, _state.open);
|
|
97
|
+
},
|
|
98
|
+
open: (e: Event) => {
|
|
99
|
+
_state.open = true;
|
|
100
|
+
events.onOpenChange?.(e, _state.open);
|
|
101
|
+
},
|
|
102
|
+
close: (e: Event) => {
|
|
103
|
+
_state.open = false;
|
|
104
|
+
events.onOpenChange?.(e, _state.open);
|
|
105
|
+
},
|
|
106
|
+
toggleCheckbox: (e: Event, value: string, name: string) => {
|
|
107
|
+
const current = _state.checkedValues?.[name] ?? [];
|
|
108
|
+
const updated = current.includes(value) ? current.filter((v) => v !== value) : [...current, value];
|
|
109
|
+
_state.checkedValues = { ..._state.checkedValues, [name]: updated };
|
|
110
|
+
events.onCheckedValueChange?.(e, _state.checkedValues!);
|
|
111
|
+
},
|
|
112
|
+
toggleRadio: (e: Event, value: string, name: string) => {
|
|
113
|
+
if (!_state.checkedValues?.[name]?.includes(value)) {
|
|
114
|
+
_state.checkedValues = { ..._state.checkedValues, [name]: [value] };
|
|
115
|
+
events.onCheckedValueChange?.(e, _state.checkedValues!);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// svelte-ignore state_referenced_locally
|
|
121
|
+
setMenuContext({ config, state: _state, events, methods });
|
|
122
|
+
</script>
|
|
123
|
+
|
|
124
|
+
{@render children?.()}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { createFSContext, getOffset } from '../../internal/index.js';
|
|
2
|
+
export const COMPONENT_NAME = 'fs-menu-';
|
|
3
|
+
export const [getMenuContext, setMenuContext] = createFSContext();
|
|
4
|
+
/** Distance, in pixels, the popover keeps from the anchor edge when a vertical intro starts. */
|
|
5
|
+
const VERTICAL_INTRO_DISTANCE = 10;
|
|
6
|
+
/** Distance, in pixels, a horizontal intro slides out of the anchor edge. */
|
|
7
|
+
const HORIZONTAL_INTRO_DISTANCE = 15;
|
|
8
|
+
/**
|
|
9
|
+
* Rect of an element relative to its `offsetParent`, which is the coordinate space an absolutely
|
|
10
|
+
* positioned sibling lives in. It matches what FloatingUI resolves for such an element.
|
|
11
|
+
*/
|
|
12
|
+
const getOffsetRect = (element) => ({
|
|
13
|
+
x: element.offsetLeft,
|
|
14
|
+
y: element.offsetTop,
|
|
15
|
+
top: element.offsetTop,
|
|
16
|
+
left: element.offsetLeft,
|
|
17
|
+
right: element.offsetLeft + element.offsetWidth,
|
|
18
|
+
bottom: element.offsetTop + element.offsetHeight,
|
|
19
|
+
width: element.offsetWidth,
|
|
20
|
+
height: element.offsetHeight
|
|
21
|
+
});
|
|
22
|
+
/**
|
|
23
|
+
* Resolves the coordinates FloatingUI settles the popover at for the given placement, in the same
|
|
24
|
+
* space as the anchor rect it is given: the viewport for a menu, the parent popover for a submenu.
|
|
25
|
+
*
|
|
26
|
+
* The `in:` transition runs before FloatingUI has computed anything, so the animation has to start
|
|
27
|
+
* and end on these coordinates for the handover to be seamless.
|
|
28
|
+
*/
|
|
29
|
+
export const getIntroCoords = ({ placement, anchor, floating, offset = 0 }) => {
|
|
30
|
+
const [side, alignment] = placement.split('-');
|
|
31
|
+
const isVertical = side === 'top' || side === 'bottom';
|
|
32
|
+
// Main axis: the popover sits right outside the anchor edge, pushed away by the `offset` middleware.
|
|
33
|
+
const main = side === 'top'
|
|
34
|
+
? anchor.top - floating.height - offset
|
|
35
|
+
: side === 'bottom'
|
|
36
|
+
? anchor.bottom + offset
|
|
37
|
+
: side === 'left'
|
|
38
|
+
? anchor.left - floating.width - offset
|
|
39
|
+
: anchor.right + offset;
|
|
40
|
+
// Cross axis: flush with the anchor start or end edge, centered when the placement has no alignment.
|
|
41
|
+
const anchorStart = isVertical ? anchor.left : anchor.top;
|
|
42
|
+
const anchorSize = isVertical ? anchor.width : anchor.height;
|
|
43
|
+
const floatingSize = isVertical ? floating.width : floating.height;
|
|
44
|
+
const cross = alignment === 'start'
|
|
45
|
+
? anchorStart
|
|
46
|
+
: alignment === 'end'
|
|
47
|
+
? anchorStart + anchorSize - floatingSize
|
|
48
|
+
: anchorStart + (anchorSize - floatingSize) / 2;
|
|
49
|
+
return isVertical ? { top: main, left: cross } : { top: cross, left: main };
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Builds the `flyToOffset` options for the popover intro: the popover emerges from the anchor and
|
|
53
|
+
* lands exactly where FloatingUI will keep it (or should, if element is not crossing the viewport), so nothing jumps when the transition ends.
|
|
54
|
+
*/
|
|
55
|
+
export const getIntroTransition = ({ config, anchor, element, ref, isSubMenu = false }) => {
|
|
56
|
+
const offset = getOffset(config);
|
|
57
|
+
const placement = config.placement ?? (isSubMenu ? 'right-start' : 'bottom-start');
|
|
58
|
+
const [side] = placement.split('-');
|
|
59
|
+
const isVertical = side === 'top' || side === 'bottom';
|
|
60
|
+
// A submenu is absolutely positioned inside its parent popover, so it is placed in the coordinate
|
|
61
|
+
// space of that popover instead of the viewport, the very same space FloatingUI resolves it in.
|
|
62
|
+
const rect = isSubMenu && ref instanceof HTMLElement ? getOffsetRect(ref) : anchor;
|
|
63
|
+
const { top, left } = getIntroCoords({
|
|
64
|
+
placement,
|
|
65
|
+
anchor: rect,
|
|
66
|
+
floating: element?.getBoundingClientRect() ?? { width: 0, height: 0 },
|
|
67
|
+
offset
|
|
68
|
+
});
|
|
69
|
+
// The popover starts overlapping the anchor and slides out of it, towards the resolved
|
|
70
|
+
// coordinates: a vertical intro emerges from the whole anchor, a horizontal one just peeks out.
|
|
71
|
+
const travel = isVertical ? rect.height + offset - VERTICAL_INTRO_DISTANCE : HORIZONTAL_INTRO_DISTANCE;
|
|
72
|
+
const distance = side === 'top' || side === 'left' ? travel : -travel;
|
|
73
|
+
return {
|
|
74
|
+
...(isVertical ? { y: distance } : { x: distance }),
|
|
75
|
+
css: `top: ${top}px; left: ${left}px;`
|
|
76
|
+
};
|
|
77
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { ComputePositionConfig, VirtualElement } from '@floating-ui/dom';
|
|
2
|
+
import type { FSContext } from '../../internal/index.js';
|
|
3
|
+
import type { Component, ComponentProps, Snippet } from 'svelte';
|
|
4
|
+
import type { NoUndefinedField, Shapes } from '../../types/index.js';
|
|
5
|
+
import type { Button } from '../../index.ts';
|
|
6
|
+
import type { ButtonProps } from '../button/types.ts';
|
|
7
|
+
export type MenuContext = FSContext<{
|
|
8
|
+
id: string;
|
|
9
|
+
isSubMenu: boolean;
|
|
10
|
+
parentHasCheckmarks: boolean;
|
|
11
|
+
parentHasIcons: boolean;
|
|
12
|
+
} & Omit<MenuProps, 'element' | 'children' | 'onOpenChange' | 'open' | 'onCheckedValueChange' | 'checkedValues'>, MenuState, NoUndefinedField<Pick<MenuProps, 'onCheckedValueChange' | 'onOpenChange'>>, {
|
|
13
|
+
toggle: (e: Event) => void;
|
|
14
|
+
open: (e: Event) => void;
|
|
15
|
+
close: (e: Event) => void;
|
|
16
|
+
toggleCheckbox: (e: Event, value: string, name: string) => void;
|
|
17
|
+
toggleRadio: (e: Event, value: string, name: string) => void;
|
|
18
|
+
}>;
|
|
19
|
+
export type MenuState = {
|
|
20
|
+
open: boolean | undefined;
|
|
21
|
+
ref: HTMLElement | VirtualElement | null | undefined;
|
|
22
|
+
locked: boolean;
|
|
23
|
+
checkedValues: MenuProps['checkedValues'];
|
|
24
|
+
};
|
|
25
|
+
/** @propsmith MenuProps */
|
|
26
|
+
export type MenuProps = {
|
|
27
|
+
/** The position configuration handed over to floating-ui.
|
|
28
|
+
* @type ComputePositionConfig
|
|
29
|
+
*/
|
|
30
|
+
positionConfig?: Partial<ComputePositionConfig>;
|
|
31
|
+
/** Reserves the room every item needs for an icon, so the labels line up. */
|
|
32
|
+
hasIcons?: boolean;
|
|
33
|
+
/** Reserves the room every item needs for a checkmark, so the labels line up. */
|
|
34
|
+
hasCheckmarks?: boolean;
|
|
35
|
+
/** Controls the open state of the menu. */
|
|
36
|
+
open?: boolean;
|
|
37
|
+
/** Called whenever the menu opens or closes. */
|
|
38
|
+
onOpenChange?: (e: Event, open: boolean) => void;
|
|
39
|
+
/** The checked values of the menu, grouped by the `name` of each item.
|
|
40
|
+
* @default {}
|
|
41
|
+
*/
|
|
42
|
+
checkedValues?: Record<string, string[]>;
|
|
43
|
+
/** Called whenever a checkbox or radio item changes.
|
|
44
|
+
* @type (e: Event, checkedValues: Record<string, string[]>) => void
|
|
45
|
+
*/
|
|
46
|
+
onCheckedValueChange?: (e: Event, checkedValues: Record<string, string[]>) => void;
|
|
47
|
+
/** Opens the menu on hover instead of on click.
|
|
48
|
+
* @default false
|
|
49
|
+
*/
|
|
50
|
+
openOnHover?: boolean;
|
|
51
|
+
/** How long to wait, in milliseconds, before opening the menu.
|
|
52
|
+
* @default 0
|
|
53
|
+
*/
|
|
54
|
+
openingDelay?: number;
|
|
55
|
+
/** Keeps the menu open after an item is activated.
|
|
56
|
+
* @default false
|
|
57
|
+
*/
|
|
58
|
+
persistOnItemActivation?: boolean;
|
|
59
|
+
/** The parts of the menu: a trigger and a popover. */
|
|
60
|
+
children?: Snippet;
|
|
61
|
+
};
|
|
62
|
+
/** @propsmith MenuTriggerProps */
|
|
63
|
+
export type MenuTriggerProps = {
|
|
64
|
+
/** Disables the user interaction. */
|
|
65
|
+
disabled?: boolean;
|
|
66
|
+
/** The trigger can be rounded, circular, or square. */
|
|
67
|
+
shape?: Shapes;
|
|
68
|
+
/** An optional icon for the trigger.
|
|
69
|
+
* @type Snippet | Component
|
|
70
|
+
*/
|
|
71
|
+
icon?: Snippet | Component;
|
|
72
|
+
/** A custom trigger. It receives the menu state and the props to spread on your own buttons.
|
|
73
|
+
* @type Snippet
|
|
74
|
+
*/
|
|
75
|
+
children?: Snippet<[
|
|
76
|
+
{
|
|
77
|
+
state: MenuState;
|
|
78
|
+
menuTriggerProps: ButtonProps<'button'>;
|
|
79
|
+
primaryButtonProps: ButtonProps<'button'>;
|
|
80
|
+
}
|
|
81
|
+
]>;
|
|
82
|
+
};
|
|
83
|
+
/** @propsmith MenuGroupProps */
|
|
84
|
+
export type MenuGroupProps = {
|
|
85
|
+
/** The DOM reference of the group element.
|
|
86
|
+
* @bindable
|
|
87
|
+
*/
|
|
88
|
+
ref?: HTMLDivElement;
|
|
89
|
+
/** The label of the group. */
|
|
90
|
+
header?: string;
|
|
91
|
+
/** The items of the group. */
|
|
92
|
+
children: Snippet;
|
|
93
|
+
};
|
|
94
|
+
/** @propsmith MenuItemProps */
|
|
95
|
+
export type MenuItemProps = {
|
|
96
|
+
/** The icon to display before the label.
|
|
97
|
+
* @type Snippet | Component
|
|
98
|
+
*/
|
|
99
|
+
icon?: Snippet<[{
|
|
100
|
+
class: string;
|
|
101
|
+
}]> | Component<{
|
|
102
|
+
class: string;
|
|
103
|
+
}>;
|
|
104
|
+
/** Right aligned text, usually a keyboard shortcut. */
|
|
105
|
+
secondaryContent?: string;
|
|
106
|
+
/** Disables the user interaction. */
|
|
107
|
+
disabled?: boolean;
|
|
108
|
+
/** A second line of text below the label. */
|
|
109
|
+
subText?: string;
|
|
110
|
+
/** Renders the item as a link pointing to this URL. */
|
|
111
|
+
href?: string;
|
|
112
|
+
};
|
|
113
|
+
/** @propsmith MenuItemActionableProps */
|
|
114
|
+
export type MenuItemActionableProps = {
|
|
115
|
+
/** Whether the item is checked.
|
|
116
|
+
* @bindable
|
|
117
|
+
*/
|
|
118
|
+
checked?: boolean;
|
|
119
|
+
/** The value reported to the menu when the item is checked. Falls back to the id of the item.
|
|
120
|
+
* @default id
|
|
121
|
+
*/
|
|
122
|
+
value?: string;
|
|
123
|
+
/** The group of items this one belongs to. Falls back to the id of the item.
|
|
124
|
+
* @default id
|
|
125
|
+
*/
|
|
126
|
+
name?: string;
|
|
127
|
+
} & Omit<MenuItemProps, 'href'> & ComponentProps<typeof Button<'div'>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Number Box
|
|
2
|
+
|
|
3
|
+
The NumberBox component allows users to input numeric values with specified constraints such as minimum, maximum, and step values.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```svelte
|
|
8
|
+
<script>
|
|
9
|
+
import { NumberBox } from 'fluentui-svelte';
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<NumberBox value={0} min={0} max={100} step={1} />
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Component API
|
|
16
|
+
|
|
17
|
+
A brief explanation of the props that really need explaining. You can see the rest of the props in the Component Props table below.
|
|
18
|
+
|
|
19
|
+
## Examples
|
|
20
|
+
|
|
21
|
+
### Variant
|
|
22
|
+
|
|
23
|
+
The variant prop determines the visual style of the NumberBox.
|
|
24
|
+
|
|
25
|
+
```svelte
|
|
26
|
+
<NumberBox hideActionButtons min={0} max={100} step={1} />
|
|
27
|
+
<NumberBox hideActionButtons min={0} max={100} step={1} variant="compact" />
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Component Props
|
|
31
|
+
|
|
32
|
+
| Name | Type | Description |
|
|
33
|
+
| ------------- | ----------------------- | ------------------------------------------------------------- |
|
|
34
|
+
| `value` | `number` | The current value of the NumberBox. |
|
|
35
|
+
| `variant` | `'inline' \| 'compact'` | The visual style of the NumberBox, e.g., 'inline', 'compact'. |
|
|
36
|
+
| `ref` | `HTMLInputElement` | The DOM reference to the input element. |
|
|
37
|
+
| TextBox Props | | Additional props inherited from the TextBox component. |
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { on } from 'svelte/events';
|
|
3
|
+
import { floating } from '../../internal/index.js';
|
|
4
|
+
import { offset, shift } from '@floating-ui/dom';
|
|
5
|
+
import { Flyout, TextBoxButton, TextBox } from '../../index.js';
|
|
6
|
+
import { ChevronUpFilled, ChevronDownFilled, ChevronUpDownFilled } from 'fluentui-icons-svelte';
|
|
7
|
+
import type { NumberBoxProps } from './types.js';
|
|
8
|
+
|
|
9
|
+
const ID = $props.id();
|
|
10
|
+
|
|
11
|
+
let {
|
|
12
|
+
id = 'input-' + ID,
|
|
13
|
+
name = id,
|
|
14
|
+
value = $bindable(),
|
|
15
|
+
variant = 'inline',
|
|
16
|
+
ref = $bindable(),
|
|
17
|
+
placeholder = '',
|
|
18
|
+
class: classes,
|
|
19
|
+
...attributes
|
|
20
|
+
}: NumberBoxProps = $props();
|
|
21
|
+
|
|
22
|
+
let openFlyout = $state(false);
|
|
23
|
+
let cleanEvent: () => void;
|
|
24
|
+
|
|
25
|
+
let handler = (e: Event) => {
|
|
26
|
+
if (!(e.target as HTMLElement).closest(`.${id}`)) {
|
|
27
|
+
openFlyout = false;
|
|
28
|
+
cleanEvent();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const compactToggler = () => {
|
|
33
|
+
openFlyout = true;
|
|
34
|
+
cleanEvent = on(document, 'click', handler);
|
|
35
|
+
};
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<!-- @component
|
|
39
|
+
A number box component that displays a number input with an optional increase and decrease button.
|
|
40
|
+
- Usage:
|
|
41
|
+
```tsx
|
|
42
|
+
<script>
|
|
43
|
+
import { NumberBox } from 'fluentui-svelte';
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<NumberBox />
|
|
47
|
+
```
|
|
48
|
+
-->
|
|
49
|
+
<TextBox class={['fs-number-box', classes]} type="number" {id} {name} {placeholder} bind:value bind:ref {...attributes}>
|
|
50
|
+
{#if variant === 'inline'}
|
|
51
|
+
<TextBoxButton aria-label="Increase Number" onclick={() => (value = value ? ++value : 1)}>
|
|
52
|
+
<ChevronUpFilled />
|
|
53
|
+
</TextBoxButton>
|
|
54
|
+
<TextBoxButton aria-label="Decrease Number" onclick={() => (value = value ? --value : -1)}>
|
|
55
|
+
<ChevronDownFilled />
|
|
56
|
+
</TextBoxButton>
|
|
57
|
+
{:else}
|
|
58
|
+
<TextBoxButton aria-label="Open" onclick={() => compactToggler()}>
|
|
59
|
+
<ChevronUpDownFilled />
|
|
60
|
+
</TextBoxButton>
|
|
61
|
+
{#if openFlyout}
|
|
62
|
+
<div
|
|
63
|
+
class="flyout-absolute"
|
|
64
|
+
{@attach ref
|
|
65
|
+
? floating(ref, {
|
|
66
|
+
placement: 'right',
|
|
67
|
+
middleware: [
|
|
68
|
+
shift({
|
|
69
|
+
crossAxis: true
|
|
70
|
+
}),
|
|
71
|
+
offset(({ rects }) => {
|
|
72
|
+
return -rects.reference.width / 1.4;
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
})
|
|
76
|
+
: undefined}
|
|
77
|
+
>
|
|
78
|
+
<Flyout>
|
|
79
|
+
<div class="flex-column">
|
|
80
|
+
<TextBoxButton aria-label="Increase Number" onclick={() => (value = value ? ++value : 1)}>
|
|
81
|
+
<ChevronUpFilled />
|
|
82
|
+
</TextBoxButton>
|
|
83
|
+
<TextBoxButton aria-label="Decrease Number" onclick={() => (value = value ? --value : -1)}>
|
|
84
|
+
<ChevronDownFilled />
|
|
85
|
+
</TextBoxButton>
|
|
86
|
+
</div>
|
|
87
|
+
</Flyout>
|
|
88
|
+
</div>
|
|
89
|
+
{/if}
|
|
90
|
+
{/if}
|
|
91
|
+
</TextBox>
|
|
92
|
+
|
|
93
|
+
<style>
|
|
94
|
+
.flyout-absolute {
|
|
95
|
+
position: absolute;
|
|
96
|
+
right: 0;
|
|
97
|
+
top: 0;
|
|
98
|
+
z-index: 2;
|
|
99
|
+
& :global(.fs-flyout) {
|
|
100
|
+
padding: 8px;
|
|
101
|
+
}
|
|
102
|
+
& div.flex-column {
|
|
103
|
+
display: flex;
|
|
104
|
+
flex-direction: column;
|
|
105
|
+
gap: 12px;
|
|
106
|
+
& :global(button) {
|
|
107
|
+
margin: 0;
|
|
108
|
+
& :global(svg) {
|
|
109
|
+
width: 1.6rem;
|
|
110
|
+
height: 1.6rem;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { NumberBoxProps } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* A number box component that displays a number input with an optional increase and decrease button.
|
|
4
|
+
* - Usage:
|
|
5
|
+
* ```tsx
|
|
6
|
+
* <script>
|
|
7
|
+
* import { NumberBox } from 'fluentui-svelte';
|
|
8
|
+
* </script>
|
|
9
|
+
*
|
|
10
|
+
* <NumberBox />
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
declare const NumberBox: import("svelte").Component<NumberBoxProps, {}, "ref" | "value">;
|
|
14
|
+
type NumberBox = ReturnType<typeof NumberBox>;
|
|
15
|
+
export default NumberBox;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { TextBoxProps } from '../text-box/types.ts';
|
|
2
|
+
/** @propsmith NumberBoxProps */
|
|
3
|
+
export type NumberBoxProps = {
|
|
4
|
+
/** The current value of the input.
|
|
5
|
+
* @bindable
|
|
6
|
+
*/
|
|
7
|
+
value?: number;
|
|
8
|
+
/** How the increment and decrement buttons are laid out.
|
|
9
|
+
*
|
|
10
|
+
* `inline`: the buttons sit inside the input, one next to the other.
|
|
11
|
+
*
|
|
12
|
+
* `compact`: the buttons are stacked in a flyout, opened from inside the input.
|
|
13
|
+
* @default 'inline'
|
|
14
|
+
*/
|
|
15
|
+
variant?: 'inline' | 'compact';
|
|
16
|
+
} & Omit<TextBoxProps, 'type'>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|