@vitus-labs/elements 2.0.0-beta.0 → 2.0.0-beta.1
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/lib/index.d.ts +24 -11
- package/lib/index.js +327 -251
- package/lib/vitus-labs-elements.native.js +98 -130
- package/package.json +10 -11
- package/LICENSE +0 -21
package/lib/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Provider } from "@vitus-labs/unistyle";
|
|
2
2
|
import { BreakpointKeys, HTMLTags, HTMLTextTags, config, render } from "@vitus-labs/core";
|
|
3
|
-
import * as react from "react";
|
|
4
|
-
import { ComponentType, FC, ForwardRefExoticComponent, ForwardedRef,
|
|
3
|
+
import * as _$react from "react";
|
|
4
|
+
import { ComponentType, FC, ForwardRefExoticComponent, ForwardedRef, ReactElement, ReactNode } from "react";
|
|
5
5
|
|
|
6
6
|
//#region src/types.d.ts
|
|
7
7
|
type ExtractNullableKeys<T> = { [P in keyof T as T[P] extends null | undefined ? never : P]: T[P] };
|
|
@@ -24,8 +24,9 @@ type Direction = ContentDirection | ContentDirection[] | Partial<Record<Breakpoi
|
|
|
24
24
|
type ResponsiveBoolType = ContentBoolean | ContentBoolean[] | Partial<Record<BreakpointKeys, ContentBoolean>>;
|
|
25
25
|
type Responsive = ContentSimpleValue | ContentSimpleValue[] | Partial<Record<BreakpointKeys, number | string>>;
|
|
26
26
|
type ExtendCss = Css | Css[] | Partial<Record<BreakpointKeys, Css>>;
|
|
27
|
-
type
|
|
28
|
-
|
|
27
|
+
type VLComponent<P extends Record<string, any> = {}> = ((props: P & {
|
|
28
|
+
ref?: any;
|
|
29
|
+
}) => ReactElement | null) & VLStatic;
|
|
29
30
|
interface VLStatic {
|
|
30
31
|
/**
|
|
31
32
|
* React displayName
|
|
@@ -291,7 +292,9 @@ type Props = Partial<{
|
|
|
291
292
|
*/
|
|
292
293
|
afterContentCss: ExtendCss;
|
|
293
294
|
}>;
|
|
294
|
-
type VLElement<P extends Record<string, unknown> = {}> =
|
|
295
|
+
type VLElement<P extends Record<string, unknown> = {}> = ((props: Props & P & {
|
|
296
|
+
ref?: any;
|
|
297
|
+
}) => ReactElement | null) & VLStatic;
|
|
295
298
|
//#endregion
|
|
296
299
|
//#region src/Element/component.d.ts
|
|
297
300
|
declare const Component: VLElement;
|
|
@@ -385,10 +388,13 @@ declare const Component$3: FC<Context & {
|
|
|
385
388
|
children: ReactNode;
|
|
386
389
|
}>;
|
|
387
390
|
//#endregion
|
|
388
|
-
//#region src/Overlay/
|
|
391
|
+
//#region src/Overlay/positionMath.d.ts
|
|
389
392
|
type Align$1 = 'bottom' | 'top' | 'left' | 'right';
|
|
390
393
|
type AlignX$2 = 'left' | 'center' | 'right';
|
|
391
394
|
type AlignY$2 = 'bottom' | 'top' | 'center';
|
|
395
|
+
type OverlayType = 'dropdown' | 'tooltip' | 'popover' | 'modal' | 'custom';
|
|
396
|
+
//#endregion
|
|
397
|
+
//#region src/Overlay/useOverlay.d.ts
|
|
392
398
|
type UseOverlayProps = Partial<{
|
|
393
399
|
/**
|
|
394
400
|
* Defines default state whether **Overlay** component should be active.
|
|
@@ -412,7 +418,7 @@ type UseOverlayProps = Partial<{
|
|
|
412
418
|
* has different positioning calculations than others.
|
|
413
419
|
* @defaultValue `dropdown`
|
|
414
420
|
*/
|
|
415
|
-
type:
|
|
421
|
+
type: OverlayType;
|
|
416
422
|
/**
|
|
417
423
|
* Defines how `content` is treated regarding CSS positioning.
|
|
418
424
|
* @defaultValue `fixed`
|
|
@@ -461,6 +467,12 @@ type UseOverlayProps = Partial<{
|
|
|
461
467
|
* @defaultValue `true`
|
|
462
468
|
*/
|
|
463
469
|
closeOnEsc: boolean;
|
|
470
|
+
/**
|
|
471
|
+
* Delay in milliseconds before hiding content on hover leave. Bridges the
|
|
472
|
+
* gap between trigger and content elements to prevent flicker.
|
|
473
|
+
* @defaultValue `100`
|
|
474
|
+
*/
|
|
475
|
+
hoverDelay: number;
|
|
464
476
|
/**
|
|
465
477
|
* When set to `true`, **Overlay** is automatically closed and is blocked for
|
|
466
478
|
* being opened.
|
|
@@ -491,11 +503,12 @@ declare const useOverlay: ({
|
|
|
491
503
|
throttleDelay,
|
|
492
504
|
parentContainer,
|
|
493
505
|
closeOnEsc,
|
|
506
|
+
hoverDelay,
|
|
494
507
|
disabled,
|
|
495
508
|
onOpen,
|
|
496
509
|
onClose
|
|
497
510
|
}?: Partial<UseOverlayProps>) => {
|
|
498
|
-
triggerRef: react.RefObject<HTMLElement | null>;
|
|
511
|
+
triggerRef: _$react.RefObject<HTMLElement | null>;
|
|
499
512
|
contentRef: (node: HTMLElement | null) => void;
|
|
500
513
|
active: boolean;
|
|
501
514
|
align: Align$1;
|
|
@@ -506,8 +519,8 @@ declare const useOverlay: ({
|
|
|
506
519
|
blocked: boolean;
|
|
507
520
|
setBlocked: () => void;
|
|
508
521
|
setUnblocked: () => void;
|
|
509
|
-
Provider: react.FC<Context & {
|
|
510
|
-
children: react.ReactNode;
|
|
522
|
+
Provider: _$react.FC<Context & {
|
|
523
|
+
children: _$react.ReactNode;
|
|
511
524
|
}>;
|
|
512
525
|
};
|
|
513
526
|
//#endregion
|
|
@@ -601,7 +614,7 @@ type Props$5 = Partial<{
|
|
|
601
614
|
*/
|
|
602
615
|
css: ExtendCss;
|
|
603
616
|
}>;
|
|
604
|
-
declare const Component$5:
|
|
617
|
+
declare const Component$5: VLComponent<Props$5> & {
|
|
605
618
|
isText?: true;
|
|
606
619
|
};
|
|
607
620
|
//#endregion
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Provider, alignContent, extendCss, makeItResponsive, value } from "@vitus-labs/unistyle";
|
|
2
2
|
import { config, context, isEmpty, omit, pick, render, throttle } from "@vitus-labs/core";
|
|
3
|
-
import { Children, createContext,
|
|
3
|
+
import { Children, createContext, memo, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { isFragment } from "react-is";
|
|
6
6
|
import { createPortal } from "react-dom";
|
|
@@ -214,13 +214,12 @@ const isWebFixNeeded = (tag) => {
|
|
|
214
214
|
//#region src/helpers/Wrapper/component.tsx
|
|
215
215
|
/**
|
|
216
216
|
* Wrapper component that serves as the outermost styled container for Element.
|
|
217
|
-
*
|
|
218
|
-
* detects button/fieldset/legend tags and applies a two-layer flex fix
|
|
217
|
+
* On web, it detects button/fieldset/legend tags and applies a two-layer flex fix
|
|
219
218
|
* (parent + child Styled) because these HTML elements do not natively
|
|
220
219
|
* support `display: flex` consistently across browsers.
|
|
221
220
|
*/
|
|
222
221
|
const DEV_PROPS = IS_DEVELOPMENT ? { "data-vl-element": "Element" } : {};
|
|
223
|
-
const Component$8 =
|
|
222
|
+
const Component$8 = ({ children, ref, tag, block, extendCss, direction, alignX, alignY, equalCols, isInline, ...props }) => {
|
|
224
223
|
const COMMON_PROPS = {
|
|
225
224
|
...props,
|
|
226
225
|
...DEV_PROPS,
|
|
@@ -276,7 +275,7 @@ const Component$8 = forwardRef(({ children, tag, block, extendCss, direction, al
|
|
|
276
275
|
children
|
|
277
276
|
})
|
|
278
277
|
});
|
|
279
|
-
}
|
|
278
|
+
};
|
|
280
279
|
|
|
281
280
|
//#endregion
|
|
282
281
|
//#region src/helpers/Wrapper/index.ts
|
|
@@ -386,7 +385,7 @@ const defaultDirection = "inline";
|
|
|
386
385
|
const defaultContentDirection = "rows";
|
|
387
386
|
const defaultAlignX = "left";
|
|
388
387
|
const defaultAlignY = "center";
|
|
389
|
-
const Component$7 =
|
|
388
|
+
const Component$7 = ({ innerRef, ref, tag, label, content, children, beforeContent, afterContent, equalBeforeAfter, block, equalCols, gap, direction, alignX = defaultAlignX, alignY = defaultAlignY, css, contentCss, beforeContentCss, afterContentCss, contentDirection = defaultContentDirection, contentAlignX = defaultAlignX, contentAlignY = defaultAlignY, beforeContentDirection = defaultDirection, beforeContentAlignX = defaultAlignX, beforeContentAlignY = defaultAlignY, afterContentDirection = defaultDirection, afterContentAlignX = defaultAlignX, afterContentAlignY = defaultAlignY, ...props }) => {
|
|
390
389
|
const shouldBeEmpty = !!props.dangerouslySetInnerHTML || getShouldBeEmpty(tag);
|
|
391
390
|
const isSimpleElement = !beforeContent && !afterContent;
|
|
392
391
|
const CHILDREN = children ?? content ?? label;
|
|
@@ -425,7 +424,13 @@ const Component$7 = forwardRef(({ innerRef, tag, label, content, children, befor
|
|
|
425
424
|
}, [externalRef]);
|
|
426
425
|
useLayoutEffect(() => {
|
|
427
426
|
if (!equalBeforeAfter || !beforeContent || !afterContent) return;
|
|
428
|
-
|
|
427
|
+
const node = equalizeRef.current;
|
|
428
|
+
if (!node) return;
|
|
429
|
+
equalize(node, direction);
|
|
430
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
431
|
+
const observer = new ResizeObserver(() => equalize(node, direction));
|
|
432
|
+
observer.observe(node);
|
|
433
|
+
return () => observer.disconnect();
|
|
429
434
|
}, [
|
|
430
435
|
equalBeforeAfter,
|
|
431
436
|
beforeContent,
|
|
@@ -488,7 +493,7 @@ const Component$7 = forwardRef(({ innerRef, tag, label, content, children, befor
|
|
|
488
493
|
})
|
|
489
494
|
]
|
|
490
495
|
});
|
|
491
|
-
}
|
|
496
|
+
};
|
|
492
497
|
const name$5 = `${PKG_NAME}/Element`;
|
|
493
498
|
Component$7.displayName = name$5;
|
|
494
499
|
Component$7.pkgName = PKG_NAME;
|
|
@@ -508,27 +513,6 @@ var Element_default = Component$7;
|
|
|
508
513
|
* wrapped with `wrapComponent`. Children always take priority over the
|
|
509
514
|
* component+data prop pattern.
|
|
510
515
|
*/
|
|
511
|
-
const classifyData = (data) => {
|
|
512
|
-
const items = data.filter((item) => item != null && !(typeof item === "object" && isEmpty(item)));
|
|
513
|
-
if (items.length === 0) return null;
|
|
514
|
-
let isSimple = true;
|
|
515
|
-
let isComplex = true;
|
|
516
|
-
for (const item of items) if (typeof item === "string" || typeof item === "number") isComplex = false;
|
|
517
|
-
else if (typeof item === "object") isSimple = false;
|
|
518
|
-
else {
|
|
519
|
-
isSimple = false;
|
|
520
|
-
isComplex = false;
|
|
521
|
-
}
|
|
522
|
-
if (isSimple) return {
|
|
523
|
-
type: "simple",
|
|
524
|
-
data: items
|
|
525
|
-
};
|
|
526
|
-
if (isComplex) return {
|
|
527
|
-
type: "complex",
|
|
528
|
-
data: items
|
|
529
|
-
};
|
|
530
|
-
return null;
|
|
531
|
-
};
|
|
532
516
|
const RESERVED_PROPS = [
|
|
533
517
|
"children",
|
|
534
518
|
"component",
|
|
@@ -539,7 +523,7 @@ const RESERVED_PROPS = [
|
|
|
539
523
|
"itemProps",
|
|
540
524
|
"wrapProps"
|
|
541
525
|
];
|
|
542
|
-
const
|
|
526
|
+
const buildExtendedProps = (i, length) => {
|
|
543
527
|
const position = i + 1;
|
|
544
528
|
return {
|
|
545
529
|
index: i,
|
|
@@ -550,106 +534,96 @@ const attachItemProps = ({ i, length }) => {
|
|
|
550
534
|
position
|
|
551
535
|
};
|
|
552
536
|
};
|
|
553
|
-
const
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
const renderChild = (child, total = 1, i = 0) => {
|
|
562
|
-
if (!itemProps && !Wrapper) return child;
|
|
563
|
-
const extendedProps = attachItemProps({
|
|
564
|
-
i,
|
|
565
|
-
length: total
|
|
566
|
-
});
|
|
567
|
-
const finalItemProps = itemProps ? injectItemProps({}, extendedProps) : {};
|
|
568
|
-
if (Wrapper) return /* @__PURE__ */ jsx(Wrapper, {
|
|
569
|
-
...wrapProps ? injectWrapItemProps({}, extendedProps) : {},
|
|
570
|
-
children: render(child, finalItemProps)
|
|
571
|
-
}, i);
|
|
572
|
-
return render(child, {
|
|
573
|
-
key: i,
|
|
574
|
-
...finalItemProps
|
|
575
|
-
});
|
|
576
|
-
};
|
|
577
|
-
const renderChildren = () => {
|
|
578
|
-
if (!children) return null;
|
|
579
|
-
if (Array.isArray(children)) return Children.map(children, (item, i) => renderChild(item, children.length, i));
|
|
580
|
-
if (isFragment(children)) {
|
|
581
|
-
const fragmentChildren = children.props.children;
|
|
582
|
-
const childrenLength = fragmentChildren.length;
|
|
583
|
-
return fragmentChildren.map((item, i) => renderChild(item, childrenLength, i));
|
|
584
|
-
}
|
|
585
|
-
return renderChild(children);
|
|
586
|
-
};
|
|
587
|
-
const renderSimpleArray = (data) => {
|
|
588
|
-
const { length } = data;
|
|
589
|
-
if (length === 0) return null;
|
|
590
|
-
return data.map((item, i) => {
|
|
591
|
-
const key = getKey(item, i);
|
|
592
|
-
const keyName = valueName ?? "children";
|
|
593
|
-
const extendedProps = attachItemProps({
|
|
594
|
-
i,
|
|
595
|
-
length
|
|
596
|
-
});
|
|
597
|
-
const finalItemProps = {
|
|
598
|
-
...itemProps ? injectItemProps({ [keyName]: item }, extendedProps) : {},
|
|
599
|
-
[keyName]: item
|
|
600
|
-
};
|
|
601
|
-
if (Wrapper) return /* @__PURE__ */ jsx(Wrapper, {
|
|
602
|
-
...wrapProps ? injectWrapItemProps({ [keyName]: item }, extendedProps) : {},
|
|
603
|
-
children: render(component, finalItemProps)
|
|
604
|
-
}, key);
|
|
605
|
-
return render(component, {
|
|
606
|
-
key,
|
|
607
|
-
...finalItemProps
|
|
608
|
-
});
|
|
609
|
-
});
|
|
610
|
-
};
|
|
611
|
-
const getObjectKey = (item, index) => {
|
|
612
|
-
if (!itemKey) return item.key ?? item.id ?? item.itemId ?? index;
|
|
613
|
-
if (typeof itemKey === "function") return itemKey(item, index);
|
|
614
|
-
if (typeof itemKey === "string") return item[itemKey];
|
|
615
|
-
return index;
|
|
537
|
+
const resolveCallback = (cb, source, ext) => {
|
|
538
|
+
if (!cb) return {};
|
|
539
|
+
return typeof cb === "function" ? cb(source, ext) : cb;
|
|
540
|
+
};
|
|
541
|
+
const renderSpec = (spec, ext, itemProps, wrapProps, Wrapper) => {
|
|
542
|
+
const finalItemProps = {
|
|
543
|
+
...resolveCallback(itemProps, spec.source, ext),
|
|
544
|
+
...spec.base
|
|
616
545
|
};
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
const extendedProps = attachItemProps({
|
|
625
|
-
i,
|
|
626
|
-
length
|
|
627
|
-
});
|
|
628
|
-
const finalItemProps = {
|
|
629
|
-
...itemProps ? injectItemProps(item, extendedProps) : {},
|
|
630
|
-
...restItem
|
|
631
|
-
};
|
|
632
|
-
if (Wrapper && !itemComponent) return /* @__PURE__ */ jsx(Wrapper, {
|
|
633
|
-
...wrapProps ? injectWrapItemProps(item, extendedProps) : {},
|
|
634
|
-
children: render(renderItem, finalItemProps)
|
|
635
|
-
}, key);
|
|
636
|
-
return render(renderItem, {
|
|
637
|
-
key,
|
|
638
|
-
...finalItemProps
|
|
639
|
-
});
|
|
640
|
-
});
|
|
546
|
+
if (Wrapper && !spec.skipWrap) return /* @__PURE__ */ jsx(Wrapper, {
|
|
547
|
+
...resolveCallback(wrapProps, spec.source, ext),
|
|
548
|
+
children: spec.isNode ? render(spec.target, finalItemProps) : render(spec.target, finalItemProps)
|
|
549
|
+
}, spec.key);
|
|
550
|
+
const propsWithKey = {
|
|
551
|
+
key: spec.key,
|
|
552
|
+
...finalItemProps
|
|
641
553
|
};
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
554
|
+
return spec.isNode ? render(spec.target, propsWithKey) : render(spec.target, propsWithKey);
|
|
555
|
+
};
|
|
556
|
+
/** Normalize children (single, array, or fragment) into an array of nodes. */
|
|
557
|
+
const flattenChildren = (children) => {
|
|
558
|
+
if (Array.isArray(children)) return children;
|
|
559
|
+
if (isFragment(children)) return children.props.children;
|
|
560
|
+
return [children];
|
|
561
|
+
};
|
|
562
|
+
/** Drop nullish entries and empty objects (matches legacy behavior). */
|
|
563
|
+
const filterValidItems = (data) => data.filter((item) => item != null && !(typeof item === "object" && isEmpty(item)));
|
|
564
|
+
/** Determine if the array is uniformly simple (string/number) or complex (object). Mixed → null. */
|
|
565
|
+
const detectKind = (items) => {
|
|
566
|
+
let kind = null;
|
|
567
|
+
for (const item of items) {
|
|
568
|
+
const t = typeof item === "string" || typeof item === "number" ? "simple" : typeof item === "object" ? "complex" : null;
|
|
569
|
+
if (t === null) return null;
|
|
570
|
+
if (kind === null) kind = t;
|
|
571
|
+
else if (kind !== t) return null;
|
|
572
|
+
}
|
|
573
|
+
return kind;
|
|
574
|
+
};
|
|
575
|
+
const objectKey = (item, index, itemKey) => {
|
|
576
|
+
if (!itemKey) return item.key ?? item.id ?? item.itemId ?? index;
|
|
577
|
+
if (typeof itemKey === "function") return itemKey(item, index);
|
|
578
|
+
if (typeof itemKey === "string") return item[itemKey] ?? index;
|
|
579
|
+
return index;
|
|
580
|
+
};
|
|
581
|
+
const buildChildrenSpecs = (children) => flattenChildren(children).map((node, i) => ({
|
|
582
|
+
key: i,
|
|
583
|
+
target: node,
|
|
584
|
+
source: {},
|
|
585
|
+
base: {},
|
|
586
|
+
isNode: true,
|
|
587
|
+
skipWrap: false
|
|
588
|
+
}));
|
|
589
|
+
const buildSimpleSpecs = (items, component, valueName, itemKey) => {
|
|
590
|
+
const keyName = valueName ?? "children";
|
|
591
|
+
return items.map((value, i) => ({
|
|
592
|
+
key: typeof itemKey === "function" ? itemKey(value, i) : i,
|
|
593
|
+
target: component,
|
|
594
|
+
source: { [keyName]: value },
|
|
595
|
+
base: { [keyName]: value },
|
|
596
|
+
isNode: false,
|
|
597
|
+
skipWrap: false
|
|
598
|
+
}));
|
|
599
|
+
};
|
|
600
|
+
const buildObjectSpecs = (items, component, itemKey) => items.map((item, i) => {
|
|
601
|
+
const { component: itemComponent, ...rest } = item;
|
|
602
|
+
return {
|
|
603
|
+
key: objectKey(rest, i, itemKey),
|
|
604
|
+
target: itemComponent ?? component,
|
|
605
|
+
source: item,
|
|
606
|
+
base: rest,
|
|
607
|
+
isNode: false,
|
|
608
|
+
skipWrap: Boolean(itemComponent)
|
|
651
609
|
};
|
|
652
|
-
|
|
610
|
+
});
|
|
611
|
+
const buildDataSpecs = (data, component, valueName, itemKey) => {
|
|
612
|
+
const items = filterValidItems(data);
|
|
613
|
+
if (items.length === 0) return null;
|
|
614
|
+
const kind = detectKind(items);
|
|
615
|
+
if (!kind) return null;
|
|
616
|
+
return kind === "simple" ? buildSimpleSpecs(items, component, valueName, itemKey) : buildObjectSpecs(items, component, itemKey);
|
|
617
|
+
};
|
|
618
|
+
const Component$6 = ({ itemKey, valueName, children, component, data, wrapComponent: Wrapper, wrapProps, itemProps }) => {
|
|
619
|
+
let specs = null;
|
|
620
|
+
if (children) {
|
|
621
|
+
if (!Array.isArray(children) && !isFragment(children) && !itemProps && !Wrapper) return children;
|
|
622
|
+
specs = buildChildrenSpecs(children);
|
|
623
|
+
} else if (component && Array.isArray(data)) specs = buildDataSpecs(data, component, valueName, itemKey);
|
|
624
|
+
if (!specs || specs.length === 0) return null;
|
|
625
|
+
const total = specs.length;
|
|
626
|
+
return Children.toArray(specs.map((spec, i) => renderSpec(spec, buildExtendedProps(i, total), itemProps, wrapProps, Wrapper)));
|
|
653
627
|
};
|
|
654
628
|
var component_default = Object.assign(memo(Component$6), {
|
|
655
629
|
isIterator: true,
|
|
@@ -669,7 +643,7 @@ var Iterator_default = component_default;
|
|
|
669
643
|
* is wrapped in an Element that receives all non-iterator props (e.g.,
|
|
670
644
|
* layout, alignment, css), allowing the list to be styled as a single block.
|
|
671
645
|
*/
|
|
672
|
-
const Component$5 =
|
|
646
|
+
const Component$5 = ({ rootElement = false, ref, ...props }) => {
|
|
673
647
|
const renderedList = /* @__PURE__ */ jsx(Iterator_default, { ...pick(props, Iterator_default.RESERVED_PROPS) });
|
|
674
648
|
if (!rootElement) return renderedList;
|
|
675
649
|
return /* @__PURE__ */ jsx(Element_default, {
|
|
@@ -677,7 +651,7 @@ const Component$5 = forwardRef(({ rootElement = false, ...props }, ref) => {
|
|
|
677
651
|
...omit(props, Iterator_default.RESERVED_PROPS),
|
|
678
652
|
children: renderedList
|
|
679
653
|
});
|
|
680
|
-
}
|
|
654
|
+
};
|
|
681
655
|
const name$4 = `${PKG_NAME}/List`;
|
|
682
656
|
Component$5.displayName = name$4;
|
|
683
657
|
Component$5.pkgName = PKG_NAME;
|
|
@@ -746,14 +720,12 @@ const Component = ({ children, blocked, setBlocked, setUnblocked }) => {
|
|
|
746
720
|
};
|
|
747
721
|
|
|
748
722
|
//#endregion
|
|
749
|
-
//#region src/Overlay/
|
|
723
|
+
//#region src/Overlay/positionMath.ts
|
|
750
724
|
/**
|
|
751
|
-
*
|
|
752
|
-
*
|
|
753
|
-
*
|
|
754
|
-
*
|
|
755
|
-
* Event handlers are throttled for performance, and nested overlay blocking
|
|
756
|
-
* is coordinated through the overlay context.
|
|
725
|
+
* Pure positioning math for the Overlay component. No React, no DOM mutations.
|
|
726
|
+
* Given the current trigger and content rects (plus alignment options), computes
|
|
727
|
+
* the final viewport-relative position and the alignment that was actually used
|
|
728
|
+
* (which may differ from the requested alignment when an edge would be clipped).
|
|
757
729
|
*/
|
|
758
730
|
const sel = (cond, a, b) => cond ? a : b;
|
|
759
731
|
const devWarn = (msg) => {
|
|
@@ -923,24 +895,192 @@ const processVisibilityEvent = (e, active, openOn, closeOn, isTrigger, isContent
|
|
|
923
895
|
else if (closeOn === "clickOnTrigger" && isTrigger(e)) hideContent();
|
|
924
896
|
else if (closeOn === "clickOutsideContent" && !isContent(e)) hideContent();
|
|
925
897
|
};
|
|
926
|
-
|
|
898
|
+
|
|
899
|
+
//#endregion
|
|
900
|
+
//#region src/Overlay/useEscapeKey.ts
|
|
901
|
+
/** Closes the overlay on Escape keypress when `enabled` and `active`. */
|
|
902
|
+
const useEscapeKey = (enabled, active, blocked, hide) => {
|
|
903
|
+
useEffect(() => {
|
|
904
|
+
if (!enabled || !active || blocked) return void 0;
|
|
905
|
+
const onKey = (e) => {
|
|
906
|
+
if (e.key === "Escape") hide();
|
|
907
|
+
};
|
|
908
|
+
window.addEventListener("keydown", onKey);
|
|
909
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
910
|
+
}, [
|
|
911
|
+
enabled,
|
|
912
|
+
active,
|
|
913
|
+
blocked,
|
|
914
|
+
hide
|
|
915
|
+
]);
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
//#endregion
|
|
919
|
+
//#region src/Overlay/useHoverListeners.ts
|
|
920
|
+
/**
|
|
921
|
+
* Hover-based open/close. Uses mouseenter/mouseleave on trigger + content
|
|
922
|
+
* (instead of window-level mousemove) and a configurable delay to bridge
|
|
923
|
+
* the gap between trigger and content elements without flicker.
|
|
924
|
+
*/
|
|
925
|
+
const useHoverListeners = ({ triggerRef, contentRef, isContentLoaded, active, blocked, disabled, openOn, closeOn, hoverDelay, showContent, hideContent }) => {
|
|
926
|
+
const hoverTimeoutRef = useRef(null);
|
|
927
|
+
useEffect(() => {
|
|
928
|
+
if (blocked || disabled || !(openOn === "hover" || closeOn === "hover")) return void 0;
|
|
929
|
+
const trigger = triggerRef.current;
|
|
930
|
+
const content = contentRef.current;
|
|
931
|
+
const clearHoverTimeout = () => {
|
|
932
|
+
if (hoverTimeoutRef.current != null) {
|
|
933
|
+
clearTimeout(hoverTimeoutRef.current);
|
|
934
|
+
hoverTimeoutRef.current = null;
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
const scheduleHide = () => {
|
|
938
|
+
clearHoverTimeout();
|
|
939
|
+
hoverTimeoutRef.current = setTimeout(hideContent, hoverDelay);
|
|
940
|
+
};
|
|
941
|
+
const onTriggerEnter = () => {
|
|
942
|
+
clearHoverTimeout();
|
|
943
|
+
if (openOn === "hover" && !active) showContent();
|
|
944
|
+
};
|
|
945
|
+
const onTriggerLeave = () => {
|
|
946
|
+
if (closeOn === "hover" && active) scheduleHide();
|
|
947
|
+
};
|
|
948
|
+
const onContentEnter = () => {
|
|
949
|
+
clearHoverTimeout();
|
|
950
|
+
};
|
|
951
|
+
const onContentLeave = () => {
|
|
952
|
+
if (closeOn === "hover" && active) scheduleHide();
|
|
953
|
+
};
|
|
954
|
+
if (trigger) {
|
|
955
|
+
trigger.addEventListener("mouseenter", onTriggerEnter);
|
|
956
|
+
trigger.addEventListener("mouseleave", onTriggerLeave);
|
|
957
|
+
}
|
|
958
|
+
if (content) {
|
|
959
|
+
content.addEventListener("mouseenter", onContentEnter);
|
|
960
|
+
content.addEventListener("mouseleave", onContentLeave);
|
|
961
|
+
}
|
|
962
|
+
return () => {
|
|
963
|
+
clearHoverTimeout();
|
|
964
|
+
if (trigger) {
|
|
965
|
+
trigger.removeEventListener("mouseenter", onTriggerEnter);
|
|
966
|
+
trigger.removeEventListener("mouseleave", onTriggerLeave);
|
|
967
|
+
}
|
|
968
|
+
if (content) {
|
|
969
|
+
content.removeEventListener("mouseenter", onContentEnter);
|
|
970
|
+
content.removeEventListener("mouseleave", onContentLeave);
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
}, [
|
|
974
|
+
active,
|
|
975
|
+
isContentLoaded,
|
|
976
|
+
blocked,
|
|
977
|
+
disabled,
|
|
978
|
+
openOn,
|
|
979
|
+
closeOn,
|
|
980
|
+
hoverDelay,
|
|
981
|
+
showContent,
|
|
982
|
+
hideContent
|
|
983
|
+
]);
|
|
984
|
+
};
|
|
985
|
+
|
|
986
|
+
//#endregion
|
|
987
|
+
//#region src/Overlay/useScrollReposition.ts
|
|
988
|
+
let modalOverflowCount = 0;
|
|
989
|
+
/**
|
|
990
|
+
* Window-level scroll/resize listeners that reposition active overlays and
|
|
991
|
+
* re-evaluate close-on-scroll behavior. Also manages the body overflow lock
|
|
992
|
+
* for modal overlays (refcounted across nested modals).
|
|
993
|
+
*/
|
|
994
|
+
const useWindowReposition = (active, type, handleContentPosition, handleVisibility) => {
|
|
995
|
+
useEffect(() => {
|
|
996
|
+
if (!active) return void 0;
|
|
997
|
+
const shouldSetOverflow = type === "modal";
|
|
998
|
+
const onScroll = (e) => {
|
|
999
|
+
handleContentPosition();
|
|
1000
|
+
handleVisibility(e);
|
|
1001
|
+
};
|
|
1002
|
+
if (shouldSetOverflow) {
|
|
1003
|
+
modalOverflowCount++;
|
|
1004
|
+
if (modalOverflowCount === 1) document.body.style.overflow = "hidden";
|
|
1005
|
+
}
|
|
1006
|
+
window.addEventListener("resize", handleContentPosition);
|
|
1007
|
+
window.addEventListener("scroll", onScroll, { passive: true });
|
|
1008
|
+
return () => {
|
|
1009
|
+
handleContentPosition.cancel();
|
|
1010
|
+
handleVisibility.cancel();
|
|
1011
|
+
if (shouldSetOverflow) {
|
|
1012
|
+
modalOverflowCount--;
|
|
1013
|
+
if (modalOverflowCount === 0) document.body.style.overflow = "";
|
|
1014
|
+
}
|
|
1015
|
+
window.removeEventListener("resize", handleContentPosition);
|
|
1016
|
+
window.removeEventListener("scroll", onScroll);
|
|
1017
|
+
};
|
|
1018
|
+
}, [
|
|
1019
|
+
active,
|
|
1020
|
+
type,
|
|
1021
|
+
handleContentPosition,
|
|
1022
|
+
handleVisibility
|
|
1023
|
+
]);
|
|
1024
|
+
};
|
|
1025
|
+
/**
|
|
1026
|
+
* Same as `useWindowReposition` but for a custom scrollable ancestor.
|
|
1027
|
+
* Locks the parent's overflow while the overlay is active (unless hover-driven,
|
|
1028
|
+
* which expects the parent to keep scrolling).
|
|
1029
|
+
*/
|
|
1030
|
+
const useParentContainerReposition = (active, parentContainer, closeOn, handleContentPosition, handleVisibility) => {
|
|
1031
|
+
useEffect(() => {
|
|
1032
|
+
if (!active || !parentContainer) return void 0;
|
|
1033
|
+
if (closeOn !== "hover") parentContainer.style.overflow = "hidden";
|
|
1034
|
+
const onScroll = (e) => {
|
|
1035
|
+
handleContentPosition();
|
|
1036
|
+
handleVisibility(e);
|
|
1037
|
+
};
|
|
1038
|
+
parentContainer.addEventListener("scroll", onScroll, { passive: true });
|
|
1039
|
+
return () => {
|
|
1040
|
+
parentContainer.style.overflow = "";
|
|
1041
|
+
parentContainer.removeEventListener("scroll", onScroll);
|
|
1042
|
+
};
|
|
1043
|
+
}, [
|
|
1044
|
+
active,
|
|
1045
|
+
parentContainer,
|
|
1046
|
+
closeOn,
|
|
1047
|
+
handleContentPosition,
|
|
1048
|
+
handleVisibility
|
|
1049
|
+
]);
|
|
1050
|
+
};
|
|
1051
|
+
const useScrollReposition = ({ active, type, parentContainer, closeOn, handleContentPosition, handleVisibility }) => {
|
|
1052
|
+
useWindowReposition(active, type, handleContentPosition, handleVisibility);
|
|
1053
|
+
useParentContainerReposition(active, parentContainer, closeOn, handleContentPosition, handleVisibility);
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
//#endregion
|
|
1057
|
+
//#region src/Overlay/useOverlay.tsx
|
|
1058
|
+
/**
|
|
1059
|
+
* Core hook powering the Overlay component. Manages open/close state, DOM
|
|
1060
|
+
* event listeners (click, hover, scroll, resize, ESC key), and dynamic
|
|
1061
|
+
* positioning of overlay content relative to its trigger. Supports dropdown,
|
|
1062
|
+
* tooltip, popover, and modal types with automatic edge-of-viewport flipping.
|
|
1063
|
+
*
|
|
1064
|
+
* Pure positioning math lives in `./positionMath`. Event-listener concerns
|
|
1065
|
+
* live in dedicated hooks: `./useEscapeKey`, `./useHoverListeners`,
|
|
1066
|
+
* `./useScrollReposition`.
|
|
1067
|
+
*/
|
|
1068
|
+
const useOverlay = ({ isOpen = false, openOn = "click", closeOn = "click", type = "dropdown", position = "fixed", align = "bottom", alignX = "left", alignY = "bottom", offsetX = 0, offsetY = 0, throttleDelay = 200, parentContainer, closeOnEsc = true, hoverDelay = 100, disabled, onOpen, onClose } = {}) => {
|
|
927
1069
|
const { rootSize } = useContext(context);
|
|
928
1070
|
const ctx = useOverlayContext();
|
|
929
1071
|
const [isContentLoaded, setContentLoaded] = useState(false);
|
|
930
1072
|
const [innerAlignX, setInnerAlignX] = useState(alignX);
|
|
931
1073
|
const [innerAlignY, setInnerAlignY] = useState(alignY);
|
|
932
|
-
const [
|
|
933
|
-
const
|
|
1074
|
+
const [blockedCount, setBlockedCount] = useState(0);
|
|
1075
|
+
const blocked = blockedCount > 0;
|
|
1076
|
+
const [active, setActive] = useState(isOpen);
|
|
934
1077
|
const triggerRef = useRef(null);
|
|
935
1078
|
const contentRef = useRef(null);
|
|
936
|
-
const
|
|
937
|
-
const
|
|
938
|
-
const
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
const hideContent = useCallback(() => {
|
|
942
|
-
handleActive(false);
|
|
943
|
-
}, []);
|
|
1079
|
+
const prevFocusRef = useRef(null);
|
|
1080
|
+
const setBlocked = useCallback(() => setBlockedCount((c) => c + 1), []);
|
|
1081
|
+
const setUnblocked = useCallback(() => setBlockedCount((c) => Math.max(0, c - 1)), []);
|
|
1082
|
+
const showContent = useCallback(() => setActive(true), []);
|
|
1083
|
+
const hideContent = useCallback(() => setActive(false), []);
|
|
944
1084
|
const getAncestorOffset = useCallback(() => {
|
|
945
1085
|
if (position !== "absolute" || !contentRef.current) return {
|
|
946
1086
|
top: 0,
|
|
@@ -1009,7 +1149,7 @@ const useOverlay = ({ isOpen = false, openOn = "click", closeOn = "click", type
|
|
|
1009
1149
|
const latestHandleVisibility = useRef(handleVisibilityByEventType);
|
|
1010
1150
|
latestHandleVisibility.current = handleVisibilityByEventType;
|
|
1011
1151
|
const handleContentPosition = useMemo(() => throttle(() => latestSetContentPosition.current(), throttleDelay), [throttleDelay]);
|
|
1012
|
-
const handleClick =
|
|
1152
|
+
const handleClick = useCallback((e) => latestHandleVisibility.current(e), []);
|
|
1013
1153
|
const handleVisibility = useMemo(() => throttle((e) => latestHandleVisibility.current(e), throttleDelay), [throttleDelay]);
|
|
1014
1154
|
useEffect(() => {
|
|
1015
1155
|
setInnerAlignX(alignX);
|
|
@@ -1056,62 +1196,30 @@ const useOverlay = ({ isOpen = false, openOn = "click", closeOn = "click", type
|
|
|
1056
1196
|
onOpen
|
|
1057
1197
|
]);
|
|
1058
1198
|
useEffect(() => {
|
|
1059
|
-
if (
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1199
|
+
if (type !== "modal") return;
|
|
1200
|
+
if (active && isContentLoaded && contentRef.current) {
|
|
1201
|
+
prevFocusRef.current = document.activeElement;
|
|
1202
|
+
if (contentRef.current.tabIndex < 0) contentRef.current.tabIndex = -1;
|
|
1203
|
+
contentRef.current.focus();
|
|
1204
|
+
}
|
|
1205
|
+
if (!active && prevFocusRef.current) {
|
|
1206
|
+
prevFocusRef.current.focus();
|
|
1207
|
+
prevFocusRef.current = null;
|
|
1208
|
+
}
|
|
1067
1209
|
}, [
|
|
1068
1210
|
active,
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
hideContent
|
|
1211
|
+
isContentLoaded,
|
|
1212
|
+
type
|
|
1072
1213
|
]);
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
const shouldSetOverflow = type === "modal";
|
|
1076
|
-
const onScroll = (e) => {
|
|
1077
|
-
handleContentPosition();
|
|
1078
|
-
handleVisibility(e);
|
|
1079
|
-
};
|
|
1080
|
-
if (shouldSetOverflow) document.body.style.overflow = "hidden";
|
|
1081
|
-
window.addEventListener("resize", handleContentPosition);
|
|
1082
|
-
window.addEventListener("scroll", onScroll, { passive: true });
|
|
1083
|
-
return () => {
|
|
1084
|
-
handleContentPosition.cancel();
|
|
1085
|
-
handleVisibility.cancel();
|
|
1086
|
-
if (shouldSetOverflow) document.body.style.overflow = "";
|
|
1087
|
-
window.removeEventListener("resize", handleContentPosition);
|
|
1088
|
-
window.removeEventListener("scroll", onScroll);
|
|
1089
|
-
};
|
|
1090
|
-
}, [
|
|
1214
|
+
useEscapeKey(closeOnEsc, active, blocked, hideContent);
|
|
1215
|
+
useScrollReposition({
|
|
1091
1216
|
active,
|
|
1092
1217
|
type,
|
|
1093
|
-
handleVisibility,
|
|
1094
|
-
handleContentPosition
|
|
1095
|
-
]);
|
|
1096
|
-
useEffect(() => {
|
|
1097
|
-
if (!active || !parentContainer) return void 0;
|
|
1098
|
-
if (closeOn !== "hover") parentContainer.style.overflow = "hidden";
|
|
1099
|
-
const onScroll = (e) => {
|
|
1100
|
-
handleContentPosition();
|
|
1101
|
-
handleVisibility(e);
|
|
1102
|
-
};
|
|
1103
|
-
parentContainer.addEventListener("scroll", onScroll, { passive: true });
|
|
1104
|
-
return () => {
|
|
1105
|
-
parentContainer.style.overflow = "";
|
|
1106
|
-
parentContainer.removeEventListener("scroll", onScroll);
|
|
1107
|
-
};
|
|
1108
|
-
}, [
|
|
1109
|
-
active,
|
|
1110
1218
|
parentContainer,
|
|
1111
1219
|
closeOn,
|
|
1112
1220
|
handleContentPosition,
|
|
1113
1221
|
handleVisibility
|
|
1114
|
-
|
|
1222
|
+
});
|
|
1115
1223
|
useEffect(() => {
|
|
1116
1224
|
if (blocked || disabled) return void 0;
|
|
1117
1225
|
if (openOn === "click" || [
|
|
@@ -1119,9 +1227,7 @@ const useOverlay = ({ isOpen = false, openOn = "click", closeOn = "click", type
|
|
|
1119
1227
|
"clickOnTrigger",
|
|
1120
1228
|
"clickOutsideContent"
|
|
1121
1229
|
].includes(closeOn)) window.addEventListener("click", handleClick);
|
|
1122
|
-
return () =>
|
|
1123
|
-
window.removeEventListener("click", handleClick);
|
|
1124
|
-
};
|
|
1230
|
+
return () => window.removeEventListener("click", handleClick);
|
|
1125
1231
|
}, [
|
|
1126
1232
|
openOn,
|
|
1127
1233
|
closeOn,
|
|
@@ -1129,63 +1235,19 @@ const useOverlay = ({ isOpen = false, openOn = "click", closeOn = "click", type
|
|
|
1129
1235
|
disabled,
|
|
1130
1236
|
handleClick
|
|
1131
1237
|
]);
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
const trigger = triggerRef.current;
|
|
1136
|
-
const content = contentRef.current;
|
|
1137
|
-
const clearHoverTimeout = () => {
|
|
1138
|
-
if (hoverTimeoutRef.current != null) {
|
|
1139
|
-
clearTimeout(hoverTimeoutRef.current);
|
|
1140
|
-
hoverTimeoutRef.current = null;
|
|
1141
|
-
}
|
|
1142
|
-
};
|
|
1143
|
-
const scheduleHide = () => {
|
|
1144
|
-
clearHoverTimeout();
|
|
1145
|
-
hoverTimeoutRef.current = setTimeout(hideContent, 100);
|
|
1146
|
-
};
|
|
1147
|
-
const onTriggerEnter = () => {
|
|
1148
|
-
clearHoverTimeout();
|
|
1149
|
-
if (openOn === "hover" && !active) showContent();
|
|
1150
|
-
};
|
|
1151
|
-
const onTriggerLeave = () => {
|
|
1152
|
-
if (closeOn === "hover" && active) scheduleHide();
|
|
1153
|
-
};
|
|
1154
|
-
const onContentEnter = () => {
|
|
1155
|
-
clearHoverTimeout();
|
|
1156
|
-
};
|
|
1157
|
-
const onContentLeave = () => {
|
|
1158
|
-
if (closeOn === "hover" && active) scheduleHide();
|
|
1159
|
-
};
|
|
1160
|
-
if (trigger) {
|
|
1161
|
-
trigger.addEventListener("mouseenter", onTriggerEnter);
|
|
1162
|
-
trigger.addEventListener("mouseleave", onTriggerLeave);
|
|
1163
|
-
}
|
|
1164
|
-
if (content) {
|
|
1165
|
-
content.addEventListener("mouseenter", onContentEnter);
|
|
1166
|
-
content.addEventListener("mouseleave", onContentLeave);
|
|
1167
|
-
}
|
|
1168
|
-
return () => {
|
|
1169
|
-
clearHoverTimeout();
|
|
1170
|
-
if (trigger) {
|
|
1171
|
-
trigger.removeEventListener("mouseenter", onTriggerEnter);
|
|
1172
|
-
trigger.removeEventListener("mouseleave", onTriggerLeave);
|
|
1173
|
-
}
|
|
1174
|
-
if (content) {
|
|
1175
|
-
content.removeEventListener("mouseenter", onContentEnter);
|
|
1176
|
-
content.removeEventListener("mouseleave", onContentLeave);
|
|
1177
|
-
}
|
|
1178
|
-
};
|
|
1179
|
-
}, [
|
|
1180
|
-
active,
|
|
1238
|
+
useHoverListeners({
|
|
1239
|
+
triggerRef,
|
|
1240
|
+
contentRef,
|
|
1181
1241
|
isContentLoaded,
|
|
1242
|
+
active,
|
|
1182
1243
|
blocked,
|
|
1183
1244
|
disabled,
|
|
1184
1245
|
openOn,
|
|
1185
1246
|
closeOn,
|
|
1247
|
+
hoverDelay,
|
|
1186
1248
|
showContent,
|
|
1187
1249
|
hideContent
|
|
1188
|
-
|
|
1250
|
+
});
|
|
1189
1251
|
return {
|
|
1190
1252
|
triggerRef,
|
|
1191
1253
|
contentRef: useCallback((node) => {
|
|
@@ -1217,11 +1279,22 @@ const useOverlay = ({ isOpen = false, openOn = "click", closeOn = "click", type
|
|
|
1217
1279
|
const IS_BROWSER = typeof window !== "undefined";
|
|
1218
1280
|
const Component$3 = ({ children, trigger, DOMLocation, triggerRefName = "ref", contentRefName = "ref", ...props }) => {
|
|
1219
1281
|
const { active, triggerRef, contentRef, showContent, hideContent, align, alignX, alignY, Provider, ...ctx } = useOverlay(props);
|
|
1220
|
-
const { openOn, closeOn } = props;
|
|
1282
|
+
const { openOn, closeOn, type } = props;
|
|
1283
|
+
const contentId = useId();
|
|
1221
1284
|
const passHandlers = useMemo(() => openOn === "manual" || closeOn === "manual" || closeOn === "clickOutsideContent", [openOn, closeOn]);
|
|
1285
|
+
const ariaHasPopup = useMemo(() => {
|
|
1286
|
+
switch (type) {
|
|
1287
|
+
case "modal": return "dialog";
|
|
1288
|
+
case "tooltip": return "true";
|
|
1289
|
+
default: return "menu";
|
|
1290
|
+
}
|
|
1291
|
+
}, [type]);
|
|
1222
1292
|
return /* @__PURE__ */ jsxs(Fragment, { children: [render(trigger, {
|
|
1223
1293
|
[triggerRefName]: triggerRef,
|
|
1224
1294
|
active,
|
|
1295
|
+
"aria-expanded": active,
|
|
1296
|
+
"aria-haspopup": ariaHasPopup,
|
|
1297
|
+
"aria-controls": active ? contentId : void 0,
|
|
1225
1298
|
...passHandlers ? {
|
|
1226
1299
|
showContent,
|
|
1227
1300
|
hideContent
|
|
@@ -1232,6 +1305,9 @@ const Component$3 = ({ children, trigger, DOMLocation, triggerRefName = "ref", c
|
|
|
1232
1305
|
...ctx,
|
|
1233
1306
|
children: render(children, {
|
|
1234
1307
|
[contentRefName]: contentRef,
|
|
1308
|
+
id: contentId,
|
|
1309
|
+
role: type === "modal" ? "dialog" : void 0,
|
|
1310
|
+
"aria-modal": type === "modal" ? true : void 0,
|
|
1235
1311
|
active,
|
|
1236
1312
|
align,
|
|
1237
1313
|
alignX,
|
|
@@ -1282,7 +1358,7 @@ var styled_default = styled(textComponent)`
|
|
|
1282
1358
|
|
|
1283
1359
|
//#endregion
|
|
1284
1360
|
//#region src/Text/component.tsx
|
|
1285
|
-
const Component$2 =
|
|
1361
|
+
const Component$2 = ({ paragraph, label, children, tag, css, ref, ...props }) => {
|
|
1286
1362
|
const renderContent = (as = void 0) => /* @__PURE__ */ jsx(styled_default, {
|
|
1287
1363
|
ref,
|
|
1288
1364
|
as,
|
|
@@ -1294,7 +1370,7 @@ const Component$2 = forwardRef(({ paragraph, label, children, tag, css, ...props
|
|
|
1294
1370
|
if (paragraph) finalTag = "p";
|
|
1295
1371
|
else finalTag = tag;
|
|
1296
1372
|
return renderContent(finalTag);
|
|
1297
|
-
}
|
|
1373
|
+
};
|
|
1298
1374
|
const name$1 = `${PKG_NAME}/Text`;
|
|
1299
1375
|
Component$2.displayName = name$1;
|
|
1300
1376
|
Component$2.pkgName = PKG_NAME;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Provider, alignContent, extendCss, makeItResponsive, value } from "@vitus-labs/unistyle";
|
|
2
2
|
import { config, isEmpty, omit, pick, render } from "@vitus-labs/core";
|
|
3
|
-
import { Children,
|
|
3
|
+
import { Children, memo, useCallback, useLayoutEffect, useMemo, useRef } from "react";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { isFragment } from "react-is";
|
|
6
6
|
|
|
@@ -186,13 +186,12 @@ var styled_default$1 = styled$1(component)`
|
|
|
186
186
|
//#region src/helpers/Wrapper/component.tsx
|
|
187
187
|
/**
|
|
188
188
|
* Wrapper component that serves as the outermost styled container for Element.
|
|
189
|
-
*
|
|
190
|
-
* detects button/fieldset/legend tags and applies a two-layer flex fix
|
|
189
|
+
* On web, it detects button/fieldset/legend tags and applies a two-layer flex fix
|
|
191
190
|
* (parent + child Styled) because these HTML elements do not natively
|
|
192
191
|
* support `display: flex` consistently across browsers.
|
|
193
192
|
*/
|
|
194
193
|
const DEV_PROPS = IS_DEVELOPMENT ? { "data-vl-element": "Element" } : {};
|
|
195
|
-
const Component$5 =
|
|
194
|
+
const Component$5 = ({ children, ref, tag, block, extendCss, direction, alignX, alignY, equalCols, isInline, ...props }) => {
|
|
196
195
|
const COMMON_PROPS = {
|
|
197
196
|
...props,
|
|
198
197
|
...DEV_PROPS,
|
|
@@ -236,7 +235,7 @@ const Component$5 = forwardRef(({ children, tag, block, extendCss, direction, al
|
|
|
236
235
|
$element: normalElement,
|
|
237
236
|
children
|
|
238
237
|
});
|
|
239
|
-
}
|
|
238
|
+
};
|
|
240
239
|
|
|
241
240
|
//#endregion
|
|
242
241
|
//#region src/helpers/Wrapper/index.ts
|
|
@@ -256,7 +255,7 @@ const defaultDirection = "inline";
|
|
|
256
255
|
const defaultContentDirection = "rows";
|
|
257
256
|
const defaultAlignX = "left";
|
|
258
257
|
const defaultAlignY = "center";
|
|
259
|
-
const Component$4 =
|
|
258
|
+
const Component$4 = ({ innerRef, ref, tag, label, content, children, beforeContent, afterContent, equalBeforeAfter, block, equalCols, gap, direction, alignX = defaultAlignX, alignY = defaultAlignY, css, contentCss, beforeContentCss, afterContentCss, contentDirection = defaultContentDirection, contentAlignX = defaultAlignX, contentAlignY = defaultAlignY, beforeContentDirection = defaultDirection, beforeContentAlignX = defaultAlignX, beforeContentAlignY = defaultAlignY, afterContentDirection = defaultDirection, afterContentAlignX = defaultAlignX, afterContentAlignY = defaultAlignY, ...props }) => {
|
|
260
259
|
const isSimpleElement = !beforeContent && !afterContent;
|
|
261
260
|
const CHILDREN = children ?? content ?? label;
|
|
262
261
|
const isInline = false;
|
|
@@ -350,7 +349,7 @@ const Component$4 = forwardRef(({ innerRef, tag, label, content, children, befor
|
|
|
350
349
|
})
|
|
351
350
|
]
|
|
352
351
|
});
|
|
353
|
-
}
|
|
352
|
+
};
|
|
354
353
|
const name$3 = `${PKG_NAME}/Element`;
|
|
355
354
|
Component$4.displayName = name$3;
|
|
356
355
|
Component$4.pkgName = PKG_NAME;
|
|
@@ -370,27 +369,6 @@ var Element_default = Component$4;
|
|
|
370
369
|
* wrapped with `wrapComponent`. Children always take priority over the
|
|
371
370
|
* component+data prop pattern.
|
|
372
371
|
*/
|
|
373
|
-
const classifyData = (data) => {
|
|
374
|
-
const items = data.filter((item) => item != null && !(typeof item === "object" && isEmpty(item)));
|
|
375
|
-
if (items.length === 0) return null;
|
|
376
|
-
let isSimple = true;
|
|
377
|
-
let isComplex = true;
|
|
378
|
-
for (const item of items) if (typeof item === "string" || typeof item === "number") isComplex = false;
|
|
379
|
-
else if (typeof item === "object") isSimple = false;
|
|
380
|
-
else {
|
|
381
|
-
isSimple = false;
|
|
382
|
-
isComplex = false;
|
|
383
|
-
}
|
|
384
|
-
if (isSimple) return {
|
|
385
|
-
type: "simple",
|
|
386
|
-
data: items
|
|
387
|
-
};
|
|
388
|
-
if (isComplex) return {
|
|
389
|
-
type: "complex",
|
|
390
|
-
data: items
|
|
391
|
-
};
|
|
392
|
-
return null;
|
|
393
|
-
};
|
|
394
372
|
const RESERVED_PROPS = [
|
|
395
373
|
"children",
|
|
396
374
|
"component",
|
|
@@ -401,7 +379,7 @@ const RESERVED_PROPS = [
|
|
|
401
379
|
"itemProps",
|
|
402
380
|
"wrapProps"
|
|
403
381
|
];
|
|
404
|
-
const
|
|
382
|
+
const buildExtendedProps = (i, length) => {
|
|
405
383
|
const position = i + 1;
|
|
406
384
|
return {
|
|
407
385
|
index: i,
|
|
@@ -412,106 +390,96 @@ const attachItemProps = ({ i, length }) => {
|
|
|
412
390
|
position
|
|
413
391
|
};
|
|
414
392
|
};
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const renderChild = (child, total = 1, i = 0) => {
|
|
424
|
-
if (!itemProps && !Wrapper) return child;
|
|
425
|
-
const extendedProps = attachItemProps({
|
|
426
|
-
i,
|
|
427
|
-
length: total
|
|
428
|
-
});
|
|
429
|
-
const finalItemProps = itemProps ? injectItemProps({}, extendedProps) : {};
|
|
430
|
-
if (Wrapper) return /* @__PURE__ */ jsx(Wrapper, {
|
|
431
|
-
...wrapProps ? injectWrapItemProps({}, extendedProps) : {},
|
|
432
|
-
children: render(child, finalItemProps)
|
|
433
|
-
}, i);
|
|
434
|
-
return render(child, {
|
|
435
|
-
key: i,
|
|
436
|
-
...finalItemProps
|
|
437
|
-
});
|
|
438
|
-
};
|
|
439
|
-
const renderChildren = () => {
|
|
440
|
-
if (!children) return null;
|
|
441
|
-
if (Array.isArray(children)) return Children.map(children, (item, i) => renderChild(item, children.length, i));
|
|
442
|
-
if (isFragment(children)) {
|
|
443
|
-
const fragmentChildren = children.props.children;
|
|
444
|
-
const childrenLength = fragmentChildren.length;
|
|
445
|
-
return fragmentChildren.map((item, i) => renderChild(item, childrenLength, i));
|
|
446
|
-
}
|
|
447
|
-
return renderChild(children);
|
|
448
|
-
};
|
|
449
|
-
const renderSimpleArray = (data) => {
|
|
450
|
-
const { length } = data;
|
|
451
|
-
if (length === 0) return null;
|
|
452
|
-
return data.map((item, i) => {
|
|
453
|
-
const key = getKey(item, i);
|
|
454
|
-
const keyName = valueName ?? "children";
|
|
455
|
-
const extendedProps = attachItemProps({
|
|
456
|
-
i,
|
|
457
|
-
length
|
|
458
|
-
});
|
|
459
|
-
const finalItemProps = {
|
|
460
|
-
...itemProps ? injectItemProps({ [keyName]: item }, extendedProps) : {},
|
|
461
|
-
[keyName]: item
|
|
462
|
-
};
|
|
463
|
-
if (Wrapper) return /* @__PURE__ */ jsx(Wrapper, {
|
|
464
|
-
...wrapProps ? injectWrapItemProps({ [keyName]: item }, extendedProps) : {},
|
|
465
|
-
children: render(component, finalItemProps)
|
|
466
|
-
}, key);
|
|
467
|
-
return render(component, {
|
|
468
|
-
key,
|
|
469
|
-
...finalItemProps
|
|
470
|
-
});
|
|
471
|
-
});
|
|
472
|
-
};
|
|
473
|
-
const getObjectKey = (item, index) => {
|
|
474
|
-
if (!itemKey) return item.key ?? item.id ?? item.itemId ?? index;
|
|
475
|
-
if (typeof itemKey === "function") return itemKey(item, index);
|
|
476
|
-
if (typeof itemKey === "string") return item[itemKey];
|
|
477
|
-
return index;
|
|
393
|
+
const resolveCallback = (cb, source, ext) => {
|
|
394
|
+
if (!cb) return {};
|
|
395
|
+
return typeof cb === "function" ? cb(source, ext) : cb;
|
|
396
|
+
};
|
|
397
|
+
const renderSpec = (spec, ext, itemProps, wrapProps, Wrapper) => {
|
|
398
|
+
const finalItemProps = {
|
|
399
|
+
...resolveCallback(itemProps, spec.source, ext),
|
|
400
|
+
...spec.base
|
|
478
401
|
};
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
const extendedProps = attachItemProps({
|
|
487
|
-
i,
|
|
488
|
-
length
|
|
489
|
-
});
|
|
490
|
-
const finalItemProps = {
|
|
491
|
-
...itemProps ? injectItemProps(item, extendedProps) : {},
|
|
492
|
-
...restItem
|
|
493
|
-
};
|
|
494
|
-
if (Wrapper && !itemComponent) return /* @__PURE__ */ jsx(Wrapper, {
|
|
495
|
-
...wrapProps ? injectWrapItemProps(item, extendedProps) : {},
|
|
496
|
-
children: render(renderItem, finalItemProps)
|
|
497
|
-
}, key);
|
|
498
|
-
return render(renderItem, {
|
|
499
|
-
key,
|
|
500
|
-
...finalItemProps
|
|
501
|
-
});
|
|
502
|
-
});
|
|
402
|
+
if (Wrapper && !spec.skipWrap) return /* @__PURE__ */ jsx(Wrapper, {
|
|
403
|
+
...resolveCallback(wrapProps, spec.source, ext),
|
|
404
|
+
children: spec.isNode ? render(spec.target, finalItemProps) : render(spec.target, finalItemProps)
|
|
405
|
+
}, spec.key);
|
|
406
|
+
const propsWithKey = {
|
|
407
|
+
key: spec.key,
|
|
408
|
+
...finalItemProps
|
|
503
409
|
};
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
410
|
+
return spec.isNode ? render(spec.target, propsWithKey) : render(spec.target, propsWithKey);
|
|
411
|
+
};
|
|
412
|
+
/** Normalize children (single, array, or fragment) into an array of nodes. */
|
|
413
|
+
const flattenChildren = (children) => {
|
|
414
|
+
if (Array.isArray(children)) return children;
|
|
415
|
+
if (isFragment(children)) return children.props.children;
|
|
416
|
+
return [children];
|
|
417
|
+
};
|
|
418
|
+
/** Drop nullish entries and empty objects (matches legacy behavior). */
|
|
419
|
+
const filterValidItems = (data) => data.filter((item) => item != null && !(typeof item === "object" && isEmpty(item)));
|
|
420
|
+
/** Determine if the array is uniformly simple (string/number) or complex (object). Mixed → null. */
|
|
421
|
+
const detectKind = (items) => {
|
|
422
|
+
let kind = null;
|
|
423
|
+
for (const item of items) {
|
|
424
|
+
const t = typeof item === "string" || typeof item === "number" ? "simple" : typeof item === "object" ? "complex" : null;
|
|
425
|
+
if (t === null) return null;
|
|
426
|
+
if (kind === null) kind = t;
|
|
427
|
+
else if (kind !== t) return null;
|
|
428
|
+
}
|
|
429
|
+
return kind;
|
|
430
|
+
};
|
|
431
|
+
const objectKey = (item, index, itemKey) => {
|
|
432
|
+
if (!itemKey) return item.key ?? item.id ?? item.itemId ?? index;
|
|
433
|
+
if (typeof itemKey === "function") return itemKey(item, index);
|
|
434
|
+
if (typeof itemKey === "string") return item[itemKey] ?? index;
|
|
435
|
+
return index;
|
|
436
|
+
};
|
|
437
|
+
const buildChildrenSpecs = (children) => flattenChildren(children).map((node, i) => ({
|
|
438
|
+
key: i,
|
|
439
|
+
target: node,
|
|
440
|
+
source: {},
|
|
441
|
+
base: {},
|
|
442
|
+
isNode: true,
|
|
443
|
+
skipWrap: false
|
|
444
|
+
}));
|
|
445
|
+
const buildSimpleSpecs = (items, component, valueName, itemKey) => {
|
|
446
|
+
const keyName = valueName ?? "children";
|
|
447
|
+
return items.map((value, i) => ({
|
|
448
|
+
key: typeof itemKey === "function" ? itemKey(value, i) : i,
|
|
449
|
+
target: component,
|
|
450
|
+
source: { [keyName]: value },
|
|
451
|
+
base: { [keyName]: value },
|
|
452
|
+
isNode: false,
|
|
453
|
+
skipWrap: false
|
|
454
|
+
}));
|
|
455
|
+
};
|
|
456
|
+
const buildObjectSpecs = (items, component, itemKey) => items.map((item, i) => {
|
|
457
|
+
const { component: itemComponent, ...rest } = item;
|
|
458
|
+
return {
|
|
459
|
+
key: objectKey(rest, i, itemKey),
|
|
460
|
+
target: itemComponent ?? component,
|
|
461
|
+
source: item,
|
|
462
|
+
base: rest,
|
|
463
|
+
isNode: false,
|
|
464
|
+
skipWrap: Boolean(itemComponent)
|
|
513
465
|
};
|
|
514
|
-
|
|
466
|
+
});
|
|
467
|
+
const buildDataSpecs = (data, component, valueName, itemKey) => {
|
|
468
|
+
const items = filterValidItems(data);
|
|
469
|
+
if (items.length === 0) return null;
|
|
470
|
+
const kind = detectKind(items);
|
|
471
|
+
if (!kind) return null;
|
|
472
|
+
return kind === "simple" ? buildSimpleSpecs(items, component, valueName, itemKey) : buildObjectSpecs(items, component, itemKey);
|
|
473
|
+
};
|
|
474
|
+
const Component$3 = ({ itemKey, valueName, children, component, data, wrapComponent: Wrapper, wrapProps, itemProps }) => {
|
|
475
|
+
let specs = null;
|
|
476
|
+
if (children) {
|
|
477
|
+
if (!Array.isArray(children) && !isFragment(children) && !itemProps && !Wrapper) return children;
|
|
478
|
+
specs = buildChildrenSpecs(children);
|
|
479
|
+
} else if (component && Array.isArray(data)) specs = buildDataSpecs(data, component, valueName, itemKey);
|
|
480
|
+
if (!specs || specs.length === 0) return null;
|
|
481
|
+
const total = specs.length;
|
|
482
|
+
return Children.toArray(specs.map((spec, i) => renderSpec(spec, buildExtendedProps(i, total), itemProps, wrapProps, Wrapper)));
|
|
515
483
|
};
|
|
516
484
|
var component_default = Object.assign(memo(Component$3), {
|
|
517
485
|
isIterator: true,
|
|
@@ -531,7 +499,7 @@ var Iterator_default = component_default;
|
|
|
531
499
|
* is wrapped in an Element that receives all non-iterator props (e.g.,
|
|
532
500
|
* layout, alignment, css), allowing the list to be styled as a single block.
|
|
533
501
|
*/
|
|
534
|
-
const Component$2 =
|
|
502
|
+
const Component$2 = ({ rootElement = false, ref, ...props }) => {
|
|
535
503
|
const renderedList = /* @__PURE__ */ jsx(Iterator_default, { ...pick(props, Iterator_default.RESERVED_PROPS) });
|
|
536
504
|
if (!rootElement) return renderedList;
|
|
537
505
|
return /* @__PURE__ */ jsx(Element_default, {
|
|
@@ -539,7 +507,7 @@ const Component$2 = forwardRef(({ rootElement = false, ...props }, ref) => {
|
|
|
539
507
|
...omit(props, Iterator_default.RESERVED_PROPS),
|
|
540
508
|
children: renderedList
|
|
541
509
|
});
|
|
542
|
-
}
|
|
510
|
+
};
|
|
543
511
|
const name$2 = `${PKG_NAME}/List`;
|
|
544
512
|
Component$2.displayName = name$2;
|
|
545
513
|
Component$2.pkgName = PKG_NAME;
|
|
@@ -574,7 +542,7 @@ var styled_default = styled(textComponent)`
|
|
|
574
542
|
|
|
575
543
|
//#endregion
|
|
576
544
|
//#region src/Text/component.tsx
|
|
577
|
-
const Component$1 =
|
|
545
|
+
const Component$1 = ({ paragraph, label, children, tag, css, ref, ...props }) => {
|
|
578
546
|
const renderContent = (as = void 0) => /* @__PURE__ */ jsx(styled_default, {
|
|
579
547
|
ref,
|
|
580
548
|
as,
|
|
@@ -584,7 +552,7 @@ const Component$1 = forwardRef(({ paragraph, label, children, tag, css, ...props
|
|
|
584
552
|
});
|
|
585
553
|
let finalTag;
|
|
586
554
|
return renderContent(finalTag);
|
|
587
|
-
}
|
|
555
|
+
};
|
|
588
556
|
const name$1 = `${PKG_NAME}/Text`;
|
|
589
557
|
Component$1.displayName = name$1;
|
|
590
558
|
Component$1.pkgName = PKG_NAME;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitus-labs/elements",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Vit Bokisch <vit@bokisch.cz>",
|
|
6
6
|
"maintainers": [
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
"version": "node ../../scripts/sync-peer-deps.mjs"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@vitus-labs/core": "2.0.0-
|
|
62
|
-
"@vitus-labs/unistyle": "2.0.0-
|
|
61
|
+
"@vitus-labs/core": "2.0.0-beta.1",
|
|
62
|
+
"@vitus-labs/unistyle": "2.0.0-beta.1",
|
|
63
63
|
"react": ">= 19",
|
|
64
64
|
"react-dom": ">= 19",
|
|
65
65
|
"react-native": ">= 0.76"
|
|
@@ -73,15 +73,14 @@
|
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@vitus-labs/core": "
|
|
77
|
-
"@vitus-labs/rocketstyle": "
|
|
78
|
-
"@vitus-labs/tools-rolldown": "
|
|
79
|
-
"@vitus-labs/tools-storybook": "
|
|
80
|
-
"@vitus-labs/tools-typescript": "1.
|
|
81
|
-
"@vitus-labs/unistyle": "
|
|
76
|
+
"@vitus-labs/core": "workspace:*",
|
|
77
|
+
"@vitus-labs/rocketstyle": "workspace:*",
|
|
78
|
+
"@vitus-labs/tools-rolldown": "2.2.0",
|
|
79
|
+
"@vitus-labs/tools-storybook": "2.2.0",
|
|
80
|
+
"@vitus-labs/tools-typescript": "2.1.0",
|
|
81
|
+
"@vitus-labs/unistyle": "workspace:*"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
84
|
"react-is": "^19.2.4"
|
|
85
|
-
}
|
|
86
|
-
"gitHead": "dd8b9f356086ecd8bfb69c87fcad1e8bfa9ab1f4"
|
|
85
|
+
}
|
|
87
86
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2023-present Vit Bokisch
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|