@seed-design/lynx-react 0.0.0-alpha-20260622094810

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 (196) hide show
  1. package/lib/_virtual/_rolldown/runtime.js +13 -0
  2. package/lib/components/ActionButton/ActionButton.d.ts +49 -0
  3. package/lib/components/ActionButton/ActionButton.d.ts.map +1 -0
  4. package/lib/components/ActionButton/ActionButton.jsx +158 -0
  5. package/lib/components/ActionButton/index.d.ts +2 -0
  6. package/lib/components/ActionButton/index.d.ts.map +1 -0
  7. package/lib/components/AppBar/AppBar.d.ts +35 -0
  8. package/lib/components/AppBar/AppBar.d.ts.map +1 -0
  9. package/lib/components/AppBar/AppBar.jsx +132 -0
  10. package/lib/components/AppBar/AppBar.namespace.d.ts +2 -0
  11. package/lib/components/AppBar/AppBar.namespace.d.ts.map +1 -0
  12. package/lib/components/AppBar/AppBar.namespace.js +15 -0
  13. package/lib/components/AppBar/context.d.ts +13 -0
  14. package/lib/components/AppBar/context.d.ts.map +1 -0
  15. package/lib/components/AppBar/context.js +12 -0
  16. package/lib/components/AppBar/index.d.ts +3 -0
  17. package/lib/components/AppBar/index.d.ts.map +1 -0
  18. package/lib/components/AppBar/useAppBar.d.ts +15 -0
  19. package/lib/components/AppBar/useAppBar.d.ts.map +1 -0
  20. package/lib/components/AppBar/useAppBar.js +72 -0
  21. package/lib/components/Badge/Badge.d.ts +14 -0
  22. package/lib/components/Badge/Badge.d.ts.map +1 -0
  23. package/lib/components/Badge/Badge.jsx +15 -0
  24. package/lib/components/Badge/index.d.ts +2 -0
  25. package/lib/components/Badge/index.d.ts.map +1 -0
  26. package/lib/components/BottomSheet/BottomSheet.d.ts +87 -0
  27. package/lib/components/BottomSheet/BottomSheet.d.ts.map +1 -0
  28. package/lib/components/BottomSheet/BottomSheet.jsx +163 -0
  29. package/lib/components/BottomSheet/BottomSheet.namespace.d.ts +2 -0
  30. package/lib/components/BottomSheet/BottomSheet.namespace.d.ts.map +1 -0
  31. package/lib/components/BottomSheet/BottomSheet.namespace.js +18 -0
  32. package/lib/components/BottomSheet/index.d.ts +3 -0
  33. package/lib/components/BottomSheet/index.d.ts.map +1 -0
  34. package/lib/components/Box/Box.d.ts +20 -0
  35. package/lib/components/Box/Box.d.ts.map +1 -0
  36. package/lib/components/Box/Box.jsx +14 -0
  37. package/lib/components/Box/index.d.ts +2 -0
  38. package/lib/components/Box/index.d.ts.map +1 -0
  39. package/lib/components/Checkbox/Checkbox.d.ts +35 -0
  40. package/lib/components/Checkbox/Checkbox.d.ts.map +1 -0
  41. package/lib/components/Checkbox/Checkbox.jsx +130 -0
  42. package/lib/components/Checkbox/Checkbox.namespace.d.ts +2 -0
  43. package/lib/components/Checkbox/Checkbox.namespace.d.ts.map +1 -0
  44. package/lib/components/Checkbox/Checkbox.namespace.js +12 -0
  45. package/lib/components/Checkbox/index.d.ts +3 -0
  46. package/lib/components/Checkbox/index.d.ts.map +1 -0
  47. package/lib/components/Icon/Icon.d.ts +37 -0
  48. package/lib/components/Icon/Icon.d.ts.map +1 -0
  49. package/lib/components/Icon/Icon.jsx +143 -0
  50. package/lib/components/Icon/index.d.ts +2 -0
  51. package/lib/components/Icon/index.d.ts.map +1 -0
  52. package/lib/components/ProgressCircle/ProgressCircle.d.ts +25 -0
  53. package/lib/components/ProgressCircle/ProgressCircle.d.ts.map +1 -0
  54. package/lib/components/ProgressCircle/ProgressCircle.jsx +281 -0
  55. package/lib/components/ProgressCircle/ProgressCircle.namespace.d.ts +2 -0
  56. package/lib/components/ProgressCircle/ProgressCircle.namespace.d.ts.map +1 -0
  57. package/lib/components/ProgressCircle/ProgressCircle.namespace.js +9 -0
  58. package/lib/components/ProgressCircle/index.d.ts +3 -0
  59. package/lib/components/ProgressCircle/index.d.ts.map +1 -0
  60. package/lib/components/RadioGroup/RadioGroup.d.ts +34 -0
  61. package/lib/components/RadioGroup/RadioGroup.d.ts.map +1 -0
  62. package/lib/components/RadioGroup/RadioGroup.jsx +160 -0
  63. package/lib/components/RadioGroup/RadioGroup.namespace.d.ts +2 -0
  64. package/lib/components/RadioGroup/RadioGroup.namespace.d.ts.map +1 -0
  65. package/lib/components/RadioGroup/RadioGroup.namespace.js +12 -0
  66. package/lib/components/RadioGroup/index.d.ts +3 -0
  67. package/lib/components/RadioGroup/index.d.ts.map +1 -0
  68. package/lib/components/Stack/Stack.d.ts +33 -0
  69. package/lib/components/Stack/Stack.d.ts.map +1 -0
  70. package/lib/components/Stack/Stack.jsx +39 -0
  71. package/lib/components/Stack/index.d.ts +2 -0
  72. package/lib/components/Stack/index.d.ts.map +1 -0
  73. package/lib/components/Switch/Switch.d.ts +21 -0
  74. package/lib/components/Switch/Switch.d.ts.map +1 -0
  75. package/lib/components/Switch/Switch.jsx +101 -0
  76. package/lib/components/Switch/Switch.namespace.d.ts +2 -0
  77. package/lib/components/Switch/Switch.namespace.d.ts.map +1 -0
  78. package/lib/components/Switch/Switch.namespace.js +11 -0
  79. package/lib/components/Switch/index.d.ts +3 -0
  80. package/lib/components/Switch/index.d.ts.map +1 -0
  81. package/lib/components/TagGroup/TagGroup.d.ts +34 -0
  82. package/lib/components/TagGroup/TagGroup.d.ts.map +1 -0
  83. package/lib/components/TagGroup/TagGroup.jsx +57 -0
  84. package/lib/components/TagGroup/TagGroup.namespace.d.ts +2 -0
  85. package/lib/components/TagGroup/TagGroup.namespace.d.ts.map +1 -0
  86. package/lib/components/TagGroup/TagGroup.namespace.js +10 -0
  87. package/lib/components/TagGroup/index.d.ts +3 -0
  88. package/lib/components/TagGroup/index.d.ts.map +1 -0
  89. package/lib/components/Text/Text.d.ts +7 -0
  90. package/lib/components/Text/Text.d.ts.map +1 -0
  91. package/lib/components/Text/Text.jsx +28 -0
  92. package/lib/components/Text/index.d.ts +2 -0
  93. package/lib/components/Text/index.d.ts.map +1 -0
  94. package/lib/components/index.d.ts +14 -0
  95. package/lib/components/index.d.ts.map +1 -0
  96. package/lib/hooks/index.d.ts +5 -0
  97. package/lib/hooks/index.d.ts.map +1 -0
  98. package/lib/hooks/useControllableState.d.ts +15 -0
  99. package/lib/hooks/useControllableState.d.ts.map +1 -0
  100. package/lib/hooks/useControllableState.js +27 -0
  101. package/lib/hooks/useIconColor.d.ts +19 -0
  102. package/lib/hooks/useIconColor.d.ts.map +1 -0
  103. package/lib/hooks/useIconColor.js +38 -0
  104. package/lib/hooks/usePressTap.d.ts +27 -0
  105. package/lib/hooks/usePressTap.d.ts.map +1 -0
  106. package/lib/hooks/usePressTap.js +35 -0
  107. package/lib/hooks/useSafeArea.d.ts +19 -0
  108. package/lib/hooks/useSafeArea.d.ts.map +1 -0
  109. package/lib/hooks/useSafeArea.js +33 -0
  110. package/lib/index.d.ts +5 -0
  111. package/lib/index.d.ts.map +1 -0
  112. package/lib/index.js +29 -0
  113. package/lib/types.d.ts +51 -0
  114. package/lib/types.d.ts.map +1 -0
  115. package/lib/utils/children.d.ts +3 -0
  116. package/lib/utils/children.d.ts.map +1 -0
  117. package/lib/utils/children.js +8 -0
  118. package/lib/utils/create-slot-recipe-context.d.ts +27 -0
  119. package/lib/utils/create-slot-recipe-context.d.ts.map +1 -0
  120. package/lib/utils/create-slot-recipe-context.jsx +94 -0
  121. package/lib/utils/get-seed-class-name.d.ts +22 -0
  122. package/lib/utils/get-seed-class-name.d.ts.map +1 -0
  123. package/lib/utils/get-seed-class-name.js +28 -0
  124. package/lib/utils/index.d.ts +5 -0
  125. package/lib/utils/index.d.ts.map +1 -0
  126. package/lib/utils/resolve-recipe-token.d.ts +38 -0
  127. package/lib/utils/resolve-recipe-token.d.ts.map +1 -0
  128. package/lib/utils/resolve-recipe-token.js +49 -0
  129. package/lib/utils/split-multiple-variants-props.d.ts +29 -0
  130. package/lib/utils/split-multiple-variants-props.d.ts.map +1 -0
  131. package/lib/utils/split-multiple-variants-props.js +34 -0
  132. package/lib/utils/styled.d.ts +83 -0
  133. package/lib/utils/styled.d.ts.map +1 -0
  134. package/lib/utils/styled.js +144 -0
  135. package/package.json +54 -0
  136. package/src/components/ActionButton/ActionButton.test.tsx +167 -0
  137. package/src/components/ActionButton/ActionButton.tsx +363 -0
  138. package/src/components/ActionButton/index.ts +1 -0
  139. package/src/components/AppBar/AppBar.namespace.ts +18 -0
  140. package/src/components/AppBar/AppBar.test.tsx +270 -0
  141. package/src/components/AppBar/AppBar.tsx +288 -0
  142. package/src/components/AppBar/context.ts +27 -0
  143. package/src/components/AppBar/index.ts +21 -0
  144. package/src/components/AppBar/useAppBar.ts +100 -0
  145. package/src/components/Badge/Badge.test.tsx +54 -0
  146. package/src/components/Badge/Badge.tsx +32 -0
  147. package/src/components/Badge/index.ts +1 -0
  148. package/src/components/BottomSheet/BottomSheet.namespace.ts +24 -0
  149. package/src/components/BottomSheet/BottomSheet.test.tsx +219 -0
  150. package/src/components/BottomSheet/BottomSheet.tsx +423 -0
  151. package/src/components/BottomSheet/index.ts +27 -0
  152. package/src/components/Box/Box.test.tsx +85 -0
  153. package/src/components/Box/Box.tsx +39 -0
  154. package/src/components/Box/index.ts +1 -0
  155. package/src/components/Checkbox/Checkbox.namespace.ts +12 -0
  156. package/src/components/Checkbox/Checkbox.tsx +282 -0
  157. package/src/components/Checkbox/index.ts +14 -0
  158. package/src/components/Icon/Icon.tsx +265 -0
  159. package/src/components/Icon/index.ts +8 -0
  160. package/src/components/ProgressCircle/ProgressCircle.namespace.ts +5 -0
  161. package/src/components/ProgressCircle/ProgressCircle.tsx +424 -0
  162. package/src/components/ProgressCircle/index.ts +9 -0
  163. package/src/components/RadioGroup/RadioGroup.namespace.ts +12 -0
  164. package/src/components/RadioGroup/RadioGroup.tsx +320 -0
  165. package/src/components/RadioGroup/index.ts +14 -0
  166. package/src/components/Stack/Stack.tsx +97 -0
  167. package/src/components/Stack/index.ts +1 -0
  168. package/src/components/Switch/Switch.namespace.ts +10 -0
  169. package/src/components/Switch/Switch.tsx +200 -0
  170. package/src/components/Switch/index.ts +12 -0
  171. package/src/components/TagGroup/TagGroup.namespace.ts +8 -0
  172. package/src/components/TagGroup/TagGroup.tsx +127 -0
  173. package/src/components/TagGroup/index.ts +10 -0
  174. package/src/components/Text/Text.tsx +64 -0
  175. package/src/components/Text/index.ts +1 -0
  176. package/src/components/index.ts +13 -0
  177. package/src/hooks/index.ts +4 -0
  178. package/src/hooks/useControllableState.test.ts +120 -0
  179. package/src/hooks/useControllableState.ts +38 -0
  180. package/src/hooks/useIconColor.test.ts +13 -0
  181. package/src/hooks/useIconColor.ts +67 -0
  182. package/src/hooks/usePressTap.test.ts +129 -0
  183. package/src/hooks/usePressTap.ts +58 -0
  184. package/src/hooks/useSafeArea.test.ts +83 -0
  185. package/src/hooks/useSafeArea.ts +56 -0
  186. package/src/index.ts +4 -0
  187. package/src/types.ts +76 -0
  188. package/src/utils/children.ts +13 -0
  189. package/src/utils/create-slot-recipe-context.test.tsx +96 -0
  190. package/src/utils/create-slot-recipe-context.tsx +187 -0
  191. package/src/utils/get-seed-class-name.ts +47 -0
  192. package/src/utils/index.ts +4 -0
  193. package/src/utils/resolve-recipe-token.ts +47 -0
  194. package/src/utils/split-multiple-variants-props.test.ts +61 -0
  195. package/src/utils/split-multiple-variants-props.ts +59 -0
  196. package/src/utils/styled.ts +442 -0
@@ -0,0 +1,288 @@
1
+ import { appBar, type AppBarVariantProps } from "@seed-design/lynx-css/recipes/app-bar";
2
+ import {
3
+ appBarMain,
4
+ type AppBarMainVariantProps,
5
+ } from "@seed-design/lynx-css/recipes/app-bar-main";
6
+ import * as React from "@lynx-js/react";
7
+ import clsx from "clsx";
8
+
9
+ import type {
10
+ LynxElementProps,
11
+ LynxIconElementProps,
12
+ LynxPressableProps,
13
+ LynxStyledElementProps,
14
+ LynxTextRef,
15
+ LynxViewProps,
16
+ LynxViewRef,
17
+ } from "../../types";
18
+ import { createSlotRecipeContext } from "../../utils/create-slot-recipe-context";
19
+ import { Icon } from "../Icon";
20
+ import { AppBarProvider, useAppBarContext } from "./context";
21
+ import { getLayoutWidth, getMainLayoutStyle, useAppBar } from "./useAppBar";
22
+
23
+ type AppBarClassNames = ReturnType<typeof appBar>;
24
+ type AppBarMainClassNames = ReturnType<typeof appBarMain>;
25
+ type LayoutChangeHandler = NonNullable<LynxViewProps["bindlayoutchange"]>;
26
+
27
+ const { ClassNamesProvider: AppBarClassNamesProvider, useClassNames: useAppBarRecipeClassNames } =
28
+ createSlotRecipeContext(appBar);
29
+ const {
30
+ ClassNamesProvider: AppBarMainClassNamesProvider,
31
+ useClassNames: useAppBarMainRecipeClassNames,
32
+ } = createSlotRecipeContext(appBarMain);
33
+
34
+ function useAppBarClassNames(consumer: string): AppBarClassNames {
35
+ try {
36
+ return useAppBarRecipeClassNames();
37
+ } catch {
38
+ throw new Error(`<${consumer}/> must be rendered inside <AppBarRoot/>.`);
39
+ }
40
+ }
41
+
42
+ function useAppBarMainClassNames(consumer: string): AppBarMainClassNames {
43
+ try {
44
+ return useAppBarMainRecipeClassNames();
45
+ } catch {
46
+ throw new Error(`<${consumer}/> must be rendered inside <AppBarMain/>.`);
47
+ }
48
+ }
49
+
50
+ ////////////////////////////////////////////////////////////////////////////////////
51
+
52
+ export interface AppBarRootProps extends AppBarVariantProps, LynxStyledElementProps {}
53
+
54
+ export const AppBarRoot = React.forwardRef<unknown, AppBarRootProps>((props, ref) => {
55
+ const [variantProps, otherProps] = appBar.splitVariantProps(props);
56
+ const { children, className, style, ...nativeProps } = otherProps;
57
+ const { contextValue, resolvedVariantProps, rootLayoutStyle } = useAppBar(variantProps);
58
+ const classNames = appBar(resolvedVariantProps);
59
+
60
+ return (
61
+ <AppBarProvider value={contextValue}>
62
+ <AppBarClassNamesProvider value={classNames}>
63
+ <view
64
+ {...(ref ? { ref: ref as LynxViewRef } : {})}
65
+ {...nativeProps}
66
+ className={clsx(classNames.root, className)}
67
+ style={
68
+ {
69
+ "--seed-safe-area-top": contextValue.safeAreaInsetTop,
70
+ "--centered-title-padding-x": contextValue.centeredTitlePaddingX,
71
+ ...rootLayoutStyle,
72
+ ...style,
73
+ } as LynxViewProps["style"]
74
+ }
75
+ >
76
+ <view accessibility-elements-hidden className={classNames.background} />
77
+ {children}
78
+ </view>
79
+ </AppBarClassNamesProvider>
80
+ </AppBarProvider>
81
+ );
82
+ });
83
+ AppBarRoot.displayName = "AppBarRoot";
84
+
85
+ ////////////////////////////////////////////////////////////////////////////////////
86
+
87
+ export interface AppBarLeftProps extends LynxStyledElementProps {
88
+ bindlayoutchange?: LynxViewProps["bindlayoutchange"];
89
+ }
90
+
91
+ export const AppBarLeft = React.forwardRef<unknown, AppBarLeftProps>((props, ref) => {
92
+ const { children, className, bindlayoutchange, ...nativeProps } = props;
93
+ const { setLeftWidth } = useAppBarContext("AppBarLeft");
94
+ const classNames = useAppBarClassNames("AppBarLeft");
95
+
96
+ const handleLayoutChange = React.useCallback<LayoutChangeHandler>(
97
+ (...args) => {
98
+ bindlayoutchange?.(...args);
99
+ const width = getLayoutWidth(args[0]);
100
+ if (width != null) {
101
+ setLeftWidth(width);
102
+ }
103
+ },
104
+ [bindlayoutchange, setLeftWidth],
105
+ );
106
+
107
+ return (
108
+ <view
109
+ {...(ref ? { ref: ref as LynxViewRef } : {})}
110
+ {...nativeProps}
111
+ bindlayoutchange={handleLayoutChange}
112
+ className={clsx(classNames.left, className)}
113
+ >
114
+ {children}
115
+ </view>
116
+ );
117
+ });
118
+ AppBarLeft.displayName = "AppBarLeft";
119
+
120
+ export interface AppBarRightProps extends LynxStyledElementProps {
121
+ bindlayoutchange?: LynxViewProps["bindlayoutchange"];
122
+ }
123
+
124
+ export const AppBarRight = React.forwardRef<unknown, AppBarRightProps>((props, ref) => {
125
+ const { children, className, bindlayoutchange, ...nativeProps } = props;
126
+ const { setRightWidth } = useAppBarContext("AppBarRight");
127
+ const classNames = useAppBarClassNames("AppBarRight");
128
+
129
+ const handleLayoutChange = React.useCallback<LayoutChangeHandler>(
130
+ (...args) => {
131
+ bindlayoutchange?.(...args);
132
+ const width = getLayoutWidth(args[0]);
133
+ if (width != null) {
134
+ setRightWidth(width);
135
+ }
136
+ },
137
+ [bindlayoutchange, setRightWidth],
138
+ );
139
+
140
+ return (
141
+ <view
142
+ {...(ref ? { ref: ref as LynxViewRef } : {})}
143
+ {...nativeProps}
144
+ bindlayoutchange={handleLayoutChange}
145
+ className={clsx(classNames.right, className)}
146
+ >
147
+ {children}
148
+ </view>
149
+ );
150
+ });
151
+ AppBarRight.displayName = "AppBarRight";
152
+
153
+ ////////////////////////////////////////////////////////////////////////////////////
154
+
155
+ export interface AppBarMainProps extends AppBarMainVariantProps, LynxStyledElementProps {}
156
+
157
+ export const AppBarMain = React.forwardRef<unknown, AppBarMainProps>((props, ref) => {
158
+ const { centeredTitlePaddingX, safeAreaInsetTop, sharedVariantProps } =
159
+ useAppBarContext("AppBarMain");
160
+ const [variantProps, otherProps] = appBarMain.splitVariantProps({
161
+ ...sharedVariantProps,
162
+ ...props,
163
+ });
164
+ const resolvedTheme = variantProps.theme ?? "cupertino";
165
+ const classNames = appBarMain(variantProps);
166
+ const { children, className, style, ...nativeProps } = otherProps;
167
+ const centeredTitleStyle =
168
+ variantProps.theme === "cupertino"
169
+ ? {
170
+ paddingLeft: centeredTitlePaddingX,
171
+ paddingRight: centeredTitlePaddingX,
172
+ }
173
+ : undefined;
174
+
175
+ return (
176
+ <AppBarMainClassNamesProvider value={classNames}>
177
+ <view
178
+ {...(ref ? { ref: ref as LynxViewRef } : {})}
179
+ {...nativeProps}
180
+ className={clsx(classNames.root, className)}
181
+ style={
182
+ {
183
+ ...centeredTitleStyle,
184
+ ...getMainLayoutStyle(resolvedTheme, safeAreaInsetTop),
185
+ ...style,
186
+ } as LynxViewProps["style"]
187
+ }
188
+ >
189
+ {children}
190
+ </view>
191
+ </AppBarMainClassNamesProvider>
192
+ );
193
+ });
194
+ AppBarMain.displayName = "AppBarMain";
195
+
196
+ export interface AppBarTitleProps extends LynxElementProps {}
197
+
198
+ export const AppBarTitle = React.forwardRef<unknown, AppBarTitleProps>((props, ref) => {
199
+ const { children, className, ...nativeProps } = props;
200
+ const classNames = useAppBarMainClassNames("AppBarTitle");
201
+
202
+ return (
203
+ <text
204
+ {...(ref ? { ref: ref as LynxTextRef } : {})}
205
+ {...nativeProps}
206
+ className={clsx(classNames.title, className)}
207
+ >
208
+ {children}
209
+ </text>
210
+ );
211
+ });
212
+ AppBarTitle.displayName = "AppBarTitle";
213
+
214
+ export interface AppBarSubtitleProps extends LynxElementProps {}
215
+
216
+ export const AppBarSubtitle = React.forwardRef<unknown, AppBarSubtitleProps>((props, ref) => {
217
+ const { children, className, ...nativeProps } = props;
218
+ const classNames = useAppBarMainClassNames("AppBarSubtitle");
219
+
220
+ return (
221
+ <text
222
+ {...(ref ? { ref: ref as LynxTextRef } : {})}
223
+ {...nativeProps}
224
+ className={clsx(classNames.subtitle, className)}
225
+ >
226
+ {children}
227
+ </text>
228
+ );
229
+ });
230
+ AppBarSubtitle.displayName = "AppBarSubtitle";
231
+
232
+ ////////////////////////////////////////////////////////////////////////////////////
233
+
234
+ export interface AppBarIconButtonProps extends LynxElementProps, LynxPressableProps {
235
+ icon?: React.ReactElement<LynxIconElementProps>;
236
+ "accessibility-label"?: LynxViewProps["accessibility-label"];
237
+ "accessibility-element"?: LynxViewProps["accessibility-element"];
238
+ "accessibility-traits"?: LynxViewProps["accessibility-traits"];
239
+ }
240
+
241
+ export const AppBarIconButton = React.forwardRef<unknown, AppBarIconButtonProps>((props, ref) => {
242
+ const {
243
+ children,
244
+ className,
245
+ icon,
246
+ "accessibility-element": accessibilityElement = true,
247
+ "accessibility-label": accessibilityLabel,
248
+ "accessibility-traits": accessibilityTraits = "button",
249
+ ...nativeProps
250
+ } = props;
251
+ const classNames = useAppBarClassNames("AppBarIconButton");
252
+
253
+ if (process.env.NODE_ENV !== "production" && accessibilityElement && !accessibilityLabel) {
254
+ console.warn("AppBarIconButton requires `accessibility-label` for accessibility.");
255
+ }
256
+
257
+ return (
258
+ <view
259
+ {...(ref ? { ref: ref as LynxViewRef } : {})}
260
+ {...nativeProps}
261
+ accessibility-element={accessibilityElement}
262
+ accessibility-label={accessibilityLabel}
263
+ accessibility-traits={accessibilityTraits}
264
+ className={clsx(classNames.iconButton, className)}
265
+ >
266
+ {icon ? <Icon className={classNames.icon} icon={icon} /> : children}
267
+ </view>
268
+ );
269
+ });
270
+ AppBarIconButton.displayName = "AppBarIconButton";
271
+
272
+ export interface AppBarSlotProps extends LynxStyledElementProps {}
273
+
274
+ export const AppBarSlot = React.forwardRef<unknown, AppBarSlotProps>((props, ref) => {
275
+ const { children, className, ...nativeProps } = props;
276
+ const classNames = useAppBarClassNames("AppBarSlot");
277
+
278
+ return (
279
+ <view
280
+ {...(ref ? { ref: ref as LynxViewRef } : {})}
281
+ {...nativeProps}
282
+ className={clsx(classNames.custom, className)}
283
+ >
284
+ {children}
285
+ </view>
286
+ );
287
+ });
288
+ AppBarSlot.displayName = "AppBarSlot";
@@ -0,0 +1,27 @@
1
+ import { type AppBarMainVariantProps } from "@seed-design/lynx-css/recipes/app-bar-main";
2
+ import * as React from "@lynx-js/react";
3
+
4
+ export type SharedAppBarVariantProps = Pick<
5
+ AppBarMainVariantProps,
6
+ "theme" | "tone" | "transitionStyle"
7
+ >;
8
+
9
+ export interface AppBarContextValue {
10
+ centeredTitlePaddingX: string;
11
+ safeAreaInsetTop: string;
12
+ sharedVariantProps: SharedAppBarVariantProps;
13
+ setLeftWidth: (width: number) => void;
14
+ setRightWidth: (width: number) => void;
15
+ }
16
+
17
+ const AppBarContext = React.createContext<AppBarContextValue | null>(null);
18
+
19
+ export const AppBarProvider = AppBarContext.Provider;
20
+
21
+ export function useAppBarContext(consumer: string): AppBarContextValue {
22
+ const ctx = React.useContext(AppBarContext);
23
+ if (!ctx) {
24
+ throw new Error(`<${consumer}/> must be rendered inside <AppBarRoot/>.`);
25
+ }
26
+ return ctx;
27
+ }
@@ -0,0 +1,21 @@
1
+ export {
2
+ AppBarIconButton,
3
+ AppBarLeft,
4
+ AppBarMain,
5
+ AppBarRight,
6
+ AppBarRoot,
7
+ AppBarSlot,
8
+ AppBarSubtitle,
9
+ AppBarTitle,
10
+ type AppBarIconButtonProps,
11
+ type AppBarLeftProps,
12
+ type AppBarMainProps,
13
+ type AppBarRightProps,
14
+ type AppBarRootProps,
15
+ type AppBarRootProps as AppBarProps,
16
+ type AppBarSlotProps,
17
+ type AppBarSubtitleProps,
18
+ type AppBarTitleProps,
19
+ } from "./AppBar";
20
+
21
+ export * as AppBar from "./AppBar.namespace";
@@ -0,0 +1,100 @@
1
+ import type { AppBarVariantProps } from "@seed-design/lynx-css/recipes/app-bar";
2
+ import type { AppBarMainVariantProps } from "@seed-design/lynx-css/recipes/app-bar-main";
3
+ import * as React from "@lynx-js/react";
4
+
5
+ import { useSafeArea } from "../../hooks/useSafeArea";
6
+ import type { LynxViewProps } from "../../types";
7
+ import type { AppBarContextValue, SharedAppBarVariantProps } from "./context";
8
+
9
+ type LynxSystemInfo = { platform?: string };
10
+
11
+ declare const SystemInfo: LynxSystemInfo | undefined;
12
+
13
+ type AppBarTheme = NonNullable<AppBarVariantProps["theme"]>;
14
+ type LayoutChangeHandler = NonNullable<LynxViewProps["bindlayoutchange"]>;
15
+ type AppBarStyleObject = Record<string, string | number>;
16
+
17
+ const APP_BAR_HEIGHT_BY_THEME: Record<AppBarTheme, string> = {
18
+ cupertino: "44px",
19
+ android: "56px",
20
+ };
21
+
22
+ function getDefaultAppBarTheme(): AppBarTheme {
23
+ const globalSystemInfo = (globalThis as typeof globalThis & { SystemInfo?: LynxSystemInfo })
24
+ .SystemInfo;
25
+ const systemInfo =
26
+ globalSystemInfo ?? (typeof SystemInfo === "undefined" ? undefined : SystemInfo);
27
+
28
+ if (systemInfo == null) return "cupertino";
29
+
30
+ return systemInfo.platform === "Android" ? "android" : "cupertino";
31
+ }
32
+
33
+ export function getLayoutWidth(event: Parameters<LayoutChangeHandler>[0]): number | null {
34
+ const eventWithWidth = event as Parameters<LayoutChangeHandler>[0] & { width?: number };
35
+ const nextWidth = event.detail?.width ?? event.params?.width ?? eventWithWidth.width;
36
+ if (typeof nextWidth !== "number" || !Number.isFinite(nextWidth)) return null;
37
+
38
+ return Math.max(0, nextWidth);
39
+ }
40
+
41
+ function getCenteredTitlePadding(leftWidth: number, rightWidth: number): string {
42
+ return `${Math.max(leftWidth, rightWidth)}px`;
43
+ }
44
+
45
+ function getRootLayoutStyle(theme: AppBarTheme, safeAreaInsetTop: string): AppBarStyleObject {
46
+ return {
47
+ height: `calc(${APP_BAR_HEIGHT_BY_THEME[theme]} + ${safeAreaInsetTop})`,
48
+ paddingTop: safeAreaInsetTop,
49
+ };
50
+ }
51
+
52
+ export function getMainLayoutStyle(
53
+ theme: AppBarMainVariantProps["theme"],
54
+ safeAreaInsetTop: string,
55
+ ): AppBarStyleObject | undefined {
56
+ if (theme !== "cupertino") return undefined;
57
+
58
+ return {
59
+ top: safeAreaInsetTop,
60
+ bottom: "0px",
61
+ };
62
+ }
63
+
64
+ export function useAppBar(variantProps: AppBarVariantProps) {
65
+ const { safeAreaInsetTop } = useSafeArea();
66
+ const [leftWidth, setLeftWidth] = React.useState(0);
67
+ const [rightWidth, setRightWidth] = React.useState(0);
68
+ const resolvedTheme = variantProps.theme ?? getDefaultAppBarTheme();
69
+
70
+ const resolvedVariantProps: AppBarVariantProps = {
71
+ ...variantProps,
72
+ theme: resolvedTheme,
73
+ };
74
+ const centeredTitlePaddingX = getCenteredTitlePadding(leftWidth, rightWidth);
75
+ const rootLayoutStyle = getRootLayoutStyle(resolvedTheme, safeAreaInsetTop);
76
+ const sharedVariantProps = React.useMemo<SharedAppBarVariantProps>(
77
+ () => ({
78
+ theme: resolvedVariantProps.theme,
79
+ tone: resolvedVariantProps.tone,
80
+ transitionStyle: resolvedVariantProps.transitionStyle,
81
+ }),
82
+ [resolvedVariantProps.theme, resolvedVariantProps.tone, resolvedVariantProps.transitionStyle],
83
+ );
84
+ const contextValue = React.useMemo<AppBarContextValue>(
85
+ () => ({
86
+ centeredTitlePaddingX,
87
+ safeAreaInsetTop,
88
+ sharedVariantProps,
89
+ setLeftWidth,
90
+ setRightWidth,
91
+ }),
92
+ [centeredTitlePaddingX, safeAreaInsetTop, sharedVariantProps],
93
+ );
94
+
95
+ return {
96
+ contextValue,
97
+ resolvedVariantProps,
98
+ rootLayoutStyle,
99
+ };
100
+ }
@@ -0,0 +1,54 @@
1
+ import "@testing-library/jest-dom";
2
+ import { getQueriesForElement, render } from "@lynx-js/react/testing-library";
3
+ import { describe, expect, it } from "vitest";
4
+
5
+ import { Badge } from "./Badge";
6
+
7
+ function getRenderedQueries() {
8
+ return getQueriesForElement(getRenderedRoot());
9
+ }
10
+
11
+ function getRenderedRoot() {
12
+ const root = elementTree.root;
13
+
14
+ if (!root) {
15
+ throw new Error("Expected Lynx render root to exist.");
16
+ }
17
+
18
+ return root;
19
+ }
20
+
21
+ describe("Badge", () => {
22
+ it("renders label text in the label slot with default variant classes", () => {
23
+ render(<Badge>거래중</Badge>);
24
+
25
+ const { getByText } = getRenderedQueries();
26
+ const root = getRenderedRoot();
27
+ const badgeRoot = root.querySelector(".seed-badge__root");
28
+ const label = getByText("거래중");
29
+
30
+ expect(badgeRoot).toBeInTheDocument();
31
+ expect(badgeRoot).toHaveClass("seed-badge__root--size_medium");
32
+ expect(badgeRoot).toHaveClass("seed-badge__root--variant_solid");
33
+ expect(badgeRoot).toHaveClass("seed-badge__root--tone_neutral");
34
+ expect(label).toHaveClass("seed-badge__label");
35
+ });
36
+
37
+ it("applies variant classes and preserves user className", () => {
38
+ render(
39
+ <Badge className="custom-badge" size="large" variant="outline" tone="brand">
40
+ 추천
41
+ </Badge>,
42
+ );
43
+
44
+ const root = getRenderedRoot();
45
+ const badgeRoot = root.querySelector(".seed-badge__root");
46
+
47
+ expect(badgeRoot).toBeInTheDocument();
48
+ expect(badgeRoot).toHaveClass("custom-badge");
49
+ expect(badgeRoot).toHaveClass("seed-badge__root--size_large");
50
+ expect(badgeRoot).toHaveClass("seed-badge__root--variant_outline");
51
+ expect(badgeRoot).toHaveClass("seed-badge__root--tone_brand");
52
+ expect(badgeRoot).toHaveClass("seed-badge__root--tone_brand-variant_outline");
53
+ });
54
+ });
@@ -0,0 +1,32 @@
1
+ import { badge, type BadgeVariantProps } from "@seed-design/lynx-css/recipes/badge";
2
+ import clsx from "clsx";
3
+ import * as React from "@lynx-js/react";
4
+
5
+ import type { LynxStyledElementProps, LynxViewRef } from "../../types";
6
+
7
+ /**
8
+ * @platform Lynx
9
+ *
10
+ * 웹 Badge와 동일한 variant surface를 제공하지만, Lynx native `<view>` / `<text>`를
11
+ * 직접 렌더링합니다. Badge는 정적 정보 표시 컴포넌트이므로 press/tap API를 별도
12
+ * 소유하지 않습니다.
13
+ */
14
+ export interface BadgeProps extends BadgeVariantProps, LynxStyledElementProps {}
15
+
16
+ export const Badge = React.forwardRef<unknown, BadgeProps>((props, ref) => {
17
+ const [variantProps, otherProps] = badge.splitVariantProps(props);
18
+ const classes = badge(variantProps);
19
+ const { children, className, ...nativeProps } = otherProps;
20
+
21
+ return (
22
+ <view
23
+ {...(ref ? { ref: ref as LynxViewRef } : {})}
24
+ {...nativeProps}
25
+ className={clsx(classes.root, className)}
26
+ >
27
+ <text className={classes.label}>{children}</text>
28
+ </view>
29
+ );
30
+ });
31
+
32
+ Badge.displayName = "Badge";
@@ -0,0 +1 @@
1
+ export { Badge, type BadgeProps } from "./Badge";
@@ -0,0 +1,24 @@
1
+ export {
2
+ BottomSheetBackdrop as Backdrop,
3
+ BottomSheetBody as Body,
4
+ BottomSheetContent as Content,
5
+ BottomSheetDescription as Description,
6
+ BottomSheetFooter as Footer,
7
+ BottomSheetHandle as Handle,
8
+ BottomSheetHeader as Header,
9
+ BottomSheetPositioner as Positioner,
10
+ BottomSheetRoot as Root,
11
+ BottomSheetTitle as Title,
12
+ BottomSheetTrigger as Trigger,
13
+ type BottomSheetBackdropProps as BackdropProps,
14
+ type BottomSheetBodyProps as BodyProps,
15
+ type BottomSheetContentProps as ContentProps,
16
+ type BottomSheetDescriptionProps as DescriptionProps,
17
+ type BottomSheetFooterProps as FooterProps,
18
+ type BottomSheetHandleProps as HandleProps,
19
+ type BottomSheetHeaderProps as HeaderProps,
20
+ type BottomSheetPositionerProps as PositionerProps,
21
+ type BottomSheetRootProps as RootProps,
22
+ type BottomSheetTitleProps as TitleProps,
23
+ type BottomSheetTriggerProps as TriggerProps,
24
+ } from "./BottomSheet";