svelte-fluentui 1.3.1 → 1.3.3
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 +8 -12
- package/dist/components/Accordion.svelte +1 -1
- package/dist/components/AccordionItem.svelte +7 -3
- package/dist/components/Anchor.svelte +12 -12
- package/dist/components/Badge.svelte +5 -1
- package/dist/components/Badge.svelte.d.ts +1 -0
- package/dist/components/BreadcrumbItem.svelte +1 -1
- package/dist/components/Button.svelte +16 -16
- package/dist/components/Checkbox.svelte +10 -10
- package/dist/components/Combobox.svelte +13 -13
- package/dist/components/DataGrid.svelte +4 -4
- package/dist/components/DataGridCell.svelte +8 -8
- package/dist/components/DataGridRow.svelte +3 -3
- package/dist/components/Dialog.svelte +5 -5
- package/dist/components/Listbox.svelte +3 -3
- package/dist/components/MenuButton.svelte +3 -3
- package/dist/components/NumberField.svelte +15 -15
- package/dist/components/Option.svelte +6 -6
- package/dist/components/Paginator.svelte +4 -4
- package/dist/components/QuickGrid.svelte +1 -1
- package/dist/components/QuickGrid.svelte.d.ts +2 -2
- package/dist/components/Slider.svelte +12 -12
- package/dist/components/Switch.svelte +8 -8
- package/dist/components/TabPanel.svelte +1 -1
- package/dist/components/TextField.svelte +14 -14
- package/dist/components/Textarea.svelte +16 -16
- package/dist/components/Toolbar.svelte +3 -3
- package/dist/components/layout/TopNav.svelte +62 -40
- package/dist/components/layout/TopNav.svelte.d.ts +2 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,21 +2,17 @@
|
|
|
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.3.
|
|
5
|
+
## What's New in v1.3.3
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
- **`TopNav` — new `drawerPinned` + `drawerWidth` props turn the drawer into a permanent left rail with an always-visible hamburger toggle** — composes Panel's `pinned` so the same `drawerContent` snippet that renders the mobile overlay drawer also renders the desktop rail. `drawerWidth` (default `"280px"`) propagates to both modes. The hamburger stays visible when pinned so the user can collapse the rail back away, and an effect re-syncs the drawer's `open` state to `drawerPinned` on viewport flips (narrow→wide auto-opens, wide→narrow auto-closes).
|
|
9
|
-
- **Docs layout switched to a single nav surface at every width via `drawerPinned`** — the duplicate desktop sidebar `GridItem` is gone; TopNav's drawer now renders as a pinned `<aside>` at ≥1024px and collapses to the hamburger overlay below. The layout uses CSS Grid with `grid-template-areas` and a `matchMedia` listener to drive `drawerPinned`. The pinned rail is `position: sticky` below the topnav and the scrollbar sits flush with the rail's inside edge.
|
|
10
|
-
- **`TopNav` — tightened horizontal padding from `1.5rem` to `0.5rem`** — the bar's inside edges felt cramped relative to the rest of the content. Brand + hamburger now sit closer to the inline-start edge and the action slot sits closer to the inline-end edge.
|
|
7
|
+
- **Custom-element attribute bindings stop stringifying `undefined` / `null` / `false`** — Recurring regression (last fixed ~5 months ago, reintroduced during the structural rework) that affected 22 wrappers including `TextField`, `Textarea`, `Switch`, `Slider`, `Checkbox`, `Button`, `Anchor`, `Accordion(Item)`, `BreadcrumbItem`, `DataGrid(Row/Cell)`, `Dialog`, `Listbox`, `MenuButton`, `Option`, `TabPanel`, `Toolbar`, `NumberField`, `Combobox`, plus `Paginator` and `QuickGrid` sub-buttons. Svelte 5 sets properties on custom elements rather than attributes, and FAST's `@attr` decorators stringify whatever they receive — so unset props were rendering as `title="undefined"`, `readonly="false"`, `disabled="false"`, etc. The `readonly`/`disabled` cases were the worst symptom because `[readonly]` and `[disabled]` CSS attribute-presence selectors match regardless of value, leaving an enabled field with a not-allowed cursor. All affected wrappers converted to the conditional-spread pattern (`{...(title ? { title } : {})}`) which physically omits the attribute from the template when unset. Variants `{...(value != null ? { value } : {})}` for inputs (so `value=""` still renders) and `{...(attr !== undefined ? { attr } : {})}` for numeric props (so `0` survives) are used where falsy values are meaningful.
|
|
11
8
|
|
|
12
|
-
|
|
9
|
+
- **`TextField` demo page — new Readonly and Disabled example sections** — The `/components/forms/text-field` showcase previously demonstrated only the basic input and `autocomplete` variants; the readonly and disabled states (the surface that exposed the bug above) had no live example. Added Readonly with outline + filled variants and Disabled with three variants (outline + placeholder, outline + value, filled + value).
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- **`TopNav` —
|
|
17
|
-
- **`
|
|
18
|
-
- **`
|
|
19
|
-
- **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).
|
|
11
|
+
## What's New in v1.3.2
|
|
12
|
+
|
|
13
|
+
- **`TopNav` — hamburger flexibility via `menuToggleSize` + `menuToggleTemplate`** — `menuToggleSize` (default `42`) flows through a `--topnav-toggle-size` CSS variable so the glyph and close-icon scale proportionally with the box. `menuToggleTemplate: Snippet<[{open, toggle}]>` lets consumers render any button shape — text + chevron, brand-styled accent button, custom SVG — and still wire up state correctly. Both paths render inside a wrapper that owns the visibility/order/collapse rules, so custom templates automatically inherit hide-when-wide / show-when-narrow / stay-visible-when-pinned behavior.
|
|
14
|
+
- **`TopNav` — default hamburger is now a plain `<button>` instead of a fluent-button** — the previous default rendered `<Button appearance="stealth">` which still carried button chrome (hover background fill, boxed visual weight). Replaced with a vanilla `<button>` styled `background: transparent; border: none; padding: 0`, with `opacity: 0.7` on hover and a `:focus-visible` accent outline for keyboard nav. Reads as just the icon, not a button containing an icon. Click target still fills the full `menuToggleSize` box for touch reachability.
|
|
15
|
+
- **`Badge` — new `radius` prop overrides the binary rounded-rect / pill shape with an arbitrary border-radius** — Badge had exactly two shape modes (default 4px corner / `circular={true}` pill) mirroring Microsoft's FluentUI Badge `shape` prop. The new `radius?: string` accepts any CSS length (`8px`, `0.5rem`, `var(--my-radius)`) and emits inline `border-radius`, winning over both class rules via CSS specificity. Plays nicely with `circular={true}` — the circular sizing wins, the radius wins, so you get pill-sized badges with non-pill corners if you want.
|
|
20
16
|
|
|
21
17
|
## Features
|
|
22
18
|
|
|
@@ -43,14 +43,18 @@
|
|
|
43
43
|
|
|
44
44
|
onchange?.(ev, target.getAttribute("expanded") === "")
|
|
45
45
|
}
|
|
46
|
+
|
|
47
|
+
const isExpanded = $derived(
|
|
48
|
+
expanded === undefined && ctx.value !== undefined ? !!ctx.value?.includes(id) : expanded
|
|
49
|
+
)
|
|
46
50
|
</script>
|
|
47
51
|
|
|
48
52
|
<!-- todo: investigate flicker during switching of accordions -->
|
|
49
53
|
<fluent-accordion-item
|
|
50
|
-
{id}
|
|
54
|
+
{...(id ? { id } : {})}
|
|
51
55
|
data-custom-id={id}
|
|
52
|
-
heading-level
|
|
53
|
-
|
|
56
|
+
{...(headingLevel !== undefined ? { "heading-level": headingLevel } : {})}
|
|
57
|
+
{...(isExpanded ? { expanded: isExpanded } : {})}
|
|
54
58
|
onchange={handleOnChange}
|
|
55
59
|
>
|
|
56
60
|
<div slot="heading">
|
|
@@ -68,18 +68,18 @@
|
|
|
68
68
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
69
69
|
<fluent-anchor
|
|
70
70
|
bind:this={element}
|
|
71
|
-
{id}
|
|
72
|
-
|
|
73
|
-
{style}
|
|
74
|
-
{download}
|
|
75
|
-
{href}
|
|
76
|
-
{hreflang}
|
|
77
|
-
{ping}
|
|
78
|
-
{referrerpolicy}
|
|
79
|
-
{rel}
|
|
80
|
-
{target}
|
|
81
|
-
{type}
|
|
82
|
-
{appearance}
|
|
71
|
+
{...(id ? { id } : {})}
|
|
72
|
+
{...(className ? { class: className } : {})}
|
|
73
|
+
{...(style ? { style } : {})}
|
|
74
|
+
{...(download ? { download } : {})}
|
|
75
|
+
{...(href ? { href } : {})}
|
|
76
|
+
{...(hreflang ? { hreflang } : {})}
|
|
77
|
+
{...(ping ? { ping } : {})}
|
|
78
|
+
{...(referrerpolicy ? { referrerpolicy } : {})}
|
|
79
|
+
{...(rel ? { rel } : {})}
|
|
80
|
+
{...(target ? { target } : {})}
|
|
81
|
+
{...(type ? { type } : {})}
|
|
82
|
+
{...(appearance ? { appearance } : {})}
|
|
83
83
|
onclick={handleClick}
|
|
84
84
|
>
|
|
85
85
|
{#if iconStart}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
fill?: string
|
|
19
19
|
appearance?: BadgeAppearance
|
|
20
20
|
circular?: boolean
|
|
21
|
+
radius?: string
|
|
21
22
|
children?: SlotType
|
|
22
23
|
onclick?: (ev: MouseEvent) => void
|
|
23
24
|
class?: string
|
|
@@ -29,6 +30,7 @@
|
|
|
29
30
|
fill = undefined,
|
|
30
31
|
appearance = "lightweight",
|
|
31
32
|
circular = false,
|
|
33
|
+
radius = undefined,
|
|
32
34
|
children = undefined,
|
|
33
35
|
onclick = undefined,
|
|
34
36
|
class: className = "",
|
|
@@ -51,7 +53,9 @@
|
|
|
51
53
|
return styles
|
|
52
54
|
})
|
|
53
55
|
|
|
54
|
-
let
|
|
56
|
+
let radiusStyle = $derived(radius ? `border-radius: ${radius};` : "")
|
|
57
|
+
|
|
58
|
+
let computedStyle = $derived([colorStyles, radiusStyle, style].filter(Boolean).join(" "))
|
|
55
59
|
|
|
56
60
|
let classes = $derived.by(() => {
|
|
57
61
|
let cls = ["badge"]
|
|
@@ -56,22 +56,22 @@
|
|
|
56
56
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
57
57
|
<!-- svelte-ignore a11y_autofocus -->
|
|
58
58
|
<fluent-button
|
|
59
|
-
{type}
|
|
60
|
-
{name}
|
|
61
|
-
{value}
|
|
62
|
-
{appearance}
|
|
63
|
-
{autofocus}
|
|
64
|
-
{formaction}
|
|
65
|
-
{form}
|
|
66
|
-
{formenctype}
|
|
67
|
-
{formmethod}
|
|
68
|
-
{formnovalidate}
|
|
69
|
-
{formtarget}
|
|
70
|
-
{disabled}
|
|
71
|
-
{style}
|
|
72
|
-
|
|
73
|
-
aria-label
|
|
74
|
-
{title}
|
|
59
|
+
{...(type ? { type } : {})}
|
|
60
|
+
{...(name ? { name } : {})}
|
|
61
|
+
{...(value != null ? { value } : {})}
|
|
62
|
+
{...(appearance ? { appearance } : {})}
|
|
63
|
+
{...(autofocus ? { autofocus } : {})}
|
|
64
|
+
{...(formaction ? { formaction } : {})}
|
|
65
|
+
{...(form ? { form } : {})}
|
|
66
|
+
{...(formenctype ? { formenctype } : {})}
|
|
67
|
+
{...(formmethod ? { formmethod } : {})}
|
|
68
|
+
{...(formnovalidate ? { formnovalidate } : {})}
|
|
69
|
+
{...(formtarget ? { formtarget } : {})}
|
|
70
|
+
{...(disabled ? { disabled } : {})}
|
|
71
|
+
{...(style ? { style } : {})}
|
|
72
|
+
{...(className ? { class: className } : {})}
|
|
73
|
+
{...(ariaLabel ? { "aria-label": ariaLabel } : {})}
|
|
74
|
+
{...(title ? { title } : {})}
|
|
75
75
|
{onclick}
|
|
76
76
|
>
|
|
77
77
|
{#if start}
|
|
@@ -155,17 +155,17 @@
|
|
|
155
155
|
<!-- svelte-ignore a11y_autofocus -->
|
|
156
156
|
<fluent-checkbox
|
|
157
157
|
bind:this={element}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
{autofocus}
|
|
161
|
-
{readonly}
|
|
162
|
-
{disabled}
|
|
163
|
-
{required}
|
|
158
|
+
{...(checked === true ? { checked: true } : {})}
|
|
159
|
+
{...(checked === null ? { indeterminate: true } : {})}
|
|
160
|
+
{...(autofocus ? { autofocus } : {})}
|
|
161
|
+
{...(readonly ? { readonly } : {})}
|
|
162
|
+
{...(disabled ? { disabled } : {})}
|
|
163
|
+
{...(required ? { required } : {})}
|
|
164
164
|
id={effectiveId}
|
|
165
|
-
{name}
|
|
166
|
-
aria-label
|
|
167
|
-
|
|
168
|
-
style
|
|
165
|
+
{...(name ? { name } : {})}
|
|
166
|
+
{...(ariaLabel || label ? { "aria-label": ariaLabel || label } : {})}
|
|
167
|
+
{...(className ? { class: className } : {})}
|
|
168
|
+
{...(style ? { style } : {})}
|
|
169
169
|
onclick={handleOnClick}
|
|
170
170
|
></fluent-checkbox>
|
|
171
171
|
|
|
@@ -254,19 +254,19 @@
|
|
|
254
254
|
<fluent-combobox
|
|
255
255
|
bind:this={element}
|
|
256
256
|
class={className}
|
|
257
|
-
|
|
258
|
-
{id}
|
|
259
|
-
autocomplete
|
|
260
|
-
open
|
|
261
|
-
current-value
|
|
262
|
-
placeholder
|
|
263
|
-
position
|
|
264
|
-
disabled
|
|
265
|
-
appearance
|
|
266
|
-
required
|
|
267
|
-
autofocus
|
|
268
|
-
name
|
|
269
|
-
aria-label
|
|
257
|
+
{...(computedStyle() ? { style: computedStyle() } : {})}
|
|
258
|
+
{...(id ? { id } : {})}
|
|
259
|
+
{...(autocomplete ? { autocomplete } : {})}
|
|
260
|
+
{...(open ? { open } : {})}
|
|
261
|
+
{...(currentValue ? { "current-value": currentValue } : {})}
|
|
262
|
+
{...(placeholder ? { placeholder } : {})}
|
|
263
|
+
{...(position ? { position } : {})}
|
|
264
|
+
{...(disabled ? { disabled } : {})}
|
|
265
|
+
{...(appearance ? { appearance } : {})}
|
|
266
|
+
{...(required ? { required } : {})}
|
|
267
|
+
{...(autofocus ? { autofocus } : {})}
|
|
268
|
+
{...(name ? { name } : {})}
|
|
269
|
+
{...(ariaLabel || label ? { "aria-label": ariaLabel ?? label } : {})}
|
|
270
270
|
{...titleProps}
|
|
271
271
|
onchange={handleChange}
|
|
272
272
|
>
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
|
|
40
40
|
<fluent-data-grid
|
|
41
41
|
class={className}
|
|
42
|
-
{style}
|
|
43
|
-
{id}
|
|
44
|
-
aria-rowcount
|
|
45
|
-
generate-header
|
|
42
|
+
{...(style ? { style } : {})}
|
|
43
|
+
{...(id ? { id } : {})}
|
|
44
|
+
{...(ariaRowCount !== undefined ? { "aria-rowcount": ariaRowCount } : {})}
|
|
45
|
+
{...(generateHeader ? { "generate-header": generateHeader } : {})}
|
|
46
46
|
role={role}
|
|
47
47
|
onclosecolumnoptions={handleCloseColumnOptions}
|
|
48
48
|
onclosecolumnresize={handleCloseColumnResize}
|
|
@@ -52,14 +52,14 @@
|
|
|
52
52
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex a11y_click_events_have_key_events -->
|
|
53
53
|
<fluent-data-grid-cell
|
|
54
54
|
class={className}
|
|
55
|
-
{style}
|
|
56
|
-
grid-column
|
|
57
|
-
cell-type
|
|
58
|
-
col-index
|
|
59
|
-
{role}
|
|
60
|
-
|
|
61
|
-
{title}
|
|
62
|
-
aria-label
|
|
55
|
+
{...(style ? { style } : {})}
|
|
56
|
+
{...(gridColumn !== undefined ? { "grid-column": gridColumn } : {})}
|
|
57
|
+
{...(cellType ? { "cell-type": cellType } : {})}
|
|
58
|
+
{...(colIndex !== undefined ? { "col-index": colIndex } : {})}
|
|
59
|
+
{...(role ? { role } : {})}
|
|
60
|
+
{...(tabIndex !== undefined ? { tabindex: tabIndex } : {})}
|
|
61
|
+
{...(title ? { title } : {})}
|
|
62
|
+
{...(ariaLabel ? { "aria-label": ariaLabel } : {})}
|
|
63
63
|
onkeydown={handleKeyDown}
|
|
64
64
|
onclick={handleClick}
|
|
65
65
|
onfocus={handleFocus}
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
<!-- svelte-ignore a11y_interactive_supports_focus -->
|
|
49
49
|
<fluent-data-grid-row
|
|
50
50
|
class={className}
|
|
51
|
-
{style}
|
|
52
|
-
data-row-index
|
|
53
|
-
row-type
|
|
51
|
+
{...(style ? { style } : {})}
|
|
52
|
+
{...(rowIndex !== undefined ? { "data-row-index": rowIndex } : {})}
|
|
53
|
+
{...(rowType ? { "row-type": rowType } : {})}
|
|
54
54
|
role="row"
|
|
55
55
|
onkeydown={handleKeyDown}
|
|
56
56
|
onclick={handleClick}
|
|
@@ -229,12 +229,12 @@
|
|
|
229
229
|
<fluent-dialog
|
|
230
230
|
use:portal
|
|
231
231
|
bind:this={element}
|
|
232
|
-
{modal}
|
|
232
|
+
{...(modal ? { modal } : {})}
|
|
233
233
|
hidden={!visible}
|
|
234
|
-
{trapFocus}
|
|
235
|
-
{ariaDescribedby}
|
|
236
|
-
{ariaLabelledby}
|
|
237
|
-
{ariaLabel}
|
|
234
|
+
{...(trapFocus ? { trapFocus } : {})}
|
|
235
|
+
{...(ariaDescribedby ? { ariaDescribedby } : {})}
|
|
236
|
+
{...(ariaLabelledby ? { ariaLabelledby } : {})}
|
|
237
|
+
{...(ariaLabel ? { ariaLabel } : {})}
|
|
238
238
|
class="dialog-positioned"
|
|
239
239
|
style={dialogStyle + (style ? ` ${style}` : '')}
|
|
240
240
|
>
|
|
@@ -97,9 +97,9 @@
|
|
|
97
97
|
<fluent-listbox
|
|
98
98
|
bind:this={element}
|
|
99
99
|
selected-options={selectedOptionsAttr}
|
|
100
|
-
{disabled}
|
|
101
|
-
{autofocus}
|
|
102
|
-
{name}
|
|
100
|
+
{...(disabled ? { disabled } : {})}
|
|
101
|
+
{...(autofocus ? { autofocus } : {})}
|
|
102
|
+
{...(name ? { name } : {})}
|
|
103
103
|
{...(size !== undefined ? { size } : {})}
|
|
104
104
|
aria-label={ariaLabel || null}
|
|
105
105
|
class={className || null}
|
|
@@ -207,10 +207,10 @@
|
|
|
207
207
|
<span bind:this={anchorEl} class="fluent-menu-button-anchor">
|
|
208
208
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
209
209
|
<fluent-button
|
|
210
|
-
{appearance}
|
|
211
|
-
{disabled}
|
|
210
|
+
{...(appearance ? { appearance } : {})}
|
|
211
|
+
{...(disabled ? { disabled } : {})}
|
|
212
212
|
class={className}
|
|
213
|
-
{style}
|
|
213
|
+
{...(style ? { style } : {})}
|
|
214
214
|
aria-haspopup="menu"
|
|
215
215
|
aria-expanded={open}
|
|
216
216
|
onclick={toggleMenu}
|
|
@@ -187,27 +187,27 @@
|
|
|
187
187
|
<!-- svelte-ignore a11y_autofocus -->
|
|
188
188
|
<fluent-number-field
|
|
189
189
|
bind:this={element}
|
|
190
|
-
{id}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
placeholder
|
|
194
|
-
appearance
|
|
195
|
-
disabled
|
|
196
|
-
readonly
|
|
197
|
-
required
|
|
198
|
-
autofocus
|
|
199
|
-
autocomplete
|
|
190
|
+
{...(id ? { id } : {})}
|
|
191
|
+
{...(className ? { class: className } : {})}
|
|
192
|
+
{...(computedStyle ? { style: computedStyle } : {})}
|
|
193
|
+
{...(placeholder ? { placeholder } : {})}
|
|
194
|
+
{...(appearance ? { appearance } : {})}
|
|
195
|
+
{...(disabled ? { disabled } : {})}
|
|
196
|
+
{...(readonly ? { readonly } : {})}
|
|
197
|
+
{...(required ? { required } : {})}
|
|
198
|
+
{...(autofocus ? { autofocus } : {})}
|
|
199
|
+
{...(autocomplete ? { autocomplete } : {})}
|
|
200
200
|
{...(step !== undefined ? { step } : {})}
|
|
201
201
|
{...(min !== undefined ? { min } : {})}
|
|
202
202
|
{...(max !== undefined ? { max } : {})}
|
|
203
203
|
{...(minlength !== undefined ? { minlength } : {})}
|
|
204
204
|
{...(maxlength !== undefined ? { maxlength } : {})}
|
|
205
205
|
{...(size !== undefined ? { size } : {})}
|
|
206
|
-
list
|
|
207
|
-
hide-step
|
|
208
|
-
name
|
|
209
|
-
aria-label
|
|
210
|
-
value
|
|
206
|
+
{...(list ? { list } : {})}
|
|
207
|
+
{...(hideStep ? { "hide-step": hideStep } : {})}
|
|
208
|
+
{...(name ? { name } : {})}
|
|
209
|
+
{...(ariaLabel || label ? { "aria-label": ariaLabel ?? label } : {})}
|
|
210
|
+
{...(value != null ? { value } : {})}
|
|
211
211
|
{...titleProps}
|
|
212
212
|
oninput={handleOnInput}
|
|
213
213
|
onchange={handleOnChange}
|
|
@@ -55,13 +55,13 @@
|
|
|
55
55
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
56
56
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
57
57
|
<fluent-option
|
|
58
|
-
{value}
|
|
59
|
-
|
|
58
|
+
{...(value != null ? { value } : {})}
|
|
59
|
+
{...((selected !== undefined ? selected : selectedValue?.value?.includes(value)) ? { selected: true } : {})}
|
|
60
60
|
class={className}
|
|
61
|
-
{style}
|
|
62
|
-
data-option-label
|
|
63
|
-
data-option-context
|
|
64
|
-
{disabled}
|
|
61
|
+
{...(style ? { style } : {})}
|
|
62
|
+
{...(label ? { "data-option-label": label } : {})}
|
|
63
|
+
{...(data ? { "data-option-context": JSON.stringify(data) } : {})}
|
|
64
|
+
{...(disabled ? { disabled } : {})}
|
|
65
65
|
onclick={handleOnClick}
|
|
66
66
|
>
|
|
67
67
|
{#if icon}
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
56
56
|
<fluent-button
|
|
57
57
|
onclick={() => onFirst?.()}
|
|
58
|
-
|
|
58
|
+
{...(!canGoBack || disabled ? { disabled: true } : {})}
|
|
59
59
|
title="Go to first page"
|
|
60
60
|
aria-label="Go to first page"
|
|
61
61
|
>
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
67
67
|
<fluent-button
|
|
68
68
|
onclick={() => onPrevious?.()}
|
|
69
|
-
|
|
69
|
+
{...(!canGoBack || disabled ? { disabled: true } : {})}
|
|
70
70
|
title="Go to previous page"
|
|
71
71
|
aria-label="Go to previous page"
|
|
72
72
|
>
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
86
86
|
<fluent-button
|
|
87
87
|
onclick={() => onNext?.()}
|
|
88
|
-
|
|
88
|
+
{...(!canGoForwards || disabled ? { disabled: true } : {})}
|
|
89
89
|
title="Go to next page"
|
|
90
90
|
aria-label="Go to next page"
|
|
91
91
|
>
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
97
97
|
<fluent-button
|
|
98
98
|
onclick={() => onLast?.()}
|
|
99
|
-
|
|
99
|
+
{...(!canGoForwards || disabled ? { disabled: true } : {})}
|
|
100
100
|
title="Go to last page"
|
|
101
101
|
aria-label="Go to last page"
|
|
102
102
|
>
|
|
@@ -2194,7 +2194,7 @@
|
|
|
2194
2194
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
2195
2195
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
2196
2196
|
<fluent-menu-item
|
|
2197
|
-
|
|
2197
|
+
{...(isDisabled ? { disabled: true } : {})}
|
|
2198
2198
|
class:danger={menuItem.danger}
|
|
2199
2199
|
onclick={() => handleContextMenuItemClick(menuItem)}
|
|
2200
2200
|
>
|
|
@@ -764,7 +764,7 @@ declare function $$render<T>(): {
|
|
|
764
764
|
row: T;
|
|
765
765
|
rowIndex: number;
|
|
766
766
|
}) => void | Promise<void>) | undefined;
|
|
767
|
-
}, "
|
|
767
|
+
}, "group" | "title" | "icon" | "id" | "row">> & Omit<{
|
|
768
768
|
id: string;
|
|
769
769
|
icon: string;
|
|
770
770
|
title: string;
|
|
@@ -778,7 +778,7 @@ declare function $$render<T>(): {
|
|
|
778
778
|
row: T;
|
|
779
779
|
rowIndex: number;
|
|
780
780
|
}) => void | Promise<void>) | undefined;
|
|
781
|
-
}, "
|
|
781
|
+
}, "group" | "title" | "icon" | "id" | "row">;
|
|
782
782
|
rowIndex: number;
|
|
783
783
|
row: T;
|
|
784
784
|
}) => void) | undefined;
|
|
@@ -91,18 +91,18 @@
|
|
|
91
91
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
92
92
|
<fluent-slider
|
|
93
93
|
bind:this={element}
|
|
94
|
-
{id}
|
|
95
|
-
{min}
|
|
96
|
-
{max}
|
|
97
|
-
{step}
|
|
98
|
-
{orientation}
|
|
99
|
-
{disabled}
|
|
100
|
-
{readonly}
|
|
101
|
-
{required}
|
|
102
|
-
{name}
|
|
103
|
-
aria-label
|
|
104
|
-
|
|
105
|
-
style
|
|
94
|
+
{...(id ? { id } : {})}
|
|
95
|
+
{...(min !== undefined ? { min } : {})}
|
|
96
|
+
{...(max !== undefined ? { max } : {})}
|
|
97
|
+
{...(step !== undefined ? { step } : {})}
|
|
98
|
+
{...(orientation ? { orientation } : {})}
|
|
99
|
+
{...(disabled ? { disabled } : {})}
|
|
100
|
+
{...(readonly ? { readonly } : {})}
|
|
101
|
+
{...(required ? { required } : {})}
|
|
102
|
+
{...(name ? { name } : {})}
|
|
103
|
+
{...(ariaLabel || label ? { "aria-label": ariaLabel || label } : {})}
|
|
104
|
+
{...(className ? { class: className } : {})}
|
|
105
|
+
{...(style ? { style } : {})}
|
|
106
106
|
onchange={handleChange}
|
|
107
107
|
oninput={handleInput}
|
|
108
108
|
>
|
|
@@ -99,15 +99,15 @@
|
|
|
99
99
|
mere presence as `true`. -->
|
|
100
100
|
<fluent-switch
|
|
101
101
|
class={className}
|
|
102
|
-
{style}
|
|
103
|
-
{readonly}
|
|
102
|
+
{...(style ? { style } : {})}
|
|
103
|
+
{...(readonly ? { readonly } : {})}
|
|
104
104
|
id={effectiveId}
|
|
105
|
-
{disabled}
|
|
106
|
-
{autofocus}
|
|
107
|
-
{name}
|
|
108
|
-
aria-label
|
|
109
|
-
{required}
|
|
110
|
-
checked
|
|
105
|
+
{...(disabled ? { disabled } : {})}
|
|
106
|
+
{...(autofocus ? { autofocus } : {})}
|
|
107
|
+
{...(name ? { name } : {})}
|
|
108
|
+
{...(ariaLabel || label ? { "aria-label": ariaLabel || label } : {})}
|
|
109
|
+
{...(required ? { required } : {})}
|
|
110
|
+
{...(checked ? { checked } : {})}
|
|
111
111
|
aria-checked={checked ? "true" : "false"}
|
|
112
112
|
onchange={handleChange}
|
|
113
113
|
role="switch"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
}: Props = $props()
|
|
24
24
|
</script>
|
|
25
25
|
|
|
26
|
-
<fluent-tab-panel class={className} {style} {id} hidden={!active} >
|
|
26
|
+
<fluent-tab-panel class={className} {...(style ? { style } : {})} {...(id ? { id } : {})} hidden={!active} >
|
|
27
27
|
{#if children}
|
|
28
28
|
{@render children?.()}
|
|
29
29
|
{/if}
|
|
@@ -179,20 +179,20 @@
|
|
|
179
179
|
<!-- svelte-ignore a11y_autofocus -->
|
|
180
180
|
<fluent-text-field
|
|
181
181
|
bind:this={element}
|
|
182
|
-
{id}
|
|
183
|
-
{value}
|
|
184
|
-
{placeholder}
|
|
185
|
-
{appearance}
|
|
186
|
-
{disabled}
|
|
187
|
-
{readonly}
|
|
188
|
-
{required}
|
|
189
|
-
{type}
|
|
190
|
-
{name}
|
|
191
|
-
{autofocus}
|
|
192
|
-
{autocomplete}
|
|
193
|
-
{style}
|
|
194
|
-
{title}
|
|
195
|
-
|
|
182
|
+
{...(id ? { id } : {})}
|
|
183
|
+
{...(value != null ? { value } : {})}
|
|
184
|
+
{...(placeholder ? { placeholder } : {})}
|
|
185
|
+
{...(appearance ? { appearance } : {})}
|
|
186
|
+
{...(disabled ? { disabled } : {})}
|
|
187
|
+
{...(readonly ? { readonly } : {})}
|
|
188
|
+
{...(required ? { required } : {})}
|
|
189
|
+
{...(type ? { type } : {})}
|
|
190
|
+
{...(name ? { name } : {})}
|
|
191
|
+
{...(autofocus ? { autofocus } : {})}
|
|
192
|
+
{...(autocomplete ? { autocomplete } : {})}
|
|
193
|
+
{...(style ? { style } : {})}
|
|
194
|
+
{...(title ? { title } : {})}
|
|
195
|
+
{...(label || labelTemplate ? { "aria-label": label } : {})}
|
|
196
196
|
oninput={handleOnInput}
|
|
197
197
|
onchange={handleOnChange}
|
|
198
198
|
onkeydown={handleOnKeyDown}
|
|
@@ -164,26 +164,26 @@
|
|
|
164
164
|
<fluent-text-area
|
|
165
165
|
bind:this={element}
|
|
166
166
|
class={className}
|
|
167
|
-
{style}
|
|
168
|
-
{readonly}
|
|
169
|
-
{resize}
|
|
170
|
-
{autofocus}
|
|
171
|
-
autocomplete
|
|
172
|
-
{form}
|
|
173
|
-
{list}
|
|
167
|
+
{...(style ? { style } : {})}
|
|
168
|
+
{...(readonly ? { readonly } : {})}
|
|
169
|
+
{...(resize ? { resize } : {})}
|
|
170
|
+
{...(autofocus ? { autofocus } : {})}
|
|
171
|
+
{...(autocomplete ? { autocomplete } : {})}
|
|
172
|
+
{...(form ? { form } : {})}
|
|
173
|
+
{...(list ? { list } : {})}
|
|
174
174
|
{...(maxlength !== undefined ? { maxlength } : {})}
|
|
175
175
|
{...(minlength !== undefined ? { minlength } : {})}
|
|
176
|
-
{placeholder}
|
|
176
|
+
{...(placeholder ? { placeholder } : {})}
|
|
177
177
|
{...(cols !== undefined ? { cols } : {})}
|
|
178
178
|
{...(rows !== undefined ? { rows } : {})}
|
|
179
|
-
{spellcheck}
|
|
180
|
-
{id}
|
|
181
|
-
{name}
|
|
182
|
-
{disabled}
|
|
183
|
-
{required}
|
|
184
|
-
{appearance}
|
|
185
|
-
{value}
|
|
186
|
-
aria-label
|
|
179
|
+
{...(spellcheck != null ? { spellcheck } : {})}
|
|
180
|
+
{...(id ? { id } : {})}
|
|
181
|
+
{...(name ? { name } : {})}
|
|
182
|
+
{...(disabled ? { disabled } : {})}
|
|
183
|
+
{...(required ? { required } : {})}
|
|
184
|
+
{...(appearance ? { appearance } : {})}
|
|
185
|
+
{...(value != null ? { value } : {})}
|
|
186
|
+
{...(ariaLabel ? { "aria-label": ariaLabel } : {})}
|
|
187
187
|
oninput={handleInput}
|
|
188
188
|
onchange={handleChange}
|
|
189
189
|
>
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
</script>
|
|
23
23
|
|
|
24
24
|
<fluent-toolbar
|
|
25
|
-
id
|
|
25
|
+
{...(id ? { id } : {})}
|
|
26
26
|
class={className}
|
|
27
|
-
style
|
|
28
|
-
orientation
|
|
27
|
+
{...(style ? { style } : {})}
|
|
28
|
+
{...(orientation ? { orientation } : {})}
|
|
29
29
|
>
|
|
30
30
|
{#if children}
|
|
31
31
|
{@render children?.()}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type {SlotType} from "../../types/index.js"
|
|
3
|
-
import Button from "../Button.svelte"
|
|
4
3
|
import Panel from "./Panel.svelte"
|
|
5
4
|
import NavMenu from "../nav/NavMenu.svelte"
|
|
6
5
|
import NavGroup from "../nav/NavGroup.svelte"
|
|
@@ -34,6 +33,8 @@
|
|
|
34
33
|
drawerPinned?: boolean
|
|
35
34
|
drawerWidth?: string
|
|
36
35
|
height?: number
|
|
36
|
+
menuToggleSize?: number
|
|
37
|
+
menuToggleTemplate?: SlotType
|
|
37
38
|
class?: string
|
|
38
39
|
style?: string
|
|
39
40
|
}
|
|
@@ -50,6 +51,8 @@
|
|
|
50
51
|
drawerPinned = false,
|
|
51
52
|
drawerWidth = "280px",
|
|
52
53
|
height = 60,
|
|
54
|
+
menuToggleSize = 42,
|
|
55
|
+
menuToggleTemplate = undefined,
|
|
53
56
|
class: className = "",
|
|
54
57
|
style = ""
|
|
55
58
|
}: Props = $props()
|
|
@@ -92,25 +95,29 @@
|
|
|
92
95
|
class:topnav--force-collapse={collapse === "always"}
|
|
93
96
|
class:topnav--force-expand={collapse === "never"}
|
|
94
97
|
class:topnav--drawer-pinned={drawerPinned}
|
|
95
|
-
style="height: {height}px; {style}"
|
|
98
|
+
style="height: {height}px; --topnav-toggle-size: {menuToggleSize}px; {style}"
|
|
96
99
|
>
|
|
97
100
|
<div class="topnav-container">
|
|
98
101
|
{#if hasDrawerContent}
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
102
|
+
<div class="topnav-menu-toggle">
|
|
103
|
+
{#if menuToggleTemplate}
|
|
104
|
+
{@render menuToggleTemplate({open: mobileMenuOpen, toggle: toggleMobileMenu})}
|
|
105
|
+
{:else}
|
|
106
|
+
<button
|
|
107
|
+
type="button"
|
|
108
|
+
class="mobile-menu-toggle"
|
|
109
|
+
onclick={toggleMobileMenu}
|
|
110
|
+
aria-label={mobileMenuOpen ? "Close menu" : "Open menu"}
|
|
111
|
+
aria-expanded={mobileMenuOpen}
|
|
112
|
+
>
|
|
113
|
+
{#if mobileMenuOpen}
|
|
114
|
+
<DismissIcon size={Math.round(menuToggleSize * 0.48)} />
|
|
115
|
+
{:else}
|
|
116
|
+
<span class="hamburger-glyph">☰</span>
|
|
117
|
+
{/if}
|
|
118
|
+
</button>
|
|
119
|
+
{/if}
|
|
120
|
+
</div>
|
|
114
121
|
{/if}
|
|
115
122
|
|
|
116
123
|
{#if brandTemplate}
|
|
@@ -238,31 +245,46 @@
|
|
|
238
245
|
flex-shrink: 0;
|
|
239
246
|
}
|
|
240
247
|
|
|
241
|
-
/*
|
|
242
|
-
|
|
248
|
+
/* Wrapper slot — owns visibility + position so a custom menuToggleTemplate
|
|
249
|
+
gets the same collapse behavior as the default button without consumers
|
|
250
|
+
needing to know about the internal rules. */
|
|
251
|
+
.topnav-menu-toggle {
|
|
243
252
|
display: none;
|
|
244
253
|
order: -1;
|
|
245
254
|
flex-shrink: 0;
|
|
246
|
-
|
|
247
|
-
min-width: 42px;
|
|
248
|
-
height: 42px;
|
|
255
|
+
align-items: center;
|
|
249
256
|
}
|
|
250
257
|
|
|
251
|
-
/*
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
+
/* Default toggle — plain icon target, no button chrome. Sized via
|
|
259
|
+
--topnav-toggle-size (set inline from the menuToggleSize prop).
|
|
260
|
+
Custom templates render at their natural size. */
|
|
261
|
+
.mobile-menu-toggle {
|
|
262
|
+
width: var(--topnav-toggle-size, 42px);
|
|
263
|
+
height: var(--topnav-toggle-size, 42px);
|
|
264
|
+
display: inline-flex;
|
|
265
|
+
align-items: center;
|
|
266
|
+
justify-content: center;
|
|
258
267
|
padding: 0;
|
|
268
|
+
background: transparent;
|
|
269
|
+
border: none;
|
|
270
|
+
color: inherit;
|
|
271
|
+
cursor: pointer;
|
|
272
|
+
border-radius: var(--fluent-border-radius-md, 4px);
|
|
273
|
+
transition: opacity 0.15s, background-color 0.15s;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.mobile-menu-toggle:hover {
|
|
277
|
+
opacity: 0.7;
|
|
259
278
|
}
|
|
260
279
|
|
|
261
|
-
.
|
|
262
|
-
|
|
280
|
+
.mobile-menu-toggle:focus-visible {
|
|
281
|
+
outline: 2px solid var(--accent-fill-rest, currentColor);
|
|
282
|
+
outline-offset: 2px;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.hamburger-glyph {
|
|
286
|
+
font-size: calc(var(--topnav-toggle-size, 42px) * 0.55);
|
|
263
287
|
line-height: 1;
|
|
264
|
-
display: flex;
|
|
265
|
-
align-items: center;
|
|
266
288
|
}
|
|
267
289
|
|
|
268
290
|
/* Trailing flex group: items + divider + actions. `margin-left: auto`
|
|
@@ -343,7 +365,7 @@
|
|
|
343
365
|
}
|
|
344
366
|
|
|
345
367
|
@container topnav (max-width: 960px) {
|
|
346
|
-
|
|
368
|
+
.topnav-menu-toggle {
|
|
347
369
|
display: flex;
|
|
348
370
|
}
|
|
349
371
|
|
|
@@ -359,14 +381,14 @@
|
|
|
359
381
|
}
|
|
360
382
|
}
|
|
361
383
|
|
|
362
|
-
/* collapse="always" — force
|
|
363
|
-
|
|
384
|
+
/* collapse="always" — force toggle visible + items hidden regardless of width */
|
|
385
|
+
.topnav--force-collapse .topnav-menu-toggle {
|
|
364
386
|
display: flex;
|
|
365
387
|
}
|
|
366
388
|
|
|
367
|
-
/* When drawer is pinned the
|
|
389
|
+
/* When drawer is pinned the toggle acts as a show/hide control for the
|
|
368
390
|
pinned rail itself, so it must stay visible at every width. */
|
|
369
|
-
|
|
391
|
+
.topnav--drawer-pinned .topnav-menu-toggle {
|
|
370
392
|
display: flex;
|
|
371
393
|
}
|
|
372
394
|
|
|
@@ -375,8 +397,8 @@
|
|
|
375
397
|
display: none;
|
|
376
398
|
}
|
|
377
399
|
|
|
378
|
-
/* collapse="never" — force items/divider visible +
|
|
379
|
-
|
|
400
|
+
/* collapse="never" — force items/divider visible + toggle hidden regardless of width */
|
|
401
|
+
.topnav--force-expand .topnav-menu-toggle {
|
|
380
402
|
display: none;
|
|
381
403
|
}
|
|
382
404
|
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "1.3.
|
|
1
|
+
export declare const VERSION = "1.3.3";
|
package/dist/version.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// Auto-generated by scripts/pre-package.js — do NOT edit by hand.
|
|
2
2
|
// In dev this file holds whatever value was committed last; on each `npm run package`
|
|
3
3
|
// the pre-package script overwrites it with the current package.json version.
|
|
4
|
-
export const VERSION = "1.3.
|
|
4
|
+
export const VERSION = "1.3.3";
|