react-native-molecules 0.5.0-beta.23 → 0.5.0-beta.25
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.
- package/components/Accordion/Accordion.tsx +1 -1
- package/components/Accordion/AccordionItem.tsx +1 -1
- package/components/Checkbox/Checkbox.tsx +2 -1
- package/components/DateField/useDateFieldState.ts +2 -2
- package/components/DatePicker/DatePickerProvider.tsx +1 -1
- package/components/DatePickerInline/DatePickerInline.tsx +1 -1
- package/components/DatePickerInline/DatePickerInlineBase.tsx +1 -1
- package/components/DatePickerInline/Day.tsx +1 -1
- package/components/DatePickerInline/Swiper.tsx +1 -1
- package/components/DatePickerInline/SwiperUtils.ts +1 -1
- package/components/DatePickerInline/dateUtils.tsx +1 -1
- package/components/DatePickerInline/store.tsx +2 -1
- package/components/Divider/index.tsx +2 -3
- package/components/ElementGroup/ElementGroup.tsx +1 -1
- package/components/FilePicker/FilePicker.tsx +1 -1
- package/components/Icon/iconFactory.tsx +2 -1
- package/components/IconButton/IconButton.tsx +39 -13
- package/components/IconButton/index.tsx +1 -0
- package/components/IconButton/types.ts +2 -0
- package/components/List/List.tsx +2 -1
- package/components/List/context.tsx +2 -1
- package/components/Portal/Portal.tsx +1 -2
- package/components/RadioButton/RadioButtonGroup.tsx +1 -2
- package/components/Rating/Rating.tsx +1 -1
- package/components/Select/Select.tsx +103 -34
- package/components/Select/context.tsx +3 -1
- package/components/Select/index.ts +20 -2
- package/components/Select/types.ts +2 -0
- package/components/Select/utils.ts +11 -4
- package/components/Switch/Switch.ios.tsx +1 -1
- package/components/Switch/Switch.tsx +2 -1
- package/components/Tabs/Tabs.tsx +2 -2
- package/components/TextInput/TextInput.tsx +4 -3
- package/components/TimePicker/AnalogClock.tsx +1 -1
- package/components/TimePicker/TimeInputs.tsx +1 -1
- package/components/TimePicker/TimePicker.tsx +1 -1
- package/components/TimePicker/TimePickerModal.tsx +1 -1
- package/components/Tooltip/Tooltip.tsx +1 -1
- package/components/TouchableRipple/TouchableRipple.tsx +1 -1
- package/hocs/index.tsx +1 -1
- package/hocs/withKeyboardAccessibility.tsx +2 -3
- package/hooks/index.tsx +2 -6
- package/hooks/useContrastColor.ts +1 -2
- package/hooks/useFilePicker.tsx +1 -1
- package/hooks/useHandleNumberFormat.tsx +2 -2
- package/hooks/useMediaQuery.tsx +1 -2
- package/package.json +95 -118
- package/shortcuts-manager/ShortcutsManager/ShortcutsManager.tsx +1 -1
- package/shortcuts-manager/ShortcutsManager/utils.tsx +1 -1
- package/shortcuts-manager/useSetScopes/useSetScopes.tsx +1 -1
- package/shortcuts-manager/useShortcut/useShortcut.tsx +1 -1
- package/utils/extractTextStyles.ts +1 -2
- package/utils/formatNumberWithMask/formatNumberWithMask.ts +2 -1
- package/utils/index.ts +0 -3
- package/utils/normalizeToNumberString/normalizeToNumberString.ts +1 -1
- package/context-bridge/index.tsx +0 -87
- package/fast-context/index.tsx +0 -190
- package/hocs/typedMemo.tsx +0 -5
- package/hooks/useControlledValue.tsx +0 -84
- package/hooks/useLatest.tsx +0 -9
- package/hooks/useMergedRefs.ts +0 -14
- package/hooks/usePrevious.ts +0 -13
- package/hooks/useToggle.tsx +0 -24
- package/hooks/useWhatHasUpdated.tsx +0 -48
- package/utils/color.ts +0 -22
- package/utils/compare/index.ts +0 -54
- package/utils/lodash.ts +0 -121
- package/utils/repository.ts +0 -53
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useControlledValue } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import {
|
|
2
3
|
type ComponentPropsWithRef,
|
|
3
4
|
createContext,
|
|
@@ -9,7 +10,6 @@ import {
|
|
|
9
10
|
} from 'react';
|
|
10
11
|
import { View } from 'react-native';
|
|
11
12
|
|
|
12
|
-
import { useControlledValue } from '../../hooks';
|
|
13
13
|
import { accordionStyles } from './utils';
|
|
14
14
|
|
|
15
15
|
export type Props = Omit<ComponentPropsWithRef<typeof View>, 'children'> & {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useControlledValue } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import {
|
|
2
3
|
forwardRef,
|
|
3
4
|
memo,
|
|
@@ -9,7 +10,6 @@ import {
|
|
|
9
10
|
} from 'react';
|
|
10
11
|
import { View, type ViewProps } from 'react-native';
|
|
11
12
|
|
|
12
|
-
import { useControlledValue } from '../../hooks';
|
|
13
13
|
import type { WithElements } from '../../types';
|
|
14
14
|
import { extractSubcomponents } from '../../utils/extractSubcomponents';
|
|
15
15
|
import { AccordionContext } from './Accordion';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { useControlledValue } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import { forwardRef, memo, useCallback, useMemo } from 'react';
|
|
2
3
|
import { View } from 'react-native';
|
|
3
4
|
|
|
4
|
-
import { useControlledValue } from '../../hooks';
|
|
5
5
|
import { resolveStateVariant } from '../../utils';
|
|
6
6
|
import { Text } from '../Text';
|
|
7
7
|
import CheckboxBase from './CheckboxBase';
|
|
@@ -50,6 +50,7 @@ const Checkbox = (
|
|
|
50
50
|
// @ts-ignore // TODO - fix this
|
|
51
51
|
state: state as States,
|
|
52
52
|
isLeading,
|
|
53
|
+
// @ts-ignore // TODO - fix this
|
|
53
54
|
size,
|
|
54
55
|
});
|
|
55
56
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { isNil } from '@react-native-molecules/utils/helpers/lodash';
|
|
2
|
+
import { useLatest } from '@react-native-molecules/utils/hooks';
|
|
1
3
|
import { type RefObject, useCallback, useEffect, useState } from 'react';
|
|
2
4
|
import type { BlurEvent, FocusEvent } from 'react-native';
|
|
3
5
|
|
|
4
|
-
import { useLatest } from '../../hooks';
|
|
5
6
|
import { endOfDay, format, isValid, parse } from '../../utils/date-fns';
|
|
6
|
-
import { isNil } from '../../utils/lodash';
|
|
7
7
|
import type { ValidRangeType } from '../DatePickerInline';
|
|
8
8
|
import { useRangeChecker } from '../DatePickerInline/dateUtils';
|
|
9
9
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { useControlledValue } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import type { ReactNode } from 'react';
|
|
2
3
|
import { memo, useCallback, useMemo, useRef, useState } from 'react';
|
|
3
4
|
|
|
4
5
|
import { getRegisteredComponentWithFallback } from '../../core';
|
|
5
|
-
import { useControlledValue } from '../../hooks';
|
|
6
6
|
import type { ValidRangeType } from '../DatePickerInline';
|
|
7
7
|
import type {
|
|
8
8
|
DatePickerContextType,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { useControlledValue } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import { memo, useCallback } from 'react';
|
|
2
3
|
import { View, type ViewStyle } from 'react-native';
|
|
3
4
|
|
|
4
|
-
import { useControlledValue } from '../../hooks';
|
|
5
5
|
import DatePickerDockedHeader from './DatePickerDockedHeader';
|
|
6
6
|
import DatePickerInlineBase from './DatePickerInlineBase';
|
|
7
7
|
import DatePickerInlineHeader from './DatePickerInlineHeader';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { useLatest } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import { memo, useCallback, useEffect, useMemo } from 'react';
|
|
2
3
|
import { StyleSheet, View } from 'react-native';
|
|
3
4
|
|
|
4
|
-
import { useLatest } from '../../hooks';
|
|
5
5
|
import { areDatesOnSameDay, dateToUnix, getEndOfDay, getInitialIndex } from './dateUtils';
|
|
6
6
|
import Month from './Month';
|
|
7
7
|
import MonthPicker from './MonthPicker';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { memo, useCallback, useMemo } from 'react';
|
|
2
2
|
import { type StyleProp, View, type ViewStyle } from 'react-native';
|
|
3
3
|
|
|
4
|
-
import { useActionState } from '../../hooks
|
|
4
|
+
import { useActionState } from '../../hooks';
|
|
5
5
|
import { resolveStateVariant } from '../../utils';
|
|
6
6
|
import { StateLayer } from '../StateLayer';
|
|
7
7
|
import { Text } from '../Text';
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useLatest } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import {
|
|
2
3
|
type CSSProperties,
|
|
3
4
|
memo,
|
|
@@ -10,7 +11,6 @@ import {
|
|
|
10
11
|
useState,
|
|
11
12
|
} from 'react';
|
|
12
13
|
|
|
13
|
-
import { useLatest } from '../../hooks';
|
|
14
14
|
import AutoSizer from './AutoSizer';
|
|
15
15
|
import { beginOffset, estimatedMonthHeight, getInitialIndex, totalMonths } from './dateUtils';
|
|
16
16
|
import { addMonths, getRealIndex } from './dateUtils';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { useLatest } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import { type RefObject, useEffect } from 'react';
|
|
2
3
|
|
|
3
|
-
import { useLatest } from '../../hooks';
|
|
4
4
|
import { addMonths, differenceInMonths, getRealIndex, startAtIndex } from './dateUtils';
|
|
5
5
|
|
|
6
6
|
export type SwiperProps = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { useLatest } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import { useCallback } from 'react';
|
|
2
3
|
|
|
3
|
-
import { useLatest } from '../../hooks';
|
|
4
4
|
import type { CalendarDate, CalendarDates, ValidRangeType } from './types';
|
|
5
5
|
|
|
6
6
|
export type DisableWeekDaysType = number[];
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
export {
|
|
2
2
|
Divider,
|
|
3
|
+
type DividerProps,
|
|
3
4
|
horizontalDividerStyles,
|
|
4
5
|
horizontalDividerStylesDefault,
|
|
6
|
+
type Props,
|
|
5
7
|
verticalDividerStyles,
|
|
6
8
|
verticalDividerStylesDefault,
|
|
7
|
-
type DividerProps,
|
|
8
|
-
type Props,
|
|
9
9
|
} from './Divider';
|
|
10
|
-
|
|
11
10
|
export { default } from './Divider';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { isNil } from '@react-native-molecules/utils/helpers/lodash';
|
|
1
2
|
import { Children, cloneElement, forwardRef, memo, type ReactElement, useMemo } from 'react';
|
|
2
3
|
import { View, type ViewProps, type ViewStyle } from 'react-native';
|
|
3
4
|
|
|
4
5
|
import { extractPropertiesFromStyles } from '../../utils/extractPropertiesFromStyles';
|
|
5
|
-
import { isNil } from '../../utils/lodash';
|
|
6
6
|
import { elementGroupStyles } from './utils';
|
|
7
7
|
|
|
8
8
|
export enum Orientation {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { useControlledValue } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import { memo, useCallback, useMemo } from 'react';
|
|
2
3
|
|
|
3
|
-
import useControlledValue from '../../hooks/useControlledValue';
|
|
4
4
|
import useFilePicker from '../../hooks/useFilePicker';
|
|
5
5
|
import type { DocumentPickerOptions, DocumentResult } from '../../utils/DocumentPicker';
|
|
6
6
|
import { IconButton } from '../IconButton';
|
|
@@ -6,16 +6,20 @@ import {
|
|
|
6
6
|
type ViewProps,
|
|
7
7
|
} from 'react-native';
|
|
8
8
|
|
|
9
|
-
import { useActionState } from '../../hooks
|
|
9
|
+
import { useActionState } from '../../hooks';
|
|
10
10
|
import { resolveStateVariant } from '../../utils';
|
|
11
11
|
import { Icon, type IconProps, type IconType } from '../Icon';
|
|
12
12
|
import CrossFadeIcon from '../Icon/CrossFadeIcon';
|
|
13
13
|
import { StateLayer } from '../StateLayer';
|
|
14
14
|
import { TouchableRipple, type TouchableRippleProps } from '../TouchableRipple';
|
|
15
|
-
import type { IconButtonVariant } from './types';
|
|
15
|
+
import type { IconButtonShape, IconButtonVariant, IconButtonWidth } from './types';
|
|
16
16
|
import { defaultStyles, iconButtonSizeToIconSizeMap } from './utils';
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const ICON_BUTTON_MIN_CONTAINER_SIZE = 32;
|
|
19
|
+
const ICON_BUTTON_CONTAINER_PADDING = 16;
|
|
20
|
+
const M3_ICON_BUTTON_NARROW_WIDTH_ADJUSTMENT = -8;
|
|
21
|
+
const M3_ICON_BUTTON_WIDE_WIDTH_ADJUSTMENT = 12;
|
|
22
|
+
const M3_ICON_BUTTON_SQUARE_CORNER_RADIUS = 12;
|
|
19
23
|
|
|
20
24
|
export type Props = Omit<TouchableRippleProps, 'children' | 'style'> & {
|
|
21
25
|
/**
|
|
@@ -26,6 +30,14 @@ export type Props = Omit<TouchableRippleProps, 'children' | 'style'> & {
|
|
|
26
30
|
* Mode of the icon button. By default there is no specified mode - only pressable icon will be rendered.
|
|
27
31
|
*/
|
|
28
32
|
variant?: IconButtonVariant;
|
|
33
|
+
/**
|
|
34
|
+
* Container shape. Material 3 supports round and square icon buttons.
|
|
35
|
+
*/
|
|
36
|
+
shape?: IconButtonShape;
|
|
37
|
+
/**
|
|
38
|
+
* Container width option. `default` maps to Material 3's uniform width.
|
|
39
|
+
*/
|
|
40
|
+
width?: IconButtonWidth;
|
|
29
41
|
/**
|
|
30
42
|
* Whether icon button is selected. A selected button receives alternative combination of icon and container colors.
|
|
31
43
|
*/
|
|
@@ -85,6 +97,8 @@ const IconButton = (
|
|
|
85
97
|
selected = false,
|
|
86
98
|
animated = false,
|
|
87
99
|
variant = 'default',
|
|
100
|
+
shape = 'round',
|
|
101
|
+
width = 'default',
|
|
88
102
|
style,
|
|
89
103
|
testID,
|
|
90
104
|
stateLayerProps = emptyObject,
|
|
@@ -126,33 +140,45 @@ const IconButton = (
|
|
|
126
140
|
} = useMemo(() => {
|
|
127
141
|
const iconSizeInNum =
|
|
128
142
|
iconButtonSizeToIconSizeMap[size as keyof typeof iconButtonSizeToIconSizeMap] ??
|
|
129
|
-
(typeof size === 'number' && size ? (size as number) :
|
|
143
|
+
(typeof size === 'number' && size ? (size as number) : 24);
|
|
144
|
+
const containerHeight = Math.max(
|
|
145
|
+
ICON_BUTTON_MIN_CONTAINER_SIZE,
|
|
146
|
+
iconSizeInNum + ICON_BUTTON_CONTAINER_PADDING,
|
|
147
|
+
);
|
|
148
|
+
const widthAdjustment =
|
|
149
|
+
width === 'narrow'
|
|
150
|
+
? M3_ICON_BUTTON_NARROW_WIDTH_ADJUSTMENT
|
|
151
|
+
: width === 'wide'
|
|
152
|
+
? M3_ICON_BUTTON_WIDE_WIDTH_ADJUSTMENT
|
|
153
|
+
: 0;
|
|
154
|
+
const containerWidth = Math.max(iconSizeInNum, containerHeight + widthAdjustment);
|
|
155
|
+
const borderRadius =
|
|
156
|
+
shape === 'round' ? containerHeight / 2 : M3_ICON_BUTTON_SQUARE_CORNER_RADIUS;
|
|
130
157
|
|
|
131
158
|
return {
|
|
132
159
|
iconColor: _iconColor,
|
|
133
160
|
iconSize: iconSizeInNum,
|
|
134
161
|
containerStyle: [
|
|
135
|
-
iconSizeInNum
|
|
136
|
-
? {
|
|
137
|
-
width: iconSizeInNum + whiteSpace,
|
|
138
|
-
height: iconSizeInNum + whiteSpace,
|
|
139
|
-
}
|
|
140
|
-
: {},
|
|
141
162
|
defaultStyles.root,
|
|
163
|
+
{
|
|
164
|
+
width: containerWidth,
|
|
165
|
+
height: containerHeight,
|
|
166
|
+
borderRadius,
|
|
167
|
+
},
|
|
142
168
|
style,
|
|
143
169
|
],
|
|
144
170
|
iconStyle: [defaultStyles.icon, iconStyleProp],
|
|
145
171
|
// accessibilityTraits: disabled ? ['button', 'disabled'] : 'button',
|
|
146
172
|
accessibilityState: { disabled },
|
|
147
|
-
stateLayerStyle: [defaultStyles.stateLayer, stateLayerProps?.style],
|
|
173
|
+
stateLayerStyle: [defaultStyles.stateLayer, { borderRadius }, stateLayerProps?.style],
|
|
148
174
|
};
|
|
149
175
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
150
|
-
}, [_iconColor, disabled, size, stateLayerProps?.style, style, state, variant]);
|
|
176
|
+
}, [_iconColor, disabled, shape, size, stateLayerProps?.style, style, state, variant, width]);
|
|
151
177
|
|
|
152
178
|
return (
|
|
153
179
|
<TouchableRipple
|
|
154
180
|
borderless
|
|
155
|
-
centered
|
|
181
|
+
centered={shape === 'round' && width === 'default'}
|
|
156
182
|
onPress={onPress}
|
|
157
183
|
rippleAlpha={0.12}
|
|
158
184
|
accessibilityLabel={accessibilityLabel}
|
|
@@ -4,4 +4,5 @@ import IconButtonDefault from './IconButton';
|
|
|
4
4
|
export const IconButton = getRegisteredComponentWithFallback('IconButton', IconButtonDefault);
|
|
5
5
|
|
|
6
6
|
export type { Props as IconButtonProps } from './IconButton';
|
|
7
|
+
export type * from './types';
|
|
7
8
|
export { defaultStyles } from './utils';
|
package/components/List/List.tsx
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { useControlledValue, useLatest } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import { memo, useCallback, useMemo } from 'react';
|
|
2
3
|
import { ScrollView, type StyleProp, type ViewStyle } from 'react-native';
|
|
3
4
|
|
|
4
5
|
import { typedMemo } from '../../hocs';
|
|
5
|
-
import { useActionState
|
|
6
|
+
import { useActionState } from '../../hooks';
|
|
6
7
|
import { resolveStateVariant } from '../../utils';
|
|
7
8
|
import { StateLayer } from '../StateLayer';
|
|
8
9
|
import { TouchableRipple } from '../TouchableRipple';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Portal as GorhomPortal } from '@gorhom/portal';
|
|
2
|
+
import { createContextBridge } from '@react-native-molecules/utils/context-bridge';
|
|
2
3
|
import { type ComponentType, type ReactNode } from 'react';
|
|
3
4
|
|
|
4
|
-
import { createContextBridge } from '../../context-bridge';
|
|
5
|
-
|
|
6
5
|
const { BridgedComponent: Portal, registerContextToBridge: registerPortalContext } =
|
|
7
6
|
createContextBridge<Omit<any, 'children'> & { children: ReactNode }>(
|
|
8
7
|
'portal-context',
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { useControlledValue } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import { createContext, memo, type ReactNode, useMemo } from 'react';
|
|
2
3
|
import { View, type ViewProps } from 'react-native';
|
|
3
4
|
|
|
4
|
-
import { useControlledValue } from '../../hooks';
|
|
5
|
-
|
|
6
5
|
export type Props = ViewProps & {
|
|
7
6
|
/**
|
|
8
7
|
* Function to execute on selection change.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { useControlledValue } from '@react-native-molecules/utils/hooks';
|
|
1
2
|
import { forwardRef, memo, useMemo } from 'react';
|
|
2
3
|
import { View, type ViewProps, type ViewStyle } from 'react-native';
|
|
3
4
|
|
|
4
|
-
import { useControlledValue } from '../../hooks';
|
|
5
5
|
import type { IconProps, IconType } from '../Icon';
|
|
6
6
|
import type { TooltipProps } from '../Tooltip';
|
|
7
7
|
import RatingItem from './RatingItem';
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useControlledValue, useToggle } from '@react-native-molecules/utils/hooks';
|
|
2
|
+
import {
|
|
3
|
+
Fragment,
|
|
4
|
+
memo,
|
|
5
|
+
type ReactNode,
|
|
6
|
+
useCallback,
|
|
7
|
+
useEffect,
|
|
8
|
+
useMemo,
|
|
9
|
+
useRef,
|
|
10
|
+
useState,
|
|
11
|
+
} from 'react';
|
|
2
12
|
import {
|
|
3
13
|
type AccessibilityRole,
|
|
4
14
|
type GestureResponderEvent,
|
|
@@ -9,9 +19,8 @@ import {
|
|
|
9
19
|
} from 'react-native';
|
|
10
20
|
|
|
11
21
|
import { typedMemo } from '../../hocs';
|
|
12
|
-
import { useActionState, useControlledValue } from '../../hooks';
|
|
13
|
-
import { useToggle } from '../../hooks';
|
|
14
22
|
import { resolveStateVariant } from '../../utils';
|
|
23
|
+
import { extractSubcomponents } from '../../utils/extractSubcomponents';
|
|
15
24
|
import { Chip } from '../Chip';
|
|
16
25
|
import { Icon } from '../Icon';
|
|
17
26
|
import { IconButton } from '../IconButton';
|
|
@@ -24,6 +33,7 @@ import {
|
|
|
24
33
|
SelectSearchContextProvider,
|
|
25
34
|
useSelectContextValue,
|
|
26
35
|
useSelectDropdownContextValue,
|
|
36
|
+
useSelectDropdownStoreRef,
|
|
27
37
|
useSelectSearchContextValue,
|
|
28
38
|
} from './context';
|
|
29
39
|
import type {
|
|
@@ -35,21 +45,50 @@ import type {
|
|
|
35
45
|
SelectSearchContextValue,
|
|
36
46
|
SelectSearchInputProps,
|
|
37
47
|
SelectSearchKey,
|
|
48
|
+
SelectTriggerOutlineProps,
|
|
38
49
|
SelectTriggerProps,
|
|
39
50
|
SelectValueProps,
|
|
40
51
|
} from './types';
|
|
41
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
collectWebSelectKeyboardOptionElements,
|
|
54
|
+
selectOutlineStyles,
|
|
55
|
+
styles,
|
|
56
|
+
triggerStyles,
|
|
57
|
+
} from './utils';
|
|
42
58
|
|
|
43
59
|
const emptyArr: unknown[] = [];
|
|
44
60
|
|
|
45
|
-
const
|
|
61
|
+
export const getSelectTriggerState = ({
|
|
62
|
+
isOpen,
|
|
63
|
+
hovered,
|
|
64
|
+
disabled,
|
|
65
|
+
error,
|
|
66
|
+
}: {
|
|
67
|
+
isOpen: boolean;
|
|
68
|
+
hovered: boolean;
|
|
69
|
+
disabled: boolean;
|
|
70
|
+
error: boolean;
|
|
71
|
+
}) =>
|
|
72
|
+
resolveStateVariant({
|
|
73
|
+
focused: isOpen,
|
|
74
|
+
hovered,
|
|
75
|
+
disabled,
|
|
76
|
+
error,
|
|
77
|
+
hoveredAndFocused: hovered && isOpen,
|
|
78
|
+
errorFocused: error && isOpen,
|
|
79
|
+
errorHovered: error && hovered,
|
|
80
|
+
errorFocusedAndHovered: error && isOpen && hovered,
|
|
81
|
+
errorDisabled: error && disabled,
|
|
82
|
+
}) as any;
|
|
83
|
+
|
|
84
|
+
export const getDisplayLabel = (item: DefaultItemT, labelKey?: string) => {
|
|
46
85
|
const itemLabelKey = typeof item.labelKey === 'string' ? item.labelKey : undefined;
|
|
47
86
|
const key = labelKey ?? itemLabelKey ?? 'label';
|
|
48
87
|
const value = item[key];
|
|
49
88
|
return value == null ? String(item.id) : String(value);
|
|
50
89
|
};
|
|
51
90
|
|
|
52
|
-
const getNested = (item: unknown, path: string): unknown => {
|
|
91
|
+
export const getNested = (item: unknown, path: string): unknown => {
|
|
53
92
|
if (item == null || typeof item !== 'object') return undefined;
|
|
54
93
|
if (!path.includes('.')) return (item as Record<string, unknown>)[path];
|
|
55
94
|
let val: unknown = item;
|
|
@@ -60,12 +99,12 @@ const getNested = (item: unknown, path: string): unknown => {
|
|
|
60
99
|
return val;
|
|
61
100
|
};
|
|
62
101
|
|
|
63
|
-
const matchesByKey = (item: unknown, key: string, lowerQuery: string): boolean =>
|
|
102
|
+
export const matchesByKey = (item: unknown, key: string, lowerQuery: string): boolean =>
|
|
64
103
|
String(getNested(item, key) ?? '')
|
|
65
104
|
.toLowerCase()
|
|
66
105
|
.includes(lowerQuery);
|
|
67
106
|
|
|
68
|
-
const applySearch = <T extends object>(
|
|
107
|
+
export const applySearch = <T extends object>(
|
|
69
108
|
items: T[],
|
|
70
109
|
searchKey: SelectSearchKey<T> | undefined,
|
|
71
110
|
query: string,
|
|
@@ -79,13 +118,13 @@ const applySearch = <T extends object>(
|
|
|
79
118
|
return items.filter(item => keys.some(key => matchesByKey(item, key, lowerQuery)));
|
|
80
119
|
};
|
|
81
120
|
|
|
82
|
-
const SelectDropdownProvider = memo(
|
|
121
|
+
export const SelectDropdownProvider = memo(
|
|
83
122
|
({
|
|
84
123
|
children,
|
|
85
124
|
isOpen: isOpenProp,
|
|
86
125
|
onClose: onCloseProp,
|
|
87
126
|
}: {
|
|
88
|
-
children:
|
|
127
|
+
children: ReactNode;
|
|
89
128
|
isOpen?: boolean;
|
|
90
129
|
onClose?: () => void;
|
|
91
130
|
}) => {
|
|
@@ -217,7 +256,7 @@ export const SelectContent = typedMemo(
|
|
|
217
256
|
},
|
|
218
257
|
);
|
|
219
258
|
|
|
220
|
-
export const SelectTrigger = ({ children, style, ...rest }: SelectTriggerProps) => {
|
|
259
|
+
export const SelectTrigger = memo(({ children, style, ...rest }: SelectTriggerProps) => {
|
|
221
260
|
const { isOpen, onOpen, onClose, triggerRef, setTriggerLayout } = useSelectDropdownContextValue(
|
|
222
261
|
state => ({
|
|
223
262
|
isOpen: state.isOpen,
|
|
@@ -227,26 +266,28 @@ export const SelectTrigger = ({ children, style, ...rest }: SelectTriggerProps)
|
|
|
227
266
|
setTriggerLayout: state.setTriggerLayout,
|
|
228
267
|
}),
|
|
229
268
|
);
|
|
269
|
+
const setSelectDropdownContext = useSelectDropdownStoreRef().set;
|
|
230
270
|
|
|
231
271
|
const { disabled, error } = useSelectContextValue(state => ({
|
|
232
272
|
disabled: state.disabled,
|
|
233
273
|
error: state.error,
|
|
234
274
|
}));
|
|
235
275
|
|
|
236
|
-
const
|
|
276
|
+
const [hovered, setHovered] = useState(false);
|
|
277
|
+
|
|
278
|
+
const { Select_TriggerOutline, rest: restChildren } = extractSubcomponents({
|
|
279
|
+
children,
|
|
280
|
+
allowedChildren: [{ name: 'Select_TriggerOutline', allowMultiple: false }] as const,
|
|
281
|
+
includeRest: true,
|
|
282
|
+
});
|
|
237
283
|
|
|
238
284
|
triggerStyles.useVariants({
|
|
239
|
-
state:
|
|
240
|
-
|
|
285
|
+
state: getSelectTriggerState({
|
|
286
|
+
isOpen,
|
|
241
287
|
hovered,
|
|
242
288
|
disabled: !!disabled,
|
|
243
289
|
error: !!error,
|
|
244
|
-
|
|
245
|
-
errorFocused: !!error && isOpen,
|
|
246
|
-
errorHovered: !!error && hovered,
|
|
247
|
-
errorFocusedAndHovered: !!error && isOpen && hovered,
|
|
248
|
-
errorDisabled: !!error && !!disabled,
|
|
249
|
-
}) as any,
|
|
290
|
+
}),
|
|
250
291
|
});
|
|
251
292
|
|
|
252
293
|
const handleLayout = useCallback(
|
|
@@ -266,29 +307,67 @@ export const SelectTrigger = ({ children, style, ...rest }: SelectTriggerProps)
|
|
|
266
307
|
}
|
|
267
308
|
}, [isOpen, onOpen, onClose, disabled]);
|
|
268
309
|
|
|
310
|
+
const handleHoverIn = useCallback(() => {
|
|
311
|
+
setHovered(true);
|
|
312
|
+
setSelectDropdownContext(() => ({ triggerHovered: true }));
|
|
313
|
+
}, [setSelectDropdownContext]);
|
|
314
|
+
|
|
315
|
+
const handleHoverOut = useCallback(() => {
|
|
316
|
+
setHovered(false);
|
|
317
|
+
setSelectDropdownContext(() => ({ triggerHovered: false }));
|
|
318
|
+
}, [setSelectDropdownContext]);
|
|
319
|
+
|
|
320
|
+
const outlineElement =
|
|
321
|
+
Select_TriggerOutline.length > 0 ? Select_TriggerOutline : <SelectTriggerOutline />;
|
|
322
|
+
|
|
269
323
|
return (
|
|
270
324
|
<Pressable
|
|
271
325
|
ref={triggerRef}
|
|
272
326
|
onPress={handlePress}
|
|
273
327
|
onLayout={handleLayout}
|
|
328
|
+
onHoverIn={handleHoverIn}
|
|
329
|
+
onHoverOut={handleHoverOut}
|
|
274
330
|
style={[triggerStyles.trigger, style]}
|
|
275
331
|
accessibilityRole="combobox"
|
|
276
332
|
accessibilityState={{ expanded: isOpen, disabled: !!disabled }}
|
|
277
333
|
disabled={disabled}
|
|
278
334
|
{...rest}>
|
|
279
|
-
{
|
|
335
|
+
{restChildren}
|
|
280
336
|
<Icon
|
|
281
337
|
name={isOpen ? 'chevron-up' : 'chevron-down'}
|
|
282
338
|
size={20}
|
|
283
339
|
style={triggerStyles.triggerIcon}
|
|
284
340
|
/>
|
|
285
|
-
|
|
341
|
+
{outlineElement}
|
|
286
342
|
</Pressable>
|
|
287
343
|
);
|
|
288
|
-
};
|
|
344
|
+
});
|
|
289
345
|
|
|
290
346
|
SelectTrigger.displayName = 'Select_Trigger';
|
|
291
347
|
|
|
348
|
+
export const SelectTriggerOutline = memo(({ style }: SelectTriggerOutlineProps) => {
|
|
349
|
+
const { isOpen, triggerHovered } = useSelectDropdownContextValue(state => ({
|
|
350
|
+
isOpen: state.isOpen,
|
|
351
|
+
triggerHovered: state.triggerHovered,
|
|
352
|
+
}));
|
|
353
|
+
const { disabled, error } = useSelectContextValue(state => ({
|
|
354
|
+
disabled: state.disabled,
|
|
355
|
+
error: state.error,
|
|
356
|
+
}));
|
|
357
|
+
selectOutlineStyles.useVariants({
|
|
358
|
+
state: getSelectTriggerState({
|
|
359
|
+
isOpen,
|
|
360
|
+
hovered: !!triggerHovered,
|
|
361
|
+
disabled: !!disabled,
|
|
362
|
+
error: !!error,
|
|
363
|
+
}),
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
return <View pointerEvents="none" style={[selectOutlineStyles.outline, style]} />;
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
SelectTriggerOutline.displayName = 'Select_TriggerOutline';
|
|
370
|
+
|
|
292
371
|
export const SelectValue = memo(
|
|
293
372
|
({ placeholder, labelKey, renderValue, style, ...rest }: SelectValueProps) => {
|
|
294
373
|
const { value, multiple, onRemove } = useSelectContextValue(state => ({
|
|
@@ -692,14 +771,4 @@ export const SelectSearchInput = memo(({ children, ...textInputProps }: SelectSe
|
|
|
692
771
|
|
|
693
772
|
SelectSearchInput.displayName = 'Select_SearchInput';
|
|
694
773
|
|
|
695
|
-
|
|
696
|
-
Trigger: SelectTrigger,
|
|
697
|
-
Value: SelectValue,
|
|
698
|
-
Dropdown: SelectDropdown,
|
|
699
|
-
Content: SelectContent,
|
|
700
|
-
Option: SelectOption,
|
|
701
|
-
SearchInput: SelectSearchInput,
|
|
702
|
-
});
|
|
703
|
-
|
|
704
|
-
export default SelectWithSubcomponents;
|
|
705
|
-
export { SelectDropdownProvider };
|
|
774
|
+
export default SelectRoot;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { createFastContext } from '@react-native-molecules/utils/fast-context';
|
|
1
2
|
import type { View } from 'react-native';
|
|
2
3
|
|
|
3
|
-
import { createFastContext } from '../../fast-context';
|
|
4
4
|
import {
|
|
5
5
|
ListContext,
|
|
6
6
|
ListContextProvider,
|
|
@@ -24,6 +24,7 @@ export type SelectDropdownContextType = SelectDropdownContextValue & {
|
|
|
24
24
|
triggerRef: React.RefObject<View> | null;
|
|
25
25
|
triggerLayout: { width: number; height: number } | null;
|
|
26
26
|
setTriggerLayout: (layout: { width: number; height: number }) => void;
|
|
27
|
+
triggerHovered?: boolean;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
const selectDropdownContextDefaultValue: SelectDropdownContextType = {
|
|
@@ -33,6 +34,7 @@ const selectDropdownContextDefaultValue: SelectDropdownContextType = {
|
|
|
33
34
|
triggerRef: null,
|
|
34
35
|
triggerLayout: null,
|
|
35
36
|
setTriggerLayout: () => {},
|
|
37
|
+
triggerHovered: false,
|
|
36
38
|
};
|
|
37
39
|
|
|
38
40
|
const {
|
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
import { getRegisteredComponentWithFallback } from '../../core';
|
|
2
|
-
import
|
|
2
|
+
import SelectRoot, {
|
|
3
|
+
SelectContent,
|
|
4
|
+
SelectDropdown,
|
|
5
|
+
SelectOption,
|
|
6
|
+
SelectSearchInput,
|
|
7
|
+
SelectTrigger,
|
|
8
|
+
SelectTriggerOutline,
|
|
9
|
+
SelectValue,
|
|
10
|
+
} from './Select';
|
|
3
11
|
|
|
4
|
-
|
|
12
|
+
const SelectWithSubcomponents = Object.assign(SelectRoot, {
|
|
13
|
+
Trigger: SelectTrigger,
|
|
14
|
+
TriggerOutline: SelectTriggerOutline,
|
|
15
|
+
Value: SelectValue,
|
|
16
|
+
Dropdown: SelectDropdown,
|
|
17
|
+
Content: SelectContent,
|
|
18
|
+
Option: SelectOption,
|
|
19
|
+
SearchInput: SelectSearchInput,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const Select = getRegisteredComponentWithFallback('Select', SelectWithSubcomponents);
|
|
5
23
|
|
|
6
24
|
export * from './context';
|
|
7
25
|
export type * from './types';
|