@sia.soul/sia-react-ui 0.1.6 → 0.1.8

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.
@@ -1,3 +1,11 @@
1
+ import {
2
+ Button
3
+ } from "./chunk-MBS2HXLZ.js";
4
+ import {
5
+ useControllableState,
6
+ usePlaceholderMode
7
+ } from "./chunk-EJDPRAU2.js";
8
+
1
9
  // src/components/Icon.tsx
2
10
  import { forwardRef } from "react";
3
11
 
@@ -807,6 +815,9 @@ var Icon = forwardRef(function Icon2({ name, size = "1em", strokeWidth = 1.8, ro
807
815
  );
808
816
  });
809
817
 
818
+ // src/components/Navigation.tsx
819
+ import { useEffect, useId, useMemo, useRef as useRef2, useState as useState2 } from "react";
820
+
810
821
  // src/components/PopupPortal.tsx
811
822
  import { forwardRef as forwardRef2, useLayoutEffect, useRef, useState } from "react";
812
823
  import { createPortal } from "react-dom";
@@ -922,9 +933,589 @@ var PopupPortal = forwardRef2(function PopupPortal2({
922
933
  );
923
934
  });
924
935
 
936
+ // src/components/Navigation.tsx
937
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
938
+ function MenuPopup({
939
+ anchorRef,
940
+ open,
941
+ placement,
942
+ menuId,
943
+ theme,
944
+ children,
945
+ onMouseEnter,
946
+ onMouseLeave
947
+ }) {
948
+ const [mounted, setMounted] = useState2(open);
949
+ useEffect(() => {
950
+ if (open) {
951
+ setMounted(true);
952
+ return void 0;
953
+ }
954
+ const timer = window.setTimeout(() => setMounted(false), 160);
955
+ return () => window.clearTimeout(timer);
956
+ }, [open]);
957
+ return /* @__PURE__ */ jsx4(
958
+ PopupPortal,
959
+ {
960
+ anchorRef,
961
+ open: mounted,
962
+ placement,
963
+ offset: 4,
964
+ className: `sia-menu__popup sia-menu--${theme}${open ? " is-open" : " is-closing"}`,
965
+ "data-sia-menu-owner": menuId,
966
+ onMouseEnter,
967
+ onMouseLeave,
968
+ children: /* @__PURE__ */ jsx4("ul", { className: "sia-menu__popup-list", role: "menu", children })
969
+ }
970
+ );
971
+ }
972
+ function MenuEntry({
973
+ item,
974
+ level,
975
+ parents,
976
+ props
977
+ }) {
978
+ const anchorRef = useRef2(null);
979
+ const closeTimerRef = useRef2(void 0);
980
+ const hasChildren = Boolean(item.children?.length);
981
+ const isOpen = props.open.includes(item.key);
982
+ const isSelected = props.selected.includes(item.key);
983
+ const path = [item.key, ...parents];
984
+ const collapsed = props.inlineCollapsed && level === 0;
985
+ const inlineSubmenu = props.mode === "inline" && !collapsed;
986
+ useEffect(() => () => {
987
+ if (closeTimerRef.current !== void 0) window.clearTimeout(closeTimerRef.current);
988
+ }, []);
989
+ function cancelClose() {
990
+ if (closeTimerRef.current !== void 0) {
991
+ window.clearTimeout(closeTimerRef.current);
992
+ closeTimerRef.current = void 0;
993
+ }
994
+ }
995
+ function scheduleClose() {
996
+ cancelClose();
997
+ closeTimerRef.current = window.setTimeout(() => props.toggle(item.key, false), 100);
998
+ }
999
+ const hover = props.triggerSubMenuAction === "hover" && hasChildren && !inlineSubmenu;
1000
+ const submenu = hasChildren ? /* @__PURE__ */ jsx4(MenuLevel, { items: item.children ?? [], level: level + 1, parents: [item.key, ...parents], props }) : null;
1001
+ const popupPlacement = props.mode === "horizontal" && level === 0 ? "bottom-start" : "right-start";
1002
+ return /* @__PURE__ */ jsxs3(
1003
+ "li",
1004
+ {
1005
+ className: `sia-menu__entry${isOpen ? " is-open" : ""}${isSelected ? " is-selected" : ""}${item.disabled ? " is-disabled" : ""}${item.danger ? " is-danger" : ""}`,
1006
+ onMouseEnter: hover ? () => {
1007
+ cancelClose();
1008
+ props.toggle(item.key, true);
1009
+ } : void 0,
1010
+ onMouseLeave: hover ? scheduleClose : void 0,
1011
+ children: [
1012
+ /* @__PURE__ */ jsxs3(
1013
+ "button",
1014
+ {
1015
+ ref: anchorRef,
1016
+ type: "button",
1017
+ className: "sia-menu__item",
1018
+ style: { paddingInlineStart: props.mode === "inline" && !props.inlineCollapsed ? 12 + level * props.inlineIndent : void 0 },
1019
+ title: collapsed ? item.title ?? (typeof item.label === "string" ? item.label : void 0) : item.title,
1020
+ disabled: item.disabled,
1021
+ "aria-current": isSelected ? "page" : void 0,
1022
+ "aria-expanded": hasChildren ? isOpen : void 0,
1023
+ onClick: (event) => hasChildren ? props.toggle(item.key) : props.select(item, path, event),
1024
+ children: [
1025
+ item.icon ? /* @__PURE__ */ jsx4("span", { className: "sia-menu__icon", children: item.icon }) : null,
1026
+ !collapsed ? /* @__PURE__ */ jsx4("span", { className: "sia-menu__label", children: item.label }) : null,
1027
+ !collapsed && item.extra ? /* @__PURE__ */ jsx4("span", { className: "sia-menu__extra", children: item.extra }) : null,
1028
+ !collapsed && hasChildren ? /* @__PURE__ */ jsx4(Icon, { className: "sia-menu__expand-icon", name: "chevron-down", size: 13 }) : null
1029
+ ]
1030
+ }
1031
+ ),
1032
+ hasChildren ? inlineSubmenu ? /* @__PURE__ */ jsx4("ul", { className: "sia-menu__submenu", role: "menu", "aria-hidden": !isOpen, children: submenu }) : /* @__PURE__ */ jsx4(
1033
+ MenuPopup,
1034
+ {
1035
+ anchorRef,
1036
+ open: isOpen,
1037
+ placement: popupPlacement,
1038
+ menuId: props.menuId,
1039
+ theme: props.theme,
1040
+ onMouseEnter: hover ? cancelClose : void 0,
1041
+ onMouseLeave: hover ? scheduleClose : void 0,
1042
+ children: submenu
1043
+ }
1044
+ ) : null
1045
+ ]
1046
+ }
1047
+ );
1048
+ }
1049
+ function MenuLevel({
1050
+ items,
1051
+ level,
1052
+ parents,
1053
+ props
1054
+ }) {
1055
+ return /* @__PURE__ */ jsx4(Fragment3, { children: items.map((item, index) => {
1056
+ if (item.type === "divider") return /* @__PURE__ */ jsx4("li", { className: "sia-menu__divider", role: "separator" }, item.key || `divider-${index}`);
1057
+ if (item.type === "group") return /* @__PURE__ */ jsxs3("li", { className: "sia-menu__group", children: [
1058
+ /* @__PURE__ */ jsx4("div", { className: "sia-menu__group-title", children: item.label }),
1059
+ /* @__PURE__ */ jsx4("ul", { role: "group", children: /* @__PURE__ */ jsx4(MenuLevel, { items: item.children ?? [], level: level + 1, parents: [...parents, item.key], props }) })
1060
+ ] }, item.key);
1061
+ return /* @__PURE__ */ jsx4(MenuEntry, { item, level, parents, props }, item.key);
1062
+ }) });
1063
+ }
1064
+ function Menu({
1065
+ items,
1066
+ mode = "vertical",
1067
+ theme = "light",
1068
+ selectedKeys,
1069
+ defaultSelectedKeys = [],
1070
+ openKeys,
1071
+ defaultOpenKeys = [],
1072
+ multiple = false,
1073
+ selectable = true,
1074
+ inlineCollapsed = false,
1075
+ inlineIndent = 20,
1076
+ triggerSubMenuAction = "click",
1077
+ onClick,
1078
+ onSelect,
1079
+ onDeselect,
1080
+ onOpenChange,
1081
+ className = "",
1082
+ ...rest
1083
+ }) {
1084
+ const menuId = useId();
1085
+ const rootRef = useRef2(null);
1086
+ const [selected, setSelected] = useControllableState({ value: selectedKeys, defaultValue: defaultSelectedKeys });
1087
+ const [open, setOpen] = useControllableState({ value: openKeys, defaultValue: defaultOpenKeys, onChange: (next) => onOpenChange?.([...next]) });
1088
+ useEffect(() => {
1089
+ if (mode === "inline" || !open.length) return void 0;
1090
+ const closeOutside = (event) => {
1091
+ const target = event.target;
1092
+ if (rootRef.current?.contains(target)) return;
1093
+ const owner = target instanceof Element ? target.closest("[data-sia-menu-owner]")?.getAttribute("data-sia-menu-owner") : null;
1094
+ if (owner !== menuId) setOpen([]);
1095
+ };
1096
+ document.addEventListener("pointerdown", closeOutside);
1097
+ return () => document.removeEventListener("pointerdown", closeOutside);
1098
+ }, [menuId, mode, open.length, setOpen]);
1099
+ function toggle(key, force) {
1100
+ const shouldOpen = force ?? !open.includes(key);
1101
+ setOpen(shouldOpen ? open.includes(key) ? open : [...open, key] : open.filter((item) => item !== key));
1102
+ }
1103
+ function select(item, keyPath, domEvent) {
1104
+ const info = { key: item.key, keyPath, domEvent, item };
1105
+ onClick?.(info);
1106
+ if (!selectable) return;
1107
+ const exists = selected.includes(item.key);
1108
+ const next = multiple ? exists ? selected.filter((key) => key !== item.key) : [...selected, item.key] : [item.key];
1109
+ setSelected(next);
1110
+ if (exists && multiple) onDeselect?.({ ...info, selectedKeys: [...next] });
1111
+ else onSelect?.({ ...info, selectedKeys: [...next] });
1112
+ if (mode !== "inline") setOpen([]);
1113
+ }
1114
+ return /* @__PURE__ */ jsx4("ul", { ref: rootRef, className: `sia-menu sia-menu--${mode} sia-menu--${theme}${inlineCollapsed ? " sia-menu--collapsed" : ""} ${className}`.trim(), role: "menu", ...rest, "data-sia-menu-owner": menuId, children: /* @__PURE__ */ jsx4(MenuLevel, { items, level: 0, parents: [], props: { menuId, mode, theme, multiple, selectable, inlineCollapsed, inlineIndent, triggerSubMenuAction, selected, open, select, toggle } }) });
1115
+ }
1116
+ function Steps({ items, current = 0, initial = 0, direction = "horizontal", type = "default", size = "default", status = "process", progressDot = false, onChange, className = "", ...props }) {
1117
+ return /* @__PURE__ */ jsx4("div", { className: `sia-steps sia-steps--${direction} sia-steps--${type} sia-steps--${size} ${className}`.trim(), ...props, children: items.map((item, rawIndex) => {
1118
+ const index = rawIndex + initial;
1119
+ const itemStatus = item.status ?? (index < current ? "finish" : index === current ? status : "wait");
1120
+ const dot = /* @__PURE__ */ jsx4("span", { className: "sia-steps__dot" });
1121
+ const icon = progressDot ? typeof progressDot === "function" ? progressDot(dot, { index, status: itemStatus, title: item.title, description: item.description }) : dot : item.icon ?? (itemStatus === "finish" ? /* @__PURE__ */ jsx4(Icon, { name: "check", size: 15 }) : itemStatus === "error" ? /* @__PURE__ */ jsx4(Icon, { name: "close", size: 14 }) : index + 1);
1122
+ return /* @__PURE__ */ jsxs3("button", { type: "button", className: `sia-steps__item sia-steps__item--${itemStatus}`, disabled: item.disabled || !onChange, onClick: () => onChange?.(index), children: [
1123
+ /* @__PURE__ */ jsxs3("span", { className: "sia-steps__head", children: [
1124
+ /* @__PURE__ */ jsx4("span", { className: "sia-steps__icon", children: icon }),
1125
+ /* @__PURE__ */ jsx4("span", { className: "sia-steps__tail" })
1126
+ ] }),
1127
+ /* @__PURE__ */ jsxs3("span", { className: "sia-steps__content", children: [
1128
+ /* @__PURE__ */ jsxs3("span", { className: "sia-steps__title", children: [
1129
+ item.title,
1130
+ item.subTitle ? /* @__PURE__ */ jsx4("small", { children: item.subTitle }) : null
1131
+ ] }),
1132
+ item.description ? /* @__PURE__ */ jsx4("span", { className: "sia-steps__description", children: item.description }) : null
1133
+ ] })
1134
+ ] }, index);
1135
+ }) });
1136
+ }
1137
+ function Segmented({ options, value, defaultValue, size = "medium", block = false, vertical = false, disabled = false, onChange, className = "", onKeyDown, ...props }) {
1138
+ const normalized = useMemo(() => options.map((option) => typeof option === "object" ? option : { label: option, value: option }), [options]);
1139
+ const [current, setCurrent] = useControllableState({ value, defaultValue: defaultValue ?? normalized[0]?.value, onChange: (next) => next !== void 0 && onChange?.(next) });
1140
+ function keyboard(event) {
1141
+ onKeyDown?.(event);
1142
+ if (!["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(event.key)) return;
1143
+ event.preventDefault();
1144
+ const enabled = normalized.filter((option) => !option.disabled);
1145
+ const index = enabled.findIndex((option) => option.value === current);
1146
+ const next = event.key === "ArrowRight" || event.key === "ArrowDown" ? enabled[(index + 1) % enabled.length] : enabled[(index - 1 + enabled.length) % enabled.length];
1147
+ if (next) setCurrent(next.value);
1148
+ }
1149
+ return /* @__PURE__ */ jsx4("div", { className: `sia-segmented sia-segmented--${size}${block ? " sia-segmented--block" : ""}${vertical ? " sia-segmented--vertical" : ""}${disabled ? " is-disabled" : ""} ${className}`.trim(), role: "radiogroup", onKeyDown: keyboard, ...props, children: normalized.map((option) => /* @__PURE__ */ jsxs3("button", { type: "button", role: "radio", "aria-checked": option.value === current, title: option.title, className: option.value === current ? "is-selected" : "", disabled: disabled || option.disabled, onClick: () => setCurrent(option.value), children: [
1150
+ option.icon,
1151
+ /* @__PURE__ */ jsx4("span", { children: option.label ?? option.value })
1152
+ ] }, option.value)) });
1153
+ }
1154
+
1155
+ // src/components/Dropdown.tsx
1156
+ import { useEffect as useEffect2, useRef as useRef3, useState as useState3 } from "react";
1157
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1158
+ var placementMap = {
1159
+ bottomLeft: "bottom-start",
1160
+ bottomRight: "bottom-end",
1161
+ topLeft: "top-start",
1162
+ topRight: "top-end"
1163
+ };
1164
+ function DropdownRoot({
1165
+ menu,
1166
+ children,
1167
+ trigger = ["hover"],
1168
+ placement = "bottomLeft",
1169
+ open,
1170
+ defaultOpen = false,
1171
+ disabled = false,
1172
+ arrow = false,
1173
+ autoFocus = false,
1174
+ openDelay = 80,
1175
+ closeDelay = 120,
1176
+ popupClassName = "",
1177
+ popupStyle,
1178
+ popupRender,
1179
+ onOpenChange,
1180
+ className = "",
1181
+ onClick,
1182
+ onMouseEnter,
1183
+ onMouseLeave,
1184
+ onContextMenu,
1185
+ onKeyDown,
1186
+ ...props
1187
+ }) {
1188
+ const rootRef = useRef3(null);
1189
+ const contextAnchorRef = useRef3(null);
1190
+ const popupRef = useRef3(null);
1191
+ const openTimerRef = useRef3(void 0);
1192
+ const closeTimerRef = useRef3(void 0);
1193
+ const [internalOpen, setInternalOpen] = useState3(defaultOpen);
1194
+ const [mounted, setMounted] = useState3(open ?? defaultOpen);
1195
+ const [contextPoint, setContextPoint] = useState3();
1196
+ const visible = open ?? internalOpen;
1197
+ const triggerSet = new Set(trigger);
1198
+ const pointAtCenter = typeof arrow === "object" && arrow.pointAtCenter;
1199
+ function clearTimer(ref) {
1200
+ if (ref.current === void 0) return;
1201
+ window.clearTimeout(ref.current);
1202
+ ref.current = void 0;
1203
+ }
1204
+ function clearTimers() {
1205
+ clearTimer(openTimerRef);
1206
+ clearTimer(closeTimerRef);
1207
+ }
1208
+ function updateOpen(next, source) {
1209
+ clearTimers();
1210
+ if (next === visible) return;
1211
+ if (open === void 0) setInternalOpen(next);
1212
+ onOpenChange?.(next, { source });
1213
+ }
1214
+ function scheduleOpen() {
1215
+ clearTimer(closeTimerRef);
1216
+ clearTimer(openTimerRef);
1217
+ openTimerRef.current = window.setTimeout(() => updateOpen(true, "trigger"), Math.max(0, openDelay));
1218
+ }
1219
+ function scheduleClose() {
1220
+ clearTimer(openTimerRef);
1221
+ clearTimer(closeTimerRef);
1222
+ closeTimerRef.current = window.setTimeout(() => updateOpen(false, "trigger"), Math.max(0, closeDelay));
1223
+ }
1224
+ useEffect2(() => {
1225
+ if (visible) {
1226
+ setMounted(true);
1227
+ return void 0;
1228
+ }
1229
+ const timer = window.setTimeout(() => setMounted(false), 160);
1230
+ return () => window.clearTimeout(timer);
1231
+ }, [visible]);
1232
+ useEffect2(() => {
1233
+ if (!visible && !mounted) setContextPoint(void 0);
1234
+ }, [mounted, visible]);
1235
+ useEffect2(() => () => clearTimers(), []);
1236
+ useEffect2(() => {
1237
+ if (!visible) return void 0;
1238
+ const contextMenuTrigger = triggerSet.has("contextMenu");
1239
+ const closeOutside = (event) => {
1240
+ const target = event.target;
1241
+ if (popupRef.current?.contains(target)) return;
1242
+ if (!contextMenuTrigger && rootRef.current?.contains(target)) return;
1243
+ const targetOwner = target instanceof Element ? target.closest("[data-sia-menu-owner]")?.getAttribute("data-sia-menu-owner") : null;
1244
+ const menuOwner = popupRef.current?.querySelector("[data-sia-menu-owner]")?.getAttribute("data-sia-menu-owner");
1245
+ if (menuOwner && targetOwner === menuOwner) return;
1246
+ updateOpen(false, "trigger");
1247
+ };
1248
+ const closeWithEscape = (event) => {
1249
+ if (event.key !== "Escape") return;
1250
+ updateOpen(false, "trigger");
1251
+ rootRef.current?.querySelector("button, a, [tabindex]:not([tabindex='-1'])")?.focus();
1252
+ };
1253
+ const keepOpenOverNestedMenu = (event) => {
1254
+ const target = event.target;
1255
+ if (target instanceof Element && target.closest(".sia-menu__popup")) clearTimer(closeTimerRef);
1256
+ };
1257
+ document.addEventListener("pointerdown", closeOutside);
1258
+ document.addEventListener("keydown", closeWithEscape);
1259
+ document.addEventListener("pointerover", keepOpenOverNestedMenu);
1260
+ return () => {
1261
+ document.removeEventListener("pointerdown", closeOutside);
1262
+ document.removeEventListener("keydown", closeWithEscape);
1263
+ document.removeEventListener("pointerover", keepOpenOverNestedMenu);
1264
+ };
1265
+ }, [visible]);
1266
+ useEffect2(() => {
1267
+ if (!visible || !mounted || !autoFocus) return void 0;
1268
+ const frame = window.requestAnimationFrame(() => {
1269
+ popupRef.current?.querySelector(
1270
+ "[data-sia-dropdown-autofocus], input:not(:disabled), textarea:not(:disabled), .sia-menu__item:not(:disabled)"
1271
+ )?.focus();
1272
+ });
1273
+ return () => window.cancelAnimationFrame(frame);
1274
+ }, [autoFocus, mounted, visible]);
1275
+ function handleMenuClick(info) {
1276
+ info.domEvent.stopPropagation();
1277
+ menu.onClick?.(info);
1278
+ updateOpen(false, "menu");
1279
+ }
1280
+ function handleClick(event) {
1281
+ onClick?.(event);
1282
+ if (disabled || !triggerSet.has("click") || event.defaultPrevented) return;
1283
+ setContextPoint(void 0);
1284
+ updateOpen(!visible, "trigger");
1285
+ }
1286
+ function handleMouseEnter(event) {
1287
+ onMouseEnter?.(event);
1288
+ if (!disabled && triggerSet.has("hover")) scheduleOpen();
1289
+ }
1290
+ function handleMouseLeave(event) {
1291
+ onMouseLeave?.(event);
1292
+ if (!disabled && triggerSet.has("hover")) scheduleClose();
1293
+ }
1294
+ function handleContextMenu(event) {
1295
+ onContextMenu?.(event);
1296
+ if (disabled || !triggerSet.has("contextMenu") || event.defaultPrevented) return;
1297
+ event.preventDefault();
1298
+ event.stopPropagation();
1299
+ setContextPoint({ x: event.clientX, y: event.clientY });
1300
+ updateOpen(true, "trigger");
1301
+ }
1302
+ function handleKeyDown(event) {
1303
+ onKeyDown?.(event);
1304
+ if (disabled || event.defaultPrevented) return;
1305
+ if (event.key === "ArrowDown" && (triggerSet.has("click") || triggerSet.has("hover"))) {
1306
+ event.preventDefault();
1307
+ setContextPoint(void 0);
1308
+ updateOpen(true, "trigger");
1309
+ } else if (triggerSet.has("contextMenu") && (event.key === "ContextMenu" || event.shiftKey && event.key === "F10")) {
1310
+ event.preventDefault();
1311
+ setContextPoint(void 0);
1312
+ updateOpen(true, "trigger");
1313
+ }
1314
+ }
1315
+ const menuNode = /* @__PURE__ */ jsx5(
1316
+ Menu,
1317
+ {
1318
+ mode: "vertical",
1319
+ theme: menu.theme,
1320
+ items: menu.items,
1321
+ multiple: menu.multiple,
1322
+ selectable: menu.selectable,
1323
+ selectedKeys: menu.selectedKeys,
1324
+ defaultSelectedKeys: menu.defaultSelectedKeys,
1325
+ triggerSubMenuAction: "hover",
1326
+ onClick: handleMenuClick,
1327
+ onSelect: menu.onSelect,
1328
+ onDeselect: menu.onDeselect,
1329
+ className: "sia-dropdown__menu"
1330
+ }
1331
+ );
1332
+ return /* @__PURE__ */ jsxs4(
1333
+ "span",
1334
+ {
1335
+ ref: rootRef,
1336
+ className: `sia-dropdown${visible ? " is-open" : ""}${disabled ? " is-disabled" : ""} ${className}`.trim(),
1337
+ "aria-expanded": visible,
1338
+ "aria-haspopup": "menu",
1339
+ tabIndex: triggerSet.has("contextMenu") ? 0 : void 0,
1340
+ onClick: handleClick,
1341
+ onMouseEnter: handleMouseEnter,
1342
+ onMouseLeave: handleMouseLeave,
1343
+ onContextMenu: handleContextMenu,
1344
+ onKeyDown: handleKeyDown,
1345
+ ...props,
1346
+ children: [
1347
+ children,
1348
+ /* @__PURE__ */ jsx5(
1349
+ "span",
1350
+ {
1351
+ ref: contextAnchorRef,
1352
+ className: "sia-dropdown__context-anchor",
1353
+ style: contextPoint ? { left: contextPoint.x, top: contextPoint.y } : void 0,
1354
+ "aria-hidden": "true"
1355
+ }
1356
+ ),
1357
+ /* @__PURE__ */ jsx5(
1358
+ PopupPortal,
1359
+ {
1360
+ ref: popupRef,
1361
+ anchorRef: contextPoint ? contextAnchorRef : rootRef,
1362
+ open: mounted,
1363
+ placement: contextPoint ? "bottom-start" : placementMap[placement],
1364
+ offset: contextPoint ? 2 : 6,
1365
+ className: `sia-dropdown__popup${visible ? " is-open" : " is-closing"}${arrow ? " sia-dropdown__popup--arrow" : ""}${pointAtCenter ? " sia-dropdown__popup--arrow-center" : ""} ${popupClassName}`.trim(),
1366
+ style: popupStyle,
1367
+ onMouseEnter: () => {
1368
+ clearTimer(closeTimerRef);
1369
+ if (!disabled && triggerSet.has("hover")) clearTimer(openTimerRef);
1370
+ },
1371
+ onMouseLeave: () => {
1372
+ if (!disabled && triggerSet.has("hover")) scheduleClose();
1373
+ },
1374
+ onClick: (event) => event.stopPropagation(),
1375
+ children: popupRender ? popupRender(menuNode) : menuNode
1376
+ },
1377
+ contextPoint ? `context-${contextPoint.x}-${contextPoint.y}` : "trigger"
1378
+ )
1379
+ ]
1380
+ }
1381
+ );
1382
+ }
1383
+ function DropdownButton({
1384
+ children,
1385
+ className = "",
1386
+ buttonProps,
1387
+ onClick,
1388
+ disabled,
1389
+ trigger = ["click"],
1390
+ ...dropdownProps
1391
+ }) {
1392
+ return /* @__PURE__ */ jsxs4("span", { className: `sia-dropdown-button ${className}`.trim(), children: [
1393
+ /* @__PURE__ */ jsx5(Button, { ...buttonProps, disabled, onClick, children }),
1394
+ /* @__PURE__ */ jsx5(DropdownRoot, { ...dropdownProps, disabled, trigger, children: /* @__PURE__ */ jsx5(
1395
+ Button,
1396
+ {
1397
+ ...buttonProps,
1398
+ className: `sia-dropdown-button__arrow ${buttonProps?.className ?? ""}`.trim(),
1399
+ disabled,
1400
+ icon: /* @__PURE__ */ jsx5(Icon, { name: "chevron-down", size: 14 }),
1401
+ "aria-label": "\u5C55\u5F00\u4E0B\u62C9\u83DC\u5355"
1402
+ }
1403
+ ) })
1404
+ ] });
1405
+ }
1406
+ var Dropdown = Object.assign(DropdownRoot, { Button: DropdownButton });
1407
+
1408
+ // src/components/Input.tsx
1409
+ import { forwardRef as forwardRef3, useId as useId2, useRef as useRef4, useState as useState4 } from "react";
1410
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1411
+ var Input = forwardRef3(function Input2({
1412
+ label,
1413
+ hint,
1414
+ status = "default",
1415
+ size = "medium",
1416
+ prefix,
1417
+ suffix,
1418
+ allowClear = false,
1419
+ onClear,
1420
+ showCount = false,
1421
+ placeholderMode,
1422
+ placeholder,
1423
+ className = "",
1424
+ id,
1425
+ disabled,
1426
+ value,
1427
+ defaultValue,
1428
+ maxLength,
1429
+ onChange,
1430
+ ...props
1431
+ }, forwardedRef) {
1432
+ const fallbackId = useId2();
1433
+ const inputId = id ?? fallbackId;
1434
+ const localRef = useRef4(null);
1435
+ const [uncontrolledValue, setUncontrolledValue] = useState4(() => defaultValue === void 0 ? "" : String(defaultValue));
1436
+ const currentText = value !== void 0 ? String(value) : uncontrolledValue;
1437
+ const hasValue = currentText.length > 0;
1438
+ const floatingPlaceholder = usePlaceholderMode(placeholderMode) === "floating" && Boolean(placeholder);
1439
+ const hintId = `${inputId}-hint`;
1440
+ const describedBy = [props["aria-describedby"], hint ? hintId : null].filter(Boolean).join(" ") || void 0;
1441
+ function setRef(node) {
1442
+ localRef.current = node;
1443
+ if (typeof forwardedRef === "function") forwardedRef(node);
1444
+ else if (forwardedRef) forwardedRef.current = node;
1445
+ }
1446
+ function handleChange(event) {
1447
+ if (maxLength !== void 0 && maxLength >= 0 && event.target.value.length > maxLength) {
1448
+ const valueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
1449
+ valueSetter?.call(event.target, event.target.value.slice(0, maxLength));
1450
+ }
1451
+ setUncontrolledValue(event.target.value);
1452
+ onChange?.(event);
1453
+ }
1454
+ function clearValue() {
1455
+ const input2 = localRef.current;
1456
+ if (!input2 || disabled) return;
1457
+ const valueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
1458
+ valueSetter?.call(input2, "");
1459
+ input2.dispatchEvent(new Event("input", { bubbles: true }));
1460
+ setUncontrolledValue("");
1461
+ input2.focus();
1462
+ onClear?.();
1463
+ }
1464
+ function handleControlMouseDown(event) {
1465
+ if (disabled || event.defaultPrevented || event.button !== 0) return;
1466
+ const target = event.target;
1467
+ if (!(target instanceof Element)) return;
1468
+ const interactive = target.closest("input, textarea, select, button, a[href], [tabindex], [contenteditable]:not([contenteditable='false']), [role='button'], [role='link']");
1469
+ if (interactive && event.currentTarget.contains(interactive) && !interactive.classList.contains("sia-input-control__clear")) return;
1470
+ event.preventDefault();
1471
+ localRef.current?.focus({ preventScroll: true });
1472
+ }
1473
+ const input = /* @__PURE__ */ jsx6(
1474
+ "input",
1475
+ {
1476
+ ...props,
1477
+ ref: setRef,
1478
+ id: inputId,
1479
+ className: "sia-input",
1480
+ disabled,
1481
+ value,
1482
+ defaultValue,
1483
+ maxLength,
1484
+ placeholder,
1485
+ "aria-describedby": describedBy,
1486
+ "aria-invalid": status === "error" || void 0,
1487
+ onChange: handleChange
1488
+ }
1489
+ );
1490
+ const control = /* @__PURE__ */ jsxs5("span", { onMouseDown: handleControlMouseDown, className: `sia-input-control sia-input-control--${size} sia-input-control--${status}${floatingPlaceholder ? " sia-input-control--floating" : ""}${floatingPlaceholder && hasValue ? " is-filled" : ""}${disabled ? " is-disabled" : ""}`, children: [
1491
+ prefix ? /* @__PURE__ */ jsx6("span", { className: "sia-input-control__affix", children: prefix }) : null,
1492
+ floatingPlaceholder ? /* @__PURE__ */ jsxs5("span", { className: "sia-input-control__input-wrap", children: [
1493
+ input,
1494
+ /* @__PURE__ */ jsx6("span", { className: "sia-input-control__floating-placeholder", "aria-hidden": "true", children: placeholder })
1495
+ ] }) : input,
1496
+ allowClear && hasValue && !disabled ? /* @__PURE__ */ jsx6("button", { className: "sia-input-control__clear", type: "button", "aria-label": "\u6E05\u7A7A\u8F93\u5165", onClick: clearValue, children: /* @__PURE__ */ jsx6(Icon, { name: "circle-close", variant: "filled", size: 15 }) }) : null,
1497
+ suffix ? /* @__PURE__ */ jsx6("span", { className: "sia-input-control__affix", children: suffix }) : null,
1498
+ showCount ? /* @__PURE__ */ jsxs5("span", { className: `sia-input-control__count${maxLength !== void 0 && currentText.length >= maxLength ? " is-limit" : ""}`, "aria-live": "polite", children: [
1499
+ currentText.length,
1500
+ maxLength !== void 0 ? `/${maxLength}` : null
1501
+ ] }) : null
1502
+ ] });
1503
+ if (!label && !hint) return /* @__PURE__ */ jsx6("span", { className: `sia-field ${className}`.trim(), children: control });
1504
+ return /* @__PURE__ */ jsxs5("span", { className: `sia-field ${className}`.trim(), children: [
1505
+ label ? /* @__PURE__ */ jsx6("label", { className: "sia-field__label", htmlFor: inputId, children: label }) : null,
1506
+ control,
1507
+ hint ? /* @__PURE__ */ jsx6("span", { id: hintId, className: `sia-field__hint sia-field__hint--${status}`, children: hint }) : null
1508
+ ] });
1509
+ });
1510
+
925
1511
  export {
926
1512
  ICON_NAMES,
927
1513
  FILLED_ICON_NAMES,
928
1514
  Icon,
929
- PopupPortal
1515
+ PopupPortal,
1516
+ Menu,
1517
+ Steps,
1518
+ Segmented,
1519
+ Dropdown,
1520
+ Input
930
1521
  };