@ecohouse/ui 0.1.53 → 0.1.54
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/dist/index.cjs +116 -87
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +116 -87
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Select/Select.tsx +163 -105
package/dist/index.cjs
CHANGED
|
@@ -27561,7 +27561,7 @@ var require_react_dom_development = __commonJS({
|
|
|
27561
27561
|
return root2;
|
|
27562
27562
|
}
|
|
27563
27563
|
var ReactVersion = "18.3.1";
|
|
27564
|
-
function
|
|
27564
|
+
function createPortal4(children, containerInfo, implementation) {
|
|
27565
27565
|
var key = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : null;
|
|
27566
27566
|
{
|
|
27567
27567
|
checkKeyStringCoercion(key);
|
|
@@ -28417,7 +28417,7 @@ var require_react_dom_development = __commonJS({
|
|
|
28417
28417
|
if (!isValidContainer(container)) {
|
|
28418
28418
|
throw new Error("Target container is not a DOM element.");
|
|
28419
28419
|
}
|
|
28420
|
-
return
|
|
28420
|
+
return createPortal4(children, container, null, key);
|
|
28421
28421
|
}
|
|
28422
28422
|
function renderSubtreeIntoContainer(parentComponent, element, containerNode, callback) {
|
|
28423
28423
|
return unstable_renderSubtreeIntoContainer(parentComponent, element, containerNode, callback);
|
|
@@ -36214,6 +36214,9 @@ var styles32 = reactNative.StyleSheet.create({
|
|
|
36214
36214
|
color: colors.red
|
|
36215
36215
|
}
|
|
36216
36216
|
});
|
|
36217
|
+
|
|
36218
|
+
// src/components/Select/Select.tsx
|
|
36219
|
+
var import_react_dom3 = __toESM(require_react_dom());
|
|
36217
36220
|
var DEFAULT_WIDTH4 = 308;
|
|
36218
36221
|
var TRIGGER_HEIGHT2 = 44;
|
|
36219
36222
|
var TRIGGER_RADIUS2 = 60;
|
|
@@ -36223,6 +36226,9 @@ var ITEM_RADIUS2 = 12;
|
|
|
36223
36226
|
var ICON_SIZE13 = 20;
|
|
36224
36227
|
var CHIP_GAP = 6;
|
|
36225
36228
|
var FALLBACK_ELLIPSIS_WIDTH = 20;
|
|
36229
|
+
var WEB_MENU_Z_INDEX = 600;
|
|
36230
|
+
var WEB_VIEWPORT_PADDING = 8;
|
|
36231
|
+
var WEB_MENU_GAP = 8;
|
|
36226
36232
|
function itemBackground(state) {
|
|
36227
36233
|
switch (state) {
|
|
36228
36234
|
case "hover":
|
|
@@ -36369,6 +36375,7 @@ var Select = react.forwardRef(
|
|
|
36369
36375
|
const valueProp = props.value;
|
|
36370
36376
|
const rootRef = react.useRef(null);
|
|
36371
36377
|
const triggerRef = react.useRef(null);
|
|
36378
|
+
const menuRef = react.useRef(null);
|
|
36372
36379
|
const searchInputRef = react.useRef(null);
|
|
36373
36380
|
const setRootRef = react.useMemo(() => mergeRefs(rootRef, forwardedRef), [forwardedRef]);
|
|
36374
36381
|
const isOpenControlled = typeof openProp === "boolean";
|
|
@@ -36384,6 +36391,7 @@ var Select = react.forwardRef(
|
|
|
36384
36391
|
const [hoveredValue, setHoveredValue] = react.useState(null);
|
|
36385
36392
|
const [menuAlignEnd, setMenuAlignEnd] = react.useState(false);
|
|
36386
36393
|
const [menuPlaceAbove, setMenuPlaceAbove] = react.useState(false);
|
|
36394
|
+
const [webMenuPosition, setWebMenuPosition] = react.useState(null);
|
|
36387
36395
|
const selectedValues = react.useMemo(() => {
|
|
36388
36396
|
const current = isValueControlled ? valueProp : multiple ? uncontrolledMultiple : uncontrolledSingle;
|
|
36389
36397
|
return toArray(current);
|
|
@@ -36437,6 +36445,7 @@ var Select = react.forwardRef(
|
|
|
36437
36445
|
setHoveredValue(null);
|
|
36438
36446
|
setMenuAlignEnd(false);
|
|
36439
36447
|
setMenuPlaceAbove(false);
|
|
36448
|
+
setWebMenuPosition(null);
|
|
36440
36449
|
onSearchChange?.("");
|
|
36441
36450
|
}
|
|
36442
36451
|
},
|
|
@@ -36448,15 +36457,18 @@ var Select = react.forwardRef(
|
|
|
36448
36457
|
const trigger = triggerRef.current;
|
|
36449
36458
|
const rect = trigger?.getBoundingClientRect?.();
|
|
36450
36459
|
if (!rect) return;
|
|
36451
|
-
const viewportPadding = 8;
|
|
36452
|
-
const gap = 8;
|
|
36453
36460
|
const menuWidth = Math.max(rect.width, resolvedMenuWidth ?? 0);
|
|
36454
|
-
const overflowsRight = rect.left + menuWidth > window.innerWidth -
|
|
36461
|
+
const overflowsRight = rect.left + menuWidth > window.innerWidth - WEB_VIEWPORT_PADDING;
|
|
36455
36462
|
setMenuAlignEnd(overflowsRight);
|
|
36456
|
-
const spaceBelow = window.innerHeight -
|
|
36457
|
-
const spaceAbove = rect.top -
|
|
36458
|
-
const needsAbove = estimatedMenuHeight +
|
|
36463
|
+
const spaceBelow = window.innerHeight - WEB_VIEWPORT_PADDING - rect.bottom;
|
|
36464
|
+
const spaceAbove = rect.top - WEB_VIEWPORT_PADDING;
|
|
36465
|
+
const needsAbove = estimatedMenuHeight + WEB_MENU_GAP > spaceBelow && spaceAbove > spaceBelow;
|
|
36459
36466
|
setMenuPlaceAbove(needsAbove);
|
|
36467
|
+
const available = Math.max(0, (needsAbove ? spaceAbove : spaceBelow) - WEB_MENU_GAP);
|
|
36468
|
+
const maxHeight = Math.min(estimatedMenuHeight, Math.max(available, TRIGGER_HEIGHT2));
|
|
36469
|
+
const left = overflowsRight ? Math.max(WEB_VIEWPORT_PADDING, rect.right - menuWidth) : Math.min(rect.left, window.innerWidth - WEB_VIEWPORT_PADDING - menuWidth);
|
|
36470
|
+
const top = needsAbove ? Math.max(WEB_VIEWPORT_PADDING, rect.top - WEB_MENU_GAP - maxHeight) : rect.bottom + WEB_MENU_GAP;
|
|
36471
|
+
setWebMenuPosition({ top, left, width: menuWidth, maxHeight });
|
|
36460
36472
|
};
|
|
36461
36473
|
updateMenuPlacement();
|
|
36462
36474
|
window.addEventListener("resize", updateMenuPlacement);
|
|
@@ -36473,11 +36485,12 @@ var Select = react.forwardRef(
|
|
|
36473
36485
|
react.useEffect(() => {
|
|
36474
36486
|
if (reactNative.Platform.OS !== "web" || !isOpen) return;
|
|
36475
36487
|
const handlePointerDown = (event) => {
|
|
36476
|
-
const root = rootRef.current;
|
|
36477
36488
|
const target = event.target;
|
|
36478
|
-
if (
|
|
36479
|
-
|
|
36480
|
-
|
|
36489
|
+
if (!(target instanceof Node)) return;
|
|
36490
|
+
const root = rootRef.current;
|
|
36491
|
+
const menu = menuRef.current;
|
|
36492
|
+
if (root?.contains?.(target) || menu?.contains?.(target)) return;
|
|
36493
|
+
setOpen(false);
|
|
36481
36494
|
};
|
|
36482
36495
|
document.addEventListener("mousedown", handlePointerDown);
|
|
36483
36496
|
document.addEventListener("touchstart", handlePointerDown);
|
|
@@ -36591,7 +36604,7 @@ var Select = react.forwardRef(
|
|
|
36591
36604
|
]);
|
|
36592
36605
|
const leftIconNode = renderStatefulIcon(leftIcon, UserIcon, {
|
|
36593
36606
|
size: ICON_SIZE13,
|
|
36594
|
-
color: error ? colors.red : colors.primary
|
|
36607
|
+
color: error ? colors.red : isOpen ? colors.primary : colors.grey100
|
|
36595
36608
|
});
|
|
36596
36609
|
const hasLeftIcon = showLeftIcon || leftIcon != null;
|
|
36597
36610
|
const triggerBorderColor = error ? colors.redMuted : isOpen ? colors.primaryMuted : colors.grey700;
|
|
@@ -36600,6 +36613,95 @@ var Select = react.forwardRef(
|
|
|
36600
36613
|
const hintColor = error ? colors.red : colors.grey100;
|
|
36601
36614
|
const singleLabel = selectedOptions[0]?.label ?? placeholder;
|
|
36602
36615
|
const resolvedAccessibilityLabel = accessibilityLabel ?? (typeof label === "string" ? label : void 0);
|
|
36616
|
+
const optionListMaxHeight = reactNative.Platform.OS === "web" && webMenuPosition != null ? Math.max(43, webMenuPosition.maxHeight - (24 + (showSearch ? 48 : 0))) : resolvedOptionListMaxHeight;
|
|
36617
|
+
const menuNode = isOpen ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
36618
|
+
reactNative.View,
|
|
36619
|
+
{
|
|
36620
|
+
ref: menuRef,
|
|
36621
|
+
style: [
|
|
36622
|
+
styles33.menu,
|
|
36623
|
+
reactNative.Platform.OS === "web" && webMenuPosition != null ? {
|
|
36624
|
+
position: "fixed",
|
|
36625
|
+
top: webMenuPosition.top,
|
|
36626
|
+
left: webMenuPosition.left,
|
|
36627
|
+
width: webMenuPosition.width,
|
|
36628
|
+
minWidth: webMenuPosition.width,
|
|
36629
|
+
maxHeight: webMenuPosition.maxHeight,
|
|
36630
|
+
zIndex: WEB_MENU_Z_INDEX,
|
|
36631
|
+
marginTop: 0,
|
|
36632
|
+
marginBottom: 0
|
|
36633
|
+
} : reactNative.Platform.OS === "web" ? { position: "fixed", opacity: 0, pointerEvents: "none" } : [
|
|
36634
|
+
menuAlignEnd ? styles33.menuAlignEnd : styles33.menuAlignStart,
|
|
36635
|
+
menuPlaceAbove ? styles33.menuAbove : styles33.menuBelow
|
|
36636
|
+
],
|
|
36637
|
+
menuStyle
|
|
36638
|
+
],
|
|
36639
|
+
children: [
|
|
36640
|
+
showSearch ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles33.searchField, children: [
|
|
36641
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles33.iconSlot, children: /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { size: ICON_SIZE13, color: colors.grey100 }) }),
|
|
36642
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36643
|
+
reactNative.TextInput,
|
|
36644
|
+
{
|
|
36645
|
+
ref: searchInputRef,
|
|
36646
|
+
value: searchQuery,
|
|
36647
|
+
onChangeText: handleSearchChange,
|
|
36648
|
+
editable: !disabled,
|
|
36649
|
+
placeholder: searchPlaceholder,
|
|
36650
|
+
placeholderTextColor: colors.grey100,
|
|
36651
|
+
style: [
|
|
36652
|
+
styles33.searchInput,
|
|
36653
|
+
reactNative.Platform.OS === "web" ? styles33.searchInputWeb : null,
|
|
36654
|
+
reactNative.Platform.OS === "android" ? styles33.searchInputAndroid : null
|
|
36655
|
+
],
|
|
36656
|
+
accessibilityLabel: searchPlaceholder
|
|
36657
|
+
}
|
|
36658
|
+
)
|
|
36659
|
+
] }) : null,
|
|
36660
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
36661
|
+
reactNative.ScrollView,
|
|
36662
|
+
{
|
|
36663
|
+
style: [styles33.optionList, { maxHeight: optionListMaxHeight }],
|
|
36664
|
+
contentContainerStyle: styles33.optionListContent,
|
|
36665
|
+
keyboardShouldPersistTaps: "handled",
|
|
36666
|
+
showsVerticalScrollIndicator: false,
|
|
36667
|
+
children: [
|
|
36668
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles33.statusRow, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles33.statusText, children: "Loading..." }) }) : filteredOptions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles33.statusRow, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles33.statusText, children: emptyText }) }) : null,
|
|
36669
|
+
!loading && filteredOptions.map((option) => {
|
|
36670
|
+
const isSelected = selectedValues.includes(option.value);
|
|
36671
|
+
const isHovered = hoveredValue === option.value;
|
|
36672
|
+
const visualState = isSelected ? "selected" : isHovered ? "hover" : "default";
|
|
36673
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
36674
|
+
reactNative.Pressable,
|
|
36675
|
+
{
|
|
36676
|
+
onPress: () => handleSelect(option.value),
|
|
36677
|
+
disabled,
|
|
36678
|
+
onHoverIn: () => setHoveredValue(option.value),
|
|
36679
|
+
onHoverOut: () => setHoveredValue((current) => current === option.value ? null : current),
|
|
36680
|
+
onPressIn: () => setHoveredValue(option.value),
|
|
36681
|
+
onPressOut: () => setHoveredValue((current) => current === option.value ? null : current),
|
|
36682
|
+
accessibilityRole: multiple ? "checkbox" : "button",
|
|
36683
|
+
accessibilityState: { selected: isSelected, checked: isSelected, disabled },
|
|
36684
|
+
style: [
|
|
36685
|
+
styles33.item,
|
|
36686
|
+
{
|
|
36687
|
+
backgroundColor: itemBackground(visualState)
|
|
36688
|
+
}
|
|
36689
|
+
],
|
|
36690
|
+
children: [
|
|
36691
|
+
multiple ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles33.itemCheckbox, { pointerEvents: "none" }], children: /* @__PURE__ */ jsxRuntime.jsx(Checkbox, { value: isSelected, variant: "light" }) }) : null,
|
|
36692
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles33.itemLabel, numberOfLines: 1, children: option.label })
|
|
36693
|
+
]
|
|
36694
|
+
},
|
|
36695
|
+
option.value
|
|
36696
|
+
);
|
|
36697
|
+
})
|
|
36698
|
+
]
|
|
36699
|
+
}
|
|
36700
|
+
)
|
|
36701
|
+
]
|
|
36702
|
+
}
|
|
36703
|
+
) : null;
|
|
36704
|
+
const webMenuPortal = reactNative.Platform.OS === "web" && isOpen && typeof document !== "undefined" ? (0, import_react_dom3.createPortal)(menuNode, document.body) : null;
|
|
36603
36705
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
36604
36706
|
reactNative.View,
|
|
36605
36707
|
{
|
|
@@ -36640,80 +36742,7 @@ var Select = react.forwardRef(
|
|
|
36640
36742
|
]
|
|
36641
36743
|
}
|
|
36642
36744
|
),
|
|
36643
|
-
|
|
36644
|
-
reactNative.View,
|
|
36645
|
-
{
|
|
36646
|
-
style: [
|
|
36647
|
-
styles33.menu,
|
|
36648
|
-
menuAlignEnd ? styles33.menuAlignEnd : styles33.menuAlignStart,
|
|
36649
|
-
menuPlaceAbove ? styles33.menuAbove : styles33.menuBelow,
|
|
36650
|
-
menuStyle
|
|
36651
|
-
],
|
|
36652
|
-
children: [
|
|
36653
|
-
showSearch ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles33.searchField, children: [
|
|
36654
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles33.iconSlot, children: /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { size: ICON_SIZE13, color: colors.grey100 }) }),
|
|
36655
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
36656
|
-
reactNative.TextInput,
|
|
36657
|
-
{
|
|
36658
|
-
ref: searchInputRef,
|
|
36659
|
-
value: searchQuery,
|
|
36660
|
-
onChangeText: handleSearchChange,
|
|
36661
|
-
editable: !disabled,
|
|
36662
|
-
placeholder: searchPlaceholder,
|
|
36663
|
-
placeholderTextColor: colors.grey100,
|
|
36664
|
-
style: [
|
|
36665
|
-
styles33.searchInput,
|
|
36666
|
-
reactNative.Platform.OS === "web" ? styles33.searchInputWeb : null,
|
|
36667
|
-
reactNative.Platform.OS === "android" ? styles33.searchInputAndroid : null
|
|
36668
|
-
],
|
|
36669
|
-
accessibilityLabel: searchPlaceholder
|
|
36670
|
-
}
|
|
36671
|
-
)
|
|
36672
|
-
] }) : null,
|
|
36673
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
36674
|
-
reactNative.ScrollView,
|
|
36675
|
-
{
|
|
36676
|
-
style: [styles33.optionList, { maxHeight: resolvedOptionListMaxHeight }],
|
|
36677
|
-
contentContainerStyle: styles33.optionListContent,
|
|
36678
|
-
keyboardShouldPersistTaps: "handled",
|
|
36679
|
-
showsVerticalScrollIndicator: false,
|
|
36680
|
-
children: [
|
|
36681
|
-
loading ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles33.statusRow, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles33.statusText, children: "Loading..." }) }) : filteredOptions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles33.statusRow, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles33.statusText, children: emptyText }) }) : null,
|
|
36682
|
-
!loading && filteredOptions.map((option) => {
|
|
36683
|
-
const isSelected = selectedValues.includes(option.value);
|
|
36684
|
-
const isHovered = hoveredValue === option.value;
|
|
36685
|
-
const visualState = isSelected ? "selected" : isHovered ? "hover" : "default";
|
|
36686
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
36687
|
-
reactNative.Pressable,
|
|
36688
|
-
{
|
|
36689
|
-
onPress: () => handleSelect(option.value),
|
|
36690
|
-
disabled,
|
|
36691
|
-
onHoverIn: () => setHoveredValue(option.value),
|
|
36692
|
-
onHoverOut: () => setHoveredValue((current) => current === option.value ? null : current),
|
|
36693
|
-
onPressIn: () => setHoveredValue(option.value),
|
|
36694
|
-
onPressOut: () => setHoveredValue((current) => current === option.value ? null : current),
|
|
36695
|
-
accessibilityRole: multiple ? "checkbox" : "button",
|
|
36696
|
-
accessibilityState: { selected: isSelected, checked: isSelected, disabled },
|
|
36697
|
-
style: [
|
|
36698
|
-
styles33.item,
|
|
36699
|
-
{
|
|
36700
|
-
backgroundColor: itemBackground(visualState)
|
|
36701
|
-
}
|
|
36702
|
-
],
|
|
36703
|
-
children: [
|
|
36704
|
-
multiple ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles33.itemCheckbox, { pointerEvents: "none" }], children: /* @__PURE__ */ jsxRuntime.jsx(Checkbox, { value: isSelected, variant: "light" }) }) : null,
|
|
36705
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: styles33.itemLabel, numberOfLines: 1, children: option.label })
|
|
36706
|
-
]
|
|
36707
|
-
},
|
|
36708
|
-
option.value
|
|
36709
|
-
);
|
|
36710
|
-
})
|
|
36711
|
-
]
|
|
36712
|
-
}
|
|
36713
|
-
)
|
|
36714
|
-
]
|
|
36715
|
-
}
|
|
36716
|
-
) : null
|
|
36745
|
+
reactNative.Platform.OS === "web" ? webMenuPortal : menuNode
|
|
36717
36746
|
] }),
|
|
36718
36747
|
showHint && hint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles33.hint, { color: hintColor }], children: hint }) : null
|
|
36719
36748
|
]
|