@ankhorage/zora 1.4.7 → 1.4.9

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 (67) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +262 -0
  3. package/dist/components/card/meta.d.ts +1 -1
  4. package/dist/foundation/meta.d.ts +4 -4
  5. package/dist/index.d.ts +4 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +2 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/layout/auth-layout/meta.d.ts +1 -1
  10. package/dist/layout/page/meta.d.ts +1 -1
  11. package/dist/layout/page-section/meta.d.ts +1 -1
  12. package/dist/metadata/allowedChildren.d.ts +3 -3
  13. package/dist/metadata/allowedChildren.d.ts.map +1 -1
  14. package/dist/metadata/allowedChildren.js +2 -0
  15. package/dist/metadata/allowedChildren.js.map +1 -1
  16. package/dist/metadata/componentMeta.d.ts.map +1 -1
  17. package/dist/metadata/componentMeta.js +4 -0
  18. package/dist/metadata/componentMeta.js.map +1 -1
  19. package/dist/patterns/chat-list-item/ChatListItem.d.ts +4 -0
  20. package/dist/patterns/chat-list-item/ChatListItem.d.ts.map +1 -0
  21. package/dist/patterns/chat-list-item/ChatListItem.js +110 -0
  22. package/dist/patterns/chat-list-item/ChatListItem.js.map +1 -0
  23. package/dist/patterns/chat-list-item/index.d.ts +3 -0
  24. package/dist/patterns/chat-list-item/index.d.ts.map +1 -0
  25. package/dist/patterns/chat-list-item/index.js +2 -0
  26. package/dist/patterns/chat-list-item/index.js.map +1 -0
  27. package/dist/patterns/chat-list-item/meta.d.ts +74 -0
  28. package/dist/patterns/chat-list-item/meta.d.ts.map +1 -0
  29. package/dist/patterns/chat-list-item/meta.js +72 -0
  30. package/dist/patterns/chat-list-item/meta.js.map +1 -0
  31. package/dist/patterns/chat-list-item/types.d.ts +31 -0
  32. package/dist/patterns/chat-list-item/types.d.ts.map +1 -0
  33. package/dist/patterns/chat-list-item/types.js +2 -0
  34. package/dist/patterns/chat-list-item/types.js.map +1 -0
  35. package/dist/patterns/notice/meta.d.ts +1 -1
  36. package/dist/patterns/panel/meta.d.ts +1 -1
  37. package/dist/patterns/post-card/PostCard.d.ts +4 -0
  38. package/dist/patterns/post-card/PostCard.d.ts.map +1 -0
  39. package/dist/patterns/post-card/PostCard.js +133 -0
  40. package/dist/patterns/post-card/PostCard.js.map +1 -0
  41. package/dist/patterns/post-card/index.d.ts +3 -0
  42. package/dist/patterns/post-card/index.d.ts.map +1 -0
  43. package/dist/patterns/post-card/index.js +2 -0
  44. package/dist/patterns/post-card/index.js.map +1 -0
  45. package/dist/patterns/post-card/meta.d.ts +64 -0
  46. package/dist/patterns/post-card/meta.d.ts.map +1 -0
  47. package/dist/patterns/post-card/meta.js +66 -0
  48. package/dist/patterns/post-card/meta.js.map +1 -0
  49. package/dist/patterns/post-card/types.d.ts +64 -0
  50. package/dist/patterns/post-card/types.d.ts.map +1 -0
  51. package/dist/patterns/post-card/types.js +2 -0
  52. package/dist/patterns/post-card/types.js.map +1 -0
  53. package/package.json +1 -1
  54. package/src/index.ts +11 -0
  55. package/src/metadata/allowedChildren.ts +2 -0
  56. package/src/metadata/componentMeta.test.ts +2 -0
  57. package/src/metadata/componentMeta.ts +4 -0
  58. package/src/patterns/chat-list-item/ChatListItem.test.tsx +11 -0
  59. package/src/patterns/chat-list-item/ChatListItem.tsx +219 -0
  60. package/src/patterns/chat-list-item/index.ts +2 -0
  61. package/src/patterns/chat-list-item/meta.ts +74 -0
  62. package/src/patterns/chat-list-item/types.ts +33 -0
  63. package/src/patterns/post-card/PostCard.test.tsx +11 -0
  64. package/src/patterns/post-card/PostCard.tsx +234 -0
  65. package/src/patterns/post-card/index.ts +9 -0
  66. package/src/patterns/post-card/meta.ts +68 -0
  67. package/src/patterns/post-card/types.ts +71 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostCard.js","sourceRoot":"","sources":["../../../src/patterns/post-card/PostCard.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Image as ReactNativeImage } from 'react-native';\n\nimport { Avatar } from '../../components/avatar';\nimport { Button } from '../../components/button';\nimport { Card } from '../../components/card';\nimport { Text } from '../../components/text';\nimport { Box, Divider, Inline, Stack } from '../../foundation';\nimport { useZoraTheme } from '../../theme/useZoraTheme';\nimport { withZoraThemeScope } from '../../theme/withZoraThemeScope';\nimport type {\n PostAction,\n PostAuthor,\n PostCardMedia,\n PostCardProps,\n PostCommentPreview,\n} from './types';\n\nfunction resolveAuthorName(author: PostAuthor): string | undefined {\n return typeof author.name === 'string' ? author.name : author.avatar?.name;\n}\n\nfunction resolveMediaAspectRatio(aspectRatio: number | undefined): number {\n if (aspectRatio === undefined || !Number.isFinite(aspectRatio) || aspectRatio <= 0) {\n return 16 / 9;\n }\n\n return aspectRatio;\n}\n\nfunction isPostCardMediaList(\n media: NonNullable<PostCardProps['media']>,\n): media is readonly PostCardMedia[] {\n return Array.isArray(media);\n}\n\nfunction normalizeMedia(media: PostCardProps['media']): readonly PostCardMedia[] {\n if (!media) {\n return [];\n }\n\n if (isPostCardMediaList(media)) {\n return media;\n }\n\n return [media];\n}\n\nfunction PostCardAuthor({ author, compact = false }: { author: PostAuthor; compact?: boolean }) {\n const avatarName = resolveAuthorName(author);\n const { avatar } = author;\n\n return (\n <Inline align=\"center\" gap=\"s\" wrap=\"nowrap\">\n <Avatar\n initials={avatar?.initials}\n label={avatar?.label ?? avatarName}\n name={avatarName}\n shape={avatar?.shape}\n size={avatar?.size ?? (compact ? 's' : 'm')}\n source={avatar?.source}\n tone={avatar?.tone}\n />\n <Box flex={1}>\n <Stack gap=\"xxs\">\n <Text variant=\"bodySmall\" weight=\"semiBold\">\n {author.name}\n </Text>\n {author.subtitle ? (\n <Text tone=\"muted\" variant=\"caption\">\n {author.subtitle}\n </Text>\n ) : null}\n </Stack>\n </Box>\n </Inline>\n );\n}\n\nfunction PostCardMediaItem({ media }: { media: PostCardMedia }) {\n const { theme } = useZoraTheme();\n const aspectRatio = resolveMediaAspectRatio(media.aspectRatio);\n\n if (!('source' in media)) {\n return (\n <Box radius=\"m\" style={{ overflow: 'hidden' }}>\n {media.children}\n </Box>\n );\n }\n\n return (\n <Box bg={theme.semantics.neutral.surface} radius=\"m\" style={{ overflow: 'hidden' }}>\n <Box style={{ aspectRatio, width: '100%' }}>\n <ReactNativeImage\n accessibilityLabel={media.label}\n source={media.source}\n style={{ height: '100%', width: '100%' }}\n />\n </Box>\n </Box>\n );\n}\n\nfunction PostActionLabel({ action }: { action: PostAction }) {\n if (!action.count) {\n return <>{action.label}</>;\n }\n\n return (\n <>\n {action.label} {action.count}\n </>\n );\n}\n\nfunction PostCardActions({ actions }: { actions: readonly PostAction[] }) {\n if (actions.length === 0) {\n return null;\n }\n\n return (\n <Inline align=\"center\" gap=\"s\" wrap=\"wrap\">\n {actions.map((action) => (\n <Button\n key={action.id}\n disabled={action.disabled}\n emphasis={action.selected ? 'soft' : 'ghost'}\n leadingIcon={action.icon}\n onPress={action.onPress}\n size=\"s\"\n tone={action.selected ? 'primary' : 'neutral'}\n >\n <PostActionLabel action={action} />\n </Button>\n ))}\n </Inline>\n );\n}\n\nfunction PostCommentPreviewItem({ comment }: { comment: PostCommentPreview }) {\n return (\n <Inline align=\"flex-start\" gap=\"s\" wrap=\"nowrap\">\n {comment.author ? <PostCardAuthor author={comment.author} compact /> : null}\n <Box flex={1}>\n <Stack gap=\"xxs\">\n <Text variant=\"bodySmall\">{comment.text}</Text>\n {comment.meta ? (\n <Text tone=\"subtle\" variant=\"caption\">\n {comment.meta}\n </Text>\n ) : null}\n {comment.action ? <Box>{comment.action}</Box> : null}\n </Stack>\n </Box>\n </Inline>\n );\n}\n\nfunction PostCardComments({ comments }: { comments: readonly PostCommentPreview[] }) {\n if (comments.length === 0) {\n return null;\n }\n\n return (\n <Stack gap=\"s\">\n {comments.map((comment) => (\n <PostCommentPreviewItem key={comment.id} comment={comment} />\n ))}\n </Stack>\n );\n}\n\nfunction PostCardInner({\n themeId: _themeId,\n mode: _mode,\n testID,\n author,\n text,\n children,\n media,\n actions = [],\n comments = [],\n headerAction,\n footer,\n tone = 'default',\n compact = false,\n onPress,\n}: PostCardProps) {\n const mediaItems = normalizeMedia(media);\n const gap = compact ? 's' : 'm';\n const isInteractive = Boolean(onPress) && !headerAction;\n const hasBody = text != null || children != null || mediaItems.length > 0;\n const hasEngagement = actions.length > 0 || comments.length > 0;\n\n return (\n <Card\n compact={compact}\n onPress={isInteractive ? onPress : undefined}\n testID={testID}\n tone={tone}\n >\n <Stack gap={gap}>\n <Inline align=\"center\" gap=\"m\" justify=\"space-between\" wrap=\"nowrap\">\n <Box flex={1}>\n <PostCardAuthor author={author} compact={compact} />\n </Box>\n {headerAction ? <Box>{headerAction}</Box> : null}\n </Inline>\n\n {hasBody ? (\n <Stack gap={gap}>\n {text ? <Text variant=\"body\">{text}</Text> : null}\n {children ? <Box>{children}</Box> : null}\n {mediaItems.length > 0 ? (\n <Stack gap=\"s\">\n {mediaItems.map((item, index) => (\n <PostCardMediaItem key={`${index}`} media={item} />\n ))}\n </Stack>\n ) : null}\n </Stack>\n ) : null}\n\n {hasEngagement ? <Divider /> : null}\n <PostCardActions actions={actions} />\n <PostCardComments comments={comments} />\n {footer ? <Box pt=\"xs\">{footer}</Box> : null}\n </Stack>\n </Card>\n );\n}\n\nexport const PostCard = withZoraThemeScope(PostCardInner);\n"]}
@@ -0,0 +1,3 @@
1
+ export { PostCard } from './PostCard';
2
+ export type { PostAction, PostAuthor, PostAuthorAvatar, PostCardMedia, PostCardProps, PostCommentPreview, } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/patterns/post-card/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EACV,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,kBAAkB,GACnB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { PostCard } from './PostCard';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/patterns/post-card/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export { PostCard } from './PostCard';\nexport type {\n PostAction,\n PostAuthor,\n PostAuthorAvatar,\n PostCardMedia,\n PostCardProps,\n PostCommentPreview,\n} from './types';\n"]}
@@ -0,0 +1,64 @@
1
+ export declare const postCardMeta: {
2
+ readonly name: "PostCard";
3
+ readonly category: "pattern";
4
+ readonly description: "Social/content post card with author identity, body, media, actions, and comment previews.";
5
+ readonly directManifestNode: true;
6
+ readonly allowedChildren: readonly ["Box", "Stack", "Grid", "Container", "Divider", "Text", "Heading", "Button", "Input", "Textarea", "FormField", "Card", "Panel", "Notice", "EmptyState", "SectionHeader", "SettingsRow", "PostCard", "ChatListItem"];
7
+ readonly blueprint: {
8
+ readonly label: "Post card";
9
+ readonly icon: {
10
+ readonly name: "chatbubble-ellipses-outline";
11
+ };
12
+ readonly defaultProps: {
13
+ readonly author: {
14
+ readonly name: "Ada Lovelace";
15
+ readonly subtitle: "@ada · 2h";
16
+ readonly avatar: {
17
+ readonly name: "Ada Lovelace";
18
+ };
19
+ };
20
+ readonly text: "Share an update, image, or announcement with a reusable ZORA PostCard.";
21
+ };
22
+ };
23
+ readonly props: {
24
+ readonly author: {
25
+ readonly type: "array";
26
+ readonly category: "Content";
27
+ readonly label: "Author";
28
+ readonly itemSchema: readonly [{
29
+ readonly key: "name";
30
+ readonly schema: {
31
+ readonly type: "string";
32
+ readonly category: "Content";
33
+ readonly label: "Name";
34
+ };
35
+ }, {
36
+ readonly key: "subtitle";
37
+ readonly schema: {
38
+ readonly type: "string";
39
+ readonly category: "Content";
40
+ readonly label: "Subtitle";
41
+ };
42
+ }];
43
+ };
44
+ readonly text: {
45
+ readonly type: "string";
46
+ readonly category: "Content";
47
+ readonly label: "Text";
48
+ };
49
+ readonly compact: {
50
+ readonly type: "boolean";
51
+ readonly category: "Layout";
52
+ readonly label: "Compact";
53
+ readonly default: false;
54
+ };
55
+ readonly tone: {
56
+ readonly type: "enum";
57
+ readonly category: "Style";
58
+ readonly label: "Tone";
59
+ readonly enum: readonly ["default", "subtle", "outline"];
60
+ readonly default: "default";
61
+ };
62
+ };
63
+ };
64
+ //# sourceMappingURL=meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../../src/patterns/post-card/meta.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgEa,CAAC"}
@@ -0,0 +1,66 @@
1
+ import { CONTAINER_ALLOWED_CHILDREN } from '../../metadata/allowedChildren';
2
+ export const postCardMeta = {
3
+ name: 'PostCard',
4
+ category: 'pattern',
5
+ description: 'Social/content post card with author identity, body, media, actions, and comment previews.',
6
+ directManifestNode: true,
7
+ allowedChildren: [...CONTAINER_ALLOWED_CHILDREN],
8
+ blueprint: {
9
+ label: 'Post card',
10
+ icon: { name: 'chatbubble-ellipses-outline' },
11
+ defaultProps: {
12
+ author: {
13
+ name: 'Ada Lovelace',
14
+ subtitle: '@ada · 2h',
15
+ avatar: {
16
+ name: 'Ada Lovelace',
17
+ },
18
+ },
19
+ text: 'Share an update, image, or announcement with a reusable ZORA PostCard.',
20
+ },
21
+ },
22
+ props: {
23
+ author: {
24
+ type: 'array',
25
+ category: 'Content',
26
+ label: 'Author',
27
+ itemSchema: [
28
+ {
29
+ key: 'name',
30
+ schema: {
31
+ type: 'string',
32
+ category: 'Content',
33
+ label: 'Name',
34
+ },
35
+ },
36
+ {
37
+ key: 'subtitle',
38
+ schema: {
39
+ type: 'string',
40
+ category: 'Content',
41
+ label: 'Subtitle',
42
+ },
43
+ },
44
+ ],
45
+ },
46
+ text: {
47
+ type: 'string',
48
+ category: 'Content',
49
+ label: 'Text',
50
+ },
51
+ compact: {
52
+ type: 'boolean',
53
+ category: 'Layout',
54
+ label: 'Compact',
55
+ default: false,
56
+ },
57
+ tone: {
58
+ type: 'enum',
59
+ category: 'Style',
60
+ label: 'Tone',
61
+ enum: ['default', 'subtle', 'outline'],
62
+ default: 'default',
63
+ },
64
+ },
65
+ };
66
+ //# sourceMappingURL=meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../../src/patterns/post-card/meta.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAE5E,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,UAAU;IAChB,QAAQ,EAAE,SAAS;IACnB,WAAW,EACT,4FAA4F;IAC9F,kBAAkB,EAAE,IAAI;IACxB,eAAe,EAAE,CAAC,GAAG,0BAA0B,CAAC;IAChD,SAAS,EAAE;QACT,KAAK,EAAE,WAAW;QAClB,IAAI,EAAE,EAAE,IAAI,EAAE,6BAA6B,EAAE;QAC7C,YAAY,EAAE;YACZ,MAAM,EAAE;gBACN,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,WAAW;gBACrB,MAAM,EAAE;oBACN,IAAI,EAAE,cAAc;iBACrB;aACF;YACD,IAAI,EAAE,wEAAwE;SAC/E;KACF;IACD,KAAK,EAAE;QACL,MAAM,EAAE;YACN,IAAI,EAAE,OAAO;YACb,QAAQ,EAAE,SAAS;YACnB,KAAK,EAAE,QAAQ;YACf,UAAU,EAAE;gBACV;oBACE,GAAG,EAAE,MAAM;oBACX,MAAM,EAAE;wBACN,IAAI,EAAE,QAAQ;wBACd,QAAQ,EAAE,SAAS;wBACnB,KAAK,EAAE,MAAM;qBACd;iBACF;gBACD;oBACE,GAAG,EAAE,UAAU;oBACf,MAAM,EAAE;wBACN,IAAI,EAAE,QAAQ;wBACd,QAAQ,EAAE,SAAS;wBACnB,KAAK,EAAE,UAAU;qBAClB;iBACF;aACF;SACF;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,SAAS;YACnB,KAAK,EAAE,MAAM;SACd;QACD,OAAO,EAAE;YACP,IAAI,EAAE,SAAS;YACf,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,SAAS;YAChB,OAAO,EAAE,KAAK;SACf;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC;YACtC,OAAO,EAAE,SAAS;SACnB;KACF;CACmC,CAAC","sourcesContent":["import type { ZoraComponentMeta } from '../../metadata';\nimport { CONTAINER_ALLOWED_CHILDREN } from '../../metadata/allowedChildren';\n\nexport const postCardMeta = {\n name: 'PostCard',\n category: 'pattern',\n description:\n 'Social/content post card with author identity, body, media, actions, and comment previews.',\n directManifestNode: true,\n allowedChildren: [...CONTAINER_ALLOWED_CHILDREN],\n blueprint: {\n label: 'Post card',\n icon: { name: 'chatbubble-ellipses-outline' },\n defaultProps: {\n author: {\n name: 'Ada Lovelace',\n subtitle: '@ada · 2h',\n avatar: {\n name: 'Ada Lovelace',\n },\n },\n text: 'Share an update, image, or announcement with a reusable ZORA PostCard.',\n },\n },\n props: {\n author: {\n type: 'array',\n category: 'Content',\n label: 'Author',\n itemSchema: [\n {\n key: 'name',\n schema: {\n type: 'string',\n category: 'Content',\n label: 'Name',\n },\n },\n {\n key: 'subtitle',\n schema: {\n type: 'string',\n category: 'Content',\n label: 'Subtitle',\n },\n },\n ],\n },\n text: {\n type: 'string',\n category: 'Content',\n label: 'Text',\n },\n compact: {\n type: 'boolean',\n category: 'Layout',\n label: 'Compact',\n default: false,\n },\n tone: {\n type: 'enum',\n category: 'Style',\n label: 'Tone',\n enum: ['default', 'subtle', 'outline'],\n default: 'default',\n },\n },\n} as const satisfies ZoraComponentMeta;\n"]}
@@ -0,0 +1,64 @@
1
+ import type { ButtonIconSpec } from '@ankhorage/surface';
2
+ import type React from 'react';
3
+ import type { ImageSourcePropType } from 'react-native';
4
+ import type { AvatarShape, AvatarSize } from '../../components/avatar';
5
+ import type { ZoraCardTone, ZoraTone } from '../../internal/recipes';
6
+ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
7
+ export interface PostAuthorAvatar {
8
+ source?: ImageSourcePropType;
9
+ name?: string;
10
+ initials?: string;
11
+ label?: string;
12
+ size?: AvatarSize;
13
+ shape?: AvatarShape;
14
+ tone?: ZoraTone;
15
+ }
16
+ export interface PostAuthor {
17
+ name: React.ReactNode;
18
+ subtitle?: React.ReactNode;
19
+ avatar?: PostAuthorAvatar;
20
+ }
21
+ interface PostCardSourceMedia {
22
+ source: ImageSourcePropType;
23
+ label: string;
24
+ aspectRatio?: number;
25
+ children?: never;
26
+ }
27
+ interface PostCardCustomMedia {
28
+ children: React.ReactNode;
29
+ label?: string;
30
+ aspectRatio?: number;
31
+ source?: never;
32
+ }
33
+ export type PostCardMedia = PostCardSourceMedia | PostCardCustomMedia;
34
+ export interface PostAction {
35
+ id: string;
36
+ label: string;
37
+ icon?: ButtonIconSpec;
38
+ count?: React.ReactNode;
39
+ selected?: boolean;
40
+ disabled?: boolean;
41
+ onPress?: () => void;
42
+ }
43
+ export interface PostCommentPreview {
44
+ id: string;
45
+ author?: PostAuthor;
46
+ text: React.ReactNode;
47
+ meta?: React.ReactNode;
48
+ action?: React.ReactNode;
49
+ }
50
+ export interface PostCardProps extends ZoraBaseProps {
51
+ author: PostAuthor;
52
+ text?: React.ReactNode;
53
+ children?: React.ReactNode;
54
+ media?: PostCardMedia | readonly PostCardMedia[];
55
+ actions?: readonly PostAction[];
56
+ comments?: readonly PostCommentPreview[];
57
+ headerAction?: React.ReactNode;
58
+ footer?: React.ReactNode;
59
+ tone?: ZoraCardTone;
60
+ compact?: boolean;
61
+ onPress?: () => void;
62
+ }
63
+ export {};
64
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/patterns/post-card/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED,UAAU,mBAAmB;IAC3B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC;CAClB;AAED,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED,MAAM,MAAM,aAAa,GAAG,mBAAmB,GAAG,mBAAmB,CAAC;AAEtE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC1B;AAED,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,aAAa,GAAG,SAAS,aAAa,EAAE,CAAC;IACjD,OAAO,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACzC,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/patterns/post-card/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ButtonIconSpec } from '@ankhorage/surface';\nimport type React from 'react';\nimport type { ImageSourcePropType } from 'react-native';\n\nimport type { AvatarShape, AvatarSize } from '../../components/avatar';\nimport type { ZoraCardTone, ZoraTone } from '../../internal/recipes';\nimport type { ZoraBaseProps } from '../../theme/ZoraBaseProps';\n\nexport interface PostAuthorAvatar {\n source?: ImageSourcePropType;\n name?: string;\n initials?: string;\n label?: string;\n size?: AvatarSize;\n shape?: AvatarShape;\n tone?: ZoraTone;\n}\n\nexport interface PostAuthor {\n name: React.ReactNode;\n subtitle?: React.ReactNode;\n avatar?: PostAuthorAvatar;\n}\n\ninterface PostCardSourceMedia {\n source: ImageSourcePropType;\n label: string;\n aspectRatio?: number;\n children?: never;\n}\n\ninterface PostCardCustomMedia {\n children: React.ReactNode;\n label?: string;\n aspectRatio?: number;\n source?: never;\n}\n\nexport type PostCardMedia = PostCardSourceMedia | PostCardCustomMedia;\n\nexport interface PostAction {\n id: string;\n label: string;\n icon?: ButtonIconSpec;\n count?: React.ReactNode;\n selected?: boolean;\n disabled?: boolean;\n onPress?: () => void;\n}\n\nexport interface PostCommentPreview {\n id: string;\n author?: PostAuthor;\n text: React.ReactNode;\n meta?: React.ReactNode;\n action?: React.ReactNode;\n}\n\nexport interface PostCardProps extends ZoraBaseProps {\n author: PostAuthor;\n text?: React.ReactNode;\n children?: React.ReactNode;\n media?: PostCardMedia | readonly PostCardMedia[];\n actions?: readonly PostAction[];\n comments?: readonly PostCommentPreview[];\n headerAction?: React.ReactNode;\n footer?: React.ReactNode;\n tone?: ZoraCardTone;\n compact?: boolean;\n onPress?: () => void;\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ankhorage/zora",
3
3
  "type": "module",
4
- "version": "1.4.7",
4
+ "version": "1.4.9",
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": {
package/src/index.ts CHANGED
@@ -163,6 +163,8 @@ export type {
163
163
  SignUpFormValues,
164
164
  } from './patterns/auth';
165
165
  export { ForgotPasswordForm, OtpForm, SignInForm, SignUpForm } from './patterns/auth';
166
+ export type { ChatListAvatar, ChatListItemProps } from './patterns/chat-list-item';
167
+ export { ChatListItem } from './patterns/chat-list-item';
166
168
  export type {
167
169
  CollectionEditorProps,
168
170
  CollectionEditorRenderItemProps,
@@ -205,6 +207,15 @@ export type { NoticeProps } from './patterns/notice';
205
207
  export { Notice } from './patterns/notice';
206
208
  export type { PanelProps } from './patterns/panel';
207
209
  export { Panel } from './patterns/panel';
210
+ export type {
211
+ PostAction,
212
+ PostAuthor,
213
+ PostAuthorAvatar,
214
+ PostCardMedia,
215
+ PostCardProps,
216
+ PostCommentPreview,
217
+ } from './patterns/post-card';
218
+ export { PostCard } from './patterns/post-card';
208
219
  export type {
209
220
  ResponsivePanelDesktopMode,
210
221
  ResponsivePanelMobileMode,
@@ -16,6 +16,8 @@ export const CONTAINER_ALLOWED_CHILDREN = [
16
16
  'EmptyState',
17
17
  'SectionHeader',
18
18
  'SettingsRow',
19
+ 'PostCard',
20
+ 'ChatListItem',
19
21
  ] as const;
20
22
 
21
23
  export const PAGE_SECTION_ALLOWED_CHILDREN = [...CONTAINER_ALLOWED_CHILDREN] as const;
@@ -141,6 +141,7 @@ describe('ZORA_COMPONENT_META invariants', () => {
141
141
  'Text',
142
142
  'Heading',
143
143
  'Divider',
144
+ 'ChatListItem',
144
145
  ]);
145
146
 
146
147
  const expectedContainerNodes = new Set([
@@ -151,6 +152,7 @@ describe('ZORA_COMPONENT_META invariants', () => {
151
152
  'Card',
152
153
  'Panel',
153
154
  'Notice',
155
+ 'PostCard',
154
156
  'Box',
155
157
  'Stack',
156
158
  'Grid',
@@ -43,6 +43,7 @@ import {
43
43
  signInFormMeta,
44
44
  signUpFormMeta,
45
45
  } from '../patterns/auth/meta';
46
+ import { chatListItemMeta } from '../patterns/chat-list-item/meta';
46
47
  import { collectionEditorMeta } from '../patterns/collection-editor/meta';
47
48
  import { confirmDialogMeta } from '../patterns/confirm-dialog/meta';
48
49
  import { disclosureSectionMeta } from '../patterns/disclosure-section/meta';
@@ -55,6 +56,7 @@ import { inspectorFieldMeta } from '../patterns/inspector-field/meta';
55
56
  import { listMeta, listRowMeta, listSectionMeta } from '../patterns/list/meta';
56
57
  import { noticeMeta } from '../patterns/notice/meta';
57
58
  import { panelMeta } from '../patterns/panel/meta';
59
+ import { postCardMeta } from '../patterns/post-card/meta';
58
60
  import { responsivePanelMeta } from '../patterns/responsive-panel/meta';
59
61
  import { sectionHeaderMeta } from '../patterns/section-header/meta';
60
62
  import { selectableItemMeta, selectionProviderMeta } from '../patterns/selection/meta';
@@ -118,6 +120,7 @@ export const ZORA_COMPONENT_META: ZoraComponentMetaRegistry = {
118
120
  OtpForm: otpFormMeta,
119
121
  SignInForm: signInFormMeta,
120
122
  SignUpForm: signUpFormMeta,
123
+ ChatListItem: chatListItemMeta,
121
124
  CollectionEditor: collectionEditorMeta,
122
125
  ConfirmDialog: confirmDialogMeta,
123
126
  DisclosureSection: disclosureSectionMeta,
@@ -132,6 +135,7 @@ export const ZORA_COMPONENT_META: ZoraComponentMetaRegistry = {
132
135
  ListSection: listSectionMeta,
133
136
  Notice: noticeMeta,
134
137
  Panel: panelMeta,
138
+ PostCard: postCardMeta,
135
139
  ResponsivePanel: responsivePanelMeta,
136
140
  SectionHeader: sectionHeaderMeta,
137
141
  SelectableItem: selectableItemMeta,
@@ -0,0 +1,11 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+
3
+ import { ZORA_COMPONENT_META } from '../../metadata';
4
+
5
+ describe('ChatListItem', () => {
6
+ test('is registered as a public ZORA pattern', () => {
7
+ expect(ZORA_COMPONENT_META.ChatListItem?.name).toBe('ChatListItem');
8
+ expect(ZORA_COMPONENT_META.ChatListItem?.category).toBe('pattern');
9
+ expect(ZORA_COMPONENT_META.ChatListItem?.directManifestNode).toBe(true);
10
+ });
11
+ });
@@ -0,0 +1,219 @@
1
+ import { ButtonBase } from '@ankhorage/surface';
2
+ import React from 'react';
3
+
4
+ import { Avatar } from '../../components/avatar';
5
+ import { Badge } from '../../components/badge';
6
+ import { Text } from '../../components/text';
7
+ import { Box, Inline, Stack } from '../../foundation';
8
+ import { useZoraTheme } from '../../theme/useZoraTheme';
9
+ import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
10
+ import type { ChatListAvatar, ChatListItemProps } from './types';
11
+
12
+ function resolveAvatarName({
13
+ avatar,
14
+ title,
15
+ }: {
16
+ avatar: ChatListAvatar | undefined;
17
+ title: React.ReactNode;
18
+ }): string | undefined {
19
+ if (avatar?.name) {
20
+ return avatar.name;
21
+ }
22
+
23
+ return typeof title === 'string' ? title : undefined;
24
+ }
25
+
26
+ function resolvePadding(compact: boolean) {
27
+ return compact ? { px: 'm' as const, py: 's' as const } : { px: 'm' as const, py: 'm' as const };
28
+ }
29
+
30
+ function resolveContainerStyles({
31
+ theme,
32
+ selected,
33
+ pressed,
34
+ hovered,
35
+ disabled,
36
+ }: {
37
+ theme: ReturnType<typeof useZoraTheme>['theme'];
38
+ selected: boolean;
39
+ pressed: boolean;
40
+ hovered: boolean;
41
+ disabled: boolean;
42
+ }) {
43
+ const borderColor = selected ? theme.semantics.border.focus : 'transparent';
44
+
45
+ return {
46
+ bg: pressed
47
+ ? theme.semantics.neutral.surfaceActive
48
+ : hovered
49
+ ? theme.semantics.neutral.surfaceHover
50
+ : selected
51
+ ? theme.semantics.neutral.surface
52
+ : 'transparent',
53
+ borderColor,
54
+ borderWidth: selected ? 1 : 0,
55
+ opacity: disabled ? 0.72 : 1,
56
+ };
57
+ }
58
+
59
+ function renderUnreadCount(unreadCount: React.ReactNode) {
60
+ if (unreadCount == null) {
61
+ return null;
62
+ }
63
+
64
+ return (
65
+ <Badge size="s" tone="primary">
66
+ {unreadCount}
67
+ </Badge>
68
+ );
69
+ }
70
+
71
+ function ChatListItemInner({
72
+ themeId: _themeId,
73
+ mode: _mode,
74
+ testID,
75
+ title,
76
+ preview,
77
+ meta,
78
+ timestamp,
79
+ avatar,
80
+ leading,
81
+ trailing,
82
+ unread = false,
83
+ unreadCount,
84
+ selected = false,
85
+ disabled = false,
86
+ compact = false,
87
+ accessibilityLabel,
88
+ onPress,
89
+ }: ChatListItemProps) {
90
+ const { theme } = useZoraTheme();
91
+ const padding = resolvePadding(compact);
92
+ const avatarName = resolveAvatarName({ avatar, title });
93
+ const isInteractive = Boolean(onPress);
94
+ const hasTimestamp = timestamp != null;
95
+ const hasPreview = preview != null;
96
+ const hasMeta = meta != null;
97
+ const hasTrailing = trailing != null;
98
+ const hasUnreadCount = unreadCount != null;
99
+ const hasSecondaryRow = hasPreview || hasMeta || hasUnreadCount || hasTrailing;
100
+
101
+ const content = ({ pressed, hovered }: { pressed: boolean; hovered: boolean }) => {
102
+ const styles = resolveContainerStyles({
103
+ theme,
104
+ selected,
105
+ pressed,
106
+ hovered,
107
+ disabled,
108
+ });
109
+
110
+ return (
111
+ <Box
112
+ bg={styles.bg}
113
+ borderColor={styles.borderColor}
114
+ borderWidth={styles.borderWidth}
115
+ px={padding.px}
116
+ py={padding.py}
117
+ radius="m"
118
+ style={{ opacity: styles.opacity }}
119
+ >
120
+ <Inline align="center" gap="m" wrap="nowrap">
121
+ {leading ?? (
122
+ <Avatar
123
+ initials={avatar?.initials}
124
+ label={avatar?.label ?? avatarName}
125
+ name={avatarName}
126
+ shape={avatar?.shape}
127
+ size={avatar?.size ?? (compact ? 's' : 'm')}
128
+ source={avatar?.source}
129
+ tone={avatar?.tone}
130
+ />
131
+ )}
132
+
133
+ <Box flex={1}>
134
+ <Stack gap="xxs">
135
+ <Inline align="center" gap="s" justify="space-between" wrap="nowrap">
136
+ <Box flex={1}>
137
+ <Text
138
+ numberOfLines={1}
139
+ tone={disabled ? 'muted' : 'default'}
140
+ variant="bodySmall"
141
+ weight={unread || selected ? 'semiBold' : 'medium'}
142
+ >
143
+ {title}
144
+ </Text>
145
+ </Box>
146
+ {hasTimestamp ? (
147
+ <Text
148
+ numberOfLines={1}
149
+ tone={unread ? 'primary' : 'subtle'}
150
+ variant="caption"
151
+ weight={unread ? 'semiBold' : 'regular'}
152
+ >
153
+ {timestamp}
154
+ </Text>
155
+ ) : null}
156
+ </Inline>
157
+
158
+ {hasSecondaryRow ? (
159
+ <Inline align="center" gap="s" justify="space-between" wrap="nowrap">
160
+ <Box flex={1}>
161
+ <Stack gap="xxs">
162
+ {hasPreview ? (
163
+ <Text
164
+ numberOfLines={1}
165
+ tone={unread ? 'default' : 'muted'}
166
+ variant="bodySmall"
167
+ weight={unread ? 'medium' : 'regular'}
168
+ >
169
+ {preview}
170
+ </Text>
171
+ ) : null}
172
+ {hasMeta ? (
173
+ <Text numberOfLines={1} tone="subtle" variant="caption">
174
+ {meta}
175
+ </Text>
176
+ ) : null}
177
+ </Stack>
178
+ </Box>
179
+
180
+ {hasUnreadCount || hasTrailing ? (
181
+ <Inline align="center" gap="s" wrap="nowrap">
182
+ {renderUnreadCount(unreadCount)}
183
+ {trailing}
184
+ </Inline>
185
+ ) : null}
186
+ </Inline>
187
+ ) : null}
188
+ </Stack>
189
+ </Box>
190
+ </Inline>
191
+ </Box>
192
+ );
193
+ };
194
+
195
+ if (!isInteractive) {
196
+ return <Box testID={testID}>{content({ pressed: false, hovered: false })}</Box>;
197
+ }
198
+
199
+ return (
200
+ <ButtonBase
201
+ accessibilityLabel={accessibilityLabel}
202
+ accessibilityRole="button"
203
+ accessibilityState={{ disabled, selected }}
204
+ disabled={disabled}
205
+ onPress={onPress}
206
+ radius="m"
207
+ testID={testID}
208
+ >
209
+ {(state) =>
210
+ content({
211
+ pressed: state.pressed,
212
+ hovered: state.hovered,
213
+ })
214
+ }
215
+ </ButtonBase>
216
+ );
217
+ }
218
+
219
+ export const ChatListItem = withZoraThemeScope(ChatListItemInner);
@@ -0,0 +1,2 @@
1
+ export { ChatListItem } from './ChatListItem';
2
+ export type { ChatListAvatar, ChatListItemProps } from './types';