@webority/ui-react 0.53.0 → 0.54.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/components/AppActionIcon.js +1 -1
- package/dist/components/AppAvatar.js +1 -1
- package/dist/components/AppButton.js +1 -1
- package/dist/components/AppButtonGroup.js +1 -0
- package/dist/components/AppCarousel.js +1 -0
- package/dist/components/AppChipGroup.js +1 -0
- package/dist/components/AppCodeBlock.js +1 -0
- package/dist/components/AppCommandPalette.js +1 -1
- package/dist/components/AppCommentThread.js +1 -0
- package/dist/components/AppDataTable.js +1 -1
- package/dist/components/AppDateRangePicker.js +1 -1
- package/dist/components/AppDrawer.js +1 -0
- package/dist/components/AppDropdown.js +1 -1
- package/dist/components/AppEmptyState.js +1 -1
- package/dist/components/AppFilterBar.js +1 -1
- package/dist/components/AppHoverCard.js +1 -0
- package/dist/components/AppInlineEdit.js +1 -0
- package/dist/components/AppInputGroup.js +1 -0
- package/dist/components/AppKbd.js +1 -0
- package/dist/components/AppLightbox.js +1 -0
- package/dist/components/AppMentionInput.js +1 -0
- package/dist/components/AppMenubar.js +1 -0
- package/dist/components/AppNavigationMenu.js +1 -0
- package/dist/components/AppNotificationCenter.js +1 -0
- package/dist/components/AppOnboardingChecklist.js +1 -0
- package/dist/components/AppRating.js +1 -0
- package/dist/components/AppRecordPager.js +1 -0
- package/dist/components/AppRelativeTime.js +1 -0
- package/dist/components/AppResizable.js +1 -0
- package/dist/components/AppResizableHandle.js +1 -0
- package/dist/components/AppResizablePanel.js +1 -0
- package/dist/components/AppRollingNumber.js +1 -0
- package/dist/components/AppSectionCallToAction.js +1 -0
- package/dist/components/AppSectionFaq.js +1 -0
- package/dist/components/AppSectionFeatures.js +1 -0
- package/dist/components/AppSectionHero.js +1 -0
- package/dist/components/AppSectionLogos.js +1 -0
- package/dist/components/AppSectionPricing.js +1 -0
- package/dist/components/AppSectionTestimonials.js +1 -0
- package/dist/components/AppShortcutLegend.js +1 -0
- package/dist/components/AppShowMore.js +1 -0
- package/dist/components/AppSplitButton.js +1 -0
- package/dist/components/AppSplitView.js +1 -0
- package/dist/components/AppTableEmptyState.js +1 -1
- package/dist/components/AppTableToolbar.js +1 -1
- package/dist/components/AppTabs.js +1 -1
- package/dist/components/AppTooltip.js +1 -1
- package/dist/components/AppTruncate.js +1 -0
- package/dist/components/AppWhatsNew.js +1 -0
- package/dist/components/withTooltip.js +1 -1
- package/dist/lib/emptyIllustration.js +1 -0
- package/dist/lib/sectionShell.js +1 -0
- package/dist/lib/shortcutChip.js +1 -0
- package/dist/lib/useListShortcuts.js +1 -0
- package/dist/types/components/AppActionIcon.d.ts +4 -1
- package/dist/types/components/AppButton.d.ts +2 -1
- package/dist/types/components/AppButtonGroup.d.ts +23 -0
- package/dist/types/components/AppCarousel.d.ts +52 -0
- package/dist/types/components/AppChipGroup.d.ts +22 -0
- package/dist/types/components/AppCodeBlock.d.ts +28 -0
- package/dist/types/components/AppCommandPalette.d.ts +44 -2
- package/dist/types/components/AppCommentThread.d.ts +115 -0
- package/dist/types/components/AppDataTable.d.ts +44 -1
- package/dist/types/components/AppDateRangePicker.d.ts +5 -0
- package/dist/types/components/AppDrawer.d.ts +46 -0
- package/dist/types/components/AppDropdown.d.ts +4 -1
- package/dist/types/components/AppEmptyState.d.ts +4 -1
- package/dist/types/components/AppFilterBar.d.ts +9 -1
- package/dist/types/components/AppHoverCard.d.ts +35 -0
- package/dist/types/components/AppInlineEdit.d.ts +57 -0
- package/dist/types/components/AppInputGroup.d.ts +29 -0
- package/dist/types/components/AppKbd.d.ts +15 -0
- package/dist/types/components/AppLightbox.d.ts +40 -0
- package/dist/types/components/AppMentionInput.d.ts +41 -0
- package/dist/types/components/AppMenubar.d.ts +45 -0
- package/dist/types/components/AppNavigationMenu.d.ts +41 -0
- package/dist/types/components/AppNotificationCenter.d.ts +81 -0
- package/dist/types/components/AppOnboardingChecklist.d.ts +48 -0
- package/dist/types/components/AppRating.d.ts +48 -0
- package/dist/types/components/AppRecordPager.d.ts +38 -0
- package/dist/types/components/AppRelativeTime.d.ts +18 -0
- package/dist/types/components/AppResizable.d.ts +30 -0
- package/dist/types/components/AppResizableHandle.d.ts +13 -0
- package/dist/types/components/AppResizablePanel.d.ts +20 -0
- package/dist/types/components/AppRollingNumber.d.ts +27 -0
- package/dist/types/components/AppSectionCallToAction.d.ts +24 -0
- package/dist/types/components/AppSectionFaq.d.ts +28 -0
- package/dist/types/components/AppSectionFeatures.d.ts +37 -0
- package/dist/types/components/AppSectionHero.d.ts +32 -0
- package/dist/types/components/AppSectionLogos.d.ts +36 -0
- package/dist/types/components/AppSectionPricing.d.ts +28 -0
- package/dist/types/components/AppSectionTestimonials.d.ts +34 -0
- package/dist/types/components/AppShortcutLegend.d.ts +34 -0
- package/dist/types/components/AppShowMore.d.ts +29 -0
- package/dist/types/components/AppSplitButton.d.ts +53 -0
- package/dist/types/components/AppSplitView.d.ts +85 -0
- package/dist/types/components/AppTableEmptyState.d.ts +4 -1
- package/dist/types/components/AppTableToolbar.d.ts +13 -1
- package/dist/types/components/AppTabs.d.ts +12 -6
- package/dist/types/components/AppTooltip.d.ts +4 -1
- package/dist/types/components/AppTruncate.d.ts +21 -0
- package/dist/types/components/AppWhatsNew.d.ts +44 -0
- package/dist/types/components/withTooltip.d.ts +1 -1
- package/dist/types/index.d.ts +37 -0
- package/dist/types/lib/emptyIllustration.d.ts +22 -0
- package/dist/types/lib/sectionShell.d.ts +43 -0
- package/dist/types/lib/shortcutChip.d.ts +11 -0
- package/dist/types/lib/useListShortcuts.d.ts +24 -0
- package/dist/ui-react.js +1 -1
- package/package.json +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export default function AppButton({ children, variant, size, type, loading, disabled, block, leftIcon, rightIcon, href, static: isStatic, tooltip, tooltipPlacement, className, ...rest }: {
|
|
1
|
+
export default function AppButton({ children, variant, size, type, loading, disabled, block, leftIcon, rightIcon, href, static: isStatic, tooltip, tooltipPlacement, shortcut, className, ...rest }: {
|
|
2
2
|
[x: string]: any;
|
|
3
3
|
block?: boolean;
|
|
4
4
|
children: any;
|
|
@@ -8,6 +8,7 @@ export default function AppButton({ children, variant, size, type, loading, disa
|
|
|
8
8
|
leftIcon?: any;
|
|
9
9
|
loading?: boolean;
|
|
10
10
|
rightIcon?: any;
|
|
11
|
+
shortcut: any;
|
|
11
12
|
size?: string;
|
|
12
13
|
static?: boolean;
|
|
13
14
|
tooltip: any;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Related buttons joined into one control: a view switch, a bulk-action row, a text-style set
|
|
3
|
+
* ("Bold", "Italic"). The buttons touch, share one outline and keep their own variants and
|
|
4
|
+
* handlers; give every button in the group the same `variant` and leave `size` to the group.
|
|
5
|
+
* The group is announced by `label`; each button is still its own tab stop (this is a set of
|
|
6
|
+
* actions, not a single-choice control; for one choice of several use `AppSegmented`).
|
|
7
|
+
*
|
|
8
|
+
* @param {object} props
|
|
9
|
+
* @param {string} props.label Accessible name for the group ("Text style").
|
|
10
|
+
* @param {import('react').ReactNode} props.children `AppButton`s (or button-styled links).
|
|
11
|
+
* @param {'sm'|'md'|'lg'} [props.size='md'] One size for every button in the group.
|
|
12
|
+
* @param {boolean} [props.vertical=false] Stack the buttons top to bottom.
|
|
13
|
+
* @param {boolean} [props.fullWidth=false] Fill the container, the buttons sharing the row equally.
|
|
14
|
+
* @param {string} [props.className]
|
|
15
|
+
*/
|
|
16
|
+
export default function AppButtonGroup({ label, children, size, vertical, fullWidth, className, ...rest }: {
|
|
17
|
+
label: string;
|
|
18
|
+
children: import('react').ReactNode;
|
|
19
|
+
size?: 'sm' | 'md' | 'lg';
|
|
20
|
+
vertical?: boolean;
|
|
21
|
+
fullWidth?: boolean;
|
|
22
|
+
className?: string;
|
|
23
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import "@webority/ui-elements/elements/carousel";
|
|
2
|
+
/**
|
|
3
|
+
* A row of slides you can step through, drag or swipe: previous and next buttons, a dot per page, and
|
|
4
|
+
* optional auto-advance that can always be stopped. Each child is one slide.
|
|
5
|
+
*
|
|
6
|
+
* With `autoplay` it advances every that many milliseconds and shows a visible Pause / Play button
|
|
7
|
+
* before the slides. It holds while the pointer is over it or focus is inside, while the tab is hidden,
|
|
8
|
+
* and not at all when the user prefers reduced motion (the button is hidden then). It wraps to the
|
|
9
|
+
* first slide; the buttons wrap only with `loop`. The slides are named "2 of 5", and the page that
|
|
10
|
+
* comes into view is announced politely when the user, not the autoplay, moved it. The focused slide
|
|
11
|
+
* row also takes Left, Right, Home and End.
|
|
12
|
+
*
|
|
13
|
+
* `perView` shows several slides at once (its `Md` and `Lg` forms apply from those breakpoints), and
|
|
14
|
+
* the dots then stand for pages of slides. Wraps the shared `<wui-carousel>` element, which owns the
|
|
15
|
+
* stepping and the autoplay; the Razor `<app-carousel>` renders the same markup.
|
|
16
|
+
*
|
|
17
|
+
* @param {object} props
|
|
18
|
+
* @param {string} props.label What the slides are ("Customer stories"): the carousel's accessible name.
|
|
19
|
+
* @param {number} [props.autoplay] Milliseconds between automatic steps (5000 is typical). Omit for none.
|
|
20
|
+
* @param {boolean} [props.loop=false] The previous and next buttons wrap around at the ends.
|
|
21
|
+
* @param {number} [props.perView=1] Slides in view on a phone.
|
|
22
|
+
* @param {number} [props.perViewMd] Slides in view from the md breakpoint. Defaults to `perView`.
|
|
23
|
+
* @param {number} [props.perViewLg] Slides in view from the lg breakpoint. Defaults to `perViewMd`.
|
|
24
|
+
* @param {boolean} [props.arrows=true] Show the previous and next buttons.
|
|
25
|
+
* @param {boolean} [props.dots=true] Show the page dots.
|
|
26
|
+
* @param {string} [props.previousLabel="Previous slide"] The previous button's name.
|
|
27
|
+
* @param {string} [props.nextLabel="Next slide"] The next button's name.
|
|
28
|
+
* @param {string} [props.dotLabel="Go to slide"] The words before the slide number in each dot's name.
|
|
29
|
+
* @param {string} [props.pauseLabel="Pause"] The pause button's text and name while playing.
|
|
30
|
+
* @param {string} [props.playLabel="Play"] The pause button's text and name while paused.
|
|
31
|
+
* @param {string} [props.className]
|
|
32
|
+
* @param {import('react').CSSProperties} [props.style] Merged after the per-view custom properties.
|
|
33
|
+
* @param {import('react').ReactNode} props.children The slides.
|
|
34
|
+
*/
|
|
35
|
+
export default function AppCarousel({ label, autoplay, loop, perView, perViewMd, perViewLg, arrows, dots, previousLabel, nextLabel, dotLabel, pauseLabel, playLabel, className, children, style, ...rest }: {
|
|
36
|
+
label: string;
|
|
37
|
+
autoplay?: number;
|
|
38
|
+
loop?: boolean;
|
|
39
|
+
perView?: number;
|
|
40
|
+
perViewMd?: number;
|
|
41
|
+
perViewLg?: number;
|
|
42
|
+
arrows?: boolean;
|
|
43
|
+
dots?: boolean;
|
|
44
|
+
previousLabel?: string;
|
|
45
|
+
nextLabel?: string;
|
|
46
|
+
dotLabel?: string;
|
|
47
|
+
pauseLabel?: string;
|
|
48
|
+
playLabel?: string;
|
|
49
|
+
className?: string;
|
|
50
|
+
style?: import('react').CSSProperties;
|
|
51
|
+
children: import('react').ReactNode;
|
|
52
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import "@webority/ui-elements/elements/overflow";
|
|
2
|
+
/**
|
|
3
|
+
* A row of chips (`AppChip`, `AppChoiceChip`) that either wraps onto more lines or, with
|
|
4
|
+
* `overflow="menu"`, keeps one line and moves the chips that do not fit into a More menu
|
|
5
|
+
* (`<wui-overflow>`, which Razor `<app-chip-group>` renders too). Choosing a chip in the menu
|
|
6
|
+
* clicks that chip's own control, so a clickable `AppChip` runs its `onClick` and an
|
|
7
|
+
* `AppChoiceChip` toggles. A chip with no control (static or only removable) is listed greyed out.
|
|
8
|
+
*
|
|
9
|
+
* @param {object} props
|
|
10
|
+
* @param {import('react').ReactNode} props.children The chips.
|
|
11
|
+
* @param {"wrap"|"menu"} [props.overflow="wrap"] `wrap` lets the chips wrap; `menu` moves the extras into a More menu.
|
|
12
|
+
* @param {string} [props.moreLabel="More"] The More button's text when `overflow="menu"`.
|
|
13
|
+
* @param {string} [props.label] Accessible name for the group.
|
|
14
|
+
* @param {string} [props.className]
|
|
15
|
+
*/
|
|
16
|
+
export default function AppChipGroup({ children, overflow, moreLabel, label, className, ...rest }: {
|
|
17
|
+
children: import('react').ReactNode;
|
|
18
|
+
overflow?: "wrap" | "menu";
|
|
19
|
+
moreLabel?: string;
|
|
20
|
+
label?: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import "@webority/ui-elements/elements/code-block";
|
|
2
|
+
/**
|
|
3
|
+
* Source code with syntax colours (light and dark), a Copy button with a confirmation, optional
|
|
4
|
+
* line numbers and optional wrapping, for docs pages, API keys, webhook payloads and request
|
|
5
|
+
* examples. The colouring is a small built-in tokenizer in `<wui-code-block>`, which Razor
|
|
6
|
+
* `<app-code-block>` renders too; the source is only ever drawn as text, never as HTML. Source
|
|
7
|
+
* beyond 100,000 characters is shown uncoloured. Not an editor: it shows code, it does not edit it.
|
|
8
|
+
*
|
|
9
|
+
* @param {object} props
|
|
10
|
+
* @param {string} props.code The source text. A single trailing newline is dropped.
|
|
11
|
+
* @param {"text"|"json"|"js"|"cs"|"sql"|"bash"|"http"|"html"|"css"} [props.language="text"] What to colour; `text` shows it as written.
|
|
12
|
+
* @param {boolean} [props.lineNumbers=false] Number the lines. The numbers are not copied or selected.
|
|
13
|
+
* @param {boolean} [props.wrap=false] Wrap long lines instead of scrolling sideways.
|
|
14
|
+
* @param {string} [props.label] The header title ("webhook.json") and the code region's accessible name. Without it the header names the language.
|
|
15
|
+
* @param {string} [props.copyLabel="Copy"] The copy button's label.
|
|
16
|
+
* @param {string} [props.copiedLabel="Copied"] The copy button's label for two seconds after a copy.
|
|
17
|
+
* @param {string} [props.className]
|
|
18
|
+
*/
|
|
19
|
+
export default function AppCodeBlock({ code, language, lineNumbers, wrap, label, copyLabel, copiedLabel, className, ...rest }: {
|
|
20
|
+
code: string;
|
|
21
|
+
language?: "text" | "json" | "js" | "cs" | "sql" | "bash" | "http" | "html" | "css";
|
|
22
|
+
lineNumbers?: boolean;
|
|
23
|
+
wrap?: boolean;
|
|
24
|
+
label?: string;
|
|
25
|
+
copyLabel?: string;
|
|
26
|
+
copiedLabel?: string;
|
|
27
|
+
className?: string;
|
|
28
|
+
}): import("react").JSX.Element;
|
|
@@ -12,6 +12,15 @@ import "@webority/ui-elements/elements/command-palette";
|
|
|
12
12
|
* You own the search: `query` is controlled, and `groups` is whatever your search returned
|
|
13
13
|
* for it. The palette does not filter. Selecting a result calls its `onSelect`, then `onClose`.
|
|
14
14
|
*
|
|
15
|
+
* Nested pages are controlled the same way. An item with a `page` opens it instead of acting:
|
|
16
|
+
* the palette calls `onPathChange` with the new path and `onQueryChange("")`, and you pass the
|
|
17
|
+
* groups of the page `path` names. A Back button and a breadcrumb appear while the path is not
|
|
18
|
+
* empty; Backspace in an empty search goes back. Reset `path` yourself when you close the palette.
|
|
19
|
+
*
|
|
20
|
+
* With `recentsKey` the palette remembers what was chosen on this device and lists it first, under
|
|
21
|
+
* "Recent", while the search is empty on the first page. Items are remembered by group key and
|
|
22
|
+
* item key, so keep both stable, and only items present in the root `groups` are listed again.
|
|
23
|
+
*
|
|
15
24
|
* @param {object} props
|
|
16
25
|
* @param {boolean} props.open
|
|
17
26
|
* @param {() => void} props.onClose Called on Escape, a backdrop click, and after a selection.
|
|
@@ -21,13 +30,28 @@ import "@webority/ui-elements/elements/command-palette";
|
|
|
21
30
|
* @param {{ key: string, label: import('react').ReactNode, items: { key: string,
|
|
22
31
|
* label: import('react').ReactNode, description?: import('react').ReactNode,
|
|
23
32
|
* icon?: string | import('react').ReactNode, meta?: import('react').ReactNode,
|
|
24
|
-
* disabled?: boolean, ariaLabel?: string,
|
|
33
|
+
* disabled?: boolean, ariaLabel?: string, shortcut?: string,
|
|
34
|
+
* page?: { key: string, label: string }, onSelect?: () => void }[] }[]} [props.groups=[]]
|
|
25
35
|
* Results, rendered in order under their group headings. Keys must be unique within their
|
|
26
36
|
* group; groups with no items are left out. `icon` is a library icon name or a node; `meta` is
|
|
27
37
|
* short trailing text or a node. A `disabled` item is listed but cannot be chosen: the arrow
|
|
28
38
|
* keys skip it. `ariaLabel` is the option's accessible name, by default a string `label`, so a
|
|
29
39
|
* screen reader reads the name whole rather than in the pieces the search emphasis splits it
|
|
30
40
|
* into; give it for a label passed as a node. The description and meta describe the option.
|
|
41
|
+
* `shortcut` is the key that runs the item elsewhere ("N", "Ctrl K"), drawn as a key chip at
|
|
42
|
+
* the end of the row; it is a hint, your page binds the key. `page` makes the item open a
|
|
43
|
+
* nested page ({ key, label }, the label shows in the breadcrumb) instead of calling `onSelect`.
|
|
44
|
+
* @param {{ key: string, label: string }[]} [props.path=[]] The open nested pages, outermost first
|
|
45
|
+
* (controlled). Empty shows the first page.
|
|
46
|
+
* @param {(path: { key: string, label: string }[]) => void} [props.onPathChange] Called with the
|
|
47
|
+
* new path when the user opens a page, presses Back, picks a breadcrumb entry, or presses
|
|
48
|
+
* Backspace in an empty search. The search is cleared with it.
|
|
49
|
+
* @param {string} [props.rootLabel='All'] Breadcrumb text for the first page.
|
|
50
|
+
* @param {string} [props.backLabel='Back'] Accessible name of the Back button.
|
|
51
|
+
* @param {string} [props.recentsKey] localStorage key to remember chosen items under; omit for no
|
|
52
|
+
* recents. Make it per user, for example from the user's public id.
|
|
53
|
+
* @param {number} [props.recentsLimit=5] How many recent items to keep (at most 20).
|
|
54
|
+
* @param {string} [props.recentsLabel='Recent'] Heading of the recent items.
|
|
31
55
|
* @param {boolean} [props.loading=false] Shows the library spinner in the input.
|
|
32
56
|
* @param {import('react').ReactNode} [props.emptyText='No results'] Shown when the query is
|
|
33
57
|
* not blank, nothing is loading, and no group has items.
|
|
@@ -38,7 +62,7 @@ import "@webority/ui-elements/elements/command-palette";
|
|
|
38
62
|
* @param {string} [props.id] Seeds the result and heading ids; defaults to a generated id.
|
|
39
63
|
* @param {string} [props.className] Extra classes on the dialog card.
|
|
40
64
|
*/
|
|
41
|
-
export default function AppCommandPalette({ open, onClose, query, onQueryChange, placeholder, groups, loading, emptyText, footer, ariaLabel, highlight, id, className, ...rest }: {
|
|
65
|
+
export default function AppCommandPalette({ open, onClose, query, onQueryChange, placeholder, groups, path, onPathChange, rootLabel, backLabel, recentsKey, recentsLimit, recentsLabel, loading, emptyText, footer, ariaLabel, highlight, id, className, ...rest }: {
|
|
42
66
|
open: boolean;
|
|
43
67
|
onClose: () => void;
|
|
44
68
|
query?: string;
|
|
@@ -55,9 +79,27 @@ export default function AppCommandPalette({ open, onClose, query, onQueryChange,
|
|
|
55
79
|
meta?: import('react').ReactNode;
|
|
56
80
|
disabled?: boolean;
|
|
57
81
|
ariaLabel?: string;
|
|
82
|
+
shortcut?: string;
|
|
83
|
+
page?: {
|
|
84
|
+
key: string;
|
|
85
|
+
label: string;
|
|
86
|
+
};
|
|
58
87
|
onSelect?: () => void;
|
|
59
88
|
}[];
|
|
60
89
|
}[];
|
|
90
|
+
path?: {
|
|
91
|
+
key: string;
|
|
92
|
+
label: string;
|
|
93
|
+
}[];
|
|
94
|
+
onPathChange?: (path: {
|
|
95
|
+
key: string;
|
|
96
|
+
label: string;
|
|
97
|
+
}[]) => void;
|
|
98
|
+
rootLabel?: string;
|
|
99
|
+
backLabel?: string;
|
|
100
|
+
recentsKey?: string;
|
|
101
|
+
recentsLimit?: number;
|
|
102
|
+
recentsLabel?: string;
|
|
61
103
|
loading?: boolean;
|
|
62
104
|
emptyText?: import('react').ReactNode;
|
|
63
105
|
footer?: import('react').ReactNode;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
export type CommentThreadItem = {
|
|
2
|
+
/**
|
|
3
|
+
* The comment's public id.
|
|
4
|
+
*/
|
|
5
|
+
id: string;
|
|
6
|
+
/**
|
|
7
|
+
* Who wrote it; `src` is a photo URL.
|
|
8
|
+
*/
|
|
9
|
+
author: {
|
|
10
|
+
name: string;
|
|
11
|
+
src?: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* When it was written: an ISO instant with its zone, epoch ms or a Date. Shown in IST.
|
|
15
|
+
*/
|
|
16
|
+
at: string | number | Date;
|
|
17
|
+
/**
|
|
18
|
+
* The stored body, with mentions as `@[Label](id)`.
|
|
19
|
+
*/
|
|
20
|
+
value?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Shows "Edited" beside the time.
|
|
23
|
+
*/
|
|
24
|
+
edited?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Shows "This comment was deleted." in place of the body; replies stay.
|
|
27
|
+
*/
|
|
28
|
+
deleted?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* This person may edit it.
|
|
31
|
+
*/
|
|
32
|
+
canEdit?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* This person may delete it.
|
|
35
|
+
*/
|
|
36
|
+
canDelete?: boolean;
|
|
37
|
+
reactions?: {
|
|
38
|
+
emoji: string;
|
|
39
|
+
count: number;
|
|
40
|
+
mine?: boolean;
|
|
41
|
+
}[];
|
|
42
|
+
/**
|
|
43
|
+
* Replies, oldest first. Replies to a reply are not nested.
|
|
44
|
+
*/
|
|
45
|
+
replies?: CommentThreadItem[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* A discussion: comments with their author, time in IST, replies one level deep, reactions and
|
|
49
|
+
* mentions. People reply, edit and delete in place (Delete asks first), react from a small panel,
|
|
50
|
+
* and write with "@" to mention someone (see `AppMentionInput`). Ctrl or Cmd+Enter sends a box,
|
|
51
|
+
* Escape closes it and returns focus. Changes are announced to screen readers.
|
|
52
|
+
*
|
|
53
|
+
* The comments are yours: each callback persists a change and the thread waits for it, then you
|
|
54
|
+
* pass the updated `comments` back. Throw (or reject) with a message written for the person and it
|
|
55
|
+
* shows where they acted. Bodies are stored mention values (`Thanks @[Asha Rao](u-12)`) and always
|
|
56
|
+
* render as text, never HTML.
|
|
57
|
+
*
|
|
58
|
+
* Wraps the shared `<wui-comment-thread>` element, which owns the boxes, keys and states; Razor
|
|
59
|
+
* `<app-comment-thread>` renders the same markup.
|
|
60
|
+
*
|
|
61
|
+
* @typedef {object} CommentThreadItem
|
|
62
|
+
* @property {string} id The comment's public id.
|
|
63
|
+
* @property {{ name: string, src?: string }} author Who wrote it; `src` is a photo URL.
|
|
64
|
+
* @property {string | number | Date} at When it was written: an ISO instant with its zone, epoch ms or a Date. Shown in IST.
|
|
65
|
+
* @property {string} [value] The stored body, with mentions as `@[Label](id)`.
|
|
66
|
+
* @property {boolean} [edited] Shows "Edited" beside the time.
|
|
67
|
+
* @property {boolean} [deleted] Shows "This comment was deleted." in place of the body; replies stay.
|
|
68
|
+
* @property {boolean} [canEdit] This person may edit it.
|
|
69
|
+
* @property {boolean} [canDelete] This person may delete it.
|
|
70
|
+
* @property {{ emoji: string, count: number, mine?: boolean }[]} [reactions]
|
|
71
|
+
* @property {CommentThreadItem[]} [replies] Replies, oldest first. Replies to a reply are not nested.
|
|
72
|
+
*
|
|
73
|
+
* @param {object} props
|
|
74
|
+
* @param {CommentThreadItem[]} [props.comments] Top-level comments, oldest first.
|
|
75
|
+
* @param {(body: string) => unknown | Promise<unknown>} [props.onPost] A new comment.
|
|
76
|
+
* @param {(parentId: string, body: string) => unknown | Promise<unknown>} [props.onReply]
|
|
77
|
+
* @param {(commentId: string, body: string) => unknown | Promise<unknown>} [props.onEdit]
|
|
78
|
+
* @param {(commentId: string) => unknown | Promise<unknown>} [props.onDelete]
|
|
79
|
+
* @param {(commentId: string, emoji: string) => unknown | Promise<unknown>} [props.onReact] Toggle
|
|
80
|
+
* this person's reaction.
|
|
81
|
+
* @param {{ value: string, label: string, description?: string, src?: string }[]} [props.people]
|
|
82
|
+
* The people the boxes offer after "@".
|
|
83
|
+
* @param {(query: string) => Promise<{ value: string, label: string, description?: string, src?: string }[]>} [props.loadPeople]
|
|
84
|
+
* Look people up instead of `people`.
|
|
85
|
+
* @param {string[]} [props.reactionChoices] The reactions the panel offers (default 👍 ❤️ 🎉 😄 👀 🙏).
|
|
86
|
+
* @param {boolean} [props.readOnly=false] Show the thread without the box, actions or reacting.
|
|
87
|
+
* @param {string} [props.label="Comments"] The list's accessible name.
|
|
88
|
+
* @param {string} [props.id] The root's id. Generated when omitted.
|
|
89
|
+
* @param {string} [props.className] Extra classes on the root.
|
|
90
|
+
*/
|
|
91
|
+
export default function AppCommentThread({ comments, onPost, onReply, onEdit, onDelete, onReact, people, loadPeople, reactionChoices, readOnly, label, id, className, ...rest }: {
|
|
92
|
+
comments?: CommentThreadItem[];
|
|
93
|
+
onPost?: (body: string) => unknown | Promise<unknown>;
|
|
94
|
+
onReply?: (parentId: string, body: string) => unknown | Promise<unknown>;
|
|
95
|
+
onEdit?: (commentId: string, body: string) => unknown | Promise<unknown>;
|
|
96
|
+
onDelete?: (commentId: string) => unknown | Promise<unknown>;
|
|
97
|
+
onReact?: (commentId: string, emoji: string) => unknown | Promise<unknown>;
|
|
98
|
+
people?: {
|
|
99
|
+
value: string;
|
|
100
|
+
label: string;
|
|
101
|
+
description?: string;
|
|
102
|
+
src?: string;
|
|
103
|
+
}[];
|
|
104
|
+
loadPeople?: (query: string) => Promise<{
|
|
105
|
+
value: string;
|
|
106
|
+
label: string;
|
|
107
|
+
description?: string;
|
|
108
|
+
src?: string;
|
|
109
|
+
}[]>;
|
|
110
|
+
reactionChoices?: string[];
|
|
111
|
+
readOnly?: boolean;
|
|
112
|
+
label?: string;
|
|
113
|
+
id?: string;
|
|
114
|
+
className?: string;
|
|
115
|
+
}): import("react").JSX.Element;
|
|
@@ -48,14 +48,48 @@
|
|
|
48
48
|
* on it, for in-page actions (open a drawer). Same nested-control rule as rowHref.
|
|
49
49
|
* @param {(row: object) => 'success'|'warning'|'danger'|'info'|undefined} [props.rowStatus] A coloured
|
|
50
50
|
* bar on the row's leading edge, e.g. danger for an overdue invoice. Undefined draws none.
|
|
51
|
+
* @param {string|number} [props.activeRowKey] The key (what `rowKey` returns) of the row whose record is
|
|
52
|
+
* open, e.g. in a detail pane beside the table. That row gets `aria-current="true"` and the subtle
|
|
53
|
+
* primary background; it is separate from `rowStatus`'s edge bar and from selected (checkbox) rows.
|
|
54
|
+
* Razor: `active-row-key` against each row's `data-row-key`.
|
|
51
55
|
* @param {boolean} [props.selectable=false] Render a leading checkbox column.
|
|
52
56
|
* @param {Set<string|number>} [props.selectedIds] Currently selected row keys.
|
|
53
57
|
* @param {(id: string|number) => void} [props.onToggleRow]
|
|
54
58
|
* @param {(checked: boolean) => void} [props.onToggleAll] Toggle all current rows.
|
|
59
|
+
* @param {(keys: Array<string|number>, checked: boolean) => void} [props.onSelectRange] Shift+click on a row
|
|
60
|
+
* checkbox selects (or clears) every row from the last clicked one to this one; this receives the keys
|
|
61
|
+
* of the other rows that change. Without it, `onToggleRow` is called once per key, so it must be safe
|
|
62
|
+
* to call several times in a row (a functional state update). Razor: built in.
|
|
55
63
|
* @param {(row: object) => import('react').ReactNode} [props.renderExpanded] When given, each row
|
|
56
64
|
* gets a leading expand toggle; the returned content renders in a full-width row beneath it.
|
|
65
|
+
* @param {boolean} [props.resizableColumns=false] Each column but the last gets a handle on its end edge:
|
|
66
|
+
* drag it, or focus it and press the arrow keys (Shift for bigger steps, Home or a double-click to
|
|
67
|
+
* undo). The table then keeps fixed widths measured from its rows, and the last column takes the rest.
|
|
68
|
+
* Razor: `resizable-columns`.
|
|
69
|
+
* @param {string} [props.viewKey] Remembers resized widths in this browser under this name (the same name
|
|
70
|
+
* `useTableView` takes). Razor: `view-key`, with `data-key` on each header cell.
|
|
71
|
+
* @param {string} [props.groupBy] A column key: rows gather under a header row per value of it, in the
|
|
72
|
+
* order each value first appears (sort within groups by sorting `rows`), each header collapsing its
|
|
73
|
+
* rows and showing their count. Razor: `group-by`, against the header cells' `data-key`.
|
|
74
|
+
* @param {(value: unknown, rows: object[]) => import('react').ReactNode} [props.groupLabel] A group
|
|
75
|
+
* header's label; without it the value shows as a cell would.
|
|
76
|
+
* @param {boolean} [props.virtual=false] Renders only the rows in view (plus a margin) for a long
|
|
77
|
+
* client-side list. Needs `maxHeight`; rows are taken to share one height, so it is not for
|
|
78
|
+
* `renderExpanded` or `stackOnMobile`. Razor: `virtual`.
|
|
79
|
+
* @param {(row: object) => boolean} [props.rowSaving] True while the row's add or change is on its way to
|
|
80
|
+
* the server: the row shows at once, tinted and marked busy, instead of waiting for the answer. Put an
|
|
81
|
+
* added row in `rows` straight away with this true (give it its final key if you can, so the outcome is
|
|
82
|
+
* announced). Razor: `data-wui-save-state="saving"` on the <tr>, or a server table's `saveRow`.
|
|
83
|
+
* @param {(row: object) => string|undefined} [props.rowSaveError] Why the row's last save failed: the row
|
|
84
|
+
* shows the error look with this line under its first cell. Put a changed row's old values back in `rows`
|
|
85
|
+
* as you set it, so the row shows what is really saved; keep a failed added row until the person retries
|
|
86
|
+
* or removes it. When a row leaves `rowSaving`, screen readers hear "Ana Rao saved." or "Ana Rao was not
|
|
87
|
+
* saved. <reason>" (the name is the first column's value). Razor: `data-wui-save-state="error"`.
|
|
88
|
+
*
|
|
89
|
+
* A sort or reorder of up to 200 rows glides each row to its new place; not under reduced motion, and not
|
|
90
|
+
* on a `virtual` table.
|
|
57
91
|
*/
|
|
58
|
-
export default function AppDataTable({ columns, rows, rowKey, sort, onSort, loading, skeletonRows, empty, emptyFiltered, sourceCount, rowActions, rowActionsLabel, pagination, ariaLabel, className, wrapperClassName, selectable, selectedIds, onToggleRow, onToggleAll, renderExpanded, density, striped, maxHeight, stickyFirstColumn, stickyActions, stackOnMobile, hiddenColumns, rowStatus, rowHref, onRowClick, ...rest }: {
|
|
92
|
+
export default function AppDataTable({ columns, rows, rowKey, sort, onSort, loading, skeletonRows, empty, emptyFiltered, sourceCount, rowActions, rowActionsLabel, pagination, ariaLabel, className, wrapperClassName, selectable, selectedIds, onToggleRow, onToggleAll, onSelectRange, renderExpanded, density, striped, maxHeight, stickyFirstColumn, stickyActions, stackOnMobile, hiddenColumns, rowStatus, rowHref, onRowClick, activeRowKey, resizableColumns, viewKey, groupBy, groupLabel, virtual, rowSaving, rowSaveError, ...rest }: {
|
|
59
93
|
columns: object[];
|
|
60
94
|
rows: object[];
|
|
61
95
|
rowKey?: (row: object, index: number) => string | number;
|
|
@@ -85,9 +119,18 @@ export default function AppDataTable({ columns, rows, rowKey, sort, onSort, load
|
|
|
85
119
|
rowHref?: (row: object) => string;
|
|
86
120
|
onRowClick?: (row: object) => void;
|
|
87
121
|
rowStatus?: (row: object) => 'success' | 'warning' | 'danger' | 'info' | undefined;
|
|
122
|
+
activeRowKey?: string | number;
|
|
88
123
|
selectable?: boolean;
|
|
89
124
|
selectedIds?: Set<string | number>;
|
|
90
125
|
onToggleRow?: (id: string | number) => void;
|
|
91
126
|
onToggleAll?: (checked: boolean) => void;
|
|
127
|
+
onSelectRange?: (keys: Array<string | number>, checked: boolean) => void;
|
|
92
128
|
renderExpanded?: (row: object) => import('react').ReactNode;
|
|
129
|
+
resizableColumns?: boolean;
|
|
130
|
+
viewKey?: string;
|
|
131
|
+
groupBy?: string;
|
|
132
|
+
groupLabel?: (value: unknown, rows: object[]) => import('react').ReactNode;
|
|
133
|
+
virtual?: boolean;
|
|
134
|
+
rowSaving?: (row: object) => boolean;
|
|
135
|
+
rowSaveError?: (row: object) => string | undefined;
|
|
93
136
|
}): import("react").JSX.Element;
|
|
@@ -25,6 +25,11 @@ import "@webority/ui-elements/elements/date-range";
|
|
|
25
25
|
* @param {'sm'|'md'|'lg'} [props.size] Control height tier, matching AppInput.
|
|
26
26
|
* @param {0|1|2|3|4|5|6} [props.firstDay] First weekday of the calendar, 0 Sunday to 6 Saturday. Unset, it
|
|
27
27
|
* follows the theme's `--wui-first-day` token, which is 1 (Monday) unless the product sets it.
|
|
28
|
+
* @param {(('today'|'last7Days'|'thisMonth'|'lastMonth'|'thisFinancialYear')|{ label: string, start: string, end: string })[]} [props.presets]
|
|
29
|
+
* Quick ranges, listed beside the calendar (above it on a phone); picking one fills the range and
|
|
30
|
+
* closes the calendar. An item is a name, resolved against today in IST (`thisFinancialYear` runs
|
|
31
|
+
* 1 April to 31 March; `thisMonth` and `lastMonth` span the whole month), or `{ label, start, end }`
|
|
32
|
+
* with ISO dates. A preset outside `min`/`max` is disabled.
|
|
28
33
|
* @param {string} [props.id]
|
|
29
34
|
* @param {string} [props.ariaLabel]
|
|
30
35
|
* @param {string} [props.className] Class to apply to the control element.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import "@webority/ui-elements/elements/drawer";
|
|
2
|
+
/**
|
|
3
|
+
* A panel over the page that is a side drawer from md up and a bottom sheet below it. The sheet
|
|
4
|
+
* rests on `snapPoints` (percent of the screen height), follows a finger on its handle or header,
|
|
5
|
+
* flicks to the next point and is dragged down to close; its handle is a vertical slider the arrow
|
|
6
|
+
* keys, Home and End also move. Focus moves in on open, Tab stays inside, Escape closes, and
|
|
7
|
+
* focus returns to what opened it. Controlled: set `open` and close it in `onClose`. Distinct from
|
|
8
|
+
* `AppModal`, which is a centred dialog on every screen. Wraps `<wui-drawer>`, which Razor
|
|
9
|
+
* `<app-drawer>` renders too. Place it where no ancestor has a transform, since it is fixed to the
|
|
10
|
+
* viewport.
|
|
11
|
+
*
|
|
12
|
+
* @param {object} props
|
|
13
|
+
* @param {boolean} [props.open=false]
|
|
14
|
+
* @param {() => void} [props.onClose] Called when the backdrop, Escape, the close button or a drag
|
|
15
|
+
* down asks to close it. It stays open until `open` becomes false.
|
|
16
|
+
* @param {string} [props.title] The heading, and the dialog's accessible name.
|
|
17
|
+
* @param {string} [props.subtitle] A line under the title.
|
|
18
|
+
* @param {string} [props.ariaLabel] The dialog's accessible name when there is no `title`.
|
|
19
|
+
* @param {'end'|'start'} [props.side="end"] Which edge the side drawer slides from.
|
|
20
|
+
* @param {'sm'|'md'|'lg'} [props.size="md"] The side drawer's width: 360, 480 or 640 px.
|
|
21
|
+
* @param {number[]} [props.snapPoints=[50, 90]] The sheet's resting heights, each 10 to 100 percent of the screen.
|
|
22
|
+
* @param {number} [props.defaultSnap=0] Which of the sorted snap points it opens on.
|
|
23
|
+
* @param {(index: number, percent: number) => void} [props.onSnapChange] Called when the sheet moves to another point.
|
|
24
|
+
* @param {boolean} [props.dismissible=true] Show the close button.
|
|
25
|
+
* @param {boolean} [props.staticBackdrop=false] The backdrop, Escape and a drag down no longer close it; only the close button or `open` can.
|
|
26
|
+
* @param {import('react').ReactNode} [props.footer] Pinned below the scrolling body.
|
|
27
|
+
* @param {string} [props.className]
|
|
28
|
+
* @param {import('react').ReactNode} props.children
|
|
29
|
+
*/
|
|
30
|
+
export default function AppDrawer({ open, onClose, title, subtitle, ariaLabel, side, size, snapPoints, defaultSnap, onSnapChange, dismissible, staticBackdrop, footer, className, children, ...rest }: {
|
|
31
|
+
open?: boolean;
|
|
32
|
+
onClose?: () => void;
|
|
33
|
+
title?: string;
|
|
34
|
+
subtitle?: string;
|
|
35
|
+
ariaLabel?: string;
|
|
36
|
+
side?: 'end' | 'start';
|
|
37
|
+
size?: 'sm' | 'md' | 'lg';
|
|
38
|
+
snapPoints?: number[];
|
|
39
|
+
defaultSnap?: number;
|
|
40
|
+
onSnapChange?: (index: number, percent: number) => void;
|
|
41
|
+
dismissible?: boolean;
|
|
42
|
+
staticBackdrop?: boolean;
|
|
43
|
+
footer?: import('react').ReactNode;
|
|
44
|
+
className?: string;
|
|
45
|
+
children: import('react').ReactNode;
|
|
46
|
+
}): import("react").JSX.Element;
|
|
@@ -15,8 +15,10 @@
|
|
|
15
15
|
* @param {string} [props.label] Tooltip + accessible-name fallback for the toggle.
|
|
16
16
|
* @param {"start"|"end"} [props.align="end"] Menu alignment.
|
|
17
17
|
* @param {string} [props.ariaLabel]
|
|
18
|
-
* @param {{ key: string, label?: string, icon?: string|import('react').ReactNode, image?: string, to?: string, onClick?: () => void, danger?: boolean, divider?: true }[]} [props.items]
|
|
18
|
+
* @param {{ key: string, label?: string, icon?: string|import('react').ReactNode, image?: string, to?: string, onClick?: () => void, danger?: boolean, shortcut?: string, divider?: true }[]} [props.items]
|
|
19
19
|
* `icon` is a glyph name OR a custom node (e.g. an iconsax glyph); `image` is a picture URL (external logo/avatar) — pass one.
|
|
20
|
+
* `shortcut` is the key that runs the item ("E"), drawn as a key chip at the end of the row; the
|
|
21
|
+
* page binds the key itself (useListShortcuts).
|
|
20
22
|
* An item with `divider: true` renders a separator instead of an action; it needs no
|
|
21
23
|
* `label`/`onClick`, just a unique `key`.
|
|
22
24
|
* @param {string} [props.menuClassName]
|
|
@@ -53,6 +55,7 @@ export default function AppDropdown({ icon, iconSize, toggleClassName, label, ar
|
|
|
53
55
|
to?: string;
|
|
54
56
|
onClick?: () => void;
|
|
55
57
|
danger?: boolean;
|
|
58
|
+
shortcut?: string;
|
|
56
59
|
divider?: true;
|
|
57
60
|
}[];
|
|
58
61
|
menuClassName?: string;
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @param {object} props
|
|
13
13
|
* @param {string|import('react').ReactNode} props.icon Semantic icon name for the bubble, or a custom node
|
|
14
|
+
* @param {"no-results"|"no-data"|"empty-inbox"|"no-notifications"|"no-files"|"no-access"|"offline"|"error"} [props.illustration]
|
|
15
|
+
* Decorative drawing by name, in theme colours. Replaces the icon bubble when set.
|
|
14
16
|
* @param {number} [props.iconSize=24]
|
|
15
17
|
* @param {"md"|"sm"} [props.size="md"]
|
|
16
18
|
* @param {import('react').ReactNode} props.title
|
|
@@ -19,8 +21,9 @@
|
|
|
19
21
|
* @param {string} [props.className]
|
|
20
22
|
* @param {import('react').CSSProperties} [props.style]
|
|
21
23
|
*/
|
|
22
|
-
export default function AppEmptyState({ icon, iconSize, size, title, text, action, className, style, ...rest }: {
|
|
24
|
+
export default function AppEmptyState({ icon, illustration, iconSize, size, title, text, action, className, style, ...rest }: {
|
|
23
25
|
icon: string | import('react').ReactNode;
|
|
26
|
+
illustration?: "no-results" | "no-data" | "empty-inbox" | "no-notifications" | "no-files" | "no-access" | "offline" | "error";
|
|
24
27
|
iconSize?: number;
|
|
25
28
|
size?: "md" | "sm";
|
|
26
29
|
title: import('react').ReactNode;
|
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
* and clears itself. The controls, chips and Clear all share one row, the search box wider and
|
|
11
11
|
* selects and date ranges narrow; it wraps only when full, and each facet takes its own line on a phone.
|
|
12
12
|
*
|
|
13
|
+
* Only the first `inline` facets sit in the row. The rest go in a panel behind a "Filters (n)" button,
|
|
14
|
+
* n counting the active ones among them (no number while none is active); their chips stay in the row.
|
|
15
|
+
* The panel is a `<details>` that closes on an outside click or Escape. On a phone every facet folds
|
|
16
|
+
* into that one button and the panel becomes a sheet from the bottom edge. The button and Clear all
|
|
17
|
+
* never wrap.
|
|
18
|
+
*
|
|
13
19
|
* @param {object} props
|
|
14
20
|
* @param {{ key: string, label: string, type: 'enum'|'multiEnum'|'dateRange'|'text',
|
|
15
21
|
* options?: { value: string, label: string }[] }[]} props.facets `options` fills an `enum` or `multiEnum`;
|
|
@@ -17,9 +23,10 @@
|
|
|
17
23
|
* @param {Record<string, string|string[]|{ from: string, to: string }>} props.value The current filters.
|
|
18
24
|
* @param {(key: string, value: string|string[]|{ from: string, to: string }) => void} props.onChange
|
|
19
25
|
* Called with the facet key and its new value. Clear all calls it once per active facet, with the empty value.
|
|
26
|
+
* @param {number} [props.inline=3] How many facets stay in the row; the rest fold into the Filters button.
|
|
20
27
|
* @param {string} [props.className]
|
|
21
28
|
*/
|
|
22
|
-
export default function AppFilterBar({ facets: allFacets, value, onChange, className, ...rest }: {
|
|
29
|
+
export default function AppFilterBar({ facets: allFacets, value, onChange, inline, className, ...rest }: {
|
|
23
30
|
facets: {
|
|
24
31
|
key: string;
|
|
25
32
|
label: string;
|
|
@@ -37,5 +44,6 @@ export default function AppFilterBar({ facets: allFacets, value, onChange, class
|
|
|
37
44
|
from: string;
|
|
38
45
|
to: string;
|
|
39
46
|
}) => void;
|
|
47
|
+
inline?: number;
|
|
40
48
|
className?: string;
|
|
41
49
|
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import "@webority/ui-elements/elements/hover-card";
|
|
2
|
+
/**
|
|
3
|
+
* A small preview card that opens beside a name or record link: who someone is, a record's status,
|
|
4
|
+
* without opening the record. It opens after `openDelay` ms of mouse hover or when the trigger takes
|
|
5
|
+
* keyboard focus, and closes `closeDelay` ms after the pointer or focus leaves the trigger and the
|
|
6
|
+
* card (the pointer can cross into the card to read or click inside it). Escape closes it. Touch
|
|
7
|
+
* never opens it, so the trigger must itself lead to the same information (a link to the record).
|
|
8
|
+
* Distinct from `AppPopover` (opened by a click, for a panel of actions) and `AppTooltip` (one line of
|
|
9
|
+
* text, no interactive content). Wraps `<wui-hover-card>`, which Razor `<app-hover-card>` renders too.
|
|
10
|
+
*
|
|
11
|
+
* @param {object} props
|
|
12
|
+
* @param {import('react').ReactNode} props.trigger The name or link the card belongs to. Make it a link
|
|
13
|
+
* or button so keyboard users can focus it.
|
|
14
|
+
* @param {import('react').ReactNode} [props.children] The card's content. The card is phrasing content, so it can
|
|
15
|
+
* sit on a name inside a sentence; there, build the content from spans (a `<div>` cannot be inside a `<p>`).
|
|
16
|
+
* @param {boolean} [props.loading=false] Shows a spinner and `loadingLabel` in place of the children while
|
|
17
|
+
* the preview is fetched; open the fetch from `onOpenChange`.
|
|
18
|
+
* @param {string} [props.loadingLabel="Loading"] The text beside the spinner.
|
|
19
|
+
* @param {string} [props.label] The card's accessible name ("Asha Verma, profile").
|
|
20
|
+
* @param {number} [props.openDelay=300] Milliseconds of hover or focus before it opens.
|
|
21
|
+
* @param {number} [props.closeDelay=150] Milliseconds after leaving before it closes.
|
|
22
|
+
* @param {(open: boolean) => void} [props.onOpenChange] Called when the card opens or closes.
|
|
23
|
+
* @param {string} [props.className]
|
|
24
|
+
*/
|
|
25
|
+
export default function AppHoverCard({ trigger, children, loading, loadingLabel, label, openDelay, closeDelay, onOpenChange, className, ...rest }: {
|
|
26
|
+
trigger: import('react').ReactNode;
|
|
27
|
+
children?: import('react').ReactNode;
|
|
28
|
+
loading?: boolean;
|
|
29
|
+
loadingLabel?: string;
|
|
30
|
+
label?: string;
|
|
31
|
+
openDelay?: number;
|
|
32
|
+
closeDelay?: number;
|
|
33
|
+
onOpenChange?: (open: boolean) => void;
|
|
34
|
+
className?: string;
|
|
35
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import "@webority/ui-elements/elements/datepicker";
|
|
2
|
+
import "@webority/ui-elements/elements/select";
|
|
3
|
+
/**
|
|
4
|
+
* One value edited where it is shown: a table cell or a fact on a detail page. It reads as plain
|
|
5
|
+
* text with a pencil on hover and focus; a click or Enter turns it into the matching library control
|
|
6
|
+
* (a text or number input, a textarea, a select or a date picker, whose list opens at once).
|
|
7
|
+
*
|
|
8
|
+
* Enter saves a text or number, Ctrl or Cmd+Enter a textarea, picking saves a select or date, and
|
|
9
|
+
* leaving the control saves whatever it holds; Escape cancels. An unchanged value closes without
|
|
10
|
+
* saving. While `onSave` runs the new value shows with a spinner, then a tick for two seconds; a
|
|
11
|
+
* rejection puts the old value back and shows the rejection's message under it (so write it for the
|
|
12
|
+
* person editing), and the next edit starts from the value that failed. Saved and failed are
|
|
13
|
+
* announced to screen readers.
|
|
14
|
+
*
|
|
15
|
+
* Inside an `AppDataTable` row that opens on click or Enter, clicks and keys on the value never
|
|
16
|
+
* reach the row.
|
|
17
|
+
*
|
|
18
|
+
* Wraps the shared `<wui-inline-edit>` element, which owns the editing, the keys and the states;
|
|
19
|
+
* the Razor `<app-inline-edit>` renders the same markup.
|
|
20
|
+
*
|
|
21
|
+
* @param {object} props
|
|
22
|
+
* @param {string | number | null} [props.value] The saved value. A date is `yyyy-MM-dd`; a select
|
|
23
|
+
* value is one of the `options` values.
|
|
24
|
+
* @param {(next: string | number | null) => void | Promise<unknown>} [props.onSave] Persist the new
|
|
25
|
+
* value. A number field passes a number (null when cleared); the others pass a string. Reject to
|
|
26
|
+
* refuse it: the rejection's message is shown.
|
|
27
|
+
* @param {'text'|'number'|'select'|'date'|'textarea'} [props.type='text'] The control it turns into.
|
|
28
|
+
* @param {{ value: string | number, label: string }[]} [props.options] The choices of a select.
|
|
29
|
+
* @param {string} props.label What the value is ("Owner"): the accessible name of the value and
|
|
30
|
+
* the control, and the subject of what screen readers hear ("Owner saved.").
|
|
31
|
+
* @param {string} [props.placeholder] Shown, muted, when there is no value, and in the empty
|
|
32
|
+
* control. Without it an empty value shows a hyphen.
|
|
33
|
+
* @param {(next: string | number | null) => string | null | undefined} [props.validate] Checked
|
|
34
|
+
* before saving: return a message to keep the control open with that message, or nothing to save.
|
|
35
|
+
* @param {(value: string | number | null) => import('react').ReactNode} [props.renderValue] How a
|
|
36
|
+
* saved, non-empty value reads (a formatted amount, a status badge). Text and markup only: the
|
|
37
|
+
* value is a button, so it must not hold its own controls or links.
|
|
38
|
+
* @param {boolean} [props.disabled=false] Show the value without the edit affordance.
|
|
39
|
+
* @param {string} [props.className] Extra classes on the root element.
|
|
40
|
+
* @param {string} [props.id] The root's id; the control and error ids derive from it. Generated when omitted.
|
|
41
|
+
*/
|
|
42
|
+
export default function AppInlineEdit({ value, onSave, type, options, label, placeholder, validate, renderValue, disabled, className, id, ...rest }: {
|
|
43
|
+
value?: string | number | null;
|
|
44
|
+
onSave?: (next: string | number | null) => void | Promise<unknown>;
|
|
45
|
+
type?: 'text' | 'number' | 'select' | 'date' | 'textarea';
|
|
46
|
+
options?: {
|
|
47
|
+
value: string | number;
|
|
48
|
+
label: string;
|
|
49
|
+
}[];
|
|
50
|
+
label: string;
|
|
51
|
+
placeholder?: string;
|
|
52
|
+
validate?: (next: string | number | null) => string | null | undefined;
|
|
53
|
+
renderValue?: (value: string | number | null) => import('react').ReactNode;
|
|
54
|
+
disabled?: boolean;
|
|
55
|
+
className?: string;
|
|
56
|
+
id?: string;
|
|
57
|
+
}): import("react").JSX.Element;
|