jp-composter 0.1.0

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 (194) hide show
  1. package/dist/index.d.mts +997 -0
  2. package/dist/index.d.ts +997 -0
  3. package/dist/index.js +36837 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/index.mjs +36778 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/package.json +66 -0
  8. package/src/SliceUI/IconMoon.tsx +33 -0
  9. package/src/SliceUI/assets/Anatomy diagram copy.svg +19 -0
  10. package/src/SliceUI/assets/Anatomy diagram.svg +19 -0
  11. package/src/SliceUI/assets/Anatomycheck.svg +15 -0
  12. package/src/SliceUI/assets/Anatomyinput.svg +32 -0
  13. package/src/SliceUI/assets/Checkbox.jpg +0 -0
  14. package/src/SliceUI/assets/Diagram copy.svg +15 -0
  15. package/src/SliceUI/assets/Diagram.jpg +0 -0
  16. package/src/SliceUI/assets/Diagram.svg +15 -0
  17. package/src/SliceUI/assets/Frame 5 copy.png +0 -0
  18. package/src/SliceUI/assets/Frame 5.png +0 -0
  19. package/src/SliceUI/assets/Frame 65.png +0 -0
  20. package/src/SliceUI/assets/Frame_65.png +0 -0
  21. package/src/SliceUI/assets/Icon copy.svg +3 -0
  22. package/src/SliceUI/assets/Icon.svg +3 -0
  23. package/src/SliceUI/assets/Icon_Bridging copy.svg +39 -0
  24. package/src/SliceUI/assets/Icon_Bridging.svg +39 -0
  25. package/src/SliceUI/assets/Icon_Consistent copy.svg +39 -0
  26. package/src/SliceUI/assets/Icon_Consistent.svg +39 -0
  27. package/src/SliceUI/assets/Icon_Plug copy.svg +38 -0
  28. package/src/SliceUI/assets/Icon_Plug.svg +38 -0
  29. package/src/SliceUI/assets/Icon_Reusable copy.svg +39 -0
  30. package/src/SliceUI/assets/Icon_Reusable.svg +39 -0
  31. package/src/SliceUI/assets/Layer_1.png +0 -0
  32. package/src/SliceUI/assets/accessibility.png +0 -0
  33. package/src/SliceUI/assets/accessibility.svg +1 -0
  34. package/src/SliceUI/assets/addon-library.png +0 -0
  35. package/src/SliceUI/assets/assets.png +0 -0
  36. package/src/SliceUI/assets/avif-test-image.avif +0 -0
  37. package/src/SliceUI/assets/bridging.svg +13 -0
  38. package/src/SliceUI/assets/consistent.svg +11 -0
  39. package/src/SliceUI/assets/context.png +0 -0
  40. package/src/SliceUI/assets/discord.svg +1 -0
  41. package/src/SliceUI/assets/docs.png +0 -0
  42. package/src/SliceUI/assets/figma-plugin.png +0 -0
  43. package/src/SliceUI/assets/github.svg +1 -0
  44. package/src/SliceUI/assets/resources/Anatomy diagram.svg +19 -0
  45. package/src/SliceUI/assets/resources/Anatomycheck.svg +15 -0
  46. package/src/SliceUI/assets/resources/Anatomyinput.svg +32 -0
  47. package/src/SliceUI/assets/resources/Diagram.svg +15 -0
  48. package/src/SliceUI/assets/resources/Frame 5.png +0 -0
  49. package/src/SliceUI/assets/resources/Frame 65.png +0 -0
  50. package/src/SliceUI/assets/resources/Icon.svg +3 -0
  51. package/src/SliceUI/assets/resources/Icon_Bridging.svg +39 -0
  52. package/src/SliceUI/assets/resources/Icon_Consistent.svg +39 -0
  53. package/src/SliceUI/assets/resources/Icon_Plug.svg +38 -0
  54. package/src/SliceUI/assets/resources/Icon_Reusable.svg +39 -0
  55. package/src/SliceUI/assets/resources/fonts/FontIcon.json +150 -0
  56. package/src/SliceUI/assets/resources/fonts/Lato-Black.ttf +0 -0
  57. package/src/SliceUI/assets/resources/fonts/Lato-Bold.ttf +0 -0
  58. package/src/SliceUI/assets/resources/fonts/Lato-Heavy.ttf +0 -0
  59. package/src/SliceUI/assets/resources/fonts/Lato-Medium.ttf +0 -0
  60. package/src/SliceUI/assets/resources/fonts/Lato-Regular.ttf +0 -0
  61. package/src/SliceUI/assets/resources/fonts/Lato.woff2 +0 -0
  62. package/src/SliceUI/assets/resources/fonts/icomoon.eot +0 -0
  63. package/src/SliceUI/assets/resources/fonts/icomoon.svg +601 -0
  64. package/src/SliceUI/assets/resources/fonts/icomoon.ttf +0 -0
  65. package/src/SliceUI/assets/resources/fonts/icomoon.woff +0 -0
  66. package/src/SliceUI/assets/resources/fonts/selection.json +1 -0
  67. package/src/SliceUI/assets/share.png +0 -0
  68. package/src/SliceUI/assets/styling.png +0 -0
  69. package/src/SliceUI/assets/testing.png +0 -0
  70. package/src/SliceUI/assets/theming.png +0 -0
  71. package/src/SliceUI/assets/tutorials.svg +1 -0
  72. package/src/SliceUI/assets/youtube.svg +1 -0
  73. package/src/SliceUI/automation/helper.ts +29 -0
  74. package/src/SliceUI/avatar/Avatar.tsx +237 -0
  75. package/src/SliceUI/avatar/Token.ts +116 -0
  76. package/src/SliceUI/avatar/Type.ts +36 -0
  77. package/src/SliceUI/avatar/helper.ts +53 -0
  78. package/src/SliceUI/badge/Badge.tsx +308 -0
  79. package/src/SliceUI/badge/Token.ts +202 -0
  80. package/src/SliceUI/badge/Type.ts +46 -0
  81. package/src/SliceUI/badge/helper.ts +39 -0
  82. package/src/SliceUI/button/Button.tsx +243 -0
  83. package/src/SliceUI/button/Token.ts +138 -0
  84. package/src/SliceUI/button/Type.ts +34 -0
  85. package/src/SliceUI/button/helper.ts +125 -0
  86. package/src/SliceUI/checkbox/Checkbox.tsx +176 -0
  87. package/src/SliceUI/checkbox/Token.ts +128 -0
  88. package/src/SliceUI/checkbox/Type.ts +35 -0
  89. package/src/SliceUI/chip/Chip.tsx +290 -0
  90. package/src/SliceUI/chip/Token.ts +151 -0
  91. package/src/SliceUI/chip/Type.ts +43 -0
  92. package/src/SliceUI/chip/helper.ts +40 -0
  93. package/src/SliceUI/colors/Pallete.ts +151 -0
  94. package/src/SliceUI/colors/Token.ts +110 -0
  95. package/src/SliceUI/colors/Type.ts +56 -0
  96. package/src/SliceUI/contextProvider/context.tsx +108 -0
  97. package/src/SliceUI/divider/Divider.tsx +109 -0
  98. package/src/SliceUI/divider/Token.ts +18 -0
  99. package/src/SliceUI/divider/Type.ts +26 -0
  100. package/src/SliceUI/icon/CustomIcon.ts +4 -0
  101. package/src/SliceUI/icon/IcoMoonIcon.tsx +11 -0
  102. package/src/SliceUI/icon/Icon.tsx +38 -0
  103. package/src/SliceUI/icon/Token.ts +14 -0
  104. package/src/SliceUI/icon/Type.ts +13 -0
  105. package/src/SliceUI/icon/selection.json +1 -0
  106. package/src/SliceUI/input/Input.tsx +573 -0
  107. package/src/SliceUI/input/ToDo.md +99 -0
  108. package/src/SliceUI/input/Token.ts +372 -0
  109. package/src/SliceUI/input/Type.ts +109 -0
  110. package/src/SliceUI/input/components/InputPortal.tsx +211 -0
  111. package/src/SliceUI/input/components/NativeBottomSheet.tsx +296 -0
  112. package/src/SliceUI/input/components/SelectChip.tsx +185 -0
  113. package/src/SliceUI/input/components/SelectList.tsx +173 -0
  114. package/src/SliceUI/input/components/SelectListItem.tsx +377 -0
  115. package/src/SliceUI/input/components/SelectScrollbarStyle.ts +44 -0
  116. package/src/SliceUI/input/hooks/useCustomScrollbar.ts +17 -0
  117. package/src/SliceUI/input/hooks/useInputState.ts +41 -0
  118. package/src/SliceUI/input/hooks/useLabelAnimation.ts +132 -0
  119. package/src/SliceUI/input/hooks/useOutsideClick.ts +38 -0
  120. package/src/SliceUI/input/hooks/useSelectLogic.ts +338 -0
  121. package/src/SliceUI/input/utils/inputUtils.ts +120 -0
  122. package/src/SliceUI/input/utils/selectUtils.ts +85 -0
  123. package/src/SliceUI/input/utils/styleUtils.ts +50 -0
  124. package/src/SliceUI/input/variants/CurrencyInput/CurrencyInput.tsx +16 -0
  125. package/src/SliceUI/input/variants/CurrencyInput/NativeCurrencyInput.tsx +181 -0
  126. package/src/SliceUI/input/variants/CurrencyInput/WebCurrencyInput.tsx +163 -0
  127. package/src/SliceUI/input/variants/CurrencyInput/types.ts +17 -0
  128. package/src/SliceUI/input/variants/PhoneInput/NativePhoneInput.tsx +189 -0
  129. package/src/SliceUI/input/variants/PhoneInput/PhoneInput.tsx +16 -0
  130. package/src/SliceUI/input/variants/PhoneInput/WebPhoneInput.tsx +291 -0
  131. package/src/SliceUI/input/variants/PhoneInput/types.ts +22 -0
  132. package/src/SliceUI/input/variants/SelectInput/SelectInput.tsx +407 -0
  133. package/src/SliceUI/input/variants/SelectInput/types.ts +34 -0
  134. package/src/SliceUI/input/variants/TextInput.tsx +68 -0
  135. package/src/SliceUI/layout/Box.tsx +38 -0
  136. package/src/SliceUI/layout/Center.tsx +38 -0
  137. package/src/SliceUI/layout/Divider.tsx +37 -0
  138. package/src/SliceUI/layout/Grid.tsx +75 -0
  139. package/src/SliceUI/layout/PageContainer.tsx +60 -0
  140. package/src/SliceUI/layout/ScrollContainer.tsx +72 -0
  141. package/src/SliceUI/layout/Spacer.tsx +54 -0
  142. package/src/SliceUI/layout/Stack.tsx +97 -0
  143. package/src/SliceUI/layout/StickyHeader.tsx +71 -0
  144. package/src/SliceUI/radio/RadioButton.tsx +130 -0
  145. package/src/SliceUI/radio/Token.ts +197 -0
  146. package/src/SliceUI/radio/Type.ts +35 -0
  147. package/src/SliceUI/react-native.config.js +3 -0
  148. package/src/SliceUI/responsive/Type.ts +7 -0
  149. package/src/SliceUI/responsive/helper.ts +53 -0
  150. package/src/SliceUI/switch/Switch.tsx +119 -0
  151. package/src/SliceUI/switch/Token.ts +205 -0
  152. package/src/SliceUI/switch/Type.ts +26 -0
  153. package/src/SliceUI/tab/TabItem.tsx +204 -0
  154. package/src/SliceUI/tab/Tabs.tsx +110 -0
  155. package/src/SliceUI/tab/Token.ts +282 -0
  156. package/src/SliceUI/tab/Type.ts +66 -0
  157. package/src/SliceUI/tab/helper.ts +53 -0
  158. package/src/SliceUI/table/Table.tsx +388 -0
  159. package/src/SliceUI/table/TableCell.tsx +158 -0
  160. package/src/SliceUI/table/TableFooter.tsx +353 -0
  161. package/src/SliceUI/table/TableHeader.tsx +247 -0
  162. package/src/SliceUI/table/TableRow.tsx +218 -0
  163. package/src/SliceUI/table/Token.ts +252 -0
  164. package/src/SliceUI/table/Type.ts +213 -0
  165. package/src/SliceUI/table/helper.ts +376 -0
  166. package/src/SliceUI/table/index.ts +53 -0
  167. package/src/SliceUI/theme/dummyColors.tsx +7 -0
  168. package/src/SliceUI/theme/theme.ts +107 -0
  169. package/src/SliceUI/typography/BaseTypographyToken.ts +62 -0
  170. package/src/SliceUI/typography/FoundationToken.ts +48 -0
  171. package/src/SliceUI/typography/Token.ts +228 -0
  172. package/src/SliceUI/typography/Type.ts +20 -0
  173. package/src/SliceUI/typography/Typography.tsx +99 -0
  174. package/src/SliceUI/values/BorderRadius.ts +17 -0
  175. package/src/SliceUI/values/BorderWidth.ts +7 -0
  176. package/src/SliceUI/values/Dimension.ts +35 -0
  177. package/src/SliceUI/values/IconSizes.ts +13 -0
  178. package/src/SliceUI/values/Spacing.ts +22 -0
  179. package/src/declarations.d.ts +8 -0
  180. package/src/index.tsx +119 -0
  181. package/src/stories/Colors.mdx +1418 -0
  182. package/src/stories/Dimensions.mdx +60 -0
  183. package/src/stories/GetStarted.mdx +90 -0
  184. package/src/stories/Introduction.mdx +136 -0
  185. package/src/stories/Shape.mdx +126 -0
  186. package/src/stories/Spacing.mdx +104 -0
  187. package/src/stories/Typography.mdx +454 -0
  188. package/src/stories/Utils.mdx +277 -0
  189. package/src/stories/story-components/AddIcon.js +13 -0
  190. package/src/stories/story-components/RectangleWithBox.jsx +51 -0
  191. package/src/stories/story-components/RoundedRectangle.jsx +18 -0
  192. package/src/stories/story-components/RoundedWithWhiteInside.jsx +33 -0
  193. package/src/stories/story-components/WhiteRoundedRectangle.jsx +107 -0
  194. package/src/stories/story-components/svgPaths.js +126 -0
@@ -0,0 +1,573 @@
1
+ import React, {forwardRef, useMemo, useRef, useState, useCallback} from 'react';
2
+ import {View, Text, StyleSheet, Animated} from 'react-native';
3
+
4
+ import {useSliceTheme} from '../contextProvider/context';
5
+ import {useGetColors} from '../theme/dummyColors';
6
+ import {resolveVariant} from '../responsive/helper';
7
+ import {spacing} from '../values/Spacing';
8
+
9
+ import type {ExtendedInputProps, InputSizeType} from './Type';
10
+
11
+ import {
12
+ isWeb,
13
+ getNormalizedVariant,
14
+ getNormalizedMultiple,
15
+ getNormalizedListType,
16
+ isSelectVariant,
17
+ getDisplayValue,
18
+ } from './utils/inputUtils';
19
+
20
+ import {useInputState} from './hooks/useInputState';
21
+ import {useLabelAnimation} from './hooks/useLabelAnimation';
22
+ import {useSelectLogic} from './hooks/useSelectLogic';
23
+ import {useOutsideClick} from './hooks/useOutsideClick';
24
+ import IconMoon from '../IconMoon';
25
+ import FONT_ICON from '../assets/resources/fonts/FontIcon.json';
26
+ import Icon from '../icon/Icon';
27
+
28
+ import TextInputVariant from './variants/TextInput';
29
+ import CurrencyInput from './variants/CurrencyInput/CurrencyInput';
30
+ import PhoneInput from './variants/PhoneInput/PhoneInput';
31
+ import SelectInput from './variants/SelectInput/SelectInput';
32
+ import SelectList from './components/SelectList';
33
+
34
+ import {getCountryCallingCode} from 'react-phone-number-input';
35
+ import type {CountryCode} from 'libphonenumber-js';
36
+ import {colors} from '../colors/Pallete';
37
+
38
+ const labelTopBySize: Record<InputSizeType, number> = {
39
+ small: 14,
40
+ medium: 16,
41
+ large: 18,
42
+ xlarge: 17,
43
+ xxlarge: 19,
44
+ };
45
+
46
+ const Input = forwardRef<any, ExtendedInputProps>((props, ref) => {
47
+ const {
48
+ variant = 'outlined',
49
+ size = 'medium',
50
+ labelText,
51
+ error,
52
+ helperText,
53
+ containerStyle,
54
+ inputStyle,
55
+ labelStyle,
56
+ helperTextStyle,
57
+ value,
58
+ onChangeText,
59
+ onFocus,
60
+ onBlur,
61
+ placeholder,
62
+ prefixIcon,
63
+ suffixIcon,
64
+ disabled,
65
+ hover = false,
66
+ multiple,
67
+ listType = 'default',
68
+ searchable = false,
69
+ options = [],
70
+ noItemText,
71
+ maxVisibleItems,
72
+ selectedIcon,
73
+ ...rest
74
+ } = props;
75
+ const inputRef = useRef<HTMLInputElement | null>(null);
76
+ const webInputContainerRef = useRef<any>(null);
77
+
78
+ const normalizedVariant = getNormalizedVariant(variant);
79
+ const normalizedMultiple = getNormalizedMultiple(variant, multiple);
80
+ const normalizedListType = getNormalizedListType(variant, listType);
81
+
82
+ const [currency, setCurrency] = React.useState('CAD');
83
+ const [currencyDropdownOpen, setCurrencyDropdownOpen] = React.useState(false);
84
+ const [country, setCountry] = useState<CountryCode>('CA');
85
+ const [number, setNumber] = useState('');
86
+ const [dropdownOpen, setDropdownOpen] = useState(false);
87
+
88
+ const onNumberChange = (val: string) => {
89
+ setNumber(val);
90
+ const fullNumber = `+${getCountryCallingCode(country)}${val.replace(
91
+ /\D/g,
92
+ '',
93
+ )}`;
94
+ (onChangeText as any)?.(fullNumber);
95
+ };
96
+
97
+ const rawTheme = useGetColors();
98
+ const colorTheme = useMemo(() => rawTheme, [rawTheme]);
99
+
100
+ const {theme, deviceBreakpoint} = useSliceTheme();
101
+ const isWebMobile =
102
+ isWeb && (deviceBreakpoint === 'xs' || deviceBreakpoint === 'sm');
103
+ const responsiveSize = useMemo(
104
+ () => resolveVariant(size, deviceBreakpoint) as InputSizeType,
105
+ [size, deviceBreakpoint],
106
+ );
107
+
108
+ const selectLogic = useSelectLogic({
109
+ variant: normalizedVariant,
110
+ value,
111
+ options,
112
+ searchable,
113
+ normalizedMultiple,
114
+ onChangeText,
115
+ disabled,
116
+ maxAllowed: rest.maxAllowed,
117
+ focusInput: () => {
118
+ requestAnimationFrame(() => {
119
+ inputRef.current?.focus();
120
+ });
121
+ },
122
+ });
123
+ const {registerOptionRef} = selectLogic;
124
+
125
+ const focusSearchInput = useCallback(() => {
126
+ if (!isWeb || normalizedVariant !== 'select' || !searchable) {
127
+ return;
128
+ }
129
+
130
+ requestAnimationFrame(() => {
131
+ inputRef.current?.focus?.();
132
+ });
133
+ }, [normalizedVariant, searchable]);
134
+
135
+ const handleSelectOpen = useCallback(() => {
136
+ if (!disabled) {
137
+ if (selectLogic.suppressNextOpenRef.current) {
138
+ selectLogic.suppressNextOpenRef.current = false;
139
+ return;
140
+ }
141
+ selectLogic.setSelectDropdownOpen(true);
142
+ focusSearchInput();
143
+ }
144
+ }, [disabled, selectLogic, focusSearchInput]);
145
+
146
+ const handleSelectClose = useCallback(() => {
147
+ selectLogic.setSelectDropdownOpen(false);
148
+ }, [selectLogic]);
149
+
150
+ const handleSelectContainerClick = useCallback(
151
+ (e: any) => {
152
+ const clickTarget = e?.target as HTMLElement | null;
153
+
154
+ if (clickTarget?.closest?.('.select-dropdown')) {
155
+ return;
156
+ }
157
+
158
+ handleSelectOpen();
159
+ },
160
+ [handleSelectOpen],
161
+ );
162
+
163
+ const {isFocused, setIsFocused, hasValue} = useInputState({
164
+ value,
165
+ hover,
166
+ normalizedMultiple,
167
+ variant: normalizedVariant,
168
+ });
169
+
170
+ const handleInputFocus = useCallback(
171
+ (e: any) => {
172
+ setIsFocused(true);
173
+ onFocus?.(e);
174
+ },
175
+ [onFocus, setIsFocused],
176
+ );
177
+
178
+ const handleInputBlur = useCallback(
179
+ (e: any) => {
180
+ setIsFocused(false);
181
+ onBlur?.(e);
182
+ },
183
+ [onBlur, setIsFocused],
184
+ );
185
+
186
+ const {animatedStyle} = useLabelAnimation({
187
+ value,
188
+ hasValue,
189
+ isFocused,
190
+ variant: normalizedVariant,
191
+ size: responsiveSize,
192
+ prefixIcon: !!prefixIcon,
193
+ selectDropdownOpen: selectLogic.selectDropdownOpen,
194
+ });
195
+
196
+ useOutsideClick({
197
+ enabled: isWeb && !isWebMobile && selectLogic.selectDropdownOpen,
198
+ onOutsideClick: handleSelectClose,
199
+ ignoredClassNames: [
200
+ 'select-dropdown',
201
+ 'select-button',
202
+ 'slice-input-container',
203
+ ],
204
+ });
205
+
206
+ const displayValue = useMemo(
207
+ () =>
208
+ getDisplayValue({
209
+ variant: normalizedVariant,
210
+ value,
211
+ options,
212
+ selectedValues: selectLogic.selectedValues,
213
+ labelText,
214
+ placeholder,
215
+ normalizedMultiple,
216
+ }),
217
+ [
218
+ normalizedVariant,
219
+ value,
220
+ options,
221
+ selectLogic.selectedValues,
222
+ labelText,
223
+ placeholder,
224
+ normalizedMultiple,
225
+ ],
226
+ );
227
+
228
+ const variantForTokens = isSelectVariant(normalizedVariant)
229
+ ? 'outlined'
230
+ : normalizedVariant;
231
+ const inputTheme =
232
+ theme.inputStyles[responsiveSize as keyof typeof theme.inputStyles]?.[
233
+ variantForTokens as keyof typeof theme.inputStyles.medium
234
+ ] ?? theme.inputStyles.medium.outlined;
235
+
236
+ const defaultSelectedIcon = useMemo(() => {
237
+ return (
238
+ <Icon
239
+ component={<IconMoon icon={FONT_ICON.TICK} />}
240
+ variant="small"
241
+ color={colors.black[1000]}
242
+ />
243
+ );
244
+ }, []);
245
+
246
+ const labelTop = useMemo(() => {
247
+ return labelTopBySize[responsiveSize] ?? 14;
248
+ }, [responsiveSize]);
249
+
250
+ const labelPositionStyle = useMemo(
251
+ () => ({
252
+ top: labelTop,
253
+ zIndex: 10,
254
+ }),
255
+ [labelTop],
256
+ );
257
+
258
+ const webContainerFocusResetStyle = useMemo(
259
+ () =>
260
+ isWeb && normalizedVariant === 'select'
261
+ ? {
262
+ ['outlineStyle' as any]: 'none',
263
+ ['outlineWidth' as any]: 0,
264
+ ['outlineColor' as any]: 'transparent',
265
+ ['boxShadow' as any]: 'none',
266
+ }
267
+ : null,
268
+ [normalizedVariant],
269
+ );
270
+
271
+ const combinedContainerStyle = [
272
+ styles.baseContainer,
273
+ inputTheme.container,
274
+ {
275
+ borderColor: error
276
+ ? colorTheme.colors.colorBorderNegative
277
+ : isFocused
278
+ ? colorTheme.colors.colorBorderStrong
279
+ : `var(--slice-input-border-color, ${colorTheme.colors.colorBorderSubtle})`,
280
+ borderWidth: isFocused ? 1.2 : 1,
281
+ borderRadius: theme.dimensions.dimension06,
282
+ ['--slice-input-font-size' as any]: inputTheme.input.fontSize,
283
+ ['--slice-input-line-height' as any]: inputTheme.input.lineHeight,
284
+ ['--slice-input-min-height' as any]: inputTheme.container.minHeight,
285
+ },
286
+ webContainerFocusResetStyle,
287
+ containerStyle,
288
+ ];
289
+
290
+ const combinedInputStyle = [
291
+ styles.baseInput,
292
+ inputTheme.input,
293
+ {
294
+ color: colorTheme.colors.colorForegroundPrimary,
295
+ paddingHorizontal: spacing.space200,
296
+ },
297
+ inputStyle,
298
+ ];
299
+
300
+ const combinedLabelStyle = [
301
+ styles.baseLabel,
302
+ inputTheme.label,
303
+ {
304
+ color: error
305
+ ? colorTheme.colors.colorForegroundNegative
306
+ : colorTheme.colors.colorForegroundLight,
307
+ backgroundColor: colorTheme.colors.colorBackgroundPrimary,
308
+ },
309
+ labelStyle,
310
+ ];
311
+
312
+ const combinedHelperTextStyle = [
313
+ styles.baseHelperText,
314
+ inputTheme.helperText,
315
+ {
316
+ color: error
317
+ ? colorTheme.colors.colorForegroundNegative
318
+ : colorTheme.colors.colorForegroundSecondary,
319
+ },
320
+ helperTextStyle,
321
+ ];
322
+
323
+ const isFullWidthVariant =
324
+ normalizedVariant === 'currency' ||
325
+ normalizedVariant === 'phoneWithFlag' ||
326
+ normalizedVariant === 'phoneWithCodeOnly';
327
+
328
+ const renderInput = () => {
329
+ switch (normalizedVariant) {
330
+ case 'currency':
331
+ return (
332
+ <CurrencyInput
333
+ value={typeof value === 'string' ? value : ''}
334
+ currency={currency}
335
+ currencyDropdownOpen={currencyDropdownOpen}
336
+ onToggleDropdown={() => setCurrencyDropdownOpen(v => !v)}
337
+ onCloseDropdown={() => setCurrencyDropdownOpen(false)}
338
+ onSelectCurrency={c => {
339
+ setCurrency(c);
340
+ setCurrencyDropdownOpen(false);
341
+ }}
342
+ disabled={disabled}
343
+ labelText={labelText}
344
+ placeholder={placeholder}
345
+ onChangeText={
346
+ onChangeText
347
+ ? (val: string) => (onChangeText as any)(val)
348
+ : undefined
349
+ }
350
+ colorTheme={colorTheme}
351
+ portalAnchorRef={webInputContainerRef}
352
+ />
353
+ );
354
+
355
+ case 'phoneWithFlag':
356
+ case 'phoneWithCodeOnly':
357
+ return (
358
+ <PhoneInput
359
+ mode={normalizedVariant === 'phoneWithFlag' ? 'flag' : 'code'}
360
+ country={country}
361
+ number={number}
362
+ dropdownOpen={dropdownOpen}
363
+ disabled={disabled}
364
+ labelText={labelText}
365
+ placeholder={placeholder}
366
+ onToggleDropdown={() => setDropdownOpen(v => !v)}
367
+ onCloseDropdown={() => setDropdownOpen(false)}
368
+ onSelectCountry={c => {
369
+ setCountry(c);
370
+ setDropdownOpen(false);
371
+ if (onChangeText) {
372
+ (onChangeText as any)(
373
+ `+${getCountryCallingCode(c)}${number.replace(/\D/g, '')}`,
374
+ );
375
+ }
376
+ }}
377
+ onNumberChange={onNumberChange}
378
+ onFocus={handleInputFocus}
379
+ onBlur={handleInputBlur}
380
+ colorTheme={colorTheme}
381
+ size={size}
382
+ portalAnchorRef={webInputContainerRef}
383
+ />
384
+ );
385
+
386
+ case 'select':
387
+ return (
388
+ <SelectInput
389
+ value={value}
390
+ displayValue={displayValue}
391
+ options={options}
392
+ searchable={searchable}
393
+ normalizedMultiple={normalizedMultiple}
394
+ normalizedListType={normalizedListType}
395
+ selectDropdownOpen={selectLogic.selectDropdownOpen}
396
+ filteredOptions={selectLogic.filteredOptions}
397
+ searchValue={selectLogic.searchValue}
398
+ setSearchValue={selectLogic.setSearchValue}
399
+ onOpen={handleSelectOpen}
400
+ onClose={handleSelectClose}
401
+ onKeyDown={selectLogic.handleSelectKeyDown}
402
+ onOptionSelect={selectLogic.handleOptionSelect}
403
+ onCheckboxToggle={selectLogic.handleCheckboxToggle}
404
+ colorTheme={colorTheme}
405
+ placeholder={placeholder}
406
+ noItemText={noItemText}
407
+ maxAllowed={rest.maxAllowed}
408
+ maxVisibleItems={maxVisibleItems}
409
+ selectedIcon={selectedIcon ?? defaultSelectedIcon}
410
+ selectedValues={selectLogic.selectedValues}
411
+ disabled={disabled}
412
+ registerOptionRef={registerOptionRef}
413
+ inputRef={inputRef}
414
+ size={responsiveSize}
415
+ expandChips={rest.expandChips}
416
+ />
417
+ );
418
+
419
+ default:
420
+ return (
421
+ <TextInputVariant
422
+ inputRef={inputRef}
423
+ value={typeof value === 'string' ? value : ''}
424
+ onChangeText={
425
+ onChangeText
426
+ ? (val: string | string[]) => {
427
+ const stringVal = typeof val === 'string' ? val : '';
428
+ (onChangeText as any)(stringVal);
429
+ }
430
+ : undefined
431
+ }
432
+ onFocus={handleInputFocus}
433
+ onBlur={handleInputBlur}
434
+ placeholder={!labelText ? placeholder : undefined}
435
+ disabled={disabled}
436
+ style={combinedInputStyle}
437
+ placeholderTextColor={colorTheme.colors.colorForegroundTertiary}
438
+ restProps={rest}
439
+ />
440
+ );
441
+ }
442
+ };
443
+
444
+ return (
445
+ <View style={styles.wrapper}>
446
+ <View
447
+ ref={webInputContainerRef}
448
+ style={combinedContainerStyle}
449
+ {...(isWeb && {
450
+ tabIndex: 0,
451
+ onFocus: () => setIsFocused(true),
452
+ onBlur: () => setIsFocused(false),
453
+ className: disabled
454
+ ? 'slice-input-container slice-input-container--disabled'
455
+ : 'slice-input-container',
456
+ onKeyDown:
457
+ normalizedVariant === 'select'
458
+ ? selectLogic.handleSelectKeyDown
459
+ : undefined,
460
+ onClick:
461
+ normalizedVariant === 'select' && !disabled
462
+ ? handleSelectContainerClick
463
+ : undefined,
464
+ })}>
465
+ {labelText && (
466
+ <Animated.Text
467
+ style={[combinedLabelStyle, animatedStyle, labelPositionStyle]}>
468
+ {labelText}
469
+ </Animated.Text>
470
+ )}
471
+
472
+ <View style={styles.inputWrapper}>
473
+ {isFullWidthVariant ? (
474
+ <View style={styles.fullWidthInputContainer}>{renderInput()}</View>
475
+ ) : (
476
+ <>
477
+ {prefixIcon && (
478
+ <View style={styles.prefixSlot}>{prefixIcon}</View>
479
+ )}
480
+
481
+ <View style={styles.inputSlot}>{renderInput()}</View>
482
+
483
+ {suffixIcon && (
484
+ <View style={styles.suffixSlot}>{suffixIcon}</View>
485
+ )}
486
+ </>
487
+ )}
488
+ </View>
489
+
490
+ {normalizedVariant === 'select' &&
491
+ isWeb &&
492
+ !isWebMobile &&
493
+ selectLogic.selectDropdownOpen &&
494
+ !disabled && (
495
+ <SelectList
496
+ options={selectLogic.filteredOptions}
497
+ value={value}
498
+ normalizedMultiple={normalizedMultiple}
499
+ normalizedListType={normalizedListType}
500
+ onOptionSelect={selectLogic.handleOptionSelect}
501
+ onCheckboxToggle={selectLogic.handleCheckboxToggle}
502
+ onKeyDown={selectLogic.handleSelectKeyDown}
503
+ colorTheme={colorTheme}
504
+ noItemText={noItemText ?? 'No items'}
505
+ maxVisibleItems={maxVisibleItems}
506
+ selectedIcon={selectedIcon ?? defaultSelectedIcon}
507
+ disabled={disabled}
508
+ registerOptionRef={registerOptionRef}
509
+ size={responsiveSize}
510
+ />
511
+ )}
512
+ </View>
513
+
514
+ {(error || helperText) && (
515
+ <Text style={combinedHelperTextStyle}>{error || helperText}</Text>
516
+ )}
517
+ </View>
518
+ );
519
+ });
520
+
521
+ const styles = StyleSheet.create({
522
+ wrapper: {
523
+ marginVertical: 8,
524
+ },
525
+ baseContainer: {
526
+ position: 'relative',
527
+ backgroundColor: 'transparent',
528
+ },
529
+ baseInput: {
530
+ flex: 1,
531
+ minHeight: 24,
532
+ fontSize: 16,
533
+ },
534
+ baseLabel: {
535
+ position: 'absolute',
536
+ left: 12,
537
+ paddingHorizontal: 4,
538
+ includeFontPadding: false,
539
+ pointerEvents: 'none',
540
+ },
541
+ baseHelperText: {
542
+ marginTop: 4,
543
+ fontSize: 12,
544
+ paddingHorizontal: 12,
545
+ },
546
+ inputWrapper: {
547
+ flexDirection: 'row',
548
+ alignItems: 'center',
549
+ minHeight: 24,
550
+ position: 'relative',
551
+ },
552
+ prefixSlot: {
553
+ justifyContent: 'center',
554
+ alignItems: 'center',
555
+ marginLeft: spacing.space100,
556
+ },
557
+
558
+ suffixSlot: {
559
+ justifyContent: 'center',
560
+ alignItems: 'center',
561
+ marginRight: spacing.space100,
562
+ },
563
+
564
+ inputSlot: {
565
+ flex: 1,
566
+ justifyContent: 'center',
567
+ },
568
+ fullWidthInputContainer: {
569
+ flex: 1,
570
+ },
571
+ });
572
+
573
+ export default Input;
@@ -0,0 +1,99 @@
1
+ ## Input Dropdown
2
+ ## Day 1 To Do
3
+ - [x] Add select and checkbox variant support with dropdown functionality
4
+ - [x] Add Multi-select Variant by adding Select-Checkbox as a variant
5
+ - [x] Display selected values with smart formatting (single, two, or "first +N" format)
6
+ - [x] Add click-outside handler to close dropdown
7
+ - [x] Update label animation to work with dropdown open state
8
+ - [x] Import and integrate Checkbox component
9
+
10
+ ## Day 2 To Do
11
+ - [x] Match Logic to Country & Currency Code Dropdown
12
+ - [x] Add Keyboard Accessibility
13
+ - [x] Add Searchable prop
14
+ - [x] Type Check the Implementation
15
+
16
+ ## Day 3 To Do
17
+ - [x] Split Files as proposed
18
+ - [x] Bug Fixes
19
+ - [x] Hover Colors
20
+ - [x] Final Type Check
21
+ - [x] Add Ability to backspace selected items for select variant
22
+ - [x] Add an No Items found Item
23
+
24
+ ## Day 4 To Do
25
+ - [x] Add Disabled State
26
+ - [x] Add Icon Support for ListItem (selected Item Icon (tick,X or anything) on right & Each item can have its own icon on left)
27
+ - [x] Add Custom Scrollbar
28
+ - [x] Add Selected Item Chip for Multi-select.
29
+ - [x] Add a Prop to Show only Max of x Items
30
+ - [x] Add sole/exact word enter in searchable
31
+ - [x] Bug fix
32
+ - [x] Keyboard Hover and Mouse Hover are independently working.Need them to work as 1 so that there isn’t 2 hover at 1 time
33
+
34
+ ## Day 5 To Do
35
+ - [x] Stablize Elements
36
+
37
+ ## Day 6 To Do
38
+ - [x] Optimize
39
+
40
+ ### Result
41
+
42
+ #### Single Select Dropdown
43
+ | Metric | Pre-Optimization | Post-Optimization | Δ (Pre → Post) |
44
+ | ---------------------------------- | ---------------- | ----------------- | -------------- |
45
+ | Total commits | 23 | 7 | -16 |
46
+ | Total render duration (ms) | 72 | 36 | -36 |
47
+ | Average commit duration (ms) | 3.13 | 5.14 | +2.01 |
48
+ | Max single commit duration (ms) | 8 | 15 | +7 |
49
+ | Total effect duration (ms) | 1 | 0 | -1 |
50
+ | Total passive effect duration (ms) | 6 | 1 | -5 |
51
+
52
+ #### Multi-Select Dropdown
53
+ | Metric | Pre-Optimization | Post-Optimization | Δ (Pre → Post) |
54
+ | ---------------------------------- | ---------------- | ----------------- | -------------- |
55
+ | Total commits | 24 | 18 | -6 |
56
+ | Total render duration (ms) | 84 | 49 | -35 |
57
+ | Average commit duration (ms) | 3.50 | 2.72 | -0.78 |
58
+ | Max single commit duration (ms) | 10 | 15 | +5 |
59
+ | Total effect duration (ms) | 2 | 1 | -1 |
60
+ | Total passive effect duration (ms) | 4 | 5 | +1 |
61
+
62
+ ## Day 7 To Do
63
+ - [x] Match Label to Design
64
+ - [x] Add Default Icon to selected Icon
65
+ - [x] Make size variants work for input based on the Tokens
66
+
67
+ ## Day 8 To Do
68
+ - [x] Add Sizes Based on design using the token styling from Chips Component
69
+ - [x] Replace Normal Text With Typography code calls
70
+ - [x] Add Size Based Animation for Labels
71
+ - [x] Match Text Styles to the design
72
+ - [x] Check Android Working
73
+
74
+ ## Day 9 To Do
75
+ - [x] Remake the Details page for Showcase
76
+ - [x] Select-Input Fixes
77
+ - [x] Move Icon to be below Animated Labels and Aligns with Item Icon
78
+ - [x] Select-Chip Icon Size Controls
79
+ - [x] Dropdown Width Matching the Parent
80
+ - [x] Align Size Based Labels Properly
81
+ - [x] Click outside to lose focus
82
+ - [x] Prepare a Documentation of what work is done
83
+ - [x] Add Native Support using bottom Sheet
84
+
85
+ ## Day 10 To Do
86
+ - [x] Edit Testscreen to support Mobile view
87
+ - [x] Mimic Input-Dropdown Web on Mobile
88
+ - [x] Features
89
+ - [x] Searchable
90
+ - [x] Max Allowed
91
+ - [x] Max Visible Items
92
+ - [x] Checkbox Support
93
+ - [x] Empty State
94
+ - [x] Styles
95
+ - [x] Add Expanded Chips for Mobile
96
+
97
+ ## Day 11 To Do
98
+ - [x] Move inline styles into Internal Stylesheet/Memonized style component (If rendered dynamically/web specific)
99
+ - []