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,104 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createEventDispatcher, setContext } from "svelte";
|
|
3
|
+
import { externalMouseEvents, arrowNavigation } from "$lib/internal";
|
|
4
|
+
import { tabbable } from "tabbable";
|
|
5
|
+
|
|
6
|
+
import MenuFlyoutSurface from "../MenuFlyout/MenuFlyoutSurface.svelte";
|
|
7
|
+
|
|
8
|
+
/** Controls if the flyout will be closed when clicking a standard variant item. Only applies if `closable` is set to `true`. */
|
|
9
|
+
export let closeOnSelect = true;
|
|
10
|
+
|
|
11
|
+
/** The current visibility state of the context menu. */
|
|
12
|
+
export let open = false;
|
|
13
|
+
|
|
14
|
+
/** Obtains a bound DOM reference to the content wrapper element. */
|
|
15
|
+
export let wrapperElement: HTMLDivElement = null;
|
|
16
|
+
|
|
17
|
+
/** Obtains a bound DOM reference to the menu's positioning anchor element. */
|
|
18
|
+
export let anchorElement: HTMLDivElement = null;
|
|
19
|
+
|
|
20
|
+
/** Obtains a bound DOM reference to the inner menu element. */
|
|
21
|
+
export let menuElement: HTMLUListElement = null;
|
|
22
|
+
|
|
23
|
+
const dispatch = createEventDispatcher();
|
|
24
|
+
|
|
25
|
+
let menu;
|
|
26
|
+
let menuPosition = {
|
|
27
|
+
x: 0,
|
|
28
|
+
y: 0
|
|
29
|
+
};
|
|
30
|
+
let mousePosition = {
|
|
31
|
+
x: 0,
|
|
32
|
+
y: 0
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
$: dispatch(open ? "open" : "close");
|
|
36
|
+
$: if (menu && tabbable(menuElement).length > 0) tabbable(menuElement)[0].focus();
|
|
37
|
+
$: if (anchorElement) {
|
|
38
|
+
const { width, height } = anchorElement.getBoundingClientRect();
|
|
39
|
+
|
|
40
|
+
menuPosition.x = Math.min(window.innerWidth - width, mousePosition.x);
|
|
41
|
+
menuPosition.y =
|
|
42
|
+
mousePosition.y > window.innerHeight - height
|
|
43
|
+
? (mousePosition.y -= height)
|
|
44
|
+
: mousePosition.y;
|
|
45
|
+
|
|
46
|
+
if (menuPosition.y < 0) menuPosition.y = 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function handleContextMenu({ clientX, clientY }: MouseEvent) {
|
|
50
|
+
open = true;
|
|
51
|
+
|
|
52
|
+
mousePosition = {
|
|
53
|
+
x: clientX,
|
|
54
|
+
y: clientY
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function handleEscapeKey({ key }) {
|
|
59
|
+
if (key === "Escape") open = false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function mountMenu(node: HTMLDivElement) {
|
|
63
|
+
document.body.appendChild(node);
|
|
64
|
+
return {
|
|
65
|
+
destroy: () => node.remove()
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setContext("closeFlyout", event => {
|
|
70
|
+
dispatch("select");
|
|
71
|
+
if (closeOnSelect) open = false;
|
|
72
|
+
});
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
<svelte:window on:keydown={handleEscapeKey} />
|
|
76
|
+
|
|
77
|
+
<div
|
|
78
|
+
class="context-menu-wrapper"
|
|
79
|
+
on:contextmenu|preventDefault|stopPropagation={handleContextMenu}
|
|
80
|
+
on:contextmenu
|
|
81
|
+
bind:this={wrapperElement}
|
|
82
|
+
>
|
|
83
|
+
<slot />
|
|
84
|
+
{#if open}
|
|
85
|
+
<div
|
|
86
|
+
use:mountMenu
|
|
87
|
+
use:arrowNavigation={{ preventTab: true }}
|
|
88
|
+
use:externalMouseEvents={{ type: "mousedown" }}
|
|
89
|
+
on:contextmenu|stopPropagation={e => e.preventDefault()}
|
|
90
|
+
bind:this={anchorElement}
|
|
91
|
+
on:outermousedown={() => (open = false)}
|
|
92
|
+
class="context-menu-anchor"
|
|
93
|
+
style="top: {menuPosition.y}px; left: {menuPosition.x}px;"
|
|
94
|
+
>
|
|
95
|
+
<MenuFlyoutSurface bind:this={menu} bind:element={menuElement} {...$$restProps}>
|
|
96
|
+
<slot name="flyout" />
|
|
97
|
+
</MenuFlyoutSurface>
|
|
98
|
+
</div>
|
|
99
|
+
{/if}
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<style lang="scss">
|
|
103
|
+
@use "./ContextMenu";
|
|
104
|
+
</style>
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
@use "../mixins" as *;
|
|
2
|
+
|
|
3
|
+
.expander {
|
|
4
|
+
@include flex($direction: column);
|
|
5
|
+
color: var(--text-primary);
|
|
6
|
+
border-radius: var(--control-corner-radius);
|
|
7
|
+
inline-size: 100%;
|
|
8
|
+
user-select: none;
|
|
9
|
+
&.direction- {
|
|
10
|
+
&down {
|
|
11
|
+
.expander-content {
|
|
12
|
+
border-block-start: none;
|
|
13
|
+
border-radius: var(--control-corner-radius);
|
|
14
|
+
border-start-start-radius: 0;
|
|
15
|
+
border-start-end-radius: 0;
|
|
16
|
+
transform: translateY(-100%);
|
|
17
|
+
}
|
|
18
|
+
&.expanded .expander-header {
|
|
19
|
+
border-radius: var(--control-corner-radius);
|
|
20
|
+
border-end-start-radius: 0;
|
|
21
|
+
border-end-end-radius: 0;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
&up {
|
|
25
|
+
.expander-content {
|
|
26
|
+
border-bottom: none;
|
|
27
|
+
border-radius: var(--control-corner-radius);
|
|
28
|
+
border-end-start-radius: 0;
|
|
29
|
+
border-end-end-radius: 0;
|
|
30
|
+
transform: translateY(100%);
|
|
31
|
+
&-anchor {
|
|
32
|
+
order: -1;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
&.expanded .expander-header {
|
|
36
|
+
border-radius: var(--control-corner-radius);
|
|
37
|
+
border-start-start-radius: 0;
|
|
38
|
+
border-start-end-radius: 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
&.expanded {
|
|
43
|
+
.expander {
|
|
44
|
+
&-content {
|
|
45
|
+
transform: none;
|
|
46
|
+
transition: var(--control-slow-duration) var(--control-fast-out-slow-in-easing)
|
|
47
|
+
transform;
|
|
48
|
+
&-anchor {
|
|
49
|
+
max-block-size: 6.02e23vmax;
|
|
50
|
+
transition: none;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
&-chevron svg {
|
|
54
|
+
transform: rotate(180deg);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
> h3 {
|
|
59
|
+
display: contents;
|
|
60
|
+
}
|
|
61
|
+
&-icon {
|
|
62
|
+
flex: 0 0 auto;
|
|
63
|
+
color: var(--text-primary);
|
|
64
|
+
inline-size: 16px;
|
|
65
|
+
block-size: 16px;
|
|
66
|
+
margin-inline-end: 16px;
|
|
67
|
+
> :global(svg) {
|
|
68
|
+
@include icon($size: 16px);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
&-header {
|
|
72
|
+
@include flex($align: center);
|
|
73
|
+
@include typography-body;
|
|
74
|
+
text-align: start;
|
|
75
|
+
outline: none;
|
|
76
|
+
box-sizing: border-box;
|
|
77
|
+
padding-inline-start: 16px;
|
|
78
|
+
padding: 8px;
|
|
79
|
+
background-clip: padding-box;
|
|
80
|
+
background-color: var(--card-background-default);
|
|
81
|
+
border: 1px solid var(--card-stroke-default);
|
|
82
|
+
border-radius: var(--control-corner-radius);
|
|
83
|
+
&-title {
|
|
84
|
+
flex: 1 1 auto;
|
|
85
|
+
}
|
|
86
|
+
&:focus-visible {
|
|
87
|
+
box-shadow: var(--focus-stroke);
|
|
88
|
+
}
|
|
89
|
+
&:hover .expander-chevron {
|
|
90
|
+
background-color: var(--subtle-fill-secondary);
|
|
91
|
+
}
|
|
92
|
+
&:active .expander-chevron {
|
|
93
|
+
color: var(--text-secondary);
|
|
94
|
+
background-color: var(--subtle-fill-tertiary);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
&-chevron {
|
|
98
|
+
@include flex($align: center, $justify: center);
|
|
99
|
+
flex: 0 0 auto;
|
|
100
|
+
inline-size: 32px;
|
|
101
|
+
block-size: 32px;
|
|
102
|
+
margin-inline-start: 20px;
|
|
103
|
+
border: none;
|
|
104
|
+
outline: none;
|
|
105
|
+
appearance: none;
|
|
106
|
+
color: var(--text-primary);
|
|
107
|
+
border-radius: var(--control-corner-radius);
|
|
108
|
+
background-color: var(--subtle-fill-transparent);
|
|
109
|
+
&:focus-visible {
|
|
110
|
+
box-shadow: var(--focus-stroke);
|
|
111
|
+
}
|
|
112
|
+
svg {
|
|
113
|
+
inline-size: 12px;
|
|
114
|
+
block-size: 12px;
|
|
115
|
+
fill: currentColor;
|
|
116
|
+
transition: calc(var(--control-faster-duration) * 1.2) linear transform
|
|
117
|
+
var(--control-faster-duration);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
&-content {
|
|
121
|
+
@include typography-body;
|
|
122
|
+
background-clip: padding-box;
|
|
123
|
+
background-color: var(--card-background-secondary);
|
|
124
|
+
border: 1px solid var(--card-stroke-default);
|
|
125
|
+
padding: 16px;
|
|
126
|
+
transition: var(--control-fast-duration) cubic-bezier(1, 1, 0, 1) transform;
|
|
127
|
+
&-anchor {
|
|
128
|
+
max-height: 0;
|
|
129
|
+
position: relative;
|
|
130
|
+
overflow: hidden;
|
|
131
|
+
transition: 0ms linear var(--control-slow-duration) max-height;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// TODO: progressively enhance this
|
|
3
|
+
|
|
4
|
+
import { createEventDispatcher } from "svelte";
|
|
5
|
+
import { get_current_component } from "svelte/internal";
|
|
6
|
+
import { createEventForwarder, uid } from "$lib/internal";
|
|
7
|
+
|
|
8
|
+
/** Determines whether the expander is expanded (open) or not. */
|
|
9
|
+
export let expanded = false;
|
|
10
|
+
|
|
11
|
+
/** Determines the direction that the expander will extend to. */
|
|
12
|
+
export let direction: "down" | "up" = "down";
|
|
13
|
+
|
|
14
|
+
// svelte-ignore unused-export-let
|
|
15
|
+
/** Determines the expander header's semantic HTML heading tag (h1-h6). */
|
|
16
|
+
export let headingLevel: 1 | 2 | 3 | 4 | 5 | 6 = 3;
|
|
17
|
+
|
|
18
|
+
/** Specifies a custom class name for the expander. */
|
|
19
|
+
let className = "";
|
|
20
|
+
export { className as class };
|
|
21
|
+
|
|
22
|
+
/** Obtains a bound DOM reference to the expander's container element. */
|
|
23
|
+
export let containerElement: HTMLDivElement = null;
|
|
24
|
+
|
|
25
|
+
/** Obtains a bound DOM reference to the expander's header button element. */
|
|
26
|
+
export let headerElement: HTMLDivElement = null;
|
|
27
|
+
|
|
28
|
+
/** Obtains a bound DOM reference to the expander's content container. */
|
|
29
|
+
export let contentElement: HTMLDivElement = null;
|
|
30
|
+
|
|
31
|
+
const dispatch = createEventDispatcher();
|
|
32
|
+
const forwardEvents = createEventForwarder(get_current_component(), ["expand", "collapse"]);
|
|
33
|
+
const headerId = uid("fds-expander-header-");
|
|
34
|
+
const contentId = uid("fds-expander-content-");
|
|
35
|
+
|
|
36
|
+
$: if (expanded) {
|
|
37
|
+
dispatch("expand");
|
|
38
|
+
} else {
|
|
39
|
+
dispatch("collapse");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function handleKeydown({ key }) {
|
|
43
|
+
if (key === "Enter" || key === " ") {
|
|
44
|
+
event.preventDefault();
|
|
45
|
+
expanded = !expanded;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<!--
|
|
51
|
+
@component
|
|
52
|
+
Expanders are controls that display a header and a collapsable content area. The content area can be expanded clicking on the header. [Docs](https://fluent-svelte.vercel.app/docs/components/expander)
|
|
53
|
+
- Usage:
|
|
54
|
+
```tsx
|
|
55
|
+
<Expander>
|
|
56
|
+
Header
|
|
57
|
+
<svelte:fragment slot="content">
|
|
58
|
+
Content
|
|
59
|
+
</svelte:fragment>
|
|
60
|
+
</Expander>
|
|
61
|
+
```
|
|
62
|
+
-->
|
|
63
|
+
<div
|
|
64
|
+
use:forwardEvents
|
|
65
|
+
class="expander direction-{direction} {className}"
|
|
66
|
+
role="region"
|
|
67
|
+
class:expanded
|
|
68
|
+
bind:this={containerElement}
|
|
69
|
+
{...$$restProps}
|
|
70
|
+
>
|
|
71
|
+
<svelte:element this="h">
|
|
72
|
+
<div
|
|
73
|
+
role="button"
|
|
74
|
+
id={headerId}
|
|
75
|
+
aria-controls={contentId}
|
|
76
|
+
class="expander-header"
|
|
77
|
+
aria-expanded={expanded}
|
|
78
|
+
tabindex="0"
|
|
79
|
+
bind:this={headerElement}
|
|
80
|
+
on:keydown={handleKeydown}
|
|
81
|
+
on:click={() => (expanded = !expanded)}
|
|
82
|
+
>
|
|
83
|
+
{#if $$slots.icon}
|
|
84
|
+
<div class="expander-icon">
|
|
85
|
+
<slot name="icon" />
|
|
86
|
+
</div>
|
|
87
|
+
{/if}
|
|
88
|
+
<span class="expander-header-title">
|
|
89
|
+
<slot />
|
|
90
|
+
</span>
|
|
91
|
+
<button
|
|
92
|
+
class="expander-chevron"
|
|
93
|
+
type="button"
|
|
94
|
+
tabindex="-1"
|
|
95
|
+
id={contentId}
|
|
96
|
+
aria-labelledby={headerId}
|
|
97
|
+
>
|
|
98
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
|
|
99
|
+
{#if direction === "down"}
|
|
100
|
+
<path
|
|
101
|
+
fill="currentColor"
|
|
102
|
+
d="M2.14645 4.64645C2.34171 4.45118 2.65829 4.45118 2.85355 4.64645L6 7.79289L9.14645 4.64645C9.34171 4.45118 9.65829 4.45118 9.85355 4.64645C10.0488 4.84171 10.0488 5.15829 9.85355 5.35355L6.35355 8.85355C6.15829 9.04882 5.84171 9.04882 5.64645 8.85355L2.14645 5.35355C1.95118 5.15829 1.95118 4.84171 2.14645 4.64645Z"
|
|
103
|
+
/>
|
|
104
|
+
{:else}
|
|
105
|
+
<path
|
|
106
|
+
fill="currentColor"
|
|
107
|
+
d="M2.14645 7.35355C2.34171 7.54882 2.65829 7.54882 2.85355 7.35355L6 4.20711L9.14645 7.35355C9.34171 7.54882 9.65829 7.54882 9.85355 7.35355C10.0488 7.15829 10.0488 6.84171 9.85355 6.64645L6.35355 3.14645C6.15829 2.95118 5.84171 2.95118 5.64645 3.14645L2.14645 6.64645C1.95118 6.84171 1.95118 7.15829 2.14645 7.35355Z"
|
|
108
|
+
/>
|
|
109
|
+
{/if}
|
|
110
|
+
</svg>
|
|
111
|
+
</button>
|
|
112
|
+
</div>
|
|
113
|
+
</svelte:element>
|
|
114
|
+
<div class="expander-content-anchor">
|
|
115
|
+
<div class="expander-content" bind:this={contentElement}>
|
|
116
|
+
<slot name="content" />
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<style lang="scss">
|
|
122
|
+
@use "./Expander";
|
|
123
|
+
</style>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
export let direction;
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<div id="flipper">
|
|
6
|
+
{#if direction === "right"}
|
|
7
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" height="16px" viewBox="0 0 16 16" version="1.1">
|
|
8
|
+
<g id="surface1">
|
|
9
|
+
<path d="M 6 11.933594 C 6 12.644531 6.84375 13.03125 7.378906 12.558594 L 11.589844 8.878906 C 11.84375 8.65625 11.988281 8.339844 11.988281 8 C 11.988281 7.660156 11.84375 7.34375 11.589844 7.121094 L 7.378906 3.441406 C 6.84375 2.96875 6 3.355469 6 4.066406 Z M 6 11.933594 "/>
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
|
12
|
+
{:else if direction === "left"}
|
|
13
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16px" height="16px" viewBox="0 0 16 16" version="1.1">
|
|
14
|
+
<g id="surface1">
|
|
15
|
+
<path d="M 10 11.933594 C 10 12.648438 9.15625 13.03125 8.617188 12.558594 L 4.410156 8.878906 C 4.15625 8.65625 4.011719 8.335938 4.011719 8 C 4.011719 7.664062 4.15625 7.34375 4.410156 7.121094 L 8.617188 3.441406 C 9.15625 2.96875 10 3.351562 10 4.066406 Z M 10 11.933594 "/>
|
|
16
|
+
</g>
|
|
17
|
+
</svg>
|
|
18
|
+
{/if}
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<style>
|
|
22
|
+
|
|
23
|
+
#flipper {
|
|
24
|
+
display:flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content:center;
|
|
27
|
+
height:35px;
|
|
28
|
+
border-radius:3px;
|
|
29
|
+
background-color: rgba(255,255,255,.1);
|
|
30
|
+
backdrop-filter: blur(30px) saturate(125%);
|
|
31
|
+
fill: rgb(205, 193, 193);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
#flipper > svg {
|
|
35
|
+
transform:scale(0.9);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#flipper:hover {
|
|
39
|
+
fill: currentColor;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#flipper:hover > svg {
|
|
43
|
+
transform:scale(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#flipper:active > svg {
|
|
47
|
+
transform:scale(0.8);
|
|
48
|
+
}
|
|
49
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
@use "../mixins" as *;
|
|
2
|
+
|
|
3
|
+
.flyout {
|
|
4
|
+
@include typography-body;
|
|
5
|
+
padding: 16px;
|
|
6
|
+
min-inline-size: 320px;
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
color: var(--text-primary);
|
|
9
|
+
border-radius: var(--overlay-corner-radius);
|
|
10
|
+
border: 1px solid var(--surface-stroke-flyout);
|
|
11
|
+
background-color: var(--solid-background-quarternary);
|
|
12
|
+
background-clip: padding-box;
|
|
13
|
+
box-shadow: var(--flyout-shadow);
|
|
14
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { get_current_component } from "svelte/internal";
|
|
3
|
+
import { createEventForwarder } from "$lib/internal";
|
|
4
|
+
|
|
5
|
+
/** Specifies a custom class name for the surface. */
|
|
6
|
+
let className = "";
|
|
7
|
+
export { className as class };
|
|
8
|
+
|
|
9
|
+
/** Obtains a bound DOM reference to the surface element. */
|
|
10
|
+
export let element: HTMLDivElement = null;
|
|
11
|
+
|
|
12
|
+
const forwardEvents = createEventForwarder(get_current_component());
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<div class="flyout {className}" use:forwardEvents bind:this={element} {...$$restProps}>
|
|
16
|
+
<slot />
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<style lang="scss">
|
|
20
|
+
@use "./FlyoutSurface";
|
|
21
|
+
</style>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
@keyframes flyout-in {
|
|
2
|
+
0% {
|
|
3
|
+
opacity: 0;
|
|
4
|
+
transform: var(--flyout-transform) var(--flyout-transition-offset, translateY(12px));
|
|
5
|
+
}
|
|
6
|
+
100% {
|
|
7
|
+
opacity: 1;
|
|
8
|
+
transform: var(--flyout-transform);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.flyout- {
|
|
13
|
+
&wrapper {
|
|
14
|
+
display: inline-block;
|
|
15
|
+
inline-size: fit-content;
|
|
16
|
+
block-size: fit-content;
|
|
17
|
+
position: relative;
|
|
18
|
+
}
|
|
19
|
+
&backdrop {
|
|
20
|
+
position: fixed;
|
|
21
|
+
top: 0;
|
|
22
|
+
left: 0;
|
|
23
|
+
inline-size: 100%;
|
|
24
|
+
block-size: 100%;
|
|
25
|
+
z-index: 9999;
|
|
26
|
+
}
|
|
27
|
+
&anchor {
|
|
28
|
+
position: absolute;
|
|
29
|
+
z-index: 10000;
|
|
30
|
+
animation: flyout-in var(--control-normal-duration) var(--control-fast-out-slow-in-easing);
|
|
31
|
+
transform: var(--flyout-transform);
|
|
32
|
+
&.placement- {
|
|
33
|
+
&top {
|
|
34
|
+
bottom: calc(100% + var(--flyout-offset));
|
|
35
|
+
--flyout-transition-offset: translateY(12px);
|
|
36
|
+
}
|
|
37
|
+
&bottom {
|
|
38
|
+
top: calc(100% + var(--flyout-offset));
|
|
39
|
+
--flyout-transition-offset: translateY(-12px);
|
|
40
|
+
}
|
|
41
|
+
&left {
|
|
42
|
+
right: calc(100% + var(--flyout-offset));
|
|
43
|
+
--flyout-transition-offset: translateX(12px);
|
|
44
|
+
}
|
|
45
|
+
&right {
|
|
46
|
+
left: calc(100% + var(--flyout-offset));
|
|
47
|
+
--flyout-transition-offset: translateX(-12px);
|
|
48
|
+
}
|
|
49
|
+
&top,
|
|
50
|
+
&bottom {
|
|
51
|
+
&.alignment- {
|
|
52
|
+
&start {
|
|
53
|
+
inset-inline-start: 0;
|
|
54
|
+
}
|
|
55
|
+
&end {
|
|
56
|
+
inset-inline-end: 0;
|
|
57
|
+
}
|
|
58
|
+
¢er {
|
|
59
|
+
inset-inline-start: 50%;
|
|
60
|
+
--flyout-transform: translateX(-50%);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
&left,
|
|
65
|
+
&right {
|
|
66
|
+
&.alignment- {
|
|
67
|
+
&start {
|
|
68
|
+
inset-block-start: 0;
|
|
69
|
+
}
|
|
70
|
+
&end {
|
|
71
|
+
inset-block-end: 0;
|
|
72
|
+
}
|
|
73
|
+
¢er {
|
|
74
|
+
inset-block-start: 50%;
|
|
75
|
+
--flyout-transform: translateY(-50%);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createEventDispatcher } from "svelte";
|
|
3
|
+
import { uid, focusTrap, getCSSDuration } from "$lib/internal";
|
|
4
|
+
import { fade } from "svelte/transition";
|
|
5
|
+
import { circOut } from "svelte/easing";
|
|
6
|
+
|
|
7
|
+
import FlyoutSurface from "./FlyoutSurface.svelte";
|
|
8
|
+
|
|
9
|
+
/** Determines the flyout's visibility. */
|
|
10
|
+
export let open = false;
|
|
11
|
+
|
|
12
|
+
/** Determines if the flyout can be closed using conventional user interaction. */
|
|
13
|
+
export let closable = true;
|
|
14
|
+
|
|
15
|
+
/** Direction that the flyout will be opened from. */
|
|
16
|
+
export let placement: "top" | "bottom" | "left" | "right" = "top";
|
|
17
|
+
|
|
18
|
+
/** Alignment of the menu along the clickable target's given axis. */
|
|
19
|
+
export let alignment: "start" | "center" | "end" = "center";
|
|
20
|
+
|
|
21
|
+
/** Distance of the flyout from the control button in pixels. */
|
|
22
|
+
export let offset = 4;
|
|
23
|
+
|
|
24
|
+
/** Determines if keyboard focus should be locked to the flyout's contents. */
|
|
25
|
+
export let trapFocus = true;
|
|
26
|
+
|
|
27
|
+
/** Specifies a custom class name for the content wrapper. */
|
|
28
|
+
let className = "";
|
|
29
|
+
export { className as class };
|
|
30
|
+
|
|
31
|
+
/** Obtains a bound DOM reference to the content wrapper element. */
|
|
32
|
+
export let wrapperElement: HTMLDivElement = null;
|
|
33
|
+
|
|
34
|
+
/** Obtains a bound DOM reference to the menu's positioning anchor element. */
|
|
35
|
+
export let anchorElement: HTMLDivElement = null;
|
|
36
|
+
|
|
37
|
+
/** Obtains a bound DOM reference to the inner menu element. */
|
|
38
|
+
export let menuElement: HTMLDivElement = null;
|
|
39
|
+
|
|
40
|
+
/** Obtains a bound DOM reference to the menu backdrop, which is present while the menu is `open`. */
|
|
41
|
+
export let backdropElement: HTMLDivElement = null;
|
|
42
|
+
|
|
43
|
+
const dispatch = createEventDispatcher();
|
|
44
|
+
const menuId = uid("fds-flyout-anchor-");
|
|
45
|
+
|
|
46
|
+
$: _focusTrap = trapFocus ? focusTrap : () => {};
|
|
47
|
+
$: if (open) {
|
|
48
|
+
dispatch("open");
|
|
49
|
+
} else {
|
|
50
|
+
dispatch("close");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function handleEscapeKey({ key }: KeyboardEvent) {
|
|
54
|
+
if (key === "Escape" && closable) open = false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function closeFlyout() {
|
|
58
|
+
if (closable) open = false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function handleKeyDown(event: KeyboardEvent) {
|
|
62
|
+
if (event.key === " " || event.key === "Enter") {
|
|
63
|
+
event.preventDefault();
|
|
64
|
+
open = !open;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<!--
|
|
70
|
+
@component
|
|
71
|
+
Flyouts represent a control that displays lightweight UI that is either information, or requires user interaction. Unlike a dialog, a Flyout can be dismissed by clicking or tapping outside of it, or pressing the Esc key. [Docs](https://fluent-svelte.vercel.app/docs/components/flyout)
|
|
72
|
+
- Usage:
|
|
73
|
+
```tsx
|
|
74
|
+
<Flyout>
|
|
75
|
+
<Button>Trigger Button</Button>
|
|
76
|
+
<svelte:fragment slot="flyout">
|
|
77
|
+
Flyout Contents
|
|
78
|
+
</svelte:fragment>
|
|
79
|
+
</Flyout>
|
|
80
|
+
```
|
|
81
|
+
-->
|
|
82
|
+
|
|
83
|
+
<svelte:window on:keydown={handleEscapeKey} />
|
|
84
|
+
|
|
85
|
+
<div
|
|
86
|
+
class="flyout-wrapper {className}"
|
|
87
|
+
aria-expanded={open}
|
|
88
|
+
aria-haspopup={open}
|
|
89
|
+
aria-controls={menuId}
|
|
90
|
+
on:click={() => (open = !open)}
|
|
91
|
+
on:keydown={handleKeyDown}
|
|
92
|
+
bind:this={wrapperElement}
|
|
93
|
+
>
|
|
94
|
+
<slot />
|
|
95
|
+
{#if open}
|
|
96
|
+
<div
|
|
97
|
+
id={menuId}
|
|
98
|
+
class="flyout-anchor placement-{placement} alignment-{alignment}"
|
|
99
|
+
style="--fds-flyout-offset: {offset}px;"
|
|
100
|
+
use:_focusTrap
|
|
101
|
+
out:fade|local={{
|
|
102
|
+
duration: getCSSDuration("--fds-control-faster-duration"),
|
|
103
|
+
easing: circOut
|
|
104
|
+
}}
|
|
105
|
+
bind:this={anchorElement}
|
|
106
|
+
on:click={e => e.stopPropagation()}
|
|
107
|
+
{...$$restProps}
|
|
108
|
+
>
|
|
109
|
+
<slot name="override">
|
|
110
|
+
<FlyoutSurface bind:element={menuElement}>
|
|
111
|
+
<slot name="flyout" />
|
|
112
|
+
</FlyoutSurface>
|
|
113
|
+
</slot>
|
|
114
|
+
</div>
|
|
115
|
+
<div
|
|
116
|
+
class="flyout-backdrop"
|
|
117
|
+
bind:this={backdropElement}
|
|
118
|
+
on:click={e => e.stopPropagation()}
|
|
119
|
+
on:mousedown={closeFlyout}
|
|
120
|
+
/>
|
|
121
|
+
{/if}
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<style lang="scss">
|
|
125
|
+
@use "./FlyoutWrapper";
|
|
126
|
+
</style>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
@use "../mixins" as *;
|
|
2
|
+
|
|
3
|
+
.icon-button {
|
|
4
|
+
@include flex($inline: true, $align: center, $justify: center);
|
|
5
|
+
outline: none;
|
|
6
|
+
border: none;
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
min-inline-size: 30px;
|
|
9
|
+
min-block-size: 30px;
|
|
10
|
+
padding: 8px;
|
|
11
|
+
color: var(--text-primary);
|
|
12
|
+
border-radius: var(--control-corner-radius);
|
|
13
|
+
background-color: var(--subtle-fill-transparent);
|
|
14
|
+
&:focus-visible {
|
|
15
|
+
box-shadow: var(--focus-stroke);
|
|
16
|
+
}
|
|
17
|
+
&:hover {
|
|
18
|
+
background-color: var(--subtle-fill-secondary);
|
|
19
|
+
}
|
|
20
|
+
&:active {
|
|
21
|
+
color: var(--text-secondary);
|
|
22
|
+
background-color: var(--subtle-fill-tertiary);
|
|
23
|
+
}
|
|
24
|
+
&:disabled {
|
|
25
|
+
background-color: var(--subtle-fill-disabled);
|
|
26
|
+
color: var(--text-disabled);
|
|
27
|
+
}
|
|
28
|
+
:global(svg) {
|
|
29
|
+
@include icon($size: 16px);
|
|
30
|
+
}
|
|
31
|
+
}
|