@navikt/ds-react 8.5.1 → 8.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 (102) hide show
  1. package/cjs/data/table/root/DataTableRoot.d.ts +27 -0
  2. package/cjs/data/table/root/DataTableRoot.js +8 -2
  3. package/cjs/data/table/root/DataTableRoot.js.map +1 -1
  4. package/cjs/data/table/td/DataTableTd.d.ts +5 -4
  5. package/cjs/data/table/td/DataTableTd.js +2 -2
  6. package/cjs/data/table/td/DataTableTd.js.map +1 -1
  7. package/cjs/data/token-filter/AutoSuggest.d.ts +2 -14
  8. package/cjs/data/token-filter/AutoSuggest.js +13 -89
  9. package/cjs/data/token-filter/AutoSuggest.js.map +1 -1
  10. package/cjs/data/token-filter/AutoSuggest.types.d.ts +11 -0
  11. package/cjs/data/token-filter/AutoSuggest.types.js +3 -0
  12. package/cjs/data/token-filter/AutoSuggest.types.js.map +1 -0
  13. package/cjs/data/token-filter/TokenFilter.d.ts +5 -0
  14. package/cjs/data/token-filter/TokenFilter.js +20 -10
  15. package/cjs/data/token-filter/TokenFilter.js.map +1 -1
  16. package/cjs/data/token-filter/TokenFilter.types.d.ts +8 -4
  17. package/cjs/data/token-filter/helpers/generate-autocomplete-options.d.ts +13 -61
  18. package/cjs/data/token-filter/helpers/generate-autocomplete-options.js +152 -135
  19. package/cjs/data/token-filter/helpers/generate-autocomplete-options.js.map +1 -1
  20. package/cjs/data/token-filter/helpers/grouping.d.ts +28 -0
  21. package/cjs/data/token-filter/helpers/grouping.js +61 -0
  22. package/cjs/data/token-filter/helpers/grouping.js.map +1 -0
  23. package/cjs/data/token-filter/helpers/operators.d.ts +22 -0
  24. package/cjs/data/token-filter/helpers/operators.js +66 -0
  25. package/cjs/data/token-filter/helpers/operators.js.map +1 -0
  26. package/cjs/data/token-filter/helpers/parse-query-text.d.ts +1 -7
  27. package/cjs/data/token-filter/helpers/parse-query-text.js +5 -50
  28. package/cjs/data/token-filter/helpers/parse-query-text.js.map +1 -1
  29. package/cjs/data/token-filter/helpers/query-builder.d.ts +20 -0
  30. package/cjs/data/token-filter/helpers/query-builder.js +38 -0
  31. package/cjs/data/token-filter/helpers/query-builder.js.map +1 -0
  32. package/cjs/data/token-filter/helpers/text-matching.d.ts +16 -0
  33. package/cjs/data/token-filter/helpers/text-matching.js +47 -0
  34. package/cjs/data/token-filter/helpers/text-matching.js.map +1 -0
  35. package/cjs/form/combobox/Input/InputController.js +1 -1
  36. package/cjs/form/combobox/Input/InputController.js.map +1 -1
  37. package/cjs/form/file-upload/dropzone/FileUploadDropzone.js +1 -1
  38. package/cjs/form/file-upload/dropzone/FileUploadDropzone.js.map +1 -1
  39. package/cjs/toggle-group/useToggleGroup.js +5 -3
  40. package/cjs/toggle-group/useToggleGroup.js.map +1 -1
  41. package/esm/data/table/root/DataTableRoot.d.ts +27 -0
  42. package/esm/data/table/root/DataTableRoot.js +8 -2
  43. package/esm/data/table/root/DataTableRoot.js.map +1 -1
  44. package/esm/data/table/td/DataTableTd.d.ts +5 -4
  45. package/esm/data/table/td/DataTableTd.js +2 -2
  46. package/esm/data/table/td/DataTableTd.js.map +1 -1
  47. package/esm/data/token-filter/AutoSuggest.d.ts +2 -14
  48. package/esm/data/token-filter/AutoSuggest.js +14 -90
  49. package/esm/data/token-filter/AutoSuggest.js.map +1 -1
  50. package/esm/data/token-filter/AutoSuggest.types.d.ts +11 -0
  51. package/esm/data/token-filter/AutoSuggest.types.js +2 -0
  52. package/esm/data/token-filter/AutoSuggest.types.js.map +1 -0
  53. package/esm/data/token-filter/TokenFilter.d.ts +5 -0
  54. package/esm/data/token-filter/TokenFilter.js +20 -10
  55. package/esm/data/token-filter/TokenFilter.js.map +1 -1
  56. package/esm/data/token-filter/TokenFilter.types.d.ts +8 -4
  57. package/esm/data/token-filter/helpers/generate-autocomplete-options.d.ts +13 -61
  58. package/esm/data/token-filter/helpers/generate-autocomplete-options.js +152 -135
  59. package/esm/data/token-filter/helpers/generate-autocomplete-options.js.map +1 -1
  60. package/esm/data/token-filter/helpers/grouping.d.ts +28 -0
  61. package/esm/data/token-filter/helpers/grouping.js +59 -0
  62. package/esm/data/token-filter/helpers/grouping.js.map +1 -0
  63. package/esm/data/token-filter/helpers/operators.d.ts +22 -0
  64. package/esm/data/token-filter/helpers/operators.js +60 -0
  65. package/esm/data/token-filter/helpers/operators.js.map +1 -0
  66. package/esm/data/token-filter/helpers/parse-query-text.d.ts +1 -7
  67. package/esm/data/token-filter/helpers/parse-query-text.js +2 -45
  68. package/esm/data/token-filter/helpers/parse-query-text.js.map +1 -1
  69. package/esm/data/token-filter/helpers/query-builder.d.ts +20 -0
  70. package/esm/data/token-filter/helpers/query-builder.js +34 -0
  71. package/esm/data/token-filter/helpers/query-builder.js.map +1 -0
  72. package/esm/data/token-filter/helpers/text-matching.d.ts +16 -0
  73. package/esm/data/token-filter/helpers/text-matching.js +45 -0
  74. package/esm/data/token-filter/helpers/text-matching.js.map +1 -0
  75. package/esm/form/combobox/Input/InputController.js +1 -1
  76. package/esm/form/combobox/Input/InputController.js.map +1 -1
  77. package/esm/form/file-upload/dropzone/FileUploadDropzone.js +1 -1
  78. package/esm/form/file-upload/dropzone/FileUploadDropzone.js.map +1 -1
  79. package/esm/toggle-group/useToggleGroup.js +6 -4
  80. package/esm/toggle-group/useToggleGroup.js.map +1 -1
  81. package/package.json +3 -3
  82. package/src/data/table/root/DataTableRoot.tsx +30 -1
  83. package/src/data/table/td/DataTableTd.tsx +13 -6
  84. package/src/data/token-filter/AutoSuggest.tsx +33 -163
  85. package/src/data/token-filter/AutoSuggest.types.ts +13 -0
  86. package/src/data/token-filter/TokenFilter.tsx +21 -13
  87. package/src/data/token-filter/TokenFilter.types.ts +8 -4
  88. package/src/data/token-filter/helpers/generate-autocomplete-options.test.ts +836 -0
  89. package/src/data/token-filter/helpers/generate-autocomplete-options.ts +241 -186
  90. package/src/data/token-filter/helpers/grouping.test.ts +206 -0
  91. package/src/data/token-filter/helpers/grouping.ts +73 -0
  92. package/src/data/token-filter/helpers/operators.test.ts +281 -0
  93. package/src/data/token-filter/helpers/operators.ts +91 -0
  94. package/src/data/token-filter/helpers/parse-query-text.test.ts +4 -213
  95. package/src/data/token-filter/helpers/parse-query-text.ts +7 -69
  96. package/src/data/token-filter/helpers/query-builder.test.ts +126 -0
  97. package/src/data/token-filter/helpers/query-builder.ts +41 -0
  98. package/src/data/token-filter/helpers/text-matching.test.ts +125 -0
  99. package/src/data/token-filter/helpers/text-matching.ts +58 -0
  100. package/src/form/combobox/Input/InputController.tsx +0 -1
  101. package/src/form/file-upload/dropzone/FileUploadDropzone.tsx +0 -1
  102. package/src/toggle-group/useToggleGroup.ts +6 -5
@@ -1,179 +1,49 @@
1
- import React, { forwardRef, useMemo } from "react";
2
- import { cl } from "../../utils/helpers";
3
- import type {
4
- QueryFilteringOption,
5
- QueryFilteringOptionGroup,
6
- } from "./TokenFilter.types";
7
-
8
- interface AutoSuggestOption {
9
- value: string;
10
- label: string;
11
- tags?: string[];
12
- filteringTags?: string[];
13
- description?: string;
14
- }
15
-
16
- interface AutoSuggestGroup {
17
- label: string;
18
- options: AutoSuggestOption[];
19
- }
1
+ import React, { forwardRef } from "react";
2
+ import { Box } from "../../primitives/box";
3
+ import { VStack } from "../../primitives/stack";
4
+ import { Label } from "../../typography";
5
+ import type { AutoCompleteOption, OptionGroup } from "./AutoSuggest.types";
20
6
 
21
7
  interface AutoSuggestProps {
22
- options: AutoSuggestGroup[];
23
- value: string;
24
- filterText: string;
8
+ options: OptionGroup<AutoCompleteOption>[];
25
9
  onSelect: (value: string) => void;
26
10
  className?: string;
27
11
  }
28
12
 
29
13
  const AutoSuggest = forwardRef<HTMLDivElement, AutoSuggestProps>(
30
- ({ options, value, filterText, onSelect, className }, ref) => {
31
- console.info({ options, value, filterText });
32
- /* const highlightedText = filterText === undefined ? value : filterText; */
33
- /* const filterValue = (value || "").toLowerCase();
34
-
35
- const filteredGroups = options
36
- .map((group) => ({
37
- ...group,
38
- options: group.options.filter((option) => {
39
- const searchableText = [
40
- option.label,
41
- option.description,
42
- ...(option.filteringTags ?? []),
43
- ...(option.tags ?? []),
44
- ]
45
- .filter(Boolean)
46
- .join(" ")
47
- .toLowerCase();
48
- return searchableText.includes(filterValue);
49
- }),
50
- }))
51
- .filter((group) => group.options.length > 0); */
52
-
53
- const { items } = useAutosuggestItems({ options, filterValue: filterText });
54
-
55
- console.info({ items });
56
-
14
+ ({ options, onSelect }, ref) => {
57
15
  return (
58
- <div ref={ref} className={cl("aksel-auto-suggest", className)}>
16
+ <Box ref={ref} padding="space-6">
59
17
  {options.map((group) => (
60
- <div key={group.label} className="aksel-auto-suggest__group">
61
- <div className="aksel-auto-suggest__group-label">{group.label}</div>
62
- <ul className="aksel-auto-suggest__list">
63
- {group.options.map((option) => (
64
- <li key={option.value} className="aksel-auto-suggest__item">
65
- <button
66
- type="button"
67
- className="aksel-auto-suggest__button"
68
- onClick={() => onSelect(option.value)}
69
- >
70
- <span className="aksel-auto-suggest__label">
71
- {option.label}
72
- </span>
73
- {option.description && (
74
- <span className="aksel-auto-suggest__description">
75
- {option.description}
76
- </span>
77
- )}
78
- {option.tags && option.tags.length > 0 && (
79
- <div className="aksel-auto-suggest__tags">
80
- {option.tags.map((tag) => (
81
- <span key={tag} className="aksel-auto-suggest__tag">
82
- {tag}
83
- </span>
84
- ))}
85
- </div>
86
- )}
87
- </button>
88
- </li>
89
- ))}
90
- </ul>
18
+ <div key={group.label}>
19
+ <Label as="div">{group.label}</Label>
20
+ <VStack gap="space-4">
21
+ {group.options.map((option) => {
22
+ return (
23
+ <div key={option.value}>
24
+ <button
25
+ type="button"
26
+ onClick={() => onSelect(option.value)}
27
+ >
28
+ <span>{option.label}</span>
29
+ {option.description && <span>{option.description}</span>}
30
+ {option.tags && option.tags.length > 0 && (
31
+ <div>
32
+ {option.tags.map((tag) => (
33
+ <span key={tag}>{tag}</span>
34
+ ))}
35
+ </div>
36
+ )}
37
+ </button>
38
+ </div>
39
+ );
40
+ })}
41
+ </VStack>
91
42
  </div>
92
43
  ))}
93
- </div>
44
+ </Box>
94
45
  );
95
46
  },
96
47
  );
97
48
 
98
- function useAutosuggestItems({ options, filterValue }) {
99
- const { items } = useMemo(() => createItems(options), [options]);
100
-
101
- const filteredItems = useMemo(() => {
102
- const localFilteredItems = items;
103
- if (filterValue) {
104
- localFilteredItems.unshift({
105
- value: filterValue,
106
- type: "use-entered",
107
- label: `Use "${filterValue}"`,
108
- option: { value: filterValue },
109
- });
110
- }
111
- return localFilteredItems;
112
- }, [items, filterValue]);
113
-
114
- return { items: filteredItems };
115
- }
116
-
117
- /* TODO: Need to split autosuggest types and filter types */
118
- type AutoSuggestItem = {
119
- type?: "parent" | "child" | "use-entered";
120
- option: QueryFilteringOption | QueryFilteringOptionGroup | { value: string };
121
- parent?: QueryFilteringOptionGroup;
122
- disabled?: boolean;
123
- value?: string;
124
- label?: string;
125
- };
126
-
127
- function createItems(
128
- options: (QueryFilteringOption | QueryFilteringOptionGroup)[],
129
- ) {
130
- const items: AutoSuggestItem[] = [];
131
- const itemToGroup = new WeakMap<AutoSuggestItem, AutoSuggestItem>();
132
-
133
- for (const option of options) {
134
- if (isGroup(option)) {
135
- for (const item of flattenGroup(option, itemToGroup)) {
136
- items.push(item);
137
- }
138
- } else {
139
- items.push({ ...option, option });
140
- }
141
- }
142
-
143
- return { items };
144
- }
145
-
146
- function flattenGroup(
147
- group: QueryFilteringOptionGroup,
148
- map: WeakMap<AutoSuggestItem, AutoSuggestItem>,
149
- ) {
150
- const { options, ...rest } = group;
151
-
152
- const groupItem: AutoSuggestItem = { ...rest, type: "parent", option: group };
153
-
154
- const items: AutoSuggestItem[] = [groupItem];
155
-
156
- for (const option of options) {
157
- const childOption: AutoSuggestItem = {
158
- ...option,
159
- type: "child",
160
- disabled: option.disabled ?? false,
161
- option,
162
- parent: group,
163
- };
164
-
165
- items.push(childOption);
166
-
167
- map.set(childOption, groupItem);
168
- }
169
-
170
- return items;
171
- }
172
-
173
- function isGroup(
174
- optionOrGroup: QueryFilteringOption | QueryFilteringOptionGroup,
175
- ): optionOrGroup is QueryFilteringOptionGroup {
176
- return "options" in optionOrGroup;
177
- }
178
-
179
49
  export { AutoSuggest };
@@ -0,0 +1,13 @@
1
+ interface OptionGroup<T> {
2
+ label: string;
3
+ options: T[];
4
+ }
5
+
6
+ interface AutoCompleteOption {
7
+ value: string;
8
+ label: string;
9
+ tags?: string[];
10
+ description?: string;
11
+ }
12
+
13
+ export type { AutoCompleteOption, OptionGroup };
@@ -1,6 +1,7 @@
1
1
  import React, { forwardRef, useState } from "react";
2
2
  import { Popover } from "../../popover";
3
3
  import { cl } from "../../utils/helpers";
4
+ import { AutoSuggest } from "./AutoSuggest";
4
5
  import type {
5
6
  ParsedOption,
6
7
  ParsedProperty,
@@ -19,6 +20,11 @@ type TokenFilterProps = {
19
20
  filteringProperties: QueryFilteringProperties;
20
21
  };
21
22
 
23
+ /**
24
+ * TODO:
25
+ * - Implement onChange handler to update query state when user selects an autocomplete option.
26
+ * - Handle token rendering and editing (e.g., show tokens for matched properties/operators/values, allow deleting tokens).
27
+ */
22
28
  export const TokenFilter = forwardRef<HTMLDivElement, TokenFilterProps>(
23
29
  ({ query, className, filteringProperties, filteringOptions }, ref) => {
24
30
  const [inputAnchor, setInputAnchor] = useState<HTMLInputElement | null>(
@@ -39,9 +45,12 @@ export const TokenFilter = forwardRef<HTMLDivElement, TokenFilterProps>(
39
45
  options,
40
46
  );
41
47
 
42
- /* const handleSelectOption = (value: string) => {
48
+ const handleSelectOption = (value: string) => {
43
49
  setFilterText(value);
44
- }; */
50
+ setCustomOpen(false);
51
+ };
52
+
53
+ const [customOpen, setCustomOpen] = useState(false);
45
54
 
46
55
  return (
47
56
  <div
@@ -56,20 +65,20 @@ export const TokenFilter = forwardRef<HTMLDivElement, TokenFilterProps>(
56
65
  ref={setInputAnchor}
57
66
  value={filterText}
58
67
  onChange={(e) => setFilterText(e.target.value)}
68
+ onFocus={() => setCustomOpen(true)}
59
69
  />
60
70
  <Popover
61
71
  anchorEl={inputAnchor}
62
- open={filterText.length > 0}
63
- onClose={() => setFilterText("")}
72
+ open={customOpen}
73
+ onClose={() => {
74
+ setFilterText("");
75
+ setCustomOpen(false);
76
+ }}
64
77
  >
65
- a
66
- {/* <AutoSuggest
67
-
78
+ <AutoSuggest
68
79
  options={autoCompleteOptions.options}
69
- value={filterText}
70
- filterText={autoCompleteOptions.value}
71
80
  onSelect={handleSelectOption}
72
- /> */}
81
+ />
73
82
  </Popover>
74
83
  {query.tokens.map((token, index) => {
75
84
  return (
@@ -83,7 +92,7 @@ export const TokenFilter = forwardRef<HTMLDivElement, TokenFilterProps>(
83
92
  <li key={prop.key}>{prop.propertyLabel}</li>
84
93
  ))}
85
94
  </ul>
86
- <pre>{JSON.stringify(queryState, null, 2)}</pre>
95
+ {/* <pre>{JSON.stringify(queryState, null, 2)}</pre> */}
87
96
  <pre>{JSON.stringify(autoCompleteOptions, null, 2)}</pre>
88
97
  </div>
89
98
  );
@@ -106,7 +115,7 @@ function derrivedFilterState(
106
115
  propertyLabel: property?.propertyLabel ?? "",
107
116
  groupValuesLabel: property?.groupValuesLabel ?? "",
108
117
  propertyGroup: property?.group,
109
- /* operators: (property?.operators ?? []).map(op => (typeof op === 'string' ? op : op.operator)), */
118
+ operators: property?.operators ?? [],
110
119
  /* defaultOperator: property?.defaultOperator ?? '=', */
111
120
  externalProperty: property,
112
121
  });
@@ -117,7 +126,6 @@ function derrivedFilterState(
117
126
  value: option.value,
118
127
  label: option.label ?? option.value ?? "",
119
128
  tags: option.tags ?? [],
120
- filteringTags: option.filteringTags ?? [],
121
129
  }));
122
130
 
123
131
  return { properties: [...propertyMap.values()], options: internalOptions };
@@ -29,7 +29,6 @@ type QueryFilteringOption = {
29
29
  value: any;
30
30
  label?: string;
31
31
  tags?: string[];
32
- filteringTags?: string[];
33
32
  disabled?: boolean;
34
33
  };
35
34
 
@@ -40,11 +39,16 @@ type QueryFilteringOptionGroup = {
40
39
  options: QueryFilteringOptions;
41
40
  };
42
41
 
42
+ type QueryFilteringScopedOperator =
43
+ | string
44
+ | { operator: string; tokenType: "single" | "multiple" };
45
+
43
46
  type QueryFilteringProperty = {
44
47
  key: string;
45
48
  propertyLabel: string;
46
- groupValuesLabel: string;
47
- group: string;
49
+ groupValuesLabel?: string;
50
+ group?: string;
51
+ operators?: QueryFilteringScopedOperator[];
48
52
  };
49
53
 
50
54
  type QueryFilteringProperties = QueryFilteringProperty[];
@@ -54,6 +58,7 @@ type ParsedProperty = {
54
58
  propertyLabel: string;
55
59
  groupValuesLabel: string;
56
60
  propertyGroup: string;
61
+ operators: QueryFilteringScopedOperator[];
57
62
  externalProperty: QueryFilteringProperty;
58
63
  };
59
64
 
@@ -62,7 +67,6 @@ type ParsedOption = {
62
67
  value: any;
63
68
  label: string;
64
69
  tags: string[];
65
- filteringTags: string[];
66
70
  };
67
71
 
68
72
  export type {