@ahrowe/ui 0.19.4 → 0.21.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.
- package/dist/esm/common/actionIcon/actionIcon.mjs +1 -1
- package/dist/esm/common/actionIcon/actionIcon.mjs.map +1 -1
- package/dist/esm/common/alert/alert.mjs +1 -1
- package/dist/esm/common/alert/alert.mjs.map +1 -1
- package/dist/esm/common/alert/alert.types.mjs.map +1 -1
- package/dist/esm/common/avatar/avatar.mjs +1 -1
- package/dist/esm/common/avatar/avatar.mjs.map +1 -1
- package/dist/esm/common/breadcrumb/breadcrumb.mjs +1 -1
- package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -1
- package/dist/esm/common/button/button.mjs +1 -1
- package/dist/esm/common/button/button.mjs.map +1 -1
- package/dist/esm/common/button/button.types.mjs.map +1 -1
- package/dist/esm/common/emptyState/emptyState.mjs +1 -1
- package/dist/esm/common/emptyState/emptyState.mjs.map +1 -1
- package/dist/esm/common/fab/fab.mjs +1 -1
- package/dist/esm/common/fab/fab.mjs.map +1 -1
- package/dist/esm/common/otpInput/otpInput.mjs +2 -0
- package/dist/esm/common/otpInput/otpInput.mjs.map +1 -0
- package/dist/esm/common/otpInput/otpInput.module.mjs +2 -0
- package/dist/esm/common/otpInput/otpInput.module.mjs.map +1 -0
- package/dist/esm/common/otpInput/otpInput.types.mjs +2 -0
- package/dist/esm/common/otpInput/otpInput.types.mjs.map +1 -0
- package/dist/esm/common/rating/rating.mjs +1 -1
- package/dist/esm/common/rating/rating.mjs.map +1 -1
- package/dist/esm/common/sectionHeader/sectionHeader.mjs +1 -1
- package/dist/esm/common/sectionHeader/sectionHeader.mjs.map +1 -1
- package/dist/esm/common/sectionHeader/sectionHeader.types.mjs.map +1 -1
- package/dist/esm/common/splitButton/splitButton.mjs +1 -1
- package/dist/esm/common/splitButton/splitButton.mjs.map +1 -1
- package/dist/esm/common/stepper/stepper.mjs +1 -1
- package/dist/esm/common/stepper/stepper.mjs.map +1 -1
- package/dist/esm/common/stepper/stepper.module.mjs.map +1 -1
- package/dist/esm/common/stepper/stepper.types.mjs.map +1 -1
- package/dist/esm/common/tabHeader/tabHeader.mjs +1 -1
- package/dist/esm/common/tabHeader/tabHeader.mjs.map +1 -1
- package/dist/esm/common/timeline/timeline.mjs +1 -1
- package/dist/esm/common/timeline/timeline.mjs.map +1 -1
- package/dist/esm/common/timeline/timeline.module.mjs +1 -1
- package/dist/esm/common/timeline/timeline.module.mjs.map +1 -1
- package/dist/esm/common/timeline/timeline.types.mjs.map +1 -1
- package/dist/esm/common/timer/timer.chime.mjs +2 -0
- package/dist/esm/common/timer/timer.chime.mjs.map +1 -0
- package/dist/esm/common/timer/timer.mjs +2 -0
- package/dist/esm/common/timer/timer.mjs.map +1 -0
- package/dist/esm/common/timer/timer.module.mjs +2 -0
- package/dist/esm/common/timer/timer.module.mjs.map +1 -0
- package/dist/esm/common/utils/renderIcon.mjs +2 -0
- package/dist/esm/common/utils/renderIcon.mjs.map +1 -0
- package/dist/esm/index.mjs +1 -1
- package/dist/index.cjs +6 -6
- package/dist/index.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/dist/types/package/common/actionButtons/actionButtons.types.d.ts +3 -3
- package/dist/types/package/common/actionIcon/actionIcon.types.d.ts +2 -2
- package/dist/types/package/common/alert/alert.types.d.ts +2 -2
- package/dist/types/package/common/avatar/avatar.types.d.ts +2 -2
- package/dist/types/package/common/breadcrumb/breadcrumb.types.d.ts +2 -2
- package/dist/types/package/common/button/button.types.d.ts +2 -2
- package/dist/types/package/common/configProvider/configProvider.types.d.ts +4 -0
- package/dist/types/package/common/emptyState/emptyState.types.d.ts +2 -2
- package/dist/types/package/common/fab/fab.types.d.ts +2 -2
- package/dist/types/package/common/otpInput/index.d.ts +2 -0
- package/dist/types/package/common/otpInput/otpInput.d.ts +4 -0
- package/dist/types/package/common/otpInput/otpInput.types.d.ts +49 -0
- package/dist/types/package/common/rating/rating.types.d.ts +2 -2
- package/dist/types/package/common/sectionHeader/sectionHeader.types.d.ts +2 -2
- package/dist/types/package/common/splitButton/splitButton.types.d.ts +2 -2
- package/dist/types/package/common/stepper/stepper.types.d.ts +3 -3
- package/dist/types/package/common/tabHeader/tabHeader.types.d.ts +2 -2
- package/dist/types/package/common/themeProvider/theme.types.d.ts +14 -0
- package/dist/types/package/common/timeline/timeline.types.d.ts +3 -3
- package/dist/types/package/common/timer/index.d.ts +2 -0
- package/dist/types/package/common/timer/timer.chime.d.ts +1 -0
- package/dist/types/package/common/timer/timer.d.ts +3 -0
- package/dist/types/package/common/timer/timer.types.d.ts +101 -0
- package/dist/types/package/common/types/actions.types.d.ts +2 -2
- package/dist/types/package/common/types/icon.types.d.ts +17 -0
- package/dist/types/package/common/utils/renderIcon.d.ts +29 -0
- package/dist/types/package/index.d.ts +4 -0
- package/docs/ActionIcon.md +1 -1
- package/docs/Alert.md +1 -1
- package/docs/Avatar.md +1 -1
- package/docs/Breadcrumb.md +1 -1
- package/docs/Button.md +1 -1
- package/docs/CLAUDE.md +24 -0
- package/docs/ConfigProvider.md +2 -2
- package/docs/EmptyState.md +1 -1
- package/docs/OtpInput.md +92 -0
- package/docs/Rating.md +1 -1
- package/docs/SectionHeader.md +2 -2
- package/docs/Stepper.md +1 -1
- package/docs/TabHeader.md +1 -1
- package/docs/Timeline.md +1 -1
- package/docs/Timer.md +141 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CSSProperties } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { IconContent } from '../types/icon.types';
|
|
3
3
|
import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
|
|
4
4
|
export declare enum ButtonStyleType {
|
|
5
5
|
Primary = "primary",
|
|
@@ -26,7 +26,7 @@ export interface ButtonProps extends HtmlProps {
|
|
|
26
26
|
size?: ButtonSize;
|
|
27
27
|
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => Promise<void> | void;
|
|
28
28
|
children?: React.ReactNode;
|
|
29
|
-
icon?:
|
|
29
|
+
icon?: IconContent;
|
|
30
30
|
isLoading?: boolean;
|
|
31
31
|
disabled?: boolean;
|
|
32
32
|
title?: string;
|
|
@@ -27,6 +27,8 @@ import { RevealLensProps } from '../revealLens/revealLens.types';
|
|
|
27
27
|
import { TiltProps } from '../tilt/tilt.types';
|
|
28
28
|
import { FlipProps } from '../flip/flip.types';
|
|
29
29
|
import { OptionPickerProps } from '../optionPicker/optionPicker.types';
|
|
30
|
+
import { TimerProps } from '../timer/timer.types';
|
|
31
|
+
import { OtpInputProps } from '../otpInput/otpInput.types';
|
|
30
32
|
/**
|
|
31
33
|
* Global default props keyed by component name.
|
|
32
34
|
*
|
|
@@ -70,6 +72,8 @@ export interface ComponentDefaults {
|
|
|
70
72
|
Tilt?: Partial<TiltProps>;
|
|
71
73
|
Flip?: Partial<FlipProps>;
|
|
72
74
|
OptionPicker?: Partial<OptionPickerProps>;
|
|
75
|
+
Timer?: Partial<TimerProps>;
|
|
76
|
+
OtpInput?: Partial<OtpInputProps>;
|
|
73
77
|
}
|
|
74
78
|
export interface ConfigProviderProps {
|
|
75
79
|
children: React.ReactNode;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { IconContent } from '../types/icon.types';
|
|
3
3
|
import { HtmlProps } from '../types/slots.types';
|
|
4
4
|
export interface EmptyStateProps extends HtmlProps {
|
|
5
5
|
className?: string;
|
|
6
|
-
icon?:
|
|
6
|
+
icon?: IconContent;
|
|
7
7
|
children?: ReactNode;
|
|
8
8
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { IconContent } from '../types/icon.types';
|
|
3
3
|
import { HtmlProps } from '../types/slots.types';
|
|
4
4
|
export type FabSize = 'default' | 'mini';
|
|
5
5
|
export interface FabMenuEntry {
|
|
6
6
|
id: string;
|
|
7
|
-
icon:
|
|
7
|
+
icon: IconContent;
|
|
8
8
|
label?: string;
|
|
9
9
|
}
|
|
10
10
|
export interface FabProps extends HtmlProps {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { FormValidator } from '../../services/formValidation';
|
|
3
|
+
import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
|
|
4
|
+
export type OtpInputSlots = 'root' | 'label' | 'inputs' | 'input' | 'separator';
|
|
5
|
+
export declare enum OtpInputCharset {
|
|
6
|
+
/** Digits only (0-9). Shows a numeric mobile keyboard. */
|
|
7
|
+
Numeric = "numeric",
|
|
8
|
+
/** Letters and digits. */
|
|
9
|
+
Alphanumeric = "alphanumeric"
|
|
10
|
+
}
|
|
11
|
+
export interface OtpInputProps extends HtmlProps {
|
|
12
|
+
/** Number of character boxes. Default 6. */
|
|
13
|
+
length?: number;
|
|
14
|
+
/** Current code as a plain string, e.g. "123456". */
|
|
15
|
+
value?: string;
|
|
16
|
+
/** Fired on every change with the full current code (may be shorter than `length`). */
|
|
17
|
+
onChange?: ((value: string) => void) | null;
|
|
18
|
+
/** Fired once, when the code reaches `length` characters. */
|
|
19
|
+
onComplete?: ((value: string) => void) | null;
|
|
20
|
+
formValidator?: FormValidator | null;
|
|
21
|
+
/** Restricts which characters can be typed and picks the mobile keyboard. Default `numeric`. */
|
|
22
|
+
charset?: OtpInputCharset;
|
|
23
|
+
/** Render each box's value as a dot, like a password field. */
|
|
24
|
+
masked?: boolean;
|
|
25
|
+
/** Draw a small gap after these 1-based box indices, e.g. `[3]` to split 6 boxes into 3+3. */
|
|
26
|
+
groupAfter?: number[];
|
|
27
|
+
label?: string;
|
|
28
|
+
isValid?: boolean;
|
|
29
|
+
/** Shown in an error Tooltip on focus/hover once `isValid` is `false` (or, with a
|
|
30
|
+
* `formValidator`, once it's touched and has an error). Persists until the value changes
|
|
31
|
+
* `isValid`/`formValidator`'s error state itself — see `clearOnError` to auto-dismiss it. */
|
|
32
|
+
errorMessage?: string;
|
|
33
|
+
isRequired?: boolean;
|
|
34
|
+
/** When an error newly appears (`isValid`/`formValidator` turning invalid), clear every box and
|
|
35
|
+
* refocus the first one after `clearErrorDelay`, so the next attempt starts clean instead of the
|
|
36
|
+
* user editing individual wrong digits (and re-triggering `onComplete` on every keystroke while
|
|
37
|
+
* the code stays at full length). Default `false`. */
|
|
38
|
+
clearOnError?: boolean;
|
|
39
|
+
/** Delay in ms before `clearOnError` clears the boxes, so the wrong code and error message are
|
|
40
|
+
* still visible for a moment first. Default `900`. */
|
|
41
|
+
clearErrorDelay?: number;
|
|
42
|
+
disabled?: boolean;
|
|
43
|
+
/** Focuses the first empty box (or the first box) on mount. */
|
|
44
|
+
autoFocus?: boolean;
|
|
45
|
+
className?: string;
|
|
46
|
+
style?: React.CSSProperties;
|
|
47
|
+
classNames?: SlotClassNames<OtpInputSlots>;
|
|
48
|
+
styles?: SlotStyles<OtpInputSlots>;
|
|
49
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CSSProperties } from 'react';
|
|
2
|
-
import {
|
|
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
5
|
export interface RatingProps extends HtmlProps {
|
|
@@ -11,7 +11,7 @@ export interface RatingProps extends HtmlProps {
|
|
|
11
11
|
allowClear?: boolean;
|
|
12
12
|
readOnly?: boolean;
|
|
13
13
|
disabled?: boolean;
|
|
14
|
-
icon?:
|
|
14
|
+
icon?: IconContent;
|
|
15
15
|
className?: string;
|
|
16
16
|
style?: CSSProperties;
|
|
17
17
|
classNames?: SlotClassNames<RatingSlots>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { IconContent } from '../types/icon.types';
|
|
3
3
|
import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
|
|
4
4
|
import { IconAction } from '../types/actions.types';
|
|
5
5
|
export declare enum SectionHeaderSize {
|
|
@@ -12,7 +12,7 @@ export type SectionHeaderSlots = 'root' | 'leading' | 'titles' | 'title' | 'subt
|
|
|
12
12
|
export interface SectionHeaderProps extends HtmlProps {
|
|
13
13
|
title?: ReactNode;
|
|
14
14
|
subtitle?: ReactNode;
|
|
15
|
-
icon?:
|
|
15
|
+
icon?: IconContent;
|
|
16
16
|
thumbnail?: string | ReactNode;
|
|
17
17
|
left?: ReactNode;
|
|
18
18
|
center?: ReactNode;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { IconContent } from '../types/icon.types';
|
|
3
3
|
import { ButtonStyleType, ButtonSize } from '../button/button.types';
|
|
4
4
|
import { Align } from '../floatingMenu/floatingMenu.types';
|
|
5
5
|
import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
|
|
@@ -8,7 +8,7 @@ export interface SplitButtonAction {
|
|
|
8
8
|
label: ReactNode;
|
|
9
9
|
onClick: () => void;
|
|
10
10
|
disabled?: boolean;
|
|
11
|
-
icon?:
|
|
11
|
+
icon?: IconContent;
|
|
12
12
|
}
|
|
13
13
|
export type SplitButtonSlots = 'root' | 'primaryButton' | 'triggerButton' | 'menu' | 'menuItem';
|
|
14
14
|
export interface SplitButtonProps extends HtmlProps {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { IconContent } from '../types/icon.types';
|
|
3
3
|
import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
|
|
4
4
|
/** Layout direction of the stepper. */
|
|
5
5
|
export declare enum StepperAlignment {
|
|
@@ -46,8 +46,8 @@ export interface StepperStep {
|
|
|
46
46
|
description?: React.ReactNode;
|
|
47
47
|
/** Collapsible body content, rendered under the label (vertical only). */
|
|
48
48
|
content?: React.ReactNode;
|
|
49
|
-
/**
|
|
50
|
-
icon?:
|
|
49
|
+
/** Icon shown in the marker instead of the step number — a FontAwesome icon or any node. */
|
|
50
|
+
icon?: IconContent;
|
|
51
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. */
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { IconContent } from '../types/icon.types';
|
|
3
3
|
import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
|
|
4
4
|
export type TabHeaderSlots = 'root' | 'tab' | 'icon' | 'labels' | 'title' | 'subtitle';
|
|
5
5
|
export interface TabHeaderTab {
|
|
6
6
|
id: string;
|
|
7
|
-
icon:
|
|
7
|
+
icon: IconContent;
|
|
8
8
|
title?: string;
|
|
9
9
|
subtitle?: string;
|
|
10
10
|
disabled?: boolean;
|
|
@@ -109,6 +109,20 @@ export interface ThemeVariables {
|
|
|
109
109
|
'--stepper-gap'?: string;
|
|
110
110
|
/** Text/check colour on a filled marker. Falls back to --text-on-primary. */
|
|
111
111
|
'--stepper-text-on-marker'?: string;
|
|
112
|
+
/** Timer ring track (unfilled) colour. Falls back to --background-accent-light. */
|
|
113
|
+
'--timer-track-color'?: string;
|
|
114
|
+
/** Timer ring progress (remaining time) colour. Falls back to --primary-color. */
|
|
115
|
+
'--timer-progress-color'?: string;
|
|
116
|
+
/** Timer ring colour once inside the urgent threshold. Falls back to --error-color. */
|
|
117
|
+
'--timer-urgent-color'?: string;
|
|
118
|
+
/** Timer ring diameter. Falls back to 160px (also settable per instance via the `size` prop). */
|
|
119
|
+
'--timer-size'?: string;
|
|
120
|
+
/** Timer ring stroke thickness. Falls back to 10px (also settable per instance via `strokeWidth`). */
|
|
121
|
+
'--timer-stroke-width'?: string;
|
|
122
|
+
/** Timer MM:SS readout text colour. Falls back to --text-color. */
|
|
123
|
+
'--timer-text-color'?: string;
|
|
124
|
+
/** Timer label (below the readout) text colour. Falls back to --text-dark. */
|
|
125
|
+
'--timer-label-color'?: string;
|
|
112
126
|
/** Width a column collapses to once it has no cards (see `collapseEmptyColumns`). Falls back to 140px. */
|
|
113
127
|
'--kanban-empty-column-width'?: string;
|
|
114
128
|
'--option-picker-padding'?: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { IconContent } from '../types/icon.types';
|
|
3
3
|
import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
|
|
4
4
|
/** Layout of entries relative to the connecting line. */
|
|
5
5
|
export declare enum TimelineAlignment {
|
|
@@ -28,8 +28,8 @@ export interface TimelineItem {
|
|
|
28
28
|
description?: React.ReactNode;
|
|
29
29
|
/** Rendered next to the title, e.g. a date or relative time ("2 hours ago"). */
|
|
30
30
|
timestamp?: React.ReactNode;
|
|
31
|
-
/**
|
|
32
|
-
icon?:
|
|
31
|
+
/** Icon shown in the marker instead of a plain dot — a FontAwesome icon or any node. */
|
|
32
|
+
icon?: IconContent;
|
|
33
33
|
/** Semantic marker colour (default `Default`). */
|
|
34
34
|
status?: TimelineItemStatus;
|
|
35
35
|
/** Extra content rendered under the description, e.g. a diff, an attachment, an actor avatar. */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const DEFAULT_CHIME_DATA_URI = "data:audio/wav;base64,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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANACUAKwAKAMr/kv+R/9n/TwCxALwAVwCs/xb/8/5p/0YAFgFfAeYA3f/N/lP+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";
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
import { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';
|
|
3
|
+
export type TimerSlots = 'root' | 'ringWrapper' | 'ringSvg' | 'ringTrack' | 'ringProgress' | 'ripples' | 'ripple' | 'display' | 'time' | 'label' | 'controls' | 'addButton' | 'removeButton' | 'pauseButton' | 'cancelButton';
|
|
4
|
+
export type TimerStatus = 'idle' | 'running' | 'paused' | 'completed' | 'cancelled';
|
|
5
|
+
export interface TimerHandle {
|
|
6
|
+
/** Starts (or restarts, if idle/completed/cancelled) the countdown from its current duration. */
|
|
7
|
+
start: () => void;
|
|
8
|
+
/** Pauses a running timer. No-op if not running. */
|
|
9
|
+
pause: () => void;
|
|
10
|
+
/** Resumes a paused timer from where it left off. No-op if not paused. */
|
|
11
|
+
resume: () => void;
|
|
12
|
+
/** Adds seconds to the remaining time. Clamped to `maxSeconds` if set. */
|
|
13
|
+
addTime: (seconds: number) => void;
|
|
14
|
+
/** Removes seconds from the remaining time. Clamped to 0, which triggers completion. */
|
|
15
|
+
removeTime: (seconds: number) => void;
|
|
16
|
+
/** Stops the timer and resets it back to idle at its original starting duration. Does not fire onComplete. */
|
|
17
|
+
cancel: () => void;
|
|
18
|
+
/** Resets to idle at `durationSeconds` without starting. */
|
|
19
|
+
reset: () => void;
|
|
20
|
+
/** Current status snapshot. */
|
|
21
|
+
getStatus: () => TimerStatus;
|
|
22
|
+
/** Current remaining time in ms, read synchronously. */
|
|
23
|
+
getRemainingMs: () => number;
|
|
24
|
+
}
|
|
25
|
+
export interface TimerProps extends HtmlProps {
|
|
26
|
+
/** Starting duration in seconds. Changing this prop while mounted resets the timer to the new duration. */
|
|
27
|
+
durationSeconds: number;
|
|
28
|
+
/** Start ticking automatically on mount (and whenever `durationSeconds` changes). @default true */
|
|
29
|
+
autoStart?: boolean;
|
|
30
|
+
/** When `durationSeconds` changes after mount, restart from the new duration immediately (`true`) or only update the idle baseline (`false`). @default true */
|
|
31
|
+
resetOnDurationChange?: boolean;
|
|
32
|
+
/** Fires roughly every 200ms with the live remaining ms. */
|
|
33
|
+
onTick?: (remainingMs: number) => void;
|
|
34
|
+
/** Fires exactly once when the countdown reaches zero. */
|
|
35
|
+
onComplete?: () => void;
|
|
36
|
+
/** Fires when the timer transitions to running (initial start or resume). */
|
|
37
|
+
onStart?: () => void;
|
|
38
|
+
/** Fires when paused. */
|
|
39
|
+
onPause?: () => void;
|
|
40
|
+
/** Fires when resumed from pause. */
|
|
41
|
+
onResume?: () => void;
|
|
42
|
+
/** Fires when cancelled (via button or ref). */
|
|
43
|
+
onCancel?: () => void;
|
|
44
|
+
/** Fires whenever time is added, with the seconds added and the new total remaining seconds. */
|
|
45
|
+
onAddTime?: (secondsAdded: number, newRemainingSeconds: number) => void;
|
|
46
|
+
/** Fires whenever time is removed. */
|
|
47
|
+
onRemoveTime?: (secondsRemoved: number, newRemainingSeconds: number) => void;
|
|
48
|
+
/** Show the built-in control buttons (add/remove/pause-resume/cancel). @default true */
|
|
49
|
+
showControls?: boolean;
|
|
50
|
+
/** Individually hide the add-time button while keeping the others. */
|
|
51
|
+
hideAddButton?: boolean;
|
|
52
|
+
/** Individually hide the remove-time button while keeping the others. */
|
|
53
|
+
hideRemoveButton?: boolean;
|
|
54
|
+
/** Individually hide the pause/resume button while keeping the others. */
|
|
55
|
+
hidePauseButton?: boolean;
|
|
56
|
+
/** Individually hide the cancel button while keeping the others. */
|
|
57
|
+
hideCancelButton?: boolean;
|
|
58
|
+
/** Seconds added/removed per click of the add/remove buttons. @default 30 */
|
|
59
|
+
adjustSeconds?: number;
|
|
60
|
+
/** Optional cap on remaining time when adding. Unset = uncapped. */
|
|
61
|
+
maxSeconds?: number;
|
|
62
|
+
/** Label rendered under the time readout, e.g. "Boil pasta". */
|
|
63
|
+
label?: ReactNode;
|
|
64
|
+
/** Format the MM:SS (or H:MM:SS) readout. Defaults to a built-in formatter. */
|
|
65
|
+
formatTime?: (remainingMs: number) => ReactNode;
|
|
66
|
+
/** Diameter of the ring, any CSS length. Sets `--timer-size`. @default '160px' */
|
|
67
|
+
size?: string;
|
|
68
|
+
/** Ring stroke width in px. Sets `--timer-stroke-width`. @default 10 */
|
|
69
|
+
strokeWidth?: number;
|
|
70
|
+
/** Sweeps the depleting boundary counter-clockwise instead of the default clockwise (matching a clock face). @default false */
|
|
71
|
+
counterClockwise?: boolean;
|
|
72
|
+
/** Fraction of total duration (0-1) at which the ring switches to its urgent colour and the pulse (if enabled) kicks in. @default 0.1 */
|
|
73
|
+
urgentThreshold?: number;
|
|
74
|
+
/**
|
|
75
|
+
* Floor, in seconds, for how much time the urgent state gets — whichever of this or
|
|
76
|
+
* `urgentThreshold` (as a fraction of the total duration) produces the larger window wins.
|
|
77
|
+
* Without this, a short timer's `urgentThreshold` fraction can resolve to under a second,
|
|
78
|
+
* making the urgent/critical state barely perceptible. @default 3
|
|
79
|
+
*/
|
|
80
|
+
urgentMinSeconds?: number;
|
|
81
|
+
/** Enables the heartbeat/pulse effect once inside `urgentThreshold`. @default true */
|
|
82
|
+
pulseOnUrgent?: boolean;
|
|
83
|
+
/** Shows a thin ring pulsing outward from the dial's own edge and fading out while running (a beacon/live-indicator-style halo). @default false */
|
|
84
|
+
showRunningRipples?: boolean;
|
|
85
|
+
/** Play a short built-in chime on completion. @default false */
|
|
86
|
+
playSoundOnComplete?: boolean;
|
|
87
|
+
/** Overrides the built-in sound with a consumer-supplied audio URL. */
|
|
88
|
+
soundUrl?: string;
|
|
89
|
+
/** Volume 0-1 for the completion sound. @default 0.5 */
|
|
90
|
+
soundVolume?: number;
|
|
91
|
+
/** Show a browser Notification on completion (permission requested lazily on first `start()`, fails silently if denied/unsupported). @default false */
|
|
92
|
+
notifyOnComplete?: boolean;
|
|
93
|
+
/** Notification title when `notifyOnComplete` is set. @default 'Timer done' */
|
|
94
|
+
notificationTitle?: string;
|
|
95
|
+
/** Notification body when `notifyOnComplete` is set. Falls back to `label` when it's a string. */
|
|
96
|
+
notificationBody?: string;
|
|
97
|
+
className?: string;
|
|
98
|
+
style?: CSSProperties;
|
|
99
|
+
classNames?: SlotClassNames<TimerSlots>;
|
|
100
|
+
styles?: SlotStyles<TimerSlots>;
|
|
101
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IconContent } from './icon.types';
|
|
2
2
|
/** A single icon-triggered action, rendered as an `ActionIcon` */
|
|
3
3
|
export interface IconAction {
|
|
4
4
|
title?: string;
|
|
5
5
|
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
|
6
|
-
icon:
|
|
6
|
+
icon: IconContent;
|
|
7
7
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
|
|
2
|
+
import { ReactElement } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Anything a component will accept for an `icon` prop: either a FontAwesome
|
|
5
|
+
* `IconDefinition` (rendered through `FontAwesomeIcon`) or an arbitrary React
|
|
6
|
+
* element (rendered as-is) — an `<img>`, an inline `<svg>`, another icon
|
|
7
|
+
* library's component, …
|
|
8
|
+
*
|
|
9
|
+
* Deliberately `ReactElement` rather than `ReactNode`: `ReactNode` also covers
|
|
10
|
+
* strings, numbers and booleans, so a required icon prop would stop catching
|
|
11
|
+
* `icon="star"` at compile time and silently render the text instead. Matches
|
|
12
|
+
* what `Input` has always accepted for its own icon prop.
|
|
13
|
+
*
|
|
14
|
+
* Render one with `renderIcon` from `components/common/utils/renderIcon`, which
|
|
15
|
+
* picks the right branch.
|
|
16
|
+
*/
|
|
17
|
+
export type IconContent = IconDefinition | ReactElement;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
import { IconDefinition } from '@fortawesome/fontawesome-svg-core';
|
|
3
|
+
import { IconContent } from '../types/icon.types';
|
|
4
|
+
interface RenderIconOptions {
|
|
5
|
+
/** Class applied to the rendered icon (or to the wrapper span for a custom element). */
|
|
6
|
+
className?: string;
|
|
7
|
+
/** Inline style applied to the rendered icon (or to the wrapper span for a custom element). */
|
|
8
|
+
style?: CSSProperties;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Narrows an `IconContent` to a FontAwesome `IconDefinition`.
|
|
12
|
+
*
|
|
13
|
+
* Both halves of the union are plain objects (a React element is one too), so
|
|
14
|
+
* they can only be told apart structurally: an icon definition always carries
|
|
15
|
+
* `prefix`, `iconName` and the `icon` tuple.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isIconDefinition(icon: IconContent | null | undefined): icon is IconDefinition;
|
|
18
|
+
/**
|
|
19
|
+
* Renders an `icon` prop that may be either a FontAwesome `IconDefinition` or an
|
|
20
|
+
* arbitrary React element.
|
|
21
|
+
*
|
|
22
|
+
* A definition goes through `FontAwesomeIcon`; an element is returned untouched
|
|
23
|
+
* unless a `className`/`style` was given, in which case it is wrapped in a
|
|
24
|
+
* `<span>` carrying them so component and consumer slot styling still lands
|
|
25
|
+
* somewhere. Note that a custom element is not sized by FontAwesome's `1em`
|
|
26
|
+
* geometry — size it yourself if the surrounding layout expects a square icon.
|
|
27
|
+
*/
|
|
28
|
+
export declare function renderIcon(icon: IconContent | null | undefined, options?: RenderIconOptions): ReactNode;
|
|
29
|
+
export {};
|
|
@@ -78,6 +78,8 @@ export { default as NumberInput } from './common/numberInput';
|
|
|
78
78
|
export * from './common/numberInput';
|
|
79
79
|
export { default as OptionPicker } from './common/optionPicker';
|
|
80
80
|
export * from './common/optionPicker';
|
|
81
|
+
export { default as OtpInput } from './common/otpInput';
|
|
82
|
+
export * from './common/otpInput';
|
|
81
83
|
export { default as Overscroll } from './common/overscroll';
|
|
82
84
|
export * from './common/overscroll';
|
|
83
85
|
export { default as Popover } from './common/popover';
|
|
@@ -129,6 +131,8 @@ export { default as TimeInput } from './common/timeInput';
|
|
|
129
131
|
export * from './common/timeInput';
|
|
130
132
|
export { default as Timeline } from './common/timeline';
|
|
131
133
|
export * from './common/timeline';
|
|
134
|
+
export { default as Timer } from './common/timer';
|
|
135
|
+
export * from './common/timer';
|
|
132
136
|
export { default as ToastProvider } from './common/toast';
|
|
133
137
|
export * from './common/toast';
|
|
134
138
|
export { default as Tooltip } from './common/tooltip';
|
package/docs/ActionIcon.md
CHANGED
|
@@ -23,7 +23,7 @@ import { faTrash } from '@fortawesome/free-solid-svg-icons';
|
|
|
23
23
|
|
|
24
24
|
| Prop | Type | Description |
|
|
25
25
|
|------|------|-------------|
|
|
26
|
-
| `icon` | `IconDefinition` | FontAwesome icon (required) |
|
|
26
|
+
| `icon` | `IconDefinition \| ReactElement` | FontAwesome icon or any React element (required) |
|
|
27
27
|
| `title` | `string` | Tooltip / accessible label |
|
|
28
28
|
| `onClick` | `(event: MouseEvent) => void` | Click handler |
|
|
29
29
|
| `className` | `string` | Root element class |
|
package/docs/Alert.md
CHANGED
|
@@ -57,7 +57,7 @@ import { faRocket } from '@fortawesome/free-solid-svg-icons';
|
|
|
57
57
|
| `title` | `ReactNode` | Optional bold heading above the description |
|
|
58
58
|
| `children` | `ReactNode` | The message body |
|
|
59
59
|
| `styleType` | `AlertStyleType` | Colour variant and default icon (default `Default`) |
|
|
60
|
-
| `icon` | `IconDefinition` | Overrides the default
|
|
60
|
+
| `icon` | `IconDefinition \| ReactElement` | Overrides the default icon for `styleType` — FontAwesome icon or any React element |
|
|
61
61
|
| `hideIcon` | `boolean` | Hide the leading icon entirely |
|
|
62
62
|
| `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 |
|
|
63
63
|
|
package/docs/Avatar.md
CHANGED
|
@@ -46,7 +46,7 @@ import { Avatar, AvatarGroup } from '@ahrowe/ui';
|
|
|
46
46
|
| `src` | `string` | Image URL |
|
|
47
47
|
| `alt` | `string` | Image alt text (falls back to `name`) |
|
|
48
48
|
| `name` | `string` | Used to derive fallback initials, and as `alt` text when `alt` isn't given |
|
|
49
|
-
| `icon` | `IconDefinition` |
|
|
49
|
+
| `icon` | `IconDefinition \| ReactElement` | Icon shown when there's no `src` and no `name` — FontAwesome icon or any React element (default a person icon) |
|
|
50
50
|
| `content` | `ReactNode` | Custom fallback content overriding the computed initials/icon (e.g. `"+3"` — what `AvatarGroup` uses for its overflow indicator) |
|
|
51
51
|
| `status` | `'online' \| 'away' \| 'busy' \| 'offline'` | Small status dot on the bottom-right corner, rendered via `Badge` |
|
|
52
52
|
| `className` / `style` | | Root element — sizing is `em`-based, so `style={{ fontSize }}` scales the whole avatar. Shape defaults to `var(--default-border-radius)`; override via the `--avatar-radius` custom property (e.g. `'50%'` for fully circular) |
|
package/docs/Breadcrumb.md
CHANGED
|
@@ -89,7 +89,7 @@ function Example() {
|
|
|
89
89
|
| `id` | `string` | Optional stable key; falls back to the item's index |
|
|
90
90
|
| `label` | `ReactNode` | The crumb's text |
|
|
91
91
|
| `href` | `string` | Renders the crumb as a real `<a>`. Omit to render a plain clickable element (with `onClick`) or static text |
|
|
92
|
-
| `icon` | `IconDefinition` | Optional leading FontAwesome icon |
|
|
92
|
+
| `icon` | `IconDefinition \| ReactElement` | Optional leading icon — FontAwesome icon or any React element |
|
|
93
93
|
| `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` |
|
|
94
94
|
| `disabled` | `boolean` | Dims the crumb and makes it non-interactive, regardless of `href`/`onClick` |
|
|
95
95
|
|
package/docs/Button.md
CHANGED
|
@@ -46,7 +46,7 @@ import { faSave } from '@fortawesome/free-solid-svg-icons';
|
|
|
46
46
|
| `styleType` | `ButtonStyleType` | Visual variant |
|
|
47
47
|
| `size` | `ButtonSize` | Size variant |
|
|
48
48
|
| `type` | `ButtonType` | HTML button type |
|
|
49
|
-
| `icon` | `IconDefinition` | FontAwesome icon shown before label |
|
|
49
|
+
| `icon` | `IconDefinition \| ReactElement` | FontAwesome icon or any React element, shown before label |
|
|
50
50
|
| `isLoading` | `boolean` | Replaces content with a spinner |
|
|
51
51
|
| `disabled` | `boolean` | |
|
|
52
52
|
| `onClick` | `(e: MouseEvent) => void \| Promise<void>` | |
|
package/docs/CLAUDE.md
CHANGED
|
@@ -90,6 +90,28 @@ Most components expose `classNames` and `styles` props for styling inner element
|
|
|
90
90
|
|
|
91
91
|
Slot keys per component are documented in each component's doc file below.
|
|
92
92
|
|
|
93
|
+
## Icon props (`IconDefinition | ReactElement`)
|
|
94
|
+
|
|
95
|
+
Every `icon` prop (and every icon field inside an item/action object) accepts either a
|
|
96
|
+
FontAwesome `IconDefinition` or an arbitrary React node — an inline `<svg>`, an `<img>`,
|
|
97
|
+
or another icon library's component.
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import { faPen } from '@fortawesome/free-solid-svg-icons';
|
|
101
|
+
|
|
102
|
+
<Button icon={faPen}>Edit</Button> // FontAwesome
|
|
103
|
+
<Button icon={<MyIcon />}>Edit</Button> // any React node
|
|
104
|
+
<Button icon={<img src="/pen.svg" alt="" />}>Edit</Button>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
A definition is rendered through `FontAwesomeIcon`; an element is rendered as-is, wrapped in a
|
|
108
|
+
`<span>` carrying the component's icon class when that slot is styled. A custom element is not
|
|
109
|
+
sized by FontAwesome's `1em` geometry, so give it its own width/height if the surrounding
|
|
110
|
+
layout expects a square icon.
|
|
111
|
+
|
|
112
|
+
`IconPicker` and the internal `AnimatedIcon` are the exceptions — their behaviour depends on
|
|
113
|
+
FontAwesome internals, so they still take an `IconDefinition` only.
|
|
114
|
+
|
|
93
115
|
## Component docs
|
|
94
116
|
|
|
95
117
|
@Accordion.md
|
|
@@ -135,6 +157,7 @@ Slot keys per component are documented in each component's doc file below.
|
|
|
135
157
|
@Modal.md
|
|
136
158
|
@NumberInput.md
|
|
137
159
|
@OptionPicker.md
|
|
160
|
+
@OtpInput.md
|
|
138
161
|
@Overscroll.md
|
|
139
162
|
@Popover.md
|
|
140
163
|
@ProgressBar.md
|
|
@@ -159,6 +182,7 @@ Slot keys per component are documented in each component's doc file below.
|
|
|
159
182
|
@Tilt.md
|
|
160
183
|
@TimeInput.md
|
|
161
184
|
@Timeline.md
|
|
185
|
+
@Timer.md
|
|
162
186
|
@Toast.md
|
|
163
187
|
@Tooltip.md
|
|
164
188
|
@VirtualList.md
|
package/docs/ConfigProvider.md
CHANGED
|
@@ -60,8 +60,8 @@ So a global default only fills in props a given instance left out — any instan
|
|
|
60
60
|
|
|
61
61
|
Each entry is a `Partial<...Props>`, so any of that component's props can be defaulted:
|
|
62
62
|
|
|
63
|
-
- **Form inputs:** `Input` · `Textarea` · `NumberInput` · `Dropdown` · `InputDropdown` · `Checkbox` · `Switch` · `RadioGroup` · `DatePicker` · `OptionPicker`
|
|
64
|
-
- **Display:** `Button` · `ActionButtons` · `Badge` · `Chip` · `Card` · `SectionHeader` · `Skeleton` · `Accordion` · `Divider`
|
|
63
|
+
- **Form inputs:** `Input` · `Textarea` · `NumberInput` · `Dropdown` · `InputDropdown` · `Checkbox` · `Switch` · `RadioGroup` · `DatePicker` · `OptionPicker` · `OtpInput`
|
|
64
|
+
- **Display:** `Button` · `ActionButtons` · `Badge` · `Chip` · `Card` · `SectionHeader` · `Skeleton` · `Accordion` · `Divider` · `Timer`
|
|
65
65
|
- **Overlays:** `ConfirmModal`
|
|
66
66
|
|
|
67
67
|
```tsx
|
package/docs/EmptyState.md
CHANGED
|
@@ -25,6 +25,6 @@ import { faInbox } from '@fortawesome/free-solid-svg-icons';
|
|
|
25
25
|
|
|
26
26
|
| Prop | Type | Description |
|
|
27
27
|
|------|------|-------------|
|
|
28
|
-
| `icon` | `IconDefinition` |
|
|
28
|
+
| `icon` | `IconDefinition \| ReactElement` | Icon shown above the message — FontAwesome icon or any React element |
|
|
29
29
|
| `children` | `ReactNode` | Message body (defaults to `"No entries available"`) |
|
|
30
30
|
| `className` | `string` | Root element class |
|