@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.
Files changed (229) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +0 -90
  3. package/dist/components/badge/Badge.js.map +1 -1
  4. package/dist/components/badge/index.js.map +1 -1
  5. package/dist/components/badge/types.js.map +1 -1
  6. package/dist/components/button/Button.js.map +1 -1
  7. package/dist/components/button/index.js.map +1 -1
  8. package/dist/components/button/types.js.map +1 -1
  9. package/dist/components/card/Card.js.map +1 -1
  10. package/dist/components/card/index.js.map +1 -1
  11. package/dist/components/card/types.js.map +1 -1
  12. package/dist/components/drawer/Drawer.js.map +1 -1
  13. package/dist/components/drawer/index.js.map +1 -1
  14. package/dist/components/drawer/types.js.map +1 -1
  15. package/dist/components/icon/Icon.js.map +1 -1
  16. package/dist/components/icon/index.js.map +1 -1
  17. package/dist/components/icon-button/IconButton.js.map +1 -1
  18. package/dist/components/icon-button/index.js.map +1 -1
  19. package/dist/components/icon-button/types.js.map +1 -1
  20. package/dist/components/input/Input.js.map +1 -1
  21. package/dist/components/input/index.js.map +1 -1
  22. package/dist/components/input/types.js.map +1 -1
  23. package/dist/components/modal/Modal.js.map +1 -1
  24. package/dist/components/modal/index.js.map +1 -1
  25. package/dist/components/modal/types.js.map +1 -1
  26. package/dist/components/select/Select.js.map +1 -1
  27. package/dist/components/select/index.js.map +1 -1
  28. package/dist/components/select/types.js.map +1 -1
  29. package/dist/components/tabs/Tabs.js.map +1 -1
  30. package/dist/components/tabs/index.js.map +1 -1
  31. package/dist/components/tabs/types.js.map +1 -1
  32. package/dist/components/textarea/Textarea.js.map +1 -1
  33. package/dist/components/textarea/index.js.map +1 -1
  34. package/dist/components/textarea/types.js.map +1 -1
  35. package/dist/components/toolbar/Toolbar.js.map +1 -1
  36. package/dist/components/toolbar/ToolbarAction.js.map +1 -1
  37. package/dist/components/toolbar/index.js.map +1 -1
  38. package/dist/components/toolbar/types.js.map +1 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/internal/deepMerge.js.map +1 -1
  41. package/dist/internal/recipes.js.map +1 -1
  42. package/dist/layout/app-shell/AppShell.js.map +1 -1
  43. package/dist/layout/app-shell/index.js.map +1 -1
  44. package/dist/layout/app-shell/types.js.map +1 -1
  45. package/dist/layout/auth-layout/AuthLayout.js.map +1 -1
  46. package/dist/layout/auth-layout/index.js.map +1 -1
  47. package/dist/layout/auth-layout/types.js.map +1 -1
  48. package/dist/layout/page/Page.js.map +1 -1
  49. package/dist/layout/page/index.js.map +1 -1
  50. package/dist/layout/page/types.js.map +1 -1
  51. package/dist/layout/page-header/PageHeader.js.map +1 -1
  52. package/dist/layout/page-header/index.js.map +1 -1
  53. package/dist/layout/page-header/types.js.map +1 -1
  54. package/dist/layout/page-section/PageSection.js.map +1 -1
  55. package/dist/layout/page-section/index.js.map +1 -1
  56. package/dist/layout/page-section/types.js.map +1 -1
  57. package/dist/layout/settings-layout/SettingsLayout.js.map +1 -1
  58. package/dist/layout/settings-layout/index.js.map +1 -1
  59. package/dist/layout/settings-layout/types.js.map +1 -1
  60. package/dist/layout/sidebar-layout/SidebarLayout.js.map +1 -1
  61. package/dist/layout/sidebar-layout/index.js.map +1 -1
  62. package/dist/layout/sidebar-layout/types.js.map +1 -1
  63. package/dist/layout/topbar-layout/TopbarLayout.js.map +1 -1
  64. package/dist/layout/topbar-layout/index.js.map +1 -1
  65. package/dist/layout/topbar-layout/types.js.map +1 -1
  66. package/dist/patterns/collection-editor/CollectionEditor.js.map +1 -1
  67. package/dist/patterns/collection-editor/index.js.map +1 -1
  68. package/dist/patterns/collection-editor/types.js.map +1 -1
  69. package/dist/patterns/confirm-dialog/ConfirmDialog.js.map +1 -1
  70. package/dist/patterns/confirm-dialog/index.js.map +1 -1
  71. package/dist/patterns/confirm-dialog/types.js.map +1 -1
  72. package/dist/patterns/disclosure-section/DisclosureSection.js.map +1 -1
  73. package/dist/patterns/disclosure-section/index.js.map +1 -1
  74. package/dist/patterns/disclosure-section/types.js.map +1 -1
  75. package/dist/patterns/empty-state/EmptyState.js.map +1 -1
  76. package/dist/patterns/empty-state/index.js.map +1 -1
  77. package/dist/patterns/empty-state/types.js.map +1 -1
  78. package/dist/patterns/form-field/FormField.js.map +1 -1
  79. package/dist/patterns/form-field/index.js.map +1 -1
  80. package/dist/patterns/form-field/types.js.map +1 -1
  81. package/dist/patterns/inspector-field/InspectorField.js.map +1 -1
  82. package/dist/patterns/inspector-field/index.js.map +1 -1
  83. package/dist/patterns/inspector-field/types.js.map +1 -1
  84. package/dist/patterns/notice/Notice.js.map +1 -1
  85. package/dist/patterns/notice/index.js.map +1 -1
  86. package/dist/patterns/notice/types.js.map +1 -1
  87. package/dist/patterns/panel/Panel.js.map +1 -1
  88. package/dist/patterns/panel/index.js.map +1 -1
  89. package/dist/patterns/panel/types.js.map +1 -1
  90. package/dist/patterns/responsive-panel/ResponsivePanel.js.map +1 -1
  91. package/dist/patterns/responsive-panel/index.js.map +1 -1
  92. package/dist/patterns/responsive-panel/types.js.map +1 -1
  93. package/dist/patterns/section-header/SectionHeader.js.map +1 -1
  94. package/dist/patterns/section-header/index.js.map +1 -1
  95. package/dist/patterns/section-header/types.js.map +1 -1
  96. package/dist/patterns/settings-row/SettingsRow.js.map +1 -1
  97. package/dist/patterns/settings-row/index.js.map +1 -1
  98. package/dist/patterns/settings-row/types.js.map +1 -1
  99. package/dist/patterns/switch-field/SwitchField.js.map +1 -1
  100. package/dist/patterns/switch-field/index.js.map +1 -1
  101. package/dist/patterns/switch-field/types.js.map +1 -1
  102. package/dist/patterns/tile-grid/PaletteItem.js.map +1 -1
  103. package/dist/patterns/tile-grid/TileGrid.js.map +1 -1
  104. package/dist/patterns/tile-grid/index.js.map +1 -1
  105. package/dist/patterns/tile-grid/types.js.map +1 -1
  106. package/dist/patterns/tree-view/TreeItem.js.map +1 -1
  107. package/dist/patterns/tree-view/TreeView.js.map +1 -1
  108. package/dist/patterns/tree-view/index.js.map +1 -1
  109. package/dist/patterns/tree-view/types.js.map +1 -1
  110. package/dist/theme/ZoraProvider.js.map +1 -1
  111. package/dist/theme/createZoraTheme.js.map +1 -1
  112. package/dist/theme/index.js.map +1 -1
  113. package/dist/theme/useZoraTheme.js.map +1 -1
  114. package/dist/theme/zoraTheme.js.map +1 -1
  115. package/package.json +15 -11
  116. package/src/components/badge/Badge.tsx +19 -0
  117. package/src/components/badge/index.ts +2 -0
  118. package/src/components/badge/types.ts +14 -0
  119. package/src/components/button/Button.tsx +13 -0
  120. package/src/components/button/index.ts +2 -0
  121. package/src/components/button/types.ts +16 -0
  122. package/src/components/card/Card.tsx +65 -0
  123. package/src/components/card/index.ts +2 -0
  124. package/src/components/card/types.ts +15 -0
  125. package/src/components/drawer/Drawer.tsx +27 -0
  126. package/src/components/drawer/index.ts +2 -0
  127. package/src/components/drawer/types.ts +12 -0
  128. package/src/components/icon/Icon.tsx +8 -0
  129. package/src/components/icon/index.ts +2 -0
  130. package/src/components/icon-button/IconButton.tsx +27 -0
  131. package/src/components/icon-button/index.ts +2 -0
  132. package/src/components/icon-button/types.ts +15 -0
  133. package/src/components/input/Input.tsx +38 -0
  134. package/src/components/input/index.ts +2 -0
  135. package/src/components/input/types.ts +12 -0
  136. package/src/components/modal/Modal.tsx +37 -0
  137. package/src/components/modal/index.ts +2 -0
  138. package/src/components/modal/types.ts +15 -0
  139. package/src/components/select/Select.tsx +49 -0
  140. package/src/components/select/index.ts +2 -0
  141. package/src/components/select/types.ts +14 -0
  142. package/src/components/tabs/Tabs.tsx +103 -0
  143. package/src/components/tabs/index.ts +2 -0
  144. package/src/components/tabs/types.ts +25 -0
  145. package/src/components/textarea/Textarea.tsx +38 -0
  146. package/src/components/textarea/index.ts +2 -0
  147. package/src/components/textarea/types.ts +12 -0
  148. package/src/components/toolbar/Toolbar.tsx +38 -0
  149. package/src/components/toolbar/ToolbarAction.tsx +15 -0
  150. package/src/components/toolbar/index.ts +3 -0
  151. package/src/components/toolbar/types.ts +21 -0
  152. package/src/index.ts +72 -0
  153. package/src/internal/deepMerge.ts +23 -0
  154. package/src/internal/recipes.test.ts +46 -0
  155. package/src/internal/recipes.ts +92 -0
  156. package/src/layout/app-shell/AppShell.tsx +15 -0
  157. package/src/layout/app-shell/index.ts +2 -0
  158. package/src/layout/app-shell/types.ts +7 -0
  159. package/src/layout/auth-layout/AuthLayout.tsx +29 -0
  160. package/src/layout/auth-layout/index.ts +2 -0
  161. package/src/layout/auth-layout/types.ts +10 -0
  162. package/src/layout/page/Page.tsx +17 -0
  163. package/src/layout/page/index.ts +2 -0
  164. package/src/layout/page/types.ts +11 -0
  165. package/src/layout/page-header/PageHeader.tsx +41 -0
  166. package/src/layout/page-header/index.ts +2 -0
  167. package/src/layout/page-header/types.ts +10 -0
  168. package/src/layout/page-section/PageSection.tsx +14 -0
  169. package/src/layout/page-section/index.ts +2 -0
  170. package/src/layout/page-section/types.ts +9 -0
  171. package/src/layout/settings-layout/SettingsLayout.tsx +26 -0
  172. package/src/layout/settings-layout/index.ts +2 -0
  173. package/src/layout/settings-layout/types.ts +10 -0
  174. package/src/layout/sidebar-layout/SidebarLayout.tsx +23 -0
  175. package/src/layout/sidebar-layout/index.ts +2 -0
  176. package/src/layout/sidebar-layout/types.ts +10 -0
  177. package/src/layout/topbar-layout/TopbarLayout.tsx +14 -0
  178. package/src/layout/topbar-layout/index.ts +2 -0
  179. package/src/layout/topbar-layout/types.ts +8 -0
  180. package/src/patterns/collection-editor/CollectionEditor.tsx +100 -0
  181. package/src/patterns/collection-editor/index.ts +2 -0
  182. package/src/patterns/collection-editor/types.ts +25 -0
  183. package/src/patterns/confirm-dialog/ConfirmDialog.tsx +46 -0
  184. package/src/patterns/confirm-dialog/index.ts +2 -0
  185. package/src/patterns/confirm-dialog/types.ts +19 -0
  186. package/src/patterns/disclosure-section/DisclosureSection.tsx +61 -0
  187. package/src/patterns/disclosure-section/index.ts +2 -0
  188. package/src/patterns/disclosure-section/types.ts +15 -0
  189. package/src/patterns/empty-state/EmptyState.tsx +53 -0
  190. package/src/patterns/empty-state/index.ts +2 -0
  191. package/src/patterns/empty-state/types.ts +20 -0
  192. package/src/patterns/form-field/FormField.tsx +27 -0
  193. package/src/patterns/form-field/index.ts +2 -0
  194. package/src/patterns/form-field/types.ts +11 -0
  195. package/src/patterns/inspector-field/InspectorField.tsx +16 -0
  196. package/src/patterns/inspector-field/index.ts +2 -0
  197. package/src/patterns/inspector-field/types.ts +15 -0
  198. package/src/patterns/notice/Notice.tsx +30 -0
  199. package/src/patterns/notice/index.ts +2 -0
  200. package/src/patterns/notice/types.ts +12 -0
  201. package/src/patterns/panel/Panel.tsx +8 -0
  202. package/src/patterns/panel/index.ts +2 -0
  203. package/src/patterns/panel/types.ts +15 -0
  204. package/src/patterns/responsive-panel/ResponsivePanel.tsx +70 -0
  205. package/src/patterns/responsive-panel/index.ts +2 -0
  206. package/src/patterns/responsive-panel/types.ts +20 -0
  207. package/src/patterns/section-header/SectionHeader.tsx +39 -0
  208. package/src/patterns/section-header/index.ts +2 -0
  209. package/src/patterns/section-header/types.ts +9 -0
  210. package/src/patterns/settings-row/SettingsRow.tsx +40 -0
  211. package/src/patterns/settings-row/index.ts +2 -0
  212. package/src/patterns/settings-row/types.ts +27 -0
  213. package/src/patterns/switch-field/SwitchField.tsx +24 -0
  214. package/src/patterns/switch-field/index.ts +2 -0
  215. package/src/patterns/switch-field/types.ts +10 -0
  216. package/src/patterns/tile-grid/PaletteItem.tsx +49 -0
  217. package/src/patterns/tile-grid/TileGrid.tsx +44 -0
  218. package/src/patterns/tile-grid/index.ts +3 -0
  219. package/src/patterns/tile-grid/types.ts +20 -0
  220. package/src/patterns/tree-view/TreeItem.tsx +86 -0
  221. package/src/patterns/tree-view/TreeView.tsx +50 -0
  222. package/src/patterns/tree-view/index.ts +3 -0
  223. package/src/patterns/tree-view/types.ts +31 -0
  224. package/src/theme/ZoraProvider.tsx +22 -0
  225. package/src/theme/createZoraTheme.test.ts +25 -0
  226. package/src/theme/createZoraTheme.ts +10 -0
  227. package/src/theme/index.ts +6 -0
  228. package/src/theme/useZoraTheme.ts +5 -0
  229. package/src/theme/zoraTheme.ts +16 -0
@@ -0,0 +1,2 @@
1
+ export * from './CollectionEditor';
2
+ export * from './types';
@@ -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,2 @@
1
+ export { ConfirmDialog } from './ConfirmDialog';
2
+ export type { ConfirmDialogProps } from './types';
@@ -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,2 @@
1
+ export * from './DisclosureSection';
2
+ export * from './types';
@@ -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,2 @@
1
+ export { EmptyState } from './EmptyState';
2
+ export type { EmptyStateAction, EmptyStateProps } from './types';
@@ -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,2 @@
1
+ export { FormField } from './FormField';
2
+ export type { FormFieldProps } from './types';
@@ -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,2 @@
1
+ export * from './InspectorField';
2
+ export * from './types';
@@ -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,2 @@
1
+ export { Notice } from './Notice';
2
+ export type { NoticeProps } from './types';
@@ -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,8 @@
1
+ import React from 'react';
2
+
3
+ import { Card } from '../../components/card';
4
+ import type { PanelProps } from './types';
5
+
6
+ export function Panel(props: PanelProps) {
7
+ return <Card {...props} />;
8
+ }
@@ -0,0 +1,2 @@
1
+ export { Panel } from './Panel';
2
+ export type { PanelProps } from './types';
@@ -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,2 @@
1
+ export * from './ResponsivePanel';
2
+ export * from './types';
@@ -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,2 @@
1
+ export { SectionHeader } from './SectionHeader';
2
+ export type { SectionHeaderProps } from './types';
@@ -0,0 +1,9 @@
1
+ import type React from 'react';
2
+
3
+ export interface SectionHeaderProps {
4
+ title: React.ReactNode;
5
+ description?: React.ReactNode;
6
+ eyebrow?: React.ReactNode;
7
+ actions?: React.ReactNode;
8
+ testID?: string;
9
+ }
@@ -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,2 @@
1
+ export { SettingsRow } from './SettingsRow';
2
+ export type { SettingsRowProps } from './types';
@@ -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
+ }