@ankhorage/zora 0.0.3 → 0.1.0

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 (153) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1207 -18
  3. package/dist/components/card/types.d.ts +1 -1
  4. package/dist/components/card/types.d.ts.map +1 -1
  5. package/dist/components/icon-button/IconButton.d.ts +4 -0
  6. package/dist/components/icon-button/IconButton.d.ts.map +1 -0
  7. package/dist/components/icon-button/IconButton.js +8 -0
  8. package/dist/components/icon-button/IconButton.js.map +1 -0
  9. package/dist/components/icon-button/index.d.ts +3 -0
  10. package/dist/components/icon-button/index.d.ts.map +1 -0
  11. package/dist/components/icon-button/index.js +3 -0
  12. package/dist/components/icon-button/index.js.map +1 -0
  13. package/dist/components/icon-button/types.d.ts +14 -0
  14. package/dist/components/icon-button/types.d.ts.map +1 -0
  15. package/dist/components/icon-button/types.js +2 -0
  16. package/dist/components/icon-button/types.js.map +1 -0
  17. package/dist/components/select/Select.d.ts +4 -0
  18. package/dist/components/select/Select.d.ts.map +1 -0
  19. package/dist/components/select/Select.js +18 -0
  20. package/dist/components/select/Select.js.map +1 -0
  21. package/dist/components/select/index.d.ts +3 -0
  22. package/dist/components/select/index.d.ts.map +1 -0
  23. package/dist/components/select/index.js +3 -0
  24. package/dist/components/select/index.js.map +1 -0
  25. package/dist/components/select/types.d.ts +14 -0
  26. package/dist/components/select/types.d.ts.map +1 -0
  27. package/dist/components/select/types.js +2 -0
  28. package/dist/components/select/types.js.map +1 -0
  29. package/dist/components/tabs/Tabs.d.ts +4 -0
  30. package/dist/components/tabs/Tabs.d.ts.map +1 -0
  31. package/dist/components/tabs/Tabs.js +37 -0
  32. package/dist/components/tabs/Tabs.js.map +1 -0
  33. package/dist/components/tabs/index.d.ts +3 -0
  34. package/dist/components/tabs/index.d.ts.map +1 -0
  35. package/dist/components/tabs/index.js +3 -0
  36. package/dist/components/tabs/index.js.map +1 -0
  37. package/dist/components/tabs/types.d.ts +22 -0
  38. package/dist/components/tabs/types.d.ts.map +1 -0
  39. package/dist/components/tabs/types.js +2 -0
  40. package/dist/components/tabs/types.js.map +1 -0
  41. package/dist/components/toolbar/Toolbar.d.ts +4 -0
  42. package/dist/components/toolbar/Toolbar.d.ts.map +1 -0
  43. package/dist/components/toolbar/Toolbar.js +20 -0
  44. package/dist/components/toolbar/Toolbar.js.map +1 -0
  45. package/dist/components/toolbar/ToolbarAction.d.ts +4 -0
  46. package/dist/components/toolbar/ToolbarAction.d.ts.map +1 -0
  47. package/dist/components/toolbar/ToolbarAction.js +6 -0
  48. package/dist/components/toolbar/ToolbarAction.js.map +1 -0
  49. package/dist/components/toolbar/index.d.ts +4 -0
  50. package/dist/components/toolbar/index.d.ts.map +1 -0
  51. package/dist/components/toolbar/index.js +4 -0
  52. package/dist/components/toolbar/index.js.map +1 -0
  53. package/dist/components/toolbar/types.d.ts +19 -0
  54. package/dist/components/toolbar/types.d.ts.map +1 -0
  55. package/dist/components/toolbar/types.js +2 -0
  56. package/dist/components/toolbar/types.js.map +1 -0
  57. package/dist/index.d.ts +22 -0
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +11 -0
  60. package/dist/index.js.map +1 -1
  61. package/dist/patterns/collection-editor/CollectionEditor.d.ts +4 -0
  62. package/dist/patterns/collection-editor/CollectionEditor.d.ts.map +1 -0
  63. package/dist/patterns/collection-editor/CollectionEditor.js +41 -0
  64. package/dist/patterns/collection-editor/CollectionEditor.js.map +1 -0
  65. package/dist/patterns/collection-editor/index.d.ts +3 -0
  66. package/dist/patterns/collection-editor/index.d.ts.map +1 -0
  67. package/dist/patterns/collection-editor/index.js +3 -0
  68. package/dist/patterns/collection-editor/index.js.map +1 -0
  69. package/dist/patterns/collection-editor/types.d.ts +24 -0
  70. package/dist/patterns/collection-editor/types.d.ts.map +1 -0
  71. package/dist/patterns/collection-editor/types.js +2 -0
  72. package/dist/patterns/collection-editor/types.js.map +1 -0
  73. package/dist/patterns/disclosure-section/DisclosureSection.d.ts +4 -0
  74. package/dist/patterns/disclosure-section/DisclosureSection.d.ts.map +1 -0
  75. package/dist/patterns/disclosure-section/DisclosureSection.js +27 -0
  76. package/dist/patterns/disclosure-section/DisclosureSection.js.map +1 -0
  77. package/dist/patterns/disclosure-section/index.d.ts +3 -0
  78. package/dist/patterns/disclosure-section/index.d.ts.map +1 -0
  79. package/dist/patterns/disclosure-section/index.js +3 -0
  80. package/dist/patterns/disclosure-section/index.js.map +1 -0
  81. package/dist/patterns/disclosure-section/types.d.ts +15 -0
  82. package/dist/patterns/disclosure-section/types.d.ts.map +1 -0
  83. package/dist/patterns/disclosure-section/types.js +2 -0
  84. package/dist/patterns/disclosure-section/types.js.map +1 -0
  85. package/dist/patterns/inspector-field/InspectorField.d.ts +4 -0
  86. package/dist/patterns/inspector-field/InspectorField.d.ts.map +1 -0
  87. package/dist/patterns/inspector-field/InspectorField.js +12 -0
  88. package/dist/patterns/inspector-field/InspectorField.js.map +1 -0
  89. package/dist/patterns/inspector-field/index.d.ts +3 -0
  90. package/dist/patterns/inspector-field/index.d.ts.map +1 -0
  91. package/dist/patterns/inspector-field/index.js +3 -0
  92. package/dist/patterns/inspector-field/index.js.map +1 -0
  93. package/dist/patterns/inspector-field/types.d.ts +15 -0
  94. package/dist/patterns/inspector-field/types.d.ts.map +1 -0
  95. package/dist/patterns/inspector-field/types.js +2 -0
  96. package/dist/patterns/inspector-field/types.js.map +1 -0
  97. package/dist/patterns/responsive-panel/ResponsivePanel.d.ts +4 -0
  98. package/dist/patterns/responsive-panel/ResponsivePanel.d.ts.map +1 -0
  99. package/dist/patterns/responsive-panel/ResponsivePanel.js +25 -0
  100. package/dist/patterns/responsive-panel/ResponsivePanel.js.map +1 -0
  101. package/dist/patterns/responsive-panel/index.d.ts +3 -0
  102. package/dist/patterns/responsive-panel/index.d.ts.map +1 -0
  103. package/dist/patterns/responsive-panel/index.js +3 -0
  104. package/dist/patterns/responsive-panel/index.js.map +1 -0
  105. package/dist/patterns/responsive-panel/types.d.ts +19 -0
  106. package/dist/patterns/responsive-panel/types.d.ts.map +1 -0
  107. package/dist/patterns/responsive-panel/types.js +2 -0
  108. package/dist/patterns/responsive-panel/types.js.map +1 -0
  109. package/dist/patterns/switch-field/SwitchField.d.ts +4 -0
  110. package/dist/patterns/switch-field/SwitchField.d.ts.map +1 -0
  111. package/dist/patterns/switch-field/SwitchField.js +7 -0
  112. package/dist/patterns/switch-field/SwitchField.js.map +1 -0
  113. package/dist/patterns/switch-field/index.d.ts +3 -0
  114. package/dist/patterns/switch-field/index.d.ts.map +1 -0
  115. package/dist/patterns/switch-field/index.js +3 -0
  116. package/dist/patterns/switch-field/index.js.map +1 -0
  117. package/dist/patterns/switch-field/types.d.ts +10 -0
  118. package/dist/patterns/switch-field/types.d.ts.map +1 -0
  119. package/dist/patterns/switch-field/types.js +2 -0
  120. package/dist/patterns/switch-field/types.js.map +1 -0
  121. package/dist/patterns/tile-grid/PaletteItem.d.ts +4 -0
  122. package/dist/patterns/tile-grid/PaletteItem.d.ts.map +1 -0
  123. package/dist/patterns/tile-grid/PaletteItem.js +24 -0
  124. package/dist/patterns/tile-grid/PaletteItem.js.map +1 -0
  125. package/dist/patterns/tile-grid/TileGrid.d.ts +4 -0
  126. package/dist/patterns/tile-grid/TileGrid.d.ts.map +1 -0
  127. package/dist/patterns/tile-grid/TileGrid.js +26 -0
  128. package/dist/patterns/tile-grid/TileGrid.js.map +1 -0
  129. package/dist/patterns/tile-grid/index.d.ts +4 -0
  130. package/dist/patterns/tile-grid/index.d.ts.map +1 -0
  131. package/dist/patterns/tile-grid/index.js +4 -0
  132. package/dist/patterns/tile-grid/index.js.map +1 -0
  133. package/dist/patterns/tile-grid/types.d.ts +19 -0
  134. package/dist/patterns/tile-grid/types.d.ts.map +1 -0
  135. package/dist/patterns/tile-grid/types.js +2 -0
  136. package/dist/patterns/tile-grid/types.js.map +1 -0
  137. package/dist/patterns/tree-view/TreeItem.d.ts +14 -0
  138. package/dist/patterns/tree-view/TreeItem.d.ts.map +1 -0
  139. package/dist/patterns/tree-view/TreeItem.js +31 -0
  140. package/dist/patterns/tree-view/TreeItem.js.map +1 -0
  141. package/dist/patterns/tree-view/TreeView.d.ts +4 -0
  142. package/dist/patterns/tree-view/TreeView.d.ts.map +1 -0
  143. package/dist/patterns/tree-view/TreeView.js +20 -0
  144. package/dist/patterns/tree-view/TreeView.js.map +1 -0
  145. package/dist/patterns/tree-view/index.d.ts +4 -0
  146. package/dist/patterns/tree-view/index.d.ts.map +1 -0
  147. package/dist/patterns/tree-view/index.js +4 -0
  148. package/dist/patterns/tree-view/index.js.map +1 -0
  149. package/dist/patterns/tree-view/types.d.ts +29 -0
  150. package/dist/patterns/tree-view/types.d.ts.map +1 -0
  151. package/dist/patterns/tree-view/types.js +2 -0
  152. package/dist/patterns/tree-view/types.js.map +1 -0
  153. package/package.json +6 -1
package/README.md CHANGED
@@ -1,32 +1,1221 @@
1
1
  # zora
2
2
 
3
- A UI framework for React Native and Web.
3
+ <!-- markdownlint-disable MD013 MD033 -->
4
4
 
5
- ## 🎯 What you get
6
- - Build full screens, not just primitives
7
- - Consistent spacing and typography
8
- - Works out of the box with Expo + Web
5
+ Opinionated React Native and React Native Web UI kit built on
6
+ `@ankhorage/surface`.
9
7
 
10
- ## Features
11
- - Ready-to-use UI components
12
- - Design consistency
13
- - Built on primitives
8
+ ZORA sits above Surface. Surface provides the foundation primitives, theme system,
9
+ and low-level controls; ZORA adds product-facing components, app layouts, and
10
+ ready-made patterns with stronger defaults.
11
+
12
+ ## Install
14
13
 
15
- ## 🚀 Installation
16
14
  ```bash
17
15
  bun add @ankhorage/zora
18
16
  ```
19
17
 
20
- ## 📦 Usage
18
+ Peer dependencies:
19
+
20
+ - `react >=18.2.0`
21
+ - `react-native >=0.72.0`
22
+ - `@expo/vector-icons >=14.0.0` when using icon specs
23
+ - `expo-font >=14.0.4` when using runtime font registration
24
+
25
+ ## Quick Start
26
+
27
+ Wrap your app in `ZoraProvider`, then import components from
28
+ `@ankhorage/zora`.
29
+
30
+ ```tsx
31
+ import React from 'react';
32
+ import { Button, Card, Page, PageHeader, ZoraProvider } from '@ankhorage/zora';
33
+
34
+ export function App() {
35
+ return (
36
+ <ZoraProvider>
37
+ <Page header={<PageHeader title="Dashboard" description="Ready to build." />}>
38
+ <Card
39
+ actions={<Button>Continue</Button>}
40
+ description="ZORA provides composed UI surfaces for apps."
41
+ title="Welcome"
42
+ />
43
+ </Page>
44
+ </ZoraProvider>
45
+ );
46
+ }
47
+ ```
48
+
49
+ ## Shared Types
50
+
51
+ These unions appear across the catalogue:
52
+
53
+ - `ZoraTone` comes from Surface `ButtonProps['tone']`.
54
+ - `ZoraEmphasis` comes from Surface `ButtonProps['variant']`.
55
+ - `ZoraBadgeEmphasis` comes from Surface `BadgeProps['variant']`.
56
+ - `ZoraControlSize` comes from Surface `ButtonProps['size']`.
57
+ - `ZoraCardTone = 'default' | 'subtle' | 'outline'`.
58
+ - `ZoraContentWidth = 'narrow' | 'default' | 'wide'`.
59
+
60
+ Width presets:
61
+
62
+ - Dialog widths: `narrow=420`, `default=520`, `wide=560`.
63
+ - Page widths: `narrow=760`, `default=1040`, `wide=1280`.
64
+
65
+ ## Components
66
+
67
+ ### `Button`
68
+
69
+ Action button with ZORA defaults for tone, emphasis, size, and icons.
70
+
71
+ ```tsx
72
+ <Button leadingIcon={{ name: 'checkmark-circle-outline' }}>Save</Button>
73
+ ```
74
+
75
+ <details>
76
+ <summary>Props</summary>
77
+
78
+ ZORA props:
79
+
80
+ | Prop | Type | Default | Notes |
81
+ | --- | --- | --- | --- |
82
+ | `children` | `React.ReactNode` | - | Button label or content. |
83
+ | `tone` | `ZoraTone` | `'primary'` | Passed to Surface as `tone`. |
84
+ | `emphasis` | `ZoraEmphasis` | `'solid'` | Passed to Surface as `variant`. |
85
+ | `size` | `ZoraControlSize` | `'l'` | Passed to Surface as `size`. |
86
+ | `leadingIcon` | `ButtonIconSpec` | - | Surface icon spec rendered before content. |
87
+ | `trailingIcon` | `ButtonIconSpec` | - | Surface icon spec rendered after content. |
88
+
89
+ Inherited props:
90
+
91
+ Inherits all Surface `ButtonProps` except `children`, `size`, `tone`, and
92
+ `variant`. This includes Surface button behavior such as `loading`,
93
+ `fullWidth`, pressability props, disabled state, accessibility props allowed by
94
+ Surface, and `testID`.
95
+
96
+ </details>
97
+
98
+ ### `IconButton`
99
+
100
+ Compact icon-only button for toolbars, rows, and actions.
101
+
102
+ ```tsx
103
+ <IconButton icon={{ name: 'trash-outline' }} label="Delete" tone="danger" />
104
+ ```
105
+
106
+ <details>
107
+ <summary>Props</summary>
108
+
109
+ ZORA props:
110
+
111
+ | Prop | Type | Default | Notes |
112
+ | --- | --- | --- | --- |
113
+ | `icon` | `ButtonIconSpec` | - | Required icon to render. |
114
+ | `label` | `string` | - | Required for `accessibilityLabel`. |
115
+ | `tone` | `ZoraTone` | `'neutral'` | Button tone. |
116
+ | `emphasis` | `ZoraEmphasis` | `'ghost'` | Button emphasis. |
117
+ | `size` | `ZoraControlSize` | `'m'` | Button size. |
118
+
119
+ Inherited props:
120
+
121
+ Inherits behavior from Surface `IconButton` including `disabled`, `loading`,
122
+ `onPress`, and `testID`.
123
+
124
+ </details>
125
+
126
+ ### `Badge`
127
+
128
+ Small status label with ZORA tone, emphasis, and size defaults.
129
+
130
+ ```tsx
131
+ <Badge tone="success">Active</Badge>
132
+ ```
133
+
134
+ <details>
135
+ <summary>Props</summary>
136
+
137
+ ZORA props:
138
+
139
+ | Prop | Type | Default | Notes |
140
+ | --- | --- | --- | --- |
141
+ | `children` | `React.ReactNode` | - | Rendered as Surface badge `content`. |
142
+ | `tone` | `ZoraTone` | `'primary'` | Passed to Surface as `tone`. |
143
+ | `emphasis` | `ZoraBadgeEmphasis` | `'soft'` | Passed to Surface as `variant`. |
144
+ | `size` | `ZoraControlSize` | `'m'` | Passed to Surface as `size`. |
145
+
146
+ Inherited props:
147
+
148
+ Inherits all Surface `BadgeProps` except `content`, `size`, `tone`, and
149
+ `variant`. The remaining inherited prop is `testID`.
150
+
151
+ </details>
152
+
153
+ ### `Card`
154
+
155
+ Composed content surface with optional header, actions, footer, and ZORA card
156
+ tones.
157
+
158
+ ```tsx
159
+ <Card
160
+ actions={<Button>Open</Button>}
161
+ description="A reusable product surface."
162
+ title="Project"
163
+ />
164
+ ```
165
+
166
+ <details>
167
+ <summary>Props</summary>
168
+
169
+ ZORA props:
170
+
171
+ | Prop | Type | Default | Notes |
172
+ | --- | --- | --- | --- |
173
+ | `children` | `React.ReactNode` | - | Main card body. |
174
+ | `title` | `React.ReactNode` | - | Header title. |
175
+ | `description` | `React.ReactNode` | - | Header description. |
176
+ | `eyebrow` | `React.ReactNode` | - | Small muted text above the title. |
177
+ | `actions` | `React.ReactNode` | - | Header action area. |
178
+ | `footer` | `React.ReactNode` | - | Footer area below body content. |
179
+ | `tone` | `ZoraCardTone` | `'default'` | Maps to Surface variants: `default -> raised`, `subtle -> subtle`, `outline -> outline`. |
180
+ | `compact` | `boolean` | `false` | Uses tighter padding and heading scale. |
181
+
182
+ Inherited props:
183
+
184
+ Inherits all Surface `CardProps` except `children`, `p`, `radius`, `variant`, and
185
+ `style`. ZORA owns spacing, radius, and variant selection for this wrapper.
186
+
187
+ </details>
188
+
189
+ ### `Input`
190
+
191
+ Text input wrapper with ZORA sizing and optional Surface icon specs.
192
+
193
+ ```tsx
194
+ <Input
195
+ autoCapitalize="none"
196
+ keyboardType="email-address"
197
+ leadingIcon={{ name: 'mail-outline' }}
198
+ placeholder="you@example.com"
199
+ />
200
+ ```
201
+
202
+ <details>
203
+ <summary>Props</summary>
204
+
205
+ ZORA props:
206
+
207
+ | Prop | Type | Default | Notes |
208
+ | --- | --- | --- | --- |
209
+ | `size` | `ZoraControlSize` | `'l'` | Passed to Surface as `size`. |
210
+ | `leadingIcon` | `ButtonIconSpec` | - | Rendered as Surface `leadingAccessory`. |
211
+ | `trailingIcon` | `ButtonIconSpec` | - | Rendered as Surface `trailingAccessory`. |
212
+
213
+ Inherited props:
214
+
215
+ Inherits all Surface `TextInputProps` except `leadingAccessory`, `size`, and
216
+ `trailingAccessory`. Surface `TextInputProps` also inherit React Native
217
+ `TextInputProps` except `defaultValue`, `editable`, `onChangeText`,
218
+ `placeholderTextColor`, `style`, `testID`, and `value`; Surface re-exposes
219
+ `value`, `defaultValue`, `onChangeText`, `placeholder`, `disabled`, `readOnly`,
220
+ `invalid`, `style`, and `testID`.
221
+
222
+ </details>
223
+
224
+ ### `Textarea`
225
+
226
+ Multiline text input wrapper with ZORA sizing and optional Surface icon specs.
227
+
228
+ ```tsx
229
+ <Textarea leadingIcon={{ name: 'document-text-outline' }} rows={5} />
230
+ ```
231
+
232
+ <details>
233
+ <summary>Props</summary>
234
+
235
+ ZORA props:
236
+
237
+ | Prop | Type | Default | Notes |
238
+ | --- | --- | --- | --- |
239
+ | `size` | `ZoraControlSize` | `'l'` | Passed to Surface as `size`. |
240
+ | `leadingIcon` | `ButtonIconSpec` | - | Rendered as Surface `leadingAccessory`. |
241
+ | `trailingIcon` | `ButtonIconSpec` | - | Rendered as Surface `trailingAccessory`. |
242
+
243
+ Inherited props:
244
+
245
+ Inherits all Surface `TextareaProps` except `leadingAccessory`, `size`, and
246
+ `trailingAccessory`. Surface `TextareaProps` extend Surface `TextInputProps`
247
+ except `multiline`, so React Native text input props are available through
248
+ Surface with the same Surface exclusions and re-exposed values listed for
249
+ `Input`.
250
+
251
+ </details>
252
+
253
+ ### `Tabs`
254
+
255
+ Generic controlled tabs for navigation and filtering.
256
+
257
+ ```tsx
258
+ <Tabs
259
+ items={[
260
+ { value: 'all', label: 'All' },
261
+ { value: 'active', label: 'Active' },
262
+ ]}
263
+ onValueChange={setValue}
264
+ value={value}
265
+ />
266
+ ```
267
+
268
+ <details>
269
+ <summary>Props</summary>
270
+
271
+ ZORA props:
272
+
273
+ | Prop | Type | Default | Notes |
274
+ | --- | --- | --- | --- |
275
+ | `value` | `string` | - | Active tab value. |
276
+ | `items` | `TabItem[]` | - | Array of tab objects. |
277
+ | `onValueChange` | `(value: string) => void` | - | Change handler. |
278
+ | `variant` | `'underline' \| 'pill' \| 'segmented'` | `'underline'` | Visual style. |
279
+ | `size` | `ZoraControlSize` | `'m'` | Control size. |
280
+
281
+ </details>
282
+
283
+ ### `Toolbar`
284
+
285
+ Horizontal shell for actions and tools.
286
+
287
+ ```tsx
288
+ <Toolbar>
289
+ <ToolbarAction icon={{ name: 'add-outline' }} label="Add" />
290
+ <ToolbarAction icon={{ name: 'search-outline' }} label="Search" />
291
+ </Toolbar>
292
+ ```
293
+
294
+ <details>
295
+ <summary>Props</summary>
296
+
297
+ `Toolbar` props:
298
+
299
+ | Prop | Type | Default | Notes |
300
+ | --- | --- | --- | --- |
301
+ | `children` | `React.ReactNode` | - | Toolbar content. |
302
+ | `position` | `'top' \| 'bottom' \| 'inline'` | `'inline'` | Layout position. |
303
+ | `floating` | `boolean` | `false` | Whether the toolbar floats with a shadow. |
304
+ | `compact` | `boolean` | `true` | Tighter padding. |
305
+
306
+ `ToolbarAction` props:
307
+
308
+ | Prop | Type | Default | Notes |
309
+ | --- | --- | --- | --- |
310
+ | `icon` | `ButtonIconSpec` | - | Required icon. |
311
+ | `label` | `string` | - | Accessibility label. |
312
+ | `active` | `boolean` | `false` | Highlighted state. |
313
+ | `onPress` | `() => void` | - | Click handler. |
314
+
315
+ </details>
316
+
317
+ ### `Select`
318
+
319
+ Standard dropdown selector wrapping `@react-native-picker/picker`.
320
+
321
+ ```tsx
322
+ <Select
323
+ onValueChange={setValue}
324
+ options={[
325
+ { value: '1', label: 'Option 1' },
326
+ { value: '2', label: 'Option 2' },
327
+ ]}
328
+ value={value}
329
+ />
330
+ ```
331
+
332
+ <details>
333
+ <summary>Props</summary>
334
+
335
+ ZORA props:
336
+
337
+ | Prop | Type | Default | Notes |
338
+ | --- | --- | --- | --- |
339
+ | `value` | `string` | - | Selected value. |
340
+ | `options` | `SelectOption[]` | - | Array of option objects. |
341
+ | `onValueChange` | `(value: string) => void` | - | Change handler. |
342
+ | `invalid` | `boolean` | `false` | Error state styling. |
343
+ | `disabled` | `boolean` | `false` | Interaction state. |
344
+
345
+ </details>
346
+
347
+ ### `Modal`
348
+
349
+ Centered overlay shell with optional header, body, footer, and width preset.
350
+
351
+ ```tsx
352
+ <Modal
353
+ footer={<Button>Done</Button>}
354
+ onDismiss={close}
355
+ title="Details"
356
+ visible={visible}
357
+ />
358
+ ```
359
+
360
+ <details>
361
+ <summary>Props</summary>
362
+
363
+ ZORA props:
364
+
365
+ | Prop | Type | Default | Notes |
366
+ | --- | --- | --- | --- |
367
+ | `children` | `React.ReactNode` | - | Modal body. |
368
+ | `title` | `React.ReactNode` | - | Header title. |
369
+ | `description` | `React.ReactNode` | - | Header description. |
370
+ | `footer` | `React.ReactNode` | - | Footer area. |
371
+ | `width` | `ZoraContentWidth` | `'default'` | Resolves to `420`, `520`, or `560` pixels. |
372
+
373
+ Inherited props:
374
+
375
+ Picks these Surface `ModalProps`: `closeOnBackdrop`, `onDismiss`, `testID`, and
376
+ `visible`.
377
+
378
+ </details>
379
+
380
+ ### `Drawer`
381
+
382
+ Side overlay shell with optional header, body, and footer.
383
+
384
+ ```tsx
385
+ <Drawer onDismiss={close} title="Filters" visible={visible}>
386
+ {content}
387
+ </Drawer>
388
+ ```
389
+
390
+ <details>
391
+ <summary>Props</summary>
392
+
393
+ ZORA props:
394
+
395
+ | Prop | Type | Default | Notes |
396
+ | --- | --- | --- | --- |
397
+ | `children` | `React.ReactNode` | - | Drawer body. |
398
+ | `title` | `React.ReactNode` | - | Header title. |
399
+ | `description` | `React.ReactNode` | - | Header description. |
400
+ | `footer` | `React.ReactNode` | - | Footer area. |
401
+
402
+ Inherited props:
403
+
404
+ Picks these Surface `DrawerProps`: `closeOnBackdrop`, `onDismiss`, `position`,
405
+ `testID`, and `visible`.
406
+
407
+ </details>
408
+
409
+ ## Layouts
410
+
411
+ ### `Page`
412
+
413
+ Constrained page container with optional header and footer slots.
414
+
21
415
  ```tsx
22
- import { Button } from '@ankhorage/zora'
416
+ <Page header={<PageHeader title="Projects" />} width="wide">
417
+ {content}
418
+ </Page>
419
+ ```
420
+
421
+ <details>
422
+ <summary>Props</summary>
23
423
 
24
- <Button>Click me</Button>
424
+ ZORA props:
425
+
426
+ | Prop | Type | Default | Notes |
427
+ | --- | --- | --- | --- |
428
+ | `children` | `React.ReactNode` | - | Page body. |
429
+ | `header` | `React.ReactNode` | - | Rendered above body content. |
430
+ | `footer` | `React.ReactNode` | - | Rendered below body content. |
431
+ | `width` | `ZoraContentWidth` | `'default'` | Resolves to `760`, `1040`, or `1280` pixels. |
432
+ | `testID` | `string` | - | Forwarded to the root Surface container. |
433
+
434
+ Inherited props:
435
+
436
+ No inherited props. `PageProps` is declared directly by ZORA.
437
+
438
+ </details>
439
+
440
+ ### `PageHeader`
441
+
442
+ Top-level page heading with optional eyebrow, metadata, and actions.
443
+
444
+ ```tsx
445
+ <PageHeader actions={<Button>New</Button>} title="Projects" />
25
446
  ```
26
447
 
27
- ## 🧪 Use Cases
28
- - Rapid app development
29
- - UI standardization across teams
448
+ <details>
449
+ <summary>Props</summary>
450
+
451
+ ZORA props:
452
+
453
+ | Prop | Type | Default | Notes |
454
+ | --- | --- | --- | --- |
455
+ | `title` | `React.ReactNode` | - | Required page title. |
456
+ | `description` | `React.ReactNode` | - | Supporting copy below title. |
457
+ | `eyebrow` | `React.ReactNode` | - | Small muted text above title. |
458
+ | `actions` | `React.ReactNode` | - | Action area opposite the heading. |
459
+ | `meta` | `React.ReactNode` | - | Extra content below description. |
460
+ | `testID` | `string` | - | Forwarded to the root Surface stack. |
461
+
462
+ Inherited props:
463
+
464
+ No inherited props. `PageHeaderProps` is declared directly by ZORA.
465
+
466
+ </details>
467
+
468
+ ### `PageSection`
469
+
470
+ Section wrapper that optionally renders a `SectionHeader`.
471
+
472
+ ```tsx
473
+ <PageSection actions={<Button>Refresh</Button>} title="Recent activity">
474
+ {content}
475
+ </PageSection>
476
+ ```
477
+
478
+ <details>
479
+ <summary>Props</summary>
480
+
481
+ ZORA props:
482
+
483
+ | Prop | Type | Default | Notes |
484
+ | --- | --- | --- | --- |
485
+ | `title` | `React.ReactNode` | - | Section title; when absent, no header is rendered. |
486
+ | `description` | `React.ReactNode` | - | Passed to the section header. |
487
+ | `actions` | `React.ReactNode` | - | Passed to the section header. |
488
+ | `children` | `React.ReactNode` | - | Section body. |
489
+ | `testID` | `string` | - | Forwarded to the root Surface stack. |
490
+
491
+ Inherited props:
492
+
493
+ No inherited props. `PageSectionProps` is declared directly by ZORA.
494
+
495
+ </details>
496
+
497
+ ### `SidebarLayout`
498
+
499
+ Responsive shell with required sidebar, main content, and optional aside.
500
+
501
+ ```tsx
502
+ <SidebarLayout sidebar={navigation} aside={details}>
503
+ {content}
504
+ </SidebarLayout>
505
+ ```
506
+
507
+ <details>
508
+ <summary>Props</summary>
509
+
510
+ ZORA props:
511
+
512
+ | Prop | Type | Default | Notes |
513
+ | --- | --- | --- | --- |
514
+ | `sidebar` | `React.ReactNode` | - | Required left column content. |
515
+ | `children` | `React.ReactNode` | - | Main content. |
516
+ | `aside` | `React.ReactNode` | - | Optional right column content. |
517
+ | `sidebarWidth` | `number` | `280` | Desktop sidebar width. |
518
+ | `asideWidth` | `number` | `280` | Desktop aside width. |
519
+ | `testID` | `string` | - | Forwarded to the root Surface stack. |
520
+
521
+ Inherited props:
522
+
523
+ No inherited props. `SidebarLayoutProps` is declared directly by ZORA.
524
+
525
+ </details>
526
+
527
+ ### `TopbarLayout`
528
+
529
+ Top navigation shell with optional sidebar composition.
530
+
531
+ ```tsx
532
+ <TopbarLayout topbar={topbar} sidebar={sidebar}>
533
+ {content}
534
+ </TopbarLayout>
535
+ ```
536
+
537
+ <details>
538
+ <summary>Props</summary>
539
+
540
+ ZORA props:
541
+
542
+ | Prop | Type | Default | Notes |
543
+ | --- | --- | --- | --- |
544
+ | `topbar` | `React.ReactNode` | - | Required topbar content. |
545
+ | `children` | `React.ReactNode` | - | Main content. |
546
+ | `sidebar` | `React.ReactNode` | - | Optional sidebar; when present, content is rendered through `SidebarLayout`. |
547
+ | `testID` | `string` | - | Forwarded to the root Surface stack. |
548
+
549
+ Inherited props:
550
+
551
+ No inherited props. `TopbarLayoutProps` is declared directly by ZORA.
552
+
553
+ </details>
554
+
555
+ ### `SettingsLayout`
556
+
557
+ Reusable settings shell with page header, sidebar, and content region.
558
+
559
+ ```tsx
560
+ <SettingsLayout actions={<Button>Save</Button>} sidebar={nav} title="Settings">
561
+ {content}
562
+ </SettingsLayout>
563
+ ```
564
+
565
+ <details>
566
+ <summary>Props</summary>
567
+
568
+ ZORA props:
569
+
570
+ | Prop | Type | Default | Notes |
571
+ | --- | --- | --- | --- |
572
+ | `title` | `React.ReactNode` | - | Optional page title; when absent, no page header is rendered. |
573
+ | `description` | `React.ReactNode` | - | Header description. |
574
+ | `sidebar` | `React.ReactNode` | - | Required settings navigation or context sidebar. |
575
+ | `children` | `React.ReactNode` | - | Settings content. |
576
+ | `actions` | `React.ReactNode` | - | Header action area. |
577
+ | `testID` | `string` | - | Forwarded to `Page`. |
578
+
579
+ Inherited props:
580
+
581
+ No inherited props. `SettingsLayoutProps` is declared directly by ZORA.
582
+
583
+ </details>
584
+
585
+ ### `AuthLayout`
586
+
587
+ Centered authentication-style shell for sign-in, onboarding, and recovery
588
+ screens.
589
+
590
+ ```tsx
591
+ <AuthLayout description="Sign in to continue" title="Welcome back">
592
+ {form}
593
+ </AuthLayout>
594
+ ```
595
+
596
+ <details>
597
+ <summary>Props</summary>
598
+
599
+ ZORA props:
600
+
601
+ | Prop | Type | Default | Notes |
602
+ | --- | --- | --- | --- |
603
+ | `title` | `React.ReactNode` | - | Card title. |
604
+ | `description` | `React.ReactNode` | - | Card description. |
605
+ | `eyebrow` | `React.ReactNode` | - | Card eyebrow. |
606
+ | `children` | `React.ReactNode` | - | Form or auth content. |
607
+ | `footer` | `React.ReactNode` | - | Card footer. |
608
+ | `testID` | `string` | - | Forwarded to the root Surface center. |
609
+
610
+ Inherited props:
611
+
612
+ No inherited props. `AuthLayoutProps` is declared directly by ZORA.
613
+
614
+ </details>
615
+
616
+ ## Patterns
617
+
618
+ ### `FormField`
619
+
620
+ Form field wrapper with rich label composition, description, helper text, and
621
+ Surface field state.
622
+
623
+ ```tsx
624
+ <FormField helperText="We only use this for sign-in." label="Email">
625
+ <Input keyboardType="email-address" />
626
+ </FormField>
627
+ ```
628
+
629
+ <details>
630
+ <summary>Props</summary>
631
+
632
+ ZORA props:
633
+
634
+ | Prop | Type | Default | Notes |
635
+ | --- | --- | --- | --- |
636
+ | `label` | `React.ReactNode` | - | Required field label. |
637
+ | `description` | `React.ReactNode` | - | Rendered under the label. |
638
+ | `helperText` | `React.ReactNode` | - | Passed to Surface `Field` as `helperText`. |
639
+
640
+ Inherited props:
641
+
642
+ Picks these Surface `FieldProps`: `children`, `disabled`, `errorText`,
643
+ `invalid`, `readOnly`, `required`, and `testID`.
644
+
645
+ </details>
646
+
647
+ ### `Notice`
648
+
649
+ Semantic notice surface with badge eyebrow, optional body, and actions.
650
+
651
+ ```tsx
652
+ <Notice actions={<Button>Review</Button>} title="Publish pipeline ready" tone="success" />
653
+ ```
654
+
655
+ <details>
656
+ <summary>Props</summary>
657
+
658
+ ZORA props:
659
+
660
+ | Prop | Type | Default | Notes |
661
+ | --- | --- | --- | --- |
662
+ | `title` | `React.ReactNode` | - | Required notice title. |
663
+ | `description` | `React.ReactNode` | - | Notice description. |
664
+ | `children` | `React.ReactNode` | - | Optional body content. |
665
+ | `actions` | `React.ReactNode` | - | Optional action area. |
666
+ | `tone` | `ZoraTone` | `'primary'` | Drives the badge eyebrow tone. |
667
+ | `testID` | `string` | - | Forwarded to the underlying `Card`. |
668
+
669
+ Inherited props:
670
+
671
+ No inherited props. `NoticeProps` is declared directly by ZORA.
672
+
673
+ </details>
674
+
675
+ ### `Panel`
676
+
677
+ Named composition surface that currently forwards to `Card`.
678
+
679
+ ```tsx
680
+ <Panel description="Release details" title="Release Candidate">
681
+ {content}
682
+ </Panel>
683
+ ```
684
+
685
+ <details>
686
+ <summary>Props</summary>
687
+
688
+ ZORA props:
689
+
690
+ | Prop | Type | Default | Notes |
691
+ | --- | --- | --- | --- |
692
+ | `title` | `React.ReactNode` | - | Header title. |
693
+ | `description` | `React.ReactNode` | - | Header description. |
694
+ | `eyebrow` | `React.ReactNode` | - | Small muted text above the title. |
695
+ | `actions` | `React.ReactNode` | - | Header action area. |
696
+ | `footer` | `React.ReactNode` | - | Footer area below body content. |
697
+ | `children` | `React.ReactNode` | - | Panel body. |
698
+ | `tone` | `ZoraCardTone` | `'default'` | Same tone behavior as `Card`. |
699
+ | `compact` | `boolean` | `false` | Same compact behavior as `Card`. |
700
+ | `testID` | `string` | - | Forwarded through `Card`. |
701
+
702
+ Inherited props:
703
+
704
+ No inherited props. `PanelProps` is declared directly by ZORA.
705
+
706
+ </details>
707
+
708
+ ### `SectionHeader`
709
+
710
+ Reusable section heading with optional eyebrow, description, and actions.
711
+
712
+ ```tsx
713
+ <SectionHeader actions={<Badge>Live</Badge>} title="Activity" />
714
+ ```
715
+
716
+ <details>
717
+ <summary>Props</summary>
718
+
719
+ ZORA props:
720
+
721
+ | Prop | Type | Default | Notes |
722
+ | --- | --- | --- | --- |
723
+ | `title` | `React.ReactNode` | - | Required heading title. |
724
+ | `description` | `React.ReactNode` | - | Supporting copy. |
725
+ | `eyebrow` | `React.ReactNode` | - | Small muted text above the title. |
726
+ | `actions` | `React.ReactNode` | - | Action area opposite the heading. |
727
+ | `testID` | `string` | - | Forwarded to the root Surface stack. |
728
+
729
+ Inherited props:
730
+
731
+ No inherited props. `SectionHeaderProps` is declared directly by ZORA.
732
+
733
+ </details>
734
+
735
+ ### `SettingsRow`
736
+
737
+ Compact settings row with optional metadata, control, and press handling.
738
+
739
+ ```tsx
740
+ <SettingsRow control={<Switch value={enabled} />} title="Notifications" />
741
+ ```
742
+
743
+ <details>
744
+ <summary>Props</summary>
745
+
746
+ ZORA props:
747
+
748
+ | Prop | Type | Default | Notes |
749
+ | --- | --- | --- | --- |
750
+ | `title` | `React.ReactNode` | - | Required row title. |
751
+ | `description` | `React.ReactNode` | - | Row description. |
752
+ | `meta` | `React.ReactNode` | - | Small muted metadata below the row content. |
753
+ | `control` | `React.ReactNode` | - | Trailing control or action content. |
754
+ | `onPress` | `() => void` | - | Makes the underlying card pressable. |
755
+ | `disabled` | `boolean` | `false` | Forwarded to the underlying card. |
756
+ | `testID` | `string` | - | Forwarded to the underlying card. |
757
+
758
+ Inherited props:
759
+
760
+ No inherited props. `SettingsRowProps` is declared directly by ZORA.
761
+
762
+ </details>
763
+
764
+ ### `EmptyState`
765
+
766
+ No-data surface with title, optional supporting text, actions, and footer.
767
+
768
+ ```tsx
769
+ <EmptyState
770
+ primaryAction={{ label: 'Create project', onPress: createProject }}
771
+ title="Nothing here yet"
772
+ />
773
+ ```
774
+
775
+ <details>
776
+ <summary>Props</summary>
777
+
778
+ ZORA props:
779
+
780
+ | Prop | Type | Default | Notes |
781
+ | --- | --- | --- | --- |
782
+ | `title` | `React.ReactNode` | - | Required empty-state title. |
783
+ | `description` | `React.ReactNode` | - | Supporting copy. |
784
+ | `eyebrow` | `React.ReactNode` | - | Card eyebrow. |
785
+ | `primaryAction` | `EmptyStateAction` | - | Primary action button. |
786
+ | `secondaryAction` | `EmptyStateAction` | - | Secondary action button; defaults to `tone="neutral"` and `emphasis="soft"` when omitted on the action. |
787
+ | `footer` | `React.ReactNode` | - | Footer content below actions. |
788
+ | `testID` | `string` | - | Forwarded to the underlying card. |
789
+
790
+ `EmptyStateAction`:
791
+
792
+ | Prop | Type | Default | Notes |
793
+ | --- | --- | --- | --- |
794
+ | `label` | `React.ReactNode` | - | Button label. |
795
+ | `onPress` | `() => void` | - | Button handler. |
796
+ | `tone` | `ZoraTone` | - | Button tone. |
797
+ | `emphasis` | `ZoraEmphasis` | - | Button emphasis. |
798
+
799
+ Inherited props:
800
+
801
+ No inherited props. `EmptyStateProps` and `EmptyStateAction` are declared
802
+ directly by ZORA.
803
+
804
+ </details>
805
+
806
+ ### `ConfirmDialog`
807
+
808
+ Narrow confirmation modal for destructive or high-signal decisions.
809
+
810
+ ```tsx
811
+ <ConfirmDialog
812
+ confirmLabel="Archive"
813
+ confirmTone="danger"
814
+ onCancel={close}
815
+ onConfirm={archive}
816
+ title="Archive project?"
817
+ visible={visible}
818
+ />
819
+ ```
820
+
821
+ <details>
822
+ <summary>Props</summary>
823
+
824
+ ZORA props:
825
+
826
+ | Prop | Type | Default | Notes |
827
+ | --- | --- | --- | --- |
828
+ | `visible` | `boolean` | - | Required modal visibility. |
829
+ | `title` | `React.ReactNode` | - | Required dialog title. |
830
+ | `description` | `React.ReactNode` | - | Dialog description. |
831
+ | `children` | `React.ReactNode` | - | Dialog body. |
832
+ | `confirmLabel` | `React.ReactNode` | `'Confirm'` | Confirm button label. |
833
+ | `cancelLabel` | `React.ReactNode` | `'Cancel'` | Cancel button label. |
834
+ | `confirmTone` | `ZoraTone` | `'danger'` | Confirm button tone. |
835
+ | `confirmEmphasis` | `ZoraEmphasis` | `'solid'` | Confirm button emphasis. |
836
+ | `busy` | `boolean` | `false` | Passed to the confirm button as `loading`. |
837
+ | `closeOnBackdrop` | `boolean` | `true` | Passed to the underlying modal. |
838
+ | `onConfirm` | `() => void` | - | Confirm button handler. |
839
+ | `onCancel` | `() => void` | - | Cancel button and modal dismiss handler. |
840
+ | `testID` | `string` | - | Forwarded to the underlying modal. |
841
+
842
+ Confirm dialogs always use `Modal` with `width="narrow"`.
843
+
844
+ Inherited props:
845
+
846
+ No inherited props. `ConfirmDialogProps` is declared directly by ZORA.
847
+
848
+ </details>
849
+
850
+ ### `DisclosureSection`
851
+
852
+ Collapsible section for property groups and settings.
853
+
854
+ ```tsx
855
+ <DisclosureSection title="Advanced Settings">
856
+ {content}
857
+ </DisclosureSection>
858
+ ```
859
+
860
+ <details>
861
+ <summary>Props</summary>
862
+
863
+ ZORA props:
864
+
865
+ | Prop | Type | Default | Notes |
866
+ | --- | --- | --- | --- |
867
+ | `title` | `React.ReactNode` | - | Section title. |
868
+ | `description` | `React.ReactNode` | - | Subheading text. |
869
+ | `defaultOpen` | `boolean` | `true` | Initial state. |
870
+ | `open` | `boolean` | - | Controlled state. |
871
+ | `onOpenChange` | `(open: boolean) => void` | - | Toggle handler. |
872
+ | `actions` | `React.ReactNode` | - | Extra header actions. |
873
+
874
+ </details>
875
+
876
+ ### `ResponsivePanel`
877
+
878
+ Side panel that adapts to screen size (inline or overlay).
879
+
880
+ ```tsx
881
+ <ResponsivePanel onOpenChange={setOpen} open={open} title="Inspector">
882
+ {content}
883
+ </ResponsivePanel>
884
+ ```
885
+
886
+ <details>
887
+ <summary>Props</summary>
888
+
889
+ ZORA props:
890
+
891
+ | Prop | Type | Default | Notes |
892
+ | --- | --- | --- | --- |
893
+ | `open` | `boolean` | - | Required visibility. |
894
+ | `onOpenChange` | `(open: boolean) => void` | - | Required change handler. |
895
+ | `side` | `'left' \| 'right'` | `'right'` | Layout side. |
896
+ | `desktopMode` | `'inline' \| 'floating'` | `'inline'` | Desktop rendering style. |
897
+ | `mobileMode` | `'drawer' \| 'modal'` | `'drawer'` | Mobile rendering style. |
898
+
899
+ </details>
900
+
901
+ ### `InspectorField`
902
+
903
+ Dense form field optimized for property panels.
904
+
905
+ ```tsx
906
+ <InspectorField control={<IconButton icon={{ name: 'refresh-outline' }} label="Reset" />} label="Opacity">
907
+ <Input value="100%" />
908
+ </InspectorField>
909
+ ```
910
+
911
+ <details>
912
+ <summary>Props</summary>
913
+
914
+ ZORA props:
915
+
916
+ | Prop | Type | Default | Notes |
917
+ | --- | --- | --- | --- |
918
+ | `label` | `React.ReactNode` | - | Field label. |
919
+ | `control` | `React.ReactNode` | - | Trailing control slot. |
920
+ | `children` | `React.ReactNode` | - | Main editor content. |
921
+
922
+ Inherits all `FormField` props.
923
+
924
+ </details>
925
+
926
+ ### `SwitchField`
927
+
928
+ Labeled boolean toggle row.
929
+
930
+ ```tsx
931
+ <SwitchField label="Enable Notifications" onValueChange={setVal} value={val} />
932
+ ```
933
+
934
+ <details>
935
+ <summary>Props</summary>
936
+
937
+ ZORA props:
938
+
939
+ | Prop | Type | Default | Notes |
940
+ | --- | --- | --- | --- |
941
+ | `label` | `React.ReactNode` | - | Required label. |
942
+ | `description` | `React.ReactNode` | - | Subheading text. |
943
+ | `value` | `boolean` | - | Required state. |
944
+ | `onValueChange` | `(value: boolean) => void` | - | Required handler. |
945
+
946
+ </details>
947
+
948
+ ### `TreeView`
949
+
950
+ Hierarchical list for navigation and layers.
951
+
952
+ ```tsx
953
+ <TreeView
954
+ nodes={[
955
+ { id: '1', label: 'Folder', children: [{ id: '2', label: 'File' }] }
956
+ ]}
957
+ onSelect={id => console.log(id)}
958
+ />
959
+ ```
960
+
961
+ <details>
962
+ <summary>Props</summary>
963
+
964
+ ZORA props:
965
+
966
+ | Prop | Type | Default | Notes |
967
+ | --- | --- | --- | --- |
968
+ | `nodes` | `TreeItemNode[]` | - | Required tree data. |
969
+ | `selectedId` | `string` | - | Active node. |
970
+ | `expandedIds` | `string[]` | - | Controlled expansion. |
971
+ | `onSelect` | `(id: string) => void` | - | Click handler. |
972
+
973
+ </details>
974
+
975
+ ### `TileGrid` / `PaletteItem`
976
+
977
+ Grid-based selection for palettes and toolboxes.
978
+
979
+ ```tsx
980
+ <TileGrid>
981
+ <PaletteItem title="Red" onPress={() => setCol('red')} />
982
+ <PaletteItem title="Blue" onPress={() => setCol('blue')} />
983
+ </TileGrid>
984
+ ```
985
+
986
+ <details>
987
+ <summary>Props</summary>
988
+
989
+ `TileGrid` props:
990
+
991
+ | Prop | Type | Default | Notes |
992
+ | --- | --- | --- | --- |
993
+ | `columns` | `number \| 'responsive'` | `'responsive'` | Grid layout. |
994
+
995
+ `PaletteItem` props:
996
+
997
+ | Prop | Type | Default | Notes |
998
+ | --- | --- | --- | --- |
999
+ | `title` | `React.ReactNode` | - | Item title. |
1000
+ | `selected` | `boolean` | `false` | Highlighted state. |
1001
+ | `onPress` | `() => void` | - | Click handler. |
1002
+
1003
+ </details>
1004
+
1005
+ ### `CollectionEditor`
1006
+
1007
+ Generic visual shell for editing ordered collections.
1008
+
1009
+ ```tsx
1010
+ <CollectionEditor
1011
+ items={items}
1012
+ renderItem={({ item }) => <Text>{item.name}</Text>}
1013
+ onAdd={() => add()}
1014
+ onRemove={index => remove(index)}
1015
+ />
1016
+ ```
1017
+
1018
+ <details>
1019
+ <summary>Props</summary>
1020
+
1021
+ ZORA props:
1022
+
1023
+ | Prop | Type | Default | Notes |
1024
+ | --- | --- | --- | --- |
1025
+ | `items` | `readonly T[]` | - | Required collection. |
1026
+ | `renderItem` | `(props) => ReactNode` | - | Required item renderer. |
1027
+ | `onAdd` | `() => void` | - | Add handler. |
1028
+ | `onRemove` | `(index: number) => void` | - | Remove handler. |
1029
+ | `onMove` | `(from, to) => void` | - | Reorder handler. |
1030
+
1031
+ </details>
1032
+
1033
+ ## Theme
1034
+
1035
+ ### `ZoraProvider`
1036
+
1037
+ Theme provider that creates the ZORA theme and passes it to Surface
1038
+ `ThemeProvider`.
1039
+
1040
+ ```tsx
1041
+ <ZoraProvider initialMode="dark">
1042
+ <App />
1043
+ </ZoraProvider>
1044
+ ```
1045
+
1046
+ <details>
1047
+ <summary>Props</summary>
1048
+
1049
+ ZORA props:
1050
+
1051
+ | Prop | Type | Default | Notes |
1052
+ | --- | --- | --- | --- |
1053
+ | `children` | `React.ReactNode` | - | Required app content. |
1054
+ | `initialConfig` | `ZoraThemeOverride` | - | Partial Surface `ThemeConfig` override merged into `zoraTheme`. |
1055
+ | `initialMode` | `'light' \| 'dark'` | `'light'` | Initial theme mode passed to Surface. |
1056
+
1057
+ Inherited props:
1058
+
1059
+ No inherited props. `ZoraProviderProps` is declared directly by ZORA.
1060
+
1061
+ </details>
1062
+
1063
+ ### `createZoraTheme`
1064
+
1065
+ Creates a Surface `ThemeConfig` by deep-merging overrides into `zoraTheme`.
1066
+
1067
+ ```tsx
1068
+ const theme = createZoraTheme({
1069
+ light: {
1070
+ primaryColor: '#1d4ed8',
1071
+ },
1072
+ });
1073
+ ```
1074
+
1075
+ <details>
1076
+ <summary>API</summary>
1077
+
1078
+ ```ts
1079
+ type ZoraThemeOverride = Partial<ThemeConfig>;
1080
+
1081
+ function createZoraTheme(overrides?: ZoraThemeOverride): ThemeConfig;
1082
+ ```
1083
+
1084
+ The returned theme keeps `id: 'zora'` unless explicitly changed by the merge
1085
+ input.
1086
+
1087
+ </details>
1088
+
1089
+ ### `zoraTheme`
1090
+
1091
+ Default ZORA Surface theme preset.
1092
+
1093
+ <details>
1094
+ <summary>Value</summary>
1095
+
1096
+ ```ts
1097
+ const zoraTheme: ThemeConfig = {
1098
+ id: 'zora',
1099
+ name: 'ZORA',
1100
+ light: {
1101
+ primaryColor: '#0f766e',
1102
+ harmony: 'analogous',
1103
+ systemTone: 'jewel',
1104
+ },
1105
+ dark: {
1106
+ primaryColor: '#2dd4bf',
1107
+ harmony: 'analogous',
1108
+ systemTone: 'jewel',
1109
+ },
1110
+ };
1111
+ ```
1112
+
1113
+ </details>
1114
+
1115
+ ## Public Exports
1116
+
1117
+ ```ts
1118
+ export {
1119
+ AuthLayout,
1120
+ Badge,
1121
+ Button,
1122
+ Card,
1123
+ CollectionEditor,
1124
+ ConfirmDialog,
1125
+ createZoraTheme,
1126
+ DisclosureSection,
1127
+ Drawer,
1128
+ EmptyState,
1129
+ FormField,
1130
+ IconButton,
1131
+ Input,
1132
+ InspectorField,
1133
+ Modal,
1134
+ Notice,
1135
+ Page,
1136
+ PageHeader,
1137
+ PageSection,
1138
+ PaletteItem,
1139
+ Panel,
1140
+ ResponsivePanel,
1141
+ SectionHeader,
1142
+ Select,
1143
+ SettingsLayout,
1144
+ SettingsRow,
1145
+ SidebarLayout,
1146
+ SwitchField,
1147
+ Tabs,
1148
+ Textarea,
1149
+ TileGrid,
1150
+ Toolbar,
1151
+ ToolbarAction,
1152
+ TopbarLayout,
1153
+ TreeView,
1154
+ ZoraProvider,
1155
+ zoraTheme,
1156
+ };
1157
+
1158
+ export type {
1159
+ AuthLayoutProps,
1160
+ BadgeProps,
1161
+ ButtonProps,
1162
+ CardProps,
1163
+ CollectionEditorProps,
1164
+ ConfirmDialogProps,
1165
+ DisclosureSectionProps,
1166
+ DrawerProps,
1167
+ EmptyStateAction,
1168
+ EmptyStateProps,
1169
+ FormFieldProps,
1170
+ IconButtonProps,
1171
+ InputProps,
1172
+ InspectorFieldProps,
1173
+ ModalProps,
1174
+ NoticeProps,
1175
+ PageHeaderProps,
1176
+ PageProps,
1177
+ PageSectionProps,
1178
+ PaletteItemProps,
1179
+ PanelProps,
1180
+ ResponsivePanelProps,
1181
+ SectionHeaderProps,
1182
+ SelectProps,
1183
+ SettingsLayoutProps,
1184
+ SettingsRowProps,
1185
+ SidebarLayoutProps,
1186
+ SwitchFieldProps,
1187
+ TabsProps,
1188
+ TextareaProps,
1189
+ TileGridProps,
1190
+ ToolbarProps,
1191
+ ToolbarActionProps,
1192
+ TopbarLayoutProps,
1193
+ TreeViewProps,
1194
+ ZoraProviderProps,
1195
+ ZoraThemeOverride,
1196
+ };
1197
+ ```
1198
+
1199
+ ## Example App
1200
+
1201
+ A complete Expo showcase lives in `examples/expo-showcase`. It renders every
1202
+ current ZORA component, pattern, layout, and theme entry point on one screen.
1203
+
1204
+ Run it locally:
1205
+
1206
+ ```bash
1207
+ cd examples/expo-showcase
1208
+ npm install
1209
+ npm run web
1210
+ ```
1211
+
1212
+ The example imports `@ankhorage/zora` and demonstrates the package API in
1213
+ `examples/expo-showcase/App.tsx`.
1214
+
1215
+ ## Changelog
1216
+
1217
+ Version history is maintained in [CHANGELOG.md](./CHANGELOG.md).
1218
+
1219
+ ## License
30
1220
 
31
- ## 🧠 Why this exists
32
- Building UI from scratch is slow. Zora speeds up development with reusable patterns.
1221
+ MIT