@navikt/ds-react 8.4.1 → 8.5.1
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.
- package/cjs/accordion/Accordion.d.ts +10 -0
- package/cjs/accordion/Accordion.js +2 -2
- package/cjs/accordion/Accordion.js.map +1 -1
- package/cjs/data/table/helpers/table-cell.d.ts +2 -2
- package/cjs/data/table/helpers/table-cell.js +2 -5
- package/cjs/data/table/helpers/table-cell.js.map +1 -1
- package/cjs/data/table/helpers/table-focus.d.ts +26 -2
- package/cjs/data/table/helpers/table-focus.js +60 -9
- package/cjs/data/table/helpers/table-focus.js.map +1 -1
- package/cjs/data/table/helpers/table-grid-nav.d.ts +40 -10
- package/cjs/data/table/helpers/table-grid-nav.js +102 -25
- package/cjs/data/table/helpers/table-grid-nav.js.map +1 -1
- package/cjs/data/table/helpers/table-keyboard.d.ts +24 -3
- package/cjs/data/table/helpers/table-keyboard.js +25 -5
- package/cjs/data/table/helpers/table-keyboard.js.map +1 -1
- package/cjs/data/table/hooks/useGridCache.d.ts +17 -0
- package/cjs/data/table/hooks/useGridCache.js +65 -0
- package/cjs/data/table/hooks/useGridCache.js.map +1 -0
- package/cjs/data/table/root/DataTableRoot.d.ts +14 -4
- package/cjs/data/table/root/DataTableRoot.js +4 -6
- package/cjs/data/table/root/DataTableRoot.js.map +1 -1
- package/cjs/data/table/root/useTableKeyboardNav.d.ts +10 -4
- package/cjs/data/table/root/useTableKeyboardNav.js +70 -99
- package/cjs/data/table/root/useTableKeyboardNav.js.map +1 -1
- package/cjs/data/token-filter/AutoSuggest.d.ts +21 -0
- package/cjs/data/token-filter/AutoSuggest.js +129 -0
- package/cjs/data/token-filter/AutoSuggest.js.map +1 -0
- package/cjs/data/token-filter/TokenFilter.d.ts +11 -0
- package/cjs/data/token-filter/TokenFilter.js +91 -0
- package/cjs/data/token-filter/TokenFilter.js.map +1 -0
- package/cjs/data/token-filter/TokenFilter.types.d.ts +46 -0
- package/cjs/data/token-filter/TokenFilter.types.js +3 -0
- package/cjs/data/token-filter/TokenFilter.types.js.map +1 -0
- package/cjs/data/token-filter/helpers/generate-autocomplete-options.d.ts +70 -0
- package/cjs/data/token-filter/helpers/generate-autocomplete-options.js +171 -0
- package/cjs/data/token-filter/helpers/generate-autocomplete-options.js.map +1 -0
- package/cjs/data/token-filter/helpers/parse-query-text.d.ts +31 -0
- package/cjs/data/token-filter/helpers/parse-query-text.js +91 -0
- package/cjs/data/token-filter/helpers/parse-query-text.js.map +1 -0
- package/cjs/link-card/LinkCard.d.ts +13 -0
- package/cjs/link-card/LinkCard.js +2 -2
- package/cjs/link-card/LinkCard.js.map +1 -1
- package/cjs/process/Process.d.ts +1 -1
- package/cjs/tooltip/Tooltip.js +1 -1
- package/cjs/tooltip/Tooltip.js.map +1 -1
- package/esm/accordion/Accordion.d.ts +10 -0
- package/esm/accordion/Accordion.js +2 -2
- package/esm/accordion/Accordion.js.map +1 -1
- package/esm/data/table/helpers/table-cell.d.ts +2 -2
- package/esm/data/table/helpers/table-cell.js +2 -5
- package/esm/data/table/helpers/table-cell.js.map +1 -1
- package/esm/data/table/helpers/table-focus.d.ts +26 -2
- package/esm/data/table/helpers/table-focus.js +55 -9
- package/esm/data/table/helpers/table-focus.js.map +1 -1
- package/esm/data/table/helpers/table-grid-nav.d.ts +40 -10
- package/esm/data/table/helpers/table-grid-nav.js +96 -24
- package/esm/data/table/helpers/table-grid-nav.js.map +1 -1
- package/esm/data/table/helpers/table-keyboard.d.ts +24 -3
- package/esm/data/table/helpers/table-keyboard.js +24 -4
- package/esm/data/table/helpers/table-keyboard.js.map +1 -1
- package/esm/data/table/hooks/useGridCache.d.ts +17 -0
- package/esm/data/table/hooks/useGridCache.js +63 -0
- package/esm/data/table/hooks/useGridCache.js.map +1 -0
- package/esm/data/table/root/DataTableRoot.d.ts +14 -4
- package/esm/data/table/root/DataTableRoot.js +4 -6
- package/esm/data/table/root/DataTableRoot.js.map +1 -1
- package/esm/data/table/root/useTableKeyboardNav.d.ts +10 -4
- package/esm/data/table/root/useTableKeyboardNav.js +75 -104
- package/esm/data/table/root/useTableKeyboardNav.js.map +1 -1
- package/esm/data/token-filter/AutoSuggest.d.ts +21 -0
- package/esm/data/token-filter/AutoSuggest.js +93 -0
- package/esm/data/token-filter/AutoSuggest.js.map +1 -0
- package/esm/data/token-filter/TokenFilter.d.ts +11 -0
- package/esm/data/token-filter/TokenFilter.js +55 -0
- package/esm/data/token-filter/TokenFilter.js.map +1 -0
- package/esm/data/token-filter/TokenFilter.types.d.ts +46 -0
- package/esm/data/token-filter/TokenFilter.types.js +2 -0
- package/esm/data/token-filter/TokenFilter.types.js.map +1 -0
- package/esm/data/token-filter/helpers/generate-autocomplete-options.d.ts +70 -0
- package/esm/data/token-filter/helpers/generate-autocomplete-options.js +169 -0
- package/esm/data/token-filter/helpers/generate-autocomplete-options.js.map +1 -0
- package/esm/data/token-filter/helpers/parse-query-text.d.ts +31 -0
- package/esm/data/token-filter/helpers/parse-query-text.js +87 -0
- package/esm/data/token-filter/helpers/parse-query-text.js.map +1 -0
- package/esm/link-card/LinkCard.d.ts +13 -0
- package/esm/link-card/LinkCard.js +2 -2
- package/esm/link-card/LinkCard.js.map +1 -1
- package/esm/process/Process.d.ts +1 -1
- package/esm/tooltip/Tooltip.js +2 -2
- package/esm/tooltip/Tooltip.js.map +1 -1
- package/package.json +3 -3
- package/src/accordion/Accordion.tsx +19 -2
- package/src/data/table/helpers/table-cell.ts +2 -7
- package/src/data/table/helpers/table-focus.ts +70 -9
- package/src/data/table/helpers/table-grid-nav.test.ts +659 -0
- package/src/data/table/helpers/table-grid-nav.ts +128 -32
- package/src/data/table/helpers/table-keyboard.test.ts +27 -27
- package/src/data/table/helpers/table-keyboard.ts +34 -4
- package/src/data/table/hooks/useGridCache.ts +73 -0
- package/src/data/table/root/DataTableRoot.tsx +21 -11
- package/src/data/table/root/useTableKeyboardNav.ts +110 -128
- package/src/data/token-filter/AutoSuggest.tsx +179 -0
- package/src/data/token-filter/TokenFilter.tsx +124 -0
- package/src/data/token-filter/TokenFilter.types.ts +79 -0
- package/src/data/token-filter/helpers/generate-autocomplete-options.ts +244 -0
- package/src/data/token-filter/helpers/parse-query-text.test.ts +410 -0
- package/src/data/token-filter/helpers/parse-query-text.ts +148 -0
- package/src/link-card/LinkCard.tsx +15 -1
- package/src/process/Process.tsx +1 -1
- package/src/tooltip/Tooltip.tsx +3 -3
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { ParsedProperty, QueryFilterOperator } from "../TokenFilter.types";
|
|
2
|
+
|
|
3
|
+
type ParsedText =
|
|
4
|
+
| {
|
|
5
|
+
/** User has typed property + complete operator + value (e.g., "Status != active") */
|
|
6
|
+
step: "property";
|
|
7
|
+
property: ParsedProperty;
|
|
8
|
+
operator: QueryFilterOperator;
|
|
9
|
+
value: string;
|
|
10
|
+
}
|
|
11
|
+
| {
|
|
12
|
+
/** User is typing the operator after property (e.g., "Status !") */
|
|
13
|
+
step: "operator";
|
|
14
|
+
property: ParsedProperty;
|
|
15
|
+
operatorPrefix: string;
|
|
16
|
+
}
|
|
17
|
+
| {
|
|
18
|
+
/** No property match; treat as free-text search */
|
|
19
|
+
step: "free-text";
|
|
20
|
+
value: string;
|
|
21
|
+
operator?: QueryFilterOperator;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parse user input text to extract property, operator, and value components.
|
|
26
|
+
* Handles partial input (e.g., user typing "Status !" to complete the operator).
|
|
27
|
+
*/
|
|
28
|
+
function parseQueryText(
|
|
29
|
+
filteringText: string,
|
|
30
|
+
filteringProperties: ParsedProperty[],
|
|
31
|
+
): ParsedText {
|
|
32
|
+
const property = matchFilteringProperty(filteringProperties, filteringText);
|
|
33
|
+
if (!property) {
|
|
34
|
+
const freeTextOperator = matchOperator(QUERY_OPERATORS, filteringText);
|
|
35
|
+
if (freeTextOperator) {
|
|
36
|
+
return {
|
|
37
|
+
step: "free-text",
|
|
38
|
+
operator: freeTextOperator,
|
|
39
|
+
value: filteringText.substring(freeTextOperator.length).trimStart(),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
step: "free-text",
|
|
45
|
+
value: filteringText,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const textWithoutProperty = filteringText
|
|
50
|
+
.substring(property.propertyLabel.length)
|
|
51
|
+
.trimStart();
|
|
52
|
+
|
|
53
|
+
const operator = matchOperator(QUERY_OPERATORS, textWithoutProperty);
|
|
54
|
+
|
|
55
|
+
if (operator) {
|
|
56
|
+
return {
|
|
57
|
+
step: "property",
|
|
58
|
+
property,
|
|
59
|
+
operator,
|
|
60
|
+
value: textWithoutProperty.substring(operator.length).trimStart(),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const operatorPrefix = matchOperatorPrefix(
|
|
65
|
+
QUERY_OPERATORS,
|
|
66
|
+
textWithoutProperty,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (operatorPrefix !== null) {
|
|
70
|
+
return { step: "operator", property, operatorPrefix };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
step: "free-text",
|
|
75
|
+
value: filteringText,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Operators ordered by specificity (longest/most specific first)
|
|
81
|
+
* This ensures longer operators like ">=" and "<=" are matched
|
|
82
|
+
* before shorter ones like ">" and "<"
|
|
83
|
+
*/
|
|
84
|
+
const QUERY_OPERATORS: QueryFilterOperator[] = [
|
|
85
|
+
">=",
|
|
86
|
+
"<=",
|
|
87
|
+
"!=",
|
|
88
|
+
"!:",
|
|
89
|
+
"!^",
|
|
90
|
+
"=",
|
|
91
|
+
":",
|
|
92
|
+
"^",
|
|
93
|
+
">",
|
|
94
|
+
"<",
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Match a property from the input text by longest property label.
|
|
99
|
+
* Case-insensitive matching.
|
|
100
|
+
*/
|
|
101
|
+
function matchFilteringProperty(
|
|
102
|
+
filteringProperties: ParsedProperty[],
|
|
103
|
+
text: string,
|
|
104
|
+
): ParsedProperty | undefined {
|
|
105
|
+
const sortedProperties = [...filteringProperties].sort(
|
|
106
|
+
(a, b) => b.propertyLabel.length - a.propertyLabel.length,
|
|
107
|
+
);
|
|
108
|
+
return sortedProperties.find((prop) =>
|
|
109
|
+
text.toLowerCase().startsWith(prop.propertyLabel.toLowerCase()),
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Check if the input text is a valid prefix of any allowed operator.
|
|
115
|
+
* Returns the prefix if valid, null otherwise.
|
|
116
|
+
*/
|
|
117
|
+
function matchOperatorPrefix(
|
|
118
|
+
allowedOperators: QueryFilterOperator[],
|
|
119
|
+
filteringText: string,
|
|
120
|
+
): string | null {
|
|
121
|
+
const trimmedText = filteringText.trim();
|
|
122
|
+
|
|
123
|
+
if (trimmedText.length === 0) {
|
|
124
|
+
return "";
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const isValidPrefix = allowedOperators.some((operator) =>
|
|
128
|
+
operator.toLowerCase().startsWith(trimmedText.toLowerCase()),
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
return isValidPrefix ? trimmedText : null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Match an operator from the input text.
|
|
136
|
+
* Operators are already sorted by specificity, so no re-sorting needed.
|
|
137
|
+
*/
|
|
138
|
+
function matchOperator(
|
|
139
|
+
allowedOperators: QueryFilterOperator[],
|
|
140
|
+
text: string,
|
|
141
|
+
): QueryFilterOperator | undefined {
|
|
142
|
+
return allowedOperators.find((operator) =>
|
|
143
|
+
text.toLowerCase().startsWith(operator.toLowerCase()),
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export { QUERY_OPERATORS, parseQueryText };
|
|
148
|
+
export type { ParsedText };
|
|
@@ -33,6 +33,19 @@ interface LinkCardProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
33
33
|
* @see [📝 Documentation](https://aksel.nav.no/grunnleggende/styling/farger-tokens)
|
|
34
34
|
*/
|
|
35
35
|
"data-color"?: AkselColor;
|
|
36
|
+
/**
|
|
37
|
+
* Changes the HTML element used for the root element.
|
|
38
|
+
*
|
|
39
|
+
* **When using `section`, provide either `aria-label` or `aria-labelledby` for better accessibility.**
|
|
40
|
+
* `axe-core` might warn about unique landmarks if you have multiple Accordions on page with the same label.
|
|
41
|
+
* In those cases consider updating to unique `aria-label` or `aria-labelledby` props.
|
|
42
|
+
* @see [📝 Landmarks unique](https://dequeuniversity.com/rules/axe/4.6/landmark-unique)
|
|
43
|
+
*
|
|
44
|
+
*
|
|
45
|
+
* **When using `article`, make sure `<LinkCard.Title />` is a heading and not a `span`.**
|
|
46
|
+
* @default "div"
|
|
47
|
+
*/
|
|
48
|
+
as?: "div" | "section" | "article";
|
|
36
49
|
}
|
|
37
50
|
|
|
38
51
|
type LinkCardContextProps = {
|
|
@@ -106,6 +119,7 @@ export const LinkCard = forwardRef<HTMLDivElement, LinkCardProps>(
|
|
|
106
119
|
arrow = true,
|
|
107
120
|
arrowPosition = "baseline",
|
|
108
121
|
size = "medium",
|
|
122
|
+
as: Component = "div",
|
|
109
123
|
...restProps
|
|
110
124
|
}: LinkCardProps,
|
|
111
125
|
forwardedRef,
|
|
@@ -114,7 +128,7 @@ export const LinkCard = forwardRef<HTMLDivElement, LinkCardProps>(
|
|
|
114
128
|
<LinkCardContextProvider size={size}>
|
|
115
129
|
<LinkAnchorOverlay asChild>
|
|
116
130
|
<BodyLong
|
|
117
|
-
as=
|
|
131
|
+
as={Component}
|
|
118
132
|
size={size}
|
|
119
133
|
ref={forwardedRef}
|
|
120
134
|
data-color="neutral"
|
package/src/process/Process.tsx
CHANGED
|
@@ -15,7 +15,7 @@ interface ProcessProps extends React.HTMLAttributes<HTMLOListElement> {
|
|
|
15
15
|
/**
|
|
16
16
|
* `<Process.Event />` elements.
|
|
17
17
|
*/
|
|
18
|
-
children: React.
|
|
18
|
+
children: React.ReactNode;
|
|
19
19
|
/**
|
|
20
20
|
* Hides the "aktiv"-text when the event is active.
|
|
21
21
|
* @default false
|
package/src/tooltip/Tooltip.tsx
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
useHover,
|
|
12
12
|
useInteractions,
|
|
13
13
|
} from "@floating-ui/react";
|
|
14
|
-
import React, { HTMLAttributes, forwardRef, useRef } from "react";
|
|
14
|
+
import React, { Fragment, HTMLAttributes, forwardRef, useRef } from "react";
|
|
15
15
|
import { useModalContext } from "../modal/Modal.context";
|
|
16
16
|
import { Portal } from "../portal";
|
|
17
17
|
import { HStack } from "../primitives/stack";
|
|
@@ -296,7 +296,7 @@ function TooltipShortcuts({ shortcuts }: { shortcuts: TooltipProps["keys"] }) {
|
|
|
296
296
|
return (
|
|
297
297
|
<span className="aksel-tooltip__keys" aria-hidden>
|
|
298
298
|
{shortcuts.map((key, index) => (
|
|
299
|
-
|
|
299
|
+
<Fragment key={key.join("+")}>
|
|
300
300
|
<HStack gap="space-4">
|
|
301
301
|
{key.map((k, i) => (
|
|
302
302
|
<Detail as="kbd" key={i} className="aksel-tooltip__key">
|
|
@@ -307,7 +307,7 @@ function TooltipShortcuts({ shortcuts }: { shortcuts: TooltipProps["keys"] }) {
|
|
|
307
307
|
{index < shortcuts.length - 1 && (
|
|
308
308
|
<span> {translate("shortcutSeparator")} </span>
|
|
309
309
|
)}
|
|
310
|
-
|
|
310
|
+
</Fragment>
|
|
311
311
|
))}
|
|
312
312
|
</span>
|
|
313
313
|
);
|