@xqmsg/ui-core 0.9.2 → 0.10.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 (47) hide show
  1. package/dist/components/input/InputTypes.d.ts +5 -3
  2. package/dist/components/input/StackedInput/StackedInput.d.ts +0 -3
  3. package/dist/components/input/StackedMultiSelect/index.d.ts +1 -1
  4. package/dist/components/input/StackedSelect/StackedSelect.d.ts +7 -3
  5. package/dist/components/input/components/dropdown/index.d.ts +10 -0
  6. package/dist/components/input/components/label/index.d.ts +9 -0
  7. package/dist/components/input/components/token/Token.stories.d.ts +5 -0
  8. package/dist/components/input/components/token/index.d.ts +7 -0
  9. package/dist/components/input/index.d.ts +1 -3
  10. package/dist/theme/components/form-error.d.ts +3 -3
  11. package/dist/theme/components/form-label.d.ts +4 -6
  12. package/dist/theme/components/form.d.ts +3 -3
  13. package/dist/theme/components/input.d.ts +32 -161
  14. package/dist/theme/components/select.d.ts +27 -153
  15. package/dist/theme/components/textarea.d.ts +10 -117
  16. package/dist/theme/foundations/colors.d.ts +30 -0
  17. package/dist/ui-core.cjs.development.js +455 -490
  18. package/dist/ui-core.cjs.development.js.map +1 -1
  19. package/dist/ui-core.cjs.production.min.js +1 -1
  20. package/dist/ui-core.cjs.production.min.js.map +1 -1
  21. package/dist/ui-core.esm.js +459 -494
  22. package/dist/ui-core.esm.js.map +1 -1
  23. package/package.json +5 -3
  24. package/src/components/input/Input.stories.tsx +28 -12
  25. package/src/components/input/InputTypes.ts +7 -1
  26. package/src/components/input/StackedInput/StackedInput.tsx +3 -15
  27. package/src/components/input/StackedMultiSelect/components/MultiValue/index.tsx +2 -2
  28. package/src/components/input/StackedMultiSelect/index.tsx +89 -93
  29. package/src/components/input/StackedPilledInput/index.tsx +145 -56
  30. package/src/components/input/StackedSelect/StackedSelect.tsx +63 -20
  31. package/src/components/input/StackedSelect/assets/svg/subtract.svg +3 -0
  32. package/src/components/input/components/dropdown/index.tsx +79 -0
  33. package/src/components/input/components/label/index.tsx +24 -0
  34. package/src/components/input/components/token/Token.stories.tsx +22 -0
  35. package/src/components/input/components/token/assets/svg/close.svg +3 -0
  36. package/src/components/input/components/token/index.tsx +37 -0
  37. package/src/components/input/index.tsx +8 -20
  38. package/src/theme/components/alert.ts +4 -4
  39. package/src/theme/components/form-error.ts +11 -14
  40. package/src/theme/components/form-label.ts +8 -8
  41. package/src/theme/components/form.ts +10 -13
  42. package/src/theme/components/input.ts +17 -191
  43. package/src/theme/components/select.ts +5 -10
  44. package/src/theme/components/textarea.ts +2 -38
  45. package/src/theme/foundations/colors.ts +17 -1
  46. package/dist/components/input/components/InputTag/index.d.ts +0 -7
  47. package/src/components/input/components/InputTag/index.tsx +0 -24
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.9.2",
2
+ "version": "0.10.0",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
@@ -79,6 +79,10 @@
79
79
  "tsdx": "^0.14.1",
80
80
  "tslib": "^2.4.0",
81
81
  "typescript": "^4.8.2",
82
+ "generate-changelog": "^1.8.0",
83
+ "yalc": "^1.0.0-pre.53"
84
+ },
85
+ "dependencies": {
82
86
  "@chakra-ui/icons": "^2.0.0",
83
87
  "@chakra-ui/media-query": "^2.0.0",
84
88
  "@chakra-ui/progress": "^2.0.0",
@@ -94,7 +98,6 @@
94
98
  "@hookform/resolvers": "^2.9.7",
95
99
  "axios": "^0.27.2",
96
100
  "framer-motion": "6.3.0",
97
- "generate-changelog": "^1.8.0",
98
101
  "ip-regex": "^5.0.0",
99
102
  "react": "^18.0.0",
100
103
  "react-dom": "^18.0.0",
@@ -102,7 +105,6 @@
102
105
  "react-icons": "^4.4.0",
103
106
  "react-is": "^18.2.0",
104
107
  "react-select": "^5.4.0",
105
- "yalc": "^1.0.0-pre.53",
106
108
  "yup": "^0.32.11"
107
109
  },
108
110
  "resolutions": {
@@ -7,6 +7,7 @@ import * as Yup from 'yup';
7
7
  import { Form } from '../form';
8
8
  import ipRegex from 'ip-regex';
9
9
  import { useEffect, useMemo } from '@storybook/addons';
10
+ import { Box } from '@chakra-ui/react';
10
11
 
11
12
  const meta: Meta<InputProps<StoryFormSchema>> = {
12
13
  title: 'Input example',
@@ -85,7 +86,7 @@ const storyFormSchema: Yup.SchemaOf<StoryFormSchema> = Yup.object().shape({
85
86
  (value, testContext) => {
86
87
  if (value) {
87
88
  const ipStringsToArray = value.split(',');
88
- const isIPValidArray = ipStringsToArray.map(ip => {
89
+ const isIPValidArray = ipStringsToArray.map((ip) => {
89
90
  return ipRegex({ exact: true }).test(ip as string);
90
91
  });
91
92
 
@@ -99,7 +100,7 @@ const storyFormSchema: Yup.SchemaOf<StoryFormSchema> = Yup.object().shape({
99
100
  return malformedIP.trim();
100
101
  }
101
102
  })
102
- .filter(invalidIP => invalidIP !== undefined);
103
+ .filter((invalidIP) => invalidIP !== undefined);
103
104
 
104
105
  const errorMessage = `Malformed IPs: ${malformedIPList.join(', ')}`;
105
106
  return testContext.createError({
@@ -114,7 +115,7 @@ const storyFormSchema: Yup.SchemaOf<StoryFormSchema> = Yup.object().shape({
114
115
  });
115
116
 
116
117
  export default meta;
117
- const Template: Story<InputProps<StoryFormSchema>> = args => {
118
+ const Template: Story<InputProps<StoryFormSchema>> = (args) => {
118
119
  const formHandler = useFormHandler<StoryFormSchema>(
119
120
  onStubbedSubmit,
120
121
  storyFormDefaultValues,
@@ -129,20 +130,15 @@ const Template: Story<InputProps<StoryFormSchema>> = args => {
129
130
  if (form.formState.errors) return form.formState.errors.prop?.message;
130
131
  }, [form.formState.errors]);
131
132
 
132
- console.log(form.watch('prop'));
133
-
134
133
  useEffect(() => {
135
134
  form.resetField('prop');
136
- }, [args.inputType]);
135
+ }, [args.inputType, form]);
137
136
 
138
137
  return (
139
138
  <Form formHandler={formHandler}>
140
- <Input
141
- {...args}
142
- setValue={form.setValue}
143
- errorText={valueErrorMessage}
144
- isInvalid={!!valueErrorMessage}
145
- />
139
+ <Input {...args} setValue={form.setValue} errorText={valueErrorMessage} />
140
+ <Box mb={10}>Hi</Box> <Box mb={10}>there</Box> <Box mb={10}>Hi</Box>{' '}
141
+ <Box mb={10}>hey</Box> hello
146
142
  </Form>
147
143
  );
148
144
  };
@@ -153,17 +149,37 @@ Default.args = {
153
149
  inputType: 'text',
154
150
  name: 'prop',
155
151
  options: [
152
+ { value: 'section_header', label: 'Section 1', sortValue: 0 },
156
153
  {
157
154
  value: 'value1',
158
155
  label: 'Value 1',
156
+ sortValue: 1,
159
157
  },
160
158
  {
161
159
  value: 'value2',
162
160
  label: 'Value 2',
161
+ sortValue: 2,
163
162
  },
164
163
  {
165
164
  value: 'value3',
166
165
  label: 'Value 3',
166
+ sortValue: 3,
167
+ },
168
+ {
169
+ value: 'value4',
170
+ label: 'Value 4',
171
+ sortValue: 4,
172
+ },
173
+ { value: 'section_header', label: 'Section 2', sortValue: 5 },
174
+ {
175
+ value: 'value5',
176
+ label: 'Value 5',
177
+ sortValue: 6,
178
+ },
179
+ {
180
+ value: 'value6',
181
+ label: 'Value 6',
182
+ sortValue: 7,
167
183
  },
168
184
  ],
169
185
  isRequired: true,
@@ -18,7 +18,13 @@ export type InputType =
18
18
  | 'checkbox'
19
19
  | 'switch';
20
20
 
21
- export type FieldOptions = { label: string; value: string }[];
21
+ export type FieldOption = {
22
+ label: string;
23
+ value: string | 'section_header';
24
+ sortValue: number;
25
+ };
26
+
27
+ export type FieldOptions = FieldOption[];
22
28
 
23
29
  export interface ValidationProps {
24
30
  isRequired: boolean;
@@ -1,29 +1,17 @@
1
1
  import React from 'react';
2
- import { Input, InputGroup } from '@chakra-ui/react';
2
+ import { Input } from '@chakra-ui/react';
3
3
  import { InputFieldProps } from '../InputTypes';
4
4
 
5
5
  export interface StackedInputProps extends InputFieldProps {
6
- label?: string;
7
6
  isRequired?: boolean;
8
- leftElement?: React.ReactNode;
9
- rightElement?: React.ReactNode;
10
7
  }
11
8
 
12
9
  /**
13
10
  * A functional React component utilized to render the `StackedInput` component.
14
11
  */
15
12
  const StackedInput = React.forwardRef<HTMLInputElement, StackedInputProps>(
16
- (
17
- { type = 'text', isRequired, leftElement, rightElement, ...props },
18
- _ref
19
- ) => {
20
- return (
21
- <InputGroup>
22
- {leftElement && leftElement}
23
- <Input ref={_ref} type={type} isRequired={isRequired} {...props} />
24
- {rightElement && rightElement}
25
- </InputGroup>
26
- );
13
+ ({ type = 'text', isRequired, ...props }, _ref) => {
14
+ return <Input ref={_ref} type={type} isRequired={isRequired} {...props} />;
27
15
  }
28
16
  );
29
17
 
@@ -1,6 +1,6 @@
1
1
  import { Box } from '@chakra-ui/react';
2
2
  import React, { PropsWithChildren } from 'react';
3
- import InputTag from '../../../components/InputTag';
3
+ import InputTag from '../../../components/token';
4
4
 
5
5
  interface MultiValueProps extends PropsWithChildren {
6
6
  clearValue: () => void;
@@ -13,7 +13,7 @@ interface MultiValueProps extends PropsWithChildren {
13
13
  const MultiValue: React.FC<MultiValueProps> = ({ children, clearValue }) => {
14
14
  return (
15
15
  <Box marginRight="5px">
16
- <InputTag value={children} onDelete={clearValue} />
16
+ <InputTag label={children} onDelete={clearValue} />
17
17
  </Box>
18
18
  );
19
19
  };
@@ -1,15 +1,20 @@
1
- import React, { useEffect, useState } from 'react';
2
- import { Flex } from '@chakra-ui/react';
3
- import { FieldOptions, ReactSelectFieldProps } from '../InputTypes';
4
- import ReactSelect from 'react-select';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { Box, Flex, Text, Image, useOutsideClick } from '@chakra-ui/react';
3
+ import {
4
+ FieldOption,
5
+ FieldOptions,
6
+ ReactSelectFieldProps,
7
+ } from '../InputTypes';
5
8
  import colors from '../../../theme/foundations/colors';
6
- import MultiValue from './components/MultiValue';
7
9
  import {
8
10
  Control,
9
11
  FieldValues,
10
12
  UseFormSetValue,
11
13
  useWatch,
12
14
  } from 'react-hook-form';
15
+ import SubtractIcon from '../StackedSelect/assets/svg/subtract.svg';
16
+ import { Dropdown } from '../components/dropdown';
17
+ import Token from '../components/token';
13
18
 
14
19
  export interface StackedMultiSelectProps extends ReactSelectFieldProps {
15
20
  options: FieldOptions;
@@ -21,124 +26,115 @@ export interface StackedMultiSelectProps extends ReactSelectFieldProps {
21
26
  * A functional React component utilized to render the `StackedMultiSelect` component.
22
27
  */
23
28
  const StackedMultiSelect = React.forwardRef<
24
- HTMLSelectElement,
29
+ HTMLInputElement,
25
30
  StackedMultiSelectProps
26
- >(({ options, setValue, control, name }, _ref) => {
31
+ >(({ options, setValue, control, name, placeholder, disabled }, _ref) => {
27
32
  const watchedValue = useWatch({ control, name: name as string });
33
+ const dropdownRef = useRef(null);
34
+
35
+ const [localValues, setLocalValues] = useState<FieldOptions>([]);
36
+ const [localOptions, setLocalOptions] = useState<FieldOptions>(options);
37
+ const [isFocussed, setIsFocussed] = useState(false);
28
38
 
29
- const [inputValue, setInputValue] = useState('');
30
- const [localValue, setLocalValue] = useState([]);
39
+ useOutsideClick({ ref: dropdownRef, handler: () => setIsFocussed(false) });
31
40
 
32
41
  // gets latest watched form value (common delimited) from RHF state and creates a list
33
42
  useEffect(() => {
34
43
  if (watchedValue !== undefined && !watchedValue.length) {
35
- setLocalValue([]);
44
+ setLocalValues([]);
36
45
  }
37
46
 
38
47
  if (watchedValue !== undefined && watchedValue?.length) {
39
- setLocalValue(
48
+ setLocalValues(
40
49
  watchedValue
41
50
  .split(',')
42
51
  .filter(Boolean)
43
52
  .map((value: string) =>
44
- options.find(option => option.value === value)
53
+ options.find((option) => option.value === value)
45
54
  )
46
55
  );
47
56
  }
48
57
  }, [options, watchedValue]);
49
58
 
50
- const component = {
51
- DropdownIndicator: null,
52
- MultiValue: (props: any) => (
53
- <MultiValue
54
- clearValue={() => {
55
- const arrayValue = watchedValue
56
- .split(',')
57
- .filter((_: string, index: number) => index !== props.index);
58
-
59
- setLocalValue(
60
- arrayValue.map((value: string) =>
61
- options.find(option => option.value === value)
62
- )
63
- );
64
-
65
- setValue(name as string, arrayValue.join(','), {
66
- shouldValidate: true,
67
- shouldDirty: true,
68
- });
69
- }}
70
- >
71
- {props.children}
72
- </MultiValue>
73
- ),
74
- };
59
+ const handleChange = (option: FieldOption) => {
60
+ const newValue = [...localValues, option]
61
+ .map(({ value }) => value)
62
+ .join(',');
75
63
 
76
- const handleChange = (values: any) => {
77
- setValue(
78
- name as string,
79
- values.map(({ value }: { value: string }) => value).join(','),
80
- {
81
- shouldValidate: true,
82
- shouldDirty: true,
83
- }
64
+ setValue(name as string, newValue, {
65
+ shouldValidate: true,
66
+ shouldDirty: true,
67
+ });
68
+
69
+ setLocalOptions((prevLocalOptions) =>
70
+ prevLocalOptions.filter((prevLocalOption) => prevLocalOption !== option)
84
71
  );
72
+
73
+ setLocalValues((prevLocalValues) => [...prevLocalValues, option]);
85
74
  };
86
75
 
87
- const handleInputChange = (value: string, action: any) => {
88
- if (action.action === 'input-change' && action !== 'set-value') {
89
- return setInputValue(value);
90
- }
76
+ const handleDelete = (option: FieldOption) => {
77
+ const newValue = localValues
78
+ .filter((localValue) => localValue !== option)
79
+ .map(({ value }) => value)
80
+ .join(',');
91
81
 
92
- // reset on select of an option
93
- return setInputValue('');
94
- };
82
+ setValue(name as string, newValue, {
83
+ shouldValidate: true,
84
+ shouldDirty: true,
85
+ });
95
86
 
96
- const formatGroupLabel = (data: any) => {
97
- return (
98
- <Flex alignItems="center" justifyContent="space-between">
99
- <span>{data.label}</span>
100
- </Flex>
87
+ setLocalOptions((prevLocalOptions) =>
88
+ [...prevLocalOptions, option].sort((a, b) => a.sortValue - b.sortValue)
101
89
  );
102
- };
103
90
 
104
- const customStyles = {
105
- control: () => ({
106
- borderRadius: '6px',
107
- fontSize: '16px',
108
- color: '#202020',
109
- backgroundColor: '#FFFFFF',
110
- border: '1px solid',
111
- borderColor: colors.gray[200],
112
- minHeight: '48px',
113
- display: 'flex',
114
- padding: '2px 6px',
115
- }),
116
- menu: () => ({
117
- boxShadow: '0 5px 5px 0 rgba(16, 27, 79, 0.15)',
118
- borderRadius: '6px',
119
- backgroundColor: 'white',
120
- }),
121
- indicatorsContainer: () => ({ display: 'none' }),
122
- placeholder: () => ({ color: '#CBCDCF', fontSize: '16px' }),
91
+ setLocalValues((prevLocalValues) =>
92
+ prevLocalValues.filter((prevLocalValue) => prevLocalValue !== option)
93
+ );
123
94
  };
124
95
 
125
96
  return (
126
- <ReactSelect
127
- components={component}
128
- inputValue={inputValue}
129
- value={localValue}
130
- isClearable
131
- isSearchable
132
- isMulti
133
- menuPortalTarget={document.body}
134
- menuPosition={'fixed'}
135
- onChange={handleChange}
136
- onInputChange={handleInputChange}
137
- styles={customStyles}
138
- options={options}
139
- placeholder={false}
140
- formatGroupLabel={formatGroupLabel}
141
- />
97
+ <Box ref={dropdownRef} position="relative">
98
+ <Flex
99
+ fontSize="13px"
100
+ border={isFocussed ? '2px solid' : '1px solid'}
101
+ borderColor={isFocussed ? colors.border.focus : colors.border.default}
102
+ py="5px"
103
+ pl="8px"
104
+ borderRadius="4px"
105
+ alignItems="center"
106
+ justifyContent="space-between"
107
+ onClick={() => !disabled && setIsFocussed(true)}
108
+ bg={disabled ? colors.fill.light : '#ffffff'}
109
+ cursor={disabled ? 'not-allowed' : 'pointer'}
110
+ >
111
+ <Flex height="28px" alignItems="center">
112
+ {localValues.length ? (
113
+ localValues.map((option) => (
114
+ <Box mr="4px">
115
+ <Token
116
+ label={option.label}
117
+ onDelete={() => handleDelete(option)}
118
+ />
119
+ </Box>
120
+ ))
121
+ ) : (
122
+ <Text color={colors.label.secondary.light} fontSize="13px">
123
+ {placeholder}
124
+ </Text>
125
+ )}
126
+ </Flex>
127
+ <Flex width="39px" justifyContent="center" alignItems="center">
128
+ <Image src={SubtractIcon} alt="subtract" boxSize="16px" />
129
+ </Flex>
130
+ </Flex>
131
+ {isFocussed && (
132
+ <Dropdown
133
+ onSelectItem={(option) => handleChange(option)}
134
+ options={localOptions}
135
+ />
136
+ )}
137
+ </Box>
142
138
  );
143
139
  });
144
140