@vellira-ui/react-native 2.40.0 → 2.41.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/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export type { SelectOption, SelectProps } from './components/Select';
8
8
  export { Select } from './components/Select';
9
9
  export type { TabsContentProps, TabsListProps, TabsProps, TabsTriggerProps, } from './components/Tabs';
10
10
  export { Tabs } from './components/Tabs';
11
- export type { TooltipProps } from './components/Tooltip';
11
+ export type { TooltipArrowProps, TooltipContentProps, TooltipProps, TooltipRootProps, TooltipTriggerProps, } from './components/Tooltip';
12
12
  export { Tooltip } from './components/Tooltip';
13
13
  export type { FormFieldProps } from './patterns/FormField';
14
14
  export { FormField } from './patterns/FormField';
package/dist/index.js CHANGED
@@ -4155,6 +4155,50 @@ const Tabs = Object.assign(TabsRoot, {
4155
4155
  });
4156
4156
  Tabs.displayName = "Tabs";
4157
4157
  //#endregion
4158
+ //#region src/components/Tooltip/internal/TooltipContext.tsx
4159
+ const TooltipContext = createContext(null);
4160
+ const TooltipProvider = TooltipContext.Provider;
4161
+ const useTooltipContext = () => {
4162
+ const context = useContext(TooltipContext);
4163
+ if (!context) throw new Error("Tooltip components must be used inside <Tooltip>.");
4164
+ return context;
4165
+ };
4166
+ TooltipContext.displayName = "TooltipContext";
4167
+ //#endregion
4168
+ //#region src/components/Tooltip/Arrow/TooltipArrow.tsx
4169
+ const TooltipArrow = ({ style }) => {
4170
+ const { theme } = useTheme();
4171
+ const tooltip = useTooltipContext();
4172
+ const size = theme.components.tooltip.arrow.size;
4173
+ const side = tooltip.placement.split("-")[0];
4174
+ const staticSide = {
4175
+ top: "bottom",
4176
+ right: "left",
4177
+ bottom: "top",
4178
+ left: "right"
4179
+ }[side];
4180
+ const crossAxisStyle = side === "left" || side === "right" ? {
4181
+ top: "50%",
4182
+ marginTop: -size / 2
4183
+ } : {
4184
+ left: "50%",
4185
+ marginLeft: -size / 2
4186
+ };
4187
+ return /* @__PURE__ */ jsx(View, {
4188
+ pointerEvents: "none",
4189
+ style: [{
4190
+ position: "absolute",
4191
+ width: size,
4192
+ height: size,
4193
+ backgroundColor: theme.components.tooltip.arrow.bg,
4194
+ transform: [{ rotate: "45deg" }],
4195
+ [staticSide]: -size / 2,
4196
+ ...crossAxisStyle
4197
+ }, style]
4198
+ });
4199
+ };
4200
+ TooltipArrow.displayName = "Tooltip.Arrow";
4201
+ //#endregion
4158
4202
  //#region src/components/Tooltip/Tooltip.styles.ts
4159
4203
  const createStyles$3 = (theme) => StyleSheet.create({
4160
4204
  root: { alignSelf: "flex-start" },
@@ -4162,13 +4206,13 @@ const createStyles$3 = (theme) => StyleSheet.create({
4162
4206
  bubble: {
4163
4207
  position: "absolute",
4164
4208
  zIndex: 1e3,
4165
- maxWidth: 280,
4166
- paddingHorizontal: theme.tokens.spacing[3],
4167
- paddingVertical: theme.tokens.spacing[2],
4209
+ maxWidth: theme.components.tooltip.content.maxWidth,
4210
+ paddingHorizontal: theme.components.tooltip.content.paddingX,
4211
+ paddingVertical: theme.components.tooltip.content.paddingY,
4168
4212
  backgroundColor: theme.components.tooltip.content.bg,
4169
4213
  borderColor: theme.components.tooltip.content.border,
4170
- borderRadius: theme.tokens.radius.sm,
4171
- borderWidth: 1,
4214
+ borderRadius: theme.components.tooltip.content.radius,
4215
+ borderWidth: theme.components.tooltip.content.borderWidth,
4172
4216
  shadowColor: theme.tokens.shadows.md.color,
4173
4217
  shadowOffset: {
4174
4218
  width: theme.tokens.shadows.md.x,
@@ -4182,83 +4226,192 @@ const createStyles$3 = (theme) => StyleSheet.create({
4182
4226
  flexShrink: 1,
4183
4227
  color: theme.components.tooltip.content.fg,
4184
4228
  fontFamily: theme.tokens.typography.family.regular,
4185
- fontSize: theme.tokens.typography.size.sm,
4186
- lineHeight: theme.tokens.typography.lineHeight.sm,
4229
+ fontSize: theme.components.tooltip.content.fontSize,
4230
+ lineHeight: theme.components.tooltip.content.lineHeight,
4187
4231
  textAlign: "center"
4188
4232
  }
4189
4233
  });
4190
4234
  //#endregion
4191
- //#region src/components/Tooltip/Tooltip.tsx
4192
- function Tooltip({ children, content, placement = "top", disabled = false, maxWidth = 240, delay, style, contentStyle, textStyle }) {
4235
+ //#region src/components/Tooltip/Content/TooltipContent.tsx
4236
+ const TooltipContent = ({ children, forceMount = false, style, textStyle }) => {
4193
4237
  const styles = useThemeStyles(createStyles$3);
4194
- const overlayId = useId();
4195
- const [visible, setVisible] = useState(false);
4238
+ const tooltip = useTooltipContext();
4239
+ const visible = tooltip.open && !tooltip.disabled;
4240
+ if (!forceMount && !visible) return null;
4241
+ const bubble = /* @__PURE__ */ jsx(View, {
4242
+ nativeID: tooltip.contentId,
4243
+ pointerEvents: "none",
4244
+ style: [
4245
+ styles.bubble,
4246
+ {
4247
+ top: tooltip.position.top,
4248
+ left: tooltip.position.left
4249
+ },
4250
+ !visible && { display: "none" },
4251
+ style
4252
+ ],
4253
+ onLayout: tooltip.onFloatingLayout,
4254
+ children: Children.map(children, (child) => typeof child === "string" || typeof child === "number" ? /* @__PURE__ */ jsx(Text, {
4255
+ style: [styles.text, textStyle],
4256
+ children: child
4257
+ }) : child)
4258
+ });
4259
+ if (!visible) return bubble;
4260
+ return /* @__PURE__ */ jsx(Modal$1, {
4261
+ visible,
4262
+ transparent: true,
4263
+ animationType: "fade",
4264
+ onRequestClose: tooltip.requestClose,
4265
+ children: /* @__PURE__ */ jsx(Pressable, {
4266
+ style: styles.overlay,
4267
+ onPress: tooltip.requestOutsideClose,
4268
+ children: bubble
4269
+ })
4270
+ });
4271
+ };
4272
+ TooltipContent.displayName = "Tooltip.Content";
4273
+ //#endregion
4274
+ //#region src/components/Tooltip/internal/useTooltipDelay.ts
4275
+ const resolveTooltipDelay = (delay) => {
4276
+ if (typeof delay === "number") return {
4277
+ open: delay,
4278
+ close: 2500
4279
+ };
4280
+ return {
4281
+ open: delay?.open ?? 0,
4282
+ close: delay?.close ?? 2500
4283
+ };
4284
+ };
4285
+ //#endregion
4286
+ //#region src/components/Tooltip/Root/TooltipRoot.tsx
4287
+ const TooltipRoot = ({ children, open: openProp, defaultOpen = false, onOpenChange, placement = "top", disabled = false, delay, offset = 8, closeOnOutsidePress = true, style }) => {
4288
+ const contentId = `${useId()}-content`;
4196
4289
  const triggerRef = useRef(null);
4197
4290
  const closeTimerRef = useRef(null);
4198
- const { position, updatePosition, onFloatingLayout } = useNativeFloatingPosition(placement, 8);
4199
- const hideDelay = delay?.close ?? 2500;
4200
- const clearCloseTimer = () => {
4291
+ const resolvedDelay = useMemo(() => resolveTooltipDelay(delay), [delay]);
4292
+ const [open, setOpenState] = useControllableState({
4293
+ value: openProp,
4294
+ defaultValue: defaultOpen,
4295
+ onChange: onOpenChange
4296
+ });
4297
+ const { position, updatePosition, onFloatingLayout } = useNativeFloatingPosition(placement, offset);
4298
+ const clearCloseTimer = useCallback(() => {
4201
4299
  if (closeTimerRef.current) {
4202
4300
  clearTimeout(closeTimerRef.current);
4203
4301
  closeTimerRef.current = null;
4204
4302
  }
4205
- };
4206
- const dismiss = useNativeDismiss({
4207
- id: overlayId,
4208
- visible: visible && !disabled,
4209
- onClose: () => {
4210
- clearCloseTimer();
4211
- setVisible(false);
4212
- }
4213
- });
4214
- const showTooltip = () => {
4303
+ }, []);
4304
+ const setOpen = useCallback((nextOpen) => {
4305
+ if (disabled && nextOpen) return;
4306
+ setOpenState(nextOpen);
4307
+ }, [disabled, setOpenState]);
4308
+ const hide = useCallback(() => {
4309
+ clearCloseTimer();
4310
+ setOpen(false);
4311
+ }, [clearCloseTimer, setOpen]);
4312
+ const show = useCallback(() => {
4215
4313
  if (disabled) return;
4216
4314
  clearCloseTimer();
4217
4315
  updatePosition(triggerRef);
4218
- setVisible(true);
4219
- closeTimerRef.current = setTimeout(() => {
4220
- setVisible(false);
4221
- closeTimerRef.current = null;
4222
- }, hideDelay);
4223
- };
4316
+ const openTooltip = () => {
4317
+ setOpen(true);
4318
+ closeTimerRef.current = setTimeout(() => {
4319
+ setOpen(false);
4320
+ closeTimerRef.current = null;
4321
+ }, resolvedDelay.close);
4322
+ };
4323
+ if (resolvedDelay.open > 0) {
4324
+ closeTimerRef.current = setTimeout(openTooltip, resolvedDelay.open);
4325
+ return;
4326
+ }
4327
+ openTooltip();
4328
+ }, [
4329
+ clearCloseTimer,
4330
+ disabled,
4331
+ resolvedDelay,
4332
+ setOpen,
4333
+ updatePosition
4334
+ ]);
4335
+ const dismiss = useNativeDismiss({
4336
+ id: contentId,
4337
+ visible: open && !disabled,
4338
+ closeOnOutsidePress,
4339
+ onClose: hide
4340
+ });
4341
+ useEffect(() => {
4342
+ if (disabled && open) hide();
4343
+ }, [
4344
+ disabled,
4345
+ hide,
4346
+ open
4347
+ ]);
4224
4348
  useEffect(() => {
4225
4349
  return clearCloseTimer;
4226
- }, []);
4227
- return /* @__PURE__ */ jsxs(View, {
4228
- style: [styles.root, style],
4229
- children: [/* @__PURE__ */ jsx(Pressable, {
4230
- ref: triggerRef,
4231
- onLongPress: showTooltip,
4350
+ }, [clearCloseTimer]);
4351
+ return /* @__PURE__ */ jsx(TooltipProvider, {
4352
+ value: useMemo(() => ({
4353
+ contentId,
4354
+ open,
4355
+ disabled,
4356
+ placement,
4357
+ position,
4358
+ triggerRef,
4359
+ setOpen,
4360
+ show,
4361
+ hide,
4362
+ requestClose: dismiss.requestClose,
4363
+ requestOutsideClose: dismiss.requestOutsideClose,
4364
+ onFloatingLayout
4365
+ }), [
4366
+ contentId,
4367
+ disabled,
4368
+ dismiss.requestClose,
4369
+ dismiss.requestOutsideClose,
4370
+ hide,
4371
+ open,
4372
+ placement,
4373
+ position,
4374
+ setOpen,
4375
+ show,
4376
+ onFloatingLayout
4377
+ ]),
4378
+ children: /* @__PURE__ */ jsx(View, {
4379
+ style,
4232
4380
  children
4233
- }), /* @__PURE__ */ jsx(Modal$1, {
4234
- visible: visible && !disabled,
4235
- transparent: true,
4236
- animationType: "fade",
4237
- onRequestClose: dismiss.requestClose,
4238
- children: /* @__PURE__ */ jsx(Pressable, {
4239
- style: styles.overlay,
4240
- onPress: dismiss.requestOutsideClose,
4241
- children: /* @__PURE__ */ jsx(View, {
4242
- pointerEvents: "none",
4243
- style: [
4244
- styles.bubble,
4245
- {
4246
- maxWidth,
4247
- top: position.top,
4248
- left: position.left
4249
- },
4250
- contentStyle
4251
- ],
4252
- onLayout: onFloatingLayout,
4253
- children: typeof content === "string" ? /* @__PURE__ */ jsx(Text, {
4254
- style: [styles.text, textStyle],
4255
- children: content
4256
- }) : content
4257
- })
4258
- })
4259
- })]
4381
+ })
4260
4382
  });
4261
- }
4383
+ };
4384
+ TooltipRoot.displayName = "Tooltip.Root";
4385
+ //#endregion
4386
+ //#region src/components/Tooltip/Trigger/TooltipTrigger.tsx
4387
+ const TooltipTrigger = ({ children, disabled, onLongPress, style, ...props }) => {
4388
+ const tooltip = useTooltipContext();
4389
+ const isDisabled = tooltip.disabled || disabled;
4390
+ return /* @__PURE__ */ jsx(Pressable, {
4391
+ ...props,
4392
+ ref: tooltip.triggerRef,
4393
+ accessibilityState: {
4394
+ ...props.accessibilityState,
4395
+ disabled: isDisabled || props.accessibilityState?.disabled
4396
+ },
4397
+ disabled: isDisabled,
4398
+ onLongPress: (event) => {
4399
+ onLongPress?.(event);
4400
+ if (event.defaultPrevented) return;
4401
+ tooltip.show();
4402
+ },
4403
+ style,
4404
+ children
4405
+ });
4406
+ };
4407
+ TooltipTrigger.displayName = "Tooltip.Trigger";
4408
+ //#endregion
4409
+ //#region src/components/Tooltip/Tooltip.tsx
4410
+ const Tooltip = Object.assign(TooltipRoot, {
4411
+ Trigger: TooltipTrigger,
4412
+ Content: TooltipContent,
4413
+ Arrow: TooltipArrow
4414
+ });
4262
4415
  Tooltip.displayName = "Tooltip";
4263
4416
  //#endregion
4264
4417
  //#region src/utils/devWarning.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellira-ui/react-native",
3
- "version": "2.40.0",
3
+ "version": "2.41.0",
4
4
  "description": "React Native components for Vellira Design System",
5
5
  "author": "Roman Bakurov",
6
6
  "license": "MIT",