@ahrowe/ui 0.11.0 → 0.13.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 (102) hide show
  1. package/dist/esm/common/accordion/accordion.module.mjs.map +1 -1
  2. package/dist/esm/common/accordion/accordion.plain.module.mjs.map +1 -1
  3. package/dist/esm/common/accordion/accordion.primary.module.mjs.map +1 -1
  4. package/dist/esm/common/actionIcon/actionIcon.module.mjs.map +1 -1
  5. package/dist/esm/common/alert/alert.mjs +2 -0
  6. package/dist/esm/common/alert/alert.mjs.map +1 -0
  7. package/dist/esm/common/alert/alert.module.mjs +2 -0
  8. package/dist/esm/common/alert/alert.module.mjs.map +1 -0
  9. package/dist/esm/common/alert/alert.types.mjs +2 -0
  10. package/dist/esm/common/alert/alert.types.mjs.map +1 -0
  11. package/dist/esm/common/animatedText/animatedText.mjs +1 -1
  12. package/dist/esm/common/animatedText/animatedText.mjs.map +1 -1
  13. package/dist/esm/common/animatedText/animatedText.types.mjs.map +1 -1
  14. package/dist/esm/common/breadcrumb/breadcrumb.mjs +2 -0
  15. package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -0
  16. package/dist/esm/common/breadcrumb/breadcrumb.module.mjs +2 -0
  17. package/dist/esm/common/breadcrumb/breadcrumb.module.mjs.map +1 -0
  18. package/dist/esm/common/button/button.module.mjs.map +1 -1
  19. package/dist/esm/common/card/card.module.mjs.map +1 -1
  20. package/dist/esm/common/carousel/carousel.mjs +2 -0
  21. package/dist/esm/common/carousel/carousel.mjs.map +1 -0
  22. package/dist/esm/common/carousel/carousel.module.mjs +2 -0
  23. package/dist/esm/common/carousel/carousel.module.mjs.map +1 -0
  24. package/dist/esm/common/checkbox/checkbox.module.mjs.map +1 -1
  25. package/dist/esm/common/chip/chip.module.mjs.map +1 -1
  26. package/dist/esm/common/colorPicker/colorPicker.mjs +1 -1
  27. package/dist/esm/common/colorPicker/colorPicker.mjs.map +1 -1
  28. package/dist/esm/common/colorPicker/colorPicker.module.mjs +1 -1
  29. package/dist/esm/common/colorPicker/colorPicker.module.mjs.map +1 -1
  30. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.module.mjs.map +1 -1
  31. package/dist/esm/common/datePicker/datePicker.module.mjs.map +1 -1
  32. package/dist/esm/common/dropZone/dropZone.module.mjs.map +1 -1
  33. package/dist/esm/common/dropdown/dropdown.module.mjs.map +1 -1
  34. package/dist/esm/common/fab/fab.module.mjs.map +1 -1
  35. package/dist/esm/common/floatingMenu/floatingMenu.module.mjs.map +1 -1
  36. package/dist/esm/common/iconPicker/iconPicker.module.mjs.map +1 -1
  37. package/dist/esm/common/input/input.module.mjs.map +1 -1
  38. package/dist/esm/common/inputDropdown/inputDropdown.module.mjs.map +1 -1
  39. package/dist/esm/common/klipyPicker/klipyPicker.mjs +1 -1
  40. package/dist/esm/common/klipyPicker/klipyPicker.module.mjs.map +1 -1
  41. package/dist/esm/common/modal/modal.module.mjs.map +1 -1
  42. package/dist/esm/common/numberInput/numberInput.module.mjs.map +1 -1
  43. package/dist/esm/common/optionPicker/optionPicker.module.mjs.map +1 -1
  44. package/dist/esm/common/radioGroup/radioGroup.module.mjs.map +1 -1
  45. package/dist/esm/common/rating/rating.mjs +2 -0
  46. package/dist/esm/common/rating/rating.mjs.map +1 -0
  47. package/dist/esm/common/rating/rating.module.mjs +2 -0
  48. package/dist/esm/common/rating/rating.module.mjs.map +1 -0
  49. package/dist/esm/common/roomDrawer/roomDrawer.module.mjs.map +1 -1
  50. package/dist/esm/common/roomViewer/roomViewer.module.mjs.map +1 -1
  51. package/dist/esm/common/slider/slider.mjs +2 -0
  52. package/dist/esm/common/slider/slider.mjs.map +1 -0
  53. package/dist/esm/common/slider/slider.module.mjs +2 -0
  54. package/dist/esm/common/slider/slider.module.mjs.map +1 -0
  55. package/dist/esm/common/stepper/stepper.mjs +1 -1
  56. package/dist/esm/common/stepper/stepper.mjs.map +1 -1
  57. package/dist/esm/common/stepper/stepper.module.mjs +1 -1
  58. package/dist/esm/common/stepper/stepper.module.mjs.map +1 -1
  59. package/dist/esm/common/stepper/stepper.types.mjs.map +1 -1
  60. package/dist/esm/common/switch/switch.module.mjs.map +1 -1
  61. package/dist/esm/common/tabHeader/tabHeader.module.mjs.map +1 -1
  62. package/dist/esm/common/timeInput/components/clockDial/clockDial.module.mjs.map +1 -1
  63. package/dist/esm/common/timeInput/timeInput.module.mjs.map +1 -1
  64. package/dist/esm/common/toast/toast.module.mjs.map +1 -1
  65. package/dist/esm/common/virtualList/virtualList.mjs +1 -1
  66. package/dist/esm/common/virtualList/virtualList.mjs.map +1 -1
  67. package/dist/esm/common/virtualList/virtualList.module.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/animatedText/animatedText.d.ts +1 -1
  76. package/dist/types/package/common/animatedText/animatedText.types.d.ts +6 -0
  77. package/dist/types/package/common/breadcrumb/breadcrumb.d.ts +4 -0
  78. package/dist/types/package/common/breadcrumb/breadcrumb.types.d.ts +26 -0
  79. package/dist/types/package/common/breadcrumb/index.d.ts +2 -0
  80. package/dist/types/package/common/carousel/carousel.d.ts +3 -0
  81. package/dist/types/package/common/carousel/carousel.types.d.ts +20 -0
  82. package/dist/types/package/common/carousel/index.d.ts +2 -0
  83. package/dist/types/package/common/configProvider/configProvider.types.d.ts +8 -0
  84. package/dist/types/package/common/rating/index.d.ts +2 -0
  85. package/dist/types/package/common/rating/rating.d.ts +4 -0
  86. package/dist/types/package/common/rating/rating.types.d.ts +19 -0
  87. package/dist/types/package/common/slider/index.d.ts +2 -0
  88. package/dist/types/package/common/slider/slider.d.ts +3 -0
  89. package/dist/types/package/common/slider/slider.types.d.ts +43 -0
  90. package/dist/types/package/common/stepper/stepper.types.d.ts +5 -5
  91. package/dist/types/package/common/themeProvider/theme.types.d.ts +10 -0
  92. package/dist/types/package/index.d.ts +10 -0
  93. package/docs/Alert.md +64 -0
  94. package/docs/AnimatedText.md +5 -0
  95. package/docs/Breadcrumb.md +106 -0
  96. package/docs/CLAUDE.md +5 -0
  97. package/docs/Carousel.md +67 -0
  98. package/docs/ColorPicker.md +2 -0
  99. package/docs/Rating.md +72 -0
  100. package/docs/Slider.md +93 -0
  101. package/docs/Stepper.md +6 -6
  102. package/package.json +1 -1
@@ -0,0 +1,43 @@
1
+ import { CSSProperties, ReactNode } from 'react';
2
+ import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
3
+ export interface SliderMark {
4
+ /** Position of the mark, in the same units as `value`. */
5
+ value: number;
6
+ /** Optional label rendered under the mark. */
7
+ label?: ReactNode;
8
+ }
9
+ export type SliderSlots = 'root' | 'track' | 'range' | 'thumb' | 'mark' | 'markLabel' | 'value';
10
+ export interface SliderProps extends HtmlProps {
11
+ /** Controlled value. Omit for uncontrolled. */
12
+ value?: number;
13
+ /** Initial value when uncontrolled (default `min`). */
14
+ defaultValue?: number;
15
+ /** Fires on every value change (drag, keyboard, click). */
16
+ onChange?: (value: number) => void;
17
+ /** Fires once when the value is committed: pointer release or a keyboard step. */
18
+ onChangeEnd?: (value: number) => void;
19
+ /** Minimum value (default `0`). */
20
+ min?: number;
21
+ /** Maximum value (default `100`). */
22
+ max?: number;
23
+ /** Step increment; values snap to it (default `1`). */
24
+ step?: number;
25
+ /** Disable interaction. */
26
+ disabled?: boolean;
27
+ /** Tick marks along the track, optionally labelled. */
28
+ marks?: SliderMark[];
29
+ /** Show the current value in a bubble above the thumb. */
30
+ showValue?: boolean;
31
+ /** Format the value shown in the bubble and announced to assistive tech. */
32
+ formatValue?: (value: number) => ReactNode;
33
+ /** Thumb diameter, any CSS length (default `'18px'`). Sets `--slider-thumb-size`. */
34
+ size?: string;
35
+ /** Tab index of the thumb (default `0`). */
36
+ tabIndex?: number;
37
+ /** Accessible label for the slider. */
38
+ 'aria-label'?: string;
39
+ className?: string;
40
+ style?: CSSProperties;
41
+ classNames?: SlotClassNames<SliderSlots>;
42
+ styles?: SlotStyles<SliderSlots>;
43
+ }
@@ -10,9 +10,9 @@ export declare enum StepperAlignment {
10
10
  export declare enum StepperStyleType {
11
11
  /** Numbered markers, filled solid on completion (the default look). */
12
12
  Default = "default",
13
- /** Numbered markers that stay ringed when completed a coloured check, no solid fill. */
13
+ /** Numbered markers that stay ringed when completed (a coloured check, no solid fill). */
14
14
  Outlined = "outlined",
15
- /** Minimal dots without numbers compact onboarding / carousel style. */
15
+ /** Minimal dots without numbers, for a compact onboarding or carousel style. */
16
16
  Dots = "dots"
17
17
  }
18
18
  /**
@@ -48,11 +48,11 @@ export interface StepperStep {
48
48
  content?: React.ReactNode;
49
49
  /** FontAwesome icon shown in the marker instead of the step number. */
50
50
  icon?: IconDefinition;
51
- /** Marks the step as errored recolours the marker with `--stepper-error-color`. */
51
+ /** Marks the step as errored, recolouring the marker with `--stepper-error-color`. */
52
52
  error?: boolean;
53
53
  /** `true` renders an "Optional" hint; a node renders custom hint text. */
54
54
  optional?: boolean | React.ReactNode;
55
- /** Disables this step never clickable, dimmed. */
55
+ /** Disables this step: never clickable, dimmed. */
56
56
  disabled?: boolean;
57
57
  }
58
58
  export interface StepperProps extends HtmlProps {
@@ -66,7 +66,7 @@ export interface StepperProps extends HtmlProps {
66
66
  hideLabels?: boolean;
67
67
  /** Visual preset for markers and connectors (default `Default`). */
68
68
  styleType?: StepperStyleType;
69
- /** Which step bodies are expanded vertical `content` only (default `None`). */
69
+ /** Which step bodies are expanded. Vertical `content` only (default `None`). */
70
70
  collapse?: StepperCollapse;
71
71
  /** Label position relative to the marker (default: horizontal `Bottom`, vertical `Right`). */
72
72
  labelPlacement?: StepperLabelPlacement;
@@ -74,6 +74,16 @@ export interface ThemeVariables {
74
74
  '--background-card-elevated'?: string;
75
75
  '--background-card-outlined'?: string;
76
76
  '--background-card-filled'?: string;
77
+ /** Slider track (unfilled) colour. Falls back to --background-accent-light. */
78
+ '--slider-track-color'?: string;
79
+ /** Slider filled-range colour. Falls back to --primary-color. */
80
+ '--slider-range-color'?: string;
81
+ /** Slider thumb colour. Falls back to --primary-color. */
82
+ '--slider-thumb-color'?: string;
83
+ /** Slider thumb diameter. Falls back to 18px (also settable per instance via the `size` prop). */
84
+ '--slider-thumb-size'?: string;
85
+ /** Slider track thickness. Falls back to 6px. */
86
+ '--slider-track-height'?: string;
77
87
  /** Step marker diameter. Falls back to 40px. */
78
88
  '--stepper-marker-size'?: string;
79
89
  /** Step marker corner radius. Falls back to --default-border-radius. */
@@ -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,14 @@ 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';
18
22
  export { default as Card } from './common/card';
19
23
  export * from './common/card';
24
+ export { default as Carousel } from './common/carousel';
25
+ export * from './common/carousel';
20
26
  export { default as Checkbox } from './common/checkbox';
21
27
  export * from './common/checkbox';
22
28
  export { default as Chip } from './common/chip';
@@ -74,6 +80,8 @@ export { default as ProgressBar } from './common/progressBar';
74
80
  export * from './common/progressBar';
75
81
  export { default as RadioGroup } from './common/radioGroup';
76
82
  export * from './common/radioGroup';
83
+ export { default as Rating } from './common/rating';
84
+ export * from './common/rating';
77
85
  export { default as Ripple } from './common/ripple';
78
86
  export * from './common/ripple';
79
87
  export { default as RoomDrawer } from './common/roomDrawer';
@@ -88,6 +96,8 @@ export { default as SectionHeader } from './common/sectionHeader';
88
96
  export * from './common/sectionHeader';
89
97
  export { default as Skeleton } from './common/skeleton';
90
98
  export * from './common/skeleton';
99
+ export { default as Slider } from './common/slider';
100
+ export * from './common/slider';
91
101
  export { default as Stepper } from './common/stepper';
92
102
  export * from './common/stepper';
93
103
  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`
@@ -59,6 +59,10 @@ import { AnimatedText, AnimatedTextVariant, AnimatedTextUnit } from '@ahrowe/ui'
59
59
  // A marker-style highlight block wipes in behind the text, once
60
60
  <AnimatedText text="Marked as important" variant={AnimatedTextVariant.Highlight} />
61
61
 
62
+ // Plays immediately on mount instead of waiting for it to scroll into view
63
+ // (default behaviour) — e.g. a hero headline that's already above the fold
64
+ <AnimatedText text="Welcome back" triggerOnView={false} />
65
+
62
66
  // Changing `text` (or `variant`/`unit`/`staggerDelay`/`duration`) automatically replays,
63
67
  // so no key is needed for that. A key is only needed to replay with the exact same text again:
64
68
  <AnimatedText key={replayKey} text="Hello there" />
@@ -74,6 +78,7 @@ import { AnimatedText, AnimatedTextVariant, AnimatedTextUnit } from '@ahrowe/ui'
74
78
  | `unit` | `AnimatedTextUnit` | Whether entrance/loop variants stagger by letter or by whole word (default `Letter`). Ignored by `Shine`/`Highlight` |
75
79
  | `staggerDelay` | `number` | Delay in ms between each unit's animation start. Applies to every variant except `Shine`/`Highlight`, which animate as a single run (default `40`) |
76
80
  | `duration` | `number` | Duration in ms of one animation cycle: a single unit's entrance for `RiseUp`/`BlurIn`/`Bounce`/`Glitch` (default `500`), one bob cycle for `Wave` (default `1200`), one sweep of the highlight for `Shine` (default `2000`), or the one-shot wipe-in for `Highlight` (default `600`). Ignored by `Typewriter` and `Scramble`, since each unit resolves instantly; use `staggerDelay` to control their pacing |
81
+ | `triggerOnView` | `boolean` | When `true` (default), the animation doesn't start until the component first scrolls into the viewport. Set `false` to play immediately on mount |
77
82
 
78
83
  **Word mode:** with `unit={AnimatedTextUnit.Word}`, each whole word animates as one block instead of each letter animating individually; `staggerDelay` then applies between words. Words are split on whitespace, and consecutive spaces collapse to one.
79
84
 
@@ -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`
package/docs/CLAUDE.md CHANGED
@@ -95,13 +95,16 @@ 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
104
106
  @Card.md
107
+ @Carousel.md
105
108
  @Checkbox.md
106
109
  @Chip.md
107
110
  @ColorPicker.md
@@ -133,6 +136,7 @@ Slot keys per component are documented in each component's doc file below.
133
136
  @Popover.md
134
137
  @ProgressBar.md
135
138
  @RadioGroup.md
139
+ @Rating.md
136
140
  @Ripple.md
137
141
  @RoomDrawer.md
138
142
  @RoomViewer.md
@@ -140,6 +144,7 @@ Slot keys per component are documented in each component's doc file below.
140
144
  @SearchInput.md
141
145
  @SectionHeader.md
142
146
  @Skeleton.md
147
+ @Slider.md
143
148
  @Stepper.md
144
149
  @Sticky.md
145
150
  @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`
@@ -36,3 +36,5 @@ import { ColorPicker } from '@ahrowe/ui';
36
36
  | `onChange` | `(hex: string) => void` | Called with new hex on change |
37
37
  | `showInput` | `boolean` | Show hex text input |
38
38
  | `inline` | `boolean` | Render picker inline instead of as a popover |
39
+
40
+ An eyedropper button is shown automatically next to the hex input on browsers that support the native `EyeDropper` API (Chromium-based desktop/Android browsers). It lets the user sample a colour from anywhere on screen, not just within the page. It's hidden entirely on unsupported browsers (Firefox, Safari, iOS) — no prop needed.
package/docs/Rating.md ADDED
@@ -0,0 +1,72 @@
1
+ # Rating
2
+
3
+ **When to use:** A star rating input or display, for review scores, feedback prompts, and quality indicators. Use `readOnly` to just show an existing rating (e.g. a product's average score) rather than collect one.
4
+
5
+ **Import:** `import { Rating } from '@ahrowe/ui'`
6
+ **Types:** `import type { RatingProps } from '@ahrowe/ui'`
7
+
8
+ ```tsx
9
+ import { useState } from 'react';
10
+ import { Rating } from '@ahrowe/ui';
11
+
12
+ // Controlled
13
+ const [value, setValue] = useState(3);
14
+ <Rating value={value} onChange={setValue} />
15
+
16
+ // Uncontrolled
17
+ <Rating defaultValue={4} onChange={(value) => console.log(value)} />
18
+
19
+ // Half-star increments
20
+ <Rating defaultValue={3.5} allowHalf />
21
+
22
+ // A different number of stars
23
+ <Rating defaultValue={6} max={10} />
24
+
25
+ // Read-only, for displaying an existing rating (e.g. a product card)
26
+ <Rating value={4} readOnly />
27
+
28
+ // Disabled
29
+ <Rating value={2} disabled />
30
+
31
+ // Larger, via font-size (sizing is em-based, like Switch and Avatar)
32
+ <Rating defaultValue={4} style={{ fontSize: 32 }} />
33
+
34
+ // Custom icon
35
+ import { faHeart } from '@fortawesome/free-solid-svg-icons';
36
+ <Rating defaultValue={3} icon={faHeart} />
37
+
38
+ // Disable click-to-clear (clicking the currently-selected star normally resets to 0)
39
+ <Rating value={value} onChange={setValue} allowClear={false} />
40
+ ```
41
+
42
+ **Interaction:** click, tap, or drag/swipe across the stars to set the rating, on any pointer type (mouse, touch, pen) via the Pointer Events API. Dragging updates the preview live and commits on release, which is the natural gesture on mobile rather than requiring a precise tap on one star. A plain click/tap on the currently-selected star clears it to `0` (set `allowClear={false}` to keep it fixed instead); a drag that happens to end back near its starting value doesn't clear, since that's a different gesture from a deliberate re-tap. With keyboard focus: `←`/`↓` and `→`/`↑` move by one star (or half a star with `allowHalf`), `Home`/`End` jump to `0`/`max`.
43
+
44
+ **Sizing:** there's no dedicated size prop, `font-size` scales the whole control (like `Switch` and `Avatar`). The root sizes to its content (`width: fit-content`) rather than stretching to fill a flex/grid ancestor, since the click/drag position is measured against the root's own width.
45
+
46
+ **Key props:**
47
+
48
+ | Prop | Type | Description |
49
+ |------|------|-------------|
50
+ | `value` | `number` | Controlled value (omit for uncontrolled) |
51
+ | `defaultValue` | `number` | Initial value when uncontrolled (default `0`) |
52
+ | `onChange` | `(value: number) => void` | Fires when the rating changes, from a click or keyboard input |
53
+ | `max` | `number` | Number of stars (default `5`) |
54
+ | `allowHalf` | `boolean` | Allow half-star increments (default `false`) |
55
+ | `allowClear` | `boolean` | Clicking the currently-selected star resets the value to `0` (default `true`) |
56
+ | `readOnly` | `boolean` | Display only, not focusable or interactive |
57
+ | `disabled` | `boolean` | Dims the control and disables interaction |
58
+ | `icon` | `IconDefinition` | Overrides the default star icon |
59
+ | `aria-label` | `string` | Accessible label (default `'Rating'`) |
60
+
61
+ **Accessibility:** renders `role="slider"` with `aria-valuemin`/`aria-valuemax`/`aria-valuenow`/`aria-valuetext`, matching `Slider`'s pattern.
62
+
63
+ **Theming:** override these CSS variables theme-wide via `ThemeProvider` or per instance via `style`; each falls back to a built-in default:
64
+
65
+ | Variable | Falls back to |
66
+ |----------|---------------|
67
+ | `--rating-filled-color` | `var(--primary-color)` |
68
+ | `--rating-empty-color` | `var(--background-accent-light)` |
69
+
70
+ **Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ Rating: { allowHalf: true } }}`. See [ConfigProvider.md](ConfigProvider.md).
71
+
72
+ **Slots:** `root` `item` `iconEmpty` `iconFilled`
package/docs/Slider.md ADDED
@@ -0,0 +1,93 @@
1
+ # Slider
2
+
3
+ **When to use:** Let the user pick a number from a continuous or stepped range by dragging a thumb: volume, brightness, price ranges, zoom, quality presets. For free numeric entry use `NumberInput`; for a few discrete options use `OptionPicker` or `RadioGroup`.
4
+
5
+ **Import:** `import { Slider } from '@ahrowe/ui'`
6
+ **Types:** `import type { SliderProps, SliderMark } from '@ahrowe/ui'`
7
+
8
+ ```tsx
9
+ import { useState } from 'react';
10
+ import { Slider } from '@ahrowe/ui';
11
+
12
+ // Controlled
13
+ const [value, setValue] = useState(40);
14
+ <Slider value={value} onChange={setValue} aria-label="Value" />
15
+
16
+ // Uncontrolled
17
+ <Slider defaultValue={40} onChangeEnd={(v) => save(v)} />
18
+
19
+ // Value bubble above the thumb
20
+ <Slider value={volume} onChange={setVolume} showValue />
21
+
22
+ // Custom range, step, and formatting
23
+ <Slider
24
+ value={price}
25
+ onChange={setPrice}
26
+ min={0}
27
+ max={1000}
28
+ step={50}
29
+ showValue
30
+ formatValue={(v) => `€${v}`}
31
+ />
32
+
33
+ // Tick marks (labelled and unlabelled)
34
+ <Slider
35
+ value={quality}
36
+ onChange={setQuality}
37
+ min={0}
38
+ max={4}
39
+ step={1}
40
+ marks={[
41
+ { value: 0, label: 'Low' },
42
+ { value: 2, label: 'Medium' },
43
+ { value: 4, label: 'High' },
44
+ ]}
45
+ />
46
+
47
+ // Larger thumb, themed colours (one-off)
48
+ <Slider
49
+ value={value}
50
+ onChange={setValue}
51
+ size="26px"
52
+ style={{
53
+ '--slider-range-color': 'var(--success-color)',
54
+ '--slider-thumb-color': 'var(--success-color)',
55
+ } as React.CSSProperties}
56
+ />
57
+ ```
58
+
59
+ **Interaction:** drag the thumb or click anywhere on the track to jump there. With keyboard focus: `←`/`↓` and `→`/`↑` move by `step`, `Page Up`/`Page Down` by ten steps, `Home`/`End` jump to `min`/`max`. Values always snap to `step`.
60
+
61
+ **`onChange` vs `onChangeEnd`:** `onChange` fires on every change (each drag move and each key press); `onChangeEnd` fires once the value is committed, on pointer release or on each keyboard step. Use `onChangeEnd` to defer expensive work (a network save, a heavy re-render) until the user settles.
62
+
63
+ **Key props:**
64
+
65
+ | Prop | Type | Description |
66
+ |------|------|-------------|
67
+ | `value` | `number` | Controlled value (omit for uncontrolled) |
68
+ | `defaultValue` | `number` | Initial value when uncontrolled (default `min`) |
69
+ | `onChange` | `(value: number) => void` | Fires on every change |
70
+ | `onChangeEnd` | `(value: number) => void` | Fires once the value is committed |
71
+ | `min` | `number` | Minimum (default `0`) |
72
+ | `max` | `number` | Maximum (default `100`) |
73
+ | `step` | `number` | Snap increment (default `1`) |
74
+ | `disabled` | `boolean` | Disable interaction |
75
+ | `marks` | `SliderMark[]` | Tick marks, `{ value, label? }` |
76
+ | `showValue` | `boolean` | Show the current value in a bubble above the thumb |
77
+ | `formatValue` | `(value: number) => ReactNode` | Format the bubble text and `aria-valuetext` |
78
+ | `size` | `string` | Thumb diameter, any CSS length (default `'18px'`) |
79
+ | `aria-label` | `string` | Accessible label |
80
+
81
+ **Accessibility:** renders `role="slider"` with `aria-valuemin` / `aria-valuemax` / `aria-valuenow` (and `aria-valuetext` when `formatValue` returns a string/number). Give it an `aria-label` (or wire up your own visible label). Respects `prefers-reduced-motion` (no thumb/fill transition).
82
+
83
+ **Theming:** override these CSS variables theme-wide via `ThemeProvider` or per instance via `style`; each falls back to a built-in default:
84
+
85
+ | Variable | Falls back to |
86
+ |----------|---------------|
87
+ | `--slider-track-color` | `var(--background-accent-light)` |
88
+ | `--slider-range-color` | `var(--primary-color)` |
89
+ | `--slider-thumb-color` | `var(--primary-color)` |
90
+ | `--slider-thumb-size` | `18px` (also settable per instance via `size`) |
91
+ | `--slider-track-height` | `6px` |
92
+
93
+ **Slots:** `root` `track` `range` `thumb` `mark` `markLabel` `value`
package/docs/Stepper.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Stepper
2
2
 
3
- **When to use:** Step progress indicator multi-step forms, onboarding flows, checkout wizards. Shows completed, current, and upcoming steps, and (vertically) can expand a collapsible body under the active step.
3
+ **When to use:** Step progress indicator for multi-step forms, onboarding flows, and checkout wizards. Shows completed, current, and upcoming steps, and (vertically) can expand a collapsible body under the active step.
4
4
 
5
5
  **Import:** `import { Stepper } from '@ahrowe/ui'`
6
6
  **Types:** `import type { StepperStep, StepperProps } from '@ahrowe/ui'`
@@ -36,7 +36,7 @@ const steps = [
36
36
  onStepClicked={(stepIndex) => setCurrentStep(stepIndex)}
37
37
  />
38
38
 
39
- // Rich steps icon, description, error, optional
39
+ // Rich steps: icon, description, error, optional
40
40
  <Stepper
41
41
  currentStep={2}
42
42
  steps={[
@@ -46,7 +46,7 @@ const steps = [
46
46
  ]}
47
47
  />
48
48
 
49
- // Vertical wizard with collapsible bodies only the active step's body is open
49
+ // Vertical wizard with collapsible bodies (only the active step's body is open)
50
50
  <Stepper
51
51
  alignment={StepperAlignment.Vertical}
52
52
  collapse={StepperCollapse.ActiveOnly}
@@ -80,7 +80,7 @@ const steps = [
80
80
  | `currentStep` | `number` | Zero-based active step index |
81
81
  | `alignment` | `StepperAlignment \| 'horizontal' \| 'vertical'` | Layout direction (default `Horizontal`) |
82
82
  | `styleType` | `StepperStyleType` | Marker/connector preset (default `Default`) |
83
- | `collapse` | `StepperCollapse` | Which `content` bodies are expanded vertical only (default `None`) |
83
+ | `collapse` | `StepperCollapse` | Which `content` bodies are expanded. Vertical only (default `None`) |
84
84
  | `labelPlacement` | `StepperLabelPlacement` | Label position; default `Bottom` (horizontal) / `Right` (vertical). An out-of-orientation value falls back to that default |
85
85
  | `onStepClicked` | `(stepIndex: number) => void` | Navigate on step click. Linear: only completed steps are clickable; with `nonLinear`, any enabled step except the current one |
86
86
  | `nonLinear` | `boolean` | Allow clicking any step, not just completed ones |
@@ -88,7 +88,7 @@ const steps = [
88
88
 
89
89
  **Collapse (vertical `content`):** `None` keeps every body open; `ActiveOnly` opens just the current step's body (classic vertical wizard); `Completed` collapses completed bodies while keeping the current and upcoming ones open. Bodies animate their height and respect `prefers-reduced-motion`. Horizontal steppers don't render inline `content` and ignore `collapse`.
90
90
 
91
- **Theming:** these are theme variables (typed on `ThemeVariables`) set them theme-wide via `ThemeProvider`'s `variables`, or per instance via `style`, without fighting specificity. Each falls back to a built-in default when unset:
91
+ **Theming:** these are theme variables (typed on `ThemeVariables`). Set them theme-wide via `ThemeProvider`'s `variables`, or per instance via `style`, without fighting specificity. Each falls back to a built-in default when unset:
92
92
 
93
93
  | Variable | Falls back to |
94
94
  |----------|---------------|
@@ -105,7 +105,7 @@ const steps = [
105
105
  | `--stepper-text-on-marker` | `var(--text-on-primary)` |
106
106
 
107
107
  ```tsx
108
- // Theme-wide, via ThemeProvider circular pink markers, thicker connectors
108
+ // Theme-wide, via ThemeProvider: circular pink markers, thicker connectors
109
109
  const theme: Theme = {
110
110
  id: 'brand',
111
111
  variables: {