@fanvue/ui 1.19.0 → 1.20.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/cjs/components/Autocomplete/Autocomplete.cjs +6 -6
- package/dist/cjs/components/Autocomplete/Autocomplete.cjs.map +1 -1
- package/dist/cjs/components/InfoBox/InfoBox.cjs +111 -0
- package/dist/cjs/components/InfoBox/InfoBox.cjs.map +1 -0
- package/dist/cjs/components/Tooltip/Tooltip.cjs +17 -92
- package/dist/cjs/components/Tooltip/Tooltip.cjs.map +1 -1
- package/dist/cjs/index.cjs +4 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/components/Autocomplete/Autocomplete.mjs +5 -5
- package/dist/components/Autocomplete/Autocomplete.mjs.map +1 -1
- package/dist/components/InfoBox/InfoBox.mjs +93 -0
- package/dist/components/InfoBox/InfoBox.mjs.map +1 -0
- package/dist/components/Tooltip/Tooltip.mjs +18 -93
- package/dist/components/Tooltip/Tooltip.mjs.map +1 -1
- package/dist/index.d.ts +50 -88
- package/dist/index.mjs +4 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
4
|
const jsxRuntime = require("react/jsx-runtime");
|
|
5
|
-
const
|
|
5
|
+
const PopoverPrimitive = require("@radix-ui/react-popover");
|
|
6
6
|
const React = require("react");
|
|
7
7
|
const cn = require("../../utils/cn.cjs");
|
|
8
8
|
const ChevronDownIcon = require("../Icons/ChevronDownIcon.cjs");
|
|
@@ -27,7 +27,7 @@ function _interopNamespaceDefault(e) {
|
|
|
27
27
|
n.default = e;
|
|
28
28
|
return Object.freeze(n);
|
|
29
29
|
}
|
|
30
|
-
const
|
|
30
|
+
const PopoverPrimitive__namespace = /* @__PURE__ */ _interopNamespaceDefault(PopoverPrimitive);
|
|
31
31
|
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
32
32
|
const CONTAINER_HEIGHT = {
|
|
33
33
|
"48": "min-h-12",
|
|
@@ -79,7 +79,7 @@ const Autocomplete = React__namespace.forwardRef((props, ref) => {
|
|
|
79
79
|
React__namespace.useImperativeHandle(ref, () => ac.inputRef.current);
|
|
80
80
|
warnMissingAccessibleName(label, ariaLabel, ariaLabelledby);
|
|
81
81
|
const bottomText = error && errorMessage ? errorMessage : helperText;
|
|
82
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
82
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Root, { open: ac.isOpen && !disabled, onOpenChange: ac.handleOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
83
83
|
"div",
|
|
84
84
|
{
|
|
85
85
|
className: cn.cn("flex flex-col", fullWidth && "w-full", className),
|
|
@@ -95,7 +95,7 @@ const Autocomplete = React__namespace.forwardRef((props, ref) => {
|
|
|
95
95
|
children: label
|
|
96
96
|
}
|
|
97
97
|
),
|
|
98
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
98
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Anchor, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
99
99
|
"div",
|
|
100
100
|
{
|
|
101
101
|
className: cn.cn(
|
|
@@ -174,8 +174,8 @@ const Autocomplete = React__namespace.forwardRef((props, ref) => {
|
|
|
174
174
|
]
|
|
175
175
|
}
|
|
176
176
|
) }),
|
|
177
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
178
|
-
|
|
177
|
+
/* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
178
|
+
PopoverPrimitive__namespace.Content,
|
|
179
179
|
{
|
|
180
180
|
sideOffset: 4,
|
|
181
181
|
collisionPadding: 8,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Autocomplete.cjs","sources":["../../../../src/components/Autocomplete/Autocomplete.tsx"],"sourcesContent":["import * as Popover from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { ChevronDownIcon } from \"../Icons/ChevronDownIcon\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\nimport { SpinnerIcon } from \"../Icons/SpinnerIcon\";\nimport { AutocompleteDropdownContent } from \"./AutocompleteDropdownContent\";\nimport { AutocompleteTag } from \"./AutocompleteTag\";\nimport { useAutocomplete } from \"./useAutocomplete\";\n\nexport type AutocompleteSize = \"48\" | \"40\" | \"32\";\n\nexport interface AutocompleteOption {\n value: string;\n label?: string;\n disabled?: boolean;\n}\n\ninterface AutocompleteBaseProps {\n label?: string;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n helperText?: string;\n /** @default \"48\" */\n size?: AutocompleteSize;\n /** @default false */\n error?: boolean;\n errorMessage?: string;\n placeholder?: string;\n leftIcon?: React.ReactNode;\n /** @default false */\n fullWidth?: boolean;\n /** @default false */\n disabled?: boolean;\n /** @default false */\n clearable?: boolean;\n clearAriaLabel?: string;\n id?: string;\n className?: string;\n options: AutocompleteOption[];\n inputValue?: string;\n onInputChange?: (value: string) => void;\n filterFn?: (option: AutocompleteOption, query: string) => boolean;\n /** @default false */\n creatable?: boolean;\n creatableLabel?: (inputValue: string) => string;\n onCreate?: (inputValue: string) => void;\n /** @default false */\n loading?: boolean;\n loadingText?: string;\n emptyText?: string;\n renderOption?: (\n option: AutocompleteOption,\n state: { selected: boolean; active: boolean },\n ) => React.ReactNode;\n renderTag?: (option: AutocompleteOption, onRemove: () => void) => React.ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\ninterface AutocompleteSingleProps extends AutocompleteBaseProps {\n multiple?: false;\n value?: string | null;\n defaultValue?: string | null;\n onChange?: (value: string | null) => void;\n}\n\ninterface AutocompleteMultiProps extends AutocompleteBaseProps {\n multiple: true;\n value?: string[];\n defaultValue?: string[];\n onChange?: (values: string[]) => void;\n}\n\nexport type AutocompleteProps = AutocompleteSingleProps | AutocompleteMultiProps;\n\nconst CONTAINER_HEIGHT: Record<AutocompleteSize, string> = {\n \"48\": \"min-h-12\",\n \"40\": \"min-h-10\",\n \"32\": \"min-h-8\",\n};\n\nconst INPUT_SIZE_CLASSES: Record<AutocompleteSize, string> = {\n \"48\": \"typography-regular-body-lg\",\n \"40\": \"typography-regular-body-lg\",\n \"32\": \"typography-regular-body-md\",\n};\n\nconst PADDING_CLASSES: Record<AutocompleteSize, string> = {\n \"48\": \"px-4 py-1.5 gap-3\",\n \"40\": \"px-4 py-1 gap-3\",\n \"32\": \"px-3 py-1 gap-2\",\n};\n\nfunction warnMissingAccessibleName(label?: string, ariaLabel?: string, ariaLabelledBy?: string) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!label && !ariaLabel && !ariaLabelledBy) {\n console.warn(\n \"Autocomplete: no accessible name provided. Pass a `label`, `aria-label`, or `aria-labelledby` prop.\",\n );\n }\n }\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Conditional JSX branches in the render template\nexport const Autocomplete = React.forwardRef<HTMLInputElement, AutocompleteProps>((props, ref) => {\n const {\n label,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n helperText,\n size = \"48\",\n error = false,\n errorMessage,\n placeholder,\n leftIcon,\n fullWidth = false,\n disabled = false,\n clearable = false,\n clearAriaLabel = \"Clear\",\n className,\n loading = false,\n loadingText,\n emptyText = \"No results\",\n renderOption,\n renderTag,\n } = props;\n\n const ac = useAutocomplete(props);\n\n React.useImperativeHandle(ref, () => ac.inputRef.current as HTMLInputElement);\n\n warnMissingAccessibleName(label, ariaLabel, ariaLabelledby);\n\n const bottomText = error && errorMessage ? errorMessage : helperText;\n\n return (\n <Popover.Root open={ac.isOpen && !disabled} onOpenChange={ac.handleOpenChange}>\n <div\n className={cn(\"flex flex-col\", fullWidth && \"w-full\", className)}\n data-autocomplete-root=\"\"\n data-disabled={disabled ? \"\" : undefined}\n data-error={error ? \"\" : undefined}\n >\n {label && (\n <label\n htmlFor={ac.inputId}\n className=\"typography-semibold-body-sm px-1 pt-1 pb-2 text-foreground-default\"\n >\n {label}\n </label>\n )}\n\n <Popover.Anchor asChild>\n {/* biome-ignore lint/a11y/noStaticElementInteractions: Container delegates click to the inner input */}\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: Keyboard interaction is handled by the inner combobox input */}\n <div\n className={cn(\n \"flex flex-wrap items-center overflow-hidden rounded-xl border bg-neutral-100 has-focus-visible:outline-none motion-safe:transition-colors\",\n error ? \"border-error-default\" : \"border-transparent\",\n !disabled && !error && \"hover:border-neutral-400\",\n ac.isOpen && !error && !disabled && \"border-neutral-400\",\n CONTAINER_HEIGHT[size],\n PADDING_CLASSES[size],\n disabled && \"opacity-50\",\n )}\n onClick={ac.handleContainerClick}\n >\n {leftIcon && (\n <div className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary\">\n {leftIcon}\n </div>\n )}\n\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n {ac.isMulti &&\n ac.selectedMultiOptions.map((opt) => (\n <AutocompleteTag\n key={opt.value}\n option={opt}\n disabled={disabled}\n onRemove={() => ac.toggleMulti(opt.value)}\n renderTag={renderTag}\n />\n ))}\n\n <input\n ref={ac.inputRef}\n id={ac.inputId}\n role=\"combobox\"\n type=\"text\"\n disabled={disabled}\n aria-expanded={ac.isOpen}\n aria-controls={ac.isOpen ? ac.listboxId : undefined}\n aria-activedescendant={ac.activeDescendantId}\n aria-autocomplete=\"list\"\n aria-describedby={bottomText ? ac.helperTextId : undefined}\n aria-invalid={error || undefined}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n autoComplete=\"off\"\n placeholder={\n ac.isMulti && ac.selectedMultiValues.length > 0 ? undefined : placeholder\n }\n value={ac.displayInputValue}\n onChange={ac.handleInputChange}\n onKeyDown={ac.handleKeyDown}\n onFocus={ac.handleFocus}\n onBlur={ac.handleBlur}\n className={cn(\n \"min-w-[40px] flex-1 truncate rounded-xl bg-transparent text-foreground-default no-underline placeholder:text-foreground-secondary placeholder:opacity-40 focus:outline-none disabled:cursor-not-allowed\",\n INPUT_SIZE_CLASSES[size],\n )}\n />\n </div>\n\n <div className=\"flex shrink-0 items-center gap-1\">\n {loading && <SpinnerIcon className=\"size-4 animate-spin text-foreground-secondary\" />}\n {clearable && ac.hasClearableValue && !disabled && (\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={clearAriaLabel}\n className=\"flex size-5 shrink-0 cursor-pointer items-center justify-center text-foreground-secondary hover:text-foreground-default active:scale-95\"\n onClick={ac.handleClear}\n >\n <CloseIcon className=\"size-4\" />\n </button>\n )}\n <div className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary\">\n <ChevronDownIcon\n className={cn(\"size-5 transition-transform\", ac.isOpen && \"rotate-180\")}\n />\n </div>\n </div>\n </div>\n </Popover.Anchor>\n\n <Popover.Portal>\n <Popover.Content\n sideOffset={4}\n collisionPadding={8}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\" }}\n className={cn(\n \"w-(--radix-popover-trigger-width) min-w-(--radix-popper-anchor-width) overflow-hidden rounded-xl border border-neutral-200 bg-surface-page text-foreground-default shadow-[0_4px_16px_rgba(0,0,0,0.10)]\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n \"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n \"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2\",\n )}\n >\n <div\n ref={ac.listRef}\n id={ac.listboxId}\n role=\"listbox\"\n aria-label={label ?? ariaLabel ?? \"Options\"}\n aria-multiselectable={ac.isMulti || undefined}\n className=\"max-h-60 overflow-y-auto p-1\"\n >\n <AutocompleteDropdownContent\n loading={loading}\n loadingText={loadingText}\n emptyText={emptyText}\n visibleOptions={ac.visibleOptions}\n listboxId={ac.listboxId}\n activeIndex={ac.activeIndex}\n isMulti={ac.isMulti}\n selectedMultiValues={ac.selectedMultiValues}\n selectedValue={ac.selectedValue}\n onSelect={ac.handleSelect}\n onMouseEnter={ac.setActiveIndex}\n renderOption={renderOption}\n />\n </div>\n </Popover.Content>\n </Popover.Portal>\n\n {bottomText && (\n <p\n id={ac.helperTextId}\n className={cn(\n \"typography-regular-body-sm px-2 pt-1 pb-0.5\",\n error ? \"text-error-default\" : \"text-foreground-secondary\",\n )}\n >\n {bottomText}\n </p>\n )}\n </div>\n </Popover.Root>\n );\n});\n\nAutocomplete.displayName = \"Autocomplete\";\n"],"names":["React","useAutocomplete","jsx","Popover","jsxs","cn","AutocompleteTag","SpinnerIcon","CloseIcon","ChevronDownIcon","AutocompleteDropdownContent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Autocomplete.cjs","sources":["../../../../src/components/Autocomplete/Autocomplete.tsx"],"sourcesContent":["import * as Popover from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { ChevronDownIcon } from \"../Icons/ChevronDownIcon\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\nimport { SpinnerIcon } from \"../Icons/SpinnerIcon\";\nimport { AutocompleteDropdownContent } from \"./AutocompleteDropdownContent\";\nimport { AutocompleteTag } from \"./AutocompleteTag\";\nimport { useAutocomplete } from \"./useAutocomplete\";\n\nexport type AutocompleteSize = \"48\" | \"40\" | \"32\";\n\nexport interface AutocompleteOption {\n value: string;\n label?: string;\n disabled?: boolean;\n}\n\ninterface AutocompleteBaseProps {\n label?: string;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n helperText?: string;\n /** @default \"48\" */\n size?: AutocompleteSize;\n /** @default false */\n error?: boolean;\n errorMessage?: string;\n placeholder?: string;\n leftIcon?: React.ReactNode;\n /** @default false */\n fullWidth?: boolean;\n /** @default false */\n disabled?: boolean;\n /** @default false */\n clearable?: boolean;\n clearAriaLabel?: string;\n id?: string;\n className?: string;\n options: AutocompleteOption[];\n inputValue?: string;\n onInputChange?: (value: string) => void;\n filterFn?: (option: AutocompleteOption, query: string) => boolean;\n /** @default false */\n creatable?: boolean;\n creatableLabel?: (inputValue: string) => string;\n onCreate?: (inputValue: string) => void;\n /** @default false */\n loading?: boolean;\n loadingText?: string;\n emptyText?: string;\n renderOption?: (\n option: AutocompleteOption,\n state: { selected: boolean; active: boolean },\n ) => React.ReactNode;\n renderTag?: (option: AutocompleteOption, onRemove: () => void) => React.ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\ninterface AutocompleteSingleProps extends AutocompleteBaseProps {\n multiple?: false;\n value?: string | null;\n defaultValue?: string | null;\n onChange?: (value: string | null) => void;\n}\n\ninterface AutocompleteMultiProps extends AutocompleteBaseProps {\n multiple: true;\n value?: string[];\n defaultValue?: string[];\n onChange?: (values: string[]) => void;\n}\n\nexport type AutocompleteProps = AutocompleteSingleProps | AutocompleteMultiProps;\n\nconst CONTAINER_HEIGHT: Record<AutocompleteSize, string> = {\n \"48\": \"min-h-12\",\n \"40\": \"min-h-10\",\n \"32\": \"min-h-8\",\n};\n\nconst INPUT_SIZE_CLASSES: Record<AutocompleteSize, string> = {\n \"48\": \"typography-regular-body-lg\",\n \"40\": \"typography-regular-body-lg\",\n \"32\": \"typography-regular-body-md\",\n};\n\nconst PADDING_CLASSES: Record<AutocompleteSize, string> = {\n \"48\": \"px-4 py-1.5 gap-3\",\n \"40\": \"px-4 py-1 gap-3\",\n \"32\": \"px-3 py-1 gap-2\",\n};\n\nfunction warnMissingAccessibleName(label?: string, ariaLabel?: string, ariaLabelledBy?: string) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!label && !ariaLabel && !ariaLabelledBy) {\n console.warn(\n \"Autocomplete: no accessible name provided. Pass a `label`, `aria-label`, or `aria-labelledby` prop.\",\n );\n }\n }\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Conditional JSX branches in the render template\nexport const Autocomplete = React.forwardRef<HTMLInputElement, AutocompleteProps>((props, ref) => {\n const {\n label,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n helperText,\n size = \"48\",\n error = false,\n errorMessage,\n placeholder,\n leftIcon,\n fullWidth = false,\n disabled = false,\n clearable = false,\n clearAriaLabel = \"Clear\",\n className,\n loading = false,\n loadingText,\n emptyText = \"No results\",\n renderOption,\n renderTag,\n } = props;\n\n const ac = useAutocomplete(props);\n\n React.useImperativeHandle(ref, () => ac.inputRef.current as HTMLInputElement);\n\n warnMissingAccessibleName(label, ariaLabel, ariaLabelledby);\n\n const bottomText = error && errorMessage ? errorMessage : helperText;\n\n return (\n <Popover.Root open={ac.isOpen && !disabled} onOpenChange={ac.handleOpenChange}>\n <div\n className={cn(\"flex flex-col\", fullWidth && \"w-full\", className)}\n data-autocomplete-root=\"\"\n data-disabled={disabled ? \"\" : undefined}\n data-error={error ? \"\" : undefined}\n >\n {label && (\n <label\n htmlFor={ac.inputId}\n className=\"typography-semibold-body-sm px-1 pt-1 pb-2 text-foreground-default\"\n >\n {label}\n </label>\n )}\n\n <Popover.Anchor asChild>\n {/* biome-ignore lint/a11y/noStaticElementInteractions: Container delegates click to the inner input */}\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: Keyboard interaction is handled by the inner combobox input */}\n <div\n className={cn(\n \"flex flex-wrap items-center overflow-hidden rounded-xl border bg-neutral-100 has-focus-visible:outline-none motion-safe:transition-colors\",\n error ? \"border-error-default\" : \"border-transparent\",\n !disabled && !error && \"hover:border-neutral-400\",\n ac.isOpen && !error && !disabled && \"border-neutral-400\",\n CONTAINER_HEIGHT[size],\n PADDING_CLASSES[size],\n disabled && \"opacity-50\",\n )}\n onClick={ac.handleContainerClick}\n >\n {leftIcon && (\n <div className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary\">\n {leftIcon}\n </div>\n )}\n\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n {ac.isMulti &&\n ac.selectedMultiOptions.map((opt) => (\n <AutocompleteTag\n key={opt.value}\n option={opt}\n disabled={disabled}\n onRemove={() => ac.toggleMulti(opt.value)}\n renderTag={renderTag}\n />\n ))}\n\n <input\n ref={ac.inputRef}\n id={ac.inputId}\n role=\"combobox\"\n type=\"text\"\n disabled={disabled}\n aria-expanded={ac.isOpen}\n aria-controls={ac.isOpen ? ac.listboxId : undefined}\n aria-activedescendant={ac.activeDescendantId}\n aria-autocomplete=\"list\"\n aria-describedby={bottomText ? ac.helperTextId : undefined}\n aria-invalid={error || undefined}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n autoComplete=\"off\"\n placeholder={\n ac.isMulti && ac.selectedMultiValues.length > 0 ? undefined : placeholder\n }\n value={ac.displayInputValue}\n onChange={ac.handleInputChange}\n onKeyDown={ac.handleKeyDown}\n onFocus={ac.handleFocus}\n onBlur={ac.handleBlur}\n className={cn(\n \"min-w-[40px] flex-1 truncate rounded-xl bg-transparent text-foreground-default no-underline placeholder:text-foreground-secondary placeholder:opacity-40 focus:outline-none disabled:cursor-not-allowed\",\n INPUT_SIZE_CLASSES[size],\n )}\n />\n </div>\n\n <div className=\"flex shrink-0 items-center gap-1\">\n {loading && <SpinnerIcon className=\"size-4 animate-spin text-foreground-secondary\" />}\n {clearable && ac.hasClearableValue && !disabled && (\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={clearAriaLabel}\n className=\"flex size-5 shrink-0 cursor-pointer items-center justify-center text-foreground-secondary hover:text-foreground-default active:scale-95\"\n onClick={ac.handleClear}\n >\n <CloseIcon className=\"size-4\" />\n </button>\n )}\n <div className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary\">\n <ChevronDownIcon\n className={cn(\"size-5 transition-transform\", ac.isOpen && \"rotate-180\")}\n />\n </div>\n </div>\n </div>\n </Popover.Anchor>\n\n <Popover.Portal>\n <Popover.Content\n sideOffset={4}\n collisionPadding={8}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\" }}\n className={cn(\n \"w-(--radix-popover-trigger-width) min-w-(--radix-popper-anchor-width) overflow-hidden rounded-xl border border-neutral-200 bg-surface-page text-foreground-default shadow-[0_4px_16px_rgba(0,0,0,0.10)]\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n \"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n \"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2\",\n )}\n >\n <div\n ref={ac.listRef}\n id={ac.listboxId}\n role=\"listbox\"\n aria-label={label ?? ariaLabel ?? \"Options\"}\n aria-multiselectable={ac.isMulti || undefined}\n className=\"max-h-60 overflow-y-auto p-1\"\n >\n <AutocompleteDropdownContent\n loading={loading}\n loadingText={loadingText}\n emptyText={emptyText}\n visibleOptions={ac.visibleOptions}\n listboxId={ac.listboxId}\n activeIndex={ac.activeIndex}\n isMulti={ac.isMulti}\n selectedMultiValues={ac.selectedMultiValues}\n selectedValue={ac.selectedValue}\n onSelect={ac.handleSelect}\n onMouseEnter={ac.setActiveIndex}\n renderOption={renderOption}\n />\n </div>\n </Popover.Content>\n </Popover.Portal>\n\n {bottomText && (\n <p\n id={ac.helperTextId}\n className={cn(\n \"typography-regular-body-sm px-2 pt-1 pb-0.5\",\n error ? \"text-error-default\" : \"text-foreground-secondary\",\n )}\n >\n {bottomText}\n </p>\n )}\n </div>\n </Popover.Root>\n );\n});\n\nAutocomplete.displayName = \"Autocomplete\";\n"],"names":["React","useAutocomplete","jsx","Popover","jsxs","cn","AutocompleteTag","SpinnerIcon","CloseIcon","ChevronDownIcon","AutocompleteDropdownContent"],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
5
|
+
const PopoverPrimitive = require("@radix-ui/react-popover");
|
|
6
|
+
const React = require("react");
|
|
7
|
+
const cn = require("../../utils/cn.cjs");
|
|
8
|
+
const Button = require("../Button/Button.cjs");
|
|
9
|
+
function _interopNamespaceDefault(e) {
|
|
10
|
+
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
11
|
+
if (e) {
|
|
12
|
+
for (const k in e) {
|
|
13
|
+
if (k !== "default") {
|
|
14
|
+
const d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: () => e[k]
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
const PopoverPrimitive__namespace = /* @__PURE__ */ _interopNamespaceDefault(PopoverPrimitive);
|
|
26
|
+
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
27
|
+
const InfoBox = PopoverPrimitive__namespace.Root;
|
|
28
|
+
const InfoBoxTrigger = PopoverPrimitive__namespace.Trigger;
|
|
29
|
+
const ACTION_CLASSES = {
|
|
30
|
+
brand: "hover:bg-brand-accent-default/80 hover:text-foreground-onaccent",
|
|
31
|
+
tertiary: "text-foreground-inverse hover:text-foreground-inverse hover:bg-foreground-inverse/10"
|
|
32
|
+
};
|
|
33
|
+
const ActionButton = ({
|
|
34
|
+
action,
|
|
35
|
+
variant
|
|
36
|
+
}) => "element" in action ? action.element : /* @__PURE__ */ jsxRuntime.jsx(Button.Button, { variant, onClick: action.onClick, className: ACTION_CLASSES[variant], children: action.label });
|
|
37
|
+
const InfoBoxContent = React__namespace.forwardRef(
|
|
38
|
+
({
|
|
39
|
+
className,
|
|
40
|
+
showArrow = true,
|
|
41
|
+
sideOffset = 8,
|
|
42
|
+
heading,
|
|
43
|
+
icon,
|
|
44
|
+
pill,
|
|
45
|
+
primaryAction,
|
|
46
|
+
secondaryAction,
|
|
47
|
+
children,
|
|
48
|
+
style,
|
|
49
|
+
onOpenAutoFocus,
|
|
50
|
+
...props
|
|
51
|
+
}, ref) => {
|
|
52
|
+
const hasHeader = icon !== void 0 || heading !== void 0 || pill !== void 0;
|
|
53
|
+
const hasActions = primaryAction !== void 0 || secondaryAction !== void 0;
|
|
54
|
+
const headingId = React__namespace.useId();
|
|
55
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PopoverPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
56
|
+
PopoverPrimitive__namespace.Content,
|
|
57
|
+
{
|
|
58
|
+
ref,
|
|
59
|
+
sideOffset,
|
|
60
|
+
collisionPadding: 8,
|
|
61
|
+
style: { zIndex: "var(--fanvue-ui-portal-z-index, 50)", ...style },
|
|
62
|
+
className: cn.cn(
|
|
63
|
+
"typography-regular-body-md max-w-[280px] overflow-hidden rounded-2xl border border-neutral-200 bg-surface-pageinverse p-4 text-foreground-inverse shadow-[0px_2px_4px_0px_rgba(17,24,39,0.08)]",
|
|
64
|
+
className
|
|
65
|
+
),
|
|
66
|
+
align: "center",
|
|
67
|
+
"aria-labelledby": heading ? headingId : void 0,
|
|
68
|
+
arrowPadding: 12,
|
|
69
|
+
onOpenAutoFocus: (e) => {
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
onOpenAutoFocus?.(e);
|
|
72
|
+
},
|
|
73
|
+
...props,
|
|
74
|
+
children: [
|
|
75
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
76
|
+
hasHeader && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
77
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "size-5 shrink-0", children: icon }),
|
|
78
|
+
heading && /* @__PURE__ */ jsxRuntime.jsx(
|
|
79
|
+
"p",
|
|
80
|
+
{
|
|
81
|
+
id: headingId,
|
|
82
|
+
className: "typography-semibold-body-lg min-w-0 flex-1 text-foreground-inverse",
|
|
83
|
+
children: heading
|
|
84
|
+
}
|
|
85
|
+
),
|
|
86
|
+
pill && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: pill })
|
|
87
|
+
] }),
|
|
88
|
+
children && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "typography-regular-body-md text-foreground-inverse", children }),
|
|
89
|
+
hasActions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
90
|
+
primaryAction && /* @__PURE__ */ jsxRuntime.jsx(ActionButton, { action: primaryAction, variant: "brand" }),
|
|
91
|
+
secondaryAction && /* @__PURE__ */ jsxRuntime.jsx(ActionButton, { action: secondaryAction, variant: "tertiary" })
|
|
92
|
+
] })
|
|
93
|
+
] }),
|
|
94
|
+
showArrow && /* @__PURE__ */ jsxRuntime.jsx(
|
|
95
|
+
PopoverPrimitive__namespace.Arrow,
|
|
96
|
+
{
|
|
97
|
+
className: "-translate-y-px! fill-surface-pageinverse stroke-2 stroke-surface-pageinverse",
|
|
98
|
+
width: 12,
|
|
99
|
+
height: 6
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
) });
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
InfoBoxContent.displayName = "InfoBoxContent";
|
|
108
|
+
exports.InfoBox = InfoBox;
|
|
109
|
+
exports.InfoBoxContent = InfoBoxContent;
|
|
110
|
+
exports.InfoBoxTrigger = InfoBoxTrigger;
|
|
111
|
+
//# sourceMappingURL=InfoBox.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InfoBox.cjs","sources":["../../../../src/components/InfoBox/InfoBox.tsx"],"sourcesContent":["import * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../Button/Button\";\n\n/** Props for the {@link InfoBox} root component. */\nexport interface InfoBoxProps extends React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Root> {\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for an info box. */\nexport const InfoBox = PopoverPrimitive.Root;\n\n/** Props for the {@link InfoBoxTrigger} component. */\nexport type InfoBoxTriggerProps = React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Trigger>;\n\n/** The element that triggers the info box on click. */\nexport const InfoBoxTrigger = PopoverPrimitive.Trigger;\n\n/** Action button with a label and click handler. */\ninterface InfoBoxButtonAction {\n label: string;\n onClick?: () => void;\n}\n\n/** Custom element rendered in place of the default action button. */\ninterface InfoBoxElementAction {\n element: React.ReactNode;\n}\n\n/** Action configuration for {@link InfoBoxContent}. */\nexport type InfoBoxAction = InfoBoxButtonAction | InfoBoxElementAction;\n\nexport interface InfoBoxContentProps\n extends React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> {\n /** Whether to show the directional arrow pointer. @default true */\n showArrow?: boolean;\n /** Heading text rendered at the top of the info box. */\n heading?: React.ReactNode;\n /** Icon element displayed to the left of the heading. */\n icon?: React.ReactNode;\n /** Pill or badge element displayed to the right of the heading. */\n pill?: React.ReactNode;\n /** Primary action button (brand green). */\n primaryAction?: InfoBoxAction;\n /** Secondary action button (ghost). */\n secondaryAction?: InfoBoxAction;\n}\n\nconst ACTION_CLASSES: Record<\"brand\" | \"tertiary\", string> = {\n brand: \"hover:bg-brand-accent-default/80 hover:text-foreground-onaccent\",\n tertiary: \"text-foreground-inverse hover:text-foreground-inverse hover:bg-foreground-inverse/10\",\n};\n\nconst ActionButton = ({\n action,\n variant,\n}: {\n action: InfoBoxAction;\n variant: \"brand\" | \"tertiary\";\n}) =>\n \"element\" in action ? (\n action.element\n ) : (\n <Button variant={variant} onClick={action.onClick} className={ACTION_CLASSES[variant]}>\n {action.label}\n </Button>\n );\n\nexport const InfoBoxContent = React.forwardRef<\n React.ComponentRef<typeof PopoverPrimitive.Content>,\n InfoBoxContentProps\n>(\n (\n {\n className,\n showArrow = true,\n sideOffset = 8,\n heading,\n icon,\n pill,\n primaryAction,\n secondaryAction,\n children,\n style,\n onOpenAutoFocus,\n ...props\n },\n ref,\n ) => {\n const hasHeader = icon !== undefined || heading !== undefined || pill !== undefined;\n const hasActions = primaryAction !== undefined || secondaryAction !== undefined;\n const headingId = React.useId();\n\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n collisionPadding={8}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"typography-regular-body-md max-w-[280px] overflow-hidden rounded-2xl border border-neutral-200 bg-surface-pageinverse p-4 text-foreground-inverse shadow-[0px_2px_4px_0px_rgba(17,24,39,0.08)]\",\n className,\n )}\n align=\"center\"\n aria-labelledby={heading ? headingId : undefined}\n arrowPadding={12}\n onOpenAutoFocus={(e) => {\n // Prevent auto-focus stealing when opening — content is supplementary, not a dialog.\n e.preventDefault();\n onOpenAutoFocus?.(e);\n }}\n {...props}\n >\n <div className=\"flex flex-col gap-3\">\n {hasHeader && (\n <div className=\"flex items-center gap-3\">\n {icon && <div className=\"size-5 shrink-0\">{icon}</div>}\n {heading && (\n <p\n id={headingId}\n className=\"typography-semibold-body-lg min-w-0 flex-1 text-foreground-inverse\"\n >\n {heading}\n </p>\n )}\n {pill && <div className=\"shrink-0\">{pill}</div>}\n </div>\n )}\n {children && (\n <div className=\"typography-regular-body-md text-foreground-inverse\">{children}</div>\n )}\n {hasActions && (\n <div className=\"flex items-center gap-1\">\n {primaryAction && <ActionButton action={primaryAction} variant=\"brand\" />}\n {secondaryAction && <ActionButton action={secondaryAction} variant=\"tertiary\" />}\n </div>\n )}\n </div>\n {showArrow && (\n <PopoverPrimitive.Arrow\n className={\n \"-translate-y-px! fill-surface-pageinverse stroke-2 stroke-surface-pageinverse\"\n }\n width={12}\n height={6}\n />\n )}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n );\n },\n);\nInfoBoxContent.displayName = \"InfoBoxContent\";\n"],"names":["PopoverPrimitive","Button","React","jsx","jsxs","cn"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAaO,MAAM,UAAUA,4BAAiB;AAMjC,MAAM,iBAAiBA,4BAAiB;AAgC/C,MAAM,iBAAuD;AAAA,EAC3D,OAAO;AAAA,EACP,UAAU;AACZ;AAEA,MAAM,eAAe,CAAC;AAAA,EACpB;AAAA,EACA;AACF,MAIE,aAAa,SACX,OAAO,yCAENC,OAAAA,QAAA,EAAO,SAAkB,SAAS,OAAO,SAAS,WAAW,eAAe,OAAO,GACjF,iBAAO,OACV;AAGG,MAAM,iBAAiBC,iBAAM;AAAA,EAIlC,CACE;AAAA,IACE;AAAA,IACA,YAAY;AAAA,IACZ,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,YAAY,SAAS,UAAa,YAAY,UAAa,SAAS;AAC1E,UAAM,aAAa,kBAAkB,UAAa,oBAAoB;AACtE,UAAM,YAAYA,iBAAM,MAAA;AAExB,WACEC,2BAAAA,IAACH,4BAAiB,QAAjB,EACC,UAAAI,2BAAAA;AAAAA,MAACJ,4BAAiB;AAAA,MAAjB;AAAA,QACC;AAAA,QACA;AAAA,QACA,kBAAkB;AAAA,QAClB,OAAO,EAAE,QAAQ,uCAAuC,GAAG,MAAA;AAAA,QAC3D,WAAWK,GAAAA;AAAAA,UACT;AAAA,UACA;AAAA,QAAA;AAAA,QAEF,OAAM;AAAA,QACN,mBAAiB,UAAU,YAAY;AAAA,QACvC,cAAc;AAAA,QACd,iBAAiB,CAAC,MAAM;AAEtB,YAAE,eAAA;AACF,4BAAkB,CAAC;AAAA,QACrB;AAAA,QACC,GAAG;AAAA,QAEJ,UAAA;AAAA,UAAAD,2BAAAA,KAAC,OAAA,EAAI,WAAU,uBACZ,UAAA;AAAA,YAAA,aACCA,2BAAAA,KAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,cAAA,QAAQD,2BAAAA,IAAC,OAAA,EAAI,WAAU,mBAAmB,UAAA,MAAK;AAAA,cAC/C,WACCA,2BAAAA;AAAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,IAAI;AAAA,kBACJ,WAAU;AAAA,kBAET,UAAA;AAAA,gBAAA;AAAA,cAAA;AAAA,cAGJ,QAAQA,2BAAAA,IAAC,OAAA,EAAI,WAAU,YAAY,UAAA,KAAA,CAAK;AAAA,YAAA,GAC3C;AAAA,YAED,YACCA,2BAAAA,IAAC,OAAA,EAAI,WAAU,sDAAsD,UAAS;AAAA,YAE/E,cACCC,2BAAAA,KAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,cAAA,iBAAiBD,2BAAAA,IAAC,cAAA,EAAa,QAAQ,eAAe,SAAQ,SAAQ;AAAA,cACtE,mBAAmBA,2BAAAA,IAAC,cAAA,EAAa,QAAQ,iBAAiB,SAAQ,WAAA,CAAW;AAAA,YAAA,EAAA,CAChF;AAAA,UAAA,GAEJ;AAAA,UACC,aACCA,2BAAAA;AAAAA,YAACH,4BAAiB;AAAA,YAAjB;AAAA,cACC,WACE;AAAA,cAEF,OAAO;AAAA,cACP,QAAQ;AAAA,YAAA;AAAA,UAAA;AAAA,QACV;AAAA,MAAA;AAAA,IAAA,GAGN;AAAA,EAEJ;AACF;AACA,eAAe,cAAc;;;;"}
|
|
@@ -5,7 +5,6 @@ const jsxRuntime = require("react/jsx-runtime");
|
|
|
5
5
|
const TooltipPrimitive = require("@radix-ui/react-tooltip");
|
|
6
6
|
const React = require("react");
|
|
7
7
|
const cn = require("../../utils/cn.cjs");
|
|
8
|
-
const Button = require("../Button/Button.cjs");
|
|
9
8
|
function _interopNamespaceDefault(e) {
|
|
10
9
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
11
10
|
if (e) {
|
|
@@ -27,97 +26,23 @@ const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React);
|
|
|
27
26
|
const TooltipProvider = TooltipPrimitive__namespace.Provider;
|
|
28
27
|
const Tooltip = TooltipPrimitive__namespace.Root;
|
|
29
28
|
const TooltipTrigger = TooltipPrimitive__namespace.Trigger;
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
48
|
-
hasHeader && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
49
|
-
icon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "size-5 shrink-0", children: icon }),
|
|
50
|
-
heading && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "typography-semibold-body-lg min-w-0 flex-1 text-foreground-inverse", children: heading }),
|
|
51
|
-
pill && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", children: pill })
|
|
52
|
-
] }),
|
|
53
|
-
children && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "typography-regular-body-md text-foreground-inverse", children }),
|
|
54
|
-
hasActions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
55
|
-
primaryAction && /* @__PURE__ */ jsxRuntime.jsx(ActionButton, { action: primaryAction, variant: "brand" }),
|
|
56
|
-
secondaryAction && /* @__PURE__ */ jsxRuntime.jsx(ActionButton, { action: secondaryAction, variant: "tertiary" })
|
|
57
|
-
] })
|
|
58
|
-
] });
|
|
59
|
-
const TooltipContent = React__namespace.forwardRef(
|
|
60
|
-
({
|
|
61
|
-
className,
|
|
62
|
-
variant = "tooltip",
|
|
63
|
-
showArrow = true,
|
|
64
|
-
sideOffset = 8,
|
|
65
|
-
heading,
|
|
66
|
-
icon,
|
|
67
|
-
pill,
|
|
68
|
-
primaryAction,
|
|
69
|
-
secondaryAction,
|
|
70
|
-
children,
|
|
71
|
-
side,
|
|
72
|
-
style,
|
|
73
|
-
...props
|
|
74
|
-
}, ref) => {
|
|
75
|
-
const isInfobox = variant === "infobox";
|
|
76
|
-
const hasHeader = isInfobox && (icon !== void 0 || heading !== void 0 || pill !== void 0);
|
|
77
|
-
const hasActions = isInfobox && (primaryAction !== void 0 || secondaryAction !== void 0);
|
|
78
|
-
return /* @__PURE__ */ jsxRuntime.jsx(TooltipPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
79
|
-
TooltipPrimitive__namespace.Content,
|
|
80
|
-
{
|
|
81
|
-
ref,
|
|
82
|
-
sideOffset,
|
|
83
|
-
collisionPadding: 8,
|
|
84
|
-
style: { zIndex: "var(--fanvue-ui-portal-z-index, 50)", ...style },
|
|
85
|
-
className: cn.cn(
|
|
86
|
-
"typography-regular-body-md max-h-[var(--radix-tooltip-content-available-height)] max-w-[320px] overflow-hidden rounded-3xl bg-surface-pageinverse p-4 text-foreground-inverse shadow-[0px_2px_4px_0px_rgba(17,24,39,0.08)]",
|
|
87
|
-
isInfobox && "border border-neutral-200",
|
|
88
|
-
className
|
|
89
|
-
),
|
|
90
|
-
align: "center",
|
|
91
|
-
arrowPadding: 12,
|
|
92
|
-
side,
|
|
93
|
-
...props,
|
|
94
|
-
children: [
|
|
95
|
-
isInfobox ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
96
|
-
InfoboxContent,
|
|
97
|
-
{
|
|
98
|
-
icon,
|
|
99
|
-
heading,
|
|
100
|
-
pill,
|
|
101
|
-
primaryAction,
|
|
102
|
-
secondaryAction,
|
|
103
|
-
hasHeader,
|
|
104
|
-
hasActions,
|
|
105
|
-
children
|
|
106
|
-
}
|
|
107
|
-
) : children,
|
|
108
|
-
showArrow && /* @__PURE__ */ jsxRuntime.jsx(
|
|
109
|
-
TooltipPrimitive__namespace.Arrow,
|
|
110
|
-
{
|
|
111
|
-
className: "-translate-y-px! fill-surface-pageinverse stroke-2 stroke-surface-pageinverse",
|
|
112
|
-
width: 12,
|
|
113
|
-
height: 6
|
|
114
|
-
}
|
|
115
|
-
)
|
|
116
|
-
]
|
|
117
|
-
}
|
|
118
|
-
) });
|
|
119
|
-
}
|
|
120
|
-
);
|
|
29
|
+
const TooltipContent = React__namespace.forwardRef(({ className, sideOffset = 8, style, ...props }, ref) => {
|
|
30
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TooltipPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
31
|
+
TooltipPrimitive__namespace.Content,
|
|
32
|
+
{
|
|
33
|
+
ref,
|
|
34
|
+
sideOffset,
|
|
35
|
+
collisionPadding: 8,
|
|
36
|
+
style: { zIndex: "var(--fanvue-ui-portal-z-index, 50)", ...style },
|
|
37
|
+
className: cn.cn(
|
|
38
|
+
"typography-semibold-body-sm max-w-[320px] rounded-full bg-surface-pageinverse px-4 py-2 text-foreground-inverse shadow-[0px_1px_4px_0px_rgba(0,0,0,0.06),0px_1px_3px_0px_rgba(0,0,0,0.05)]",
|
|
39
|
+
className
|
|
40
|
+
),
|
|
41
|
+
align: "center",
|
|
42
|
+
...props
|
|
43
|
+
}
|
|
44
|
+
) });
|
|
45
|
+
});
|
|
121
46
|
TooltipContent.displayName = "TooltipContent";
|
|
122
47
|
exports.Tooltip = Tooltip;
|
|
123
48
|
exports.TooltipContent = TooltipContent;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tooltip.cjs","sources":["../../../../src/components/Tooltip/Tooltip.tsx"],"sourcesContent":["import * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../Button/Button\";\n\n/** Props for the {@link TooltipProvider}. Wraps Radix `Tooltip.Provider`. */\nexport type TooltipProviderProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Provider>;\n\n/** Provides tooltip delay and skip-delay context. Wrap your app or a subtree. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\n/** Props for the {@link Tooltip} root component. */\nexport interface TooltipProps extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root> {\n /**\n * Controlled open state. When provided, the component is in controlled mode\n * and you must also supply `onOpenChange` to update the value.\n */\n open?: boolean;\n /** Called when the open state changes. Required when `open` is controlled. */\n onOpenChange?: (open: boolean) => void;\n /** The open state of the tooltip when it is initially rendered (uncontrolled). */\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for a single tooltip. */\nexport const Tooltip = TooltipPrimitive.Root;\n\n/** Props for the {@link TooltipTrigger} component. */\nexport type TooltipTriggerProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger>;\n\n/** The element that triggers the tooltip on hover/focus. */\nexport const TooltipTrigger = TooltipPrimitive.Trigger;\n\n/**\n * Visual style variant of the tooltip content.\n *\n * - `\"tooltip\"` — simple text bubble, no border.\n * - `\"infobox\"` — richer card with a visible border, structured header, body text, and optional actions.\n */\nexport type TooltipContentVariant = \"tooltip\" | \"infobox\";\n\n/** Action button configuration for the infobox variant of {@link TooltipContent}. */\nexport interface TooltipAction {\n /** Button label. */\n label: string;\n /** Click handler. */\n onClick?: () => void;\n /**\n * Optional custom React node to be rendered for the action instead of the default button.\n * Only used in the infobox variant.\n */\n element?: React.ReactNode;\n}\n\nexport interface TooltipContentProps\n extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> {\n /**\n * Visual style variant.\n *\n * `\"tooltip\"` is a lightweight text bubble. `\"infobox\"` renders a structured card\n * with optional heading, icon, pill, body text, and action buttons.\n *\n * @default \"tooltip\"\n */\n variant?: TooltipContentVariant;\n /** Whether to show the directional arrow pointer. @default true */\n showArrow?: boolean;\n /**\n * Heading text rendered in subtitle style at the top of the infobox.\n * Infobox variant only.\n */\n heading?: React.ReactNode;\n /**\n * Icon element displayed to the left of the heading.\n * Infobox variant only.\n */\n icon?: React.ReactNode;\n /**\n * Pill or badge element displayed to the right of the heading.\n * Infobox variant only.\n */\n pill?: React.ReactNode;\n /**\n * Primary action button (brand green). Rendered below the body text.\n * Infobox variant only.\n */\n primaryAction?: TooltipAction;\n /**\n * Secondary action button (ghost). Rendered next to the primary action.\n * Infobox variant only.\n */\n secondaryAction?: TooltipAction;\n}\n\n/** Class overrides so CTA buttons render correctly on the tooltip's inverted background. */\nconst TOOLTIP_ACTION_CLASSES: Record<\"brand\" | \"tertiary\", string> = {\n brand: \"hover:bg-brand-accent-default/80 hover:text-foreground-onaccent\",\n tertiary: \"text-foreground-inverse hover:text-foreground-inverse hover:bg-foreground-inverse/10\",\n};\n\nconst ActionButton = ({\n action,\n variant,\n}: {\n action: TooltipAction;\n variant: \"brand\" | \"tertiary\";\n}) =>\n action.element ? (\n action.element\n ) : (\n <Button variant={variant} onClick={action.onClick} className={TOOLTIP_ACTION_CLASSES[variant]}>\n {action.label}\n </Button>\n );\n\nconst InfoboxContent = ({\n icon,\n heading,\n pill,\n children,\n primaryAction,\n secondaryAction,\n hasHeader,\n hasActions,\n}: {\n icon?: React.ReactNode;\n heading?: React.ReactNode;\n pill?: React.ReactNode;\n children?: React.ReactNode;\n primaryAction?: TooltipAction;\n secondaryAction?: TooltipAction;\n hasHeader: boolean;\n hasActions: boolean;\n}) => (\n <div className=\"flex flex-col gap-3\">\n {hasHeader && (\n <div className=\"flex items-center gap-3\">\n {icon && <div className=\"size-5 shrink-0\">{icon}</div>}\n {heading && (\n <p className=\"typography-semibold-body-lg min-w-0 flex-1 text-foreground-inverse\">\n {heading}\n </p>\n )}\n {pill && <div className=\"shrink-0\">{pill}</div>}\n </div>\n )}\n {children && (\n <div className=\"typography-regular-body-md text-foreground-inverse\">{children}</div>\n )}\n {hasActions && (\n <div className=\"flex items-center gap-1\">\n {primaryAction && <ActionButton action={primaryAction} variant=\"brand\" />}\n {secondaryAction && <ActionButton action={secondaryAction} variant=\"tertiary\" />}\n </div>\n )}\n </div>\n);\n\n/**\n * The popup content of the tooltip. Renders inside a portal.\n *\n * Arrow direction is controlled via the `side` and `align` props (Radix passthrough).\n *\n * @example\n * ```tsx\n * // Simple tooltip\n * <TooltipContent>Info text</TooltipContent>\n *\n * // Infobox with structured content\n * <TooltipContent\n * variant=\"infobox\"\n * heading=\"Title\"\n * icon={<InfoCircleIcon className=\"size-5\" />}\n * primaryAction={{ label: \"OK\", onClick: () => {} }}\n * secondaryAction={{ label: \"Dismiss\" }}\n * >\n * Info text\n * </TooltipContent>\n * ```\n */\nexport const TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n TooltipContentProps\n>(\n (\n {\n className,\n variant = \"tooltip\",\n showArrow = true,\n sideOffset = 8,\n heading,\n icon,\n pill,\n primaryAction,\n secondaryAction,\n children,\n side,\n style,\n ...props\n },\n ref,\n ) => {\n const isInfobox = variant === \"infobox\";\n const hasHeader =\n isInfobox && (icon !== undefined || heading !== undefined || pill !== undefined);\n const hasActions = isInfobox && (primaryAction !== undefined || secondaryAction !== undefined);\n\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n collisionPadding={8}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"typography-regular-body-md max-h-[var(--radix-tooltip-content-available-height)] max-w-[320px] overflow-hidden rounded-3xl bg-surface-pageinverse p-4 text-foreground-inverse shadow-[0px_2px_4px_0px_rgba(17,24,39,0.08)]\",\n isInfobox && \"border border-neutral-200\",\n className,\n )}\n align=\"center\"\n arrowPadding={12}\n side={side}\n {...props}\n >\n {isInfobox ? (\n <InfoboxContent\n icon={icon}\n heading={heading}\n pill={pill}\n primaryAction={primaryAction}\n secondaryAction={secondaryAction}\n hasHeader={hasHeader}\n hasActions={hasActions}\n >\n {children}\n </InfoboxContent>\n ) : (\n children\n )}\n {showArrow && (\n <TooltipPrimitive.Arrow\n className={\n \"-translate-y-px! fill-surface-pageinverse stroke-2 stroke-surface-pageinverse\"\n }\n width={12}\n height={6}\n />\n )}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n );\n },\n);\nTooltipContent.displayName = \"TooltipContent\";\n"],"names":["TooltipPrimitive","Button","jsxs","jsx","React","cn"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AASO,MAAM,kBAAkBA,4BAAiB;AAgBzC,MAAM,UAAUA,4BAAiB;AAMjC,MAAM,iBAAiBA,4BAAiB;AAgE/C,MAAM,yBAA+D;AAAA,EACnE,OAAO;AAAA,EACP,UAAU;AACZ;AAEA,MAAM,eAAe,CAAC;AAAA,EACpB;AAAA,EACA;AACF,MAIE,OAAO,UACL,OAAO,yCAENC,OAAAA,QAAA,EAAO,SAAkB,SAAS,OAAO,SAAS,WAAW,uBAAuB,OAAO,GACzF,iBAAO,OACV;AAGJ,MAAM,iBAAiB,CAAC;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAUEC,2BAAAA,KAAC,OAAA,EAAI,WAAU,uBACZ,UAAA;AAAA,EAAA,aACCA,2BAAAA,KAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,IAAA,QAAQC,2BAAAA,IAAC,OAAA,EAAI,WAAU,mBAAmB,UAAA,MAAK;AAAA,IAC/C,WACCA,2BAAAA,IAAC,KAAA,EAAE,WAAU,sEACV,UAAA,SACH;AAAA,IAED,QAAQA,2BAAAA,IAAC,OAAA,EAAI,WAAU,YAAY,UAAA,KAAA,CAAK;AAAA,EAAA,GAC3C;AAAA,EAED,YACCA,2BAAAA,IAAC,OAAA,EAAI,WAAU,sDAAsD,UAAS;AAAA,EAE/E,cACCD,2BAAAA,KAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,IAAA,iBAAiBC,2BAAAA,IAAC,cAAA,EAAa,QAAQ,eAAe,SAAQ,SAAQ;AAAA,IACtE,mBAAmBA,2BAAAA,IAAC,cAAA,EAAa,QAAQ,iBAAiB,SAAQ,WAAA,CAAW;AAAA,EAAA,EAAA,CAChF;AAAA,GAEJ;AAyBK,MAAM,iBAAiBC,iBAAM;AAAA,EAIlC,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,YAAY,YAAY;AAC9B,UAAM,YACJ,cAAc,SAAS,UAAa,YAAY,UAAa,SAAS;AACxE,UAAM,aAAa,cAAc,kBAAkB,UAAa,oBAAoB;AAEpF,WACED,2BAAAA,IAACH,4BAAiB,QAAjB,EACC,UAAAE,2BAAAA;AAAAA,MAACF,4BAAiB;AAAA,MAAjB;AAAA,QACC;AAAA,QACA;AAAA,QACA,kBAAkB;AAAA,QAClB,OAAO,EAAE,QAAQ,uCAAuC,GAAG,MAAA;AAAA,QAC3D,WAAWK,GAAAA;AAAAA,UACT;AAAA,UACA,aAAa;AAAA,UACb;AAAA,QAAA;AAAA,QAEF,OAAM;AAAA,QACN,cAAc;AAAA,QACd;AAAA,QACC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,YACCF,2BAAAA;AAAAA,YAAC;AAAA,YAAA;AAAA,cACC;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cAEC;AAAA,YAAA;AAAA,UAAA,IAGH;AAAA,UAED,aACCA,2BAAAA;AAAAA,YAACH,4BAAiB;AAAA,YAAjB;AAAA,cACC,WACE;AAAA,cAEF,OAAO;AAAA,cACP,QAAQ;AAAA,YAAA;AAAA,UAAA;AAAA,QACV;AAAA,MAAA;AAAA,IAAA,GAGN;AAAA,EAEJ;AACF;AACA,eAAe,cAAc;;;;;"}
|
|
1
|
+
{"version":3,"file":"Tooltip.cjs","sources":["../../../../src/components/Tooltip/Tooltip.tsx"],"sourcesContent":["import * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Props for the {@link TooltipProvider}. Wraps Radix `Tooltip.Provider`. */\nexport type TooltipProviderProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Provider>;\n\n/** Provides tooltip delay and skip-delay context. Wrap your app or a subtree. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\n/** Props for the {@link Tooltip} root component. */\nexport interface TooltipProps extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root> {\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for a single tooltip. */\nexport const Tooltip = TooltipPrimitive.Root;\n\n/** Props for the {@link TooltipTrigger} component. */\nexport type TooltipTriggerProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger>;\n\n/** The element that triggers the tooltip on hover/focus. */\nexport const TooltipTrigger = TooltipPrimitive.Trigger;\n\nexport type TooltipContentProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>;\n\nexport const TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n TooltipContentProps\n>(({ className, sideOffset = 8, style, ...props }, ref) => {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n collisionPadding={8}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"typography-semibold-body-sm max-w-[320px] rounded-full bg-surface-pageinverse px-4 py-2 text-foreground-inverse shadow-[0px_1px_4px_0px_rgba(0,0,0,0.06),0px_1px_3px_0px_rgba(0,0,0,0.05)]\",\n className,\n )}\n align=\"center\"\n {...props}\n />\n </TooltipPrimitive.Portal>\n );\n});\nTooltipContent.displayName = \"TooltipContent\";\n"],"names":["TooltipPrimitive","React","jsx","cn"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAQO,MAAM,kBAAkBA,4BAAiB;AAUzC,MAAM,UAAUA,4BAAiB;AAMjC,MAAM,iBAAiBA,4BAAiB;AAIxC,MAAM,iBAAiBC,iBAAM,WAGlC,CAAC,EAAE,WAAW,aAAa,GAAG,OAAO,GAAG,MAAA,GAAS,QAAQ;AACzD,SACEC,2BAAAA,IAACF,4BAAiB,QAAjB,EACC,UAAAE,2BAAAA;AAAAA,IAACF,4BAAiB;AAAA,IAAjB;AAAA,MACC;AAAA,MACA;AAAA,MACA,kBAAkB;AAAA,MAClB,OAAO,EAAE,QAAQ,uCAAuC,GAAG,MAAA;AAAA,MAC3D,WAAWG,GAAAA;AAAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,OAAM;AAAA,MACL,GAAG;AAAA,IAAA;AAAA,EAAA,GAER;AAEJ,CAAC;AACD,eAAe,cAAc;;;;;"}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -141,6 +141,7 @@ const WarningTriangleIcon = require("./components/Icons/WarningTriangleIcon.cjs"
|
|
|
141
141
|
const WifiOffIcon = require("./components/Icons/WifiOffIcon.cjs");
|
|
142
142
|
const WifiOnIcon = require("./components/Icons/WifiOnIcon.cjs");
|
|
143
143
|
const WrenchIcon = require("./components/Icons/WrenchIcon.cjs");
|
|
144
|
+
const InfoBox = require("./components/InfoBox/InfoBox.cjs");
|
|
144
145
|
const Loader = require("./components/Loader/Loader.cjs");
|
|
145
146
|
const Logo = require("./components/Logo/Logo.cjs");
|
|
146
147
|
const MobileStepper = require("./components/MobileStepper/MobileStepper.cjs");
|
|
@@ -337,6 +338,9 @@ exports.WarningTriangleIcon = WarningTriangleIcon.WarningTriangleIcon;
|
|
|
337
338
|
exports.WifiOffIcon = WifiOffIcon.WifiOffIcon;
|
|
338
339
|
exports.WifiOnIcon = WifiOnIcon.WifiOnIcon;
|
|
339
340
|
exports.WrenchIcon = WrenchIcon.WrenchIcon;
|
|
341
|
+
exports.InfoBox = InfoBox.InfoBox;
|
|
342
|
+
exports.InfoBoxContent = InfoBox.InfoBoxContent;
|
|
343
|
+
exports.InfoBoxTrigger = InfoBox.InfoBoxTrigger;
|
|
340
344
|
exports.Loader = Loader.Loader;
|
|
341
345
|
exports.Logo = Logo.Logo;
|
|
342
346
|
exports.MobileStepper = MobileStepper.MobileStepper;
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import * as
|
|
3
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { cn } from "../../utils/cn.mjs";
|
|
6
6
|
import { ChevronDownIcon } from "../Icons/ChevronDownIcon.mjs";
|
|
@@ -59,7 +59,7 @@ const Autocomplete = React.forwardRef((props, ref) => {
|
|
|
59
59
|
React.useImperativeHandle(ref, () => ac.inputRef.current);
|
|
60
60
|
warnMissingAccessibleName(label, ariaLabel, ariaLabelledby);
|
|
61
61
|
const bottomText = error && errorMessage ? errorMessage : helperText;
|
|
62
|
-
return /* @__PURE__ */ jsx(
|
|
62
|
+
return /* @__PURE__ */ jsx(PopoverPrimitive.Root, { open: ac.isOpen && !disabled, onOpenChange: ac.handleOpenChange, children: /* @__PURE__ */ jsxs(
|
|
63
63
|
"div",
|
|
64
64
|
{
|
|
65
65
|
className: cn("flex flex-col", fullWidth && "w-full", className),
|
|
@@ -75,7 +75,7 @@ const Autocomplete = React.forwardRef((props, ref) => {
|
|
|
75
75
|
children: label
|
|
76
76
|
}
|
|
77
77
|
),
|
|
78
|
-
/* @__PURE__ */ jsx(
|
|
78
|
+
/* @__PURE__ */ jsx(PopoverPrimitive.Anchor, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
79
79
|
"div",
|
|
80
80
|
{
|
|
81
81
|
className: cn(
|
|
@@ -154,8 +154,8 @@ const Autocomplete = React.forwardRef((props, ref) => {
|
|
|
154
154
|
]
|
|
155
155
|
}
|
|
156
156
|
) }),
|
|
157
|
-
/* @__PURE__ */ jsx(
|
|
158
|
-
|
|
157
|
+
/* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
158
|
+
PopoverPrimitive.Content,
|
|
159
159
|
{
|
|
160
160
|
sideOffset: 4,
|
|
161
161
|
collisionPadding: 8,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Autocomplete.mjs","sources":["../../../src/components/Autocomplete/Autocomplete.tsx"],"sourcesContent":["import * as Popover from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { ChevronDownIcon } from \"../Icons/ChevronDownIcon\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\nimport { SpinnerIcon } from \"../Icons/SpinnerIcon\";\nimport { AutocompleteDropdownContent } from \"./AutocompleteDropdownContent\";\nimport { AutocompleteTag } from \"./AutocompleteTag\";\nimport { useAutocomplete } from \"./useAutocomplete\";\n\nexport type AutocompleteSize = \"48\" | \"40\" | \"32\";\n\nexport interface AutocompleteOption {\n value: string;\n label?: string;\n disabled?: boolean;\n}\n\ninterface AutocompleteBaseProps {\n label?: string;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n helperText?: string;\n /** @default \"48\" */\n size?: AutocompleteSize;\n /** @default false */\n error?: boolean;\n errorMessage?: string;\n placeholder?: string;\n leftIcon?: React.ReactNode;\n /** @default false */\n fullWidth?: boolean;\n /** @default false */\n disabled?: boolean;\n /** @default false */\n clearable?: boolean;\n clearAriaLabel?: string;\n id?: string;\n className?: string;\n options: AutocompleteOption[];\n inputValue?: string;\n onInputChange?: (value: string) => void;\n filterFn?: (option: AutocompleteOption, query: string) => boolean;\n /** @default false */\n creatable?: boolean;\n creatableLabel?: (inputValue: string) => string;\n onCreate?: (inputValue: string) => void;\n /** @default false */\n loading?: boolean;\n loadingText?: string;\n emptyText?: string;\n renderOption?: (\n option: AutocompleteOption,\n state: { selected: boolean; active: boolean },\n ) => React.ReactNode;\n renderTag?: (option: AutocompleteOption, onRemove: () => void) => React.ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\ninterface AutocompleteSingleProps extends AutocompleteBaseProps {\n multiple?: false;\n value?: string | null;\n defaultValue?: string | null;\n onChange?: (value: string | null) => void;\n}\n\ninterface AutocompleteMultiProps extends AutocompleteBaseProps {\n multiple: true;\n value?: string[];\n defaultValue?: string[];\n onChange?: (values: string[]) => void;\n}\n\nexport type AutocompleteProps = AutocompleteSingleProps | AutocompleteMultiProps;\n\nconst CONTAINER_HEIGHT: Record<AutocompleteSize, string> = {\n \"48\": \"min-h-12\",\n \"40\": \"min-h-10\",\n \"32\": \"min-h-8\",\n};\n\nconst INPUT_SIZE_CLASSES: Record<AutocompleteSize, string> = {\n \"48\": \"typography-regular-body-lg\",\n \"40\": \"typography-regular-body-lg\",\n \"32\": \"typography-regular-body-md\",\n};\n\nconst PADDING_CLASSES: Record<AutocompleteSize, string> = {\n \"48\": \"px-4 py-1.5 gap-3\",\n \"40\": \"px-4 py-1 gap-3\",\n \"32\": \"px-3 py-1 gap-2\",\n};\n\nfunction warnMissingAccessibleName(label?: string, ariaLabel?: string, ariaLabelledBy?: string) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!label && !ariaLabel && !ariaLabelledBy) {\n console.warn(\n \"Autocomplete: no accessible name provided. Pass a `label`, `aria-label`, or `aria-labelledby` prop.\",\n );\n }\n }\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Conditional JSX branches in the render template\nexport const Autocomplete = React.forwardRef<HTMLInputElement, AutocompleteProps>((props, ref) => {\n const {\n label,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n helperText,\n size = \"48\",\n error = false,\n errorMessage,\n placeholder,\n leftIcon,\n fullWidth = false,\n disabled = false,\n clearable = false,\n clearAriaLabel = \"Clear\",\n className,\n loading = false,\n loadingText,\n emptyText = \"No results\",\n renderOption,\n renderTag,\n } = props;\n\n const ac = useAutocomplete(props);\n\n React.useImperativeHandle(ref, () => ac.inputRef.current as HTMLInputElement);\n\n warnMissingAccessibleName(label, ariaLabel, ariaLabelledby);\n\n const bottomText = error && errorMessage ? errorMessage : helperText;\n\n return (\n <Popover.Root open={ac.isOpen && !disabled} onOpenChange={ac.handleOpenChange}>\n <div\n className={cn(\"flex flex-col\", fullWidth && \"w-full\", className)}\n data-autocomplete-root=\"\"\n data-disabled={disabled ? \"\" : undefined}\n data-error={error ? \"\" : undefined}\n >\n {label && (\n <label\n htmlFor={ac.inputId}\n className=\"typography-semibold-body-sm px-1 pt-1 pb-2 text-foreground-default\"\n >\n {label}\n </label>\n )}\n\n <Popover.Anchor asChild>\n {/* biome-ignore lint/a11y/noStaticElementInteractions: Container delegates click to the inner input */}\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: Keyboard interaction is handled by the inner combobox input */}\n <div\n className={cn(\n \"flex flex-wrap items-center overflow-hidden rounded-xl border bg-neutral-100 has-focus-visible:outline-none motion-safe:transition-colors\",\n error ? \"border-error-default\" : \"border-transparent\",\n !disabled && !error && \"hover:border-neutral-400\",\n ac.isOpen && !error && !disabled && \"border-neutral-400\",\n CONTAINER_HEIGHT[size],\n PADDING_CLASSES[size],\n disabled && \"opacity-50\",\n )}\n onClick={ac.handleContainerClick}\n >\n {leftIcon && (\n <div className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary\">\n {leftIcon}\n </div>\n )}\n\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n {ac.isMulti &&\n ac.selectedMultiOptions.map((opt) => (\n <AutocompleteTag\n key={opt.value}\n option={opt}\n disabled={disabled}\n onRemove={() => ac.toggleMulti(opt.value)}\n renderTag={renderTag}\n />\n ))}\n\n <input\n ref={ac.inputRef}\n id={ac.inputId}\n role=\"combobox\"\n type=\"text\"\n disabled={disabled}\n aria-expanded={ac.isOpen}\n aria-controls={ac.isOpen ? ac.listboxId : undefined}\n aria-activedescendant={ac.activeDescendantId}\n aria-autocomplete=\"list\"\n aria-describedby={bottomText ? ac.helperTextId : undefined}\n aria-invalid={error || undefined}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n autoComplete=\"off\"\n placeholder={\n ac.isMulti && ac.selectedMultiValues.length > 0 ? undefined : placeholder\n }\n value={ac.displayInputValue}\n onChange={ac.handleInputChange}\n onKeyDown={ac.handleKeyDown}\n onFocus={ac.handleFocus}\n onBlur={ac.handleBlur}\n className={cn(\n \"min-w-[40px] flex-1 truncate rounded-xl bg-transparent text-foreground-default no-underline placeholder:text-foreground-secondary placeholder:opacity-40 focus:outline-none disabled:cursor-not-allowed\",\n INPUT_SIZE_CLASSES[size],\n )}\n />\n </div>\n\n <div className=\"flex shrink-0 items-center gap-1\">\n {loading && <SpinnerIcon className=\"size-4 animate-spin text-foreground-secondary\" />}\n {clearable && ac.hasClearableValue && !disabled && (\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={clearAriaLabel}\n className=\"flex size-5 shrink-0 cursor-pointer items-center justify-center text-foreground-secondary hover:text-foreground-default active:scale-95\"\n onClick={ac.handleClear}\n >\n <CloseIcon className=\"size-4\" />\n </button>\n )}\n <div className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary\">\n <ChevronDownIcon\n className={cn(\"size-5 transition-transform\", ac.isOpen && \"rotate-180\")}\n />\n </div>\n </div>\n </div>\n </Popover.Anchor>\n\n <Popover.Portal>\n <Popover.Content\n sideOffset={4}\n collisionPadding={8}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\" }}\n className={cn(\n \"w-(--radix-popover-trigger-width) min-w-(--radix-popper-anchor-width) overflow-hidden rounded-xl border border-neutral-200 bg-surface-page text-foreground-default shadow-[0_4px_16px_rgba(0,0,0,0.10)]\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n \"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n \"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2\",\n )}\n >\n <div\n ref={ac.listRef}\n id={ac.listboxId}\n role=\"listbox\"\n aria-label={label ?? ariaLabel ?? \"Options\"}\n aria-multiselectable={ac.isMulti || undefined}\n className=\"max-h-60 overflow-y-auto p-1\"\n >\n <AutocompleteDropdownContent\n loading={loading}\n loadingText={loadingText}\n emptyText={emptyText}\n visibleOptions={ac.visibleOptions}\n listboxId={ac.listboxId}\n activeIndex={ac.activeIndex}\n isMulti={ac.isMulti}\n selectedMultiValues={ac.selectedMultiValues}\n selectedValue={ac.selectedValue}\n onSelect={ac.handleSelect}\n onMouseEnter={ac.setActiveIndex}\n renderOption={renderOption}\n />\n </div>\n </Popover.Content>\n </Popover.Portal>\n\n {bottomText && (\n <p\n id={ac.helperTextId}\n className={cn(\n \"typography-regular-body-sm px-2 pt-1 pb-0.5\",\n error ? \"text-error-default\" : \"text-foreground-secondary\",\n )}\n >\n {bottomText}\n </p>\n )}\n </div>\n </Popover.Root>\n );\n});\n\nAutocomplete.displayName = \"Autocomplete\";\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Autocomplete.mjs","sources":["../../../src/components/Autocomplete/Autocomplete.tsx"],"sourcesContent":["import * as Popover from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { ChevronDownIcon } from \"../Icons/ChevronDownIcon\";\nimport { CloseIcon } from \"../Icons/CloseIcon\";\nimport { SpinnerIcon } from \"../Icons/SpinnerIcon\";\nimport { AutocompleteDropdownContent } from \"./AutocompleteDropdownContent\";\nimport { AutocompleteTag } from \"./AutocompleteTag\";\nimport { useAutocomplete } from \"./useAutocomplete\";\n\nexport type AutocompleteSize = \"48\" | \"40\" | \"32\";\n\nexport interface AutocompleteOption {\n value: string;\n label?: string;\n disabled?: boolean;\n}\n\ninterface AutocompleteBaseProps {\n label?: string;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n helperText?: string;\n /** @default \"48\" */\n size?: AutocompleteSize;\n /** @default false */\n error?: boolean;\n errorMessage?: string;\n placeholder?: string;\n leftIcon?: React.ReactNode;\n /** @default false */\n fullWidth?: boolean;\n /** @default false */\n disabled?: boolean;\n /** @default false */\n clearable?: boolean;\n clearAriaLabel?: string;\n id?: string;\n className?: string;\n options: AutocompleteOption[];\n inputValue?: string;\n onInputChange?: (value: string) => void;\n filterFn?: (option: AutocompleteOption, query: string) => boolean;\n /** @default false */\n creatable?: boolean;\n creatableLabel?: (inputValue: string) => string;\n onCreate?: (inputValue: string) => void;\n /** @default false */\n loading?: boolean;\n loadingText?: string;\n emptyText?: string;\n renderOption?: (\n option: AutocompleteOption,\n state: { selected: boolean; active: boolean },\n ) => React.ReactNode;\n renderTag?: (option: AutocompleteOption, onRemove: () => void) => React.ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n}\n\ninterface AutocompleteSingleProps extends AutocompleteBaseProps {\n multiple?: false;\n value?: string | null;\n defaultValue?: string | null;\n onChange?: (value: string | null) => void;\n}\n\ninterface AutocompleteMultiProps extends AutocompleteBaseProps {\n multiple: true;\n value?: string[];\n defaultValue?: string[];\n onChange?: (values: string[]) => void;\n}\n\nexport type AutocompleteProps = AutocompleteSingleProps | AutocompleteMultiProps;\n\nconst CONTAINER_HEIGHT: Record<AutocompleteSize, string> = {\n \"48\": \"min-h-12\",\n \"40\": \"min-h-10\",\n \"32\": \"min-h-8\",\n};\n\nconst INPUT_SIZE_CLASSES: Record<AutocompleteSize, string> = {\n \"48\": \"typography-regular-body-lg\",\n \"40\": \"typography-regular-body-lg\",\n \"32\": \"typography-regular-body-md\",\n};\n\nconst PADDING_CLASSES: Record<AutocompleteSize, string> = {\n \"48\": \"px-4 py-1.5 gap-3\",\n \"40\": \"px-4 py-1 gap-3\",\n \"32\": \"px-3 py-1 gap-2\",\n};\n\nfunction warnMissingAccessibleName(label?: string, ariaLabel?: string, ariaLabelledBy?: string) {\n if (process.env.NODE_ENV !== \"production\") {\n if (!label && !ariaLabel && !ariaLabelledBy) {\n console.warn(\n \"Autocomplete: no accessible name provided. Pass a `label`, `aria-label`, or `aria-labelledby` prop.\",\n );\n }\n }\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Conditional JSX branches in the render template\nexport const Autocomplete = React.forwardRef<HTMLInputElement, AutocompleteProps>((props, ref) => {\n const {\n label,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n helperText,\n size = \"48\",\n error = false,\n errorMessage,\n placeholder,\n leftIcon,\n fullWidth = false,\n disabled = false,\n clearable = false,\n clearAriaLabel = \"Clear\",\n className,\n loading = false,\n loadingText,\n emptyText = \"No results\",\n renderOption,\n renderTag,\n } = props;\n\n const ac = useAutocomplete(props);\n\n React.useImperativeHandle(ref, () => ac.inputRef.current as HTMLInputElement);\n\n warnMissingAccessibleName(label, ariaLabel, ariaLabelledby);\n\n const bottomText = error && errorMessage ? errorMessage : helperText;\n\n return (\n <Popover.Root open={ac.isOpen && !disabled} onOpenChange={ac.handleOpenChange}>\n <div\n className={cn(\"flex flex-col\", fullWidth && \"w-full\", className)}\n data-autocomplete-root=\"\"\n data-disabled={disabled ? \"\" : undefined}\n data-error={error ? \"\" : undefined}\n >\n {label && (\n <label\n htmlFor={ac.inputId}\n className=\"typography-semibold-body-sm px-1 pt-1 pb-2 text-foreground-default\"\n >\n {label}\n </label>\n )}\n\n <Popover.Anchor asChild>\n {/* biome-ignore lint/a11y/noStaticElementInteractions: Container delegates click to the inner input */}\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: Keyboard interaction is handled by the inner combobox input */}\n <div\n className={cn(\n \"flex flex-wrap items-center overflow-hidden rounded-xl border bg-neutral-100 has-focus-visible:outline-none motion-safe:transition-colors\",\n error ? \"border-error-default\" : \"border-transparent\",\n !disabled && !error && \"hover:border-neutral-400\",\n ac.isOpen && !error && !disabled && \"border-neutral-400\",\n CONTAINER_HEIGHT[size],\n PADDING_CLASSES[size],\n disabled && \"opacity-50\",\n )}\n onClick={ac.handleContainerClick}\n >\n {leftIcon && (\n <div className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary\">\n {leftIcon}\n </div>\n )}\n\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n {ac.isMulti &&\n ac.selectedMultiOptions.map((opt) => (\n <AutocompleteTag\n key={opt.value}\n option={opt}\n disabled={disabled}\n onRemove={() => ac.toggleMulti(opt.value)}\n renderTag={renderTag}\n />\n ))}\n\n <input\n ref={ac.inputRef}\n id={ac.inputId}\n role=\"combobox\"\n type=\"text\"\n disabled={disabled}\n aria-expanded={ac.isOpen}\n aria-controls={ac.isOpen ? ac.listboxId : undefined}\n aria-activedescendant={ac.activeDescendantId}\n aria-autocomplete=\"list\"\n aria-describedby={bottomText ? ac.helperTextId : undefined}\n aria-invalid={error || undefined}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledby}\n autoComplete=\"off\"\n placeholder={\n ac.isMulti && ac.selectedMultiValues.length > 0 ? undefined : placeholder\n }\n value={ac.displayInputValue}\n onChange={ac.handleInputChange}\n onKeyDown={ac.handleKeyDown}\n onFocus={ac.handleFocus}\n onBlur={ac.handleBlur}\n className={cn(\n \"min-w-[40px] flex-1 truncate rounded-xl bg-transparent text-foreground-default no-underline placeholder:text-foreground-secondary placeholder:opacity-40 focus:outline-none disabled:cursor-not-allowed\",\n INPUT_SIZE_CLASSES[size],\n )}\n />\n </div>\n\n <div className=\"flex shrink-0 items-center gap-1\">\n {loading && <SpinnerIcon className=\"size-4 animate-spin text-foreground-secondary\" />}\n {clearable && ac.hasClearableValue && !disabled && (\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={clearAriaLabel}\n className=\"flex size-5 shrink-0 cursor-pointer items-center justify-center text-foreground-secondary hover:text-foreground-default active:scale-95\"\n onClick={ac.handleClear}\n >\n <CloseIcon className=\"size-4\" />\n </button>\n )}\n <div className=\"flex size-5 shrink-0 items-center justify-center text-foreground-secondary\">\n <ChevronDownIcon\n className={cn(\"size-5 transition-transform\", ac.isOpen && \"rotate-180\")}\n />\n </div>\n </div>\n </div>\n </Popover.Anchor>\n\n <Popover.Portal>\n <Popover.Content\n sideOffset={4}\n collisionPadding={8}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\" }}\n className={cn(\n \"w-(--radix-popover-trigger-width) min-w-(--radix-popper-anchor-width) overflow-hidden rounded-xl border border-neutral-200 bg-surface-page text-foreground-default shadow-[0_4px_16px_rgba(0,0,0,0.10)]\",\n \"data-[state=closed]:animate-out data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n \"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95\",\n \"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2\",\n )}\n >\n <div\n ref={ac.listRef}\n id={ac.listboxId}\n role=\"listbox\"\n aria-label={label ?? ariaLabel ?? \"Options\"}\n aria-multiselectable={ac.isMulti || undefined}\n className=\"max-h-60 overflow-y-auto p-1\"\n >\n <AutocompleteDropdownContent\n loading={loading}\n loadingText={loadingText}\n emptyText={emptyText}\n visibleOptions={ac.visibleOptions}\n listboxId={ac.listboxId}\n activeIndex={ac.activeIndex}\n isMulti={ac.isMulti}\n selectedMultiValues={ac.selectedMultiValues}\n selectedValue={ac.selectedValue}\n onSelect={ac.handleSelect}\n onMouseEnter={ac.setActiveIndex}\n renderOption={renderOption}\n />\n </div>\n </Popover.Content>\n </Popover.Portal>\n\n {bottomText && (\n <p\n id={ac.helperTextId}\n className={cn(\n \"typography-regular-body-sm px-2 pt-1 pb-0.5\",\n error ? \"text-error-default\" : \"text-foreground-secondary\",\n )}\n >\n {bottomText}\n </p>\n )}\n </div>\n </Popover.Root>\n );\n});\n\nAutocomplete.displayName = \"Autocomplete\";\n"],"names":["Popover"],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
import { cn } from "../../utils/cn.mjs";
|
|
6
|
+
import { Button } from "../Button/Button.mjs";
|
|
7
|
+
const InfoBox = PopoverPrimitive.Root;
|
|
8
|
+
const InfoBoxTrigger = PopoverPrimitive.Trigger;
|
|
9
|
+
const ACTION_CLASSES = {
|
|
10
|
+
brand: "hover:bg-brand-accent-default/80 hover:text-foreground-onaccent",
|
|
11
|
+
tertiary: "text-foreground-inverse hover:text-foreground-inverse hover:bg-foreground-inverse/10"
|
|
12
|
+
};
|
|
13
|
+
const ActionButton = ({
|
|
14
|
+
action,
|
|
15
|
+
variant
|
|
16
|
+
}) => "element" in action ? action.element : /* @__PURE__ */ jsx(Button, { variant, onClick: action.onClick, className: ACTION_CLASSES[variant], children: action.label });
|
|
17
|
+
const InfoBoxContent = React.forwardRef(
|
|
18
|
+
({
|
|
19
|
+
className,
|
|
20
|
+
showArrow = true,
|
|
21
|
+
sideOffset = 8,
|
|
22
|
+
heading,
|
|
23
|
+
icon,
|
|
24
|
+
pill,
|
|
25
|
+
primaryAction,
|
|
26
|
+
secondaryAction,
|
|
27
|
+
children,
|
|
28
|
+
style,
|
|
29
|
+
onOpenAutoFocus,
|
|
30
|
+
...props
|
|
31
|
+
}, ref) => {
|
|
32
|
+
const hasHeader = icon !== void 0 || heading !== void 0 || pill !== void 0;
|
|
33
|
+
const hasActions = primaryAction !== void 0 || secondaryAction !== void 0;
|
|
34
|
+
const headingId = React.useId();
|
|
35
|
+
return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
36
|
+
PopoverPrimitive.Content,
|
|
37
|
+
{
|
|
38
|
+
ref,
|
|
39
|
+
sideOffset,
|
|
40
|
+
collisionPadding: 8,
|
|
41
|
+
style: { zIndex: "var(--fanvue-ui-portal-z-index, 50)", ...style },
|
|
42
|
+
className: cn(
|
|
43
|
+
"typography-regular-body-md max-w-[280px] overflow-hidden rounded-2xl border border-neutral-200 bg-surface-pageinverse p-4 text-foreground-inverse shadow-[0px_2px_4px_0px_rgba(17,24,39,0.08)]",
|
|
44
|
+
className
|
|
45
|
+
),
|
|
46
|
+
align: "center",
|
|
47
|
+
"aria-labelledby": heading ? headingId : void 0,
|
|
48
|
+
arrowPadding: 12,
|
|
49
|
+
onOpenAutoFocus: (e) => {
|
|
50
|
+
e.preventDefault();
|
|
51
|
+
onOpenAutoFocus?.(e);
|
|
52
|
+
},
|
|
53
|
+
...props,
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
56
|
+
hasHeader && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
57
|
+
icon && /* @__PURE__ */ jsx("div", { className: "size-5 shrink-0", children: icon }),
|
|
58
|
+
heading && /* @__PURE__ */ jsx(
|
|
59
|
+
"p",
|
|
60
|
+
{
|
|
61
|
+
id: headingId,
|
|
62
|
+
className: "typography-semibold-body-lg min-w-0 flex-1 text-foreground-inverse",
|
|
63
|
+
children: heading
|
|
64
|
+
}
|
|
65
|
+
),
|
|
66
|
+
pill && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: pill })
|
|
67
|
+
] }),
|
|
68
|
+
children && /* @__PURE__ */ jsx("div", { className: "typography-regular-body-md text-foreground-inverse", children }),
|
|
69
|
+
hasActions && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
70
|
+
primaryAction && /* @__PURE__ */ jsx(ActionButton, { action: primaryAction, variant: "brand" }),
|
|
71
|
+
secondaryAction && /* @__PURE__ */ jsx(ActionButton, { action: secondaryAction, variant: "tertiary" })
|
|
72
|
+
] })
|
|
73
|
+
] }),
|
|
74
|
+
showArrow && /* @__PURE__ */ jsx(
|
|
75
|
+
PopoverPrimitive.Arrow,
|
|
76
|
+
{
|
|
77
|
+
className: "-translate-y-px! fill-surface-pageinverse stroke-2 stroke-surface-pageinverse",
|
|
78
|
+
width: 12,
|
|
79
|
+
height: 6
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
) });
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
InfoBoxContent.displayName = "InfoBoxContent";
|
|
88
|
+
export {
|
|
89
|
+
InfoBox,
|
|
90
|
+
InfoBoxContent,
|
|
91
|
+
InfoBoxTrigger
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=InfoBox.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InfoBox.mjs","sources":["../../../src/components/InfoBox/InfoBox.tsx"],"sourcesContent":["import * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../Button/Button\";\n\n/** Props for the {@link InfoBox} root component. */\nexport interface InfoBoxProps extends React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Root> {\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for an info box. */\nexport const InfoBox = PopoverPrimitive.Root;\n\n/** Props for the {@link InfoBoxTrigger} component. */\nexport type InfoBoxTriggerProps = React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Trigger>;\n\n/** The element that triggers the info box on click. */\nexport const InfoBoxTrigger = PopoverPrimitive.Trigger;\n\n/** Action button with a label and click handler. */\ninterface InfoBoxButtonAction {\n label: string;\n onClick?: () => void;\n}\n\n/** Custom element rendered in place of the default action button. */\ninterface InfoBoxElementAction {\n element: React.ReactNode;\n}\n\n/** Action configuration for {@link InfoBoxContent}. */\nexport type InfoBoxAction = InfoBoxButtonAction | InfoBoxElementAction;\n\nexport interface InfoBoxContentProps\n extends React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> {\n /** Whether to show the directional arrow pointer. @default true */\n showArrow?: boolean;\n /** Heading text rendered at the top of the info box. */\n heading?: React.ReactNode;\n /** Icon element displayed to the left of the heading. */\n icon?: React.ReactNode;\n /** Pill or badge element displayed to the right of the heading. */\n pill?: React.ReactNode;\n /** Primary action button (brand green). */\n primaryAction?: InfoBoxAction;\n /** Secondary action button (ghost). */\n secondaryAction?: InfoBoxAction;\n}\n\nconst ACTION_CLASSES: Record<\"brand\" | \"tertiary\", string> = {\n brand: \"hover:bg-brand-accent-default/80 hover:text-foreground-onaccent\",\n tertiary: \"text-foreground-inverse hover:text-foreground-inverse hover:bg-foreground-inverse/10\",\n};\n\nconst ActionButton = ({\n action,\n variant,\n}: {\n action: InfoBoxAction;\n variant: \"brand\" | \"tertiary\";\n}) =>\n \"element\" in action ? (\n action.element\n ) : (\n <Button variant={variant} onClick={action.onClick} className={ACTION_CLASSES[variant]}>\n {action.label}\n </Button>\n );\n\nexport const InfoBoxContent = React.forwardRef<\n React.ComponentRef<typeof PopoverPrimitive.Content>,\n InfoBoxContentProps\n>(\n (\n {\n className,\n showArrow = true,\n sideOffset = 8,\n heading,\n icon,\n pill,\n primaryAction,\n secondaryAction,\n children,\n style,\n onOpenAutoFocus,\n ...props\n },\n ref,\n ) => {\n const hasHeader = icon !== undefined || heading !== undefined || pill !== undefined;\n const hasActions = primaryAction !== undefined || secondaryAction !== undefined;\n const headingId = React.useId();\n\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n collisionPadding={8}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"typography-regular-body-md max-w-[280px] overflow-hidden rounded-2xl border border-neutral-200 bg-surface-pageinverse p-4 text-foreground-inverse shadow-[0px_2px_4px_0px_rgba(17,24,39,0.08)]\",\n className,\n )}\n align=\"center\"\n aria-labelledby={heading ? headingId : undefined}\n arrowPadding={12}\n onOpenAutoFocus={(e) => {\n // Prevent auto-focus stealing when opening — content is supplementary, not a dialog.\n e.preventDefault();\n onOpenAutoFocus?.(e);\n }}\n {...props}\n >\n <div className=\"flex flex-col gap-3\">\n {hasHeader && (\n <div className=\"flex items-center gap-3\">\n {icon && <div className=\"size-5 shrink-0\">{icon}</div>}\n {heading && (\n <p\n id={headingId}\n className=\"typography-semibold-body-lg min-w-0 flex-1 text-foreground-inverse\"\n >\n {heading}\n </p>\n )}\n {pill && <div className=\"shrink-0\">{pill}</div>}\n </div>\n )}\n {children && (\n <div className=\"typography-regular-body-md text-foreground-inverse\">{children}</div>\n )}\n {hasActions && (\n <div className=\"flex items-center gap-1\">\n {primaryAction && <ActionButton action={primaryAction} variant=\"brand\" />}\n {secondaryAction && <ActionButton action={secondaryAction} variant=\"tertiary\" />}\n </div>\n )}\n </div>\n {showArrow && (\n <PopoverPrimitive.Arrow\n className={\n \"-translate-y-px! fill-surface-pageinverse stroke-2 stroke-surface-pageinverse\"\n }\n width={12}\n height={6}\n />\n )}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n );\n },\n);\nInfoBoxContent.displayName = \"InfoBoxContent\";\n"],"names":[],"mappings":";;;;;;AAaO,MAAM,UAAU,iBAAiB;AAMjC,MAAM,iBAAiB,iBAAiB;AAgC/C,MAAM,iBAAuD;AAAA,EAC3D,OAAO;AAAA,EACP,UAAU;AACZ;AAEA,MAAM,eAAe,CAAC;AAAA,EACpB;AAAA,EACA;AACF,MAIE,aAAa,SACX,OAAO,8BAEN,QAAA,EAAO,SAAkB,SAAS,OAAO,SAAS,WAAW,eAAe,OAAO,GACjF,iBAAO,OACV;AAGG,MAAM,iBAAiB,MAAM;AAAA,EAIlC,CACE;AAAA,IACE;AAAA,IACA,YAAY;AAAA,IACZ,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,YAAY,SAAS,UAAa,YAAY,UAAa,SAAS;AAC1E,UAAM,aAAa,kBAAkB,UAAa,oBAAoB;AACtE,UAAM,YAAY,MAAM,MAAA;AAExB,WACE,oBAAC,iBAAiB,QAAjB,EACC,UAAA;AAAA,MAAC,iBAAiB;AAAA,MAAjB;AAAA,QACC;AAAA,QACA;AAAA,QACA,kBAAkB;AAAA,QAClB,OAAO,EAAE,QAAQ,uCAAuC,GAAG,MAAA;AAAA,QAC3D,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QAAA;AAAA,QAEF,OAAM;AAAA,QACN,mBAAiB,UAAU,YAAY;AAAA,QACvC,cAAc;AAAA,QACd,iBAAiB,CAAC,MAAM;AAEtB,YAAE,eAAA;AACF,4BAAkB,CAAC;AAAA,QACrB;AAAA,QACC,GAAG;AAAA,QAEJ,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,uBACZ,UAAA;AAAA,YAAA,aACC,qBAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,cAAA,QAAQ,oBAAC,OAAA,EAAI,WAAU,mBAAmB,UAAA,MAAK;AAAA,cAC/C,WACC;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,IAAI;AAAA,kBACJ,WAAU;AAAA,kBAET,UAAA;AAAA,gBAAA;AAAA,cAAA;AAAA,cAGJ,QAAQ,oBAAC,OAAA,EAAI,WAAU,YAAY,UAAA,KAAA,CAAK;AAAA,YAAA,GAC3C;AAAA,YAED,YACC,oBAAC,OAAA,EAAI,WAAU,sDAAsD,UAAS;AAAA,YAE/E,cACC,qBAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,cAAA,iBAAiB,oBAAC,cAAA,EAAa,QAAQ,eAAe,SAAQ,SAAQ;AAAA,cACtE,mBAAmB,oBAAC,cAAA,EAAa,QAAQ,iBAAiB,SAAQ,WAAA,CAAW;AAAA,YAAA,EAAA,CAChF;AAAA,UAAA,GAEJ;AAAA,UACC,aACC;AAAA,YAAC,iBAAiB;AAAA,YAAjB;AAAA,cACC,WACE;AAAA,cAEF,OAAO;AAAA,cACP,QAAQ;AAAA,YAAA;AAAA,UAAA;AAAA,QACV;AAAA,MAAA;AAAA,IAAA,GAGN;AAAA,EAEJ;AACF;AACA,eAAe,cAAc;"}
|
|
@@ -1,103 +1,28 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { cn } from "../../utils/cn.mjs";
|
|
6
|
-
import { Button } from "../Button/Button.mjs";
|
|
7
6
|
const TooltipProvider = TooltipPrimitive.Provider;
|
|
8
7
|
const Tooltip = TooltipPrimitive.Root;
|
|
9
8
|
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
28
|
-
hasHeader && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
29
|
-
icon && /* @__PURE__ */ jsx("div", { className: "size-5 shrink-0", children: icon }),
|
|
30
|
-
heading && /* @__PURE__ */ jsx("p", { className: "typography-semibold-body-lg min-w-0 flex-1 text-foreground-inverse", children: heading }),
|
|
31
|
-
pill && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: pill })
|
|
32
|
-
] }),
|
|
33
|
-
children && /* @__PURE__ */ jsx("div", { className: "typography-regular-body-md text-foreground-inverse", children }),
|
|
34
|
-
hasActions && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
35
|
-
primaryAction && /* @__PURE__ */ jsx(ActionButton, { action: primaryAction, variant: "brand" }),
|
|
36
|
-
secondaryAction && /* @__PURE__ */ jsx(ActionButton, { action: secondaryAction, variant: "tertiary" })
|
|
37
|
-
] })
|
|
38
|
-
] });
|
|
39
|
-
const TooltipContent = React.forwardRef(
|
|
40
|
-
({
|
|
41
|
-
className,
|
|
42
|
-
variant = "tooltip",
|
|
43
|
-
showArrow = true,
|
|
44
|
-
sideOffset = 8,
|
|
45
|
-
heading,
|
|
46
|
-
icon,
|
|
47
|
-
pill,
|
|
48
|
-
primaryAction,
|
|
49
|
-
secondaryAction,
|
|
50
|
-
children,
|
|
51
|
-
side,
|
|
52
|
-
style,
|
|
53
|
-
...props
|
|
54
|
-
}, ref) => {
|
|
55
|
-
const isInfobox = variant === "infobox";
|
|
56
|
-
const hasHeader = isInfobox && (icon !== void 0 || heading !== void 0 || pill !== void 0);
|
|
57
|
-
const hasActions = isInfobox && (primaryAction !== void 0 || secondaryAction !== void 0);
|
|
58
|
-
return /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
59
|
-
TooltipPrimitive.Content,
|
|
60
|
-
{
|
|
61
|
-
ref,
|
|
62
|
-
sideOffset,
|
|
63
|
-
collisionPadding: 8,
|
|
64
|
-
style: { zIndex: "var(--fanvue-ui-portal-z-index, 50)", ...style },
|
|
65
|
-
className: cn(
|
|
66
|
-
"typography-regular-body-md max-h-[var(--radix-tooltip-content-available-height)] max-w-[320px] overflow-hidden rounded-3xl bg-surface-pageinverse p-4 text-foreground-inverse shadow-[0px_2px_4px_0px_rgba(17,24,39,0.08)]",
|
|
67
|
-
isInfobox && "border border-neutral-200",
|
|
68
|
-
className
|
|
69
|
-
),
|
|
70
|
-
align: "center",
|
|
71
|
-
arrowPadding: 12,
|
|
72
|
-
side,
|
|
73
|
-
...props,
|
|
74
|
-
children: [
|
|
75
|
-
isInfobox ? /* @__PURE__ */ jsx(
|
|
76
|
-
InfoboxContent,
|
|
77
|
-
{
|
|
78
|
-
icon,
|
|
79
|
-
heading,
|
|
80
|
-
pill,
|
|
81
|
-
primaryAction,
|
|
82
|
-
secondaryAction,
|
|
83
|
-
hasHeader,
|
|
84
|
-
hasActions,
|
|
85
|
-
children
|
|
86
|
-
}
|
|
87
|
-
) : children,
|
|
88
|
-
showArrow && /* @__PURE__ */ jsx(
|
|
89
|
-
TooltipPrimitive.Arrow,
|
|
90
|
-
{
|
|
91
|
-
className: "-translate-y-px! fill-surface-pageinverse stroke-2 stroke-surface-pageinverse",
|
|
92
|
-
width: 12,
|
|
93
|
-
height: 6
|
|
94
|
-
}
|
|
95
|
-
)
|
|
96
|
-
]
|
|
97
|
-
}
|
|
98
|
-
) });
|
|
99
|
-
}
|
|
100
|
-
);
|
|
9
|
+
const TooltipContent = React.forwardRef(({ className, sideOffset = 8, style, ...props }, ref) => {
|
|
10
|
+
return /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
11
|
+
TooltipPrimitive.Content,
|
|
12
|
+
{
|
|
13
|
+
ref,
|
|
14
|
+
sideOffset,
|
|
15
|
+
collisionPadding: 8,
|
|
16
|
+
style: { zIndex: "var(--fanvue-ui-portal-z-index, 50)", ...style },
|
|
17
|
+
className: cn(
|
|
18
|
+
"typography-semibold-body-sm max-w-[320px] rounded-full bg-surface-pageinverse px-4 py-2 text-foreground-inverse shadow-[0px_1px_4px_0px_rgba(0,0,0,0.06),0px_1px_3px_0px_rgba(0,0,0,0.05)]",
|
|
19
|
+
className
|
|
20
|
+
),
|
|
21
|
+
align: "center",
|
|
22
|
+
...props
|
|
23
|
+
}
|
|
24
|
+
) });
|
|
25
|
+
});
|
|
101
26
|
TooltipContent.displayName = "TooltipContent";
|
|
102
27
|
export {
|
|
103
28
|
Tooltip,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tooltip.mjs","sources":["../../../src/components/Tooltip/Tooltip.tsx"],"sourcesContent":["import * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../Button/Button\";\n\n/** Props for the {@link TooltipProvider}. Wraps Radix `Tooltip.Provider`. */\nexport type TooltipProviderProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Provider>;\n\n/** Provides tooltip delay and skip-delay context. Wrap your app or a subtree. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\n/** Props for the {@link Tooltip} root component. */\nexport interface TooltipProps extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root> {\n /**\n * Controlled open state. When provided, the component is in controlled mode\n * and you must also supply `onOpenChange` to update the value.\n */\n open?: boolean;\n /** Called when the open state changes. Required when `open` is controlled. */\n onOpenChange?: (open: boolean) => void;\n /** The open state of the tooltip when it is initially rendered (uncontrolled). */\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for a single tooltip. */\nexport const Tooltip = TooltipPrimitive.Root;\n\n/** Props for the {@link TooltipTrigger} component. */\nexport type TooltipTriggerProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger>;\n\n/** The element that triggers the tooltip on hover/focus. */\nexport const TooltipTrigger = TooltipPrimitive.Trigger;\n\n/**\n * Visual style variant of the tooltip content.\n *\n * - `\"tooltip\"` — simple text bubble, no border.\n * - `\"infobox\"` — richer card with a visible border, structured header, body text, and optional actions.\n */\nexport type TooltipContentVariant = \"tooltip\" | \"infobox\";\n\n/** Action button configuration for the infobox variant of {@link TooltipContent}. */\nexport interface TooltipAction {\n /** Button label. */\n label: string;\n /** Click handler. */\n onClick?: () => void;\n /**\n * Optional custom React node to be rendered for the action instead of the default button.\n * Only used in the infobox variant.\n */\n element?: React.ReactNode;\n}\n\nexport interface TooltipContentProps\n extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> {\n /**\n * Visual style variant.\n *\n * `\"tooltip\"` is a lightweight text bubble. `\"infobox\"` renders a structured card\n * with optional heading, icon, pill, body text, and action buttons.\n *\n * @default \"tooltip\"\n */\n variant?: TooltipContentVariant;\n /** Whether to show the directional arrow pointer. @default true */\n showArrow?: boolean;\n /**\n * Heading text rendered in subtitle style at the top of the infobox.\n * Infobox variant only.\n */\n heading?: React.ReactNode;\n /**\n * Icon element displayed to the left of the heading.\n * Infobox variant only.\n */\n icon?: React.ReactNode;\n /**\n * Pill or badge element displayed to the right of the heading.\n * Infobox variant only.\n */\n pill?: React.ReactNode;\n /**\n * Primary action button (brand green). Rendered below the body text.\n * Infobox variant only.\n */\n primaryAction?: TooltipAction;\n /**\n * Secondary action button (ghost). Rendered next to the primary action.\n * Infobox variant only.\n */\n secondaryAction?: TooltipAction;\n}\n\n/** Class overrides so CTA buttons render correctly on the tooltip's inverted background. */\nconst TOOLTIP_ACTION_CLASSES: Record<\"brand\" | \"tertiary\", string> = {\n brand: \"hover:bg-brand-accent-default/80 hover:text-foreground-onaccent\",\n tertiary: \"text-foreground-inverse hover:text-foreground-inverse hover:bg-foreground-inverse/10\",\n};\n\nconst ActionButton = ({\n action,\n variant,\n}: {\n action: TooltipAction;\n variant: \"brand\" | \"tertiary\";\n}) =>\n action.element ? (\n action.element\n ) : (\n <Button variant={variant} onClick={action.onClick} className={TOOLTIP_ACTION_CLASSES[variant]}>\n {action.label}\n </Button>\n );\n\nconst InfoboxContent = ({\n icon,\n heading,\n pill,\n children,\n primaryAction,\n secondaryAction,\n hasHeader,\n hasActions,\n}: {\n icon?: React.ReactNode;\n heading?: React.ReactNode;\n pill?: React.ReactNode;\n children?: React.ReactNode;\n primaryAction?: TooltipAction;\n secondaryAction?: TooltipAction;\n hasHeader: boolean;\n hasActions: boolean;\n}) => (\n <div className=\"flex flex-col gap-3\">\n {hasHeader && (\n <div className=\"flex items-center gap-3\">\n {icon && <div className=\"size-5 shrink-0\">{icon}</div>}\n {heading && (\n <p className=\"typography-semibold-body-lg min-w-0 flex-1 text-foreground-inverse\">\n {heading}\n </p>\n )}\n {pill && <div className=\"shrink-0\">{pill}</div>}\n </div>\n )}\n {children && (\n <div className=\"typography-regular-body-md text-foreground-inverse\">{children}</div>\n )}\n {hasActions && (\n <div className=\"flex items-center gap-1\">\n {primaryAction && <ActionButton action={primaryAction} variant=\"brand\" />}\n {secondaryAction && <ActionButton action={secondaryAction} variant=\"tertiary\" />}\n </div>\n )}\n </div>\n);\n\n/**\n * The popup content of the tooltip. Renders inside a portal.\n *\n * Arrow direction is controlled via the `side` and `align` props (Radix passthrough).\n *\n * @example\n * ```tsx\n * // Simple tooltip\n * <TooltipContent>Info text</TooltipContent>\n *\n * // Infobox with structured content\n * <TooltipContent\n * variant=\"infobox\"\n * heading=\"Title\"\n * icon={<InfoCircleIcon className=\"size-5\" />}\n * primaryAction={{ label: \"OK\", onClick: () => {} }}\n * secondaryAction={{ label: \"Dismiss\" }}\n * >\n * Info text\n * </TooltipContent>\n * ```\n */\nexport const TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n TooltipContentProps\n>(\n (\n {\n className,\n variant = \"tooltip\",\n showArrow = true,\n sideOffset = 8,\n heading,\n icon,\n pill,\n primaryAction,\n secondaryAction,\n children,\n side,\n style,\n ...props\n },\n ref,\n ) => {\n const isInfobox = variant === \"infobox\";\n const hasHeader =\n isInfobox && (icon !== undefined || heading !== undefined || pill !== undefined);\n const hasActions = isInfobox && (primaryAction !== undefined || secondaryAction !== undefined);\n\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n collisionPadding={8}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"typography-regular-body-md max-h-[var(--radix-tooltip-content-available-height)] max-w-[320px] overflow-hidden rounded-3xl bg-surface-pageinverse p-4 text-foreground-inverse shadow-[0px_2px_4px_0px_rgba(17,24,39,0.08)]\",\n isInfobox && \"border border-neutral-200\",\n className,\n )}\n align=\"center\"\n arrowPadding={12}\n side={side}\n {...props}\n >\n {isInfobox ? (\n <InfoboxContent\n icon={icon}\n heading={heading}\n pill={pill}\n primaryAction={primaryAction}\n secondaryAction={secondaryAction}\n hasHeader={hasHeader}\n hasActions={hasActions}\n >\n {children}\n </InfoboxContent>\n ) : (\n children\n )}\n {showArrow && (\n <TooltipPrimitive.Arrow\n className={\n \"-translate-y-px! fill-surface-pageinverse stroke-2 stroke-surface-pageinverse\"\n }\n width={12}\n height={6}\n />\n )}\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n );\n },\n);\nTooltipContent.displayName = \"TooltipContent\";\n"],"names":[],"mappings":";;;;;;AASO,MAAM,kBAAkB,iBAAiB;AAgBzC,MAAM,UAAU,iBAAiB;AAMjC,MAAM,iBAAiB,iBAAiB;AAgE/C,MAAM,yBAA+D;AAAA,EACnE,OAAO;AAAA,EACP,UAAU;AACZ;AAEA,MAAM,eAAe,CAAC;AAAA,EACpB;AAAA,EACA;AACF,MAIE,OAAO,UACL,OAAO,8BAEN,QAAA,EAAO,SAAkB,SAAS,OAAO,SAAS,WAAW,uBAAuB,OAAO,GACzF,iBAAO,OACV;AAGJ,MAAM,iBAAiB,CAAC;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAUE,qBAAC,OAAA,EAAI,WAAU,uBACZ,UAAA;AAAA,EAAA,aACC,qBAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,IAAA,QAAQ,oBAAC,OAAA,EAAI,WAAU,mBAAmB,UAAA,MAAK;AAAA,IAC/C,WACC,oBAAC,KAAA,EAAE,WAAU,sEACV,UAAA,SACH;AAAA,IAED,QAAQ,oBAAC,OAAA,EAAI,WAAU,YAAY,UAAA,KAAA,CAAK;AAAA,EAAA,GAC3C;AAAA,EAED,YACC,oBAAC,OAAA,EAAI,WAAU,sDAAsD,UAAS;AAAA,EAE/E,cACC,qBAAC,OAAA,EAAI,WAAU,2BACZ,UAAA;AAAA,IAAA,iBAAiB,oBAAC,cAAA,EAAa,QAAQ,eAAe,SAAQ,SAAQ;AAAA,IACtE,mBAAmB,oBAAC,cAAA,EAAa,QAAQ,iBAAiB,SAAQ,WAAA,CAAW;AAAA,EAAA,EAAA,CAChF;AAAA,GAEJ;AAyBK,MAAM,iBAAiB,MAAM;AAAA,EAIlC,CACE;AAAA,IACE;AAAA,IACA,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AACH,UAAM,YAAY,YAAY;AAC9B,UAAM,YACJ,cAAc,SAAS,UAAa,YAAY,UAAa,SAAS;AACxE,UAAM,aAAa,cAAc,kBAAkB,UAAa,oBAAoB;AAEpF,WACE,oBAAC,iBAAiB,QAAjB,EACC,UAAA;AAAA,MAAC,iBAAiB;AAAA,MAAjB;AAAA,QACC;AAAA,QACA;AAAA,QACA,kBAAkB;AAAA,QAClB,OAAO,EAAE,QAAQ,uCAAuC,GAAG,MAAA;AAAA,QAC3D,WAAW;AAAA,UACT;AAAA,UACA,aAAa;AAAA,UACb;AAAA,QAAA;AAAA,QAEF,OAAM;AAAA,QACN,cAAc;AAAA,QACd;AAAA,QACC,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,YACC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cAEC;AAAA,YAAA;AAAA,UAAA,IAGH;AAAA,UAED,aACC;AAAA,YAAC,iBAAiB;AAAA,YAAjB;AAAA,cACC,WACE;AAAA,cAEF,OAAO;AAAA,cACP,QAAQ;AAAA,YAAA;AAAA,UAAA;AAAA,QACV;AAAA,MAAA;AAAA,IAAA,GAGN;AAAA,EAEJ;AACF;AACA,eAAe,cAAc;"}
|
|
1
|
+
{"version":3,"file":"Tooltip.mjs","sources":["../../../src/components/Tooltip/Tooltip.tsx"],"sourcesContent":["import * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\n/** Props for the {@link TooltipProvider}. Wraps Radix `Tooltip.Provider`. */\nexport type TooltipProviderProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Provider>;\n\n/** Provides tooltip delay and skip-delay context. Wrap your app or a subtree. */\nexport const TooltipProvider = TooltipPrimitive.Provider;\n\n/** Props for the {@link Tooltip} root component. */\nexport interface TooltipProps extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root> {\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n defaultOpen?: boolean;\n}\n\n/** Root component that manages open/close state for a single tooltip. */\nexport const Tooltip = TooltipPrimitive.Root;\n\n/** Props for the {@link TooltipTrigger} component. */\nexport type TooltipTriggerProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger>;\n\n/** The element that triggers the tooltip on hover/focus. */\nexport const TooltipTrigger = TooltipPrimitive.Trigger;\n\nexport type TooltipContentProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>;\n\nexport const TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n TooltipContentProps\n>(({ className, sideOffset = 8, style, ...props }, ref) => {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n collisionPadding={8}\n style={{ zIndex: \"var(--fanvue-ui-portal-z-index, 50)\", ...style }}\n className={cn(\n \"typography-semibold-body-sm max-w-[320px] rounded-full bg-surface-pageinverse px-4 py-2 text-foreground-inverse shadow-[0px_1px_4px_0px_rgba(0,0,0,0.06),0px_1px_3px_0px_rgba(0,0,0,0.05)]\",\n className,\n )}\n align=\"center\"\n {...props}\n />\n </TooltipPrimitive.Portal>\n );\n});\nTooltipContent.displayName = \"TooltipContent\";\n"],"names":[],"mappings":";;;;;AAQO,MAAM,kBAAkB,iBAAiB;AAUzC,MAAM,UAAU,iBAAiB;AAMjC,MAAM,iBAAiB,iBAAiB;AAIxC,MAAM,iBAAiB,MAAM,WAGlC,CAAC,EAAE,WAAW,aAAa,GAAG,OAAO,GAAG,MAAA,GAAS,QAAQ;AACzD,SACE,oBAAC,iBAAiB,QAAjB,EACC,UAAA;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC;AAAA,MACA;AAAA,MACA,kBAAkB;AAAA,MAClB,OAAO,EAAE,QAAQ,uCAAuC,GAAG,MAAA;AAAA,MAC3D,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAEF,OAAM;AAAA,MACL,GAAG;AAAA,IAAA;AAAA,EAAA,GAER;AAEJ,CAAC;AACD,eAAe,cAAc;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { ClassValue } from 'clsx';
|
|
|
5
5
|
import { default as default_2 } from 'react';
|
|
6
6
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
7
7
|
import { JSX } from 'react/jsx-runtime';
|
|
8
|
+
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
8
9
|
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
9
10
|
import * as React_2 from 'react';
|
|
10
11
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
@@ -1225,6 +1226,53 @@ export declare const InboxIcon: React_2.ForwardRefExoticComponent<React_2.SVGAtt
|
|
|
1225
1226
|
className?: string;
|
|
1226
1227
|
} & React_2.RefAttributes<SVGSVGElement>>;
|
|
1227
1228
|
|
|
1229
|
+
/** Root component that manages open/close state for an info box. */
|
|
1230
|
+
export declare const InfoBox: React_2.FC<PopoverPrimitive.PopoverProps>;
|
|
1231
|
+
|
|
1232
|
+
/** Action configuration for {@link InfoBoxContent}. */
|
|
1233
|
+
export declare type InfoBoxAction = InfoBoxButtonAction | InfoBoxElementAction;
|
|
1234
|
+
|
|
1235
|
+
/** Action button with a label and click handler. */
|
|
1236
|
+
declare interface InfoBoxButtonAction {
|
|
1237
|
+
label: string;
|
|
1238
|
+
onClick?: () => void;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
export declare const InfoBoxContent: React_2.ForwardRefExoticComponent<InfoBoxContentProps & React_2.RefAttributes<HTMLDivElement>>;
|
|
1242
|
+
|
|
1243
|
+
export declare interface InfoBoxContentProps extends React_2.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> {
|
|
1244
|
+
/** Whether to show the directional arrow pointer. @default true */
|
|
1245
|
+
showArrow?: boolean;
|
|
1246
|
+
/** Heading text rendered at the top of the info box. */
|
|
1247
|
+
heading?: React_2.ReactNode;
|
|
1248
|
+
/** Icon element displayed to the left of the heading. */
|
|
1249
|
+
icon?: React_2.ReactNode;
|
|
1250
|
+
/** Pill or badge element displayed to the right of the heading. */
|
|
1251
|
+
pill?: React_2.ReactNode;
|
|
1252
|
+
/** Primary action button (brand green). */
|
|
1253
|
+
primaryAction?: InfoBoxAction;
|
|
1254
|
+
/** Secondary action button (ghost). */
|
|
1255
|
+
secondaryAction?: InfoBoxAction;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
/** Custom element rendered in place of the default action button. */
|
|
1259
|
+
declare interface InfoBoxElementAction {
|
|
1260
|
+
element: React_2.ReactNode;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
/** Props for the {@link InfoBox} root component. */
|
|
1264
|
+
export declare interface InfoBoxProps extends React_2.ComponentPropsWithoutRef<typeof PopoverPrimitive.Root> {
|
|
1265
|
+
open?: boolean;
|
|
1266
|
+
onOpenChange?: (open: boolean) => void;
|
|
1267
|
+
defaultOpen?: boolean;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/** The element that triggers the info box on click. */
|
|
1271
|
+
export declare const InfoBoxTrigger: React_2.ForwardRefExoticComponent<PopoverPrimitive.PopoverTriggerProps & React_2.RefAttributes<HTMLButtonElement>>;
|
|
1272
|
+
|
|
1273
|
+
/** Props for the {@link InfoBoxTrigger} component. */
|
|
1274
|
+
export declare type InfoBoxTriggerProps = React_2.ComponentPropsWithoutRef<typeof PopoverPrimitive.Trigger>;
|
|
1275
|
+
|
|
1228
1276
|
/** An "i" inside a filled circle icon for informational tooltips (20 × 20). */
|
|
1229
1277
|
export declare const InfoCircleIcon: React_2.ForwardRefExoticComponent<React_2.SVGAttributes<SVGSVGElement> & {
|
|
1230
1278
|
className?: string;
|
|
@@ -2239,100 +2287,14 @@ export declare interface ToastViewportProps extends React_2.ComponentPropsWithou
|
|
|
2239
2287
|
/** Root component that manages open/close state for a single tooltip. */
|
|
2240
2288
|
export declare const Tooltip: React_2.FC<TooltipPrimitive.TooltipProps>;
|
|
2241
2289
|
|
|
2242
|
-
|
|
2243
|
-
export declare interface TooltipAction {
|
|
2244
|
-
/** Button label. */
|
|
2245
|
-
label: string;
|
|
2246
|
-
/** Click handler. */
|
|
2247
|
-
onClick?: () => void;
|
|
2248
|
-
/**
|
|
2249
|
-
* Optional custom React node to be rendered for the action instead of the default button.
|
|
2250
|
-
* Only used in the infobox variant.
|
|
2251
|
-
*/
|
|
2252
|
-
element?: React_2.ReactNode;
|
|
2253
|
-
}
|
|
2290
|
+
export declare const TooltipContent: React_2.ForwardRefExoticComponent<Omit<TooltipPrimitive.TooltipContentProps & React_2.RefAttributes<HTMLDivElement>, "ref"> & React_2.RefAttributes<HTMLDivElement>>;
|
|
2254
2291
|
|
|
2255
|
-
|
|
2256
|
-
* The popup content of the tooltip. Renders inside a portal.
|
|
2257
|
-
*
|
|
2258
|
-
* Arrow direction is controlled via the `side` and `align` props (Radix passthrough).
|
|
2259
|
-
*
|
|
2260
|
-
* @example
|
|
2261
|
-
* ```tsx
|
|
2262
|
-
* // Simple tooltip
|
|
2263
|
-
* <TooltipContent>Info text</TooltipContent>
|
|
2264
|
-
*
|
|
2265
|
-
* // Infobox with structured content
|
|
2266
|
-
* <TooltipContent
|
|
2267
|
-
* variant="infobox"
|
|
2268
|
-
* heading="Title"
|
|
2269
|
-
* icon={<InfoCircleIcon className="size-5" />}
|
|
2270
|
-
* primaryAction={{ label: "OK", onClick: () => {} }}
|
|
2271
|
-
* secondaryAction={{ label: "Dismiss" }}
|
|
2272
|
-
* >
|
|
2273
|
-
* Info text
|
|
2274
|
-
* </TooltipContent>
|
|
2275
|
-
* ```
|
|
2276
|
-
*/
|
|
2277
|
-
export declare const TooltipContent: React_2.ForwardRefExoticComponent<TooltipContentProps & React_2.RefAttributes<HTMLDivElement>>;
|
|
2278
|
-
|
|
2279
|
-
export declare interface TooltipContentProps extends React_2.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> {
|
|
2280
|
-
/**
|
|
2281
|
-
* Visual style variant.
|
|
2282
|
-
*
|
|
2283
|
-
* `"tooltip"` is a lightweight text bubble. `"infobox"` renders a structured card
|
|
2284
|
-
* with optional heading, icon, pill, body text, and action buttons.
|
|
2285
|
-
*
|
|
2286
|
-
* @default "tooltip"
|
|
2287
|
-
*/
|
|
2288
|
-
variant?: TooltipContentVariant;
|
|
2289
|
-
/** Whether to show the directional arrow pointer. @default true */
|
|
2290
|
-
showArrow?: boolean;
|
|
2291
|
-
/**
|
|
2292
|
-
* Heading text rendered in subtitle style at the top of the infobox.
|
|
2293
|
-
* Infobox variant only.
|
|
2294
|
-
*/
|
|
2295
|
-
heading?: React_2.ReactNode;
|
|
2296
|
-
/**
|
|
2297
|
-
* Icon element displayed to the left of the heading.
|
|
2298
|
-
* Infobox variant only.
|
|
2299
|
-
*/
|
|
2300
|
-
icon?: React_2.ReactNode;
|
|
2301
|
-
/**
|
|
2302
|
-
* Pill or badge element displayed to the right of the heading.
|
|
2303
|
-
* Infobox variant only.
|
|
2304
|
-
*/
|
|
2305
|
-
pill?: React_2.ReactNode;
|
|
2306
|
-
/**
|
|
2307
|
-
* Primary action button (brand green). Rendered below the body text.
|
|
2308
|
-
* Infobox variant only.
|
|
2309
|
-
*/
|
|
2310
|
-
primaryAction?: TooltipAction;
|
|
2311
|
-
/**
|
|
2312
|
-
* Secondary action button (ghost). Rendered next to the primary action.
|
|
2313
|
-
* Infobox variant only.
|
|
2314
|
-
*/
|
|
2315
|
-
secondaryAction?: TooltipAction;
|
|
2316
|
-
}
|
|
2317
|
-
|
|
2318
|
-
/**
|
|
2319
|
-
* Visual style variant of the tooltip content.
|
|
2320
|
-
*
|
|
2321
|
-
* - `"tooltip"` — simple text bubble, no border.
|
|
2322
|
-
* - `"infobox"` — richer card with a visible border, structured header, body text, and optional actions.
|
|
2323
|
-
*/
|
|
2324
|
-
export declare type TooltipContentVariant = "tooltip" | "infobox";
|
|
2292
|
+
export declare type TooltipContentProps = React_2.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>;
|
|
2325
2293
|
|
|
2326
2294
|
/** Props for the {@link Tooltip} root component. */
|
|
2327
2295
|
export declare interface TooltipProps extends React_2.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root> {
|
|
2328
|
-
/**
|
|
2329
|
-
* Controlled open state. When provided, the component is in controlled mode
|
|
2330
|
-
* and you must also supply `onOpenChange` to update the value.
|
|
2331
|
-
*/
|
|
2332
2296
|
open?: boolean;
|
|
2333
|
-
/** Called when the open state changes. Required when `open` is controlled. */
|
|
2334
2297
|
onOpenChange?: (open: boolean) => void;
|
|
2335
|
-
/** The open state of the tooltip when it is initially rendered (uncontrolled). */
|
|
2336
2298
|
defaultOpen?: boolean;
|
|
2337
2299
|
}
|
|
2338
2300
|
|
package/dist/index.mjs
CHANGED
|
@@ -139,6 +139,7 @@ import { WarningTriangleIcon } from "./components/Icons/WarningTriangleIcon.mjs"
|
|
|
139
139
|
import { WifiOffIcon } from "./components/Icons/WifiOffIcon.mjs";
|
|
140
140
|
import { WifiOnIcon } from "./components/Icons/WifiOnIcon.mjs";
|
|
141
141
|
import { WrenchIcon } from "./components/Icons/WrenchIcon.mjs";
|
|
142
|
+
import { InfoBox, InfoBoxContent, InfoBoxTrigger } from "./components/InfoBox/InfoBox.mjs";
|
|
142
143
|
import { Loader } from "./components/Loader/Loader.mjs";
|
|
143
144
|
import { Logo } from "./components/Logo/Logo.mjs";
|
|
144
145
|
import { MobileStepper } from "./components/MobileStepper/MobileStepper.mjs";
|
|
@@ -274,6 +275,9 @@ export {
|
|
|
274
275
|
IconButton,
|
|
275
276
|
ImageIcon,
|
|
276
277
|
InboxIcon,
|
|
278
|
+
InfoBox,
|
|
279
|
+
InfoBoxContent,
|
|
280
|
+
InfoBoxTrigger,
|
|
277
281
|
InfoCircleIcon,
|
|
278
282
|
InfoIcon,
|
|
279
283
|
LinkIcon,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|