@ankhorage/zora 2.4.7 → 2.5.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.
- package/CHANGELOG.md +12 -0
- package/README.md +1542 -3430
- package/dist/components/breadcrumbs/Breadcrumbs.d.ts +4 -0
- package/dist/components/breadcrumbs/Breadcrumbs.d.ts.map +1 -0
- package/dist/components/breadcrumbs/Breadcrumbs.js +77 -0
- package/dist/components/breadcrumbs/Breadcrumbs.js.map +1 -0
- package/dist/components/breadcrumbs/index.d.ts +3 -0
- package/dist/components/breadcrumbs/index.d.ts.map +1 -0
- package/dist/components/breadcrumbs/index.js +2 -0
- package/dist/components/breadcrumbs/index.js.map +1 -0
- package/dist/components/breadcrumbs/meta.d.ts +9 -0
- package/dist/components/breadcrumbs/meta.d.ts.map +1 -0
- package/dist/components/breadcrumbs/meta.js +9 -0
- package/dist/components/breadcrumbs/meta.js.map +1 -0
- package/dist/components/breadcrumbs/types.d.ts +19 -0
- package/dist/components/breadcrumbs/types.d.ts.map +1 -0
- package/dist/components/breadcrumbs/types.js +2 -0
- package/dist/components/breadcrumbs/types.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/metadata/bindableComponentMeta.d.ts +553 -0
- package/dist/metadata/bindableComponentMeta.d.ts.map +1 -0
- package/dist/metadata/bindableComponentMeta.js +473 -0
- package/dist/metadata/bindableComponentMeta.js.map +1 -0
- package/dist/metadata/componentMeta.d.ts.map +1 -1
- package/dist/metadata/componentMeta.js +2 -0
- package/dist/metadata/componentMeta.js.map +1 -1
- package/dist/metadata/index.d.ts +2 -0
- package/dist/metadata/index.d.ts.map +1 -1
- package/dist/metadata/index.js +1 -0
- package/dist/metadata/index.js.map +1 -1
- package/dist/theme/useZoraTheme.d.ts +1 -1
- package/package.json +11 -2
- package/src/components/breadcrumbs/Breadcrumbs.tsx +143 -0
- package/src/components/breadcrumbs/index.ts +2 -0
- package/src/components/breadcrumbs/meta.ts +10 -0
- package/src/components/breadcrumbs/types.ts +21 -0
- package/src/index.ts +4 -1
- package/src/metadata/bindableComponentMeta.test.ts +18 -0
- package/src/metadata/bindableComponentMeta.ts +476 -0
- package/src/metadata/componentMeta.ts +2 -0
- package/src/metadata/index.ts +2 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/zora",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.5.0",
|
|
5
5
|
"description": "Opinionated React Native and React Native Web UI kit built on @ankhorage/surface.",
|
|
6
6
|
"homepage": "https://github.com/ankhorage/zora#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@ankhorage/color-theory": "^0.0.7",
|
|
47
|
-
"@ankhorage/contracts": "^1.
|
|
47
|
+
"@ankhorage/contracts": "^1.12.0",
|
|
48
48
|
"@ankhorage/surface": "^2.0.2"
|
|
49
49
|
},
|
|
50
50
|
"files": [
|
|
@@ -63,6 +63,13 @@
|
|
|
63
63
|
"import": "./dist/index.js",
|
|
64
64
|
"default": "./dist/index.js"
|
|
65
65
|
},
|
|
66
|
+
"./metadata": {
|
|
67
|
+
"react-native": "./src/metadata/index.ts",
|
|
68
|
+
"browser": "./src/metadata/index.ts",
|
|
69
|
+
"types": "./dist/metadata/index.d.ts",
|
|
70
|
+
"import": "./dist/metadata/index.js",
|
|
71
|
+
"default": "./dist/metadata/index.js"
|
|
72
|
+
},
|
|
66
73
|
"./package.json": "./package.json"
|
|
67
74
|
},
|
|
68
75
|
"publishConfig": {
|
|
@@ -72,6 +79,7 @@
|
|
|
72
79
|
"build": "rm -rf dist tsconfig.tsbuildinfo && bun x tsc -p tsconfig.json",
|
|
73
80
|
"changeset": "changeset",
|
|
74
81
|
"changeset:status": "changeset status --since=origin/main",
|
|
82
|
+
"docs": "paradox",
|
|
75
83
|
"knip": "ankhorage-knip",
|
|
76
84
|
"lint": "ankhorage-eslint . --max-warnings=0",
|
|
77
85
|
"lint:fix": "ankhorage-eslint . --fix --max-warnings=0",
|
|
@@ -84,6 +92,7 @@
|
|
|
84
92
|
},
|
|
85
93
|
"devDependencies": {
|
|
86
94
|
"@ankhorage/devtools": "^1.0.6",
|
|
95
|
+
"@ankhorage/paradox": "^0.1.7",
|
|
87
96
|
"@changesets/cli": "^2.31.0",
|
|
88
97
|
"@expo/vector-icons": "^15.1.1",
|
|
89
98
|
"@react-native-picker/picker": "^2.11.4",
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Inline } from '../../foundation';
|
|
4
|
+
import { resolveIconSize } from '../../internal/recipes';
|
|
5
|
+
import { useZoraTheme } from '../../theme/useZoraTheme';
|
|
6
|
+
import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
|
|
7
|
+
import { Button } from '../button';
|
|
8
|
+
import { Icon } from '../icon';
|
|
9
|
+
import { Text } from '../text';
|
|
10
|
+
import type { BreadcrumbItem, BreadcrumbsProps } from './types';
|
|
11
|
+
|
|
12
|
+
type BreadcrumbRenderItem =
|
|
13
|
+
| {
|
|
14
|
+
item: BreadcrumbItem;
|
|
15
|
+
type: 'item';
|
|
16
|
+
}
|
|
17
|
+
| {
|
|
18
|
+
type: 'ellipsis';
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function normalizeMaxItems(value: number | undefined): number | undefined {
|
|
22
|
+
if (value === undefined || !Number.isFinite(value)) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return Math.max(0, Math.trunc(value));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function createRenderItems(
|
|
30
|
+
items: readonly BreadcrumbItem[],
|
|
31
|
+
maxItems: number | undefined,
|
|
32
|
+
): readonly BreadcrumbRenderItem[] {
|
|
33
|
+
if (maxItems === undefined || maxItems === 0 || items.length <= maxItems || maxItems < 3) {
|
|
34
|
+
return items.map((item) => ({ item, type: 'item' }));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const [firstItem] = items;
|
|
38
|
+
if (firstItem === undefined) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const trailingCount = maxItems - 2;
|
|
43
|
+
const trailingItems = items.slice(items.length - trailingCount);
|
|
44
|
+
|
|
45
|
+
return [
|
|
46
|
+
{ item: firstItem, type: 'item' },
|
|
47
|
+
{ type: 'ellipsis' },
|
|
48
|
+
...trailingItems.map((item) => ({ item, type: 'item' }) satisfies BreadcrumbRenderItem),
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function renderSeparator(separator: React.ReactNode) {
|
|
53
|
+
return (
|
|
54
|
+
<Text emphasis="muted" variant="bodySmall">
|
|
55
|
+
{separator}
|
|
56
|
+
</Text>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function BreadcrumbLabel({ item, compact }: { item: BreadcrumbItem; compact: boolean }) {
|
|
61
|
+
const { theme } = useZoraTheme();
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<Inline align="center" gap="xs" wrap="nowrap">
|
|
65
|
+
{item.icon ? (
|
|
66
|
+
<Icon
|
|
67
|
+
color={theme.semantics.content.muted}
|
|
68
|
+
name={item.icon.name}
|
|
69
|
+
provider={item.icon.provider}
|
|
70
|
+
size={resolveIconSize(compact ? 's' : 'm')}
|
|
71
|
+
/>
|
|
72
|
+
) : null}
|
|
73
|
+
<Text emphasis="muted" variant={compact ? 'caption' : 'bodySmall'}>
|
|
74
|
+
{item.label}
|
|
75
|
+
</Text>
|
|
76
|
+
</Inline>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function BreadcrumbsInner({
|
|
81
|
+
themeId: _themeId,
|
|
82
|
+
mode: _mode,
|
|
83
|
+
items,
|
|
84
|
+
separator = '/',
|
|
85
|
+
maxItems,
|
|
86
|
+
compact = false,
|
|
87
|
+
disabled = false,
|
|
88
|
+
testID,
|
|
89
|
+
}: BreadcrumbsProps) {
|
|
90
|
+
const normalizedMaxItems = normalizeMaxItems(maxItems);
|
|
91
|
+
const renderItems = createRenderItems(items, normalizedMaxItems);
|
|
92
|
+
const currentItemId = items.at(-1)?.id;
|
|
93
|
+
|
|
94
|
+
if (items.length === 0) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<Inline align="center" gap={compact ? 'xs' : 's'} testID={testID} wrap="wrap">
|
|
100
|
+
{renderItems.map((renderItem, index) => {
|
|
101
|
+
const isLastRenderedItem = index === renderItems.length - 1;
|
|
102
|
+
const showSeparator = !isLastRenderedItem;
|
|
103
|
+
|
|
104
|
+
if (renderItem.type === 'ellipsis') {
|
|
105
|
+
return (
|
|
106
|
+
<React.Fragment key="ellipsis">
|
|
107
|
+
<Text emphasis="muted" variant={compact ? 'caption' : 'bodySmall'}>
|
|
108
|
+
…
|
|
109
|
+
</Text>
|
|
110
|
+
{showSeparator ? renderSeparator(separator) : null}
|
|
111
|
+
</React.Fragment>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const { item } = renderItem;
|
|
116
|
+
const current = item.id === currentItemId;
|
|
117
|
+
const interactive = !current && !disabled && !item.disabled && Boolean(item.onPress);
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<React.Fragment key={item.id}>
|
|
121
|
+
{interactive ? (
|
|
122
|
+
<Button
|
|
123
|
+
color="neutral"
|
|
124
|
+
leadingIcon={item.icon}
|
|
125
|
+
onPress={item.onPress}
|
|
126
|
+
size={compact ? 's' : 'm'}
|
|
127
|
+
testID={testID ? `${testID}-item-${item.id}` : undefined}
|
|
128
|
+
variant="ghost"
|
|
129
|
+
>
|
|
130
|
+
{item.label}
|
|
131
|
+
</Button>
|
|
132
|
+
) : (
|
|
133
|
+
<BreadcrumbLabel item={item} compact={compact} />
|
|
134
|
+
)}
|
|
135
|
+
{showSeparator ? renderSeparator(separator) : null}
|
|
136
|
+
</React.Fragment>
|
|
137
|
+
);
|
|
138
|
+
})}
|
|
139
|
+
</Inline>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export const Breadcrumbs = withZoraThemeScope(BreadcrumbsInner);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ZoraComponentMeta } from '../../metadata';
|
|
2
|
+
|
|
3
|
+
export const breadcrumbsMeta = {
|
|
4
|
+
name: 'Breadcrumbs',
|
|
5
|
+
category: 'component',
|
|
6
|
+
directManifestNode: false,
|
|
7
|
+
allowedChildren: [],
|
|
8
|
+
note: 'Code-facing route hierarchy component; not represented as a manifest node in v1.',
|
|
9
|
+
props: {},
|
|
10
|
+
} as const satisfies ZoraComponentMeta;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ButtonIconSpec } from '@ankhorage/surface';
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
|
|
5
|
+
|
|
6
|
+
export interface BreadcrumbItem {
|
|
7
|
+
id: string;
|
|
8
|
+
label: React.ReactNode;
|
|
9
|
+
icon?: ButtonIconSpec;
|
|
10
|
+
onPress?: () => void;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface BreadcrumbsProps extends ZoraBaseProps {
|
|
15
|
+
items: readonly BreadcrumbItem[];
|
|
16
|
+
separator?: React.ReactNode;
|
|
17
|
+
maxItems?: number;
|
|
18
|
+
compact?: boolean;
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
testID?: string;
|
|
21
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,8 @@ export type { AvatarGroupItem, AvatarGroupProps } from './components/avatar-grou
|
|
|
8
8
|
export { AvatarGroup } from './components/avatar-group';
|
|
9
9
|
export type { BadgeProps } from './components/badge';
|
|
10
10
|
export { Badge } from './components/badge';
|
|
11
|
+
export type { BreadcrumbItem, BreadcrumbsProps } from './components/breadcrumbs';
|
|
12
|
+
export { Breadcrumbs } from './components/breadcrumbs';
|
|
11
13
|
export type { ButtonProps } from './components/button';
|
|
12
14
|
export { Button } from './components/button';
|
|
13
15
|
export type {
|
|
@@ -192,6 +194,7 @@ export { SidebarLayout } from './layout/sidebar-layout';
|
|
|
192
194
|
export type { TopbarLayoutProps } from './layout/topbar-layout';
|
|
193
195
|
export { TopbarLayout } from './layout/topbar-layout';
|
|
194
196
|
export type {
|
|
197
|
+
ZoraBindableComponentType,
|
|
195
198
|
ZoraComponentBlueprint,
|
|
196
199
|
ZoraComponentCategory,
|
|
197
200
|
ZoraComponentEventMeta,
|
|
@@ -207,7 +210,7 @@ export type {
|
|
|
207
210
|
ZoraComponentPropValue,
|
|
208
211
|
ZoraComponentSlotMeta,
|
|
209
212
|
} from './metadata';
|
|
210
|
-
export { ZORA_COMPONENT_META } from './metadata';
|
|
213
|
+
export { ZORA_BINDABLE_COMPONENT_META, ZORA_COMPONENT_META } from './metadata';
|
|
211
214
|
export type {
|
|
212
215
|
AuthFormBaseProps,
|
|
213
216
|
AuthIdentifierKind,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { UiComponentMetaRegistry } from '@ankhorage/contracts';
|
|
2
|
+
import { describe, expect, it } from 'bun:test';
|
|
3
|
+
|
|
4
|
+
import { ZORA_BINDABLE_COMPONENT_META } from './bindableComponentMeta';
|
|
5
|
+
|
|
6
|
+
describe('ZORA bindable component metadata', () => {
|
|
7
|
+
it('matches the shared UI metadata registry shape', () => {
|
|
8
|
+
const registry: UiComponentMetaRegistry = ZORA_BINDABLE_COMPONENT_META;
|
|
9
|
+
|
|
10
|
+
expect(registry.Text?.bindings?.props?.text?.value.type).toBe('string');
|
|
11
|
+
expect(registry.Heading?.bindings?.props?.text?.value.type).toBe('string');
|
|
12
|
+
expect(registry.Button?.bindings?.props?.children?.value.type).toBe('string');
|
|
13
|
+
expect(registry.Input?.bindings?.props?.value?.value.type).toBe('string');
|
|
14
|
+
expect(registry.Select?.bindings?.props?.value?.value.type).toBe('string');
|
|
15
|
+
expect(registry.Image?.bindings?.props?.source?.value.type).toBe('imageAsset');
|
|
16
|
+
expect(registry.DataTable?.bindings?.props?.rows?.value.type).toBe('array');
|
|
17
|
+
});
|
|
18
|
+
});
|