@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.
Files changed (57) hide show
  1. package/dist/atomic/Accordion/index.d.ts +2 -16
  2. package/dist/atomic/Accordion/index.d.ts.map +1 -1
  3. package/dist/atomic/Accordion/index.js +4 -25
  4. package/dist/atomic/Alert/index.d.ts.map +1 -1
  5. package/dist/atomic/Alert/index.js +1 -1
  6. package/dist/atomic/Button/index.js +6 -3
  7. package/dist/atomic/Calendar/index.js +1 -1
  8. package/dist/atomic/CallToAction/index.d.ts.map +1 -1
  9. package/dist/atomic/CallToAction/index.js +1 -1
  10. package/dist/atomic/Collapsible/index.d.ts +12 -16
  11. package/dist/atomic/Collapsible/index.d.ts.map +1 -1
  12. package/dist/atomic/Collapsible/index.js +24 -24
  13. package/dist/atomic/Combobox/index.d.ts +9 -47
  14. package/dist/atomic/Combobox/index.d.ts.map +1 -1
  15. package/dist/atomic/Combobox/index.js +135 -87
  16. package/dist/atomic/Dialog/index.d.ts.map +1 -1
  17. package/dist/atomic/Dialog/index.js +1 -1
  18. package/dist/atomic/DropdownMenu/index.js +1 -1
  19. package/dist/atomic/Input/index.d.ts +1 -1
  20. package/dist/atomic/Input/index.d.ts.map +1 -1
  21. package/dist/atomic/Input/index.js +6 -22
  22. package/dist/atomic/Label/FloatingLabel.d.ts +31 -0
  23. package/dist/atomic/Label/FloatingLabel.d.ts.map +1 -0
  24. package/dist/atomic/Label/FloatingLabel.js +34 -0
  25. package/dist/atomic/Label/index.d.ts +5 -1
  26. package/dist/atomic/Label/index.d.ts.map +1 -1
  27. package/dist/atomic/Label/index.js +8 -2
  28. package/dist/atomic/PasswordInput/index.d.ts +9 -10
  29. package/dist/atomic/PasswordInput/index.d.ts.map +1 -1
  30. package/dist/atomic/PasswordInput/index.js +10 -30
  31. package/dist/atomic/Section/index.d.ts +25 -1
  32. package/dist/atomic/Section/index.d.ts.map +1 -1
  33. package/dist/atomic/Section/index.js +22 -4
  34. package/dist/atomic/Select/index.d.ts +3 -1
  35. package/dist/atomic/Select/index.d.ts.map +1 -1
  36. package/dist/atomic/Select/index.js +13 -24
  37. package/dist/atomic/Skeleton/index.d.ts.map +1 -1
  38. package/dist/atomic/Skeleton/index.js +6 -3
  39. package/dist/atomic/Switch/index.d.ts +18 -4
  40. package/dist/atomic/Switch/index.d.ts.map +1 -1
  41. package/dist/atomic/Switch/index.js +25 -6
  42. package/dist/atomic/Table/index.d.ts +17 -7
  43. package/dist/atomic/Table/index.d.ts.map +1 -1
  44. package/dist/atomic/Table/index.js +13 -3
  45. package/dist/atomic/Tooltip/index.d.ts.map +1 -1
  46. package/dist/atomic/Tooltip/index.js +6 -2
  47. package/dist/atomic/VideoPlayer/index.d.ts.map +1 -1
  48. package/dist/atomic/index.d.ts +2 -3
  49. package/dist/atomic/index.d.ts.map +1 -1
  50. package/dist/atomic/index.js +1 -2
  51. package/dist/hooks/useIntersectionObserver.js +3 -1
  52. package/dist/index.js +4 -4
  53. package/dist/styles/index.css +495 -81
  54. package/package.json +1 -1
  55. package/dist/atomic/Combobox/ComboboxPrimitive.d.ts +0 -18
  56. package/dist/atomic/Combobox/ComboboxPrimitive.d.ts.map +0 -1
  57. 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
- return options.filter((option) => filterFn(option, search));
64
- }, [options, search, filterFn]);
65
- // Reset search and highlighted index when opening
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
- }, [open]);
74
- // Scroll highlighted item into view
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
- setHighlightedIndex((prev) => (prev + 1) % filteredOptions.length);
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
- setHighlightedIndex((prev) => (prev - 1 + filteredOptions.length) % filteredOptions.length);
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 (filteredOptions[highlightedIndex] &&
110
- !filteredOptions[highlightedIndex].disabled) {
111
- handleSelect(filteredOptions[highlightedIndex].value);
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
- // Get display text for selected values
125
- const getDisplayText = () => {
139
+ const getDisplayValue = () => {
140
+ if (open && search)
141
+ return search;
126
142
  if (selectedValues.length === 0)
127
- return placeholder;
128
- if (multiple) {
129
- return `${selectedValues.length} selected`;
130
- }
143
+ return '';
144
+ if (multiple)
145
+ return '';
131
146
  const selectedOption = options.find((opt) => opt.value === selectedValues[0]);
132
- return selectedOption?.label || placeholder;
147
+ return selectedOption?.label || (creatable ? selectedValues[0] : '');
133
148
  };
134
- const displayText = getDisplayText();
149
+ const displayValue = getDisplayValue();
135
150
  const hasSelection = selectedValues.length > 0;
136
- const hasLabel = !!label;
137
- return (_jsxs(ComboboxRootPrimitive, { open: open, onOpenChange: setOpen, children: [_jsx(ComboboxAnchorPrimitive, { asChild: true, children: trigger ? (_jsx(ComboboxTriggerPrimitive, { asChild: true, disabled: disabled, children: trigger })) : (_jsxs("div", { className: "dndev-relative", children: [hasLabel && (_jsx(Label, { htmlFor: id, style: {
138
- position: 'absolute',
139
- left: 'var(--gap-md)',
140
- top: 'calc(-1 * var(--font-size-xs) / 2 - 1px)',
141
- fontSize: 'var(--font-size-xs)',
142
- fontWeight: 500,
143
- color: disabled
144
- ? 'var(--muted-foreground)'
145
- : 'var(--foreground)',
146
- pointerEvents: 'none',
147
- zIndex: 1,
148
- backgroundColor: 'var(--background)',
149
- padding: '0 var(--gap-xs)',
150
- lineHeight: 1,
151
- }, children: label })), _jsx(ComboboxTriggerPrimitive, { id: id, className: "dndev-input dndev-combobox-trigger", disabled: disabled, asChild: true, children: _jsxs("button", { type: "button", children: [isLoading ? (_jsxs("div", { className: "dndev-combobox-loading-container", children: [_jsx("div", { className: "dndev-animate-spin dndev-combobox-loading-spinner" }), _jsx("span", { children: "Loading..." })] })) : (_jsx("span", { className: cn(!hasSelection && 'dndev-combobox-placeholder'), children: displayText })), _jsxs("div", { className: "dndev-combobox-trigger-icons", children: [hasSelection && !disabled && (_jsx("span", { role: "button", tabIndex: 0, onClick: handleClear, onKeyDown: (e) => {
152
- if (e.key === 'Enter' || e.key === ' ') {
153
- e.preventDefault();
154
- handleClear(e);
155
- }
156
- }, className: "dndev-combobox-clear", "aria-label": "Clear selection", children: _jsx(X, {}) })), _jsx(ChevronDown, { className: "dndev-combobox-chevron" })] })] }) })] })) }), _jsxs(ComboboxContentPrimitive, { className: "dndev-floating dndev-menu-content dndev-z-tooltip dndev-combobox-content", sideOffset: 4, align: "start", "data-glow": "blank", onOpenAutoFocus: (e) => e.preventDefault(), children: [_jsx("div", { className: "dndev-combobox-search-container", children: _jsx(Input, { ref: inputRef, value: search, onChange: (e) => setSearch(e.target.value), onKeyDown: handleKeyDown, placeholder: searchPlaceholder, className: "dndev-combobox-search-input" }) }), _jsx("div", { className: "dndev-combobox-list", ref: listRef, children: filteredOptions.length === 0 ? (_jsx("div", { className: "dndev-combobox-empty", children: emptyMessage })) : (filteredOptions.map((option, index) => {
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
- 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'), onMouseEnter: () => setHighlightedIndex(index), children: option.content ? (option.content) : (_jsxs(_Fragment, { children: [_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 && (_jsx(Check, { className: "dndev-combobox-option-check" }))] })) }, option.value));
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,4CA2Eb,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"}
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 }), description && (_jsx(DialogDescription, { className: "dndev-sr-only", children: description }))] })) : (_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" }) }))] })] }));
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-dropdown-scroll-area", end: true, children: content }) })] }));
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,6EAUZ,UAAU,4CA4EZ,CAAC;AAEF,eAAe,KAAK,CAAC"}
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 Label from '../Label';
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
- const inputElement = (_jsx("input", { id: id, type: type, value: value, className: inputClasses, ...props }));
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(Label, { htmlFor: id, style: {
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;AAG5E,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,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,QAAA,MAAM,KAAK,GAAI,+DAOZ,UAAU,4CAmBZ,CAAC;AAEF,eAAe,KAAK,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
- return (_jsxs(LabelPrimitive, { className: cn('dndev-text-base dndev-label-base', className), "data-plain": plain ? 'true' : undefined, ...props, children: [!iconEnd && iconElement, children, iconEnd && iconElement] }));
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, type ReactNode } from 'react';
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.1
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, showToggle, toggleButton, visible: controlledVisible, onVisibilityChange, label, value, onFocus, onBlur, ...props }: PasswordInputProps) => import("react/jsx-runtime").JSX.Element;
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,EAGL,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAKf,OAAO,qBAAqB,CAAC;AAE7B,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAC9C,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,MAAM,CACP;IACC,iDAAiD;IACjD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mCAAmC;IACnC,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,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;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,QAAA,MAAM,aAAa,GAAI,kIAWpB,kBAAkB,4CAyFpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
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"}