@dorsk/tsumikit 0.63.1 → 0.64.1
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 +27 -9
- package/dist/components/atoms/Button.svelte +8 -2
- package/dist/components/atoms/Checkbox.svelte +22 -4
- package/dist/components/atoms/Checkbox.svelte.d.ts +5 -1
- package/dist/components/atoms/Icon.svelte +2 -0
- package/dist/components/atoms/Icon.svelte.d.ts +2 -0
- package/dist/components/layouts/ResizablePanel.svelte +26 -3
- package/dist/components/layouts/ResizablePanel.svelte.d.ts +8 -0
- package/dist/components/molecules/Accordion.svelte +29 -5
- package/dist/components/molecules/Accordion.svelte.d.ts +14 -3
- package/dist/components/molecules/Disclosure.svelte +16 -4
- package/dist/components/molecules/Disclosure.svelte.d.ts +5 -0
- package/dist/components/molecules/FileButton.svelte +3 -1
- package/dist/components/molecules/IconButton.svelte +8 -4
- package/dist/components/molecules/IconButton.svelte.d.ts +3 -0
- package/dist/components/molecules/Menu.svelte +18 -2
- package/dist/components/molecules/Menu.svelte.d.ts +7 -2
- package/dist/components/molecules/Popover.svelte +6 -2
- package/dist/components/molecules/SplitButton.svelte +10 -1
- package/dist/components/molecules/SplitButton.svelte.d.ts +8 -1
- package/dist/index.d.ts +2 -2
- package/dist/styles/reset.css +11 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -248,7 +248,8 @@ any test, and change without a major.
|
|
|
248
248
|
`clearable` + `onclear`, `shape="pill"`, `width` fixed + `flex: none`,
|
|
249
249
|
`onenter(value)`; the bare `<input>` DOM is unchanged unless `icon`/`clearable`
|
|
250
250
|
is used), Textarea, Select (`options` array with per-option `icon`/`emoji`/`hint`/`disabled`;
|
|
251
|
-
the trigger overlays the selected option's glyph + muted hint on the native control), Switch, Checkbox
|
|
251
|
+
the trigger overlays the selected option's glyph + muted hint on the native control), Switch, Checkbox (`size`
|
|
252
|
+
sm/md/lg as on `Switch`, or `--cb-box` for the box alone),
|
|
252
253
|
Slider (`ticks` draws a dot per step for a segmented slider), Progress, Gauge (vertical consumption cell, `variant` continuous/segments,
|
|
253
254
|
threshold tones via `warnAt`/`dangerAt`, `corner` snippet), Artwork (lazy cover image with seeded gradient + initials
|
|
254
255
|
fallback, `aspect`, `status` overlay), Avatar (grapheme-safe initial or `glyph`, hue hashed from
|
|
@@ -266,13 +267,16 @@ horizontal/vertical hairline, `tone`, `spacing`, optional centred label,
|
|
|
266
267
|
always/hover/none, `align`), Icon (open registry — pass a `children` snippet for
|
|
267
268
|
any custom SVG).
|
|
268
269
|
|
|
269
|
-
**Molecules:** Field (`grow`), IconButton
|
|
270
|
+
**Molecules:** Field (`grow`), IconButton (`filled` forwards to `Icon`, for a
|
|
271
|
+
filled pin/star toggle), SelectButton, Toggle, OptionButton (`value` +
|
|
270
272
|
`description` secondary text wired via `aria-describedby`, `onfocuschange(value)` on
|
|
271
273
|
focus/hover to drive a preview pane), Modal,
|
|
272
274
|
Popover, Menu (items take a free-form trailing `tag` + `tagTone`, or a `tag` snippet,
|
|
273
275
|
and an `attrs` object for `data-*`/test ids on the row; a checkable `pressed` item keeps
|
|
274
276
|
its icon leading and shows its check trailing, or uses the leading check slot when it has
|
|
275
|
-
no icon; selecting closes the menu unless `closeOnSelect={false}` or the item sets `keepOpen
|
|
277
|
+
no icon; selecting closes the menu unless `closeOnSelect={false}` or the item sets `keepOpen`;
|
|
278
|
+
rest props land on the trigger, `count`/`countMax` paint its corner badge and `panelStyle`
|
|
279
|
+
sizes the panel),
|
|
276
280
|
Tabs (omit `panel` for a strip-only tablist of document tabs: `closable` + `onclose(id)`
|
|
277
281
|
close through the ✕, Delete and middle-click, per-tab `leading` snippet, `title`,
|
|
278
282
|
trailing `actions` snippet; `--tab-max-width` truncates long labels),
|
|
@@ -281,9 +285,10 @@ RadioGroup (per-option `description` in every variant, announced via
|
|
|
281
285
|
`variant="rows"`: bordered rows, per-option `note`,
|
|
282
286
|
`action(option)` trailing control that never toggles, `below(option)` inline panel),
|
|
283
287
|
Tooltip, Disclosure (single collapsible: `header` snippet, bindable `open` or `open` + `onchange` for
|
|
284
|
-
controlled mode, `chevron` start/end/false, native button with
|
|
285
|
-
`region` panel), Accordion (a stack of Disclosures; items take a
|
|
286
|
-
|
|
288
|
+
controlled mode, `chevron` start/end/false, `size="compact"` for strip rows, native button with
|
|
289
|
+
`aria-expanded`/`aria-controls` over a `region` panel), Accordion (a stack of Disclosures; items take a
|
|
290
|
+
`title` string or a `summary` snippet that receives the `item` it heads, per-item `open`/`onchange`,
|
|
291
|
+
`multiple=false` keeps one open, `variant="plain"` drops the outer border, `size` forwards to every item), CopyButton, FileButton, InputGroup (a field with inset
|
|
287
292
|
leading/trailing controls fused into one bordered unit, see below),
|
|
288
293
|
Dropzone, CodeBlock, Callout, EmptyState, ConfirmModal, Pagination, Toaster,
|
|
289
294
|
ThemePicker (popover grid of 2×2 palette swatches: bg · surface · text · accent per theme),
|
|
@@ -383,6 +388,11 @@ fixed non-modal drawer (`role="dialog"`) on the viewport edge: `bind:open`,
|
|
|
383
388
|
the dim backdrop, `fullWidthBelow="960px"` makes the drawer span the viewport (no
|
|
384
389
|
handle, no scrim) on small screens, and `clampToViewport` (default true) keeps a
|
|
385
390
|
stored width inside a shrunken window. `children` is optional in overlay mode.
|
|
391
|
+
`onresizestart` / `onresize(width)` / `onresizeend(width)` report the drag: start
|
|
392
|
+
fires on pointer-down, `onresize` once per animation frame (and per keyboard
|
|
393
|
+
step), `onresizeend` with the settled width on release — enough to suspend
|
|
394
|
+
expensive panel work only while the width is in flux. A keyboard step commits
|
|
395
|
+
without a start.
|
|
386
396
|
|
|
387
397
|
```svelte
|
|
388
398
|
<ResizablePanel mode="overlay" side="right" label="Conversation" bind:open
|
|
@@ -702,7 +712,11 @@ panel.
|
|
|
702
712
|
one outer radius, square inner corners, a 1px divider, two tab stops. The
|
|
703
713
|
primary takes `onclick`, `type` (submit inside a form) and `loading`; the caret
|
|
704
714
|
takes `label` (its accessible name), `items`, `placement` and the `Menu`
|
|
705
|
-
panel props (`tag`, `panelClass`, `gap`, `open`, `onopen`,
|
|
715
|
+
panel props (`tag`, `panelClass`, `panelStyle`, `gap`, `open`, `onopen`,
|
|
716
|
+
`onclose`). `primaryProps` sets attributes on the primary segment itself
|
|
717
|
+
(`title`, `aria-describedby`, `data-*` — a disabled-with-reason tooltip), while
|
|
718
|
+
rest props stay on the root box; the props SplitButton owns are applied after it,
|
|
719
|
+
so the fused chrome cannot be clobbered.
|
|
706
720
|
`variant` (default | primary | danger), `size` and `control` apply to both
|
|
707
721
|
segments and match `Button` heights; `disabled` turns off the whole control,
|
|
708
722
|
`menuDisabled` only the caret. `caret="half"` narrows the caret to half the
|
|
@@ -791,7 +805,7 @@ Button and Popover share the same semantic tones. For a confirmed positive
|
|
|
791
805
|
action, `tone="success"` gives neutral controls a success tint; combine it with
|
|
792
806
|
`variant="primary"` for a filled success action without consumer CSS.
|
|
793
807
|
|
|
794
|
-
`count` on `Button`, `IconButton` and `
|
|
808
|
+
`count` on `Button`, `IconButton`, `Popover` and `Menu` (their trigger) paints a corner
|
|
795
809
|
count pill (unread, selected, queued) on any size, variant or `box`. It hides at
|
|
796
810
|
`0`/`undefined`, displays `99+` past `countMax`, and the exact number joins the
|
|
797
811
|
accessible name (`"Inbox, 120"`) whether that comes from `aria-label`, `label`
|
|
@@ -823,7 +837,11 @@ glyphs (`size` stays the SVG px, emoji ×1.35).
|
|
|
823
837
|
On `(pointer: coarse)` every icon-only/square control (and `Popover`'s default
|
|
824
838
|
trigger) carries an invisible `::after` slab that extends its hit area to
|
|
825
839
|
`--touch-target` (44px, WCAG 2.5.8) without moving layout; fine pointers are
|
|
826
|
-
untouched.
|
|
840
|
+
untouched. The slab grows on both block sides but only towards the inline
|
|
841
|
+
*start*: inline-end overflow would count towards the scrollable overflow of
|
|
842
|
+
every scroll ancestor, so a button near the right edge of an `overflow-y: auto`
|
|
843
|
+
container would make it scroll sideways by a pixel or two.
|
|
844
|
+
`hitArea="compact"` opts a dense-table row out. `Button
|
|
827
845
|
collapseLabel="mobile" | "container"` hides `<span data-label>` children below
|
|
828
846
|
40rem viewport / 30rem container, drops to icon padding, and names the button
|
|
829
847
|
from the hidden text unless `aria-label` is set:
|
|
@@ -508,7 +508,11 @@
|
|
|
508
508
|
|
|
509
509
|
/* Coarse pointers: icon-only and square buttons carry an invisible slab that
|
|
510
510
|
extends the hit area to --touch-target without changing layout. Buttons
|
|
511
|
-
already at or above the target keep their own box (inset never positive).
|
|
511
|
+
already at or above the target keep their own box (inset never positive).
|
|
512
|
+
The slab grows towards the inline start only: inline-end overflow counts
|
|
513
|
+
towards the scrollable overflow of every scroll ancestor, so a button near
|
|
514
|
+
the right edge of an `overflow-y: auto` container would make it scroll
|
|
515
|
+
sideways. Start-side overflow is unscrollable, so the full target survives. */
|
|
512
516
|
@media (pointer: coarse) {
|
|
513
517
|
.btn-icon:not(.hit-compact),
|
|
514
518
|
.btn-icon-inline:not(.hit-compact),
|
|
@@ -524,7 +528,9 @@
|
|
|
524
528
|
.btn-chip:not(.hit-compact)::after {
|
|
525
529
|
content: '';
|
|
526
530
|
position: absolute;
|
|
527
|
-
inset: min(0px, calc((100% - var(--touch-target)) / 2));
|
|
531
|
+
inset-block: min(0px, calc((100% - var(--touch-target)) / 2));
|
|
532
|
+
inset-inline-start: min(0px, calc(100% - var(--touch-target)));
|
|
533
|
+
inset-inline-end: 0;
|
|
528
534
|
}
|
|
529
535
|
}
|
|
530
536
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// native attribute via `...rest`.
|
|
6
6
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
7
7
|
import { getFieldContext } from '../../field-context';
|
|
8
|
+
import type { ControlSize } from '../../size';
|
|
8
9
|
|
|
9
10
|
let {
|
|
10
11
|
checked = $bindable(false),
|
|
@@ -12,13 +13,14 @@
|
|
|
12
13
|
invalid = false,
|
|
13
14
|
label,
|
|
14
15
|
labelHidden = false,
|
|
16
|
+
size = 'md',
|
|
15
17
|
id,
|
|
16
18
|
'aria-describedby': ariaDescribedby,
|
|
17
19
|
'aria-invalid': ariaInvalid,
|
|
18
20
|
class: klass = '',
|
|
19
21
|
el = $bindable(null),
|
|
20
22
|
...rest
|
|
21
|
-
}: HTMLInputAttributes & {
|
|
23
|
+
}: Omit<HTMLInputAttributes, 'size'> & {
|
|
22
24
|
checked?: boolean;
|
|
23
25
|
indeterminate?: boolean;
|
|
24
26
|
/** Error state: danger box border + aria-invalid. */
|
|
@@ -26,6 +28,9 @@
|
|
|
26
28
|
label: string;
|
|
27
29
|
/** Keep `label` for AT only (sr-only). */
|
|
28
30
|
labelHidden?: boolean;
|
|
31
|
+
/** Box + label scale, as on `Switch`. Override the box alone with
|
|
32
|
+
* `style="--cb-box: 1rem"`. */
|
|
33
|
+
size?: ControlSize;
|
|
29
34
|
id?: string;
|
|
30
35
|
'aria-describedby'?: string | null;
|
|
31
36
|
'aria-invalid'?: HTMLInputAttributes['aria-invalid'];
|
|
@@ -41,7 +46,12 @@
|
|
|
41
46
|
});
|
|
42
47
|
</script>
|
|
43
48
|
|
|
44
|
-
<label
|
|
49
|
+
<label
|
|
50
|
+
class="checkbox {klass}"
|
|
51
|
+
class:checkbox-sm={size === 'sm'}
|
|
52
|
+
class:checkbox-lg={size === 'lg'}
|
|
53
|
+
data-tsu="Checkbox"
|
|
54
|
+
>
|
|
45
55
|
<input
|
|
46
56
|
bind:this={el}
|
|
47
57
|
type="checkbox"
|
|
@@ -72,11 +82,19 @@
|
|
|
72
82
|
opacity: 0;
|
|
73
83
|
margin: 0;
|
|
74
84
|
}
|
|
85
|
+
.checkbox-sm {
|
|
86
|
+
--cb-box: 0.95rem;
|
|
87
|
+
font-size: var(--fs-xs);
|
|
88
|
+
}
|
|
89
|
+
.checkbox-lg {
|
|
90
|
+
--cb-box: 1.35rem;
|
|
91
|
+
font-size: var(--fs-base);
|
|
92
|
+
}
|
|
75
93
|
.box {
|
|
76
94
|
position: relative;
|
|
77
95
|
flex: none;
|
|
78
|
-
width: 1.15rem;
|
|
79
|
-
height: 1.15rem;
|
|
96
|
+
width: var(--cb-box, 1.15rem);
|
|
97
|
+
height: var(--cb-box, 1.15rem);
|
|
80
98
|
border: 1px solid var(--border-strong);
|
|
81
99
|
border-radius: var(--r-sm);
|
|
82
100
|
background: var(--bg);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
|
-
type
|
|
2
|
+
import type { ControlSize } from '../../size';
|
|
3
|
+
type $$ComponentProps = Omit<HTMLInputAttributes, 'size'> & {
|
|
3
4
|
checked?: boolean;
|
|
4
5
|
indeterminate?: boolean;
|
|
5
6
|
/** Error state: danger box border + aria-invalid. */
|
|
@@ -7,6 +8,9 @@ type $$ComponentProps = HTMLInputAttributes & {
|
|
|
7
8
|
label: string;
|
|
8
9
|
/** Keep `label` for AT only (sr-only). */
|
|
9
10
|
labelHidden?: boolean;
|
|
11
|
+
/** Box + label scale, as on `Switch`. Override the box alone with
|
|
12
|
+
* `style="--cb-box: 1rem"`. */
|
|
13
|
+
size?: ControlSize;
|
|
10
14
|
id?: string;
|
|
11
15
|
'aria-describedby'?: string | null;
|
|
12
16
|
'aria-invalid'?: HTMLInputAttributes['aria-invalid'];
|
|
@@ -35,6 +35,8 @@
|
|
|
35
35
|
upload: '<path d="M12 3v12" /><path d="m17 8-5-5-5 5" /><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />',
|
|
36
36
|
send: '<path d="M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z" /><path d="m21.854 2.147-10.94 10.939" />',
|
|
37
37
|
share: '<circle cx="18" cy="5" r="3" /><circle cx="6" cy="12" r="3" /><circle cx="18" cy="19" r="3" /><line x1="8.59" x2="15.42" y1="13.51" y2="17.49" /><line x1="15.41" x2="8.59" y1="6.51" y2="10.49" />',
|
|
38
|
+
reply: '<path d="M20 18v-2a4 4 0 0 0-4-4H4" /><path d="m9 17-5-5 5-5" />',
|
|
39
|
+
quote: '<path d="M16 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z" /><path d="M5 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z" />',
|
|
38
40
|
retry: '<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" /><path d="M21 3v5h-5" /><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" /><path d="M8 16H3v5" />',
|
|
39
41
|
settings: '<path d="M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915" /><circle cx="12" cy="12" r="3" />',
|
|
40
42
|
recycle: '<path d="M7 19H4.815a1.83 1.83 0 0 1-1.57-.881 1.785 1.785 0 0 1-.004-1.784L7.196 9.5" /><path d="M11 19h8.203a1.83 1.83 0 0 0 1.556-.89 1.784 1.784 0 0 0 0-1.775l-1.226-2.12" /><path d="m14 16-3 3 3 3" /><path d="M8.293 13.596 7.196 9.5 3.1 10.598" /><path d="m9.344 5.811 1.093-1.892A1.83 1.83 0 0 1 11.985 3a1.784 1.784 0 0 1 1.546.888l3.943 6.843" /><path d="m13.378 9.633 4.096 1.098 1.097-4.096" />',
|
|
@@ -26,6 +26,8 @@ declare const ICONS: {
|
|
|
26
26
|
readonly upload: "<path d=\"M12 3v12\" /><path d=\"m17 8-5-5-5 5\" /><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />";
|
|
27
27
|
readonly send: "<path d=\"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z\" /><path d=\"m21.854 2.147-10.94 10.939\" />";
|
|
28
28
|
readonly share: "<circle cx=\"18\" cy=\"5\" r=\"3\" /><circle cx=\"6\" cy=\"12\" r=\"3\" /><circle cx=\"18\" cy=\"19\" r=\"3\" /><line x1=\"8.59\" x2=\"15.42\" y1=\"13.51\" y2=\"17.49\" /><line x1=\"15.41\" x2=\"8.59\" y1=\"6.51\" y2=\"10.49\" />";
|
|
29
|
+
readonly reply: "<path d=\"M20 18v-2a4 4 0 0 0-4-4H4\" /><path d=\"m9 17-5-5 5-5\" />";
|
|
30
|
+
readonly quote: "<path d=\"M16 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z\" /><path d=\"M5 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z\" />";
|
|
29
31
|
readonly retry: "<path d=\"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\" /><path d=\"M21 3v5h-5\" /><path d=\"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\" /><path d=\"M8 16H3v5\" />";
|
|
30
32
|
readonly settings: "<path d=\"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915\" /><circle cx=\"12\" cy=\"12\" r=\"3\" />";
|
|
31
33
|
readonly recycle: "<path d=\"M7 19H4.815a1.83 1.83 0 0 1-1.57-.881 1.785 1.785 0 0 1-.004-1.784L7.196 9.5\" /><path d=\"M11 19h8.203a1.83 1.83 0 0 0 1.556-.89 1.784 1.784 0 0 0 0-1.775l-1.226-2.12\" /><path d=\"m14 16-3 3 3 3\" /><path d=\"M8.293 13.596 7.196 9.5 3.1 10.598\" /><path d=\"m9.344 5.811 1.093-1.892A1.83 1.83 0 0 1 11.985 3a1.784 1.784 0 0 1 1.546.888l3.943 6.843\" /><path d=\"m13.378 9.633 4.096 1.098 1.097-4.096\" />";
|
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
collapsed = $bindable(false),
|
|
20
20
|
persistCollapsed = true,
|
|
21
21
|
resizeStep = 16,
|
|
22
|
+
onresizestart,
|
|
23
|
+
onresize,
|
|
24
|
+
onresizeend,
|
|
22
25
|
handlePlacement = 'bottom',
|
|
23
26
|
stickyHandle = true,
|
|
24
27
|
mode = 'inline',
|
|
@@ -53,6 +56,14 @@
|
|
|
53
56
|
persistCollapsed?: boolean;
|
|
54
57
|
/** Pixels added or removed by each resize-separator arrow key press. */
|
|
55
58
|
resizeStep?: number;
|
|
59
|
+
/** A pointer drag of the separator began. Pair with `onresizeend` to
|
|
60
|
+
* suspend expensive work in the panel body while the width is in flux. */
|
|
61
|
+
onresizestart?: () => void;
|
|
62
|
+
/** Live width, once per animation frame while dragging and on each
|
|
63
|
+
* keyboard step. */
|
|
64
|
+
onresize?: (width: number) => void;
|
|
65
|
+
/** Settled width: on pointer release, and after each keyboard step. */
|
|
66
|
+
onresizeend?: (width: number) => void;
|
|
56
67
|
/** Anchor the collapse handle at the top or bottom of the panel edge. */
|
|
57
68
|
handlePlacement?: 'top' | 'bottom';
|
|
58
69
|
/** Keep the collapse handle in view when the panel scrolls past the
|
|
@@ -206,6 +217,17 @@
|
|
|
206
217
|
|
|
207
218
|
function setWidth(nextWidth: number) {
|
|
208
219
|
panelWidth = Math.round(Math.max(boundedMin, Math.min(nextWidth, boundedMax)));
|
|
220
|
+
onresize?.(panelWidth);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function commitWidth(nextWidth: number) {
|
|
224
|
+
persistWidth(nextWidth);
|
|
225
|
+
onresizeend?.(nextWidth);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function setResizing(active: boolean) {
|
|
229
|
+
resizing = active;
|
|
230
|
+
if (active) onresizestart?.();
|
|
209
231
|
}
|
|
210
232
|
|
|
211
233
|
// Keep the collapse handle within the viewport (and its panel) while a long
|
|
@@ -322,8 +344,8 @@
|
|
|
322
344
|
step: resizeStep,
|
|
323
345
|
measure: () => currentWidth,
|
|
324
346
|
onwidth: setWidth,
|
|
325
|
-
oncommit:
|
|
326
|
-
onactive:
|
|
347
|
+
oncommit: commitWidth,
|
|
348
|
+
onactive: setResizing
|
|
327
349
|
}}
|
|
328
350
|
></div>
|
|
329
351
|
{/if}
|
|
@@ -400,7 +422,8 @@
|
|
|
400
422
|
.panel-content {
|
|
401
423
|
flex: 1;
|
|
402
424
|
min-height: 0;
|
|
403
|
-
overflow: auto;
|
|
425
|
+
overflow-y: auto;
|
|
426
|
+
overflow-x: hidden;
|
|
404
427
|
}
|
|
405
428
|
/* Subtle chevron handle anchored to the panel's inner edge — never a filled
|
|
406
429
|
button, never overlapping the neighbouring main content. It stays visible
|
|
@@ -22,6 +22,14 @@ type $$ComponentProps = {
|
|
|
22
22
|
persistCollapsed?: boolean;
|
|
23
23
|
/** Pixels added or removed by each resize-separator arrow key press. */
|
|
24
24
|
resizeStep?: number;
|
|
25
|
+
/** A pointer drag of the separator began. Pair with `onresizeend` to
|
|
26
|
+
* suspend expensive work in the panel body while the width is in flux. */
|
|
27
|
+
onresizestart?: () => void;
|
|
28
|
+
/** Live width, once per animation frame while dragging and on each
|
|
29
|
+
* keyboard step. */
|
|
30
|
+
onresize?: (width: number) => void;
|
|
31
|
+
/** Settled width: on pointer release, and after each keyboard step. */
|
|
32
|
+
onresizeend?: (width: number) => void;
|
|
25
33
|
/** Anchor the collapse handle at the top or bottom of the panel edge. */
|
|
26
34
|
handlePlacement?: 'top' | 'bottom';
|
|
27
35
|
/** Keep the collapse handle in view when the panel scrolls past the
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { DisclosureHeaderContext } from './Disclosure.svelte';
|
|
4
|
+
export type AccordionVariant = 'default' | 'plain';
|
|
5
|
+
/** What a `summary` snippet receives: the live open state plus the item it is
|
|
6
|
+
* rendering, so one shared snippet can head every item. */
|
|
7
|
+
export interface AccordionHeaderContext extends DisclosureHeaderContext {
|
|
8
|
+
item: AccordionItem;
|
|
9
|
+
}
|
|
4
10
|
export interface AccordionItem {
|
|
5
11
|
id: string;
|
|
6
12
|
/** Plain-text header; `summary` wins when both are given. */
|
|
7
13
|
title?: string;
|
|
8
|
-
/** Rich header content; receives the live open state. */
|
|
9
|
-
summary?: Snippet<[
|
|
14
|
+
/** Rich header content; receives the live open state and this item. */
|
|
15
|
+
summary?: Snippet<[AccordionHeaderContext]>;
|
|
10
16
|
/** Panel content for this item. */
|
|
11
17
|
content: Snippet;
|
|
12
18
|
/** Open state. Re-passing a new value takes over from any local toggle. */
|
|
@@ -22,12 +28,14 @@
|
|
|
22
28
|
// closes the other items when one opens.
|
|
23
29
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
24
30
|
import Disclosure from './Disclosure.svelte';
|
|
25
|
-
import type { DisclosureChevron } from './Disclosure.svelte';
|
|
31
|
+
import type { DisclosureChevron, DisclosureSize } from './Disclosure.svelte';
|
|
26
32
|
|
|
27
33
|
let {
|
|
28
34
|
items,
|
|
29
35
|
multiple = true,
|
|
30
36
|
chevron = 'end',
|
|
37
|
+
variant = 'default',
|
|
38
|
+
size = 'default',
|
|
31
39
|
onchange,
|
|
32
40
|
class: klass = '',
|
|
33
41
|
style: styleProp = '',
|
|
@@ -38,6 +46,11 @@
|
|
|
38
46
|
items: AccordionItem[];
|
|
39
47
|
multiple?: boolean;
|
|
40
48
|
chevron?: DisclosureChevron;
|
|
49
|
+
/** `plain` drops the outer border and radius and keeps the item dividers,
|
|
50
|
+
* for a stack that only separates rows. */
|
|
51
|
+
variant?: AccordionVariant;
|
|
52
|
+
/** Header/panel density of every item; forwarded to `Disclosure`. */
|
|
53
|
+
size?: DisclosureSize;
|
|
41
54
|
onchange?: (id: string, open: boolean) => void;
|
|
42
55
|
class?: string;
|
|
43
56
|
style?: string;
|
|
@@ -75,7 +88,13 @@
|
|
|
75
88
|
<span class="acc-title">{title}</span>
|
|
76
89
|
{/snippet}
|
|
77
90
|
|
|
78
|
-
<div
|
|
91
|
+
<div
|
|
92
|
+
{...rest}
|
|
93
|
+
class="accordion {klass}"
|
|
94
|
+
class:accordion--plain={variant === 'plain'}
|
|
95
|
+
style={styleProp}
|
|
96
|
+
data-tsu="Accordion"
|
|
97
|
+
>
|
|
79
98
|
{#each items as item (item.id)}
|
|
80
99
|
<Disclosure
|
|
81
100
|
class="acc-item"
|
|
@@ -84,10 +103,11 @@
|
|
|
84
103
|
onchange={(o) => set(item, o)}
|
|
85
104
|
disabled={item.disabled}
|
|
86
105
|
{chevron}
|
|
106
|
+
{size}
|
|
87
107
|
>
|
|
88
108
|
{#snippet header(ctx)}
|
|
89
109
|
{#if item.summary}
|
|
90
|
-
{@render item.summary(ctx)}
|
|
110
|
+
{@render item.summary({ ...ctx, item })}
|
|
91
111
|
{:else}
|
|
92
112
|
{@render plain(item.title)}
|
|
93
113
|
{/if}
|
|
@@ -103,6 +123,10 @@
|
|
|
103
123
|
border-radius: var(--r-lg);
|
|
104
124
|
overflow: hidden;
|
|
105
125
|
}
|
|
126
|
+
.accordion--plain {
|
|
127
|
+
border: 0;
|
|
128
|
+
border-radius: 0;
|
|
129
|
+
}
|
|
106
130
|
.accordion > :global(.acc-item + .acc-item) {
|
|
107
131
|
border-top: 1px solid var(--border);
|
|
108
132
|
}
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { DisclosureHeaderContext } from './Disclosure.svelte';
|
|
3
|
+
export type AccordionVariant = 'default' | 'plain';
|
|
4
|
+
/** What a `summary` snippet receives: the live open state plus the item it is
|
|
5
|
+
* rendering, so one shared snippet can head every item. */
|
|
6
|
+
export interface AccordionHeaderContext extends DisclosureHeaderContext {
|
|
7
|
+
item: AccordionItem;
|
|
8
|
+
}
|
|
3
9
|
export interface AccordionItem {
|
|
4
10
|
id: string;
|
|
5
11
|
/** Plain-text header; `summary` wins when both are given. */
|
|
6
12
|
title?: string;
|
|
7
|
-
/** Rich header content; receives the live open state. */
|
|
8
|
-
summary?: Snippet<[
|
|
13
|
+
/** Rich header content; receives the live open state and this item. */
|
|
14
|
+
summary?: Snippet<[AccordionHeaderContext]>;
|
|
9
15
|
/** Panel content for this item. */
|
|
10
16
|
content: Snippet;
|
|
11
17
|
/** Open state. Re-passing a new value takes over from any local toggle. */
|
|
@@ -14,11 +20,16 @@ export interface AccordionItem {
|
|
|
14
20
|
disabled?: boolean;
|
|
15
21
|
}
|
|
16
22
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
17
|
-
import type { DisclosureChevron } from './Disclosure.svelte';
|
|
23
|
+
import type { DisclosureChevron, DisclosureSize } from './Disclosure.svelte';
|
|
18
24
|
type Own = {
|
|
19
25
|
items: AccordionItem[];
|
|
20
26
|
multiple?: boolean;
|
|
21
27
|
chevron?: DisclosureChevron;
|
|
28
|
+
/** `plain` drops the outer border and radius and keeps the item dividers,
|
|
29
|
+
* for a stack that only separates rows. */
|
|
30
|
+
variant?: AccordionVariant;
|
|
31
|
+
/** Header/panel density of every item; forwarded to `Disclosure`. */
|
|
32
|
+
size?: DisclosureSize;
|
|
22
33
|
onchange?: (id: string, open: boolean) => void;
|
|
23
34
|
class?: string;
|
|
24
35
|
style?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
export type DisclosureChevron = 'start' | 'end' | false;
|
|
3
|
+
export type DisclosureSize = 'default' | 'compact';
|
|
3
4
|
export interface DisclosureHeaderContext {
|
|
4
5
|
open: boolean;
|
|
5
6
|
}
|
|
@@ -18,6 +19,7 @@
|
|
|
18
19
|
header,
|
|
19
20
|
children,
|
|
20
21
|
chevron = 'end',
|
|
22
|
+
size = 'default',
|
|
21
23
|
id,
|
|
22
24
|
onchange,
|
|
23
25
|
disabled = false,
|
|
@@ -35,6 +37,10 @@
|
|
|
35
37
|
children: Snippet;
|
|
36
38
|
/** Chevron placement; `false` hides it. */
|
|
37
39
|
chevron?: DisclosureChevron;
|
|
40
|
+
/** Header/panel density. `compact` shrinks both to `--fs-xs` and tighter
|
|
41
|
+
* padding for strip rows; tune either with `--disclosure-pad`,
|
|
42
|
+
* `--disclosure-fs`, `--disclosure-panel-pad`. */
|
|
43
|
+
size?: DisclosureSize;
|
|
38
44
|
/** Base for the button/panel ids the ARIA wiring uses. */
|
|
39
45
|
id?: string;
|
|
40
46
|
onchange?: (open: boolean) => void;
|
|
@@ -60,6 +66,7 @@
|
|
|
60
66
|
{...rest}
|
|
61
67
|
class="disclosure {klass}"
|
|
62
68
|
class:disclosure--open={open}
|
|
69
|
+
class:disclosure--compact={size === 'compact'}
|
|
63
70
|
style={styleProp}
|
|
64
71
|
data-tsu="Disclosure"
|
|
65
72
|
>
|
|
@@ -101,13 +108,13 @@
|
|
|
101
108
|
justify-content: space-between;
|
|
102
109
|
gap: var(--sp-2);
|
|
103
110
|
width: 100%;
|
|
104
|
-
padding: var(--sp-3) var(--sp-4);
|
|
111
|
+
padding: var(--disclosure-pad, var(--sp-3) var(--sp-4));
|
|
105
112
|
border: 0;
|
|
106
113
|
background: none;
|
|
107
114
|
color: inherit;
|
|
108
115
|
font: inherit;
|
|
109
116
|
font-weight: var(--fw-medium);
|
|
110
|
-
font-size: var(--fs-sm);
|
|
117
|
+
font-size: var(--disclosure-fs, var(--fs-sm));
|
|
111
118
|
text-align: start;
|
|
112
119
|
cursor: pointer;
|
|
113
120
|
user-select: none;
|
|
@@ -145,10 +152,15 @@
|
|
|
145
152
|
}
|
|
146
153
|
}
|
|
147
154
|
.disclosure__panel {
|
|
148
|
-
padding: 0 var(--sp-4) var(--sp-4);
|
|
149
|
-
font-size: var(--fs-sm);
|
|
155
|
+
padding: var(--disclosure-panel-pad, 0 var(--sp-4) var(--sp-4));
|
|
156
|
+
font-size: var(--disclosure-fs, var(--fs-sm));
|
|
150
157
|
color: var(--text-muted);
|
|
151
158
|
}
|
|
159
|
+
.disclosure--compact {
|
|
160
|
+
--disclosure-pad: var(--sp-1) var(--sp-2);
|
|
161
|
+
--disclosure-fs: var(--fs-xs);
|
|
162
|
+
--disclosure-panel-pad: 0 var(--sp-2) var(--sp-2);
|
|
163
|
+
}
|
|
152
164
|
.disclosure__panel[hidden] {
|
|
153
165
|
display: none;
|
|
154
166
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type DisclosureChevron = 'start' | 'end' | false;
|
|
2
|
+
export type DisclosureSize = 'default' | 'compact';
|
|
2
3
|
export interface DisclosureHeaderContext {
|
|
3
4
|
open: boolean;
|
|
4
5
|
}
|
|
@@ -11,6 +12,10 @@ type Own = {
|
|
|
11
12
|
children: Snippet;
|
|
12
13
|
/** Chevron placement; `false` hides it. */
|
|
13
14
|
chevron?: DisclosureChevron;
|
|
15
|
+
/** Header/panel density. `compact` shrinks both to `--fs-xs` and tighter
|
|
16
|
+
* padding for strip rows; tune either with `--disclosure-pad`,
|
|
17
|
+
* `--disclosure-fs`, `--disclosure-panel-pad`. */
|
|
18
|
+
size?: DisclosureSize;
|
|
14
19
|
/** Base for the button/panel ids the ARIA wiring uses. */
|
|
15
20
|
id?: string;
|
|
16
21
|
onchange?: (open: boolean) => void;
|
|
@@ -157,7 +157,9 @@
|
|
|
157
157
|
.file-btn.icon-only:not(.hit-compact)::after {
|
|
158
158
|
content: '';
|
|
159
159
|
position: absolute;
|
|
160
|
-
inset: min(0px, calc((100% - var(--touch-target)) / 2));
|
|
160
|
+
inset-block: min(0px, calc((100% - var(--touch-target)) / 2));
|
|
161
|
+
inset-inline-start: min(0px, calc(100% - var(--touch-target)));
|
|
162
|
+
inset-inline-end: 0;
|
|
161
163
|
}
|
|
162
164
|
}
|
|
163
165
|
/* Emoji glyph is bumped above the text size — at 1em a paperclip is hard to
|
|
@@ -54,6 +54,9 @@
|
|
|
54
54
|
showLabel?: boolean | 'row';
|
|
55
55
|
/** Rotate the glyph (refresh in flight). */
|
|
56
56
|
spin?: boolean;
|
|
57
|
+
/** Force the glyph filled (or outlined), overriding its registry default —
|
|
58
|
+
* a pin/star toggle painting its "on" state. Forwarded to Icon. */
|
|
59
|
+
filled?: boolean;
|
|
57
60
|
/** Forwarded to Button: spinner, blocks clicks, aria-busy. */
|
|
58
61
|
loading?: boolean;
|
|
59
62
|
/** Corner count indicator, forwarded to Button; the count joins `label`
|
|
@@ -83,6 +86,7 @@
|
|
|
83
86
|
pressed,
|
|
84
87
|
showLabel = false,
|
|
85
88
|
spin = false,
|
|
89
|
+
filled,
|
|
86
90
|
loading = false,
|
|
87
91
|
count,
|
|
88
92
|
countMax,
|
|
@@ -126,17 +130,17 @@
|
|
|
126
130
|
>
|
|
127
131
|
{#if children}
|
|
128
132
|
{#if glyphCss}
|
|
129
|
-
<span class="glyph" style="font-size: {glyphCss}"><Icon {spin}>{@render children()}</Icon></span>
|
|
133
|
+
<span class="glyph" style="font-size: {glyphCss}"><Icon {spin} {filled}>{@render children()}</Icon></span>
|
|
130
134
|
{:else}
|
|
131
|
-
<Icon {size} {spin}>{@render children()}</Icon>
|
|
135
|
+
<Icon {size} {spin} {filled}>{@render children()}</Icon>
|
|
132
136
|
{/if}
|
|
133
137
|
{:else if emoji}
|
|
134
138
|
<span class="emoji" style="font-size: {emojiCss}" aria-hidden="true">{emoji}</span>
|
|
135
139
|
{:else if icon}
|
|
136
140
|
{#if glyphCss}
|
|
137
|
-
<span class="glyph" style="font-size: {glyphCss}"><Icon name={icon} {spin} /></span>
|
|
141
|
+
<span class="glyph" style="font-size: {glyphCss}"><Icon name={icon} {spin} {filled} /></span>
|
|
138
142
|
{:else}
|
|
139
|
-
<Icon name={icon} {size} {spin} />
|
|
143
|
+
<Icon name={icon} {size} {spin} {filled} />
|
|
140
144
|
{/if}
|
|
141
145
|
{/if}
|
|
142
146
|
{#if showLabel}<span class="ib-label">{label}</span>{/if}
|
|
@@ -31,6 +31,9 @@ type IconButtonProps = HTMLButtonAttributes & {
|
|
|
31
31
|
showLabel?: boolean | 'row';
|
|
32
32
|
/** Rotate the glyph (refresh in flight). */
|
|
33
33
|
spin?: boolean;
|
|
34
|
+
/** Force the glyph filled (or outlined), overriding its registry default —
|
|
35
|
+
* a pin/star toggle painting its "on" state. Forwarded to Icon. */
|
|
36
|
+
filled?: boolean;
|
|
34
37
|
/** Forwarded to Button: spinner, blocks clicks, aria-busy. */
|
|
35
38
|
loading?: boolean;
|
|
36
39
|
/** Corner count indicator, forwarded to Button; the count joins `label`
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
// (inherited from the native popover). An item's `tag` renders as a soft
|
|
37
37
|
// Badge pill after the label; the `tag` snippet replaces that pill.
|
|
38
38
|
import type { ComponentProps, Snippet } from 'svelte';
|
|
39
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
39
40
|
import Popover from './Popover.svelte';
|
|
40
41
|
import Icon from '../atoms/Icon.svelte';
|
|
41
42
|
import Badge from '../atoms/Badge.svelte';
|
|
@@ -57,6 +58,8 @@
|
|
|
57
58
|
| 'hitArea'
|
|
58
59
|
| 'disabled'
|
|
59
60
|
| 'gap'
|
|
61
|
+
| 'count'
|
|
62
|
+
| 'countMax'
|
|
60
63
|
| 'onopen'
|
|
61
64
|
| 'onclose'
|
|
62
65
|
>;
|
|
@@ -80,6 +83,8 @@
|
|
|
80
83
|
hitArea,
|
|
81
84
|
disabled,
|
|
82
85
|
gap,
|
|
86
|
+
count,
|
|
87
|
+
countMax,
|
|
83
88
|
onopen,
|
|
84
89
|
onclose,
|
|
85
90
|
open = $bindable(false),
|
|
@@ -87,7 +92,11 @@
|
|
|
87
92
|
class: klass = '',
|
|
88
93
|
style: styleProp = '',
|
|
89
94
|
panelClass = '',
|
|
90
|
-
|
|
95
|
+
panelStyle = '',
|
|
96
|
+
...rest
|
|
97
|
+
}: Omit<HTMLAttributes<HTMLElement>, keyof Own> & Own = $props();
|
|
98
|
+
|
|
99
|
+
type Own = {
|
|
91
100
|
label: string;
|
|
92
101
|
items: MenuItem[];
|
|
93
102
|
trigger: Snippet;
|
|
@@ -100,8 +109,11 @@
|
|
|
100
109
|
closeOnSelect?: boolean;
|
|
101
110
|
class?: string;
|
|
102
111
|
style?: string;
|
|
112
|
+
/** Class / inline style on the floating panel; `panelStyle` is how you
|
|
113
|
+
* size or cap it (`min-width`, `max-height`, `padding`). */
|
|
103
114
|
panelClass?: string;
|
|
104
|
-
|
|
115
|
+
panelStyle?: string;
|
|
116
|
+
} & TriggerChrome;
|
|
105
117
|
|
|
106
118
|
let listEl = $state<HTMLDivElement | null>(null);
|
|
107
119
|
|
|
@@ -139,6 +151,7 @@
|
|
|
139
151
|
</script>
|
|
140
152
|
|
|
141
153
|
<Popover
|
|
154
|
+
{...rest}
|
|
142
155
|
{label}
|
|
143
156
|
{placement}
|
|
144
157
|
{trigger}
|
|
@@ -154,10 +167,13 @@
|
|
|
154
167
|
class={klass}
|
|
155
168
|
style={styleProp}
|
|
156
169
|
{panelClass}
|
|
170
|
+
{panelStyle}
|
|
157
171
|
{bare}
|
|
158
172
|
{hitArea}
|
|
159
173
|
{disabled}
|
|
160
174
|
{gap}
|
|
175
|
+
{count}
|
|
176
|
+
{countMax}
|
|
161
177
|
role="menu"
|
|
162
178
|
haspopup="menu"
|
|
163
179
|
bind:open
|
|
@@ -25,10 +25,11 @@ export interface MenuItem {
|
|
|
25
25
|
attrs?: import('svelte/elements').HTMLButtonAttributes;
|
|
26
26
|
}
|
|
27
27
|
import type { ComponentProps, Snippet } from 'svelte';
|
|
28
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
28
29
|
import Popover from './Popover.svelte';
|
|
29
30
|
type PopoverProps = ComponentProps<typeof Popover>;
|
|
30
|
-
type TriggerChrome = Pick<PopoverProps, 'variant' | 'tone' | 'size' | 'box' | 'pill' | 'control' | 'block' | 'triggerClass' | 'title' | 'bare' | 'hitArea' | 'disabled' | 'gap' | 'onopen' | 'onclose'>;
|
|
31
|
-
type
|
|
31
|
+
type TriggerChrome = Pick<PopoverProps, 'variant' | 'tone' | 'size' | 'box' | 'pill' | 'control' | 'block' | 'triggerClass' | 'title' | 'bare' | 'hitArea' | 'disabled' | 'gap' | 'count' | 'countMax' | 'onopen' | 'onclose'>;
|
|
32
|
+
type Own = {
|
|
32
33
|
label: string;
|
|
33
34
|
items: MenuItem[];
|
|
34
35
|
trigger: Snippet;
|
|
@@ -41,8 +42,12 @@ type $$ComponentProps = {
|
|
|
41
42
|
closeOnSelect?: boolean;
|
|
42
43
|
class?: string;
|
|
43
44
|
style?: string;
|
|
45
|
+
/** Class / inline style on the floating panel; `panelStyle` is how you
|
|
46
|
+
* size or cap it (`min-width`, `max-height`, `padding`). */
|
|
44
47
|
panelClass?: string;
|
|
48
|
+
panelStyle?: string;
|
|
45
49
|
} & TriggerChrome;
|
|
50
|
+
type $$ComponentProps = Omit<HTMLAttributes<HTMLElement>, keyof Own> & Own;
|
|
46
51
|
declare const Menu: import("svelte").Component<$$ComponentProps, {}, "open">;
|
|
47
52
|
type Menu = ReturnType<typeof Menu>;
|
|
48
53
|
export default Menu;
|
|
@@ -450,7 +450,9 @@
|
|
|
450
450
|
flex: none;
|
|
451
451
|
}
|
|
452
452
|
/* Coarse pointers: icon-only triggers extend their hit area to --touch-target
|
|
453
|
-
via an invisible slab; layout does not move.
|
|
453
|
+
via an invisible slab; layout does not move. The slab grows towards the
|
|
454
|
+
inline start only, so it never adds scrollable overflow to a scroll ancestor
|
|
455
|
+
(see Button.svelte). */
|
|
454
456
|
@media (pointer: coarse) {
|
|
455
457
|
.pop-trigger:not(.canonical, .hit-compact) {
|
|
456
458
|
position: relative;
|
|
@@ -458,7 +460,9 @@
|
|
|
458
460
|
.pop-trigger:not(.canonical, .hit-compact)::after {
|
|
459
461
|
content: '';
|
|
460
462
|
position: absolute;
|
|
461
|
-
inset: min(0px, calc((100% - var(--touch-target)) / 2));
|
|
463
|
+
inset-block: min(0px, calc((100% - var(--touch-target)) / 2));
|
|
464
|
+
inset-inline-start: min(0px, calc(100% - var(--touch-target)));
|
|
465
|
+
inset-inline-end: 0;
|
|
462
466
|
}
|
|
463
467
|
}
|
|
464
468
|
.pop-trigger.trigger-tone-accent {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// properties so the fused look needs no reach into their scoped CSS.
|
|
7
7
|
import type { ControlSize } from '../../size';
|
|
8
8
|
import type { ComponentProps, Snippet } from 'svelte';
|
|
9
|
-
import type { HTMLAttributes } from 'svelte/elements';
|
|
9
|
+
import type { HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
|
10
10
|
import Button from '../atoms/Button.svelte';
|
|
11
11
|
import Icon from '../atoms/Icon.svelte';
|
|
12
12
|
import Menu, { type MenuItem } from './Menu.svelte';
|
|
@@ -32,6 +32,11 @@
|
|
|
32
32
|
/** Custom trailing content for items that carry a `tag`. */
|
|
33
33
|
tag?: MenuProps['tag'];
|
|
34
34
|
panelClass?: string;
|
|
35
|
+
panelStyle?: MenuProps['panelStyle'];
|
|
36
|
+
/** Attributes for the primary segment itself — `title`,
|
|
37
|
+
* `aria-describedby`, `data-*`. Rest props stay on the root box, which is
|
|
38
|
+
* where a layout class or `data-journey` for the pair belongs. */
|
|
39
|
+
primaryProps?: Omit<HTMLButtonAttributes, 'class'> & { class?: string };
|
|
35
40
|
gap?: number;
|
|
36
41
|
/** Bindable open state of the menu. */
|
|
37
42
|
open?: boolean;
|
|
@@ -61,6 +66,8 @@
|
|
|
61
66
|
placement = 'bottom-end',
|
|
62
67
|
tag,
|
|
63
68
|
panelClass,
|
|
69
|
+
panelStyle,
|
|
70
|
+
primaryProps,
|
|
64
71
|
gap,
|
|
65
72
|
open = $bindable(false),
|
|
66
73
|
onopen,
|
|
@@ -100,6 +107,7 @@
|
|
|
100
107
|
>
|
|
101
108
|
<span class="split-main">
|
|
102
109
|
<Button
|
|
110
|
+
{...primaryProps}
|
|
103
111
|
{variant}
|
|
104
112
|
{size}
|
|
105
113
|
{control}
|
|
@@ -120,6 +128,7 @@
|
|
|
120
128
|
{placement}
|
|
121
129
|
{tag}
|
|
122
130
|
{panelClass}
|
|
131
|
+
{panelStyle}
|
|
123
132
|
{gap}
|
|
124
133
|
{variant}
|
|
125
134
|
{size}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ControlSize } from '../../size';
|
|
2
2
|
import type { ComponentProps, Snippet } from 'svelte';
|
|
3
|
-
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import type { HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements';
|
|
4
4
|
import Menu, { type MenuItem } from './Menu.svelte';
|
|
5
5
|
type MenuProps = ComponentProps<typeof Menu>;
|
|
6
6
|
type Own = {
|
|
@@ -22,6 +22,13 @@ type Own = {
|
|
|
22
22
|
/** Custom trailing content for items that carry a `tag`. */
|
|
23
23
|
tag?: MenuProps['tag'];
|
|
24
24
|
panelClass?: string;
|
|
25
|
+
panelStyle?: MenuProps['panelStyle'];
|
|
26
|
+
/** Attributes for the primary segment itself — `title`,
|
|
27
|
+
* `aria-describedby`, `data-*`. Rest props stay on the root box, which is
|
|
28
|
+
* where a layout class or `data-journey` for the pair belongs. */
|
|
29
|
+
primaryProps?: Omit<HTMLButtonAttributes, 'class'> & {
|
|
30
|
+
class?: string;
|
|
31
|
+
};
|
|
25
32
|
gap?: number;
|
|
26
33
|
/** Bindable open state of the menu. */
|
|
27
34
|
open?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export { default as ResizablePanel } from './components/layouts/ResizablePanel.s
|
|
|
42
42
|
export { type ResizeHandleParams, resizeHandle, } from './components/layouts/resizable-panel-frame.js';
|
|
43
43
|
export { default as Stack } from './components/layouts/Stack.svelte';
|
|
44
44
|
export { default as Toolbar } from './components/layouts/Toolbar.svelte';
|
|
45
|
-
export { type AccordionItem, default as Accordion, } from './components/molecules/Accordion.svelte';
|
|
45
|
+
export { type AccordionHeaderContext, type AccordionItem, type AccordionVariant, default as Accordion, } from './components/molecules/Accordion.svelte';
|
|
46
46
|
export { type Attachment, default as AttachmentList, } from './components/molecules/AttachmentList.svelte';
|
|
47
47
|
export { type BreadcrumbItem, default as Breadcrumb, } from './components/molecules/Breadcrumb.svelte';
|
|
48
48
|
export { default as Callout } from './components/molecules/Callout.svelte';
|
|
@@ -55,7 +55,7 @@ export { default as Composer } from './components/molecules/Composer.svelte';
|
|
|
55
55
|
export { default as ConfirmModal } from './components/molecules/ConfirmModal.svelte';
|
|
56
56
|
export { default as CopyButton } from './components/molecules/CopyButton.svelte';
|
|
57
57
|
export { applyTrigger, comboboxAction, findTrigger, nextComboboxIndex, } from './components/molecules/combobox-keyboard.js';
|
|
58
|
-
export { type DisclosureChevron, type DisclosureHeaderContext, default as Disclosure, } from './components/molecules/Disclosure.svelte';
|
|
58
|
+
export { type DisclosureChevron, type DisclosureHeaderContext, type DisclosureSize, default as Disclosure, } from './components/molecules/Disclosure.svelte';
|
|
59
59
|
export { default as Drawer } from './components/molecules/Drawer.svelte';
|
|
60
60
|
export { default as Dropzone } from './components/molecules/Dropzone.svelte';
|
|
61
61
|
export { default as EmojiPicker } from './components/molecules/EmojiPicker.svelte';
|
package/dist/styles/reset.css
CHANGED
|
@@ -88,12 +88,16 @@ pre {
|
|
|
88
88
|
border-radius: var(--r-sm);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
/* Slim scrollbars for mice only. On touch, a custom scrollbar replaces the
|
|
92
|
+
native overlay bars with classic space-taking ones. */
|
|
93
|
+
@media (hover: hover) and (pointer: fine) {
|
|
94
|
+
::-webkit-scrollbar {
|
|
95
|
+
width: 8px;
|
|
96
|
+
height: 8px;
|
|
97
|
+
}
|
|
98
|
+
::-webkit-scrollbar-thumb {
|
|
99
|
+
background: var(--border-strong);
|
|
100
|
+
border-radius: var(--r-pill);
|
|
101
|
+
}
|
|
98
102
|
}
|
|
99
103
|
|
package/package.json
CHANGED