@ankhorage/zora 17.0.0 → 18.0.1

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 (158) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +1 -1
  3. package/dist/constants.d.ts +1 -1
  4. package/dist/constants.js +1 -1
  5. package/dist/constants.js.map +1 -1
  6. package/dist/features/auth/adapters/inbound/AuthFormField.js +3 -3
  7. package/dist/features/auth/adapters/inbound/AuthFormField.js.map +1 -1
  8. package/dist/features/chip/adapters/inbound/Chip.js +3 -3
  9. package/dist/features/chip/adapters/inbound/Chip.js.map +1 -1
  10. package/dist/features/form/field/adapters/inbound/Field.d.ts +5 -0
  11. package/dist/features/form/field/adapters/inbound/Field.d.ts.map +1 -0
  12. package/dist/features/form/field/adapters/inbound/Field.js +20 -0
  13. package/dist/features/form/field/adapters/inbound/Field.js.map +1 -0
  14. package/dist/features/form/{formFieldMeta.d.ts → field/meta.d.ts} +4 -4
  15. package/dist/features/form/field/meta.d.ts.map +1 -0
  16. package/dist/features/form/{formFieldMeta.js → field/meta.js} +4 -4
  17. package/dist/features/form/field/meta.js.map +1 -0
  18. package/dist/features/form/field/public.d.ts +2 -0
  19. package/dist/features/form/field/public.d.ts.map +1 -0
  20. package/dist/features/form/field/public.js +2 -0
  21. package/dist/features/form/field/public.js.map +1 -0
  22. package/dist/features/form/formMeta.d.ts +1 -1
  23. package/dist/features/form/formMeta.js +1 -1
  24. package/dist/features/form/formMeta.js.map +1 -1
  25. package/dist/features/form/public.d.ts +2 -2
  26. package/dist/features/form/public.d.ts.map +1 -1
  27. package/dist/features/form/public.js +1 -1
  28. package/dist/features/form/public.js.map +1 -1
  29. package/dist/features/list/adapters/inbound/List.d.ts +5 -0
  30. package/dist/features/list/adapters/inbound/List.d.ts.map +1 -0
  31. package/dist/features/list/adapters/inbound/List.js +34 -0
  32. package/dist/features/list/adapters/inbound/List.js.map +1 -0
  33. package/dist/features/list/adapters/inbound/ListItem.d.ts +5 -0
  34. package/dist/features/list/adapters/inbound/ListItem.d.ts.map +1 -0
  35. package/dist/features/list/adapters/inbound/ListItem.js +43 -0
  36. package/dist/features/list/adapters/inbound/ListItem.js.map +1 -0
  37. package/dist/features/list/adapters/inbound/ListSection.d.ts +5 -0
  38. package/dist/features/list/adapters/inbound/ListSection.d.ts.map +1 -0
  39. package/dist/{patterns/list → features/list/adapters/inbound}/ListSection.js +4 -8
  40. package/dist/features/list/adapters/inbound/ListSection.js.map +1 -0
  41. package/dist/{patterns → features}/list/meta.d.ts +6 -6
  42. package/dist/features/list/meta.d.ts.map +1 -0
  43. package/dist/{patterns → features}/list/meta.js +6 -14
  44. package/dist/features/list/meta.js.map +1 -0
  45. package/dist/features/list/public.d.ts +4 -0
  46. package/dist/features/list/public.d.ts.map +1 -1
  47. package/dist/features/list/public.js +3 -0
  48. package/dist/features/list/public.js.map +1 -1
  49. package/dist/features/list/utils/resolveListSeparator.d.ts +5 -0
  50. package/dist/features/list/utils/resolveListSeparator.d.ts.map +1 -0
  51. package/dist/{patterns/list → features/list/utils}/resolveListSeparator.js +1 -0
  52. package/dist/features/list/utils/resolveListSeparator.js.map +1 -0
  53. package/dist/features/skeleton/adapters/inbound/SkeletonList.d.ts.map +1 -1
  54. package/dist/features/skeleton/adapters/inbound/SkeletonList.js +2 -2
  55. package/dist/features/skeleton/adapters/inbound/SkeletonList.js.map +1 -1
  56. package/dist/features/uploader/adapters/inbound/Uploader.js +3 -3
  57. package/dist/features/uploader/adapters/inbound/Uploader.js.map +1 -1
  58. package/dist/index.d.ts +4 -4
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +2 -2
  61. package/dist/index.js.map +1 -1
  62. package/dist/metadata/bindableComponentMeta.d.ts +1 -1
  63. package/dist/metadata/bindableComponentMeta.js +1 -1
  64. package/dist/metadata/bindableComponentMeta.js.map +1 -1
  65. package/dist/metadata/componentMeta.js +4 -4
  66. package/dist/metadata/componentMeta.js.map +1 -1
  67. package/dist/patterns/chat-list-item/ChatListItem.js +3 -3
  68. package/dist/patterns/chat-list-item/ChatListItem.js.map +1 -1
  69. package/dist/patterns/inspector-field/InspectorField.js +3 -3
  70. package/dist/patterns/inspector-field/InspectorField.js.map +1 -1
  71. package/dist/patterns/message-bubble/MessageBubble.js +3 -3
  72. package/dist/patterns/message-bubble/MessageBubble.js.map +1 -1
  73. package/dist/patterns/selection/SelectableItem.js +4 -4
  74. package/dist/patterns/selection/SelectableItem.js.map +1 -1
  75. package/dist/patterns/switch-field/SwitchField.d.ts +1 -2
  76. package/dist/patterns/switch-field/SwitchField.d.ts.map +1 -1
  77. package/dist/patterns/switch-field/SwitchField.js +3 -4
  78. package/dist/patterns/switch-field/SwitchField.js.map +1 -1
  79. package/dist/patterns/tree-view/TreeItem.d.ts.map +1 -1
  80. package/dist/patterns/tree-view/TreeItem.js +2 -2
  81. package/dist/patterns/tree-view/TreeItem.js.map +1 -1
  82. package/dist/registry.js +4 -4
  83. package/dist/registry.js.map +1 -1
  84. package/dist/types/form.d.ts +1 -1
  85. package/dist/types/form.d.ts.map +1 -1
  86. package/dist/types/form.js.map +1 -1
  87. package/dist/{patterns/list/types.d.ts → types/list.d.ts} +14 -18
  88. package/dist/types/list.d.ts.map +1 -0
  89. package/dist/types/list.js +2 -0
  90. package/dist/types/list.js.map +1 -0
  91. package/package.json +2 -2
  92. package/src/constants.ts +1 -1
  93. package/src/features/auth/adapters/inbound/AuthFormField.tsx +3 -3
  94. package/src/features/bottom-sheet/public.test.ts +1 -1
  95. package/src/features/chip/adapters/inbound/Chip.tsx +3 -3
  96. package/src/features/form/{adapters/inbound/FormField.tsx → field/adapters/inbound/Field.tsx} +10 -10
  97. package/src/features/form/{formFieldMeta.ts → field/meta.ts} +5 -4
  98. package/src/features/form/field/public.ts +1 -0
  99. package/src/features/form/formMeta.ts +1 -1
  100. package/src/features/form/public.ts +2 -2
  101. package/src/features/list/adapters/inbound/List.tsx +77 -0
  102. package/src/features/list/adapters/inbound/ListItem.tsx +89 -0
  103. package/src/{patterns/list → features/list/adapters/inbound}/ListSection.tsx +5 -10
  104. package/src/{patterns → features}/list/meta.ts +7 -14
  105. package/src/features/list/public.ts +11 -0
  106. package/src/features/list/utils/resolveListSeparator.ts +9 -0
  107. package/src/features/skeleton/adapters/inbound/SkeletonList.tsx +3 -3
  108. package/src/features/uploader/adapters/inbound/Uploader.tsx +3 -3
  109. package/src/index.ts +11 -10
  110. package/src/metadata/bindableComponentMeta.ts +1 -1
  111. package/src/metadata/componentMeta.test.ts +5 -5
  112. package/src/metadata/componentMeta.ts +4 -4
  113. package/src/patterns/chat-list-item/ChatListItem.tsx +3 -3
  114. package/src/patterns/inspector-field/InspectorField.tsx +3 -3
  115. package/src/patterns/message-bubble/MessageBubble.tsx +3 -3
  116. package/src/patterns/selection/SelectableItem.tsx +4 -4
  117. package/src/patterns/switch-field/SwitchField.tsx +8 -8
  118. package/src/patterns/tree-view/TreeItem.tsx +2 -2
  119. package/src/platformAcceptance.test.ts +1 -1
  120. package/src/registry.ts +4 -4
  121. package/src/showcaseCoverage.test.ts +2 -2
  122. package/src/theme/themeScopeStructure.test.ts +5 -5
  123. package/src/types/form.ts +1 -1
  124. package/src/{patterns/list/types.ts → types/list.ts} +17 -18
  125. package/dist/features/form/adapters/inbound/FormField.d.ts +0 -5
  126. package/dist/features/form/adapters/inbound/FormField.d.ts.map +0 -1
  127. package/dist/features/form/adapters/inbound/FormField.js +0 -20
  128. package/dist/features/form/adapters/inbound/FormField.js.map +0 -1
  129. package/dist/features/form/formFieldMeta.d.ts.map +0 -1
  130. package/dist/features/form/formFieldMeta.js.map +0 -1
  131. package/dist/patterns/list/List.d.ts +0 -9
  132. package/dist/patterns/list/List.d.ts.map +0 -1
  133. package/dist/patterns/list/List.js +0 -40
  134. package/dist/patterns/list/List.js.map +0 -1
  135. package/dist/patterns/list/ListRow.d.ts +0 -9
  136. package/dist/patterns/list/ListRow.d.ts.map +0 -1
  137. package/dist/patterns/list/ListRow.js +0 -113
  138. package/dist/patterns/list/ListRow.js.map +0 -1
  139. package/dist/patterns/list/ListSection.d.ts +0 -9
  140. package/dist/patterns/list/ListSection.d.ts.map +0 -1
  141. package/dist/patterns/list/ListSection.js.map +0 -1
  142. package/dist/patterns/list/index.d.ts +0 -5
  143. package/dist/patterns/list/index.d.ts.map +0 -1
  144. package/dist/patterns/list/index.js +0 -4
  145. package/dist/patterns/list/index.js.map +0 -1
  146. package/dist/patterns/list/meta.d.ts.map +0 -1
  147. package/dist/patterns/list/meta.js.map +0 -1
  148. package/dist/patterns/list/resolveListSeparator.d.ts +0 -5
  149. package/dist/patterns/list/resolveListSeparator.d.ts.map +0 -1
  150. package/dist/patterns/list/resolveListSeparator.js.map +0 -1
  151. package/dist/patterns/list/types.d.ts.map +0 -1
  152. package/dist/patterns/list/types.js +0 -2
  153. package/dist/patterns/list/types.js.map +0 -1
  154. package/src/patterns/list/List.tsx +0 -77
  155. package/src/patterns/list/ListRow.tsx +0 -198
  156. package/src/patterns/list/index.ts +0 -10
  157. package/src/patterns/list/resolveListSeparator.test.ts +0 -18
  158. package/src/patterns/list/resolveListSeparator.ts +0 -8
@@ -0,0 +1,89 @@
1
+ import { ListItem as SurfaceListItem } from '@ankhorage/surface';
2
+ import React from 'react';
3
+
4
+ import { useZoraTheme } from '../../../../theme/useZoraTheme';
5
+ import { withZoraThemeScope } from '../../../../theme/withZoraThemeScope';
6
+ import type { ListItemProps, ListItemVariant } from '../../../../types/list';
7
+ import { View } from '../../../layout/public';
8
+ import { Text } from '../../../typography/public';
9
+
10
+ function ListItemInner({
11
+ themeId: _themeId,
12
+ mode: _mode,
13
+ testID,
14
+ interactionPolicy,
15
+ title,
16
+ description,
17
+ meta,
18
+ leading,
19
+ trailing,
20
+ action,
21
+ onPress,
22
+ selected = false,
23
+ disabled = false,
24
+ compact = false,
25
+ variant = 'divider',
26
+ }: ListItemProps) {
27
+ const { theme } = useZoraTheme();
28
+ const trailingContent = renderTrailing(trailing, action);
29
+
30
+ return (
31
+ <View
32
+ bg={variant === 'card' ? theme.semantics.surface.raised : 'transparent'}
33
+ borderColor={
34
+ selected
35
+ ? theme.semantics.border.focus
36
+ : variant === 'card'
37
+ ? theme.semantics.border.default
38
+ : 'transparent'
39
+ }
40
+ borderWidth={variant === 'card' || selected ? 1 : 0}
41
+ overflow="hidden"
42
+ radius={resolveRadius(variant)}
43
+ >
44
+ <SurfaceListItem
45
+ compact={compact}
46
+ disabled={disabled}
47
+ interactionPolicy={interactionPolicy}
48
+ leading={leading}
49
+ onPress={action ? undefined : onPress}
50
+ selected={selected}
51
+ testID={testID}
52
+ trailing={trailingContent}
53
+ >
54
+ <View gap="xxs">
55
+ <Text variant="body" weight={selected ? 'semiBold' : 'medium'}>
56
+ {title}
57
+ </Text>
58
+ {description ? (
59
+ <Text emphasis="muted" variant="bodySmall">
60
+ {description}
61
+ </Text>
62
+ ) : null}
63
+ {meta ? (
64
+ <Text emphasis="subtle" variant="caption">
65
+ {meta}
66
+ </Text>
67
+ ) : null}
68
+ </View>
69
+ </SurfaceListItem>
70
+ </View>
71
+ );
72
+ }
73
+
74
+ function resolveRadius(variant: ListItemVariant) {
75
+ return variant === 'card' ? ('l' as const) : ('m' as const);
76
+ }
77
+
78
+ function renderTrailing(trailing: React.ReactNode, action: React.ReactNode) {
79
+ if (!trailing && !action) return undefined;
80
+ return (
81
+ <View align="center" direction="row" gap="s" wrap="nowrap">
82
+ {trailing}
83
+ {action}
84
+ </View>
85
+ );
86
+ }
87
+
88
+ /*** Opinionated list item built on the Surface list-item interaction and geometry boundary. */
89
+ export const ListItem = withZoraThemeScope(ListItemInner);
@@ -1,10 +1,10 @@
1
1
  import React from 'react';
2
2
 
3
- import { View } from '../../features/layout/public';
4
- import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
5
- import { SectionHeader } from '../section-header';
3
+ import { SectionHeader } from '../../../../patterns/section-header';
4
+ import { withZoraThemeScope } from '../../../../theme/withZoraThemeScope';
5
+ import type { ListSectionProps } from '../../../../types/list';
6
+ import { View } from '../../../layout/public';
6
7
  import { List } from './List';
7
- import type { ListSectionProps } from './types';
8
8
 
9
9
  function ListSectionInner({
10
10
  themeId: _themeId,
@@ -17,7 +17,6 @@ function ListSectionInner({
17
17
  ...props
18
18
  }: ListSectionProps) {
19
19
  const hasHeader = title !== undefined;
20
-
21
20
  return (
22
21
  <View gap="s" testID={testID}>
23
22
  {hasHeader ? (
@@ -33,9 +32,5 @@ function ListSectionInner({
33
32
  );
34
33
  }
35
34
 
36
- /***
37
- * Section wrapper for lists with optional title and description.
38
- *
39
-
40
- */
35
+ /*** Section wrapper for lists with optional ZORA section-heading semantics. */
41
36
  export const ListSection = withZoraThemeScope(ListSectionInner);
@@ -1,6 +1,7 @@
1
1
  import type { ZoraComponentMeta } from '../../metadata';
2
2
 
3
- const LIST_NOTE = 'List pattern component; not represented as a manifest node in v1.';
3
+ const LIST_NOTE =
4
+ 'List feature component; collection authoring is represented through List metadata.';
4
5
 
5
6
  export const listMeta = {
6
7
  name: 'List',
@@ -11,8 +12,8 @@ export const listMeta = {
11
12
  props: {},
12
13
  } as const satisfies ZoraComponentMeta;
13
14
 
14
- export const listRowMeta = {
15
- name: 'ListRow',
15
+ export const listItemMeta = {
16
+ name: 'ListItem',
16
17
  category: 'pattern',
17
18
  directManifestNode: false,
18
19
  allowedChildren: [],
@@ -21,18 +22,10 @@ export const listRowMeta = {
21
22
  itemPress: {
22
23
  label: 'Item press',
23
24
  eventType: 'collection.itemPress',
24
- description: 'Emitted when a collection item row is selected.',
25
+ description: 'Emitted when a collection item is selected.',
25
26
  payloadFields: [
26
- {
27
- path: 'payload.itemId',
28
- type: 'string',
29
- label: 'Item ID',
30
- },
31
- {
32
- path: 'payload.item',
33
- type: 'record',
34
- label: 'Item',
35
- },
27
+ { path: 'payload.itemId', type: 'string', label: 'Item ID' },
28
+ { path: 'payload.item', type: 'record', label: 'Item' },
36
29
  ],
37
30
  },
38
31
  },
@@ -1,7 +1,18 @@
1
+ export type {
2
+ ListChildrenProps,
3
+ ListItemProps,
4
+ ListItemsProps,
5
+ ListItemVariant,
6
+ ListProps,
7
+ ListSectionProps,
8
+ } from '../../types/list';
1
9
  export type {
2
10
  ManifestListProps,
3
11
  ManifestListSection,
4
12
  ManifestSectionListProps,
5
13
  } from '../../types/manifest-list';
6
14
  export { FlatList } from './adapters/inbound/FlatList';
15
+ export { List } from './adapters/inbound/List';
16
+ export { ListItem } from './adapters/inbound/ListItem';
17
+ export { ListSection } from './adapters/inbound/ListSection';
7
18
  export { SectionList } from './adapters/inbound/SectionList';
@@ -0,0 +1,9 @@
1
+ import type { ListItemVariant } from '../../../types/list';
2
+
3
+ export type ListSeparatorKind = 'none' | 'divider' | 'spacer';
4
+
5
+ /*** Resolves the separator preceding an item for the active list presentation. */
6
+ export function resolveListSeparator(variant: ListItemVariant, index: number): ListSeparatorKind {
7
+ if (index === 0) return 'none';
8
+ return variant === 'divider' ? 'divider' : 'spacer';
9
+ }
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
2
 
3
- import { List, type ListRowProps } from '../../../../patterns/list';
4
3
  import { withZoraThemeScope } from '../../../../theme/withZoraThemeScope';
5
4
  import type { SkeletonListProps } from '../../../../types/skeleton';
5
+ import { List, type ListItemProps } from '../../../list/public';
6
6
  import { Skeleton } from './Skeleton';
7
7
  import { SkeletonText } from './SkeletonText';
8
8
 
@@ -38,7 +38,7 @@ function SkeletonListInner({
38
38
  compact = false,
39
39
  }: SkeletonListProps) {
40
40
  const rowCount = clampRows(rows);
41
- const items: ListRowProps[] = Array.from({ length: rowCount }).map(() => ({
41
+ const items: ListItemProps[] = Array.from({ length: rowCount }).map(() => ({
42
42
  compact,
43
43
  description: <SkeletonText lines={lines} />,
44
44
  leading: renderLeading({ avatar, media }),
@@ -46,7 +46,7 @@ function SkeletonListInner({
46
46
  variant,
47
47
  }));
48
48
 
49
- return <List compact={compact} items={items} rowVariant={variant} testID={testID} />;
49
+ return <List compact={compact} items={items} itemVariant={variant} testID={testID} />;
50
50
  }
51
51
 
52
52
  /***
@@ -4,7 +4,7 @@ import { withZoraThemeScope } from '../../../../theme/withZoraThemeScope';
4
4
  import type { UploadAsset, UploaderProps, UploadType } from '../../../../types/upload';
5
5
  import { Button } from '../../../button/public';
6
6
  import { Dialog } from '../../../dialog/public';
7
- import { FormField } from '../../../form/public';
7
+ import { Field } from '../../../form/public';
8
8
  import { Icon } from '../../../icon/public';
9
9
  import { Image } from '../../../image/public';
10
10
  import { View } from '../../../layout/public';
@@ -206,7 +206,7 @@ function UploaderInner({
206
206
 
207
207
  return (
208
208
  <>
209
- <FormField
209
+ <Field
210
210
  description={description}
211
211
  disabled={disabled}
212
212
  errorText={effectiveError}
@@ -285,7 +285,7 @@ function UploaderInner({
285
285
  ) : null}
286
286
  </View>
287
287
  </View>
288
- </FormField>
288
+ </Field>
289
289
 
290
290
  {canPreviewImage ? (
291
291
  <Dialog
package/src/index.ts CHANGED
@@ -128,12 +128,12 @@ export {
128
128
  type CheckboxProps,
129
129
  } from './features/form/checkbox/public';
130
130
  export type {
131
+ FieldProps,
131
132
  FormActionsProps,
132
133
  FormErrorProps,
133
134
  FormErrors,
134
135
  FormFieldConfig,
135
136
  FormFieldInputType,
136
- FormFieldProps,
137
137
  FormProps,
138
138
  FormValidationErrors,
139
139
  FormValidationResult,
@@ -143,10 +143,10 @@ export type {
143
143
  ValidationRule,
144
144
  } from './features/form/public';
145
145
  export {
146
+ Field,
146
147
  Form,
147
148
  FormActions,
148
149
  FormError,
149
- FormField,
150
150
  hasRequiredRule,
151
151
  useFormController,
152
152
  validateField,
@@ -218,7 +218,16 @@ export type {
218
218
  ManifestListSection,
219
219
  ManifestSectionListProps,
220
220
  } from './features/list/public';
221
+ export type {
222
+ ListChildrenProps,
223
+ ListItemProps,
224
+ ListItemsProps,
225
+ ListItemVariant,
226
+ ListProps,
227
+ ListSectionProps,
228
+ } from './features/list/public';
221
229
  export { FlatList, SectionList } from './features/list/public';
230
+ export { List, ListItem, ListSection } from './features/list/public';
222
231
  export { MissingElement, type MissingElementProps } from './features/missing-element/public';
223
232
  export { Pagination, type PaginationProps } from './features/pagination/public';
224
233
  export type { PaletteItemProps } from './features/palette-item/public';
@@ -361,14 +370,6 @@ export type { FilterBarProps } from './patterns/filter-bar';
361
370
  export { FilterBar } from './patterns/filter-bar';
362
371
  export type { InspectorFieldProps } from './patterns/inspector-field';
363
372
  export { InspectorField } from './patterns/inspector-field';
364
- export type {
365
- ListChildrenProps,
366
- ListItemsProps,
367
- ListProps,
368
- ListRowProps,
369
- ListRowVariant,
370
- } from './patterns/list';
371
- export { List, ListRow, ListSection } from './patterns/list';
372
373
  export type {
373
374
  MessageBubbleAuthor,
374
375
  MessageBubbleAvatar,
@@ -356,7 +356,7 @@ export const ZORA_BINDABLE_COMPONENT_META = {
356
356
  category: 'pattern',
357
357
  description: 'Renders a collection of list items.',
358
358
  directManifestNode: true,
359
- allowedChildren: ['ListSection', 'ListRow'],
359
+ allowedChildren: ['ListSection', 'ListItem'],
360
360
  bindings: {
361
361
  props: {
362
362
  items: {
@@ -63,7 +63,7 @@ describe('ZORA_COMPONENT_META event metadata', () => {
63
63
  });
64
64
 
65
65
  test('declares collection item metadata for list rows', () => {
66
- const event = ZORA_COMPONENT_META.ListRow.events?.itemPress;
66
+ const event = ZORA_COMPONENT_META.ListItem.events?.itemPress;
67
67
  const eventType: ZoraComponentEventPayloadKind = event?.eventType ?? 'collection.itemPress';
68
68
 
69
69
  expect(eventType).toBe('collection.itemPress');
@@ -101,8 +101,8 @@ describe('ZORA_COMPONENT_META requirement metadata', () => {
101
101
 
102
102
  describe('ZORA_COMPONENT_META invariants', () => {
103
103
  test('keeps form nodes in their canonical hierarchy', () => {
104
- expect(ZORA_COMPONENT_META.Form.allowedChildren).toEqual(['FormError', 'FormField']);
105
- expect(ZORA_COMPONENT_META.FormField.allowedChildren).toEqual([
104
+ expect(ZORA_COMPONENT_META.Form.allowedChildren).toEqual(['FormError', 'Field']);
105
+ expect(ZORA_COMPONENT_META.Field.allowedChildren).toEqual([
106
106
  'Checkbox',
107
107
  'CheckboxGroup',
108
108
  'RadioGroup',
@@ -113,7 +113,7 @@ describe('ZORA_COMPONENT_META invariants', () => {
113
113
  for (const [name, meta] of Object.entries(ZORA_COMPONENT_META)) {
114
114
  if (name === 'Form') continue;
115
115
  expect(meta.allowedChildren).not.toContain('FormError');
116
- expect(meta.allowedChildren).not.toContain('FormField');
116
+ expect(meta.allowedChildren).not.toContain('Field');
117
117
  }
118
118
  });
119
119
 
@@ -204,7 +204,7 @@ describe('ZORA_COMPONENT_META invariants', () => {
204
204
  'SectionList',
205
205
  'BottomSheet',
206
206
  'KeyboardAvoidingView',
207
- 'FormField',
207
+ 'Field',
208
208
  'ButtonGroup',
209
209
  'Screen',
210
210
  'ScreenSection',
@@ -29,9 +29,9 @@ import { datePickerMeta } from '../features/date-picker/datePickerMeta';
29
29
  import { dialogMeta } from '../features/dialog/dialogMeta';
30
30
  import { emptyStateMeta } from '../features/empty-state/emptyStateMeta';
31
31
  import { checkboxGroupMeta, checkboxMeta } from '../features/form/checkbox/checkboxMeta';
32
+ import { fieldMeta } from '../features/form/field/meta';
32
33
  import { formActionsMeta } from '../features/form/formActionsMeta';
33
34
  import { formErrorMeta } from '../features/form/formErrorMeta';
34
- import { formFieldMeta } from '../features/form/formFieldMeta';
35
35
  import { formMeta } from '../features/form/formMeta';
36
36
  import { radioGroupMeta, radioMeta } from '../features/form/radio/radioMeta';
37
37
  import { searchInputMeta } from '../features/form/search-input/searchInputMeta';
@@ -50,6 +50,7 @@ import { screenSectionMeta } from '../features/layout/screenSectionMeta';
50
50
  import { scrollViewMeta } from '../features/layout/scrollViewMeta';
51
51
  import { viewMeta } from '../features/layout/viewMeta';
52
52
  import { flatListMeta } from '../features/list/flatListMeta';
53
+ import { listItemMeta, listMeta, listSectionMeta } from '../features/list/meta';
53
54
  import { sectionListMeta } from '../features/list/sectionListMeta';
54
55
  import { missingElementMeta } from '../features/missing-element/missingElementMeta';
55
56
  import { paginationMeta } from '../features/pagination/paginationMeta';
@@ -80,7 +81,6 @@ import { collectionEditorMeta } from '../patterns/collection-editor/meta';
80
81
  import { confirmDialogMeta } from '../patterns/confirm-dialog/meta';
81
82
  import { filterBarMeta } from '../patterns/filter-bar/meta';
82
83
  import { inspectorFieldMeta } from '../patterns/inspector-field/meta';
83
- import { listMeta, listRowMeta, listSectionMeta } from '../patterns/list/meta';
84
84
  import { messageBubbleMeta } from '../patterns/message-bubble/meta';
85
85
  import { noticeMeta } from '../patterns/notice/meta';
86
86
  import { panelMeta } from '../patterns/panel/meta';
@@ -127,7 +127,7 @@ export const ZORA_COMPONENT_META: ZoraComponentMetaRegistry = finalizeFeatureMet
127
127
  Form: formMeta,
128
128
  FormActions: formActionsMeta,
129
129
  FormError: formErrorMeta,
130
- FormField: formFieldMeta,
130
+ Field: fieldMeta,
131
131
  Gradient: gradientMeta,
132
132
  Heading: headingMeta,
133
133
  Icon: iconMeta,
@@ -182,7 +182,7 @@ export const ZORA_COMPONENT_META: ZoraComponentMetaRegistry = finalizeFeatureMet
182
182
  Hero: heroMeta,
183
183
  InspectorField: inspectorFieldMeta,
184
184
  List: listMeta,
185
- ListRow: listRowMeta,
185
+ ListItem: listItemMeta,
186
186
  ListSection: listSectionMeta,
187
187
  MessageBubble: messageBubbleMeta,
188
188
  MissingElement: missingElementMeta,
@@ -1,4 +1,4 @@
1
- import { ButtonBase } from '@ankhorage/surface';
1
+ import { Pressable } from '@ankhorage/surface';
2
2
  import React from 'react';
3
3
 
4
4
  import { Avatar } from '../../features/avatar/public';
@@ -199,7 +199,7 @@ function ChatListItemInner({
199
199
  }
200
200
 
201
201
  return (
202
- <ButtonBase
202
+ <Pressable
203
203
  accessibilityLabel={accessibilityLabel}
204
204
  accessibilityRole="button"
205
205
  accessibilityState={{ disabled, selected }}
@@ -215,7 +215,7 @@ function ChatListItemInner({
215
215
  hovered: state.hovered,
216
216
  })
217
217
  }
218
- </ButtonBase>
218
+ </Pressable>
219
219
  );
220
220
  }
221
221
 
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
 
3
- import { FormField } from '../../features/form/public';
3
+ import { Field } from '../../features/form/public';
4
4
  import { View } from '../../features/layout/public';
5
5
  import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
6
6
  import type { InspectorFieldProps } from './types';
@@ -15,12 +15,12 @@ function InspectorFieldInner({
15
15
  ...props
16
16
  }: InspectorFieldProps) {
17
17
  return (
18
- <FormField {...props} label={label}>
18
+ <Field {...props} label={label}>
19
19
  <View direction="row" gap="s" align="center">
20
20
  <View flex={1}>{children}</View>
21
21
  {control ? <View>{control}</View> : null}
22
22
  </View>
23
- </FormField>
23
+ </Field>
24
24
  );
25
25
  }
26
26
 
@@ -1,4 +1,4 @@
1
- import { ButtonBase } from '@ankhorage/surface';
1
+ import { Pressable } from '@ankhorage/surface';
2
2
  import React from 'react';
3
3
 
4
4
  import { Avatar } from '../../features/avatar/public';
@@ -221,7 +221,7 @@ function MessageBubbleInner({
221
221
  };
222
222
 
223
223
  const bubbleContent = isInteractive ? (
224
- <ButtonBase
224
+ <Pressable
225
225
  accessibilityLabel={accessibilityLabel}
226
226
  accessibilityRole="button"
227
227
  accessibilityState={{ disabled, selected }}
@@ -232,7 +232,7 @@ function MessageBubbleInner({
232
232
  testID={testID}
233
233
  >
234
234
  {(state) => renderBubble({ pressed: state.pressed, hovered: state.hovered })}
235
- </ButtonBase>
235
+ </Pressable>
236
236
  ) : (
237
237
  <View testID={testID}>{renderBubble({ pressed: false, hovered: false })}</View>
238
238
  );
@@ -1,4 +1,4 @@
1
- import { ButtonBase } from '@ankhorage/surface';
1
+ import { Pressable } from '@ankhorage/surface';
2
2
  import React from 'react';
3
3
  import type { GestureResponderEvent } from 'react-native';
4
4
 
@@ -63,7 +63,7 @@ export function SelectableItem({
63
63
  }, [clear, id, resolvedDisabled, select, selected, selection.mode, toggle]);
64
64
 
65
65
  // IMPORTANT:
66
- // Do not pass `children` directly into ButtonBase. ButtonBase also supports function children,
66
+ // Do not pass `children` directly into Pressable. Pressable also supports function children,
67
67
  // but its function signature receives interaction state, not SelectableItemState.
68
68
  const content = isRenderProp(children) ? children(itemState) : children;
69
69
 
@@ -96,7 +96,7 @@ export function SelectableItem({
96
96
  };
97
97
 
98
98
  return (
99
- <ButtonBase
99
+ <Pressable
100
100
  interactionPolicy={interactionPolicy}
101
101
  accessibilityRole="button"
102
102
  accessibilityState={{ disabled: resolvedDisabled, selected }}
@@ -105,6 +105,6 @@ export function SelectableItem({
105
105
  onPress={resolvedTrigger === 'press' ? handlePress : undefined}
106
106
  >
107
107
  {content}
108
- </ButtonBase>
108
+ </Pressable>
109
109
  );
110
110
  }
@@ -1,8 +1,8 @@
1
1
  import { Switch } from '@ankhorage/surface';
2
2
  import React from 'react';
3
3
 
4
+ import { ListItem } from '../../features/list/public';
4
5
  import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
5
- import { ListRow } from '../list';
6
6
  import type { SwitchFieldProps } from './types';
7
7
 
8
8
  function SwitchFieldInner({
@@ -17,11 +17,7 @@ function SwitchFieldInner({
17
17
  interactionPolicy,
18
18
  }: SwitchFieldProps) {
19
19
  return (
20
- <ListRow
21
- title={label}
22
- description={description}
23
- disabled={disabled}
24
- testID={testID}
20
+ <ListItem
25
21
  action={
26
22
  <Switch
27
23
  checked={value}
@@ -30,13 +26,17 @@ function SwitchFieldInner({
30
26
  onCheckedChange={onValueChange}
31
27
  />
32
28
  }
29
+ description={description}
30
+ disabled={disabled}
31
+ testID={testID}
32
+ title={label}
33
+ variant="card"
33
34
  />
34
35
  );
35
36
  }
36
37
 
37
38
  /***
38
- * Labeled switch field pattern built on `ListRow`.
39
+ * Labeled switch field pattern built on the card-style `ListItem` presentation.
39
40
  *
40
-
41
41
  */
42
42
  export const SwitchField = withZoraThemeScope(SwitchFieldInner);
@@ -2,9 +2,9 @@ import React from 'react';
2
2
 
3
3
  import { IconButton } from '../../features/button/public';
4
4
  import { View } from '../../features/layout/public';
5
+ import { ListItem } from '../../features/list/public';
5
6
  import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
6
7
  import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
7
- import { ListRow } from '../list';
8
8
  import type { TreeItemNode, TreeItemRenderProps } from './types';
9
9
 
10
10
  interface TreeItemProps<TId extends string = string> extends ZoraBaseProps {
@@ -46,7 +46,7 @@ function TreeItemInner<TId extends string = string>({
46
46
  }
47
47
 
48
48
  return (
49
- <ListRow
49
+ <ListItem
50
50
  title={node.label}
51
51
  action={
52
52
  <View direction="row" gap="xs" align="center">
@@ -1,6 +1,6 @@
1
1
  import { expect, test } from 'bun:test';
2
2
 
3
- test('passes the isolated Surface 6 and RN Web 0.21 acceptance suite', () => {
3
+ test('passes the isolated Surface and RN Web 0.21 acceptance suite', () => {
4
4
  const subprocess = Bun.spawnSync({
5
5
  cmd: [process.execPath, 'test', 'test-fixtures/platformAcceptance.test.tsx'],
6
6
  stderr: 'pipe',
package/src/registry.ts CHANGED
@@ -33,7 +33,7 @@ import { DatePicker } from './features/date-picker/public';
33
33
  import { Dialog } from './features/dialog/public';
34
34
  import { EmptyState } from './features/empty-state/public';
35
35
  import { Checkbox, CheckboxGroup } from './features/form/checkbox/public';
36
- import { Form, FormActions, FormError, FormField } from './features/form/public';
36
+ import { Field, Form, FormActions, FormError } from './features/form/public';
37
37
  import { Radio, RadioGroup } from './features/form/radio/public';
38
38
  import { SearchInput } from './features/form/search-input/public';
39
39
  import { Select } from './features/form/select/public';
@@ -53,6 +53,7 @@ import {
53
53
  View,
54
54
  } from './features/layout/public';
55
55
  import { FlatList, SectionList } from './features/list/public';
56
+ import { List, ListItem, ListSection } from './features/list/public';
56
57
  import { MissingElement } from './features/missing-element/public';
57
58
  import { Pagination } from './features/pagination/public';
58
59
  import { PaletteItem } from './features/palette-item/public';
@@ -73,7 +74,6 @@ import { CollectionEditor } from './patterns/collection-editor';
73
74
  import { ConfirmDialog } from './patterns/confirm-dialog';
74
75
  import { FilterBar } from './patterns/filter-bar';
75
76
  import { InspectorField } from './patterns/inspector-field';
76
- import { List, ListRow, ListSection } from './patterns/list';
77
77
  import { MessageBubble } from './patterns/message-bubble';
78
78
  import { Notice } from './patterns/notice';
79
79
  import { Panel } from './patterns/panel';
@@ -134,7 +134,7 @@ const _ZORA_COMPONENT_REGISTRY = {
134
134
  Form,
135
135
  FormActions,
136
136
  FormError,
137
- FormField,
137
+ Field,
138
138
  Gradient,
139
139
  Heading,
140
140
  Icon,
@@ -193,7 +193,7 @@ const _ZORA_COMPONENT_REGISTRY = {
193
193
  Hero,
194
194
  InspectorField,
195
195
  List,
196
- ListRow,
196
+ ListItem,
197
197
  ListSection,
198
198
  MessageBubble,
199
199
  MissingElement,
@@ -34,7 +34,7 @@ const REQUIRED_SHOWCASE_COVERAGE = {
34
34
  'Form',
35
35
  'FormActions',
36
36
  'FormError',
37
- 'FormField',
37
+ 'Field',
38
38
  'Heading',
39
39
  'Icon',
40
40
  'IconButton',
@@ -74,7 +74,7 @@ const REQUIRED_SHOWCASE_COVERAGE = {
74
74
  'SelectionProvider',
75
75
  'useSelection',
76
76
  'List',
77
- 'ListRow',
77
+ 'ListItem',
78
78
  'ListSection',
79
79
  'InspectorField',
80
80
  'Notice',