@tedi-design-system/react 17.0.0 → 17.1.0-rc.2

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 (59) hide show
  1. package/bundle-stats.html +1 -1
  2. package/external/hoist-non-react-statics/external/react-is/cjs/react-is.development.cjs.js +1 -1
  3. package/external/hoist-non-react-statics/external/react-is/cjs/react-is.development.es.js +1 -1
  4. package/external/hoist-non-react-statics/external/react-is/cjs/react-is.production.min.cjs.js +1 -1
  5. package/external/hoist-non-react-statics/external/react-is/cjs/react-is.production.min.es.js +1 -1
  6. package/external/hoist-non-react-statics/external/react-is/index.cjs.js +1 -1
  7. package/external/hoist-non-react-statics/external/react-is/index.es.js +1 -1
  8. package/external/prop-types/external/react-is/cjs/react-is.development.cjs.js +1 -1
  9. package/external/prop-types/external/react-is/cjs/react-is.development.es.js +1 -1
  10. package/external/prop-types/external/react-is/cjs/react-is.production.min.cjs.js +1 -1
  11. package/external/prop-types/external/react-is/cjs/react-is.production.min.es.js +1 -1
  12. package/external/prop-types/external/react-is/index.cjs.js +1 -1
  13. package/external/prop-types/external/react-is/index.es.js +1 -1
  14. package/index.css +1 -1
  15. package/package.json +5 -17
  16. package/src/tedi/components/form/field/field.cjs.js +1 -0
  17. package/src/tedi/components/form/field/field.d.ts +88 -0
  18. package/src/tedi/components/form/field/field.es.js +54 -0
  19. package/src/tedi/components/form/field/field.module.scss.cjs.js +1 -0
  20. package/src/tedi/components/form/field/field.module.scss.es.js +6 -0
  21. package/src/tedi/components/form/file-upload/file-upload.cjs.js +1 -1
  22. package/src/tedi/components/form/file-upload/file-upload.d.ts +14 -2
  23. package/src/tedi/components/form/file-upload/file-upload.es.js +97 -90
  24. package/src/tedi/components/form/input-group/components/input/input.cjs.js +1 -0
  25. package/src/tedi/components/form/input-group/components/input/input.d.ts +19 -0
  26. package/src/tedi/components/form/input-group/components/input/input.es.js +20 -0
  27. package/src/tedi/components/form/input-group/components/prefix/prefix.cjs.js +1 -0
  28. package/src/tedi/components/form/input-group/components/prefix/prefix.d.ts +18 -0
  29. package/src/tedi/components/form/input-group/components/prefix/prefix.es.js +26 -0
  30. package/src/tedi/components/form/input-group/components/suffix/suffix.cjs.js +1 -0
  31. package/src/tedi/components/form/input-group/components/suffix/suffix.d.ts +18 -0
  32. package/src/tedi/components/form/input-group/components/suffix/suffix.es.js +26 -0
  33. package/src/tedi/components/form/input-group/index.d.ts +4 -0
  34. package/src/tedi/components/form/input-group/input-group.cjs.js +1 -0
  35. package/src/tedi/components/form/input-group/input-group.d.ts +87 -0
  36. package/src/tedi/components/form/input-group/input-group.es.js +61 -0
  37. package/src/tedi/components/form/input-group/input-group.module.scss.cjs.js +1 -0
  38. package/src/tedi/components/form/input-group/input-group.module.scss.es.js +16 -0
  39. package/src/tedi/components/form/search/search.cjs.js +1 -1
  40. package/src/tedi/components/form/search/search.es.js +35 -25
  41. package/src/tedi/components/form/select/components/select-control.cjs.js +1 -1
  42. package/src/tedi/components/form/select/components/select-control.es.js +7 -3
  43. package/src/tedi/components/form/select/select.cjs.js +1 -1
  44. package/src/tedi/components/form/select/select.d.ts +3 -2
  45. package/src/tedi/components/form/select/select.es.js +168 -166
  46. package/src/tedi/components/form/slider/slider.cjs.js +1 -0
  47. package/src/tedi/components/form/slider/slider.d.ts +116 -0
  48. package/src/tedi/components/form/slider/slider.es.js +145 -0
  49. package/src/tedi/components/form/slider/slider.module.scss.cjs.js +1 -0
  50. package/src/tedi/components/form/slider/slider.module.scss.es.js +18 -0
  51. package/src/tedi/components/form/textfield/textfield.cjs.js +1 -1
  52. package/src/tedi/components/form/textfield/textfield.d.ts +118 -36
  53. package/src/tedi/components/form/textfield/textfield.es.js +134 -172
  54. package/src/tedi/components/overlays/overlay/overlay.cjs.js +1 -1
  55. package/src/tedi/components/overlays/overlay/overlay.d.ts +12 -0
  56. package/src/tedi/components/overlays/overlay/overlay.es.js +75 -74
  57. package/src/tedi/index.d.ts +3 -0
  58. package/tedi.cjs.js +1 -1
  59. package/tedi.es.js +170 -156
@@ -0,0 +1,18 @@
1
+ const d = {
2
+ "tedi-slider": "tedi-slider-90e24e7d",
3
+ "tedi-slider__container": "tedi-slider__container-525c4b64",
4
+ "tedi-slider__track-row": "tedi-slider__track-row-95e9c2d5",
5
+ "tedi-slider__range-label": "tedi-slider__range-label-a2a6a43b",
6
+ "tedi-slider__track": "tedi-slider__track-a7afc8d6",
7
+ "tedi-slider__thumb-anchor": "tedi-slider__thumb-anchor-7e282370",
8
+ "tedi-slider__input": "tedi-slider__input-b2d1c042",
9
+ "tedi-slider__input--dragging": "tedi-slider__input--dragging-6a2f5f85",
10
+ "tedi-slider__addon": "tedi-slider__addon-6b259d81",
11
+ "tedi-slider__feedback": "tedi-slider__feedback-dad1545e",
12
+ "tedi-slider--disabled": "tedi-slider--disabled-d1da914a",
13
+ "tedi-slider--dragging": "tedi-slider--dragging-c82f4f25",
14
+ "tedi-slider--invalid": "tedi-slider--invalid-e5adda94"
15
+ };
16
+ export {
17
+ d as default
18
+ };
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const i=require("react/jsx-runtime"),p=require("../../../../../external/classnames/index.cjs.js"),r=require("react"),ce=require("../../base/icon/icon.cjs.js"),fe=require("../../buttons/closing-button/closing-button.cjs.js"),xe=require("../../misc/separator/separator.cjs.js"),U=require("../feedback-text/feedback-text.cjs.js"),pe=require("../form-label/form-label.cjs.js"),a=require("./textfield.module.scss.cjs.js"),me=require("../../../helpers/hooks/use-breakpoint-props.cjs.js"),be=require("../../../providers/label-provider/use-labels.cjs.js"),ye={large:24,default:18},C=r.forwardRef((f,G)=>{const{getCurrentBreakpointProps:J}=me.useBreakpointProps(f.defaultServerBreakpoint),{id:u,label:k,className:Q,inputClassName:q,disabled:l,required:A,hideLabel:h,invalid:o,readOnly:B,icon:c,onIconClick:m,size:n,placeholder:T,isArrowsHidden:M=!0,isClearable:R,onClear:b,onChange:d,onChangeEvent:y,onKeyUp:X,onKeyDown:Y,onKeyPress:ve,defaultValue:Z,value:j,onFocus:w,onBlur:F,onClick:ee,helper:t,input:P,name:S,isTextArea:v,...te}=J(f)||{},{getLabel:$}=be.useLabels(),x=r.useRef(null),z=r.useRef(null),[L,V]=r.useState(j??Z??""),_=r.useMemo(()=>{var e;if(t)return Array.isArray(t)?((e=t[0])==null?void 0:e.id)??`${u}-helper`:t.id??`${u}-helper`},[t,u]),N=r.useMemo(()=>j??L,[j,L]),g=R&&N;r.useImperativeHandle(G,()=>({get input(){return x.current},get inner(){return z.current}}));const I=r.useMemo(()=>Array.isArray(t)?o||t.some(e=>e.type==="error"):o||(t==null?void 0:t.type)==="error",[o,t]),re=r.useMemo(()=>!t||Array.isArray(t)&&t.length===0?!1:Array.isArray(t)?!o&&t.every(e=>e.type==="valid"):!o&&t.type==="valid",[o,t]),ae=n==="large"?"default":n,H=r.useCallback(e=>{const s={size:n==="large"?24:n==="small"?16:18,className:p.default(a.default["tedi-textfield__icon"])},de=typeof e=="string"?{...s,name:e}:{...s,...e,className:p.default(s.className,e==null?void 0:e.className)},ue=i.jsx(ce.Icon,{...de}),oe=m?"button":"div";return i.jsx(oe,{className:a.default["tedi-textfield__icon-wrapper"],type:m?"button":void 0,onClick:l?void 0:m,disabled:l,tabIndex:l?-1:0,children:ue})},[l,m,n]),K=r.useCallback(e=>{const s=e.currentTarget.value;V(s),d==null||d(s),y==null||y(e)},[d,y]),E=r.useCallback(()=>{V(""),d==null||d(""),b==null||b()},[d,b]),O=r.useCallback((e,s)=>!!v,[v]),W=r.useCallback((e,s)=>!v,[v]),le=r.useMemo(()=>{const e={...P,id:u,name:S,...h?{"aria-label":k}:{},"aria-describedby":_,"aria-disabled":l||void 0,className:p.default(a.default["tedi-textfield__input"],q,{[a.default["tedi-textfield__input--hidden-arrows"]]:M}),disabled:l,required:A,"aria-invalid":I||void 0,placeholder:T,readOnly:B,onChange:K,value:N,onBlur:F,onFocus:w};return O(f,x)?i.jsx("textarea",{...e,ref:x,tabIndex:l?-1:0}):W(f,x)?i.jsx("input",{...e,ref:x,tabIndex:l?-1:0}):null},[P,u,S,h,k,_,l,q,M,A,I,T,B,K,N,F,w,O,f,W]),D=r.useMemo(()=>{const e={iconSize:ye[n==="large"?"large":"default"],onClick:l?()=>{}:E,disabled:l,"aria-disabled":l||void 0,title:`${$("clear")}`,className:p.default(a.default["tedi-textfield__clear-button"])};return i.jsx(fe.ClosingButton,{...e})},[E,l,$,n]),ie=r.useMemo(()=>i.jsxs("div",{className:a.default["tedi-textfield__right-area"],children:[g&&D,g&&c?i.jsx(xe.Separator,{color:"primary",axis:"vertical",className:a.default["tedi-textfield__separator"]}):null,c&&H(c)]}),[H,c,D,g]),se=p.default(a.default["tedi-textfield"],{[a.default[`tedi-textfield--${n}`]]:n},{[a.default["tedi-textfield--with-icon"]]:c},{[a.default["tedi-textfield--invalid"]]:I},{[a.default["tedi-textfield--valid"]]:re},{[a.default["tedi-textfield--clearable"]]:g},Q),ne=()=>!t||Array.isArray(t)&&t.length===0?null:i.jsx("div",{className:a.default["tedi-textfield__feedback-wrapper"],children:Array.isArray(t)?t.map((e,s)=>i.jsx(U.FeedbackText,{...e,id:`${_}-${s}`},s)):i.jsx(U.FeedbackText,{...t,id:_})});return i.jsxs("div",{"data-name":"textfield",...te,className:se,children:[i.jsx(pe.FormLabel,{id:u,label:k,required:A,hideLabel:h,size:ae}),i.jsxs("div",{className:a.default["tedi-textfield__inner"],onKeyDown:Y,onKeyUp:X,onClick:ee,ref:z,children:[le,R||c?ie:null]}),ne()]})});C.displayName="TextField";exports.TextField=C;exports.default=C;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const a=require("react/jsx-runtime"),A=require("../../../../../external/classnames/index.cjs.js"),i=require("react"),E=require("../../base/icon/icon.cjs.js"),fe=require("../../buttons/closing-button/closing-button.cjs.js"),xe=require("../../misc/separator/separator.cjs.js"),H=require("../feedback-text/feedback-text.cjs.js"),me=require("../field/field.cjs.js"),ye=require("../form-label/form-label.cjs.js"),k=require("../input-group/input-group.cjs.js"),r=require("./textfield.module.scss.cjs.js"),be=require("../../../helpers/hooks/use-breakpoint-props.cjs.js"),ve=require("../../../providers/label-provider/use-labels.cjs.js"),pe={large:24,default:18},N=i.forwardRef((v,K)=>{var V;const{getCurrentBreakpointProps:O}=be.useBreakpointProps(v.defaultServerBreakpoint),{id:_e,label:p,className:D,inputClassName:U,disabled:c,required:q,hideLabel:I,invalid:u,readOnly:C,icon:s,onIconClick:_,size:d="default",placeholder:J,isArrowsHidden:Q=!0,isClearable:B,onClear:y,onChange:o,onChangeEvent:W,onKeyUp:X,onKeyDown:Y,onKeyPress:Z,defaultValue:F,value:h,onFocus:g,onBlur:j,onClick:G,helper:e,input:n,name:ee,isTextArea:te,...re}=O(v)||{},{getLabel:T}=ve.useLabels(),w=i.useRef(null),L=i.useRef(null),[ae,R]=i.useState(h??F??""),S=h??ae,f=!!(B&&S&&!C),x=(V=k.useOptionalInputGroup)==null?void 0:V.call(k),le=i.useId(),ie=x==null?void 0:x.hasExternalLabel,m=v.id??(x==null?void 0:x.inputId)??le;i.useImperativeHandle(K,()=>({get input(){return L.current},get inner(){return w.current}}));const M=i.useMemo(()=>Array.isArray(e)?u||e.some(t=>t.type==="error"):u||(e==null?void 0:e.type)==="error",[u,e]),se=i.useMemo(()=>!e||Array.isArray(e)&&e.length===0?!1:Array.isArray(e)?!u&&e.every(t=>t.type==="valid"):!u&&e.type==="valid",[u,e]),ne=d==="large"?"default":d,b=h!==void 0,de=i.useCallback(t=>{b||R(t),o==null||o(t)},[b,o]),P=i.useCallback(()=>{b||R(""),o==null||o(""),y==null||y()},[b,o,y]),z=i.useCallback(()=>{if(!s)return null;const t={size:d==="large"?24:d==="small"?16:18,className:r.default["tedi-textfield__icon"]},l=typeof s=="string"?{...t,name:s}:{...t,...s,className:A.default(t.className,s.className)};return _?a.jsx("button",{type:"button",className:r.default["tedi-textfield__icon-wrapper"],onClick:c?void 0:_,disabled:c,children:a.jsx(E.Icon,{...l})}):a.jsx("div",{className:r.default["tedi-textfield__icon-wrapper"],"aria-hidden":"true",children:a.jsx(E.Icon,{...l})})},[s,d,_,c]),$=i.useMemo(()=>f?a.jsx(fe.ClosingButton,{iconSize:pe[d==="large"?"large":"default"],onClick:c?void 0:P,disabled:c,title:T("clear"),className:r.default["tedi-textfield__clear-button"]}):null,[f,d,c,P,T]),oe=i.useMemo(()=>!f&&!s?null:a.jsxs("div",{className:r.default["tedi-textfield__right-area"],children:[$,f&&s&&a.jsx(xe.Separator,{color:"primary",axis:"vertical",className:r.default["tedi-textfield__separator"]}),s&&z()]}),[f,s,$,z]),ce=A.default(r.default["tedi-textfield"],{[r.default[`tedi-textfield--${d}`]]:d},{[r.default["tedi-textfield--with-icon"]]:s},{[r.default["tedi-textfield--invalid"]]:M},{[r.default["tedi-textfield--valid"]]:se},{[r.default["tedi-textfield--clearable"]]:f},D),ue=()=>!e||Array.isArray(e)&&e.length===0?null:a.jsx("div",{className:r.default["tedi-textfield__feedback-wrapper"],children:Array.isArray(e)?e.map((t,l)=>a.jsx(H.FeedbackText,{...t,id:`${m}-helper-${l}`},l)):a.jsx(H.FeedbackText,{...e,id:`${m}-helper`})});return a.jsxs("div",{"data-name":"textfield",...re,className:ce,children:[!ie&&a.jsx(ye.FormLabel,{id:m,label:p,required:q,hideLabel:I,size:ne}),a.jsxs("div",{className:r.default["tedi-textfield__inner"],onKeyDown:Y,onKeyUp:X,onKeyPress:Z,onClick:G,ref:w,children:[a.jsx(me.Field,{...n,id:m,name:ee,value:S,defaultValue:F,onChange:de,onChangeEvent:W,disabled:c,readOnly:C,required:q,invalid:M,placeholder:J,className:A.default(r.default["tedi-textfield__input"],U,{[r.default["tedi-textfield__input--hidden-arrows"]]:Q}),onFocus:t=>{var l;(l=n==null?void 0:n.onFocus)==null||l.call(n,t),g==null||g(t)},onBlur:t=>{var l;(l=n==null?void 0:n.onBlur)==null||l.call(n,t),j==null||j(t)},isTextArea:te,"aria-describedby":!e||Array.isArray(e)&&e.length===0?void 0:Array.isArray(e)?e.map((t,l)=>`${m}-helper-${l}`).join(" "):`${m}-helper`,"aria-label":I&&typeof p=="string"?p:void 0,ref:L}),(B||s)&&oe]}),ue()]})});N.displayName="TextField";exports.TextField=N;exports.default=N;
@@ -2,114 +2,196 @@ import { default as React } from 'react';
2
2
  import { BreakpointSupport } from '../../../helpers';
3
3
  import { IconWithoutBackgroundProps } from '../../base/icon/icon';
4
4
  import { FeedbackTextProps } from '../feedback-text/feedback-text';
5
+ import { FieldElement } from '../field/field';
5
6
  import { FormLabelProps } from '../form-label/form-label';
6
7
  type TextFieldBreakpointProps = {
7
8
  /**
8
- * Input field size
9
+ * Controls the visual size of the text field.
10
+ *
11
+ * - `'small'` → Compact version (smaller height, padding, and font size)
12
+ * - `'default'` → Standard size (most commonly used)
13
+ * - `'large'` → Larger touch target, bigger text and padding
14
+ *
9
15
  * @default 'default'
10
16
  */
11
17
  size?: 'default' | 'small' | 'large';
12
18
  /**
13
- * Icon name or configuration for the input field.
19
+ * Icon displayed inside the text field on the right side.
20
+ *
21
+ * Accepts either:
22
+ * - A simple string (icon name) → e.g. `'search'`, `'user'`, `'calendar'`
23
+ * - A full `IconWithoutBackgroundProps` object for advanced configuration (size, color, className, etc.)
24
+ *
25
+ * When `onIconClick` is provided, the icon becomes a clickable button.
26
+ * Otherwise, it is rendered as a non-interactive decorative element.
14
27
  */
15
28
  icon?: string | IconWithoutBackgroundProps;
16
29
  /**
17
- * Whether to render a textarea instead of an input.
30
+ * If `true`, renders a `<textarea>` instead of a regular `<input>`.
31
+ * Useful for multi-line text input (comments, descriptions, addresses, etc.).
32
+ *
33
+ * Note: When using `isTextArea`, the component still behaves like a text field
34
+ * (same styling, clear button, icon support, validation, etc.).
35
+ *
36
+ * @default false
18
37
  */
19
38
  isTextArea?: boolean;
20
39
  /**
21
- * Placeholder text displayed inside the input.
40
+ * Placeholder text shown when the field is empty.
41
+ *
42
+ * Recommended to be short and descriptive. Avoid using placeholder as a label.
22
43
  */
23
44
  placeholder?: string;
24
45
  /**
25
- * Whether the input includes a clear button.
46
+ * When `true`, displays a clear (×) button on the right side when the field has a value.
47
+ *
48
+ * Clicking the button clears the input and calls `onClear` (if provided).
49
+ *
50
+ * @default false
26
51
  */
27
52
  isClearable?: boolean;
28
53
  /**
29
- * Custom CSS classes for the container.
54
+ * Additional CSS class name applied to the root container (`<div>`).
55
+ *
56
+ * Use this for layout adjustments, custom spacing, or theming the entire text field wrapper.
30
57
  */
31
58
  className?: string;
32
59
  };
33
- export interface TextFieldProps extends BreakpointSupport<TextFieldBreakpointProps>, Omit<FormLabelProps, 'size'> {
60
+ export interface TextFieldProps extends BreakpointSupport<TextFieldBreakpointProps>, Omit<FormLabelProps, 'size' | 'id' | 'label'> {
34
61
  /**
35
- * Unique identifier for the input field.
62
+ * Unique identifier for the text field.
63
+ *
64
+ * Required for accessibility (associates label, helper text, and input).
65
+ * Also used to generate `aria-describedby` and helper IDs automatically.
36
66
  */
37
- id: string;
67
+ id?: string;
68
+ label?: React.ReactNode;
38
69
  /**
39
- * Name attribute for the input element.
70
+ * Name attribute for the underlying input/textarea element.
71
+ *
72
+ * Important for form submission and integration with form libraries (React Hook Form, Formik, etc.).
40
73
  */
41
74
  name?: string;
42
75
  /**
43
- * Custom CSS classes for the input element.
76
+ * Custom CSS class applied directly to the `<input>` or `<textarea>` element (via the internal `Field` component).
77
+ *
78
+ * Use this when you need to style the input itself (e.g. text alignment, font, custom focus styles).
79
+ *
80
+ * Note: The root container uses `className`.
44
81
  */
45
82
  inputClassName?: string;
46
83
  /**
47
- * Callback triggered when the input value changes.
84
+ * Callback fired when the value changes. Receives the new value as a plain string.
85
+ *
86
+ * Preferred for most use cases (simpler than `onChangeEvent`).
87
+ *
88
+ * @param value - The current value of the field after change
48
89
  */
49
90
  onChange?: (value: string) => void;
50
91
  /**
51
- * Callback triggered with the change event.
92
+ * Native `onChange` event handler.
93
+ *
94
+ * Gives you access to the full `ChangeEvent` object (useful if you need `event.target`, `event.preventDefault()`, etc.).
95
+ *
96
+ * Note: Both `onChange` and `onChangeEvent` are called when the value changes.
52
97
  */
53
- onChangeEvent?: React.ChangeEventHandler<HTMLTextAreaElement | HTMLInputElement>;
98
+ onChangeEvent?: React.ChangeEventHandler<FieldElement>;
54
99
  /**
55
- * Callback for keypress events.
100
+ * Keyboard event handlers attached to the inner wrapper `<div>`.
101
+ *
102
+ * Useful for handling Enter key submission, arrow key navigation, or custom keyboard shortcuts.
103
+ *
104
+ * Note: These are **not** attached to the input/textarea directly, but to the surrounding container.
56
105
  */
57
106
  onKeyPress?: React.KeyboardEventHandler<HTMLDivElement>;
58
- /**
59
- * Callback for keydown events.
60
- */
61
107
  onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
62
- /**
63
- * Callback for keyup events.
64
- */
65
108
  onKeyUp?: React.KeyboardEventHandler<HTMLDivElement>;
66
109
  /**
67
- * Initial default value of the input.
110
+ * Default value for **uncontrolled** usage.
111
+ *
112
+ * Use this when you don't want to manage state yourself.
113
+ * The component will manage its internal state.
68
114
  */
69
115
  defaultValue?: string;
70
116
  /**
71
- * Controlled value of the input field.
117
+ * Controlled value of the text field.
118
+ *
119
+ * When provided, the component becomes **fully controlled**.
120
+ * You must update this value via `onChange` to reflect user input.
72
121
  */
73
122
  value?: string;
74
123
  /**
75
- * Callback for clicking the icon.
124
+ * Called when the user clicks on the icon (only works if `icon` is provided).
125
+ *
126
+ * The icon is automatically wrapped in a `<button>` when this prop is present.
127
+ *
128
+ * @param event - Mouse event from the icon wrapper
76
129
  */
77
130
  onIconClick?: (event: React.MouseEvent<HTMLButtonElement | HTMLDivElement>) => void;
78
131
  /**
79
- * Callback for input container clicks.
132
+ * Click handler for the entire inner container (the area around the input).
133
+ *
134
+ * Can be used to focus the input when clicking anywhere in the field area,
135
+ * or to trigger custom behavior.
80
136
  */
81
137
  onClick?: React.MouseEventHandler<HTMLDivElement>;
82
138
  /**
83
- * Whether the input is disabled.
139
+ * Disables the entire text field.
140
+ *
141
+ * When `true`:
142
+ * - Input becomes non-editable and non-focusable
143
+ * - Clear button and icon are disabled
144
+ * - Visual disabled styles are applied
84
145
  */
85
146
  disabled?: boolean;
86
147
  /**
87
- * Whether the input is marked as invalid.
148
+ * Marks the field as invalid and triggers error styling.
149
+ *
150
+ * Also affects `aria-invalid` attribute.
151
+ *
152
+ * Note: The `helper` prop can override this if it contains items with `type: 'error'`.
88
153
  */
89
154
  invalid?: boolean;
90
155
  /**
91
- * Whether the input is read-only.
156
+ * Makes the field read-only.
157
+ *
158
+ * User can focus and select text, but cannot modify the value.
159
+ * Useful for pre-filled data that should not be changed.
92
160
  */
93
161
  readOnly?: boolean;
94
162
  /**
95
- * Helper text or feedback messages.
163
+ * Helper text, success message, or error message displayed below the field.
164
+ *
165
+ * Accepts either:
166
+ * - A single `FeedbackTextProps` object
167
+ * - An array of `FeedbackTextProps` (useful for multiple messages or mixed error/success states)
168
+ *
169
+ * The component automatically detects error states from helper items.
96
170
  */
97
171
  helper?: FeedbackTextProps | FeedbackTextProps[];
98
172
  /**
99
- * Callback for input focus events.
173
+ * Fired when the input/textarea receives focus.
100
174
  */
101
- onFocus?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
175
+ onFocus?: React.FocusEventHandler<FieldElement>;
102
176
  /**
103
- * Callback for input blur events.
177
+ * Fired when the input/textarea loses focus.
104
178
  */
105
- onBlur?: React.FocusEventHandler<HTMLInputElement | HTMLTextAreaElement>;
179
+ onBlur?: React.FocusEventHandler<FieldElement>;
106
180
  /**
107
- * Whether to hide arrows for number inputs.
181
+ * Hides the spinner/arrows for number inputs (`type="number"`).
182
+ *
183
+ * Only has effect when the underlying input has `type="number"`.
184
+ *
108
185
  * @default true
109
186
  */
110
187
  isArrowsHidden?: boolean;
111
188
  /**
112
- * Callback triggered when the clear button is clicked.
189
+ * Callback fired when the clear button (×) is clicked.
190
+ *
191
+ * Useful if you need to perform additional actions besides clearing the value
192
+ * (e.g. analytics, resetting related fields, etc.).
193
+ *
194
+ * Note: The field value is automatically cleared regardless of this callback.
113
195
  */
114
196
  onClear?: () => void;
115
197
  /**
@@ -118,7 +200,7 @@ export interface TextFieldProps extends BreakpointSupport<TextFieldBreakpointPro
118
200
  input?: React.InputHTMLAttributes<HTMLInputElement> | React.TextareaHTMLAttributes<HTMLTextAreaElement>;
119
201
  }
120
202
  export interface TextFieldForwardRef {
121
- input: HTMLInputElement | HTMLTextAreaElement | null;
203
+ input: FieldElement | null;
122
204
  inner: HTMLDivElement | null;
123
205
  }
124
206
  export declare const TextField: React.ForwardRefExoticComponent<TextFieldProps & React.RefAttributes<TextFieldForwardRef>>;
@@ -1,198 +1,160 @@
1
- import { jsx as n, jsxs as w } from "react/jsx-runtime";
2
- import p from "../../../../../external/classnames/index.es.js";
3
- import t, { forwardRef as ue } from "react";
4
- import { Icon as ce } from "../../base/icon/icon.es.js";
5
- import { ClosingButton as fe } from "../../buttons/closing-button/closing-button.es.js";
6
- import { Separator as me } from "../../misc/separator/separator.es.js";
7
- import { FeedbackText as U } from "../feedback-text/feedback-text.es.js";
8
- import { FormLabel as pe } from "../form-label/form-label.es.js";
9
- import a from "./textfield.module.scss.es.js";
10
- import { useBreakpointProps as xe } from "../../../helpers/hooks/use-breakpoint-props.es.js";
1
+ import { jsx as n, jsxs as I } from "react/jsx-runtime";
2
+ import k from "../../../../../external/classnames/index.es.js";
3
+ import p, { forwardRef as me, useMemo as v, useCallback as C } from "react";
4
+ import { Icon as M } from "../../base/icon/icon.es.js";
5
+ import { ClosingButton as pe } from "../../buttons/closing-button/closing-button.es.js";
6
+ import { Separator as ye } from "../../misc/separator/separator.es.js";
7
+ import { FeedbackText as O } from "../feedback-text/feedback-text.es.js";
8
+ import { Field as xe } from "../field/field.es.js";
9
+ import { FormLabel as ve } from "../form-label/form-label.es.js";
10
+ import { useOptionalInputGroup as he } from "../input-group/input-group.es.js";
11
+ import t from "./textfield.module.scss.es.js";
12
+ import { useBreakpointProps as _e } from "../../../helpers/hooks/use-breakpoint-props.es.js";
11
13
  import { useLabels as be } from "../../../providers/label-provider/use-labels.es.js";
12
- const ye = {
14
+ const ge = {
13
15
  large: 24,
14
16
  default: 18
15
- }, ve = ue((f, G) => {
16
- const { getCurrentBreakpointProps: J } = xe(f.defaultServerBreakpoint), {
17
- id: d,
18
- label: N,
19
- className: Q,
20
- inputClassName: B,
21
- disabled: i,
22
- required: g,
23
- hideLabel: h,
24
- invalid: u,
25
- readOnly: R,
26
- icon: c,
27
- onIconClick: x,
28
- size: s,
29
- placeholder: M,
30
- isArrowsHidden: F = !0,
31
- isClearable: P,
32
- onClear: b,
17
+ }, Ae = me((h, q) => {
18
+ var K;
19
+ const { getCurrentBreakpointProps: D } = _e(h.defaultServerBreakpoint), {
20
+ id: Ne,
21
+ label: _,
22
+ className: U,
23
+ inputClassName: J,
24
+ disabled: d,
25
+ required: B,
26
+ hideLabel: w,
27
+ invalid: c,
28
+ readOnly: F,
29
+ icon: a,
30
+ onIconClick: b,
31
+ size: s = "default",
32
+ placeholder: Q,
33
+ isArrowsHidden: W = !0,
34
+ isClearable: R,
35
+ onClear: y,
33
36
  onChange: o,
34
- onChangeEvent: y,
35
- onKeyUp: X,
36
- onKeyDown: Y,
37
- onKeyPress: _e,
38
- defaultValue: Z,
39
- value: k,
40
- onFocus: T,
41
- onBlur: z,
37
+ onChangeEvent: X,
38
+ onKeyUp: Y,
39
+ onKeyDown: Z,
40
+ onKeyPress: G,
41
+ defaultValue: $,
42
+ value: g,
43
+ onFocus: A,
44
+ onBlur: N,
42
45
  onClick: ee,
43
- helper: r,
44
- input: S,
45
- name: V,
46
- isTextArea: v,
47
- ...re
48
- } = J(f) || {}, { getLabel: $ } = be(), m = t.useRef(null), L = t.useRef(null), [E, H] = t.useState(k ?? Z ?? ""), _ = t.useMemo(() => {
49
- var e;
50
- if (r)
51
- return Array.isArray(r) ? ((e = r[0]) == null ? void 0 : e.id) ?? `${d}-helper` : r.id ?? `${d}-helper`;
52
- }, [r, d]), I = t.useMemo(() => k ?? E, [k, E]), A = P && I;
53
- t.useImperativeHandle(G, () => ({
46
+ helper: e,
47
+ input: l,
48
+ name: re,
49
+ isTextArea: te,
50
+ ...ie
51
+ } = D(h) || {}, { getLabel: z } = be(), L = p.useRef(null), S = p.useRef(null), [ae, P] = p.useState(g ?? $ ?? ""), T = g ?? ae, f = !!(R && T && !F), u = (K = he) == null ? void 0 : K(), le = p.useId(), ne = u == null ? void 0 : u.hasExternalLabel, m = h.id ?? (u == null ? void 0 : u.inputId) ?? le;
52
+ p.useImperativeHandle(q, () => ({
54
53
  get input() {
55
- return m.current;
54
+ return S.current;
56
55
  },
57
56
  get inner() {
58
57
  return L.current;
59
58
  }
60
59
  }));
61
- const C = t.useMemo(() => Array.isArray(r) ? u || r.some((e) => e.type === "error") : u || (r == null ? void 0 : r.type) === "error", [u, r]), te = t.useMemo(() => !r || Array.isArray(r) && r.length === 0 ? !1 : Array.isArray(r) ? !u && r.every((e) => e.type === "valid") : !u && r.type === "valid", [u, r]), ae = s === "large" ? "default" : s, K = t.useCallback(
62
- (e) => {
63
- const l = {
64
- size: s === "large" ? 24 : s === "small" ? 16 : 18,
65
- className: p(a["tedi-textfield__icon"])
66
- }, oe = typeof e == "string" ? { ...l, name: e } : { ...l, ...e, className: p(l.className, e == null ? void 0 : e.className) }, de = /* @__PURE__ */ n(ce, { ...oe });
67
- return /* @__PURE__ */ n(
68
- x ? "button" : "div",
69
- {
70
- className: a["tedi-textfield__icon-wrapper"],
71
- type: x ? "button" : void 0,
72
- onClick: i ? void 0 : x,
73
- disabled: i,
74
- tabIndex: i ? -1 : 0,
75
- children: de
76
- }
77
- );
60
+ const V = v(() => Array.isArray(e) ? c || e.some((r) => r.type === "error") : c || (e == null ? void 0 : e.type) === "error", [c, e]), se = v(() => !e || Array.isArray(e) && e.length === 0 ? !1 : Array.isArray(e) ? !c && e.every((r) => r.type === "valid") : !c && e.type === "valid", [c, e]), oe = s === "large" ? "default" : s, x = g !== void 0, de = C(
61
+ (r) => {
62
+ x || P(r), o == null || o(r);
78
63
  },
79
- [i, x, s]
80
- ), W = t.useCallback(
81
- (e) => {
82
- const l = e.currentTarget.value;
83
- H(l), o == null || o(l), y == null || y(e);
84
- },
85
- [o, y]
86
- ), j = t.useCallback(() => {
87
- H(""), o == null || o(""), b == null || b();
88
- }, [o, b]), q = t.useCallback(
89
- (e, l) => !!v,
90
- [v]
91
- ), D = t.useCallback(
92
- (e, l) => !v,
93
- [v]
94
- ), ie = t.useMemo(() => {
95
- const e = {
96
- ...S,
97
- id: d,
98
- name: V,
99
- ...h ? { "aria-label": N } : {},
100
- "aria-describedby": _,
101
- "aria-disabled": i || void 0,
102
- className: p(a["tedi-textfield__input"], B, {
103
- [a["tedi-textfield__input--hidden-arrows"]]: F
104
- }),
105
- disabled: i,
106
- required: g,
107
- "aria-invalid": C || void 0,
108
- placeholder: M,
109
- readOnly: R,
110
- onChange: W,
111
- value: I,
112
- onBlur: z,
113
- onFocus: T
114
- };
115
- return q(f, m) ? /* @__PURE__ */ n(
116
- "textarea",
117
- {
118
- ...e,
119
- ref: m,
120
- tabIndex: i ? -1 : 0
121
- }
122
- ) : D(f, m) ? /* @__PURE__ */ n(
123
- "input",
64
+ [x, o]
65
+ ), j = C(() => {
66
+ x || P(""), o == null || o(""), y == null || y();
67
+ }, [x, o, y]), E = C(() => {
68
+ if (!a) return null;
69
+ const r = {
70
+ size: s === "large" ? 24 : s === "small" ? 16 : 18,
71
+ className: t["tedi-textfield__icon"]
72
+ }, i = typeof a == "string" ? { ...r, name: a } : { ...r, ...a, className: k(r.className, a.className) };
73
+ return b ? /* @__PURE__ */ n(
74
+ "button",
124
75
  {
125
- ...e,
126
- ref: m,
127
- tabIndex: i ? -1 : 0
76
+ type: "button",
77
+ className: t["tedi-textfield__icon-wrapper"],
78
+ onClick: d ? void 0 : b,
79
+ disabled: d,
80
+ children: /* @__PURE__ */ n(M, { ...i })
128
81
  }
129
- ) : null;
130
- }, [
131
- S,
132
- d,
133
- V,
134
- h,
135
- N,
136
- _,
137
- i,
138
- B,
139
- F,
140
- g,
141
- C,
142
- M,
143
- R,
144
- W,
145
- I,
146
- z,
147
- T,
148
- q,
149
- f,
150
- D
151
- ]), O = t.useMemo(() => {
152
- const e = {
153
- iconSize: ye[s === "large" ? "large" : "default"],
154
- onClick: i ? () => {
155
- } : j,
156
- disabled: i,
157
- "aria-disabled": i || void 0,
158
- title: `${$("clear")}`,
159
- className: p(a["tedi-textfield__clear-button"])
160
- };
161
- return /* @__PURE__ */ n(fe, { ...e });
162
- }, [j, i, $, s]), le = t.useMemo(() => /* @__PURE__ */ w("div", { className: a["tedi-textfield__right-area"], children: [
163
- A && O,
164
- A && c ? /* @__PURE__ */ n(me, { color: "primary", axis: "vertical", className: a["tedi-textfield__separator"] }) : null,
165
- c && K(c)
166
- ] }), [K, c, O, A]), ne = p(
167
- a["tedi-textfield"],
168
- { [a[`tedi-textfield--${s}`]]: s },
169
- { [a["tedi-textfield--with-icon"]]: c },
170
- { [a["tedi-textfield--invalid"]]: C },
171
- { [a["tedi-textfield--valid"]]: te },
172
- { [a["tedi-textfield--clearable"]]: A },
173
- Q
174
- ), se = () => !r || Array.isArray(r) && r.length === 0 ? null : /* @__PURE__ */ n("div", { className: a["tedi-textfield__feedback-wrapper"], children: Array.isArray(r) ? r.map((e, l) => /* @__PURE__ */ n(U, { ...e, id: `${_}-${l}` }, l)) : /* @__PURE__ */ n(U, { ...r, id: _ }) });
175
- return /* @__PURE__ */ w("div", { "data-name": "textfield", ...re, className: ne, children: [
176
- /* @__PURE__ */ n(pe, { id: d, label: N, required: g, hideLabel: h, size: ae }),
177
- /* @__PURE__ */ w(
82
+ ) : /* @__PURE__ */ n("div", { className: t["tedi-textfield__icon-wrapper"], "aria-hidden": "true", children: /* @__PURE__ */ n(M, { ...i }) });
83
+ }, [a, s, b, d]), H = v(() => f ? /* @__PURE__ */ n(
84
+ pe,
85
+ {
86
+ iconSize: ge[s === "large" ? "large" : "default"],
87
+ onClick: d ? void 0 : j,
88
+ disabled: d,
89
+ title: z("clear"),
90
+ className: t["tedi-textfield__clear-button"]
91
+ }
92
+ ) : null, [f, s, d, j, z]), ce = v(() => !f && !a ? null : /* @__PURE__ */ I("div", { className: t["tedi-textfield__right-area"], children: [
93
+ H,
94
+ f && a && /* @__PURE__ */ n(ye, { color: "primary", axis: "vertical", className: t["tedi-textfield__separator"] }),
95
+ a && E()
96
+ ] }), [f, a, H, E]), fe = k(
97
+ t["tedi-textfield"],
98
+ { [t[`tedi-textfield--${s}`]]: s },
99
+ { [t["tedi-textfield--with-icon"]]: a },
100
+ { [t["tedi-textfield--invalid"]]: V },
101
+ { [t["tedi-textfield--valid"]]: se },
102
+ { [t["tedi-textfield--clearable"]]: f },
103
+ U
104
+ ), ue = () => !e || Array.isArray(e) && e.length === 0 ? null : /* @__PURE__ */ n("div", { className: t["tedi-textfield__feedback-wrapper"], children: Array.isArray(e) ? e.map((r, i) => /* @__PURE__ */ n(O, { ...r, id: `${m}-helper-${i}` }, i)) : /* @__PURE__ */ n(O, { ...e, id: `${m}-helper` }) });
105
+ return /* @__PURE__ */ I("div", { "data-name": "textfield", ...ie, className: fe, children: [
106
+ !ne && /* @__PURE__ */ n(ve, { id: m, label: _, required: B, hideLabel: w, size: oe }),
107
+ /* @__PURE__ */ I(
178
108
  "div",
179
109
  {
180
- className: a["tedi-textfield__inner"],
181
- onKeyDown: Y,
182
- onKeyUp: X,
110
+ className: t["tedi-textfield__inner"],
111
+ onKeyDown: Z,
112
+ onKeyUp: Y,
113
+ onKeyPress: G,
183
114
  onClick: ee,
184
115
  ref: L,
185
116
  children: [
186
- ie,
187
- P || c ? le : null
117
+ /* @__PURE__ */ n(
118
+ xe,
119
+ {
120
+ ...l,
121
+ id: m,
122
+ name: re,
123
+ value: T,
124
+ defaultValue: $,
125
+ onChange: de,
126
+ onChangeEvent: X,
127
+ disabled: d,
128
+ readOnly: F,
129
+ required: B,
130
+ invalid: V,
131
+ placeholder: Q,
132
+ className: k(t["tedi-textfield__input"], J, {
133
+ [t["tedi-textfield__input--hidden-arrows"]]: W
134
+ }),
135
+ onFocus: (r) => {
136
+ var i;
137
+ (i = l == null ? void 0 : l.onFocus) == null || i.call(l, r), A == null || A(r);
138
+ },
139
+ onBlur: (r) => {
140
+ var i;
141
+ (i = l == null ? void 0 : l.onBlur) == null || i.call(l, r), N == null || N(r);
142
+ },
143
+ isTextArea: te,
144
+ "aria-describedby": !e || Array.isArray(e) && e.length === 0 ? void 0 : Array.isArray(e) ? e.map((r, i) => `${m}-helper-${i}`).join(" ") : `${m}-helper`,
145
+ "aria-label": w && typeof _ == "string" ? _ : void 0,
146
+ ref: S
147
+ }
148
+ ),
149
+ (R || a) && ce
188
150
  ]
189
151
  }
190
152
  ),
191
- se()
153
+ ue()
192
154
  ] });
193
155
  });
194
- ve.displayName = "TextField";
156
+ Ae.displayName = "TextField";
195
157
  export {
196
- ve as TextField,
197
- ve as default
158
+ Ae as TextField,
159
+ Ae as default
198
160
  };