@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,13 @@
|
|
|
1
|
+
import { Button as SurfaceButton } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { resolveButtonRecipe } from '../../internal/recipes';
|
|
5
|
+
import type { ButtonProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function Button({ tone, emphasis, size, ...props }: ButtonProps) {
|
|
8
|
+
const recipe = resolveButtonRecipe({ tone, emphasis, size });
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<SurfaceButton {...props} size={recipe.size} tone={recipe.tone} variant={recipe.variant} />
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ButtonIconSpec, ButtonProps as SurfaceButtonProps } from '@ankhorage/surface';
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { ZoraControlSize, ZoraEmphasis, ZoraTone } from '../../internal/recipes';
|
|
5
|
+
|
|
6
|
+
export interface ButtonProps extends Omit<
|
|
7
|
+
SurfaceButtonProps,
|
|
8
|
+
'children' | 'size' | 'tone' | 'variant'
|
|
9
|
+
> {
|
|
10
|
+
children?: React.ReactNode;
|
|
11
|
+
tone?: ZoraTone;
|
|
12
|
+
emphasis?: ZoraEmphasis;
|
|
13
|
+
size?: ZoraControlSize;
|
|
14
|
+
leadingIcon?: ButtonIconSpec;
|
|
15
|
+
trailingIcon?: ButtonIconSpec;
|
|
16
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Box, Card as SurfaceCard, Heading, Stack, Text } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { resolveCardVariant } from '../../internal/recipes';
|
|
5
|
+
import type { CardProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function Card({
|
|
8
|
+
children,
|
|
9
|
+
title,
|
|
10
|
+
description,
|
|
11
|
+
eyebrow,
|
|
12
|
+
actions,
|
|
13
|
+
footer,
|
|
14
|
+
tone = 'default',
|
|
15
|
+
compact = false,
|
|
16
|
+
onPress,
|
|
17
|
+
...props
|
|
18
|
+
}: CardProps) {
|
|
19
|
+
const hasHeader = [eyebrow, title, description, actions].some((item) => item != null);
|
|
20
|
+
const hasFooter = footer !== undefined;
|
|
21
|
+
const gap = compact ? 's' : 'm';
|
|
22
|
+
const isInteractive = Boolean(onPress) && !actions;
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<SurfaceCard
|
|
26
|
+
{...props}
|
|
27
|
+
onPress={isInteractive ? onPress : undefined}
|
|
28
|
+
p={compact ? 'm' : 'l'}
|
|
29
|
+
radius="l"
|
|
30
|
+
variant={resolveCardVariant(tone)}
|
|
31
|
+
>
|
|
32
|
+
<Stack gap={gap}>
|
|
33
|
+
{hasHeader ? (
|
|
34
|
+
<Stack
|
|
35
|
+
align={{ base: 'flex-start', md: 'center' }}
|
|
36
|
+
direction={{ base: 'column', md: 'row' }}
|
|
37
|
+
gap="m"
|
|
38
|
+
justify="space-between"
|
|
39
|
+
>
|
|
40
|
+
<Box flex={1}>
|
|
41
|
+
<Stack gap="xs">
|
|
42
|
+
{eyebrow ? (
|
|
43
|
+
<Text tone="muted" variant="caption" weight="semiBold">
|
|
44
|
+
{eyebrow}
|
|
45
|
+
</Text>
|
|
46
|
+
) : null}
|
|
47
|
+
{title ? <Heading level={compact ? 4 : 3}>{title}</Heading> : null}
|
|
48
|
+
{description ? (
|
|
49
|
+
<Text tone="muted" variant="bodySmall">
|
|
50
|
+
{description}
|
|
51
|
+
</Text>
|
|
52
|
+
) : null}
|
|
53
|
+
</Stack>
|
|
54
|
+
</Box>
|
|
55
|
+
{actions ? <Box>{actions}</Box> : null}
|
|
56
|
+
</Stack>
|
|
57
|
+
) : null}
|
|
58
|
+
|
|
59
|
+
{children ? <Box>{children}</Box> : null}
|
|
60
|
+
|
|
61
|
+
{hasFooter ? <Box pt="xs">{footer}</Box> : null}
|
|
62
|
+
</Stack>
|
|
63
|
+
</SurfaceCard>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CardProps as SurfaceCardProps } from '@ankhorage/surface';
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { ZoraCardTone } from '../../internal/recipes';
|
|
5
|
+
|
|
6
|
+
export interface CardProps extends Omit<SurfaceCardProps, 'children' | 'p' | 'radius' | 'variant'> {
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
title?: React.ReactNode;
|
|
9
|
+
description?: React.ReactNode;
|
|
10
|
+
eyebrow?: React.ReactNode;
|
|
11
|
+
actions?: React.ReactNode;
|
|
12
|
+
footer?: React.ReactNode;
|
|
13
|
+
tone?: ZoraCardTone;
|
|
14
|
+
compact?: boolean;
|
|
15
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Box, Drawer as SurfaceDrawer, Heading, Stack, Text } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { DrawerProps } from './types';
|
|
5
|
+
|
|
6
|
+
export function Drawer({ children, title, description, footer, ...props }: DrawerProps) {
|
|
7
|
+
const hasHeader = title != null || description != null;
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<SurfaceDrawer {...props}>
|
|
11
|
+
<Stack gap="m">
|
|
12
|
+
{hasHeader ? (
|
|
13
|
+
<Stack gap="xs">
|
|
14
|
+
{title ? <Heading level={3}>{title}</Heading> : null}
|
|
15
|
+
{description ? (
|
|
16
|
+
<Text tone="muted" variant="bodySmall">
|
|
17
|
+
{description}
|
|
18
|
+
</Text>
|
|
19
|
+
) : null}
|
|
20
|
+
</Stack>
|
|
21
|
+
) : null}
|
|
22
|
+
{children ? <Box flex={1}>{children}</Box> : null}
|
|
23
|
+
{footer ? <Box pt="xs">{footer}</Box> : null}
|
|
24
|
+
</Stack>
|
|
25
|
+
</SurfaceDrawer>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DrawerProps as SurfaceDrawerProps } from '@ankhorage/surface';
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
|
|
4
|
+
export interface DrawerProps extends Pick<
|
|
5
|
+
SurfaceDrawerProps,
|
|
6
|
+
'closeOnBackdrop' | 'onDismiss' | 'position' | 'testID' | 'visible'
|
|
7
|
+
> {
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
title?: React.ReactNode;
|
|
10
|
+
description?: React.ReactNode;
|
|
11
|
+
footer?: React.ReactNode;
|
|
12
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { IconButton as SurfaceIconButton } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { resolveButtonRecipe } from '../../internal/recipes';
|
|
5
|
+
import type { IconButtonProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function IconButton({
|
|
8
|
+
icon,
|
|
9
|
+
label,
|
|
10
|
+
emphasis = 'ghost',
|
|
11
|
+
tone = 'neutral',
|
|
12
|
+
size = 'm',
|
|
13
|
+
...props
|
|
14
|
+
}: IconButtonProps) {
|
|
15
|
+
const recipe = resolveButtonRecipe({ emphasis, tone, size });
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<SurfaceIconButton
|
|
19
|
+
{...props}
|
|
20
|
+
icon={icon}
|
|
21
|
+
accessibilityLabel={label}
|
|
22
|
+
size={recipe.size}
|
|
23
|
+
tone={recipe.tone}
|
|
24
|
+
variant={recipe.variant}
|
|
25
|
+
/>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ButtonIconSpec } from '@ankhorage/surface';
|
|
2
|
+
|
|
3
|
+
import type { ZoraControlSize, ZoraEmphasis, ZoraTone } from '../../internal/recipes';
|
|
4
|
+
|
|
5
|
+
export interface IconButtonProps {
|
|
6
|
+
icon: ButtonIconSpec;
|
|
7
|
+
label: string;
|
|
8
|
+
emphasis?: ZoraEmphasis;
|
|
9
|
+
tone?: ZoraTone;
|
|
10
|
+
size?: ZoraControlSize;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
loading?: boolean;
|
|
13
|
+
onPress?: () => void;
|
|
14
|
+
testID?: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Icon, TextInput as SurfaceTextInput, useTheme } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { resolveIconSize } from '../../internal/recipes';
|
|
5
|
+
import type { InputProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function Input({ size = 'l', leadingIcon, trailingIcon, ...props }: InputProps) {
|
|
8
|
+
const { theme } = useTheme();
|
|
9
|
+
const iconSize = resolveIconSize(size);
|
|
10
|
+
const iconColor = theme.semantics.content.muted;
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<SurfaceTextInput
|
|
14
|
+
{...props}
|
|
15
|
+
leadingAccessory={
|
|
16
|
+
leadingIcon ? (
|
|
17
|
+
<Icon
|
|
18
|
+
color={iconColor}
|
|
19
|
+
name={leadingIcon.name}
|
|
20
|
+
provider={leadingIcon.provider}
|
|
21
|
+
size={iconSize}
|
|
22
|
+
/>
|
|
23
|
+
) : undefined
|
|
24
|
+
}
|
|
25
|
+
size={size}
|
|
26
|
+
trailingAccessory={
|
|
27
|
+
trailingIcon ? (
|
|
28
|
+
<Icon
|
|
29
|
+
color={iconColor}
|
|
30
|
+
name={trailingIcon.name}
|
|
31
|
+
provider={trailingIcon.provider}
|
|
32
|
+
size={iconSize}
|
|
33
|
+
/>
|
|
34
|
+
) : undefined
|
|
35
|
+
}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ButtonIconSpec, TextInputProps as SurfaceTextInputProps } from '@ankhorage/surface';
|
|
2
|
+
|
|
3
|
+
import type { ZoraControlSize } from '../../internal/recipes';
|
|
4
|
+
|
|
5
|
+
export interface InputProps extends Omit<
|
|
6
|
+
SurfaceTextInputProps,
|
|
7
|
+
'leadingAccessory' | 'size' | 'trailingAccessory'
|
|
8
|
+
> {
|
|
9
|
+
size?: ZoraControlSize;
|
|
10
|
+
leadingIcon?: ButtonIconSpec;
|
|
11
|
+
trailingIcon?: ButtonIconSpec;
|
|
12
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Box, Heading, Modal as SurfaceModal, Stack, Text } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { resolveDialogWidth } from '../../internal/recipes';
|
|
5
|
+
import type { ModalProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function Modal({
|
|
8
|
+
children,
|
|
9
|
+
title,
|
|
10
|
+
description,
|
|
11
|
+
footer,
|
|
12
|
+
width = 'default',
|
|
13
|
+
...props
|
|
14
|
+
}: ModalProps) {
|
|
15
|
+
const hasHeader = title != null || description != null;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<SurfaceModal {...props}>
|
|
19
|
+
<Box maxWidth={resolveDialogWidth(width)} style={{ alignSelf: 'center', width: '100%' }}>
|
|
20
|
+
<Stack gap="m">
|
|
21
|
+
{hasHeader ? (
|
|
22
|
+
<Stack gap="xs">
|
|
23
|
+
{title ? <Heading level={3}>{title}</Heading> : null}
|
|
24
|
+
{description ? (
|
|
25
|
+
<Text tone="muted" variant="bodySmall">
|
|
26
|
+
{description}
|
|
27
|
+
</Text>
|
|
28
|
+
) : null}
|
|
29
|
+
</Stack>
|
|
30
|
+
) : null}
|
|
31
|
+
{children ? <Box>{children}</Box> : null}
|
|
32
|
+
{footer ? <Box pt="xs">{footer}</Box> : null}
|
|
33
|
+
</Stack>
|
|
34
|
+
</Box>
|
|
35
|
+
</SurfaceModal>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ModalProps as SurfaceModalProps } from '@ankhorage/surface';
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { ZoraContentWidth } from '../../internal/recipes';
|
|
5
|
+
|
|
6
|
+
export interface ModalProps extends Pick<
|
|
7
|
+
SurfaceModalProps,
|
|
8
|
+
'closeOnBackdrop' | 'onDismiss' | 'testID' | 'visible'
|
|
9
|
+
> {
|
|
10
|
+
children?: React.ReactNode;
|
|
11
|
+
title?: React.ReactNode;
|
|
12
|
+
description?: React.ReactNode;
|
|
13
|
+
footer?: React.ReactNode;
|
|
14
|
+
width?: ZoraContentWidth;
|
|
15
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Box, useTheme } from '@ankhorage/surface';
|
|
2
|
+
import { Picker } from '@react-native-picker/picker';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
|
|
5
|
+
import type { SelectProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function Select<TValue extends string = string>({
|
|
8
|
+
value,
|
|
9
|
+
options,
|
|
10
|
+
onValueChange,
|
|
11
|
+
disabled,
|
|
12
|
+
invalid,
|
|
13
|
+
testID,
|
|
14
|
+
}: SelectProps<TValue>) {
|
|
15
|
+
const { theme } = useTheme();
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<Box
|
|
19
|
+
bg="surface"
|
|
20
|
+
borderColor={invalid ? theme.colors.error : theme.colors.border}
|
|
21
|
+
borderWidth={1}
|
|
22
|
+
opacity={disabled ? 0.5 : 1}
|
|
23
|
+
radius="m"
|
|
24
|
+
testID={testID}
|
|
25
|
+
>
|
|
26
|
+
<Picker
|
|
27
|
+
enabled={!disabled}
|
|
28
|
+
onValueChange={(itemValue) => onValueChange(itemValue)}
|
|
29
|
+
selectedValue={value}
|
|
30
|
+
style={{
|
|
31
|
+
height: 44,
|
|
32
|
+
width: '100%',
|
|
33
|
+
backgroundColor: 'transparent',
|
|
34
|
+
color: theme.colors.text,
|
|
35
|
+
borderWidth: 0,
|
|
36
|
+
}}
|
|
37
|
+
>
|
|
38
|
+
{options.map((option) => (
|
|
39
|
+
<Picker.Item
|
|
40
|
+
key={option.value}
|
|
41
|
+
enabled={!option.disabled}
|
|
42
|
+
label={option.label}
|
|
43
|
+
value={option.value}
|
|
44
|
+
/>
|
|
45
|
+
))}
|
|
46
|
+
</Picker>
|
|
47
|
+
</Box>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface SelectOption<TValue extends string = string> {
|
|
2
|
+
value: TValue;
|
|
3
|
+
label: string;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface SelectProps<TValue extends string = string> {
|
|
8
|
+
value: TValue;
|
|
9
|
+
options: readonly SelectOption<TValue>[];
|
|
10
|
+
onValueChange: (value: TValue) => void;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
invalid?: boolean;
|
|
13
|
+
testID?: string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Box, Stack, Text, useTheme } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { Button } from '../button';
|
|
5
|
+
import type { TabItem, TabsProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function Tabs<TValue extends string = string>({
|
|
8
|
+
value,
|
|
9
|
+
items,
|
|
10
|
+
onValueChange,
|
|
11
|
+
variant = 'underline',
|
|
12
|
+
size = 'm',
|
|
13
|
+
disabled: tabsDisabled,
|
|
14
|
+
testID,
|
|
15
|
+
}: TabsProps<TValue>) {
|
|
16
|
+
const { theme } = useTheme();
|
|
17
|
+
|
|
18
|
+
const renderTab = (item: TabItem<TValue>) => {
|
|
19
|
+
const isActive = item.value === value;
|
|
20
|
+
const isDisabled = tabsDisabled ?? item.disabled;
|
|
21
|
+
|
|
22
|
+
if (variant === 'segmented') {
|
|
23
|
+
return (
|
|
24
|
+
<Button
|
|
25
|
+
key={item.value}
|
|
26
|
+
emphasis={isActive ? 'solid' : 'ghost'}
|
|
27
|
+
tone="neutral"
|
|
28
|
+
size={size}
|
|
29
|
+
disabled={isDisabled}
|
|
30
|
+
onPress={() => onValueChange(item.value)}
|
|
31
|
+
leadingIcon={item.icon}
|
|
32
|
+
testID={item.testID}
|
|
33
|
+
>
|
|
34
|
+
{item.label}
|
|
35
|
+
{item.badge}
|
|
36
|
+
</Button>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (variant === 'pill') {
|
|
41
|
+
return (
|
|
42
|
+
<Button
|
|
43
|
+
key={item.value}
|
|
44
|
+
emphasis={isActive ? 'soft' : 'ghost'}
|
|
45
|
+
tone={isActive ? 'primary' : 'neutral'}
|
|
46
|
+
size={size}
|
|
47
|
+
disabled={isDisabled}
|
|
48
|
+
onPress={() => onValueChange(item.value)}
|
|
49
|
+
leadingIcon={item.icon}
|
|
50
|
+
testID={item.testID}
|
|
51
|
+
>
|
|
52
|
+
{item.label}
|
|
53
|
+
{item.badge}
|
|
54
|
+
</Button>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Default: 'underline'
|
|
59
|
+
return (
|
|
60
|
+
<Box
|
|
61
|
+
key={item.value}
|
|
62
|
+
borderColor={isActive ? theme.colors.primary : 'transparent'}
|
|
63
|
+
pb="xs"
|
|
64
|
+
style={{
|
|
65
|
+
borderBottomWidth: 2,
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
<Button
|
|
69
|
+
emphasis="ghost"
|
|
70
|
+
tone="neutral"
|
|
71
|
+
size={size}
|
|
72
|
+
disabled={isDisabled}
|
|
73
|
+
onPress={() => onValueChange(item.value)}
|
|
74
|
+
leadingIcon={item.icon}
|
|
75
|
+
testID={item.testID}
|
|
76
|
+
>
|
|
77
|
+
<Text
|
|
78
|
+
color={isActive ? theme.colors.primary : undefined}
|
|
79
|
+
tone={isActive ? undefined : 'muted'}
|
|
80
|
+
weight={isActive ? 'semiBold' : 'regular'}
|
|
81
|
+
>
|
|
82
|
+
{item.label}
|
|
83
|
+
</Text>
|
|
84
|
+
{item.badge}
|
|
85
|
+
</Button>
|
|
86
|
+
</Box>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<Stack
|
|
92
|
+
direction="row"
|
|
93
|
+
gap={variant === 'segmented' ? 'none' : 'm'}
|
|
94
|
+
align="center"
|
|
95
|
+
testID={testID}
|
|
96
|
+
p={variant === 'segmented' ? 'xxs' : 'none'}
|
|
97
|
+
bg={variant === 'segmented' ? 'subtle' : 'transparent'}
|
|
98
|
+
radius={variant === 'segmented' ? 'm' : 'none'}
|
|
99
|
+
>
|
|
100
|
+
{items.map(renderTab)}
|
|
101
|
+
</Stack>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ButtonIconSpec } from '@ankhorage/surface';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import type { ZoraControlSize } from '../../internal/recipes';
|
|
5
|
+
|
|
6
|
+
export interface TabItem<TValue extends string = string> {
|
|
7
|
+
value: TValue;
|
|
8
|
+
label: ReactNode;
|
|
9
|
+
icon?: ButtonIconSpec;
|
|
10
|
+
badge?: ReactNode;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
testID?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type TabsVariant = 'underline' | 'pill' | 'segmented';
|
|
16
|
+
|
|
17
|
+
export interface TabsProps<TValue extends string = string> {
|
|
18
|
+
value: TValue;
|
|
19
|
+
items: readonly TabItem<TValue>[];
|
|
20
|
+
onValueChange: (value: TValue) => void;
|
|
21
|
+
variant?: TabsVariant;
|
|
22
|
+
size?: ZoraControlSize;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
testID?: string;
|
|
25
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Icon, Textarea as SurfaceTextarea, useTheme } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { resolveIconSize } from '../../internal/recipes';
|
|
5
|
+
import type { TextareaProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function Textarea({ size = 'l', leadingIcon, trailingIcon, ...props }: TextareaProps) {
|
|
8
|
+
const { theme } = useTheme();
|
|
9
|
+
const iconSize = resolveIconSize(size);
|
|
10
|
+
const iconColor = theme.semantics.content.muted;
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<SurfaceTextarea
|
|
14
|
+
{...props}
|
|
15
|
+
leadingAccessory={
|
|
16
|
+
leadingIcon ? (
|
|
17
|
+
<Icon
|
|
18
|
+
color={iconColor}
|
|
19
|
+
name={leadingIcon.name}
|
|
20
|
+
provider={leadingIcon.provider}
|
|
21
|
+
size={iconSize}
|
|
22
|
+
/>
|
|
23
|
+
) : undefined
|
|
24
|
+
}
|
|
25
|
+
size={size}
|
|
26
|
+
trailingAccessory={
|
|
27
|
+
trailingIcon ? (
|
|
28
|
+
<Icon
|
|
29
|
+
color={iconColor}
|
|
30
|
+
name={trailingIcon.name}
|
|
31
|
+
provider={trailingIcon.provider}
|
|
32
|
+
size={iconSize}
|
|
33
|
+
/>
|
|
34
|
+
) : undefined
|
|
35
|
+
}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ButtonIconSpec, TextareaProps as SurfaceTextareaProps } from '@ankhorage/surface';
|
|
2
|
+
|
|
3
|
+
import type { ZoraControlSize } from '../../internal/recipes';
|
|
4
|
+
|
|
5
|
+
export interface TextareaProps extends Omit<
|
|
6
|
+
SurfaceTextareaProps,
|
|
7
|
+
'leadingAccessory' | 'size' | 'trailingAccessory'
|
|
8
|
+
> {
|
|
9
|
+
size?: ZoraControlSize;
|
|
10
|
+
leadingIcon?: ButtonIconSpec;
|
|
11
|
+
trailingIcon?: ButtonIconSpec;
|
|
12
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Stack } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { Card } from '../card';
|
|
5
|
+
import type { ToolbarProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function Toolbar({
|
|
8
|
+
children,
|
|
9
|
+
position = 'inline',
|
|
10
|
+
floating = false,
|
|
11
|
+
compact = true,
|
|
12
|
+
testID,
|
|
13
|
+
}: ToolbarProps) {
|
|
14
|
+
const isFixed = position === 'top' || position === 'bottom';
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<Card
|
|
18
|
+
compact={compact}
|
|
19
|
+
tone={floating ? 'default' : 'subtle'}
|
|
20
|
+
testID={testID}
|
|
21
|
+
style={
|
|
22
|
+
isFixed
|
|
23
|
+
? {
|
|
24
|
+
position: 'absolute',
|
|
25
|
+
left: 0,
|
|
26
|
+
right: 0,
|
|
27
|
+
[position]: 0,
|
|
28
|
+
zIndex: 10,
|
|
29
|
+
}
|
|
30
|
+
: undefined
|
|
31
|
+
}
|
|
32
|
+
>
|
|
33
|
+
<Stack direction="row" gap="s" align="center">
|
|
34
|
+
{children}
|
|
35
|
+
</Stack>
|
|
36
|
+
</Card>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { IconButton } from '../icon-button';
|
|
4
|
+
import type { ToolbarActionProps } from './types';
|
|
5
|
+
|
|
6
|
+
export function ToolbarAction({ active, ...props }: ToolbarActionProps) {
|
|
7
|
+
return (
|
|
8
|
+
<IconButton
|
|
9
|
+
{...props}
|
|
10
|
+
emphasis={active ? 'soft' : 'ghost'}
|
|
11
|
+
tone={active ? 'primary' : 'neutral'}
|
|
12
|
+
size="m"
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
}
|