@performant-software/semantic-components 1.0.19 → 1.0.20-beta.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.
@@ -1,112 +0,0 @@
1
- // @flow
2
-
3
- import React, {
4
- useCallback,
5
- useEffect,
6
- useState,
7
- type ComponentType
8
- } from 'react';
9
- import { Button, Input, Label } from 'semantic-ui-react';
10
- import _ from 'underscore';
11
- import './UserDefinedFieldOptions.css';
12
-
13
- type Props = {
14
- options: Array<string>,
15
- onChange: (options: Array<string>) => void
16
- };
17
-
18
- const UserDefinedFieldOptions: ComponentType<any> = (props: Props) => {
19
- const [options, setOptions] = useState(_.map(props.options, (option) => ({ value: option })));
20
-
21
- /**
22
- * Adds a new option to the list.
23
- *
24
- * @type {(function(): void)|*}
25
- */
26
- const onAddOption = useCallback(() => {
27
- setOptions((prevOptions) => [...prevOptions, { new: true }]);
28
- }, []);
29
-
30
- /**
31
- * Deletes the option at the passed index from the list.
32
- *
33
- * @type {(function(*): void)|*}
34
- */
35
- const onDeleteOption = useCallback((findIndex) => {
36
- setOptions((prevOptions) => _.filter(prevOptions, (option, index) => index !== findIndex));
37
- }, []);
38
-
39
- /**
40
- * Removes the "new" indicator from the option at the passed index.
41
- *
42
- * @type {(function(*): void)|*}
43
- */
44
- const onSaveOption = useCallback((findIndex) => {
45
- setOptions((prevOptions) => _.map(
46
- prevOptions,
47
- (option, index) => (findIndex !== index ? option : ({ ...option, new: false }))
48
- ));
49
- }, [options]);
50
-
51
- /**
52
- * Updates the value of the option at the passed index.
53
- *
54
- * @type {(function(*, *, {value: *}): void)|*}
55
- */
56
- const onUpdateOption = useCallback((findIndex, e, { value }) => {
57
- setOptions((prevOptions) => _.map(
58
- prevOptions,
59
- (option, index) => (index !== findIndex ? option : ({ ...option, value }))
60
- ));
61
- }, []);
62
-
63
- /**
64
- * Calls the onChange prop when the list of options changes.
65
- */
66
- useEffect(() => {
67
- const savedOptions = _.filter(options, (option) => !option.new);
68
- props.onChange(_.pluck(savedOptions, 'value'));
69
- }, [options]);
70
-
71
- return (
72
- <div
73
- className='user-defined-field-options'
74
- >
75
- <Button
76
- basic
77
- icon='plus'
78
- onClick={onAddOption}
79
- type='button'
80
- />
81
- { _.map(options, (option, index) => (
82
- <>
83
- { option.new && (
84
- <Label>
85
- <Input
86
- autoFocus
87
- onChange={onUpdateOption.bind(this, index)}
88
- value={option.value}
89
- />
90
- <Button
91
- basic
92
- color='green'
93
- icon='checkmark'
94
- onClick={onSaveOption.bind(this, index)}
95
- type='button'
96
- size='tiny'
97
- />
98
- </Label>
99
- )}
100
- { !option.new && (
101
- <Label
102
- content={option.value}
103
- onRemove={onDeleteOption.bind(this, index)}
104
- />
105
- )}
106
- </>
107
- ))}
108
- </div>
109
- );
110
- };
111
-
112
- export default UserDefinedFieldOptions;
@@ -1,45 +0,0 @@
1
- // @flow
2
-
3
- import React from 'react';
4
- import i18n from '../i18n/i18n';
5
- import BooleanIcon from './BooleanIcon';
6
- import EmbeddedList from './EmbeddedList';
7
- import UserDefinedFieldModal from './UserDefinedFieldModal';
8
-
9
- type Props = {
10
- items: Array<any>,
11
- onDelete: (item: any) => Promise<any>,
12
- onSave: (item: any) => Promise<any>
13
- };
14
-
15
- const UserDefinedFieldsEmbeddedList = (props: Props) => (
16
- <EmbeddedList
17
- actions={[{
18
- name: 'edit'
19
- }, {
20
- name: 'delete'
21
- }]}
22
- columns={[{
23
- name: 'table_name',
24
- label: i18n.t('UserDefinedFieldsEmbeddedList.columns.table')
25
- }, {
26
- name: 'column_name',
27
- label: i18n.t('UserDefinedFieldsEmbeddedList.columns.name')
28
- }, {
29
- name: 'data_type',
30
- label: i18n.t('UserDefinedFieldsEmbeddedList.columns.dataType')
31
- }, {
32
- name: 'required',
33
- label: i18n.t('UserDefinedFieldsEmbeddedList.columns.required'),
34
- render: (udf) => <BooleanIcon value={udf.required} />
35
- }]}
36
- items={props.items}
37
- modal={{
38
- component: UserDefinedFieldModal
39
- }}
40
- onDelete={props.onDelete}
41
- onSave={props.onSave}
42
- />
43
- );
44
-
45
- export default UserDefinedFieldsEmbeddedList;
@@ -1,209 +0,0 @@
1
- // @flow
2
-
3
- import { RichTextArea, UserDefinedFieldsService } from '@performant-software/shared-components';
4
- import React, {
5
- useCallback,
6
- useEffect,
7
- useMemo,
8
- useState,
9
- type ComponentType
10
- } from 'react';
11
- import { Form } from 'semantic-ui-react';
12
- import _ from 'underscore';
13
- import DatePicker from './DatePicker';
14
-
15
- type Props = {
16
- defineableId?: number,
17
- defineableType?: string,
18
- isError: (key: string) => boolean,
19
- item: any,
20
- onChange: (obj: any) => void,
21
- onClearValidationError: (...keys: Array<string>) => void
22
- };
23
-
24
- const DataTypes = {
25
- boolean: 'Boolean',
26
- date: 'Date',
27
- number: 'Number',
28
- richText: 'RichText',
29
- select: 'Select',
30
- string: 'String',
31
- text: 'Text'
32
- };
33
-
34
- const UserDefinedFieldsForm: ComponentType<any> = (props: Props) => {
35
- const [fields, setFields] = useState([]);
36
-
37
- /**
38
- * Sets the parsed value by parsing the JSON stored in the "user_defined" prop of the item.
39
- *
40
- * @type {unknown}
41
- */
42
- const parsedValue = useMemo(() => {
43
- let value = {};
44
-
45
- if (_.isString(props.item.user_defined)) {
46
- value = JSON.parse(props.item.user_defined);
47
- }
48
-
49
- return value;
50
- }, [props.item.user_defined]);
51
-
52
- /**
53
- * Returns the key for the passed field.
54
- *
55
- * @type {function(*): string}
56
- */
57
- const getFieldKey = useCallback((field) => `user_defined[${field.column_name}]`, []);
58
-
59
- /**
60
- * Returns true if an error exists on the state for the passed field.
61
- *
62
- * @type {function(*): *}
63
- */
64
- const isError = useCallback((field) => props.isError(getFieldKey(field)), [getFieldKey, props.isError]);
65
-
66
- /**
67
- * Changes the value for the passed item.
68
- *
69
- * @type {(function(*, *): void)|*}
70
- */
71
- const onChange = useCallback((field, value) => {
72
- props.onChange(JSON.stringify({ ...parsedValue, [field.column_name]: value }));
73
-
74
- // Clear the validation error if one exists
75
- if (props.onClearValidationError) {
76
- props.onClearValidationError(getFieldKey(field));
77
- }
78
- }, [getFieldKey, parsedValue, props.onChange, props.onClearValidationError]);
79
-
80
- /**
81
- * Renders the passed item.
82
- *
83
- * @type {function(*): *}
84
- */
85
- const renderItem = useCallback((field) => {
86
- let rendered;
87
-
88
- const fieldValue = parsedValue && parsedValue[field.column_name];
89
-
90
- if (field.data_type === DataTypes.string) {
91
- rendered = (
92
- <Form.Input
93
- error={isError(field)}
94
- label={field.column_name}
95
- required={field.required}
96
- onChange={(e, { value }) => onChange(field, value)}
97
- value={fieldValue}
98
- />
99
- );
100
- }
101
-
102
- if (field.data_type === DataTypes.number) {
103
- rendered = (
104
- <Form.Input
105
- error={isError(field)}
106
- label={field.column_name}
107
- required={field.required}
108
- onChange={(e, { value }) => onChange(field, value)}
109
- value={fieldValue}
110
- type='number'
111
- />
112
- );
113
- }
114
-
115
- if (field.data_type === DataTypes.select) {
116
- rendered = (
117
- <Form.Dropdown
118
- clearable
119
- error={isError(field)}
120
- label={field.column_name}
121
- multiple={field.allow_multiple}
122
- required={field.required}
123
- options={_.map(field.options, (option) => ({ key: option, value: option, text: option }))}
124
- onChange={(e, { value }) => onChange(field, value)}
125
- selectOnBlur={false}
126
- selection
127
- value={fieldValue}
128
- />
129
- );
130
- }
131
-
132
- if (field.data_type === DataTypes.text) {
133
- rendered = (
134
- <Form.TextArea
135
- error={isError(field)}
136
- label={field.column_name}
137
- required={field.required}
138
- onChange={(e, { value }) => onChange(field, value)}
139
- value={fieldValue}
140
- />
141
- );
142
- }
143
-
144
- if (field.data_type === DataTypes.date) {
145
- rendered = (
146
- <Form.Input
147
- error={isError(field)}
148
- label={field.column_name}
149
- required={field.required}
150
- >
151
- <DatePicker
152
- onChange={(date) => onChange(field, date && date.toString())}
153
- value={fieldValue && new Date(fieldValue)}
154
- />
155
- </Form.Input>
156
- );
157
- }
158
-
159
- if (field.data_type === DataTypes.boolean) {
160
- rendered = (
161
- <Form.Checkbox
162
- checked={!!fieldValue}
163
- error={isError(field)}
164
- label={field.column_name}
165
- onChange={(e, { checked }) => onChange(field, checked)}
166
- />
167
- );
168
- }
169
-
170
- if (field.data_type === DataTypes.richText) {
171
- rendered = (
172
- <Form.Input
173
- error={isError(field)}
174
- label={field.column_name}
175
- required={field.required}
176
- >
177
- <RichTextArea
178
- onChange={(value) => onChange(field, value)}
179
- value={fieldValue}
180
- />
181
- </Form.Input>
182
- );
183
- }
184
-
185
- return rendered;
186
- }, [parsedValue, isError, onChange]);
187
-
188
- /**
189
- * Fetches the user defined fields when the component mounts.
190
- */
191
- useEffect(() => {
192
- const params = {
193
- defineable_id: props.defineableId,
194
- defineable_type: props.defineableType
195
- };
196
-
197
- UserDefinedFieldsService
198
- .fetchAll(params)
199
- .then(({ data }) => setFields(data.user_defined_fields));
200
- }, []);
201
-
202
- return (
203
- <>
204
- { _.map(fields, renderItem.bind(this)) }
205
- </>
206
- );
207
- };
208
-
209
- export default UserDefinedFieldsForm;
@@ -1,41 +0,0 @@
1
- // @flow
2
-
3
- import { UserDefinedFieldsService } from '@performant-software/shared-components';
4
- import React, { type ComponentType } from 'react';
5
- import i18n from '../i18n/i18n';
6
- import BooleanIcon from './BooleanIcon';
7
- import ListTable from './ListTable';
8
- import UserDefinedFieldModal from './UserDefinedFieldModal';
9
-
10
- const UserDefinedFieldsList: ComponentType<any> = () => (
11
- <ListTable
12
- actions={[{
13
- name: 'edit'
14
- }, {
15
- name: 'delete'
16
- }]}
17
- columns={[{
18
- name: 'table_name',
19
- label: i18n.t('UserDefinedFieldsList.columns.table')
20
- }, {
21
- name: 'column_name',
22
- label: i18n.t('UserDefinedFieldsList.columns.name')
23
- }, {
24
- name: 'data_type',
25
- label: i18n.t('UserDefinedFieldsList.columns.dataType')
26
- }, {
27
- name: 'required',
28
- label: i18n.t('UserDefinedFieldsList.columns.required'),
29
- render: (udf) => <BooleanIcon value={udf.required} />
30
- }]}
31
- collectionName='user_defined_fields'
32
- modal={{
33
- component: UserDefinedFieldModal
34
- }}
35
- onLoad={(params) => UserDefinedFieldsService.fetchAll(params)}
36
- onSave={(udf) => UserDefinedFieldsService.save(udf)}
37
- onDelete={(udf) => UserDefinedFieldsService.delete(udf)}
38
- />
39
- );
40
-
41
- export default UserDefinedFieldsList;
@@ -1,5 +0,0 @@
1
- // @flow
2
-
3
- import 'semantic-ui-less/semantic.less';
4
-
5
- export default {};
@@ -1,54 +0,0 @@
1
- // @flow
2
-
3
- import React, {
4
- useEffect,
5
- useRef,
6
- useState,
7
- type ComponentType
8
- } from 'react';
9
-
10
- type Imageable = {
11
- contextRef: any,
12
- imageLoaded: boolean,
13
- onImageLoaded: () => void,
14
- onImageUnloaded: () => void
15
- };
16
-
17
- const useImageable = (WrappedComponent: ComponentType<any>) => (props: any) => {
18
- const [loaded, setLoaded] = useState(false);
19
- const imageRef = useRef(null);
20
-
21
- /**
22
- * Since images may be cached, we cannot always rely on the img onLoad event. Here we'll use a ref to check to see
23
- * if the image has completed loading.
24
- */
25
- useEffect(() => {
26
- const imageInstance = imageRef.current;
27
-
28
- if (imageInstance && imageInstance.firstChild && imageInstance.firstChild.firstChild) {
29
- const image = imageInstance.firstChild.firstChild;
30
-
31
- if (image && image.complete) {
32
- setLoaded(true);
33
- }
34
- }
35
- }, []);
36
-
37
- return (
38
- <WrappedComponent
39
- {...props}
40
- contextRef={imageRef}
41
- imageLoaded={loaded}
42
- onImageLoaded={() => setLoaded(true)}
43
- onImageUnloaded={() => setLoaded(false)}
44
- />
45
- );
46
- };
47
-
48
- export {
49
- useImageable
50
- };
51
-
52
- export type {
53
- Imageable
54
- };
@@ -1,95 +0,0 @@
1
- // @flow
2
-
3
- import { useConnector } from 'react-instantsearch-hooks-web';
4
- import connectRange from 'instantsearch.js/es/connectors/range/connectRange';
5
- import connectStats from 'instantsearch.js/es/connectors/stats/connectStats';
6
-
7
- /**
8
- * Utility function to create the range slider hook.
9
- *
10
- * @param props
11
- */
12
- export const useRangeSlider = (props) => useConnector(connectRange, props);
13
-
14
- /**
15
- * Utility function to create the stats hook.
16
- *
17
- * @param props
18
- */
19
- export const useStats = (props) => useConnector(connectStats, props);
20
-
21
- export type ClearRefinementsProps = {
22
- useClearRefinements: (props: any) => ({ canRefine: boolean, refine: () => void })
23
- };
24
-
25
- export type CurrentRefinementsProps = {
26
- useCurrentRefinements: (props: any) => ({ items: Array<any> })
27
- };
28
-
29
- export type HitsPerPageProps = {
30
- useHitsPerPage: (props: any) => ({
31
- items: Array<{ value: number, label: string, default: boolean}>,
32
- refine: (value: number) => void
33
- })
34
- };
35
-
36
- export type HitsProps = {
37
- useHits: (props: any) => ({
38
- hits: Array<any>
39
- })
40
- };
41
-
42
- export type PaginationProps = {
43
- usePagination: (props: any) => ({
44
- currentRefinement: number,
45
- nbPages: number,
46
- refine: (value: number) => void
47
- })
48
- };
49
-
50
- export type RangeSliderProps = {
51
- useRangeSlider: (props: any) => ({
52
- start: Array<number>,
53
- range: {
54
- min: number,
55
- max: number
56
- },
57
- refine: ({ min: number, max: number }) => void
58
- })
59
- };
60
-
61
- export type RefinementListProps = {
62
- useRefinementList: (props: any) => ({
63
- items: Array<any>,
64
- refine: (value: any) => void,
65
- canToggleShowMore: boolean,
66
- isShowingMore: boolean,
67
- toggleShowMore: () => void
68
- })
69
- };
70
-
71
- export type SearchBoxProps = {
72
- useSearchBox: (props: any) => ({
73
- query: string,
74
- refine: (value: string) => void,
75
- clear: () => void,
76
- isSearchStalled: boolean
77
- })
78
- };
79
-
80
- export type StatsProps = {
81
- useStats: (props: any) => ({
82
- nbHits: number,
83
- processingTimeMS: number
84
- })
85
- };
86
-
87
- export type ToggleRefinementProps = {
88
- useToggleRefinement: (props: any) => ({
89
- value: {
90
- isRefined: boolean,
91
- count: number
92
- },
93
- refine: (value: boolean) => void
94
- })
95
- };