@flood-md/react 0.2.9 → 0.2.11
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 +256 -2
- 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 +3 -3
- package/dist/data-table.js +44 -9
- 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/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 +805 -120
- package/dist/index.d.ts +403 -3
- package/dist/index.js +65 -11
- 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 +3 -0
- package/dist/overlay-runtime.js +35 -1
- package/dist/overlays.js +32 -16
- package/dist/select.js +4 -1
- package/dist/sidebar.d.ts +2 -0
- package/dist/sidebar.js +58 -0
- package/dist/toolbar.js +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,9 +6,199 @@ HTML semantics and refs, no third-party component library or Tailwind dependency
|
|
|
6
6
|
Named imports support tree shaking in optimizing ES-module bundlers. Import the
|
|
7
7
|
shared stylesheet explicitly; styles are not split by component.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
SegmentedControl options can display a `count` alongside the label, for example
|
|
10
|
+
`{value: "pending", label: "Pending", count: 2}`. Use this for a small, mutually
|
|
11
|
+
exclusive choice that updates one collection. The count is read with the visible
|
|
12
|
+
label and does not change the submitted value.
|
|
13
|
+
|
|
14
|
+
The 0.2.11 candidate adds optional DataTable row `primaryAction` for opening an
|
|
15
|
+
in-place detail panel, plus `toolbar` and `inset="roomy"` for a shared table edge.
|
|
16
|
+
The title is a native button and the rest of the row also responds to pointer
|
|
17
|
+
activation. Nested controls keep their own actions.
|
|
18
|
+
Set `numeric: true` on a DataTable column of comparable amounts or quantities
|
|
19
|
+
for logical end alignment and tabular digits. An explicit `align` still applies.
|
|
20
|
+
|
|
21
|
+
The 0.2.11 candidate adds optional compact NavigationTree item `flyout` settings
|
|
22
|
+
for mouse-hover previews and a separate positioning reference. Click, keyboard
|
|
23
|
+
and touch activation still work. Popover `focusOnOpen` defaults to true; use false
|
|
24
|
+
for a pointer preview that preserves the current keyboard focus.
|
|
25
|
+
|
|
26
|
+
In the 0.2.11 candidate, `NavigationItem.trailingAction` adds a named sibling
|
|
27
|
+
control to an expanded row. `NavigationTree` items accept the same slot.
|
|
28
|
+
Enable `branchGuides` on a tree or Sidebar group for visual depth cues.
|
|
29
|
+
Choose `Sidebar.headerLayout="inline"` to put the identity and collapse button
|
|
30
|
+
on one line while expanded. The stacked layout keeps the original toggle position.
|
|
31
|
+
|
|
32
|
+
CommandPalette (0.2.11 candidate) provides modal search over pages or commands.
|
|
33
|
+
It shares the CommandList item contract and supports grouped results, disabled
|
|
34
|
+
items, loading and two densities. The host supplies actions and any shortcut.
|
|
35
|
+
|
|
36
|
+
Tooltip trigger props are HTMLElement-safe: render the existing Link or Button
|
|
37
|
+
directly and forward its ref, hover/focus handlers and aria-describedby. Tooltip
|
|
38
|
+
does not add button type, popup or navigation semantics. Raw button triggers
|
|
39
|
+
inside forms keep an explicit type="button". Popover/Menu retain button trigger
|
|
40
|
+
contracts. When one control owns both Tooltip and Popover, compose both refs,
|
|
41
|
+
handlers and descriptions, and disable the tooltip while the interactive layer
|
|
42
|
+
is open so Escape and focus remain owned by that layer.
|
|
43
|
+
|
|
44
|
+
IconButton iconSize (0.2.11 candidate) sizes its inner IconSlot independently of
|
|
45
|
+
the interactive size. It defaults to size; shrinking a supporting glyph must
|
|
46
|
+
not shrink its target or bypass IconSlot with a custom SVG width. Existing glyph
|
|
47
|
+
roles at a 16px root are 2xs=14px, xs/sm=16px and md/lg=20px.
|
|
48
|
+
|
|
49
|
+
This package documents the **0.2.11** source API. Keep Flood package versions aligned and follow the guide matching
|
|
10
50
|
your installed declarations; source changes do not modify an existing npm release.
|
|
11
51
|
|
|
52
|
+
NavigationItem (0.2.11 candidate) is the shared small row for destinations,
|
|
53
|
+
commands and disclosures. Supply label and either href for a native Link or
|
|
54
|
+
onAction for a Button command. disclosure supplies expanded, onExpandedChange,
|
|
55
|
+
label and optional controls/disabled. With disclosure alone, the full primary
|
|
56
|
+
row toggles the branch; with href or onAction, disclosure is a separate sibling
|
|
57
|
+
IconButton. The row shares its visual surface across both controls, without
|
|
58
|
+
nested interactive elements or making a link click toggle expansion. Current,
|
|
59
|
+
ancestorCurrent, focus and disclosure expansion are separate states. icon,
|
|
60
|
+
reserveIcon, trailing and description are optional anatomy, not required filler.
|
|
61
|
+
Compact rows keep their accessible label and optional Tooltip; NavigationTree
|
|
62
|
+
owns any branch hierarchy and compact Popover, not NavigationItem itself.
|
|
63
|
+
Raw compact NavigationItem cannot combine a separate primary destination/action
|
|
64
|
+
and disclosure: use the NavigationTree branch composition, which retains the
|
|
65
|
+
parent destination alongside children in its flyout. trailing is noninteractive
|
|
66
|
+
metadata; independent controls belong in their own sibling action anatomy.
|
|
67
|
+
|
|
68
|
+
NavigationGroup (0.2.11 candidate) composes related children with optional label,
|
|
69
|
+
hideLabel, headingAction and separator. collapsible uses the existing Collapsible;
|
|
70
|
+
expanded/onExpandedChange or defaultExpanded control only the group disclosure.
|
|
71
|
+
defaultExpanded is true. A collapsible group requires a nonempty label; hideLabel
|
|
72
|
+
omits the visual title while preserving the toggle name. collapseDisabled disables
|
|
73
|
+
only that disclosure, not arbitrary child destinations or heading actions.
|
|
74
|
+
Compact presentation keeps children available and preserves the accepted expanded
|
|
75
|
+
choice for return to expanded navigation. Heading actions remain available on the
|
|
76
|
+
compact axis. Collapsible headerAction supplies a sibling action in its own header,
|
|
77
|
+
so a group command need not be nested in the disclosure button or moved elsewhere.
|
|
78
|
+
|
|
79
|
+
Sidebar (0.2.11 candidate) composes grouped NavigationTree destinations and a
|
|
80
|
+
bounded ScrollArea between fixed header/footer slots. NavigationGroup owns each
|
|
81
|
+
section's optional presentation; NavigationTree composes NavigationItem rows.
|
|
82
|
+
Supply label
|
|
83
|
+
and choose variant="quiet" (default) for restrained inactive navigation and
|
|
84
|
+
rectangular current rows, or standard for the stronger pill recipe. This is a
|
|
85
|
+
scoped component recipe using existing roles, not a global theme change.
|
|
86
|
+
Supply groups `{id,label,items}` and currentValue; item values must be globally unique. Set a
|
|
87
|
+
height on the host. Expanded width defaults to 16rem; collapsed rail is 4.5rem (5rem for coarse pointers).
|
|
88
|
+
collapsed/defaultCollapsed/onCollapsedChange are independent of the route and
|
|
89
|
+
expandedValues/defaultExpandedValues/onExpandedValuesChange. Controlled refusal
|
|
90
|
+
preserves accepted state. side is logical start/end; size matches NavigationTree.
|
|
91
|
+
Header/footer accept ReactNode or `({collapsed}) => ReactNode`; adapt their content
|
|
92
|
+
explicitly. collapsible=false omits the toggle. Localize collapseLabel,
|
|
93
|
+
expandLabel and expandItemLabel; group/item labels supply the navigation names.
|
|
94
|
+
The component does not add preference storage, routing, a mobile drawer or shortcuts.
|
|
95
|
+
Groups can set hideLabel to omit redundant visible section titles while retaining
|
|
96
|
+
nav names. headingAction, separator and collapsible/expanded group configuration
|
|
97
|
+
are independent of branch expandedValues. headerSeparator/footerSeparator are
|
|
98
|
+
independent opt-in shell choices and default false. Header/footer content must
|
|
99
|
+
follow the mode contract: common icon/text tracks when expanded and one full-rail
|
|
100
|
+
axis for the actual brand, toggle, destinations and account target when compact.
|
|
101
|
+
currentKind defaults to page; location identifies a current global
|
|
102
|
+
module. Compose a flat compact Sidebar as a GlobalRail and another Sidebar as
|
|
103
|
+
its ContextBar, keeping route, module, expansion and visibility in the host.
|
|
104
|
+
|
|
105
|
+
Sidebar places its overlay scrollbar inside the existing outer edge spacing.
|
|
106
|
+
Header, body and footer keep the same tracks without an additional reserved
|
|
107
|
+
column, whether navigation overflows or not.
|
|
108
|
+
NavigationTree rows share NavigationItem's space-3 start inset, icon/text tracks
|
|
109
|
+
and deliberate columns for actual trailing anatomy. Iconless descendants begin at the parent text track; missing
|
|
110
|
+
peer icons reserve a slot. Header content should use the same icon size and gap.
|
|
111
|
+
|
|
112
|
+
NavigationTree rows use space-1 between peers and before an expanded branch;
|
|
113
|
+
group separation remains owned by Sidebar.
|
|
114
|
+
|
|
115
|
+
NavigationTree compact (0.2.11 candidate) exposes an icon rail: leaf destinations
|
|
116
|
+
remain links, disabled items remain unavailable, branches use Popover with full
|
|
117
|
+
navigation. flyoutSide controls its physical placement; Sidebar resolves its own
|
|
118
|
+
side and RTL direction. Branch selection closes the flyout and preserves current
|
|
119
|
+
destination/expanded state independently. trailing composes meaningful metadata
|
|
120
|
+
such as Badge in expanded rows. Flood tooltips identify compact destinations on
|
|
121
|
+
hover and focus while preserving the actual link/button; an open branch flyout
|
|
122
|
+
suppresses its hint. Missing icons use a neutral fallback glyph. Current ancestor styling does not
|
|
123
|
+
claim aria-current on a non-current parent.
|
|
124
|
+
|
|
125
|
+
DataTable emptyContent (0.2.11 candidate) accepts a composed EmptyState and
|
|
126
|
+
applicable actions inside the existing full-width body cell. It renders only
|
|
127
|
+
when state="ready" has no visible rows; loading/error retain Spinner/Alert and
|
|
128
|
+
retry ownership. Omitting it preserves labels.empty. Keep header/sort context
|
|
129
|
+
and distinguish an empty collection from no matching results in host content.
|
|
130
|
+
Reset filters in the host and return focus to a persistent query control.
|
|
131
|
+
|
|
132
|
+
CollectionViewSwitcher (0.2.11 candidate) composes a hidden-label Select and
|
|
133
|
+
applicable view commands. Supply views `{id,name,disabled?}`, controlled value
|
|
134
|
+
and onValueChange. Optional actions/onAction use the OverflowActions contract:
|
|
135
|
+
one command renders Button directly, multiple commands adapt through overflow.
|
|
136
|
+
The host owns saved queries, persistence, naming, confirmation and recovery.
|
|
137
|
+
Keep it separate from CollectionToolbar; selectRef gives host dialogs a stable
|
|
138
|
+
focus destination. controlSize defaults to sm; disabled blocks choice/commands.
|
|
139
|
+
Localize label, actionsLabel, moreLabel, view names and supplied action labels.
|
|
140
|
+
Its multi-action rail uses OverflowActions containerVariant="plain" to match
|
|
141
|
+
the adjacent field height. Toolbar variant="plain" removes its material and
|
|
142
|
+
outer inset; contained remains the default for standalone rails. Button variant
|
|
143
|
+
and toolbar containerVariant remain independent in OverflowActions.
|
|
144
|
+
|
|
145
|
+
CollectionToolbar (0.2.11 candidate) composes a named search field, applied Tag
|
|
146
|
+
summaries, reserved Clear filters action and end-aligned Filters Popover. Supply
|
|
147
|
+
controlled searchValue/onSearchValueChange; appliedFilters and onRemoveFilter
|
|
148
|
+
describe accepted conditions. filterContent supplies the host's staged editor.
|
|
149
|
+
The host owns Apply/Cancel, query execution, validation and saved views. Omit
|
|
150
|
+
filterContent for search/summary-only use. onClear is optional; canClear describes
|
|
151
|
+
whether the host has anything to reset, including slot-owned quickFilters.
|
|
152
|
+
Clearing and tag removal focus Filters (or search without a panel). The root is
|
|
153
|
+
a fieldset with ordinary Tab navigation, not an action-only roving toolbar.
|
|
154
|
+
Use summaryPrefix for meaningful all/any context, localized labels for controls,
|
|
155
|
+
and keep saved-view management outside this query row. Narrow containers move
|
|
156
|
+
summaries below search/actions; no material surface is added.
|
|
157
|
+
|
|
158
|
+
FilterGroup (0.2.11 candidate) composes FilterCondition rows and SegmentedControl
|
|
159
|
+
for a flat finite-choice draft. Supply label, properties, controlled value
|
|
160
|
+
`{match:"all"|"any", conditions:[{id,property,operator,values}]}` and onValueChange.
|
|
161
|
+
Rows keep stable IDs. All/any appears at two conditions; an empty group offers
|
|
162
|
+
Add condition without extra explanatory chrome. New rows use an available
|
|
163
|
+
enabled property and empty values. Duplicate properties are prevented for new
|
|
164
|
+
choices by default; allowDuplicateProperties and maxConditions can change that
|
|
165
|
+
policy. Existing accepted rows are preserved when constraints change.
|
|
166
|
+
Accepted additions/removals restore useful focus; refused proposals retain state
|
|
167
|
+
and focus. The host owns application, validation, persistence and query semantics.
|
|
168
|
+
controlSize defaults to sm; labels and conditionLabels localize group/row text.
|
|
169
|
+
|
|
170
|
+
FilterCondition (0.2.11 candidate) composes Fieldset, Field, Grid, two Selects,
|
|
171
|
+
MultiSelect and an optional removal IconButton. Supply a named label, properties
|
|
172
|
+
with finite options, controlled value `{property, operator: "is" | "is-not", values}`
|
|
173
|
+
and onValueChange. Property changes propose an empty values array; operator
|
|
174
|
+
changes preserve values. Empty values remain a draft for host validation.
|
|
175
|
+
No query execution or Apply/Cancel state is built in. controlSize defaults to sm;
|
|
176
|
+
labels localizes names/operator text and hideLabel defaults to true for a named
|
|
177
|
+
row. disabled blocks all interaction; onRemove is optional. A wide host gets one
|
|
178
|
+
row with a larger value track; container queries reflow narrow rows. Hosts own
|
|
179
|
+
duplicate-property policy and focus after removal.
|
|
180
|
+
MultiSelect shows its placeholder only while no values are selected. With chips
|
|
181
|
+
and an empty query, the editor reserves only its real action/caret budget;
|
|
182
|
+
typing expands the search area. A needless placeholder row must not enlarge the
|
|
183
|
+
control, while actual chip overflow can still wrap without clipping values.
|
|
184
|
+
|
|
185
|
+
Toolbar supports shape="rounded" (default) or "pill". OverflowActions uses
|
|
186
|
+
shape="pill" by default and forwards that capability to Toolbar; choose rounded
|
|
187
|
+
for the earlier geometry. A horizontal pill toolbar stays on one scrollable rail.
|
|
188
|
+
Read-only text controls retain keyboard focus and copying while preventing edits
|
|
189
|
+
and picker activation; they are not disabled controls.
|
|
190
|
+
|
|
191
|
+
Tabs uses `variant="contained"` by default. Choose `variant="line"` for page
|
|
192
|
+
sections with a selection marker along the edge next to the panel. Both variants
|
|
193
|
+
support horizontal and vertical orientation and the same keyboard behavior.
|
|
194
|
+
|
|
195
|
+
Version 0.2.10 adds Fieldset legendSize="label" | "section"
|
|
196
|
+
(default label). Independent section legends use a 1rem/600 role; named fields
|
|
197
|
+
retain their 13px-equivalent label size with a .25rem inner gap. Dialog task
|
|
198
|
+
titles use 1.25rem/600 and a 1.5rem body inset. These dark-profile recipe changes
|
|
199
|
+
do not enlarge compact Popover captions or default choice legends. DatePicker
|
|
200
|
+
calendar panels prefer at least 20rem when available, bounded by the viewport.
|
|
201
|
+
|
|
12
202
|
Version 0.2.9 improves constrained file rows, Drawer readability and Select pointer
|
|
13
203
|
focus without changing public signatures or token values.
|
|
14
204
|
|
|
@@ -655,11 +845,20 @@ explicit id/headers associations for complex spanning headers. Do not add anothe
|
|
|
655
845
|
caption child. See [WAI table guidance](https://www.w3.org/WAI/tutorials/tables/).
|
|
656
846
|
|
|
657
847
|
Table density defaults comfortable; compact reduces vertical cell padding.
|
|
848
|
+
In 0.2.10, cellVerticalAlign defaults to "middle" for consistent
|
|
849
|
+
record/action and editable rows. Choose "top" for deliberate multiline prose
|
|
850
|
+
alignment or "bottom" when content requires it. This sets the shared cell recipe without consumer
|
|
851
|
+
specificity overrides. Native style on a particular th/td can override an
|
|
852
|
+
exceptional cell. DataTable manages its own header geometry separately.
|
|
658
853
|
striped is false by default. Native tfoot rows use a quiet tinted background and
|
|
659
854
|
medium-weight text to distinguish summaries; the top separator stays decorative.
|
|
660
855
|
data-numeric on a th or td uses logical end alignment,
|
|
661
856
|
tabular figures and no wrapping for numbers. data-align=start/center/end overrides
|
|
662
|
-
alignment explicitly. Text cells
|
|
857
|
+
alignment explicitly. Text cells preserve word-based intrinsic widths and wrap
|
|
858
|
+
at word boundaries; a constrained long token can still use break-word fallback.
|
|
859
|
+
Use native data-wrap="anywhere" deliberately for a technical identifier cell
|
|
860
|
+
when fragmentation is preferable to local scrolling. StatusIndicator preserves
|
|
861
|
+
the same word-based minimum in tables and file rows. Set style.minWidth to preserve room for a
|
|
663
862
|
wide table, and the containing ScrollArea handles overflow. The host owns dates,
|
|
664
863
|
units, totals, empty rows/colSpan and any cell actions. Avoid interactive whole rows.
|
|
665
864
|
|
|
@@ -739,6 +938,26 @@ See [WAI Menu Button](https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/) and
|
|
|
739
938
|
|
|
740
939
|
### Toolbar and Kbd (0.2.4)
|
|
741
940
|
|
|
941
|
+
BulkActionBar (0.2.11 candidate) composes Toolbar and OverflowActions for selected
|
|
942
|
+
records. Supply label, selectionCount, items and onClear; onAction receives the
|
|
943
|
+
command ID. A zero count renders nothing. selectionLabel is the complete
|
|
944
|
+
localized count. The pill rail stays in one row, with two visible commands by
|
|
945
|
+
default; maxVisibleActions accepts 1, 2 or 3 and available width can reduce it
|
|
946
|
+
further. Remaining commands use More. pending disables all commands and clearing.
|
|
947
|
+
counter="label" (default) shows the summary, "number" shows only the number with
|
|
948
|
+
the full accessible label, and "none" removes the counter slot. Label/number
|
|
949
|
+
slots reserve 7rem/3rem respectively, bounded on narrow rails, and use tabular
|
|
950
|
+
digits so changing selection does not move commands. counterWidth customizes
|
|
951
|
+
that reservation for translations or larger counts; long summaries truncate
|
|
952
|
+
visually while retaining their full text/title. A hidden counter frees its slot.
|
|
953
|
+
The host owns accepted changes, captured IDs, confirmation and focus after the
|
|
954
|
+
bar disappears. Positioning is host-owned: use a stable bounded width for a
|
|
955
|
+
floating rail, plus viewport safe-area spacing and measured scroll clearance.
|
|
956
|
+
|
|
957
|
+
OverflowActions also accepts leading/trailing slots and maxVisibleActions. Slot
|
|
958
|
+
width is reserved before measuring commands; use action owners in those slots
|
|
959
|
+
and retain a stable containing width. Do not add form inputs to the Toolbar.
|
|
960
|
+
|
|
742
961
|
Toolbar groups Button, IconButton, Toggle, native buttons/links and Menu triggers
|
|
743
962
|
under one named action panel. After hydration it uses one Tab entry, directional
|
|
744
963
|
arrows, Home/End and optional looping. Disabled/hidden actions are skipped. Arrows
|
|
@@ -946,3 +1165,38 @@ Popover positionReference optionally supplies a connected same-document element
|
|
|
946
1165
|
DateRangeField, RangeCalendar and DateRangePicker (0.2.7) share ordered range values and the original Calendar grid. ResizablePanels adds real pointer/keyboard geometry above static Split. ErrorSummary links host validation to native controls. See each generated catalog page and its guide under docs/components/. DateField validationMessage adds an external native constraint after the field's own date validity.
|
|
947
1166
|
|
|
948
1167
|
Menu (0.2.7) supports recursive submenu items and ContextMenu reuses its native layer engine. Context triggers preserve the actual pointer/keyboard source; nested searches stay scoped, Escape unwinds one level and Tab exits through the root. See docs/components/menu.md and context-menu.md.
|
|
1168
|
+
|
|
1169
|
+
## Collection contracts in 0.2.11
|
|
1170
|
+
|
|
1171
|
+
Autocomplete submits free text, including strings outside its suggestions.
|
|
1172
|
+
Combobox and MultiSelect continue submitting IDs. Search controls accept local
|
|
1173
|
+
filtering (default) or manual filtering with controlled query/value and
|
|
1174
|
+
optionsQuery identifying the result. A mismatched result stays nonselectable.
|
|
1175
|
+
loadState distinguishes ready/loading/error; onRetry is an optional host action.
|
|
1176
|
+
Use selectedOptions to retain a selected record's presentation while results
|
|
1177
|
+
change. Query cancellation and transport stay with the host. Options may have
|
|
1178
|
+
group labels; option IDs remain globally unique.
|
|
1179
|
+
|
|
1180
|
+
OverflowActions takes named command items, an onAction callback, optional priority,
|
|
1181
|
+
size/variant and a localized moreLabel. It preserves source order and moves lower
|
|
1182
|
+
priorities to an existing Menu. It is not a navigation-link container. Menubar
|
|
1183
|
+
coordinates menus with controlled/uncontrolled openValue and roving triggers;
|
|
1184
|
+
child commands reuse Menu. Use native links for destinations. Button/IconButton
|
|
1185
|
+
tone="danger" uses existing semantic colors within FloodRoot, independently of
|
|
1186
|
+
prominence. Tone itself does not confirm a destructive operation.
|
|
1187
|
+
|
|
1188
|
+
DataTable paginationMode="server" renders supplied rows without sorting/slicing.
|
|
1189
|
+
Provide page/onPageChange and nonnegative totalRows; sortable columns also require
|
|
1190
|
+
controlled sort (null when absent) and onSortChange. Reconcile an out-of-range page
|
|
1191
|
+
when a query changes; ready rows must match pageSize/totalRows. Selection defaults
|
|
1192
|
+
to the supplied page in server mode and the full collection in client mode.
|
|
1193
|
+
Server selectionScope="dataset" requires controlled selectedIds/onSelectionChange;
|
|
1194
|
+
the host validates IDs outside the page. Checkboxes only select the current page.
|
|
1195
|
+
This API does not fetch, cancel requests, select an entire remote query, virtualize
|
|
1196
|
+
or manage column visibility/resizing/pinning.
|
|
1197
|
+
|
|
1198
|
+
DatePicker and DateRangePicker pass viewLabels to their calendars. Calendar panels
|
|
1199
|
+
use minimal Popover chrome, with Escape/selection/trigger dismissal; there is no
|
|
1200
|
+
separate hidden close-button API. DateTimePicker datePickerLabels/timePickerLabels
|
|
1201
|
+
forward popup labels plus segmentLabels and validation messages. DateTimeRangePicker
|
|
1202
|
+
exposes corresponding start/end label objects; outer field labels remain distinct.
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type AppShellProps, type AppTopBarProps } from "./index.js";
|
|
2
|
+
export declare const ApplicationTopBar: import("react").ForwardRefExoticComponent<AppTopBarProps & import("react").RefAttributes<HTMLElement>>;
|
|
3
|
+
export declare const ApplicationShell: import("react").ForwardRefExoticComponent<AppShellProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useEffect, useId, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
|
|
3
|
+
import { AppTopBar, Button, Drawer, Inline, ScrollArea, SkipLink } from "./index.js";
|
|
4
|
+
const useBrowserLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
5
|
+
export const ApplicationTopBar = /* @__PURE__ */ forwardRef(function ApplicationTopBar({ start, end, bordered, className, ...props }, ref) {
|
|
6
|
+
return _jsxs("header", { ...props, ref: ref, className: ["flood-app-top-bar", className].filter(Boolean).join(" "), "data-bordered": bordered || undefined, children: [start != null && _jsx(Inline, { align: "center", gap: "2", className: "flood-app-top-bar__start", children: start }), end != null && _jsx(Inline, { align: "center", gap: "2", className: "flood-app-top-bar__end", children: end })] });
|
|
7
|
+
});
|
|
8
|
+
export const ApplicationShell = /* @__PURE__ */ forwardRef(function ApplicationShell({ navigation, navigationSide, navigationDrawer, topBar, footer, scroll, mainId, mainAs: Main = "main", mainLabel, mainRef, scrollLabel, scrollOrientation = "both", skipLabel, children, className, ...props }, ref) {
|
|
9
|
+
const generatedId = useId();
|
|
10
|
+
const contentId = mainId ?? `flood-app-${generatedId}`;
|
|
11
|
+
const root = useRef(null);
|
|
12
|
+
const dock = useRef(null);
|
|
13
|
+
const trigger = useRef(null);
|
|
14
|
+
const drawer = useRef(null);
|
|
15
|
+
const focusAfterResize = useRef(false);
|
|
16
|
+
const [narrow, setNarrow] = useState(false);
|
|
17
|
+
const [open, setOpen] = useState(false);
|
|
18
|
+
const below = navigationDrawer?.below;
|
|
19
|
+
const useDrawer = Boolean(navigationDrawer && narrow);
|
|
20
|
+
useImperativeHandle(ref, () => root.current, []);
|
|
21
|
+
useBrowserLayoutEffect(() => {
|
|
22
|
+
const node = root.current;
|
|
23
|
+
if (!node || below === undefined) {
|
|
24
|
+
setNarrow(false);
|
|
25
|
+
setOpen(false);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const update = () => {
|
|
29
|
+
const width = node.getBoundingClientRect().width;
|
|
30
|
+
if (!width)
|
|
31
|
+
return;
|
|
32
|
+
const next = width < below;
|
|
33
|
+
if (next === narrow)
|
|
34
|
+
return;
|
|
35
|
+
const active = node.ownerDocument.activeElement;
|
|
36
|
+
focusAfterResize.current = Boolean(next ? dock.current?.contains(active) : trigger.current === active || drawer.current?.contains(active));
|
|
37
|
+
if (!next)
|
|
38
|
+
setOpen(false);
|
|
39
|
+
setNarrow(next);
|
|
40
|
+
};
|
|
41
|
+
update();
|
|
42
|
+
const observer = new ResizeObserver(update);
|
|
43
|
+
observer.observe(node);
|
|
44
|
+
return () => observer.disconnect();
|
|
45
|
+
}, [below, narrow]);
|
|
46
|
+
useBrowserLayoutEffect(() => {
|
|
47
|
+
if (!focusAfterResize.current)
|
|
48
|
+
return;
|
|
49
|
+
focusAfterResize.current = false;
|
|
50
|
+
const target = useDrawer ? trigger.current : root.current?.ownerDocument.getElementById(contentId);
|
|
51
|
+
target?.focus({ preventScroll: true });
|
|
52
|
+
}, [contentId, useDrawer]);
|
|
53
|
+
const navigationSlot = !useDrawer && navigation != null && navigation !== false
|
|
54
|
+
? _jsx("div", { ref: dock, className: "flood-app-shell__navigation", children: navigation })
|
|
55
|
+
: null;
|
|
56
|
+
const navigationTrigger = useDrawer && navigationDrawer ? _jsx(Drawer, { ref: drawer, title: navigationDrawer.title, side: navigationSide, size: navigationDrawer.size ?? "sm", open: open, onOpenChange: setOpen, trigger: ({ ref: drawerTrigger, ...buttonProps }) => _jsx(Button, { ...buttonProps, ref: node => {
|
|
57
|
+
trigger.current = node;
|
|
58
|
+
drawerTrigger(node);
|
|
59
|
+
}, variant: "subtle", size: "sm", children: navigationDrawer.triggerLabel ?? "Navigation" }), children: open && navigationDrawer.renderContent(() => setOpen(false)) }) : null;
|
|
60
|
+
const chrome = typeof topBar === "function"
|
|
61
|
+
? topBar(navigationTrigger)
|
|
62
|
+
: _jsxs(_Fragment, { children: [navigationTrigger && _jsx(AppTopBar, { start: navigationTrigger }), topBar] });
|
|
63
|
+
return _jsxs("div", { ...props, ref: root, className: ["flood-app-shell", className].filter(Boolean).join(" "), "data-scroll": scroll, children: [_jsx(SkipLink, { href: `#${contentId}`, children: skipLabel }), navigationSide === "start" && navigationSlot, _jsxs("div", { className: "flood-app-shell__workspace", children: [chrome, _jsx(Main, { ref: mainRef, id: contentId, "aria-label": mainLabel, tabIndex: -1, className: "flood-app-shell__main", children: scroll === "content"
|
|
64
|
+
? _jsx(ScrollArea, { orientation: scrollOrientation, "aria-label": scrollLabel, className: "flood-app-shell__scroll", children: children })
|
|
65
|
+
: children }), footer] }), navigationSide === "end" && navigationSlot] });
|
|
66
|
+
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type BulkActionBarProps } from "./index.js";
|
|
2
|
+
/** Selection owns the count; the host owns accepted record updates and focus after removal. */
|
|
3
|
+
export declare const SelectionActionBar: import("react").ForwardRefExoticComponent<BulkActionBarProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { IconButton, OverflowActions, Text, VisuallyHidden } from "./index.js";
|
|
4
|
+
/** Selection owns the count; the host owns accepted record updates and focus after removal. */
|
|
5
|
+
export const SelectionActionBar = /* @__PURE__ */ forwardRef(function SelectionActionBar({ label, selectionCount, selectionLabel = `${selectionCount} selected`, items, onAction, onClear, counter = "label", counterWidth, clearLabel = "Clear selection", moreLabel = "More", size = "sm", maxVisibleActions = 2, disabled = false, pending = false, className, ...props }, ref) {
|
|
6
|
+
if (!Number.isSafeInteger(selectionCount) || selectionCount < 0)
|
|
7
|
+
throw new Error("Flood BulkActionBar selectionCount must be a nonnegative safe integer");
|
|
8
|
+
if (!selectionLabel.trim() || !clearLabel.trim())
|
|
9
|
+
throw new Error("Flood BulkActionBar requires named selection and clear action");
|
|
10
|
+
if (![1, 2, 3].includes(maxVisibleActions))
|
|
11
|
+
throw new Error("Flood BulkActionBar keeps one to three commands visible");
|
|
12
|
+
if (!["label", "number", "none"].includes(counter))
|
|
13
|
+
throw new Error("Flood BulkActionBar counter must be label, number or none");
|
|
14
|
+
if (selectionCount === 0)
|
|
15
|
+
return null;
|
|
16
|
+
return _jsx(OverflowActions, { ...props, ref: ref, label: label, items: items, onAction: onAction, moreLabel: moreLabel, size: size, variant: "subtle", shape: "pill", maxVisibleActions: maxVisibleActions, disabled: disabled || pending, "aria-busy": pending || undefined, className: ["flood-bulk-action-bar", className].filter(Boolean).join(" "), leading: counter === "none" ? undefined : _jsx(Text, { size: "compact", className: "flood-bulk-action-bar__selection", "data-counter": counter, style: counterWidth === undefined ? undefined : { inlineSize: counterWidth }, title: selectionLabel, children: counter === "number" ? _jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", children: selectionCount }), _jsx(VisuallyHidden, { children: selectionLabel })] }) : selectionLabel }), trailing: _jsx(IconButton, { label: clearLabel, size: size, variant: "subtle", disabled: disabled || pending, onClick: onClear, children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", "aria-hidden": "true", children: _jsx("path", { d: "m6 6 12 12M18 6 6 18" }) }) }) });
|
|
17
|
+
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type CollectionToolbarProps } from './index.js';
|
|
2
|
+
/** Query chrome only: the host supplies filter drafts, accepted query and saved views. */
|
|
3
|
+
export declare const CollectionQueryBar: import("react").ForwardRefExoticComponent<CollectionToolbarProps & import("react").RefAttributes<HTMLFieldSetElement>>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useId, useImperativeHandle, useRef } from 'react';
|
|
3
|
+
import { Button, Field, Fieldset, IconSlot, Inline, Popover, SearchInput, Tag, Text } from './index.js';
|
|
4
|
+
/** Query chrome only: the host supplies filter drafts, accepted query and saved views. */
|
|
5
|
+
export const CollectionQueryBar = /* @__PURE__ */ forwardRef(function CollectionQueryBar({ label, searchValue, onSearchValueChange, searchLabel = 'Search', searchPlaceholder = 'Search…', clearSearchLabel = 'Clear search', appliedFilters = [], onRemoveFilter, appliedFiltersLabel = 'Applied filters', summaryPrefix, quickFilters, filterContent, filtersLabel = 'Filters', filterTitle = filtersLabel, filtersOpen, onFiltersOpenChange, filterPanelRef, filterPanelClassName, onClear, canClear = Boolean(searchValue || appliedFilters.length), clearLabel = 'Clear filters', controlSize = 'sm', disabled = false, hideLabel = true, className, ...props }, forwardedRef) {
|
|
6
|
+
const root = useRef(null);
|
|
7
|
+
useImperativeHandle(forwardedRef, () => root.current, []);
|
|
8
|
+
const generated = useId(), triggerId = `flood-collection-filters-${generated}`, searchId = `flood-collection-search-${generated}`;
|
|
9
|
+
if (![label, searchLabel, clearSearchLabel, appliedFiltersLabel, filtersLabel, filterTitle, clearLabel].every(text => text.trim()) ||
|
|
10
|
+
new Set(appliedFilters.map(filter => filter.id)).size !== appliedFilters.length || appliedFilters.some(filter => !filter.id.trim() || !filter.label.trim()))
|
|
11
|
+
throw new Error('Flood CollectionToolbar requires named controls and unique applied filter IDs');
|
|
12
|
+
const hasPanel = filterContent !== undefined && filterContent !== null && filterContent !== false;
|
|
13
|
+
const hasSummary = Boolean(quickFilters) || appliedFilters.length > 0;
|
|
14
|
+
function focusPersistent() {
|
|
15
|
+
const document = root.current?.ownerDocument;
|
|
16
|
+
document?.getElementById(hasPanel ? triggerId : searchId)?.focus({ preventScroll: true });
|
|
17
|
+
}
|
|
18
|
+
return _jsx(Fieldset, { ...props, ref: root, legend: label, hideLabel: hideLabel, disabled: disabled, className: ['flood-collection-toolbar', className].filter(Boolean).join(' '), children: _jsxs(Inline, { gap: "3", align: "center", className: "flood-collection-toolbar__row", children: [_jsx("div", { className: "flood-collection-toolbar__search", children: _jsx(Field, { id: searchId, label: searchLabel, hideLabel: true, children: field => _jsx(SearchInput, { ...field, controlSize: controlSize, value: searchValue, placeholder: searchPlaceholder, clearLabel: clearSearchLabel, disabled: disabled, onChange: event => { if (!disabled)
|
|
19
|
+
onSearchValueChange(event.currentTarget.value); } }) }) }), hasSummary && _jsxs(Inline, { gap: "2", align: "center", role: "group", "aria-label": appliedFiltersLabel, className: "flood-collection-toolbar__summaries", children: [quickFilters, summaryPrefix && _jsx(Text, { size: "compact", tone: "subtle", children: summaryPrefix }), appliedFilters.map(filter => _jsx(Tag, { size: controlSize === 'xl' ? 'lg' : 'md', disabled: disabled || filter.disabled, removeLabel: filter.removeLabel ?? `Remove ${filter.label}`, onRemove: onRemoveFilter ? () => {
|
|
20
|
+
if (disabled || filter.disabled)
|
|
21
|
+
return;
|
|
22
|
+
focusPersistent();
|
|
23
|
+
onRemoveFilter(filter.id);
|
|
24
|
+
} : undefined, children: filter.label }, filter.id))] }), (onClear || hasPanel) && _jsxs(Inline, { gap: "2", align: "center", className: "flood-collection-toolbar__commands", children: [onClear && _jsx(Button, { size: controlSize, variant: "outline", className: "flood-collection-toolbar__clear", "data-visible": canClear, disabled: disabled || !canClear, "aria-hidden": !canClear || undefined, onClick: () => { if (disabled || !canClear)
|
|
25
|
+
return; focusPersistent(); onClear(); }, children: clearLabel }), hasPanel && _jsx(Popover, { title: filterTitle, ref: filterPanelRef, className: filterPanelClassName, open: filtersOpen, onOpenChange: onFiltersOpenChange, disabled: disabled, align: "end", trigger: trigger => _jsxs(Button, { ...trigger, id: triggerId, variant: "outline", size: controlSize, children: [_jsx(IconSlot, { size: controlSize, children: _jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", "aria-hidden": "true", children: _jsx("path", { d: "M4 6h16M7 12h10m-7 6h4" }) }) }), filtersLabel] }), children: filterContent })] })] }) });
|
|
26
|
+
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type CollectionViewSwitcherProps } from './index.js';
|
|
2
|
+
/** Presentation of accepted definitions; the host owns their queries and persistence. */
|
|
3
|
+
export declare const CollectionViewSelector: import("react").ForwardRefExoticComponent<CollectionViewSwitcherProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { Button, Field, IconSlot, Inline, OverflowActions, Select } from './index.js';
|
|
4
|
+
/** Presentation of accepted definitions; the host owns their queries and persistence. */
|
|
5
|
+
export const CollectionViewSelector = /* @__PURE__ */ forwardRef(function CollectionViewSelector({ label, views, value, onValueChange, actions = [], onAction, actionsLabel = `${label} actions`, moreLabel = 'View actions', controlSize = 'sm', disabled = false, selectRef, className, ...props }, ref) {
|
|
6
|
+
if (!label.trim() || !actionsLabel.trim() || !moreLabel.trim() || new Set(views.map(view => view.id)).size !== views.length ||
|
|
7
|
+
views.some(view => !view.id.trim() || !view.name.trim()) || new Set(actions.map(action => action.id)).size !== actions.length ||
|
|
8
|
+
actions.some(action => !action.id.trim() || !action.label.trim()))
|
|
9
|
+
throw new Error('Flood CollectionViewSwitcher requires unique named views and actions');
|
|
10
|
+
const single = actions.length === 1 ? actions[0] : undefined;
|
|
11
|
+
return _jsxs(Inline, { ...props, ref: ref, role: "group", "aria-label": `${label} controls`, gap: "3", align: "center", className: ['flood-collection-view-switcher', className].filter(Boolean).join(' '), children: [_jsx("div", { className: "flood-collection-view-switcher__select", children: _jsx(Field, { label: label, hideLabel: true, children: field => _jsx(Select, { ...field, ref: selectRef, controlSize: controlSize, disabled: disabled, value: value, onChange: event => {
|
|
12
|
+
const next = views.find(view => view.id === event.currentTarget.value);
|
|
13
|
+
if (!disabled && next && !next.disabled)
|
|
14
|
+
onValueChange(next.id);
|
|
15
|
+
}, children: views.map(view => _jsx("option", { value: view.id, disabled: view.disabled, children: view.name }, view.id)) }) }) }), actions.length > 0 && _jsx("div", { className: "flood-collection-view-switcher__actions", children: single ?
|
|
16
|
+
_jsxs(Button, { size: controlSize, variant: "subtle", tone: single.tone, disabled: disabled || single.disabled, onClick: () => { if (!disabled && !single.disabled)
|
|
17
|
+
onAction?.(single.id); }, children: [single.icon && _jsx(IconSlot, { size: controlSize, children: single.icon }), single.label] }) : _jsx(OverflowActions, { label: actionsLabel, moreLabel: moreLabel, size: controlSize, items: actions, containerVariant: "plain", disabled: disabled, onAction: id => { if (!disabled)
|
|
18
|
+
onAction?.(id); } }) })] });
|
|
19
|
+
});
|
package/dist/combobox.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { type ComboboxProps } from "./index.js";
|
|
1
|
+
import { type ComboboxProps, type ComboboxOption } from "./index.js";
|
|
2
2
|
interface SearchSelectionProps extends Omit<ComboboxProps, "value" | "defaultValue" | "onValueChange"> {
|
|
3
3
|
selectedValues?: readonly string[];
|
|
4
4
|
initialValues: readonly string[];
|
|
5
5
|
onSelectionChange?: (value: string[]) => void;
|
|
6
6
|
multiple?: boolean;
|
|
7
|
+
freeText?: boolean;
|
|
8
|
+
textValue?: string;
|
|
9
|
+
initialText?: string;
|
|
10
|
+
onTextChange?: (text: string) => void;
|
|
11
|
+
onOptionSelect?: (option: ComboboxOption) => void;
|
|
7
12
|
removeItemLabel?: string;
|
|
8
13
|
}
|
|
9
14
|
/** Shared search/layer model. Public single and multiple value contracts stay distinct. */
|