@dt-dds/react-text-field 1.0.0-beta.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,478 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __objRest = (source, exclude) => {
21
+ var target = {};
22
+ for (var prop in source)
23
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
+ target[prop] = source[prop];
25
+ if (source != null && __getOwnPropSymbols)
26
+ for (var prop of __getOwnPropSymbols(source)) {
27
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
+ target[prop] = source[prop];
29
+ }
30
+ return target;
31
+ };
32
+
33
+ // src/TextField.tsx
34
+ import {
35
+ forwardRef,
36
+ useEffect,
37
+ useState
38
+ } from "react";
39
+ import { Icon } from "@dt-dds/react-icon";
40
+ import { IconButton } from "@dt-dds/react-icon-button";
41
+ import { LabelField } from "@dt-dds/react-label-field";
42
+ import { Typography } from "@dt-dds/react-typography";
43
+
44
+ // src/TextField.styled.ts
45
+ import styled from "@emotion/styled";
46
+
47
+ // src/constants/helpers.ts
48
+ var getThemedBackgroundFill = (backgroundFill, theme) => ({
49
+ default: theme.palette.surface.default,
50
+ contrast: theme.palette.surface.contrast,
51
+ light: theme.palette.surface.light
52
+ })[backgroundFill] || theme.palette.surface.default;
53
+
54
+ // src/TextField.styled.ts
55
+ var TextFieldStyled = styled.div`
56
+ ${({ theme, isFloatingLabel = true, hasPrefix = false }) => `
57
+ display: flex;
58
+ flex-direction: column;
59
+ gap: ${theme.spacing.spacing_20};
60
+ width: 100%;
61
+ position: relative;
62
+
63
+ ${hasPrefix ? `
64
+ label {
65
+ left: 0;
66
+ padding-left: ${isFloatingLabel ? theme.spacing.l : ""};
67
+ }
68
+ ` : ""}
69
+
70
+ :has(input[disabled]) {
71
+ i, label > span {
72
+ color: ${theme.palette.content.light};
73
+ }
74
+ }
75
+
76
+ &:has(input[readonly]:not(input[disabled])) {
77
+ i, label, label > span {
78
+ color: ${theme.palette.content.medium};
79
+ }
80
+ }
81
+
82
+ ${!isFloatingLabel && `
83
+ &:has(input[readonly]:not([disabled]):focus) {
84
+ label {
85
+ color: ${theme.palette.informative.default};
86
+ }
87
+ }
88
+ `}
89
+ `}
90
+
91
+ input[type="search"]::-webkit-search-decoration,
92
+ input[type="search"]::-webkit-search-cancel-button,
93
+ input[type="search"]::-webkit-search-results-button,
94
+ input[type="search"]::-webkit-search-results-decoration {
95
+ display: none;
96
+ }
97
+ `;
98
+ var InputContainerStyled = styled.div`
99
+ ${({ theme, isFloatingLabel }) => `
100
+ position: relative;
101
+ display: flex;
102
+ flex-direction: column;
103
+ gap: ${isFloatingLabel ? "0" : theme.spacing.spacing_30};
104
+ `}
105
+ `;
106
+ var InputFieldStyled = styled.input`
107
+ ${({ theme, isFloatingLabel, scale, isFocused }) => `
108
+ ${theme.fontStyles.bodyMdRegular}
109
+ border: 0;
110
+ outline: 0;
111
+ width: 100%;
112
+ background-color: inherit;
113
+
114
+ &:focus {
115
+ outline: none;
116
+ }
117
+
118
+ &:read-only {
119
+ color: ${theme.palette.content.medium};
120
+ }
121
+
122
+ input:-webkit-autofill,
123
+ input:-webkit-autofill:hover,
124
+ input:-webkit-autofill:focus,
125
+ input:-webkit-autofill:active {
126
+ transition: background-color 5000s ease-in-out 0s;
127
+ }
128
+
129
+ &[readonly]::placeholder,
130
+ &[readonly]:focus::placeholder {
131
+ color: transparent;
132
+ }
133
+
134
+ &::placeholder {
135
+ color: ${isFloatingLabel && !isFocused ? "transparent" : theme.palette.content.medium};
136
+ }
137
+
138
+ &:disabled {
139
+ color: ${theme.palette.content.light};
140
+ }
141
+
142
+ color: ${theme.palette.content.default};
143
+
144
+ ${scale === "compact" ? `
145
+ padding: ${isFloatingLabel ? `${theme.spacing.spacing_60} ${theme.spacing.spacing_40} ${theme.spacing.spacing_30} ${theme.spacing.spacing_40}` : `14px ${theme.spacing.spacing_30}`};
146
+ ` : `
147
+ padding: ${isFloatingLabel ? `28px ${theme.spacing.spacing_40} ${theme.spacing.spacing_40}` : `20px ${theme.spacing.spacing_40}`};
148
+ `}
149
+ `}
150
+ `;
151
+ var InputExtraPrefixStyled = styled.div`
152
+ ${({ theme, onClick }) => {
153
+ const isClickable = !!onClick;
154
+ return `
155
+ display: flex;
156
+ cursor: ${isClickable ? "pointer" : "default"};
157
+ padding-left: ${theme.spacing.spacing_40}};
158
+
159
+ &:focus-visible {
160
+ outline: 2px solid ${theme.palette.border.dark};
161
+ outline-offset: 1px;
162
+ }
163
+
164
+ ${isClickable && `
165
+ &:hover > i {
166
+ color: ${theme.palette.content.dark};
167
+ }
168
+ `}
169
+
170
+ `;
171
+ }}
172
+ `;
173
+ var InputExtraSuffixStyled = styled.div`
174
+ ${({ theme, onClick }) => {
175
+ const isClickable = !!onClick;
176
+ return `
177
+ display: flex;
178
+ cursor: ${isClickable ? "pointer" : "default"};
179
+ margin-right: ${theme.spacing.spacing_40}};
180
+
181
+ &:focus-visible {
182
+ outline: 2px solid ${theme.palette.border.dark};
183
+ outline-offset: 1px;
184
+ }
185
+
186
+ ${isClickable && `
187
+ &:hover > i {
188
+ color: ${theme.palette.primary.default};
189
+ }
190
+ `}
191
+ `;
192
+ }}
193
+ `;
194
+ var TextFieldMessageStyled = styled.div`
195
+ padding-left: ${({ theme }) => theme.spacing.spacing_40};
196
+ `;
197
+ var InputWrapperStyled = styled.div`
198
+ ${({ theme, isFloatingLabel, variant, backgroundFill, hasError }) => {
199
+ const borderColor = hasError ? theme.palette.error.default : theme.palette.border.medium;
200
+ const borderFocusColor = hasError ? theme.palette.error.default : theme.palette.informative.default;
201
+ return `
202
+ display:flex;
203
+ flex-direction: row;
204
+ align-items: center;
205
+ min-width: 198px;
206
+ width: 100%;
207
+ color: ${theme.palette.content.default};
208
+ background-color: ${getThemedBackgroundFill(backgroundFill, theme)};
209
+
210
+ ${variant === "outlined" ? `border-radius: ${theme.shape.formField};
211
+ border: 1px solid ${borderColor};
212
+
213
+ &:focus-within,
214
+ &:hover:not([disabled]) {
215
+ border: 1px solid ${borderFocusColor};
216
+ }
217
+
218
+ &:hover:([disabled]) {
219
+ border: 1px solid ${borderColor};
220
+ }
221
+ ` : `border-radius: ${theme.shape.formField} ${theme.shape.formField} 0 0;
222
+ border-bottom: 1px solid ${borderColor};
223
+
224
+ &:focus-within,
225
+ &:hover:not([disabled]) {
226
+ border-bottom: 1px solid ${borderFocusColor};
227
+ }
228
+ `};
229
+
230
+ &:has(input[readonly]:not([disabled])) {
231
+ background-color: ${theme.palette.surface.light};
232
+ border: 1px solid ${theme.palette.surface.default};
233
+
234
+ &:focus-within, &:hover {
235
+ border: 1px solid ${theme.palette.informative.default};
236
+ }
237
+ }
238
+
239
+ &:has(input[disabled]), &:has(input[disabled]) > * {
240
+ cursor: not-allowed;
241
+
242
+ &:hover {
243
+ border-color: ${borderColor};
244
+ }
245
+
246
+ input::placeholder {
247
+ color: ${isFloatingLabel ? "transparent" : theme.palette.content.light};
248
+ }
249
+ }
250
+ `;
251
+ }}
252
+ `;
253
+
254
+ // src/TextField.tsx
255
+ import { jsx, jsxs } from "react/jsx-runtime";
256
+ var EXTRA_SUFFIX_DATA_TEST_ID = "extra-suffix";
257
+ var TextField = forwardRef(
258
+ (_a, ref) => {
259
+ var _b = _a, {
260
+ dataTestId,
261
+ hasError = false,
262
+ extraPrefix,
263
+ extraSuffix,
264
+ label,
265
+ labelIcon,
266
+ isFloatingLabel = true,
267
+ name,
268
+ id,
269
+ required,
270
+ requiredMessage,
271
+ style,
272
+ children,
273
+ initialValue,
274
+ inputRef,
275
+ isInputFocused,
276
+ message: messageProp = "",
277
+ type = "text",
278
+ variant = "outlined",
279
+ scale = "standard",
280
+ backgroundFill = "default",
281
+ disabled = false,
282
+ onChange = () => null,
283
+ onResetInput = () => null
284
+ } = _b, rest = __objRest(_b, [
285
+ "dataTestId",
286
+ "hasError",
287
+ "extraPrefix",
288
+ "extraSuffix",
289
+ "label",
290
+ "labelIcon",
291
+ "isFloatingLabel",
292
+ "name",
293
+ "id",
294
+ "required",
295
+ "requiredMessage",
296
+ "style",
297
+ "children",
298
+ "initialValue",
299
+ "inputRef",
300
+ "isInputFocused",
301
+ "message",
302
+ "type",
303
+ "variant",
304
+ "scale",
305
+ "backgroundFill",
306
+ "disabled",
307
+ "onChange",
308
+ "onResetInput"
309
+ ]);
310
+ const [activeInput, setActiveInput] = useState(false);
311
+ const [inputValue, setInputValue] = useState("");
312
+ const [hasRequiredError, setHasRequiredError] = useState(false);
313
+ const textFieldId = id != null ? id : label.replaceAll(" ", "-").toLowerCase();
314
+ const testId = dataTestId != null ? dataTestId : `${label.replaceAll(" ", "-").toLowerCase()}-text-field`;
315
+ useEffect(() => {
316
+ if (!!initialValue) {
317
+ setInputValue(initialValue);
318
+ setHasRequiredError(false);
319
+ } else {
320
+ setInputValue("");
321
+ }
322
+ }, [initialValue]);
323
+ const handleChange = (event) => {
324
+ setInputValue(event.target.value);
325
+ setHasRequiredError(false);
326
+ if (onChange) {
327
+ onChange(event);
328
+ }
329
+ };
330
+ const onFocus = (event) => {
331
+ if (!rest.readOnly) {
332
+ setActiveInput(true);
333
+ }
334
+ if (rest.onFocus) {
335
+ rest.onFocus(event);
336
+ }
337
+ };
338
+ const onBlur = (event) => {
339
+ var _a2;
340
+ setActiveInput(false);
341
+ const isEmptyOrOnlySpaces = event.currentTarget.value.trim().length === 0;
342
+ const isExtraSuffixClicked = ((_a2 = event.relatedTarget) == null ? void 0 : _a2.getAttribute("data-testid")) === EXTRA_SUFFIX_DATA_TEST_ID;
343
+ if (isEmptyOrOnlySpaces && required && !isExtraSuffixClicked) {
344
+ setHasRequiredError(true);
345
+ }
346
+ if (rest.onBlur) {
347
+ rest.onBlur(event);
348
+ }
349
+ };
350
+ const handleResetInput = () => {
351
+ setInputValue("");
352
+ setActiveInput(false);
353
+ onResetInput();
354
+ };
355
+ const handleExtraPrefixEnter = (event) => event.code === "Enter" && (extraPrefix == null ? void 0 : extraPrefix.onClick) && extraPrefix.onClick(inputValue);
356
+ const handleExtraSuffixEnter = (event) => event.code === "Enter" && (extraSuffix == null ? void 0 : extraSuffix.onClick) && extraSuffix.onClick(inputValue);
357
+ const messageColor = disabled ? "content.light" : "content.medium";
358
+ const showError = hasError || hasRequiredError;
359
+ const message = hasRequiredError ? requiredMessage != null ? requiredMessage : messageProp : messageProp;
360
+ const isActiveInput = activeInput || !!inputValue.trim();
361
+ const isSearchType = type === "search";
362
+ const extraPrefixOnClick = (extraPrefix == null ? void 0 : extraPrefix.onClick) ? extraPrefix.onClick : null;
363
+ const extraSuffixOnClick = (extraSuffix == null ? void 0 : extraSuffix.onClick) ? extraSuffix.onClick : null;
364
+ return /* @__PURE__ */ jsxs(
365
+ TextFieldStyled,
366
+ {
367
+ "data-testid": testId,
368
+ hasPrefix: !!extraPrefix,
369
+ isFloatingLabel,
370
+ style,
371
+ children: [
372
+ /* @__PURE__ */ jsxs(InputContainerStyled, { isFloatingLabel, ref, children: [
373
+ /* @__PURE__ */ jsx(
374
+ LabelField,
375
+ {
376
+ hasError: showError,
377
+ htmlFor: textFieldId,
378
+ icon: labelIcon,
379
+ isActive: isInputFocused || activeInput,
380
+ isCentered: !isActiveInput && isFloatingLabel,
381
+ isDisabled: disabled,
382
+ isFloating: isFloatingLabel,
383
+ isInputFilled: !!inputValue,
384
+ isRequired: required,
385
+ scale,
386
+ children: label
387
+ }
388
+ ),
389
+ /* @__PURE__ */ jsxs(
390
+ InputWrapperStyled,
391
+ {
392
+ backgroundFill,
393
+ "data-testid": `${testId}-wrapper`,
394
+ hasError: showError,
395
+ isFloatingLabel,
396
+ variant,
397
+ children: [
398
+ (extraPrefix == null ? void 0 : extraPrefix.component) ? /* @__PURE__ */ jsx(
399
+ InputExtraPrefixStyled,
400
+ __spreadProps(__spreadValues({
401
+ "data-testid": "extra-prefix"
402
+ }, !!extraPrefixOnClick && {
403
+ tabIndex: 0,
404
+ onClick: () => !disabled && extraPrefixOnClick(inputValue),
405
+ onKeyDown: handleExtraPrefixEnter
406
+ }), {
407
+ children: extraPrefix.component
408
+ })
409
+ ) : null,
410
+ /* @__PURE__ */ jsx(
411
+ InputFieldStyled,
412
+ __spreadProps(__spreadValues({
413
+ "data-error": showError,
414
+ "data-testid": `${testId}-input`,
415
+ disabled,
416
+ id: textFieldId,
417
+ isFloatingLabel,
418
+ isFocused: isActiveInput,
419
+ name: name != null ? name : textFieldId,
420
+ ref: inputRef,
421
+ scale,
422
+ type,
423
+ value: inputValue
424
+ }, rest), {
425
+ onBlur,
426
+ onChange: handleChange,
427
+ onFocus
428
+ })
429
+ ),
430
+ isSearchType && !!inputValue ? /* @__PURE__ */ jsx(
431
+ IconButton,
432
+ {
433
+ dataTestId: "reset-icon",
434
+ onClick: handleResetInput,
435
+ style: { marginRight: 12 },
436
+ children: /* @__PURE__ */ jsx(Icon, { code: "close" })
437
+ }
438
+ ) : null,
439
+ (extraSuffix == null ? void 0 : extraSuffix.component) ? /* @__PURE__ */ jsx(
440
+ InputExtraSuffixStyled,
441
+ __spreadProps(__spreadValues({
442
+ "data-testid": EXTRA_SUFFIX_DATA_TEST_ID
443
+ }, !!extraSuffixOnClick && {
444
+ tabIndex: 0,
445
+ onClick: () => !disabled && extraSuffixOnClick(inputValue),
446
+ onKeyDown: handleExtraSuffixEnter
447
+ }), {
448
+ children: extraSuffix.component
449
+ })
450
+ ) : null
451
+ ]
452
+ }
453
+ )
454
+ ] }),
455
+ message ? /* @__PURE__ */ jsx(TextFieldMessageStyled, { children: /* @__PURE__ */ jsx(
456
+ Typography,
457
+ {
458
+ color: showError ? "error.default" : messageColor,
459
+ fontStyles: "bodySmRegular",
460
+ children: message
461
+ }
462
+ ) }) : null,
463
+ children
464
+ ]
465
+ }
466
+ );
467
+ }
468
+ );
469
+ export {
470
+ InputContainerStyled,
471
+ InputExtraPrefixStyled,
472
+ InputExtraSuffixStyled,
473
+ InputFieldStyled,
474
+ InputWrapperStyled,
475
+ TextField,
476
+ TextFieldMessageStyled,
477
+ TextFieldStyled
478
+ };
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@dt-dds/react-text-field",
3
+ "version": "1.0.0-beta.100",
4
+ "license": "MIT",
5
+ "exports": {
6
+ ".": "./dist/index.js"
7
+ },
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.mjs",
10
+ "types": "./dist/index.d.ts",
11
+ "files": [
12
+ "dist/**"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "dev": "tsup --watch",
17
+ "lint": "eslint --cache .",
18
+ "test": "jest",
19
+ "test:report": "open ./jest-coverage/lcov-report/index.html",
20
+ "test:update:snapshot": "jest -u"
21
+ },
22
+ "dependencies": {
23
+ "@dt-dds/react-core": "1.0.0-beta.53",
24
+ "@dt-dds/react-spinner": "1.0.0-beta.95",
25
+ "@dt-dds/react-label-field": "1.0.0-beta.54",
26
+ "@dt-dds/react-typography": "1.0.0-beta.44",
27
+ "@dt-dds/react-icon-button": "1.0.0-beta.22",
28
+ "@dt-dds/react-icon": "1.0.0-beta.56",
29
+ "@dt-dds/react-tooltip": "1.0.0-beta.62",
30
+ "@dt-dds/themes": "1.0.0-beta.10"
31
+ },
32
+ "devDependencies": {
33
+ "@babel/core": "^7.22.9",
34
+ "@babel/preset-env": "^7.22.9",
35
+ "@babel/preset-react": "^7.22.5",
36
+ "@babel/preset-typescript": "^7.23.3",
37
+ "@emotion/babel-plugin": "^11.11.0",
38
+ "@emotion/css": "^11.7.1",
39
+ "@emotion/jest": "^11.10.0",
40
+ "@emotion/react": "^11.8.2",
41
+ "@emotion/styled": "^11.8.1",
42
+ "@types/react": "^18.0.9",
43
+ "@types/react-dom": "^18.0.4",
44
+ "babel-loader": "^8.3.0",
45
+ "eslint-config-custom": "*",
46
+ "eslint-plugin-storybook": "^9.1.0",
47
+ "jest-config": "*",
48
+ "react": "^18.1.0",
49
+ "react-dom": "^18.2.0",
50
+ "tsconfig": "*",
51
+ "tsup": "^8.5.0",
52
+ "typescript": "^4.5.3"
53
+ },
54
+ "peerDependencies": {
55
+ "@emotion/css": "^11.7.1",
56
+ "@emotion/react": "^11.8.2",
57
+ "@emotion/styled": "^11.8.1",
58
+ "react": ">=17.0.2",
59
+ "react-dom": ">=17.0.2"
60
+ }
61
+ }