sonahang-ui 1.0.4 → 1.0.6
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/README.md +4 -2
- package/dist/components/AudioPlayer/AudioPlayer.d.ts +48 -0
- package/dist/components/AudioPlayer/AudioPlaylist.d.ts +59 -0
- package/dist/components/AudioPlayer/formatAudioTime.d.ts +8 -0
- package/dist/components/AudioPlayer/index.d.ts +7 -0
- package/dist/components/AudioPlayer/playlistOrder.d.ts +45 -0
- package/dist/components/Collapsible/Collapsible.d.ts +36 -0
- package/dist/components/Collapsible/CollapsibleItem.d.ts +24 -0
- package/dist/components/Collapsible/collapsible.context.d.ts +23 -0
- package/dist/components/Collapsible/index.d.ts +4 -0
- package/dist/components/Toast/Toast.d.ts +32 -0
- package/dist/components/Toast/Toaster.d.ts +42 -0
- package/dist/components/Toast/index.d.ts +8 -0
- package/dist/components/Toast/toast.store.d.ts +94 -0
- package/dist/components/Toast/toast.tokens.d.ts +4 -0
- package/dist/index.d.ts +6 -0
- package/dist/internal/statusIcons.d.ts +10 -0
- package/dist/internal/useTopModalDialog.d.ts +11 -0
- package/dist/sonahang-ui.cjs +3 -3
- package/dist/sonahang-ui.cjs.map +1 -1
- package/dist/sonahang-ui.css +1 -1
- package/dist/sonahang-ui.js +1147 -283
- package/dist/sonahang-ui.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,12 +82,14 @@ Actions: `Button`, `Dropdown`, `SegmentedControl`
|
|
|
82
82
|
|
|
83
83
|
Forms: `Input`, `InputOtp`, `Textarea`, `Select`, `Checkbox`, `Radio`, `Switch`, `RangeSlider`, `MinMaxSlider`, `FileDrop`
|
|
84
84
|
|
|
85
|
-
Feedback: `Alert`, `Spinner`, `ProgressBar`, `Tooltip`, `Dialog`, `Drawer`
|
|
85
|
+
Feedback: `Alert`, `Toast`, `Spinner`, `ProgressBar`, `Tooltip`, `Dialog`, `Drawer`
|
|
86
86
|
|
|
87
|
-
Navigation: `Tabs`, `Breadcrumb`, `Pagination`, `Stepper`, `Accordion`
|
|
87
|
+
Navigation: `Tabs`, `Breadcrumb`, `Pagination`, `Stepper`, `Accordion`, `Collapsible`
|
|
88
88
|
|
|
89
89
|
Data display: `Avatar`, `Tag`, `Chip`, `Carousel`
|
|
90
90
|
|
|
91
|
+
Media: `AudioPlayer`, `AudioPlaylist`
|
|
92
|
+
|
|
91
93
|
Every component, every prop, and every state is documented with live controls
|
|
92
94
|
in [Storybook](https://github.com/sonangrai/sonahang-ui) — that's the real
|
|
93
95
|
reference, this file is the summary.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AudioHTMLAttributes, ReactNode, Ref } from "react";
|
|
2
|
+
import "./AudioPlayer.css";
|
|
3
|
+
export type AudioPlayerLabels = {
|
|
4
|
+
play?: string;
|
|
5
|
+
pause?: string;
|
|
6
|
+
previous?: string;
|
|
7
|
+
next?: string;
|
|
8
|
+
seek?: string;
|
|
9
|
+
mute?: string;
|
|
10
|
+
unmute?: string;
|
|
11
|
+
volume?: string;
|
|
12
|
+
/** Shown in place of the controls when the source fails to load. */
|
|
13
|
+
error?: string;
|
|
14
|
+
};
|
|
15
|
+
export type AudioPlayerProps = {
|
|
16
|
+
/** URL of the audio file. */
|
|
17
|
+
src: string;
|
|
18
|
+
/** Track name, shown above the controls. Also names the player region. */
|
|
19
|
+
title?: ReactNode;
|
|
20
|
+
/** Secondary line under the title — an artist, show, or episode. */
|
|
21
|
+
subtitle?: ReactNode;
|
|
22
|
+
/** Hides the volume controls, e.g. where the OS volume is all that matters. */
|
|
23
|
+
hideVolume?: boolean;
|
|
24
|
+
/** Initial volume, 0–1. Defaults to 1. */
|
|
25
|
+
defaultVolume?: number;
|
|
26
|
+
/** Accessible names for the controls — override to localise. */
|
|
27
|
+
labels?: AudioPlayerLabels;
|
|
28
|
+
/** Renders a Previous button beside Play. Omit for a single track. */
|
|
29
|
+
onPrevious?: () => void;
|
|
30
|
+
/** Renders a Next button beside Play. Omit for a single track. */
|
|
31
|
+
onNext?: () => void;
|
|
32
|
+
/** Extra controls, placed in the control row before the volume. */
|
|
33
|
+
actions?: ReactNode;
|
|
34
|
+
/** Class for the wrapper element. */
|
|
35
|
+
className?: string;
|
|
36
|
+
/** Ref to the underlying `<audio>` element, for imperative control. */
|
|
37
|
+
ref?: Ref<HTMLAudioElement>;
|
|
38
|
+
} & Omit<AudioHTMLAttributes<HTMLAudioElement>, "src" | "title" | "className" | "controls">;
|
|
39
|
+
/**
|
|
40
|
+
* Custom controls over a native `<audio>` element.
|
|
41
|
+
*
|
|
42
|
+
* The element stays the source of truth: playing, position, and volume are
|
|
43
|
+
* read back from its media events rather than tracked alongside it, so the UI
|
|
44
|
+
* can't drift from what's actually playing — even when something else drives
|
|
45
|
+
* the element through `ref`. The seek and volume bars are `RangeSlider`s, so
|
|
46
|
+
* arrow keys, Home/End, and screen-reader announcements come from the platform.
|
|
47
|
+
*/
|
|
48
|
+
export declare function AudioPlayer({ src, title, subtitle, hideVolume, defaultVolume, labels, onPrevious, onNext, actions, className, ref, onPlay, onPause, onEnded, onTimeUpdate, onLoadedMetadata, onDurationChange, onVolumeChange, onError, ...props }: AudioPlayerProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ReactNode, Ref } from "react";
|
|
2
|
+
import type { AudioPlayerLabels } from "./AudioPlayer";
|
|
3
|
+
import type { PlayMode } from "./playlistOrder";
|
|
4
|
+
import "./AudioPlaylist.css";
|
|
5
|
+
export type AudioTrack = {
|
|
6
|
+
src: string;
|
|
7
|
+
title: ReactNode;
|
|
8
|
+
subtitle?: ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* Length in seconds, shown in the track list. Optional — the player learns
|
|
11
|
+
* it once a track loads, but the list can't without loading every file.
|
|
12
|
+
*/
|
|
13
|
+
duration?: number;
|
|
14
|
+
/** Stable key. Falls back to the index and `src`. */
|
|
15
|
+
id?: string;
|
|
16
|
+
};
|
|
17
|
+
export type AudioPlaylistLabels = AudioPlayerLabels & {
|
|
18
|
+
/** Prefix for the play-mode button's name, e.g. "Play mode: Shuffle". */
|
|
19
|
+
playMode?: string;
|
|
20
|
+
/** Names of the individual modes. */
|
|
21
|
+
modes?: Partial<Record<PlayMode, string>>;
|
|
22
|
+
/** Name of the track list. */
|
|
23
|
+
tracks?: string;
|
|
24
|
+
};
|
|
25
|
+
export type AudioPlaylistProps = {
|
|
26
|
+
tracks: readonly AudioTrack[];
|
|
27
|
+
/** Names the playlist as a whole. Defaults to "Playlist". */
|
|
28
|
+
label?: string;
|
|
29
|
+
/** Current track — makes the playlist's position controlled. */
|
|
30
|
+
trackIndex?: number;
|
|
31
|
+
/** Initial track when uncontrolled. Defaults to the first. */
|
|
32
|
+
defaultTrackIndex?: number;
|
|
33
|
+
/** Fired with the index of the track being moved to. */
|
|
34
|
+
onTrackChange?: (index: number) => void;
|
|
35
|
+
/** Current play mode — makes it controlled. */
|
|
36
|
+
playMode?: PlayMode;
|
|
37
|
+
/** Initial play mode when uncontrolled. Defaults to `sequential`. */
|
|
38
|
+
defaultPlayMode?: PlayMode;
|
|
39
|
+
/** Fired with the next mode when the play-mode button is pressed. */
|
|
40
|
+
onPlayModeChange?: (mode: PlayMode) => void;
|
|
41
|
+
/** Hides the track list, leaving the player and its skip buttons. */
|
|
42
|
+
hideTrackList?: boolean;
|
|
43
|
+
hideVolume?: boolean;
|
|
44
|
+
/** Initial volume, 0–1. Carries across tracks. */
|
|
45
|
+
defaultVolume?: number;
|
|
46
|
+
labels?: AudioPlaylistLabels;
|
|
47
|
+
className?: string;
|
|
48
|
+
/** Ref to the underlying `<audio>` element. */
|
|
49
|
+
ref?: Ref<HTMLAudioElement>;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* An `AudioPlayer` that works through a list of tracks, with Previous/Next,
|
|
53
|
+
* a play-mode button cycling through in order, repeat all, repeat one and
|
|
54
|
+
* shuffle, and a track list to jump around in.
|
|
55
|
+
*
|
|
56
|
+
* Volume and mute carry from track to track — it's one `<audio>` element
|
|
57
|
+
* whose source changes, not a player per track.
|
|
58
|
+
*/
|
|
59
|
+
export declare function AudioPlaylist({ tracks, label, trackIndex, defaultTrackIndex, onTrackChange, playMode, defaultPlayMode, onPlayModeChange, hideTrackList, hideVolume, defaultVolume, labels, className, ref, }: AudioPlaylistProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats a playback position as `m:ss`, or `h:mm:ss` once it passes an hour.
|
|
3
|
+
*
|
|
4
|
+
* Anything that isn't a finite, non-negative number comes back as `--:--`.
|
|
5
|
+
* That covers the `NaN` a media element reports before its metadata loads and
|
|
6
|
+
* the `Infinity` it reports for a live stream — neither has a length to show.
|
|
7
|
+
*/
|
|
8
|
+
export declare function formatAudioTime(seconds: number): string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { AudioPlayer } from "./AudioPlayer";
|
|
2
|
+
export type { AudioPlayerProps, AudioPlayerLabels } from "./AudioPlayer";
|
|
3
|
+
export { AudioPlaylist } from "./AudioPlaylist";
|
|
4
|
+
export type { AudioPlaylistProps, AudioPlaylistLabels, AudioTrack } from "./AudioPlaylist";
|
|
5
|
+
export { formatAudioTime } from "./formatAudioTime";
|
|
6
|
+
export { playModes, getNextTrack, getPreviousTrack, createShuffleOrder, } from "./playlistOrder";
|
|
7
|
+
export type { PlayMode, PlaylistAdvance, PlaylistPosition, PlaylistStep, } from "./playlistOrder";
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export declare const playModes: readonly ["sequential", "repeat-all", "repeat-one", "shuffle"];
|
|
2
|
+
export type PlayMode = (typeof playModes)[number];
|
|
3
|
+
/** What moved the playlist on: the track finishing, or the Next button. */
|
|
4
|
+
export type PlaylistAdvance = "ended" | "next";
|
|
5
|
+
export type PlaylistPosition = {
|
|
6
|
+
/** Index of the current track. */
|
|
7
|
+
index: number;
|
|
8
|
+
/** Number of tracks in the playlist. */
|
|
9
|
+
count: number;
|
|
10
|
+
mode: PlayMode;
|
|
11
|
+
/**
|
|
12
|
+
* Shuffled play order, as track indices. Only read in `shuffle` mode; an
|
|
13
|
+
* order that no longer fits the playlist is replaced.
|
|
14
|
+
*/
|
|
15
|
+
order?: readonly number[];
|
|
16
|
+
/** Source of randomness, for deterministic tests. Defaults to `Math.random`. */
|
|
17
|
+
random?: () => number;
|
|
18
|
+
};
|
|
19
|
+
export type PlaylistStep = {
|
|
20
|
+
/** Track to move to, or `null` to stop where we are. */
|
|
21
|
+
index: number | null;
|
|
22
|
+
/** The shuffle order to keep for the next step. */
|
|
23
|
+
order: number[];
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* A random permutation of `0..count-1` that starts with `first`, so turning
|
|
27
|
+
* shuffle on never jumps away from the track that's playing.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createShuffleOrder(count: number, first: number, random?: () => number): number[];
|
|
30
|
+
/**
|
|
31
|
+
* Where the playlist goes after the current track.
|
|
32
|
+
*
|
|
33
|
+
* - `sequential` stops after the last track when it ends; Next wraps.
|
|
34
|
+
* - `repeat-all` wraps either way.
|
|
35
|
+
* - `repeat-one` replays the track when it ends; Next still moves on, since
|
|
36
|
+
* pressing it is asking for a different track.
|
|
37
|
+
* - `shuffle` walks a shuffled order and reshuffles once every track has
|
|
38
|
+
* played, never starting the new round on the track that just finished.
|
|
39
|
+
*/
|
|
40
|
+
export declare function getNextTrack(position: PlaylistPosition, advance: PlaylistAdvance): PlaylistStep;
|
|
41
|
+
/**
|
|
42
|
+
* Where Previous goes. In `shuffle` it retraces the shuffled order and stays
|
|
43
|
+
* on the first track of the round; otherwise it steps back and wraps.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getPreviousTrack(position: PlaylistPosition): PlaylistStep;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import "./Collapsible.css";
|
|
3
|
+
export type CollapsibleProps = {
|
|
4
|
+
/** `CollapsibleItem`s — which may themselves contain `CollapsibleItem`s. */
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
/**
|
|
7
|
+
* Values of the open items, at any level — makes the component controlled.
|
|
8
|
+
* Values must therefore be unique across the whole tree.
|
|
9
|
+
*/
|
|
10
|
+
value?: string[];
|
|
11
|
+
/** Initially open items when uncontrolled. */
|
|
12
|
+
defaultValue?: string[];
|
|
13
|
+
/** Fired with the full list of open items. */
|
|
14
|
+
onChange?: (value: string[]) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Replaces the default chevron on open items. Applies to every level;
|
|
17
|
+
* an item's own `expandedIcon` wins over this.
|
|
18
|
+
*/
|
|
19
|
+
expandedIcon?: ReactNode;
|
|
20
|
+
/**
|
|
21
|
+
* Replaces the default chevron on closed items. Applies to every level;
|
|
22
|
+
* an item's own `collapsedIcon` wins over this.
|
|
23
|
+
*/
|
|
24
|
+
collapsedIcon?: ReactNode;
|
|
25
|
+
className?: string;
|
|
26
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "className" | "onChange">;
|
|
27
|
+
/**
|
|
28
|
+
* Multi-level set of collapsible sections — nav trees, file trees, nested
|
|
29
|
+
* settings.
|
|
30
|
+
*
|
|
31
|
+
* Nest `CollapsibleItem`s inside each other to add levels; depth and
|
|
32
|
+
* indentation are worked out from the nesting. Every item opens and closes
|
|
33
|
+
* independently, and closing a parent keeps its children's state, so they
|
|
34
|
+
* reappear as they were.
|
|
35
|
+
*/
|
|
36
|
+
export declare function Collapsible({ children, value, defaultValue, onChange, expandedIcon, collapsedIcon, className, ...props }: CollapsibleProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import "./Collapsible.css";
|
|
3
|
+
export type CollapsibleItemProps = {
|
|
4
|
+
/** Identifies this item in the open list. Unique across the whole tree. */
|
|
5
|
+
value: string;
|
|
6
|
+
/** Content of the row. */
|
|
7
|
+
title: ReactNode;
|
|
8
|
+
/** Leading icon, shown between the chevron and the title. Any level. */
|
|
9
|
+
icon?: ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* Revealed when open — nested `CollapsibleItem`s for another level, or any
|
|
12
|
+
* other content. With no children the item is a plain, non-toggling row.
|
|
13
|
+
*/
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
/** Replaces the chevron on this item while open. */
|
|
16
|
+
expandedIcon?: ReactNode;
|
|
17
|
+
/** Replaces the chevron on this item while closed. */
|
|
18
|
+
collapsedIcon?: ReactNode;
|
|
19
|
+
/** Prevents the item being opened or closed. */
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
className?: string;
|
|
22
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "className" | "title">;
|
|
23
|
+
/** One row of a `Collapsible`, optionally containing a further level. */
|
|
24
|
+
export declare function CollapsibleItem({ value, title, icon, children, expandedIcon, collapsedIcon, disabled, className, style, ...props }: CollapsibleItemProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export type CollapsibleContextValue = {
|
|
3
|
+
/** Values of every open item, across all levels. */
|
|
4
|
+
value: string[];
|
|
5
|
+
/** Opens or closes one item. */
|
|
6
|
+
toggle: (value: string) => void;
|
|
7
|
+
baseId: string;
|
|
8
|
+
/** Indicator shown on open items, when overridden. */
|
|
9
|
+
expandedIcon?: ReactNode;
|
|
10
|
+
/** Indicator shown on closed items, when overridden. */
|
|
11
|
+
collapsedIcon?: ReactNode;
|
|
12
|
+
};
|
|
13
|
+
export declare const CollapsibleContext: import("react").Context<CollapsibleContextValue | undefined>;
|
|
14
|
+
/**
|
|
15
|
+
* Nesting depth of the items currently rendering. Each open panel provides
|
|
16
|
+
* `depth + 1` to whatever it contains, so items don't need a `level` prop.
|
|
17
|
+
*/
|
|
18
|
+
export declare const CollapsibleDepthContext: import("react").Context<number>;
|
|
19
|
+
/** Reads the surrounding `Collapsible`, failing loudly rather than silently. */
|
|
20
|
+
export declare function useCollapsibleContext(component: string): CollapsibleContextValue;
|
|
21
|
+
/** Ids are derived rather than registered, so trigger and panel always agree. */
|
|
22
|
+
export declare const triggerId: (baseId: string, value: string) => string;
|
|
23
|
+
export declare const panelId: (baseId: string, value: string) => string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
import type { ToastAction } from "./toast.store";
|
|
3
|
+
import type { ToastVariant } from "./toast.tokens";
|
|
4
|
+
import "./Toast.css";
|
|
5
|
+
export type ToastProps = {
|
|
6
|
+
/** Defaults to `default`, which has no icon. `loading` shows a spinner. */
|
|
7
|
+
variant?: ToastVariant;
|
|
8
|
+
title: ReactNode;
|
|
9
|
+
/** Secondary line under the title. */
|
|
10
|
+
description?: ReactNode;
|
|
11
|
+
/** Replaces the variant's icon, or hides it with `false`. */
|
|
12
|
+
icon?: ReactNode | false;
|
|
13
|
+
/** A single button, e.g. "Undo". */
|
|
14
|
+
action?: ToastAction;
|
|
15
|
+
/** Renders a close button and is called when it's activated. */
|
|
16
|
+
onDismiss?: () => void;
|
|
17
|
+
/** Accessible name for the close button. Defaults to "Dismiss". */
|
|
18
|
+
dismissLabel?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Overrides how assistive tech announces this. Defaults to `alert` for
|
|
21
|
+
* warning/error and `status` otherwise.
|
|
22
|
+
*/
|
|
23
|
+
role?: "alert" | "status" | "none";
|
|
24
|
+
} & Omit<HTMLAttributes<HTMLDivElement>, "title" | "role">;
|
|
25
|
+
/**
|
|
26
|
+
* A single notification card.
|
|
27
|
+
*
|
|
28
|
+
* Usually you won't render this yourself — call `toast()` and let
|
|
29
|
+
* `<Toaster />` handle stacking, timing and dismissal. It's exported for
|
|
30
|
+
* custom layouts and for documentation.
|
|
31
|
+
*/
|
|
32
|
+
export declare function Toast({ variant, title, description, icon, action, onDismiss, dismissLabel, role, className, ...props }: ToastProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ToastPosition } from "./toast.tokens";
|
|
2
|
+
import "./Toast.css";
|
|
3
|
+
export type ToasterProps = {
|
|
4
|
+
/** Corner or edge the stack sits in. Defaults to `bottom-right`. */
|
|
5
|
+
position?: ToastPosition;
|
|
6
|
+
/** Default time on screen in ms, when a toast doesn't set its own. Defaults to 5000. */
|
|
7
|
+
duration?: number;
|
|
8
|
+
/**
|
|
9
|
+
* Most toasts shown at once. When another arrives, the oldest closes to
|
|
10
|
+
* make room. Defaults to 3.
|
|
11
|
+
*/
|
|
12
|
+
max?: number;
|
|
13
|
+
/** Default for whether toasts show a close button. Defaults to true. */
|
|
14
|
+
closeButton?: boolean;
|
|
15
|
+
/** Accessible name of the notification region. Defaults to "Notifications". */
|
|
16
|
+
label?: string;
|
|
17
|
+
/** Accessible name of each close button. Defaults to "Dismiss". */
|
|
18
|
+
dismissLabel?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Where to render. `true` (default) portals to `document.body`, an element
|
|
21
|
+
* portals there, `false` renders in place.
|
|
22
|
+
*
|
|
23
|
+
* While a modal `Dialog` or `Drawer` is open, toasts move inside it
|
|
24
|
+
* regardless — everything outside a modal is inert, so they'd otherwise be
|
|
25
|
+
* unclickable.
|
|
26
|
+
*/
|
|
27
|
+
portal?: boolean | HTMLElement;
|
|
28
|
+
className?: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Renders the toasts raised with `toast()`. Mount one, once, near the root
|
|
32
|
+
* of the app — no provider needed.
|
|
33
|
+
*
|
|
34
|
+
* Timers pause while the pointer is over the stack, while focus is inside
|
|
35
|
+
* it, and while the tab is hidden, so nothing disappears mid-read.
|
|
36
|
+
* Escape closes the focused toast.
|
|
37
|
+
*
|
|
38
|
+
* Toasts stay on top of, and usable over, an open modal `Dialog` or `Drawer`:
|
|
39
|
+
* the stack is a popover, so it's in the top layer, and it moves into the
|
|
40
|
+
* topmost modal while one is open, so it isn't made inert.
|
|
41
|
+
*/
|
|
42
|
+
export declare function Toaster({ position, duration, max, closeButton, label, dismissLabel, portal, className, }: ToasterProps): import("react").ReactNode;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { Toast } from "./Toast";
|
|
2
|
+
export type { ToastProps } from "./Toast";
|
|
3
|
+
export { Toaster } from "./Toaster";
|
|
4
|
+
export type { ToasterProps } from "./Toaster";
|
|
5
|
+
export { toast } from "./toast.store";
|
|
6
|
+
export type { ToastAction, ToastFunction, ToastOptions, ToastPromiseContent, ToastPromiseMessages, } from "./toast.store";
|
|
7
|
+
export { toastVariants, toastPositions } from "./toast.tokens";
|
|
8
|
+
export type { ToastVariant, ToastPosition } from "./toast.tokens";
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { MouseEvent, ReactNode } from "react";
|
|
2
|
+
import type { ToastVariant } from "./toast.tokens";
|
|
3
|
+
export type ToastAction = {
|
|
4
|
+
label: ReactNode;
|
|
5
|
+
/** Called on click. The toast closes afterwards unless you call `event.preventDefault()`. */
|
|
6
|
+
onClick: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
7
|
+
};
|
|
8
|
+
export type ToastOptions = {
|
|
9
|
+
/**
|
|
10
|
+
* Reuse an id to replace a toast in place — e.g. turn "Uploading…" into
|
|
11
|
+
* "Uploaded" — instead of stacking a second one. Its timer restarts.
|
|
12
|
+
*/
|
|
13
|
+
id?: string;
|
|
14
|
+
variant?: ToastVariant;
|
|
15
|
+
/** Secondary line under the title. */
|
|
16
|
+
description?: ReactNode;
|
|
17
|
+
/**
|
|
18
|
+
* Milliseconds before it closes on its own. `Infinity` keeps it until
|
|
19
|
+
* dismissed. Defaults to the `Toaster`'s `duration`.
|
|
20
|
+
*/
|
|
21
|
+
duration?: number;
|
|
22
|
+
/** A single button, e.g. "Undo". */
|
|
23
|
+
action?: ToastAction;
|
|
24
|
+
/** Replaces the variant's icon, or hides it with `false`. */
|
|
25
|
+
icon?: ReactNode | false;
|
|
26
|
+
/** Whether to show the close button. Defaults to the `Toaster`'s `closeButton`. */
|
|
27
|
+
dismissible?: boolean;
|
|
28
|
+
/** Called once the toast has closed, however that happened. */
|
|
29
|
+
onDismiss?: () => void;
|
|
30
|
+
};
|
|
31
|
+
export type ToastRecord = Omit<ToastOptions, "id"> & {
|
|
32
|
+
id: string;
|
|
33
|
+
title: ReactNode;
|
|
34
|
+
variant: ToastVariant;
|
|
35
|
+
/** Bumped on every update so the toast's timer knows to restart. */
|
|
36
|
+
version: number;
|
|
37
|
+
/** Playing its exit animation; removed from the store shortly after. */
|
|
38
|
+
closing: boolean;
|
|
39
|
+
};
|
|
40
|
+
/** Long enough for the exit animation in Toast.css to finish. */
|
|
41
|
+
export declare const EXIT_DURATION_MS = 200;
|
|
42
|
+
type Listener = () => void;
|
|
43
|
+
export declare const toastStore: {
|
|
44
|
+
subscribe(listener: Listener): () => void;
|
|
45
|
+
getSnapshot: () => ToastRecord[];
|
|
46
|
+
/** Nothing is queued on the server, and this must be a stable reference. */
|
|
47
|
+
getServerSnapshot: () => ToastRecord[];
|
|
48
|
+
};
|
|
49
|
+
type VariantShortcut = (title: ReactNode, options?: Omit<ToastOptions, "variant">) => string;
|
|
50
|
+
/** A result message: just a title, or a title with any other toast options. */
|
|
51
|
+
export type ToastPromiseContent = ReactNode | ({
|
|
52
|
+
title: ReactNode;
|
|
53
|
+
} & Omit<ToastOptions, "id" | "variant">);
|
|
54
|
+
export type ToastPromiseMessages<T> = {
|
|
55
|
+
/** Shown while pending. Stays up until the promise settles. */
|
|
56
|
+
loading: ReactNode;
|
|
57
|
+
/** Shown on resolve. A function receives the resolved value. */
|
|
58
|
+
success: ToastPromiseContent | ((value: T) => ToastPromiseContent);
|
|
59
|
+
/**
|
|
60
|
+
* Shown on reject. A function receives the rejection reason. Leave it out
|
|
61
|
+
* and the loading toast just closes.
|
|
62
|
+
*/
|
|
63
|
+
error?: ToastPromiseContent | ((reason: unknown) => ToastPromiseContent);
|
|
64
|
+
};
|
|
65
|
+
export type ToastFunction = {
|
|
66
|
+
/** Shows a toast and returns its id. */
|
|
67
|
+
(title: ReactNode, options?: ToastOptions): string;
|
|
68
|
+
success: VariantShortcut;
|
|
69
|
+
info: VariantShortcut;
|
|
70
|
+
warning: VariantShortcut;
|
|
71
|
+
error: VariantShortcut;
|
|
72
|
+
/**
|
|
73
|
+
* Shows a loading toast that turns into success or error when `promise`
|
|
74
|
+
* settles. Returns the same promise, so it can be awaited or chained —
|
|
75
|
+
* pass `options.id` to address the toast afterwards.
|
|
76
|
+
*/
|
|
77
|
+
promise: <T>(promise: Promise<T> | (() => Promise<T>), messages: ToastPromiseMessages<T>, options?: Omit<ToastOptions, "variant">) => Promise<T>;
|
|
78
|
+
/** Closes one toast, or every toast when called without an id. */
|
|
79
|
+
dismiss: (id?: string) => void;
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Shows a toast in whichever `<Toaster />` is mounted.
|
|
83
|
+
*
|
|
84
|
+
* ```ts
|
|
85
|
+
* toast("Draft saved");
|
|
86
|
+
* toast.success("Uploaded", { description: "report.pdf" });
|
|
87
|
+
* const id = toast("Uploading…", { duration: Infinity });
|
|
88
|
+
* toast.success("Uploaded", { id });
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare const toast: ToastFunction;
|
|
92
|
+
/** Clears everything immediately. For tests — not exported from the package. */
|
|
93
|
+
export declare function resetToastStore(): void;
|
|
94
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const toastVariants: readonly ["default", "success", "info", "warning", "error", "loading"];
|
|
2
|
+
export type ToastVariant = (typeof toastVariants)[number];
|
|
3
|
+
export declare const toastPositions: readonly ["top-left", "top-center", "top-right", "bottom-left", "bottom-center", "bottom-right"];
|
|
4
|
+
export type ToastPosition = (typeof toastPositions)[number];
|
package/dist/index.d.ts
CHANGED
|
@@ -48,6 +48,8 @@ export { Pagination, getPaginationRange } from './components/Pagination';
|
|
|
48
48
|
export type { PaginationProps, PaginationItem, PaginationRangeOptions, } from './components/Pagination';
|
|
49
49
|
export { Accordion, AccordionItem } from './components/Accordion';
|
|
50
50
|
export type { AccordionProps, AccordionItemProps, AccordionType, AccordionHeadingLevel, } from './components/Accordion';
|
|
51
|
+
export { Collapsible, CollapsibleItem } from './components/Collapsible';
|
|
52
|
+
export type { CollapsibleProps, CollapsibleItemProps } from './components/Collapsible';
|
|
51
53
|
export { Stepper, Step } from './components/Stepper';
|
|
52
54
|
export type { StepperProps, StepProps, StepperOrientation, StepStatus } from './components/Stepper';
|
|
53
55
|
export { Breadcrumb, BreadcrumbItem } from './components/Breadcrumb';
|
|
@@ -64,6 +66,8 @@ export { ProgressBar, progressBarSizes } from './components/ProgressBar';
|
|
|
64
66
|
export type { ProgressBarProps, ProgressBarSize } from './components/ProgressBar';
|
|
65
67
|
export { Alert, alertVariants } from './components/Alert';
|
|
66
68
|
export type { AlertProps, AlertVariant } from './components/Alert';
|
|
69
|
+
export { Toast, Toaster, toast, toastVariants, toastPositions } from './components/Toast';
|
|
70
|
+
export type { ToastProps, ToasterProps, ToastAction, ToastFunction, ToastOptions, ToastPromiseContent, ToastPromiseMessages, ToastVariant, ToastPosition, } from './components/Toast';
|
|
67
71
|
export { FileDrop, isFileAccepted, formatFileSize } from './components/FileDrop';
|
|
68
72
|
export type { FileDropProps } from './components/FileDrop';
|
|
69
73
|
export { RangeSlider } from './components/RangeSlider';
|
|
@@ -74,6 +78,8 @@ export { Switch, SwitchGroup } from './components/Switch';
|
|
|
74
78
|
export type { SwitchProps, SwitchGroupProps } from './components/Switch';
|
|
75
79
|
export { SegmentedControl } from './components/SegmentedControl';
|
|
76
80
|
export type { SegmentedControlProps, SegmentedControlOption, } from './components/SegmentedControl';
|
|
81
|
+
export { AudioPlayer, AudioPlaylist, formatAudioTime, playModes, getNextTrack, getPreviousTrack, createShuffleOrder, } from './components/AudioPlayer';
|
|
82
|
+
export type { AudioPlayerProps, AudioPlayerLabels, AudioPlaylistProps, AudioPlaylistLabels, AudioTrack, PlayMode, PlaylistAdvance, PlaylistPosition, PlaylistStep, } from './components/AudioPlayer';
|
|
77
83
|
/**
|
|
78
84
|
* Design tokens. The stylesheet already defines every color as a CSS var
|
|
79
85
|
* (`--color-accent-600`, `--color-bg-surface`, …) — these are the same
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Status icons and the dismiss glyph shared by Alert and Toast, so the two
|
|
4
|
+
* always tell variants apart the same way.
|
|
5
|
+
*
|
|
6
|
+
* Not part of the public API.
|
|
7
|
+
*/
|
|
8
|
+
export type StatusVariant = "success" | "info" | "warning" | "error";
|
|
9
|
+
export declare const statusIcons: Record<StatusVariant, ReactNode>;
|
|
10
|
+
export declare const closeIcon: import("react").JSX.Element;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The topmost open modal `<dialog>`, or null.
|
|
3
|
+
*
|
|
4
|
+
* Anything outside a modal dialog is inert while it's open — not just
|
|
5
|
+
* covered, but unclickable and unfocusable — so UI that must stay usable on
|
|
6
|
+
* top of one (toasts) has to render inside it. Watching the DOM, rather than
|
|
7
|
+
* asking Dialog and Drawer to report in, also catches modals that aren't ours.
|
|
8
|
+
*
|
|
9
|
+
* Not part of the public API.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useTopModalDialog(): HTMLDialogElement | null;
|