h2o-library 2.0.0 → 2.0.1

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/CHANGELOG.md CHANGED
@@ -20,6 +20,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
20
20
 
21
21
  ---
22
22
 
23
+ ## [2.0.1] — 2026-05-14
24
+
25
+ ### Added
26
+
27
+ - **ExpandableSearch** — Reintroduced as a first-class component. Icon-only trigger that expands into an inline input on click, collapses on outside click when empty, supports controlled (`value` + `onChange`) and uncontrolled (`defaultValue`) usage, three sizes (`sm`/`md`/`lg`), and customizable `expandedWidth`. Trigger exposes `aria-expanded`; hidden input is removed from the tab order when collapsed. `onChange` receives the new string value directly (no synthetic event).
28
+
29
+ ---
30
+
23
31
  ## [2.0.0] — 2026-04-29
24
32
 
25
33
  First tracked release. Establishes the package's public API surface and module layout.
@@ -71,4 +79,5 @@ First tracked release. Establishes the package's public API surface and module l
71
79
  None for this release.
72
80
 
73
81
  [Unreleased]: #unreleased
82
+ [2.0.1]: #201--2026-05-14
74
83
  [2.0.0]: #200--2026-04-29
@@ -34,3 +34,4 @@ 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";
@@ -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 {};
@@ -34,3 +34,4 @@ 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";
@@ -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 {};
@@ -34,3 +34,4 @@ 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";
@@ -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
package/dist/esm/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export{ToastProvider}from"./components/src/toast/toast.js";export{Button}from"./components/src/button/button.js";export{Checkbox,CheckboxGroup}from"./components/src/checkbox/checkbox.js";export{Icon}from"./components/src/icon/icon.js";export{Radio}from"./components/src/radio/radio.js";export{Tooltip}from"./components/src/tooltip/tooltip.js";export{Toggle}from"./components/src/toggle/toggle.js";export{ContentSwitch}from"./components/src/content-switch/content-switch.js";export{Input}from"./components/src/input/input.js";export{Textarea}from"./components/src/textarea/textarea.js";export{Dropdown}from"./components/src/dropdown/dropdown.js";export{Slider}from"./components/src/slider/slider.js";export{SidePanel}from"./components/src/side-panel/side-panel.js";export{Modal}from"./components/src/modal/modal.js";export{Tag}from"./components/src/tag/tag.js";export{Accordion}from"./components/src/accordion/accordion.js";export{MultiSelect}from"./components/src/multi-select/multi-select.js";export{RadioGroup}from"./components/src/radio-group/radio-group.js";export{Tabs}from"./components/src/tabs/tabs.js";export{PopOver,PopOverContent,PopOverTrigger}from"./components/src/popover/popover.js";export{Pagination}from"./components/src/pagination/pagination.js";export{Table}from"./components/src/table/table.js";export{Logo}from"./components/src/logo/logo.js";export{Calendar}from"./components/src/calendar/calendar.js";export{MonthCalendar}from"./components/src/month-calendar/month-calendar.js";export{Loader}from"./components/src/loader/loader.js";export{Message}from"./components/src/message/message.js";export{MultiMenu}from"./components/src/multi-menu/multi-menu.js";export{CompactMultiSelect}from"./components/src/compact-multi-select/compact-multi-select.js";export{DateRangePicker}from"./components/src/date-range-picker/date-range-picker.js";export{ExpandableTable}from"./components/src/expandable-table/expandable-table.js";export{Chip}from"./components/src/chip/chip.js";export{SegmentedToggle}from"./components/src/segmented-toggle/segmented-toggle.js";export{Skeleton}from"./components/src/skeleton/skeleton.js";export{DatePicker}from"./components/src/date-picker/date-picker.js";export{TimePicker}from"./components/src/time-picker/time-picker.js";
1
+ export{ToastProvider}from"./components/src/toast/toast.js";export{Button}from"./components/src/button/button.js";export{Checkbox,CheckboxGroup}from"./components/src/checkbox/checkbox.js";export{Icon}from"./components/src/icon/icon.js";export{Radio}from"./components/src/radio/radio.js";export{Tooltip}from"./components/src/tooltip/tooltip.js";export{Toggle}from"./components/src/toggle/toggle.js";export{ContentSwitch}from"./components/src/content-switch/content-switch.js";export{Input}from"./components/src/input/input.js";export{Textarea}from"./components/src/textarea/textarea.js";export{Dropdown}from"./components/src/dropdown/dropdown.js";export{Slider}from"./components/src/slider/slider.js";export{SidePanel}from"./components/src/side-panel/side-panel.js";export{Modal}from"./components/src/modal/modal.js";export{Tag}from"./components/src/tag/tag.js";export{Accordion}from"./components/src/accordion/accordion.js";export{MultiSelect}from"./components/src/multi-select/multi-select.js";export{RadioGroup}from"./components/src/radio-group/radio-group.js";export{Tabs}from"./components/src/tabs/tabs.js";export{PopOver,PopOverContent,PopOverTrigger}from"./components/src/popover/popover.js";export{Pagination}from"./components/src/pagination/pagination.js";export{Table}from"./components/src/table/table.js";export{Logo}from"./components/src/logo/logo.js";export{Calendar}from"./components/src/calendar/calendar.js";export{MonthCalendar}from"./components/src/month-calendar/month-calendar.js";export{Loader}from"./components/src/loader/loader.js";export{Message}from"./components/src/message/message.js";export{MultiMenu}from"./components/src/multi-menu/multi-menu.js";export{CompactMultiSelect}from"./components/src/compact-multi-select/compact-multi-select.js";export{DateRangePicker}from"./components/src/date-range-picker/date-range-picker.js";export{ExpandableTable}from"./components/src/expandable-table/expandable-table.js";export{Chip}from"./components/src/chip/chip.js";export{SegmentedToggle}from"./components/src/segmented-toggle/segmented-toggle.js";export{Skeleton}from"./components/src/skeleton/skeleton.js";export{DatePicker}from"./components/src/date-picker/date-picker.js";export{TimePicker}from"./components/src/time-picker/time-picker.js";export{ExpandableSearch}from"./components/src/expandable-search/expandable-search.js";
2
2
  //# sourceMappingURL=index.js.map
@@ -34,3 +34,4 @@ 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";
@@ -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 {};