@indico-data/design-system 2.4.2 → 2.6.0

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 (44) hide show
  1. package/.storybook/preview.ts +4 -14
  2. package/lib/index.css +208 -0
  3. package/lib/index.d.ts +31 -3
  4. package/lib/index.esm.css +208 -0
  5. package/lib/index.esm.js +23 -1
  6. package/lib/index.esm.js.map +1 -1
  7. package/lib/index.js +24 -0
  8. package/lib/index.js.map +1 -1
  9. package/lib/src/components/forms/input/Input.d.ts +18 -0
  10. package/lib/src/components/forms/input/Input.stories.d.ts +12 -0
  11. package/lib/src/components/forms/input/__tests__/Input.test.d.ts +1 -0
  12. package/lib/src/components/forms/input/index.d.ts +1 -0
  13. package/lib/src/components/forms/radio/Radio.d.ts +11 -0
  14. package/lib/src/components/forms/radio/Radio.stories.d.ts +6 -0
  15. package/lib/src/components/forms/radio/__tests__/Radio.test.d.ts +1 -0
  16. package/lib/src/components/forms/radio/index.d.ts +1 -0
  17. package/lib/src/components/forms/subcomponents/ErrorList.d.ts +6 -0
  18. package/lib/src/components/forms/subcomponents/Label.d.ts +8 -0
  19. package/lib/src/components/forms/subcomponents/__tests__/ErrorList.test.d.ts +1 -0
  20. package/lib/src/components/forms/subcomponents/__tests__/Label.test.d.ts +1 -0
  21. package/lib/src/components/index.d.ts +2 -0
  22. package/lib/src/index.d.ts +2 -0
  23. package/package.json +1 -1
  24. package/src/components/forms/input/Input.mdx +19 -0
  25. package/src/components/forms/input/Input.stories.tsx +301 -0
  26. package/src/components/forms/input/Input.tsx +86 -0
  27. package/src/components/forms/input/__tests__/Input.test.tsx +213 -0
  28. package/src/components/forms/input/index.ts +1 -0
  29. package/src/components/forms/input/styles/Input.scss +112 -0
  30. package/src/components/forms/radio/Radio.mdx +83 -0
  31. package/src/components/forms/radio/Radio.stories.tsx +121 -0
  32. package/src/components/forms/radio/Radio.tsx +47 -0
  33. package/src/components/forms/radio/__tests__/Radio.test.tsx +35 -0
  34. package/src/components/forms/radio/index.ts +1 -0
  35. package/src/components/forms/radio/styles/Radio.scss +98 -0
  36. package/src/components/forms/subcomponents/ErrorList.tsx +14 -0
  37. package/src/components/forms/subcomponents/Label.tsx +20 -0
  38. package/src/components/forms/subcomponents/__tests__/ErrorList.test.tsx +16 -0
  39. package/src/components/forms/subcomponents/__tests__/Label.test.tsx +33 -0
  40. package/src/components/index.ts +2 -0
  41. package/src/index.ts +2 -0
  42. package/src/styles/_typography.scss +29 -11
  43. package/src/styles/index.scss +2 -0
  44. package/src/styles/storybook.scss +15 -0
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { IconName } from '@/types';
3
+ export interface InputProps {
4
+ ref?: React.LegacyRef<HTMLInputElement>;
5
+ label: string;
6
+ name: string;
7
+ placeholder: string;
8
+ value: string;
9
+ onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
10
+ isRequired?: boolean;
11
+ isDisabled?: boolean;
12
+ errorList?: string[];
13
+ helpText?: string;
14
+ hasHiddenLabel?: boolean;
15
+ iconName?: IconName;
16
+ isClearable?: boolean;
17
+ }
18
+ export declare const Input: ({ ref, label, name, placeholder, value, onChange, isRequired, isDisabled, errorList, helpText, iconName, hasHiddenLabel, isClearable, ...rest }: InputProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { Input } from './Input';
3
+ declare const meta: Meta;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Input>;
6
+ export declare const Default: Story;
7
+ export declare const Errors: Story;
8
+ export declare const HiddenLabel: Story;
9
+ export declare const HelpText: Story;
10
+ export declare const Clearable: Story;
11
+ export declare const Icon: Story;
12
+ export declare const Required: Story;
@@ -0,0 +1 @@
1
+ export { Input } from './Input';
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ export interface RadioProps {
3
+ ref?: React.LegacyRef<HTMLInputElement>;
4
+ id: string;
5
+ label: string;
6
+ name: string;
7
+ value?: string;
8
+ onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
9
+ isDisabled?: boolean;
10
+ }
11
+ export declare const Radio: ({ ref, id, label, name, value, onChange, isDisabled, ...rest }: RadioProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { Radio } from './Radio';
3
+ declare const meta: Meta;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Radio>;
6
+ export declare const Default: Story;
@@ -0,0 +1 @@
1
+ export { Radio } from './Radio';
@@ -0,0 +1,6 @@
1
+ interface ErrorListProps {
2
+ name: string;
3
+ errorList: string[];
4
+ }
5
+ export declare const ErrorList: ({ errorList, name }: ErrorListProps) => import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,8 @@
1
+ interface LabelProps {
2
+ label: string;
3
+ name: string;
4
+ isRequired?: boolean;
5
+ hasHiddenLabel?: boolean;
6
+ }
7
+ export declare const Label: ({ label, name, isRequired, hasHiddenLabel }: LabelProps) => import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -2,3 +2,5 @@ export { Container, Col, Row } from './grid';
2
2
  export { Button } from './button';
3
3
  export { Icon } from './icons';
4
4
  export { Table } from './table';
5
+ export { Input } from './forms/input';
6
+ export { Radio } from './forms/radio';
@@ -7,3 +7,5 @@ export { Container, Row, Col } from './components/grid';
7
7
  export { Button } from './components/button';
8
8
  export { Icon } from './components/icons';
9
9
  export { Table } from './components/table';
10
+ export { Input } from './components/forms/input';
11
+ export { Radio as RadioInput } from './components/forms/radio';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indico-data/design-system",
3
- "version": "2.4.2",
3
+ "version": "2.6.0",
4
4
  "description": "",
5
5
  "author": "",
6
6
  "main": "lib/index.js",
@@ -0,0 +1,19 @@
1
+ import { Canvas, Meta, Controls } from '@storybook/blocks';
2
+ import * as Input from './Input.stories';
3
+
4
+ <Meta title="Forms/Input" name="Input" />
5
+
6
+ # Input
7
+
8
+ The input component is the building block of any form. Below you will find the accepted properties for this component. It is encouraged to build forms utilizing [React Hook Form](https://react-hook-form.com/) library in your application. This will facilitate form state management and enforce best practices. (***Our components are compatible with but do not provide the plugin***)
9
+
10
+ <Canvas
11
+ of={Input.Default}
12
+ source={{
13
+ code: `
14
+ <Input name="first_name" required={true} isRequired helpText="This Is Help Text" isClearable label="Label Name" iconName="user" />
15
+ `,
16
+ }}
17
+ />
18
+
19
+ <Controls of={Input.Default} />
@@ -0,0 +1,301 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import { Input, InputProps } from './Input';
3
+ import { useState } from 'react';
4
+ import { iconNames } from 'build/generated/iconTypes';
5
+
6
+ const meta: Meta = {
7
+ title: 'Forms/Input',
8
+ component: Input,
9
+ argTypes: {
10
+ onChange: {
11
+ control: false,
12
+ description: 'onChange event handler',
13
+ table: {
14
+ category: 'Callbacks',
15
+ type: {
16
+ summary: '(e: React.ChangeEvent<HTMLInputElement>) => void',
17
+ },
18
+ },
19
+ action: 'onChange',
20
+ },
21
+ label: {
22
+ control: 'text',
23
+ description: 'The label for the input field',
24
+ table: {
25
+ category: 'Props',
26
+ type: {
27
+ summary: 'string',
28
+ },
29
+ },
30
+ defaultValue: { summary: '' },
31
+ },
32
+ name: {
33
+ control: 'text',
34
+ description: 'The name for the input field',
35
+ table: {
36
+ category: 'Props',
37
+ type: {
38
+ summary: 'string',
39
+ },
40
+ },
41
+ defaultValue: { summary: '' },
42
+ },
43
+ placeholder: {
44
+ control: 'text',
45
+ description: 'The placeholder for the input field',
46
+ table: {
47
+ category: 'Props',
48
+ type: {
49
+ summary: 'string',
50
+ },
51
+ },
52
+ defaultValue: { summary: '' },
53
+ },
54
+ value: {
55
+ control: 'text',
56
+ description: 'The value for the input field',
57
+ table: {
58
+ category: 'Props',
59
+ type: {
60
+ summary: 'string',
61
+ },
62
+ },
63
+ defaultValue: { summary: '' },
64
+ },
65
+ isRequired: {
66
+ control: 'boolean',
67
+ description: 'Toggles the required astherisc on the label',
68
+ table: {
69
+ category: 'Props',
70
+ type: {
71
+ summary: 'boolean',
72
+ },
73
+ },
74
+ defaultValue: { summary: 'false' },
75
+ },
76
+ isDisabled: {
77
+ control: 'boolean',
78
+ description: 'Toggles the disabled state of the input',
79
+ table: {
80
+ category: 'Props',
81
+ type: {
82
+ summary: 'boolean',
83
+ },
84
+ },
85
+ defaultValue: { summary: 'false' },
86
+ },
87
+ errorList: {
88
+ control: false,
89
+ description: 'An array of error messages',
90
+ table: {
91
+ category: 'Props',
92
+ type: {
93
+ summary: 'string[]',
94
+ },
95
+ },
96
+ defaultValue: { summary: '[]' },
97
+ },
98
+ helpText: {
99
+ control: 'text',
100
+ description: 'The help text for the input field',
101
+ table: {
102
+ category: 'Props',
103
+ type: {
104
+ summary: 'string',
105
+ },
106
+ },
107
+ defaultValue: { summary: '' },
108
+ },
109
+ hasHiddenLabel: {
110
+ control: 'boolean',
111
+ description: 'Hides the label visually (retains it for screen readers)',
112
+ table: {
113
+ category: 'Props',
114
+ type: {
115
+ summary: 'boolean',
116
+ },
117
+ },
118
+ defaultValue: { summary: 'false' },
119
+ },
120
+ iconName: {
121
+ control: 'select',
122
+ options: iconNames,
123
+ description: 'Adds an icon to the left hand side of the input field',
124
+ table: {
125
+ category: 'Props',
126
+ type: {
127
+ summary: 'string',
128
+ },
129
+ },
130
+ defaultValue: { summary: '' },
131
+ },
132
+ isClearable: {
133
+ control: 'boolean',
134
+ description: 'Adds a clear x icon to the right hand side of the input field',
135
+ table: {
136
+ category: 'Props',
137
+ type: {
138
+ summary: 'boolean',
139
+ },
140
+ },
141
+ defaultValue: { summary: 'false' },
142
+ },
143
+ ref: {
144
+ table: {
145
+ disable: true,
146
+ },
147
+ },
148
+ },
149
+ };
150
+
151
+ export default meta;
152
+
153
+ type Story = StoryObj<typeof Input>;
154
+
155
+ const defaultArgs = {
156
+ label: 'Enter your name',
157
+ name: 'first_name',
158
+ placeholder: 'Please enter a value',
159
+ } as InputProps;
160
+
161
+ export const Default: Story = {
162
+ args: {
163
+ isRequired: true,
164
+ iconName: 'user',
165
+ helpText: 'This Is Help Text',
166
+ isClearable: true,
167
+ label: 'Label Name',
168
+ name: 'firsT_name',
169
+ placeholder: 'Please enter a value',
170
+ hasHiddenLabel: false,
171
+ isDisabled: false,
172
+ errorList: [],
173
+ value: '',
174
+ },
175
+ render: (args) => {
176
+ const [value, setValue] = useState('');
177
+ return (
178
+ <Input
179
+ {...args}
180
+ value={value}
181
+ onChange={(e) => {
182
+ setValue(e.target.value);
183
+ }}
184
+ />
185
+ );
186
+ },
187
+ };
188
+
189
+ export const Errors: Story = {
190
+ args: {
191
+ ...defaultArgs,
192
+ errorList: ['You require a username value.'],
193
+ },
194
+ render: (args) => {
195
+ const [value, setValue] = useState('');
196
+ return (
197
+ <Input
198
+ {...args}
199
+ value={value}
200
+ onChange={(e) => {
201
+ setValue(e.target.value);
202
+ }}
203
+ />
204
+ );
205
+ },
206
+ };
207
+
208
+ export const HiddenLabel: Story = {
209
+ args: {
210
+ ...defaultArgs,
211
+ hasHiddenLabel: true,
212
+ },
213
+ render: (args) => {
214
+ const [value, setValue] = useState('');
215
+ return (
216
+ <Input
217
+ {...args}
218
+ value={value}
219
+ onChange={(e) => {
220
+ setValue(e.target.value);
221
+ }}
222
+ />
223
+ );
224
+ },
225
+ };
226
+
227
+ export const HelpText: Story = {
228
+ args: {
229
+ ...defaultArgs,
230
+ helpText: 'In order to submit the form, this field is required.',
231
+ },
232
+ render: (args) => {
233
+ const [value, setValue] = useState('');
234
+ return (
235
+ <Input
236
+ {...args}
237
+ value={value}
238
+ onChange={(e) => {
239
+ setValue(e.target.value);
240
+ }}
241
+ />
242
+ );
243
+ },
244
+ };
245
+
246
+ export const Clearable: Story = {
247
+ args: {
248
+ ...defaultArgs,
249
+ isClearable: true,
250
+ },
251
+ render: (args) => {
252
+ const [value, setValue] = useState('');
253
+ return (
254
+ <Input
255
+ {...args}
256
+ value={value}
257
+ onChange={(e) => {
258
+ setValue(e.target.value);
259
+ }}
260
+ />
261
+ );
262
+ },
263
+ };
264
+
265
+ export const Icon: Story = {
266
+ args: {
267
+ ...defaultArgs,
268
+ iconName: 'user',
269
+ },
270
+ render: (args) => {
271
+ const [value, setValue] = useState('');
272
+ return (
273
+ <Input
274
+ {...args}
275
+ value={value}
276
+ onChange={(e) => {
277
+ setValue(e.target.value);
278
+ }}
279
+ />
280
+ );
281
+ },
282
+ };
283
+
284
+ export const Required: Story = {
285
+ args: {
286
+ ...defaultArgs,
287
+ isRequired: true,
288
+ },
289
+ render: (args) => {
290
+ const [value, setValue] = useState('');
291
+ return (
292
+ <Input
293
+ {...args}
294
+ value={value}
295
+ onChange={(e) => {
296
+ setValue(e.target.value);
297
+ }}
298
+ />
299
+ );
300
+ },
301
+ };
@@ -0,0 +1,86 @@
1
+ import React from 'react';
2
+ import { Icon } from '@/components/icons';
3
+ import { IconName } from '@/types';
4
+ import { Label } from '../subcomponents/Label';
5
+ import { ErrorList } from '../subcomponents/ErrorList';
6
+
7
+ export interface InputProps {
8
+ ref?: React.LegacyRef<HTMLInputElement>;
9
+ label: string;
10
+ name: string;
11
+ placeholder: string;
12
+ value: string;
13
+ onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
14
+ isRequired?: boolean;
15
+ isDisabled?: boolean;
16
+ errorList?: string[];
17
+ helpText?: string;
18
+ hasHiddenLabel?: boolean;
19
+ iconName?: IconName;
20
+ isClearable?: boolean;
21
+ }
22
+
23
+ export const Input = ({
24
+ ref,
25
+ label,
26
+ name,
27
+ placeholder,
28
+ value,
29
+ onChange,
30
+ isRequired,
31
+ isDisabled,
32
+ errorList,
33
+ helpText,
34
+ iconName,
35
+ hasHiddenLabel,
36
+ isClearable,
37
+ ...rest
38
+ }: InputProps) => {
39
+ const hasErrors = errorList && errorList.length > 0;
40
+ const handleClear = () => {
41
+ onChange({ target: { value: '' } } as React.ChangeEvent<HTMLInputElement>);
42
+ };
43
+
44
+ return (
45
+ <div className="form-control">
46
+ <Label label={label} name={name} isRequired={isRequired} hasHiddenLabel={hasHiddenLabel} />
47
+ <div className="input-wrapper">
48
+ {iconName && (
49
+ <Icon name={iconName} data-testid={`${name}-embedded-icon`} className="embedded-icon" />
50
+ )}
51
+ <input
52
+ ref={ref}
53
+ data-testid={`form-input-${name}`}
54
+ name={name}
55
+ type="text"
56
+ disabled={isDisabled}
57
+ required={isRequired}
58
+ placeholder={placeholder}
59
+ value={value}
60
+ onChange={onChange}
61
+ className={`input ${hasErrors ? 'error' : ''} ${iconName ? 'input--has-icon' : ''}`}
62
+ aria-invalid={hasErrors}
63
+ aria-describedby={hasErrors || helpText ? `${name}-helper` : undefined}
64
+ aria-required={isRequired}
65
+ aria-label={label}
66
+ {...rest}
67
+ />
68
+ {isClearable && (
69
+ <Icon
70
+ name="x-close"
71
+ data-testid={`${name}-clearable-icon`}
72
+ size="sm"
73
+ onClick={handleClear}
74
+ className="clearable-icon"
75
+ />
76
+ )}
77
+ </div>
78
+ {hasErrors && <ErrorList errorList={errorList} name={name} />}
79
+ {helpText && (
80
+ <div data-testid={`${name}-help-text`} className="help-text" id={`${name}-helper`}>
81
+ {helpText}
82
+ </div>
83
+ )}
84
+ </div>
85
+ );
86
+ };