@oxyhq/bloom 0.3.4 → 0.3.6

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.
@@ -48,6 +48,8 @@ const ButtonComponent = ({
48
48
  textStyle,
49
49
  icon,
50
50
  iconPosition = 'left',
51
+ loading = false,
52
+ loadingColor,
51
53
  accessibilityLabel,
52
54
  accessibilityHint,
53
55
  hitSlop,
@@ -57,11 +59,12 @@ const ButtonComponent = ({
57
59
  }) => {
58
60
  const theme = (0, _useTheme.useTheme)();
59
61
  const hasScaleFeedback = SCALE_VARIANTS.has(variant);
62
+ const isInteractionBlocked = disabled || loading;
60
63
  const {
61
64
  scaleAnim,
62
65
  onPressIn,
63
66
  onPressOut
64
- } = (0, _usePressAnimation.usePressAnimation)(hasScaleFeedback ? PRESS_SCALE : undefined);
67
+ } = (0, _usePressAnimation.usePressAnimation)(hasScaleFeedback && !isInteractionBlocked ? PRESS_SCALE : undefined);
65
68
  const baseStyles = (0, _react.useMemo)(() => {
66
69
  const sizeConfig = SIZE_CONFIG[size];
67
70
  const styles = {
@@ -108,68 +111,103 @@ const ButtonComponent = ({
108
111
  }
109
112
  return styles;
110
113
  }, [variant, size, theme]);
111
- const computedTextStyle = (0, _react.useMemo)(() => {
112
- const sizeConfig = SIZE_CONFIG[size];
113
- const styles = {
114
- fontSize: sizeConfig.fontSize,
115
- fontWeight: _reactNative.Platform.OS === 'web' ? 'bold' : '600'
116
- };
114
+ const resolvedTextColor = (0, _react.useMemo)(() => {
117
115
  switch (variant) {
118
116
  case 'primary':
119
- styles.color = theme.colors.card;
120
- break;
117
+ return theme.colors.card;
121
118
  case 'secondary':
122
- styles.color = theme.colors.text;
123
- break;
119
+ return theme.colors.text;
124
120
  case 'inverse':
125
- styles.color = '#000000';
126
- break;
121
+ return '#000000';
127
122
  case 'ghost':
128
123
  case 'text':
129
- styles.color = theme.colors.primary;
130
- break;
124
+ return theme.colors.primary;
125
+ case 'icon':
126
+ default:
127
+ return theme.colors.text;
131
128
  }
132
- return styles;
133
- }, [variant, size, theme]);
129
+ }, [variant, theme]);
130
+ const computedTextStyle = (0, _react.useMemo)(() => {
131
+ const sizeConfig = SIZE_CONFIG[size];
132
+ return {
133
+ fontSize: sizeConfig.fontSize,
134
+ fontWeight: _reactNative.Platform.OS === 'web' ? 'bold' : '600',
135
+ color: resolvedTextColor
136
+ };
137
+ }, [size, resolvedTextColor]);
134
138
  const defaultHitSlop = variant === 'icon' ? ICON_HIT_SLOP : undefined;
135
139
  const resolvedActiveOpacity = activeOpacity ?? (variant === 'icon' ? 0.7 : 0.8);
136
140
  const resolvedClassName = className ?? (variant === 'icon' ? 'bg-background border border-border' : undefined);
141
+ const content = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
142
+ children: [iconPosition === 'left' && icon, children != null && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
143
+ style: [computedTextStyle, textStyle],
144
+ children: children
145
+ }), iconPosition === 'right' && icon]
146
+ });
137
147
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, {
138
148
  style: hasScaleFeedback ? {
139
149
  transform: [{
140
150
  scale: scaleAnim
141
151
  }]
142
152
  } : undefined,
143
- children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
153
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
144
154
  ...(resolvedClassName ? {
145
155
  className: resolvedClassName
146
156
  } : {}),
147
157
  style: ({
148
158
  pressed
149
- }) => [baseStyles, disabled && {
159
+ }) => [baseStyles, disabled && !loading && {
150
160
  opacity: 0.5
151
- }, pressed && !hasScaleFeedback && {
161
+ }, pressed && !hasScaleFeedback && !isInteractionBlocked && {
152
162
  opacity: resolvedActiveOpacity
153
163
  }, style],
154
- onPress: onPress,
155
- onPressIn: onPressIn,
156
- onPressOut: onPressOut,
157
- disabled: disabled,
164
+ onPress: isInteractionBlocked ? undefined : onPress,
165
+ onPressIn: isInteractionBlocked ? undefined : onPressIn,
166
+ onPressOut: isInteractionBlocked ? undefined : onPressOut,
167
+ disabled: isInteractionBlocked,
158
168
  hitSlop: hitSlop ?? defaultHitSlop,
159
169
  accessibilityLabel: accessibilityLabel,
160
170
  accessibilityHint: accessibilityHint,
161
171
  accessibilityRole: "button",
162
- accessibilityState: {
163
- disabled
172
+ accessibilityState: loading ? {
173
+ disabled: isInteractionBlocked,
174
+ busy: true
175
+ } : {
176
+ disabled: isInteractionBlocked
164
177
  },
165
178
  testID: testID,
166
- children: [iconPosition === 'left' && icon, children != null && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
167
- style: [computedTextStyle, textStyle],
168
- children: children
169
- }), iconPosition === 'right' && icon]
179
+ children: loading ? /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
180
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
181
+ style: styles.loadingHiddenContent,
182
+ importantForAccessibility: "no-hide-descendants",
183
+ accessibilityElementsHidden: true,
184
+ children: content
185
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
186
+ style: styles.loadingOverlay,
187
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
188
+ size: "small",
189
+ color: loadingColor ?? resolvedTextColor
190
+ })
191
+ })]
192
+ }) : content
170
193
  })
171
194
  });
172
195
  };
196
+ const styles = _reactNative.StyleSheet.create({
197
+ loadingHiddenContent: {
198
+ flexDirection: 'row',
199
+ alignItems: 'center',
200
+ justifyContent: 'center',
201
+ opacity: 0,
202
+ pointerEvents: 'none'
203
+ },
204
+ loadingOverlay: {
205
+ ..._reactNative.StyleSheet.absoluteFillObject,
206
+ alignItems: 'center',
207
+ justifyContent: 'center',
208
+ pointerEvents: 'none'
209
+ }
210
+ });
173
211
  const Button = exports.Button = /*#__PURE__*/(0, _react.memo)(ButtonComponent);
174
212
  Button.displayName = 'Button';
175
213
  const PrimaryButton = exports.PrimaryButton = /*#__PURE__*/(0, _react.memo)(props => /*#__PURE__*/(0, _jsxRuntime.jsx)(Button, {
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_useTheme","_usePressAnimation","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","SIZE_CONFIG","small","paddingVertical","paddingHorizontal","fontSize","minHeight","medium","large","ICON_HIT_SLOP","top","bottom","left","right","PRESS_SCALE","SCALE_VARIANTS","Set","ButtonComponent","onPress","children","disabled","variant","size","style","textStyle","icon","iconPosition","accessibilityLabel","accessibilityHint","hitSlop","activeOpacity","testID","className","theme","useTheme","hasScaleFeedback","scaleAnim","onPressIn","onPressOut","usePressAnimation","undefined","baseStyles","useMemo","sizeConfig","styles","alignItems","justifyContent","flexDirection","overflow","backgroundColor","colors","primary","borderRadius","borderWidth","borderColor","border","padding","width","height","computedTextStyle","fontWeight","Platform","OS","color","card","text","defaultHitSlop","resolvedActiveOpacity","resolvedClassName","jsx","Animated","View","transform","scale","jsxs","Pressable","pressed","opacity","accessibilityRole","accessibilityState","Text","Button","exports","memo","displayName","PrimaryButton","props","SecondaryButton","IconButton","GhostButton","InverseButton","TextButton"],"sourceRoot":"../../../src","sources":["button/Button.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_useTheme","_usePressAnimation","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","SIZE_CONFIG","small","paddingVertical","paddingHorizontal","fontSize","minHeight","medium","large","ICON_HIT_SLOP","top","bottom","left","right","PRESS_SCALE","SCALE_VARIANTS","Set","ButtonComponent","onPress","children","disabled","variant","size","style","textStyle","icon","iconPosition","loading","loadingColor","accessibilityLabel","accessibilityHint","hitSlop","activeOpacity","testID","className","theme","useTheme","hasScaleFeedback","isInteractionBlocked","scaleAnim","onPressIn","onPressOut","usePressAnimation","undefined","baseStyles","useMemo","sizeConfig","styles","alignItems","justifyContent","flexDirection","overflow","backgroundColor","colors","primary","borderRadius","borderWidth","borderColor","border","padding","width","height","resolvedTextColor","card","text","computedTextStyle","fontWeight","Platform","OS","color","defaultHitSlop","resolvedActiveOpacity","resolvedClassName","content","jsxs","Fragment","jsx","Text","Animated","View","transform","scale","Pressable","pressed","opacity","accessibilityRole","accessibilityState","busy","loadingHiddenContent","importantForAccessibility","accessibilityElementsHidden","loadingOverlay","ActivityIndicator","StyleSheet","create","pointerEvents","absoluteFillObject","Button","exports","memo","displayName","PrimaryButton","props","SecondaryButton","IconButton","GhostButton","InverseButton","TextButton"],"sourceRoot":"../../../src","sources":["button/Button.tsx"],"mappings":"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","ignoreList":[]}
@@ -7,15 +7,33 @@ exports.setColorSchemeSafe = setColorSchemeSafe;
7
7
  var _reactNative = require("react-native");
8
8
  /**
9
9
  * Safely set the color scheme via Appearance API.
10
- * On Android (RN 0.83+), Appearance.setColorScheme has a Kotlin non-null
11
- * annotation on `style`. Passing null for 'system' crashes.
12
- * Workaround: resolve the system preference and pass 'light'/'dark' instead.
13
10
  *
14
- * On react-native-web, Appearance.setColorScheme is not implemented at all
15
- * (it's `undefined`), which crashes with "setColorScheme is not a function".
16
- * Appearance.getColorScheme() still works on web, so reading the system
17
- * preference is fine it's only the setter that's missing. The browser /
18
- * electron controls the color scheme anyway, so we just bail out on web.
11
+ * Behavior by mode:
12
+ * - 'light' / 'dark': set the explicit override.
13
+ * - 'system' / 'adaptive': leave the OS in control. We must NOT call
14
+ * Appearance.setColorScheme(resolved) heredoing so installs an
15
+ * app-level override that masks the OS preference. Once that override
16
+ * is set, useColorScheme() / Appearance.getColorScheme() return the
17
+ * frozen override instead of the live OS value, and the app stops
18
+ * following dark↔light OS toggles until a cold restart.
19
+ *
20
+ * On iOS we additionally pass 'unspecified' to clear any prior
21
+ * override that may have been installed by a previous explicit mode.
22
+ * 'unspecified' is the documented sentinel that tells the native
23
+ * Appearance module to fall back to the OS preference. (RN's JS
24
+ * implementation forwards this straight through to the native
25
+ * bridge; on iOS this clears the override.)
26
+ *
27
+ * On Android (RN 0.83+) the native Kotlin signature has @NonNull on
28
+ * `style` and rejects null, and 'unspecified' is not honored as a
29
+ * clear-override sentinel on Android either. As a result, if a user
30
+ * previously selected 'light' or 'dark' and then switches back to
31
+ * 'system' on Android, the override remains until the next cold
32
+ * restart. Users who never explicitly overrode are unaffected because
33
+ * we never install an override in system mode in the first place.
34
+ *
35
+ * On react-native-web, Appearance.setColorScheme is not implemented at
36
+ * all; the browser controls the color scheme, so we bail out on web.
19
37
  */
20
38
  function setColorSchemeSafe(mode) {
21
39
  if (_reactNative.Platform.OS === 'web') {
@@ -23,10 +41,14 @@ function setColorSchemeSafe(mode) {
23
41
  }
24
42
  const effectiveMode = mode === 'adaptive' ? 'system' : mode;
25
43
  if (effectiveMode === 'system') {
26
- const resolved = _reactNative.Appearance.getColorScheme() ?? 'light';
27
- _reactNative.Appearance.setColorScheme(resolved);
28
- } else {
29
- _reactNative.Appearance.setColorScheme(effectiveMode);
44
+ // Clear any prior app-level override so useColorScheme() tracks the
45
+ // OS. iOS honors 'unspecified' as a sentinel to fall back to the
46
+ // system preference; Android does not (see note above).
47
+ if (_reactNative.Platform.OS === 'ios') {
48
+ _reactNative.Appearance.setColorScheme('unspecified');
49
+ }
50
+ return;
30
51
  }
52
+ _reactNative.Appearance.setColorScheme(effectiveMode);
31
53
  }
32
54
  //# sourceMappingURL=set-color-scheme-safe.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","setColorSchemeSafe","mode","Platform","OS","effectiveMode","resolved","Appearance","getColorScheme","setColorScheme"],"sourceRoot":"../../../src","sources":["theme/set-color-scheme-safe.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,kBAAkBA,CAACC,IAAe,EAAE;EAClD,IAAIC,qBAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;IACzB;EACF;EAEA,MAAMC,aAAa,GAAGH,IAAI,KAAK,UAAU,GAAG,QAAQ,GAAGA,IAAI;EAC3D,IAAIG,aAAa,KAAK,QAAQ,EAAE;IAC9B,MAAMC,QAAQ,GAAGC,uBAAU,CAACC,cAAc,CAAC,CAAC,IAAI,OAAO;IACvDD,uBAAU,CAACE,cAAc,CAACH,QAAQ,CAAC;EACrC,CAAC,MAAM;IACLC,uBAAU,CAACE,cAAc,CAACJ,aAAa,CAAC;EAC1C;AACF","ignoreList":[]}
1
+ {"version":3,"names":["_reactNative","require","setColorSchemeSafe","mode","Platform","OS","effectiveMode","Appearance","setColorScheme"],"sourceRoot":"../../../src","sources":["theme/set-color-scheme-safe.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,kBAAkBA,CAACC,IAAe,EAAE;EAClD,IAAIC,qBAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;IACzB;EACF;EAEA,MAAMC,aAAa,GAAGH,IAAI,KAAK,UAAU,GAAG,QAAQ,GAAGA,IAAI;EAE3D,IAAIG,aAAa,KAAK,QAAQ,EAAE;IAC9B;IACA;IACA;IACA,IAAIF,qBAAQ,CAACC,EAAE,KAAK,KAAK,EAAE;MACzBE,uBAAU,CAACC,cAAc,CAAC,aAAa,CAAC;IAC1C;IACA;EACF;EAEAD,uBAAU,CAACC,cAAc,CAACF,aAAa,CAAC;AAC1C","ignoreList":[]}
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
 
3
3
  import React, { useMemo, memo } from 'react';
4
- import { Pressable, Text, Platform, Animated } from 'react-native';
4
+ import { ActivityIndicator, Animated, Platform, Pressable, StyleSheet, Text, View } from 'react-native';
5
5
  import { useTheme } from "../theme/use-theme.js";
6
6
  import { usePressAnimation } from "../hooks/usePressAnimation.js";
7
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
8
8
  const SIZE_CONFIG = {
9
9
  small: {
10
10
  paddingVertical: 6,
@@ -43,6 +43,8 @@ const ButtonComponent = ({
43
43
  textStyle,
44
44
  icon,
45
45
  iconPosition = 'left',
46
+ loading = false,
47
+ loadingColor,
46
48
  accessibilityLabel,
47
49
  accessibilityHint,
48
50
  hitSlop,
@@ -52,11 +54,12 @@ const ButtonComponent = ({
52
54
  }) => {
53
55
  const theme = useTheme();
54
56
  const hasScaleFeedback = SCALE_VARIANTS.has(variant);
57
+ const isInteractionBlocked = disabled || loading;
55
58
  const {
56
59
  scaleAnim,
57
60
  onPressIn,
58
61
  onPressOut
59
- } = usePressAnimation(hasScaleFeedback ? PRESS_SCALE : undefined);
62
+ } = usePressAnimation(hasScaleFeedback && !isInteractionBlocked ? PRESS_SCALE : undefined);
60
63
  const baseStyles = useMemo(() => {
61
64
  const sizeConfig = SIZE_CONFIG[size];
62
65
  const styles = {
@@ -103,68 +106,103 @@ const ButtonComponent = ({
103
106
  }
104
107
  return styles;
105
108
  }, [variant, size, theme]);
106
- const computedTextStyle = useMemo(() => {
107
- const sizeConfig = SIZE_CONFIG[size];
108
- const styles = {
109
- fontSize: sizeConfig.fontSize,
110
- fontWeight: Platform.OS === 'web' ? 'bold' : '600'
111
- };
109
+ const resolvedTextColor = useMemo(() => {
112
110
  switch (variant) {
113
111
  case 'primary':
114
- styles.color = theme.colors.card;
115
- break;
112
+ return theme.colors.card;
116
113
  case 'secondary':
117
- styles.color = theme.colors.text;
118
- break;
114
+ return theme.colors.text;
119
115
  case 'inverse':
120
- styles.color = '#000000';
121
- break;
116
+ return '#000000';
122
117
  case 'ghost':
123
118
  case 'text':
124
- styles.color = theme.colors.primary;
125
- break;
119
+ return theme.colors.primary;
120
+ case 'icon':
121
+ default:
122
+ return theme.colors.text;
126
123
  }
127
- return styles;
128
- }, [variant, size, theme]);
124
+ }, [variant, theme]);
125
+ const computedTextStyle = useMemo(() => {
126
+ const sizeConfig = SIZE_CONFIG[size];
127
+ return {
128
+ fontSize: sizeConfig.fontSize,
129
+ fontWeight: Platform.OS === 'web' ? 'bold' : '600',
130
+ color: resolvedTextColor
131
+ };
132
+ }, [size, resolvedTextColor]);
129
133
  const defaultHitSlop = variant === 'icon' ? ICON_HIT_SLOP : undefined;
130
134
  const resolvedActiveOpacity = activeOpacity ?? (variant === 'icon' ? 0.7 : 0.8);
131
135
  const resolvedClassName = className ?? (variant === 'icon' ? 'bg-background border border-border' : undefined);
136
+ const content = /*#__PURE__*/_jsxs(_Fragment, {
137
+ children: [iconPosition === 'left' && icon, children != null && /*#__PURE__*/_jsx(Text, {
138
+ style: [computedTextStyle, textStyle],
139
+ children: children
140
+ }), iconPosition === 'right' && icon]
141
+ });
132
142
  return /*#__PURE__*/_jsx(Animated.View, {
133
143
  style: hasScaleFeedback ? {
134
144
  transform: [{
135
145
  scale: scaleAnim
136
146
  }]
137
147
  } : undefined,
138
- children: /*#__PURE__*/_jsxs(Pressable, {
148
+ children: /*#__PURE__*/_jsx(Pressable, {
139
149
  ...(resolvedClassName ? {
140
150
  className: resolvedClassName
141
151
  } : {}),
142
152
  style: ({
143
153
  pressed
144
- }) => [baseStyles, disabled && {
154
+ }) => [baseStyles, disabled && !loading && {
145
155
  opacity: 0.5
146
- }, pressed && !hasScaleFeedback && {
156
+ }, pressed && !hasScaleFeedback && !isInteractionBlocked && {
147
157
  opacity: resolvedActiveOpacity
148
158
  }, style],
149
- onPress: onPress,
150
- onPressIn: onPressIn,
151
- onPressOut: onPressOut,
152
- disabled: disabled,
159
+ onPress: isInteractionBlocked ? undefined : onPress,
160
+ onPressIn: isInteractionBlocked ? undefined : onPressIn,
161
+ onPressOut: isInteractionBlocked ? undefined : onPressOut,
162
+ disabled: isInteractionBlocked,
153
163
  hitSlop: hitSlop ?? defaultHitSlop,
154
164
  accessibilityLabel: accessibilityLabel,
155
165
  accessibilityHint: accessibilityHint,
156
166
  accessibilityRole: "button",
157
- accessibilityState: {
158
- disabled
167
+ accessibilityState: loading ? {
168
+ disabled: isInteractionBlocked,
169
+ busy: true
170
+ } : {
171
+ disabled: isInteractionBlocked
159
172
  },
160
173
  testID: testID,
161
- children: [iconPosition === 'left' && icon, children != null && /*#__PURE__*/_jsx(Text, {
162
- style: [computedTextStyle, textStyle],
163
- children: children
164
- }), iconPosition === 'right' && icon]
174
+ children: loading ? /*#__PURE__*/_jsxs(_Fragment, {
175
+ children: [/*#__PURE__*/_jsx(View, {
176
+ style: styles.loadingHiddenContent,
177
+ importantForAccessibility: "no-hide-descendants",
178
+ accessibilityElementsHidden: true,
179
+ children: content
180
+ }), /*#__PURE__*/_jsx(View, {
181
+ style: styles.loadingOverlay,
182
+ children: /*#__PURE__*/_jsx(ActivityIndicator, {
183
+ size: "small",
184
+ color: loadingColor ?? resolvedTextColor
185
+ })
186
+ })]
187
+ }) : content
165
188
  })
166
189
  });
167
190
  };
191
+ const styles = StyleSheet.create({
192
+ loadingHiddenContent: {
193
+ flexDirection: 'row',
194
+ alignItems: 'center',
195
+ justifyContent: 'center',
196
+ opacity: 0,
197
+ pointerEvents: 'none'
198
+ },
199
+ loadingOverlay: {
200
+ ...StyleSheet.absoluteFillObject,
201
+ alignItems: 'center',
202
+ justifyContent: 'center',
203
+ pointerEvents: 'none'
204
+ }
205
+ });
168
206
  export const Button = /*#__PURE__*/memo(ButtonComponent);
169
207
  Button.displayName = 'Button';
170
208
  export const PrimaryButton = /*#__PURE__*/memo(props => /*#__PURE__*/_jsx(Button, {
@@ -1 +1 @@
1
- {"version":3,"names":["React","useMemo","memo","Pressable","Text","Platform","Animated","useTheme","usePressAnimation","jsx","_jsx","jsxs","_jsxs","SIZE_CONFIG","small","paddingVertical","paddingHorizontal","fontSize","minHeight","medium","large","ICON_HIT_SLOP","top","bottom","left","right","PRESS_SCALE","SCALE_VARIANTS","Set","ButtonComponent","onPress","children","disabled","variant","size","style","textStyle","icon","iconPosition","accessibilityLabel","accessibilityHint","hitSlop","activeOpacity","testID","className","theme","hasScaleFeedback","has","scaleAnim","onPressIn","onPressOut","undefined","baseStyles","sizeConfig","styles","alignItems","justifyContent","flexDirection","overflow","backgroundColor","colors","primary","borderRadius","borderWidth","borderColor","border","padding","width","height","computedTextStyle","fontWeight","OS","color","card","text","defaultHitSlop","resolvedActiveOpacity","resolvedClassName","View","transform","scale","pressed","opacity","accessibilityRole","accessibilityState","Button","displayName","PrimaryButton","props","SecondaryButton","IconButton","GhostButton","InverseButton","TextButton"],"sourceRoot":"../../../src","sources":["button/Button.tsx"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["React","useMemo","memo","ActivityIndicator","Animated","Platform","Pressable","StyleSheet","Text","View","useTheme","usePressAnimation","jsx","_jsx","Fragment","_Fragment","jsxs","_jsxs","SIZE_CONFIG","small","paddingVertical","paddingHorizontal","fontSize","minHeight","medium","large","ICON_HIT_SLOP","top","bottom","left","right","PRESS_SCALE","SCALE_VARIANTS","Set","ButtonComponent","onPress","children","disabled","variant","size","style","textStyle","icon","iconPosition","loading","loadingColor","accessibilityLabel","accessibilityHint","hitSlop","activeOpacity","testID","className","theme","hasScaleFeedback","has","isInteractionBlocked","scaleAnim","onPressIn","onPressOut","undefined","baseStyles","sizeConfig","styles","alignItems","justifyContent","flexDirection","overflow","backgroundColor","colors","primary","borderRadius","borderWidth","borderColor","border","padding","width","height","resolvedTextColor","card","text","computedTextStyle","fontWeight","OS","color","defaultHitSlop","resolvedActiveOpacity","resolvedClassName","content","transform","scale","pressed","opacity","accessibilityRole","accessibilityState","busy","loadingHiddenContent","importantForAccessibility","accessibilityElementsHidden","loadingOverlay","create","pointerEvents","absoluteFillObject","Button","displayName","PrimaryButton","props","SecondaryButton","IconButton","GhostButton","InverseButton","TextButton"],"sourceRoot":"../../../src","sources":["button/Button.tsx"],"mappings":"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","ignoreList":[]}
@@ -3,15 +3,33 @@
3
3
  import { Appearance, Platform } from 'react-native';
4
4
  /**
5
5
  * Safely set the color scheme via Appearance API.
6
- * On Android (RN 0.83+), Appearance.setColorScheme has a Kotlin non-null
7
- * annotation on `style`. Passing null for 'system' crashes.
8
- * Workaround: resolve the system preference and pass 'light'/'dark' instead.
9
6
  *
10
- * On react-native-web, Appearance.setColorScheme is not implemented at all
11
- * (it's `undefined`), which crashes with "setColorScheme is not a function".
12
- * Appearance.getColorScheme() still works on web, so reading the system
13
- * preference is fine it's only the setter that's missing. The browser /
14
- * electron controls the color scheme anyway, so we just bail out on web.
7
+ * Behavior by mode:
8
+ * - 'light' / 'dark': set the explicit override.
9
+ * - 'system' / 'adaptive': leave the OS in control. We must NOT call
10
+ * Appearance.setColorScheme(resolved) heredoing so installs an
11
+ * app-level override that masks the OS preference. Once that override
12
+ * is set, useColorScheme() / Appearance.getColorScheme() return the
13
+ * frozen override instead of the live OS value, and the app stops
14
+ * following dark↔light OS toggles until a cold restart.
15
+ *
16
+ * On iOS we additionally pass 'unspecified' to clear any prior
17
+ * override that may have been installed by a previous explicit mode.
18
+ * 'unspecified' is the documented sentinel that tells the native
19
+ * Appearance module to fall back to the OS preference. (RN's JS
20
+ * implementation forwards this straight through to the native
21
+ * bridge; on iOS this clears the override.)
22
+ *
23
+ * On Android (RN 0.83+) the native Kotlin signature has @NonNull on
24
+ * `style` and rejects null, and 'unspecified' is not honored as a
25
+ * clear-override sentinel on Android either. As a result, if a user
26
+ * previously selected 'light' or 'dark' and then switches back to
27
+ * 'system' on Android, the override remains until the next cold
28
+ * restart. Users who never explicitly overrode are unaffected because
29
+ * we never install an override in system mode in the first place.
30
+ *
31
+ * On react-native-web, Appearance.setColorScheme is not implemented at
32
+ * all; the browser controls the color scheme, so we bail out on web.
15
33
  */
16
34
  export function setColorSchemeSafe(mode) {
17
35
  if (Platform.OS === 'web') {
@@ -19,10 +37,14 @@ export function setColorSchemeSafe(mode) {
19
37
  }
20
38
  const effectiveMode = mode === 'adaptive' ? 'system' : mode;
21
39
  if (effectiveMode === 'system') {
22
- const resolved = Appearance.getColorScheme() ?? 'light';
23
- Appearance.setColorScheme(resolved);
24
- } else {
25
- Appearance.setColorScheme(effectiveMode);
40
+ // Clear any prior app-level override so useColorScheme() tracks the
41
+ // OS. iOS honors 'unspecified' as a sentinel to fall back to the
42
+ // system preference; Android does not (see note above).
43
+ if (Platform.OS === 'ios') {
44
+ Appearance.setColorScheme('unspecified');
45
+ }
46
+ return;
26
47
  }
48
+ Appearance.setColorScheme(effectiveMode);
27
49
  }
28
50
  //# sourceMappingURL=set-color-scheme-safe.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["Appearance","Platform","setColorSchemeSafe","mode","OS","effectiveMode","resolved","getColorScheme","setColorScheme"],"sourceRoot":"../../../src","sources":["theme/set-color-scheme-safe.ts"],"mappings":";;AAAA,SAASA,UAAU,EAAEC,QAAQ,QAAQ,cAAc;AAGnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,kBAAkBA,CAACC,IAAe,EAAE;EAClD,IAAIF,QAAQ,CAACG,EAAE,KAAK,KAAK,EAAE;IACzB;EACF;EAEA,MAAMC,aAAa,GAAGF,IAAI,KAAK,UAAU,GAAG,QAAQ,GAAGA,IAAI;EAC3D,IAAIE,aAAa,KAAK,QAAQ,EAAE;IAC9B,MAAMC,QAAQ,GAAGN,UAAU,CAACO,cAAc,CAAC,CAAC,IAAI,OAAO;IACvDP,UAAU,CAACQ,cAAc,CAACF,QAAQ,CAAC;EACrC,CAAC,MAAM;IACLN,UAAU,CAACQ,cAAc,CAACH,aAAa,CAAC;EAC1C;AACF","ignoreList":[]}
1
+ {"version":3,"names":["Appearance","Platform","setColorSchemeSafe","mode","OS","effectiveMode","setColorScheme"],"sourceRoot":"../../../src","sources":["theme/set-color-scheme-safe.ts"],"mappings":";;AAAA,SAASA,UAAU,EAAEC,QAAQ,QAAQ,cAAc;AAGnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,kBAAkBA,CAACC,IAAe,EAAE;EAClD,IAAIF,QAAQ,CAACG,EAAE,KAAK,KAAK,EAAE;IACzB;EACF;EAEA,MAAMC,aAAa,GAAGF,IAAI,KAAK,UAAU,GAAG,QAAQ,GAAGA,IAAI;EAE3D,IAAIE,aAAa,KAAK,QAAQ,EAAE;IAC9B;IACA;IACA;IACA,IAAIJ,QAAQ,CAACG,EAAE,KAAK,KAAK,EAAE;MACzBJ,UAAU,CAACM,cAAc,CAAC,aAAa,CAAC;IAC1C;IACA;EACF;EAEAN,UAAU,CAACM,cAAc,CAACD,aAAa,CAAC;AAC1C","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../../src/button/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwB,MAAM,OAAO,CAAC;AAK7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAkKtE,eAAO,MAAM,MAAM,yCAAwB,CAAC;AAG5C,eAAO,MAAM,aAAa,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEpE,CAAC;AAGH,eAAO,MAAM,eAAe,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEtE,CAAC;AAGH,eAAO,MAAM,UAAU,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEjE,CAAC;AAGH,eAAO,MAAM,WAAW,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAElE,CAAC;AAGH,eAAO,MAAM,aAAa,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEpE,CAAC;AAGH,eAAO,MAAM,UAAU,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEjE,CAAC"}
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../../src/button/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwB,MAAM,OAAO,CAAC;AAe7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AA0MtE,eAAO,MAAM,MAAM,yCAAwB,CAAC;AAG5C,eAAO,MAAM,aAAa,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEpE,CAAC;AAGH,eAAO,MAAM,eAAe,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEtE,CAAC;AAGH,eAAO,MAAM,UAAU,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEjE,CAAC;AAGH,eAAO,MAAM,WAAW,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAElE,CAAC;AAGH,eAAO,MAAM,aAAa,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEpE,CAAC;AAGH,eAAO,MAAM,UAAU,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEjE,CAAC"}
@@ -11,6 +11,17 @@ export interface ButtonProps {
11
11
  textStyle?: StyleProp<TextStyle>;
12
12
  icon?: React.ReactNode;
13
13
  iconPosition?: 'left' | 'right';
14
+ /**
15
+ * When true, displays a centered loading spinner overlay and prevents
16
+ * presses. Children remain in the layout (but visually hidden) so the
17
+ * button preserves its width. Use this for async actions like submit.
18
+ */
19
+ loading?: boolean;
20
+ /**
21
+ * Optional color override for the loading spinner. Defaults to the
22
+ * resolved button text color.
23
+ */
24
+ loadingColor?: string;
14
25
  accessibilityLabel?: string;
15
26
  accessibilityHint?: string;
16
27
  hitSlop?: {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/button/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpE,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5F,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAEjC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAEhC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/button/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpE,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5F,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAEjC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAEhC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -1,15 +1,33 @@
1
1
  import type { ThemeMode } from './types';
2
2
  /**
3
3
  * Safely set the color scheme via Appearance API.
4
- * On Android (RN 0.83+), Appearance.setColorScheme has a Kotlin non-null
5
- * annotation on `style`. Passing null for 'system' crashes.
6
- * Workaround: resolve the system preference and pass 'light'/'dark' instead.
7
- *
8
- * On react-native-web, Appearance.setColorScheme is not implemented at all
9
- * (it's `undefined`), which crashes with "setColorScheme is not a function".
10
- * Appearance.getColorScheme() still works on web, so reading the system
11
- * preference is fine it's only the setter that's missing. The browser /
12
- * electron controls the color scheme anyway, so we just bail out on web.
4
+ *
5
+ * Behavior by mode:
6
+ * - 'light' / 'dark': set the explicit override.
7
+ * - 'system' / 'adaptive': leave the OS in control. We must NOT call
8
+ * Appearance.setColorScheme(resolved) here doing so installs an
9
+ * app-level override that masks the OS preference. Once that override
10
+ * is set, useColorScheme() / Appearance.getColorScheme() return the
11
+ * frozen override instead of the live OS value, and the app stops
12
+ * following dark↔light OS toggles until a cold restart.
13
+ *
14
+ * On iOS we additionally pass 'unspecified' to clear any prior
15
+ * override that may have been installed by a previous explicit mode.
16
+ * 'unspecified' is the documented sentinel that tells the native
17
+ * Appearance module to fall back to the OS preference. (RN's JS
18
+ * implementation forwards this straight through to the native
19
+ * bridge; on iOS this clears the override.)
20
+ *
21
+ * On Android (RN 0.83+) the native Kotlin signature has @NonNull on
22
+ * `style` and rejects null, and 'unspecified' is not honored as a
23
+ * clear-override sentinel on Android either. As a result, if a user
24
+ * previously selected 'light' or 'dark' and then switches back to
25
+ * 'system' on Android, the override remains until the next cold
26
+ * restart. Users who never explicitly overrode are unaffected because
27
+ * we never install an override in system mode in the first place.
28
+ *
29
+ * On react-native-web, Appearance.setColorScheme is not implemented at
30
+ * all; the browser controls the color scheme, so we bail out on web.
13
31
  */
14
32
  export declare function setColorSchemeSafe(mode: ThemeMode): void;
15
33
  //# sourceMappingURL=set-color-scheme-safe.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"set-color-scheme-safe.d.ts","sourceRoot":"","sources":["../../../../src/theme/set-color-scheme-safe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,QAYjD"}
1
+ {"version":3,"file":"set-color-scheme-safe.d.ts","sourceRoot":"","sources":["../../../../src/theme/set-color-scheme-safe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,QAkBjD"}
@@ -1 +1 @@
1
- {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../../src/button/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwB,MAAM,OAAO,CAAC;AAK7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAkKtE,eAAO,MAAM,MAAM,yCAAwB,CAAC;AAG5C,eAAO,MAAM,aAAa,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEpE,CAAC;AAGH,eAAO,MAAM,eAAe,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEtE,CAAC;AAGH,eAAO,MAAM,UAAU,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEjE,CAAC;AAGH,eAAO,MAAM,WAAW,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAElE,CAAC;AAGH,eAAO,MAAM,aAAa,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEpE,CAAC;AAGH,eAAO,MAAM,UAAU,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEjE,CAAC"}
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../../src/button/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwB,MAAM,OAAO,CAAC;AAe7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AA0MtE,eAAO,MAAM,MAAM,yCAAwB,CAAC;AAG5C,eAAO,MAAM,aAAa,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEpE,CAAC;AAGH,eAAO,MAAM,eAAe,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEtE,CAAC;AAGH,eAAO,MAAM,UAAU,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEjE,CAAC;AAGH,eAAO,MAAM,WAAW,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAElE,CAAC;AAGH,eAAO,MAAM,aAAa,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEpE,CAAC;AAGH,eAAO,MAAM,UAAU,oCAAgB,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,6CAEjE,CAAC"}
@@ -11,6 +11,17 @@ export interface ButtonProps {
11
11
  textStyle?: StyleProp<TextStyle>;
12
12
  icon?: React.ReactNode;
13
13
  iconPosition?: 'left' | 'right';
14
+ /**
15
+ * When true, displays a centered loading spinner overlay and prevents
16
+ * presses. Children remain in the layout (but visually hidden) so the
17
+ * button preserves its width. Use this for async actions like submit.
18
+ */
19
+ loading?: boolean;
20
+ /**
21
+ * Optional color override for the loading spinner. Defaults to the
22
+ * resolved button text color.
23
+ */
24
+ loadingColor?: string;
14
25
  accessibilityLabel?: string;
15
26
  accessibilityHint?: string;
16
27
  hitSlop?: {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/button/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpE,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5F,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAEjC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAEhC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/button/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpE,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5F,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEtD,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAEjC,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAEhC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,OAAO,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -1,15 +1,33 @@
1
1
  import type { ThemeMode } from './types';
2
2
  /**
3
3
  * Safely set the color scheme via Appearance API.
4
- * On Android (RN 0.83+), Appearance.setColorScheme has a Kotlin non-null
5
- * annotation on `style`. Passing null for 'system' crashes.
6
- * Workaround: resolve the system preference and pass 'light'/'dark' instead.
7
- *
8
- * On react-native-web, Appearance.setColorScheme is not implemented at all
9
- * (it's `undefined`), which crashes with "setColorScheme is not a function".
10
- * Appearance.getColorScheme() still works on web, so reading the system
11
- * preference is fine it's only the setter that's missing. The browser /
12
- * electron controls the color scheme anyway, so we just bail out on web.
4
+ *
5
+ * Behavior by mode:
6
+ * - 'light' / 'dark': set the explicit override.
7
+ * - 'system' / 'adaptive': leave the OS in control. We must NOT call
8
+ * Appearance.setColorScheme(resolved) here doing so installs an
9
+ * app-level override that masks the OS preference. Once that override
10
+ * is set, useColorScheme() / Appearance.getColorScheme() return the
11
+ * frozen override instead of the live OS value, and the app stops
12
+ * following dark↔light OS toggles until a cold restart.
13
+ *
14
+ * On iOS we additionally pass 'unspecified' to clear any prior
15
+ * override that may have been installed by a previous explicit mode.
16
+ * 'unspecified' is the documented sentinel that tells the native
17
+ * Appearance module to fall back to the OS preference. (RN's JS
18
+ * implementation forwards this straight through to the native
19
+ * bridge; on iOS this clears the override.)
20
+ *
21
+ * On Android (RN 0.83+) the native Kotlin signature has @NonNull on
22
+ * `style` and rejects null, and 'unspecified' is not honored as a
23
+ * clear-override sentinel on Android either. As a result, if a user
24
+ * previously selected 'light' or 'dark' and then switches back to
25
+ * 'system' on Android, the override remains until the next cold
26
+ * restart. Users who never explicitly overrode are unaffected because
27
+ * we never install an override in system mode in the first place.
28
+ *
29
+ * On react-native-web, Appearance.setColorScheme is not implemented at
30
+ * all; the browser controls the color scheme, so we bail out on web.
13
31
  */
14
32
  export declare function setColorSchemeSafe(mode: ThemeMode): void;
15
33
  //# sourceMappingURL=set-color-scheme-safe.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"set-color-scheme-safe.d.ts","sourceRoot":"","sources":["../../../../src/theme/set-color-scheme-safe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,QAYjD"}
1
+ {"version":3,"file":"set-color-scheme-safe.d.ts","sourceRoot":"","sources":["../../../../src/theme/set-color-scheme-safe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,QAkBjD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxyhq/bloom",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Bloom UI — Oxy ecosystem component library for React Native + Expo + Web",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { Text } from 'react-native';
2
3
  import { render, fireEvent } from '@testing-library/react-native';
3
4
 
4
5
  import { BloomThemeProvider } from '../theme/BloomThemeProvider';
@@ -58,6 +59,40 @@ describe('Button', () => {
58
59
  const btn = getByTestId('dis-btn');
59
60
  expect(btn.props.accessibilityState).toEqual({ disabled: true });
60
61
  });
62
+
63
+ it('keeps children mounted when loading so width is preserved', () => {
64
+ const { UNSAFE_queryAllByType } = renderWithTheme(
65
+ <Button loading>Submit</Button>,
66
+ );
67
+ // The text node remains in the tree even though it is visually hidden.
68
+ const texts = UNSAFE_queryAllByType(Text);
69
+ const hasSubmit = texts.some((node) =>
70
+ Array.isArray(node.props.children)
71
+ ? node.props.children.includes('Submit')
72
+ : node.props.children === 'Submit',
73
+ );
74
+ expect(hasSubmit).toBe(true);
75
+ });
76
+
77
+ it('disables the underlying Pressable when loading', () => {
78
+ const { getByTestId } = renderWithTheme(
79
+ <Button testID="loading-btn" loading>
80
+ Submit
81
+ </Button>,
82
+ );
83
+ const btn = getByTestId('loading-btn');
84
+ expect(btn.props.disabled).toBe(true);
85
+ });
86
+
87
+ it('marks loading state via accessibilityState busy + disabled', () => {
88
+ const { getByTestId } = renderWithTheme(
89
+ <Button testID="busy-btn" loading>
90
+ Submit
91
+ </Button>,
92
+ );
93
+ const btn = getByTestId('busy-btn');
94
+ expect(btn.props.accessibilityState).toEqual({ disabled: true, busy: true });
95
+ });
61
96
  });
62
97
 
63
98
  describe('Button variants', () => {
@@ -1,5 +1,15 @@
1
1
  import React, { useMemo, memo } from 'react';
2
- import { Pressable, Text, Platform, Animated, type ViewStyle, type TextStyle } from 'react-native';
2
+ import {
3
+ ActivityIndicator,
4
+ Animated,
5
+ Platform,
6
+ Pressable,
7
+ StyleSheet,
8
+ Text,
9
+ View,
10
+ type TextStyle,
11
+ type ViewStyle,
12
+ } from 'react-native';
3
13
 
4
14
  import { useTheme } from '../theme/use-theme';
5
15
  import { usePressAnimation } from '../hooks/usePressAnimation';
@@ -43,6 +53,8 @@ const ButtonComponent: React.FC<ButtonProps> = ({
43
53
  textStyle,
44
54
  icon,
45
55
  iconPosition = 'left',
56
+ loading = false,
57
+ loadingColor,
46
58
  accessibilityLabel,
47
59
  accessibilityHint,
48
60
  hitSlop,
@@ -52,8 +64,9 @@ const ButtonComponent: React.FC<ButtonProps> = ({
52
64
  }) => {
53
65
  const theme = useTheme();
54
66
  const hasScaleFeedback = SCALE_VARIANTS.has(variant);
67
+ const isInteractionBlocked = disabled || loading;
55
68
  const { scaleAnim, onPressIn, onPressOut } = usePressAnimation(
56
- hasScaleFeedback ? PRESS_SCALE : undefined,
69
+ hasScaleFeedback && !isInteractionBlocked ? PRESS_SCALE : undefined,
57
70
  );
58
71
 
59
72
  const baseStyles = useMemo((): ViewStyle => {
@@ -106,67 +119,104 @@ const ButtonComponent: React.FC<ButtonProps> = ({
106
119
  return styles;
107
120
  }, [variant, size, theme]);
108
121
 
109
- const computedTextStyle = useMemo((): TextStyle => {
110
- const sizeConfig = SIZE_CONFIG[size];
111
- const styles: TextStyle = {
112
- fontSize: sizeConfig.fontSize,
113
- fontWeight: Platform.OS === 'web' ? 'bold' : '600',
114
- };
115
-
122
+ const resolvedTextColor = useMemo((): string => {
116
123
  switch (variant) {
117
124
  case 'primary':
118
- styles.color = theme.colors.card;
119
- break;
125
+ return theme.colors.card;
120
126
  case 'secondary':
121
- styles.color = theme.colors.text;
122
- break;
127
+ return theme.colors.text;
123
128
  case 'inverse':
124
- styles.color = '#000000';
125
- break;
129
+ return '#000000';
126
130
  case 'ghost':
127
131
  case 'text':
128
- styles.color = theme.colors.primary;
129
- break;
132
+ return theme.colors.primary;
133
+ case 'icon':
134
+ default:
135
+ return theme.colors.text;
130
136
  }
137
+ }, [variant, theme]);
131
138
 
132
- return styles;
133
- }, [variant, size, theme]);
139
+ const computedTextStyle = useMemo((): TextStyle => {
140
+ const sizeConfig = SIZE_CONFIG[size];
141
+ return {
142
+ fontSize: sizeConfig.fontSize,
143
+ fontWeight: Platform.OS === 'web' ? 'bold' : '600',
144
+ color: resolvedTextColor,
145
+ };
146
+ }, [size, resolvedTextColor]);
134
147
 
135
148
  const defaultHitSlop = variant === 'icon' ? ICON_HIT_SLOP : undefined;
136
149
  const resolvedActiveOpacity = activeOpacity ?? (variant === 'icon' ? 0.7 : 0.8);
137
150
  const resolvedClassName = className ?? (variant === 'icon' ? 'bg-background border border-border' : undefined);
138
151
 
152
+ const content = (
153
+ <>
154
+ {iconPosition === 'left' && icon}
155
+ {children != null && (
156
+ <Text style={[computedTextStyle, textStyle]}>{children}</Text>
157
+ )}
158
+ {iconPosition === 'right' && icon}
159
+ </>
160
+ );
161
+
139
162
  return (
140
163
  <Animated.View style={hasScaleFeedback ? { transform: [{ scale: scaleAnim }] } : undefined}>
141
164
  <Pressable
142
165
  {...(resolvedClassName ? { className: resolvedClassName } as Record<string, string> : {})}
143
166
  style={({ pressed }) => [
144
167
  baseStyles,
145
- disabled && { opacity: 0.5 },
146
- pressed && !hasScaleFeedback && { opacity: resolvedActiveOpacity },
168
+ disabled && !loading && { opacity: 0.5 },
169
+ pressed && !hasScaleFeedback && !isInteractionBlocked && { opacity: resolvedActiveOpacity },
147
170
  style,
148
171
  ]}
149
- onPress={onPress}
150
- onPressIn={onPressIn}
151
- onPressOut={onPressOut}
152
- disabled={disabled}
172
+ onPress={isInteractionBlocked ? undefined : onPress}
173
+ onPressIn={isInteractionBlocked ? undefined : onPressIn}
174
+ onPressOut={isInteractionBlocked ? undefined : onPressOut}
175
+ disabled={isInteractionBlocked}
153
176
  hitSlop={hitSlop ?? defaultHitSlop}
154
177
  accessibilityLabel={accessibilityLabel}
155
178
  accessibilityHint={accessibilityHint}
156
179
  accessibilityRole="button"
157
- accessibilityState={{ disabled }}
180
+ accessibilityState={loading ? { disabled: isInteractionBlocked, busy: true } : { disabled: isInteractionBlocked }}
158
181
  testID={testID}
159
182
  >
160
- {iconPosition === 'left' && icon}
161
- {children != null && (
162
- <Text style={[computedTextStyle, textStyle]}>{children}</Text>
183
+ {loading ? (
184
+ <>
185
+ <View
186
+ style={styles.loadingHiddenContent}
187
+ importantForAccessibility="no-hide-descendants"
188
+ accessibilityElementsHidden
189
+ >
190
+ {content}
191
+ </View>
192
+ <View style={styles.loadingOverlay}>
193
+ <ActivityIndicator size="small" color={loadingColor ?? resolvedTextColor} />
194
+ </View>
195
+ </>
196
+ ) : (
197
+ content
163
198
  )}
164
- {iconPosition === 'right' && icon}
165
199
  </Pressable>
166
200
  </Animated.View>
167
201
  );
168
202
  };
169
203
 
204
+ const styles = StyleSheet.create({
205
+ loadingHiddenContent: {
206
+ flexDirection: 'row',
207
+ alignItems: 'center',
208
+ justifyContent: 'center',
209
+ opacity: 0,
210
+ pointerEvents: 'none',
211
+ },
212
+ loadingOverlay: {
213
+ ...StyleSheet.absoluteFillObject,
214
+ alignItems: 'center',
215
+ justifyContent: 'center',
216
+ pointerEvents: 'none',
217
+ },
218
+ });
219
+
170
220
  export const Button = memo(ButtonComponent);
171
221
  Button.displayName = 'Button';
172
222
 
@@ -17,6 +17,18 @@ export interface ButtonProps {
17
17
  icon?: React.ReactNode;
18
18
  iconPosition?: 'left' | 'right';
19
19
 
20
+ /**
21
+ * When true, displays a centered loading spinner overlay and prevents
22
+ * presses. Children remain in the layout (but visually hidden) so the
23
+ * button preserves its width. Use this for async actions like submit.
24
+ */
25
+ loading?: boolean;
26
+ /**
27
+ * Optional color override for the loading spinner. Defaults to the
28
+ * resolved button text color.
29
+ */
30
+ loadingColor?: string;
31
+
20
32
  accessibilityLabel?: string;
21
33
  accessibilityHint?: string;
22
34
  hitSlop?: { top: number; bottom: number; left: number; right: number };
@@ -3,15 +3,33 @@ import type { ThemeMode } from './types';
3
3
 
4
4
  /**
5
5
  * Safely set the color scheme via Appearance API.
6
- * On Android (RN 0.83+), Appearance.setColorScheme has a Kotlin non-null
7
- * annotation on `style`. Passing null for 'system' crashes.
8
- * Workaround: resolve the system preference and pass 'light'/'dark' instead.
9
6
  *
10
- * On react-native-web, Appearance.setColorScheme is not implemented at all
11
- * (it's `undefined`), which crashes with "setColorScheme is not a function".
12
- * Appearance.getColorScheme() still works on web, so reading the system
13
- * preference is fine it's only the setter that's missing. The browser /
14
- * electron controls the color scheme anyway, so we just bail out on web.
7
+ * Behavior by mode:
8
+ * - 'light' / 'dark': set the explicit override.
9
+ * - 'system' / 'adaptive': leave the OS in control. We must NOT call
10
+ * Appearance.setColorScheme(resolved) heredoing so installs an
11
+ * app-level override that masks the OS preference. Once that override
12
+ * is set, useColorScheme() / Appearance.getColorScheme() return the
13
+ * frozen override instead of the live OS value, and the app stops
14
+ * following dark↔light OS toggles until a cold restart.
15
+ *
16
+ * On iOS we additionally pass 'unspecified' to clear any prior
17
+ * override that may have been installed by a previous explicit mode.
18
+ * 'unspecified' is the documented sentinel that tells the native
19
+ * Appearance module to fall back to the OS preference. (RN's JS
20
+ * implementation forwards this straight through to the native
21
+ * bridge; on iOS this clears the override.)
22
+ *
23
+ * On Android (RN 0.83+) the native Kotlin signature has @NonNull on
24
+ * `style` and rejects null, and 'unspecified' is not honored as a
25
+ * clear-override sentinel on Android either. As a result, if a user
26
+ * previously selected 'light' or 'dark' and then switches back to
27
+ * 'system' on Android, the override remains until the next cold
28
+ * restart. Users who never explicitly overrode are unaffected because
29
+ * we never install an override in system mode in the first place.
30
+ *
31
+ * On react-native-web, Appearance.setColorScheme is not implemented at
32
+ * all; the browser controls the color scheme, so we bail out on web.
15
33
  */
16
34
  export function setColorSchemeSafe(mode: ThemeMode) {
17
35
  if (Platform.OS === 'web') {
@@ -19,10 +37,16 @@ export function setColorSchemeSafe(mode: ThemeMode) {
19
37
  }
20
38
 
21
39
  const effectiveMode = mode === 'adaptive' ? 'system' : mode;
40
+
22
41
  if (effectiveMode === 'system') {
23
- const resolved = Appearance.getColorScheme() ?? 'light';
24
- Appearance.setColorScheme(resolved);
25
- } else {
26
- Appearance.setColorScheme(effectiveMode);
42
+ // Clear any prior app-level override so useColorScheme() tracks the
43
+ // OS. iOS honors 'unspecified' as a sentinel to fall back to the
44
+ // system preference; Android does not (see note above).
45
+ if (Platform.OS === 'ios') {
46
+ Appearance.setColorScheme('unspecified');
47
+ }
48
+ return;
27
49
  }
50
+
51
+ Appearance.setColorScheme(effectiveMode);
28
52
  }