@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/esm/index.js
CHANGED
|
@@ -1164,25 +1164,50 @@ function OverlayRenderer({ style } = {}) {
|
|
|
1164
1164
|
}) }));
|
|
1165
1165
|
}
|
|
1166
1166
|
function OverlayContent({ overlay, isTopmost, onBackdropPress }) {
|
|
1167
|
-
var _a, _b, _c;
|
|
1167
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1168
1168
|
useTheme();
|
|
1169
1169
|
const DEBUG = overlay.debug === true;
|
|
1170
1170
|
if (DEBUG) {
|
|
1171
1171
|
console.log('Rendering overlay content:');
|
|
1172
1172
|
console.log('- anchor:', overlay.anchor);
|
|
1173
|
+
console.log('- placement:', overlay.placement);
|
|
1173
1174
|
console.log('- strategy:', overlay.strategy);
|
|
1174
1175
|
console.log('- zIndex:', overlay.zIndex);
|
|
1175
1176
|
}
|
|
1177
|
+
// Check if this is a top-positioned overlay
|
|
1178
|
+
const isTopPlacement = (_a = overlay.placement) === null || _a === void 0 ? void 0 : _a.startsWith('top');
|
|
1179
|
+
// For top placements, we need to anchor from the bottom of the overlay
|
|
1180
|
+
// The anchor.y represents where the bottom of the overlay should be (top of the trigger minus offset)
|
|
1181
|
+
// So we use the estimated height to calculate where the top of the overlay would be
|
|
1176
1182
|
const overlayStyle = {
|
|
1177
1183
|
// Use fixed positioning on web for viewport-anchored overlays
|
|
1178
1184
|
position: (Platform.OS === 'web' && overlay.strategy === 'fixed') ? 'fixed' : 'absolute',
|
|
1179
|
-
top: ((_a = overlay.anchor) === null || _a === void 0 ? void 0 : _a.y) || 0,
|
|
1180
1185
|
left: ((_b = overlay.anchor) === null || _b === void 0 ? void 0 : _b.x) || 0,
|
|
1181
1186
|
zIndex: overlay.zIndex,
|
|
1182
1187
|
width: overlay.width || (((_c = overlay.anchor) === null || _c === void 0 ? void 0 : _c.width) ? overlay.anchor.width : undefined),
|
|
1183
1188
|
maxWidth: overlay.maxWidth,
|
|
1184
1189
|
maxHeight: overlay.maxHeight,
|
|
1185
1190
|
};
|
|
1191
|
+
if (isTopPlacement && Platform.OS === 'web') {
|
|
1192
|
+
// For top placements, position from the bottom of the overlay
|
|
1193
|
+
// anchor.y is where the top of the overlay should be, but we want to anchor from the bottom
|
|
1194
|
+
// so the overlay can grow upward naturally
|
|
1195
|
+
// The "bottom" of the anchor point is: viewport.height - (anchor.y + estimatedHeight)
|
|
1196
|
+
// But since we don't know actual height, use bottom anchoring relative to the trigger
|
|
1197
|
+
// Actually, anchor.y already accounts for the estimated height, so:
|
|
1198
|
+
// anchor.y = trigger.y - estimatedHeight - offset
|
|
1199
|
+
// We want the overlay's bottom edge to be at: trigger.y - offset
|
|
1200
|
+
// Which means: bottom = viewport.height - (trigger.y - offset) = viewport.height - anchor.y - estimatedHeight
|
|
1201
|
+
// Simpler: just set top and let it render, but the issue is the estimate is wrong
|
|
1202
|
+
// Better approach: use the anchor.y + anchor.height as the "bottom anchor point"
|
|
1203
|
+
// This is where the bottom of the overlay should be
|
|
1204
|
+
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);
|
|
1205
|
+
overlayStyle.top = undefined;
|
|
1206
|
+
overlayStyle.bottom = `calc(100vh - ${bottomAnchorPoint}px)`;
|
|
1207
|
+
}
|
|
1208
|
+
else {
|
|
1209
|
+
overlayStyle.top = ((_f = overlay.anchor) === null || _f === void 0 ? void 0 : _f.y) || 0;
|
|
1210
|
+
}
|
|
1186
1211
|
if (DEBUG) {
|
|
1187
1212
|
console.log('- overlayStyle:', overlayStyle);
|
|
1188
1213
|
}
|
|
@@ -6153,31 +6178,29 @@ const Button = (allProps) => {
|
|
|
6153
6178
|
const { getDuration } = useReducedMotion$1();
|
|
6154
6179
|
const { announce } = useAnnouncer();
|
|
6155
6180
|
const { ref: focusRef} = useFocus(`button-${title || 'button'}`);
|
|
6181
|
+
// Track measured width for loading state preservation
|
|
6182
|
+
const [measuredWidth, setMeasuredWidth] = useState(null);
|
|
6183
|
+
const wasLoadingRef = useRef(loading);
|
|
6184
|
+
// When loading starts, we want to preserve the current measured width
|
|
6185
|
+
// When loading ends, clear the preserved width so it can resize naturally
|
|
6186
|
+
useEffect(() => {
|
|
6187
|
+
if (!loading && wasLoadingRef.current) {
|
|
6188
|
+
// Loading just ended, allow width to be recalculated
|
|
6189
|
+
setMeasuredWidth(null);
|
|
6190
|
+
}
|
|
6191
|
+
wasLoadingRef.current = loading;
|
|
6192
|
+
}, [loading]);
|
|
6193
|
+
const handleLayout = useCallback((event) => {
|
|
6194
|
+
// Only update measured width when not loading, so we capture the natural content width
|
|
6195
|
+
if (!loading) {
|
|
6196
|
+
const { width } = event.nativeEvent.layout;
|
|
6197
|
+
setMeasuredWidth(width);
|
|
6198
|
+
}
|
|
6199
|
+
// Call user's onLayout if provided
|
|
6200
|
+
onLayout === null || onLayout === void 0 ? void 0 : onLayout(event);
|
|
6201
|
+
}, [loading, onLayout]);
|
|
6156
6202
|
// Determine button content - children takes precedence over title
|
|
6157
6203
|
const buttonContent = children !== null && children !== void 0 ? children : title;
|
|
6158
|
-
// Calculate minimum width for loading state based on content and size
|
|
6159
|
-
const calculateMinWidth = () => {
|
|
6160
|
-
if (!buttonContent || typeof buttonContent !== 'string')
|
|
6161
|
-
return undefined;
|
|
6162
|
-
// Base character width estimates based on size
|
|
6163
|
-
const charWidthBySize = {
|
|
6164
|
-
xs: 6,
|
|
6165
|
-
sm: 7,
|
|
6166
|
-
md: 8,
|
|
6167
|
-
lg: 9,
|
|
6168
|
-
xl: 10,
|
|
6169
|
-
'2xl': 11,
|
|
6170
|
-
'3xl': 12
|
|
6171
|
-
};
|
|
6172
|
-
const sizeKey = typeof size === 'string' ? size : 'md';
|
|
6173
|
-
const charWidth = charWidthBySize[sizeKey] || 8;
|
|
6174
|
-
const horizontalPadding = getSpacing(size) * 2; // Left + right padding
|
|
6175
|
-
// Estimate content width: character count * average char width + padding
|
|
6176
|
-
const contentWidth = buttonContent.length * charWidth + horizontalPadding;
|
|
6177
|
-
// Add space for loader and gap when loading
|
|
6178
|
-
const loaderWidth = getFontSize$1(size) + getSpacing(size) / 2; // Loader + margin
|
|
6179
|
-
return Math.max(contentWidth, contentWidth + loaderWidth);
|
|
6180
|
-
};
|
|
6181
6204
|
// Determine what content to show based on loading state
|
|
6182
6205
|
const displayContent = loading
|
|
6183
6206
|
? (loadingTitle !== undefined ? loadingTitle : '')
|
|
@@ -6216,12 +6239,12 @@ const Button = (allProps) => {
|
|
|
6216
6239
|
const shadowStyles = getShadowStyles({ shadow: effectiveShadow }, theme, 'button');
|
|
6217
6240
|
const spacingStyles = getSpacingStyles(spacingProps);
|
|
6218
6241
|
const baseLayoutStyles = getLayoutStyles(layoutProps);
|
|
6219
|
-
// Apply
|
|
6220
|
-
|
|
6242
|
+
// Apply measured width when loading to prevent size changes
|
|
6243
|
+
// Use the actual measured width instead of character-based estimates
|
|
6221
6244
|
const layoutStyles = {
|
|
6222
6245
|
...baseLayoutStyles,
|
|
6223
|
-
...(loading &&
|
|
6224
|
-
? { minWidth:
|
|
6246
|
+
...(loading && measuredWidth && !layoutProps.width && !layoutProps.w && !layoutProps.fullWidth
|
|
6247
|
+
? { width: measuredWidth, minWidth: measuredWidth }
|
|
6225
6248
|
: {})
|
|
6226
6249
|
};
|
|
6227
6250
|
const iconSpacing = getSpacing(size) / 2;
|
|
@@ -6414,7 +6437,7 @@ const Button = (allProps) => {
|
|
|
6414
6437
|
...(Platform.OS !== 'web' ? { transform: [{ translateY: 1 }] } : {})
|
|
6415
6438
|
} : null,
|
|
6416
6439
|
style,
|
|
6417
|
-
], onPress: handleInternalPress, onLayout:
|
|
6440
|
+
], onPress: handleInternalPress, onLayout: handleLayout, onPressIn: handlePressIn, onPressOut: handlePressOut, onHoverIn: onHoverIn, onHoverOut: onHoverOut, onLongPress: onLongPress, disabled: isInteractionDisabled, children: [variant === 'gradient' && hasLinearGradient$4 && (jsx(OptionalLinearGradient$6, { colors: resolvedCustomColor
|
|
6418
6441
|
? [resolvedCustomColor, theme.colors.primary[7]]
|
|
6419
6442
|
: [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 ? (jsxs(Fragment, { children: [jsx(Loader, { size: size, color: getLoaderColor(), style: !isIconButton ? { marginRight: iconSpacing } : undefined }), !isIconButton && renderButtonContent(displayContent)] })) : isIconButton ? (
|
|
6420
6443
|
// Icon-only button
|
|
@@ -9732,593 +9755,6 @@ function UniversalCSS() {
|
|
|
9732
9755
|
return null;
|
|
9733
9756
|
}
|
|
9734
9757
|
|
|
9735
|
-
/**
|
|
9736
|
-
* Core Ability class for managing permissions
|
|
9737
|
-
*/
|
|
9738
|
-
class AbilityCore {
|
|
9739
|
-
constructor(rules = []) {
|
|
9740
|
-
this.rules = [];
|
|
9741
|
-
this.cache = new Map();
|
|
9742
|
-
this.rules = [...rules];
|
|
9743
|
-
}
|
|
9744
|
-
/**
|
|
9745
|
-
* Check if action is allowed on subject
|
|
9746
|
-
*/
|
|
9747
|
-
can(action, subject, field) {
|
|
9748
|
-
return this.check(action, subject, field).allowed;
|
|
9749
|
-
}
|
|
9750
|
-
/**
|
|
9751
|
-
* Check if action is forbidden on subject
|
|
9752
|
-
*/
|
|
9753
|
-
cannot(action, subject, field) {
|
|
9754
|
-
return !this.can(action, subject, field);
|
|
9755
|
-
}
|
|
9756
|
-
/**
|
|
9757
|
-
* Get detailed permission check result
|
|
9758
|
-
*/
|
|
9759
|
-
check(action, subject, field) {
|
|
9760
|
-
const cacheKey = this.getCacheKey(action, subject, field);
|
|
9761
|
-
if (this.cache.has(cacheKey)) {
|
|
9762
|
-
return this.cache.get(cacheKey);
|
|
9763
|
-
}
|
|
9764
|
-
const result = this.performCheck(action, subject, field);
|
|
9765
|
-
this.cache.set(cacheKey, result);
|
|
9766
|
-
return result;
|
|
9767
|
-
}
|
|
9768
|
-
/**
|
|
9769
|
-
* Update ability rules and clear cache
|
|
9770
|
-
*/
|
|
9771
|
-
update(rules) {
|
|
9772
|
-
this.rules = [...rules];
|
|
9773
|
-
this.cache.clear();
|
|
9774
|
-
}
|
|
9775
|
-
/**
|
|
9776
|
-
* Get all current rules
|
|
9777
|
-
*/
|
|
9778
|
-
getRules() {
|
|
9779
|
-
return [...this.rules];
|
|
9780
|
-
}
|
|
9781
|
-
/**
|
|
9782
|
-
* Clear all rules and cache
|
|
9783
|
-
*/
|
|
9784
|
-
clear() {
|
|
9785
|
-
this.rules = [];
|
|
9786
|
-
this.cache.clear();
|
|
9787
|
-
}
|
|
9788
|
-
/**
|
|
9789
|
-
* Perform the actual permission check
|
|
9790
|
-
*/
|
|
9791
|
-
performCheck(action, subject, field) {
|
|
9792
|
-
// Start with denied by default
|
|
9793
|
-
let result = {
|
|
9794
|
-
allowed: false,
|
|
9795
|
-
reason: 'No matching permission rule found'
|
|
9796
|
-
};
|
|
9797
|
-
// Check rules in order (later rules can override earlier ones)
|
|
9798
|
-
for (const rule of this.rules) {
|
|
9799
|
-
if (this.ruleMatches(rule, action, subject, field)) {
|
|
9800
|
-
result = {
|
|
9801
|
-
allowed: !rule.inverted,
|
|
9802
|
-
reason: rule.reason || (rule.inverted ? 'Access denied by rule' : 'Access granted by rule'),
|
|
9803
|
-
rule
|
|
9804
|
-
};
|
|
9805
|
-
}
|
|
9806
|
-
}
|
|
9807
|
-
return result;
|
|
9808
|
-
}
|
|
9809
|
-
/**
|
|
9810
|
-
* Check if a rule matches the current permission check
|
|
9811
|
-
*/
|
|
9812
|
-
ruleMatches(rule, action, subject, field) {
|
|
9813
|
-
// Check action match
|
|
9814
|
-
const actions = Array.isArray(rule.action) ? rule.action : [rule.action];
|
|
9815
|
-
if (!actions.includes(action) && !actions.includes('*')) {
|
|
9816
|
-
return false;
|
|
9817
|
-
}
|
|
9818
|
-
// Check subject match
|
|
9819
|
-
const subjects = Array.isArray(rule.subject) ? rule.subject : [rule.subject];
|
|
9820
|
-
if (!this.subjectMatches(subjects, subject)) {
|
|
9821
|
-
return false;
|
|
9822
|
-
}
|
|
9823
|
-
// Check field match (if specified)
|
|
9824
|
-
if (field && rule.fields && !rule.fields.includes(field)) {
|
|
9825
|
-
return false;
|
|
9826
|
-
}
|
|
9827
|
-
// Check conditions (if subject is an object)
|
|
9828
|
-
if (rule.conditions && typeof subject === 'object' && subject !== null) {
|
|
9829
|
-
return this.conditionsMatch(rule.conditions, subject);
|
|
9830
|
-
}
|
|
9831
|
-
return true;
|
|
9832
|
-
}
|
|
9833
|
-
/**
|
|
9834
|
-
* Check if subject matches any of the rule subjects
|
|
9835
|
-
*/
|
|
9836
|
-
subjectMatches(ruleSubjects, checkSubject) {
|
|
9837
|
-
for (const ruleSubject of ruleSubjects) {
|
|
9838
|
-
if (ruleSubject === '*')
|
|
9839
|
-
return true;
|
|
9840
|
-
if (ruleSubject === checkSubject)
|
|
9841
|
-
return true;
|
|
9842
|
-
// Handle class/constructor matching
|
|
9843
|
-
if (typeof ruleSubject === 'function' && typeof checkSubject === 'object') {
|
|
9844
|
-
if (checkSubject instanceof ruleSubject)
|
|
9845
|
-
return true;
|
|
9846
|
-
if (checkSubject.constructor === ruleSubject)
|
|
9847
|
-
return true;
|
|
9848
|
-
}
|
|
9849
|
-
// Handle string matching for object types
|
|
9850
|
-
if (typeof ruleSubject === 'string' && typeof checkSubject === 'object') {
|
|
9851
|
-
if (checkSubject.__type === ruleSubject)
|
|
9852
|
-
return true;
|
|
9853
|
-
if (checkSubject.type === ruleSubject)
|
|
9854
|
-
return true;
|
|
9855
|
-
if (checkSubject.constructor.name === ruleSubject)
|
|
9856
|
-
return true;
|
|
9857
|
-
}
|
|
9858
|
-
}
|
|
9859
|
-
return false;
|
|
9860
|
-
}
|
|
9861
|
-
/**
|
|
9862
|
-
* Check if conditions match the subject object
|
|
9863
|
-
*/
|
|
9864
|
-
conditionsMatch(conditions, subject) {
|
|
9865
|
-
for (const [key, expectedValue] of Object.entries(conditions)) {
|
|
9866
|
-
const actualValue = subject[key];
|
|
9867
|
-
if (!this.valuesMatch(actualValue, expectedValue)) {
|
|
9868
|
-
return false;
|
|
9869
|
-
}
|
|
9870
|
-
}
|
|
9871
|
-
return true;
|
|
9872
|
-
}
|
|
9873
|
-
/**
|
|
9874
|
-
* Check if two values match (handles various comparison types)
|
|
9875
|
-
*/
|
|
9876
|
-
valuesMatch(actual, expected) {
|
|
9877
|
-
// Exact match
|
|
9878
|
-
if (actual === expected)
|
|
9879
|
-
return true;
|
|
9880
|
-
// Array contains check
|
|
9881
|
-
if (Array.isArray(expected) && expected.includes(actual))
|
|
9882
|
-
return true;
|
|
9883
|
-
if (Array.isArray(actual) && actual.includes(expected))
|
|
9884
|
-
return true;
|
|
9885
|
-
// Function/predicate check
|
|
9886
|
-
if (typeof expected === 'function') {
|
|
9887
|
-
return expected(actual);
|
|
9888
|
-
}
|
|
9889
|
-
// Regex match for strings
|
|
9890
|
-
if (expected instanceof RegExp && typeof actual === 'string') {
|
|
9891
|
-
return expected.test(actual);
|
|
9892
|
-
}
|
|
9893
|
-
// Object comparison (shallow)
|
|
9894
|
-
if (typeof expected === 'object' && typeof actual === 'object' && expected !== null && actual !== null) {
|
|
9895
|
-
return Object.keys(expected).every(key => this.valuesMatch(actual[key], expected[key]));
|
|
9896
|
-
}
|
|
9897
|
-
return false;
|
|
9898
|
-
}
|
|
9899
|
-
/**
|
|
9900
|
-
* Generate cache key for permission check
|
|
9901
|
-
*/
|
|
9902
|
-
getCacheKey(action, subject, field) {
|
|
9903
|
-
const subjectKey = typeof subject === 'object'
|
|
9904
|
-
? JSON.stringify(subject)
|
|
9905
|
-
: String(subject);
|
|
9906
|
-
return `${action}:${subjectKey}:${field || ''}`;
|
|
9907
|
-
}
|
|
9908
|
-
}
|
|
9909
|
-
/**
|
|
9910
|
-
* Create a new Ability instance
|
|
9911
|
-
*/
|
|
9912
|
-
function createAbility(rules = []) {
|
|
9913
|
-
return new AbilityCore(rules);
|
|
9914
|
-
}
|
|
9915
|
-
|
|
9916
|
-
/**
|
|
9917
|
-
* Permission Context
|
|
9918
|
-
*/
|
|
9919
|
-
const PermissionContext = createContext(null);
|
|
9920
|
-
/**
|
|
9921
|
-
* Permission Provider Component
|
|
9922
|
-
*/
|
|
9923
|
-
const PermissionProvider = ({ rules = [], user, children, dev = {} }) => {
|
|
9924
|
-
const [ability] = useState(() => createAbility(rules));
|
|
9925
|
-
const [currentUser, setCurrentUser] = useState(user);
|
|
9926
|
-
const updateAbility = useCallback((newRules) => {
|
|
9927
|
-
ability.update(newRules);
|
|
9928
|
-
}, [ability]);
|
|
9929
|
-
const can = useCallback((action, subject, field) => {
|
|
9930
|
-
const result = ability.can(action, subject, field);
|
|
9931
|
-
if (dev.logChecks) {
|
|
9932
|
-
console.log(`[Permissions] Can ${action} ${subject}${field ? `.${field}` : ''}:`, result);
|
|
9933
|
-
}
|
|
9934
|
-
return result;
|
|
9935
|
-
}, [ability, dev.logChecks]);
|
|
9936
|
-
const cannot = useCallback((action, subject, field) => {
|
|
9937
|
-
const result = ability.cannot(action, subject, field);
|
|
9938
|
-
if (dev.logChecks) {
|
|
9939
|
-
console.log(`[Permissions] Cannot ${action} ${subject}${field ? `.${field}` : ''}:`, result);
|
|
9940
|
-
}
|
|
9941
|
-
return result;
|
|
9942
|
-
}, [ability, dev.logChecks]);
|
|
9943
|
-
const setUser = useCallback((newUser) => {
|
|
9944
|
-
setCurrentUser(newUser);
|
|
9945
|
-
}, []);
|
|
9946
|
-
const contextValue = useMemo(() => ({
|
|
9947
|
-
ability,
|
|
9948
|
-
updateAbility,
|
|
9949
|
-
can,
|
|
9950
|
-
cannot,
|
|
9951
|
-
user: currentUser,
|
|
9952
|
-
setUser
|
|
9953
|
-
}), [ability, updateAbility, can, cannot, currentUser, setUser]);
|
|
9954
|
-
return React__default.createElement(PermissionContext.Provider, { value: contextValue }, children);
|
|
9955
|
-
};
|
|
9956
|
-
/**
|
|
9957
|
-
* Hook to access permission context
|
|
9958
|
-
*/
|
|
9959
|
-
const usePermissions = (options = {}) => {
|
|
9960
|
-
const context = useContext(PermissionContext);
|
|
9961
|
-
if (!context) {
|
|
9962
|
-
if (options.required) {
|
|
9963
|
-
throw new Error('usePermissions must be used within a PermissionProvider');
|
|
9964
|
-
}
|
|
9965
|
-
if (options.debug) {
|
|
9966
|
-
console.warn('[Permissions] usePermissions called outside of PermissionProvider');
|
|
9967
|
-
}
|
|
9968
|
-
// Return a fallback context that allows everything
|
|
9969
|
-
return {
|
|
9970
|
-
ability: createAbility([{ action: '*', subject: '*' }]),
|
|
9971
|
-
updateAbility: () => { },
|
|
9972
|
-
can: () => true,
|
|
9973
|
-
cannot: () => false,
|
|
9974
|
-
user: null,
|
|
9975
|
-
setUser: () => { }
|
|
9976
|
-
};
|
|
9977
|
-
}
|
|
9978
|
-
return context;
|
|
9979
|
-
};
|
|
9980
|
-
/**
|
|
9981
|
-
* Hook to get the current ability instance
|
|
9982
|
-
*/
|
|
9983
|
-
const useAbility = () => {
|
|
9984
|
-
const { ability } = usePermissions();
|
|
9985
|
-
return ability;
|
|
9986
|
-
};
|
|
9987
|
-
|
|
9988
|
-
/**
|
|
9989
|
-
* Can Component - Renders children if permission is granted
|
|
9990
|
-
*/
|
|
9991
|
-
const Can = ({ I: action, a: subject, field, children, fallback = null, ability: customAbility, style, testID, passthrough = false }) => {
|
|
9992
|
-
const { ability: contextAbility } = usePermissions();
|
|
9993
|
-
const ability = customAbility || contextAbility;
|
|
9994
|
-
// Development passthrough
|
|
9995
|
-
if (passthrough && __DEV__) {
|
|
9996
|
-
return React__default.createElement(View, { style, testID }, children);
|
|
9997
|
-
}
|
|
9998
|
-
const hasPermission = subject
|
|
9999
|
-
? ability.can(action, subject, field)
|
|
10000
|
-
: ability.can(action, '*', field);
|
|
10001
|
-
if (hasPermission) {
|
|
10002
|
-
return React__default.createElement(View, { style, testID }, children);
|
|
10003
|
-
}
|
|
10004
|
-
return React__default.createElement(View, { style, testID }, fallback);
|
|
10005
|
-
};
|
|
10006
|
-
/**
|
|
10007
|
-
* Can Component with conditions - For object-level permissions
|
|
10008
|
-
*/
|
|
10009
|
-
const CanWithConditions = ({ I: action, this: subject, field, children, fallback = null, ability: customAbility, style, testID, passthrough = false }) => {
|
|
10010
|
-
const { ability: contextAbility } = usePermissions();
|
|
10011
|
-
const ability = customAbility || contextAbility;
|
|
10012
|
-
// Development passthrough
|
|
10013
|
-
if (passthrough && __DEV__) {
|
|
10014
|
-
return React__default.createElement(View, { style, testID }, children);
|
|
10015
|
-
}
|
|
10016
|
-
const hasPermission = ability.can(action, subject, field);
|
|
10017
|
-
if (hasPermission) {
|
|
10018
|
-
return React__default.createElement(View, { style, testID }, children);
|
|
10019
|
-
}
|
|
10020
|
-
return React__default.createElement(View, { style, testID }, fallback);
|
|
10021
|
-
};
|
|
10022
|
-
/**
|
|
10023
|
-
* Cannot Component - Renders children if permission is NOT granted
|
|
10024
|
-
*/
|
|
10025
|
-
const Cannot = ({ I: action, a: subject, field, children, fallback = null, ability: customAbility, style, testID, passthrough = false }) => {
|
|
10026
|
-
const { ability: contextAbility } = usePermissions();
|
|
10027
|
-
const ability = customAbility || contextAbility;
|
|
10028
|
-
// Development passthrough
|
|
10029
|
-
if (passthrough && __DEV__) {
|
|
10030
|
-
return React__default.createElement(View, { style, testID }, fallback);
|
|
10031
|
-
}
|
|
10032
|
-
const hasPermission = subject
|
|
10033
|
-
? ability.can(action, subject, field)
|
|
10034
|
-
: ability.can(action, '*', field);
|
|
10035
|
-
if (!hasPermission) {
|
|
10036
|
-
return React__default.createElement(View, { style, testID }, children);
|
|
10037
|
-
}
|
|
10038
|
-
return React__default.createElement(View, { style, testID }, fallback);
|
|
10039
|
-
};
|
|
10040
|
-
/**
|
|
10041
|
-
* Permission Gate - Requires ALL permissions to pass
|
|
10042
|
-
*/
|
|
10043
|
-
const PermissionGate = ({ permissions, children, fallback = null, ability: customAbility, onUnauthorized }) => {
|
|
10044
|
-
const { ability: contextAbility } = usePermissions();
|
|
10045
|
-
const ability = customAbility || contextAbility;
|
|
10046
|
-
const allPermissionsGranted = permissions.every(({ action, subject, field }) => ability.can(action, subject, field));
|
|
10047
|
-
React__default.useEffect(() => {
|
|
10048
|
-
if (!allPermissionsGranted && onUnauthorized) {
|
|
10049
|
-
onUnauthorized();
|
|
10050
|
-
}
|
|
10051
|
-
}, [allPermissionsGranted, onUnauthorized]);
|
|
10052
|
-
if (allPermissionsGranted) {
|
|
10053
|
-
return React__default.createElement(React__default.Fragment, null, children);
|
|
10054
|
-
}
|
|
10055
|
-
return React__default.createElement(React__default.Fragment, null, fallback);
|
|
10056
|
-
};
|
|
10057
|
-
/**
|
|
10058
|
-
* Higher-Order Component for permission checking
|
|
10059
|
-
*/
|
|
10060
|
-
function withCan(action, subject, field) {
|
|
10061
|
-
return function CanHOC(Component) {
|
|
10062
|
-
const WrappedComponent = (props) => {
|
|
10063
|
-
const { fallback, ...componentProps } = props;
|
|
10064
|
-
return React__default.createElement(Can, { I: action, a: subject, field, fallback }, React__default.createElement(Component, componentProps));
|
|
10065
|
-
};
|
|
10066
|
-
WrappedComponent.displayName = `withCan(${Component.displayName || Component.name})`;
|
|
10067
|
-
return WrappedComponent;
|
|
10068
|
-
};
|
|
10069
|
-
}
|
|
10070
|
-
/**
|
|
10071
|
-
* Higher-Order Component for permission denial checking
|
|
10072
|
-
*/
|
|
10073
|
-
function withCannot(action, subject, field) {
|
|
10074
|
-
return function CannotHOC(Component) {
|
|
10075
|
-
const WrappedComponent = (props) => {
|
|
10076
|
-
const { fallback, ...componentProps } = props;
|
|
10077
|
-
return React__default.createElement(Cannot, { I: action, a: subject, field, fallback }, React__default.createElement(Component, componentProps));
|
|
10078
|
-
};
|
|
10079
|
-
WrappedComponent.displayName = `withCannot(${Component.displayName || Component.name})`;
|
|
10080
|
-
return WrappedComponent;
|
|
10081
|
-
};
|
|
10082
|
-
}
|
|
10083
|
-
|
|
10084
|
-
/**
|
|
10085
|
-
* Fluent API for building permissions
|
|
10086
|
-
*/
|
|
10087
|
-
class PermissionBuilder {
|
|
10088
|
-
constructor() {
|
|
10089
|
-
this.rules = [];
|
|
10090
|
-
}
|
|
10091
|
-
/**
|
|
10092
|
-
* Grant permission
|
|
10093
|
-
*/
|
|
10094
|
-
allow(action, subject, field) {
|
|
10095
|
-
this.rules.push({
|
|
10096
|
-
action,
|
|
10097
|
-
subject: subject || '*',
|
|
10098
|
-
fields: field ? [field] : undefined,
|
|
10099
|
-
inverted: false
|
|
10100
|
-
});
|
|
10101
|
-
return this;
|
|
10102
|
-
}
|
|
10103
|
-
/**
|
|
10104
|
-
* Deny permission
|
|
10105
|
-
*/
|
|
10106
|
-
forbid(action, subject, field) {
|
|
10107
|
-
this.rules.push({
|
|
10108
|
-
action,
|
|
10109
|
-
subject: subject || '*',
|
|
10110
|
-
fields: field ? [field] : undefined,
|
|
10111
|
-
inverted: true
|
|
10112
|
-
});
|
|
10113
|
-
return this;
|
|
10114
|
-
}
|
|
10115
|
-
/**
|
|
10116
|
-
* Conditional permission
|
|
10117
|
-
*/
|
|
10118
|
-
allowIf(action, subject, conditions, field) {
|
|
10119
|
-
this.rules.push({
|
|
10120
|
-
action,
|
|
10121
|
-
subject: subject || '*',
|
|
10122
|
-
fields: field ? [field] : undefined,
|
|
10123
|
-
inverted: false,
|
|
10124
|
-
conditions
|
|
10125
|
-
});
|
|
10126
|
-
return this;
|
|
10127
|
-
}
|
|
10128
|
-
/**
|
|
10129
|
-
* Conditional denial
|
|
10130
|
-
*/
|
|
10131
|
-
forbidIf(action, subject, conditions, field) {
|
|
10132
|
-
this.rules.push({
|
|
10133
|
-
action,
|
|
10134
|
-
subject: subject || '*',
|
|
10135
|
-
fields: field ? [field] : undefined,
|
|
10136
|
-
inverted: true,
|
|
10137
|
-
conditions
|
|
10138
|
-
});
|
|
10139
|
-
return this;
|
|
10140
|
-
}
|
|
10141
|
-
/**
|
|
10142
|
-
* Grant all actions on a subject
|
|
10143
|
-
*/
|
|
10144
|
-
manage(subject) {
|
|
10145
|
-
this.rules.push({
|
|
10146
|
-
action: '*',
|
|
10147
|
-
subject,
|
|
10148
|
-
inverted: false
|
|
10149
|
-
});
|
|
10150
|
-
return this;
|
|
10151
|
-
}
|
|
10152
|
-
/**
|
|
10153
|
-
* Forbid all actions on a subject
|
|
10154
|
-
*/
|
|
10155
|
-
forbidAll(subject) {
|
|
10156
|
-
this.rules.push({
|
|
10157
|
-
action: '*',
|
|
10158
|
-
subject,
|
|
10159
|
-
inverted: true
|
|
10160
|
-
});
|
|
10161
|
-
return this;
|
|
10162
|
-
}
|
|
10163
|
-
/**
|
|
10164
|
-
* Role-based permissions
|
|
10165
|
-
*/
|
|
10166
|
-
role(roleName, callback) {
|
|
10167
|
-
const roleBuilder = new RoleBuilder(roleName);
|
|
10168
|
-
callback(roleBuilder);
|
|
10169
|
-
this.rules.push(...roleBuilder.getRules());
|
|
10170
|
-
return this;
|
|
10171
|
-
}
|
|
10172
|
-
/**
|
|
10173
|
-
* Build the ability with all rules
|
|
10174
|
-
*/
|
|
10175
|
-
build() {
|
|
10176
|
-
return new AbilityCore(this.rules);
|
|
10177
|
-
}
|
|
10178
|
-
/**
|
|
10179
|
-
* Get all rules
|
|
10180
|
-
*/
|
|
10181
|
-
getRules() {
|
|
10182
|
-
return [...this.rules];
|
|
10183
|
-
}
|
|
10184
|
-
/**
|
|
10185
|
-
* Clear all rules
|
|
10186
|
-
*/
|
|
10187
|
-
clear() {
|
|
10188
|
-
this.rules = [];
|
|
10189
|
-
return this;
|
|
10190
|
-
}
|
|
10191
|
-
/**
|
|
10192
|
-
* Merge rules from another builder
|
|
10193
|
-
*/
|
|
10194
|
-
merge(other) {
|
|
10195
|
-
this.rules.push(...other.getRules());
|
|
10196
|
-
return this;
|
|
10197
|
-
}
|
|
10198
|
-
}
|
|
10199
|
-
/**
|
|
10200
|
-
* Role-specific permission builder
|
|
10201
|
-
*/
|
|
10202
|
-
class RoleBuilder {
|
|
10203
|
-
constructor(roleName) {
|
|
10204
|
-
this.roleName = roleName;
|
|
10205
|
-
this.rules = [];
|
|
10206
|
-
}
|
|
10207
|
-
/**
|
|
10208
|
-
* Grant permission for this role
|
|
10209
|
-
*/
|
|
10210
|
-
can(action, subject, field) {
|
|
10211
|
-
this.rules.push({
|
|
10212
|
-
action,
|
|
10213
|
-
subject: subject || '*',
|
|
10214
|
-
fields: field ? [field] : undefined,
|
|
10215
|
-
inverted: false,
|
|
10216
|
-
conditions: { role: this.roleName }
|
|
10217
|
-
});
|
|
10218
|
-
return this;
|
|
10219
|
-
}
|
|
10220
|
-
/**
|
|
10221
|
-
* Deny permission for this role
|
|
10222
|
-
*/
|
|
10223
|
-
cannot(action, subject, field) {
|
|
10224
|
-
this.rules.push({
|
|
10225
|
-
action,
|
|
10226
|
-
subject: subject || '*',
|
|
10227
|
-
fields: field ? [field] : undefined,
|
|
10228
|
-
inverted: true,
|
|
10229
|
-
conditions: { role: this.roleName }
|
|
10230
|
-
});
|
|
10231
|
-
return this;
|
|
10232
|
-
}
|
|
10233
|
-
/**
|
|
10234
|
-
* Manage all actions on subject for this role
|
|
10235
|
-
*/
|
|
10236
|
-
manage(subject) {
|
|
10237
|
-
this.rules.push({
|
|
10238
|
-
action: '*',
|
|
10239
|
-
subject,
|
|
10240
|
-
inverted: false,
|
|
10241
|
-
conditions: { role: this.roleName }
|
|
10242
|
-
});
|
|
10243
|
-
return this;
|
|
10244
|
-
}
|
|
10245
|
-
/**
|
|
10246
|
-
* Get all rules for this role
|
|
10247
|
-
*/
|
|
10248
|
-
getRules() {
|
|
10249
|
-
return [...this.rules];
|
|
10250
|
-
}
|
|
10251
|
-
}
|
|
10252
|
-
/**
|
|
10253
|
-
* Common permission patterns
|
|
10254
|
-
*/
|
|
10255
|
-
class PermissionPatterns {
|
|
10256
|
-
/**
|
|
10257
|
-
* Admin permissions - can do everything
|
|
10258
|
-
*/
|
|
10259
|
-
static admin() {
|
|
10260
|
-
return new PermissionBuilder()
|
|
10261
|
-
.manage('*');
|
|
10262
|
-
}
|
|
10263
|
-
/**
|
|
10264
|
-
* User permissions - basic CRUD on own resources
|
|
10265
|
-
*/
|
|
10266
|
-
static user(userId) {
|
|
10267
|
-
return new PermissionBuilder()
|
|
10268
|
-
.allowIf('read', 'User', { id: userId })
|
|
10269
|
-
.allowIf('update', 'User', { id: userId })
|
|
10270
|
-
.allowIf('delete', 'User', { id: userId })
|
|
10271
|
-
.allow('read', 'public');
|
|
10272
|
-
}
|
|
10273
|
-
/**
|
|
10274
|
-
* Guest permissions - read-only public content
|
|
10275
|
-
*/
|
|
10276
|
-
static guest() {
|
|
10277
|
-
return new PermissionBuilder()
|
|
10278
|
-
.allow('read', 'public');
|
|
10279
|
-
}
|
|
10280
|
-
/**
|
|
10281
|
-
* Moderator permissions - manage content but not users
|
|
10282
|
-
*/
|
|
10283
|
-
static moderator() {
|
|
10284
|
-
return new PermissionBuilder()
|
|
10285
|
-
.manage('Content')
|
|
10286
|
-
.manage('Comment')
|
|
10287
|
-
.allow('read', 'User')
|
|
10288
|
-
.forbid('delete', 'User');
|
|
10289
|
-
}
|
|
10290
|
-
/**
|
|
10291
|
-
* Owner permissions - full control over owned resources
|
|
10292
|
-
*/
|
|
10293
|
-
static owner(ownerId) {
|
|
10294
|
-
return new PermissionBuilder()
|
|
10295
|
-
.allowIf('*', '*', { ownerId })
|
|
10296
|
-
.allow('create', '*');
|
|
10297
|
-
}
|
|
10298
|
-
}
|
|
10299
|
-
/**
|
|
10300
|
-
* Helper function to create a new permission builder
|
|
10301
|
-
*/
|
|
10302
|
-
function permissions() {
|
|
10303
|
-
return new PermissionBuilder();
|
|
10304
|
-
}
|
|
10305
|
-
/**
|
|
10306
|
-
* Helper function to create ability from rules array
|
|
10307
|
-
*/
|
|
10308
|
-
function defineAbility(callback) {
|
|
10309
|
-
const builder = new PermissionBuilder();
|
|
10310
|
-
callback(builder);
|
|
10311
|
-
return builder.build();
|
|
10312
|
-
}
|
|
10313
|
-
/**
|
|
10314
|
-
* Helper function to create common role-based abilities
|
|
10315
|
-
*/
|
|
10316
|
-
function defineRoleAbility(role, callback) {
|
|
10317
|
-
const roleBuilder = new RoleBuilder(role);
|
|
10318
|
-
callback(roleBuilder);
|
|
10319
|
-
return new AbilityCore(roleBuilder.getRules());
|
|
10320
|
-
}
|
|
10321
|
-
|
|
10322
9758
|
const ThemeModeContext = createContext(null);
|
|
10323
9759
|
// Default persistence using localStorage (web only)
|
|
10324
9760
|
const defaultPersistence = {
|
|
@@ -10448,7 +9884,6 @@ const OverlayBoundary = React__default.memo(function OverlayBoundary({ enabled,
|
|
|
10448
9884
|
const I18nBoundary = React__default.memo(function I18nBoundary({ locale, fallbackLocale, resources, children }) {
|
|
10449
9885
|
return (jsx(I18nProvider, { initial: { locale, fallbackLocale, resources }, children: children }));
|
|
10450
9886
|
});
|
|
10451
|
-
const DEFAULT_PERMISSION_RULES = [{ action: '*', subject: '*' }];
|
|
10452
9887
|
/**
|
|
10453
9888
|
* Internal component that uses the enhanced theme mode when config is provided
|
|
10454
9889
|
*/
|
|
@@ -10486,30 +9921,20 @@ function PlatformBlocksContent({ children, theme, inherit = true, withCSSVariabl
|
|
|
10486
9921
|
document.documentElement.setAttribute('data-platform-blocks-color-scheme', target);
|
|
10487
9922
|
}
|
|
10488
9923
|
}, [effectiveColorScheme, osColorScheme]);
|
|
10489
|
-
const mainContent = (
|
|
10490
|
-
return
|
|
9924
|
+
const mainContent = (jsx(ThemeBoundary, { theme: resolvedTheme, inherit: inherit, withCSSVariables: withCSSVariables, cssVariablesSelector: cssVariablesSelector, withGlobalCSS: withGlobalCSS, children: jsxs(OverlayBoundary, { enabled: withOverlays, children: [children, withSpotlight && jsx(SpotlightController, { config: spotlightConfig })] }) }));
|
|
9925
|
+
return mainContent;
|
|
10491
9926
|
}
|
|
10492
9927
|
/**
|
|
10493
9928
|
* Main provider component for Platform Blocks library
|
|
10494
9929
|
* Provides theme context and injects CSS variables
|
|
10495
9930
|
*/
|
|
10496
|
-
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
|
|
9931
|
+
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 }) {
|
|
10497
9932
|
const i18nStore = useMemo(() => i18nResources || { en: { translation: {} } }, [i18nResources]);
|
|
10498
9933
|
const content = (jsx(PlatformBlocksContent, { theme: theme, inherit: inherit, withCSSVariables: withCSSVariables, cssVariablesSelector: cssVariablesSelector, colorSchemeMode: colorSchemeMode, withOverlays: withOverlays, withSpotlight: withSpotlight, withGlobalCSS: withGlobalCSS, spotlightConfig: spotlightConfig, themeModeConfig: themeModeConfig, children: children }));
|
|
10499
9934
|
const themedTree = themeModeConfig ? (jsx(ThemeModeProvider, { config: themeModeConfig, children: content })) : (content);
|
|
10500
9935
|
const directionConfig = direction === false ? null : (direction !== null && direction !== void 0 ? direction : {});
|
|
10501
9936
|
const hapticsConfig = haptics === false ? null : (haptics !== null && haptics !== void 0 ? haptics : {});
|
|
10502
|
-
const permissionConfig = permissions === false ? null : (() => {
|
|
10503
|
-
const base = { ...(permissions !== null && permissions !== void 0 ? permissions : {}) };
|
|
10504
|
-
if (base.rules === undefined) {
|
|
10505
|
-
base.rules = DEFAULT_PERMISSION_RULES;
|
|
10506
|
-
}
|
|
10507
|
-
return base;
|
|
10508
|
-
})();
|
|
10509
9937
|
let enhancedTree = themedTree;
|
|
10510
|
-
if (permissionConfig) {
|
|
10511
|
-
enhancedTree = (jsx(PermissionProvider, { ...permissionConfig, children: enhancedTree }));
|
|
10512
|
-
}
|
|
10513
9938
|
if (hapticsConfig) {
|
|
10514
9939
|
enhancedTree = (jsx(HapticsProvider, { ...hapticsConfig, children: enhancedTree }));
|
|
10515
9940
|
}
|
|
@@ -10999,14 +10424,18 @@ function usePopoverPositioning(isOpen, options = {}) {
|
|
|
10999
10424
|
// Get popover dimensions
|
|
11000
10425
|
// Always use measureElement for robustness across platforms (RNW refs may not expose getBoundingClientRect)
|
|
11001
10426
|
let popoverDimensions = { width: 200, height: 100 }; // sensible defaults for initial calculation
|
|
10427
|
+
let hasMeasuredPopover = false;
|
|
11002
10428
|
if (popoverRef.current) {
|
|
11003
10429
|
const popoverRect = await measureElement(popoverRef);
|
|
11004
10430
|
if (popoverRect.width > 0 && popoverRect.height > 0) {
|
|
11005
10431
|
popoverDimensions = { width: popoverRect.width, height: popoverRect.height };
|
|
10432
|
+
hasMeasuredPopover = true;
|
|
11006
10433
|
}
|
|
11007
10434
|
}
|
|
11008
10435
|
// Calculate optimal position
|
|
11009
10436
|
const result = calculateOverlayPositionEnhanced(anchorRect, popoverDimensions, positioningOptionsRef.current);
|
|
10437
|
+
// Mark whether this position is based on actual measurements
|
|
10438
|
+
result._hasMeasuredPopover = hasMeasuredPopover;
|
|
11010
10439
|
setPosition(result);
|
|
11011
10440
|
}
|
|
11012
10441
|
catch (error) {
|
|
@@ -17257,6 +16686,7 @@ const TextInputBase = factory((props, ref) => {
|
|
|
17257
16686
|
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;
|
|
17258
16687
|
const renderDisclaimer = useDisclaimer(disclaimerData.disclaimer, disclaimerData.disclaimerProps);
|
|
17259
16688
|
const [focused, setFocused] = useState(false);
|
|
16689
|
+
const [cursorVisible, setCursorVisible] = useState(true);
|
|
17260
16690
|
const theme = useTheme();
|
|
17261
16691
|
const { isRTL } = useDirection();
|
|
17262
16692
|
const internalInputRef = useRef(null);
|
|
@@ -17328,6 +16758,16 @@ const TextInputBase = factory((props, ref) => {
|
|
|
17328
16758
|
return '';
|
|
17329
16759
|
return '•'.repeat(length);
|
|
17330
16760
|
}, [isSecureEntry, normalizedValue]);
|
|
16761
|
+
// Blinking cursor for secure entry (simple interval toggle)
|
|
16762
|
+
useEffect(() => {
|
|
16763
|
+
if (focused && isSecureEntry) {
|
|
16764
|
+
setCursorVisible(true);
|
|
16765
|
+
const interval = setInterval(() => {
|
|
16766
|
+
setCursorVisible(v => !v);
|
|
16767
|
+
}, 530);
|
|
16768
|
+
return () => clearInterval(interval);
|
|
16769
|
+
}
|
|
16770
|
+
}, [focused, isSecureEntry]);
|
|
17331
16771
|
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);
|
|
17332
16772
|
const resolvedInputStyle = useMemo(() => {
|
|
17333
16773
|
const base = [styles.input];
|
|
@@ -17429,7 +16869,12 @@ const TextInputBase = factory((props, ref) => {
|
|
|
17429
16869
|
}
|
|
17430
16870
|
}, [keyboardManager, pendingFocusTarget, focusTargetId]);
|
|
17431
16871
|
const disclaimerNode = renderDisclaimer();
|
|
17432
|
-
return (jsxs(View, { style: [styles.container, spacingStyles, layoutStyles, style], ...rest, children: [jsx(FieldHeader, { label: label, description: description, required: required, withAsterisk: withAsterisk, disabled: disabled, error: !!error, size: size }), jsxs(View, { style: styles.inputContainer, children: [startSection && (jsx(View, { style: styles.startSection, children: startSection })), jsxs(View, { style: { flex: 1, position: 'relative', justifyContent: 'center' }, children: [jsx(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 &&
|
|
16872
|
+
return (jsxs(View, { style: [styles.container, spacingStyles, layoutStyles, style], ...rest, children: [jsx(FieldHeader, { label: label, description: description, required: required, withAsterisk: withAsterisk, disabled: disabled, error: !!error, size: size }), jsxs(View, { style: styles.inputContainer, children: [startSection && (jsx(View, { style: styles.startSection, children: startSection })), jsxs(View, { style: { flex: 1, position: 'relative', justifyContent: 'center' }, children: [jsx(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 && (jsxs(View, { pointerEvents: "none", style: [overlayStyle, { flexDirection: 'row', alignItems: 'center' }], children: [jsx(Text$1, { accessible: false, style: { color: textColor, fontSize: styles.input.fontSize, fontFamily: theme.fontFamily }, numberOfLines: 1, children: maskedValue }), focused && cursorVisible && (jsx(View, { style: {
|
|
16873
|
+
width: 1,
|
|
16874
|
+
height: styles.input.fontSize || 16,
|
|
16875
|
+
backgroundColor: textColor,
|
|
16876
|
+
marginLeft: 1,
|
|
16877
|
+
} }))] }))] }), (showClearButton || endSection) && (jsxs(View, { style: styles.endSection, children: [showClearButton && (jsx(ClearButton, { onPress: handleClear, size: size, accessibilityLabel: clearButtonLabelText, hasRightSection: !!endSection })), endSection] }))] }), disclaimerNode, error && (jsx(Text$1, { style: styles.error, role: "alert", accessibilityLiveRegion: "polite", children: error })), helperText && !error && (jsx(Text$1, { style: styles.helperText, children: helperText }))] }));
|
|
17433
16878
|
});
|
|
17434
16879
|
|
|
17435
16880
|
const getInputTypeConfig = (type) => {
|
|
@@ -17987,18 +17432,19 @@ const useTextAreaStyles = (props) => {
|
|
|
17987
17432
|
? theme.colors.error[5]
|
|
17988
17433
|
: styleProps.focused
|
|
17989
17434
|
? theme.colors.primary[5]
|
|
17990
|
-
:
|
|
17991
|
-
? theme.backgrounds.border
|
|
17992
|
-
: 'transparent',
|
|
17435
|
+
: theme.backgrounds.border,
|
|
17993
17436
|
borderRadius: DESIGN_TOKENS.radius.lg,
|
|
17994
|
-
borderWidth:
|
|
17437
|
+
borderWidth: 2,
|
|
17995
17438
|
paddingHorizontal: DESIGN_TOKENS.spacing.sm,
|
|
17996
17439
|
paddingVertical: DESIGN_TOKENS.spacing.xs,
|
|
17440
|
+
// Match Input focus treatment on web
|
|
17997
17441
|
...(styleProps.focused && !styleProps.disabled && Platform.OS === 'web' && {
|
|
17998
17442
|
boxShadow: `0 0 0 2px ${((_a = theme.states) === null || _a === void 0 ? void 0 : _a.focusRing) || theme.colors.primary[2]}`,
|
|
17999
17443
|
}),
|
|
17444
|
+
// Light elevation similar to Input
|
|
18000
17445
|
...(!styleProps.disabled && theme.colorScheme === 'light' && {
|
|
18001
17446
|
elevation: 1,
|
|
17447
|
+
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)',
|
|
18002
17448
|
}),
|
|
18003
17449
|
opacity: styleProps.disabled ? DESIGN_TOKENS.opacity.disabled : 1,
|
|
18004
17450
|
},
|
|
@@ -19680,7 +19126,7 @@ const useSwitchStyles = (props) => {
|
|
|
19680
19126
|
...(Platform.OS === 'web' && { userSelect: 'none' }),
|
|
19681
19127
|
},
|
|
19682
19128
|
labelContainer: {
|
|
19683
|
-
|
|
19129
|
+
flexShrink: 1,
|
|
19684
19130
|
justifyContent: 'center',
|
|
19685
19131
|
},
|
|
19686
19132
|
labelDisabled: {
|
|
@@ -19849,8 +19295,8 @@ const Switch = factory((rawProps, ref) => {
|
|
|
19849
19295
|
const LayoutComponent = isVertical ? Column : Row;
|
|
19850
19296
|
// For vertical layouts (top/bottom), we want tighter spacing and center alignment
|
|
19851
19297
|
const layoutProps = isVertical
|
|
19852
|
-
? { gap: 'xs',
|
|
19853
|
-
: { gap: 'sm',
|
|
19298
|
+
? { gap: 'xs', align: 'center' }
|
|
19299
|
+
: { gap: 'sm', align: 'center' };
|
|
19854
19300
|
const disclaimerNode = renderDisclaimer();
|
|
19855
19301
|
return (jsxs(View, { style: spacingStyles, children: [jsxs(LayoutComponent, { ...layoutProps, children: [labelPosition === 'top' && labelElement, labelPosition === 'left' && labelElement, switchElement, labelPosition === 'right' && labelElement, labelPosition === 'bottom' && labelElement] }), disclaimerNode ? (jsx(View, { style: { width: '100%' }, children: disclaimerNode })) : null] }));
|
|
19856
19302
|
});
|
|
@@ -27464,7 +26910,7 @@ const MiniCalendar = ({ value, onChange, defaultValue, numberOfDays = 7, default
|
|
|
27464
26910
|
}
|
|
27465
26911
|
onChange === null || onChange === void 0 ? void 0 : onChange(date);
|
|
27466
26912
|
}, [isControlled, maxDate, minDate, onChange]);
|
|
27467
|
-
return (jsxs(View, { children: [jsxs(Flex, { direction: "row", justify: "space-between", align: "center", style: { marginBottom: 16 }, children: [jsx(Pressable, { onPress: handlePrevious, style: ({ pressed }) => [
|
|
26913
|
+
return (jsxs(View, { style: { alignSelf: 'flex-start' }, children: [jsxs(Flex, { direction: "row", justify: "space-between", align: "center", style: { marginBottom: 16 }, children: [jsx(Pressable, { onPress: handlePrevious, style: ({ pressed }) => [
|
|
27468
26914
|
{
|
|
27469
26915
|
padding: 8,
|
|
27470
26916
|
borderRadius: 6,
|
|
@@ -27476,7 +26922,7 @@ const MiniCalendar = ({ value, onChange, defaultValue, numberOfDays = 7, default
|
|
|
27476
26922
|
borderRadius: 6,
|
|
27477
26923
|
backgroundColor: pressed ? theme.colors.gray[2] : 'transparent',
|
|
27478
26924
|
},
|
|
27479
|
-
], ...nextControlProps, children: jsx(Icon, { name: "chevron-right", size: 16, color: theme.colors.gray[6] }) })] }), jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: jsx(Flex, { direction: "row", gap: 4, children: days.map((date) => {
|
|
26925
|
+
], ...nextControlProps, children: jsx(Icon, { name: "chevron-right", size: 16, color: theme.colors.gray[6] }) })] }), jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, contentContainerStyle: { flexGrow: 0 }, style: { flexGrow: 0 }, children: jsx(Flex, { direction: "row", gap: 4, children: days.map((date) => {
|
|
27480
26926
|
const isSelected = selectedDate ? dateUtils$1.isSameDay(date, selectedDate) : false;
|
|
27481
26927
|
const isToday = dateUtils$1.isToday(date);
|
|
27482
26928
|
const isWeekend = dateUtils$1.isWeekend(date);
|
|
@@ -30217,6 +29663,7 @@ function MenuBase(props, ref) {
|
|
|
30217
29663
|
const overlayId = openOverlay({
|
|
30218
29664
|
content: menuDropdown,
|
|
30219
29665
|
anchor: { x: positionResult.x, y: positionResult.y, width: overlaySize.width, height: overlaySize.height },
|
|
29666
|
+
placement: positionResult.placement || position,
|
|
30220
29667
|
closeOnClickOutside,
|
|
30221
29668
|
closeOnEscape,
|
|
30222
29669
|
strategy,
|
|
@@ -32186,7 +31633,7 @@ function usePopoverContext(component) {
|
|
|
32186
31633
|
const DEFAULT_ARROW_SIZE = 7;
|
|
32187
31634
|
const PopoverBase = (props, ref) => {
|
|
32188
31635
|
var _a;
|
|
32189
|
-
const { children, opened: controlledOpened, defaultOpened = false, onChange, onOpen, onClose, onDismiss, disabled = false, closeOnClickOutside = true, closeOnEscape = true, clickOutsideEvents, // currently not implemented
|
|
31636
|
+
const { children, opened: controlledOpened, defaultOpened = false, onChange, onOpen, onClose, onDismiss, trigger = 'click', disabled = false, closeOnClickOutside = true, closeOnEscape = true, clickOutsideEvents, // currently not implemented
|
|
32190
31637
|
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;
|
|
32191
31638
|
const theme = useTheme();
|
|
32192
31639
|
const { spacingProps } = extractSpacingProps(rest);
|
|
@@ -32198,9 +31645,18 @@ const PopoverBase = (props, ref) => {
|
|
|
32198
31645
|
const openedRef = useRef(opened);
|
|
32199
31646
|
const closingReasonRef = useRef(null);
|
|
32200
31647
|
const anchorMeasurementsRef = useRef(null);
|
|
31648
|
+
const hoverTimeoutRef = useRef(null);
|
|
32201
31649
|
useEffect(() => {
|
|
32202
31650
|
openedRef.current = opened;
|
|
32203
31651
|
}, [opened]);
|
|
31652
|
+
// Cleanup hover timeout on unmount
|
|
31653
|
+
useEffect(() => {
|
|
31654
|
+
return () => {
|
|
31655
|
+
if (hoverTimeoutRef.current) {
|
|
31656
|
+
clearTimeout(hoverTimeoutRef.current);
|
|
31657
|
+
}
|
|
31658
|
+
};
|
|
31659
|
+
}, []);
|
|
32204
31660
|
const resolvedOffset = typeof offset === 'number' ? offset : (_a = offset === null || offset === void 0 ? void 0 : offset.mainAxis) !== null && _a !== void 0 ? _a : 8;
|
|
32205
31661
|
const resolvedFlip = preventPositionChangeWhenVisible
|
|
32206
31662
|
? false
|
|
@@ -32213,7 +31669,7 @@ const PopoverBase = (props, ref) => {
|
|
|
32213
31669
|
? false
|
|
32214
31670
|
: true;
|
|
32215
31671
|
const resolvedStrategy = floatingStrategy !== null && floatingStrategy !== void 0 ? floatingStrategy : 'fixed';
|
|
32216
|
-
const { position: positioningResult, anchorRef, popoverRef, showOverlay, hideOverlay, updatePosition } = useDropdownPositioning({
|
|
31672
|
+
const { position: positioningResult, anchorRef, popoverRef, showOverlay, hideOverlay, updatePosition, isPositioning } = useDropdownPositioning({
|
|
32217
31673
|
isOpen: opened && !disabled && !!dropdownState,
|
|
32218
31674
|
placement: position,
|
|
32219
31675
|
offset: resolvedOffset,
|
|
@@ -32225,9 +31681,20 @@ const PopoverBase = (props, ref) => {
|
|
|
32225
31681
|
fallbackPlacements,
|
|
32226
31682
|
viewport,
|
|
32227
31683
|
onClose: () => handleOverlayClose('dismiss'),
|
|
32228
|
-
closeOnClickOutside,
|
|
31684
|
+
closeOnClickOutside: trigger === 'hover' ? false : closeOnClickOutside,
|
|
32229
31685
|
closeOnEscape,
|
|
32230
31686
|
});
|
|
31687
|
+
// Track if we've done measurement-based positioning to avoid flicker
|
|
31688
|
+
const hasPositionedRef = useRef(false);
|
|
31689
|
+
useEffect(() => {
|
|
31690
|
+
// Only mark as positioned when we have a measurement-based position
|
|
31691
|
+
if (opened && positioningResult && positioningResult._hasMeasuredPopover) {
|
|
31692
|
+
hasPositionedRef.current = true;
|
|
31693
|
+
}
|
|
31694
|
+
if (!opened) {
|
|
31695
|
+
hasPositionedRef.current = false;
|
|
31696
|
+
}
|
|
31697
|
+
}, [opened, positioningResult]);
|
|
32231
31698
|
const popoverStyles = useMemo(() => createPopoverStyles(theme)({
|
|
32232
31699
|
radius,
|
|
32233
31700
|
shadow,
|
|
@@ -32331,6 +31798,28 @@ const PopoverBase = (props, ref) => {
|
|
|
32331
31798
|
openPopover();
|
|
32332
31799
|
}
|
|
32333
31800
|
}, [closePopover, openPopover]);
|
|
31801
|
+
// Hover-specific handlers with delay to prevent glitching when moving between target and dropdown
|
|
31802
|
+
const handleHoverOpen = useCallback(() => {
|
|
31803
|
+
if (hoverTimeoutRef.current) {
|
|
31804
|
+
clearTimeout(hoverTimeoutRef.current);
|
|
31805
|
+
hoverTimeoutRef.current = null;
|
|
31806
|
+
}
|
|
31807
|
+
openPopover();
|
|
31808
|
+
}, [openPopover]);
|
|
31809
|
+
const handleHoverClose = useCallback(() => {
|
|
31810
|
+
if (hoverTimeoutRef.current) {
|
|
31811
|
+
clearTimeout(hoverTimeoutRef.current);
|
|
31812
|
+
}
|
|
31813
|
+
hoverTimeoutRef.current = setTimeout(() => {
|
|
31814
|
+
closePopover('programmatic');
|
|
31815
|
+
hoverTimeoutRef.current = null;
|
|
31816
|
+
}, 150); // Delay to allow mouse to move to dropdown
|
|
31817
|
+
}, [closePopover]);
|
|
31818
|
+
// Store hover handlers in refs to avoid causing re-renders in useEffect
|
|
31819
|
+
const hoverHandlersRef = useRef({ open: handleHoverOpen, close: handleHoverClose });
|
|
31820
|
+
useEffect(() => {
|
|
31821
|
+
hoverHandlersRef.current = { open: handleHoverOpen, close: handleHoverClose };
|
|
31822
|
+
}, [handleHoverOpen, handleHoverClose]);
|
|
32334
31823
|
useEffect(() => {
|
|
32335
31824
|
if (opened) {
|
|
32336
31825
|
updateAnchorMeasurements();
|
|
@@ -32389,14 +31878,26 @@ const PopoverBase = (props, ref) => {
|
|
|
32389
31878
|
if (typeof resolvedMaxHeight === 'number')
|
|
32390
31879
|
sizeStyles.maxHeight = resolvedMaxHeight;
|
|
32391
31880
|
const dropdownStyle = [popoverStyles.dropdown, dropdownState.style, sizeStyles];
|
|
32392
|
-
|
|
31881
|
+
// Hover handlers for the dropdown to keep it open when mouse moves from target to dropdown
|
|
31882
|
+
const dropdownHoverHandlers = trigger === 'hover' && Platform.OS === 'web'
|
|
31883
|
+
? {
|
|
31884
|
+
onMouseEnter: () => hoverHandlersRef.current.open(),
|
|
31885
|
+
onMouseLeave: () => hoverHandlersRef.current.close(),
|
|
31886
|
+
}
|
|
31887
|
+
: {};
|
|
31888
|
+
// Hide content until we have measurement-based positioning to prevent visual "snap"
|
|
31889
|
+
const hasMeasuredPosition = (positioningResult === null || positioningResult === void 0 ? void 0 : positioningResult._hasMeasuredPopover) === true;
|
|
31890
|
+
const visibilityStyle = !hasMeasuredPosition && Platform.OS === 'web'
|
|
31891
|
+
? { opacity: 0 }
|
|
31892
|
+
: {};
|
|
31893
|
+
const content = (jsxs(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: [jsx(View, { style: dropdownStyle, children: dropdownState.content }), withArrow && (jsx(View, { style: getArrowStyle(positioningResult.placement, arrowSize, arrowRadius, arrowOffset, arrowPosition, theme) }))] }));
|
|
32393
31894
|
showOverlay(content, {
|
|
32394
31895
|
width: widthOverride,
|
|
32395
31896
|
maxHeight: resolvedMaxHeight,
|
|
32396
31897
|
zIndex,
|
|
32397
31898
|
});
|
|
32398
31899
|
onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange(positioningResult.placement);
|
|
32399
|
-
}, [opened, dropdownState, positioningResult, popoverRef, showOverlay, hideOverlay, popoverStyles.dropdown, popoverStyles.wrapper, width, maxHeight, minWidth, minHeight, maxWidth, withArrow, arrowSize, arrowRadius, arrowOffset, arrowPosition, theme, zIndex, onPositionChange, schedulePositionUpdate]);
|
|
31900
|
+
}, [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]);
|
|
32400
31901
|
useEffect(() => {
|
|
32401
31902
|
return () => {
|
|
32402
31903
|
hideOverlay();
|
|
@@ -32417,6 +31918,8 @@ const PopoverBase = (props, ref) => {
|
|
|
32417
31918
|
open: openPopover,
|
|
32418
31919
|
close: () => closePopover('programmatic'),
|
|
32419
31920
|
toggle: togglePopover,
|
|
31921
|
+
hoverOpen: handleHoverOpen,
|
|
31922
|
+
hoverClose: handleHoverClose,
|
|
32420
31923
|
registerDropdown,
|
|
32421
31924
|
unregisterDropdown,
|
|
32422
31925
|
anchorRef,
|
|
@@ -32425,7 +31928,8 @@ const PopoverBase = (props, ref) => {
|
|
|
32425
31928
|
withRoles,
|
|
32426
31929
|
disabled,
|
|
32427
31930
|
returnFocus,
|
|
32428
|
-
|
|
31931
|
+
trigger,
|
|
31932
|
+
}), [opened, openPopover, closePopover, togglePopover, handleHoverOpen, handleHoverClose, registerDropdown, unregisterDropdown, anchorRef, targetId, dropdownId, withRoles, disabled, returnFocus, trigger]);
|
|
32429
31933
|
const setContainerRef = useCallback((node) => {
|
|
32430
31934
|
if (typeof ref === 'function') {
|
|
32431
31935
|
ref(node);
|
|
@@ -32475,16 +31979,44 @@ const PopoverTargetBase = (props, ref) => {
|
|
|
32475
31979
|
: { id: context.targetId };
|
|
32476
31980
|
const composedRef = mergeRefs(children.ref, externalTargetRef);
|
|
32477
31981
|
const triggerHandlers = {};
|
|
32478
|
-
|
|
32479
|
-
|
|
32480
|
-
|
|
32481
|
-
|
|
32482
|
-
|
|
32483
|
-
|
|
32484
|
-
|
|
32485
|
-
|
|
32486
|
-
|
|
32487
|
-
|
|
31982
|
+
const wrapperHoverHandlers = {};
|
|
31983
|
+
// Click trigger: toggle on press
|
|
31984
|
+
if (context.trigger === 'click') {
|
|
31985
|
+
triggerHandlers.onPress = (...args) => {
|
|
31986
|
+
const tgt = targetProps;
|
|
31987
|
+
if (tgt && typeof tgt.onPress === 'function') {
|
|
31988
|
+
tgt.onPress(...args);
|
|
31989
|
+
}
|
|
31990
|
+
if (typeof childProps.onPress === 'function') {
|
|
31991
|
+
childProps.onPress(...args);
|
|
31992
|
+
}
|
|
31993
|
+
context.toggle();
|
|
31994
|
+
};
|
|
31995
|
+
}
|
|
31996
|
+
// Hover trigger: open/close on mouse enter/leave (web only)
|
|
31997
|
+
// Applied to the wrapper View for reliable hover detection
|
|
31998
|
+
if (context.trigger === 'hover' && Platform.OS === 'web') {
|
|
31999
|
+
wrapperHoverHandlers.onMouseEnter = (...args) => {
|
|
32000
|
+
const tgt = targetProps;
|
|
32001
|
+
if (tgt && typeof tgt.onMouseEnter === 'function') {
|
|
32002
|
+
tgt.onMouseEnter(...args);
|
|
32003
|
+
}
|
|
32004
|
+
if (typeof childProps.onMouseEnter === 'function') {
|
|
32005
|
+
childProps.onMouseEnter(...args);
|
|
32006
|
+
}
|
|
32007
|
+
context.hoverOpen();
|
|
32008
|
+
};
|
|
32009
|
+
wrapperHoverHandlers.onMouseLeave = (...args) => {
|
|
32010
|
+
const tgt = targetProps;
|
|
32011
|
+
if (tgt && typeof tgt.onMouseLeave === 'function') {
|
|
32012
|
+
tgt.onMouseLeave(...args);
|
|
32013
|
+
}
|
|
32014
|
+
if (typeof childProps.onMouseLeave === 'function') {
|
|
32015
|
+
childProps.onMouseLeave(...args);
|
|
32016
|
+
}
|
|
32017
|
+
context.hoverClose();
|
|
32018
|
+
};
|
|
32019
|
+
}
|
|
32488
32020
|
if (Platform.OS === 'web') {
|
|
32489
32021
|
triggerHandlers.onKeyDown = (event) => {
|
|
32490
32022
|
const tgt = targetProps;
|
|
@@ -32506,7 +32038,14 @@ const PopoverTargetBase = (props, ref) => {
|
|
|
32506
32038
|
};
|
|
32507
32039
|
}
|
|
32508
32040
|
const dynamicRefProp = { [refProp]: composedRef };
|
|
32509
|
-
|
|
32041
|
+
// Remove handlers that we're overriding from sanitizedTargetProps
|
|
32042
|
+
if (context.trigger === 'click') {
|
|
32043
|
+
delete sanitizedTargetProps.onPress;
|
|
32044
|
+
}
|
|
32045
|
+
if (context.trigger === 'hover') {
|
|
32046
|
+
delete sanitizedTargetProps.onMouseEnter;
|
|
32047
|
+
delete sanitizedTargetProps.onMouseLeave;
|
|
32048
|
+
}
|
|
32510
32049
|
delete sanitizedTargetProps.onKeyDown;
|
|
32511
32050
|
const mergedProps = {
|
|
32512
32051
|
...sanitizedTargetProps,
|
|
@@ -32518,7 +32057,7 @@ const PopoverTargetBase = (props, ref) => {
|
|
|
32518
32057
|
mergedProps.disabled = true;
|
|
32519
32058
|
}
|
|
32520
32059
|
const anchorWrapperRef = mergeRefs(context.anchorRef, ref);
|
|
32521
|
-
return (jsx(View, { ref: anchorWrapperRef, collapsable: false, children: cloneElement(children, mergedProps) }));
|
|
32060
|
+
return (jsx(View, { ref: anchorWrapperRef, collapsable: false, ...wrapperHoverHandlers, children: cloneElement(children, mergedProps) }));
|
|
32522
32061
|
};
|
|
32523
32062
|
const PopoverDropdownBase = (props, _ref) => {
|
|
32524
32063
|
const { children, trapFocus = false, keepMounted, style, testID, ...rest } = props;
|
|
@@ -32562,8 +32101,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
|
|
|
32562
32101
|
const [side, alignment] = placement.split('-');
|
|
32563
32102
|
switch (side) {
|
|
32564
32103
|
case 'top':
|
|
32104
|
+
// Arrow points down, hide the borders that overlap with content (top-left corner after rotation)
|
|
32565
32105
|
return {
|
|
32566
32106
|
...base,
|
|
32107
|
+
borderTopWidth: 0,
|
|
32108
|
+
borderLeftWidth: 0,
|
|
32567
32109
|
bottom: -arrowSize,
|
|
32568
32110
|
left: alignment === 'end'
|
|
32569
32111
|
? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
|
|
@@ -32573,8 +32115,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
|
|
|
32573
32115
|
marginLeft: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
|
|
32574
32116
|
};
|
|
32575
32117
|
case 'bottom':
|
|
32118
|
+
// Arrow points up, hide the borders that overlap with content (bottom-right corner after rotation)
|
|
32576
32119
|
return {
|
|
32577
32120
|
...base,
|
|
32121
|
+
borderBottomWidth: 0,
|
|
32122
|
+
borderRightWidth: 0,
|
|
32578
32123
|
top: -arrowSize,
|
|
32579
32124
|
left: alignment === 'end'
|
|
32580
32125
|
? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
|
|
@@ -32584,8 +32129,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
|
|
|
32584
32129
|
marginLeft: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
|
|
32585
32130
|
};
|
|
32586
32131
|
case 'left':
|
|
32132
|
+
// Arrow points right, hide the borders that overlap with content (bottom-left corner after rotation)
|
|
32587
32133
|
return {
|
|
32588
32134
|
...base,
|
|
32135
|
+
borderBottomWidth: 0,
|
|
32136
|
+
borderLeftWidth: 0,
|
|
32589
32137
|
right: -arrowSize,
|
|
32590
32138
|
top: alignment === 'end'
|
|
32591
32139
|
? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
|
|
@@ -32595,8 +32143,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
|
|
|
32595
32143
|
marginTop: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
|
|
32596
32144
|
};
|
|
32597
32145
|
case 'right':
|
|
32146
|
+
// Arrow points left, hide the borders that overlap with content (top-right corner after rotation)
|
|
32598
32147
|
return {
|
|
32599
32148
|
...base,
|
|
32149
|
+
borderTopWidth: 0,
|
|
32150
|
+
borderRightWidth: 0,
|
|
32600
32151
|
left: -arrowSize,
|
|
32601
32152
|
top: alignment === 'end'
|
|
32602
32153
|
? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
|
|
@@ -35731,104 +35282,6 @@ const Ring = factory((props, ref) => {
|
|
|
35731
35282
|
return (jsxs(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: [jsxs(View, { style: [styles$8.ringWrapper, { width: size, height: size }, ringStyle], children: [jsxs(Svg, { width: size, height: size, viewBox: `0 0 ${size} ${size}`, children: [jsx(Circle, { cx: size / 2, cy: size / 2, r: radius, stroke: defaultTrackColor, strokeWidth: thickness, fill: "transparent" }), jsx(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})` })] }), jsx(View, { pointerEvents: "none", style: [styles$8.centerContent, { width: size, height: size }, contentStyle], children: centerContent })] }), caption !== undefined && caption !== null ? (React__default.isValidElement(caption) ? (caption) : (jsx(Text, { variant: "span", size: "xs", color: captionTextColor, weight: "600", style: [{ marginTop: 6, letterSpacing: 1 }, captionStyle], children: caption }))) : null] }));
|
|
35732
35283
|
}, { displayName: 'Ring' });
|
|
35733
35284
|
|
|
35734
|
-
const NAVIGATIONPROGRESS_DEFAULTS = {
|
|
35735
|
-
size: 3,
|
|
35736
|
-
color: 'primary',
|
|
35737
|
-
zIndex: 9999,
|
|
35738
|
-
overlay: true,
|
|
35739
|
-
stepInterval: 500,
|
|
35740
|
-
radius: 0,
|
|
35741
|
-
};
|
|
35742
|
-
|
|
35743
|
-
let subscribers = new Set();
|
|
35744
|
-
let internalState = { value: 0, active: false };
|
|
35745
|
-
let interval = null;
|
|
35746
|
-
function broadcast() { subscribers.forEach(cb => cb({ ...internalState })); }
|
|
35747
|
-
function schedule(intervalMs) {
|
|
35748
|
-
clearInterval(interval);
|
|
35749
|
-
interval = setInterval(() => {
|
|
35750
|
-
if (!internalState.active)
|
|
35751
|
-
return;
|
|
35752
|
-
const remain = 100 - internalState.value;
|
|
35753
|
-
const inc = Math.max(0.1, remain * 0.03);
|
|
35754
|
-
internalState.value = Math.min(99, internalState.value + inc);
|
|
35755
|
-
broadcast();
|
|
35756
|
-
}, intervalMs);
|
|
35757
|
-
}
|
|
35758
|
-
const navigationProgress = {
|
|
35759
|
-
start() { if (internalState.active)
|
|
35760
|
-
return; internalState.active = true; if (internalState.value >= 100)
|
|
35761
|
-
internalState.value = 0; broadcast(); schedule(NAVIGATIONPROGRESS_DEFAULTS.stepInterval); },
|
|
35762
|
-
stop() { internalState.active = false; broadcast(); },
|
|
35763
|
-
complete() { internalState.active = true; internalState.value = 100; broadcast(); setTimeout(() => { internalState.active = false; internalState.value = 0; broadcast(); }, 400); },
|
|
35764
|
-
reset() { internalState.value = 0; internalState.active = false; broadcast(); },
|
|
35765
|
-
set(v) { internalState.value = Math.max(0, Math.min(100, v)); broadcast(); },
|
|
35766
|
-
increment(delta = 5) { internalState.value = Math.min(100, internalState.value + delta); broadcast(); },
|
|
35767
|
-
decrement(delta = 5) { internalState.value = Math.max(0, internalState.value - delta); broadcast(); },
|
|
35768
|
-
isActive() { return internalState.active; }
|
|
35769
|
-
};
|
|
35770
|
-
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 }) => {
|
|
35771
|
-
const theme = useTheme();
|
|
35772
|
-
const scheme = useColorScheme();
|
|
35773
|
-
const isDark = scheme === 'dark';
|
|
35774
|
-
const progress = useSharedValue(0);
|
|
35775
|
-
const opacity = useSharedValue(0);
|
|
35776
|
-
useEffect(() => {
|
|
35777
|
-
const sub = (s) => {
|
|
35778
|
-
if (value == null) {
|
|
35779
|
-
progress.value = withTiming(s.value, { duration: stepInterval });
|
|
35780
|
-
opacity.value = withTiming(s.active ? 1 : 0, { duration: 150 });
|
|
35781
|
-
}
|
|
35782
|
-
};
|
|
35783
|
-
subscribers.add(sub);
|
|
35784
|
-
broadcast();
|
|
35785
|
-
return () => { subscribers.delete(sub); };
|
|
35786
|
-
}, [value, stepInterval, progress, opacity]);
|
|
35787
|
-
useEffect(() => {
|
|
35788
|
-
if (value != null) {
|
|
35789
|
-
progress.value = withTiming(value, { duration: stepInterval });
|
|
35790
|
-
opacity.value = withTiming(active ? 1 : 0, { duration: 150 });
|
|
35791
|
-
}
|
|
35792
|
-
}, [value, active, stepInterval]);
|
|
35793
|
-
let resolvedColor = color;
|
|
35794
|
-
if (theme.colors[color]) {
|
|
35795
|
-
const bucket = theme.colors[color];
|
|
35796
|
-
resolvedColor = bucket[5] || bucket[4] || bucket[0];
|
|
35797
|
-
}
|
|
35798
|
-
const barStyle = useAnimatedStyle(() => ({ width: `${progress.value}%` }));
|
|
35799
|
-
const containerStyle = useAnimatedStyle(() => ({ opacity: opacity.value }));
|
|
35800
|
-
return (jsxs(Animated.View, { style: [
|
|
35801
|
-
{
|
|
35802
|
-
position: overlay ? 'absolute' : 'relative',
|
|
35803
|
-
top: 0,
|
|
35804
|
-
left: 0,
|
|
35805
|
-
right: 0,
|
|
35806
|
-
height: size,
|
|
35807
|
-
backgroundColor: isDark ? theme.colors.gray[3] : theme.colors.gray[2],
|
|
35808
|
-
overflow: 'hidden',
|
|
35809
|
-
zIndex,
|
|
35810
|
-
borderRadius: radius,
|
|
35811
|
-
pointerEvents: 'none'
|
|
35812
|
-
},
|
|
35813
|
-
containerStyle,
|
|
35814
|
-
style
|
|
35815
|
-
], children: [jsx(Animated.View, { style: [{
|
|
35816
|
-
position: 'absolute',
|
|
35817
|
-
top: 0,
|
|
35818
|
-
bottom: 0,
|
|
35819
|
-
left: 0,
|
|
35820
|
-
backgroundColor: resolvedColor,
|
|
35821
|
-
borderRadius: radius,
|
|
35822
|
-
}, barStyle] }), jsx(Animated.View, { style: [{
|
|
35823
|
-
position: 'absolute',
|
|
35824
|
-
top: 0,
|
|
35825
|
-
bottom: 0,
|
|
35826
|
-
right: 0,
|
|
35827
|
-
width: 80,
|
|
35828
|
-
backgroundColor: 'rgba(255,255,255,0.2)'
|
|
35829
|
-
}, barStyle] })] }));
|
|
35830
|
-
};
|
|
35831
|
-
|
|
35832
35285
|
const DEFAULT_OPACITY = 0.6;
|
|
35833
35286
|
const HEX_COLOR_REGEX = /^#?[0-9a-f]{3,8}$/i;
|
|
35834
35287
|
const clampOpacity = (value) => {
|
|
@@ -36021,270 +35474,6 @@ const LoadingOverlay = React__default.forwardRef((props, ref) => {
|
|
|
36021
35474
|
});
|
|
36022
35475
|
LoadingOverlay.displayName = 'LoadingOverlay';
|
|
36023
35476
|
|
|
36024
|
-
// A lightweight hover-activated floating panel similar to Mantine HoverCard
|
|
36025
|
-
function HoverCardBase(props, ref) {
|
|
36026
|
-
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;
|
|
36027
|
-
const [opened, setOpened] = useState(false);
|
|
36028
|
-
const openTimeout = useRef(null);
|
|
36029
|
-
const closeTimeout = useRef(null);
|
|
36030
|
-
const containerRef = useRef(null);
|
|
36031
|
-
const targetRef = useRef(null);
|
|
36032
|
-
const overlayIdRef = useRef(null);
|
|
36033
|
-
const overlayContentRef = useRef(null);
|
|
36034
|
-
const isHoveringTargetRef = useRef(false);
|
|
36035
|
-
const isHoveringOverlayRef = useRef(false);
|
|
36036
|
-
const theme = useTheme();
|
|
36037
|
-
const { openOverlay, closeOverlay, updateOverlay } = useOverlay();
|
|
36038
|
-
const isOpened = controlledOpened !== undefined ? controlledOpened : opened;
|
|
36039
|
-
const clearTimers = () => {
|
|
36040
|
-
if (openTimeout.current) {
|
|
36041
|
-
clearTimeout(openTimeout.current);
|
|
36042
|
-
openTimeout.current = null;
|
|
36043
|
-
}
|
|
36044
|
-
if (closeTimeout.current) {
|
|
36045
|
-
clearTimeout(closeTimeout.current);
|
|
36046
|
-
closeTimeout.current = null;
|
|
36047
|
-
}
|
|
36048
|
-
};
|
|
36049
|
-
const doOpen = useCallback(() => {
|
|
36050
|
-
if (disabled)
|
|
36051
|
-
return;
|
|
36052
|
-
setOpened(true);
|
|
36053
|
-
onOpen === null || onOpen === void 0 ? void 0 : onOpen();
|
|
36054
|
-
}, [disabled, onOpen]);
|
|
36055
|
-
const doClose = useCallback(() => {
|
|
36056
|
-
setOpened(false);
|
|
36057
|
-
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
36058
|
-
}, [onClose]);
|
|
36059
|
-
const scheduleOpen = useCallback(() => {
|
|
36060
|
-
clearTimers();
|
|
36061
|
-
openTimeout.current = setTimeout(doOpen, openDelay);
|
|
36062
|
-
}, [doOpen, openDelay]);
|
|
36063
|
-
const scheduleClose = useCallback(() => {
|
|
36064
|
-
clearTimers();
|
|
36065
|
-
closeTimeout.current = setTimeout(() => {
|
|
36066
|
-
// Only close if neither target nor overlay are hovered (web)
|
|
36067
|
-
if (Platform.OS === 'web') {
|
|
36068
|
-
if (isHoveringTargetRef.current || isHoveringOverlayRef.current)
|
|
36069
|
-
return;
|
|
36070
|
-
}
|
|
36071
|
-
doClose();
|
|
36072
|
-
}, closeDelay);
|
|
36073
|
-
}, [doClose, closeDelay]);
|
|
36074
|
-
useEffect(() => () => clearTimers(), []);
|
|
36075
|
-
// Escape key (web only)
|
|
36076
|
-
useEffect(() => {
|
|
36077
|
-
if (!closeOnEscape || Platform.OS !== 'web')
|
|
36078
|
-
return;
|
|
36079
|
-
const handler = (e) => { if (e.key === 'Escape')
|
|
36080
|
-
doClose(); };
|
|
36081
|
-
document.addEventListener('keydown', handler);
|
|
36082
|
-
return () => document.removeEventListener('keydown', handler);
|
|
36083
|
-
}, [closeOnEscape, doClose]);
|
|
36084
|
-
const getInlinePositionStyle = () => {
|
|
36085
|
-
const base = { position: 'absolute' };
|
|
36086
|
-
switch (position) {
|
|
36087
|
-
case 'top': return { ...base, bottom: '100%', left: 0, marginBottom: offset };
|
|
36088
|
-
case 'bottom': return { ...base, top: '100%', left: 0, marginTop: offset };
|
|
36089
|
-
case 'left': return { ...base, right: '100%', top: 0, marginRight: offset };
|
|
36090
|
-
case 'right': return { ...base, left: '100%', top: 0, marginLeft: offset };
|
|
36091
|
-
default: return { ...base, top: '100%', left: 0, marginTop: offset };
|
|
36092
|
-
}
|
|
36093
|
-
};
|
|
36094
|
-
const shadowStyle = (() => {
|
|
36095
|
-
switch (shadow) {
|
|
36096
|
-
case 'sm':
|
|
36097
|
-
return { boxShadow: '0 1px 2px rgba(0, 0, 0, 0.1)', elevation: 2 };
|
|
36098
|
-
case 'md':
|
|
36099
|
-
return { boxShadow: '0 2px 4px rgba(0, 0, 0, 0.15)', elevation: 4 };
|
|
36100
|
-
case 'lg':
|
|
36101
|
-
return { boxShadow: '0 4px 8px rgba(0, 0, 0, 0.2)', elevation: 8 };
|
|
36102
|
-
default:
|
|
36103
|
-
return {};
|
|
36104
|
-
}
|
|
36105
|
-
})();
|
|
36106
|
-
const renderArrow = (placement) => {
|
|
36107
|
-
if (!withArrow)
|
|
36108
|
-
return null;
|
|
36109
|
-
const base = { position: 'absolute', width: 0, height: 0 };
|
|
36110
|
-
const color = theme.colors.gray[0];
|
|
36111
|
-
const styles = {
|
|
36112
|
-
top: { top: '100%', left: 12, borderLeftWidth: 6, borderRightWidth: 6, borderTopWidth: 6, borderLeftColor: 'transparent', borderRightColor: 'transparent', borderTopColor: color },
|
|
36113
|
-
bottom: { bottom: '100%', left: 12, borderLeftWidth: 6, borderRightWidth: 6, borderBottomWidth: 6, borderLeftColor: 'transparent', borderRightColor: 'transparent', borderBottomColor: color },
|
|
36114
|
-
left: { left: '100%', top: 12, borderTopWidth: 6, borderBottomWidth: 6, borderLeftWidth: 6, borderTopColor: 'transparent', borderBottomColor: 'transparent', borderLeftColor: color },
|
|
36115
|
-
right: { right: '100%', top: 12, borderTopWidth: 6, borderBottomWidth: 6, borderRightWidth: 6, borderTopColor: 'transparent', borderBottomColor: 'transparent', borderRightColor: color },
|
|
36116
|
-
};
|
|
36117
|
-
const key = placement.split('-')[0];
|
|
36118
|
-
return jsx(View, { style: { ...base, ...(styles[key] || styles.top) } });
|
|
36119
|
-
};
|
|
36120
|
-
const openPortal = useCallback(async () => {
|
|
36121
|
-
if (!withinPortal || !isOpened || overlayIdRef.current)
|
|
36122
|
-
return;
|
|
36123
|
-
const rect = await measureElement(targetRef);
|
|
36124
|
-
const estWidth = width || 240;
|
|
36125
|
-
const estHeight = 160; // rough initial height
|
|
36126
|
-
const pos = calculateOverlayPositionEnhanced(rect, { width: estWidth, height: estHeight }, {
|
|
36127
|
-
placement: position,
|
|
36128
|
-
offset,
|
|
36129
|
-
viewport: getViewport(),
|
|
36130
|
-
strategy: 'fixed'
|
|
36131
|
-
});
|
|
36132
|
-
const overlayContent = (jsxs(View, { ref: overlayContentRef, style: [
|
|
36133
|
-
{
|
|
36134
|
-
backgroundColor: theme.colors.gray[0],
|
|
36135
|
-
borderRadius: getRadius$2(radius),
|
|
36136
|
-
paddingHorizontal: getSpacing('md'),
|
|
36137
|
-
paddingVertical: getSpacing('sm'),
|
|
36138
|
-
borderWidth: 1,
|
|
36139
|
-
borderColor: theme.colors.gray[3],
|
|
36140
|
-
minWidth: width || 160,
|
|
36141
|
-
maxWidth: width || 320,
|
|
36142
|
-
},
|
|
36143
|
-
shadowStyle,
|
|
36144
|
-
], ...(Platform.OS === 'web' && trigger === 'hover' ? {
|
|
36145
|
-
onMouseEnter: () => { isHoveringOverlayRef.current = true; clearTimers(); },
|
|
36146
|
-
onMouseLeave: () => { isHoveringOverlayRef.current = false; scheduleClose(); },
|
|
36147
|
-
} : {}), children: [children, renderArrow(pos.placement)] }));
|
|
36148
|
-
const id = openOverlay({
|
|
36149
|
-
content: overlayContent,
|
|
36150
|
-
anchor: { x: pos.x, y: pos.y, width: estWidth, height: estHeight },
|
|
36151
|
-
trigger: trigger,
|
|
36152
|
-
// For hover-triggered overlays, do NOT render a click-outside backdrop – it steals hover
|
|
36153
|
-
// and immediately fires target onMouseLeave. We rely on pointer leave timers instead.
|
|
36154
|
-
closeOnClickOutside: trigger !== 'hover',
|
|
36155
|
-
closeOnEscape: closeOnEscape,
|
|
36156
|
-
strategy: 'fixed',
|
|
36157
|
-
onClose: () => { overlayIdRef.current = null; if (opened)
|
|
36158
|
-
setOpened(false); onClose === null || onClose === void 0 ? void 0 : onClose(); },
|
|
36159
|
-
zIndex
|
|
36160
|
-
});
|
|
36161
|
-
overlayIdRef.current = id;
|
|
36162
|
-
}, [withinPortal, isOpened, overlayIdRef, position, offset, width, trigger, closeOnEscape, theme, radius, shadowStyle, children, opened, onClose, getSpacing, getRadius$2]);
|
|
36163
|
-
const closePortal = useCallback(() => {
|
|
36164
|
-
if (overlayIdRef.current) {
|
|
36165
|
-
closeOverlay(overlayIdRef.current);
|
|
36166
|
-
overlayIdRef.current = null;
|
|
36167
|
-
}
|
|
36168
|
-
}, [closeOverlay]);
|
|
36169
|
-
useEffect(() => {
|
|
36170
|
-
if (withinPortal) {
|
|
36171
|
-
if (isOpened)
|
|
36172
|
-
openPortal();
|
|
36173
|
-
else
|
|
36174
|
-
closePortal();
|
|
36175
|
-
}
|
|
36176
|
-
return () => { if (!isOpened)
|
|
36177
|
-
closePortal(); };
|
|
36178
|
-
}, [isOpened, withinPortal, openPortal, closePortal]);
|
|
36179
|
-
useEffect(() => {
|
|
36180
|
-
if (!withinPortal || Platform.OS !== 'web' || !isOpened || !overlayIdRef.current)
|
|
36181
|
-
return;
|
|
36182
|
-
const handler = () => {
|
|
36183
|
-
Promise.all([measureElement(targetRef)]).then(([rect]) => {
|
|
36184
|
-
var _a, _b;
|
|
36185
|
-
const actualWidth = ((_a = overlayContentRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || width || 240;
|
|
36186
|
-
const actualHeight = ((_b = overlayContentRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 160;
|
|
36187
|
-
const pos = calculateOverlayPositionEnhanced(rect, { width: actualWidth, height: actualHeight }, {
|
|
36188
|
-
placement: position,
|
|
36189
|
-
offset,
|
|
36190
|
-
viewport: getViewport(),
|
|
36191
|
-
strategy: 'fixed'
|
|
36192
|
-
});
|
|
36193
|
-
updateOverlay(overlayIdRef.current, { anchor: { x: pos.x, y: pos.y, width: actualWidth, height: actualHeight } });
|
|
36194
|
-
});
|
|
36195
|
-
};
|
|
36196
|
-
window.addEventListener('resize', handler);
|
|
36197
|
-
window.addEventListener('scroll', handler, true);
|
|
36198
|
-
return () => {
|
|
36199
|
-
window.removeEventListener('resize', handler);
|
|
36200
|
-
window.removeEventListener('scroll', handler, true);
|
|
36201
|
-
};
|
|
36202
|
-
}, [withinPortal, isOpened, position, offset, width, updateOverlay]);
|
|
36203
|
-
// Smart sizing: after content mounts, measure actual size and reposition if changed
|
|
36204
|
-
useEffect(() => {
|
|
36205
|
-
if (!withinPortal || !isOpened || !overlayIdRef.current)
|
|
36206
|
-
return;
|
|
36207
|
-
let frame;
|
|
36208
|
-
const attempt = () => {
|
|
36209
|
-
Promise.all([
|
|
36210
|
-
measureElement(targetRef),
|
|
36211
|
-
measureElement({ current: overlayContentRef.current })
|
|
36212
|
-
]).then(([targetRect, contentRect]) => {
|
|
36213
|
-
if (!targetRect.width || !contentRect.width)
|
|
36214
|
-
return; // skip invalid
|
|
36215
|
-
const desiredWidth = width || contentRect.width;
|
|
36216
|
-
const desiredHeight = contentRect.height;
|
|
36217
|
-
// Recalculate with actual content size
|
|
36218
|
-
const pos = calculateOverlayPositionEnhanced(targetRect, { width: desiredWidth, height: desiredHeight }, {
|
|
36219
|
-
placement: position,
|
|
36220
|
-
offset,
|
|
36221
|
-
viewport: getViewport(),
|
|
36222
|
-
strategy: 'fixed'
|
|
36223
|
-
});
|
|
36224
|
-
updateOverlay(overlayIdRef.current, { anchor: { x: pos.x, y: pos.y, width: desiredWidth, height: desiredHeight } });
|
|
36225
|
-
});
|
|
36226
|
-
};
|
|
36227
|
-
// Delay a bit to allow layout
|
|
36228
|
-
frame = setTimeout(attempt, 30);
|
|
36229
|
-
return () => { if (frame)
|
|
36230
|
-
clearTimeout(frame); };
|
|
36231
|
-
}, [withinPortal, isOpened, position, offset, width, updateOverlay]);
|
|
36232
|
-
const targetProps = {};
|
|
36233
|
-
if (trigger === 'hover') {
|
|
36234
|
-
if (Platform.OS === 'web') {
|
|
36235
|
-
targetProps.onMouseEnter = () => { isHoveringTargetRef.current = true; scheduleOpen(); };
|
|
36236
|
-
targetProps.onMouseLeave = () => { isHoveringTargetRef.current = false; scheduleClose(); };
|
|
36237
|
-
}
|
|
36238
|
-
else {
|
|
36239
|
-
// fallback: tap to toggle on native
|
|
36240
|
-
targetProps.onPress = () => {
|
|
36241
|
-
if (isOpened) {
|
|
36242
|
-
doClose();
|
|
36243
|
-
}
|
|
36244
|
-
else {
|
|
36245
|
-
doOpen();
|
|
36246
|
-
}
|
|
36247
|
-
};
|
|
36248
|
-
}
|
|
36249
|
-
}
|
|
36250
|
-
else if (trigger === 'click') {
|
|
36251
|
-
targetProps.onPress = () => {
|
|
36252
|
-
if (isOpened) {
|
|
36253
|
-
doClose();
|
|
36254
|
-
}
|
|
36255
|
-
else {
|
|
36256
|
-
doOpen();
|
|
36257
|
-
}
|
|
36258
|
-
};
|
|
36259
|
-
}
|
|
36260
|
-
const inlineContent = (isOpened || keepMounted) && !withinPortal ? (jsxs(View, { style: [
|
|
36261
|
-
getInlinePositionStyle(),
|
|
36262
|
-
{
|
|
36263
|
-
backgroundColor: theme.colors.gray[0],
|
|
36264
|
-
borderRadius: getRadius$2(radius),
|
|
36265
|
-
paddingHorizontal: getSpacing('md'),
|
|
36266
|
-
paddingVertical: getSpacing('sm'),
|
|
36267
|
-
borderWidth: 1,
|
|
36268
|
-
borderColor: theme.colors.gray[3],
|
|
36269
|
-
minWidth: width,
|
|
36270
|
-
zIndex,
|
|
36271
|
-
},
|
|
36272
|
-
shadowStyle,
|
|
36273
|
-
], pointerEvents: "auto", ...(Platform.OS === 'web' && trigger === 'hover' ? {
|
|
36274
|
-
onMouseEnter: () => { isHoveringOverlayRef.current = true; clearTimers(); },
|
|
36275
|
-
onMouseLeave: () => { isHoveringOverlayRef.current = false; scheduleClose(); },
|
|
36276
|
-
} : {}), children: [children, renderArrow(position)] })) : null;
|
|
36277
|
-
return (jsxs(View, { ref: ref, style: [{ position: 'relative', alignSelf: 'flex-start' }, style], testID: testID, children: [jsx(Pressable, { ref: (node) => { containerRef.current = node; targetRef.current = node; }, ...targetProps, style: ({ pressed }) => {
|
|
36278
|
-
var _a;
|
|
36279
|
-
return [
|
|
36280
|
-
{ opacity: pressed ? 0.85 : 1 },
|
|
36281
|
-
(_a = target === null || target === void 0 ? void 0 : target.props) === null || _a === void 0 ? void 0 : _a.style,
|
|
36282
|
-
];
|
|
36283
|
-
}, children: target }), inlineContent] }));
|
|
36284
|
-
}
|
|
36285
|
-
const HoverCard = factory(HoverCardBase);
|
|
36286
|
-
HoverCard.displayName = 'HoverCard';
|
|
36287
|
-
|
|
36288
35477
|
const ContextMenu = ({ children, items, closeOnSelect = true, longPressDelay = 350, maxHeight = 280, onOpen, onClose, open: controlledOpen, position: controlledPosition, portalId, style, }) => {
|
|
36289
35478
|
var _a, _b;
|
|
36290
35479
|
const [internalOpen, setInternalOpen] = useState(false);
|
|
@@ -39874,11 +39063,14 @@ QRCodeSVG.displayName = 'QRCodeSVG';
|
|
|
39874
39063
|
*/
|
|
39875
39064
|
function QRCode(props) {
|
|
39876
39065
|
var _a;
|
|
39066
|
+
const theme = useTheme();
|
|
39877
39067
|
const { spacingProps, otherProps: propsAfterSpacing } = extractSpacingProps(props);
|
|
39878
39068
|
const { layoutProps, otherProps } = extractLayoutProps(propsAfterSpacing);
|
|
39879
|
-
const { value, size = 400, backgroundColor = 'transparent', color
|
|
39069
|
+
const { value, size = 400, backgroundColor = 'transparent', color, errorCorrectionLevel = 'M', quietZone = 4, logo, style, testID, accessibilityLabel, onError, onLoadStart, // deprecated noop
|
|
39880
39070
|
onLoadEnd, // deprecated noop
|
|
39881
39071
|
...rest } = otherProps;
|
|
39072
|
+
// Default color to theme's primary text color for dark mode support
|
|
39073
|
+
const resolvedColor = color !== null && color !== void 0 ? color : theme.text.primary;
|
|
39882
39074
|
const { copy } = useClipboard();
|
|
39883
39075
|
const toast = useToast();
|
|
39884
39076
|
const shouldCopyOnPress = !!otherProps.copyOnPress;
|
|
@@ -39894,7 +39086,7 @@ function QRCode(props) {
|
|
|
39894
39086
|
});
|
|
39895
39087
|
}
|
|
39896
39088
|
}, [copy, copyValue, toast, otherProps.copyToastMessage, otherProps.copyToastTitle]);
|
|
39897
|
-
const content = (jsxs(View, { style: { borderRadius: 8, overflow: 'hidden' }, children: [jsx(QRCodeSVG, { value: value, size: size, maxWidth: '100%', backgroundColor: backgroundColor, color:
|
|
39089
|
+
const content = (jsxs(View, { style: { borderRadius: 8, overflow: 'hidden' }, children: [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 && (jsx(CopyButton, { value: copyValue, iconOnly: true, size: "sm", style: { position: 'absolute', top: 8, right: 8 }, onCopy: () => { } }))] }));
|
|
39898
39090
|
if (shouldCopyOnPress) {
|
|
39899
39091
|
return (jsx(Pressable, { onPress: handleCopy, accessibilityLabel: accessibilityLabel || 'QR code', children: content }));
|
|
39900
39092
|
}
|
|
@@ -41967,5 +41159,5 @@ function withPressAnimation(Component, animationProps) {
|
|
|
41967
41159
|
*/
|
|
41968
41160
|
const AnimatedPressable = PressAnimation;
|
|
41969
41161
|
|
|
41970
|
-
export {
|
|
41162
|
+
export { AccessibilityProvider, Accordion, AmazonAppstoreBadge, AmazonAppstoreButton, AmazonMusicListenBadge, AmazonPrimeVideoBadge, AmazonStoreBadge, AnimatedPressable, AppLayoutProvider, AppLayoutRenderer, AppShell, AppShellAside, AppShellBottomNav, AppShellFooter, AppShellHeader, AppShellMain, AppShellNavbar, AppShellSection, AppStoreBadge, AppStoreButton, AppStoreDownloadBadge, AppleAppStoreButton, AppleMusicListenBadge, ApplePodcastsListenBadge, AutoComplete, Avatar, AvatarGroup, Badge, Block, Blockquote, Bold, BottomAppBar, BrandButton, BrandIcon, Breadcrumbs, Button, COMPONENT_SIZES$1 as COMPONENT_SIZES, COMPONENT_SIZE_ORDER, Calendar, Card, Carousel, Checkbox, Chip, ChromeWebStoreBadge, Cite, Code, CodeBlock, Collapse, ColorPicker, ColorSwatch, Column, ComponentWithDisclaimer, ContextMenu, CopyButton, DARK_THEME, DEFAULT_BREAKPOINTS, DEFAULT_COMPONENT_SIZE, DEFAULT_SOUND_IDS, DEFAULT_THEME, DataTable, DatePicker, DatePickerInput, Day, Dialog, DialogProvider, DialogRenderer, DirectionProvider, Disclaimer, DiscordJoinBadge, Divider, EmojiPicker, Emphasis, FDroidButton, FileInput, Flex, FloatingActions, Form, GalaxyStoreDownloadBadge, Gallery, Gauge, GitHubViewBadge, GooglePlayButton, GooglePlayDownloadBadge, Grid, GridItem, H1, H2, H3, H4, H5, H6, HapticsProvider, Heading1, Heading2, Heading3, Heading4, Heading5, Heading6, Highlight, HuaweiAppGalleryBadge, I18nProvider, Icon, IconButton, Image, Indicator, Input, Italic, Kbd, KeyCap, KeyboardAwareLayout, KeyboardManagerProvider, Knob, Link, ListGroup, ListGroupBody, ListGroupDivider, ListGroupItem, Loader, LoadingOverlay, Lottie, MacAppStoreButton, Mark, Markdown, Masonry, Menu, MenuDivider, MenuDropdown, MenuItem, MenuItemButton, MenuLabel, MicrosoftStoreButton, MicrosoftStoreDownloadBadge, MiniCalendar, Month, MonthPicker, MonthPickerInput, Notice, NumberInput, Overlay, OverlayProvider, P, Pagination, PasswordInput, PhoneInput, PinInput, PlatformBlocksProvider, Popover, PressAnimation, Progress, QRCode, Radio, RadioGroup, RangeSlider, Rating, RedditJoinBadge, RichTextEditor, Ring, Row, SIZE_SCALES, Search, SegmentedControl, Select, ShimmerText, Skeleton, Slider, Small, SoundCloudListenBadge, SoundProvider, Space, Spoiler, SpotifyListenBadge, Spotlight, SpotlightProvider, StatusBarManager, StepperWithSubComponents as Stepper, Strong, Sub, Sup, Switch, Table, TableOfContents, Tabs, Text, TextArea, TextInputBase, ThemeModeProvider, TikTokWatchBadge, TimePickerInput as TimePicker, TimePickerInput, TimelineWithItems as Timeline, Title, TitleRegistryProvider, Toast, ToastProvider, ToggleBar, ToggleButton, ToggleGroup, Tooltip, Tree, TwitchWatchBadge, Underline, Video, Waveform, YearPicker, YearPickerInput, YouTubeMusicListenBadge, YouTubeWatchBadge, calculateOverlayPositionEnhanced, clampComponentSize, clearOverlayPositionCache, createSound, createSpotlightStore, createTheme, debounce$1 as debounce, defineAppLayout, directSpotlight, extractDisclaimerProps, factory, getAllSounds, getColor, getFontSize, getHeight, getIconSize$1 as getIconSize, getLineHeight, getRadius$1 as getRadius, getScrollPosition, getShadow$1 as getShadow, getSize, getSoundsByCategory, getSpacing, getViewport, globalHotkeys, measureAsyncPerformance, measureElement, measurePerformance, onDialogsRequested, onSpotlightRequested, onToastsRequested, pointInRect, polymorphicFactory, px, rem, resolveComponentSize, resolveResponsiveProp, resolveResponsiveValue, resolveSize, spotlight, throttle, useAccessibility, useAppLayoutContext, useAppShell, useAppShellApi, useAppShellLayout, useBreakpoint, useColorScheme, useDialog, useDialogApi, useDialogs, useDirectSpotlightState, useDirection, useDirectionSafe, useDisclaimer, useDropdownPositioning, useEscapeKey, useFormContext, useGlobalHotkeys, useHaptics, useHapticsSettings, useHotkeys, useI18n, useKeyboardManager, useKeyboardManagerOptional, useNavbarHover, useOptionalFormContext, useOverlay, useOverlayApi, useOverlays, usePopoverPositioning, useSimpleDialog, useSound, useSpotlightStore, useSpotlightStoreInstance, useSpotlightToggle, useTheme, useThemeMode, useTitleRegistry, useTitleRegistryOptional, useToast, useToastApi, useToggleColorScheme, useTooltipPositioning, withDisclaimer, withPressAnimation };
|
|
41971
41163
|
//# sourceMappingURL=index.js.map
|