@react-native-reusables/cli 0.0.9 → 0.0.11

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 (137) hide show
  1. package/README.md +95 -5
  2. package/dist/generated/components/primitives/accordion/accordion.tsx +216 -0
  3. package/dist/generated/components/primitives/accordion/accordion.web.tsx +295 -0
  4. package/dist/generated/components/primitives/accordion/index.ts +1 -0
  5. package/dist/generated/components/primitives/accordion/types.ts +45 -0
  6. package/dist/generated/components/primitives/alert-dialog/alert-dialog.tsx +237 -0
  7. package/dist/generated/components/primitives/alert-dialog/alert-dialog.web.tsx +256 -0
  8. package/dist/generated/components/primitives/alert-dialog/index.ts +1 -0
  9. package/dist/generated/components/primitives/alert-dialog/types.ts +48 -0
  10. package/dist/generated/components/primitives/aspect-ratio.tsx +23 -0
  11. package/dist/generated/components/primitives/avatar/ types.ts +10 -0
  12. package/dist/generated/components/primitives/avatar/index.tsx +95 -0
  13. package/dist/generated/components/primitives/checkbox/checkbox.tsx +101 -0
  14. package/dist/generated/components/primitives/checkbox/checkbox.web.tsx +114 -0
  15. package/dist/generated/components/primitives/checkbox/index.ts +1 -0
  16. package/dist/generated/components/primitives/checkbox/types.ts +11 -0
  17. package/dist/generated/components/primitives/collapsible/collapsible.tsx +119 -0
  18. package/dist/generated/components/primitives/collapsible/collapsible.web.tsx +157 -0
  19. package/dist/generated/components/primitives/collapsible/index.ts +1 -0
  20. package/dist/generated/components/primitives/collapsible/types.ts +18 -0
  21. package/dist/generated/components/primitives/context-menu/context-menu.tsx +626 -0
  22. package/dist/generated/components/primitives/context-menu/context-menu.web.tsx +504 -0
  23. package/dist/generated/components/primitives/context-menu/index.ts +1 -0
  24. package/dist/generated/components/primitives/context-menu/types.ts +82 -0
  25. package/dist/generated/components/primitives/dialog/dialog.tsx +211 -0
  26. package/dist/generated/components/primitives/dialog/dialog.web.tsx +197 -0
  27. package/dist/generated/components/primitives/dialog/index.ts +1 -0
  28. package/dist/generated/components/primitives/dialog/types.ts +60 -0
  29. package/dist/generated/components/primitives/dropdown-menu/dropdown-menu.tsx +584 -0
  30. package/dist/generated/components/primitives/dropdown-menu/dropdown-menu.web.tsx +521 -0
  31. package/dist/generated/components/primitives/dropdown-menu/index.ts +1 -0
  32. package/dist/generated/components/primitives/dropdown-menu/types.ts +71 -0
  33. package/dist/generated/components/primitives/hooks/index.ts +3 -0
  34. package/dist/generated/components/primitives/hooks/useAugmentedRef.tsx +29 -0
  35. package/dist/generated/components/primitives/hooks/useControllableState.tsx +75 -0
  36. package/dist/generated/components/primitives/hooks/useRelativePosition.tsx +227 -0
  37. package/dist/generated/components/primitives/hover-card/hover-card.tsx +271 -0
  38. package/dist/generated/components/primitives/hover-card/hover-card.web.tsx +145 -0
  39. package/dist/generated/components/primitives/hover-card/index.ts +1 -0
  40. package/dist/generated/components/primitives/hover-card/types.ts +42 -0
  41. package/dist/generated/components/primitives/label/index.ts +1 -0
  42. package/dist/generated/components/primitives/label/label.tsx +31 -0
  43. package/dist/generated/components/primitives/label/label.web.tsx +36 -0
  44. package/dist/generated/components/primitives/label/types.ts +15 -0
  45. package/dist/generated/components/primitives/menubar/index.ts +1 -0
  46. package/dist/generated/components/primitives/menubar/menubar.tsx +624 -0
  47. package/dist/generated/components/primitives/menubar/menubar.web.tsx +543 -0
  48. package/dist/generated/components/primitives/menubar/types.ts +76 -0
  49. package/dist/generated/components/primitives/navigation-menu/index.ts +1 -0
  50. package/dist/generated/components/primitives/navigation-menu/navigation-menu.tsx +315 -0
  51. package/dist/generated/components/primitives/navigation-menu/navigation-menu.web.tsx +264 -0
  52. package/dist/generated/components/primitives/navigation-menu/types.ts +49 -0
  53. package/dist/generated/components/primitives/popover/index.ts +1 -0
  54. package/dist/generated/components/primitives/popover/popover.tsx +286 -0
  55. package/dist/generated/components/primitives/popover/popover.web.tsx +179 -0
  56. package/dist/generated/components/primitives/popover/types.ts +30 -0
  57. package/dist/generated/components/primitives/portal.tsx +67 -0
  58. package/dist/generated/components/primitives/progress/index.ts +1 -0
  59. package/dist/generated/components/primitives/progress/progress.tsx +59 -0
  60. package/dist/generated/components/primitives/progress/progress.web.tsx +36 -0
  61. package/dist/generated/components/primitives/progress/types.ts +7 -0
  62. package/dist/generated/components/primitives/radio-group/index.ts +1 -0
  63. package/dist/generated/components/primitives/radio-group/radio-group.tsx +116 -0
  64. package/dist/generated/components/primitives/radio-group/radio-group.web.tsx +78 -0
  65. package/dist/generated/components/primitives/radio-group/types.ts +15 -0
  66. package/dist/generated/components/primitives/select/index.ts +1 -0
  67. package/dist/generated/components/primitives/select/select.tsx +455 -0
  68. package/dist/generated/components/primitives/select/select.web.tsx +319 -0
  69. package/dist/generated/components/primitives/select/types.ts +87 -0
  70. package/dist/generated/components/primitives/separator/ types.ts +6 -0
  71. package/dist/generated/components/primitives/separator/index.tsx +23 -0
  72. package/dist/generated/components/primitives/slider/index.ts +1 -0
  73. package/dist/generated/components/primitives/slider/slider.tsx +89 -0
  74. package/dist/generated/components/primitives/slider/slider.web.tsx +67 -0
  75. package/dist/generated/components/primitives/slider/types.ts +24 -0
  76. package/dist/generated/components/primitives/slot.tsx +187 -0
  77. package/dist/generated/components/primitives/switch/index.ts +1 -0
  78. package/dist/generated/components/primitives/switch/switch.tsx +65 -0
  79. package/dist/generated/components/primitives/switch/switch.web.tsx +67 -0
  80. package/dist/generated/components/primitives/switch/types.ts +11 -0
  81. package/dist/generated/components/primitives/table.tsx +55 -0
  82. package/dist/generated/components/primitives/tabs/index.ts +1 -0
  83. package/dist/generated/components/primitives/tabs/tabs.tsx +133 -0
  84. package/dist/generated/components/primitives/tabs/tabs.web.tsx +97 -0
  85. package/dist/generated/components/primitives/tabs/types.ts +24 -0
  86. package/dist/generated/components/primitives/toast/ types.ts +7 -0
  87. package/dist/generated/components/primitives/toast/index.tsx +128 -0
  88. package/dist/generated/components/primitives/toggle/index.ts +1 -0
  89. package/dist/generated/components/primitives/toggle/toggle.tsx +37 -0
  90. package/dist/generated/components/primitives/toggle/toggle.web.tsx +26 -0
  91. package/dist/generated/components/primitives/toggle/types.ts +7 -0
  92. package/dist/generated/components/primitives/toggle-group/index.ts +1 -0
  93. package/dist/generated/components/primitives/toggle-group/toggle-group.tsx +125 -0
  94. package/dist/generated/components/primitives/toggle-group/toggle-group.web.tsx +124 -0
  95. package/dist/generated/components/primitives/toggle-group/types.ts +37 -0
  96. package/dist/generated/components/primitives/toolbar/index.ts +1 -0
  97. package/dist/generated/components/primitives/toolbar/toolbar.tsx +125 -0
  98. package/dist/generated/components/primitives/toolbar/toolbar.web.tsx +129 -0
  99. package/dist/generated/components/primitives/toolbar/types.ts +39 -0
  100. package/dist/generated/components/primitives/tooltip/index.ts +1 -0
  101. package/dist/generated/components/primitives/tooltip/tooltip.tsx +271 -0
  102. package/dist/generated/components/primitives/tooltip/tooltip.web.tsx +167 -0
  103. package/dist/generated/components/primitives/tooltip/types.ts +44 -0
  104. package/dist/generated/components/primitives/types.ts +105 -0
  105. package/dist/generated/components/primitives/utils.ts +61 -0
  106. package/dist/generated/components/ui/accordion.tsx +127 -0
  107. package/dist/generated/components/ui/alert-dialog.tsx +167 -0
  108. package/dist/generated/components/ui/aspect-ratio.tsx +5 -0
  109. package/dist/generated/components/ui/avatar.tsx +44 -0
  110. package/dist/generated/components/ui/badge.tsx +51 -0
  111. package/dist/generated/components/ui/button.tsx +88 -0
  112. package/dist/generated/components/ui/card.tsx +67 -0
  113. package/dist/generated/components/ui/checkbox.tsx +34 -0
  114. package/dist/generated/components/ui/collapsible.tsx +9 -0
  115. package/dist/generated/components/ui/context-menu.tsx +244 -0
  116. package/dist/generated/components/ui/dialog.tsx +150 -0
  117. package/dist/generated/components/ui/dropdown-menu.tsx +244 -0
  118. package/dist/generated/components/ui/hover-card.tsx +45 -0
  119. package/dist/generated/components/ui/input.tsx +26 -0
  120. package/dist/generated/components/ui/label.tsx +28 -0
  121. package/dist/generated/components/ui/menubar.tsx +260 -0
  122. package/dist/generated/components/ui/navigation-menu.tsx +177 -0
  123. package/dist/generated/components/ui/popover.tsx +39 -0
  124. package/dist/generated/components/ui/radio-group.tsx +38 -0
  125. package/dist/generated/components/ui/select.tsx +181 -0
  126. package/dist/generated/components/ui/separator.tsx +23 -0
  127. package/dist/generated/components/ui/skeleton.tsx +39 -0
  128. package/dist/generated/components/ui/switch.tsx +97 -0
  129. package/dist/generated/components/ui/table.tsx +99 -0
  130. package/dist/generated/components/ui/tabs.tsx +65 -0
  131. package/dist/generated/components/ui/text.tsx +24 -0
  132. package/dist/generated/components/ui/textarea.tsx +28 -0
  133. package/dist/generated/components/ui/toggle-group.tsx +86 -0
  134. package/dist/generated/components/ui/toggle.tsx +85 -0
  135. package/dist/generated/components/ui/tooltip.tsx +36 -0
  136. package/dist/generated/components/ui/typography.tsx +204 -0
  137. package/package.json +8 -8
package/README.md CHANGED
@@ -1,7 +1,97 @@
1
1
  # React Native Reusables CLI
2
2
 
3
- > This project uses code from shadcn.
4
- <br />
5
- > The code is licensed under the MIT License.
6
- <br />
7
- > https://github.com/shadcn-ui/ui
3
+ > Please follow [the initial setup steps](https://rnr-docs.vercel.app/getting-started/initial-setup/) before using
4
+
5
+ A CLI to add [react-native-reusables](https://rnr-docs.vercel.app/getting-started/introduction/) components to your project. When components depend on other components and/or primitives, they will also be added to your project.
6
+
7
+ ## How to use
8
+
9
+ Use the following command _(with optional arugments and flags)_:
10
+
11
+ ```bash
12
+ npx @react-native-reusables/cli@latest add
13
+ ```
14
+
15
+ ### Arguments
16
+
17
+ If you do not add arguments, you will be promted to select the `ui` components you would like to add to your project.
18
+
19
+ #### UI Components
20
+
21
+ - `accordion`
22
+ - `alert-dialog`
23
+ - `aspect-ratio`
24
+ - `avatar`
25
+ - `badge`
26
+ - `button`
27
+ - `card`
28
+ - `checkbox`
29
+ - `collapsible`
30
+ - `context-menu`
31
+ - `dialog`
32
+ - `dropdown-menu`
33
+ - `hover-card`
34
+ - `input`
35
+ - `label`
36
+ - `menubar`
37
+ - `navigation-menu`
38
+ - `popover`
39
+ - `radio-group`
40
+ - `select`
41
+ - `separator`
42
+ - `skeleton`
43
+ - `switch`
44
+ - `table`
45
+ - `tabs`
46
+ - `text`
47
+ - `textarea`
48
+ - `toggle`
49
+ - `toggle-group`
50
+ - `tooltip`
51
+ - `typography`
52
+
53
+ #### Primitive Components
54
+
55
+ - `accordion-primitive`
56
+ - `alert-dialog-primitive`
57
+ - `aspect-ratio-primitive`
58
+ - `avatar-primitive`
59
+ - `checkbox-primitive`
60
+ - `collapsible-primitive`
61
+ - `context-menu-primitive`
62
+ - `dialog-primitive`
63
+ - `dropdown-menu-primitive`
64
+ - `hover-card-primitive`
65
+ - `label-primitive`
66
+ - `menubar-primitive`
67
+ - `navigation-menu-primitive`
68
+ - `popover-primitive`
69
+ - `progress-primitive`
70
+ - `radio-group-primitive`
71
+ - `select-primitive`
72
+ - `separator-primitive`
73
+ - `slider-primitive`
74
+ - `switch-primitive`
75
+ - `table-primitive`
76
+ - `tabs-primitive`
77
+ - `toast-primitive`
78
+ - `toggle-primitive`
79
+ - `toggle-group-primitive`
80
+ - `toolbar-primitive`
81
+ - `tooltip-primitive`
82
+ - `hooks-primitive`
83
+ - `portal-primitive`
84
+ - `slot-primitive`
85
+ - `types-primitive`
86
+ - `utils-primitive`
87
+
88
+ ### Flags
89
+
90
+ - `-o` or `--overwrite`: Overwrite existing files. Default to `false`
91
+ - `-c <cmd>` or `--cwd <cwd>`: The working directory. Defaults to the current directory.
92
+
93
+ ```mdx
94
+ This project uses code from shadcn.
95
+ The code is licensed under the MIT License.
96
+ https://github.com/shadcn-ui/ui
97
+ ```
@@ -0,0 +1,216 @@
1
+ import * as React from 'react';
2
+ import { Pressable, View, type GestureResponderEvent } from 'react-native';
3
+ import * as Slot from '@rnr/slot';
4
+ import type {
5
+ PressableRef,
6
+ SlottablePressableProps,
7
+ SlottableViewProps,
8
+ ViewRef,
9
+ } from '@rnr/types';
10
+ import type {
11
+ AccordionContentProps,
12
+ AccordionItemProps,
13
+ AccordionRootProps,
14
+ RootContext,
15
+ } from './types';
16
+ import { useControllableState } from '@rnr/hooks';
17
+
18
+ const AccordionContext = React.createContext<RootContext | null>(null);
19
+
20
+ const Root = React.forwardRef<ViewRef, SlottableViewProps & AccordionRootProps>(
21
+ (
22
+ {
23
+ asChild,
24
+ type,
25
+ disabled,
26
+ collapsible = true,
27
+ value: valueProp,
28
+ onValueChange: onValueChangeProps,
29
+ defaultValue,
30
+ ...viewProps
31
+ },
32
+ ref
33
+ ) => {
34
+ const [value = type === 'multiple' ? [] : undefined, onValueChange] = useControllableState<
35
+ (string | undefined) | string[]
36
+ >({
37
+ prop: valueProp,
38
+ defaultProp: defaultValue,
39
+ onChange: onValueChangeProps as (state: string | string[] | undefined) => void,
40
+ });
41
+
42
+ const Component = asChild ? Slot.View : View;
43
+ return (
44
+ <AccordionContext.Provider
45
+ value={{
46
+ type,
47
+ disabled,
48
+ collapsible,
49
+ value,
50
+ onValueChange,
51
+ }}
52
+ >
53
+ <Component ref={ref} {...viewProps} />
54
+ </AccordionContext.Provider>
55
+ );
56
+ }
57
+ );
58
+
59
+ Root.displayName = 'RootNativeAccordion';
60
+
61
+ function useRootContext() {
62
+ const context = React.useContext(AccordionContext);
63
+ if (!context) {
64
+ throw new Error(
65
+ 'Accordion compound components cannot be rendered outside the Accordion component'
66
+ );
67
+ }
68
+ return context;
69
+ }
70
+
71
+ type AccordionItemContext = AccordionItemProps & {
72
+ nativeID: string;
73
+ isExpanded: boolean;
74
+ };
75
+
76
+ const AccordionItemContext = React.createContext<AccordionItemContext | null>(null);
77
+
78
+ const Item = React.forwardRef<ViewRef, SlottableViewProps & AccordionItemProps>(
79
+ ({ asChild, value, disabled, ...viewProps }, ref) => {
80
+ const { value: rootValue } = useRootContext();
81
+ const nativeID = React.useId();
82
+
83
+ const Component = asChild ? Slot.View : View;
84
+ return (
85
+ <AccordionItemContext.Provider
86
+ value={{
87
+ value,
88
+ disabled,
89
+ nativeID,
90
+ isExpanded: isItemExpanded(rootValue, value),
91
+ }}
92
+ >
93
+ <Component ref={ref} {...viewProps} />
94
+ </AccordionItemContext.Provider>
95
+ );
96
+ }
97
+ );
98
+
99
+ Item.displayName = 'ItemNativeAccordion';
100
+
101
+ function useItemContext() {
102
+ const context = React.useContext(AccordionItemContext);
103
+ if (!context) {
104
+ throw new Error(
105
+ 'AccordionItem compound components cannot be rendered outside the AccordionItem component'
106
+ );
107
+ }
108
+ return context;
109
+ }
110
+
111
+ const Header = React.forwardRef<ViewRef, SlottableViewProps>(({ asChild, ...props }, ref) => {
112
+ const { disabled: rootDisabled } = useRootContext();
113
+ const { disabled: itemDisabled, isExpanded } = useItemContext();
114
+
115
+ const Component = asChild ? Slot.View : View;
116
+ return (
117
+ <Component
118
+ ref={ref}
119
+ role='heading'
120
+ aria-expanded={isExpanded}
121
+ aria-disabled={rootDisabled ?? itemDisabled}
122
+ {...props}
123
+ />
124
+ );
125
+ });
126
+
127
+ Header.displayName = 'HeaderNativeAccordion';
128
+
129
+ const Trigger = React.forwardRef<PressableRef, SlottablePressableProps>(
130
+ ({ asChild, onPress: onPressProp, disabled: disabledProp, ...props }, ref) => {
131
+ const {
132
+ disabled: rootDisabled,
133
+ type,
134
+ onValueChange,
135
+ value: rootValue,
136
+ collapsible,
137
+ } = useRootContext();
138
+ const { nativeID, disabled: itemDisabled, value, isExpanded } = useItemContext();
139
+
140
+ function onPress(ev: GestureResponderEvent) {
141
+ if (rootDisabled || itemDisabled) return;
142
+ if (type === 'single') {
143
+ const newValue = collapsible ? (value === rootValue ? undefined : value) : value;
144
+ onValueChange(newValue);
145
+ }
146
+ if (type === 'multiple') {
147
+ const rootToArray = toStringArray(rootValue);
148
+ const newValue = collapsible
149
+ ? rootToArray.includes(value)
150
+ ? rootToArray.filter((val) => val !== value)
151
+ : rootToArray.concat(value)
152
+ : [...new Set(rootToArray.concat(value))];
153
+ // @ts-ignore - `newValue` is of type `string[]` which is OK
154
+ onValueChange(newValue);
155
+ }
156
+ onPressProp?.(ev);
157
+ }
158
+
159
+ const isDisabled = disabledProp || rootDisabled || itemDisabled;
160
+ const Component = asChild ? Slot.Pressable : Pressable;
161
+ return (
162
+ <Component
163
+ ref={ref}
164
+ key={`${nativeID}-${JSON.stringify(rootValue)}-${isDisabled}-${collapsible}-${type}`}
165
+ nativeID={nativeID}
166
+ aria-disabled={isDisabled}
167
+ role='button'
168
+ onPress={onPress}
169
+ accessibilityState={{
170
+ expanded: isExpanded,
171
+ disabled: isDisabled,
172
+ }}
173
+ disabled={isDisabled}
174
+ {...props}
175
+ />
176
+ );
177
+ }
178
+ );
179
+
180
+ Trigger.displayName = 'TriggerNativeAccordion';
181
+
182
+ const Content = React.forwardRef<ViewRef, SlottableViewProps & AccordionContentProps>(
183
+ ({ asChild, forceMount, ...props }, ref) => {
184
+ const { type } = useRootContext();
185
+ const { nativeID, isExpanded } = useItemContext();
186
+
187
+ if (!forceMount) {
188
+ if (!isExpanded) {
189
+ return null;
190
+ }
191
+ }
192
+
193
+ const Component = asChild ? Slot.View : View;
194
+ return (
195
+ <Component
196
+ ref={ref}
197
+ aria-hidden={!(forceMount || isExpanded)}
198
+ aria-labelledby={nativeID}
199
+ role={type === 'single' ? 'region' : 'summary'}
200
+ {...props}
201
+ />
202
+ );
203
+ }
204
+ );
205
+
206
+ Content.displayName = 'ContentNativeAccordion';
207
+
208
+ export { Content, Header, Item, Root, Trigger, useRootContext, useItemContext };
209
+
210
+ function toStringArray(value?: string | string[]) {
211
+ return Array.isArray(value) ? value : value ? [value] : [];
212
+ }
213
+
214
+ function isItemExpanded(rootValue: string | string[] | undefined, value: string) {
215
+ return Array.isArray(rootValue) ? rootValue.includes(value) : rootValue === value;
216
+ }
@@ -0,0 +1,295 @@
1
+ import * as Accordion from '@radix-ui/react-accordion';
2
+ import { useAugmentedRef, useControllableState } from '@rnr/hooks';
3
+ import * as Slot from '@rnr/slot';
4
+ import type {
5
+ PressableRef,
6
+ SlottablePressableProps,
7
+ SlottableViewProps,
8
+ ViewRef,
9
+ } from '@rnr/types';
10
+ import * as React from 'react';
11
+ import { Pressable, View } from 'react-native';
12
+ import type { AccordionContentProps, AccordionItemProps, AccordionRootProps } from './types';
13
+
14
+ function useIsomorphicLayoutEffect(
15
+ effect: React.EffectCallback,
16
+ dependencies?: React.DependencyList
17
+ ) {
18
+ if (typeof window === 'undefined') {
19
+ React.useEffect(effect, dependencies);
20
+ } else {
21
+ React.useLayoutEffect(effect, dependencies);
22
+ }
23
+ }
24
+
25
+ const AccordionContext = React.createContext<AccordionRootProps | null>(null);
26
+
27
+ const Root = React.forwardRef<ViewRef, SlottableViewProps & AccordionRootProps>(
28
+ (
29
+ {
30
+ asChild,
31
+ value: valueProp,
32
+ onValueChange: onValueChangeProps,
33
+ defaultValue,
34
+ type,
35
+ disabled,
36
+ dir,
37
+ orientation = 'vertical',
38
+ collapsible,
39
+ ...props
40
+ },
41
+ ref
42
+ ) => {
43
+ const [value = type === 'multiple' ? [] : undefined, onValueChange] = useControllableState<
44
+ (string | undefined) | string[]
45
+ >({
46
+ prop: valueProp,
47
+ defaultProp: defaultValue,
48
+ onChange: onValueChangeProps as (state: string | string[] | undefined) => void,
49
+ });
50
+
51
+ const Component = asChild ? Slot.View : View;
52
+ return (
53
+ <AccordionContext.Provider
54
+ value={
55
+ {
56
+ value,
57
+ onValueChange,
58
+ type,
59
+ disabled,
60
+ dir,
61
+ orientation,
62
+ } as AccordionRootProps
63
+ }
64
+ >
65
+ <Accordion.Root
66
+ asChild
67
+ value={value as any}
68
+ onValueChange={onValueChange as any}
69
+ type={type as any}
70
+ disabled={disabled}
71
+ dir={dir}
72
+ orientation={orientation}
73
+ collapsible={collapsible}
74
+ >
75
+ <Component ref={ref} {...props} />
76
+ </Accordion.Root>
77
+ </AccordionContext.Provider>
78
+ );
79
+ }
80
+ );
81
+
82
+ Root.displayName = 'RootWebAccordion';
83
+
84
+ function useRootContext() {
85
+ const context = React.useContext(AccordionContext);
86
+ if (!context) {
87
+ throw new Error(
88
+ 'Accordion compound components cannot be rendered outside the Accordion component'
89
+ );
90
+ }
91
+ return context;
92
+ }
93
+
94
+ const AccordionItemContext = React.createContext<
95
+ (AccordionItemProps & { isExpanded: boolean }) | null
96
+ >(null);
97
+
98
+ const Item = React.forwardRef<ViewRef, AccordionItemProps & SlottableViewProps>(
99
+ ({ asChild, value: itemValue, disabled, ...props }, ref) => {
100
+ const augmentedRef = useAugmentedRef({ ref });
101
+ const { value, orientation, disabled: disabledRoot } = useRootContext();
102
+
103
+ useIsomorphicLayoutEffect(() => {
104
+ if (augmentedRef.current) {
105
+ const augRef = augmentedRef.current as unknown as HTMLDivElement;
106
+ const isExpanded = Array.isArray(value) ? value.includes(itemValue) : value === itemValue;
107
+ augRef.dataset.state = isExpanded ? 'open' : 'closed';
108
+ }
109
+ }, [value, itemValue]);
110
+
111
+ useIsomorphicLayoutEffect(() => {
112
+ if (augmentedRef.current) {
113
+ const augRef = augmentedRef.current as unknown as HTMLDivElement;
114
+ augRef.dataset.orientation = orientation;
115
+ if (disabled || disabledRoot) {
116
+ augRef.dataset.disabled = 'true';
117
+ } else {
118
+ augRef.dataset.disabled = undefined;
119
+ }
120
+ }
121
+ }, [orientation, disabled, disabledRoot]);
122
+
123
+ const Component = asChild ? Slot.View : View;
124
+ return (
125
+ <AccordionItemContext.Provider
126
+ value={{
127
+ value: itemValue,
128
+ disabled,
129
+ isExpanded: isItemExpanded(value, itemValue),
130
+ }}
131
+ >
132
+ <Accordion.Item value={itemValue} disabled={disabled} asChild>
133
+ <Component ref={augmentedRef} {...props} />
134
+ </Accordion.Item>
135
+ </AccordionItemContext.Provider>
136
+ );
137
+ }
138
+ );
139
+
140
+ Item.displayName = 'ItemWebAccordion';
141
+
142
+ function useItemContext() {
143
+ const context = React.useContext(AccordionItemContext);
144
+ if (!context) {
145
+ throw new Error(
146
+ 'AccordionItem compound components cannot be rendered outside the AccordionItem component'
147
+ );
148
+ }
149
+ return context;
150
+ }
151
+
152
+ const Header = React.forwardRef<ViewRef, SlottableViewProps>(({ asChild, ...props }, ref) => {
153
+ const augmentedRef = useAugmentedRef({ ref });
154
+ const { disabled, isExpanded } = useItemContext();
155
+ const { orientation, disabled: disabledRoot } = useRootContext();
156
+
157
+ useIsomorphicLayoutEffect(() => {
158
+ if (augmentedRef.current) {
159
+ const augRef = augmentedRef.current as unknown as HTMLDivElement;
160
+ augRef.dataset.state = isExpanded ? 'open' : 'closed';
161
+ }
162
+ }, [isExpanded]);
163
+
164
+ useIsomorphicLayoutEffect(() => {
165
+ if (augmentedRef.current) {
166
+ const augRef = augmentedRef.current as unknown as HTMLDivElement;
167
+ augRef.dataset.orientation = orientation;
168
+ if (disabled || disabledRoot) {
169
+ augRef.dataset.disabled = 'true';
170
+ } else {
171
+ augRef.dataset.disabled = undefined;
172
+ }
173
+ }
174
+ }, [orientation, disabled, disabledRoot]);
175
+
176
+ const Component = asChild ? Slot.View : View;
177
+ return (
178
+ <Accordion.Header asChild>
179
+ <Component ref={augmentedRef} {...props} />
180
+ </Accordion.Header>
181
+ );
182
+ });
183
+
184
+ Header.displayName = 'HeaderWebAccordion';
185
+
186
+ const HIDDEN_STYLE: React.CSSProperties = {
187
+ position: 'absolute',
188
+ top: 0,
189
+ left: 0,
190
+ zIndex: -999999,
191
+ opacity: 0,
192
+ };
193
+
194
+ const Trigger = React.forwardRef<PressableRef, SlottablePressableProps>(
195
+ ({ asChild, disabled: disabledProp, ...props }, ref) => {
196
+ const { disabled: disabledRoot } = useRootContext();
197
+ const { disabled, isExpanded } = useItemContext();
198
+ const triggerRef = React.useRef<HTMLButtonElement>(null);
199
+ const augmentedRef = useAugmentedRef({ ref });
200
+
201
+ useIsomorphicLayoutEffect(() => {
202
+ if (augmentedRef.current) {
203
+ const augRef = augmentedRef.current as unknown as HTMLDivElement;
204
+
205
+ augRef.dataset.state = isExpanded ? 'expanded' : 'closed';
206
+ }
207
+ }, [isExpanded]);
208
+
209
+ useIsomorphicLayoutEffect(() => {
210
+ if (augmentedRef.current) {
211
+ const augRef = augmentedRef.current as unknown as HTMLDivElement;
212
+
213
+ if (disabled || disabledRoot || disabledProp) {
214
+ augRef.dataset.disabled = 'true';
215
+ } else {
216
+ augRef.dataset.disabled = undefined;
217
+ }
218
+ }
219
+ }, [disabled, disabledRoot, disabledProp]);
220
+
221
+ useIsomorphicLayoutEffect(() => {
222
+ if (triggerRef.current) {
223
+ triggerRef.current.disabled = true;
224
+ }
225
+ }, []);
226
+
227
+ const isDisabled = disabledProp ?? disabledRoot ?? disabled;
228
+ const Component = asChild ? Slot.Pressable : Pressable;
229
+ return (
230
+ <>
231
+ <Accordion.Trigger ref={triggerRef} aria-hidden tabIndex={-1} style={HIDDEN_STYLE} />
232
+ <Accordion.Trigger disabled={isDisabled} asChild>
233
+ <Component
234
+ ref={augmentedRef}
235
+ role='button'
236
+ disabled={isDisabled}
237
+ {...props}
238
+ onPress={() => {
239
+ if (triggerRef.current && !isDisabled) {
240
+ triggerRef.current.disabled = false;
241
+ triggerRef.current.click();
242
+ triggerRef.current.disabled = true;
243
+ }
244
+ }}
245
+ />
246
+ </Accordion.Trigger>
247
+ </>
248
+ );
249
+ }
250
+ );
251
+
252
+ Trigger.displayName = 'TriggerWebAccordion';
253
+
254
+ const Content = React.forwardRef<ViewRef, AccordionContentProps & SlottableViewProps>(
255
+ ({ asChild, forceMount, ...props }, ref) => {
256
+ const augmentedRef = useAugmentedRef({ ref });
257
+
258
+ const { orientation, disabled: disabledRoot } = useRootContext();
259
+ const { disabled, isExpanded } = useItemContext();
260
+ useIsomorphicLayoutEffect(() => {
261
+ if (augmentedRef.current) {
262
+ const augRef = augmentedRef.current as unknown as HTMLDivElement;
263
+ augRef.dataset.state = isExpanded ? 'expanded' : 'closed';
264
+ }
265
+ }, [isExpanded]);
266
+
267
+ useIsomorphicLayoutEffect(() => {
268
+ if (augmentedRef.current) {
269
+ const augRef = augmentedRef.current as unknown as HTMLDivElement;
270
+ augRef.dataset.orientation = orientation;
271
+
272
+ if (disabled || disabledRoot) {
273
+ augRef.dataset.disabled = 'true';
274
+ } else {
275
+ augRef.dataset.disabled = undefined;
276
+ }
277
+ }
278
+ }, [orientation, disabled, disabledRoot]);
279
+
280
+ const Component = asChild ? Slot.View : View;
281
+ return (
282
+ <Accordion.Content forceMount={forceMount} asChild>
283
+ <Component ref={augmentedRef} {...props} />
284
+ </Accordion.Content>
285
+ );
286
+ }
287
+ );
288
+
289
+ Content.displayName = 'ContentWebAccordion';
290
+
291
+ export { Content, Header, Item, Root, Trigger, useItemContext, useRootContext };
292
+
293
+ function isItemExpanded(rootValue: string | string[] | undefined, value: string) {
294
+ return Array.isArray(rootValue) ? rootValue.includes(value) : rootValue === value;
295
+ }
@@ -0,0 +1 @@
1
+ export * from './accordion';
@@ -0,0 +1,45 @@
1
+ import { ForceMountable } from '@rnr/types';
2
+
3
+ type RootContext = {
4
+ type: 'single' | 'multiple';
5
+ value: (string | undefined) | string[];
6
+ onValueChange: (value: string | undefined) => void | ((value: string[]) => void);
7
+ collapsible: boolean;
8
+ disabled?: boolean;
9
+ };
10
+
11
+ type SingleRootProps = {
12
+ type: 'single';
13
+ defaultValue?: string | undefined;
14
+ value?: string | undefined;
15
+ onValueChange?: (value: string | undefined) => void;
16
+ };
17
+
18
+ type MultipleRootProps = {
19
+ type: 'multiple';
20
+ defaultValue?: string[];
21
+ value?: string[];
22
+ onValueChange?: (value: string[]) => void;
23
+ };
24
+
25
+ type AccordionRootProps = (SingleRootProps | MultipleRootProps) & {
26
+ defaultValue?: string | string[];
27
+ disabled?: boolean;
28
+ collapsible?: boolean;
29
+ /**
30
+ * Platform: WEB ONLY
31
+ */
32
+ dir?: 'ltr' | 'rtl';
33
+ /**
34
+ * Platform: WEB ONLY
35
+ */
36
+ orientation?: 'vertical' | 'horizontal';
37
+ };
38
+
39
+ type AccordionItemProps = {
40
+ value: string;
41
+ disabled?: boolean;
42
+ };
43
+ type AccordionContentProps = ForceMountable;
44
+
45
+ export type { AccordionContentProps, AccordionItemProps, AccordionRootProps, RootContext };