@xaui/native 0.9.1-alpha.5 → 0.9.1-alpha.7

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.
@@ -741,4 +741,4 @@ function stringify(node) {
741
741
 
742
742
 
743
743
 
744
- exports.IconContext = IconContext; exports.useIconContext = useIconContext; exports.Icon = Icon; exports.PortalContext = PortalContext; exports.Portal = Portal; exports.PortalHost = PortalHost; exports.createSlotContext = createSlotContext; exports.useFeedback = useFeedback; exports.PRESS_SCALE = PRESS_SCALE; exports.PRESS_DURATION = PRESS_DURATION; exports.RELEASE_DURATION = RELEASE_DURATION; exports.HIGHLIGHT_OPACITY = HIGHLIGHT_OPACITY; exports.RIPPLE_OPACITY = RIPPLE_OPACITY; exports.RIPPLE_DURATION = RIPPLE_DURATION; exports.RIPPLE_COVERAGE = RIPPLE_COVERAGE; exports.resolveAnimation = resolveAnimation; exports.resolveSlotAnimation = resolveSlotAnimation; exports.mergeRefs = mergeRefs; exports.mergeProps = mergeProps; exports.Slot = Slot; exports.PressableFeedback = PressableFeedback3; exports.createRecipe = createRecipe; exports.childrenToString = childrenToString;
744
+ exports.mergeRefs = mergeRefs; exports.IconContext = IconContext; exports.useIconContext = useIconContext; exports.Icon = Icon; exports.PortalContext = PortalContext; exports.Portal = Portal; exports.PortalHost = PortalHost; exports.createSlotContext = createSlotContext; exports.useFeedback = useFeedback; exports.PRESS_SCALE = PRESS_SCALE; exports.PRESS_DURATION = PRESS_DURATION; exports.RELEASE_DURATION = RELEASE_DURATION; exports.HIGHLIGHT_OPACITY = HIGHLIGHT_OPACITY; exports.RIPPLE_OPACITY = RIPPLE_OPACITY; exports.RIPPLE_DURATION = RIPPLE_DURATION; exports.RIPPLE_COVERAGE = RIPPLE_COVERAGE; exports.resolveAnimation = resolveAnimation; exports.resolveSlotAnimation = resolveSlotAnimation; exports.mergeProps = mergeProps; exports.Slot = Slot; exports.PressableFeedback = PressableFeedback3; exports.createRecipe = createRecipe; exports.childrenToString = childrenToString;
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
3
 
4
4
 
@@ -22,7 +22,7 @@
22
22
 
23
23
 
24
24
 
25
- var _chunkPSSG6C3Qcjs = require('./chunk-PSSG6C3Q.cjs');
25
+ var _chunk46M765BScjs = require('./chunk-46M765BS.cjs');
26
26
 
27
27
 
28
28
 
@@ -43,14 +43,82 @@ var _chunkAW63PTQ4cjs = require('./chunk-AW63PTQ4.cjs');
43
43
 
44
44
  var _chunk3QBT3Q65cjs = require('./chunk-3QBT3Q65.cjs');
45
45
 
46
+ // src/hooks/use-controllable-state.ts
47
+ var _react = require('react');
46
48
 
49
+ // src/utils/warn-dev.ts
50
+ function warnDev(message) {
51
+ if (typeof __DEV__ !== "undefined" && !__DEV__) return;
52
+ console.warn(`XAUI: ${message}`);
53
+ }
47
54
 
55
+ // src/hooks/use-controllable-state.ts
56
+ function useControllableState({
57
+ value,
58
+ defaultValue,
59
+ onChange
60
+ }) {
61
+ const [uncontrolled, setUncontrolled] = _react.useState.call(void 0, defaultValue);
62
+ const isControlled = value !== void 0;
63
+ const current = isControlled ? value : uncontrolled;
64
+ useControlWarning(isControlled);
65
+ const latest = _react.useRef.call(void 0, current);
66
+ latest.current = current;
67
+ const onChangeRef = _react.useRef.call(void 0, onChange);
68
+ onChangeRef.current = onChange;
69
+ const controlled = _react.useRef.call(void 0, isControlled);
70
+ controlled.current = isControlled;
71
+ const set = _react.useCallback.call(void 0, (next) => {
72
+ const resolved = typeof next === "function" ? next(latest.current) : next;
73
+ if (resolved === latest.current) return;
74
+ if (!controlled.current) setUncontrolled(resolved);
75
+ _optionalChain([onChangeRef, 'access', _ => _.current, 'optionalCall', _2 => _2(resolved)]);
76
+ }, []);
77
+ return [current, set];
78
+ }
79
+ function useControlWarning(isControlled) {
80
+ const wasControlled = _react.useRef.call(void 0, isControlled);
81
+ if (wasControlled.current !== isControlled) {
82
+ warnDev(
83
+ `a component switched from ${wasControlled.current ? "controlled" : "uncontrolled"} to ${isControlled ? "controlled" : "uncontrolled"}. Decide for the life of the component: pass \`value\` always, or never. Passing \`undefined\` for a value you do control reads as "uncontrolled" here.`
84
+ );
85
+ wasControlled.current = isControlled;
86
+ }
87
+ }
48
88
 
89
+ // src/hooks/use-merged-ref.ts
49
90
 
91
+ function useMergedRef(...refs) {
92
+ return _react.useMemo.call(void 0, () => _chunk46M765BScjs.mergeRefs.call(void 0, ...refs), refs);
93
+ }
50
94
 
95
+ // src/hooks/use-press-state.ts
51
96
 
97
+ function usePressState(handlers = {}) {
98
+ const [isPressed, setIsPressed] = _react.useState.call(void 0, false);
99
+ const latest = _react.useRef.call(void 0, handlers);
100
+ latest.current = handlers;
101
+ const onPressIn = _react.useCallback.call(void 0, (event) => {
102
+ setIsPressed(true);
103
+ _optionalChain([latest, 'access', _3 => _3.current, 'access', _4 => _4.onPressIn, 'optionalCall', _5 => _5(event)]);
104
+ }, []);
105
+ const onPressOut = _react.useCallback.call(void 0, (event) => {
106
+ setIsPressed(false);
107
+ _optionalChain([latest, 'access', _6 => _6.current, 'access', _7 => _7.onPressOut, 'optionalCall', _8 => _8(event)]);
108
+ }, []);
109
+ const press = _react.useRef.call(void 0, { onPressIn, onPressOut }).current;
110
+ return [isPressed, press];
111
+ }
52
112
 
113
+ // src/hooks/use-previous.ts
53
114
 
115
+ function usePrevious(value) {
116
+ const previous = _react.useRef.call(void 0, void 0);
117
+ _react.useEffect.call(void 0, () => {
118
+ previous.current = value;
119
+ }, [value]);
120
+ return previous.current;
121
+ }
54
122
 
55
123
 
56
124
 
@@ -81,4 +149,17 @@ var _chunk3QBT3Q65cjs = require('./chunk-3QBT3Q65.cjs');
81
149
 
82
150
 
83
151
 
84
- exports.HIGHLIGHT_OPACITY = _chunkPSSG6C3Qcjs.HIGHLIGHT_OPACITY; exports.Icon = _chunkPSSG6C3Qcjs.Icon; exports.IconContext = _chunkPSSG6C3Qcjs.IconContext; exports.PRESS_DURATION = _chunkPSSG6C3Qcjs.PRESS_DURATION; exports.PRESS_SCALE = _chunkPSSG6C3Qcjs.PRESS_SCALE; exports.Portal = _chunkPSSG6C3Qcjs.Portal; exports.PortalContext = _chunkPSSG6C3Qcjs.PortalContext; exports.PortalHost = _chunkPSSG6C3Qcjs.PortalHost; exports.PressableFeedback = _chunkPSSG6C3Qcjs.PressableFeedback; exports.RELEASE_DURATION = _chunkPSSG6C3Qcjs.RELEASE_DURATION; exports.RIPPLE_COVERAGE = _chunkPSSG6C3Qcjs.RIPPLE_COVERAGE; exports.RIPPLE_DURATION = _chunkPSSG6C3Qcjs.RIPPLE_DURATION; exports.RIPPLE_OPACITY = _chunkPSSG6C3Qcjs.RIPPLE_OPACITY; exports.Slot = _chunkPSSG6C3Qcjs.Slot; exports.ThemeContext = _chunk3QBT3Q65cjs.ThemeContext; exports.XAUIProvider = _chunkAW63PTQ4cjs.XAUIProvider; exports.buildRadius = _chunkAW63PTQ4cjs.buildRadius; exports.buildShadows = _chunkAW63PTQ4cjs.buildShadows; exports.childrenToString = _chunkPSSG6C3Qcjs.childrenToString; exports.createRecipe = _chunkPSSG6C3Qcjs.createRecipe; exports.createSlotContext = _chunkPSSG6C3Qcjs.createSlotContext; exports.createTheme = _chunkAW63PTQ4cjs.createTheme; exports.defaultTheme = _chunkAW63PTQ4cjs.defaultTheme; exports.deriveColors = _chunkAW63PTQ4cjs.deriveColors; exports.deriveTint = _chunk3QBT3Q65cjs.deriveTint; exports.mergeProps = _chunkPSSG6C3Qcjs.mergeProps; exports.mergeRefs = _chunkPSSG6C3Qcjs.mergeRefs; exports.palette = _chunkAW63PTQ4cjs.palette; exports.primitives = _chunkAW63PTQ4cjs.primitives; exports.resolveAnimation = _chunkPSSG6C3Qcjs.resolveAnimation; exports.resolveSlotAnimation = _chunkPSSG6C3Qcjs.resolveSlotAnimation; exports.sourceKeys = _chunkAW63PTQ4cjs.sourceKeys; exports.tokens = _chunkAW63PTQ4cjs.tokens; exports.useColorMode = _chunk3QBT3Q65cjs.useColorMode; exports.useFeedback = _chunkPSSG6C3Qcjs.useFeedback; exports.useIconContext = _chunkPSSG6C3Qcjs.useIconContext; exports.useThemeColor = _chunk3QBT3Q65cjs.useThemeColor; exports.useXAUITheme = _chunk3QBT3Q65cjs.useXAUITheme;
152
+
153
+
154
+
155
+
156
+
157
+
158
+
159
+
160
+
161
+
162
+
163
+
164
+
165
+ exports.HIGHLIGHT_OPACITY = _chunk46M765BScjs.HIGHLIGHT_OPACITY; exports.Icon = _chunk46M765BScjs.Icon; exports.IconContext = _chunk46M765BScjs.IconContext; exports.PRESS_DURATION = _chunk46M765BScjs.PRESS_DURATION; exports.PRESS_SCALE = _chunk46M765BScjs.PRESS_SCALE; exports.Portal = _chunk46M765BScjs.Portal; exports.PortalContext = _chunk46M765BScjs.PortalContext; exports.PortalHost = _chunk46M765BScjs.PortalHost; exports.PressableFeedback = _chunk46M765BScjs.PressableFeedback; exports.RELEASE_DURATION = _chunk46M765BScjs.RELEASE_DURATION; exports.RIPPLE_COVERAGE = _chunk46M765BScjs.RIPPLE_COVERAGE; exports.RIPPLE_DURATION = _chunk46M765BScjs.RIPPLE_DURATION; exports.RIPPLE_OPACITY = _chunk46M765BScjs.RIPPLE_OPACITY; exports.Slot = _chunk46M765BScjs.Slot; exports.ThemeContext = _chunk3QBT3Q65cjs.ThemeContext; exports.XAUIProvider = _chunkAW63PTQ4cjs.XAUIProvider; exports.buildRadius = _chunkAW63PTQ4cjs.buildRadius; exports.buildShadows = _chunkAW63PTQ4cjs.buildShadows; exports.childrenToString = _chunk46M765BScjs.childrenToString; exports.createRecipe = _chunk46M765BScjs.createRecipe; exports.createSlotContext = _chunk46M765BScjs.createSlotContext; exports.createTheme = _chunkAW63PTQ4cjs.createTheme; exports.defaultTheme = _chunkAW63PTQ4cjs.defaultTheme; exports.deriveColors = _chunkAW63PTQ4cjs.deriveColors; exports.deriveTint = _chunk3QBT3Q65cjs.deriveTint; exports.mergeProps = _chunk46M765BScjs.mergeProps; exports.mergeRefs = _chunk46M765BScjs.mergeRefs; exports.palette = _chunkAW63PTQ4cjs.palette; exports.primitives = _chunkAW63PTQ4cjs.primitives; exports.resolveAnimation = _chunk46M765BScjs.resolveAnimation; exports.resolveSlotAnimation = _chunk46M765BScjs.resolveSlotAnimation; exports.sourceKeys = _chunkAW63PTQ4cjs.sourceKeys; exports.tokens = _chunkAW63PTQ4cjs.tokens; exports.useColorMode = _chunk3QBT3Q65cjs.useColorMode; exports.useControllableState = useControllableState; exports.useFeedback = _chunk46M765BScjs.useFeedback; exports.useIconContext = _chunk46M765BScjs.useIconContext; exports.useMergedRef = useMergedRef; exports.usePressState = usePressState; exports.usePrevious = usePrevious; exports.useThemeColor = _chunk3QBT3Q65cjs.useThemeColor; exports.useXAUITheme = _chunk3QBT3Q65cjs.useXAUITheme;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,64 @@
1
- export { AnimationConfig, AnimationProp, AsChildProps, Axes, CompoundVariant, FeedbackContext, FeedbackVariant, HIGHLIGHT_OPACITY, Icon, IconComponentProps, IconContext, IconContextValue, IconProps, MergeableProps, PRESS_DURATION, PRESS_SCALE, Portal, PortalContext, PortalHost, PortalHostProps, PortalMethods, PortalProps, PossibleRef, PressableFeedback, PressableFeedbackHighlightProps, PressableFeedbackProps, PressableFeedbackRippleProps, RELEASE_DURATION, RIPPLE_COVERAGE, RIPPLE_DURATION, RIPPLE_OPACITY, Recipe, RecipeConfig, ResolveArgs, ResolvedAnimation, ResolvedSelection, ResolvedStyles, Selection, Slot, SlotAnimation, SlotProps, SlotStyle, SlotStyles, StateName, States, StyleFn, TintArgs, VariantColors, VariantRole, VariantTokens, childrenToString, createRecipe, createSlotContext, mergeProps, mergeRefs, resolveAnimation, resolveSlotAnimation, useFeedback, useIconContext } from './system/index.cjs';
1
+ import { RefCallback } from 'react';
2
+ import { PossibleRef } from './system/index.cjs';
3
+ export { AnimationConfig, AnimationProp, AsChildProps, Axes, CompoundVariant, FeedbackContext, FeedbackVariant, HIGHLIGHT_OPACITY, Icon, IconComponentProps, IconContext, IconContextValue, IconProps, MergeableProps, PRESS_DURATION, PRESS_SCALE, Portal, PortalContext, PortalHost, PortalHostProps, PortalMethods, PortalProps, PressableFeedback, PressableFeedbackHighlightProps, PressableFeedbackProps, PressableFeedbackRippleProps, RELEASE_DURATION, RIPPLE_COVERAGE, RIPPLE_DURATION, RIPPLE_OPACITY, Recipe, RecipeConfig, ResolveArgs, ResolvedAnimation, ResolvedSelection, ResolvedStyles, Selection, Slot, SlotAnimation, SlotProps, SlotStyle, SlotStyles, StateName, States, StyleFn, TintArgs, VariantColors, VariantRole, VariantTokens, childrenToString, createRecipe, createSlotContext, mergeProps, mergeRefs, resolveAnimation, resolveSlotAnimation, useFeedback, useIconContext } from './system/index.cjs';
4
+ import { GestureResponderEvent } from 'react-native';
2
5
  export { ColorModePreference, PaletteFamily, PaletteShade, ThemeContext, XAUIProvider, XAUIProviderProps, XAUITint, buildRadius, buildShadows, createTheme, defaultTheme, deriveColors, deriveTint, palette, primitives, sourceKeys, tokens, useColorMode, useThemeColor, useXAUITheme } from './theme/index.cjs';
3
6
  export { C as ColorMode, F as FontSizeKey, a as FontWeightKey, R as RadiusKey, S as Size, X as XAUIColors, b as XAUIDerivedColors, c as XAUIPrimitiveColors, d as XAUIRadius, e as XAUIShadow, f as XAUISourceColors, g as XAUITheme, h as XAUIThemeConfig, i as XAUIThemeSet } from './theme.type-C9bFJKFm.cjs';
4
- import 'react';
5
- import 'react-native';
6
7
  import 'react-native-reanimated';
8
+
9
+ type ControllableStateOptions<T> = {
10
+ /** Present means controlled: the caller owns the value and this never stores one. */
11
+ value?: T;
12
+ /** The starting value when uncontrolled. */
13
+ defaultValue: T;
14
+ /** Called with every new value, controlled or not. */
15
+ onChange?: (value: T) => void;
16
+ };
17
+ /**
18
+ * One state that works both ways, so a component never has two code paths for "the
19
+ * caller drives this" and "we do".
20
+ *
21
+ * The setter is stable across renders and reads the current value from a ref, so a
22
+ * handler built on it can be passed to a memoized child without rebuilding it on every
23
+ * render — which is the whole reason components reach for this rather than a local
24
+ * `useState` plus an `if`.
25
+ */
26
+ declare function useControllableState<T>({ value, defaultValue, onChange, }: ControllableStateOptions<T>): [T, (next: T | ((current: T) => T)) => void];
27
+
28
+ /**
29
+ * `mergeRefs` for a component that renders: memoized on the refs it was given, so React
30
+ * does not detach and reattach every one of them on each render — which it does whenever
31
+ * a ref callback changes identity, and which costs a node measurement every time.
32
+ */
33
+ declare function useMergedRef<T>(...refs: Array<PossibleRef<T>>): RefCallback<T>;
34
+
35
+ type PressHandlers = {
36
+ onPressIn?: (event: GestureResponderEvent) => void;
37
+ onPressOut?: (event: GestureResponderEvent) => void;
38
+ };
39
+ /**
40
+ * The press state a root owns, with the handlers that maintain it.
41
+ *
42
+ * It exists because every pressable component needs the same three things and gets one
43
+ * of them wrong on its own: the state has to be *up here* — the recipe resolves on it
44
+ * (R5) — the caller's handlers must be **composed, never replaced**, and the returned
45
+ * handlers must keep their identity so passing them down does not defeat a memo.
46
+ *
47
+ * ```tsx
48
+ * const [isPressed, pressHandlers] = usePressState(props)
49
+ * const styles = recipe.resolve({ theme, selection, states: { pressed: isPressed } })
50
+ * <PressableFeedback isPressed={isPressed} {...pressHandlers} />
51
+ * ```
52
+ */
53
+ declare function usePressState(handlers?: PressHandlers): [boolean, Required<PressHandlers>];
54
+
55
+ /**
56
+ * The value from the render before this one, `undefined` on the first.
57
+ *
58
+ * Written in an effect rather than during render on purpose: reading it mid-render would
59
+ * make "previous" mean something different depending on whether React re-ran the render,
60
+ * which under StrictMode it does.
61
+ */
62
+ declare function usePrevious<T>(value: T): T | undefined;
63
+
64
+ export { type ControllableStateOptions, PossibleRef, type PressHandlers, useControllableState, useMergedRef, usePressState, usePrevious };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,64 @@
1
- export { AnimationConfig, AnimationProp, AsChildProps, Axes, CompoundVariant, FeedbackContext, FeedbackVariant, HIGHLIGHT_OPACITY, Icon, IconComponentProps, IconContext, IconContextValue, IconProps, MergeableProps, PRESS_DURATION, PRESS_SCALE, Portal, PortalContext, PortalHost, PortalHostProps, PortalMethods, PortalProps, PossibleRef, PressableFeedback, PressableFeedbackHighlightProps, PressableFeedbackProps, PressableFeedbackRippleProps, RELEASE_DURATION, RIPPLE_COVERAGE, RIPPLE_DURATION, RIPPLE_OPACITY, Recipe, RecipeConfig, ResolveArgs, ResolvedAnimation, ResolvedSelection, ResolvedStyles, Selection, Slot, SlotAnimation, SlotProps, SlotStyle, SlotStyles, StateName, States, StyleFn, TintArgs, VariantColors, VariantRole, VariantTokens, childrenToString, createRecipe, createSlotContext, mergeProps, mergeRefs, resolveAnimation, resolveSlotAnimation, useFeedback, useIconContext } from './system/index.js';
1
+ import { RefCallback } from 'react';
2
+ import { PossibleRef } from './system/index.js';
3
+ export { AnimationConfig, AnimationProp, AsChildProps, Axes, CompoundVariant, FeedbackContext, FeedbackVariant, HIGHLIGHT_OPACITY, Icon, IconComponentProps, IconContext, IconContextValue, IconProps, MergeableProps, PRESS_DURATION, PRESS_SCALE, Portal, PortalContext, PortalHost, PortalHostProps, PortalMethods, PortalProps, PressableFeedback, PressableFeedbackHighlightProps, PressableFeedbackProps, PressableFeedbackRippleProps, RELEASE_DURATION, RIPPLE_COVERAGE, RIPPLE_DURATION, RIPPLE_OPACITY, Recipe, RecipeConfig, ResolveArgs, ResolvedAnimation, ResolvedSelection, ResolvedStyles, Selection, Slot, SlotAnimation, SlotProps, SlotStyle, SlotStyles, StateName, States, StyleFn, TintArgs, VariantColors, VariantRole, VariantTokens, childrenToString, createRecipe, createSlotContext, mergeProps, mergeRefs, resolveAnimation, resolveSlotAnimation, useFeedback, useIconContext } from './system/index.js';
4
+ import { GestureResponderEvent } from 'react-native';
2
5
  export { ColorModePreference, PaletteFamily, PaletteShade, ThemeContext, XAUIProvider, XAUIProviderProps, XAUITint, buildRadius, buildShadows, createTheme, defaultTheme, deriveColors, deriveTint, palette, primitives, sourceKeys, tokens, useColorMode, useThemeColor, useXAUITheme } from './theme/index.js';
3
6
  export { C as ColorMode, F as FontSizeKey, a as FontWeightKey, R as RadiusKey, S as Size, X as XAUIColors, b as XAUIDerivedColors, c as XAUIPrimitiveColors, d as XAUIRadius, e as XAUIShadow, f as XAUISourceColors, g as XAUITheme, h as XAUIThemeConfig, i as XAUIThemeSet } from './theme.type-C9bFJKFm.js';
4
- import 'react';
5
- import 'react-native';
6
7
  import 'react-native-reanimated';
8
+
9
+ type ControllableStateOptions<T> = {
10
+ /** Present means controlled: the caller owns the value and this never stores one. */
11
+ value?: T;
12
+ /** The starting value when uncontrolled. */
13
+ defaultValue: T;
14
+ /** Called with every new value, controlled or not. */
15
+ onChange?: (value: T) => void;
16
+ };
17
+ /**
18
+ * One state that works both ways, so a component never has two code paths for "the
19
+ * caller drives this" and "we do".
20
+ *
21
+ * The setter is stable across renders and reads the current value from a ref, so a
22
+ * handler built on it can be passed to a memoized child without rebuilding it on every
23
+ * render — which is the whole reason components reach for this rather than a local
24
+ * `useState` plus an `if`.
25
+ */
26
+ declare function useControllableState<T>({ value, defaultValue, onChange, }: ControllableStateOptions<T>): [T, (next: T | ((current: T) => T)) => void];
27
+
28
+ /**
29
+ * `mergeRefs` for a component that renders: memoized on the refs it was given, so React
30
+ * does not detach and reattach every one of them on each render — which it does whenever
31
+ * a ref callback changes identity, and which costs a node measurement every time.
32
+ */
33
+ declare function useMergedRef<T>(...refs: Array<PossibleRef<T>>): RefCallback<T>;
34
+
35
+ type PressHandlers = {
36
+ onPressIn?: (event: GestureResponderEvent) => void;
37
+ onPressOut?: (event: GestureResponderEvent) => void;
38
+ };
39
+ /**
40
+ * The press state a root owns, with the handlers that maintain it.
41
+ *
42
+ * It exists because every pressable component needs the same three things and gets one
43
+ * of them wrong on its own: the state has to be *up here* — the recipe resolves on it
44
+ * (R5) — the caller's handlers must be **composed, never replaced**, and the returned
45
+ * handlers must keep their identity so passing them down does not defeat a memo.
46
+ *
47
+ * ```tsx
48
+ * const [isPressed, pressHandlers] = usePressState(props)
49
+ * const styles = recipe.resolve({ theme, selection, states: { pressed: isPressed } })
50
+ * <PressableFeedback isPressed={isPressed} {...pressHandlers} />
51
+ * ```
52
+ */
53
+ declare function usePressState(handlers?: PressHandlers): [boolean, Required<PressHandlers>];
54
+
55
+ /**
56
+ * The value from the render before this one, `undefined` on the first.
57
+ *
58
+ * Written in an effect rather than during render on purpose: reading it mid-render would
59
+ * make "previous" mean something different depending on whether React re-ran the render,
60
+ * which under StrictMode it does.
61
+ */
62
+ declare function usePrevious<T>(value: T): T | undefined;
63
+
64
+ export { type ControllableStateOptions, PossibleRef, type PressHandlers, useControllableState, useMergedRef, usePressState, usePrevious };
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  resolveSlotAnimation,
23
23
  useFeedback,
24
24
  useIconContext
25
- } from "./chunk-AUDOMZR3.js";
25
+ } from "./chunk-GYK2CAX4.js";
26
26
  import {
27
27
  XAUIProvider,
28
28
  buildRadius,
@@ -42,6 +42,83 @@ import {
42
42
  useThemeColor,
43
43
  useXAUITheme
44
44
  } from "./chunk-X2K2FX3W.js";
45
+
46
+ // src/hooks/use-controllable-state.ts
47
+ import { useCallback, useRef, useState } from "react";
48
+
49
+ // src/utils/warn-dev.ts
50
+ function warnDev(message) {
51
+ if (typeof __DEV__ !== "undefined" && !__DEV__) return;
52
+ console.warn(`XAUI: ${message}`);
53
+ }
54
+
55
+ // src/hooks/use-controllable-state.ts
56
+ function useControllableState({
57
+ value,
58
+ defaultValue,
59
+ onChange
60
+ }) {
61
+ const [uncontrolled, setUncontrolled] = useState(defaultValue);
62
+ const isControlled = value !== void 0;
63
+ const current = isControlled ? value : uncontrolled;
64
+ useControlWarning(isControlled);
65
+ const latest = useRef(current);
66
+ latest.current = current;
67
+ const onChangeRef = useRef(onChange);
68
+ onChangeRef.current = onChange;
69
+ const controlled = useRef(isControlled);
70
+ controlled.current = isControlled;
71
+ const set = useCallback((next) => {
72
+ const resolved = typeof next === "function" ? next(latest.current) : next;
73
+ if (resolved === latest.current) return;
74
+ if (!controlled.current) setUncontrolled(resolved);
75
+ onChangeRef.current?.(resolved);
76
+ }, []);
77
+ return [current, set];
78
+ }
79
+ function useControlWarning(isControlled) {
80
+ const wasControlled = useRef(isControlled);
81
+ if (wasControlled.current !== isControlled) {
82
+ warnDev(
83
+ `a component switched from ${wasControlled.current ? "controlled" : "uncontrolled"} to ${isControlled ? "controlled" : "uncontrolled"}. Decide for the life of the component: pass \`value\` always, or never. Passing \`undefined\` for a value you do control reads as "uncontrolled" here.`
84
+ );
85
+ wasControlled.current = isControlled;
86
+ }
87
+ }
88
+
89
+ // src/hooks/use-merged-ref.ts
90
+ import { useMemo } from "react";
91
+ function useMergedRef(...refs) {
92
+ return useMemo(() => mergeRefs(...refs), refs);
93
+ }
94
+
95
+ // src/hooks/use-press-state.ts
96
+ import { useCallback as useCallback2, useRef as useRef2, useState as useState2 } from "react";
97
+ function usePressState(handlers = {}) {
98
+ const [isPressed, setIsPressed] = useState2(false);
99
+ const latest = useRef2(handlers);
100
+ latest.current = handlers;
101
+ const onPressIn = useCallback2((event) => {
102
+ setIsPressed(true);
103
+ latest.current.onPressIn?.(event);
104
+ }, []);
105
+ const onPressOut = useCallback2((event) => {
106
+ setIsPressed(false);
107
+ latest.current.onPressOut?.(event);
108
+ }, []);
109
+ const press = useRef2({ onPressIn, onPressOut }).current;
110
+ return [isPressed, press];
111
+ }
112
+
113
+ // src/hooks/use-previous.ts
114
+ import { useEffect, useRef as useRef3 } from "react";
115
+ function usePrevious(value) {
116
+ const previous = useRef3(void 0);
117
+ useEffect(() => {
118
+ previous.current = value;
119
+ }, [value]);
120
+ return previous.current;
121
+ }
45
122
  export {
46
123
  HIGHLIGHT_OPACITY,
47
124
  Icon,
@@ -77,8 +154,12 @@ export {
77
154
  sourceKeys,
78
155
  tokens,
79
156
  useColorMode,
157
+ useControllableState,
80
158
  useFeedback,
81
159
  useIconContext,
160
+ useMergedRef,
161
+ usePressState,
162
+ usePrevious,
82
163
  useThemeColor,
83
164
  useXAUITheme
84
165
  };
@@ -22,7 +22,7 @@
22
22
 
23
23
 
24
24
 
25
- var _chunkPSSG6C3Qcjs = require('../chunk-PSSG6C3Q.cjs');
25
+ var _chunk46M765BScjs = require('../chunk-46M765BS.cjs');
26
26
  require('../chunk-3QBT3Q65.cjs');
27
27
 
28
28
 
@@ -48,4 +48,4 @@ require('../chunk-3QBT3Q65.cjs');
48
48
 
49
49
 
50
50
 
51
- exports.HIGHLIGHT_OPACITY = _chunkPSSG6C3Qcjs.HIGHLIGHT_OPACITY; exports.Icon = _chunkPSSG6C3Qcjs.Icon; exports.IconContext = _chunkPSSG6C3Qcjs.IconContext; exports.PRESS_DURATION = _chunkPSSG6C3Qcjs.PRESS_DURATION; exports.PRESS_SCALE = _chunkPSSG6C3Qcjs.PRESS_SCALE; exports.Portal = _chunkPSSG6C3Qcjs.Portal; exports.PortalContext = _chunkPSSG6C3Qcjs.PortalContext; exports.PortalHost = _chunkPSSG6C3Qcjs.PortalHost; exports.PressableFeedback = _chunkPSSG6C3Qcjs.PressableFeedback; exports.RELEASE_DURATION = _chunkPSSG6C3Qcjs.RELEASE_DURATION; exports.RIPPLE_COVERAGE = _chunkPSSG6C3Qcjs.RIPPLE_COVERAGE; exports.RIPPLE_DURATION = _chunkPSSG6C3Qcjs.RIPPLE_DURATION; exports.RIPPLE_OPACITY = _chunkPSSG6C3Qcjs.RIPPLE_OPACITY; exports.Slot = _chunkPSSG6C3Qcjs.Slot; exports.childrenToString = _chunkPSSG6C3Qcjs.childrenToString; exports.createRecipe = _chunkPSSG6C3Qcjs.createRecipe; exports.createSlotContext = _chunkPSSG6C3Qcjs.createSlotContext; exports.mergeProps = _chunkPSSG6C3Qcjs.mergeProps; exports.mergeRefs = _chunkPSSG6C3Qcjs.mergeRefs; exports.resolveAnimation = _chunkPSSG6C3Qcjs.resolveAnimation; exports.resolveSlotAnimation = _chunkPSSG6C3Qcjs.resolveSlotAnimation; exports.useFeedback = _chunkPSSG6C3Qcjs.useFeedback; exports.useIconContext = _chunkPSSG6C3Qcjs.useIconContext;
51
+ exports.HIGHLIGHT_OPACITY = _chunk46M765BScjs.HIGHLIGHT_OPACITY; exports.Icon = _chunk46M765BScjs.Icon; exports.IconContext = _chunk46M765BScjs.IconContext; exports.PRESS_DURATION = _chunk46M765BScjs.PRESS_DURATION; exports.PRESS_SCALE = _chunk46M765BScjs.PRESS_SCALE; exports.Portal = _chunk46M765BScjs.Portal; exports.PortalContext = _chunk46M765BScjs.PortalContext; exports.PortalHost = _chunk46M765BScjs.PortalHost; exports.PressableFeedback = _chunk46M765BScjs.PressableFeedback; exports.RELEASE_DURATION = _chunk46M765BScjs.RELEASE_DURATION; exports.RIPPLE_COVERAGE = _chunk46M765BScjs.RIPPLE_COVERAGE; exports.RIPPLE_DURATION = _chunk46M765BScjs.RIPPLE_DURATION; exports.RIPPLE_OPACITY = _chunk46M765BScjs.RIPPLE_OPACITY; exports.Slot = _chunk46M765BScjs.Slot; exports.childrenToString = _chunk46M765BScjs.childrenToString; exports.createRecipe = _chunk46M765BScjs.createRecipe; exports.createSlotContext = _chunk46M765BScjs.createSlotContext; exports.mergeProps = _chunk46M765BScjs.mergeProps; exports.mergeRefs = _chunk46M765BScjs.mergeRefs; exports.resolveAnimation = _chunk46M765BScjs.resolveAnimation; exports.resolveSlotAnimation = _chunk46M765BScjs.resolveSlotAnimation; exports.useFeedback = _chunk46M765BScjs.useFeedback; exports.useIconContext = _chunk46M765BScjs.useIconContext;
@@ -1,10 +1,25 @@
1
1
  import * as react from 'react';
2
- import { ComponentType, ReactNode, Provider, Ref, RefCallback } from 'react';
2
+ import { Ref, ComponentType, ReactNode, Provider, RefCallback } from 'react';
3
3
  import * as react_native from 'react-native';
4
4
  import { ImageSourcePropType, StyleProp, ImageStyle, PressableProps, ViewStyle, TextStyle } from 'react-native';
5
5
  import { SharedValue } from 'react-native-reanimated';
6
6
  import { g as XAUITheme, X as XAUIColors } from '../theme.type-C9bFJKFm.cjs';
7
7
 
8
+ /** Anything React accepts as a ref, plus the absence of one. */
9
+ type PossibleRef<T> = Ref<T> | undefined;
10
+ /**
11
+ * The props `mergeProps` knows how to combine. Deliberately loose: it merges whatever a
12
+ * root hands to whatever child it was given, and neither side is knowable from here.
13
+ */
14
+ type MergeableProps = Record<string, unknown>;
15
+ type AsChildProps = {
16
+ /**
17
+ * Merge this component's props into its single child instead of rendering an element
18
+ * of its own — a navigation `Link` as a `Button`, a bespoke trigger as a `Select`.
19
+ */
20
+ asChild?: boolean;
21
+ };
22
+
8
23
  /**
9
24
  * The props Lucide, Ionicons and `react-native-vector-icons` all accept — the shape
10
25
  * `as` is handed. It is a convention rather than an interface anyone published, which is
@@ -389,21 +404,6 @@ declare function childrenToString(children: ReactNode): string | null;
389
404
  */
390
405
  declare function createSlotContext<T>(name: string): readonly [Provider<T | null>, () => T];
391
406
 
392
- /** Anything React accepts as a ref, plus the absence of one. */
393
- type PossibleRef<T> = Ref<T> | undefined;
394
- /**
395
- * The props `mergeProps` knows how to combine. Deliberately loose: it merges whatever a
396
- * root hands to whatever child it was given, and neither side is knowable from here.
397
- */
398
- type MergeableProps = Record<string, unknown>;
399
- type AsChildProps = {
400
- /**
401
- * Merge this component's props into its single child instead of rendering an element
402
- * of its own — a navigation `Link` as a `Button`, a bespoke trigger as a `Select`.
403
- */
404
- asChild?: boolean;
405
- };
406
-
407
407
  /**
408
408
  * Merges a root's own props into the child it renders through `asChild` (R12). Four
409
409
  * rules, and the child wins wherever they do not apply — it is the more specific intent:
@@ -1,10 +1,25 @@
1
1
  import * as react from 'react';
2
- import { ComponentType, ReactNode, Provider, Ref, RefCallback } from 'react';
2
+ import { Ref, ComponentType, ReactNode, Provider, RefCallback } from 'react';
3
3
  import * as react_native from 'react-native';
4
4
  import { ImageSourcePropType, StyleProp, ImageStyle, PressableProps, ViewStyle, TextStyle } from 'react-native';
5
5
  import { SharedValue } from 'react-native-reanimated';
6
6
  import { g as XAUITheme, X as XAUIColors } from '../theme.type-C9bFJKFm.js';
7
7
 
8
+ /** Anything React accepts as a ref, plus the absence of one. */
9
+ type PossibleRef<T> = Ref<T> | undefined;
10
+ /**
11
+ * The props `mergeProps` knows how to combine. Deliberately loose: it merges whatever a
12
+ * root hands to whatever child it was given, and neither side is knowable from here.
13
+ */
14
+ type MergeableProps = Record<string, unknown>;
15
+ type AsChildProps = {
16
+ /**
17
+ * Merge this component's props into its single child instead of rendering an element
18
+ * of its own — a navigation `Link` as a `Button`, a bespoke trigger as a `Select`.
19
+ */
20
+ asChild?: boolean;
21
+ };
22
+
8
23
  /**
9
24
  * The props Lucide, Ionicons and `react-native-vector-icons` all accept — the shape
10
25
  * `as` is handed. It is a convention rather than an interface anyone published, which is
@@ -389,21 +404,6 @@ declare function childrenToString(children: ReactNode): string | null;
389
404
  */
390
405
  declare function createSlotContext<T>(name: string): readonly [Provider<T | null>, () => T];
391
406
 
392
- /** Anything React accepts as a ref, plus the absence of one. */
393
- type PossibleRef<T> = Ref<T> | undefined;
394
- /**
395
- * The props `mergeProps` knows how to combine. Deliberately loose: it merges whatever a
396
- * root hands to whatever child it was given, and neither side is knowable from here.
397
- */
398
- type MergeableProps = Record<string, unknown>;
399
- type AsChildProps = {
400
- /**
401
- * Merge this component's props into its single child instead of rendering an element
402
- * of its own — a navigation `Link` as a `Button`, a bespoke trigger as a `Select`.
403
- */
404
- asChild?: boolean;
405
- };
406
-
407
407
  /**
408
408
  * Merges a root's own props into the child it renders through `asChild` (R12). Four
409
409
  * rules, and the child wins wherever they do not apply — it is the more specific intent:
@@ -22,7 +22,7 @@ import {
22
22
  resolveSlotAnimation,
23
23
  useFeedback,
24
24
  useIconContext
25
- } from "../chunk-AUDOMZR3.js";
25
+ } from "../chunk-GYK2CAX4.js";
26
26
  import "../chunk-X2K2FX3W.js";
27
27
  export {
28
28
  HIGHLIGHT_OPACITY,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xaui/native",
3
- "version": "0.9.1-alpha.5",
3
+ "version": "0.9.1-alpha.7",
4
4
  "description": "Composition-first React Native UI components with native animations powered by Reanimated",
5
5
  "keywords": [
6
6
  "react-native",
@@ -718,6 +718,7 @@ function stringify(node) {
718
718
  }
719
719
 
720
720
  export {
721
+ mergeRefs,
721
722
  IconContext,
722
723
  useIconContext,
723
724
  Icon,
@@ -735,7 +736,6 @@ export {
735
736
  RIPPLE_COVERAGE,
736
737
  resolveAnimation,
737
738
  resolveSlotAnimation,
738
- mergeRefs,
739
739
  mergeProps,
740
740
  Slot,
741
741
  PressableFeedback3 as PressableFeedback,