@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,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,2 @@
1
+ export { Button } from './Button';
2
+ export type { ButtonProps } from './types';
@@ -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,2 @@
1
+ export { Card } from './Card';
2
+ export type { CardProps } from './types';
@@ -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,2 @@
1
+ export { Drawer } from './Drawer';
2
+ export type { DrawerProps } from './types';
@@ -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,8 @@
1
+ import { Icon as SurfaceIcon, type IconProps as SurfaceIconProps } from '@ankhorage/surface';
2
+ import React from 'react';
3
+
4
+ export type IconProps = SurfaceIconProps;
5
+
6
+ export function Icon(props: IconProps) {
7
+ return <SurfaceIcon {...props} />;
8
+ }
@@ -0,0 +1,2 @@
1
+ export type { IconProps } from './Icon';
2
+ export { Icon } from './Icon';
@@ -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,2 @@
1
+ export * from './IconButton';
2
+ export * from './types';
@@ -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,2 @@
1
+ export { Input } from './Input';
2
+ export type { InputProps } from './types';
@@ -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,2 @@
1
+ export { Modal } from './Modal';
2
+ export type { ModalProps } from './types';
@@ -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,2 @@
1
+ export * from './Select';
2
+ export * from './types';
@@ -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,2 @@
1
+ export * from './Tabs';
2
+ export * from './types';
@@ -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,2 @@
1
+ export { Textarea } from './Textarea';
2
+ export type { TextareaProps } from './types';
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ export * from './Toolbar';
2
+ export * from './ToolbarAction';
3
+ export * from './types';