@canvas-components/react-components 0.2.0 → 0.3.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/dist/index.cjs CHANGED
@@ -47,7 +47,7 @@ function styleInject(css, { insertAt } = {}) {
47
47
  }
48
48
 
49
49
  // src/styles/variables.css
50
- styleInject(":root {\n --canvas-react-color-primary: #1677ff;\n --canvas-react-color-primary-hover: #4096ff;\n --canvas-react-color-border: #d9d9d9;\n --canvas-react-color-border-strong: #bfbfbf;\n --canvas-react-color-text: #1f2937;\n --canvas-react-color-text-muted: #6b7280;\n --canvas-react-color-bg: #ffffff;\n --canvas-react-color-bg-soft: #f5f5f5;\n --canvas-react-color-bg-hover: #f3f4f6;\n --canvas-react-color-bg-active: #e6f4ff;\n --canvas-react-shadow-focus: 0 0 0 2px rgba(22, 119, 255, 0.12);\n --canvas-react-shadow-popup: 0 8px 24px rgba(15, 23, 42, 0.16);\n --canvas-react-radius-sm: 6px;\n --canvas-react-radius-md: 8px;\n --canvas-react-control-height: 32px;\n --canvas-react-font-size: 14px;\n --canvas-react-control-padding-inline: 11px;\n --canvas-react-control-padding-block: 0px;\n --canvas-react-content-zoom: 1;\n}\n");
50
+ styleInject(":root {\n --canvas-react-color-primary: #1677ff;\n --canvas-react-color-primary-hover: #4096ff;\n --canvas-react-color-border: #d9d9d9;\n --canvas-react-color-border-strong: #bfbfbf;\n --canvas-react-color-text: #1f2937;\n --canvas-react-color-text-muted: #6b7280;\n --canvas-react-color-bg: #ffffff;\n --canvas-react-color-bg-soft: #f5f5f5;\n --canvas-react-color-bg-hover: #f3f4f6;\n --canvas-react-color-bg-active: #e6f4ff;\n --canvas-react-shadow-focus: 0 0 0 2px rgba(22, 119, 255, 0.12);\n --canvas-react-shadow-popup: 0 8px 24px rgba(15, 23, 42, 0.16);\n --canvas-react-radius-sm: 6px;\n --canvas-react-radius-md: 8px;\n --canvas-react-control-height: 32px;\n --canvas-react-font-size: 14px;\n --canvas-react-control-padding-inline: 11px;\n --canvas-react-control-padding-block: 0px;\n --canvas-react-content-zoom: 1;\n}\n*,\n*::before,\n*::after {\n scrollbar-width: thin;\n scrollbar-color: #aeb4bd transparent;\n}\n*::-webkit-scrollbar {\n width: 8px;\n height: 8px;\n}\n*::-webkit-scrollbar-track {\n background: transparent;\n}\n*::-webkit-scrollbar-thumb {\n min-height: 32px;\n border: 2px solid transparent;\n border-radius: 999px;\n background: #aeb4bd;\n background-clip: content-box;\n}\n*::-webkit-scrollbar-thumb:hover {\n background: #8f98a5;\n background-clip: content-box;\n}\n*::-webkit-scrollbar-corner {\n background: transparent;\n}\n");
51
51
 
52
52
  // src/shared/class-names.ts
53
53
  function joinClassNames(...values) {
@@ -1128,16 +1128,31 @@ var operators = [
1128
1128
  ];
1129
1129
  function ReactFilterPanel(props) {
1130
1130
  const { request } = props;
1131
- const [draft, setDraft] = React.useState(request?.value ?? null);
1131
+ const [draft, setDraft] = React.useState(() => createDraft(request?.value));
1132
1132
  const [tab, setTab] = React.useState(resolveTab(request?.value));
1133
1133
  const [options, setOptions] = React.useState(request?.options ?? []);
1134
1134
  const [loading, setLoading] = React.useState(Boolean(request?.loadOptions));
1135
+ const conditionListRef = React.useRef(null);
1136
+ const [conditionListOverflowing, setConditionListOverflowing] = React.useState(false);
1135
1137
  React.useEffect(() => {
1136
- setDraft(request?.value ?? null);
1138
+ setDraft(createDraft(request?.value));
1137
1139
  setTab(resolveTab(request?.value));
1138
1140
  setOptions(request?.options ?? []);
1139
1141
  setLoading(Boolean(request?.loadOptions));
1140
1142
  }, [request]);
1143
+ React.useLayoutEffect(() => {
1144
+ const element = conditionListRef.current;
1145
+ if (!element || tab !== "condition") {
1146
+ setConditionListOverflowing(false);
1147
+ return;
1148
+ }
1149
+ const measure = () => setConditionListOverflowing(element.scrollHeight > element.clientHeight + 1);
1150
+ measure();
1151
+ if (typeof ResizeObserver === "undefined") return;
1152
+ const observer = new ResizeObserver(measure);
1153
+ observer.observe(element);
1154
+ return () => observer.disconnect();
1155
+ }, [draft?.conditions, tab]);
1141
1156
  React.useEffect(() => {
1142
1157
  if (!request?.loadOptions) return;
1143
1158
  const controller = new AbortController();
@@ -1172,6 +1187,20 @@ function ReactFilterPanel(props) {
1172
1187
  const allChecked = visibleKeys.length > 0 && selectedCount === visibleKeys.length;
1173
1188
  const allCount = request.options.find((item) => item.kind === "all")?.count ?? visibleOptions.filter((item) => item.kind === "value").reduce((sum, item) => sum + item.count, 0);
1174
1189
  const update = (patch) => setDraft((current) => ({ ...current ?? request.value, ...patch }));
1190
+ const updateConditions = (conditions) => {
1191
+ const first = conditions[0] ?? createEmptyCondition();
1192
+ const second = conditions[1] ?? createEmptyCondition();
1193
+ update({
1194
+ conditions,
1195
+ filterType: "condition",
1196
+ conditionOperator: first.operator,
1197
+ conditionValue: first.value ?? "",
1198
+ conditionSecondValue: first.secondValue ?? "",
1199
+ secondConditionOperator: second.operator,
1200
+ secondConditionValue: second.value ?? "",
1201
+ secondConditionSecondValue: second.secondValue ?? ""
1202
+ });
1203
+ };
1175
1204
  const toggle = (keys, checked) => {
1176
1205
  const next = new Set(draft.selectedKeys ?? []);
1177
1206
  keys.forEach((key) => checked ? next.add(key) : next.delete(key));
@@ -1278,97 +1307,138 @@ function ReactFilterPanel(props) {
1278
1307
  )
1279
1308
  }
1280
1309
  ) })
1281
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: 12, display: "grid", gap: 12, minHeight: 290, alignContent: "start", flex: "1 1 auto" }, children: [
1282
- /* @__PURE__ */ jsxRuntime.jsx(
1283
- ConditionEditor,
1284
- {
1285
- label: request.texts.firstConditionLabel,
1286
- operator: draft.conditionOperator ?? "none",
1287
- value: draft.conditionValue ?? "",
1288
- secondValue: draft.conditionSecondValue ?? "",
1289
- texts: request.texts,
1290
- onChange: (patch) => update(patch),
1291
- onSubmit: apply
1292
- }
1293
- ),
1294
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1295
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: fieldLabelStyle, children: request.texts.relationLabel }),
1296
- /* @__PURE__ */ jsxRuntime.jsx(
1297
- ReactSelect,
1298
- {
1299
- value: draft.conditionRelation === "or" ? "or" : "and",
1300
- allowClear: false,
1301
- options: [{ label: request.texts.relationAndLabel, value: "and" }, { label: request.texts.relationOrLabel, value: "or" }],
1302
- onChange: (value) => update({ conditionRelation: value, filterType: "condition" }),
1303
- style: { width: "100%" }
1304
- }
1305
- )
1306
- ] }),
1307
- /* @__PURE__ */ jsxRuntime.jsx(
1308
- ConditionEditor,
1310
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 12, display: "flex", flexDirection: "column", gap: 10, minHeight: 0, flex: "1 1 auto" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1311
+ "div",
1312
+ {
1313
+ ref: conditionListRef,
1314
+ className: "react-filter-panel-condition-list",
1315
+ style: { ...conditionListStyle, overflowY: conditionListOverflowing ? "auto" : "hidden" },
1316
+ children: (draft.conditions ?? []).map((condition, index, conditions) => /* @__PURE__ */ jsxRuntime.jsxs(React.Fragment, { children: [
1317
+ index > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "react-filter-panel-condition-relation", style: conditionRowStyle, children: [
1318
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: inlineLabelStyle, children: request.texts.relationLabel }),
1319
+ /* @__PURE__ */ jsxRuntime.jsx(
1320
+ ReactSelect,
1321
+ {
1322
+ value: draft.conditionRelation === "or" ? "or" : "and",
1323
+ allowClear: false,
1324
+ options: [{ label: request.texts.relationAndLabel, value: "and" }, { label: request.texts.relationOrLabel, value: "or" }],
1325
+ onChange: (value) => update({ conditionRelation: value, filterType: "condition" }),
1326
+ style: { width: "100%" }
1327
+ }
1328
+ ),
1329
+ /* @__PURE__ */ jsxRuntime.jsx("span", {})
1330
+ ] }) : null,
1331
+ /* @__PURE__ */ jsxRuntime.jsx(
1332
+ ConditionEditor,
1333
+ {
1334
+ label: resolveConditionLabel(request.texts, index),
1335
+ condition,
1336
+ texts: request.texts,
1337
+ canDelete: conditions.length > 1,
1338
+ onDelete: () => updateConditions(conditions.filter((_item, itemIndex) => itemIndex !== index)),
1339
+ onChange: (nextCondition) => updateConditions(conditions.map((item, itemIndex) => itemIndex === index ? nextCondition : item)),
1340
+ onSubmit: apply
1341
+ }
1342
+ )
1343
+ ] }, index))
1344
+ }
1345
+ ) }),
1346
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "react-filter-panel-footer", style: footerStyle, children: [
1347
+ tab === "condition" ? /* @__PURE__ */ jsxRuntime.jsxs(
1348
+ "button",
1309
1349
  {
1310
- second: true,
1311
- label: request.texts.secondConditionLabel,
1312
- operator: draft.secondConditionOperator ?? "none",
1313
- value: draft.secondConditionValue ?? "",
1314
- secondValue: draft.secondConditionSecondValue ?? "",
1315
- texts: request.texts,
1316
- onChange: (patch) => update(patch),
1317
- onSubmit: apply
1350
+ type: "button",
1351
+ style: addConditionStyle,
1352
+ onClick: () => updateConditions([...draft.conditions ?? [], createEmptyCondition()]),
1353
+ children: [
1354
+ "+ ",
1355
+ request.texts.addConditionAction ?? "\u65B0\u589E\u6761\u4EF6"
1356
+ ]
1318
1357
  }
1319
- )
1320
- ] }),
1321
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
1322
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: actionStyle(false), onClick: () => {
1323
- request.onReset();
1324
- request.onClose();
1325
- }, children: request.texts.resetAction }),
1326
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: actionStyle(true), onClick: apply, children: request.texts.applyAction })
1358
+ ) : null,
1359
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "react-filter-panel-footer-actions", style: footerActionsStyle, children: [
1360
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: actionStyle(false), onClick: () => {
1361
+ request.onReset();
1362
+ request.onClose();
1363
+ }, children: request.texts.resetAction }),
1364
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", style: actionStyle(true), onClick: apply, children: request.texts.applyAction })
1365
+ ] })
1327
1366
  ] })
1328
1367
  ] })
1329
1368
  }
1330
1369
  );
1331
1370
  }
1332
1371
  function ConditionEditor(props) {
1333
- const prefix = props.second ? "secondCondition" : "condition";
1334
- const hidesValue = ["none", "blank", "notBlank"].includes(props.operator);
1335
- const needsSecond = ["between", "notBetween"].includes(props.operator);
1336
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1337
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: fieldLabelStyle, children: props.label }),
1338
- /* @__PURE__ */ jsxRuntime.jsx(
1339
- ReactSelect,
1340
- {
1341
- value: props.operator,
1342
- options: operators,
1343
- allowClear: false,
1344
- onChange: (value) => props.onChange({ [`${prefix}Operator`]: value, filterType: "condition" }),
1345
- style: { width: "100%" }
1346
- }
1347
- ),
1348
- hidesValue ? null : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "grid", gap: 8, marginTop: 8 }, children: [
1372
+ const hidesValue = ["none", "blank", "notBlank"].includes(props.condition.operator);
1373
+ const needsSecond = ["between", "notBetween"].includes(props.condition.operator);
1374
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: conditionEditorStyle, children: [
1375
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "react-filter-panel-condition-row", style: conditionRowStyle, children: [
1376
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: inlineLabelStyle, children: props.label }),
1377
+ /* @__PURE__ */ jsxRuntime.jsx(
1378
+ ReactSelect,
1379
+ {
1380
+ value: props.condition.operator,
1381
+ options: operators,
1382
+ allowClear: false,
1383
+ onChange: (value) => props.onChange({ ...props.condition, operator: value }),
1384
+ style: { width: "100%" }
1385
+ }
1386
+ ),
1387
+ props.canDelete ? /* @__PURE__ */ jsxRuntime.jsx(
1388
+ "button",
1389
+ {
1390
+ type: "button",
1391
+ title: `${props.texts.deleteConditionAction ?? "\u5220\u9664\u6761\u4EF6"} ${props.label}`,
1392
+ "aria-label": `${props.texts.deleteConditionAction ?? "\u5220\u9664\u6761\u4EF6"} ${props.label}`,
1393
+ style: deleteConditionStyle,
1394
+ onClick: props.onDelete,
1395
+ children: "\xD7"
1396
+ }
1397
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", {})
1398
+ ] }),
1399
+ hidesValue ? null : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: conditionValueStyle, children: [
1349
1400
  /* @__PURE__ */ jsxRuntime.jsx(
1350
1401
  ReactInput,
1351
1402
  {
1352
- value: props.value,
1403
+ value: props.condition.value ?? "",
1353
1404
  placeholder: props.texts.firstValuePlaceholder,
1354
1405
  onPressEnter: props.onSubmit,
1355
- onChange: (event) => props.onChange({ [`${prefix}Value`]: event.target.value, filterType: "condition" }),
1406
+ onChange: (event) => props.onChange({ ...props.condition, value: event.target.value }),
1356
1407
  style: { width: "100%" }
1357
1408
  }
1358
1409
  ),
1359
1410
  needsSecond ? /* @__PURE__ */ jsxRuntime.jsx(
1360
1411
  ReactInput,
1361
1412
  {
1362
- value: props.secondValue,
1413
+ value: props.condition.secondValue ?? "",
1363
1414
  placeholder: props.texts.secondValuePlaceholder,
1364
1415
  onPressEnter: props.onSubmit,
1365
- onChange: (event) => props.onChange({ [`${prefix}SecondValue`]: event.target.value, filterType: "condition" }),
1416
+ onChange: (event) => props.onChange({ ...props.condition, secondValue: event.target.value }),
1366
1417
  style: { width: "100%" }
1367
1418
  }
1368
1419
  ) : null
1369
1420
  ] })
1370
1421
  ] });
1371
1422
  }
1423
+ function createDraft(value) {
1424
+ if (!value) return null;
1425
+ return { ...value, conditions: resolveDraftConditions(value) };
1426
+ }
1427
+ function resolveDraftConditions(value) {
1428
+ if (value.conditions?.length) return value.conditions.map((condition) => ({ ...condition }));
1429
+ return [
1430
+ { operator: value.conditionOperator ?? "none", value: value.conditionValue ?? "", secondValue: value.conditionSecondValue ?? "" },
1431
+ { operator: value.secondConditionOperator ?? "none", value: value.secondConditionValue ?? "", secondValue: value.secondConditionSecondValue ?? "" }
1432
+ ];
1433
+ }
1434
+ function createEmptyCondition() {
1435
+ return { operator: "none", value: "", secondValue: "" };
1436
+ }
1437
+ function resolveConditionLabel(texts, index) {
1438
+ if (index === 0) return texts.firstConditionLabel;
1439
+ if (index === 1) return texts.secondConditionLabel;
1440
+ return `${texts.conditionLabel ?? "\u6761\u4EF6"} ${index + 1}`;
1441
+ }
1372
1442
  function resolveTab(value) {
1373
1443
  return value?.filterType === "condition" || value?.conditionOperator && value.conditionOperator !== "none" ? "condition" : "value";
1374
1444
  }
@@ -1380,7 +1450,15 @@ function optionLabel(item, texts) {
1380
1450
  var checkLabelStyle = { display: "inline-flex", alignItems: "center", gap: 8, color: "#374151", fontSize: 14 };
1381
1451
  var optionStyle = { display: "flex", alignItems: "center", gap: 8, minHeight: 40, padding: "4px 8px", borderRadius: 6, color: "#374151", fontSize: 14, cursor: "pointer", boxSizing: "border-box" };
1382
1452
  var optionTextStyle = { display: "block", flex: "1 1 0", width: 0, minWidth: 0, overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis" };
1383
- var fieldLabelStyle = { marginBottom: 6, fontSize: 12, color: "#6b7280" };
1453
+ var conditionListStyle = { display: "grid", gap: 8, minHeight: 0, flex: "1 1 auto", alignContent: "start", paddingRight: 3 };
1454
+ var conditionEditorStyle = { display: "grid", gap: 8 };
1455
+ var conditionRowStyle = { display: "grid", gridTemplateColumns: "56px minmax(0, 1fr) 22px", alignItems: "center", gap: 8 };
1456
+ var inlineLabelStyle = { color: "#6b7280", fontSize: 12, whiteSpace: "nowrap" };
1457
+ var conditionValueStyle = { display: "grid", gap: 8, marginLeft: 64, marginRight: 30 };
1458
+ var addConditionStyle = { height: 32, padding: "0 10px", border: "1px solid #91caff", borderRadius: 6, background: "#f0f7ff", color: "#1677ff", cursor: "pointer", whiteSpace: "nowrap" };
1459
+ var deleteConditionStyle = { width: 22, height: 22, padding: 0, border: 0, borderRadius: 4, background: "transparent", color: "#9ca3af", fontSize: 18, lineHeight: "20px", cursor: "pointer" };
1460
+ var footerStyle = { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8 };
1461
+ var footerActionsStyle = { display: "flex", gap: 8, marginLeft: "auto" };
1384
1462
  function tabStyle(active) {
1385
1463
  return { flex: 1, height: 32, border: active ? "1px solid #1677ff" : "1px solid #d9d9d9", borderRadius: 6, background: active ? "#e6f4ff" : "#fff", color: active ? "#1677ff" : "#374151", cursor: "pointer" };
1386
1464
  }
@@ -5273,7 +5351,7 @@ function useCompatibleId(prefix = "canvas-react-id") {
5273
5351
  }
5274
5352
 
5275
5353
  // src/components/modal/style.css
5276
- styleInject('@import "../../styles/variables.css";\n.canvas-react-modal-root,\n.canvas-react-modal-root * {\n box-sizing: border-box;\n}\n.canvas-react-modal-root {\n position: fixed;\n inset: 0;\n color: var(--canvas-react-color-text);\n font-size: var(--canvas-react-font-size);\n line-height: 1.5;\n}\n.canvas-react-modal-mask {\n position: absolute;\n inset: 0;\n background: rgba(0, 0, 0, 0.45);\n}\n.canvas-react-modal-wrap {\n position: absolute;\n inset: 0;\n overflow: auto;\n padding: 100px 24px 24px;\n pointer-events: none;\n}\n.canvas-react-modal-root-centered .canvas-react-modal-wrap {\n display: flex;\n align-items: center;\n padding-top: 24px;\n}\n.canvas-react-modal-root-fullscreen .canvas-react-modal-wrap {\n padding: 0;\n overflow: hidden;\n}\n.canvas-react-modal {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 520px;\n max-width: calc(100vw - 48px);\n max-height: calc(100vh - 124px);\n margin: 0 auto;\n overflow: hidden;\n border-radius: var(--canvas-react-radius-md, 8px);\n background: var(--canvas-react-color-bg, #ffffff);\n box-shadow: 0 12px 40px rgba(15, 23, 42, 0.22);\n outline: none;\n pointer-events: auto;\n}\n.canvas-react-modal-root-centered .canvas-react-modal {\n max-height: calc(100vh - 48px);\n}\n.canvas-react-modal.canvas-react-modal-fullscreen {\n width: 100% !important;\n max-width: none;\n height: 100%;\n max-height: none;\n border-radius: 0;\n}\n.canvas-react-modal-header {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n min-height: 56px;\n padding: 0 16px 0 24px;\n border-bottom: 1px solid var(--canvas-react-color-border);\n}\n.canvas-react-modal-title {\n min-width: 0;\n flex: 1 1 auto;\n color: var(--canvas-react-color-text);\n font-size: 16px;\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n.canvas-react-modal-tools {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: 4px;\n margin-left: 16px;\n}\n.canvas-react-modal-tool {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: 0;\n border-radius: var(--canvas-react-radius-sm, 6px);\n background: transparent;\n color: var(--canvas-react-color-text-muted);\n cursor: pointer;\n transition: background-color 0.18s ease, color 0.18s ease;\n}\n.canvas-react-modal-tool:hover {\n background: var(--canvas-react-color-bg-hover);\n color: var(--canvas-react-color-text);\n}\n.canvas-react-modal-tool:focus-visible,\n.canvas-react-modal-button:focus-visible {\n outline: 2px solid var(--canvas-react-color-primary);\n outline-offset: 2px;\n}\n.canvas-react-modal-fullscreen-icon {\n position: relative;\n display: block;\n width: 15px;\n height: 15px;\n border: 1.5px solid currentColor;\n}\n.canvas-react-modal-fullscreen-icon-exit::before {\n position: absolute;\n inset: 3px -4px -4px 3px;\n border-right: 1.5px solid currentColor;\n border-bottom: 1.5px solid currentColor;\n content: "";\n}\n.canvas-react-modal-close-icon {\n position: relative;\n display: block;\n width: 16px;\n height: 16px;\n}\n.canvas-react-modal-close-icon::before,\n.canvas-react-modal-close-icon::after {\n position: absolute;\n top: 7px;\n left: 1px;\n width: 14px;\n height: 1.5px;\n border-radius: 1px;\n background: currentColor;\n content: "";\n}\n.canvas-react-modal-close-icon::before {\n transform: rotate(45deg);\n}\n.canvas-react-modal-close-icon::after {\n transform: rotate(-45deg);\n}\n.canvas-react-modal-body {\n min-height: 0;\n flex: 1 1 auto;\n overflow: auto;\n padding: 20px 24px;\n}\n.canvas-react-modal-footer {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 24px;\n border-top: 1px solid var(--canvas-react-color-border);\n}\n.canvas-react-modal-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: var(--canvas-react-control-height, 32px);\n min-width: 64px;\n padding: 0 var(--canvas-react-control-padding-inline, 11px);\n border: 1px solid var(--canvas-react-color-border);\n border-radius: var(--canvas-react-radius-sm, 6px);\n background: var(--canvas-react-color-bg);\n color: var(--canvas-react-color-text);\n font: inherit;\n line-height: 1;\n white-space: nowrap;\n cursor: pointer;\n transition:\n border-color 0.18s ease,\n background-color 0.18s ease,\n color 0.18s ease,\n opacity 0.18s ease;\n}\n.canvas-react-modal-button:hover {\n border-color: var(--canvas-react-color-primary-hover);\n color: var(--canvas-react-color-primary-hover);\n}\n.canvas-react-modal-button-primary {\n border-color: var(--canvas-react-color-primary);\n background: var(--canvas-react-color-primary);\n color: #ffffff;\n}\n.canvas-react-modal-button-primary:hover {\n border-color: var(--canvas-react-color-primary-hover);\n background: var(--canvas-react-color-primary-hover);\n color: #ffffff;\n}\n.canvas-react-modal-button:disabled {\n opacity: 0.56;\n cursor: not-allowed;\n}\n.canvas-react-modal-loading {\n width: 14px;\n height: 14px;\n border: 2px solid rgba(255, 255, 255, 0.45);\n border-top-color: #ffffff;\n border-radius: 50%;\n animation: canvas-react-modal-loading 0.8s linear infinite;\n}\n.canvas-react-modal-motion-enter-active,\n.canvas-react-modal-motion-leave-active {\n transition: opacity 0.2s ease;\n}\n.canvas-react-modal-motion-enter-active .canvas-react-modal,\n.canvas-react-modal-motion-leave-active .canvas-react-modal {\n transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);\n}\n.canvas-react-modal-motion-enter-from,\n.canvas-react-modal-motion-leave-to {\n opacity: 0;\n}\n.canvas-react-modal-motion-enter-from .canvas-react-modal,\n.canvas-react-modal-motion-leave-to .canvas-react-modal {\n opacity: 0;\n transform: scale(0.96) translateY(-8px);\n}\n@keyframes canvas-react-modal-loading {\n to {\n transform: rotate(360deg);\n }\n}\n@media (max-width: 575px) {\n .canvas-react-modal-wrap {\n padding: 24px 12px;\n }\n .canvas-react-modal {\n max-width: calc(100vw - 24px);\n max-height: calc(100vh - 48px);\n }\n .canvas-react-modal-header {\n padding-right: 12px;\n padding-left: 16px;\n }\n .canvas-react-modal-body {\n padding: 16px;\n }\n .canvas-react-modal-footer {\n padding: 12px 16px;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .canvas-react-modal-motion-enter-active,\n .canvas-react-modal-motion-leave-active,\n .canvas-react-modal-motion-enter-active .canvas-react-modal,\n .canvas-react-modal-motion-leave-active .canvas-react-modal {\n transition-duration: 0.01ms;\n }\n}\n');
5354
+ styleInject('@import "../../styles/variables.css";\n.canvas-react-modal-root,\n.canvas-react-modal-root * {\n box-sizing: border-box;\n}\n.canvas-react-modal-root {\n position: fixed;\n inset: 0;\n color: var(--canvas-react-color-text);\n font-size: var(--canvas-react-font-size);\n line-height: 1.5;\n}\n.canvas-react-modal-root-passthrough {\n pointer-events: none;\n}\n.canvas-react-modal-root-passthrough .canvas-react-modal {\n pointer-events: auto;\n}\n.canvas-react-modal-mask {\n position: absolute;\n inset: 0;\n background: rgba(0, 0, 0, 0.45);\n}\n.canvas-react-modal-wrap {\n position: absolute;\n inset: 0;\n overflow: auto;\n padding: 100px 24px 24px;\n pointer-events: none;\n}\n.canvas-react-modal-root-centered .canvas-react-modal-wrap {\n display: flex;\n align-items: center;\n padding-top: 24px;\n}\n.canvas-react-modal-root-fullscreen .canvas-react-modal-wrap {\n padding: 0;\n overflow: hidden;\n}\n.canvas-react-modal {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 520px;\n max-width: calc(100vw - 48px);\n max-height: calc(100vh - 124px);\n margin: 0 auto;\n overflow: hidden;\n border-radius: var(--canvas-react-radius-md, 8px);\n background: var(--canvas-react-color-bg, #ffffff);\n box-shadow: 0 12px 40px rgba(15, 23, 42, 0.22);\n outline: none;\n pointer-events: auto;\n}\n.canvas-react-modal-root-centered .canvas-react-modal {\n max-height: calc(100vh - 48px);\n}\n.canvas-react-modal.canvas-react-modal-fullscreen {\n width: 100% !important;\n max-width: none;\n height: 100%;\n max-height: none;\n border-radius: 0;\n}\n.canvas-react-modal-header {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n min-height: 56px;\n padding: 0 16px 0 24px;\n border-bottom: 1px solid var(--canvas-react-color-border);\n}\n.canvas-react-modal-header-draggable {\n cursor: move;\n user-select: none;\n}\n.canvas-react-modal-title {\n min-width: 0;\n flex: 1 1 auto;\n color: var(--canvas-react-color-text);\n font-size: 16px;\n font-weight: 600;\n overflow-wrap: anywhere;\n}\n.canvas-react-modal-tools {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: 4px;\n margin-left: 16px;\n}\n.canvas-react-modal-tool {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n border: 0;\n border-radius: var(--canvas-react-radius-sm, 6px);\n background: transparent;\n color: var(--canvas-react-color-text-muted);\n cursor: pointer;\n transition: background-color 0.18s ease, color 0.18s ease;\n}\n.canvas-react-modal-tool:hover {\n background: var(--canvas-react-color-bg-hover);\n color: var(--canvas-react-color-text);\n}\n.canvas-react-modal-tool:focus-visible,\n.canvas-react-modal-button:focus-visible {\n outline: 2px solid var(--canvas-react-color-primary);\n outline-offset: 2px;\n}\n.canvas-react-modal-fullscreen-icon {\n position: relative;\n display: block;\n width: 15px;\n height: 15px;\n border: 1.5px solid currentColor;\n}\n.canvas-react-modal-fullscreen-icon-exit::before {\n position: absolute;\n inset: 3px -4px -4px 3px;\n border-right: 1.5px solid currentColor;\n border-bottom: 1.5px solid currentColor;\n content: "";\n}\n.canvas-react-modal-close-icon {\n position: relative;\n display: block;\n width: 16px;\n height: 16px;\n}\n.canvas-react-modal-close-icon::before,\n.canvas-react-modal-close-icon::after {\n position: absolute;\n top: 7px;\n left: 1px;\n width: 14px;\n height: 1.5px;\n border-radius: 1px;\n background: currentColor;\n content: "";\n}\n.canvas-react-modal-close-icon::before {\n transform: rotate(45deg);\n}\n.canvas-react-modal-close-icon::after {\n transform: rotate(-45deg);\n}\n.canvas-react-modal-body {\n min-height: 0;\n flex: 1 1 auto;\n overflow: auto;\n padding: 20px 24px;\n}\n.canvas-react-modal-footer {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 24px;\n border-top: 1px solid var(--canvas-react-color-border);\n}\n.canvas-react-modal-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: var(--canvas-react-control-height, 32px);\n min-width: 64px;\n padding: 0 var(--canvas-react-control-padding-inline, 11px);\n border: 1px solid var(--canvas-react-color-border);\n border-radius: var(--canvas-react-radius-sm, 6px);\n background: var(--canvas-react-color-bg);\n color: var(--canvas-react-color-text);\n font: inherit;\n line-height: 1;\n white-space: nowrap;\n cursor: pointer;\n transition:\n border-color 0.18s ease,\n background-color 0.18s ease,\n color 0.18s ease,\n opacity 0.18s ease;\n}\n.canvas-react-modal-button:hover {\n border-color: var(--canvas-react-color-primary-hover);\n color: var(--canvas-react-color-primary-hover);\n}\n.canvas-react-modal-button-primary {\n border-color: var(--canvas-react-color-primary);\n background: var(--canvas-react-color-primary);\n color: #ffffff;\n}\n.canvas-react-modal-button-primary:hover {\n border-color: var(--canvas-react-color-primary-hover);\n background: var(--canvas-react-color-primary-hover);\n color: #ffffff;\n}\n.canvas-react-modal-button:disabled {\n opacity: 0.56;\n cursor: not-allowed;\n}\n.canvas-react-modal-loading {\n width: 14px;\n height: 14px;\n border: 2px solid rgba(255, 255, 255, 0.45);\n border-top-color: #ffffff;\n border-radius: 50%;\n animation: canvas-react-modal-loading 0.8s linear infinite;\n}\n.canvas-react-modal-motion-enter-active,\n.canvas-react-modal-motion-leave-active {\n transition: opacity 0.2s ease;\n}\n.canvas-react-modal-motion-enter-active .canvas-react-modal,\n.canvas-react-modal-motion-leave-active .canvas-react-modal {\n transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);\n}\n.canvas-react-modal-motion-enter-from,\n.canvas-react-modal-motion-leave-to {\n opacity: 0;\n}\n.canvas-react-modal-motion-enter-from .canvas-react-modal,\n.canvas-react-modal-motion-leave-to .canvas-react-modal {\n opacity: 0;\n transform: scale(0.96) translateY(-8px);\n}\n@keyframes canvas-react-modal-loading {\n to {\n transform: rotate(360deg);\n }\n}\n@media (max-width: 575px) {\n .canvas-react-modal-wrap {\n padding: 24px 12px;\n }\n .canvas-react-modal {\n max-width: calc(100vw - 24px);\n max-height: calc(100vh - 48px);\n }\n .canvas-react-modal-header {\n padding-right: 12px;\n padding-left: 16px;\n }\n .canvas-react-modal-body {\n padding: 16px;\n }\n .canvas-react-modal-footer {\n padding: 12px 16px;\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .canvas-react-modal-motion-enter-active,\n .canvas-react-modal-motion-leave-active,\n .canvas-react-modal-motion-enter-active .canvas-react-modal,\n .canvas-react-modal-motion-leave-active .canvas-react-modal {\n transition-duration: 0.01ms;\n }\n}\n');
5277
5355
  var MODAL_MOTION_DURATION = 200;
5278
5356
  var FOCUSABLE_SELECTOR = [
5279
5357
  "a[href]",
@@ -5297,6 +5375,7 @@ function ReactModal(props) {
5297
5375
  closable = true,
5298
5376
  confirmLoading,
5299
5377
  defaultFullscreen = false,
5378
+ draggable = false,
5300
5379
  focusTriggerAfterClose = true,
5301
5380
  footer,
5302
5381
  fullscreen,
@@ -5325,7 +5404,9 @@ function ReactModal(props) {
5325
5404
  });
5326
5405
  const [innerFullscreen, setInnerFullscreen] = React.useState(defaultFullscreen);
5327
5406
  const [innerConfirmLoading, setInnerConfirmLoading] = React.useState(false);
5407
+ const [dragOffset, setDragOffset] = React.useState({ x: 0, y: 0 });
5328
5408
  const panelRef = React.useRef(null);
5409
+ const dragRef = React.useRef(null);
5329
5410
  const restoreFocusRef = React.useRef(null);
5330
5411
  const wasRenderedRef = React.useRef(false);
5331
5412
  const titleId = useCompatibleId(`${REACT_COMPONENT_PREFIX}-modal-title`);
@@ -5333,6 +5414,32 @@ function ReactModal(props) {
5333
5414
  const mergedFullscreen = controlledFullscreen ? Boolean(fullscreen) : innerFullscreen;
5334
5415
  const mergedConfirmLoading = confirmLoading ?? innerConfirmLoading;
5335
5416
  const hasTitle = title !== null && title !== void 0 && title !== false;
5417
+ React.useEffect(() => {
5418
+ if (!draggable || !transition.rendered) return;
5419
+ const handleMouseMove = (event) => {
5420
+ const drag = dragRef.current;
5421
+ if (!drag) return;
5422
+ setDragOffset({
5423
+ x: drag.offsetX + event.clientX - drag.startX,
5424
+ y: drag.offsetY + event.clientY - drag.startY
5425
+ });
5426
+ };
5427
+ const handleMouseUp = () => {
5428
+ dragRef.current = null;
5429
+ };
5430
+ window.addEventListener("mousemove", handleMouseMove);
5431
+ window.addEventListener("mouseup", handleMouseUp);
5432
+ return () => {
5433
+ window.removeEventListener("mousemove", handleMouseMove);
5434
+ window.removeEventListener("mouseup", handleMouseUp);
5435
+ };
5436
+ }, [draggable, transition.rendered]);
5437
+ React.useEffect(() => {
5438
+ if (!open) {
5439
+ dragRef.current = null;
5440
+ setDragOffset({ x: 0, y: 0 });
5441
+ }
5442
+ }, [open]);
5336
5443
  React.useEffect(() => {
5337
5444
  if (!transition.rendered) {
5338
5445
  if (wasRenderedRef.current) {
@@ -5349,11 +5456,13 @@ function ReactModal(props) {
5349
5456
  wasRenderedRef.current = true;
5350
5457
  restoreFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
5351
5458
  }
5352
- lockBodyScroll();
5353
- return unlockBodyScroll;
5354
- }, [afterClose, focusTriggerAfterClose, transition.rendered]);
5459
+ if (mask) {
5460
+ lockBodyScroll();
5461
+ return unlockBodyScroll;
5462
+ }
5463
+ }, [afterClose, focusTriggerAfterClose, mask, transition.rendered]);
5355
5464
  React.useEffect(() => {
5356
- if (!open || !transition.rendered) {
5465
+ if (!mask || !open || !transition.rendered) {
5357
5466
  return;
5358
5467
  }
5359
5468
  const frameId = window.requestAnimationFrame(() => {
@@ -5362,9 +5471,9 @@ function ReactModal(props) {
5362
5471
  return () => {
5363
5472
  window.cancelAnimationFrame(frameId);
5364
5473
  };
5365
- }, [open, transition.rendered]);
5474
+ }, [mask, open, transition.rendered]);
5366
5475
  React.useEffect(() => {
5367
- if (!transition.rendered) {
5476
+ if (!mask || !transition.rendered) {
5368
5477
  return;
5369
5478
  }
5370
5479
  const handleKeyDown = (event) => {
@@ -5382,7 +5491,7 @@ function ReactModal(props) {
5382
5491
  return () => {
5383
5492
  document.removeEventListener("keydown", handleKeyDown);
5384
5493
  };
5385
- }, [keyboard, onCancel, open, transition.rendered]);
5494
+ }, [keyboard, mask, onCancel, open, transition.rendered]);
5386
5495
  const setFullscreen = (nextFullscreen) => {
5387
5496
  if (!controlledFullscreen) {
5388
5497
  setInnerFullscreen(nextFullscreen);
@@ -5467,6 +5576,7 @@ function ReactModal(props) {
5467
5576
  {
5468
5577
  className: joinClassNames(
5469
5578
  `${REACT_COMPONENT_PREFIX}-modal-root`,
5579
+ !mask && `${REACT_COMPONENT_PREFIX}-modal-root-passthrough`,
5470
5580
  centered && `${REACT_COMPONENT_PREFIX}-modal-root-centered`,
5471
5581
  mergedFullscreen && `${REACT_COMPONENT_PREFIX}-modal-root-fullscreen`,
5472
5582
  transition.className,
@@ -5496,63 +5606,95 @@ function ReactModal(props) {
5496
5606
  mergedFullscreen && `${REACT_COMPONENT_PREFIX}-modal-fullscreen`,
5497
5607
  className
5498
5608
  ),
5499
- style: { width, ...style },
5609
+ style: {
5610
+ width,
5611
+ ...style,
5612
+ ...draggable && !mergedFullscreen ? {
5613
+ position: "relative",
5614
+ left: dragOffset.x,
5615
+ top: dragOffset.y
5616
+ } : void 0
5617
+ },
5500
5618
  role: "dialog",
5501
- "aria-modal": "true",
5619
+ "aria-modal": mask ? "true" : void 0,
5502
5620
  "aria-label": hasTitle ? void 0 : "\u5BF9\u8BDD\u6846",
5503
5621
  "aria-labelledby": hasTitle ? titleId : void 0,
5504
5622
  tabIndex: -1,
5505
5623
  children: [
5506
- hasTitle || closable || fullscreenable ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${REACT_COMPONENT_PREFIX}-modal-header`, children: [
5507
- /* @__PURE__ */ jsxRuntime.jsx(
5508
- "div",
5509
- {
5510
- id: hasTitle ? titleId : void 0,
5511
- className: `${REACT_COMPONENT_PREFIX}-modal-title`,
5512
- children: title
5513
- }
5514
- ),
5515
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${REACT_COMPONENT_PREFIX}-modal-tools`, children: [
5516
- fullscreenable ? /* @__PURE__ */ jsxRuntime.jsx(
5517
- "button",
5518
- {
5519
- type: "button",
5520
- className: `${REACT_COMPONENT_PREFIX}-modal-tool`,
5521
- title: mergedFullscreen ? "\u9000\u51FA\u5168\u5C4F" : "\u5168\u5C4F",
5522
- "aria-label": mergedFullscreen ? "\u9000\u51FA\u5168\u5C4F" : "\u5168\u5C4F",
5523
- "aria-pressed": mergedFullscreen,
5524
- onClick: () => setFullscreen(!mergedFullscreen),
5525
- children: /* @__PURE__ */ jsxRuntime.jsx(
5526
- "span",
5624
+ hasTitle || closable || fullscreenable ? /* @__PURE__ */ jsxRuntime.jsxs(
5625
+ "div",
5626
+ {
5627
+ className: joinClassNames(
5628
+ `${REACT_COMPONENT_PREFIX}-modal-header`,
5629
+ draggable && !mergedFullscreen ? `${REACT_COMPONENT_PREFIX}-modal-header-draggable` : void 0
5630
+ ),
5631
+ onMouseDown: (event) => {
5632
+ if (!draggable || mergedFullscreen || event.button !== 0) {
5633
+ return;
5634
+ }
5635
+ if (event.target.closest("button")) {
5636
+ return;
5637
+ }
5638
+ dragRef.current = {
5639
+ startX: event.clientX,
5640
+ startY: event.clientY,
5641
+ offsetX: dragOffset.x,
5642
+ offsetY: dragOffset.y
5643
+ };
5644
+ event.preventDefault();
5645
+ },
5646
+ children: [
5647
+ /* @__PURE__ */ jsxRuntime.jsx(
5648
+ "div",
5649
+ {
5650
+ id: hasTitle ? titleId : void 0,
5651
+ className: `${REACT_COMPONENT_PREFIX}-modal-title`,
5652
+ children: title
5653
+ }
5654
+ ),
5655
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${REACT_COMPONENT_PREFIX}-modal-tools`, children: [
5656
+ fullscreenable ? /* @__PURE__ */ jsxRuntime.jsx(
5657
+ "button",
5527
5658
  {
5528
- className: joinClassNames(
5529
- `${REACT_COMPONENT_PREFIX}-modal-fullscreen-icon`,
5530
- mergedFullscreen && `${REACT_COMPONENT_PREFIX}-modal-fullscreen-icon-exit`
5531
- ),
5532
- "aria-hidden": "true"
5659
+ type: "button",
5660
+ className: `${REACT_COMPONENT_PREFIX}-modal-tool`,
5661
+ title: mergedFullscreen ? "\u9000\u51FA\u5168\u5C4F" : "\u5168\u5C4F",
5662
+ "aria-label": mergedFullscreen ? "\u9000\u51FA\u5168\u5C4F" : "\u5168\u5C4F",
5663
+ "aria-pressed": mergedFullscreen,
5664
+ onClick: () => setFullscreen(!mergedFullscreen),
5665
+ children: /* @__PURE__ */ jsxRuntime.jsx(
5666
+ "span",
5667
+ {
5668
+ className: joinClassNames(
5669
+ `${REACT_COMPONENT_PREFIX}-modal-fullscreen-icon`,
5670
+ mergedFullscreen && `${REACT_COMPONENT_PREFIX}-modal-fullscreen-icon-exit`
5671
+ ),
5672
+ "aria-hidden": "true"
5673
+ }
5674
+ )
5533
5675
  }
5534
- )
5535
- }
5536
- ) : null,
5537
- closable ? /* @__PURE__ */ jsxRuntime.jsx(
5538
- "button",
5539
- {
5540
- type: "button",
5541
- className: `${REACT_COMPONENT_PREFIX}-modal-tool`,
5542
- title: "\u5173\u95ED",
5543
- "aria-label": "\u5173\u95ED",
5544
- onClick: onCancel,
5545
- children: /* @__PURE__ */ jsxRuntime.jsx(
5546
- "span",
5676
+ ) : null,
5677
+ closable ? /* @__PURE__ */ jsxRuntime.jsx(
5678
+ "button",
5547
5679
  {
5548
- className: `${REACT_COMPONENT_PREFIX}-modal-close-icon`,
5549
- "aria-hidden": "true"
5680
+ type: "button",
5681
+ className: `${REACT_COMPONENT_PREFIX}-modal-tool`,
5682
+ title: "\u5173\u95ED",
5683
+ "aria-label": "\u5173\u95ED",
5684
+ onClick: onCancel,
5685
+ children: /* @__PURE__ */ jsxRuntime.jsx(
5686
+ "span",
5687
+ {
5688
+ className: `${REACT_COMPONENT_PREFIX}-modal-close-icon`,
5689
+ "aria-hidden": "true"
5690
+ }
5691
+ )
5550
5692
  }
5551
- )
5552
- }
5553
- ) : null
5554
- ] })
5555
- ] }) : null,
5693
+ ) : null
5694
+ ] })
5695
+ ]
5696
+ }
5697
+ ) : null,
5556
5698
  /* @__PURE__ */ jsxRuntime.jsx(
5557
5699
  "div",
5558
5700
  {