@ankhorage/zora 1.0.4 → 1.0.5

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 (122) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +214 -5
  3. package/dist/components/avatar/Avatar.d.ts +4 -0
  4. package/dist/components/avatar/Avatar.d.ts.map +1 -0
  5. package/dist/components/avatar/Avatar.js +80 -0
  6. package/dist/components/avatar/Avatar.js.map +1 -0
  7. package/dist/components/avatar/index.d.ts +4 -0
  8. package/dist/components/avatar/index.d.ts.map +1 -0
  9. package/dist/components/avatar/index.js +3 -0
  10. package/dist/components/avatar/index.js.map +1 -0
  11. package/dist/components/avatar/resolveAvatarInitials.d.ts +2 -0
  12. package/dist/components/avatar/resolveAvatarInitials.d.ts.map +1 -0
  13. package/dist/components/avatar/resolveAvatarInitials.js +44 -0
  14. package/dist/components/avatar/resolveAvatarInitials.js.map +1 -0
  15. package/dist/components/avatar/types.d.ts +17 -0
  16. package/dist/components/avatar/types.d.ts.map +1 -0
  17. package/dist/components/avatar/types.js +2 -0
  18. package/dist/components/avatar/types.js.map +1 -0
  19. package/dist/components/avatar-group/AvatarGroup.d.ts +4 -0
  20. package/dist/components/avatar-group/AvatarGroup.d.ts.map +1 -0
  21. package/dist/components/avatar-group/AvatarGroup.js +26 -0
  22. package/dist/components/avatar-group/AvatarGroup.js.map +1 -0
  23. package/dist/components/avatar-group/index.d.ts +3 -0
  24. package/dist/components/avatar-group/index.d.ts.map +1 -0
  25. package/dist/components/avatar-group/index.js +2 -0
  26. package/dist/components/avatar-group/index.js.map +1 -0
  27. package/dist/components/avatar-group/types.d.ts +22 -0
  28. package/dist/components/avatar-group/types.d.ts.map +1 -0
  29. package/dist/components/avatar-group/types.js +2 -0
  30. package/dist/components/avatar-group/types.js.map +1 -0
  31. package/dist/components/chip/Chip.d.ts +4 -0
  32. package/dist/components/chip/Chip.d.ts.map +1 -0
  33. package/dist/components/chip/Chip.js +54 -0
  34. package/dist/components/chip/Chip.js.map +1 -0
  35. package/dist/components/chip/index.d.ts +3 -0
  36. package/dist/components/chip/index.d.ts.map +1 -0
  37. package/dist/components/chip/index.js +2 -0
  38. package/dist/components/chip/index.js.map +1 -0
  39. package/dist/components/chip/resolveChipColors.d.ts +10 -0
  40. package/dist/components/chip/resolveChipColors.d.ts.map +1 -0
  41. package/dist/components/chip/resolveChipColors.js +47 -0
  42. package/dist/components/chip/resolveChipColors.js.map +1 -0
  43. package/dist/components/chip/types.d.ts +26 -0
  44. package/dist/components/chip/types.d.ts.map +1 -0
  45. package/dist/components/chip/types.js +2 -0
  46. package/dist/components/chip/types.js.map +1 -0
  47. package/dist/components/chip-group/ChipGroup.d.ts +4 -0
  48. package/dist/components/chip-group/ChipGroup.d.ts.map +1 -0
  49. package/dist/components/chip-group/ChipGroup.js +32 -0
  50. package/dist/components/chip-group/ChipGroup.js.map +1 -0
  51. package/dist/components/chip-group/index.d.ts +3 -0
  52. package/dist/components/chip-group/index.d.ts.map +1 -0
  53. package/dist/components/chip-group/index.js +2 -0
  54. package/dist/components/chip-group/index.js.map +1 -0
  55. package/dist/components/chip-group/types.d.ts +31 -0
  56. package/dist/components/chip-group/types.d.ts.map +1 -0
  57. package/dist/components/chip-group/types.js +2 -0
  58. package/dist/components/chip-group/types.js.map +1 -0
  59. package/dist/components/input/Input.d.ts.map +1 -1
  60. package/dist/components/input/Input.js +3 -2
  61. package/dist/components/input/Input.js.map +1 -1
  62. package/dist/components/input/index.d.ts +1 -1
  63. package/dist/components/input/index.d.ts.map +1 -1
  64. package/dist/components/input/index.js.map +1 -1
  65. package/dist/components/input/types.d.ts +15 -2
  66. package/dist/components/input/types.d.ts.map +1 -1
  67. package/dist/components/input/types.js.map +1 -1
  68. package/dist/components/search-bar/SearchBar.d.ts +4 -0
  69. package/dist/components/search-bar/SearchBar.d.ts.map +1 -0
  70. package/dist/components/search-bar/SearchBar.js +18 -0
  71. package/dist/components/search-bar/SearchBar.js.map +1 -0
  72. package/dist/components/search-bar/index.d.ts +3 -0
  73. package/dist/components/search-bar/index.d.ts.map +1 -0
  74. package/dist/components/search-bar/index.js +2 -0
  75. package/dist/components/search-bar/index.js.map +1 -0
  76. package/dist/components/search-bar/types.d.ts +14 -0
  77. package/dist/components/search-bar/types.d.ts.map +1 -0
  78. package/dist/components/search-bar/types.js +2 -0
  79. package/dist/components/search-bar/types.js.map +1 -0
  80. package/dist/index.d.ts +13 -1
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +6 -0
  83. package/dist/index.js.map +1 -1
  84. package/dist/patterns/filter-bar/FilterBar.d.ts +4 -0
  85. package/dist/patterns/filter-bar/FilterBar.d.ts.map +1 -0
  86. package/dist/patterns/filter-bar/FilterBar.js +12 -0
  87. package/dist/patterns/filter-bar/FilterBar.js.map +1 -0
  88. package/dist/patterns/filter-bar/index.d.ts +3 -0
  89. package/dist/patterns/filter-bar/index.d.ts.map +1 -0
  90. package/dist/patterns/filter-bar/index.js +2 -0
  91. package/dist/patterns/filter-bar/index.js.map +1 -0
  92. package/dist/patterns/filter-bar/types.d.ts +9 -0
  93. package/dist/patterns/filter-bar/types.d.ts.map +1 -0
  94. package/dist/patterns/filter-bar/types.js +2 -0
  95. package/dist/patterns/filter-bar/types.js.map +1 -0
  96. package/package.json +1 -1
  97. package/src/components/avatar/Avatar.tsx +133 -0
  98. package/src/components/avatar/index.ts +3 -0
  99. package/src/components/avatar/resolveAvatarInitials.test.ts +27 -0
  100. package/src/components/avatar/resolveAvatarInitials.ts +46 -0
  101. package/src/components/avatar/types.ts +20 -0
  102. package/src/components/avatar-group/AvatarGroup.tsx +74 -0
  103. package/src/components/avatar-group/index.ts +2 -0
  104. package/src/components/avatar-group/types.ts +24 -0
  105. package/src/components/chip/Chip.tsx +95 -0
  106. package/src/components/chip/index.ts +2 -0
  107. package/src/components/chip/resolveChipColors.ts +65 -0
  108. package/src/components/chip/types.ts +29 -0
  109. package/src/components/chip-group/ChipGroup.tsx +66 -0
  110. package/src/components/chip-group/index.ts +2 -0
  111. package/src/components/chip-group/types.ts +36 -0
  112. package/src/components/input/Input.tsx +17 -1
  113. package/src/components/input/index.ts +1 -1
  114. package/src/components/input/types.ts +19 -2
  115. package/src/components/search-bar/SearchBar.tsx +50 -0
  116. package/src/components/search-bar/index.ts +2 -0
  117. package/src/components/search-bar/types.ts +14 -0
  118. package/src/index.ts +13 -1
  119. package/src/patterns/filter-bar/FilterBar.tsx +25 -0
  120. package/src/patterns/filter-bar/index.ts +2 -0
  121. package/src/patterns/filter-bar/types.ts +10 -0
  122. package/src/showcaseCoverage.test.ts +6 -0
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["export type { BadgeProps } from './components/badge';\nexport { Badge } from './components/badge';\nexport type { ButtonProps } from './components/button';\nexport { Button } from './components/button';\nexport type { CardProps } from './components/card';\nexport { Card } from './components/card';\nexport type { CheckboxGroupOption, CheckboxGroupProps, CheckboxProps } from './components/checkbox';\nexport { Checkbox, CheckboxGroup } from './components/checkbox';\nexport type { DrawerProps } from './components/drawer';\nexport { Drawer } from './components/drawer';\nexport type {\n FormActionsProps,\n FormErrorProps,\n FormErrors,\n FormFieldConfig,\n FormFieldControlProps,\n FormFieldInputType,\n FormFieldProps,\n FormFieldValue,\n FormFieldWrapperProps,\n FormProps,\n FormValidationErrors,\n FormValidationResult,\n FormValues,\n UseFormControllerOptions,\n UseFormControllerResult,\n ValidationRule,\n} from './components/form';\nexport {\n Form,\n FormActions,\n FormError,\n FormField,\n hasRequiredRule,\n useFormController,\n validateField,\n validateFields,\n validateValue,\n} from './components/form';\nexport type {\n HeadingAlign,\n HeadingLevel,\n HeadingProps,\n HeadingSize,\n HeadingTone,\n HeadingWeight,\n} from './components/heading';\nexport { Heading } from './components/heading';\nexport type { IconProps } from './components/icon';\nexport { Icon } from './components/icon';\nexport type { IconButtonProps } from './components/icon-button';\nexport { IconButton } from './components/icon-button';\nexport type { InputProps } from './components/input';\nexport { Input } from './components/input';\nexport type { ModalProps } from './components/modal';\nexport { Modal } from './components/modal';\nexport type { RadioGroupOption, RadioGroupProps, RadioProps } from './components/radio';\nexport { Radio, RadioGroup } from './components/radio';\nexport type { SelectOption, SelectProps } from './components/select';\nexport { Select } from './components/select';\nexport type { TabItem, TabsProps } from './components/tabs';\nexport { Tabs } from './components/tabs';\nexport type { TextAlign, TextProps, TextTone, TextVariant, TextWeight } from './components/text';\nexport { Text } from './components/text';\nexport type { TextareaProps } from './components/textarea';\nexport { Textarea } from './components/textarea';\nexport type { ToolbarActionProps, ToolbarProps } from './components/toolbar';\nexport { Toolbar, ToolbarAction } from './components/toolbar';\nexport type {\n BoxProps,\n CenterProps,\n ContainerProps,\n DividerProps,\n GridProps,\n InlineProps,\n ShowProps,\n SpacerProps,\n StackProps,\n SurfaceProps,\n SurfaceVariant,\n} from './foundation';\nexport {\n Box,\n Center,\n Container,\n Divider,\n Grid,\n Inline,\n Show,\n Spacer,\n Stack,\n Surface,\n} from './foundation';\nexport type { AppShellProps } from './layout/app-shell';\nexport { AppShell } from './layout/app-shell';\nexport type { AuthLayoutProps } from './layout/auth-layout';\nexport { AuthLayout } from './layout/auth-layout';\nexport type { PageProps } from './layout/page';\nexport { Page } from './layout/page';\nexport type { PageHeaderProps } from './layout/page-header';\nexport { PageHeader } from './layout/page-header';\nexport type { PageSectionProps } from './layout/page-section';\nexport { PageSection } from './layout/page-section';\nexport type { SettingsLayoutProps } from './layout/settings-layout';\nexport { SettingsLayout } from './layout/settings-layout';\nexport type { SidebarLayoutProps } from './layout/sidebar-layout';\nexport { SidebarLayout } from './layout/sidebar-layout';\nexport type { TopbarLayoutProps } from './layout/topbar-layout';\nexport { TopbarLayout } from './layout/topbar-layout';\nexport type {\n AuthFormBaseProps,\n AuthIdentifierKind,\n ForgotPasswordFormProps,\n ForgotPasswordFormValues,\n OtpFormProps,\n OtpFormValues,\n SignInFormProps,\n SignInFormValues,\n SignUpFormField,\n SignUpFormProps,\n SignUpFormValues,\n} from './patterns/auth';\nexport { ForgotPasswordForm, OtpForm, SignInForm, SignUpForm } from './patterns/auth';\nexport type {\n CollectionEditorProps,\n CollectionEditorRenderItemProps,\n} from './patterns/collection-editor';\nexport { CollectionEditor } from './patterns/collection-editor';\nexport type { ConfirmDialogProps } from './patterns/confirm-dialog';\nexport { ConfirmDialog } from './patterns/confirm-dialog';\nexport type { DisclosureSectionProps } from './patterns/disclosure-section';\nexport { DisclosureSection } from './patterns/disclosure-section';\nexport type { EmptyStateAction, EmptyStateProps } from './patterns/empty-state';\nexport { EmptyState } from './patterns/empty-state';\nexport type { InspectorFieldProps } from './patterns/inspector-field';\nexport { InspectorField } from './patterns/inspector-field';\nexport type { NoticeProps } from './patterns/notice';\nexport { Notice } from './patterns/notice';\nexport type { PanelProps } from './patterns/panel';\nexport { Panel } from './patterns/panel';\nexport type { ResponsivePanelProps } from './patterns/responsive-panel';\nexport { ResponsivePanel } from './patterns/responsive-panel';\nexport type { SectionHeaderProps } from './patterns/section-header';\nexport { SectionHeader } from './patterns/section-header';\nexport type { SettingsRowProps } from './patterns/settings-row';\nexport { SettingsRow } from './patterns/settings-row';\nexport type { SwitchFieldProps } from './patterns/switch-field';\nexport { SwitchField } from './patterns/switch-field';\nexport type { ThemeComposerProps } from './patterns/theme-composer';\nexport { ThemeComposer } from './patterns/theme-composer';\nexport type { PaletteItemProps, TileGridProps } from './patterns/tile-grid';\nexport { PaletteItem, TileGrid } from './patterns/tile-grid';\nexport type { TreeItemNode, TreeItemRenderProps, TreeViewProps } from './patterns/tree-view';\nexport { TreeItem, TreeView } from './patterns/tree-view';\nexport * from './theme';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["export type { AvatarProps, AvatarShape, AvatarSize } from './components/avatar';\nexport { Avatar, resolveAvatarInitials } from './components/avatar';\nexport type { AvatarGroupItem, AvatarGroupProps } from './components/avatar-group';\nexport { AvatarGroup } from './components/avatar-group';\nexport type { BadgeProps } from './components/badge';\nexport { Badge } from './components/badge';\nexport type { ButtonProps } from './components/button';\nexport { Button } from './components/button';\nexport type { CardProps } from './components/card';\nexport { Card } from './components/card';\nexport type { CheckboxGroupOption, CheckboxGroupProps, CheckboxProps } from './components/checkbox';\nexport { Checkbox, CheckboxGroup } from './components/checkbox';\nexport type { ChipProps } from './components/chip';\nexport { Chip } from './components/chip';\nexport type { ChipGroupItem, ChipGroupProps } from './components/chip-group';\nexport { ChipGroup } from './components/chip-group';\nexport type { DrawerProps } from './components/drawer';\nexport { Drawer } from './components/drawer';\nexport type {\n FormActionsProps,\n FormErrorProps,\n FormErrors,\n FormFieldConfig,\n FormFieldControlProps,\n FormFieldInputType,\n FormFieldProps,\n FormFieldValue,\n FormFieldWrapperProps,\n FormProps,\n FormValidationErrors,\n FormValidationResult,\n FormValues,\n UseFormControllerOptions,\n UseFormControllerResult,\n ValidationRule,\n} from './components/form';\nexport {\n Form,\n FormActions,\n FormError,\n FormField,\n hasRequiredRule,\n useFormController,\n validateField,\n validateFields,\n validateValue,\n} from './components/form';\nexport type {\n HeadingAlign,\n HeadingLevel,\n HeadingProps,\n HeadingSize,\n HeadingTone,\n HeadingWeight,\n} from './components/heading';\nexport { Heading } from './components/heading';\nexport type { IconProps } from './components/icon';\nexport { Icon } from './components/icon';\nexport type { IconButtonProps } from './components/icon-button';\nexport { IconButton } from './components/icon-button';\nexport type { InputProps, InputTrailingAction } from './components/input';\nexport { Input } from './components/input';\nexport type { ModalProps } from './components/modal';\nexport { Modal } from './components/modal';\nexport type { RadioGroupOption, RadioGroupProps, RadioProps } from './components/radio';\nexport { Radio, RadioGroup } from './components/radio';\nexport type { SearchBarProps } from './components/search-bar';\nexport { SearchBar } from './components/search-bar';\nexport type { SelectOption, SelectProps } from './components/select';\nexport { Select } from './components/select';\nexport type { TabItem, TabsProps } from './components/tabs';\nexport { Tabs } from './components/tabs';\nexport type { TextAlign, TextProps, TextTone, TextVariant, TextWeight } from './components/text';\nexport { Text } from './components/text';\nexport type { TextareaProps } from './components/textarea';\nexport { Textarea } from './components/textarea';\nexport type { ToolbarActionProps, ToolbarProps } from './components/toolbar';\nexport { Toolbar, ToolbarAction } from './components/toolbar';\nexport type {\n BoxProps,\n CenterProps,\n ContainerProps,\n DividerProps,\n GridProps,\n InlineProps,\n ShowProps,\n SpacerProps,\n StackProps,\n SurfaceProps,\n SurfaceVariant,\n} from './foundation';\nexport {\n Box,\n Center,\n Container,\n Divider,\n Grid,\n Inline,\n Show,\n Spacer,\n Stack,\n Surface,\n} from './foundation';\nexport type { AppShellProps } from './layout/app-shell';\nexport { AppShell } from './layout/app-shell';\nexport type { AuthLayoutProps } from './layout/auth-layout';\nexport { AuthLayout } from './layout/auth-layout';\nexport type { PageProps } from './layout/page';\nexport { Page } from './layout/page';\nexport type { PageHeaderProps } from './layout/page-header';\nexport { PageHeader } from './layout/page-header';\nexport type { PageSectionProps } from './layout/page-section';\nexport { PageSection } from './layout/page-section';\nexport type { SettingsLayoutProps } from './layout/settings-layout';\nexport { SettingsLayout } from './layout/settings-layout';\nexport type { SidebarLayoutProps } from './layout/sidebar-layout';\nexport { SidebarLayout } from './layout/sidebar-layout';\nexport type { TopbarLayoutProps } from './layout/topbar-layout';\nexport { TopbarLayout } from './layout/topbar-layout';\nexport type {\n AuthFormBaseProps,\n AuthIdentifierKind,\n ForgotPasswordFormProps,\n ForgotPasswordFormValues,\n OtpFormProps,\n OtpFormValues,\n SignInFormProps,\n SignInFormValues,\n SignUpFormField,\n SignUpFormProps,\n SignUpFormValues,\n} from './patterns/auth';\nexport { ForgotPasswordForm, OtpForm, SignInForm, SignUpForm } from './patterns/auth';\nexport type {\n CollectionEditorProps,\n CollectionEditorRenderItemProps,\n} from './patterns/collection-editor';\nexport { CollectionEditor } from './patterns/collection-editor';\nexport type { ConfirmDialogProps } from './patterns/confirm-dialog';\nexport { ConfirmDialog } from './patterns/confirm-dialog';\nexport type { DisclosureSectionProps } from './patterns/disclosure-section';\nexport { DisclosureSection } from './patterns/disclosure-section';\nexport type { EmptyStateAction, EmptyStateProps } from './patterns/empty-state';\nexport { EmptyState } from './patterns/empty-state';\nexport type { FilterBarProps } from './patterns/filter-bar';\nexport { FilterBar } from './patterns/filter-bar';\nexport type { InspectorFieldProps } from './patterns/inspector-field';\nexport { InspectorField } from './patterns/inspector-field';\nexport type { NoticeProps } from './patterns/notice';\nexport { Notice } from './patterns/notice';\nexport type { PanelProps } from './patterns/panel';\nexport { Panel } from './patterns/panel';\nexport type { ResponsivePanelProps } from './patterns/responsive-panel';\nexport { ResponsivePanel } from './patterns/responsive-panel';\nexport type { SectionHeaderProps } from './patterns/section-header';\nexport { SectionHeader } from './patterns/section-header';\nexport type { SettingsRowProps } from './patterns/settings-row';\nexport { SettingsRow } from './patterns/settings-row';\nexport type { SwitchFieldProps } from './patterns/switch-field';\nexport { SwitchField } from './patterns/switch-field';\nexport type { ThemeComposerProps } from './patterns/theme-composer';\nexport { ThemeComposer } from './patterns/theme-composer';\nexport type { PaletteItemProps, TileGridProps } from './patterns/tile-grid';\nexport { PaletteItem, TileGrid } from './patterns/tile-grid';\nexport type { TreeItemNode, TreeItemRenderProps, TreeViewProps } from './patterns/tree-view';\nexport { TreeItem, TreeView } from './patterns/tree-view';\nexport * from './theme';\n"]}
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import type { FilterBarProps } from './types';
3
+ export declare const FilterBar: (props: FilterBarProps) => React.ReactElement | null;
4
+ //# sourceMappingURL=FilterBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FilterBar.d.ts","sourceRoot":"","sources":["../../../src/patterns/filter-bar/FilterBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAoB9C,eAAO,MAAM,SAAS,sDAAqC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { Box, Inline } from '../../foundation';
3
+ import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
4
+ function FilterBarInner({ themeId: _themeId, mode: _mode, testID, leading, trailing, children, wrap = true, }) {
5
+ return (<Inline align="center" gap="s" testID={testID} wrap={wrap ? 'wrap' : 'nowrap'}>
6
+ {leading ? <Box>{leading}</Box> : null}
7
+ <Box flex={1}>{children}</Box>
8
+ {trailing ? <Box>{trailing}</Box> : null}
9
+ </Inline>);
10
+ }
11
+ export const FilterBar = withZoraThemeScope(FilterBarInner);
12
+ //# sourceMappingURL=FilterBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FilterBar.js","sourceRoot":"","sources":["../../../src/patterns/filter-bar/FilterBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAGpE,SAAS,cAAc,CAAC,EACtB,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,KAAK,EACX,MAAM,EACN,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,IAAI,GAAG,IAAI,GACI;IACf,OAAO,CACL,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAC5E;MAAA,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CACtC;MAAA,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,GAAG,CAC7B;MAAA,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAC1C;IAAA,EAAE,MAAM,CAAC,CACV,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC","sourcesContent":["import React from 'react';\n\nimport { Box, Inline } from '../../foundation';\nimport { withZoraThemeScope } from '../../theme/withZoraThemeScope';\nimport type { FilterBarProps } from './types';\n\nfunction FilterBarInner({\n themeId: _themeId,\n mode: _mode,\n testID,\n leading,\n trailing,\n children,\n wrap = true,\n}: FilterBarProps) {\n return (\n <Inline align=\"center\" gap=\"s\" testID={testID} wrap={wrap ? 'wrap' : 'nowrap'}>\n {leading ? <Box>{leading}</Box> : null}\n <Box flex={1}>{children}</Box>\n {trailing ? <Box>{trailing}</Box> : null}\n </Inline>\n );\n}\n\nexport const FilterBar = withZoraThemeScope(FilterBarInner);\n"]}
@@ -0,0 +1,3 @@
1
+ export { FilterBar } from './FilterBar';
2
+ export type { FilterBarProps } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/patterns/filter-bar/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { FilterBar } from './FilterBar';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/patterns/filter-bar/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC","sourcesContent":["export { FilterBar } from './FilterBar';\nexport type { FilterBarProps } from './types';\n"]}
@@ -0,0 +1,9 @@
1
+ import type React from 'react';
2
+ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
3
+ export interface FilterBarProps extends ZoraBaseProps {
4
+ leading?: React.ReactNode;
5
+ trailing?: React.ReactNode;
6
+ children: React.ReactNode;
7
+ wrap?: boolean;
8
+ }
9
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/patterns/filter-bar/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/patterns/filter-bar/types.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nimport type { ZoraBaseProps } from '../../theme/ZoraBaseProps';\n\nexport interface FilterBarProps extends ZoraBaseProps {\n leading?: React.ReactNode;\n trailing?: React.ReactNode;\n children: React.ReactNode;\n wrap?: 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",
4
+ "version": "1.0.5",
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,133 @@
1
+ import type { RoleSemantics, SurfaceTheme } from '@ankhorage/surface';
2
+ import React from 'react';
3
+ import { Image } from 'react-native';
4
+
5
+ import { Box } from '../../foundation';
6
+ import type { ZoraTone } from '../../internal/recipes';
7
+ import { useZoraTheme } from '../../theme/useZoraTheme';
8
+ import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
9
+ import { Icon } from '../icon';
10
+ import { Text, type TextTone, type TextVariant } from '../text';
11
+ import { resolveAvatarInitials } from './resolveAvatarInitials';
12
+ import type { AvatarProps, AvatarShape, AvatarSize } from './types';
13
+
14
+ const AVATAR_SIZES: Record<AvatarSize, number> = {
15
+ xs: 24,
16
+ s: 32,
17
+ m: 40,
18
+ l: 48,
19
+ xl: 64,
20
+ };
21
+
22
+ function resolveRoleSemantics(theme: SurfaceTheme, tone: ZoraTone): RoleSemantics {
23
+ switch (tone) {
24
+ case 'primary':
25
+ return theme.semantics.action.primary;
26
+ case 'danger':
27
+ return theme.semantics.action.danger;
28
+ case 'success':
29
+ return theme.semantics.success;
30
+ case 'warning':
31
+ return theme.semantics.warning;
32
+ case 'neutral':
33
+ default:
34
+ return theme.semantics.action.neutral;
35
+ }
36
+ }
37
+
38
+ function resolveTextTone(tone: ZoraTone): TextTone {
39
+ return tone === 'neutral' ? 'default' : tone;
40
+ }
41
+
42
+ function resolveTextVariant(size: AvatarSize): TextVariant {
43
+ switch (size) {
44
+ case 'xs':
45
+ case 's':
46
+ return 'caption';
47
+ case 'l':
48
+ return 'bodySmall';
49
+ case 'xl':
50
+ return 'lead';
51
+ case 'm':
52
+ default:
53
+ return 'label';
54
+ }
55
+ }
56
+
57
+ function resolveRadius(shape: AvatarShape): 'full' | 'l' {
58
+ return shape === 'circle' ? 'full' : 'l';
59
+ }
60
+
61
+ function AvatarInner({
62
+ themeId: _themeId,
63
+ mode: _mode,
64
+ testID,
65
+ source,
66
+ name,
67
+ initials,
68
+ iconFallback,
69
+ label,
70
+ size = 'm',
71
+ shape = 'circle',
72
+ tone = 'neutral',
73
+ }: AvatarProps) {
74
+ const { theme } = useZoraTheme();
75
+ const resolvedSize = AVATAR_SIZES[size];
76
+ const resolvedInitials = initials ?? resolveAvatarInitials(name);
77
+ const role = resolveRoleSemantics(theme, tone);
78
+ const backgroundColor = tone === 'neutral' ? theme.semantics.neutral.surface : role.softBg;
79
+ const contentColor = tone === 'neutral' ? theme.semantics.content.default : role.base;
80
+ const radius = resolveRadius(shape);
81
+
82
+ const renderFallback = () => {
83
+ if (resolvedInitials) {
84
+ return (
85
+ <Text tone={resolveTextTone(tone)} variant={resolveTextVariant(size)} weight="semiBold">
86
+ {resolvedInitials}
87
+ </Text>
88
+ );
89
+ }
90
+
91
+ if (iconFallback) {
92
+ const iconSize = Math.max(16, Math.round(resolvedSize * 0.48));
93
+ return (
94
+ <Icon
95
+ color={contentColor}
96
+ name={iconFallback.name}
97
+ provider={iconFallback.provider}
98
+ size={iconSize}
99
+ />
100
+ );
101
+ }
102
+
103
+ return null;
104
+ };
105
+
106
+ return (
107
+ <Box
108
+ accessibilityLabel={label}
109
+ bg={backgroundColor}
110
+ height={resolvedSize}
111
+ radius={radius}
112
+ testID={testID}
113
+ width={resolvedSize}
114
+ style={{
115
+ alignItems: 'center',
116
+ justifyContent: 'center',
117
+ overflow: 'hidden',
118
+ }}
119
+ >
120
+ {source ? (
121
+ <Image
122
+ accessibilityLabel={label}
123
+ source={source}
124
+ style={{ height: '100%', width: '100%' }}
125
+ />
126
+ ) : (
127
+ renderFallback()
128
+ )}
129
+ </Box>
130
+ );
131
+ }
132
+
133
+ export const Avatar = withZoraThemeScope(AvatarInner);
@@ -0,0 +1,3 @@
1
+ export { Avatar } from './Avatar';
2
+ export { resolveAvatarInitials } from './resolveAvatarInitials';
3
+ export type { AvatarProps, AvatarShape, AvatarSize } from './types';
@@ -0,0 +1,27 @@
1
+ import { describe, expect, it } from 'bun:test';
2
+
3
+ import { resolveAvatarInitials } from './resolveAvatarInitials';
4
+
5
+ describe('resolveAvatarInitials', () => {
6
+ it('returns null for empty input', () => {
7
+ expect(resolveAvatarInitials(undefined)).toBeNull();
8
+ expect(resolveAvatarInitials('')).toBeNull();
9
+ expect(resolveAvatarInitials(' ')).toBeNull();
10
+ });
11
+
12
+ it('returns the first two characters for a single word', () => {
13
+ expect(resolveAvatarInitials('Zora')).toBe('ZO');
14
+ expect(resolveAvatarInitials('a')).toBe('A');
15
+ });
16
+
17
+ it('returns first+last initials for multiple words', () => {
18
+ expect(resolveAvatarInitials('Fabio Gartenmann')).toBe('FG');
19
+ expect(resolveAvatarInitials('Fabio Gartenmann')).toBe('FG');
20
+ expect(resolveAvatarInitials('Fabio Gartenmann Example')).toBe('FE');
21
+ });
22
+
23
+ it('handles non-letter characters', () => {
24
+ expect(resolveAvatarInitials('🧠 Brain')).toBe('🧠B');
25
+ expect(resolveAvatarInitials('Brain 🧠')).toBe('B🧠');
26
+ });
27
+ });
@@ -0,0 +1,46 @@
1
+ function takeFirstCharacter(value: string): string | null {
2
+ const trimmed = value.trim();
3
+ if (!trimmed) return null;
4
+
5
+ const chars = Array.from(trimmed);
6
+ return chars[0] ? chars[0].toUpperCase() : null;
7
+ }
8
+
9
+ function takeFirstTwoCharacters(value: string): string | null {
10
+ const trimmed = value.trim();
11
+ if (!trimmed) return null;
12
+
13
+ const chars = Array.from(trimmed);
14
+ const [first, second] = chars;
15
+ if (!first) return null;
16
+
17
+ return `${first}${second ?? ''}`.toUpperCase();
18
+ }
19
+
20
+ export function resolveAvatarInitials(name: string | undefined): string | null {
21
+ if (!name) return null;
22
+
23
+ const parts = name
24
+ .trim()
25
+ .split(/\s+/)
26
+ .map((part) => part.trim())
27
+ .filter(Boolean);
28
+
29
+ if (parts.length === 0) return null;
30
+
31
+ if (parts.length === 1) {
32
+ const [part] = parts;
33
+ return part ? takeFirstTwoCharacters(part) : null;
34
+ }
35
+
36
+ const [firstPart] = parts;
37
+ const [lastPart] = parts.slice(-1);
38
+ const first = firstPart ? takeFirstCharacter(firstPart) : null;
39
+ const last = lastPart ? takeFirstCharacter(lastPart) : null;
40
+
41
+ if (!first && !last) return null;
42
+ if (!last) return first;
43
+ if (!first) return last;
44
+
45
+ return `${first}${last}`;
46
+ }
@@ -0,0 +1,20 @@
1
+ import type { ButtonIconSpec } from '@ankhorage/surface';
2
+ import type { ImageSourcePropType } from 'react-native';
3
+
4
+ import type { ZoraTone } from '../../internal/recipes';
5
+ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
6
+
7
+ export type AvatarSize = 'xs' | 's' | 'm' | 'l' | 'xl';
8
+
9
+ export type AvatarShape = 'circle' | 'rounded';
10
+
11
+ export interface AvatarProps extends ZoraBaseProps {
12
+ source?: ImageSourcePropType;
13
+ name?: string;
14
+ initials?: string;
15
+ iconFallback?: ButtonIconSpec;
16
+ label?: string;
17
+ size?: AvatarSize;
18
+ shape?: AvatarShape;
19
+ tone?: ZoraTone;
20
+ }
@@ -0,0 +1,74 @@
1
+ import React from 'react';
2
+
3
+ import { Box, Stack } from '../../foundation';
4
+ import { useZoraTheme } from '../../theme/useZoraTheme';
5
+ import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
6
+ import { Avatar } from '../avatar';
7
+ import type { AvatarGroupItem, AvatarGroupProps } from './types';
8
+
9
+ function defaultOverflowLabel(overflowCount: number): string {
10
+ return `+${overflowCount}`;
11
+ }
12
+
13
+ function AvatarGroupInner({
14
+ themeId: _themeId,
15
+ mode: _mode,
16
+ testID,
17
+ items,
18
+ max = 4,
19
+ size = 's',
20
+ shape = 'circle',
21
+ overflowLabel = defaultOverflowLabel,
22
+ }: AvatarGroupProps) {
23
+ const { theme } = useZoraTheme();
24
+
25
+ const visibleItems = items.slice(0, max);
26
+ const overflowCount = Math.max(0, items.length - visibleItems.length);
27
+ const overlap =
28
+ size === 'xs' ? 8 : size === 's' ? 10 : size === 'm' ? 12 : size === 'l' ? 14 : 16;
29
+ const borderColor = theme.semantics.surface.default;
30
+
31
+ const renderItem = (item: AvatarGroupItem, index: number) => (
32
+ <Box
33
+ key={item.id ?? `${index}`}
34
+ ml={index === 0 ? 0 : -overlap}
35
+ radius="full"
36
+ borderWidth={2}
37
+ borderColor={borderColor}
38
+ >
39
+ <Avatar
40
+ iconFallback={item.iconFallback}
41
+ initials={item.initials}
42
+ label={item.label}
43
+ name={item.name}
44
+ shape={shape}
45
+ size={size}
46
+ source={item.source}
47
+ tone={item.tone}
48
+ />
49
+ </Box>
50
+ );
51
+
52
+ return (
53
+ <Stack align="center" direction="row" testID={testID} wrap="nowrap">
54
+ {visibleItems.map(renderItem)}
55
+ {overflowCount > 0 ? (
56
+ <Box
57
+ ml={visibleItems.length === 0 ? 0 : -overlap}
58
+ radius="full"
59
+ borderWidth={2}
60
+ borderColor={borderColor}
61
+ >
62
+ <Avatar
63
+ initials={overflowLabel(overflowCount)}
64
+ size={size}
65
+ shape={shape}
66
+ tone="neutral"
67
+ />
68
+ </Box>
69
+ ) : null}
70
+ </Stack>
71
+ );
72
+ }
73
+
74
+ export const AvatarGroup = withZoraThemeScope(AvatarGroupInner);
@@ -0,0 +1,2 @@
1
+ export { AvatarGroup } from './AvatarGroup';
2
+ export type { AvatarGroupItem, AvatarGroupProps } from './types';
@@ -0,0 +1,24 @@
1
+ import type { ButtonIconSpec } from '@ankhorage/surface';
2
+ import type { ImageSourcePropType } from 'react-native';
3
+
4
+ import type { ZoraTone } from '../../internal/recipes';
5
+ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
6
+ import type { AvatarShape, AvatarSize } from '../avatar';
7
+
8
+ export interface AvatarGroupItem {
9
+ id?: string;
10
+ source?: ImageSourcePropType;
11
+ name?: string;
12
+ initials?: string;
13
+ iconFallback?: ButtonIconSpec;
14
+ label?: string;
15
+ tone?: ZoraTone;
16
+ }
17
+
18
+ export interface AvatarGroupProps extends ZoraBaseProps {
19
+ items: readonly AvatarGroupItem[];
20
+ max?: number;
21
+ size?: AvatarSize;
22
+ shape?: AvatarShape;
23
+ overflowLabel?: (overflowCount: number) => string;
24
+ }
@@ -0,0 +1,95 @@
1
+ import { ButtonBase } from '@ankhorage/surface';
2
+ import React from 'react';
3
+
4
+ import { Box, Inline } from '../../foundation';
5
+ import { resolveIconSize } from '../../internal/recipes';
6
+ import { useZoraTheme } from '../../theme/useZoraTheme';
7
+ import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
8
+ import { Icon } from '../icon';
9
+ import { Text } from '../text';
10
+ import { resolveChipColors } from './resolveChipColors';
11
+ import type { ChipInteractionState, ChipProps } from './types';
12
+
13
+ function resolveChipPadding(size: NonNullable<ChipProps['size']>): {
14
+ px: 's' | 'm';
15
+ py: 'xxs' | 'xs';
16
+ } {
17
+ switch (size) {
18
+ case 's':
19
+ return { px: 's', py: 'xxs' };
20
+ case 'm':
21
+ return { px: 'm', py: 'xs' };
22
+ case 'l':
23
+ default:
24
+ return { px: 'm', py: 'xs' };
25
+ }
26
+ }
27
+
28
+ function ChipInner({
29
+ themeId: _themeId,
30
+ mode: _mode,
31
+ testID,
32
+ children,
33
+ icon,
34
+ selected = false,
35
+ disabled = false,
36
+ tone = 'neutral',
37
+ size = 's',
38
+ onPress,
39
+ }: ChipProps) {
40
+ const { theme } = useZoraTheme();
41
+ const padding = resolveChipPadding(size);
42
+ const iconSize = resolveIconSize(size);
43
+
44
+ const renderContent = (state: ChipInteractionState) => {
45
+ const colors = resolveChipColors({ theme, tone, selected, state });
46
+ const textTone = state.disabled
47
+ ? 'muted'
48
+ : selected
49
+ ? tone === 'neutral'
50
+ ? 'default'
51
+ : tone
52
+ : 'default';
53
+
54
+ return (
55
+ <Box
56
+ bg={colors.backgroundColor}
57
+ borderColor={colors.borderColor}
58
+ borderWidth={1}
59
+ px={padding.px}
60
+ py={padding.py}
61
+ radius="full"
62
+ style={{
63
+ alignSelf: 'flex-start',
64
+ opacity: colors.opacity,
65
+ }}
66
+ >
67
+ <Inline align="center" gap="xs" wrap="nowrap">
68
+ {icon ? (
69
+ <Icon
70
+ color={colors.contentColor}
71
+ name={icon.name}
72
+ provider={icon.provider}
73
+ size={iconSize}
74
+ />
75
+ ) : null}
76
+ <Text tone={textTone} variant="label">
77
+ {children}
78
+ </Text>
79
+ </Inline>
80
+ </Box>
81
+ );
82
+ };
83
+
84
+ if (!onPress) {
85
+ return renderContent({ disabled, focused: false, hovered: false, pressed: false });
86
+ }
87
+
88
+ return (
89
+ <ButtonBase disabled={disabled} onPress={onPress} radius="full" testID={testID}>
90
+ {(state) => renderContent(state)}
91
+ </ButtonBase>
92
+ );
93
+ }
94
+
95
+ export const Chip = withZoraThemeScope(ChipInner);
@@ -0,0 +1,2 @@
1
+ export { Chip } from './Chip';
2
+ export type { ChipProps } from './types';
@@ -0,0 +1,65 @@
1
+ import type { RoleSemantics, SurfaceTheme } from '@ankhorage/surface';
2
+
3
+ import type { ZoraTone } from '../../internal/recipes';
4
+ import type { ChipColors, ChipInteractionState } from './types';
5
+
6
+ function resolveChipRole(theme: SurfaceTheme, tone: ZoraTone): RoleSemantics {
7
+ switch (tone) {
8
+ case 'primary':
9
+ return theme.semantics.action.primary;
10
+ case 'danger':
11
+ return theme.semantics.action.danger;
12
+ case 'success':
13
+ return theme.semantics.success;
14
+ case 'warning':
15
+ return theme.semantics.warning;
16
+ case 'neutral':
17
+ default:
18
+ return theme.semantics.action.neutral;
19
+ }
20
+ }
21
+
22
+ export function resolveChipColors({
23
+ theme,
24
+ tone,
25
+ selected,
26
+ state,
27
+ }: {
28
+ theme: SurfaceTheme;
29
+ tone: ZoraTone;
30
+ selected: boolean;
31
+ state: ChipInteractionState;
32
+ }): ChipColors {
33
+ if (state.disabled) {
34
+ return {
35
+ backgroundColor: theme.semantics.neutral.surface,
36
+ borderColor: theme.semantics.neutral.divider,
37
+ contentColor: theme.semantics.content.muted,
38
+ opacity: 0.72,
39
+ };
40
+ }
41
+
42
+ const role = resolveChipRole(theme, tone);
43
+
44
+ if (selected) {
45
+ return {
46
+ backgroundColor: state.pressed
47
+ ? role.softActive
48
+ : state.hovered
49
+ ? role.softHover
50
+ : role.softBg,
51
+ borderColor: 'transparent',
52
+ contentColor: role.base,
53
+ };
54
+ }
55
+
56
+ return {
57
+ backgroundColor: state.pressed
58
+ ? theme.semantics.neutral.surfaceActive
59
+ : state.hovered
60
+ ? theme.semantics.neutral.surfaceHover
61
+ : theme.semantics.neutral.surface,
62
+ borderColor: theme.semantics.neutral.divider,
63
+ contentColor: theme.semantics.content.default,
64
+ };
65
+ }
@@ -0,0 +1,29 @@
1
+ import type { ButtonIconSpec } from '@ankhorage/surface';
2
+ import type React from 'react';
3
+
4
+ import type { ZoraControlSize, ZoraTone } from '../../internal/recipes';
5
+ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
6
+
7
+ export interface ChipProps extends ZoraBaseProps {
8
+ children: React.ReactNode;
9
+ icon?: ButtonIconSpec;
10
+ selected?: boolean;
11
+ disabled?: boolean;
12
+ tone?: ZoraTone;
13
+ size?: ZoraControlSize;
14
+ onPress?: () => void;
15
+ }
16
+
17
+ export interface ChipColors {
18
+ backgroundColor: string;
19
+ borderColor: string;
20
+ contentColor: string;
21
+ opacity?: number;
22
+ }
23
+
24
+ export interface ChipInteractionState {
25
+ pressed: boolean;
26
+ hovered: boolean;
27
+ focused: boolean;
28
+ disabled: boolean;
29
+ }