fluent-svelte-extra 2.1.4 → 2.1.6

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.
@@ -131,6 +131,11 @@
131
131
  inset-block-start: var(--menu-offset, 0);
132
132
  inset-inline-start: 0;
133
133
 
134
+ &.auto-width {
135
+ inline-size: max-content;
136
+ min-inline-size: calc(100% + 8px);
137
+ }
138
+
134
139
  &.acrylic {
135
140
  background-color: var(--acrylic-fallback-background-base);
136
141
  background-image: var(--acrylic-noise-asset-alpha);
@@ -21,6 +21,18 @@ export let disabled = false;
21
21
  export let open = false;
22
22
  /** Wheter to use acrylic styling for the dropdown menu. */
23
23
  export let acrylic = true;
24
+ /**
25
+ * Specifies the direction the menu should open.
26
+ * 'auto' (default): Centers the selected item.
27
+ * 'top': Forces menu to open upwards (overlaying the button).
28
+ * 'bottom': Forces menu to open downwards (overlaying the button).
29
+ */
30
+ export let direction = "auto";
31
+ /**
32
+ * If true, the dropdown menu will expand horizontally to fit the widest item
33
+ * instead of being constrained to the width of the trigger button.
34
+ */
35
+ export let autoWidth = false;
24
36
  /** Specifies a custom class name for the outer combobox container. */
25
37
  let className = "";
26
38
  export { className as class };
@@ -46,6 +58,7 @@ const forwardEvents = createEventForwarder(get_current_component(), [
46
58
  const dispatch = createEventDispatcher();
47
59
  const buttonId = uid("fds-combo-box-button-");
48
60
  const dropdownId = uid("fds-combo-box-dropdown-");
61
+ let isRightAligned = false;
49
62
  $: selectableItems = items.filter(item => !item.disabled);
50
63
  $: selection = items.find(i => i.value === value);
51
64
  $: if (menuElement && menuElement.children.length > 0 && !editable) {
@@ -66,11 +79,15 @@ $: if (items.length > 0) {
66
79
  }
67
80
  $: dispatch("select", selection);
68
81
  $: menuGrowDirection =
69
- !selection || items[items.indexOf(selection)] === items[Math.floor(items.length / 2)]
70
- ? "center"
71
- : items.indexOf(selection) < items.indexOf(items[Math.floor(items.length / 2)])
72
- ? "top"
73
- : "bottom";
82
+ direction !== "auto"
83
+ ? direction === "top"
84
+ ? "bottom"
85
+ : "top"
86
+ : !selection || items[items.indexOf(selection)] === items[Math.floor(items.length / 2)]
87
+ ? "center"
88
+ : items.indexOf(selection) < items.indexOf(items[Math.floor(items.length / 2)])
89
+ ? "top"
90
+ : "bottom";
74
91
  let inputFocused = false;
75
92
  let itemHeight = 36;
76
93
  const maxItems = 14; // 504 (`max-block-size` in ComboBox.scss) / 36 (itemHeight)
@@ -97,12 +114,30 @@ function selectItem(item) {
97
114
  containerElement.children[0].focus();
98
115
  }
99
116
  async function openMenu() {
117
+ isRightAligned = false;
100
118
  open = !open;
101
119
  await tick();
102
120
  if (editable && searchInputElement)
103
121
  searchInputElement.focus();
104
- if (menuElement && selection)
122
+ if (direction === "auto" && menuElement && selection) {
105
123
  updateOffset(menuElement.children[items.indexOf(selection)]);
124
+ }
125
+ else if (containerElement) {
126
+ if (direction === "top") {
127
+ const visibleItems = items.length > maxItems ? maxItems : items.length;
128
+ menuOffset = containerElement.offsetHeight - visibleItems * itemHeight;
129
+ }
130
+ else if (direction === "bottom") {
131
+ menuOffset = 0;
132
+ }
133
+ }
134
+ if (open && menuElement && autoWidth) {
135
+ const rect = menuElement.getBoundingClientRect();
136
+ const viewportWidth = window.innerWidth;
137
+ if (rect.right > viewportWidth) {
138
+ isRightAligned = true;
139
+ }
140
+ }
106
141
  }
107
142
  async function handleKeyboardNavigation(event) {
108
143
  const { key } = event;
@@ -292,10 +327,16 @@ When the combo box is closed, it either displays the current selection or is emp
292
327
  : `${dropdownId}-item-${items.indexOf(selection)}`}
293
328
  role="listbox"
294
329
  class:acrylic
330
+ class:auto-width={autoWidth}
295
331
  class="combo-box-dropdown direction-{!editable
296
332
  ? (menuGrowDirection ?? 'center')
297
333
  : 'top'}"
298
- style="--fds-menu-offset: {menuOffset}px;"
334
+ style="
335
+ --fds-menu-offset: {menuOffset}px;
336
+ {isRightAligned
337
+ ? 'inset-inline-start: auto; inset-inline-end: 0; margin-inline-start: 0; margin-inline-end: -5px;'
338
+ : ''}
339
+ "
299
340
  >
300
341
  {#each items as item, i}
301
342
  <ComboBoxItem
@@ -325,4 +366,4 @@ When the combo box is closed, it either displays the current selection or is emp
325
366
  {/if}
326
367
  </div>
327
368
 
328
- <style >@-webkit-keyframes menu-in{0%{-webkit-clip-path:var(--fds-grow-clip-path);clip-path:var(--fds-grow-clip-path)}to{-webkit-clip-path:polygon(0 0,100% 0,100% 100%,0 100%);clip-path:polygon(0 0,100% 0,100% 100%,0 100%)}}@keyframes menu-in{0%{-webkit-clip-path:var(--fds-grow-clip-path);clip-path:var(--fds-grow-clip-path)}to{-webkit-clip-path:polygon(0 0,100% 0,100% 100%,0 100%);clip-path:polygon(0 0,100% 0,100% 100%,0 100%)}}@-webkit-keyframes shadow-in{0%{box-shadow:none}to{box-shadow:var(--fds-flyout-shadow)}}@keyframes shadow-in{0%{box-shadow:none}to{box-shadow:var(--fds-flyout-shadow)}}.combo-box{display:inline-flex;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.combo-box :global(.button),.combo-box :global(.text-box){flex:1 1 auto}.combo-box :global(.text-box){border-color:var(--fds-control-border-default)}.combo-box :global(.text-box-underline:after){border-color:transparent}.combo-box :global(.text-box-container){cursor:default}.combo-box :global(.text-box-container:focus-visible){cursor:text}.combo-box.editable :global(.combo-box-textbox:not(:focus-within)){border-color:var(--fds-control-border-default);cursor:default}.combo-box.editable :global(.combo-box-textbox:not(:focus-within)) :global(.text-box-underline:after){content:none}.combo-box.editable :global(.combo-box-textbox.disabled){border-color:var(--fds-control-stroke-default)}.combo-box.editable.open :global(.combo-box-textbox){background-color:var(--fds-control-fill-input-active);cursor:text}.combo-box.editable.open :global(.combo-box-textbox) :global(.text-box-underline:after){border-bottom:2px solid var(--fds-accent-default);content:""}.combo-box.editable.open :global(.combo-box-textbox) :global(input::-moz-placeholder){color:var(--fds-text-tertiary)}.combo-box.editable.open :global(.combo-box-textbox) :global(input:-ms-input-placeholder){color:var(--fds-text-tertiary)}.combo-box.editable.open :global(.combo-box-textbox) :global(input::placeholder){color:var(--fds-text-tertiary)}.combo-box.editable.open :global(.text-box-underline){border-end-end-radius:0;border-end-start-radius:0}.combo-box.editable .combo-box-dropdown{border-radius:var(--fds-overlay-corner-radius);border-start-end-radius:0;border-start-start-radius:0;inline-size:100%;inset-block-start:100%;inset-inline-start:0;margin:0}.combo-box.editable .combo-box-icon{margin:0}.combo-box-label{flex:1 1 auto;min-block-size:20px;text-align:start}.combo-box-label.placeholder{color:var(--fds-text-secondary)}.combo-box.disabled .placeholder{color:var(--fds-text-disabled)}.combo-box-icon{-webkit-margin-start:8px;block-size:12px;inline-size:12px;margin-inline-start:8px}.combo-box-dropdown{-webkit-margin-before:-6px;-webkit-margin-start:-5px;-webkit-animation:menu-in var(--fds-control-normal-duration) var(--fds-control-fast-out-slow-in-easing),shadow-in var(--fds-control-normal-duration) var(--fds-control-fast-out-slow-in-easing) var(--fds-control-normal-duration);animation:menu-in var(--fds-control-normal-duration) var(--fds-control-fast-out-slow-in-easing),shadow-in var(--fds-control-normal-duration) var(--fds-control-fast-out-slow-in-easing) var(--fds-control-normal-duration);background-clip:padding-box;background-color:var(--fds-solid-background-quarternary);border:1px solid var(--fds-surface-stroke-flyout);border-radius:var(--fds-overlay-corner-radius);box-shadow:var(--fds-flyout-shadow);box-sizing:border-box;inline-size:calc(100% + 8px);inset-block-start:var(--fds-menu-offset,0);inset-inline-start:0;margin:0;margin-block-start:-6px;margin-inline-start:-5px;max-block-size:504px;overflow:auto;padding:1px;position:absolute;z-index:100}.combo-box-dropdown.acrylic{-webkit-backdrop-filter:var(--fds-acrylic-fallback-filter);backdrop-filter:var(--fds-acrylic-fallback-filter);background-clip:border-box;background-color:var(--fds-acrylic-fallback-background-base);background-image:var(--fds-acrylic-noise-asset-alpha)}@supports (overflow:overlay){.combo-box-dropdown{overflow:overlay}}.combo-box-dropdown.direction-top{--fds-grow-clip-path:polygon(0 0,100% 0,100% 25%,0 25%)}.combo-box-dropdown.direction-center{--fds-grow-clip-path:polygon(0 25%,100% 24%,100% 75%,0 75%)}.combo-box-dropdown.direction-bottom{--fds-grow-clip-path:polygon(0 75%,100% 75%,100% 100%,0 100%)}</style>
369
+ <style >@-webkit-keyframes menu-in{0%{-webkit-clip-path:var(--fds-grow-clip-path);clip-path:var(--fds-grow-clip-path)}to{-webkit-clip-path:polygon(0 0,100% 0,100% 100%,0 100%);clip-path:polygon(0 0,100% 0,100% 100%,0 100%)}}@keyframes menu-in{0%{-webkit-clip-path:var(--fds-grow-clip-path);clip-path:var(--fds-grow-clip-path)}to{-webkit-clip-path:polygon(0 0,100% 0,100% 100%,0 100%);clip-path:polygon(0 0,100% 0,100% 100%,0 100%)}}@-webkit-keyframes shadow-in{0%{box-shadow:none}to{box-shadow:var(--fds-flyout-shadow)}}@keyframes shadow-in{0%{box-shadow:none}to{box-shadow:var(--fds-flyout-shadow)}}.combo-box{display:inline-flex;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.combo-box :global(.button),.combo-box :global(.text-box){flex:1 1 auto}.combo-box :global(.text-box){border-color:var(--fds-control-border-default)}.combo-box :global(.text-box-underline:after){border-color:transparent}.combo-box :global(.text-box-container){cursor:default}.combo-box :global(.text-box-container:focus-visible){cursor:text}.combo-box.editable :global(.combo-box-textbox:not(:focus-within)){border-color:var(--fds-control-border-default);cursor:default}.combo-box.editable :global(.combo-box-textbox:not(:focus-within)) :global(.text-box-underline:after){content:none}.combo-box.editable :global(.combo-box-textbox.disabled){border-color:var(--fds-control-stroke-default)}.combo-box.editable.open :global(.combo-box-textbox){background-color:var(--fds-control-fill-input-active);cursor:text}.combo-box.editable.open :global(.combo-box-textbox) :global(.text-box-underline:after){border-bottom:2px solid var(--fds-accent-default);content:""}.combo-box.editable.open :global(.combo-box-textbox) :global(input::-moz-placeholder){color:var(--fds-text-tertiary)}.combo-box.editable.open :global(.combo-box-textbox) :global(input:-ms-input-placeholder){color:var(--fds-text-tertiary)}.combo-box.editable.open :global(.combo-box-textbox) :global(input::placeholder){color:var(--fds-text-tertiary)}.combo-box.editable.open :global(.text-box-underline){border-end-end-radius:0;border-end-start-radius:0}.combo-box.editable .combo-box-dropdown{border-radius:var(--fds-overlay-corner-radius);border-start-end-radius:0;border-start-start-radius:0;inline-size:100%;inset-block-start:100%;inset-inline-start:0;margin:0}.combo-box.editable .combo-box-icon{margin:0}.combo-box-label{flex:1 1 auto;min-block-size:20px;text-align:start}.combo-box-label.placeholder{color:var(--fds-text-secondary)}.combo-box.disabled .placeholder{color:var(--fds-text-disabled)}.combo-box-icon{-webkit-margin-start:8px;block-size:12px;inline-size:12px;margin-inline-start:8px}.combo-box-dropdown{-webkit-margin-before:-6px;-webkit-margin-start:-5px;-webkit-animation:menu-in var(--fds-control-normal-duration) var(--fds-control-fast-out-slow-in-easing),shadow-in var(--fds-control-normal-duration) var(--fds-control-fast-out-slow-in-easing) var(--fds-control-normal-duration);animation:menu-in var(--fds-control-normal-duration) var(--fds-control-fast-out-slow-in-easing),shadow-in var(--fds-control-normal-duration) var(--fds-control-fast-out-slow-in-easing) var(--fds-control-normal-duration);background-clip:padding-box;background-color:var(--fds-solid-background-quarternary);border:1px solid var(--fds-surface-stroke-flyout);border-radius:var(--fds-overlay-corner-radius);box-shadow:var(--fds-flyout-shadow);box-sizing:border-box;inline-size:calc(100% + 8px);inset-block-start:var(--fds-menu-offset,0);inset-inline-start:0;margin:0;margin-block-start:-6px;margin-inline-start:-5px;max-block-size:504px;overflow:auto;padding:1px;position:absolute;z-index:100}.combo-box-dropdown.auto-width{inline-size:-webkit-max-content;inline-size:-moz-max-content;inline-size:max-content;min-inline-size:calc(100% + 8px)}.combo-box-dropdown.acrylic{-webkit-backdrop-filter:var(--fds-acrylic-fallback-filter);backdrop-filter:var(--fds-acrylic-fallback-filter);background-clip:border-box;background-color:var(--fds-acrylic-fallback-background-base);background-image:var(--fds-acrylic-noise-asset-alpha)}@supports (overflow:overlay){.combo-box-dropdown{overflow:overlay}}.combo-box-dropdown.direction-top{--fds-grow-clip-path:polygon(0 0,100% 0,100% 25%,0 25%)}.combo-box-dropdown.direction-center{--fds-grow-clip-path:polygon(0 25%,100% 24%,100% 75%,0 75%)}.combo-box-dropdown.direction-bottom{--fds-grow-clip-path:polygon(0 75%,100% 75%,100% 100%,0 100%)}</style>
@@ -14,6 +14,8 @@ declare const __propDef: {
14
14
  disabled?: boolean;
15
15
  open?: boolean;
16
16
  acrylic?: boolean;
17
+ direction?: "auto" | "top" | "bottom";
18
+ autoWidth?: boolean;
17
19
  class?: string;
18
20
  inputElement?: HTMLInputElement;
19
21
  searchInputElement?: HTMLInputElement;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fluent-svelte-extra",
3
- "version": "2.1.4",
3
+ "version": "2.1.6",
4
4
  "description": "A faithful implementation of Microsoft's Fluent Design System in Svelte.",
5
5
  "homepage": "https://github.com/OpenAnime/fluent-svelte-extra",
6
6
  "license": "MIT",