Compare commits

...
Author SHA1 Message Date
Halvor Haugan 06435aaeab Merge branch 'main' into cb2stuff 2026-11-09 11:47:49 +01:00
Halvor Haugan b9dcb0a209 live region inside list 2026-11-09 11:46:36 +01:00
dependabot[bot] 7a49867e77 ⬆️ Bump tsc-alias from 1.9.7 to 1.9.10 (#5522)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-09 11:46:30 +01:00
Vehbi Karaagac 0ee13d82d7 fix: ignore selection when an open Combobox becomes disabled (#5520) 2026-11-09 11:45:08 +01:00
dependabot[bot]andKen 18a1eda79c ⬆️ Bump @axe-core/playwright from 4.13.0 to 4.14.0 (#5523)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ken <ken.aleksander@gmail.com>
2026-11-09 11:39:45 +01:00
dependabot[bot] 12ff585b3e ⬆️ Bump @navikt/oasis from 4.1.4 to 4.2.2 (#5524)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-09 11:37:55 +01:00
dependabot[bot] 3390f0f230 ⬆️ Bump prettier from 3.9.6 to 3.9.10 (#5525)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-11-09 11:36:30 +01:00
Halvor Haugan 2c1a3378cb Combobox2: Misc. improvements 2026-11-06 19:06:57 +01:00
18 changed files with 203 additions and 128 deletions

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
---
"@navikt/ds-react": patch
---
Combobox: Ignore option selection when an open Combobox becomes disabled.
+2 -2
View File
@@ -88,11 +88,11 @@
"hast-util-select": "6.0.4",
"js-yaml": "^5.5.0",
"lodash": "4.18.1",
"prettier": "3.9.6",
"prettier": "3.9.10",
"react": "19.3.1",
"rehype-parse": "9.0.1",
"svgo": "3.3.5",
"tsc-alias": "1.9.7",
"tsc-alias": "1.9.10",
"tsx": "^4.23.15",
"typescript": "6.0.3",
"unified": "11.0.5",
+1 -1
View File
@@ -811,7 +811,7 @@
"react-dom": "19.3.1",
"rimraf": "6.1.3",
"swr": "^2.4.2",
"tsc-alias": "1.9.7",
"tsc-alias": "1.9.10",
"tsx": "^4.23.15",
"typescript": "6.0.3",
"vitest": "5.0.5"
@@ -37,7 +37,12 @@ const SelectedOptionsProvider = ({
"allowNewValues" | "isMultiSelect" | "onToggleSelected" | "maxSelected"
> & { options: ComboboxOption[]; selectedOptions?: ComboboxOption[] };
}) => {
const { clearInput, focusInput, setHideCaret } = useInputContext();
const {
clearInput,
focusInput,
setHideCaret,
inputProps: { disabled },
} = useInputContext();
const {
customOptions,
removeCustomOption,
@@ -122,6 +127,9 @@ const SelectedOptionsProvider = ({
option: ComboboxOption,
event: React.KeyboardEvent | React.PointerEvent,
) => {
if (disabled) {
return;
}
if (isInList(option.value, selectedOptions)) {
removeSelectedOption(option);
} else if (isMultiSelect && isLimitReached) {
@@ -135,6 +143,7 @@ const SelectedOptionsProvider = ({
[
addSelectedOption,
clearInput,
disabled,
focusInput,
removeSelectedOption,
selectedOptions,
@@ -56,6 +56,26 @@ describe("Render combobox", () => {
});
});
test("ignores option selection after the open Combobox becomes disabled", async () => {
const onToggleSelected = vi.fn();
const props = { options, selectedOptions: ["apple"], onToggleSelected };
const { rerender } = render(<App {...props} />);
const input = screen.getByRole("combobox");
await userEvent.click(input);
rerender(<App {...props} disabled />);
expect(input).toBeDisabled();
await userEvent.click(
await screen.findByRole("option", { name: "banana" }),
);
expect(onToggleSelected).not.toHaveBeenCalled();
rerender(<App {...props} />);
await userEvent.click(
await screen.findByRole("option", { name: "banana" }),
);
expect(onToggleSelected).toHaveBeenCalledWith("banana", true, false);
});
describe("Combobox state-handling", () => {
test("Should show loading icon when loading (used for async search)", async () => {
render(<App options={[]} isListOpen isLoading />);
@@ -272,6 +272,7 @@ export const Composition = () => {
: [...prev, option.value],
);
},
multiple: true,
};
return (
@@ -126,6 +126,7 @@ export const OptionMemoization = () => {
</div>
<ComboboxRoot
defaultOpen
multiple
options={groupedOptions}
value={value}
onToggleOption={(option) => {
@@ -38,7 +38,7 @@ export const ComboboxFilter = (props: ComboboxFilterProps) => {
}}
onKeyDown={(event) => {
if (["ArrowLeft", "ArrowRight"].includes(event.key)) {
setVirtuallyFocusedOptionValue("");
setVirtuallyFocusedOptionValue(""); // Assume you want to edit the input, so remove virtual focus
}
}}
aria-autocomplete="list"
@@ -1,4 +1,4 @@
import React, { useCallback } from "react";
import React, { useRef } from "react";
import { Listbox } from "../../../utils/components/Listbox/root/ListboxRoot";
import { useDeferredValue, useEventCallback } from "../../../utils/hooks";
import { useI18n } from "../../../utils/i18n/i18n.hooks";
@@ -34,40 +34,48 @@ function ComboboxList<
});
}, []);*/
const liveRegionRef = useRef<HTMLDivElement>(null);
return (
<Listbox.Options className="aksel-combobox2__list">
{/*isPending && (
<>
<Listbox.Options className="aksel-combobox2__list">
{/*isPending && (
<div className="aksel-combobox2__loading" role="status">
Laster...
</div>
)*/}
<ComboboxListContent<T>>{children}</ComboboxListContent>
</Listbox.Options>
<ComboboxListContent<T> liveRegionRef={liveRegionRef}>
{children}
</ComboboxListContent>
</Listbox.Options>
<div ref={liveRegionRef} className="aksel-sr-only" role="status" />
</>
);
}
interface ComboboxListContentProps<
T extends ComboboxOptionData | ComboboxGroupData<ComboboxOptionData>,
> extends ComboboxListProps<T> {
liveRegionRef: React.RefObject<HTMLDivElement | null>;
}
function ComboboxListContent<
T extends ComboboxOptionData | ComboboxGroupData<ComboboxOptionData>,
>({ children }: ComboboxListProps<T>) {
>({ children, liveRegionRef }: ComboboxListContentProps<T>) {
const { virtuallyFocusedOptionValue, filterString } =
useComboboxPopupContext();
const { setOpen, options, value, onToggleOption, multiple, triggerRef } =
useComboboxRootContext();
const memoizedOnToggleOption = useEventCallback(onToggleOption);
const {
options,
value, // Selected options
onToggleOption: originalOnToggleOption,
} = useComboboxRootContext();
const onToggleOption = useEventCallback(originalOnToggleOption);
const deferredFilterString = useDeferredValue(filterString);
const maybeAnnouceHits = useHitsAnnouncer(deferredFilterString);
const translate = useI18n("Combobox2");
const localOnToggleOption = useCallback(
(option: ComboboxOptionData, isSelected: boolean) => {
memoizedOnToggleOption(option, isSelected);
if (!multiple) {
setOpen(false);
triggerRef.current?.focus();
}
},
[memoizedOnToggleOption, multiple, triggerRef, setOpen],
const maybeAnnouceHits = useHitsAnnouncer(
deferredFilterString,
liveRegionRef,
);
const translate = useI18n("Combobox2");
if (children && typeof children !== "function") {
return children;
@@ -97,7 +105,7 @@ function ComboboxListContent<
<ComboboxOption
key={option.value}
option={option}
onToggleOption={localOnToggleOption}
onToggleOption={onToggleOption}
isSelected={value.includes(option.value)}
hasVirtualFocus={virtuallyFocusedOptionValue === option.value}
highlightText={deferredFilterString}
@@ -110,7 +118,7 @@ function ComboboxListContent<
<ComboboxOption
key={optOrGroup.value}
option={optOrGroup}
onToggleOption={localOnToggleOption}
onToggleOption={onToggleOption}
isSelected={value.includes(optOrGroup.value)}
hasVirtualFocus={virtuallyFocusedOptionValue === optOrGroup.value}
highlightText={deferredFilterString} // TODO: Vurder å kunne slå av dette for bedre ytelse
@@ -126,26 +134,27 @@ function filterOptions<T extends ComboboxOptionData>(
filterString: string,
): (T | ComboboxGroupData<T>)[] {
const filterStringLowerCase = filterString.toLocaleLowerCase();
const results: (T | ComboboxGroupData<T>)[] = [];
return options
.map((optOrGroup) => {
if ("options" in optOrGroup) {
const matchingOptions = optOrGroup.options.filter((option) =>
option.label.toLocaleLowerCase().includes(filterStringLowerCase),
);
if (matchingOptions.length > 0) {
return { ...optOrGroup, options: matchingOptions };
for (const optOrGroup of options) {
if ("options" in optOrGroup) {
const matchingOptions: T[] = [];
for (const option of optOrGroup.options) {
if (option.label.toLocaleLowerCase().includes(filterStringLowerCase)) {
matchingOptions.push(option);
}
return null;
}
if (
optOrGroup.label.toLocaleLowerCase().includes(filterStringLowerCase)
) {
return optOrGroup;
if (matchingOptions.length > 0) {
results.push({ ...optOrGroup, options: matchingOptions });
}
return null;
})
.filter((option): option is T | ComboboxGroupData<T> => option !== null);
} else if (
optOrGroup.label.toLocaleLowerCase().includes(filterStringLowerCase)
) {
results.push(optOrGroup);
}
}
return results;
}
export type { ComboboxListProps };
@@ -46,9 +46,9 @@ let regions: {
function createRegion(politeness: Politeness) {
const el = document.createElement("div");
el.dataset.akselAnnouncer = "";
el.className = "aksel-sr-only";
el.className = "aksel-sr-only"; // TODO: Bruk inline style fra FocusGuards.tsx
el.role = politeness === "assertive" ? "alert" : "status";
document.body.appendChild(el);
document.body.appendChild(el); // TODO Bruk root fra Provider (se Portal.tsx)
return el;
}
@@ -91,7 +91,7 @@ function announce(message: string, politeness: Politeness = "polite") {
}
/**
* Speaks a message through a persistently-mounted, visually-hidden live region.
* Announces a message through a persistently-mounted, visually-hidden live region.
*
* The polite and assertive regions are created once and kept mounted.
*
@@ -1,11 +1,11 @@
import { useEffect, useMemo, useRef } from "react";
import { useCallback, useEffect, useMemo, useRef } from "react";
import { debounce } from "../../../utils-external";
import { useTimeout } from "../../../utils/hooks";
import { useI18n } from "../../../utils/i18n/i18n.hooks";
import type {
ComboboxGroupData,
ComboboxOptionData,
} from "../root/ComboboxRoot";
import { useAnnounce } from "./useAnnounce";
function getNumberOfOptions<T extends ComboboxOptionData>(
options: (T | ComboboxGroupData<T>)[],
@@ -18,10 +18,30 @@ function getNumberOfOptions<T extends ComboboxOptionData>(
}, 0);
}
function useHitsAnnouncer(deferredFilterString: string) {
function useHitsAnnouncer(
deferredFilterString: string,
liveRegionRef: React.RefObject<HTMLDivElement | null>,
) {
const translate = useI18n("Combobox2");
const oldFilterStringRef = useRef(deferredFilterString);
const announce = useAnnounce();
const timeout = useTimeout();
const announce = useCallback(
(message: string) => {
if (!liveRegionRef.current) {
return;
}
const target = liveRegionRef.current;
// If the message is the same as the current text,
// append a non-breaking space to force a re-announcement.
target.textContent =
message === target.textContent ? `${message} ` : message; // eslint-disable-line no-irregular-whitespace
timeout.start(2000, () => {
target.textContent = "";
});
},
[liveRegionRef, timeout],
);
const announceHits = useMemo(() => {
return debounce((count: number) => {
@@ -19,16 +19,7 @@ function ComboboxOverlay({ children, mobileHeader }: ComboboxOverlayProps) {
if (isMobile) {
return (
<ComboboxModal
open={rootContext.open}
onOpenChange={(open) => {
rootContext.setOpen(open);
!open && rootContext.triggerRef.current?.focus(); // This does not work when closing with button
}}
onOpenChangeComplete={(open) =>
!open && rootContext.triggerRef.current?.focus()
}
>
<ComboboxModal open={rootContext.open} onOpenChange={rootContext.setOpen}>
{mobileHeader}
{children}
</ComboboxModal>
@@ -42,7 +33,6 @@ function ComboboxOverlay({ children, mobileHeader }: ComboboxOverlayProps) {
return (
<DismissableLayer
asChild
//safeZone={{ anchor: rootContext.triggerRef.current }}
onDismiss={(event) => {
// We don't have trigger as `safeZone` because we want to close when trigger is focused.
// To avoid immediately re-opening the popup when trigger is clicked (blur closes, click opens),
@@ -55,7 +45,6 @@ function ComboboxOverlay({ children, mobileHeader }: ComboboxOverlayProps) {
return;
}
rootContext.setOpen(false);
rootContext.triggerRef.current?.focus();
}}
enabled={rootContext.open}
>
@@ -77,7 +66,6 @@ type ComboboxModalProps = {
children: React.ReactNode;
open: boolean;
onOpenChange: (open: boolean) => void;
onOpenChangeComplete: (open: boolean) => void;
};
function subscribeToResize(callback: () => void) {
@@ -89,12 +77,7 @@ function getVisualViewportHeight() {
return visualViewport?.height; // Takes into account virtual keyboard etc.
}
function ComboboxModal({
children,
open,
onOpenChange,
onOpenChangeComplete,
}: ComboboxModalProps) {
function ComboboxModal({ children, open, onOpenChange }: ComboboxModalProps) {
const visualViewportHeight = useSyncExternalStore(
subscribeToResize,
getVisualViewportHeight,
@@ -112,12 +95,7 @@ function ComboboxModal({
}, [open]);
return (
<Dialog
size="small"
open={open}
onOpenChange={onOpenChange}
onOpenChangeComplete={onOpenChangeComplete}
>
<Dialog size="small" open={open} onOpenChange={onOpenChange}>
<Dialog.Popup className="aksel-combobox2__modal" position="fullscreen">
<div
className="aksel-combobox2__modal-inner"
@@ -62,6 +62,7 @@ export const Default = () => {
return (
<ComboboxRoot
defaultOpen
multiple
options={options}
value={value}
onToggleOption={(option, newSelected) => {
@@ -173,6 +174,7 @@ export const CustomOptionRendering = () => {
return (
<ComboboxRoot
defaultOpen
multiple
options={options}
value={value}
onToggleOption={(option, isSelected) => {
@@ -259,6 +261,7 @@ export const ControlledInput = () => {
return (
<ComboboxRoot
defaultOpen
multiple
options={filteredOptions}
value={value}
onToggleOption={(option) => {
@@ -1,4 +1,5 @@
import React, { useLayoutEffect, useRef, useState } from "react";
import React, { useRef, useState } from "react";
import { useClientLayoutEffect } from "../../../utils-external";
import { Listbox } from "../../../utils/components/Listbox/root/ListboxRoot";
import { createStrictContext } from "../../../utils/helpers";
import { useComboboxRootContext } from "../root/ComboboxRoot";
@@ -29,7 +30,7 @@ export const ComboboxPopup = ({ children }: ComboboxPopupProps) => {
const rootContext = useComboboxRootContext();
const ref = useRef<HTMLDivElement | null>(null);
useLayoutEffect(
useClientLayoutEffect(
function onOpen() {
const canHover = window.matchMedia("(hover: hover)").matches;
@@ -85,7 +86,7 @@ export const ComboboxPopup = ({ children }: ComboboxPopupProps) => {
filterString={filterString}
setFilterString={(newString) => {
setFilterString(newString);
setVirtuallyFocusedOptionValue("");
setVirtuallyFocusedOptionValue(""); // Remove virtual focus when filter string changes
}}
>
{children}
@@ -1,4 +1,4 @@
import React, { useRef, useState } from "react";
import React, { useCallback, useRef, useState } from "react";
import { Floating } from "../../../utils/components/floating/Floating";
import { cl, createStrictContext } from "../../../utils/helpers";
import type { FormFieldProps } from "../../useFormField";
@@ -74,9 +74,8 @@ export interface ComboboxRootProps<
defaultOpen?: boolean;
/**
* Whether multiple options can be selected.
* @default true
*/
multiple?: boolean; // TODO: Hva skal være default?
multiple?: boolean;
}
export interface ComboboxRootContextProps {
@@ -84,9 +83,10 @@ export interface ComboboxRootContextProps {
setOpen: (newOpen: boolean) => void;
triggerRef: React.RefObject<HTMLDivElement | null>;
options: ComboboxRootProps["options"];
/** Values of selected options */
value: ComboboxRootProps["value"];
/** Consumer callback */
onToggleOption: ComboboxRootProps["onToggleOption"];
multiple: boolean;
size: Exclude<ComboboxRootProps["size"], undefined>;
disabled: ComboboxRootProps["disabled"];
}
@@ -107,7 +107,7 @@ export function ComboboxRoot<
value,
onToggleOption,
defaultOpen = false,
multiple = true,
multiple = false,
size = "medium",
disabled,
className,
@@ -125,14 +125,25 @@ export function ComboboxRoot<
>
<ComboboxRootContextProvider
open={open}
setOpen={setOpen}
setOpen={useCallback((newOpen) => {
setOpen(newOpen);
if (!newOpen) {
// queueMicrotask is needed when closing with close button in Dialog
queueMicrotask(() => triggerRef.current?.focus());
}
}, [])}
triggerRef={triggerRef}
options={options}
value={value}
onToggleOption={
onToggleOption as ComboboxRootContextProps["onToggleOption"]
}
multiple={multiple}
onToggleOption={useCallback(
(...args) => {
(onToggleOption as ComboboxRootProps["onToggleOption"])(...args);
if (!multiple) {
setOpen(false);
}
},
[onToggleOption, multiple],
)}
size={size}
disabled={disabled}
>
+2 -2
View File
@@ -33,7 +33,7 @@
"dependencies": {
"@navikt/analytics-types": "0.0.9",
"@navikt/next-logger": "5.0.1",
"@navikt/oasis": "4.1.4",
"@navikt/oasis": "4.2.2",
"@portabletext/react": "^8.0.1",
"@sanity/client": "7.27.0",
"@sanity/image-url": "2.1.1",
@@ -69,7 +69,7 @@
"zod": "^4.6.5"
},
"devDependencies": {
"@axe-core/playwright": "4.13.0",
"@axe-core/playwright": "4.14.0",
"@babel/core": "^7.19.0",
"@babel/parser": "^7.27.5",
"@babel/traverse": "^7.27.4",
+1 -1
View File
@@ -116,7 +116,7 @@
"lint-staged": "17.6.0",
"oxlint": "1.88.0",
"playwright": "1.61.1",
"prettier": "3.9.6",
"prettier": "3.9.10",
"react": "19.3.1",
"react-docgen-typescript": "2.4.0",
"react-dom": "19.3.1",
+53 -36
View File
@@ -249,14 +249,14 @@ __metadata:
languageName: node
linkType: hard
"@axe-core/playwright@npm:4.13.0":
version: 4.13.0
resolution: "@axe-core/playwright@npm:4.13.0"
"@axe-core/playwright@npm:4.14.0":
version: 4.14.0
resolution: "@axe-core/playwright@npm:4.14.0"
dependencies:
axe-core: "npm:~4.13.0"
axe-core: "npm:~4.14.0"
peerDependencies:
playwright-core: ">= 1.0.0"
checksum: 10/2400e309d6f6d96b3f3f12b00a80e32cb0213726fcfc3c457b36d17f7136a3361f02a7523286024d7e8ceba9045a5f9c18edd8bc352f76b549faedce298fada2
checksum: 10/ee72bd4a961758b069e444d8fbf944a3deb9721d758cf720399b46af8196262d8fbf496e3bc410bf5b66f718376d6ffbe9167ea7487426071c653c63620da7f6
languageName: node
linkType: hard
@@ -4888,11 +4888,11 @@ __metadata:
hast-util-select: "npm:6.0.4"
js-yaml: "npm:^5.5.0"
lodash: "npm:4.18.1"
prettier: "npm:3.9.6"
prettier: "npm:3.9.10"
react: "npm:19.3.1"
rehype-parse: "npm:9.0.1"
svgo: "npm:3.3.5"
tsc-alias: "npm:1.9.7"
tsc-alias: "npm:1.9.10"
tsx: "npm:^4.23.15"
typescript: "npm:6.0.3"
unified: "npm:11.0.5"
@@ -4989,7 +4989,7 @@ __metadata:
react-dom: "npm:19.3.1"
rimraf: "npm:6.1.3"
swr: "npm:^2.4.2"
tsc-alias: "npm:1.9.7"
tsc-alias: "npm:1.9.10"
tsx: "npm:^4.23.15"
typescript: "npm:6.0.3"
vitest: "npm:5.0.5"
@@ -5045,15 +5045,15 @@ __metadata:
languageName: node
linkType: hard
"@navikt/oasis@npm:4.1.4":
version: 4.1.4
resolution: "@navikt/oasis@npm:4.1.4::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Foasis%2F4.1.4%2F0d9c93820b9b6d93b1bd9da134feb95461ad8a47"
"@navikt/oasis@npm:4.2.2":
version: 4.2.2
resolution: "@navikt/oasis@npm:4.2.2::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Foasis%2F4.2.2%2F3c43e1e89bb2d46646a9a2aaf27972a024377a6f"
dependencies:
"@navikt/texas": "npm:^4.1.4"
"@opentelemetry/api": "npm:^1.9.0"
jose: "npm:^6.1.3"
prom-client: "npm:^15.1.3"
checksum: 10/1f0a9df3aa1b79d17a4076579a140eae607f45d8974072330b3faee3f80706560945aee7ad84f8aac7429e7dc719bdcb4c96774395d1f6cd75d422bfdce0b534
"@navikt/texas": "npm:^4.2.2"
"@opentelemetry/api": "npm:^1.9.1"
"@prometheus-io/client": "npm:^0.16.1"
jose: "npm:^6.2.10"
checksum: 10/ff6c0ff545e39c7f358077de97f19e2e9d04045cfa948093d2cd1b7417b38fd4d35ee202894ef984257d1c74b19560345eafbd7620602aa159d42a36bbef8ab6
languageName: node
linkType: hard
@@ -5072,10 +5072,10 @@ __metadata:
languageName: node
linkType: hard
"@navikt/texas@npm:^4.1.4":
version: 4.1.4
resolution: "@navikt/texas@npm:4.1.4::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Ftexas%2F4.1.4%2F1725aca0fa0b803e0048212c3e202d24c10f3c3b"
checksum: 10/43a3e9a840e16893d919a5aa4e02c093d8b3b2263e5900de951e079b4788708e1d172ee1eadceac092e03b27a46b6bde088d64ebba5e98ed23c977b08d82bb0a
"@navikt/texas@npm:^4.2.2":
version: 4.2.2
resolution: "@navikt/texas@npm:4.2.2::__archiveUrl=https%3A%2F%2Fnpm.pkg.github.com%2Fdownload%2F%40navikt%2Ftexas%2F4.2.2%2F862d743a1df21630a007a0d2d2a36a74dd8b5187"
checksum: 10/ee1067aa92437e688d1c035d028ae472e9eb0b554e41e739bac953a38adea125ada81dcf6eb2d215be076790d1bfa2157d3b9bead27920a42c917491929c2fb4
languageName: node
linkType: hard
@@ -5261,7 +5261,7 @@ __metadata:
languageName: node
linkType: hard
"@opentelemetry/api@npm:^1.4.0, @opentelemetry/api@npm:^1.9.0, @opentelemetry/api@npm:^1.9.1":
"@opentelemetry/api@npm:^1.4.0, @opentelemetry/api@npm:^1.9.1":
version: 1.9.1
resolution: "@opentelemetry/api@npm:1.9.1"
checksum: 10/b26032739d3c54ca99b5a2920844a1fbd4c3ee383cacbb0915e8c706a2626fe91e96feaa6e893397abe0545dc8d0a765b220aa18a31b1773176eeaf3a225e10e
@@ -6155,6 +6155,16 @@ __metadata:
languageName: node
linkType: hard
"@prometheus-io/client@npm:^0.16.1":
version: 0.16.1
resolution: "@prometheus-io/client@npm:0.16.1"
dependencies:
"@opentelemetry/api": "npm:^1.4.0"
tdigest: "npm:^0.1.1"
checksum: 10/6e8cdf0fbafc8506e3b5fb32815504fdfcf702e06b0d5d3d345a41ecf7e726e9a8e23b536eded80fdfb2073e14baee1622819129802104984c9fc179d1787048
languageName: node
linkType: hard
"@quansync/fs@npm:^1.0.0":
version: 1.0.0
resolution: "@quansync/fs@npm:1.0.0"
@@ -10125,7 +10135,7 @@ __metadata:
lint-staged: "npm:17.6.0"
oxlint: "npm:1.88.0"
playwright: "npm:1.61.1"
prettier: "npm:3.9.6"
prettier: "npm:3.9.10"
react: "npm:19.3.1"
react-docgen-typescript: "npm:2.4.0"
react-dom: "npm:19.3.1"
@@ -10633,10 +10643,10 @@ __metadata:
languageName: node
linkType: hard
"axe-core@npm:^4.2.0, axe-core@npm:~4.13.0":
version: 4.13.0
resolution: "axe-core@npm:4.13.0"
checksum: 10/b9319bedc705fde00e4abd981d8724202cc20102e4ae6d8edfde33cb5265e0fb8f67f32adcb4ad33fbd4a2c8d7ad7ef5af1d933d9ad859bed90e3eae0ee8c52f
"axe-core@npm:^4.2.0, axe-core@npm:~4.14.0":
version: 4.14.0
resolution: "axe-core@npm:4.14.0"
checksum: 10/b41f9c5fb670b3e1812ba203b17570efa026071e6c722cd8384bacbe5f2be1578fc5d7544acf06df7758eb755c7d23629df922e86cc0655d656784157c0d8df5
languageName: node
linkType: hard
@@ -16545,6 +16555,13 @@ __metadata:
languageName: node
linkType: hard
"jose@npm:^6.2.10":
version: 6.2.15
resolution: "jose@npm:6.2.15"
checksum: 10/57ea834a3aae6612b603dc04e5e068dabf1582934ffc759f004a0c654632bec06e6184aee73246157d03fb56179d50ac4e5c56ad02cf939086ef888ae8d8ebec
languageName: node
linkType: hard
"joycon@npm:^3.1.1":
version: 3.1.1
resolution: "joycon@npm:3.1.1"
@@ -20310,12 +20327,12 @@ __metadata:
languageName: node
linkType: hard
"prettier@npm:3.9.6":
version: 3.9.6
resolution: "prettier@npm:3.9.6"
"prettier@npm:3.9.10":
version: 3.9.10
resolution: "prettier@npm:3.9.10"
bin:
prettier: bin/prettier.cjs
checksum: 10/1dd1a1e0e40ec3b91cda9d294c4a95022aef61880ca3f441aad99b1252279f58a766c4cece81132c01550dcff1fd445efbd8812ea4a2374313e7fc6c8136f11f
checksum: 10/5d0118add4b44eb9d50c114f5c525451cc92be9da300ad0552787472535a3f23884baed3223d9b577bb7d1152eb58aeccfcc2b4541c0cf2274c0b4d328e36834
languageName: node
linkType: hard
@@ -23903,9 +23920,9 @@ __metadata:
languageName: node
linkType: hard
"tsc-alias@npm:1.9.7":
version: 1.9.7
resolution: "tsc-alias@npm:1.9.7"
"tsc-alias@npm:1.9.10":
version: 1.9.10
resolution: "tsc-alias@npm:1.9.10"
dependencies:
chokidar: "npm:^3.5.3"
commander: "npm:^9.0.0"
@@ -23916,7 +23933,7 @@ __metadata:
plimit-lit: "npm:^1.2.6"
bin:
tsc-alias: dist/bin/index.js
checksum: 10/9d4d37609c4aee4e31ae996283a2b78770d3bd7ba15341a7ae6c44b3036457c65591e0e761063bdcc3e943f13b2db7c705327332fbc2c4489594e9c1181321fa
checksum: 10/3a67f27aff49c26c002df56f101abbb18342d948bd1f9913edad6ad8ebdb1978c82149d0b3b3c1aa49ef79f9eb79ffe155478e1f639f608a44d5a9a31051c873
languageName: node
linkType: hard
@@ -25200,14 +25217,14 @@ __metadata:
version: 0.0.0-use.local
resolution: "website@workspace:aksel.nav.no/website"
dependencies:
"@axe-core/playwright": "npm:4.13.0"
"@axe-core/playwright": "npm:4.14.0"
"@babel/core": "npm:^7.19.0"
"@babel/parser": "npm:^7.27.5"
"@babel/traverse": "npm:^7.27.4"
"@google-cloud/bigquery": "npm:^9.5.0"
"@navikt/analytics-types": "npm:0.0.9"
"@navikt/next-logger": "npm:5.0.1"
"@navikt/oasis": "npm:4.1.4"
"@navikt/oasis": "npm:4.2.2"
"@next/eslint-plugin-next": "npm:16.4.3"
"@playwright/test": "npm:1.61.1"
"@portabletext/block-tools": "npm:^6.0.0"