fluent-svelte-extra 1.0.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.
Files changed (145) hide show
  1. package/.prettierignore +1 -0
  2. package/.prettierrc +7 -0
  3. package/CHANGELOG.md +7 -0
  4. package/LICENSE +21 -0
  5. package/README.md +33 -0
  6. package/package.json +83 -0
  7. package/src/app.html +12 -0
  8. package/src/global.d.ts +1 -0
  9. package/src/lib/AutoSuggestBox/AutoSuggestBox.scss +44 -0
  10. package/src/lib/AutoSuggestBox/AutoSuggestBox.svelte +173 -0
  11. package/src/lib/Button/Button.scss +94 -0
  12. package/src/lib/Button/Button.svelte +48 -0
  13. package/src/lib/CalendarDatePicker/CalendarDatePicker.scss +15 -0
  14. package/src/lib/CalendarDatePicker/CalendarDatePicker.svelte +86 -0
  15. package/src/lib/CalendarView/CalendarView.scss +156 -0
  16. package/src/lib/CalendarView/CalendarView.svelte +753 -0
  17. package/src/lib/CalendarView/CalendarViewItem.scss +130 -0
  18. package/src/lib/CalendarView/CalendarViewItem.svelte +33 -0
  19. package/src/lib/Checkbox/Checkbox.scss +117 -0
  20. package/src/lib/Checkbox/Checkbox.svelte +81 -0
  21. package/src/lib/ComboBox/ComboBox.scss +152 -0
  22. package/src/lib/ComboBox/ComboBox.svelte +360 -0
  23. package/src/lib/ComboBox/ComboBoxItem.scss +80 -0
  24. package/src/lib/ComboBox/ComboBoxItem.svelte +30 -0
  25. package/src/lib/ContentDialog/ContentDialog.scss +68 -0
  26. package/src/lib/ContentDialog/ContentDialog.svelte +123 -0
  27. package/src/lib/ContextMenu/ContextMenu.scss +11 -0
  28. package/src/lib/ContextMenu/ContextMenu.svelte +104 -0
  29. package/src/lib/Expander/Expander.scss +134 -0
  30. package/src/lib/Expander/Expander.svelte +123 -0
  31. package/src/lib/Flipper/Flipper.svelte +49 -0
  32. package/src/lib/Flyout/FlyoutSurface.scss +14 -0
  33. package/src/lib/Flyout/FlyoutSurface.svelte +21 -0
  34. package/src/lib/Flyout/FlyoutWrapper.scss +81 -0
  35. package/src/lib/Flyout/FlyoutWrapper.svelte +126 -0
  36. package/src/lib/IconButton/IconButton.scss +31 -0
  37. package/src/lib/IconButton/IconButton.svelte +49 -0
  38. package/src/lib/InfoBadge/InfoBadge.scss +39 -0
  39. package/src/lib/InfoBadge/InfoBadge.svelte +81 -0
  40. package/src/lib/InfoBar/InfoBar.scss +122 -0
  41. package/src/lib/InfoBar/InfoBar.svelte +133 -0
  42. package/src/lib/ListItem/ListItem.scss +74 -0
  43. package/src/lib/ListItem/ListItem.svelte +88 -0
  44. package/src/lib/MenuBar/MenuBar.scss +10 -0
  45. package/src/lib/MenuBar/MenuBar.svelte +49 -0
  46. package/src/lib/MenuBar/MenuBarItem.scss +38 -0
  47. package/src/lib/MenuBar/MenuBarItem.svelte +135 -0
  48. package/src/lib/MenuBar/flyoutState.ts +5 -0
  49. package/src/lib/MenuFlyout/MenuFlyoutDivider.scss +7 -0
  50. package/src/lib/MenuFlyout/MenuFlyoutDivider.svelte +14 -0
  51. package/src/lib/MenuFlyout/MenuFlyoutItem.scss +147 -0
  52. package/src/lib/MenuFlyout/MenuFlyoutItem.svelte +239 -0
  53. package/src/lib/MenuFlyout/MenuFlyoutSurface.scss +42 -0
  54. package/src/lib/MenuFlyout/MenuFlyoutSurface.svelte +28 -0
  55. package/src/lib/MenuFlyout/MenuFlyoutWrapper.scss +64 -0
  56. package/src/lib/MenuFlyout/MenuFlyoutWrapper.svelte +114 -0
  57. package/src/lib/NavigationView/NavigationView.scss +0 -0
  58. package/src/lib/NavigationView/NavigationView.svelte +82 -0
  59. package/src/lib/NumberBox/NumberBox.scss +31 -0
  60. package/src/lib/NumberBox/NumberBox.svelte +267 -0
  61. package/src/lib/PersonPicture/PersonPicture.scss +35 -0
  62. package/src/lib/PersonPicture/PersonPicture.svelte +62 -0
  63. package/src/lib/ProgressBar/ProgressBar.scss +83 -0
  64. package/src/lib/ProgressBar/ProgressBar.svelte +60 -0
  65. package/src/lib/ProgressRing/ProgressRing.scss +37 -0
  66. package/src/lib/ProgressRing/ProgressRing.svelte +73 -0
  67. package/src/lib/RadioButton/RadioButton.scss +114 -0
  68. package/src/lib/RadioButton/RadioButton.svelte +67 -0
  69. package/src/lib/RangeSlider/RangeSlider.svelte +91 -0
  70. package/src/lib/ScrollView/ScrollView.svelte +9 -0
  71. package/src/lib/Slider/Slider.scss +263 -0
  72. package/src/lib/Slider/Slider.svelte +261 -0
  73. package/src/lib/TextBlock/TextBlock.scss +62 -0
  74. package/src/lib/TextBlock/TextBlock.svelte +70 -0
  75. package/src/lib/TextBox/TextBox.scss +108 -0
  76. package/src/lib/TextBox/TextBox.svelte +225 -0
  77. package/src/lib/TextBox/TextBoxButton.scss +34 -0
  78. package/src/lib/TextBox/TextBoxButton.svelte +27 -0
  79. package/src/lib/ToggleSwitch/ToggleSwitch.scss +118 -0
  80. package/src/lib/ToggleSwitch/ToggleSwitch.svelte +55 -0
  81. package/src/lib/Tooltip/TooltipSurface.scss +16 -0
  82. package/src/lib/Tooltip/TooltipSurface.svelte +27 -0
  83. package/src/lib/Tooltip/TooltipWrapper.scss +66 -0
  84. package/src/lib/Tooltip/TooltipWrapper.svelte +117 -0
  85. package/src/lib/_mixins.scss +130 -0
  86. package/src/lib/index.ts +33 -0
  87. package/src/lib/internal.ts +213 -0
  88. package/src/lib/svelte-jsx.d.ts +14 -0
  89. package/src/lib/theme.css +414 -0
  90. package/src/routes/__layout.svelte +48 -0
  91. package/src/routes/docs/__layout.svelte +122 -0
  92. package/src/routes/docs/components/button.md +43 -0
  93. package/src/routes/docs/components/calendarview.md +188 -0
  94. package/src/routes/docs/components/checkbox.md +87 -0
  95. package/src/routes/docs/components/contentdialog.md +155 -0
  96. package/src/routes/docs/components/expander.md +115 -0
  97. package/src/routes/docs/components/flyout.md +107 -0
  98. package/src/routes/docs/components/iconbutton.md +39 -0
  99. package/src/routes/docs/components/infobadge.md +54 -0
  100. package/src/routes/docs/components/infobar.md +102 -0
  101. package/src/routes/docs/components/listitem.md +87 -0
  102. package/src/routes/docs/components/personpicture.md +125 -0
  103. package/src/routes/docs/components/progressring.md +83 -0
  104. package/src/routes/docs/components/radiobutton.md +88 -0
  105. package/src/routes/docs/components/slider.md +165 -0
  106. package/src/routes/docs/components/textblock.md +46 -0
  107. package/src/routes/docs/components/textbox.md +124 -0
  108. package/src/routes/docs/components/toggleswitch.md +73 -0
  109. package/src/routes/docs/getting-started.md +116 -0
  110. package/src/routes/docs/index.md +37 -0
  111. package/src/routes/docs/internals/index.md +0 -0
  112. package/src/routes/index.svelte +121 -0
  113. package/src/routes/test/__layout-test.svelte +1 -0
  114. package/src/routes/test/index.svelte +757 -0
  115. package/src/routes/test/nav.svelte +7 -0
  116. package/src/site/data/docs.ts +176 -0
  117. package/src/site/data/home.ts +12 -0
  118. package/src/site/lib/APIDocs/APIDocs.svelte +178 -0
  119. package/src/site/lib/APIDocs/ParsedComponent.d.ts +85 -0
  120. package/src/site/lib/CopyBox/CopyBox.svelte +23 -0
  121. package/src/site/lib/Example/Example.scss +33 -0
  122. package/src/site/lib/Example/Example.svelte +18 -0
  123. package/src/site/lib/HeroCard/HeroCard.scss +24 -0
  124. package/src/site/lib/HeroCard/HeroCard.svelte +36 -0
  125. package/src/site/lib/Metadata/Metadata.svelte +14 -0
  126. package/src/site/lib/Navbar/Navbar.scss +92 -0
  127. package/src/site/lib/Navbar/Navbar.svelte +47 -0
  128. package/src/site/lib/PageSection/PageSection.scss +57 -0
  129. package/src/site/lib/PageSection/PageSection.svelte +10 -0
  130. package/src/site/lib/Showcase/Showcase.scss +53 -0
  131. package/src/site/lib/Showcase/Showcase.svelte +67 -0
  132. package/src/site/lib/Toc/Toc.scss +18 -0
  133. package/src/site/lib/Toc/Toc.svelte +59 -0
  134. package/src/site/lib/TreeView/TreeView.svelte +89 -0
  135. package/src/site/lib/index.ts +9 -0
  136. package/src/site/styles/_markdown.scss +260 -0
  137. package/src/site/styles/_mixins.scss +319 -0
  138. package/src/site/styles/global.scss +40 -0
  139. package/src/site/styles/pages/docs.scss +74 -0
  140. package/src/site/styles/pages/home.scss +134 -0
  141. package/static/bloom-mica-dark.png +0 -0
  142. package/static/bloom-mica-light.png +0 -0
  143. package/static/logo.svg +11 -0
  144. package/svelte.config.js +57 -0
  145. package/tsconfig.json +38 -0
@@ -0,0 +1,135 @@
1
+ <script lang="ts">
2
+ import type { SvelteComponentTyped } from "svelte";
3
+
4
+ import { currentMenu } from "./flyoutState";
5
+
6
+ import { tabbable } from "tabbable";
7
+ import { createEventDispatcher, getContext, setContext } from "svelte";
8
+ import { get_current_component } from "svelte/internal";
9
+ import { createEventForwarder, arrowNavigation, externalMouseEvents, uid } from "$lib/internal";
10
+
11
+ import MenuFlyoutSurface from "../MenuFlyout/MenuFlyoutSurface.svelte";
12
+
13
+ /** The current visibility state of the item's menu. */
14
+ export let open = false;
15
+
16
+ /** Controls whether the item is intended for user interaction, and styles it accordingly. */
17
+ export let disabled = false;
18
+
19
+ /** Specifies a custom class name for the item. */
20
+ let className = "";
21
+ export { className as class };
22
+
23
+ /** Obtains a bound DOM reference to the item. */
24
+ export let element: HTMLLIElement = null;
25
+
26
+ /** Obtains a bound DOM reference to the menu's positioning anchor element. */
27
+ export let anchorElement: HTMLDivElement = null;
28
+
29
+ /** Obtains a bound DOM reference to the inner menu element. */
30
+ export let menuElement: HTMLUListElement = null;
31
+
32
+ let menu: SvelteComponentTyped;
33
+
34
+ const forwardEvents = createEventForwarder(get_current_component(), [
35
+ "open",
36
+ "close",
37
+ "select"
38
+ ]);
39
+ const dispatch = createEventDispatcher();
40
+ const menuId = uid("fds-menu-flyout-anchor-");
41
+ const handleSideNavigation =
42
+ getContext<(event: Event, activeItem: HTMLElement) => void>("sideNavigation");
43
+
44
+ $: if ($currentMenu !== menu) open = false;
45
+ $: if (!menu && element) element.focus();
46
+ $: if (menu) {
47
+ focusFirstItem();
48
+ $currentMenu = menu;
49
+ } else {
50
+ $currentMenu = null;
51
+ }
52
+ $: if ($$slots.flyout && open && !disabled) {
53
+ if (open) {
54
+ dispatch("open");
55
+ } else {
56
+ dispatch("close");
57
+ }
58
+ }
59
+
60
+ function focusFirstItem() {
61
+ if (open && menu && tabbable(menuElement).length > 0) tabbable(menuElement)[0].focus();
62
+ }
63
+
64
+ function handleEscapeKey({ key }: KeyboardEvent) {
65
+ if (key === "Escape") open = false;
66
+ }
67
+
68
+ function handleMouseEnter() {
69
+ if ($currentMenu && $$slots.flyout) {
70
+ $currentMenu = menu;
71
+ open = true;
72
+ }
73
+ }
74
+
75
+ function handleKeyDown({ key }) {
76
+ if (key === "Enter" || key === " ") {
77
+ event.preventDefault();
78
+ open = !open;
79
+ }
80
+ }
81
+
82
+ function handleFocus() {
83
+ if (open) {
84
+ focusFirstItem();
85
+ } else if ($currentMenu) {
86
+ $currentMenu = menu;
87
+ open = true;
88
+ }
89
+ }
90
+
91
+ setContext("closeFlyout", event => {
92
+ dispatch("select");
93
+ event.stopPropagation();
94
+ open = false;
95
+ });
96
+ </script>
97
+
98
+ <svelte:window on:keydown={handleEscapeKey} />
99
+
100
+ <li
101
+ use:forwardEvents
102
+ class="menu-bar-item {className}"
103
+ class:disabled
104
+ role="menuitem"
105
+ tabindex={disabled ? -1 : 0}
106
+ aria-expanded={$$slots.flyout && !disabled && open}
107
+ aria-haspopup={$$slots.flyout && !disabled && open}
108
+ aria-controls={$$slots.flyout && !disabled && menuId}
109
+ bind:this={element}
110
+ on:keydown={event => handleSideNavigation(event, element)}
111
+ on:keydown|self={handleKeyDown}
112
+ on:focus={handleFocus}
113
+ on:mousedown={() => (open = !open)}
114
+ on:mouseenter={handleMouseEnter}
115
+ {...$$restProps}
116
+ >
117
+ <slot />
118
+ {#if $$slots.flyout && open && !disabled}
119
+ <div
120
+ class="menu-flyout-anchor"
121
+ use:arrowNavigation={{ preventTab: true }}
122
+ use:externalMouseEvents={{ type: "mousedown", stopPropagation: true }}
123
+ on:outermousedown={() => (open = false)}
124
+ bind:this={anchorElement}
125
+ >
126
+ <MenuFlyoutSurface bind:element={menuElement} bind:this={menu}>
127
+ <slot name="flyout" />
128
+ </MenuFlyoutSurface>
129
+ </div>
130
+ {/if}
131
+ </li>
132
+
133
+ <style lang="scss">
134
+ @use "./MenuBarItem";
135
+ </style>
@@ -0,0 +1,5 @@
1
+ import type { SvelteComponentTyped } from "svelte";
2
+
3
+ import { writable } from "svelte/store";
4
+
5
+ export const currentMenu = writable<SvelteComponentTyped>(null);
@@ -0,0 +1,7 @@
1
+ .menu-flyout-divider {
2
+ inline-size: 100%;
3
+ margin-block: 2px;
4
+ block-size: 1px;
5
+ border: none;
6
+ border-block-start: 1px solid var(--divider-stroke-default);
7
+ }
@@ -0,0 +1,14 @@
1
+ <script lang="ts">
2
+ /** Specifies a custom class name for the divider. */
3
+ let className = "";
4
+ export { className as class };
5
+
6
+ /** Obtains a bound DOM reference to the divider's element. */
7
+ export let element: HTMLElement = null;
8
+ </script>
9
+
10
+ <hr class="menu-flyout-divider {className}" bind:this={element} {...$$restProps} />
11
+
12
+ <style lang="scss">
13
+ @use "./MenuFlyoutDivider";
14
+ </style>
@@ -0,0 +1,147 @@
1
+ @use "../mixins" as *;
2
+
3
+ .menu-flyout-item {
4
+ @include flex($align: center);
5
+ @include typography-body;
6
+
7
+ inline-size: calc(100% - 8px);
8
+ position: relative;
9
+ box-sizing: border-box;
10
+ flex: 0 0 auto;
11
+ // overflow: hidden;
12
+ margin: 2px 4px;
13
+ padding-inline: 12px;
14
+ border-radius: var(--control-corner-radius);
15
+ outline: none;
16
+ background-color: var(--subtle-fill-transparent);
17
+ color: var(--text-primary);
18
+ text-decoration: none;
19
+ cursor: default;
20
+ user-select: none;
21
+ block-size: 28px;
22
+ white-space: nowrap;
23
+ text-overflow: ellipsis;
24
+ text-decoration: none;
25
+
26
+ &::before {
27
+ content: "";
28
+ position: absolute;
29
+ border-radius: 3px;
30
+ background-color: var(--accent-default);
31
+ transition: transform var(--control-fast-duration) var(--control-fast-out-slow-in-easing);
32
+ opacity: 0;
33
+ inset-inline-start: 0;
34
+ inline-size: 3px;
35
+ block-size: 0;
36
+ }
37
+
38
+ &:focus-visible {
39
+ box-shadow: var(--focus-stroke);
40
+ }
41
+
42
+ &:hover,
43
+ &[aria-expanded="true"],
44
+ &.selected {
45
+ background-color: var(--subtle-fill-secondary);
46
+ }
47
+
48
+ &.checked {
49
+ :global {
50
+ .menu-flyout-item- {
51
+ &bullet,
52
+ &checkmark {
53
+ visibility: visible;
54
+ }
55
+ }
56
+ }
57
+ }
58
+
59
+ &:active {
60
+ background-color: var(--subtle-fill-tertiary);
61
+
62
+ &::before {
63
+ transform: scaleY(0.625);
64
+ }
65
+ }
66
+
67
+ &.disabled {
68
+ background-color: var(--subtle-fill-transparent);
69
+ color: var(--text-disabled);
70
+ pointer-events: none;
71
+ &.selected {
72
+ background-color: var(--subtle-fill-secondary);
73
+ &::before {
74
+ background-color: var(--accent-disabled);
75
+ }
76
+ }
77
+ > :global(.menu-flyout-item-hint) {
78
+ color: var(--text-disabled);
79
+ }
80
+ }
81
+
82
+ &.selected::before {
83
+ opacity: 1;
84
+ block-size: 16px;
85
+ }
86
+
87
+ &.indented {
88
+ padding-inline-start: 40px;
89
+ }
90
+
91
+ &-checkmark,
92
+ &-bullet {
93
+ visibility: hidden;
94
+ }
95
+
96
+ & &-arrow {
97
+ box-sizing: content-box;
98
+ inline-size: 12px;
99
+ block-size: 12px;
100
+ margin-inline-end: 0;
101
+ margin-inline-start: auto;
102
+ padding-inline-start: 24px;
103
+ }
104
+
105
+ &-checkmark {
106
+ @include flex($align: center, $justify: center);
107
+ inline-size: 12px;
108
+ block-size: 12px;
109
+ margin-inline-start: 2px;
110
+ margin-inline-end: 14px;
111
+ }
112
+
113
+ &-bullet {
114
+ inline-size: 4px;
115
+ block-size: 4px;
116
+ border-radius: 4px;
117
+ margin-inline-start: 6px;
118
+ margin-inline-end: 18px;
119
+ background-color: currentColor;
120
+ }
121
+
122
+ &-input-label {
123
+ display: contents;
124
+ }
125
+
126
+ > :global(svg) {
127
+ @include icon($size: 16px);
128
+ margin-inline-end: 12px;
129
+ }
130
+
131
+ > :global(.menu-flyout-item-hint) {
132
+ flex: 1 1 auto;
133
+ text-align: end;
134
+ padding-left: 24px;
135
+ overflow: hidden;
136
+ text-overflow: ellipsis;
137
+ color: var(--text-secondary);
138
+ }
139
+ }
140
+
141
+ .menu-flyout-submenu-anchor {
142
+ --fds-menu-flyout-transition-offset: -50%;
143
+ z-index: 10000;
144
+ position: absolute;
145
+ inset-block-start: 0;
146
+ inset-inline-start: 100%;
147
+ }
@@ -0,0 +1,239 @@
1
+ <script lang="ts">
2
+ import type { SvelteComponentTyped } from "svelte";
3
+
4
+ import { createEventDispatcher, getContext } from "svelte";
5
+ import { get_current_component } from "svelte/internal";
6
+
7
+ import { arrowNavigation, uid, createEventForwarder } from "$lib/internal";
8
+ import { tabbable } from "tabbable";
9
+
10
+ import MenuFlyoutSurface from "../MenuFlyout/MenuFlyoutSurface.svelte";
11
+ import TextBlock from "../TextBlock/TextBlock.svelte";
12
+
13
+ /** Specifies an input type for the item. */
14
+ export let variant: "standard" | "radio" | "toggle" = "standard";
15
+
16
+ /** Marks the item as having a cascading submenu attached to it, and makes the `flyout` slot available. */
17
+ export let cascading = false;
18
+
19
+ /** Secondary hint text displayed to the right of the item. Useful for displaying keyboard accelerators. */
20
+ export let hint: string = undefined;
21
+
22
+ /** Specifies if the item should be styled as selected by the user. */
23
+ export let selected = false;
24
+
25
+ /** Marks a radio or toggle variant item as checked. */
26
+ export let checked = false;
27
+
28
+ /** Indents the left padding of the item making it's text inline with the added icons of other items. */
29
+ export let indented = false;
30
+
31
+ /** Specifies a radio input group that the item should be bound to. Only valid if `variant` is set to `radio`. */
32
+ export let group: any = [];
33
+
34
+ /** Specifies a form input value attribute if `variant` is set to `toggle` or `radio`. */
35
+ export let value: any = undefined;
36
+
37
+ /** Controls whether the item is intended for user interaction, and styles it accordingly. */
38
+ export let disabled = false;
39
+
40
+ /** The current visibility state of a cascading submenu. Only valid is `cascading` is true. */
41
+ export let open = false;
42
+
43
+ /** INTERNAL USE ONLY: Communicates to the wrapped <svelte:self /> instance that the item variant should not be recursively rendered. */
44
+ export let __depth = false;
45
+
46
+ /** Specifies a custom class name for the item. */
47
+ let className = "";
48
+ export { className as class };
49
+
50
+ /** Obtains a bound DOM reference to the item's main container. */
51
+ export let element: HTMLLIElement = null;
52
+
53
+ /** Obtains a bound DOM reference to the item's input element, which is present if `variant` is set to `toggle` or `radio`. */
54
+ export let inputElement: HTMLInputElement = null;
55
+
56
+ /** Obtains a bound DOM reference to the item's outer label, which is present if `variant` is set to `toggle` or `radio`. */
57
+ export let inputLabelElement: HTMLLabelElement = null;
58
+
59
+ /** Obtains a bound DOM reference to the item's submenu anchor element, which is present if the item is cascading and the submenu is visible. */
60
+ export let subMenuAnchorElement: HTMLDivElement = null;
61
+
62
+ /** Obtains a bound DOM reference to the inner submenumenu element, which is present if the item is cascading and the submenu is visible. */
63
+ export let subMenuElement: HTMLUListElement = null;
64
+
65
+ const forwardEvents = createEventForwarder(get_current_component());
66
+ const dispatch = createEventDispatcher();
67
+ const closeFlyout = getContext<(event: Event) => void>("closeFlyout");
68
+ const menuId = uid("fds-menu-flyout-submenu-");
69
+
70
+ let menu: SvelteComponentTyped = null;
71
+ let subMenuQueue = {
72
+ open: false,
73
+ close: false
74
+ };
75
+
76
+ $: dispatch(open ? "open" : "close");
77
+ $: if (open && menu && tabbable(subMenuElement).length > 0) tabbable(subMenuElement)[0].focus();
78
+
79
+ function close(event) {
80
+ setTimeout(() => {
81
+ if (!cascading && closeFlyout) closeFlyout(event);
82
+ });
83
+ }
84
+
85
+ function handleKeyDown(event) {
86
+ const { key, target } = event;
87
+ if (key === "Enter" || key === " ") {
88
+ event.preventDefault();
89
+ target.click();
90
+ }
91
+ if (cascading) {
92
+ if (key === "ArrowRight") {
93
+ event.stopPropagation();
94
+ open = true;
95
+ } else if (open && key === "ArrowLeft") {
96
+ event.stopPropagation();
97
+ open = false;
98
+ element.focus();
99
+ }
100
+ }
101
+ }
102
+
103
+ function handleMouseEnter() {
104
+ subMenuQueue.close = false;
105
+ subMenuQueue.open = true;
106
+ setTimeout(() => {
107
+ if (subMenuQueue.open) open = true;
108
+ }, 500);
109
+ }
110
+
111
+ function handleMouseLeave() {
112
+ subMenuQueue.close = true;
113
+ subMenuQueue.open = false;
114
+ setTimeout(() => {
115
+ if (subMenuQueue.close) open = false;
116
+ }, 500);
117
+ }
118
+ </script>
119
+
120
+ {#if variant === "standard" || __depth}
121
+ <li
122
+ tabindex={disabled ? -1 : 0}
123
+ role="menuitem"
124
+ aria-expanded={$$slots.flyout && !disabled && open}
125
+ aria-haspopup={$$slots.flyout && !disabled && open}
126
+ aria-controls={$$slots.flyout && !disabled && menuId}
127
+ aria-selected={selected || checked}
128
+ class="menu-flyout-item type-{variant} {className}"
129
+ class:cascading
130
+ class:selected
131
+ class:checked
132
+ class:disabled
133
+ class:indented
134
+ use:forwardEvents
135
+ bind:this={element}
136
+ on:click={close}
137
+ on:mouseenter={handleMouseEnter}
138
+ on:mouseleave={handleMouseLeave}
139
+ on:keydown={handleKeyDown}
140
+ {...$$restProps}
141
+ >
142
+ <slot name="icon" />
143
+ <slot />
144
+ {#if hint}
145
+ <TextBlock class="menu-flyout-item-hint" variant="caption">{hint}</TextBlock>
146
+ {/if}
147
+ {#if cascading}
148
+ <svg
149
+ class="menu-flyout-item-arrow"
150
+ xmlns="http://www.w3.org/2000/svg"
151
+ width="12"
152
+ height="12"
153
+ viewBox="0 0 12 12"
154
+ fill="none"
155
+ >
156
+ <path
157
+ d="M4.64645 2.14645C4.45118 2.34171 4.45118 2.65829 4.64645 2.85355L7.79289 6L4.64645 9.14645C4.45118 9.34171 4.45118 9.65829 4.64645 9.85355C4.84171 10.0488 5.15829 10.0488 5.35355 9.85355L8.85355 6.35355C9.04882 6.15829 9.04882 5.84171 8.85355 5.64645L5.35355 2.14645C5.15829 1.95118 4.84171 1.95118 4.64645 2.14645Z"
158
+ fill="currentColor"
159
+ />
160
+ </svg>
161
+ {#if open && $$slots.flyout && !disabled}
162
+ <div
163
+ use:arrowNavigation={{ preventTab: true, stopPropagation: true }}
164
+ bind:this={subMenuAnchorElement}
165
+ id={menuId}
166
+ class="menu-flyout-submenu-anchor"
167
+ >
168
+ <MenuFlyoutSurface bind:element={subMenuElement} bind:this={menu}>
169
+ <slot name="flyout" />
170
+ </MenuFlyoutSurface>
171
+ </div>
172
+ {/if}
173
+ {/if}
174
+ </li>
175
+ {:else if variant === "radio" || variant === "toggle"}
176
+ <!-- svelte-ignore a11y-label-has-associated-control -->
177
+ <label bind:this={inputLabelElement} class="menu-flyout-item-input-label">
178
+ <svelte:self
179
+ checked={checked || group === value}
180
+ {selected}
181
+ {variant}
182
+ {indented}
183
+ {group}
184
+ {disabled}
185
+ __depth
186
+ >
187
+ <slot name="icon" slot="icon" />
188
+ <div class="menu-flyout-item-{variant === 'radio' ? 'bullet' : 'checkmark'}">
189
+ {#if variant === "toggle"}
190
+ <svg
191
+ width="12"
192
+ height="12"
193
+ viewBox="0 0 12 12"
194
+ fill="none"
195
+ xmlns="http://www.w3.org/2000/svg"
196
+ >
197
+ <path
198
+ d="M9.85355 3.14645C10.0488 3.34171 10.0488 3.65829 9.85355 3.85355L5.35355 8.35355C5.15829 8.54882 4.84171 8.54882 4.64645 8.35355L2.64645 6.35355C2.45118 6.15829 2.45118 5.84171 2.64645 5.64645C2.84171 5.45118 3.15829 5.45118 3.35355 5.64645L5 7.29289L9.14645 3.14645C9.34171 2.95118 9.65829 2.95118 9.85355 3.14645Z"
199
+ fill="currentColor"
200
+ />
201
+ </svg>
202
+ {/if}
203
+ </div>
204
+ <slot />
205
+ </svelte:self>
206
+
207
+ {#if variant === "radio"}
208
+ <input
209
+ type="radio"
210
+ hidden
211
+ on:change
212
+ on:input
213
+ on:beforeinput
214
+ bind:group
215
+ bind:this={inputElement}
216
+ {value}
217
+ {checked}
218
+ {disabled}
219
+ />
220
+ {:else}
221
+ <input
222
+ type="checkbox"
223
+ hidden
224
+ on:change
225
+ on:input
226
+ on:beforeinput
227
+ bind:this={inputElement}
228
+ bind:group
229
+ bind:checked
230
+ bind:value
231
+ {disabled}
232
+ />
233
+ {/if}
234
+ </label>
235
+ {/if}
236
+
237
+ <style lang="scss">
238
+ @use "./MenuFlyoutItem";
239
+ </style>
@@ -0,0 +1,42 @@
1
+ @use "../mixins" as *;
2
+
3
+ @keyframes menu-open {
4
+ from {
5
+ transform: translateY(var(--menu-flyout-transition-offset, -50%));
6
+ }
7
+ to {
8
+ transform: none;
9
+ }
10
+ }
11
+
12
+ @keyframes menu-shadow {
13
+ from {
14
+ box-shadow: none;
15
+ }
16
+ to {
17
+ box-shadow: var(--flyout-shadow);
18
+ }
19
+ }
20
+
21
+ .menu-flyout {
22
+ @include typography-body;
23
+ @include flex($direction: column);
24
+ animation: menu-open var(--control-normal-duration) var(--control-fast-out-slow-in-easing),
25
+ menu-shadow var(--control-fast-duration) var(--control-fast-out-slow-in-easing)
26
+ var(--control-normal-duration) forwards;
27
+ min-inline-size: 120px;
28
+ max-inline-size: 100%;
29
+ max-block-size: 100vh;
30
+ margin: 0;
31
+ padding: 0;
32
+ padding-block: 2px;
33
+ box-sizing: border-box;
34
+ color: var(--text-primary);
35
+ border-radius: var(--overlay-corner-radius);
36
+ border: 1px solid var(--surface-stroke-flyout);
37
+ background-color: var(--solid-background-quarternary);
38
+ background-clip: padding-box;
39
+ &-surface-container {
40
+ overflow: hidden;
41
+ }
42
+ }
@@ -0,0 +1,28 @@
1
+ <script lang="ts">
2
+ /** Specifies a custom class name for the surface. */
3
+ let className = "";
4
+ export { className as class };
5
+
6
+ /** Obtains a bound DOM reference to the surface element. */
7
+ export let element: HTMLUListElement = null;
8
+
9
+ let animationComplete = false;
10
+ </script>
11
+
12
+ <div
13
+ class="menu-flyout-surface-container"
14
+ style={animationComplete ? "overflow: visible;" : undefined}
15
+ >
16
+ <ul
17
+ on:animationend|once={() => (animationComplete = true)}
18
+ class="menu-flyout {className}"
19
+ bind:this={element}
20
+ {...$$restProps}
21
+ >
22
+ <slot />
23
+ </ul>
24
+ </div>
25
+
26
+ <style lang="scss">
27
+ @use "./MenuFlyoutSurface";
28
+ </style>
@@ -0,0 +1,64 @@
1
+ .menu-flyout- {
2
+ &wrapper {
3
+ display: inline-block;
4
+ height: auto;
5
+ position: relative;
6
+ }
7
+ &backdrop {
8
+ position: fixed;
9
+ top: 0;
10
+ left: 0;
11
+ width: 100%;
12
+ height: 100%;
13
+ z-index: 9999;
14
+ }
15
+ &anchor {
16
+ position: absolute;
17
+ z-index: 10000;
18
+ &.placement- {
19
+ &top {
20
+ --fds-menu-flyout-transition-offset: 50%;
21
+ bottom: calc(100% + var(--menu-flyout-offset));
22
+ }
23
+ &bottom {
24
+ top: calc(100% + var(--menu-flyout-offset));
25
+ }
26
+ &left {
27
+ right: calc(100% + var(--menu-flyout-offset));
28
+ }
29
+ &right {
30
+ left: calc(100% + var(--menu-flyout-offset));
31
+ }
32
+ &top,
33
+ &bottom {
34
+ &.alignment- {
35
+ &start {
36
+ inset-inline-start: 0;
37
+ }
38
+ &end {
39
+ inset-inline-end: 0;
40
+ }
41
+ &center {
42
+ inset-inline-start: 50%;
43
+ transform: translateX(-50%);
44
+ }
45
+ }
46
+ }
47
+ &left,
48
+ &right {
49
+ &.alignment- {
50
+ &start {
51
+ inset-block-start: 0;
52
+ }
53
+ &end {
54
+ inset-block-end: 0;
55
+ }
56
+ &center {
57
+ inset-block-start: 50%;
58
+ transform: translateY(-50%);
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }