@entur/tab 0.7.1 → 1.0.0-next.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.
package/dist/Tab.d.ts CHANGED
@@ -5,8 +5,8 @@ export type TabProps = {
5
5
  /** Om taben er disabled eller ikke */
6
6
  disabled?: boolean;
7
7
  /** HTML-elementet eller React-komponenten som lager komponenten */
8
- as?: keyof JSX.IntrinsicElements | any;
8
+ as?: keyof JSX.IntrinsicElements | React.ElementType;
9
9
  removeActiveLine?: boolean;
10
- [key: string]: any;
11
- };
12
- export declare const Tab: React.FC<TabProps>;
10
+ className?: string;
11
+ } & Omit<React.ComponentPropsWithoutRef<'button'>, 'children' | 'disabled'>;
12
+ export declare const Tab: ({ className, removeActiveLine, as, disabled, children, ...rest }: TabProps) => import("react/jsx-runtime").JSX.Element;
package/dist/TabList.d.ts CHANGED
@@ -3,8 +3,12 @@ export type TabListProps = {
3
3
  /** Tab-komponenter */
4
4
  children: React.ReactNode;
5
5
  /** HTML-elementet eller React-komponenten som lager komponenten */
6
- as?: keyof JSX.IntrinsicElements | any;
6
+ as?: keyof JSX.IntrinsicElements | React.ElementType;
7
7
  width?: 'fluid';
8
- [key: string]: any;
9
- };
10
- export declare const TabList: React.FC<TabListProps>;
8
+ className?: string;
9
+ /** Tilgjengelig navn på tab-listen (dersom det ikke finnes en synlig overskrift) */
10
+ 'aria-label'?: string;
11
+ /** ID til elementet som navngir tab-listen */
12
+ 'aria-labelledby'?: string;
13
+ } & Omit<React.ComponentPropsWithoutRef<'div'>, 'children'>;
14
+ export declare const TabList: ({ className, width, as, children, ...rest }: TabListProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,9 +1,9 @@
1
1
  import { default as React } from 'react';
2
2
  export type TabPanelProps = {
3
- /** Overskriften til taben */
4
- children: React.ReactNode;
3
+ /** Innholdet i tab-panelet */
4
+ children?: React.ReactNode;
5
5
  /** HTML-elementet eller React-komponenten som lager komponenten */
6
- as?: keyof JSX.IntrinsicElements | any;
7
- [key: string]: any;
8
- };
9
- export declare const TabPanel: React.FC<TabPanelProps>;
6
+ as?: keyof JSX.IntrinsicElements | React.ElementType;
7
+ className?: string;
8
+ } & Omit<React.ComponentPropsWithoutRef<'div'>, 'children'>;
9
+ export declare const TabPanel: ({ className, as, children, ...rest }: TabPanelProps) => import("react/jsx-runtime").JSX.Element | null;
@@ -3,7 +3,9 @@ export type TabPanelsProps = {
3
3
  /** Tab-panelene */
4
4
  children: React.ReactNode;
5
5
  /** HTML-elementet eller React-komponenten som lager komponenten */
6
- as?: keyof JSX.IntrinsicElements | any;
7
- [key: string]: any;
8
- };
9
- export declare const TabPanels: React.FC<TabPanelsProps>;
6
+ as?: keyof JSX.IntrinsicElements | React.ElementType;
7
+ /** Behold alle panel-noder i DOM (skjult med hidden-attributt) i stedet for å avmontere */
8
+ keepMounted?: boolean;
9
+ className?: string;
10
+ } & Omit<React.ComponentPropsWithoutRef<'div'>, 'children'>;
11
+ export declare const TabPanels: ({ className, as, keepMounted, children, ...rest }: TabPanelsProps) => import("react/jsx-runtime").JSX.Element;
package/dist/Tabs.d.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  import { default as React } from 'react';
2
2
  export type TabsProps = {
3
- /** Overskriften til taben */
3
+ /** Tab-innholdet */
4
4
  children: React.ReactNode;
5
5
  /** Kalles når taben endres */
6
6
  onChange?: (index: number) => void;
7
7
  /** Hvilken tab som skal være åpen by default */
8
8
  defaultIndex?: number;
9
- /** Den åpne indexen */
9
+ /** Den åpne indexen (kontrollert) */
10
10
  index?: number;
11
11
  /** HTML-elementet eller React-komponenten som lager komponenten */
12
- as?: keyof JSX.IntrinsicElements | any;
13
- [key: string]: any;
14
- };
15
- export declare const Tabs: React.FC<TabsProps>;
12
+ as?: keyof JSX.IntrinsicElements | React.ElementType;
13
+ className?: string;
14
+ } & Omit<React.ComponentPropsWithoutRef<'div'>, 'children' | 'onChange'>;
15
+ export declare const Tabs: ({ className, index, defaultIndex, onChange, as, children, ...rest }: TabsProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { default as React } from 'react';
2
+ export type TabsContextValue = {
3
+ selectedIndex: number;
4
+ onSelect: (index: number) => void;
5
+ tabsId: string;
6
+ };
7
+ export declare const TabsContext: React.Context<TabsContextValue>;
8
+ export type TabItemContextValue = {
9
+ tabIndex: number;
10
+ tabId: string;
11
+ panelId: string;
12
+ };
13
+ export declare const TabItemContext: React.Context<TabItemContextValue | null>;
14
+ export type TabPanelItemContextValue = {
15
+ tabIndex: number;
16
+ tabId: string;
17
+ panelId: string;
18
+ keepMounted: boolean;
19
+ };
20
+ export declare const TabPanelItemContext: React.Context<TabPanelItemContextValue | null>;
package/dist/styles.css CHANGED
@@ -186,7 +186,6 @@
186
186
  }
187
187
 
188
188
  :root{
189
- --reach-tabs:1;
190
189
  --eds-tab:1;
191
190
  }
192
191
 
@@ -237,6 +236,18 @@
237
236
  color:#181c56;
238
237
  color:var(--components-tab-standard-text);
239
238
  cursor:pointer;
239
+ display:-webkit-inline-box;
240
+ display:-webkit-inline-flex;
241
+ display:-moz-inline-box;
242
+ display:inline-flex;
243
+ -webkit-box-align:center;
244
+ -webkit-align-items:center;
245
+ -moz-box-align:center;
246
+ align-items:center;
247
+ -webkit-box-pack:center;
248
+ -webkit-justify-content:center;
249
+ -moz-box-pack:center;
250
+ justify-content:center;
240
251
  font-family:inherit;
241
252
  font-size:inherit;
242
253
  height:3rem;
@@ -331,7 +342,7 @@
331
342
  .eds-tab--remove-active-line[aria-selected=true]::before{
332
343
  background:transparent;
333
344
  }
334
- .eds-tab[disabled]{
345
+ .eds-tab[disabled], .eds-tab[aria-disabled=true]{
335
346
  background:#cfd2d4;
336
347
  background:var(--components-tab-standard-fill-disabled);
337
348
  border-color:none;
@@ -339,7 +350,7 @@
339
350
  color:var(--components-tab-standard-text-disabled);
340
351
  cursor:not-allowed;
341
352
  }
342
- .eds-contrast .eds-tab[disabled]{
353
+ .eds-contrast .eds-tab[disabled], .eds-contrast .eds-tab[aria-disabled=true]{
343
354
  background:rgba(84, 86, 140, 0.4);
344
355
  background:var(--components-tab-contrast-fill-disabled);
345
356
  border-color:none;
package/dist/tab.cjs.js CHANGED
@@ -2,59 +2,191 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const utils = require("@entur/utils");
4
4
  const jsxRuntime = require("react/jsx-runtime");
5
- const tabs = require("@reach/tabs");
5
+ const React = require("react");
6
6
  const classNames = require("classnames");
7
+ const TabsContext = React.createContext({
8
+ selectedIndex: 0,
9
+ onSelect: () => void 0,
10
+ tabsId: ""
11
+ });
12
+ const TabItemContext = React.createContext(
13
+ null
14
+ );
15
+ const TabPanelItemContext = React.createContext(null);
7
16
  const Tab = ({
8
17
  className,
9
18
  removeActiveLine = false,
19
+ as,
20
+ disabled = false,
21
+ children,
10
22
  ...rest
11
23
  }) => {
24
+ const { selectedIndex, onSelect } = React.useContext(TabsContext);
25
+ const itemContext = React.useContext(TabItemContext);
26
+ const tabIndex = itemContext?.tabIndex ?? 0;
27
+ const isSelected = selectedIndex === tabIndex;
28
+ const Element = as || "button";
12
29
  return /* @__PURE__ */ jsxRuntime.jsx(
13
- tabs.Tab,
30
+ Element,
14
31
  {
32
+ role: "tab",
33
+ type: as ? void 0 : "button",
34
+ id: itemContext?.tabId,
35
+ "aria-selected": isSelected,
36
+ "aria-controls": itemContext?.panelId,
37
+ tabIndex: isSelected ? 0 : -1,
38
+ disabled: disabled || void 0,
39
+ "aria-disabled": disabled || void 0,
15
40
  className: classNames(
16
41
  "eds-tab",
17
42
  { "eds-tab--remove-active-line": removeActiveLine },
18
43
  className
19
44
  ),
20
- ...rest
45
+ onClick: () => {
46
+ if (!disabled) onSelect(tabIndex);
47
+ },
48
+ ...rest,
49
+ children
21
50
  }
22
51
  );
23
52
  };
24
- const Tabs = ({ className, ...rest }) => {
25
- return /* @__PURE__ */ jsxRuntime.jsx(tabs.Tabs, { className: classNames("eds-tabs", className), ...rest });
53
+ const Tabs = ({
54
+ className,
55
+ index,
56
+ defaultIndex,
57
+ onChange,
58
+ as,
59
+ children,
60
+ ...rest
61
+ }) => {
62
+ const [internalIndex, setInternalIndex] = React.useState(defaultIndex ?? 0);
63
+ const isControlled = index !== void 0;
64
+ const selectedIndex = isControlled ? index : internalIndex;
65
+ const tabsId = React.useId();
66
+ const onSelect = React.useCallback(
67
+ (i) => {
68
+ if (!isControlled) {
69
+ setInternalIndex(i);
70
+ }
71
+ onChange?.(i);
72
+ },
73
+ [isControlled, onChange]
74
+ );
75
+ const Element = as || "div";
76
+ return /* @__PURE__ */ jsxRuntime.jsx(TabsContext.Provider, { value: { selectedIndex, onSelect, tabsId }, children: /* @__PURE__ */ jsxRuntime.jsx(Element, { className: classNames("eds-tabs", className), ...rest, children }) });
26
77
  };
27
- const TabPanel = ({ className, ...rest }) => {
78
+ const TabPanel = ({
79
+ className,
80
+ as,
81
+ children,
82
+ ...rest
83
+ }) => {
84
+ const { selectedIndex } = React.useContext(TabsContext);
85
+ const itemContext = React.useContext(TabPanelItemContext);
86
+ const tabIndex = itemContext?.tabIndex ?? 0;
87
+ const keepMounted = itemContext?.keepMounted ?? false;
88
+ const isSelected = selectedIndex === tabIndex;
89
+ const isHiddenButMounted = keepMounted && !isSelected;
90
+ if (!isSelected && !keepMounted) return null;
91
+ const Element = as || "div";
28
92
  return /* @__PURE__ */ jsxRuntime.jsx(
29
- tabs.TabPanel,
93
+ Element,
30
94
  {
95
+ role: "tabpanel",
96
+ id: itemContext?.panelId,
97
+ "aria-labelledby": itemContext?.tabId,
98
+ tabIndex: isSelected ? 0 : -1,
99
+ hidden: isHiddenButMounted || void 0,
31
100
  className: classNames("eds-tab-panel", className),
32
101
  ...rest,
33
- tabIndex: void 0
102
+ children
34
103
  }
35
104
  );
36
105
  };
37
- const TabPanels = ({ className, ...rest }) => {
38
- return /* @__PURE__ */ jsxRuntime.jsx(
39
- tabs.TabPanels,
106
+ const TabPanels = ({
107
+ className,
108
+ as,
109
+ keepMounted = false,
110
+ children,
111
+ ...rest
112
+ }) => {
113
+ const { tabsId } = React.useContext(TabsContext);
114
+ const Element = as || "div";
115
+ return /* @__PURE__ */ jsxRuntime.jsx(Element, { className: classNames("eds-tab-panels", className), ...rest, children: React.Children.map(children, (child, idx) => /* @__PURE__ */ jsxRuntime.jsx(
116
+ TabPanelItemContext.Provider,
40
117
  {
41
- className: classNames("eds-tab-panels", className),
42
- ...rest
118
+ value: {
119
+ tabIndex: idx,
120
+ tabId: `${tabsId}-tab-${idx}`,
121
+ panelId: `${tabsId}-panel-${idx}`,
122
+ keepMounted
123
+ },
124
+ children: child
43
125
  }
44
- );
126
+ )) });
45
127
  };
46
128
  const TabList = ({
47
129
  className,
48
130
  width,
131
+ as,
132
+ children,
49
133
  ...rest
50
134
  }) => {
135
+ const { tabsId } = React.useContext(TabsContext);
136
+ const tabListRef = React.useRef(null);
137
+ const handleKeyDown = React.useCallback((e) => {
138
+ const tabs = tabListRef.current?.querySelectorAll(
139
+ '[role="tab"]:not([disabled])'
140
+ );
141
+ if (!tabs || tabs.length === 0) return;
142
+ const currentIndex = Array.from(tabs).findIndex(
143
+ (tab) => tab === document.activeElement
144
+ );
145
+ if (currentIndex === -1) return;
146
+ let nextIndex;
147
+ switch (e.key) {
148
+ case "ArrowRight":
149
+ nextIndex = (currentIndex + 1) % tabs.length;
150
+ break;
151
+ case "ArrowLeft":
152
+ nextIndex = (currentIndex - 1 + tabs.length) % tabs.length;
153
+ break;
154
+ case "Home":
155
+ nextIndex = 0;
156
+ break;
157
+ case "End":
158
+ nextIndex = tabs.length - 1;
159
+ break;
160
+ }
161
+ if (nextIndex !== void 0) {
162
+ e.preventDefault();
163
+ tabs[nextIndex].focus();
164
+ tabs[nextIndex].click();
165
+ }
166
+ }, []);
167
+ const Element = as || "div";
51
168
  return /* @__PURE__ */ jsxRuntime.jsx(
52
- tabs.TabList,
169
+ Element,
53
170
  {
171
+ role: "tablist",
172
+ tabIndex: -1,
173
+ ref: tabListRef,
54
174
  className: classNames("eds-tab-list", className, {
55
175
  "eds-tab-list--width-fluid": width === "fluid"
56
176
  }),
57
- ...rest
177
+ onKeyDown: handleKeyDown,
178
+ ...rest,
179
+ children: React.Children.map(children, (child, idx) => /* @__PURE__ */ jsxRuntime.jsx(
180
+ TabItemContext.Provider,
181
+ {
182
+ value: {
183
+ tabIndex: idx,
184
+ tabId: `${tabsId}-tab-${idx}`,
185
+ panelId: `${tabsId}-panel-${idx}`
186
+ },
187
+ children: child
188
+ }
189
+ ))
58
190
  }
59
191
  );
60
192
  };
@@ -1 +1 @@
1
- {"version":3,"file":"tab.cjs.js","sources":["../src/Tab.tsx","../src/Tabs.tsx","../src/TabPanel.tsx","../src/TabPanels.tsx","../src/TabList.tsx","../src/index.tsx"],"sourcesContent":["import React from 'react';\nimport { Tab as ReachTab } from '@reach/tabs';\nimport classNames from 'classnames';\n\nexport type TabProps = {\n /** Overskriften til taben */\n children: React.ReactNode;\n /** Om taben er disabled eller ikke */\n disabled?: boolean;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | any;\n removeActiveLine?: boolean;\n [key: string]: any;\n};\n\nexport const Tab: React.FC<TabProps> = ({\n className,\n removeActiveLine = false,\n ...rest\n}) => {\n return (\n <ReachTab\n className={classNames(\n 'eds-tab',\n { 'eds-tab--remove-active-line': removeActiveLine },\n className,\n )}\n {...rest}\n />\n );\n};\n","import React from 'react';\nimport { Tabs as ReachTabs } from '@reach/tabs';\nimport classNames from 'classnames';\n\nexport type TabsProps = {\n /** Overskriften til taben */\n children: React.ReactNode;\n /** Kalles når taben endres */\n onChange?: (index: number) => void;\n /** Hvilken tab som skal være åpen by default */\n defaultIndex?: number;\n /** Den åpne indexen */\n index?: number;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | any;\n\n [key: string]: any;\n};\n\nexport const Tabs: React.FC<TabsProps> = ({ className, ...rest }) => {\n return <ReachTabs className={classNames('eds-tabs', className)} {...rest} />;\n};\n","import React from 'react';\nimport { TabPanel as ReachTabPanel } from '@reach/tabs';\nimport classNames from 'classnames';\n\nexport type TabPanelProps = {\n /** Overskriften til taben */\n children: React.ReactNode;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | any;\n [key: string]: any;\n};\n\nexport const TabPanel: React.FC<TabPanelProps> = ({ className, ...rest }) => {\n return (\n <ReachTabPanel\n className={classNames('eds-tab-panel', className)}\n {...rest}\n tabIndex={undefined}\n />\n );\n};\n","import React from 'react';\nimport { TabPanels as ReachTabPanels } from '@reach/tabs';\nimport classNames from 'classnames';\n\nexport type TabPanelsProps = {\n /** Tab-panelene */\n children: React.ReactNode;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | any;\n [key: string]: any;\n};\n\nexport const TabPanels: React.FC<TabPanelsProps> = ({ className, ...rest }) => {\n return (\n <ReachTabPanels\n className={classNames('eds-tab-panels', className)}\n {...rest}\n />\n );\n};\n","import React from 'react';\nimport { TabList as ReachTabList } from '@reach/tabs';\nimport classNames from 'classnames';\n\nexport type TabListProps = {\n /** Tab-komponenter */\n children: React.ReactNode;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | any;\n width?: 'fluid';\n [key: string]: any;\n};\n\nexport const TabList: React.FC<TabListProps> = ({\n className,\n width,\n ...rest\n}) => {\n return (\n <ReachTabList\n className={classNames('eds-tab-list', className, {\n 'eds-tab-list--width-fluid': width === 'fluid',\n })}\n {...rest}\n />\n );\n};\n","import { warnAboutMissingStyles } from '@entur/utils';\nimport './index.scss';\n\nwarnAboutMissingStyles('tab');\n\nexport * from './Tab';\nexport * from './Tabs';\nexport * from './TabPanel';\nexport * from './TabPanels';\nexport * from './TabList';\n"],"names":["jsx","ReachTab","ReachTabs","ReachTabPanel","ReachTabPanels","ReachTabList","warnAboutMissingStyles"],"mappings":";;;;;;AAeO,MAAM,MAA0B,CAAC;AAAA,EACtC;AAAA,EACA,mBAAmB;AAAA,EACnB,GAAG;AACL,MAAM;AACJ,SACEA,2BAAAA;AAAAA,IAACC,KAAAA;AAAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,EAAE,+BAA+B,iBAAA;AAAA,QACjC;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;ACXO,MAAM,OAA4B,CAAC,EAAE,WAAW,GAAG,WAAW;AACnE,SAAOD,2BAAAA,IAACE,aAAU,WAAW,WAAW,YAAY,SAAS,GAAI,GAAG,MAAM;AAC5E;ACTO,MAAM,WAAoC,CAAC,EAAE,WAAW,GAAG,WAAW;AAC3E,SACEF,2BAAAA;AAAAA,IAACG,KAAAA;AAAAA,IAAA;AAAA,MACC,WAAW,WAAW,iBAAiB,SAAS;AAAA,MAC/C,GAAG;AAAA,MACJ,UAAU;AAAA,IAAA;AAAA,EAAA;AAGhB;ACRO,MAAM,YAAsC,CAAC,EAAE,WAAW,GAAG,WAAW;AAC7E,SACEH,2BAAAA;AAAAA,IAACI,KAAAA;AAAAA,IAAA;AAAA,MACC,WAAW,WAAW,kBAAkB,SAAS;AAAA,MAChD,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;ACNO,MAAM,UAAkC,CAAC;AAAA,EAC9C;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAM;AACJ,SACEJ,2BAAAA;AAAAA,IAACK,KAAAA;AAAAA,IAAA;AAAA,MACC,WAAW,WAAW,gBAAgB,WAAW;AAAA,QAC/C,6BAA6B,UAAU;AAAA,MAAA,CACxC;AAAA,MACA,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;ACvBAC,MAAAA,uBAAuB,KAAK;;;;;;"}
1
+ {"version":3,"file":"tab.cjs.js","sources":["../src/TabsContext.tsx","../src/Tab.tsx","../src/Tabs.tsx","../src/TabPanel.tsx","../src/TabPanels.tsx","../src/TabList.tsx","../src/index.tsx"],"sourcesContent":["import React from 'react';\n\nexport type TabsContextValue = {\n selectedIndex: number;\n onSelect: (index: number) => void;\n tabsId: string;\n};\n\nexport const TabsContext = React.createContext<TabsContextValue>({\n selectedIndex: 0,\n onSelect: () => undefined,\n tabsId: '',\n});\n\nexport type TabItemContextValue = {\n tabIndex: number;\n tabId: string;\n panelId: string;\n};\n\nexport const TabItemContext = React.createContext<TabItemContextValue | null>(\n null,\n);\n\nexport type TabPanelItemContextValue = {\n tabIndex: number;\n tabId: string;\n panelId: string;\n keepMounted: boolean;\n};\n\nexport const TabPanelItemContext =\n React.createContext<TabPanelItemContextValue | null>(null);\n","import React, { useContext } from 'react';\nimport classNames from 'classnames';\n\nimport { TabItemContext, TabsContext } from './TabsContext';\n\nexport type TabProps = {\n /** Overskriften til taben */\n children: React.ReactNode;\n /** Om taben er disabled eller ikke */\n disabled?: boolean;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | React.ElementType;\n removeActiveLine?: boolean;\n className?: string;\n} & Omit<React.ComponentPropsWithoutRef<'button'>, 'children' | 'disabled'>;\n\nexport const Tab = ({\n className,\n removeActiveLine = false,\n as,\n disabled = false,\n children,\n ...rest\n}: TabProps) => {\n const { selectedIndex, onSelect } = useContext(TabsContext);\n const itemContext = useContext(TabItemContext);\n const tabIndex = itemContext?.tabIndex ?? 0;\n const isSelected = selectedIndex === tabIndex;\n const Element: React.ElementType = as || 'button';\n\n return (\n <Element\n role=\"tab\"\n type={as ? undefined : 'button'}\n id={itemContext?.tabId}\n aria-selected={isSelected}\n aria-controls={itemContext?.panelId}\n tabIndex={isSelected ? 0 : -1}\n disabled={disabled || undefined}\n aria-disabled={disabled || undefined}\n className={classNames(\n 'eds-tab',\n { 'eds-tab--remove-active-line': removeActiveLine },\n className,\n )}\n onClick={() => {\n if (!disabled) onSelect(tabIndex);\n }}\n {...rest}\n >\n {children}\n </Element>\n );\n};\n","import React, { useCallback, useId, useState } from 'react';\nimport classNames from 'classnames';\n\nimport { TabsContext } from './TabsContext';\n\nexport type TabsProps = {\n /** Tab-innholdet */\n children: React.ReactNode;\n /** Kalles når taben endres */\n onChange?: (index: number) => void;\n /** Hvilken tab som skal være åpen by default */\n defaultIndex?: number;\n /** Den åpne indexen (kontrollert) */\n index?: number;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | React.ElementType;\n className?: string;\n} & Omit<React.ComponentPropsWithoutRef<'div'>, 'children' | 'onChange'>;\n\nexport const Tabs = ({\n className,\n index,\n defaultIndex,\n onChange,\n as,\n children,\n ...rest\n}: TabsProps) => {\n const [internalIndex, setInternalIndex] = useState(defaultIndex ?? 0);\n const isControlled = index !== undefined;\n const selectedIndex = isControlled ? index : internalIndex;\n const tabsId = useId();\n\n const onSelect = useCallback(\n (i: number) => {\n if (!isControlled) {\n setInternalIndex(i);\n }\n onChange?.(i);\n },\n [isControlled, onChange],\n );\n\n const Element: React.ElementType = as || 'div';\n\n return (\n <TabsContext.Provider value={{ selectedIndex, onSelect, tabsId }}>\n <Element className={classNames('eds-tabs', className)} {...rest}>\n {children}\n </Element>\n </TabsContext.Provider>\n );\n};\n","import React, { useContext } from 'react';\nimport classNames from 'classnames';\n\nimport { TabPanelItemContext, TabsContext } from './TabsContext';\n\nexport type TabPanelProps = {\n /** Innholdet i tab-panelet */\n children?: React.ReactNode;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | React.ElementType;\n className?: string;\n} & Omit<React.ComponentPropsWithoutRef<'div'>, 'children'>;\n\nexport const TabPanel = ({\n className,\n as,\n children,\n ...rest\n}: TabPanelProps) => {\n const { selectedIndex } = useContext(TabsContext);\n const itemContext = useContext(TabPanelItemContext);\n const tabIndex = itemContext?.tabIndex ?? 0;\n const keepMounted = itemContext?.keepMounted ?? false;\n\n const isSelected = selectedIndex === tabIndex;\n const isHiddenButMounted = keepMounted && !isSelected;\n\n if (!isSelected && !keepMounted) return null;\n\n const Element: React.ElementType = as || 'div';\n\n return (\n <Element\n role=\"tabpanel\"\n id={itemContext?.panelId}\n aria-labelledby={itemContext?.tabId}\n tabIndex={isSelected ? 0 : -1}\n hidden={isHiddenButMounted || undefined}\n className={classNames('eds-tab-panel', className)}\n {...rest}\n >\n {children}\n </Element>\n );\n};\n","import React, { useContext } from 'react';\nimport classNames from 'classnames';\n\nimport { TabPanelItemContext, TabsContext } from './TabsContext';\n\nexport type TabPanelsProps = {\n /** Tab-panelene */\n children: React.ReactNode;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | React.ElementType;\n /** Behold alle panel-noder i DOM (skjult med hidden-attributt) i stedet for å avmontere */\n keepMounted?: boolean;\n className?: string;\n} & Omit<React.ComponentPropsWithoutRef<'div'>, 'children'>;\n\nexport const TabPanels = ({\n className,\n as,\n keepMounted = false,\n children,\n ...rest\n}: TabPanelsProps) => {\n const { tabsId } = useContext(TabsContext);\n\n const Element: React.ElementType = as || 'div';\n\n return (\n <Element className={classNames('eds-tab-panels', className)} {...rest}>\n {React.Children.map(children, (child, idx) => (\n <TabPanelItemContext.Provider\n value={{\n tabIndex: idx,\n tabId: `${tabsId}-tab-${idx}`,\n panelId: `${tabsId}-panel-${idx}`,\n keepMounted,\n }}\n >\n {child}\n </TabPanelItemContext.Provider>\n ))}\n </Element>\n );\n};\n","import React, { useCallback, useContext, useRef } from 'react';\nimport classNames from 'classnames';\n\nimport { TabItemContext, TabsContext } from './TabsContext';\n\nexport type TabListProps = {\n /** Tab-komponenter */\n children: React.ReactNode;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | React.ElementType;\n width?: 'fluid';\n className?: string;\n /** Tilgjengelig navn på tab-listen (dersom det ikke finnes en synlig overskrift) */\n 'aria-label'?: string;\n /** ID til elementet som navngir tab-listen */\n 'aria-labelledby'?: string;\n} & Omit<React.ComponentPropsWithoutRef<'div'>, 'children'>;\n\nexport const TabList = ({\n className,\n width,\n as,\n children,\n ...rest\n}: TabListProps) => {\n const { tabsId } = useContext(TabsContext);\n const tabListRef = useRef<HTMLElement>(null);\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n const tabs = tabListRef.current?.querySelectorAll<HTMLElement>(\n '[role=\"tab\"]:not([disabled])',\n );\n if (!tabs || tabs.length === 0) return;\n\n const currentIndex = Array.from(tabs).findIndex(\n tab => tab === document.activeElement,\n );\n if (currentIndex === -1) return;\n\n let nextIndex: number | undefined;\n switch (e.key) {\n case 'ArrowRight':\n nextIndex = (currentIndex + 1) % tabs.length;\n break;\n case 'ArrowLeft':\n nextIndex = (currentIndex - 1 + tabs.length) % tabs.length;\n break;\n case 'Home':\n nextIndex = 0;\n break;\n case 'End':\n nextIndex = tabs.length - 1;\n break;\n }\n\n if (nextIndex !== undefined) {\n e.preventDefault();\n tabs[nextIndex].focus();\n tabs[nextIndex].click();\n }\n }, []);\n\n const Element: React.ElementType = as || 'div';\n\n return (\n <Element\n role=\"tablist\"\n tabIndex={-1}\n ref={tabListRef}\n className={classNames('eds-tab-list', className, {\n 'eds-tab-list--width-fluid': width === 'fluid',\n })}\n onKeyDown={handleKeyDown}\n {...rest}\n >\n {React.Children.map(children, (child, idx) => (\n <TabItemContext.Provider\n value={{\n tabIndex: idx,\n tabId: `${tabsId}-tab-${idx}`,\n panelId: `${tabsId}-panel-${idx}`,\n }}\n >\n {child}\n </TabItemContext.Provider>\n ))}\n </Element>\n );\n};\n","import { warnAboutMissingStyles } from '@entur/utils';\nimport './index.scss';\n\nwarnAboutMissingStyles('tab');\n\nexport * from './Tab';\nexport * from './Tabs';\nexport * from './TabPanel';\nexport * from './TabPanels';\nexport * from './TabList';\n"],"names":["useContext","jsx","useState","useId","useCallback","useRef","warnAboutMissingStyles"],"mappings":";;;;;;AAQO,MAAM,cAAc,MAAM,cAAgC;AAAA,EAC/D,eAAe;AAAA,EACf,UAAU,MAAM;AAAA,EAChB,QAAQ;AACV,CAAC;AAQM,MAAM,iBAAiB,MAAM;AAAA,EAClC;AACF;AASO,MAAM,sBACX,MAAM,cAA+C,IAAI;AChBpD,MAAM,MAAM,CAAC;AAAA,EAClB;AAAA,EACA,mBAAmB;AAAA,EACnB;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA,GAAG;AACL,MAAgB;AACd,QAAM,EAAE,eAAe,aAAaA,MAAAA,WAAW,WAAW;AAC1D,QAAM,cAAcA,MAAAA,WAAW,cAAc;AAC7C,QAAM,WAAW,aAAa,YAAY;AAC1C,QAAM,aAAa,kBAAkB;AACrC,QAAM,UAA6B,MAAM;AAEzC,SACEC,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,MAAM,KAAK,SAAY;AAAA,MACvB,IAAI,aAAa;AAAA,MACjB,iBAAe;AAAA,MACf,iBAAe,aAAa;AAAA,MAC5B,UAAU,aAAa,IAAI;AAAA,MAC3B,UAAU,YAAY;AAAA,MACtB,iBAAe,YAAY;AAAA,MAC3B,WAAW;AAAA,QACT;AAAA,QACA,EAAE,+BAA+B,iBAAA;AAAA,QACjC;AAAA,MAAA;AAAA,MAEF,SAAS,MAAM;AACb,YAAI,CAAC,SAAU,UAAS,QAAQ;AAAA,MAClC;AAAA,MACC,GAAG;AAAA,MAEH;AAAA,IAAA;AAAA,EAAA;AAGP;AClCO,MAAM,OAAO,CAAC;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAiB;AACf,QAAM,CAAC,eAAe,gBAAgB,IAAIC,MAAAA,SAAS,gBAAgB,CAAC;AACpE,QAAM,eAAe,UAAU;AAC/B,QAAM,gBAAgB,eAAe,QAAQ;AAC7C,QAAM,SAASC,MAAAA,MAAA;AAEf,QAAM,WAAWC,MAAAA;AAAAA,IACf,CAAC,MAAc;AACb,UAAI,CAAC,cAAc;AACjB,yBAAiB,CAAC;AAAA,MACpB;AACA,iBAAW,CAAC;AAAA,IACd;AAAA,IACA,CAAC,cAAc,QAAQ;AAAA,EAAA;AAGzB,QAAM,UAA6B,MAAM;AAEzC,SACEH,2BAAAA,IAAC,YAAY,UAAZ,EAAqB,OAAO,EAAE,eAAe,UAAU,OAAA,GACtD,yCAAC,SAAA,EAAQ,WAAW,WAAW,YAAY,SAAS,GAAI,GAAG,MACxD,UACH,GACF;AAEJ;ACvCO,MAAM,WAAW,CAAC;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAqB;AACnB,QAAM,EAAE,cAAA,IAAkBD,MAAAA,WAAW,WAAW;AAChD,QAAM,cAAcA,MAAAA,WAAW,mBAAmB;AAClD,QAAM,WAAW,aAAa,YAAY;AAC1C,QAAM,cAAc,aAAa,eAAe;AAEhD,QAAM,aAAa,kBAAkB;AACrC,QAAM,qBAAqB,eAAe,CAAC;AAE3C,MAAI,CAAC,cAAc,CAAC,YAAa,QAAO;AAExC,QAAM,UAA6B,MAAM;AAEzC,SACEC,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,IAAI,aAAa;AAAA,MACjB,mBAAiB,aAAa;AAAA,MAC9B,UAAU,aAAa,IAAI;AAAA,MAC3B,QAAQ,sBAAsB;AAAA,MAC9B,WAAW,WAAW,iBAAiB,SAAS;AAAA,MAC/C,GAAG;AAAA,MAEH;AAAA,IAAA;AAAA,EAAA;AAGP;AC7BO,MAAM,YAAY,CAAC;AAAA,EACxB;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA,GAAG;AACL,MAAsB;AACpB,QAAM,EAAE,OAAA,IAAWD,MAAAA,WAAW,WAAW;AAEzC,QAAM,UAA6B,MAAM;AAEzC,SACEC,2BAAAA,IAAC,SAAA,EAAQ,WAAW,WAAW,kBAAkB,SAAS,GAAI,GAAG,MAC9D,gBAAM,SAAS,IAAI,UAAU,CAAC,OAAO,QACpCA,2BAAAA;AAAAA,IAAC,oBAAoB;AAAA,IAApB;AAAA,MACC,OAAO;AAAA,QACL,UAAU;AAAA,QACV,OAAO,GAAG,MAAM,QAAQ,GAAG;AAAA,QAC3B,SAAS,GAAG,MAAM,UAAU,GAAG;AAAA,QAC/B;AAAA,MAAA;AAAA,MAGD,UAAA;AAAA,IAAA;AAAA,EAAA,CAEJ,GACH;AAEJ;ACxBO,MAAM,UAAU,CAAC;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAoB;AAClB,QAAM,EAAE,OAAA,IAAWD,MAAAA,WAAW,WAAW;AACzC,QAAM,aAAaK,MAAAA,OAAoB,IAAI;AAE3C,QAAM,gBAAgBD,kBAAY,CAAC,MAA2B;AAC5D,UAAM,OAAO,WAAW,SAAS;AAAA,MAC/B;AAAA,IAAA;AAEF,QAAI,CAAC,QAAQ,KAAK,WAAW,EAAG;AAEhC,UAAM,eAAe,MAAM,KAAK,IAAI,EAAE;AAAA,MACpC,CAAA,QAAO,QAAQ,SAAS;AAAA,IAAA;AAE1B,QAAI,iBAAiB,GAAI;AAEzB,QAAI;AACJ,YAAQ,EAAE,KAAA;AAAA,MACR,KAAK;AACH,qBAAa,eAAe,KAAK,KAAK;AACtC;AAAA,MACF,KAAK;AACH,qBAAa,eAAe,IAAI,KAAK,UAAU,KAAK;AACpD;AAAA,MACF,KAAK;AACH,oBAAY;AACZ;AAAA,MACF,KAAK;AACH,oBAAY,KAAK,SAAS;AAC1B;AAAA,IAAA;AAGJ,QAAI,cAAc,QAAW;AAC3B,QAAE,eAAA;AACF,WAAK,SAAS,EAAE,MAAA;AAChB,WAAK,SAAS,EAAE,MAAA;AAAA,IAClB;AAAA,EACF,GAAG,CAAA,CAAE;AAEL,QAAM,UAA6B,MAAM;AAEzC,SACEH,2BAAAA;AAAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,UAAU;AAAA,MACV,KAAK;AAAA,MACL,WAAW,WAAW,gBAAgB,WAAW;AAAA,QAC/C,6BAA6B,UAAU;AAAA,MAAA,CACxC;AAAA,MACD,WAAW;AAAA,MACV,GAAG;AAAA,MAEH,gBAAM,SAAS,IAAI,UAAU,CAAC,OAAO,QACpCA,2BAAAA;AAAAA,QAAC,eAAe;AAAA,QAAf;AAAA,UACC,OAAO;AAAA,YACL,UAAU;AAAA,YACV,OAAO,GAAG,MAAM,QAAQ,GAAG;AAAA,YAC3B,SAAS,GAAG,MAAM,UAAU,GAAG;AAAA,UAAA;AAAA,UAGhC,UAAA;AAAA,QAAA;AAAA,MAAA,CAEJ;AAAA,IAAA;AAAA,EAAA;AAGP;ACrFAK,MAAAA,uBAAuB,KAAK;;;;;;"}
package/dist/tab.esm.js CHANGED
@@ -1,58 +1,190 @@
1
1
  import { warnAboutMissingStyles } from "@entur/utils";
2
2
  import { jsx } from "react/jsx-runtime";
3
- import { Tab as Tab$1, Tabs as Tabs$1, TabPanel as TabPanel$1, TabPanels as TabPanels$1, TabList as TabList$1 } from "@reach/tabs";
3
+ import React, { useContext, useState, useId, useCallback, useRef } from "react";
4
4
  import classNames from "classnames";
5
+ const TabsContext = React.createContext({
6
+ selectedIndex: 0,
7
+ onSelect: () => void 0,
8
+ tabsId: ""
9
+ });
10
+ const TabItemContext = React.createContext(
11
+ null
12
+ );
13
+ const TabPanelItemContext = React.createContext(null);
5
14
  const Tab = ({
6
15
  className,
7
16
  removeActiveLine = false,
17
+ as,
18
+ disabled = false,
19
+ children,
8
20
  ...rest
9
21
  }) => {
22
+ const { selectedIndex, onSelect } = useContext(TabsContext);
23
+ const itemContext = useContext(TabItemContext);
24
+ const tabIndex = itemContext?.tabIndex ?? 0;
25
+ const isSelected = selectedIndex === tabIndex;
26
+ const Element = as || "button";
10
27
  return /* @__PURE__ */ jsx(
11
- Tab$1,
28
+ Element,
12
29
  {
30
+ role: "tab",
31
+ type: as ? void 0 : "button",
32
+ id: itemContext?.tabId,
33
+ "aria-selected": isSelected,
34
+ "aria-controls": itemContext?.panelId,
35
+ tabIndex: isSelected ? 0 : -1,
36
+ disabled: disabled || void 0,
37
+ "aria-disabled": disabled || void 0,
13
38
  className: classNames(
14
39
  "eds-tab",
15
40
  { "eds-tab--remove-active-line": removeActiveLine },
16
41
  className
17
42
  ),
18
- ...rest
43
+ onClick: () => {
44
+ if (!disabled) onSelect(tabIndex);
45
+ },
46
+ ...rest,
47
+ children
19
48
  }
20
49
  );
21
50
  };
22
- const Tabs = ({ className, ...rest }) => {
23
- return /* @__PURE__ */ jsx(Tabs$1, { className: classNames("eds-tabs", className), ...rest });
51
+ const Tabs = ({
52
+ className,
53
+ index,
54
+ defaultIndex,
55
+ onChange,
56
+ as,
57
+ children,
58
+ ...rest
59
+ }) => {
60
+ const [internalIndex, setInternalIndex] = useState(defaultIndex ?? 0);
61
+ const isControlled = index !== void 0;
62
+ const selectedIndex = isControlled ? index : internalIndex;
63
+ const tabsId = useId();
64
+ const onSelect = useCallback(
65
+ (i) => {
66
+ if (!isControlled) {
67
+ setInternalIndex(i);
68
+ }
69
+ onChange?.(i);
70
+ },
71
+ [isControlled, onChange]
72
+ );
73
+ const Element = as || "div";
74
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: { selectedIndex, onSelect, tabsId }, children: /* @__PURE__ */ jsx(Element, { className: classNames("eds-tabs", className), ...rest, children }) });
24
75
  };
25
- const TabPanel = ({ className, ...rest }) => {
76
+ const TabPanel = ({
77
+ className,
78
+ as,
79
+ children,
80
+ ...rest
81
+ }) => {
82
+ const { selectedIndex } = useContext(TabsContext);
83
+ const itemContext = useContext(TabPanelItemContext);
84
+ const tabIndex = itemContext?.tabIndex ?? 0;
85
+ const keepMounted = itemContext?.keepMounted ?? false;
86
+ const isSelected = selectedIndex === tabIndex;
87
+ const isHiddenButMounted = keepMounted && !isSelected;
88
+ if (!isSelected && !keepMounted) return null;
89
+ const Element = as || "div";
26
90
  return /* @__PURE__ */ jsx(
27
- TabPanel$1,
91
+ Element,
28
92
  {
93
+ role: "tabpanel",
94
+ id: itemContext?.panelId,
95
+ "aria-labelledby": itemContext?.tabId,
96
+ tabIndex: isSelected ? 0 : -1,
97
+ hidden: isHiddenButMounted || void 0,
29
98
  className: classNames("eds-tab-panel", className),
30
99
  ...rest,
31
- tabIndex: void 0
100
+ children
32
101
  }
33
102
  );
34
103
  };
35
- const TabPanels = ({ className, ...rest }) => {
36
- return /* @__PURE__ */ jsx(
37
- TabPanels$1,
104
+ const TabPanels = ({
105
+ className,
106
+ as,
107
+ keepMounted = false,
108
+ children,
109
+ ...rest
110
+ }) => {
111
+ const { tabsId } = useContext(TabsContext);
112
+ const Element = as || "div";
113
+ return /* @__PURE__ */ jsx(Element, { className: classNames("eds-tab-panels", className), ...rest, children: React.Children.map(children, (child, idx) => /* @__PURE__ */ jsx(
114
+ TabPanelItemContext.Provider,
38
115
  {
39
- className: classNames("eds-tab-panels", className),
40
- ...rest
116
+ value: {
117
+ tabIndex: idx,
118
+ tabId: `${tabsId}-tab-${idx}`,
119
+ panelId: `${tabsId}-panel-${idx}`,
120
+ keepMounted
121
+ },
122
+ children: child
41
123
  }
42
- );
124
+ )) });
43
125
  };
44
126
  const TabList = ({
45
127
  className,
46
128
  width,
129
+ as,
130
+ children,
47
131
  ...rest
48
132
  }) => {
133
+ const { tabsId } = useContext(TabsContext);
134
+ const tabListRef = useRef(null);
135
+ const handleKeyDown = useCallback((e) => {
136
+ const tabs = tabListRef.current?.querySelectorAll(
137
+ '[role="tab"]:not([disabled])'
138
+ );
139
+ if (!tabs || tabs.length === 0) return;
140
+ const currentIndex = Array.from(tabs).findIndex(
141
+ (tab) => tab === document.activeElement
142
+ );
143
+ if (currentIndex === -1) return;
144
+ let nextIndex;
145
+ switch (e.key) {
146
+ case "ArrowRight":
147
+ nextIndex = (currentIndex + 1) % tabs.length;
148
+ break;
149
+ case "ArrowLeft":
150
+ nextIndex = (currentIndex - 1 + tabs.length) % tabs.length;
151
+ break;
152
+ case "Home":
153
+ nextIndex = 0;
154
+ break;
155
+ case "End":
156
+ nextIndex = tabs.length - 1;
157
+ break;
158
+ }
159
+ if (nextIndex !== void 0) {
160
+ e.preventDefault();
161
+ tabs[nextIndex].focus();
162
+ tabs[nextIndex].click();
163
+ }
164
+ }, []);
165
+ const Element = as || "div";
49
166
  return /* @__PURE__ */ jsx(
50
- TabList$1,
167
+ Element,
51
168
  {
169
+ role: "tablist",
170
+ tabIndex: -1,
171
+ ref: tabListRef,
52
172
  className: classNames("eds-tab-list", className, {
53
173
  "eds-tab-list--width-fluid": width === "fluid"
54
174
  }),
55
- ...rest
175
+ onKeyDown: handleKeyDown,
176
+ ...rest,
177
+ children: React.Children.map(children, (child, idx) => /* @__PURE__ */ jsx(
178
+ TabItemContext.Provider,
179
+ {
180
+ value: {
181
+ tabIndex: idx,
182
+ tabId: `${tabsId}-tab-${idx}`,
183
+ panelId: `${tabsId}-panel-${idx}`
184
+ },
185
+ children: child
186
+ }
187
+ ))
56
188
  }
57
189
  );
58
190
  };
@@ -1 +1 @@
1
- {"version":3,"file":"tab.esm.js","sources":["../src/Tab.tsx","../src/Tabs.tsx","../src/TabPanel.tsx","../src/TabPanels.tsx","../src/TabList.tsx","../src/index.tsx"],"sourcesContent":["import React from 'react';\nimport { Tab as ReachTab } from '@reach/tabs';\nimport classNames from 'classnames';\n\nexport type TabProps = {\n /** Overskriften til taben */\n children: React.ReactNode;\n /** Om taben er disabled eller ikke */\n disabled?: boolean;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | any;\n removeActiveLine?: boolean;\n [key: string]: any;\n};\n\nexport const Tab: React.FC<TabProps> = ({\n className,\n removeActiveLine = false,\n ...rest\n}) => {\n return (\n <ReachTab\n className={classNames(\n 'eds-tab',\n { 'eds-tab--remove-active-line': removeActiveLine },\n className,\n )}\n {...rest}\n />\n );\n};\n","import React from 'react';\nimport { Tabs as ReachTabs } from '@reach/tabs';\nimport classNames from 'classnames';\n\nexport type TabsProps = {\n /** Overskriften til taben */\n children: React.ReactNode;\n /** Kalles når taben endres */\n onChange?: (index: number) => void;\n /** Hvilken tab som skal være åpen by default */\n defaultIndex?: number;\n /** Den åpne indexen */\n index?: number;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | any;\n\n [key: string]: any;\n};\n\nexport const Tabs: React.FC<TabsProps> = ({ className, ...rest }) => {\n return <ReachTabs className={classNames('eds-tabs', className)} {...rest} />;\n};\n","import React from 'react';\nimport { TabPanel as ReachTabPanel } from '@reach/tabs';\nimport classNames from 'classnames';\n\nexport type TabPanelProps = {\n /** Overskriften til taben */\n children: React.ReactNode;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | any;\n [key: string]: any;\n};\n\nexport const TabPanel: React.FC<TabPanelProps> = ({ className, ...rest }) => {\n return (\n <ReachTabPanel\n className={classNames('eds-tab-panel', className)}\n {...rest}\n tabIndex={undefined}\n />\n );\n};\n","import React from 'react';\nimport { TabPanels as ReachTabPanels } from '@reach/tabs';\nimport classNames from 'classnames';\n\nexport type TabPanelsProps = {\n /** Tab-panelene */\n children: React.ReactNode;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | any;\n [key: string]: any;\n};\n\nexport const TabPanels: React.FC<TabPanelsProps> = ({ className, ...rest }) => {\n return (\n <ReachTabPanels\n className={classNames('eds-tab-panels', className)}\n {...rest}\n />\n );\n};\n","import React from 'react';\nimport { TabList as ReachTabList } from '@reach/tabs';\nimport classNames from 'classnames';\n\nexport type TabListProps = {\n /** Tab-komponenter */\n children: React.ReactNode;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | any;\n width?: 'fluid';\n [key: string]: any;\n};\n\nexport const TabList: React.FC<TabListProps> = ({\n className,\n width,\n ...rest\n}) => {\n return (\n <ReachTabList\n className={classNames('eds-tab-list', className, {\n 'eds-tab-list--width-fluid': width === 'fluid',\n })}\n {...rest}\n />\n );\n};\n","import { warnAboutMissingStyles } from '@entur/utils';\nimport './index.scss';\n\nwarnAboutMissingStyles('tab');\n\nexport * from './Tab';\nexport * from './Tabs';\nexport * from './TabPanel';\nexport * from './TabPanels';\nexport * from './TabList';\n"],"names":["ReachTab","ReachTabs","ReachTabPanel","ReachTabPanels","ReachTabList"],"mappings":";;;;AAeO,MAAM,MAA0B,CAAC;AAAA,EACtC;AAAA,EACA,mBAAmB;AAAA,EACnB,GAAG;AACL,MAAM;AACJ,SACE;AAAA,IAACA;AAAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,EAAE,+BAA+B,iBAAA;AAAA,QACjC;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;ACXO,MAAM,OAA4B,CAAC,EAAE,WAAW,GAAG,WAAW;AACnE,SAAO,oBAACC,UAAU,WAAW,WAAW,YAAY,SAAS,GAAI,GAAG,MAAM;AAC5E;ACTO,MAAM,WAAoC,CAAC,EAAE,WAAW,GAAG,WAAW;AAC3E,SACE;AAAA,IAACC;AAAAA,IAAA;AAAA,MACC,WAAW,WAAW,iBAAiB,SAAS;AAAA,MAC/C,GAAG;AAAA,MACJ,UAAU;AAAA,IAAA;AAAA,EAAA;AAGhB;ACRO,MAAM,YAAsC,CAAC,EAAE,WAAW,GAAG,WAAW;AAC7E,SACE;AAAA,IAACC;AAAAA,IAAA;AAAA,MACC,WAAW,WAAW,kBAAkB,SAAS;AAAA,MAChD,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;ACNO,MAAM,UAAkC,CAAC;AAAA,EAC9C;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAM;AACJ,SACE;AAAA,IAACC;AAAAA,IAAA;AAAA,MACC,WAAW,WAAW,gBAAgB,WAAW;AAAA,QAC/C,6BAA6B,UAAU;AAAA,MAAA,CACxC;AAAA,MACA,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;ACvBA,uBAAuB,KAAK;"}
1
+ {"version":3,"file":"tab.esm.js","sources":["../src/TabsContext.tsx","../src/Tab.tsx","../src/Tabs.tsx","../src/TabPanel.tsx","../src/TabPanels.tsx","../src/TabList.tsx","../src/index.tsx"],"sourcesContent":["import React from 'react';\n\nexport type TabsContextValue = {\n selectedIndex: number;\n onSelect: (index: number) => void;\n tabsId: string;\n};\n\nexport const TabsContext = React.createContext<TabsContextValue>({\n selectedIndex: 0,\n onSelect: () => undefined,\n tabsId: '',\n});\n\nexport type TabItemContextValue = {\n tabIndex: number;\n tabId: string;\n panelId: string;\n};\n\nexport const TabItemContext = React.createContext<TabItemContextValue | null>(\n null,\n);\n\nexport type TabPanelItemContextValue = {\n tabIndex: number;\n tabId: string;\n panelId: string;\n keepMounted: boolean;\n};\n\nexport const TabPanelItemContext =\n React.createContext<TabPanelItemContextValue | null>(null);\n","import React, { useContext } from 'react';\nimport classNames from 'classnames';\n\nimport { TabItemContext, TabsContext } from './TabsContext';\n\nexport type TabProps = {\n /** Overskriften til taben */\n children: React.ReactNode;\n /** Om taben er disabled eller ikke */\n disabled?: boolean;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | React.ElementType;\n removeActiveLine?: boolean;\n className?: string;\n} & Omit<React.ComponentPropsWithoutRef<'button'>, 'children' | 'disabled'>;\n\nexport const Tab = ({\n className,\n removeActiveLine = false,\n as,\n disabled = false,\n children,\n ...rest\n}: TabProps) => {\n const { selectedIndex, onSelect } = useContext(TabsContext);\n const itemContext = useContext(TabItemContext);\n const tabIndex = itemContext?.tabIndex ?? 0;\n const isSelected = selectedIndex === tabIndex;\n const Element: React.ElementType = as || 'button';\n\n return (\n <Element\n role=\"tab\"\n type={as ? undefined : 'button'}\n id={itemContext?.tabId}\n aria-selected={isSelected}\n aria-controls={itemContext?.panelId}\n tabIndex={isSelected ? 0 : -1}\n disabled={disabled || undefined}\n aria-disabled={disabled || undefined}\n className={classNames(\n 'eds-tab',\n { 'eds-tab--remove-active-line': removeActiveLine },\n className,\n )}\n onClick={() => {\n if (!disabled) onSelect(tabIndex);\n }}\n {...rest}\n >\n {children}\n </Element>\n );\n};\n","import React, { useCallback, useId, useState } from 'react';\nimport classNames from 'classnames';\n\nimport { TabsContext } from './TabsContext';\n\nexport type TabsProps = {\n /** Tab-innholdet */\n children: React.ReactNode;\n /** Kalles når taben endres */\n onChange?: (index: number) => void;\n /** Hvilken tab som skal være åpen by default */\n defaultIndex?: number;\n /** Den åpne indexen (kontrollert) */\n index?: number;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | React.ElementType;\n className?: string;\n} & Omit<React.ComponentPropsWithoutRef<'div'>, 'children' | 'onChange'>;\n\nexport const Tabs = ({\n className,\n index,\n defaultIndex,\n onChange,\n as,\n children,\n ...rest\n}: TabsProps) => {\n const [internalIndex, setInternalIndex] = useState(defaultIndex ?? 0);\n const isControlled = index !== undefined;\n const selectedIndex = isControlled ? index : internalIndex;\n const tabsId = useId();\n\n const onSelect = useCallback(\n (i: number) => {\n if (!isControlled) {\n setInternalIndex(i);\n }\n onChange?.(i);\n },\n [isControlled, onChange],\n );\n\n const Element: React.ElementType = as || 'div';\n\n return (\n <TabsContext.Provider value={{ selectedIndex, onSelect, tabsId }}>\n <Element className={classNames('eds-tabs', className)} {...rest}>\n {children}\n </Element>\n </TabsContext.Provider>\n );\n};\n","import React, { useContext } from 'react';\nimport classNames from 'classnames';\n\nimport { TabPanelItemContext, TabsContext } from './TabsContext';\n\nexport type TabPanelProps = {\n /** Innholdet i tab-panelet */\n children?: React.ReactNode;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | React.ElementType;\n className?: string;\n} & Omit<React.ComponentPropsWithoutRef<'div'>, 'children'>;\n\nexport const TabPanel = ({\n className,\n as,\n children,\n ...rest\n}: TabPanelProps) => {\n const { selectedIndex } = useContext(TabsContext);\n const itemContext = useContext(TabPanelItemContext);\n const tabIndex = itemContext?.tabIndex ?? 0;\n const keepMounted = itemContext?.keepMounted ?? false;\n\n const isSelected = selectedIndex === tabIndex;\n const isHiddenButMounted = keepMounted && !isSelected;\n\n if (!isSelected && !keepMounted) return null;\n\n const Element: React.ElementType = as || 'div';\n\n return (\n <Element\n role=\"tabpanel\"\n id={itemContext?.panelId}\n aria-labelledby={itemContext?.tabId}\n tabIndex={isSelected ? 0 : -1}\n hidden={isHiddenButMounted || undefined}\n className={classNames('eds-tab-panel', className)}\n {...rest}\n >\n {children}\n </Element>\n );\n};\n","import React, { useContext } from 'react';\nimport classNames from 'classnames';\n\nimport { TabPanelItemContext, TabsContext } from './TabsContext';\n\nexport type TabPanelsProps = {\n /** Tab-panelene */\n children: React.ReactNode;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | React.ElementType;\n /** Behold alle panel-noder i DOM (skjult med hidden-attributt) i stedet for å avmontere */\n keepMounted?: boolean;\n className?: string;\n} & Omit<React.ComponentPropsWithoutRef<'div'>, 'children'>;\n\nexport const TabPanels = ({\n className,\n as,\n keepMounted = false,\n children,\n ...rest\n}: TabPanelsProps) => {\n const { tabsId } = useContext(TabsContext);\n\n const Element: React.ElementType = as || 'div';\n\n return (\n <Element className={classNames('eds-tab-panels', className)} {...rest}>\n {React.Children.map(children, (child, idx) => (\n <TabPanelItemContext.Provider\n value={{\n tabIndex: idx,\n tabId: `${tabsId}-tab-${idx}`,\n panelId: `${tabsId}-panel-${idx}`,\n keepMounted,\n }}\n >\n {child}\n </TabPanelItemContext.Provider>\n ))}\n </Element>\n );\n};\n","import React, { useCallback, useContext, useRef } from 'react';\nimport classNames from 'classnames';\n\nimport { TabItemContext, TabsContext } from './TabsContext';\n\nexport type TabListProps = {\n /** Tab-komponenter */\n children: React.ReactNode;\n /** HTML-elementet eller React-komponenten som lager komponenten */\n as?: keyof JSX.IntrinsicElements | React.ElementType;\n width?: 'fluid';\n className?: string;\n /** Tilgjengelig navn på tab-listen (dersom det ikke finnes en synlig overskrift) */\n 'aria-label'?: string;\n /** ID til elementet som navngir tab-listen */\n 'aria-labelledby'?: string;\n} & Omit<React.ComponentPropsWithoutRef<'div'>, 'children'>;\n\nexport const TabList = ({\n className,\n width,\n as,\n children,\n ...rest\n}: TabListProps) => {\n const { tabsId } = useContext(TabsContext);\n const tabListRef = useRef<HTMLElement>(null);\n\n const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\n const tabs = tabListRef.current?.querySelectorAll<HTMLElement>(\n '[role=\"tab\"]:not([disabled])',\n );\n if (!tabs || tabs.length === 0) return;\n\n const currentIndex = Array.from(tabs).findIndex(\n tab => tab === document.activeElement,\n );\n if (currentIndex === -1) return;\n\n let nextIndex: number | undefined;\n switch (e.key) {\n case 'ArrowRight':\n nextIndex = (currentIndex + 1) % tabs.length;\n break;\n case 'ArrowLeft':\n nextIndex = (currentIndex - 1 + tabs.length) % tabs.length;\n break;\n case 'Home':\n nextIndex = 0;\n break;\n case 'End':\n nextIndex = tabs.length - 1;\n break;\n }\n\n if (nextIndex !== undefined) {\n e.preventDefault();\n tabs[nextIndex].focus();\n tabs[nextIndex].click();\n }\n }, []);\n\n const Element: React.ElementType = as || 'div';\n\n return (\n <Element\n role=\"tablist\"\n tabIndex={-1}\n ref={tabListRef}\n className={classNames('eds-tab-list', className, {\n 'eds-tab-list--width-fluid': width === 'fluid',\n })}\n onKeyDown={handleKeyDown}\n {...rest}\n >\n {React.Children.map(children, (child, idx) => (\n <TabItemContext.Provider\n value={{\n tabIndex: idx,\n tabId: `${tabsId}-tab-${idx}`,\n panelId: `${tabsId}-panel-${idx}`,\n }}\n >\n {child}\n </TabItemContext.Provider>\n ))}\n </Element>\n );\n};\n","import { warnAboutMissingStyles } from '@entur/utils';\nimport './index.scss';\n\nwarnAboutMissingStyles('tab');\n\nexport * from './Tab';\nexport * from './Tabs';\nexport * from './TabPanel';\nexport * from './TabPanels';\nexport * from './TabList';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@entur/tab",
3
- "version": "0.7.1",
3
+ "version": "1.0.0-next.0",
4
4
  "license": "EUPL-1.2",
5
5
  "main": "dist/tab.cjs.js",
6
6
  "module": "dist/tab.esm.js",
@@ -22,18 +22,17 @@
22
22
  "test": "jest"
23
23
  },
24
24
  "peerDependencies": {
25
- "react": ">=16.8.0",
26
- "react-dom": ">=16.8.0"
25
+ "react": ">=18.0.0",
26
+ "react-dom": ">=18.0.0"
27
27
  },
28
28
  "dependencies": {
29
- "@entur/tokens": "^3.24.0",
30
- "@entur/utils": "^0.13.5",
31
- "@reach/tabs": "^0.15.3",
29
+ "@entur/tokens": "^3.24.1-next.0",
30
+ "@entur/utils": "^1.0.0-next.0",
32
31
  "classnames": "^2.5.1"
33
32
  },
34
33
  "devDependencies": {
35
34
  "@testing-library/jest-dom": "^5.17.0",
36
- "@testing-library/react": "^10.4.9",
35
+ "@testing-library/react": "^16.3.0",
37
36
  "@testing-library/user-event": "14.6.1",
38
37
  "@vitejs/plugin-react": "^5.0.1",
39
38
  "jest": "^29.0.0",
@@ -43,5 +42,5 @@
43
42
  "vite": "^7.3.2",
44
43
  "vite-plugin-dts": "^4.5.4"
45
44
  },
46
- "gitHead": "ac37425c6b442481549814941b317886e3a7defb"
45
+ "gitHead": "0f435bdeec98cc3cea1db7434b13b1f771a39a18"
47
46
  }