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.
- package/.prettierignore +1 -0
- package/.prettierrc +7 -0
- package/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/package.json +83 -0
- package/src/app.html +12 -0
- package/src/global.d.ts +1 -0
- package/src/lib/AutoSuggestBox/AutoSuggestBox.scss +44 -0
- package/src/lib/AutoSuggestBox/AutoSuggestBox.svelte +173 -0
- package/src/lib/Button/Button.scss +94 -0
- package/src/lib/Button/Button.svelte +48 -0
- package/src/lib/CalendarDatePicker/CalendarDatePicker.scss +15 -0
- package/src/lib/CalendarDatePicker/CalendarDatePicker.svelte +86 -0
- package/src/lib/CalendarView/CalendarView.scss +156 -0
- package/src/lib/CalendarView/CalendarView.svelte +753 -0
- package/src/lib/CalendarView/CalendarViewItem.scss +130 -0
- package/src/lib/CalendarView/CalendarViewItem.svelte +33 -0
- package/src/lib/Checkbox/Checkbox.scss +117 -0
- package/src/lib/Checkbox/Checkbox.svelte +81 -0
- package/src/lib/ComboBox/ComboBox.scss +152 -0
- package/src/lib/ComboBox/ComboBox.svelte +360 -0
- package/src/lib/ComboBox/ComboBoxItem.scss +80 -0
- package/src/lib/ComboBox/ComboBoxItem.svelte +30 -0
- package/src/lib/ContentDialog/ContentDialog.scss +68 -0
- package/src/lib/ContentDialog/ContentDialog.svelte +123 -0
- package/src/lib/ContextMenu/ContextMenu.scss +11 -0
- package/src/lib/ContextMenu/ContextMenu.svelte +104 -0
- package/src/lib/Expander/Expander.scss +134 -0
- package/src/lib/Expander/Expander.svelte +123 -0
- package/src/lib/Flipper/Flipper.svelte +49 -0
- package/src/lib/Flyout/FlyoutSurface.scss +14 -0
- package/src/lib/Flyout/FlyoutSurface.svelte +21 -0
- package/src/lib/Flyout/FlyoutWrapper.scss +81 -0
- package/src/lib/Flyout/FlyoutWrapper.svelte +126 -0
- package/src/lib/IconButton/IconButton.scss +31 -0
- package/src/lib/IconButton/IconButton.svelte +49 -0
- package/src/lib/InfoBadge/InfoBadge.scss +39 -0
- package/src/lib/InfoBadge/InfoBadge.svelte +81 -0
- package/src/lib/InfoBar/InfoBar.scss +122 -0
- package/src/lib/InfoBar/InfoBar.svelte +133 -0
- package/src/lib/ListItem/ListItem.scss +74 -0
- package/src/lib/ListItem/ListItem.svelte +88 -0
- package/src/lib/MenuBar/MenuBar.scss +10 -0
- package/src/lib/MenuBar/MenuBar.svelte +49 -0
- package/src/lib/MenuBar/MenuBarItem.scss +38 -0
- package/src/lib/MenuBar/MenuBarItem.svelte +135 -0
- package/src/lib/MenuBar/flyoutState.ts +5 -0
- package/src/lib/MenuFlyout/MenuFlyoutDivider.scss +7 -0
- package/src/lib/MenuFlyout/MenuFlyoutDivider.svelte +14 -0
- package/src/lib/MenuFlyout/MenuFlyoutItem.scss +147 -0
- package/src/lib/MenuFlyout/MenuFlyoutItem.svelte +239 -0
- package/src/lib/MenuFlyout/MenuFlyoutSurface.scss +42 -0
- package/src/lib/MenuFlyout/MenuFlyoutSurface.svelte +28 -0
- package/src/lib/MenuFlyout/MenuFlyoutWrapper.scss +64 -0
- package/src/lib/MenuFlyout/MenuFlyoutWrapper.svelte +114 -0
- package/src/lib/NavigationView/NavigationView.scss +0 -0
- package/src/lib/NavigationView/NavigationView.svelte +82 -0
- package/src/lib/NumberBox/NumberBox.scss +31 -0
- package/src/lib/NumberBox/NumberBox.svelte +267 -0
- package/src/lib/PersonPicture/PersonPicture.scss +35 -0
- package/src/lib/PersonPicture/PersonPicture.svelte +62 -0
- package/src/lib/ProgressBar/ProgressBar.scss +83 -0
- package/src/lib/ProgressBar/ProgressBar.svelte +60 -0
- package/src/lib/ProgressRing/ProgressRing.scss +37 -0
- package/src/lib/ProgressRing/ProgressRing.svelte +73 -0
- package/src/lib/RadioButton/RadioButton.scss +114 -0
- package/src/lib/RadioButton/RadioButton.svelte +67 -0
- package/src/lib/RangeSlider/RangeSlider.svelte +91 -0
- package/src/lib/ScrollView/ScrollView.svelte +9 -0
- package/src/lib/Slider/Slider.scss +263 -0
- package/src/lib/Slider/Slider.svelte +261 -0
- package/src/lib/TextBlock/TextBlock.scss +62 -0
- package/src/lib/TextBlock/TextBlock.svelte +70 -0
- package/src/lib/TextBox/TextBox.scss +108 -0
- package/src/lib/TextBox/TextBox.svelte +225 -0
- package/src/lib/TextBox/TextBoxButton.scss +34 -0
- package/src/lib/TextBox/TextBoxButton.svelte +27 -0
- package/src/lib/ToggleSwitch/ToggleSwitch.scss +118 -0
- package/src/lib/ToggleSwitch/ToggleSwitch.svelte +55 -0
- package/src/lib/Tooltip/TooltipSurface.scss +16 -0
- package/src/lib/Tooltip/TooltipSurface.svelte +27 -0
- package/src/lib/Tooltip/TooltipWrapper.scss +66 -0
- package/src/lib/Tooltip/TooltipWrapper.svelte +117 -0
- package/src/lib/_mixins.scss +130 -0
- package/src/lib/index.ts +33 -0
- package/src/lib/internal.ts +213 -0
- package/src/lib/svelte-jsx.d.ts +14 -0
- package/src/lib/theme.css +414 -0
- package/src/routes/__layout.svelte +48 -0
- package/src/routes/docs/__layout.svelte +122 -0
- package/src/routes/docs/components/button.md +43 -0
- package/src/routes/docs/components/calendarview.md +188 -0
- package/src/routes/docs/components/checkbox.md +87 -0
- package/src/routes/docs/components/contentdialog.md +155 -0
- package/src/routes/docs/components/expander.md +115 -0
- package/src/routes/docs/components/flyout.md +107 -0
- package/src/routes/docs/components/iconbutton.md +39 -0
- package/src/routes/docs/components/infobadge.md +54 -0
- package/src/routes/docs/components/infobar.md +102 -0
- package/src/routes/docs/components/listitem.md +87 -0
- package/src/routes/docs/components/personpicture.md +125 -0
- package/src/routes/docs/components/progressring.md +83 -0
- package/src/routes/docs/components/radiobutton.md +88 -0
- package/src/routes/docs/components/slider.md +165 -0
- package/src/routes/docs/components/textblock.md +46 -0
- package/src/routes/docs/components/textbox.md +124 -0
- package/src/routes/docs/components/toggleswitch.md +73 -0
- package/src/routes/docs/getting-started.md +116 -0
- package/src/routes/docs/index.md +37 -0
- package/src/routes/docs/internals/index.md +0 -0
- package/src/routes/index.svelte +121 -0
- package/src/routes/test/__layout-test.svelte +1 -0
- package/src/routes/test/index.svelte +757 -0
- package/src/routes/test/nav.svelte +7 -0
- package/src/site/data/docs.ts +176 -0
- package/src/site/data/home.ts +12 -0
- package/src/site/lib/APIDocs/APIDocs.svelte +178 -0
- package/src/site/lib/APIDocs/ParsedComponent.d.ts +85 -0
- package/src/site/lib/CopyBox/CopyBox.svelte +23 -0
- package/src/site/lib/Example/Example.scss +33 -0
- package/src/site/lib/Example/Example.svelte +18 -0
- package/src/site/lib/HeroCard/HeroCard.scss +24 -0
- package/src/site/lib/HeroCard/HeroCard.svelte +36 -0
- package/src/site/lib/Metadata/Metadata.svelte +14 -0
- package/src/site/lib/Navbar/Navbar.scss +92 -0
- package/src/site/lib/Navbar/Navbar.svelte +47 -0
- package/src/site/lib/PageSection/PageSection.scss +57 -0
- package/src/site/lib/PageSection/PageSection.svelte +10 -0
- package/src/site/lib/Showcase/Showcase.scss +53 -0
- package/src/site/lib/Showcase/Showcase.svelte +67 -0
- package/src/site/lib/Toc/Toc.scss +18 -0
- package/src/site/lib/Toc/Toc.svelte +59 -0
- package/src/site/lib/TreeView/TreeView.svelte +89 -0
- package/src/site/lib/index.ts +9 -0
- package/src/site/styles/_markdown.scss +260 -0
- package/src/site/styles/_mixins.scss +319 -0
- package/src/site/styles/global.scss +40 -0
- package/src/site/styles/pages/docs.scss +74 -0
- package/src/site/styles/pages/home.scss +134 -0
- package/static/bloom-mica-dark.png +0 -0
- package/static/bloom-mica-light.png +0 -0
- package/static/logo.svg +11 -0
- package/svelte.config.js +57 -0
- 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,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
|
+
¢er {
|
|
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
|
+
¢er {
|
|
57
|
+
inset-block-start: 50%;
|
|
58
|
+
transform: translateY(-50%);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|