@xaui/native 0.9.1-alpha.40 → 0.9.1-alpha.41

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.
@@ -0,0 +1,518 @@
1
+ import { useControllableState } from "./chunk-F6W3JQ7K.js";
2
+ import { PressableFeedback } from "./chunk-6UEZJRVI.js";
3
+ import { usePressState } from "./chunk-423RQBOX.js";
4
+ import { createRecipe, radiusAxis } from "./chunk-4GTAZM2C.js";
5
+ import { useXAUITheme } from "./chunk-A3EGFI6T.js";
6
+ import { childrenToString, createSlotContext } from "./chunk-K72UDPVN.js";
7
+ import { useStyleProps } from "./chunk-M63GFNKV.js";
8
+
9
+ // src/components/tabs/tabs-content.tsx
10
+ import { forwardRef } from "react";
11
+ import { View } from "react-native";
12
+
13
+ // src/components/tabs/tabs.context.ts
14
+ var [TabsProvider, useTabs] = createSlotContext("Tabs");
15
+ var [TabsTriggerProvider, useTabsTrigger] = createSlotContext("Tabs.Trigger");
16
+
17
+ // src/components/tabs/tabs-content.tsx
18
+ import { jsx } from "react/jsx-runtime";
19
+ var TabsContent = forwardRef(function TabsContent2({
20
+ value,
21
+ children,
22
+ accessibilityRole = "tab",
23
+ style,
24
+ ...props
25
+ }, ref) {
26
+ const {
27
+ value: selected
28
+ } = useTabs();
29
+ const [styleProps, rest] = useStyleProps(props);
30
+ if (selected !== value) return null;
31
+ return /* @__PURE__ */jsx(View, {
32
+ ref,
33
+ accessibilityRole,
34
+ ...rest,
35
+ style: [styleProps, style],
36
+ children
37
+ });
38
+ });
39
+ TabsContent.displayName = "XAUI.Tabs.Content";
40
+
41
+ // src/components/tabs/tabs-indicator.tsx
42
+ import { useEffect } from "react";
43
+ import Animated, { useAnimatedStyle, useSharedValue, withSpring } from "react-native-reanimated";
44
+
45
+ // src/components/tabs/tabs.animation.ts
46
+ var INDICATOR_SPRING = {
47
+ damping: 20,
48
+ stiffness: 220,
49
+ mass: 0.6
50
+ };
51
+
52
+ // src/components/tabs/tabs-indicator.tsx
53
+ import { jsx as jsx2 } from "react/jsx-runtime";
54
+ const _worklet_9378830951522_init_data = {
55
+ code: "function chunkG3CCT4EYJs1(){const{x,width,hasArrived}=this.__closure;return{transform:[{translateX:x.get()}],width:width.get(),opacity:hasArrived.get()?1:0};}",
56
+ location: "/home/runner/work/xaui/xaui/packages/native/dist/chunk-G3CCT4EY.js",
57
+ sourceMap: "{\"version\":3,\"names\":[\"chunkG3CCT4EYJs1\",\"x\",\"width\",\"hasArrived\",\"__closure\",\"transform\",\"translateX\",\"get\",\"opacity\"],\"sources\":[\"/home/runner/work/xaui/xaui/packages/native/dist/chunk-G3CCT4EY.js\"],\"mappings\":\"AAkFkC,SAAAA,iBAAA,QAAAC,CAAA,CAAAC,KAAA,CAAAC,UAAA,OAAAC,SAAA,OAAO,CACrCC,SAAS,CAAE,CAAC,CAAEC,UAAU,CAAEL,CAAC,CAACM,GAAG,CAAC,CAAE,CAAC,CAAC,CACpCL,KAAK,CAAEA,KAAK,CAACK,GAAG,CAAC,CAAC,CAClBC,OAAO,CAAEL,UAAU,CAACI,GAAG,CAAC,CAAC,CAAG,CAAC,CAAG,CAClC,CAAC\",\"ignoreList\":[]}"
58
+ };
59
+ function TabsIndicator({
60
+ style,
61
+ ...props
62
+ }) {
63
+ const {
64
+ indicatorStyle,
65
+ value,
66
+ rects
67
+ } = useTabs();
68
+ const [styleProps, rest] = useStyleProps(props);
69
+ const rect = value === void 0 ? void 0 : rects[value];
70
+ const x = useSharedValue(rect?.x ?? 0);
71
+ const width = useSharedValue(rect?.width ?? 0);
72
+ const hasArrived = useSharedValue(rect !== void 0);
73
+ useEffect(() => {
74
+ if (rect === void 0) return;
75
+ if (hasArrived.get()) {
76
+ x.set(withSpring(rect.x, INDICATOR_SPRING));
77
+ width.set(withSpring(rect.width, INDICATOR_SPRING));
78
+ } else {
79
+ x.set(rect.x);
80
+ width.set(rect.width);
81
+ hasArrived.set(true);
82
+ }
83
+ }, [rect, hasArrived, width, x]);
84
+ const travel = useAnimatedStyle(function chunkG3CCT4EYJs1Factory({
85
+ _worklet_9378830951522_init_data,
86
+ x,
87
+ width,
88
+ hasArrived
89
+ }) {
90
+ const _e = [new global.Error(), -4, -27];
91
+ const chunkG3CCT4EYJs1 = () => ({
92
+ transform: [{
93
+ translateX: x.get()
94
+ }],
95
+ width: width.get(),
96
+ opacity: hasArrived.get() ? 1 : 0
97
+ });
98
+ chunkG3CCT4EYJs1.__closure = {
99
+ x,
100
+ width,
101
+ hasArrived
102
+ };
103
+ chunkG3CCT4EYJs1.__workletHash = 9378830951522;
104
+ chunkG3CCT4EYJs1.__pluginVersion = "0.7.4";
105
+ chunkG3CCT4EYJs1.__initData = _worklet_9378830951522_init_data;
106
+ chunkG3CCT4EYJs1.__stackDetails = _e;
107
+ return chunkG3CCT4EYJs1;
108
+ }({
109
+ _worklet_9378830951522_init_data,
110
+ x,
111
+ width,
112
+ hasArrived
113
+ }));
114
+ return /* @__PURE__ */jsx2(Animated.View, {
115
+ ...rest,
116
+ style: [indicatorStyle, travel, styleProps, style]
117
+ });
118
+ }
119
+ TabsIndicator.displayName = "XAUI.Tabs.Indicator";
120
+
121
+ // src/components/tabs/tabs-label.tsx
122
+ import { forwardRef as forwardRef2 } from "react";
123
+ import { Text } from "react-native";
124
+ import { jsx as jsx3 } from "react/jsx-runtime";
125
+ var TabsLabel = forwardRef2(function TabsLabel2({
126
+ children,
127
+ numberOfLines = 1,
128
+ style,
129
+ ...props
130
+ }, ref) {
131
+ const {
132
+ labelStyle,
133
+ labelSelectedStyle
134
+ } = useTabs();
135
+ const {
136
+ isSelected
137
+ } = useTabsTrigger();
138
+ const [styleProps, rest] = useStyleProps(props);
139
+ return /* @__PURE__ */jsx3(Text, {
140
+ ref,
141
+ numberOfLines,
142
+ ...rest,
143
+ style: [labelStyle, isSelected && labelSelectedStyle, styleProps, style],
144
+ children
145
+ });
146
+ });
147
+ TabsLabel.displayName = "XAUI.Tabs.Label";
148
+
149
+ // src/components/tabs/tabs-list.tsx
150
+ import { forwardRef as forwardRef3 } from "react";
151
+ import { View as View2 } from "react-native";
152
+ import { jsx as jsx4 } from "react/jsx-runtime";
153
+ var TabsList = forwardRef3(function TabsList2({
154
+ children,
155
+ accessibilityRole = "tablist",
156
+ style,
157
+ ...props
158
+ }, ref) {
159
+ const {
160
+ listStyle
161
+ } = useTabs();
162
+ const [styleProps, rest] = useStyleProps(props);
163
+ return /* @__PURE__ */jsx4(View2, {
164
+ ref,
165
+ accessibilityRole,
166
+ ...rest,
167
+ style: [listStyle, styleProps, style],
168
+ children
169
+ });
170
+ });
171
+ TabsList.displayName = "XAUI.Tabs.List";
172
+
173
+ // src/components/tabs/tabs-trigger.tsx
174
+ import { forwardRef as forwardRef4, useCallback, useMemo } from "react";
175
+ import { jsx as jsx5 } from "react/jsx-runtime";
176
+ var TabsTrigger = forwardRef4(function TabsTrigger2({
177
+ value,
178
+ children,
179
+ isDisabled = false,
180
+ asChild = false,
181
+ accessibilityRole = "tab",
182
+ accessibilityState,
183
+ style,
184
+ onLayout,
185
+ onPress,
186
+ onPressIn,
187
+ onPressOut,
188
+ ...props
189
+ }, ref) {
190
+ const {
191
+ triggerStyle,
192
+ value: selected,
193
+ isDisabled: isRootDisabled,
194
+ select,
195
+ setRect
196
+ } = useTabs();
197
+ const [styleProps, rest] = useStyleProps(props);
198
+ const [isPressed, press] = usePressState({
199
+ onPressIn,
200
+ onPressOut
201
+ });
202
+ const isSelected = selected === value;
203
+ const disabled = isRootDisabled || isDisabled;
204
+ const measure = useCallback(event => {
205
+ onLayout?.(event);
206
+ const {
207
+ x,
208
+ width
209
+ } = event.nativeEvent.layout;
210
+ setRect(value, {
211
+ x,
212
+ width
213
+ });
214
+ }, [onLayout, setRect, value]);
215
+ const handlePress = useCallback(event => {
216
+ onPress?.(event);
217
+ select(value);
218
+ }, [onPress, select, value]);
219
+ const context = useMemo(() => ({
220
+ isSelected,
221
+ isPressed,
222
+ isDisabled: disabled
223
+ }), [isSelected, isPressed, disabled]);
224
+ const text = typeof children === "function" ? null : childrenToString(children);
225
+ return /* @__PURE__ */jsx5(TabsTriggerProvider, {
226
+ value: context,
227
+ children: /* @__PURE__ */jsx5(PressableFeedback, {
228
+ ref,
229
+ isPressed,
230
+ isDisabled: disabled,
231
+ asChild,
232
+ accessibilityRole,
233
+ accessibilityState: {
234
+ disabled,
235
+ selected: isSelected,
236
+ ...accessibilityState
237
+ },
238
+ ...rest,
239
+ onLayout: measure,
240
+ style: [triggerStyle, styleProps, typeof style === "function" ? style({
241
+ pressed: isPressed
242
+ }) : style],
243
+ onPress: handlePress,
244
+ onPressIn: press.onPressIn,
245
+ onPressOut: press.onPressOut,
246
+ children: typeof children === "function" ? children(context) : text !== null ?
247
+ // R3 — a stringifiable tab becomes its label, which is what makes the common
248
+ // case `<Tabs.Trigger value="all">Tout</Tabs.Trigger>`.
249
+ /* @__PURE__ */
250
+ jsx5(TabsLabel, {
251
+ children: text
252
+ }) : children
253
+ })
254
+ });
255
+ });
256
+ TabsTrigger.displayName = "XAUI.Tabs.Trigger";
257
+
258
+ // src/components/tabs/tabs.tsx
259
+ import { forwardRef as forwardRef5, useCallback as useCallback2, useMemo as useMemo2, useState } from "react";
260
+ import { StyleSheet, View as View3 } from "react-native";
261
+
262
+ // src/components/tabs/tabs.recipe.ts
263
+ var SLOTS = ["root", "list", "trigger", "label", "indicator", "content"];
264
+ var VARIANT_TOKENS = {
265
+ primary: {
266
+ bg: "default",
267
+ bgSelected: "segment",
268
+ fgSelected: "segmentForeground"
269
+ },
270
+ secondary: {
271
+ bgSelected: "accent",
272
+ fgSelected: "foreground"
273
+ },
274
+ // The accent rather than the foreground: with nothing else moving, the colour is the
275
+ // whole signal, and a chosen tab in plain ink reads as one that is merely darker.
276
+ light: {
277
+ fgSelected: "accent"
278
+ }
279
+ };
280
+ var SIZES = {
281
+ sm: {
282
+ paddingHorizontal: 2.5,
283
+ paddingVertical: 1,
284
+ gap: 1,
285
+ label: "sm"
286
+ },
287
+ md: {
288
+ paddingHorizontal: 3,
289
+ paddingVertical: 1.5,
290
+ gap: 1.5,
291
+ label: "md"
292
+ },
293
+ lg: {
294
+ paddingHorizontal: 4,
295
+ paddingVertical: 2,
296
+ gap: 2,
297
+ label: "lg"
298
+ }
299
+ };
300
+ var TRACK_INSET = 3;
301
+ function sizeAxis(step) {
302
+ const {
303
+ paddingHorizontal,
304
+ paddingVertical,
305
+ gap,
306
+ label
307
+ } = step;
308
+ return theme => ({
309
+ trigger: {
310
+ paddingHorizontal: theme.spacing(paddingHorizontal),
311
+ paddingVertical: theme.spacing(paddingVertical),
312
+ gap: theme.spacing(gap)
313
+ },
314
+ label: {
315
+ fontSize: theme.fontSizes[label],
316
+ lineHeight: theme.lineHeights[label]
317
+ }
318
+ });
319
+ }
320
+ var tabsRecipe = createRecipe({
321
+ slots: SLOTS,
322
+ base: theme => ({
323
+ root: {
324
+ flexDirection: "column",
325
+ gap: theme.spacing(2)
326
+ },
327
+ list: {
328
+ // Hugs its tabs rather than filling the row. A tab bar as wide as the screen with
329
+ // three tabs in it is a segmented control pretending to be a navigation bar.
330
+ alignSelf: "flex-start",
331
+ flexDirection: "row",
332
+ alignItems: "center",
333
+ borderCurve: "continuous"
334
+ },
335
+ trigger: {
336
+ flexDirection: "row",
337
+ alignItems: "center",
338
+ justifyContent: "center"
339
+ },
340
+ label: {
341
+ fontFamily: theme.fontFamilies.body,
342
+ fontWeight: theme.fontWeights.medium,
343
+ color: theme.colors.muted
344
+ },
345
+ // Behind the triggers, not over them: it is the surface the chosen tab sits on.
346
+ indicator: {
347
+ position: "absolute",
348
+ zIndex: 0,
349
+ borderCurve: "continuous"
350
+ }
351
+ }),
352
+ variantTokens: VARIANT_TOKENS,
353
+ paint: (_theme, colors) => ({
354
+ list: {
355
+ backgroundColor: colors.bg
356
+ },
357
+ indicator: {
358
+ backgroundColor: colors.bgSelected
359
+ },
360
+ // Read by the root and handed to the chosen trigger's label alone, which is why it is
361
+ // on a slot the recipe otherwise leaves to `muted`.
362
+ content: {
363
+ color: colors.fgSelected
364
+ }
365
+ }),
366
+ variants: {
367
+ size: {
368
+ sm: sizeAxis(SIZES.sm),
369
+ md: sizeAxis(SIZES.md),
370
+ lg: sizeAxis(SIZES.lg)
371
+ },
372
+ radius: radiusAxis("list", "indicator")
373
+ },
374
+ /**
375
+ * Where the shapes differ, and `light` is absent on purpose: the base gives the list no
376
+ * padding, no corner and no edge, so a shape that adds none of them is the base itself.
377
+ * `primary` is a pill inside a filled track, so the track is padded and both corners are
378
+ * round; `secondary` is a rule along a bottom edge, so the track carries a hairline and
379
+ * the indicator is that rule.
380
+ */
381
+ compoundVariants: [{
382
+ when: {
383
+ variant: "primary"
384
+ },
385
+ style: theme => ({
386
+ list: {
387
+ padding: TRACK_INSET,
388
+ borderRadius: theme.radius["3xl"]
389
+ },
390
+ indicator: {
391
+ top: TRACK_INSET,
392
+ bottom: TRACK_INSET,
393
+ borderRadius: theme.radius["3xl"],
394
+ ...theme.shadows.surface
395
+ }
396
+ })
397
+ }, {
398
+ when: {
399
+ variant: "secondary"
400
+ },
401
+ style: theme => ({
402
+ list: {
403
+ borderBottomWidth: theme.borderWidth.default,
404
+ borderColor: theme.colors.border
405
+ },
406
+ // Two points rather than a hairline: a rule that says which tab is chosen has to
407
+ // outweigh the one it sits on.
408
+ indicator: {
409
+ bottom: 0,
410
+ height: 2,
411
+ borderRadius: 0
412
+ }
413
+ })
414
+ }],
415
+ states: {
416
+ disabled: theme => ({
417
+ list: {
418
+ opacity: theme.opacity.disabled
419
+ }
420
+ })
421
+ },
422
+ defaultVariants: {
423
+ variant: "primary",
424
+ size: "md"
425
+ }
426
+ });
427
+
428
+ // src/components/tabs/tabs.tsx
429
+ import { jsx as jsx6 } from "react/jsx-runtime";
430
+ var TabsRoot = forwardRef5(function Tabs({
431
+ children,
432
+ variant,
433
+ size,
434
+ radius,
435
+ color,
436
+ value: controlledValue,
437
+ defaultValue,
438
+ onValueChange,
439
+ isDisabled = false,
440
+ style,
441
+ ...props
442
+ }, ref) {
443
+ const theme = useXAUITheme();
444
+ const [styleProps, rest] = useStyleProps(props);
445
+ const [rects, setRects] = useState({});
446
+ const [value, setValue] = useControllableState({
447
+ value: controlledValue,
448
+ defaultValue,
449
+ onChange: onValueChange
450
+ });
451
+ const selection = {
452
+ variant,
453
+ size,
454
+ radius
455
+ };
456
+ const styles = tabsRecipe.resolve({
457
+ theme,
458
+ selection,
459
+ states: {
460
+ disabled: isDisabled
461
+ }
462
+ });
463
+ const tint = color ? tabsRecipe.tint({
464
+ theme,
465
+ color,
466
+ selection
467
+ }) : void 0;
468
+ const select = useCallback2(next => setValue(next), [setValue]);
469
+ const setRect = useCallback2((tab, rect) => {
470
+ setRects(current => {
471
+ const previous = current[tab];
472
+ if (previous && previous.x === rect.x && previous.width === rect.width) return current;
473
+ return {
474
+ ...current,
475
+ [tab]: rect
476
+ };
477
+ });
478
+ }, []);
479
+ const context = useMemo2(() => {
480
+ const selected = StyleSheet.flatten([styles.content, tint?.content]);
481
+ return {
482
+ listStyle: tint ? [styles.list, tint.list] : styles.list,
483
+ triggerStyle: styles.trigger,
484
+ labelStyle: styles.label,
485
+ labelSelectedStyle: {
486
+ color: selected.color
487
+ },
488
+ indicatorStyle: tint ? [styles.indicator, tint.indicator] : styles.indicator,
489
+ contentStyle: void 0,
490
+ variant: variant ?? "primary",
491
+ value,
492
+ isDisabled,
493
+ select,
494
+ rects,
495
+ setRect
496
+ };
497
+ }, [styles, tint, variant, value, isDisabled, select, rects, setRect]);
498
+ return /* @__PURE__ */jsx6(TabsProvider, {
499
+ value: context,
500
+ children: /* @__PURE__ */jsx6(View3, {
501
+ ref,
502
+ ...rest,
503
+ style: [styles.root, styleProps, style],
504
+ children
505
+ })
506
+ });
507
+ });
508
+ TabsRoot.displayName = "XAUI.Tabs.Root";
509
+
510
+ // src/components/tabs/index.ts
511
+ var Tabs2 = Object.assign(TabsRoot, {
512
+ List: TabsList,
513
+ Trigger: TabsTrigger,
514
+ Label: TabsLabel,
515
+ Indicator: TabsIndicator,
516
+ Content: TabsContent
517
+ });
518
+ export { useTabs, useTabsTrigger, TabsContent, TabsIndicator, TabsLabel, TabsList, TabsTrigger, tabsRecipe, TabsRoot, Tabs2 as Tabs };