@ahrowe/ui 0.22.0 → 0.24.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 (86) hide show
  1. package/dist/esm/common/alert/alert.types.mjs.map +1 -1
  2. package/dist/esm/common/badge/badge.types.mjs.map +1 -1
  3. package/dist/esm/common/button/button.mjs +1 -1
  4. package/dist/esm/common/button/button.mjs.map +1 -1
  5. package/dist/esm/common/button/button.module.mjs +1 -1
  6. package/dist/esm/common/button/button.module.mjs.map +1 -1
  7. package/dist/esm/common/button/button.types.mjs +1 -1
  8. package/dist/esm/common/button/button.types.mjs.map +1 -1
  9. package/dist/esm/common/card/Card.mjs +1 -1
  10. package/dist/esm/common/card/Card.mjs.map +1 -1
  11. package/dist/esm/common/card/card.types.mjs.map +1 -1
  12. package/dist/esm/common/carousel/carousel.mjs +1 -1
  13. package/dist/esm/common/carousel/carousel.mjs.map +1 -1
  14. package/dist/esm/common/carousel/carousel.module.mjs +1 -1
  15. package/dist/esm/common/carousel/carousel.module.mjs.map +1 -1
  16. package/dist/esm/common/chip/chip.mjs +1 -1
  17. package/dist/esm/common/chip/chip.mjs.map +1 -1
  18. package/dist/esm/common/chip/chip.types.mjs.map +1 -1
  19. package/dist/esm/common/dropZone/dropZone.types.mjs.map +1 -1
  20. package/dist/esm/common/floatingMenu/floatingMenu.types.mjs.map +1 -1
  21. package/dist/esm/common/hooks/useCoarsePointer.mjs +2 -0
  22. package/dist/esm/common/hooks/useCoarsePointer.mjs.map +1 -0
  23. package/dist/esm/common/hooks/useSwipeDismiss.mjs +1 -1
  24. package/dist/esm/common/hooks/useSwipeDismiss.mjs.map +1 -1
  25. package/dist/esm/common/iconPicker/iconPicker.mjs +1 -1
  26. package/dist/esm/common/iconPicker/iconPicker.mjs.map +1 -1
  27. package/dist/esm/common/input/input.types.mjs.map +1 -1
  28. package/dist/esm/common/interactableDiv/interactableDiv.mjs +1 -1
  29. package/dist/esm/common/interactableDiv/interactableDiv.mjs.map +1 -1
  30. package/dist/esm/common/numberInput/index.mjs.map +1 -1
  31. package/dist/esm/common/numberInput/numberInput.mjs +1 -1
  32. package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
  33. package/dist/esm/common/numberInput/numberInput.module.mjs +1 -1
  34. package/dist/esm/common/numberInput/numberInput.module.mjs.map +1 -1
  35. package/dist/esm/common/numberInput/useStepRepeat.mjs +2 -0
  36. package/dist/esm/common/numberInput/useStepRepeat.mjs.map +1 -0
  37. package/dist/esm/common/otpInput/otpInput.types.mjs.map +1 -1
  38. package/dist/esm/common/popover/popover.types.mjs.map +1 -1
  39. package/dist/esm/common/radioGroup/radioGroup.types.mjs.map +1 -1
  40. package/dist/esm/common/sectionHeader/sectionHeader.types.mjs.map +1 -1
  41. package/dist/index.cjs +6 -6
  42. package/dist/index.cjs.map +1 -1
  43. package/dist/style.css +1 -1
  44. package/dist/types/package/common/alert/alert.types.d.ts +1 -1
  45. package/dist/types/package/common/animatedLogo/animatedLogo.types.d.ts +11 -3
  46. package/dist/types/package/common/avatar/avatar.types.d.ts +1 -1
  47. package/dist/types/package/common/badge/badge.types.d.ts +1 -1
  48. package/dist/types/package/common/button/button.types.d.ts +10 -4
  49. package/dist/types/package/common/card/card.types.d.ts +1 -1
  50. package/dist/types/package/common/carousel/carousel.types.d.ts +3 -1
  51. package/dist/types/package/common/checkbox/checkbox.types.d.ts +1 -1
  52. package/dist/types/package/common/chip/chip.types.d.ts +2 -0
  53. package/dist/types/package/common/colorPicker/colorPicker.types.d.ts +1 -1
  54. package/dist/types/package/common/configProvider/configProvider.types.d.ts +1 -1
  55. package/dist/types/package/common/dropZone/dropZone.types.d.ts +1 -1
  56. package/dist/types/package/common/dropdown/dropdown.types.d.ts +1 -1
  57. package/dist/types/package/common/errorBoundary/errorBoundary.types.d.ts +1 -1
  58. package/dist/types/package/common/floatingMenu/floatingMenu.types.d.ts +1 -1
  59. package/dist/types/package/common/hooks/useCoarsePointer.d.ts +10 -0
  60. package/dist/types/package/common/iconPicker/iconPicker.types.d.ts +1 -1
  61. package/dist/types/package/common/input/input.types.d.ts +2 -2
  62. package/dist/types/package/common/inputDropdown/inputDropdown.types.d.ts +1 -1
  63. package/dist/types/package/common/interactableDiv/interactableDiv.d.ts +2 -2
  64. package/dist/types/package/common/kanbanBoard/kanbanBoard.types.d.ts +1 -1
  65. package/dist/types/package/common/numberInput/index.d.ts +1 -0
  66. package/dist/types/package/common/numberInput/numberInput.d.ts +3 -32
  67. package/dist/types/package/common/numberInput/numberInput.types.d.ts +61 -0
  68. package/dist/types/package/common/numberInput/useStepRepeat.d.ts +17 -0
  69. package/dist/types/package/common/optionPicker/optionPicker.types.d.ts +1 -1
  70. package/dist/types/package/common/otpInput/otpInput.types.d.ts +1 -1
  71. package/dist/types/package/common/popover/popover.types.d.ts +1 -1
  72. package/dist/types/package/common/radioGroup/radioGroup.types.d.ts +1 -1
  73. package/dist/types/package/common/rating/rating.types.d.ts +1 -1
  74. package/dist/types/package/common/searchInput/searchInput.types.d.ts +1 -1
  75. package/dist/types/package/common/sectionHeader/sectionHeader.types.d.ts +1 -1
  76. package/dist/types/package/common/slider/slider.types.d.ts +1 -1
  77. package/dist/types/package/common/switch/switch.types.d.ts +1 -1
  78. package/dist/types/package/common/tabHeader/tabHeader.types.d.ts +1 -1
  79. package/dist/types/package/common/timeInput/timeInput.types.d.ts +1 -1
  80. package/dist/types/package/common/types/baseProps.types.d.ts +20 -5
  81. package/dist/types/package/common/types/slots.types.d.ts +1 -1
  82. package/docs/Button.md +23 -2
  83. package/docs/Carousel.md +19 -0
  84. package/docs/Chip.md +1 -0
  85. package/docs/NumberInput.md +66 -2
  86. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
- import { CSSProperties } from 'react';
1
+ import { default as React, CSSProperties } from 'react';
2
2
  import { IconContent } from '../types/icon.types';
3
- import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
3
+ import { SlotClassNames, SlotStyles, DataProps } from '../types/slots.types';
4
4
  export declare enum ButtonStyleType {
5
5
  Primary = "primary",
6
6
  Default = "default",
@@ -10,7 +10,9 @@ export declare enum ButtonSize {
10
10
  Default = "default",
11
11
  Small = "small",
12
12
  Medium = "medium",
13
- Large = "large"
13
+ Large = "large",
14
+ /** Square, padding-free button for a lone icon. Give it its own width/height. */
15
+ Icon = "icon"
14
16
  }
15
17
  export declare enum ButtonType {
16
18
  Button = "button",
@@ -18,7 +20,11 @@ export declare enum ButtonType {
18
20
  Submit = "submit"
19
21
  }
20
22
  export type ButtonSlots = 'background' | 'content' | 'loadingContainer' | 'label';
21
- export interface ButtonProps extends HtmlProps {
23
+ /**
24
+ * `DataProps` supplies the `data-*` index signature, which `ButtonHTMLAttributes` doesn't cover.
25
+ * `type` and `onClick` below deliberately narrow their inherited counterparts.
26
+ */
27
+ export interface ButtonProps extends DataProps, React.ButtonHTMLAttributes<HTMLButtonElement> {
22
28
  className?: string;
23
29
  style?: CSSProperties;
24
30
  type?: ButtonType;
@@ -7,7 +7,7 @@ export declare enum CardStyleType {
7
7
  Outlined = "outlined",
8
8
  Filled = "filled"
9
9
  }
10
- export interface CardProps extends HtmlProps {
10
+ export interface CardProps extends Omit<HtmlProps, 'tabIndex'> {
11
11
  className?: string | undefined;
12
12
  children?: ReactNode;
13
13
  styleType?: CardStyleType;
@@ -1,7 +1,7 @@
1
1
  import { CSSProperties, ReactNode } from 'react';
2
2
  import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
3
3
  export type CarouselSlots = 'root' | 'track' | 'slide' | 'prevButton' | 'nextButton' | 'dots' | 'dot';
4
- export interface CarouselProps extends HtmlProps {
4
+ export interface CarouselProps extends Omit<HtmlProps, 'onChange'> {
5
5
  children?: ReactNode;
6
6
  currentIndex?: number;
7
7
  defaultIndex?: number;
@@ -13,6 +13,8 @@ export interface CarouselProps extends HtmlProps {
13
13
  showArrows?: boolean;
14
14
  showDots?: boolean;
15
15
  swipeable?: boolean;
16
+ lazyRender?: boolean;
17
+ adaptiveHeight?: boolean;
16
18
  className?: string;
17
19
  style?: CSSProperties;
18
20
  classNames?: SlotClassNames<CarouselSlots>;
@@ -2,7 +2,7 @@ import { CSSProperties, ReactNode } from 'react';
2
2
  import { FormValidator } from '../../services/formValidation';
3
3
  import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
4
4
  export type CheckboxSlots = 'icon' | 'checkmark' | 'label';
5
- export interface CheckboxProps extends HtmlProps {
5
+ export interface CheckboxProps extends Omit<HtmlProps, 'onToggle'> {
6
6
  label?: string;
7
7
  selected?: boolean;
8
8
  onToggle?: (isToggled: boolean, event?: React.MouseEvent | React.KeyboardEvent) => void;
@@ -12,6 +12,8 @@ export interface ChipProps extends HtmlProps {
12
12
  thumbnail?: React.ReactNode;
13
13
  styleType?: ChipStyleType;
14
14
  showRemoveIcon?: boolean;
15
+ /** Accessible name for the remove button. Default `'Remove'`. */
16
+ removeLabel?: string;
15
17
  onClick?: () => void;
16
18
  onRemove?: () => void;
17
19
  }
@@ -1,5 +1,5 @@
1
1
  import { HtmlProps } from '../types/slots.types';
2
- export interface ColorPickerProps extends HtmlProps {
2
+ export interface ColorPickerProps extends Omit<HtmlProps, 'onChange'> {
3
3
  className?: string;
4
4
  value?: string;
5
5
  onChange?: (hex: string) => void;
@@ -1,7 +1,7 @@
1
1
  import { default as React } from 'react';
2
2
  import { InputProps } from '../input/input.types';
3
3
  import { TextareaProps } from '../textarea/textarea.types';
4
- import { NumberInputProps } from '../numberInput/numberInput';
4
+ import { NumberInputProps } from '../numberInput/numberInput.types';
5
5
  import { DropdownProps } from '../dropdown/dropdown.types';
6
6
  import { InputDropdownProps } from '../inputDropdown/inputDropdown.types';
7
7
  import { CheckboxProps } from '../checkbox/checkbox.types';
@@ -48,7 +48,7 @@ export interface DropZoneRenderState {
48
48
  disabled: boolean;
49
49
  }
50
50
  export type DropZoneSlots = 'root' | 'content' | 'fileList' | 'fileItem' | 'input';
51
- export interface DropZoneProps extends HtmlProps {
51
+ export interface DropZoneProps extends Omit<HtmlProps, 'children'> {
52
52
  /** Static content, or a render function that receives the live drop state. */
53
53
  children?: React.ReactNode | ((state: DropZoneRenderState) => React.ReactNode);
54
54
  /**
@@ -6,7 +6,7 @@ export interface DropdownItem {
6
6
  label: ReactNode;
7
7
  disabled?: boolean;
8
8
  }
9
- export interface DropdownProps extends HtmlProps {
9
+ export interface DropdownProps extends Omit<HtmlProps, 'onFocus' | 'onBlur' | 'onMouseEnter' | 'onMouseLeave'> {
10
10
  formValidator?: FormValidator | null;
11
11
  onMouseEnter?: ((event: React.MouseEvent) => void) | null;
12
12
  onMouseLeave?: ((event: React.MouseEvent) => void) | null;
@@ -24,7 +24,7 @@ export interface ErrorBoundaryLabels {
24
24
  /** Toast shown if the copy fails (only visible if `ToastProvider` is mounted). */
25
25
  copyErrorToast?: string;
26
26
  }
27
- export interface ErrorBoundaryProps extends HtmlProps {
27
+ export interface ErrorBoundaryProps extends Omit<HtmlProps, 'title' | 'onError'> {
28
28
  children?: ReactNode;
29
29
  /** Heading shown above the error message. Default: "Something went wrong". */
30
30
  title?: ReactNode;
@@ -6,7 +6,7 @@ export declare enum Align {
6
6
  Center = "center"
7
7
  }
8
8
  export type FloatingMenuSlots = 'root' | 'trigger' | 'menu' | 'menuContainer';
9
- export interface FloatingMenuProps extends HtmlProps {
9
+ export interface FloatingMenuProps extends Omit<HtmlProps, 'content'> {
10
10
  align?: Align;
11
11
  children?: ReactNode;
12
12
  content?: ReactNode;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `true` when the primary pointing device is coarse (touch), kept current so a device that
3
+ * switches input modes re-renders.
4
+ *
5
+ * `useSyncExternalStore` rather than `useState` + `useEffect`: callers pick *markup* with this,
6
+ * so hydration has to start from the server's answer. Reading `matchMedia` in a `useState`
7
+ * initialiser makes the client's first render disagree with the server's HTML.
8
+ */
9
+ export declare function useCoarsePointer(): boolean;
10
+ export default useCoarsePointer;
@@ -9,7 +9,7 @@ export interface IconPickerItem {
9
9
  icon?: IconDefinition;
10
10
  customIcon?: React.ReactNode;
11
11
  }
12
- export interface IconPickerProps extends HtmlProps {
12
+ export interface IconPickerProps extends Omit<HtmlProps, 'onChange'> {
13
13
  data?: IconPickerItem[];
14
14
  selectedId?: string | null;
15
15
  label?: string;
@@ -1,6 +1,6 @@
1
1
  import { default as React } from 'react';
2
2
  import { FormValidator } from '../../services/formValidation';
3
- import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
3
+ import { SlotClassNames, SlotStyles, DataProps } from '../types/slots.types';
4
4
  export declare enum InputType {
5
5
  Edit = "edit",
6
6
  Phone = "phone",
@@ -17,7 +17,7 @@ export declare enum InputIconPosition {
17
17
  }
18
18
  export type InputSlots = 'label' | 'container' | 'input' | 'suffix' | 'upperRightLabel' | 'fieldset';
19
19
  type OverriddenInputAttributes = 'onChange' | 'onFocus' | 'onBlur' | 'onMouseEnter' | 'onMouseLeave' | 'onClick' | 'type' | 'value' | 'min' | 'max' | 'autoComplete';
20
- export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, OverriddenInputAttributes>, HtmlProps {
20
+ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, OverriddenInputAttributes>, DataProps {
21
21
  onMouseEnter?: ((event: React.MouseEvent) => void) | null;
22
22
  onMouseLeave?: ((event: React.MouseEvent) => void) | null;
23
23
  onFocus?: ((event: React.FocusEvent) => void) | null;
@@ -6,7 +6,7 @@ export interface InputDropdownItem {
6
6
  label?: string;
7
7
  value: string;
8
8
  }
9
- export interface InputDropdownProps extends HtmlProps {
9
+ export interface InputDropdownProps extends Omit<HtmlProps, 'onSelect'> {
10
10
  label?: string;
11
11
  value?: string;
12
12
  formValidator?: FormValidator | null;
@@ -1,6 +1,6 @@
1
1
  import { default as React } from 'react';
2
- import { HtmlProps } from '../types/baseProps.types';
3
- interface Properties extends HtmlProps, Omit<React.HTMLAttributes<HTMLDivElement>, 'tabIndex'> {
2
+ import { DataProps } from '../types/baseProps.types';
3
+ interface Properties extends DataProps, Omit<React.HTMLAttributes<HTMLDivElement>, 'tabIndex'> {
4
4
  tabIndex?: number | null;
5
5
  }
6
6
  declare const InteractableDiv: React.ForwardRefExoticComponent<Properties & React.RefAttributes<HTMLDivElement>>;
@@ -25,7 +25,7 @@ export interface KanbanColumnDef {
25
25
  hasMore?: boolean;
26
26
  }
27
27
  export type KanbanBoardSlots = 'dragOverlay';
28
- export interface KanbanBoardProps<T = unknown> extends HtmlProps {
28
+ export interface KanbanBoardProps<T = unknown> extends Omit<HtmlProps, 'onChange'> {
29
29
  /** Ordered list of column definitions. Each column owns its itemIds. */
30
30
  columns: KanbanColumnDef[];
31
31
  /** Flat map of all items keyed by their id. */
@@ -1,2 +1,3 @@
1
1
  import { default as NumberInput } from './numberInput';
2
+ export type { NumberInputProps, NumberInputArrowsLayout } from './numberInput.types';
2
3
  export default NumberInput;
@@ -1,34 +1,5 @@
1
- import { ReactElement, default as React } from 'react';
2
- import { NumericFormatProps } from 'react-number-format';
3
- import { FormValidator } from '../../services/formValidation';
4
- export interface NumberInputProps extends Omit<NumericFormatProps, 'onValueChange' | 'value' | 'customInput' | 'onChange' | 'step' | 'onKeyDown'> {
5
- value?: number | string;
6
- onChange?: (value: number | undefined) => void;
7
- formValidator?: FormValidator | null;
8
- label?: string;
9
- error?: string;
10
- className?: string;
11
- allowNegative?: boolean;
12
- decimalSeparator?: string;
13
- thousandSeparator?: string | boolean;
14
- prefix?: string;
15
- suffix?: string;
16
- decimalScale?: number;
17
- /**
18
- * Whether to pad the value to exactly `decimalScale` decimals. Default `true`
19
- * (e.g. with `decimalScale={2}`, `12` displays as `12.00`). Set `false` to make
20
- * `decimalScale` an upper limit only — the user may type fewer decimals and they
21
- * are kept as-is (`12` stays `12`, `12.1` stays `12.1`), while anything beyond
22
- * `decimalScale` is still truncated.
23
- */
24
- fixedDecimalScale?: boolean;
25
- placeholder?: string;
26
- sign?: '+' | '-';
27
- showArrows?: boolean;
28
- step?: number;
29
- readOnly?: boolean;
30
- isRequired?: boolean;
31
- onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
32
- }
1
+ import { ReactElement } from 'react';
2
+ import { NumberInputProps } from './numberInput.types';
3
+ export type { NumberInputProps, NumberInputArrowsLayout } from './numberInput.types';
33
4
  declare function NumberInput(props: NumberInputProps): ReactElement;
34
5
  export default NumberInput;
@@ -0,0 +1,61 @@
1
+ import { default as React } from 'react';
2
+ import { NumericFormatProps } from 'react-number-format';
3
+ import { FormValidator } from '../../services/formValidation';
4
+ /**
5
+ * How the stepper buttons are laid out.
6
+ *
7
+ * - `stacked` — chevrons stacked inside the field's right edge. Compact; suits a mouse.
8
+ * - `split` — square `−` / `+` buttons flanking the field, each as tall and wide as the field.
9
+ * Far apart with the field between them, so a mis-tap can't step the value the wrong way.
10
+ * - `auto` — `split` on a coarse (touch) pointer, `stacked` otherwise.
11
+ */
12
+ export type NumberInputArrowsLayout = 'auto' | 'stacked' | 'split';
13
+ export interface NumberInputProps extends Omit<NumericFormatProps, 'onValueChange' | 'value' | 'customInput' | 'onChange' | 'step' | 'onKeyDown' | 'min' | 'max'> {
14
+ value?: number | string;
15
+ onChange?: (value: number | undefined) => void;
16
+ formValidator?: FormValidator | null;
17
+ label?: string;
18
+ error?: string;
19
+ className?: string;
20
+ allowNegative?: boolean;
21
+ decimalSeparator?: string;
22
+ thousandSeparator?: string | boolean;
23
+ prefix?: string;
24
+ suffix?: string;
25
+ decimalScale?: number;
26
+ /**
27
+ * Whether to pad the value to exactly `decimalScale` decimals. Default `true`
28
+ * (e.g. with `decimalScale={2}`, `12` displays as `12.00`). Set `false` to make
29
+ * `decimalScale` an upper limit only — the user may type fewer decimals and they
30
+ * are kept as-is (`12` stays `12`, `12.1` stays `12.1`), while anything beyond
31
+ * `decimalScale` is still truncated.
32
+ */
33
+ fixedDecimalScale?: boolean;
34
+ placeholder?: string;
35
+ sign?: '+' | '-';
36
+ showArrows?: boolean;
37
+ step?: number;
38
+ /**
39
+ * Lower bound. Constrains the steppers and the ArrowDown key, disables the decrease button
40
+ * once reached, and clamps a typed value on blur and on Enter — the two moments it stops
41
+ * being mid-edit. Typing is never blocked; see {@link NumberInputProps.max}.
42
+ */
43
+ min?: number;
44
+ /**
45
+ * Upper bound. Behaves exactly like {@link NumberInputProps.min} in the other direction.
46
+ *
47
+ * Neither bound rejects a keystroke as it is typed — an edit passes through out-of-range
48
+ * states on its way somewhere valid — and an empty field is never clamped. Use a
49
+ * `formValidator` if out-of-range input must be *rejected* rather than corrected.
50
+ */
51
+ max?: number;
52
+ /** Stepper layout. Default `'auto'`. */
53
+ arrowsLayout?: NumberInputArrowsLayout;
54
+ /** Accessible name for the increase button. Default `'Increase'`. */
55
+ increaseLabel?: string;
56
+ /** Accessible name for the decrease button. Default `'Decrease'`. */
57
+ decreaseLabel?: string;
58
+ readOnly?: boolean;
59
+ isRequired?: boolean;
60
+ onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
61
+ }
@@ -0,0 +1,17 @@
1
+ export interface UseStepRepeatResult {
2
+ /** Fires one step immediately, then starts the hold-to-repeat timer. */
3
+ start: (direction: 1 | -1, multiplier: number) => void;
4
+ /** Cancels a running repeat. Safe to call when nothing is running. */
5
+ stop: () => void;
6
+ }
7
+ /**
8
+ * Hold-to-repeat for the stepper buttons: one step on press, then an accelerating repeat.
9
+ *
10
+ * The release is watched on `window` rather than by capturing the pointer, which would retarget
11
+ * the following click past the node Button's ripple listens on. Capture would have guaranteed a
12
+ * `pointerup`, so the extra listeners cover the ways a press can end without one.
13
+ *
14
+ * `onStep` returns whether anything changed; `false` ends the repeat, so a hold at a bound stops.
15
+ */
16
+ export declare function useStepRepeat(onStep: (delta: number) => boolean): UseStepRepeatResult;
17
+ export default useStepRepeat;
@@ -5,7 +5,7 @@ export interface Option {
5
5
  key: string;
6
6
  }
7
7
  export type OptionPickerSlots = 'root' | 'chip' | 'option';
8
- export interface OptionPickerProps extends HtmlProps {
8
+ export interface OptionPickerProps extends Omit<HtmlProps, 'onChange'> {
9
9
  className?: string;
10
10
  style?: React.CSSProperties;
11
11
  classNames?: SlotClassNames<OptionPickerSlots>;
@@ -8,7 +8,7 @@ export declare enum OtpInputCharset {
8
8
  /** Letters and digits. */
9
9
  Alphanumeric = "alphanumeric"
10
10
  }
11
- export interface OtpInputProps extends HtmlProps {
11
+ export interface OtpInputProps extends Omit<HtmlProps, 'onChange'> {
12
12
  /** Number of character boxes. Default 6. */
13
13
  length?: number;
14
14
  /** Current code as a plain string, e.g. "123456". */
@@ -20,7 +20,7 @@ export declare enum PopoverTrigger {
20
20
  Focus = "focus"
21
21
  }
22
22
  export type PopoverSlots = 'root' | 'trigger' | 'floating' | 'panel' | 'arrow';
23
- export interface PopoverProps extends HtmlProps {
23
+ export interface PopoverProps extends Omit<HtmlProps, 'content'> {
24
24
  /** The trigger element. */
25
25
  children?: ReactNode;
26
26
  /** The popover body. */
@@ -16,7 +16,7 @@ export interface RadioOption {
16
16
  disabled?: boolean;
17
17
  }
18
18
  export type RadioGroupSlots = 'root' | 'option' | 'radio' | 'dot' | 'label' | 'description';
19
- export interface RadioGroupProps extends HtmlProps {
19
+ export interface RadioGroupProps extends Omit<HtmlProps, 'onChange'> {
20
20
  /** The selectable options. */
21
21
  options: RadioOption[];
22
22
  /** Controlled selected value. Omit for uncontrolled. */
@@ -2,7 +2,7 @@ import { CSSProperties } from 'react';
2
2
  import { IconContent } from '../types/icon.types';
3
3
  import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
4
4
  export type RatingSlots = 'root' | 'item' | 'iconEmpty' | 'iconFilled';
5
- export interface RatingProps extends HtmlProps {
5
+ export interface RatingProps extends Omit<HtmlProps, 'onChange'> {
6
6
  value?: number;
7
7
  defaultValue?: number;
8
8
  onChange?: (value: number) => void;
@@ -1,5 +1,5 @@
1
1
  import { HtmlProps } from '../types/slots.types';
2
- export interface SearchInputProps extends HtmlProps {
2
+ export interface SearchInputProps extends Omit<HtmlProps, 'onChange'> {
3
3
  value: string;
4
4
  onChange: (value: string) => void;
5
5
  onDebounce?: (value: string) => void;
@@ -9,7 +9,7 @@ export declare enum SectionHeaderSize {
9
9
  }
10
10
  export type SectionHeaderAction = IconAction;
11
11
  export type SectionHeaderSlots = 'root' | 'identity' | 'leading' | 'titles' | 'title' | 'subtitle' | 'trailing' | 'left' | 'center' | 'actions';
12
- export interface SectionHeaderProps extends HtmlProps {
12
+ export interface SectionHeaderProps extends Omit<HtmlProps, 'title'> {
13
13
  title?: ReactNode;
14
14
  subtitle?: ReactNode;
15
15
  icon?: IconContent;
@@ -7,7 +7,7 @@ export interface SliderMark {
7
7
  label?: ReactNode;
8
8
  }
9
9
  export type SliderSlots = 'root' | 'track' | 'range' | 'thumb' | 'mark' | 'markLabel' | 'value';
10
- export interface SliderProps extends HtmlProps {
10
+ export interface SliderProps extends Omit<HtmlProps, 'onChange'> {
11
11
  /** Controlled value. Omit for uncontrolled. */
12
12
  value?: number;
13
13
  /** Initial value when uncontrolled (default `min`). */
@@ -2,7 +2,7 @@ import { CSSProperties, ReactNode } from 'react';
2
2
  import { FormValidator } from '../../services/formValidation';
3
3
  import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
4
4
  export type SwitchSlots = 'track' | 'thumb' | 'label';
5
- export interface SwitchProps extends HtmlProps {
5
+ export interface SwitchProps extends Omit<HtmlProps, 'onToggle'> {
6
6
  label?: string;
7
7
  selected?: boolean;
8
8
  onToggle?: (isToggled: boolean, event?: React.MouseEvent | React.KeyboardEvent) => void;
@@ -9,7 +9,7 @@ export interface TabHeaderTab {
9
9
  subtitle?: string;
10
10
  disabled?: boolean;
11
11
  }
12
- export interface TabHeaderProps extends HtmlProps {
12
+ export interface TabHeaderProps extends Omit<HtmlProps, 'onChange'> {
13
13
  tabs: TabHeaderTab[];
14
14
  currentTab: string;
15
15
  onChange: (id: string) => void;
@@ -2,7 +2,7 @@ import { default as React } from 'react';
2
2
  import { FormValidator } from '../../services/formValidation';
3
3
  import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
4
4
  export type TimeInputSlots = 'root' | 'clock' | 'clockHeader' | 'headerSegment' | 'meridiem' | 'clockFace' | 'clockHand' | 'clockNumber' | 'footer';
5
- export interface TimeInputProps extends HtmlProps {
5
+ export interface TimeInputProps extends Omit<HtmlProps, 'onChange' | 'onSelect'> {
6
6
  /** Current time as a "HH:MM" (24-hour) string. */
7
7
  value?: string | null;
8
8
  /** Alias for `value`, to mirror DatePicker. */
@@ -1,8 +1,23 @@
1
1
  import { default as React } from 'react';
2
- /** HTML pass-through props accepted on the root element of every component. */
3
- export type HtmlProps = React.AriaAttributes & {
4
- id?: string;
5
- role?: React.AriaRole;
6
- } & {
2
+ /**
3
+ * TypeScript allows hyphenated attributes on *intrinsic* elements only, so a component's props
4
+ * interface has to declare these itself — no React attribute type provides them.
5
+ */
6
+ type DataAttributes = {
7
7
  [K in `data-${string}`]?: string;
8
8
  };
9
+ /**
10
+ * HTML pass-through props accepted on the root element of every component: the full native
11
+ * attribute set for that element, plus `data-*`.
12
+ *
13
+ * Pass the root's element type for correctly-typed event handlers (`HtmlProps<HTMLDivElement>`);
14
+ * the default is the loose `HTMLElement`. Where the root is not a plain container, extend the
15
+ * matching React type instead and add `DataProps` for the `data-*` half — `Button` does this
16
+ * with `React.ButtonHTMLAttributes<HTMLButtonElement>`.
17
+ *
18
+ * A component prop that collides with a native one of the same name must `Omit` the native one.
19
+ */
20
+ export type HtmlProps<E extends HTMLElement = HTMLElement> = React.HTMLAttributes<E> & DataAttributes;
21
+ /** The `data-*` half of {@link HtmlProps}, for components that source attributes elsewhere. */
22
+ export type DataProps = DataAttributes;
23
+ export {};
@@ -1,4 +1,4 @@
1
1
  import { CSSProperties } from 'react';
2
2
  export type SlotClassNames<Keys extends string> = Partial<Record<Keys, string>>;
3
3
  export type SlotStyles<Keys extends string> = Partial<Record<Keys, CSSProperties>>;
4
- export type { HtmlProps } from './baseProps.types';
4
+ export type { HtmlProps, DataProps } from './baseProps.types';
package/docs/Button.md CHANGED
@@ -29,6 +29,18 @@ import { faSave } from '@fortawesome/free-solid-svg-icons';
29
29
  // Small
30
30
  <Button size={ButtonSize.Small}>Cancel</Button>
31
31
 
32
+ // Icon-only — padding-free and square; give it the box size you want
33
+ <Button size={ButtonSize.Icon} icon={faPlus} aria-label="Add" style={{ width: 44, height: 44 }} />
34
+
35
+ // Press-and-hold: act on press rather than release
36
+ <Button
37
+ icon={faPlus}
38
+ aria-label="Increase"
39
+ onPointerDown={startRepeat}
40
+ onPointerUp={stopRepeat}
41
+ onPointerCancel={stopRepeat}
42
+ />
43
+
32
44
  // Submit button in a form
33
45
  <Button type={ButtonType.Submit} styleType={ButtonStyleType.Primary}>Submit</Button>
34
46
  ```
@@ -36,7 +48,7 @@ import { faSave } from '@fortawesome/free-solid-svg-icons';
36
48
  **Enums:**
37
49
 
38
50
  - `ButtonStyleType`: `Primary` | `Default` | `Delete`
39
- - `ButtonSize`: `Default` | `Small` | `Medium` | `Large`
51
+ - `ButtonSize`: `Default` | `Small` | `Medium` | `Large` | `Icon`
40
52
  - `ButtonType`: `Button` | `Reset` | `Submit`
41
53
 
42
54
  **Key props:**
@@ -44,13 +56,19 @@ import { faSave } from '@fortawesome/free-solid-svg-icons';
44
56
  | Prop | Type | Description |
45
57
  |------|------|-------------|
46
58
  | `styleType` | `ButtonStyleType` | Visual variant |
47
- | `size` | `ButtonSize` | Size variant |
59
+ | `size` | `ButtonSize` | Size variant. `Icon` strips all padding, inherits the surrounding text size, and centres a lone icon — set the width/height yourself |
48
60
  | `type` | `ButtonType` | HTML button type |
49
61
  | `icon` | `IconDefinition \| ReactElement` | FontAwesome icon or any React element, shown before label |
50
62
  | `isLoading` | `boolean` | Replaces content with a spinner |
51
63
  | `disabled` | `boolean` | |
52
64
  | `onClick` | `(e: MouseEvent) => void \| Promise<void>` | |
53
65
 
66
+ `ButtonProps` extends `React.ButtonHTMLAttributes<HTMLButtonElement>`, so every native `<button>`
67
+ attribute is accepted and forwarded — pointer handlers (`onPointerDown` and friends, for
68
+ press-and-hold controls that act on press rather than release), `onContextMenu`, `tabIndex`,
69
+ `name`, `value`, `form`, `autoFocus`, and the rest. `type` and `onClick` are narrowed: `type`
70
+ takes the `ButtonType` enum, and `onClick` may return a promise.
71
+
54
72
  **Theming (default style):** the `Default` style is transparent text-coloured by default. Override it theme-wide (or per button via `style`) without touching `Primary`/`Delete`:
55
73
 
56
74
  - `--button-default-background` — fill (default transparent)
@@ -73,3 +91,6 @@ const theme: Theme = {
73
91
  ```
74
92
 
75
93
  **Slots:** `background` `content` `loadingContainer` `label`
94
+
95
+ **Sizing in a flex row:** a Button never shrinks below its own content (`min-width: min-content`),
96
+ so an icon is never cut off by a flexible sibling. A multi-word label still wraps above that floor.
package/docs/Carousel.md CHANGED
@@ -37,6 +37,19 @@ const [index, setIndex] = useState(0);
37
37
  <div>Slide 2</div>
38
38
  </Carousel>
39
39
 
40
+ // Grow and shrink with the active slide instead of sizing every slide to the tallest one
41
+ <Carousel adaptiveHeight>
42
+ <div>Short slide</div>
43
+ <div>A much taller slide with a lot more content in it</div>
44
+ </Carousel>
45
+
46
+ // Only render the visible slides (plus the immediate neighbours) — for heavy slide content
47
+ <Carousel lazyRender>
48
+ <HeavyChart />
49
+ <HeavyChart />
50
+ <HeavyChart />
51
+ </Carousel>
52
+
40
53
  // No swipe/drag, arrows only
41
54
  <Carousel swipeable={false} showDots={false}>
42
55
  <div>Slide 1</div>
@@ -63,6 +76,12 @@ Pass slides as direct children (an array or a set of sibling elements), not thro
63
76
  | `showArrows` | `boolean` | Show the prev/next buttons (default `true`); hidden automatically with one slide or none |
64
77
  | `showDots` | `boolean` | Show the position dots (default `true`); hidden automatically with one slide or none |
65
78
  | `swipeable` | `boolean` | Allow dragging/swiping the track (default `true`) |
79
+ | `adaptiveHeight` | `boolean` | Size the carousel to the active slide's height, animated over the same duration as the slide transition, instead of to the tallest slide (default `false`) |
80
+ | `lazyRender` | `boolean` | Only mount the current slide and its immediate neighbours; off-screen slides render as empty placeholders and unmount once they move out of range (default `false`) |
81
+
82
+ **Height:** by default the track stretches every slide to the height of the tallest one, so the carousel keeps one fixed height. Set `adaptiveHeight` to have it follow the active slide's own height instead; the height animates over the same 0.4s as the slide transition, so a taller incoming slide is clipped until the two finish together. During a drag the height only follows once the new slide commits on release, so a drag between slides of very different heights clips for as long as the drag lasts.
83
+
84
+ **Lazy rendering:** `lazyRender` unmounts a slide's content once it is more than one position away from the current one. Slides a multi-step jump travels past stay mounted for the duration of the transition, and pruning happens when the track's transform transition ends, so a consumer that disables the track transition in CSS keeps slides mounted rather than unmounting them. Unmounted slides lose their internal state (scroll position, uncontrolled inputs, media playback), which is why the flag is opt-in. Combine it with `adaptiveHeight` when slides differ in height, so the carousel sizes to the active slide rather than to whichever slides happen to be mounted.
66
85
 
67
86
  **Global defaults:** adopts `ConfigProvider`, e.g. `defaultProps={{ Carousel: { autoPlay: true } }}`. See [ConfigProvider.md](ConfigProvider.md).
68
87
 
package/docs/Chip.md CHANGED
@@ -56,6 +56,7 @@ import { Chip, ChipContainer, ChipStyleType } from '@ahrowe/ui';
56
56
  | `text` | `string` | Chip label |
57
57
  | `styleType` | `ChipStyleType` | Colour variant (default `Default`) |
58
58
  | `thumbnail` | `string` | Avatar image URL |
59
+ | `removeLabel` | `string` | Accessible name for the remove button. Default: `'Remove'` |
59
60
  | `showRemoveIcon` | `boolean` | Show × icon |
60
61
  | `onRemove` | `() => void` | Remove button handler |
61
62
  | `onClick` | `() => void` | Makes chip clickable |