@flood-md/react 0.2.3 → 0.2.5

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.
Files changed (49) hide show
  1. package/README.md +398 -3
  2. package/dist/alert-dialog.d.ts +2 -0
  3. package/dist/alert-dialog.js +23 -0
  4. package/dist/avatar.d.ts +5 -0
  5. package/dist/avatar.js +8 -0
  6. package/dist/checkbox.d.ts +4 -0
  7. package/dist/checkbox.js +15 -0
  8. package/dist/combobox.d.ts +11 -0
  9. package/dist/combobox.js +301 -0
  10. package/dist/content-elements.d.ts +8 -0
  11. package/dist/content-elements.js +47 -0
  12. package/dist/data-display.d.ts +3 -0
  13. package/dist/data-display.js +11 -0
  14. package/dist/disclosure.js +2 -1
  15. package/dist/feedback-actions.d.ts +3 -0
  16. package/dist/feedback-actions.js +106 -0
  17. package/dist/feedback.d.ts +8 -0
  18. package/dist/feedback.js +29 -0
  19. package/dist/file-input.d.ts +8 -0
  20. package/dist/file-input.js +86 -0
  21. package/dist/focusable-hidden.d.ts +3 -0
  22. package/dist/focusable-hidden.js +99 -0
  23. package/dist/fonts/InterVariable-Italic.woff2 +0 -0
  24. package/dist/fonts/README.md +9 -5
  25. package/dist/form-controls.d.ts +6 -0
  26. package/dist/form-controls.js +250 -0
  27. package/dist/foundations.css +543 -12
  28. package/dist/index.d.ts +513 -2
  29. package/dist/index.js +223 -36
  30. package/dist/menu.d.ts +2 -0
  31. package/dist/menu.js +130 -0
  32. package/dist/navigation-layout.d.ts +7 -0
  33. package/dist/navigation-layout.js +77 -0
  34. package/dist/navigation.js +8 -8
  35. package/dist/numeric-input.d.ts +8 -0
  36. package/dist/numeric-input.js +68 -0
  37. package/dist/overlay-runtime.js +43 -16
  38. package/dist/overlays.d.ts +7 -1
  39. package/dist/overlays.js +17 -6
  40. package/dist/scroll-area.js +17 -2
  41. package/dist/select.js +96 -47
  42. package/dist/slider.d.ts +7 -0
  43. package/dist/slider.js +89 -0
  44. package/dist/styles.css +9 -0
  45. package/dist/text-inputs.d.ts +9 -0
  46. package/dist/text-inputs.js +45 -0
  47. package/dist/toolbar.d.ts +2 -0
  48. package/dist/toolbar.js +80 -0
  49. package/package.json +2 -2
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Original React 18.3/19 components for TypeScript and Next.js App Router. Native
4
4
  HTML semantics and refs, no third-party component library or Tailwind dependency.
5
5
 
6
- This package documents the **0.2.3** API. Keep Flood package versions aligned and follow the guide matching
6
+ This package documents the **0.2.5** source API. Keep Flood package versions aligned and follow the guide matching
7
7
  your installed declarations; source changes do not modify an existing npm release.
8
8
 
9
9
  ```tsx
@@ -314,11 +314,16 @@ Available in 0.2.3. Use matching installed declarations.
314
314
 
315
315
  Field and Fieldset accept hideLabel (false by default). It visually hides the real
316
316
  Label or legend, preserving its association and accessible name, while removing
317
- the label's layout row and spacing. The required label/legend prop remains required.
317
+ the label's layout row and spacing while it has no focused descendants. The
318
+ required label/legend prop remains required.
318
319
  RadioGroup, CheckboxGroup and SegmentedControl inherit hideLabel. Required native
319
320
  controls, descriptions, error/status, group names and form behavior are unchanged.
320
321
  Keep essential instructions in a visible hint/message when they are needed.
321
- Use textual label content; do not put interactive elements inside hidden labels.
322
+ Prefer textual label content. Hidden labels/legends reveal while a descendant
323
+ has focus, then hide again when focus leaves. A supporting link in a Field label
324
+ or a control in a Fieldset first legend therefore retains visible keyboard focus;
325
+ React child state, refs and native first-legend disabled exceptions are preserved.
326
+ Do not nest another labelable control (button/input) inside a Field label.
322
327
 
323
328
  For Input/Textarea/Select/InputGroup apply hideLabel to their surrounding Field,
324
329
  not the native control. Input aria-label/aria-labelledby remain available when
@@ -507,3 +512,393 @@ The native nav ref is HTMLElement. This component does not fetch data or own URL
507
512
  ```
508
513
 
509
514
  All three are available in 0.2.3. Use Flood styles and FloodRoot for the neutral dark profile.
515
+
516
+
517
+ ## Badge, Spinner, Skeleton and Avatar · 0.2.4
518
+
519
+ These original primitives are compatible additions in the 0.2.4.
520
+ Import Flood CSS and use FloodRoot. Verify registry publication before installing.
521
+ Native span props and refs target their roots; className/style remain host overrides.
522
+
523
+ Badge is a noninteractive span: size sm/md/lg, tone neutral/accent/error/warning/
524
+ success/info and variant subtle/outline. Its text carries the meaning; color is
525
+ supplementary. It has no selection, dismissal, click-action or live-region model.
526
+ Use a separate named action when needed instead of treating it as a button.
527
+
528
+ Spinner defaults to size md and label="Loading". Localize label for standalone
529
+ status. decorative hides it and its label from assistive technology. Button
530
+ loading uses the same Spinner decoratively, inherits its icon size and retains
531
+ its accessible button name and aria-busy. Announcements belong at the appropriate
532
+ host level; do not create one live region for each decorative loading graphic.
533
+ Reduced motion stops rotation. This indicator does not measure completion.
534
+
535
+ Skeleton is always aria-hidden. shape is text/rounded/circle; width and height
536
+ accept CSS dimensions (numbers are React CSS pixels), and style overrides them.
537
+ Prefer relative dimensions. For a circle supply equal dimensions. animate defaults
538
+ true; reduced motion and forced colors stop animation. Match the final geometry;
539
+ Skeleton does not fetch, detect loading or announce changes. The host owns busy
540
+ state, loading text and replacement with real content. Do not add interactive children.
541
+
542
+ Avatar requires name, accepts src, fallback text, size sm/md/lg, shape circle/
543
+ rounded and decorative. The root exposes one named image; the internal image has
544
+ empty alt and is hidden from assistive technology. Use decorative beside an
545
+ already visible equivalent name. Defaults use the first letters of the first two
546
+ whitespace-separated name parts; override fallback for your locale or naming rules.
547
+ The image overlays the fallback only after successful load; an error retains the
548
+ fallback. A new src remounts the image load state, including returning to an earlier
549
+ source. The root stays the same size. This API does not upload or crop images.
550
+
551
+ ```tsx
552
+ <Badge tone="success">Active</Badge>
553
+ <Spinner label="Loading workspace" />
554
+ <Skeleton width="12rem" />
555
+ <Avatar name="Alex Morgan" src="/team/alex.webp" />
556
+ ```
557
+
558
+
559
+ ## Progress, Meter and Alert · 0.2.4
560
+
561
+ Progress describes task completion. label is required; max defaults to 100 and
562
+ value is a finite number in 0..max. Omit value for indeterminate progress; its
563
+ progressbar then omits aria-valuenow. Meter describes a measurement in a bounded
564
+ range, such as storage or battery. It requires value, with min=0 and max=100 by
565
+ default. Require finite min < max, a finite range span, and min <= value <= max.
566
+ Invalid ranges/values throw RangeError; they are not silently clamped.
567
+
568
+ Both support size sm/md/lg, semantic tone, hideLabel and valueText. Tone defaults
569
+ to accent for Progress and neutral for Meter. valueText supplies localized,
570
+ human-readable units; it also appears beside the caption. hideLabel visually
571
+ hides the caption while retaining the accessible name and valueText. The bar's
572
+ role is progressbar or meter; neither becomes a live region. Native div props,
573
+ className/style and HTMLDivElement ref target the wrapper; the internal bar owns
574
+ its ARIA range and label associations. Wrapper ARIA props stay on the wrapper; use valueText for range-specific wording. No keyboard model,
575
+ threshold calculation, fetching, timers or task cancellation is built in.
576
+ Reduced motion stops indeterminate movement and value transitions. Forced colors
577
+ preserves the track boundary and fill. Use a host loading message when needed.
578
+
579
+ Alert is an inline message, with optional plain-text title and React children.
580
+ Tones are neutral/info/success/warning/error; info is the default. Meaning must
581
+ remain in the text. Original decorative status glyphs are included; icon accepts
582
+ noninteractive host artwork, and icon={null} removes it without an empty column.
583
+ The title is message content, not the root's HTML title tooltip or a document heading.
584
+ Native div props/className/style/ref target the root.
585
+
586
+ announcement defaults to off for static messages. polite uses role=status;
587
+ assertive uses role=alert. Choose urgency deliberately for dynamically inserted
588
+ content. Announcements depend on actual assistive technology; initial static
589
+ markup is not guaranteed to be read aloud. No focus movement, auto-dismiss,
590
+ timeout or built-in close/action button is supplied. Compose named host actions
591
+ inside children when needed. Alert is separate from Dialog and future Toast.
592
+
593
+ See the [WAI Meter pattern](https://www.w3.org/WAI/ARIA/apg/patterns/meter/),
594
+ [Alert pattern](https://www.w3.org/WAI/ARIA/apg/patterns/alert/) and
595
+ [progressbar definition](https://www.w3.org/TR/wai-aria-1.2/#progressbar).
596
+
597
+ ```tsx
598
+ <Progress label="Uploading files" value={60} valueText="60%" />
599
+ <Progress label="Preparing workspace" />
600
+ <Meter label="Storage used" min={0} max={100} value={75} valueText="75 of 100 GB" />
601
+ <Alert tone="warning" title="Storage is almost full">
602
+ Free some space before your next upload.
603
+ </Alert>
604
+ ```
605
+
606
+
607
+ ## DescriptionList and Table · 0.2.4
608
+
609
+ DescriptionList renders native dl groups, each with dt and dd. items is a readonly
610
+ array of {id, term, description}; IDs must be unique and nonempty, and are React
611
+ keys rather than DOM anchors. term is text and description is ReactNode, so a
612
+ value can include a Badge, Link or other meaningful content. The host formats
613
+ values and supplies fallback text for missing data. An empty items array stays
614
+ an empty list, without invented placeholder content. Native dl props,
615
+ className/style and HTMLDListElement ref target the list.
616
+
617
+ layout defaults inline: term and value share a row. It becomes stacked below a
618
+ 22rem component container width, independently of viewport width. layout=stacked
619
+ always puts the value below its term. Density defaults compact; comfortable adds
620
+ space between pairs, without inflating the term/value relationship. dividers is
621
+ false by default and adds quiet separators when enabled. This is not an editable
622
+ form and its terms do not label controls; use Field/Fieldset for form inputs.
623
+
624
+ Table wraps an actual HTML table in Flood's horizontal ScrollArea. caption is
625
+ required and must be meaningful; hideCaption visually hides it without removing
626
+ the accessible table name. children owns native thead/tbody/tfoot/colgroup markup
627
+ and th/td associations. Supply scope=col or scope=row for simple headers, and
628
+ explicit id/headers associations for complex spanning headers. Do not add another
629
+ caption child. See [WAI table guidance](https://www.w3.org/WAI/tutorials/tables/).
630
+
631
+ Table density defaults comfortable; compact reduces vertical cell padding.
632
+ striped is false by default. Native tfoot rows use a quiet tinted background and
633
+ medium-weight text to distinguish summaries; the top separator stays decorative.
634
+ data-numeric on a th or td uses logical end alignment,
635
+ tabular figures and no wrapping for numbers. data-align=start/center/end overrides
636
+ alignment explicitly. Text cells wrap; set style.minWidth to preserve room for a
637
+ wide table, and the containing ScrollArea handles overflow. The host owns dates,
638
+ units, totals, empty rows/colSpan and any cell actions. Avoid interactive whole rows.
639
+
640
+ Native table props, className/style and HTMLTableElement ref target the table,
641
+ not its viewport. dir/lang/hidden also govern the containing scroll area.
642
+ scrollLabel names that viewport independently and defaults to caption. The native
643
+ table keeps its own caption; viewport keyboard scrolling does not turn it into a
644
+ grid widget. Keep action controls inside cells normally focusable. No sorting,
645
+ selection, data fetching, pagination, sticky header or virtualization is implied.
646
+ This is the compositional table primitive, not a DataTable engine.
647
+
648
+ ```tsx
649
+ <DescriptionList items={[
650
+ {id:"project",term:"Project",description:"Flood"},
651
+ {id:"version",term:"Version",description:"0.2.4"},
652
+ ]} />
653
+ <Table caption="Workspace projects" style={{minWidth:"32rem"}}>
654
+ <thead><tr><th scope="col">Project</th><th scope="col" data-numeric>Members</th></tr></thead>
655
+ <tbody><tr><th scope="row">Flood</th><td data-numeric>12</td></tr></tbody>
656
+ </Table>
657
+ ```
658
+
659
+
660
+ ## Menu · 0.2.4
661
+
662
+ Menu is an original action menu using Flood's positioning/layer stack and the
663
+ native Popover API. label names the menu; there is no extra visible caption.
664
+ trigger is a render function receiving OverlayTriggerProps: forward all props
665
+ and ref to one persistent Button/IconButton/native button, and compose existing
666
+ handlers rather than replacing the supplied ones. The trigger exposes
667
+ aria-haspopup=menu, aria-expanded and aria-controls. disabled affects the trigger,
668
+ not actions inside a menu the controlled host keeps open.
669
+
670
+ items is a readonly array of action items {id,label,icon?,shortcut?,disabled?,tone?}
671
+ or separators {id,type:"separator"}. IDs must be unique and nonempty, action
672
+ labels nonempty, and at least one action must exist. The optional item type is
673
+ item. Icons must be decorative, noninteractive artwork. shortcut is display-only,
674
+ not an installed keyboard binding or part of the accessible action name. Destructive
675
+ actions use tone=danger; that visual treatment does not perform confirmation or
676
+ execute any business operation. Disabled items remain focusable with aria-disabled,
677
+ but neither pointer nor keyboard activation calls onAction or closes the menu.
678
+
679
+ Enter/Space/ArrowDown open at the first action; ArrowUp opens at the last.
680
+ Inside: Up/Down wrap, Home/End choose edges, printable label-prefix typeahead
681
+ matches items (repeated characters cycle). Separators are not focusable. Enter
682
+ or Space activates through a native button. Escape closes the top menu and
683
+ returns focus. Tab moves to the next focusable control after the trigger;
684
+ Shift+Tab returns to the trigger. The menu does not trap focus. Outside pointer
685
+ or focus departure requests dismissal and preserves deliberately moved focus.
686
+
687
+ open/onOpenChange is controlled, or use defaultOpen for initial local state.
688
+ The host may refuse a close request. onAction(id) requests closing before calling
689
+ the host; the host owns business logic, asynchronous work and errors. If it moves
690
+ focus elsewhere or opens a Dialog, normal focus restoration must not steal it.
691
+ Actions mount while open and unmount on close. The persistent popup ref and native
692
+ div props/className/style target its panel. Engine-owned coordinates and available
693
+ space variables belong to positioning; side/align follow Popover conventions.
694
+ controlSize is sm/md/lg/xl (sm default); pointer-coarse targets retain touch size.
695
+
696
+ The popup uses Flood ScrollArea for long action lists, bounded to the available
697
+ viewport. Its inner corners follow shell padding and border geometry. Focus is
698
+ inset to stay visible. There is no href/navigation-item, submenu, checkbox/radio,
699
+ context-menu trigger or menubar contract in this first action-menu component.
700
+ Use ordinary Link for ordinary navigation; keep different selection models separate.
701
+
702
+ See [WAI Menu Button](https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/) and
703
+ [Menu keyboard patterns](https://www.w3.org/WAI/ARIA/apg/patterns/menubar/).
704
+
705
+ ```tsx
706
+ <Menu label="Project actions"
707
+ trigger={props => <Button {...props}>Project actions</Button>}
708
+ items={[{id:"rename",label:"Rename…"},{id:"divider",type:"separator"},
709
+ {id:"delete",label:"Delete project",tone:"danger"}]}
710
+ onAction={id => chooseProjectAction(id)}
711
+ />
712
+ ```
713
+
714
+ ### Toolbar and Kbd (0.2.4)
715
+
716
+ Toolbar groups Button, IconButton, Toggle, native buttons/links and Menu triggers
717
+ under one named action panel. After hydration it uses one Tab entry, directional
718
+ arrows, Home/End and optional looping. Disabled/hidden actions are skipped. Arrows
719
+ move focus, not activation. Horizontal order follows writing direction. In vertical
720
+ toolbars open Menu with Enter/Space; horizontal menus retain Up/Down opening.
721
+ Keep text inputs and independent selection widgets outside this action-only API.
722
+ Native child handlers and refs remain attached; Toolbar owns their tabIndex while
723
+ mounted and restores original attributes on cleanup. Without JavaScript, native
724
+ child Tab order remains available. Use a meaningful required label.
725
+
726
+ Kbd renders native kbd markup with sm/md/lg sizes and relative keycap heights.
727
+ It displays a key or combination; the host implements real shortcuts. It is not
728
+ interactive. Menu shortcut hints reuse Kbd and remain hidden from item names.
729
+
730
+ ```tsx
731
+ <Toolbar label="Editor actions">
732
+ <Button variant="ghost">Undo</Button>
733
+ <Toggle variant="ghost">Bold</Toggle>
734
+ <Button variant="ghost">Share</Button>
735
+ </Toolbar>
736
+ <Kbd>Ctrl</Kbd> + <Kbd>K</Kbd>
737
+ ```
738
+
739
+ ### Card (0.2.4)
740
+
741
+ Card composes Surface into a header, body and footer. Optional title, description,
742
+ actions and footer accept React content; children are the body. Missing slots
743
+ create no empty section. Use Surface when only a background/padding is needed.
744
+
745
+ Card is a noninteractive div. Put Button, Link or Menu in actions/footer and keep
746
+ its container out of the Tab order. Do not make the entire card clickable around
747
+ nested controls. Native div props, styles and HTMLDivElement ref target the root.
748
+ The title prop is heading content, not an HTML tooltip; supply phrasing content.
749
+ headingLevel defaults to 2; choose the correct hierarchy for the host page.
750
+
751
+ Compact/comfortable density controls existing spacing tokens. Header actions wrap
752
+ without clipping menus or focus indicators. Footer uses a quiet separator; a
753
+ footer-only card has no redundant separator. Elevation is default or raised.
754
+ No data access, selection or interactive-card behavior is implied.
755
+
756
+ ```tsx
757
+ <Card title="Project details" description="Keep your team in sync."
758
+ footer={<Button variant="subtle">Open project</Button>}>
759
+ <Text as="p" size="compact">A calm place for the next idea.</Text>
760
+ </Card>
761
+ ```
762
+
763
+ ## Structural, media and accessible primitives · 0.2.4
764
+
765
+ Container centers a max-width box with logical gutters. size sm/md/lg uses
766
+ 40/64/80rem bounds including padding; full removes the max. gutter uses Space.
767
+ Grid defaults to auto-fit with a16rem semantic minimum clamped to available
768
+ width. gap uses Space. minItemWidth overrides the auto minimum; explicit columns
769
+ (1/2/3/4/6/12) remain fixed. Grid is ordinary layout, never an ARIA grid widget.
770
+
771
+ VisuallyHidden preserves content in the accessibility tree using span/div. Default
772
+ is for noninteractive content. Use focusable for a skip link: focus-within reveals
773
+ its wrapper; style the actual link's focus. This is different from aria-hidden or
774
+ conditional rendering. Native captions/legends may use the same hiding utility
775
+ without an invalid generic wrapper. Spinner and hidden indicator captions compose
776
+ VisuallyHidden.
777
+
778
+ AspectRatio reserves responsive media geometry before loading, accepting a finite
779
+ positive ratio (16/9 default). Direct img/video/iframe children fill its box. It
780
+ does not clip focus or make arbitrary long content fit; the host owns alternative
781
+ text, captions, media controls and deliberate cropping. Image is a native img
782
+ with required alt (empty for decorative content), cover/contain fit and preserved
783
+ srcSet/sizes/loading/decoding/dimensions/events/ref. No optimizer, fetch engine or
784
+ fallback is implied. Avatar composes Image for its own loading lifecycle. Supply
785
+ image dimensions or AspectRatio to reserve space.
786
+
787
+ List renders native ul/ol with native li children and token gap. ordered selects
788
+ ol; start/reversed apply there. start must be a safe integer. marker=false retains
789
+ explicit list semantics for platforms that drop lists without visible markers.
790
+ This is content, not ListBox selection or arrow navigation.
791
+
792
+ EmptyState composes Stack, Heading, Text, IconSlot and Inline. Required title,
793
+ optional description, decorative icon and actions explain absent content; choose
794
+ headingLevel for the host hierarchy. It is static, with no automatic focus or
795
+ announcement. compact/comfortable density controls padding. The host implements
796
+ real actions and decides whether asynchronously changed results need announcing.
797
+
798
+ Checkbox adds indeterminate for a host-controlled mixed presentation after
799
+ hydration. checked independently determines form submission; mixed does not mean
800
+ a third submitted value. The host owns aggregate/select-all values. Native reset
801
+ and ref access remain available. Radio and Switch do not expose indeterminate.
802
+
803
+ ButtonGroup/ToggleGroup retain their keyboard contracts and locally scroll when
804
+ a connected row cannot fit. InputGroup actions keep words intact and can wrap to
805
+ a new row while the input retains usable space. Plain string adornments are bidi
806
+ isolated; for protocols/phones with explicit direction pass a bdi dir=ltr node.
807
+ Keep very long addon content concise. Hidden native choices hide their label too.
808
+
809
+ Dark foundations bundle both normal and italic Inter, including Cyrillic, with
810
+ original OFL notices. Color alone never communicates validation or progress.
811
+
812
+ CodeSnippet codeDirection defaults to ltr independently of RTL parent action layout; choose rtl/auto explicitly for content that needs it. Native dir still applies to the wrapper. Protected ScrollArea reveals focused descendants fully when needed, composes the host focus handler and avoids scrolling to nested top-layer controls.
813
+
814
+ Checkbox, Radio and Switch apply native hidden/dir/lang to their visible label wrapper as well as the input, so a component-local language/direction applies to its whole choice.
815
+
816
+
817
+ 0.2.5 adds NumberInput (native numeric editing and integrated step actions) and Slider (one value or an ordered pair). Use matching declarations and the numeric controls guide in docs/base-components.md. Registry publication is separate from source availability.
818
+
819
+ Combobox adds editable single selection in 0.2.5. Reuse Field for the
820
+ label, use options with stable value/label pairs, and observe onValueChange for
821
+ the selected ID. Search query text is not form data. See docs/base-components.md
822
+ for reset, required, read-only, localized messages and native Popover requirements.
823
+
824
+ Tag and MultiSelect are compatible additions in 0.2.5.
825
+ Tag labels an item and optionally requests host-owned removal. MultiSelect uses
826
+ arrays of stable option IDs and composes those tags with the shared searchable
827
+ selection model. See docs/base-components.md for keyboard behavior, locked values,
828
+ readonly/required forms, focus recovery and relative nested geometry. Existing
829
+ Combobox continues to accept and return a single string.
830
+
831
+
832
+ SearchInput and PasswordInput join 0.2.5. Both compose
833
+ InputGroup with native input props, Field feedback, ref, sizes and form ownership.
834
+ SearchInput uses type=search and a decorative leading icon; clearable defaults to
835
+ true and clearLabel names its sole suffix action. Clearing dispatches native input
836
+ editing, restores input focus and respects read-only/disabled. The host owns search
837
+ results and submission. PasswordInput keeps one visibility action; use
838
+ visible/onVisibleChange or defaultVisible, and localize showPasswordLabel and
839
+ hidePasswordLabel. Revealing retains the value and caret; read-only permits reveal.
840
+ Use autocomplete appropriate to the host form. Both accept accessible names via
841
+ Field, aria-label or aria-labelledby. These controls add no authentication logic.
842
+
843
+
844
+ FileInput (0.2.5) composes a native file input with Flood field geometry,
845
+ IconSlot and one optional clear IconButton. Pass Field's render props for its
846
+ accessible name/description/status. Native name, form, required, accept, multiple,
847
+ capture and input ref remain available. onChange is a native React change handler;
848
+ onFilesChange receives a new readonly File array for selection and clear. Do not
849
+ pass value/defaultValue/readOnly; FileList belongs to the browser. Uncontrolled
850
+ form reset clears the summary; cancelling the chooser keeps its prior selection.
851
+ Localize placeholder and clearLabel. Long names truncate visually, and the host
852
+ owns upload, file validation and progress. accept only guides the chooser.
853
+
854
+
855
+ FileInput multiple selection exposes a collapsible file list with full names and
856
+ localized file sizes (lang controls number formatting), and a count in the picker.
857
+ Translate selectionLabel and removeFileLabel. Individual removal updates the native
858
+ FileList through DataTransfer, then emits the same change callbacks as selection.
859
+ Focus moves to the next/previous remove action, or back to the input when empty.
860
+ clearable=false disables individual and global removal UI. In multiple mode, picking again appends files to the current selection; cancel
861
+ preserves it. Repeated files are deduplicated by name, size, type, lastModified and
862
+ relative path, without reading their contents. Single mode replaces its selection. The host remains responsible for upload.
863
+
864
+
865
+ AlertDialog (0.2.5) is a concise confirmation, composed from Flood's
866
+ native modal layer and Button. Supply title, description, trigger and onConfirm.
867
+ Cancel receives initial focus; Escape cancels; outside clicks do not dismiss.
868
+ Tab containment, background inertness, scroll lock and return focus reuse Dialog.
869
+ Translate confirmLabel/cancelLabel. onConfirm runs before requesting close, while
870
+ onCancel covers Cancel/Escape. Use open/onOpenChange for controlled state and
871
+ confirmDisabled to disable confirmation. Callbacks are not awaited; the host owns
872
+ async requests, pending UI and errors. Use Dialog for forms/complex content.
873
+
874
+
875
+ Drawer (0.2.5) reuses Dialog's modal behavior with an edge-panel layout.
876
+ side is logical start/end (default end) or top/bottom; size sm/md/lg sets the
877
+ cross-axis extent to 20/26/34rem within the viewport. Vertical panels fill height,
878
+ horizontal panels fill width. Use footer for host-owned actions; only body content
879
+ scrolls with Flood ScrollArea. Header/close action/footer remain visible. Native
880
+ ref, controlled open/onOpenChange, outside dismissal and initialFocusRef match
881
+ Dialog. Translate closeLabel/title/description; reduced motion disables entry
882
+ animation. Closing is immediate. There is no swipe/drag gesture or auto-save logic.
883
+
884
+
885
+ The 0.2.5 separates floating surfaces from modal surfaces.
886
+ Nine additional semantic roles bring the dark profile to 193 roles; previous token
887
+ values remain intact. surface.floating is the opaque fallback;
888
+ surface.floating-translucent, border.floating, selection.floating, shadow.floating
889
+ and effect.floating blur/saturation/shadow-offset/shadow-blur define the floating
890
+ material. Select, Combobox, MultiSelect, Menu, Popover and Tooltip share it; Dialog
891
+ and Drawer retain surface.overlay. Backdrop filtering is progressive enhancement;
892
+ reduced transparency uses the opaque fill and forced colors use system colors.
893
+ Keep text opaque and evaluate it against the actual composited background.
894
+
895
+
896
+ The 0.2.5 component expansion adds native content/typography,
897
+ collection/form controls, navigation/layout and clipboard/notification primitives.
898
+ See docs/base-components.md and the per-component catalog for contracts and limits.
899
+ The CSS build assembles the original component styles into the shared stylesheet.
900
+
901
+
902
+ Section headingLevel controls native h2–h6 semantics. Its independent headingSize
903
+ uses the existing Heading roles (section/page/large/display), defaulting to section.
904
+ Keep document hierarchy meaningful when changing visual emphasis.
@@ -0,0 +1,2 @@
1
+ import type { AlertDialogProps } from "./index.js";
2
+ export declare const ConfirmationDialog: import("react").ForwardRefExoticComponent<AlertDialogProps & import("react").RefAttributes<HTMLDialogElement>>;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useRef, useState } from "react";
3
+ import { Button } from "./index.js";
4
+ import { ModalOverlay } from "./overlays.js";
5
+ export const ConfirmationDialog = forwardRef(function ConfirmationDialog({ open: controlled, defaultOpen = false, onOpenChange, onConfirm, onCancel, confirmLabel = "Continue", cancelLabel = "Cancel", confirmDisabled = false, className, ...props }, ref) {
6
+ const [local, setLocal] = useState(defaultOpen);
7
+ const cancel = useRef(null);
8
+ const request = (next) => {
9
+ if (controlled === undefined)
10
+ setLocal(next);
11
+ onOpenChange?.(next);
12
+ };
13
+ const dismiss = () => { onCancel?.(); request(false); };
14
+ return _jsx(ModalOverlay, { ...props, ref: ref, role: "alertdialog", open: controlled ?? local, onOpenChange: next => { if (next)
15
+ request(true);
16
+ else
17
+ dismiss(); }, closeOnOutsideClick: false, showCloseButton: false, initialFocusRef: cancel, className: ["flood-alert-dialog", className].filter(Boolean).join(" "), children: _jsxs("div", { className: "flood-alert-dialog__actions", children: [_jsx(Button, { ref: cancel, type: "button", variant: "subtle", onClick: dismiss, children: cancelLabel }), _jsx(Button, { type: "button", disabled: confirmDisabled, onClick: () => {
18
+ if (confirmDisabled)
19
+ return;
20
+ onConfirm();
21
+ request(false);
22
+ }, children: confirmLabel })] }) });
23
+ });
@@ -0,0 +1,5 @@
1
+ /** Keyed by src in Avatar so each source starts with its own load lifecycle. */
2
+ export declare function AvatarArtwork({ src, fallback }: {
3
+ src?: string;
4
+ fallback: string;
5
+ }): import("react").JSX.Element;
package/dist/avatar.js ADDED
@@ -0,0 +1,8 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { Image } from "./index.js";
4
+ /** Keyed by src in Avatar so each source starts with its own load lifecycle. */
5
+ export function AvatarArtwork({ src, fallback }) {
6
+ const [state, setState] = useState("loading");
7
+ return _jsxs(_Fragment, { children: [_jsx("span", { className: "flood-avatar__fallback", "aria-hidden": "true", children: fallback }), src && state !== "error" && _jsx(Image, { src: src, alt: "", "aria-hidden": "true", decoding: "async", className: "flood-avatar__image", "data-ready": state === "ready", onLoad: () => setState("ready"), onError: () => setState("error") })] });
8
+ }
@@ -0,0 +1,4 @@
1
+ import { type InputHTMLAttributes } from "react";
2
+ export declare const MixedCheckbox: import("react").ForwardRefExoticComponent<InputHTMLAttributes<HTMLInputElement> & {
3
+ indeterminate: boolean;
4
+ } & import("react").RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useRef } from "react";
3
+ const useBrowserLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
4
+ export const MixedCheckbox = forwardRef(function MixedCheckbox({ indeterminate, onChange, ...props }, ref) {
5
+ const node = useRef(null), mixed = useRef(indeterminate);
6
+ useImperativeHandle(ref, () => node.current, []);
7
+ useBrowserLayoutEffect(() => { mixed.current = indeterminate; if (node.current)
8
+ node.current.indeterminate = indeterminate; });
9
+ return _jsx("input", { ...props, ref: node, type: "checkbox", className: "flood-check", "aria-checked": indeterminate ? "mixed" : props["aria-checked"], onChange: event => { const control = event.currentTarget; try {
10
+ onChange?.(event);
11
+ }
12
+ finally {
13
+ control.indeterminate = mixed.current;
14
+ } } });
15
+ });
@@ -0,0 +1,11 @@
1
+ import { type ComboboxProps } from "./index.js";
2
+ interface SearchSelectionProps extends Omit<ComboboxProps, "value" | "defaultValue" | "onValueChange"> {
3
+ selectedValues?: readonly string[];
4
+ initialValues: readonly string[];
5
+ onSelectionChange?: (value: string[]) => void;
6
+ multiple?: boolean;
7
+ removeItemLabel?: string;
8
+ }
9
+ /** Shared search/layer model. Public single and multiple value contracts stay distinct. */
10
+ export declare const SearchSelection: import("react").ForwardRefExoticComponent<SearchSelectionProps & import("react").RefAttributes<HTMLInputElement>>;
11
+ export {};