@ahrowe/ui 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/esm/common/alert/alert.mjs +2 -0
  2. package/dist/esm/common/alert/alert.mjs.map +1 -0
  3. package/dist/esm/common/alert/alert.module.mjs +2 -0
  4. package/dist/esm/common/alert/alert.module.mjs.map +1 -0
  5. package/dist/esm/common/alert/alert.types.mjs +2 -0
  6. package/dist/esm/common/alert/alert.types.mjs.map +1 -0
  7. package/dist/esm/common/animatedIcon/animatedIcon.mjs +2 -0
  8. package/dist/esm/common/animatedIcon/animatedIcon.mjs.map +1 -0
  9. package/dist/esm/common/animatedIcon/animatedIcon.module.mjs +2 -0
  10. package/dist/esm/common/animatedIcon/animatedIcon.module.mjs.map +1 -0
  11. package/dist/esm/common/breadcrumb/breadcrumb.mjs +2 -0
  12. package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -0
  13. package/dist/esm/common/breadcrumb/breadcrumb.module.mjs +2 -0
  14. package/dist/esm/common/breadcrumb/breadcrumb.module.mjs.map +1 -0
  15. package/dist/esm/common/buttonGroup/buttonGroup.mjs +2 -0
  16. package/dist/esm/common/buttonGroup/buttonGroup.mjs.map +1 -0
  17. package/dist/esm/common/buttonGroup/buttonGroup.module.mjs +2 -0
  18. package/dist/esm/common/buttonGroup/buttonGroup.module.mjs.map +1 -0
  19. package/dist/esm/common/buttonGroup/buttonGroup.types.mjs +2 -0
  20. package/dist/esm/common/buttonGroup/buttonGroup.types.mjs.map +1 -0
  21. package/dist/esm/common/carousel/carousel.mjs +2 -0
  22. package/dist/esm/common/carousel/carousel.mjs.map +1 -0
  23. package/dist/esm/common/carousel/carousel.module.mjs +2 -0
  24. package/dist/esm/common/carousel/carousel.module.mjs.map +1 -0
  25. package/dist/esm/common/divider/divider.mjs +1 -1
  26. package/dist/esm/common/divider/divider.mjs.map +1 -1
  27. package/dist/esm/common/divider/divider.module.mjs +1 -1
  28. package/dist/esm/common/divider/divider.module.mjs.map +1 -1
  29. package/dist/esm/common/divider/divider.types.mjs +1 -1
  30. package/dist/esm/common/divider/divider.types.mjs.map +1 -1
  31. package/dist/esm/common/dropdown/dropdown.module.mjs +1 -1
  32. package/dist/esm/common/dropdown/dropdown.module.mjs.map +1 -1
  33. package/dist/esm/common/fab/fab.mjs +1 -1
  34. package/dist/esm/common/fab/fab.mjs.map +1 -1
  35. package/dist/esm/common/floatingMenu/floatingMenu.mjs +1 -1
  36. package/dist/esm/common/floatingMenu/floatingMenu.mjs.map +1 -1
  37. package/dist/esm/common/floatingMenu/floatingMenu.module.mjs.map +1 -1
  38. package/dist/esm/common/hooks/useFocusBoundary.mjs +2 -0
  39. package/dist/esm/common/hooks/useFocusBoundary.mjs.map +1 -0
  40. package/dist/esm/common/input/input.mjs +1 -1
  41. package/dist/esm/common/input/input.mjs.map +1 -1
  42. package/dist/esm/common/input/input.module.mjs +1 -1
  43. package/dist/esm/common/input/input.module.mjs.map +1 -1
  44. package/dist/esm/common/input/input.types.mjs +1 -1
  45. package/dist/esm/common/input/input.types.mjs.map +1 -1
  46. package/dist/esm/common/klipyPicker/klipyPicker.mjs +1 -1
  47. package/dist/esm/common/klipyPicker/klipyPicker.mjs.map +1 -1
  48. package/dist/esm/common/numberInput/numberInput.mjs +1 -1
  49. package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
  50. package/dist/esm/common/popover/popover.mjs +1 -1
  51. package/dist/esm/common/popover/popover.mjs.map +1 -1
  52. package/dist/esm/common/rating/rating.mjs +2 -0
  53. package/dist/esm/common/rating/rating.mjs.map +1 -0
  54. package/dist/esm/common/rating/rating.module.mjs +2 -0
  55. package/dist/esm/common/rating/rating.module.mjs.map +1 -0
  56. package/dist/esm/common/splitButton/splitButton.mjs +2 -0
  57. package/dist/esm/common/splitButton/splitButton.mjs.map +1 -0
  58. package/dist/esm/common/splitButton/splitButton.module.mjs +2 -0
  59. package/dist/esm/common/splitButton/splitButton.module.mjs.map +1 -0
  60. package/dist/esm/common/virtualList/useRowDrag.mjs +1 -1
  61. package/dist/esm/common/virtualList/useRowDrag.mjs.map +1 -1
  62. package/dist/esm/common/virtualList/useVirtualWindow.mjs +1 -1
  63. package/dist/esm/common/virtualList/useVirtualWindow.mjs.map +1 -1
  64. package/dist/esm/common/virtualList/virtualList.mjs +1 -1
  65. package/dist/esm/common/virtualList/virtualList.mjs.map +1 -1
  66. package/dist/esm/common/virtualList/virtualRow.mjs +1 -1
  67. package/dist/esm/common/virtualList/virtualRow.mjs.map +1 -1
  68. package/dist/esm/index.mjs +1 -1
  69. package/dist/index.cjs +4 -4
  70. package/dist/index.cjs.map +1 -1
  71. package/dist/style.css +1 -1
  72. package/dist/types/package/common/alert/alert.d.ts +4 -0
  73. package/dist/types/package/common/alert/alert.types.d.ts +23 -0
  74. package/dist/types/package/common/alert/index.d.ts +2 -0
  75. package/dist/types/package/common/animatedIcon/animatedIcon.d.ts +3 -0
  76. package/dist/types/package/common/animatedIcon/animatedIcon.types.d.ts +25 -0
  77. package/dist/types/package/common/animatedIcon/index.d.ts +2 -0
  78. package/dist/types/package/common/breadcrumb/breadcrumb.d.ts +4 -0
  79. package/dist/types/package/common/breadcrumb/breadcrumb.types.d.ts +26 -0
  80. package/dist/types/package/common/breadcrumb/index.d.ts +2 -0
  81. package/dist/types/package/common/buttonGroup/buttonGroup.d.ts +4 -0
  82. package/dist/types/package/common/buttonGroup/buttonGroup.types.d.ts +12 -0
  83. package/dist/types/package/common/buttonGroup/index.d.ts +2 -0
  84. package/dist/types/package/common/carousel/carousel.d.ts +3 -0
  85. package/dist/types/package/common/carousel/carousel.types.d.ts +20 -0
  86. package/dist/types/package/common/carousel/index.d.ts +2 -0
  87. package/dist/types/package/common/configProvider/configProvider.types.d.ts +10 -0
  88. package/dist/types/package/common/divider/divider.types.d.ts +5 -0
  89. package/dist/types/package/common/hooks/useFocusBoundary.d.ts +20 -0
  90. package/dist/types/package/common/input/input.types.d.ts +5 -0
  91. package/dist/types/package/common/rating/index.d.ts +2 -0
  92. package/dist/types/package/common/rating/rating.d.ts +4 -0
  93. package/dist/types/package/common/rating/rating.types.d.ts +19 -0
  94. package/dist/types/package/common/splitButton/index.d.ts +2 -0
  95. package/dist/types/package/common/splitButton/splitButton.d.ts +3 -0
  96. package/dist/types/package/common/splitButton/splitButton.types.d.ts +28 -0
  97. package/dist/types/package/common/themeProvider/theme.types.d.ts +1 -0
  98. package/dist/types/package/common/virtualList/useRowDrag.d.ts +4 -0
  99. package/dist/types/package/common/virtualList/useVirtualWindow.d.ts +3 -1
  100. package/dist/types/package/common/virtualList/virtualList.types.d.ts +5 -1
  101. package/dist/types/package/common/virtualList/virtualRow.d.ts +8 -1
  102. package/dist/types/package/index.d.ts +12 -0
  103. package/docs/Alert.md +64 -0
  104. package/docs/Breadcrumb.md +106 -0
  105. package/docs/ButtonGroup.md +90 -0
  106. package/docs/CLAUDE.md +6 -0
  107. package/docs/Carousel.md +67 -0
  108. package/docs/Divider.md +15 -3
  109. package/docs/FloatingMenu.md +7 -3
  110. package/docs/Input.md +30 -6
  111. package/docs/NumberInput.md +2 -0
  112. package/docs/Rating.md +72 -0
  113. package/docs/SearchInput.md +6 -0
  114. package/docs/SplitButton.md +79 -0
  115. package/docs/VirtualList.md +86 -3
  116. package/package.json +1 -1
@@ -18,6 +18,11 @@ import { SectionHeaderProps } from '../sectionHeader/sectionHeader.types';
18
18
  import { SkeletonProps } from '../skeleton/skeleton.types';
19
19
  import { AccordionProps } from '../accordion/accordion.types';
20
20
  import { DividerProps } from '../divider/divider.types';
21
+ import { AlertProps } from '../alert/alert.types';
22
+ import { CarouselProps } from '../carousel/carousel.types';
23
+ import { BreadcrumbProps } from '../breadcrumb/breadcrumb.types';
24
+ import { RatingProps } from '../rating/rating.types';
25
+ import { SplitButtonProps } from '../splitButton/splitButton.types';
21
26
  /**
22
27
  * Global default props keyed by component name.
23
28
  *
@@ -52,6 +57,11 @@ export interface ComponentDefaults {
52
57
  Skeleton?: Partial<SkeletonProps>;
53
58
  Accordion?: Partial<AccordionProps>;
54
59
  Divider?: Partial<DividerProps>;
60
+ Alert?: Partial<AlertProps>;
61
+ Carousel?: Partial<CarouselProps>;
62
+ Breadcrumb?: Partial<BreadcrumbProps>;
63
+ Rating?: Partial<RatingProps>;
64
+ SplitButton?: Partial<SplitButtonProps>;
55
65
  }
56
66
  export interface ConfigProviderProps {
57
67
  children: React.ReactNode;
@@ -5,10 +5,15 @@ export declare enum DividerTextPosition {
5
5
  Center = "center",
6
6
  Right = "right"
7
7
  }
8
+ export declare enum DividerOrientation {
9
+ Horizontal = "horizontal",
10
+ Vertical = "vertical"
11
+ }
8
12
  export type DividerSlots = 'root' | 'line' | 'content';
9
13
  export interface DividerProps extends HtmlProps {
10
14
  text?: ReactNode;
11
15
  textPosition?: DividerTextPosition;
16
+ orientation?: DividerOrientation;
12
17
  className?: string;
13
18
  style?: CSSProperties;
14
19
  classNames?: SlotClassNames<DividerSlots>;
@@ -0,0 +1,20 @@
1
+ import { RefObject } from 'react';
2
+ /** Tabbable descendants of `root`, in DOM order. */
3
+ export declare function tabbablesIn(root: ParentNode | null): HTMLElement[];
4
+ export interface UseFocusBoundaryArgs {
5
+ /** The trigger element focus returns to on Escape / Shift+Tab out of the content's top. */
6
+ triggerRef: RefObject<HTMLElement | null>;
7
+ /** The portaled content root — tabbables inside it define the Tab boundary. */
8
+ contentRef: RefObject<HTMLElement | null>;
9
+ }
10
+ /**
11
+ * Focus helpers for content portaled to the end of the DOM (e.g. via BodyEnd), where Tab can't
12
+ * reach it in visual document order on its own. Shared by FloatingMenu and Popover, which both
13
+ * need to hand focus back to the trigger on Escape / Shift+Tab out of the top, and continue
14
+ * focus naturally past the trigger when Tab exits the bottom.
15
+ */
16
+ export declare function useFocusBoundary({ triggerRef, contentRef }: UseFocusBoundaryArgs): {
17
+ firstTriggerFocusable: () => HTMLElement | null;
18
+ restoreFocusToTrigger: () => void;
19
+ focusAfterTrigger: () => void;
20
+ };
@@ -11,6 +11,10 @@ export declare enum InputType {
11
11
  Search = "searchInput",
12
12
  Password = "password"
13
13
  }
14
+ export declare enum InputIconPosition {
15
+ Left = "left",
16
+ Right = "right"
17
+ }
14
18
  export type InputSlots = 'label' | 'container' | 'input' | 'suffix' | 'upperRightLabel' | 'fieldset';
15
19
  type OverriddenInputAttributes = 'onChange' | 'onFocus' | 'onBlur' | 'onMouseEnter' | 'onMouseLeave' | 'onClick' | 'type' | 'value' | 'min' | 'max' | 'autoComplete';
16
20
  export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, OverriddenInputAttributes>, HtmlProps {
@@ -28,6 +32,7 @@ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElem
28
32
  style?: React.CSSProperties;
29
33
  value?: string | number;
30
34
  icon?: React.ReactElement | null;
35
+ iconPosition?: InputIconPosition;
31
36
  isUppercase?: boolean;
32
37
  isRow?: boolean;
33
38
  tabIndex?: number;
@@ -0,0 +1,2 @@
1
+ export { default } from './rating';
2
+ export * from './rating.types';
@@ -0,0 +1,4 @@
1
+ import { ReactElement } from 'react';
2
+ import { RatingProps } from './rating.types';
3
+ declare function Rating(props: RatingProps): ReactElement;
4
+ export default Rating;
@@ -0,0 +1,19 @@
1
+ import { CSSProperties } from 'react';
2
+ import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
3
+ import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
4
+ export type RatingSlots = 'root' | 'item' | 'iconEmpty' | 'iconFilled';
5
+ export interface RatingProps extends HtmlProps {
6
+ value?: number;
7
+ defaultValue?: number;
8
+ onChange?: (value: number) => void;
9
+ max?: number;
10
+ allowHalf?: boolean;
11
+ allowClear?: boolean;
12
+ readOnly?: boolean;
13
+ disabled?: boolean;
14
+ icon?: IconDefinition;
15
+ className?: string;
16
+ style?: CSSProperties;
17
+ classNames?: SlotClassNames<RatingSlots>;
18
+ styles?: SlotStyles<RatingSlots>;
19
+ }
@@ -0,0 +1,2 @@
1
+ export { default } from './splitButton';
2
+ export * from './splitButton.types';
@@ -0,0 +1,3 @@
1
+ import { SplitButtonProps } from './splitButton.types';
2
+ declare function SplitButton(props: SplitButtonProps): import("react/jsx-runtime").JSX.Element;
3
+ export default SplitButton;
@@ -0,0 +1,28 @@
1
+ import { CSSProperties, ReactNode } from 'react';
2
+ import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
3
+ import { ButtonStyleType, ButtonSize } from '../button/button.types';
4
+ import { Align } from '../floatingMenu/floatingMenu.types';
5
+ import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
6
+ export interface SplitButtonAction {
7
+ id: string;
8
+ label: ReactNode;
9
+ onClick: () => void;
10
+ disabled?: boolean;
11
+ icon?: IconDefinition;
12
+ }
13
+ export type SplitButtonSlots = 'root' | 'primaryButton' | 'triggerButton' | 'menu' | 'menuItem';
14
+ export interface SplitButtonProps extends HtmlProps {
15
+ children?: ReactNode;
16
+ onClick?: (event: React.MouseEvent<HTMLButtonElement>) => Promise<void> | void;
17
+ actions: SplitButtonAction[];
18
+ styleType?: ButtonStyleType;
19
+ size?: ButtonSize;
20
+ disabled?: boolean;
21
+ isLoading?: boolean;
22
+ /** Alignment of the actions menu relative to the trigger button (default `Align.Right`) */
23
+ align?: Align;
24
+ className?: string;
25
+ style?: CSSProperties;
26
+ classNames?: SlotClassNames<SplitButtonSlots>;
27
+ styles?: SlotStyles<SplitButtonSlots>;
28
+ }
@@ -56,6 +56,7 @@ export interface ThemeVariables {
56
56
  '--error-border-color'?: string;
57
57
  '--input-label-resting-color'?: string;
58
58
  '--input-label-floating-color'?: string;
59
+ '--search-input-color'?: string;
59
60
  '--default-border-radius'?: string;
60
61
  '--padding-sides'?: string;
61
62
  '--margin-top'?: string;
@@ -19,9 +19,13 @@ interface UseRowDragArgs {
19
19
  /** The drag-related props the parent spreads onto a given row. */
20
20
  export interface RowDragProps {
21
21
  reorderable: boolean;
22
+ /** Native mouse DnD is active for the list (independent of which row is armed). */
23
+ mouseDragEnabled: boolean;
22
24
  draggable: boolean | undefined;
23
25
  isDragging: boolean;
24
26
  onMouseDown: ((e: React.MouseEvent<HTMLDivElement>) => void) | undefined;
27
+ onMouseOver: ((e: React.MouseEvent<HTMLDivElement>) => void) | undefined;
28
+ onMouseLeave: ((e: React.MouseEvent<HTMLDivElement>) => void) | undefined;
25
29
  onDragStart: ((e: React.DragEvent<HTMLDivElement>) => void) | undefined;
26
30
  onDragOver: ((e: React.DragEvent<HTMLDivElement>) => void) | undefined;
27
31
  onDragEnd: (() => void) | undefined;
@@ -10,6 +10,8 @@ interface UseVirtualWindowArgs<T> {
10
10
  overscan: number;
11
11
  onLoadMore?: () => Promise<void>;
12
12
  loadMoreThreshold: number;
13
+ /** Initial/filter load in progress — the body is replaced by a spinner. */
14
+ isLoading: boolean;
13
15
  }
14
16
  interface UseVirtualWindowResult {
15
17
  rootRef: React.RefObject<HTMLDivElement | null>;
@@ -37,5 +39,5 @@ interface UseVirtualWindowResult {
37
39
  * scroll handle. Mode-agnostic — knows nothing about columns, selection or
38
40
  * dragging.
39
41
  */
40
- export declare function useVirtualWindow<T>({ items, keys, getItemKey, estimatedRowHeight, rowGap, overscan, onLoadMore, loadMoreThreshold, }: UseVirtualWindowArgs<T>): UseVirtualWindowResult;
42
+ export declare function useVirtualWindow<T>({ items, keys, getItemKey, estimatedRowHeight, rowGap, overscan, onLoadMore, loadMoreThreshold, isLoading, }: UseVirtualWindowArgs<T>): UseVirtualWindowResult;
41
43
  export {};
@@ -132,7 +132,11 @@ export interface VirtualListProps<T> extends HtmlProps {
132
132
  /** Show the gear column-toggle button in the header. Default: true when columns present. */
133
133
  showColumnToggle?: boolean;
134
134
  /**
135
- * Called when the user scrolls within `loadMoreThreshold` px of the bottom.
135
+ * Called when the user scrolls within `loadMoreThreshold` px of the bottom, and
136
+ * repeatedly while the rows don't fill the viewport — a list too short to scroll
137
+ * would otherwise never ask for a second batch. Each row count is asked at most
138
+ * once, so the loop ends as soon as a call appends nothing; pass `undefined`
139
+ * once the source is exhausted to skip even that final probe.
136
140
  * Must return a Promise that resolves once new items have been appended to `items`.
137
141
  * A spinner is shown at the bottom while the Promise is pending.
138
142
  */
@@ -16,10 +16,17 @@ export interface VirtualRowProps {
16
16
  ariaSetSize?: number;
17
17
  rowRole: 'row' | 'listitem';
18
18
  reorderable?: boolean;
19
+ /**
20
+ * Native mouse DnD is active for the list. Distinct from `draggable`, which in
21
+ * `dragHandle` mode is only set on the row the pointer has armed.
22
+ */
23
+ mouseDragEnabled?: boolean;
19
24
  draggable?: boolean;
20
25
  isDragging?: boolean;
21
26
  reserveToggleGutter?: boolean;
22
27
  onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void;
28
+ onMouseOver?: (e: React.MouseEvent<HTMLDivElement>) => void;
29
+ onMouseLeave?: (e: React.MouseEvent<HTMLDivElement>) => void;
23
30
  onDragStart?: (e: React.DragEvent<HTMLDivElement>) => void;
24
31
  onDragOver?: (e: React.DragEvent<HTMLDivElement>) => void;
25
32
  onDragEnd?: () => void;
@@ -38,5 +45,5 @@ export interface VirtualRowProps {
38
45
  * grid (table mode), registering itself with the shared ResizeObserver and
39
46
  * carrying all the drag / drop-indicator wiring the parent assigns it.
40
47
  */
41
- declare function VirtualRow({ index, top, padding, columnTemplate, isSelected, showDivider, hover, onClick, observer, ariaRowIndex, ariaPosInSet, ariaSetSize, rowRole, reorderable, draggable, isDragging, reserveToggleGutter, onMouseDown, onDragStart, onDragOver, onDragEnd, onDrop, onTouchStart, dropPosition, dropIndentPx, dropIndicatorClassName, dropIndicatorStyle, rowClassName, rowStyle, children, }: VirtualRowProps): import("react/jsx-runtime").JSX.Element;
48
+ declare function VirtualRow({ index, top, padding, columnTemplate, isSelected, showDivider, hover, onClick, observer, ariaRowIndex, ariaPosInSet, ariaSetSize, rowRole, reorderable, mouseDragEnabled, draggable, isDragging, reserveToggleGutter, onMouseDown, onMouseOver, onMouseLeave, onDragStart, onDragOver, onDragEnd, onDrop, onTouchStart, dropPosition, dropIndentPx, dropIndicatorClassName, dropIndicatorStyle, rowClassName, rowStyle, children, }: VirtualRowProps): import("react/jsx-runtime").JSX.Element;
42
49
  export default VirtualRow;
@@ -3,6 +3,8 @@ export * from './common/accordion';
3
3
  export * from './common/actionButtons';
4
4
  export { default as ActionIcon } from './common/actionIcon';
5
5
  export * from './common/actionIcon';
6
+ export { default as Alert } from './common/alert';
7
+ export * from './common/alert';
6
8
  export { default as AnimatedLogo } from './common/animatedLogo';
7
9
  export * from './common/animatedLogo';
8
10
  export { default as AnimatedText } from './common/animatedText';
@@ -13,10 +15,16 @@ export { default as Badge } from './common/badge';
13
15
  export * from './common/badge';
14
16
  export { default as BodyEnd } from './common/bodyEnd';
15
17
  export * from './common/bodyEnd';
18
+ export { default as Breadcrumb } from './common/breadcrumb';
19
+ export * from './common/breadcrumb';
16
20
  export { default as Button } from './common/button';
17
21
  export * from './common/button';
22
+ export { default as ButtonGroup } from './common/buttonGroup';
23
+ export * from './common/buttonGroup';
18
24
  export { default as Card } from './common/card';
19
25
  export * from './common/card';
26
+ export { default as Carousel } from './common/carousel';
27
+ export * from './common/carousel';
20
28
  export { default as Checkbox } from './common/checkbox';
21
29
  export * from './common/checkbox';
22
30
  export { default as Chip } from './common/chip';
@@ -74,6 +82,8 @@ export { default as ProgressBar } from './common/progressBar';
74
82
  export * from './common/progressBar';
75
83
  export { default as RadioGroup } from './common/radioGroup';
76
84
  export * from './common/radioGroup';
85
+ export { default as Rating } from './common/rating';
86
+ export * from './common/rating';
77
87
  export { default as Ripple } from './common/ripple';
78
88
  export * from './common/ripple';
79
89
  export { default as RoomDrawer } from './common/roomDrawer';
@@ -90,6 +100,8 @@ export { default as Skeleton } from './common/skeleton';
90
100
  export * from './common/skeleton';
91
101
  export { default as Slider } from './common/slider';
92
102
  export * from './common/slider';
103
+ export { default as SplitButton } from './common/splitButton';
104
+ export * from './common/splitButton';
93
105
  export { default as Stepper } from './common/stepper';
94
106
  export * from './common/stepper';
95
107
  export { default as Sticky } from './common/sticky';
package/docs/Alert.md ADDED
@@ -0,0 +1,64 @@
1
+ # Alert
2
+
3
+ **When to use:** A persistent inline status message, used for form-level errors, page/section banners, empty-config warnings, and "here's what changed" notices. Unlike `Toast`, it isn't portaled or auto-dismissed, and it stays in the page's normal flow for as long as its consumer renders it. Use `Toast` instead for a transient, corner-anchored notification.
4
+
5
+ **Import:** `import { Alert, AlertStyleType } from '@ahrowe/ui'`
6
+
7
+ **Style variants:** `AlertStyleType.Default` | `AlertStyleType.Info` | `AlertStyleType.Success` | `AlertStyleType.Warn` | `AlertStyleType.Error`
8
+
9
+ ```tsx
10
+ import { Alert, AlertStyleType } from '@ahrowe/ui';
11
+
12
+ // Default, neutral message
13
+ <Alert>A default, neutral message.</Alert>
14
+
15
+ // Semantic variants
16
+ <Alert styleType={AlertStyleType.Info}>Here's something worth knowing.</Alert>
17
+ <Alert styleType={AlertStyleType.Success}>Your changes were saved.</Alert>
18
+ <Alert styleType={AlertStyleType.Warn}>Your storage is almost full.</Alert>
19
+ <Alert styleType={AlertStyleType.Error}>Something went wrong. Please try again.</Alert>
20
+
21
+ // With a title
22
+ <Alert styleType={AlertStyleType.Warn} title="Storage almost full">
23
+ You've used 92% of your available space. Free up room or upgrade your plan.
24
+ </Alert>
25
+
26
+ // Dismissible: the consumer owns visibility. onClose is called on click,
27
+ // so stop rendering the Alert (or flip your own state) to actually hide it
28
+ const [visible, setVisible] = useState(true);
29
+ {visible && (
30
+ <Alert
31
+ styleType={AlertStyleType.Info}
32
+ title="New feature available"
33
+ onClose={() => setVisible(false)}
34
+ >
35
+ Try out the new dashboard layout from your account settings.
36
+ </Alert>
37
+ )}
38
+
39
+ // Without the leading icon
40
+ <Alert styleType={AlertStyleType.Success} hideIcon>
41
+ A minimal message with no leading icon.
42
+ </Alert>
43
+
44
+ // Custom icon, overriding the styleType default
45
+ import { faRocket } from '@fortawesome/free-solid-svg-icons';
46
+ <Alert styleType={AlertStyleType.Info} icon={faRocket}>
47
+ Shipping a new release tonight.
48
+ </Alert>
49
+ ```
50
+
51
+ **Key props:**
52
+
53
+ | Prop | Type | Description |
54
+ |------|------|-------------|
55
+ | `title` | `ReactNode` | Optional bold heading above the description |
56
+ | `children` | `ReactNode` | The message body |
57
+ | `styleType` | `AlertStyleType` | Colour variant and default icon (default `Default`) |
58
+ | `icon` | `IconDefinition` | Overrides the default FontAwesome icon for `styleType` |
59
+ | `hideIcon` | `boolean` | Hide the leading icon entirely |
60
+ | `onClose` | `() => void` | Shows a close button and is called when it's clicked. `Alert` doesn't hide itself, so stop rendering it (or update your own state) in the handler |
61
+
62
+ **Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ Alert: { hideIcon: true } }}`. See [ConfigProvider.md](ConfigProvider.md).
63
+
64
+ **Slots:** `root` `icon` `content` `title` `description` `closeButton`
@@ -0,0 +1,106 @@
1
+ # Breadcrumb
2
+
3
+ **When to use:** A trail showing the current page's position within a hierarchy, with links back to each ancestor, such as a file browser path, a category/subcategory drill-down, or a multi-level settings page. The last item is always rendered as the current page and isn't clickable.
4
+
5
+ **Import:** `import { Breadcrumb } from '@ahrowe/ui'`
6
+ **Types:** `import type { BreadcrumbItem, BreadcrumbProps } from '@ahrowe/ui'`
7
+
8
+ ```tsx
9
+ import { Breadcrumb } from '@ahrowe/ui';
10
+ import type { BreadcrumbItem } from '@ahrowe/ui';
11
+
12
+ const items: BreadcrumbItem[] = [
13
+ { label: 'Home', href: '/' },
14
+ { label: 'Documents', href: '/documents' },
15
+ { label: 'Report.pdf' }, // last item: rendered as the current page, not a link
16
+ ];
17
+
18
+ <Breadcrumb items={items} />
19
+
20
+ // With leading icons
21
+ import { faHouse, faFolder } from '@fortawesome/free-solid-svg-icons';
22
+
23
+ <Breadcrumb
24
+ items={[
25
+ { label: 'Home', href: '/', icon: faHouse },
26
+ { label: 'Projects', href: '/projects', icon: faFolder },
27
+ { label: 'Current project' },
28
+ ]}
29
+ />
30
+
31
+ // Client-side routing (e.g. react-router): keep href for a real, right-clickable link,
32
+ // and use onClick to intercept the native navigation with the router's own navigate()
33
+ import { useNavigate } from 'react-router-dom';
34
+
35
+ function Example() {
36
+ const navigate = useNavigate();
37
+ return (
38
+ <Breadcrumb
39
+ items={[
40
+ {
41
+ label: 'Home',
42
+ href: '/',
43
+ onClick: (event) => {
44
+ event.preventDefault();
45
+ navigate('/');
46
+ },
47
+ },
48
+ { label: 'Current page' },
49
+ ]}
50
+ />
51
+ );
52
+ }
53
+
54
+ // A disabled crumb: dimmed, not clickable, regardless of href/onClick
55
+ <Breadcrumb
56
+ items={[
57
+ { label: 'Home', href: '/' },
58
+ { label: 'Archived', href: '/archived', disabled: true },
59
+ { label: 'Old report' },
60
+ ]}
61
+ />
62
+
63
+ // Custom separator (default is a chevron icon)
64
+ <Breadcrumb items={items} separator="/" />
65
+
66
+ // Long trails: collapse the middle behind a clickable ellipsis once items.length
67
+ // exceeds maxItems. The ellipsis counts as one of the visible slots, so maxItems={3}
68
+ // on a 4-item trail shows: Home / ... / Settings. Clicking the ellipsis opens a menu
69
+ // (via FloatingMenu) listing the hidden items.
70
+ <Breadcrumb
71
+ items={[
72
+ { label: 'Home', href: '/' },
73
+ { label: 'Invoices', href: '/invoices' },
74
+ { label: 'Editor', href: '/invoices/editor' },
75
+ { label: 'Settings' },
76
+ ]}
77
+ maxItems={3}
78
+ />
79
+ ```
80
+
81
+ **Requires:** `<div id="bodyEnd"></div>` in your HTML when `maxItems` is used and the trail actually collapses (the hidden-items menu is a `FloatingMenu`, which renders via portal).
82
+
83
+ **BreadcrumbItem:**
84
+
85
+ | Field | Type | Description |
86
+ |-------|------|-------------|
87
+ | `id` | `string` | Optional stable key; falls back to the item's index |
88
+ | `label` | `ReactNode` | The crumb's text |
89
+ | `href` | `string` | Renders the crumb as a real `<a>`. Omit to render a plain clickable element (with `onClick`) or static text |
90
+ | `icon` | `IconDefinition` | Optional leading FontAwesome icon |
91
+ | `onClick` | `(event: MouseEvent) => void` | Click handler. Works alongside `href`: call `event.preventDefault()` to stop the native navigation and hand off to a client-side router's own navigate function (see the react-router example above). Also works on its own, with no `href` |
92
+ | `disabled` | `boolean` | Dims the crumb and makes it non-interactive, regardless of `href`/`onClick` |
93
+
94
+ **Key props:**
95
+
96
+ | Prop | Type | Description |
97
+ |------|------|-------------|
98
+ | `items` | `BreadcrumbItem[]` | The crumbs, in order. The last one is always rendered as the current page |
99
+ | `separator` | `ReactNode` | Overrides the default chevron separator between items |
100
+ | `maxItems` | `number` | Collapses the middle items behind a clickable ellipsis once `items.length` exceeds this. The ellipsis counts as one of the visible slots, alongside the always-shown first item (so `maxItems={3}` shows first item, ellipsis, last item) |
101
+
102
+ **Collapsing behaviour:** the hidden count grows and shrinks by exactly however many items are actually over the limit, rather than always jumping to the same minimal first/ellipsis/last shape. A trail with 11 items and `maxItems={10}` hides only 2 items, not the whole middle, so the trail doesn't visually lurch as one more level of navigation pushes it just over the limit.
103
+
104
+ **Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ Breadcrumb: { separator: '/' } }}`. See [ConfigProvider.md](ConfigProvider.md).
105
+
106
+ **Slots:** `root` `list` `item` `link` `icon` `separator` `current` `ellipsis` `hiddenList` `hiddenItem`
@@ -0,0 +1,90 @@
1
+ # ButtonGroup
2
+
3
+ **When to use:** Joins a row (or column) of buttons into a single seamless control, merging their borders and rounding only the outer corners. Use for a segmented toggle ("Day / Week / Month"), an icon toolbar (bold/italic/underline), or any set of related actions that should read as one control rather than separate buttons. Purely a layout wrapper, no interaction logic of its own, so any button-like children work, not just `Button`.
4
+
5
+ **Import:** `import { ButtonGroup, ButtonGroupOrientation } from '@ahrowe/ui'`
6
+
7
+ **Orientation:** `ButtonGroupOrientation.Horizontal` (default) | `ButtonGroupOrientation.Vertical`
8
+
9
+ ```tsx
10
+ import { ButtonGroup, ButtonGroupOrientation, Button, ButtonStyleType } from '@ahrowe/ui';
11
+
12
+ // Segmented toggle
13
+ <ButtonGroup>
14
+ <Button styleType={ButtonStyleType.Default}>Day</Button>
15
+ <Button styleType={ButtonStyleType.Default}>Week</Button>
16
+ <Button styleType={ButtonStyleType.Default}>Month</Button>
17
+ </ButtonGroup>
18
+
19
+ // Icon toolbar
20
+ <ButtonGroup>
21
+ <Button styleType={ButtonStyleType.Default} icon={faBold} aria-label="Bold" />
22
+ <Button styleType={ButtonStyleType.Default} icon={faItalic} aria-label="Italic" />
23
+ <Button styleType={ButtonStyleType.Default} icon={faUnderline} aria-label="Underline" />
24
+ </ButtonGroup>
25
+
26
+ // Vertical
27
+ <ButtonGroup orientation={ButtonGroupOrientation.Vertical}>
28
+ <Button styleType={ButtonStyleType.Default}>Bold</Button>
29
+ <Button styleType={ButtonStyleType.Default}>Italic</Button>
30
+ <Button styleType={ButtonStyleType.Default}>Underline</Button>
31
+ </ButtonGroup>
32
+
33
+ // With a separator — filled styles (Primary/Delete) have no border of their own to merge,
34
+ // so a vertical Divider gives adjacent buttons a visible seam instead of blending together
35
+ import { Divider, DividerOrientation } from '@ahrowe/ui';
36
+
37
+ <ButtonGroup>
38
+ <Button styleType={ButtonStyleType.Primary}>Save</Button>
39
+ <Divider orientation={DividerOrientation.Vertical} />
40
+ <Button styleType={ButtonStyleType.Primary}>Save & new</Button>
41
+ </ButtonGroup>
42
+
43
+ // Nested groups — a toolbar made of two self-contained sub-groups, spaced apart rather
44
+ // than merged into one continuous strip
45
+ <ButtonGroup>
46
+ <ButtonGroup>
47
+ <Button styleType={ButtonStyleType.Default} icon={faBold} aria-label="Bold" />
48
+ <Button styleType={ButtonStyleType.Default} icon={faItalic} aria-label="Italic" />
49
+ <Button styleType={ButtonStyleType.Default} icon={faUnderline} aria-label="Underline" />
50
+ </ButtonGroup>
51
+ <ButtonGroup>
52
+ <Button styleType={ButtonStyleType.Default} icon={faAlignLeft} aria-label="Align left" />
53
+ <Button styleType={ButtonStyleType.Default} icon={faAlignCenter} aria-label="Align center" />
54
+ <Button styleType={ButtonStyleType.Default} icon={faAlignRight} aria-label="Align right" />
55
+ </ButtonGroup>
56
+ </ButtonGroup>
57
+
58
+ // With an Input — a search bar. Input's visible border lives on its own container/fieldset
59
+ // elements, not its root, so (like SplitButton) the side touching the button needs a manual
60
+ // corner override via Input's own slots rather than ButtonGroup's automatic ones
61
+ import { Input } from '@ahrowe/ui';
62
+
63
+ const groupedInputStyle = { borderTopRightRadius: 0, borderBottomRightRadius: 0 };
64
+
65
+ <ButtonGroup>
66
+ <Input
67
+ placeholder="Search…"
68
+ useMatLabelStyle={false}
69
+ value={search}
70
+ onChange={setSearch}
71
+ styles={{ container: groupedInputStyle, fieldset: groupedInputStyle }}
72
+ />
73
+ <Button styleType={ButtonStyleType.Primary} icon={faMagnifyingGlass} aria-label="Search" />
74
+ </ButtonGroup>
75
+ ```
76
+
77
+ **Key props:**
78
+
79
+ | Prop | Type | Description |
80
+ |------|------|-------------|
81
+ | `children` | `ReactNode` | The buttons (or button-like elements) to join, in order |
82
+ | `orientation` | `ButtonGroupOrientation` | Layout direction (default `Horizontal`) |
83
+
84
+ **How it works:** the first and last children keep rounded outer corners; every child in between is flattened on both sides. Adjacent borders are collapsed with a `-1px` margin so two 1px borders don't stack into a visible double line, and whichever child is hovered/focused gets a `z-index` bump so its border/focus ring isn't clipped by its neighbors.
85
+
86
+ **Separators:** any child with `role="separator"` (what `Divider` sets) is excluded from that border-collapsing margin, on both sides — it stays fully visible between its neighbors instead of being partially hidden under one of them. Use a vertical `Divider` (see [Divider.md](Divider.md)) between two buttons when their style has no visible border of its own to merge (`Primary`, `Delete`), so there's still a clear seam between them.
87
+
88
+ **Note:** the corner-flattening rules key off DOM position (`:first-child`/`:last-child`), so they work for direct `Button` children out of the box. A child that renders as a wrapper around its own button (e.g. a component that portals its real content elsewhere) won't get the flattening automatically. `SplitButton` is exactly that case (its second child is a `FloatingMenu`-wrapped button), which is why it sets its own corner overrides directly rather than relying on `ButtonGroup`'s automatic ones. See [SplitButton.md](SplitButton.md).
89
+
90
+ **Slots:** none — `ButtonGroup` has no named inner elements, only `className`/`style` on the root.
package/docs/CLAUDE.md CHANGED
@@ -95,13 +95,17 @@ Slot keys per component are documented in each component's doc file below.
95
95
  @Accordion.md
96
96
  @ActionButtons.md
97
97
  @ActionIcon.md
98
+ @Alert.md
98
99
  @AnimatedLogo.md
99
100
  @AnimatedText.md
100
101
  @Avatar.md
101
102
  @Badge.md
102
103
  @BodyEnd.md
104
+ @Breadcrumb.md
103
105
  @Button.md
106
+ @ButtonGroup.md
104
107
  @Card.md
108
+ @Carousel.md
105
109
  @Checkbox.md
106
110
  @Chip.md
107
111
  @ColorPicker.md
@@ -133,6 +137,7 @@ Slot keys per component are documented in each component's doc file below.
133
137
  @Popover.md
134
138
  @ProgressBar.md
135
139
  @RadioGroup.md
140
+ @Rating.md
136
141
  @Ripple.md
137
142
  @RoomDrawer.md
138
143
  @RoomViewer.md
@@ -141,6 +146,7 @@ Slot keys per component are documented in each component's doc file below.
141
146
  @SectionHeader.md
142
147
  @Skeleton.md
143
148
  @Slider.md
149
+ @SplitButton.md
144
150
  @Stepper.md
145
151
  @Sticky.md
146
152
  @Switch.md
@@ -0,0 +1,67 @@
1
+ # Carousel
2
+
3
+ **When to use:** A slide track for stepping through a set of items one at a time, with arrows, dots, and drag/swipe support, plus optional autoplay. Slides are plain children, so any content works (images, cards, mixed content), not just a fixed image-gallery shape.
4
+
5
+ **Import:** `import { Carousel } from '@ahrowe/ui'`
6
+ **Types:** `import type { CarouselProps } from '@ahrowe/ui'`
7
+
8
+ ```tsx
9
+ import { Carousel } from '@ahrowe/ui';
10
+
11
+ // Uncontrolled, looping by default, with arrows, dots, and swipe all on
12
+ <Carousel>
13
+ <div>Slide 1</div>
14
+ <div>Slide 2</div>
15
+ <div>Slide 3</div>
16
+ </Carousel>
17
+
18
+ // Controlled
19
+ const [index, setIndex] = useState(0);
20
+ <Carousel currentIndex={index} onChange={setIndex}>
21
+ <div>Slide 1</div>
22
+ <div>Slide 2</div>
23
+ <div>Slide 3</div>
24
+ </Carousel>
25
+
26
+ // Autoplay, paused on hover/focus by default, with dots hidden
27
+ <Carousel autoPlay autoPlayInterval={4000} showDots={false}>
28
+ <div>Slide 1</div>
29
+ <div>Slide 2</div>
30
+ </Carousel>
31
+
32
+ // Bounded instead of looping: arrows disable at the first/last slide
33
+ <Carousel loop={false}>
34
+ <div>Slide 1</div>
35
+ <div>Slide 2</div>
36
+ </Carousel>
37
+
38
+ // No swipe/drag, arrows only
39
+ <Carousel swipeable={false} showDots={false}>
40
+ <div>Slide 1</div>
41
+ <div>Slide 2</div>
42
+ </Carousel>
43
+ ```
44
+
45
+ Pass slides as direct children (an array or a set of sibling elements), not through a component that returns a fragment internally. `Carousel` reads its immediate children via `React.Children`, so a wrapper component's own children aren't visible to it. If slides come from a `.map()`, spread the array straight into `Carousel`, the same way `children` normally works in React.
46
+
47
+ **Interaction:** drag or swipe the track to move between slides (committing past roughly 20% of the container's width, or releasing further than that snaps to the next/previous slide; a shorter drag springs back). Left/right arrow keys move between slides when focus is anywhere inside the carousel.
48
+
49
+ **Key props:**
50
+
51
+ | Prop | Type | Description |
52
+ |------|------|-------------|
53
+ | `children` | `ReactNode` | The slides, one per direct child |
54
+ | `currentIndex` | `number` | Controlled active slide index |
55
+ | `defaultIndex` | `number` | Initial active slide index when uncontrolled (default `0`) |
56
+ | `onChange` | `(index: number) => void` | Called whenever the active slide changes, from arrows, dots, keyboard, drag, or autoplay |
57
+ | `loop` | `boolean` | Wrap from the last slide to the first and back (default `true`) |
58
+ | `autoPlay` | `boolean` | Automatically advance on a timer (default `false`) |
59
+ | `autoPlayInterval` | `number` | Autoplay delay in ms (default `4000`) |
60
+ | `pauseOnHover` | `boolean` | Pause autoplay while hovered or focused (default `true`) |
61
+ | `showArrows` | `boolean` | Show the prev/next buttons (default `true`); hidden automatically with one slide or none |
62
+ | `showDots` | `boolean` | Show the position dots (default `true`); hidden automatically with one slide or none |
63
+ | `swipeable` | `boolean` | Allow dragging/swiping the track (default `true`) |
64
+
65
+ **Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ Carousel: { autoPlay: true } }}`. See [ConfigProvider.md](ConfigProvider.md).
66
+
67
+ **Slots:** `root` `track` `slide` `prevButton` `nextButton` `dots` `dot`