@sia.soul/sia-react-ui 0.1.77 → 0.1.79

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,6 +1,7 @@
1
1
  import {
2
- Button
3
- } from "./chunk-IKAMZNCK.js";
2
+ Button,
3
+ TextArea
4
+ } from "./chunk-JZWTTSOZ.js";
4
5
  import {
5
6
  PopupPortal,
6
7
  useControlSize,
@@ -1340,10 +1341,331 @@ var Dropdown = Object.assign(DropdownRoot, {
1340
1341
  Button: DropdownButton
1341
1342
  });
1342
1343
 
1344
+ // src/components/Modal.tsx
1345
+ import { forwardRef as forwardRef2, useEffect as useEffect4, useId as useId2, useRef as useRef4, useState as useState3 } from "react";
1346
+ import { createRoot } from "react-dom/client";
1347
+
1348
+ // src/components/Overlay.tsx
1349
+ import { useEffect as useEffect3, useRef as useRef3 } from "react";
1350
+ import { createPortal } from "react-dom";
1351
+ var bodyLockCount = 0;
1352
+ var previousBodyOverflow = "";
1353
+ var overlayStack = [];
1354
+ function lockBodyScroll() {
1355
+ if (bodyLockCount === 0) {
1356
+ previousBodyOverflow = document.body.style.overflow;
1357
+ document.body.style.overflow = "hidden";
1358
+ }
1359
+ bodyLockCount += 1;
1360
+ return () => {
1361
+ bodyLockCount = Math.max(0, bodyLockCount - 1);
1362
+ if (bodyLockCount === 0) document.body.style.overflow = previousBodyOverflow;
1363
+ };
1364
+ }
1365
+ function focusableElements(container) {
1366
+ return [...container.querySelectorAll(
1367
+ 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])'
1368
+ )].filter((element) => !element.hidden && element.getAttribute("aria-hidden") !== "true");
1369
+ }
1370
+ function useOverlayLifecycle(open, panelRef, onRequestClose, keyboard = true) {
1371
+ const overlayIdRef = useRef3(/* @__PURE__ */ Symbol("sia-overlay"));
1372
+ const closeRef = useRef3(onRequestClose);
1373
+ closeRef.current = onRequestClose;
1374
+ useEffect3(() => {
1375
+ if (!open || typeof document === "undefined") return void 0;
1376
+ const overlayId = overlayIdRef.current;
1377
+ const previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
1378
+ overlayStack.push(overlayId);
1379
+ const unlockBody = lockBodyScroll();
1380
+ const focusTimer = window.setTimeout(() => {
1381
+ const panel = panelRef.current;
1382
+ if (!panel) return;
1383
+ const [firstFocusable] = focusableElements(panel);
1384
+ (firstFocusable ?? panel).focus({ preventScroll: true });
1385
+ }, 0);
1386
+ function handleKeyDown(event) {
1387
+ if (overlayStack.at(-1) !== overlayId) return;
1388
+ if (event.key === "Escape" && keyboard) {
1389
+ event.preventDefault();
1390
+ closeRef.current();
1391
+ return;
1392
+ }
1393
+ if (event.key !== "Tab" || !panelRef.current) return;
1394
+ const focusable = focusableElements(panelRef.current);
1395
+ if (focusable.length === 0) {
1396
+ event.preventDefault();
1397
+ panelRef.current.focus();
1398
+ return;
1399
+ }
1400
+ const first = focusable[0];
1401
+ const last = focusable.at(-1);
1402
+ if (event.shiftKey && document.activeElement === first) {
1403
+ event.preventDefault();
1404
+ last.focus();
1405
+ } else if (!event.shiftKey && document.activeElement === last) {
1406
+ event.preventDefault();
1407
+ first.focus();
1408
+ }
1409
+ }
1410
+ document.addEventListener("keydown", handleKeyDown);
1411
+ return () => {
1412
+ window.clearTimeout(focusTimer);
1413
+ document.removeEventListener("keydown", handleKeyDown);
1414
+ const index = overlayStack.lastIndexOf(overlayId);
1415
+ if (index >= 0) overlayStack.splice(index, 1);
1416
+ unlockBody();
1417
+ previouslyFocused?.focus({ preventScroll: true });
1418
+ };
1419
+ }, [keyboard, open, panelRef]);
1420
+ }
1421
+ function OverlayPortal({ children, container }) {
1422
+ if (typeof document === "undefined") return null;
1423
+ const target = typeof container === "function" ? container() : container ?? document.body;
1424
+ return createPortal(children, target);
1425
+ }
1426
+
1427
+ // src/components/Modal.tsx
1428
+ import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1429
+ var modalHandles = /* @__PURE__ */ new Set();
1430
+ var MODAL_MOTION_DURATION = 220;
1431
+ var typeIcons = {
1432
+ info: /* @__PURE__ */ jsx5(Icon, { name: "info", size: 23 }),
1433
+ success: /* @__PURE__ */ jsx5(Icon, { name: "circle-check", size: 23 }),
1434
+ warning: /* @__PURE__ */ jsx5(Icon, { name: "warning", size: 23 }),
1435
+ error: /* @__PURE__ */ jsx5(Icon, { name: "circle-close", size: 23 }),
1436
+ confirm: /* @__PURE__ */ jsx5(Icon, { name: "question", size: 23 })
1437
+ };
1438
+ var ModalRoot = forwardRef2(function Modal({
1439
+ open,
1440
+ title,
1441
+ children,
1442
+ footer,
1443
+ footerExtra,
1444
+ type = "default",
1445
+ okText = "\u786E\u5B9A",
1446
+ cancelText = "\u53D6\u6D88",
1447
+ showCancel = type === "default" || type === "confirm",
1448
+ confirmLoading = false,
1449
+ okButtonProps,
1450
+ cancelButtonProps,
1451
+ closable = true,
1452
+ maskClosable = true,
1453
+ keyboard = true,
1454
+ centered = false,
1455
+ width = 520,
1456
+ height,
1457
+ zIndex = 1e3,
1458
+ getContainer,
1459
+ onOk,
1460
+ onCancel,
1461
+ onOpenChange,
1462
+ afterOpenChange,
1463
+ className = "",
1464
+ style,
1465
+ ...props
1466
+ }, forwardedRef) {
1467
+ const localRef = useRef4(null);
1468
+ const titleId = useId2();
1469
+ const [submitting, setSubmitting] = useState3(false);
1470
+ const [rendered, setRendered] = useState3(open);
1471
+ const [closing, setClosing] = useState3(false);
1472
+ const afterOpenChangeRef = useRef4(afterOpenChange);
1473
+ afterOpenChangeRef.current = afterOpenChange;
1474
+ const submitLock = useRef4(false);
1475
+ useEffect4(() => {
1476
+ if (!open || !rendered) return void 0;
1477
+ const timer = window.setTimeout(() => afterOpenChangeRef.current?.(true), MODAL_MOTION_DURATION);
1478
+ return () => window.clearTimeout(timer);
1479
+ }, [open, rendered]);
1480
+ useEffect4(() => {
1481
+ if (open) {
1482
+ setRendered(true);
1483
+ setClosing(false);
1484
+ return void 0;
1485
+ }
1486
+ if (!rendered) return void 0;
1487
+ setClosing(true);
1488
+ const timer = window.setTimeout(() => {
1489
+ setRendered(false);
1490
+ setClosing(false);
1491
+ afterOpenChangeRef.current?.(false);
1492
+ }, MODAL_MOTION_DURATION);
1493
+ return () => window.clearTimeout(timer);
1494
+ }, [open, rendered]);
1495
+ function setRef(node) {
1496
+ localRef.current = node;
1497
+ if (typeof forwardedRef === "function") forwardedRef(node);
1498
+ else if (forwardedRef) forwardedRef.current = node;
1499
+ }
1500
+ function requestClose() {
1501
+ if (submitting || confirmLoading) return;
1502
+ onCancel?.();
1503
+ onOpenChange?.(false);
1504
+ }
1505
+ async function handleOk() {
1506
+ if (submitLock.current || confirmLoading) return;
1507
+ submitLock.current = true;
1508
+ if (!onOk) {
1509
+ onOpenChange?.(false);
1510
+ submitLock.current = false;
1511
+ return;
1512
+ }
1513
+ try {
1514
+ const result = onOk();
1515
+ if (result instanceof Promise) {
1516
+ setSubmitting(true);
1517
+ const resolved = await result;
1518
+ if (resolved !== false) onOpenChange?.(false);
1519
+ } else if (result !== false) {
1520
+ onOpenChange?.(false);
1521
+ }
1522
+ } catch {
1523
+ return;
1524
+ } finally {
1525
+ submitLock.current = false;
1526
+ setSubmitting(false);
1527
+ }
1528
+ }
1529
+ useOverlayLifecycle(rendered, localRef, requestClose, keyboard);
1530
+ if (!rendered) return null;
1531
+ const mergedStyle = {
1532
+ ...height !== void 0 ? { display: "flex", flexDirection: "column", height, maxHeight: "calc(100dvh - 48px)" } : {},
1533
+ ...style,
1534
+ "--sia-modal-width": typeof width === "number" ? `${width}px` : width
1535
+ };
1536
+ const loading = submitting || confirmLoading;
1537
+ const defaultFooter = /* @__PURE__ */ jsxs5(Fragment4, { children: [
1538
+ showCancel ? /* @__PURE__ */ jsx5(Button, { ...cancelButtonProps, onClick: requestClose, disabled: loading || cancelButtonProps?.disabled, children: cancelText }) : null,
1539
+ /* @__PURE__ */ jsx5(Button, { variant: "primary", ...okButtonProps, onClick: handleOk, loading, children: okText })
1540
+ ] });
1541
+ return /* @__PURE__ */ jsx5(OverlayPortal, { container: getContainer, children: /* @__PURE__ */ jsx5(
1542
+ "div",
1543
+ {
1544
+ className: `sia-modal-root${centered ? " sia-modal-root--centered" : ""}`,
1545
+ "data-state": closing ? "closing" : "open",
1546
+ style: { zIndex },
1547
+ onMouseDown: (event) => {
1548
+ if (event.target === event.currentTarget && maskClosable) requestClose();
1549
+ },
1550
+ children: /* @__PURE__ */ jsxs5(
1551
+ "div",
1552
+ {
1553
+ ref: setRef,
1554
+ className: `sia-modal sia-modal--${type} ${className}`.trim(),
1555
+ style: mergedStyle,
1556
+ role: "dialog",
1557
+ "aria-modal": "true",
1558
+ "aria-labelledby": title ? titleId : void 0,
1559
+ tabIndex: -1,
1560
+ ...withTitleTooltip(props),
1561
+ children: [
1562
+ /* @__PURE__ */ jsxs5("div", { className: "sia-modal__header", style: height !== void 0 ? { flexShrink: 0 } : void 0, children: [
1563
+ /* @__PURE__ */ jsxs5("div", { className: "sia-modal__heading", children: [
1564
+ typeIcons[type] ? /* @__PURE__ */ jsx5("span", { className: "sia-modal__type-icon", "aria-hidden": "true", children: typeIcons[type] }) : null,
1565
+ title ? /* @__PURE__ */ jsx5("strong", { id: titleId, children: title }) : null
1566
+ ] }),
1567
+ closable ? /* @__PURE__ */ jsx5("button", { type: "button", className: "sia-modal__close", "aria-label": "\u5173\u95ED\u5BF9\u8BDD\u6846", onClick: requestClose, children: /* @__PURE__ */ jsx5(Icon, { name: "close", size: 17 }) }) : null
1568
+ ] }),
1569
+ children !== void 0 ? /* @__PURE__ */ jsx5("div", { className: "sia-modal__body", style: height !== void 0 ? { flex: 1, minHeight: 0, overflow: "auto" } : void 0, children }) : null,
1570
+ footer !== null ? /* @__PURE__ */ jsxs5("div", { className: "sia-modal__footer", style: height !== void 0 ? { flexShrink: 0 } : void 0, children: [
1571
+ footer === void 0 && footerExtra != null ? /* @__PURE__ */ jsx5("div", { style: { marginRight: "auto" }, children: footerExtra }) : null,
1572
+ footer ?? defaultFooter
1573
+ ] }) : null
1574
+ ]
1575
+ }
1576
+ )
1577
+ }
1578
+ ) });
1579
+ });
1580
+ function openModal(config) {
1581
+ if (typeof document === "undefined") return { destroy() {
1582
+ }, update() {
1583
+ } };
1584
+ const container = document.createElement("div");
1585
+ container.className = "sia-modal-api-host";
1586
+ document.body.appendChild(container);
1587
+ const root = createRoot(container);
1588
+ let currentConfig = config;
1589
+ let currentOpen = true;
1590
+ let destroyed = false;
1591
+ let mounted = false;
1592
+ function cleanup() {
1593
+ if (destroyed) return;
1594
+ destroyed = true;
1595
+ root.unmount();
1596
+ container.remove();
1597
+ modalHandles.delete(handle);
1598
+ }
1599
+ function closeWithMotion() {
1600
+ if (destroyed || !currentOpen) return;
1601
+ currentOpen = false;
1602
+ render();
1603
+ }
1604
+ function ModalInstance() {
1605
+ useEffect4(() => {
1606
+ mounted = true;
1607
+ if (!currentOpen) render();
1608
+ }, []);
1609
+ return /* @__PURE__ */ jsx5(ModalRoot, { ...currentConfig, open: !mounted || currentOpen, onOpenChange: (nextOpen) => {
1610
+ currentConfig.onOpenChange?.(nextOpen);
1611
+ if (!nextOpen) closeWithMotion();
1612
+ }, afterOpenChange: (nextOpen) => {
1613
+ try {
1614
+ currentConfig.afterOpenChange?.(nextOpen);
1615
+ } finally {
1616
+ if (!nextOpen) queueMicrotask(cleanup);
1617
+ }
1618
+ } });
1619
+ }
1620
+ function render() {
1621
+ root.render(/* @__PURE__ */ jsx5(ModalInstance, {}));
1622
+ }
1623
+ const handle = {
1624
+ destroy: closeWithMotion,
1625
+ update(next) {
1626
+ if (destroyed) return;
1627
+ currentConfig = { ...currentConfig, ...next };
1628
+ render();
1629
+ }
1630
+ };
1631
+ modalHandles.add(handle);
1632
+ render();
1633
+ return handle;
1634
+ }
1635
+ function preset(type, defaults = {}) {
1636
+ return (config) => openModal({
1637
+ okText: type === "confirm" ? "\u786E\u5B9A" : "\u77E5\u9053\u4E86",
1638
+ showCancel: type === "confirm",
1639
+ closable: type !== "confirm",
1640
+ maskClosable: type !== "confirm",
1641
+ ...defaults,
1642
+ ...config,
1643
+ type
1644
+ });
1645
+ }
1646
+ var Modal2 = Object.assign(ModalRoot, {
1647
+ /** 直接打开实例,返回更新和关闭句柄;关闭动画完成后先调用 afterOpenChange(false),再卸载实例。 */
1648
+ open: openModal,
1649
+ /** 显示普通信息提示。 */
1650
+ info: preset("info", { title: "\u63D0\u793A" }),
1651
+ /** 显示成功提示。 */
1652
+ success: preset("success", { title: "\u64CD\u4F5C\u6210\u529F" }),
1653
+ /** 显示警告提示。 */
1654
+ warning: preset("warning", { title: "\u8BF7\u6CE8\u610F" }),
1655
+ /** 显示错误提示。 */
1656
+ error: preset("error", { title: "\u64CD\u4F5C\u5931\u8D25" }),
1657
+ /** 打开确认弹框,支持异步确认;返回 false 可阻止关闭。 */
1658
+ confirm: preset("confirm", { title: "\u786E\u8BA4\u64CD\u4F5C" }),
1659
+ /** 关闭由此 API 打开的所有弹层。 */
1660
+ destroyAll() {
1661
+ [...modalHandles].forEach((handle) => handle.destroy());
1662
+ }
1663
+ });
1664
+
1343
1665
  // src/components/Input.tsx
1344
- import { forwardRef as forwardRef2, useId as useId2, useRef as useRef3, useState as useState3 } from "react";
1345
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1346
- var Input = forwardRef2(function Input2({
1666
+ import { forwardRef as forwardRef3, useId as useId3, useRef as useRef5, useState as useState4 } from "react";
1667
+ import { Fragment as Fragment5, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1668
+ var Input = forwardRef3(function Input2({
1347
1669
  label,
1348
1670
  hint,
1349
1671
  status = "default",
@@ -1362,15 +1684,18 @@ var Input = forwardRef2(function Input2({
1362
1684
  defaultValue,
1363
1685
  maxLength,
1364
1686
  onChange,
1687
+ expandable = false,
1365
1688
  ...props
1366
1689
  }, forwardedRef) {
1367
1690
  const size = useControlSize(sizeProp);
1368
- const fallbackId = useId2();
1691
+ const fallbackId = useId3();
1369
1692
  const inputId = id ?? fallbackId;
1370
- const localRef = useRef3(null);
1371
- const [uncontrolledValue, setUncontrolledValue] = useState3(() => defaultValue === void 0 ? "" : String(defaultValue));
1693
+ const localRef = useRef5(null);
1694
+ const [uncontrolledValue, setUncontrolledValue] = useState4(() => defaultValue === void 0 ? "" : String(defaultValue));
1372
1695
  const currentText = value !== void 0 ? String(value) : uncontrolledValue;
1373
1696
  const hasValue = currentText.length > 0;
1697
+ const [expanded, setExpanded] = useState4(false);
1698
+ const [expandedDraft, setExpandedDraft] = useState4("");
1374
1699
  const floatingPlaceholder = usePlaceholderMode(placeholderMode) === "floating" && Boolean(placeholder);
1375
1700
  const hintId = `${inputId}-hint`;
1376
1701
  const describedBy = [props["aria-describedby"], hint ? hintId : null].filter(Boolean).join(" ") || void 0;
@@ -1406,7 +1731,7 @@ var Input = forwardRef2(function Input2({
1406
1731
  event.preventDefault();
1407
1732
  localRef.current?.focus({ preventScroll: true });
1408
1733
  }
1409
- const input = /* @__PURE__ */ jsx5(
1734
+ const input = /* @__PURE__ */ jsx6(
1410
1735
  "input",
1411
1736
  {
1412
1737
  ...withTitleTooltip(props),
@@ -1423,24 +1748,82 @@ var Input = forwardRef2(function Input2({
1423
1748
  onChange: handleChange
1424
1749
  }
1425
1750
  );
1426
- 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: [
1427
- prefix ? /* @__PURE__ */ jsx5("span", { className: "sia-input-control__affix", children: prefix }) : null,
1428
- floatingPlaceholder ? /* @__PURE__ */ jsxs5("span", { className: "sia-input-control__input-wrap", children: [
1751
+ const control = /* @__PURE__ */ jsxs6("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: [
1752
+ prefix ? /* @__PURE__ */ jsx6("span", { className: "sia-input-control__affix", children: prefix }) : null,
1753
+ floatingPlaceholder ? /* @__PURE__ */ jsxs6("span", { className: "sia-input-control__input-wrap", children: [
1429
1754
  input,
1430
- /* @__PURE__ */ jsx5("span", { className: "sia-input-control__floating-placeholder", "aria-hidden": "true", children: placeholder })
1755
+ /* @__PURE__ */ jsx6("span", { className: "sia-input-control__floating-placeholder", "aria-hidden": "true", children: placeholder })
1431
1756
  ] }) : input,
1432
- allowClear && hasValue && !disabled ? /* @__PURE__ */ jsx5("button", { className: "sia-input-control__clear", type: "button", "aria-label": "\u6E05\u7A7A\u8F93\u5165", onClick: clearValue, children: /* @__PURE__ */ jsx5(Icon, { name: "circle-close", variant: "filled", size: 15 }) }) : null,
1433
- suffix ? /* @__PURE__ */ jsx5("span", { className: "sia-input-control__affix", children: suffix }) : null,
1434
- showCount ? /* @__PURE__ */ jsxs5("span", { className: `sia-input-control__count${maxLength !== void 0 && currentText.length >= maxLength ? " is-limit" : ""}`, "aria-live": "polite", children: [
1757
+ 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,
1758
+ suffix ? /* @__PURE__ */ jsx6("span", { className: "sia-input-control__affix", children: suffix }) : null,
1759
+ expandable && !disabled && !props.readOnly && (!props.type || props.type === "text") ? /* @__PURE__ */ jsx6(
1760
+ "button",
1761
+ {
1762
+ type: "button",
1763
+ className: "sia-input-control__expand",
1764
+ "aria-label": "\u5C55\u5F00\u7F16\u8F91",
1765
+ title: "\u5C55\u5F00\u7F16\u8F91",
1766
+ onClick: () => {
1767
+ if (localRef.current?.matches(":disabled")) return;
1768
+ setExpandedDraft(currentText);
1769
+ setExpanded(true);
1770
+ },
1771
+ children: /* @__PURE__ */ jsx6(Icon, { name: "expand", size: 15 })
1772
+ }
1773
+ ) : null,
1774
+ showCount ? /* @__PURE__ */ jsxs6("span", { className: `sia-input-control__count${maxLength !== void 0 && currentText.length >= maxLength ? " is-limit" : ""}`, "aria-live": "polite", children: [
1435
1775
  currentText.length,
1436
1776
  maxLength !== void 0 ? `/${maxLength}` : null
1437
1777
  ] }) : null
1438
1778
  ] });
1439
- if (!label && !hint) return /* @__PURE__ */ jsx5("span", { className: `sia-field ${className}`.trim(), children: control });
1440
- return /* @__PURE__ */ jsxs5("span", { className: `sia-field ${className}`.trim(), children: [
1441
- label ? /* @__PURE__ */ jsx5("label", { className: "sia-field__label", htmlFor: inputId, children: label }) : null,
1442
- control,
1443
- hint ? /* @__PURE__ */ jsx5("span", { id: hintId, className: `sia-field__hint sia-field__hint--${status}`, children: hint }) : null
1779
+ const editor = expandable ? /* @__PURE__ */ jsx6(
1780
+ Modal2,
1781
+ {
1782
+ open: expanded,
1783
+ title: "\u5C55\u5F00\u7F16\u8F91",
1784
+ okText: "\u786E\u5B9A",
1785
+ cancelText: "\u53D6\u6D88",
1786
+ onCancel: () => setExpanded(false),
1787
+ afterOpenChange: (open) => {
1788
+ if (!open) setExpandedDraft("");
1789
+ },
1790
+ onOk: () => {
1791
+ const target = localRef.current;
1792
+ if (!target || target.matches(":disabled") || props.readOnly) return false;
1793
+ const normalized = expandedDraft.replace(/\r\n|[\r\n]/g, " ");
1794
+ const next = maxLength !== void 0 && maxLength >= 0 ? normalized.slice(0, maxLength) : normalized;
1795
+ Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set?.call(target, next);
1796
+ target.dispatchEvent(new Event("input", { bubbles: true }));
1797
+ setUncontrolledValue(next);
1798
+ setExpanded(false);
1799
+ },
1800
+ children: /* @__PURE__ */ jsx6(
1801
+ TextArea,
1802
+ {
1803
+ "aria-label": "\u5C55\u5F00\u7F16\u8F91\u5185\u5BB9",
1804
+ value: expandedDraft,
1805
+ onChange: (event) => setExpandedDraft(event.target.value),
1806
+ maxLength,
1807
+ showCount,
1808
+ placeholder,
1809
+ rows: 8,
1810
+ disabled,
1811
+ readOnly: props.readOnly
1812
+ }
1813
+ )
1814
+ }
1815
+ ) : null;
1816
+ if (!label && !hint) return /* @__PURE__ */ jsxs6(Fragment5, { children: [
1817
+ /* @__PURE__ */ jsx6("span", { className: `sia-field ${className}`.trim(), children: control }),
1818
+ editor
1819
+ ] });
1820
+ return /* @__PURE__ */ jsxs6(Fragment5, { children: [
1821
+ /* @__PURE__ */ jsxs6("span", { className: `sia-field ${className}`.trim(), children: [
1822
+ label ? /* @__PURE__ */ jsx6("label", { className: "sia-field__label", htmlFor: inputId, children: label }) : null,
1823
+ control,
1824
+ hint ? /* @__PURE__ */ jsx6("span", { id: hintId, className: `sia-field__hint sia-field__hint--${status}`, children: hint }) : null
1825
+ ] }),
1826
+ editor
1444
1827
  ] });
1445
1828
  });
1446
1829
 
@@ -1452,5 +1835,8 @@ export {
1452
1835
  Steps,
1453
1836
  Segmented,
1454
1837
  Dropdown,
1838
+ useOverlayLifecycle,
1839
+ OverlayPortal,
1840
+ Modal2 as Modal,
1455
1841
  Input
1456
1842
  };
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  FloatingScrollbarProvider,
3
3
  Select
4
- } from "./chunk-TKCXP6RZ.js";
4
+ } from "./chunk-WXERMWTW.js";
5
5
  import {
6
6
  Icon
7
- } from "./chunk-YMOOL62S.js";
7
+ } from "./chunk-XHLIIDD2.js";
8
8
  import {
9
9
  PopupPortal,
10
10
  useControlSize,
@@ -1,18 +1,16 @@
1
- import {
2
- TextArea
3
- } from "./chunk-SMCYEPBL.js";
4
1
  import {
5
2
  Popover,
6
- Tooltip,
7
- useOverlayLifecycle
8
- } from "./chunk-TKCXP6RZ.js";
3
+ Tooltip
4
+ } from "./chunk-WXERMWTW.js";
9
5
  import {
10
6
  Dropdown,
11
- Icon
12
- } from "./chunk-YMOOL62S.js";
7
+ Icon,
8
+ useOverlayLifecycle
9
+ } from "./chunk-XHLIIDD2.js";
13
10
  import {
14
- Button
15
- } from "./chunk-IKAMZNCK.js";
11
+ Button,
12
+ TextArea
13
+ } from "./chunk-JZWTTSOZ.js";
16
14
  import {
17
15
  useControlSize,
18
16
  useControllableState,
@@ -1667,7 +1665,7 @@ var UploadRoot = forwardRef(function UploadRoot2({
1667
1665
  event.preventDefault();
1668
1666
  ingest(selected.map((file) => ({ file, path: file.name })));
1669
1667
  }
1670
- const trigger = !(listType === "picture-card" && full) && /* @__PURE__ */ jsx8("div", { className: "sia-upload__trigger", children: /* @__PURE__ */ jsx8(Button, { className: "sia-upload__choose", "aria-label": compactCard ? directory ? "\u9009\u62E9\u6587\u4EF6\u5939" : "\u9009\u62E9\u6587\u4EF6" : void 0, disabled: disabled || full, onClick: () => {
1668
+ const trigger = !full && /* @__PURE__ */ jsx8("div", { className: "sia-upload__trigger", children: /* @__PURE__ */ jsx8(Button, { className: "sia-upload__choose", "aria-label": compactCard ? directory ? "\u9009\u62E9\u6587\u4EF6\u5939" : "\u9009\u62E9\u6587\u4EF6" : void 0, disabled: disabled || full, onClick: () => {
1671
1669
  if (!disabled && !full && onChoose?.() !== false) inputRef.current?.click();
1672
1670
  }, children: children ?? (listType === "picture-card" ? /* @__PURE__ */ jsxs8(Fragment4, { children: [
1673
1671
  /* @__PURE__ */ jsx8(Icon, { name: "plus", size: 24 }),
@@ -1756,7 +1754,7 @@ var UploadDragger = forwardRef(function UploadDragger2({ hint = "\u652F\u6301\u5
1756
1754
  ] }) });
1757
1755
  });
1758
1756
  var Upload = Object.assign(UploadRoot, {
1759
- /** 可点击、键盘操作和拖拽的上传区域,ref 支持手动上传、取消及移除;默认内容在文字或图片列表非空且可见时收紧高度,清空后恢复。 */
1757
+ /** 可点击、键盘操作和拖拽的上传区域,ref 支持手动上传、取消及移除;达到 maxCount 后隐藏入口,低于上限时恢复;未达上限且文字或图片列表非空、可见时收紧默认内容高度。 */
1760
1758
  Dragger: UploadDragger,
1761
1759
  /** beforeUpload 返回时移除该文件,不进行上传。 */
1762
1760
  LIST_IGNORE
@@ -1887,6 +1887,13 @@ interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "prefix
1887
1887
  showCount?: boolean;
1888
1888
  /** 占位文案的显示模式 */
1889
1889
  placeholderMode?: InputPlaceholderMode;
1890
+ /**
1891
+ * 在普通文本输入框末尾显示展开按钮,弹框正文仅显示多行编辑器,继承 maxLength、placeholder 和 showCount。
1892
+ * 打开时复制当前值,确定后通过原生 input 事件触发 onChange;受控模式需由调用方回写 value,取消不修改原值。
1893
+ * 多行换行在回填单行输入框时转换为空格;禁用、只读及非 text 类型不显示展开按钮。
1894
+ * @defaultValue false
1895
+ */
1896
+ expandable?: boolean;
1890
1897
  }
1891
1898
  /** 输入框组件。 */
1892
1899
  declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
@@ -2019,7 +2026,7 @@ interface UploadProps extends Omit<HTMLAttributes<HTMLDivElement>, "defaultValue
2019
2026
  disabled?: boolean;
2020
2027
  /** 添加后自动上传;false 为手动模式,调用 ref.upload 或自定义列表操作启动。 @defaultValue true */
2021
2028
  autoUpload?: boolean;
2022
- /** 最大文件数量,包含等待及失败项;超出部分拒绝,不替换已有文件。默认不限。 */
2029
+ /** 最大文件数量,包含等待及失败项;达到上限时隐藏上传入口(含拖拽区域),低于上限后恢复,已选列表继续显示。超出部分拒绝,不替换已有文件。默认不限;有限数值向下取整且不小于 0,设为 0 时始终隐藏入口。受控列表需在 onChange 中回填后更新显示。 */
2023
2030
  maxCount?: number;
2024
2031
  /** 受控列表,onChange 中回填;外部移除记录会取消关联请求。 */
2025
2032
  fileList?: readonly UploadFile[];
@@ -2069,7 +2076,7 @@ interface UploadDraggerProps extends UploadProps {
2069
2076
 
2070
2077
  /** 上传组件,默认以带数量标题和状态的文字卡片展示已选文件;支持图片列表、照片墙、目录、粘贴与完全受控请求,未配置请求时仅选择文件。 */
2071
2078
  declare const Upload: react.ForwardRefExoticComponent<UploadProps & react.RefAttributes<UploadRef>> & {
2072
- /** 可点击、键盘操作和拖拽的上传区域,ref 支持手动上传、取消及移除;默认内容在文字或图片列表非空且可见时收紧高度,清空后恢复。 */
2079
+ /** 可点击、键盘操作和拖拽的上传区域,ref 支持手动上传、取消及移除;达到 maxCount 后隐藏入口,低于上限时恢复;未达上限且文字或图片列表非空、可见时收紧默认内容高度。 */
2073
2080
  Dragger: react.ForwardRefExoticComponent<UploadDraggerProps & react.RefAttributes<UploadRef>>;
2074
2081
  /** beforeUpload 返回时移除该文件,不进行上传。 */
2075
2082
  LIST_IGNORE: symbol;
@@ -1887,6 +1887,13 @@ interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "prefix
1887
1887
  showCount?: boolean;
1888
1888
  /** 占位文案的显示模式 */
1889
1889
  placeholderMode?: InputPlaceholderMode;
1890
+ /**
1891
+ * 在普通文本输入框末尾显示展开按钮,弹框正文仅显示多行编辑器,继承 maxLength、placeholder 和 showCount。
1892
+ * 打开时复制当前值,确定后通过原生 input 事件触发 onChange;受控模式需由调用方回写 value,取消不修改原值。
1893
+ * 多行换行在回填单行输入框时转换为空格;禁用、只读及非 text 类型不显示展开按钮。
1894
+ * @defaultValue false
1895
+ */
1896
+ expandable?: boolean;
1890
1897
  }
1891
1898
  /** 输入框组件。 */
1892
1899
  declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
@@ -2019,7 +2026,7 @@ interface UploadProps extends Omit<HTMLAttributes<HTMLDivElement>, "defaultValue
2019
2026
  disabled?: boolean;
2020
2027
  /** 添加后自动上传;false 为手动模式,调用 ref.upload 或自定义列表操作启动。 @defaultValue true */
2021
2028
  autoUpload?: boolean;
2022
- /** 最大文件数量,包含等待及失败项;超出部分拒绝,不替换已有文件。默认不限。 */
2029
+ /** 最大文件数量,包含等待及失败项;达到上限时隐藏上传入口(含拖拽区域),低于上限后恢复,已选列表继续显示。超出部分拒绝,不替换已有文件。默认不限;有限数值向下取整且不小于 0,设为 0 时始终隐藏入口。受控列表需在 onChange 中回填后更新显示。 */
2023
2030
  maxCount?: number;
2024
2031
  /** 受控列表,onChange 中回填;外部移除记录会取消关联请求。 */
2025
2032
  fileList?: readonly UploadFile[];
@@ -2069,7 +2076,7 @@ interface UploadDraggerProps extends UploadProps {
2069
2076
 
2070
2077
  /** 上传组件,默认以带数量标题和状态的文字卡片展示已选文件;支持图片列表、照片墙、目录、粘贴与完全受控请求,未配置请求时仅选择文件。 */
2071
2078
  declare const Upload: react.ForwardRefExoticComponent<UploadProps & react.RefAttributes<UploadRef>> & {
2072
- /** 可点击、键盘操作和拖拽的上传区域,ref 支持手动上传、取消及移除;默认内容在文字或图片列表非空且可见时收紧高度,清空后恢复。 */
2079
+ /** 可点击、键盘操作和拖拽的上传区域,ref 支持手动上传、取消及移除;达到 maxCount 后隐藏入口,低于上限时恢复;未达上限且文字或图片列表非空、可见时收紧默认内容高度。 */
2073
2080
  Dragger: react.ForwardRefExoticComponent<UploadDraggerProps & react.RefAttributes<UploadRef>>;
2074
2081
  /** beforeUpload 返回时移除该文件,不进行上传。 */
2075
2082
  LIST_IGNORE: symbol;