@primer/react 38.34.0-rc.d17f87af7 → 38.34.0-rc.dad320815

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/CHANGELOG.md CHANGED
@@ -12,6 +12,8 @@
12
12
 
13
13
  - [#8169](https://github.com/primer/react/pull/8169) [`1d6f559`](https://github.com/primer/react/commit/1d6f5593f5e482d1d03027522bc882560c7b1f06) Thanks [@liuliu-dev](https://github.com/liuliu-dev)! - Timeline: `Timeline.Actions` now wraps onto a new row below `Timeline.Body`, left-aligned with the body content, when `Timeline.Item` is narrower than 480px.
14
14
 
15
+ - [#8214](https://github.com/primer/react/pull/8214) [`41705f4`](https://github.com/primer/react/commit/41705f430ce0f64eb61c2665313f36a88cf6f16c) Thanks [@rickyzhangca](https://github.com/rickyzhangca)! - UnderlinePanels: The experimental `UnderlinePanels` component is now built on the experimental `Tabs` component instead of `@github/tab-container-element`. Its public API and behavior are unchanged.
16
+
15
17
  ## 38.33.0
16
18
 
17
19
  ### Minor Changes
@@ -13,10 +13,11 @@ import React, { useId } from "react";
13
13
  * The `Tab`, `TabList`, and `TabPanel` components are provided for convenience to showcase the API & implementation.
14
14
  */
15
15
  function Tabs(props) {
16
- var _props$defaultValue;
16
+ var _props$id, _props$defaultValue;
17
17
  const $ = c(13);
18
18
  const { children, onValueChange } = props;
19
- const groupId = useId();
19
+ const generatedId = useId();
20
+ const groupId = (_props$id = props.id) !== null && _props$id !== void 0 ? _props$id : generatedId;
20
21
  const t0 = (_props$defaultValue = props.defaultValue) !== null && _props$defaultValue !== void 0 ? _props$defaultValue : props.value;
21
22
  let t1;
22
23
  if ($[0] !== props.value || $[1] !== t0) {
@@ -45,7 +45,14 @@ type UncontrolledTabsProps = {
45
45
  value: string;
46
46
  }) => void;
47
47
  };
48
- type TabsProps = PropsWithChildren<ControlledTabsProps | UncontrolledTabsProps>;
48
+ type CommonTabsProps = {
49
+ /**
50
+ * Optional id used as the base for generated tab and panel ids. If omitted, a
51
+ * unique id is generated automatically.
52
+ */
53
+ id?: string;
54
+ };
55
+ type TabsProps = PropsWithChildren<(ControlledTabsProps | UncontrolledTabsProps) & CommonTabsProps>;
49
56
  type Label = {
50
57
  'aria-label': string;
51
58
  };
@@ -3,15 +3,16 @@ import { useResizeObserver } from "../../hooks/useResizeObserver.js";
3
3
  import { useId as useId$1 } from "../../hooks/useId.js";
4
4
  import { isSlot } from "../../utils/is-slot.js";
5
5
  import { invariant } from "../../utils/invariant.js";
6
- import { createComponent } from "../../utils/create-component.js";
7
6
  import { UnderlineItem, UnderlineItemList, UnderlineWrapper } from "../../internal/components/UnderlineTabbedInterface.js";
8
7
  import UnderlinePanels_module_css_default from "./UnderlinePanels.module.css.js";
8
+ import { useTab } from "../Tabs/useTab.js";
9
+ import { useTabList } from "../Tabs/useTabList.js";
10
+ import { useTabPanel } from "../Tabs/useTabPanel.js";
11
+ import { Tabs } from "../Tabs/Tabs.js";
9
12
  import { clsx } from "clsx";
10
13
  import { jsx, jsxs } from "react/jsx-runtime";
11
14
  import React, { Children, cloneElement, createContext, isValidElement, useContext, useMemo, useRef, useState } from "react";
12
- import { TabContainerElement } from "@github/tab-container-element";
13
15
  //#region src/experimental/UnderlinePanels/UnderlinePanels.tsx
14
- const TabContainerComponent = createComponent(TabContainerElement, "tab-container");
15
16
  const UnderlinePanelsContext = /*#__PURE__*/ createContext({
16
17
  iconsVisible: true,
17
18
  loadingCounters: void 0
@@ -21,27 +22,43 @@ const UnderlinePanels = ({ "aria-label": ariaLabel, "aria-labelledby": ariaLabel
21
22
  const wrapperRef = useRef(null);
22
23
  const listRef = useRef(null);
23
24
  const parentId = useId$1(props.id);
24
- const [tabs, tabPanels, tabsHaveIcons] = useMemo(() => {
25
+ const [tabs, tabPanels, tabsHaveIcons, selectedFromProps] = useMemo(() => {
25
26
  let tabIndex = 0;
26
27
  let panelIndex = 0;
27
28
  const childrenWithProps = Children.map(children, (child) => {
28
- if (/*#__PURE__*/ isValidElement(child) && (child.type === Tab || isSlot(child, Tab))) return /*#__PURE__*/ cloneElement(child, { id: `${parentId}-tab-${tabIndex++}` });
29
- if (/*#__PURE__*/ isValidElement(child) && (child.type === Panel || isSlot(child, Panel))) return /*#__PURE__*/ cloneElement(child, { "aria-labelledby": `${parentId}-tab-${panelIndex++}` });
29
+ if (/*#__PURE__*/ isValidElement(child) && (child.type === Tab || isSlot(child, Tab))) return /*#__PURE__*/ cloneElement(child, { value: `${tabIndex++}` });
30
+ if (/*#__PURE__*/ isValidElement(child) && (child.type === Panel || isSlot(child, Panel))) return /*#__PURE__*/ cloneElement(child, { value: `${panelIndex++}` });
30
31
  return child;
31
32
  });
32
33
  const tabs = [];
33
34
  const tabPanels = [];
35
+ let selectedFromProps;
34
36
  for (const child of Children.toArray(childrenWithProps)) {
35
37
  if (!/*#__PURE__*/ isValidElement(child)) continue;
36
- if (child.type === Tab || isSlot(child, Tab)) tabs.push(child);
37
- else if (child.type === Panel || isSlot(child, Panel)) tabPanels.push(child);
38
+ if (child.type === Tab || isSlot(child, Tab)) {
39
+ const ariaSelected = child.props["aria-selected"];
40
+ if (ariaSelected === true || ariaSelected === "true") selectedFromProps = `${tabs.length}`;
41
+ tabs.push(child);
42
+ } else if (child.type === Panel || isSlot(child, Panel)) tabPanels.push(child);
38
43
  }
39
44
  return [
40
45
  tabs,
41
46
  tabPanels,
42
- tabs.some((tab) => /*#__PURE__*/ React.isValidElement(tab) && tab.props.icon)
47
+ tabs.some((tab) => /*#__PURE__*/ React.isValidElement(tab) && tab.props.icon),
48
+ selectedFromProps
43
49
  ];
44
- }, [children, parentId]);
50
+ }, [children]);
51
+ const [selectedValue, setSelectedValue] = useState(() => selectedFromProps !== null && selectedFromProps !== void 0 ? selectedFromProps : "0");
52
+ const [prevSelectedFromProps, setPrevSelectedFromProps] = useState(selectedFromProps);
53
+ if (selectedFromProps !== prevSelectedFromProps) {
54
+ setPrevSelectedFromProps(selectedFromProps);
55
+ if (selectedFromProps !== void 0 && selectedFromProps !== selectedValue) setSelectedValue(selectedFromProps);
56
+ }
57
+ const { tabListProps } = useTabList({
58
+ "aria-label": ariaLabel,
59
+ "aria-labelledby": ariaLabelledBy,
60
+ ref: listRef
61
+ });
45
62
  const contextValue = useMemo(() => ({
46
63
  iconsVisible,
47
64
  loadingCounters
@@ -68,55 +85,65 @@ const UnderlinePanels = ({ "aria-label": ariaLabel, "aria-labelledby": ariaLabel
68
85
  !(tabs.length === tabPanels.length) && invariant(false, `The number of tabs and panels must be equal. Counted ${tabs.length} tabs and ${tabPanels.length} panels.`);
69
86
  return /*#__PURE__*/ jsx(UnderlinePanelsContext.Provider, {
70
87
  value: contextValue,
71
- children: /*#__PURE__*/ jsxs(TabContainerComponent, { children: [/*#__PURE__*/ jsx(UnderlineWrapper, {
72
- ref: wrapperRef,
73
- slot: "tablist-wrapper",
74
- "data-icons-visible": iconsVisible,
75
- className: clsx(className, UnderlinePanels_module_css_default.StyledUnderlineWrapper),
76
- ...props,
77
- children: /*#__PURE__*/ jsx(UnderlineItemList, {
78
- ref: listRef,
79
- "aria-label": ariaLabel,
80
- "aria-labelledby": ariaLabelledBy,
81
- role: "tablist",
82
- children: tabs
83
- })
84
- }), tabPanels] })
88
+ children: /*#__PURE__*/ jsxs(Tabs, {
89
+ id: parentId,
90
+ value: selectedValue,
91
+ onValueChange: ({ value }) => setSelectedValue(value),
92
+ children: [/*#__PURE__*/ jsx(UnderlineWrapper, {
93
+ ref: wrapperRef,
94
+ "data-icons-visible": iconsVisible,
95
+ className: clsx(className, UnderlinePanels_module_css_default.StyledUnderlineWrapper),
96
+ ...props,
97
+ children: /*#__PURE__*/ jsx(UnderlineItemList, {
98
+ ref: listRef,
99
+ role: tabListProps.role,
100
+ "aria-label": tabListProps["aria-label"],
101
+ "aria-labelledby": tabListProps["aria-labelledby"],
102
+ "aria-orientation": tabListProps["aria-orientation"],
103
+ onKeyDown: tabListProps.onKeyDown,
104
+ children: tabs
105
+ })
106
+ }), tabPanels]
107
+ })
85
108
  });
86
109
  };
87
110
  UnderlinePanels.displayName = "UnderlinePanels";
88
- const TabImpl = ({ "aria-selected": ariaSelected, onSelect, ...props }) => {
111
+ const TabImpl = ({ onSelect, value, ...itemProps }) => {
89
112
  const { loadingCounters } = useContext(UnderlinePanelsContext);
90
- const clickHandler = React.useCallback((event) => {
91
- if (!event.defaultPrevented && typeof onSelect === "function") onSelect(event);
92
- }, [onSelect]);
93
- const keyDownHandler = React.useCallback((event) => {
94
- if ((event.key === " " || event.key === "Enter") && !event.defaultPrevented && typeof onSelect === "function") onSelect(event);
95
- }, [onSelect]);
113
+ const { tabProps } = useTab({ value: value !== null && value !== void 0 ? value : "" });
114
+ const { onKeyDown: tabOnKeyDown, onMouseDown: tabOnMouseDown, onFocus: tabOnFocus, ...restTabProps } = tabProps;
96
115
  return /*#__PURE__*/ jsx(UnderlineItem, {
97
116
  as: "button",
98
- role: "tab",
99
- tabIndex: ariaSelected ? 0 : -1,
100
- "aria-selected": ariaSelected,
117
+ ...itemProps,
118
+ ...restTabProps,
101
119
  type: "button",
102
- onClick: clickHandler,
103
- onKeyDown: keyDownHandler,
104
- loadingCounters,
105
- ...props
120
+ onClick: (event) => {
121
+ if (!event.defaultPrevented && typeof onSelect === "function") onSelect(event);
122
+ },
123
+ onKeyDown: (event) => {
124
+ tabOnKeyDown === null || tabOnKeyDown === void 0 || tabOnKeyDown(event);
125
+ if ((event.key === " " || event.key === "Enter") && !event.defaultPrevented && typeof onSelect === "function") onSelect(event);
126
+ },
127
+ onMouseDown: tabOnMouseDown,
128
+ onFocus: tabOnFocus,
129
+ loadingCounters
106
130
  });
107
131
  };
108
132
  TabImpl.displayName = "TabImpl";
109
133
  TabImpl.displayName = "UnderlinePanels.Tab";
110
134
  const Tab = /*#__PURE__*/ React.memo(TabImpl);
111
135
  Tab.displayName = "UnderlinePanels.Tab";
112
- const Panel = ({ children, ...rest }) => {
136
+ const PanelImpl = ({ children, value, ...panelRest }) => {
137
+ const { tabPanelProps } = useTabPanel({ value: value !== null && value !== void 0 ? value : "" });
113
138
  return /*#__PURE__*/ jsx("div", {
114
- role: "tabpanel",
115
- ...rest,
139
+ ...panelRest,
140
+ ...tabPanelProps,
116
141
  children
117
142
  });
118
143
  };
119
- Panel.displayName = "Panel";
144
+ PanelImpl.displayName = "PanelImpl";
145
+ PanelImpl.displayName = "UnderlinePanels.Panel";
146
+ const Panel = PanelImpl;
120
147
  Panel.displayName = "UnderlinePanels.Panel";
121
148
  var UnderlinePanels_default = Object.assign(UnderlinePanels, {
122
149
  Panel,
@@ -30,12 +30,12 @@ import { Table } from "../DataTable/index.js";
30
30
  import { InlineMessage } from "../InlineMessage/InlineMessage.js";
31
31
  import { Hidden } from "../Hidden/Hidden.js";
32
32
  import { SelectPanel } from "./SelectPanel2/SelectPanel.js";
33
- import UnderlinePanels_default from "./UnderlinePanels/UnderlinePanels.js";
34
- import { IssueLabel } from "./IssueLabel/IssueLabel.js";
35
33
  import { useTab } from "./Tabs/useTab.js";
36
34
  import { useTabList } from "./Tabs/useTabList.js";
37
35
  import { useTabPanel } from "./Tabs/useTabPanel.js";
38
36
  import { Tabs } from "./Tabs/Tabs.js";
37
+ import UnderlinePanels_default from "./UnderlinePanels/UnderlinePanels.js";
38
+ import { IssueLabel } from "./IssueLabel/IssueLabel.js";
39
39
  import { TopicTag } from "../TopicTag/index.js";
40
40
  //#region src/experimental/index.ts
41
41
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@primer/react",
3
3
  "type": "module",
4
- "version": "38.34.0-rc.d17f87af7",
4
+ "version": "38.34.0-rc.dad320815",
5
5
  "description": "An implementation of GitHub's Primer Design System using React",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
@@ -77,7 +77,6 @@
77
77
  "dependencies": {
78
78
  "@github/mini-throttle": "^2.1.1",
79
79
  "@github/relative-time-element": "^5.0.0",
80
- "@github/tab-container-element": "^4.8.2",
81
80
  "@lit-labs/react": "1.2.1",
82
81
  "@oddbird/popover-polyfill": "^0.5.2",
83
82
  "@primer/behaviors": "^1.10.3",