@ankhorage/zora 2.10.0 → 2.12.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 +2 -2
- package/dist/components/button/Button.d.ts.map +1 -1
- package/dist/components/button/Button.js +4 -2
- package/dist/components/button/Button.js.map +1 -1
- package/dist/components/button/meta.d.ts +3 -6
- package/dist/components/button/meta.d.ts.map +1 -1
- package/dist/components/button/meta.js +9 -15
- package/dist/components/button/meta.js.map +1 -1
- package/dist/components/button/resolveButtonThemeRecipe.d.ts +9 -0
- package/dist/components/button/resolveButtonThemeRecipe.d.ts.map +1 -0
- package/dist/components/button/resolveButtonThemeRecipe.js +30 -0
- package/dist/components/button/resolveButtonThemeRecipe.js.map +1 -0
- package/dist/components/button/themeRecipeMeta.d.ts +4 -10
- package/dist/components/button/themeRecipeMeta.d.ts.map +1 -1
- package/dist/components/button/themeRecipeMeta.js +5 -10
- package/dist/components/button/themeRecipeMeta.js.map +1 -1
- package/dist/components/card/Card.d.ts.map +1 -1
- package/dist/components/card/Card.js +8 -4
- package/dist/components/card/Card.js.map +1 -1
- package/dist/components/card/meta.d.ts +23 -4
- package/dist/components/card/meta.d.ts.map +1 -1
- package/dist/components/card/meta.js +14 -15
- package/dist/components/card/meta.js.map +1 -1
- package/dist/components/card/resolveCardThemeRecipe.d.ts +15 -0
- package/dist/components/card/resolveCardThemeRecipe.d.ts.map +1 -0
- package/dist/components/card/resolveCardThemeRecipe.js +22 -0
- package/dist/components/card/resolveCardThemeRecipe.js.map +1 -0
- package/dist/components/card/themeRecipeMeta.d.ts +1 -1
- package/dist/components/card/themeRecipeMeta.js +1 -1
- package/dist/components/card/themeRecipeMeta.js.map +1 -1
- package/dist/components/card/types.d.ts +2 -0
- package/dist/components/card/types.d.ts.map +1 -1
- package/dist/components/card/types.js.map +1 -1
- package/dist/components/heading/Heading.d.ts.map +1 -1
- package/dist/components/heading/Heading.js +14 -15
- package/dist/components/heading/Heading.js.map +1 -1
- package/dist/components/heading/meta.d.ts +6 -1
- package/dist/components/heading/meta.d.ts.map +1 -1
- package/dist/components/heading/meta.js +13 -22
- package/dist/components/heading/meta.js.map +1 -1
- package/dist/components/heading/resolveHeadingThemeRecipe.d.ts +11 -0
- package/dist/components/heading/resolveHeadingThemeRecipe.d.ts.map +1 -0
- package/dist/components/heading/resolveHeadingThemeRecipe.js +46 -0
- package/dist/components/heading/resolveHeadingThemeRecipe.js.map +1 -0
- package/dist/components/heading/themeRecipeMeta.d.ts +39 -0
- package/dist/components/heading/themeRecipeMeta.d.ts.map +1 -0
- package/dist/components/heading/themeRecipeMeta.js +32 -0
- package/dist/components/heading/themeRecipeMeta.js.map +1 -0
- package/dist/components/text/Text.d.ts +0 -1
- package/dist/components/text/Text.d.ts.map +1 -1
- package/dist/components/text/Text.js +14 -16
- package/dist/components/text/Text.js.map +1 -1
- package/dist/components/text/meta.d.ts +6 -5
- package/dist/components/text/meta.d.ts.map +1 -1
- package/dist/components/text/meta.js +13 -25
- package/dist/components/text/meta.js.map +1 -1
- package/dist/components/text/resolveTextThemeRecipe.d.ts +11 -0
- package/dist/components/text/resolveTextThemeRecipe.d.ts.map +1 -0
- package/dist/components/text/resolveTextThemeRecipe.js +46 -0
- package/dist/components/text/resolveTextThemeRecipe.js.map +1 -0
- package/dist/components/text/themeRecipeMeta.d.ts +15 -7
- package/dist/components/text/themeRecipeMeta.d.ts.map +1 -1
- package/dist/components/text/themeRecipeMeta.js +12 -11
- package/dist/components/text/themeRecipeMeta.js.map +1 -1
- package/dist/foundation/meta.d.ts +4 -4
- package/dist/layout/screen/meta.d.ts +1 -1
- package/dist/layout/screen-section/meta.d.ts +1 -1
- package/dist/metadata/allowedChildren.d.ts +3 -3
- package/dist/metadata/allowedChildren.d.ts.map +1 -1
- package/dist/metadata/allowedChildren.js +1 -0
- package/dist/metadata/allowedChildren.js.map +1 -1
- 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/themeRecipeMeta.d.ts.map +1 -1
- package/dist/metadata/themeRecipeMeta.js +2 -0
- package/dist/metadata/themeRecipeMeta.js.map +1 -1
- package/dist/metadata/themeRecipeTypes.d.ts +3 -3
- package/dist/metadata/themeRecipeTypes.d.ts.map +1 -1
- package/dist/metadata/themeRecipeTypes.js.map +1 -1
- package/dist/metadata/types.d.ts +1 -0
- package/dist/metadata/types.d.ts.map +1 -1
- package/dist/metadata/types.js.map +1 -1
- package/dist/patterns/message-bubble/meta.d.ts +1 -1
- package/dist/patterns/notice/meta.d.ts +1 -1
- package/dist/patterns/panel/Panel.d.ts +0 -2
- package/dist/patterns/panel/Panel.d.ts.map +1 -1
- package/dist/patterns/panel/Panel.js +6 -4
- package/dist/patterns/panel/Panel.js.map +1 -1
- package/dist/patterns/panel/meta.d.ts +23 -4
- package/dist/patterns/panel/meta.d.ts.map +1 -1
- package/dist/patterns/panel/meta.js +14 -15
- package/dist/patterns/panel/meta.js.map +1 -1
- package/dist/patterns/panel/themeRecipeMeta.d.ts +1 -1
- package/dist/patterns/panel/themeRecipeMeta.js +1 -1
- package/dist/patterns/panel/themeRecipeMeta.js.map +1 -1
- package/dist/patterns/panel/types.d.ts +2 -0
- package/dist/patterns/panel/types.d.ts.map +1 -1
- package/dist/patterns/panel/types.js.map +1 -1
- package/dist/patterns/post-card/meta.d.ts +1 -1
- package/dist/patterns/scanner/meta.d.ts +2 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +2 -0
- package/dist/registry.js.map +1 -1
- package/dist/theme/ThemeModeToggle.d.ts +1 -1
- package/dist/theme/ThemeModeToggle.d.ts.map +1 -1
- package/dist/theme/ThemeModeToggle.js +2 -2
- package/dist/theme/ThemeModeToggle.js.map +1 -1
- package/dist/theme/ThemeModeToggle.meta.d.ts +28 -0
- package/dist/theme/ThemeModeToggle.meta.d.ts.map +1 -0
- package/dist/theme/ThemeModeToggle.meta.js +28 -0
- package/dist/theme/ThemeModeToggle.meta.js.map +1 -0
- package/dist/theme/ThemeModeToggleProps.d.ts +1 -1
- package/dist/theme/ThemeModeToggleProps.d.ts.map +1 -1
- package/dist/theme/ThemeModeToggleProps.js.map +1 -1
- package/dist/theme/ZoraProvider.d.ts +4 -12
- package/dist/theme/ZoraProvider.d.ts.map +1 -1
- package/dist/theme/ZoraProvider.js +5 -14
- package/dist/theme/ZoraProvider.js.map +1 -1
- package/dist/theme/ZoraThemeRuntimeContext.d.ts +1 -2
- package/dist/theme/ZoraThemeRuntimeContext.d.ts.map +1 -1
- package/dist/theme/ZoraThemeRuntimeContext.js +0 -1
- package/dist/theme/ZoraThemeRuntimeContext.js.map +1 -1
- package/dist/theme/ZoraThemeScope.d.ts.map +1 -1
- package/dist/theme/ZoraThemeScope.js +4 -10
- package/dist/theme/ZoraThemeScope.js.map +1 -1
- package/dist/theme/resolveZoraThemeRecipe.d.ts +16 -0
- package/dist/theme/resolveZoraThemeRecipe.d.ts.map +1 -0
- package/dist/theme/resolveZoraThemeRecipe.js +56 -0
- package/dist/theme/resolveZoraThemeRecipe.js.map +1 -0
- package/dist/theme/useZoraThemeRecipe.d.ts +2 -0
- package/dist/theme/useZoraThemeRecipe.d.ts.map +1 -0
- package/dist/theme/useZoraThemeRecipe.js +7 -0
- package/dist/theme/useZoraThemeRecipe.js.map +1 -0
- package/package.json +4 -4
- package/src/components/button/Button.tsx +4 -2
- package/src/components/button/meta.ts +10 -15
- package/src/components/button/resolveButtonThemeRecipe.test.ts +25 -0
- package/src/components/button/resolveButtonThemeRecipe.ts +41 -0
- package/src/components/button/themeRecipeMeta.ts +5 -10
- package/src/components/card/Card.tsx +13 -7
- package/src/components/card/meta.ts +15 -15
- package/src/components/card/resolveCardThemeRecipe.test.ts +28 -0
- package/src/components/card/resolveCardThemeRecipe.ts +33 -0
- package/src/components/card/themeRecipeMeta.ts +1 -1
- package/src/components/card/types.ts +2 -0
- package/src/components/contentFallback.test.ts +4 -4
- package/src/components/heading/Heading.tsx +18 -28
- package/src/components/heading/meta.ts +14 -22
- package/src/components/heading/resolveHeadingThemeRecipe.ts +55 -0
- package/src/components/heading/themeRecipeMeta.ts +33 -0
- package/src/components/text/Text.tsx +16 -25
- package/src/components/text/meta.ts +14 -25
- package/src/components/text/resolveTextThemeRecipe.ts +48 -0
- package/src/components/text/themeRecipeMeta.ts +12 -11
- package/src/metadata/allowedChildren.ts +1 -0
- package/src/metadata/authoringMeta.test.ts +18 -44
- package/src/metadata/componentMeta.test.ts +8 -0
- package/src/metadata/componentMeta.ts +2 -0
- package/src/metadata/themeRecipeMeta.test.ts +41 -39
- package/src/metadata/themeRecipeMeta.ts +2 -0
- package/src/metadata/themeRecipeTypes.ts +3 -3
- package/src/metadata/types.ts +3 -9
- package/src/patterns/panel/Panel.tsx +14 -4
- package/src/patterns/panel/meta.ts +15 -15
- package/src/patterns/panel/themeRecipeMeta.ts +1 -1
- package/src/patterns/panel/types.ts +2 -0
- package/src/registry.test.ts +5 -3
- package/src/registry.ts +2 -0
- package/src/theme/ThemeModeToggle.meta.ts +29 -0
- package/src/theme/ThemeModeToggle.tsx +7 -1
- package/src/theme/ThemeModeToggleProps.ts +4 -1
- package/src/theme/ZoraProvider.tsx +10 -13
- package/src/theme/ZoraThemeRuntimeContext.tsx +1 -3
- package/src/theme/ZoraThemeScope.tsx +5 -25
- package/src/theme/resolveZoraThemeRecipe.test.ts +72 -0
- package/src/theme/resolveZoraThemeRecipe.ts +91 -0
- package/src/theme/themeConfigScope.test.ts +25 -0
- package/src/theme/useZoraThemeRecipe.ts +7 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import { resolveCardThemeRecipe } from './resolveCardThemeRecipe';
|
|
4
|
+
|
|
5
|
+
describe('resolveCardThemeRecipe', () => {
|
|
6
|
+
test('preserves compact-aware padding when theme padding is unset', () => {
|
|
7
|
+
expect(
|
|
8
|
+
resolveCardThemeRecipe({ themeFields: { tone: 'default', compact: true, radius: 'l' } }),
|
|
9
|
+
).toEqual({
|
|
10
|
+
tone: 'default',
|
|
11
|
+
compact: true,
|
|
12
|
+
padding: 'm',
|
|
13
|
+
radius: 'l',
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('lets explicit instance props win over theme values', () => {
|
|
18
|
+
expect(
|
|
19
|
+
resolveCardThemeRecipe({
|
|
20
|
+
tone: 'outline',
|
|
21
|
+
compact: false,
|
|
22
|
+
padding: 'hero',
|
|
23
|
+
radius: 'pill',
|
|
24
|
+
themeFields: { tone: 'subtle', compact: true, padding: 'm', radius: 'l' },
|
|
25
|
+
}),
|
|
26
|
+
).toEqual({ tone: 'outline', compact: false, padding: 'hero', radius: 'pill' });
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ThemeRecipeOverrideValue } from '@ankhorage/contracts';
|
|
2
|
+
|
|
3
|
+
import type { ZoraCardTone } from '../../internal/recipes';
|
|
4
|
+
|
|
5
|
+
export function resolveCardThemeRecipe(input: {
|
|
6
|
+
readonly tone?: ZoraCardTone;
|
|
7
|
+
readonly compact?: boolean;
|
|
8
|
+
readonly padding?: string;
|
|
9
|
+
readonly radius?: string;
|
|
10
|
+
readonly themeFields: Readonly<Record<string, ThemeRecipeOverrideValue>>;
|
|
11
|
+
}) {
|
|
12
|
+
const tone = input.tone ?? readTone(input.themeFields.tone) ?? 'default';
|
|
13
|
+
const compact = input.compact ?? readBoolean(input.themeFields.compact) ?? false;
|
|
14
|
+
return {
|
|
15
|
+
tone,
|
|
16
|
+
compact,
|
|
17
|
+
padding: input.padding ?? readString(input.themeFields.padding) ?? (compact ? 'm' : 'l'),
|
|
18
|
+
radius: input.radius ?? readString(input.themeFields.radius) ?? 'l',
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function readTone(value: ThemeRecipeOverrideValue | undefined): ZoraCardTone | undefined {
|
|
23
|
+
if (value === 'default' || value === 'subtle' || value === 'outline') return value;
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function readBoolean(value: ThemeRecipeOverrideValue | undefined): boolean | undefined {
|
|
28
|
+
return typeof value === 'boolean' ? value : undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function readString(value: ThemeRecipeOverrideValue | undefined): string | undefined {
|
|
32
|
+
return typeof value === 'string' ? value : undefined;
|
|
33
|
+
}
|
|
@@ -9,15 +9,15 @@ const headingSource = readFileSync(join(import.meta.dir, 'heading', 'Heading.tsx
|
|
|
9
9
|
describe('content fallback ownership', () => {
|
|
10
10
|
it('keeps Text free of translation context coupling', () => {
|
|
11
11
|
expect(textSource).not.toMatch(/useTranslationContext/);
|
|
12
|
-
expect(textSource).toMatch(/if \(children !== undefined\)
|
|
13
|
-
expect(textSource).toMatch(/if \(text !== undefined\)
|
|
12
|
+
expect(textSource).toMatch(/if \(children !== undefined\) return children;/);
|
|
13
|
+
expect(textSource).toMatch(/if \(text !== undefined\) return text;/);
|
|
14
14
|
expect(textSource).toMatch(/return i18nKey;/);
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
it('keeps Heading free of translation context coupling', () => {
|
|
18
18
|
expect(headingSource).not.toMatch(/useTranslationContext/);
|
|
19
|
-
expect(headingSource).toMatch(/if \(children !== undefined\)
|
|
20
|
-
expect(headingSource).toMatch(/if \(text !== undefined\)
|
|
19
|
+
expect(headingSource).toMatch(/if \(children !== undefined\) return children;/);
|
|
20
|
+
expect(headingSource).toMatch(/if \(text !== undefined\) return text;/);
|
|
21
21
|
expect(headingSource).toMatch(/return i18nKey;/);
|
|
22
22
|
});
|
|
23
23
|
});
|
|
@@ -3,8 +3,10 @@ import React from 'react';
|
|
|
3
3
|
import { Platform, Text as ReactNativeText, type TextStyle } from 'react-native';
|
|
4
4
|
|
|
5
5
|
import { useZoraTheme } from '../../theme/useZoraTheme';
|
|
6
|
+
import { useZoraThemeRecipe } from '../../theme/useZoraThemeRecipe';
|
|
6
7
|
import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
|
|
7
8
|
import { resolveHeadingRecipe, resolveHeadingSizeFromLevel } from './resolveHeadingRecipe';
|
|
9
|
+
import { resolveHeadingThemeRecipe } from './resolveHeadingThemeRecipe';
|
|
8
10
|
import type { HeadingProps } from './types';
|
|
9
11
|
|
|
10
12
|
const headingLayoutStyle = {
|
|
@@ -24,23 +26,10 @@ function resolveHeadingContent({
|
|
|
24
26
|
children,
|
|
25
27
|
text,
|
|
26
28
|
i18nKey,
|
|
27
|
-
}: {
|
|
28
|
-
children
|
|
29
|
-
text
|
|
30
|
-
i18nKey
|
|
31
|
-
}): React.ReactNode {
|
|
32
|
-
if (children !== undefined) {
|
|
33
|
-
return children;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (text !== undefined) {
|
|
37
|
-
return text;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (!i18nKey) {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
|
|
29
|
+
}: Pick<HeadingProps, 'children' | 'text' | 'i18nKey'>) {
|
|
30
|
+
if (children !== undefined) return children;
|
|
31
|
+
if (text !== undefined) return text;
|
|
32
|
+
if (i18nKey === undefined || i18nKey === '') return null;
|
|
44
33
|
return i18nKey;
|
|
45
34
|
}
|
|
46
35
|
|
|
@@ -53,10 +42,10 @@ function HeadingInner({
|
|
|
53
42
|
level = 2,
|
|
54
43
|
size,
|
|
55
44
|
color,
|
|
56
|
-
emphasis
|
|
45
|
+
emphasis,
|
|
57
46
|
align,
|
|
58
47
|
weight,
|
|
59
|
-
italic
|
|
48
|
+
italic,
|
|
60
49
|
numberOfLines,
|
|
61
50
|
ellipsizeMode,
|
|
62
51
|
selectable,
|
|
@@ -70,16 +59,17 @@ function HeadingInner({
|
|
|
70
59
|
}: HeadingProps) {
|
|
71
60
|
const { theme } = useZoraTheme();
|
|
72
61
|
const { breakpoint } = useResponsiveRuntime();
|
|
62
|
+
const themeRecipe = resolveHeadingThemeRecipe(useZoraThemeRecipe('Heading'));
|
|
73
63
|
const content = resolveHeadingContent({ children, text, i18nKey });
|
|
74
|
-
const resolvedSize =
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
|
|
64
|
+
const resolvedSize =
|
|
65
|
+
resolveResponsive(size ?? themeRecipe.size, breakpoint) ?? resolveHeadingSizeFromLevel(level);
|
|
66
|
+
const resolvedColor = resolveResponsive(color ?? themeRecipe.color, breakpoint);
|
|
67
|
+
const resolvedEmphasis =
|
|
68
|
+
resolveResponsive(emphasis ?? themeRecipe.emphasis, breakpoint) ?? 'default';
|
|
69
|
+
const resolvedAlign = resolveResponsive(align ?? themeRecipe.align, breakpoint);
|
|
70
|
+
const resolvedWeight = resolveResponsive(weight ?? themeRecipe.weight, breakpoint);
|
|
79
71
|
|
|
80
|
-
if (content === null
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
72
|
+
if (content === null) return null;
|
|
83
73
|
|
|
84
74
|
return (
|
|
85
75
|
<ReactNativeText
|
|
@@ -95,7 +85,7 @@ function HeadingInner({
|
|
|
95
85
|
headingLayoutStyle,
|
|
96
86
|
resolveHeadingRecipe(theme, {
|
|
97
87
|
align: resolvedAlign,
|
|
98
|
-
italic,
|
|
88
|
+
italic: italic ?? themeRecipe.italic ?? false,
|
|
99
89
|
level,
|
|
100
90
|
size: resolvedSize,
|
|
101
91
|
color: resolvedColor,
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import { ZORA_COLORS, ZORA_EMPHASES } from '../../internal/colorModel';
|
|
2
2
|
import type { ZoraComponentMeta } from '../../metadata';
|
|
3
3
|
|
|
4
|
+
const themeAuthoring = {
|
|
5
|
+
authority: 'theme',
|
|
6
|
+
scope: 'component',
|
|
7
|
+
allowInstanceOverride: true,
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
4
10
|
export const headingMeta = {
|
|
5
11
|
name: 'Heading',
|
|
6
12
|
category: 'component',
|
|
7
13
|
directManifestNode: true,
|
|
8
14
|
allowedChildren: [],
|
|
9
|
-
blueprint: {
|
|
10
|
-
|
|
11
|
-
defaultProps: {
|
|
12
|
-
text: 'Heading',
|
|
13
|
-
level: 2,
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
i18n: {
|
|
17
|
-
fields: [{ keyProp: 'i18nKey', defaultTextProp: 'text' }],
|
|
18
|
-
},
|
|
15
|
+
blueprint: { label: 'Heading', defaultProps: { text: 'Heading', level: 2 } },
|
|
16
|
+
i18n: { fields: [{ keyProp: 'i18nKey', defaultTextProp: 'text' }] },
|
|
19
17
|
props: {
|
|
20
18
|
text: {
|
|
21
19
|
type: 'string',
|
|
@@ -43,43 +41,37 @@ export const headingMeta = {
|
|
|
43
41
|
category: 'Typography',
|
|
44
42
|
label: 'Size',
|
|
45
43
|
enum: ['display', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
|
|
46
|
-
authoring:
|
|
44
|
+
authoring: themeAuthoring,
|
|
47
45
|
},
|
|
48
46
|
color: {
|
|
49
47
|
type: 'enum',
|
|
50
48
|
category: 'Style',
|
|
51
49
|
label: 'Color',
|
|
52
50
|
enum: ZORA_COLORS,
|
|
53
|
-
authoring:
|
|
51
|
+
authoring: themeAuthoring,
|
|
54
52
|
},
|
|
55
53
|
emphasis: {
|
|
56
54
|
type: 'enum',
|
|
57
55
|
category: 'Style',
|
|
58
56
|
label: 'Emphasis',
|
|
59
57
|
enum: ZORA_EMPHASES,
|
|
60
|
-
authoring:
|
|
58
|
+
authoring: themeAuthoring,
|
|
61
59
|
},
|
|
62
60
|
align: {
|
|
63
61
|
type: 'enum',
|
|
64
62
|
category: 'Layout',
|
|
65
63
|
label: 'Align',
|
|
66
64
|
enum: ['auto', 'left', 'right', 'center', 'justify'],
|
|
67
|
-
authoring:
|
|
65
|
+
authoring: themeAuthoring,
|
|
68
66
|
},
|
|
69
67
|
weight: {
|
|
70
68
|
type: 'enum',
|
|
71
69
|
category: 'Typography',
|
|
72
70
|
label: 'Weight',
|
|
73
71
|
enum: ['regular', 'medium', 'semiBold', 'bold'],
|
|
74
|
-
authoring:
|
|
75
|
-
},
|
|
76
|
-
italic: {
|
|
77
|
-
type: 'boolean',
|
|
78
|
-
category: 'Typography',
|
|
79
|
-
label: 'Italic',
|
|
80
|
-
default: false,
|
|
81
|
-
authoring: { authority: 'theme', scope: 'component' },
|
|
72
|
+
authoring: themeAuthoring,
|
|
82
73
|
},
|
|
74
|
+
italic: { type: 'boolean', category: 'Typography', label: 'Italic', authoring: themeAuthoring },
|
|
83
75
|
numberOfLines: {
|
|
84
76
|
type: 'number',
|
|
85
77
|
category: 'Layout',
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ThemeRecipeOverrideValue } from '@ankhorage/contracts';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
HeadingAlign,
|
|
5
|
+
HeadingColor,
|
|
6
|
+
HeadingEmphasis,
|
|
7
|
+
HeadingSize,
|
|
8
|
+
HeadingWeight,
|
|
9
|
+
} from './types';
|
|
10
|
+
|
|
11
|
+
export function resolveHeadingThemeRecipe(
|
|
12
|
+
fields: Readonly<Record<string, ThemeRecipeOverrideValue>>,
|
|
13
|
+
) {
|
|
14
|
+
return {
|
|
15
|
+
size: readSize(fields.size),
|
|
16
|
+
color: readColor(fields.color),
|
|
17
|
+
emphasis: readEmphasis(fields.emphasis),
|
|
18
|
+
align: readAlign(fields.align),
|
|
19
|
+
weight: readWeight(fields.weight),
|
|
20
|
+
italic: typeof fields.italic === 'boolean' ? fields.italic : undefined,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readSize(value: ThemeRecipeOverrideValue | undefined): HeadingSize | undefined {
|
|
25
|
+
if (value === 'display' || value === 'h1' || value === 'h2' || value === 'h3') return value;
|
|
26
|
+
if (value === 'h4' || value === 'h5' || value === 'h6') return value;
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function readColor(value: ThemeRecipeOverrideValue | undefined): HeadingColor | undefined {
|
|
31
|
+
if (typeof value !== 'string') return undefined;
|
|
32
|
+
if (value === 'primary' || value === 'secondary' || value === 'tertiary') return value;
|
|
33
|
+
if (value === 'quaternary' || value === 'neutral' || value === 'danger') return value;
|
|
34
|
+
if (value === 'success' || value === 'warning' || value === 'error' || value === 'info')
|
|
35
|
+
return value;
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function readEmphasis(value: ThemeRecipeOverrideValue | undefined): HeadingEmphasis | undefined {
|
|
40
|
+
if (value === 'default' || value === 'muted' || value === 'subtle' || value === 'inverse')
|
|
41
|
+
return value;
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function readAlign(value: ThemeRecipeOverrideValue | undefined): HeadingAlign | undefined {
|
|
46
|
+
if (value === 'auto' || value === 'left' || value === 'right') return value;
|
|
47
|
+
if (value === 'center' || value === 'justify') return value;
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function readWeight(value: ThemeRecipeOverrideValue | undefined): HeadingWeight | undefined {
|
|
52
|
+
if (value === 'regular' || value === 'medium' || value === 'semiBold' || value === 'bold')
|
|
53
|
+
return value;
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ZORA_COLORS, ZORA_EMPHASES } from '../../internal/colorModel';
|
|
2
|
+
import type { ZoraThemeRecipeMeta } from '../../metadata/themeRecipeTypes';
|
|
3
|
+
|
|
4
|
+
export const headingThemeRecipeMeta = {
|
|
5
|
+
name: 'Heading',
|
|
6
|
+
kind: 'component',
|
|
7
|
+
description: 'Maps Heading presentation defaults without replacing semantic heading levels.',
|
|
8
|
+
fields: {
|
|
9
|
+
size: {
|
|
10
|
+
type: 'choice',
|
|
11
|
+
label: 'Size',
|
|
12
|
+
options: ['display', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
|
|
13
|
+
},
|
|
14
|
+
color: { type: 'choice', label: 'Color', options: ZORA_COLORS },
|
|
15
|
+
emphasis: {
|
|
16
|
+
type: 'choice',
|
|
17
|
+
label: 'Emphasis',
|
|
18
|
+
options: ZORA_EMPHASES,
|
|
19
|
+
default: 'default',
|
|
20
|
+
},
|
|
21
|
+
align: {
|
|
22
|
+
type: 'choice',
|
|
23
|
+
label: 'Align',
|
|
24
|
+
options: ['auto', 'left', 'right', 'center', 'justify'],
|
|
25
|
+
},
|
|
26
|
+
weight: {
|
|
27
|
+
type: 'choice',
|
|
28
|
+
label: 'Weight',
|
|
29
|
+
options: ['regular', 'medium', 'semiBold', 'bold'],
|
|
30
|
+
},
|
|
31
|
+
italic: { type: 'boolean', label: 'Italic', default: false },
|
|
32
|
+
},
|
|
33
|
+
} as const satisfies ZoraThemeRecipeMeta;
|
|
@@ -3,8 +3,10 @@ import React from 'react';
|
|
|
3
3
|
import { Platform, Text as ReactNativeText, type TextStyle } from 'react-native';
|
|
4
4
|
|
|
5
5
|
import { useZoraTheme } from '../../theme/useZoraTheme';
|
|
6
|
+
import { useZoraThemeRecipe } from '../../theme/useZoraThemeRecipe';
|
|
6
7
|
import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
|
|
7
8
|
import { resolveTextStyle } from './resolveTextRecipe';
|
|
9
|
+
import { resolveTextThemeRecipe } from './resolveTextThemeRecipe';
|
|
8
10
|
import type { TextProps } from './types';
|
|
9
11
|
|
|
10
12
|
const textLayoutStyle = {
|
|
@@ -29,18 +31,9 @@ function resolveTextContent({
|
|
|
29
31
|
text: TextProps['text'];
|
|
30
32
|
i18nKey: TextProps['i18nKey'];
|
|
31
33
|
}): React.ReactNode {
|
|
32
|
-
if (children !== undefined)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (text !== undefined) {
|
|
37
|
-
return text;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (!i18nKey) {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
|
|
34
|
+
if (children !== undefined) return children;
|
|
35
|
+
if (text !== undefined) return text;
|
|
36
|
+
if (i18nKey === undefined || i18nKey === '') return null;
|
|
44
37
|
return i18nKey;
|
|
45
38
|
}
|
|
46
39
|
|
|
@@ -50,12 +43,12 @@ function TextInner({
|
|
|
50
43
|
children,
|
|
51
44
|
text,
|
|
52
45
|
i18nKey,
|
|
53
|
-
variant
|
|
46
|
+
variant,
|
|
54
47
|
color,
|
|
55
|
-
emphasis
|
|
48
|
+
emphasis,
|
|
56
49
|
align,
|
|
57
50
|
weight,
|
|
58
|
-
italic
|
|
51
|
+
italic,
|
|
59
52
|
numberOfLines,
|
|
60
53
|
ellipsizeMode,
|
|
61
54
|
selectable,
|
|
@@ -69,22 +62,21 @@ function TextInner({
|
|
|
69
62
|
}: TextProps) {
|
|
70
63
|
const { theme } = useZoraTheme();
|
|
71
64
|
const { breakpoint } = useResponsiveRuntime();
|
|
65
|
+
const themeRecipe = resolveTextThemeRecipe(useZoraThemeRecipe('Text'));
|
|
72
66
|
const content = resolveTextContent({ children, text, i18nKey });
|
|
73
|
-
const resolvedVariant = resolveResponsive(variant, breakpoint) ?? 'body';
|
|
67
|
+
const resolvedVariant = resolveResponsive(variant ?? themeRecipe.variant, breakpoint) ?? 'body';
|
|
74
68
|
const resolvedStyle = resolveTextStyle({
|
|
75
69
|
theme,
|
|
76
70
|
breakpoint,
|
|
77
71
|
variant: resolvedVariant,
|
|
78
|
-
color,
|
|
79
|
-
emphasis,
|
|
80
|
-
align,
|
|
81
|
-
weight,
|
|
82
|
-
italic,
|
|
72
|
+
color: color ?? themeRecipe.color,
|
|
73
|
+
emphasis: emphasis ?? themeRecipe.emphasis,
|
|
74
|
+
align: align ?? themeRecipe.align,
|
|
75
|
+
weight: weight ?? themeRecipe.weight,
|
|
76
|
+
italic: italic ?? themeRecipe.italic ?? false,
|
|
83
77
|
});
|
|
84
78
|
|
|
85
|
-
if (content === null || content === undefined)
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
79
|
+
if (content === null || content === undefined) return null;
|
|
88
80
|
|
|
89
81
|
return (
|
|
90
82
|
<ReactNativeText
|
|
@@ -109,7 +101,6 @@ function TextInner({
|
|
|
109
101
|
* `Text` owns normal body, caption, label, code, and supporting-copy variants so
|
|
110
102
|
* consumers do not need to import lower-level Surface typography directly.
|
|
111
103
|
*
|
|
112
|
-
|
|
113
104
|
* @example Muted supporting copy
|
|
114
105
|
* ```tsx
|
|
115
106
|
* <Text variant="bodySmall" emphasis="muted">Updated just now</Text>
|
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
import { ZORA_COLORS, ZORA_EMPHASES } from '../../internal/colorModel';
|
|
2
2
|
import type { ZoraComponentMeta } from '../../metadata';
|
|
3
3
|
|
|
4
|
+
const themeAuthoring = {
|
|
5
|
+
authority: 'theme',
|
|
6
|
+
scope: 'component',
|
|
7
|
+
allowInstanceOverride: true,
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
4
10
|
export const textMeta = {
|
|
5
11
|
name: 'Text',
|
|
6
12
|
category: 'component',
|
|
7
13
|
directManifestNode: true,
|
|
8
14
|
allowedChildren: [],
|
|
9
|
-
blueprint: {
|
|
10
|
-
|
|
11
|
-
defaultProps: {
|
|
12
|
-
text: 'Text',
|
|
13
|
-
emphasis: 'default',
|
|
14
|
-
variant: 'body',
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
i18n: {
|
|
18
|
-
fields: [{ keyProp: 'i18nKey', defaultTextProp: 'text' }],
|
|
19
|
-
},
|
|
15
|
+
blueprint: { label: 'Text', defaultProps: { text: 'Text' } },
|
|
16
|
+
i18n: { fields: [{ keyProp: 'i18nKey', defaultTextProp: 'text' }] },
|
|
20
17
|
props: {
|
|
21
18
|
text: {
|
|
22
19
|
type: 'string',
|
|
@@ -36,45 +33,37 @@ export const textMeta = {
|
|
|
36
33
|
category: 'Typography',
|
|
37
34
|
label: 'Variant',
|
|
38
35
|
enum: ['body', 'lead', 'bodySmall', 'caption', 'label', 'eyebrow', 'code'],
|
|
39
|
-
|
|
40
|
-
authoring: { authority: 'theme', scope: 'component' },
|
|
36
|
+
authoring: themeAuthoring,
|
|
41
37
|
},
|
|
42
38
|
color: {
|
|
43
39
|
type: 'enum',
|
|
44
40
|
category: 'Style',
|
|
45
41
|
label: 'Color',
|
|
46
42
|
enum: ZORA_COLORS,
|
|
47
|
-
authoring:
|
|
43
|
+
authoring: themeAuthoring,
|
|
48
44
|
},
|
|
49
45
|
emphasis: {
|
|
50
46
|
type: 'enum',
|
|
51
47
|
category: 'Style',
|
|
52
48
|
label: 'Emphasis',
|
|
53
49
|
enum: ZORA_EMPHASES,
|
|
54
|
-
|
|
55
|
-
authoring: { authority: 'theme', scope: 'component' },
|
|
50
|
+
authoring: themeAuthoring,
|
|
56
51
|
},
|
|
57
52
|
align: {
|
|
58
53
|
type: 'enum',
|
|
59
54
|
category: 'Layout',
|
|
60
55
|
label: 'Align',
|
|
61
56
|
enum: ['auto', 'left', 'right', 'center', 'justify'],
|
|
62
|
-
authoring:
|
|
57
|
+
authoring: themeAuthoring,
|
|
63
58
|
},
|
|
64
59
|
weight: {
|
|
65
60
|
type: 'enum',
|
|
66
61
|
category: 'Typography',
|
|
67
62
|
label: 'Weight',
|
|
68
63
|
enum: ['regular', 'medium', 'semiBold', 'bold'],
|
|
69
|
-
authoring:
|
|
70
|
-
},
|
|
71
|
-
italic: {
|
|
72
|
-
type: 'boolean',
|
|
73
|
-
category: 'Typography',
|
|
74
|
-
label: 'Italic',
|
|
75
|
-
default: false,
|
|
76
|
-
authoring: { authority: 'theme', scope: 'component' },
|
|
64
|
+
authoring: themeAuthoring,
|
|
77
65
|
},
|
|
66
|
+
italic: { type: 'boolean', category: 'Typography', label: 'Italic', authoring: themeAuthoring },
|
|
78
67
|
numberOfLines: {
|
|
79
68
|
type: 'number',
|
|
80
69
|
category: 'Layout',
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ThemeRecipeOverrideValue } from '@ankhorage/contracts';
|
|
2
|
+
|
|
3
|
+
import type { TextAlign, TextColor, TextEmphasis, TextVariant, TextWeight } from './types';
|
|
4
|
+
|
|
5
|
+
export function resolveTextThemeRecipe(fields: Readonly<Record<string, ThemeRecipeOverrideValue>>) {
|
|
6
|
+
return {
|
|
7
|
+
variant: readVariant(fields.variant),
|
|
8
|
+
color: readColor(fields.color),
|
|
9
|
+
emphasis: readEmphasis(fields.emphasis),
|
|
10
|
+
align: readAlign(fields.align),
|
|
11
|
+
weight: readWeight(fields.weight),
|
|
12
|
+
italic: typeof fields.italic === 'boolean' ? fields.italic : undefined,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function readVariant(value: ThemeRecipeOverrideValue | undefined): TextVariant | undefined {
|
|
17
|
+
if (value === 'body' || value === 'lead' || value === 'bodySmall' || value === 'caption')
|
|
18
|
+
return value;
|
|
19
|
+
if (value === 'label' || value === 'eyebrow' || value === 'code') return value;
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function readColor(value: ThemeRecipeOverrideValue | undefined): TextColor | undefined {
|
|
24
|
+
if (typeof value !== 'string') return undefined;
|
|
25
|
+
if (value === 'primary' || value === 'secondary' || value === 'tertiary') return value;
|
|
26
|
+
if (value === 'quaternary' || value === 'neutral' || value === 'danger') return value;
|
|
27
|
+
if (value === 'success' || value === 'warning' || value === 'error' || value === 'info')
|
|
28
|
+
return value;
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function readEmphasis(value: ThemeRecipeOverrideValue | undefined): TextEmphasis | undefined {
|
|
33
|
+
if (value === 'default' || value === 'muted' || value === 'subtle' || value === 'inverse')
|
|
34
|
+
return value;
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function readAlign(value: ThemeRecipeOverrideValue | undefined): TextAlign | undefined {
|
|
39
|
+
if (value === 'auto' || value === 'left' || value === 'right') return value;
|
|
40
|
+
if (value === 'center' || value === 'justify') return value;
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function readWeight(value: ThemeRecipeOverrideValue | undefined): TextWeight | undefined {
|
|
45
|
+
if (value === 'regular' || value === 'medium' || value === 'semiBold' || value === 'bold')
|
|
46
|
+
return value;
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
@@ -1,33 +1,34 @@
|
|
|
1
|
+
import { ZORA_COLORS, ZORA_EMPHASES } from '../../internal/colorModel';
|
|
1
2
|
import type { ZoraThemeRecipeMeta } from '../../metadata/themeRecipeTypes';
|
|
2
3
|
|
|
3
4
|
export const textThemeRecipeMeta = {
|
|
4
5
|
name: 'Text',
|
|
5
6
|
kind: 'component',
|
|
6
|
-
description: 'Maps
|
|
7
|
+
description: 'Maps semantic Text presentation defaults into runtime props.',
|
|
7
8
|
fields: {
|
|
8
9
|
variant: {
|
|
9
|
-
type: '
|
|
10
|
-
tokenFamily: 'typography',
|
|
10
|
+
type: 'choice',
|
|
11
11
|
label: 'Typography variant',
|
|
12
|
+
options: ['body', 'lead', 'bodySmall', 'caption', 'label', 'eyebrow', 'code'],
|
|
12
13
|
default: 'body',
|
|
13
14
|
},
|
|
14
|
-
color: {
|
|
15
|
-
type: 'token',
|
|
16
|
-
tokenFamily: 'colors',
|
|
17
|
-
label: 'Color',
|
|
18
|
-
default: 'text',
|
|
19
|
-
},
|
|
15
|
+
color: { type: 'choice', label: 'Color', options: ZORA_COLORS },
|
|
20
16
|
emphasis: {
|
|
21
17
|
type: 'choice',
|
|
22
18
|
label: 'Emphasis',
|
|
23
|
-
options:
|
|
19
|
+
options: ZORA_EMPHASES,
|
|
24
20
|
default: 'default',
|
|
25
21
|
},
|
|
22
|
+
align: {
|
|
23
|
+
type: 'choice',
|
|
24
|
+
label: 'Align',
|
|
25
|
+
options: ['auto', 'left', 'right', 'center', 'justify'],
|
|
26
|
+
},
|
|
26
27
|
weight: {
|
|
27
28
|
type: 'choice',
|
|
28
29
|
label: 'Weight',
|
|
29
30
|
options: ['regular', 'medium', 'semiBold', 'bold'],
|
|
30
|
-
default: 'regular',
|
|
31
31
|
},
|
|
32
|
+
italic: { type: 'boolean', label: 'Italic', default: false },
|
|
32
33
|
},
|
|
33
34
|
} as const satisfies ZoraThemeRecipeMeta;
|