@platform-blocks/ui 0.4.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 +684 -1211
- package/lib/cjs/index.js.map +1 -1
- package/lib/components/Avatar/Avatar.d.ts +1 -1
- package/lib/components/Avatar/types.d.ts +3 -3
- package/lib/components/Carousel/types.d.ts +32 -0
- package/lib/components/DataTable/DataTable.d.ts +1 -1
- package/lib/components/DataTable/types.d.ts +2 -0
- package/lib/components/HoverCard/types.d.ts +4 -2
- package/lib/components/Popover/types.d.ts +2 -0
- package/lib/components/Slider/types.d.ts +29 -1
- 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 +685 -1193
- 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) {
|
|
@@ -12056,7 +11485,7 @@ function AppShellBase(props, ref) {
|
|
|
12056
11485
|
const breakpoint = useBreakpoint();
|
|
12057
11486
|
// Determine if mobile based on breakpoint and platform
|
|
12058
11487
|
const isMobile = Platform.OS !== 'web' || breakpoint === 'xs' || breakpoint === 'sm';
|
|
12059
|
-
const headerConfig = layoutVisibility.header
|
|
11488
|
+
const headerConfig = layoutVisibility.header ? header : undefined;
|
|
12060
11489
|
const navbarConfig = layoutVisibility.navbar ? navbar : undefined;
|
|
12061
11490
|
const asideConfig = layoutVisibility.aside ? aside : undefined;
|
|
12062
11491
|
const footerConfig = layoutVisibility.footer ? footer : undefined;
|
|
@@ -17148,9 +16577,7 @@ const createInputStyles = (theme, isRTL = false) => {
|
|
|
17148
16577
|
? theme.colors.error[5]
|
|
17149
16578
|
: props.focused
|
|
17150
16579
|
? theme.colors.primary[5]
|
|
17151
|
-
:
|
|
17152
|
-
? theme.backgrounds.border
|
|
17153
|
-
: 'transparent',
|
|
16580
|
+
: theme.backgrounds.border,
|
|
17154
16581
|
// Optional focus shadow (web only) without affecting layout
|
|
17155
16582
|
...(props.focused && !props.disabled && typeof window !== 'undefined' && ((_a = theme.states) === null || _a === void 0 ? void 0 : _a.focusRing) && {
|
|
17156
16583
|
boxShadow: `0 0 0 2px ${theme.states.focusRing}`,
|
|
@@ -17259,6 +16686,7 @@ const TextInputBase = factory((props, ref) => {
|
|
|
17259
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;
|
|
17260
16687
|
const renderDisclaimer = useDisclaimer(disclaimerData.disclaimer, disclaimerData.disclaimerProps);
|
|
17261
16688
|
const [focused, setFocused] = useState(false);
|
|
16689
|
+
const [cursorVisible, setCursorVisible] = useState(true);
|
|
17262
16690
|
const theme = useTheme();
|
|
17263
16691
|
const { isRTL } = useDirection();
|
|
17264
16692
|
const internalInputRef = useRef(null);
|
|
@@ -17330,6 +16758,16 @@ const TextInputBase = factory((props, ref) => {
|
|
|
17330
16758
|
return '';
|
|
17331
16759
|
return '•'.repeat(length);
|
|
17332
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]);
|
|
17333
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);
|
|
17334
16772
|
const resolvedInputStyle = useMemo(() => {
|
|
17335
16773
|
const base = [styles.input];
|
|
@@ -17431,7 +16869,12 @@ const TextInputBase = factory((props, ref) => {
|
|
|
17431
16869
|
}
|
|
17432
16870
|
}, [keyboardManager, pendingFocusTarget, focusTargetId]);
|
|
17433
16871
|
const disclaimerNode = renderDisclaimer();
|
|
17434
|
-
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 }))] }));
|
|
17435
16878
|
});
|
|
17436
16879
|
|
|
17437
16880
|
const getInputTypeConfig = (type) => {
|
|
@@ -17989,18 +17432,19 @@ const useTextAreaStyles = (props) => {
|
|
|
17989
17432
|
? theme.colors.error[5]
|
|
17990
17433
|
: styleProps.focused
|
|
17991
17434
|
? theme.colors.primary[5]
|
|
17992
|
-
:
|
|
17993
|
-
? theme.backgrounds.border
|
|
17994
|
-
: 'transparent',
|
|
17435
|
+
: theme.backgrounds.border,
|
|
17995
17436
|
borderRadius: DESIGN_TOKENS.radius.lg,
|
|
17996
|
-
borderWidth:
|
|
17437
|
+
borderWidth: 2,
|
|
17997
17438
|
paddingHorizontal: DESIGN_TOKENS.spacing.sm,
|
|
17998
17439
|
paddingVertical: DESIGN_TOKENS.spacing.xs,
|
|
17440
|
+
// Match Input focus treatment on web
|
|
17999
17441
|
...(styleProps.focused && !styleProps.disabled && Platform.OS === 'web' && {
|
|
18000
17442
|
boxShadow: `0 0 0 2px ${((_a = theme.states) === null || _a === void 0 ? void 0 : _a.focusRing) || theme.colors.primary[2]}`,
|
|
18001
17443
|
}),
|
|
17444
|
+
// Light elevation similar to Input
|
|
18002
17445
|
...(!styleProps.disabled && theme.colorScheme === 'light' && {
|
|
18003
17446
|
elevation: 1,
|
|
17447
|
+
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.05)',
|
|
18004
17448
|
}),
|
|
18005
17449
|
opacity: styleProps.disabled ? DESIGN_TOKENS.opacity.disabled : 1,
|
|
18006
17450
|
},
|
|
@@ -19682,7 +19126,7 @@ const useSwitchStyles = (props) => {
|
|
|
19682
19126
|
...(Platform.OS === 'web' && { userSelect: 'none' }),
|
|
19683
19127
|
},
|
|
19684
19128
|
labelContainer: {
|
|
19685
|
-
|
|
19129
|
+
flexShrink: 1,
|
|
19686
19130
|
justifyContent: 'center',
|
|
19687
19131
|
},
|
|
19688
19132
|
labelDisabled: {
|
|
@@ -19851,8 +19295,8 @@ const Switch = factory((rawProps, ref) => {
|
|
|
19851
19295
|
const LayoutComponent = isVertical ? Column : Row;
|
|
19852
19296
|
// For vertical layouts (top/bottom), we want tighter spacing and center alignment
|
|
19853
19297
|
const layoutProps = isVertical
|
|
19854
|
-
? { gap: 'xs',
|
|
19855
|
-
: { gap: 'sm',
|
|
19298
|
+
? { gap: 'xs', align: 'center' }
|
|
19299
|
+
: { gap: 'sm', align: 'center' };
|
|
19856
19300
|
const disclaimerNode = renderDisclaimer();
|
|
19857
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] }));
|
|
19858
19302
|
});
|
|
@@ -21047,105 +20491,116 @@ const useSliderGesture = (min, max, step, restrictToTicks, ticks, disabled) => {
|
|
|
21047
20491
|
}, [min, max, step, restrictToTicks, ticks]);
|
|
21048
20492
|
return { calculateNewValue };
|
|
21049
20493
|
};
|
|
21050
|
-
const SliderTrack = ({ disabled, theme, size, orientation, activeWidth = 0, activeLeft =
|
|
20494
|
+
const SliderTrack = ({ disabled, theme, size, orientation, activeWidth = 0, activeLeft, isRange = false, trackColor, activeTrackColor, trackStyle, activeTrackStyle, trackHeight, thumbSize, }) => {
|
|
21051
20495
|
const orientationProps = getOrientationProps(orientation);
|
|
21052
|
-
const
|
|
21053
|
-
const
|
|
21054
|
-
const
|
|
20496
|
+
const resolvedThumbSize = thumbSize !== null && thumbSize !== void 0 ? thumbSize : SLIDER_CONSTANTS.THUMB_SIZE[size];
|
|
20497
|
+
const resolvedTrackHeight = trackHeight !== null && trackHeight !== void 0 ? trackHeight : SLIDER_CONSTANTS.TRACK_HEIGHT[size];
|
|
20498
|
+
const resolvedActiveLeft = activeLeft !== null && activeLeft !== void 0 ? activeLeft : (resolvedThumbSize / 2);
|
|
20499
|
+
const inactiveTrackBaseStyle = {
|
|
21055
20500
|
position: 'absolute',
|
|
21056
|
-
backgroundColor: disabled ? theme.colors.gray[2] : theme.colors.gray[3],
|
|
21057
|
-
borderRadius:
|
|
20501
|
+
backgroundColor: disabled && !trackColor ? theme.colors.gray[2] : (trackColor !== null && trackColor !== void 0 ? trackColor : theme.colors.gray[3]),
|
|
20502
|
+
borderRadius: resolvedTrackHeight / 2,
|
|
21058
20503
|
};
|
|
21059
|
-
const
|
|
20504
|
+
const activeTrackBaseStyle = {
|
|
21060
20505
|
position: 'absolute',
|
|
21061
|
-
backgroundColor: disabled ? theme.colors.gray[4] : theme.colors.primary[5],
|
|
21062
|
-
borderRadius:
|
|
20506
|
+
backgroundColor: disabled && !activeTrackColor ? theme.colors.gray[4] : (activeTrackColor !== null && activeTrackColor !== void 0 ? activeTrackColor : theme.colors.primary[5]),
|
|
20507
|
+
borderRadius: resolvedTrackHeight / 2,
|
|
21063
20508
|
};
|
|
21064
20509
|
if (orientationProps.isVertical) {
|
|
21065
|
-
return (jsxs(Fragment, { children: [jsx(View, { style:
|
|
21066
|
-
|
|
21067
|
-
|
|
21068
|
-
|
|
21069
|
-
|
|
21070
|
-
|
|
21071
|
-
|
|
21072
|
-
|
|
21073
|
-
|
|
21074
|
-
|
|
21075
|
-
|
|
21076
|
-
|
|
21077
|
-
|
|
21078
|
-
|
|
21079
|
-
|
|
21080
|
-
|
|
21081
|
-
|
|
21082
|
-
|
|
21083
|
-
|
|
21084
|
-
|
|
21085
|
-
|
|
21086
|
-
|
|
21087
|
-
|
|
21088
|
-
|
|
21089
|
-
|
|
21090
|
-
|
|
21091
|
-
|
|
21092
|
-
|
|
21093
|
-
|
|
21094
|
-
|
|
21095
|
-
|
|
21096
|
-
|
|
21097
|
-
|
|
21098
|
-
|
|
21099
|
-
|
|
20510
|
+
return (jsxs(Fragment, { children: [jsx(View, { style: [
|
|
20511
|
+
{
|
|
20512
|
+
...inactiveTrackBaseStyle,
|
|
20513
|
+
top: resolvedThumbSize / 2,
|
|
20514
|
+
bottom: resolvedThumbSize / 2,
|
|
20515
|
+
width: resolvedTrackHeight,
|
|
20516
|
+
left: (resolvedThumbSize - resolvedTrackHeight) / 2,
|
|
20517
|
+
},
|
|
20518
|
+
trackStyle,
|
|
20519
|
+
] }), activeWidth > 0 && (jsx(View, { style: [
|
|
20520
|
+
{
|
|
20521
|
+
...activeTrackBaseStyle,
|
|
20522
|
+
...(isRange ? {
|
|
20523
|
+
top: activeLeft !== null && activeLeft !== void 0 ? activeLeft : resolvedActiveLeft,
|
|
20524
|
+
height: activeWidth,
|
|
20525
|
+
} : {
|
|
20526
|
+
bottom: resolvedThumbSize / 2,
|
|
20527
|
+
height: activeWidth,
|
|
20528
|
+
}),
|
|
20529
|
+
width: resolvedTrackHeight,
|
|
20530
|
+
left: (resolvedThumbSize - resolvedTrackHeight) / 2,
|
|
20531
|
+
},
|
|
20532
|
+
activeTrackStyle,
|
|
20533
|
+
] }))] }));
|
|
20534
|
+
}
|
|
20535
|
+
return (jsxs(Fragment, { children: [jsx(View, { style: [
|
|
20536
|
+
{
|
|
20537
|
+
...inactiveTrackBaseStyle,
|
|
20538
|
+
left: resolvedThumbSize / 2,
|
|
20539
|
+
right: resolvedThumbSize / 2,
|
|
20540
|
+
height: resolvedTrackHeight,
|
|
20541
|
+
top: (SLIDER_CONSTANTS.CONTAINER_HEIGHT - resolvedTrackHeight) / 2,
|
|
20542
|
+
},
|
|
20543
|
+
trackStyle,
|
|
20544
|
+
] }), activeWidth > 0 && (jsx(View, { style: [
|
|
20545
|
+
{
|
|
20546
|
+
...activeTrackBaseStyle,
|
|
20547
|
+
left: activeLeft !== null && activeLeft !== void 0 ? activeLeft : resolvedActiveLeft,
|
|
20548
|
+
width: activeWidth,
|
|
20549
|
+
height: resolvedTrackHeight,
|
|
20550
|
+
top: (SLIDER_CONSTANTS.CONTAINER_HEIGHT - resolvedTrackHeight) / 2,
|
|
20551
|
+
},
|
|
20552
|
+
activeTrackStyle,
|
|
20553
|
+
] }))] }));
|
|
20554
|
+
};
|
|
20555
|
+
const SliderTicks = ({ ticks, disabled, theme, size, orientation, keyPrefix = 'tick', trackHeight, thumbSize, activeTickColor, tickColor, }) => {
|
|
21100
20556
|
const orientationProps = getOrientationProps(orientation);
|
|
21101
|
-
const
|
|
21102
|
-
const
|
|
20557
|
+
const resolvedThumbSize = thumbSize !== null && thumbSize !== void 0 ? thumbSize : SLIDER_CONSTANTS.THUMB_SIZE[size];
|
|
20558
|
+
const resolvedTrackHeight = trackHeight !== null && trackHeight !== void 0 ? trackHeight : SLIDER_CONSTANTS.TRACK_HEIGHT[size];
|
|
20559
|
+
const inactiveColor = disabled && !tickColor ? theme.colors.gray[2] : (tickColor !== null && tickColor !== void 0 ? tickColor : theme.colors.gray[4]);
|
|
20560
|
+
const activeColor = disabled && !activeTickColor ? theme.colors.gray[4] : (activeTickColor !== null && activeTickColor !== void 0 ? activeTickColor : theme.colors.primary[5]);
|
|
21103
20561
|
if (orientationProps.isVertical) {
|
|
21104
20562
|
return (jsxs(Fragment, { children: [ticks.map((tick, index) => (jsx(View, { style: {
|
|
21105
20563
|
position: 'absolute',
|
|
21106
|
-
top:
|
|
21107
|
-
left: (
|
|
20564
|
+
top: resolvedThumbSize / 2 + tick.position,
|
|
20565
|
+
left: (resolvedThumbSize - resolvedTrackHeight) / 2 - 3,
|
|
21108
20566
|
height: 2,
|
|
21109
|
-
width:
|
|
21110
|
-
backgroundColor: tick.isActive
|
|
21111
|
-
? (disabled ? theme.colors.gray[4] : theme.colors.primary[5])
|
|
21112
|
-
: (disabled ? theme.colors.gray[2] : theme.colors.gray[4]),
|
|
20567
|
+
width: resolvedTrackHeight + 6,
|
|
20568
|
+
backgroundColor: tick.isActive ? activeColor : inactiveColor,
|
|
21113
20569
|
borderRadius: 1,
|
|
21114
20570
|
} }, `${keyPrefix}-${tick.value}-${index}`))), ticks.map((tick, index) => (tick.label ? (jsx(View, { style: {
|
|
21115
20571
|
position: 'absolute',
|
|
21116
|
-
top:
|
|
21117
|
-
left:
|
|
20572
|
+
top: resolvedThumbSize / 2 + tick.position - 10,
|
|
20573
|
+
left: resolvedThumbSize + 8,
|
|
21118
20574
|
height: 20,
|
|
21119
20575
|
justifyContent: 'center',
|
|
21120
20576
|
}, children: jsx(Text, { size: "xs", children: tick.label }) }, `${keyPrefix}-label-${tick.value}-${index}`)) : null))] }));
|
|
21121
20577
|
}
|
|
21122
20578
|
return (jsxs(Fragment, { children: [ticks.map((tick, index) => (jsx(View, { style: {
|
|
21123
20579
|
position: 'absolute',
|
|
21124
|
-
left:
|
|
21125
|
-
top: (SLIDER_CONSTANTS.CONTAINER_HEIGHT -
|
|
20580
|
+
left: resolvedThumbSize / 2 + tick.position,
|
|
20581
|
+
top: (SLIDER_CONSTANTS.CONTAINER_HEIGHT - resolvedTrackHeight) / 2 - 3,
|
|
21126
20582
|
width: 2,
|
|
21127
|
-
height:
|
|
21128
|
-
backgroundColor: tick.isActive
|
|
21129
|
-
? (disabled ? theme.colors.gray[4] : theme.colors.primary[5])
|
|
21130
|
-
: (disabled ? theme.colors.gray[2] : theme.colors.gray[4]),
|
|
20583
|
+
height: resolvedTrackHeight + 6,
|
|
20584
|
+
backgroundColor: tick.isActive ? activeColor : inactiveColor,
|
|
21131
20585
|
borderRadius: 1,
|
|
21132
20586
|
} }, `${keyPrefix}-${tick.value}-${index}`))), ticks.map((tick, index) => (tick.label ? (jsx(View, { style: {
|
|
21133
20587
|
position: 'absolute',
|
|
21134
|
-
left:
|
|
20588
|
+
left: resolvedThumbSize / 2 + tick.position - 20,
|
|
21135
20589
|
top: SLIDER_CONSTANTS.CONTAINER_HEIGHT + 8,
|
|
21136
20590
|
width: 40,
|
|
21137
20591
|
alignItems: 'center',
|
|
21138
20592
|
}, children: jsx(Text, { size: "xs", style: { textAlign: 'center' }, children: tick.label }) }, `${keyPrefix}-label-${tick.value}-${index}`)) : null))] }));
|
|
21139
20593
|
};
|
|
21140
|
-
const SliderThumb = ({ position, disabled, theme, size, orientation, isDragging, zIndex = 1, panHandlers }) => {
|
|
20594
|
+
const SliderThumb = ({ position, disabled, theme, size, orientation, isDragging, zIndex = 1, panHandlers, thumbColor, thumbStyle, thumbSize, }) => {
|
|
21141
20595
|
const orientationProps = getOrientationProps(orientation);
|
|
21142
|
-
const
|
|
20596
|
+
const resolvedThumbSize = thumbSize !== null && thumbSize !== void 0 ? thumbSize : SLIDER_CONSTANTS.THUMB_SIZE[size];
|
|
20597
|
+
const resolvedThumbColor = disabled && !thumbColor ? theme.colors.gray[4] : (thumbColor !== null && thumbColor !== void 0 ? thumbColor : theme.colors.primary[5]);
|
|
21143
20598
|
const baseStyle = {
|
|
21144
20599
|
position: 'absolute',
|
|
21145
|
-
width:
|
|
21146
|
-
height:
|
|
21147
|
-
backgroundColor:
|
|
21148
|
-
borderRadius:
|
|
20600
|
+
width: resolvedThumbSize,
|
|
20601
|
+
height: resolvedThumbSize,
|
|
20602
|
+
backgroundColor: resolvedThumbColor,
|
|
20603
|
+
borderRadius: resolvedThumbSize / 2,
|
|
21149
20604
|
borderWidth: 2,
|
|
21150
20605
|
borderColor: 'white',
|
|
21151
20606
|
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)',
|
|
@@ -21154,36 +20609,43 @@ const SliderThumb = ({ position, disabled, theme, size, orientation, isDragging,
|
|
|
21154
20609
|
zIndex,
|
|
21155
20610
|
};
|
|
21156
20611
|
if (orientationProps.isVertical) {
|
|
21157
|
-
return (jsx(View, { style:
|
|
21158
|
-
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
|
|
20612
|
+
return (jsx(View, { style: [
|
|
20613
|
+
baseStyle,
|
|
20614
|
+
{
|
|
20615
|
+
top: position,
|
|
20616
|
+
left: 0,
|
|
20617
|
+
},
|
|
20618
|
+
thumbStyle,
|
|
20619
|
+
], ...panHandlers }));
|
|
21162
20620
|
}
|
|
21163
|
-
return (jsx(View, { style:
|
|
21164
|
-
|
|
21165
|
-
|
|
21166
|
-
|
|
21167
|
-
|
|
20621
|
+
return (jsx(View, { style: [
|
|
20622
|
+
baseStyle,
|
|
20623
|
+
{
|
|
20624
|
+
left: position,
|
|
20625
|
+
top: (SLIDER_CONSTANTS.CONTAINER_HEIGHT - resolvedThumbSize) / 2,
|
|
20626
|
+
},
|
|
20627
|
+
thumbStyle,
|
|
20628
|
+
], ...panHandlers }));
|
|
21168
20629
|
};
|
|
21169
20630
|
const SliderLabel = ({ label }) => (jsx(View, { style: { marginBottom: 8 }, children: typeof label === 'string' ? (jsx(Text, { size: "sm", weight: "medium", children: label })) : (label) }));
|
|
21170
|
-
const SliderValueLabel = ({ value, position, size, orientation, isCard = false }) => {
|
|
20631
|
+
const SliderValueLabel = ({ value, position, size, orientation, isCard = false, thumbSize, }) => {
|
|
21171
20632
|
const orientationProps = getOrientationProps(orientation);
|
|
21172
|
-
const
|
|
20633
|
+
const resolvedThumbSize = thumbSize !== null && thumbSize !== void 0 ? thumbSize : SLIDER_CONSTANTS.THUMB_SIZE[size];
|
|
21173
20634
|
// round number to 2 decimal places for display
|
|
21174
20635
|
const displayValue = typeof value === 'number' ? value.toFixed(2) : value;
|
|
21175
20636
|
if (orientationProps.isVertical) {
|
|
20637
|
+
const verticalLabelOffset = resolvedThumbSize + 16; // keep label clear of the thumb
|
|
21176
20638
|
return (jsx(View, { style: {
|
|
21177
20639
|
position: 'absolute',
|
|
21178
|
-
top: position + (
|
|
21179
|
-
right:
|
|
20640
|
+
top: position + (resolvedThumbSize / 2) - 10,
|
|
20641
|
+
right: verticalLabelOffset,
|
|
21180
20642
|
height: 20,
|
|
21181
20643
|
justifyContent: 'center',
|
|
21182
20644
|
}, children: isCard ? (jsx(Card, { p: "xs", variant: "filled", children: jsx(Text, { size: "sm", children: displayValue }) })) : (jsx(Text, { size: "sm", children: displayValue })) }));
|
|
21183
20645
|
}
|
|
21184
20646
|
return (jsx(View, { style: {
|
|
21185
20647
|
position: 'absolute',
|
|
21186
|
-
left: position + (
|
|
20648
|
+
left: position + (resolvedThumbSize / 2) - 50,
|
|
21187
20649
|
bottom: SLIDER_CONSTANTS.CONTAINER_HEIGHT - 6, // Moved closer to thumb
|
|
21188
20650
|
width: 100,
|
|
21189
20651
|
alignItems: 'center',
|
|
@@ -21199,9 +20661,34 @@ const SLIDER_SIZE_SCALE = {
|
|
|
21199
20661
|
'2xl': 'lg',
|
|
21200
20662
|
'3xl': 'lg',
|
|
21201
20663
|
};
|
|
20664
|
+
const resolvePaletteColor = (themeColors, scheme) => {
|
|
20665
|
+
if (!scheme || typeof scheme !== 'string') {
|
|
20666
|
+
return undefined;
|
|
20667
|
+
}
|
|
20668
|
+
const palette = themeColors[scheme];
|
|
20669
|
+
if (Array.isArray(palette)) {
|
|
20670
|
+
return palette;
|
|
20671
|
+
}
|
|
20672
|
+
return undefined;
|
|
20673
|
+
};
|
|
20674
|
+
const resolveSliderColors = (theme, { colorScheme, trackColor, activeTrackColor, thumbColor, tickColor, activeTickColor, }) => {
|
|
20675
|
+
var _a, _b;
|
|
20676
|
+
const palette = resolvePaletteColor(theme.colors, colorScheme);
|
|
20677
|
+
const schemeColor = (_b = (_a = palette === null || palette === void 0 ? void 0 : palette[5]) !== null && _a !== void 0 ? _a : (typeof colorScheme === 'string' ? colorScheme : undefined)) !== null && _b !== void 0 ? _b : theme.colors.primary[5];
|
|
20678
|
+
const resolvedActiveTrack = activeTrackColor !== null && activeTrackColor !== void 0 ? activeTrackColor : schemeColor;
|
|
20679
|
+
const defaultTrackColor = theme.colorScheme === 'dark' ? theme.colors.gray[6] : theme.colors.gray[3];
|
|
20680
|
+
const defaultTickColor = theme.colorScheme === 'dark' ? theme.colors.gray[5] : theme.colors.gray[4];
|
|
20681
|
+
return {
|
|
20682
|
+
trackColor: trackColor !== null && trackColor !== void 0 ? trackColor : defaultTrackColor,
|
|
20683
|
+
activeTrackColor: resolvedActiveTrack,
|
|
20684
|
+
thumbColor: thumbColor !== null && thumbColor !== void 0 ? thumbColor : resolvedActiveTrack,
|
|
20685
|
+
tickColor: tickColor !== null && tickColor !== void 0 ? tickColor : defaultTickColor,
|
|
20686
|
+
activeTickColor: activeTickColor !== null && activeTickColor !== void 0 ? activeTickColor : resolvedActiveTrack,
|
|
20687
|
+
};
|
|
20688
|
+
};
|
|
21202
20689
|
// Optimized Single Slider Component
|
|
21203
20690
|
const Slider = factory((props, ref) => {
|
|
21204
|
-
const { value, defaultValue = 0, onChange, min = 0, max = 100, step = 1, disabled = false, size = 'md', orientation = 'horizontal', containerSize, fullWidth = true, label, valueLabel, valueLabelAlwaysOn = false, ticks, showTicks = false, restrictToTicks = false, style, ...spacingProps } = props;
|
|
20691
|
+
const { value, defaultValue = 0, onChange, min = 0, max = 100, step = 1, disabled = false, size = 'md', orientation = 'horizontal', containerSize, fullWidth = true, label, valueLabel, valueLabelAlwaysOn = false, ticks, showTicks = false, restrictToTicks = false, trackColor, activeTrackColor, thumbColor, trackSize, thumbSize: thumbSizeProp, colorScheme = 'primary', trackStyle, activeTrackStyle, thumbStyle, tickColor, activeTickColor, style, ...spacingProps } = props;
|
|
21205
20692
|
const theme = useTheme();
|
|
21206
20693
|
const [isDragging, setIsDragging] = useState(false);
|
|
21207
20694
|
// Uncontrolled internal value
|
|
@@ -21230,14 +20717,31 @@ const Slider = factory((props, ref) => {
|
|
|
21230
20717
|
: 'md'
|
|
21231
20718
|
: (resolvedSliderSize !== null && resolvedSliderSize !== void 0 ? resolvedSliderSize : 'md');
|
|
21232
20719
|
const orientationProps = getOrientationProps(orientation, containerSize);
|
|
21233
|
-
const thumbSize = SLIDER_CONSTANTS.THUMB_SIZE[sliderSize];
|
|
20720
|
+
const thumbSize = thumbSizeProp !== null && thumbSizeProp !== void 0 ? thumbSizeProp : SLIDER_CONSTANTS.THUMB_SIZE[sliderSize];
|
|
20721
|
+
const trackHeight = trackSize !== null && trackSize !== void 0 ? trackSize : SLIDER_CONSTANTS.TRACK_HEIGHT[sliderSize];
|
|
21234
20722
|
// Memoized processed value
|
|
21235
20723
|
const clampedValue = useSliderValue(isControlled ? value : internal, min, max, step, restrictToTicks, ticks, false);
|
|
21236
20724
|
// Memoized value label handling
|
|
20725
|
+
const defaultValueFormatter = useCallback((val) => Math.round(val).toString(), []);
|
|
20726
|
+
const resolvedValueLabel = useMemo(() => {
|
|
20727
|
+
if (valueLabel === null)
|
|
20728
|
+
return null;
|
|
20729
|
+
if (valueLabel)
|
|
20730
|
+
return valueLabel;
|
|
20731
|
+
return defaultValueFormatter;
|
|
20732
|
+
}, [valueLabel, defaultValueFormatter]);
|
|
21237
20733
|
const labelConfig = useMemo(() => ({
|
|
21238
|
-
shouldShow:
|
|
21239
|
-
formatter:
|
|
21240
|
-
}), [
|
|
20734
|
+
shouldShow: !!resolvedValueLabel && (valueLabelAlwaysOn || isDragging || (Platform.OS === 'web' && isHovering)),
|
|
20735
|
+
formatter: resolvedValueLabel !== null && resolvedValueLabel !== void 0 ? resolvedValueLabel : defaultValueFormatter,
|
|
20736
|
+
}), [resolvedValueLabel, valueLabelAlwaysOn, isDragging, isHovering, defaultValueFormatter]);
|
|
20737
|
+
const sliderColors = useMemo(() => resolveSliderColors(theme, {
|
|
20738
|
+
colorScheme,
|
|
20739
|
+
trackColor,
|
|
20740
|
+
activeTrackColor,
|
|
20741
|
+
thumbColor,
|
|
20742
|
+
tickColor,
|
|
20743
|
+
activeTickColor,
|
|
20744
|
+
}), [theme, colorScheme, trackColor, activeTrackColor, thumbColor, tickColor, activeTickColor]);
|
|
21241
20745
|
// Memoized position calculations
|
|
21242
20746
|
const positions = useMemo(() => {
|
|
21243
20747
|
var _a, _b;
|
|
@@ -21367,6 +20871,7 @@ const Slider = factory((props, ref) => {
|
|
|
21367
20871
|
height: fullWidth && orientation === 'vertical' ? '100%' : orientationProps.containerHeight,
|
|
21368
20872
|
justifyContent: 'center',
|
|
21369
20873
|
position: 'relative',
|
|
20874
|
+
...(Platform.OS === 'web' && orientation === 'vertical' ? { touchAction: 'none' } : null),
|
|
21370
20875
|
}, onLayout: (event) => {
|
|
21371
20876
|
// When fullWidth is enabled, track the actual container dimensions
|
|
21372
20877
|
if (fullWidth) {
|
|
@@ -21380,11 +20885,11 @@ const Slider = factory((props, ref) => {
|
|
|
21380
20885
|
}, onStartShouldSetResponder: () => !isDragging, onResponderGrant: handlePress, ...(Platform.OS === 'web' && {
|
|
21381
20886
|
onMouseEnter: () => setIsHovering(true),
|
|
21382
20887
|
onMouseLeave: () => setIsHovering(false),
|
|
21383
|
-
}), ...panResponder.panHandlers, children: [jsx(SliderTrack, { disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, activeWidth: positions.activeLength }), jsx(SliderTicks, { ticks: allTicks, disabled: disabled, theme: theme, size: sliderSize, orientation: orientation }), jsx(SliderThumb, { position: positions.thumbPosition, disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, isDragging: isDragging }), labelConfig.shouldShow && (jsx(SliderValueLabel, { value: labelConfig.formatter(clampedValue), position: positions.thumbPosition, size: sliderSize, orientation: orientation, isCard: true }))] })] }));
|
|
20888
|
+
}), ...panResponder.panHandlers, children: [jsx(SliderTrack, { disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, activeWidth: positions.activeLength, trackColor: sliderColors.trackColor, activeTrackColor: sliderColors.activeTrackColor, trackStyle: trackStyle, activeTrackStyle: activeTrackStyle, trackHeight: trackHeight, thumbSize: thumbSize }), jsx(SliderTicks, { ticks: allTicks, disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, trackHeight: trackHeight, thumbSize: thumbSize, tickColor: sliderColors.tickColor, activeTickColor: sliderColors.activeTickColor }), jsx(SliderThumb, { position: positions.thumbPosition, disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, isDragging: isDragging, thumbColor: sliderColors.thumbColor, thumbStyle: thumbStyle, thumbSize: thumbSize }), labelConfig.shouldShow && (jsx(SliderValueLabel, { value: labelConfig.formatter(clampedValue), position: positions.thumbPosition, size: sliderSize, orientation: orientation, isCard: true, thumbSize: thumbSize }))] })] }));
|
|
21384
20889
|
});
|
|
21385
20890
|
// Optimized Range Slider Component
|
|
21386
20891
|
const RangeSlider = factory((props, ref) => {
|
|
21387
|
-
const { value = [0, 100], onChange, min = 0, max = 100, step = 1, disabled = false, size = 'md', orientation = 'horizontal', containerSize, fullWidth = true, label, valueLabel, valueLabelAlwaysOn = false, ticks, showTicks = false, restrictToTicks = false, pushOnOverlap = true, style, ...spacingProps } = props;
|
|
20892
|
+
const { value = [0, 100], onChange, min = 0, max = 100, step = 1, disabled = false, size = 'md', orientation = 'horizontal', containerSize, fullWidth = true, label, valueLabel, valueLabelAlwaysOn = false, ticks, showTicks = false, restrictToTicks = false, pushOnOverlap = true, trackColor, activeTrackColor, thumbColor, trackSize, thumbSize: thumbSizeProp, colorScheme = 'primary', trackStyle, activeTrackStyle, thumbStyle, tickColor, activeTickColor, style, ...spacingProps } = props;
|
|
21388
20893
|
const theme = useTheme();
|
|
21389
20894
|
const [dragState, setDragState] = useState({ thumb: null });
|
|
21390
20895
|
const [isHovering, setIsHovering] = useState(false);
|
|
@@ -21404,8 +20909,17 @@ const RangeSlider = factory((props, ref) => {
|
|
|
21404
20909
|
: 'md'
|
|
21405
20910
|
: (rangeResolvedSliderSize !== null && rangeResolvedSliderSize !== void 0 ? rangeResolvedSliderSize : 'md');
|
|
21406
20911
|
const orientationProps = getOrientationProps(orientation, containerSize);
|
|
21407
|
-
const thumbSize = SLIDER_CONSTANTS.THUMB_SIZE[sliderSize];
|
|
20912
|
+
const thumbSize = thumbSizeProp !== null && thumbSizeProp !== void 0 ? thumbSizeProp : SLIDER_CONSTANTS.THUMB_SIZE[sliderSize];
|
|
20913
|
+
const trackHeight = trackSize !== null && trackSize !== void 0 ? trackSize : SLIDER_CONSTANTS.TRACK_HEIGHT[sliderSize];
|
|
21408
20914
|
useRef(null);
|
|
20915
|
+
const sliderColors = useMemo(() => resolveSliderColors(theme, {
|
|
20916
|
+
colorScheme,
|
|
20917
|
+
trackColor,
|
|
20918
|
+
activeTrackColor,
|
|
20919
|
+
thumbColor,
|
|
20920
|
+
tickColor,
|
|
20921
|
+
activeTickColor,
|
|
20922
|
+
}), [theme, colorScheme, trackColor, activeTrackColor, thumbColor, tickColor, activeTickColor]);
|
|
21409
20923
|
// Memoized processed values
|
|
21410
20924
|
const [minValue, maxValue] = useSliderValue(value, min, max, step, restrictToTicks, ticks, true);
|
|
21411
20925
|
// Memoized backward compatibility handling
|
|
@@ -21641,6 +21155,7 @@ const RangeSlider = factory((props, ref) => {
|
|
|
21641
21155
|
height: fullWidth && orientation === 'vertical' ? '100%' : orientationProps.containerHeight,
|
|
21642
21156
|
justifyContent: 'center',
|
|
21643
21157
|
position: 'relative',
|
|
21158
|
+
...(Platform.OS === 'web' && orientation === 'vertical' ? { touchAction: 'none' } : null),
|
|
21644
21159
|
}, onLayout: (event) => {
|
|
21645
21160
|
// When fullWidth is enabled, track the actual container dimensions
|
|
21646
21161
|
if (fullWidth) {
|
|
@@ -21654,7 +21169,7 @@ const RangeSlider = factory((props, ref) => {
|
|
|
21654
21169
|
}, onStartShouldSetResponder: () => true, onResponderGrant: handleTrackPress, ...(Platform.OS === 'web' && {
|
|
21655
21170
|
onMouseEnter: () => setIsHovering(true),
|
|
21656
21171
|
onMouseLeave: () => setIsHovering(false),
|
|
21657
|
-
}), collapsable: false, children: [jsx(SliderTrack, { disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, activeWidth: positions.activeWidth, activeLeft: positions.activeLeft, isRange: true }), jsx(SliderTicks, { ticks: allTicks, disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, keyPrefix: "range-tick" }), jsx(SliderThumb, { position: positions.minThumbPosition, disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, isDragging: dragState.thumb === 'min', zIndex: dragState.thumb === 'min' ? 10 : 1, panHandlers: minThumbPanResponder.panHandlers }), jsx(SliderThumb, { position: positions.maxThumbPosition, disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, isDragging: dragState.thumb === 'max', zIndex: dragState.thumb === 'max' ? 10 : 2, panHandlers: maxThumbPanResponder.panHandlers }), labelConfig.shouldShow && (jsxs(Fragment, { children: [jsx(SliderValueLabel, { value: labelConfig.formatter(minValue, 0), position: positions.minThumbPosition, size: sliderSize, orientation: orientation, isCard: true }), jsx(SliderValueLabel, { value: labelConfig.formatter(maxValue, 1), position: positions.maxThumbPosition, size: sliderSize, orientation: orientation, isCard: true })] }))] })] }));
|
|
21172
|
+
}), collapsable: false, children: [jsx(SliderTrack, { disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, activeWidth: positions.activeWidth, activeLeft: positions.activeLeft, isRange: true, trackColor: sliderColors.trackColor, activeTrackColor: sliderColors.activeTrackColor, trackStyle: trackStyle, activeTrackStyle: activeTrackStyle, trackHeight: trackHeight, thumbSize: thumbSize }), jsx(SliderTicks, { ticks: allTicks, disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, keyPrefix: "range-tick", trackHeight: trackHeight, thumbSize: thumbSize, tickColor: sliderColors.tickColor, activeTickColor: sliderColors.activeTickColor }), jsx(SliderThumb, { position: positions.minThumbPosition, disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, isDragging: dragState.thumb === 'min', zIndex: dragState.thumb === 'min' ? 10 : 1, panHandlers: minThumbPanResponder.panHandlers, thumbColor: sliderColors.thumbColor, thumbStyle: thumbStyle, thumbSize: thumbSize }), jsx(SliderThumb, { position: positions.maxThumbPosition, disabled: disabled, theme: theme, size: sliderSize, orientation: orientation, isDragging: dragState.thumb === 'max', zIndex: dragState.thumb === 'max' ? 10 : 2, panHandlers: maxThumbPanResponder.panHandlers, thumbColor: sliderColors.thumbColor, thumbStyle: thumbStyle, thumbSize: thumbSize }), labelConfig.shouldShow && (jsxs(Fragment, { children: [jsx(SliderValueLabel, { value: labelConfig.formatter(minValue, 0), position: positions.minThumbPosition, size: sliderSize, orientation: orientation, isCard: true, thumbSize: thumbSize }), jsx(SliderValueLabel, { value: labelConfig.formatter(maxValue, 1), position: positions.maxThumbPosition, size: sliderSize, orientation: orientation, isCard: true, thumbSize: thumbSize })] }))] })] }));
|
|
21658
21173
|
});
|
|
21659
21174
|
|
|
21660
21175
|
const clampNumber$1 = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
@@ -27395,7 +26910,7 @@ const MiniCalendar = ({ value, onChange, defaultValue, numberOfDays = 7, default
|
|
|
27395
26910
|
}
|
|
27396
26911
|
onChange === null || onChange === void 0 ? void 0 : onChange(date);
|
|
27397
26912
|
}, [isControlled, maxDate, minDate, onChange]);
|
|
27398
|
-
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 }) => [
|
|
27399
26914
|
{
|
|
27400
26915
|
padding: 8,
|
|
27401
26916
|
borderRadius: 6,
|
|
@@ -27407,7 +26922,7 @@ const MiniCalendar = ({ value, onChange, defaultValue, numberOfDays = 7, default
|
|
|
27407
26922
|
borderRadius: 6,
|
|
27408
26923
|
backgroundColor: pressed ? theme.colors.gray[2] : 'transparent',
|
|
27409
26924
|
},
|
|
27410
|
-
], ...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) => {
|
|
27411
26926
|
const isSelected = selectedDate ? dateUtils$1.isSameDay(date, selectedDate) : false;
|
|
27412
26927
|
const isToday = dateUtils$1.isToday(date);
|
|
27413
26928
|
const isWeekend = dateUtils$1.isWeekend(date);
|
|
@@ -30148,6 +29663,7 @@ function MenuBase(props, ref) {
|
|
|
30148
29663
|
const overlayId = openOverlay({
|
|
30149
29664
|
content: menuDropdown,
|
|
30150
29665
|
anchor: { x: positionResult.x, y: positionResult.y, width: overlaySize.width, height: overlaySize.height },
|
|
29666
|
+
placement: positionResult.placement || position,
|
|
30151
29667
|
closeOnClickOutside,
|
|
30152
29668
|
closeOnEscape,
|
|
30153
29669
|
strategy,
|
|
@@ -31548,13 +31064,13 @@ function Indicator({ size = 'sm', color, borderColor, borderWidth = 1, placement
|
|
|
31548
31064
|
|
|
31549
31065
|
const AVATAR_ALLOWED_SIZES = ['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'];
|
|
31550
31066
|
const AVATAR_SIZE_SCALE = {
|
|
31551
|
-
xs: { avatar: 24,
|
|
31552
|
-
sm: { avatar: 32,
|
|
31553
|
-
md: { avatar: 40,
|
|
31554
|
-
lg: { avatar: 48,
|
|
31555
|
-
xl: { avatar: 64,
|
|
31556
|
-
'2xl': { avatar: 80,
|
|
31557
|
-
'3xl': { avatar: 96,
|
|
31067
|
+
xs: { avatar: 24, indicator: 6, text: 'xs' },
|
|
31068
|
+
sm: { avatar: 32, indicator: 8, text: 'xs' },
|
|
31069
|
+
md: { avatar: 40, indicator: 10, text: 'sm' },
|
|
31070
|
+
lg: { avatar: 48, indicator: 12, text: 'md' },
|
|
31071
|
+
xl: { avatar: 64, indicator: 16, text: 'lg' },
|
|
31072
|
+
'2xl': { avatar: 80, indicator: 20, text: 'xl' },
|
|
31073
|
+
'3xl': { avatar: 96, indicator: 24, text: '2xl' },
|
|
31558
31074
|
};
|
|
31559
31075
|
const BASE_AVATAR_METRICS = AVATAR_SIZE_SCALE.md;
|
|
31560
31076
|
function resolveAvatarMetrics(value) {
|
|
@@ -31572,11 +31088,11 @@ function resolveAvatarMetrics(value) {
|
|
|
31572
31088
|
}
|
|
31573
31089
|
function calculateNumericMetrics$1(value) {
|
|
31574
31090
|
const ratio = value / BASE_AVATAR_METRICS.avatar;
|
|
31575
|
-
const
|
|
31091
|
+
const indicator = Math.max(4, Math.round(BASE_AVATAR_METRICS.indicator * ratio));
|
|
31576
31092
|
const text = pickTextSize(value);
|
|
31577
31093
|
return {
|
|
31578
31094
|
avatar: value,
|
|
31579
|
-
|
|
31095
|
+
indicator,
|
|
31580
31096
|
text,
|
|
31581
31097
|
};
|
|
31582
31098
|
}
|
|
@@ -31595,9 +31111,9 @@ function pickTextSize(value) {
|
|
|
31595
31111
|
return 'sm';
|
|
31596
31112
|
return 'xs';
|
|
31597
31113
|
}
|
|
31598
|
-
function Avatar({ size = 'md', src, fallback, backgroundColor, textColor = 'white', online,
|
|
31114
|
+
function Avatar({ size = 'md', src, fallback, backgroundColor, textColor = 'white', online, indicatorColor, style, accessibilityLabel, label, description, gap = 8, showText = true, }) {
|
|
31599
31115
|
const theme = useTheme();
|
|
31600
|
-
const { avatar: avatarSize,
|
|
31116
|
+
const { avatar: avatarSize, indicator: indicatorSize, text: textSize } = resolveAvatarMetrics(size);
|
|
31601
31117
|
const avatarStyle = {
|
|
31602
31118
|
width: avatarSize,
|
|
31603
31119
|
height: avatarSize,
|
|
@@ -31615,7 +31131,7 @@ function Avatar({ size = 'md', src, fallback, backgroundColor, textColor = 'whit
|
|
|
31615
31131
|
width: avatarSize,
|
|
31616
31132
|
height: avatarSize,
|
|
31617
31133
|
borderRadius: avatarSize / 2,
|
|
31618
|
-
}, accessibilityLabel: accessibilityLabel })) : (jsx(Text, { size: textSize, color: textColor, weight: "semibold", style: { textAlign: 'center' }, children: fallback || '?' })) }), online && (jsx(Indicator, { size:
|
|
31134
|
+
}, accessibilityLabel: accessibilityLabel })) : (jsx(Text, { size: textSize, color: textColor, weight: "semibold", style: { textAlign: 'center' }, children: fallback || '?' })) }), online && (jsx(Indicator, { size: indicatorSize, color: indicatorColor || theme.colors.success[5], borderColor: theme.colors.gray[0], placement: "bottom-right" }))] }));
|
|
31619
31135
|
if (label || description) {
|
|
31620
31136
|
return (jsxs(View, { style: { flexDirection: 'row', alignItems: 'center' }, children: [content, showText && (jsxs(View, { style: { marginLeft: gap, justifyContent: 'center' }, children: [label && (typeof label === 'string' ? (jsx(Text, { size: textSize, weight: "semibold", children: label })) : label), description && (typeof description === 'string' ? (jsx(Text, { size: textSize, color: theme.colors.gray[6], children: description })) : description)] }))] }));
|
|
31621
31137
|
}
|
|
@@ -32117,7 +31633,7 @@ function usePopoverContext(component) {
|
|
|
32117
31633
|
const DEFAULT_ARROW_SIZE = 7;
|
|
32118
31634
|
const PopoverBase = (props, ref) => {
|
|
32119
31635
|
var _a;
|
|
32120
|
-
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
|
|
32121
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;
|
|
32122
31638
|
const theme = useTheme();
|
|
32123
31639
|
const { spacingProps } = extractSpacingProps(rest);
|
|
@@ -32129,9 +31645,18 @@ const PopoverBase = (props, ref) => {
|
|
|
32129
31645
|
const openedRef = useRef(opened);
|
|
32130
31646
|
const closingReasonRef = useRef(null);
|
|
32131
31647
|
const anchorMeasurementsRef = useRef(null);
|
|
31648
|
+
const hoverTimeoutRef = useRef(null);
|
|
32132
31649
|
useEffect(() => {
|
|
32133
31650
|
openedRef.current = opened;
|
|
32134
31651
|
}, [opened]);
|
|
31652
|
+
// Cleanup hover timeout on unmount
|
|
31653
|
+
useEffect(() => {
|
|
31654
|
+
return () => {
|
|
31655
|
+
if (hoverTimeoutRef.current) {
|
|
31656
|
+
clearTimeout(hoverTimeoutRef.current);
|
|
31657
|
+
}
|
|
31658
|
+
};
|
|
31659
|
+
}, []);
|
|
32135
31660
|
const resolvedOffset = typeof offset === 'number' ? offset : (_a = offset === null || offset === void 0 ? void 0 : offset.mainAxis) !== null && _a !== void 0 ? _a : 8;
|
|
32136
31661
|
const resolvedFlip = preventPositionChangeWhenVisible
|
|
32137
31662
|
? false
|
|
@@ -32144,7 +31669,7 @@ const PopoverBase = (props, ref) => {
|
|
|
32144
31669
|
? false
|
|
32145
31670
|
: true;
|
|
32146
31671
|
const resolvedStrategy = floatingStrategy !== null && floatingStrategy !== void 0 ? floatingStrategy : 'fixed';
|
|
32147
|
-
const { position: positioningResult, anchorRef, popoverRef, showOverlay, hideOverlay, updatePosition } = useDropdownPositioning({
|
|
31672
|
+
const { position: positioningResult, anchorRef, popoverRef, showOverlay, hideOverlay, updatePosition, isPositioning } = useDropdownPositioning({
|
|
32148
31673
|
isOpen: opened && !disabled && !!dropdownState,
|
|
32149
31674
|
placement: position,
|
|
32150
31675
|
offset: resolvedOffset,
|
|
@@ -32156,9 +31681,20 @@ const PopoverBase = (props, ref) => {
|
|
|
32156
31681
|
fallbackPlacements,
|
|
32157
31682
|
viewport,
|
|
32158
31683
|
onClose: () => handleOverlayClose('dismiss'),
|
|
32159
|
-
closeOnClickOutside,
|
|
31684
|
+
closeOnClickOutside: trigger === 'hover' ? false : closeOnClickOutside,
|
|
32160
31685
|
closeOnEscape,
|
|
32161
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]);
|
|
32162
31698
|
const popoverStyles = useMemo(() => createPopoverStyles(theme)({
|
|
32163
31699
|
radius,
|
|
32164
31700
|
shadow,
|
|
@@ -32262,6 +31798,28 @@ const PopoverBase = (props, ref) => {
|
|
|
32262
31798
|
openPopover();
|
|
32263
31799
|
}
|
|
32264
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]);
|
|
32265
31823
|
useEffect(() => {
|
|
32266
31824
|
if (opened) {
|
|
32267
31825
|
updateAnchorMeasurements();
|
|
@@ -32320,14 +31878,26 @@ const PopoverBase = (props, ref) => {
|
|
|
32320
31878
|
if (typeof resolvedMaxHeight === 'number')
|
|
32321
31879
|
sizeStyles.maxHeight = resolvedMaxHeight;
|
|
32322
31880
|
const dropdownStyle = [popoverStyles.dropdown, dropdownState.style, sizeStyles];
|
|
32323
|
-
|
|
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) }))] }));
|
|
32324
31894
|
showOverlay(content, {
|
|
32325
31895
|
width: widthOverride,
|
|
32326
31896
|
maxHeight: resolvedMaxHeight,
|
|
32327
31897
|
zIndex,
|
|
32328
31898
|
});
|
|
32329
31899
|
onPositionChange === null || onPositionChange === void 0 ? void 0 : onPositionChange(positioningResult.placement);
|
|
32330
|
-
}, [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]);
|
|
32331
31901
|
useEffect(() => {
|
|
32332
31902
|
return () => {
|
|
32333
31903
|
hideOverlay();
|
|
@@ -32348,6 +31918,8 @@ const PopoverBase = (props, ref) => {
|
|
|
32348
31918
|
open: openPopover,
|
|
32349
31919
|
close: () => closePopover('programmatic'),
|
|
32350
31920
|
toggle: togglePopover,
|
|
31921
|
+
hoverOpen: handleHoverOpen,
|
|
31922
|
+
hoverClose: handleHoverClose,
|
|
32351
31923
|
registerDropdown,
|
|
32352
31924
|
unregisterDropdown,
|
|
32353
31925
|
anchorRef,
|
|
@@ -32356,7 +31928,8 @@ const PopoverBase = (props, ref) => {
|
|
|
32356
31928
|
withRoles,
|
|
32357
31929
|
disabled,
|
|
32358
31930
|
returnFocus,
|
|
32359
|
-
|
|
31931
|
+
trigger,
|
|
31932
|
+
}), [opened, openPopover, closePopover, togglePopover, handleHoverOpen, handleHoverClose, registerDropdown, unregisterDropdown, anchorRef, targetId, dropdownId, withRoles, disabled, returnFocus, trigger]);
|
|
32360
31933
|
const setContainerRef = useCallback((node) => {
|
|
32361
31934
|
if (typeof ref === 'function') {
|
|
32362
31935
|
ref(node);
|
|
@@ -32406,16 +31979,44 @@ const PopoverTargetBase = (props, ref) => {
|
|
|
32406
31979
|
: { id: context.targetId };
|
|
32407
31980
|
const composedRef = mergeRefs(children.ref, externalTargetRef);
|
|
32408
31981
|
const triggerHandlers = {};
|
|
32409
|
-
|
|
32410
|
-
|
|
32411
|
-
|
|
32412
|
-
|
|
32413
|
-
|
|
32414
|
-
|
|
32415
|
-
|
|
32416
|
-
|
|
32417
|
-
|
|
32418
|
-
|
|
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
|
+
}
|
|
32419
32020
|
if (Platform.OS === 'web') {
|
|
32420
32021
|
triggerHandlers.onKeyDown = (event) => {
|
|
32421
32022
|
const tgt = targetProps;
|
|
@@ -32437,7 +32038,14 @@ const PopoverTargetBase = (props, ref) => {
|
|
|
32437
32038
|
};
|
|
32438
32039
|
}
|
|
32439
32040
|
const dynamicRefProp = { [refProp]: composedRef };
|
|
32440
|
-
|
|
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
|
+
}
|
|
32441
32049
|
delete sanitizedTargetProps.onKeyDown;
|
|
32442
32050
|
const mergedProps = {
|
|
32443
32051
|
...sanitizedTargetProps,
|
|
@@ -32449,7 +32057,7 @@ const PopoverTargetBase = (props, ref) => {
|
|
|
32449
32057
|
mergedProps.disabled = true;
|
|
32450
32058
|
}
|
|
32451
32059
|
const anchorWrapperRef = mergeRefs(context.anchorRef, ref);
|
|
32452
|
-
return (jsx(View, { ref: anchorWrapperRef, collapsable: false, children: cloneElement(children, mergedProps) }));
|
|
32060
|
+
return (jsx(View, { ref: anchorWrapperRef, collapsable: false, ...wrapperHoverHandlers, children: cloneElement(children, mergedProps) }));
|
|
32453
32061
|
};
|
|
32454
32062
|
const PopoverDropdownBase = (props, _ref) => {
|
|
32455
32063
|
const { children, trapFocus = false, keepMounted, style, testID, ...rest } = props;
|
|
@@ -32493,8 +32101,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
|
|
|
32493
32101
|
const [side, alignment] = placement.split('-');
|
|
32494
32102
|
switch (side) {
|
|
32495
32103
|
case 'top':
|
|
32104
|
+
// Arrow points down, hide the borders that overlap with content (top-left corner after rotation)
|
|
32496
32105
|
return {
|
|
32497
32106
|
...base,
|
|
32107
|
+
borderTopWidth: 0,
|
|
32108
|
+
borderLeftWidth: 0,
|
|
32498
32109
|
bottom: -arrowSize,
|
|
32499
32110
|
left: alignment === 'end'
|
|
32500
32111
|
? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
|
|
@@ -32504,8 +32115,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
|
|
|
32504
32115
|
marginLeft: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
|
|
32505
32116
|
};
|
|
32506
32117
|
case 'bottom':
|
|
32118
|
+
// Arrow points up, hide the borders that overlap with content (bottom-right corner after rotation)
|
|
32507
32119
|
return {
|
|
32508
32120
|
...base,
|
|
32121
|
+
borderBottomWidth: 0,
|
|
32122
|
+
borderRightWidth: 0,
|
|
32509
32123
|
top: -arrowSize,
|
|
32510
32124
|
left: alignment === 'end'
|
|
32511
32125
|
? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
|
|
@@ -32515,8 +32129,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
|
|
|
32515
32129
|
marginLeft: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
|
|
32516
32130
|
};
|
|
32517
32131
|
case 'left':
|
|
32132
|
+
// Arrow points right, hide the borders that overlap with content (bottom-left corner after rotation)
|
|
32518
32133
|
return {
|
|
32519
32134
|
...base,
|
|
32135
|
+
borderBottomWidth: 0,
|
|
32136
|
+
borderLeftWidth: 0,
|
|
32520
32137
|
right: -arrowSize,
|
|
32521
32138
|
top: alignment === 'end'
|
|
32522
32139
|
? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
|
|
@@ -32526,8 +32143,11 @@ function getArrowStyle(placement, arrowSize, arrowRadius, arrowOffset, arrowPosi
|
|
|
32526
32143
|
marginTop: alignment || arrowPosition === 'side' ? 0 : -arrowSize,
|
|
32527
32144
|
};
|
|
32528
32145
|
case 'right':
|
|
32146
|
+
// Arrow points left, hide the borders that overlap with content (top-right corner after rotation)
|
|
32529
32147
|
return {
|
|
32530
32148
|
...base,
|
|
32149
|
+
borderTopWidth: 0,
|
|
32150
|
+
borderRightWidth: 0,
|
|
32531
32151
|
left: -arrowSize,
|
|
32532
32152
|
top: alignment === 'end'
|
|
32533
32153
|
? `calc(100% - ${(arrowPosition === 'side' ? arrowOffset : arrowSize)}px)`
|
|
@@ -33448,7 +33068,7 @@ const filterData = (data, filters, columns, searchValue, rowFeatureToggle) => {
|
|
|
33448
33068
|
return filteredData;
|
|
33449
33069
|
};
|
|
33450
33070
|
// DataTable component
|
|
33451
|
-
const DataTable = ({ id, data, columns, loading = false, error = null, emptyMessage = 'No data available', searchable = true, searchPlaceholder = 'Search...', searchValue: controlledSearchValue, onSearchChange, sortBy = [], onSortChange, filters = [], onFilterChange, pagination, onPaginationChange, selectable = false, selectedRows = [], onSelectionChange, getRowId = (_, index) => index, onRowClick, editMode = false, onEditModeChange, onCellEdit, bulkActions = [], variant = 'default', density = 'normal', height, virtual = false, style, hoverHighlight = true, enableColumnResizing = false, rowFeatureToggle, initialHiddenColumns = [], onColumnVisibilityChange, onColumnSettings, showColumnVisibilityManager = true, rowsPerPageOptions = [10, 25, 50, 100], showRowsPerPageControl = true, rowActions, actionsColumnWidth = 100, fullWidth = true,
|
|
33071
|
+
const DataTable = ({ id, data, columns, loading = false, error = null, emptyMessage = 'No data available', searchable = true, searchPlaceholder = 'Search...', searchValue: controlledSearchValue, onSearchChange, sortBy = [], onSortChange, filters = [], onFilterChange, pagination, onPaginationChange, selectable = false, selectedRows = [], onSelectionChange, getRowId = (_, index) => index, onRowClick, editMode = false, onEditModeChange, onCellEdit, bulkActions = [], variant = 'default', striped: stripedProp, density = 'normal', height, virtual = false, style, hoverHighlight = true, enableColumnResizing = false, rowFeatureToggle, initialHiddenColumns = [], onColumnVisibilityChange, onColumnSettings, showColumnVisibilityManager = true, rowsPerPageOptions = [10, 25, 50, 100], showRowsPerPageControl = true, rowActions, actionsColumnWidth = 100, fullWidth = true,
|
|
33452
33072
|
// Border styling props
|
|
33453
33073
|
rowBorderWidth, rowBorderColor, rowBorderStyle = 'solid', columnBorderWidth, columnBorderColor, columnBorderStyle = 'solid', showOuterBorder = false, outerBorderWidth = 1, outerBorderColor,
|
|
33454
33074
|
// Expandable rows props
|
|
@@ -33456,6 +33076,7 @@ expandableRowRender, initialExpandedRows = [], expandedRows: controlledExpandedR
|
|
|
33456
33076
|
const { spacingProps, otherProps } = extractSpacingProps(props);
|
|
33457
33077
|
const theme = useTheme();
|
|
33458
33078
|
const { isRTL } = useDirection();
|
|
33079
|
+
const isStriped = stripedProp !== null && stripedProp !== void 0 ? stripedProp : variant === 'striped';
|
|
33459
33080
|
// Local state
|
|
33460
33081
|
const [internalSearchValue, setInternalSearchValue] = useState('');
|
|
33461
33082
|
const [editingCell, setEditingCell] = useState(null);
|
|
@@ -33892,7 +33513,7 @@ expandableRowRender, initialExpandedRows = [], expandedRows: controlledExpandedR
|
|
|
33892
33513
|
const rowElement = (jsxs(Fragment, { children: [jsxs(TableTr, { selected: isSelected, onPress: () => onRowClick === null || onRowClick === void 0 ? void 0 : onRowClick(row, rowIndex), style: {
|
|
33893
33514
|
backgroundColor: isSelected
|
|
33894
33515
|
? theme.colors.primary[1]
|
|
33895
|
-
:
|
|
33516
|
+
: isStriped && rowIndex % 2 === 1
|
|
33896
33517
|
? theme.colors.gray[0]
|
|
33897
33518
|
: 'transparent',
|
|
33898
33519
|
borderBottomWidth: rowBorderWidth || (variant === 'bordered' ? 1 : 0),
|
|
@@ -33972,7 +33593,7 @@ expandableRowRender, initialExpandedRows = [], expandedRows: controlledExpandedR
|
|
|
33972
33593
|
borderRadius: showOuterBorder ? 8 : 0
|
|
33973
33594
|
};
|
|
33974
33595
|
if (loading) {
|
|
33975
|
-
return (jsxs(View, { style: [getSpacingStyles(spacingProps), style], ...otherProps, children: [renderHeader(), jsxs(Table, { striped:
|
|
33596
|
+
return (jsxs(View, { style: [getSpacingStyles(spacingProps), style], ...otherProps, children: [renderHeader(), jsxs(Table, { striped: isStriped, withTableBorder: variant === 'bordered', withRowBorders: variant !== 'default', verticalSpacing: density === 'compact' ? 'xs' : density === 'comfortable' ? 'lg' : 'sm', fullWidth: fullWidth, children: [jsxs(TableTr, { style: { backgroundColor: theme.colors.gray[0] }, children: [selectable && (jsx(TableTh, { w: 50, children: jsx(View, { style: { width: 20, height: 20, backgroundColor: theme.colors.gray[2], borderRadius: 4 } }) })), expandableRowRender && (jsx(TableTh, { w: 50, children: jsx(View, { style: { width: 20, height: 20, backgroundColor: theme.colors.gray[2], borderRadius: 4 } }) })), visibleColumns.map(column => (jsx(TableTh, { w: column.width || columnWidths[column.key], minWidth: column.minWidth, children: jsx(View, { style: {
|
|
33976
33597
|
height: 20,
|
|
33977
33598
|
backgroundColor: theme.colors.gray[2],
|
|
33978
33599
|
borderRadius: 4,
|
|
@@ -33994,9 +33615,9 @@ expandableRowRender, initialExpandedRows = [], expandedRows: controlledExpandedR
|
|
|
33994
33615
|
borderColor: theme.colors.error[2]
|
|
33995
33616
|
}, children: [jsx(Icon, { name: "error", size: 32, color: theme.colors.error[5], style: { marginBottom: 12 } }), jsx(Text, { variant: "h6", color: theme.colors.error[7], style: { marginBottom: 8 }, children: "Error Loading Data" }), jsx(Text, { variant: "p", colorVariant: "muted", style: { textAlign: 'center' }, children: error })] })] }));
|
|
33996
33617
|
}
|
|
33997
|
-
return (jsxs(View, { style: [getSpacingStyles(spacingProps), style], ...otherProps, children: [renderHeader(), virtual ? (jsx(View, { style: [{ width: '100%', overflow: 'hidden' }, tableBorderStyle], children: jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: Platform.OS === 'web', contentContainerStyle: minWidthValue ? { minWidth: minWidthValue } : undefined, children: jsxs(View, { style: { flex: 1 }, children: [jsx(Table, { striped:
|
|
33618
|
+
return (jsxs(View, { style: [getSpacingStyles(spacingProps), style], ...otherProps, children: [renderHeader(), virtual ? (jsx(View, { style: [{ width: '100%', overflow: 'hidden' }, tableBorderStyle], children: jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: Platform.OS === 'web', contentContainerStyle: minWidthValue ? { minWidth: minWidthValue } : undefined, children: jsxs(View, { style: { flex: 1 }, children: [jsx(Table, { striped: isStriped, withTableBorder: variant === 'bordered', withRowBorders: variant !== 'default', verticalSpacing: density === 'compact' ? 'xs' : density === 'comfortable' ? 'lg' : 'sm', fullWidth: fullWidth, children: headerRow }), processedData.length === 0 ? (jsx(Table, { striped: isStriped, withTableBorder: variant === 'bordered', withRowBorders: variant !== 'default', verticalSpacing: density === 'compact' ? 'xs' : density === 'comfortable' ? 'lg' : 'sm', fullWidth: fullWidth, children: emptyStateRow })) : (jsx(FlashList, { data: processedData, keyExtractor: (item, index) => String(getRowId(item, index)), renderItem: renderVirtualRow, ...flashListSizingProps, extraData: flashListExtraData, contentContainerStyle: { flexGrow: 1 }, showsVerticalScrollIndicator: Platform.OS === 'web' }))] }) }) })) : (
|
|
33998
33619
|
// <TableScrollContainer style={tableBorderStyle} minWidth={minWidthValue}>
|
|
33999
|
-
jsxs(Table, { striped:
|
|
33620
|
+
jsxs(Table, { striped: isStriped, withTableBorder: variant === 'bordered', withRowBorders: variant !== 'default', verticalSpacing: density === 'compact' ? 'xs' : density === 'comfortable' ? 'lg' : 'sm', fullWidth //</TableScrollContainer>={fullWidth}
|
|
34000
33621
|
: true, children: [headerRow, processedData.length === 0 ? emptyStateRow : nonVirtualRows] })
|
|
34001
33622
|
// </TableScrollContainer>
|
|
34002
33623
|
), pagination && onPaginationChange && (jsx(View, { style: {
|
|
@@ -35661,104 +35282,6 @@ const Ring = factory((props, ref) => {
|
|
|
35661
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] }));
|
|
35662
35283
|
}, { displayName: 'Ring' });
|
|
35663
35284
|
|
|
35664
|
-
const NAVIGATIONPROGRESS_DEFAULTS = {
|
|
35665
|
-
size: 3,
|
|
35666
|
-
color: 'primary',
|
|
35667
|
-
zIndex: 9999,
|
|
35668
|
-
overlay: true,
|
|
35669
|
-
stepInterval: 500,
|
|
35670
|
-
radius: 0,
|
|
35671
|
-
};
|
|
35672
|
-
|
|
35673
|
-
let subscribers = new Set();
|
|
35674
|
-
let internalState = { value: 0, active: false };
|
|
35675
|
-
let interval = null;
|
|
35676
|
-
function broadcast() { subscribers.forEach(cb => cb({ ...internalState })); }
|
|
35677
|
-
function schedule(intervalMs) {
|
|
35678
|
-
clearInterval(interval);
|
|
35679
|
-
interval = setInterval(() => {
|
|
35680
|
-
if (!internalState.active)
|
|
35681
|
-
return;
|
|
35682
|
-
const remain = 100 - internalState.value;
|
|
35683
|
-
const inc = Math.max(0.1, remain * 0.03);
|
|
35684
|
-
internalState.value = Math.min(99, internalState.value + inc);
|
|
35685
|
-
broadcast();
|
|
35686
|
-
}, intervalMs);
|
|
35687
|
-
}
|
|
35688
|
-
const navigationProgress = {
|
|
35689
|
-
start() { if (internalState.active)
|
|
35690
|
-
return; internalState.active = true; if (internalState.value >= 100)
|
|
35691
|
-
internalState.value = 0; broadcast(); schedule(NAVIGATIONPROGRESS_DEFAULTS.stepInterval); },
|
|
35692
|
-
stop() { internalState.active = false; broadcast(); },
|
|
35693
|
-
complete() { internalState.active = true; internalState.value = 100; broadcast(); setTimeout(() => { internalState.active = false; internalState.value = 0; broadcast(); }, 400); },
|
|
35694
|
-
reset() { internalState.value = 0; internalState.active = false; broadcast(); },
|
|
35695
|
-
set(v) { internalState.value = Math.max(0, Math.min(100, v)); broadcast(); },
|
|
35696
|
-
increment(delta = 5) { internalState.value = Math.min(100, internalState.value + delta); broadcast(); },
|
|
35697
|
-
decrement(delta = 5) { internalState.value = Math.max(0, internalState.value - delta); broadcast(); },
|
|
35698
|
-
isActive() { return internalState.active; }
|
|
35699
|
-
};
|
|
35700
|
-
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 }) => {
|
|
35701
|
-
const theme = useTheme();
|
|
35702
|
-
const scheme = useColorScheme();
|
|
35703
|
-
const isDark = scheme === 'dark';
|
|
35704
|
-
const progress = useSharedValue(0);
|
|
35705
|
-
const opacity = useSharedValue(0);
|
|
35706
|
-
useEffect(() => {
|
|
35707
|
-
const sub = (s) => {
|
|
35708
|
-
if (value == null) {
|
|
35709
|
-
progress.value = withTiming(s.value, { duration: stepInterval });
|
|
35710
|
-
opacity.value = withTiming(s.active ? 1 : 0, { duration: 150 });
|
|
35711
|
-
}
|
|
35712
|
-
};
|
|
35713
|
-
subscribers.add(sub);
|
|
35714
|
-
broadcast();
|
|
35715
|
-
return () => { subscribers.delete(sub); };
|
|
35716
|
-
}, [value, stepInterval, progress, opacity]);
|
|
35717
|
-
useEffect(() => {
|
|
35718
|
-
if (value != null) {
|
|
35719
|
-
progress.value = withTiming(value, { duration: stepInterval });
|
|
35720
|
-
opacity.value = withTiming(active ? 1 : 0, { duration: 150 });
|
|
35721
|
-
}
|
|
35722
|
-
}, [value, active, stepInterval]);
|
|
35723
|
-
let resolvedColor = color;
|
|
35724
|
-
if (theme.colors[color]) {
|
|
35725
|
-
const bucket = theme.colors[color];
|
|
35726
|
-
resolvedColor = bucket[5] || bucket[4] || bucket[0];
|
|
35727
|
-
}
|
|
35728
|
-
const barStyle = useAnimatedStyle(() => ({ width: `${progress.value}%` }));
|
|
35729
|
-
const containerStyle = useAnimatedStyle(() => ({ opacity: opacity.value }));
|
|
35730
|
-
return (jsxs(Animated.View, { style: [
|
|
35731
|
-
{
|
|
35732
|
-
position: overlay ? 'absolute' : 'relative',
|
|
35733
|
-
top: 0,
|
|
35734
|
-
left: 0,
|
|
35735
|
-
right: 0,
|
|
35736
|
-
height: size,
|
|
35737
|
-
backgroundColor: isDark ? theme.colors.gray[3] : theme.colors.gray[2],
|
|
35738
|
-
overflow: 'hidden',
|
|
35739
|
-
zIndex,
|
|
35740
|
-
borderRadius: radius,
|
|
35741
|
-
pointerEvents: 'none'
|
|
35742
|
-
},
|
|
35743
|
-
containerStyle,
|
|
35744
|
-
style
|
|
35745
|
-
], children: [jsx(Animated.View, { style: [{
|
|
35746
|
-
position: 'absolute',
|
|
35747
|
-
top: 0,
|
|
35748
|
-
bottom: 0,
|
|
35749
|
-
left: 0,
|
|
35750
|
-
backgroundColor: resolvedColor,
|
|
35751
|
-
borderRadius: radius,
|
|
35752
|
-
}, barStyle] }), jsx(Animated.View, { style: [{
|
|
35753
|
-
position: 'absolute',
|
|
35754
|
-
top: 0,
|
|
35755
|
-
bottom: 0,
|
|
35756
|
-
right: 0,
|
|
35757
|
-
width: 80,
|
|
35758
|
-
backgroundColor: 'rgba(255,255,255,0.2)'
|
|
35759
|
-
}, barStyle] })] }));
|
|
35760
|
-
};
|
|
35761
|
-
|
|
35762
35285
|
const DEFAULT_OPACITY = 0.6;
|
|
35763
35286
|
const HEX_COLOR_REGEX = /^#?[0-9a-f]{3,8}$/i;
|
|
35764
35287
|
const clampOpacity = (value) => {
|
|
@@ -35951,270 +35474,6 @@ const LoadingOverlay = React__default.forwardRef((props, ref) => {
|
|
|
35951
35474
|
});
|
|
35952
35475
|
LoadingOverlay.displayName = 'LoadingOverlay';
|
|
35953
35476
|
|
|
35954
|
-
// A lightweight hover-activated floating panel similar to Mantine HoverCard
|
|
35955
|
-
function HoverCardBase(props, ref) {
|
|
35956
|
-
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;
|
|
35957
|
-
const [opened, setOpened] = useState(false);
|
|
35958
|
-
const openTimeout = useRef(null);
|
|
35959
|
-
const closeTimeout = useRef(null);
|
|
35960
|
-
const containerRef = useRef(null);
|
|
35961
|
-
const targetRef = useRef(null);
|
|
35962
|
-
const overlayIdRef = useRef(null);
|
|
35963
|
-
const overlayContentRef = useRef(null);
|
|
35964
|
-
const isHoveringTargetRef = useRef(false);
|
|
35965
|
-
const isHoveringOverlayRef = useRef(false);
|
|
35966
|
-
const theme = useTheme();
|
|
35967
|
-
const { openOverlay, closeOverlay, updateOverlay } = useOverlay();
|
|
35968
|
-
const isOpened = controlledOpened !== undefined ? controlledOpened : opened;
|
|
35969
|
-
const clearTimers = () => {
|
|
35970
|
-
if (openTimeout.current) {
|
|
35971
|
-
clearTimeout(openTimeout.current);
|
|
35972
|
-
openTimeout.current = null;
|
|
35973
|
-
}
|
|
35974
|
-
if (closeTimeout.current) {
|
|
35975
|
-
clearTimeout(closeTimeout.current);
|
|
35976
|
-
closeTimeout.current = null;
|
|
35977
|
-
}
|
|
35978
|
-
};
|
|
35979
|
-
const doOpen = useCallback(() => {
|
|
35980
|
-
if (disabled)
|
|
35981
|
-
return;
|
|
35982
|
-
setOpened(true);
|
|
35983
|
-
onOpen === null || onOpen === void 0 ? void 0 : onOpen();
|
|
35984
|
-
}, [disabled, onOpen]);
|
|
35985
|
-
const doClose = useCallback(() => {
|
|
35986
|
-
setOpened(false);
|
|
35987
|
-
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
35988
|
-
}, [onClose]);
|
|
35989
|
-
const scheduleOpen = useCallback(() => {
|
|
35990
|
-
clearTimers();
|
|
35991
|
-
openTimeout.current = setTimeout(doOpen, openDelay);
|
|
35992
|
-
}, [doOpen, openDelay]);
|
|
35993
|
-
const scheduleClose = useCallback(() => {
|
|
35994
|
-
clearTimers();
|
|
35995
|
-
closeTimeout.current = setTimeout(() => {
|
|
35996
|
-
// Only close if neither target nor overlay are hovered (web)
|
|
35997
|
-
if (Platform.OS === 'web') {
|
|
35998
|
-
if (isHoveringTargetRef.current || isHoveringOverlayRef.current)
|
|
35999
|
-
return;
|
|
36000
|
-
}
|
|
36001
|
-
doClose();
|
|
36002
|
-
}, closeDelay);
|
|
36003
|
-
}, [doClose, closeDelay]);
|
|
36004
|
-
useEffect(() => () => clearTimers(), []);
|
|
36005
|
-
// Escape key (web only)
|
|
36006
|
-
useEffect(() => {
|
|
36007
|
-
if (!closeOnEscape || Platform.OS !== 'web')
|
|
36008
|
-
return;
|
|
36009
|
-
const handler = (e) => { if (e.key === 'Escape')
|
|
36010
|
-
doClose(); };
|
|
36011
|
-
document.addEventListener('keydown', handler);
|
|
36012
|
-
return () => document.removeEventListener('keydown', handler);
|
|
36013
|
-
}, [closeOnEscape, doClose]);
|
|
36014
|
-
const getInlinePositionStyle = () => {
|
|
36015
|
-
const base = { position: 'absolute' };
|
|
36016
|
-
switch (position) {
|
|
36017
|
-
case 'top': return { ...base, bottom: '100%', left: 0, marginBottom: offset };
|
|
36018
|
-
case 'bottom': return { ...base, top: '100%', left: 0, marginTop: offset };
|
|
36019
|
-
case 'left': return { ...base, right: '100%', top: 0, marginRight: offset };
|
|
36020
|
-
case 'right': return { ...base, left: '100%', top: 0, marginLeft: offset };
|
|
36021
|
-
default: return { ...base, top: '100%', left: 0, marginTop: offset };
|
|
36022
|
-
}
|
|
36023
|
-
};
|
|
36024
|
-
const shadowStyle = (() => {
|
|
36025
|
-
switch (shadow) {
|
|
36026
|
-
case 'sm':
|
|
36027
|
-
return { boxShadow: '0 1px 2px rgba(0, 0, 0, 0.1)', elevation: 2 };
|
|
36028
|
-
case 'md':
|
|
36029
|
-
return { boxShadow: '0 2px 4px rgba(0, 0, 0, 0.15)', elevation: 4 };
|
|
36030
|
-
case 'lg':
|
|
36031
|
-
return { boxShadow: '0 4px 8px rgba(0, 0, 0, 0.2)', elevation: 8 };
|
|
36032
|
-
default:
|
|
36033
|
-
return {};
|
|
36034
|
-
}
|
|
36035
|
-
})();
|
|
36036
|
-
const renderArrow = (placement) => {
|
|
36037
|
-
if (!withArrow)
|
|
36038
|
-
return null;
|
|
36039
|
-
const base = { position: 'absolute', width: 0, height: 0 };
|
|
36040
|
-
const color = theme.colors.gray[0];
|
|
36041
|
-
const styles = {
|
|
36042
|
-
top: { top: '100%', left: 12, borderLeftWidth: 6, borderRightWidth: 6, borderTopWidth: 6, borderLeftColor: 'transparent', borderRightColor: 'transparent', borderTopColor: color },
|
|
36043
|
-
bottom: { bottom: '100%', left: 12, borderLeftWidth: 6, borderRightWidth: 6, borderBottomWidth: 6, borderLeftColor: 'transparent', borderRightColor: 'transparent', borderBottomColor: color },
|
|
36044
|
-
left: { left: '100%', top: 12, borderTopWidth: 6, borderBottomWidth: 6, borderLeftWidth: 6, borderTopColor: 'transparent', borderBottomColor: 'transparent', borderLeftColor: color },
|
|
36045
|
-
right: { right: '100%', top: 12, borderTopWidth: 6, borderBottomWidth: 6, borderRightWidth: 6, borderTopColor: 'transparent', borderBottomColor: 'transparent', borderRightColor: color },
|
|
36046
|
-
};
|
|
36047
|
-
const key = placement.split('-')[0];
|
|
36048
|
-
return jsx(View, { style: { ...base, ...(styles[key] || styles.top) } });
|
|
36049
|
-
};
|
|
36050
|
-
const openPortal = useCallback(async () => {
|
|
36051
|
-
if (!withinPortal || !isOpened || overlayIdRef.current)
|
|
36052
|
-
return;
|
|
36053
|
-
const rect = await measureElement(targetRef);
|
|
36054
|
-
const estWidth = width || 240;
|
|
36055
|
-
const estHeight = 160; // rough initial height
|
|
36056
|
-
const pos = calculateOverlayPositionEnhanced(rect, { width: estWidth, height: estHeight }, {
|
|
36057
|
-
placement: position,
|
|
36058
|
-
offset,
|
|
36059
|
-
viewport: getViewport(),
|
|
36060
|
-
strategy: 'fixed'
|
|
36061
|
-
});
|
|
36062
|
-
const overlayContent = (jsxs(View, { ref: overlayContentRef, style: [
|
|
36063
|
-
{
|
|
36064
|
-
backgroundColor: theme.colors.gray[0],
|
|
36065
|
-
borderRadius: getRadius$2(radius),
|
|
36066
|
-
paddingHorizontal: getSpacing('md'),
|
|
36067
|
-
paddingVertical: getSpacing('sm'),
|
|
36068
|
-
borderWidth: 1,
|
|
36069
|
-
borderColor: theme.colors.gray[3],
|
|
36070
|
-
minWidth: width || 160,
|
|
36071
|
-
maxWidth: width || 320,
|
|
36072
|
-
},
|
|
36073
|
-
shadowStyle,
|
|
36074
|
-
], ...(Platform.OS === 'web' && trigger === 'hover' ? {
|
|
36075
|
-
onMouseEnter: () => { isHoveringOverlayRef.current = true; clearTimers(); },
|
|
36076
|
-
onMouseLeave: () => { isHoveringOverlayRef.current = false; scheduleClose(); },
|
|
36077
|
-
} : {}), children: [children, renderArrow(pos.placement)] }));
|
|
36078
|
-
const id = openOverlay({
|
|
36079
|
-
content: overlayContent,
|
|
36080
|
-
anchor: { x: pos.x, y: pos.y, width: estWidth, height: estHeight },
|
|
36081
|
-
trigger: trigger,
|
|
36082
|
-
// For hover-triggered overlays, do NOT render a click-outside backdrop – it steals hover
|
|
36083
|
-
// and immediately fires target onMouseLeave. We rely on pointer leave timers instead.
|
|
36084
|
-
closeOnClickOutside: trigger !== 'hover',
|
|
36085
|
-
closeOnEscape: closeOnEscape,
|
|
36086
|
-
strategy: 'fixed',
|
|
36087
|
-
onClose: () => { overlayIdRef.current = null; if (opened)
|
|
36088
|
-
setOpened(false); onClose === null || onClose === void 0 ? void 0 : onClose(); },
|
|
36089
|
-
zIndex
|
|
36090
|
-
});
|
|
36091
|
-
overlayIdRef.current = id;
|
|
36092
|
-
}, [withinPortal, isOpened, overlayIdRef, position, offset, width, trigger, closeOnEscape, theme, radius, shadowStyle, children, opened, onClose, getSpacing, getRadius$2]);
|
|
36093
|
-
const closePortal = useCallback(() => {
|
|
36094
|
-
if (overlayIdRef.current) {
|
|
36095
|
-
closeOverlay(overlayIdRef.current);
|
|
36096
|
-
overlayIdRef.current = null;
|
|
36097
|
-
}
|
|
36098
|
-
}, [closeOverlay]);
|
|
36099
|
-
useEffect(() => {
|
|
36100
|
-
if (withinPortal) {
|
|
36101
|
-
if (isOpened)
|
|
36102
|
-
openPortal();
|
|
36103
|
-
else
|
|
36104
|
-
closePortal();
|
|
36105
|
-
}
|
|
36106
|
-
return () => { if (!isOpened)
|
|
36107
|
-
closePortal(); };
|
|
36108
|
-
}, [isOpened, withinPortal, openPortal, closePortal]);
|
|
36109
|
-
useEffect(() => {
|
|
36110
|
-
if (!withinPortal || Platform.OS !== 'web' || !isOpened || !overlayIdRef.current)
|
|
36111
|
-
return;
|
|
36112
|
-
const handler = () => {
|
|
36113
|
-
Promise.all([measureElement(targetRef)]).then(([rect]) => {
|
|
36114
|
-
var _a, _b;
|
|
36115
|
-
const actualWidth = ((_a = overlayContentRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || width || 240;
|
|
36116
|
-
const actualHeight = ((_b = overlayContentRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 160;
|
|
36117
|
-
const pos = calculateOverlayPositionEnhanced(rect, { width: actualWidth, height: actualHeight }, {
|
|
36118
|
-
placement: position,
|
|
36119
|
-
offset,
|
|
36120
|
-
viewport: getViewport(),
|
|
36121
|
-
strategy: 'fixed'
|
|
36122
|
-
});
|
|
36123
|
-
updateOverlay(overlayIdRef.current, { anchor: { x: pos.x, y: pos.y, width: actualWidth, height: actualHeight } });
|
|
36124
|
-
});
|
|
36125
|
-
};
|
|
36126
|
-
window.addEventListener('resize', handler);
|
|
36127
|
-
window.addEventListener('scroll', handler, true);
|
|
36128
|
-
return () => {
|
|
36129
|
-
window.removeEventListener('resize', handler);
|
|
36130
|
-
window.removeEventListener('scroll', handler, true);
|
|
36131
|
-
};
|
|
36132
|
-
}, [withinPortal, isOpened, position, offset, width, updateOverlay]);
|
|
36133
|
-
// Smart sizing: after content mounts, measure actual size and reposition if changed
|
|
36134
|
-
useEffect(() => {
|
|
36135
|
-
if (!withinPortal || !isOpened || !overlayIdRef.current)
|
|
36136
|
-
return;
|
|
36137
|
-
let frame;
|
|
36138
|
-
const attempt = () => {
|
|
36139
|
-
Promise.all([
|
|
36140
|
-
measureElement(targetRef),
|
|
36141
|
-
measureElement({ current: overlayContentRef.current })
|
|
36142
|
-
]).then(([targetRect, contentRect]) => {
|
|
36143
|
-
if (!targetRect.width || !contentRect.width)
|
|
36144
|
-
return; // skip invalid
|
|
36145
|
-
const desiredWidth = width || contentRect.width;
|
|
36146
|
-
const desiredHeight = contentRect.height;
|
|
36147
|
-
// Recalculate with actual content size
|
|
36148
|
-
const pos = calculateOverlayPositionEnhanced(targetRect, { width: desiredWidth, height: desiredHeight }, {
|
|
36149
|
-
placement: position,
|
|
36150
|
-
offset,
|
|
36151
|
-
viewport: getViewport(),
|
|
36152
|
-
strategy: 'fixed'
|
|
36153
|
-
});
|
|
36154
|
-
updateOverlay(overlayIdRef.current, { anchor: { x: pos.x, y: pos.y, width: desiredWidth, height: desiredHeight } });
|
|
36155
|
-
});
|
|
36156
|
-
};
|
|
36157
|
-
// Delay a bit to allow layout
|
|
36158
|
-
frame = setTimeout(attempt, 30);
|
|
36159
|
-
return () => { if (frame)
|
|
36160
|
-
clearTimeout(frame); };
|
|
36161
|
-
}, [withinPortal, isOpened, position, offset, width, updateOverlay]);
|
|
36162
|
-
const targetProps = {};
|
|
36163
|
-
if (trigger === 'hover') {
|
|
36164
|
-
if (Platform.OS === 'web') {
|
|
36165
|
-
targetProps.onMouseEnter = () => { isHoveringTargetRef.current = true; scheduleOpen(); };
|
|
36166
|
-
targetProps.onMouseLeave = () => { isHoveringTargetRef.current = false; scheduleClose(); };
|
|
36167
|
-
}
|
|
36168
|
-
else {
|
|
36169
|
-
// fallback: tap to toggle on native
|
|
36170
|
-
targetProps.onPress = () => {
|
|
36171
|
-
if (isOpened) {
|
|
36172
|
-
doClose();
|
|
36173
|
-
}
|
|
36174
|
-
else {
|
|
36175
|
-
doOpen();
|
|
36176
|
-
}
|
|
36177
|
-
};
|
|
36178
|
-
}
|
|
36179
|
-
}
|
|
36180
|
-
else if (trigger === 'click') {
|
|
36181
|
-
targetProps.onPress = () => {
|
|
36182
|
-
if (isOpened) {
|
|
36183
|
-
doClose();
|
|
36184
|
-
}
|
|
36185
|
-
else {
|
|
36186
|
-
doOpen();
|
|
36187
|
-
}
|
|
36188
|
-
};
|
|
36189
|
-
}
|
|
36190
|
-
const inlineContent = (isOpened || keepMounted) && !withinPortal ? (jsxs(View, { style: [
|
|
36191
|
-
getInlinePositionStyle(),
|
|
36192
|
-
{
|
|
36193
|
-
backgroundColor: theme.colors.gray[0],
|
|
36194
|
-
borderRadius: getRadius$2(radius),
|
|
36195
|
-
paddingHorizontal: getSpacing('md'),
|
|
36196
|
-
paddingVertical: getSpacing('sm'),
|
|
36197
|
-
borderWidth: 1,
|
|
36198
|
-
borderColor: theme.colors.gray[3],
|
|
36199
|
-
minWidth: width,
|
|
36200
|
-
zIndex,
|
|
36201
|
-
},
|
|
36202
|
-
shadowStyle,
|
|
36203
|
-
], pointerEvents: "auto", ...(Platform.OS === 'web' && trigger === 'hover' ? {
|
|
36204
|
-
onMouseEnter: () => { isHoveringOverlayRef.current = true; clearTimers(); },
|
|
36205
|
-
onMouseLeave: () => { isHoveringOverlayRef.current = false; scheduleClose(); },
|
|
36206
|
-
} : {}), children: [children, renderArrow(position)] })) : null;
|
|
36207
|
-
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 }) => {
|
|
36208
|
-
var _a;
|
|
36209
|
-
return [
|
|
36210
|
-
{ opacity: pressed ? 0.85 : 1 },
|
|
36211
|
-
(_a = target === null || target === void 0 ? void 0 : target.props) === null || _a === void 0 ? void 0 : _a.style,
|
|
36212
|
-
];
|
|
36213
|
-
}, children: target }), inlineContent] }));
|
|
36214
|
-
}
|
|
36215
|
-
const HoverCard = factory(HoverCardBase);
|
|
36216
|
-
HoverCard.displayName = 'HoverCard';
|
|
36217
|
-
|
|
36218
35477
|
const ContextMenu = ({ children, items, closeOnSelect = true, longPressDelay = 350, maxHeight = 280, onOpen, onClose, open: controlledOpen, position: controlledPosition, portalId, style, }) => {
|
|
36219
35478
|
var _a, _b;
|
|
36220
35479
|
const [internalOpen, setInternalOpen] = useState(false);
|
|
@@ -37434,49 +36693,101 @@ const CarouselDot = memo(({ index, pageProgress, metrics, totalPages, loop, them
|
|
|
37434
36693
|
: { marginHorizontal: metrics.margin, height: baseDotSize, justifyContent: 'center' };
|
|
37435
36694
|
return (jsx(Pressable, { onPress: handlePress, accessibilityRole: "button", accessibilityLabel: `Go to slide ${index + 1}`, style: containerStyle, children: jsx(Animated.View, { style: [{ borderRadius: baseDotSize / 2 }, animatedStyle] }) }));
|
|
37436
36695
|
});
|
|
36696
|
+
const getBreakpointName = (width) => {
|
|
36697
|
+
if (width >= 1200)
|
|
36698
|
+
return 'xl';
|
|
36699
|
+
if (width >= 992)
|
|
36700
|
+
return 'lg';
|
|
36701
|
+
if (width >= 768)
|
|
36702
|
+
return 'md';
|
|
36703
|
+
if (width >= 576)
|
|
36704
|
+
return 'sm';
|
|
36705
|
+
return 'xs';
|
|
36706
|
+
};
|
|
36707
|
+
const getViewportWidth = () => {
|
|
36708
|
+
if (Platform.OS === 'web' && typeof window !== 'undefined' && typeof window.innerWidth === 'number') {
|
|
36709
|
+
return window.innerWidth;
|
|
36710
|
+
}
|
|
36711
|
+
const dimensions = Dimensions.get('window');
|
|
36712
|
+
return typeof (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) === 'number' ? dimensions.width : 0;
|
|
36713
|
+
};
|
|
37437
36714
|
// Optimized breakpoint hook with debouncing
|
|
37438
36715
|
const useOptimizedBreakpoint = () => {
|
|
37439
|
-
const
|
|
36716
|
+
const computeState = () => {
|
|
36717
|
+
const width = getViewportWidth();
|
|
36718
|
+
return {
|
|
36719
|
+
width,
|
|
36720
|
+
breakpoint: getBreakpointName(width),
|
|
36721
|
+
};
|
|
36722
|
+
};
|
|
36723
|
+
const [state, setState] = useState(computeState);
|
|
37440
36724
|
useEffect(() => {
|
|
37441
36725
|
let timeoutId;
|
|
37442
|
-
const
|
|
37443
|
-
const
|
|
37444
|
-
|
|
37445
|
-
: Dimensions.get('window').width;
|
|
37446
|
-
let newBreakpoint = 'sm';
|
|
37447
|
-
if (w >= 1200)
|
|
37448
|
-
newBreakpoint = 'xl';
|
|
37449
|
-
else if (w >= 992)
|
|
37450
|
-
newBreakpoint = 'lg';
|
|
37451
|
-
else if (w >= 768)
|
|
37452
|
-
newBreakpoint = 'md';
|
|
37453
|
-
else if (w >= 576)
|
|
37454
|
-
newBreakpoint = 'sm';
|
|
37455
|
-
else
|
|
37456
|
-
newBreakpoint = 'xs';
|
|
37457
|
-
setBreakpoint(prev => prev !== newBreakpoint ? newBreakpoint : prev);
|
|
36726
|
+
const update = () => {
|
|
36727
|
+
const next = computeState();
|
|
36728
|
+
setState(prev => (prev.breakpoint === next.breakpoint && prev.width === next.width) ? prev : next);
|
|
37458
36729
|
};
|
|
37459
|
-
const
|
|
36730
|
+
const debouncedUpdate = () => {
|
|
37460
36731
|
clearTimeout(timeoutId);
|
|
37461
|
-
timeoutId = setTimeout(
|
|
36732
|
+
timeoutId = setTimeout(update, 100); // Debounce resize events
|
|
37462
36733
|
};
|
|
37463
|
-
|
|
37464
|
-
if (Platform.OS === 'web') {
|
|
37465
|
-
window.addEventListener('resize',
|
|
36734
|
+
update();
|
|
36735
|
+
if (Platform.OS === 'web' && typeof window !== 'undefined') {
|
|
36736
|
+
window.addEventListener('resize', debouncedUpdate, { passive: true });
|
|
37466
36737
|
return () => {
|
|
37467
|
-
window.removeEventListener('resize',
|
|
36738
|
+
window.removeEventListener('resize', debouncedUpdate);
|
|
37468
36739
|
clearTimeout(timeoutId);
|
|
37469
36740
|
};
|
|
37470
36741
|
}
|
|
37471
|
-
|
|
36742
|
+
const subscription = Dimensions.addEventListener('change', debouncedUpdate);
|
|
36743
|
+
return () => {
|
|
36744
|
+
subscription === null || subscription === void 0 ? void 0 : subscription.remove();
|
|
36745
|
+
clearTimeout(timeoutId);
|
|
36746
|
+
};
|
|
37472
36747
|
}, []);
|
|
37473
|
-
return
|
|
36748
|
+
return state;
|
|
36749
|
+
};
|
|
36750
|
+
const parseMediaQuery = (query) => {
|
|
36751
|
+
const minMatch = query.match(/min-width:\s*(\d+)px/);
|
|
36752
|
+
const maxMatch = query.match(/max-width:\s*(\d+)px/);
|
|
36753
|
+
return {
|
|
36754
|
+
min: minMatch ? parseInt(minMatch[1], 10) : undefined,
|
|
36755
|
+
max: maxMatch ? parseInt(maxMatch[1], 10) : undefined,
|
|
36756
|
+
};
|
|
36757
|
+
};
|
|
36758
|
+
const matchQuery = (query, width) => {
|
|
36759
|
+
const { min, max } = parseMediaQuery(query);
|
|
36760
|
+
if (min != null && width < min)
|
|
36761
|
+
return false;
|
|
36762
|
+
if (max != null && width > max)
|
|
36763
|
+
return false;
|
|
36764
|
+
return true;
|
|
36765
|
+
};
|
|
36766
|
+
const mergeBreakpointProps = (baseProps, breakpointProps, width) => {
|
|
36767
|
+
if (!breakpointProps)
|
|
36768
|
+
return baseProps;
|
|
36769
|
+
const sortedEntries = Object.entries(breakpointProps).sort((a, b) => {
|
|
36770
|
+
var _a, _b;
|
|
36771
|
+
const aMin = (_a = parseMediaQuery(a[0]).min) !== null && _a !== void 0 ? _a : 0;
|
|
36772
|
+
const bMin = (_b = parseMediaQuery(b[0]).min) !== null && _b !== void 0 ? _b : 0;
|
|
36773
|
+
return aMin - bMin;
|
|
36774
|
+
});
|
|
36775
|
+
let resolvedProps = { ...baseProps };
|
|
36776
|
+
sortedEntries.forEach(([query, value]) => {
|
|
36777
|
+
const shouldApply = width != null ? matchQuery(query, width) : (Platform.OS === 'web' && typeof window !== 'undefined' ? window.matchMedia(query).matches : false);
|
|
36778
|
+
if (shouldApply) {
|
|
36779
|
+
resolvedProps = { ...resolvedProps, ...value };
|
|
36780
|
+
}
|
|
36781
|
+
});
|
|
36782
|
+
return resolvedProps;
|
|
37474
36783
|
};
|
|
37475
|
-
const Carousel = (
|
|
37476
|
-
const {
|
|
36784
|
+
const Carousel = (incomingProps) => {
|
|
36785
|
+
const { breakpoint, width: viewportWidth } = useOptimizedBreakpoint();
|
|
36786
|
+
const mergedProps = useMemo(() => mergeBreakpointProps(incomingProps, incomingProps.breakpoints, viewportWidth), [incomingProps, viewportWidth]);
|
|
36787
|
+
const { children, orientation = 'horizontal', height = 200, showDots = true, showArrows = true, loop = true, autoPlay = false, autoPlayInterval = 3000, itemsPerPage = 1, slidesToScroll, slideSize, slideGap, itemGap = 16, containScroll = 'trimSnaps', startIndex, align = 'start', dragFree = false, skipSnaps = true, dragThreshold, duration, breakpoints: _breakpoints, onSlideChange, style, itemStyle, arrowSize = 'md', dotSize = 'md', // currently uniform size; active expands
|
|
37477
36788
|
snapToItem = true, // kept for API parity (engine handles snapping)
|
|
37478
36789
|
windowSize = 0, // 0 means no virtualization
|
|
37479
|
-
reducedMotion = false, ...rest } =
|
|
36790
|
+
reducedMotion = false, ...rest } = mergedProps;
|
|
37480
36791
|
const { spacingProps, otherProps } = extractSpacingProps(rest);
|
|
37481
36792
|
const spacingStyles = getSpacingStyles(spacingProps);
|
|
37482
36793
|
const theme = useTheme();
|
|
@@ -37488,10 +36799,9 @@ const Carousel = (props) => {
|
|
|
37488
36799
|
// progress holds absolute item progress (fractional, not modulo) supplied by engine
|
|
37489
36800
|
const progress = useSharedValue(0);
|
|
37490
36801
|
const [currentIndex, setCurrentIndex] = useState(0);
|
|
36802
|
+
const hasInitializedRef = useRef(false);
|
|
37491
36803
|
const itemsArray = useMemo(() => React__default.Children.toArray(children), [children]);
|
|
37492
36804
|
const totalItems = itemsArray.length;
|
|
37493
|
-
// Use optimized breakpoint detection with debouncing
|
|
37494
|
-
const breakpoint = useOptimizedBreakpoint();
|
|
37495
36805
|
const resolvedGap = useMemo(() => {
|
|
37496
36806
|
const raw = resolveResponsive(slideGap, breakpoint);
|
|
37497
36807
|
if (raw == null)
|
|
@@ -37506,7 +36816,7 @@ const Carousel = (props) => {
|
|
|
37506
36816
|
}, [slideGap, breakpoint, itemGap]);
|
|
37507
36817
|
const isVertical = orientation === 'vertical';
|
|
37508
36818
|
const containerSize = isVertical ? containerHeight : containerWidth;
|
|
37509
|
-
const
|
|
36819
|
+
const desiredItemSize = useMemo(() => {
|
|
37510
36820
|
if (containerSize <= 0)
|
|
37511
36821
|
return 0;
|
|
37512
36822
|
const rawSize = resolveResponsive(slideSize, breakpoint);
|
|
@@ -37532,28 +36842,166 @@ const Carousel = (props) => {
|
|
|
37532
36842
|
}
|
|
37533
36843
|
return (containerSize - resolvedGap * (itemsPerPage - 1)) / itemsPerPage;
|
|
37534
36844
|
}, [slideSize, breakpoint, containerSize, itemsPerPage, resolvedGap]);
|
|
36845
|
+
const hasLayout = isVertical ? containerHeight > 0 : containerWidth > 0;
|
|
36846
|
+
const baseItemsPerPage = Math.max(1, itemsPerPage);
|
|
36847
|
+
const slidesToScrollValue = Math.max(1, slidesToScroll !== null && slidesToScroll !== void 0 ? slidesToScroll : baseItemsPerPage);
|
|
36848
|
+
const containMode = containScroll === false
|
|
36849
|
+
? 'none'
|
|
36850
|
+
: containScroll === 'keepSnaps'
|
|
36851
|
+
? 'keepSnaps'
|
|
36852
|
+
: 'trimSnaps';
|
|
36853
|
+
const isDragFree = !!dragFree;
|
|
36854
|
+
const allowSkipSnaps = skipSnaps !== null && skipSnaps !== void 0 ? skipSnaps : true;
|
|
36855
|
+
const dragThresholdValue = typeof dragThreshold === 'number'
|
|
36856
|
+
? Math.max(dragThreshold, 0)
|
|
36857
|
+
: undefined;
|
|
36858
|
+
const visibleSlides = useMemo(() => {
|
|
36859
|
+
if (!hasLayout || containerSize <= 0)
|
|
36860
|
+
return baseItemsPerPage;
|
|
36861
|
+
if (desiredItemSize <= 0)
|
|
36862
|
+
return baseItemsPerPage;
|
|
36863
|
+
const maxFit = Math.max(1, Math.floor((containerSize + resolvedGap) / (desiredItemSize + resolvedGap)));
|
|
36864
|
+
if (slideSize == null) {
|
|
36865
|
+
return Math.min(baseItemsPerPage, maxFit);
|
|
36866
|
+
}
|
|
36867
|
+
return maxFit;
|
|
36868
|
+
}, [hasLayout, containerSize, desiredItemSize, resolvedGap, baseItemsPerPage, slideSize]);
|
|
36869
|
+
const cardSize = useMemo(() => {
|
|
36870
|
+
if (!hasLayout)
|
|
36871
|
+
return desiredItemSize;
|
|
36872
|
+
if (visibleSlides <= 1) {
|
|
36873
|
+
if (desiredItemSize > 0)
|
|
36874
|
+
return desiredItemSize;
|
|
36875
|
+
return containerSize > 0 ? containerSize : desiredItemSize;
|
|
36876
|
+
}
|
|
36877
|
+
const totalGap = resolvedGap * (visibleSlides - 1);
|
|
36878
|
+
const available = Math.max(containerSize - totalGap, 0);
|
|
36879
|
+
return available / visibleSlides;
|
|
36880
|
+
}, [hasLayout, desiredItemSize, visibleSlides, resolvedGap, containerSize]);
|
|
36881
|
+
const slideExtent = useMemo(() => {
|
|
36882
|
+
if (!hasLayout || cardSize <= 0)
|
|
36883
|
+
return undefined;
|
|
36884
|
+
return cardSize + resolvedGap;
|
|
36885
|
+
}, [hasLayout, cardSize, resolvedGap]);
|
|
36886
|
+
const scrollStep = useMemo(() => {
|
|
36887
|
+
if (totalItems === 0)
|
|
36888
|
+
return slidesToScrollValue;
|
|
36889
|
+
return Math.min(slidesToScrollValue, Math.max(1, totalItems));
|
|
36890
|
+
}, [slidesToScrollValue, totalItems]);
|
|
36891
|
+
const maxScrollDistancePerSwipe = useMemo(() => {
|
|
36892
|
+
if (allowSkipSnaps || slideExtent == null)
|
|
36893
|
+
return undefined;
|
|
36894
|
+
return slideExtent * scrollStep;
|
|
36895
|
+
}, [allowSkipSnaps, slideExtent, scrollStep]);
|
|
36896
|
+
const lastStart = useMemo(() => Math.max(totalItems - visibleSlides, 0), [totalItems, visibleSlides]);
|
|
36897
|
+
const pageStartIndices = useMemo(() => {
|
|
36898
|
+
if (totalItems === 0)
|
|
36899
|
+
return [];
|
|
36900
|
+
if (loop) {
|
|
36901
|
+
const count = Math.max(1, Math.ceil(totalItems / scrollStep));
|
|
36902
|
+
return Array.from({ length: count }, (_, idx) => (idx * scrollStep) % totalItems);
|
|
36903
|
+
}
|
|
36904
|
+
const starts = [];
|
|
36905
|
+
const seen = new Set();
|
|
36906
|
+
const limit = containMode === 'none' ? Math.max(totalItems - 1, 0) : lastStart;
|
|
36907
|
+
const addStart = (value) => {
|
|
36908
|
+
if (!seen.has(value)) {
|
|
36909
|
+
seen.add(value);
|
|
36910
|
+
starts.push(Math.max(0, value));
|
|
36911
|
+
}
|
|
36912
|
+
};
|
|
36913
|
+
for (let start = 0; start <= limit; start += scrollStep) {
|
|
36914
|
+
const value = containMode === 'trimSnaps'
|
|
36915
|
+
? Math.min(start, lastStart)
|
|
36916
|
+
: start;
|
|
36917
|
+
addStart(value);
|
|
36918
|
+
}
|
|
36919
|
+
if (containMode !== 'trimSnaps') {
|
|
36920
|
+
addStart(lastStart);
|
|
36921
|
+
}
|
|
36922
|
+
starts.sort((a, b) => a - b);
|
|
36923
|
+
return starts;
|
|
36924
|
+
}, [totalItems, loop, scrollStep, containMode, lastStart]);
|
|
36925
|
+
const pagedItems = useMemo(() => {
|
|
36926
|
+
if (!totalItems)
|
|
36927
|
+
return [];
|
|
36928
|
+
return pageStartIndices.map(start => {
|
|
36929
|
+
const group = [];
|
|
36930
|
+
for (let offset = 0; offset < visibleSlides; offset++) {
|
|
36931
|
+
const targetIndex = start + offset;
|
|
36932
|
+
if (loop) {
|
|
36933
|
+
const normalized = ((targetIndex % totalItems) + totalItems) % totalItems;
|
|
36934
|
+
group.push(itemsArray[normalized]);
|
|
36935
|
+
}
|
|
36936
|
+
else if (targetIndex < totalItems) {
|
|
36937
|
+
group.push(itemsArray[targetIndex]);
|
|
36938
|
+
}
|
|
36939
|
+
}
|
|
36940
|
+
return group;
|
|
36941
|
+
});
|
|
36942
|
+
}, [pageStartIndices, visibleSlides, loop, totalItems, itemsArray]);
|
|
36943
|
+
const totalPages = pagedItems.length;
|
|
36944
|
+
const normalizedStartIndex = useMemo(() => {
|
|
36945
|
+
if (!totalItems)
|
|
36946
|
+
return 0;
|
|
36947
|
+
const rawIndex = startIndex !== null && startIndex !== void 0 ? startIndex : 0;
|
|
36948
|
+
if (loop) {
|
|
36949
|
+
return ((rawIndex % totalItems) + totalItems) % totalItems;
|
|
36950
|
+
}
|
|
36951
|
+
return Math.max(0, Math.min(rawIndex, Math.max(totalItems - 1, 0)));
|
|
36952
|
+
}, [startIndex, totalItems, loop]);
|
|
36953
|
+
const initialPageStart = useMemo(() => {
|
|
36954
|
+
if (!totalItems)
|
|
36955
|
+
return 0;
|
|
36956
|
+
const base = Math.floor(normalizedStartIndex / scrollStep) * scrollStep;
|
|
36957
|
+
if (loop) {
|
|
36958
|
+
return totalItems ? base % totalItems : 0;
|
|
36959
|
+
}
|
|
36960
|
+
if (containMode === 'none') {
|
|
36961
|
+
return Math.min(base, Math.max(totalItems - 1, 0));
|
|
36962
|
+
}
|
|
36963
|
+
if (containMode === 'keepSnaps') {
|
|
36964
|
+
return Math.min(base, Math.max(totalItems - 1, 0));
|
|
36965
|
+
}
|
|
36966
|
+
return Math.min(base, lastStart);
|
|
36967
|
+
}, [normalizedStartIndex, scrollStep, loop, totalItems, containMode, lastStart]);
|
|
36968
|
+
const initialPageIndex = useMemo(() => {
|
|
36969
|
+
if (!pageStartIndices.length)
|
|
36970
|
+
return 0;
|
|
36971
|
+
const idx = pageStartIndices.indexOf(initialPageStart);
|
|
36972
|
+
return idx >= 0 ? idx : 0;
|
|
36973
|
+
}, [pageStartIndices, initialPageStart]);
|
|
37535
36974
|
const handleLayout = useCallback((e) => {
|
|
37536
36975
|
setContainerWidth(e.nativeEvent.layout.width);
|
|
37537
36976
|
setContainerHeight(e.nativeEvent.layout.height);
|
|
37538
36977
|
}, []);
|
|
37539
|
-
const
|
|
37540
|
-
if (!carouselRef.current)
|
|
37541
|
-
return;
|
|
37542
|
-
if (totalItems === 0)
|
|
36978
|
+
const scrollToPage = useCallback((index, animated = true) => {
|
|
36979
|
+
if (!carouselRef.current || totalPages === 0)
|
|
37543
36980
|
return;
|
|
37544
|
-
const clamped = ((index %
|
|
36981
|
+
const clamped = ((index % totalPages) + totalPages) % totalPages;
|
|
37545
36982
|
const delta = clamped - currentIndex;
|
|
37546
|
-
if (delta === 0)
|
|
36983
|
+
if (delta === 0) {
|
|
36984
|
+
if (!animated) {
|
|
36985
|
+
progress.value = clamped;
|
|
36986
|
+
setCurrentIndex(clamped);
|
|
36987
|
+
}
|
|
37547
36988
|
return;
|
|
37548
|
-
|
|
36989
|
+
}
|
|
37549
36990
|
let count = delta;
|
|
37550
36991
|
if (loop) {
|
|
37551
|
-
const alt = delta > 0 ? delta -
|
|
36992
|
+
const alt = delta > 0 ? delta - totalPages : delta + totalPages;
|
|
37552
36993
|
if (Math.abs(alt) < Math.abs(count))
|
|
37553
36994
|
count = alt;
|
|
37554
36995
|
}
|
|
37555
|
-
carouselRef.current.scrollTo({ count, animated
|
|
37556
|
-
|
|
36996
|
+
carouselRef.current.scrollTo({ count, animated });
|
|
36997
|
+
if (!animated) {
|
|
36998
|
+
progress.value = clamped;
|
|
36999
|
+
setCurrentIndex(clamped);
|
|
37000
|
+
}
|
|
37001
|
+
}, [carouselRef, totalPages, currentIndex, loop, progress]);
|
|
37002
|
+
const goTo = useCallback((index) => {
|
|
37003
|
+
scrollToPage(index, true);
|
|
37004
|
+
}, [scrollToPage]);
|
|
37557
37005
|
const goPrev = useCallback(() => {
|
|
37558
37006
|
if (!carouselRef.current)
|
|
37559
37007
|
return;
|
|
@@ -37564,13 +37012,22 @@ const Carousel = (props) => {
|
|
|
37564
37012
|
return;
|
|
37565
37013
|
carouselRef.current.next();
|
|
37566
37014
|
}, []);
|
|
37567
|
-
const totalPages = useMemo(() => totalItems, [totalItems]);
|
|
37568
37015
|
// Page progress derived directly from absolute item progress
|
|
37569
37016
|
const pageProgress = useDerivedValue(() => {
|
|
37570
37017
|
return progress.value;
|
|
37571
37018
|
}, []);
|
|
37572
37019
|
const arrowMetrics = useMemo(() => resolveCarouselArrowMetrics(arrowSize), [arrowSize]);
|
|
37573
37020
|
const dotMetrics = useMemo(() => resolveCarouselDotMetrics(dotSize), [dotSize]);
|
|
37021
|
+
const alignJustify = useMemo(() => {
|
|
37022
|
+
switch (align) {
|
|
37023
|
+
case 'center':
|
|
37024
|
+
return 'center';
|
|
37025
|
+
case 'end':
|
|
37026
|
+
return 'flex-end';
|
|
37027
|
+
default:
|
|
37028
|
+
return 'flex-start';
|
|
37029
|
+
}
|
|
37030
|
+
}, [align]);
|
|
37574
37031
|
// Memoized render functions to prevent unnecessary re-renders
|
|
37575
37032
|
const renderDots = useMemo(() => {
|
|
37576
37033
|
if (!showDots || totalPages <= 1)
|
|
@@ -37586,7 +37043,7 @@ const Carousel = (props) => {
|
|
|
37586
37043
|
}, [showDots, totalPages, pageProgress, dotMetrics, loop, theme, goTo, isVertical, isRTL]);
|
|
37587
37044
|
// Arrows
|
|
37588
37045
|
const renderArrows = () => {
|
|
37589
|
-
if (!showArrows ||
|
|
37046
|
+
if (!showArrows || totalPages <= 1)
|
|
37590
37047
|
return null;
|
|
37591
37048
|
const buttonSize = arrowMetrics.buttonSizeToken;
|
|
37592
37049
|
const iconSize = arrowMetrics.iconSize;
|
|
@@ -37623,37 +37080,69 @@ const Carousel = (props) => {
|
|
|
37623
37080
|
}, children: jsx(Button, { size: buttonSize, variant: "secondary", icon: jsx(Icon, { name: isRTL ? 'chevron-left' : 'chevron-right', size: iconSize }), onPress: goNext, radius: "full" }) })] }));
|
|
37624
37081
|
};
|
|
37625
37082
|
// Autoplay: if library autoPlay not sufficient for pause logic, we can just pass through for now.
|
|
37626
|
-
const enableAutoPlay = autoPlay &&
|
|
37083
|
+
const enableAutoPlay = autoPlay && totalPages > 1;
|
|
37084
|
+
useEffect(() => {
|
|
37085
|
+
if (!carouselRef.current || totalPages === 0 || !hasLayout)
|
|
37086
|
+
return;
|
|
37087
|
+
const controlledStart = startIndex != null;
|
|
37088
|
+
if (controlledStart) {
|
|
37089
|
+
scrollToPage(initialPageIndex, false);
|
|
37090
|
+
return;
|
|
37091
|
+
}
|
|
37092
|
+
if (!hasInitializedRef.current) {
|
|
37093
|
+
scrollToPage(initialPageIndex, false);
|
|
37094
|
+
hasInitializedRef.current = true;
|
|
37095
|
+
}
|
|
37096
|
+
}, [scrollToPage, initialPageIndex, startIndex, totalPages, hasLayout]);
|
|
37627
37097
|
return (jsxs(View, { ref: containerRef, style: [
|
|
37628
37098
|
{
|
|
37099
|
+
width: '100%',
|
|
37629
37100
|
position: 'relative',
|
|
37630
37101
|
...(isVertical ? { flexDirection: 'row' } : {})
|
|
37631
37102
|
},
|
|
37632
37103
|
spacingStyles,
|
|
37633
37104
|
style
|
|
37634
|
-
], onLayout: handleLayout, ...otherProps, children: [jsx(View, { style: { flex: 1 }, children:
|
|
37105
|
+
], onLayout: handleLayout, ...otherProps, children: [jsx(View, { style: { flex: 1 }, children: hasLayout && pagedItems.length > 0 && cardSize > 0 && (jsx(ReanimatedCarousel, { ref: carouselRef, width: isVertical ? containerWidth : containerWidth, height: isVertical ? containerHeight : height, style: isVertical ? { height: containerHeight } : { width: containerWidth }, vertical: isVertical, loop: loop, autoPlay: enableAutoPlay, autoPlayInterval: autoPlayInterval, data: pagedItems, pagingEnabled: isDragFree ? false : snapToItem, snapEnabled: isDragFree ? false : undefined, windowSize: windowSize > 0 ? windowSize : undefined, scrollAnimationDuration: duration,
|
|
37635
37106
|
// Performance optimizations
|
|
37636
37107
|
overscrollEnabled: false, enabled: !reducedMotion, withAnimation: reducedMotion ?
|
|
37637
37108
|
{ type: 'timing', config: { duration: 100 } } :
|
|
37638
|
-
{ type: 'spring', config: { damping: 60, stiffness: 150 } }, onProgressChange: (offset, absolute) => {
|
|
37109
|
+
{ type: 'spring', config: { damping: 60, stiffness: 150 } }, maxScrollDistancePerSwipe: maxScrollDistancePerSwipe, minScrollDistancePerSwipe: dragThresholdValue, onProgressChange: (offset, absolute) => {
|
|
37639
37110
|
// absolute may be undefined in some versions; fallback to offset
|
|
37640
37111
|
const val = typeof absolute === 'number' ? absolute : offset;
|
|
37641
37112
|
progress.value = val;
|
|
37642
|
-
const ci =
|
|
37113
|
+
const ci = totalPages > 0
|
|
37114
|
+
? ((Math.round(val) % totalPages) + totalPages) % totalPages
|
|
37115
|
+
: 0;
|
|
37643
37116
|
if (ci !== currentIndex) {
|
|
37644
37117
|
setCurrentIndex(ci);
|
|
37645
37118
|
onSlideChange === null || onSlideChange === void 0 ? void 0 : onSlideChange(ci);
|
|
37646
37119
|
}
|
|
37647
|
-
}, renderItem: ({ item, index }) =>
|
|
37648
|
-
|
|
37649
|
-
|
|
37650
|
-
|
|
37651
|
-
|
|
37652
|
-
|
|
37653
|
-
|
|
37654
|
-
|
|
37655
|
-
|
|
37656
|
-
|
|
37120
|
+
}, renderItem: ({ item, index }) => {
|
|
37121
|
+
const pageItems = Array.isArray(item) ? item : [item];
|
|
37122
|
+
const pageWidth = isVertical ? containerWidth : containerWidth;
|
|
37123
|
+
const pageHeight = isVertical ? containerHeight : height;
|
|
37124
|
+
const justify = containMode === 'trimSnaps' ? 'flex-start' : alignJustify;
|
|
37125
|
+
return (jsx(View, { style: [
|
|
37126
|
+
{
|
|
37127
|
+
width: pageWidth,
|
|
37128
|
+
height: pageHeight,
|
|
37129
|
+
justifyContent: 'center',
|
|
37130
|
+
},
|
|
37131
|
+
itemStyle,
|
|
37132
|
+
], accessibilityLabel: `Carousel item ${index + 1} of ${totalPages}`, children: jsx(View, { style: {
|
|
37133
|
+
flexDirection: isVertical ? 'column' : 'row',
|
|
37134
|
+
alignItems: 'stretch',
|
|
37135
|
+
justifyContent: justify,
|
|
37136
|
+
flexWrap: 'nowrap',
|
|
37137
|
+
flex: 1,
|
|
37138
|
+
}, children: pageItems.map((child, childIndex) => (jsx(View, { style: {
|
|
37139
|
+
width: isVertical ? '100%' : cardSize,
|
|
37140
|
+
height: isVertical ? cardSize : '100%',
|
|
37141
|
+
marginRight: !isVertical && childIndex < pageItems.length - 1 ? resolvedGap : 0,
|
|
37142
|
+
marginBottom: isVertical && childIndex < pageItems.length - 1 ? resolvedGap : 0,
|
|
37143
|
+
flexShrink: 0,
|
|
37144
|
+
}, children: child }, childIndex))) }) }));
|
|
37145
|
+
} })) }), renderArrows(), renderDots] }));
|
|
37657
37146
|
};
|
|
37658
37147
|
|
|
37659
37148
|
// Types extracted to types.ts
|
|
@@ -39574,11 +39063,14 @@ QRCodeSVG.displayName = 'QRCodeSVG';
|
|
|
39574
39063
|
*/
|
|
39575
39064
|
function QRCode(props) {
|
|
39576
39065
|
var _a;
|
|
39066
|
+
const theme = useTheme();
|
|
39577
39067
|
const { spacingProps, otherProps: propsAfterSpacing } = extractSpacingProps(props);
|
|
39578
39068
|
const { layoutProps, otherProps } = extractLayoutProps(propsAfterSpacing);
|
|
39579
|
-
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
|
|
39580
39070
|
onLoadEnd, // deprecated noop
|
|
39581
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;
|
|
39582
39074
|
const { copy } = useClipboard();
|
|
39583
39075
|
const toast = useToast();
|
|
39584
39076
|
const shouldCopyOnPress = !!otherProps.copyOnPress;
|
|
@@ -39594,7 +39086,7 @@ function QRCode(props) {
|
|
|
39594
39086
|
});
|
|
39595
39087
|
}
|
|
39596
39088
|
}, [copy, copyValue, toast, otherProps.copyToastMessage, otherProps.copyToastTitle]);
|
|
39597
|
-
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: () => { } }))] }));
|
|
39598
39090
|
if (shouldCopyOnPress) {
|
|
39599
39091
|
return (jsx(Pressable, { onPress: handleCopy, accessibilityLabel: accessibilityLabel || 'QR code', children: content }));
|
|
39600
39092
|
}
|
|
@@ -41667,5 +41159,5 @@ function withPressAnimation(Component, animationProps) {
|
|
|
41667
41159
|
*/
|
|
41668
41160
|
const AnimatedPressable = PressAnimation;
|
|
41669
41161
|
|
|
41670
|
-
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 };
|
|
41671
41163
|
//# sourceMappingURL=index.js.map
|