@ankhorage/zora 3.3.1 → 3.3.3

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 (64) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/components/card/meta.d.ts +1 -1
  3. package/dist/foundation/meta.d.ts +4 -4
  4. package/dist/index.d.ts +3 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/layout/screen/meta.d.ts +1 -1
  9. package/dist/layout/screen-section/meta.d.ts +1 -1
  10. package/dist/metadata/allowedChildren.d.ts +4 -4
  11. package/dist/metadata/allowedChildren.d.ts.map +1 -1
  12. package/dist/metadata/allowedChildren.js +2 -0
  13. package/dist/metadata/allowedChildren.js.map +1 -1
  14. package/dist/metadata/bindableComponentMeta.d.ts +2 -2
  15. package/dist/metadata/componentMeta.d.ts.map +1 -1
  16. package/dist/metadata/componentMeta.js +2 -0
  17. package/dist/metadata/componentMeta.js.map +1 -1
  18. package/dist/metadata/index.d.ts +1 -1
  19. package/dist/metadata/index.d.ts.map +1 -1
  20. package/dist/metadata/index.js.map +1 -1
  21. package/dist/metadata/types.d.ts +6 -0
  22. package/dist/metadata/types.d.ts.map +1 -1
  23. package/dist/metadata/types.js.map +1 -1
  24. package/dist/patterns/content-rail/meta.d.ts +2 -2
  25. package/dist/patterns/message-bubble/meta.d.ts +1 -1
  26. package/dist/patterns/missing-element/MissingElement.d.ts +10 -0
  27. package/dist/patterns/missing-element/MissingElement.d.ts.map +1 -0
  28. package/dist/patterns/missing-element/MissingElement.js +41 -0
  29. package/dist/patterns/missing-element/MissingElement.js.map +1 -0
  30. package/dist/patterns/missing-element/index.d.ts +3 -0
  31. package/dist/patterns/missing-element/index.d.ts.map +1 -0
  32. package/dist/patterns/missing-element/index.js +2 -0
  33. package/dist/patterns/missing-element/index.js.map +1 -0
  34. package/dist/patterns/missing-element/meta.d.ts +68 -0
  35. package/dist/patterns/missing-element/meta.d.ts.map +1 -0
  36. package/dist/patterns/missing-element/meta.js +59 -0
  37. package/dist/patterns/missing-element/meta.js.map +1 -0
  38. package/dist/patterns/missing-element/types.d.ts +9 -0
  39. package/dist/patterns/missing-element/types.d.ts.map +1 -0
  40. package/dist/patterns/missing-element/types.js +2 -0
  41. package/dist/patterns/missing-element/types.js.map +1 -0
  42. package/dist/patterns/notice/meta.d.ts +1 -1
  43. package/dist/patterns/panel/meta.d.ts +1 -1
  44. package/dist/patterns/post-card/meta.d.ts +1 -1
  45. package/dist/patterns/reader/meta.d.ts +2 -2
  46. package/dist/patterns/scanner/meta.d.ts +2 -2
  47. package/dist/registry.d.ts.map +1 -1
  48. package/dist/registry.js +2 -0
  49. package/dist/registry.js.map +1 -1
  50. package/package.json +5 -5
  51. package/src/expo57Migration.test.ts +16 -1
  52. package/src/index.ts +3 -0
  53. package/src/metadata/allowedChildren.ts +2 -0
  54. package/src/metadata/componentMeta.test.ts +16 -0
  55. package/src/metadata/componentMeta.ts +2 -0
  56. package/src/metadata/index.ts +1 -0
  57. package/src/metadata/types.ts +7 -0
  58. package/src/patterns/missing-element/MissingElement.test.ts +66 -0
  59. package/src/patterns/missing-element/MissingElement.tsx +73 -0
  60. package/src/patterns/missing-element/index.ts +2 -0
  61. package/src/patterns/missing-element/meta.ts +62 -0
  62. package/src/patterns/missing-element/types.ts +9 -0
  63. package/src/patterns/theme-composer/ThemeComposer.test.ts +9 -13
  64. package/src/registry.ts +2 -0
@@ -0,0 +1,66 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+
3
+ import { ZORA_BINDABLE_COMPONENT_META, ZORA_COMPONENT_META } from '../../metadata';
4
+ import { missingElementMeta } from './meta';
5
+
6
+ describe('MissingElement draft contract', () => {
7
+ test('is a release-blocking manifest leaf distinct from completed states', () => {
8
+ expect(ZORA_COMPONENT_META.MissingElement).toBe(missingElementMeta);
9
+ expect(missingElementMeta.directManifestNode).toBe(true);
10
+ expect(missingElementMeta.allowedChildren).toEqual([]);
11
+ expect(missingElementMeta.manifestPolicy).toEqual({
12
+ kind: 'unresolved-element',
13
+ availability: 'draft-only',
14
+ releaseGate: 'blocked',
15
+ });
16
+ expect(ZORA_COMPONENT_META.Notice.manifestPolicy).toBeUndefined();
17
+ expect(ZORA_COMPONENT_META.EmptyState.manifestPolicy).toBeUndefined();
18
+ });
19
+
20
+ test('captures only stable serializable gap and layout data', () => {
21
+ expect(Object.keys(missingElementMeta.props)).toEqual([
22
+ 'requestedCapability',
23
+ 'reason',
24
+ 'evidenceId',
25
+ 'minimumWidth',
26
+ 'minimumHeight',
27
+ ]);
28
+ expect(missingElementMeta.blueprint.defaultProps).toEqual({
29
+ requestedCapability: 'Unresolved interface capability',
30
+ reason: 'No matching ZORA element is available.',
31
+ minimumWidth: 240,
32
+ minimumHeight: 160,
33
+ });
34
+ expect(() => JSON.stringify(missingElementMeta)).not.toThrow();
35
+ });
36
+
37
+ test('has no event, data-binding, runtime-requirement, or fallback contract', () => {
38
+ expect(missingElementMeta.events).toBeUndefined();
39
+ expect(missingElementMeta.requirements).toBeUndefined();
40
+ expect(ZORA_BINDABLE_COMPONENT_META).not.toHaveProperty('MissingElement');
41
+ });
42
+
43
+ test('visibly and accessibly identifies the gap while preserving its minimum dimensions', async () => {
44
+ const source = await Bun.file('src/patterns/missing-element/MissingElement.tsx').text();
45
+
46
+ expect(source).toContain('accessibilityLabel={accessibilityLabel}');
47
+ expect(source).toContain('accessibilityRole="text"');
48
+ expect(source).toContain('accessible');
49
+ expect(source).toContain('minHeight={minimumHeight}');
50
+ expect(source).toContain('minWidth={minimumWidth}');
51
+ expect(source).toContain('{requestedCapability}');
52
+ expect(source).toContain('{reason}');
53
+ });
54
+
55
+ test('accepts the canonical interaction policy without owning interactive behavior', async () => {
56
+ const [source, types] = await Promise.all([
57
+ Bun.file('src/patterns/missing-element/MissingElement.tsx').text(),
58
+ Bun.file('src/patterns/missing-element/types.ts').text(),
59
+ ]);
60
+
61
+ expect(types).toContain('MissingElementProps extends ZoraBaseProps');
62
+ expect(source).toContain('interactionPolicy: _interactionPolicy');
63
+ expect(source).not.toMatch(/onPress|onLongPress|onChange|onSubmit/);
64
+ expect(source).not.toMatch(/<Button|<IconButton|<Notice|<EmptyState/);
65
+ });
66
+ });
@@ -0,0 +1,73 @@
1
+ import React from 'react';
2
+ import { StyleSheet } from 'react-native';
3
+
4
+ import { Badge } from '../../components/badge';
5
+ import { Text } from '../../components/text';
6
+ import { Box, Stack } from '../../foundation';
7
+ import { useZoraTheme } from '../../theme/useZoraTheme';
8
+ import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
9
+ import type { MissingElementProps } from './types';
10
+
11
+ /***
12
+ * Renders the visible, non-interactive body of a draft missing-element marker.
13
+ */
14
+ function MissingElementInner({
15
+ themeId: _themeId,
16
+ mode: _mode,
17
+ interactionPolicy: _interactionPolicy,
18
+ requestedCapability,
19
+ reason,
20
+ evidenceId,
21
+ minimumWidth,
22
+ minimumHeight,
23
+ testID,
24
+ }: MissingElementProps) {
25
+ const { theme } = useZoraTheme();
26
+ const accessibilityLabel = `Missing element: ${requestedCapability}. ${reason}`;
27
+
28
+ return (
29
+ <Box
30
+ accessibilityLabel={accessibilityLabel}
31
+ accessibilityRole="text"
32
+ accessible
33
+ bg={theme.semantics.warning.softBg}
34
+ borderColor={theme.semantics.warning.base}
35
+ borderWidth={1}
36
+ minHeight={minimumHeight}
37
+ minWidth={minimumWidth}
38
+ p="m"
39
+ radius="m"
40
+ style={styles.root}
41
+ testID={testID}
42
+ >
43
+ <Stack gap="xs">
44
+ <Badge color="warning">Missing element</Badge>
45
+ <Text variant="label" weight="semiBold">
46
+ {requestedCapability}
47
+ </Text>
48
+ <Text emphasis="muted" variant="bodySmall">
49
+ {reason}
50
+ </Text>
51
+ {evidenceId ? (
52
+ <Text emphasis="subtle" variant="caption">
53
+ Evidence: {evidenceId}
54
+ </Text>
55
+ ) : null}
56
+ </Stack>
57
+ </Box>
58
+ );
59
+ }
60
+
61
+ const styles = StyleSheet.create({
62
+ root: {
63
+ borderStyle: 'dashed',
64
+ },
65
+ });
66
+
67
+ /***
68
+ * Draft-only marker that preserves an unsupported manifest region without faking its capability.
69
+ *
70
+ * `MissingElement` is intentionally non-interactive and release-blocking in component metadata.
71
+ * Replace it with a released semantic ZORA element before publishing a production template.
72
+ */
73
+ export const MissingElement = withZoraThemeScope(MissingElementInner);
@@ -0,0 +1,2 @@
1
+ export { MissingElement } from './MissingElement';
2
+ export type { MissingElementProps } from './types';
@@ -0,0 +1,62 @@
1
+ import type { ZoraComponentMeta } from '../../metadata';
2
+
3
+ const instanceAuthoring = { authority: 'instance' } as const;
4
+
5
+ export const missingElementMeta = {
6
+ name: 'MissingElement',
7
+ category: 'pattern',
8
+ description:
9
+ 'Draft-only marker for an unresolved semantic ZORA capability that must be replaced before release.',
10
+ directManifestNode: true,
11
+ allowedChildren: [],
12
+ manifestPolicy: {
13
+ kind: 'unresolved-element',
14
+ availability: 'draft-only',
15
+ releaseGate: 'blocked',
16
+ },
17
+ blueprint: {
18
+ label: 'Missing element',
19
+ defaultProps: {
20
+ requestedCapability: 'Unresolved interface capability',
21
+ reason: 'No matching ZORA element is available.',
22
+ minimumWidth: 240,
23
+ minimumHeight: 160,
24
+ },
25
+ },
26
+ props: {
27
+ requestedCapability: {
28
+ type: 'string',
29
+ category: 'Gap',
30
+ label: 'Requested capability',
31
+ default: 'Unresolved interface capability',
32
+ authoring: instanceAuthoring,
33
+ },
34
+ reason: {
35
+ type: 'string',
36
+ category: 'Gap',
37
+ label: 'Reason',
38
+ default: 'No matching ZORA element is available.',
39
+ authoring: instanceAuthoring,
40
+ },
41
+ evidenceId: {
42
+ type: 'string',
43
+ category: 'Evidence',
44
+ label: 'Evidence ID',
45
+ authoring: instanceAuthoring,
46
+ },
47
+ minimumWidth: {
48
+ type: 'number',
49
+ category: 'Layout',
50
+ label: 'Minimum width',
51
+ default: 240,
52
+ authoring: instanceAuthoring,
53
+ },
54
+ minimumHeight: {
55
+ type: 'number',
56
+ category: 'Layout',
57
+ label: 'Minimum height',
58
+ default: 160,
59
+ authoring: instanceAuthoring,
60
+ },
61
+ },
62
+ } as const satisfies ZoraComponentMeta;
@@ -0,0 +1,9 @@
1
+ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
2
+
3
+ export interface MissingElementProps extends ZoraBaseProps {
4
+ requestedCapability: string;
5
+ reason: string;
6
+ evidenceId?: string;
7
+ minimumWidth?: number;
8
+ minimumHeight?: number;
9
+ }
@@ -1,10 +1,14 @@
1
- import { COLOR_HARMONIES, parseHexColorOrThrow } from '@ankhorage/color-theory';
1
+ import { readFileSync } from 'node:fs';
2
+
3
+ import { parseHexColorOrThrow } from '@ankhorage/color-theory';
2
4
  import { APP_CATEGORIES } from '@ankhorage/contracts';
3
5
  import { describe, expect, test } from 'bun:test';
4
6
 
5
7
  import { zoraDefaultTheme } from '../../theme/zoraDefaultTheme';
6
8
  import type { ThemeComposerProps } from './types';
7
9
 
10
+ const themeComposerSource = readFileSync(new URL('./ThemeComposer.tsx', import.meta.url), 'utf8');
11
+
8
12
  // ---------------------------------------------------------------------------
9
13
  // ThemeComposerProps shape tests
10
14
  // ---------------------------------------------------------------------------
@@ -56,20 +60,12 @@ describe('ThemeComposerProps', () => {
56
60
  });
57
61
 
58
62
  // ---------------------------------------------------------------------------
59
- // COLOR_HARMONIES coverage
63
+ // COLOR_HARMONIES ownership
60
64
  // ---------------------------------------------------------------------------
61
65
 
62
- describe('COLOR_HARMONIES coverage for ThemeComposer', () => {
63
- test('all canonical harmony values are present for the Select options', () => {
64
- const expected = [
65
- 'monochromatic',
66
- 'analogous',
67
- 'complementary',
68
- 'triadic',
69
- 'tetradic',
70
- 'splitComplementary',
71
- ] as const;
72
- expect(COLOR_HARMONIES).toEqual(expected);
66
+ describe('COLOR_HARMONIES ownership for ThemeComposer', () => {
67
+ test('derives Select options from the canonical Color Theory catalog', () => {
68
+ expect(themeComposerSource).toContain('COLOR_HARMONIES.map');
73
69
  });
74
70
  });
75
71
 
package/src/registry.ts CHANGED
@@ -82,6 +82,7 @@ import { ImageUploadField } from './patterns/image-upload-field';
82
82
  import { InspectorField } from './patterns/inspector-field';
83
83
  import { List, ListRow, ListSection } from './patterns/list';
84
84
  import { MessageBubble } from './patterns/message-bubble';
85
+ import { MissingElement } from './patterns/missing-element';
85
86
  import { Notice } from './patterns/notice';
86
87
  import { Panel } from './patterns/panel';
87
88
  import { PostCard } from './patterns/post-card';
@@ -219,6 +220,7 @@ const _ZORA_COMPONENT_REGISTRY = {
219
220
  ListRow,
220
221
  ListSection,
221
222
  MessageBubble,
223
+ MissingElement,
222
224
  Notice,
223
225
  Panel,
224
226
  PostCard,