@platform-blocks/ui 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/index.js +215 -1042
- package/lib/cjs/index.js.map +1 -1
- package/lib/components/Carousel/types.d.ts +14 -0
- package/lib/components/HoverCard/types.d.ts +4 -2
- package/lib/components/Popover/types.d.ts +2 -0
- package/lib/components/Switch/styles.d.ts +1 -1
- package/lib/components/TextArea/styles.d.ts +1 -1
- package/lib/components/index.d.ts +0 -2
- package/lib/core/providers/OverlayProvider.d.ts +1 -1
- package/lib/core/theme/PlatformBlocksProvider.d.ts +1 -5
- package/lib/esm/index.js +216 -1024
- package/lib/esm/index.js.map +1 -1
- package/lib/index.d.ts +0 -7
- package/package.json +1 -1
- package/lib/components/Can/Can.d.ts +0 -30
- package/lib/components/Can/PermissionDemo.d.ts +0 -2
- package/lib/components/Can/ability.d.ts +0 -89
- package/lib/components/Can/builder.d.ts +0 -113
- package/lib/components/Can/context.d.ts +0 -25
- package/lib/components/Can/index.d.ts +0 -6
- package/lib/components/Can/types.d.ts +0 -230
- package/lib/components/HoverCard/index.d.ts +0 -2
- package/lib/components/NavigationProgress/NavigationProgress.d.ts +0 -4
- package/lib/components/NavigationProgress/defaults.d.ts +0 -8
- package/lib/components/NavigationProgress/hooks/useNavigationProgressState.d.ts +0 -1
- package/lib/components/NavigationProgress/index.d.ts +0 -2
- package/lib/components/NavigationProgress/styles/resolver.d.ts +0 -1
- package/lib/components/NavigationProgress/tokens.d.ts +0 -4
- package/lib/components/NavigationProgress/types.d.ts +0 -30
package/lib/cjs/index.js
CHANGED
|
@@ -1184,25 +1184,50 @@ function OverlayRenderer({ style } = {}) {
|
|
|
1184
1184
|
}) }));
|
|
1185
1185
|
}
|
|
1186
1186
|
function OverlayContent({ overlay, isTopmost, onBackdropPress }) {
|
|
1187
|
-
var _a, _b, _c;
|
|
1187
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1188
1188
|
useTheme();
|
|
1189
1189
|
const DEBUG = overlay.debug === true;
|
|
1190
1190
|
if (DEBUG) {
|
|
1191
1191
|
console.log('Rendering overlay content:');
|
|
1192
1192
|
console.log('- anchor:', overlay.anchor);
|
|
1193
|
+
console.log('- placement:', overlay.placement);
|
|
1193
1194
|
console.log('- strategy:', overlay.strategy);
|
|
1194
1195
|
console.log('- zIndex:', overlay.zIndex);
|
|
1195
1196
|
}
|
|
1197
|
+
// Check if this is a top-positioned overlay
|
|
1198
|
+
const isTopPlacement = (_a = overlay.placement) === null || _a === void 0 ? void 0 : _a.startsWith('top');
|
|
1199
|
+
// For top placements, we need to anchor from the bottom of the overlay
|
|
1200
|
+
// The anchor.y represents where the bottom of the overlay should be (top of the trigger minus offset)
|
|
1201
|
+
// So we use the estimated height to calculate where the top of the overlay would be
|
|
1196
1202
|
const overlayStyle = {
|
|
1197
1203
|
// Use fixed positioning on web for viewport-anchored overlays
|
|
1198
1204
|
position: (reactNative.Platform.OS === 'web' && overlay.strategy === 'fixed') ? 'fixed' : 'absolute',
|
|
1199
|
-
top: ((_a = overlay.anchor) === null || _a === void 0 ? void 0 : _a.y) || 0,
|
|
1200
1205
|
left: ((_b = overlay.anchor) === null || _b === void 0 ? void 0 : _b.x) || 0,
|
|
1201
1206
|
zIndex: overlay.zIndex,
|
|
1202
1207
|
width: overlay.width || (((_c = overlay.anchor) === null || _c === void 0 ? void 0 : _c.width) ? overlay.anchor.width : undefined),
|
|
1203
1208
|
maxWidth: overlay.maxWidth,
|
|
1204
1209
|
maxHeight: overlay.maxHeight,
|
|
1205
1210
|
};
|
|
1211
|
+
if (isTopPlacement && reactNative.Platform.OS === 'web') {
|
|
1212
|
+
// For top placements, position from the bottom of the overlay
|
|
1213
|
+
// anchor.y is where the top of the overlay should be, but we want to anchor from the bottom
|
|
1214
|
+
// so the overlay can grow upward naturally
|
|
1215
|
+
// The "bottom" of the anchor point is: viewport.height - (anchor.y + estimatedHeight)
|
|
1216
|
+
// But since we don't know actual height, use bottom anchoring relative to the trigger
|
|
1217
|
+
// Actually, anchor.y already accounts for the estimated height, so:
|
|
1218
|
+
// anchor.y = trigger.y - estimatedHeight - offset
|
|
1219
|
+
// We want the overlay's bottom edge to be at: trigger.y - offset
|
|
1220
|
+
// Which means: bottom = viewport.height - (trigger.y - offset) = viewport.height - anchor.y - estimatedHeight
|
|
1221
|
+
// Simpler: just set top and let it render, but the issue is the estimate is wrong
|
|
1222
|
+
// Better approach: use the anchor.y + anchor.height as the "bottom anchor point"
|
|
1223
|
+
// This is where the bottom of the overlay should be
|
|
1224
|
+
const bottomAnchorPoint = (((_d = overlay.anchor) === null || _d === void 0 ? void 0 : _d.y) || 0) + (((_e = overlay.anchor) === null || _e === void 0 ? void 0 : _e.height) || 0);
|
|
1225
|
+
overlayStyle.top = undefined;
|
|
1226
|
+
overlayStyle.bottom = `calc(100vh - ${bottomAnchorPoint}px)`;
|
|
1227
|
+
}
|
|
1228
|
+
else {
|
|
1229
|
+
overlayStyle.top = ((_f = overlay.anchor) === null || _f === void 0 ? void 0 : _f.y) || 0;
|
|
1230
|
+
}
|
|
1206
1231
|
if (DEBUG) {
|
|
1207
1232
|
console.log('- overlayStyle:', overlayStyle);
|
|
1208
1233
|
}
|
|
@@ -6173,31 +6198,29 @@ const Button = (allProps) => {
|
|
|
6173
6198
|
const { getDuration } = useReducedMotion$1();
|
|
6174
6199
|
const { announce } = useAnnouncer();
|
|
6175
6200
|
const { ref: focusRef} = useFocus(`button-${title || 'button'}`);
|
|
6201
|
+
// Track measured width for loading state preservation
|
|
6202
|
+
const [measuredWidth, setMeasuredWidth] = React.useState(null);
|
|
6203
|
+
const wasLoadingRef = React.useRef(loading);
|
|
6204
|
+
// When loading starts, we want to preserve the current measured width
|
|
6205
|
+
// When loading ends, clear the preserved width so it can resize naturally
|
|
6206
|
+
React.useEffect(() => {
|
|
6207
|
+
if (!loading && wasLoadingRef.current) {
|
|
6208
|
+
// Loading just ended, allow width to be recalculated
|
|
6209
|
+
setMeasuredWidth(null);
|
|
6210
|
+
}
|
|
6211
|
+
wasLoadingRef.current = loading;
|
|
6212
|
+
}, [loading]);
|
|
6213
|
+
const handleLayout = React.useCallback((event) => {
|
|
6214
|
+
// Only update measured width when not loading, so we capture the natural content width
|
|
6215
|
+
if (!loading) {
|
|
6216
|
+
const { width } = event.nativeEvent.layout;
|
|
6217
|
+
setMeasuredWidth(width);
|
|
6218
|
+
}
|
|
6219
|
+
// Call user's onLayout if provided
|
|
6220
|
+
onLayout === null || onLayout === void 0 ? void 0 : onLayout(event);
|
|
6221
|
+
}, [loading, onLayout]);
|
|
6176
6222
|
// Determine button content - children takes precedence over title
|
|
6177
6223
|
const buttonContent = children !== null && children !== void 0 ? children : title;
|
|
6178
|
-
// Calculate minimum width for loading state based on content and size
|
|
6179
|
-
const calculateMinWidth = () => {
|
|
6180
|
-
if (!buttonContent || typeof buttonContent !== 'string')
|
|
6181
|
-
return undefined;
|
|
6182
|
-
// Base character width estimates based on size
|
|
6183
|
-
const charWidthBySize = {
|
|
6184
|
-
xs: 6,
|
|
6185
|
-
sm: 7,
|
|
6186
|
-
md: 8,
|
|
6187
|
-
lg: 9,
|
|
6188
|
-
xl: 10,
|
|
6189
|
-
'2xl': 11,
|
|
6190
|
-
'3xl': 12
|
|
6191
|
-
};
|
|
6192
|
-
const sizeKey = typeof size === 'string' ? size : 'md';
|
|
6193
|
-
const charWidth = charWidthBySize[sizeKey] || 8;
|
|
6194
|
-
const horizontalPadding = getSpacing(size) * 2; // Left + right padding
|
|
6195
|
-
// Estimate content width: character count * average char width + padding
|
|
6196
|
-
const contentWidth = buttonContent.length * charWidth + horizontalPadding;
|
|
6197
|
-
// Add space for loader and gap when loading
|
|
6198
|
-
const loaderWidth = getFontSize$1(size) + getSpacing(size) / 2; // Loader + margin
|
|
6199
|
-
return Math.max(contentWidth, contentWidth + loaderWidth);
|
|
6200
|
-
};
|
|
6201
6224
|
// Determine what content to show based on loading state
|
|
6202
6225
|
const displayContent = loading
|
|
6203
6226
|
? (loadingTitle !== undefined ? loadingTitle : '')
|
|
@@ -6236,12 +6259,12 @@ const Button = (allProps) => {
|
|
|
6236
6259
|
const shadowStyles = getShadowStyles({ shadow: effectiveShadow }, theme, 'button');
|
|
6237
6260
|
const spacingStyles = getSpacingStyles(spacingProps);
|
|
6238
6261
|
const baseLayoutStyles = getLayoutStyles(layoutProps);
|
|
6239
|
-
// Apply
|
|
6240
|
-
|
|
6262
|
+
// Apply measured width when loading to prevent size changes
|
|
6263
|
+
// Use the actual measured width instead of character-based estimates
|
|
6241
6264
|
const layoutStyles = {
|
|
6242
6265
|
...baseLayoutStyles,
|
|
6243
|
-
...(loading &&
|
|
6244
|
-
? { minWidth:
|
|
6266
|
+
...(loading && measuredWidth && !layoutProps.width && !layoutProps.w && !layoutProps.fullWidth
|
|
6267
|
+
? { width: measuredWidth, minWidth: measuredWidth }
|
|
6245
6268
|
: {})
|
|
6246
6269
|
};
|
|
6247
6270
|
const iconSpacing = getSpacing(size) / 2;
|
|
@@ -6434,7 +6457,7 @@ const Button = (allProps) => {
|
|
|
6434
6457
|
...(reactNative.Platform.OS !== 'web' ? { transform: [{ translateY: 1 }] } : {})
|
|
6435
6458
|
} : null,
|
|
6436
6459
|
style,
|
|
6437
|
-
], onPress: handleInternalPress, onLayout:
|
|
6460
|
+
], onPress: handleInternalPress, onLayout: handleLayout, onPressIn: handlePressIn, onPressOut: handlePressOut, onHoverIn: onHoverIn, onHoverOut: onHoverOut, onLongPress: onLongPress, disabled: isInteractionDisabled, children: [variant === 'gradient' && hasLinearGradient$4 && (jsxRuntime.jsx(OptionalLinearGradient$6, { colors: resolvedCustomColor
|
|
6438
6461
|
? [resolvedCustomColor, theme.colors.primary[7]]
|
|
6439
6462
|
: [theme.colors.primary[5], theme.colors.primary[7]], style: { position: 'absolute', zIndex: -1, top: 0, left: 0, right: 0, bottom: 0, borderRadius: radiusStyles.borderRadius }, start: { x: 0, y: 0 }, end: { x: 1, y: 0 } })), loading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Loader, { size: size, color: getLoaderColor(), style: !isIconButton ? { marginRight: iconSpacing } : undefined }), !isIconButton && renderButtonContent(displayContent)] })) : isIconButton ? (
|
|
6440
6463
|
// Icon-only button
|
|
@@ -9752,593 +9775,6 @@ function UniversalCSS() {
|
|
|
9752
9775
|
return null;
|
|
9753
9776
|
}
|
|
9754
9777
|
|
|
9755
|
-
/**
|
|
9756
|
-
* Core Ability class for managing permissions
|
|
9757
|
-
*/
|
|
9758
|
-
class AbilityCore {
|
|
9759
|
-
constructor(rules = []) {
|
|
9760
|
-
this.rules = [];
|
|
9761
|
-
this.cache = new Map();
|
|
9762
|
-
this.rules = [...rules];
|
|
9763
|
-
}
|
|
9764
|
-
/**
|
|
9765
|
-
* Check if action is allowed on subject
|
|
9766
|
-
*/
|
|
9767
|
-
can(action, subject, field) {
|
|
9768
|
-
return this.check(action, subject, field).allowed;
|
|
9769
|
-
}
|
|
9770
|
-
/**
|
|
9771
|
-
* Check if action is forbidden on subject
|
|
9772
|
-
*/
|
|
9773
|
-
cannot(action, subject, field) {
|
|
9774
|
-
return !this.can(action, subject, field);
|
|
9775
|
-
}
|
|
9776
|
-
/**
|
|
9777
|
-
* Get detailed permission check result
|
|
9778
|
-
*/
|
|
9779
|
-
check(action, subject, field) {
|
|
9780
|
-
const cacheKey = this.getCacheKey(action, subject, field);
|
|
9781
|
-
if (this.cache.has(cacheKey)) {
|
|
9782
|
-
return this.cache.get(cacheKey);
|
|
9783
|
-
}
|
|
9784
|
-
const result = this.performCheck(action, subject, field);
|
|
9785
|
-
this.cache.set(cacheKey, result);
|
|
9786
|
-
return result;
|
|
9787
|
-
}
|
|
9788
|
-
/**
|
|
9789
|
-
* Update ability rules and clear cache
|
|
9790
|
-
*/
|
|
9791
|
-
update(rules) {
|
|
9792
|
-
this.rules = [...rules];
|
|
9793
|
-
this.cache.clear();
|
|
9794
|
-
}
|
|
9795
|
-
/**
|
|
9796
|
-
* Get all current rules
|
|
9797
|
-
*/
|
|
9798
|
-
getRules() {
|
|
9799
|
-
return [...this.rules];
|
|
9800
|
-
}
|
|
9801
|
-
/**
|
|
9802
|
-
* Clear all rules and cache
|
|
9803
|
-
*/
|
|
9804
|
-
clear() {
|
|
9805
|
-
this.rules = [];
|
|
9806
|
-
this.cache.clear();
|
|
9807
|
-
}
|
|
9808
|
-
/**
|
|
9809
|
-
* Perform the actual permission check
|
|
9810
|
-
*/
|
|
9811
|
-
performCheck(action, subject, field) {
|
|
9812
|
-
// Start with denied by default
|
|
9813
|
-
let result = {
|
|
9814
|
-
allowed: false,
|
|
9815
|
-
reason: 'No matching permission rule found'
|
|
9816
|
-
};
|
|
9817
|
-
// Check rules in order (later rules can override earlier ones)
|
|
9818
|
-
for (const rule of this.rules) {
|
|
9819
|
-
if (this.ruleMatches(rule, action, subject, field)) {
|
|
9820
|
-
result = {
|
|
9821
|
-
allowed: !rule.inverted,
|
|
9822
|
-
reason: rule.reason || (rule.inverted ? 'Access denied by rule' : 'Access granted by rule'),
|
|
9823
|
-
rule
|
|
9824
|
-
};
|
|
9825
|
-
}
|
|
9826
|
-
}
|
|
9827
|
-
return result;
|
|
9828
|
-
}
|
|
9829
|
-
/**
|
|
9830
|
-
* Check if a rule matches the current permission check
|
|
9831
|
-
*/
|
|
9832
|
-
ruleMatches(rule, action, subject, field) {
|
|
9833
|
-
// Check action match
|
|
9834
|
-
const actions = Array.isArray(rule.action) ? rule.action : [rule.action];
|
|
9835
|
-
if (!actions.includes(action) && !actions.includes('*')) {
|
|
9836
|
-
return false;
|
|
9837
|
-
}
|
|
9838
|
-
// Check subject match
|
|
9839
|
-
const subjects = Array.isArray(rule.subject) ? rule.subject : [rule.subject];
|
|
9840
|
-
if (!this.subjectMatches(subjects, subject)) {
|
|
9841
|
-
return false;
|
|
9842
|
-
}
|
|
9843
|
-
// Check field match (if specified)
|
|
9844
|
-
if (field && rule.fields && !rule.fields.includes(field)) {
|
|
9845
|
-
return false;
|
|
9846
|
-
}
|
|
9847
|
-
// Check conditions (if subject is an object)
|
|
9848
|
-
if (rule.conditions && typeof subject === 'object' && subject !== null) {
|
|
9849
|
-
return this.conditionsMatch(rule.conditions, subject);
|
|
9850
|
-
}
|
|
9851
|
-
return true;
|
|
9852
|
-
}
|
|
9853
|
-
/**
|
|
9854
|
-
* Check if subject matches any of the rule subjects
|
|
9855
|
-
*/
|
|
9856
|
-
subjectMatches(ruleSubjects, checkSubject) {
|
|
9857
|
-
for (const ruleSubject of ruleSubjects) {
|
|
9858
|
-
if (ruleSubject === '*')
|
|
9859
|
-
return true;
|
|
9860
|
-
if (ruleSubject === checkSubject)
|
|
9861
|
-
return true;
|
|
9862
|
-
// Handle class/constructor matching
|
|
9863
|
-
if (typeof ruleSubject === 'function' && typeof checkSubject === 'object') {
|
|
9864
|
-
if (checkSubject instanceof ruleSubject)
|
|
9865
|
-
return true;
|
|
9866
|
-
if (checkSubject.constructor === ruleSubject)
|
|
9867
|
-
return true;
|
|
9868
|
-
}
|
|
9869
|
-
// Handle string matching for object types
|
|
9870
|
-
if (typeof ruleSubject === 'string' && typeof checkSubject === 'object') {
|
|
9871
|
-
if (checkSubject.__type === ruleSubject)
|
|
9872
|
-
return true;
|
|
9873
|
-
if (checkSubject.type === ruleSubject)
|
|
9874
|
-
return true;
|
|
9875
|
-
if (checkSubject.constructor.name === ruleSubject)
|
|
9876
|
-
return true;
|
|
9877
|
-
}
|
|
9878
|
-
}
|
|
9879
|
-
return false;
|
|
9880
|
-
}
|
|
9881
|
-
/**
|
|
9882
|
-
* Check if conditions match the subject object
|
|
9883
|
-
*/
|
|
9884
|
-
conditionsMatch(conditions, subject) {
|
|
9885
|
-
for (const [key, expectedValue] of Object.entries(conditions)) {
|
|
9886
|
-
const actualValue = subject[key];
|
|
9887
|
-
if (!this.valuesMatch(actualValue, expectedValue)) {
|
|
9888
|
-
return false;
|
|
9889
|
-
}
|
|
9890
|
-
}
|
|
9891
|
-
return true;
|
|
9892
|
-
}
|
|
9893
|
-
/**
|
|
9894
|
-
* Check if two values match (handles various comparison types)
|
|
9895
|
-
*/
|
|
9896
|
-
valuesMatch(actual, expected) {
|
|
9897
|
-
// Exact match
|
|
9898
|
-
if (actual === expected)
|
|
9899
|
-
return true;
|
|
9900
|
-
// Array contains check
|
|
9901
|
-
if (Array.isArray(expected) && expected.includes(actual))
|
|
9902
|
-
return true;
|
|
9903
|
-
if (Array.isArray(actual) && actual.includes(expected))
|
|
9904
|
-
return true;
|
|
9905
|
-
// Function/predicate check
|
|
9906
|
-
if (typeof expected === 'function') {
|
|
9907
|
-
return expected(actual);
|
|
9908
|
-
}
|
|
9909
|
-
// Regex match for strings
|
|
9910
|
-
if (expected instanceof RegExp && typeof actual === 'string') {
|
|
9911
|
-
return expected.test(actual);
|
|
9912
|
-
}
|
|
9913
|
-
// Object comparison (shallow)
|
|
9914
|
-
if (typeof expected === 'object' && typeof actual === 'object' && expected !== null && actual !== null) {
|
|
9915
|
-
return Object.keys(expected).every(key => this.valuesMatch(actual[key], expected[key]));
|
|
9916
|
-
}
|
|
9917
|
-
return false;
|
|
9918
|
-
}
|
|
9919
|
-
/**
|
|
9920
|
-
* Generate cache key for permission check
|
|
9921
|
-
*/
|
|
9922
|
-
getCacheKey(action, subject, field) {
|
|
9923
|
-
const subjectKey = typeof subject === 'object'
|
|
9924
|
-
? JSON.stringify(subject)
|
|
9925
|
-
: String(subject);
|
|
9926
|
-
return `${action}:${subjectKey}:${field || ''}`;
|
|
9927
|
-
}
|
|
9928
|
-
}
|
|
9929
|
-
/**
|
|
9930
|
-
* Create a new Ability instance
|
|
9931
|
-
*/
|
|
9932
|
-
function createAbility(rules = []) {
|
|
9933
|
-
return new AbilityCore(rules);
|
|
9934
|
-
}
|
|
9935
|
-
|
|
9936
|
-
/**
|
|
9937
|
-
* Permission Context
|
|
9938
|
-
*/
|
|
9939
|
-
const PermissionContext = React.createContext(null);
|
|
9940
|
-
/**
|
|
9941
|
-
* Permission Provider Component
|
|
9942
|
-
*/
|
|
9943
|
-
const PermissionProvider = ({ rules = [], user, children, dev = {} }) => {
|
|
9944
|
-
const [ability] = React.useState(() => createAbility(rules));
|
|
9945
|
-
const [currentUser, setCurrentUser] = React.useState(user);
|
|
9946
|
-
const updateAbility = React.useCallback((newRules) => {
|
|
9947
|
-
ability.update(newRules);
|
|
9948
|
-
}, [ability]);
|
|
9949
|
-
const can = React.useCallback((action, subject, field) => {
|
|
9950
|
-
const result = ability.can(action, subject, field);
|
|
9951
|
-
if (dev.logChecks) {
|
|
9952
|
-
console.log(`[Permissions] Can ${action} ${subject}${field ? `.${field}` : ''}:`, result);
|
|
9953
|
-
}
|
|
9954
|
-
return result;
|
|
9955
|
-
}, [ability, dev.logChecks]);
|
|
9956
|
-
const cannot = React.useCallback((action, subject, field) => {
|
|
9957
|
-
const result = ability.cannot(action, subject, field);
|
|
9958
|
-
if (dev.logChecks) {
|
|
9959
|
-
console.log(`[Permissions] Cannot ${action} ${subject}${field ? `.${field}` : ''}:`, result);
|
|
9960
|
-
}
|
|
9961
|
-
return result;
|
|
9962
|
-
}, [ability, dev.logChecks]);
|
|
9963
|
-
const setUser = React.useCallback((newUser) => {
|
|
9964
|
-
setCurrentUser(newUser);
|
|
9965
|
-
}, []);
|
|
9966
|
-
const contextValue = React.useMemo(() => ({
|
|
9967
|
-
ability,
|
|
9968
|
-
updateAbility,
|
|
9969
|
-
can,
|
|
9970
|
-
cannot,
|
|
9971
|
-
user: currentUser,
|
|
9972
|
-
setUser
|
|
9973
|
-
}), [ability, updateAbility, can, cannot, currentUser, setUser]);
|
|
9974
|
-
return React.createElement(PermissionContext.Provider, { value: contextValue }, children);
|
|
9975
|
-
};
|
|
9976
|
-
/**
|
|
9977
|
-
* Hook to access permission context
|
|
9978
|
-
*/
|
|
9979
|
-
const usePermissions = (options = {}) => {
|
|
9980
|
-
const context = React.useContext(PermissionContext);
|
|
9981
|
-
if (!context) {
|
|
9982
|
-
if (options.required) {
|
|
9983
|
-
throw new Error('usePermissions must be used within a PermissionProvider');
|
|
9984
|
-
}
|
|
9985
|
-
if (options.debug) {
|
|
9986
|
-
console.warn('[Permissions] usePermissions called outside of PermissionProvider');
|
|
9987
|
-
}
|
|
9988
|
-
// Return a fallback context that allows everything
|
|
9989
|
-
return {
|
|
9990
|
-
ability: createAbility([{ action: '*', subject: '*' }]),
|
|
9991
|
-
updateAbility: () => { },
|
|
9992
|
-
can: () => true,
|
|
9993
|
-
cannot: () => false,
|
|
9994
|
-
user: null,
|
|
9995
|
-
setUser: () => { }
|
|
9996
|
-
};
|
|
9997
|
-
}
|
|
9998
|
-
return context;
|
|
9999
|
-
};
|
|
10000
|
-
/**
|
|
10001
|
-
* Hook to get the current ability instance
|
|
10002
|
-
*/
|
|
10003
|
-
const useAbility = () => {
|
|
10004
|
-
const { ability } = usePermissions();
|
|
10005
|
-
return ability;
|
|
10006
|
-
};
|
|
10007
|
-
|
|
10008
|
-
/**
|
|
10009
|
-
* Can Component - Renders children if permission is granted
|
|
10010
|
-
*/
|
|
10011
|
-
const Can = ({ I: action, a: subject, field, children, fallback = null, ability: customAbility, style, testID, passthrough = false }) => {
|
|
10012
|
-
const { ability: contextAbility } = usePermissions();
|
|
10013
|
-
const ability = customAbility || contextAbility;
|
|
10014
|
-
// Development passthrough
|
|
10015
|
-
if (passthrough && __DEV__) {
|
|
10016
|
-
return React.createElement(reactNative.View, { style, testID }, children);
|
|
10017
|
-
}
|
|
10018
|
-
const hasPermission = subject
|
|
10019
|
-
? ability.can(action, subject, field)
|
|
10020
|
-
: ability.can(action, '*', field);
|
|
10021
|
-
if (hasPermission) {
|
|
10022
|
-
return React.createElement(reactNative.View, { style, testID }, children);
|
|
10023
|
-
}
|
|
10024
|
-
return React.createElement(reactNative.View, { style, testID }, fallback);
|
|
10025
|
-
};
|
|
10026
|
-
/**
|
|
10027
|
-
* Can Component with conditions - For object-level permissions
|
|
10028
|
-
*/
|
|
10029
|
-
const CanWithConditions = ({ I: action, this: subject, field, children, fallback = null, ability: customAbility, style, testID, passthrough = false }) => {
|
|
10030
|
-
const { ability: contextAbility } = usePermissions();
|
|
10031
|
-
const ability = customAbility || contextAbility;
|
|
10032
|
-
// Development passthrough
|
|
10033
|
-
if (passthrough && __DEV__) {
|
|
10034
|
-
return React.createElement(reactNative.View, { style, testID }, children);
|
|
10035
|
-
}
|
|
10036
|
-
const hasPermission = ability.can(action, subject, field);
|
|
10037
|
-
if (hasPermission) {
|
|
10038
|
-
return React.createElement(reactNative.View, { style, testID }, children);
|
|
10039
|
-
}
|
|
10040
|
-
return React.createElement(reactNative.View, { style, testID }, fallback);
|
|
10041
|
-
};
|
|
10042
|
-
/**
|
|
10043
|
-
* Cannot Component - Renders children if permission is NOT granted
|
|
10044
|
-
*/
|
|
10045
|
-
const Cannot = ({ I: action, a: subject, field, children, fallback = null, ability: customAbility, style, testID, passthrough = false }) => {
|
|
10046
|
-
const { ability: contextAbility } = usePermissions();
|
|
10047
|
-
const ability = customAbility || contextAbility;
|
|
10048
|
-
// Development passthrough
|
|
10049
|
-
if (passthrough && __DEV__) {
|
|
10050
|
-
return React.createElement(reactNative.View, { style, testID }, fallback);
|
|
10051
|
-
}
|
|
10052
|
-
const hasPermission = subject
|
|
10053
|
-
? ability.can(action, subject, field)
|
|
10054
|
-
: ability.can(action, '*', field);
|
|
10055
|
-
if (!hasPermission) {
|
|
10056
|
-
return React.createElement(reactNative.View, { style, testID }, children);
|
|
10057
|
-
}
|
|
10058
|
-
return React.createElement(reactNative.View, { style, testID }, fallback);
|
|
10059
|
-
};
|
|
10060
|
-
/**
|
|
10061
|
-
* Permission Gate - Requires ALL permissions to pass
|
|
10062
|
-
*/
|
|
10063
|
-
const PermissionGate = ({ permissions, children, fallback = null, ability: customAbility, onUnauthorized }) => {
|
|
10064
|
-
const { ability: contextAbility } = usePermissions();
|
|
10065
|
-
const ability = customAbility || contextAbility;
|
|
10066
|
-
const allPermissionsGranted = permissions.every(({ action, subject, field }) => ability.can(action, subject, field));
|
|
10067
|
-
React.useEffect(() => {
|
|
10068
|
-
if (!allPermissionsGranted && onUnauthorized) {
|
|
10069
|
-
onUnauthorized();
|
|
10070
|
-
}
|
|
10071
|
-
}, [allPermissionsGranted, onUnauthorized]);
|
|
10072
|
-
if (allPermissionsGranted) {
|
|
10073
|
-
return React.createElement(React.Fragment, null, children);
|
|
10074
|
-
}
|
|
10075
|
-
return React.createElement(React.Fragment, null, fallback);
|
|
10076
|
-
};
|
|
10077
|
-
/**
|
|
10078
|
-
* Higher-Order Component for permission checking
|
|
10079
|
-
*/
|
|
10080
|
-
function withCan(action, subject, field) {
|
|
10081
|
-
return function CanHOC(Component) {
|
|
10082
|
-
const WrappedComponent = (props) => {
|
|
10083
|
-
const { fallback, ...componentProps } = props;
|
|
10084
|
-
return React.createElement(Can, { I: action, a: subject, field, fallback }, React.createElement(Component, componentProps));
|
|
10085
|
-
};
|
|
10086
|
-
WrappedComponent.displayName = `withCan(${Component.displayName || Component.name})`;
|
|
10087
|
-
return WrappedComponent;
|
|
10088
|
-
};
|
|
10089
|
-
}
|
|
10090
|
-
/**
|
|
10091
|
-
* Higher-Order Component for permission denial checking
|
|
10092
|
-
*/
|
|
10093
|
-
function withCannot(action, subject, field) {
|
|
10094
|
-
return function CannotHOC(Component) {
|
|
10095
|
-
const WrappedComponent = (props) => {
|
|
10096
|
-
const { fallback, ...componentProps } = props;
|
|
10097
|
-
return React.createElement(Cannot, { I: action, a: subject, field, fallback }, React.createElement(Component, componentProps));
|
|
10098
|
-
};
|
|
10099
|
-
WrappedComponent.displayName = `withCannot(${Component.displayName || Component.name})`;
|
|
10100
|
-
return WrappedComponent;
|
|
10101
|
-
};
|
|
10102
|
-
}
|
|
10103
|
-
|
|
10104
|
-
/**
|
|
10105
|
-
* Fluent API for building permissions
|
|
10106
|
-
*/
|
|
10107
|
-
class PermissionBuilder {
|
|
10108
|
-
constructor() {
|
|
10109
|
-
this.rules = [];
|
|
10110
|
-
}
|
|
10111
|
-
/**
|
|
10112
|
-
* Grant permission
|
|
10113
|
-
*/
|
|
10114
|
-
allow(action, subject, field) {
|
|
10115
|
-
this.rules.push({
|
|
10116
|
-
action,
|
|
10117
|
-
subject: subject || '*',
|
|
10118
|
-
fields: field ? [field] : undefined,
|
|
10119
|
-
inverted: false
|
|
10120
|
-
});
|
|
10121
|
-
return this;
|
|
10122
|
-
}
|
|
10123
|
-
/**
|
|
10124
|
-
* Deny permission
|
|
10125
|
-
*/
|
|
10126
|
-
forbid(action, subject, field) {
|
|
10127
|
-
this.rules.push({
|
|
10128
|
-
action,
|
|
10129
|
-
subject: subject || '*',
|
|
10130
|
-
fields: field ? [field] : undefined,
|
|
10131
|
-
inverted: true
|
|
10132
|
-
});
|
|
10133
|
-
return this;
|
|
10134
|
-
}
|
|
10135
|
-
/**
|
|
10136
|
-
* Conditional permission
|
|
10137
|
-
*/
|
|
10138
|
-
allowIf(action, subject, conditions, field) {
|
|
10139
|
-
this.rules.push({
|
|
10140
|
-
action,
|
|
10141
|
-
subject: subject || '*',
|
|
10142
|
-
fields: field ? [field] : undefined,
|
|
10143
|
-
inverted: false,
|
|
10144
|
-
conditions
|
|
10145
|
-
});
|
|
10146
|
-
return this;
|
|
10147
|
-
}
|
|
10148
|
-
/**
|
|
10149
|
-
* Conditional denial
|
|
10150
|
-
*/
|
|
10151
|
-
forbidIf(action, subject, conditions, field) {
|
|
10152
|
-
this.rules.push({
|
|
10153
|
-
action,
|
|
10154
|
-
subject: subject || '*',
|
|
10155
|
-
fields: field ? [field] : undefined,
|
|
10156
|
-
inverted: true,
|
|
10157
|
-
conditions
|
|
10158
|
-
});
|
|
10159
|
-
return this;
|
|
10160
|
-
}
|
|
10161
|
-
/**
|
|
10162
|
-
* Grant all actions on a subject
|
|
10163
|
-
*/
|
|
10164
|
-
manage(subject) {
|
|
10165
|
-
this.rules.push({
|
|
10166
|
-
action: '*',
|
|
10167
|
-
subject,
|
|
10168
|
-
inverted: false
|
|
10169
|
-
});
|
|
10170
|
-
return this;
|
|
10171
|
-
}
|
|
10172
|
-
/**
|
|
10173
|
-
* Forbid all actions on a subject
|
|
10174
|
-
*/
|
|
10175
|
-
forbidAll(subject) {
|
|
10176
|
-
this.rules.push({
|
|
10177
|
-
action: '*',
|
|
10178
|
-
subject,
|
|
10179
|
-
inverted: true
|
|
10180
|
-
});
|
|
10181
|
-
return this;
|
|
10182
|
-
}
|
|
10183
|
-
/**
|
|
10184
|
-
* Role-based permissions
|
|
10185
|
-
*/
|
|
10186
|
-
role(roleName, callback) {
|
|
10187
|
-
const roleBuilder = new RoleBuilder(roleName);
|
|
10188
|
-
callback(roleBuilder);
|
|
10189
|
-
this.rules.push(...roleBuilder.getRules());
|
|
10190
|
-
return this;
|
|
10191
|
-
}
|
|
10192
|
-
/**
|
|
10193
|
-
* Build the ability with all rules
|
|
10194
|
-
*/
|
|
10195
|
-
build() {
|
|
10196
|
-
return new AbilityCore(this.rules);
|
|
10197
|
-
}
|
|
10198
|
-
/**
|
|
10199
|
-
* Get all rules
|
|
10200
|
-
*/
|
|
10201
|
-
getRules() {
|
|
10202
|
-
return [...this.rules];
|
|
10203
|
-
}
|
|
10204
|
-
/**
|
|
10205
|
-
* Clear all rules
|
|
10206
|
-
*/
|
|
10207
|
-
clear() {
|
|
10208
|
-
this.rules = [];
|
|
10209
|
-
return this;
|
|
10210
|
-
}
|
|
10211
|
-
/**
|
|
10212
|
-
* Merge rules from another builder
|
|
10213
|
-
*/
|
|
10214
|
-
merge(other) {
|
|
10215
|
-
this.rules.push(...other.getRules());
|
|
10216
|
-
return this;
|
|
10217
|
-
}
|
|
10218
|
-
}
|
|
10219
|
-
/**
|
|
10220
|
-
* Role-specific permission builder
|
|
10221
|
-
*/
|
|
10222
|
-
class RoleBuilder {
|
|
10223
|
-
constructor(roleName) {
|
|
10224
|
-
this.roleName = roleName;
|
|
10225
|
-
this.rules = [];
|
|
10226
|
-
}
|
|
10227
|
-
/**
|
|
10228
|
-
* Grant permission for this role
|
|
10229
|
-
*/
|
|
10230
|
-
can(action, subject, field) {
|
|
10231
|
-
this.rules.push({
|
|
10232
|
-
action,
|
|
10233
|
-
subject: subject || '*',
|
|
10234
|
-
fields: field ? [field] : undefined,
|
|
10235
|
-
inverted: false,
|
|
10236
|
-
conditions: { role: this.roleName }
|
|
10237
|
-
});
|
|
10238
|
-
return this;
|
|
10239
|
-
}
|
|
10240
|
-
/**
|
|
10241
|
-
* Deny permission for this role
|
|
10242
|
-
*/
|
|
10243
|
-
cannot(action, subject, field) {
|
|
10244
|
-
this.rules.push({
|
|
10245
|
-
action,
|
|
10246
|
-
subject: subject || '*',
|
|
10247
|
-
fields: field ? [field] : undefined,
|
|
10248
|
-
inverted: true,
|
|
10249
|
-
conditions: { role: this.roleName }
|
|
10250
|
-
});
|
|
10251
|
-
return this;
|
|
10252
|
-
}
|
|
10253
|
-
/**
|
|
10254
|
-
* Manage all actions on subject for this role
|
|
10255
|
-
*/
|
|
10256
|
-
manage(subject) {
|
|
10257
|
-
this.rules.push({
|
|
10258
|
-
action: '*',
|
|
10259
|
-
subject,
|
|
10260
|
-
inverted: false,
|
|
10261
|
-
conditions: { role: this.roleName }
|
|
10262
|
-
});
|
|
10263
|
-
return this;
|
|
10264
|
-
}
|
|
10265
|
-
/**
|
|
10266
|
-
* Get all rules for this role
|
|
10267
|
-
*/
|
|
10268
|
-
getRules() {
|
|
10269
|
-
return [...this.rules];
|
|
10270
|
-
}
|
|
10271
|
-
}
|
|
10272
|
-
/**
|
|
10273
|
-
* Common permission patterns
|
|
10274
|
-
*/
|
|
10275
|
-
class PermissionPatterns {
|
|
10276
|
-
/**
|
|
10277
|
-
* Admin permissions - can do everything
|
|
10278
|
-
*/
|
|
10279
|
-
static admin() {
|
|
10280
|
-
return new PermissionBuilder()
|
|
10281
|
-
.manage('*');
|
|
10282
|
-
}
|
|
10283
|
-
/**
|
|
10284
|
-
* User permissions - basic CRUD on own resources
|
|
10285
|
-
*/
|
|
10286
|
-
static user(userId) {
|
|
10287
|
-
return new PermissionBuilder()
|
|
10288
|
-
.allowIf('read', 'User', { id: userId })
|
|
10289
|
-
.allowIf('update', 'User', { id: userId })
|
|
10290
|
-
.allowIf('delete', 'User', { id: userId })
|
|
10291
|
-
.allow('read', 'public');
|
|
10292
|
-
}
|
|
10293
|
-
/**
|
|
10294
|
-
* Guest permissions - read-only public content
|
|
10295
|
-
*/
|
|
10296
|
-
static guest() {
|
|
10297
|
-
return new PermissionBuilder()
|
|
10298
|
-
.allow('read', 'public');
|
|
10299
|
-
}
|
|
10300
|
-
/**
|
|
10301
|
-
* Moderator permissions - manage content but not users
|
|
10302
|
-
*/
|
|
10303
|
-
static moderator() {
|
|
10304
|
-
return new PermissionBuilder()
|
|
10305
|
-
.manage('Content')
|
|
10306
|
-
.manage('Comment')
|
|
10307
|
-
.allow('read', 'User')
|
|
10308
|
-
.forbid('delete', 'User');
|
|
10309
|
-
}
|
|
10310
|
-
/**
|
|
10311
|
-
* Owner permissions - full control over owned resources
|
|
10312
|
-
*/
|
|
10313
|
-
static owner(ownerId) {
|
|
10314
|
-
return new PermissionBuilder()
|
|
10315
|
-
.allowIf('*', '*', { ownerId })
|
|
10316
|
-
.allow('create', '*');
|
|
10317
|
-
}
|
|
10318
|
-
}
|
|
10319
|
-
/**
|
|
10320
|
-
* Helper function to create a new permission builder
|
|
10321
|
-
*/
|
|
10322
|
-
function permissions() {
|
|
10323
|
-
return new PermissionBuilder();
|
|
10324
|
-
}
|
|
10325
|
-
/**
|
|
10326
|
-
* Helper function to create ability from rules array
|
|
10327
|
-
*/
|
|
10328
|
-
function defineAbility(callback) {
|
|
10329
|
-
const builder = new PermissionBuilder();
|
|
10330
|
-
callback(builder);
|
|
10331
|
-
return builder.build();
|
|
10332
|
-
}
|
|
10333
|
-
/**
|
|
10334
|
-
* Helper function to create common role-based abilities
|
|
10335
|
-
*/
|
|
10336
|
-
function defineRoleAbility(role, callback) {
|
|
10337
|
-
const roleBuilder = new RoleBuilder(role);
|
|
10338
|
-
callback(roleBuilder);
|
|
10339
|
-
return new AbilityCore(roleBuilder.getRules());
|
|
10340
|
-
}
|
|
10341
|
-
|
|
10342
9778
|
const ThemeModeContext = React.createContext(null);
|
|
10343
9779
|
// Default persistence using localStorage (web only)
|
|
10344
9780
|
const defaultPersistence = {
|
|
@@ -10468,7 +9904,6 @@ const OverlayBoundary = React.memo(function OverlayBoundary({ enabled, children
|
|
|
10468
9904
|
const I18nBoundary = React.memo(function I18nBoundary({ locale, fallbackLocale, resources, children }) {
|
|
10469
9905
|
return (jsxRuntime.jsx(I18nProvider, { initial: { locale, fallbackLocale, resources }, children: children }));
|
|
10470
9906
|
});
|
|
10471
|
-
const DEFAULT_PERMISSION_RULES = [{ action: '*', subject: '*' }];
|
|
10472
9907
|
/**
|
|
10473
9908
|
* Internal component that uses the enhanced theme mode when config is provided
|
|
10474
9909
|
*/
|
|
@@ -10506,30 +9941,20 @@ function PlatformBlocksContent({ children, theme, inherit = true, withCSSVariabl
|
|
|
10506
9941
|
document.documentElement.setAttribute('data-platform-blocks-color-scheme', target);
|
|
10507
9942
|
}
|
|
10508
9943
|
}, [effectiveColorScheme, osColorScheme]);
|
|
10509
|
-
const mainContent = (jsxRuntime.
|
|
10510
|
-
return
|
|
9944
|
+
const mainContent = (jsxRuntime.jsx(ThemeBoundary, { theme: resolvedTheme, inherit: inherit, withCSSVariables: withCSSVariables, cssVariablesSelector: cssVariablesSelector, withGlobalCSS: withGlobalCSS, children: jsxRuntime.jsxs(OverlayBoundary, { enabled: withOverlays, children: [children, withSpotlight && jsxRuntime.jsx(SpotlightController, { config: spotlightConfig })] }) }));
|
|
9945
|
+
return mainContent;
|
|
10511
9946
|
}
|
|
10512
9947
|
/**
|
|
10513
9948
|
* Main provider component for Platform Blocks library
|
|
10514
9949
|
* Provides theme context and injects CSS variables
|
|
10515
9950
|
*/
|
|
10516
|
-
function PlatformBlocksProvider({ children, theme, inherit = true, withCSSVariables = true, cssVariablesSelector = ':root', colorSchemeMode = 'auto', withOverlays = true, withSpotlight = false, withGlobalCSS = true, themeModeConfig, spotlightConfig, locale = 'en', fallbackLocale = 'en', i18nResources, direction, haptics
|
|
9951
|
+
function PlatformBlocksProvider({ children, theme, inherit = true, withCSSVariables = true, cssVariablesSelector = ':root', colorSchemeMode = 'auto', withOverlays = true, withSpotlight = false, withGlobalCSS = true, themeModeConfig, spotlightConfig, locale = 'en', fallbackLocale = 'en', i18nResources, direction, haptics }) {
|
|
10517
9952
|
const i18nStore = React.useMemo(() => i18nResources || { en: { translation: {} } }, [i18nResources]);
|
|
10518
9953
|
const content = (jsxRuntime.jsx(PlatformBlocksContent, { theme: theme, inherit: inherit, withCSSVariables: withCSSVariables, cssVariablesSelector: cssVariablesSelector, colorSchemeMode: colorSchemeMode, withOverlays: withOverlays, withSpotlight: withSpotlight, withGlobalCSS: withGlobalCSS, spotlightConfig: spotlightConfig, themeModeConfig: themeModeConfig, children: children }));
|
|
10519
9954
|
const themedTree = themeModeConfig ? (jsxRuntime.jsx(ThemeModeProvider, { config: themeModeConfig, children: content })) : (content);
|
|
10520
9955
|
const directionConfig = direction === false ? null : (direction !== null && direction !== void 0 ? direction : {});
|
|
10521
9956
|
const hapticsConfig = haptics === false ? null : (haptics !== null && haptics !== void 0 ? haptics : {});
|
|
10522
|
-
const permissionConfig = permissions === false ? null : (() => {
|
|
10523
|
-
const base = { ...(permissions !== null && permissions !== void 0 ? permissions : {}) };
|
|
10524
|
-
if (base.rules === undefined) {
|
|
10525
|
-
base.rules = DEFAULT_PERMISSION_RULES;
|
|
10526
|
-
}
|
|
10527
|
-
return base;
|
|
10528
|
-
})();
|
|
10529
9957
|
let enhancedTree = themedTree;
|
|
10530
|
-
if (permissionConfig) {
|
|
10531
|
-
enhancedTree = (jsxRuntime.jsx(PermissionProvider, { ...permissionConfig, children: enhancedTree }));
|
|
10532
|
-
}
|
|
10533
9958
|
if (hapticsConfig) {
|
|
10534
9959
|
enhancedTree = (jsxRuntime.jsx(HapticsProvider, { ...hapticsConfig, children: enhancedTree }));
|
|
10535
9960
|
}
|
|
@@ -11019,14 +10444,18 @@ function usePopoverPositioning(isOpen, options = {}) {
|
|
|
11019
10444
|
// Get popover dimensions
|
|
11020
10445
|
// Always use measureElement for robustness across platforms (RNW refs may not expose getBoundingClientRect)
|
|
11021
10446
|
let popoverDimensions = { width: 200, height: 100 }; // sensible defaults for initial calculation
|
|
10447
|
+
let hasMeasuredPopover = false;
|
|
11022
10448
|
if (popoverRef.current) {
|
|
11023
10449
|
const popoverRect = await measureElement(popoverRef);
|
|
11024
10450
|
if (popoverRect.width > 0 && popoverRect.height > 0) {
|
|
11025
10451
|
popoverDimensions = { width: popoverRect.width, height: popoverRect.height };
|
|
10452
|
+
hasMeasuredPopover = true;
|
|
11026
10453
|
}
|
|
11027
10454
|
}
|
|
11028
10455
|
// Calculate optimal position
|
|
11029
10456
|
const result = calculateOverlayPositionEnhanced(anchorRect, popoverDimensions, positioningOptionsRef.current);
|
|
10457
|
+
// Mark whether this position is based on actual measurements
|
|
10458
|
+
result._hasMeasuredPopover = hasMeasuredPopover;
|
|
11030
10459
|
setPosition(result);
|
|
11031
10460
|
}
|
|
11032
10461
|
catch (error) {
|
|
@@ -17277,6 +16706,7 @@ const TextInputBase = factory((props, ref) => {
|
|
|
17277
16706
|
const { value, onChangeText, onEnter, label, description, error, helperText, disabled, required, size = 'md', withAsterisk, placeholder, startSection, endSection, focused: focusedProp, accessibilityLabel, accessibilityHint, testID, textInputProps, style, radius, secureTextEntry, clearable, clearButtonLabel, onClear, inputRef, name, keyboardFocusId, ...rest } = otherProps;
|
|
17278
16707
|
const renderDisclaimer = useDisclaimer(disclaimerData.disclaimer, disclaimerData.disclaimerProps);
|
|
17279
16708
|
const [focused, setFocused] = React.useState(false);
|
|
16709
|
+
const [cursorVisible, setCursorVisible] = React.useState(true);
|
|
17280
16710
|
const theme = useTheme();
|
|
17281
16711
|
const { isRTL } = useDirection();
|
|
17282
16712
|
const internalInputRef = React.useRef(null);
|
|
@@ -17348,6 +16778,16 @@ const TextInputBase = factory((props, ref) => {
|
|
|
17348
16778
|
return '';
|
|
17349
16779
|
return '•'.repeat(length);
|
|
17350
16780
|
}, [isSecureEntry, normalizedValue]);
|
|
16781
|
+
// Blinking cursor for secure entry (simple interval toggle)
|
|
16782
|
+
React.useEffect(() => {
|
|
16783
|
+
if (focused && isSecureEntry) {
|
|
16784
|
+
setCursorVisible(true);
|
|
16785
|
+
const interval = setInterval(() => {
|
|
16786
|
+
setCursorVisible(v => !v);
|
|
16787
|
+
}, 530);
|
|
16788
|
+
return () => clearInterval(interval);
|
|
16789
|
+
}
|
|
16790
|
+
}, [focused, isSecureEntry]);
|
|
17351
16791
|
const textColor = (_a = flattenedInputStyle === null || flattenedInputStyle === void 0 ? void 0 : flattenedInputStyle.color) !== null && _a !== void 0 ? _a : (styleProps.disabled ? theme.text.disabled : theme.text.primary);
|
|
17352
16792
|
const resolvedInputStyle = React.useMemo(() => {
|
|
17353
16793
|
const base = [styles.input];
|
|
@@ -17449,7 +16889,12 @@ const TextInputBase = factory((props, ref) => {
|
|
|
17449
16889
|
}
|
|
17450
16890
|
}, [keyboardManager, pendingFocusTarget, focusTargetId]);
|
|
17451
16891
|
const disclaimerNode = renderDisclaimer();
|
|
17452
|
-
return (jsxRuntime.jsxs(reactNative.View, { style: [styles.container, spacingStyles, layoutStyles, style], ...rest, children: [jsxRuntime.jsx(FieldHeader, { label: label, description: description, required: required, withAsterisk: withAsterisk, disabled: disabled, error: !!error, size: size }), jsxRuntime.jsxs(reactNative.View, { style: styles.inputContainer, children: [startSection && (jsxRuntime.jsx(reactNative.View, { style: styles.startSection, children: startSection })), jsxRuntime.jsxs(reactNative.View, { style: { flex: 1, position: 'relative', justifyContent: 'center' }, children: [jsxRuntime.jsx(reactNative.TextInput, { ref: assignInputRef, value: value, onChangeText: onChangeText, onFocus: handleFocus, onBlur: handleBlur, onSubmitEditing: handleSubmitEditing, editable: !disabled, placeholder: placeholder, placeholderTextColor: theme.text.muted, style: resolvedInputStyle, selectionColor: selectionColorProp !== null && selectionColorProp !== void 0 ? selectionColorProp : textColor, testID: testID, secureTextEntry: isSecureEntry, ...inputAccessibilityProps, ...restTextInputProps }), isSecureEntry &&
|
|
16892
|
+
return (jsxRuntime.jsxs(reactNative.View, { style: [styles.container, spacingStyles, layoutStyles, style], ...rest, children: [jsxRuntime.jsx(FieldHeader, { label: label, description: description, required: required, withAsterisk: withAsterisk, disabled: disabled, error: !!error, size: size }), jsxRuntime.jsxs(reactNative.View, { style: styles.inputContainer, children: [startSection && (jsxRuntime.jsx(reactNative.View, { style: styles.startSection, children: startSection })), jsxRuntime.jsxs(reactNative.View, { style: { flex: 1, position: 'relative', justifyContent: 'center' }, children: [jsxRuntime.jsx(reactNative.TextInput, { ref: assignInputRef, value: value, onChangeText: onChangeText, onFocus: handleFocus, onBlur: handleBlur, onSubmitEditing: handleSubmitEditing, editable: !disabled, placeholder: placeholder, placeholderTextColor: theme.text.muted, style: resolvedInputStyle, selectionColor: selectionColorProp !== null && selectionColorProp !== void 0 ? selectionColorProp : textColor, testID: testID, secureTextEntry: isSecureEntry, ...inputAccessibilityProps, ...restTextInputProps }), isSecureEntry && (jsxRuntime.jsxs(reactNative.View, { pointerEvents: "none", style: [overlayStyle, { flexDirection: 'row', alignItems: 'center' }], children: [jsxRuntime.jsx(reactNative.Text, { accessible: false, style: { color: textColor, fontSize: styles.input.fontSize, fontFamily: theme.fontFamily }, numberOfLines: 1, children: maskedValue }), focused && cursorVisible && (jsxRuntime.jsx(reactNative.View, { style: {
|
|
16893
|
+
width: 1,
|
|
16894
|
+
height: styles.input.fontSize || 16,
|
|
16895
|
+
backgroundColor: textColor,
|
|
16896
|
+
marginLeft: 1,
|
|
16897
|
+
} }))] }))] }), (showClearButton || endSection) && (jsxRuntime.jsxs(reactNative.View, { style: styles.endSection, children: [showClearButton && (jsxRuntime.jsx(ClearButton, { onPress: handleClear, size: size, accessibilityLabel: clearButtonLabelText, hasRightSection: !!endSection })), endSection] }))] }), disclaimerNode, error && (jsxRuntime.jsx(reactNative.Text, { style: styles.error, role: "alert", accessibilityLiveRegion: "polite", children: error })), helperText && !error && (jsxRuntime.jsx(reactNative.Text, { style: styles.helperText, children: helperText }))] }));
|
|
17453
16898
|
});
|
|
17454
16899
|
|
|
17455
16900
|
const getInputTypeConfig = (type) => {
|
|
@@ -18007,18 +17452,19 @@ const useTextAreaStyles = (props) => {
|
|
|
18007
17452
|
? theme.colors.error[5]
|
|
18008
17453
|
: styleProps.focused
|
|
18009
17454
|
? theme.colors.primary[5]
|
|
18010
|
-
:
|
|
18011
|
-
? theme.backgrounds.border
|
|
18012
|
-
: 'transparent',
|
|
17455
|
+
: theme.backgrounds.border,
|
|
18013
17456
|
borderRadius: DESIGN_TOKENS.radius.lg,
|
|
18014
|
-
borderWidth:
|
|
17457
|
+
borderWidth: 2,
|
|
18015
17458
|
paddingHorizontal: DESIGN_TOKENS.spacing.sm,
|
|
18016
17459
|
paddingVertical: DESIGN_TOKENS.spacing.xs,
|
|
17460
|
+
// Match Input focus treatment on web
|
|
18017
17461
|
...(styleProps.focused && !styleProps.disabled && reactNative.Platform.OS === 'web' && {
|
|
18018
17462
|
boxShadow: `0 0 0 2px ${((_a = theme.states) === null || _a === void 0 ? void 0 : _a.focusRing) || theme.colors.primary[2]}`,
|
|
18019
17463
|
}),
|
|
17464
|
+
// Light elevation similar to Input
|
|
18020
17465
|
...(!styleProps.disabled && theme.colorScheme === 'light' && {
|
|
18021
17466
|
elevation: 1,
|
|
17467
|
+
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)',
|
|
18022
17468
|
}),
|
|
18023
17469
|
opacity: styleProps.disabled ? DESIGN_TOKENS.opacity.disabled : 1,
|
|
18024
17470
|
},
|
|
@@ -19700,7 +19146,7 @@ const useSwitchStyles = (props) => {
|
|
|
19700
19146
|
...(reactNative.Platform.OS === 'web' && { userSelect: 'none' }),
|
|
19701
19147
|
},
|
|
19702
19148
|
labelContainer: {
|
|
19703
|
-
|
|
19149
|
+
flexShrink: 1,
|
|
19704
19150
|
justifyContent: 'center',
|
|
19705
19151
|
},
|
|
19706
19152
|
labelDisabled: {
|
|
@@ -19869,8 +19315,8 @@ const Switch = factory((rawProps, ref) => {
|
|
|
19869
19315
|
const LayoutComponent = isVertical ? Column : Row;
|
|
19870
19316
|
// For vertical layouts (top/bottom), we want tighter spacing and center alignment
|
|
19871
19317
|
const layoutProps = isVertical
|
|
19872
|
-
? { gap: 'xs',
|
|
19873
|
-
: { gap: 'sm',
|
|
19318
|
+
? { gap: 'xs', align: 'center' }
|
|
19319
|
+
: { gap: 'sm', align: 'center' };
|
|
19874
19320
|
const disclaimerNode = renderDisclaimer();
|
|
19875
19321
|
return (jsxRuntime.jsxs(reactNative.View, { style: spacingStyles, children: [jsxRuntime.jsxs(LayoutComponent, { ...layoutProps, children: [labelPosition === 'top' && labelElement, labelPosition === 'left' && labelElement, switchElement, labelPosition === 'right' && labelElement, labelPosition === 'bottom' && labelElement] }), disclaimerNode ? (jsxRuntime.jsx(reactNative.View, { style: { width: '100%' }, children: disclaimerNode })) : null] }));
|
|
19876
19322
|
});
|
|
@@ -27484,7 +26930,7 @@ const MiniCalendar = ({ value, onChange, defaultValue, numberOfDays = 7, default
|
|
|
27484
26930
|
}
|
|
27485
26931
|
onChange === null || onChange === void 0 ? void 0 : onChange(date);
|
|
27486
26932
|
}, [isControlled, maxDate, minDate, onChange]);
|
|
27487
|
-
return (jsxRuntime.jsxs(reactNative.View, { children: [jsxRuntime.jsxs(Flex, { direction: "row", justify: "space-between", align: "center", style: { marginBottom: 16 }, children: [jsxRuntime.jsx(reactNative.Pressable, { onPress: handlePrevious, style: ({ pressed }) => [
|
|
26933
|
+
return (jsxRuntime.jsxs(reactNative.View, { style: { alignSelf: 'flex-start' }, children: [jsxRuntime.jsxs(Flex, { direction: "row", justify: "space-between", align: "center", style: { marginBottom: 16 }, children: [jsxRuntime.jsx(reactNative.Pressable, { onPress: handlePrevious, style: ({ pressed }) => [
|
|
27488
26934
|
{
|
|
27489
26935
|
padding: 8,
|
|
27490
26936
|
borderRadius: 6,
|
|
@@ -27496,7 +26942,7 @@ const MiniCalendar = ({ value, onChange, defaultValue, numberOfDays = 7, default
|
|
|
27496
26942
|
borderRadius: 6,
|
|
27497
26943
|
backgroundColor: pressed ? theme.colors.gray[2] : 'transparent',
|
|
27498
26944
|
},
|
|
27499
|
-
], ...nextControlProps, children: jsxRuntime.jsx(Icon, { name: "chevron-right", size: 16, color: theme.colors.gray[6] }) })] }), jsxRuntime.jsx(reactNative.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: jsxRuntime.jsx(Flex, { direction: "row", gap: 4, children: days.map((date) => {
|
|
26945
|
+
], ...nextControlProps, children: jsxRuntime.jsx(Icon, { name: "chevron-right", size: 16, color: theme.colors.gray[6] }) })] }), jsxRuntime.jsx(reactNative.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: { flexGrow: 0 }, style: { flexGrow: 0 }, children: jsxRuntime.jsx(Flex, { direction: "row", gap: 4, children: days.map((date) => {
|
|
27500
26946
|
const isSelected = selectedDate ? dateUtils$1.isSameDay(date, selectedDate) : false;
|
|
27501
26947
|
const isToday = dateUtils$1.isToday(date);
|
|
27502
26948
|
const isWeekend = dateUtils$1.isWeekend(date);
|
|
@@ -30237,6 +29683,7 @@ function MenuBase(props, ref) {
|
|
|
30237
29683
|
const overlayId = openOverlay({
|
|
30238
29684
|
content: menuDropdown,
|
|
30239
29685
|
anchor: { x: positionResult.x, y: positionResult.y, width: overlaySize.width, height: overlaySize.height },
|
|
29686
|
+
placement: positionResult.placement || position,
|
|
30240
29687
|
closeOnClickOutside,
|
|
30241
29688
|
closeOnEscape,
|
|
30242
29689
|
strategy,
|
|
@@ -32206,7 +31653,7 @@ function usePopoverContext(component) {
|
|
|
32206
31653
|
const DEFAULT_ARROW_SIZE = 7;
|
|
32207
31654
|
const PopoverBase = (props, ref) => {
|
|
32208
31655
|
var _a;
|
|
32209
|
-
const { children, opened: controlledOpened, defaultOpened = false, onChange, onOpen, onClose, onDismiss, disabled = false, closeOnClickOutside = true, closeOnEscape = true, clickOutsideEvents, // currently not implemented
|
|
31656
|
+
const { children, opened: controlledOpened, defaultOpened = false, onChange, onOpen, onClose, onDismiss, trigger = 'click', disabled = false, closeOnClickOutside = true, closeOnEscape = true, clickOutsideEvents, // currently not implemented
|
|
32210
31657
|
trapFocus = false, keepMounted = false, returnFocus = false, withinPortal = true, withOverlay = false, overlayProps, width, minWidth, minHeight, maxWidth, maxHeight, radius, shadow, zIndex = 300, position = 'bottom', offset = 8, floatingStrategy = 'fixed', middlewares, preventPositionChangeWhenVisible = false, hideDetached = true, viewport, keyboardAvoidance = true, fallbackPlacements, boundary, withRoles = true, id, withArrow = false, arrowSize = DEFAULT_ARROW_SIZE, arrowRadius = 0, arrowOffset = 5, arrowPosition = 'center', onPositionChange, testID, ...rest } = props;
|
|
32211
31658
|
const theme = useTheme();
|
|
32212
31659
|
const { spacingProps } = extractSpacingProps(rest);
|
|
@@ -32218,9 +31665,18 @@ const PopoverBase = (props, ref) => {
|
|
|
32218
31665
|
const openedRef = React.useRef(opened);
|
|
32219
31666
|
const closingReasonRef = React.useRef(null);
|
|
32220
31667
|
const anchorMeasurementsRef = React.useRef(null);
|
|
31668
|
+
const hoverTimeoutRef = React.useRef(null);
|
|
32221
31669
|
React.useEffect(() => {
|
|
32222
31670
|
openedRef.current = opened;
|
|
32223
31671
|
}, [opened]);
|
|
31672
|
+
// Cleanup hover timeout on unmount
|
|
31673
|
+
React.useEffect(() => {
|
|
31674
|
+
return () => {
|
|
31675
|
+
if (hoverTimeoutRef.current) {
|
|
31676
|
+
clearTimeout(hoverTimeoutRef.current);
|
|
31677
|
+
}
|
|
31678
|
+
};
|
|
31679
|
+
}, []);
|
|
32224
31680
|
const resolvedOffset = typeof offset === 'number' ? offset : (_a = offset === null || offset === void 0 ? void 0 : offset.mainAxis) !== null && _a !== void 0 ? _a : 8;
|
|
32225
31681
|
const resolvedFlip = preventPositionChangeWhenVisible
|
|
32226
31682
|
? false
|
|
@@ -32233,7 +31689,7 @@ const PopoverBase = (props, ref) => {
|
|
|
32233
31689
|
? false
|
|
32234
31690
|
: true;
|
|
32235
31691
|
const resolvedStrategy = floatingStrategy !== null && floatingStrategy !== void 0 ? floatingStrategy : 'fixed';
|
|
32236
|
-
const { position: positioningResult, anchorRef, popoverRef, showOverlay, hideOverlay, updatePosition } = useDropdownPositioning({
|
|
31692
|
+
const { position: positioningResult, anchorRef, popoverRef, showOverlay, hideOverlay, updatePosition, isPositioning } = useDropdownPositioning({
|
|
32237
31693
|
isOpen: opened && !disabled && !!dropdownState,
|
|
32238
31694
|
placement: position,
|
|
32239
31695
|
offset: resolvedOffset,
|
|
@@ -32245,9 +31701,20 @@ const PopoverBase = (props, ref) => {
|
|
|
32245
31701
|
fallbackPlacements,
|
|
32246
31702
|
viewport,
|
|
32247
31703
|
onClose: () => handleOverlayClose('dismiss'),
|
|
32248
|
-
closeOnClickOutside,
|
|
31704
|
+
closeOnClickOutside: trigger === 'hover' ? false : closeOnClickOutside,
|
|
32249
31705
|
closeOnEscape,
|
|
32250
31706
|
});
|
|
31707
|
+
// Track if we've done measurement-based positioning to avoid flicker
|
|
31708
|
+
const hasPositionedRef = React.useRef(false);
|
|
31709
|
+
React.useEffect(() => {
|
|
31710
|
+
// Only mark as positioned when we have a measurement-based position
|
|
31711
|
+
if (opened && positioningResult && positioningResult._hasMeasuredPopover) {
|
|
31712
|
+
hasPositionedRef.current = true;
|
|
31713
|
+
}
|
|
31714
|
+
if (!opened) {
|
|
31715
|
+
hasPositionedRef.current = false;
|
|
31716
|
+
}
|
|
31717
|
+
}, [opened, positioningResult]);
|
|
32251
31718
|
const popoverStyles = React.useMemo(() => createPopoverStyles(theme)({
|
|
32252
31719
|
radius,
|
|
32253
31720
|
shadow,
|
|
@@ -32351,6 +31818,28 @@ const PopoverBase = (props, ref) => {
|
|
|
32351
31818
|
openPopover();
|
|
32352
31819
|
}
|
|
32353
31820
|
}, [closePopover, openPopover]);
|
|
31821
|
+
// Hover-specific handlers with delay to prevent glitching when moving between target and dropdown
|
|
31822
|
+
const handleHoverOpen = React.useCallback(() => {
|
|
31823
|
+
if (hoverTimeoutRef.current) {
|
|
31824
|
+
clearTimeout(hoverTimeoutRef.current);
|
|
31825
|
+
hoverTimeoutRef.current = null;
|
|
31826
|
+
}
|
|
31827
|
+
openPopover();
|
|
31828
|
+
}, [openPopover]);
|
|
31829
|
+
const handleHoverClose = React.useCallback(() => {
|
|
31830
|
+
if (hoverTimeoutRef.current) {
|
|
31831
|
+
clearTimeout(hoverTimeoutRef.current);
|
|
31832
|
+
}
|
|
31833
|
+
hoverTimeoutRef.current = setTimeout(() => {
|
|
31834
|
+
closePopover('programmatic');
|
|
31835
|
+
hoverTimeoutRef.current = null;
|
|
31836
|
+
}, 150); // Delay to allow mouse to move to dropdown
|
|
31837
|
+
}, [closePopover]);
|
|
31838
|
+
// Store hover handlers in refs to avoid causing re-renders in useEffect
|
|
31839
|
+
const hoverHandlersRef = React.useRef({ open: handleHoverOpen, close: handleHoverClose });
|
|
31840
|
+
React.useEffect(() => {
|
|
31841
|
+
hoverHandlersRef.current = { open: handleHoverOpen, close: handleHoverClose };
|
|
31842
|
+
}, [handleHoverOpen, handleHoverClose]);
|
|
32354
31843
|
React.useEffect(() => {
|
|
32355
31844
|
if (opened) {
|
|
32356
31845
|
updateAnchorMeasurements();
|
|
@@ -32409,14 +31898,26 @@ const PopoverBase = (props, ref) => {
|
|
|
32409
31898
|
if (typeof resolvedMaxHeight === 'number')
|
|
32410
31899
|
sizeStyles.maxHeight = resolvedMaxHeight;
|
|
32411
31900
|
const dropdownStyle = [popoverStyles.dropdown, dropdownState.style, sizeStyles];
|
|
32412
|
-
|
|
31901
|
+
// Hover handlers for the dropdown to keep it open when mouse moves from target to dropdown
|
|
31902
|
+
const dropdownHoverHandlers = trigger === 'hover' && reactNative.Platform.OS === 'web'
|
|
31903
|
+
? {
|
|
31904
|
+
onMouseEnter: () => hoverHandlersRef.current.open(),
|
|
31905
|
+
onMouseLeave: () => hoverHandlersRef.current.close(),
|
|
31906
|
+
}
|
|
31907
|
+
: {};
|
|
31908
|
+
// Hide content until we have measurement-based positioning to prevent visual "snap"
|
|
31909
|
+
const hasMeasuredPosition = (positioningResult === null || positioningResult === void 0 ? void 0 : positioningResult._hasMeasuredPopover) === true;
|
|
31910
|
+
const visibilityStyle = !hasMeasuredPosition && reactNative.Platform.OS === 'web'
|
|
31911
|
+
? { opacity: 0 }
|
|
31912
|
+
: {};
|
|
31913
|
+
const content = (jsxRuntime.jsxs(reactNative.View, { ref: popoverRef, style: [popoverStyles.wrapper, widthOverride ? { width: widthOverride } : null, visibilityStyle], pointerEvents: trigger === 'hover' ? 'auto' : (dropdownState.trapFocus ? 'auto' : 'box-none'), testID: dropdownState.testID, onLayout: handleDropdownLayout, ...dropdownHoverHandlers, ...dropdownState.containerProps, children: [jsxRuntime.jsx(reactNative.View, { style: dropdownStyle, children: dropdownState.content }), withArrow && (jsxRuntime.jsx(reactNative.View, { style: getArrowStyle(positioningResult.placement, arrowSize, arrowRadius, arrowOffset, arrowPosition, theme) }))] }));
|
|
32413
31914
|
showOverlay(content, {
|
|
32414
31915
|
width: widthOverride,
|
|
32415
31916
|
maxHeight: resolvedMaxHeight,
|
|
32416
31917
|
zIndex,
|
|
32417
31918
|
});
|
|
32418
31919
|
onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange(positioningResult.placement);
|
|
32419
|
-
}, [opened, dropdownState, positioningResult, popoverRef, showOverlay, hideOverlay, popoverStyles.dropdown, popoverStyles.wrapper, width, maxHeight, minWidth, minHeight, maxWidth, withArrow, arrowSize, arrowRadius, arrowOffset, arrowPosition, theme, zIndex, onPositionChange, schedulePositionUpdate]);
|
|
31920
|
+
}, [opened, dropdownState, positioningResult, popoverRef, showOverlay, hideOverlay, popoverStyles.dropdown, popoverStyles.wrapper, width, maxHeight, minWidth, minHeight, maxWidth, withArrow, arrowSize, arrowRadius, arrowOffset, arrowPosition, theme, zIndex, onPositionChange, schedulePositionUpdate, trigger, isPositioning]);
|
|
32420
31921
|
React.useEffect(() => {
|
|
32421
31922
|
return () => {
|
|
32422
31923
|
hideOverlay();
|
|
@@ -32437,6 +31938,8 @@ const PopoverBase = (props, ref) => {
|
|
|
32437
31938
|
open: openPopover,
|
|
32438
31939
|
close: () => closePopover('programmatic'),
|
|
32439
31940
|
toggle: togglePopover,
|
|
31941
|
+
hoverOpen: handleHoverOpen,
|
|
31942
|
+
hoverClose: handleHoverClose,
|
|
32440
31943
|
registerDropdown,
|
|
32441
31944
|
unregisterDropdown,
|
|
32442
31945
|
anchorRef,
|
|
@@ -32445,7 +31948,8 @@ const PopoverBase = (props, ref) => {
|
|
|
32445
31948
|
withRoles,
|
|
32446
31949
|
disabled,
|
|
32447
31950
|
returnFocus,
|
|
32448
|
-
|
|
31951
|
+
trigger,
|
|
31952
|
+
}), [opened, openPopover, closePopover, togglePopover, handleHoverOpen, handleHoverClose, registerDropdown, unregisterDropdown, anchorRef, targetId, dropdownId, withRoles, disabled, returnFocus, trigger]);
|
|
32449
31953
|
const setContainerRef = React.useCallback((node) => {
|
|
32450
31954
|
if (typeof ref === 'function') {
|
|
32451
31955
|
ref(node);
|
|
@@ -32495,16 +31999,44 @@ const PopoverTargetBase = (props, ref) => {
|
|
|
32495
31999
|
: { id: context.targetId };
|
|
32496
32000
|
const composedRef = mergeRefs(children.ref, externalTargetRef);
|
|
32497
32001
|
const triggerHandlers = {};
|
|
32498
|
-
|
|
32499
|
-
|
|
32500
|
-
|
|
32501
|
-
|
|
32502
|
-
|
|
32503
|
-
|
|
32504
|
-
|
|
32505
|
-
|
|
32506
|
-
|
|
32507
|
-
|
|
32002
|
+
const wrapperHoverHandlers = {};
|
|
32003
|
+
// Click trigger: toggle on press
|
|
32004
|
+
if (context.trigger === 'click') {
|
|
32005
|
+
triggerHandlers.onPress = (...args) => {
|
|
32006
|
+
const tgt = targetProps;
|
|
32007
|
+
if (tgt && typeof tgt.onPress === 'function') {
|
|
32008
|
+
tgt.onPress(...args);
|
|
32009
|
+
}
|
|
32010
|
+
if (typeof childProps.onPress === 'function') {
|
|
32011
|
+
childProps.onPress(...args);
|
|
32012
|
+
}
|
|
32013
|
+
context.toggle();
|
|
32014
|
+
};
|
|
32015
|
+
}
|
|
32016
|
+
// Hover trigger: open/close on mouse enter/leave (web only)
|
|
32017
|
+
// Applied to the wrapper View for reliable hover detection
|
|
32018
|
+
if (context.trigger === 'hover' && reactNative.Platform.OS === 'web') {
|
|
32019
|
+
wrapperHoverHandlers.onMouseEnter = (...args) => {
|
|
32020
|
+
const tgt = targetProps;
|
|
32021
|
+
if (tgt && typeof tgt.onMouseEnter === 'function') {
|
|
32022
|
+
tgt.onMouseEnter(...args);
|
|
32023
|
+
}
|
|
32024
|
+
if (typeof childProps.onMouseEnter === 'function') {
|
|
32025
|
+
childProps.onMouseEnter(...args);
|
|
32026
|
+
}
|
|
32027
|
+
context.hoverOpen();
|
|
32028
|
+
};
|
|
32029
|
+
wrapperHoverHandlers.onMouseLeave = (...args) => {
|
|
32030
|
+
const tgt = targetProps;
|
|
32031
|
+
if (tgt && typeof tgt.onMouseLeave === 'function') {
|
|
32032
|
+
tgt.onMouseLeave(...args);
|
|
32033
|
+
}
|
|
32034
|
+
if (typeof childProps.onMouseLeave === 'function') {
|
|
32035
|
+
childProps.onMouseLeave(...args);
|
|
32036
|
+
}
|
|
32037
|
+
context.hoverClose();
|
|
32038
|
+
};
|
|
32039
|
+
}
|
|
32508
32040
|
if (reactNative.Platform.OS === 'web') {
|
|
32509
32041
|
triggerHandlers.onKeyDown = (event) => {
|
|
32510
32042
|
const tgt = targetProps;
|
|
@@ -32526,7 +32058,14 @@ const PopoverTargetBase = (props, ref) => {
|
|
|
32526
32058
|
};
|
|
32527
32059
|
}
|
|
32528
32060
|
const dynamicRefProp = { [refProp]: composedRef };
|
|
32529
|
-
|
|
32061
|
+
// Remove handlers that we're overriding from sanitizedTargetProps
|
|
32062
|
+
if (context.trigger === 'click') {
|
|
32063
|
+
delete sanitizedTargetProps.onPress;
|
|
32064
|
+
}
|
|
32065
|
+
if (context.trigger === 'hover') {
|
|
32066
|
+
delete sanitizedTargetProps.onMouseEnter;
|
|
32067
|
+
delete sanitizedTargetProps.onMouseLeave;
|
|
32068
|
+
}
|
|
32530
32069
|
delete sanitizedTargetProps.onKeyDown;
|
|
32531
32070
|
const mergedProps = {
|
|
32532
32071
|
...sanitizedTargetProps,
|
|
@@ -32538,7 +32077,7 @@ const PopoverTargetBase = (props, ref) => {
|
|
|
32538
32077
|
mergedProps.disabled = true;
|
|
32539
32078
|
}
|
|
32540
32079
|
const anchorWrapperRef = mergeRefs(context.anchorRef, ref);
|
|
32541
|
-
return (jsxRuntime.jsx(reactNative.View, { ref: anchorWrapperRef, collapsable: false, children: React.cloneElement(children, mergedProps) }));
|
|
32080
|
+
return (jsxRuntime.jsx(reactNative.View, { ref: anchorWrapperRef, collapsable: false, ...wrapperHoverHandlers, children: React.cloneElement(children, mergedProps) }));
|
|
32542
32081
|
};
|
|
32543
32082
|
const PopoverDropdownBase = (props, _ref) => {
|
|
32544
32083
|
const { children, trapFocus = false, keepMounted, style, testID, ...rest } = props;
|
|
@@ -32582,8 +32121,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
|
|
|
32582
32121
|
const [side, alignment] = placement.split('-');
|
|
32583
32122
|
switch (side) {
|
|
32584
32123
|
case 'top':
|
|
32124
|
+
// Arrow points down, hide the borders that overlap with content (top-left corner after rotation)
|
|
32585
32125
|
return {
|
|
32586
32126
|
...base,
|
|
32127
|
+
borderTopWidth: 0,
|
|
32128
|
+
borderLeftWidth: 0,
|
|
32587
32129
|
bottom: -arrowSize,
|
|
32588
32130
|
left: alignment === 'end'
|
|
32589
32131
|
? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
|
|
@@ -32593,8 +32135,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
|
|
|
32593
32135
|
marginLeft: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
|
|
32594
32136
|
};
|
|
32595
32137
|
case 'bottom':
|
|
32138
|
+
// Arrow points up, hide the borders that overlap with content (bottom-right corner after rotation)
|
|
32596
32139
|
return {
|
|
32597
32140
|
...base,
|
|
32141
|
+
borderBottomWidth: 0,
|
|
32142
|
+
borderRightWidth: 0,
|
|
32598
32143
|
top: -arrowSize,
|
|
32599
32144
|
left: alignment === 'end'
|
|
32600
32145
|
? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
|
|
@@ -32604,8 +32149,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
|
|
|
32604
32149
|
marginLeft: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
|
|
32605
32150
|
};
|
|
32606
32151
|
case 'left':
|
|
32152
|
+
// Arrow points right, hide the borders that overlap with content (bottom-left corner after rotation)
|
|
32607
32153
|
return {
|
|
32608
32154
|
...base,
|
|
32155
|
+
borderBottomWidth: 0,
|
|
32156
|
+
borderLeftWidth: 0,
|
|
32609
32157
|
right: -arrowSize,
|
|
32610
32158
|
top: alignment === 'end'
|
|
32611
32159
|
? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
|
|
@@ -32615,8 +32163,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
|
|
|
32615
32163
|
marginTop: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
|
|
32616
32164
|
};
|
|
32617
32165
|
case 'right':
|
|
32166
|
+
// Arrow points left, hide the borders that overlap with content (top-right corner after rotation)
|
|
32618
32167
|
return {
|
|
32619
32168
|
...base,
|
|
32169
|
+
borderTopWidth: 0,
|
|
32170
|
+
borderRightWidth: 0,
|
|
32620
32171
|
left: -arrowSize,
|
|
32621
32172
|
top: alignment === 'end'
|
|
32622
32173
|
? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
|
|
@@ -35751,104 +35302,6 @@ const Ring = factory((props, ref) => {
|
|
|
35751
35302
|
return (jsxRuntime.jsxs(reactNative.View, { ref: ref, style: [styles$8.container, spacingStyles, style], testID: testID, accessibilityLabel: accessibilityLabel !== null && accessibilityLabel !== void 0 ? accessibilityLabel : `Ring value ${Math.round(percent)} percent`, accessibilityRole: "progressbar", accessibilityValue: { min, max, now: Math.round(clampedValue) }, ...otherProps, children: [jsxRuntime.jsxs(reactNative.View, { style: [styles$8.ringWrapper, { width: size, height: size }, ringStyle], children: [jsxRuntime.jsxs(Svg, { width: size, height: size, viewBox: `0 0 ${size} ${size}`, children: [jsxRuntime.jsx(Svg.Circle, { cx: size / 2, cy: size / 2, r: radius, stroke: defaultTrackColor, strokeWidth: thickness, fill: "transparent" }), jsxRuntime.jsx(Svg.Circle, { cx: size / 2, cy: size / 2, r: radius, stroke: resolvedProgressColor, strokeWidth: thickness, strokeLinecap: roundedCaps ? 'round' : 'butt', strokeDasharray: `${circumference} ${circumference}`, strokeDashoffset: dashOffset, fill: "transparent", transform: `rotate(-90 ${size / 2} ${size / 2})` })] }), jsxRuntime.jsx(reactNative.View, { pointerEvents: "none", style: [styles$8.centerContent, { width: size, height: size }, contentStyle], children: centerContent })] }), caption !== undefined && caption !== null ? (React.isValidElement(caption) ? (caption) : (jsxRuntime.jsx(Text, { variant: "span", size: "xs", color: captionTextColor, weight: "600", style: [{ marginTop: 6, letterSpacing: 1 }, captionStyle], children: caption }))) : null] }));
|
|
35752
35303
|
}, { displayName: 'Ring' });
|
|
35753
35304
|
|
|
35754
|
-
const NAVIGATIONPROGRESS_DEFAULTS = {
|
|
35755
|
-
size: 3,
|
|
35756
|
-
color: 'primary',
|
|
35757
|
-
zIndex: 9999,
|
|
35758
|
-
overlay: true,
|
|
35759
|
-
stepInterval: 500,
|
|
35760
|
-
radius: 0,
|
|
35761
|
-
};
|
|
35762
|
-
|
|
35763
|
-
let subscribers = new Set();
|
|
35764
|
-
let internalState = { value: 0, active: false };
|
|
35765
|
-
let interval = null;
|
|
35766
|
-
function broadcast() { subscribers.forEach(cb => cb({ ...internalState })); }
|
|
35767
|
-
function schedule(intervalMs) {
|
|
35768
|
-
clearInterval(interval);
|
|
35769
|
-
interval = setInterval(() => {
|
|
35770
|
-
if (!internalState.active)
|
|
35771
|
-
return;
|
|
35772
|
-
const remain = 100 - internalState.value;
|
|
35773
|
-
const inc = Math.max(0.1, remain * 0.03);
|
|
35774
|
-
internalState.value = Math.min(99, internalState.value + inc);
|
|
35775
|
-
broadcast();
|
|
35776
|
-
}, intervalMs);
|
|
35777
|
-
}
|
|
35778
|
-
const navigationProgress = {
|
|
35779
|
-
start() { if (internalState.active)
|
|
35780
|
-
return; internalState.active = true; if (internalState.value >= 100)
|
|
35781
|
-
internalState.value = 0; broadcast(); schedule(NAVIGATIONPROGRESS_DEFAULTS.stepInterval); },
|
|
35782
|
-
stop() { internalState.active = false; broadcast(); },
|
|
35783
|
-
complete() { internalState.active = true; internalState.value = 100; broadcast(); setTimeout(() => { internalState.active = false; internalState.value = 0; broadcast(); }, 400); },
|
|
35784
|
-
reset() { internalState.value = 0; internalState.active = false; broadcast(); },
|
|
35785
|
-
set(v) { internalState.value = Math.max(0, Math.min(100, v)); broadcast(); },
|
|
35786
|
-
increment(delta = 5) { internalState.value = Math.min(100, internalState.value + delta); broadcast(); },
|
|
35787
|
-
decrement(delta = 5) { internalState.value = Math.max(0, internalState.value - delta); broadcast(); },
|
|
35788
|
-
isActive() { return internalState.active; }
|
|
35789
|
-
};
|
|
35790
|
-
const NavigationProgress = ({ value, size = NAVIGATIONPROGRESS_DEFAULTS.size, color = NAVIGATIONPROGRESS_DEFAULTS.color, zIndex = NAVIGATIONPROGRESS_DEFAULTS.zIndex, overlay = NAVIGATIONPROGRESS_DEFAULTS.overlay, stepInterval = NAVIGATIONPROGRESS_DEFAULTS.stepInterval, radius = NAVIGATIONPROGRESS_DEFAULTS.radius, active = true, style }) => {
|
|
35791
|
-
const theme = useTheme();
|
|
35792
|
-
const scheme = useColorScheme();
|
|
35793
|
-
const isDark = scheme === 'dark';
|
|
35794
|
-
const progress = Animated.useSharedValue(0);
|
|
35795
|
-
const opacity = Animated.useSharedValue(0);
|
|
35796
|
-
React.useEffect(() => {
|
|
35797
|
-
const sub = (s) => {
|
|
35798
|
-
if (value == null) {
|
|
35799
|
-
progress.value = Animated.withTiming(s.value, { duration: stepInterval });
|
|
35800
|
-
opacity.value = Animated.withTiming(s.active ? 1 : 0, { duration: 150 });
|
|
35801
|
-
}
|
|
35802
|
-
};
|
|
35803
|
-
subscribers.add(sub);
|
|
35804
|
-
broadcast();
|
|
35805
|
-
return () => { subscribers.delete(sub); };
|
|
35806
|
-
}, [value, stepInterval, progress, opacity]);
|
|
35807
|
-
React.useEffect(() => {
|
|
35808
|
-
if (value != null) {
|
|
35809
|
-
progress.value = Animated.withTiming(value, { duration: stepInterval });
|
|
35810
|
-
opacity.value = Animated.withTiming(active ? 1 : 0, { duration: 150 });
|
|
35811
|
-
}
|
|
35812
|
-
}, [value, active, stepInterval]);
|
|
35813
|
-
let resolvedColor = color;
|
|
35814
|
-
if (theme.colors[color]) {
|
|
35815
|
-
const bucket = theme.colors[color];
|
|
35816
|
-
resolvedColor = bucket[5] || bucket[4] || bucket[0];
|
|
35817
|
-
}
|
|
35818
|
-
const barStyle = Animated.useAnimatedStyle(() => ({ width: `${progress.value}%` }));
|
|
35819
|
-
const containerStyle = Animated.useAnimatedStyle(() => ({ opacity: opacity.value }));
|
|
35820
|
-
return (jsxRuntime.jsxs(Animated.View, { style: [
|
|
35821
|
-
{
|
|
35822
|
-
position: overlay ? 'absolute' : 'relative',
|
|
35823
|
-
top: 0,
|
|
35824
|
-
left: 0,
|
|
35825
|
-
right: 0,
|
|
35826
|
-
height: size,
|
|
35827
|
-
backgroundColor: isDark ? theme.colors.gray[3] : theme.colors.gray[2],
|
|
35828
|
-
overflow: 'hidden',
|
|
35829
|
-
zIndex,
|
|
35830
|
-
borderRadius: radius,
|
|
35831
|
-
pointerEvents: 'none'
|
|
35832
|
-
},
|
|
35833
|
-
containerStyle,
|
|
35834
|
-
style
|
|
35835
|
-
], children: [jsxRuntime.jsx(Animated.View, { style: [{
|
|
35836
|
-
position: 'absolute',
|
|
35837
|
-
top: 0,
|
|
35838
|
-
bottom: 0,
|
|
35839
|
-
left: 0,
|
|
35840
|
-
backgroundColor: resolvedColor,
|
|
35841
|
-
borderRadius: radius,
|
|
35842
|
-
}, barStyle] }), jsxRuntime.jsx(Animated.View, { style: [{
|
|
35843
|
-
position: 'absolute',
|
|
35844
|
-
top: 0,
|
|
35845
|
-
bottom: 0,
|
|
35846
|
-
right: 0,
|
|
35847
|
-
width: 80,
|
|
35848
|
-
backgroundColor: 'rgba(255,255,255,0.2)'
|
|
35849
|
-
}, barStyle] })] }));
|
|
35850
|
-
};
|
|
35851
|
-
|
|
35852
35305
|
const DEFAULT_OPACITY = 0.6;
|
|
35853
35306
|
const HEX_COLOR_REGEX = /^#?[0-9a-f]{3,8}$/i;
|
|
35854
35307
|
const clampOpacity = (value) => {
|
|
@@ -36041,270 +35494,6 @@ const LoadingOverlay = React.forwardRef((props, ref) => {
|
|
|
36041
35494
|
});
|
|
36042
35495
|
LoadingOverlay.displayName = 'LoadingOverlay';
|
|
36043
35496
|
|
|
36044
|
-
// A lightweight hover-activated floating panel similar to Mantine HoverCard
|
|
36045
|
-
function HoverCardBase(props, ref) {
|
|
36046
|
-
const { children, target, position = 'top', offset = 8, openDelay = 100, closeDelay = 150, opened: controlledOpened, shadow = 'md', radius = 'md', withinPortal = true, width, withArrow = false, closeOnEscape = true, onOpen, onClose, disabled = false, style, testID, zIndex = 3000, keepMounted = false, trigger = 'hover', } = props;
|
|
36047
|
-
const [opened, setOpened] = React.useState(false);
|
|
36048
|
-
const openTimeout = React.useRef(null);
|
|
36049
|
-
const closeTimeout = React.useRef(null);
|
|
36050
|
-
const containerRef = React.useRef(null);
|
|
36051
|
-
const targetRef = React.useRef(null);
|
|
36052
|
-
const overlayIdRef = React.useRef(null);
|
|
36053
|
-
const overlayContentRef = React.useRef(null);
|
|
36054
|
-
const isHoveringTargetRef = React.useRef(false);
|
|
36055
|
-
const isHoveringOverlayRef = React.useRef(false);
|
|
36056
|
-
const theme = useTheme();
|
|
36057
|
-
const { openOverlay, closeOverlay, updateOverlay } = useOverlay();
|
|
36058
|
-
const isOpened = controlledOpened !== undefined ? controlledOpened : opened;
|
|
36059
|
-
const clearTimers = () => {
|
|
36060
|
-
if (openTimeout.current) {
|
|
36061
|
-
clearTimeout(openTimeout.current);
|
|
36062
|
-
openTimeout.current = null;
|
|
36063
|
-
}
|
|
36064
|
-
if (closeTimeout.current) {
|
|
36065
|
-
clearTimeout(closeTimeout.current);
|
|
36066
|
-
closeTimeout.current = null;
|
|
36067
|
-
}
|
|
36068
|
-
};
|
|
36069
|
-
const doOpen = React.useCallback(() => {
|
|
36070
|
-
if (disabled)
|
|
36071
|
-
return;
|
|
36072
|
-
setOpened(true);
|
|
36073
|
-
onOpen === null || onOpen === void 0 ? void 0 : onOpen();
|
|
36074
|
-
}, [disabled, onOpen]);
|
|
36075
|
-
const doClose = React.useCallback(() => {
|
|
36076
|
-
setOpened(false);
|
|
36077
|
-
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
36078
|
-
}, [onClose]);
|
|
36079
|
-
const scheduleOpen = React.useCallback(() => {
|
|
36080
|
-
clearTimers();
|
|
36081
|
-
openTimeout.current = setTimeout(doOpen, openDelay);
|
|
36082
|
-
}, [doOpen, openDelay]);
|
|
36083
|
-
const scheduleClose = React.useCallback(() => {
|
|
36084
|
-
clearTimers();
|
|
36085
|
-
closeTimeout.current = setTimeout(() => {
|
|
36086
|
-
// Only close if neither target nor overlay are hovered (web)
|
|
36087
|
-
if (reactNative.Platform.OS === 'web') {
|
|
36088
|
-
if (isHoveringTargetRef.current || isHoveringOverlayRef.current)
|
|
36089
|
-
return;
|
|
36090
|
-
}
|
|
36091
|
-
doClose();
|
|
36092
|
-
}, closeDelay);
|
|
36093
|
-
}, [doClose, closeDelay]);
|
|
36094
|
-
React.useEffect(() => () => clearTimers(), []);
|
|
36095
|
-
// Escape key (web only)
|
|
36096
|
-
React.useEffect(() => {
|
|
36097
|
-
if (!closeOnEscape || reactNative.Platform.OS !== 'web')
|
|
36098
|
-
return;
|
|
36099
|
-
const handler = (e) => { if (e.key === 'Escape')
|
|
36100
|
-
doClose(); };
|
|
36101
|
-
document.addEventListener('keydown', handler);
|
|
36102
|
-
return () => document.removeEventListener('keydown', handler);
|
|
36103
|
-
}, [closeOnEscape, doClose]);
|
|
36104
|
-
const getInlinePositionStyle = () => {
|
|
36105
|
-
const base = { position: 'absolute' };
|
|
36106
|
-
switch (position) {
|
|
36107
|
-
case 'top': return { ...base, bottom: '100%', left: 0, marginBottom: offset };
|
|
36108
|
-
case 'bottom': return { ...base, top: '100%', left: 0, marginTop: offset };
|
|
36109
|
-
case 'left': return { ...base, right: '100%', top: 0, marginRight: offset };
|
|
36110
|
-
case 'right': return { ...base, left: '100%', top: 0, marginLeft: offset };
|
|
36111
|
-
default: return { ...base, top: '100%', left: 0, marginTop: offset };
|
|
36112
|
-
}
|
|
36113
|
-
};
|
|
36114
|
-
const shadowStyle = (() => {
|
|
36115
|
-
switch (shadow) {
|
|
36116
|
-
case 'sm':
|
|
36117
|
-
return { boxShadow: '0 1px 2px rgba(0, 0, 0, 0.1)', elevation: 2 };
|
|
36118
|
-
case 'md':
|
|
36119
|
-
return { boxShadow: '0 2px 4px rgba(0, 0, 0, 0.15)', elevation: 4 };
|
|
36120
|
-
case 'lg':
|
|
36121
|
-
return { boxShadow: '0 4px 8px rgba(0, 0, 0, 0.2)', elevation: 8 };
|
|
36122
|
-
default:
|
|
36123
|
-
return {};
|
|
36124
|
-
}
|
|
36125
|
-
})();
|
|
36126
|
-
const renderArrow = (placement) => {
|
|
36127
|
-
if (!withArrow)
|
|
36128
|
-
return null;
|
|
36129
|
-
const base = { position: 'absolute', width: 0, height: 0 };
|
|
36130
|
-
const color = theme.colors.gray[0];
|
|
36131
|
-
const styles = {
|
|
36132
|
-
top: { top: '100%', left: 12, borderLeftWidth: 6, borderRightWidth: 6, borderTopWidth: 6, borderLeftColor: 'transparent', borderRightColor: 'transparent', borderTopColor: color },
|
|
36133
|
-
bottom: { bottom: '100%', left: 12, borderLeftWidth: 6, borderRightWidth: 6, borderBottomWidth: 6, borderLeftColor: 'transparent', borderRightColor: 'transparent', borderBottomColor: color },
|
|
36134
|
-
left: { left: '100%', top: 12, borderTopWidth: 6, borderBottomWidth: 6, borderLeftWidth: 6, borderTopColor: 'transparent', borderBottomColor: 'transparent', borderLeftColor: color },
|
|
36135
|
-
right: { right: '100%', top: 12, borderTopWidth: 6, borderBottomWidth: 6, borderRightWidth: 6, borderTopColor: 'transparent', borderBottomColor: 'transparent', borderRightColor: color },
|
|
36136
|
-
};
|
|
36137
|
-
const key = placement.split('-')[0];
|
|
36138
|
-
return jsxRuntime.jsx(reactNative.View, { style: { ...base, ...(styles[key] || styles.top) } });
|
|
36139
|
-
};
|
|
36140
|
-
const openPortal = React.useCallback(async () => {
|
|
36141
|
-
if (!withinPortal || !isOpened || overlayIdRef.current)
|
|
36142
|
-
return;
|
|
36143
|
-
const rect = await measureElement(targetRef);
|
|
36144
|
-
const estWidth = width || 240;
|
|
36145
|
-
const estHeight = 160; // rough initial height
|
|
36146
|
-
const pos = calculateOverlayPositionEnhanced(rect, { width: estWidth, height: estHeight }, {
|
|
36147
|
-
placement: position,
|
|
36148
|
-
offset,
|
|
36149
|
-
viewport: getViewport(),
|
|
36150
|
-
strategy: 'fixed'
|
|
36151
|
-
});
|
|
36152
|
-
const overlayContent = (jsxRuntime.jsxs(reactNative.View, { ref: overlayContentRef, style: [
|
|
36153
|
-
{
|
|
36154
|
-
backgroundColor: theme.colors.gray[0],
|
|
36155
|
-
borderRadius: getRadius$2(radius),
|
|
36156
|
-
paddingHorizontal: getSpacing('md'),
|
|
36157
|
-
paddingVertical: getSpacing('sm'),
|
|
36158
|
-
borderWidth: 1,
|
|
36159
|
-
borderColor: theme.colors.gray[3],
|
|
36160
|
-
minWidth: width || 160,
|
|
36161
|
-
maxWidth: width || 320,
|
|
36162
|
-
},
|
|
36163
|
-
shadowStyle,
|
|
36164
|
-
], ...(reactNative.Platform.OS === 'web' && trigger === 'hover' ? {
|
|
36165
|
-
onMouseEnter: () => { isHoveringOverlayRef.current = true; clearTimers(); },
|
|
36166
|
-
onMouseLeave: () => { isHoveringOverlayRef.current = false; scheduleClose(); },
|
|
36167
|
-
} : {}), children: [children, renderArrow(pos.placement)] }));
|
|
36168
|
-
const id = openOverlay({
|
|
36169
|
-
content: overlayContent,
|
|
36170
|
-
anchor: { x: pos.x, y: pos.y, width: estWidth, height: estHeight },
|
|
36171
|
-
trigger: trigger,
|
|
36172
|
-
// For hover-triggered overlays, do NOT render a click-outside backdrop – it steals hover
|
|
36173
|
-
// and immediately fires target onMouseLeave. We rely on pointer leave timers instead.
|
|
36174
|
-
closeOnClickOutside: trigger !== 'hover',
|
|
36175
|
-
closeOnEscape: closeOnEscape,
|
|
36176
|
-
strategy: 'fixed',
|
|
36177
|
-
onClose: () => { overlayIdRef.current = null; if (opened)
|
|
36178
|
-
setOpened(false); onClose === null || onClose === void 0 ? void 0 : onClose(); },
|
|
36179
|
-
zIndex
|
|
36180
|
-
});
|
|
36181
|
-
overlayIdRef.current = id;
|
|
36182
|
-
}, [withinPortal, isOpened, overlayIdRef, position, offset, width, trigger, closeOnEscape, theme, radius, shadowStyle, children, opened, onClose, getSpacing, getRadius$2]);
|
|
36183
|
-
const closePortal = React.useCallback(() => {
|
|
36184
|
-
if (overlayIdRef.current) {
|
|
36185
|
-
closeOverlay(overlayIdRef.current);
|
|
36186
|
-
overlayIdRef.current = null;
|
|
36187
|
-
}
|
|
36188
|
-
}, [closeOverlay]);
|
|
36189
|
-
React.useEffect(() => {
|
|
36190
|
-
if (withinPortal) {
|
|
36191
|
-
if (isOpened)
|
|
36192
|
-
openPortal();
|
|
36193
|
-
else
|
|
36194
|
-
closePortal();
|
|
36195
|
-
}
|
|
36196
|
-
return () => { if (!isOpened)
|
|
36197
|
-
closePortal(); };
|
|
36198
|
-
}, [isOpened, withinPortal, openPortal, closePortal]);
|
|
36199
|
-
React.useEffect(() => {
|
|
36200
|
-
if (!withinPortal || reactNative.Platform.OS !== 'web' || !isOpened || !overlayIdRef.current)
|
|
36201
|
-
return;
|
|
36202
|
-
const handler = () => {
|
|
36203
|
-
Promise.all([measureElement(targetRef)]).then(([rect]) => {
|
|
36204
|
-
var _a, _b;
|
|
36205
|
-
const actualWidth = ((_a = overlayContentRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || width || 240;
|
|
36206
|
-
const actualHeight = ((_b = overlayContentRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 160;
|
|
36207
|
-
const pos = calculateOverlayPositionEnhanced(rect, { width: actualWidth, height: actualHeight }, {
|
|
36208
|
-
placement: position,
|
|
36209
|
-
offset,
|
|
36210
|
-
viewport: getViewport(),
|
|
36211
|
-
strategy: 'fixed'
|
|
36212
|
-
});
|
|
36213
|
-
updateOverlay(overlayIdRef.current, { anchor: { x: pos.x, y: pos.y, width: actualWidth, height: actualHeight } });
|
|
36214
|
-
});
|
|
36215
|
-
};
|
|
36216
|
-
window.addEventListener('resize', handler);
|
|
36217
|
-
window.addEventListener('scroll', handler, true);
|
|
36218
|
-
return () => {
|
|
36219
|
-
window.removeEventListener('resize', handler);
|
|
36220
|
-
window.removeEventListener('scroll', handler, true);
|
|
36221
|
-
};
|
|
36222
|
-
}, [withinPortal, isOpened, position, offset, width, updateOverlay]);
|
|
36223
|
-
// Smart sizing: after content mounts, measure actual size and reposition if changed
|
|
36224
|
-
React.useEffect(() => {
|
|
36225
|
-
if (!withinPortal || !isOpened || !overlayIdRef.current)
|
|
36226
|
-
return;
|
|
36227
|
-
let frame;
|
|
36228
|
-
const attempt = () => {
|
|
36229
|
-
Promise.all([
|
|
36230
|
-
measureElement(targetRef),
|
|
36231
|
-
measureElement({ current: overlayContentRef.current })
|
|
36232
|
-
]).then(([targetRect, contentRect]) => {
|
|
36233
|
-
if (!targetRect.width || !contentRect.width)
|
|
36234
|
-
return; // skip invalid
|
|
36235
|
-
const desiredWidth = width || contentRect.width;
|
|
36236
|
-
const desiredHeight = contentRect.height;
|
|
36237
|
-
// Recalculate with actual content size
|
|
36238
|
-
const pos = calculateOverlayPositionEnhanced(targetRect, { width: desiredWidth, height: desiredHeight }, {
|
|
36239
|
-
placement: position,
|
|
36240
|
-
offset,
|
|
36241
|
-
viewport: getViewport(),
|
|
36242
|
-
strategy: 'fixed'
|
|
36243
|
-
});
|
|
36244
|
-
updateOverlay(overlayIdRef.current, { anchor: { x: pos.x, y: pos.y, width: desiredWidth, height: desiredHeight } });
|
|
36245
|
-
});
|
|
36246
|
-
};
|
|
36247
|
-
// Delay a bit to allow layout
|
|
36248
|
-
frame = setTimeout(attempt, 30);
|
|
36249
|
-
return () => { if (frame)
|
|
36250
|
-
clearTimeout(frame); };
|
|
36251
|
-
}, [withinPortal, isOpened, position, offset, width, updateOverlay]);
|
|
36252
|
-
const targetProps = {};
|
|
36253
|
-
if (trigger === 'hover') {
|
|
36254
|
-
if (reactNative.Platform.OS === 'web') {
|
|
36255
|
-
targetProps.onMouseEnter = () => { isHoveringTargetRef.current = true; scheduleOpen(); };
|
|
36256
|
-
targetProps.onMouseLeave = () => { isHoveringTargetRef.current = false; scheduleClose(); };
|
|
36257
|
-
}
|
|
36258
|
-
else {
|
|
36259
|
-
// fallback: tap to toggle on native
|
|
36260
|
-
targetProps.onPress = () => {
|
|
36261
|
-
if (isOpened) {
|
|
36262
|
-
doClose();
|
|
36263
|
-
}
|
|
36264
|
-
else {
|
|
36265
|
-
doOpen();
|
|
36266
|
-
}
|
|
36267
|
-
};
|
|
36268
|
-
}
|
|
36269
|
-
}
|
|
36270
|
-
else if (trigger === 'click') {
|
|
36271
|
-
targetProps.onPress = () => {
|
|
36272
|
-
if (isOpened) {
|
|
36273
|
-
doClose();
|
|
36274
|
-
}
|
|
36275
|
-
else {
|
|
36276
|
-
doOpen();
|
|
36277
|
-
}
|
|
36278
|
-
};
|
|
36279
|
-
}
|
|
36280
|
-
const inlineContent = (isOpened || keepMounted) && !withinPortal ? (jsxRuntime.jsxs(reactNative.View, { style: [
|
|
36281
|
-
getInlinePositionStyle(),
|
|
36282
|
-
{
|
|
36283
|
-
backgroundColor: theme.colors.gray[0],
|
|
36284
|
-
borderRadius: getRadius$2(radius),
|
|
36285
|
-
paddingHorizontal: getSpacing('md'),
|
|
36286
|
-
paddingVertical: getSpacing('sm'),
|
|
36287
|
-
borderWidth: 1,
|
|
36288
|
-
borderColor: theme.colors.gray[3],
|
|
36289
|
-
minWidth: width,
|
|
36290
|
-
zIndex,
|
|
36291
|
-
},
|
|
36292
|
-
shadowStyle,
|
|
36293
|
-
], pointerEvents: "auto", ...(reactNative.Platform.OS === 'web' && trigger === 'hover' ? {
|
|
36294
|
-
onMouseEnter: () => { isHoveringOverlayRef.current = true; clearTimers(); },
|
|
36295
|
-
onMouseLeave: () => { isHoveringOverlayRef.current = false; scheduleClose(); },
|
|
36296
|
-
} : {}), children: [children, renderArrow(position)] })) : null;
|
|
36297
|
-
return (jsxRuntime.jsxs(reactNative.View, { ref: ref, style: [{ position: 'relative', alignSelf: 'flex-start' }, style], testID: testID, children: [jsxRuntime.jsx(reactNative.Pressable, { ref: (node) => { containerRef.current = node; targetRef.current = node; }, ...targetProps, style: ({ pressed }) => {
|
|
36298
|
-
var _a;
|
|
36299
|
-
return [
|
|
36300
|
-
{ opacity: pressed ? 0.85 : 1 },
|
|
36301
|
-
(_a = target === null || target === void 0 ? void 0 : target.props) === null || _a === void 0 ? void 0 : _a.style,
|
|
36302
|
-
];
|
|
36303
|
-
}, children: target }), inlineContent] }));
|
|
36304
|
-
}
|
|
36305
|
-
const HoverCard = factory(HoverCardBase);
|
|
36306
|
-
HoverCard.displayName = 'HoverCard';
|
|
36307
|
-
|
|
36308
35497
|
const ContextMenu = ({ children, items, closeOnSelect = true, longPressDelay = 350, maxHeight = 280, onOpen, onClose, open: controlledOpen, position: controlledPosition, portalId, style, }) => {
|
|
36309
35498
|
var _a, _b;
|
|
36310
35499
|
const [internalOpen, setInternalOpen] = React.useState(false);
|
|
@@ -39894,11 +39083,14 @@ QRCodeSVG.displayName = 'QRCodeSVG';
|
|
|
39894
39083
|
*/
|
|
39895
39084
|
function QRCode(props) {
|
|
39896
39085
|
var _a;
|
|
39086
|
+
const theme = useTheme();
|
|
39897
39087
|
const { spacingProps, otherProps: propsAfterSpacing } = extractSpacingProps(props);
|
|
39898
39088
|
const { layoutProps, otherProps } = extractLayoutProps(propsAfterSpacing);
|
|
39899
|
-
const { value, size = 400, backgroundColor = 'transparent', color
|
|
39089
|
+
const { value, size = 400, backgroundColor = 'transparent', color, errorCorrectionLevel = 'M', quietZone = 4, logo, style, testID, accessibilityLabel, onError, onLoadStart, // deprecated noop
|
|
39900
39090
|
onLoadEnd, // deprecated noop
|
|
39901
39091
|
...rest } = otherProps;
|
|
39092
|
+
// Default color to theme's primary text color for dark mode support
|
|
39093
|
+
const resolvedColor = color !== null && color !== void 0 ? color : theme.text.primary;
|
|
39902
39094
|
const { copy } = useClipboard();
|
|
39903
39095
|
const toast = useToast();
|
|
39904
39096
|
const shouldCopyOnPress = !!otherProps.copyOnPress;
|
|
@@ -39914,7 +39106,7 @@ function QRCode(props) {
|
|
|
39914
39106
|
});
|
|
39915
39107
|
}
|
|
39916
39108
|
}, [copy, copyValue, toast, otherProps.copyToastMessage, otherProps.copyToastTitle]);
|
|
39917
|
-
const content = (jsxRuntime.jsxs(reactNative.View, { style: { borderRadius: 8, overflow: 'hidden' }, children: [jsxRuntime.jsx(QRCodeSVG, { value: value, size: size, maxWidth: '100%', backgroundColor: backgroundColor, color:
|
|
39109
|
+
const content = (jsxRuntime.jsxs(reactNative.View, { style: { borderRadius: 8, overflow: 'hidden' }, children: [jsxRuntime.jsx(QRCodeSVG, { value: value, size: size, maxWidth: '100%', backgroundColor: backgroundColor, color: resolvedColor, errorCorrectionLevel: errorCorrectionLevel, quietZone: quietZone, logo: logo, style: style, testID: testID, accessibilityLabel: accessibilityLabel, onError: onError, ...spacingProps, ...layoutProps, ...rest }), otherProps.showCopyButton && (jsxRuntime.jsx(CopyButton, { value: copyValue, iconOnly: true, size: "sm", style: { position: 'absolute', top: 8, right: 8 }, onCopy: () => { } }))] }));
|
|
39918
39110
|
if (shouldCopyOnPress) {
|
|
39919
39111
|
return (jsxRuntime.jsx(reactNative.Pressable, { onPress: handleCopy, accessibilityLabel: accessibilityLabel || 'QR code', children: content }));
|
|
39920
39112
|
}
|
|
@@ -41987,7 +41179,6 @@ function withPressAnimation(Component, animationProps) {
|
|
|
41987
41179
|
*/
|
|
41988
41180
|
const AnimatedPressable = PressAnimation;
|
|
41989
41181
|
|
|
41990
|
-
exports.AbilityCore = AbilityCore;
|
|
41991
41182
|
exports.AccessibilityProvider = AccessibilityProvider;
|
|
41992
41183
|
exports.Accordion = Accordion;
|
|
41993
41184
|
exports.AmazonAppstoreBadge = AmazonAppstoreBadge;
|
|
@@ -42027,9 +41218,6 @@ exports.Button = Button;
|
|
|
42027
41218
|
exports.COMPONENT_SIZES = COMPONENT_SIZES$1;
|
|
42028
41219
|
exports.COMPONENT_SIZE_ORDER = COMPONENT_SIZE_ORDER;
|
|
42029
41220
|
exports.Calendar = Calendar;
|
|
42030
|
-
exports.Can = Can;
|
|
42031
|
-
exports.CanWithConditions = CanWithConditions;
|
|
42032
|
-
exports.Cannot = Cannot;
|
|
42033
41221
|
exports.Card = Card;
|
|
42034
41222
|
exports.Carousel = Carousel;
|
|
42035
41223
|
exports.Checkbox = Checkbox;
|
|
@@ -42090,7 +41278,6 @@ exports.Heading4 = Heading4;
|
|
|
42090
41278
|
exports.Heading5 = Heading5;
|
|
42091
41279
|
exports.Heading6 = Heading6;
|
|
42092
41280
|
exports.Highlight = Highlight;
|
|
42093
|
-
exports.HoverCard = HoverCard;
|
|
42094
41281
|
exports.HuaweiAppGalleryBadge = HuaweiAppGalleryBadge;
|
|
42095
41282
|
exports.I18nProvider = I18nProvider;
|
|
42096
41283
|
exports.Icon = Icon;
|
|
@@ -42128,7 +41315,6 @@ exports.MiniCalendar = MiniCalendar;
|
|
|
42128
41315
|
exports.Month = Month;
|
|
42129
41316
|
exports.MonthPicker = MonthPicker;
|
|
42130
41317
|
exports.MonthPickerInput = MonthPickerInput;
|
|
42131
|
-
exports.NavigationProgress = NavigationProgress;
|
|
42132
41318
|
exports.Notice = Notice;
|
|
42133
41319
|
exports.NumberInput = NumberInput;
|
|
42134
41320
|
exports.Overlay = Overlay;
|
|
@@ -42136,10 +41322,6 @@ exports.OverlayProvider = OverlayProvider;
|
|
|
42136
41322
|
exports.P = P;
|
|
42137
41323
|
exports.Pagination = Pagination;
|
|
42138
41324
|
exports.PasswordInput = PasswordInput;
|
|
42139
|
-
exports.PermissionBuilder = PermissionBuilder;
|
|
42140
|
-
exports.PermissionGate = PermissionGate;
|
|
42141
|
-
exports.PermissionPatterns = PermissionPatterns;
|
|
42142
|
-
exports.PermissionProvider = PermissionProvider;
|
|
42143
41325
|
exports.PhoneInput = PhoneInput;
|
|
42144
41326
|
exports.PinInput = PinInput;
|
|
42145
41327
|
exports.PlatformBlocksProvider = PlatformBlocksProvider;
|
|
@@ -42154,7 +41336,6 @@ exports.Rating = Rating;
|
|
|
42154
41336
|
exports.RedditJoinBadge = RedditJoinBadge;
|
|
42155
41337
|
exports.RichTextEditor = RichTextEditor;
|
|
42156
41338
|
exports.Ring = Ring;
|
|
42157
|
-
exports.RoleBuilder = RoleBuilder;
|
|
42158
41339
|
exports.Row = Row;
|
|
42159
41340
|
exports.SIZE_SCALES = SIZE_SCALES;
|
|
42160
41341
|
exports.Search = Search;
|
|
@@ -42212,9 +41393,7 @@ exports.createSound = createSound;
|
|
|
42212
41393
|
exports.createSpotlightStore = createSpotlightStore;
|
|
42213
41394
|
exports.createTheme = createTheme;
|
|
42214
41395
|
exports.debounce = debounce$1;
|
|
42215
|
-
exports.defineAbility = defineAbility;
|
|
42216
41396
|
exports.defineAppLayout = defineAppLayout;
|
|
42217
|
-
exports.defineRoleAbility = defineRoleAbility;
|
|
42218
41397
|
exports.directSpotlight = directSpotlight;
|
|
42219
41398
|
exports.extractDisclaimerProps = extractDisclaimerProps;
|
|
42220
41399
|
exports.factory = factory;
|
|
@@ -42235,11 +41414,9 @@ exports.globalHotkeys = globalHotkeys;
|
|
|
42235
41414
|
exports.measureAsyncPerformance = measureAsyncPerformance;
|
|
42236
41415
|
exports.measureElement = measureElement;
|
|
42237
41416
|
exports.measurePerformance = measurePerformance;
|
|
42238
|
-
exports.navigationProgress = navigationProgress;
|
|
42239
41417
|
exports.onDialogsRequested = onDialogsRequested;
|
|
42240
41418
|
exports.onSpotlightRequested = onSpotlightRequested;
|
|
42241
41419
|
exports.onToastsRequested = onToastsRequested;
|
|
42242
|
-
exports.permissions = permissions;
|
|
42243
41420
|
exports.pointInRect = pointInRect;
|
|
42244
41421
|
exports.polymorphicFactory = polymorphicFactory;
|
|
42245
41422
|
exports.px = px;
|
|
@@ -42250,7 +41427,6 @@ exports.resolveResponsiveValue = resolveResponsiveValue;
|
|
|
42250
41427
|
exports.resolveSize = resolveSize;
|
|
42251
41428
|
exports.spotlight = spotlight;
|
|
42252
41429
|
exports.throttle = throttle;
|
|
42253
|
-
exports.useAbility = useAbility;
|
|
42254
41430
|
exports.useAccessibility = useAccessibility;
|
|
42255
41431
|
exports.useAppLayoutContext = useAppLayoutContext;
|
|
42256
41432
|
exports.useAppShell = useAppShell;
|
|
@@ -42280,7 +41456,6 @@ exports.useOptionalFormContext = useOptionalFormContext;
|
|
|
42280
41456
|
exports.useOverlay = useOverlay;
|
|
42281
41457
|
exports.useOverlayApi = useOverlayApi;
|
|
42282
41458
|
exports.useOverlays = useOverlays;
|
|
42283
|
-
exports.usePermissions = usePermissions;
|
|
42284
41459
|
exports.usePopoverPositioning = usePopoverPositioning;
|
|
42285
41460
|
exports.useSimpleDialog = useSimpleDialog;
|
|
42286
41461
|
exports.useSound = useSound;
|
|
@@ -42295,8 +41470,6 @@ exports.useToast = useToast;
|
|
|
42295
41470
|
exports.useToastApi = useToastApi;
|
|
42296
41471
|
exports.useToggleColorScheme = useToggleColorScheme;
|
|
42297
41472
|
exports.useTooltipPositioning = useTooltipPositioning;
|
|
42298
|
-
exports.withCan = withCan;
|
|
42299
|
-
exports.withCannot = withCannot;
|
|
42300
41473
|
exports.withDisclaimer = withDisclaimer;
|
|
42301
41474
|
exports.withPressAnimation = withPressAnimation;
|
|
42302
41475
|
//# sourceMappingURL=index.js.map
|