@ankhorage/zora 1.0.5 → 1.0.7
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 +284 -0
- package/dist/components/media-card/MediaCard.d.ts +4 -0
- package/dist/components/media-card/MediaCard.d.ts.map +1 -0
- package/dist/components/media-card/MediaCard.js +64 -0
- package/dist/components/media-card/MediaCard.js.map +1 -0
- package/dist/components/media-card/index.d.ts +3 -0
- package/dist/components/media-card/index.d.ts.map +1 -0
- package/dist/components/media-card/index.js +2 -0
- package/dist/components/media-card/index.js.map +1 -0
- package/dist/components/media-card/types.d.ts +36 -0
- package/dist/components/media-card/types.d.ts.map +1 -0
- package/dist/components/media-card/types.js +2 -0
- package/dist/components/media-card/types.js.map +1 -0
- package/dist/components/metric-card/MetricCard.d.ts +4 -0
- package/dist/components/metric-card/MetricCard.d.ts.map +1 -0
- package/dist/components/metric-card/MetricCard.js +43 -0
- package/dist/components/metric-card/MetricCard.js.map +1 -0
- package/dist/components/metric-card/index.d.ts +3 -0
- package/dist/components/metric-card/index.d.ts.map +1 -0
- package/dist/components/metric-card/index.js +2 -0
- package/dist/components/metric-card/index.js.map +1 -0
- package/dist/components/metric-card/types.d.ts +17 -0
- package/dist/components/metric-card/types.d.ts.map +1 -0
- package/dist/components/metric-card/types.js +2 -0
- package/dist/components/metric-card/types.js.map +1 -0
- package/dist/components/progress/Progress.d.ts +4 -0
- package/dist/components/progress/Progress.d.ts.map +1 -0
- package/dist/components/progress/Progress.js +28 -0
- package/dist/components/progress/Progress.js.map +1 -0
- package/dist/components/progress/index.d.ts +3 -0
- package/dist/components/progress/index.d.ts.map +1 -0
- package/dist/components/progress/index.js +2 -0
- package/dist/components/progress/index.js.map +1 -0
- package/dist/components/progress/resolveProgressFraction.d.ts +5 -0
- package/dist/components/progress/resolveProgressFraction.d.ts.map +1 -0
- package/dist/components/progress/resolveProgressFraction.js +14 -0
- package/dist/components/progress/resolveProgressFraction.js.map +1 -0
- package/dist/components/progress/types.d.ts +11 -0
- package/dist/components/progress/types.d.ts.map +1 -0
- package/dist/components/progress/types.js +16 -0
- package/dist/components/progress/types.js.map +1 -0
- package/dist/components/rating/Rating.d.ts +4 -0
- package/dist/components/rating/Rating.d.ts.map +1 -0
- package/dist/components/rating/Rating.js +23 -0
- package/dist/components/rating/Rating.js.map +1 -0
- package/dist/components/rating/index.d.ts +3 -0
- package/dist/components/rating/index.d.ts.map +1 -0
- package/dist/components/rating/index.js +2 -0
- package/dist/components/rating/index.js.map +1 -0
- package/dist/components/rating/resolveRatingSegments.d.ts +7 -0
- package/dist/components/rating/resolveRatingSegments.d.ts.map +1 -0
- package/dist/components/rating/resolveRatingSegments.js +22 -0
- package/dist/components/rating/resolveRatingSegments.js.map +1 -0
- package/dist/components/rating/types.d.ts +11 -0
- package/dist/components/rating/types.d.ts.map +1 -0
- package/dist/components/rating/types.js +16 -0
- package/dist/components/rating/types.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/patterns/list/List.d.ts +4 -0
- package/dist/patterns/list/List.d.ts.map +1 -0
- package/dist/patterns/list/List.js +35 -0
- package/dist/patterns/list/List.js.map +1 -0
- package/dist/patterns/list/ListRow.d.ts +4 -0
- package/dist/patterns/list/ListRow.d.ts.map +1 -0
- package/dist/patterns/list/ListRow.js +108 -0
- package/dist/patterns/list/ListRow.js.map +1 -0
- package/dist/patterns/list/ListSection.d.ts +4 -0
- package/dist/patterns/list/ListSection.d.ts.map +1 -0
- package/dist/patterns/list/ListSection.js +14 -0
- package/dist/patterns/list/ListSection.js.map +1 -0
- package/dist/patterns/list/index.d.ts +5 -0
- package/dist/patterns/list/index.d.ts.map +1 -0
- package/dist/patterns/list/index.js +4 -0
- package/dist/patterns/list/index.js.map +1 -0
- package/dist/patterns/list/resolveListSeparator.d.ts +5 -0
- package/dist/patterns/list/resolveListSeparator.d.ts.map +1 -0
- package/dist/patterns/list/resolveListSeparator.js +6 -0
- package/dist/patterns/list/resolveListSeparator.js.map +1 -0
- package/dist/patterns/list/types.d.ts +55 -0
- package/dist/patterns/list/types.d.ts.map +1 -0
- package/dist/patterns/list/types.js +2 -0
- package/dist/patterns/list/types.js.map +1 -0
- package/dist/patterns/timeline/Timeline.d.ts +4 -0
- package/dist/patterns/timeline/Timeline.d.ts.map +1 -0
- package/dist/patterns/timeline/Timeline.js +59 -0
- package/dist/patterns/timeline/Timeline.js.map +1 -0
- package/dist/patterns/timeline/index.d.ts +3 -0
- package/dist/patterns/timeline/index.d.ts.map +1 -0
- package/dist/patterns/timeline/index.js +2 -0
- package/dist/patterns/timeline/index.js.map +1 -0
- package/dist/patterns/timeline/types.d.ts +18 -0
- package/dist/patterns/timeline/types.d.ts.map +1 -0
- package/dist/patterns/timeline/types.js +2 -0
- package/dist/patterns/timeline/types.js.map +1 -0
- package/package.json +1 -1
- package/src/components/media-card/MediaCard.tsx +120 -0
- package/src/components/media-card/index.ts +2 -0
- package/src/components/media-card/types.ts +44 -0
- package/src/components/metric-card/MetricCard.tsx +84 -0
- package/src/components/metric-card/index.ts +2 -0
- package/src/components/metric-card/types.ts +18 -0
- package/src/components/progress/Progress.tsx +50 -0
- package/src/components/progress/index.ts +2 -0
- package/src/components/progress/resolveProgressFraction.test.ts +23 -0
- package/src/components/progress/resolveProgressFraction.ts +17 -0
- package/src/components/progress/types.ts +27 -0
- package/src/components/rating/Rating.tsx +38 -0
- package/src/components/rating/index.ts +2 -0
- package/src/components/rating/resolveRatingSegments.test.ts +60 -0
- package/src/components/rating/resolveRatingSegments.ts +34 -0
- package/src/components/rating/types.ts +27 -0
- package/src/index.ts +19 -0
- package/src/patterns/list/List.tsx +72 -0
- package/src/patterns/list/ListRow.tsx +193 -0
- package/src/patterns/list/ListSection.tsx +36 -0
- package/src/patterns/list/index.ts +11 -0
- package/src/patterns/list/resolveListSeparator.test.ts +18 -0
- package/src/patterns/list/resolveListSeparator.ts +8 -0
- package/src/patterns/list/types.ts +67 -0
- package/src/patterns/timeline/Timeline.tsx +104 -0
- package/src/patterns/timeline/index.ts +2 -0
- package/src/patterns/timeline/types.ts +20 -0
- package/src/showcaseCoverage.test.ts +8 -0
- package/src/theme/themeScopeStructure.test.ts +14 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Stack } from '../../foundation';
|
|
3
|
+
import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
|
|
4
|
+
import { SectionHeader } from '../section-header';
|
|
5
|
+
import { List } from './List';
|
|
6
|
+
function ListSectionInner({ themeId: _themeId, mode: _mode, testID, title, description, eyebrow, actions, ...props }) {
|
|
7
|
+
const hasHeader = title !== undefined;
|
|
8
|
+
return (<Stack gap="s" testID={testID}>
|
|
9
|
+
{hasHeader ? (<SectionHeader actions={actions} description={description} eyebrow={eyebrow} title={title}/>) : null}
|
|
10
|
+
<List {...props}/>
|
|
11
|
+
</Stack>);
|
|
12
|
+
}
|
|
13
|
+
export const ListSection = withZoraThemeScope(ListSectionInner);
|
|
14
|
+
//# sourceMappingURL=ListSection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ListSection.js","sourceRoot":"","sources":["../../../src/patterns/list/ListSection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAG9B,SAAS,gBAAgB,CAAC,EACxB,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,KAAK,EACX,MAAM,EACN,KAAK,EACL,WAAW,EACX,OAAO,EACP,OAAO,EACP,GAAG,KAAK,EACS;IACjB,MAAM,SAAS,GAAG,KAAK,KAAK,SAAS,CAAC;IAEtC,OAAO,CACL,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAC5B;MAAA,CAAC,SAAS,CAAC,CAAC,CAAC,CACX,CAAC,aAAa,CACZ,OAAO,CAAC,CAAC,OAAO,CAAC,CACjB,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,OAAO,CAAC,CAAC,OAAO,CAAC,CACjB,KAAK,CAAC,CAAC,KAAK,CAAC,EACb,CACH,CAAC,CAAC,CAAC,IAAI,CACR;MAAA,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,EAClB;IAAA,EAAE,KAAK,CAAC,CACT,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,kBAAkB,CAAC,gBAAgB,CAAC,CAAC","sourcesContent":["import React from 'react';\n\nimport { Stack } from '../../foundation';\nimport { withZoraThemeScope } from '../../theme/withZoraThemeScope';\nimport { SectionHeader } from '../section-header';\nimport { List } from './List';\nimport type { ListSectionProps } from './types';\n\nfunction ListSectionInner({\n themeId: _themeId,\n mode: _mode,\n testID,\n title,\n description,\n eyebrow,\n actions,\n ...props\n}: ListSectionProps) {\n const hasHeader = title !== undefined;\n\n return (\n <Stack gap=\"s\" testID={testID}>\n {hasHeader ? (\n <SectionHeader\n actions={actions}\n description={description}\n eyebrow={eyebrow}\n title={title}\n />\n ) : null}\n <List {...props} />\n </Stack>\n );\n}\n\nexport const ListSection = withZoraThemeScope(ListSectionInner);\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { List } from './List';
|
|
2
|
+
export { ListRow } from './ListRow';
|
|
3
|
+
export { ListSection } from './ListSection';
|
|
4
|
+
export type { ListChildrenProps, ListItemsProps, ListProps, ListRowProps, ListRowVariant, ListSectionProps, } from './types';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/patterns/list/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,YAAY,EACZ,cAAc,EACd,gBAAgB,GACjB,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/patterns/list/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC","sourcesContent":["export { List } from './List';\nexport { ListRow } from './ListRow';\nexport { ListSection } from './ListSection';\nexport type {\n ListChildrenProps,\n ListItemsProps,\n ListProps,\n ListRowProps,\n ListRowVariant,\n ListSectionProps,\n} from './types';\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ListRowVariant } from './types';
|
|
2
|
+
type ListSeparatorKind = 'none' | 'divider' | 'spacer';
|
|
3
|
+
export declare function resolveListSeparator(variant: ListRowVariant, index: number): ListSeparatorKind;
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=resolveListSeparator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveListSeparator.d.ts","sourceRoot":"","sources":["../../../src/patterns/list/resolveListSeparator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,KAAK,iBAAiB,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEvD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAG9F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveListSeparator.js","sourceRoot":"","sources":["../../../src/patterns/list/resolveListSeparator.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,oBAAoB,CAAC,OAAuB,EAAE,KAAa;IACzE,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAC/B,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;AACtD,CAAC","sourcesContent":["import type { ListRowVariant } from './types';\n\ntype ListSeparatorKind = 'none' | 'divider' | 'spacer';\n\nexport function resolveListSeparator(variant: ListRowVariant, index: number): ListSeparatorKind {\n if (index === 0) return 'none';\n return variant === 'divider' ? 'divider' : 'spacer';\n}\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
|
|
3
|
+
export type ListRowVariant = 'divider' | 'card';
|
|
4
|
+
interface ListRowBaseProps extends ZoraBaseProps {
|
|
5
|
+
title: React.ReactNode;
|
|
6
|
+
description?: React.ReactNode;
|
|
7
|
+
meta?: React.ReactNode;
|
|
8
|
+
leading?: React.ReactNode;
|
|
9
|
+
trailing?: React.ReactNode;
|
|
10
|
+
selected?: boolean;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
compact?: boolean;
|
|
13
|
+
variant?: ListRowVariant;
|
|
14
|
+
}
|
|
15
|
+
interface ListRowPressableProps {
|
|
16
|
+
onPress: () => void;
|
|
17
|
+
action?: never;
|
|
18
|
+
}
|
|
19
|
+
interface ListRowActionProps {
|
|
20
|
+
action: React.ReactNode;
|
|
21
|
+
onPress?: never;
|
|
22
|
+
}
|
|
23
|
+
interface ListRowStaticProps {
|
|
24
|
+
action?: never;
|
|
25
|
+
onPress?: never;
|
|
26
|
+
}
|
|
27
|
+
export type ListRowProps = ListRowBaseProps & (ListRowPressableProps | ListRowActionProps | ListRowStaticProps);
|
|
28
|
+
export interface ListItemsProps extends ZoraBaseProps {
|
|
29
|
+
items: readonly ListRowProps[];
|
|
30
|
+
rowVariant?: ListRowVariant;
|
|
31
|
+
compact?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface ListChildrenProps extends ZoraBaseProps {
|
|
34
|
+
children: React.ReactNode;
|
|
35
|
+
}
|
|
36
|
+
export type ListProps = ListItemsProps | ListChildrenProps;
|
|
37
|
+
export interface ListSectionItemsProps extends ZoraBaseProps {
|
|
38
|
+
title?: React.ReactNode;
|
|
39
|
+
description?: React.ReactNode;
|
|
40
|
+
eyebrow?: React.ReactNode;
|
|
41
|
+
actions?: React.ReactNode;
|
|
42
|
+
items: readonly ListRowProps[];
|
|
43
|
+
rowVariant?: ListRowVariant;
|
|
44
|
+
compact?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface ListSectionChildrenProps extends ZoraBaseProps {
|
|
47
|
+
title?: React.ReactNode;
|
|
48
|
+
description?: React.ReactNode;
|
|
49
|
+
eyebrow?: React.ReactNode;
|
|
50
|
+
actions?: React.ReactNode;
|
|
51
|
+
children: React.ReactNode;
|
|
52
|
+
}
|
|
53
|
+
export type ListSectionProps = ListSectionItemsProps | ListSectionChildrenProps;
|
|
54
|
+
export {};
|
|
55
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/patterns/list/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,MAAM,CAAC;AAEhD,UAAU,gBAAiB,SAAQ,aAAa;IAC9C,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED,UAAU,kBAAkB;IAC1B,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB;AAED,UAAU,kBAAkB;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB;AAED,MAAM,MAAM,YAAY,GAAG,gBAAgB,GACzC,CAAC,qBAAqB,GAAG,kBAAkB,GAAG,kBAAkB,CAAC,CAAC;AAEpE,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,MAAM,SAAS,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAE3D,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC7D,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,GAAG,wBAAwB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/patterns/list/types.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nimport type { ZoraBaseProps } from '../../theme/ZoraBaseProps';\n\nexport type ListRowVariant = 'divider' | 'card';\n\ninterface ListRowBaseProps extends ZoraBaseProps {\n title: React.ReactNode;\n description?: React.ReactNode;\n meta?: React.ReactNode;\n leading?: React.ReactNode;\n trailing?: React.ReactNode;\n selected?: boolean;\n disabled?: boolean;\n compact?: boolean;\n variant?: ListRowVariant;\n}\n\ninterface ListRowPressableProps {\n onPress: () => void;\n action?: never;\n}\n\ninterface ListRowActionProps {\n action: React.ReactNode;\n onPress?: never;\n}\n\ninterface ListRowStaticProps {\n action?: never;\n onPress?: never;\n}\n\nexport type ListRowProps = ListRowBaseProps &\n (ListRowPressableProps | ListRowActionProps | ListRowStaticProps);\n\nexport interface ListItemsProps extends ZoraBaseProps {\n items: readonly ListRowProps[];\n rowVariant?: ListRowVariant;\n compact?: boolean;\n}\n\nexport interface ListChildrenProps extends ZoraBaseProps {\n children: React.ReactNode;\n}\n\nexport type ListProps = ListItemsProps | ListChildrenProps;\n\nexport interface ListSectionItemsProps extends ZoraBaseProps {\n title?: React.ReactNode;\n description?: React.ReactNode;\n eyebrow?: React.ReactNode;\n actions?: React.ReactNode;\n items: readonly ListRowProps[];\n rowVariant?: ListRowVariant;\n compact?: boolean;\n}\n\nexport interface ListSectionChildrenProps extends ZoraBaseProps {\n title?: React.ReactNode;\n description?: React.ReactNode;\n eyebrow?: React.ReactNode;\n actions?: React.ReactNode;\n children: React.ReactNode;\n}\n\nexport type ListSectionProps = ListSectionItemsProps | ListSectionChildrenProps;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Timeline.d.ts","sourceRoot":"","sources":["../../../src/patterns/timeline/Timeline.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,SAAS,CAAC;AA4F3D,eAAO,MAAM,QAAQ,qDAAoC,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Heading } from '../../components/heading';
|
|
3
|
+
import { Icon } from '../../components/icon';
|
|
4
|
+
import { Text } from '../../components/text';
|
|
5
|
+
import { Box, Inline, Stack } from '../../foundation';
|
|
6
|
+
import { resolveIconSize } from '../../internal/recipes';
|
|
7
|
+
import { useZoraTheme } from '../../theme/useZoraTheme';
|
|
8
|
+
import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
|
|
9
|
+
function resolveRoleSemantics(theme, tone) {
|
|
10
|
+
switch (tone) {
|
|
11
|
+
case 'primary':
|
|
12
|
+
return theme.semantics.action.primary;
|
|
13
|
+
case 'danger':
|
|
14
|
+
return theme.semantics.action.danger;
|
|
15
|
+
case 'success':
|
|
16
|
+
return theme.semantics.success;
|
|
17
|
+
case 'warning':
|
|
18
|
+
return theme.semantics.warning;
|
|
19
|
+
case 'neutral':
|
|
20
|
+
default:
|
|
21
|
+
return theme.semantics.action.neutral;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function TimelineInner({ themeId: _themeId, mode: _mode, testID, items, compact = false, }) {
|
|
25
|
+
const { theme } = useZoraTheme();
|
|
26
|
+
const gap = compact ? 'm' : 'l';
|
|
27
|
+
const renderItem = (item, index) => {
|
|
28
|
+
const status = item.status ?? 'neutral';
|
|
29
|
+
const role = resolveRoleSemantics(theme, status);
|
|
30
|
+
const showConnector = index < items.length - 1;
|
|
31
|
+
const iconSize = Math.max(12, resolveIconSize('s'));
|
|
32
|
+
return (<Inline key={item.id} align="flex-start" gap="m" testID={item.testID} wrap="nowrap">
|
|
33
|
+
<Stack align="center" flexShrink={0} gap="xs" style={{ width: 24 }}>
|
|
34
|
+
<Box bg={status === 'neutral' ? theme.semantics.neutral.surface : role.softBg} borderColor={status === 'neutral' ? theme.semantics.neutral.divider : role.base} borderWidth={1} height={20} radius="full" width={20} style={{ alignItems: 'center', justifyContent: 'center' }}>
|
|
35
|
+
{item.icon ? (<Icon color={status === 'neutral' ? theme.semantics.content.muted : role.base} name={item.icon.name} provider={item.icon.provider} size={iconSize}/>) : null}
|
|
36
|
+
</Box>
|
|
37
|
+
|
|
38
|
+
{showConnector ? (<Box bg={theme.semantics.neutral.divider} flex={1} radius="full" style={{ minHeight: 16, width: 2 }}/>) : null}
|
|
39
|
+
</Stack>
|
|
40
|
+
|
|
41
|
+
<Stack flex={1} gap="xs" testID={testID}>
|
|
42
|
+
<Inline align="flex-start" gap="s" justify="space-between" wrap="wrap">
|
|
43
|
+
<Heading level={compact ? 4 : 3}>{item.title}</Heading>
|
|
44
|
+
{item.meta ? (<Text tone="muted" variant="caption">
|
|
45
|
+
{item.meta}
|
|
46
|
+
</Text>) : null}
|
|
47
|
+
</Inline>
|
|
48
|
+
{item.description ? (<Text tone="muted" variant="bodySmall">
|
|
49
|
+
{item.description}
|
|
50
|
+
</Text>) : null}
|
|
51
|
+
</Stack>
|
|
52
|
+
</Inline>);
|
|
53
|
+
};
|
|
54
|
+
return (<Stack gap={gap} testID={testID}>
|
|
55
|
+
{items.map(renderItem)}
|
|
56
|
+
</Stack>);
|
|
57
|
+
}
|
|
58
|
+
export const Timeline = withZoraThemeScope(TimelineInner);
|
|
59
|
+
//# sourceMappingURL=Timeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Timeline.js","sourceRoot":"","sources":["../../../src/patterns/timeline/Timeline.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { RoleSemantics, SurfaceTheme } from '@ankhorage/surface';\nimport React from 'react';\n\nimport { Heading } from '../../components/heading';\nimport { Icon } from '../../components/icon';\nimport { Text } from '../../components/text';\nimport { Box, Inline, Stack } from '../../foundation';\nimport type { ZoraTone } from '../../internal/recipes';\nimport { resolveIconSize } from '../../internal/recipes';\nimport { useZoraTheme } from '../../theme/useZoraTheme';\nimport { withZoraThemeScope } from '../../theme/withZoraThemeScope';\nimport type { TimelineItem, TimelineProps } from './types';\n\nfunction resolveRoleSemantics(theme: SurfaceTheme, tone: ZoraTone): RoleSemantics {\n switch (tone) {\n case 'primary':\n return theme.semantics.action.primary;\n case 'danger':\n return theme.semantics.action.danger;\n case 'success':\n return theme.semantics.success;\n case 'warning':\n return theme.semantics.warning;\n case 'neutral':\n default:\n return theme.semantics.action.neutral;\n }\n}\n\nfunction TimelineInner({\n themeId: _themeId,\n mode: _mode,\n testID,\n items,\n compact = false,\n}: TimelineProps) {\n const { theme } = useZoraTheme();\n const gap = compact ? 'm' : 'l';\n\n const renderItem = (item: TimelineItem, index: number) => {\n const status = item.status ?? 'neutral';\n const role = resolveRoleSemantics(theme, status);\n const showConnector = index < items.length - 1;\n const iconSize = Math.max(12, resolveIconSize('s'));\n\n return (\n <Inline key={item.id} align=\"flex-start\" gap=\"m\" testID={item.testID} wrap=\"nowrap\">\n <Stack align=\"center\" flexShrink={0} gap=\"xs\" style={{ width: 24 }}>\n <Box\n bg={status === 'neutral' ? theme.semantics.neutral.surface : role.softBg}\n borderColor={status === 'neutral' ? theme.semantics.neutral.divider : role.base}\n borderWidth={1}\n height={20}\n radius=\"full\"\n width={20}\n style={{ alignItems: 'center', justifyContent: 'center' }}\n >\n {item.icon ? (\n <Icon\n color={status === 'neutral' ? theme.semantics.content.muted : role.base}\n name={item.icon.name}\n provider={item.icon.provider}\n size={iconSize}\n />\n ) : null}\n </Box>\n\n {showConnector ? (\n <Box\n bg={theme.semantics.neutral.divider}\n flex={1}\n radius=\"full\"\n style={{ minHeight: 16, width: 2 }}\n />\n ) : null}\n </Stack>\n\n <Stack flex={1} gap=\"xs\" testID={testID}>\n <Inline align=\"flex-start\" gap=\"s\" justify=\"space-between\" wrap=\"wrap\">\n <Heading level={compact ? 4 : 3}>{item.title}</Heading>\n {item.meta ? (\n <Text tone=\"muted\" variant=\"caption\">\n {item.meta}\n </Text>\n ) : null}\n </Inline>\n {item.description ? (\n <Text tone=\"muted\" variant=\"bodySmall\">\n {item.description}\n </Text>\n ) : null}\n </Stack>\n </Inline>\n );\n };\n\n return (\n <Stack gap={gap} testID={testID}>\n {items.map(renderItem)}\n </Stack>\n );\n}\n\nexport const Timeline = withZoraThemeScope(TimelineInner);\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/patterns/timeline/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/patterns/timeline/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export { Timeline } from './Timeline';\nexport type { TimelineItem, TimelineProps } from './types';\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ButtonIconSpec } from '@ankhorage/surface';
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
import type { ZoraTone } from '../../internal/recipes';
|
|
4
|
+
import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
|
|
5
|
+
export interface TimelineItem {
|
|
6
|
+
id: string;
|
|
7
|
+
title: React.ReactNode;
|
|
8
|
+
description?: React.ReactNode;
|
|
9
|
+
meta?: React.ReactNode;
|
|
10
|
+
status?: ZoraTone;
|
|
11
|
+
icon?: ButtonIconSpec;
|
|
12
|
+
testID?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface TimelineProps extends ZoraBaseProps {
|
|
15
|
+
items: readonly TimelineItem[];
|
|
16
|
+
compact?: boolean;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/patterns/timeline/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/patterns/timeline/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ButtonIconSpec } from '@ankhorage/surface';\nimport type React from 'react';\n\nimport type { ZoraTone } from '../../internal/recipes';\nimport type { ZoraBaseProps } from '../../theme/ZoraBaseProps';\n\nexport interface TimelineItem {\n id: string;\n title: React.ReactNode;\n description?: React.ReactNode;\n meta?: React.ReactNode;\n status?: ZoraTone;\n icon?: ButtonIconSpec;\n testID?: string;\n}\n\nexport interface TimelineProps extends ZoraBaseProps {\n items: readonly TimelineItem[];\n compact?: boolean;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/zora",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.7",
|
|
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": {
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Image } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { Box, Stack } from '../../foundation';
|
|
5
|
+
import { useZoraTheme } from '../../theme/useZoraTheme';
|
|
6
|
+
import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
|
|
7
|
+
import { Card } from '../card';
|
|
8
|
+
import { Heading } from '../heading';
|
|
9
|
+
import { Text } from '../text';
|
|
10
|
+
import type { MediaCardProps } from './types';
|
|
11
|
+
|
|
12
|
+
function resolveImageAspectRatio(
|
|
13
|
+
imageAspectRatio: NonNullable<MediaCardProps['imageAspectRatio']>,
|
|
14
|
+
) {
|
|
15
|
+
if (!Number.isFinite(imageAspectRatio) || imageAspectRatio <= 0) {
|
|
16
|
+
return 16 / 9;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return imageAspectRatio;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function MediaCardInner({
|
|
23
|
+
themeId: _themeId,
|
|
24
|
+
mode: _mode,
|
|
25
|
+
testID,
|
|
26
|
+
imageSource,
|
|
27
|
+
imageLabel,
|
|
28
|
+
image,
|
|
29
|
+
imageAspectRatio = 16 / 9,
|
|
30
|
+
title,
|
|
31
|
+
description,
|
|
32
|
+
eyebrow,
|
|
33
|
+
badges,
|
|
34
|
+
actions,
|
|
35
|
+
footer,
|
|
36
|
+
children,
|
|
37
|
+
tone = 'default',
|
|
38
|
+
compact = false,
|
|
39
|
+
onPress,
|
|
40
|
+
}: MediaCardProps) {
|
|
41
|
+
const { theme } = useZoraTheme();
|
|
42
|
+
const gap = compact ? 's' : 'm';
|
|
43
|
+
const isInteractive = Boolean(onPress) && !actions;
|
|
44
|
+
const resolvedAspectRatio = resolveImageAspectRatio(imageAspectRatio);
|
|
45
|
+
|
|
46
|
+
const renderImage = () => {
|
|
47
|
+
if (image) {
|
|
48
|
+
return (
|
|
49
|
+
<Box radius="m" style={{ overflow: 'hidden' }}>
|
|
50
|
+
{image}
|
|
51
|
+
</Box>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!imageSource) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Box bg={theme.semantics.neutral.surface} radius="m" style={{ overflow: 'hidden' }}>
|
|
61
|
+
<Box style={{ aspectRatio: resolvedAspectRatio, width: '100%' }}>
|
|
62
|
+
<Image
|
|
63
|
+
accessibilityLabel={imageLabel}
|
|
64
|
+
source={imageSource}
|
|
65
|
+
style={{ height: '100%', width: '100%' }}
|
|
66
|
+
/>
|
|
67
|
+
</Box>
|
|
68
|
+
</Box>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const hasHeader = [eyebrow, title, description, badges, actions].some((item) => item != null);
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<Card
|
|
76
|
+
compact={compact}
|
|
77
|
+
onPress={isInteractive ? onPress : undefined}
|
|
78
|
+
testID={testID}
|
|
79
|
+
tone={tone}
|
|
80
|
+
>
|
|
81
|
+
<Stack gap={gap}>
|
|
82
|
+
{renderImage()}
|
|
83
|
+
|
|
84
|
+
{hasHeader ? (
|
|
85
|
+
<Stack
|
|
86
|
+
align={{ base: 'flex-start', md: 'center' }}
|
|
87
|
+
direction={{ base: 'column', md: 'row' }}
|
|
88
|
+
gap="m"
|
|
89
|
+
justify="space-between"
|
|
90
|
+
>
|
|
91
|
+
<Box flex={1}>
|
|
92
|
+
<Stack gap="xs">
|
|
93
|
+
{eyebrow ? (
|
|
94
|
+
<Text tone="muted" variant="caption" weight="semiBold">
|
|
95
|
+
{eyebrow}
|
|
96
|
+
</Text>
|
|
97
|
+
) : null}
|
|
98
|
+
<Stack gap="xs">
|
|
99
|
+
<Heading level={compact ? 4 : 3}>{title}</Heading>
|
|
100
|
+
{badges ? <Box>{badges}</Box> : null}
|
|
101
|
+
</Stack>
|
|
102
|
+
{description ? (
|
|
103
|
+
<Text tone="muted" variant="bodySmall">
|
|
104
|
+
{description}
|
|
105
|
+
</Text>
|
|
106
|
+
) : null}
|
|
107
|
+
</Stack>
|
|
108
|
+
</Box>
|
|
109
|
+
{actions ? <Box>{actions}</Box> : null}
|
|
110
|
+
</Stack>
|
|
111
|
+
) : null}
|
|
112
|
+
|
|
113
|
+
{children ? <Box>{children}</Box> : null}
|
|
114
|
+
{footer ? <Box pt="xs">{footer}</Box> : null}
|
|
115
|
+
</Stack>
|
|
116
|
+
</Card>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export const MediaCard = withZoraThemeScope(MediaCardInner);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { ImageSourcePropType } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import type { ZoraCardTone } from '../../internal/recipes';
|
|
5
|
+
import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
|
|
6
|
+
|
|
7
|
+
interface MediaCardWithImageSource {
|
|
8
|
+
imageSource: ImageSourcePropType;
|
|
9
|
+
imageLabel?: string;
|
|
10
|
+
image?: never;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface MediaCardWithImageSlot {
|
|
14
|
+
image: React.ReactNode;
|
|
15
|
+
imageSource?: never;
|
|
16
|
+
imageLabel?: never;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface MediaCardWithoutImage {
|
|
20
|
+
image?: never;
|
|
21
|
+
imageSource?: never;
|
|
22
|
+
imageLabel?: never;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type MediaCardImageProps =
|
|
26
|
+
| MediaCardWithImageSource
|
|
27
|
+
| MediaCardWithImageSlot
|
|
28
|
+
| MediaCardWithoutImage;
|
|
29
|
+
|
|
30
|
+
interface MediaCardBaseProps extends ZoraBaseProps {
|
|
31
|
+
title: React.ReactNode;
|
|
32
|
+
description?: React.ReactNode;
|
|
33
|
+
eyebrow?: React.ReactNode;
|
|
34
|
+
badges?: React.ReactNode;
|
|
35
|
+
actions?: React.ReactNode;
|
|
36
|
+
footer?: React.ReactNode;
|
|
37
|
+
children?: React.ReactNode;
|
|
38
|
+
tone?: ZoraCardTone;
|
|
39
|
+
compact?: boolean;
|
|
40
|
+
onPress?: () => void;
|
|
41
|
+
imageAspectRatio?: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type MediaCardProps = MediaCardBaseProps & MediaCardImageProps;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Box, Inline, Stack } from '../../foundation';
|
|
4
|
+
import { resolveBadgeRecipe, resolveIconSize } from '../../internal/recipes';
|
|
5
|
+
import { useZoraTheme } from '../../theme/useZoraTheme';
|
|
6
|
+
import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
|
|
7
|
+
import { Badge } from '../badge';
|
|
8
|
+
import { Card } from '../card';
|
|
9
|
+
import { Heading } from '../heading';
|
|
10
|
+
import { Icon } from '../icon';
|
|
11
|
+
import { Text } from '../text';
|
|
12
|
+
import type { MetricCardProps } from './types';
|
|
13
|
+
|
|
14
|
+
function MetricCardInner({
|
|
15
|
+
themeId: _themeId,
|
|
16
|
+
mode: _mode,
|
|
17
|
+
testID,
|
|
18
|
+
label,
|
|
19
|
+
value,
|
|
20
|
+
description,
|
|
21
|
+
icon,
|
|
22
|
+
delta,
|
|
23
|
+
deltaTone = 'neutral',
|
|
24
|
+
actions,
|
|
25
|
+
tone = 'default',
|
|
26
|
+
compact = false,
|
|
27
|
+
onPress,
|
|
28
|
+
}: MetricCardProps) {
|
|
29
|
+
const { theme } = useZoraTheme();
|
|
30
|
+
const isInteractive = Boolean(onPress) && !actions;
|
|
31
|
+
|
|
32
|
+
const badgeRecipe = resolveBadgeRecipe({ tone: deltaTone, emphasis: 'soft', size: 's' });
|
|
33
|
+
const iconColor = theme.semantics.content.muted;
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Card
|
|
37
|
+
compact={compact}
|
|
38
|
+
onPress={isInteractive ? onPress : undefined}
|
|
39
|
+
testID={testID}
|
|
40
|
+
tone={tone}
|
|
41
|
+
>
|
|
42
|
+
<Stack gap={compact ? 's' : 'm'}>
|
|
43
|
+
<Inline align="flex-start" gap="m" justify="space-between">
|
|
44
|
+
<Stack flex={1} gap="xs">
|
|
45
|
+
<Inline align="center" gap="xs" wrap="wrap">
|
|
46
|
+
{icon ? (
|
|
47
|
+
<Icon
|
|
48
|
+
color={iconColor}
|
|
49
|
+
name={icon.name}
|
|
50
|
+
provider={icon.provider}
|
|
51
|
+
size={resolveIconSize('s')}
|
|
52
|
+
/>
|
|
53
|
+
) : null}
|
|
54
|
+
<Text tone="muted" variant="caption" weight="semiBold">
|
|
55
|
+
{label}
|
|
56
|
+
</Text>
|
|
57
|
+
{delta != null ? (
|
|
58
|
+
<Badge
|
|
59
|
+
emphasis={badgeRecipe.variant}
|
|
60
|
+
size={badgeRecipe.size}
|
|
61
|
+
tone={badgeRecipe.tone}
|
|
62
|
+
>
|
|
63
|
+
{delta}
|
|
64
|
+
</Badge>
|
|
65
|
+
) : null}
|
|
66
|
+
</Inline>
|
|
67
|
+
|
|
68
|
+
<Heading level={compact ? 3 : 2}>{value}</Heading>
|
|
69
|
+
|
|
70
|
+
{description ? (
|
|
71
|
+
<Text tone="muted" variant="bodySmall">
|
|
72
|
+
{description}
|
|
73
|
+
</Text>
|
|
74
|
+
) : null}
|
|
75
|
+
</Stack>
|
|
76
|
+
|
|
77
|
+
{actions ? <Box>{actions}</Box> : null}
|
|
78
|
+
</Inline>
|
|
79
|
+
</Stack>
|
|
80
|
+
</Card>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const MetricCard = withZoraThemeScope(MetricCardInner);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ButtonIconSpec } from '@ankhorage/surface';
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { ZoraCardTone, ZoraTone } from '../../internal/recipes';
|
|
5
|
+
import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
|
|
6
|
+
|
|
7
|
+
export interface MetricCardProps extends ZoraBaseProps {
|
|
8
|
+
label: React.ReactNode;
|
|
9
|
+
value: React.ReactNode;
|
|
10
|
+
description?: React.ReactNode;
|
|
11
|
+
icon?: ButtonIconSpec;
|
|
12
|
+
delta?: React.ReactNode;
|
|
13
|
+
deltaTone?: ZoraTone;
|
|
14
|
+
actions?: React.ReactNode;
|
|
15
|
+
tone?: ZoraCardTone;
|
|
16
|
+
compact?: boolean;
|
|
17
|
+
onPress?: () => void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Box } from '../../foundation';
|
|
4
|
+
import { useZoraTheme } from '../../theme/useZoraTheme';
|
|
5
|
+
import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
|
|
6
|
+
import { resolveProgressFraction } from './resolveProgressFraction';
|
|
7
|
+
import { type ProgressProps, resolveProgressRole } from './types';
|
|
8
|
+
|
|
9
|
+
function resolveProgressHeight(size: NonNullable<ProgressProps['size']>): number {
|
|
10
|
+
switch (size) {
|
|
11
|
+
case 's':
|
|
12
|
+
return 4;
|
|
13
|
+
case 'm':
|
|
14
|
+
return 6;
|
|
15
|
+
case 'l':
|
|
16
|
+
default:
|
|
17
|
+
return 8;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function ProgressInner({
|
|
22
|
+
themeId: _themeId,
|
|
23
|
+
mode: _mode,
|
|
24
|
+
testID,
|
|
25
|
+
value,
|
|
26
|
+
max = 100,
|
|
27
|
+
tone = 'primary',
|
|
28
|
+
size = 'm',
|
|
29
|
+
}: ProgressProps) {
|
|
30
|
+
const { theme } = useZoraTheme();
|
|
31
|
+
const fraction = resolveProgressFraction({ value, max });
|
|
32
|
+
const height = resolveProgressHeight(size);
|
|
33
|
+
const role = resolveProgressRole(theme, tone);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Box
|
|
37
|
+
accessibilityRole="progressbar"
|
|
38
|
+
bg={theme.semantics.neutral.surface}
|
|
39
|
+
borderColor={theme.semantics.neutral.divider}
|
|
40
|
+
borderWidth={1}
|
|
41
|
+
radius="full"
|
|
42
|
+
testID={testID}
|
|
43
|
+
style={{ height, overflow: 'hidden' }}
|
|
44
|
+
>
|
|
45
|
+
<Box bg={role.base} style={{ height: '100%', width: `${fraction * 100}%` }} />
|
|
46
|
+
</Box>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const Progress = withZoraThemeScope(ProgressInner);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import { resolveProgressFraction } from './resolveProgressFraction';
|
|
4
|
+
|
|
5
|
+
describe('resolveProgressFraction', () => {
|
|
6
|
+
test('clamps values to [0, 1]', () => {
|
|
7
|
+
expect(resolveProgressFraction({ value: -5, max: 10 })).toBe(0);
|
|
8
|
+
expect(resolveProgressFraction({ value: 0, max: 10 })).toBe(0);
|
|
9
|
+
expect(resolveProgressFraction({ value: 5, max: 10 })).toBe(0.5);
|
|
10
|
+
expect(resolveProgressFraction({ value: 10, max: 10 })).toBe(1);
|
|
11
|
+
expect(resolveProgressFraction({ value: 15, max: 10 })).toBe(1);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('returns 0 for invalid max', () => {
|
|
15
|
+
expect(resolveProgressFraction({ value: 5, max: 0 })).toBe(0);
|
|
16
|
+
expect(resolveProgressFraction({ value: 5, max: -3 })).toBe(0);
|
|
17
|
+
expect(resolveProgressFraction({ value: 5, max: Number.NaN })).toBe(0);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('returns 0 for invalid value', () => {
|
|
21
|
+
expect(resolveProgressFraction({ value: Number.NaN, max: 10 })).toBe(0);
|
|
22
|
+
});
|
|
23
|
+
});
|