@ankhorage/zora 0.3.6 → 0.3.8
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 +13 -0
- package/README.md +0 -90
- package/dist/components/badge/Badge.js.map +1 -1
- package/dist/components/badge/index.js.map +1 -1
- package/dist/components/badge/types.js.map +1 -1
- package/dist/components/button/Button.js.map +1 -1
- package/dist/components/button/index.js.map +1 -1
- package/dist/components/button/types.js.map +1 -1
- package/dist/components/card/Card.js.map +1 -1
- package/dist/components/card/index.js.map +1 -1
- package/dist/components/card/types.js.map +1 -1
- package/dist/components/drawer/Drawer.js.map +1 -1
- package/dist/components/drawer/index.js.map +1 -1
- package/dist/components/drawer/types.js.map +1 -1
- package/dist/components/icon/Icon.js.map +1 -1
- package/dist/components/icon/index.js.map +1 -1
- package/dist/components/icon-button/IconButton.js.map +1 -1
- package/dist/components/icon-button/index.js.map +1 -1
- package/dist/components/icon-button/types.js.map +1 -1
- package/dist/components/input/Input.js.map +1 -1
- package/dist/components/input/index.js.map +1 -1
- package/dist/components/input/types.js.map +1 -1
- package/dist/components/modal/Modal.js.map +1 -1
- package/dist/components/modal/index.js.map +1 -1
- package/dist/components/modal/types.js.map +1 -1
- package/dist/components/select/Select.js.map +1 -1
- package/dist/components/select/index.js.map +1 -1
- package/dist/components/select/types.js.map +1 -1
- package/dist/components/tabs/Tabs.js.map +1 -1
- package/dist/components/tabs/index.js.map +1 -1
- package/dist/components/tabs/types.js.map +1 -1
- package/dist/components/textarea/Textarea.js.map +1 -1
- package/dist/components/textarea/index.js.map +1 -1
- package/dist/components/textarea/types.js.map +1 -1
- package/dist/components/toolbar/Toolbar.js.map +1 -1
- package/dist/components/toolbar/ToolbarAction.js.map +1 -1
- package/dist/components/toolbar/index.js.map +1 -1
- package/dist/components/toolbar/types.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal/deepMerge.js.map +1 -1
- package/dist/internal/recipes.js.map +1 -1
- package/dist/layout/app-shell/AppShell.js.map +1 -1
- package/dist/layout/app-shell/index.js.map +1 -1
- package/dist/layout/app-shell/types.js.map +1 -1
- package/dist/layout/auth-layout/AuthLayout.js.map +1 -1
- package/dist/layout/auth-layout/index.js.map +1 -1
- package/dist/layout/auth-layout/types.js.map +1 -1
- package/dist/layout/page/Page.js.map +1 -1
- package/dist/layout/page/index.js.map +1 -1
- package/dist/layout/page/types.js.map +1 -1
- package/dist/layout/page-header/PageHeader.js.map +1 -1
- package/dist/layout/page-header/index.js.map +1 -1
- package/dist/layout/page-header/types.js.map +1 -1
- package/dist/layout/page-section/PageSection.js.map +1 -1
- package/dist/layout/page-section/index.js.map +1 -1
- package/dist/layout/page-section/types.js.map +1 -1
- package/dist/layout/settings-layout/SettingsLayout.js.map +1 -1
- package/dist/layout/settings-layout/index.js.map +1 -1
- package/dist/layout/settings-layout/types.js.map +1 -1
- package/dist/layout/sidebar-layout/SidebarLayout.js.map +1 -1
- package/dist/layout/sidebar-layout/index.js.map +1 -1
- package/dist/layout/sidebar-layout/types.js.map +1 -1
- package/dist/layout/topbar-layout/TopbarLayout.js.map +1 -1
- package/dist/layout/topbar-layout/index.js.map +1 -1
- package/dist/layout/topbar-layout/types.js.map +1 -1
- package/dist/patterns/collection-editor/CollectionEditor.js.map +1 -1
- package/dist/patterns/collection-editor/index.js.map +1 -1
- package/dist/patterns/collection-editor/types.js.map +1 -1
- package/dist/patterns/confirm-dialog/ConfirmDialog.js.map +1 -1
- package/dist/patterns/confirm-dialog/index.js.map +1 -1
- package/dist/patterns/confirm-dialog/types.js.map +1 -1
- package/dist/patterns/disclosure-section/DisclosureSection.js.map +1 -1
- package/dist/patterns/disclosure-section/index.js.map +1 -1
- package/dist/patterns/disclosure-section/types.js.map +1 -1
- package/dist/patterns/empty-state/EmptyState.js.map +1 -1
- package/dist/patterns/empty-state/index.js.map +1 -1
- package/dist/patterns/empty-state/types.js.map +1 -1
- package/dist/patterns/form-field/FormField.js.map +1 -1
- package/dist/patterns/form-field/index.js.map +1 -1
- package/dist/patterns/form-field/types.js.map +1 -1
- package/dist/patterns/inspector-field/InspectorField.js.map +1 -1
- package/dist/patterns/inspector-field/index.js.map +1 -1
- package/dist/patterns/inspector-field/types.js.map +1 -1
- package/dist/patterns/notice/Notice.js.map +1 -1
- package/dist/patterns/notice/index.js.map +1 -1
- package/dist/patterns/notice/types.js.map +1 -1
- package/dist/patterns/panel/Panel.js.map +1 -1
- package/dist/patterns/panel/index.js.map +1 -1
- package/dist/patterns/panel/types.js.map +1 -1
- package/dist/patterns/responsive-panel/ResponsivePanel.js.map +1 -1
- package/dist/patterns/responsive-panel/index.js.map +1 -1
- package/dist/patterns/responsive-panel/types.js.map +1 -1
- package/dist/patterns/section-header/SectionHeader.js.map +1 -1
- package/dist/patterns/section-header/index.js.map +1 -1
- package/dist/patterns/section-header/types.js.map +1 -1
- package/dist/patterns/settings-row/SettingsRow.js.map +1 -1
- package/dist/patterns/settings-row/index.js.map +1 -1
- package/dist/patterns/settings-row/types.js.map +1 -1
- package/dist/patterns/switch-field/SwitchField.js.map +1 -1
- package/dist/patterns/switch-field/index.js.map +1 -1
- package/dist/patterns/switch-field/types.js.map +1 -1
- package/dist/patterns/tile-grid/PaletteItem.js.map +1 -1
- package/dist/patterns/tile-grid/TileGrid.js.map +1 -1
- package/dist/patterns/tile-grid/index.js.map +1 -1
- package/dist/patterns/tile-grid/types.js.map +1 -1
- package/dist/patterns/tree-view/TreeItem.js.map +1 -1
- package/dist/patterns/tree-view/TreeView.js.map +1 -1
- package/dist/patterns/tree-view/index.js.map +1 -1
- package/dist/patterns/tree-view/types.js.map +1 -1
- package/dist/theme/ZoraProvider.js.map +1 -1
- package/dist/theme/createZoraTheme.js.map +1 -1
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/useZoraTheme.js.map +1 -1
- package/dist/theme/zoraTheme.js.map +1 -1
- package/package.json +15 -11
- package/src/components/badge/Badge.tsx +19 -0
- package/src/components/badge/index.ts +2 -0
- package/src/components/badge/types.ts +14 -0
- package/src/components/button/Button.tsx +13 -0
- package/src/components/button/index.ts +2 -0
- package/src/components/button/types.ts +16 -0
- package/src/components/card/Card.tsx +65 -0
- package/src/components/card/index.ts +2 -0
- package/src/components/card/types.ts +15 -0
- package/src/components/drawer/Drawer.tsx +27 -0
- package/src/components/drawer/index.ts +2 -0
- package/src/components/drawer/types.ts +12 -0
- package/src/components/icon/Icon.tsx +8 -0
- package/src/components/icon/index.ts +2 -0
- package/src/components/icon-button/IconButton.tsx +27 -0
- package/src/components/icon-button/index.ts +2 -0
- package/src/components/icon-button/types.ts +15 -0
- package/src/components/input/Input.tsx +38 -0
- package/src/components/input/index.ts +2 -0
- package/src/components/input/types.ts +12 -0
- package/src/components/modal/Modal.tsx +37 -0
- package/src/components/modal/index.ts +2 -0
- package/src/components/modal/types.ts +15 -0
- package/src/components/select/Select.tsx +49 -0
- package/src/components/select/index.ts +2 -0
- package/src/components/select/types.ts +14 -0
- package/src/components/tabs/Tabs.tsx +103 -0
- package/src/components/tabs/index.ts +2 -0
- package/src/components/tabs/types.ts +25 -0
- package/src/components/textarea/Textarea.tsx +38 -0
- package/src/components/textarea/index.ts +2 -0
- package/src/components/textarea/types.ts +12 -0
- package/src/components/toolbar/Toolbar.tsx +38 -0
- package/src/components/toolbar/ToolbarAction.tsx +15 -0
- package/src/components/toolbar/index.ts +3 -0
- package/src/components/toolbar/types.ts +21 -0
- package/src/index.ts +72 -0
- package/src/internal/deepMerge.ts +23 -0
- package/src/internal/recipes.test.ts +46 -0
- package/src/internal/recipes.ts +92 -0
- package/src/layout/app-shell/AppShell.tsx +15 -0
- package/src/layout/app-shell/index.ts +2 -0
- package/src/layout/app-shell/types.ts +7 -0
- package/src/layout/auth-layout/AuthLayout.tsx +29 -0
- package/src/layout/auth-layout/index.ts +2 -0
- package/src/layout/auth-layout/types.ts +10 -0
- package/src/layout/page/Page.tsx +17 -0
- package/src/layout/page/index.ts +2 -0
- package/src/layout/page/types.ts +11 -0
- package/src/layout/page-header/PageHeader.tsx +41 -0
- package/src/layout/page-header/index.ts +2 -0
- package/src/layout/page-header/types.ts +10 -0
- package/src/layout/page-section/PageSection.tsx +14 -0
- package/src/layout/page-section/index.ts +2 -0
- package/src/layout/page-section/types.ts +9 -0
- package/src/layout/settings-layout/SettingsLayout.tsx +26 -0
- package/src/layout/settings-layout/index.ts +2 -0
- package/src/layout/settings-layout/types.ts +10 -0
- package/src/layout/sidebar-layout/SidebarLayout.tsx +23 -0
- package/src/layout/sidebar-layout/index.ts +2 -0
- package/src/layout/sidebar-layout/types.ts +10 -0
- package/src/layout/topbar-layout/TopbarLayout.tsx +14 -0
- package/src/layout/topbar-layout/index.ts +2 -0
- package/src/layout/topbar-layout/types.ts +8 -0
- package/src/patterns/collection-editor/CollectionEditor.tsx +100 -0
- package/src/patterns/collection-editor/index.ts +2 -0
- package/src/patterns/collection-editor/types.ts +25 -0
- package/src/patterns/confirm-dialog/ConfirmDialog.tsx +46 -0
- package/src/patterns/confirm-dialog/index.ts +2 -0
- package/src/patterns/confirm-dialog/types.ts +19 -0
- package/src/patterns/disclosure-section/DisclosureSection.tsx +61 -0
- package/src/patterns/disclosure-section/index.ts +2 -0
- package/src/patterns/disclosure-section/types.ts +15 -0
- package/src/patterns/empty-state/EmptyState.tsx +53 -0
- package/src/patterns/empty-state/index.ts +2 -0
- package/src/patterns/empty-state/types.ts +20 -0
- package/src/patterns/form-field/FormField.tsx +27 -0
- package/src/patterns/form-field/index.ts +2 -0
- package/src/patterns/form-field/types.ts +11 -0
- package/src/patterns/inspector-field/InspectorField.tsx +16 -0
- package/src/patterns/inspector-field/index.ts +2 -0
- package/src/patterns/inspector-field/types.ts +15 -0
- package/src/patterns/notice/Notice.tsx +30 -0
- package/src/patterns/notice/index.ts +2 -0
- package/src/patterns/notice/types.ts +12 -0
- package/src/patterns/panel/Panel.tsx +8 -0
- package/src/patterns/panel/index.ts +2 -0
- package/src/patterns/panel/types.ts +15 -0
- package/src/patterns/responsive-panel/ResponsivePanel.tsx +70 -0
- package/src/patterns/responsive-panel/index.ts +2 -0
- package/src/patterns/responsive-panel/types.ts +20 -0
- package/src/patterns/section-header/SectionHeader.tsx +39 -0
- package/src/patterns/section-header/index.ts +2 -0
- package/src/patterns/section-header/types.ts +9 -0
- package/src/patterns/settings-row/SettingsRow.tsx +40 -0
- package/src/patterns/settings-row/index.ts +2 -0
- package/src/patterns/settings-row/types.ts +27 -0
- package/src/patterns/switch-field/SwitchField.tsx +24 -0
- package/src/patterns/switch-field/index.ts +2 -0
- package/src/patterns/switch-field/types.ts +10 -0
- package/src/patterns/tile-grid/PaletteItem.tsx +49 -0
- package/src/patterns/tile-grid/TileGrid.tsx +44 -0
- package/src/patterns/tile-grid/index.ts +3 -0
- package/src/patterns/tile-grid/types.ts +20 -0
- package/src/patterns/tree-view/TreeItem.tsx +86 -0
- package/src/patterns/tree-view/TreeView.tsx +50 -0
- package/src/patterns/tree-view/index.ts +3 -0
- package/src/patterns/tree-view/types.ts +31 -0
- package/src/theme/ZoraProvider.tsx +22 -0
- package/src/theme/createZoraTheme.test.ts +25 -0
- package/src/theme/createZoraTheme.ts +10 -0
- package/src/theme/index.ts +6 -0
- package/src/theme/useZoraTheme.ts +5 -0
- package/src/theme/zoraTheme.ts +16 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface CollectionEditorRenderItemProps<TItem> {
|
|
4
|
+
item: TItem;
|
|
5
|
+
index: number;
|
|
6
|
+
remove: () => void;
|
|
7
|
+
moveUp: () => void;
|
|
8
|
+
moveDown: () => void;
|
|
9
|
+
canMoveUp: boolean;
|
|
10
|
+
canMoveDown: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface CollectionEditorProps<TItem> {
|
|
14
|
+
title?: React.ReactNode;
|
|
15
|
+
description?: React.ReactNode;
|
|
16
|
+
items: readonly TItem[];
|
|
17
|
+
renderItem: (props: CollectionEditorRenderItemProps<TItem>) => React.ReactNode;
|
|
18
|
+
onAdd?: () => void;
|
|
19
|
+
onRemove?: (index: number) => void;
|
|
20
|
+
onMove?: (from: number, to: number) => void;
|
|
21
|
+
addLabel?: React.ReactNode;
|
|
22
|
+
emptyLabel?: React.ReactNode;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
testID?: string;
|
|
25
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Stack } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { Button } from '../../components/button';
|
|
5
|
+
import { Modal } from '../../components/modal';
|
|
6
|
+
import type { ConfirmDialogProps } from './types';
|
|
7
|
+
|
|
8
|
+
export function ConfirmDialog({
|
|
9
|
+
visible,
|
|
10
|
+
title,
|
|
11
|
+
description,
|
|
12
|
+
children,
|
|
13
|
+
confirmLabel = 'Confirm',
|
|
14
|
+
cancelLabel = 'Cancel',
|
|
15
|
+
confirmTone = 'danger',
|
|
16
|
+
confirmEmphasis = 'solid',
|
|
17
|
+
busy = false,
|
|
18
|
+
closeOnBackdrop = true,
|
|
19
|
+
onConfirm,
|
|
20
|
+
onCancel,
|
|
21
|
+
testID,
|
|
22
|
+
}: ConfirmDialogProps) {
|
|
23
|
+
return (
|
|
24
|
+
<Modal
|
|
25
|
+
closeOnBackdrop={closeOnBackdrop}
|
|
26
|
+
description={description}
|
|
27
|
+
footer={
|
|
28
|
+
<Stack direction={{ base: 'column', md: 'row' }} gap="s" justify="flex-end">
|
|
29
|
+
<Button emphasis="soft" onPress={onCancel} tone="neutral">
|
|
30
|
+
{cancelLabel}
|
|
31
|
+
</Button>
|
|
32
|
+
<Button emphasis={confirmEmphasis} loading={busy} onPress={onConfirm} tone={confirmTone}>
|
|
33
|
+
{confirmLabel}
|
|
34
|
+
</Button>
|
|
35
|
+
</Stack>
|
|
36
|
+
}
|
|
37
|
+
onDismiss={onCancel}
|
|
38
|
+
testID={testID}
|
|
39
|
+
title={title}
|
|
40
|
+
visible={visible}
|
|
41
|
+
width="narrow"
|
|
42
|
+
>
|
|
43
|
+
{children}
|
|
44
|
+
</Modal>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { ZoraEmphasis, ZoraTone } from '../../internal/recipes';
|
|
4
|
+
|
|
5
|
+
export interface ConfirmDialogProps {
|
|
6
|
+
visible: boolean;
|
|
7
|
+
title: React.ReactNode;
|
|
8
|
+
description?: React.ReactNode;
|
|
9
|
+
children?: React.ReactNode;
|
|
10
|
+
confirmLabel?: React.ReactNode;
|
|
11
|
+
cancelLabel?: React.ReactNode;
|
|
12
|
+
confirmTone?: ZoraTone;
|
|
13
|
+
confirmEmphasis?: ZoraEmphasis;
|
|
14
|
+
busy?: boolean;
|
|
15
|
+
closeOnBackdrop?: boolean;
|
|
16
|
+
onConfirm?: () => void;
|
|
17
|
+
onCancel?: () => void;
|
|
18
|
+
testID?: string;
|
|
19
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Box, Stack } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { IconButton } from '../../components/icon-button';
|
|
5
|
+
import { Panel } from '../panel';
|
|
6
|
+
import type { DisclosureSectionProps } from './types';
|
|
7
|
+
|
|
8
|
+
export function DisclosureSection({
|
|
9
|
+
title,
|
|
10
|
+
description,
|
|
11
|
+
icon,
|
|
12
|
+
defaultOpen = true,
|
|
13
|
+
open: controlledOpen,
|
|
14
|
+
onOpenChange,
|
|
15
|
+
actions,
|
|
16
|
+
children,
|
|
17
|
+
disabled,
|
|
18
|
+
testID,
|
|
19
|
+
}: DisclosureSectionProps) {
|
|
20
|
+
const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
|
|
21
|
+
|
|
22
|
+
const isControlled = controlledOpen !== undefined;
|
|
23
|
+
const isOpen = isControlled ? controlledOpen : internalOpen;
|
|
24
|
+
|
|
25
|
+
const toggleOpen = () => {
|
|
26
|
+
if (disabled) return;
|
|
27
|
+
|
|
28
|
+
if (isControlled) {
|
|
29
|
+
onOpenChange?.(!controlledOpen);
|
|
30
|
+
} else {
|
|
31
|
+
setInternalOpen(!internalOpen);
|
|
32
|
+
onOpenChange?.(!internalOpen);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Panel
|
|
38
|
+
compact
|
|
39
|
+
description={description}
|
|
40
|
+
testID={testID}
|
|
41
|
+
title={title}
|
|
42
|
+
eyebrow={icon ? <Box pb="xs">{/* Surface icon spec would go here */}</Box> : null}
|
|
43
|
+
actions={
|
|
44
|
+
<Stack direction="row" gap="xs" align="center">
|
|
45
|
+
{actions}
|
|
46
|
+
<IconButton
|
|
47
|
+
icon={{ name: isOpen ? 'chevron-up-outline' : 'chevron-down-outline' }}
|
|
48
|
+
label={isOpen ? 'Collapse' : 'Expand'}
|
|
49
|
+
emphasis="ghost"
|
|
50
|
+
tone="neutral"
|
|
51
|
+
size="s"
|
|
52
|
+
disabled={disabled}
|
|
53
|
+
onPress={toggleOpen}
|
|
54
|
+
/>
|
|
55
|
+
</Stack>
|
|
56
|
+
}
|
|
57
|
+
>
|
|
58
|
+
{isOpen ? <Box pt="m">{children}</Box> : null}
|
|
59
|
+
</Panel>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ButtonIconSpec } from '@ankhorage/surface';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
export interface DisclosureSectionProps {
|
|
5
|
+
title: ReactNode;
|
|
6
|
+
description?: ReactNode;
|
|
7
|
+
icon?: ButtonIconSpec;
|
|
8
|
+
defaultOpen?: boolean;
|
|
9
|
+
open?: boolean;
|
|
10
|
+
onOpenChange?: (open: boolean) => void;
|
|
11
|
+
actions?: ReactNode;
|
|
12
|
+
children?: ReactNode;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
testID?: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Stack } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { Button } from '../../components/button';
|
|
5
|
+
import { Card } from '../../components/card';
|
|
6
|
+
import type { EmptyStateProps } from './types';
|
|
7
|
+
|
|
8
|
+
export function EmptyState({
|
|
9
|
+
title,
|
|
10
|
+
description,
|
|
11
|
+
eyebrow,
|
|
12
|
+
primaryAction,
|
|
13
|
+
secondaryAction,
|
|
14
|
+
footer,
|
|
15
|
+
testID,
|
|
16
|
+
}: EmptyStateProps) {
|
|
17
|
+
return (
|
|
18
|
+
<Card
|
|
19
|
+
compact
|
|
20
|
+
description={description}
|
|
21
|
+
eyebrow={eyebrow}
|
|
22
|
+
testID={testID}
|
|
23
|
+
title={title}
|
|
24
|
+
tone="subtle"
|
|
25
|
+
>
|
|
26
|
+
<Stack gap="m">
|
|
27
|
+
{primaryAction || secondaryAction ? (
|
|
28
|
+
<Stack direction={{ base: 'column', md: 'row' }} gap="s">
|
|
29
|
+
{primaryAction ? (
|
|
30
|
+
<Button
|
|
31
|
+
emphasis={primaryAction.emphasis}
|
|
32
|
+
onPress={primaryAction.onPress}
|
|
33
|
+
tone={primaryAction.tone}
|
|
34
|
+
>
|
|
35
|
+
{primaryAction.label}
|
|
36
|
+
</Button>
|
|
37
|
+
) : null}
|
|
38
|
+
{secondaryAction ? (
|
|
39
|
+
<Button
|
|
40
|
+
emphasis={secondaryAction.emphasis ?? 'soft'}
|
|
41
|
+
onPress={secondaryAction.onPress}
|
|
42
|
+
tone={secondaryAction.tone ?? 'neutral'}
|
|
43
|
+
>
|
|
44
|
+
{secondaryAction.label}
|
|
45
|
+
</Button>
|
|
46
|
+
) : null}
|
|
47
|
+
</Stack>
|
|
48
|
+
) : null}
|
|
49
|
+
{footer}
|
|
50
|
+
</Stack>
|
|
51
|
+
</Card>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { ZoraEmphasis, ZoraTone } from '../../internal/recipes';
|
|
4
|
+
|
|
5
|
+
export interface EmptyStateAction {
|
|
6
|
+
label: React.ReactNode;
|
|
7
|
+
onPress: () => void;
|
|
8
|
+
tone?: ZoraTone;
|
|
9
|
+
emphasis?: ZoraEmphasis;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface EmptyStateProps {
|
|
13
|
+
title: React.ReactNode;
|
|
14
|
+
description?: React.ReactNode;
|
|
15
|
+
eyebrow?: React.ReactNode;
|
|
16
|
+
primaryAction?: EmptyStateAction;
|
|
17
|
+
secondaryAction?: EmptyStateAction;
|
|
18
|
+
footer?: React.ReactNode;
|
|
19
|
+
testID?: string;
|
|
20
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Field, Stack, Text } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { FormFieldProps } from './types';
|
|
5
|
+
|
|
6
|
+
export function FormField({ label, description, helperText, children, ...props }: FormFieldProps) {
|
|
7
|
+
return (
|
|
8
|
+
<Field
|
|
9
|
+
{...props}
|
|
10
|
+
helperText={helperText}
|
|
11
|
+
label={
|
|
12
|
+
<Stack gap="xs">
|
|
13
|
+
<Text variant="label" weight="semiBold">
|
|
14
|
+
{label}
|
|
15
|
+
</Text>
|
|
16
|
+
{description ? (
|
|
17
|
+
<Text tone="muted" variant="bodySmall">
|
|
18
|
+
{description}
|
|
19
|
+
</Text>
|
|
20
|
+
) : null}
|
|
21
|
+
</Stack>
|
|
22
|
+
}
|
|
23
|
+
>
|
|
24
|
+
{children}
|
|
25
|
+
</Field>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FieldProps as SurfaceFieldProps } from '@ankhorage/surface';
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
|
|
4
|
+
export interface FormFieldProps extends Pick<
|
|
5
|
+
SurfaceFieldProps,
|
|
6
|
+
'children' | 'disabled' | 'errorText' | 'invalid' | 'readOnly' | 'required' | 'testID'
|
|
7
|
+
> {
|
|
8
|
+
label: React.ReactNode;
|
|
9
|
+
description?: React.ReactNode;
|
|
10
|
+
helperText?: React.ReactNode;
|
|
11
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Box, Stack } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { FormField } from '../form-field';
|
|
5
|
+
import type { InspectorFieldProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function InspectorField({ label, control, children, ...props }: InspectorFieldProps) {
|
|
8
|
+
return (
|
|
9
|
+
<FormField {...props} label={label}>
|
|
10
|
+
<Stack direction="row" gap="s" align="center">
|
|
11
|
+
<Box flex={1}>{children}</Box>
|
|
12
|
+
{control ? <Box>{control}</Box> : null}
|
|
13
|
+
</Stack>
|
|
14
|
+
</FormField>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface InspectorFieldProps {
|
|
4
|
+
label: ReactNode;
|
|
5
|
+
description?: ReactNode;
|
|
6
|
+
helperText?: ReactNode;
|
|
7
|
+
errorText?: ReactNode;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
invalid?: boolean;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
readOnly?: boolean;
|
|
12
|
+
control?: ReactNode;
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
testID?: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Box, Stack } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { Badge } from '../../components/badge';
|
|
5
|
+
import { Card } from '../../components/card';
|
|
6
|
+
import type { NoticeProps } from './types';
|
|
7
|
+
|
|
8
|
+
export function Notice({
|
|
9
|
+
title,
|
|
10
|
+
description,
|
|
11
|
+
children,
|
|
12
|
+
actions,
|
|
13
|
+
tone = 'primary',
|
|
14
|
+
testID,
|
|
15
|
+
}: NoticeProps) {
|
|
16
|
+
return (
|
|
17
|
+
<Card
|
|
18
|
+
description={description}
|
|
19
|
+
eyebrow={<Badge tone={tone}>{String(tone).toUpperCase()}</Badge>}
|
|
20
|
+
testID={testID}
|
|
21
|
+
title={title}
|
|
22
|
+
tone="subtle"
|
|
23
|
+
>
|
|
24
|
+
<Stack gap="m">
|
|
25
|
+
{children ? <Box>{children}</Box> : null}
|
|
26
|
+
{actions ? <Box>{actions}</Box> : null}
|
|
27
|
+
</Stack>
|
|
28
|
+
</Card>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { ZoraTone } from '../../internal/recipes';
|
|
4
|
+
|
|
5
|
+
export interface NoticeProps {
|
|
6
|
+
title: React.ReactNode;
|
|
7
|
+
description?: React.ReactNode;
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
actions?: React.ReactNode;
|
|
10
|
+
tone?: ZoraTone;
|
|
11
|
+
testID?: string;
|
|
12
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { ZoraCardTone } from '../../internal/recipes';
|
|
4
|
+
|
|
5
|
+
export interface PanelProps {
|
|
6
|
+
title?: React.ReactNode;
|
|
7
|
+
description?: React.ReactNode;
|
|
8
|
+
eyebrow?: React.ReactNode;
|
|
9
|
+
actions?: React.ReactNode;
|
|
10
|
+
footer?: React.ReactNode;
|
|
11
|
+
children?: React.ReactNode;
|
|
12
|
+
tone?: ZoraCardTone;
|
|
13
|
+
compact?: boolean;
|
|
14
|
+
testID?: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Drawer } from '../../components/drawer';
|
|
4
|
+
import { Modal } from '../../components/modal';
|
|
5
|
+
import { Panel } from '../panel';
|
|
6
|
+
import type { ResponsivePanelProps } from './types';
|
|
7
|
+
|
|
8
|
+
export function ResponsivePanel({
|
|
9
|
+
title,
|
|
10
|
+
description,
|
|
11
|
+
actions,
|
|
12
|
+
footer,
|
|
13
|
+
children,
|
|
14
|
+
open,
|
|
15
|
+
onOpenChange,
|
|
16
|
+
side = 'right',
|
|
17
|
+
desktopMode = 'inline',
|
|
18
|
+
mobileMode = 'drawer',
|
|
19
|
+
compact = true,
|
|
20
|
+
testID,
|
|
21
|
+
}: ResponsivePanelProps) {
|
|
22
|
+
if (!open) return null;
|
|
23
|
+
|
|
24
|
+
// For now, we assume desktopMode determines the rendering.
|
|
25
|
+
// In a real app, this would react to window size.
|
|
26
|
+
if (desktopMode === 'floating') {
|
|
27
|
+
if (mobileMode === 'modal') {
|
|
28
|
+
return (
|
|
29
|
+
<Modal
|
|
30
|
+
description={description}
|
|
31
|
+
footer={footer}
|
|
32
|
+
onDismiss={() => onOpenChange(false)}
|
|
33
|
+
testID={testID}
|
|
34
|
+
title={title}
|
|
35
|
+
visible={open}
|
|
36
|
+
>
|
|
37
|
+
{children}
|
|
38
|
+
</Modal>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Drawer
|
|
44
|
+
description={description}
|
|
45
|
+
footer={footer}
|
|
46
|
+
onDismiss={() => onOpenChange(false)}
|
|
47
|
+
position={side}
|
|
48
|
+
testID={testID}
|
|
49
|
+
title={title}
|
|
50
|
+
visible={open}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
</Drawer>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// default: inline -> Panel
|
|
58
|
+
return (
|
|
59
|
+
<Panel
|
|
60
|
+
actions={actions}
|
|
61
|
+
compact={compact}
|
|
62
|
+
description={description}
|
|
63
|
+
footer={footer}
|
|
64
|
+
testID={testID}
|
|
65
|
+
title={title}
|
|
66
|
+
>
|
|
67
|
+
{children}
|
|
68
|
+
</Panel>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
export type ResponsivePanelSide = 'left' | 'right';
|
|
4
|
+
export type ResponsivePanelDesktopMode = 'inline' | 'floating';
|
|
5
|
+
export type ResponsivePanelMobileMode = 'drawer' | 'modal';
|
|
6
|
+
|
|
7
|
+
export interface ResponsivePanelProps {
|
|
8
|
+
title?: React.ReactNode;
|
|
9
|
+
description?: React.ReactNode;
|
|
10
|
+
actions?: React.ReactNode;
|
|
11
|
+
footer?: React.ReactNode;
|
|
12
|
+
children?: React.ReactNode;
|
|
13
|
+
open: boolean;
|
|
14
|
+
onOpenChange: (open: boolean) => void;
|
|
15
|
+
side?: ResponsivePanelSide;
|
|
16
|
+
desktopMode?: ResponsivePanelDesktopMode;
|
|
17
|
+
mobileMode?: ResponsivePanelMobileMode;
|
|
18
|
+
compact?: boolean;
|
|
19
|
+
testID?: string;
|
|
20
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Box, Heading, Stack, Text } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { SectionHeaderProps } from './types';
|
|
5
|
+
|
|
6
|
+
export function SectionHeader({
|
|
7
|
+
title,
|
|
8
|
+
description,
|
|
9
|
+
eyebrow,
|
|
10
|
+
actions,
|
|
11
|
+
testID,
|
|
12
|
+
}: SectionHeaderProps) {
|
|
13
|
+
return (
|
|
14
|
+
<Stack
|
|
15
|
+
align={{ base: 'flex-start', md: 'center' }}
|
|
16
|
+
direction={{ base: 'column', md: 'row' }}
|
|
17
|
+
gap="m"
|
|
18
|
+
justify="space-between"
|
|
19
|
+
testID={testID}
|
|
20
|
+
>
|
|
21
|
+
<Box flex={1}>
|
|
22
|
+
<Stack gap="xs">
|
|
23
|
+
{eyebrow ? (
|
|
24
|
+
<Text tone="muted" variant="caption" weight="semiBold">
|
|
25
|
+
{eyebrow}
|
|
26
|
+
</Text>
|
|
27
|
+
) : null}
|
|
28
|
+
<Heading level={3}>{title}</Heading>
|
|
29
|
+
{description ? (
|
|
30
|
+
<Text tone="muted" variant="bodySmall">
|
|
31
|
+
{description}
|
|
32
|
+
</Text>
|
|
33
|
+
) : null}
|
|
34
|
+
</Stack>
|
|
35
|
+
</Box>
|
|
36
|
+
{actions ? <Box>{actions}</Box> : null}
|
|
37
|
+
</Stack>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Box, Text } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { Card } from '../../components/card';
|
|
5
|
+
import type { SettingsRowProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function SettingsRow({
|
|
8
|
+
title,
|
|
9
|
+
description,
|
|
10
|
+
meta,
|
|
11
|
+
control,
|
|
12
|
+
onPress,
|
|
13
|
+
disabled = false,
|
|
14
|
+
testID,
|
|
15
|
+
}: SettingsRowProps) {
|
|
16
|
+
// Prevent nested interactive elements:
|
|
17
|
+
// If a control is present (likely contains buttons), the row itself must not be clickable
|
|
18
|
+
const isInteractive = Boolean(onPress) && !control;
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Card
|
|
22
|
+
compact
|
|
23
|
+
actions={control}
|
|
24
|
+
description={description}
|
|
25
|
+
disabled={disabled}
|
|
26
|
+
onPress={isInteractive ? onPress : undefined}
|
|
27
|
+
testID={testID}
|
|
28
|
+
title={title}
|
|
29
|
+
tone="subtle"
|
|
30
|
+
>
|
|
31
|
+
{meta ? (
|
|
32
|
+
<Box pt="xs">
|
|
33
|
+
<Text tone="muted" variant="caption">
|
|
34
|
+
{meta}
|
|
35
|
+
</Text>
|
|
36
|
+
</Box>
|
|
37
|
+
) : null}
|
|
38
|
+
</Card>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
interface SettingsRowBaseProps {
|
|
4
|
+
title: React.ReactNode;
|
|
5
|
+
description?: React.ReactNode;
|
|
6
|
+
meta?: React.ReactNode;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
testID?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface SettingsRowPressableProps {
|
|
12
|
+
onPress: () => void;
|
|
13
|
+
control?: never;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface SettingsRowControlledProps {
|
|
17
|
+
control: React.ReactNode;
|
|
18
|
+
onPress?: never;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface SettingsRowStaticProps {
|
|
22
|
+
control?: never;
|
|
23
|
+
onPress?: never;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type SettingsRowProps = SettingsRowBaseProps &
|
|
27
|
+
(SettingsRowPressableProps | SettingsRowControlledProps | SettingsRowStaticProps);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Switch } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { SettingsRow } from '../settings-row';
|
|
5
|
+
import type { SwitchFieldProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function SwitchField({
|
|
8
|
+
label,
|
|
9
|
+
description,
|
|
10
|
+
value,
|
|
11
|
+
onValueChange,
|
|
12
|
+
disabled,
|
|
13
|
+
testID,
|
|
14
|
+
}: SwitchFieldProps) {
|
|
15
|
+
return (
|
|
16
|
+
<SettingsRow
|
|
17
|
+
title={label}
|
|
18
|
+
description={description}
|
|
19
|
+
disabled={disabled}
|
|
20
|
+
testID={testID}
|
|
21
|
+
control={<Switch checked={value} onCheckedChange={onValueChange} disabled={disabled} />}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|