@primer/react 38.36.0 → 38.37.0-rc.05923388d
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 +14 -0
- package/dist/ActionList/Item.js +5 -4
- package/dist/AnchoredOverlay/AnchoredOverlay.js +5 -3
- package/dist/FeatureFlags/DefaultFeatureFlags.js +2 -1
- package/dist/Flash/Flash.d.ts +6 -0
- package/dist/Flash/Flash.js +6 -0
- package/dist/InlineMessage/InlineMessage.js +11 -10
- package/dist/LabelGroup/LabelGroup.js +6 -4
- package/dist/SegmentedControl/SegmentedControl-4ef72733.css +2 -0
- package/dist/SegmentedControl/SegmentedControl-4ef72733.css.map +1 -0
- package/dist/SegmentedControl/SegmentedControl.js +9 -5
- package/dist/SegmentedControl/SegmentedControl.module.css.js +1 -1
- package/dist/Textarea/{TextArea-53e27580.css → TextArea-2dc51d35.css} +2 -2
- package/dist/Textarea/TextArea-2dc51d35.css.map +1 -0
- package/dist/Textarea/TextArea.module.css.js +1 -1
- package/dist/Textarea/Textarea.d.ts +8 -0
- package/dist/Textarea/Textarea.js +128 -121
- package/dist/deprecated/index.d.ts +2 -1
- package/dist/deprecated/index.js +2 -1
- package/dist/experimental/Tabs/Tabs.js +33 -19
- package/dist/experimental/Tabs/types.d.ts +6 -0
- package/dist/experimental/Tabs/useTab.js +6 -1
- package/dist/experimental/Tabs/useTabList.js +29 -22
- package/dist/experimental/UnderlinePanels/UnderlinePanels.d.ts +38 -1
- package/dist/experimental/UnderlinePanels/UnderlinePanels.js +69 -18
- package/dist/hooks/useFocusTrap.js +9 -7
- package/dist/hooks/useFocusZone.js +16 -14
- package/dist/hooks/useMenuInitialFocus.js +4 -3
- package/generated/components.json +70 -11
- package/package.json +7 -7
- package/dist/SegmentedControl/SegmentedControl-de65527b.css +0 -2
- package/dist/SegmentedControl/SegmentedControl-de65527b.css.map +0 -1
- package/dist/Textarea/TextArea-53e27580.css.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import useIsomorphicLayoutEffect from "../../utils/useIsomorphicLayoutEffect.js";
|
|
2
|
+
import { useFeatureFlag } from "../../FeatureFlags/useFeatureFlag.js";
|
|
2
3
|
import { useControllableState } from "../../hooks/useControllableState.js";
|
|
3
4
|
import { TabsContext } from "./TabsContext.js";
|
|
4
5
|
import { c } from "react-compiler-runtime";
|
|
@@ -13,11 +14,13 @@ import React, { useId } from "react";
|
|
|
13
14
|
* The `Tab`, `TabList`, and `TabPanel` components are provided for convenience to showcase the API & implementation.
|
|
14
15
|
*/
|
|
15
16
|
function Tabs(props) {
|
|
16
|
-
var _props$id, _props$defaultValue;
|
|
17
|
-
const $ = c(
|
|
17
|
+
var _props$id, _props$activationMode, _props$defaultValue;
|
|
18
|
+
const $ = c(16);
|
|
18
19
|
const { children, onValueChange } = props;
|
|
19
20
|
const generatedId = useId();
|
|
20
21
|
const groupId = (_props$id = props.id) !== null && _props$id !== void 0 ? _props$id : generatedId;
|
|
22
|
+
const controlledApiEnabled = useFeatureFlag("primer_react_underline_panels_controlled");
|
|
23
|
+
const activationMode = controlledApiEnabled ? (_props$activationMode = props.activationMode) !== null && _props$activationMode !== void 0 ? _props$activationMode : "automatic" : "automatic";
|
|
21
24
|
const t0 = (_props$defaultValue = props.defaultValue) !== null && _props$defaultValue !== void 0 ? _props$defaultValue : props.value;
|
|
22
25
|
let t1;
|
|
23
26
|
if ($[0] !== props.value || $[1] !== t0) {
|
|
@@ -31,49 +34,60 @@ function Tabs(props) {
|
|
|
31
34
|
$[2] = t1;
|
|
32
35
|
} else t1 = $[2];
|
|
33
36
|
const [selectedValue, setSelectedValue] = useControllableState(t1);
|
|
37
|
+
const [focusedValue, setFocusedValue] = React.useState();
|
|
34
38
|
const savedOnValueChange = React.useRef(onValueChange);
|
|
35
39
|
let t2;
|
|
36
|
-
if ($[3] !==
|
|
40
|
+
if ($[3] !== activationMode || $[4] !== controlledApiEnabled || $[5] !== focusedValue || $[6] !== groupId || $[7] !== selectedValue || $[8] !== setSelectedValue) {
|
|
37
41
|
t2 = {
|
|
38
42
|
groupId,
|
|
39
43
|
selectedValue,
|
|
44
|
+
activationMode,
|
|
45
|
+
focusedValue,
|
|
40
46
|
selectTab(value) {
|
|
41
47
|
var _savedOnValueChange$c;
|
|
48
|
+
setFocusedValue(void 0);
|
|
49
|
+
if (controlledApiEnabled && value === selectedValue) return;
|
|
42
50
|
setSelectedValue(value);
|
|
43
51
|
(_savedOnValueChange$c = savedOnValueChange.current) === null || _savedOnValueChange$c === void 0 || _savedOnValueChange$c.call(savedOnValueChange, { value });
|
|
52
|
+
},
|
|
53
|
+
focusTab(value_0) {
|
|
54
|
+
setFocusedValue(value_0);
|
|
44
55
|
}
|
|
45
56
|
};
|
|
46
|
-
$[3] =
|
|
47
|
-
$[4] =
|
|
48
|
-
$[5] =
|
|
49
|
-
$[6] =
|
|
50
|
-
|
|
57
|
+
$[3] = activationMode;
|
|
58
|
+
$[4] = controlledApiEnabled;
|
|
59
|
+
$[5] = focusedValue;
|
|
60
|
+
$[6] = groupId;
|
|
61
|
+
$[7] = selectedValue;
|
|
62
|
+
$[8] = setSelectedValue;
|
|
63
|
+
$[9] = t2;
|
|
64
|
+
} else t2 = $[9];
|
|
51
65
|
const contextValue = t2;
|
|
52
66
|
let t3;
|
|
53
67
|
let t4;
|
|
54
|
-
if ($[
|
|
68
|
+
if ($[10] !== onValueChange) {
|
|
55
69
|
t3 = () => {
|
|
56
70
|
savedOnValueChange.current = onValueChange;
|
|
57
71
|
};
|
|
58
72
|
t4 = [onValueChange];
|
|
59
|
-
$[
|
|
60
|
-
$[
|
|
61
|
-
$[
|
|
73
|
+
$[10] = onValueChange;
|
|
74
|
+
$[11] = t3;
|
|
75
|
+
$[12] = t4;
|
|
62
76
|
} else {
|
|
63
|
-
t3 = $[
|
|
64
|
-
t4 = $[
|
|
77
|
+
t3 = $[11];
|
|
78
|
+
t4 = $[12];
|
|
65
79
|
}
|
|
66
80
|
useIsomorphicLayoutEffect(t3, t4);
|
|
67
81
|
let t5;
|
|
68
|
-
if ($[
|
|
82
|
+
if ($[13] !== children || $[14] !== contextValue) {
|
|
69
83
|
t5 = /*#__PURE__*/ jsx(TabsContext.Provider, {
|
|
70
84
|
value: contextValue,
|
|
71
85
|
children
|
|
72
86
|
});
|
|
73
|
-
$[
|
|
74
|
-
$[
|
|
75
|
-
$[
|
|
76
|
-
} else t5 = $[
|
|
87
|
+
$[13] = children;
|
|
88
|
+
$[14] = contextValue;
|
|
89
|
+
$[15] = t5;
|
|
90
|
+
} else t5 = $[15];
|
|
77
91
|
return t5;
|
|
78
92
|
}
|
|
79
93
|
//#endregion
|
|
@@ -51,6 +51,12 @@ type CommonTabsProps = {
|
|
|
51
51
|
* unique id is generated automatically.
|
|
52
52
|
*/
|
|
53
53
|
id?: string;
|
|
54
|
+
/**
|
|
55
|
+
* `'automatic'` (default) selects on focus, so Arrow/Home/End keys select immediately. `'manual'`
|
|
56
|
+
* only moves focus; selection commits on Enter/Space/click. Prefer `'manual'` when displaying a
|
|
57
|
+
* panel is not instant (e.g. it triggers a network request).
|
|
58
|
+
*/
|
|
59
|
+
activationMode?: 'automatic' | 'manual';
|
|
54
60
|
};
|
|
55
61
|
type TabsProps = PropsWithChildren<(ControlledTabsProps | UncontrolledTabsProps) & CommonTabsProps>;
|
|
56
62
|
type Label = {
|
|
@@ -12,6 +12,7 @@ function useTab(props) {
|
|
|
12
12
|
const selected = tabs.selectedValue === value;
|
|
13
13
|
const id = `${tabs.groupId}-tab-${value}`;
|
|
14
14
|
const panelId = `${tabs.groupId}-panel-${value}`;
|
|
15
|
+
const isTabStop = tabs.activationMode === "manual" && tabs.focusedValue !== void 0 ? tabs.focusedValue === value : selected;
|
|
15
16
|
let t0;
|
|
16
17
|
if ($[0] !== tabs || $[1] !== value) {
|
|
17
18
|
t0 = function onKeyDown(event) {
|
|
@@ -37,6 +38,10 @@ function useTab(props) {
|
|
|
37
38
|
let t2;
|
|
38
39
|
if ($[7] !== disabled || $[8] !== selected || $[9] !== tabs || $[10] !== value) {
|
|
39
40
|
t2 = function onFocus() {
|
|
41
|
+
if (tabs.activationMode === "manual") {
|
|
42
|
+
if (!disabled) tabs.focusTab(value);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
40
45
|
if (!selected && !disabled) tabs.selectTab(value);
|
|
41
46
|
};
|
|
42
47
|
$[7] = disabled;
|
|
@@ -47,7 +52,7 @@ function useTab(props) {
|
|
|
47
52
|
} else t2 = $[11];
|
|
48
53
|
const onFocus = t2;
|
|
49
54
|
const t3 = disabled ? true : void 0;
|
|
50
|
-
const t4 =
|
|
55
|
+
const t4 = isTabStop ? 0 : -1;
|
|
51
56
|
let t5;
|
|
52
57
|
if ($[12] !== id || $[13] !== onFocus || $[14] !== onKeyDown || $[15] !== onMouseDown || $[16] !== panelId || $[17] !== selected || $[18] !== t3 || $[19] !== t4) {
|
|
53
58
|
t5 = { tabProps: {
|
|
@@ -5,20 +5,29 @@ import { c } from "react-compiler-runtime";
|
|
|
5
5
|
import { useRef } from "react";
|
|
6
6
|
//#region src/experimental/Tabs/useTabList.ts
|
|
7
7
|
function useTabList(props) {
|
|
8
|
-
const $ = c(
|
|
8
|
+
const $ = c(10);
|
|
9
9
|
const { "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, "aria-orientation": ariaOrientation } = props;
|
|
10
10
|
const mergedRefEnabled = useFeatureFlag("primer_react_merged_forwarded_refs");
|
|
11
|
+
const controlledApiEnabled = useFeatureFlag("primer_react_underline_panels_controlled");
|
|
11
12
|
const tabListRef = useRef(null);
|
|
12
13
|
const mergedRef = useMergedRefs(tabListRef, props.ref);
|
|
13
14
|
const providedOrCreatedRef = useProvidedRefOrCreate(props.ref);
|
|
14
15
|
const readRef = mergedRefEnabled ? tabListRef : providedOrCreatedRef;
|
|
15
16
|
const appliedRef = mergedRefEnabled ? mergedRef : providedOrCreatedRef;
|
|
16
17
|
let t0;
|
|
17
|
-
if ($[0] !== ariaOrientation || $[1] !== readRef) {
|
|
18
|
+
if ($[0] !== ariaOrientation || $[1] !== controlledApiEnabled || $[2] !== readRef) {
|
|
18
19
|
t0 = (event) => {
|
|
19
20
|
const { current: tablist } = readRef;
|
|
20
21
|
if (tablist === null) return;
|
|
21
22
|
const tabs = getFocusableTabs(tablist);
|
|
23
|
+
const getCurrentIndex = () => {
|
|
24
|
+
if (controlledApiEnabled) {
|
|
25
|
+
const activeElement = tablist.ownerDocument.activeElement;
|
|
26
|
+
const focusedIndex = activeElement instanceof HTMLElement ? tabs.indexOf(activeElement) : -1;
|
|
27
|
+
if (focusedIndex !== -1) return focusedIndex;
|
|
28
|
+
}
|
|
29
|
+
return tabs.findIndex(_temp);
|
|
30
|
+
};
|
|
22
31
|
const isVertical = ariaOrientation === "vertical";
|
|
23
32
|
const nextKey = isVertical ? "ArrowDown" : "ArrowRight";
|
|
24
33
|
const prevKey = isVertical ? "ArrowUp" : "ArrowLeft";
|
|
@@ -27,13 +36,13 @@ function useTabList(props) {
|
|
|
27
36
|
event.stopPropagation();
|
|
28
37
|
}
|
|
29
38
|
if (event.key === nextKey) {
|
|
30
|
-
const
|
|
31
|
-
if (
|
|
32
|
-
tabs[(
|
|
39
|
+
const currentTabIndex = getCurrentIndex();
|
|
40
|
+
if (currentTabIndex === -1) return;
|
|
41
|
+
tabs[(currentTabIndex + 1) % tabs.length].focus();
|
|
33
42
|
} else if (event.key === prevKey) {
|
|
34
|
-
const
|
|
35
|
-
if (
|
|
36
|
-
tabs[(tabs.length +
|
|
43
|
+
const currentTabIndex_0 = getCurrentIndex();
|
|
44
|
+
if (currentTabIndex_0 === -1) return;
|
|
45
|
+
tabs[(tabs.length + currentTabIndex_0 - 1) % tabs.length].focus();
|
|
37
46
|
} else if (event.key === "Home") {
|
|
38
47
|
if (tabs[0]) tabs[0].focus();
|
|
39
48
|
} else if (event.key === "End") {
|
|
@@ -41,13 +50,14 @@ function useTabList(props) {
|
|
|
41
50
|
}
|
|
42
51
|
};
|
|
43
52
|
$[0] = ariaOrientation;
|
|
44
|
-
$[1] =
|
|
45
|
-
$[2] =
|
|
46
|
-
|
|
53
|
+
$[1] = controlledApiEnabled;
|
|
54
|
+
$[2] = readRef;
|
|
55
|
+
$[3] = t0;
|
|
56
|
+
} else t0 = $[3];
|
|
47
57
|
const onKeyDown = t0;
|
|
48
58
|
const t1 = ariaOrientation !== null && ariaOrientation !== void 0 ? ariaOrientation : "horizontal";
|
|
49
59
|
let t2;
|
|
50
|
-
if ($[
|
|
60
|
+
if ($[4] !== appliedRef || $[5] !== ariaLabel || $[6] !== ariaLabelledby || $[7] !== onKeyDown || $[8] !== t1) {
|
|
51
61
|
t2 = { tabListProps: {
|
|
52
62
|
ref: appliedRef,
|
|
53
63
|
"aria-label": ariaLabel,
|
|
@@ -56,18 +66,15 @@ function useTabList(props) {
|
|
|
56
66
|
role: "tablist",
|
|
57
67
|
onKeyDown
|
|
58
68
|
} };
|
|
59
|
-
$[
|
|
60
|
-
$[
|
|
61
|
-
$[
|
|
62
|
-
$[
|
|
63
|
-
$[
|
|
64
|
-
$[
|
|
65
|
-
} else t2 = $[
|
|
69
|
+
$[4] = appliedRef;
|
|
70
|
+
$[5] = ariaLabel;
|
|
71
|
+
$[6] = ariaLabelledby;
|
|
72
|
+
$[7] = onKeyDown;
|
|
73
|
+
$[8] = t1;
|
|
74
|
+
$[9] = t2;
|
|
75
|
+
} else t2 = $[9];
|
|
66
76
|
return t2;
|
|
67
77
|
}
|
|
68
|
-
function _temp2(tab_0) {
|
|
69
|
-
return tab_0.getAttribute("aria-selected") === "true";
|
|
70
|
-
}
|
|
71
78
|
function _temp(tab) {
|
|
72
79
|
return tab.getAttribute("aria-selected") === "true";
|
|
73
80
|
}
|
|
@@ -16,6 +16,31 @@ type UnderlinePanelsProps = {
|
|
|
16
16
|
* ID of the element containing the name for the tab list
|
|
17
17
|
*/
|
|
18
18
|
'aria-labelledby'?: React.AriaAttributes['aria-labelledby'];
|
|
19
|
+
/**
|
|
20
|
+
* The value of the selected tab, keyed to each `UnderlinePanels.Tab`/`UnderlinePanels.Panel`
|
|
21
|
+
* `value`. Provide this (with `onChange`) for a controlled component where the selected tab is
|
|
22
|
+
* the single source of truth.
|
|
23
|
+
*/
|
|
24
|
+
value?: string;
|
|
25
|
+
/**
|
|
26
|
+
* The value of the tab that should be selected by default, keyed to each tab's `value`. Use this
|
|
27
|
+
* for an uncontrolled component. Cannot be combined with `value`.
|
|
28
|
+
*/
|
|
29
|
+
defaultValue?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Fires whenever the selected tab changes, for every selection method including arrow keys.
|
|
32
|
+
* Unlike `UnderlinePanels.Tab`'s `onSelect`, which only fires on click and Enter/Space.
|
|
33
|
+
*/
|
|
34
|
+
onChange?: ({
|
|
35
|
+
value
|
|
36
|
+
}: {
|
|
37
|
+
value: string;
|
|
38
|
+
}) => void;
|
|
39
|
+
/**
|
|
40
|
+
* `'automatic'` (default) selects on focus/arrow keys; `'manual'` only moves focus until
|
|
41
|
+
* Enter/Space/click. Prefer `'manual'` when displaying a panel is not instant.
|
|
42
|
+
*/
|
|
43
|
+
activationMode?: 'automatic' | 'manual';
|
|
19
44
|
/**
|
|
20
45
|
* Custom string to use when generating the IDs of tabs and `aria-labelledby` for the panels
|
|
21
46
|
*/
|
|
@@ -34,6 +59,12 @@ type UnderlinePanelsProps = {
|
|
|
34
59
|
as?: React.ElementType;
|
|
35
60
|
};
|
|
36
61
|
type TabProps = PropsWithChildren<{
|
|
62
|
+
/**
|
|
63
|
+
* A value that uniquely identifies this tab, paired with the `UnderlinePanels.Panel` of the same
|
|
64
|
+
* `value`. Provide this to use domain values (e.g. `'branch'`) with the container's controlled
|
|
65
|
+
* `value`/`onChange` API. When omitted, tabs and panels are paired by their DOM order.
|
|
66
|
+
*/
|
|
67
|
+
value?: string;
|
|
37
68
|
/**
|
|
38
69
|
* Whether this is the selected tab
|
|
39
70
|
*/
|
|
@@ -51,7 +82,13 @@ type TabProps = PropsWithChildren<{
|
|
|
51
82
|
*/
|
|
52
83
|
icon?: FC<IconProps>;
|
|
53
84
|
}>;
|
|
54
|
-
type PanelProps = React.HTMLAttributes<HTMLDivElement
|
|
85
|
+
type PanelProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
86
|
+
/**
|
|
87
|
+
* A value that uniquely identifies this panel, paired with the `UnderlinePanels.Tab` of the same
|
|
88
|
+
* `value`. When omitted, tabs and panels are paired by their DOM order.
|
|
89
|
+
*/
|
|
90
|
+
value?: string;
|
|
91
|
+
};
|
|
55
92
|
declare const _default: React.FC<UnderlinePanelsProps> & SlotMarker & {
|
|
56
93
|
Panel: FCWithSlotMarker<PanelProps>;
|
|
57
94
|
Tab: FCWithSlotMarker<TabProps>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import useIsomorphicLayoutEffect from "../../utils/useIsomorphicLayoutEffect.js";
|
|
2
2
|
import { useResizeObserver } from "../../hooks/useResizeObserver.js";
|
|
3
3
|
import { useId as useId$1 } from "../../hooks/useId.js";
|
|
4
|
+
import { warning } from "../../utils/warning.js";
|
|
4
5
|
import { isSlot } from "../../utils/is-slot.js";
|
|
6
|
+
import { useFeatureFlag } from "../../FeatureFlags/useFeatureFlag.js";
|
|
5
7
|
import { invariant } from "../../utils/invariant.js";
|
|
6
8
|
import { UnderlineItem, UnderlineItemList, UnderlineWrapper } from "../../internal/components/UnderlineTabbedInterface.js";
|
|
7
9
|
import UnderlinePanels_module_css_default from "./UnderlinePanels.module.css.js";
|
|
@@ -17,43 +19,78 @@ const UnderlinePanelsContext = /*#__PURE__*/ createContext({
|
|
|
17
19
|
iconsVisible: true,
|
|
18
20
|
loadingCounters: void 0
|
|
19
21
|
});
|
|
20
|
-
const UnderlinePanels = ({ "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, children, loadingCounters, className, ...props }) => {
|
|
22
|
+
const UnderlinePanels = ({ "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, children, loadingCounters, className, value: valueProp, defaultValue: defaultValueProp, onChange: onChangeProp, activationMode = "automatic", ...props }) => {
|
|
23
|
+
var _tabValues$;
|
|
24
|
+
const controlledApiEnabled = useFeatureFlag("primer_react_underline_panels_controlled");
|
|
25
|
+
const controlledValue = controlledApiEnabled ? valueProp : void 0;
|
|
26
|
+
const defaultValue = controlledApiEnabled ? defaultValueProp : void 0;
|
|
27
|
+
const onChange = controlledApiEnabled ? onChangeProp : void 0;
|
|
21
28
|
const [iconsVisible, setIconsVisible] = useState(true);
|
|
22
29
|
const wrapperRef = useRef(null);
|
|
23
30
|
const listRef = useRef(null);
|
|
24
31
|
const parentId = useId$1(props.id);
|
|
25
|
-
const [tabs, tabPanels, tabsHaveIcons, selectedFromProps] = useMemo(() => {
|
|
32
|
+
const [tabs, tabPanels, tabsHaveIcons, selectedFromProps, tabValues, panelValues] = useMemo(() => {
|
|
26
33
|
let tabIndex = 0;
|
|
27
34
|
let panelIndex = 0;
|
|
28
35
|
const childrenWithProps = Children.map(children, (child) => {
|
|
29
|
-
if (/*#__PURE__*/ isValidElement(child) && (child.type === Tab || isSlot(child, Tab)))
|
|
30
|
-
|
|
36
|
+
if (/*#__PURE__*/ isValidElement(child) && (child.type === Tab || isSlot(child, Tab))) {
|
|
37
|
+
var _ref;
|
|
38
|
+
const value = (_ref = controlledApiEnabled ? child.props.value : void 0) !== null && _ref !== void 0 ? _ref : `${tabIndex}`;
|
|
39
|
+
tabIndex++;
|
|
40
|
+
return /*#__PURE__*/ cloneElement(child, { value });
|
|
41
|
+
}
|
|
42
|
+
if (/*#__PURE__*/ isValidElement(child) && (child.type === Panel || isSlot(child, Panel))) {
|
|
43
|
+
var _ref2;
|
|
44
|
+
const value = (_ref2 = controlledApiEnabled ? child.props.value : void 0) !== null && _ref2 !== void 0 ? _ref2 : `${panelIndex}`;
|
|
45
|
+
panelIndex++;
|
|
46
|
+
return /*#__PURE__*/ cloneElement(child, { value });
|
|
47
|
+
}
|
|
31
48
|
return child;
|
|
32
49
|
});
|
|
33
50
|
const tabs = [];
|
|
34
51
|
const tabPanels = [];
|
|
52
|
+
const tabValues = [];
|
|
53
|
+
const panelValues = [];
|
|
35
54
|
let selectedFromProps;
|
|
36
55
|
for (const child of Children.toArray(childrenWithProps)) {
|
|
37
56
|
if (!/*#__PURE__*/ isValidElement(child)) continue;
|
|
38
57
|
if (child.type === Tab || isSlot(child, Tab)) {
|
|
58
|
+
const value = child.props.value;
|
|
59
|
+
if (value !== void 0) tabValues.push(value);
|
|
39
60
|
const ariaSelected = child.props["aria-selected"];
|
|
40
|
-
if (ariaSelected === true || ariaSelected === "true") selectedFromProps =
|
|
61
|
+
if (ariaSelected === true || ariaSelected === "true") selectedFromProps = value;
|
|
41
62
|
tabs.push(child);
|
|
42
|
-
} else if (child.type === Panel || isSlot(child, Panel))
|
|
63
|
+
} else if (child.type === Panel || isSlot(child, Panel)) {
|
|
64
|
+
const value = child.props.value;
|
|
65
|
+
if (value !== void 0) panelValues.push(value);
|
|
66
|
+
tabPanels.push(child);
|
|
67
|
+
}
|
|
43
68
|
}
|
|
44
69
|
return [
|
|
45
70
|
tabs,
|
|
46
71
|
tabPanels,
|
|
47
72
|
tabs.some((tab) => /*#__PURE__*/ React.isValidElement(tab) && tab.props.icon),
|
|
48
|
-
selectedFromProps
|
|
73
|
+
selectedFromProps,
|
|
74
|
+
tabValues,
|
|
75
|
+
panelValues
|
|
49
76
|
];
|
|
50
|
-
}, [children]);
|
|
51
|
-
const
|
|
77
|
+
}, [children, controlledApiEnabled]);
|
|
78
|
+
const isControlled = controlledValue !== void 0;
|
|
79
|
+
const [uncontrolledValue, setUncontrolledValue] = useState(() => {
|
|
80
|
+
var _ref3;
|
|
81
|
+
return (_ref3 = defaultValue !== null && defaultValue !== void 0 ? defaultValue : selectedFromProps) !== null && _ref3 !== void 0 ? _ref3 : "0";
|
|
82
|
+
});
|
|
52
83
|
const [prevSelectedFromProps, setPrevSelectedFromProps] = useState(selectedFromProps);
|
|
53
|
-
if (selectedFromProps !== prevSelectedFromProps) {
|
|
84
|
+
if (!isControlled && selectedFromProps !== prevSelectedFromProps) {
|
|
54
85
|
setPrevSelectedFromProps(selectedFromProps);
|
|
55
|
-
if (selectedFromProps !== void 0 && selectedFromProps !==
|
|
86
|
+
if (selectedFromProps !== void 0 && selectedFromProps !== uncontrolledValue) setUncontrolledValue(selectedFromProps);
|
|
56
87
|
}
|
|
88
|
+
const selectedValue = isControlled ? controlledValue : uncontrolledValue;
|
|
89
|
+
const effectiveValue = tabValues.includes(selectedValue) ? selectedValue : (_tabValues$ = tabValues[0]) !== null && _tabValues$ !== void 0 ? _tabValues$ : selectedValue;
|
|
90
|
+
const handleValueChange = (value) => {
|
|
91
|
+
if (!isControlled) setUncontrolledValue(value);
|
|
92
|
+
onChange === null || onChange === void 0 || onChange({ value });
|
|
93
|
+
};
|
|
57
94
|
const { tabListProps } = useTabList({
|
|
58
95
|
"aria-label": ariaLabel,
|
|
59
96
|
"aria-labelledby": ariaLabelledBy,
|
|
@@ -78,17 +115,31 @@ const UnderlinePanels = ({ "aria-label": ariaLabel, "aria-labelledby": ariaLabel
|
|
|
78
115
|
const wrapperWidth = resizeObserverEntries[0].contentRect.width;
|
|
79
116
|
setIconsVisible(wrapperWidth > listWidthRef.current);
|
|
80
117
|
}, wrapperRef, []);
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
118
|
+
{
|
|
119
|
+
const selectedTabs = tabs.filter((tab) => {
|
|
120
|
+
const ariaSelected = /*#__PURE__*/ React.isValidElement(tab) && tab.props["aria-selected"];
|
|
121
|
+
return ariaSelected === true || ariaSelected === "true";
|
|
122
|
+
});
|
|
123
|
+
!(selectedTabs.length <= 1) && invariant(false, "Only one tab can be selected at a time.");
|
|
124
|
+
!(tabs.length === tabPanels.length) && invariant(false, `The number of tabs and panels must be equal. Counted ${tabs.length} tabs and ${tabPanels.length} panels.`);
|
|
125
|
+
const duplicateTabValue = tabValues.find((value, index) => tabValues.indexOf(value) !== index);
|
|
126
|
+
!(duplicateTabValue === void 0) && invariant(false, `Every tab must have a unique \`value\`. Found duplicate "${duplicateTabValue}".`);
|
|
127
|
+
const duplicatePanelValue = panelValues.find((value, index) => panelValues.indexOf(value) !== index);
|
|
128
|
+
!(duplicatePanelValue === void 0) && invariant(false, `Every panel must have a unique \`value\`. Found duplicate "${duplicatePanelValue}".`);
|
|
129
|
+
const unmatchedTabValue = tabValues.find((value) => !panelValues.includes(value));
|
|
130
|
+
!(unmatchedTabValue === void 0) && invariant(false, `Tab with \`value\` "${unmatchedTabValue}" has no matching panel. Give a \`UnderlinePanels.Panel\` the same \`value\`.`);
|
|
131
|
+
warning(isControlled && selectedTabs.length > 0, "UnderlinePanels: do not combine the controlled `value` prop with `aria-selected` on a tab. `value` takes precedence; use `value`/`onChange` (or `defaultValue`) to drive selection.");
|
|
132
|
+
warning(controlledValue !== void 0 && defaultValue !== void 0, "UnderlinePanels: do not combine the controlled `value` prop with `defaultValue`. `value` takes precedence; use one or the other.");
|
|
133
|
+
const providedValue = controlledValue !== null && controlledValue !== void 0 ? controlledValue : defaultValue;
|
|
134
|
+
warning(providedValue !== void 0 && tabValues.length > 0 && !tabValues.includes(providedValue), `UnderlinePanels: the selected value "${providedValue}" does not match any tab, so the first tab is selected instead. Provide a \`value\`/\`defaultValue\` that matches a \`UnderlinePanels.Tab\` \`value\`.`);
|
|
135
|
+
}
|
|
86
136
|
return /*#__PURE__*/ jsx(UnderlinePanelsContext.Provider, {
|
|
87
137
|
value: contextValue,
|
|
88
138
|
children: /*#__PURE__*/ jsxs(Tabs, {
|
|
89
139
|
id: parentId,
|
|
90
|
-
value:
|
|
91
|
-
|
|
140
|
+
value: effectiveValue,
|
|
141
|
+
activationMode,
|
|
142
|
+
onValueChange: ({ value }) => handleValueChange(value),
|
|
92
143
|
children: [/*#__PURE__*/ jsx(UnderlineWrapper, {
|
|
93
144
|
ref: wrapperRef,
|
|
94
145
|
"data-icons-visible": iconsVisible,
|
|
@@ -27,13 +27,15 @@ function useFocusTrap(settings, dependencies = []) {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
React.useEffect(() => {
|
|
30
|
-
if (containerRef.current instanceof HTMLElement)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
if (containerRef.current instanceof HTMLElement) {
|
|
31
|
+
if (!disabled) {
|
|
32
|
+
var _initialFocusRef$curr;
|
|
33
|
+
abortController.current = focusTrap(containerRef.current, (_initialFocusRef$curr = initialFocusRef.current) !== null && _initialFocusRef$curr !== void 0 ? _initialFocusRef$curr : void 0);
|
|
34
|
+
return () => {
|
|
35
|
+
disableTrap();
|
|
36
|
+
};
|
|
37
|
+
} else disableTrap();
|
|
38
|
+
}
|
|
37
39
|
}, [
|
|
38
40
|
containerRef,
|
|
39
41
|
initialFocusRef,
|
|
@@ -10,20 +10,22 @@ function useFocusZone(settings = {}, dependencies = []) {
|
|
|
10
10
|
const disabled = settings.disabled;
|
|
11
11
|
const abortController = React.useRef();
|
|
12
12
|
useEffect(() => {
|
|
13
|
-
if (containerRef.current instanceof HTMLElement && (!useActiveDescendant || activeDescendantControlRef.current instanceof HTMLElement))
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
if (containerRef.current instanceof HTMLElement && (!useActiveDescendant || activeDescendantControlRef.current instanceof HTMLElement)) {
|
|
14
|
+
if (!disabled) {
|
|
15
|
+
var _activeDescendantCont;
|
|
16
|
+
const vanillaSettings = {
|
|
17
|
+
...settings,
|
|
18
|
+
activeDescendantControl: (_activeDescendantCont = activeDescendantControlRef.current) !== null && _activeDescendantCont !== void 0 ? _activeDescendantCont : void 0
|
|
19
|
+
};
|
|
20
|
+
abortController.current = focusZone(containerRef.current, vanillaSettings);
|
|
21
|
+
return () => {
|
|
22
|
+
var _abortController$curr;
|
|
23
|
+
(_abortController$curr = abortController.current) === null || _abortController$curr === void 0 || _abortController$curr.abort();
|
|
24
|
+
};
|
|
25
|
+
} else {
|
|
26
|
+
var _abortController$curr2;
|
|
27
|
+
(_abortController$curr2 = abortController.current) === null || _abortController$curr2 === void 0 || _abortController$curr2.abort();
|
|
28
|
+
}
|
|
27
29
|
}
|
|
28
30
|
}, [disabled, ...dependencies]);
|
|
29
31
|
return {
|
|
@@ -43,9 +43,10 @@ const useMenuInitialFocus = (open, containerRef, anchorRef) => {
|
|
|
43
43
|
t2 = function moveFocusOnOpen() {
|
|
44
44
|
if (!open || !(containerRef !== null && containerRef !== void 0 && containerRef.current)) return;
|
|
45
45
|
const iterable = iterateFocusableElements(containerRef.current);
|
|
46
|
-
if (openingGesture === "mouse-click")
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
if (openingGesture === "mouse-click") {
|
|
47
|
+
if (anchorRef !== null && anchorRef !== void 0 && anchorRef.current) anchorRef.current.focus();
|
|
48
|
+
else throw new Error("For focus management, please attach anchorRef");
|
|
49
|
+
} else if (openingGesture && [
|
|
49
50
|
"ArrowDown",
|
|
50
51
|
"Space",
|
|
51
52
|
"Enter"
|