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,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
+ &center {
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
+ &center {
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
+ }