@navikt/ds-react 5.18.0 → 5.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/cjs/date/parts/DateWrapper.js +2 -2
  2. package/cjs/form/search/Search.js +1 -1
  3. package/cjs/modal/Modal.context.js +9 -0
  4. package/cjs/modal/Modal.js +3 -6
  5. package/cjs/modal/ModalHeader.js +2 -6
  6. package/cjs/panel/Panel.js +6 -16
  7. package/cjs/popover/Popover.js +2 -2
  8. package/cjs/tooltip/Tooltip.js +2 -2
  9. package/cjs/util/create-context.js +9 -5
  10. package/esm/date/parts/DateWrapper.js +3 -3
  11. package/esm/date/parts/DateWrapper.js.map +1 -1
  12. package/esm/form/search/Search.js +1 -1
  13. package/esm/modal/Modal.context.d.ts +9 -0
  14. package/esm/modal/Modal.context.js +6 -0
  15. package/esm/modal/Modal.context.js.map +1 -0
  16. package/esm/modal/Modal.js +3 -6
  17. package/esm/modal/Modal.js.map +1 -1
  18. package/esm/modal/ModalHeader.js +3 -7
  19. package/esm/modal/ModalHeader.js.map +1 -1
  20. package/esm/panel/Panel.d.ts +9 -16
  21. package/esm/panel/Panel.js +6 -16
  22. package/esm/panel/Panel.js.map +1 -1
  23. package/esm/popover/Popover.js +2 -2
  24. package/esm/popover/Popover.js.map +1 -1
  25. package/esm/tooltip/Tooltip.js +3 -3
  26. package/esm/tooltip/Tooltip.js.map +1 -1
  27. package/esm/util/create-context.d.ts +2 -5
  28. package/esm/util/create-context.js +10 -6
  29. package/esm/util/create-context.js.map +1 -1
  30. package/package.json +3 -3
  31. package/src/accordion/accordion.stories.tsx +121 -135
  32. package/src/alert/alert.stories.tsx +202 -113
  33. package/src/button/button.stories.tsx +88 -185
  34. package/src/chat/chat.stories.tsx +284 -206
  35. package/src/date/datepicker/datepicker.stories.tsx +6 -2
  36. package/src/date/monthpicker/monthpicker.stories.tsx +2 -1
  37. package/src/date/parts/DateWrapper.tsx +3 -3
  38. package/src/dropdown/dropdown.stories.tsx +1 -1
  39. package/src/form/error-summary/error-summary.stories.tsx +1 -1
  40. package/src/form/search/Search.tsx +3 -3
  41. package/src/form/stories/confirmation-panel.stories.tsx +1 -1
  42. package/src/help-text/help-text.stories.tsx +2 -1
  43. package/src/internal-header/header.stories.tsx +2 -1
  44. package/src/layout/bleed/Bleed.stories.tsx +2 -1
  45. package/src/layout/box/Box.stories.tsx +2 -1
  46. package/src/layout/sidemal-test/navno-sidemal.stories.tsx +5 -1
  47. package/src/link/stories/link.stories.tsx +20 -22
  48. package/src/link-panel/link-panel.stories.tsx +1 -1
  49. package/src/list/list.stories.tsx +2 -1
  50. package/src/loader/loader.stories.tsx +1 -1
  51. package/src/modal/Modal.context.ts +13 -0
  52. package/src/modal/Modal.tsx +6 -8
  53. package/src/modal/ModalHeader.tsx +3 -7
  54. package/src/modal/modal.stories.tsx +3 -1
  55. package/src/panel/Panel.tsx +9 -16
  56. package/src/popover/Popover.tsx +2 -2
  57. package/src/stepper/stepper.stories.tsx +1 -1
  58. package/src/table/stories/{table.stories.tsx → table-1.stories.tsx} +118 -92
  59. package/src/table/stories/{table-expandable.stories.tsx → table-2-expandable.stories.tsx} +10 -34
  60. package/src/table/stories/{table-async.stories.tsx → table-3-async.stories.tsx} +5 -3
  61. package/src/table/stories/tests/table.stories.tsx +4 -1
  62. package/src/tabs/Tabs.test.tsx +109 -0
  63. package/src/toggle-group/ToggleGroup.test.tsx +54 -0
  64. package/src/tooltip/Tooltip.tsx +3 -9
  65. package/src/tooltip/tooltip.stories.tsx +4 -1
  66. package/src/typography/stories/bodylong.stories.tsx +49 -3
  67. package/src/typography/stories/bodyshort.stories.tsx +50 -4
  68. package/src/typography/stories/detail.stories.tsx +32 -3
  69. package/src/typography/stories/error-message.stories.tsx +34 -3
  70. package/src/typography/stories/heading.stories.tsx +32 -3
  71. package/src/typography/stories/label.stories.tsx +38 -3
  72. package/src/util/create-context.tsx +26 -15
  73. package/cjs/modal/ModalContext.js +0 -8
  74. package/esm/modal/ModalContext.d.ts +0 -7
  75. package/esm/modal/ModalContext.js +0 -3
  76. package/esm/modal/ModalContext.js.map +0 -1
  77. package/src/modal/ModalContext.ts +0 -7
  78. package/src/panel/panel.stories.tsx +0 -63
  79. package/src/typography/stories/ingress.stories.tsx +0 -50
@@ -0,0 +1,109 @@
1
+ import { fireEvent, render, screen } from "@testing-library/react";
2
+ import React from "react";
3
+ import { Tabs } from "./Tabs";
4
+
5
+ const TestTabs = ({
6
+ value,
7
+ onChange,
8
+ defaultValue,
9
+ selectionFollowsFocus,
10
+ loop,
11
+ iconPosition,
12
+ }: any) => (
13
+ <Tabs
14
+ value={value}
15
+ onChange={onChange}
16
+ defaultValue={defaultValue}
17
+ selectionFollowsFocus={selectionFollowsFocus}
18
+ loop={loop}
19
+ iconPosition={iconPosition}
20
+ >
21
+ <Tabs.List data-testid="tablist">
22
+ <Tabs.Tab value="tab1" data-testid="tab1" label="Tab 1" />
23
+ <Tabs.Tab value="tab2" data-testid="tab2" label="Tab 2" />
24
+ <Tabs.Tab value="tab3" data-testid="tab3" label="Tab 3" />
25
+ </Tabs.List>
26
+ <Tabs.Panel value="tab1" data-testid="tabpanel1">
27
+ Tabpanel 1
28
+ </Tabs.Panel>
29
+ <Tabs.Panel value="tab2" data-testid="tabpanel2">
30
+ Tabpanel 2
31
+ </Tabs.Panel>
32
+ <Tabs.Panel value="tab3" data-testid="tabpanel3">
33
+ Tabpanel 3
34
+ </Tabs.Panel>
35
+ </Tabs>
36
+ );
37
+
38
+ describe("Tabs", () => {
39
+ test("sets default value correctly", () => {
40
+ render(<TestTabs defaultValue="tab2" />);
41
+ const tab = screen.getByTestId("tab2");
42
+ const panel = screen.getByTestId("tabpanel2");
43
+
44
+ expect(tab).toHaveAttribute("aria-selected", "true");
45
+ expect(panel).toHaveTextContent("Tabpanel 2");
46
+ });
47
+
48
+ test("label-connection between tab and tabpanel is correct", async () => {
49
+ render(<TestTabs defaultValue="tab2" />);
50
+ const tab = screen.getByTestId("tab2");
51
+ const panel = screen.getByTestId("tabpanel2");
52
+
53
+ const controlsId = tab.getAttribute("aria-controls");
54
+ const panelLabelledBy = panel.getAttribute("aria-labelledby");
55
+
56
+ expect(controlsId).toEqual(panel.id);
57
+ expect(tab.id).toEqual(panelLabelledBy);
58
+ });
59
+
60
+ test("sets correct attributes on active tab", () => {
61
+ render(<TestTabs defaultValue="tab2" />);
62
+ const tab = screen.getByTestId("tab2");
63
+
64
+ expect(tab).toHaveAttribute("aria-selected", "true");
65
+ expect(tab).toHaveAttribute("role", "tab");
66
+ expect(tab).toHaveAttribute("aria-controls");
67
+ expect(tab).toHaveAttribute("tabindex", "-1");
68
+ });
69
+
70
+ test("sets correct attributes on idle tab", () => {
71
+ render(<TestTabs defaultValue="tab2" />);
72
+ const tab = screen.getByTestId("tab1");
73
+
74
+ expect(tab).toHaveAttribute("aria-selected", "false");
75
+ expect(tab).toHaveAttribute("role", "tab");
76
+ expect(tab).toHaveAttribute("aria-controls");
77
+ expect(tab).toHaveAttribute("tabindex", "-1");
78
+ });
79
+
80
+ test("sets correct attributes on active tabpanel", () => {
81
+ render(<TestTabs defaultValue="tab2" />);
82
+ const panel = screen.getByTestId("tabpanel2");
83
+
84
+ expect(panel).toHaveAttribute("aria-labelledby");
85
+ expect(panel).toHaveAttribute("role", "tabpanel");
86
+ expect(panel).toHaveAttribute("tabindex", "0");
87
+ expect(panel).toHaveTextContent("Tabpanel 2");
88
+ expect(panel).toHaveStyle({ display: "block" });
89
+ });
90
+
91
+ test("sets correct attributes on idle tabpanel", () => {
92
+ render(<TestTabs defaultValue="tab1" />);
93
+ const panel = screen.getByTestId("tabpanel2");
94
+
95
+ expect(panel).toHaveAttribute("aria-labelledby");
96
+ expect(panel).toHaveAttribute("role", "tabpanel");
97
+ expect(panel).toHaveAttribute("tabindex", "0");
98
+ expect(panel).toBeEmptyDOMElement();
99
+ expect(panel).toHaveStyle({ display: "none" });
100
+ });
101
+
102
+ test("sets tabindex to 0 when focused", () => {
103
+ render(<TestTabs defaultValue="tab2" />);
104
+ const tab = screen.getByTestId("tab2");
105
+
106
+ fireEvent.focus(tab);
107
+ expect(tab).toHaveAttribute("tabindex", "0");
108
+ });
109
+ });
@@ -0,0 +1,54 @@
1
+ import { fireEvent, render, screen } from "@testing-library/react";
2
+ import React from "react";
3
+ import { ToggleGroup } from "./ToggleGroup";
4
+
5
+ const TestToggleGroup = ({ value, onChange, defaultValue }: any) => (
6
+ <ToggleGroup value={value} onChange={onChange} defaultValue={defaultValue}>
7
+ <ToggleGroup.Item value="toggle1" data-testid="toggle1">
8
+ Toggle 1
9
+ </ToggleGroup.Item>
10
+ <ToggleGroup.Item value="toggle2" data-testid="toggle2">
11
+ Toggle 2
12
+ </ToggleGroup.Item>
13
+ <ToggleGroup.Item value="toggle3" data-testid="toggle3">
14
+ Toggle 3
15
+ </ToggleGroup.Item>
16
+ </ToggleGroup>
17
+ );
18
+
19
+ describe("ToggleGroup", () => {
20
+ test("sets default value correctly", () => {
21
+ render(<TestToggleGroup defaultValue="toggle2" />);
22
+ const toggle = screen.getByTestId("toggle2");
23
+
24
+ expect(toggle).toHaveAttribute("aria-checked", "true");
25
+ });
26
+
27
+ test("sets correct attributes on active toggle", () => {
28
+ render(<TestToggleGroup defaultValue="toggle2" />);
29
+ const toggle = screen.getByTestId("toggle2");
30
+
31
+ expect(toggle).toHaveAttribute("aria-checked", "true");
32
+ expect(toggle).toHaveAttribute("role", "radio");
33
+ expect(toggle).toHaveAttribute("type", "button");
34
+ expect(toggle).toHaveAttribute("tabindex", "-1");
35
+ });
36
+
37
+ test("sets correct attributes on idle toggle", () => {
38
+ render(<TestToggleGroup defaultValue="toggle1" />);
39
+ const toggle = screen.getByTestId("toggle2");
40
+
41
+ expect(toggle).toHaveAttribute("aria-checked", "false");
42
+ expect(toggle).toHaveAttribute("role", "radio");
43
+ expect(toggle).toHaveAttribute("type", "button");
44
+ expect(toggle).toHaveAttribute("tabindex", "-1");
45
+ });
46
+
47
+ test("sets tabindex to 0 when focused", () => {
48
+ render(<TestToggleGroup defaultValue="toggle2" />);
49
+ const toggle = screen.getByTestId("toggle2");
50
+
51
+ fireEvent.focus(toggle);
52
+ expect(toggle).toHaveAttribute("tabindex", "0");
53
+ });
54
+ });
@@ -12,14 +12,8 @@ import {
12
12
  useInteractions,
13
13
  } from "@floating-ui/react";
14
14
  import cl from "clsx";
15
- import React, {
16
- HTMLAttributes,
17
- cloneElement,
18
- forwardRef,
19
- useContext,
20
- useRef,
21
- } from "react";
22
- import { ModalContext } from "../modal/ModalContext";
15
+ import React, { HTMLAttributes, cloneElement, forwardRef, useRef } from "react";
16
+ import { useModalContext } from "../modal/Modal.context";
23
17
  import Portal from "../overlays/portal/Portal";
24
18
  import { Detail } from "../typography";
25
19
  import { useId } from "../util/hooks";
@@ -121,7 +115,7 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
121
115
  });
122
116
 
123
117
  const arrowRef = useRef<HTMLDivElement | null>(null);
124
- const modalContext = useContext(ModalContext);
118
+ const modalContext = useModalContext(false);
125
119
  const rootElement = modalContext ? modalContext.ref.current : undefined;
126
120
 
127
121
  const {
@@ -1,6 +1,9 @@
1
1
  import { Meta } from "@storybook/react";
2
2
  import React from "react";
3
- import { Alert, Button, Search, Tooltip } from "..";
3
+ import { Alert } from "../alert";
4
+ import { Button } from "../button";
5
+ import { Search } from "../form";
6
+ import Tooltip from "./Tooltip";
4
7
 
5
8
  export default {
6
9
  title: "ds-react/Tooltip",
@@ -1,13 +1,16 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { expect, within } from "@storybook/test";
3
3
  import React from "react";
4
- import { BodyLong } from "..";
5
- import { VStack } from "../..";
4
+ import { VStack } from "../../layout/stack";
5
+ import BodyLong from "../BodyLong";
6
6
 
7
7
  const meta = {
8
8
  title: "ds-react/Typography/BodyLong",
9
9
  component: BodyLong,
10
10
  decorators: [(story) => <div style={{ maxWidth: "700px" }}>{story()}</div>],
11
+ parameters: {
12
+ chromatic: { disable: true },
13
+ },
11
14
  } satisfies Meta<typeof BodyLong>;
12
15
 
13
16
  export default meta;
@@ -17,7 +20,7 @@ type Story = StoryObj<typeof meta>;
17
20
  const lorem =
18
21
  "Hvis du ikke bor sammen med begge foreldrene dine, kan du ha rett til barnebidrag fra en eller begge foreldre mens du fullfører videregående skole eller tilsvarende.";
19
22
 
20
- export const Default: Story = {
23
+ export const Controls: Story = {
21
24
  args: {
22
25
  spacing: false,
23
26
  children: lorem,
@@ -162,3 +165,46 @@ export const OverrideTag: Story = {
162
165
  expect(legendBodyLong.tagName).toEqual("LEGEND");
163
166
  },
164
167
  };
168
+
169
+ export const Chromatic: Story = {
170
+ render: (...props) => (
171
+ <div>
172
+ <div>
173
+ <h2>Large</h2>
174
+ <h3>Size</h3>
175
+ {SizeLarge.render?.(...props)}
176
+ <h3>Spacing</h3>
177
+ {SpacingLarge.render?.(...props)}
178
+ </div>
179
+ <div>
180
+ <h2>Medium</h2>
181
+ <h3>Size</h3>
182
+ {SizeMedium.render?.(...props)}
183
+ <h3>Spacing</h3>
184
+ {SpacingMedium.render?.(...props)}
185
+ </div>
186
+ <div>
187
+ <h2>Small</h2>
188
+ <h3>Size</h3>
189
+ {SizeSmall.render?.(...props)}
190
+ <h3>Spacing</h3>
191
+ {SpacingSmall.render?.(...props)}
192
+ </div>
193
+ <div>
194
+ <h2>Colors</h2>
195
+ {Colors.render?.(...props)}
196
+ </div>
197
+ <div>
198
+ <h2>Align</h2>
199
+ {Align.render?.(...props)}
200
+ </div>
201
+ <div>
202
+ <h2>Override Tag</h2>
203
+ {OverrideTag.render?.(...props)}
204
+ </div>
205
+ </div>
206
+ ),
207
+ parameters: {
208
+ chromatic: { disable: false },
209
+ },
210
+ };
@@ -1,13 +1,16 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { expect, within } from "@storybook/test";
3
3
  import React from "react";
4
- import { BodyShort } from "..";
5
- import { VStack } from "../..";
4
+ import { VStack } from "../../layout/stack";
5
+ import { BodyShort } from "../BodyShort";
6
6
 
7
7
  const meta = {
8
8
  title: "ds-react/Typography/BodyShort",
9
9
  component: BodyShort,
10
- decorators: [(story) => <div style={{ maxWidth: "200px" }}>{story()}</div>],
10
+ decorators: [(story) => <div style={{ maxWidth: "250px" }}>{story()}</div>],
11
+ parameters: {
12
+ chromatic: { disable: true },
13
+ },
11
14
  } satisfies Meta<typeof BodyShort>;
12
15
 
13
16
  export default meta;
@@ -16,7 +19,7 @@ type Story = StoryObj<typeof meta>;
16
19
 
17
20
  const lorem = "Du må gjøre en filtrering for å se brukere i listen.";
18
21
 
19
- export const Default: Story = {
22
+ export const Controls: Story = {
20
23
  args: {
21
24
  spacing: false,
22
25
  children: lorem,
@@ -161,3 +164,46 @@ export const OverrideTag: Story = {
161
164
  expect(legendBodyShort.tagName).toEqual("LEGEND");
162
165
  },
163
166
  };
167
+
168
+ export const Chromatic: Story = {
169
+ render: (...props) => (
170
+ <div>
171
+ <div>
172
+ <h2>Large</h2>
173
+ <h3>Size</h3>
174
+ {SizeLarge.render?.(...props)}
175
+ <h3>Spacing</h3>
176
+ {SpacingLarge.render?.(...props)}
177
+ </div>
178
+ <div>
179
+ <h2>Medium</h2>
180
+ <h3>Size</h3>
181
+ {SizeMedium.render?.(...props)}
182
+ <h3>Spacing</h3>
183
+ {SpacingMedium.render?.(...props)}
184
+ </div>
185
+ <div>
186
+ <h2>Small</h2>
187
+ <h3>Size</h3>
188
+ {SizeSmall.render?.(...props)}
189
+ <h3>Spacing</h3>
190
+ {SpacingSmall.render?.(...props)}
191
+ </div>
192
+ <div>
193
+ <h2>Colors</h2>
194
+ {Colors.render?.(...props)}
195
+ </div>
196
+ <div>
197
+ <h2>Align</h2>
198
+ {Align.render?.(...props)}
199
+ </div>
200
+ <div>
201
+ <h2>Override Tag</h2>
202
+ {OverrideTag.render?.(...props)}
203
+ </div>
204
+ </div>
205
+ ),
206
+ parameters: {
207
+ chromatic: { disable: false },
208
+ },
209
+ };
@@ -1,13 +1,16 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { expect, within } from "@storybook/test";
3
3
  import React from "react";
4
- import { Detail } from "..";
5
- import { VStack } from "../..";
4
+ import { VStack } from "../../layout/stack";
5
+ import Detail from "../Detail";
6
6
 
7
7
  const meta = {
8
8
  title: "ds-react/Typography/Detail",
9
9
  component: Detail,
10
10
  decorators: [(story) => <div style={{ maxWidth: "200px" }}>{story()}</div>],
11
+ parameters: {
12
+ chromatic: { disable: true },
13
+ },
11
14
  } satisfies Meta<typeof Detail>;
12
15
 
13
16
  export default meta;
@@ -16,7 +19,7 @@ type Story = StoryObj<typeof meta>;
16
19
 
17
20
  const lorem = "Du må gjøre en filtrering for å se brukere i listen.";
18
21
 
19
- export const Default: Story = {
22
+ export const Controls: Story = {
20
23
  args: {
21
24
  spacing: false,
22
25
  children: lorem,
@@ -85,3 +88,29 @@ export const OverrideTag: Story = {
85
88
  expect(legendDetail.tagName).toEqual("LEGEND");
86
89
  },
87
90
  };
91
+
92
+ export const Chromatic: Story = {
93
+ render: (...props) => (
94
+ <div>
95
+ <div>
96
+ <h2>Spacing</h2>
97
+ {Spacing.render?.(...props)}
98
+ </div>
99
+ <div>
100
+ <h2>Colors</h2>
101
+ {Colors.render?.(...props)}
102
+ </div>
103
+ <div>
104
+ <h2>Align</h2>
105
+ {Align.render?.(...props)}
106
+ </div>
107
+ <div>
108
+ <h2>Override Tag</h2>
109
+ {OverrideTag.render?.(...props)}
110
+ </div>
111
+ </div>
112
+ ),
113
+ parameters: {
114
+ chromatic: { disable: false },
115
+ },
116
+ };
@@ -1,12 +1,15 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { expect, within } from "@storybook/test";
3
3
  import React from "react";
4
- import { ErrorMessage } from "..";
5
- import { VStack } from "../..";
4
+ import { VStack } from "../../layout/stack";
5
+ import ErrorMessage from "../ErrorMessage";
6
6
 
7
7
  const meta = {
8
8
  title: "ds-react/Typography/ErrorMessage",
9
9
  component: ErrorMessage,
10
+ parameters: {
11
+ chromatic: { disable: true },
12
+ },
10
13
  } satisfies Meta<typeof ErrorMessage>;
11
14
 
12
15
  export default meta;
@@ -16,7 +19,7 @@ type Story = StoryObj<typeof meta>;
16
19
  const lorem =
17
20
  "Du må fylle ut: Oppgi årsaken til at du har ventet mer enn 6 måneder med å søke om refusjon";
18
21
 
19
- export const Default: Story = {
22
+ export const Controls: Story = {
20
23
  args: {
21
24
  spacing: false,
22
25
  children: lorem,
@@ -90,3 +93,31 @@ export const OverrideTag: Story = {
90
93
  expect(legendErrorMessage.tagName).toEqual("LEGEND");
91
94
  },
92
95
  };
96
+
97
+ export const Chromatic: Story = {
98
+ render: (...props) => (
99
+ <div>
100
+ <div>
101
+ <h2>Medium</h2>
102
+ <h3>Size</h3>
103
+ {SizeMedium.render?.(...props)}
104
+ <h3>Spacing</h3>
105
+ {SpacingMedium.render?.(...props)}
106
+ </div>
107
+ <div>
108
+ <h2>Small</h2>
109
+ <h3>Size</h3>
110
+ {SizeSmall.render?.(...props)}
111
+ <h3>Spacing</h3>
112
+ {SpacingSmall.render?.(...props)}
113
+ </div>
114
+ <div>
115
+ <h2>Override Tag</h2>
116
+ {OverrideTag.render?.(...props)}
117
+ </div>
118
+ </div>
119
+ ),
120
+ parameters: {
121
+ chromatic: { disable: false },
122
+ },
123
+ };
@@ -1,13 +1,16 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { expect, within } from "@storybook/test";
3
3
  import { default as React } from "react";
4
- import { Heading } from "..";
5
- import { VStack } from "../..";
4
+ import { VStack } from "../../layout/stack";
5
+ import Heading from "../Heading";
6
6
 
7
7
  const meta = {
8
8
  title: "ds-react/Typography/Heading",
9
9
  component: Heading,
10
10
  decorators: [(story) => <div style={{ maxWidth: "300px" }}>{story()}</div>],
11
+ parameters: {
12
+ chromatic: { disable: true },
13
+ },
11
14
  } satisfies Meta<typeof Heading>;
12
15
 
13
16
  export default meta;
@@ -16,7 +19,7 @@ type Story = StoryObj<typeof meta>;
16
19
 
17
20
  const lorem = "Hva kan vi hjelpe deg med?";
18
21
 
19
- export const Default: Story = {
22
+ export const Controls: Story = {
20
23
  args: {
21
24
  spacing: false,
22
25
  children: lorem,
@@ -139,3 +142,29 @@ export const OverrideTag: Story = {
139
142
  expect(legendHeading.tagName).toEqual("LEGEND");
140
143
  },
141
144
  };
145
+
146
+ export const Chromatic: Story = {
147
+ render: (...props) => (
148
+ <div>
149
+ <div>
150
+ <h2>Sizes</h2>
151
+ {Sizes.render?.(...props)}
152
+ </div>
153
+ <div>
154
+ <h2>Colors</h2>
155
+ {Colors.render?.(...props)}
156
+ </div>
157
+ <div>
158
+ <h2>Align</h2>
159
+ {Align.render?.(...props)}
160
+ </div>
161
+ <div>
162
+ <h2>Override Tag</h2>
163
+ {OverrideTag.render?.(...props)}
164
+ </div>
165
+ </div>
166
+ ),
167
+ parameters: {
168
+ chromatic: { disable: false },
169
+ },
170
+ };
@@ -1,13 +1,16 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { expect, within } from "@storybook/test";
3
3
  import React from "react";
4
- import { Label } from "..";
5
- import { VStack } from "../..";
4
+ import { VStack } from "../../layout/stack";
5
+ import Label from "../Label";
6
6
 
7
7
  const meta = {
8
8
  title: "ds-react/Typography/Label",
9
9
  component: Label,
10
10
  decorators: [(story) => <div style={{ maxWidth: "400px" }}>{story()}</div>],
11
+ parameters: {
12
+ chromatic: { disable: true },
13
+ },
11
14
  } satisfies Meta<typeof Label>;
12
15
 
13
16
  export default meta;
@@ -17,7 +20,7 @@ type Story = StoryObj<typeof meta>;
17
20
  const lorem =
18
21
  "Oppgi årsaken til at du har ventet mer enn 6 måneder med å søke om refusjon";
19
22
 
20
- export const Default: Story = {
23
+ export const Controls: Story = {
21
24
  args: {
22
25
  spacing: false,
23
26
  children: lorem,
@@ -95,3 +98,35 @@ export const OverrideTag: Story = {
95
98
  expect(legendLabel.tagName).toEqual("LEGEND");
96
99
  },
97
100
  };
101
+
102
+ export const Chromatic: Story = {
103
+ render: (...props) => (
104
+ <div>
105
+ <div>
106
+ <h2>Medium</h2>
107
+ <h3>Size</h3>
108
+ {SizeMedium.render?.(...props)}
109
+ <h3>Spacing</h3>
110
+ {SpacingMedium.render?.(...props)}
111
+ </div>
112
+ <div>
113
+ <h2>Small</h2>
114
+ <h3>Size</h3>
115
+ {SizeSmall.render?.(...props)}
116
+ <h3>Spacing</h3>
117
+ {SpacingSmall.render?.(...props)}
118
+ </div>
119
+ <div>
120
+ <h2>Colors</h2>
121
+ {Colors.render?.(...props)}
122
+ </div>
123
+ <div>
124
+ <h2>Override Tag</h2>
125
+ {OverrideTag.render?.(...props)}
126
+ </div>
127
+ </div>
128
+ ),
129
+ parameters: {
130
+ chromatic: { disable: false },
131
+ },
132
+ };
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import React, {
8
8
  createContext as createReactContext,
9
+ forwardRef,
9
10
  useContext as useReactContext,
10
11
  } from "react";
11
12
 
@@ -19,11 +20,6 @@ export interface CreateContextOptions<T> {
19
20
 
20
21
  type ProviderProps<T> = T & { children: React.ReactNode };
21
22
 
22
- export type CreateContextReturn<T> = [
23
- (contextValues: ProviderProps<T>) => React.JSX.Element,
24
- () => T,
25
- ];
26
-
27
23
  function getErrorMessage(hook: string, provider: string) {
28
24
  return `${hook} returned \`undefined\`. Seems you forgot to wrap component within ${provider}`;
29
25
  }
@@ -39,17 +35,30 @@ export function createContext<T>(options: CreateContextOptions<T> = {}) {
39
35
 
40
36
  const Context = createReactContext<T | undefined>(defaultValue);
41
37
 
42
- function Provider({ children, ...context }: ProviderProps<T>) {
43
- // Only re-memoize when prop values change
44
- // eslint-disable-next-line react-hooks/exhaustive-deps
45
- const value = React.useMemo(() => context, Object.values(context)) as T;
46
- return <Context.Provider value={value}>{children}</Context.Provider>;
47
- }
38
+ /**
39
+ * We use forwardRef to allow `ref` to be used as a regular context value
40
+ * @see https://reactjs.org/docs/forwarding-refs.html#forwarding-refs-to-dom-components
41
+ */
42
+ const Provider = forwardRef(
43
+ ({ children, ...context }: ProviderProps<T>, ref) => {
44
+ // Only re-memoize when prop values change
45
+ // eslint-disable-next-line react-hooks/exhaustive-deps
46
+ const value = React.useMemo(() => context, Object.values(context)) as T;
48
47
 
49
- function useContext() {
48
+ return (
49
+ <Context.Provider value={ref ? { ...value, ref } : value}>
50
+ {children}
51
+ </Context.Provider>
52
+ );
53
+ },
54
+ );
55
+
56
+ function useContext<S extends boolean = true>(
57
+ strict: S = true as S,
58
+ ): Context<S, T> {
50
59
  const context = useReactContext(Context);
51
60
 
52
- if (!context) {
61
+ if (!context && strict) {
53
62
  const error = new Error(
54
63
  errorMessage ?? getErrorMessage(hookName, providerName),
55
64
  );
@@ -58,10 +67,12 @@ export function createContext<T>(options: CreateContextOptions<T> = {}) {
58
67
  throw error;
59
68
  }
60
69
 
61
- return context;
70
+ return context as Context<S, T>;
62
71
  }
63
72
 
64
73
  Context.displayName = name;
65
74
 
66
- return [Provider, useContext] as CreateContextReturn<T>;
75
+ return [Provider, useContext] as const;
67
76
  }
77
+
78
+ type Context<S, T> = S extends true ? T : T | undefined;
@@ -1,8 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ModalContext = void 0;
7
- const react_1 = __importDefault(require("react"));
8
- exports.ModalContext = react_1.default.createContext(null);
@@ -1,7 +0,0 @@
1
- import React from "react";
2
- interface ModalContextProps {
3
- closeHandler?: React.MouseEventHandler<HTMLButtonElement>;
4
- ref: React.RefObject<HTMLDialogElement>;
5
- }
6
- export declare const ModalContext: React.Context<ModalContextProps | null>;
7
- export {};
@@ -1,3 +0,0 @@
1
- import React from "react";
2
- export const ModalContext = React.createContext(null);
3
- //# sourceMappingURL=ModalContext.js.map