@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,21 @@
|
|
|
1
|
+
import type { ButtonIconSpec } from '@ankhorage/surface';
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
|
|
4
|
+
export type ToolbarPosition = 'top' | 'bottom' | 'inline';
|
|
5
|
+
|
|
6
|
+
export interface ToolbarProps {
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
position?: ToolbarPosition;
|
|
9
|
+
floating?: boolean;
|
|
10
|
+
compact?: boolean;
|
|
11
|
+
testID?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ToolbarActionProps {
|
|
15
|
+
label: string;
|
|
16
|
+
icon: ButtonIconSpec;
|
|
17
|
+
active?: boolean;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
onPress?: () => void;
|
|
20
|
+
testID?: string;
|
|
21
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export type { BadgeProps } from './components/badge';
|
|
2
|
+
export { Badge } from './components/badge';
|
|
3
|
+
export type { ButtonProps } from './components/button';
|
|
4
|
+
export { Button } from './components/button';
|
|
5
|
+
export type { CardProps } from './components/card';
|
|
6
|
+
export { Card } from './components/card';
|
|
7
|
+
export type { DrawerProps } from './components/drawer';
|
|
8
|
+
export { Drawer } from './components/drawer';
|
|
9
|
+
export type { IconProps } from './components/icon';
|
|
10
|
+
export { Icon } from './components/icon';
|
|
11
|
+
export type { IconButtonProps } from './components/icon-button';
|
|
12
|
+
export { IconButton } from './components/icon-button';
|
|
13
|
+
export type { InputProps } from './components/input';
|
|
14
|
+
export { Input } from './components/input';
|
|
15
|
+
export type { ModalProps } from './components/modal';
|
|
16
|
+
export { Modal } from './components/modal';
|
|
17
|
+
export type { SelectOption, SelectProps } from './components/select';
|
|
18
|
+
export { Select } from './components/select';
|
|
19
|
+
export type { TabItem, TabsProps } from './components/tabs';
|
|
20
|
+
export { Tabs } from './components/tabs';
|
|
21
|
+
export type { TextareaProps } from './components/textarea';
|
|
22
|
+
export { Textarea } from './components/textarea';
|
|
23
|
+
export type { ToolbarActionProps, ToolbarProps } from './components/toolbar';
|
|
24
|
+
export { Toolbar, ToolbarAction } from './components/toolbar';
|
|
25
|
+
export type { AppShellProps } from './layout/app-shell';
|
|
26
|
+
export { AppShell } from './layout/app-shell';
|
|
27
|
+
export type { AuthLayoutProps } from './layout/auth-layout';
|
|
28
|
+
export { AuthLayout } from './layout/auth-layout';
|
|
29
|
+
export type { PageProps } from './layout/page';
|
|
30
|
+
export { Page } from './layout/page';
|
|
31
|
+
export type { PageHeaderProps } from './layout/page-header';
|
|
32
|
+
export { PageHeader } from './layout/page-header';
|
|
33
|
+
export type { PageSectionProps } from './layout/page-section';
|
|
34
|
+
export { PageSection } from './layout/page-section';
|
|
35
|
+
export type { SettingsLayoutProps } from './layout/settings-layout';
|
|
36
|
+
export { SettingsLayout } from './layout/settings-layout';
|
|
37
|
+
export type { SidebarLayoutProps } from './layout/sidebar-layout';
|
|
38
|
+
export { SidebarLayout } from './layout/sidebar-layout';
|
|
39
|
+
export type { TopbarLayoutProps } from './layout/topbar-layout';
|
|
40
|
+
export { TopbarLayout } from './layout/topbar-layout';
|
|
41
|
+
export type {
|
|
42
|
+
CollectionEditorProps,
|
|
43
|
+
CollectionEditorRenderItemProps,
|
|
44
|
+
} from './patterns/collection-editor';
|
|
45
|
+
export { CollectionEditor } from './patterns/collection-editor';
|
|
46
|
+
export type { ConfirmDialogProps } from './patterns/confirm-dialog';
|
|
47
|
+
export { ConfirmDialog } from './patterns/confirm-dialog';
|
|
48
|
+
export type { DisclosureSectionProps } from './patterns/disclosure-section';
|
|
49
|
+
export { DisclosureSection } from './patterns/disclosure-section';
|
|
50
|
+
export type { EmptyStateAction, EmptyStateProps } from './patterns/empty-state';
|
|
51
|
+
export { EmptyState } from './patterns/empty-state';
|
|
52
|
+
export type { FormFieldProps } from './patterns/form-field';
|
|
53
|
+
export { FormField } from './patterns/form-field';
|
|
54
|
+
export type { InspectorFieldProps } from './patterns/inspector-field';
|
|
55
|
+
export { InspectorField } from './patterns/inspector-field';
|
|
56
|
+
export type { NoticeProps } from './patterns/notice';
|
|
57
|
+
export { Notice } from './patterns/notice';
|
|
58
|
+
export type { PanelProps } from './patterns/panel';
|
|
59
|
+
export { Panel } from './patterns/panel';
|
|
60
|
+
export type { ResponsivePanelProps } from './patterns/responsive-panel';
|
|
61
|
+
export { ResponsivePanel } from './patterns/responsive-panel';
|
|
62
|
+
export type { SectionHeaderProps } from './patterns/section-header';
|
|
63
|
+
export { SectionHeader } from './patterns/section-header';
|
|
64
|
+
export type { SettingsRowProps } from './patterns/settings-row';
|
|
65
|
+
export { SettingsRow } from './patterns/settings-row';
|
|
66
|
+
export type { SwitchFieldProps } from './patterns/switch-field';
|
|
67
|
+
export { SwitchField } from './patterns/switch-field';
|
|
68
|
+
export type { PaletteItemProps, TileGridProps } from './patterns/tile-grid';
|
|
69
|
+
export { PaletteItem, TileGrid } from './patterns/tile-grid';
|
|
70
|
+
export type { TreeItemNode, TreeItemRenderProps, TreeViewProps } from './patterns/tree-view';
|
|
71
|
+
export { TreeItem, TreeView } from './patterns/tree-view';
|
|
72
|
+
export * from './theme';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function deepMerge<T extends object>(target: T, source: Partial<T>): T {
|
|
2
|
+
const result = { ...target };
|
|
3
|
+
|
|
4
|
+
(Object.keys(source) as (keyof T)[]).forEach((key) => {
|
|
5
|
+
const sourceValue = source[key];
|
|
6
|
+
const targetValue = target[key];
|
|
7
|
+
|
|
8
|
+
if (
|
|
9
|
+
sourceValue &&
|
|
10
|
+
typeof sourceValue === 'object' &&
|
|
11
|
+
!Array.isArray(sourceValue) &&
|
|
12
|
+
targetValue &&
|
|
13
|
+
typeof targetValue === 'object' &&
|
|
14
|
+
!Array.isArray(targetValue)
|
|
15
|
+
) {
|
|
16
|
+
result[key] = deepMerge(targetValue as object, sourceValue as object) as T[keyof T];
|
|
17
|
+
} else if (sourceValue !== undefined) {
|
|
18
|
+
result[key] = sourceValue as T[keyof T];
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
resolveBadgeRecipe,
|
|
5
|
+
resolveButtonRecipe,
|
|
6
|
+
resolveCardVariant,
|
|
7
|
+
resolveDialogWidth,
|
|
8
|
+
resolveIconSize,
|
|
9
|
+
resolvePageMaxWidth,
|
|
10
|
+
} from './recipes';
|
|
11
|
+
|
|
12
|
+
describe('recipes', () => {
|
|
13
|
+
test('maps button defaults to a more opinionated large solid primary button', () => {
|
|
14
|
+
expect(resolveButtonRecipe({})).toEqual({
|
|
15
|
+
size: 'l',
|
|
16
|
+
tone: 'primary',
|
|
17
|
+
variant: 'solid',
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('maps badge defaults to a soft medium primary badge', () => {
|
|
22
|
+
expect(resolveBadgeRecipe({})).toEqual({
|
|
23
|
+
size: 'm',
|
|
24
|
+
tone: 'primary',
|
|
25
|
+
variant: 'soft',
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('resolves elevated cards by default', () => {
|
|
30
|
+
expect(resolveCardVariant()).toBe('raised');
|
|
31
|
+
expect(resolveCardVariant('outline')).toBe('outline');
|
|
32
|
+
expect(resolveCardVariant('subtle')).toBe('subtle');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('keeps width presets stable for layouts and dialogs', () => {
|
|
36
|
+
expect(resolveDialogWidth('narrow')).toBeLessThan(resolveDialogWidth('default'));
|
|
37
|
+
expect(resolveDialogWidth('wide')).toBeGreaterThanOrEqual(resolveDialogWidth('default'));
|
|
38
|
+
expect(resolvePageMaxWidth('wide')).toBeGreaterThan(resolvePageMaxWidth('default'));
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('keeps icon sizes aligned with control sizes', () => {
|
|
42
|
+
expect(resolveIconSize('s')).toBe(16);
|
|
43
|
+
expect(resolveIconSize('m')).toBe(18);
|
|
44
|
+
expect(resolveIconSize('l')).toBe(20);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BadgeProps as SurfaceBadgeProps,
|
|
3
|
+
ButtonProps as SurfaceButtonProps,
|
|
4
|
+
CardProps as SurfaceCardProps,
|
|
5
|
+
} from '@ankhorage/surface';
|
|
6
|
+
|
|
7
|
+
export type ZoraTone = NonNullable<SurfaceButtonProps['tone']>;
|
|
8
|
+
export type ZoraEmphasis = NonNullable<SurfaceButtonProps['variant']>;
|
|
9
|
+
export type ZoraControlSize = NonNullable<SurfaceButtonProps['size']>;
|
|
10
|
+
export type ZoraBadgeEmphasis = NonNullable<SurfaceBadgeProps['variant']>;
|
|
11
|
+
export type ZoraCardTone = 'default' | 'subtle' | 'outline';
|
|
12
|
+
export type ZoraContentWidth = 'narrow' | 'default' | 'wide';
|
|
13
|
+
|
|
14
|
+
export function resolveButtonRecipe({
|
|
15
|
+
tone = 'primary',
|
|
16
|
+
emphasis = 'solid',
|
|
17
|
+
size = 'l',
|
|
18
|
+
}: {
|
|
19
|
+
tone?: ZoraTone;
|
|
20
|
+
emphasis?: ZoraEmphasis;
|
|
21
|
+
size?: ZoraControlSize;
|
|
22
|
+
}): Pick<SurfaceButtonProps, 'size' | 'tone' | 'variant'> {
|
|
23
|
+
return {
|
|
24
|
+
size,
|
|
25
|
+
tone,
|
|
26
|
+
variant: emphasis,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function resolveBadgeRecipe({
|
|
31
|
+
tone = 'primary',
|
|
32
|
+
emphasis = 'soft',
|
|
33
|
+
size = 'm',
|
|
34
|
+
}: {
|
|
35
|
+
tone?: ZoraTone;
|
|
36
|
+
emphasis?: ZoraBadgeEmphasis;
|
|
37
|
+
size?: ZoraControlSize;
|
|
38
|
+
}): Pick<SurfaceBadgeProps, 'size' | 'tone' | 'variant'> {
|
|
39
|
+
return {
|
|
40
|
+
size,
|
|
41
|
+
tone,
|
|
42
|
+
variant: emphasis,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function resolveCardVariant(tone: ZoraCardTone = 'default'): SurfaceCardProps['variant'] {
|
|
47
|
+
switch (tone) {
|
|
48
|
+
case 'outline':
|
|
49
|
+
return 'outline';
|
|
50
|
+
case 'subtle':
|
|
51
|
+
return 'subtle';
|
|
52
|
+
case 'default':
|
|
53
|
+
default:
|
|
54
|
+
return 'raised';
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function resolveDialogWidth(width: ZoraContentWidth = 'default'): number {
|
|
59
|
+
switch (width) {
|
|
60
|
+
case 'narrow':
|
|
61
|
+
return 420;
|
|
62
|
+
case 'wide':
|
|
63
|
+
return 560;
|
|
64
|
+
case 'default':
|
|
65
|
+
default:
|
|
66
|
+
return 520;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function resolvePageMaxWidth(width: ZoraContentWidth = 'default'): number {
|
|
71
|
+
switch (width) {
|
|
72
|
+
case 'narrow':
|
|
73
|
+
return 760;
|
|
74
|
+
case 'wide':
|
|
75
|
+
return 1280;
|
|
76
|
+
case 'default':
|
|
77
|
+
default:
|
|
78
|
+
return 1040;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function resolveIconSize(size: ZoraControlSize = 'l'): number {
|
|
83
|
+
switch (size) {
|
|
84
|
+
case 's':
|
|
85
|
+
return 16;
|
|
86
|
+
case 'm':
|
|
87
|
+
return 18;
|
|
88
|
+
case 'l':
|
|
89
|
+
default:
|
|
90
|
+
return 20;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Box, Stack } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { AppShellProps } from './types';
|
|
5
|
+
|
|
6
|
+
export function AppShell({ children, topbar, testID }: AppShellProps) {
|
|
7
|
+
return (
|
|
8
|
+
<Box bg="background" flex={1} testID={testID}>
|
|
9
|
+
<Stack gap="none">
|
|
10
|
+
{topbar ? <Box>{topbar}</Box> : null}
|
|
11
|
+
<Box flex={1}>{children}</Box>
|
|
12
|
+
</Stack>
|
|
13
|
+
</Box>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Center, Stack } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { Card } from '../../components/card';
|
|
5
|
+
import type { AuthLayoutProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function AuthLayout({
|
|
8
|
+
title,
|
|
9
|
+
description,
|
|
10
|
+
eyebrow,
|
|
11
|
+
children,
|
|
12
|
+
footer,
|
|
13
|
+
testID,
|
|
14
|
+
}: AuthLayoutProps) {
|
|
15
|
+
return (
|
|
16
|
+
<Center py="xl" testID={testID}>
|
|
17
|
+
<Card
|
|
18
|
+
compact
|
|
19
|
+
description={description}
|
|
20
|
+
eyebrow={eyebrow}
|
|
21
|
+
footer={footer}
|
|
22
|
+
title={title}
|
|
23
|
+
tone="default"
|
|
24
|
+
>
|
|
25
|
+
<Stack gap="m">{children}</Stack>
|
|
26
|
+
</Card>
|
|
27
|
+
</Center>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Container, Stack } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { resolvePageMaxWidth } from '../../internal/recipes';
|
|
5
|
+
import type { PageProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function Page({ children, header, footer, width = 'default', testID }: PageProps) {
|
|
8
|
+
return (
|
|
9
|
+
<Container maxWidth={resolvePageMaxWidth(width)} py="xl" testID={testID}>
|
|
10
|
+
<Stack gap="l">
|
|
11
|
+
{header}
|
|
12
|
+
{children}
|
|
13
|
+
{footer}
|
|
14
|
+
</Stack>
|
|
15
|
+
</Container>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { ZoraContentWidth } from '../../internal/recipes';
|
|
4
|
+
|
|
5
|
+
export interface PageProps {
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
header?: React.ReactNode;
|
|
8
|
+
footer?: React.ReactNode;
|
|
9
|
+
width?: ZoraContentWidth;
|
|
10
|
+
testID?: string;
|
|
11
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Box, Heading, Stack, Text } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { PageHeaderProps } from './types';
|
|
5
|
+
|
|
6
|
+
export function PageHeader({
|
|
7
|
+
title,
|
|
8
|
+
description,
|
|
9
|
+
eyebrow,
|
|
10
|
+
actions,
|
|
11
|
+
meta,
|
|
12
|
+
testID,
|
|
13
|
+
}: PageHeaderProps) {
|
|
14
|
+
return (
|
|
15
|
+
<Stack
|
|
16
|
+
align={{ base: 'flex-start', md: 'center' }}
|
|
17
|
+
direction={{ base: 'column', md: 'row' }}
|
|
18
|
+
gap="l"
|
|
19
|
+
justify="space-between"
|
|
20
|
+
testID={testID}
|
|
21
|
+
>
|
|
22
|
+
<Box flex={1}>
|
|
23
|
+
<Stack gap="s">
|
|
24
|
+
{eyebrow ? (
|
|
25
|
+
<Text tone="muted" variant="caption" weight="semiBold">
|
|
26
|
+
{eyebrow}
|
|
27
|
+
</Text>
|
|
28
|
+
) : null}
|
|
29
|
+
<Heading level={1}>{title}</Heading>
|
|
30
|
+
{description ? (
|
|
31
|
+
<Text tone="muted" variant="body">
|
|
32
|
+
{description}
|
|
33
|
+
</Text>
|
|
34
|
+
) : null}
|
|
35
|
+
{meta ? <Box pt="xs">{meta}</Box> : null}
|
|
36
|
+
</Stack>
|
|
37
|
+
</Box>
|
|
38
|
+
{actions ? <Box>{actions}</Box> : null}
|
|
39
|
+
</Stack>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Stack } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { SectionHeader } from '../../patterns/section-header';
|
|
5
|
+
import type { PageSectionProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function PageSection({ title, description, actions, children, testID }: PageSectionProps) {
|
|
8
|
+
return (
|
|
9
|
+
<Stack gap="m" testID={testID}>
|
|
10
|
+
{title ? <SectionHeader actions={actions} description={description} title={title} /> : null}
|
|
11
|
+
{children}
|
|
12
|
+
</Stack>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Page } from '../page';
|
|
4
|
+
import { PageHeader } from '../page-header';
|
|
5
|
+
import { SidebarLayout } from '../sidebar-layout';
|
|
6
|
+
import type { SettingsLayoutProps } from './types';
|
|
7
|
+
|
|
8
|
+
export function SettingsLayout({
|
|
9
|
+
title,
|
|
10
|
+
description,
|
|
11
|
+
sidebar,
|
|
12
|
+
children,
|
|
13
|
+
actions,
|
|
14
|
+
testID,
|
|
15
|
+
}: SettingsLayoutProps) {
|
|
16
|
+
return (
|
|
17
|
+
<Page
|
|
18
|
+
header={
|
|
19
|
+
title ? <PageHeader actions={actions} description={description} title={title} /> : null
|
|
20
|
+
}
|
|
21
|
+
testID={testID}
|
|
22
|
+
>
|
|
23
|
+
<SidebarLayout sidebar={sidebar}>{children}</SidebarLayout>
|
|
24
|
+
</Page>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Box, Stack } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { SidebarLayoutProps } from './types';
|
|
5
|
+
|
|
6
|
+
export function SidebarLayout({
|
|
7
|
+
sidebar,
|
|
8
|
+
children,
|
|
9
|
+
aside,
|
|
10
|
+
sidebarWidth = 280,
|
|
11
|
+
asideWidth = 280,
|
|
12
|
+
testID,
|
|
13
|
+
}: SidebarLayoutProps) {
|
|
14
|
+
return (
|
|
15
|
+
<Stack direction={{ base: 'column', lg: 'row' }} gap="l" testID={testID} align="flex-start">
|
|
16
|
+
<Box width={{ base: '100%', lg: sidebarWidth }}>{sidebar}</Box>
|
|
17
|
+
<Box flex={1} width="100%">
|
|
18
|
+
{children}
|
|
19
|
+
</Box>
|
|
20
|
+
{aside ? <Box width={{ base: '100%', lg: asideWidth }}>{aside}</Box> : null}
|
|
21
|
+
</Stack>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Box, Stack } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { SidebarLayout } from '../sidebar-layout';
|
|
5
|
+
import type { TopbarLayoutProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function TopbarLayout({ topbar, children, sidebar, testID }: TopbarLayoutProps) {
|
|
8
|
+
return (
|
|
9
|
+
<Stack gap="l" testID={testID}>
|
|
10
|
+
<Box>{topbar}</Box>
|
|
11
|
+
{sidebar ? <SidebarLayout sidebar={sidebar}>{children}</SidebarLayout> : children}
|
|
12
|
+
</Stack>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Box, Stack, Text } from '@ankhorage/surface';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { Button } from '../../components/button';
|
|
5
|
+
import { IconButton } from '../../components/icon-button';
|
|
6
|
+
import { Panel } from '../panel';
|
|
7
|
+
import type { CollectionEditorProps } from './types';
|
|
8
|
+
|
|
9
|
+
export function CollectionEditor<TItem>({
|
|
10
|
+
title,
|
|
11
|
+
description,
|
|
12
|
+
items,
|
|
13
|
+
renderItem,
|
|
14
|
+
onAdd,
|
|
15
|
+
onRemove,
|
|
16
|
+
onMove,
|
|
17
|
+
addLabel = 'Add Item',
|
|
18
|
+
emptyLabel = 'No items yet.',
|
|
19
|
+
disabled,
|
|
20
|
+
testID,
|
|
21
|
+
}: CollectionEditorProps<TItem>) {
|
|
22
|
+
const isEmpty = items.length === 0;
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<Panel
|
|
26
|
+
compact
|
|
27
|
+
description={description}
|
|
28
|
+
testID={testID}
|
|
29
|
+
title={title}
|
|
30
|
+
actions={
|
|
31
|
+
onAdd ? (
|
|
32
|
+
<Button emphasis="soft" size="s" disabled={disabled} onPress={onAdd}>
|
|
33
|
+
{addLabel}
|
|
34
|
+
</Button>
|
|
35
|
+
) : null
|
|
36
|
+
}
|
|
37
|
+
>
|
|
38
|
+
<Stack gap="s">
|
|
39
|
+
{isEmpty ? (
|
|
40
|
+
<Box py="m">
|
|
41
|
+
<Text align="center" tone="muted">
|
|
42
|
+
{emptyLabel}
|
|
43
|
+
</Text>
|
|
44
|
+
</Box>
|
|
45
|
+
) : (
|
|
46
|
+
items.map((item, index) => (
|
|
47
|
+
<Box key={index} bg="subtle" p="s" radius="m" borderColor="border" borderWidth={1}>
|
|
48
|
+
<Stack direction="row" gap="m" align="center">
|
|
49
|
+
<Box flex={1}>
|
|
50
|
+
{renderItem({
|
|
51
|
+
item,
|
|
52
|
+
index,
|
|
53
|
+
remove: () => onRemove?.(index),
|
|
54
|
+
moveUp: () => onMove?.(index, index - 1),
|
|
55
|
+
moveDown: () => onMove?.(index, index + 1),
|
|
56
|
+
canMoveUp: index > 0,
|
|
57
|
+
canMoveDown: index < items.length - 1,
|
|
58
|
+
})}
|
|
59
|
+
</Box>
|
|
60
|
+
<Stack direction="row" gap="xs">
|
|
61
|
+
{onMove ? (
|
|
62
|
+
<>
|
|
63
|
+
<IconButton
|
|
64
|
+
icon={{ name: 'arrow-up-outline' }}
|
|
65
|
+
label="Move Up"
|
|
66
|
+
disabled={disabled ?? index === 0}
|
|
67
|
+
onPress={() => onMove(index, index - 1)}
|
|
68
|
+
size="s"
|
|
69
|
+
emphasis="ghost"
|
|
70
|
+
/>
|
|
71
|
+
<IconButton
|
|
72
|
+
icon={{ name: 'arrow-down-outline' }}
|
|
73
|
+
label="Move Down"
|
|
74
|
+
disabled={disabled ?? index === items.length - 1}
|
|
75
|
+
onPress={() => onMove(index, index + 1)}
|
|
76
|
+
size="s"
|
|
77
|
+
emphasis="ghost"
|
|
78
|
+
/>
|
|
79
|
+
</>
|
|
80
|
+
) : null}
|
|
81
|
+
{onRemove ? (
|
|
82
|
+
<IconButton
|
|
83
|
+
icon={{ name: 'trash-outline' }}
|
|
84
|
+
label="Remove"
|
|
85
|
+
tone="danger"
|
|
86
|
+
disabled={disabled}
|
|
87
|
+
onPress={() => onRemove(index)}
|
|
88
|
+
size="s"
|
|
89
|
+
emphasis="ghost"
|
|
90
|
+
/>
|
|
91
|
+
) : null}
|
|
92
|
+
</Stack>
|
|
93
|
+
</Stack>
|
|
94
|
+
</Box>
|
|
95
|
+
))
|
|
96
|
+
)}
|
|
97
|
+
</Stack>
|
|
98
|
+
</Panel>
|
|
99
|
+
);
|
|
100
|
+
}
|