@donotdev/components 0.0.10 → 0.0.12
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/atomic/Accordion/index.d.ts +2 -16
- package/dist/atomic/Accordion/index.d.ts.map +1 -1
- package/dist/atomic/Accordion/index.js +4 -25
- package/dist/atomic/Alert/index.d.ts.map +1 -1
- package/dist/atomic/Alert/index.js +1 -1
- package/dist/atomic/Button/index.js +6 -3
- package/dist/atomic/Calendar/index.js +1 -1
- package/dist/atomic/CallToAction/index.d.ts.map +1 -1
- package/dist/atomic/CallToAction/index.js +1 -1
- package/dist/atomic/Collapsible/index.d.ts +12 -16
- package/dist/atomic/Collapsible/index.d.ts.map +1 -1
- package/dist/atomic/Collapsible/index.js +24 -24
- package/dist/atomic/Combobox/index.d.ts +9 -47
- package/dist/atomic/Combobox/index.d.ts.map +1 -1
- package/dist/atomic/Combobox/index.js +135 -87
- package/dist/atomic/Dialog/index.d.ts.map +1 -1
- package/dist/atomic/Dialog/index.js +1 -1
- package/dist/atomic/DropdownMenu/index.js +1 -1
- package/dist/atomic/Input/index.d.ts +1 -1
- package/dist/atomic/Input/index.d.ts.map +1 -1
- package/dist/atomic/Input/index.js +6 -22
- package/dist/atomic/Label/FloatingLabel.d.ts +31 -0
- package/dist/atomic/Label/FloatingLabel.d.ts.map +1 -0
- package/dist/atomic/Label/FloatingLabel.js +34 -0
- package/dist/atomic/Label/index.d.ts +5 -1
- package/dist/atomic/Label/index.d.ts.map +1 -1
- package/dist/atomic/Label/index.js +8 -2
- package/dist/atomic/PasswordInput/index.d.ts +9 -10
- package/dist/atomic/PasswordInput/index.d.ts.map +1 -1
- package/dist/atomic/PasswordInput/index.js +10 -30
- package/dist/atomic/Section/index.d.ts +25 -1
- package/dist/atomic/Section/index.d.ts.map +1 -1
- package/dist/atomic/Section/index.js +22 -4
- package/dist/atomic/Select/index.d.ts +3 -1
- package/dist/atomic/Select/index.d.ts.map +1 -1
- package/dist/atomic/Select/index.js +13 -24
- package/dist/atomic/Skeleton/index.d.ts.map +1 -1
- package/dist/atomic/Skeleton/index.js +6 -3
- package/dist/atomic/Switch/index.d.ts +18 -4
- package/dist/atomic/Switch/index.d.ts.map +1 -1
- package/dist/atomic/Switch/index.js +25 -6
- package/dist/atomic/Table/index.d.ts +17 -7
- package/dist/atomic/Table/index.d.ts.map +1 -1
- package/dist/atomic/Table/index.js +13 -3
- package/dist/atomic/Tooltip/index.d.ts.map +1 -1
- package/dist/atomic/Tooltip/index.js +6 -2
- package/dist/atomic/VideoPlayer/index.d.ts.map +1 -1
- package/dist/atomic/index.d.ts +2 -3
- package/dist/atomic/index.d.ts.map +1 -1
- package/dist/atomic/index.js +1 -2
- package/dist/hooks/useIntersectionObserver.js +3 -1
- package/dist/index.js +4 -4
- package/dist/styles/index.css +495 -81
- package/package.json +1 -1
- package/dist/atomic/Combobox/ComboboxPrimitive.d.ts +0 -18
- package/dist/atomic/Combobox/ComboboxPrimitive.d.ts.map +0 -1
- package/dist/atomic/Combobox/ComboboxPrimitive.js +0 -14
|
@@ -1,77 +1,64 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
// packages/components/src/atomic/Combobox/index.tsx
|
|
3
|
-
/**
|
|
4
|
-
* @fileoverview Combobox component
|
|
5
|
-
* @description Accessible combobox with search/filter functionality. Provides a prop-based implementation.
|
|
6
|
-
*
|
|
7
|
-
* @version 0.0.1
|
|
8
|
-
* @since 0.0.1
|
|
9
|
-
* @author AMBROISE PARK Consulting
|
|
10
|
-
*/
|
|
11
3
|
import { useState, useMemo, useRef, useEffect, useId, } from 'react';
|
|
12
|
-
import { Check, ChevronDown, X } from 'lucide-react';
|
|
4
|
+
import { Check, ChevronDown, Plus, X } from 'lucide-react';
|
|
5
|
+
import Spinner from '../Spinner';
|
|
6
|
+
import ScrollArea from '../ScrollArea';
|
|
13
7
|
import { cn } from '../../utils/helpers';
|
|
14
8
|
import { CONTROL_VARIANT } from '../../utils/constants';
|
|
15
|
-
import { ComboboxRootPrimitive, ComboboxTriggerPrimitive, ComboboxContentPrimitive, ComboboxAnchorPrimitive, } from './ComboboxPrimitive';
|
|
16
9
|
import Input from '../Input';
|
|
17
|
-
import Button from '../Button';
|
|
18
|
-
import Label from '../Label';
|
|
19
10
|
import './Combobox.css';
|
|
20
|
-
|
|
21
|
-
* Default filter function - case-insensitive label search
|
|
22
|
-
*/
|
|
23
|
-
const defaultFilterFn = (option, searchTerm) => {
|
|
24
|
-
return option.label.toLowerCase().includes(searchTerm.toLowerCase());
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* Accessible combobox component with search/filter functionality.
|
|
28
|
-
* Provides a prop-based implementation to abstract complexity.
|
|
29
|
-
*
|
|
30
|
-
* @component
|
|
31
|
-
* @example
|
|
32
|
-
* ```tsx
|
|
33
|
-
* <Combobox
|
|
34
|
-
* value={value}
|
|
35
|
-
* onValueChange={setValue}
|
|
36
|
-
* placeholder="Select option..."
|
|
37
|
-
* options={[
|
|
38
|
-
* { value: 'option1', label: 'Option 1' },
|
|
39
|
-
* { value: 'option2', label: 'Option 2' }
|
|
40
|
-
* ]}
|
|
41
|
-
* />
|
|
42
|
-
* ```
|
|
43
|
-
* @param {ComboboxProps} props - The props for the combobox
|
|
44
|
-
* @returns {JSX.Element} The rendered combobox
|
|
45
|
-
*/
|
|
46
|
-
const Combobox = ({ value, onValueChange, placeholder = 'Select...', searchPlaceholder = 'Search...', emptyMessage = 'No results found', options = [], trigger, disabled, isLoading, variant, filterFn = defaultFilterFn, multiple = false, label, }) => {
|
|
11
|
+
const Combobox = ({ value, onValueChange, placeholder = 'Select...', emptyMessage = 'No results found', options = [], disabled, isLoading, variant, multiple = false, label, creatable = false, createLabel = 'Create', clearable = false, onOpenChange, onSearchChange, required, }) => {
|
|
47
12
|
const id = useId();
|
|
48
13
|
const [open, setOpen] = useState(false);
|
|
49
14
|
const [search, setSearch] = useState('');
|
|
50
15
|
const [highlightedIndex, setHighlightedIndex] = useState(0);
|
|
16
|
+
const containerRef = useRef(null);
|
|
51
17
|
const inputRef = useRef(null);
|
|
52
18
|
const listRef = useRef(null);
|
|
53
|
-
// Normalize value to array for easier handling
|
|
54
19
|
const selectedValues = useMemo(() => {
|
|
55
20
|
if (!value)
|
|
56
21
|
return [];
|
|
57
22
|
return Array.isArray(value) ? value : [value];
|
|
58
23
|
}, [value]);
|
|
59
|
-
// Filter options based on search
|
|
60
24
|
const filteredOptions = useMemo(() => {
|
|
61
25
|
if (!search)
|
|
62
26
|
return options;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
27
|
+
const searchLower = search.toLowerCase();
|
|
28
|
+
return options.filter((option) => {
|
|
29
|
+
const labelMatch = option.label.toLowerCase().includes(searchLower);
|
|
30
|
+
const descMatch = option.description?.toLowerCase().includes(searchLower);
|
|
31
|
+
return labelMatch || descMatch;
|
|
32
|
+
});
|
|
33
|
+
}, [options, search]);
|
|
34
|
+
const showCreateOption = useMemo(() => {
|
|
35
|
+
if (!creatable || !search.trim())
|
|
36
|
+
return false;
|
|
37
|
+
const exactMatch = options.some((opt) => opt.value.toLowerCase() === search.toLowerCase() ||
|
|
38
|
+
opt.label.toLowerCase() === search.toLowerCase());
|
|
39
|
+
return !exactMatch;
|
|
40
|
+
}, [creatable, search, options]);
|
|
41
|
+
const displayOptions = useMemo(() => {
|
|
42
|
+
if (showCreateOption) {
|
|
43
|
+
return [
|
|
44
|
+
...filteredOptions,
|
|
45
|
+
{
|
|
46
|
+
value: search.trim(),
|
|
47
|
+
label: `${createLabel} "${search.trim()}"`,
|
|
48
|
+
isCreateOption: true,
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
return filteredOptions;
|
|
53
|
+
}, [filteredOptions, showCreateOption, search, createLabel]);
|
|
66
54
|
useEffect(() => {
|
|
67
55
|
if (open) {
|
|
68
|
-
setSearch('');
|
|
69
56
|
setHighlightedIndex(0);
|
|
70
|
-
// Focus input when opened
|
|
71
|
-
setTimeout(() => inputRef.current?.focus(), 0);
|
|
72
57
|
}
|
|
73
|
-
|
|
74
|
-
|
|
58
|
+
else if (!multiple) {
|
|
59
|
+
setSearch('');
|
|
60
|
+
}
|
|
61
|
+
}, [open, multiple]);
|
|
75
62
|
useEffect(() => {
|
|
76
63
|
if (open && listRef.current) {
|
|
77
64
|
const highlightedElement = listRef.current.children[highlightedIndex];
|
|
@@ -80,6 +67,21 @@ const Combobox = ({ value, onValueChange, placeholder = 'Select...', searchPlace
|
|
|
80
67
|
}
|
|
81
68
|
}
|
|
82
69
|
}, [highlightedIndex, open]);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
setHighlightedIndex(0);
|
|
72
|
+
}, [displayOptions.length]);
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
const handleClickOutside = (e) => {
|
|
75
|
+
if (containerRef.current &&
|
|
76
|
+
!containerRef.current.contains(e.target)) {
|
|
77
|
+
setOpen(false);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
if (open) {
|
|
81
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
82
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
83
|
+
}
|
|
84
|
+
}, [open]);
|
|
83
85
|
const handleSelect = (optionValue) => {
|
|
84
86
|
if (multiple) {
|
|
85
87
|
const newValues = selectedValues.includes(optionValue)
|
|
@@ -90,30 +92,43 @@ const Combobox = ({ value, onValueChange, placeholder = 'Select...', searchPlace
|
|
|
90
92
|
else {
|
|
91
93
|
onValueChange?.(optionValue);
|
|
92
94
|
setOpen(false);
|
|
95
|
+
setSearch('');
|
|
96
|
+
inputRef.current?.blur();
|
|
93
97
|
}
|
|
94
98
|
};
|
|
95
99
|
const handleKeyDown = (e) => {
|
|
96
|
-
if (!open)
|
|
97
|
-
return;
|
|
98
100
|
switch (e.key) {
|
|
99
101
|
case 'ArrowDown':
|
|
100
102
|
e.preventDefault();
|
|
101
|
-
|
|
103
|
+
if (!open) {
|
|
104
|
+
setOpen(true);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
setHighlightedIndex((prev) => (prev + 1) % displayOptions.length);
|
|
108
|
+
}
|
|
102
109
|
break;
|
|
103
110
|
case 'ArrowUp':
|
|
104
111
|
e.preventDefault();
|
|
105
|
-
|
|
112
|
+
if (open) {
|
|
113
|
+
setHighlightedIndex((prev) => (prev - 1 + displayOptions.length) % displayOptions.length);
|
|
114
|
+
}
|
|
106
115
|
break;
|
|
107
116
|
case 'Enter':
|
|
108
117
|
e.preventDefault();
|
|
109
|
-
if (
|
|
110
|
-
|
|
111
|
-
|
|
118
|
+
if (open &&
|
|
119
|
+
displayOptions[highlightedIndex] &&
|
|
120
|
+
!displayOptions[highlightedIndex].disabled) {
|
|
121
|
+
handleSelect(displayOptions[highlightedIndex].value);
|
|
122
|
+
}
|
|
123
|
+
else if (!open) {
|
|
124
|
+
setOpen(true);
|
|
112
125
|
}
|
|
113
126
|
break;
|
|
114
127
|
case 'Escape':
|
|
115
128
|
e.preventDefault();
|
|
116
129
|
setOpen(false);
|
|
130
|
+
setSearch('');
|
|
131
|
+
inputRef.current?.blur();
|
|
117
132
|
break;
|
|
118
133
|
}
|
|
119
134
|
};
|
|
@@ -121,43 +136,76 @@ const Combobox = ({ value, onValueChange, placeholder = 'Select...', searchPlace
|
|
|
121
136
|
e.stopPropagation();
|
|
122
137
|
onValueChange?.(multiple ? [] : '');
|
|
123
138
|
};
|
|
124
|
-
|
|
125
|
-
|
|
139
|
+
const getDisplayValue = () => {
|
|
140
|
+
if (open && search)
|
|
141
|
+
return search;
|
|
126
142
|
if (selectedValues.length === 0)
|
|
127
|
-
return
|
|
128
|
-
if (multiple)
|
|
129
|
-
return
|
|
130
|
-
}
|
|
143
|
+
return '';
|
|
144
|
+
if (multiple)
|
|
145
|
+
return '';
|
|
131
146
|
const selectedOption = options.find((opt) => opt.value === selectedValues[0]);
|
|
132
|
-
return selectedOption?.label ||
|
|
147
|
+
return selectedOption?.label || (creatable ? selectedValues[0] : '');
|
|
133
148
|
};
|
|
134
|
-
const
|
|
149
|
+
const displayValue = getDisplayValue();
|
|
135
150
|
const hasSelection = selectedValues.length > 0;
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
151
|
+
const handleInputChange = (e) => {
|
|
152
|
+
const newValue = e.target.value;
|
|
153
|
+
setSearch(newValue);
|
|
154
|
+
onSearchChange?.(newValue);
|
|
155
|
+
if (!open)
|
|
156
|
+
setOpen(true);
|
|
157
|
+
};
|
|
158
|
+
const handleInputFocus = () => {
|
|
159
|
+
if (!disabled && !isLoading) {
|
|
160
|
+
setOpen(true);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const handleInputClick = () => {
|
|
164
|
+
if (!disabled && !isLoading) {
|
|
165
|
+
setOpen(true);
|
|
166
|
+
inputRef.current?.focus();
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
const handleOpenChange = (isOpen) => {
|
|
170
|
+
setOpen(isOpen);
|
|
171
|
+
onOpenChange?.(isOpen);
|
|
172
|
+
};
|
|
173
|
+
return (_jsxs("div", { ref: containerRef, className: cn('dndev-relative', open && 'dndev-combobox-open'), style: { width: '100%' }, children: [_jsxs("div", { className: "dndev-relative", children: [_jsx(Input, { ref: inputRef, id: id, label: label, value: displayValue, onChange: handleInputChange, onFocus: handleInputFocus, onClick: handleInputClick, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled || isLoading, icon: isLoading ? _jsx(Spinner, {}) : ChevronDown, iconEnd: true, required: required, "data-variant": variant, style: {
|
|
174
|
+
'--chevron-rotation': open ? '180deg' : '0deg',
|
|
175
|
+
} }), clearable && hasSelection && !disabled && (_jsx("button", { type: "button", onClick: handleClear, className: "dndev-absolute", style: {
|
|
176
|
+
insetInlineEnd: 'calc(var(--gap-md) + var(--icon-md) + var(--gap-sm))',
|
|
177
|
+
top: '50%',
|
|
178
|
+
transform: 'translateY(-50%)',
|
|
179
|
+
background: 'none',
|
|
180
|
+
border: 'none',
|
|
181
|
+
cursor: 'pointer',
|
|
182
|
+
padding: 'var(--gap-tight)',
|
|
183
|
+
display: 'flex',
|
|
184
|
+
alignItems: 'center',
|
|
185
|
+
opacity: 0.5,
|
|
186
|
+
zIndex: 1,
|
|
187
|
+
}, "aria-label": "Clear", children: _jsx(X, { style: {
|
|
188
|
+
width: 'var(--size-icon-sm)',
|
|
189
|
+
height: 'var(--size-icon-sm)',
|
|
190
|
+
} }) }))] }), open && (_jsx("div", { className: "dndev-floating dndev-menu-content dndev-z-tooltip dndev-combobox-content", style: {
|
|
191
|
+
position: 'absolute',
|
|
192
|
+
top: '100%',
|
|
193
|
+
insetInlineStart: 0,
|
|
194
|
+
insetInlineEnd: 0,
|
|
195
|
+
width: '100%',
|
|
196
|
+
marginTop: 'var(--gap-tight)',
|
|
197
|
+
padding: 'var(--gap-tight)',
|
|
198
|
+
textAlign: 'start',
|
|
199
|
+
}, "data-glow": "blank", children: _jsx(ScrollArea, { className: "dndev-menu-scroll-area", end: true, children: _jsx("div", { ref: listRef, style: {
|
|
200
|
+
display: 'flex',
|
|
201
|
+
flexDirection: 'column',
|
|
202
|
+
gap: 'var(--gap-none)',
|
|
203
|
+
}, children: displayOptions.length === 0 ? (_jsx("div", { className: "dndev-combobox-empty", style: { textAlign: 'start' }, children: emptyMessage })) : (displayOptions.map((option, index) => {
|
|
157
204
|
const isSelected = selectedValues.includes(option.value);
|
|
158
205
|
const isHighlighted = index === highlightedIndex;
|
|
159
|
-
|
|
160
|
-
|
|
206
|
+
const isCreateOption = option.isCreateOption;
|
|
207
|
+
return (_jsx("button", { type: "button", onClick: () => !option.disabled && handleSelect(option.value), disabled: option.disabled, className: cn('dndev-interactive dndev-combobox-option', isHighlighted && 'dndev-combobox-option-highlighted', isSelected && 'dndev-combobox-option-selected', isCreateOption && 'dndev-combobox-option-create'), onMouseEnter: () => setHighlightedIndex(index), children: option.content ? (option.content) : (_jsxs(_Fragment, { children: [isCreateOption && (_jsx(Plus, { className: "dndev-combobox-option-create-icon" })), _jsxs("div", { className: "dndev-combobox-option-content", children: [_jsx("span", { className: "dndev-combobox-option-label", children: option.label }), option.description && (_jsx("span", { className: "dndev-combobox-option-description", children: option.description }))] }), isSelected && !isCreateOption && (_jsx(Check, { className: "dndev-combobox-option-check" }))] })) }, isCreateOption ? `create-${option.value}` : option.value));
|
|
208
|
+
})) }) }) }))] }));
|
|
161
209
|
};
|
|
162
210
|
export default Combobox;
|
|
163
211
|
export { CONTROL_VARIANT as COMBOBOX_VARIANT };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/Dialog/index.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG7E,OAAe,EAAkB,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAGL,aAAa,IAAI,gBAAgB,EAQlC,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAU/E,QAAA,MAAM,aAAa,GAAI,0EAOpB,cAAc,CAAC,OAAO,gBAAgB,CAAC,GAAG;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACrD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC,4CAyBA,CAAC;AAiCF,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,aAAa,CAAC,CAAC;AAEtE,MAAM,WAAW,WAAY,SAAQ,IAAI,CACvC,kBAAkB,EAClB,UAAU,GAAG,OAAO,CACrB;IACC,wCAAwC;IACxC,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,mBAAmB;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,qBAAqB;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,4BAA4B;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uCAAuC;IACvC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,uCAAuC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,sIAAsI;IACtI,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kDAAkD;IAClD,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE;YACP,KAAK,EAAE,MAAM,CAAC;YACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;SACtB,CAAC;QACF,OAAO,CAAC,EAAE;YACR,KAAK,EAAE,MAAM,CAAC;YACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;YACrB,OAAO,CAAC,EAAE,aAAa,CAAC;SACzB,CAAC;KACH,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,QAAA,MAAM,MAAM,GAAI,yIAcb,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/Dialog/index.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG7E,OAAe,EAAkB,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAGL,aAAa,IAAI,gBAAgB,EAQlC,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAU/E,QAAA,MAAM,aAAa,GAAI,0EAOpB,cAAc,CAAC,OAAO,gBAAgB,CAAC,GAAG;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACrD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC,4CAyBA,CAAC;AAiCF,MAAM,MAAM,kBAAkB,GAAG,cAAc,CAAC,OAAO,aAAa,CAAC,CAAC;AAEtE,MAAM,WAAW,WAAY,SAAQ,IAAI,CACvC,kBAAkB,EAClB,UAAU,GAAG,OAAO,CACrB;IACC,wCAAwC;IACxC,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,mBAAmB;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,qBAAqB;IACrB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,4BAA4B;IAC5B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uCAAuC;IACvC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,uCAAuC;IACvC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,sIAAsI;IACtI,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kDAAkD;IAClD,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE;YACP,KAAK,EAAE,MAAM,CAAC;YACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;SACtB,CAAC;QACF,OAAO,CAAC,EAAE;YACR,KAAK,EAAE,MAAM,CAAC;YACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;YACrB,OAAO,CAAC,EAAE,aAAa,CAAC;SACzB,CAAC;KACH,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,QAAA,MAAM,MAAM,GAAI,yIAcb,WAAW,4CAyEb,CAAC;AAEF,eAAe,MAAM,CAAC;AACtB,OAAO,EAAE,eAAe,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC1E,YAAY,EAAE,cAAc,IAAI,aAAa,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -57,7 +57,7 @@ const Dialog = ({ trigger, title, description, children, footer, open, onOpenCha
|
|
|
57
57
|
const variantAttrs = getVariantDataAttrs({
|
|
58
58
|
variant: variant !== SURFACE_VARIANT.DEFAULT ? variant : undefined,
|
|
59
59
|
});
|
|
60
|
-
return (_jsxs(Root, { open: open, onOpenChange: onOpenChange, children: [trigger && _jsx(Trigger, { asChild: true, children: trigger }), _jsxs(DialogContent, { className: cn('dndev-surface', className), noSwipe: noSwipe, closeButtonRef: closeButtonRef, onOpenChange: onOpenChange, ...variantAttrs, ...contentProps, children: [title ? (_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: title }),
|
|
60
|
+
return (_jsxs(Root, { open: open, onOpenChange: onOpenChange, children: [trigger && _jsx(Trigger, { asChild: true, children: trigger }), _jsxs(DialogContent, { className: cn('dndev-surface dndev-modal-content', className), noSwipe: noSwipe, closeButtonRef: closeButtonRef, onOpenChange: onOpenChange, ...variantAttrs, ...contentProps, children: [title ? (_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { className: "dndev-sr-only", children: description || 'Dialog content' })] })) : (_jsxs(_Fragment, { children: [_jsx(DialogTitle, { className: "dndev-sr-only", children: "Dialog" }), _jsx(DialogDescription, { className: "dndev-sr-only", children: description || 'Dialog content' })] })), _jsx("div", { className: "dndev-modal-body", children: children }), (footer || actions) && (_jsxs(DialogFooter, { children: [footer, actions && (_jsxs(_Fragment, { children: [actions.cancel && (_jsx(Close, { asChild: true, children: _jsx(Button, { variant: BUTTON_VARIANT.OUTLINE, onClick: actions.cancel.onClick, children: actions.cancel.label }) })), actions.confirm && (_jsx(Button, { variant: actions.confirm.variant || BUTTON_VARIANT.PRIMARY, onClick: actions.confirm.onClick, children: actions.confirm.label }))] }))] })), showClose && (_jsx(Close, { ref: closeButtonRef, asChild: true, children: _jsx(Button, { variant: BUTTON_VARIANT.GHOST, icon: X, className: "dndev-modal-close", "aria-label": "Close" }) }))] })] }));
|
|
61
61
|
};
|
|
62
62
|
export default Dialog;
|
|
63
63
|
export { SURFACE_VARIANT as DIALOG_VARIANT } from '../../utils/constants';
|
|
@@ -112,6 +112,6 @@ const DropdownMenu = ({ trigger, items = [], children, contentWidth, contentAlig
|
|
|
112
112
|
'data-state': 'checked',
|
|
113
113
|
}), children: normalItem.children ? (_jsxs(_Fragment, { children: [normalItem.children, IconEnd && (_jsx(IconEnd, { className: "dndev-dropdown-menu-trailing" }))] })) : (_jsxs(_Fragment, { children: [Icon && _jsx(Icon, {}), _jsx("span", { children: normalItem.label }), IconEnd && (_jsx(IconEnd, { className: "dndev-dropdown-menu-trailing" })), normalItem.checked && (_jsx(Check, { className: "dndev-dropdown-menu-checkmark dndev-dropdown-menu-trailing" }))] })) }, index));
|
|
114
114
|
})] }));
|
|
115
|
-
return (_jsxs(DropdownMenuPrimitive, { open: open, onOpenChange: onOpenChange, children: [_jsx(DropdownMenuTriggerPrimitive, { asChild: true, children: trigger }), _jsx(DropdownMenuContentPrimitive, { align: contentAlign, className: "dndev-floating dndev-menu-content dndev-z-tooltip", style: contentWidth ? { width: contentWidth } : undefined, children: _jsx(ScrollArea, { className: "dndev-
|
|
115
|
+
return (_jsxs(DropdownMenuPrimitive, { open: open, onOpenChange: onOpenChange, children: [_jsx(DropdownMenuTriggerPrimitive, { asChild: true, children: trigger }), _jsx(DropdownMenuContentPrimitive, { align: contentAlign, className: "dndev-floating dndev-menu-content dndev-z-tooltip", style: contentWidth ? { width: contentWidth } : undefined, children: _jsx(ScrollArea, { className: "dndev-menu-scroll-area", end: true, children: content }) })] }));
|
|
116
116
|
};
|
|
117
117
|
export default DropdownMenu;
|
|
@@ -32,6 +32,6 @@ export interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
|
|
|
32
32
|
* @param {InputProps} props - The props for the input
|
|
33
33
|
* @returns {JSX.Element} The rendered input
|
|
34
34
|
*/
|
|
35
|
-
declare const Input: ({ className, type, icon, iconEnd, label, value, onFocus, onBlur, ...props }: InputProps) => import("react/jsx-runtime").JSX.Element;
|
|
35
|
+
declare const Input: ({ className, type, icon, iconEnd, label, value, onFocus, onBlur, required, ...props }: InputProps) => import("react/jsx-runtime").JSX.Element;
|
|
36
36
|
export default Input;
|
|
37
37
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/Input/index.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAEtD,MAAM,WAAW,UAAW,SAAQ,mBAAmB,CAAC,gBAAgB,CAAC;IACvE,gDAAgD;IAChD,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,KAAK,GAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/Input/index.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAEtD,MAAM,WAAW,UAAW,SAAQ,mBAAmB,CAAC,gBAAgB,CAAC;IACvE,gDAAgD;IAChD,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,KAAK,GAAI,uFAWZ,UAAU,4CA+DZ,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
|
@@ -11,7 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
import { useState, useId } from 'react';
|
|
12
12
|
import { cn } from '../../utils/helpers';
|
|
13
13
|
import Icon from '../Icons/Icon';
|
|
14
|
-
import
|
|
14
|
+
import { FloatingLabel } from '../Label';
|
|
15
15
|
import './Input.css';
|
|
16
16
|
/**
|
|
17
17
|
* Accessible input component with mobile-friendly touch targets.
|
|
@@ -31,36 +31,20 @@ import './Input.css';
|
|
|
31
31
|
* @param {InputProps} props - The props for the input
|
|
32
32
|
* @returns {JSX.Element} The rendered input
|
|
33
33
|
*/
|
|
34
|
-
const Input = ({ className, type, icon, iconEnd = false, label, value, onFocus, onBlur, ...props }) => {
|
|
34
|
+
const Input = ({ className, type, icon, iconEnd = false, label, value, onFocus, onBlur, required, ...props }) => {
|
|
35
35
|
const id = useId();
|
|
36
36
|
const hasIcon = !!icon;
|
|
37
37
|
const isLeading = !iconEnd;
|
|
38
38
|
const isTrailing = iconEnd;
|
|
39
39
|
const hasLabel = !!label;
|
|
40
40
|
const inputClasses = cn('dndev-input', hasIcon && isLeading && 'dndev-input-with-leading-icon', hasIcon && isTrailing && 'dndev-input-with-trailing-icon', className);
|
|
41
|
-
|
|
41
|
+
// Explicitly exclude children to prevent void element error (input is a void element)
|
|
42
|
+
const { children: _children, ...inputProps } = props;
|
|
43
|
+
const inputElement = (_jsx("input", { id: id, type: type, value: value, required: required, className: inputClasses, ...inputProps }));
|
|
42
44
|
const needsWrapper = hasIcon || hasLabel;
|
|
43
45
|
if (!needsWrapper) {
|
|
44
46
|
return inputElement;
|
|
45
47
|
}
|
|
46
|
-
return (_jsxs("div", { className: "dndev-relative", children: [hasLabel && (_jsx(
|
|
47
|
-
position: 'absolute',
|
|
48
|
-
left: 'var(--gap-md)',
|
|
49
|
-
top: 'calc(-1 * var(--font-size-xs) / 2 - 1px)',
|
|
50
|
-
fontSize: 'var(--font-size-xs)',
|
|
51
|
-
fontWeight: 500,
|
|
52
|
-
color: props.disabled
|
|
53
|
-
? 'var(--muted-foreground)'
|
|
54
|
-
: 'var(--foreground)',
|
|
55
|
-
pointerEvents: 'none',
|
|
56
|
-
zIndex: 1,
|
|
57
|
-
backgroundColor: 'var(--background)',
|
|
58
|
-
padding: '0 var(--gap-xs)',
|
|
59
|
-
lineHeight: 1,
|
|
60
|
-
maxWidth: 'calc(100% - var(--gap-md) * 2)',
|
|
61
|
-
overflow: 'hidden',
|
|
62
|
-
textOverflow: 'ellipsis',
|
|
63
|
-
whiteSpace: 'nowrap',
|
|
64
|
-
}, children: label })), inputElement, hasIcon && (_jsx("div", { className: cn('dndev-input-icon', isLeading && 'dndev-input-icon-leading', isTrailing && 'dndev-input-icon-trailing'), children: _jsx(Icon, { icon: icon, className: "dndev-size-md", ariaHidden: true }) }))] }));
|
|
48
|
+
return (_jsxs("div", { className: "dndev-relative", children: [hasLabel && (_jsx(FloatingLabel, { htmlFor: id, disabled: props.disabled, required: required, children: label })), inputElement, hasIcon && (_jsx("div", { className: cn('dndev-input-icon', isLeading && 'dndev-input-icon-leading', isTrailing && 'dndev-input-icon-trailing'), children: _jsx(Icon, { icon: icon, className: "dndev-size-md", ariaHidden: true }) }))] }));
|
|
65
49
|
};
|
|
66
50
|
export default Input;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import './Label.css';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
export interface FloatingLabelProps {
|
|
4
|
+
/** HTML id to associate label with input */
|
|
5
|
+
htmlFor: string;
|
|
6
|
+
/** Label text or content */
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
/** Whether the input is disabled */
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
/** Whether to truncate long labels with ellipsis */
|
|
11
|
+
truncate?: boolean;
|
|
12
|
+
/** Whether the field is required - shows asterisk indicator */
|
|
13
|
+
required?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* FloatingLabel - Shared floating label component
|
|
17
|
+
*
|
|
18
|
+
* Positioned absolutely at the top of input fields.
|
|
19
|
+
* Uses transparent background to adapt to any parent container (dropdowns, cards, etc.)
|
|
20
|
+
*
|
|
21
|
+
* @component
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* <FloatingLabel htmlFor="email" disabled={false} truncate>
|
|
25
|
+
* Email Address
|
|
26
|
+
* </FloatingLabel>
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function FloatingLabel({ htmlFor, children, disabled, truncate, required, }: FloatingLabelProps): import("react/jsx-runtime").JSX.Element;
|
|
30
|
+
export default FloatingLabel;
|
|
31
|
+
//# sourceMappingURL=FloatingLabel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FloatingLabel.d.ts","sourceRoot":"","sources":["../../../src/atomic/Label/FloatingLabel.tsx"],"names":[],"mappings":"AAaA,OAAO,aAAa,CAAC;AAErB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,QAAQ,EAAE,SAAS,CAAC;IACpB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,QAAQ,EACR,QAAgB,EAChB,QAAgB,EAChB,QAAgB,GACjB,EAAE,kBAAkB,2CAsBpB;AAED,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// packages/components/src/atomic/Label/FloatingLabel.tsx
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview FloatingLabel component
|
|
5
|
+
* @description Shared floating label component for Input, PasswordInput, Select, and Combobox
|
|
6
|
+
*
|
|
7
|
+
* @version 0.0.1
|
|
8
|
+
* @since 0.0.1
|
|
9
|
+
* @author AMBROISE PARK Consulting
|
|
10
|
+
*/
|
|
11
|
+
import LabelPrimitive from './LabelPrimitive';
|
|
12
|
+
import { cn } from '../../utils/helpers';
|
|
13
|
+
import './Label.css';
|
|
14
|
+
/**
|
|
15
|
+
* FloatingLabel - Shared floating label component
|
|
16
|
+
*
|
|
17
|
+
* Positioned absolutely at the top of input fields.
|
|
18
|
+
* Uses transparent background to adapt to any parent container (dropdowns, cards, etc.)
|
|
19
|
+
*
|
|
20
|
+
* @component
|
|
21
|
+
* @example
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <FloatingLabel htmlFor="email" disabled={false} truncate>
|
|
24
|
+
* Email Address
|
|
25
|
+
* </FloatingLabel>
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function FloatingLabel({ htmlFor, children, disabled = false, truncate = false, required = false, }) {
|
|
29
|
+
return (_jsxs(LabelPrimitive, { htmlFor: htmlFor, className: "dndev-floating-label", "data-disabled": disabled ? 'true' : undefined, "data-truncate": truncate ? 'true' : undefined, children: [children, required && (_jsx("span", { style: {
|
|
30
|
+
color: 'var(--destructive-foreground)',
|
|
31
|
+
marginInlineStart: 'var(--gap-tight)',
|
|
32
|
+
}, "aria-hidden": "true", children: "*" }))] }));
|
|
33
|
+
}
|
|
34
|
+
export default FloatingLabel;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* @author AMBROISE PARK Consulting
|
|
8
8
|
*/
|
|
9
9
|
import { type LabelPrimitiveProps } from './LabelPrimitive';
|
|
10
|
+
import { FloatingLabel, type FloatingLabelProps } from './FloatingLabel';
|
|
10
11
|
import type { ComponentType, ReactNode } from 'react';
|
|
11
12
|
export interface LabelProps extends LabelPrimitiveProps {
|
|
12
13
|
/** Optional icon to display with the label */
|
|
@@ -24,6 +25,8 @@ export interface LabelProps extends LabelPrimitiveProps {
|
|
|
24
25
|
* @default false
|
|
25
26
|
*/
|
|
26
27
|
plain?: boolean;
|
|
28
|
+
/** Whether the field is required - shows asterisk indicator */
|
|
29
|
+
required?: boolean;
|
|
27
30
|
children?: ReactNode;
|
|
28
31
|
}
|
|
29
32
|
/**
|
|
@@ -38,6 +41,7 @@ export interface LabelProps extends LabelPrimitiveProps {
|
|
|
38
41
|
* @param {LabelProps} props - The props for the label
|
|
39
42
|
* @returns {JSX.Element} The rendered label
|
|
40
43
|
*/
|
|
41
|
-
declare const Label: ({ className, icon: Icon, iconEnd, plain, children, ...props }: LabelProps) => import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
declare const Label: ({ className, icon: Icon, iconEnd, plain, required, children, ...props }: LabelProps) => import("react/jsx-runtime").JSX.Element;
|
|
42
45
|
export default Label;
|
|
46
|
+
export { FloatingLabel, type FloatingLabelProps };
|
|
43
47
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/Label/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAuB,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/Label/index.tsx"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,OAAuB,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE5E,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,MAAM,WAAW,UAAW,SAAQ,mBAAmB;IACrD,8CAA8C;IAC9C,IAAI,CAAC,EAAE,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,QAAA,MAAM,KAAK,GAAI,yEAQZ,UAAU,4CAgCZ,CAAC;AAEF,eAAe,KAAK,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,CAAC"}
|
|
@@ -10,6 +10,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
10
10
|
*/
|
|
11
11
|
import LabelPrimitive, {} from './LabelPrimitive';
|
|
12
12
|
import { cn } from '../../utils/helpers';
|
|
13
|
+
import { FloatingLabel } from './FloatingLabel';
|
|
13
14
|
/**
|
|
14
15
|
* Accessible label component built on Radix UI Label.
|
|
15
16
|
* Supports icons and various label positions.
|
|
@@ -22,8 +23,13 @@ import { cn } from '../../utils/helpers';
|
|
|
22
23
|
* @param {LabelProps} props - The props for the label
|
|
23
24
|
* @returns {JSX.Element} The rendered label
|
|
24
25
|
*/
|
|
25
|
-
const Label = ({ className, icon: Icon, iconEnd = false, plain = false, children, ...props }) => {
|
|
26
|
+
const Label = ({ className, icon: Icon, iconEnd = false, plain = false, required = false, children, ...props }) => {
|
|
26
27
|
const iconElement = Icon ? (_jsx(Icon, { className: "dndev-label-icon", "data-position": iconEnd ? 'trailing' : 'leading' })) : null;
|
|
27
|
-
|
|
28
|
+
const requiredIndicator = required ? (_jsx("span", { style: {
|
|
29
|
+
color: 'var(--destructive-foreground)',
|
|
30
|
+
marginInlineStart: 'var(--gap-tight)',
|
|
31
|
+
}, "aria-hidden": "true", children: "*" })) : null;
|
|
32
|
+
return (_jsxs(LabelPrimitive, { className: cn('dndev-text-base dndev-label-base', className), "data-plain": plain ? 'true' : undefined, ...props, children: [!iconEnd && iconElement, children, requiredIndicator, iconEnd && iconElement] }));
|
|
28
33
|
};
|
|
29
34
|
export default Label;
|
|
35
|
+
export { FloatingLabel };
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import { type InputHTMLAttributes
|
|
1
|
+
import { type InputHTMLAttributes } from 'react';
|
|
2
2
|
import './PasswordInput.css';
|
|
3
3
|
export interface PasswordInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type'> {
|
|
4
|
-
/** Whether to show the password toggle button */
|
|
5
|
-
showToggle?: boolean;
|
|
6
|
-
/** Custom toggle button content */
|
|
7
|
-
toggleButton?: ReactNode;
|
|
8
4
|
/** Whether the password is currently visible */
|
|
9
5
|
visible?: boolean;
|
|
10
6
|
/** Callback when visibility changes */
|
|
11
7
|
onVisibilityChange?: (visible: boolean) => void;
|
|
12
8
|
/** Label for floating label - always shown small at top-left when provided */
|
|
13
9
|
label?: string;
|
|
10
|
+
/** Whether the field is required - shows asterisk indicator */
|
|
11
|
+
required?: boolean;
|
|
14
12
|
}
|
|
15
13
|
/**
|
|
16
14
|
* PasswordInput Component
|
|
17
15
|
*
|
|
18
16
|
* A password input field with show/hide toggle functionality.
|
|
19
17
|
* Features industry-standard UX patterns:
|
|
20
|
-
* - Eye icon toggle (show/hide password)
|
|
21
|
-
* - Keyboard accessibility (Enter to toggle)
|
|
18
|
+
* - Eye icon toggle (show/hide password) - ALWAYS at end, cannot be overridden
|
|
22
19
|
* - Smooth icon transitions
|
|
23
20
|
* - Mobile-friendly touch targets
|
|
24
21
|
* - Screen reader support
|
|
25
22
|
* - ARIA labels and descriptions
|
|
26
23
|
*
|
|
24
|
+
* Opinionated: Eye icon is ALWAYS positioned at end with inline styles.
|
|
25
|
+
* If you need different behavior, create your own component.
|
|
26
|
+
*
|
|
27
27
|
* @component
|
|
28
|
-
* @version 0.0.
|
|
28
|
+
* @version 0.0.2
|
|
29
29
|
* @since 0.0.1
|
|
30
30
|
* @author AMBROISE PARK Consulting
|
|
31
31
|
* @example
|
|
@@ -34,12 +34,11 @@ export interface PasswordInputProps extends Omit<InputHTMLAttributes<HTMLInputEl
|
|
|
34
34
|
* value={password}
|
|
35
35
|
* onChange={setPassword}
|
|
36
36
|
* placeholder="Enter password"
|
|
37
|
-
* showToggle={true}
|
|
38
37
|
* />
|
|
39
38
|
* ```
|
|
40
39
|
* @param {PasswordInputProps} props - The props for the password input
|
|
41
40
|
* @returns {JSX.Element} The rendered password input
|
|
42
41
|
*/
|
|
43
|
-
declare const PasswordInput: ({ className,
|
|
42
|
+
declare const PasswordInput: ({ className, visible: controlledVisible, onVisibilityChange, label, value, onFocus, onBlur, required, ...props }: PasswordInputProps) => import("react/jsx-runtime").JSX.Element;
|
|
44
43
|
export default PasswordInput;
|
|
45
44
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/PasswordInput/index.tsx"],"names":[],"mappings":"AAYA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/atomic/PasswordInput/index.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAIlE,OAAO,qBAAqB,CAAC;AAE7B,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAC9C,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,MAAM,CACP;IACC,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,aAAa,GAAI,kHAUpB,kBAAkB,4CA+DpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
|