svelte-fluentui 1.1.0 → 1.3.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/README.md +17 -29
- package/dist/assets/styles/components.scss +23 -3
- package/dist/assets/styles/fluent-ui/fluent-components.scss +0 -10
- package/dist/assets/styles/layout.scss +43 -5
- package/dist/components/Checkbox.svelte +21 -15
- package/dist/components/Combobox.svelte +1 -9
- package/dist/components/Divider.svelte +9 -2
- package/dist/components/Divider.svelte.d.ts +2 -0
- package/dist/components/PositioningRegion.svelte +23 -5
- package/dist/components/PositioningRegion.svelte.d.ts +6 -0
- package/dist/components/QuickGrid.svelte.d.ts +7 -7
- package/dist/components/Select.svelte +665 -188
- package/dist/components/Select.svelte.d.ts +6 -3
- package/dist/components/Switch.svelte +19 -13
- package/dist/components/layout/Footer.svelte +29 -3
- package/dist/components/layout/Footer.svelte.d.ts +5 -0
- package/dist/components/layout/Panel.svelte +266 -0
- package/dist/components/layout/Panel.svelte.d.ts +18 -0
- package/dist/components/layout/TopNav.svelte +185 -84
- package/dist/components/layout/TopNav.svelte.d.ts +4 -0
- package/dist/components/layout/index.d.ts +1 -0
- package/dist/components/layout/index.js +1 -0
- package/dist/main.css +60 -16
- package/dist/main.css.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,35 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
A comprehensive Svelte wrapper library for Microsoft FluentUI web components (v2.6.x), providing a seamless way to use FluentUI components in Svelte applications.
|
|
4
4
|
|
|
5
|
-
## What's New in v1.
|
|
6
|
-
|
|
7
|
-
- **`
|
|
8
|
-
- **`
|
|
9
|
-
- **`
|
|
10
|
-
- **`
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- **`
|
|
18
|
-
- **`
|
|
19
|
-
-
|
|
20
|
-
- **`
|
|
21
|
-
- **`
|
|
22
|
-
- **`Checkbox` — `labelPosition="end"` (now the default)** — was `"start"` (label on the LEFT, atypical for forms). New default puts the label after the box `[☐] Label text`. Implemented via flex `order` so a trailing status message stays after the [box, label] pair without flipping.
|
|
23
|
-
- **Docs — per-page SEO metadata via shared `<Meta>` component on all 63 routes** — every page now emits its own `<title>`, description, keywords, canonical, Open Graph, and Twitter Card tags. Browser tabs, bookmarks, and JS-capable crawlers (Google) get the per-page tags; non-JS crawlers (Slack, Discord, Facebook, LinkedIn, X) still see the static `app.html` fallback since the docs site runs as a pure SPA.
|
|
24
|
-
- **Docs — every `<h1>` / `<h2>` / `<h3>` in component pages is now a shareable anchor with a copy-link button on hover** — pure post-render DOM decoration at the layout level, so it works on every existing and future component page automatically. Stable slugified ids, `-2`/`-3` suffixes on collisions, copy-to-clipboard with flash feedback.
|
|
25
|
-
- **Docs — shared `<References>` component replaces hand-rolled references cards on 48 pages** — single source of truth for the references block; `na: true` / `custom: true` variants for "Not available in FluentUI Web Components" and "Custom component" disabled spans with tooltips. Format tweaks now live in one file instead of 48.
|
|
26
|
-
- **Docs — API tables relocated to the BOTTOM of every component page, AFTER the Examples** — the previous layout forced visitors to scroll past dense reference material to reach the examples. New order: `[title + description] → [References] → [Examples] → [API tables]`.
|
|
27
|
-
- **`InputFile` — 2547-line component split across six files for maintainability** — types extracted to `InputFile.types.ts`, utilities + default labels to `InputFile.utils.ts`, ~725 lines of inline CSS to an external SCSS partial, and the three `selectorAppearance` variants pulled into `InputFileSelectorCard.svelte` / `InputFileSelectorButton.svelte` / `InputFileSelectorMinimal.svelte`. Public API unchanged; type-check clean.
|
|
28
|
-
|
|
29
|
-
### Previously (rc22)
|
|
30
|
-
|
|
31
|
-
- **`InputFile` chips mode now has an overall progress footer** — the same `Pause all` / `Resume all` / `Retry all` controls plus the aggregate progress bar that list/popover modes already had. Works for both `chipsPosition` values; rendered as a sibling below the chips so layout stays sane regardless of position.
|
|
32
|
-
- **`package.json` `homepage` points at the docs site** — npm's "Homepage" sidebar link now goes to `svelte-fluentui.keenmate.dev` instead of duplicating the GitHub repo link. Two distinct destinations on the package page.
|
|
33
|
-
- **InputFile demo playground persists in localStorage** — the live selector × list × cardSize × chipsPosition mixer at `/components/inputfile` remembers your last configuration across page reloads. Files themselves are not persisted (File objects don't survive JSON).
|
|
5
|
+
## What's New in v1.3.0
|
|
6
|
+
|
|
7
|
+
- **`Panel` — new slide-in side-panel primitive** — fixed-position, edge-anchored container with a single `children` slot and CSS-driven open/close transitions. Props cover physical sides (`left`/`right`), logical sides (`start`/`end` that follow RTL), `width`, `overlay`, `closeOnOutsideClick`, `closeOnEscape`, and a new `top` offset so the panel + overlay can sit below a sticky header (e.g. TopNav) and leave the trigger button clickable. Portals to `document.body` with direction captured before portal so locally-RTL wrappers still anchor correctly. First-class demo at `/components/navigation-layout/panel`.
|
|
8
|
+
- **`TopNav` drawer rebuilt on `Panel`; container queries replace media queries** — the bespoke `.mobile-sidebar` div with hand-rolled `left: -280px` / `transition` CSS is gone, replaced with `<Panel side="start" width="280px" top="{height}px">` so Escape-close, portal, overlay outside-click, and `aria-modal` all come for free. The collapse breakpoint is now an `@container topnav (max-width: 960px)` query keyed on the nav's own width (aligns with Grid's `md`), so behavior is intrinsic to the bar regardless of where it's mounted. `items` auto-populate the drawer, the hamburger only renders when there's content to open, and the action slot now stays visible at every width.
|
|
9
|
+
- **`TopNav` — `brandTemplate`, `drawerContent`, and `collapse` snippets/props** — `brandTemplate` replaces the default `<a>` brand rendering so consumers can compose logo + wordmark + version badge as one unit; `drawerContent: Snippet<[() => void]>` renders custom content inside the mobile drawer and receives a `closeDrawer` callback so link clicks can dismiss the drawer before navigation; `collapse: "auto" | "always" | "never"` overrides the container-query state when the consumer drives sidebar visibility from its own responsive breakpoint. First demo page added at `/components/navigation-layout/topnav`.
|
|
10
|
+
- **`Footer` — `start` / `center` / `end` named snippets with a truly-centered grid layout** — Footer previously had a single `children` slot, so a "© left, brand center, version right" arrangement required inline `justify-content: space-between` and hoping the middle item floated where you wanted. The new snippets switch Footer into a CSS Grid (`1fr auto 1fr`) where the center column is genuinely centered regardless of side-section widths, with explicit `grid-column` placement so a missing section doesn't reflow the others. New `stack` prop (default `true`) collapses to a single inline-start column below 600px via a container query keyed on the footer itself. RTL flips `start` ↔ `end` automatically.
|
|
11
|
+
- **`Footer` — class namespaced as `.fluent-footer`, wired to the dedicated theme tokens, thin-strip bug fixed** — the rendered class went from generic `.footer` (collided with anything else using that name) to `.fluent-footer`, the rule now reads from `--fluent-footer-bg/text/border` (which were defined in the theme system but unused) with the previous neutral-layer values as fallback, a duplicate Blazor-port `.footer` rule was deleted, and `min-height: 48px` + `padding: 0.75rem 1rem` replaces the original horizontal-only padding so a default Footer is no longer a ~24px thin strip. First dedicated demo page at `/components/navigation-layout/footer`.
|
|
12
|
+
- **Docs site dogfoods the new primitives** — the hand-rolled `<div class="topnav">` with ~90 lines of parallel CSS is replaced with `<TopNav class="docs-topnav" collapse="always">` using `brandTemplate` for the brand+version pair and `drawerContent` for the mobile sidebar nav. The sidebar nav is extracted into a single `{#snippet sidebarNav(closeDrawer)}` rendered both as the desktop sidebar and inside the TopNav drawer, with the sidebar/hamburger handoff at `lg` (1280px) instead of `md` so laptops at 1280×800 stay roomy. The footer at the bottom of every page now uses the three-part layout (© + MIT / attribution / GitHub + npm + version chip).
|
|
13
|
+
|
|
14
|
+
## What's New in v1.2.0
|
|
15
|
+
|
|
16
|
+
- **`Divider` — `orientation` and `role` props now forwarded** — the wrapper previously only exposed `class` and `style`, so vertical dividers and `role="presentation"` (for decorative separators that should be skipped by screen readers) weren't expressible through the Svelte API. `<fluent-divider>` natively supports both via fast-foundation; the wrapper just forwards them. Defaults preserved (`orientation="horizontal"`, `role="separator"`) so every existing call site renders identically. First proper demo page at `/components/divider` — the previous `/divider` route was an HMR sandbox and the components-list link to `/components/divider` was a 404.
|
|
17
|
+
- **`Select` rewritten as a custom component** — the wrapped `<fluent-select>` rendered its dropdown listbox inside its own shadow DOM with a static `--max-height`, so inside Dialogs and other overflow-hidden ancestors the option list extended past the viewport with no scroll cutoff. New custom Select portals the listbox to `document.body` via `PositioningRegion` (Floating-UI), so it escapes any clipping ancestor and stays inside the viewport regardless of where the trigger sits. Full keyboard wiring (Arrow/Home/End/Enter/Space/Escape/Tab, single-char type-ahead with cycle-through-matches), multi-mode renders an always-expanded inline listbox matching FluentUI Blazor, and a hidden `<input>` keeps native form submission working. Public API mostly preserved; `value` widened to `string | string[]` for multi mode, `open` is now bindable, and `position` means "force placement" rather than the old static attribute.
|
|
18
|
+
- **`PositioningRegion` — new `availableHeight` prop** — writes the computed remaining viewport height into the `--available-height` CSS custom property on the floating element on every reposition, so dropdowns can cap their max-height with `max-height: var(--available-height, <fallback>)` instead of hard-coding a value that overflows on small screens or near viewport edges. Works alongside `matchWidth` in a single `size()` middleware pass.
|
|
19
|
+
- **`.fluent-value-label` — new canonical class for inline value labels next to a control** — separates field labels (the bold, stacked-above text that names a form field) from value labels (the inline text next to a single control that describes the value, e.g. "Remember me" next to a checkbox). Value labels are normal weight with a pointer cursor, matching FluentUI Blazor's pickers and `<fluent-radio>`'s slotted label. `data-disabled` / `data-readonly` on the wrapper drive a `not-allowed` cursor when the host is inactive.
|
|
20
|
+
- **`Checkbox` & `Switch` — inline label fixes** — labels were rendering bold with a text cursor (using the field-label class) and clicks on the label didn't reliably toggle the control when no `id` was passed. Switched to the new `.fluent-value-label` class, and a stable per-instance `fallbackId` is now used as `<label for>` / element `id` when the caller didn't supply one, so label-click-to-toggle works regardless of whether an `id` was passed in. Applies across all three `labelPosition` values (`top` / `start` / `end`).
|
|
21
|
+
- **`Select` & `Combobox` — field-label class consolidated to shared `.fluent-label`** — both components had component-scoped `.select-label` / `.combobox-label` rules that duplicated the canonical `.fluent-label` declarations from `assets/styles/components.scss`. A single library-wide tweak to label styling now lives in one place. After this change, every component that renders a stacked field label uses `.fluent-label`, Field uses its BEM-namespaced `fluent-field__label`, and Checkbox/Switch use `.fluent-value-label` — three classes total, each with a clear semantic role.
|
|
34
22
|
|
|
35
23
|
## Features
|
|
36
24
|
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
align-items: center;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
// Canonical label
|
|
36
|
-
//
|
|
37
|
-
//
|
|
35
|
+
// Canonical FIELD label — bold, block, sits ABOVE a stacked input
|
|
36
|
+
// (TextField, Select, Combobox, Autocomplete, NumberField, Textarea, Slider,
|
|
37
|
+
// DatePicker, TimePicker, RadioGroup, and Checkbox/Switch when labelPosition="top").
|
|
38
38
|
.fluent-label {
|
|
39
39
|
display: block;
|
|
40
40
|
font-size: 0.875rem;
|
|
@@ -44,3 +44,23 @@
|
|
|
44
44
|
margin-bottom: 0.25rem;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
// Canonical VALUE label — inline, normal weight, pointer cursor.
|
|
48
|
+
// Used for the text that sits next to a control and describes the value/option
|
|
49
|
+
// itself (Checkbox/Switch inline labels in labelPosition="start"/"end"). The
|
|
50
|
+
// pointer cursor is the sole hover affordance — no color shift, matching how
|
|
51
|
+
// fluent-radio's slotted default-slot label behaves natively.
|
|
52
|
+
.fluent-value-label {
|
|
53
|
+
display: inline;
|
|
54
|
+
font-size: 0.875rem;
|
|
55
|
+
font-weight: normal;
|
|
56
|
+
line-height: 1.25;
|
|
57
|
+
color: var(--neutral-foreground-rest);
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
user-select: none;
|
|
60
|
+
}
|
|
61
|
+
// Disabled / readonly host swaps the cursor to indicate non-interactivity.
|
|
62
|
+
[data-disabled="true"] > .fluent-value-label,
|
|
63
|
+
[data-readonly="true"] > .fluent-value-label {
|
|
64
|
+
cursor: not-allowed;
|
|
65
|
+
}
|
|
66
|
+
|
|
@@ -1068,16 +1068,6 @@ div[dragged-over="true"] {
|
|
|
1068
1068
|
animation: blinker 1s linear infinite;
|
|
1069
1069
|
}
|
|
1070
1070
|
|
|
1071
|
-
/* _content/Microsoft.FluentUI.AspNetCore.Components/Components/Footer/FluentFooter.razor.rz.scp.css */
|
|
1072
|
-
.footer {
|
|
1073
|
-
display: flex;
|
|
1074
|
-
z-index: 10;
|
|
1075
|
-
flex-direction: row;
|
|
1076
|
-
font-family: var(--body-font);
|
|
1077
|
-
font-weight: normal;
|
|
1078
|
-
font-size: var(--type-ramp-minus-1-font-size);
|
|
1079
|
-
line-height: var(--type-ramp-minus-1-line-height);
|
|
1080
|
-
}
|
|
1081
1071
|
|
|
1082
1072
|
/* _content/Microsoft.FluentUI.AspNetCore.Components/Components/Forms/FluentValidationMessage.razor.rz.scp.css */
|
|
1083
1073
|
.validation-message {
|
|
@@ -35,12 +35,50 @@
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// Footer component
|
|
38
|
-
.footer {
|
|
38
|
+
.fluent-footer {
|
|
39
39
|
display: flex;
|
|
40
40
|
align-items: center;
|
|
41
|
-
background-color: var(--neutral-layer-4);
|
|
42
|
-
color: var(--neutral-foreground-rest);
|
|
43
|
-
border-top: 1px solid var(--neutral-stroke-layer-rest);
|
|
44
|
-
padding: 0 1rem;
|
|
41
|
+
background-color: var(--fluent-footer-bg, var(--neutral-layer-4));
|
|
42
|
+
color: var(--fluent-footer-text, var(--neutral-foreground-rest));
|
|
43
|
+
border-top: 1px solid var(--fluent-footer-border, var(--neutral-stroke-layer-rest));
|
|
44
|
+
padding: 0.75rem 1rem;
|
|
45
|
+
min-height: 48px;
|
|
46
|
+
z-index: 10;
|
|
45
47
|
transition: background-color 0.3s ease, color 0.3s ease;
|
|
46
48
|
}
|
|
49
|
+
|
|
50
|
+
// Three-part mode: switch to CSS Grid so the center column is truly centered
|
|
51
|
+
// (1fr | auto | 1fr — side columns absorb equal slack regardless of widths).
|
|
52
|
+
// Explicit grid-column placement so a missing section doesn't shift the
|
|
53
|
+
// remaining ones into the wrong column.
|
|
54
|
+
.fluent-footer--three-part {
|
|
55
|
+
display: grid;
|
|
56
|
+
grid-template-columns: 1fr auto 1fr;
|
|
57
|
+
gap: 1rem;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.fluent-footer__start { grid-column: 1; justify-self: start; }
|
|
61
|
+
.fluent-footer__center { grid-column: 2; justify-self: center; }
|
|
62
|
+
.fluent-footer__end { grid-column: 3; justify-self: end; }
|
|
63
|
+
|
|
64
|
+
// Stacking on narrow widths — opt-in via the `stack` prop (default true).
|
|
65
|
+
// Container query keyed on the footer itself so behavior is intrinsic to
|
|
66
|
+
// the bar's width, not the viewport (mirrors TopNav's approach).
|
|
67
|
+
.fluent-footer--stacks {
|
|
68
|
+
container-type: inline-size;
|
|
69
|
+
container-name: fluent-footer;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@container fluent-footer (max-width: 600px) {
|
|
73
|
+
.fluent-footer--stacks {
|
|
74
|
+
grid-template-columns: 1fr;
|
|
75
|
+
gap: 0.5rem;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.fluent-footer--stacks .fluent-footer__start,
|
|
79
|
+
.fluent-footer--stacks .fluent-footer__center,
|
|
80
|
+
.fluent-footer--stacks .fluent-footer__end {
|
|
81
|
+
grid-column: 1;
|
|
82
|
+
justify-self: start;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -56,6 +56,16 @@
|
|
|
56
56
|
onclick = undefined
|
|
57
57
|
}: Props = $props()
|
|
58
58
|
|
|
59
|
+
// Stable fallback id so <label for={...}> always links to the checkbox —
|
|
60
|
+
// without it, clicking the value label on an id-less <Checkbox /> wouldn't
|
|
61
|
+
// toggle the box.
|
|
62
|
+
const fallbackId = `fluent-checkbox-${Math.random().toString(36).slice(2, 11)}`
|
|
63
|
+
const effectiveId = $derived(id ?? fallbackId)
|
|
64
|
+
|
|
65
|
+
// Checkbox label always describes the value next to the control — never a
|
|
66
|
+
// field-label — so styling stays the same across all positions; only the
|
|
67
|
+
// wrapper's flex direction changes per labelPosition.
|
|
68
|
+
|
|
59
69
|
const currentMessage = $derived(
|
|
60
70
|
checked === true ? checkedMessage
|
|
61
71
|
: checked === false ? uncheckedMessage
|
|
@@ -126,9 +136,14 @@
|
|
|
126
136
|
}
|
|
127
137
|
</script>
|
|
128
138
|
|
|
129
|
-
<span
|
|
139
|
+
<span
|
|
140
|
+
class="fluent-checkbox-wrapper"
|
|
141
|
+
data-label-position={labelPosition}
|
|
142
|
+
data-disabled={disabled ? "true" : null}
|
|
143
|
+
data-readonly={readonly ? "true" : null}
|
|
144
|
+
>
|
|
130
145
|
{#if label || labelTemplate || children}
|
|
131
|
-
<label for={
|
|
146
|
+
<label for={effectiveId} class="fluent-value-label">
|
|
132
147
|
{#if label}{label}{/if}
|
|
133
148
|
{#if labelTemplate}{@render labelTemplate?.()}{/if}
|
|
134
149
|
{#if children}{@render children?.()}{/if}
|
|
@@ -146,7 +161,7 @@
|
|
|
146
161
|
{readonly}
|
|
147
162
|
{disabled}
|
|
148
163
|
{required}
|
|
149
|
-
{
|
|
164
|
+
id={effectiveId}
|
|
150
165
|
{name}
|
|
151
166
|
aria-label={ariaLabel || label || null}
|
|
152
167
|
class={className || null}
|
|
@@ -176,17 +191,8 @@
|
|
|
176
191
|
gap: 0.5rem;
|
|
177
192
|
}
|
|
178
193
|
|
|
179
|
-
/*
|
|
180
|
-
|
|
181
|
-
margin extends the label's flex-item box downward, so `align-items:
|
|
182
|
-
center` lifts the label's visible text above the checkbox midline. Zero
|
|
183
|
-
it out for start/end; keep it for top where the bottom margin is the
|
|
184
|
-
intended gap before the control. */
|
|
185
|
-
.fluent-checkbox-wrapper[data-label-position="start"] .fluent-label,
|
|
186
|
-
.fluent-checkbox-wrapper[data-label-position="end"] .fluent-label {
|
|
187
|
-
margin-bottom: 0;
|
|
188
|
-
}
|
|
189
|
-
|
|
194
|
+
/* "top" position: label stacks above the checkbox. Label keeps its
|
|
195
|
+
value-label styling — only the wrapper layout changes. */
|
|
190
196
|
.fluent-checkbox-wrapper[data-label-position="top"] {
|
|
191
197
|
flex-direction: column;
|
|
192
198
|
align-items: flex-start;
|
|
@@ -200,7 +206,7 @@
|
|
|
200
206
|
We use the `order` property rather than `flex-direction: row-reverse`
|
|
201
207
|
so the optional status message always trails the [checkbox, label] pair
|
|
202
208
|
instead of jumping to the front (which row-reverse would do). */
|
|
203
|
-
.fluent-checkbox-wrapper[data-label-position="end"] .fluent-label {
|
|
209
|
+
.fluent-checkbox-wrapper[data-label-position="end"] :global(.fluent-value-label) {
|
|
204
210
|
order: 1;
|
|
205
211
|
}
|
|
206
212
|
.fluent-checkbox-wrapper[data-label-position="end"] .checkbox-message {
|
|
@@ -239,7 +239,7 @@
|
|
|
239
239
|
|
|
240
240
|
<!-- svelte-ignore a11y_label_has_associated_control -->
|
|
241
241
|
{#if label || labelTemplate}
|
|
242
|
-
<label class="
|
|
242
|
+
<label class="fluent-label" for={id}>
|
|
243
243
|
{#if label}
|
|
244
244
|
{label}
|
|
245
245
|
{/if}
|
|
@@ -282,14 +282,6 @@
|
|
|
282
282
|
</fluent-combobox>
|
|
283
283
|
|
|
284
284
|
<style>
|
|
285
|
-
.combobox-label {
|
|
286
|
-
display: block;
|
|
287
|
-
font-size: 0.875rem;
|
|
288
|
-
font-weight: 600;
|
|
289
|
-
color: var(--neutral-foreground-rest);
|
|
290
|
-
margin-bottom: 0.25rem;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
285
|
.required-indicator {
|
|
294
286
|
color: var(--error-foreground-rest, #d13438);
|
|
295
287
|
margin-left: 0.25rem;
|
|
@@ -8,9 +8,11 @@
|
|
|
8
8
|
type Props = {
|
|
9
9
|
class?: string
|
|
10
10
|
style?: string
|
|
11
|
+
orientation?: "horizontal" | "vertical"
|
|
12
|
+
role?: "separator" | "presentation"
|
|
11
13
|
}
|
|
12
14
|
|
|
13
|
-
let {class: className = "", style = ""}: Props = $props()
|
|
15
|
+
let {class: className = "", style = "", orientation = "horizontal", role = "separator"}: Props = $props()
|
|
14
16
|
</script>
|
|
15
17
|
|
|
16
18
|
<!-- fluent-divider's shadow DOM borders itself with `--neutral-stroke-divider-rest`
|
|
@@ -18,5 +20,10 @@
|
|
|
18
20
|
page background and reads as invisible. Re-point the token at the heavier
|
|
19
21
|
`--neutral-stroke-rest` so the line actually shows up. The variable is
|
|
20
22
|
inherited into the shadow DOM, so setting it on the host suffices. -->
|
|
21
|
-
<fluent-divider
|
|
23
|
+
<fluent-divider
|
|
24
|
+
class={className}
|
|
25
|
+
{orientation}
|
|
26
|
+
{role}
|
|
27
|
+
style="--neutral-stroke-divider-rest: var(--neutral-stroke-rest); {style}"
|
|
28
|
+
></fluent-divider>
|
|
22
29
|
|
|
@@ -28,6 +28,12 @@
|
|
|
28
28
|
* width via Floating UI's `size` middleware. Useful for dropdowns whose
|
|
29
29
|
* options should align under the input. */
|
|
30
30
|
matchWidth?: boolean
|
|
31
|
+
/** When true, exposes the remaining viewport height as the CSS custom
|
|
32
|
+
* property `--available-height` on the floating element (minus the
|
|
33
|
+
* shift padding). Consumers should set max-height: var(--available-height)
|
|
34
|
+
* on a scroll container inside, so the dropdown stays inside the viewport
|
|
35
|
+
* regardless of which side flip() picks. */
|
|
36
|
+
availableHeight?: boolean
|
|
31
37
|
children?: SlotType
|
|
32
38
|
}
|
|
33
39
|
|
|
@@ -39,6 +45,7 @@
|
|
|
39
45
|
position: positionProp = "bottom",
|
|
40
46
|
align: alignProp = "center",
|
|
41
47
|
matchWidth = true,
|
|
48
|
+
availableHeight = false,
|
|
42
49
|
children = undefined
|
|
43
50
|
}: Props = $props()
|
|
44
51
|
|
|
@@ -60,10 +67,12 @@
|
|
|
60
67
|
anchor: HTMLElement
|
|
61
68
|
placement: Placement
|
|
62
69
|
matchWidth: boolean
|
|
70
|
+
availableHeight: boolean
|
|
63
71
|
}
|
|
64
72
|
|
|
65
73
|
function position(node: HTMLElement, params: PositionParams) {
|
|
66
74
|
let cleanup: () => void = () => {}
|
|
75
|
+
const SHIFT_PADDING = 8
|
|
67
76
|
|
|
68
77
|
function attach(p: PositionParams) {
|
|
69
78
|
cleanup()
|
|
@@ -71,13 +80,22 @@
|
|
|
71
80
|
const middleware = [
|
|
72
81
|
offset(0),
|
|
73
82
|
flip(),
|
|
74
|
-
shift({padding:
|
|
83
|
+
shift({padding: SHIFT_PADDING})
|
|
75
84
|
]
|
|
76
|
-
if (p.matchWidth) {
|
|
85
|
+
if (p.matchWidth || p.availableHeight) {
|
|
77
86
|
middleware.push(
|
|
78
87
|
size({
|
|
79
|
-
|
|
80
|
-
|
|
88
|
+
padding: SHIFT_PADDING,
|
|
89
|
+
apply({rects, elements, availableHeight: h}) {
|
|
90
|
+
if (p.matchWidth) {
|
|
91
|
+
elements.floating.style.width = `${rects.reference.width}px`
|
|
92
|
+
}
|
|
93
|
+
if (p.availableHeight) {
|
|
94
|
+
elements.floating.style.setProperty(
|
|
95
|
+
"--available-height",
|
|
96
|
+
`${Math.max(0, Math.floor(h))}px`
|
|
97
|
+
)
|
|
98
|
+
}
|
|
81
99
|
}
|
|
82
100
|
})
|
|
83
101
|
)
|
|
@@ -110,7 +128,7 @@
|
|
|
110
128
|
{#if visible}
|
|
111
129
|
<div
|
|
112
130
|
use:portal
|
|
113
|
-
use:position={{anchor, placement, matchWidth}}
|
|
131
|
+
use:position={{anchor, placement, matchWidth, availableHeight}}
|
|
114
132
|
class="positioning-region positioning-region-floating"
|
|
115
133
|
{title}
|
|
116
134
|
style="position: fixed; top: 0; left: 0; {style}"
|
|
@@ -15,6 +15,12 @@ type Props = {
|
|
|
15
15
|
* width via Floating UI's `size` middleware. Useful for dropdowns whose
|
|
16
16
|
* options should align under the input. */
|
|
17
17
|
matchWidth?: boolean;
|
|
18
|
+
/** When true, exposes the remaining viewport height as the CSS custom
|
|
19
|
+
* property `--available-height` on the floating element (minus the
|
|
20
|
+
* shift padding). Consumers should set max-height: var(--available-height)
|
|
21
|
+
* on a scroll container inside, so the dropdown stays inside the viewport
|
|
22
|
+
* regardless of which side flip() picks. */
|
|
23
|
+
availableHeight?: boolean;
|
|
18
24
|
children?: SlotType;
|
|
19
25
|
};
|
|
20
26
|
declare const PositioningRegion: import("svelte").Component<Props, {}, "">;
|
|
@@ -32,7 +32,7 @@ declare function $$render<T>(): {
|
|
|
32
32
|
filter?: ((filterValue: string, row: T) => boolean | null) | undefined;
|
|
33
33
|
isEditable?: boolean | ((row: T) => boolean) | undefined;
|
|
34
34
|
editor?: "number" | "select" | "text" | "custom" | "autocomplete" | "combobox" | "checkbox" | "date";
|
|
35
|
-
editTrigger?: "
|
|
35
|
+
editTrigger?: "click" | "dblclick" | "button" | "always" | "navigate";
|
|
36
36
|
editorOptions?: {
|
|
37
37
|
options?: {
|
|
38
38
|
[key: string]: unknown;
|
|
@@ -123,7 +123,7 @@ declare function $$render<T>(): {
|
|
|
123
123
|
style?: string;
|
|
124
124
|
cellTemplate?: SlotType;
|
|
125
125
|
editable?: boolean;
|
|
126
|
-
editTrigger?: "
|
|
126
|
+
editTrigger?: "click" | "dblclick" | "button" | "always" | "navigate";
|
|
127
127
|
dropdownShowOnFocus?: boolean;
|
|
128
128
|
isRowEditable?: boolean | ((row: T) => boolean) | undefined;
|
|
129
129
|
checkboxAlwaysEditable?: boolean;
|
|
@@ -201,7 +201,7 @@ declare function $$render<T>(): {
|
|
|
201
201
|
filter?: ((filterValue: string, row: T) => boolean | null) | undefined;
|
|
202
202
|
isEditable?: boolean | ((row: T) => boolean) | undefined;
|
|
203
203
|
editor?: "number" | "select" | "text" | "custom" | "autocomplete" | "combobox" | "checkbox" | "date";
|
|
204
|
-
editTrigger?: "
|
|
204
|
+
editTrigger?: "click" | "dblclick" | "button" | "always" | "navigate";
|
|
205
205
|
editorOptions?: {
|
|
206
206
|
options?: {
|
|
207
207
|
[key: string]: unknown;
|
|
@@ -310,7 +310,7 @@ declare function $$render<T>(): {
|
|
|
310
310
|
filter?: ((filterValue: string, row: T) => boolean | null) | undefined;
|
|
311
311
|
isEditable?: boolean | ((row: T) => boolean) | undefined;
|
|
312
312
|
editor?: "number" | "select" | "text" | "custom" | "autocomplete" | "combobox" | "checkbox" | "date";
|
|
313
|
-
editTrigger?: "
|
|
313
|
+
editTrigger?: "click" | "dblclick" | "button" | "always" | "navigate";
|
|
314
314
|
editorOptions?: {
|
|
315
315
|
options?: {
|
|
316
316
|
[key: string]: unknown;
|
|
@@ -418,7 +418,7 @@ declare function $$render<T>(): {
|
|
|
418
418
|
filter?: ((filterValue: string, row: T) => boolean | null) | undefined;
|
|
419
419
|
isEditable?: boolean | ((row: T) => boolean) | undefined;
|
|
420
420
|
editor?: "number" | "select" | "text" | "custom" | "autocomplete" | "combobox" | "checkbox" | "date";
|
|
421
|
-
editTrigger?: "
|
|
421
|
+
editTrigger?: "click" | "dblclick" | "button" | "always" | "navigate";
|
|
422
422
|
editorOptions?: {
|
|
423
423
|
options?: {
|
|
424
424
|
[key: string]: unknown;
|
|
@@ -529,7 +529,7 @@ declare function $$render<T>(): {
|
|
|
529
529
|
filter?: ((filterValue: string, row: T) => boolean | null) | undefined;
|
|
530
530
|
isEditable?: boolean | ((row: T) => boolean) | undefined;
|
|
531
531
|
editor?: "number" | "select" | "text" | "custom" | "autocomplete" | "combobox" | "checkbox" | "date";
|
|
532
|
-
editTrigger?: "
|
|
532
|
+
editTrigger?: "click" | "dblclick" | "button" | "always" | "navigate";
|
|
533
533
|
editorOptions?: {
|
|
534
534
|
options?: {
|
|
535
535
|
[key: string]: unknown;
|
|
@@ -638,7 +638,7 @@ declare function $$render<T>(): {
|
|
|
638
638
|
filter?: ((filterValue: string, row: T) => boolean | null) | undefined;
|
|
639
639
|
isEditable?: boolean | ((row: T) => boolean) | undefined;
|
|
640
640
|
editor?: "number" | "select" | "text" | "custom" | "autocomplete" | "combobox" | "checkbox" | "date";
|
|
641
|
-
editTrigger?: "
|
|
641
|
+
editTrigger?: "click" | "dblclick" | "button" | "always" | "navigate";
|
|
642
642
|
editorOptions?: {
|
|
643
643
|
options?: {
|
|
644
644
|
[key: string]: unknown;
|