tycho-components 0.0.1 → 0.0.3

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 (36) hide show
  1. package/.storybook/preview.tsx +2 -2
  2. package/package.json +17 -13
  3. package/src/AppColorpicker/AppColorpicker.tsx +1 -1
  4. package/src/AppModal/AppModal.tsx +14 -12
  5. package/src/AppModal/AppModalConfirm.tsx +10 -11
  6. package/src/AppModal/AppModalRemove.tsx +9 -4
  7. package/src/AppModal/style.scss +1 -1
  8. package/src/AppToast/AppToast.tsx +2 -2
  9. package/src/Participants/ParticipantCreate/ParticipantCreate.tsx +10 -13
  10. package/src/Participants/ParticipantRemove/ParticipantRemove.tsx +3 -3
  11. package/src/Participants/Participants.tsx +9 -9
  12. package/src/Participants/types/Participant.ts +1 -1
  13. package/src/Participants/types/ParticipantService.ts +2 -2
  14. package/src/TextField/TextField.stories.tsx +54 -0
  15. package/src/TextField/TextField.tsx +172 -0
  16. package/src/TextField/TextFieldTheme.ts +70 -0
  17. package/src/TextField/index.tsx +3 -0
  18. package/src/TextField/inputRefManager.ts +24 -0
  19. package/src/TextField/styles.scss +36 -0
  20. package/src/configs/Localization.ts +1 -1
  21. package/src/configs/MessageUtils.ts +2 -2
  22. package/src/configs/localization/CommonTexts.ts +1 -0
  23. package/src/configs/localization/ParticipantsTexts.ts +1 -1
  24. package/src/configs/store/actions.ts +1 -1
  25. package/src/configs/store/store.ts +1 -1
  26. package/src/configs/store/types.ts +1 -1
  27. package/src/index.ts +4 -0
  28. package/src/new-styles/base/_borders.scss +30 -0
  29. package/src/new-styles/base/_colors.scss +100 -0
  30. package/src/new-styles/base/_displays.scss +207 -0
  31. package/src/new-styles/base/_margins.css +174 -0
  32. package/src/new-styles/base/_spacing.scss +26 -0
  33. package/src/new-styles/base/_tokens.scss +329 -0
  34. package/src/new-styles/base/_typographs.scss +348 -0
  35. package/src/new-styles/main.scss +27 -0
  36. package/vite.config.ts +3 -7
@@ -1,11 +1,11 @@
1
1
  import type { Preview } from '@storybook/react';
2
2
  import { CommonProvider } from '../src/configs/CommonContext';
3
- import configLocalization from '../src/configs/Localization';
3
+ import commonLocalization from '../src/configs/Localization';
4
4
  import '../src/styles/bootstrap.min.css';
5
5
  import '../src/styles/main.scss';
6
6
  import './preview.css';
7
7
 
8
- configLocalization();
8
+ commonLocalization();
9
9
 
10
10
  const preview: Preview = {
11
11
  parameters: {
package/package.json CHANGED
@@ -1,21 +1,18 @@
1
1
  {
2
2
  "name": "tycho-components",
3
3
  "private": false,
4
- "version": "0.0.1",
4
+ "version": "0.0.3",
5
5
  "main": "src/index.ts",
6
6
  "dependencies": {
7
- "@emotion/react": "^11.11.1",
8
- "@emotion/styled": "^11.11.0",
7
+ "@emotion/react": "^11.13.3",
8
+ "@emotion/styled": "^11.13.0",
9
9
  "@fortawesome/fontawesome-svg-core": "^6.4.2",
10
10
  "@fortawesome/free-regular-svg-icons": "^6.4.2",
11
11
  "@fortawesome/free-solid-svg-icons": "^6.4.2",
12
12
  "@fortawesome/react-fontawesome": "^0.2.0",
13
- "axios": "^1.7.7",
14
- "react": "^18.2.0",
15
- "react-dom": "^18.2.0",
16
- "root": "file:",
17
- "vite-plugin-checker": "^0.6.1",
18
- "vite-plugin-svgr": "^3.2.0"
13
+ "@mui/icons-material": "6.1.5",
14
+ "@mui/material": "6.1.5",
15
+ "axios": "^1.7.7"
19
16
  },
20
17
  "peerDependencies": {
21
18
  "@hookform/resolvers": "^3.1.1",
@@ -25,13 +22,16 @@
25
22
  "date-fns-tz": "^1.3.6",
26
23
  "i18next-browser-languagedetector": "^7.1.0",
27
24
  "js-cookie": "^3.0.5",
25
+ "react": ">=17 <19",
28
26
  "react-bootstrap": "^2.8.0",
27
+ "react-colorful": "^5.6.1",
28
+ "react-dom": ">=17 <19",
29
29
  "react-easy-edit": "^2.0.0",
30
+ "react-hook-form": "^7.45.2",
30
31
  "react-i18next": "^13.0.2",
31
32
  "react-loading": "^2.0.3",
32
- "react-toastify": "^9.1.3",
33
33
  "react-switch": "^7.1.0",
34
- "tycho-storybook": "^0.0.32",
34
+ "react-toastify": "^9.1.3",
35
35
  "yup": "^1.2.0"
36
36
  },
37
37
  "devDependencies": {
@@ -45,8 +45,8 @@
45
45
  "@storybook/react-vite": "^7.5.3",
46
46
  "@storybook/testing-library": "^0.2.2",
47
47
  "@types/js-cookie": "^3.0.6",
48
- "@types/react": "^18.2.37",
49
- "@types/react-dom": "^18.2.15",
48
+ "@types/react": "^18.2.0",
49
+ "@types/react-dom": "^18.2.0",
50
50
  "@typescript-eslint/eslint-plugin": "^5.62.0",
51
51
  "@typescript-eslint/parser": "^5.62.0",
52
52
  "@vitejs/plugin-react": "^4.1.1",
@@ -54,9 +54,13 @@
54
54
  "eslint-plugin-react-hooks": "^4.6.2",
55
55
  "eslint-plugin-react-refresh": "^0.4.1",
56
56
  "eslint-plugin-storybook": "^0.11.2",
57
+ "react": "^18.2.0",
58
+ "react-dom": "^18.2.0",
57
59
  "storybook": "^7.5.3",
58
60
  "typescript": "^5.2.2",
59
61
  "vite": "^4.5.0",
62
+ "vite-plugin-checker": "^0.6.1",
63
+ "vite-plugin-svgr": "^3.2.0",
60
64
  "vitest": "^0.33.0"
61
65
  },
62
66
  "scripts": {
@@ -1,4 +1,4 @@
1
- import { FieldValue } from '@/AppEditable/FormFieldOption';
1
+ import { FieldValue } from '../AppEditable/FormFieldOption';
2
2
  import { useEffect, useState } from 'react';
3
3
  import { HexColorPicker } from 'react-colorful';
4
4
  import { useTranslation } from 'react-i18next';
@@ -2,8 +2,10 @@ import { Box, Fade, Modal } from '@mui/material';
2
2
  import cx from 'classnames';
3
3
  import React from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
- import { Button, Icon } from 'tycho-storybook';
6
5
  import './style.scss';
6
+ import { Button } from 'react-bootstrap';
7
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
8
+ import { faTimes } from '@fortawesome/free-solid-svg-icons';
7
9
 
8
10
  type Props = {
9
11
  children: React.ReactNode;
@@ -52,25 +54,25 @@ export default function AppModal({
52
54
  {subtitle && <span className="subtitle">{subtitle}</span>}
53
55
  </div>
54
56
  {!disableClose && (
55
- <Icon name="close" onClick={close} className="pointer" />
57
+ <FontAwesomeIcon
58
+ onClick={close}
59
+ className="ms-auto pointer"
60
+ icon={faTimes}
61
+ />
56
62
  )}
57
63
  </div>
58
64
  <div className="body">{children}</div>
59
65
  {!hideFooter ? (
60
66
  <div className="footer">
61
67
  {!disableCancel && (
62
- <Button
63
- onClick={cancel || close}
64
- text={closeLabel || t('button.cancel')}
65
- color="danger"
66
- />
68
+ <Button onClick={cancel || close} variant="danger">
69
+ {closeLabel || t('button.cancel')}
70
+ </Button>
67
71
  )}
68
72
  {confirm && (
69
- <Button
70
- onClick={confirm}
71
- disabled={disableConfirm}
72
- text={confirmLabel || t('button.confirm')}
73
- />
73
+ <Button onClick={confirm} disabled={disableConfirm}>
74
+ {confirmLabel || t('button.confirm')}
75
+ </Button>
74
76
  )}
75
77
  </div>
76
78
  ) : null}
@@ -1,7 +1,9 @@
1
1
  import { Box, Modal } from '@mui/material';
2
2
  import { useTranslation } from 'react-i18next';
3
- import { Button, Icon } from 'tycho-storybook';
4
3
  import './style.scss';
4
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
5
+ import { faWarning } from '@fortawesome/free-solid-svg-icons';
6
+ import { Button } from 'react-bootstrap';
5
7
 
6
8
  type Props = {
7
9
  title: string;
@@ -26,7 +28,7 @@ export default function AppModalConfirm({
26
28
  <Modal open>
27
29
  <Box className="modal-container modal-remove" sx={style}>
28
30
  <div className="body">
29
- <Icon name="warning" size="large" filled />
31
+ <FontAwesomeIcon icon={faWarning} />
30
32
  <div className="texts">
31
33
  <span className="title">{title}</span>
32
34
  <span className="subtitle">{subtitle}</span>
@@ -34,15 +36,12 @@ export default function AppModalConfirm({
34
36
  </div>
35
37
 
36
38
  <div className="footer">
37
- <Button
38
- onClick={onClose}
39
- text={closeLabel || t('modal.button.cancel')}
40
- mode="tonal"
41
- />
42
- <Button
43
- onClick={onConfirm}
44
- text={confirmLabel || t('modal.button.confirm')}
45
- />
39
+ <Button onClick={onClose} variant="secondary">
40
+ {closeLabel || t('modal.button.cancel')}
41
+ </Button>
42
+ <Button onClick={onConfirm}>
43
+ {confirmLabel || t('modal.button.confirm')}
44
+ </Button>
46
45
  </div>
47
46
  </Box>
48
47
  </Modal>
@@ -1,7 +1,9 @@
1
1
  import { Box, Modal } from '@mui/material';
2
2
  import { useTranslation } from 'react-i18next';
3
- import { Button, Icon } from 'tycho-storybook';
4
3
  import './style.scss';
4
+ import { Button } from 'react-bootstrap';
5
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
6
+ import { faWarning } from '@fortawesome/free-solid-svg-icons';
5
7
 
6
8
  type Props = {
7
9
  title: string;
@@ -22,7 +24,7 @@ export default function AppModalRemove({
22
24
  <Modal open>
23
25
  <Box className="modal-container modal-remove" sx={style}>
24
26
  <div className="body">
25
- <Icon name="warning" size="large" filled />
27
+ <FontAwesomeIcon icon={faWarning} />
26
28
  <div className="texts">
27
29
  <span className="title">{title}</span>
28
30
  <span className="subtitle">{subtitle}</span>
@@ -30,8 +32,11 @@ export default function AppModalRemove({
30
32
  </div>
31
33
 
32
34
  <div className="footer">
33
- <Button onClick={onClose} text={t('button.cancel')} mode="tonal" />
34
- <Button onClick={onConfirm} text={t('button.confirm')} />
35
+ <Button onClick={onClose} variant="secondary">
36
+ {t('button.cancel')}
37
+ </Button>
38
+
39
+ <Button onClick={onConfirm}>{t('button.confirm')}</Button>
35
40
  </div>
36
41
  </Box>
37
42
  </Modal>
@@ -1,4 +1,4 @@
1
- @use 'tycho-storybook/src/styles/main' as *;
1
+ @use '../new-styles/main' as *;
2
2
 
3
3
  .modal-container {
4
4
  .header {
@@ -1,5 +1,5 @@
1
- import CommonContext from '@/configs/CommonContext';
2
- import { message } from '@/configs/store/actions';
1
+ import CommonContext from '../configs/CommonContext';
2
+ import { message } from '../configs/store/actions';
3
3
  import { useContext, useEffect } from 'react';
4
4
  import ReactLoading from 'react-loading';
5
5
  import { ToastContainer, toast } from 'react-toastify';
@@ -1,19 +1,16 @@
1
- import AppModal from '@/AppModal';
2
- import CommonContext from '@/configs/CommonContext';
3
- import { toastLoading } from '@/configs/store/actions';
4
- import { useContext, useRef, useState } from 'react';
5
- import { useTranslation } from 'react-i18next';
6
- import Participant, {
7
- EMPTY_PARTICIPANT,
8
- ParticipantCreateRequest,
9
- } from '../types/Participant';
10
- import ParticipantService from '../types/ParticipantService';
11
- import { useForm } from 'react-hook-form';
1
+ import { yupResolver } from '@hookform/resolvers/yup';
12
2
  import { TFunction } from 'i18next';
3
+ import { useContext } from 'react';
4
+ import { useForm } from 'react-hook-form';
5
+ import { useTranslation } from 'react-i18next';
13
6
  import * as yup from 'yup';
14
- import { yupResolver } from '@hookform/resolvers/yup';
7
+ import AppModal from '../../AppModal';
8
+ import CommonContext from '../../configs/CommonContext';
9
+ import { toastLoading } from '../../configs/store/actions';
10
+ import Participant, { ParticipantCreateRequest } from '../types/Participant';
11
+ import ParticipantService from '../types/ParticipantService';
15
12
  import './style.scss';
16
- import { TextField } from 'tycho-storybook';
13
+ import TextField from '../../TextField';
17
14
 
18
15
  type Props = {
19
16
  document: string;
@@ -1,8 +1,8 @@
1
- import AppModalRemove from '@/AppModal/AppModalRemove';
2
- import CommonContext from '@/configs/CommonContext';
3
- import { toastLoading } from '@/configs/store/actions';
4
1
  import { useContext } from 'react';
5
2
  import { useTranslation } from 'react-i18next';
3
+ import AppModalRemove from '../../AppModal/AppModalRemove';
4
+ import CommonContext from '../../configs/CommonContext';
5
+ import { toastLoading } from '../../configs/store/actions';
6
6
  import Participant from '../types/Participant';
7
7
  import ParticipantService from '../types/ParticipantService';
8
8
  import './style.scss';
@@ -1,12 +1,12 @@
1
- import AppEditable from '@/AppEditable';
2
- import AppEditableField from '@/AppEditable/AppEditableField';
3
- import CommonContext from '@/configs/CommonContext';
4
- import { dispatchMessage } from '@/configs/MessageUtils';
5
- import { faPlus, faTimes } from '@fortawesome/free-solid-svg-icons';
1
+ import { faPlus, faTrash } from '@fortawesome/free-solid-svg-icons';
6
2
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
7
3
  import { useContext, useEffect, useState } from 'react';
8
4
  import { Button, Form } from 'react-bootstrap';
9
5
  import { useTranslation } from 'react-i18next';
6
+ import AppEditable from '../AppEditable';
7
+ import AppEditableField from '../AppEditable/AppEditableField';
8
+ import CommonContext from '../configs/CommonContext';
9
+ import { dispatchMessage } from '../configs/MessageUtils';
10
10
  import ParticipantCreate from './ParticipantCreate';
11
11
  import ParticipantRemove from './ParticipantRemove';
12
12
  import './style.scss';
@@ -25,7 +25,7 @@ export default function Participants({
25
25
  onChange,
26
26
  }: Props) {
27
27
  const { t } = useTranslation('participants');
28
- const { dispatch, state } = useContext(CommonContext);
28
+ const { dispatch } = useContext(CommonContext);
29
29
 
30
30
  const [participant, setParticipant] = useState<Participant>();
31
31
  const [openRemove, setOpenRemove] = useState(false);
@@ -69,7 +69,7 @@ export default function Participants({
69
69
  onClick={() => setOpenCreate(true)}
70
70
  >
71
71
  <FontAwesomeIcon icon={faPlus} title={t('button.label.add')} />
72
- <span className="ms-2">add new participant</span>
72
+ <span className="ms-2">{t('button.label.add')}</span>
73
73
  </button>
74
74
  </div>
75
75
  </div>
@@ -104,8 +104,8 @@ export default function Participants({
104
104
  setOpenRemove(true);
105
105
  }}
106
106
  >
107
- <FontAwesomeIcon icon={faTimes} />
108
- <span className="ms-1">Remove</span>
107
+ <FontAwesomeIcon icon={faTrash} />
108
+ <span className="ms-1">{t('common:button.remove')}</span>
109
109
  </Button>
110
110
  </div>
111
111
  </>
@@ -1,4 +1,4 @@
1
- import FormField from '@/AppEditable/FormField';
1
+ import FormField from '../../AppEditable/FormField';
2
2
 
3
3
  type Participant = {
4
4
  order: number;
@@ -1,5 +1,5 @@
1
- import AppEditableField from '@/AppEditable/AppEditableField';
2
- import api from '@/configs/api';
1
+ import AppEditableField from '../../AppEditable/AppEditableField';
2
+ import api from '../../configs/api';
3
3
  import Participant, { ParticipantCreateRequest } from './Participant';
4
4
 
5
5
  function add(uid: string, request: ParticipantCreateRequest) {
@@ -0,0 +1,54 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { useForm } from 'react-hook-form';
3
+ import TextField from './TextField';
4
+
5
+ const meta = {
6
+ title: 'Components/TextField',
7
+ component: TextField,
8
+ parameters: {
9
+ layout: 'padded',
10
+ },
11
+ tags: ['autodocs'],
12
+ argTypes: {
13
+ label: { control: 'text' },
14
+ attr: { control: 'text' },
15
+ createdForm: { control: false },
16
+ className: { control: 'text' },
17
+ title: { control: 'text' },
18
+ placeholder: { control: 'text' },
19
+ disabled: { control: 'boolean' },
20
+ multiline: { control: 'boolean' },
21
+ maxChars: { control: 'text' },
22
+ showEndAdornment: { control: 'boolean' },
23
+ onChange: { action: 'changed' },
24
+ },
25
+ } satisfies Meta<typeof TextField>;
26
+
27
+ export default meta;
28
+ type Story = StoryObj<typeof meta>;
29
+
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ const template = (args: any) => {
32
+ const createdForm = useForm({
33
+ defaultValues: {
34
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
35
+ [args.attr]: '',
36
+ },
37
+ });
38
+
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ const handleChange = (attr: string, value: any) => {
41
+ console.log(`Attribute: ${attr}, Value: ${String(value)}`);
42
+ };
43
+
44
+ return (
45
+ <TextField {...args} createdForm={createdForm} onChange={handleChange} />
46
+ );
47
+ };
48
+
49
+ export const Default = template.bind({});
50
+ // @ts-expect-error: Suppress error for args property assignment
51
+ Default.args = {
52
+ attr: 'title',
53
+ label: 'Title',
54
+ };
@@ -0,0 +1,172 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */
2
+ import { InputAdornment, TextField as MuiTextField } from '@mui/material';
3
+ import { ThemeProvider, useTheme } from '@mui/material/styles';
4
+ import cx from 'classnames';
5
+ import { useEffect, useState } from 'react';
6
+ import { Controller, UseFormReturn } from 'react-hook-form';
7
+ import { textFieldTheme } from './TextFieldTheme';
8
+ import { setCurrentInput } from './inputRefManager';
9
+ import './styles.scss';
10
+
11
+ type Props = {
12
+ attr: string;
13
+ label: string;
14
+ createdForm: UseFormReturn<any, any, any>;
15
+ className?: string;
16
+ disabled?: boolean;
17
+ multiline?: boolean;
18
+ title?: string;
19
+ placeholder?: string;
20
+ maxChars?: number;
21
+ required?: boolean;
22
+ showEndAdornment?: boolean;
23
+ startAdornment?: React.ReactNode;
24
+ onChange?: (attr: string, value: any) => void;
25
+ onFocus?: (
26
+ e: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement, Element>
27
+ ) => void;
28
+ onRemove?: () => void;
29
+ password?: boolean;
30
+ rows?: number;
31
+ hideInfoIcon?: boolean;
32
+ };
33
+
34
+ export default function TextField({
35
+ className,
36
+ attr,
37
+ label,
38
+ createdForm,
39
+ disabled,
40
+ title,
41
+ placeholder,
42
+ multiline,
43
+ maxChars,
44
+ required,
45
+ startAdornment,
46
+ showEndAdornment = true,
47
+ onChange,
48
+ onFocus,
49
+ onRemove,
50
+ password,
51
+ rows = 4,
52
+ hideInfoIcon,
53
+ }: Props) {
54
+ const outerTheme = useTheme();
55
+ const [showPassword, setShowPassword] = useState(false);
56
+ const [active, setActive] = useState(false);
57
+ const [focus, setFocus] = useState(false);
58
+ const [mouseOver, setMouseOver] = useState(false);
59
+
60
+ const hasError = () => createdForm.formState.errors[attr];
61
+
62
+ const getClassNames = cx('ds-input-text', className, {
63
+ disabled: disabled,
64
+ });
65
+
66
+ useEffect(() => {
67
+ if (focus || mouseOver) {
68
+ setActive(true);
69
+ } else {
70
+ setActive(false);
71
+ }
72
+ }, [focus, mouseOver]);
73
+
74
+ return (
75
+ <div className={getClassNames}>
76
+ <Controller
77
+ name={attr}
78
+ control={createdForm.control}
79
+ render={({ field }) => (
80
+ <ThemeProvider theme={textFieldTheme(outerTheme)}>
81
+ <MuiTextField
82
+ {...field}
83
+ label={label}
84
+ value={field.value || ''}
85
+ type={
86
+ password === undefined
87
+ ? 'text'
88
+ : showPassword
89
+ ? 'text'
90
+ : 'password'
91
+ }
92
+ fullWidth
93
+ required={required}
94
+ disabled={disabled}
95
+ variant="filled"
96
+ placeholder={!focus ? placeholder : ''}
97
+ color="error"
98
+ multiline={multiline}
99
+ minRows={rows}
100
+ slotProps={{
101
+ inputLabel: {
102
+ shrink: true,
103
+ },
104
+ }}
105
+ onFocus={(e) => {
106
+ setCurrentInput(e.target, (e: any) => {
107
+ field.onChange(e);
108
+ onChange && onChange(attr, e.target.value);
109
+ });
110
+ setFocus(true);
111
+ onFocus && onFocus(e);
112
+ }}
113
+ onBlur={() => setFocus(false)}
114
+ onMouseOver={() => setMouseOver(true)}
115
+ onMouseOut={() => setMouseOver(false)}
116
+ onChange={(event) => {
117
+ field.onChange(event);
118
+ onChange && onChange(attr, event.target.value);
119
+ }}
120
+ sx={{
121
+ borderColor: disabled
122
+ ? '#BEBFC1'
123
+ : hasError()
124
+ ? '#C6080A'
125
+ : active
126
+ ? '#1C83F4'
127
+ : '#BEBFC1',
128
+ '.MuiInputLabel-root': {
129
+ color: disabled
130
+ ? '#BEBFC1'
131
+ : hasError()
132
+ ? '#C6080A'
133
+ : active
134
+ ? '#1C83F4'
135
+ : '#000000',
136
+ },
137
+ '.MuiInputBase-root': {
138
+ paddingTop: multiline ? '12px' : '4px',
139
+ height: multiline ? 'auto' : '48px',
140
+ },
141
+ '& .MuiInputBase-inputMultiline': {
142
+ paddingTop: '24px',
143
+ paddingBottom: '16px',
144
+ },
145
+ '& .MuiInputBase-input': {
146
+ paddingTop: multiline ? 'none' : '16px',
147
+ },
148
+ '& .MuiInputAdornment-positionEnd': {
149
+ paddingTop: multiline ? '12px' : '0px',
150
+ },
151
+ }}
152
+ />
153
+
154
+ {maxChars && (
155
+ <div className="character-counter">
156
+ {field.value?.length || 0}/{maxChars}
157
+ </div>
158
+ )}
159
+
160
+ {title && !hasError() && <div className="helper">{title}</div>}
161
+
162
+ {hasError() && (
163
+ <div className="helper error">
164
+ {String(createdForm.formState.errors[attr]?.message)}
165
+ </div>
166
+ )}
167
+ </ThemeProvider>
168
+ )}
169
+ />
170
+ </div>
171
+ );
172
+ }
@@ -0,0 +1,70 @@
1
+ import { createTheme, Theme } from '@mui/material/styles';
2
+
3
+ export const textFieldTheme = (outerTheme: Theme) =>
4
+ createTheme({
5
+ ...outerTheme,
6
+ components: {
7
+ MuiTextField: {
8
+ styleOverrides: {
9
+ root: {
10
+ backgroundColor: 'white',
11
+ padding: '0px',
12
+ border: '1px solid #EAEAEB',
13
+ borderRadius: '4px',
14
+ '& .MuiInputBase-root': {
15
+ padding: '0px!important',
16
+ backgroundColor: 'white',
17
+ borderBottomLeftRadius: '4px',
18
+ borderBottomRightRadius: '4px',
19
+ },
20
+ '& .MuiFilledInput-root::before': {
21
+ content: 'none',
22
+ },
23
+ '& .MuiFilledInput-root::after': {
24
+ content: 'none',
25
+ },
26
+ '& .MuiInputLabel-root': {
27
+ paddingLeft: '4px',
28
+ color: '#000000',
29
+ textTransform: 'uppercase',
30
+ // helper-medium-1
31
+ fontSize: '12px',
32
+ fontWeight: '400',
33
+ lineHeight: '100%',
34
+ letterSpacing: '0.16px',
35
+ fontFamily: 'Work Sans, sans-serif',
36
+ },
37
+ '& .MuiInputAdornment-root': {
38
+ height: '100%',
39
+ maxHeight: '100%',
40
+ },
41
+ '& .MuiInputAdornment-positionStart': {
42
+ margin: '0px!important',
43
+ padding: '0px!important',
44
+ },
45
+ '& .MuiInputAdornment-positionEnd': {
46
+ margin: '0px 16px auto!important',
47
+ },
48
+ '& .MuiInputBase-input': {
49
+ padding: '0px 16px',
50
+ height: '48px',
51
+ // label-medium-1
52
+ fontSize: '16px',
53
+ fontWeight: '400',
54
+ lineHeight: '120%',
55
+ letterSpacing: '0px',
56
+ fontFamily: 'Work Sans, sans-serif',
57
+ '&::placeholder': {
58
+ color: '#707276',
59
+ },
60
+ '&:-webkit-autofill': {
61
+ WebkitBoxShadow: '0 0 0px 1000px transparent inset !important',
62
+ WebkitTextFillColor: '#000 !important',
63
+ transition: 'background-color 5000s ease-in-out 0s', // Prevents flashing
64
+ },
65
+ },
66
+ },
67
+ },
68
+ },
69
+ },
70
+ });
@@ -0,0 +1,3 @@
1
+ import TextField from './TextField';
2
+
3
+ export default TextField;
@@ -0,0 +1,24 @@
1
+ let currentInput: HTMLInputElement | HTMLTextAreaElement | null = null;
2
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
+ let currentOnChange: ((e: any) => void) | null = null;
4
+
5
+ export function removeCurrentInput() {
6
+ currentInput = null;
7
+ }
8
+
9
+ export function setCurrentInput(
10
+ input: HTMLInputElement | HTMLTextAreaElement | null,
11
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
+ onChange: (e: any) => void
13
+ ) {
14
+ currentInput = input;
15
+ currentOnChange = onChange;
16
+ }
17
+
18
+ export function getCurrentInput() {
19
+ return currentInput;
20
+ }
21
+
22
+ export function getCurrentOnChange() {
23
+ return currentOnChange;
24
+ }