import { PintGlassIcon, WindIcon } from "@phosphor-icons/react";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { useRef, useState } from "react";
import type { DSSuggestionElement } from "../";
import type { FieldSuggestionSelected } from "../react";
import { Field, Flex, Input } from "../react";
import styles from "../styles.module.css";
const meta = {
title: "Designsystem/Field",
argTypes: {
as: {
description: "Element type",
table: {
defaultValue: { summary: "input" },
type: { summary: "input | textarea | select" },
},
},
type: {
description: "Input type",
table: {
type: { summary: "text | checkbox | radio | ..." },
},
},
label: {
description: "Label text",
table: {
type: { summary: "React.ReactNode" },
},
},
description: {
description: "Description text",
table: {
type: { summary: "React.ReactNode" },
},
},
value: {
description: "Value",
table: {
type: { summary: "string" },
},
},
checked: {
description: 'If `type="checkbox"` or `type="radio"`',
table: {
type: { summary: "boolean" },
},
},
validation: {
description: "Validation message",
table: {
type: { summary: "React.ReactNode" },
},
},
count: {
description: "Character count",
table: {
type: { summary: "number" },
},
},
options: {
description: 'If `as="select"` or `as={Field.Suggestion}`',
table: {
type: {
summary:
"string[] | { label: string; value: string; children?: React.ReactNode }[]",
},
},
},
prefix: {
description: "Prefix",
table: {
type: { summary: "string" },
},
},
suffix: {
description: "Suffix",
table: {
type: { summary: "string" },
},
},
helpText: {
description: "What to display in HelpText",
table: {
type: { summary: "React.ReactNode" },
},
},
helpTextLabel: {
description: "Label of HelpText button",
table: {
type: { summary: "string" },
},
},
"data-nofilter": {
description: "If `as={Field.Suggestion}`",
table: {
type: { summary: "boolean" },
},
},
selected: {
description: "If `as={Field.Suggestion}`",
table: {
type: {
summary:
"{ label: string; value: string; children?: React.ReactNode }[]",
},
},
},
onSelectedChange: {
description: "If `as={Field.Suggestion}`",
table: {
type: { summary: "(selected) => void" },
},
},
},
decorators: [
(Story) => (
),
],
} satisfies Meta;
export default meta;
type Story = StoryObj;
export const Default: Story = {
render: () => (
Beskrivelse
),
};
export const React: Story = {
render: () => (
<>
Field uten as attributt lar deg bygge opp av bestanddeler:
Ledetekst
Beskrivelse
Field med as="input" gir deg en komplett field med
label + description + input +{" "}
error + prefix + suffix:
Field med as="input" og type="checkbox":
Field med as="textarea" og{" "}
count={15}:
Field med as="select":
>
),
};
export const Required: Story = {
parameters: { showInOverview: true },
render: () => (
Beskrivelse
),
};
export const Indeterminate: Story = {
render: function Render() {
const [checked, setChecked] = useState(["1", "2"]);
const all = ["1", "2", "3"];
const isAll = checked.length === all.length;
const onChange = ({ target }: React.ChangeEvent) =>
setChecked(
checked.includes(target.value)
? checked.filter((v) => v !== target.value)
: [...checked, target.value],
);
return (
);
},
};
export const Toggles: Story = {
render: () => (
<>
>
),
};
export const WithValidation: Story = {
parameters: { showInOverview: true },
render: () => (
Beskrivelse
Validation
),
};
export const WithValidationForm: Story = {
parameters: { layout: "padded" },
name: "With Validation Form",
render: () => {
const [selected, setSelected] = useState([]);
return (
);
},
};
export const WithAffixes: Story = {
parameters: {
showInOverview: true,
},
render: () => (
NOK
pr. mnd.
),
};
export const WithCharacterCount: Story = {
parameters: {
layout: "padded",
showInOverview: true,
},
render: () => (
Beskrivelse
),
};
export const WithCustomDescriptionTag: Story = {
parameters: { layout: "padded" },
render: () => (
Beskrivelse i en data-field="description" som virker med
og uten <p>
),
};
export const WithSuggestion: Story = {
parameters: {
layout: "padded",
},
render: () => (
Sogndal
Oslo
Brønnøysund
Stavanger
Trondheim
Bergen
Lillestrøm
),
};
export const WithSuggestionMultiple: Story = {
parameters: {
layout: "padded",
},
render: () => (
Sogndal
Sogndal
Oslo
Brønnøysund
Stavanger
Trondheim
Bergen
Lillestrøm
),
};
export const WithSuggestionMultipleInside: Story = {
parameters: {
layout: "padded",
},
render: () => (
Sogndal
Sogndal
Oslo
Brønnøysund
Stavanger
Trondheim
Bergen
Lillestrøm
),
};
export const WithSuggestionCreatable: Story = {
parameters: {
layout: "padded",
},
render: () => (
Sogndal
Sogndal
Oslo
Brønnøysund
Stavanger
Trondheim
Bergen
Lillestrøm
),
};
export const WithSuggestionNoResults: Story = {
parameters: {
layout: "padded",
},
render: () => (
Ingen treff
Sogndal
Oslo
Brønnøysund
Stavanger
Trondheim
Bergen
Lillestrøm
),
};
export const WithSuggestionAPI: Story = {
parameters: {
layout: "padded",
},
render: () => {
const [options, setOptions] = useState("Name a country"); // Store results
const timer = useRef | number>(0);
const getCountries = async (value: string) => {
if (!value) return setOptions("Name a country");
const api = `https://dummyjson.com/recipes/search?q=${value}`; // TODO FIX
const data = await (await fetch(api)).json();
setOptions(
Array.isArray(data.recipes)
? data.recipes.map(({ name }: { name: string }) => name)
: "No results",
);
};
const handleInput = (event: React.InputEvent) => {
const value = encodeURIComponent(event.currentTarget.value.trim());
setOptions(value ? "Loading..." : "Find a recipe");
clearTimeout(timer.current);
timer.current = setTimeout(getCountries, 500, value); // Debounce API call
};
return (
{Array.isArray(options) ? (
options.map((option) => (
{option}
))
) : (
{options}
)}
);
},
};
export const WithSuggestionCustomFilter: Story = {
parameters: {
layout: "padded",
},
render: () => {
const ref = useRef(null);
const [value, setValue] = useState("");
const options = [
"Sogndal",
"Oslo",
"Brønnøysund",
"Stavanger",
"Trondheim",
"Bergen",
"Lillestrøm",
];
return (
setValue(currentTarget.value)}
/>
{options
.filter((option) =>
option.toLowerCase().startsWith(value.toLowerCase()),
)
.map((option) => (
{option}
))}
);
},
};
export const ReactWithSuggestion: Story = {
parameters: {
layout: "padded",
},
render: function Render() {
// IMPORTANT:
// Using Field.Suggestion requires
// "use client" if doing server-side rendering
const [selected, setSelected] = useState([
{ value: "saft", label: "Saft" },
]);
return (
Suse
),
},
]}
/>
);
},
};
export const ReactWithSuggestionWithChildren: Story = {
parameters: {
layout: "padded",
},
render: function Render() {
const multiple = true;
const [selected, setSelected] = useState([]);
return (
React med Field.Suggestion med barn
Hvis Field.Suggestion har barn, tegner den ikke input selv.
Saft
Suse
);
},
};
export const ReactWithSuggestionMultiple: Story = {
parameters: {
layout: "padded",
},
render: function Render() {
// IMPORTANT:
// Using Field.Suggestion requires
// "use client" if doing server-side rendering
const [selected, setSelected] = useState([
{ value: "saft", label: "Saft" },
]);
return (
);
},
};
export const ReactWithSuggestionMultipleInside: Story = {
parameters: {
layout: "padded",
},
render: function Render() {
// IMPORTANT:
// Using Field.Suggestion requires
// "use client" if doing server-side rendering
const [selected, setSelected] = useState([
{ value: "saft", label: "Saft" },
]);
return (
);
},
};
export const ReactWithSuggestionCreatable: Story = {
parameters: {
layout: "padded",
},
render: function Render() {
// IMPORTANT:
// Using Field.Suggestion requires
// "use client" if doing server-side rendering
const [selected, setSelected] = useState([
{ value: "saft", label: "Saft" },
]);
return (
);
},
};
export const ReactWithSuggestionLong: Story = {
parameters: {
layout: "padded",
},
render: () => {
// IMPORTANT:
// Using Field.Suggestion requires
// "use client" if doing server-side rendering
const [selected, setSelected] = useState([]);
return (
<>
React med lange og mange
Beskrivelse
Thunder Thunder Thunder Thunder Thunder Thunder Thunder Thunder
Thunder Thunder Thunder Thunder Thunder
Whisper
Galaxy
Melody
Crystal
Sunset
Journey
Phoenix
Harmony
Neptune
Cascade
Velvet
Rhythm
Compass
Prism
Breeze
Eclipse
Sterling
Canvas
Zenith
>
);
},
};
export const ReactWithSuggestionCustomFilter: Story = {
parameters: {
layout: "padded",
},
render: function Render() {
const [value, setValue] = useState("");
const [selected, setSelected] = useState([]);
const options = [
"Sogndal",
"Oslo",
"Brønnøysund",
"Stavanger",
"Trondheim",
"Bergen",
"Lillestrøm",
];
return (
Filterer på starten av ordet
opt.toLowerCase().startsWith(value.toLowerCase()))
.map((value) => ({ label: value, value }))}
>
setValue(currentTarget.value)}
/>
);
},
};