@flood-md/react 0.2.10 → 0.2.12
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 +275 -5
- package/dist/app-shell.d.ts +3 -0
- package/dist/app-shell.js +66 -0
- package/dist/bulk-action-bar.d.ts +3 -0
- package/dist/bulk-action-bar.js +17 -0
- package/dist/collection-toolbar.d.ts +3 -0
- package/dist/collection-toolbar.js +26 -0
- package/dist/collection-view-switcher.d.ts +3 -0
- package/dist/collection-view-switcher.js +19 -0
- package/dist/combobox.d.ts +6 -1
- package/dist/combobox.js +77 -29
- package/dist/command-list.d.ts +5 -1
- package/dist/command-list.js +2 -2
- package/dist/data-display.js +28 -4
- package/dist/data-table-columns.d.ts +25 -0
- package/dist/data-table-columns.js +271 -0
- package/dist/data-table-expansion.d.ts +21 -0
- package/dist/data-table-expansion.js +79 -0
- package/dist/data-table.js +140 -12
- package/dist/date-picker.js +2 -2
- package/dist/date-range-picker.js +2 -2
- package/dist/date-time-picker.js +2 -2
- package/dist/date-time-range-picker.js +2 -2
- package/dist/disclosure.d.ts +2 -1
- package/dist/disclosure.js +4 -4
- package/dist/editable.js +57 -18
- package/dist/filter-condition.d.ts +3 -0
- package/dist/filter-condition.js +21 -0
- package/dist/filter-group.d.ts +2 -0
- package/dist/filter-group.js +62 -0
- package/dist/foundations.css +1131 -93
- package/dist/index.d.ts +469 -5
- package/dist/index.js +72 -9
- package/dist/menu.js +5 -4
- package/dist/menubar.d.ts +2 -0
- package/dist/menubar.js +85 -0
- package/dist/navigation-group.d.ts +3 -0
- package/dist/navigation-group.js +13 -0
- package/dist/navigation-item.d.ts +3 -0
- package/dist/navigation-item.js +68 -0
- package/dist/navigation-layout.d.ts +2 -1
- package/dist/navigation-layout.js +12 -4
- package/dist/navigation-tree.js +51 -7
- package/dist/navigation.js +2 -2
- package/dist/overflow-actions.d.ts +2 -0
- package/dist/overflow-actions.js +75 -0
- package/dist/overlay-runtime.d.ts +6 -2
- package/dist/overlay-runtime.js +41 -5
- package/dist/overlays.d.ts +1 -0
- package/dist/overlays.js +34 -18
- package/dist/select.js +4 -1
- package/dist/sidebar.d.ts +2 -0
- package/dist/sidebar.js +58 -0
- package/dist/sparkline.d.ts +2 -0
- package/dist/sparkline.js +65 -0
- package/dist/toolbar.js +2 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { forwardRef, createElement, useId, useState, } from "react";
|
|
3
|
+
import { forwardRef, createElement, useId, useRef, useState, } from "react";
|
|
4
4
|
import { useFocusableHidden } from "./focusable-hidden.js";
|
|
5
|
+
import { PredicateRow } from "./filter-condition.js";
|
|
6
|
+
import { PredicateGroup } from "./filter-group.js";
|
|
7
|
+
import { CollectionQueryBar } from "./collection-toolbar.js";
|
|
8
|
+
import { CollectionViewSelector } from "./collection-view-switcher.js";
|
|
9
|
+
import { WorkspaceSidebar } from "./sidebar.js";
|
|
10
|
+
import { NavigationRow } from "./navigation-item.js";
|
|
11
|
+
import { NavigationSection } from "./navigation-group.js";
|
|
5
12
|
import { resolveFieldStatus, hasFieldContent, mergeDescriptions } from "./field-state.js";
|
|
6
13
|
import { SingleSelect } from "./select.js";
|
|
7
14
|
import { MixedCheckbox } from "./checkbox.js";
|
|
@@ -18,7 +25,8 @@ import { RovingToolbar } from "./toolbar.js";
|
|
|
18
25
|
import { NumericStepper } from "./numeric-input.js";
|
|
19
26
|
import { RangeControl } from "./slider.js";
|
|
20
27
|
import { GroupedAvatars, NamedStatus, CaptionedFigure, AttributedQuote, InlineCodeText, MeasuredValue, EventTimeline } from "./content-elements.js";
|
|
21
|
-
import { NavigationMenu, StepSequence, ContentSection, SplitLayout, CenterLayout, SkipNavigation } from "./navigation-layout.js";
|
|
28
|
+
import { NavigationMenu, StepSequence, ContentSection, PageHeading, SplitLayout, CenterLayout, SkipNavigation } from "./navigation-layout.js";
|
|
29
|
+
import { ApplicationShell, ApplicationTopBar } from "./app-shell.js";
|
|
22
30
|
import { CollectionListBox, SegmentedPinInput, StarRating, FileDropzone, SupportingCharacterCount } from "./form-controls.js";
|
|
23
31
|
import { ClipboardAction, NotificationRegion } from "./feedback-actions.js";
|
|
24
32
|
import { ConfirmationDialog } from "./alert-dialog.js";
|
|
@@ -43,12 +51,30 @@ import { ClockTimePicker } from "./time-picker.js";
|
|
|
43
51
|
import { CivilDateTimeRangePicker } from "./date-time-range-picker.js";
|
|
44
52
|
import { FileRecord, UploadRecord, ModalImagePreview, FileMetadata } from "./file-records.js";
|
|
45
53
|
import { ManagedDataTable } from "./data-table.js";
|
|
54
|
+
import { TrendPlot } from "./sparkline.js";
|
|
46
55
|
import { CheckableCard, ExclusiveCard } from "./collection-cards.js";
|
|
47
56
|
import { ColorPreview, ColorEditor } from "./color-controls.js";
|
|
48
57
|
import { HoverPreview } from "./hover-card.js";
|
|
49
58
|
import { HierarchicalSelect } from "./tree-select.js";
|
|
50
59
|
import { CivilDateTimePicker } from "./date-time-picker.js";
|
|
51
60
|
import { HierarchicalNavigation } from "./navigation-tree.js";
|
|
61
|
+
import { AdaptiveActions } from "./overflow-actions.js";
|
|
62
|
+
import { SelectionActionBar } from "./bulk-action-bar.js";
|
|
63
|
+
import { ApplicationMenubar } from "./menubar.js";
|
|
64
|
+
/** Priority-based overflow composed from Toolbar, Button and Menu. @since 0.2.11 */
|
|
65
|
+
export const OverflowActions = /* @__PURE__ */ forwardRef(function OverflowActions(props, ref) { return _jsx(AdaptiveActions, { ...props, ref: ref }); });
|
|
66
|
+
/** One finite-choice filter predicate; the host owns application and query semantics. @since 0.2.11 */
|
|
67
|
+
export const FilterCondition = /* @__PURE__ */ forwardRef(function FilterCondition(props, ref) { return _jsx(PredicateRow, { ...props, ref: ref }); });
|
|
68
|
+
/** A flat controlled group of finite-choice predicates, without query execution or Apply/Cancel ownership. @since 0.2.11 */
|
|
69
|
+
export const FilterGroup = /* @__PURE__ */ forwardRef(function FilterGroup(props, ref) { return _jsx(PredicateGroup, { ...props, ref: ref }); });
|
|
70
|
+
/** Search, accepted summaries and staged filter disclosure; saved views and query semantics stay host-owned. @since 0.2.11 */
|
|
71
|
+
export const CollectionToolbar = /* @__PURE__ */ forwardRef(function CollectionToolbar(props, ref) { return _jsx(CollectionQueryBar, { ...props, ref: ref }); });
|
|
72
|
+
/** Controlled saved/preset view choice with optional adaptive commands. @since 0.2.11 */
|
|
73
|
+
export const CollectionViewSwitcher = /* @__PURE__ */ forwardRef(function CollectionViewSwitcher(props, ref) { return _jsx(CollectionViewSelector, { ...props, ref: ref }); });
|
|
74
|
+
/** A bounded single-row selection command capsule. The host owns positioning and updates. @since 0.2.11 */
|
|
75
|
+
export const BulkActionBar = /* @__PURE__ */ forwardRef(function BulkActionBar(props, ref) { return _jsx(SelectionActionBar, { ...props, ref: ref }); });
|
|
76
|
+
/** Desktop application commands; destinations use native links instead. @since 0.2.11 */
|
|
77
|
+
export const Menubar = /* @__PURE__ */ forwardRef(function Menubar(props, ref) { return _jsx(ApplicationMenubar, { ...props, ref: ref }); });
|
|
52
78
|
/** @since 0.2.8 */
|
|
53
79
|
export const TimePicker = /* @__PURE__ */ forwardRef(function TimePicker(props, ref) { return _jsx(ClockTimePicker, { ...props, ref: ref }); });
|
|
54
80
|
/** Four atomic civil date/time form values, without timezone conversion. @since 0.2.8 */
|
|
@@ -71,6 +97,10 @@ export const UploadList = /* @__PURE__ */ forwardRef(function UploadList(props,
|
|
|
71
97
|
export const ImagePreview = /* @__PURE__ */ forwardRef(function ImagePreview(props, ref) { return _jsx(ModalImagePreview, { ...props, ref: ref }); });
|
|
72
98
|
/** A client-side table composed from native table, checkbox and pagination. @since 0.2.8 */
|
|
73
99
|
export const DataTable = /* @__PURE__ */ forwardRef(function DataTable(props, ref) { return _jsx(ManagedDataTable, { ...props, ref: ref }); });
|
|
100
|
+
/** @since 0.2.11 */
|
|
101
|
+
export const Sparkline = /* @__PURE__ */ forwardRef(function Sparkline({ showLabel = false, size = "md", tone = "accent", variant = "area", ...props }, ref) {
|
|
102
|
+
return _jsx(TrendPlot, { ...props, showLabel: showLabel, size: size, tone: tone, variant: variant, ref: ref });
|
|
103
|
+
});
|
|
74
104
|
/** A native list; links and actions stay independent. @since 0.2.8 */
|
|
75
105
|
export const DataList = /* @__PURE__ */ forwardRef(function DataList({ density = "comfortable", dividers = true, className, ...props }, ref) {
|
|
76
106
|
return _jsx("ul", { ...props, ref: ref, role: "list", "data-density": density, "data-dividers": dividers, className: classes("flood-data-list", className) });
|
|
@@ -99,10 +129,16 @@ export const DateTimePicker = /* @__PURE__ */ forwardRef(function DateTimePicker
|
|
|
99
129
|
export const Tree = /* @__PURE__ */ forwardRef(function Tree(props, ref) {
|
|
100
130
|
return _jsx(SelectionTree, { ...props, ref: ref });
|
|
101
131
|
});
|
|
132
|
+
/** Shared navigation row geometry and native destination/action behavior. @since 0.2.11 */
|
|
133
|
+
export const NavigationItem = /* @__PURE__ */ forwardRef(function NavigationItem(props, ref) { return _jsx(NavigationRow, { ...props, ref: ref }); });
|
|
134
|
+
/** Related navigation with independently configurable presentation. @since 0.2.11 */
|
|
135
|
+
export const NavigationGroup = /* @__PURE__ */ forwardRef(function NavigationGroup(props, ref) { return _jsx(NavigationSection, { ...props, ref: ref }); });
|
|
102
136
|
/** @since 0.2.7 */
|
|
103
137
|
export const NavigationTree = /* @__PURE__ */ forwardRef(function NavigationTree(props, ref) {
|
|
104
138
|
return _jsx(HierarchicalNavigation, { ...props, ref: ref });
|
|
105
139
|
});
|
|
140
|
+
/** Bounded desktop navigation composed from NavigationTree and ScrollArea. @since 0.2.11 */
|
|
141
|
+
export const Sidebar = /* @__PURE__ */ forwardRef(function Sidebar(props, ref) { return _jsx(WorkspaceSidebar, { ...props, ref: ref }); });
|
|
106
142
|
/** @since 0.2.7 */
|
|
107
143
|
export const ErrorSummary = /* @__PURE__ */ forwardRef(function ErrorSummary({ announcement = "off", autoFocus = false, ...props }, ref) { return _jsx(ValidationErrorSummary, { ...props, ref: ref, announcement: announcement, autoFocus: autoFocus }); });
|
|
108
144
|
/** @since 0.2.7 */
|
|
@@ -128,8 +164,8 @@ export const TagInput = /* @__PURE__ */ forwardRef(function TagInput({ controlSi
|
|
|
128
164
|
/** @since 0.2.7 */
|
|
129
165
|
export const Editable = /* @__PURE__ */ forwardRef(function Editable({ controlSize = "md", blurAction = "commit", showActions = true, ...props }, ref) { return _jsx(InlineEditable, { ...props, ref: ref, controlSize: controlSize, blurAction: blurAction, showActions: showActions }); });
|
|
130
166
|
const classes = (...values) => values.filter(Boolean).join(" ");
|
|
131
|
-
export const Button = /* @__PURE__ */ forwardRef(function Button({ variant = "solid", size = "md", loading = false, disabled, type = "button", className, children, ...props }, ref) {
|
|
132
|
-
return (_jsxs("button", { ...props, ref: ref, type: type, disabled: disabled || loading, "aria-busy": loading || undefined, className: classes("flood-button", `flood-button--${variant}`, `flood-button--${size}`, className), children: [loading && _jsx(Spinner, { decorative: true }), children] }));
|
|
167
|
+
export const Button = /* @__PURE__ */ forwardRef(function Button({ variant = "solid", tone = "default", size = "md", loading = false, disabled, type = "button", className, children, ...props }, ref) {
|
|
168
|
+
return (_jsxs("button", { ...props, ref: ref, type: type, "data-tone": tone === "danger" ? tone : undefined, disabled: disabled || loading, "aria-busy": loading || undefined, className: classes("flood-button", `flood-button--${variant}`, `flood-button--${size}`, className), children: [loading && _jsx(Spinner, { decorative: true }), children] }));
|
|
133
169
|
});
|
|
134
170
|
/** @since 0.2.5 */
|
|
135
171
|
export const Tag = /* @__PURE__ */ forwardRef(function Tag({ size = "md", icon, disabled = false, onRemove, removeLabel, removeButtonProps, className, children, ...props }, ref) {
|
|
@@ -153,8 +189,8 @@ export const DescriptionList = /* @__PURE__ */ forwardRef(function DescriptionLi
|
|
|
153
189
|
return _jsx(DescribedData, { ...props, ref: ref, items: items, layout: layout, density: density, dividers: dividers });
|
|
154
190
|
});
|
|
155
191
|
/** @since 0.2.4 */
|
|
156
|
-
export const Table = /* @__PURE__ */ forwardRef(function Table({ caption, children, hideCaption = false, density = "comfortable", striped = false, scrollLabel, cellVerticalAlign = "middle", ...props }, ref) {
|
|
157
|
-
return _jsx(TabularData, { ...props, ref: ref, caption: caption, hideCaption: hideCaption, density: density, striped: striped, scrollLabel: scrollLabel, cellVerticalAlign: cellVerticalAlign, children: children });
|
|
192
|
+
export const Table = /* @__PURE__ */ forwardRef(function Table({ caption, children, hideCaption = false, density = "comfortable", striped = false, scrollLabel, cellVerticalAlign = "middle", stickyHeader = false, ...props }, ref) {
|
|
193
|
+
return _jsx(TabularData, { ...props, ref: ref, caption: caption, hideCaption: hideCaption, density: density, striped: striped, scrollLabel: scrollLabel, cellVerticalAlign: cellVerticalAlign, stickyHeader: stickyHeader, children: children });
|
|
158
194
|
});
|
|
159
195
|
/** @since 0.2.4 */
|
|
160
196
|
export const Badge = /* @__PURE__ */ forwardRef(function Badge({ size = "md", tone = "neutral", variant = "subtle", className, ...props }, ref) {
|
|
@@ -197,9 +233,24 @@ export const Menu = /* @__PURE__ */ forwardRef(function Menu({ defaultOpen = fal
|
|
|
197
233
|
export const Tooltip = /* @__PURE__ */ forwardRef(function Tooltip({ side = "top", align = "center", delay = 300, disabled = false, ...props }, ref) { return _jsx(AnchoredOverlay, { ...props, ref: ref, kind: "tooltip", side: side, align: align, delay: delay, disabled: disabled }); });
|
|
198
234
|
export const Popover = /* @__PURE__ */ forwardRef(function Popover({ side = "bottom", align = "start", defaultOpen = false, disabled = false, closeLabel = "Close", ...props }, ref) { return _jsx(AnchoredOverlay, { ...props, ref: ref, kind: "popover", side: side, align: align, defaultOpen: defaultOpen, disabled: disabled, closeLabel: closeLabel }); });
|
|
199
235
|
export const Dialog = /* @__PURE__ */ forwardRef(function Dialog({ defaultOpen = false, disabled = false, closeLabel = "Close", closeOnOutsideClick = true, ...props }, ref) { return _jsx(ModalOverlay, { ...props, ref: ref, defaultOpen: defaultOpen, disabled: disabled, closeLabel: closeLabel, closeOnOutsideClick: closeOnOutsideClick }); });
|
|
236
|
+
/** @since 0.2.11 */
|
|
237
|
+
export const CommandPalette = /* @__PURE__ */ forwardRef(function CommandPalette({ searchLabel, items, density = "comfortable", query, defaultQuery, onQueryChange, onAction, loading, placeholder, emptyMessage, loadingMessage, open, defaultOpen = false, onOpenChange, className, ...props }, ref) {
|
|
238
|
+
const input = useRef(null);
|
|
239
|
+
const [localOpen, setLocalOpen] = useState(defaultOpen);
|
|
240
|
+
const requestOpen = (next) => {
|
|
241
|
+
if (open === undefined)
|
|
242
|
+
setLocalOpen(next);
|
|
243
|
+
onOpenChange?.(next);
|
|
244
|
+
};
|
|
245
|
+
return _jsxs(Dialog, { ...props, ref: ref, open: open ?? localOpen, onOpenChange: requestOpen, initialFocusRef: input, className: classes("flood-command-palette", className), children: [_jsx("div", { className: "flood-command-palette__search-icon", children: _jsx(IconSlot, { size: "sm", children: _jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", "aria-hidden": "true", focusable: "false", children: [_jsx("circle", { cx: "10.5", cy: "10.5", r: "5.75" }), _jsx("path", { d: "m15 15 4 4" })] }) }) }), _jsx(SearchCommandList, { ref: input, label: searchLabel, hideLabel: true, integrated: true, items: items, controlSize: density === "compact" ? "sm" : "md", query: query, defaultQuery: defaultQuery, onQueryChange: onQueryChange, loading: loading, placeholder: placeholder, emptyMessage: emptyMessage, loadingMessage: loadingMessage, onAction: id => { requestOpen(false); onAction(id); } })] });
|
|
246
|
+
});
|
|
200
247
|
export const Drawer = /* @__PURE__ */ forwardRef(function Drawer({ side = "end", size = "md", defaultOpen = false, closeLabel = "Close", closeOnOutsideClick = true, className, footer, ...props }, ref) {
|
|
201
248
|
return _jsx(ModalOverlay, { ...props, ref: ref, defaultOpen: defaultOpen, closeLabel: closeLabel, closeOnOutsideClick: closeOnOutsideClick, className: classes("flood-drawer", className), "data-side": side, "data-size": size, scrollBody: true, footer: footer });
|
|
202
249
|
});
|
|
250
|
+
/** A modal bottom sheet for a short task or a list of choices. @since 0.2.12 */
|
|
251
|
+
export const Sheet = /* @__PURE__ */ forwardRef(function Sheet({ className, size = "md", ...props }, ref) {
|
|
252
|
+
return _jsx(ModalOverlay, { ...props, ref: ref, "data-side": "bottom", "data-size": size, className: classes("flood-drawer", "flood-sheet", className), scrollBody: true, bodyContentInset: "none" });
|
|
253
|
+
});
|
|
203
254
|
export const AlertDialog = /* @__PURE__ */ forwardRef(function AlertDialog({ defaultOpen = false, confirmLabel = "Continue", cancelLabel = "Cancel", confirmDisabled = false, ...props }, ref) {
|
|
204
255
|
return _jsx(ConfirmationDialog, { ...props, ref: ref, defaultOpen: defaultOpen, confirmLabel: confirmLabel, cancelLabel: cancelLabel, confirmDisabled: confirmDisabled });
|
|
205
256
|
});
|
|
@@ -304,6 +355,10 @@ export const SearchInput = /* @__PURE__ */ forwardRef(function SearchInput({ cle
|
|
|
304
355
|
export const PasswordInput = /* @__PURE__ */ forwardRef(function PasswordInput({ defaultVisible = false, showPasswordLabel = "Show password", hidePasswordLabel = "Hide password", controlSize = "md", ...props }, ref) {
|
|
305
356
|
return _jsx(PasswordField, { ...props, ref: ref, defaultVisible: defaultVisible, showPasswordLabel: showPasswordLabel, hidePasswordLabel: hidePasswordLabel, controlSize: controlSize, group: InputGroup, action: IconButton, icon: IconSlot });
|
|
306
357
|
});
|
|
358
|
+
/** A free text field with suggestions; FormData contains text rather than an option ID. @since 0.2.11 */
|
|
359
|
+
export const Autocomplete = /* @__PURE__ */ forwardRef(function Autocomplete({ value, defaultValue = "", onValueChange, onOptionSelect, ...props }, ref) {
|
|
360
|
+
return _jsx(SearchSelection, { ...props, ref: ref, freeText: true, textValue: value, initialText: defaultValue, onTextChange: onValueChange, onOptionSelect: onOptionSelect, initialValues: [] });
|
|
361
|
+
});
|
|
307
362
|
/** @since 0.2.5 */
|
|
308
363
|
export const Combobox = /* @__PURE__ */ forwardRef(function Combobox({ value, defaultValue = "", onValueChange, clearable = false, emptyMessage = "No results found.", listLabel = "Options", toggleLabel = "Show options", clearLabel = "Clear selection", invalidSelectionMessage = "Select an option.", controlSize = "md", ...props }, ref) {
|
|
309
364
|
return _jsx(SearchSelection, { ...props, ref: ref, multiple: false, selectedValues: value === undefined ? undefined : value ? [value] : [], initialValues: defaultValue ? [defaultValue] : [], onSelectionChange: next => onValueChange?.(next[0] ?? ""), clearable: clearable, emptyMessage: emptyMessage, listLabel: listLabel, toggleLabel: toggleLabel, clearLabel: clearLabel, invalidSelectionMessage: invalidSelectionMessage, controlSize: controlSize });
|
|
@@ -360,7 +415,9 @@ export const RadioGroup = /* @__PURE__ */ forwardRef(function RadioGroup({ value
|
|
|
360
415
|
export const SegmentedControl = /* @__PURE__ */ forwardRef(function SegmentedControl({ label, options, controlSize = "md", iconOnly = false, fullWidth = false, orientation = "horizontal", className, onKeyDown, ...props }, ref) {
|
|
361
416
|
if (iconOnly && options.some(option => !option.icon))
|
|
362
417
|
throw new Error("Flood icon-only segments require icons");
|
|
363
|
-
return _jsx(RadioGroup, { ...props, ref: ref, legend: label, orientation: orientation, className: classes("flood-segmented", `flood-control--${controlSize}`, iconOnly && "flood-segmented--icons", fullWidth && "flood-segmented--full", className), options: options.map(option => ({ ...option, label: _jsxs(_Fragment, { children: [option.icon && _jsx(IconSlot, { size: controlSize, children: option.icon }), iconOnly ? _jsx("span", { className: "flood-segmented__name", children: option.label })
|
|
418
|
+
return _jsx(RadioGroup, { ...props, ref: ref, legend: label, orientation: orientation, className: classes("flood-segmented", `flood-control--${controlSize}`, iconOnly && "flood-segmented--icons", fullWidth && "flood-segmented--full", className), options: options.map(option => ({ ...option, label: _jsxs(_Fragment, { children: [option.icon && _jsx(IconSlot, { size: controlSize, children: option.icon }), iconOnly ? _jsx("span", { className: "flood-segmented__name", children: option.label })
|
|
419
|
+
: option.count == null || option.count === "" ? option.label
|
|
420
|
+
: _jsxs("span", { className: "flood-segmented__counted-label", children: [option.label, " ", _jsx("span", { className: "flood-segmented__count", children: option.count })] })] }) })), onKeyDown: event => {
|
|
364
421
|
onKeyDown?.(event);
|
|
365
422
|
if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.nativeEvent.isComposing)
|
|
366
423
|
return;
|
|
@@ -476,8 +533,8 @@ export const Card = /* @__PURE__ */ forwardRef(function Card({ title, descriptio
|
|
|
476
533
|
export const IconSlot = /* @__PURE__ */ forwardRef(function IconSlot({ size = "md", label, className, children, ...props }, ref) {
|
|
477
534
|
return _jsx("span", { ...props, ref: ref, role: label ? "img" : undefined, "aria-label": label, "aria-hidden": label ? undefined : true, className: classes("flood-icon", `flood-icon--${size}`, className), children: children });
|
|
478
535
|
});
|
|
479
|
-
export const IconButton = /* @__PURE__ */ forwardRef(function IconButton({ label, size = "md", variant = "subtle", className, children, ...props }, ref) {
|
|
480
|
-
return _jsx(Button, { ...props, ref: ref, size: size, variant: variant, "aria-label": label, className: classes("flood-icon-button", className), children: _jsx(IconSlot, { size:
|
|
536
|
+
export const IconButton = /* @__PURE__ */ forwardRef(function IconButton({ label, size = "md", iconSize = size, variant = "subtle", className, children, ...props }, ref) {
|
|
537
|
+
return _jsx(Button, { ...props, ref: ref, size: size, variant: variant, "aria-label": label, className: classes("flood-icon-button", className), children: _jsx(IconSlot, { size: iconSize, children: children }) });
|
|
481
538
|
});
|
|
482
539
|
export const Divider = /* @__PURE__ */ forwardRef(function Divider({ className, ...props }, ref) {
|
|
483
540
|
return _jsx("hr", { ...props, ref: ref, className: classes("flood-divider", className) });
|
|
@@ -510,6 +567,12 @@ export const Timeline = /* @__PURE__ */ forwardRef(function Timeline(props, ref)
|
|
|
510
567
|
export const NavigationList = /* @__PURE__ */ forwardRef(function NavigationList({ size = "md", ...props }, ref) { return _jsx(NavigationMenu, { ...props, ref: ref, size: size }); });
|
|
511
568
|
export const Steps = /* @__PURE__ */ forwardRef(function Steps({ orientation = "horizontal", ...props }, ref) { return _jsx(StepSequence, { ...props, ref: ref, orientation: orientation }); });
|
|
512
569
|
export const Section = /* @__PURE__ */ forwardRef(function Section({ headingLevel = 2, headingSize = "section", ...props }, ref) { return _jsx(ContentSection, { ...props, ref: ref, headingLevel: headingLevel, headingSize: headingSize }); });
|
|
570
|
+
/** The primary heading and associated actions inside a page's main region. @since 0.2.11 */
|
|
571
|
+
export const PageHeader = /* @__PURE__ */ forwardRef(function PageHeader({ headingSize = "large", headingLevel = 1, ...props }, ref) { return _jsx(PageHeading, { ...props, ref: ref, headingSize: headingSize, headingLevel: headingLevel }); });
|
|
572
|
+
/** Persistent application chrome with independent context and action slots. @since 0.2.11 */
|
|
573
|
+
export const AppTopBar = /* @__PURE__ */ forwardRef(function AppTopBar({ bordered = false, ...props }, ref) { return _jsx(ApplicationTopBar, { ...props, ref: ref, bordered: bordered }); });
|
|
574
|
+
/** Composes application navigation and a main landmark with optional bounded scrolling. @since 0.2.11 */
|
|
575
|
+
export const AppShell = /* @__PURE__ */ forwardRef(function AppShell({ navigationSide = "start", scroll = "content", mainAs = "main", ...props }, ref) { return _jsx(ApplicationShell, { ...props, ref: ref, navigationSide: navigationSide, scroll: scroll, mainAs: mainAs }); });
|
|
513
576
|
export const Split = /* @__PURE__ */ forwardRef(function Split({ side = "end", ratio = "main", collapseAt = "md", gap = "6", ...props }, ref) { return _jsx(SplitLayout, { ...props, ref: ref, side: side, ratio: ratio, collapseAt: collapseAt, gap: gap }); });
|
|
514
577
|
export const Center = /* @__PURE__ */ forwardRef(function Center({ inline = false, ...props }, ref) { return _jsx(CenterLayout, { ...props, ref: ref, inline: inline }); });
|
|
515
578
|
export const SkipLink = /* @__PURE__ */ forwardRef(function SkipLink({ children = "Skip to content", ...props }, ref) { return _jsx(SkipNavigation, { ...props, ref: ref, children: children }); });
|
package/dist/menu.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Fragment, forwardRef, useCallback, useEffect, useId, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
|
|
3
3
|
import { Button, Kbd, ScrollArea } from "./index.js";
|
|
4
|
-
import { positionLayer, registerLayer, returnFocus, tabbables } from "./overlay-runtime.js";
|
|
4
|
+
import { positionLayer, registerLayer, returnFocus, tabbables, useLayerExitContent } from "./overlay-runtime.js";
|
|
5
5
|
const useBrowserLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
6
6
|
/** Validate each level while retaining globally unique action IDs. */
|
|
7
7
|
export function validateMenuTree(items) {
|
|
@@ -171,6 +171,7 @@ export const MenuLayer = /* @__PURE__ */ forwardRef(function MenuLayerRender({ l
|
|
|
171
171
|
element.hidePopover();
|
|
172
172
|
};
|
|
173
173
|
}, [open, side, align, nested]);
|
|
174
|
+
const showContent = useLayerExitContent(panel, open);
|
|
174
175
|
useBrowserLayoutEffect(() => {
|
|
175
176
|
if (openChild && !items.some(item => item.id === openChild && item.type === "submenu" && !item.disabled))
|
|
176
177
|
setOpenChild(undefined);
|
|
@@ -211,7 +212,7 @@ export const MenuLayer = /* @__PURE__ */ forwardRef(function MenuLayerRender({ l
|
|
|
211
212
|
if (item.type === "separator")
|
|
212
213
|
return _jsx("div", { role: "separator", className: "flood-menu__separator" }, item.id);
|
|
213
214
|
const submenu = item.type === "submenu", childId = `${id}-submenu-${encodeURIComponent(item.id)}`;
|
|
214
|
-
return _jsxs(Fragment, { children: [_jsxs(Button, { ref: anchorRef(item.id), role: item.type === "checkbox" ? "menuitemcheckbox" : item.type === "radio" ? "menuitemradio" : "menuitem", "aria-checked": item.type === "checkbox" || item.type === "radio" ? item.checked : undefined, "aria-haspopup": submenu ? "menu" : undefined, "aria-expanded": submenu ? openChild === item.id && !item.disabled : undefined, "aria-controls": submenu ? childId : undefined, tabIndex: -1, variant: "ghost", size: controlSize, "aria-label": item.label, "aria-disabled": item.disabled || undefined, "data-label": item.label, "data-menu-id": item.id,
|
|
215
|
+
return _jsxs(Fragment, { children: [_jsxs(Button, { ref: anchorRef(item.id), role: item.type === "checkbox" ? "menuitemcheckbox" : item.type === "radio" ? "menuitemradio" : "menuitem", "aria-checked": item.type === "checkbox" || item.type === "radio" ? item.checked : undefined, "aria-haspopup": submenu ? "menu" : undefined, "aria-expanded": submenu ? openChild === item.id && !item.disabled : undefined, "aria-controls": submenu ? childId : undefined, tabIndex: -1, variant: "ghost", size: controlSize, "aria-label": item.label, "aria-disabled": item.disabled || undefined, "data-label": item.label, "data-menu-id": item.id, tone: "tone" in item ? item.tone : undefined, "data-submenu": submenu || undefined, className: "flood-menu__item", onPointerDown: event => { pointerType.current = event.pointerType; }, onPointerEnter: event => { if (event.pointerType === "mouse")
|
|
215
216
|
scheduleHover(item, event.currentTarget); }, onPointerLeave: () => clearHover(), onPointerMove: event => {
|
|
216
217
|
if (event.pointerType === "touch" || openChild)
|
|
217
218
|
return;
|
|
@@ -262,7 +263,7 @@ export const MenuLayer = /* @__PURE__ */ forwardRef(function MenuLayerRender({ l
|
|
|
262
263
|
group.push(items[++index]);
|
|
263
264
|
rows.push(_jsxs("div", { role: "group", "aria-label": item.group, children: [_jsx("div", { className: "flood-menu__group-label", "aria-hidden": "true", children: item.group }), group.map(renderItem)] }, `radio-${item.id}`));
|
|
264
265
|
}
|
|
265
|
-
return _jsx("div", { ...props, ref: panel, id: id, popover: "manual", role: "menu", "aria-label": label, "aria-orientation": "vertical", tabIndex: -1, className: ["flood-overlay-panel", "flood-menu", nested && "flood-menu--submenu", className].filter(Boolean).join(" "), onKeyDown: event => {
|
|
266
|
+
return _jsx("div", { ...props, ref: panel, id: id, popover: "manual", role: "menu", "aria-label": label, "aria-orientation": "vertical", "aria-hidden": !open || undefined, tabIndex: -1, className: ["flood-overlay-panel", "flood-menu", nested && "flood-menu--submenu", className].filter(Boolean).join(" "), onKeyDown: event => {
|
|
266
267
|
if (event.target.closest('[role="menu"]') !== panel.current)
|
|
267
268
|
return;
|
|
268
269
|
onKeyDown?.(event);
|
|
@@ -325,7 +326,7 @@ export const MenuLayer = /* @__PURE__ */ forwardRef(function MenuLayerRender({ l
|
|
|
325
326
|
all[next].focus({ preventScroll: true });
|
|
326
327
|
all[next].scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
327
328
|
}
|
|
328
|
-
}, children:
|
|
329
|
+
}, children: showContent && _jsx(ScrollArea, { orientation: "vertical", role: "group", tabIndex: -1, className: "flood-menu__viewport", children: rows }) });
|
|
329
330
|
});
|
|
330
331
|
export const ActionMenu = /* @__PURE__ */ forwardRef(function ActionMenu({ label, trigger, items, onAction, open: controlled, defaultOpen, onOpenChange, disabled, side = "bottom", align = "start", controlSize = "sm", ...props }, forwardedRef) {
|
|
331
332
|
if (!label.trim())
|
package/dist/menubar.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
|
|
3
|
+
import { Button, Menu } from "./index.js";
|
|
4
|
+
import { tabbables } from "./overlay-runtime.js";
|
|
5
|
+
const useBrowserLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
6
|
+
export const ApplicationMenubar = /* @__PURE__ */ forwardRef(function ApplicationMenubar({ label, menus, openValue, defaultOpenValue = null, onOpenValueChange, onAction, controlSize = "sm", disabled = false, className, onKeyDown, onKeyDownCapture, ...props }, ref) {
|
|
7
|
+
if (!label.trim() || menus.some(menu => !menu.id.trim() || !menu.label.trim()) || new Set(menus.map(menu => menu.id)).size !== menus.length)
|
|
8
|
+
throw new Error("Flood Menubar requires unique named menus");
|
|
9
|
+
const root = useRef(null);
|
|
10
|
+
useImperativeHandle(ref, () => root.current, []);
|
|
11
|
+
const [local, setLocal] = useState(defaultOpenValue), [active, setActive] = useState();
|
|
12
|
+
const requested = openValue === undefined ? local : openValue;
|
|
13
|
+
const enabled = menus.filter(menu => !disabled && !menu.disabled), open = enabled.some(menu => menu.id === requested) ? requested : null;
|
|
14
|
+
const current = useRef(open);
|
|
15
|
+
current.current = open;
|
|
16
|
+
const activeId = enabled.some(menu => menu.id === active) ? active : enabled[0]?.id;
|
|
17
|
+
const request = (next) => { if (openValue === undefined)
|
|
18
|
+
setLocal(next); onOpenValueChange?.(next); };
|
|
19
|
+
const trigger = (id) => [...root.current?.querySelectorAll('[data-menubar-trigger]') ?? []].find(node => node.dataset.menubarTrigger === id);
|
|
20
|
+
const move = (id, delta) => {
|
|
21
|
+
const at = enabled.findIndex(menu => menu.id === id), next = enabled[(at + delta + enabled.length) % enabled.length];
|
|
22
|
+
if (!next)
|
|
23
|
+
return;
|
|
24
|
+
setActive(next.id);
|
|
25
|
+
if (open)
|
|
26
|
+
request(next.id);
|
|
27
|
+
else
|
|
28
|
+
trigger(next.id)?.focus({ preventScroll: true });
|
|
29
|
+
};
|
|
30
|
+
useBrowserLayoutEffect(() => { if (open)
|
|
31
|
+
setActive(open); }, [open]);
|
|
32
|
+
useEffect(() => { if (requested && !open)
|
|
33
|
+
request(null); }, [requested, open]);
|
|
34
|
+
return _jsx("div", { ...props, ref: root, role: "menubar", "aria-label": label, "aria-orientation": "horizontal", "aria-disabled": disabled || undefined, tabIndex: enabled.length ? undefined : 0, className: ["flood-menubar", className].filter(Boolean).join(" "), onKeyDownCapture: event => {
|
|
35
|
+
onKeyDownCapture?.(event);
|
|
36
|
+
if (event.defaultPrevented || event.key !== "Tab" || event.altKey || event.ctrlKey || event.metaKey || !open)
|
|
37
|
+
return;
|
|
38
|
+
// Capture also sees nested menus; their ordinary Menu Tab contract returns
|
|
39
|
+
// to its trigger, while an application menubar exits the whole bar.
|
|
40
|
+
const anchor = trigger(open), scope = anchor?.closest('dialog[open]') ?? anchor?.ownerDocument.body;
|
|
41
|
+
if (anchor && scope) {
|
|
42
|
+
const stops = tabbables(scope), at = stops.indexOf(anchor);
|
|
43
|
+
const next = event.shiftKey ? stops.slice(0, at).reverse().find(node => !root.current?.contains(node)) : stops.slice(at + 1).find(node => !root.current?.contains(node));
|
|
44
|
+
if (next) {
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
event.stopPropagation();
|
|
47
|
+
next.focus();
|
|
48
|
+
request(null);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}, onKeyDown: event => {
|
|
52
|
+
onKeyDown?.(event);
|
|
53
|
+
if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.nativeEvent.isComposing)
|
|
54
|
+
return;
|
|
55
|
+
const source = event.target.closest('[data-menubar-trigger]');
|
|
56
|
+
if (!source)
|
|
57
|
+
return;
|
|
58
|
+
const id = source.dataset.menubarTrigger, rtl = getComputedStyle(event.currentTarget).direction === "rtl";
|
|
59
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
|
|
60
|
+
event.preventDefault();
|
|
61
|
+
move(id, event.key === (rtl ? "ArrowLeft" : "ArrowRight") ? 1 : -1);
|
|
62
|
+
}
|
|
63
|
+
else if (event.key === "Home" || event.key === "End") {
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
const next = event.key === "Home" ? enabled[0] : enabled.at(-1);
|
|
66
|
+
if (next) {
|
|
67
|
+
setActive(next.id);
|
|
68
|
+
trigger(next.id)?.focus();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}, children: menus.map(menu => _jsx(Menu, { label: menu.label, items: menu.items, open: open === menu.id, disabled: disabled || menu.disabled, controlSize: controlSize, onOpenChange: next => { if (next)
|
|
72
|
+
request(menu.id);
|
|
73
|
+
else if (current.current === menu.id)
|
|
74
|
+
request(null); }, onAction: id => onAction?.(menu.id, id), onKeyDown: event => {
|
|
75
|
+
if (event.altKey || event.ctrlKey || event.metaKey || event.nativeEvent.isComposing)
|
|
76
|
+
return;
|
|
77
|
+
const rtl = getComputedStyle(root.current).direction === "rtl", forward = event.key === (rtl ? "ArrowLeft" : "ArrowRight");
|
|
78
|
+
if ((forward || (event.key === (rtl ? "ArrowRight" : "ArrowLeft"))) && !(forward && event.target.closest('[aria-haspopup="menu"]'))) {
|
|
79
|
+
event.preventDefault();
|
|
80
|
+
event.stopPropagation();
|
|
81
|
+
move(menu.id, forward ? 1 : -1);
|
|
82
|
+
}
|
|
83
|
+
}, trigger: binding => _jsx(Button, { ...binding, role: "menuitem", "data-menubar-trigger": menu.id, tabIndex: menu.id === activeId ? 0 : -1, variant: "ghost", size: controlSize, onFocus: () => setActive(menu.id), onPointerEnter: () => { if (open && open !== menu.id && !disabled && !menu.disabled)
|
|
84
|
+
request(menu.id); }, children: menu.label }) }, menu.id)) });
|
|
85
|
+
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { NavigationGroupProps } from "./index.js";
|
|
2
|
+
/** Related navigation with optional presentation and an independent disclosure owner. */
|
|
3
|
+
export declare const NavigationSection: import("react").ForwardRefExoticComponent<NavigationGroupProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { Collapsible, Text } from "./index.js";
|
|
4
|
+
/** Related navigation with optional presentation and an independent disclosure owner. */
|
|
5
|
+
export const NavigationSection = /* @__PURE__ */ forwardRef(function NavigationSection({ label, hideLabel = false, headingAction, separator = false, collapsible = false, expanded, defaultExpanded = true, onExpandedChange, compact = false, size = "md", collapseDisabled = false, className, children, ...props }, ref) {
|
|
6
|
+
if (label !== undefined && !label.trim())
|
|
7
|
+
throw new Error("Flood NavigationGroup label must be nonempty when provided");
|
|
8
|
+
if (collapsible && !label?.trim())
|
|
9
|
+
throw new Error("Flood collapsible NavigationGroup requires a nonempty label");
|
|
10
|
+
const action = headingAction == null ? undefined : _jsx("div", { className: "flood-navigation-group__action", children: headingAction });
|
|
11
|
+
const body = _jsx("div", { className: "flood-navigation-group__body", children: children });
|
|
12
|
+
return _jsx("div", { ...props, ref: ref, role: label ? "group" : props.role, "aria-label": props["aria-label"] ?? label, "data-size": size, "data-compact": compact || undefined, "data-hide-label": hideLabel || undefined, "data-separator": separator || undefined, "data-collapsible": collapsible || undefined, className: ["flood-navigation-group", className].filter(Boolean).join(" "), children: collapsible ? _jsx(Collapsible, { title: label, open: compact ? true : expanded, defaultOpen: defaultExpanded, onOpenChange: compact ? undefined : onExpandedChange, disabled: collapseDisabled, controlSize: size, headerAction: action, className: "flood-navigation-group__disclosure", children: body }) : _jsxs(_Fragment, { children: [(!compact && label && !hideLabel || action) && _jsxs("div", { className: "flood-navigation-group__heading", children: [!compact && label && !hideLabel && _jsx(Text, { size: "helper", tone: "subtle", className: "flood-navigation-group__label", children: label }), action] }), body] }) });
|
|
13
|
+
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { NavigationItemProps } from "./index.js";
|
|
2
|
+
/** Shared anatomy for destinations, commands and navigation disclosures. */
|
|
3
|
+
export declare const NavigationRow: import("react").ForwardRefExoticComponent<NavigationItemProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useCallback, useRef } from 'react';
|
|
3
|
+
import { Button, IconButton, IconSlot, Link, Text, Tooltip } from './index.js';
|
|
4
|
+
function assignRef(ref, node) { if (typeof ref === 'function')
|
|
5
|
+
ref(node);
|
|
6
|
+
else if (ref)
|
|
7
|
+
ref.current = node; }
|
|
8
|
+
const classes = (...values) => values.filter(Boolean).join(' ');
|
|
9
|
+
/** Shared anatomy for destinations, commands and navigation disclosures. */
|
|
10
|
+
export const NavigationRow = /* @__PURE__ */ forwardRef(function NavigationRow({ label, description, icon, reserveIcon = false, trailing, trailingAction, href, linkProps, onAction, actionProps, disclosure, current = false, currentKind = 'page', ancestorCurrent = false, disabled = false, size = 'md', compact = false, variant = 'quiet', tooltip = true, tooltipSide = 'right', controlRef, disclosureRef, className, ...props }, ref) {
|
|
11
|
+
if (!label.trim())
|
|
12
|
+
throw new Error('Flood NavigationItem requires a nonempty label');
|
|
13
|
+
if (href !== undefined && !href.trim())
|
|
14
|
+
throw new Error('Flood NavigationItem requires a nonempty destination');
|
|
15
|
+
if (href !== undefined && onAction)
|
|
16
|
+
throw new Error('Flood NavigationItem uses either a destination or a command');
|
|
17
|
+
if (compact && disclosure && (href !== undefined || onAction || actionProps?.onClick))
|
|
18
|
+
throw new Error('Flood compact rows with separate actions and disclosure require a branch composition such as NavigationTree');
|
|
19
|
+
if (disclosure && !disclosure.label.trim())
|
|
20
|
+
throw new Error('Flood NavigationItem requires a named disclosure');
|
|
21
|
+
const toggleOnly = Boolean(disclosure && href === undefined && !onAction);
|
|
22
|
+
const hasAction = !compact && trailingAction != null;
|
|
23
|
+
const unavailable = disabled || Boolean(toggleOnly && disclosure?.disabled) || Boolean(href === undefined && actionProps?.disabled);
|
|
24
|
+
const hintRef = useRef(undefined);
|
|
25
|
+
const setControl = useCallback((node) => { assignRef(controlRef, node); hintRef.current?.(node); }, [controlRef]);
|
|
26
|
+
const glyph = icon ?? (compact ? _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", "aria-hidden": "true", children: _jsx("rect", { x: "5", y: "5", width: "14", height: "14", rx: "4" }) }) : null);
|
|
27
|
+
const chevron = _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "m9 6 6 6-6 6" }) });
|
|
28
|
+
const content = _jsxs(_Fragment, { children: [(icon != null || reserveIcon || compact) && _jsx(IconSlot, { size: size, children: glyph }), _jsxs("span", { className: "flood-navigation-item__content", children: [_jsx(Text, { as: "span", className: "flood-navigation-item__label", children: label }), !compact && description && _jsx(Text, { as: "span", size: "helper", tone: "subtle", className: "flood-navigation-item__description", children: description })] }), !compact && !hasAction && trailing != null && _jsx("span", { className: "flood-navigation-item__trailing", children: trailing }), !compact && toggleOnly && _jsx("span", { className: "flood-navigation-item__indicator", children: _jsx(IconSlot, { size: size === 'lg' ? 'xs' : '2xs', children: chevron }) })] });
|
|
29
|
+
const primary = (hint) => {
|
|
30
|
+
hintRef.current = hint?.ref;
|
|
31
|
+
const hintEvents = {
|
|
32
|
+
onPointerEnter: (event) => { if (href !== undefined)
|
|
33
|
+
linkProps?.onPointerEnter?.(event);
|
|
34
|
+
else
|
|
35
|
+
actionProps?.onPointerEnter?.(event); if (!event.defaultPrevented)
|
|
36
|
+
hint?.onPointerEnter?.(event); },
|
|
37
|
+
onPointerLeave: (event) => { if (href !== undefined)
|
|
38
|
+
linkProps?.onPointerLeave?.(event);
|
|
39
|
+
else
|
|
40
|
+
actionProps?.onPointerLeave?.(event); hint?.onPointerLeave?.(event); },
|
|
41
|
+
onFocus: (event) => { if (href !== undefined)
|
|
42
|
+
linkProps?.onFocus?.(event);
|
|
43
|
+
else
|
|
44
|
+
actionProps?.onFocus?.(event); if (!event.defaultPrevented)
|
|
45
|
+
hint?.onFocus?.(event); },
|
|
46
|
+
onBlur: (event) => { if (href !== undefined)
|
|
47
|
+
linkProps?.onBlur?.(event);
|
|
48
|
+
else
|
|
49
|
+
actionProps?.onBlur?.(event); hint?.onBlur?.(event); },
|
|
50
|
+
};
|
|
51
|
+
const source = href !== undefined ? linkProps : actionProps;
|
|
52
|
+
const descriptionIds = [source?.['aria-describedby'], hint?.['aria-describedby']].filter(Boolean).join(' ') || undefined;
|
|
53
|
+
const controlClass = classes('flood-navigation-item__control', source?.className);
|
|
54
|
+
if (href !== undefined) {
|
|
55
|
+
if (unavailable)
|
|
56
|
+
return _jsx("span", { ref: setControl, role: "link", "aria-disabled": "true", "aria-label": compact ? linkProps?.['aria-label'] ?? label : linkProps?.['aria-label'], "aria-current": current ? currentKind : undefined, className: controlClass, children: content });
|
|
57
|
+
return _jsx(Link, { ...linkProps, ...hintEvents, ref: setControl, href: href, variant: "ghost", size: size, className: controlClass, title: hint ? undefined : linkProps?.title, "aria-label": compact ? linkProps?.['aria-label'] ?? label : linkProps?.['aria-label'], "aria-describedby": descriptionIds, "aria-current": current ? currentKind : undefined, children: content });
|
|
58
|
+
}
|
|
59
|
+
if (onAction || toggleOnly || actionProps?.onClick)
|
|
60
|
+
return _jsx(Button, { ...actionProps, ...hintEvents, ref: setControl, type: "button", variant: "ghost", size: size, className: controlClass, disabled: unavailable || actionProps?.disabled, "aria-label": actionProps?.['aria-label'] ?? (toggleOnly ? disclosure.label : compact ? label : undefined), "aria-describedby": descriptionIds, "aria-current": current ? currentKind : undefined, "aria-expanded": toggleOnly ? disclosure.expanded : actionProps?.['aria-expanded'], "aria-controls": toggleOnly ? disclosure.controls : actionProps?.['aria-controls'], onClick: event => { actionProps?.onClick?.(event); if (event.defaultPrevented)
|
|
61
|
+
return; if (toggleOnly)
|
|
62
|
+
disclosure.onExpandedChange(!disclosure.expanded);
|
|
63
|
+
else
|
|
64
|
+
onAction?.(); }, children: content });
|
|
65
|
+
return _jsx("span", { ref: setControl, className: controlClass, "aria-disabled": unavailable || undefined, "aria-current": current ? currentKind : undefined, children: content });
|
|
66
|
+
};
|
|
67
|
+
return _jsxs("div", { ...props, ref: ref, className: classes('flood-navigation-item', className), "data-size": size, "data-variant": variant, "data-compact": compact || undefined, "data-current": current || undefined, "data-ancestor-current": ancestorCurrent || undefined, "data-disabled": unavailable || undefined, "data-disclosure": disclosure && !toggleOnly && !compact || undefined, "data-trailing-action": hasAction || undefined, "data-expanded": disclosure?.expanded, children: [compact ? _jsx(Tooltip, { content: label, side: tooltipSide, disabled: !tooltip || unavailable, trigger: hint => primary(hint) }) : primary(), hasAction && _jsxs("div", { className: "flood-navigation-item__accessories", children: [trailing != null && _jsx("span", { className: "flood-navigation-item__metadata", children: trailing }), _jsx("div", { className: "flood-navigation-item__action", children: trailingAction })] }), disclosure && !toggleOnly && !compact && _jsx(IconButton, { ref: disclosureRef, label: disclosure.label, size: size, iconSize: size === 'lg' ? 'xs' : '2xs', variant: "ghost", className: "flood-navigation-item__disclosure", disabled: disabled || disclosure.disabled, "aria-expanded": disclosure.expanded, "aria-controls": disclosure.controls, onClick: () => disclosure.onExpandedChange(!disclosure.expanded), children: chevron })] });
|
|
68
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { NavigationListProps, StepsProps, SectionProps, SplitProps, CenterProps, SkipLinkProps } from "./index.js";
|
|
1
|
+
import type { NavigationListProps, StepsProps, SectionProps, PageHeaderProps, SplitProps, CenterProps, SkipLinkProps } from "./index.js";
|
|
2
2
|
export declare const NavigationMenu: import("react").ForwardRefExoticComponent<NavigationListProps & import("react").RefAttributes<HTMLElement>>;
|
|
3
3
|
export declare const StepSequence: import("react").ForwardRefExoticComponent<StepsProps & import("react").RefAttributes<HTMLOListElement>>;
|
|
4
|
+
export declare const PageHeading: import("react").ForwardRefExoticComponent<PageHeaderProps & import("react").RefAttributes<HTMLElement>>;
|
|
4
5
|
export declare const ContentSection: import("react").ForwardRefExoticComponent<SectionProps & import("react").RefAttributes<HTMLElement>>;
|
|
5
6
|
export declare const SplitLayout: import("react").ForwardRefExoticComponent<SplitProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
6
7
|
export declare const CenterLayout: import("react").ForwardRefExoticComponent<CenterProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, useId } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { Heading, NavigationGroup, NavigationItem } from "./index.js";
|
|
4
4
|
const classes = (...names) => names.filter(Boolean).join(" ");
|
|
5
5
|
function uniqueValues(items, component) {
|
|
6
6
|
if (items.some(item => !item.value.trim()) || new Set(items.map(item => item.value)).size !== items.length)
|
|
@@ -19,8 +19,8 @@ export const NavigationMenu = /* @__PURE__ */ forwardRef(function NavigationMenu
|
|
|
19
19
|
else
|
|
20
20
|
groups.push({ label: item.group ?? "", items: [item] });
|
|
21
21
|
}
|
|
22
|
-
const links = (entries) => entries.map(item => _jsx("li", { children:
|
|
23
|
-
return _jsx("nav", { ...props, ref: ref, "aria-label": label, className: classes("flood-navigation-list", className), "data-size": size, children: _jsx("ul", { role: "list", className: "flood-navigation-list__groups", children: groups.map((group, index) => group.label ?
|
|
22
|
+
const links = (entries) => entries.map(item => _jsx("li", { children: _jsx(NavigationItem, { label: item.label, description: item.description, href: item.href, icon: item.icon, reserveIcon: entries.some(entry => entry.icon != null), current: item.value === currentValue, size: size, linkProps: { ...item.linkProps, className: classes("flood-navigation-list__link", item.linkProps?.className) } }) }, item.value));
|
|
23
|
+
return _jsx("nav", { ...props, ref: ref, "aria-label": label, className: classes("flood-navigation-list", className), "data-size": size, children: _jsx("ul", { role: "list", className: "flood-navigation-list__groups", children: groups.map((group, index) => group.label ? _jsx("li", { className: "flood-navigation-list__group", children: _jsx(NavigationGroup, { label: group.label, id: `${id}-${index}`, size: size, children: _jsx("ul", { role: "list", "aria-labelledby": `${id}-${index}`, children: links(group.items) }) }) }, index) : links(group.items)) }) });
|
|
24
24
|
});
|
|
25
25
|
export const StepSequence = /* @__PURE__ */ forwardRef(function StepSequence({ items, label, currentValue = items[0]?.value, orientation = "horizontal", onStepChange, statusLabels = { complete: "Completed", current: "Current step", upcoming: "Upcoming", error: "Needs attention" }, className, ...props }, ref) {
|
|
26
26
|
uniqueValues(items, "Steps");
|
|
@@ -36,11 +36,19 @@ export const StepSequence = /* @__PURE__ */ forwardRef(function StepSequence({ i
|
|
|
36
36
|
return _jsx("li", { "data-state": state, "aria-current": current ? "step" : undefined, children: onStepChange ? _jsx("button", { type: "button", className: "flood-steps__content flood-steps__action", disabled: item.disabled, onClick: () => onStepChange(item.value), children: content }) : _jsx("div", { className: "flood-steps__content", children: content }) }, item.value);
|
|
37
37
|
}) });
|
|
38
38
|
});
|
|
39
|
+
const ContentHeader = /* @__PURE__ */ forwardRef(function ContentHeader({ title, description, actions, headingId, headingLevel, headingSize, className, ...props }, ref) {
|
|
40
|
+
return _jsxs("header", { ...props, ref: ref, className: classes("flood-section__header", className), children: [_jsxs("div", { className: "flood-section__heading", children: [_jsx(Heading, { id: headingId, level: headingLevel, size: headingSize, className: "flood-section__title", children: title }), description != null && _jsx("div", { className: "flood-section__description", children: description })] }), actions != null && _jsx("div", { className: "flood-section__actions", children: actions })] });
|
|
41
|
+
});
|
|
42
|
+
export const PageHeading = /* @__PURE__ */ forwardRef(function PageHeader({ title, headingSize = "large", headingLevel = 1, className, ...props }, ref) {
|
|
43
|
+
if (!title.trim())
|
|
44
|
+
throw new Error("Flood PageHeader requires a nonempty title");
|
|
45
|
+
return _jsx(ContentHeader, { ...props, ref: ref, title: title, headingLevel: headingLevel, headingSize: headingSize, className: classes("flood-page-header", className) });
|
|
46
|
+
});
|
|
39
47
|
export const ContentSection = /* @__PURE__ */ forwardRef(function ContentSection({ title, description, actions, headingLevel = 2, headingSize = "section", children, id: explicitId, className, "aria-labelledby": labelledBy, ...props }, ref) {
|
|
40
48
|
if (!title.trim() || ![2, 3, 4, 5, 6].includes(headingLevel))
|
|
41
49
|
throw new Error("Flood Section requires a nonempty title and headingLevel from 2 to 6");
|
|
42
50
|
const generated = useId(), headingId = `${explicitId ?? `flood-section-${generated}`}-title`;
|
|
43
|
-
return _jsxs("section", { ...props, ref: ref, id: explicitId, "aria-labelledby": labelledBy ?? headingId, className: classes("flood-section", className), children: [
|
|
51
|
+
return _jsxs("section", { ...props, ref: ref, id: explicitId, "aria-labelledby": labelledBy ?? headingId, className: classes("flood-section", className), children: [_jsx(ContentHeader, { title: title, description: description, actions: actions, headingId: headingId, headingLevel: headingLevel, headingSize: headingSize }), children != null && _jsx("div", { className: "flood-section__body", children: children })] });
|
|
44
52
|
});
|
|
45
53
|
export const SplitLayout = /* @__PURE__ */ forwardRef(function SplitLayout({ main, aside, side = "end", ratio = "main", collapseAt = "md", gap = "6", className, style, ...props }, ref) {
|
|
46
54
|
const primary = _jsx("div", { className: "flood-split__main", children: main }, "main"), secondary = _jsx("div", { className: "flood-split__aside", children: aside }, "aside");
|