@exsto/ds 0.0.0-stage → 0.0.1-rc.10
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/LICENSE +202 -0
- package/README.md +165 -2
- package/dist/chunks/date-range-picker-CWVcHgy2.js +204 -0
- package/dist/chunks/date-range-picker-CWVcHgy2.js.map +1 -0
- package/dist/chunks/input-syWxjY2U.js +172 -0
- package/dist/chunks/input-syWxjY2U.js.map +1 -0
- package/dist/chunks/toggle-CVnIkJVC.js +484 -0
- package/dist/chunks/toggle-CVnIkJVC.js.map +1 -0
- package/dist/date-picker.js +345 -0
- package/dist/date-picker.js.map +1 -0
- package/dist/ds/src/date-picker.d.ts +9 -0
- package/dist/ds/src/index.d.ts +7 -0
- package/dist/ds/src/rich-text-editor.d.ts +8 -0
- package/dist/index.js +4512 -0
- package/dist/index.js.map +1 -0
- package/dist/rich-text-editor.js +905 -0
- package/dist/rich-text-editor.js.map +1 -0
- package/dist/styles.css +8167 -0
- package/dist/styles.css.d.ts +2 -0
- package/dist/theme/src/index.d.ts +4 -0
- package/dist/theme.css +308 -0
- package/dist/theme.css.d.ts +2 -0
- package/dist/ui/src/components/edyn/animated-number/animated-number.d.ts +30 -0
- package/dist/ui/src/components/edyn/animated-number/animated-number.test.d.ts +9 -0
- package/dist/ui/src/components/edyn/animated-number/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/audio-player/audio-player.d.ts +30 -0
- package/dist/ui/src/components/edyn/audio-player/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/date-picker/date-picker.d.ts +76 -0
- package/dist/ui/src/components/edyn/date-picker/date-picker.state.test.d.ts +9 -0
- package/dist/ui/src/components/edyn/date-picker/date-text.d.ts +40 -0
- package/dist/ui/src/components/edyn/date-picker/date-text.test.d.ts +1 -0
- package/dist/ui/src/components/edyn/date-picker/index.d.ts +2 -0
- package/dist/ui/src/components/edyn/date-range-picker/date-range-picker.d.ts +28 -0
- package/dist/ui/src/components/edyn/date-range-picker/date-range-picker.test.d.ts +9 -0
- package/dist/ui/src/components/edyn/date-range-picker/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/initials-avatar/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/initials-avatar/initials-avatar.d.ts +54 -0
- package/dist/ui/src/components/edyn/initials-avatar/initials-avatar.test.d.ts +10 -0
- package/dist/ui/src/components/edyn/multi-select/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/multi-select/multi-select.d.ts +106 -0
- package/dist/ui/src/components/edyn/multi-select/multi-select.test.d.ts +9 -0
- package/dist/ui/src/components/edyn/progress-line/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/progress-line/progress-line.d.ts +23 -0
- package/dist/ui/src/components/edyn/progress-line/progress-line.test.d.ts +9 -0
- package/dist/ui/src/components/edyn/rich-text-content/allow-list.d.ts +11 -0
- package/dist/ui/src/components/edyn/rich-text-content/index.d.ts +2 -0
- package/dist/ui/src/components/edyn/rich-text-content/rich-text-content.d.ts +22 -0
- package/dist/ui/src/components/edyn/rich-text-content/rich-text-content.test.d.ts +8 -0
- package/dist/ui/src/components/edyn/rich-text-editor/extensions.d.ts +18 -0
- package/dist/ui/src/components/edyn/rich-text-editor/index.d.ts +3 -0
- package/dist/ui/src/components/edyn/rich-text-editor/mention-list.d.ts +17 -0
- package/dist/ui/src/components/edyn/rich-text-editor/rich-text-editor.d.ts +53 -0
- package/dist/ui/src/components/edyn/rich-text-editor/rich-text-editor.test.d.ts +6 -0
- package/dist/ui/src/components/edyn/rich-text-editor/serialize.d.ts +13 -0
- package/dist/ui/src/components/edyn/rich-text-editor/sync.d.ts +19 -0
- package/dist/ui/src/components/edyn/rich-text-editor/sync.test.d.ts +11 -0
- package/dist/ui/src/components/edyn/rich-text-editor/toolbar.d.ts +20 -0
- package/dist/ui/src/components/edyn/rich-text-editor/types.d.ts +68 -0
- package/dist/ui/src/components/edyn/video-player/index.d.ts +1 -0
- package/dist/ui/src/components/edyn/video-player/video-player.d.ts +55 -0
- package/dist/ui/src/components/forwarded-props.test.d.ts +8 -0
- package/dist/ui/src/components/ui/accordion/accordion.behavior.test.d.ts +13 -0
- package/dist/ui/src/components/ui/accordion/accordion.d.ts +28 -0
- package/dist/ui/src/components/ui/accordion/index.d.ts +1 -0
- package/dist/ui/src/components/ui/alert/alert.d.ts +10 -0
- package/dist/ui/src/components/ui/alert/index.d.ts +1 -0
- package/dist/ui/src/components/ui/alert-dialog/alert-dialog.d.ts +17 -0
- package/dist/ui/src/components/ui/alert-dialog/index.d.ts +1 -0
- package/dist/ui/src/components/ui/aspect-ratio/aspect-ratio.d.ts +3 -0
- package/dist/ui/src/components/ui/aspect-ratio/index.d.ts +1 -0
- package/dist/ui/src/components/ui/attachment/attachment.d.ts +23 -0
- package/dist/ui/src/components/ui/attachment/index.d.ts +1 -0
- package/dist/ui/src/components/ui/avatar/avatar.d.ts +10 -0
- package/dist/ui/src/components/ui/avatar/index.d.ts +1 -0
- package/dist/ui/src/components/ui/badge/badge.d.ts +7 -0
- package/dist/ui/src/components/ui/badge/index.d.ts +1 -0
- package/dist/ui/src/components/ui/breadcrumb/breadcrumb.d.ts +9 -0
- package/dist/ui/src/components/ui/breadcrumb/index.d.ts +1 -0
- package/dist/ui/src/components/ui/bubble/bubble.d.ts +16 -0
- package/dist/ui/src/components/ui/bubble/index.d.ts +1 -0
- package/dist/ui/src/components/ui/button/button.behavior.test.d.ts +8 -0
- package/dist/ui/src/components/ui/button/button.d.ts +7 -0
- package/dist/ui/src/components/ui/button/index.d.ts +1 -0
- package/dist/ui/src/components/ui/button-group/button-group.d.ts +12 -0
- package/dist/ui/src/components/ui/button-group/index.d.ts +1 -0
- package/dist/ui/src/components/ui/calendar/calendar.d.ts +9 -0
- package/dist/ui/src/components/ui/calendar/index.d.ts +1 -0
- package/dist/ui/src/components/ui/card/card.d.ts +10 -0
- package/dist/ui/src/components/ui/card/index.d.ts +1 -0
- package/dist/ui/src/components/ui/carousel/carousel.d.ts +28 -0
- package/dist/ui/src/components/ui/carousel/index.d.ts +3 -0
- package/dist/ui/src/components/ui/chart/chart.d.ts +44 -0
- package/dist/ui/src/components/ui/chart/index.d.ts +3 -0
- package/dist/ui/src/components/ui/checkbox/checkbox.d.ts +2 -0
- package/dist/ui/src/components/ui/checkbox/index.d.ts +1 -0
- package/dist/ui/src/components/ui/collapsible/collapsible.d.ts +4 -0
- package/dist/ui/src/components/ui/collapsible/index.d.ts +1 -0
- package/dist/ui/src/components/ui/combobox/combobox.d.ts +15 -0
- package/dist/ui/src/components/ui/combobox/index.d.ts +1 -0
- package/dist/ui/src/components/ui/command/command.d.ts +34 -0
- package/dist/ui/src/components/ui/command/index.d.ts +1 -0
- package/dist/ui/src/components/ui/context-menu/context-menu.d.ts +28 -0
- package/dist/ui/src/components/ui/context-menu/index.d.ts +1 -0
- package/dist/ui/src/components/ui/dialog/dialog.d.ts +16 -0
- package/dist/ui/src/components/ui/dialog/index.d.ts +1 -0
- package/dist/ui/src/components/ui/direction/direction.d.ts +1 -0
- package/dist/ui/src/components/ui/direction/index.d.ts +1 -0
- package/dist/ui/src/components/ui/drawer/drawer.d.ts +15 -0
- package/dist/ui/src/components/ui/drawer/index.d.ts +1 -0
- package/dist/ui/src/components/ui/dropdown-menu/dropdown-menu.d.ts +39 -0
- package/dist/ui/src/components/ui/dropdown-menu/index.d.ts +1 -0
- package/dist/ui/src/components/ui/empty/empty.d.ts +11 -0
- package/dist/ui/src/components/ui/empty/index.d.ts +1 -0
- package/dist/ui/src/components/ui/field/field.d.ts +5 -0
- package/dist/ui/src/components/ui/field/index.d.ts +1 -0
- package/dist/ui/src/components/ui/hover-card/hover-card.d.ts +4 -0
- package/dist/ui/src/components/ui/hover-card/index.d.ts +1 -0
- package/dist/ui/src/components/ui/indicator/index.d.ts +1 -0
- package/dist/ui/src/components/ui/indicator/indicator.d.ts +10 -0
- package/dist/ui/src/components/ui/input/index.d.ts +1 -0
- package/dist/ui/src/components/ui/input/input.d.ts +2 -0
- package/dist/ui/src/components/ui/input-group/index.d.ts +1 -0
- package/dist/ui/src/components/ui/input-group/input-group.d.ts +26 -0
- package/dist/ui/src/components/ui/input-otp/index.d.ts +1 -0
- package/dist/ui/src/components/ui/input-otp/input-otp.d.ts +10 -0
- package/dist/ui/src/components/ui/item/index.d.ts +1 -0
- package/dist/ui/src/components/ui/item/item.d.ts +22 -0
- package/dist/ui/src/components/ui/kbd/index.d.ts +1 -0
- package/dist/ui/src/components/ui/kbd/kbd.d.ts +2 -0
- package/dist/ui/src/components/ui/label/index.d.ts +1 -0
- package/dist/ui/src/components/ui/label/label.d.ts +2 -0
- package/dist/ui/src/components/ui/marker/index.d.ts +1 -0
- package/dist/ui/src/components/ui/marker/marker.d.ts +9 -0
- package/dist/ui/src/components/ui/menubar/index.d.ts +1 -0
- package/dist/ui/src/components/ui/menubar/menubar.d.ts +28 -0
- package/dist/ui/src/components/ui/message/index.d.ts +1 -0
- package/dist/ui/src/components/ui/message/message.d.ts +9 -0
- package/dist/ui/src/components/ui/message-scroller/index.d.ts +1 -0
- package/dist/ui/src/components/ui/message-scroller/message-scroller.d.ts +10 -0
- package/dist/ui/src/components/ui/native-select/index.d.ts +1 -0
- package/dist/ui/src/components/ui/native-select/native-select.d.ts +8 -0
- package/dist/ui/src/components/ui/navigation-menu/index.d.ts +1 -0
- package/dist/ui/src/components/ui/navigation-menu/navigation-menu.d.ts +10 -0
- package/dist/ui/src/components/ui/pagination/index.d.ts +1 -0
- package/dist/ui/src/components/ui/pagination/pagination.behavior.test.d.ts +1 -0
- package/dist/ui/src/components/ui/pagination/pagination.d.ts +18 -0
- package/dist/ui/src/components/ui/pagination/pagination.test.d.ts +1 -0
- package/dist/ui/src/components/ui/popover/index.d.ts +1 -0
- package/dist/ui/src/components/ui/popover/popover.d.ts +8 -0
- package/dist/ui/src/components/ui/progress/index.d.ts +1 -0
- package/dist/ui/src/components/ui/progress/progress.behavior.test.d.ts +8 -0
- package/dist/ui/src/components/ui/progress/progress.d.ts +47 -0
- package/dist/ui/src/components/ui/questionnaire/index.d.ts +1 -0
- package/dist/ui/src/components/ui/questionnaire/questionnaire.d.ts +18 -0
- package/dist/ui/src/components/ui/radio-group/index.d.ts +1 -0
- package/dist/ui/src/components/ui/radio-group/radio-group.d.ts +10 -0
- package/dist/ui/src/components/ui/resizable/index.d.ts +1 -0
- package/dist/ui/src/components/ui/resizable/resizable.d.ts +6 -0
- package/dist/ui/src/components/ui/scroll-area/index.d.ts +1 -0
- package/dist/ui/src/components/ui/scroll-area/scroll-area.behavior.test.d.ts +12 -0
- package/dist/ui/src/components/ui/scroll-area/scroll-area.d.ts +85 -0
- package/dist/ui/src/components/ui/select/index.d.ts +1 -0
- package/dist/ui/src/components/ui/select/select.d.ts +17 -0
- package/dist/ui/src/components/ui/separator/index.d.ts +1 -0
- package/dist/ui/src/components/ui/separator/separator.behavior.test.d.ts +14 -0
- package/dist/ui/src/components/ui/separator/separator.d.ts +16 -0
- package/dist/ui/src/components/ui/sheet/index.d.ts +1 -0
- package/dist/ui/src/components/ui/sheet/sheet.d.ts +13 -0
- package/dist/ui/src/components/ui/sidebar/index.d.ts +1 -0
- package/dist/ui/src/components/ui/sidebar/sidebar.d.ts +63 -0
- package/dist/ui/src/components/ui/skeleton/index.d.ts +1 -0
- package/dist/ui/src/components/ui/skeleton/skeleton.d.ts +1 -0
- package/dist/ui/src/components/ui/slider/index.d.ts +1 -0
- package/dist/ui/src/components/ui/slider/slider.d.ts +17 -0
- package/dist/ui/src/components/ui/spinner/index.d.ts +1 -0
- package/dist/ui/src/components/ui/spinner/spinner.d.ts +5 -0
- package/dist/ui/src/components/ui/switch/index.d.ts +1 -0
- package/dist/ui/src/components/ui/switch/switch.d.ts +4 -0
- package/dist/ui/src/components/ui/table/index.d.ts +1 -0
- package/dist/ui/src/components/ui/table/table.behavior.test.d.ts +9 -0
- package/dist/ui/src/components/ui/table/table.d.ts +9 -0
- package/dist/ui/src/components/ui/tabs/index.d.ts +1 -0
- package/dist/ui/src/components/ui/tabs/tabs.behavior.test.d.ts +21 -0
- package/dist/ui/src/components/ui/tabs/tabs.d.ts +36 -0
- package/dist/ui/src/components/ui/textarea/index.d.ts +1 -0
- package/dist/ui/src/components/ui/textarea/textarea.d.ts +2 -0
- package/dist/ui/src/components/ui/toast/index.d.ts +1 -0
- package/dist/ui/src/components/ui/toast/toast.d.ts +15 -0
- package/dist/ui/src/components/ui/toggle/index.d.ts +1 -0
- package/dist/ui/src/components/ui/toggle/toggle.d.ts +8 -0
- package/dist/ui/src/components/ui/toggle-group/index.d.ts +1 -0
- package/dist/ui/src/components/ui/toggle-group/toggle-group.d.ts +7 -0
- package/dist/ui/src/components/ui/tooltip/index.d.ts +1 -0
- package/dist/ui/src/components/ui/tooltip/tooltip.d.ts +5 -0
- package/dist/ui/src/hooks/use-media-player.d.ts +29 -0
- package/dist/ui/src/hooks/use-merged-refs.d.ts +4 -0
- package/dist/ui/src/hooks/use-mobile.d.ts +1 -0
- package/dist/ui/src/index.d.ts +74 -0
- package/dist/ui/src/lib/first-weekday.d.ts +6 -0
- package/dist/ui/src/lib/first-weekday.test.d.ts +1 -0
- package/dist/ui/src/lib/focus-ring.test.d.ts +8 -0
- package/dist/ui/src/lib/popup-list.d.ts +47 -0
- package/dist/ui/src/lib/popup-list.test.d.ts +10 -0
- package/dist/ui/src/lib/utils.d.ts +13 -0
- package/package.json +95 -4
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
2
|
+
/** An option: `leading` goes before its label (an avatar, a status dot), `count` after it (how many it would show). */
|
|
3
|
+
export type TMultiSelectOption = {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
count?: number;
|
|
7
|
+
leading?: ReactNode;
|
|
8
|
+
};
|
|
9
|
+
/** Every word the component prints, so a product can translate it. */
|
|
10
|
+
export interface IMultiSelectLabels {
|
|
11
|
+
noMatches: string;
|
|
12
|
+
loading: string;
|
|
13
|
+
/** Shown when `error` is `true`; a string `error` replaces it. */
|
|
14
|
+
error: string;
|
|
15
|
+
retry: string;
|
|
16
|
+
loadMore: string;
|
|
17
|
+
loadingMore: string;
|
|
18
|
+
clear: string;
|
|
19
|
+
selectedCount: (count: number) => string;
|
|
20
|
+
}
|
|
21
|
+
export declare const DEFAULT_MULTI_SELECT_LABELS: IMultiSelectLabels;
|
|
22
|
+
/** Above this many options a list draws only the rows on screen. */
|
|
23
|
+
export declare const VIRTUALIZE_FROM = 100;
|
|
24
|
+
/** Anything else a button takes (data-*, aria-*, title) goes to the trigger. */
|
|
25
|
+
export interface IMultiSelectProps extends Omit<ComponentPropsWithoutRef<'button'>, 'placeholder' | 'value' | 'defaultValue' | 'id' | 'disabled' | 'className' | 'children' | 'onChange'> {
|
|
26
|
+
/** The trigger's text with nothing picked, which means no filter ("All dealer groups"). */
|
|
27
|
+
placeholder: string;
|
|
28
|
+
/** The search field's prompt ("Search dealer groups…"). */
|
|
29
|
+
searchPlaceholder: string;
|
|
30
|
+
/** The options to show now: all of a short fixed list, or in async mode the ones for the typed text. */
|
|
31
|
+
options: readonly TMultiSelectOption[];
|
|
32
|
+
value: readonly string[];
|
|
33
|
+
onValueChange: (value: string[]) => void;
|
|
34
|
+
/**
|
|
35
|
+
* What the trigger says once something is chosen. `selection` (default) names the one chosen or counts several;
|
|
36
|
+
* `label` keeps the label and only counts, so a value the page shows elsewhere (as a removable chip, say) is
|
|
37
|
+
* not repeated here: nothing chosen reads `placeholder`, anything chosen reads `labels.selectedCount(n)`.
|
|
38
|
+
*/
|
|
39
|
+
summary?: 'selection' | 'label';
|
|
40
|
+
/** For a Label's htmlFor. */
|
|
41
|
+
id?: string;
|
|
42
|
+
'aria-label'?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Marks the trigger invalid: the kit's destructive border, and a screen reader says so. For a form that does not use
|
|
45
|
+
* Field; inside one, its invalid state already does this.
|
|
46
|
+
*/
|
|
47
|
+
'aria-invalid'?: boolean | 'true' | 'false';
|
|
48
|
+
/**
|
|
49
|
+
* The id of the text that explains it (the error). Added to what a Field names already, never replacing it.
|
|
50
|
+
*/
|
|
51
|
+
'aria-describedby'?: string;
|
|
52
|
+
/** Shown but not changeable (a read-only form). */
|
|
53
|
+
disabled?: boolean;
|
|
54
|
+
/** Layout only (a width); the look is the kit's. */
|
|
55
|
+
className?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Passing this turns on ASYNC MODE, for lists that grow (people, dealer groups) and must
|
|
58
|
+
* be searched by the API rather than loaded whole and filtered in the browser. The
|
|
59
|
+
* component then never filters: it reports the typed text (after `searchDelay`) and shows
|
|
60
|
+
* whatever `options` the caller supplies for it. It is also called with '' each time the
|
|
61
|
+
* list opens, so the first page is fetched on demand, not at page load.
|
|
62
|
+
*/
|
|
63
|
+
onSearchChange?: (text: string) => void;
|
|
64
|
+
/** How long typing must pause before `onSearchChange` is called. Async mode only. */
|
|
65
|
+
searchDelay?: number;
|
|
66
|
+
/**
|
|
67
|
+
* The options behind the chosen values, for the ones not in the current `options`. A
|
|
68
|
+
* search that no longer returns a chosen value must not make it vanish from the trigger
|
|
69
|
+
* or the count, so the caller says what it is called. Without a label a value shows as
|
|
70
|
+
* itself.
|
|
71
|
+
*/
|
|
72
|
+
selectedOptions?: readonly TMultiSelectOption[];
|
|
73
|
+
/** The options for the typed text are on their way. The old ones stay until they arrive. */
|
|
74
|
+
loading?: boolean;
|
|
75
|
+
/** The request failed: `true` for the default message, or the message itself. */
|
|
76
|
+
error?: boolean | string;
|
|
77
|
+
onRetry?: () => void;
|
|
78
|
+
/** There is another page after `options`. */
|
|
79
|
+
hasMore?: boolean;
|
|
80
|
+
onLoadMore?: () => void;
|
|
81
|
+
/** The next page is on its way. */
|
|
82
|
+
loadingMore?: boolean;
|
|
83
|
+
labels?: Partial<IMultiSelectLabels>;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The options behind the chosen values, in the order they were chosen. A value with no
|
|
87
|
+
* known option is kept and shown as itself rather than dropped: a selection must never
|
|
88
|
+
* change just because a list did.
|
|
89
|
+
*/
|
|
90
|
+
export declare const resolveChosen: (value: readonly string[], options: readonly TMultiSelectOption[], selectedOptions?: readonly TMultiSelectOption[]) => TMultiSelectOption[];
|
|
91
|
+
/** What the trigger says: the placeholder, the one picked, or a count. */
|
|
92
|
+
export declare const summarize: (chosen: readonly TMultiSelectOption[], placeholder: string, labels: IMultiSelectLabels, summary?: "selection" | "label") => string;
|
|
93
|
+
/** Every chosen name, for a tooltip on a trigger whose text is cut. With `label` the names are not shown, so it is the text itself. */
|
|
94
|
+
export declare const fullSelection: (chosen: readonly TMultiSelectOption[], placeholder: string, labels: IMultiSelectLabels, summary?: "selection" | "label") => string;
|
|
95
|
+
/**
|
|
96
|
+
* A choice of several from a list: a trigger shaped like a Select that says what is picked
|
|
97
|
+
* (the placeholder, the one picked, or a count), and a popup with a search field and checkbox
|
|
98
|
+
* options, with the shared popup list style, the ScrollArea's bar and fades, and virtualization
|
|
99
|
+
* past VIRTUALIZE_FROM options. Nothing chosen means no filter.
|
|
100
|
+
*
|
|
101
|
+
* For a short fixed list pass `options` and nothing else: the component filters them as the
|
|
102
|
+
* user types. For a list that grows, pass `onSearchChange` and it becomes a window onto a
|
|
103
|
+
* server: the caller fetches the options for the typed text, and says when they are loading,
|
|
104
|
+
* failed, or have another page.
|
|
105
|
+
*/
|
|
106
|
+
export declare const MultiSelect: ({ placeholder, searchPlaceholder, options, value, onValueChange, id, disabled, className, onSearchChange, searchDelay, selectedOptions, loading, error, onRetry, hasMore, onLoadMore, loadingMore, labels: labelOverrides, summary, ...rest }: IMultiSelectProps) => import('react').JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MultiSelect: what stays chosen, what the trigger says, and what words it prints.
|
|
3
|
+
*
|
|
4
|
+
* PATH TAKEN: the rules that keep a selection stable while the list under it changes
|
|
5
|
+
* are plain functions, and the closed trigger renders in happy-dom. Opening the popup,
|
|
6
|
+
* typing, the server round trips and virtualization need a real browser, so
|
|
7
|
+
* e2e/multi-select.spec.ts drives those against a fake server.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './progress-line';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, CSSProperties } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The line's colour: an app sets --progress-line (on :root, or on any element above the
|
|
4
|
+
* line) to match its accent. The fallback is read where the line is, so it follows the
|
|
5
|
+
* theme, which a default declared once on :root would not.
|
|
6
|
+
*/
|
|
7
|
+
export declare const PROGRESS_LINE_COLOR = "var(--progress-line, var(--primary))";
|
|
8
|
+
export interface IProgressLineProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'className' | 'style' | 'role'> {
|
|
9
|
+
/** Work is under way. */
|
|
10
|
+
active: boolean;
|
|
11
|
+
label?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
style?: CSSProperties;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A thin line in the accent (--progress-line, by default --primary) that runs along the top of what is loading (a table's rows
|
|
17
|
+
* under its header, a page under the top bar). It waits a moment before it shows, so
|
|
18
|
+
* quick work never flashes it; it eases towards the end without reaching it while the
|
|
19
|
+
* work runs; when the work is done it runs to the end and only then fades. More work
|
|
20
|
+
* before it has gone carries on from where it is. With reduced motion it is a
|
|
21
|
+
* full-width line that fades.
|
|
22
|
+
*/
|
|
23
|
+
export declare const ProgressLine: ({ active, label, className, style, ...props }: IProgressLineProps) => import('react').JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProgressLine: waits before it shows, eases while the work runs, finishes before it fades.
|
|
3
|
+
*
|
|
4
|
+
* PATH TAKEN: the phase machine is timers and state, so happy-dom with the real
|
|
5
|
+
* clock covers it (the delays are 150, 150 and 200ms, waited out with margin
|
|
6
|
+
* rather than faked). Carrying on from where the line is after more work arrives
|
|
7
|
+
* mid-fade needs a real computed transform, so e2e/progress-line.spec.ts covers it.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The HTML the rich-text editor emits, and the only HTML RichTextContent renders. An app that
|
|
3
|
+
* sanitises on a server takes its allow-list from here: nothing outside these elements and this
|
|
4
|
+
* attribute ever comes out of the editor, whatever was pasted into it.
|
|
5
|
+
*/
|
|
6
|
+
export declare const RICH_TEXT_ELEMENTS: readonly ["p", "br", "hr", "strong", "em", "u", "ul", "ol", "li", "a"];
|
|
7
|
+
/** The attributes each element may carry. Every other element carries none (no class, no style). */
|
|
8
|
+
export declare const RICH_TEXT_ATTRIBUTES: Readonly<Record<string, readonly string[]>>;
|
|
9
|
+
/** A link must be absolute and use one of these. `javascript:`, `data:` and relative links are refused. */
|
|
10
|
+
export declare const RICH_TEXT_LINK_PROTOCOLS: readonly ["http", "https", "mailto"];
|
|
11
|
+
export declare const isAllowedRichTextHref: (href: string) => boolean;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* How rich text looks, shared by the editor and by RichTextContent so a comment reads the same while it is typed and
|
|
4
|
+
* after it is saved. Descendant selectors rather than classes on the elements, because the HTML that is stored carries
|
|
5
|
+
* no classes.
|
|
6
|
+
*/
|
|
7
|
+
export declare const RICH_TEXT_BODY_CLASS = "text-sm leading-6 wrap-break-word [&_a]:text-primary [&_a]:underline [&_a]:underline-offset-2 [&_hr]:my-3 [&_hr]:border-0 [&_hr]:border-t [&_hr]:border-border [&_ol]:list-decimal [&_ol]:ps-5 [&_p+p]:mt-2 [&_ul]:list-disc [&_ul]:ps-5 [&_ul+p]:mt-2 [&_ol+p]:mt-2 [&_p+ul]:mt-2 [&_p+ol]:mt-2";
|
|
8
|
+
export declare const RICH_TEXT_MENTION_CLASS = "rounded-sm bg-primary/10 px-1 py-0.5 font-medium text-primary";
|
|
9
|
+
/** The HTML as React elements, keeping only what the editor can produce. Browser only (it needs a DOM parser). */
|
|
10
|
+
export declare const richTextToNodes: (html: string) => ReactNode[];
|
|
11
|
+
export interface IRichTextContentProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'dangerouslySetInnerHTML'> {
|
|
12
|
+
/** The HTML to show. Only the editor's elements are rendered, whatever else it holds. */
|
|
13
|
+
html: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Shows rich text the editor produced (or any HTML), as the same elements the editor emits and nothing else:
|
|
17
|
+
* `p`, `br`, `hr`, `strong`, `em`, `u`, `ul`, `ol`, `li` and `a` with an `href` (http, https or mailto; it opens in a new tab
|
|
18
|
+
* with `rel="noopener noreferrer"`). Everything else is dropped and its text kept. Built as React elements, not injected
|
|
19
|
+
* as markup, so it is safe on HTML that has not been cleaned. A run like `@name@example.test` or `@assignees` is shown
|
|
20
|
+
* as a chip.
|
|
21
|
+
*/
|
|
22
|
+
export declare const RichTextContent: ({ html, className, ...props }: IRichTextContentProps) => import('react').JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RichTextContent shows saved HTML as the editor's own elements and nothing else. It is built as React elements,
|
|
3
|
+
* so these assertions read the markup it renders: a script or a javascript: link that survived would show here.
|
|
4
|
+
*
|
|
5
|
+
* PATH TAKEN: happy-dom parses the input (DOMParser) and renderToStaticMarkup prints the result, which is enough
|
|
6
|
+
* for what this component decides (what stays, what goes, what is added). How it looks is the browser spec's.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Extension } from '@tiptap/core';
|
|
2
|
+
import { SuggestionKeyDownProps, SuggestionProps } from '@tiptap/suggestion';
|
|
3
|
+
import { TMentionToText } from './serialize';
|
|
4
|
+
import { IRichTextMentionItem } from './types';
|
|
5
|
+
/** What the editor needs from the component while it runs. Held in a ref, so the extensions are built once. */
|
|
6
|
+
export interface IEditorHost {
|
|
7
|
+
mentionEnabled: () => boolean;
|
|
8
|
+
maxLength: () => number | undefined;
|
|
9
|
+
toText: () => TMentionToText;
|
|
10
|
+
onSuggestion: (props: SuggestionProps<IRichTextMentionItem, IRichTextMentionItem> | null) => void;
|
|
11
|
+
onSuggestionKey: (props: SuggestionKeyDownProps) => boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The editor's whole schema: paragraph, line break, bold, italic, underline, bullet and numbered lists, link, and the
|
|
15
|
+
* mention chip. Whatever else arrives (a paste, `value`) is not in the schema, so ProseMirror drops the markup and keeps
|
|
16
|
+
* the text.
|
|
17
|
+
*/
|
|
18
|
+
export declare const buildExtensions: (host: IEditorHost) => (Extension<any, any> | import('@tiptap/core').Node<any, any> | import('@tiptap/core').Node<import('@tiptap/extension-paragraph').ParagraphOptions, any> | import('@tiptap/core').Node<import('@tiptap/extension-hard-break').HardBreakOptions, any> | import('@tiptap/core').Mark<import('@tiptap/extension-bold').BoldOptions, any> | import('@tiptap/core').Node<import('@tiptap/extension-list').BulletListOptions, any> | import('@tiptap/core').Node<import('@tiptap/extension-list').ListItemOptions, any> | import('@tiptap/core').Node<import('@tiptap/extension-horizontal-rule').HorizontalRuleOptions, any> | import('@tiptap/core').Mark<import('@tiptap/extension-link').LinkOptions, any> | Extension<import('@tiptap/extensions').UndoRedoOptions, any> | import('@tiptap/core').Node<import('@tiptap/extension-mention').MentionOptions<any, import('@tiptap/extension-mention').MentionNodeAttrs>, any>)[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
import { IRichTextLabels, IRichTextMention, IRichTextMentionItem } from './types';
|
|
3
|
+
export interface IMentionListProps {
|
|
4
|
+
query: string;
|
|
5
|
+
/** Where the @ was typed. */
|
|
6
|
+
rect: (() => DOMRect | null) | null;
|
|
7
|
+
config: IRichTextMention;
|
|
8
|
+
labels: IRichTextLabels;
|
|
9
|
+
listId: string;
|
|
10
|
+
onPick: (item: IRichTextMentionItem) => void;
|
|
11
|
+
/** The editor keeps focus, so the list is driven by its keys: the editor calls this one. */
|
|
12
|
+
keyHandler: RefObject<((event: KeyboardEvent) => boolean) | null>;
|
|
13
|
+
/** The id of the option the editor should name as `aria-activedescendant`. */
|
|
14
|
+
onActiveChange: (optionId: string | undefined) => void;
|
|
15
|
+
}
|
|
16
|
+
/** The list that opens under the caret when the writer types @. */
|
|
17
|
+
export declare const MentionList: ({ query, rect, config, labels, listId, onPick, keyHandler, onActiveChange }: IMentionListProps) => import('react').JSX.Element;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, Ref } from 'react';
|
|
2
|
+
import { IRichTextEditorHandle, IRichTextField, IRichTextLabels, IRichTextMention } from './types';
|
|
3
|
+
export interface IRichTextEditorProps extends Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'defaultValue' | 'onChange' | 'id'> {
|
|
4
|
+
/** The HTML, when the parent owns it. Pass back what `onChange` gave. An empty editor is `""`. */
|
|
5
|
+
value?: string;
|
|
6
|
+
/** The HTML to start from when the editor owns its own value. */
|
|
7
|
+
defaultValue?: string;
|
|
8
|
+
/** Called with the HTML after every edit. Only the elements in `RICH_TEXT_ELEMENTS` can appear, and `""` when there is no text. */
|
|
9
|
+
onChange?: (html: string) => void;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
/** Shows the content and keeps it selectable and copyable, with no toolbar. */
|
|
13
|
+
readOnly?: boolean;
|
|
14
|
+
/** Draws the error border and sets `aria-invalid`. The message is the form's to draw: point `aria-describedby` at it. */
|
|
15
|
+
invalid?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Lines the box is tall when empty.
|
|
18
|
+
* @default 6
|
|
19
|
+
*/
|
|
20
|
+
minRows?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Lines it grows to before it scrolls inside.
|
|
23
|
+
* @default 20
|
|
24
|
+
*/
|
|
25
|
+
maxRows?: number;
|
|
26
|
+
/** The most characters of text (a mention counts as the text it is written as). An edit past it is refused. Off by default. */
|
|
27
|
+
maxLength?: number;
|
|
28
|
+
/** Turns @ into a search the app answers. Without it, @ is an ordinary character. */
|
|
29
|
+
mention?: IRichTextMention;
|
|
30
|
+
/** Adds an "Insert a field" menu that writes `{{id}}` at the caret. */
|
|
31
|
+
fields?: IRichTextField[];
|
|
32
|
+
/**
|
|
33
|
+
* Whether the formatting toolbar shows.
|
|
34
|
+
* @default true
|
|
35
|
+
*/
|
|
36
|
+
toolbar?: boolean;
|
|
37
|
+
/** Replaces any of the strings the editor shows (the defaults are English). */
|
|
38
|
+
labels?: Partial<IRichTextLabels>;
|
|
39
|
+
/** On the editable element, so a form can name it. */
|
|
40
|
+
id?: string;
|
|
41
|
+
autoFocus?: boolean;
|
|
42
|
+
/** Called with the files when the writer pastes only files (a screenshot). Without it, such a paste does nothing. */
|
|
43
|
+
onPasteFiles?: (files: File[]) => void;
|
|
44
|
+
/** Gives `insertText` and `focus`, for buttons outside the editor. */
|
|
45
|
+
ref?: Ref<IRichTextEditorHandle>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A small rich-text field: paragraphs, bold, italic, underline, bulleted and numbered lists and links, with optional
|
|
49
|
+
* @mentions the app answers asynchronously. The value is HTML in and out, and only the elements in `RICH_TEXT_ELEMENTS`
|
|
50
|
+
* can come out (no class, no style), whatever is pasted. A mention is a chip while editing and plain text in the HTML.
|
|
51
|
+
* The server should still sanitise: this is a convenience for the writer, not a security boundary.
|
|
52
|
+
*/
|
|
53
|
+
export declare const RichTextEditor: ({ value, defaultValue, onChange, placeholder, disabled, readOnly, invalid, minRows, maxRows, maxLength, mention, fields, toolbar, labels, id, autoFocus, onPasteFiles, ref, className, "aria-invalid": ariaInvalid, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, ...props }: IRichTextEditorProps) => import('react').JSX.Element;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor's schema decides what HTML can come out, whatever goes in. These tests drive the real extension set
|
|
3
|
+
* through a headless ProseMirror editor and read what it serialises, so the allow-list the docs promise is the one
|
|
4
|
+
* that is checked. Typing, focus and the mention list need a real browser: e2e/rich-text-editor.spec.ts.
|
|
5
|
+
*/
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Node as TProseNode } from '@tiptap/pm/model';
|
|
2
|
+
import { IRichTextMention } from './types';
|
|
3
|
+
export type TMentionToText = NonNullable<IRichTextMention['toText']>;
|
|
4
|
+
export declare const defaultMentionToText: TMentionToText;
|
|
5
|
+
/**
|
|
6
|
+
* The document as HTML. Not `editor.getHTML()`: that would write a mention as its chip element, and
|
|
7
|
+
* the HTML must carry the plain text the app chose (`@person@example.test`) and nothing else.
|
|
8
|
+
*/
|
|
9
|
+
export declare const serializeDocument: (doc: TProseNode, toText: TMentionToText) => string;
|
|
10
|
+
/** No text and no mention. A document of blank paragraphs, spaces and line breaks is empty too. */
|
|
11
|
+
export declare const isDocumentEmpty: (doc: TProseNode) => boolean;
|
|
12
|
+
/** Characters the HTML text will have: a mention counts as the text it is written as. */
|
|
13
|
+
export declare const countCharacters: (doc: TProseNode, toText: TMentionToText) => number;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Editor } from '@tiptap/core';
|
|
2
|
+
/**
|
|
3
|
+
* Whether commands may be called on the editor. TipTap builds an editor during the render, mounts its view later, and
|
|
4
|
+
* destroys one that has not been mounted within a moment (useEditor then makes a new one), so an effect can be handed an
|
|
5
|
+
* editor that is not there yet or no longer is. `isDestroyed` is true for both: it reads true until the view exists. A
|
|
6
|
+
* destroyed editor has no command manager, so `editor.commands` throws on it.
|
|
7
|
+
*/
|
|
8
|
+
export declare const isLive: (editor: Editor) => boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Brings the editor to a value the parent passed in, if it is one the editor did not just report itself.
|
|
11
|
+
* `known` is the last HTML the editor and the parent agree on (the starting value, then whatever the editor emitted or was
|
|
12
|
+
* given). The caret stays where it was, kept inside the new content, so a value changed from outside while the writer is
|
|
13
|
+
* typing does not throw the caret to the start.
|
|
14
|
+
*/
|
|
15
|
+
export declare const syncValue: (editor: Editor, value: string | undefined, known: {
|
|
16
|
+
current: string | undefined;
|
|
17
|
+
}) => void;
|
|
18
|
+
/** Sets whether the editor can be edited without telling the app something changed (TipTap emits an update by default). */
|
|
19
|
+
export declare const syncEditable: (editor: Editor, editable: boolean) => void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keeping the editor in step with the parent's value without ever touching an editor that is not there. A controlled
|
|
3
|
+
* RichTextEditor crashed on mount in rc.7 ("Cannot read properties of null (reading 'commands')"): TipTap makes the editor
|
|
4
|
+
* during the render, mounts its view later and destroys one that is not mounted in time, and the value effect ran at the
|
|
5
|
+
* first commit for every controlled value and called a command on whatever editor it was handed.
|
|
6
|
+
*
|
|
7
|
+
* PATH TAKEN: the destroyed editor is reproduced as the state TipTap leaves it in (no command manager, so `commands`
|
|
8
|
+
* throws), because the timing that produces it in an app cannot be driven from a test. The real behaviour in a browser,
|
|
9
|
+
* mount order included, is e2e/rich-text-editor-lifecycle.spec.ts.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Editor } from '@tiptap/core';
|
|
2
|
+
import { RefObject } from 'react';
|
|
3
|
+
import { IRichTextField, IRichTextLabels } from './types';
|
|
4
|
+
/** A typed address becomes a link: "name@example.test" a mailto, "example.test" an https address. */
|
|
5
|
+
export declare const normalizeHref: (raw: string) => string;
|
|
6
|
+
/** Where the writer's selection was when the link box opened: moving focus into the box must not lose it. */
|
|
7
|
+
export interface ILinkRange {
|
|
8
|
+
from: number;
|
|
9
|
+
to: number;
|
|
10
|
+
}
|
|
11
|
+
export interface IRichTextToolbarProps {
|
|
12
|
+
linkRange: RefObject<ILinkRange | null>;
|
|
13
|
+
editor: Editor;
|
|
14
|
+
labels: IRichTextLabels;
|
|
15
|
+
fields: IRichTextField[] | undefined;
|
|
16
|
+
disabled: boolean;
|
|
17
|
+
linkOpen: boolean;
|
|
18
|
+
onLinkOpenChange: (open: boolean) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare const RichTextToolbar: ({ linkRange, editor, labels, fields, disabled, linkOpen, onLinkOpenChange }: IRichTextToolbarProps) => import('react').JSX.Element;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** One person (or anything else) the app offers when the writer types @. */
|
|
2
|
+
export interface IRichTextMentionItem {
|
|
3
|
+
/** What the HTML carries. By default the value is written as `@${id}`, so an email address works as an id. */
|
|
4
|
+
id: string;
|
|
5
|
+
/** What the chip shows while the text is being edited. */
|
|
6
|
+
label: string;
|
|
7
|
+
/** A second, muted line in the list (a role, an email address). */
|
|
8
|
+
secondary?: string;
|
|
9
|
+
}
|
|
10
|
+
/** A page of results. Return a plain array instead when there is only ever one page. */
|
|
11
|
+
export interface IRichTextMentionPage {
|
|
12
|
+
items: IRichTextMentionItem[];
|
|
13
|
+
/** True when asking for `page + 1` would return more. The list loads it when it is scrolled to the end. */
|
|
14
|
+
hasMore?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface IRichTextMentionSearchOptions {
|
|
17
|
+
/** 1-based. */
|
|
18
|
+
page: number;
|
|
19
|
+
/** Aborted when the writer types on or closes the list: pass it to `fetch` so a stale search stops. */
|
|
20
|
+
signal: AbortSignal;
|
|
21
|
+
}
|
|
22
|
+
export type TRichTextMentionSearch = (query: string, options: IRichTextMentionSearchOptions) => Promise<IRichTextMentionItem[] | IRichTextMentionPage>;
|
|
23
|
+
export interface IRichTextMention {
|
|
24
|
+
/** Asked for the first page when the writer types @ and again for every change of the text after it, debounced. */
|
|
25
|
+
search: TRichTextMentionSearch;
|
|
26
|
+
/**
|
|
27
|
+
* How a mention is written into the HTML. The chip exists only while editing; the HTML carries this text
|
|
28
|
+
* and no element. Default: `@${item.id}`.
|
|
29
|
+
*/
|
|
30
|
+
toText?: (item: Pick<IRichTextMentionItem, 'id' | 'label'>) => string;
|
|
31
|
+
/** Milliseconds to wait after the last keystroke before searching. Default 250. */
|
|
32
|
+
debounce?: number;
|
|
33
|
+
}
|
|
34
|
+
/** A field of a template (a mail merge token). Inserted as the plain text `{{id}}`. */
|
|
35
|
+
export interface IRichTextField {
|
|
36
|
+
id: string;
|
|
37
|
+
label: string;
|
|
38
|
+
}
|
|
39
|
+
/** What a ref to the editor can do, for a button outside it (a merge tag, say). */
|
|
40
|
+
export interface IRichTextEditorHandle {
|
|
41
|
+
/** Writes plain text at the caret (over the selection), and puts focus back in the editor. */
|
|
42
|
+
insertText: (text: string) => void;
|
|
43
|
+
focus: () => void;
|
|
44
|
+
}
|
|
45
|
+
/** Every string the editor shows, so an app can translate them. */
|
|
46
|
+
export interface IRichTextLabels {
|
|
47
|
+
toolbar: string;
|
|
48
|
+
bold: string;
|
|
49
|
+
italic: string;
|
|
50
|
+
underline: string;
|
|
51
|
+
bulletList: string;
|
|
52
|
+
numberedList: string;
|
|
53
|
+
link: string;
|
|
54
|
+
horizontalRule: string;
|
|
55
|
+
insertField: string;
|
|
56
|
+
linkAddress: string;
|
|
57
|
+
linkApply: string;
|
|
58
|
+
linkRemove: string;
|
|
59
|
+
linkInvalid: string;
|
|
60
|
+
mentionList: string;
|
|
61
|
+
mentionSearching: string;
|
|
62
|
+
mentionEmpty: string;
|
|
63
|
+
mentionError: string;
|
|
64
|
+
mentionLoadingMore: string;
|
|
65
|
+
/** Announced as the list changes. `{count}` is replaced. */
|
|
66
|
+
mentionResults: string;
|
|
67
|
+
}
|
|
68
|
+
export declare const DEFAULT_RICH_TEXT_LABELS: IRichTextLabels;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './video-player';
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { TCssLength } from '../../../lib/utils';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
export interface IVideoPlayerProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'children' | 'className' | 'title' | 'onPlay' | 'onPause' | 'onEnded' | 'onTimeUpdate'> {
|
|
4
|
+
/** Video source URL. */
|
|
5
|
+
src?: string;
|
|
6
|
+
/** Still frame shown before playback starts. */
|
|
7
|
+
poster?: string;
|
|
8
|
+
/** Primary label rendered in the control overlay. */
|
|
9
|
+
title?: string;
|
|
10
|
+
/** Secondary label rendered under the title. */
|
|
11
|
+
description?: string;
|
|
12
|
+
/** Start muted. Required by browsers for unattended autoplay. */
|
|
13
|
+
muted?: boolean;
|
|
14
|
+
/** Loop playback when the video ends. */
|
|
15
|
+
loop?: boolean;
|
|
16
|
+
/** Disable every control without hiding the player. */
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Box width. A number is px, a string is any CSS length (`'100%'`, `'34rem'`).
|
|
20
|
+
* Omitted, the player fills the width it is given.
|
|
21
|
+
*/
|
|
22
|
+
width?: TCssLength;
|
|
23
|
+
/**
|
|
24
|
+
* Box height. A number is px, a string is any CSS length. Omitted, the height
|
|
25
|
+
* comes from `ratio`. Setting this letterboxes a source that does not match.
|
|
26
|
+
*/
|
|
27
|
+
height?: TCssLength;
|
|
28
|
+
/**
|
|
29
|
+
* Aspect ratio of the media box, as a CSS `aspect-ratio` value (`'16/9'`).
|
|
30
|
+
*
|
|
31
|
+
* Defaults to `auto`, so the height follows the source's own dimensions and a
|
|
32
|
+
* portrait or 4:3 clip is shown whole rather than letterboxed. Pair `auto`
|
|
33
|
+
* with a `poster`: a `<video>` reports a 300x150 intrinsic size until metadata
|
|
34
|
+
* arrives, and the poster's dimensions stand in for it, which is what stops
|
|
35
|
+
* the box from resizing when the first frame lands.
|
|
36
|
+
*
|
|
37
|
+
* Ignored when `height` is set.
|
|
38
|
+
*/
|
|
39
|
+
ratio?: string;
|
|
40
|
+
className?: string;
|
|
41
|
+
'aria-label'?: string;
|
|
42
|
+
onPlay?: () => void;
|
|
43
|
+
onPause?: () => void;
|
|
44
|
+
onEnded?: () => void;
|
|
45
|
+
onTimeUpdate?: (currentTime: number, duration: number) => void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Media surface with an overlaid control bar: title and description, elapsed and
|
|
49
|
+
* total time, a seekable scrubber, play/pause, volume, and fullscreen.
|
|
50
|
+
*
|
|
51
|
+
* The root carries the `dark` class so its tokens resolve to the dark palette in
|
|
52
|
+
* both themes. Video is dark, so the letterbox and controls must stay dark and
|
|
53
|
+
* light-on-dark; this re-scopes existing tokens rather than hardcoding a colour.
|
|
54
|
+
*/
|
|
55
|
+
export declare const VideoPlayer: ({ src, poster, title, description, muted, loop, disabled, width, height, ratio, className, "aria-label": ariaLabel, style, onPlay, onPause, onEnded, onTimeUpdate, ...props }: IVideoPlayerProps) => React.JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every exported component hands `aria-label`, `id` and `data-testid` to the element it documents as its root or main part.
|
|
3
|
+
* A component that took a closed list of props dropped the rest (Tabs' tablist had no accessible name even though the app
|
|
4
|
+
* passed `aria-label`), so this renders each one with the three and finds them again.
|
|
5
|
+
*
|
|
6
|
+
* Components that are not covered here, and why, are listed in INTENTIONAL_DROPS.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A11y + interaction test for Accordion.
|
|
3
|
+
*
|
|
4
|
+
* Uses happy-dom to verify:
|
|
5
|
+
* 1. Triggers are rendered as buttons with aria-expanded.
|
|
6
|
+
* 2. Panels are present in the DOM (keepMounted=true on AccordionContent).
|
|
7
|
+
* 3. Clicking a trigger fires onValueChange with the correct value.
|
|
8
|
+
* 4. aria-expanded flips to true on the opened item after re-render.
|
|
9
|
+
*
|
|
10
|
+
* Full real-browser keyboard navigation (ArrowDown/Up/Home/End/Enter/Space) is
|
|
11
|
+
* proven separately in e2e/accordion-keyboard.spec.ts.
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Accordion as BaseAccordion } from '@base-ui/react/accordion';
|
|
2
|
+
import type * as React from 'react';
|
|
3
|
+
export interface IAccordionProps extends Omit<BaseAccordion.Root.Props, 'value' | 'defaultValue' | 'onValueChange' | 'multiple' | 'className' | 'children'> {
|
|
4
|
+
value?: string[];
|
|
5
|
+
defaultValue?: string[];
|
|
6
|
+
onValueChange?: (value: string[]) => void;
|
|
7
|
+
multiple?: boolean;
|
|
8
|
+
className?: string;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
export declare const Accordion: ({ value, defaultValue, onValueChange, multiple, className, children, ...props }: IAccordionProps) => React.JSX.Element;
|
|
12
|
+
export interface IAccordionItemProps extends Omit<BaseAccordion.Item.Props, 'value' | 'disabled' | 'className' | 'children'> {
|
|
13
|
+
value: string;
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
className?: string;
|
|
16
|
+
children: React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
export declare const AccordionItem: ({ value, disabled, className, children, ...props }: IAccordionItemProps) => React.JSX.Element;
|
|
19
|
+
export interface IAccordionTriggerProps extends Omit<BaseAccordion.Trigger.Props, 'className' | 'children'> {
|
|
20
|
+
className?: string;
|
|
21
|
+
children: React.ReactNode;
|
|
22
|
+
}
|
|
23
|
+
export declare const AccordionTrigger: ({ className, children, ...props }: IAccordionTriggerProps) => React.JSX.Element;
|
|
24
|
+
export interface IAccordionContentProps extends Omit<BaseAccordion.Panel.Props, 'className' | 'children'> {
|
|
25
|
+
className?: string;
|
|
26
|
+
children: React.ReactNode;
|
|
27
|
+
}
|
|
28
|
+
export declare const AccordionContent: ({ className, children, ...props }: IAccordionContentProps) => React.JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './accordion';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { VariantProps } from 'class-variance-authority';
|
|
2
|
+
import type * as React from 'react';
|
|
3
|
+
declare const alertVariants: (props?: ({
|
|
4
|
+
variant?: "default" | "destructive" | "success" | "warning" | "info" | null | undefined;
|
|
5
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
6
|
+
export declare const Alert: ({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) => React.JSX.Element;
|
|
7
|
+
export declare const AlertTitle: ({ className, ...props }: React.ComponentProps<"div">) => React.JSX.Element;
|
|
8
|
+
export declare const AlertDescription: ({ className, ...props }: React.ComponentProps<"div">) => React.JSX.Element;
|
|
9
|
+
export declare const AlertAction: ({ className, ...props }: React.ComponentProps<"div">) => React.JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './alert';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AlertDialog as AlertDialogPrimitive } from '@base-ui/react/alert-dialog';
|
|
2
|
+
import { Button } from '../button';
|
|
3
|
+
import type * as React from 'react';
|
|
4
|
+
export declare const AlertDialog: ({ ...props }: AlertDialogPrimitive.Root.Props) => React.JSX.Element;
|
|
5
|
+
export declare const AlertDialogTrigger: ({ ...props }: AlertDialogPrimitive.Trigger.Props) => React.JSX.Element;
|
|
6
|
+
export declare const AlertDialogPortal: ({ ...props }: AlertDialogPrimitive.Portal.Props) => React.JSX.Element;
|
|
7
|
+
export declare const AlertDialogOverlay: ({ className, ...props }: AlertDialogPrimitive.Backdrop.Props) => React.JSX.Element;
|
|
8
|
+
export declare const AlertDialogContent: ({ className, size, ...props }: AlertDialogPrimitive.Popup.Props & {
|
|
9
|
+
size?: "default" | "sm";
|
|
10
|
+
}) => React.JSX.Element;
|
|
11
|
+
export declare const AlertDialogHeader: ({ className, ...props }: React.ComponentProps<"div">) => React.JSX.Element;
|
|
12
|
+
export declare const AlertDialogFooter: ({ className, ...props }: React.ComponentProps<"div">) => React.JSX.Element;
|
|
13
|
+
export declare const AlertDialogMedia: ({ className, ...props }: React.ComponentProps<"div">) => React.JSX.Element;
|
|
14
|
+
export declare const AlertDialogTitle: ({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) => React.JSX.Element;
|
|
15
|
+
export declare const AlertDialogDescription: ({ className, ...props }: React.ComponentProps<typeof AlertDialogPrimitive.Description>) => React.JSX.Element;
|
|
16
|
+
export declare const AlertDialogAction: ({ className, ...props }: React.ComponentProps<typeof Button>) => React.JSX.Element;
|
|
17
|
+
export declare const AlertDialogCancel: ({ className, variant, size, ...props }: AlertDialogPrimitive.Close.Props & Pick<React.ComponentProps<typeof Button>, "variant" | "size">) => React.JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './alert-dialog';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './aspect-ratio';
|