@kennycorrea/ui 0.11.3 → 1.6.1
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/CHANGELOG.md +189 -0
- package/README.md +251 -1
- package/dist/atoms/ActionMenu/ActionMenu.d.ts +37 -0
- package/dist/atoms/ActionMenu/ActionMenu.js +28 -0
- package/dist/atoms/ActionMenu/index.d.ts +1 -0
- package/dist/atoms/ActionMenu/index.js +1 -0
- package/dist/atoms/ActionSheet/ActionSheet.d.ts +10 -4
- package/dist/atoms/ActionSheet/ActionSheet.js +6 -15
- package/dist/atoms/ActionSheet/confirm.d.ts +1 -1
- package/dist/atoms/ActionSheet/confirm.js +1 -1
- package/dist/atoms/Avatar/Avatar.d.ts +1 -1
- package/dist/atoms/Badge/Badge.js +4 -4
- package/dist/atoms/Button/Button.js +2 -3
- package/dist/atoms/Button/Button.types.d.ts +5 -8
- package/dist/atoms/Card/Card.d.ts +5 -3
- package/dist/atoms/Card/Card.js +21 -4
- package/dist/atoms/ContextMenu/ContextMenu.d.ts +1 -1
- package/dist/atoms/ContextMenu/ContextMenu.js +1 -1
- package/dist/atoms/Drawer/Drawer.js +1 -1
- package/dist/atoms/Icon/Icon.d.ts +7 -9
- package/dist/atoms/Icon/Icon.js +23 -8
- package/dist/atoms/Pill/Pill.d.ts +17 -0
- package/dist/atoms/Pill/Pill.js +12 -0
- package/dist/atoms/Pill/index.d.ts +1 -0
- package/dist/atoms/Pill/index.js +1 -0
- package/dist/atoms/ResponsiveDialog/ResponsiveDialog.d.ts +9 -2
- package/dist/atoms/ResponsiveDialog/ResponsiveDialog.js +6 -15
- package/dist/atoms/Sheet/Sheet.js +1 -1
- package/dist/atoms/StatusIndicator/StatusIndicator.d.ts +14 -0
- package/dist/atoms/StatusIndicator/StatusIndicator.js +8 -0
- package/dist/atoms/StatusIndicator/index.d.ts +1 -0
- package/dist/atoms/StatusIndicator/index.js +1 -0
- package/dist/atoms/TextLink/TextLink.d.ts +36 -0
- package/dist/atoms/TextLink/TextLink.js +17 -0
- package/dist/atoms/TextLink/index.d.ts +1 -0
- package/dist/atoms/TextLink/index.js +1 -0
- package/dist/atoms/Toast/Toast.d.ts +1 -1
- package/dist/atoms/Toast/Toast.js +1 -1
- package/dist/atoms/index.d.ts +4 -0
- package/dist/atoms/index.js +4 -0
- package/dist/hooks/breakpoints.d.ts +20 -0
- package/dist/hooks/breakpoints.js +13 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/useControllableState.d.ts +17 -0
- package/dist/hooks/useControllableState.js +22 -0
- package/dist/hooks/useElementWidth.d.ts +7 -0
- package/dist/hooks/useElementWidth.js +22 -0
- package/dist/hooks/useMediaQuery.d.ts +18 -0
- package/dist/hooks/useMediaQuery.js +51 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/molecules/AccentPicker/AccentPicker.d.ts +30 -0
- package/dist/molecules/AccentPicker/AccentPicker.js +27 -0
- package/dist/molecules/AccentPicker/index.d.ts +1 -0
- package/dist/molecules/AccentPicker/index.js +1 -0
- package/dist/molecules/Breadcrumbs/Breadcrumbs.d.ts +27 -0
- package/dist/molecules/Breadcrumbs/Breadcrumbs.js +40 -0
- package/dist/molecules/Breadcrumbs/index.d.ts +1 -0
- package/dist/molecules/Breadcrumbs/index.js +1 -0
- package/dist/molecules/Calendar/Calendar.d.ts +42 -0
- package/dist/molecules/Calendar/Calendar.js +111 -0
- package/dist/molecules/Calendar/index.d.ts +1 -0
- package/dist/molecules/Calendar/index.js +1 -0
- package/dist/molecules/DateInput/DateInput.d.ts +35 -0
- package/dist/molecules/DateInput/DateInput.js +41 -0
- package/dist/molecules/DateInput/index.d.ts +1 -0
- package/dist/molecules/DateInput/index.js +1 -0
- package/dist/molecules/EmptyState/EmptyState.d.ts +19 -0
- package/dist/molecules/EmptyState/EmptyState.js +7 -0
- package/dist/molecules/EmptyState/index.d.ts +1 -0
- package/dist/molecules/EmptyState/index.js +1 -0
- package/dist/molecules/ErrorState/ErrorState.d.ts +18 -0
- package/dist/molecules/ErrorState/ErrorState.js +12 -0
- package/dist/molecules/ErrorState/index.d.ts +1 -0
- package/dist/molecules/ErrorState/index.js +1 -0
- package/dist/molecules/ErrorSummary/ErrorSummary.d.ts +25 -0
- package/dist/molecules/ErrorSummary/ErrorSummary.js +32 -0
- package/dist/molecules/ErrorSummary/index.d.ts +1 -0
- package/dist/molecules/ErrorSummary/index.js +1 -0
- package/dist/molecules/FilterChips/FilterChips.d.ts +10 -0
- package/dist/molecules/FilterChips/FilterChips.js +13 -0
- package/dist/molecules/FilterChips/index.d.ts +1 -0
- package/dist/molecules/FilterChips/index.js +1 -0
- package/dist/molecules/FilterPopover/FilterPopover.d.ts +27 -0
- package/dist/molecules/FilterPopover/FilterPopover.js +32 -0
- package/dist/molecules/FilterPopover/index.d.ts +1 -0
- package/dist/molecules/FilterPopover/index.js +1 -0
- package/dist/molecules/FormActions/FormActions.d.ts +16 -0
- package/dist/molecules/FormActions/FormActions.js +5 -0
- package/dist/molecules/FormActions/index.d.ts +1 -0
- package/dist/molecules/FormActions/index.js +1 -0
- package/dist/molecules/FormField/FormField.d.ts +52 -0
- package/dist/molecules/FormField/FormField.js +63 -0
- package/dist/molecules/FormField/index.d.ts +1 -0
- package/dist/molecules/FormField/index.js +1 -0
- package/dist/molecules/FormSection/FormSection.d.ts +14 -0
- package/dist/molecules/FormSection/FormSection.js +10 -0
- package/dist/molecules/FormSection/index.d.ts +1 -0
- package/dist/molecules/FormSection/index.js +1 -0
- package/dist/molecules/KeyValueList/KeyValueList.d.ts +22 -0
- package/dist/molecules/KeyValueList/KeyValueList.js +9 -0
- package/dist/molecules/KeyValueList/index.d.ts +1 -0
- package/dist/molecules/KeyValueList/index.js +1 -0
- package/dist/molecules/LoadingState/LoadingState.d.ts +20 -0
- package/dist/molecules/LoadingState/LoadingState.js +22 -0
- package/dist/molecules/LoadingState/index.d.ts +1 -0
- package/dist/molecules/LoadingState/index.js +1 -0
- package/dist/molecules/NavItem/NavItem.d.ts +31 -0
- package/dist/molecules/NavItem/NavItem.js +72 -0
- package/dist/molecules/NavItem/context.d.ts +14 -0
- package/dist/molecules/NavItem/context.js +5 -0
- package/dist/molecules/NavItem/index.d.ts +1 -0
- package/dist/molecules/NavItem/index.js +1 -0
- package/dist/molecules/Pagination/Pagination.d.ts +32 -0
- package/dist/molecules/Pagination/Pagination.js +57 -0
- package/dist/molecules/Pagination/index.d.ts +1 -0
- package/dist/molecules/Pagination/index.js +1 -0
- package/dist/molecules/PasswordInput/PasswordInput.d.ts +14 -0
- package/dist/molecules/PasswordInput/PasswordInput.js +16 -0
- package/dist/molecules/PasswordInput/index.d.ts +1 -0
- package/dist/molecules/PasswordInput/index.js +1 -0
- package/dist/molecules/SearchField/SearchField.d.ts +24 -0
- package/dist/molecules/SearchField/SearchField.js +58 -0
- package/dist/molecules/SearchField/index.d.ts +1 -0
- package/dist/molecules/SearchField/index.js +1 -0
- package/dist/molecules/StatGroup/StatGroup.d.ts +21 -0
- package/dist/molecules/StatGroup/StatGroup.js +10 -0
- package/dist/molecules/StatGroup/index.d.ts +1 -0
- package/dist/molecules/StatGroup/index.js +1 -0
- package/dist/molecules/ThemeToggle/ThemeToggle.d.ts +23 -0
- package/dist/molecules/ThemeToggle/ThemeToggle.js +26 -0
- package/dist/molecules/ThemeToggle/index.d.ts +1 -0
- package/dist/molecules/ThemeToggle/index.js +1 -0
- package/dist/molecules/UserMenu/UserMenu.d.ts +20 -0
- package/dist/molecules/UserMenu/UserMenu.js +14 -0
- package/dist/molecules/UserMenu/index.d.ts +1 -0
- package/dist/molecules/UserMenu/index.js +1 -0
- package/dist/molecules/index.d.ts +21 -0
- package/dist/molecules/index.js +21 -0
- package/dist/organisms/AppShell/AppShell.d.ts +29 -0
- package/dist/organisms/AppShell/AppShell.js +34 -0
- package/dist/organisms/AppShell/context.d.ts +14 -0
- package/dist/organisms/AppShell/context.js +6 -0
- package/dist/organisms/AppShell/index.d.ts +1 -0
- package/dist/organisms/AppShell/index.js +1 -0
- package/dist/organisms/AuthForms/AuthForms.d.ts +83 -0
- package/dist/organisms/AuthForms/AuthForms.js +57 -0
- package/dist/organisms/AuthForms/index.d.ts +2 -0
- package/dist/organisms/AuthForms/index.js +1 -0
- package/dist/organisms/AuthForms/shared.d.ts +36 -0
- package/dist/organisms/AuthForms/shared.js +36 -0
- package/dist/organisms/BulkActionBar/BulkActionBar.d.ts +25 -0
- package/dist/organisms/BulkActionBar/BulkActionBar.js +18 -0
- package/dist/organisms/BulkActionBar/index.d.ts +1 -0
- package/dist/organisms/BulkActionBar/index.js +1 -0
- package/dist/organisms/Chart/CategoryCharts.d.ts +34 -0
- package/dist/organisms/Chart/CategoryCharts.js +93 -0
- package/dist/organisms/Chart/ChartFrame.d.ts +26 -0
- package/dist/organisms/Chart/ChartFrame.js +18 -0
- package/dist/organisms/Chart/DonutChart.d.ts +25 -0
- package/dist/organisms/Chart/DonutChart.js +53 -0
- package/dist/organisms/Chart/Sparkline.d.ts +15 -0
- package/dist/organisms/Chart/Sparkline.js +18 -0
- package/dist/organisms/Chart/index.d.ts +5 -0
- package/dist/organisms/Chart/index.js +5 -0
- package/dist/organisms/Chart/shared.d.ts +51 -0
- package/dist/organisms/Chart/shared.js +113 -0
- package/dist/organisms/DataTable/DataTable.d.ts +63 -0
- package/dist/organisms/DataTable/DataTable.js +119 -0
- package/dist/organisms/DataTable/index.d.ts +3 -0
- package/dist/organisms/DataTable/index.js +3 -0
- package/dist/organisms/DataTable/types.d.ts +39 -0
- package/dist/organisms/DataTable/types.js +1 -0
- package/dist/organisms/DataTable/useClientTable.d.ts +27 -0
- package/dist/organisms/DataTable/useClientTable.js +51 -0
- package/dist/organisms/DateRangePicker/DateRangePicker.d.ts +43 -0
- package/dist/organisms/DateRangePicker/DateRangePicker.js +54 -0
- package/dist/organisms/DateRangePicker/index.d.ts +1 -0
- package/dist/organisms/DateRangePicker/index.js +1 -0
- package/dist/organisms/FilterBar/FilterBar.d.ts +28 -0
- package/dist/organisms/FilterBar/FilterBar.js +16 -0
- package/dist/organisms/FilterBar/index.d.ts +1 -0
- package/dist/organisms/FilterBar/index.js +1 -0
- package/dist/organisms/PageHeader/PageHeader.d.ts +31 -0
- package/dist/organisms/PageHeader/PageHeader.js +19 -0
- package/dist/organisms/PageHeader/index.d.ts +1 -0
- package/dist/organisms/PageHeader/index.js +1 -0
- package/dist/organisms/PageTabs/PageTabs.d.ts +27 -0
- package/dist/organisms/PageTabs/PageTabs.js +31 -0
- package/dist/organisms/PageTabs/index.d.ts +1 -0
- package/dist/organisms/PageTabs/index.js +1 -0
- package/dist/organisms/Sidebar/Sidebar.d.ts +48 -0
- package/dist/organisms/Sidebar/Sidebar.js +61 -0
- package/dist/organisms/Sidebar/index.d.ts +1 -0
- package/dist/organisms/Sidebar/index.js +1 -0
- package/dist/organisms/Topbar/Topbar.d.ts +24 -0
- package/dist/organisms/Topbar/Topbar.js +18 -0
- package/dist/organisms/Topbar/index.d.ts +1 -0
- package/dist/organisms/Topbar/index.js +1 -0
- package/dist/organisms/index.d.ts +11 -0
- package/dist/organisms/index.js +11 -0
- package/dist/strings.d.ts +108 -15
- package/dist/strings.js +73 -7
- package/dist/templates/AdminLayout/AdminLayout.d.ts +14 -0
- package/dist/templates/AdminLayout/AdminLayout.js +9 -0
- package/dist/templates/AdminLayout/index.d.ts +1 -0
- package/dist/templates/AdminLayout/index.js +1 -0
- package/dist/templates/AuthLayout/AuthLayout.d.ts +28 -0
- package/dist/templates/AuthLayout/AuthLayout.js +11 -0
- package/dist/templates/AuthLayout/index.d.ts +1 -0
- package/dist/templates/AuthLayout/index.js +1 -0
- package/dist/templates/DashboardPage/DashboardPage.d.ts +25 -0
- package/dist/templates/DashboardPage/DashboardPage.js +12 -0
- package/dist/templates/DashboardPage/index.d.ts +1 -0
- package/dist/templates/DashboardPage/index.js +1 -0
- package/dist/templates/DetailPage/DetailPage.d.ts +20 -0
- package/dist/templates/DetailPage/DetailPage.js +11 -0
- package/dist/templates/DetailPage/index.d.ts +1 -0
- package/dist/templates/DetailPage/index.js +1 -0
- package/dist/templates/FormPage/FormPage.d.ts +26 -0
- package/dist/templates/FormPage/FormPage.js +11 -0
- package/dist/templates/FormPage/index.d.ts +1 -0
- package/dist/templates/FormPage/index.js +1 -0
- package/dist/templates/ListPage/ListPage.d.ts +17 -0
- package/dist/templates/ListPage/ListPage.js +8 -0
- package/dist/templates/ListPage/index.d.ts +1 -0
- package/dist/templates/ListPage/index.js +1 -0
- package/dist/templates/SettingsPage/SettingsPage.d.ts +32 -0
- package/dist/templates/SettingsPage/SettingsPage.js +13 -0
- package/dist/templates/SettingsPage/index.d.ts +1 -0
- package/dist/templates/SettingsPage/index.js +1 -0
- package/dist/templates/StatusPage/StatusPage.d.ts +18 -0
- package/dist/templates/StatusPage/StatusPage.js +8 -0
- package/dist/templates/StatusPage/index.d.ts +1 -0
- package/dist/templates/StatusPage/index.js +1 -0
- package/dist/templates/index.d.ts +8 -0
- package/dist/templates/index.js +8 -0
- package/dist/utils/dates.d.ts +67 -0
- package/dist/utils/dates.js +154 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/theme.d.ts +4 -0
- package/dist/utils/theme.js +7 -3
- package/package.json +4 -1
- package/tokens.css +513 -21
|
@@ -25,7 +25,7 @@ function subscribe(l) {
|
|
|
25
25
|
* Asks and resolves `true` on accept, `false` on Cancel, Escape or any other dismissal.
|
|
26
26
|
* Never rejects.
|
|
27
27
|
*
|
|
28
|
-
* if (await confirm({ title: 'Delete
|
|
28
|
+
* if (await confirm({ title: 'Delete item?', confirmLabel: 'Delete', tone: 'danger' })) …
|
|
29
29
|
*/
|
|
30
30
|
export function confirm(options) {
|
|
31
31
|
return new Promise((resolve) => emit([...queue, { ...options, resolve }]));
|
|
@@ -5,12 +5,12 @@ import { warnMissingScales } from '../../utils/scales.js';
|
|
|
5
5
|
* The five meanings this library names, in Themes' colour vocabulary.
|
|
6
6
|
*
|
|
7
7
|
* **`brand` names no colour on purpose.** Themes falls back to whatever accent the theme
|
|
8
|
-
* carries, so a badge that means "this is ours" follows the
|
|
8
|
+
* carries, so a badge that means "this is ours" follows the app's chosen colour while
|
|
9
9
|
* the four that mean something specific do not. It said `jade` until accents became
|
|
10
|
-
* choosable, which left
|
|
10
|
+
* choosable, which left brand badges green in a purple-accented app.
|
|
11
11
|
*
|
|
12
|
-
* `success` is jade and stays jade. Green means fine in a way purple does not, and
|
|
13
|
-
*
|
|
12
|
+
* `success` is jade and stays jade. Green means fine in a way purple does not, and an app
|
|
13
|
+
* whose accent is orange should not end up with an orange "paid".
|
|
14
14
|
*/
|
|
15
15
|
const COLORS = {
|
|
16
16
|
neutral: 'gray',
|
|
@@ -5,10 +5,9 @@ import { cn } from '../../utils/cn.js';
|
|
|
5
5
|
/**
|
|
6
6
|
* The house intents, expressed in Radix Themes' variant-and-colour vocabulary.
|
|
7
7
|
*
|
|
8
|
-
* The mapping exists so
|
|
8
|
+
* The mapping exists so apps keep saying `variant="danger"` rather than
|
|
9
9
|
* `variant="solid" color="red"` at sixty call sites — and so that when the house style changes
|
|
10
|
-
* its mind about what "secondary" looks like, it changes here and everywhere at once.
|
|
11
|
-
* second half is what the dashboard and the site did not have, and why they drifted.
|
|
10
|
+
* its mind about what "secondary" looks like, it changes here and everywhere at once.
|
|
12
11
|
*/
|
|
13
12
|
const VARIANTS = {
|
|
14
13
|
primary: { variant: 'solid' },
|
|
@@ -3,13 +3,10 @@ import type { ComponentPropsWithoutRef, ReactNode } from 'react';
|
|
|
3
3
|
/**
|
|
4
4
|
* The house button intents.
|
|
5
5
|
*
|
|
6
|
-
* **`
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* about the word rather than about the need: the site wants the bordered, translucent button
|
|
11
|
-
* because it sits over a dark hero, and the dashboard wants the tinted one because it sits on a
|
|
12
|
-
* panel. So `secondary` means exactly one thing everywhere and the other look has its own name.
|
|
6
|
+
* **`secondary` and `outline` are two looks with two names.** `secondary` is Themes' `soft`, a
|
|
7
|
+
* tinted button for use on a panel. `outline` is Themes' `surface`, a bordered, translucent
|
|
8
|
+
* button for use over a dark or busy background. One word for both would mean different things
|
|
9
|
+
* in different places, so each look has its own name.
|
|
13
10
|
*/
|
|
14
11
|
export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
|
|
15
12
|
/** `touch` is `md` type with a 44px minimum height, for primary actions on touch screens. */
|
|
@@ -37,7 +34,7 @@ export interface ButtonProps extends Omit<ComponentPropsWithoutRef<typeof Themed
|
|
|
37
34
|
/**
|
|
38
35
|
* Renders an anchor, keeping Radix's focus ring and sizing.
|
|
39
36
|
*
|
|
40
|
-
*
|
|
37
|
+
* For pages where most buttons are really links. It is `asChild` underneath,
|
|
41
38
|
* so the anchor stays an anchor — middle-click, copy link, the lot — and it is here rather
|
|
42
39
|
* than left to each app because "a button that is really a link" is a house concern.
|
|
43
40
|
*/
|
|
@@ -21,9 +21,11 @@ export interface CardProps extends HTMLAttributes<HTMLDivElement>, CardStyleProp
|
|
|
21
21
|
* Radix Themes' Card, with the padding taken off.
|
|
22
22
|
*
|
|
23
23
|
* Themes pads its card for you; the house card is built from a header and a body with a
|
|
24
|
-
* rule between them, so the padding belongs to those rather than to the card.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* rule between them, so the padding belongs to those rather than to the card. Themes' padding
|
|
25
|
+
* is unlayered CSS and beats a layered `p-0`, so the zero is `!p-0` (plus an unlayered rule in
|
|
26
|
+
* `tokens.css`), and any padding utility a caller passes is promoted to `!` so it still wins.
|
|
27
|
+
* Variant and density reach the header, title and body through context, and each can still
|
|
28
|
+
* override them.
|
|
27
29
|
*/
|
|
28
30
|
export declare function Card({ raised, variant, density, className, ...props }: CardProps): import("react").JSX.Element;
|
|
29
31
|
export interface CardPartProps extends HTMLAttributes<HTMLDivElement>, CardStyleProps {
|
package/dist/atoms/Card/Card.js
CHANGED
|
@@ -32,17 +32,34 @@ function useStyleAttrs(own) {
|
|
|
32
32
|
...responsiveAttrs('density', own.density ?? inherited.density),
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
+
const PADDING_CLASS = /^(?:[\w-]+:)*-?p[xytrblse]?-/;
|
|
36
|
+
/** `md:px-4` → `md:!px-4`; other classes untouched. Already-important classes are left alone. */
|
|
37
|
+
function importantPadding(className) {
|
|
38
|
+
if (!className)
|
|
39
|
+
return className;
|
|
40
|
+
return className
|
|
41
|
+
.split(/\s+/)
|
|
42
|
+
.map((c) => {
|
|
43
|
+
if (!c || c.includes('!') || !PADDING_CLASS.test(c))
|
|
44
|
+
return c;
|
|
45
|
+
const i = c.lastIndexOf(':') + 1;
|
|
46
|
+
return `${c.slice(0, i)}!${c.slice(i)}`;
|
|
47
|
+
})
|
|
48
|
+
.join(' ');
|
|
49
|
+
}
|
|
35
50
|
/**
|
|
36
51
|
* Radix Themes' Card, with the padding taken off.
|
|
37
52
|
*
|
|
38
53
|
* Themes pads its card for you; the house card is built from a header and a body with a
|
|
39
|
-
* rule between them, so the padding belongs to those rather than to the card.
|
|
40
|
-
*
|
|
41
|
-
*
|
|
54
|
+
* rule between them, so the padding belongs to those rather than to the card. Themes' padding
|
|
55
|
+
* is unlayered CSS and beats a layered `p-0`, so the zero is `!p-0` (plus an unlayered rule in
|
|
56
|
+
* `tokens.css`), and any padding utility a caller passes is promoted to `!` so it still wins.
|
|
57
|
+
* Variant and density reach the header, title and body through context, and each can still
|
|
58
|
+
* override them.
|
|
42
59
|
*/
|
|
43
60
|
export function Card({ raised = false, variant = 'outlined', density = 'comfortable', className, ...props }) {
|
|
44
61
|
const attrs = useStyleAttrs({ variant, density });
|
|
45
|
-
return (_jsx(CardContext.Provider, { value: { variant, density }, children: _jsx(ThemedCard, { size: "2", variant: raised ? 'classic' : 'surface', className: cn('ui-card p-0', className), ...attrs, ...props }) }));
|
|
62
|
+
return (_jsx(CardContext.Provider, { value: { variant, density }, children: _jsx(ThemedCard, { size: "2", variant: raised ? 'classic' : 'surface', className: cn('ui-card !p-0', importantPadding(className)), ...attrs, ...props }) }));
|
|
46
63
|
}
|
|
47
64
|
export function CardHeader({ variant, density, className, ...props }) {
|
|
48
65
|
const attrs = useStyleAttrs({ variant, density });
|
|
@@ -17,7 +17,7 @@ export interface ContextMenuProps extends Omit<HTMLAttributes<HTMLElement>, 'onS
|
|
|
17
17
|
* The menu a right-click opens, in the house vocabulary.
|
|
18
18
|
*
|
|
19
19
|
* Items are data rather than children, like `Select`'s options, because every caller
|
|
20
|
-
* builds them from something — a
|
|
20
|
+
* builds them from something — a record's status decides which of them make sense.
|
|
21
21
|
*
|
|
22
22
|
* **A shortcut, never the only way.** Right-click is invisible, mouse-only and absent on
|
|
23
23
|
* touch, so everything here also has a path through the form the block opens on click.
|
|
@@ -5,7 +5,7 @@ import { Fragment, forwardRef } from 'react';
|
|
|
5
5
|
* The menu a right-click opens, in the house vocabulary.
|
|
6
6
|
*
|
|
7
7
|
* Items are data rather than children, like `Select`'s options, because every caller
|
|
8
|
-
* builds them from something — a
|
|
8
|
+
* builds them from something — a record's status decides which of them make sense.
|
|
9
9
|
*
|
|
10
10
|
* **A shortcut, never the only way.** Right-click is invisible, mouse-only and absent on
|
|
11
11
|
* touch, so everything here also has a path through the form the block opens on click.
|
|
@@ -192,6 +192,6 @@ export function Drawer({ mode = 'modal', open: openProp, defaultOpen = true, onO
|
|
|
192
192
|
onPointerUp: end,
|
|
193
193
|
onPointerCancel: cancel,
|
|
194
194
|
};
|
|
195
|
-
return (_jsxs(_Fragment, { children: [anchor, _jsx(ThemePortal, { target: target, children: _jsxs("div", { ref: wrapperRef, "data-drawer-root": "", children: [modal ? (_jsx("div", { "data-testid": "drawer-scrim", "aria-hidden": "true", className: "fixed inset-0 z-40 bg-scrim", onClick: dismissible ? close : undefined })) : null, _jsxs("div", { ref: sheetRef, role: modal ? 'dialog' : 'region', "aria-modal": modal ? true : undefined, "aria-labelledby": titleId, "aria-describedby": description ? descId : undefined, tabIndex: -1, "data-snap": snap, "data-mode": mode, onKeyDown: trapTab, style: { transform: `translateY(${Math.max(offset, -40)}px)` }, className: cn('fixed inset-x-0 bottom-0 z-50 mx-auto flex w-full flex-col', 'rounded-t-2xl
|
|
195
|
+
return (_jsxs(_Fragment, { children: [anchor, _jsx(ThemePortal, { target: target, children: _jsxs("div", { ref: wrapperRef, "data-drawer-root": "", children: [modal ? (_jsx("div", { "data-testid": "drawer-scrim", "aria-hidden": "true", className: "fixed inset-0 z-40 bg-scrim", onClick: dismissible ? close : undefined })) : null, _jsxs("div", { ref: sheetRef, role: modal ? 'dialog' : 'region', "aria-modal": modal ? true : undefined, "aria-labelledby": titleId, "aria-describedby": description ? descId : undefined, tabIndex: -1, "data-snap": snap, "data-mode": mode, onKeyDown: trapTab, style: { transform: `translateY(${Math.max(offset, -40)}px)` }, className: cn('fixed inset-x-0 bottom-0 z-50 mx-auto flex w-full flex-col', 'rounded-t-2xl bg-sheet text-ink shadow-2xl', 'pb-[env(safe-area-inset-bottom)] outline-none', !dragging &&
|
|
196
196
|
'transition-transform duration-200 ease-out motion-reduce:transition-none', maxWidthClassName, className), children: [_jsxs("div", { className: "touch-none select-none px-5 pt-2", onPointerDown: (e) => begin(e, false), ...dragHandlers, children: [_jsx("button", { type: "button", "aria-expanded": expanded, "aria-controls": bodyId, "aria-label": expanded ? (collapseLabel ?? strings.collapse) : (expandLabel ?? strings.expand), onClick: onHandleClick, className: "mx-auto flex h-6 w-16 cursor-grab items-center justify-center rounded-full focus-visible:outline-2 focus-visible:outline-brand-700 active:cursor-grabbing", children: _jsx("span", { "aria-hidden": "true", className: "h-1.5 w-10 rounded-full bg-hairline" }) }), _jsxs("div", { className: "flex items-start gap-3 pb-3 pt-1", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h2", { id: titleId, className: "m-0 text-base font-medium text-brand-900", children: title }), description ? (_jsx("p", { id: descId, className: "m-0 mt-1 text-sm text-ink-muted", children: description })) : null] }), showCloseButton && dismissible ? (_jsx("button", { type: "button", "aria-label": closeLabel ?? strings.close, onClick: close, className: "-mr-1 flex size-8 shrink-0 items-center justify-center rounded-full text-ink-muted hover:bg-brand-700/8 focus-visible:outline-2 focus-visible:outline-brand-700", children: _jsx("svg", { "aria-hidden": "true", width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", children: _jsx("path", { d: "M3.5 3.5l8 8m0-8l-8 8", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) })) : null] })] }), !expanded && peek ? _jsx("div", { className: "px-5 pb-4", children: peek }) : null, _jsx("div", { ref: bodyRef, id: bodyId, hidden: !expanded, className: "max-h-[80vh] overflow-y-auto overscroll-contain px-5 pb-4", onPointerDown: (e) => begin(e, true), ...dragHandlers, children: children }), footer ? (_jsx("div", { className: "flex justify-end gap-2 border-t border-hairline px-5 py-3", children: footer })) : null] })] }) })] }));
|
|
197
197
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The handful of icons this app actually uses, drawn inline.
|
|
3
|
-
*
|
|
4
|
-
* No icon library: a dependency for twelve glyphs costs more in bundle and upgrade surface
|
|
5
|
-
* than it saves, and these are all one or two paths. They inherit `currentColor` and size
|
|
6
|
-
* with the text around them, which is what makes them work in a collapsed sidebar and a
|
|
7
|
-
* button alike.
|
|
8
|
-
*/
|
|
9
1
|
declare const PATHS: {
|
|
2
|
+
readonly home: "M3 12l9-8 9 8M5 10v10h5v-6h4v6h5V10";
|
|
3
|
+
readonly list: "M4 7h16M4 12h16M4 17h10";
|
|
4
|
+
readonly calendar: "M7 3v3M17 3v3M4 8h16M5 6h14a1 1 0 011 1v12a1 1 0 01-1 1H5a1 1 0 01-1-1V7a1 1 0 011-1z";
|
|
5
|
+
readonly users: "M16 20v-2a4 4 0 00-4-4H7a4 4 0 00-4 4v2M9.5 9.5a3 3 0 100-6 3 3 0 000 6zM21 20v-2a4 4 0 00-3-3.87";
|
|
6
|
+
readonly card: "M3 7h18v12H3zM3 11h18M7 15h3";
|
|
7
|
+
readonly document: "M14 3H7a1 1 0 00-1 1v16a1 1 0 001 1h10a1 1 0 001-1V7zM14 3v4h4M9 13h6M9 17h4";
|
|
10
8
|
readonly overview: "M3 12l9-8 9 8M5 10v10h5v-6h4v6h5V10";
|
|
11
9
|
readonly services: "M4 7h16M4 12h16M4 17h10";
|
|
12
10
|
readonly bookings: "M7 3v3M17 3v3M4 8h16M5 6h14a1 1 0 011 1v12a1 1 0 01-1 1H5a1 1 0 01-1-1V7a1 1 0 011-1z";
|
|
@@ -44,7 +42,7 @@ export interface IconProps {
|
|
|
44
42
|
* A label makes it an image with a name; leaving it out makes it decoration.
|
|
45
43
|
*
|
|
46
44
|
* Decoration is the right answer whenever adjacent text already says the same thing —
|
|
47
|
-
* a screen reader announcing "
|
|
45
|
+
* a screen reader announcing "Settings, Settings" is worse than saying it once.
|
|
48
46
|
*/
|
|
49
47
|
label?: string;
|
|
50
48
|
}
|
package/dist/atoms/Icon/Icon.js
CHANGED
|
@@ -1,20 +1,35 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cn } from '../../utils/cn.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* A small set of interface icons, drawn inline. For anything else, use `@radix-ui/react-icons`
|
|
5
|
+
* (re-exported from this package).
|
|
5
6
|
*
|
|
6
|
-
* No icon library: a dependency for
|
|
7
|
+
* No icon library: a dependency for a few dozen glyphs costs more in bundle and upgrade surface
|
|
7
8
|
* than it saves, and these are all one or two paths. They inherit `currentColor` and size
|
|
8
9
|
* with the text around them, which is what makes them work in a collapsed sidebar and a
|
|
9
10
|
* button alike.
|
|
10
11
|
*/
|
|
12
|
+
const HOME = 'M3 12l9-8 9 8M5 10v10h5v-6h4v6h5V10';
|
|
13
|
+
const LIST = 'M4 7h16M4 12h16M4 17h10';
|
|
14
|
+
const CALENDAR = 'M7 3v3M17 3v3M4 8h16M5 6h14a1 1 0 011 1v12a1 1 0 01-1 1H5a1 1 0 01-1-1V7a1 1 0 011-1z';
|
|
15
|
+
const USERS = 'M16 20v-2a4 4 0 00-4-4H7a4 4 0 00-4 4v2M9.5 9.5a3 3 0 100-6 3 3 0 000 6zM21 20v-2a4 4 0 00-3-3.87';
|
|
16
|
+
const CARD = 'M3 7h18v12H3zM3 11h18M7 15h3';
|
|
17
|
+
const DOCUMENT = 'M14 3H7a1 1 0 00-1 1v16a1 1 0 001 1h10a1 1 0 001-1V7zM14 3v4h4M9 13h6M9 17h4';
|
|
11
18
|
const PATHS = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
home: HOME,
|
|
20
|
+
list: LIST,
|
|
21
|
+
calendar: CALENDAR,
|
|
22
|
+
users: USERS,
|
|
23
|
+
card: CARD,
|
|
24
|
+
document: DOCUMENT,
|
|
25
|
+
// Legacy names for the six above, named after what one app used them for. Kept so nothing
|
|
26
|
+
// that already passes them breaks; prefer the names above in new code.
|
|
27
|
+
overview: HOME,
|
|
28
|
+
services: LIST,
|
|
29
|
+
bookings: CALENDAR,
|
|
30
|
+
clients: USERS,
|
|
31
|
+
payments: CARD,
|
|
32
|
+
compliance: DOCUMENT,
|
|
18
33
|
settings: 'M12 15.5a3.5 3.5 0 100-7 3.5 3.5 0 000 7zM19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 11-2.83 2.83l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 11-4 0v-.09A1.65 1.65 0 008 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 11-2.83-2.83l.06-.06A1.65 1.65 0 004.6 15a1.65 1.65 0 00-1.51-1H3a2 2 0 110-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 112.83-2.83l.06.06A1.65 1.65 0 009 4.6a1.65 1.65 0 001-1.51V3a2 2 0 114 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 112.83 2.83l-.06.06A1.65 1.65 0 0019.4 9c.14.35.4.65.73.85',
|
|
19
34
|
collapse: 'M15 6l-6 6 6 6',
|
|
20
35
|
expand: 'M9 6l6 6-6 6',
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface PillProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
/** Shows a remove button. */
|
|
5
|
+
onRemove?: () => void;
|
|
6
|
+
/**
|
|
7
|
+
* The remove button's name. Default: the `remove` UI string with the pill's text, which
|
|
8
|
+
* needs `children` to be a string; pass this when it is not.
|
|
9
|
+
*/
|
|
10
|
+
removeLabel?: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A small token, removable or not: an active filter, a chosen tag. The remove button has its
|
|
15
|
+
* own name ("Remove Status: Active"), and a 44px hit area on touch screens.
|
|
16
|
+
*/
|
|
17
|
+
export declare function Pill({ children, onRemove, removeLabel, className }: PillProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Cross2Icon } from '@radix-ui/react-icons';
|
|
3
|
+
import { useUiStrings } from '../../strings.js';
|
|
4
|
+
/**
|
|
5
|
+
* A small token, removable or not: an active filter, a chosen tag. The remove button has its
|
|
6
|
+
* own name ("Remove Status: Active"), and a 44px hit area on touch screens.
|
|
7
|
+
*/
|
|
8
|
+
export function Pill({ children, onRemove, removeLabel, className }) {
|
|
9
|
+
const strings = useUiStrings();
|
|
10
|
+
const label = removeLabel ?? (typeof children === 'string' ? strings.remove(children) : undefined);
|
|
11
|
+
return (_jsxs("span", { className: ['ui-pill', className].filter(Boolean).join(' '), "data-removable": onRemove ? '' : undefined, children: [children, onRemove ? (_jsx("button", { type: "button", className: "ui-pill__remove", "aria-label": label, onClick: onRemove, children: _jsx(Cross2Icon, { "aria-hidden": "true" }) })) : null] }));
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Pill.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Pill.js';
|
|
@@ -1,13 +1,20 @@
|
|
|
1
|
+
import { type Breakpoint } from '../../hooks/breakpoints.js';
|
|
1
2
|
import { type DialogProps } from '../Dialog/Dialog.js';
|
|
2
3
|
import { type SheetDetent } from '../Sheet/Sheet.js';
|
|
3
4
|
export interface ResponsiveDialogProps extends DialogProps {
|
|
4
|
-
/** The detent the sheet opens at below `
|
|
5
|
+
/** The detent the sheet opens at below `breakpoint`. Default `fit`. */
|
|
5
6
|
sheetDetent?: SheetDetent;
|
|
7
|
+
/**
|
|
8
|
+
* From this breakpoint up it is a Dialog; below it, a Sheet. Default `sm` (768px), which is
|
|
9
|
+
* what Tailwind calls `md`.
|
|
10
|
+
*/
|
|
11
|
+
breakpoint?: Breakpoint;
|
|
6
12
|
}
|
|
7
13
|
/**
|
|
8
14
|
* The same props as {@link Dialog}, presented the way the screen asks: a centred dialog on a
|
|
9
15
|
* desktop, a bottom sheet on a phone. Both sit on Radix Dialog, so the role, the focus trap,
|
|
10
16
|
* Escape and the labelling are the same either way. Crossing the breakpoint while open remounts
|
|
11
17
|
* the content, which loses uncommitted state inside `children` — keep form state in the parent.
|
|
18
|
+
* Without `matchMedia` (SSR) it renders the Dialog.
|
|
12
19
|
*/
|
|
13
|
-
export declare function ResponsiveDialog({ sheetDetent, ...props }: ResponsiveDialogProps): import("react").JSX.Element;
|
|
20
|
+
export declare function ResponsiveDialog({ sheetDetent, breakpoint, ...props }: ResponsiveDialogProps): import("react").JSX.Element;
|
|
@@ -1,27 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { minWidth } from '../../hooks/breakpoints.js';
|
|
3
|
+
import { useMediaQuery } from '../../hooks/useMediaQuery.js';
|
|
3
4
|
import { Dialog } from '../Dialog/Dialog.js';
|
|
4
5
|
import { Sheet } from '../Sheet/Sheet.js';
|
|
5
|
-
/** Tailwind's `md`. Below it the dialog becomes a bottom sheet. */
|
|
6
|
-
const MD = '(min-width: 768px)';
|
|
7
|
-
function subscribe(onChange) {
|
|
8
|
-
const query = window.matchMedia(MD);
|
|
9
|
-
query.addEventListener('change', onChange);
|
|
10
|
-
return () => query.removeEventListener('change', onChange);
|
|
11
|
-
}
|
|
12
|
-
/** A Dialog at `md` and up, a Sheet below. Without `matchMedia` (SSR) the Dialog. */
|
|
13
|
-
function useIsMdUp() {
|
|
14
|
-
return useSyncExternalStore(subscribe, () => window.matchMedia(MD).matches, () => true);
|
|
15
|
-
}
|
|
16
6
|
/**
|
|
17
7
|
* The same props as {@link Dialog}, presented the way the screen asks: a centred dialog on a
|
|
18
8
|
* desktop, a bottom sheet on a phone. Both sit on Radix Dialog, so the role, the focus trap,
|
|
19
9
|
* Escape and the labelling are the same either way. Crossing the breakpoint while open remounts
|
|
20
10
|
* the content, which loses uncommitted state inside `children` — keep form state in the parent.
|
|
11
|
+
* Without `matchMedia` (SSR) it renders the Dialog.
|
|
21
12
|
*/
|
|
22
|
-
export function ResponsiveDialog({ sheetDetent = 'fit', ...props }) {
|
|
23
|
-
const
|
|
24
|
-
if (
|
|
13
|
+
export function ResponsiveDialog({ sheetDetent = 'fit', breakpoint = 'sm', ...props }) {
|
|
14
|
+
const wide = useMediaQuery(minWidth(breakpoint));
|
|
15
|
+
if (wide)
|
|
25
16
|
return _jsx(Dialog, { ...props });
|
|
26
17
|
return (_jsx(Sheet, { open: props.open, onOpenChange: props.onOpenChange, title: props.title, description: props.description, footer: props.footer, className: props.className, detent: sheetDetent, showCloseButton: true, children: props.children }));
|
|
27
18
|
}
|
|
@@ -248,7 +248,7 @@ export function Sheet({ open, onOpenChange, title, description, children, footer
|
|
|
248
248
|
const content = (_jsxs("div", { ref: rootRef, "data-sheet-root": "", className: "contents", children: [_jsx(RadixDialog.Overlay, { "data-testid": "sheet-scrim", className: "ui-sheet-scrim fixed inset-0 z-40 bg-scrim" }), _jsxs(RadixDialog.Content, { ref: contentRef, "data-detent": detent, "data-dragging": dragging ? '' : undefined, ...(description ? {} : { 'aria-describedby': undefined }), onEscapeKeyDown: dismissGuard, onPointerDownOutside: dismissGuard, onInteractOutside: dismissGuard,
|
|
249
249
|
// The sheet moves focus to its first control; for a sheet that is the handle or close
|
|
250
250
|
// button, which is correct, so Radix's default is kept.
|
|
251
|
-
style: style, className: cn('ui-sheet fixed inset-x-0 bottom-0 z-50 mx-auto flex w-full flex-col overflow-hidden', 'rounded-t-2xl
|
|
251
|
+
style: style, className: cn('ui-sheet fixed inset-x-0 bottom-0 z-50 mx-auto flex w-full flex-col overflow-hidden', 'rounded-t-2xl bg-sheet text-ink shadow-2xl outline-none', maxWidthClassName, className), children: [_jsxs("div", { className: "touch-none select-none px-5 pt-2", onPointerDown: (e) => begin(e, false), ...dragHandlers, children: [cycles ? (_jsx("button", { type: "button", "aria-label": raising ? (expandLabel ?? strings.expand) : (collapseLabel ?? strings.collapse), onClick: onHandleClick, className: "mx-auto flex h-6 w-16 cursor-grab items-center justify-center rounded-full focus-visible:outline-2 focus-visible:outline-brand-700 active:cursor-grabbing", children: _jsx("span", { "aria-hidden": "true", className: "h-1.5 w-10 rounded-full bg-hairline" }) })) : (_jsx("div", { "aria-hidden": "true", className: "mx-auto flex h-6 w-16 items-center justify-center", children: _jsx("span", { className: "h-1.5 w-10 rounded-full bg-hairline" }) })), _jsxs("div", { className: "flex items-start gap-3 pb-3 pt-1", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(RadixDialog.Title, { className: "m-0 text-base font-medium text-brand-900", children: title }), description ? (_jsx(RadixDialog.Description, { className: "m-0 mt-1 text-sm text-ink-muted", children: description })) : null] }), showCloseButton && dismissible ? (_jsx(RadixDialog.Close, { "aria-label": closeLabel ?? strings.close, className: "-mr-1 flex size-8 shrink-0 items-center justify-center rounded-full text-ink-muted hover:bg-brand-700/8 focus-visible:outline-2 focus-visible:outline-brand-700", children: _jsx("svg", { "aria-hidden": "true", width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", children: _jsx("path", { d: "M3.5 3.5l8 8m0-8l-8 8", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) })) : null] })] }), _jsx("div", { ref: bodyRef, "data-sheet-body": "", className: "min-h-0 flex-1 overflow-y-auto overscroll-contain px-5 pb-4", onPointerDown: (e) => begin(e, true), ...dragHandlers, children: children }), footer ? (_jsx("div", { "data-sheet-footer": "", className: "flex shrink-0 justify-end gap-2 border-t border-hairline px-5 pt-3",
|
|
252
252
|
// Over the keyboard there is no home indicator to clear, only a gap to leave.
|
|
253
253
|
style: {
|
|
254
254
|
paddingBottom: keyboard ? '0.75rem' : 'max(0.75rem, var(--safe-bottom, 0px))',
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type StatusTone = 'neutral' | 'success' | 'warning' | 'danger' | 'info';
|
|
2
|
+
export interface StatusIndicatorProps {
|
|
3
|
+
tone?: StatusTone;
|
|
4
|
+
/** Always shown: the colour is never the only signal. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** A slow pulse, for something in progress. Off under reduced motion. */
|
|
7
|
+
pulse?: boolean;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A coloured dot and a word: "Active", "Failed", "Syncing". Lighter than a Badge, for table
|
|
12
|
+
* cells and lists where a filled pill per row would be loud.
|
|
13
|
+
*/
|
|
14
|
+
export declare function StatusIndicator({ tone, label, pulse, className, }: StatusIndicatorProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* A coloured dot and a word: "Active", "Failed", "Syncing". Lighter than a Badge, for table
|
|
4
|
+
* cells and lists where a filled pill per row would be loud.
|
|
5
|
+
*/
|
|
6
|
+
export function StatusIndicator({ tone = 'neutral', label, pulse, className, }) {
|
|
7
|
+
return (_jsxs("span", { className: ['ui-status', className].filter(Boolean).join(' '), "data-tone": tone, "data-pulse": pulse ? '' : undefined, children: [_jsx("span", { className: "ui-status__dot", "aria-hidden": "true" }), label] }));
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './StatusIndicator.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './StatusIndicator.js';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AnchorHTMLAttributes, MouseEventHandler, ReactElement, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* What a `render` function receives to build a router link. Spread it onto the element you
|
|
4
|
+
* return, e.g. `render={(p) => <RouterLink to={p.href} {...p} />}`.
|
|
5
|
+
*
|
|
6
|
+
* Every component in this library that navigates (TextLink, NavItem, Breadcrumbs, PageTabs)
|
|
7
|
+
* takes the same `render`, so the library never imports a router.
|
|
8
|
+
*/
|
|
9
|
+
export interface LinkRenderProps {
|
|
10
|
+
href: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
'aria-current'?: 'page';
|
|
14
|
+
onClick?: MouseEventHandler<HTMLElement>;
|
|
15
|
+
}
|
|
16
|
+
export type RenderLink = (props: LinkRenderProps) => ReactElement;
|
|
17
|
+
export interface TextLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href' | 'color' | 'children'> {
|
|
18
|
+
href: string;
|
|
19
|
+
children: ReactNode;
|
|
20
|
+
/** Wraps a router link. Receives {@link LinkRenderProps}. */
|
|
21
|
+
render?: RenderLink;
|
|
22
|
+
/**
|
|
23
|
+
* Opens in a new tab with `rel="noopener noreferrer"`, and says so to screen readers
|
|
24
|
+
* (the `opensInNewTab` UI string).
|
|
25
|
+
*/
|
|
26
|
+
external?: boolean;
|
|
27
|
+
/** Default `hover`, Themes' own default. */
|
|
28
|
+
underline?: 'auto' | 'hover' | 'always';
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* An inline text link in the theme's link style, router-agnostic.
|
|
32
|
+
*
|
|
33
|
+
* Named `TextLink` because `Link` is already Radix Themes' own component, re-exported from
|
|
34
|
+
* this package as a primitive.
|
|
35
|
+
*/
|
|
36
|
+
export declare function TextLink({ href, children, render, external, underline, ...rest }: TextLinkProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Link as ThemedLink } from '@radix-ui/themes';
|
|
3
|
+
import { useUiStrings } from '../../strings.js';
|
|
4
|
+
/**
|
|
5
|
+
* An inline text link in the theme's link style, router-agnostic.
|
|
6
|
+
*
|
|
7
|
+
* Named `TextLink` because `Link` is already Radix Themes' own component, re-exported from
|
|
8
|
+
* this package as a primitive.
|
|
9
|
+
*/
|
|
10
|
+
export function TextLink({ href, children, render, external = false, underline, ...rest }) {
|
|
11
|
+
const strings = useUiStrings();
|
|
12
|
+
const content = external ? (_jsxs(_Fragment, { children: [children, " ", _jsx("span", { className: "ui-sr-only", children: strings.opensInNewTab })] })) : (children);
|
|
13
|
+
if (render) {
|
|
14
|
+
return (_jsx(ThemedLink, { asChild: true, underline: underline, children: render({ href, children: content }) }));
|
|
15
|
+
}
|
|
16
|
+
return (_jsx(ThemedLink, { href: href, underline: underline, ...(external ? { target: '_blank', rel: 'noopener noreferrer' } : {}), ...rest, children: content }));
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TextLink.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TextLink.js';
|
|
@@ -30,7 +30,7 @@ type Shorthand = (options: Omit<ToastOptions, 'type'>) => string;
|
|
|
30
30
|
*
|
|
31
31
|
* toast({ title: 'Saved' });
|
|
32
32
|
* toast.error({ title: 'Payment failed', duration: Infinity });
|
|
33
|
-
* toast.success({ title: '
|
|
33
|
+
* toast.success({ title: 'Item archived', action: { label: 'Undo', onClick: restore } });
|
|
34
34
|
* toast.dismiss(id);
|
|
35
35
|
*/
|
|
36
36
|
export declare const toast: typeof show & {
|
|
@@ -36,7 +36,7 @@ function show(options) {
|
|
|
36
36
|
*
|
|
37
37
|
* toast({ title: 'Saved' });
|
|
38
38
|
* toast.error({ title: 'Payment failed', duration: Infinity });
|
|
39
|
-
* toast.success({ title: '
|
|
39
|
+
* toast.success({ title: 'Item archived', action: { label: 'Undo', onClick: restore } });
|
|
40
40
|
* toast.dismiss(id);
|
|
41
41
|
*/
|
|
42
42
|
export const toast = Object.assign(show, {
|
package/dist/atoms/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from './ActionMenu/index.js';
|
|
1
2
|
export * from './ActionSheet/index.js';
|
|
2
3
|
export * from './Alert/index.js';
|
|
3
4
|
export * from './Avatar/index.js';
|
|
@@ -15,6 +16,7 @@ export * from './Label/index.js';
|
|
|
15
16
|
export * from './List/index.js';
|
|
16
17
|
export * from './NavBar/index.js';
|
|
17
18
|
export * from './NotificationCard/index.js';
|
|
19
|
+
export * from './Pill/index.js';
|
|
18
20
|
export * from './Popover/index.js';
|
|
19
21
|
export * from './Progress/index.js';
|
|
20
22
|
export * from './PullToRefresh/index.js';
|
|
@@ -29,8 +31,10 @@ export * from './Skeleton/index.js';
|
|
|
29
31
|
export * from './Slider/index.js';
|
|
30
32
|
export * from './Spinner/index.js';
|
|
31
33
|
export * from './StatTile/index.js';
|
|
34
|
+
export * from './StatusIndicator/index.js';
|
|
32
35
|
export * from './Switch/index.js';
|
|
33
36
|
export * from './TabBar/index.js';
|
|
34
37
|
export * from './Textarea/index.js';
|
|
38
|
+
export * from './TextLink/index.js';
|
|
35
39
|
export * from './Toast/index.js';
|
|
36
40
|
export * from './Tooltip/index.js';
|
package/dist/atoms/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from './ActionMenu/index.js';
|
|
1
2
|
export * from './ActionSheet/index.js';
|
|
2
3
|
export * from './Alert/index.js';
|
|
3
4
|
export * from './Avatar/index.js';
|
|
@@ -15,6 +16,7 @@ export * from './Label/index.js';
|
|
|
15
16
|
export * from './List/index.js';
|
|
16
17
|
export * from './NavBar/index.js';
|
|
17
18
|
export * from './NotificationCard/index.js';
|
|
19
|
+
export * from './Pill/index.js';
|
|
18
20
|
export * from './Popover/index.js';
|
|
19
21
|
export * from './Progress/index.js';
|
|
20
22
|
export * from './PullToRefresh/index.js';
|
|
@@ -29,8 +31,10 @@ export * from './Skeleton/index.js';
|
|
|
29
31
|
export * from './Slider/index.js';
|
|
30
32
|
export * from './Spinner/index.js';
|
|
31
33
|
export * from './StatTile/index.js';
|
|
34
|
+
export * from './StatusIndicator/index.js';
|
|
32
35
|
export * from './Switch/index.js';
|
|
33
36
|
export * from './TabBar/index.js';
|
|
34
37
|
export * from './Textarea/index.js';
|
|
38
|
+
export * from './TextLink/index.js';
|
|
35
39
|
export * from './Toast/index.js';
|
|
36
40
|
export * from './Tooltip/index.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Radix Themes' breakpoints, in pixels. `Card`, `TabBar`, `ScrollStrip` and the media queries in
|
|
3
|
+
* `tokens.css` already use this scale; this constant is the one place JavaScript reads it from.
|
|
4
|
+
*
|
|
5
|
+
* Note that `sm` here is 768px, which is what Tailwind calls `md`. A class cannot be generated
|
|
6
|
+
* for both scales, so components that switch structure in JavaScript take a name from this
|
|
7
|
+
* scale rather than a Tailwind one.
|
|
8
|
+
*/
|
|
9
|
+
export declare const BREAKPOINTS: {
|
|
10
|
+
readonly xs: 520;
|
|
11
|
+
readonly sm: 768;
|
|
12
|
+
readonly md: 1024;
|
|
13
|
+
readonly lg: 1280;
|
|
14
|
+
readonly xl: 1640;
|
|
15
|
+
};
|
|
16
|
+
export type Breakpoint = keyof typeof BREAKPOINTS;
|
|
17
|
+
/** `initial` is below `xs`: the unconditional value, as in `Responsive<T>`. */
|
|
18
|
+
export type BreakpointOrInitial = 'initial' | Breakpoint;
|
|
19
|
+
/** The media query that matches from `bp` up, e.g. `(min-width: 1024px)` for `md`. */
|
|
20
|
+
export declare function minWidth(bp: Breakpoint): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Radix Themes' breakpoints, in pixels. `Card`, `TabBar`, `ScrollStrip` and the media queries in
|
|
3
|
+
* `tokens.css` already use this scale; this constant is the one place JavaScript reads it from.
|
|
4
|
+
*
|
|
5
|
+
* Note that `sm` here is 768px, which is what Tailwind calls `md`. A class cannot be generated
|
|
6
|
+
* for both scales, so components that switch structure in JavaScript take a name from this
|
|
7
|
+
* scale rather than a Tailwind one.
|
|
8
|
+
*/
|
|
9
|
+
export const BREAKPOINTS = { xs: 520, sm: 768, md: 1024, lg: 1280, xl: 1640 };
|
|
10
|
+
/** The media query that matches from `bp` up, e.g. `(min-width: 1024px)` for `md`. */
|
|
11
|
+
export function minWidth(bp) {
|
|
12
|
+
return `(min-width: ${BREAKPOINTS[bp]}px)`;
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface UseControllableStateOptions<T> {
|
|
2
|
+
/** Controlled value. When it is not `undefined`, the hook holds no state of its own. */
|
|
3
|
+
value?: T;
|
|
4
|
+
/** Initial value when uncontrolled. */
|
|
5
|
+
defaultValue: T;
|
|
6
|
+
/** Called with every requested change, whether controlled or not. */
|
|
7
|
+
onChange?: (value: T) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The `value` / `defaultValue` / `onValueChange` pattern in one place, so every component that
|
|
11
|
+
* offers both modes behaves the same way: a controlled component never changes on its own,
|
|
12
|
+
* and an uncontrolled one still reports each change.
|
|
13
|
+
*
|
|
14
|
+
* Whether it is controlled is decided by the first render. Switching between the two is a
|
|
15
|
+
* bug in the caller, the same rule React applies to inputs.
|
|
16
|
+
*/
|
|
17
|
+
export declare function useControllableState<T>({ value, defaultValue, onChange, }: UseControllableStateOptions<T>): [T, (next: T) => void];
|