@tonyarbor/components 0.1.0 → 0.2.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/dist/Banner.d.mts +59 -0
- package/dist/Banner.d.ts +59 -0
- package/dist/Banner.js +222 -0
- package/dist/Banner.js.map +1 -0
- package/dist/Banner.mjs +7 -0
- package/dist/Banner.mjs.map +1 -0
- package/dist/Checkbox.d.mts +52 -0
- package/dist/Checkbox.d.ts +52 -0
- package/dist/Checkbox.js +194 -0
- package/dist/Checkbox.js.map +1 -0
- package/dist/Checkbox.mjs +7 -0
- package/dist/Checkbox.mjs.map +1 -0
- package/dist/Combobox.d.mts +67 -0
- package/dist/Combobox.d.ts +67 -0
- package/dist/Combobox.js +329 -0
- package/dist/Combobox.js.map +1 -0
- package/dist/Combobox.mjs +7 -0
- package/dist/Combobox.mjs.map +1 -0
- package/dist/DatePicker.d.mts +68 -0
- package/dist/DatePicker.d.ts +68 -0
- package/dist/DatePicker.js +490 -0
- package/dist/DatePicker.js.map +1 -0
- package/dist/DatePicker.mjs +7 -0
- package/dist/DatePicker.mjs.map +1 -0
- package/dist/NumericInput.d.mts +68 -0
- package/dist/NumericInput.d.ts +68 -0
- package/dist/NumericInput.js +319 -0
- package/dist/NumericInput.js.map +1 -0
- package/dist/NumericInput.mjs +7 -0
- package/dist/NumericInput.mjs.map +1 -0
- package/dist/Pagination.d.mts +36 -0
- package/dist/Pagination.d.ts +36 -0
- package/dist/Pagination.js +301 -0
- package/dist/Pagination.js.map +1 -0
- package/dist/Pagination.mjs +7 -0
- package/dist/Pagination.mjs.map +1 -0
- package/dist/Radio.d.mts +48 -0
- package/dist/Radio.d.ts +48 -0
- package/dist/Radio.js +194 -0
- package/dist/Radio.js.map +1 -0
- package/dist/Radio.mjs +7 -0
- package/dist/Radio.mjs.map +1 -0
- package/dist/Table.d.mts +80 -0
- package/dist/Table.d.ts +80 -0
- package/dist/Table.js +347 -0
- package/dist/Table.js.map +1 -0
- package/dist/Table.mjs +8 -0
- package/dist/Table.mjs.map +1 -0
- package/dist/TableControls.d.mts +76 -0
- package/dist/TableControls.d.ts +76 -0
- package/dist/TableControls.js +461 -0
- package/dist/TableControls.js.map +1 -0
- package/dist/TableControls.mjs +7 -0
- package/dist/TableControls.mjs.map +1 -0
- package/dist/TableFooterPagination.d.mts +56 -0
- package/dist/TableFooterPagination.d.ts +56 -0
- package/dist/TableFooterPagination.js +499 -0
- package/dist/TableFooterPagination.js.map +1 -0
- package/dist/TableFooterPagination.mjs +7 -0
- package/dist/TableFooterPagination.mjs.map +1 -0
- package/dist/Tabs.d.mts +50 -0
- package/dist/Tabs.d.ts +50 -0
- package/dist/Tabs.js +187 -0
- package/dist/Tabs.js.map +1 -0
- package/dist/Tabs.mjs +7 -0
- package/dist/Tabs.mjs.map +1 -0
- package/dist/TextArea.d.mts +64 -0
- package/dist/TextArea.d.ts +64 -0
- package/dist/TextArea.js +171 -0
- package/dist/TextArea.js.map +1 -0
- package/dist/TextArea.mjs +7 -0
- package/dist/TextArea.mjs.map +1 -0
- package/dist/Toast.d.mts +48 -0
- package/dist/Toast.d.ts +48 -0
- package/dist/Toast.js +169 -0
- package/dist/Toast.js.map +1 -0
- package/dist/Toast.mjs +7 -0
- package/dist/Toast.mjs.map +1 -0
- package/dist/Toggle.d.mts +48 -0
- package/dist/Toggle.d.ts +48 -0
- package/dist/Toggle.js +291 -0
- package/dist/Toggle.js.map +1 -0
- package/dist/Toggle.mjs +7 -0
- package/dist/Toggle.mjs.map +1 -0
- package/dist/Tooltip.d.mts +32 -0
- package/dist/Tooltip.d.ts +32 -0
- package/dist/Tooltip.js +109 -0
- package/dist/Tooltip.js.map +1 -0
- package/dist/Tooltip.mjs +7 -0
- package/dist/Tooltip.mjs.map +1 -0
- package/dist/chunk-52TG3BFX.mjs +463 -0
- package/dist/chunk-52TG3BFX.mjs.map +1 -0
- package/dist/chunk-5BUXFTPW.mjs +283 -0
- package/dist/chunk-5BUXFTPW.mjs.map +1 -0
- package/dist/chunk-7OWLBYNM.mjs +293 -0
- package/dist/chunk-7OWLBYNM.mjs.map +1 -0
- package/dist/chunk-AI2U34CF.mjs +159 -0
- package/dist/chunk-AI2U34CF.mjs.map +1 -0
- package/dist/chunk-C25FFMRQ.mjs +255 -0
- package/dist/chunk-C25FFMRQ.mjs.map +1 -0
- package/dist/chunk-CUTYEIFE.mjs +158 -0
- package/dist/chunk-CUTYEIFE.mjs.map +1 -0
- package/dist/chunk-DULH2KRW.mjs +133 -0
- package/dist/chunk-DULH2KRW.mjs.map +1 -0
- package/dist/chunk-G5NVKF2G.mjs +434 -0
- package/dist/chunk-G5NVKF2G.mjs.map +1 -0
- package/dist/chunk-M6DVBEEL.mjs +158 -0
- package/dist/chunk-M6DVBEEL.mjs.map +1 -0
- package/dist/chunk-MBUMR2XJ.mjs +135 -0
- package/dist/chunk-MBUMR2XJ.mjs.map +1 -0
- package/dist/chunk-MNH2TGUX.mjs +73 -0
- package/dist/chunk-MNH2TGUX.mjs.map +1 -0
- package/dist/chunk-RRMG2SSZ.mjs +265 -0
- package/dist/chunk-RRMG2SSZ.mjs.map +1 -0
- package/dist/chunk-U4JXKZZG.mjs +186 -0
- package/dist/chunk-U4JXKZZG.mjs.map +1 -0
- package/dist/chunk-W55QJIAN.mjs +467 -0
- package/dist/chunk-W55QJIAN.mjs.map +1 -0
- package/dist/chunk-YV4OXFIM.mjs +151 -0
- package/dist/chunk-YV4OXFIM.mjs.map +1 -0
- package/dist/index.d.mts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +3559 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +61 -1
- package/package.json +81 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/Checkbox/index.ts","../src/Checkbox/Checkbox.tsx"],"sourcesContent":["export { Checkbox } from './Checkbox';\nexport type { CheckboxProps } from './Checkbox';\n","import * as React from 'react';\nimport { clsx } from 'clsx';\nimport { Check, Minus } from 'lucide-react';\n\nexport interface CheckboxProps {\n /**\n * The label for the checkbox\n */\n label?: string;\n /**\n * Whether the checkbox is checked\n */\n checked?: boolean;\n /**\n * Callback when checked state changes\n */\n onChange?: (checked: boolean) => void;\n /**\n * Whether the checkbox is disabled\n */\n disabled?: boolean;\n /**\n * Custom className\n */\n className?: string;\n /**\n * Custom style\n */\n style?: React.CSSProperties;\n /**\n * Test ID for testing\n */\n 'data-testid'?: string;\n /**\n * Name attribute for form submission\n */\n name?: string;\n /**\n * Value attribute for form submission\n */\n value?: string;\n /**\n * Indeterminate state (shows minus icon)\n */\n indeterminate?: boolean;\n}\n\nconst checkboxStyles: React.CSSProperties = {\n width: '16px',\n height: '16px',\n border: '1px solid #7e7e7e', // grey-500\n borderRadius: '4px',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n cursor: 'pointer',\n transition: 'all 0.2s ease-in-out',\n flexShrink: 0,\n backgroundColor: '#ffffff',\n};\n\nconst checkedStyles: React.CSSProperties = {\n backgroundColor: '#0e8a0e', // brand-600\n border: '1px solid #0e8a0e',\n};\n\nconst checkedHoverStyles: React.CSSProperties = {\n backgroundColor: '#005700', // brand-800\n border: '1px solid #005700',\n};\n\nconst uncheckedHoverStyles: React.CSSProperties = {\n border: '1px solid #474747', // grey-700\n};\n\nconst labelStyles: React.CSSProperties = {\n fontSize: '13px',\n color: '#2f2f2f',\n cursor: 'pointer',\n userSelect: 'none' as const,\n fontFamily: \"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n};\n\nconst wrapperStyles: React.CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n};\n\n/**\n * Checkbox component - Arbor Design System\n *\n * A checkbox input with label support.\n */\nexport const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(\n (\n {\n label,\n checked = false,\n onChange,\n disabled = false,\n className,\n style,\n 'data-testid': dataTestId,\n name,\n value,\n indeterminate = false,\n },\n ref\n ) => {\n const [isFocused, setIsFocused] = React.useState(false);\n const [isHovered, setIsHovered] = React.useState(false);\n const checkboxId = React.useId();\n const innerRef = React.useRef<HTMLInputElement | null>(null);\n\n // Merge refs\n React.useEffect(() => {\n const node = innerRef.current;\n if (node) {\n // Set indeterminate property on the native input element\n node.indeterminate = indeterminate;\n\n // Forward to external ref if provided\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n (ref as React.MutableRefObject<HTMLInputElement | null>).current = node;\n }\n }\n }, [indeterminate, ref]);\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n if (!disabled) {\n onChange?.(e.target.checked);\n }\n };\n\n const boxStyle: React.CSSProperties = {\n ...checkboxStyles,\n ...((checked || indeterminate) && !disabled && checkedStyles),\n ...(isHovered && !disabled && !(checked || indeterminate) && uncheckedHoverStyles),\n ...(isHovered && !disabled && (checked || indeterminate) && checkedHoverStyles),\n ...(disabled && !checked && !indeterminate && { backgroundColor: '#efefef', border: '1px solid #b3b3b3' }),\n ...(disabled && (checked || indeterminate) && { backgroundColor: '#b3b3b3', border: '1px solid #b3b3b3' }),\n ...(isFocused && !disabled && {\n boxShadow: '0px 0px 0px 3px #3cad51',\n }),\n };\n\n const checkmarkColor = '#ffffff';\n\n return (\n <div\n className={clsx('arbor-checkbox-wrapper', className)}\n style={{ ...wrapperStyles, ...style }}\n data-testid={dataTestId}\n >\n <input\n ref={innerRef}\n id={checkboxId}\n type=\"checkbox\"\n checked={checked}\n onChange={handleChange}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n disabled={disabled}\n name={name}\n value={value}\n style={{\n position: 'absolute',\n opacity: 0,\n width: 0,\n height: 0,\n }}\n aria-checked={indeterminate ? 'mixed' : checked}\n />\n <label\n htmlFor={checkboxId}\n onMouseEnter={() => !disabled && setIsHovered(true)}\n onMouseLeave={() => !disabled && setIsHovered(false)}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n cursor: disabled ? 'not-allowed' : 'pointer',\n }}\n >\n <div style={boxStyle}>\n {(checked || indeterminate) && (\n indeterminate ? (\n <Minus size={12} color={checkmarkColor} strokeWidth={3} />\n ) : (\n <Check size={16} color={checkmarkColor} strokeWidth={3} />\n )\n )}\n </div>\n {label && (\n <span\n style={{\n ...labelStyles,\n color: disabled ? '#7e7e7e' : '#2f2f2f',\n cursor: disabled ? 'not-allowed' : 'pointer',\n }}\n >\n {label}\n </span>\n )}\n </label>\n </div>\n );\n }\n);\n\nCheckbox.displayName = 'Checkbox';\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type ComboboxOption = {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
};
|
|
7
|
+
type ComboboxState = 'default' | 'error' | 'success';
|
|
8
|
+
interface ComboboxProps {
|
|
9
|
+
/**
|
|
10
|
+
* The label for the combobox
|
|
11
|
+
*/
|
|
12
|
+
label?: string;
|
|
13
|
+
/**
|
|
14
|
+
* The placeholder text
|
|
15
|
+
*/
|
|
16
|
+
placeholder?: string;
|
|
17
|
+
/**
|
|
18
|
+
* The available options
|
|
19
|
+
*/
|
|
20
|
+
options: ComboboxOption[];
|
|
21
|
+
/**
|
|
22
|
+
* The selected value
|
|
23
|
+
*/
|
|
24
|
+
value?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Callback when value changes
|
|
27
|
+
*/
|
|
28
|
+
onChange?: (value: string | undefined) => void;
|
|
29
|
+
/**
|
|
30
|
+
* The validation state
|
|
31
|
+
* @default 'default'
|
|
32
|
+
*/
|
|
33
|
+
state?: ComboboxState;
|
|
34
|
+
/**
|
|
35
|
+
* Optional error message
|
|
36
|
+
*/
|
|
37
|
+
error?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Optional helper text
|
|
40
|
+
*/
|
|
41
|
+
helperText?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Whether the combobox is disabled
|
|
44
|
+
*/
|
|
45
|
+
disabled?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Custom className
|
|
48
|
+
*/
|
|
49
|
+
className?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Custom style
|
|
52
|
+
*/
|
|
53
|
+
style?: React.CSSProperties;
|
|
54
|
+
/**
|
|
55
|
+
* Test ID for testing
|
|
56
|
+
*/
|
|
57
|
+
'data-testid'?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Combobox component - Arbor Design System
|
|
61
|
+
*
|
|
62
|
+
* A searchable select/autocomplete component with filtering.
|
|
63
|
+
* Supports labels, validation states, and helper text.
|
|
64
|
+
*/
|
|
65
|
+
declare const Combobox: React.ForwardRefExoticComponent<ComboboxProps & React.RefAttributes<HTMLDivElement>>;
|
|
66
|
+
|
|
67
|
+
export { Combobox, type ComboboxOption, type ComboboxProps, type ComboboxState };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type ComboboxOption = {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
};
|
|
7
|
+
type ComboboxState = 'default' | 'error' | 'success';
|
|
8
|
+
interface ComboboxProps {
|
|
9
|
+
/**
|
|
10
|
+
* The label for the combobox
|
|
11
|
+
*/
|
|
12
|
+
label?: string;
|
|
13
|
+
/**
|
|
14
|
+
* The placeholder text
|
|
15
|
+
*/
|
|
16
|
+
placeholder?: string;
|
|
17
|
+
/**
|
|
18
|
+
* The available options
|
|
19
|
+
*/
|
|
20
|
+
options: ComboboxOption[];
|
|
21
|
+
/**
|
|
22
|
+
* The selected value
|
|
23
|
+
*/
|
|
24
|
+
value?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Callback when value changes
|
|
27
|
+
*/
|
|
28
|
+
onChange?: (value: string | undefined) => void;
|
|
29
|
+
/**
|
|
30
|
+
* The validation state
|
|
31
|
+
* @default 'default'
|
|
32
|
+
*/
|
|
33
|
+
state?: ComboboxState;
|
|
34
|
+
/**
|
|
35
|
+
* Optional error message
|
|
36
|
+
*/
|
|
37
|
+
error?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Optional helper text
|
|
40
|
+
*/
|
|
41
|
+
helperText?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Whether the combobox is disabled
|
|
44
|
+
*/
|
|
45
|
+
disabled?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Custom className
|
|
48
|
+
*/
|
|
49
|
+
className?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Custom style
|
|
52
|
+
*/
|
|
53
|
+
style?: React.CSSProperties;
|
|
54
|
+
/**
|
|
55
|
+
* Test ID for testing
|
|
56
|
+
*/
|
|
57
|
+
'data-testid'?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Combobox component - Arbor Design System
|
|
61
|
+
*
|
|
62
|
+
* A searchable select/autocomplete component with filtering.
|
|
63
|
+
* Supports labels, validation states, and helper text.
|
|
64
|
+
*/
|
|
65
|
+
declare const Combobox: React.ForwardRefExoticComponent<ComboboxProps & React.RefAttributes<HTMLDivElement>>;
|
|
66
|
+
|
|
67
|
+
export { Combobox, type ComboboxOption, type ComboboxProps, type ComboboxState };
|
package/dist/Combobox.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/Combobox/index.ts
|
|
31
|
+
var Combobox_exports = {};
|
|
32
|
+
__export(Combobox_exports, {
|
|
33
|
+
Combobox: () => Combobox
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(Combobox_exports);
|
|
36
|
+
|
|
37
|
+
// src/Combobox/Combobox.tsx
|
|
38
|
+
var React = __toESM(require("react"));
|
|
39
|
+
var import_clsx = require("clsx");
|
|
40
|
+
var import_lucide_react = require("lucide-react");
|
|
41
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
42
|
+
var comboboxStyles = {
|
|
43
|
+
base: {
|
|
44
|
+
width: "100%",
|
|
45
|
+
height: "36px",
|
|
46
|
+
fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
47
|
+
backgroundColor: "#ffffff",
|
|
48
|
+
borderRadius: "8px",
|
|
49
|
+
transition: "all 0.2s ease-in-out",
|
|
50
|
+
outline: "none",
|
|
51
|
+
fontSize: "13px",
|
|
52
|
+
padding: "8px",
|
|
53
|
+
paddingRight: "32px",
|
|
54
|
+
margin: "0",
|
|
55
|
+
display: "flex",
|
|
56
|
+
alignItems: "center",
|
|
57
|
+
cursor: "pointer",
|
|
58
|
+
position: "relative"
|
|
59
|
+
},
|
|
60
|
+
states: {
|
|
61
|
+
default: {
|
|
62
|
+
border: "1px solid #d1d1d1",
|
|
63
|
+
// grey-300
|
|
64
|
+
color: "#2f2f2f"
|
|
65
|
+
// grey-900
|
|
66
|
+
},
|
|
67
|
+
defaultFocus: {
|
|
68
|
+
borderColor: "#3cad51",
|
|
69
|
+
// brand-500
|
|
70
|
+
outline: "3px solid rgba(60, 173, 81, 0.2)"
|
|
71
|
+
},
|
|
72
|
+
error: {
|
|
73
|
+
border: "1px solid #c93232",
|
|
74
|
+
// destructive-500
|
|
75
|
+
color: "#2f2f2f"
|
|
76
|
+
},
|
|
77
|
+
errorFocus: {
|
|
78
|
+
borderColor: "#c93232",
|
|
79
|
+
outline: "3px solid rgba(201, 50, 50, 0.2)"
|
|
80
|
+
},
|
|
81
|
+
success: {
|
|
82
|
+
border: "1px solid #16a33d",
|
|
83
|
+
// success-500
|
|
84
|
+
color: "#2f2f2f"
|
|
85
|
+
},
|
|
86
|
+
successFocus: {
|
|
87
|
+
borderColor: "#16a33d",
|
|
88
|
+
outline: "3px solid rgba(22, 163, 61, 0.2)"
|
|
89
|
+
},
|
|
90
|
+
disabled: {
|
|
91
|
+
backgroundColor: "#f8f8f8",
|
|
92
|
+
// grey-050
|
|
93
|
+
borderColor: "#efefef",
|
|
94
|
+
// grey-100
|
|
95
|
+
color: "#7e7e7e",
|
|
96
|
+
// grey-500
|
|
97
|
+
cursor: "not-allowed"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
var labelStyles = {
|
|
102
|
+
display: "block",
|
|
103
|
+
fontSize: "13px",
|
|
104
|
+
fontWeight: "600",
|
|
105
|
+
color: "#2f2f2f",
|
|
106
|
+
marginBottom: "4px",
|
|
107
|
+
fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif"
|
|
108
|
+
};
|
|
109
|
+
var helperTextStyles = {
|
|
110
|
+
fontSize: "13px",
|
|
111
|
+
margin: "0",
|
|
112
|
+
marginTop: "2px",
|
|
113
|
+
color: "#595959",
|
|
114
|
+
fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
115
|
+
lineHeight: "1.4"
|
|
116
|
+
};
|
|
117
|
+
var errorTextStyles = {
|
|
118
|
+
...helperTextStyles,
|
|
119
|
+
color: "#a62323",
|
|
120
|
+
// destructive-600
|
|
121
|
+
display: "flex",
|
|
122
|
+
alignItems: "center",
|
|
123
|
+
gap: "4px"
|
|
124
|
+
};
|
|
125
|
+
var dropdownStyles = {
|
|
126
|
+
position: "absolute",
|
|
127
|
+
top: "calc(100% + 4px)",
|
|
128
|
+
left: "0",
|
|
129
|
+
right: "0",
|
|
130
|
+
backgroundColor: "#ffffff",
|
|
131
|
+
border: "1px solid #d1d1d1",
|
|
132
|
+
borderRadius: "8px",
|
|
133
|
+
maxHeight: "200px",
|
|
134
|
+
overflowY: "auto",
|
|
135
|
+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.1)",
|
|
136
|
+
zIndex: 1e3
|
|
137
|
+
};
|
|
138
|
+
var optionStyles = {
|
|
139
|
+
padding: "8px 12px",
|
|
140
|
+
fontSize: "13px",
|
|
141
|
+
cursor: "pointer",
|
|
142
|
+
display: "flex",
|
|
143
|
+
alignItems: "center",
|
|
144
|
+
justifyContent: "space-between",
|
|
145
|
+
fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
|
|
146
|
+
color: "#2f2f2f"
|
|
147
|
+
// grey-900
|
|
148
|
+
};
|
|
149
|
+
var Combobox = React.forwardRef(
|
|
150
|
+
({
|
|
151
|
+
label,
|
|
152
|
+
placeholder = "default-text",
|
|
153
|
+
options,
|
|
154
|
+
value,
|
|
155
|
+
onChange,
|
|
156
|
+
state = "default",
|
|
157
|
+
error,
|
|
158
|
+
helperText,
|
|
159
|
+
disabled = false,
|
|
160
|
+
className,
|
|
161
|
+
style,
|
|
162
|
+
"data-testid": dataTestId
|
|
163
|
+
}, ref) => {
|
|
164
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
|
165
|
+
const [searchQuery, setSearchQuery] = React.useState("");
|
|
166
|
+
const [isFocused, setIsFocused] = React.useState(false);
|
|
167
|
+
const inputRef = React.useRef(null);
|
|
168
|
+
const dropdownRef = React.useRef(null);
|
|
169
|
+
const wrapperRef = React.useRef(null);
|
|
170
|
+
const comboboxId = React.useId();
|
|
171
|
+
const helperTextId = React.useId();
|
|
172
|
+
const errorId = React.useId();
|
|
173
|
+
const selectedOption = options.find((opt) => opt.value === value);
|
|
174
|
+
const filteredOptions = React.useMemo(() => {
|
|
175
|
+
if (!searchQuery) return options;
|
|
176
|
+
return options.filter(
|
|
177
|
+
(option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())
|
|
178
|
+
);
|
|
179
|
+
}, [options, searchQuery]);
|
|
180
|
+
React.useEffect(() => {
|
|
181
|
+
const handleClickOutside = (event) => {
|
|
182
|
+
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
|
|
183
|
+
setIsOpen(false);
|
|
184
|
+
setSearchQuery("");
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
188
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
189
|
+
}, []);
|
|
190
|
+
const handleInputChange = (e) => {
|
|
191
|
+
setSearchQuery(e.target.value);
|
|
192
|
+
if (!isOpen) setIsOpen(true);
|
|
193
|
+
};
|
|
194
|
+
const handleSelectOption = (optionValue) => {
|
|
195
|
+
onChange?.(optionValue);
|
|
196
|
+
setIsOpen(false);
|
|
197
|
+
setSearchQuery("");
|
|
198
|
+
inputRef.current?.blur();
|
|
199
|
+
};
|
|
200
|
+
const handleClear = (e) => {
|
|
201
|
+
e.stopPropagation();
|
|
202
|
+
onChange?.(void 0);
|
|
203
|
+
setSearchQuery("");
|
|
204
|
+
inputRef.current?.focus();
|
|
205
|
+
};
|
|
206
|
+
const handleInputFocus = () => {
|
|
207
|
+
setIsFocused(true);
|
|
208
|
+
if (!disabled) setIsOpen(true);
|
|
209
|
+
};
|
|
210
|
+
const handleInputBlur = () => {
|
|
211
|
+
setIsFocused(false);
|
|
212
|
+
setTimeout(() => {
|
|
213
|
+
if (!wrapperRef.current?.contains(document.activeElement)) {
|
|
214
|
+
setSearchQuery("");
|
|
215
|
+
}
|
|
216
|
+
}, 200);
|
|
217
|
+
};
|
|
218
|
+
const currentState = error ? "error" : state;
|
|
219
|
+
const stateStyles = comboboxStyles.states[currentState];
|
|
220
|
+
const focusStyles = currentState === "error" ? comboboxStyles.states.errorFocus : currentState === "success" ? comboboxStyles.states.successFocus : comboboxStyles.states.defaultFocus;
|
|
221
|
+
const inputWrapperStyle = {
|
|
222
|
+
...comboboxStyles.base,
|
|
223
|
+
...stateStyles,
|
|
224
|
+
...isFocused && !disabled && focusStyles,
|
|
225
|
+
...disabled && comboboxStyles.states.disabled
|
|
226
|
+
};
|
|
227
|
+
const displayValue = selectedOption ? selectedOption.label : "";
|
|
228
|
+
const showPlaceholder = !selectedOption && !searchQuery && !isFocused;
|
|
229
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: (0, import_clsx.clsx)("arbor-combobox-wrapper", className), style, ref: wrapperRef, "data-testid": dataTestId, children: [
|
|
230
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: comboboxId, style: labelStyles, children: label }),
|
|
231
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { position: "relative" }, ref, children: [
|
|
232
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: inputWrapperStyle, children: [
|
|
233
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
234
|
+
"input",
|
|
235
|
+
{
|
|
236
|
+
ref: inputRef,
|
|
237
|
+
id: comboboxId,
|
|
238
|
+
type: "text",
|
|
239
|
+
value: searchQuery || displayValue,
|
|
240
|
+
onChange: handleInputChange,
|
|
241
|
+
onFocus: handleInputFocus,
|
|
242
|
+
onBlur: handleInputBlur,
|
|
243
|
+
placeholder: showPlaceholder ? placeholder : "",
|
|
244
|
+
disabled,
|
|
245
|
+
"aria-invalid": error ? "true" : "false",
|
|
246
|
+
"aria-describedby": error ? errorId : helperText ? helperTextId : void 0,
|
|
247
|
+
"aria-expanded": isOpen,
|
|
248
|
+
"aria-autocomplete": "list",
|
|
249
|
+
role: "combobox",
|
|
250
|
+
style: {
|
|
251
|
+
border: "none",
|
|
252
|
+
outline: "none",
|
|
253
|
+
background: "transparent",
|
|
254
|
+
flex: 1,
|
|
255
|
+
fontSize: "13px",
|
|
256
|
+
padding: 0,
|
|
257
|
+
margin: 0,
|
|
258
|
+
color: showPlaceholder ? "#7e7e7e" : "#2f2f2f",
|
|
259
|
+
fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif"
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
),
|
|
263
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: "4px", position: "absolute", right: "8px" }, children: [
|
|
264
|
+
selectedOption && !disabled && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
265
|
+
"button",
|
|
266
|
+
{
|
|
267
|
+
type: "button",
|
|
268
|
+
onClick: handleClear,
|
|
269
|
+
style: {
|
|
270
|
+
border: "none",
|
|
271
|
+
background: "transparent",
|
|
272
|
+
padding: "2px",
|
|
273
|
+
cursor: "pointer",
|
|
274
|
+
display: "flex",
|
|
275
|
+
alignItems: "center",
|
|
276
|
+
color: "#7e7e7e"
|
|
277
|
+
},
|
|
278
|
+
"aria-label": "Clear selection",
|
|
279
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { size: 16 })
|
|
280
|
+
}
|
|
281
|
+
),
|
|
282
|
+
currentState === "success" && !isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Check, { size: 16, color: "#16a33d" }),
|
|
283
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
284
|
+
import_lucide_react.ChevronDown,
|
|
285
|
+
{
|
|
286
|
+
size: 16,
|
|
287
|
+
color: "#7e7e7e",
|
|
288
|
+
style: {
|
|
289
|
+
transform: isOpen ? "rotate(180deg)" : "rotate(0deg)",
|
|
290
|
+
transition: "transform 0.2s"
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
)
|
|
294
|
+
] })
|
|
295
|
+
] }),
|
|
296
|
+
isOpen && !disabled && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: dropdownRef, style: dropdownStyles, children: filteredOptions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...optionStyles, color: "#7e7e7e", cursor: "default" }, children: "No options found" }) : filteredOptions.map((option) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
297
|
+
"div",
|
|
298
|
+
{
|
|
299
|
+
onClick: () => handleSelectOption(option.value),
|
|
300
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
301
|
+
style: {
|
|
302
|
+
...optionStyles,
|
|
303
|
+
backgroundColor: option.value === value ? "#f8f8f8" : "transparent"
|
|
304
|
+
},
|
|
305
|
+
onMouseEnter: (e) => {
|
|
306
|
+
e.currentTarget.style.backgroundColor = "#f8f8f8";
|
|
307
|
+
},
|
|
308
|
+
onMouseLeave: (e) => {
|
|
309
|
+
e.currentTarget.style.backgroundColor = option.value === value ? "#f8f8f8" : "transparent";
|
|
310
|
+
},
|
|
311
|
+
children: [
|
|
312
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: option.label }),
|
|
313
|
+
option.value === value && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Check, { size: 16, color: "#16a33d" })
|
|
314
|
+
]
|
|
315
|
+
},
|
|
316
|
+
option.value
|
|
317
|
+
)) })
|
|
318
|
+
] }),
|
|
319
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { id: errorId, style: errorTextStyles, role: "alert", children: error }),
|
|
320
|
+
!error && helperText && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { id: helperTextId, style: helperTextStyles, children: helperText })
|
|
321
|
+
] });
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
Combobox.displayName = "Combobox";
|
|
325
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
326
|
+
0 && (module.exports = {
|
|
327
|
+
Combobox
|
|
328
|
+
});
|
|
329
|
+
//# sourceMappingURL=Combobox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/Combobox/index.ts","../src/Combobox/Combobox.tsx"],"sourcesContent":["export { Combobox } from './Combobox';\nexport type { ComboboxProps, ComboboxOption, ComboboxState } from './Combobox';\n","import * as React from 'react';\nimport { clsx } from 'clsx';\nimport { X, ChevronDown, Check } from 'lucide-react';\n\nexport type ComboboxOption = {\n value: string;\n label: string;\n};\n\nexport type ComboboxState = 'default' | 'error' | 'success';\n\nexport interface ComboboxProps {\n /**\n * The label for the combobox\n */\n label?: string;\n /**\n * The placeholder text\n */\n placeholder?: string;\n /**\n * The available options\n */\n options: ComboboxOption[];\n /**\n * The selected value\n */\n value?: string;\n /**\n * Callback when value changes\n */\n onChange?: (value: string | undefined) => void;\n /**\n * The validation state\n * @default 'default'\n */\n state?: ComboboxState;\n /**\n * Optional error message\n */\n error?: string;\n /**\n * Optional helper text\n */\n helperText?: string;\n /**\n * Whether the combobox is disabled\n */\n disabled?: boolean;\n /**\n * Custom className\n */\n className?: string;\n /**\n * Custom style\n */\n style?: React.CSSProperties;\n /**\n * Test ID for testing\n */\n 'data-testid'?: string;\n}\n\nconst comboboxStyles = {\n base: {\n width: '100%',\n height: '36px',\n fontFamily: \"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n backgroundColor: '#ffffff',\n borderRadius: '8px',\n transition: 'all 0.2s ease-in-out',\n outline: 'none',\n fontSize: '13px',\n padding: '8px',\n paddingRight: '32px',\n margin: '0',\n display: 'flex',\n alignItems: 'center',\n cursor: 'pointer',\n position: 'relative' as const,\n },\n states: {\n default: {\n border: '1px solid #d1d1d1', // grey-300\n color: '#2f2f2f', // grey-900\n },\n defaultFocus: {\n borderColor: '#3cad51', // brand-500\n outline: '3px solid rgba(60, 173, 81, 0.2)',\n },\n error: {\n border: '1px solid #c93232', // destructive-500\n color: '#2f2f2f',\n },\n errorFocus: {\n borderColor: '#c93232',\n outline: '3px solid rgba(201, 50, 50, 0.2)',\n },\n success: {\n border: '1px solid #16a33d', // success-500\n color: '#2f2f2f',\n },\n successFocus: {\n borderColor: '#16a33d',\n outline: '3px solid rgba(22, 163, 61, 0.2)',\n },\n disabled: {\n backgroundColor: '#f8f8f8', // grey-050\n borderColor: '#efefef', // grey-100\n color: '#7e7e7e', // grey-500\n cursor: 'not-allowed',\n },\n },\n};\n\nconst labelStyles: React.CSSProperties = {\n display: 'block',\n fontSize: '13px',\n fontWeight: '600',\n color: '#2f2f2f',\n marginBottom: '4px',\n fontFamily: \"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n};\n\nconst helperTextStyles: React.CSSProperties = {\n fontSize: '13px',\n margin: '0',\n marginTop: '2px',\n color: '#595959',\n fontFamily: \"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n lineHeight: '1.4',\n};\n\nconst errorTextStyles: React.CSSProperties = {\n ...helperTextStyles,\n color: '#a62323', // destructive-600\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n};\n\nconst dropdownStyles: React.CSSProperties = {\n position: 'absolute',\n top: 'calc(100% + 4px)',\n left: '0',\n right: '0',\n backgroundColor: '#ffffff',\n border: '1px solid #d1d1d1',\n borderRadius: '8px',\n maxHeight: '200px',\n overflowY: 'auto',\n boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',\n zIndex: 1000,\n};\n\nconst optionStyles: React.CSSProperties = {\n padding: '8px 12px',\n fontSize: '13px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n fontFamily: \"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n color: '#2f2f2f', // grey-900\n};\n\n/**\n * Combobox component - Arbor Design System\n *\n * A searchable select/autocomplete component with filtering.\n * Supports labels, validation states, and helper text.\n */\nexport const Combobox = React.forwardRef<HTMLDivElement, ComboboxProps>(\n (\n {\n label,\n placeholder = 'default-text',\n options,\n value,\n onChange,\n state = 'default',\n error,\n helperText,\n disabled = false,\n className,\n style,\n 'data-testid': dataTestId,\n },\n ref\n ) => {\n const [isOpen, setIsOpen] = React.useState(false);\n const [searchQuery, setSearchQuery] = React.useState('');\n const [isFocused, setIsFocused] = React.useState(false);\n const inputRef = React.useRef<HTMLInputElement>(null);\n const dropdownRef = React.useRef<HTMLDivElement>(null);\n const wrapperRef = React.useRef<HTMLDivElement>(null);\n\n const comboboxId = React.useId();\n const helperTextId = React.useId();\n const errorId = React.useId();\n\n const selectedOption = options.find((opt) => opt.value === value);\n\n const filteredOptions = React.useMemo(() => {\n if (!searchQuery) return options;\n return options.filter((option) =>\n option.label.toLowerCase().includes(searchQuery.toLowerCase())\n );\n }, [options, searchQuery]);\n\n // Close dropdown when clicking outside\n React.useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n wrapperRef.current &&\n !wrapperRef.current.contains(event.target as Node)\n ) {\n setIsOpen(false);\n setSearchQuery('');\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setSearchQuery(e.target.value);\n if (!isOpen) setIsOpen(true);\n };\n\n const handleSelectOption = (optionValue: string) => {\n onChange?.(optionValue);\n setIsOpen(false);\n setSearchQuery('');\n inputRef.current?.blur();\n };\n\n const handleClear = (e: React.MouseEvent) => {\n e.stopPropagation();\n onChange?.(undefined);\n setSearchQuery('');\n inputRef.current?.focus();\n };\n\n const handleInputFocus = () => {\n setIsFocused(true);\n if (!disabled) setIsOpen(true);\n };\n\n const handleInputBlur = () => {\n setIsFocused(false);\n // Delay to allow click on option\n setTimeout(() => {\n if (!wrapperRef.current?.contains(document.activeElement)) {\n setSearchQuery('');\n }\n }, 200);\n };\n\n const currentState = error ? 'error' : state;\n const stateStyles = comboboxStyles.states[currentState];\n const focusStyles =\n currentState === 'error'\n ? comboboxStyles.states.errorFocus\n : currentState === 'success'\n ? comboboxStyles.states.successFocus\n : comboboxStyles.states.defaultFocus;\n\n const inputWrapperStyle: React.CSSProperties = {\n ...comboboxStyles.base,\n ...stateStyles,\n ...(isFocused && !disabled && focusStyles),\n ...(disabled && comboboxStyles.states.disabled),\n };\n\n const displayValue = selectedOption ? selectedOption.label : '';\n const showPlaceholder = !selectedOption && !searchQuery && !isFocused;\n\n return (\n <div className={clsx('arbor-combobox-wrapper', className)} style={style} ref={wrapperRef} data-testid={dataTestId}>\n {label && (\n <label htmlFor={comboboxId} style={labelStyles}>\n {label}\n </label>\n )}\n\n <div style={{ position: 'relative' }} ref={ref}>\n <div style={inputWrapperStyle}>\n <input\n ref={inputRef}\n id={comboboxId}\n type=\"text\"\n value={searchQuery || displayValue}\n onChange={handleInputChange}\n onFocus={handleInputFocus}\n onBlur={handleInputBlur}\n placeholder={showPlaceholder ? placeholder : ''}\n disabled={disabled}\n aria-invalid={error ? 'true' : 'false'}\n aria-describedby={error ? errorId : helperText ? helperTextId : undefined}\n aria-expanded={isOpen}\n aria-autocomplete=\"list\"\n role=\"combobox\"\n style={{\n border: 'none',\n outline: 'none',\n background: 'transparent',\n flex: 1,\n fontSize: '13px',\n padding: 0,\n margin: 0,\n color: showPlaceholder ? '#7e7e7e' : '#2f2f2f',\n fontFamily: \"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n }}\n />\n\n <div style={{ display: 'flex', alignItems: 'center', gap: '4px', position: 'absolute', right: '8px' }}>\n {selectedOption && !disabled && (\n <button\n type=\"button\"\n onClick={handleClear}\n style={{\n border: 'none',\n background: 'transparent',\n padding: '2px',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n color: '#7e7e7e',\n }}\n aria-label=\"Clear selection\"\n >\n <X size={16} />\n </button>\n )}\n\n {currentState === 'success' && !isOpen && (\n <Check size={16} color=\"#16a33d\" />\n )}\n\n <ChevronDown\n size={16}\n color=\"#7e7e7e\"\n style={{\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform 0.2s',\n }}\n />\n </div>\n </div>\n\n {isOpen && !disabled && (\n <div ref={dropdownRef} style={dropdownStyles}>\n {filteredOptions.length === 0 ? (\n <div style={{ ...optionStyles, color: '#7e7e7e', cursor: 'default' }}>\n No options found\n </div>\n ) : (\n filteredOptions.map((option) => (\n <div\n key={option.value}\n onClick={() => handleSelectOption(option.value)}\n onMouseDown={(e) => e.preventDefault()} // Prevent blur\n style={{\n ...optionStyles,\n backgroundColor: option.value === value ? '#f8f8f8' : 'transparent',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = '#f8f8f8';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor =\n option.value === value ? '#f8f8f8' : 'transparent';\n }}\n >\n <span>{option.label}</span>\n {option.value === value && <Check size={16} color=\"#16a33d\" />}\n </div>\n ))\n )}\n </div>\n )}\n </div>\n\n {error && (\n <p id={errorId} style={errorTextStyles} role=\"alert\">\n {error}\n </p>\n )}\n {!error && helperText && (\n <p id={helperTextId} style={helperTextStyles}>\n {helperText}\n </p>\n )}\n </div>\n );\n }\n);\n\nCombobox.displayName = 'Combobox';\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface DatePickerProps {
|
|
4
|
+
/**
|
|
5
|
+
* The selected date value
|
|
6
|
+
*/
|
|
7
|
+
value?: Date;
|
|
8
|
+
/**
|
|
9
|
+
* Callback when date changes
|
|
10
|
+
*/
|
|
11
|
+
onChange?: (date: Date | undefined) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Label for the input
|
|
14
|
+
*/
|
|
15
|
+
label?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Placeholder text
|
|
18
|
+
*/
|
|
19
|
+
placeholder?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Helper text below the input
|
|
22
|
+
*/
|
|
23
|
+
helperText?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Error message
|
|
26
|
+
*/
|
|
27
|
+
error?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Success state
|
|
30
|
+
*/
|
|
31
|
+
state?: 'default' | 'success' | 'error';
|
|
32
|
+
/**
|
|
33
|
+
* Whether the input is disabled
|
|
34
|
+
*/
|
|
35
|
+
disabled?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Custom className
|
|
38
|
+
*/
|
|
39
|
+
className?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Custom style
|
|
42
|
+
*/
|
|
43
|
+
style?: React.CSSProperties;
|
|
44
|
+
/**
|
|
45
|
+
* Test ID for testing
|
|
46
|
+
*/
|
|
47
|
+
'data-testid'?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Minimum selectable date
|
|
50
|
+
*/
|
|
51
|
+
minDate?: Date;
|
|
52
|
+
/**
|
|
53
|
+
* Maximum selectable date
|
|
54
|
+
*/
|
|
55
|
+
maxDate?: Date;
|
|
56
|
+
/**
|
|
57
|
+
* Date format string (default: dd/MM/yyyy)
|
|
58
|
+
*/
|
|
59
|
+
dateFormat?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* DatePicker component - Arbor Design System
|
|
63
|
+
*
|
|
64
|
+
* A date picker with calendar popup for selecting dates.
|
|
65
|
+
*/
|
|
66
|
+
declare const DatePicker: React.ForwardRefExoticComponent<DatePickerProps & React.RefAttributes<HTMLInputElement>>;
|
|
67
|
+
|
|
68
|
+
export { DatePicker, type DatePickerProps };
|