draft-components 1.7.1 → 1.9.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.
@@ -14,14 +14,22 @@ const keyboardKeys = require('../../lib/keyboard-keys.cjs');
14
14
  const helpers = require('../../lib/helpers.cjs');
15
15
  const reactHelpers = require('../../lib/react-helpers.cjs');
16
16
 
17
- function FilteredSearch({ className, placeholder = 'Search and filter', applyButtonLabel = 'Apply', cancelButtonLabel = 'Cancel', clearButtonAccessibleName = 'Clear', removeFilterButtonAccessibleName = 'Remove filter', filtersConfig, filters, onChange, onMouseDown, ...props }) {
17
+ function FilteredSearch({ filters: appliedFilters, className, placeholder = 'Search and filter', applyButtonLabel = 'Apply', cancelButtonLabel = 'Cancel', clearButtonAccessibleName = 'Clear', removeFilterButtonAccessibleName = 'Remove filter', filtersConfig, onChangeFilters, onMouseDown, ...props }) {
18
18
  const containerRef = react.useRef(null);
19
+ const [newFilter, setNewFilter] = react.useState(null);
19
20
  const [query, setQuery] = react.useState('');
20
21
  const [hasFocus, setHasFocus] = react.useState(false);
21
22
  const [expanded, setExpanded] = react.useState(false);
22
23
  const [selectedId, setSelectedId] = react.useState('');
23
24
  const [activeField, setActiveField] = react.useState('');
24
25
  const { textBoxId, listBoxId, getOptionId } = useComboboxIds.useComboboxIds();
26
+ let filters;
27
+ if (newFilter) {
28
+ filters = [...appliedFilters, newFilter];
29
+ }
30
+ else {
31
+ filters = appliedFilters;
32
+ }
25
33
  const filtersConfigMap = react.useMemo(() => {
26
34
  const map = new Map();
27
35
  for (const config of filtersConfig) {
@@ -36,21 +44,17 @@ function FilteredSearch({ className, placeholder = 'Search and filter', applyBut
36
44
  }
37
45
  return textBox;
38
46
  };
39
- const addFilter = (config) => {
40
- const filter = createFilter(config);
41
- const textBoxElement = getTextBoxElement();
42
- onChange([...filters, filter]);
43
- textBoxElement.blur();
44
- setQuery('');
45
- setActiveField(filter.field);
47
+ const addFilter = (filter) => {
48
+ const newFilters = [...appliedFilters, filter];
49
+ onChangeFilters(newFilters);
46
50
  };
47
- const changeFilter = (changedFilter) => {
48
- const newFilters = filters.map((filter) => (filter.field === changedFilter.field ? changedFilter : filter));
49
- onChange(newFilters);
51
+ const updateFilter = (updatedFilter) => {
52
+ const newFilters = appliedFilters.map((filter) => (filter.field === updatedFilter.field ? updatedFilter : filter));
53
+ onChangeFilters(newFilters);
50
54
  };
51
- const removeFilter = (filterToRemove) => {
52
- const newFilters = filters.filter((filter) => (filter.field !== filterToRemove.field));
53
- onChange(newFilters);
55
+ const removeFilter = (removedFilter) => {
56
+ const newFilters = appliedFilters.filter((filter) => (filter.field !== removedFilter.field));
57
+ onChangeFilters(newFilters);
54
58
  };
55
59
  const onFilterEditStarted = (filter) => {
56
60
  setActiveField(filter.field);
@@ -58,12 +62,23 @@ function FilteredSearch({ className, placeholder = 'Search and filter', applyBut
58
62
  const onFilterEditCanceled = (filter) => {
59
63
  setActiveField('');
60
64
  if (filter.isEmpty()) {
61
- removeFilter(filter);
65
+ if (newFilter && filter.field === newFilter.field) {
66
+ setNewFilter(null);
67
+ }
68
+ else {
69
+ removeFilter(filter);
70
+ }
62
71
  getTextBoxElement().focus();
63
72
  }
64
73
  };
65
74
  const onFilterChanged = (filter) => {
66
- changeFilter(filter);
75
+ if (newFilter && filter.field === newFilter.field) {
76
+ addFilter(filter);
77
+ setNewFilter(null);
78
+ }
79
+ else {
80
+ updateFilter(filter);
81
+ }
67
82
  setActiveField('');
68
83
  };
69
84
  const renderedFilters = [];
@@ -73,6 +88,14 @@ function FilteredSearch({ className, placeholder = 'Search and filter', applyBut
73
88
  fieldsWithAppliedFilters.add(field);
74
89
  renderedFilters.push(jsxRuntime.jsx(filterItem.FilterItem, { filter: filter, isEditing: activeField === field, onEditStart: onFilterEditStarted, onEditCancel: onFilterEditCanceled, onChange: onFilterChanged, onRemove: removeFilter }, field));
75
90
  }
91
+ const onOptionSelected = (config) => {
92
+ const filter = createFilter(config);
93
+ const textBoxElement = getTextBoxElement();
94
+ setQuery('');
95
+ setNewFilter(filter);
96
+ setActiveField(filter.field);
97
+ textBoxElement.blur();
98
+ };
76
99
  const onOptionHovered = (event) => {
77
100
  const listItemElement = event.currentTarget;
78
101
  setSelectedId(listItemElement.id);
@@ -83,7 +106,7 @@ function FilteredSearch({ className, placeholder = 'Search and filter', applyBut
83
106
  const listItemElement = event.currentTarget;
84
107
  const config = filtersConfigMap.get(listItemElement.id);
85
108
  if (config) {
86
- addFilter(config);
109
+ onOptionSelected(config);
87
110
  }
88
111
  };
89
112
  const renderedOptions = [];
@@ -127,13 +150,13 @@ function FilteredSearch({ className, placeholder = 'Search and filter', applyBut
127
150
  else if (key === keyboardKeys.KeyboardKeys.Enter) {
128
151
  const config = filtersConfigMap.get(selectedId);
129
152
  if (config) {
130
- addFilter(config);
153
+ onOptionSelected(config);
131
154
  isHandled = true;
132
155
  }
133
156
  }
134
157
  else if (key === keyboardKeys.KeyboardKeys.Backspace) {
135
158
  if (query === '' && filters.length > 0) {
136
- onChange(filters.slice(0, -1));
159
+ onChangeFilters(filters.slice(0, -1));
137
160
  isHandled = true;
138
161
  }
139
162
  }
@@ -163,7 +186,7 @@ function FilteredSearch({ className, placeholder = 'Search and filter', applyBut
163
186
  };
164
187
  const onClearButtonPressed = (event) => {
165
188
  event.stopPropagation();
166
- onChange([]);
189
+ onChangeFilters([]);
167
190
  };
168
191
  const onContainerPressed = (event) => {
169
192
  if (event.currentTarget === event.target) {
@@ -24,9 +24,9 @@ const emptyState = require('./empty-state/empty-state.cjs');
24
24
  const filePicker = require('./file-picker/file-picker.cjs');
25
25
  const filterButtons = require('./filter-buttons/filter-buttons.cjs');
26
26
  const filterButton = require('./filter-buttons/filter-button.cjs');
27
+ const filteredSearch = require('./filtered-search/filtered-search.cjs');
27
28
  const stringFilter = require('./filtered-search/model/string-filter.cjs');
28
29
  const stringSetFilter = require('./filtered-search/model/string-set-filter.cjs');
29
- const filteredSearch = require('./filtered-search/filtered-search.cjs');
30
30
  const formField = require('./form-field/form-field.cjs');
31
31
  const label = require('./label/label.cjs');
32
32
  const menu = require('./menu/menu.cjs');
@@ -95,9 +95,9 @@ exports.EmptyState = emptyState.EmptyState;
95
95
  exports.FilePicker = filePicker.FilePicker;
96
96
  exports.FilterButtons = filterButtons.FilterButtons;
97
97
  exports.FilterButton = filterButton.FilterButton;
98
+ exports.FilteredSearch = filteredSearch.FilteredSearch;
98
99
  exports.StringFilter = stringFilter.StringFilter;
99
100
  exports.StringSetFilter = stringSetFilter.StringSetFilter;
100
- exports.FilteredSearch = filteredSearch.FilteredSearch;
101
101
  exports.FormField = formField.FormField;
102
102
  exports.Label = label.Label;
103
103
  exports.Menu = menu.Menu;
package/cjs/index.cjs CHANGED
@@ -31,9 +31,9 @@ const emptyState = require('./components/empty-state/empty-state.cjs');
31
31
  const filePicker = require('./components/file-picker/file-picker.cjs');
32
32
  const filterButtons = require('./components/filter-buttons/filter-buttons.cjs');
33
33
  const filterButton = require('./components/filter-buttons/filter-button.cjs');
34
+ const filteredSearch = require('./components/filtered-search/filtered-search.cjs');
34
35
  const stringFilter = require('./components/filtered-search/model/string-filter.cjs');
35
36
  const stringSetFilter = require('./components/filtered-search/model/string-set-filter.cjs');
36
- const filteredSearch = require('./components/filtered-search/filtered-search.cjs');
37
37
  const formField = require('./components/form-field/form-field.cjs');
38
38
  const label = require('./components/label/label.cjs');
39
39
  const menu = require('./components/menu/menu.cjs');
@@ -115,9 +115,9 @@ exports.EmptyState = emptyState.EmptyState;
115
115
  exports.FilePicker = filePicker.FilePicker;
116
116
  exports.FilterButtons = filterButtons.FilterButtons;
117
117
  exports.FilterButton = filterButton.FilterButton;
118
+ exports.FilteredSearch = filteredSearch.FilteredSearch;
118
119
  exports.StringFilter = stringFilter.StringFilter;
119
120
  exports.StringSetFilter = stringSetFilter.StringSetFilter;
120
- exports.FilteredSearch = filteredSearch.FilteredSearch;
121
121
  exports.FormField = formField.FormField;
122
122
  exports.Label = label.Label;
123
123
  exports.Menu = menu.Menu;
@@ -12,14 +12,22 @@ import { KeyboardKeys } from '../../lib/keyboard-keys.js';
12
12
  import { exhaustiveCheck } from '../../lib/helpers.js';
13
13
  import { classNames } from '../../lib/react-helpers.js';
14
14
 
15
- function FilteredSearch({ className, placeholder = 'Search and filter', applyButtonLabel = 'Apply', cancelButtonLabel = 'Cancel', clearButtonAccessibleName = 'Clear', removeFilterButtonAccessibleName = 'Remove filter', filtersConfig, filters, onChange, onMouseDown, ...props }) {
15
+ function FilteredSearch({ filters: appliedFilters, className, placeholder = 'Search and filter', applyButtonLabel = 'Apply', cancelButtonLabel = 'Cancel', clearButtonAccessibleName = 'Clear', removeFilterButtonAccessibleName = 'Remove filter', filtersConfig, onChangeFilters, onMouseDown, ...props }) {
16
16
  const containerRef = useRef(null);
17
+ const [newFilter, setNewFilter] = useState(null);
17
18
  const [query, setQuery] = useState('');
18
19
  const [hasFocus, setHasFocus] = useState(false);
19
20
  const [expanded, setExpanded] = useState(false);
20
21
  const [selectedId, setSelectedId] = useState('');
21
22
  const [activeField, setActiveField] = useState('');
22
23
  const { textBoxId, listBoxId, getOptionId } = useComboboxIds();
24
+ let filters;
25
+ if (newFilter) {
26
+ filters = [...appliedFilters, newFilter];
27
+ }
28
+ else {
29
+ filters = appliedFilters;
30
+ }
23
31
  const filtersConfigMap = useMemo(() => {
24
32
  const map = new Map();
25
33
  for (const config of filtersConfig) {
@@ -34,21 +42,17 @@ function FilteredSearch({ className, placeholder = 'Search and filter', applyBut
34
42
  }
35
43
  return textBox;
36
44
  };
37
- const addFilter = (config) => {
38
- const filter = createFilter(config);
39
- const textBoxElement = getTextBoxElement();
40
- onChange([...filters, filter]);
41
- textBoxElement.blur();
42
- setQuery('');
43
- setActiveField(filter.field);
45
+ const addFilter = (filter) => {
46
+ const newFilters = [...appliedFilters, filter];
47
+ onChangeFilters(newFilters);
44
48
  };
45
- const changeFilter = (changedFilter) => {
46
- const newFilters = filters.map((filter) => (filter.field === changedFilter.field ? changedFilter : filter));
47
- onChange(newFilters);
49
+ const updateFilter = (updatedFilter) => {
50
+ const newFilters = appliedFilters.map((filter) => (filter.field === updatedFilter.field ? updatedFilter : filter));
51
+ onChangeFilters(newFilters);
48
52
  };
49
- const removeFilter = (filterToRemove) => {
50
- const newFilters = filters.filter((filter) => (filter.field !== filterToRemove.field));
51
- onChange(newFilters);
53
+ const removeFilter = (removedFilter) => {
54
+ const newFilters = appliedFilters.filter((filter) => (filter.field !== removedFilter.field));
55
+ onChangeFilters(newFilters);
52
56
  };
53
57
  const onFilterEditStarted = (filter) => {
54
58
  setActiveField(filter.field);
@@ -56,12 +60,23 @@ function FilteredSearch({ className, placeholder = 'Search and filter', applyBut
56
60
  const onFilterEditCanceled = (filter) => {
57
61
  setActiveField('');
58
62
  if (filter.isEmpty()) {
59
- removeFilter(filter);
63
+ if (newFilter && filter.field === newFilter.field) {
64
+ setNewFilter(null);
65
+ }
66
+ else {
67
+ removeFilter(filter);
68
+ }
60
69
  getTextBoxElement().focus();
61
70
  }
62
71
  };
63
72
  const onFilterChanged = (filter) => {
64
- changeFilter(filter);
73
+ if (newFilter && filter.field === newFilter.field) {
74
+ addFilter(filter);
75
+ setNewFilter(null);
76
+ }
77
+ else {
78
+ updateFilter(filter);
79
+ }
65
80
  setActiveField('');
66
81
  };
67
82
  const renderedFilters = [];
@@ -71,6 +86,14 @@ function FilteredSearch({ className, placeholder = 'Search and filter', applyBut
71
86
  fieldsWithAppliedFilters.add(field);
72
87
  renderedFilters.push(jsx(FilterItem, { filter: filter, isEditing: activeField === field, onEditStart: onFilterEditStarted, onEditCancel: onFilterEditCanceled, onChange: onFilterChanged, onRemove: removeFilter }, field));
73
88
  }
89
+ const onOptionSelected = (config) => {
90
+ const filter = createFilter(config);
91
+ const textBoxElement = getTextBoxElement();
92
+ setQuery('');
93
+ setNewFilter(filter);
94
+ setActiveField(filter.field);
95
+ textBoxElement.blur();
96
+ };
74
97
  const onOptionHovered = (event) => {
75
98
  const listItemElement = event.currentTarget;
76
99
  setSelectedId(listItemElement.id);
@@ -81,7 +104,7 @@ function FilteredSearch({ className, placeholder = 'Search and filter', applyBut
81
104
  const listItemElement = event.currentTarget;
82
105
  const config = filtersConfigMap.get(listItemElement.id);
83
106
  if (config) {
84
- addFilter(config);
107
+ onOptionSelected(config);
85
108
  }
86
109
  };
87
110
  const renderedOptions = [];
@@ -125,13 +148,13 @@ function FilteredSearch({ className, placeholder = 'Search and filter', applyBut
125
148
  else if (key === KeyboardKeys.Enter) {
126
149
  const config = filtersConfigMap.get(selectedId);
127
150
  if (config) {
128
- addFilter(config);
151
+ onOptionSelected(config);
129
152
  isHandled = true;
130
153
  }
131
154
  }
132
155
  else if (key === KeyboardKeys.Backspace) {
133
156
  if (query === '' && filters.length > 0) {
134
- onChange(filters.slice(0, -1));
157
+ onChangeFilters(filters.slice(0, -1));
135
158
  isHandled = true;
136
159
  }
137
160
  }
@@ -161,7 +184,7 @@ function FilteredSearch({ className, placeholder = 'Search and filter', applyBut
161
184
  };
162
185
  const onClearButtonPressed = (event) => {
163
186
  event.stopPropagation();
164
- onChange([]);
187
+ onChangeFilters([]);
165
188
  };
166
189
  const onContainerPressed = (event) => {
167
190
  if (event.currentTarget === event.target) {
@@ -22,9 +22,9 @@ export { EmptyState } from './empty-state/empty-state.js';
22
22
  export { FilePicker } from './file-picker/file-picker.js';
23
23
  export { FilterButtons } from './filter-buttons/filter-buttons.js';
24
24
  export { FilterButton } from './filter-buttons/filter-button.js';
25
+ export { FilteredSearch } from './filtered-search/filtered-search.js';
25
26
  export { StringFilter } from './filtered-search/model/string-filter.js';
26
27
  export { StringSetFilter } from './filtered-search/model/string-set-filter.js';
27
- export { FilteredSearch } from './filtered-search/filtered-search.js';
28
28
  export { FormField } from './form-field/form-field.js';
29
29
  export { Label } from './label/label.js';
30
30
  export { Menu } from './menu/menu.js';
package/esm/index.js CHANGED
@@ -29,9 +29,9 @@ export { EmptyState } from './components/empty-state/empty-state.js';
29
29
  export { FilePicker } from './components/file-picker/file-picker.js';
30
30
  export { FilterButtons } from './components/filter-buttons/filter-buttons.js';
31
31
  export { FilterButton } from './components/filter-buttons/filter-button.js';
32
+ export { FilteredSearch } from './components/filtered-search/filtered-search.js';
32
33
  export { StringFilter } from './components/filtered-search/model/string-filter.js';
33
34
  export { StringSetFilter } from './components/filtered-search/model/string-set-filter.js';
34
- export { FilteredSearch } from './components/filtered-search/filtered-search.js';
35
35
  export { FormField } from './components/form-field/form-field.js';
36
36
  export { Label } from './components/label/label.js';
37
37
  export { Menu } from './components/menu/menu.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "draft-components",
3
- "version": "1.7.1",
3
+ "version": "1.9.0",
4
4
  "description": "The React based UI components library.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -29,8 +29,8 @@
29
29
  "coverage": "npm run test -- --coverage --no-cache",
30
30
  "lint": "eslint '**/*.{js,ts,tsx}'",
31
31
  "lint-styles": "stylelint 'src/**/*.css'",
32
- "check-types": "tsc --noEmit",
33
- "prebuild": "npm run test && npm run lint && npm run lint-styles",
32
+ "check-types": "tsc --project 'tsconfig.json' --noEmit",
33
+ "prebuild": "npm run check-types && npm run test && npm run lint && npm run lint-styles",
34
34
  "build": "node scripts/build.js",
35
35
  "build-storybook": "storybook build",
36
36
  "preversion": "npm run build",
@@ -10,6 +10,6 @@ export type FilteredSearchProps = FilteredSearchBaseProps & {
10
10
  removeFilterButtonAccessibleName?: string;
11
11
  filtersConfig: FilterConfig[];
12
12
  filters: Filter[];
13
- onChange: (filters: Filter[]) => void;
13
+ onChangeFilters: (filters: Filter[]) => void;
14
14
  };
15
- export declare function FilteredSearch({ className, placeholder, applyButtonLabel, cancelButtonLabel, clearButtonAccessibleName, removeFilterButtonAccessibleName, filtersConfig, filters, onChange, onMouseDown, ...props }: FilteredSearchProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function FilteredSearch({ filters: appliedFilters, className, placeholder, applyButtonLabel, cancelButtonLabel, clearButtonAccessibleName, removeFilterButtonAccessibleName, filtersConfig, onChangeFilters, onMouseDown, ...props }: FilteredSearchProps): import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,4 @@
1
- export { StringFilter } from './model/string-filter';
2
- export { StringSetFilter } from './model/string-set-filter';
3
1
  export { FilteredSearch, type FilteredSearchProps, type FilteredSearchBaseProps, type FilteredSearchHTMLProps, } from './filtered-search';
4
2
  export { type Filter, type FilterConfig, } from './types';
3
+ export { StringFilter, type StringFilterState, type StringFilterConfig, } from './model/string-filter';
4
+ export { StringSetFilter, type StringSetFilterState, type StringSetFilterConfig, } from './model/string-set-filter';
@@ -1,6 +1,6 @@
1
1
  import { AbstractFilter } from './abstract-filter';
2
2
  import { ValidationResult } from './validation-result';
3
- declare const TYPE = "STRING";
3
+ declare const TYPE: "STRING";
4
4
  declare const OPERATORS: {
5
5
  readonly equal: "EQUAL";
6
6
  readonly notEqual: "NOT_EQUAL";
@@ -25,7 +25,7 @@ export type StringFilterState = {
25
25
  operator: StringFilterOperator;
26
26
  };
27
27
  export declare class StringFilter extends AbstractFilter {
28
- static readonly Type = "STRING";
28
+ static readonly Type: "STRING";
29
29
  static readonly Operators: {
30
30
  readonly equal: "EQUAL";
31
31
  readonly notEqual: "NOT_EQUAL";
@@ -1,5 +1,5 @@
1
1
  import { AbstractFilter } from './abstract-filter';
2
- declare const TYPE = "STRING_SET";
2
+ declare const TYPE: "STRING_SET";
3
3
  declare const OPERATORS: {
4
4
  readonly in: "IN";
5
5
  readonly notIn: "NOT_IN";
@@ -21,7 +21,7 @@ export type StringSetFilterState = {
21
21
  operator: StringSetFilterOperator;
22
22
  };
23
23
  export declare class StringSetFilter extends AbstractFilter {
24
- static readonly Type = "STRING_SET";
24
+ static readonly Type: "STRING_SET";
25
25
  static readonly Operators: {
26
26
  readonly in: "IN";
27
27
  readonly notIn: "NOT_IN";