mirror of
https://github.com/navikt/aksel.git
synced 2026-11-02 19:04:07 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca65ffba89 | ||
|
|
f5d9c288ad | ||
|
|
009cab1bc1 | ||
|
|
1d55e2481e | ||
|
|
3e039503fb | ||
|
|
a47cbaff83 | ||
|
|
e30a1edd98 | ||
|
|
32c578184e | ||
|
|
cd8fadf444 | ||
|
|
b69c5fca30 | ||
|
|
7a9530a252 | ||
|
|
3a858027b8 | ||
|
|
ab4ab6f488 |
No files matched your search
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@navikt/ds-react": patch
|
||||
"@navikt/aksel-icons": patch
|
||||
---
|
||||
|
||||
ESM: Mark ESM output as side-effect free, so bundlers like webpack, Turbopack and esbuild can tree-shake unused components and icons.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@navikt/ds-react": patch
|
||||
---
|
||||
|
||||
Date utilities: Import date-fns functions and locales from their own paths, so unbundled Node imports (SSR, Vitest/Jest) no longer load every date-fns locale.
|
||||
@@ -64,7 +64,7 @@
|
||||
"parse-svg": "node -e 'require(\"./config/parse-svg.js\").main()'",
|
||||
"copy": "copyfiles util/* src",
|
||||
"update-metadata": "node config/metadata.js",
|
||||
"write-packagejson": "echo '{\"type\": \"module\"}' > dist/react/esm/package.json",
|
||||
"write-packagejson": "echo '{\"type\": \"module\", \"sideEffects\": false}' > dist/react/esm/package.json",
|
||||
"build": "yarn copy && yarn create-icons && concurrently \"tsc\" \"tsc -p tsconfig.esm.json && tsc-alias -p tsconfig.esm.json && yarn write-packagejson\" && node config/cleanTypes.js && yarn update-metadata && yarn parse-svg",
|
||||
"fetch-new:icons": "tsx --env-file=.env config/figma/index.ts",
|
||||
"zip:icons": "node config/zip.js",
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.aksel-combobox2:has(:not(.aksel-combobox2__modal)) & {
|
||||
.aksel-combobox2:not(:has(.aksel-combobox2__modal)) & {
|
||||
outline: 1px solid var(--ax-border-neutral-subtleA);
|
||||
outline-offset: -1px;
|
||||
border-radius: var(--ax-radius-8);
|
||||
@@ -158,26 +158,21 @@
|
||||
margin: -1px;
|
||||
}
|
||||
|
||||
.aksel-combobox2__filter .aksel-search__wrapper {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
.aksel-combobox2__filter .aksel-search__wrapper:has(.aksel-search__input:focus-visible) {
|
||||
outline: none;
|
||||
position: relative;
|
||||
|
||||
&:has(.aksel-search__input:focus-visible) {
|
||||
outline: none;
|
||||
position: relative;
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
border: 2px solid var(--ax-border-focus);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
border: 2px solid var(--ax-border-focus);
|
||||
}
|
||||
|
||||
.aksel-combobox2:has(:not(.aksel-combobox2__modal)) &::after {
|
||||
border-top-left-radius: var(--ax-radius-8);
|
||||
border-top-right-radius: var(--ax-radius-8);
|
||||
}
|
||||
.aksel-combobox2:not(:has(.aksel-combobox2__modal)) &::after {
|
||||
border-top-left-radius: var(--ax-radius-8);
|
||||
border-top-right-radius: var(--ax-radius-8);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +184,7 @@
|
||||
border-color: var(--ax-border-neutral-subtleA);
|
||||
}
|
||||
|
||||
.aksel-combobox2[data-size="medium"] & {
|
||||
.aksel-combobox2__popup[data-size="medium"] & {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
@@ -221,15 +216,6 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Group *
|
||||
************************************************/
|
||||
|
||||
.aksel-combobox2__group-label {
|
||||
padding: var(--ax-space-8) var(--ax-space-8);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Option *
|
||||
************************************************/
|
||||
@@ -253,7 +239,7 @@
|
||||
margin-top: var(--ax-space-2);
|
||||
float: left;
|
||||
|
||||
.aksel-combobox2[data-size="small"] & {
|
||||
.aksel-combobox2__popup[data-size="small"] & {
|
||||
--__axc-combobox2-option-checkmark-size: 1rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -775,7 +775,7 @@
|
||||
"docgen:meta": "yarn metadata:generate-names && tsx ./scripts/extract-metadata.ts",
|
||||
"metadata:generate-names": "tsx ./scripts/extract-component-names.ts",
|
||||
"i18n-jsdoc": "tsx ./scripts/addJsdocToLocales.ts",
|
||||
"write-packagejson": "echo '{\"type\": \"module\"}' > esm/package.json",
|
||||
"write-packagejson": "echo '{\"type\": \"module\", \"sideEffects\": false}' > esm/package.json",
|
||||
"clean": "rimraf cjs esm",
|
||||
"build": "yarn i18n-jsdoc && yarn metadata:generate-names && concurrently \"tsc -p tsconfig.build.json --module commonjs --outDir cjs --tsBuildInfoFile cjs/.tsbuildinfo\" \"tsc -p tsconfig.build.json --module esnext --outDir esm --tsBuildInfoFile esm/.tsbuildinfo && tsc-alias -p tsconfig.build.json --dir esm -f && yarn write-packagejson\" && yarn i18n-jsdoc --cleanup && yarn copy-types",
|
||||
"watch": "tsc --watch -p tsconfig.build.json --module esnext --outDir esm --tsBuildInfoFile esm/.tsbuildinfo",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { type Locale, format } from "date-fns";
|
||||
import type { Locale } from "date-fns";
|
||||
import { format } from "date-fns/format";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import type { CalendarDay, Modifiers } from "react-day-picker";
|
||||
import { cl } from "../../utils/helpers";
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import {
|
||||
type Locale,
|
||||
format,
|
||||
getMonth,
|
||||
getYear,
|
||||
setMonth,
|
||||
setYear,
|
||||
startOfMonth,
|
||||
} from "date-fns";
|
||||
import type { Locale } from "date-fns";
|
||||
import { format } from "date-fns/format";
|
||||
import { getMonth } from "date-fns/getMonth";
|
||||
import { getYear } from "date-fns/getYear";
|
||||
import { setMonth } from "date-fns/setMonth";
|
||||
import { setYear } from "date-fns/setYear";
|
||||
import { startOfMonth } from "date-fns/startOfMonth";
|
||||
import React, { type ChangeEvent, useCallback } from "react";
|
||||
import { type CalendarMonth, useDayPicker } from "react-day-picker";
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from "@navikt/aksel-icons";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isWeekend } from "date-fns";
|
||||
import { isWeekend } from "date-fns/isWeekend";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import {
|
||||
type ClassNames,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isSameDay } from "date-fns";
|
||||
import { isSameDay } from "date-fns/isSameDay";
|
||||
import React, { forwardRef, useRef, useState } from "react";
|
||||
import type { DateRange } from "react-day-picker";
|
||||
import { useId } from "../../utils-external";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { differenceInCalendarDays, isWeekend } from "date-fns";
|
||||
import { differenceInCalendarDays } from "date-fns/differenceInCalendarDays";
|
||||
import { isWeekend } from "date-fns/isWeekend";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { type DayEventHandler, dateMatchModifiers } from "react-day-picker";
|
||||
import { getLocaleFromString } from "../../utils/components/date/Date.locale";
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { differenceInCalendarDays, isSameDay, isWeekend } from "date-fns";
|
||||
import { differenceInCalendarDays } from "date-fns/differenceInCalendarDays";
|
||||
import { isSameDay } from "date-fns/isSameDay";
|
||||
import { isWeekend } from "date-fns/isWeekend";
|
||||
import React, { useState } from "react";
|
||||
import { dateMatchModifiers } from "react-day-picker";
|
||||
import { getLocaleFromString } from "../../utils/components/date/Date.locale";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React, { forwardRef } from "react";
|
||||
import { Dialog } from "../../dialog";
|
||||
import { BodyShort, ErrorMessage } from "../../typography";
|
||||
import { cl } from "../../utils/helpers";
|
||||
@@ -36,109 +36,114 @@ interface ComboboxProps<
|
||||
name?: string;
|
||||
}
|
||||
|
||||
function Combobox<
|
||||
T extends ComboboxOptionData | ComboboxGroupData<ComboboxOptionData>,
|
||||
>({
|
||||
label,
|
||||
hideLabel,
|
||||
name,
|
||||
size: sizeProp,
|
||||
error,
|
||||
errorId: errorIdProp,
|
||||
disabled: disabledProp,
|
||||
description,
|
||||
id,
|
||||
readOnly: readOnlyProp,
|
||||
multiple,
|
||||
...rest
|
||||
}: ComboboxProps<T>) {
|
||||
const {
|
||||
inputProps,
|
||||
errorId,
|
||||
showErrorMsg,
|
||||
hasError,
|
||||
size,
|
||||
inputDescriptionId,
|
||||
readOnly,
|
||||
} = useFormField(
|
||||
const Combobox = forwardRef(
|
||||
<T extends ComboboxOptionData | ComboboxGroupData<ComboboxOptionData>>(
|
||||
{
|
||||
description,
|
||||
disabled: disabledProp,
|
||||
label,
|
||||
hideLabel,
|
||||
name,
|
||||
size: sizeProp,
|
||||
error,
|
||||
errorId: errorIdProp,
|
||||
disabled: disabledProp,
|
||||
description,
|
||||
id,
|
||||
readOnly: readOnlyProp,
|
||||
size: sizeProp,
|
||||
},
|
||||
"combobox",
|
||||
);
|
||||
multiple,
|
||||
...rest
|
||||
}: ComboboxProps<T>,
|
||||
ref: React.ForwardedRef<HTMLButtonElement>,
|
||||
) => {
|
||||
const {
|
||||
inputProps,
|
||||
errorId,
|
||||
showErrorMsg,
|
||||
hasError,
|
||||
size,
|
||||
inputDescriptionId,
|
||||
readOnly,
|
||||
} = useFormField(
|
||||
{
|
||||
description,
|
||||
disabled: disabledProp,
|
||||
error,
|
||||
errorId: errorIdProp,
|
||||
id,
|
||||
readOnly: readOnlyProp,
|
||||
size: sizeProp,
|
||||
},
|
||||
"combobox",
|
||||
);
|
||||
|
||||
return (
|
||||
<ComboboxRoot
|
||||
size={size}
|
||||
disabled={inputProps.disabled}
|
||||
multiple={multiple}
|
||||
{...rest}
|
||||
>
|
||||
<ComboboxLabel
|
||||
htmlFor={inputProps.id}
|
||||
hide={hideLabel}
|
||||
readOnly={readOnly}
|
||||
return (
|
||||
<ComboboxRoot
|
||||
size={size}
|
||||
disabled={inputProps.disabled}
|
||||
multiple={multiple}
|
||||
{...rest}
|
||||
>
|
||||
{label}
|
||||
</ComboboxLabel>
|
||||
{!!description && (
|
||||
<BodyShort
|
||||
className={cl(
|
||||
"aksel-form-field__description aksel-combobox2__description",
|
||||
{ "aksel-sr-only": hideLabel },
|
||||
)}
|
||||
id={inputDescriptionId}
|
||||
size={size}
|
||||
as="div"
|
||||
<ComboboxLabel
|
||||
htmlFor={inputProps.id}
|
||||
hide={hideLabel}
|
||||
readOnly={readOnly}
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
)}
|
||||
<ComboboxTrigger readOnly={readOnly} {...inputProps}>
|
||||
<ComboboxField hasError={hasError} />
|
||||
</ComboboxTrigger>
|
||||
<div
|
||||
className="aksel-form-field__error aksel-combobox2__error"
|
||||
id={errorId}
|
||||
aria-relevant="additions removals"
|
||||
aria-live="polite"
|
||||
>
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size} showIcon>
|
||||
{error}
|
||||
</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{name &&
|
||||
rest.value.map((val) => (
|
||||
<input key={val} type="hidden" name={name} value={val} />
|
||||
))}
|
||||
|
||||
<ComboboxOverlay
|
||||
mobileHeader={
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>{label}</Dialog.Title>
|
||||
{!!description && (
|
||||
<Dialog.Description>{description}</Dialog.Description>
|
||||
{label}
|
||||
</ComboboxLabel>
|
||||
{!!description && (
|
||||
<BodyShort
|
||||
className={cl(
|
||||
"aksel-form-field__description aksel-combobox2__description",
|
||||
{ "aksel-sr-only": hideLabel },
|
||||
)}
|
||||
</Dialog.Header>
|
||||
}
|
||||
>
|
||||
<ComboboxPopup>
|
||||
<ComboboxFilter />
|
||||
<ComboboxList />
|
||||
</ComboboxPopup>
|
||||
</ComboboxOverlay>
|
||||
</ComboboxRoot>
|
||||
);
|
||||
}
|
||||
id={inputDescriptionId}
|
||||
size={size}
|
||||
as="div"
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
)}
|
||||
<ComboboxTrigger readOnly={readOnly} {...inputProps}>
|
||||
<ComboboxField ref={ref} hasError={hasError} />
|
||||
</ComboboxTrigger>
|
||||
<div
|
||||
className="aksel-form-field__error aksel-combobox2__error"
|
||||
id={errorId}
|
||||
aria-relevant="additions removals"
|
||||
aria-live="polite"
|
||||
>
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size} showIcon>
|
||||
{error}
|
||||
</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{name &&
|
||||
rest.value.map((val) => (
|
||||
<input key={val} type="hidden" name={name} value={val} />
|
||||
))}
|
||||
|
||||
<ComboboxOverlay
|
||||
mobileHeader={
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>{label}</Dialog.Title>
|
||||
{!!description && (
|
||||
<Dialog.Description>{description}</Dialog.Description>
|
||||
)}
|
||||
</Dialog.Header>
|
||||
}
|
||||
>
|
||||
<ComboboxPopup>
|
||||
<ComboboxFilter />
|
||||
<ComboboxList />
|
||||
</ComboboxPopup>
|
||||
</ComboboxOverlay>
|
||||
</ComboboxRoot>
|
||||
);
|
||||
},
|
||||
) as <T extends ComboboxOptionData | ComboboxGroupData<ComboboxOptionData>>(
|
||||
props: ComboboxProps<T> & React.RefAttributes<HTMLButtonElement>,
|
||||
) => React.ReactElement;
|
||||
|
||||
// ----------- ComboboxSingle ----------- //
|
||||
|
||||
@@ -149,44 +154,67 @@ interface ComboboxSingleProps<
|
||||
* Called when selected option changes.
|
||||
*/
|
||||
onChange?: (
|
||||
newValue: NonNullable<ComboboxProps<T>["value"]>[number] | undefined,
|
||||
newValue: NonNullable<ComboboxProps<T>["value"]>[number] | null,
|
||||
) => void;
|
||||
/**
|
||||
* Value of the selected option.
|
||||
*/
|
||||
value?: NonNullable<ComboboxProps<T>["value"]>[number];
|
||||
value?: NonNullable<ComboboxProps<T>["value"]>[number] | null;
|
||||
/**
|
||||
* Initial value when uncontrolled.
|
||||
*/
|
||||
defaultValue?: NonNullable<ComboboxProps<T>["value"]>[number];
|
||||
}
|
||||
|
||||
function ComboboxSingle<
|
||||
T extends ComboboxOptionData | ComboboxGroupData<ComboboxOptionData>,
|
||||
>({ onChange, value, defaultValue, ...rest }: ComboboxSingleProps<T>) {
|
||||
const [localValue, setLocalValue] = useControllableState({
|
||||
defaultValue,
|
||||
value,
|
||||
onChange,
|
||||
});
|
||||
|
||||
const onToggleOption: ComboboxProps<T>["onToggleOption"] = (
|
||||
option,
|
||||
isSelected,
|
||||
/**
|
||||
* Component for selecting a value from a list of options that can be filtered.
|
||||
*
|
||||
* **WARNING: This component is in active development and may receive breaking changes outside major releases!**
|
||||
*
|
||||
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/TODO)
|
||||
* @see 🏷️ {@link ComboboxSingleProps}
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* <ComboboxSingle
|
||||
* label="Select country"
|
||||
* name="country"
|
||||
* options={countries}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
const ComboboxSingle = forwardRef(
|
||||
<T extends ComboboxOptionData | ComboboxGroupData<ComboboxOptionData>>(
|
||||
{ onChange, value, defaultValue, ...rest }: ComboboxSingleProps<T>,
|
||||
ref: React.ForwardedRef<HTMLButtonElement>,
|
||||
) => {
|
||||
setLocalValue(isSelected ? option.value : undefined);
|
||||
}; // TODO: Dumt at ikke får hele option-objektet... Legge til i onChange? Hvis vi tilbyr onToggle så blir det så likt onChange...
|
||||
const [localValue, setLocalValue] = useControllableState({
|
||||
defaultValue,
|
||||
value,
|
||||
onChange,
|
||||
});
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
{...rest}
|
||||
value={localValue ? [localValue] : []}
|
||||
defaultValue={defaultValue ? [defaultValue] : []}
|
||||
multiple={false}
|
||||
onToggleOption={onToggleOption}
|
||||
/>
|
||||
);
|
||||
}
|
||||
const onToggleOption: ComboboxProps<T>["onToggleOption"] = (
|
||||
option,
|
||||
isSelected,
|
||||
) => {
|
||||
setLocalValue(isSelected ? option.value : null);
|
||||
}; // TODO: Dumt at ikke får hele option-objektet... Legge til i onChange? Hvis vi tilbyr onToggle så blir det så likt onChange...
|
||||
|
||||
return (
|
||||
<Combobox
|
||||
{...rest}
|
||||
ref={ref}
|
||||
value={localValue ? [localValue] : []}
|
||||
defaultValue={defaultValue ? [defaultValue] : []}
|
||||
multiple={false}
|
||||
onToggleOption={onToggleOption}
|
||||
/>
|
||||
);
|
||||
},
|
||||
) as <T extends ComboboxOptionData | ComboboxGroupData<ComboboxOptionData>>(
|
||||
props: ComboboxSingleProps<T> & React.RefAttributes<HTMLButtonElement>,
|
||||
) => React.ReactElement;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
export namespace ComboboxSingle {
|
||||
|
||||
@@ -157,7 +157,7 @@ export const Name = () => (
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
const formData = new FormData(event.target);
|
||||
const land = formData.getAll("land");
|
||||
const land = formData.get("land");
|
||||
console.log(land);
|
||||
}}
|
||||
>
|
||||
@@ -168,7 +168,7 @@ export const Name = () => (
|
||||
);
|
||||
|
||||
export const Controlled = () => {
|
||||
const [value, setValue] = useState<MyOption["value"] | undefined>("opt-1");
|
||||
const [value, setValue] = useState<MyOption["value"] | null>("opt-1");
|
||||
|
||||
return (
|
||||
<VStack gap="space-8" minWidth="250px">
|
||||
@@ -180,7 +180,7 @@ export const Controlled = () => {
|
||||
/>
|
||||
Selected: {value}
|
||||
<div>
|
||||
<button type="button" onClick={() => setValue(undefined)}>
|
||||
<button type="button" onClick={() => setValue(null)}>
|
||||
Clear
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Meta } from "@storybook/react-vite";
|
||||
import React, { useState } from "react";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { expect, userEvent, within } from "storybook/test";
|
||||
import { ComboboxSingle } from "./Combobox";
|
||||
import { ComboboxFilter } from "./filter/ComboboxFilter";
|
||||
@@ -60,7 +60,7 @@ const groupedOptions = [
|
||||
function BaseCombobox<
|
||||
T extends ComboboxOptionData | ComboboxGroupData<ComboboxOptionData>,
|
||||
>(props: Partial<ComboboxSingle.Props<T>>) {
|
||||
const [value, setValue] = useState<string | undefined>("option-1");
|
||||
const [value, setValue] = useState<string | null>("opt-1");
|
||||
|
||||
return (
|
||||
<ComboboxSingle
|
||||
@@ -81,6 +81,27 @@ AccessibleNameAndDesc.play = async ({ canvasElement }) => {
|
||||
await expect(trigger).toHaveAccessibleDescription("Landet hvor du er født.");
|
||||
};
|
||||
|
||||
export const FocusWithRef = () => {
|
||||
const ref = useRef<HTMLButtonElement>(null);
|
||||
return (
|
||||
<div>
|
||||
<button type="button" onClick={() => ref.current?.focus()}>
|
||||
Fokuser combobox
|
||||
</button>
|
||||
<ComboboxSingle ref={ref} options={countries} label="Velg land" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
FocusWithRef.play = async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const combobox = await canvas.findByRole("combobox", { name: "Velg land" });
|
||||
await expect(combobox).not.toHaveFocus();
|
||||
await userEvent.click(
|
||||
canvas.getByRole("button", { name: "Fokuser combobox" }),
|
||||
);
|
||||
await expect(combobox).toHaveFocus();
|
||||
};
|
||||
|
||||
let optionMemoTestRenderCnt = 0;
|
||||
const optionMemoTestRenderFn = (
|
||||
optOrGroup: (typeof groupedOptions)[number],
|
||||
@@ -93,7 +114,7 @@ const optionMemoTestRenderFn = (
|
||||
return optOrGroup.label;
|
||||
};
|
||||
export const OptionMemoization = () => {
|
||||
const [value, setValue] = useState(["option-1"]);
|
||||
const [value, setValue] = useState(["opt-1"]);
|
||||
|
||||
return (
|
||||
<div style={{ minHeight: "450px" }}>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { forwardRef } from "react";
|
||||
import React, { forwardRef, useEffect, useState } from "react";
|
||||
import { ChevronDownIcon } from "@navikt/aksel-icons";
|
||||
import { cl } from "../../../utils/helpers";
|
||||
import { useI18n } from "../../../utils/i18n/i18n.hooks";
|
||||
import {
|
||||
type ComboboxRootProps,
|
||||
useComboboxRootContext,
|
||||
@@ -14,10 +15,23 @@ interface ComboboxFieldProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
|
||||
const ComboboxField = forwardRef<HTMLButtonElement, ComboboxFieldProps>(
|
||||
({ children, hasError, ...rest }, ref) => {
|
||||
const { options, value, size } = useComboboxRootContext();
|
||||
const translate = useI18n("Combobox2");
|
||||
|
||||
const labels = getLabels(value, options);
|
||||
const label =
|
||||
children ?? (labels.length > 1 ? `${labels.length} valgt` : labels[0]);
|
||||
children ??
|
||||
(labels.length > 1
|
||||
? translate("selectedCount", { count: labels.length })
|
||||
: labels[0]);
|
||||
|
||||
// Workaround for issue where VO on Safari announces the old label when focusing this button right after selecting a new option
|
||||
const [ariaLabel, setAriaLabel] = useState<string>();
|
||||
useEffect(() => {
|
||||
if (label) {
|
||||
setAriaLabel(label);
|
||||
setTimeout(() => setAriaLabel(undefined), 100);
|
||||
}
|
||||
}, [label]);
|
||||
|
||||
return (
|
||||
<div className="aksel-combobox2__field-container">
|
||||
@@ -30,8 +44,7 @@ const ComboboxField = forwardRef<HTMLButtonElement, ComboboxFieldProps>(
|
||||
"aksel-body-short",
|
||||
`aksel-body-short--${size ?? "medium"}`,
|
||||
)}
|
||||
// TODO: This results in other problems. Find another fix!
|
||||
//aria-label={label} // Without this, VO on Safari will announce the old label when focusing this button right after selecting a new option
|
||||
aria-label={ariaLabel}
|
||||
{...rest}
|
||||
>
|
||||
{label}
|
||||
|
||||
@@ -42,6 +42,7 @@ export const ComboboxFilter = (props: ComboboxFilterProps) => {
|
||||
}
|
||||
}}
|
||||
aria-autocomplete="list"
|
||||
aria-expanded="true"
|
||||
inputMode="text"
|
||||
/>
|
||||
</Listbox.InputSlot>
|
||||
|
||||
@@ -55,7 +55,7 @@ function ComboboxListContent<
|
||||
useComboboxRootContext();
|
||||
const memoizedOnToggleOption = useEventCallback(onToggleOption);
|
||||
const deferredFilterString = useDeferredValue(filterString);
|
||||
const maybeAnnouceHits = useHitsAnnouncer(deferredFilterString, filterString);
|
||||
const maybeAnnouceHits = useHitsAnnouncer(deferredFilterString);
|
||||
const translate = useI18n("Combobox2");
|
||||
|
||||
const localOnToggleOption = useCallback(
|
||||
@@ -80,6 +80,7 @@ function ComboboxListContent<
|
||||
maybeAnnouceHits(filteredOptions);
|
||||
|
||||
if (filteredOptions.length === 0) {
|
||||
// TODO: Consider moving outside of role=listbox
|
||||
return (
|
||||
<div className="aksel-combobox2__no-results">{translate("noHits")}</div>
|
||||
);
|
||||
|
||||
@@ -18,9 +18,9 @@ function getNumberOfOptions<T extends ComboboxOptionData>(
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function useHitsAnnouncer(deferredFilterString: string, filterString: string) {
|
||||
function useHitsAnnouncer(deferredFilterString: string) {
|
||||
const translate = useI18n("Combobox2");
|
||||
const shouldAnnounceRef = useRef(false);
|
||||
const oldFilterStringRef = useRef(deferredFilterString);
|
||||
const announce = useAnnounce();
|
||||
|
||||
const announceHits = useMemo(() => {
|
||||
@@ -50,20 +50,20 @@ function useHitsAnnouncer(deferredFilterString: string, filterString: string) {
|
||||
ComboboxOptionData | ComboboxGroupData<ComboboxOptionData>
|
||||
)[],
|
||||
) => {
|
||||
// The options are filtered based on deferredFilterString, so we need to wait for it to settle.
|
||||
if (deferredFilterString !== filterString) {
|
||||
shouldAnnounceRef.current = true;
|
||||
} else if (shouldAnnounceRef.current) {
|
||||
if (filteredOptions.length === 0) {
|
||||
announceHits.clear();
|
||||
announceNoHits();
|
||||
} else {
|
||||
const hits = getNumberOfOptions(filteredOptions);
|
||||
announceNoHits.clear();
|
||||
announceHits(hits);
|
||||
}
|
||||
shouldAnnounceRef.current = false;
|
||||
// Announce number of hits when filter string changes.
|
||||
// We can't do this in a useEffect b.c. of how ComboboxList is structured. Consider refactoring.
|
||||
if (deferredFilterString === oldFilterStringRef.current) {
|
||||
return;
|
||||
}
|
||||
if (filteredOptions.length === 0) {
|
||||
announceHits.clear();
|
||||
announceNoHits();
|
||||
} else {
|
||||
const hits = getNumberOfOptions(filteredOptions);
|
||||
announceNoHits.clear();
|
||||
announceHits(hits);
|
||||
}
|
||||
oldFilterStringRef.current = deferredFilterString;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { CheckmarkHeavyIcon } from "@navikt/aksel-icons";
|
||||
import { Listbox } from "../../../utils/components/Listbox/root/ListboxRoot";
|
||||
import type { ComboboxListProps } from "../list/ComboboxList";
|
||||
import type { ComboboxOptionData } from "../root/ComboboxRoot";
|
||||
import { highlightSubstring } from "./highlightSubstring";
|
||||
|
||||
export interface ComboboxOptionProps<T extends ComboboxOptionData> {
|
||||
option: T;
|
||||
@@ -49,31 +50,6 @@ function ComboboxOptionComponent<T extends ComboboxOptionData>({
|
||||
);
|
||||
}
|
||||
|
||||
const highlightSubstring = (text: string, substring: string) => {
|
||||
const indexOfHighlightedText = text
|
||||
.toLocaleLowerCase()
|
||||
.indexOf(substring.toLocaleLowerCase());
|
||||
if (indexOfHighlightedText === -1) {
|
||||
// This can happen if the consumer has implemented their own filtering logic
|
||||
return text;
|
||||
}
|
||||
const start = text.substring(0, indexOfHighlightedText);
|
||||
const highlight = text.substring(
|
||||
indexOfHighlightedText,
|
||||
indexOfHighlightedText + substring.length,
|
||||
);
|
||||
const end = text.substring(indexOfHighlightedText + substring.length);
|
||||
return (
|
||||
// Aria-label is used to fix testing-library wrongly evaluating the accessible name of the option when highlighting text
|
||||
// biome-ignore lint/a11y/useAriaPropsSupportedByRole: Doesn't matter if aria-label doesn't work
|
||||
<span aria-label={text}>
|
||||
{start}
|
||||
{highlight && <mark>{highlight}</mark>}
|
||||
{end}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export const ComboboxOption = React.memo(
|
||||
ComboboxOptionComponent,
|
||||
) as typeof ComboboxOptionComponent;
|
||||
@@ -0,0 +1,27 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { getHighlightRange } from "./highlightSubstring";
|
||||
|
||||
const highlighted = (text: string, substring: string) => {
|
||||
const range = getHighlightRange(text, substring);
|
||||
return range && text.substring(...range);
|
||||
};
|
||||
|
||||
describe("getHighlightRange", () => {
|
||||
test("matches case-insensitively", () => {
|
||||
expect(getHighlightRange("Norge", "OR")).toEqual([1, 3]);
|
||||
});
|
||||
|
||||
test("returns null when there is no match", () => {
|
||||
expect(getHighlightRange("Norge", "x")).toBeUndefined();
|
||||
});
|
||||
|
||||
test("handles characters that get longer when lowercased", () => {
|
||||
expect(highlighted("İstanbul", "an")).toBe("an");
|
||||
expect(highlighted("İzmir og Antalya", "an")).toBe("An");
|
||||
expect(highlighted("İzmir", "İz")).toBe("İz");
|
||||
});
|
||||
|
||||
test("includes the whole original character when only part of its lowercase form matches", () => {
|
||||
expect(highlighted("İstanbul", "i")).toBe("İ");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from "react";
|
||||
|
||||
function highlightSubstring(text: string, substring: string) {
|
||||
const range = getHighlightRange(text, substring);
|
||||
if (!range) {
|
||||
// This can happen if the consumer has implemented their own filtering logic
|
||||
return text;
|
||||
}
|
||||
const [rangeStart, rangeEnd] = range;
|
||||
return (
|
||||
// Aria-label is used to fix testing-library wrongly evaluating the accessible name of the option when highlighting text
|
||||
// biome-ignore lint/a11y/useAriaPropsSupportedByRole: Doesn't matter if it doesn't work in normal browsers
|
||||
<span aria-label={text}>
|
||||
{text.substring(0, rangeStart)}
|
||||
<mark>{text.substring(rangeStart, rangeEnd)}</mark>
|
||||
{text.substring(rangeEnd)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the first case-insensitive occurrence of `substring` in `text`.
|
||||
* Handles characters whose lowercase form has a different length than the original (e.g. "İ").
|
||||
* @returns The `[start, end]` range of the match in `text`, or `undefined` if there is no match.
|
||||
*/
|
||||
function getHighlightRange(text: string, substring: string) {
|
||||
const lowerSubstring = substring.toLocaleLowerCase();
|
||||
const matchIndex = text.toLocaleLowerCase().indexOf(lowerSubstring);
|
||||
if (matchIndex === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matchEnd = matchIndex + lowerSubstring.length;
|
||||
let start = 0;
|
||||
let origPos = 0;
|
||||
let lowerPos = 0;
|
||||
|
||||
for (const char of text) {
|
||||
if (lowerPos <= matchIndex) {
|
||||
start = origPos;
|
||||
}
|
||||
origPos += char.length;
|
||||
lowerPos += char.toLocaleLowerCase().length;
|
||||
if (lowerPos >= matchEnd) {
|
||||
return [start, origPos] as const;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { highlightSubstring, getHighlightRange };
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import React, { useLayoutEffect, useRef, useState } from "react";
|
||||
import { Listbox } from "../../../utils/components/Listbox/root/ListboxRoot";
|
||||
import { createStrictContext } from "../../../utils/helpers";
|
||||
import { useComboboxRootContext } from "../root/ComboboxRoot";
|
||||
@@ -29,7 +29,7 @@ export const ComboboxPopup = ({ children }: ComboboxPopupProps) => {
|
||||
const rootContext = useComboboxRootContext();
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(
|
||||
useLayoutEffect(
|
||||
function onOpen() {
|
||||
const canHover = window.matchMedia("(hover: hover)").matches;
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import {
|
||||
compareAsc,
|
||||
compareDesc,
|
||||
format,
|
||||
isSameMonth,
|
||||
setYear,
|
||||
} from "date-fns";
|
||||
import { compareAsc } from "date-fns/compareAsc";
|
||||
import { compareDesc } from "date-fns/compareDesc";
|
||||
import { format } from "date-fns/format";
|
||||
import { isSameMonth } from "date-fns/isSameMonth";
|
||||
import { setYear } from "date-fns/setYear";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { dateIsInCurrentMonth, isMatch } from "../../utils/date";
|
||||
import { cl } from "../../utils/helpers";
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import {
|
||||
format,
|
||||
isAfter,
|
||||
isBefore,
|
||||
setYear,
|
||||
startOfMonth,
|
||||
startOfYear,
|
||||
} from "date-fns";
|
||||
import { format } from "date-fns/format";
|
||||
import { isAfter } from "date-fns/isAfter";
|
||||
import { isBefore } from "date-fns/isBefore";
|
||||
import { setYear } from "date-fns/setYear";
|
||||
import { startOfMonth } from "date-fns/startOfMonth";
|
||||
import { startOfYear } from "date-fns/startOfYear";
|
||||
import React from "react";
|
||||
import { ArrowLeftIcon, ArrowRightIcon } from "@navikt/aksel-icons";
|
||||
import { Button } from "../../button";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { type Locale, isSameYear } from "date-fns";
|
||||
import type { Locale } from "date-fns";
|
||||
import { isSameYear } from "date-fns/isSameYear";
|
||||
import React from "react";
|
||||
import { clampDisplayYear } from "../../utils/date";
|
||||
import { createStrictContext } from "../../utils/helpers";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { setYear } from "date-fns";
|
||||
import { setYear } from "date-fns/setYear";
|
||||
import type { Matcher } from "../../utils/components/date/Date.typeutils";
|
||||
import { isMatch } from "../../utils/date";
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { isSameMonth, setMonth, setYear, startOfMonth } from "date-fns";
|
||||
import { isSameMonth } from "date-fns/isSameMonth";
|
||||
import { setMonth } from "date-fns/setMonth";
|
||||
import { setYear } from "date-fns/setYear";
|
||||
import { startOfMonth } from "date-fns/startOfMonth";
|
||||
import React, { useState } from "react";
|
||||
import { BodyShort } from "../../typography";
|
||||
import { isMatch } from "../../utils/date";
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
import {
|
||||
type Locale,
|
||||
addDays,
|
||||
addMonths,
|
||||
addYears,
|
||||
differenceInDays,
|
||||
differenceInMonths,
|
||||
differenceInYears,
|
||||
endOfMonth,
|
||||
endOfYear,
|
||||
format,
|
||||
startOfDay,
|
||||
startOfMonth,
|
||||
startOfYear,
|
||||
subDays,
|
||||
} from "date-fns";
|
||||
import type { Locale } from "date-fns";
|
||||
import { addDays } from "date-fns/addDays";
|
||||
import { addMonths } from "date-fns/addMonths";
|
||||
import { addYears } from "date-fns/addYears";
|
||||
import { differenceInDays } from "date-fns/differenceInDays";
|
||||
import { differenceInMonths } from "date-fns/differenceInMonths";
|
||||
import { differenceInYears } from "date-fns/differenceInYears";
|
||||
import { endOfMonth } from "date-fns/endOfMonth";
|
||||
import { endOfYear } from "date-fns/endOfYear";
|
||||
import { format } from "date-fns/format";
|
||||
import { startOfDay } from "date-fns/startOfDay";
|
||||
import { startOfMonth } from "date-fns/startOfMonth";
|
||||
import { startOfYear } from "date-fns/startOfYear";
|
||||
import { subDays } from "date-fns/subDays";
|
||||
import React, { useCallback, useMemo } from "react";
|
||||
import { Detail } from "../../typography/Detail";
|
||||
import { useDateLocale, useI18n } from "../../utils/i18n/i18n.hooks";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isBefore } from "date-fns";
|
||||
import { isBefore } from "date-fns/isBefore";
|
||||
import React, { forwardRef } from "react";
|
||||
import { useTimelineContext } from "../root/TimelineRoot.context";
|
||||
import {
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
useHover,
|
||||
useInteractions,
|
||||
} from "@floating-ui/react";
|
||||
import { format } from "date-fns";
|
||||
import { format } from "date-fns/format";
|
||||
import React, { forwardRef, useMemo, useState } from "react";
|
||||
import { useMergeRefs } from "../../utils/hooks";
|
||||
import { useI18n } from "../../utils/i18n/i18n.hooks";
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { endOfDay, isSameDay, startOfDay } from "date-fns";
|
||||
import { endOfDay } from "date-fns/endOfDay";
|
||||
import { isSameDay } from "date-fns/isSameDay";
|
||||
import { startOfDay } from "date-fns/startOfDay";
|
||||
import React, { forwardRef, useMemo, useState } from "react";
|
||||
import { consoleWarning } from "../../utils/helpers/consoleWarning";
|
||||
import { TimelineAxisLabelsInternal } from "../axis-labels/TimelineAxisLabelsInternal";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { renderHook } from "@testing-library/react";
|
||||
import { addDays, isSameDay } from "date-fns";
|
||||
import { addDays } from "date-fns/addDays";
|
||||
import { isSameDay } from "date-fns/isSameDay";
|
||||
import { describe, expect, test } from "vitest";
|
||||
import {
|
||||
useEarliestDate,
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { addDays, endOfDay, isAfter, startOfDay, subDays } from "date-fns";
|
||||
import { addDays } from "date-fns/addDays";
|
||||
import { endOfDay } from "date-fns/endOfDay";
|
||||
import { isAfter } from "date-fns/isAfter";
|
||||
import { startOfDay } from "date-fns/startOfDay";
|
||||
import { subDays } from "date-fns/subDays";
|
||||
import { useMemo } from "react";
|
||||
import { horizontalPositionAndWidth } from "../utils/calc";
|
||||
import { invisiblePeriods, withinADay } from "../utils/filter";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { format } from "date-fns";
|
||||
import { format } from "date-fns/format";
|
||||
import React, { forwardRef } from "react";
|
||||
import { BodyShort } from "../../typography/BodyShort";
|
||||
import { cl } from "../../utils/helpers";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { differenceInMilliseconds } from "date-fns";
|
||||
import { differenceInMilliseconds } from "date-fns/differenceInMilliseconds";
|
||||
|
||||
const position = (date: Date, start: Date, endInclusive: Date) => {
|
||||
const diff = differenceInMilliseconds(endInclusive, start);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { differenceInDays } from "date-fns";
|
||||
import { differenceInDays } from "date-fns/differenceInDays";
|
||||
import type { PeriodProps } from "../Timeline.types";
|
||||
import type { Spatial } from "./types.internal";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { format } from "date-fns";
|
||||
import { format } from "date-fns/format";
|
||||
import { cl } from "../../utils/helpers";
|
||||
import type { TFunction } from "../../utils/i18n/i18n.types";
|
||||
import type { PeriodProps } from "../Timeline.types";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { differenceInMilliseconds } from "date-fns";
|
||||
import { differenceInMilliseconds } from "date-fns/differenceInMilliseconds";
|
||||
import type { Period, PositionedPeriod } from "./types.internal";
|
||||
|
||||
const lastDate = (a: Date, b: Date): number => differenceInMilliseconds(a, b);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import {
|
||||
addMonths,
|
||||
addYears,
|
||||
format,
|
||||
isSameDay,
|
||||
subMonths,
|
||||
subYears,
|
||||
} from "date-fns";
|
||||
import { addMonths } from "date-fns/addMonths";
|
||||
import { addYears } from "date-fns/addYears";
|
||||
import { format } from "date-fns/format";
|
||||
import { isSameDay } from "date-fns/isSameDay";
|
||||
import { subMonths } from "date-fns/subMonths";
|
||||
import { subYears } from "date-fns/subYears";
|
||||
import React, { forwardRef } from "react";
|
||||
import { Detail } from "../../typography/Detail";
|
||||
import { useI18n } from "../../utils/i18n/i18n.hooks";
|
||||
|
||||
@@ -39,4 +39,12 @@ function ListboxOptions({ children, ...rest }: ListboxOptionsProps) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Things that should be fixed before we allow focus directly
|
||||
* on the listbox (i.e. when there's no filter input/combobox elm.)
|
||||
* - Set aria-activedescendant
|
||||
* - Consider aria-multiselectable
|
||||
* - Probably aria-label(ledby)?
|
||||
*/
|
||||
|
||||
export { ListboxOptions };
|
||||
@@ -1,4 +1,6 @@
|
||||
import { enGB, nb, nn } from "date-fns/locale";
|
||||
import { enGB } from "date-fns/locale/en-GB";
|
||||
import { nb } from "date-fns/locale/nb";
|
||||
import { nn } from "date-fns/locale/nn";
|
||||
import { createStrictContext } from "../../helpers";
|
||||
import type { TFunction } from "../../i18n/i18n.types";
|
||||
import en_translations from "../../i18n/locales/en";
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import {
|
||||
addYears,
|
||||
endOfMonth,
|
||||
endOfYear,
|
||||
startOfDay,
|
||||
startOfMonth,
|
||||
startOfYear,
|
||||
} from "date-fns";
|
||||
import { addYears } from "date-fns/addYears";
|
||||
import { endOfMonth } from "date-fns/endOfMonth";
|
||||
import { endOfYear } from "date-fns/endOfYear";
|
||||
import { startOfDay } from "date-fns/startOfDay";
|
||||
import { startOfMonth } from "date-fns/startOfMonth";
|
||||
import { startOfYear } from "date-fns/startOfYear";
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { calendarRange } from "./calendar-range";
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import {
|
||||
addYears,
|
||||
endOfMonth,
|
||||
endOfYear,
|
||||
startOfDay,
|
||||
startOfMonth,
|
||||
startOfYear,
|
||||
} from "date-fns";
|
||||
import { addYears } from "date-fns/addYears";
|
||||
import { endOfMonth } from "date-fns/endOfMonth";
|
||||
import { endOfYear } from "date-fns/endOfYear";
|
||||
import { startOfDay } from "date-fns/startOfDay";
|
||||
import { startOfMonth } from "date-fns/startOfMonth";
|
||||
import { startOfYear } from "date-fns/startOfYear";
|
||||
|
||||
/**
|
||||
* Generates the min and max-dates possible to show and navigate to in the calendar.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { setYear } from "date-fns";
|
||||
import { setYear } from "date-fns/setYear";
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { dateIsInCurrentMonth, isValidDate } from "./check-dates";
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import {
|
||||
differenceInCalendarDays,
|
||||
isThisMonth,
|
||||
setYear,
|
||||
startOfDay,
|
||||
} from "date-fns";
|
||||
import { differenceInCalendarDays } from "date-fns/differenceInCalendarDays";
|
||||
import { isThisMonth } from "date-fns/isThisMonth";
|
||||
import { setYear } from "date-fns/setYear";
|
||||
import { startOfDay } from "date-fns/startOfDay";
|
||||
|
||||
export const dateIsInCurrentMonth = (
|
||||
date: Date,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { startOfMonth, startOfYear } from "date-fns";
|
||||
import { startOfMonth } from "date-fns/startOfMonth";
|
||||
import { startOfYear } from "date-fns/startOfYear";
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { isDateOutsideRange } from "./check-dates";
|
||||
import { clampDisplayMonth, clampDisplayYear } from "./clamp-dates";
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { isAfter, isBefore, startOfMonth, startOfYear } from "date-fns";
|
||||
import { isAfter } from "date-fns/isAfter";
|
||||
import { isBefore } from "date-fns/isBefore";
|
||||
import { startOfMonth } from "date-fns/startOfMonth";
|
||||
import { startOfYear } from "date-fns/startOfYear";
|
||||
|
||||
/**
|
||||
* Makes sure the month is within the min and max daterange to avoid showing disabled months
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isSameDay } from "date-fns";
|
||||
import { isSameDay } from "date-fns/isSameDay";
|
||||
import { isDateRange } from "../components/date/Date.typeutils";
|
||||
|
||||
export const disableDate = (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { nb } from "date-fns/locale";
|
||||
import { nb } from "date-fns/locale/nb";
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { getMonthOptions, getYearOptions } from "./dropdown-options";
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import {
|
||||
type Locale,
|
||||
addYears,
|
||||
eachMonthOfInterval,
|
||||
endOfYear,
|
||||
format,
|
||||
getMonth,
|
||||
getYear,
|
||||
isBefore,
|
||||
isSameYear,
|
||||
startOfMonth,
|
||||
startOfYear,
|
||||
} from "date-fns";
|
||||
import type { Locale } from "date-fns";
|
||||
import { addYears } from "date-fns/addYears";
|
||||
import { eachMonthOfInterval } from "date-fns/eachMonthOfInterval";
|
||||
import { endOfYear } from "date-fns/endOfYear";
|
||||
import { format } from "date-fns/format";
|
||||
import { getMonth } from "date-fns/getMonth";
|
||||
import { getYear } from "date-fns/getYear";
|
||||
import { isBefore } from "date-fns/isBefore";
|
||||
import { isSameYear } from "date-fns/isSameYear";
|
||||
import { startOfMonth } from "date-fns/startOfMonth";
|
||||
import { startOfYear } from "date-fns/startOfYear";
|
||||
|
||||
/** Return the months to show in the dropdown. */
|
||||
export function getMonthOptions({
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { type Locale, format } from "date-fns";
|
||||
import type { Locale } from "date-fns";
|
||||
import { format } from "date-fns/format";
|
||||
import {
|
||||
INPUT_DATE_STRING_FORMAT_DATE,
|
||||
INPUT_DATE_STRING_FORMAT_MONTH,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { nb } from "date-fns/locale";
|
||||
import { nb } from "date-fns/locale/nb";
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { formatDateForInput } from "./format-date";
|
||||
import { parseDate } from "./parse-date";
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import {
|
||||
differenceInCalendarDays,
|
||||
isDate,
|
||||
isSameDay,
|
||||
isSameMonth,
|
||||
} from "date-fns";
|
||||
import { differenceInCalendarDays } from "date-fns/differenceInCalendarDays";
|
||||
import { isDate } from "date-fns/isDate";
|
||||
import { isSameDay } from "date-fns/isSameDay";
|
||||
import { isSameMonth } from "date-fns/isSameMonth";
|
||||
import {
|
||||
type DateRange,
|
||||
type Matcher,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { type Locale, isBefore, parse, sub } from "date-fns";
|
||||
import type { Locale } from "date-fns";
|
||||
import { isBefore } from "date-fns/isBefore";
|
||||
import { parse } from "date-fns/parse";
|
||||
import { sub } from "date-fns/sub";
|
||||
import { isValidDate } from "./check-dates";
|
||||
|
||||
export const INPUT_DATE_STRING_FORMAT_DATE = "dd.MM.yyyy";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getMonth } from "date-fns";
|
||||
import { nb } from "date-fns/locale";
|
||||
import { getMonth } from "date-fns/getMonth";
|
||||
import { nb } from "date-fns/locale/nb";
|
||||
import { describe, expect, test } from "vitest";
|
||||
import { isValidDate } from "./check-dates";
|
||||
import { parseDate } from "./parse-date";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { isBefore, isSameDay } from "date-fns";
|
||||
import { isBefore } from "date-fns/isBefore";
|
||||
import { isSameDay } from "date-fns/isSameDay";
|
||||
import type { DateRange } from "../components/date/Date.typeutils";
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,8 @@ const internalTranslations = {
|
||||
selected: "{count} rows selected",
|
||||
},
|
||||
Combobox2: {
|
||||
/** The "value" that is shown when multiple options are selected. */
|
||||
selectedCount: "{count} valgt",
|
||||
/** Label for filter input. Only visible to screen readers. */
|
||||
filter: "Filtrer",
|
||||
noHits: "Ingen treff",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { enGB } from "date-fns/locale";
|
||||
import { enGB } from "date-fns/locale/en-GB";
|
||||
import type { Translations } from "../i18n.types";
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { type Locale, nb } from "date-fns/locale";
|
||||
import type { Locale } from "date-fns";
|
||||
import { nb } from "date-fns/locale/nb";
|
||||
|
||||
interface TranslationMap {
|
||||
[component: string]: Record<string, string | Record<string, string> | Locale>;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { nn } from "date-fns/locale";
|
||||
import { nn } from "date-fns/locale/nn";
|
||||
import type { Translations } from "../i18n.types";
|
||||
|
||||
export default {
|
||||
|
||||
+23
-17
@@ -1,27 +1,33 @@
|
||||
import Fuse from "fuse.js";
|
||||
import { type TokenDocT, tokens } from "@navikt/ds-tokens/token_docs";
|
||||
|
||||
function tokenIndex(_tokens: TokenDocT[]) {
|
||||
return new Fuse(_tokens, {
|
||||
threshold: 0.25,
|
||||
keys: [
|
||||
{ name: "name", weight: 0.9 },
|
||||
{ name: "group", weight: 0.3 },
|
||||
{ name: "category", weight: 0.7 },
|
||||
{ name: "categoryTitle", weight: 0.7 },
|
||||
{ name: "comment", weight: 0.3 },
|
||||
{ name: "type", weight: 0.7 },
|
||||
{ name: "role", weight: 0.7 },
|
||||
{ name: "modifier", weight: 0.7 },
|
||||
],
|
||||
//shouldSort: false,
|
||||
ignoreLocation: true,
|
||||
});
|
||||
let tokenSearchIndex: Fuse<TokenDocT> | undefined;
|
||||
|
||||
function getTokenSearchIndex() {
|
||||
if (!tokenSearchIndex) {
|
||||
tokenSearchIndex = new Fuse(tokens, {
|
||||
threshold: 0.25,
|
||||
keys: [
|
||||
{ name: "name", weight: 0.9 },
|
||||
{ name: "group", weight: 0.3 },
|
||||
{ name: "category", weight: 0.7 },
|
||||
{ name: "categoryTitle", weight: 0.7 },
|
||||
{ name: "comment", weight: 0.3 },
|
||||
{ name: "type", weight: 0.7 },
|
||||
{ name: "role", weight: 0.7 },
|
||||
{ name: "modifier", weight: 0.7 },
|
||||
],
|
||||
//shouldSort: false,
|
||||
ignoreLocation: true,
|
||||
});
|
||||
}
|
||||
|
||||
return tokenSearchIndex;
|
||||
}
|
||||
|
||||
function searchTokens(query: string): TokenDocT[] {
|
||||
return query
|
||||
? tokenIndex(tokens)
|
||||
? getTokenSearchIndex()
|
||||
.search(query)
|
||||
.map((t) => t.item)
|
||||
: tokens;
|
||||
|
||||
@@ -36,32 +36,41 @@ async function globalSearch(
|
||||
}
|
||||
|
||||
const fuse = await getSearchIndex();
|
||||
const fuseResults = fuse
|
||||
.search(query)
|
||||
.filter((x) => x.score !== undefined && x.score < 0.3)
|
||||
.sort((a, b) => Number(isOverrideHit(b)) - Number(isOverrideHit(a)));
|
||||
const overrideResults: FuseResult<SearchPageT>[] = [];
|
||||
const regularResults: FuseResult<SearchPageT>[] = [];
|
||||
let totalHits = 0;
|
||||
|
||||
const topResults =
|
||||
fuseResults.length > MAX_TOP_RESULTS
|
||||
? fuseResults
|
||||
.filter((x) => x.score !== undefined && x.score < 0.1)
|
||||
.slice(0, MAX_TOP_RESULTS)
|
||||
: [];
|
||||
const topResultSet = new Set(topResults);
|
||||
|
||||
const groups = new Map<SearchResultPageTypesT, SearchHitGroupT>();
|
||||
for (const result of fuseResults) {
|
||||
if (topResultSet.has(result)) {
|
||||
for (const result of fuse.search(query)) {
|
||||
if (result.score === undefined || result.score >= 0.3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const type = result.item._type;
|
||||
const group = groups.get(type) ?? { type, total: 0, hits: [] };
|
||||
groups.set(type, group);
|
||||
totalHits++;
|
||||
(isOverrideHit(result) ? overrideResults : regularResults).push(result);
|
||||
}
|
||||
|
||||
group.total++;
|
||||
if (group.hits.length < MAX_HITS_PER_TYPE) {
|
||||
group.hits.push(toSearchHit(result));
|
||||
const groups = new Map<SearchResultPageTypesT, SearchHitGroupT>();
|
||||
const topResults: SearchHitT[] = [];
|
||||
for (const rankedResults of [overrideResults, regularResults]) {
|
||||
for (const result of rankedResults) {
|
||||
if (
|
||||
totalHits > MAX_TOP_RESULTS &&
|
||||
topResults.length < MAX_TOP_RESULTS &&
|
||||
result.score !== undefined &&
|
||||
result.score < 0.1
|
||||
) {
|
||||
topResults.push(toSearchHit(result));
|
||||
continue;
|
||||
}
|
||||
|
||||
const type = result.item._type;
|
||||
const group = groups.get(type) ?? { type, total: 0, hits: [] };
|
||||
groups.set(type, group);
|
||||
|
||||
group.total++;
|
||||
if (group.hits.length < MAX_HITS_PER_TYPE) {
|
||||
group.hits.push(toSearchHit(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,8 +81,8 @@ async function globalSearch(
|
||||
|
||||
return {
|
||||
result: {
|
||||
totalHits: fuseResults.length,
|
||||
topResults: topResults.map(toSearchHit),
|
||||
totalHits,
|
||||
topResults,
|
||||
groupedHits,
|
||||
},
|
||||
query,
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
"jscodeshift": "17.4.0",
|
||||
"lodash": "4.18.1",
|
||||
"lz-string": "^1.5.0",
|
||||
"next": "16.4.2",
|
||||
"next": "16.4.3",
|
||||
"next-logger": "^5.0.2",
|
||||
"next-sanity": "13.2.3",
|
||||
"next-themes": "^0.4.6",
|
||||
@@ -71,9 +71,9 @@
|
||||
"@babel/core": "^7.19.0",
|
||||
"@babel/parser": "^7.27.5",
|
||||
"@babel/traverse": "^7.27.4",
|
||||
"@google-cloud/bigquery": "^9.0.2",
|
||||
"@next/bundle-analyzer": "16.4.2",
|
||||
"@next/eslint-plugin-next": "16.4.2",
|
||||
"@google-cloud/bigquery": "^9.5.0",
|
||||
"@next/bundle-analyzer": "16.4.3",
|
||||
"@next/eslint-plugin-next": "16.4.3",
|
||||
"@playwright/test": "1.61.1",
|
||||
"@portabletext/block-tools": "^6.0.0",
|
||||
"@portabletext/markdown": "^2.5.1",
|
||||
|
||||
@@ -167,6 +167,31 @@ module.exports = defineConfig([
|
||||
"import/no-named-export": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["@navikt/core/react/src/**/*.{ts,tsx}"],
|
||||
ignores: ["**/*.stories.tsx"],
|
||||
rules: {
|
||||
"@typescript-eslint/no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
paths: [
|
||||
{
|
||||
name: "date-fns",
|
||||
allowTypeImports: true,
|
||||
message:
|
||||
'Import functions from their own path, e.g. `import { format } from "date-fns/format"`. The root barrel makes unbundled Node imports load all of date-fns.',
|
||||
},
|
||||
{
|
||||
name: "date-fns/locale",
|
||||
allowTypeImports: true,
|
||||
message:
|
||||
'Import locales from their own path, e.g. `import { nb } from "date-fns/locale/nb"`. The barrel makes unbundled Node imports load all locales.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["@navikt/**"],
|
||||
ignores: ["**/*.stories.tsx"],
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@
|
||||
"@biomejs/biome": "2.5.14",
|
||||
"@changesets/cli": "2.31.1",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@github-ui/storybook-addon-performance-panel": "^1.3.0",
|
||||
"@github-ui/storybook-addon-performance-panel": "^1.3.1",
|
||||
"@storybook/addon-a11y": "^10.6.3",
|
||||
"@storybook/addon-docs": "^10.6.3",
|
||||
"@storybook/addon-themes": "^10.6.3",
|
||||
|
||||
@@ -3026,9 +3026,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@github-ui/storybook-addon-performance-panel@npm:^1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "@github-ui/storybook-addon-performance-panel@npm:1.3.0"
|
||||
"@github-ui/storybook-addon-performance-panel@npm:^1.3.1":
|
||||
version: 1.3.1
|
||||
resolution: "@github-ui/storybook-addon-performance-panel@npm:1.3.1"
|
||||
peerDependencies:
|
||||
"@storybook/icons": ^2.0.0
|
||||
"@storybook/react": ^10.0.0 || >=11.0.0-0 <12.0.0-0
|
||||
@@ -3039,25 +3039,31 @@ __metadata:
|
||||
optional: true
|
||||
react:
|
||||
optional: true
|
||||
checksum: 10/25c956d23a99ea49f11b5dc7dadcaf7084bc7df0ce4644c97db66d13f10a5c76d777f1ae1259cb1a5d6cf60afcb180413429e9c56638281b6e28521db53f750a
|
||||
checksum: 10/f9f1eca61b071d1f1e3eadc9302f6aa17557732225bff88580e259ddcbe33469c045b273daa095095fcc044b63635ce86e36d5adb2c0a5dbeba5eb8ca20f3e3b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@google-cloud/bigquery@npm:^9.0.2":
|
||||
version: 9.0.2
|
||||
resolution: "@google-cloud/bigquery@npm:9.0.2"
|
||||
"@google-cloud/bigquery@npm:^9.5.0":
|
||||
version: 9.5.0
|
||||
resolution: "@google-cloud/bigquery@npm:9.5.0"
|
||||
dependencies:
|
||||
"@google-cloud/common": "npm:^8.0.0"
|
||||
"@google-cloud/paginator": "npm:^7.0.0"
|
||||
"@google-cloud/precise-date": "npm:^6.0.0"
|
||||
"@google-cloud/promisify": "npm:^6.0.0"
|
||||
apache-arrow: "npm:^21.0.0"
|
||||
arrify: "npm:^3.0.0"
|
||||
big.js: "npm:^7.0.0"
|
||||
duplexify: "npm:^4.1.3"
|
||||
extend: "npm:^3.0.2"
|
||||
stream-events: "npm:^1.0.5"
|
||||
teeny-request: "npm:^11.0.0"
|
||||
checksum: 10/4db3af38f51b80bffada28a6dbe2cec02c1f7ccee82a37dbf1b4790584e1bd0606eb34e0eef675571289dd31dfff41931f049d6e4012e09498f5c357266cd266
|
||||
peerDependencies:
|
||||
"@google-cloud/bigquery-storage": ^6.3.0
|
||||
peerDependenciesMeta:
|
||||
"@google-cloud/bigquery-storage":
|
||||
optional: true
|
||||
checksum: 10/b068c895bec6f0fa64cb65e05590f470edec9409725fe6471d476eb7d053036091d754ec25b024318335cbe813438fea56da2082c3353afe9801a59fcb640775
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -3109,11 +3115,11 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@hono/node-server@npm:^1.19.9 || ^2.0.5, @hono/node-server@npm:^2.0.12":
|
||||
version: 2.1.1
|
||||
resolution: "@hono/node-server@npm:2.1.1"
|
||||
version: 2.1.5
|
||||
resolution: "@hono/node-server@npm:2.1.5"
|
||||
peerDependencies:
|
||||
hono: ^4
|
||||
checksum: 10/af031ec46684c7a201cf70ce2e14f17dcd64624b42bbbf5a84dc54d7a2a9fe77a96d3d0280a16affcbc99a2de682f8687ee63cf6f6cc3de2cd5bee22ebe1f7fe
|
||||
hono: ^4 || ^5.0.0-0
|
||||
checksum: 10/4b6f21fe37f956a61856b6f517f91543962f32466a88477d362e8cff77272e541ea6388b8026275e1a2a1976d098c9bf4c3e1d8f8087505e8eac777f0f872901
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -5086,84 +5092,91 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/bundle-analyzer@npm:16.4.2":
|
||||
version: 16.4.2
|
||||
resolution: "@next/bundle-analyzer@npm:16.4.2"
|
||||
"@next/bundle-analyzer@npm:16.4.3":
|
||||
version: 16.4.3
|
||||
resolution: "@next/bundle-analyzer@npm:16.4.3"
|
||||
dependencies:
|
||||
webpack-bundle-analyzer: "npm:4.10.1"
|
||||
checksum: 10/88aff93dac5666bda4dae47c3c28463470abcc2361d3397e37ed20074b58c0a017305f986097cceac5520052caf7fd35b079f1b45b8e3cb19b1438a3564dfe12
|
||||
checksum: 10/cc29a60472950a8c178af34f7e164f8b903455811aeb01b12ae3f2721124485cc20dcf4e941b509c2dbb82e8023174ea01a69d4a90735fd6c7657f35fb245a60
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/env@npm:16.4.2, @next/env@npm:^15.0.0 || ^16.0.0":
|
||||
"@next/env@npm:16.4.3":
|
||||
version: 16.4.3
|
||||
resolution: "@next/env@npm:16.4.3"
|
||||
checksum: 10/61fc8844d0432a0030694486d3a2dc1af58770f81d0f47b7b8b2ce8b8c236f56b83da0d16ba16fef9f2b7d4ce5de6af06e5ca73b722a3d733821b4858b71ddb3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/env@npm:^15.0.0 || ^16.0.0":
|
||||
version: 16.4.2
|
||||
resolution: "@next/env@npm:16.4.2"
|
||||
checksum: 10/6ac734ca99aa1fb31d1130fd6cffdec711ef460cb2b87fa880fa00201c06f61de62bc5d5b7835aa2861087e9587aa1a535ba85dbf37a40979075bc50dac3588f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/eslint-plugin-next@npm:16.4.2":
|
||||
version: 16.4.2
|
||||
resolution: "@next/eslint-plugin-next@npm:16.4.2"
|
||||
"@next/eslint-plugin-next@npm:16.4.3":
|
||||
version: 16.4.3
|
||||
resolution: "@next/eslint-plugin-next@npm:16.4.3"
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils": "npm:4.9.1"
|
||||
fast-glob: "npm:3.3.1"
|
||||
checksum: 10/961ba902b831ddae05a3519862fc43e969be2cd47e0bdc75a070ddfe7136d22c0b7428bfe1fc7863e44c0af913a43317060e318329bb47907d9fd1a1fbc02420
|
||||
checksum: 10/b00bad73eedf18224e9c7700a6f8e990ace898190e2fc004b4dfc5f592d968da2b47b9cffea163b524bddba2aebf9817245bcd6f5259074fb435cb2a1ecb9994
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-arm64@npm:16.4.2":
|
||||
version: 16.4.2
|
||||
resolution: "@next/swc-darwin-arm64@npm:16.4.2"
|
||||
"@next/swc-darwin-arm64@npm:16.4.3":
|
||||
version: 16.4.3
|
||||
resolution: "@next/swc-darwin-arm64@npm:16.4.3"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-x64@npm:16.4.2":
|
||||
version: 16.4.2
|
||||
resolution: "@next/swc-darwin-x64@npm:16.4.2"
|
||||
"@next/swc-darwin-x64@npm:16.4.3":
|
||||
version: 16.4.3
|
||||
resolution: "@next/swc-darwin-x64@npm:16.4.3"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-gnu@npm:16.4.2":
|
||||
version: 16.4.2
|
||||
resolution: "@next/swc-linux-arm64-gnu@npm:16.4.2"
|
||||
"@next/swc-linux-arm64-gnu@npm:16.4.3":
|
||||
version: 16.4.3
|
||||
resolution: "@next/swc-linux-arm64-gnu@npm:16.4.3"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-musl@npm:16.4.2":
|
||||
version: 16.4.2
|
||||
resolution: "@next/swc-linux-arm64-musl@npm:16.4.2"
|
||||
"@next/swc-linux-arm64-musl@npm:16.4.3":
|
||||
version: 16.4.3
|
||||
resolution: "@next/swc-linux-arm64-musl@npm:16.4.3"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-gnu@npm:16.4.2":
|
||||
version: 16.4.2
|
||||
resolution: "@next/swc-linux-x64-gnu@npm:16.4.2"
|
||||
"@next/swc-linux-x64-gnu@npm:16.4.3":
|
||||
version: 16.4.3
|
||||
resolution: "@next/swc-linux-x64-gnu@npm:16.4.3"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-musl@npm:16.4.2":
|
||||
version: 16.4.2
|
||||
resolution: "@next/swc-linux-x64-musl@npm:16.4.2"
|
||||
"@next/swc-linux-x64-musl@npm:16.4.3":
|
||||
version: 16.4.3
|
||||
resolution: "@next/swc-linux-x64-musl@npm:16.4.3"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-arm64-msvc@npm:16.4.2":
|
||||
version: 16.4.2
|
||||
resolution: "@next/swc-win32-arm64-msvc@npm:16.4.2"
|
||||
"@next/swc-win32-arm64-msvc@npm:16.4.3":
|
||||
version: 16.4.3
|
||||
resolution: "@next/swc-win32-arm64-msvc@npm:16.4.3"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-x64-msvc@npm:16.4.2":
|
||||
version: 16.4.2
|
||||
resolution: "@next/swc-win32-x64-msvc@npm:16.4.2"
|
||||
"@next/swc-win32-x64-msvc@npm:16.4.3":
|
||||
version: 16.4.3
|
||||
resolution: "@next/swc-win32-x64-msvc@npm:16.4.3"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@@ -8509,6 +8522,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node@npm:^25.2.0":
|
||||
version: 25.9.9
|
||||
resolution: "@types/node@npm:25.9.9"
|
||||
dependencies:
|
||||
undici-types: "npm:>=7.24.0 <7.24.7"
|
||||
checksum: 10/8accbdd15bc035db3b20bf9353dabce847a5d3dd1f3976c25e67907f4fd287b00b8163f661fe48cd6d644e30a11e1dffd67e2742233209c7b7cbc500d14d394c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/parse-json@npm:^4.0.0":
|
||||
version: 4.0.2
|
||||
resolution: "@types/parse-json@npm:4.0.2"
|
||||
@@ -9890,7 +9912,7 @@ __metadata:
|
||||
"@biomejs/biome": "npm:2.5.14"
|
||||
"@changesets/cli": "npm:2.31.1"
|
||||
"@eslint/js": "npm:^10.0.1"
|
||||
"@github-ui/storybook-addon-performance-panel": "npm:^1.3.0"
|
||||
"@github-ui/storybook-addon-performance-panel": "npm:^1.3.1"
|
||||
"@storybook/addon-a11y": "npm:^10.6.3"
|
||||
"@storybook/addon-docs": "npm:^10.6.3"
|
||||
"@storybook/addon-themes": "npm:^10.6.3"
|
||||
@@ -10056,6 +10078,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"apache-arrow@npm:^21.0.0":
|
||||
version: 21.2.0
|
||||
resolution: "apache-arrow@npm:21.2.0"
|
||||
dependencies:
|
||||
"@types/node": "npm:^25.2.0"
|
||||
flatbuffers: "npm:^25.1.24"
|
||||
json-with-bigint: "npm:^3.5.3"
|
||||
tslib: "npm:^2.6.2"
|
||||
bin:
|
||||
arrow2csv: bin/arrow2csv.js
|
||||
checksum: 10/209850cda893c54e87a65d12548120ee1b0ed071682c6113d75aba8a662a2eddfa3d507e8441658842478d56759de2078da3e6a42b57914d37fd53eed2e977b0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"arg@npm:^5.0.2":
|
||||
version: 5.0.2
|
||||
resolution: "arg@npm:5.0.2"
|
||||
@@ -10696,25 +10732,25 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"body-parser@npm:^2.2.1":
|
||||
version: 2.3.0
|
||||
resolution: "body-parser@npm:2.3.0"
|
||||
version: 2.4.0
|
||||
resolution: "body-parser@npm:2.4.0"
|
||||
dependencies:
|
||||
bytes: "npm:^3.1.2"
|
||||
content-type: "npm:^2.0.0"
|
||||
content-type: "npm:^2.1.0"
|
||||
debug: "npm:^4.4.3"
|
||||
http-errors: "npm:^2.0.1"
|
||||
iconv-lite: "npm:^0.7.2"
|
||||
iconv-lite: "npm:^0.7.3"
|
||||
on-finished: "npm:^2.4.1"
|
||||
qs: "npm:^6.15.2"
|
||||
qs: "npm:^6.16.1"
|
||||
raw-body: "npm:^3.0.2"
|
||||
type-is: "npm:^2.1.0"
|
||||
checksum: 10/94f741ff525358dd0d47f0a042936dc61b9d2e348ff1228c5ffd79f1902c673a317bbb9495b3f7d1db4483befe6ffed1c42bc4cdd8da8f41690530810cfe4dad
|
||||
checksum: 10/e34971abf7051529d4fae37d3714382e7fa8198bc969f1ec4932af48aef53bba71523545c034ce04fa808d3b15e0d63849e6e93b4f1131d65227e1f414437f68
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"body-parser@npm:~1.20.5":
|
||||
version: 1.20.8
|
||||
resolution: "body-parser@npm:1.20.8"
|
||||
version: 1.20.9
|
||||
resolution: "body-parser@npm:1.20.9"
|
||||
dependencies:
|
||||
bytes: "npm:~3.1.2"
|
||||
content-type: "npm:~1.0.5"
|
||||
@@ -10728,7 +10764,7 @@ __metadata:
|
||||
raw-body: "npm:~2.5.3"
|
||||
type-is: "npm:~1.6.18"
|
||||
unpipe: "npm:~1.0.0"
|
||||
checksum: 10/e5a13ff68066a49823403f93ffe056611d9696182e6de194cd1a3c5b2159457494d4133b4666bad591d7a5a6eb924dd34dd15c83aa2d11c63800ed4d2395b5eb
|
||||
checksum: 10/e9ccf7a920205d674a83cdfae0e83ed3cfe32af668706034e9832a8bf3b80f06fbc18a7c26759611f72d334311683a4b1ff73661690038a352e8c3b4a424b709
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -14160,6 +14196,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"flatbuffers@npm:^25.1.24":
|
||||
version: 25.9.23
|
||||
resolution: "flatbuffers@npm:25.9.23"
|
||||
checksum: 10/e2086e7f9b04f7932a93f6935347d8cdca0cbdcb582cd23b2b7c55aa1f831c6e33ba595c49bebe25767a945fc4698984840692baa470d61db4484e06aac4df15
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"flatted@npm:^3.2.9, flatted@npm:^3.4.2":
|
||||
version: 3.4.4
|
||||
resolution: "flatted@npm:3.4.4"
|
||||
@@ -14193,12 +14236,12 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"follow-redirects@npm:^1.0.0":
|
||||
version: 1.16.1
|
||||
resolution: "follow-redirects@npm:1.16.1"
|
||||
version: 1.16.2
|
||||
resolution: "follow-redirects@npm:1.16.2"
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
checksum: 10/269c9f38e4bb413d7ab224fb5aa733118288a18e84d4d0a22821a850574624a55d45f2c6735fc09fc1cceedb6343a5539daf6d2dd70bce8980c8336d230a2f50
|
||||
checksum: 10/3303addfa9aaf145022c2faa76ecba8052fe325bce00f3992ca2b13f3295590d6a64828c128cfcbc9678569f2f98fbd190d6ca5f505857b07eea9867008a38a3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -15440,7 +15483,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"iconv-lite@npm:^0.7.0, iconv-lite@npm:^0.7.2, iconv-lite@npm:~0.7.0":
|
||||
"iconv-lite@npm:^0.7.0, iconv-lite@npm:^0.7.2, iconv-lite@npm:^0.7.3, iconv-lite@npm:~0.7.0":
|
||||
version: 0.7.3
|
||||
resolution: "iconv-lite@npm:0.7.3"
|
||||
dependencies:
|
||||
@@ -16701,6 +16744,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"json-with-bigint@npm:^3.5.3":
|
||||
version: 3.5.12
|
||||
resolution: "json-with-bigint@npm:3.5.12"
|
||||
checksum: 10/096a98e435311ab7cdc645769b949cda0cc723b2f1fd0dd5e86839432a703e804a99136da658536e86b876a85d193a87066352e6723dbcc498439fc6c3c34d5c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"json5@npm:2.2.3, json5@npm:^2.2.2, json5@npm:^2.2.3":
|
||||
version: 2.2.3
|
||||
resolution: "json5@npm:2.2.3"
|
||||
@@ -18538,19 +18588,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next@npm:16.4.2":
|
||||
version: 16.4.2
|
||||
resolution: "next@npm:16.4.2"
|
||||
"next@npm:16.4.3":
|
||||
version: 16.4.3
|
||||
resolution: "next@npm:16.4.3"
|
||||
dependencies:
|
||||
"@next/env": "npm:16.4.2"
|
||||
"@next/swc-darwin-arm64": "npm:16.4.2"
|
||||
"@next/swc-darwin-x64": "npm:16.4.2"
|
||||
"@next/swc-linux-arm64-gnu": "npm:16.4.2"
|
||||
"@next/swc-linux-arm64-musl": "npm:16.4.2"
|
||||
"@next/swc-linux-x64-gnu": "npm:16.4.2"
|
||||
"@next/swc-linux-x64-musl": "npm:16.4.2"
|
||||
"@next/swc-win32-arm64-msvc": "npm:16.4.2"
|
||||
"@next/swc-win32-x64-msvc": "npm:16.4.2"
|
||||
"@next/env": "npm:16.4.3"
|
||||
"@next/swc-darwin-arm64": "npm:16.4.3"
|
||||
"@next/swc-darwin-x64": "npm:16.4.3"
|
||||
"@next/swc-linux-arm64-gnu": "npm:16.4.3"
|
||||
"@next/swc-linux-arm64-musl": "npm:16.4.3"
|
||||
"@next/swc-linux-x64-gnu": "npm:16.4.3"
|
||||
"@next/swc-linux-x64-musl": "npm:16.4.3"
|
||||
"@next/swc-win32-arm64-msvc": "npm:16.4.3"
|
||||
"@next/swc-win32-x64-msvc": "npm:16.4.3"
|
||||
"@swc/helpers": "npm:0.5.23"
|
||||
baseline-browser-mapping: "npm:^2.9.19"
|
||||
caniuse-lite: "npm:^1.0.30001579"
|
||||
@@ -18594,7 +18644,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
next: dist/bin/next
|
||||
checksum: 10/f72af6bfb2d469d3ee29551c221a8fc48f5b4f4a7b685b6e1897458657607186fac34867f42ec66a67e9d5dc72e7e97abf08db875ba0ce921876b19c63617dc4
|
||||
checksum: 10/4473274bcb1da4921d33b81f8e6c25ac2a9ee959fee49b538bd186550c641111a74b42e85ad406842c1ae471ead49ed98ce1eae699d64f8fa55dc67c14557ee7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -20419,7 +20469,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"qs@npm:^6.12.3, qs@npm:^6.14.0, qs@npm:^6.15.2, qs@npm:~6.15.1":
|
||||
"qs@npm:^6.12.3, qs@npm:^6.14.0, qs@npm:~6.15.1":
|
||||
version: 6.15.3
|
||||
resolution: "qs@npm:6.15.3"
|
||||
dependencies:
|
||||
@@ -20429,7 +20479,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"qs@npm:~6.16.0":
|
||||
"qs@npm:^6.16.1, qs@npm:~6.16.0":
|
||||
version: 6.16.1
|
||||
resolution: "qs@npm:6.16.1"
|
||||
dependencies:
|
||||
@@ -23925,7 +23975,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.8.0, tslib@npm:^2.8.1":
|
||||
"tslib@npm:^2.0.0, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.6.2, tslib@npm:^2.8.0, tslib@npm:^2.8.1":
|
||||
version: 2.8.1
|
||||
resolution: "tslib@npm:2.8.1"
|
||||
checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7
|
||||
@@ -24214,6 +24264,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"undici-types@npm:>=7.24.0 <7.24.7":
|
||||
version: 7.24.6
|
||||
resolution: "undici-types@npm:7.24.6"
|
||||
checksum: 10/defc9538b952e3c15b8526596c591f7c1f0c7605ad27a2b7feddbea7ef2e3003f3eda2cdb051a3cb1a2185e3893100fd9cb925c799db99d48131ea63b5233d10
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"undici-types@npm:~7.18.0":
|
||||
version: 7.18.2
|
||||
resolution: "undici-types@npm:7.18.2"
|
||||
@@ -25135,12 +25192,12 @@ __metadata:
|
||||
"@babel/core": "npm:^7.19.0"
|
||||
"@babel/parser": "npm:^7.27.5"
|
||||
"@babel/traverse": "npm:^7.27.4"
|
||||
"@google-cloud/bigquery": "npm:^9.0.2"
|
||||
"@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"
|
||||
"@next/bundle-analyzer": "npm:16.4.2"
|
||||
"@next/eslint-plugin-next": "npm:16.4.2"
|
||||
"@next/bundle-analyzer": "npm:16.4.3"
|
||||
"@next/eslint-plugin-next": "npm:16.4.3"
|
||||
"@playwright/test": "npm:1.61.1"
|
||||
"@portabletext/block-tools": "npm:^6.0.0"
|
||||
"@portabletext/markdown": "npm:^2.5.1"
|
||||
@@ -25171,7 +25228,7 @@ __metadata:
|
||||
json5: "npm:2.2.3"
|
||||
lodash: "npm:4.18.1"
|
||||
lz-string: "npm:^1.5.0"
|
||||
next: "npm:16.4.2"
|
||||
next: "npm:16.4.3"
|
||||
next-logger: "npm:^5.0.2"
|
||||
next-sanity: "npm:13.2.3"
|
||||
next-themes: "npm:^0.4.6"
|
||||
|
||||
Reference in new issue
Block a user