@rescui/tab-list 0.16.6 → 0.17.1-RUI-293-Update-menu-component-7a032357e.20

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.
@@ -1,6 +1,6 @@
1
1
  var styles = {
2
- "light": "_light_1s9ao7_4",
3
- "dark": "_dark_1s9ao7_7",
4
- "separator": "_separator_1s9ao7_11"
2
+ "light": "_light_18ir3ig_4",
3
+ "dark": "_dark_18ir3ig_7",
4
+ "separator": "_separator_18ir3ig_11"
5
5
  };
6
6
  export { styles as default };
@@ -1,8 +1,13 @@
1
- /// <reference types="react" />
2
- export declare type TabListValueType = string | number | symbol | {};
3
- export declare type TabListContextType = {
4
- onChange: (value: TabListValueType) => void;
5
- selectedId?: number;
6
- };
7
- export declare const TabListContext: import("react").Context<TabListContextType>;
8
- export declare const useTabListContext: () => TabListContextType;
1
+ import React from 'react';
2
+ export type TabListValueType = string | number | symbol | object;
3
+ export type TabListRovingTabIndexToolkit = {
4
+ currentTabStopId: number;
5
+ onTabKeyDown: (e: React.KeyboardEvent<HTMLButtonElement | HTMLAnchorElement>, itemId: number) => void;
6
+ };
7
+ export type TabListContextType = {
8
+ onChange: (value: TabListValueType) => void;
9
+ selectedId?: number;
10
+ rovingTabIndex?: TabListRovingTabIndexToolkit;
11
+ };
12
+ export declare const TabListContext: React.Context<TabListContextType>;
13
+ export declare const useTabListContext: () => TabListContextType;
@@ -1,19 +1,28 @@
1
1
  var styles = {
2
- "light": "_light_rahv02_7",
3
- "dark": "_dark_rahv02_10",
4
- "sizeM": "_sizeM_rahv02_14",
5
- "sizeL": "_sizeL_rahv02_17",
6
- "classic": "_classic_rahv02_21",
7
- "rock": "_rock_rahv02_24",
8
- "sparse": "_sparse_rahv02_28",
9
- "short": "_short_rahv02_32",
10
- "tabsContainer": "_tabsContainer_rahv02_36",
11
- "indicator": "_indicator_rahv02_46",
12
- "isIndicatorHidden": "_isIndicatorHidden_rahv02_60",
13
- "iconLeft": "_iconLeft_rahv02_66",
14
- "iconRight": "_iconRight_rahv02_69",
15
- "tab": "_tab_rahv02_36",
16
- "selected": "_selected_rahv02_160",
17
- "icon": "_icon_rahv02_66"
2
+ "light": "_light_4vcbrf_10",
3
+ "dark": "_dark_4vcbrf_13",
4
+ "sizeM": "_sizeM_4vcbrf_17",
5
+ "sizeL": "_sizeL_4vcbrf_20",
6
+ "classic": "_classic_4vcbrf_24",
7
+ "rock": "_rock_4vcbrf_27",
8
+ "sparse": "_sparse_4vcbrf_31",
9
+ "short": "_short_4vcbrf_35",
10
+ "wrapper": "_wrapper_4vcbrf_39",
11
+ "scrollable": "_scrollable_4vcbrf_49",
12
+ "arrow": "_arrow_4vcbrf_78",
13
+ "shown": "_shown_4vcbrf_98",
14
+ "arrowLeft": "_arrowLeft_4vcbrf_106",
15
+ "arrowRight": "_arrowRight_4vcbrf_111",
16
+ "withLeftArrow": "_withLeftArrow_4vcbrf_117",
17
+ "withRightArrow": "_withRightArrow_4vcbrf_126",
18
+ "arrowButton": "_arrowButton_4vcbrf_147",
19
+ "tabsContainer": "_tabsContainer_4vcbrf_151",
20
+ "indicator": "_indicator_4vcbrf_157",
21
+ "isIndicatorHidden": "_isIndicatorHidden_4vcbrf_172",
22
+ "iconLeft": "_iconLeft_4vcbrf_178",
23
+ "iconRight": "_iconRight_4vcbrf_181",
24
+ "tab": "_tab_4vcbrf_151",
25
+ "selected": "_selected_4vcbrf_272",
26
+ "icon": "_icon_4vcbrf_178"
18
27
  };
19
28
  export { styles as default };
@@ -1,8 +1,8 @@
1
- import React from 'react';
2
- import { Theme } from '@rescui/ui-contexts';
3
- export declare type TabSeparatorProps = {
4
- className?: string;
5
- theme?: Theme;
6
- };
7
- declare const TabSeparator: React.FC<TabSeparatorProps>;
8
- export default TabSeparator;
1
+ import React from 'react';
2
+ import { Theme } from '@rescui/ui-contexts';
3
+ export type TabSeparatorProps = {
4
+ className?: string;
5
+ theme?: Theme;
6
+ };
7
+ declare const TabSeparator: React.FC<TabSeparatorProps>;
8
+ export default TabSeparator;
@@ -1,35 +1,35 @@
1
- import React from 'react';
2
- import { TabListValueType } from './tab-list-context';
3
- export declare type TabIconPosition = 'left' | 'right';
4
- export declare type TabExplicitProps = {
5
- className?: string;
6
- value?: TabListValueType;
7
- /** @ignore */
8
- itemId?: number;
9
- /** @ignore */
10
- onClick?: React.MouseEventHandler<HTMLElement>;
11
- /** @ignore */
12
- onFocus?: React.FocusEventHandler<HTMLElement>;
13
- /** @ignore */
14
- onMouseDown?: React.MouseEventHandler<HTMLElement>;
15
- /** @ignore */
16
- onKeyDown?: React.KeyboardEventHandler<HTMLElement>;
17
- /** Identifier for e2e tests */
18
- 'data-e2e'?: string;
19
- /** Href for link-type Tab */
20
- href?: string;
21
- children?: React.ReactNode;
22
- } & ({
23
- /** Additional icon */
24
- icon: React.ReactNode;
25
- /** Additional icon position */
26
- iconPosition?: TabIconPosition;
27
- } | {
28
- icon?: never;
29
- iconPosition?: never;
30
- });
31
- declare type TabButtonProps = TabExplicitProps & React.ButtonHTMLAttributes<HTMLButtonElement>;
32
- declare type TabAnchorProps = TabExplicitProps & React.AnchorHTMLAttributes<HTMLAnchorElement>;
33
- export declare type TabProps = TabButtonProps | TabAnchorProps;
34
- declare const Tab: React.ForwardRefExoticComponent<TabProps & React.RefAttributes<HTMLButtonElement | HTMLAnchorElement>>;
35
- export default Tab;
1
+ import React from 'react';
2
+ import { TabListValueType } from './tab-list-context';
3
+ export type TabIconPosition = 'left' | 'right';
4
+ export type TabExplicitProps = {
5
+ className?: string;
6
+ value?: TabListValueType;
7
+ /** @ignore */
8
+ itemId?: number;
9
+ /** @ignore */
10
+ onClick?: React.MouseEventHandler<HTMLElement>;
11
+ /** @ignore */
12
+ onFocus?: React.FocusEventHandler<HTMLElement>;
13
+ /** @ignore */
14
+ onMouseDown?: React.MouseEventHandler<HTMLElement>;
15
+ /** @ignore */
16
+ onKeyDown?: React.KeyboardEventHandler<HTMLElement>;
17
+ /** Identifier for e2e tests */
18
+ 'data-e2e'?: string;
19
+ /** Href for link-type Tab */
20
+ href?: string;
21
+ children?: React.ReactNode;
22
+ } & ({
23
+ /** Additional icon */
24
+ icon: React.ReactNode;
25
+ /** Additional icon position */
26
+ iconPosition?: TabIconPosition;
27
+ } | {
28
+ icon?: never;
29
+ iconPosition?: never;
30
+ });
31
+ type TabButtonProps = TabExplicitProps & React.ButtonHTMLAttributes<HTMLButtonElement>;
32
+ type TabAnchorProps = TabExplicitProps & React.AnchorHTMLAttributes<HTMLAnchorElement>;
33
+ export type TabProps = TabButtonProps | TabAnchorProps;
34
+ declare const Tab: React.ForwardRefExoticComponent<TabProps & React.RefAttributes<HTMLButtonElement | HTMLAnchorElement>>;
35
+ export default Tab;
package/lib/parts/tab.js CHANGED
@@ -34,9 +34,11 @@ const Tab = /*#__PURE__*/forwardRef((_ref, ref) => {
34
34
  } = _ref;
35
35
  const {
36
36
  onChange,
37
- selectedId
37
+ selectedId,
38
+ rovingTabIndex
38
39
  } = useTabListContext();
39
40
  const selected = itemId === selectedId;
41
+ const resolvedTabIndex = typeof itemId === 'undefined' || itemId === rovingTabIndex?.currentTabStopId ? 0 : -1;
40
42
  return /*#__PURE__*/React.createElement(TabTag, { ...restProps,
41
43
  className: cn(styles.tab, selected && styles.selected, iconPosition === 'right' ? styles.iconRight : styles.iconLeft, className),
42
44
  onClick: e => {
@@ -47,17 +49,20 @@ const Tab = /*#__PURE__*/forwardRef((_ref, ref) => {
47
49
  onChange(value);
48
50
  },
49
51
  onKeyDown: e => {
50
- if (e.key === ' ') {
51
- e.target.click();
52
- e.preventDefault();
52
+ if (typeof itemId !== 'undefined') {
53
+ rovingTabIndex?.onTabKeyDown(e, itemId);
53
54
  }
54
55
 
55
- if (onKeyDown) {
56
- onKeyDown(e);
56
+ if (e.key === ' ' || e.key === 'Enter') {
57
+ e.currentTarget.click();
58
+ e.preventDefault();
57
59
  }
60
+
61
+ onKeyDown?.(e);
58
62
  },
59
63
  role: "tab",
60
- tabIndex: 0,
64
+ "aria-selected": selected,
65
+ tabIndex: resolvedTabIndex,
61
66
  ref: ref,
62
67
  "data-e2e": e2eId,
63
68
  "data-test": `tab${selected ? ' tab-selected' : ''}`,
@@ -1,13 +1,13 @@
1
- import { MutableRefObject } from 'react';
2
- export declare const useIndicator: ({ activeNodeRef, containerRef, triggers }: {
3
- activeNodeRef: MutableRefObject<HTMLElement>;
4
- containerRef: MutableRefObject<HTMLDivElement>;
5
- triggers: unknown[];
6
- }) => {
7
- indicator: {
8
- left: number | string;
9
- width: number | string;
10
- transitionDuration?: string;
11
- };
12
- isIndicatorHidden: boolean;
13
- };
1
+ import { MutableRefObject } from 'react';
2
+ export declare const useIndicator: ({ activeNodeRef, containerRef, triggers }: {
3
+ activeNodeRef: MutableRefObject<HTMLElement>;
4
+ containerRef: MutableRefObject<HTMLDivElement>;
5
+ triggers: unknown[];
6
+ }) => {
7
+ indicator: {
8
+ left: number | string;
9
+ width: number | string;
10
+ transitionDuration?: string;
11
+ };
12
+ isIndicatorHidden: boolean;
13
+ };
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ export declare const useRovingTabIndex: ({ selectedId, tabRefs }: {
3
+ selectedId?: number;
4
+ tabRefs?: React.MutableRefObject<Map<number, HTMLElement>>;
5
+ }) => {
6
+ currentTabStopId: number;
7
+ onTabKeyDown: (e: React.KeyboardEvent<HTMLButtonElement | HTMLAnchorElement>, itemId: number) => void;
8
+ };
@@ -0,0 +1,68 @@
1
+ import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
2
+ import React from 'react'; // eslint-disable-next-line complexity
3
+
4
+ const getNextItemId = _ref => {
5
+ let {
6
+ currentItemId,
7
+ itemsCount,
8
+ key
9
+ } = _ref;
10
+
11
+ if (itemsCount <= 0) {
12
+ return currentItemId;
13
+ }
14
+
15
+ if (key === 'Home') {
16
+ return 0;
17
+ }
18
+
19
+ if (key === 'End') {
20
+ return itemsCount - 1;
21
+ }
22
+
23
+ if (key === 'ArrowLeft') {
24
+ return currentItemId <= 0 ? itemsCount - 1 : currentItemId - 1;
25
+ }
26
+
27
+ if (key === 'ArrowRight') {
28
+ return currentItemId >= itemsCount - 1 ? 0 : currentItemId + 1;
29
+ }
30
+
31
+ return currentItemId;
32
+ };
33
+
34
+ const useRovingTabIndex = _ref2 => {
35
+ let {
36
+ selectedId,
37
+ tabRefs
38
+ } = _ref2;
39
+ const [currentTabStopId, setCurrentTabStopId] = React.useState(selectedId ?? 0);
40
+ React.useLayoutEffect(() => {
41
+ if (typeof selectedId === 'number') {
42
+ setCurrentTabStopId(selectedId);
43
+ }
44
+ }, [selectedId]);
45
+ const onTabKeyDown = React.useCallback((e, itemId) => {
46
+ var _context;
47
+
48
+ if (!_includesInstanceProperty(_context = ['ArrowLeft', 'ArrowRight', 'Home', 'End']).call(_context, e.key)) {
49
+ return;
50
+ }
51
+
52
+ const itemsCount = tabRefs?.current.size ?? 0;
53
+ const nextItemId = getNextItemId({
54
+ currentItemId: itemId,
55
+ itemsCount,
56
+ key: e.key
57
+ });
58
+ e.preventDefault();
59
+ setCurrentTabStopId(nextItemId);
60
+ tabRefs?.current.get(nextItemId)?.focus();
61
+ }, [tabRefs]);
62
+ return {
63
+ currentTabStopId,
64
+ onTabKeyDown
65
+ };
66
+ };
67
+
68
+ export { useRovingTabIndex };
@@ -1,17 +1,18 @@
1
- import React from 'react';
2
- export declare type ScrollableListCompareValueType<T> = (activeValue: T, itemValue: T) => boolean;
3
- export declare const useScrollableList: <T>({ children, compareValues, value, CompareItem }: {
4
- children: React.ReactNode;
5
- compareValues: ScrollableListCompareValueType<T>;
6
- value: T;
7
- CompareItem: React.ElementType;
8
- }) => {
9
- selectedId: number;
10
- prepareDirectionScroller: (direction: 'left' | 'right') => () => void;
11
- activeNodeRef: React.MutableRefObject<HTMLElement>;
12
- scrollableRef: React.MutableRefObject<HTMLDivElement>;
13
- containerRef: React.MutableRefObject<HTMLElement>;
14
- childrenWithValues: (string | number | React.ReactElement<any, string | React.JSXElementConstructor<any>> | React.ReactFragment | React.ReactPortal)[];
15
- showLeftArrow: boolean;
16
- showRightArrow: boolean;
17
- };
1
+ import React, { MutableRefObject } from 'react';
2
+ export type ScrollableListCompareValueType<T> = (activeValue: T, itemValue: T) => boolean;
3
+ export declare const useScrollableList: <T>({ children, compareValues, value, CompareItem, activeNodeRef, scrollableRef, containerRef }: {
4
+ children: React.ReactNode;
5
+ compareValues: ScrollableListCompareValueType<T>;
6
+ value: T;
7
+ CompareItem: React.ElementType;
8
+ activeNodeRef: MutableRefObject<HTMLElement>;
9
+ scrollableRef: MutableRefObject<HTMLDivElement>;
10
+ containerRef: MutableRefObject<HTMLDivElement>;
11
+ }) => {
12
+ selectedId: number;
13
+ prepareDirectionScroller: (direction: "left" | "right") => () => void;
14
+ tabRefs: React.RefObject<Map<number, HTMLElement>>;
15
+ childrenWithValues: (string | number | bigint | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode>>)[];
16
+ showLeftArrow: boolean;
17
+ showRightArrow: boolean;
18
+ };
@@ -114,11 +114,12 @@ const useScrollableList = _ref2 => {
114
114
  children,
115
115
  compareValues,
116
116
  value,
117
- CompareItem
117
+ CompareItem,
118
+ activeNodeRef,
119
+ scrollableRef,
120
+ containerRef
118
121
  } = _ref2;
119
- const activeNodeRef = useRef(null);
120
- const scrollableRef = useRef(null);
121
- const containerRef = useRef(null); // reset targeted element on scrolling by arrows
122
+ const tabRefs = useRef(new Map()); // reset targeted element on scrolling by arrows
122
123
  // so on window resize there wouldn't scroll to it
123
124
 
124
125
  const [targetedEl, setTargetedEl] = useState(null);
@@ -132,6 +133,17 @@ const useScrollableList = _ref2 => {
132
133
  const onFocus = useCallback(e => {
133
134
  setTargetedEl(e.target);
134
135
  }, []);
136
+ const createTabRef = useCallback((itemId, isSelectedItem) => node => {
137
+ if (node) {
138
+ tabRefs.current.set(itemId, node);
139
+ } else {
140
+ tabRefs.current.delete(itemId);
141
+ }
142
+
143
+ if (isSelectedItem) {
144
+ activeNodeRef.current = node;
145
+ }
146
+ }, []);
135
147
  const [childrenWithValues, selectedId] = useMemo(() => {
136
148
  let counter = 0;
137
149
  let currentSelectedItemId = null;
@@ -149,6 +161,7 @@ const useScrollableList = _ref2 => {
149
161
  currentSelectedItemId = counter;
150
162
  }
151
163
 
164
+ const setTabRef = createTabRef(counter, isSelectedItem);
152
165
  const patchedItem = patchItemIfNeeded({
153
166
  child,
154
167
  itemId: counter,
@@ -161,7 +174,16 @@ const useScrollableList = _ref2 => {
161
174
 
162
175
  onFocus(e);
163
176
  },
164
- ref: isSelectedItem ? activeNodeRef : null
177
+ ref: node => {
178
+ setTabRef(node);
179
+ const childRef = child.ref;
180
+
181
+ if (typeof childRef === 'function') {
182
+ childRef(node);
183
+ } else if (childRef) {
184
+ childRef.current = node;
185
+ }
186
+ }
165
187
  });
166
188
  counter += 1;
167
189
  return patchedItem;
@@ -170,7 +192,7 @@ const useScrollableList = _ref2 => {
170
192
  }
171
193
  });
172
194
  return [React.Children.toArray(items), currentSelectedItemId];
173
- }, [children, value, compareValues, onFocus, CompareItem]);
195
+ }, [children, value, compareValues, onFocus, CompareItem, createTabRef]);
174
196
 
175
197
  const prepareDirectionScroller = direction => () => {
176
198
  const {
@@ -234,9 +256,7 @@ const useScrollableList = _ref2 => {
234
256
  return {
235
257
  selectedId,
236
258
  prepareDirectionScroller,
237
- activeNodeRef,
238
- scrollableRef,
239
- containerRef,
259
+ tabRefs,
240
260
  childrenWithValues,
241
261
  showLeftArrow,
242
262
  showRightArrow
package/lib/tab-list.d.ts CHANGED
@@ -1,35 +1,43 @@
1
- import React from 'react';
2
- import { Theme } from '@rescui/ui-contexts';
3
- import { TabListValueType } from './parts/tab-list-context';
4
- export declare type TabListSizeType = 'l' | 'm';
5
- export declare type TabListModeType = 'classic' | 'rock';
6
- export declare type InnerTabListProps = {
7
- className?: string;
8
- size?: TabListSizeType;
9
- /** Increase inner horizontal offset between the tabs. */
10
- sparse?: boolean;
11
- theme?: Theme;
12
- mode?: TabListModeType;
13
- short?: boolean;
14
- value: TabListValueType;
15
- onChange: (value: TabListValueType) => void;
16
- children: React.ReactNode;
17
- /** Identifier for e2e tests */
18
- 'data-e2e'?: string;
19
- selectedId?: number;
20
- activeNodeRef?: React.MutableRefObject<HTMLElement>;
21
- containerRef?: React.MutableRefObject<HTMLDivElement>;
22
- };
23
- export declare const TabList: {
24
- <OT extends TabListValueType>({ compareValues, value, onChange, children, theme: themeFromProps, ["data-e2e"]: e2eId, ...restProps }: React.PropsWithChildren<import("./parts/with-scroll-arrows").WithScrollArrowsProps<OT> & {
25
- size?: TabListSizeType;
26
- sparse?: boolean;
27
- className?: string;
28
- mode?: TabListModeType;
29
- short?: boolean;
30
- 'data-e2e'?: string;
31
- }>): React.ReactElement<any, string | React.JSXElementConstructor<any>>;
32
- displayName: string;
33
- };
34
- export declare type TabListProps = React.ComponentProps<typeof TabList>;
35
- export default TabList;
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Theme } from '@rescui/ui-contexts';
4
+ import { TabListValueType } from './parts/tab-list-context';
5
+ import { ScrollableListCompareValueType } from './parts/use-scrollable-list';
6
+ export type TabListSizeType = 'l' | 'm';
7
+ export type TabListModeType = 'classic' | 'rock';
8
+ export type TabListProps<T extends TabListValueType> = {
9
+ className?: string;
10
+ size?: TabListSizeType;
11
+ /** Increase inner horizontal offset between the tabs. */
12
+ sparse?: boolean;
13
+ theme?: Theme;
14
+ mode?: TabListModeType;
15
+ short?: boolean;
16
+ value: T;
17
+ onChange: (value: T) => void;
18
+ children: React.ReactNode;
19
+ /** Identifier for e2e tests */
20
+ 'data-e2e'?: string;
21
+ /** Optional a11y label for the tab list. Recommended to use either that or `aria-labelledby`. */
22
+ 'aria-label'?: string;
23
+ /** Optional a11y label reference for the tab list. Recommended to use either that or `aria-label`. */
24
+ 'aria-labelledby'?: string;
25
+ compareValues?: ScrollableListCompareValueType<T>;
26
+ };
27
+ declare const TabList: {
28
+ <T extends TabListValueType>({ size, sparse, className, mode, short, ["data-e2e"]: e2eId, compareValues, value, onChange, children, theme: themeFromProps, ...restProps }: TabListProps<T>): React.JSX.Element;
29
+ displayName: string;
30
+ propTypes: {
31
+ size: PropTypes.Requireable<string>;
32
+ sparse: PropTypes.Requireable<boolean>;
33
+ theme: PropTypes.Requireable<string>;
34
+ className: PropTypes.Requireable<string>;
35
+ mode: PropTypes.Requireable<string>;
36
+ short: PropTypes.Requireable<boolean>;
37
+ value: PropTypes.Requireable<NonNullable<string | number | symbol | object>>;
38
+ onChange: PropTypes.Requireable<(...args: any[]) => any>;
39
+ compareValues: PropTypes.Requireable<(...args: any[]) => any>;
40
+ 'data-e2e': PropTypes.Requireable<string>;
41
+ };
42
+ };
43
+ export default TabList;