h2o-library 2.0.0 → 2.1.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.
Files changed (77) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/charts/components/index.d.ts +2 -0
  3. package/dist/charts/components/src/button/button.d.ts +3 -0
  4. package/dist/charts/components/src/chip/chip.d.ts +4 -1
  5. package/dist/charts/components/src/content-switch/content-switch.d.ts +3 -0
  6. package/dist/charts/components/src/expandable-search/expandable-search.d.ts +40 -0
  7. package/dist/charts/components/src/input/input.d.ts +5 -0
  8. package/dist/charts/components/src/onboarding/onboarding.d.ts +100 -0
  9. package/dist/charts/components/src/radio-group/radio-group.d.ts +3 -0
  10. package/dist/charts/hooks/index.d.ts +1 -0
  11. package/dist/charts/hooks/src/use-onboarding.d.ts +66 -0
  12. package/dist/components/index.d.ts +2 -0
  13. package/dist/components/src/button/button.d.ts +3 -0
  14. package/dist/components/src/chip/chip.d.ts +4 -1
  15. package/dist/components/src/content-switch/content-switch.d.ts +3 -0
  16. package/dist/components/src/expandable-search/expandable-search.d.ts +40 -0
  17. package/dist/components/src/input/input.d.ts +5 -0
  18. package/dist/components/src/onboarding/onboarding.d.ts +100 -0
  19. package/dist/components/src/radio-group/radio-group.d.ts +3 -0
  20. package/dist/esm/components/index.d.ts +2 -0
  21. package/dist/esm/components/src/button/button.d.ts +3 -0
  22. package/dist/esm/components/src/button/button.js +1 -1
  23. package/dist/esm/components/src/chip/chip.d.ts +4 -1
  24. package/dist/esm/components/src/chip/chip.js +1 -1
  25. package/dist/esm/components/src/content-switch/content-switch.d.ts +3 -0
  26. package/dist/esm/components/src/content-switch/content-switch.js +1 -1
  27. package/dist/esm/components/src/expandable-search/expandable-search.css +120 -0
  28. package/dist/esm/components/src/expandable-search/expandable-search.d.ts +40 -0
  29. package/dist/esm/components/src/expandable-search/expandable-search.js +2 -0
  30. package/dist/esm/components/src/input/input.d.ts +5 -0
  31. package/dist/esm/components/src/input/input.js +1 -1
  32. package/dist/esm/components/src/modal/modal.js +1 -1
  33. package/dist/esm/components/src/onboarding/onboarding.css +178 -0
  34. package/dist/esm/components/src/onboarding/onboarding.d.ts +100 -0
  35. package/dist/esm/components/src/onboarding/onboarding.js +2 -0
  36. package/dist/esm/components/src/radio-group/radio-group.d.ts +3 -0
  37. package/dist/esm/components/src/radio-group/radio-group.js +1 -1
  38. package/dist/esm/hooks/index.d.ts +1 -0
  39. package/dist/esm/hooks/src/use-onboarding.d.ts +66 -0
  40. package/dist/esm/hooks/src/use-onboarding.js +2 -0
  41. package/dist/esm/index.js +1 -1
  42. package/dist/hooks/components/index.d.ts +2 -0
  43. package/dist/hooks/components/src/button/button.d.ts +3 -0
  44. package/dist/hooks/components/src/chip/chip.d.ts +4 -1
  45. package/dist/hooks/components/src/content-switch/content-switch.d.ts +3 -0
  46. package/dist/hooks/components/src/expandable-search/expandable-search.d.ts +40 -0
  47. package/dist/hooks/components/src/input/input.d.ts +5 -0
  48. package/dist/hooks/components/src/onboarding/onboarding.d.ts +100 -0
  49. package/dist/hooks/components/src/radio-group/radio-group.d.ts +3 -0
  50. package/dist/hooks/hooks/index.d.ts +1 -0
  51. package/dist/hooks/hooks/src/use-onboarding.d.ts +66 -0
  52. package/dist/hooks/index.cjs.js +1 -1
  53. package/dist/hooks/index.js +1 -1
  54. package/dist/hooks/src/use-onboarding.d.ts +66 -0
  55. package/dist/index.cjs.js +1 -1
  56. package/dist/index.css +1 -1
  57. package/dist/types/components/index.d.ts +2 -0
  58. package/dist/types/components/src/button/button.d.ts +3 -0
  59. package/dist/types/components/src/chip/chip.d.ts +4 -1
  60. package/dist/types/components/src/content-switch/content-switch.d.ts +3 -0
  61. package/dist/types/components/src/expandable-search/expandable-search.d.ts +40 -0
  62. package/dist/types/components/src/input/input.d.ts +5 -0
  63. package/dist/types/components/src/onboarding/onboarding.d.ts +100 -0
  64. package/dist/types/components/src/radio-group/radio-group.d.ts +3 -0
  65. package/dist/types/hooks/index.d.ts +1 -0
  66. package/dist/types/hooks/src/use-onboarding.d.ts +66 -0
  67. package/dist/utils/components/index.d.ts +2 -0
  68. package/dist/utils/components/src/button/button.d.ts +3 -0
  69. package/dist/utils/components/src/chip/chip.d.ts +4 -1
  70. package/dist/utils/components/src/content-switch/content-switch.d.ts +3 -0
  71. package/dist/utils/components/src/expandable-search/expandable-search.d.ts +40 -0
  72. package/dist/utils/components/src/input/input.d.ts +5 -0
  73. package/dist/utils/components/src/onboarding/onboarding.d.ts +100 -0
  74. package/dist/utils/components/src/radio-group/radio-group.d.ts +3 -0
  75. package/dist/utils/hooks/index.d.ts +1 -0
  76. package/dist/utils/hooks/src/use-onboarding.d.ts +66 -0
  77. package/package.json +7 -2
@@ -1,16 +1,19 @@
1
1
  import "./radio-group.css";
2
+ import { Icon } from "../icon/icon";
2
3
  import type { IconType, TooltipPosition } from "../../../types";
3
4
  /**
4
5
  * One entry in a `RadioGroup` `options` array.
5
6
  * @property {string} label - Option title.
6
7
  * @property {string} value - Emitted to `onChange` when selected.
7
8
  * @property {import("../../../types").IconType} [icon] - Optional leading icon.
9
+ * @property {Omit<React.ComponentProps<typeof Icon>, "icon">} [iconProps] - Extra props forwarded to the built-in `Icon` (and its `<svg>`).
8
10
  * @property {"active"|"inactive"} [dot] - Optional status dot style when no icon.
9
11
  */
10
12
  export interface RadioOption {
11
13
  label: string;
12
14
  value: string;
13
15
  icon?: IconType;
16
+ iconProps?: Omit<React.ComponentProps<typeof Icon>, "icon">;
14
17
  dot?: "active" | "inactive";
15
18
  disabled?: boolean;
16
19
  tooltip?: string;
@@ -34,3 +34,5 @@ export * from "./src/segmented-toggle/segmented-toggle";
34
34
  export * from "./src/skeleton/skeleton";
35
35
  export * from "./src/date-picker/date-picker";
36
36
  export * from "./src/time-picker/time-picker";
37
+ export * from "./src/expandable-search/expandable-search";
38
+ export * from "./src/onboarding/onboarding";
@@ -1,5 +1,6 @@
1
1
  import "./button.css";
2
2
  import type { IconType, TooltipPosition } from "../../../types";
3
+ import { Icon } from "../icon/icon";
3
4
  import React from "react";
4
5
  /**
5
6
  * Extends native `HTMLButtonElement` attributes
@@ -11,6 +12,7 @@ import React from "react";
11
12
  * @property {"left"|"right"} [iconPosition] - Icon position relative to the label. Default `"right"`.
12
13
  * @property {boolean} [iconOnly] - Icon without visible text.
13
14
  * @property {number} [iconStrokeWidth] - SVG stroke width for the icon. Default `1.5`.
15
+ * @property {Omit<React.ComponentProps<typeof Icon>, "icon">} [iconProps] - Extra props forwarded to the built-in `Icon` (and its `<svg>`); overrides defaults like `size`/`strokeWidth`.
14
16
  * @property {boolean} [isLoading] - Shows a spinner and disables the button. Default `false`.
15
17
  * @property {boolean} [fullWidth] - Stretches to 100% width of the container. Default `false`.
16
18
  * @property {string} [tooltip] - If set, wraps the button in a `Tooltip` with this text.
@@ -22,6 +24,7 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
22
24
  label?: string;
23
25
  iconStrokeWidth?: number;
24
26
  icon?: IconType;
27
+ iconProps?: Omit<React.ComponentProps<typeof Icon>, "icon">;
25
28
  iconPosition?: "left" | "right";
26
29
  iconOnly?: boolean;
27
30
  isLoading?: boolean;
@@ -1,2 +1,2 @@
1
- import{__rest as t}from"../../../node_modules/tslib/tslib.es6.mjs.js";import{jsx as o,jsxs as i}from"react/jsx-runtime";import"./button.css";import{Tooltip as n}from"../tooltip/tooltip.js";import{Icon as l}from"../icon/icon.js";import r from"react";const e=()=>i("svg",{className:"button__spinner",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24","aria-hidden":"true",children:[o("circle",{className:"button__spinner-circle",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),o("path",{className:"button__spinner-path",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),s=r.forwardRef(((r,s)=>{var{variant:a="primary",size:c="md",label:d,icon:m,iconStrokeWidth:u=1.5,iconOnly:b=!1,iconPosition:p="right",isLoading:h=!1,fullWidth:f=!1,tooltip:_,tooltipPosition:g="top",className:v="",disabled:N,children:j,"aria-label":w}=r,y=t(r,["variant","size","label","icon","iconStrokeWidth","iconOnly","iconPosition","isLoading","fullWidth","tooltip","tooltipPosition","className","disabled","children","aria-label"]);const x=["button",`button--${a}`,`button--${c}`,h&&"button--loading",b&&"button--icon-only",f&&"button--full-width",v].filter(Boolean).join(" "),W=null!=w?w:b?_:void 0,k=m?o(l,{icon:m,className:"button__icon",strokeWidth:u}):null,z=o("button",Object.assign({ref:s,className:x,disabled:h||N,"aria-busy":h||void 0,"aria-label":W},y,{children:b?h?o(e,{}):k:i("div",{className:"button__content",children:["left"===p&&!h&&k,d||j,"right"===p&&!h&&k,h&&o(e,{})]})}));return _?o(n,{text:_,position:g,children:z}):z}));s.displayName="Button";export{s as Button};
1
+ import{__rest as o}from"../../../node_modules/tslib/tslib.es6.mjs.js";import{jsx as t,jsxs as i}from"react/jsx-runtime";import"./button.css";import{Tooltip as n}from"../tooltip/tooltip.js";import{Icon as l}from"../icon/icon.js";import r from"react";import{cn as s}from"../../../utils/src/cn.js";const e=()=>i("svg",{className:"button__spinner",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24","aria-hidden":"true",children:[t("circle",{className:"button__spinner-circle",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),t("path",{className:"button__spinner-path",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),a=r.forwardRef(((r,a)=>{var{variant:c="primary",size:d="md",label:m,icon:u,iconProps:b,iconStrokeWidth:p=1.5,iconOnly:h=!1,iconPosition:f="right",isLoading:_=!1,fullWidth:g=!1,tooltip:v,tooltipPosition:N="top",className:j="",disabled:w,children:y,"aria-label":x}=r,P=o(r,["variant","size","label","icon","iconProps","iconStrokeWidth","iconOnly","iconPosition","isLoading","fullWidth","tooltip","tooltipPosition","className","disabled","children","aria-label"]);const W=["button",`button--${c}`,`button--${d}`,_&&"button--loading",h&&"button--icon-only",g&&"button--full-width",j].filter(Boolean).join(" "),k=null!=x?x:h?v:void 0,z=u?t(l,Object.assign({icon:u,strokeWidth:p},b,{className:s("button__icon",null==b?void 0:b.className)})):null,O=t("button",Object.assign({ref:a,className:W,disabled:_||w,"aria-busy":_||void 0,"aria-label":k},P,{children:h?_?t(e,{}):z:i("div",{className:"button__content",children:["left"===f&&!_&&z,m||y,"right"===f&&!_&&z,_&&t(e,{})]})}));return v?t(n,{text:v,position:N,children:O}):O}));a.displayName="Button";export{a as Button};
2
2
  //# sourceMappingURL=button.js.map
@@ -1,5 +1,6 @@
1
1
  import "./chip.css";
2
2
  import type React from "react";
3
+ import { Icon } from "../icon/icon";
3
4
  import type { IconType, TooltipPosition } from "../../../types";
4
5
  /**
5
6
  * Props for the `Chip` component: extends `HTMLAttributes<HTMLElement>` with H2O badge fields.
@@ -7,6 +8,7 @@ import type { IconType, TooltipPosition } from "../../../types";
7
8
  *
8
9
  * @property {string} label - Visible text (required).
9
10
  * @property {import("../../../types").IconType} [icon] - Leading icon; overrides `dot` when present.
11
+ * @property {Omit<React.ComponentProps<typeof Icon>, "icon">} [iconProps] - Extra props forwarded to the built-in `Icon` (and its `<svg>`); overrides `iconSize`/`iconStrokeWidth`/`iconClassName`.
10
12
  * @property {"neutral"|"primary"|"success"|"warning"|"error"} [variant] - Color family. Default `"neutral"`.
11
13
  * @property {"sm"|"md"|"lg"} [size] - Padding and font. Default `"md"`.
12
14
  * @property {boolean} [dot] - Renders a status dot instead of an icon when no `icon`.
@@ -16,6 +18,7 @@ import type { IconType, TooltipPosition } from "../../../types";
16
18
  type ChipProps = React.HTMLAttributes<HTMLElement> & {
17
19
  label: string;
18
20
  icon?: IconType;
21
+ iconProps?: Omit<React.ComponentProps<typeof Icon>, "icon">;
19
22
  variant?: "neutral" | "primary" | "success" | "warning" | "error";
20
23
  size?: "sm" | "md" | "lg";
21
24
  iconStrokeWidth?: number;
@@ -33,5 +36,5 @@ type ChipProps = React.HTMLAttributes<HTMLElement> & {
33
36
  * @param {ChipProps} props - Extends native element props; includes `label` and presentation.
34
37
  * @returns {JSX.Element} A `span` or `button`-like chip per `onClick` usage.
35
38
  */
36
- export declare const Chip: ({ label, icon, variant, size, iconStrokeWidth, iconClassName, iconSize, disabled, showBorder, dot, tooltip, tooltipPosition, className, onClick, ...props }: ChipProps) => import("react/jsx-runtime").JSX.Element;
39
+ export declare const Chip: ({ label, icon, iconProps, variant, size, iconStrokeWidth, iconClassName, iconSize, disabled, showBorder, dot, tooltip, tooltipPosition, className, onClick, ...props }: ChipProps) => import("react/jsx-runtime").JSX.Element;
37
40
  export {};
@@ -1,2 +1,2 @@
1
- import{__rest as i}from"../../../node_modules/tslib/tslib.es6.mjs.js";import{jsxs as o,jsx as t}from"react/jsx-runtime";import"./chip.css";import{Icon as e}from"../icon/icon.js";import{Tooltip as s}from"../tooltip/tooltip.js";const n=n=>{var{label:a,icon:c,variant:l="neutral",size:r="md",iconStrokeWidth:d=1.5,iconClassName:p="",iconSize:m=14,disabled:h=!1,showBorder:b=!1,dot:v=!1,tooltip:k,tooltipPosition:N="top",className:j="",onClick:f}=n,u=i(n,["label","icon","variant","size","iconStrokeWidth","iconClassName","iconSize","disabled","showBorder","dot","tooltip","tooltipPosition","className","onClick"]);const z=!!f,C=v&&!c,x=["chip-base",`chip-${l}`,`chip--${r}`,b?"chip--border":"",C?"chip--dot":"",c?"chip--icon":"",h?"chip--disabled":"",j].filter(Boolean).join(" "),S=o("div",Object.assign({className:x,role:z?"button":void 0,tabIndex:z&&!h?0:void 0,"aria-disabled":h||void 0,onClick:h?void 0:f,onKeyDown:z&&!h?i=>{"Enter"!==i.key&&" "!==i.key||!f||(i.preventDefault(),f(i))}:void 0},u,{children:[C&&t("span",{className:"chip-dot"}),c&&t(e,{icon:c,size:m,strokeWidth:d,className:p}),t("span",{className:"chip-label",children:a})]}));return k?t(s,{text:k,position:N,children:S}):S};export{n as Chip};
1
+ import{__rest as o}from"../../../node_modules/tslib/tslib.es6.mjs.js";import{jsxs as i,jsx as s}from"react/jsx-runtime";import"./chip.css";import{Icon as t}from"../icon/icon.js";import{Tooltip as e}from"../tooltip/tooltip.js";import{cn as c}from"../../../utils/src/cn.js";const n=n=>{var{label:a,icon:l,iconProps:r,variant:d="neutral",size:p="md",iconStrokeWidth:m=1.5,iconClassName:h="",iconSize:b=14,disabled:v=!1,showBorder:j=!1,dot:N=!1,tooltip:k,tooltipPosition:u="top",className:f="",onClick:z}=n,C=o(n,["label","icon","iconProps","variant","size","iconStrokeWidth","iconClassName","iconSize","disabled","showBorder","dot","tooltip","tooltipPosition","className","onClick"]);const x=!!z,P=N&&!l,S=["chip-base",`chip-${d}`,`chip--${p}`,j?"chip--border":"",P?"chip--dot":"",l?"chip--icon":"",v?"chip--disabled":"",f].filter(Boolean).join(" "),w=i("div",Object.assign({className:S,role:x?"button":void 0,tabIndex:x&&!v?0:void 0,"aria-disabled":v||void 0,onClick:v?void 0:z,onKeyDown:x&&!v?o=>{"Enter"!==o.key&&" "!==o.key||!z||(o.preventDefault(),z(o))}:void 0},C,{children:[P&&s("span",{className:"chip-dot"}),l&&s(t,Object.assign({icon:l,size:b,strokeWidth:m},r,{className:c(h,null==r?void 0:r.className)})),s("span",{className:"chip-label",children:a})]}));return k?s(e,{text:k,position:u,children:w}):w};export{n as Chip};
2
2
  //# sourceMappingURL=chip.js.map
@@ -1,14 +1,17 @@
1
1
  import "./content-switch.css";
2
+ import { Icon } from "../icon/icon";
2
3
  import type { IconType } from "../../../types";
3
4
  /**
4
5
  * Tab-like option in a `ContentSwitch` row (`role="tablist"` / `role="tab"`).
5
6
  * @property {string} value - Passed to `onChange` when selected.
6
7
  * @property {IconType} [icon] - Optional leading icon on the tab.
8
+ * @property {Omit<React.ComponentProps<typeof Icon>, "icon">} [iconProps] - Extra props forwarded to the built-in `Icon` (and its `<svg>`).
7
9
  */
8
10
  export type ContentSwitchOption = {
9
11
  label: string;
10
12
  value: string;
11
13
  icon?: IconType;
14
+ iconProps?: Omit<React.ComponentProps<typeof Icon>, "icon">;
12
15
  disabled?: boolean;
13
16
  };
14
17
  /**
@@ -1,2 +1,2 @@
1
- import{jsx as t,jsxs as e}from"react/jsx-runtime";import"./content-switch.css";import{Icon as i}from"../icon/icon.js";import{cn as o}from"../../../utils/src/cn.js";const n=({options:n,selected:a,onChange:c,variant:s="primary",className:l,optionClassName:r,disabled:m=!1,ariaLabel:p})=>t("div",{role:"tablist","aria-label":p,className:o("primary"===s?"content-switch-primary":"content-switch-secondary",l),children:n.map((n=>{const s=m||n.disabled;return e("button",{type:"button",role:"tab","aria-selected":a===n.value,onClick:()=>!s&&c(n.value),disabled:s,className:o("content-switch-option",r,a===n.value&&"content-switch-option-selected",s&&"content-switch-option-disabled"),children:[n.icon&&t(i,{icon:n.icon,size:16,className:"content-switch-option-icon"}),n.label]},n.value)}))});export{n as ContentSwitch};
1
+ import{jsx as t,jsxs as o}from"react/jsx-runtime";import"./content-switch.css";import{Icon as i}from"../icon/icon.js";import{cn as e}from"../../../utils/src/cn.js";const n=({options:n,selected:s,onChange:a,variant:c="primary",className:l,optionClassName:r,disabled:m=!1,ariaLabel:p})=>t("div",{role:"tablist","aria-label":p,className:e("primary"===c?"content-switch-primary":"content-switch-secondary",l),children:n.map((n=>{var c;const l=m||n.disabled;return o("button",{type:"button",role:"tab","aria-selected":s===n.value,onClick:()=>!l&&a(n.value),disabled:l,className:e("content-switch-option",r,s===n.value&&"content-switch-option-selected",l&&"content-switch-option-disabled"),children:[n.icon&&t(i,Object.assign({icon:n.icon,size:16},n.iconProps,{className:e("content-switch-option-icon",null===(c=n.iconProps)||void 0===c?void 0:c.className)})),n.label]},n.value)}))});export{n as ContentSwitch};
2
2
  //# sourceMappingURL=content-switch.js.map
@@ -0,0 +1,120 @@
1
+ .expandable-search {
2
+ --expandable-search-height: 40px;
3
+ --expandable-search-width: 200px;
4
+
5
+ position: relative;
6
+ width: fit-content;
7
+ overflow: hidden;
8
+ border: 1.5px solid transparent;
9
+ border-radius: var(--radius-md);
10
+ transition:
11
+ border-color 0.2s ease,
12
+ background-color 0.2s ease;
13
+ }
14
+
15
+ .expandable-search--sm {
16
+ --expandable-search-height: 32px;
17
+ }
18
+
19
+ .expandable-search--md {
20
+ --expandable-search-height: 40px;
21
+ }
22
+
23
+ .expandable-search--lg {
24
+ --expandable-search-height: 48px;
25
+ }
26
+
27
+ .expandable-search--expanded {
28
+ border-color: hsl(var(--primary));
29
+ background: hsl(var(--input));
30
+ }
31
+
32
+ .expandable-search-container {
33
+ position: relative;
34
+ display: flex;
35
+ align-items: center;
36
+ justify-content: flex-end;
37
+ width: var(--expandable-search-height);
38
+ overflow: hidden;
39
+ border-radius: var(--radius-md);
40
+ transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
41
+ }
42
+
43
+ .expandable-search--expanded .expandable-search-container {
44
+ width: calc(
45
+ var(--expandable-search-width) + var(--expandable-search-height)
46
+ );
47
+ }
48
+
49
+ .expandable-search-button {
50
+ display: inline-flex;
51
+ align-items: center;
52
+ justify-content: center;
53
+ flex-shrink: 0;
54
+ width: var(--expandable-search-height);
55
+ height: var(--expandable-search-height);
56
+ padding: 0;
57
+ border: none;
58
+ border-radius: var(--radius-md);
59
+ background: transparent;
60
+ color: hsl(var(--primary));
61
+ cursor: pointer;
62
+ position: relative;
63
+ z-index: 2;
64
+ transition:
65
+ background-color 0.2s ease,
66
+ color 0.2s ease;
67
+ }
68
+
69
+ .expandable-search-button:hover {
70
+ background-color: hsl(var(--primary-disabled));
71
+ }
72
+
73
+ .expandable-search-button:focus-visible {
74
+ outline: 2px solid hsl(var(--primary));
75
+ outline-offset: 2px;
76
+ }
77
+
78
+ .expandable-search--expanded .expandable-search-button:hover {
79
+ background-color: transparent;
80
+ color: hsl(var(--primary-300));
81
+ }
82
+
83
+ .expandable-search-input {
84
+ position: absolute;
85
+ top: 0;
86
+ right: var(--expandable-search-height);
87
+ width: var(--expandable-search-width);
88
+ height: var(--expandable-search-height);
89
+ padding: 0 0.875rem;
90
+ margin: 0;
91
+ border: none;
92
+ outline: none;
93
+ background: transparent;
94
+ color: hsl(var(--foreground));
95
+ font-size: 0.875rem;
96
+ font-family: inherit;
97
+ transform: translateX(100%);
98
+ opacity: 0;
99
+ visibility: hidden;
100
+ pointer-events: none;
101
+ transition:
102
+ transform 0.1s cubic-bezier(0.4, 0, 0.2, 1),
103
+ opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1),
104
+ visibility 0s linear 0.3s;
105
+ }
106
+
107
+ .expandable-search-input::placeholder {
108
+ color: hsl(var(--muted));
109
+ }
110
+
111
+ .expandable-search--expanded .expandable-search-input {
112
+ transform: translateX(0);
113
+ opacity: 1;
114
+ visibility: visible;
115
+ pointer-events: all;
116
+ transition:
117
+ transform 0.3s cubic-bezier(0.4, 0, 0.2, 1) 0.1s,
118
+ opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1) 0.1s,
119
+ visibility 0s linear 0.1s;
120
+ }
@@ -0,0 +1,40 @@
1
+ import "./expandable-search.css";
2
+ /**
3
+ * Props for `ExpandableSearch`.
4
+ *
5
+ * @property {"sm"|"md"|"lg"} [size] - Trigger and expanded field height. Default `"md"`.
6
+ * @property {string} [value] - Controlled value. When provided, the parent owns state.
7
+ * @property {string} [defaultValue] - Initial value when uncontrolled. Default `""`.
8
+ * @property {boolean} [defaultExpanded] - Initial expanded state when uncontrolled. Default `false`.
9
+ * @property {string} [placeholder] - Input placeholder. Default `"Search..."`.
10
+ * @property {number} [expandedWidth] - Width of the input area in px when expanded. Default `200`.
11
+ * @property {(value: string) => void} [onChange] - Fires on each keystroke with the new value.
12
+ * @property {(expanded: boolean) => void} [onExpandedChange] - Fires when expanded state changes.
13
+ * @property {string} [className] - Extra class names on the wrapper.
14
+ * @property {string} [openAriaLabel] - Aria label for the trigger when collapsed. Default `"Open search"`.
15
+ * @property {string} [closeAriaLabel] - Aria label for the trigger when expanded. Default `"Close search"`.
16
+ */
17
+ interface ExpandableSearchProps {
18
+ size?: "sm" | "md" | "lg";
19
+ value?: string;
20
+ defaultValue?: string;
21
+ defaultExpanded?: boolean;
22
+ placeholder?: string;
23
+ expandedWidth?: number;
24
+ onChange?: (value: string) => void;
25
+ onExpandedChange?: (expanded: boolean) => void;
26
+ className?: string;
27
+ openAriaLabel?: string;
28
+ closeAriaLabel?: string;
29
+ }
30
+ /**
31
+ * Icon-only search trigger that expands into an inline input on click.
32
+ *
33
+ * Collapses automatically when the user clicks outside while the input is empty.
34
+ * Toggling while expanded clears the value. Supports controlled or uncontrolled value.
35
+ *
36
+ * @param {ExpandableSearchProps} props - Controlled/uncontrolled value and presentation.
37
+ * @returns {JSX.Element} A pill-shaped wrapper containing the input and toggle button.
38
+ */
39
+ export declare const ExpandableSearch: ({ size, value, defaultValue, defaultExpanded, placeholder, expandedWidth, onChange, onExpandedChange, className, openAriaLabel, closeAriaLabel, }: ExpandableSearchProps) => JSX.Element;
40
+ export {};
@@ -0,0 +1,2 @@
1
+ import{jsx as e,jsxs as a}from"react/jsx-runtime";import"./expandable-search.css";import{useState as n,useRef as l,useEffect as r}from"react";import{Icon as o}from"../icon/icon.js";import{useClickOutside as s}from"../../../hooks/src/use-click-outside.js";const c=({size:c="md",value:d,defaultValue:t="",defaultExpanded:i=!1,placeholder:p="Search...",expandedWidth:h=200,onChange:u,onExpandedChange:m,className:x="",openAriaLabel:b="Open search",closeAriaLabel:f="Close search"})=>{const v=void 0!==d,[g,C]=n(t),[N,j]=n(i),k=l(null),y=l(null),z=v?d:g,A=e=>{v||C(e),null==u||u(e)},E=e=>{j(e),null==m||m(e)};s(k,(()=>{N&&!z&&E(!1)})),r((()=>{var e;N&&(null===(e=y.current)||void 0===e||e.focus())}),[N]);const L=["expandable-search",`expandable-search--${c}`,N?"expandable-search--expanded":"",x].filter(Boolean).join(" ");return e("div",{ref:k,className:L,style:{"--expandable-search-width":`${h}px`},children:a("div",{className:"expandable-search-container",children:[e("input",{ref:y,type:"text",value:z,onChange:e=>{A(e.target.value)},placeholder:p,className:"expandable-search-input",tabIndex:N?0:-1,"aria-hidden":!N||void 0}),e("button",{type:"button",onClick:()=>{if(N)return A(""),void E(!1);E(!0)},className:"expandable-search-button","aria-label":N?f:b,"aria-expanded":N,children:e(o,{icon:N?"close":"search",size:{sm:14,md:16,lg:18}[c]})})]})})};export{c as ExpandableSearch};
2
+ //# sourceMappingURL=expandable-search.js.map
@@ -1,11 +1,14 @@
1
1
  import "./input.css";
2
2
  import type { IconType, TooltipPosition } from "../../../types";
3
+ import { Icon } from "../icon/icon";
3
4
  /**
4
5
  * Extends `HTMLInputElement` attributes
5
6
  *
6
7
  * @property {"sm"|"md"|"lg"} [size] - Field height and font scale. Default `"md"`.
7
8
  * @property {import("../../../types").IconType} [leftIcon] - Optional left decorative/action icon.
9
+ * @property {Omit<React.ComponentProps<typeof Icon>, "icon">} [leftIconProps] - Extra props forwarded to the left `Icon` (and its `<svg>`).
8
10
  * @property {import("../../../types").IconType} [rightIcon] - Optional right icon; pair with `onRightIconClick` for an action.
11
+ * @property {Omit<React.ComponentProps<typeof Icon>, "icon">} [rightIconProps] - Extra props forwarded to the right `Icon` (and its `<svg>`).
9
12
  * @property {boolean} [showClear] - Shows a clear control when the field has a value. Default `false`.
10
13
  * @property {string} [note] - Helper text below the field (non-error).
11
14
  * @property {string} [error] - Error message; styles the field as invalid when set.
@@ -16,7 +19,9 @@ interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "
16
19
  size?: "sm" | "md" | "lg";
17
20
  label?: string;
18
21
  leftIcon?: IconType;
22
+ leftIconProps?: Omit<React.ComponentProps<typeof Icon>, "icon">;
19
23
  rightIcon?: IconType;
24
+ rightIconProps?: Omit<React.ComponentProps<typeof Icon>, "icon">;
20
25
  onRightIconClick?: () => void;
21
26
  showClear?: boolean;
22
27
  note?: string;
@@ -1,2 +1,2 @@
1
- import{__rest as i}from"../../../node_modules/tslib/tslib.es6.mjs.js";import{jsxs as t,jsx as e}from"react/jsx-runtime";import"./input.css";import{forwardRef as o,useState as n,useId as s}from"react";import{Icon as a}from"../icon/icon.js";const l=o(((o,l)=>{var{size:c="md",label:r,leftIcon:p,rightIcon:d,onRightIconClick:u,showClear:m,note:h,error:b="",className:N="",containerClassName:v="",type:f="text",disabled:g,tooltip:C,tooltipPosition:y="top",value:I}=o,w=i(o,["size","label","leftIcon","rightIcon","onRightIconClick","showClear","note","error","className","containerClassName","type","disabled","tooltip","tooltipPosition","value"]);const[z,x]=n(!1),$=s(),j="password"===f,k={sm:16,md:20,lg:24},P=void 0!==I&&""!==I;return t("div",{className:`input-container ${v}`,children:[(r||m&&P)&&t("div",{className:"input-header",children:[r&&t("label",{htmlFor:$,className:"input-label",children:[r,C&&e(a,{icon:"info",size:16,tooltip:C,className:"input-info-icon",tooltipPosition:y})]}),m&&P&&!g&&e("button",{type:"button",onClick:()=>{var i;null===(i=w.onChange)||void 0===i||i.call(w,{target:{value:""}})},className:"input-clear",children:"Clear"})]}),t("div",{className:`input-wrapper ${b?"input-error":""} ${g?"input-disabled":""}`,children:[p&&e("div",{className:"input-icon-left",children:e(a,{icon:p,size:k[c]})}),e("input",Object.assign({id:$,ref:l,type:j?z?"text":"password":f,className:`input input-${c} ${(()=>{const i=void 0!==p,t=void 0!==d||j;return i&&t?"input-has-both-icons":i?"input-has-left-icon":t?"input-has-right-icon":""})()} ${N}`,disabled:g,value:I},w)),(d||j)&&e("div",{className:"input-icon-right",children:j?e("button",{type:"button",onClick:()=>x(!z),className:"input-icon-button",tabIndex:-1,"aria-label":z?"Hide password":"Show password",children:e(a,{icon:z?"eye":"eye-off",size:k[c]})}):d&&u?e("button",{type:"button",onClick:u,className:"input-icon-button",tabIndex:-1,disabled:g,children:e(a,{icon:d,size:k[c]})}):d?e(a,{icon:d,size:k[c]}):null})]}),(h||b)&&e("small",{className:b?"input-error-message":"input-note",children:b||h})]})}));l.displayName="Input";const c=l;export{c as Input};
1
+ import{__rest as i}from"../../../node_modules/tslib/tslib.es6.mjs.js";import{jsxs as t,jsx as e}from"react/jsx-runtime";import"./input.css";import{forwardRef as o,useState as n,useId as s}from"react";import{Icon as a}from"../icon/icon.js";const l=o(((o,l)=>{var{size:c="md",label:r,leftIcon:p,leftIconProps:d,rightIcon:u,rightIconProps:m,onRightIconClick:h,showClear:b,note:N,error:g="",className:f="",containerClassName:v="",type:I="text",disabled:C,tooltip:y,tooltipPosition:j="top",value:w}=o,z=i(o,["size","label","leftIcon","leftIconProps","rightIcon","rightIconProps","onRightIconClick","showClear","note","error","className","containerClassName","type","disabled","tooltip","tooltipPosition","value"]);const[P,x]=n(!1),$=s(),k="password"===I,O={sm:16,md:20,lg:24},R=void 0!==w&&""!==w;return t("div",{className:`input-container ${v}`,children:[(r||b&&R)&&t("div",{className:"input-header",children:[r&&t("label",{htmlFor:$,className:"input-label",children:[r,y&&e(a,{icon:"info",size:16,tooltip:y,className:"input-info-icon",tooltipPosition:j})]}),b&&R&&!C&&e("button",{type:"button",onClick:()=>{var i;null===(i=z.onChange)||void 0===i||i.call(z,{target:{value:""}})},className:"input-clear",children:"Clear"})]}),t("div",{className:`input-wrapper ${g?"input-error":""} ${C?"input-disabled":""}`,children:[p&&e("div",{className:"input-icon-left",children:e(a,Object.assign({icon:p,size:O[c]},d))}),e("input",Object.assign({id:$,ref:l,type:k?P?"text":"password":I,className:`input input-${c} ${(()=>{const i=void 0!==p,t=void 0!==u||k;return i&&t?"input-has-both-icons":i?"input-has-left-icon":t?"input-has-right-icon":""})()} ${f}`,disabled:C,value:w},z)),(u||k)&&e("div",{className:"input-icon-right",children:k?e("button",{type:"button",onClick:()=>x(!P),className:"input-icon-button",tabIndex:-1,"aria-label":P?"Hide password":"Show password",children:e(a,{icon:P?"eye":"eye-off",size:O[c]})}):u&&h?e("button",{type:"button",onClick:h,className:"input-icon-button",tabIndex:-1,disabled:C,children:e(a,Object.assign({icon:u,size:O[c]},m))}):u?e(a,Object.assign({icon:u,size:O[c]},m)):null})]}),(N||g)&&e("small",{className:g?"input-error-message":"input-note",children:g||N})]})}));l.displayName="Input";const c=l;export{c as Input};
2
2
  //# sourceMappingURL=input.js.map
@@ -1,2 +1,2 @@
1
- import{jsx as e,jsxs as o}from"react/jsx-runtime";import"./modal.css";import{useRef as l,useEffect as a}from"react";import{createPortal as t}from"react-dom";import{Button as s}from"../button/button.js";import{useFocusTrap as r}from"../../../hooks/src/use-focus-trap.js";let d=0;const n=({isOpen:n,onClose:i,title:m,description:c,children:u,footer:N,size:v="md",className:h="",titleContainerClassName:p="",titleClassName:y="",descriptionClassName:f="",closeButtonClassName:C="",headerClassName:b="",contentClassName:$=""})=>{const k=l(null),w=l("modal-title-"+ ++d).current;return r(k,n),a((()=>{const e=e=>{"Escape"===e.key&&n&&i&&i()};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)}),[n,i]),a((()=>{if(n){const e=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{document.body.style.overflow=e}}}),[n]),n?t(e("div",{className:"modal-overlay",children:o("div",{ref:k,role:"dialog","aria-modal":"true","aria-labelledby":m?w:void 0,className:`modal modal--${v}${h?` ${h}`:""}`,children:[o("div",{className:"modal-header"+(b?` ${b}`:""),children:[o("div",{className:"modal-title-container"+(p?` ${p}`:""),children:[m&&e("h2",{id:w,className:"modal-title"+(y?` ${y}`:""),children:m}),c&&e("p",{className:"modal-description"+(f?` ${f}`:""),children:c})]}),i&&e(s,{variant:"secondary",size:"sm",onClick:i,className:"modal-close"+(C?` ${C}`:""),"aria-label":"Close modal",icon:"close",iconOnly:!0})]}),e("div",{className:"modal-content"+($?` ${$}`:""),children:u}),N&&e("div",{className:"modal-footer",children:N})]})}),document.body):null};export{n as Modal};
1
+ import{jsx as e,jsxs as o}from"react/jsx-runtime";import"./modal.css";import{useRef as t,useEffect as a}from"react";import{createPortal as r}from"react-dom";import{Button as l}from"../button/button.js";import{useFocusTrap as s}from"../../../hooks/src/use-focus-trap.js";let n=0;const d=({isOpen:d,onClose:c,title:i,description:m,children:u,footer:N,size:v="md",className:h="",titleContainerClassName:p="",titleClassName:y="",descriptionClassName:f="",closeButtonClassName:C="",headerClassName:b="",contentClassName:$=""})=>{const k=t(null),w=t("modal-title-"+ ++n).current,g=t(!1);return s(k,d),a((()=>{const e=e=>{"Escape"===e.key&&d&&c&&c()};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)}),[d,c]),a((()=>{if(d){const e=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{document.body.style.overflow=e}}}),[d]),d?r(e("div",{className:"modal-overlay",onMouseDown:e=>{g.current=e.target===e.currentTarget},onClick:e=>{c&&g.current&&e.target===e.currentTarget&&c(),g.current=!1},children:o("div",{ref:k,role:"dialog","aria-modal":"true","aria-labelledby":i?w:void 0,className:`modal modal--${v}${h?` ${h}`:""}`,children:[o("div",{className:"modal-header"+(b?` ${b}`:""),children:[o("div",{className:"modal-title-container"+(p?` ${p}`:""),children:[i&&e("h2",{id:w,className:"modal-title"+(y?` ${y}`:""),children:i}),m&&e("p",{className:"modal-description"+(f?` ${f}`:""),children:m})]}),c&&e(l,{variant:"secondary",size:"sm",onClick:c,className:"modal-close"+(C?` ${C}`:""),"aria-label":"Close modal",icon:"close",iconOnly:!0})]}),e("div",{className:"modal-content"+($?` ${$}`:""),children:u}),N&&e("div",{className:"modal-footer",children:N})]})}),document.body):null};export{d as Modal};
2
2
  //# sourceMappingURL=modal.js.map
@@ -0,0 +1,178 @@
1
+ .onboarding {
2
+ position: fixed;
3
+ inset: 0;
4
+ pointer-events: none;
5
+ }
6
+
7
+ /* Dim + click capture. Sits over the page; the spotlight glow draws the cutout. */
8
+ .onboarding__blocker {
9
+ position: fixed;
10
+ background: rgba(0, 0, 0, 0.5);
11
+ pointer-events: auto;
12
+ animation: onboardingFade 0.2s ease;
13
+ }
14
+
15
+ /* Visual-only highlight ring around the target (clicks pass through). */
16
+ .onboarding__spotlight {
17
+ position: fixed;
18
+ pointer-events: none;
19
+ box-shadow:
20
+ 0 0 0 9999px rgba(0, 0, 0, 0.5),
21
+ 0 0 0 2px hsl(var(--primary)),
22
+ 0 0 18px 4px hsl(var(--primary) / 0.45);
23
+ transition:
24
+ top 0.25s cubic-bezier(0.16, 1, 0.3, 1),
25
+ left 0.25s cubic-bezier(0.16, 1, 0.3, 1),
26
+ width 0.25s cubic-bezier(0.16, 1, 0.3, 1),
27
+ height 0.25s cubic-bezier(0.16, 1, 0.3, 1);
28
+ }
29
+
30
+ /* When the spotlight is shown, its box-shadow provides the dim — hide the flat blockers' bg. */
31
+ .onboarding:has(.onboarding__spotlight) .onboarding__blocker {
32
+ background: transparent;
33
+ }
34
+
35
+ .onboarding__popup {
36
+ position: fixed;
37
+ pointer-events: auto;
38
+ width: 320px;
39
+ max-width: calc(100vw - 24px);
40
+ background: hsl(var(--card, var(--background)));
41
+ color: hsl(var(--foreground));
42
+ border: 1px solid hsl(var(--border));
43
+ border-radius: var(--radius-md);
44
+ box-shadow: 0 10px 38px rgba(0, 0, 0, 0.22);
45
+ padding: 16px;
46
+ animation: onboardingPopIn 0.22s cubic-bezier(0.16, 1, 0.3, 1);
47
+ }
48
+
49
+ .onboarding__close {
50
+ position: absolute;
51
+ top: 10px;
52
+ right: 10px;
53
+ display: inline-flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ width: 24px;
57
+ height: 24px;
58
+ border: none;
59
+ background: transparent;
60
+ color: hsl(var(--muted));
61
+ border-radius: var(--radius-sm, 6px);
62
+ cursor: pointer;
63
+ }
64
+
65
+ .onboarding__close:hover {
66
+ background: hsl(var(--primary) / 0.08);
67
+ color: hsl(var(--foreground));
68
+ }
69
+
70
+ .onboarding__close:focus-visible {
71
+ outline: 2px solid hsl(var(--primary));
72
+ outline-offset: 1px;
73
+ }
74
+
75
+ .onboarding__title {
76
+ font-size: 15px;
77
+ font-weight: 600;
78
+ line-height: 1.3;
79
+ margin-bottom: 6px;
80
+ padding-right: 24px;
81
+ }
82
+
83
+ .onboarding__content {
84
+ font-size: 13px;
85
+ line-height: 1.5;
86
+ color: hsl(var(--muted));
87
+ }
88
+
89
+ .onboarding__footer {
90
+ display: flex;
91
+ align-items: center;
92
+ justify-content: space-between;
93
+ gap: 8px;
94
+ margin-top: 16px;
95
+ }
96
+
97
+ .onboarding__footer-right {
98
+ display: flex;
99
+ align-items: center;
100
+ gap: 8px;
101
+ }
102
+
103
+ .onboarding__progress {
104
+ font-size: 12px;
105
+ color: hsl(var(--muted));
106
+ font-variant-numeric: tabular-nums;
107
+ }
108
+
109
+ /* Arrow caret pointing at the target. */
110
+ .onboarding__arrow {
111
+ position: absolute;
112
+ width: 10px;
113
+ height: 10px;
114
+ background: hsl(var(--card, var(--background)));
115
+ border: 1px solid hsl(var(--border));
116
+ transform: rotate(45deg);
117
+ }
118
+
119
+ .onboarding__popup[data-placement="bottom"] .onboarding__arrow {
120
+ top: -6px;
121
+ left: 50%;
122
+ margin-left: -5px;
123
+ border-right: none;
124
+ border-bottom: none;
125
+ }
126
+
127
+ .onboarding__popup[data-placement="top"] .onboarding__arrow {
128
+ bottom: -6px;
129
+ left: 50%;
130
+ margin-left: -5px;
131
+ border-left: none;
132
+ border-top: none;
133
+ }
134
+
135
+ .onboarding__popup[data-placement="right"] .onboarding__arrow {
136
+ left: -6px;
137
+ top: 50%;
138
+ margin-top: -5px;
139
+ border-top: none;
140
+ border-right: none;
141
+ }
142
+
143
+ .onboarding__popup[data-placement="left"] .onboarding__arrow {
144
+ right: -6px;
145
+ top: 50%;
146
+ margin-top: -5px;
147
+ border-bottom: none;
148
+ border-left: none;
149
+ }
150
+
151
+ @keyframes onboardingFade {
152
+ from {
153
+ opacity: 0;
154
+ }
155
+ to {
156
+ opacity: 1;
157
+ }
158
+ }
159
+
160
+ @keyframes onboardingPopIn {
161
+ from {
162
+ opacity: 0;
163
+ transform: scale(0.96);
164
+ }
165
+ to {
166
+ opacity: 1;
167
+ transform: scale(1);
168
+ }
169
+ }
170
+
171
+ @media (prefers-reduced-motion: reduce) {
172
+ .onboarding__blocker,
173
+ .onboarding__popup,
174
+ .onboarding__spotlight {
175
+ animation: none;
176
+ transition: none;
177
+ }
178
+ }
@@ -0,0 +1,100 @@
1
+ import "./onboarding.css";
2
+ import type React from "react";
3
+ import type { ReactNode } from "react";
4
+ import { type OnboardingStorage, type UseOnboardingReturn } from "../../../hooks/src/use-onboarding";
5
+ /** Where a step popup sits relative to its target. `"center"` ignores the target and centers on screen. */
6
+ export type OnboardingPlacement = "top" | "bottom" | "left" | "right" | "auto" | "center";
7
+ /**
8
+ * How a step finds its anchor element:
9
+ * - `string` — a CSS selector (e.g. `"#sidebar"`, `".profile"`, `"[data-tour=save]"`). A bare word falls back to an element id.
10
+ * - `HTMLElement` — the element directly.
11
+ * - `() => HTMLElement | null` — resolved lazily when the step shows.
12
+ */
13
+ export type OnboardingTarget = string | HTMLElement | (() => HTMLElement | null);
14
+ /**
15
+ * A single step in an onboarding flow.
16
+ *
17
+ * @property {OnboardingTarget} [target] - Element to anchor + spotlight. Omit for a centered step (welcome/finish screens).
18
+ * @property {ReactNode} [title] - Heading shown at the top of the popup.
19
+ * @property {ReactNode} content - Body message (required).
20
+ * @property {OnboardingPlacement} [placement] - Popup side. Default: the flow's `placement` (which defaults to `"auto"`).
21
+ * @property {number} [spotlightPadding] - Extra px around the target in the spotlight cutout.
22
+ * @property {number} [spotlightRadius] - Spotlight corner radius in px.
23
+ * @property {boolean} [disableInteraction] - Block clicks on the spotlighted element. Default: the flow's `disableInteraction`.
24
+ */
25
+ export interface OnboardingStep {
26
+ target?: OnboardingTarget;
27
+ title?: ReactNode;
28
+ content: ReactNode;
29
+ placement?: OnboardingPlacement;
30
+ spotlightPadding?: number;
31
+ spotlightRadius?: number;
32
+ disableInteraction?: boolean;
33
+ showBack?: boolean;
34
+ showSkip?: boolean;
35
+ nextLabel?: string;
36
+ backLabel?: string;
37
+ finishLabel?: string;
38
+ }
39
+ /** Context passed to `renderStep` / `renderFooter` for fully custom popup UI. */
40
+ export interface OnboardingRenderContext extends UseOnboardingReturn {
41
+ step: OnboardingStep;
42
+ }
43
+ /** Imperative handle exposed via `ref` on `Onboarding`. */
44
+ export type OnboardingHandle = UseOnboardingReturn;
45
+ /**
46
+ * Props for `Onboarding`. Most are flow-wide defaults that individual steps can override.
47
+ *
48
+ * @property {string} id - Stable flow id; persistence key.
49
+ * @property {OnboardingStep[]} steps - Ordered steps.
50
+ * @property {boolean} [run] - Controlled active state. Omit to auto-manage (see `autoStart`).
51
+ */
52
+ export interface OnboardingProps {
53
+ id: string;
54
+ steps: OnboardingStep[];
55
+ run?: boolean;
56
+ autoStart?: boolean;
57
+ persist?: boolean;
58
+ storage?: OnboardingStorage;
59
+ startDelay?: number;
60
+ placement?: OnboardingPlacement;
61
+ spotlightPadding?: number;
62
+ spotlightRadius?: number;
63
+ disableInteraction?: boolean;
64
+ closeOnOverlayClick?: boolean;
65
+ closeOnEsc?: boolean;
66
+ keyboardNavigation?: boolean;
67
+ scrollIntoView?: boolean;
68
+ scrollBehavior?: ScrollBehavior;
69
+ offset?: number;
70
+ zIndex?: number;
71
+ showProgress?: boolean;
72
+ showSkip?: boolean;
73
+ showBack?: boolean;
74
+ showClose?: boolean;
75
+ nextLabel?: string;
76
+ backLabel?: string;
77
+ skipLabel?: string;
78
+ finishLabel?: string;
79
+ className?: string;
80
+ overlayClassName?: string;
81
+ onStart?: () => void;
82
+ onStepChange?: (index: number, previous: number, step: OnboardingStep) => void;
83
+ onSkip?: (index: number) => void;
84
+ onFinish?: () => void;
85
+ onClose?: () => void;
86
+ renderStep?: (ctx: OnboardingRenderContext) => ReactNode;
87
+ renderFooter?: (ctx: OnboardingRenderContext) => ReactNode;
88
+ }
89
+ /**
90
+ * Modular onboarding / product-tour overlay. Drive a flow by `id` with a `steps`
91
+ * array — each step spotlights an element (by selector/id) and shows a popup with
92
+ * Back / Skip / Next controls. Persists completion so a flow shows once.
93
+ *
94
+ * Headless control lives in {@link useOnboarding}; this component is the batteries-included UI.
95
+ *
96
+ * @param {OnboardingProps} props
97
+ * @param {React.Ref<OnboardingHandle>} ref - Imperative controls (`start`, `next`, `skip`, `reset`, …).
98
+ * @returns {JSX.Element | null} A portal with the spotlight overlay + popup while active.
99
+ */
100
+ export declare const Onboarding: React.ForwardRefExoticComponent<OnboardingProps & React.RefAttributes<UseOnboardingReturn>>;