@seekalfred/primitives 0.5.1 → 0.6.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 +664 -9
- package/dist/accordion/accordion.js +10 -4
- package/dist/accordion/accordion.js.map +1 -1
- package/dist/action-button/action-button.d.ts +50 -0
- package/dist/action-button/action-button.js +159 -0
- package/dist/action-button/action-button.js.map +1 -0
- package/dist/action-button/index.d.ts +2 -0
- package/dist/action-button/index.js +2 -0
- package/dist/alert/alert.d.ts +15 -1
- package/dist/alert/alert.js +116 -20
- package/dist/alert/alert.js.map +1 -1
- package/dist/avatar/avatar.d.ts +6 -0
- package/dist/avatar/avatar.js +47 -16
- package/dist/avatar/avatar.js.map +1 -1
- package/dist/badge/badge.d.ts +11 -4
- package/dist/badge/badge.js +35 -5
- package/dist/badge/badge.js.map +1 -1
- package/dist/breadcrumb/breadcrumb.d.ts +0 -27
- package/dist/breadcrumb/breadcrumb.js +20 -6
- package/dist/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/button/button.d.ts +35 -22
- package/dist/button/button.js +177 -34
- package/dist/button/button.js.map +1 -1
- package/dist/button-group/button-group.d.ts +76 -0
- package/dist/button-group/button-group.js +403 -0
- package/dist/button-group/button-group.js.map +1 -0
- package/dist/button-group/index.d.ts +2 -0
- package/dist/button-group/index.js +2 -0
- package/dist/calendar/calendar.d.ts +1 -1
- package/dist/calendar/calendar.js +257 -30
- package/dist/calendar/calendar.js.map +1 -1
- package/dist/card/card.d.ts +9 -2
- package/dist/card/card.js +15 -4
- package/dist/card/card.js.map +1 -1
- package/dist/checkbox/checkbox.d.ts +0 -7
- package/dist/checkbox/checkbox.js +24 -27
- package/dist/checkbox/checkbox.js.map +1 -1
- package/dist/confirm-morph/confirm-morph.d.ts +85 -0
- package/dist/confirm-morph/confirm-morph.js +652 -0
- package/dist/confirm-morph/confirm-morph.js.map +1 -0
- package/dist/confirm-morph/index.d.ts +2 -0
- package/dist/confirm-morph/index.js +2 -0
- package/dist/copy-button/copy-button.d.ts +32 -0
- package/dist/copy-button/copy-button.js +134 -0
- package/dist/copy-button/copy-button.js.map +1 -0
- package/dist/copy-button/index.d.ts +2 -0
- package/dist/copy-button/index.js +2 -0
- package/dist/date-picker/date-picker.d.ts +51 -0
- package/dist/date-picker/date-picker.js +241 -0
- package/dist/date-picker/date-picker.js.map +1 -0
- package/dist/date-picker/date-range-picker.d.ts +78 -0
- package/dist/date-picker/date-range-picker.js +1015 -0
- package/dist/date-picker/date-range-picker.js.map +1 -0
- package/dist/date-picker/index.d.ts +4 -0
- package/dist/date-picker/index.js +4 -0
- package/dist/date-picker/picker-parts.d.ts +46 -0
- package/dist/date-picker/picker-parts.js +135 -0
- package/dist/date-picker/picker-parts.js.map +1 -0
- package/dist/dialog/dialog.d.ts +10 -14
- package/dist/dialog/dialog.js +39 -11
- package/dist/dialog/dialog.js.map +1 -1
- package/dist/empty-state/empty-state.d.ts +44 -0
- package/dist/empty-state/empty-state.js +83 -0
- package/dist/empty-state/empty-state.js.map +1 -0
- package/dist/empty-state/index.d.ts +2 -0
- package/dist/empty-state/index.js +2 -0
- package/dist/expanding-button-group/expanding-button-group.d.ts +54 -0
- package/dist/expanding-button-group/expanding-button-group.js +350 -0
- package/dist/expanding-button-group/expanding-button-group.js.map +1 -0
- package/dist/expanding-button-group/index.d.ts +2 -0
- package/dist/expanding-button-group/index.js +2 -0
- package/dist/file-drop-zone/file-drop-zone.d.ts +71 -0
- package/dist/file-drop-zone/file-drop-zone.js +116 -0
- package/dist/file-drop-zone/file-drop-zone.js.map +1 -0
- package/dist/file-drop-zone/index.d.ts +2 -0
- package/dist/file-drop-zone/index.js +2 -0
- package/dist/filter-bar/filter-bar.d.ts +121 -0
- package/dist/filter-bar/filter-bar.js +300 -0
- package/dist/filter-bar/filter-bar.js.map +1 -0
- package/dist/filter-bar/index.d.ts +2 -0
- package/dist/filter-bar/index.js +2 -0
- package/dist/floating-button-group/floating-button-group.d.ts +61 -0
- package/dist/floating-button-group/floating-button-group.js +340 -0
- package/dist/floating-button-group/floating-button-group.js.map +1 -0
- package/dist/floating-button-group/index.d.ts +2 -0
- package/dist/floating-button-group/index.js +2 -0
- package/dist/icon-morph/icon-morph.d.ts +55 -0
- package/dist/icon-morph/icon-morph.js +331 -0
- package/dist/icon-morph/icon-morph.js.map +1 -0
- package/dist/icon-morph/index.d.ts +2 -0
- package/dist/icon-morph/index.js +2 -0
- package/dist/index.d.ts +24 -2
- package/dist/index.js +29 -7
- package/dist/input/input.d.ts +22 -0
- package/dist/input/input.js +36 -12
- package/dist/input/input.js.map +1 -1
- package/dist/lib/count-to.js +113 -0
- package/dist/lib/count-to.js.map +1 -0
- package/dist/lib/eye-morph.js +62 -0
- package/dist/lib/eye-morph.js.map +1 -0
- package/dist/lib/field-message.js +336 -0
- package/dist/lib/field-message.js.map +1 -0
- package/dist/lib/field-shell.js +81 -0
- package/dist/lib/field-shell.js.map +1 -0
- package/dist/lib/field-surface.js +4 -2
- package/dist/lib/field-surface.js.map +1 -1
- package/dist/lib/flip.js +80 -0
- package/dist/lib/flip.js.map +1 -0
- package/dist/lib/height-follow.js +59 -0
- package/dist/lib/height-follow.js.map +1 -0
- package/dist/lib/icon-swap.js +47 -0
- package/dist/lib/icon-swap.js.map +1 -0
- package/dist/lib/leaving-list.js +57 -0
- package/dist/lib/leaving-list.js.map +1 -0
- package/dist/lib/merge-refs.js +3 -3
- package/dist/lib/merge-refs.js.map +1 -1
- package/dist/lib/morph-text.js +128 -0
- package/dist/lib/morph-text.js.map +1 -0
- package/dist/lib/motion.js +162 -0
- package/dist/lib/motion.js.map +1 -0
- package/dist/lib/pausable-timeout.js +67 -0
- package/dist/lib/pausable-timeout.js.map +1 -0
- package/dist/lib/rolling-value.js +31 -0
- package/dist/lib/rolling-value.js.map +1 -0
- package/dist/lib/spring-progress.js +114 -0
- package/dist/lib/spring-progress.js.map +1 -0
- package/dist/lib/svg-id.js +10 -0
- package/dist/lib/svg-id.js.map +1 -0
- package/dist/lib/swap-text.js +77 -0
- package/dist/lib/swap-text.js.map +1 -0
- package/dist/lib/use-copy-feedback.js +36 -0
- package/dist/lib/use-copy-feedback.js.map +1 -0
- package/dist/page-header/index.d.ts +2 -0
- package/dist/page-header/index.js +2 -0
- package/dist/page-header/page-header.d.ts +75 -0
- package/dist/page-header/page-header.js +83 -0
- package/dist/page-header/page-header.js.map +1 -0
- package/dist/password-field/index.d.ts +2 -0
- package/dist/password-field/index.js +2 -0
- package/dist/password-field/password-field.d.ts +37 -0
- package/dist/password-field/password-field.js +101 -0
- package/dist/password-field/password-field.js.map +1 -0
- package/dist/password-strength/index.d.ts +2 -0
- package/dist/password-strength/index.js +2 -0
- package/dist/password-strength/password-strength.d.ts +127 -0
- package/dist/password-strength/password-strength.js +455 -0
- package/dist/password-strength/password-strength.js.map +1 -0
- package/dist/popover/popover.d.ts +8 -0
- package/dist/popover/popover.js +3 -3
- package/dist/popover/popover.js.map +1 -1
- package/dist/progress/progress.js +46 -5
- package/dist/progress/progress.js.map +1 -1
- package/dist/radio-group/radio-group.js +7 -6
- package/dist/radio-group/radio-group.js.map +1 -1
- package/dist/scroll-area/scroll-area.d.ts +10 -0
- package/dist/scroll-area/scroll-area.js +25 -3
- package/dist/scroll-area/scroll-area.js.map +1 -1
- package/dist/search-field/index.d.ts +2 -0
- package/dist/search-field/index.js +2 -0
- package/dist/search-field/search-field.d.ts +26 -0
- package/dist/search-field/search-field.js +155 -0
- package/dist/search-field/search-field.js.map +1 -0
- package/dist/select/select.js +79 -21
- package/dist/select/select.js.map +1 -1
- package/dist/sheet/sheet.js +2 -1
- package/dist/sheet/sheet.js.map +1 -1
- package/dist/side-nav/index.d.ts +2 -0
- package/dist/side-nav/index.js +2 -0
- package/dist/side-nav/side-nav.d.ts +72 -0
- package/dist/side-nav/side-nav.js +142 -0
- package/dist/side-nav/side-nav.js.map +1 -0
- package/dist/skeleton/skeleton.d.ts +8 -2
- package/dist/skeleton/skeleton.js +6 -2
- package/dist/skeleton/skeleton.js.map +1 -1
- package/dist/slider/slider.js +61 -7
- package/dist/slider/slider.js.map +1 -1
- package/dist/split-button/index.d.ts +2 -0
- package/dist/split-button/index.js +2 -0
- package/dist/split-button/split-button.d.ts +46 -0
- package/dist/split-button/split-button.js +122 -0
- package/dist/split-button/split-button.js.map +1 -0
- package/dist/stat-card/index.d.ts +2 -0
- package/dist/stat-card/index.js +2 -0
- package/dist/stat-card/stat-card.d.ts +81 -0
- package/dist/stat-card/stat-card.js +152 -0
- package/dist/stat-card/stat-card.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/switch/switch.js +9 -8
- package/dist/switch/switch.js.map +1 -1
- package/dist/table/index.d.ts +2 -2
- package/dist/table/index.js +2 -2
- package/dist/table/table.d.ts +36 -5
- package/dist/table/table.js +112 -11
- package/dist/table/table.js.map +1 -1
- package/dist/tabs/tabs.js +142 -6
- package/dist/tabs/tabs.js.map +1 -1
- package/dist/textarea/textarea.d.ts +23 -0
- package/dist/textarea/textarea.js +24 -2
- package/dist/textarea/textarea.js.map +1 -1
- package/dist/theme-switch/index.d.ts +2 -0
- package/dist/theme-switch/index.js +2 -0
- package/dist/theme-switch/theme-switch.d.ts +37 -0
- package/dist/theme-switch/theme-switch.js +123 -0
- package/dist/theme-switch/theme-switch.js.map +1 -0
- package/dist/time-picker/index.d.ts +2 -0
- package/dist/time-picker/index.js +2 -0
- package/dist/time-picker/time-picker.d.ts +54 -0
- package/dist/time-picker/time-picker.js +201 -0
- package/dist/time-picker/time-picker.js.map +1 -0
- package/dist/toast/toast.js +58 -38
- package/dist/toast/toast.js.map +1 -1
- package/dist/tooltip/tooltip.d.ts +1 -1
- package/dist/tooltip/tooltip.js +63 -14
- package/dist/tooltip/tooltip.js.map +1 -1
- package/package.json +83 -3
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn, cnAll } from "../lib/cn.js";
|
|
3
|
+
import { prefersReducedMotion, useExitBackstop, useIsomorphicLayoutEffect, useMorphWidth } from "../lib/motion.js";
|
|
4
|
+
import { Button } from "../button/button.js";
|
|
5
|
+
import { SwapText } from "../lib/swap-text.js";
|
|
6
|
+
import { useHeightFollow } from "../lib/height-follow.js";
|
|
7
|
+
import { Badge } from "../badge/badge.js";
|
|
8
|
+
import { Popover, PopoverTrigger } from "../popover/popover.js";
|
|
9
|
+
import { useLeavingList } from "../lib/leaving-list.js";
|
|
10
|
+
import { Select, SelectItem } from "../select/select.js";
|
|
11
|
+
import { cva } from "class-variance-authority";
|
|
12
|
+
import { forwardRef, useCallback, useEffect, useRef, useState } from "react";
|
|
13
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
//#region src/filter-bar/filter-bar.tsx
|
|
15
|
+
/**
|
|
16
|
+
* FilterBar -- a list toolbar that keeps the controls people use every time
|
|
17
|
+
* in the row and puts every other dropdown filter behind ONE "Filters"
|
|
18
|
+
* button.
|
|
19
|
+
*
|
|
20
|
+
* Why it exists: list screens grew a row of four to seven dropdowns beside
|
|
21
|
+
* the search box and the status tabs. At desktop width that row wraps onto a
|
|
22
|
+
* second line; on a phone it scrolls sideways. The bar keeps the row to one
|
|
23
|
+
* line and makes what IS filtered visible as chips instead of as the
|
|
24
|
+
* resting text of a dropdown.
|
|
25
|
+
*
|
|
26
|
+
* Three regions:
|
|
27
|
+
*
|
|
28
|
+
* - `inline`: always in the row, at its start (status tabs, the search box).
|
|
29
|
+
* - the Filters button: a popover with a one-column form, one full-width
|
|
30
|
+
* Select per filter with its label above. The button carries a count badge
|
|
31
|
+
* of the filters that are set.
|
|
32
|
+
* - `end`: always in the row, at its end (a count, Export, a view toggle).
|
|
33
|
+
*
|
|
34
|
+
* While any filter is set, a list of chips sits under the row, each reading
|
|
35
|
+
* "Label: option label" with its own remove button, plus "Clear all".
|
|
36
|
+
*
|
|
37
|
+
* The bar holds NO filter state. Every value and every change belongs to the
|
|
38
|
+
* caller: removing a chip hands the filter's `emptyValue` back to its
|
|
39
|
+
* `onChange`; Clear all does that for each set filter, or calls
|
|
40
|
+
* `onClearAll` when the caller resets its filters in one step.
|
|
41
|
+
*
|
|
42
|
+
* Accessibility comes from the parts: the popover is a dialog named by its
|
|
43
|
+
* trigger, the trigger carries `aria-expanded`, focus moves into the popover
|
|
44
|
+
* and is contained there, Escape closes it and focus returns to the trigger.
|
|
45
|
+
*/
|
|
46
|
+
const filterBarVariants = cva(["flex flex-col gap-2 box-border font-sans"]);
|
|
47
|
+
const filterBarRowVariants = cva(["flex flex-wrap items-center gap-2"]);
|
|
48
|
+
const filterBarChipVariants = cva([
|
|
49
|
+
"inline-flex items-center gap-1 rounded-full",
|
|
50
|
+
"border-(length:--border-width) border-border bg-muted",
|
|
51
|
+
"ps-3 pe-1 text-xs leading-(--leading-snug) text-foreground",
|
|
52
|
+
"box-border font-sans"
|
|
53
|
+
]);
|
|
54
|
+
const isCustom = (f) => "render" in f;
|
|
55
|
+
/** The set filters, each with its chip text and how to unset it. */
|
|
56
|
+
function chipsFor(filters) {
|
|
57
|
+
const chips = [];
|
|
58
|
+
for (const f of filters) {
|
|
59
|
+
if (isCustom(f)) {
|
|
60
|
+
if (f.activeLabel != null) chips.push({
|
|
61
|
+
id: f.id,
|
|
62
|
+
text: `${f.label}: ${f.activeLabel}`,
|
|
63
|
+
clear: f.onClear
|
|
64
|
+
});
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (f.value == null || f.value === f.emptyValue) continue;
|
|
68
|
+
const option = f.options.find((o) => o.id === f.value);
|
|
69
|
+
chips.push({
|
|
70
|
+
id: f.id,
|
|
71
|
+
text: `${f.label}: ${option ? option.label : String(f.value)}`,
|
|
72
|
+
clear: () => f.onChange(f.emptyValue)
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return chips;
|
|
76
|
+
}
|
|
77
|
+
/** A funnel, drawn inline: this package ships no icon dependency. */
|
|
78
|
+
function FunnelGlyph() {
|
|
79
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
80
|
+
viewBox: "0 0 16 16",
|
|
81
|
+
fill: "none",
|
|
82
|
+
stroke: "currentColor",
|
|
83
|
+
strokeWidth: "1.5",
|
|
84
|
+
"aria-hidden": "true",
|
|
85
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
86
|
+
d: "M2 3h12M4.5 8h7M7 13h2",
|
|
87
|
+
strokeLinecap: "round"
|
|
88
|
+
})
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function CrossGlyph() {
|
|
92
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
93
|
+
viewBox: "0 0 16 16",
|
|
94
|
+
fill: "none",
|
|
95
|
+
stroke: "currentColor",
|
|
96
|
+
strokeWidth: "1.5",
|
|
97
|
+
"aria-hidden": "true",
|
|
98
|
+
children: /* @__PURE__ */ jsx("path", {
|
|
99
|
+
d: "M4 4l8 8M12 4l-8 8",
|
|
100
|
+
strokeLinecap: "round"
|
|
101
|
+
})
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* A list toolbar with its dropdown filters behind one Filters button.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* <FilterBar
|
|
109
|
+
* inline={<SearchField aria-label="Search" />}
|
|
110
|
+
* end={<Button>Export</Button>}
|
|
111
|
+
* filters={[{ id: "region", label: "Region", value, emptyValue: "all", onChange: setValue,
|
|
112
|
+
* options: [{ id: "all", label: "All regions" }, { id: "nsw", label: "NSW" }] }]}
|
|
113
|
+
* />
|
|
114
|
+
*/
|
|
115
|
+
/**
|
|
116
|
+
* One place in the chip row, for a chip or for Clear all. A slot added after the
|
|
117
|
+
* first render opens from nothing while its content fades up and scales in, so the
|
|
118
|
+
* chips beside it glide over; one that is removed stays, shrinking and collapsing,
|
|
119
|
+
* until its exit ends. Nothing animates at first render.
|
|
120
|
+
*/
|
|
121
|
+
function Slot({ leaving, ready, onDone, id, children }) {
|
|
122
|
+
const [fresh] = useState(ready);
|
|
123
|
+
const remove = useCallback(() => onDone(id), [onDone, id]);
|
|
124
|
+
useExitBackstop(leaving, remove, 900);
|
|
125
|
+
useIsomorphicLayoutEffect(() => {
|
|
126
|
+
if (leaving && prefersReducedMotion()) remove();
|
|
127
|
+
}, [leaving, remove]);
|
|
128
|
+
return /* @__PURE__ */ jsx("li", {
|
|
129
|
+
"data-slot": leaving ? "filter-bar-leaving" : void 0,
|
|
130
|
+
"aria-hidden": leaving || void 0,
|
|
131
|
+
ref: (node) => {
|
|
132
|
+
if (!node) return;
|
|
133
|
+
if (leaving) node.setAttribute("inert", "");
|
|
134
|
+
else node.removeAttribute("inert");
|
|
135
|
+
},
|
|
136
|
+
onAnimationEnd: (event) => {
|
|
137
|
+
if (leaving && event.target === event.currentTarget && event.animationName === "chip-slot-out") remove();
|
|
138
|
+
},
|
|
139
|
+
className: cnAll("min-w-0 flex-none [interpolate-size:allow-keywords]", leaving ? "pointer-events-none motion-safe:animate-chip-out" : fresh && "motion-safe:animate-chip-in motion-reduce:animate-fade-in"),
|
|
140
|
+
children
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/** A chip's text: a changed value swaps (the new text rises in) and the chip's width springs to it. */
|
|
144
|
+
function ChipText({ text }) {
|
|
145
|
+
const content = useRef(null);
|
|
146
|
+
useMorphWidth(content, text);
|
|
147
|
+
return /* @__PURE__ */ jsx("span", {
|
|
148
|
+
className: "button-slot",
|
|
149
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
150
|
+
ref: content,
|
|
151
|
+
className: "inline-flex flex-none items-center",
|
|
152
|
+
children: /* @__PURE__ */ jsx(SwapText, {
|
|
153
|
+
swapKey: text,
|
|
154
|
+
className: "inline-block",
|
|
155
|
+
children: text
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const FilterBar = forwardRef(function FilterBar({ inline, end, filters, onClearAll, buttonLabel = "Filters", clearAllLabel = "Clear all", doneLabel = "Done", chipsLabel = "Filters set", removeLabel = (text) => `Remove filter ${text}`, className }, ref) {
|
|
161
|
+
const [open, setOpen] = useState(false);
|
|
162
|
+
const chips = chipsFor(filters);
|
|
163
|
+
const [ready, setReady] = useState(false);
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
const frame = requestAnimationFrame(() => setReady(true));
|
|
166
|
+
return () => cancelAnimationFrame(frame);
|
|
167
|
+
}, []);
|
|
168
|
+
const places = useLeavingList([...chips.map((chip) => ({
|
|
169
|
+
id: chip.id,
|
|
170
|
+
chip
|
|
171
|
+
})), ...chips.length > 0 ? [{
|
|
172
|
+
id: "\0clear",
|
|
173
|
+
chip: null
|
|
174
|
+
}] : []]);
|
|
175
|
+
const frame = useRef(null);
|
|
176
|
+
const row = useRef(null);
|
|
177
|
+
useHeightFollow(frame, row, chips.map((chip) => chip.id).join());
|
|
178
|
+
const clearAll = () => {
|
|
179
|
+
if (onClearAll) onClearAll();
|
|
180
|
+
else for (const c of chips) c.clear();
|
|
181
|
+
};
|
|
182
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
183
|
+
ref,
|
|
184
|
+
"data-slot": "filter-bar",
|
|
185
|
+
className: cn(filterBarVariants(), className),
|
|
186
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
187
|
+
"data-slot": "filter-bar-row",
|
|
188
|
+
className: filterBarRowVariants(),
|
|
189
|
+
children: [
|
|
190
|
+
inline,
|
|
191
|
+
filters.length > 0 ? /* @__PURE__ */ jsxs(PopoverTrigger, {
|
|
192
|
+
isOpen: open,
|
|
193
|
+
onOpenChange: setOpen,
|
|
194
|
+
children: [/* @__PURE__ */ jsxs(Button, {
|
|
195
|
+
variant: "outlineNeutral",
|
|
196
|
+
size: "sm",
|
|
197
|
+
startIcon: /* @__PURE__ */ jsx(FunnelGlyph, {}),
|
|
198
|
+
"data-slot": "filter-bar-button",
|
|
199
|
+
children: [buttonLabel, chips.length > 0 ? /* @__PURE__ */ jsx(Badge, {
|
|
200
|
+
tone: "primary",
|
|
201
|
+
appearance: "solid",
|
|
202
|
+
size: "sm",
|
|
203
|
+
shape: "pill",
|
|
204
|
+
"data-slot": "filter-bar-count",
|
|
205
|
+
children: chips.length
|
|
206
|
+
}) : null]
|
|
207
|
+
}), /* @__PURE__ */ jsx(Popover, {
|
|
208
|
+
placement: "bottom start",
|
|
209
|
+
className: "w-80 max-w-[calc(100vw-2rem)]",
|
|
210
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
211
|
+
"data-slot": "filter-bar-panel",
|
|
212
|
+
className: "flex flex-col gap-3",
|
|
213
|
+
children: [
|
|
214
|
+
/* @__PURE__ */ jsx("p", {
|
|
215
|
+
className: "m-0 text-sm font-semibold",
|
|
216
|
+
children: buttonLabel
|
|
217
|
+
}),
|
|
218
|
+
filters.map((f) => isCustom(f) ? /* @__PURE__ */ jsx("div", { children: f.render() }, f.id) : /* @__PURE__ */ jsx(Select, {
|
|
219
|
+
label: f.label,
|
|
220
|
+
size: "sm",
|
|
221
|
+
selectedKey: f.value,
|
|
222
|
+
onSelectionChange: (key) => {
|
|
223
|
+
if (key != null) f.onChange(key);
|
|
224
|
+
},
|
|
225
|
+
children: f.options.map((o) => /* @__PURE__ */ jsx(SelectItem, {
|
|
226
|
+
id: o.id,
|
|
227
|
+
textValue: o.label,
|
|
228
|
+
children: o.label
|
|
229
|
+
}, o.id))
|
|
230
|
+
}, f.id)),
|
|
231
|
+
/* @__PURE__ */ jsxs("div", {
|
|
232
|
+
className: "flex items-center justify-between gap-2 pt-1",
|
|
233
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
234
|
+
variant: "ghost",
|
|
235
|
+
size: "sm",
|
|
236
|
+
onPress: clearAll,
|
|
237
|
+
isDisabled: chips.length === 0,
|
|
238
|
+
children: clearAllLabel
|
|
239
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
240
|
+
variant: "primary",
|
|
241
|
+
size: "sm",
|
|
242
|
+
onPress: () => setOpen(false),
|
|
243
|
+
children: doneLabel
|
|
244
|
+
})]
|
|
245
|
+
})
|
|
246
|
+
]
|
|
247
|
+
})
|
|
248
|
+
})]
|
|
249
|
+
}) : null,
|
|
250
|
+
end ? /* @__PURE__ */ jsx("div", {
|
|
251
|
+
className: "ms-auto flex flex-wrap items-center gap-2",
|
|
252
|
+
children: end
|
|
253
|
+
}) : null
|
|
254
|
+
]
|
|
255
|
+
}), places.list.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
256
|
+
ref: frame,
|
|
257
|
+
"data-slot": "filter-bar-chips-frame",
|
|
258
|
+
className: "height-follow",
|
|
259
|
+
children: /* @__PURE__ */ jsx("ul", {
|
|
260
|
+
ref: row,
|
|
261
|
+
"aria-label": chipsLabel,
|
|
262
|
+
"data-slot": "filter-bar-chips",
|
|
263
|
+
className: "m-0 flex list-none flex-wrap items-center gap-2 p-0",
|
|
264
|
+
children: places.list.map(({ item, leaving }) => item.chip ? /* @__PURE__ */ jsx(Slot, {
|
|
265
|
+
id: item.id,
|
|
266
|
+
leaving,
|
|
267
|
+
ready,
|
|
268
|
+
onDone: places.done,
|
|
269
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
270
|
+
"data-slot": "filter-bar-chip",
|
|
271
|
+
className: filterBarChipVariants(),
|
|
272
|
+
children: [/* @__PURE__ */ jsx(ChipText, { text: item.chip.text }), /* @__PURE__ */ jsx(Button, {
|
|
273
|
+
variant: "ghost",
|
|
274
|
+
size: "sm",
|
|
275
|
+
"aria-label": removeLabel(item.chip.text),
|
|
276
|
+
onPress: item.chip.clear,
|
|
277
|
+
className: "h-6 px-1",
|
|
278
|
+
children: /* @__PURE__ */ jsx(CrossGlyph, {})
|
|
279
|
+
})]
|
|
280
|
+
})
|
|
281
|
+
}, item.id) : /* @__PURE__ */ jsx(Slot, {
|
|
282
|
+
id: item.id,
|
|
283
|
+
leaving,
|
|
284
|
+
ready,
|
|
285
|
+
onDone: places.done,
|
|
286
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
287
|
+
variant: "link",
|
|
288
|
+
size: "sm",
|
|
289
|
+
onPress: clearAll,
|
|
290
|
+
children: clearAllLabel
|
|
291
|
+
})
|
|
292
|
+
}, item.id))
|
|
293
|
+
})
|
|
294
|
+
}) : null]
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
//#endregion
|
|
298
|
+
export { FilterBar, filterBarChipVariants, filterBarRowVariants, filterBarVariants };
|
|
299
|
+
|
|
300
|
+
//# sourceMappingURL=filter-bar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-bar.js","names":[],"sources":["../../src/filter-bar/filter-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport { forwardRef, useCallback, useEffect, useRef, useState, type ReactNode } from \"react\";\nimport type { Key } from \"react-aria-components\";\n\nimport { Badge } from \"../badge/badge.js\";\nimport { Button } from \"../button/button.js\";\nimport { cn, cnAll } from \"../lib/cn.js\";\nimport { useHeightFollow } from \"../lib/height-follow.js\";\nimport { useLeavingList } from \"../lib/leaving-list.js\";\nimport { prefersReducedMotion, useExitBackstop, useIsomorphicLayoutEffect, useMorphWidth } from \"../lib/motion.js\";\nimport { SwapText } from \"../lib/swap-text.js\";\nimport { Popover, PopoverTrigger } from \"../popover/popover.js\";\nimport { Select, SelectItem } from \"../select/select.js\";\n\n/**\n * FilterBar -- a list toolbar that keeps the controls people use every time\n * in the row and puts every other dropdown filter behind ONE \"Filters\"\n * button.\n *\n * Why it exists: list screens grew a row of four to seven dropdowns beside\n * the search box and the status tabs. At desktop width that row wraps onto a\n * second line; on a phone it scrolls sideways. The bar keeps the row to one\n * line and makes what IS filtered visible as chips instead of as the\n * resting text of a dropdown.\n *\n * Three regions:\n *\n * - `inline`: always in the row, at its start (status tabs, the search box).\n * - the Filters button: a popover with a one-column form, one full-width\n * Select per filter with its label above. The button carries a count badge\n * of the filters that are set.\n * - `end`: always in the row, at its end (a count, Export, a view toggle).\n *\n * While any filter is set, a list of chips sits under the row, each reading\n * \"Label: option label\" with its own remove button, plus \"Clear all\".\n *\n * The bar holds NO filter state. Every value and every change belongs to the\n * caller: removing a chip hands the filter's `emptyValue` back to its\n * `onChange`; Clear all does that for each set filter, or calls\n * `onClearAll` when the caller resets its filters in one step.\n *\n * Accessibility comes from the parts: the popover is a dialog named by its\n * trigger, the trigger carries `aria-expanded`, focus moves into the popover\n * and is contained there, Escape closes it and focus returns to the trigger.\n */\n\nexport const filterBarVariants = cva([\"flex flex-col gap-2 box-border font-sans\"]);\n\nexport const filterBarRowVariants = cva([\"flex flex-wrap items-center gap-2\"]);\n\nexport const filterBarChipVariants = cva([\n \"inline-flex items-center gap-1 rounded-full\",\n \"border-(length:--border-width) border-border bg-muted\",\n \"ps-3 pe-1 text-xs leading-(--leading-snug) text-foreground\",\n \"box-border font-sans\",\n]);\n\n/** One option of a dropdown filter. */\nexport interface FilterBarOption {\n /** The option's value, handed to `onChange`. */\n id: Key;\n /** The option's text: in the list, on the trigger and on the chip. */\n label: string;\n}\n\n/** A dropdown filter, rendered as a Select in the popover. */\nexport interface FilterBarSelectField {\n /** Stable identity, used as the React key. */\n id: string;\n /** The field's name: the label above the dropdown and the start of its chip. */\n label: string;\n /** The current value. `null` reads as not set. */\n value: Key | null;\n /** The value that means \"not filtered\" (the \"All\" option's id). */\n emptyValue: Key;\n /** The options, the \"All\" option included. */\n options: readonly FilterBarOption[];\n /** Told the chosen option's id, or `emptyValue` when the chip is removed. */\n onChange: (value: Key) => void;\n}\n\n/**\n * A filter that is not a plain dropdown (a date range, a searchable picker):\n * the caller renders the control and says what its chip reads.\n */\nexport interface FilterBarCustomField {\n /** Stable identity, used as the React key. */\n id: string;\n /** The start of its chip. The control rendered by `render` names itself. */\n label: string;\n /** The control, rendered in the popover. */\n render: () => ReactNode;\n /** The chip's value text while the filter is set, or `null` while it is not. */\n activeLabel: string | null;\n /** Unsets the filter: the chip's remove button and Clear all call it. */\n onClear: () => void;\n}\n\nexport type FilterBarField = FilterBarSelectField | FilterBarCustomField;\n\nexport interface FilterBarProps {\n /** Always in the row, at its start: status tabs and the search box. */\n inline?: ReactNode;\n /** Always in the row, at its end: a count, Export, a view toggle. */\n end?: ReactNode;\n /** The filters behind the Filters button. With none, no button renders. */\n filters: readonly FilterBarField[];\n /** Resets every filter in one step. Without it, each set filter is handed its `emptyValue`. */\n onClearAll?: () => void;\n /**\n * The button's text, and the popover's name.\n *\n * @default \"Filters\"\n */\n buttonLabel?: string;\n /**\n * The text of both Clear all buttons.\n *\n * @default \"Clear all\"\n */\n clearAllLabel?: string;\n /**\n * The text of the button that closes the popover.\n *\n * @default \"Done\"\n */\n doneLabel?: string;\n /**\n * The accessible name of the list of chips.\n *\n * @default \"Filters set\"\n */\n chipsLabel?: string;\n /**\n * The accessible name of a chip's remove button, given the chip's text.\n *\n * @default (text) => `Remove filter ${text}`\n */\n removeLabel?: (chipText: string) => string;\n /** Extra classes on the root. Merged last, so they win conflicts with ours. */\n className?: string;\n}\n\nconst isCustom = (f: FilterBarField): f is FilterBarCustomField => \"render\" in f;\n\ninterface Chip {\n id: string;\n text: string;\n clear: () => void;\n}\n\n/** The set filters, each with its chip text and how to unset it. */\nfunction chipsFor(filters: readonly FilterBarField[]): Chip[] {\n const chips: Chip[] = [];\n for (const f of filters) {\n if (isCustom(f)) {\n if (f.activeLabel != null) chips.push({ id: f.id, text: `${f.label}: ${f.activeLabel}`, clear: f.onClear });\n continue;\n }\n if (f.value == null || f.value === f.emptyValue) continue;\n const option = f.options.find((o) => o.id === f.value);\n chips.push({\n id: f.id,\n text: `${f.label}: ${option ? option.label : String(f.value)}`,\n clear: () => f.onChange(f.emptyValue),\n });\n }\n return chips;\n}\n\n/** A funnel, drawn inline: this package ships no icon dependency. */\nfunction FunnelGlyph() {\n return (\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" aria-hidden=\"true\">\n <path d=\"M2 3h12M4.5 8h7M7 13h2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nfunction CrossGlyph() {\n return (\n <svg viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.5\" aria-hidden=\"true\">\n <path d=\"M4 4l8 8M12 4l-8 8\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\n/**\n * A list toolbar with its dropdown filters behind one Filters button.\n *\n * @example\n * <FilterBar\n * inline={<SearchField aria-label=\"Search\" />}\n * end={<Button>Export</Button>}\n * filters={[{ id: \"region\", label: \"Region\", value, emptyValue: \"all\", onChange: setValue,\n * options: [{ id: \"all\", label: \"All regions\" }, { id: \"nsw\", label: \"NSW\" }] }]}\n * />\n */\n/**\n * One place in the chip row, for a chip or for Clear all. A slot added after the\n * first render opens from nothing while its content fades up and scales in, so the\n * chips beside it glide over; one that is removed stays, shrinking and collapsing,\n * until its exit ends. Nothing animates at first render.\n */\nfunction Slot({\n leaving,\n ready,\n onDone,\n id,\n children,\n}: {\n leaving: boolean;\n ready: boolean;\n onDone: (id: string) => void;\n id: string;\n children: ReactNode;\n}) {\n // Decided once, at this slot's own mount.\n const [fresh] = useState(ready);\n const remove = useCallback(() => onDone(id), [onDone, id]);\n useExitBackstop(leaving, remove, 900);\n // Reduced motion removes it at once: an animation that is switched off never ends.\n useIsomorphicLayoutEffect(() => {\n if (leaving && prefersReducedMotion()) remove();\n }, [leaving, remove]);\n return (\n <li\n data-slot={leaving ? \"filter-bar-leaving\" : undefined}\n aria-hidden={leaving || undefined}\n ref={(node) => {\n if (!node) return;\n if (leaving) node.setAttribute(\"inert\", \"\");\n else node.removeAttribute(\"inert\");\n }}\n onAnimationEnd={(event) => {\n if (leaving && event.target === event.currentTarget && event.animationName === \"chip-slot-out\")\n remove();\n }}\n className={cnAll(\n \"min-w-0 flex-none [interpolate-size:allow-keywords]\",\n leaving\n ? \"pointer-events-none motion-safe:animate-chip-out\"\n : fresh && \"motion-safe:animate-chip-in motion-reduce:animate-fade-in\",\n )}\n >\n {children}\n </li>\n );\n}\n\n/** A chip's text: a changed value swaps (the new text rises in) and the chip's width springs to it. */\nfunction ChipText({ text }: { text: string }) {\n const content = useRef<HTMLSpanElement>(null);\n useMorphWidth(content, text);\n return (\n <span className=\"button-slot\">\n <span ref={content} className=\"inline-flex flex-none items-center\">\n <SwapText swapKey={text} className=\"inline-block\">\n {text}\n </SwapText>\n </span>\n </span>\n );\n}\n\nexport const FilterBar = forwardRef<HTMLDivElement, FilterBarProps>(function FilterBar(\n {\n inline,\n end,\n filters,\n onClearAll,\n buttonLabel = \"Filters\",\n clearAllLabel = \"Clear all\",\n doneLabel = \"Done\",\n chipsLabel = \"Filters set\",\n removeLabel = (text) => `Remove filter ${text}`,\n className,\n },\n ref,\n) {\n const [open, setOpen] = useState(false);\n const chips = chipsFor(filters);\n const [ready, setReady] = useState(false);\n useEffect(() => {\n // A frame after mount: chips added from then on arrive animated, the first ones do not.\n const frame = requestAnimationFrame(() => setReady(true));\n return () => cancelAnimationFrame(frame);\n }, []);\n // The chips, with Clear all as the row's last place, each kept on screen while it leaves.\n const places = useLeavingList([\n ...chips.map((chip) => ({ id: chip.id, chip })),\n ...(chips.length > 0 ? [{ id: \"\\u0000clear\", chip: null }] : []),\n ]);\n const frame = useRef<HTMLDivElement>(null);\n const row = useRef<HTMLUListElement>(null);\n // The row follows its height when a chip makes a line wrap or unwrap.\n useHeightFollow(frame, row, chips.map((chip) => chip.id).join());\n const clearAll = () => {\n if (onClearAll) onClearAll();\n else for (const c of chips) c.clear();\n };\n\n return (\n <div ref={ref} data-slot=\"filter-bar\" className={cn(filterBarVariants(), className)}>\n <div data-slot=\"filter-bar-row\" className={filterBarRowVariants()}>\n {inline}\n {filters.length > 0 ? (\n <PopoverTrigger isOpen={open} onOpenChange={setOpen}>\n <Button variant=\"outlineNeutral\" size=\"sm\" startIcon={<FunnelGlyph />} data-slot=\"filter-bar-button\">\n {buttonLabel}\n {chips.length > 0 ? (\n <Badge tone=\"primary\" appearance=\"solid\" size=\"sm\" shape=\"pill\" data-slot=\"filter-bar-count\">\n {chips.length}\n </Badge>\n ) : null}\n </Button>\n <Popover placement=\"bottom start\" className=\"w-80 max-w-[calc(100vw-2rem)]\">\n <div data-slot=\"filter-bar-panel\" className=\"flex flex-col gap-3\">\n <p className=\"m-0 text-sm font-semibold\">{buttonLabel}</p>\n {filters.map((f) =>\n isCustom(f) ? (\n <div key={f.id}>{f.render()}</div>\n ) : (\n <Select\n key={f.id}\n label={f.label}\n size=\"sm\"\n selectedKey={f.value}\n onSelectionChange={(key) => {\n if (key != null) f.onChange(key);\n }}\n >\n {f.options.map((o) => (\n <SelectItem key={o.id} id={o.id} textValue={o.label}>\n {o.label}\n </SelectItem>\n ))}\n </Select>\n ),\n )}\n <div className=\"flex items-center justify-between gap-2 pt-1\">\n <Button variant=\"ghost\" size=\"sm\" onPress={clearAll} isDisabled={chips.length === 0}>\n {clearAllLabel}\n </Button>\n <Button variant=\"primary\" size=\"sm\" onPress={() => setOpen(false)}>\n {doneLabel}\n </Button>\n </div>\n </div>\n </Popover>\n </PopoverTrigger>\n ) : null}\n {end ? <div className=\"ms-auto flex flex-wrap items-center gap-2\">{end}</div> : null}\n </div>\n {places.list.length > 0 ? (\n <div ref={frame} data-slot=\"filter-bar-chips-frame\" className=\"height-follow\">\n <ul\n ref={row}\n aria-label={chipsLabel}\n data-slot=\"filter-bar-chips\"\n className=\"m-0 flex list-none flex-wrap items-center gap-2 p-0\"\n >\n {places.list.map(({ item, leaving }) =>\n item.chip ? (\n <Slot key={item.id} id={item.id} leaving={leaving} ready={ready} onDone={places.done}>\n <span data-slot=\"filter-bar-chip\" className={filterBarChipVariants()}>\n <ChipText text={item.chip.text} />\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label={removeLabel(item.chip.text)}\n onPress={item.chip.clear}\n className=\"h-6 px-1\"\n >\n <CrossGlyph />\n </Button>\n </span>\n </Slot>\n ) : (\n <Slot key={item.id} id={item.id} leaving={leaving} ready={ready} onDone={places.done}>\n <Button variant=\"link\" size=\"sm\" onPress={clearAll}>\n {clearAllLabel}\n </Button>\n </Slot>\n ),\n )}\n </ul>\n </div>\n ) : null}\n </div>\n );\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { FilterBar, FilterBarCustomField, FilterBarField, FilterBarOption, FilterBarProps, FilterBarSelectField, filterBarChipVariants, filterBarRowVariants, filterBarVariants } from "./filter-bar.js";
|
|
2
|
+
export { FilterBar, type FilterBarCustomField, type FilterBarField, type FilterBarOption, type FilterBarProps, type FilterBarSelectField, filterBarChipVariants, filterBarRowVariants, filterBarVariants };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
//#region src/floating-button-group/floating-button-group.d.ts
|
|
3
|
+
export type FloatingButtonGroupVariant = "muted" | "floating";
|
|
4
|
+
export type FloatingButtonGroupSize = "sm" | "md";
|
|
5
|
+
export type FloatingButtonGroupOrientation = "horizontal" | "vertical";
|
|
6
|
+
export interface FloatingButtonGroupAction {
|
|
7
|
+
type?: "action";
|
|
8
|
+
/** Stable key, also passed to onAction. */
|
|
9
|
+
id: string;
|
|
10
|
+
/** Visible label, and the accessible name when the item shows only its icon. */
|
|
11
|
+
label: string;
|
|
12
|
+
/** An icon before the label. Mark it `aria-hidden`. */
|
|
13
|
+
icon?: ReactNode;
|
|
14
|
+
/** Shows only the icon. The label moves into a tooltip and the accessible name. Overrides the group's iconOnly. */
|
|
15
|
+
iconOnly?: boolean;
|
|
16
|
+
onSelect?: () => void;
|
|
17
|
+
isDisabled?: boolean;
|
|
18
|
+
/** Marks an action that switches a mode on, such as Present. Sets aria-pressed and keeps a quiet tint while on. */
|
|
19
|
+
isPressed?: boolean;
|
|
20
|
+
/** A shortcut hint shown in the tooltip, such as "⌘Z". The component does not bind the key. */
|
|
21
|
+
shortcut?: string;
|
|
22
|
+
/** Other labels this item can switch to, such as ["Copied"] for Share. The button keeps the width of the widest, so a label change never moves anything. */
|
|
23
|
+
reserveLabels?: readonly string[];
|
|
24
|
+
}
|
|
25
|
+
export interface FloatingButtonGroupSeparator {
|
|
26
|
+
type: "separator";
|
|
27
|
+
id?: string;
|
|
28
|
+
}
|
|
29
|
+
export type FloatingButtonGroupItem = FloatingButtonGroupAction | FloatingButtonGroupSeparator;
|
|
30
|
+
export interface FloatingButtonGroupProps {
|
|
31
|
+
items: readonly FloatingButtonGroupItem[];
|
|
32
|
+
/** Accessible name of the toolbar, such as "Board actions". */
|
|
33
|
+
label: string;
|
|
34
|
+
/** `muted` sits quietly on a page; `floating` raises the tray with the floating shadow for overlays such as a selection toolbar. @default "muted" */
|
|
35
|
+
variant?: FloatingButtonGroupVariant;
|
|
36
|
+
/** @default "md" */
|
|
37
|
+
size?: FloatingButtonGroupSize;
|
|
38
|
+
/** @default "horizontal" */
|
|
39
|
+
orientation?: FloatingButtonGroupOrientation;
|
|
40
|
+
/** Shows every item as an icon only, with its label in a tooltip. Items with their own iconOnly win. */
|
|
41
|
+
iconOnly?: boolean;
|
|
42
|
+
/** Side of the item tooltips. Defaults to top for a row and right for a column. */
|
|
43
|
+
tooltipSide?: "top" | "bottom" | "left" | "right";
|
|
44
|
+
/** Called with the item id after the item's own onSelect. */
|
|
45
|
+
onAction?: (id: string) => void;
|
|
46
|
+
/** Extra classes. Merged last, so they win conflicts with ours. */
|
|
47
|
+
className?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Separate soft buttons in a quiet tray. One shared highlight morphs, in
|
|
51
|
+
* position and size, to whichever button the pointer or keyboard focus is on,
|
|
52
|
+
* fades when the pointer leaves the tray, and settles darker in place while a
|
|
53
|
+
* button is pressed. It is the toolbar's main hover and focus indicator. Arrow
|
|
54
|
+
* keys move focus, Home and End jump to the ends, Enter and Space act.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* <FloatingButtonGroup label="Board actions" items={[{ id: "undo", label: "Undo", icon: <UndoIcon aria-hidden />, iconOnly: true, shortcut: "⌘Z" }]} />
|
|
58
|
+
*/
|
|
59
|
+
export declare function FloatingButtonGroup({ items, label, variant, size, orientation, iconOnly: groupIconOnly, tooltipSide, onAction, className }: FloatingButtonGroupProps): import("react").JSX.Element;
|
|
60
|
+
//#endregion
|
|
61
|
+
//# sourceMappingURL=floating-button-group.d.ts.map
|