@fluentui/react-tabs 9.74.7-experimental.cli-api.20261006-ccaa611d58.0 → 9.75.0-experimental.css-modules.20261031-810ab07afb.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/CHANGELOG.md +35 -11
- package/README.md +8 -0
- package/lib/components/Tab/Tab.js.map +1 -1
- package/lib/components/Tab/Tab.module.css +475 -0
- package/lib/components/Tab/Tab.types.js.map +1 -1
- package/lib/components/Tab/TabAnimatedIndicator.module.css +27 -0
- package/lib/components/Tab/index.js.map +1 -1
- package/lib/components/Tab/renderTab.js +2 -2
- package/lib/components/Tab/renderTab.js.map +1 -1
- package/lib/components/Tab/useTab.js.map +1 -1
- package/lib/components/Tab/useTabAnimatedIndicator.styles.css.js +93 -0
- package/lib/components/Tab/useTabAnimatedIndicator.styles.css.js.map +1 -0
- package/lib/components/Tab/useTabAnimatedIndicator.styles.raw.css.js +93 -0
- package/lib/components/Tab/useTabAnimatedIndicator.styles.raw.css.js.map +1 -0
- package/lib/components/Tab/useTabAnimatedIndicator.styles.raw.js.map +1 -1
- package/lib/components/Tab/useTabStyles.styles.css.js +53 -0
- package/lib/components/Tab/useTabStyles.styles.css.js.map +1 -0
- package/lib/components/Tab/useTabStyles.styles.raw.css.js +53 -0
- package/lib/components/Tab/useTabStyles.styles.raw.css.js.map +1 -0
- package/lib/components/Tab/useTabStyles.styles.raw.js.map +1 -1
- package/lib/components/TabList/TabList.js.map +1 -1
- package/lib/components/TabList/TabList.module.css +27 -0
- package/lib/components/TabList/TabList.types.js.map +1 -1
- package/lib/components/TabList/TabListContext.js.map +1 -1
- package/lib/components/TabList/index.js.map +1 -1
- package/lib/components/TabList/renderTabList.js +2 -2
- package/lib/components/TabList/renderTabList.js.map +1 -1
- package/lib/components/TabList/useTabList.js.map +1 -1
- package/lib/components/TabList/useTabListContextValues.js.map +1 -1
- package/lib/components/TabList/useTabListStyles.styles.css.js +12 -0
- package/lib/components/TabList/useTabListStyles.styles.css.js.map +1 -0
- package/lib/components/TabList/useTabListStyles.styles.raw.css.js +12 -0
- package/lib/components/TabList/useTabListStyles.styles.raw.css.js.map +1 -0
- package/lib/components/TabList/useTabListStyles.styles.raw.js.map +1 -1
- package/lib-commonjs/Tab.cjs +12 -12
- package/lib-commonjs/Tab.cjs.map +1 -1
- package/lib-commonjs/TabList.cjs +12 -12
- package/lib-commonjs/TabList.cjs.map +1 -1
- package/lib-commonjs/components/Tab/Tab.cjs.map +1 -1
- package/lib-commonjs/components/Tab/Tab.module.css +475 -0
- package/lib-commonjs/components/Tab/Tab.types.cjs.map +1 -1
- package/lib-commonjs/components/Tab/TabAnimatedIndicator.module.css +27 -0
- package/lib-commonjs/components/Tab/index.cjs +13 -13
- package/lib-commonjs/components/Tab/index.cjs.map +1 -1
- package/lib-commonjs/components/Tab/renderTab.cjs.map +1 -1
- package/lib-commonjs/components/Tab/useTab.cjs +4 -4
- package/lib-commonjs/components/Tab/useTab.cjs.map +1 -1
- package/lib-commonjs/components/Tab/useTabAnimatedIndicator.styles.css.cjs +103 -0
- package/lib-commonjs/components/Tab/useTabAnimatedIndicator.styles.css.cjs.map +1 -0
- package/lib-commonjs/components/Tab/useTabAnimatedIndicator.styles.raw.cjs.map +1 -1
- package/lib-commonjs/components/Tab/useTabAnimatedIndicator.styles.raw.css.cjs +103 -0
- package/lib-commonjs/components/Tab/useTabAnimatedIndicator.styles.raw.css.cjs.map +1 -0
- package/lib-commonjs/components/Tab/useTabStyles.styles.cjs +7 -7
- package/lib-commonjs/components/Tab/useTabStyles.styles.cjs.map +1 -1
- package/lib-commonjs/components/Tab/useTabStyles.styles.css.cjs +82 -0
- package/lib-commonjs/components/Tab/useTabStyles.styles.css.cjs.map +1 -0
- package/lib-commonjs/components/Tab/useTabStyles.styles.raw.cjs +7 -7
- package/lib-commonjs/components/Tab/useTabStyles.styles.raw.cjs.map +1 -1
- package/lib-commonjs/components/Tab/useTabStyles.styles.raw.css.cjs +82 -0
- package/lib-commonjs/components/Tab/useTabStyles.styles.raw.css.cjs.map +1 -0
- package/lib-commonjs/components/TabList/TabList.cjs.map +1 -1
- package/lib-commonjs/components/TabList/TabList.module.css +27 -0
- package/lib-commonjs/components/TabList/TabList.types.cjs.map +1 -1
- package/lib-commonjs/components/TabList/TabListContext.cjs +4 -4
- package/lib-commonjs/components/TabList/TabListContext.cjs.map +1 -1
- package/lib-commonjs/components/TabList/index.cjs +12 -12
- package/lib-commonjs/components/TabList/index.cjs.map +1 -1
- package/lib-commonjs/components/TabList/renderTabList.cjs.map +1 -1
- package/lib-commonjs/components/TabList/useTabList.cjs +4 -4
- package/lib-commonjs/components/TabList/useTabList.cjs.map +1 -1
- package/lib-commonjs/components/TabList/useTabListContextValues.cjs.map +1 -1
- package/lib-commonjs/components/TabList/useTabListStyles.styles.cjs +3 -3
- package/lib-commonjs/components/TabList/useTabListStyles.styles.cjs.map +1 -1
- package/lib-commonjs/components/TabList/useTabListStyles.styles.css.cjs +29 -0
- package/lib-commonjs/components/TabList/useTabListStyles.styles.css.cjs.map +1 -0
- package/lib-commonjs/components/TabList/useTabListStyles.styles.raw.cjs +3 -3
- package/lib-commonjs/components/TabList/useTabListStyles.styles.raw.cjs.map +1 -1
- package/lib-commonjs/components/TabList/useTabListStyles.styles.raw.css.cjs +29 -0
- package/lib-commonjs/components/TabList/useTabListStyles.styles.raw.css.cjs.map +1 -0
- package/lib-commonjs/index.cjs +22 -22
- package/lib-commonjs/index.cjs.map +1 -1
- package/package.json +14 -14
- package/dist/metadata/api/api-root.json +0 -1
- package/dist/metadata/index.json +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Tab/useTab.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { type TabsterDOMAttribute, useTabsterAttributes } from '@fluentui/react-tabster';\nimport { mergeCallbacks, useEventCallback, useMergedRefs, slot, omit } from '@fluentui/react-utilities';\nimport type { TabProps, TabState, TabBaseProps, TabBaseState } from './Tab.types';\nimport { useTabListContext_unstable } from '../TabList';\nimport type { SelectTabEvent } from '../TabList';\n\n/**\n * Create the state required to render Tab.\n *\n * The returned state can be modified with hooks such as useTabStyles_unstable,\n * before being passed to renderTab_unstable.\n *\n * @param props - props from this instance of Tab\n * @param ref - reference to root HTMLElement of Tab\n */\nexport const useTab_unstable = (props: TabProps, ref: React.Ref<HTMLElement>): TabState => {\n const { content } = props;\n\n const state = useTabBase_unstable(props, ref);\n const focusAttributes = useTabA11yBehavior_unstable(state);\n\n const appearance = useTabListContext_unstable(ctx => ctx.appearance);\n const reserveSelectedTabSpace = useTabListContext_unstable(ctx => ctx.reserveSelectedTabSpace);\n const size = useTabListContext_unstable(ctx => ctx.size ?? 'medium');\n\n const contentReservedSpace: typeof content =\n content && typeof content === 'object' ? omit(content, ['ref' as keyof typeof content]) : content;\n\n return {\n ...state,\n // eslint-disable-next-line @typescript-eslint/no-deprecated\n components: { ...state.components, contentReservedSpace: 'span' },\n root: {\n ...focusAttributes,\n ...state.root,\n },\n contentReservedSpace: slot.optional(contentReservedSpace, {\n renderByDefault: !state.selected && !state.iconOnly && reserveSelectedTabSpace,\n defaultProps: { children: props.children },\n elementType: 'span',\n }),\n appearance,\n size,\n };\n};\n\n/**\n * Create the based state required to render Tab without design specifics and focus attributes.\n *\n * @param props - props from this instance of Tab\n * @param ref - reference to root HTMLElement of Tab\n */\nexport const useTabBase_unstable = (props: TabBaseProps, ref: React.Ref<HTMLElement>): TabBaseState => {\n const { content, disabled: tabDisabled = false, icon, onClick, onFocus, value, ...rest } = props;\n\n const selectTabOnFocus = useTabListContext_unstable(ctx => ctx.selectTabOnFocus);\n const listDisabled = useTabListContext_unstable(ctx => ctx.disabled);\n const selected = useTabListContext_unstable(ctx => ctx.selectedValue === value);\n const onRegister = useTabListContext_unstable(ctx => ctx.onRegister);\n const onUnregister = useTabListContext_unstable(ctx => ctx.onUnregister);\n const onSelect = useTabListContext_unstable(ctx => ctx.onSelect);\n const vertical = useTabListContext_unstable(ctx => !!ctx.vertical);\n const disabled = listDisabled || tabDisabled;\n\n const innerRef = React.useRef<HTMLElement>(null);\n const onSelectCallback = (event: SelectTabEvent) => onSelect(event, { value });\n const onTabClick = useEventCallback(mergeCallbacks(onClick, onSelectCallback));\n const onTabFocus = useEventCallback(mergeCallbacks(onFocus, onSelectCallback));\n\n React.useEffect(() => {\n onRegister({\n value,\n ref: innerRef,\n });\n\n return () => {\n onUnregister({ value, ref: innerRef });\n };\n }, [onRegister, onUnregister, innerRef, value]);\n\n const iconSlot = slot.optional(icon, { elementType: 'span' });\n const contentSlot = slot.always(content, {\n defaultProps: { children: props.children },\n elementType: 'span',\n });\n const iconOnly = Boolean(iconSlot?.children && !contentSlot.children);\n return {\n components: { root: 'button', icon: 'span', content: 'span', contentReservedSpace: 'span' },\n root: slot.always(\n {\n ref: useMergedRefs(ref, innerRef),\n role: 'tab',\n type: 'button',\n // aria-selected undefined indicates it is not selectable\n // according to https://www.w3.org/TR/wai-aria-1.1/#aria-selected\n 'aria-selected': disabled ? undefined : (`${selected}` as 'true' | 'false'),\n value,\n ...rest,\n disabled,\n onClick: onTabClick,\n onFocus: selectTabOnFocus ? onTabFocus : onFocus,\n },\n { elementType: 'button' },\n ) as TabBaseState['root'],\n icon: iconSlot,\n iconOnly,\n content: contentSlot,\n disabled,\n selected,\n value,\n vertical,\n };\n};\n\n/**\n * Hook to return a11y attributes to a Tab based on selected state.\n * Should be applied on the button with role=\"tab\".\n *\n * @param selected - whether the Tab is selected\n * @returns Tabster DOM attributes\n */\nexport const useTabA11yBehavior_unstable = ({ selected }: Pick<TabBaseState, 'selected'>): TabsterDOMAttribute => {\n return useTabsterAttributes({\n focusable: { isDefault: selected },\n });\n};\n"],"names":["React","useTabsterAttributes","mergeCallbacks","useEventCallback","useMergedRefs","slot","omit","useTabListContext_unstable","useTab_unstable","props","ref","content","state","useTabBase_unstable","focusAttributes","useTabA11yBehavior_unstable","appearance","ctx","reserveSelectedTabSpace","size","contentReservedSpace","components","root","optional","renderByDefault","selected","iconOnly","defaultProps","children","elementType","disabled","tabDisabled","icon","onClick","onFocus","value","rest","selectTabOnFocus","listDisabled","selectedValue","onRegister","onUnregister","onSelect","vertical","innerRef","useRef","onSelectCallback","event","onTabClick","onTabFocus","useEffect","iconSlot","contentSlot","always","Boolean","role","type","undefined","focusable","isDefault"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAC/B,SAAmCC,oBAAoB,QAAQ,0BAA0B;AACzF,SAASC,cAAc,EAAEC,gBAAgB,EAAEC,aAAa,EAAEC,IAAI,EAAEC,IAAI,QAAQ,4BAA4B;AAExG,SAASC,0BAA0B,QAAQ,sBAAa;AAGxD;;;;;;;;CAQC,GACD,OAAO,MAAMC,kBAAkB,CAACC,OAAiBC;IAC/C,MAAM,EAAEC,OAAO,EAAE,GAAGF;IAEpB,MAAMG,QAAQC,oBAAoBJ,OAAOC;IACzC,MAAMI,kBAAkBC,4BAA4BH;IAEpD,MAAMI,aAAaT,2BAA2BU,CAAAA,MAAOA,IAAID,UAAU;IACnE,MAAME,0BAA0BX,2BAA2BU,CAAAA,MAAOA,IAAIC,uBAAuB;IAC7F,MAAMC,OAAOZ,2BAA2BU,CAAAA;YAAOA;gBAAAA,YAAAA,IAAIE,IAAI,cAARF,uBAAAA,YAAY;;IAE3D,MAAMG,uBACJT,WAAW,OAAOA,YAAY,WAAWL,KAAKK,SAAS;QAAC;KAA8B,IAAIA;IAE5F,OAAO;QACL,GAAGC,KAAK;QACR,4DAA4D;QAC5DS,YAAY;YAAE,GAAGT,MAAMS,UAAU;YAAED,sBAAsB;QAAO;QAChEE,MAAM;YACJ,GAAGR,eAAe;YAClB,GAAGF,MAAMU,IAAI;QACf;QACAF,sBAAsBf,KAAKkB,QAAQ,CAACH,sBAAsB;YACxDI,iBAAiB,CAACZ,MAAMa,QAAQ,IAAI,CAACb,MAAMc,QAAQ,IAAIR;YACvDS,cAAc;gBAAEC,UAAUnB,MAAMmB,QAAQ;YAAC;YACzCC,aAAa;QACf;QACAb;QACAG;IACF;AACF,EAAE;AAEF;;;;;CAKC,GACD,OAAO,MAAMN,sBAAsB,CAACJ,OAAqBC;IACvD,MAAM,EAAEC,OAAO,EAAEmB,UAAUC,cAAc,KAAK,EAAEC,IAAI,EAAEC,OAAO,EAAEC,OAAO,EAAEC,KAAK,EAAE,GAAGC,MAAM,GAAG3B;IAE3F,MAAM4B,mBAAmB9B,2BAA2BU,CAAAA,MAAOA,IAAIoB,gBAAgB;IAC/E,MAAMC,eAAe/B,2BAA2BU,CAAAA,MAAOA,IAAIa,QAAQ;IACnE,MAAML,WAAWlB,2BAA2BU,CAAAA,MAAOA,IAAIsB,aAAa,KAAKJ;IACzE,MAAMK,aAAajC,2BAA2BU,CAAAA,MAAOA,IAAIuB,UAAU;IACnE,MAAMC,eAAelC,2BAA2BU,CAAAA,MAAOA,IAAIwB,YAAY;IACvE,MAAMC,WAAWnC,2BAA2BU,CAAAA,MAAOA,IAAIyB,QAAQ;IAC/D,MAAMC,WAAWpC,2BAA2BU,CAAAA,MAAO,CAAC,CAACA,IAAI0B,QAAQ;IACjE,MAAMb,WAAWQ,gBAAgBP;IAEjC,MAAMa,WAAW5C,MAAM6C,MAAM,CAAc;IAC3C,MAAMC,mBAAmB,CAACC,QAA0BL,SAASK,OAAO;YAAEZ;QAAM;IAC5E,MAAMa,aAAa7C,iBAAiBD,eAAe+B,SAASa;IAC5D,MAAMG,aAAa9C,iBAAiBD,eAAegC,SAASY;IAE5D9C,MAAMkD,SAAS,CAAC;QACdV,WAAW;YACTL;YACAzB,KAAKkC;QACP;QAEA,OAAO;YACLH,aAAa;gBAAEN;gBAAOzB,KAAKkC;YAAS;QACtC;IACF,GAAG;QAACJ;QAAYC;QAAcG;QAAUT;KAAM;IAE9C,MAAMgB,WAAW9C,KAAKkB,QAAQ,CAACS,MAAM;QAAEH,aAAa;IAAO;IAC3D,MAAMuB,cAAc/C,KAAKgD,MAAM,CAAC1C,SAAS;QACvCgB,cAAc;YAAEC,UAAUnB,MAAMmB,QAAQ;QAAC;QACzCC,aAAa;IACf;IACA,MAAMH,WAAW4B,QAAQH,CAAAA,qBAAAA,+BAAAA,SAAUvB,QAAQ,KAAI,CAACwB,YAAYxB,QAAQ;IACpE,OAAO;QACLP,YAAY;YAAEC,MAAM;YAAUU,MAAM;YAAQrB,SAAS;YAAQS,sBAAsB;QAAO;QAC1FE,MAAMjB,KAAKgD,MAAM,CACf;YACE3C,KAAKN,cAAcM,KAAKkC;YACxBW,MAAM;YACNC,MAAM;YACN,yDAAyD;YACzD,iEAAiE;YACjE,iBAAiB1B,WAAW2B,YAAa,GAAGhC,UAAU;YACtDU;YACA,GAAGC,IAAI;YACPN;YACAG,SAASe;YACTd,SAASG,mBAAmBY,aAAaf;QAC3C,GACA;YAAEL,aAAa;QAAS;QAE1BG,MAAMmB;QACNzB;QACAf,SAASyC;QACTtB;QACAL;QACAU;QACAQ;IACF;AACF,EAAE;AAEF;;;;;;CAMC,GACD,OAAO,MAAM5B,8BAA8B,CAAC,EAAEU,QAAQ,EAAkC;IACtF,OAAOxB,qBAAqB;QAC1ByD,WAAW;YAAEC,WAAWlC;QAAS;IACnC;AACF,EAAE"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import styles from "./TabAnimatedIndicator.module.css";
|
|
5
|
+
import { useTabListContext_unstable } from "../TabList/TabListContext.js";
|
|
6
|
+
import { useAnimationFrame } from "@fluentui/react-utilities";
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
8
|
+
const tabIndicatorCssVars_unstable = {
|
|
9
|
+
offsetVar: '--fui-Tab__indicator--offset',
|
|
10
|
+
scaleVar: '--fui-Tab__indicator--scale'
|
|
11
|
+
};
|
|
12
|
+
const calculateTabRect = (element)=>{
|
|
13
|
+
if (element) {
|
|
14
|
+
var _element_parentElement;
|
|
15
|
+
const parentRect = ((_element_parentElement = element.parentElement) === null || _element_parentElement === void 0 ? void 0 : _element_parentElement.getBoundingClientRect()) || {
|
|
16
|
+
x: 0,
|
|
17
|
+
y: 0,
|
|
18
|
+
width: 0,
|
|
19
|
+
height: 0
|
|
20
|
+
};
|
|
21
|
+
const tabRect = element.getBoundingClientRect();
|
|
22
|
+
return {
|
|
23
|
+
x: tabRect.x - parentRect.x,
|
|
24
|
+
y: tabRect.y - parentRect.y,
|
|
25
|
+
width: tabRect.width,
|
|
26
|
+
height: tabRect.height
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
};
|
|
31
|
+
const getRegisteredTabRect = (registeredTabs, value)=>{
|
|
32
|
+
var _registeredTabs_JSON_stringify;
|
|
33
|
+
const element = isValueDefined(value) ? (_registeredTabs_JSON_stringify = registeredTabs[JSON.stringify(value)]) === null || _registeredTabs_JSON_stringify === void 0 ? void 0 : _registeredTabs_JSON_stringify.ref.current : undefined;
|
|
34
|
+
return element ? calculateTabRect(element) : undefined;
|
|
35
|
+
};
|
|
36
|
+
// eslint-disable-next-line eqeqeq
|
|
37
|
+
const isValueDefined = (value)=>value != null;
|
|
38
|
+
/**
|
|
39
|
+
* Adds additional styling to the active tab selection indicator to create a sliding animation.
|
|
40
|
+
*/ export const useTabAnimatedIndicatorStyles_unstable = (state)=>{
|
|
41
|
+
const { disabled, selected, vertical } = state;
|
|
42
|
+
const [lastAnimatedFrom, setLastAnimatedFrom] = React.useState();
|
|
43
|
+
const [animationValues, setAnimationValues] = React.useState({
|
|
44
|
+
offset: 0,
|
|
45
|
+
scale: 1
|
|
46
|
+
});
|
|
47
|
+
const getRegisteredTabs = useTabListContext_unstable((ctx)=>ctx.getRegisteredTabs);
|
|
48
|
+
const [requestAnimationFrame] = useAnimationFrame();
|
|
49
|
+
if (selected) {
|
|
50
|
+
const { previousSelectedValue, selectedValue, registeredTabs } = getRegisteredTabs();
|
|
51
|
+
if (isValueDefined(previousSelectedValue) && lastAnimatedFrom !== previousSelectedValue) {
|
|
52
|
+
const previousSelectedTabRect = getRegisteredTabRect(registeredTabs, previousSelectedValue);
|
|
53
|
+
const selectedTabRect = getRegisteredTabRect(registeredTabs, selectedValue);
|
|
54
|
+
if (selectedTabRect && previousSelectedTabRect) {
|
|
55
|
+
const offset = vertical ? previousSelectedTabRect.y - selectedTabRect.y : previousSelectedTabRect.x - selectedTabRect.x;
|
|
56
|
+
const scale = vertical ? previousSelectedTabRect.height / selectedTabRect.height : previousSelectedTabRect.width / selectedTabRect.width;
|
|
57
|
+
setAnimationValues({
|
|
58
|
+
offset,
|
|
59
|
+
scale
|
|
60
|
+
});
|
|
61
|
+
setLastAnimatedFrom(previousSelectedValue);
|
|
62
|
+
// Reset the animation values after the animation is complete
|
|
63
|
+
requestAnimationFrame(()=>setAnimationValues({
|
|
64
|
+
offset: 0,
|
|
65
|
+
scale: 1
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} else if (isValueDefined(lastAnimatedFrom)) {
|
|
70
|
+
// need to clear the last animated from so that if this tab is selected again
|
|
71
|
+
// from the same previous tab as last time, that animation still happens.
|
|
72
|
+
setLastAnimatedFrom(undefined);
|
|
73
|
+
}
|
|
74
|
+
// do not apply any animation if the tab is disabled
|
|
75
|
+
if (disabled) {
|
|
76
|
+
return state;
|
|
77
|
+
}
|
|
78
|
+
// the animation should only happen as the selection indicator returns to its
|
|
79
|
+
// original position and not when set at the previous tabs position.
|
|
80
|
+
const animating = animationValues.offset === 0 && animationValues.scale === 1;
|
|
81
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
82
|
+
state.root.className = clsx(selected && styles.base, selected && animating && styles.animated, selected && styles[vertical ? 'vertical' : 'horizontal'], state.root.className);
|
|
83
|
+
const rootCssVars = {
|
|
84
|
+
[tabIndicatorCssVars_unstable.offsetVar]: `${animationValues.offset}px`,
|
|
85
|
+
[tabIndicatorCssVars_unstable.scaleVar]: `${animationValues.scale}`
|
|
86
|
+
};
|
|
87
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
88
|
+
state.root.style = {
|
|
89
|
+
...rootCssVars,
|
|
90
|
+
...state.root.style
|
|
91
|
+
};
|
|
92
|
+
return state;
|
|
93
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Tab/useTabAnimatedIndicator.styles.css.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { TabState, TabValue } from './Tab.types';\n\nimport { clsx } from 'clsx';\nimport styles from './TabAnimatedIndicator.module.css';\nimport { useTabListContext_unstable } from '../TabList/TabListContext';\nimport type { TabRegisterData } from '../TabList/TabList.types';\nimport { useAnimationFrame } from '@fluentui/react-utilities';\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst tabIndicatorCssVars_unstable = {\n offsetVar: '--fui-Tab__indicator--offset',\n scaleVar: '--fui-Tab__indicator--scale',\n};\n\nconst calculateTabRect = (element: HTMLElement) => {\n if (element) {\n const parentRect = element.parentElement?.getBoundingClientRect() || { x: 0, y: 0, width: 0, height: 0 };\n const tabRect = element.getBoundingClientRect();\n\n return {\n x: tabRect.x - parentRect.x,\n y: tabRect.y - parentRect.y,\n width: tabRect.width,\n height: tabRect.height,\n };\n }\n return undefined;\n};\n\nconst getRegisteredTabRect = (registeredTabs: Record<string, TabRegisterData>, value?: TabValue) => {\n const element = isValueDefined(value) ? registeredTabs[JSON.stringify(value)]?.ref.current : undefined;\n return element ? calculateTabRect(element) : undefined;\n};\n\n// eslint-disable-next-line eqeqeq\nconst isValueDefined = (value: TabValue) => value != null;\n\n/**\n * Adds additional styling to the active tab selection indicator to create a sliding animation.\n */\nexport const useTabAnimatedIndicatorStyles_unstable = (state: TabState): TabState => {\n const { disabled, selected, vertical } = state;\n\n const [lastAnimatedFrom, setLastAnimatedFrom] = React.useState<TabValue>();\n const [animationValues, setAnimationValues] = React.useState({ offset: 0, scale: 1 });\n const getRegisteredTabs = useTabListContext_unstable(ctx => ctx.getRegisteredTabs);\n\n const [requestAnimationFrame] = useAnimationFrame();\n\n if (selected) {\n const { previousSelectedValue, selectedValue, registeredTabs } = getRegisteredTabs();\n\n if (isValueDefined(previousSelectedValue) && lastAnimatedFrom !== previousSelectedValue) {\n const previousSelectedTabRect = getRegisteredTabRect(registeredTabs, previousSelectedValue);\n const selectedTabRect = getRegisteredTabRect(registeredTabs, selectedValue);\n\n if (selectedTabRect && previousSelectedTabRect) {\n const offset = vertical\n ? previousSelectedTabRect.y - selectedTabRect.y\n : previousSelectedTabRect.x - selectedTabRect.x;\n\n const scale = vertical\n ? previousSelectedTabRect.height / selectedTabRect.height\n : previousSelectedTabRect.width / selectedTabRect.width;\n\n setAnimationValues({ offset, scale });\n setLastAnimatedFrom(previousSelectedValue);\n\n // Reset the animation values after the animation is complete\n requestAnimationFrame(() => setAnimationValues({ offset: 0, scale: 1 }));\n }\n }\n } else if (isValueDefined(lastAnimatedFrom)) {\n // need to clear the last animated from so that if this tab is selected again\n // from the same previous tab as last time, that animation still happens.\n setLastAnimatedFrom(undefined);\n }\n\n // do not apply any animation if the tab is disabled\n if (disabled) {\n return state;\n }\n\n // the animation should only happen as the selection indicator returns to its\n // original position and not when set at the previous tabs position.\n const animating = animationValues.offset === 0 && animationValues.scale === 1;\n\n // eslint-disable-next-line react-hooks/immutability\n state.root.className = clsx(\n selected && styles.base,\n selected && animating && styles.animated,\n selected && styles[vertical ? 'vertical' : 'horizontal'],\n state.root.className,\n );\n\n const rootCssVars = {\n [tabIndicatorCssVars_unstable.offsetVar]: `${animationValues.offset}px`,\n [tabIndicatorCssVars_unstable.scaleVar]: `${animationValues.scale}`,\n };\n\n // eslint-disable-next-line react-hooks/immutability\n state.root.style = {\n ...rootCssVars,\n ...state.root.style,\n };\n\n return state;\n};\n"],"names":["React","clsx","styles","useTabListContext_unstable","useAnimationFrame","tabIndicatorCssVars_unstable","offsetVar","scaleVar","calculateTabRect","element","parentRect","parentElement","getBoundingClientRect","x","y","width","height","tabRect","undefined","getRegisteredTabRect","registeredTabs","value","isValueDefined","JSON","stringify","ref","current","useTabAnimatedIndicatorStyles_unstable","state","disabled","selected","vertical","lastAnimatedFrom","setLastAnimatedFrom","useState","animationValues","setAnimationValues","offset","scale","getRegisteredTabs","ctx","requestAnimationFrame","previousSelectedValue","selectedValue","previousSelectedTabRect","selectedTabRect","animating","root","className","base","animated","rootCssVars","style"],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { clsx } from "clsx";
|
|
4
|
+
import styles from "./TabAnimatedIndicator.module.css";
|
|
5
|
+
import { useTabListContext_unstable } from "../TabList/TabListContext.js";
|
|
6
|
+
import { useAnimationFrame } from "@fluentui/react-utilities";
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
8
|
+
const tabIndicatorCssVars_unstable = {
|
|
9
|
+
offsetVar: '--fui-Tab__indicator--offset',
|
|
10
|
+
scaleVar: '--fui-Tab__indicator--scale'
|
|
11
|
+
};
|
|
12
|
+
const calculateTabRect = (element)=>{
|
|
13
|
+
if (element) {
|
|
14
|
+
var _element_parentElement;
|
|
15
|
+
const parentRect = ((_element_parentElement = element.parentElement) === null || _element_parentElement === void 0 ? void 0 : _element_parentElement.getBoundingClientRect()) || {
|
|
16
|
+
x: 0,
|
|
17
|
+
y: 0,
|
|
18
|
+
width: 0,
|
|
19
|
+
height: 0
|
|
20
|
+
};
|
|
21
|
+
const tabRect = element.getBoundingClientRect();
|
|
22
|
+
return {
|
|
23
|
+
x: tabRect.x - parentRect.x,
|
|
24
|
+
y: tabRect.y - parentRect.y,
|
|
25
|
+
width: tabRect.width,
|
|
26
|
+
height: tabRect.height
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return undefined;
|
|
30
|
+
};
|
|
31
|
+
const getRegisteredTabRect = (registeredTabs, value)=>{
|
|
32
|
+
var _registeredTabs_JSON_stringify;
|
|
33
|
+
const element = isValueDefined(value) ? (_registeredTabs_JSON_stringify = registeredTabs[JSON.stringify(value)]) === null || _registeredTabs_JSON_stringify === void 0 ? void 0 : _registeredTabs_JSON_stringify.ref.current : undefined;
|
|
34
|
+
return element ? calculateTabRect(element) : undefined;
|
|
35
|
+
};
|
|
36
|
+
// eslint-disable-next-line eqeqeq
|
|
37
|
+
const isValueDefined = (value)=>value != null;
|
|
38
|
+
/**
|
|
39
|
+
* Adds additional styling to the active tab selection indicator to create a sliding animation.
|
|
40
|
+
*/ export const useTabAnimatedIndicatorStyles_unstable = (state)=>{
|
|
41
|
+
const { disabled, selected, vertical } = state;
|
|
42
|
+
const [lastAnimatedFrom, setLastAnimatedFrom] = React.useState();
|
|
43
|
+
const [animationValues, setAnimationValues] = React.useState({
|
|
44
|
+
offset: 0,
|
|
45
|
+
scale: 1
|
|
46
|
+
});
|
|
47
|
+
const getRegisteredTabs = useTabListContext_unstable((ctx)=>ctx.getRegisteredTabs);
|
|
48
|
+
const [requestAnimationFrame] = useAnimationFrame();
|
|
49
|
+
if (selected) {
|
|
50
|
+
const { previousSelectedValue, selectedValue, registeredTabs } = getRegisteredTabs();
|
|
51
|
+
if (isValueDefined(previousSelectedValue) && lastAnimatedFrom !== previousSelectedValue) {
|
|
52
|
+
const previousSelectedTabRect = getRegisteredTabRect(registeredTabs, previousSelectedValue);
|
|
53
|
+
const selectedTabRect = getRegisteredTabRect(registeredTabs, selectedValue);
|
|
54
|
+
if (selectedTabRect && previousSelectedTabRect) {
|
|
55
|
+
const offset = vertical ? previousSelectedTabRect.y - selectedTabRect.y : previousSelectedTabRect.x - selectedTabRect.x;
|
|
56
|
+
const scale = vertical ? previousSelectedTabRect.height / selectedTabRect.height : previousSelectedTabRect.width / selectedTabRect.width;
|
|
57
|
+
setAnimationValues({
|
|
58
|
+
offset,
|
|
59
|
+
scale
|
|
60
|
+
});
|
|
61
|
+
setLastAnimatedFrom(previousSelectedValue);
|
|
62
|
+
// Reset the animation values after the animation is complete
|
|
63
|
+
requestAnimationFrame(()=>setAnimationValues({
|
|
64
|
+
offset: 0,
|
|
65
|
+
scale: 1
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} else if (isValueDefined(lastAnimatedFrom)) {
|
|
70
|
+
// need to clear the last animated from so that if this tab is selected again
|
|
71
|
+
// from the same previous tab as last time, that animation still happens.
|
|
72
|
+
setLastAnimatedFrom(undefined);
|
|
73
|
+
}
|
|
74
|
+
// do not apply any animation if the tab is disabled
|
|
75
|
+
if (disabled) {
|
|
76
|
+
return state;
|
|
77
|
+
}
|
|
78
|
+
// the animation should only happen as the selection indicator returns to its
|
|
79
|
+
// original position and not when set at the previous tabs position.
|
|
80
|
+
const animating = animationValues.offset === 0 && animationValues.scale === 1;
|
|
81
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
82
|
+
state.root.className = clsx(selected && styles.base, selected && animating && styles.animated, selected && styles[vertical ? 'vertical' : 'horizontal'], state.root.className);
|
|
83
|
+
const rootCssVars = {
|
|
84
|
+
[tabIndicatorCssVars_unstable.offsetVar]: `${animationValues.offset}px`,
|
|
85
|
+
[tabIndicatorCssVars_unstable.scaleVar]: `${animationValues.scale}`
|
|
86
|
+
};
|
|
87
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
88
|
+
state.root.style = {
|
|
89
|
+
...rootCssVars,
|
|
90
|
+
...state.root.style
|
|
91
|
+
};
|
|
92
|
+
return state;
|
|
93
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Tab/useTabAnimatedIndicator.styles.css.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { TabState, TabValue } from './Tab.types';\n\nimport { clsx } from 'clsx';\nimport styles from './TabAnimatedIndicator.module.css';\nimport { useTabListContext_unstable } from '../TabList/TabListContext';\nimport type { TabRegisterData } from '../TabList/TabList.types';\nimport { useAnimationFrame } from '@fluentui/react-utilities';\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst tabIndicatorCssVars_unstable = {\n offsetVar: '--fui-Tab__indicator--offset',\n scaleVar: '--fui-Tab__indicator--scale',\n};\n\nconst calculateTabRect = (element: HTMLElement) => {\n if (element) {\n const parentRect = element.parentElement?.getBoundingClientRect() || { x: 0, y: 0, width: 0, height: 0 };\n const tabRect = element.getBoundingClientRect();\n\n return {\n x: tabRect.x - parentRect.x,\n y: tabRect.y - parentRect.y,\n width: tabRect.width,\n height: tabRect.height,\n };\n }\n return undefined;\n};\n\nconst getRegisteredTabRect = (registeredTabs: Record<string, TabRegisterData>, value?: TabValue) => {\n const element = isValueDefined(value) ? registeredTabs[JSON.stringify(value)]?.ref.current : undefined;\n return element ? calculateTabRect(element) : undefined;\n};\n\n// eslint-disable-next-line eqeqeq\nconst isValueDefined = (value: TabValue) => value != null;\n\n/**\n * Adds additional styling to the active tab selection indicator to create a sliding animation.\n */\nexport const useTabAnimatedIndicatorStyles_unstable = (state: TabState): TabState => {\n const { disabled, selected, vertical } = state;\n\n const [lastAnimatedFrom, setLastAnimatedFrom] = React.useState<TabValue>();\n const [animationValues, setAnimationValues] = React.useState({ offset: 0, scale: 1 });\n const getRegisteredTabs = useTabListContext_unstable(ctx => ctx.getRegisteredTabs);\n\n const [requestAnimationFrame] = useAnimationFrame();\n\n if (selected) {\n const { previousSelectedValue, selectedValue, registeredTabs } = getRegisteredTabs();\n\n if (isValueDefined(previousSelectedValue) && lastAnimatedFrom !== previousSelectedValue) {\n const previousSelectedTabRect = getRegisteredTabRect(registeredTabs, previousSelectedValue);\n const selectedTabRect = getRegisteredTabRect(registeredTabs, selectedValue);\n\n if (selectedTabRect && previousSelectedTabRect) {\n const offset = vertical\n ? previousSelectedTabRect.y - selectedTabRect.y\n : previousSelectedTabRect.x - selectedTabRect.x;\n\n const scale = vertical\n ? previousSelectedTabRect.height / selectedTabRect.height\n : previousSelectedTabRect.width / selectedTabRect.width;\n\n setAnimationValues({ offset, scale });\n setLastAnimatedFrom(previousSelectedValue);\n\n // Reset the animation values after the animation is complete\n requestAnimationFrame(() => setAnimationValues({ offset: 0, scale: 1 }));\n }\n }\n } else if (isValueDefined(lastAnimatedFrom)) {\n // need to clear the last animated from so that if this tab is selected again\n // from the same previous tab as last time, that animation still happens.\n setLastAnimatedFrom(undefined);\n }\n\n // do not apply any animation if the tab is disabled\n if (disabled) {\n return state;\n }\n\n // the animation should only happen as the selection indicator returns to its\n // original position and not when set at the previous tabs position.\n const animating = animationValues.offset === 0 && animationValues.scale === 1;\n\n // eslint-disable-next-line react-hooks/immutability\n state.root.className = clsx(\n selected && styles.base,\n selected && animating && styles.animated,\n selected && styles[vertical ? 'vertical' : 'horizontal'],\n state.root.className,\n );\n\n const rootCssVars = {\n [tabIndicatorCssVars_unstable.offsetVar]: `${animationValues.offset}px`,\n [tabIndicatorCssVars_unstable.scaleVar]: `${animationValues.scale}`,\n };\n\n // eslint-disable-next-line react-hooks/immutability\n state.root.style = {\n ...rootCssVars,\n ...state.root.style,\n };\n\n return state;\n};\n"],"names":["React","clsx","styles","useTabListContext_unstable","useAnimationFrame","tabIndicatorCssVars_unstable","offsetVar","scaleVar","calculateTabRect","element","parentRect","parentElement","getBoundingClientRect","x","y","width","height","tabRect","undefined","getRegisteredTabRect","registeredTabs","value","isValueDefined","JSON","stringify","ref","current","useTabAnimatedIndicatorStyles_unstable","state","disabled","selected","vertical","lastAnimatedFrom","setLastAnimatedFrom","useState","animationValues","setAnimationValues","offset","scale","getRegisteredTabs","ctx","requestAnimationFrame","previousSelectedValue","selectedValue","previousSelectedTabRect","selectedTabRect","animating","root","className","base","animated","rootCssVars","style"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Tab/useTabAnimatedIndicator.styles.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { TabState, TabValue } from './Tab.types';\n\nimport { makeStyles, mergeClasses } from '@griffel/react';\nimport { useTabListContext_unstable } from '../TabList/TabListContext';\nimport type { TabRegisterData } from '../TabList/TabList.types';\nimport { tokens } from '@fluentui/react-theme';\nimport { useAnimationFrame } from '@fluentui/react-utilities';\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst tabIndicatorCssVars_unstable = {\n offsetVar: '--fui-Tab__indicator--offset',\n scaleVar: '--fui-Tab__indicator--scale',\n};\n\nconst useActiveIndicatorStyles = makeStyles({\n base: {\n // overflow is required to allow the selection indicator to animate outside the tab area.\n overflow: 'visible',\n },\n animated: {\n '::after': {\n transitionProperty: 'transform',\n transitionDuration: `${tokens.durationSlow}`,\n transitionTimingFunction: `${tokens.curveDecelerateMax}`,\n },\n '@media (prefers-reduced-motion: reduce)': {\n '::after': {\n transitionProperty: 'none',\n transitionDuration: '0.01ms',\n },\n },\n },\n horizontal: {\n '::after': {\n transformOrigin: 'left',\n transform: `translateX(var(${tabIndicatorCssVars_unstable.offsetVar}))\n scaleX(var(${tabIndicatorCssVars_unstable.scaleVar}))`,\n },\n },\n vertical: {\n '::after': {\n transformOrigin: 'top',\n transform: `translateY(var(${tabIndicatorCssVars_unstable.offsetVar}))\n scaleY(var(${tabIndicatorCssVars_unstable.scaleVar}))`,\n },\n },\n});\n\nconst calculateTabRect = (element: HTMLElement) => {\n if (element) {\n const parentRect = element.parentElement?.getBoundingClientRect() || { x: 0, y: 0, width: 0, height: 0 };\n const tabRect = element.getBoundingClientRect();\n\n return {\n x: tabRect.x - parentRect.x,\n y: tabRect.y - parentRect.y,\n width: tabRect.width,\n height: tabRect.height,\n };\n }\n return undefined;\n};\n\nconst getRegisteredTabRect = (registeredTabs: Record<string, TabRegisterData>, value?: TabValue) => {\n const element = isValueDefined(value) ? registeredTabs[JSON.stringify(value)]?.ref.current : undefined;\n return element ? calculateTabRect(element) : undefined;\n};\n\n// eslint-disable-next-line eqeqeq\nconst isValueDefined = (value: TabValue) => value != null;\n\n/**\n * Adds additional styling to the active tab selection indicator to create a sliding animation.\n */\nexport const useTabAnimatedIndicatorStyles_unstable = (state: TabState): TabState => {\n const { disabled, selected, vertical } = state;\n\n const activeIndicatorStyles = useActiveIndicatorStyles();\n const [lastAnimatedFrom, setLastAnimatedFrom] = React.useState<TabValue>();\n const [animationValues, setAnimationValues] = React.useState({ offset: 0, scale: 1 });\n const getRegisteredTabs = useTabListContext_unstable(ctx => ctx.getRegisteredTabs);\n\n const [requestAnimationFrame] = useAnimationFrame();\n\n if (selected) {\n const { previousSelectedValue, selectedValue, registeredTabs } = getRegisteredTabs();\n\n if (isValueDefined(previousSelectedValue) && lastAnimatedFrom !== previousSelectedValue) {\n const previousSelectedTabRect = getRegisteredTabRect(registeredTabs, previousSelectedValue);\n const selectedTabRect = getRegisteredTabRect(registeredTabs, selectedValue);\n\n if (selectedTabRect && previousSelectedTabRect) {\n const offset = vertical\n ? previousSelectedTabRect.y - selectedTabRect.y\n : previousSelectedTabRect.x - selectedTabRect.x;\n\n const scale = vertical\n ? previousSelectedTabRect.height / selectedTabRect.height\n : previousSelectedTabRect.width / selectedTabRect.width;\n\n setAnimationValues({ offset, scale });\n setLastAnimatedFrom(previousSelectedValue);\n\n // Reset the animation values after the animation is complete\n requestAnimationFrame(() => setAnimationValues({ offset: 0, scale: 1 }));\n }\n }\n } else if (isValueDefined(lastAnimatedFrom)) {\n // need to clear the last animated from so that if this tab is selected again\n // from the same previous tab as last time, that animation still happens.\n setLastAnimatedFrom(undefined);\n }\n\n // do not apply any animation if the tab is disabled\n if (disabled) {\n return state;\n }\n\n // the animation should only happen as the selection indicator returns to its\n // original position and not when set at the previous tabs position.\n const animating = animationValues.offset === 0 && animationValues.scale === 1;\n\n // eslint-disable-next-line react-hooks/immutability\n state.root.className = mergeClasses(\n state.root.className,\n selected && activeIndicatorStyles.base,\n selected && animating && activeIndicatorStyles.animated,\n selected && (vertical ? activeIndicatorStyles.vertical : activeIndicatorStyles.horizontal),\n );\n\n const rootCssVars = {\n [tabIndicatorCssVars_unstable.offsetVar]: `${animationValues.offset}px`,\n [tabIndicatorCssVars_unstable.scaleVar]: `${animationValues.scale}`,\n };\n\n // eslint-disable-next-line react-hooks/immutability\n state.root.style = {\n ...rootCssVars,\n ...state.root.style,\n };\n\n return state;\n};\n"],"names":["React","makeStyles","mergeClasses","useTabListContext_unstable","tokens","useAnimationFrame","tabIndicatorCssVars_unstable","offsetVar","scaleVar","useActiveIndicatorStyles","base","overflow","animated","transitionProperty","transitionDuration","durationSlow","transitionTimingFunction","curveDecelerateMax","horizontal","transformOrigin","transform","vertical","calculateTabRect","element","parentRect","parentElement","getBoundingClientRect","x","y","width","height","tabRect","undefined","getRegisteredTabRect","registeredTabs","value","isValueDefined","JSON","stringify","ref","current","useTabAnimatedIndicatorStyles_unstable","state","disabled","selected","activeIndicatorStyles","lastAnimatedFrom","setLastAnimatedFrom","useState","animationValues","setAnimationValues","offset","scale","getRegisteredTabs","ctx","requestAnimationFrame","previousSelectedValue","selectedValue","previousSelectedTabRect","selectedTabRect","animating","root","className","rootCssVars","style"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAG/B,SAASC,UAAU,EAAEC,YAAY,QAAQ,iBAAiB;AAC1D,SAASC,0BAA0B,QAAQ,+BAA4B;AAEvE,SAASC,MAAM,QAAQ,wBAAwB;AAC/C,SAASC,iBAAiB,QAAQ,4BAA4B;AAE9D,gEAAgE;AAChE,MAAMC,+BAA+B;IACnCC,WAAW;IACXC,UAAU;AACZ;AAEA,MAAMC,2BAA2BR,WAAW;IAC1CS,MAAM;QACJ,yFAAyF;QACzFC,UAAU;IACZ;IACAC,UAAU;QACR,WAAW;YACTC,oBAAoB;YACpBC,oBAAoB,GAAGV,OAAOW,YAAY,EAAE;YAC5CC,0BAA0B,GAAGZ,OAAOa,kBAAkB,EAAE;QAC1D;QACA,2CAA2C;YACzC,WAAW;gBACTJ,oBAAoB;gBACpBC,oBAAoB;YACtB;QACF;IACF;IACAI,YAAY;QACV,WAAW;YACTC,iBAAiB;YACjBC,WAAW,CAAC,eAAe,EAAEd,6BAA6BC,SAAS,CAAC;eAC3D,EAAED,6BAA6BE,QAAQ,CAAC,EAAE,CAAC;QACtD;IACF;IACAa,UAAU;QACR,WAAW;YACTF,iBAAiB;YACjBC,WAAW,CAAC,eAAe,EAAEd,6BAA6BC,SAAS,CAAC;mBACvD,EAAED,6BAA6BE,QAAQ,CAAC,EAAE,CAAC;QAC1D;IACF;AACF;AAEA,MAAMc,mBAAmB,CAACC;IACxB,IAAIA,SAAS;YACQA;QAAnB,MAAMC,aAAaD,EAAAA,yBAAAA,QAAQE,aAAa,cAArBF,6CAAAA,uBAAuBG,qBAAqB,OAAM;YAAEC,GAAG;YAAGC,GAAG;YAAGC,OAAO;YAAGC,QAAQ;QAAE;QACvG,MAAMC,UAAUR,QAAQG,qBAAqB;QAE7C,OAAO;YACLC,GAAGI,QAAQJ,CAAC,GAAGH,WAAWG,CAAC;YAC3BC,GAAGG,QAAQH,CAAC,GAAGJ,WAAWI,CAAC;YAC3BC,OAAOE,QAAQF,KAAK;YACpBC,QAAQC,QAAQD,MAAM;QACxB;IACF;IACA,OAAOE;AACT;AAEA,MAAMC,uBAAuB,CAACC,gBAAiDC;QACrCD;IAAxC,MAAMX,UAAUa,eAAeD,UAASD,iCAAAA,cAAc,CAACG,KAAKC,SAAS,CAACH,OAAO,cAArCD,qDAAAA,+BAAuCK,GAAG,CAACC,OAAO,GAAGR;IAC7F,OAAOT,UAAUD,iBAAiBC,WAAWS;AAC/C;AAEA,kCAAkC;AAClC,MAAMI,iBAAiB,CAACD,QAAoBA,SAAS;AAErD;;CAEC,GACD,OAAO,MAAMM,yCAAyC,CAACC;IACrD,MAAM,EAAEC,QAAQ,EAAEC,QAAQ,EAAEvB,QAAQ,EAAE,GAAGqB;IAEzC,MAAMG,wBAAwBpC;IAC9B,MAAM,CAACqC,kBAAkBC,oBAAoB,GAAG/C,MAAMgD,QAAQ;IAC9D,MAAM,CAACC,iBAAiBC,mBAAmB,GAAGlD,MAAMgD,QAAQ,CAAC;QAAEG,QAAQ;QAAGC,OAAO;IAAE;IACnF,MAAMC,oBAAoBlD,2BAA2BmD,CAAAA,MAAOA,IAAID,iBAAiB;IAEjF,MAAM,CAACE,sBAAsB,GAAGlD;IAEhC,IAAIuC,UAAU;QACZ,MAAM,EAAEY,qBAAqB,EAAEC,aAAa,EAAEvB,cAAc,EAAE,GAAGmB;QAEjE,IAAIjB,eAAeoB,0BAA0BV,qBAAqBU,uBAAuB;YACvF,MAAME,0BAA0BzB,qBAAqBC,gBAAgBsB;YACrE,MAAMG,kBAAkB1B,qBAAqBC,gBAAgBuB;YAE7D,IAAIE,mBAAmBD,yBAAyB;gBAC9C,MAAMP,SAAS9B,WACXqC,wBAAwB9B,CAAC,GAAG+B,gBAAgB/B,CAAC,GAC7C8B,wBAAwB/B,CAAC,GAAGgC,gBAAgBhC,CAAC;gBAEjD,MAAMyB,QAAQ/B,WACVqC,wBAAwB5B,MAAM,GAAG6B,gBAAgB7B,MAAM,GACvD4B,wBAAwB7B,KAAK,GAAG8B,gBAAgB9B,KAAK;gBAEzDqB,mBAAmB;oBAAEC;oBAAQC;gBAAM;gBACnCL,oBAAoBS;gBAEpB,6DAA6D;gBAC7DD,sBAAsB,IAAML,mBAAmB;wBAAEC,QAAQ;wBAAGC,OAAO;oBAAE;YACvE;QACF;IACF,OAAO,IAAIhB,eAAeU,mBAAmB;QAC3C,6EAA6E;QAC7E,yEAAyE;QACzEC,oBAAoBf;IACtB;IAEA,oDAAoD;IACpD,IAAIW,UAAU;QACZ,OAAOD;IACT;IAEA,6EAA6E;IAC7E,oEAAoE;IACpE,MAAMkB,YAAYX,gBAAgBE,MAAM,KAAK,KAAKF,gBAAgBG,KAAK,KAAK;IAE5E,oDAAoD;IACpDV,MAAMmB,IAAI,CAACC,SAAS,GAAG5D,aACrBwC,MAAMmB,IAAI,CAACC,SAAS,EACpBlB,YAAYC,sBAAsBnC,IAAI,EACtCkC,YAAYgB,aAAaf,sBAAsBjC,QAAQ,EACvDgC,YAAavB,CAAAA,WAAWwB,sBAAsBxB,QAAQ,GAAGwB,sBAAsB3B,UAAU,AAAD;IAG1F,MAAM6C,cAAc;QAClB,CAACzD,6BAA6BC,SAAS,CAAC,EAAE,GAAG0C,gBAAgBE,MAAM,CAAC,EAAE,CAAC;QACvE,CAAC7C,6BAA6BE,QAAQ,CAAC,EAAE,GAAGyC,gBAAgBG,KAAK,EAAE;IACrE;IAEA,oDAAoD;IACpDV,MAAMmB,IAAI,CAACG,KAAK,GAAG;QACjB,GAAGD,WAAW;QACd,GAAGrB,MAAMmB,IAAI,CAACG,KAAK;IACrB;IAEA,OAAOtB;AACT,EAAE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import styles from "./Tab.module.css";
|
|
4
|
+
import { useTabAnimatedIndicatorStyles_unstable } from "./useTabAnimatedIndicator.styles.css.js";
|
|
5
|
+
export const tabClassNames = {
|
|
6
|
+
root: 'fui-Tab',
|
|
7
|
+
icon: 'fui-Tab__icon',
|
|
8
|
+
content: 'fui-Tab__content'
|
|
9
|
+
};
|
|
10
|
+
export const tabReservedSpaceClassNames = {
|
|
11
|
+
content: 'fui-Tab__content--reserved-space'
|
|
12
|
+
};
|
|
13
|
+
export const useTabStyles_unstable = (state)=>{
|
|
14
|
+
const { appearance, disabled, selected, size, vertical } = state;
|
|
15
|
+
const isCircular = appearance === 'subtle-circular' || appearance === 'filled-circular';
|
|
16
|
+
// Orthogonal size and orientation classes — CSS compound selectors handle all combinations:
|
|
17
|
+
// padding, pending/active indicator positions, icon size, content size, circular padding.
|
|
18
|
+
const sizeClass = size === 'small' ? styles.small : size === 'large' ? styles.large : undefined;
|
|
19
|
+
const orientationClass = vertical ? styles.vertical : styles.horizontal;
|
|
20
|
+
if (!isCircular) {
|
|
21
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
22
|
+
state.root.className = clsx(tabClassNames.root, styles.root, styles.button, orientationClass, sizeClass, styles.focusBase, !disabled && appearance === 'subtle' && styles.subtle, !disabled && appearance === 'transparent' && styles.transparent, !disabled && selected && styles.selected, disabled && styles.disabled, styles.pendingBase, disabled && styles.pendingDisabled, selected && styles.activeBase, selected && !disabled && styles.activeSelected, selected && disabled && styles.activeDisabled, state.root.className);
|
|
23
|
+
} else {
|
|
24
|
+
const isSubtleCircular = appearance === 'subtle-circular';
|
|
25
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
26
|
+
state.root.className = clsx(tabClassNames.root, styles.root, styles.button, orientationClass, sizeClass, styles.circularBase, styles.focusCircular, // Appearance class: CSS handles .subtleCircular.selected, .subtleCircular.disabled, etc.
|
|
27
|
+
isSubtleCircular ? styles.subtleCircular : styles.filledCircular, selected && styles.selected, disabled && styles.disabled, state.root.className);
|
|
28
|
+
}
|
|
29
|
+
useTabAnimatedIndicatorStyles_unstable(state);
|
|
30
|
+
if (state.icon) {
|
|
31
|
+
// Icon size is driven by `.large :global(.fui-Tab__icon)` in CSS.
|
|
32
|
+
// Icon fill swap (selected) is driven by `.selected :global(.fui-Tab__icon) .fui-Icon-*` in CSS.
|
|
33
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
34
|
+
state.icon.className = clsx(tabClassNames.icon, styles.icon, state.icon.className);
|
|
35
|
+
}
|
|
36
|
+
const hasIcon = Boolean(state.icon);
|
|
37
|
+
const positionClass = hasIcon ? styles.contentIconBefore : styles.contentNoIconBefore;
|
|
38
|
+
if (state.contentReservedSpace) {
|
|
39
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
40
|
+
state.contentReservedSpace.className = clsx(tabReservedSpaceClassNames.content, styles.content, positionClass, styles.contentPlaceholder, state.content.className);
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated, react-hooks/immutability
|
|
42
|
+
state.contentReservedSpaceClassName = state.contentReservedSpace.className;
|
|
43
|
+
}
|
|
44
|
+
// Content size (large) and selected weight are handled by descendant CSS from the button's
|
|
45
|
+
// .large and .selected classes — no conditional class needed in the hook.
|
|
46
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
47
|
+
state.content.className = clsx(tabClassNames.content, styles.content, positionClass, state.content.className);
|
|
48
|
+
return state;
|
|
49
|
+
};
|
|
50
|
+
// Keep the individual exports for external callers.
|
|
51
|
+
export const useTabIndicatorStyles_unstable = useTabStyles_unstable;
|
|
52
|
+
export const useTabButtonStyles_unstable = useTabStyles_unstable;
|
|
53
|
+
export const useTabContentStyles_unstable = useTabStyles_unstable;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Tab/useTabStyles.styles.css.ts"],"sourcesContent":["'use client';\n\nimport { clsx } from 'clsx';\nimport type { SlotClassNames } from '@fluentui/react-utilities';\nimport styles from './Tab.module.css';\nimport type { TabSlots, TabState } from './Tab.types';\nimport { useTabAnimatedIndicatorStyles_unstable } from './useTabAnimatedIndicator.styles.css';\n\nexport const tabClassNames: SlotClassNames<TabSlots> = {\n root: 'fui-Tab',\n icon: 'fui-Tab__icon',\n content: 'fui-Tab__content',\n};\n\nexport const tabReservedSpaceClassNames = {\n content: 'fui-Tab__content--reserved-space',\n};\n\nexport const useTabStyles_unstable = (state: TabState): TabState => {\n const { appearance, disabled, selected, size, vertical } = state;\n const isCircular = appearance === 'subtle-circular' || appearance === 'filled-circular';\n\n // Orthogonal size and orientation classes — CSS compound selectors handle all combinations:\n // padding, pending/active indicator positions, icon size, content size, circular padding.\n const sizeClass = size === 'small' ? styles.small : size === 'large' ? styles.large : undefined;\n const orientationClass = vertical ? styles.vertical : styles.horizontal;\n\n if (!isCircular) {\n // eslint-disable-next-line react-hooks/immutability\n state.root.className = clsx(\n tabClassNames.root,\n styles.root,\n styles.button,\n orientationClass,\n sizeClass,\n styles.focusBase,\n !disabled && appearance === 'subtle' && styles.subtle,\n !disabled && appearance === 'transparent' && styles.transparent,\n !disabled && selected && styles.selected,\n disabled && styles.disabled,\n styles.pendingBase,\n disabled && styles.pendingDisabled,\n selected && styles.activeBase,\n selected && !disabled && styles.activeSelected,\n selected && disabled && styles.activeDisabled,\n state.root.className,\n );\n } else {\n const isSubtleCircular = appearance === 'subtle-circular';\n // eslint-disable-next-line react-hooks/immutability\n state.root.className = clsx(\n tabClassNames.root,\n styles.root,\n styles.button,\n orientationClass,\n sizeClass,\n styles.circularBase,\n styles.focusCircular,\n // Appearance class: CSS handles .subtleCircular.selected, .subtleCircular.disabled, etc.\n isSubtleCircular ? styles.subtleCircular : styles.filledCircular,\n selected && styles.selected,\n disabled && styles.disabled,\n state.root.className,\n );\n }\n\n useTabAnimatedIndicatorStyles_unstable(state);\n\n if (state.icon) {\n // Icon size is driven by `.large :global(.fui-Tab__icon)` in CSS.\n // Icon fill swap (selected) is driven by `.selected :global(.fui-Tab__icon) .fui-Icon-*` in CSS.\n // eslint-disable-next-line react-hooks/immutability\n state.icon.className = clsx(tabClassNames.icon, styles.icon, state.icon.className);\n }\n\n const hasIcon = Boolean(state.icon);\n const positionClass = hasIcon ? styles.contentIconBefore : styles.contentNoIconBefore;\n\n if (state.contentReservedSpace) {\n // eslint-disable-next-line react-hooks/immutability\n state.contentReservedSpace.className = clsx(\n tabReservedSpaceClassNames.content,\n styles.content,\n positionClass,\n styles.contentPlaceholder,\n state.content.className,\n );\n // eslint-disable-next-line @typescript-eslint/no-deprecated, react-hooks/immutability\n state.contentReservedSpaceClassName = state.contentReservedSpace.className;\n }\n\n // Content size (large) and selected weight are handled by descendant CSS from the button's\n // .large and .selected classes — no conditional class needed in the hook.\n // eslint-disable-next-line react-hooks/immutability\n state.content.className = clsx(tabClassNames.content, styles.content, positionClass, state.content.className);\n\n return state;\n};\n\n// Keep the individual exports for external callers.\nexport const useTabIndicatorStyles_unstable = useTabStyles_unstable;\nexport const useTabButtonStyles_unstable = useTabStyles_unstable;\nexport const useTabContentStyles_unstable = useTabStyles_unstable;\n"],"names":["clsx","styles","useTabAnimatedIndicatorStyles_unstable","tabClassNames","root","icon","content","tabReservedSpaceClassNames","useTabStyles_unstable","state","appearance","disabled","selected","size","vertical","isCircular","sizeClass","small","large","undefined","orientationClass","horizontal","className","button","focusBase","subtle","transparent","pendingBase","pendingDisabled","activeBase","activeSelected","activeDisabled","isSubtleCircular","circularBase","focusCircular","subtleCircular","filledCircular","hasIcon","Boolean","positionClass","contentIconBefore","contentNoIconBefore","contentReservedSpace","contentPlaceholder","contentReservedSpaceClassName","useTabIndicatorStyles_unstable","useTabButtonStyles_unstable","useTabContentStyles_unstable"],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { clsx } from "clsx";
|
|
3
|
+
import styles from "./Tab.module.css";
|
|
4
|
+
import { useTabAnimatedIndicatorStyles_unstable } from "./useTabAnimatedIndicator.styles.css.js";
|
|
5
|
+
export const tabClassNames = {
|
|
6
|
+
root: 'fui-Tab',
|
|
7
|
+
icon: 'fui-Tab__icon',
|
|
8
|
+
content: 'fui-Tab__content'
|
|
9
|
+
};
|
|
10
|
+
export const tabReservedSpaceClassNames = {
|
|
11
|
+
content: 'fui-Tab__content--reserved-space'
|
|
12
|
+
};
|
|
13
|
+
export const useTabStyles_unstable = (state)=>{
|
|
14
|
+
const { appearance, disabled, selected, size, vertical } = state;
|
|
15
|
+
const isCircular = appearance === 'subtle-circular' || appearance === 'filled-circular';
|
|
16
|
+
// Orthogonal size and orientation classes — CSS compound selectors handle all combinations:
|
|
17
|
+
// padding, pending/active indicator positions, icon size, content size, circular padding.
|
|
18
|
+
const sizeClass = size === 'small' ? styles.small : size === 'large' ? styles.large : undefined;
|
|
19
|
+
const orientationClass = vertical ? styles.vertical : styles.horizontal;
|
|
20
|
+
if (!isCircular) {
|
|
21
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
22
|
+
state.root.className = clsx(tabClassNames.root, styles.root, styles.button, orientationClass, sizeClass, styles.focusBase, !disabled && appearance === 'subtle' && styles.subtle, !disabled && appearance === 'transparent' && styles.transparent, !disabled && selected && styles.selected, disabled && styles.disabled, styles.pendingBase, disabled && styles.pendingDisabled, selected && styles.activeBase, selected && !disabled && styles.activeSelected, selected && disabled && styles.activeDisabled, state.root.className);
|
|
23
|
+
} else {
|
|
24
|
+
const isSubtleCircular = appearance === 'subtle-circular';
|
|
25
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
26
|
+
state.root.className = clsx(tabClassNames.root, styles.root, styles.button, orientationClass, sizeClass, styles.circularBase, styles.focusCircular, // Appearance class: CSS handles .subtleCircular.selected, .subtleCircular.disabled, etc.
|
|
27
|
+
isSubtleCircular ? styles.subtleCircular : styles.filledCircular, selected && styles.selected, disabled && styles.disabled, state.root.className);
|
|
28
|
+
}
|
|
29
|
+
useTabAnimatedIndicatorStyles_unstable(state);
|
|
30
|
+
if (state.icon) {
|
|
31
|
+
// Icon size is driven by `.large :global(.fui-Tab__icon)` in CSS.
|
|
32
|
+
// Icon fill swap (selected) is driven by `.selected :global(.fui-Tab__icon) .fui-Icon-*` in CSS.
|
|
33
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
34
|
+
state.icon.className = clsx(tabClassNames.icon, styles.icon, state.icon.className);
|
|
35
|
+
}
|
|
36
|
+
const hasIcon = Boolean(state.icon);
|
|
37
|
+
const positionClass = hasIcon ? styles.contentIconBefore : styles.contentNoIconBefore;
|
|
38
|
+
if (state.contentReservedSpace) {
|
|
39
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
40
|
+
state.contentReservedSpace.className = clsx(tabReservedSpaceClassNames.content, styles.content, positionClass, styles.contentPlaceholder, state.content.className);
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated, react-hooks/immutability
|
|
42
|
+
state.contentReservedSpaceClassName = state.contentReservedSpace.className;
|
|
43
|
+
}
|
|
44
|
+
// Content size (large) and selected weight are handled by descendant CSS from the button's
|
|
45
|
+
// .large and .selected classes — no conditional class needed in the hook.
|
|
46
|
+
// eslint-disable-next-line react-hooks/immutability
|
|
47
|
+
state.content.className = clsx(tabClassNames.content, styles.content, positionClass, state.content.className);
|
|
48
|
+
return state;
|
|
49
|
+
};
|
|
50
|
+
// Keep the individual exports for external callers.
|
|
51
|
+
export const useTabIndicatorStyles_unstable = useTabStyles_unstable;
|
|
52
|
+
export const useTabButtonStyles_unstable = useTabStyles_unstable;
|
|
53
|
+
export const useTabContentStyles_unstable = useTabStyles_unstable;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/Tab/useTabStyles.styles.css.ts"],"sourcesContent":["'use client';\n\nimport { clsx } from 'clsx';\nimport type { SlotClassNames } from '@fluentui/react-utilities';\nimport styles from './Tab.module.css';\nimport type { TabSlots, TabState } from './Tab.types';\nimport { useTabAnimatedIndicatorStyles_unstable } from './useTabAnimatedIndicator.styles.css';\n\nexport const tabClassNames: SlotClassNames<TabSlots> = {\n root: 'fui-Tab',\n icon: 'fui-Tab__icon',\n content: 'fui-Tab__content',\n};\n\nexport const tabReservedSpaceClassNames = {\n content: 'fui-Tab__content--reserved-space',\n};\n\nexport const useTabStyles_unstable = (state: TabState): TabState => {\n const { appearance, disabled, selected, size, vertical } = state;\n const isCircular = appearance === 'subtle-circular' || appearance === 'filled-circular';\n\n // Orthogonal size and orientation classes — CSS compound selectors handle all combinations:\n // padding, pending/active indicator positions, icon size, content size, circular padding.\n const sizeClass = size === 'small' ? styles.small : size === 'large' ? styles.large : undefined;\n const orientationClass = vertical ? styles.vertical : styles.horizontal;\n\n if (!isCircular) {\n // eslint-disable-next-line react-hooks/immutability\n state.root.className = clsx(\n tabClassNames.root,\n styles.root,\n styles.button,\n orientationClass,\n sizeClass,\n styles.focusBase,\n !disabled && appearance === 'subtle' && styles.subtle,\n !disabled && appearance === 'transparent' && styles.transparent,\n !disabled && selected && styles.selected,\n disabled && styles.disabled,\n styles.pendingBase,\n disabled && styles.pendingDisabled,\n selected && styles.activeBase,\n selected && !disabled && styles.activeSelected,\n selected && disabled && styles.activeDisabled,\n state.root.className,\n );\n } else {\n const isSubtleCircular = appearance === 'subtle-circular';\n // eslint-disable-next-line react-hooks/immutability\n state.root.className = clsx(\n tabClassNames.root,\n styles.root,\n styles.button,\n orientationClass,\n sizeClass,\n styles.circularBase,\n styles.focusCircular,\n // Appearance class: CSS handles .subtleCircular.selected, .subtleCircular.disabled, etc.\n isSubtleCircular ? styles.subtleCircular : styles.filledCircular,\n selected && styles.selected,\n disabled && styles.disabled,\n state.root.className,\n );\n }\n\n useTabAnimatedIndicatorStyles_unstable(state);\n\n if (state.icon) {\n // Icon size is driven by `.large :global(.fui-Tab__icon)` in CSS.\n // Icon fill swap (selected) is driven by `.selected :global(.fui-Tab__icon) .fui-Icon-*` in CSS.\n // eslint-disable-next-line react-hooks/immutability\n state.icon.className = clsx(tabClassNames.icon, styles.icon, state.icon.className);\n }\n\n const hasIcon = Boolean(state.icon);\n const positionClass = hasIcon ? styles.contentIconBefore : styles.contentNoIconBefore;\n\n if (state.contentReservedSpace) {\n // eslint-disable-next-line react-hooks/immutability\n state.contentReservedSpace.className = clsx(\n tabReservedSpaceClassNames.content,\n styles.content,\n positionClass,\n styles.contentPlaceholder,\n state.content.className,\n );\n // eslint-disable-next-line @typescript-eslint/no-deprecated, react-hooks/immutability\n state.contentReservedSpaceClassName = state.contentReservedSpace.className;\n }\n\n // Content size (large) and selected weight are handled by descendant CSS from the button's\n // .large and .selected classes — no conditional class needed in the hook.\n // eslint-disable-next-line react-hooks/immutability\n state.content.className = clsx(tabClassNames.content, styles.content, positionClass, state.content.className);\n\n return state;\n};\n\n// Keep the individual exports for external callers.\nexport const useTabIndicatorStyles_unstable = useTabStyles_unstable;\nexport const useTabButtonStyles_unstable = useTabStyles_unstable;\nexport const useTabContentStyles_unstable = useTabStyles_unstable;\n"],"names":["clsx","styles","useTabAnimatedIndicatorStyles_unstable","tabClassNames","root","icon","content","tabReservedSpaceClassNames","useTabStyles_unstable","state","appearance","disabled","selected","size","vertical","isCircular","sizeClass","small","large","undefined","orientationClass","horizontal","className","button","focusBase","subtle","transparent","pendingBase","pendingDisabled","activeBase","activeSelected","activeDisabled","isSubtleCircular","circularBase","focusCircular","subtleCircular","filledCircular","hasIcon","Boolean","positionClass","contentIconBefore","contentNoIconBefore","contentReservedSpace","contentPlaceholder","contentReservedSpaceClassName","useTabIndicatorStyles_unstable","useTabButtonStyles_unstable","useTabContentStyles_unstable"],"mappings":"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"}
|