@lumx/react 4.19.1-alpha.5 → 4.20.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_internal/{CcLi-Wuu.js → BvaFEHZn.js} +3 -6
- package/_internal/BvaFEHZn.js.map +1 -0
- package/index.d.ts +69 -12
- package/index.js +124 -82
- package/index.js.map +1 -1
- package/package.json +3 -3
- package/utils/index.d.ts +2 -6
- package/utils/index.js +1 -1
- package/_internal/CcLi-Wuu.js.map +0 -1
|
@@ -210,15 +210,12 @@ const InfiniteScroll = ({
|
|
|
210
210
|
const {
|
|
211
211
|
current: element
|
|
212
212
|
} = elementRef;
|
|
213
|
-
if (!element
|
|
213
|
+
if (!element) {
|
|
214
214
|
return undefined;
|
|
215
215
|
}
|
|
216
216
|
return setupInfiniteScrollObserver(element, callback, options);
|
|
217
|
-
// `options?.root` starts as `null` (before the scrollable list's ref attaches) and is
|
|
218
|
-
// then set to the real element — must be a dep, or the observer gets stuck watching
|
|
219
|
-
// the wrong root (falling back to the viewport) for the component's whole lifetime.
|
|
220
217
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
221
|
-
}, [elementRef.current, callback
|
|
218
|
+
}, [elementRef.current, callback]);
|
|
222
219
|
return InfiniteScroll$1({
|
|
223
220
|
ref: elementRef
|
|
224
221
|
});
|
|
@@ -262,4 +259,4 @@ const Portal = ({
|
|
|
262
259
|
};
|
|
263
260
|
|
|
264
261
|
export { ClickAwayProvider as C, DisabledStateProvider as D, InfiniteScroll as I, Portal as P, PortalProvider as a, useDisabledStateContext as u };
|
|
265
|
-
//# sourceMappingURL=
|
|
262
|
+
//# sourceMappingURL=BvaFEHZn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BvaFEHZn.js","sources":["../../src/utils/disabled/DisabledStateContext.tsx","../../../lumx-core/src/js/utils/ClickAway/index.ts","../../src/hooks/useClickAway.tsx","../../src/utils/ClickAwayProvider/ClickAwayProvider.tsx","../../../lumx-core/src/js/utils/InfiniteScroll/setupInfiniteScrollObserver.ts","../../../lumx-core/src/js/utils/InfiniteScroll/index.tsx","../../src/utils/InfiniteScroll/InfiniteScroll.tsx","../../src/utils/Portal/PortalProvider.tsx","../../src/utils/Portal/Portal.tsx"],"sourcesContent":["import React, { useContext } from 'react';\n\nimport { DisabledStateContextValue } from '@lumx/core/js/utils/disabledState';\n\nexport const DisabledStateContext = React.createContext<DisabledStateContextValue>({ state: null });\n\nexport type DisabledStateProviderProps = DisabledStateContextValue & {\n children: React.ReactNode;\n};\n\n/**\n * Disabled state provider.\n * All nested LumX Design System components inherit this disabled state.\n */\nexport function DisabledStateProvider({ children, ...value }: DisabledStateProviderProps) {\n return <DisabledStateContext.Provider value={value}>{children}</DisabledStateContext.Provider>;\n}\n\n/**\n * Get DisabledState context value\n */\nexport function useDisabledStateContext(): DisabledStateContextValue {\n return useContext(DisabledStateContext);\n}\n","/**\n * Shared types and logic for ClickAway detection.\n *\n * ClickAway detects clicks outside a set of elements and triggers a callback.\n * The core logic (event listening + target checking) is framework-agnostic.\n * Framework-specific wrappers (React hook, Vue composable) and context providers\n * (React context, Vue provide/inject) are implemented in each framework package.\n */\n\nimport type { Falsy } from '@lumx/core/js/types';\n\n/** Event types that trigger click away detection. */\nexport const CLICK_AWAY_EVENT_TYPES = ['mousedown', 'touchstart'] as const;\n\n/** Callback triggered when a click away is detected. */\nexport type ClickAwayCallback = EventListener | Falsy;\n\n/**\n * Check if the click event targets are outside all the given elements.\n *\n * @param targets - The event target elements (from `event.target` and `event.composedPath()`).\n * @param elements - The elements considered \"inside\" the click away context.\n * @returns `true` if the click is outside all elements (i.e. a click away).\n */\nexport function isClickAway(targets: HTMLElement[], elements: HTMLElement[]): boolean {\n return !elements.some((element) => element instanceof Node && targets.some((target) => element.contains(target)));\n}\n\n/**\n * Imperative setup for click away detection.\n * Adds mousedown/touchstart listeners on `document` and calls the callback when a click\n * occurs outside the elements returned by `getElements`.\n *\n * Note: when `getElements` returns an empty array, any click is considered a click away.\n * Callers should guard against calling `setupClickAway` when no refs are registered.\n *\n * @param getElements - Getter returning the current list of elements considered \"inside\".\n * @param callback - Callback to invoke on click away.\n * @returns A teardown function that removes the event listeners.\n */\nexport function setupClickAway(\n getElements: () => HTMLElement[],\n callback: ClickAwayCallback,\n): (() => void) | undefined {\n if (!callback) {\n return undefined;\n }\n\n const listener: EventListener = (evt) => {\n const targets = [evt.composedPath?.()[0], evt.target].filter((t): t is HTMLElement => t instanceof Node);\n const elements = getElements();\n if (isClickAway(targets, elements)) {\n callback(evt);\n }\n };\n\n CLICK_AWAY_EVENT_TYPES.forEach((evtType) => document.addEventListener(evtType, listener));\n return () => {\n CLICK_AWAY_EVENT_TYPES.forEach((evtType) => document.removeEventListener(evtType, listener));\n };\n}\n","import { RefObject, useEffect } from 'react';\n\nimport { Falsy } from '@lumx/react/utils/type';\nimport { setupClickAway } from '@lumx/core/js/utils/ClickAway';\n\nexport interface ClickAwayParameters {\n /**\n * A callback function to call when the user clicks away from the elements.\n */\n callback: EventListener | Falsy;\n /**\n * Elements considered within the click away context (clicking outside them will trigger the click away callback).\n */\n childrenRefs: RefObject<Array<RefObject<HTMLElement>>>;\n}\n\n/**\n * Listen to clicks away from the given elements and callback the passed in function.\n *\n * Warning: If you need to detect click away on nested React portals, please use the `ClickAwayProvider` component.\n */\nexport function useClickAway({ callback, childrenRefs }: ClickAwayParameters): void {\n useEffect(() => {\n const getElements = () => {\n const refs = childrenRefs.current;\n if (!refs) return [];\n return refs.map((ref) => ref?.current).filter(Boolean) as HTMLElement[];\n };\n return setupClickAway(getElements, callback);\n }, [callback, childrenRefs]);\n}\n","import { createContext, RefObject, useContext, useEffect, useMemo, useRef } from 'react';\nimport { ClickAwayParameters, useClickAway } from '@lumx/react/hooks/useClickAway';\n\ninterface ContextValue {\n childrenRefs: Array<RefObject<HTMLElement>>;\n addRefs(...newChildrenRefs: Array<RefObject<HTMLElement>>): void;\n}\n\nconst ClickAwayAncestorContext = createContext<ContextValue | null>(null);\n\ninterface ClickAwayProviderProps extends ClickAwayParameters {\n /**\n * (Optional) Element that should be considered as part of the parent\n */\n parentRef?: RefObject<HTMLElement>;\n /**\n * Children\n */\n children?: React.ReactNode;\n}\n\n/**\n * Component combining the `useClickAway` hook with a React context to hook into the React component tree and make sure\n * we take into account both the DOM tree and the React tree to detect click away.\n *\n * @return the react component.\n */\nexport const ClickAwayProvider: React.FC<ClickAwayProviderProps> = ({\n children,\n callback,\n childrenRefs,\n parentRef,\n}) => {\n const parentContext = useContext(ClickAwayAncestorContext);\n const currentContext = useMemo(() => {\n const context: ContextValue = {\n childrenRefs: [],\n /**\n * Add element refs to the current context and propagate to the parent context.\n */\n addRefs(...newChildrenRefs) {\n // Add element refs that should be considered as inside the click away context.\n context.childrenRefs.push(...newChildrenRefs);\n\n if (parentContext) {\n // Also add then to the parent context\n parentContext.addRefs(...newChildrenRefs);\n if (parentRef) {\n // The parent element is also considered as inside the parent click away context but not inside the current context\n parentContext.addRefs(parentRef);\n }\n }\n },\n };\n return context;\n }, [parentContext, parentRef]);\n\n useEffect(() => {\n const { current: currentRefs } = childrenRefs;\n if (!currentRefs) {\n return;\n }\n currentContext.addRefs(...currentRefs);\n }, [currentContext, childrenRefs]);\n\n useClickAway({ callback, childrenRefs: useRef(currentContext.childrenRefs) });\n return <ClickAwayAncestorContext.Provider value={currentContext}>{children}</ClickAwayAncestorContext.Provider>;\n};\nClickAwayProvider.displayName = 'ClickAwayProvider';\n","type EventCallback = (evt?: Event) => void;\n\n/**\n * Sets up an IntersectionObserver on the given element.\n * Calls `callback` when at least one observed entry is intersecting.\n * Returns a cleanup function that unobserves the element.\n */\nexport function setupInfiniteScrollObserver(\n element: Element,\n callback: EventCallback,\n options?: IntersectionObserverInit,\n): () => void {\n const observer = new IntersectionObserver((entries = []) => {\n const hasIntersection = entries.some((entry) => entry.isIntersecting);\n\n if (!hasIntersection) {\n return;\n }\n\n callback();\n }, options);\n\n observer.observe(element);\n\n return () => {\n observer.unobserve(element);\n };\n}\n","import type { CommonRef } from '../../types';\n\nexport { setupInfiniteScrollObserver } from './setupInfiniteScrollObserver';\n\nexport const INFINITE_SCROLL_CLASSNAME = 'lumx-infinite-scroll-anchor';\n\nexport interface InfiniteScrollProps {\n /** Callback when infinite scroll component is in view */\n // eslint-disable-next-line react/no-unused-prop-types\n callback: (evt?: Event) => void;\n /** Customize intersection observer option */\n // eslint-disable-next-line react/no-unused-prop-types\n options?: IntersectionObserverInit;\n}\n\n/**\n * Framework-agnostic InfiniteScroll sentinel component.\n *\n * Renders a tiny invisible div that triggers a callback when it enters the viewport\n * (or intersects its root element) via IntersectionObserver.\n *\n * The div has a small height (4px) to avoid issues when a browser zoom is applied,\n * where a zero-height element might not trigger IntersectionObserver reliably.\n */\nexport const InfiniteScroll = ({ ref }: { ref?: CommonRef }) => (\n // In order to avoid issues when a zoom is added to the browser, we add a small height to the div so that\n // the intersection has a higher chance of working correctly.\n <div ref={ref} aria-hidden=\"true\" className={INFINITE_SCROLL_CLASSNAME} style={{ height: '4px' }} />\n);\n","import React, { useEffect } from 'react';\nimport {\n InfiniteScroll as UI,\n type InfiniteScrollProps,\n setupInfiniteScrollObserver,\n} from '@lumx/core/js/utils/InfiniteScroll';\n\nexport type { InfiniteScrollProps };\n\n/**\n * Handles basic callback pattern by using intersection observers.\n */\nexport const InfiniteScroll: React.FC<InfiniteScrollProps> = ({ callback, options }) => {\n const elementRef = React.useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n const { current: element } = elementRef;\n if (!element) {\n return undefined;\n }\n\n return setupInfiniteScrollObserver(element, callback, options);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [elementRef.current, callback]);\n\n return UI({ ref: elementRef });\n};\n","import React from 'react';\nimport type { PortalInit } from '@lumx/core/js/utils/Portal';\n\nexport type { PortalInit, PortalProviderProps } from '@lumx/core/js/utils/Portal';\n\nexport const PortalContext = React.createContext<PortalInit>(() => ({ container: document.body }));\n\nexport interface ReactPortalProviderProps {\n children?: React.ReactNode;\n value: PortalInit;\n}\n\n/**\n * Customize where <Portal> wrapped elements render (tooltip, popover, dialog, etc.)\n */\nexport const PortalProvider: React.FC<ReactPortalProviderProps> = PortalContext.Provider;\n","import React from 'react';\nimport { createPortal } from 'react-dom';\nimport { PortalContext } from './PortalProvider';\n\nexport type { PortalProps } from '@lumx/core/js/utils/Portal';\n\nexport interface ReactPortalProps {\n enabled?: boolean;\n children: React.ReactNode;\n}\n\n/**\n * Render children in a portal outside the current DOM position\n * (defaults to `document.body` but can be customized with the PortalContextProvider)\n */\nexport const Portal: React.FC<ReactPortalProps> = ({ children, enabled = true }) => {\n const init = React.useContext(PortalContext);\n const context = React.useMemo(\n () => {\n return enabled ? init() : null;\n },\n // Only update on 'enabled'\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [enabled],\n );\n\n React.useLayoutEffect(() => {\n return context?.teardown;\n }, [context?.teardown, enabled]);\n\n const { container } = context ?? {};\n if (!container || typeof container === 'string') {\n return <>{children}</>;\n }\n return createPortal(children, container);\n};\n"],"names":["DisabledStateContext","React","createContext","state","DisabledStateProvider","children","value","_jsx","Provider","useDisabledStateContext","useContext","CLICK_AWAY_EVENT_TYPES","isClickAway","targets","elements","some","element","Node","target","contains","setupClickAway","getElements","callback","undefined","listener","evt","composedPath","filter","t","forEach","evtType","document","addEventListener","removeEventListener","useClickAway","childrenRefs","useEffect","refs","current","map","ref","Boolean","ClickAwayAncestorContext","ClickAwayProvider","parentRef","parentContext","currentContext","useMemo","context","addRefs","newChildrenRefs","push","currentRefs","useRef","displayName","setupInfiniteScrollObserver","options","observer","IntersectionObserver","entries","hasIntersection","entry","isIntersecting","observe","unobserve","INFINITE_SCROLL_CLASSNAME","InfiniteScroll","className","style","height","elementRef","UI","PortalContext","container","body","PortalProvider","Portal","enabled","init","useLayoutEffect","teardown","_Fragment","createPortal"],"mappings":"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"}
|
package/index.d.ts
CHANGED
|
@@ -5271,14 +5271,17 @@ interface TabListProps$1 extends HasClassName, HasTheme {
|
|
|
5271
5271
|
layout?: TabListLayout;
|
|
5272
5272
|
/** Position of the tabs in the list (requires 'clustered' layout). */
|
|
5273
5273
|
position?: Alignment;
|
|
5274
|
+
/** `role` applied to the inner `__links` container */
|
|
5275
|
+
role?: 'navigation' | 'tablist';
|
|
5274
5276
|
/** ref to the wrapper element */
|
|
5275
5277
|
ref?: CommonRef;
|
|
5276
5278
|
}
|
|
5279
|
+
type TabListPropsToOverride = 'role';
|
|
5277
5280
|
|
|
5278
5281
|
/**
|
|
5279
5282
|
* Defines the props of the component.
|
|
5280
5283
|
*/
|
|
5281
|
-
interface TabListProps extends GenericProps$1, ReactToJSX<TabListProps$1> {
|
|
5284
|
+
interface TabListProps extends GenericProps$1, ReactToJSX<TabListProps$1, TabListPropsToOverride> {
|
|
5282
5285
|
}
|
|
5283
5286
|
|
|
5284
5287
|
/**
|
|
@@ -5286,6 +5289,8 @@ interface TabListProps extends GenericProps$1, ReactToJSX<TabListProps$1> {
|
|
|
5286
5289
|
*
|
|
5287
5290
|
* Implements WAI-ARIA `tablist` role {@see https://www.w3.org/TR/wai-aria-practices-1.1/examples/tabs/tabs-1/tabs.html#rps_label}
|
|
5288
5291
|
*
|
|
5292
|
+
* Renders a `role="navigation"` landmark instead when used outside a `TabProvider` (nav-link mode).
|
|
5293
|
+
*
|
|
5289
5294
|
* @param props Component props.
|
|
5290
5295
|
* @param ref Component ref.
|
|
5291
5296
|
* @return React element.
|
|
@@ -5293,9 +5298,14 @@ interface TabListProps extends GenericProps$1, ReactToJSX<TabListProps$1> {
|
|
|
5293
5298
|
declare const TabList: Comp<TabListProps, HTMLDivElement>;
|
|
5294
5299
|
|
|
5295
5300
|
/**
|
|
5296
|
-
*
|
|
5301
|
+
* Element a `Tab` can render as: `'button'` (default, classic tab), `'a'` (nav-link, `href`
|
|
5302
|
+
* required via {@link HasRequiredLinkHref}), or any `ElementType` (nav-link, e.g. a router `Link`).
|
|
5297
5303
|
*/
|
|
5298
|
-
|
|
5304
|
+
type TabElement = 'a' | 'button' | ElementType;
|
|
5305
|
+
/**
|
|
5306
|
+
* Defines the props of the component (independent of the `as` element).
|
|
5307
|
+
*/
|
|
5308
|
+
interface CommonTabProps extends HasClassName {
|
|
5299
5309
|
/** Children are not supported. */
|
|
5300
5310
|
children?: never;
|
|
5301
5311
|
/** Icon (SVG path). */
|
|
@@ -5306,6 +5316,11 @@ interface TabProps$1 extends HasClassName {
|
|
|
5306
5316
|
id?: string;
|
|
5307
5317
|
/** Whether the tab is active or not. */
|
|
5308
5318
|
isActive?: boolean;
|
|
5319
|
+
/**
|
|
5320
|
+
* WAI-ARIA `tab` role, resolved by the framework wrapper from `TabProvider` presence:
|
|
5321
|
+
* `'tab'` inside a provider (classic tab mode), `undefined` outside (nav-link mode).
|
|
5322
|
+
*/
|
|
5323
|
+
role?: 'tab';
|
|
5309
5324
|
/** Whether the component is disabled or not. */
|
|
5310
5325
|
isDisabled?: boolean;
|
|
5311
5326
|
/** Label content. */
|
|
@@ -5326,23 +5341,38 @@ interface TabProps$1 extends HasClassName {
|
|
|
5326
5341
|
tabIndexProp?: string;
|
|
5327
5342
|
/** Name of the prop used to attach the keypress event (framework-dependent). */
|
|
5328
5343
|
keyPressProp?: string;
|
|
5329
|
-
/** ID applied to the tab button element (for aria-labelledby on the panel). */
|
|
5330
|
-
tabId?: string;
|
|
5331
5344
|
/** ID of the associated tab panel (for aria-controls). */
|
|
5332
5345
|
tabPanelId?: string;
|
|
5333
5346
|
/** Icon component injected by the framework wrapper. */
|
|
5334
5347
|
Icon: any;
|
|
5335
5348
|
/** Text component injected by the framework wrapper. */
|
|
5336
5349
|
Text: any;
|
|
5337
|
-
/** Forward ref to the underlying
|
|
5350
|
+
/** Forward ref to the underlying element. */
|
|
5338
5351
|
ref?: CommonRef;
|
|
5339
5352
|
}
|
|
5340
|
-
|
|
5353
|
+
/**
|
|
5354
|
+
* Polymorphic `as` surface for `Tab`. Not `HasPolymorphicAs<E>`: core JSX is type-checked under
|
|
5355
|
+
* both the React and Vue namespaces, so spreading React DOM prop types would break the Vue
|
|
5356
|
+
* cross-check. `href` is required at compile time when `as === 'a'` (via {@link HasRequiredLinkHref}).
|
|
5357
|
+
*/
|
|
5358
|
+
type TabAsProps<E extends TabElement = 'button'> = {
|
|
5359
|
+
as?: E;
|
|
5360
|
+
} & (E extends 'a' ? HasRequiredLinkHref<'a'> : unknown);
|
|
5361
|
+
/**
|
|
5362
|
+
* Props of the `Tab` component. Polymorphic on `as` (element selection only): `as` picks the
|
|
5363
|
+
* rendered element, while **mode is driven by `TabProvider` presence** (via the wrapper-resolved
|
|
5364
|
+
* `role`), not by `as`. The `href` conditional's false branch is `unknown` (not a record) to avoid
|
|
5365
|
+
* widening `keyof TabProps`.
|
|
5366
|
+
*/
|
|
5367
|
+
type TabProps$1<E extends TabElement = 'button'> = CommonTabProps & TabAsProps<E>;
|
|
5368
|
+
type TabPropsToOverride = 'as' | 'role' | 'isAnyDisabled' | 'shouldActivateOnFocus' | 'changeToTab' | 'tabIndex' | 'tabIndexProp' | 'keyPressProp' | 'tabPanelId' | 'Icon' | 'Text';
|
|
5341
5369
|
|
|
5342
5370
|
/**
|
|
5343
|
-
* Defines the props of the component.
|
|
5371
|
+
* Defines the props of the component. Polymorphic on `as` (element selection only): `as` picks the
|
|
5372
|
+
* rendered element (`as="a"` with required `href`, or `as={RouterLink}`), while the mode
|
|
5373
|
+
* (`role="tab"` vs nav-link) is driven by `TabProvider` presence. The forwarded ref type follows `as`.
|
|
5344
5374
|
*/
|
|
5345
|
-
|
|
5375
|
+
type TabProps<E extends ElementType$1 = 'button'> = GenericProps$1 & HasPolymorphicAs$1<E> & HasRequiredLinkHref$1<E> & ReactToJSX<TabProps$1, TabPropsToOverride> & {
|
|
5346
5376
|
/** Children are not supported. */
|
|
5347
5377
|
children?: never;
|
|
5348
5378
|
/** Icon (SVG path). */
|
|
@@ -5357,17 +5387,44 @@ interface TabProps extends GenericProps$1, ReactToJSX<TabProps$1, TabPropsToOver
|
|
|
5357
5387
|
isDisabled?: boolean;
|
|
5358
5388
|
/** Label content. */
|
|
5359
5389
|
label: string | ReactNode;
|
|
5360
|
-
}
|
|
5390
|
+
};
|
|
5361
5391
|
/**
|
|
5362
5392
|
* Tab component.
|
|
5363
5393
|
*
|
|
5364
5394
|
* Implements WAI-ARIA `tab` role {@see https://www.w3.org/TR/wai-aria-practices-1.1/examples/tabs/tabs-1/tabs.html#rps_label}
|
|
5395
|
+
* when rendered inside a `TabProvider`.
|
|
5396
|
+
*
|
|
5397
|
+
* Outside a `TabProvider` (nav-link mode): plain link, no `role="tab"`/roving tabindex/`changeToTab`
|
|
5398
|
+
* dispatch — only `aria-current` marks the active item.
|
|
5365
5399
|
*
|
|
5366
5400
|
* @param props Component props.
|
|
5367
|
-
* @param ref Component ref.
|
|
5401
|
+
* @param ref Component ref (type follows `as`).
|
|
5368
5402
|
* @return React element.
|
|
5369
5403
|
*/
|
|
5370
|
-
declare const Tab:
|
|
5404
|
+
declare const Tab: (<E extends ElementType$1 = "button">(props: GenericProps$1 & React$1.PropsWithoutRef<React$1.ComponentProps<E>> & {
|
|
5405
|
+
as?: E | undefined;
|
|
5406
|
+
} & HasRequiredLinkHref$1<E> & ReactToJSX<TabProps$1, TabPropsToOverride> & {
|
|
5407
|
+
/** Children are not supported. */
|
|
5408
|
+
children?: never;
|
|
5409
|
+
/** Icon (SVG path). */
|
|
5410
|
+
icon?: IconProps["icon"];
|
|
5411
|
+
/** Icon component properties. */
|
|
5412
|
+
iconProps?: Omit<IconProps, "icon">;
|
|
5413
|
+
/** Native id property. */
|
|
5414
|
+
id?: string;
|
|
5415
|
+
/** Whether the tab is active or not. */
|
|
5416
|
+
isActive?: boolean;
|
|
5417
|
+
/** Whether the component is disabled or not. */
|
|
5418
|
+
isDisabled?: boolean;
|
|
5419
|
+
/** Label content. */
|
|
5420
|
+
label: string | ReactNode;
|
|
5421
|
+
} & React$1.ComponentProps<E> & {
|
|
5422
|
+
ref?: ComponentRef<E> | undefined;
|
|
5423
|
+
}) => React.JSX.Element) & {
|
|
5424
|
+
displayName: string;
|
|
5425
|
+
className: string;
|
|
5426
|
+
defaultProps: Partial<TabProps$1<"button">>;
|
|
5427
|
+
};
|
|
5371
5428
|
|
|
5372
5429
|
/**
|
|
5373
5430
|
* Defines the props of the component.
|
package/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import ReactDOM__default from 'react-dom';
|
|
|
9
9
|
import { classNames, onEscapePressed, onEnterPressed as onEnterPressed$1, detectHorizontalSwipe } from '@lumx/core/js/utils';
|
|
10
10
|
import last from 'lodash/last.js';
|
|
11
11
|
import pull from 'lodash/pull.js';
|
|
12
|
-
import { u as useDisabledStateContext, P as Portal, C as ClickAwayProvider, I as InfiniteScroll } from './_internal/
|
|
12
|
+
import { u as useDisabledStateContext, P as Portal, C as ClickAwayProvider, I as InfiniteScroll } from './_internal/BvaFEHZn.js';
|
|
13
13
|
import isEmpty from 'lodash/isEmpty.js';
|
|
14
14
|
import get from 'lodash/get.js';
|
|
15
15
|
import { getDisabledState as getDisabledState$1 } from '@lumx/core/js/utils/disabledState';
|
|
@@ -17991,8 +17991,6 @@ const SelectButton$2 = (props, {
|
|
|
17991
17991
|
const isLoadingMore = listStatus === 'loadingMore';
|
|
17992
17992
|
const isError = listStatus === 'error';
|
|
17993
17993
|
const isMultiselectable = selectionType === 'multiple';
|
|
17994
|
-
// Prevent firing during loading or error states to avoid duplicate fetches.
|
|
17995
|
-
const isInfiniteScrollEnabled = !listStatus || listStatus === 'idle';
|
|
17996
17994
|
|
|
17997
17995
|
/*
|
|
17998
17996
|
* Display value: castArray normalizes single/multi value to an array, then resolve
|
|
@@ -18031,7 +18029,11 @@ const SelectButton$2 = (props, {
|
|
|
18031
18029
|
}, {
|
|
18032
18030
|
Combobox
|
|
18033
18031
|
}), onLoadMore && InfiniteScroll && /*#__PURE__*/jsx(InfiniteScroll, {
|
|
18034
|
-
callback:
|
|
18032
|
+
callback: () => {
|
|
18033
|
+
// Guard: prevent firing during loading or error states to avoid duplicate fetches.
|
|
18034
|
+
if (listStatus && listStatus !== 'idle') return;
|
|
18035
|
+
onLoadMore();
|
|
18036
|
+
},
|
|
18035
18037
|
options: infiniteScrollOptions
|
|
18036
18038
|
}), isLoadingMore && /*#__PURE__*/jsx(Combobox.OptionSkeleton, {
|
|
18037
18039
|
count: 1
|
|
@@ -18175,13 +18177,7 @@ const SelectButton$1 = React__default.forwardRef((props, ref) => {
|
|
|
18175
18177
|
as,
|
|
18176
18178
|
...buttonProps
|
|
18177
18179
|
} = props;
|
|
18178
|
-
|
|
18179
|
-
// IntersectionObserver root must be the actual scrolling/clipping element, or the
|
|
18180
|
-
// sentinel is trivially always "intersecting" its non-clipping `<ul>` parent.
|
|
18181
|
-
const [scrollContainer, setScrollContainer] = useState(null);
|
|
18182
|
-
const setListElement = useCallback(listElement => {
|
|
18183
|
-
setScrollContainer(listElement?.closest(`.${CLASSNAME$17}__scroll`) ?? null);
|
|
18184
|
-
}, []);
|
|
18180
|
+
const [listElement, setListElement] = useState(null);
|
|
18185
18181
|
const isMultiple = selectionType === 'multiple';
|
|
18186
18182
|
|
|
18187
18183
|
// Inject core-computed props into the consumer's renderOption result.
|
|
@@ -18222,7 +18218,7 @@ const SelectButton$1 = React__default.forwardRef((props, ref) => {
|
|
|
18222
18218
|
translations,
|
|
18223
18219
|
onLoadMore,
|
|
18224
18220
|
infiniteScrollOptions: {
|
|
18225
|
-
root:
|
|
18221
|
+
root: listElement,
|
|
18226
18222
|
rootMargin: '100px'
|
|
18227
18223
|
}
|
|
18228
18224
|
}, {
|
|
@@ -18295,8 +18291,6 @@ const SelectTextField$2 = (props, {
|
|
|
18295
18291
|
const isFullLoading = listStatus === 'loading';
|
|
18296
18292
|
const isLoadingMore = listStatus === 'loadingMore';
|
|
18297
18293
|
const isError = listStatus === 'error';
|
|
18298
|
-
// Prevent firing during loading or error states to avoid duplicate fetches.
|
|
18299
|
-
const isInfiniteScrollEnabled = !listStatus || listStatus === 'idle';
|
|
18300
18294
|
return /*#__PURE__*/jsxs(Combobox.Provider, {
|
|
18301
18295
|
onOpen: onOpen,
|
|
18302
18296
|
children: [/*#__PURE__*/jsx(Combobox.Input, {
|
|
@@ -18327,7 +18321,11 @@ const SelectTextField$2 = (props, {
|
|
|
18327
18321
|
}, {
|
|
18328
18322
|
Combobox
|
|
18329
18323
|
}), afterOptions, onLoadMore && InfiniteScroll && /*#__PURE__*/jsx(InfiniteScroll, {
|
|
18330
|
-
callback:
|
|
18324
|
+
callback: () => {
|
|
18325
|
+
// Guard: prevent firing during loading or error states to avoid duplicate fetches.
|
|
18326
|
+
if (listStatus && listStatus !== 'idle') return;
|
|
18327
|
+
onLoadMore();
|
|
18328
|
+
},
|
|
18331
18329
|
options: infiniteScrollOptions
|
|
18332
18330
|
}), isLoadingMore && /*#__PURE__*/jsx(Combobox.OptionSkeleton, {
|
|
18333
18331
|
count: 1
|
|
@@ -18415,14 +18413,7 @@ const SelectTextField$1 = props => {
|
|
|
18415
18413
|
// Wrap the consumer's renderOption to inject core-computed props
|
|
18416
18414
|
// (`value`, `isSelected`, `description`, `key`) into the returned <Combobox.Option>.
|
|
18417
18415
|
const wrappedRenderOption = wrapRenderOption(renderOption);
|
|
18418
|
-
|
|
18419
|
-
// The list itself doesn't scroll — its ancestor `__scroll` wrapper does. The
|
|
18420
|
-
// IntersectionObserver root must be the actual scrolling/clipping element, or the
|
|
18421
|
-
// sentinel is trivially always "intersecting" its non-clipping `<ul>` parent.
|
|
18422
|
-
const [scrollContainer, setScrollContainer] = useState(null);
|
|
18423
|
-
const setListElement = useCallback(listElement => {
|
|
18424
|
-
setScrollContainer(listElement?.closest(`.${CLASSNAME$17}__scroll`) ?? null);
|
|
18425
|
-
}, []);
|
|
18416
|
+
const [listElement, setListElement] = useState(null);
|
|
18426
18417
|
const localInputRef = useRef(null);
|
|
18427
18418
|
const mergedInputRef = useMergeRefs(localInputRef, externalInputRef);
|
|
18428
18419
|
|
|
@@ -18572,7 +18563,7 @@ const SelectTextField$1 = props => {
|
|
|
18572
18563
|
beforeOptions,
|
|
18573
18564
|
onLoadMore,
|
|
18574
18565
|
infiniteScrollOptions: {
|
|
18575
|
-
root:
|
|
18566
|
+
root: listElement,
|
|
18576
18567
|
rootMargin: '100px'
|
|
18577
18568
|
}
|
|
18578
18569
|
}, {
|
|
@@ -20944,10 +20935,12 @@ const TabList$1 = props => {
|
|
|
20944
20935
|
className,
|
|
20945
20936
|
layout = DEFAULT_PROPS$7.layout,
|
|
20946
20937
|
position = DEFAULT_PROPS$7.position,
|
|
20938
|
+
role = 'tablist',
|
|
20947
20939
|
theme,
|
|
20948
20940
|
ref,
|
|
20949
20941
|
...forwardedProps
|
|
20950
20942
|
} = props;
|
|
20943
|
+
const LinkWrapper = role === 'navigation' ? 'nav' : 'div';
|
|
20951
20944
|
return /*#__PURE__*/jsx("div", {
|
|
20952
20945
|
ref: ref,
|
|
20953
20946
|
...forwardedProps,
|
|
@@ -20956,9 +20949,9 @@ const TabList$1 = props => {
|
|
|
20956
20949
|
[`position-${position}`]: Boolean(position),
|
|
20957
20950
|
[`theme-${theme}`]: Boolean(theme)
|
|
20958
20951
|
})),
|
|
20959
|
-
children: /*#__PURE__*/jsx(
|
|
20952
|
+
children: /*#__PURE__*/jsx(LinkWrapper, {
|
|
20960
20953
|
className: element$4('links'),
|
|
20961
|
-
role:
|
|
20954
|
+
role: role,
|
|
20962
20955
|
"aria-label": ariaLabel,
|
|
20963
20956
|
children: children
|
|
20964
20957
|
})
|
|
@@ -20970,6 +20963,8 @@ const TabList$1 = props => {
|
|
|
20970
20963
|
*
|
|
20971
20964
|
* Implements WAI-ARIA `tablist` role {@see https://www.w3.org/TR/wai-aria-practices-1.1/examples/tabs/tabs-1/tabs.html#rps_label}
|
|
20972
20965
|
*
|
|
20966
|
+
* Renders a `role="navigation"` landmark instead when used outside a `TabProvider` (nav-link mode).
|
|
20967
|
+
*
|
|
20973
20968
|
* @param props Component props.
|
|
20974
20969
|
* @param ref Component ref.
|
|
20975
20970
|
* @return React element.
|
|
@@ -20981,14 +20976,19 @@ const TabList = forwardRef((props, ref) => {
|
|
|
20981
20976
|
...forwardedProps
|
|
20982
20977
|
} = props;
|
|
20983
20978
|
const tabListRef = React__default.useRef(null);
|
|
20979
|
+
const role = useTabProviderContextState() === undefined ? 'navigation' : 'tablist';
|
|
20980
|
+
|
|
20981
|
+
// Classic roving tabindex (role="tab"). Disabled in nav-link mode: nav links keep their
|
|
20982
|
+
// native per-link Tab stops, so this path is never engaged there.
|
|
20984
20983
|
useRovingTabIndexContainer({
|
|
20985
|
-
containerRef: tabListRef,
|
|
20984
|
+
containerRef: role === 'navigation' ? null : tabListRef,
|
|
20986
20985
|
itemSelector: '[role="tab"]'
|
|
20987
20986
|
});
|
|
20988
20987
|
return TabList$1({
|
|
20988
|
+
...forwardedProps,
|
|
20989
20989
|
theme,
|
|
20990
|
-
|
|
20991
|
-
|
|
20990
|
+
role,
|
|
20991
|
+
ref: mergeRefs(ref, tabListRef)
|
|
20992
20992
|
});
|
|
20993
20993
|
});
|
|
20994
20994
|
TabList.displayName = COMPONENT_NAME$6;
|
|
@@ -21014,9 +21014,11 @@ const {
|
|
|
21014
21014
|
} = bem(CLASSNAME$6);
|
|
21015
21015
|
|
|
21016
21016
|
/**
|
|
21017
|
-
* Tab component.
|
|
21018
|
-
*
|
|
21019
|
-
*
|
|
21017
|
+
* Tab component. Two modes keyed on `TabProvider` presence (via the wrapper-resolved `role`):
|
|
21018
|
+
* tab mode (`role === 'tab'`, inside a provider) implements the WAI-ARIA `tab` role
|
|
21019
|
+
* {@see https://www.w3.org/TR/wai-aria-practices-1.1/examples/tabs/tabs-1/tabs.html#rps_label};
|
|
21020
|
+
* nav-link mode (no provider) renders plain link semantics (`aria-current`, no tab role/aria).
|
|
21021
|
+
* `as` only selects the rendered element and applies in both modes.
|
|
21020
21022
|
*
|
|
21021
21023
|
* @param props Component props.
|
|
21022
21024
|
* @param ref Component ref.
|
|
@@ -21024,6 +21026,7 @@ const {
|
|
|
21024
21026
|
*/
|
|
21025
21027
|
const Tab$1 = props => {
|
|
21026
21028
|
const {
|
|
21029
|
+
as = 'button',
|
|
21027
21030
|
className,
|
|
21028
21031
|
icon,
|
|
21029
21032
|
iconProps = {},
|
|
@@ -21031,6 +21034,7 @@ const Tab$1 = props => {
|
|
|
21031
21034
|
isDisabled,
|
|
21032
21035
|
id,
|
|
21033
21036
|
isActive,
|
|
21037
|
+
role,
|
|
21034
21038
|
label,
|
|
21035
21039
|
handleFocus,
|
|
21036
21040
|
handleKeyPress,
|
|
@@ -21040,107 +21044,145 @@ const Tab$1 = props => {
|
|
|
21040
21044
|
changeToTab,
|
|
21041
21045
|
tabPanelId,
|
|
21042
21046
|
shouldActivateOnFocus,
|
|
21043
|
-
tabId,
|
|
21044
21047
|
Icon,
|
|
21045
21048
|
Text,
|
|
21046
21049
|
ref,
|
|
21047
21050
|
...forwardedProps
|
|
21048
21051
|
} = props;
|
|
21049
|
-
|
|
21050
|
-
|
|
21051
|
-
|
|
21052
|
-
|
|
21053
|
-
|
|
21054
|
-
|
|
21055
|
-
|
|
21056
|
-
|
|
21057
|
-
|
|
21052
|
+
let rawClickableProps;
|
|
21053
|
+
if (role === 'tab') {
|
|
21054
|
+
// Mode: WAI-ARIA `tab` role (inside a TabProvider)
|
|
21055
|
+
const changeToCurrentTab = () => {
|
|
21056
|
+
if (isAnyDisabled) {
|
|
21057
|
+
return;
|
|
21058
|
+
}
|
|
21059
|
+
changeToTab?.();
|
|
21060
|
+
};
|
|
21061
|
+
const onFocus = event => {
|
|
21062
|
+
handleFocus?.(event);
|
|
21063
|
+
if (shouldActivateOnFocus) {
|
|
21064
|
+
changeToCurrentTab();
|
|
21065
|
+
}
|
|
21066
|
+
};
|
|
21067
|
+
const onKeyPress = event => {
|
|
21068
|
+
handleKeyPress?.(event);
|
|
21069
|
+
if (event.key !== 'Enter' || isAnyDisabled) {
|
|
21070
|
+
return;
|
|
21071
|
+
}
|
|
21058
21072
|
changeToCurrentTab();
|
|
21059
|
-
}
|
|
21060
|
-
|
|
21061
|
-
|
|
21062
|
-
|
|
21063
|
-
|
|
21064
|
-
|
|
21065
|
-
|
|
21066
|
-
|
|
21067
|
-
|
|
21068
|
-
|
|
21069
|
-
|
|
21070
|
-
|
|
21071
|
-
|
|
21072
|
-
|
|
21073
|
+
};
|
|
21074
|
+
rawClickableProps = {
|
|
21075
|
+
...forwardedProps,
|
|
21076
|
+
'aria-disabled': isAnyDisabled ? 'true' : 'false',
|
|
21077
|
+
handleClick: changeToCurrentTab,
|
|
21078
|
+
onFocus,
|
|
21079
|
+
role: 'tab',
|
|
21080
|
+
'aria-selected': isActive,
|
|
21081
|
+
'aria-controls': tabPanelId,
|
|
21082
|
+
[keyPressProp]: onKeyPress,
|
|
21083
|
+
[tabIndexProp]: isActive ? 0 : tabIndex
|
|
21084
|
+
};
|
|
21085
|
+
} else {
|
|
21086
|
+
// Mode: nav link
|
|
21087
|
+
const {
|
|
21088
|
+
onClick,
|
|
21089
|
+
...rest
|
|
21090
|
+
} = forwardedProps;
|
|
21091
|
+
rawClickableProps = {
|
|
21092
|
+
...rest,
|
|
21093
|
+
isDisabled,
|
|
21094
|
+
handleClick: onClick,
|
|
21095
|
+
'aria-current': isActive ? 'page' : undefined
|
|
21096
|
+
};
|
|
21097
|
+
}
|
|
21098
|
+
return RawClickable({
|
|
21099
|
+
...rawClickableProps,
|
|
21100
|
+
as,
|
|
21101
|
+
id,
|
|
21073
21102
|
className: classnames(className, block$6({
|
|
21074
21103
|
'is-active': isActive,
|
|
21075
21104
|
'is-disabled': isAnyDisabled
|
|
21076
21105
|
})),
|
|
21077
|
-
|
|
21078
|
-
|
|
21079
|
-
|
|
21080
|
-
|
|
21081
|
-
|
|
21082
|
-
|
|
21083
|
-
|
|
21084
|
-
|
|
21085
|
-
|
|
21086
|
-
|
|
21087
|
-
|
|
21088
|
-
|
|
21089
|
-
}), label && /*#__PURE__*/jsx(Text, {
|
|
21090
|
-
as: "span",
|
|
21091
|
-
truncate: true,
|
|
21092
|
-
children: label
|
|
21093
|
-
})]
|
|
21106
|
+
ref: ref,
|
|
21107
|
+
children: /*#__PURE__*/jsxs(Fragment, {
|
|
21108
|
+
children: [icon && /*#__PURE__*/jsx(Icon, {
|
|
21109
|
+
icon: icon,
|
|
21110
|
+
size: Size.xs,
|
|
21111
|
+
...iconProps
|
|
21112
|
+
}), label && /*#__PURE__*/jsx(Text, {
|
|
21113
|
+
as: "span",
|
|
21114
|
+
truncate: true,
|
|
21115
|
+
children: label
|
|
21116
|
+
})]
|
|
21117
|
+
})
|
|
21094
21118
|
});
|
|
21095
21119
|
};
|
|
21096
21120
|
|
|
21097
21121
|
/**
|
|
21098
|
-
* Defines the props of the component.
|
|
21122
|
+
* Defines the props of the component. Polymorphic on `as` (element selection only): `as` picks the
|
|
21123
|
+
* rendered element (`as="a"` with required `href`, or `as={RouterLink}`), while the mode
|
|
21124
|
+
* (`role="tab"` vs nav-link) is driven by `TabProvider` presence. The forwarded ref type follows `as`.
|
|
21099
21125
|
*/
|
|
21100
21126
|
|
|
21101
21127
|
/**
|
|
21102
21128
|
* Tab component.
|
|
21103
21129
|
*
|
|
21104
21130
|
* Implements WAI-ARIA `tab` role {@see https://www.w3.org/TR/wai-aria-practices-1.1/examples/tabs/tabs-1/tabs.html#rps_label}
|
|
21131
|
+
* when rendered inside a `TabProvider`.
|
|
21132
|
+
*
|
|
21133
|
+
* Outside a `TabProvider` (nav-link mode): plain link, no `role="tab"`/roving tabindex/`changeToTab`
|
|
21134
|
+
* dispatch — only `aria-current` marks the active item.
|
|
21105
21135
|
*
|
|
21106
21136
|
* @param props Component props.
|
|
21107
|
-
* @param ref Component ref.
|
|
21137
|
+
* @param ref Component ref (type follows `as`).
|
|
21108
21138
|
* @return React element.
|
|
21109
21139
|
*/
|
|
21110
|
-
const Tab =
|
|
21140
|
+
const Tab = Object.assign(forwardRefPolymorphic((props, ref) => {
|
|
21111
21141
|
const {
|
|
21112
21142
|
isAnyDisabled,
|
|
21113
21143
|
otherProps
|
|
21114
21144
|
} = useDisableStateProps(props);
|
|
21115
21145
|
const {
|
|
21146
|
+
as = 'button',
|
|
21116
21147
|
isActive: propIsActive,
|
|
21117
21148
|
id,
|
|
21118
21149
|
onFocus,
|
|
21119
21150
|
onKeyPress,
|
|
21120
21151
|
...forwardedProps
|
|
21121
21152
|
} = otherProps;
|
|
21153
|
+
|
|
21154
|
+
// Register into the provider (if any) so it can track this tab's index / active state.
|
|
21122
21155
|
const tabState = useTabProviderContext('tab', id);
|
|
21156
|
+
// In a provider => tab mode (role="tab"); outside => nav-link mode. Mirrors TabList's role.
|
|
21157
|
+
const inProvider = tabState !== undefined;
|
|
21123
21158
|
const {
|
|
21124
21159
|
isLazy: _isLazy,
|
|
21160
|
+
tabId,
|
|
21125
21161
|
...state
|
|
21126
21162
|
} = tabState ?? {};
|
|
21163
|
+
// Without a provider there's no active index, so this collapses to the caller-provided value.
|
|
21127
21164
|
const isActive = propIsActive || state?.isActive;
|
|
21128
21165
|
return Tab$1({
|
|
21129
|
-
|
|
21166
|
+
...forwardedProps,
|
|
21130
21167
|
...state,
|
|
21168
|
+
as,
|
|
21169
|
+
role: inProvider ? 'tab' : undefined,
|
|
21131
21170
|
Icon,
|
|
21132
21171
|
Text,
|
|
21133
21172
|
ref,
|
|
21173
|
+
// Falls back to the caller-provided `id` when there's no TabProvider to generate one.
|
|
21174
|
+
id: tabId || id,
|
|
21134
21175
|
isActive,
|
|
21135
21176
|
isAnyDisabled,
|
|
21177
|
+
isDisabled: isAnyDisabled,
|
|
21136
21178
|
handleFocus: onFocus,
|
|
21137
|
-
handleKeyPress: onKeyPress
|
|
21138
|
-
...forwardedProps
|
|
21179
|
+
handleKeyPress: onKeyPress
|
|
21139
21180
|
});
|
|
21181
|
+
}), {
|
|
21182
|
+
displayName: COMPONENT_NAME$5,
|
|
21183
|
+
className: CLASSNAME$6,
|
|
21184
|
+
defaultProps: DEFAULT_PROPS$6
|
|
21140
21185
|
});
|
|
21141
|
-
Tab.displayName = COMPONENT_NAME$5;
|
|
21142
|
-
Tab.className = CLASSNAME$6;
|
|
21143
|
-
Tab.defaultProps = DEFAULT_PROPS$6;
|
|
21144
21186
|
|
|
21145
21187
|
/**
|
|
21146
21188
|
* Component display name.
|