periplo-ui 3.33.0 → 3.34.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.
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
3
  import { CalendarBlank, X } from '@phosphor-icons/react';
4
4
  import { format } from 'date-fns';
5
5
  import { fr, it, de, enGB, pt, es, enUS } from 'date-fns/locale';
@@ -39,6 +39,7 @@ function DatePicker({
39
39
  }) {
40
40
  const [isOpen, setIsOpen] = React.useState(false);
41
41
  const [isHovered, setIsHovered] = React.useState(false);
42
+ const [isClicked, setIsClicked] = React.useState(false);
42
43
  const isMobile = useIsMobile();
43
44
  const calendarRef = React.useRef(null);
44
45
  const resolvedLocale = React.useMemo(() => {
@@ -59,6 +60,11 @@ function DatePicker({
59
60
  }
60
61
  return void 0;
61
62
  });
63
+ React.useEffect(() => {
64
+ const handleWindowMouseUp = () => setIsClicked(false);
65
+ window.addEventListener("mouseup", handleWindowMouseUp);
66
+ return () => window.removeEventListener("mouseup", handleWindowMouseUp);
67
+ }, []);
62
68
  React.useEffect(() => {
63
69
  if (variant === "single") {
64
70
  const newDate = parseInputDate(valueProp);
@@ -149,6 +155,42 @@ function DatePicker({
149
155
  if (!dateRange.to) return `${fromStr} - ...`;
150
156
  return `${fromStr} - ${toStr}`;
151
157
  };
158
+ const renderClearIcon = (showClearIcon) => {
159
+ if (!showClearIcon) return null;
160
+ const clearIconClassName = "pointer-events-none absolute right-4 z-10 flex h-full w-10 items-center justify-end rounded-r-lg bg-gradient-to-l from-60% via-80% to-transparent";
161
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
162
+ /* @__PURE__ */ jsx(
163
+ "div",
164
+ {
165
+ className: cn(
166
+ clearIconClassName,
167
+ "from-neutral-50 via-neutral-50/80",
168
+ isHovered ? "opacity-100" : "opacity-0"
169
+ )
170
+ }
171
+ ),
172
+ /* @__PURE__ */ jsx(
173
+ "div",
174
+ {
175
+ className: cn(
176
+ clearIconClassName,
177
+ "from-neutral-100 via-neutral-100/80",
178
+ isClicked ? "opacity-100" : "opacity-0"
179
+ )
180
+ }
181
+ ),
182
+ /* @__PURE__ */ jsx("div", { className: "absolute right-4 z-20 flex h-full w-10 items-center justify-end", children: /* @__PURE__ */ jsx(
183
+ X,
184
+ {
185
+ "data-testid": "clear-button",
186
+ className: cn(
187
+ "h-4 w-4 shrink-0 cursor-pointer opacity-100 transition-opacity duration-150 hover:opacity-70"
188
+ ),
189
+ onClick: handleClear
190
+ }
191
+ ) })
192
+ ] });
193
+ };
152
194
  const calendarProps = React.useMemo(() => {
153
195
  const baseProps = {
154
196
  defaultMonth: (variant === "single" ? singleDate : dateRange?.from) ?? defaultMonth,
@@ -175,13 +217,13 @@ function DatePicker({
175
217
  const hasValue = variant === "single" ? singleDate : dateRange;
176
218
  const showClearButton = onClear && hasValue && isHovered;
177
219
  return /* @__PURE__ */ jsxs(PopoverRoot, { open: isOpen, onOpenChange: setIsOpen, modal, children: [
178
- /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
220
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
179
221
  Button,
180
222
  {
181
223
  id: rest.id,
182
224
  variant: "ghost",
183
225
  className: cn(
184
- "relative flex w-fit items-center justify-start text-left font-normal",
226
+ "relative flex w-fit items-center justify-start text-left font-normal hover:transition-opacity",
185
227
  !hasValue && "text-muted-foreground",
186
228
  buttonVariants({ variant: "input" }),
187
229
  buttonClassName
@@ -189,29 +231,12 @@ function DatePicker({
189
231
  disabled: typeof rest.disabled === "boolean" ? rest.disabled : false,
190
232
  onMouseEnter: () => !isMobile && setIsHovered(true),
191
233
  onMouseLeave: () => !isMobile && setIsHovered(false),
192
- children: [
193
- /* @__PURE__ */ jsx("span", { className: "w-full pr-7 text-center", children: formatForDisplay() }),
194
- /* @__PURE__ */ jsx(
195
- CalendarBlank,
196
- {
197
- className: cn(
198
- "absolute right-4 h-4 w-4 shrink-0 transition-opacity duration-150",
199
- showClearButton ? "opacity-0" : "opacity-100"
200
- )
201
- }
202
- ),
203
- onClear && hasValue && /* @__PURE__ */ jsx(
204
- X,
205
- {
206
- "data-testid": "clear-button",
207
- className: cn(
208
- "absolute right-4 h-4 w-4 shrink-0 cursor-pointer transition-opacity duration-150",
209
- showClearButton ? "opacity-100 hover:opacity-70" : "opacity-0"
210
- ),
211
- onClick: handleClear
212
- }
213
- )
214
- ]
234
+ onMouseDown: () => !isMobile && setIsClicked(true),
235
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-2", children: [
236
+ /* @__PURE__ */ jsx(CalendarBlank, { className: cn("h-4 w-4 shrink-0 transition-opacity duration-150") }),
237
+ /* @__PURE__ */ jsx("span", { className: "w-full text-center", children: formatForDisplay() }),
238
+ onClear && hasValue && renderClearIcon(showClearButton ?? false)
239
+ ] })
215
240
  }
216
241
  ) }),
217
242
  /* @__PURE__ */ jsx(PopoverContent, { className: "w-auto p-0", align: "center", ref: calendarRef, children: /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"file":"DatePicker.js","sources":["../../../src/components/DatePicker/DatePicker.tsx"],"sourcesContent":["'use client'\n\nimport { CalendarBlank, X } from '@phosphor-icons/react'\nimport { format as formatFn, Locale } from 'date-fns'\nimport { enUS, es, pt, enGB, de, it, fr } from 'date-fns/locale'\nimport * as React from 'react'\nimport { PropsBase, PropsRangeRequired, PropsSingleRequired } from 'react-day-picker'\n\nimport { Button, buttonVariants } from '../Button'\nimport { Calendar } from '../Calendar'\nimport { PopoverContent, PopoverRoot, PopoverTrigger } from '../Popover'\n\nimport {\n formatOutputDate,\n formatOutputRange,\n parseInputDate,\n parseInputRange,\n InputDate,\n InputRange,\n ValueFormat,\n} from '@/lib/dateUtils'\nimport { useIsMobile } from '@/lib/useMobile'\nimport { cn } from '@/lib/utils'\n\ntype SupportedLocaleString = 'enUS' | 'es' | 'pt' | 'enGB' | 'de' | 'it' | 'fr'\n\nconst localeMap: Record<SupportedLocaleString, Locale> = {\n enUS,\n es,\n pt,\n enGB,\n de,\n it,\n fr,\n}\n\nexport type DateRange = {\n from?: Date\n to?: Date\n}\n\nexport type IsoDateRange = {\n from?: string\n to?: string\n}\n\ntype DatePickerOutput<Variant extends 'single' | 'range', Format extends ValueFormat> = Variant extends 'single'\n ? Format extends 'date'\n ? Date | null\n : string | null\n : Format extends 'date'\n ? DateRange | null\n : IsoDateRange | null\n\ntype DatePickerInput<V extends 'single' | 'range'> = V extends 'single'\n ? Date | string | null\n : { from?: Date | string; to?: Date | string } | null\n\nexport type DatePickerProps<V extends 'single' | 'range' = 'single', F extends ValueFormat = 'iso'> = {\n /**\n * Placeholder text displayed when no date is selected\n * @default 'Pick a date' for single mode, 'Pick a date range' for range mode\n */\n readonly placeholder?: string\n\n /**\n * Format string to use when displaying the selected date in the button\n * @default 'MMM d, yyyy'\n */\n readonly displayFormat?: string\n\n /**\n * ClassName for the button\n */\n readonly buttonClassName?: string\n\n /**\n * Whether to allow the user to show the year switcher menu\n * @default true for single mode, false for range mode\n */\n readonly showYearSwitcher?: boolean\n\n /**\n * Initial value for the date picker\n * Accepts both Date objects and ISO strings regardless of valueFormat setting\n */\n readonly initialValue?: DatePickerInput<V>\n\n /**\n * Current value for the date picker\n * Accepts both Date objects and ISO strings regardless of valueFormat setting\n */\n readonly value?: DatePickerInput<V>\n\n /**\n * Determines if the picker should close after a selection\n * @default true for single mode, false for range mode\n */\n readonly closeOnSelect?: boolean\n\n /**\n * Determines the format of the value provided to the onChange callback\n * - 'iso' (default): onChange receives ISO string(s) ('yyyy-MM-dd') or empty string for cleared values\n * - 'date': onChange receives JavaScript Date object(s) or null for cleared values\n *\n * Note: The component accepts both Date objects and ISO strings for value/initialValue\n * regardless of this setting. Empty values are sent as null (date format) or '' (iso format)\n * instead of undefined to work properly with React Hook Form.\n * @default 'iso'\n */\n readonly valueFormat?: F\n\n /**\n * Callback when date or date range changes\n */\n readonly onChange?: (value: DatePickerOutput<V, F>) => void\n\n /**\n * DatePicker mode - single date or date range\n * @default 'single'\n */\n readonly variant?: V\n\n /**\n * The locale to use for formatting dates and determining the start of the week.\n * Can be a string identifier for supported locales ('enUS', 'es', 'pt', 'enGB', 'de', 'it', 'fr')\n * or a Locale object from date-fns/locale for other languages.\n * @default 'enUS'\n */\n readonly locale?: SupportedLocaleString | Locale\n\n /**\n * Callback function executed when the clear button is clicked.\n * When provided, an X button will appear on hover to clear the selected date.\n */\n readonly onClear?: boolean | (() => void)\n\n /**\n * Weather the picker is inside a modal (needed for pointer events to work at mobile)\n */\n modal?: boolean\n} & Omit<PropsBase, 'mode' | 'selected' | 'onSelect' | 'locale'>\n\nfunction DatePicker<V extends 'single' | 'range' = 'single', F extends ValueFormat = 'iso'>({\n variant = 'single' as V,\n placeholder = variant === 'single' ? 'Pick a date' : 'Pick a date range',\n valueFormat = 'iso' as F,\n initialValue: initialValueProp,\n value: valueProp,\n onChange,\n buttonClassName,\n displayFormat = 'MMM d, yyyy',\n closeOnSelect = variant === 'single',\n showYearSwitcher = variant === 'single',\n locale: localeProp = 'enUS',\n defaultMonth,\n onClear,\n modal = false,\n ...rest\n}: DatePickerProps<V, F>) {\n const [isOpen, setIsOpen] = React.useState(false)\n const [isHovered, setIsHovered] = React.useState(false)\n const isMobile = useIsMobile()\n const calendarRef = React.useRef<HTMLDivElement>(null)\n\n const resolvedLocale = React.useMemo(() => {\n if (typeof localeProp === 'string') {\n return localeMap[localeProp]\n }\n return localeProp\n }, [localeProp])\n\n const [internalSingleDate, setInternalSingleDate] = React.useState<Date | undefined>(() => {\n if (variant === 'single') {\n return parseInputDate(initialValueProp as InputDate)\n }\n return undefined\n })\n\n const [internalDateRange, setInternalDateRange] = React.useState<DateRange | undefined>(() => {\n if (variant === 'range') {\n return parseInputRange(initialValueProp as InputRange)\n }\n return undefined\n })\n\n React.useEffect(() => {\n if (variant === 'single') {\n const newDate = parseInputDate(valueProp as InputDate)\n setInternalSingleDate(newDate)\n } else {\n const newRange = parseInputRange(valueProp as InputRange)\n setInternalDateRange(newRange)\n }\n }, [valueProp, variant])\n\n React.useEffect(() => {\n if (isOpen && isMobile && calendarRef.current) {\n const timeoutId = setTimeout(() => {\n const calendarElement = calendarRef.current?.querySelector('[id=\"calendar\"]') as HTMLElement | null\n\n calendarElement?.focus()\n }, 100)\n\n return () => clearTimeout(timeoutId)\n }\n }, [isOpen, isMobile])\n\n const singleDate = internalSingleDate\n const dateRange = internalDateRange\n\n const getEmptyValue = React.useCallback((): DatePickerOutput<V, F> => {\n if (variant === 'single') {\n return (valueFormat === 'date' ? null : '') as DatePickerOutput<V, F>\n } else {\n return (valueFormat === 'date' ? null : { from: '', to: '' }) as DatePickerOutput<V, F>\n }\n }, [variant, valueFormat])\n\n const handleSelect = React.useCallback(\n (selectedDate: Date | DateRange | undefined) => {\n if (variant === 'single') {\n const date = selectedDate as Date | undefined\n\n setInternalSingleDate(date)\n\n if (onChange) {\n if (date) {\n const output = valueFormat === 'date' ? date : formatOutputDate(date, 'iso')\n onChange(output as DatePickerOutput<V, F>)\n } else {\n onChange(getEmptyValue())\n }\n }\n\n if (closeOnSelect) {\n setIsOpen(false)\n }\n } else {\n const range = selectedDate as DateRange | undefined\n setInternalDateRange(range)\n if (onChange) {\n if (range) {\n const output = valueFormat === 'date' ? range : formatOutputRange(range, 'iso')\n onChange(output as DatePickerOutput<V, F>)\n } else {\n onChange(getEmptyValue())\n }\n }\n }\n },\n [variant, valueFormat, onChange, closeOnSelect, getEmptyValue],\n )\n\n const handleClear = React.useCallback(\n (event: React.MouseEvent) => {\n if (isMobile) return\n\n event.preventDefault()\n event.stopPropagation()\n\n if (variant === 'single') {\n setInternalSingleDate(undefined)\n } else {\n setInternalDateRange(undefined)\n }\n\n if (onChange) {\n onChange(getEmptyValue())\n }\n\n if (typeof onClear === 'function') {\n onClear()\n }\n },\n [variant, onChange, onClear, getEmptyValue, isMobile],\n )\n\n const formatForDisplay = () => {\n const formatOptions = { locale: resolvedLocale }\n if (variant === 'single') {\n return singleDate ? formatFn(singleDate, displayFormat, formatOptions) : placeholder\n }\n\n if (!dateRange) return placeholder\n const fromStr = dateRange.from ? formatFn(dateRange.from, displayFormat, formatOptions) : '...'\n const toStr = dateRange.to ? formatFn(dateRange.to, displayFormat, formatOptions) : '...'\n if (!dateRange.from && !dateRange.to) return placeholder\n if (!dateRange.from) return `... - ${toStr}`\n if (!dateRange.to) return `${fromStr} - ...`\n return `${fromStr} - ${toStr}`\n }\n\n const calendarProps = React.useMemo(() => {\n const baseProps = {\n defaultMonth: (variant === 'single' ? singleDate : dateRange?.from) ?? defaultMonth,\n locale: resolvedLocale,\n initialFocus: true,\n ...rest,\n } as PropsBase\n\n if (variant === 'single') {\n return {\n ...baseProps,\n mode: 'single' as const,\n selected: singleDate,\n onSelect: (date: Date | undefined) => handleSelect(date),\n } as PropsSingleRequired\n }\n\n return {\n ...baseProps,\n mode: 'range' as const,\n selected: dateRange,\n onSelect: (range: DateRange | undefined) => handleSelect(range),\n numberOfMonths: rest.numberOfMonths ?? 2,\n } as PropsRangeRequired\n }, [variant, rest, singleDate, dateRange, handleSelect, resolvedLocale, defaultMonth])\n\n const hasValue = variant === 'single' ? singleDate : dateRange\n const showClearButton = onClear && hasValue && isHovered\n\n return (\n <PopoverRoot open={isOpen} onOpenChange={setIsOpen} modal={modal}>\n <PopoverTrigger asChild>\n <Button\n id={rest.id}\n variant=\"ghost\"\n className={cn(\n 'relative flex w-fit items-center justify-start text-left font-normal',\n !hasValue && 'text-muted-foreground',\n buttonVariants({ variant: 'input' }),\n buttonClassName,\n )}\n disabled={typeof rest.disabled === 'boolean' ? rest.disabled : false}\n onMouseEnter={() => !isMobile && setIsHovered(true)}\n onMouseLeave={() => !isMobile && setIsHovered(false)}\n >\n <span className=\"w-full pr-7 text-center\">{formatForDisplay()}</span>\n <CalendarBlank\n className={cn(\n 'absolute right-4 h-4 w-4 shrink-0 transition-opacity duration-150',\n showClearButton ? 'opacity-0' : 'opacity-100',\n )}\n />\n {onClear && hasValue && (\n <X\n data-testid=\"clear-button\"\n className={cn(\n 'absolute right-4 h-4 w-4 shrink-0 cursor-pointer transition-opacity duration-150',\n showClearButton ? 'opacity-100 hover:opacity-70' : 'opacity-0',\n )}\n onClick={handleClear}\n />\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\" align=\"center\" ref={calendarRef}>\n <Calendar\n {...calendarProps}\n className=\"border-0\"\n showYearSwitcher={variant === 'single' ? showYearSwitcher : false}\n />\n </PopoverContent>\n </PopoverRoot>\n )\n}\n\nDatePicker.displayName = 'DatePicker'\n\nexport { DatePicker }\n"],"names":[],"mappings":";;;;;;;;;;;;;AA0BA;AAAyD;AACvD;AACA;AACA;AACA;AACA;AACA;AAEF;AA6GA;AAA4F;AAChF;AAC2C;AACvC;AACA;AACP;AACP;AACA;AACgB;AACY;AACG;AACV;AACrB;AACA;AACQ;AAEV;AACE;AACA;AACA;AACA;AAEA;AACE;AACE;AAA2B;AAE7B;AAAO;AAGT;AACE;AACE;AAAmD;AAErD;AAAO;AAGT;AACE;AACE;AAAqD;AAEvD;AAAO;AAGT;AACE;AACE;AACA;AAA6B;AAE7B;AACA;AAA6B;AAC/B;AAGF;AACE;AACE;AACE;AAEA;AAAuB;AAGzB;AAAmC;AACrC;AAGF;AACA;AAEA;AACE;AACE;AAAwC;AAExC;AAA2D;AAC7D;AAGF;AAA2B;AAEvB;AACE;AAEA;AAEA;AACE;AACE;AACA;AAAyC;AAEzC;AAAwB;AAC1B;AAGF;AACE;AAAe;AACjB;AAEA;AACA;AACA;AACE;AACE;AACA;AAAyC;AAEzC;AAAwB;AAC1B;AACF;AACF;AACF;AAC6D;AAG/D;AAA0B;AAEtB;AAEA;AACA;AAEA;AACE;AAA+B;AAE/B;AAA8B;AAGhC;AACE;AAAwB;AAG1B;AACE;AAAQ;AACV;AACF;AACoD;AAGtD;AACE;AACA;AACE;AAAyE;AAG3E;AACA;AACA;AACA;AACA;AACA;AACA;AAA4B;AAG9B;AACE;AAAkB;AACuD;AAC/D;AACM;AACX;AAGL;AACE;AAAO;AACF;AACG;AACI;AAC6C;AACzD;AAGF;AAAO;AACF;AACG;AACI;AACoD;AACvB;AACzC;AAGF;AACA;AAEA;AAEI;AACE;AAAC;AAAA;AACU;AACD;AACG;AACT;AACa;AACsB;AACnC;AACF;AAC+D;AACb;AACC;AAEnD;AAA8D;AAC9D;AAAC;AAAA;AACY;AACT;AACgC;AAClC;AAAA;AACF;AAEE;AAAC;AAAA;AACa;AACD;AACT;AACmD;AACrD;AACS;AAAA;AACX;AAAA;AAAA;AAGN;AAEE;AAAC;AAAA;AACK;AACM;AACkD;AAAA;AAEhE;AAGN;AAEA;;"}
1
+ {"version":3,"file":"DatePicker.js","sources":["../../../src/components/DatePicker/DatePicker.tsx"],"sourcesContent":["'use client'\n\nimport { CalendarBlank, X } from '@phosphor-icons/react'\nimport { format as formatFn, Locale } from 'date-fns'\nimport { de, enGB, enUS, es, fr, it, pt } from 'date-fns/locale'\nimport * as React from 'react'\nimport { PropsBase, PropsRangeRequired, PropsSingleRequired } from 'react-day-picker'\n\nimport { Button, buttonVariants } from '../Button'\nimport { Calendar } from '../Calendar'\nimport { PopoverContent, PopoverRoot, PopoverTrigger } from '../Popover'\n\nimport {\n formatOutputDate,\n formatOutputRange,\n InputDate,\n InputRange,\n parseInputDate,\n parseInputRange,\n ValueFormat,\n} from '@/lib/dateUtils'\nimport { useIsMobile } from '@/lib/useMobile'\nimport { cn } from '@/lib/utils'\n\ntype SupportedLocaleString = 'enUS' | 'es' | 'pt' | 'enGB' | 'de' | 'it' | 'fr'\n\nconst localeMap: Record<SupportedLocaleString, Locale> = {\n enUS,\n es,\n pt,\n enGB,\n de,\n it,\n fr,\n}\n\nexport type DateRange = {\n from?: Date\n to?: Date\n}\n\nexport type IsoDateRange = {\n from?: string\n to?: string\n}\n\ntype DatePickerOutput<Variant extends 'single' | 'range', Format extends ValueFormat> = Variant extends 'single'\n ? Format extends 'date'\n ? Date | null\n : string | null\n : Format extends 'date'\n ? DateRange | null\n : IsoDateRange | null\n\ntype DatePickerInput<V extends 'single' | 'range'> = V extends 'single'\n ? Date | string | null\n : { from?: Date | string; to?: Date | string } | null\n\nexport type DatePickerProps<V extends 'single' | 'range' = 'single', F extends ValueFormat = 'iso'> = {\n /**\n * Placeholder text displayed when no date is selected\n * @default 'Pick a date' for single mode, 'Pick a date range' for range mode\n */\n readonly placeholder?: string\n\n /**\n * Format string to use when displaying the selected date in the button\n * @default 'MMM d, yyyy'\n */\n readonly displayFormat?: string\n\n /**\n * ClassName for the button\n */\n readonly buttonClassName?: string\n\n /**\n * Whether to allow the user to show the year switcher menu\n * @default true for single mode, false for range mode\n */\n readonly showYearSwitcher?: boolean\n\n /**\n * Initial value for the date picker\n * Accepts both Date objects and ISO strings regardless of valueFormat setting\n */\n readonly initialValue?: DatePickerInput<V>\n\n /**\n * Current value for the date picker\n * Accepts both Date objects and ISO strings regardless of valueFormat setting\n */\n readonly value?: DatePickerInput<V>\n\n /**\n * Determines if the picker should close after a selection\n * @default true for single mode, false for range mode\n */\n readonly closeOnSelect?: boolean\n\n /**\n * Determines the format of the value provided to the onChange callback\n * - 'iso' (default): onChange receives ISO string(s) ('yyyy-MM-dd') or empty string for cleared values\n * - 'date': onChange receives JavaScript Date object(s) or null for cleared values\n *\n * Note: The component accepts both Date objects and ISO strings for value/initialValue\n * regardless of this setting. Empty values are sent as null (date format) or '' (iso format)\n * instead of undefined to work properly with React Hook Form.\n * @default 'iso'\n */\n readonly valueFormat?: F\n\n /**\n * Callback when date or date range changes\n */\n readonly onChange?: (value: DatePickerOutput<V, F>) => void\n\n /**\n * DatePicker mode - single date or date range\n * @default 'single'\n */\n readonly variant?: V\n\n /**\n * The locale to use for formatting dates and determining the start of the week.\n * Can be a string identifier for supported locales ('enUS', 'es', 'pt', 'enGB', 'de', 'it', 'fr')\n * or a Locale object from date-fns/locale for other languages.\n * @default 'enUS'\n */\n readonly locale?: SupportedLocaleString | Locale\n\n /**\n * Callback function executed when the clear button is clicked.\n * When provided, an X button will appear on hover to clear the selected date.\n */\n readonly onClear?: boolean | (() => void)\n\n /**\n * Weather the picker is inside a modal (needed for pointer events to work at mobile)\n */\n modal?: boolean\n} & Omit<PropsBase, 'mode' | 'selected' | 'onSelect' | 'locale'>\n\nfunction DatePicker<V extends 'single' | 'range' = 'single', F extends ValueFormat = 'iso'>({\n variant = 'single' as V,\n placeholder = variant === 'single' ? 'Pick a date' : 'Pick a date range',\n valueFormat = 'iso' as F,\n initialValue: initialValueProp,\n value: valueProp,\n onChange,\n buttonClassName,\n displayFormat = 'MMM d, yyyy',\n closeOnSelect = variant === 'single',\n showYearSwitcher = variant === 'single',\n locale: localeProp = 'enUS',\n defaultMonth,\n onClear,\n modal = false,\n ...rest\n}: DatePickerProps<V, F>) {\n const [isOpen, setIsOpen] = React.useState(false)\n const [isHovered, setIsHovered] = React.useState(false)\n const [isClicked, setIsClicked] = React.useState(false)\n const isMobile = useIsMobile()\n const calendarRef = React.useRef<HTMLDivElement>(null)\n\n const resolvedLocale = React.useMemo(() => {\n if (typeof localeProp === 'string') {\n return localeMap[localeProp]\n }\n return localeProp\n }, [localeProp])\n\n const [internalSingleDate, setInternalSingleDate] = React.useState<Date | undefined>(() => {\n if (variant === 'single') {\n return parseInputDate(initialValueProp as InputDate)\n }\n return undefined\n })\n\n const [internalDateRange, setInternalDateRange] = React.useState<DateRange | undefined>(() => {\n if (variant === 'range') {\n return parseInputRange(initialValueProp as InputRange)\n }\n return undefined\n })\n\n React.useEffect(() => {\n const handleWindowMouseUp = () => setIsClicked(false)\n window.addEventListener('mouseup', handleWindowMouseUp)\n return () => window.removeEventListener('mouseup', handleWindowMouseUp)\n }, [])\n\n React.useEffect(() => {\n if (variant === 'single') {\n const newDate = parseInputDate(valueProp as InputDate)\n setInternalSingleDate(newDate)\n } else {\n const newRange = parseInputRange(valueProp as InputRange)\n setInternalDateRange(newRange)\n }\n }, [valueProp, variant])\n\n React.useEffect(() => {\n if (isOpen && isMobile && calendarRef.current) {\n const timeoutId = setTimeout(() => {\n const calendarElement = calendarRef.current?.querySelector('[id=\"calendar\"]') as HTMLElement | null\n\n calendarElement?.focus()\n }, 100)\n\n return () => clearTimeout(timeoutId)\n }\n }, [isOpen, isMobile])\n\n const singleDate = internalSingleDate\n const dateRange = internalDateRange\n\n const getEmptyValue = React.useCallback((): DatePickerOutput<V, F> => {\n if (variant === 'single') {\n return (valueFormat === 'date' ? null : '') as DatePickerOutput<V, F>\n } else {\n return (valueFormat === 'date' ? null : { from: '', to: '' }) as DatePickerOutput<V, F>\n }\n }, [variant, valueFormat])\n\n const handleSelect = React.useCallback(\n (selectedDate: Date | DateRange | undefined) => {\n if (variant === 'single') {\n const date = selectedDate as Date | undefined\n\n setInternalSingleDate(date)\n\n if (onChange) {\n if (date) {\n const output = valueFormat === 'date' ? date : formatOutputDate(date, 'iso')\n onChange(output as DatePickerOutput<V, F>)\n } else {\n onChange(getEmptyValue())\n }\n }\n\n if (closeOnSelect) {\n setIsOpen(false)\n }\n } else {\n const range = selectedDate as DateRange | undefined\n setInternalDateRange(range)\n if (onChange) {\n if (range) {\n const output = valueFormat === 'date' ? range : formatOutputRange(range, 'iso')\n onChange(output as DatePickerOutput<V, F>)\n } else {\n onChange(getEmptyValue())\n }\n }\n }\n },\n [variant, valueFormat, onChange, closeOnSelect, getEmptyValue],\n )\n\n const handleClear = React.useCallback(\n (event: React.MouseEvent) => {\n if (isMobile) return\n\n event.preventDefault()\n event.stopPropagation()\n\n if (variant === 'single') {\n setInternalSingleDate(undefined)\n } else {\n setInternalDateRange(undefined)\n }\n\n if (onChange) {\n onChange(getEmptyValue())\n }\n\n if (typeof onClear === 'function') {\n onClear()\n }\n },\n [variant, onChange, onClear, getEmptyValue, isMobile],\n )\n\n const formatForDisplay = () => {\n const formatOptions = { locale: resolvedLocale }\n if (variant === 'single') {\n return singleDate ? formatFn(singleDate, displayFormat, formatOptions) : placeholder\n }\n\n if (!dateRange) return placeholder\n const fromStr = dateRange.from ? formatFn(dateRange.from, displayFormat, formatOptions) : '...'\n const toStr = dateRange.to ? formatFn(dateRange.to, displayFormat, formatOptions) : '...'\n if (!dateRange.from && !dateRange.to) return placeholder\n if (!dateRange.from) return `... - ${toStr}`\n if (!dateRange.to) return `${fromStr} - ...`\n return `${fromStr} - ${toStr}`\n }\n\n const renderClearIcon = (showClearIcon: boolean) => {\n if (!showClearIcon) return null\n const clearIconClassName =\n 'pointer-events-none absolute right-4 z-10 flex h-full w-10 items-center justify-end rounded-r-lg bg-gradient-to-l from-60% via-80% to-transparent'\n\n return (\n <>\n <div\n className={cn(\n clearIconClassName,\n 'from-neutral-50 via-neutral-50/80',\n isHovered ? 'opacity-100' : 'opacity-0',\n )}\n />\n <div\n className={cn(\n clearIconClassName,\n 'from-neutral-100 via-neutral-100/80',\n isClicked ? 'opacity-100' : 'opacity-0',\n )}\n />\n <div className=\"absolute right-4 z-20 flex h-full w-10 items-center justify-end\">\n <X\n data-testid=\"clear-button\"\n className={cn(\n 'h-4 w-4 shrink-0 cursor-pointer opacity-100 transition-opacity duration-150 hover:opacity-70',\n )}\n onClick={handleClear}\n />\n </div>\n </>\n )\n }\n\n const calendarProps = React.useMemo(() => {\n const baseProps = {\n defaultMonth: (variant === 'single' ? singleDate : dateRange?.from) ?? defaultMonth,\n locale: resolvedLocale,\n initialFocus: true,\n ...rest,\n } as PropsBase\n\n if (variant === 'single') {\n return {\n ...baseProps,\n mode: 'single' as const,\n selected: singleDate,\n onSelect: (date: Date | undefined) => handleSelect(date),\n } as PropsSingleRequired\n }\n\n return {\n ...baseProps,\n mode: 'range' as const,\n selected: dateRange,\n onSelect: (range: DateRange | undefined) => handleSelect(range),\n numberOfMonths: rest.numberOfMonths ?? 2,\n } as PropsRangeRequired\n }, [variant, rest, singleDate, dateRange, handleSelect, resolvedLocale, defaultMonth])\n\n const hasValue = variant === 'single' ? singleDate : dateRange\n const showClearButton = onClear && hasValue && isHovered\n\n return (\n <PopoverRoot open={isOpen} onOpenChange={setIsOpen} modal={modal}>\n <PopoverTrigger asChild>\n <Button\n id={rest.id}\n variant=\"ghost\"\n className={cn(\n 'relative flex w-fit items-center justify-start text-left font-normal hover:transition-opacity',\n !hasValue && 'text-muted-foreground',\n buttonVariants({ variant: 'input' }),\n buttonClassName,\n )}\n disabled={typeof rest.disabled === 'boolean' ? rest.disabled : false}\n onMouseEnter={() => !isMobile && setIsHovered(true)}\n onMouseLeave={() => !isMobile && setIsHovered(false)}\n onMouseDown={() => !isMobile && setIsClicked(true)}\n >\n <div className=\"flex items-center justify-center gap-2\">\n <CalendarBlank className={cn('h-4 w-4 shrink-0 transition-opacity duration-150')} />\n <span className=\"w-full text-center\">{formatForDisplay()}</span>\n {onClear && hasValue && renderClearIcon(showClearButton ?? false)}\n </div>\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\" align=\"center\" ref={calendarRef}>\n <Calendar\n {...calendarProps}\n className=\"border-0\"\n showYearSwitcher={variant === 'single' ? showYearSwitcher : false}\n />\n </PopoverContent>\n </PopoverRoot>\n )\n}\n\nDatePicker.displayName = 'DatePicker'\n\nexport { DatePicker }\n"],"names":[],"mappings":";;;;;;;;;;;;;AA0BA;AAAyD;AACvD;AACA;AACA;AACA;AACA;AACA;AAEF;AA6GA;AAA4F;AAChF;AAC2C;AACvC;AACA;AACP;AACP;AACA;AACgB;AACY;AACG;AACV;AACrB;AACA;AACQ;AAEV;AACE;AACA;AACA;AACA;AACA;AAEA;AACE;AACE;AAA2B;AAE7B;AAAO;AAGT;AACE;AACE;AAAmD;AAErD;AAAO;AAGT;AACE;AACE;AAAqD;AAEvD;AAAO;AAGT;AACE;AACA;AACA;AAAsE;AAGxE;AACE;AACE;AACA;AAA6B;AAE7B;AACA;AAA6B;AAC/B;AAGF;AACE;AACE;AACE;AAEA;AAAuB;AAGzB;AAAmC;AACrC;AAGF;AACA;AAEA;AACE;AACE;AAAwC;AAExC;AAA2D;AAC7D;AAGF;AAA2B;AAEvB;AACE;AAEA;AAEA;AACE;AACE;AACA;AAAyC;AAEzC;AAAwB;AAC1B;AAGF;AACE;AAAe;AACjB;AAEA;AACA;AACA;AACE;AACE;AACA;AAAyC;AAEzC;AAAwB;AAC1B;AACF;AACF;AACF;AAC6D;AAG/D;AAA0B;AAEtB;AAEA;AACA;AAEA;AACE;AAA+B;AAE/B;AAA8B;AAGhC;AACE;AAAwB;AAG1B;AACE;AAAQ;AACV;AACF;AACoD;AAGtD;AACE;AACA;AACE;AAAyE;AAG3E;AACA;AACA;AACA;AACA;AACA;AACA;AAA4B;AAG9B;AACE;AACA;AAGA;AAEI;AAAA;AAAC;AAAA;AACY;AACT;AACA;AAC4B;AAC9B;AAAA;AACF;AACA;AAAC;AAAA;AACY;AACT;AACA;AAC4B;AAC9B;AAAA;AACF;AAEE;AAAC;AAAA;AACa;AACD;AACT;AACF;AACS;AAAA;AAEb;AACF;AAIJ;AACE;AAAkB;AACuD;AAC/D;AACM;AACX;AAGL;AACE;AAAO;AACF;AACG;AACI;AAC6C;AACzD;AAGF;AAAO;AACF;AACG;AACI;AACoD;AACvB;AACzC;AAGF;AACA;AAEA;AAEI;AACE;AAAC;AAAA;AACU;AACD;AACG;AACT;AACa;AACsB;AACnC;AACF;AAC+D;AACb;AACC;AACF;AAG/C;AAAkF;AACzB;AACO;AAClE;AAAA;AAEJ;AAEE;AAAC;AAAA;AACK;AACM;AACkD;AAAA;AAEhE;AAGN;AAEA;;"}
@@ -45,6 +45,18 @@ export type TooltipProps = {
45
45
  * @default false
46
46
  */
47
47
  arrow?: boolean;
48
+ /**
49
+ * The preferred side of the trigger to render the mobile
50
+ */
51
+ mobileSide?: 'top' | 'right' | 'bottom' | 'left';
52
+ /**
53
+ * The preferred alignment of the mobile
54
+ */
55
+ mobileAlign?: 'start' | 'center' | 'end';
56
+ /**
57
+ * The preferred side offset of the mobile
58
+ */
59
+ mobileSideOffset?: number;
48
60
  };
49
61
  /**
50
62
  * A versatile tooltip component that shows additional information on hover.
@@ -67,7 +79,7 @@ export type TooltipProps = {
67
79
  * Icon description
68
80
  * </Tooltip>
69
81
  */
70
- export declare function Tooltip({ triggerElement, children, side, className, delayDuration, arrow, }: Readonly<TooltipProps>): import("react/jsx-runtime").JSX.Element;
82
+ export declare function Tooltip({ triggerElement, children, side, className, delayDuration, arrow, mobileSide, mobileAlign, mobileSideOffset, ...props }: Readonly<TooltipProps>): import("react/jsx-runtime").JSX.Element;
71
83
  /**
72
84
  * Export primitive components for custom tooltip implementations.
73
85
  * Use these when you need more control over the tooltip behavior and styling.
@@ -83,4 +95,4 @@ export declare function Tooltip({ triggerElement, children, side, className, del
83
95
  * </TooltipRoot>
84
96
  * </TooltipProvider>
85
97
  */
86
- export { TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider };
98
+ export { TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger };
@@ -1,6 +1,8 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
3
3
  import * as React from 'react';
4
+ import { Popover } from '../Popover/Popover.js';
5
+ import { useIsMobile } from '../../lib/useMobile.js';
4
6
  import { cn } from '../../lib/utils.js';
5
7
 
6
8
  const TooltipProvider = TooltipPrimitive.Provider;
@@ -36,9 +38,25 @@ function Tooltip({
36
38
  side = "top",
37
39
  className,
38
40
  delayDuration = 700,
39
- arrow = false
41
+ arrow = false,
42
+ mobileSide,
43
+ mobileAlign,
44
+ mobileSideOffset,
45
+ ...props
40
46
  }) {
41
- return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration, children: [
47
+ const isMobile = useIsMobile();
48
+ return isMobile ? /* @__PURE__ */ jsx(
49
+ Popover,
50
+ {
51
+ side: mobileSide,
52
+ className,
53
+ align: mobileAlign,
54
+ sideOffset: mobileSideOffset,
55
+ triggerElement,
56
+ ...props,
57
+ children
58
+ }
59
+ ) : /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration, children: [
42
60
  /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: triggerElement }),
43
61
  /* @__PURE__ */ jsx(TooltipContent, { side, className, arrow, children })
44
62
  ] }) });
@@ -1 +1 @@
1
- {"version":3,"file":"Tooltip.js","sources":["../../../src/components/Tooltip/Tooltip.tsx"],"sourcesContent":["import * as TooltipPrimitive from '@radix-ui/react-tooltip'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\n\n/**\n * Provider component that wraps all tooltip instances.\n * Controls the delay duration and positioning of tooltips app-wide.\n */\nconst TooltipProvider = TooltipPrimitive.Provider\n\n/**\n * The root component that wraps the trigger and content.\n * Manages the open state and hover interactions.\n */\nconst TooltipRoot = TooltipPrimitive.Root\n\n/**\n * The element that triggers the tooltip when hovered or focused.\n * Wrap with asChild to use custom components as triggers.\n */\nconst TooltipTrigger = TooltipPrimitive.Trigger\n\nconst TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & { arrow?: boolean }\n>(({ className, sideOffset = 4, arrow, children, ...props }, ref) => (\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'z-50 rounded-lg bg-white px-3 py-1.5 text-sm',\n 'shadow-tooltip',\n 'animate-in fade-in-0 zoom-in-95',\n 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',\n 'data-[side=bottom]:slide-in-from-top-2',\n 'data-[side=left]:slide-in-from-right-2',\n 'data-[side=right]:slide-in-from-left-2',\n 'data-[side=top]:slide-in-from-bottom-2',\n className,\n )}\n {...props}\n >\n {children}\n {arrow && <TooltipPrimitive.Arrow fill=\"white\" />}\n </TooltipPrimitive.Content>\n))\nTooltipContent.displayName = TooltipPrimitive.Content.displayName\n\nexport type TooltipProps = {\n /**\n * The content to be displayed inside the tooltip\n */\n children: React.ReactElement | string\n\n /**\n * The element that triggers the tooltip on hover\n */\n triggerElement: React.ReactElement | string\n\n /**\n * The preferred side of the trigger to render the tooltip\n */\n side?: 'top' | 'right' | 'bottom' | 'left'\n\n /**\n * Optional custom className for additional styling\n */\n className?: string\n\n /**\n * Delay duration for showing the tooltip in milliseconds\n * @default 700\n */\n delayDuration?: number\n\n /**\n * Whether to show an arrow pointer on the tooltip\n * @default false\n */\n arrow?: boolean\n}\n\n/**\n * A versatile tooltip component that shows additional information on hover.\n * Built on top of Radix UI's tooltip primitives with custom styling and animations.\n *\n * @example\n * // Basic usage\n * <Tooltip triggerElement={<button>Hover me</button>} side=\"top\">\n * Helpful information\n * </Tooltip>\n *\n * @example\n * // With custom delay and className\n * <Tooltip\n * triggerElement={<Icon />}\n * side=\"right\"\n * delayDuration={300}\n * className=\"custom-tooltip\"\n * >\n * Icon description\n * </Tooltip>\n */\nexport function Tooltip({\n triggerElement,\n children,\n side = 'top',\n className,\n delayDuration = 700,\n arrow = false,\n}: Readonly<TooltipProps>) {\n return (\n <TooltipProvider>\n <TooltipRoot delayDuration={delayDuration}>\n <TooltipTrigger asChild>{triggerElement}</TooltipTrigger>\n <TooltipContent side={side} className={className} arrow={arrow}>\n {children}\n </TooltipContent>\n </TooltipRoot>\n </TooltipProvider>\n )\n}\n\n/**\n * Export primitive components for custom tooltip implementations.\n * Use these when you need more control over the tooltip behavior and styling.\n *\n * @example\n * // Custom implementation using primitives\n * <TooltipProvider>\n * <TooltipRoot>\n * <TooltipTrigger asChild>\n * <button>Hover</button>\n * </TooltipTrigger>\n * <TooltipContent>Custom tooltip</TooltipContent>\n * </TooltipRoot>\n * </TooltipProvider>\n */\nexport { TooltipRoot, TooltipTrigger, TooltipContent, TooltipProvider }\n"],"names":[],"mappings":";;;;;AASA,MAAM,kBAAkB,gBAAA,CAAiB;AAMzC,MAAM,cAAc,gBAAA,CAAiB;AAMrC,MAAM,iBAAiB,gBAAA,CAAiB;AAExC,MAAM,cAAA,GAAiB,KAAA,CAAM,UAAA,CAG3B,CAAC,EAAE,SAAA,EAAW,UAAA,GAAa,CAAA,EAAG,KAAA,EAAO,QAAA,EAAU,GAAG,KAAA,IAAS,GAAA,qBAC3D,IAAA;AAAA,EAAC,gBAAA,CAAiB,OAAA;AAAA,EAAjB;AAAA,IACC,GAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA,EAAW,EAAA;AAAA,MACT,8CAAA;AAAA,MACA,gBAAA;AAAA,MACA,iCAAA;AAAA,MACA,gGAAA;AAAA,MACA,wCAAA;AAAA,MACA,wCAAA;AAAA,MACA,wCAAA;AAAA,MACA,wCAAA;AAAA,MACA;AAAA,KACF;AAAA,IACC,GAAG,KAAA;AAAA,IAEH,QAAA,EAAA;AAAA,MAAA,QAAA;AAAA,MACA,yBAAS,GAAA,CAAC,gBAAA,CAAiB,KAAA,EAAjB,EAAuB,MAAK,OAAA,EAAQ;AAAA;AAAA;AACjD,CACD;AACD,cAAA,CAAe,WAAA,GAAc,iBAAiB,OAAA,CAAQ,WAAA;AAyD/C,SAAS,OAAA,CAAQ;AAAA,EACtB,cAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA,GAAO,KAAA;AAAA,EACP,SAAA;AAAA,EACA,aAAA,GAAgB,GAAA;AAAA,EAChB,KAAA,GAAQ;AACV,CAAA,EAA2B;AACzB,EAAA,uBACE,GAAA,CAAC,eAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,WAAA,EAAA,EAAY,aAAA,EACX,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,cAAA,EAAA,EAAe,OAAA,EAAO,IAAA,EAAE,QAAA,EAAA,cAAA,EAAe,CAAA;AAAA,oBACxC,GAAA,CAAC,cAAA,EAAA,EAAe,IAAA,EAAY,SAAA,EAAsB,OAC/C,QAAA,EACH;AAAA,GAAA,EACF,CAAA,EACF,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"Tooltip.js","sources":["../../../src/components/Tooltip/Tooltip.tsx"],"sourcesContent":["import * as TooltipPrimitive from '@radix-ui/react-tooltip'\nimport * as React from 'react'\n\nimport { Popover } from '../Popover/Popover'\n\nimport { useIsMobile } from '@/lib/useMobile'\nimport { cn } from '@/lib/utils'\n\n/**\n * Provider component that wraps all tooltip instances.\n * Controls the delay duration and positioning of tooltips app-wide.\n */\nconst TooltipProvider = TooltipPrimitive.Provider\n\n/**\n * The root component that wraps the trigger and content.\n * Manages the open state and hover interactions.\n */\nconst TooltipRoot = TooltipPrimitive.Root\n\n/**\n * The element that triggers the tooltip when hovered or focused.\n * Wrap with asChild to use custom components as triggers.\n */\nconst TooltipTrigger = TooltipPrimitive.Trigger\n\nconst TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & { arrow?: boolean }\n>(({ className, sideOffset = 4, arrow, children, ...props }, ref) => (\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'z-50 rounded-lg bg-white px-3 py-1.5 text-sm',\n 'shadow-tooltip',\n 'animate-in fade-in-0 zoom-in-95',\n 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',\n 'data-[side=bottom]:slide-in-from-top-2',\n 'data-[side=left]:slide-in-from-right-2',\n 'data-[side=right]:slide-in-from-left-2',\n 'data-[side=top]:slide-in-from-bottom-2',\n className,\n )}\n {...props}\n >\n {children}\n {arrow && <TooltipPrimitive.Arrow fill=\"white\" />}\n </TooltipPrimitive.Content>\n))\nTooltipContent.displayName = TooltipPrimitive.Content.displayName\n\nexport type TooltipProps = {\n /**\n * The content to be displayed inside the tooltip\n */\n children: React.ReactElement | string\n\n /**\n * The element that triggers the tooltip on hover\n */\n triggerElement: React.ReactElement | string\n\n /**\n * The preferred side of the trigger to render the tooltip\n */\n side?: 'top' | 'right' | 'bottom' | 'left'\n\n /**\n * Optional custom className for additional styling\n */\n className?: string\n\n /**\n * Delay duration for showing the tooltip in milliseconds\n * @default 700\n */\n delayDuration?: number\n\n /**\n * Whether to show an arrow pointer on the tooltip\n * @default false\n */\n arrow?: boolean\n\n /**\n * The preferred side of the trigger to render the mobile\n */\n mobileSide?: 'top' | 'right' | 'bottom' | 'left'\n\n /**\n * The preferred alignment of the mobile\n */\n mobileAlign?: 'start' | 'center' | 'end'\n\n /**\n * The preferred side offset of the mobile\n */\n mobileSideOffset?: number\n}\n\n/**\n * A versatile tooltip component that shows additional information on hover.\n * Built on top of Radix UI's tooltip primitives with custom styling and animations.\n *\n * @example\n * // Basic usage\n * <Tooltip triggerElement={<button>Hover me</button>} side=\"top\">\n * Helpful information\n * </Tooltip>\n *\n * @example\n * // With custom delay and className\n * <Tooltip\n * triggerElement={<Icon />}\n * side=\"right\"\n * delayDuration={300}\n * className=\"custom-tooltip\"\n * >\n * Icon description\n * </Tooltip>\n */\nexport function Tooltip({\n triggerElement,\n children,\n side = 'top',\n className,\n delayDuration = 700,\n arrow = false,\n mobileSide,\n mobileAlign,\n mobileSideOffset,\n ...props\n}: Readonly<TooltipProps>) {\n const isMobile = useIsMobile()\n\n return isMobile ? (\n <Popover\n side={mobileSide}\n className={className}\n align={mobileAlign}\n sideOffset={mobileSideOffset}\n triggerElement={triggerElement}\n {...props}\n >\n {children}\n </Popover>\n ) : (\n <TooltipProvider>\n <TooltipRoot delayDuration={delayDuration}>\n <TooltipTrigger asChild>{triggerElement}</TooltipTrigger>\n <TooltipContent side={side} className={className} arrow={arrow}>\n {children}\n </TooltipContent>\n </TooltipRoot>\n </TooltipProvider>\n )\n}\n\n/**\n * Export primitive components for custom tooltip implementations.\n * Use these when you need more control over the tooltip behavior and styling.\n *\n * @example\n * // Custom implementation using primitives\n * <TooltipProvider>\n * <TooltipRoot>\n * <TooltipTrigger asChild>\n * <button>Hover</button>\n * </TooltipTrigger>\n * <TooltipContent>Custom tooltip</TooltipContent>\n * </TooltipRoot>\n * </TooltipProvider>\n */\nexport { TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger }\n"],"names":[],"mappings":";;;;;;;AAYA,MAAM,kBAAkB,gBAAA,CAAiB;AAMzC,MAAM,cAAc,gBAAA,CAAiB;AAMrC,MAAM,iBAAiB,gBAAA,CAAiB;AAExC,MAAM,cAAA,GAAiB,KAAA,CAAM,UAAA,CAG3B,CAAC,EAAE,SAAA,EAAW,UAAA,GAAa,CAAA,EAAG,KAAA,EAAO,QAAA,EAAU,GAAG,KAAA,IAAS,GAAA,qBAC3D,IAAA;AAAA,EAAC,gBAAA,CAAiB,OAAA;AAAA,EAAjB;AAAA,IACC,GAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA,EAAW,EAAA;AAAA,MACT,8CAAA;AAAA,MACA,gBAAA;AAAA,MACA,iCAAA;AAAA,MACA,gGAAA;AAAA,MACA,wCAAA;AAAA,MACA,wCAAA;AAAA,MACA,wCAAA;AAAA,MACA,wCAAA;AAAA,MACA;AAAA,KACF;AAAA,IACC,GAAG,KAAA;AAAA,IAEH,QAAA,EAAA;AAAA,MAAA,QAAA;AAAA,MACA,yBAAS,GAAA,CAAC,gBAAA,CAAiB,KAAA,EAAjB,EAAuB,MAAK,OAAA,EAAQ;AAAA;AAAA;AACjD,CACD;AACD,cAAA,CAAe,WAAA,GAAc,iBAAiB,OAAA,CAAQ,WAAA;AAwE/C,SAAS,OAAA,CAAQ;AAAA,EACtB,cAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA,GAAO,KAAA;AAAA,EACP,SAAA;AAAA,EACA,aAAA,GAAgB,GAAA;AAAA,EAChB,KAAA,GAAQ,KAAA;AAAA,EACR,UAAA;AAAA,EACA,WAAA;AAAA,EACA,gBAAA;AAAA,EACA,GAAG;AACL,CAAA,EAA2B;AACzB,EAAA,MAAM,WAAW,WAAA,EAAY;AAE7B,EAAA,OAAO,QAAA,mBACL,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,UAAA;AAAA,MACN,SAAA;AAAA,MACA,KAAA,EAAO,WAAA;AAAA,MACP,UAAA,EAAY,gBAAA;AAAA,MACZ,cAAA;AAAA,MACC,GAAG,KAAA;AAAA,MAEH;AAAA;AAAA,GACH,mBAEA,GAAA,CAAC,eAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,eAAY,aAAA,EACX,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,cAAA,EAAA,EAAe,OAAA,EAAO,IAAA,EAAE,QAAA,EAAA,cAAA,EAAe,CAAA;AAAA,oBACxC,GAAA,CAAC,cAAA,EAAA,EAAe,IAAA,EAAY,SAAA,EAAsB,OAC/C,QAAA,EACH;AAAA,GAAA,EACF,CAAA,EACF,CAAA;AAEJ;;;;"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "periplo-ui",
3
3
  "description": "IATI UI library",
4
4
  "private": false,
5
- "version": "3.33.0",
5
+ "version": "3.34.0",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",