@seed-design/lynx-react 0.2.0-alpha.2 → 0.2.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.
- package/lib/_virtual/_rolldown/runtime.js +13 -0
- package/lib/components/ActionButton/ActionButton.d.ts +26 -32
- package/lib/components/ActionButton/ActionButton.d.ts.map +1 -1
- package/lib/components/ActionButton/ActionButton.jsx +139 -120
- package/lib/components/ActionButton/index.d.ts +1 -1
- package/lib/components/AppBar/AppBar.d.ts +35 -0
- package/lib/components/AppBar/AppBar.d.ts.map +1 -0
- package/lib/components/AppBar/AppBar.jsx +132 -0
- package/lib/components/AppBar/AppBar.namespace.d.ts +2 -0
- package/lib/components/AppBar/AppBar.namespace.d.ts.map +1 -0
- package/lib/components/AppBar/AppBar.namespace.js +15 -0
- package/lib/components/AppBar/context.d.ts +13 -0
- package/lib/components/AppBar/context.d.ts.map +1 -0
- package/lib/components/AppBar/context.js +12 -0
- package/lib/components/AppBar/index.d.ts +3 -0
- package/lib/components/AppBar/index.d.ts.map +1 -0
- package/lib/components/AppBar/useAppBar.d.ts +15 -0
- package/lib/components/AppBar/useAppBar.d.ts.map +1 -0
- package/lib/components/AppBar/useAppBar.js +72 -0
- package/lib/components/Badge/Badge.d.ts +14 -0
- package/lib/components/Badge/Badge.d.ts.map +1 -0
- package/lib/components/Badge/Badge.jsx +15 -0
- package/lib/components/Badge/index.d.ts +2 -0
- package/lib/components/Badge/index.d.ts.map +1 -0
- package/lib/components/BottomSheet/BottomSheet.d.ts +22 -27
- package/lib/components/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/lib/components/BottomSheet/BottomSheet.jsx +127 -142
- package/lib/components/BottomSheet/BottomSheet.namespace.d.ts +1 -1
- package/lib/components/BottomSheet/BottomSheet.namespace.js +18 -1
- package/lib/components/BottomSheet/index.d.ts +2 -2
- package/lib/components/Box/Box.d.ts +20 -0
- package/lib/components/Box/Box.d.ts.map +1 -0
- package/lib/components/Box/Box.jsx +14 -0
- package/lib/components/Box/index.d.ts +2 -0
- package/lib/components/Box/index.d.ts.map +1 -0
- package/lib/components/Checkbox/Checkbox.d.ts +14 -30
- package/lib/components/Checkbox/Checkbox.d.ts.map +1 -1
- package/lib/components/Checkbox/Checkbox.jsx +107 -98
- package/lib/components/Checkbox/Checkbox.namespace.d.ts +1 -1
- package/lib/components/Checkbox/Checkbox.namespace.js +12 -1
- package/lib/components/Checkbox/index.d.ts +2 -2
- package/lib/components/Icon/Icon.d.ts +37 -0
- package/lib/components/Icon/Icon.d.ts.map +1 -0
- package/lib/components/Icon/Icon.jsx +143 -0
- package/lib/components/Icon/index.d.ts +2 -0
- package/lib/components/Icon/index.d.ts.map +1 -0
- package/lib/components/ProgressCircle/ProgressCircle.d.ts +4 -8
- package/lib/components/ProgressCircle/ProgressCircle.d.ts.map +1 -1
- package/lib/components/ProgressCircle/ProgressCircle.jsx +255 -260
- package/lib/components/ProgressCircle/ProgressCircle.namespace.d.ts +1 -1
- package/lib/components/ProgressCircle/ProgressCircle.namespace.js +9 -1
- package/lib/components/ProgressCircle/index.d.ts +2 -2
- package/lib/components/RadioGroup/RadioGroup.d.ts +12 -28
- package/lib/components/RadioGroup/RadioGroup.d.ts.map +1 -1
- package/lib/components/RadioGroup/RadioGroup.jsx +134 -118
- package/lib/components/RadioGroup/RadioGroup.namespace.d.ts +1 -1
- package/lib/components/RadioGroup/RadioGroup.namespace.js +12 -1
- package/lib/components/RadioGroup/index.d.ts +2 -2
- package/lib/components/Stack/Stack.d.ts +33 -0
- package/lib/components/Stack/Stack.d.ts.map +1 -0
- package/lib/components/Stack/Stack.jsx +39 -0
- package/lib/components/Stack/index.d.ts +2 -0
- package/lib/components/Stack/index.d.ts.map +1 -0
- package/lib/components/Switch/Switch.d.ts +8 -14
- package/lib/components/Switch/Switch.d.ts.map +1 -1
- package/lib/components/Switch/Switch.jsx +82 -56
- package/lib/components/Switch/Switch.namespace.d.ts +1 -1
- package/lib/components/Switch/Switch.namespace.js +11 -1
- package/lib/components/Switch/index.d.ts +2 -2
- package/lib/components/TagGroup/TagGroup.d.ts +8 -14
- package/lib/components/TagGroup/TagGroup.d.ts.map +1 -1
- package/lib/components/TagGroup/TagGroup.jsx +42 -39
- package/lib/components/TagGroup/TagGroup.namespace.d.ts +1 -1
- package/lib/components/TagGroup/TagGroup.namespace.js +10 -1
- package/lib/components/TagGroup/index.d.ts +2 -2
- package/lib/components/Text/Text.d.ts +7 -0
- package/lib/components/Text/Text.d.ts.map +1 -0
- package/lib/components/Text/Text.jsx +28 -0
- package/lib/components/Text/index.d.ts +2 -0
- package/lib/components/Text/index.d.ts.map +1 -0
- package/lib/components/index.d.ts +13 -7
- package/lib/components/index.d.ts.map +1 -1
- package/lib/hooks/index.d.ts +4 -3
- package/lib/hooks/index.d.ts.map +1 -1
- package/lib/hooks/{use-controllable-state.d.ts → useControllableState.d.ts} +1 -1
- package/lib/hooks/useControllableState.d.ts.map +1 -0
- package/lib/hooks/useControllableState.js +27 -0
- package/lib/hooks/useIconColor.d.ts +19 -0
- package/lib/hooks/useIconColor.d.ts.map +1 -0
- package/lib/hooks/useIconColor.js +38 -0
- package/lib/hooks/{use-press-tap.d.ts → usePressTap.d.ts} +12 -9
- package/lib/hooks/usePressTap.d.ts.map +1 -0
- package/lib/hooks/usePressTap.js +35 -0
- package/lib/hooks/useSafeArea.d.ts +19 -0
- package/lib/hooks/useSafeArea.d.ts.map +1 -0
- package/lib/hooks/useSafeArea.js +33 -0
- package/lib/index.d.ts +4 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +29 -3
- package/lib/types.d.ts +51 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/utils/children.d.ts +3 -0
- package/lib/utils/children.d.ts.map +1 -0
- package/lib/utils/children.js +8 -0
- package/lib/utils/create-slot-recipe-context.d.ts +13 -12
- package/lib/utils/create-slot-recipe-context.d.ts.map +1 -1
- package/lib/utils/create-slot-recipe-context.jsx +88 -70
- package/lib/utils/get-seed-class-name.d.ts +6 -7
- package/lib/utils/get-seed-class-name.d.ts.map +1 -1
- package/lib/utils/get-seed-class-name.js +26 -37
- package/lib/utils/index.d.ts +4 -4
- package/lib/utils/resolve-recipe-token.js +45 -43
- package/lib/utils/split-multiple-variants-props.js +32 -32
- package/lib/utils/styled.d.ts +83 -0
- package/lib/utils/styled.d.ts.map +1 -0
- package/lib/utils/styled.js +144 -0
- package/package.json +9 -9
- package/src/components/ActionButton/ActionButton.test.tsx +167 -0
- package/src/components/ActionButton/ActionButton.tsx +210 -168
- package/src/components/AppBar/AppBar.namespace.ts +18 -0
- package/src/components/AppBar/AppBar.test.tsx +270 -0
- package/src/components/AppBar/AppBar.tsx +288 -0
- package/src/components/AppBar/context.ts +27 -0
- package/src/components/AppBar/index.ts +21 -0
- package/src/components/AppBar/useAppBar.ts +100 -0
- package/src/components/Badge/Badge.test.tsx +54 -0
- package/src/components/Badge/Badge.tsx +32 -0
- package/src/components/Badge/index.ts +1 -0
- package/src/components/BottomSheet/BottomSheet.test.tsx +219 -0
- package/src/components/BottomSheet/BottomSheet.tsx +120 -83
- package/src/components/Box/Box.test.tsx +85 -0
- package/src/components/Box/Box.tsx +39 -0
- package/src/components/Box/index.ts +1 -0
- package/src/components/Checkbox/Checkbox.tsx +108 -117
- package/src/components/Icon/Icon.tsx +265 -0
- package/src/components/Icon/index.ts +8 -0
- package/src/components/ProgressCircle/ProgressCircle.tsx +39 -25
- package/src/components/RadioGroup/RadioGroup.tsx +100 -118
- package/src/components/Stack/Stack.tsx +97 -0
- package/src/components/Stack/index.ts +1 -0
- package/src/components/Switch/Switch.tsx +61 -52
- package/src/components/TagGroup/TagGroup.tsx +27 -25
- package/src/components/Text/Text.tsx +64 -0
- package/src/components/Text/index.ts +1 -0
- package/src/components/index.ts +6 -0
- package/src/hooks/index.ts +4 -3
- package/src/hooks/{__tests__/use-controllable-state.test.ts → useControllableState.test.ts} +1 -1
- package/src/hooks/useIconColor.test.ts +13 -0
- package/src/hooks/useIconColor.ts +67 -0
- package/src/hooks/{__tests__/use-press-tap.test.ts → usePressTap.test.ts} +1 -1
- package/src/hooks/{use-press-tap.ts → usePressTap.ts} +14 -10
- package/src/hooks/useSafeArea.test.ts +83 -0
- package/src/hooks/useSafeArea.ts +56 -0
- package/src/index.ts +1 -0
- package/src/types.ts +76 -0
- package/src/utils/children.ts +13 -0
- package/src/utils/create-slot-recipe-context.test.tsx +96 -0
- package/src/utils/create-slot-recipe-context.tsx +55 -15
- package/src/utils/get-seed-class-name.ts +7 -12
- package/src/utils/{__tests__/split-multiple-variants-props.test.ts → split-multiple-variants-props.test.ts} +1 -1
- package/src/utils/styled.ts +442 -0
- package/lib/components/ActionButton/index.js +0 -1
- package/lib/components/BottomSheet/index.js +0 -2
- package/lib/components/Checkbox/index.js +0 -2
- package/lib/components/ProgressCircle/index.js +0 -2
- package/lib/components/RadioGroup/index.js +0 -2
- package/lib/components/Switch/index.js +0 -2
- package/lib/components/TagGroup/index.js +0 -2
- package/lib/components/index.js +0 -7
- package/lib/hooks/index.js +0 -3
- package/lib/hooks/use-controllable-state.d.ts.map +0 -1
- package/lib/hooks/use-controllable-state.js +0 -27
- package/lib/hooks/use-icon-color.d.ts +0 -15
- package/lib/hooks/use-icon-color.d.ts.map +0 -1
- package/lib/hooks/use-icon-color.js +0 -37
- package/lib/hooks/use-press-tap.d.ts.map +0 -1
- package/lib/hooks/use-press-tap.js +0 -35
- package/lib/utils/index.js +0 -4
- package/src/components/ActionButton/__tests__/ActionButton.test.tsx +0 -35
- package/src/components/BottomSheet/__tests__/BottomSheet.test.tsx +0 -119
- package/src/components/__tests__/ProgressCircle.test.ts +0 -33
- package/src/components/__tests__/exports.test.ts +0 -38
- package/src/components/__tests__/switch.test.ts +0 -34
- package/src/hooks/use-icon-color.ts +0 -51
- package/src/utils/__tests__/create-slot-recipe-context.test.tsx +0 -228
- /package/src/hooks/{use-controllable-state.ts → useControllableState.ts} +0 -0
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {
|
|
1
|
+
import * as React from "@lynx-js/react";
|
|
2
|
+
import { isValidElement, type ReactElement } from "@lynx-js/react";
|
|
3
3
|
import clsx from "clsx";
|
|
4
|
-
import type { MainThread } from "@lynx-js/types";
|
|
5
4
|
|
|
6
5
|
import { checkbox } from "@seed-design/lynx-css/recipes/checkbox";
|
|
7
6
|
import type { CheckboxVariantProps } from "@seed-design/lynx-css/recipes/checkbox";
|
|
8
7
|
import { checkmark } from "@seed-design/lynx-css/recipes/checkmark";
|
|
9
8
|
import type { CheckmarkVariantProps } from "@seed-design/lynx-css/recipes/checkmark";
|
|
10
9
|
import { checkboxGroup } from "@seed-design/lynx-css/recipes/checkbox-group";
|
|
11
|
-
import { vars as checkmarkVars } from "@seed-design/lynx-css/vars/component/checkmark";
|
|
12
10
|
|
|
13
|
-
import { useControllableState } from "../../hooks/
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
11
|
+
import { useControllableState } from "../../hooks/useControllableState";
|
|
12
|
+
import { usePressTap } from "../../hooks/usePressTap";
|
|
13
|
+
import type {
|
|
14
|
+
LynxIconElementProps,
|
|
15
|
+
LynxStyledElementProps,
|
|
16
|
+
LynxTextRef,
|
|
17
|
+
LynxViewRef,
|
|
18
|
+
} from "../../types";
|
|
17
19
|
import { splitMultipleVariantsProps } from "../../utils/split-multiple-variants-props";
|
|
20
|
+
import { InternalIcon } from "../Icon/Icon";
|
|
18
21
|
|
|
19
22
|
/**
|
|
20
23
|
* @platform Lynx
|
|
@@ -30,20 +33,14 @@ import { splitMultipleVariantsProps } from "../../utils/split-multiple-variants-
|
|
|
30
33
|
* recipe 의 `color` 토큰을 `tint-color` 로 동기화한다. raw SVG 주입은 Lynx 범위 밖.
|
|
31
34
|
*/
|
|
32
35
|
|
|
33
|
-
type CheckboxSize = NonNullable<CheckboxVariantProps["size"]>;
|
|
34
|
-
type CheckboxWeight = NonNullable<CheckboxVariantProps["weight"]>;
|
|
35
|
-
type CheckmarkTone = NonNullable<CheckmarkVariantProps["tone"]>;
|
|
36
|
-
type CheckmarkVariant = NonNullable<CheckmarkVariantProps["variant"]>;
|
|
37
|
-
|
|
38
36
|
interface CheckboxContextValue {
|
|
39
37
|
checked: boolean;
|
|
40
38
|
indeterminate: boolean;
|
|
41
39
|
disabled: boolean;
|
|
42
40
|
pressed: boolean;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
variant: CheckmarkVariant;
|
|
41
|
+
checkboxVariantProps: CheckboxVariantProps;
|
|
42
|
+
checkmarkVariantProps: CheckmarkVariantProps;
|
|
43
|
+
toggle: () => void;
|
|
47
44
|
}
|
|
48
45
|
|
|
49
46
|
const CheckboxContext = React.createContext<CheckboxContextValue | null>(null);
|
|
@@ -56,10 +53,15 @@ function useCheckboxContext(consumer: string): CheckboxContextValue {
|
|
|
56
53
|
return ctx;
|
|
57
54
|
}
|
|
58
55
|
|
|
59
|
-
|
|
56
|
+
interface CheckmarkControlContextValue {
|
|
57
|
+
iconClassName: string;
|
|
58
|
+
checkmarkVariantProps: CheckmarkVariantProps;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const CheckmarkControlContext = React.createContext<CheckmarkControlContextValue | null>(null);
|
|
60
62
|
|
|
61
|
-
function
|
|
62
|
-
const ctx = React.useContext(
|
|
63
|
+
function useCheckmarkControlContext(consumer: string): CheckmarkControlContextValue {
|
|
64
|
+
const ctx = React.useContext(CheckmarkControlContext);
|
|
63
65
|
if (!ctx) {
|
|
64
66
|
throw new Error(`<${consumer}/> must be rendered inside <CheckboxControl/>.`);
|
|
65
67
|
}
|
|
@@ -70,9 +72,8 @@ function useCheckmarkIconClass(consumer: string): string {
|
|
|
70
72
|
|
|
71
73
|
export interface CheckboxRootProps
|
|
72
74
|
extends CheckboxVariantProps,
|
|
73
|
-
Omit<CheckmarkVariantProps, "size" | "checked" | "disabled" | "indeterminate"
|
|
74
|
-
|
|
75
|
-
className?: string;
|
|
75
|
+
Omit<CheckmarkVariantProps, "size" | "checked" | "disabled" | "indeterminate">,
|
|
76
|
+
LynxStyledElementProps {
|
|
76
77
|
checked?: boolean;
|
|
77
78
|
defaultChecked?: boolean;
|
|
78
79
|
indeterminate?: boolean;
|
|
@@ -93,10 +94,6 @@ export const CheckboxRoot = React.forwardRef<unknown, CheckboxRootProps>((props,
|
|
|
93
94
|
} = props;
|
|
94
95
|
const [{ checkbox: checkboxVariantProps, checkmark: checkmarkVariantProps }, nativeProps] =
|
|
95
96
|
splitMultipleVariantsProps(restProps, { checkbox, checkmark });
|
|
96
|
-
const weight: CheckboxWeight = checkboxVariantProps.weight ?? "regular";
|
|
97
|
-
const size: CheckboxSize = checkboxVariantProps.size ?? "medium";
|
|
98
|
-
const tone: CheckmarkTone = checkmarkVariantProps.tone ?? "brand";
|
|
99
|
-
const variant: CheckmarkVariant = checkmarkVariantProps.variant ?? "square";
|
|
100
97
|
|
|
101
98
|
const [checked, setChecked] = useControllableState({
|
|
102
99
|
value: checkedProp,
|
|
@@ -104,22 +101,40 @@ export const CheckboxRoot = React.forwardRef<unknown, CheckboxRootProps>((props,
|
|
|
104
101
|
onChange: onCheckedChange,
|
|
105
102
|
});
|
|
106
103
|
|
|
104
|
+
const toggle = React.useCallback(() => setChecked(!checked), [checked, setChecked]);
|
|
105
|
+
|
|
107
106
|
const { pressed, ...pressHandlers } = usePressTap({
|
|
108
107
|
disabled,
|
|
109
|
-
onTap:
|
|
108
|
+
onTap: toggle,
|
|
110
109
|
});
|
|
111
110
|
|
|
112
|
-
const rootClassName = checkbox({
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
() => ({
|
|
116
|
-
|
|
111
|
+
const rootClassName = checkbox({ ...checkboxVariantProps, disabled }).root;
|
|
112
|
+
|
|
113
|
+
const contextValue = React.useMemo<CheckboxContextValue>(
|
|
114
|
+
() => ({
|
|
115
|
+
checked,
|
|
116
|
+
indeterminate,
|
|
117
|
+
disabled,
|
|
118
|
+
pressed,
|
|
119
|
+
checkboxVariantProps,
|
|
120
|
+
checkmarkVariantProps,
|
|
121
|
+
toggle,
|
|
122
|
+
}),
|
|
123
|
+
[
|
|
124
|
+
checked,
|
|
125
|
+
indeterminate,
|
|
126
|
+
disabled,
|
|
127
|
+
pressed,
|
|
128
|
+
checkboxVariantProps,
|
|
129
|
+
checkmarkVariantProps,
|
|
130
|
+
toggle,
|
|
131
|
+
],
|
|
117
132
|
);
|
|
118
133
|
|
|
119
134
|
return (
|
|
120
|
-
<CheckboxContext.Provider value={
|
|
135
|
+
<CheckboxContext.Provider value={contextValue}>
|
|
121
136
|
<view
|
|
122
|
-
{...(ref ? { ref: ref as
|
|
137
|
+
{...(ref ? { ref: ref as LynxViewRef } : {})}
|
|
123
138
|
className={clsx(rootClassName, className)}
|
|
124
139
|
{...pressHandlers}
|
|
125
140
|
{...nativeProps}
|
|
@@ -134,64 +149,49 @@ CheckboxRoot.displayName = "CheckboxRoot";
|
|
|
134
149
|
////////////////////////////////////////////////////////////////////////////////////
|
|
135
150
|
|
|
136
151
|
export interface CheckboxControlProps
|
|
137
|
-
extends Pick<CheckmarkVariantProps, "tone" | "variant" | "size"
|
|
138
|
-
|
|
139
|
-
className?: string;
|
|
140
|
-
}
|
|
152
|
+
extends Pick<CheckmarkVariantProps, "tone" | "variant" | "size">,
|
|
153
|
+
LynxStyledElementProps {}
|
|
141
154
|
|
|
142
155
|
export const CheckboxControl = React.forwardRef<unknown, CheckboxControlProps>((props, ref) => {
|
|
143
156
|
const [variantProps, restProps] = checkmark.splitVariantProps(props);
|
|
144
157
|
const { children, className, ...nativeProps } = restProps;
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const tone: CheckmarkTone = variantProps.tone ?? ctxTone;
|
|
156
|
-
const variant: CheckmarkVariant = variantProps.variant ?? ctxVariant;
|
|
157
|
-
const size: CheckboxSize = (variantProps.size as CheckboxSize | undefined) ?? ctxSize;
|
|
158
|
-
|
|
159
|
-
const classes = React.useMemo(
|
|
160
|
-
() => checkmark({ variant, tone, size, checked, disabled, indeterminate, pressed }),
|
|
161
|
-
[variant, tone, size, checked, disabled, indeterminate, pressed],
|
|
162
|
-
);
|
|
158
|
+
const context = useCheckboxContext("CheckboxControl");
|
|
159
|
+
const checkmarkVariantProps: CheckmarkVariantProps = {
|
|
160
|
+
...context.checkmarkVariantProps,
|
|
161
|
+
...variantProps,
|
|
162
|
+
checked: context.checked,
|
|
163
|
+
disabled: context.disabled,
|
|
164
|
+
indeterminate: context.indeterminate,
|
|
165
|
+
pressed: context.pressed,
|
|
166
|
+
};
|
|
167
|
+
const classes = checkmark(checkmarkVariantProps);
|
|
163
168
|
|
|
164
169
|
return (
|
|
165
|
-
<
|
|
170
|
+
<CheckmarkControlContext.Provider
|
|
171
|
+
value={{ iconClassName: classes.icon, checkmarkVariantProps }}
|
|
172
|
+
>
|
|
166
173
|
<view
|
|
167
|
-
{...(ref ? { ref: ref as
|
|
174
|
+
{...(ref ? { ref: ref as LynxViewRef } : {})}
|
|
168
175
|
className={clsx(classes.root, className)}
|
|
169
176
|
{...nativeProps}
|
|
170
177
|
>
|
|
171
178
|
{children}
|
|
172
179
|
</view>
|
|
173
|
-
</
|
|
180
|
+
</CheckmarkControlContext.Provider>
|
|
174
181
|
);
|
|
175
182
|
});
|
|
176
183
|
CheckboxControl.displayName = "CheckboxControl";
|
|
177
184
|
|
|
178
185
|
////////////////////////////////////////////////////////////////////////////////////
|
|
179
186
|
|
|
180
|
-
|
|
181
|
-
className
|
|
182
|
-
style?: CSSProperties;
|
|
183
|
-
ref?: React.Ref<MainThread.Element>;
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
export interface CheckboxIndicatorProps {
|
|
187
|
+
export interface CheckboxIndicatorProps
|
|
188
|
+
extends Pick<LynxStyledElementProps, "className" | "style"> {
|
|
187
189
|
/** Icon rendered when neither checked nor indeterminate. Optional. */
|
|
188
|
-
unchecked?: ReactElement<
|
|
190
|
+
unchecked?: ReactElement<LynxIconElementProps>;
|
|
189
191
|
/** Icon rendered when `checked=true` and `indeterminate=false`. */
|
|
190
|
-
checked: ReactElement<
|
|
192
|
+
checked: ReactElement<LynxIconElementProps>;
|
|
191
193
|
/** Icon rendered when `indeterminate=true`. */
|
|
192
|
-
indeterminate?: ReactElement<
|
|
193
|
-
className?: string;
|
|
194
|
-
style?: CSSProperties;
|
|
194
|
+
indeterminate?: ReactElement<LynxIconElementProps>;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
export function CheckboxIndicator(props: CheckboxIndicatorProps) {
|
|
@@ -202,62 +202,56 @@ export function CheckboxIndicator(props: CheckboxIndicatorProps) {
|
|
|
202
202
|
className,
|
|
203
203
|
style,
|
|
204
204
|
} = props;
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
const iconClassName = useCheckmarkIconClass("CheckboxIndicator");
|
|
208
|
-
const { ref: tintRef } = useIconColor([
|
|
209
|
-
checked,
|
|
210
|
-
indeterminate,
|
|
211
|
-
disabled,
|
|
212
|
-
pressed,
|
|
213
|
-
tone,
|
|
214
|
-
variant,
|
|
215
|
-
size,
|
|
216
|
-
]);
|
|
205
|
+
const context = useCheckboxContext("CheckboxIndicator");
|
|
206
|
+
const { iconClassName, checkmarkVariantProps } = useCheckmarkControlContext("CheckboxIndicator");
|
|
217
207
|
|
|
218
|
-
if (process.env.NODE_ENV !== "production" && indeterminate && !indeterminateIcon) {
|
|
208
|
+
if (process.env.NODE_ENV !== "production" && context.indeterminate && !indeterminateIcon) {
|
|
219
209
|
console.warn(
|
|
220
210
|
"[seed-design] CheckboxIndicator: `indeterminate` prop must be provided when the checkbox is in an indeterminate state.",
|
|
221
211
|
);
|
|
222
212
|
}
|
|
223
213
|
|
|
224
|
-
const icon = indeterminate
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
214
|
+
const icon = context.indeterminate
|
|
215
|
+
? indeterminateIcon
|
|
216
|
+
: context.checked
|
|
217
|
+
? checkedIcon
|
|
218
|
+
: unchecked;
|
|
219
|
+
if (!icon || !isValidElement<LynxIconElementProps>(icon)) return null;
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<InternalIcon
|
|
223
|
+
icon={icon}
|
|
224
|
+
className={clsx(iconClassName, className)}
|
|
225
|
+
style={style}
|
|
226
|
+
deps={[
|
|
227
|
+
context.checked,
|
|
228
|
+
context.indeterminate,
|
|
229
|
+
context.disabled,
|
|
230
|
+
context.pressed,
|
|
231
|
+
checkmarkVariantProps.tone,
|
|
232
|
+
checkmarkVariantProps.variant,
|
|
233
|
+
checkmarkVariantProps.size,
|
|
234
|
+
]}
|
|
235
|
+
/>
|
|
236
|
+
);
|
|
243
237
|
}
|
|
244
238
|
CheckboxIndicator.displayName = "CheckboxIndicator";
|
|
245
239
|
|
|
246
240
|
////////////////////////////////////////////////////////////////////////////////////
|
|
247
241
|
|
|
248
|
-
export interface CheckboxLabelProps {
|
|
249
|
-
children?: React.ReactNode;
|
|
250
|
-
className?: string;
|
|
251
|
-
}
|
|
242
|
+
export interface CheckboxLabelProps extends LynxStyledElementProps {}
|
|
252
243
|
|
|
253
244
|
export const CheckboxLabel = React.forwardRef<unknown, CheckboxLabelProps>((props, ref) => {
|
|
254
245
|
const { children, className, ...nativeProps } = props;
|
|
255
|
-
const
|
|
256
|
-
const labelClassName = checkbox({
|
|
246
|
+
const context = useCheckboxContext("CheckboxLabel");
|
|
247
|
+
const labelClassName = checkbox({
|
|
248
|
+
...context.checkboxVariantProps,
|
|
249
|
+
disabled: context.disabled,
|
|
250
|
+
}).label;
|
|
257
251
|
|
|
258
252
|
return (
|
|
259
253
|
<text
|
|
260
|
-
{...(ref ? { ref: ref as
|
|
254
|
+
{...(ref ? { ref: ref as LynxTextRef } : {})}
|
|
261
255
|
className={clsx(labelClassName, className)}
|
|
262
256
|
{...nativeProps}
|
|
263
257
|
>
|
|
@@ -269,10 +263,7 @@ CheckboxLabel.displayName = "CheckboxLabel";
|
|
|
269
263
|
|
|
270
264
|
////////////////////////////////////////////////////////////////////////////////////
|
|
271
265
|
|
|
272
|
-
export interface CheckboxGroupProps {
|
|
273
|
-
children?: React.ReactNode;
|
|
274
|
-
className?: string;
|
|
275
|
-
}
|
|
266
|
+
export interface CheckboxGroupProps extends LynxStyledElementProps {}
|
|
276
267
|
|
|
277
268
|
export const CheckboxGroup = React.forwardRef<unknown, CheckboxGroupProps>((props, ref) => {
|
|
278
269
|
const { children, className, ...nativeProps } = props;
|
|
@@ -280,8 +271,8 @@ export const CheckboxGroup = React.forwardRef<unknown, CheckboxGroupProps>((prop
|
|
|
280
271
|
|
|
281
272
|
return (
|
|
282
273
|
<view
|
|
283
|
-
{...(ref ? { ref: ref as
|
|
284
|
-
className={clsx(classes, className)}
|
|
274
|
+
{...(ref ? { ref: ref as LynxViewRef } : {})}
|
|
275
|
+
className={clsx(classes.root, className)}
|
|
285
276
|
{...nativeProps}
|
|
286
277
|
>
|
|
287
278
|
{children}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { useMainThreadRef } from "@lynx-js/react";
|
|
2
|
+
import type { CSSProperties, MainThread } from "@lynx-js/types";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import * as React from "@lynx-js/react";
|
|
5
|
+
import {
|
|
6
|
+
cloneElement,
|
|
7
|
+
isValidElement,
|
|
8
|
+
type DependencyList,
|
|
9
|
+
type ReactElement,
|
|
10
|
+
} from "@lynx-js/react";
|
|
11
|
+
|
|
12
|
+
import { useIconColor } from "../../hooks/useIconColor";
|
|
13
|
+
import type { LynxIconElementProps, LynxStyledElementProps, LynxViewRef } from "../../types";
|
|
14
|
+
import { handleColor, handleDimension, type StyleProps } from "../../utils/styled";
|
|
15
|
+
|
|
16
|
+
export type IconSlotName = "icon" | "prefixIcon" | "suffixIcon";
|
|
17
|
+
|
|
18
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
19
|
+
|
|
20
|
+
interface IconSlotContextValue {
|
|
21
|
+
classNames?: Partial<Record<IconSlotName, string>>;
|
|
22
|
+
deps?: DependencyList;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const IconSlotContext = React.createContext<IconSlotContextValue | null>(null);
|
|
26
|
+
|
|
27
|
+
interface IconRequiredContextValue {
|
|
28
|
+
register: () => void;
|
|
29
|
+
unregister: () => void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const IconRequiredContext = React.createContext<IconRequiredContextValue | null>(null);
|
|
33
|
+
|
|
34
|
+
export function IconRequired({
|
|
35
|
+
children,
|
|
36
|
+
enabled,
|
|
37
|
+
}: {
|
|
38
|
+
children: React.ReactNode;
|
|
39
|
+
enabled: boolean;
|
|
40
|
+
}) {
|
|
41
|
+
const registeredCountRef = React.useRef(0);
|
|
42
|
+
const parentContext = React.useContext(IconRequiredContext);
|
|
43
|
+
|
|
44
|
+
const register = React.useCallback(() => {
|
|
45
|
+
registeredCountRef.current += 1;
|
|
46
|
+
|
|
47
|
+
if (process.env.NODE_ENV !== "production" && registeredCountRef.current > 1) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
"Icon-only Component must render only one <Icon /> under children. Check if you are rendering multiple <Icon />.",
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}, []);
|
|
53
|
+
|
|
54
|
+
const unregister = React.useCallback(() => {
|
|
55
|
+
registeredCountRef.current = Math.max(0, registeredCountRef.current - 1);
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
React.useLayoutEffect(() => {
|
|
59
|
+
if (!enabled) return;
|
|
60
|
+
|
|
61
|
+
if (process.env.NODE_ENV !== "production") {
|
|
62
|
+
if (parentContext) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
"Icon-only Component must not be nested within another Icon-Only. Check if you are using Icon-Only inside another Icon-Only.",
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
if (registeredCountRef.current === 0) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
"Icon-only Component must render <Icon /> as a child. Check if you are using raw icon element instead of <Icon icon={} />.",
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}, [enabled, parentContext]);
|
|
74
|
+
|
|
75
|
+
const value = React.useMemo<IconRequiredContextValue | null>(() => {
|
|
76
|
+
if (!enabled) return parentContext ?? null;
|
|
77
|
+
return { register, unregister };
|
|
78
|
+
}, [enabled, parentContext, register, unregister]);
|
|
79
|
+
|
|
80
|
+
return <IconRequiredContext.Provider value={value}>{children}</IconRequiredContext.Provider>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function IconSlotProvider({
|
|
84
|
+
value,
|
|
85
|
+
children,
|
|
86
|
+
}: {
|
|
87
|
+
value: IconSlotContextValue;
|
|
88
|
+
children: React.ReactNode;
|
|
89
|
+
}) {
|
|
90
|
+
return <IconSlotContext.Provider value={value}>{children}</IconSlotContext.Provider>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
94
|
+
|
|
95
|
+
const iconSlotMarker = Symbol.for("@seed-design/lynx-react/icon-slot");
|
|
96
|
+
|
|
97
|
+
interface IconSlotComponent {
|
|
98
|
+
[iconSlotMarker]?: IconSlotName;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function getIconSlotName(node: React.ReactNode): IconSlotName | null {
|
|
102
|
+
if (!isValidElement(node)) return null;
|
|
103
|
+
|
|
104
|
+
return ((node.type as IconSlotComponent)[iconSlotMarker] ?? null) as IconSlotName | null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
108
|
+
|
|
109
|
+
export interface IconProps extends LynxStyledElementProps {
|
|
110
|
+
icon: ReactElement<LynxIconElementProps>;
|
|
111
|
+
size?: StyleProps["height"] | number;
|
|
112
|
+
color?: StyleProps["color"];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface PrefixIconProps extends IconProps {}
|
|
116
|
+
|
|
117
|
+
export interface SuffixIconProps extends IconProps {}
|
|
118
|
+
|
|
119
|
+
interface IconSlotBaseProps extends IconProps {
|
|
120
|
+
slot: IconSlotName | null;
|
|
121
|
+
baseClassName?: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function mergeWrapperStyle({
|
|
125
|
+
size,
|
|
126
|
+
color,
|
|
127
|
+
style,
|
|
128
|
+
}: Pick<IconProps, "size" | "color" | "style">): CSSProperties | undefined {
|
|
129
|
+
const dimension = handleDimension(size);
|
|
130
|
+
const resolvedColor = handleColor(color);
|
|
131
|
+
|
|
132
|
+
if (dimension == null && resolvedColor == null) return style;
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
...(dimension != null ? { width: dimension, height: dimension } : {}),
|
|
136
|
+
...(resolvedColor != null ? { color: resolvedColor } : {}),
|
|
137
|
+
...style,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function getStyleColor(style: CSSProperties | undefined): CSSProperties["color"] {
|
|
142
|
+
return style?.color;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const IconSlotBase = React.forwardRef<unknown, IconSlotBaseProps>((props, ref) => {
|
|
146
|
+
const {
|
|
147
|
+
icon,
|
|
148
|
+
slot,
|
|
149
|
+
baseClassName,
|
|
150
|
+
className,
|
|
151
|
+
style,
|
|
152
|
+
size,
|
|
153
|
+
color,
|
|
154
|
+
children: _children,
|
|
155
|
+
...nativeProps
|
|
156
|
+
} = props;
|
|
157
|
+
const context = React.useContext(IconSlotContext);
|
|
158
|
+
const iconRequiredContext = React.useContext(IconRequiredContext);
|
|
159
|
+
const sourceRef = useMainThreadRef<MainThread.Element>(null);
|
|
160
|
+
const slotClassName = slot != null ? context?.classNames?.[slot] : undefined;
|
|
161
|
+
const styleColor = getStyleColor(style);
|
|
162
|
+
const iconColor = useIconColor(
|
|
163
|
+
[baseClassName, slotClassName, className, size, color, styleColor, ...(context?.deps ?? [])],
|
|
164
|
+
{ sourceRef },
|
|
165
|
+
);
|
|
166
|
+
const hasValidIcon = isValidElement<LynxIconElementProps>(icon);
|
|
167
|
+
|
|
168
|
+
React.useLayoutEffect(() => {
|
|
169
|
+
if (slot !== "icon" || !hasValidIcon) return;
|
|
170
|
+
|
|
171
|
+
iconRequiredContext?.register();
|
|
172
|
+
return () => {
|
|
173
|
+
iconRequiredContext?.unregister();
|
|
174
|
+
};
|
|
175
|
+
}, [hasValidIcon, iconRequiredContext, slot]);
|
|
176
|
+
|
|
177
|
+
if (!hasValidIcon) return null;
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<view
|
|
181
|
+
{...(ref ? { ref: ref as LynxViewRef } : {})}
|
|
182
|
+
{...nativeProps}
|
|
183
|
+
main-thread:ref={sourceRef}
|
|
184
|
+
className={clsx(baseClassName, slotClassName, className)}
|
|
185
|
+
style={mergeWrapperStyle({ size, color, style })}
|
|
186
|
+
>
|
|
187
|
+
{cloneElement(icon, {
|
|
188
|
+
...iconColor,
|
|
189
|
+
className: icon.props.className,
|
|
190
|
+
style: {
|
|
191
|
+
...icon.props.style,
|
|
192
|
+
width: "100%",
|
|
193
|
+
height: "100%",
|
|
194
|
+
},
|
|
195
|
+
})}
|
|
196
|
+
</view>
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
IconSlotBase.displayName = "IconSlotBase";
|
|
200
|
+
|
|
201
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
202
|
+
|
|
203
|
+
function createIconComponent<Props extends IconProps>(
|
|
204
|
+
displayName: string,
|
|
205
|
+
slot: IconSlotName,
|
|
206
|
+
baseClassName: string,
|
|
207
|
+
) {
|
|
208
|
+
const Component = React.forwardRef<unknown, Props>((props, ref) => {
|
|
209
|
+
return <IconSlotBase ref={ref} slot={slot} baseClassName={baseClassName} {...props} />;
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
Component.displayName = displayName;
|
|
213
|
+
(Component as IconSlotComponent)[iconSlotMarker] = slot;
|
|
214
|
+
|
|
215
|
+
return Component;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export const Icon = createIconComponent<IconProps>("Icon", "icon", "seed-icon");
|
|
219
|
+
export const PrefixIcon = createIconComponent<PrefixIconProps>(
|
|
220
|
+
"PrefixIcon",
|
|
221
|
+
"prefixIcon",
|
|
222
|
+
"seed-prefix-icon",
|
|
223
|
+
);
|
|
224
|
+
export const SuffixIcon = createIconComponent<SuffixIconProps>(
|
|
225
|
+
"SuffixIcon",
|
|
226
|
+
"suffixIcon",
|
|
227
|
+
"seed-suffix-icon",
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
////////////////////////////////////////////////////////////////////////////////////
|
|
231
|
+
|
|
232
|
+
export interface InternalIconProps extends LynxStyledElementProps {
|
|
233
|
+
icon: ReactElement<LynxIconElementProps>;
|
|
234
|
+
deps?: DependencyList;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export const InternalIcon = React.forwardRef<unknown, InternalIconProps>((props, ref) => {
|
|
238
|
+
const { icon, deps = [], className, style, children: _children, ...nativeProps } = props;
|
|
239
|
+
const sourceRef = useMainThreadRef<MainThread.Element>(null);
|
|
240
|
+
const styleColor = getStyleColor(style);
|
|
241
|
+
const iconColor = useIconColor([className, styleColor, ...(deps ?? [])], { sourceRef });
|
|
242
|
+
|
|
243
|
+
if (!isValidElement<LynxIconElementProps>(icon)) return null;
|
|
244
|
+
|
|
245
|
+
return (
|
|
246
|
+
<view
|
|
247
|
+
{...(ref ? { ref: ref as LynxViewRef } : {})}
|
|
248
|
+
{...nativeProps}
|
|
249
|
+
main-thread:ref={sourceRef}
|
|
250
|
+
className={className}
|
|
251
|
+
style={style}
|
|
252
|
+
>
|
|
253
|
+
{cloneElement(icon, {
|
|
254
|
+
...iconColor,
|
|
255
|
+
className: icon.props.className,
|
|
256
|
+
style: {
|
|
257
|
+
...icon.props.style,
|
|
258
|
+
width: "100%",
|
|
259
|
+
height: "100%",
|
|
260
|
+
},
|
|
261
|
+
})}
|
|
262
|
+
</view>
|
|
263
|
+
);
|
|
264
|
+
});
|
|
265
|
+
InternalIcon.displayName = "InternalIcon";
|