@dbcdk/react-components 0.0.44 → 0.0.46

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.
@@ -346,7 +346,7 @@ export const DateTimePicker = forwardRef(function DateTimePicker({ mode = 'singl
346
346
  var _a, _b;
347
347
  return (_jsx("div", { onClick: toggle, className: [styles.triggerWrap, fullWidth ? styles.triggerWrapFullWidth : '']
348
348
  .filter(Boolean)
349
- .join(' '), children: _jsx(Input, { ...inputProps, autoComplete: "off", autoCorrect: "off", autoCapitalize: "off", spellCheck: "false", placeholder: (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.placeholder) !== null && _a !== void 0 ? _a : fallbackPlaceholder, value: dirty ? text : formatted, onInput: e => {
349
+ .join(' '), children: _jsx(Input, { ...inputProps, fieldClassName: styles.compactTriggerField, autoComplete: "off", autoCorrect: "off", autoCapitalize: "off", spellCheck: "false", placeholder: (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.placeholder) !== null && _a !== void 0 ? _a : fallbackPlaceholder, value: dirty ? text : formatted, onInput: e => {
350
350
  setDirty(true);
351
351
  const raw = e.target.value;
352
352
  const masked = mode === 'single' ? maskSingle(raw, enableTime) : maskRange(raw, false);
@@ -7,6 +7,15 @@
7
7
  width: 100%;
8
8
  }
9
9
 
10
+ .compactTriggerField {
11
+ padding-block: 2px;
12
+ padding-inline-end: calc(var(--spacing-xs) + 24px);
13
+ }
14
+
15
+ .compactTriggerField.fieldWithIcon {
16
+ padding-inline-start: calc(var(--icon-size-md) + var(--spacing-sm));
17
+ }
18
+
10
19
  .panel {
11
20
  display: grid;
12
21
  grid-template-columns: 1fr;
@@ -25,10 +25,11 @@ export interface FilterFieldProps extends Omit<React.InputHTMLAttributes<HTMLInp
25
25
  placeholder?: string;
26
26
  disabled?: boolean;
27
27
  width?: string;
28
+ maxWidth?: string;
28
29
  debounceTime?: number;
29
30
  }
30
31
  export declare const NUMBER_OPERATORS: Operator[];
31
- export declare function FilterField({ field, control, operator, value, onChange, operators, options, single, size, variant, label, placeholder, disabled, 'data-cy': dataCy, width, debounceTime, ...inputProps }: FilterFieldProps & {
32
+ export declare function FilterField({ field, control, operator, value, onChange, operators, options, single, size, variant, label, placeholder, disabled, 'data-cy': dataCy, width, maxWidth, debounceTime, ...inputProps }: FilterFieldProps & {
32
33
  'data-cy'?: string;
33
34
  }): React.ReactElement;
34
35
  export {};
@@ -3,9 +3,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { Check } from 'lucide-react';
4
4
  import { useMemo, useRef, useState, useEffect } from 'react';
5
5
  import { Input } from '../../components/forms/input/Input';
6
- import { MultiSelect } from '../../components/forms/multi-select/MultiSelect';
6
+ import { Typeahead } from '../../components/forms/typeahead/Typeahead';
7
7
  import styles from './FilterField.module.css';
8
- import { Select } from '../forms/select/Select';
9
8
  import { Menu } from '../menu/Menu';
10
9
  import { Popover } from '../popover/Popover';
11
10
  const LABELS = {
@@ -70,8 +69,8 @@ function isFilterActive(value) {
70
69
  return value.trim().length > 0;
71
70
  return value != null;
72
71
  }
73
- export function FilterField({ field, control, operator, value, onChange, operators, options = [], single = true, size = 'md', variant = 'surface', label, placeholder = 'Type value…', disabled, 'data-cy': dataCy, width, debounceTime = INPUT_DEBOUNCE_MS, ...inputProps }) {
74
- var _a, _b;
72
+ export function FilterField({ field, control, operator, value, onChange, operators, options = [], single = true, size = 'md', variant = 'surface', label, placeholder = 'Type value…', disabled, 'data-cy': dataCy, width, maxWidth, debounceTime = INPUT_DEBOUNCE_MS, ...inputProps }) {
73
+ var _a, _b, _c, _d, _e, _f;
75
74
  const ops = useMemo(() => operators !== null && operators !== void 0 ? operators : DEFAULT_TEXT_OPERATORS, [operators]);
76
75
  const [selectedOperator, setSelectedOperator] = useState(operator);
77
76
  const active = isFilterActive(value);
@@ -159,16 +158,18 @@ export function FilterField({ field, control, operator, value, onChange, operato
159
158
  }, []);
160
159
  return (_jsxs("div", { ...(dataCy ? { 'data-cy': dataCy } : {}), className: [styles.filterField, styles[size], styles[variant], active ? styles.active : '']
161
160
  .filter(Boolean)
162
- .join(' '), children: [label ? _jsx("span", { className: `${styles.label} ${styles[size]}`, children: label }) : null, _jsx(OperatorDropdown, { value: selectedOperator, onChange: handleOperatorChange, operators: ops, size: size, disabled: disabled }), _jsx("div", { className: `${control === 'input' ? 'dbc-flex dbc-flex-grow' : styles.valueWrapper}`, style: { width }, children: control === 'input' ? (_jsx(Input, { variant: "embedded", ...inputProps, value: localValue, onChange: e => {
161
+ .join(' '), children: [label ? _jsx("span", { className: `${styles.label} ${styles[size]}`, children: label }) : null, _jsx(OperatorDropdown, { value: selectedOperator, onChange: handleOperatorChange, operators: ops, size: size, disabled: disabled }), _jsx("div", { className: [styles.valueWrapper, control === 'input' ? 'dbc-flex dbc-flex-grow' : '']
162
+ .filter(Boolean)
163
+ .join(' '), style: { width, maxWidth }, children: control === 'input' ? (_jsx(Input, { variant: "embedded", ...inputProps, value: localValue, onChange: e => {
163
164
  const next = e.currentTarget.value;
164
165
  setLocalValue(next);
165
166
  scheduleEmitValue(next);
166
167
  }, onBlur: () => {
167
168
  flushPendingValue();
168
- }, fullWidth: true, inputSize: size, placeholder: placeholder, disabled: disabled, onClear: () => {
169
+ }, fullWidth: true, inputSize: size, placeholder: placeholder, disabled: disabled, autoComplete: (_b = inputProps.autoComplete) !== null && _b !== void 0 ? _b : 'off', autoCorrect: (_c = inputProps.autoCorrect) !== null && _c !== void 0 ? _c : 'off', autoCapitalize: (_d = inputProps.autoCapitalize) !== null && _d !== void 0 ? _d : 'off', spellCheck: (_e = inputProps.spellCheck) !== null && _e !== void 0 ? _e : false, onClear: () => {
169
170
  clearDebounce();
170
171
  pendingValueRef.current = '';
171
172
  setLocalValue('');
172
173
  emit({ value: '' });
173
- } })) : single ? (_jsx(Select, { options: options, selectedValue: (_b = value) !== null && _b !== void 0 ? _b : null, onChange: v => emit({ value: v }), placeholder: placeholder, size: size, variant: "inline", onClear: () => emit({ value: '' }), disabled: disabled })) : (_jsx(MultiSelect, { options: options, size: size, variant: "inline", selectedValues: (Array.isArray(value) ? value : []), onChange: nextSelectedValues => emit({ value: nextSelectedValues }), onClear: () => emit({ value: [] }), fullWidth: true, disabled: disabled, children: placeholder })) })] }));
174
+ } })) : (_jsx(Typeahead, { options: options, mode: single ? 'single' : 'multi', selectedValue: single ? ((_f = value) !== null && _f !== void 0 ? _f : null) : Array.isArray(value) ? value : [], onChange: v => emit({ value: v }), placeholder: placeholder, variant: "embedded", inputProps: { inputSize: size }, onClear: () => emit({ value: single ? '' : [] }), disabled: disabled, fullWidth: true })) })] }));
174
175
  }
@@ -86,8 +86,8 @@
86
86
  content: '';
87
87
  position: absolute;
88
88
  inset-inline-start: 0;
89
- top: 1px;
90
- bottom: 1px;
89
+ top: 0;
90
+ bottom: 0;
91
91
  width: 3px;
92
92
  border-top-left-radius: inherit;
93
93
  border-bottom-left-radius: inherit;
@@ -97,12 +97,7 @@
97
97
  }
98
98
 
99
99
  .filterField.outlined.active::before {
100
- inset-inline-start: -1px;
101
- top: -1px;
102
- bottom: -1px;
103
- width: 4px;
104
- border-top-left-radius: var(--border-radius-default);
105
- border-bottom-left-radius: var(--border-radius-default);
100
+ width: 3px;
106
101
  }
107
102
 
108
103
  /* =========================
@@ -273,7 +268,7 @@
273
268
  ========================= */
274
269
 
275
270
  .filterField .valueWrapper {
276
- display: inline-flex;
271
+ display: flex;
277
272
  align-items: center;
278
273
  padding: 0;
279
274
  height: 100%;
@@ -290,12 +285,37 @@
290
285
 
291
286
  .filterField .valueWrapper > div {
292
287
  display: flex;
293
- align-items: stretch;
288
+ align-items: center;
294
289
  height: 100%;
295
290
  width: 100%;
296
291
  min-width: 0;
297
292
  }
298
293
 
294
+ /* Embedded typeahead tweaks */
295
+ .filterField .valueWrapper .field {
296
+ min-height: unset;
297
+ height: 100%;
298
+ block-size: 100%;
299
+ box-shadow: none;
300
+ border: none;
301
+ background: transparent;
302
+ padding: 0;
303
+ }
304
+ .filterField .valueWrapper .input {
305
+ height: 100%;
306
+ block-size: 100%;
307
+ min-height: unset;
308
+ background: transparent;
309
+ border: none;
310
+ box-shadow: none;
311
+ padding: 0;
312
+ margin: 0;
313
+ }
314
+ .filterField .valueWrapper .startAdornment {
315
+ margin-left: 0;
316
+ gap: 2px;
317
+ }
318
+
299
319
  /* =========================
300
320
  TEXT
301
321
  ========================= */
@@ -7,6 +7,7 @@ export type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size
7
7
  autoFocus?: boolean;
8
8
  minWidth?: string | number;
9
9
  width?: string | number;
10
+ maxWidth?: string | number;
10
11
  inputSize?: Size;
11
12
  variant?: InputVariant;
12
13
  onClear?: () => void;
@@ -16,5 +17,15 @@ export type InputProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size
16
17
  tooltip?: React.ReactNode;
17
18
  tooltipPlacement?: 'top' | 'right' | 'bottom' | 'left';
18
19
  modified?: boolean;
20
+ /**
21
+ * Custom content to render inside the input field, before the input element (e.g. chips)
22
+ */
23
+ startAdornment?: React.ReactNode;
24
+ /**
25
+ * Custom content to render inside the input field, after the input element
26
+ */
27
+ endAdornment?: React.ReactNode;
28
+ fieldClassName?: string;
29
+ 'data-cy'?: string;
19
30
  };
20
31
  export declare const Input: React.ForwardRefExoticComponent<React.PropsWithoutRef<InputProps> & React.RefAttributes<HTMLInputElement>>;
@@ -18,7 +18,7 @@ function mergeRefs(...refs) {
18
18
  }
19
19
  };
20
20
  }
21
- export const Input = forwardRef(function Input({ label, error, helpText, orientation = 'vertical', labelWidth = '160px', fullWidth = false, required, tooltip, tooltipPlacement = 'right', modified, icon, autoFocus, minWidth, width, inputSize = 'md', variant = 'outlined', onClear, onButtonClick, buttonLabel, buttonIcon, id, style, className, ...inputProps }, ref) {
21
+ export const Input = forwardRef(function Input({ label, error, helpText, orientation = 'vertical', labelWidth = '160px', fullWidth = false, required, tooltip, tooltipPlacement = 'right', modified = false, icon, autoFocus, minWidth, width, maxWidth, inputSize = 'md', variant = 'outlined', onClear, onButtonClick, buttonLabel, buttonIcon, id, style, className, fieldClassName, startAdornment, endAdornment, ...inputProps }, ref) {
22
22
  const inputRef = useRef(null);
23
23
  const reactId = useId();
24
24
  const inputId = id !== null && id !== void 0 ? id : `input-${reactId}`;
@@ -32,6 +32,7 @@ export const Input = forwardRef(function Input({ label, error, helpText, orienta
32
32
  ...(style !== null && style !== void 0 ? style : {}),
33
33
  ...(minWidth ? { ['--input-min-width']: minWidth } : null),
34
34
  ...(width ? { ['--input-width']: width } : null),
35
+ ...(maxWidth ? { ['--input-max-width']: maxWidth } : null),
35
36
  };
36
37
  const { triggerProps } = useTooltipTrigger({
37
38
  content: tooltip,
@@ -47,13 +48,15 @@ export const Input = forwardRef(function Input({ label, error, helpText, orienta
47
48
  className !== null && className !== void 0 ? className : '',
48
49
  ]
49
50
  .filter(Boolean)
50
- .join(' '), children: [_jsxs("div", { className: styles.field, ...(tooltip ? triggerProps : {}), children: [icon && _jsx("span", { className: styles.icon, children: icon }), _jsx("input", { ...inputProps, id: inputId, ref: mergeRefs(inputRef, ref), className: [
51
- styles.input,
52
- icon ? styles.inputWithIcon : '',
53
- inputSize ? styles[inputSize] : '',
54
- styles[variant],
55
- ]
56
- .filter(Boolean)
57
- .join(' ') }), onClear && inputProps.value && _jsx(ClearButton, { onClick: onClear, absolute: true })] }), hasButton && (_jsxs(Button, { onClick: onButtonClick, className: styles.trailingButton, type: "button", variant: trailingButtonVariant, children: [buttonIcon !== null && buttonIcon !== void 0 ? buttonIcon : null, buttonLabel !== null && buttonLabel !== void 0 ? buttonLabel : null] }))] }) }));
51
+ .join(' '), children: [_jsxs("div", { className: [
52
+ styles.field,
53
+ styles[variant],
54
+ icon ? styles.fieldWithIcon : '',
55
+ inputSize ? styles[inputSize] : '',
56
+ modified ? styles.modified : '',
57
+ fieldClassName !== null && fieldClassName !== void 0 ? fieldClassName : '',
58
+ ]
59
+ .filter(Boolean)
60
+ .join(' '), "data-forminput": "field", "data-modified": modified ? 'true' : undefined, "aria-disabled": inputProps.disabled ? 'true' : undefined, ...(tooltip ? triggerProps : {}), children: [icon && _jsx("span", { className: styles.icon, children: icon }), startAdornment && _jsx("span", { className: styles.startAdornment, children: startAdornment }), _jsx("input", { ...inputProps, id: inputId, ref: mergeRefs(inputRef, ref), className: [styles.input, inputSize ? styles[inputSize] : ''].filter(Boolean).join(' ') }), endAdornment && _jsx("span", { className: styles.endAdornment, children: endAdornment }), onClear && inputProps.value && _jsx(ClearButton, { onClick: onClear, absolute: true })] }), hasButton && (_jsxs(Button, { onClick: onButtonClick, className: styles.trailingButton, type: "button", variant: trailingButtonVariant, children: [buttonIcon !== null && buttonIcon !== void 0 ? buttonIcon : null, buttonLabel !== null && buttonLabel !== void 0 ? buttonLabel : null] }))] }) }));
58
61
  });
59
62
  Input.displayName = 'Input';
@@ -22,8 +22,20 @@
22
22
  display: flex;
23
23
  align-items: center;
24
24
  flex: 1 1 auto;
25
+ height: 100%;
25
26
  min-inline-size: 0;
26
27
  color: var(--color-fg-default);
28
+ background: var(--color-bg-surface);
29
+ border: var(--border-width-thin) solid var(--color-border-default);
30
+ border-radius: var(--border-radius-default);
31
+ padding-inline: var(--spacing-sm);
32
+ padding-block: var(--spacing-xs);
33
+ box-sizing: border-box;
34
+ transition:
35
+ background-color var(--transition-fast) var(--ease-standard),
36
+ border-color var(--transition-fast) var(--ease-standard),
37
+ box-shadow var(--transition-fast) var(--ease-standard),
38
+ color var(--transition-fast) var(--ease-standard);
27
39
  }
28
40
 
29
41
  /* Actual input */
@@ -33,24 +45,15 @@
33
45
  inline-size: 100%;
34
46
  box-sizing: border-box;
35
47
  text-overflow: ellipsis;
36
-
37
48
  color: var(--color-fg-default);
38
- background: var(--color-bg-surface);
49
+ background: transparent;
39
50
  font-family: var(--font-family);
40
51
  font-size: var(--font-size-sm);
41
52
  line-height: var(--line-height-normal);
42
-
43
- border: var(--border-width-thin) solid var(--color-border-default);
44
- border-radius: var(--border-radius-default);
45
-
46
- padding-inline: var(--spacing-sm);
47
- padding-block: var(--spacing-xs);
48
-
49
- transition:
50
- background-color var(--transition-fast) var(--ease-standard),
51
- border-color var(--transition-fast) var(--ease-standard),
52
- box-shadow var(--transition-fast) var(--ease-standard),
53
- color var(--transition-fast) var(--ease-standard);
53
+ border: none;
54
+ outline: none;
55
+ padding: 0;
56
+ margin: 0;
54
57
  }
55
58
 
56
59
  .input::placeholder {
@@ -58,8 +61,7 @@
58
61
  }
59
62
 
60
63
  .input:disabled {
61
- background-color: var(--color-disabled-bg);
62
- border-color: transparent;
64
+ background-color: transparent;
63
65
  color: var(--color-disabled-fg);
64
66
  cursor: not-allowed;
65
67
  opacity: 1;
@@ -72,7 +74,7 @@
72
74
  border-bottom-right-radius: 0;
73
75
  }
74
76
 
75
- .withClear .input {
77
+ .withClear .field {
76
78
  padding-inline-end: calc(var(--spacing-md) + 16px);
77
79
  }
78
80
 
@@ -91,11 +93,11 @@
91
93
  border-color: var(--color-border-default);
92
94
  }
93
95
 
94
- .outlined:hover:not(:disabled) {
96
+ .outlined:hover:not([aria-disabled='true']) {
95
97
  border-color: var(--color-border-strong);
96
98
  }
97
99
 
98
- .outlined:focus-visible:not(:disabled) {
100
+ .outlined:focus-within:not([aria-disabled='true']) {
99
101
  border-color: var(--color-border-selected);
100
102
  box-shadow: inset 0 0 0 1px var(--color-border-selected);
101
103
  }
@@ -106,12 +108,12 @@
106
108
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
107
109
  }
108
110
 
109
- .surface:hover:not(:disabled) {
111
+ .surface:hover:not([aria-disabled='true']) {
110
112
  border-color: var(--color-border-default);
111
113
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
112
114
  }
113
115
 
114
- .surface:focus-visible:not(:disabled) {
116
+ .surface:focus-within:not([aria-disabled='true']) {
115
117
  border-color: var(--color-border-selected);
116
118
  box-shadow: inset 0 0 0 1px var(--color-border-selected);
117
119
  }
@@ -123,11 +125,11 @@
123
125
  box-shadow: inset 0 0 0 1px transparent;
124
126
  }
125
127
 
126
- .subtle:hover:not(:disabled) {
128
+ .subtle:hover:not([aria-disabled='true']) {
127
129
  background-color: var(--color-bg-toolbar-hover);
128
130
  }
129
131
 
130
- .subtle:focus-visible:not(:disabled) {
132
+ .subtle:focus-within:not([aria-disabled='true']) {
131
133
  border-color: var(--color-border-selected);
132
134
  box-shadow: inset 0 0 0 1px var(--color-border-selected);
133
135
  }
@@ -142,9 +144,8 @@
142
144
  block-size: 100%;
143
145
  }
144
146
 
145
- .embedded:hover:not(:disabled),
146
- .embedded:focus:not(:disabled),
147
- .embedded:focus-visible:not(:disabled) {
147
+ .embedded:hover:not([aria-disabled='true']),
148
+ .embedded:focus-within:not([aria-disabled='true']) {
148
149
  background-color: transparent;
149
150
  border-color: transparent;
150
151
  box-shadow: none;
@@ -158,12 +159,12 @@
158
159
  box-shadow: var(--shadow-xs), var(--shadow-md);
159
160
  }
160
161
 
161
- .standalone:hover:not(:disabled) {
162
+ .standalone:hover:not([aria-disabled='true']) {
162
163
  border-color: var(--color-border-strong);
163
164
  box-shadow: var(--shadow-sm), var(--shadow-md);
164
165
  }
165
166
 
166
- .standalone:focus-visible:not(:disabled) {
167
+ .standalone:focus-within:not([aria-disabled='true']) {
167
168
  border-color: var(--color-border-selected);
168
169
  box-shadow:
169
170
  var(--shadow-xs),
@@ -171,6 +172,136 @@
171
172
  inset 0 0 0 1px var(--color-border-selected);
172
173
  }
173
174
 
175
+ /* =========================
176
+ Modified state
177
+ ========================= */
178
+
179
+ .modified {
180
+ background-color: color-mix(in srgb, var(--color-status-warning-bg) 22%, var(--color-bg-surface));
181
+ border-color: color-mix(
182
+ in srgb,
183
+ var(--color-status-warning-border) 45%,
184
+ var(--color-border-default)
185
+ );
186
+ box-shadow: inset 4px 0 0 var(--color-status-warning-border);
187
+ }
188
+
189
+ /* Hover should stay warm, not switch back to the normal border */
190
+ .modified:hover:not([aria-disabled='true']) {
191
+ background-color: color-mix(in srgb, var(--color-status-warning-bg) 28%, var(--color-bg-surface));
192
+ border-color: color-mix(
193
+ in srgb,
194
+ var(--color-status-warning-border) 60%,
195
+ var(--color-border-default)
196
+ );
197
+ }
198
+
199
+ /* Focus should also stay warm and readable */
200
+ .modified:focus-within:not([aria-disabled='true']) {
201
+ background-color: color-mix(in srgb, var(--color-status-warning-bg) 28%, var(--color-bg-surface));
202
+ border-color: color-mix(
203
+ in srgb,
204
+ var(--color-status-warning-border) 75%,
205
+ var(--color-border-default)
206
+ );
207
+ box-shadow:
208
+ inset 4px 0 0 var(--color-status-warning-border),
209
+ inset 0 0 0 1px
210
+ color-mix(in srgb, var(--color-status-warning-border) 55%, var(--color-border-default));
211
+ }
212
+
213
+ /* Variant-specific tweaks when modified */
214
+ .surface.modified {
215
+ box-shadow:
216
+ inset 4px 0 0 var(--color-status-warning-border),
217
+ 0 1px 2px rgba(0, 0, 0, 0.03);
218
+ }
219
+
220
+ .surface.modified:hover:not([aria-disabled='true']) {
221
+ box-shadow:
222
+ inset 4px 0 0 var(--color-status-warning-border),
223
+ 0 1px 3px rgba(0, 0, 0, 0.05);
224
+ }
225
+
226
+ .surface.modified:focus-within:not([aria-disabled='true']) {
227
+ box-shadow:
228
+ inset 4px 0 0 var(--color-status-warning-border),
229
+ inset 0 0 0 1px
230
+ color-mix(in srgb, var(--color-status-warning-border) 55%, var(--color-border-default));
231
+ }
232
+
233
+ .subtle.modified {
234
+ background-color: color-mix(in srgb, var(--color-status-warning-bg) 30%, var(--color-bg-toolbar));
235
+ border-color: transparent;
236
+ box-shadow:
237
+ inset 4px 0 0 var(--color-status-warning-border),
238
+ inset 0 0 0 1px transparent;
239
+ }
240
+
241
+ .subtle.modified:hover:not([aria-disabled='true']) {
242
+ background-color: color-mix(
243
+ in srgb,
244
+ var(--color-status-warning-bg) 36%,
245
+ var(--color-bg-toolbar-hover)
246
+ );
247
+ }
248
+
249
+ .subtle.modified:focus-within:not([aria-disabled='true']) {
250
+ border-color: color-mix(
251
+ in srgb,
252
+ var(--color-status-warning-border) 75%,
253
+ var(--color-border-default)
254
+ );
255
+ box-shadow:
256
+ inset 4px 0 0 var(--color-status-warning-border),
257
+ inset 0 0 0 1px
258
+ color-mix(in srgb, var(--color-status-warning-border) 55%, var(--color-border-default));
259
+ }
260
+
261
+ .standalone.modified {
262
+ box-shadow:
263
+ inset 4px 0 0 var(--color-status-warning-border),
264
+ var(--shadow-xs),
265
+ var(--shadow-md);
266
+ }
267
+
268
+ .standalone.modified:hover:not([aria-disabled='true']) {
269
+ box-shadow:
270
+ inset 4px 0 0 var(--color-status-warning-border),
271
+ var(--shadow-sm),
272
+ var(--shadow-md);
273
+ }
274
+
275
+ .standalone.modified:focus-within:not([aria-disabled='true']) {
276
+ box-shadow:
277
+ inset 4px 0 0 var(--color-status-warning-border),
278
+ var(--shadow-xs),
279
+ var(--shadow-md),
280
+ inset 0 0 0 1px
281
+ color-mix(in srgb, var(--color-status-warning-border) 55%, var(--color-border-default));
282
+ }
283
+
284
+ /* Embedded should stay visually light, but can still get the marker */
285
+ .embedded.modified {
286
+ background-color: color-mix(in srgb, var(--color-status-warning-bg) 18%, transparent);
287
+ border-color: transparent;
288
+ box-shadow: inset 3px 0 0 var(--color-status-warning-border);
289
+ }
290
+
291
+ .embedded.modified:hover:not([aria-disabled='true']),
292
+ .embedded.modified:focus-within:not([aria-disabled='true']) {
293
+ background-color: color-mix(in srgb, var(--color-status-warning-bg) 22%, transparent);
294
+ border-color: transparent;
295
+ box-shadow: inset 3px 0 0 var(--color-status-warning-border);
296
+ }
297
+
298
+ /* Disabled modified state */
299
+ .modified[aria-disabled='true'] {
300
+ background-color: var(--color-disabled-bg);
301
+ border-color: var(--color-disabled-border);
302
+ box-shadow: none;
303
+ }
304
+
174
305
  /* Sizes */
175
306
  .xs {
176
307
  block-size: var(--component-size-xs);
@@ -183,6 +314,12 @@
183
314
  font-size: var(--font-size-sm);
184
315
  }
185
316
 
317
+ .sm.embedded,
318
+ .md.embedded,
319
+ .lg.embedded {
320
+ block-size: 100%;
321
+ }
322
+
186
323
  .md {
187
324
  block-size: var(--component-size-md);
188
325
  font-size: var(--font-size-sm);
@@ -194,11 +331,11 @@
194
331
  }
195
332
 
196
333
  /* Leading icon */
197
- .inputWithIcon {
334
+ .fieldWithIcon {
198
335
  padding-inline-start: calc(var(--icon-size-md) + var(--spacing-lg));
199
336
  }
200
337
 
201
- .embedded.inputWithIcon {
338
+ .embedded.fieldWithIcon {
202
339
  padding-inline-start: calc(var(--icon-size-md) + var(--spacing-xl));
203
340
  }
204
341
 
@@ -244,3 +381,18 @@
244
381
  .input[type='datetime-local']::-webkit-calendar-picker-indicator {
245
382
  filter: invert(0.7);
246
383
  }
384
+
385
+ /* Start and end adornments */
386
+ .startAdornment {
387
+ display: flex;
388
+ align-items: center;
389
+ gap: 4px;
390
+ margin-left: 4px;
391
+ }
392
+
393
+ .endAdornment {
394
+ display: flex;
395
+ align-items: center;
396
+ gap: 4px;
397
+ margin-right: 4px;
398
+ }
@@ -6,9 +6,9 @@ export function InputContainer({ label, htmlFor, error, helpText, helpTextAdditi
6
6
  const renderLabel = label && (_jsxs("label", { className: styles.label, htmlFor: htmlFor, children: [label, required && _jsx("span", { className: styles.required, children: " *" })] }));
7
7
  const renderMessageRow = (message || helpTextAddition) && (_jsxs("div", { className: `${messageClass} ${styles.messageRow}`, children: [_jsx("span", { children: message }), helpTextAddition && _jsx("span", { className: styles.helpTextAddition, children: helpTextAddition })] }));
8
8
  if (orientation === 'vertical') {
9
- return (_jsxs("div", { "data-modified": modified ? true : undefined, className: `dbc-flex dbc-flex-column dbc-gap-xs ${styles.inputContainer}`, style: { width: fullWidth ? '100%' : undefined }, children: [renderLabel, children, renderMessageRow] }));
9
+ return (_jsxs("div", { "data-modified": modified ? 'true' : undefined, className: `dbc-flex dbc-flex-column dbc-gap-xs ${styles.inputContainer}`, style: { width: fullWidth ? '100%' : undefined }, children: [renderLabel, children, renderMessageRow] }));
10
10
  }
11
- return (_jsx("div", { "data-modified": modified ? true : undefined, className: styles.inputContainer, style: {
11
+ return (_jsx("div", { "data-modified": modified ? 'true' : undefined, className: styles.inputContainer, style: {
12
12
  '--label-width': labelWidth,
13
13
  width: fullWidth ? '100%' : undefined,
14
14
  }, children: _jsxs("div", { className: `${styles.horizontal} dbc-flex dbc-flex-column dbc-gap-xs`, children: [_jsxs("div", { className: `${styles.labelContainer} dbc-flex dbc-items-center dbc-gap-xs`, children: [renderLabel, children] }), renderMessageRow] }) }));
@@ -25,6 +25,10 @@
25
25
  justify-content: space-between;
26
26
  }
27
27
 
28
+ .helpTextAddition {
29
+ color: var(--color-fg-subtle);
30
+ }
31
+
28
32
  .horizontal label {
29
33
  width: var(--label-width);
30
34
  }
@@ -39,61 +43,14 @@
39
43
  font-weight: bold;
40
44
  }
41
45
 
42
- /* ---------------- MODIFIED FIELD (DIRECT CONTROL TINT) ---------------- */
43
-
44
- /* Optional scan cue: left bar only (no box around control) */
45
- .inputContainer[data-modified] {
46
- border-left: var(--border-width-thick) solid var(--color-status-warning-border);
47
- padding-left: var(--spacing-xs);
48
- }
49
-
50
- /**
51
- * Tint "real controls" directly.
52
- * This covers:
53
- * - native input/textarea
54
- * - button-based components (Select trigger, Checkbox button, etc.)
55
- * - combobox triggers
56
- */
57
- .inputContainer[data-modified]
58
- :is(input, textarea, button[data-forminput], [role='combobox'][data-forminput]) {
59
- background-color: color-mix(in srgb, var(--color-status-warning-bg) 45%, var(--color-bg-surface));
60
- }
61
-
62
- /**
63
- * If your controls also have borders, nudge them slightly warmer.
64
- * (Keep subtle so it doesn't look like validation.)
65
- */
66
- .inputContainer[data-modified]
67
- :is(input, textarea, button[data-forminput], [role='combobox'][data-forminput]) {
68
- border-color: color-mix(
69
- in srgb,
70
- var(--color-status-warning-border) 35%,
71
- var(--color-border-default)
72
- );
46
+ .messageRow {
47
+ min-height: 1lh;
73
48
  }
74
49
 
75
- /**
76
- * Checkbox/Radio special case:
77
- * - Their "label" is inside children.
78
- * - InputContainer’s own label uses .label class.
79
- * We want to tint ONLY the child labels, not the container label column.
80
- */
50
+ /* Optional: keep this only for controls whose own label lives inside children,
51
+ such as checkbox/radio wrappers. It will not affect Input's top label. */
81
52
  .inputContainer[data-modified] label:not(.label) {
82
53
  background-color: color-mix(in srgb, var(--color-status-warning-bg) 35%, transparent);
83
54
  border-radius: var(--border-radius-default);
84
55
  padding: 2px 6px;
85
56
  }
86
-
87
- /* Correct disabled selector (no accidental “actionable” tint) */
88
- .inputContainer[data-modified]
89
- :is(input, textarea, button[data-forminput], [role='combobox'][data-forminput]):disabled,
90
- .inputContainer[data-modified]
91
- :is(
92
- input,
93
- textarea,
94
- button[data-forminput],
95
- [role='combobox'][data-forminput]
96
- )[aria-disabled='true'] {
97
- background-color: var(--color-disabled-bg);
98
- border-color: var(--color-disabled-border);
99
- }