@navikt/ds-react 6.4.1 → 6.5.0

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 (203) hide show
  1. package/cjs/date/datepicker/parts/DayButton.js +1 -1
  2. package/cjs/date/datepicker/parts/DayButton.js.map +1 -1
  3. package/cjs/date/hooks/useDatepicker.js +4 -1
  4. package/cjs/date/hooks/useDatepicker.js.map +1 -1
  5. package/cjs/date/hooks/useMonthPicker.js +4 -1
  6. package/cjs/date/hooks/useMonthPicker.js.map +1 -1
  7. package/cjs/date/monthpicker/MonthButton.js +1 -1
  8. package/cjs/date/monthpicker/MonthButton.js.map +1 -1
  9. package/cjs/tabs/Tabs.context.d.ts +30 -0
  10. package/cjs/tabs/Tabs.context.js +14 -0
  11. package/cjs/tabs/Tabs.context.js.map +1 -0
  12. package/cjs/tabs/Tabs.d.ts +8 -43
  13. package/cjs/tabs/Tabs.js +19 -12
  14. package/cjs/tabs/Tabs.js.map +1 -1
  15. package/cjs/tabs/Tabs.types.d.ts +41 -0
  16. package/cjs/tabs/Tabs.types.js +3 -0
  17. package/cjs/tabs/Tabs.types.js.map +1 -0
  18. package/cjs/tabs/index.d.ts +5 -4
  19. package/cjs/tabs/index.js +6 -6
  20. package/cjs/tabs/index.js.map +1 -1
  21. package/cjs/tabs/parts/tab/Tab.d.ts +25 -0
  22. package/cjs/tabs/{Tab.js → parts/tab/Tab.js} +15 -14
  23. package/cjs/tabs/parts/tab/Tab.js.map +1 -0
  24. package/cjs/tabs/parts/tab/useTab.d.ts +20 -0
  25. package/cjs/tabs/parts/tab/useTab.js +29 -0
  26. package/cjs/tabs/parts/tab/useTab.js.map +1 -0
  27. package/cjs/tabs/parts/tablist/ScrollButtons.d.ts +8 -0
  28. package/cjs/tabs/parts/tablist/ScrollButtons.js +15 -0
  29. package/cjs/tabs/parts/tablist/ScrollButtons.js.map +1 -0
  30. package/{esm/tabs → cjs/tabs/parts/tablist}/TabList.d.ts +1 -1
  31. package/cjs/tabs/parts/tablist/TabList.js +61 -0
  32. package/cjs/tabs/parts/tablist/TabList.js.map +1 -0
  33. package/cjs/tabs/parts/tablist/useScrollButtons.d.ts +12 -0
  34. package/cjs/tabs/parts/tablist/useScrollButtons.js +61 -0
  35. package/cjs/tabs/parts/tablist/useScrollButtons.js.map +1 -0
  36. package/cjs/tabs/parts/tablist/useTabList.d.ts +7 -0
  37. package/cjs/tabs/parts/tablist/useTabList.js +66 -0
  38. package/cjs/tabs/parts/tablist/useTabList.js.map +1 -0
  39. package/cjs/tabs/parts/tabpanel/TabPanel.d.ts +25 -0
  40. package/cjs/tabs/{TabPanel.js → parts/tabpanel/TabPanel.js} +5 -3
  41. package/cjs/tabs/parts/tabpanel/TabPanel.js.map +1 -0
  42. package/cjs/tabs/parts/tabpanel/useTabPanel.d.ts +12 -0
  43. package/cjs/tabs/parts/tabpanel/useTabPanel.js +17 -0
  44. package/cjs/tabs/parts/tabpanel/useTabPanel.js.map +1 -0
  45. package/cjs/tabs/useTabs.d.ts +14 -0
  46. package/cjs/tabs/useTabs.js +43 -0
  47. package/cjs/tabs/useTabs.js.map +1 -0
  48. package/cjs/toggle-group/ToggleGroup.context.d.ts +31 -0
  49. package/cjs/toggle-group/ToggleGroup.context.js +16 -0
  50. package/cjs/toggle-group/ToggleGroup.context.js.map +1 -0
  51. package/cjs/toggle-group/ToggleGroup.d.ts +5 -36
  52. package/cjs/toggle-group/ToggleGroup.js +24 -24
  53. package/cjs/toggle-group/ToggleGroup.js.map +1 -1
  54. package/cjs/toggle-group/ToggleGroup.types.d.ts +38 -0
  55. package/cjs/toggle-group/ToggleGroup.types.js +3 -0
  56. package/cjs/toggle-group/ToggleGroup.types.js.map +1 -0
  57. package/cjs/toggle-group/index.d.ts +3 -2
  58. package/cjs/toggle-group/index.js +1 -1
  59. package/cjs/toggle-group/index.js.map +1 -1
  60. package/cjs/toggle-group/{ToggleItem.d.ts → parts/ToggleItem.d.ts} +2 -2
  61. package/cjs/toggle-group/{ToggleItem.js → parts/ToggleItem.js} +9 -8
  62. package/cjs/toggle-group/parts/ToggleItem.js.map +1 -0
  63. package/cjs/toggle-group/parts/useToggleItem.d.ts +20 -0
  64. package/cjs/toggle-group/parts/useToggleItem.js +76 -0
  65. package/cjs/toggle-group/parts/useToggleItem.js.map +1 -0
  66. package/cjs/toggle-group/useToggleGroup.d.ts +8 -0
  67. package/cjs/toggle-group/useToggleGroup.js +29 -0
  68. package/cjs/toggle-group/useToggleGroup.js.map +1 -0
  69. package/esm/date/datepicker/parts/DayButton.js +1 -1
  70. package/esm/date/datepicker/parts/DayButton.js.map +1 -1
  71. package/esm/date/hooks/useDatepicker.js +4 -1
  72. package/esm/date/hooks/useDatepicker.js.map +1 -1
  73. package/esm/date/hooks/useMonthPicker.js +4 -1
  74. package/esm/date/hooks/useMonthPicker.js.map +1 -1
  75. package/esm/date/monthpicker/MonthButton.js +1 -1
  76. package/esm/date/monthpicker/MonthButton.js.map +1 -1
  77. package/esm/tabs/Tabs.context.d.ts +30 -0
  78. package/esm/tabs/Tabs.context.js +10 -0
  79. package/esm/tabs/Tabs.context.js.map +1 -0
  80. package/esm/tabs/Tabs.d.ts +8 -43
  81. package/esm/tabs/Tabs.js +19 -12
  82. package/esm/tabs/Tabs.js.map +1 -1
  83. package/esm/tabs/Tabs.types.d.ts +41 -0
  84. package/esm/tabs/Tabs.types.js +2 -0
  85. package/esm/tabs/Tabs.types.js.map +1 -0
  86. package/esm/tabs/index.d.ts +5 -4
  87. package/esm/tabs/index.js +3 -3
  88. package/esm/tabs/index.js.map +1 -1
  89. package/esm/tabs/parts/tab/Tab.d.ts +25 -0
  90. package/esm/tabs/parts/tab/Tab.js +35 -0
  91. package/esm/tabs/parts/tab/Tab.js.map +1 -0
  92. package/esm/tabs/parts/tab/useTab.d.ts +20 -0
  93. package/esm/tabs/parts/tab/useTab.js +25 -0
  94. package/esm/tabs/parts/tab/useTab.js.map +1 -0
  95. package/esm/tabs/parts/tablist/ScrollButtons.d.ts +8 -0
  96. package/esm/tabs/parts/tablist/ScrollButtons.js +10 -0
  97. package/esm/tabs/parts/tablist/ScrollButtons.js.map +1 -0
  98. package/{cjs/tabs → esm/tabs/parts/tablist}/TabList.d.ts +1 -1
  99. package/esm/tabs/parts/tablist/TabList.js +32 -0
  100. package/esm/tabs/parts/tablist/TabList.js.map +1 -0
  101. package/esm/tabs/parts/tablist/useScrollButtons.d.ts +12 -0
  102. package/esm/tabs/parts/tablist/useScrollButtons.js +57 -0
  103. package/esm/tabs/parts/tablist/useScrollButtons.js.map +1 -0
  104. package/esm/tabs/parts/tablist/useTabList.d.ts +7 -0
  105. package/esm/tabs/parts/tablist/useTabList.js +62 -0
  106. package/esm/tabs/parts/tablist/useTabList.js.map +1 -0
  107. package/esm/tabs/parts/tabpanel/TabPanel.d.ts +25 -0
  108. package/esm/tabs/parts/tabpanel/TabPanel.js +22 -0
  109. package/esm/tabs/parts/tabpanel/TabPanel.js.map +1 -0
  110. package/esm/tabs/parts/tabpanel/useTabPanel.d.ts +12 -0
  111. package/esm/tabs/parts/tabpanel/useTabPanel.js +13 -0
  112. package/esm/tabs/parts/tabpanel/useTabPanel.js.map +1 -0
  113. package/esm/tabs/useTabs.d.ts +14 -0
  114. package/esm/tabs/useTabs.js +39 -0
  115. package/esm/tabs/useTabs.js.map +1 -0
  116. package/esm/toggle-group/ToggleGroup.context.d.ts +31 -0
  117. package/esm/toggle-group/ToggleGroup.context.js +12 -0
  118. package/esm/toggle-group/ToggleGroup.context.js.map +1 -0
  119. package/esm/toggle-group/ToggleGroup.d.ts +5 -36
  120. package/esm/toggle-group/ToggleGroup.js +24 -24
  121. package/esm/toggle-group/ToggleGroup.js.map +1 -1
  122. package/esm/toggle-group/ToggleGroup.types.d.ts +38 -0
  123. package/esm/toggle-group/ToggleGroup.types.js +2 -0
  124. package/esm/toggle-group/ToggleGroup.types.js.map +1 -0
  125. package/esm/toggle-group/index.d.ts +3 -2
  126. package/esm/toggle-group/index.js +1 -1
  127. package/esm/toggle-group/index.js.map +1 -1
  128. package/esm/toggle-group/{ToggleItem.d.ts → parts/ToggleItem.d.ts} +2 -2
  129. package/esm/toggle-group/parts/ToggleItem.js +25 -0
  130. package/esm/toggle-group/parts/ToggleItem.js.map +1 -0
  131. package/esm/toggle-group/parts/useToggleItem.d.ts +20 -0
  132. package/esm/toggle-group/parts/useToggleItem.js +72 -0
  133. package/esm/toggle-group/parts/useToggleItem.js.map +1 -0
  134. package/esm/toggle-group/useToggleGroup.d.ts +8 -0
  135. package/esm/toggle-group/useToggleGroup.js +25 -0
  136. package/esm/toggle-group/useToggleGroup.js.map +1 -0
  137. package/package.json +3 -5
  138. package/src/date/datepicker/datepicker.stories.tsx +39 -0
  139. package/src/date/datepicker/parts/DayButton.tsx +2 -0
  140. package/src/date/hooks/useDatepicker.tsx +5 -1
  141. package/src/date/hooks/useMonthPicker.tsx +5 -1
  142. package/src/date/monthpicker/MonthButton.tsx +1 -0
  143. package/src/date/monthpicker/monthpicker.stories.tsx +36 -19
  144. package/src/modal/modal.stories.tsx +2 -6
  145. package/src/tabs/Tabs.context.ts +24 -0
  146. package/src/tabs/Tabs.stories.tsx +233 -113
  147. package/src/tabs/Tabs.test.tsx +99 -37
  148. package/src/tabs/Tabs.tsx +48 -70
  149. package/src/tabs/Tabs.types.ts +43 -0
  150. package/src/tabs/index.ts +11 -4
  151. package/src/tabs/parts/tab/Tab.tsx +93 -0
  152. package/src/tabs/parts/tab/useTab.ts +52 -0
  153. package/src/tabs/parts/tablist/ScrollButtons.tsx +29 -0
  154. package/src/tabs/parts/tablist/TabList.tsx +56 -0
  155. package/src/tabs/parts/tablist/useScrollButtons.ts +69 -0
  156. package/src/tabs/parts/tablist/useTabList.ts +68 -0
  157. package/src/tabs/parts/tabpanel/TabPanel.tsx +50 -0
  158. package/src/tabs/parts/tabpanel/useTabPanel.ts +18 -0
  159. package/src/tabs/useTabs.ts +51 -0
  160. package/src/toggle-group/ToggleGroup.context.ts +31 -0
  161. package/src/toggle-group/ToggleGroup.stories.tsx +67 -6
  162. package/src/toggle-group/ToggleGroup.test.tsx +57 -16
  163. package/src/toggle-group/ToggleGroup.tsx +63 -90
  164. package/src/toggle-group/ToggleGroup.types.ts +40 -0
  165. package/src/toggle-group/index.ts +3 -2
  166. package/src/toggle-group/parts/ToggleItem.tsx +55 -0
  167. package/src/toggle-group/parts/useToggleItem.ts +104 -0
  168. package/src/toggle-group/useToggleGroup.ts +33 -0
  169. package/cjs/tabs/Tab.d.ts +0 -18
  170. package/cjs/tabs/Tab.js.map +0 -1
  171. package/cjs/tabs/TabList.js +0 -111
  172. package/cjs/tabs/TabList.js.map +0 -1
  173. package/cjs/tabs/TabPanel.d.ts +0 -13
  174. package/cjs/tabs/TabPanel.js.map +0 -1
  175. package/cjs/tabs/context.d.ts +0 -8
  176. package/cjs/tabs/context.js +0 -6
  177. package/cjs/tabs/context.js.map +0 -1
  178. package/cjs/toggle-group/ToggleItem.js.map +0 -1
  179. package/cjs/toggle-group/context.d.ts +0 -6
  180. package/cjs/toggle-group/context.js +0 -6
  181. package/cjs/toggle-group/context.js.map +0 -1
  182. package/esm/tabs/Tab.d.ts +0 -18
  183. package/esm/tabs/Tab.js +0 -34
  184. package/esm/tabs/Tab.js.map +0 -1
  185. package/esm/tabs/TabList.js +0 -82
  186. package/esm/tabs/TabList.js.map +0 -1
  187. package/esm/tabs/TabPanel.d.ts +0 -13
  188. package/esm/tabs/TabPanel.js +0 -20
  189. package/esm/tabs/TabPanel.js.map +0 -1
  190. package/esm/tabs/context.d.ts +0 -8
  191. package/esm/tabs/context.js +0 -3
  192. package/esm/tabs/context.js.map +0 -1
  193. package/esm/toggle-group/ToggleItem.js +0 -24
  194. package/esm/toggle-group/ToggleItem.js.map +0 -1
  195. package/esm/toggle-group/context.d.ts +0 -6
  196. package/esm/toggle-group/context.js +0 -3
  197. package/esm/toggle-group/context.js.map +0 -1
  198. package/src/tabs/Tab.tsx +0 -66
  199. package/src/tabs/TabList.tsx +0 -128
  200. package/src/tabs/TabPanel.tsx +0 -26
  201. package/src/tabs/context.ts +0 -9
  202. package/src/toggle-group/ToggleItem.tsx +0 -41
  203. package/src/toggle-group/context.ts +0 -9
@@ -1,7 +1,8 @@
1
- import { Meta } from "@storybook/react";
1
+ import { Meta, StoryObj } from "@storybook/react";
2
2
  import React, { useState } from "react";
3
3
  import { DishwasherIcon, FreezerIcon, MugIcon } from "@navikt/aksel-icons";
4
4
  import { Tabs } from ".";
5
+ import { VStack } from "../layout/stack";
5
6
 
6
7
  export default {
7
8
  title: "ds-react/Tabs",
@@ -20,41 +21,44 @@ export default {
20
21
  },
21
22
  },
22
23
  },
24
+ parameters: {
25
+ chromatic: { disable: true },
26
+ },
23
27
  } satisfies Meta<typeof Tabs>;
24
28
 
25
- const Panel = () => {
26
- return (
27
- <>
28
- <Tabs.Panel
29
- value="test1"
30
- className="panel"
31
- style={{ background: "var(--a-gray-50)", height: 100 }}
32
- >
33
- Innholdspanel for Skap-tab
34
- </Tabs.Panel>
35
- <Tabs.Panel
36
- value="test2"
37
- className="panel"
38
- style={{
39
- background: "var(--a-green-50)",
40
- height: 100,
41
- }}
42
- >
43
- Innholdspanel for Oppvaskmaskin-tab
44
- </Tabs.Panel>
45
- <Tabs.Panel
46
- value="test3"
47
- className="panel"
48
- style={{ background: "var(--a-red-50)", height: 100 }}
49
- >
50
- Innholdspanel for Fryser-tab
51
- </Tabs.Panel>
52
- <style>{`.panel[data-state="active"] { display:grid; place-content: center;}`}</style>
53
- </>
54
- );
55
- };
29
+ type Story = StoryObj<typeof Tabs>;
30
+
31
+ const Panel = () => (
32
+ <>
33
+ <Tabs.Panel
34
+ value="test1"
35
+ className="panel"
36
+ style={{ background: "var(--a-gray-50)", height: 100 }}
37
+ >
38
+ Innholdspanel for Skap-tab
39
+ </Tabs.Panel>
40
+ <Tabs.Panel
41
+ value="test2"
42
+ className="panel"
43
+ style={{
44
+ background: "var(--a-green-50)",
45
+ height: 100,
46
+ }}
47
+ >
48
+ Innholdspanel for Oppvaskmaskin-tab
49
+ </Tabs.Panel>
50
+ <Tabs.Panel
51
+ value="test3"
52
+ className="panel"
53
+ style={{ background: "var(--a-red-50)", height: 100 }}
54
+ >
55
+ Innholdspanel for Fryser-tab
56
+ </Tabs.Panel>
57
+ <style>{`.panel[data-state="active"] { display:grid; place-content: center;}`}</style>
58
+ </>
59
+ );
56
60
 
57
- export const Default = {
61
+ export const Default: Story = {
58
62
  render: (props) => {
59
63
  return (
60
64
  <Tabs
@@ -65,13 +69,17 @@ export const Default = {
65
69
  iconPosition={props?.iconPosition}
66
70
  >
67
71
  <Tabs.List>
68
- <Tabs.Tab value="test1" icon={<MugIcon />} label="Skap" />
72
+ <Tabs.Tab value="test1" icon={<MugIcon aria-hidden />} label="Skap" />
69
73
  <Tabs.Tab
70
74
  value="test2"
71
75
  label="Oppvaskmaskin"
72
- icon={<DishwasherIcon />}
76
+ icon={<DishwasherIcon aria-hidden />}
77
+ />
78
+ <Tabs.Tab
79
+ value="test3"
80
+ icon={<FreezerIcon aria-hidden />}
81
+ label="Fryser"
73
82
  />
74
- <Tabs.Tab value="test3" icon={<FreezerIcon />} label="Fryser" />
75
83
  </Tabs.List>
76
84
  <Panel />
77
85
  </Tabs>
@@ -84,108 +92,220 @@ export const Default = {
84
92
  },
85
93
  };
86
94
 
87
- export const Small = () => {
95
+ export const Small = () => (
96
+ <Tabs defaultValue="test2" size="small">
97
+ <Tabs.List>
98
+ <Tabs.Tab value="test1" icon={<MugIcon aria-hidden />} label="Skap" />
99
+ <Tabs.Tab
100
+ value="test2"
101
+ label="Oppvaskmaskin"
102
+ icon={<DishwasherIcon aria-hidden />}
103
+ />
104
+ <Tabs.Tab
105
+ value="test3"
106
+ icon={<FreezerIcon aria-hidden />}
107
+ label="Fryser"
108
+ />
109
+ </Tabs.List>
110
+ <Panel />
111
+ </Tabs>
112
+ );
113
+
114
+ export const Controlled = () => {
115
+ const [activeValue, setActiveValue] = useState("test1");
88
116
  return (
89
- <Tabs defaultValue="test2" size="small">
117
+ <Tabs value={activeValue} onChange={setActiveValue}>
90
118
  <Tabs.List>
91
- <Tabs.Tab value="test1" icon={<MugIcon />} label="Skap" />
119
+ <Tabs.Tab value="test1" icon={<MugIcon aria-hidden />} label="Skap" />
92
120
  <Tabs.Tab
93
121
  value="test2"
94
122
  label="Oppvaskmaskin"
95
- icon={<DishwasherIcon />}
123
+ icon={<DishwasherIcon aria-hidden />}
124
+ />
125
+ <Tabs.Tab
126
+ value="test3"
127
+ icon={<FreezerIcon aria-hidden />}
128
+ label="Fryser"
96
129
  />
97
- <Tabs.Tab value="test3" icon={<FreezerIcon />} label="Fryser" />
98
130
  </Tabs.List>
99
131
  <Panel />
100
132
  </Tabs>
101
133
  );
102
134
  };
103
135
 
104
- export const Controlled = () => {
105
- const [activeValue, setActiveValue] = useState("test1");
106
- return (
107
- <Tabs value={activeValue} onChange={setActiveValue}>
136
+ export const IconPosition = () => (
137
+ <VStack gap="4">
138
+ <Tabs defaultValue="test2" size="small">
108
139
  <Tabs.List>
109
- <Tabs.Tab value="test1" icon={<MugIcon />} label="Skap" />
140
+ <Tabs.Tab value="test1" icon={<MugIcon aria-hidden />} label="Skap" />
110
141
  <Tabs.Tab
111
142
  value="test2"
112
143
  label="Oppvaskmaskin"
113
- icon={<DishwasherIcon />}
144
+ icon={<DishwasherIcon aria-hidden />}
145
+ />
146
+ <Tabs.Tab
147
+ value="test3"
148
+ icon={<FreezerIcon aria-hidden />}
149
+ label="Fryser"
114
150
  />
115
- <Tabs.Tab value="test3" icon={<FreezerIcon />} label="Fryser" />
116
151
  </Tabs.List>
117
152
  <Panel />
118
153
  </Tabs>
119
- );
120
- };
121
-
122
- export const IconPosition = () => {
123
- return (
124
- <div className="colgap">
125
- <Tabs defaultValue="test2" size="small">
126
- <Tabs.List>
127
- <Tabs.Tab value="test1" icon={<MugIcon />} label="Skap" />
128
- <Tabs.Tab
129
- value="test2"
130
- label="Oppvaskmaskin"
131
- icon={<DishwasherIcon />}
132
- />
133
- <Tabs.Tab value="test3" icon={<FreezerIcon />} label="Fryser" />
134
- </Tabs.List>
135
- <Panel />
136
- </Tabs>
137
- <Tabs defaultValue="test2" size="small" iconPosition="top">
138
- <Tabs.List style={{ margin: "0 auto" }}>
139
- <Tabs.Tab value="test1" icon={<MugIcon />} label="Skap" />
140
- <Tabs.Tab
141
- value="test2"
142
- label="Oppvaskmaskin"
143
- icon={<DishwasherIcon />}
144
- />
145
- <Tabs.Tab value="test3" icon={<FreezerIcon />} label="Fryser" />
146
- </Tabs.List>
147
- <Panel />
148
- </Tabs>
149
- </div>
150
- );
151
- };
152
-
153
- export const Icon = () => {
154
- return (
155
- <div className="colgap">
156
- <Tabs defaultValue="test2">
157
- <Tabs.List style={{ margin: "0 auto" }}>
158
- <Tabs.Tab value="test1" icon={<MugIcon />} />
159
- <Tabs.Tab value="test2" icon={<DishwasherIcon />} />
160
- <Tabs.Tab value="test3" icon={<FreezerIcon />} />
161
- </Tabs.List>
162
- <Panel />
163
- </Tabs>
164
- <Tabs defaultValue="test2" size="small" iconPosition="top">
165
- <Tabs.List style={{ margin: "0 auto" }}>
166
- <Tabs.Tab value="test1" icon={<MugIcon />} />
167
- <Tabs.Tab value="test2" icon={<DishwasherIcon />} />
168
- <Tabs.Tab value="test3" icon={<FreezerIcon />} />
169
- </Tabs.List>
170
- <Panel />
171
- </Tabs>
172
- </div>
173
- );
174
- };
175
-
176
- export const Overflow = () => {
177
- return (
178
- <Tabs defaultValue="test2" style={{ maxWidth: 300 }}>
179
- <Tabs.List>
180
- <Tabs.Tab value="test1" icon={<MugIcon />} label="Skap" />
154
+ <Tabs defaultValue="test2" size="small" iconPosition="top">
155
+ <Tabs.List style={{ margin: "0 auto" }}>
156
+ <Tabs.Tab value="test1" icon={<MugIcon aria-hidden />} label="Skap" />
181
157
  <Tabs.Tab
182
158
  value="test2"
183
159
  label="Oppvaskmaskin"
184
- icon={<DishwasherIcon />}
160
+ icon={<DishwasherIcon aria-hidden />}
161
+ />
162
+ <Tabs.Tab
163
+ value="test3"
164
+ icon={<FreezerIcon aria-hidden />}
165
+ label="Fryser"
185
166
  />
186
- <Tabs.Tab value="test3" icon={<FreezerIcon />} label="Fryser" />
187
167
  </Tabs.List>
188
168
  <Panel />
189
169
  </Tabs>
190
- );
170
+ </VStack>
171
+ );
172
+
173
+ export const Icon = () => (
174
+ <VStack gap="4">
175
+ <Tabs defaultValue="test2">
176
+ <Tabs.List style={{ margin: "0 auto" }}>
177
+ <Tabs.Tab value="test1" icon={<MugIcon title="Skap" />} />
178
+ <Tabs.Tab
179
+ value="test2"
180
+ icon={<DishwasherIcon title="Oppvaskmaskin" />}
181
+ />
182
+ <Tabs.Tab value="test3" icon={<FreezerIcon title="Fryser" />} />
183
+ </Tabs.List>
184
+ <Panel />
185
+ </Tabs>
186
+ <Tabs defaultValue="test2" size="small" iconPosition="top">
187
+ <Tabs.List style={{ margin: "0 auto" }}>
188
+ <Tabs.Tab value="test1" icon={<MugIcon title="Skap" />} />
189
+ <Tabs.Tab
190
+ value="test2"
191
+ icon={<DishwasherIcon title="Oppvaskmaskin" />}
192
+ />
193
+ <Tabs.Tab value="test3" icon={<FreezerIcon title="Fryser" />} />
194
+ </Tabs.List>
195
+ <Panel />
196
+ </Tabs>
197
+ </VStack>
198
+ );
199
+
200
+ export const Overflow = () => (
201
+ <Tabs defaultValue="test2" style={{ maxWidth: 300 }}>
202
+ <Tabs.List>
203
+ <Tabs.Tab value="test1" icon={<MugIcon aria-hidden />} label="Skap" />
204
+ <Tabs.Tab
205
+ value="test2"
206
+ label="Oppvaskmaskin"
207
+ icon={<DishwasherIcon aria-hidden />}
208
+ />
209
+ <Tabs.Tab
210
+ value="test3"
211
+ icon={<FreezerIcon aria-hidden />}
212
+ label="Fryser"
213
+ />
214
+ </Tabs.List>
215
+ <Panel />
216
+ </Tabs>
217
+ );
218
+
219
+ export const Fill = () => (
220
+ <Tabs defaultValue="test2" fill>
221
+ <Tabs.List>
222
+ <Tabs.Tab value="test1" icon={<MugIcon aria-hidden />} label="Skap" />
223
+ <Tabs.Tab
224
+ value="test2"
225
+ icon={<DishwasherIcon aria-hidden />}
226
+ label="Oppvaskmaskin"
227
+ />
228
+ <Tabs.Tab
229
+ value="test3"
230
+ icon={<FreezerIcon aria-hidden />}
231
+ label="Fryser"
232
+ />
233
+ </Tabs.List>
234
+ <Panel />
235
+ </Tabs>
236
+ );
237
+
238
+ Fill.parameters = {
239
+ layout: "fullscreen",
240
+ };
241
+
242
+ export const CustomIds = () => (
243
+ <Tabs defaultValue="test2">
244
+ <Tabs.List>
245
+ <Tabs.Tab
246
+ value="test1"
247
+ label="Skap"
248
+ id="custom-tabid-1"
249
+ aria-controls="custom-tabpanelid-1"
250
+ />
251
+ <Tabs.Tab
252
+ value="test2"
253
+ label="Oppvaskmaskin"
254
+ id="custom-tabid-2"
255
+ aria-controls="custom-tabpanelid-2"
256
+ />
257
+ </Tabs.List>
258
+ <Tabs.Panel
259
+ value="test1"
260
+ className="panel"
261
+ id="custom-tabpanelid-1"
262
+ aria-labelledby="custom-tabid-1"
263
+ >
264
+ Innholdspanel for Skap-tab
265
+ </Tabs.Panel>
266
+ <Tabs.Panel
267
+ value="test2"
268
+ className="panel"
269
+ id="custom-tabpanelid-2"
270
+ aria-labelledby="custom-tabid-2"
271
+ >
272
+ Innholdspanel for Oppvaskmaskin-tab
273
+ </Tabs.Panel>
274
+ </Tabs>
275
+ );
276
+
277
+ export const Chromatic = {
278
+ render: () => (
279
+ <VStack gap="6" align="center">
280
+ <div>
281
+ <h2>Small</h2>
282
+ <Small />
283
+ </div>
284
+ <div>
285
+ <h2>Controlled</h2>
286
+ <Controlled />
287
+ </div>
288
+ <div>
289
+ <h2>IconPosition</h2>
290
+ <IconPosition />
291
+ </div>
292
+ <div>
293
+ <h2>Icon</h2>
294
+ <Icon />
295
+ </div>
296
+ <div>
297
+ <h2>Overflow</h2>
298
+ <Overflow />
299
+ </div>
300
+ <div>
301
+ <h2>Fill</h2>
302
+ <div style={{ minWidth: 600 }}>
303
+ <Fill />
304
+ </div>
305
+ </div>
306
+ </VStack>
307
+ ),
308
+ parameters: {
309
+ chromatic: { disable: false, delay: 300 },
310
+ },
191
311
  };
@@ -1,4 +1,5 @@
1
- import { fireEvent, render, screen } from "@testing-library/react";
1
+ import { act, fireEvent, render, screen } from "@testing-library/react";
2
+ import userEvent from "@testing-library/user-event";
2
3
  import React from "react";
3
4
  import { describe, expect, test } from "vitest";
4
5
  import { Tabs } from "./Tabs";
@@ -39,72 +40,133 @@ const TestTabs = ({
39
40
  describe("Tabs", () => {
40
41
  test("sets default value correctly", () => {
41
42
  render(<TestTabs defaultValue="tab2" />);
42
- const tab = screen.getByTestId("tab2");
43
- const panel = screen.getByTestId("tabpanel2");
43
+ const tab2 = screen.getByTestId("tab2");
44
+ const panel2 = screen.getByTestId("tabpanel2");
44
45
 
45
- expect(tab).toHaveAttribute("aria-selected", "true");
46
- expect(panel).toHaveTextContent("Tabpanel 2");
46
+ expect(tab2).toHaveAttribute("aria-selected", "true");
47
+ expect(panel2).toHaveTextContent("Tabpanel 2");
47
48
  });
48
49
 
49
50
  test("label-connection between tab and tabpanel is correct", async () => {
50
51
  render(<TestTabs defaultValue="tab2" />);
51
- const tab = screen.getByTestId("tab2");
52
- const panel = screen.getByTestId("tabpanel2");
52
+ const tab2 = screen.getByTestId("tab2");
53
+ const panel2 = screen.getByTestId("tabpanel2");
53
54
 
54
- const controlsId = tab.getAttribute("aria-controls");
55
- const panelLabelledBy = panel.getAttribute("aria-labelledby");
55
+ const controlsId = tab2.getAttribute("aria-controls");
56
+ const panelLabelledBy = panel2.getAttribute("aria-labelledby");
56
57
 
57
- expect(controlsId).toEqual(panel.id);
58
- expect(tab.id).toEqual(panelLabelledBy);
58
+ expect(controlsId).toEqual(panel2.id);
59
+ expect(tab2.id).toEqual(panelLabelledBy);
59
60
  });
60
61
 
61
62
  test("sets correct attributes on active tab", () => {
62
63
  render(<TestTabs defaultValue="tab2" />);
63
- const tab = screen.getByTestId("tab2");
64
+ const tab2 = screen.getByTestId("tab2");
64
65
 
65
- expect(tab).toHaveAttribute("aria-selected", "true");
66
- expect(tab).toHaveAttribute("role", "tab");
67
- expect(tab).toHaveAttribute("aria-controls");
68
- expect(tab).toHaveAttribute("tabindex", "-1");
66
+ expect(tab2).toHaveAttribute("aria-selected", "true");
67
+ expect(tab2).toHaveAttribute("role", "tab");
68
+ expect(tab2).toHaveAttribute("aria-controls");
69
+ expect(tab2).toHaveAttribute("tabindex", "0");
69
70
  });
70
71
 
71
72
  test("sets correct attributes on idle tab", () => {
72
73
  render(<TestTabs defaultValue="tab2" />);
73
- const tab = screen.getByTestId("tab1");
74
+ const tab1 = screen.getByTestId("tab1");
74
75
 
75
- expect(tab).toHaveAttribute("aria-selected", "false");
76
- expect(tab).toHaveAttribute("role", "tab");
77
- expect(tab).toHaveAttribute("aria-controls");
78
- expect(tab).toHaveAttribute("tabindex", "-1");
76
+ expect(tab1).toHaveAttribute("aria-selected", "false");
77
+ expect(tab1).toHaveAttribute("role", "tab");
78
+ expect(tab1).toHaveAttribute("aria-controls");
79
+ expect(tab1).toHaveAttribute("tabindex", "-1");
79
80
  });
80
81
 
81
82
  test("sets correct attributes on active tabpanel", () => {
82
83
  render(<TestTabs defaultValue="tab2" />);
83
- const panel = screen.getByTestId("tabpanel2");
84
+ const panel2 = screen.getByTestId("tabpanel2");
84
85
 
85
- expect(panel).toHaveAttribute("aria-labelledby");
86
- expect(panel).toHaveAttribute("role", "tabpanel");
87
- expect(panel).toHaveAttribute("tabindex", "0");
88
- expect(panel).toHaveTextContent("Tabpanel 2");
89
- expect(panel).toHaveStyle({ display: "block" });
86
+ expect(panel2).toHaveAttribute("aria-labelledby");
87
+ expect(panel2).toHaveAttribute("role", "tabpanel");
88
+ expect(panel2).toHaveAttribute("tabindex", "0");
89
+ expect(panel2).toHaveTextContent("Tabpanel 2");
90
+ expect(panel2).toHaveStyle({ display: "block" });
90
91
  });
91
92
 
92
93
  test("sets correct attributes on idle tabpanel", () => {
93
94
  render(<TestTabs defaultValue="tab1" />);
94
- const panel = screen.getByTestId("tabpanel2");
95
+ const panel2 = screen.getByTestId("tabpanel2");
95
96
 
96
- expect(panel).toHaveAttribute("aria-labelledby");
97
- expect(panel).toHaveAttribute("role", "tabpanel");
98
- expect(panel).toHaveAttribute("tabindex", "0");
99
- expect(panel).toBeEmptyDOMElement();
100
- expect(panel).toHaveStyle({ display: "none" });
97
+ expect(panel2).toHaveAttribute("aria-labelledby");
98
+ expect(panel2).toHaveAttribute("role", "tabpanel");
99
+ expect(panel2).toHaveAttribute("tabindex", "0");
100
+ expect(panel2).toBeEmptyDOMElement();
101
+ expect(panel2).toHaveStyle({ display: "none" });
101
102
  });
102
103
 
103
104
  test("sets tabindex to 0 when focused", () => {
104
- render(<TestTabs defaultValue="tab2" />);
105
- const tab = screen.getByTestId("tab2");
105
+ render(<TestTabs defaultValue="tab1" />);
106
+ const tab2 = screen.getByTestId("tab2");
107
+
108
+ fireEvent.focus(tab2);
109
+ expect(tab2).toHaveAttribute("tabindex", "0");
110
+ });
111
+
112
+ test("rowing tabindex keydown moves focus", () => {
113
+ render(<TestTabs defaultValue="tab1" />);
114
+ const tab1 = screen.getByTestId("tab1");
115
+
116
+ expect(tab1).toHaveAttribute("tabindex", "0");
117
+ fireEvent.keyDown(tab1, { key: "ArrowRight" });
118
+
119
+ expect(tab1).toHaveAttribute("tabindex", "-1");
120
+ expect(screen.getByTestId("tab2")).toHaveAttribute("tabindex", "0");
121
+ expect(screen.getByTestId("tab2")).toHaveAttribute(
122
+ "aria-selected",
123
+ "false",
124
+ );
125
+ });
126
+
127
+ test("selectionFollowsFocus moves active tabs", () => {
128
+ render(<TestTabs defaultValue="tab1" selectionFollowsFocus />);
129
+ const tab1 = screen.getByTestId("tab1");
106
130
 
107
- fireEvent.focus(tab);
108
- expect(tab).toHaveAttribute("tabindex", "0");
131
+ expect(tab1).toHaveAttribute("tabindex", "0");
132
+ fireEvent.keyDown(tab1, { key: "ArrowRight" });
133
+
134
+ expect(screen.getByTestId("tab2")).toHaveAttribute("aria-selected", "true");
135
+ expect(screen.getByTestId("tab2")).toHaveAttribute("tabindex", "0");
136
+ });
137
+
138
+ test("tabbing from tabs moves focus to tabPanel", async () => {
139
+ render(<TestTabs defaultValue="tab1" />);
140
+ const tab1 = screen.getByTestId("tab1");
141
+
142
+ tab1.focus();
143
+ await userEvent.tab();
144
+
145
+ expect(screen.getByTestId("tabpanel1")).toHaveFocus();
146
+ });
147
+
148
+ test("shift+tab back to tablist should focus selected tab", async () => {
149
+ render(<TestTabs defaultValue="tab1" />);
150
+ const tab1 = screen.getByTestId("tab1");
151
+
152
+ /* Move focus to tab2 */
153
+ fireEvent.keyDown(tab1, { key: "ArrowRight" });
154
+ expect(screen.getByTestId("tab2")).toHaveFocus();
155
+
156
+ /* Move focus to tabPanel */
157
+ // eslint-disable-next-line testing-library/no-unnecessary-act
158
+ await act(async () => {
159
+ /* Tablist handles tabbing with setTimeout, so we need to use act */
160
+ await userEvent.tab();
161
+ });
162
+
163
+ expect(screen.getByTestId("tabpanel1")).toHaveFocus();
164
+ /* Move focus back to tablist, now tab1 should have focus */
165
+
166
+ // eslint-disable-next-line testing-library/no-unnecessary-act
167
+ await act(async () => {
168
+ await userEvent.tab({ shift: true });
169
+ });
170
+ expect(screen.getByTestId("tab1")).toHaveFocus();
109
171
  });
110
172
  });