@ankhorage/zora 1.0.3 → 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 +12 -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 +3 -3
  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
@@ -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
+ }
@@ -0,0 +1,66 @@
1
+ import React from 'react';
2
+
3
+ import { Inline } from '../../foundation';
4
+ import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
5
+ import { Chip } from '../chip';
6
+ import type { ChipGroupItem, ChipGroupProps } from './types';
7
+
8
+ function hasValue<TValue extends string>(values: readonly TValue[], value: TValue): boolean {
9
+ return values.includes(value);
10
+ }
11
+
12
+ function toggleValue<TValue extends string>(values: readonly TValue[], value: TValue): TValue[] {
13
+ return hasValue(values, value) ? values.filter((item) => item !== value) : [...values, value];
14
+ }
15
+
16
+ function ChipGroupInner<TValue extends string = string>({
17
+ themeId: _themeId,
18
+ mode: _mode,
19
+ testID,
20
+ items,
21
+ value,
22
+ onValueChange,
23
+ multiple,
24
+ tone = 'neutral',
25
+ size = 's',
26
+ wrap = true,
27
+ disabled,
28
+ }: ChipGroupProps<TValue>) {
29
+ const renderChip = (item: ChipGroupItem<TValue>) => {
30
+ const itemDisabled = disabled ?? item.disabled ?? false;
31
+ const isSelected = Array.isArray(value) ? hasValue(value, item.value) : value === item.value;
32
+
33
+ const handlePress = () => {
34
+ if (multiple) {
35
+ const next = toggleValue(value, item.value);
36
+ onValueChange(next);
37
+ return;
38
+ }
39
+
40
+ onValueChange(item.value);
41
+ };
42
+
43
+ return (
44
+ <Chip
45
+ key={item.value}
46
+ disabled={itemDisabled}
47
+ icon={item.icon}
48
+ onPress={handlePress}
49
+ selected={isSelected}
50
+ size={size}
51
+ testID={item.testID}
52
+ tone={tone}
53
+ >
54
+ {item.label}
55
+ </Chip>
56
+ );
57
+ };
58
+
59
+ return (
60
+ <Inline align="center" gap="s" testID={testID} wrap={wrap ? 'wrap' : 'nowrap'}>
61
+ {items.map(renderChip)}
62
+ </Inline>
63
+ );
64
+ }
65
+
66
+ export const ChipGroup = withZoraThemeScope(ChipGroupInner);
@@ -0,0 +1,2 @@
1
+ export { ChipGroup } from './ChipGroup';
2
+ export type { ChipGroupItem, ChipGroupProps } from './types';
@@ -0,0 +1,36 @@
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 ChipGroupItem<TValue extends string = string> {
8
+ value: TValue;
9
+ label: React.ReactNode;
10
+ icon?: ButtonIconSpec;
11
+ disabled?: boolean;
12
+ testID?: string;
13
+ }
14
+
15
+ interface ChipGroupBaseProps<TValue extends string> extends ZoraBaseProps {
16
+ items: readonly ChipGroupItem<TValue>[];
17
+ tone?: ZoraTone;
18
+ size?: ZoraControlSize;
19
+ wrap?: boolean;
20
+ disabled?: boolean;
21
+ }
22
+
23
+ interface ChipGroupSingleProps<TValue extends string> {
24
+ multiple?: false;
25
+ value: TValue;
26
+ onValueChange: (value: TValue) => void;
27
+ }
28
+
29
+ interface ChipGroupMultipleProps<TValue extends string> {
30
+ multiple: true;
31
+ value: readonly TValue[];
32
+ onValueChange: (value: TValue[]) => void;
33
+ }
34
+
35
+ export type ChipGroupProps<TValue extends string = string> = ChipGroupBaseProps<TValue> &
36
+ (ChipGroupSingleProps<TValue> | ChipGroupMultipleProps<TValue>);
@@ -4,6 +4,7 @@ import React from 'react';
4
4
  import { resolveIconSize } from '../../internal/recipes';
5
5
  import { useZoraTheme } from '../../theme/useZoraTheme';
6
6
  import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
7
+ import { IconButton } from '../icon-button';
7
8
  import type { InputProps } from './types';
8
9
 
9
10
  function InputInner({
@@ -12,6 +13,9 @@ function InputInner({
12
13
  size = 'l',
13
14
  leadingIcon,
14
15
  trailingIcon,
16
+ trailingAction,
17
+ disabled,
18
+ readOnly,
15
19
  ...props
16
20
  }: InputProps) {
17
21
  const { theme } = useZoraTheme();
@@ -21,6 +25,7 @@ function InputInner({
21
25
  return (
22
26
  <Surface.TextInput
23
27
  {...props}
28
+ disabled={disabled}
24
29
  leadingAccessory={
25
30
  leadingIcon ? (
26
31
  <Surface.Icon
@@ -31,9 +36,20 @@ function InputInner({
31
36
  />
32
37
  ) : undefined
33
38
  }
39
+ readOnly={readOnly}
34
40
  size={size}
35
41
  trailingAccessory={
36
- trailingIcon ? (
42
+ trailingAction ? (
43
+ <IconButton
44
+ icon={trailingAction.icon}
45
+ label={trailingAction.label}
46
+ disabled={disabled ?? readOnly}
47
+ emphasis="ghost"
48
+ size={size === 'l' ? 'm' : size}
49
+ tone="neutral"
50
+ onPress={trailingAction.onPress}
51
+ />
52
+ ) : trailingIcon ? (
37
53
  <Surface.Icon
38
54
  color={iconColor}
39
55
  name={trailingIcon.name}
@@ -1,2 +1,2 @@
1
1
  export { Input } from './Input';
2
- export type { InputProps } from './types';
2
+ export type { InputProps, InputTrailingAction } from './types';
@@ -3,7 +3,23 @@ import type * as Surface from '@ankhorage/surface';
3
3
  import type { ZoraControlSize } from '../../internal/recipes';
4
4
  import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
5
5
 
6
- export interface InputProps
6
+ export interface InputTrailingAction {
7
+ icon: Surface.ButtonIconSpec;
8
+ label: string;
9
+ onPress: () => void;
10
+ }
11
+
12
+ type InputTrailingProps =
13
+ | {
14
+ trailingIcon?: Surface.ButtonIconSpec;
15
+ trailingAction?: never;
16
+ }
17
+ | {
18
+ trailingIcon?: never;
19
+ trailingAction?: InputTrailingAction;
20
+ };
21
+
22
+ export interface InputBaseProps
7
23
  extends
8
24
  ZoraBaseProps,
9
25
  Omit<
@@ -12,5 +28,6 @@ export interface InputProps
12
28
  > {
13
29
  size?: ZoraControlSize;
14
30
  leadingIcon?: Surface.ButtonIconSpec;
15
- trailingIcon?: Surface.ButtonIconSpec;
16
31
  }
32
+
33
+ export type InputProps = InputBaseProps & InputTrailingProps;
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+
3
+ import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
4
+ import { Input, type InputTrailingAction } from '../input';
5
+ import type { SearchBarProps } from './types';
6
+
7
+ function SearchBarInner({
8
+ themeId: _themeId,
9
+ mode: _mode,
10
+ testID,
11
+ value,
12
+ onValueChange,
13
+ placeholder = 'Search',
14
+ onSubmit,
15
+ onClear,
16
+ clearable = true,
17
+ size = 'l',
18
+ disabled,
19
+ readOnly,
20
+ }: SearchBarProps) {
21
+ const trailingAction: InputTrailingAction | undefined =
22
+ clearable && value.length > 0
23
+ ? {
24
+ icon: { name: 'close-circle' },
25
+ label: 'Clear search',
26
+ onPress: () => {
27
+ onValueChange('');
28
+ onClear?.();
29
+ },
30
+ }
31
+ : undefined;
32
+
33
+ return (
34
+ <Input
35
+ disabled={disabled}
36
+ leadingIcon={{ name: 'search-outline' }}
37
+ onChangeText={onValueChange}
38
+ onSubmitEditing={onSubmit ? () => onSubmit(value) : undefined}
39
+ placeholder={placeholder}
40
+ readOnly={readOnly}
41
+ returnKeyType="search"
42
+ size={size}
43
+ testID={testID}
44
+ trailingAction={trailingAction}
45
+ value={value}
46
+ />
47
+ );
48
+ }
49
+
50
+ export const SearchBar = withZoraThemeScope(SearchBarInner);
@@ -0,0 +1,2 @@
1
+ export { SearchBar } from './SearchBar';
2
+ export type { SearchBarProps } from './types';
@@ -0,0 +1,14 @@
1
+ import type { ZoraControlSize } from '../../internal/recipes';
2
+ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
3
+
4
+ export interface SearchBarProps extends ZoraBaseProps {
5
+ value: string;
6
+ onValueChange: (value: string) => void;
7
+ placeholder?: string;
8
+ onSubmit?: (value: string) => void;
9
+ onClear?: () => void;
10
+ clearable?: boolean;
11
+ size?: ZoraControlSize;
12
+ disabled?: boolean;
13
+ readOnly?: boolean;
14
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,7 @@
1
+ export type { AvatarProps, AvatarShape, AvatarSize } from './components/avatar';
2
+ export { Avatar, resolveAvatarInitials } from './components/avatar';
3
+ export type { AvatarGroupItem, AvatarGroupProps } from './components/avatar-group';
4
+ export { AvatarGroup } from './components/avatar-group';
1
5
  export type { BadgeProps } from './components/badge';
2
6
  export { Badge } from './components/badge';
3
7
  export type { ButtonProps } from './components/button';
@@ -6,6 +10,10 @@ export type { CardProps } from './components/card';
6
10
  export { Card } from './components/card';
7
11
  export type { CheckboxGroupOption, CheckboxGroupProps, CheckboxProps } from './components/checkbox';
8
12
  export { Checkbox, CheckboxGroup } from './components/checkbox';
13
+ export type { ChipProps } from './components/chip';
14
+ export { Chip } from './components/chip';
15
+ export type { ChipGroupItem, ChipGroupProps } from './components/chip-group';
16
+ export { ChipGroup } from './components/chip-group';
9
17
  export type { DrawerProps } from './components/drawer';
10
18
  export { Drawer } from './components/drawer';
11
19
  export type {
@@ -50,12 +58,14 @@ export type { IconProps } from './components/icon';
50
58
  export { Icon } from './components/icon';
51
59
  export type { IconButtonProps } from './components/icon-button';
52
60
  export { IconButton } from './components/icon-button';
53
- export type { InputProps } from './components/input';
61
+ export type { InputProps, InputTrailingAction } from './components/input';
54
62
  export { Input } from './components/input';
55
63
  export type { ModalProps } from './components/modal';
56
64
  export { Modal } from './components/modal';
57
65
  export type { RadioGroupOption, RadioGroupProps, RadioProps } from './components/radio';
58
66
  export { Radio, RadioGroup } from './components/radio';
67
+ export type { SearchBarProps } from './components/search-bar';
68
+ export { SearchBar } from './components/search-bar';
59
69
  export type { SelectOption, SelectProps } from './components/select';
60
70
  export { Select } from './components/select';
61
71
  export type { TabItem, TabsProps } from './components/tabs';
@@ -132,6 +142,8 @@ export type { DisclosureSectionProps } from './patterns/disclosure-section';
132
142
  export { DisclosureSection } from './patterns/disclosure-section';
133
143
  export type { EmptyStateAction, EmptyStateProps } from './patterns/empty-state';
134
144
  export { EmptyState } from './patterns/empty-state';
145
+ export type { FilterBarProps } from './patterns/filter-bar';
146
+ export { FilterBar } from './patterns/filter-bar';
135
147
  export type { InspectorFieldProps } from './patterns/inspector-field';
136
148
  export { InspectorField } from './patterns/inspector-field';
137
149
  export type { NoticeProps } from './patterns/notice';
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+
3
+ import { Box, Inline } from '../../foundation';
4
+ import { withZoraThemeScope } from '../../theme/withZoraThemeScope';
5
+ import type { FilterBarProps } from './types';
6
+
7
+ function FilterBarInner({
8
+ themeId: _themeId,
9
+ mode: _mode,
10
+ testID,
11
+ leading,
12
+ trailing,
13
+ children,
14
+ wrap = true,
15
+ }: FilterBarProps) {
16
+ return (
17
+ <Inline align="center" gap="s" testID={testID} wrap={wrap ? 'wrap' : 'nowrap'}>
18
+ {leading ? <Box>{leading}</Box> : null}
19
+ <Box flex={1}>{children}</Box>
20
+ {trailing ? <Box>{trailing}</Box> : null}
21
+ </Inline>
22
+ );
23
+ }
24
+
25
+ export const FilterBar = withZoraThemeScope(FilterBarInner);
@@ -0,0 +1,2 @@
1
+ export { FilterBar } from './FilterBar';
2
+ export type { FilterBarProps } from './types';
@@ -0,0 +1,10 @@
1
+ import type React from 'react';
2
+
3
+ import type { ZoraBaseProps } from '../../theme/ZoraBaseProps';
4
+
5
+ export interface FilterBarProps extends ZoraBaseProps {
6
+ leading?: React.ReactNode;
7
+ trailing?: React.ReactNode;
8
+ children: React.ReactNode;
9
+ wrap?: boolean;
10
+ }
@@ -17,11 +17,15 @@ const IGNORED_DIRECTORY_NAMES = new Set([
17
17
 
18
18
  const REQUIRED_SHOWCASE_COVERAGE = {
19
19
  components: [
20
+ 'Avatar',
21
+ 'AvatarGroup',
20
22
  'Badge',
21
23
  'Button',
22
24
  'Card',
23
25
  'Checkbox',
24
26
  'CheckboxGroup',
27
+ 'Chip',
28
+ 'ChipGroup',
25
29
  'Drawer',
26
30
  'Form',
27
31
  'FormActions',
@@ -34,6 +38,7 @@ const REQUIRED_SHOWCASE_COVERAGE = {
34
38
  'Modal',
35
39
  'Radio',
36
40
  'RadioGroup',
41
+ 'SearchBar',
37
42
  'Select',
38
43
  'Tabs',
39
44
  'Text',
@@ -72,6 +77,7 @@ const REQUIRED_SHOWCASE_COVERAGE = {
72
77
  'ConfirmDialog',
73
78
  'DisclosureSection',
74
79
  'EmptyState',
80
+ 'FilterBar',
75
81
  'InspectorField',
76
82
  'Notice',
77
83
  'Panel',