djm-ui 0.67.4 → 0.73.0

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/README.md +38 -2
  3. package/dist/djm-ui.cjs +1625 -803
  4. package/dist/djm-ui.cjs.map +4 -4
  5. package/dist/djm-ui.css +1043 -41
  6. package/dist/djm-ui.esm.js +1581 -761
  7. package/dist/djm-ui.esm.js.map +4 -4
  8. package/dist/djm-ui.esm.min.js +439 -247
  9. package/dist/djm-ui.min.cjs +439 -247
  10. package/dist/djm-ui.min.css +2 -2
  11. package/dist/djm-ui.umd.js +1104 -285
  12. package/dist/djm-ui.umd.min.js +439 -247
  13. package/dist/mcp/manifest.json +12300 -0
  14. package/dist/mcp/server.js +90 -0
  15. package/package.json +12 -4
  16. package/src/components/drawer/index.js +4 -2
  17. package/src/components/icon/index.js +13 -1
  18. package/src/components/modal/index.js +4 -2
  19. package/src/components/progress/index.js +72 -3
  20. package/src/components/rich-editor/index.js +724 -61
  21. package/src/components/spin/index.js +69 -22
  22. package/src/index.js +2 -1
  23. package/src/locale/en-US.js +33 -1
  24. package/src/locale/zh-CN.js +33 -1
  25. package/src/styles/base.css +2 -3
  26. package/src/styles/components/button.css +2 -1
  27. package/src/styles/components/console.css +5 -0
  28. package/src/styles/components/content.css +517 -0
  29. package/src/styles/components/feedback.css +46 -0
  30. package/src/styles/components/form.css +5 -0
  31. package/src/styles/components/glass.css +58 -0
  32. package/src/styles/components/layout.css +326 -0
  33. package/src/styles/components/media-picker.css +3 -3
  34. package/src/styles/components/menu.css +2 -1
  35. package/src/styles/components/org-picker.css +1 -1
  36. package/src/styles/components/responsive.css +86 -0
  37. package/src/styles/components/rich-editor.css +206 -7
  38. package/src/styles/components/skin.css +54 -0
  39. package/src/styles/components/spin.css +156 -4
  40. package/src/styles/components/template.css +5 -0
  41. package/src/styles/index.css +2 -0
  42. package/src/styles/theme-dark.css +5 -0
  43. package/src/styles/tokens.css +13 -0
  44. package/src/theme/index.js +62 -0
  45. package/src/utils/sanitize-html.js +44 -6
  46. package/types/index.d.ts +17 -0
package/dist/djm-ui.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! DJM UI v0.67.4 · MIT · 2026-10-26 */
1
+ /*! DJM UI v0.73.0 · MIT · 2026-10-26 */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1039,6 +1039,7 @@ __export(index_exports, {
1039
1039
  djmMessage: () => djmMessage,
1040
1040
  djmMessages: () => djmMessages,
1041
1041
  getLocale: () => getLocale,
1042
+ glass: () => glass,
1042
1043
  hasPermission: () => hasPermission,
1043
1044
  initTheme: () => initTheme,
1044
1045
  install: () => install,
@@ -1048,6 +1049,7 @@ __export(index_exports, {
1048
1049
  primaryColor: () => primaryColor,
1049
1050
  resetPrimaryColor: () => resetPrimaryColor,
1050
1051
  sanitizeHtml: () => sanitizeHtml,
1052
+ setGlass: () => setGlass,
1051
1053
  setLocale: () => setLocale,
1052
1054
  setPermissions: () => setPermissions,
1053
1055
  setPrimaryColor: () => setPrimaryColor,
@@ -1119,7 +1121,19 @@ var PATHS = {
1119
1121
  activity: "M22 12h-4l-3 9L9 3l-3 9H2",
1120
1122
  database: "M12 8c4.42 0 8-1.34 8-3s-3.58-3-8-3-8 1.34-8 3 3.58 3 8 3zM4 5v14c0 1.66 3.58 3 8 3s8-1.34 8-3V5M4 12c0 1.66 3.58 3 8 3s8-1.34 8-3",
1121
1123
  sun: "M12 17a5 5 0 1 0 0-10 5 5 0 0 0 0 10zM12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42",
1122
- moon: "M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"
1124
+ moon: "M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z",
1125
+ undo: "M3 10h11a5 5 0 1 1 0 10H8M3 10l4-4M3 10l4 4",
1126
+ redo: "M21 10H10a5 5 0 1 0 0 10h6M21 10l-4-4M21 10l-4 4",
1127
+ "align-left": "M4 6h16M4 12h10M4 18h13",
1128
+ "align-center": "M4 6h16M7 12h10M6 18h12",
1129
+ "align-right": "M4 6h16M10 12h10M7 18h13",
1130
+ "align-justify": "M4 6h16M4 12h16M4 18h16",
1131
+ list: "M9 6h11M9 12h11M9 18h11M4.5 6h.01M4.5 12h.01M4.5 18h.01",
1132
+ "list-ordered": "M10 6h10M10 12h10M10 18h10M4 6h1v4M4 12h2M4 16h2v2H4",
1133
+ outdent: "M4 6h16M10 12h10M10 18h10M8 9l-3 3 3 3",
1134
+ indent: "M4 6h16M10 12h10M10 18h10M5 9l3 3-3 3",
1135
+ unlink: "M10 13a5 5 0 0 0 7.5.5M14 11a5 5 0 0 0-7.5-.5M2 2l20 20",
1136
+ images: "M8 3h12v12M4 7h12v12H4zM7 15l3-3 3 3"
1123
1137
  };
1124
1138
  var icon_default = {
1125
1139
  name: "DjmIcon",
@@ -1446,7 +1460,6 @@ var zh_CN_default = {
1446
1460
  "richEditor.italic": "\u659C\u4F53",
1447
1461
  "richEditor.underline": "\u4E0B\u5212\u7EBF",
1448
1462
  "richEditor.strike": "\u5220\u9664\u7EBF",
1449
- "richEditor.heading": "\u4E8C\u7EA7\u6807\u9898",
1450
1463
  "richEditor.paragraph": "\u6B63\u6587",
1451
1464
  "richEditor.bulletList": "\u65E0\u5E8F\u5217\u8868",
1452
1465
  "richEditor.numberList": "\u6709\u5E8F\u5217\u8868",
@@ -1457,6 +1470,39 @@ var zh_CN_default = {
1457
1470
  "richEditor.redo": "\u91CD\u505A",
1458
1471
  "richEditor.source": "\u6E90\u7801",
1459
1472
  "richEditor.visual": "\u53EF\u89C6\u5316",
1473
+ "richEditor.toolbar": "\u7F16\u8F91\u5DE5\u5177\u680F",
1474
+ "richEditor.block": "\u6BB5\u843D\u683C\u5F0F",
1475
+ "richEditor.heading1": "\u6807\u9898 1",
1476
+ "richEditor.heading2": "\u6807\u9898 2",
1477
+ "richEditor.heading3": "\u6807\u9898 3",
1478
+ "richEditor.quote": "\u5F15\u7528",
1479
+ "richEditor.codeBlock": "\u4EE3\u7801\u5757",
1480
+ "richEditor.fontSize": "\u5B57\u53F7",
1481
+ "richEditor.defaultSize": "\u9ED8\u8BA4",
1482
+ "richEditor.inlineCode": "\u884C\u5185\u4EE3\u7801",
1483
+ "richEditor.textColor": "\u6587\u5B57\u989C\u8272",
1484
+ "richEditor.bgColor": "\u80CC\u666F\u8272",
1485
+ "richEditor.alignLeft": "\u5DE6\u5BF9\u9F50",
1486
+ "richEditor.alignCenter": "\u5C45\u4E2D",
1487
+ "richEditor.alignRight": "\u53F3\u5BF9\u9F50",
1488
+ "richEditor.alignJustify": "\u4E24\u7AEF\u5BF9\u9F50",
1489
+ "richEditor.outdent": "\u51CF\u5C11\u7F29\u8FDB",
1490
+ "richEditor.indent": "\u589E\u52A0\u7F29\u8FDB",
1491
+ "richEditor.unlink": "\u53D6\u6D88\u94FE\u63A5",
1492
+ "richEditor.image": "\u63D2\u5165\u56FE\u7247",
1493
+ "richEditor.singleImage": "\u63D2\u5165\u5355\u56FE",
1494
+ "richEditor.multiImage": "\u63D2\u5165\u591A\u56FE",
1495
+ "richEditor.mediaLibrary": "\u4ECE\u7D20\u6750\u5E93\u9009\u62E9",
1496
+ "richEditor.hr": "\u5206\u5272\u7EBF",
1497
+ "richEditor.fullscreen": "\u5168\u5C4F",
1498
+ "richEditor.exitFullscreen": "\u9000\u51FA\u5168\u5C4F",
1499
+ "richEditor.wordCount": "\u5171 {count} \u5B57",
1500
+ "richEditor.uploading": "\u6B63\u5728\u4E0A\u4F20 {count} \u5F20\u56FE\u7247\u2026",
1501
+ "richEditor.uploadFailed": "\u56FE\u7247\u4E0A\u4F20\u5931\u8D25",
1502
+ "richEditor.imageTypeError": "\u53EA\u80FD\u4E0A\u4F20\u56FE\u7247\u6587\u4EF6",
1503
+ "richEditor.imageSizeError": "\u56FE\u7247\u4E0D\u80FD\u8D85\u8FC7 {size}MB",
1504
+ "richEditor.imageUrlInvalid": "\u56FE\u7247\u5730\u5740\u4E0D\u5408\u6CD5\uFF0C\u5DF2\u62D2\u7EDD\u63D2\u5165",
1505
+ "richEditor.linkInvalid": "\u94FE\u63A5\u53EA\u652F\u6301 http(s)\u3001mailto\u3001tel \u6216\u7AD9\u5185\u76F8\u5BF9\u5730\u5740",
1460
1506
  "approval.start": "\u53D1\u8D77",
1461
1507
  "approval.cc": "\u6284\u9001",
1462
1508
  "approval.approved": "\u5DF2\u901A\u8FC7",
@@ -1665,7 +1711,6 @@ var en_US_default = {
1665
1711
  "richEditor.italic": "Italic",
1666
1712
  "richEditor.underline": "Underline",
1667
1713
  "richEditor.strike": "Strikethrough",
1668
- "richEditor.heading": "Heading 2",
1669
1714
  "richEditor.paragraph": "Paragraph",
1670
1715
  "richEditor.bulletList": "Bullet list",
1671
1716
  "richEditor.numberList": "Numbered list",
@@ -1676,6 +1721,39 @@ var en_US_default = {
1676
1721
  "richEditor.redo": "Redo",
1677
1722
  "richEditor.source": "Source",
1678
1723
  "richEditor.visual": "Visual",
1724
+ "richEditor.toolbar": "Formatting toolbar",
1725
+ "richEditor.block": "Paragraph style",
1726
+ "richEditor.heading1": "Heading 1",
1727
+ "richEditor.heading2": "Heading 2",
1728
+ "richEditor.heading3": "Heading 3",
1729
+ "richEditor.quote": "Quote",
1730
+ "richEditor.codeBlock": "Code block",
1731
+ "richEditor.fontSize": "Font size",
1732
+ "richEditor.defaultSize": "Default",
1733
+ "richEditor.inlineCode": "Inline code",
1734
+ "richEditor.textColor": "Text color",
1735
+ "richEditor.bgColor": "Background color",
1736
+ "richEditor.alignLeft": "Align left",
1737
+ "richEditor.alignCenter": "Align center",
1738
+ "richEditor.alignRight": "Align right",
1739
+ "richEditor.alignJustify": "Justify",
1740
+ "richEditor.outdent": "Decrease indent",
1741
+ "richEditor.indent": "Increase indent",
1742
+ "richEditor.unlink": "Remove link",
1743
+ "richEditor.image": "Insert image",
1744
+ "richEditor.singleImage": "Insert single image",
1745
+ "richEditor.multiImage": "Insert multiple images",
1746
+ "richEditor.mediaLibrary": "Choose from media library",
1747
+ "richEditor.hr": "Divider",
1748
+ "richEditor.fullscreen": "Fullscreen",
1749
+ "richEditor.exitFullscreen": "Exit fullscreen",
1750
+ "richEditor.wordCount": "{count} characters",
1751
+ "richEditor.uploading": "Uploading {count} image(s)\u2026",
1752
+ "richEditor.uploadFailed": "Image upload failed",
1753
+ "richEditor.imageTypeError": "Only image files are allowed",
1754
+ "richEditor.imageSizeError": "Image must be smaller than {size}MB",
1755
+ "richEditor.imageUrlInvalid": "Invalid image URL, insertion rejected",
1756
+ "richEditor.linkInvalid": "Only http(s), mailto, tel or relative URLs are allowed",
1679
1757
  "approval.start": "Started",
1680
1758
  "approval.cc": "CC",
1681
1759
  "approval.approved": "Approved",
@@ -1796,7 +1874,7 @@ function t(key, params) {
1796
1874
  // src/utils/panel.js
1797
1875
  var PANEL_HIDDEN_STYLE = { position: "fixed", left: "0px", top: "0px", visibility: "hidden" };
1798
1876
  function bindPanelListeners({ root, panel, onClose, onReposition, esc = true }) {
1799
- const el = (ref50) => typeof ref50 === "function" ? ref50() : ref50;
1877
+ const el = (ref51) => typeof ref51 === "function" ? ref51() : ref51;
1800
1878
  function onDocumentMousedown(event) {
1801
1879
  const rootEl = el(root);
1802
1880
  const panelEl = el(panel);
@@ -4169,12 +4247,18 @@ var progress_default = {
4169
4247
  name: "DjmProgress",
4170
4248
  props: {
4171
4249
  percent: { type: Number, default: 0 },
4250
+ // line 横向 / circle 环形
4251
+ type: { type: String, default: "line" },
4172
4252
  // '' / success / error / warning
4173
4253
  status: { type: String, default: "" },
4174
4254
  showText: { type: Boolean, default: true },
4175
4255
  strokeWidth: { type: Number, default: 6 },
4176
4256
  // 自定义进度色,不传由状态决定
4177
- color: { type: String, default: "" }
4257
+ color: { type: String, default: "" },
4258
+ // 环形直径(px)
4259
+ size: { type: Number, default: 96 },
4260
+ // 无障碍名称,默认「进度」
4261
+ label: { type: String, default: "" }
4178
4262
  },
4179
4263
  computed: {
4180
4264
  safePercent() {
@@ -4187,10 +4271,72 @@ var progress_default = {
4187
4271
  },
4188
4272
  trackStyle() {
4189
4273
  return { height: this.strokeWidth + "px" };
4274
+ },
4275
+ circleSize() {
4276
+ return Math.max(48, Number(this.size) || 96);
4277
+ },
4278
+ circleRadius() {
4279
+ return (this.circleSize - this.strokeWidth) / 2;
4280
+ },
4281
+ circleLength() {
4282
+ return 2 * Math.PI * this.circleRadius;
4283
+ },
4284
+ circleOffset() {
4285
+ return this.circleLength * (1 - this.safePercent / 100);
4286
+ },
4287
+ circleStyle() {
4288
+ return { width: this.circleSize + "px", height: this.circleSize + "px" };
4289
+ },
4290
+ circleLabelStyle() {
4291
+ return { fontSize: Math.max(12, Math.round(this.circleSize / 5)) + "px" };
4190
4292
  }
4191
4293
  },
4192
4294
  template: `
4193
- <div class="djm-progress-line" :class="status ? 'djm-is-' + status : ''">
4295
+ <div
4296
+ v-if="type === 'circle'"
4297
+ class="djm-progress-circle"
4298
+ :class="status ? 'djm-is-' + status : ''"
4299
+ :style="circleStyle"
4300
+ role="progressbar"
4301
+ :aria-label="label || '\u8FDB\u5EA6'"
4302
+ :aria-valuenow="safePercent"
4303
+ aria-valuemin="0"
4304
+ aria-valuemax="100"
4305
+ >
4306
+ <svg :viewBox="'0 0 ' + circleSize + ' ' + circleSize" aria-hidden="true">
4307
+ <circle
4308
+ class="djm-progress-circle-track"
4309
+ :cx="circleSize / 2"
4310
+ :cy="circleSize / 2"
4311
+ :r="circleRadius"
4312
+ :stroke-width="strokeWidth"
4313
+ fill="none"
4314
+ />
4315
+ <circle
4316
+ class="djm-progress-circle-bar"
4317
+ :cx="circleSize / 2"
4318
+ :cy="circleSize / 2"
4319
+ :r="circleRadius"
4320
+ :stroke-width="strokeWidth"
4321
+ fill="none"
4322
+ stroke-linecap="round"
4323
+ :stroke-dasharray="circleLength"
4324
+ :stroke-dashoffset="circleOffset"
4325
+ :style="color ? { stroke: color } : null"
4326
+ />
4327
+ </svg>
4328
+ <span v-if="showText" class="djm-progress-circle-label" :style="circleLabelStyle">{{ safePercent }}%</span>
4329
+ </div>
4330
+ <div
4331
+ v-else
4332
+ class="djm-progress-line"
4333
+ :class="status ? 'djm-is-' + status : ''"
4334
+ role="progressbar"
4335
+ :aria-label="label || '\u8FDB\u5EA6'"
4336
+ :aria-valuenow="safePercent"
4337
+ aria-valuemin="0"
4338
+ aria-valuemax="100"
4339
+ >
4194
4340
  <div class="djm-progress" :style="trackStyle">
4195
4341
  <div class="djm-progress-bar" :style="barStyle"></div>
4196
4342
  </div>
@@ -5392,48 +5538,91 @@ var alert_default = {
5392
5538
  };
5393
5539
 
5394
5540
  // src/components/spin/index.js
5541
+ var import_vue7 = require("vue");
5395
5542
  var spin_default = {
5396
5543
  name: "DjmSpin",
5397
5544
  props: {
5398
5545
  spinning: { type: Boolean, default: true },
5399
- size: { type: String, default: "md" },
5400
5546
  // sm | md | lg
5401
- tip: { type: String, default: "" }
5547
+ size: { type: String, default: "md" },
5548
+ // ring 环形 / dots 点状 / bars 柱状 / pulse 脉冲
5549
+ type: { type: String, default: "ring" },
5550
+ tip: { type: String, default: "" },
5551
+ // 延迟多少毫秒后显示,0 表示立即
5552
+ delay: { type: Number, default: 0 },
5553
+ // 全屏加载:遮罩铺满视口
5554
+ fullscreen: { type: Boolean, default: false },
5555
+ // 自定义指示器颜色,默认跟随品牌色
5556
+ color: { type: String, default: "" }
5557
+ },
5558
+ setup(props) {
5559
+ const visible = (0, import_vue7.ref)(false);
5560
+ let timer = null;
5561
+ function sync() {
5562
+ window.clearTimeout(timer);
5563
+ timer = null;
5564
+ if (!props.spinning) {
5565
+ visible.value = false;
5566
+ return;
5567
+ }
5568
+ if (props.delay > 0) {
5569
+ timer = window.setTimeout(() => {
5570
+ visible.value = true;
5571
+ }, props.delay);
5572
+ } else {
5573
+ visible.value = true;
5574
+ }
5575
+ }
5576
+ (0, import_vue7.watch)(() => [props.spinning, props.delay], sync, { immediate: true });
5577
+ (0, import_vue7.onBeforeUnmount)(() => window.clearTimeout(timer));
5578
+ return { visible };
5402
5579
  },
5403
5580
  computed: {
5404
- // 有默认插槽即为包裹模式
5405
5581
  wrapped() {
5406
5582
  return !!this.$slots.default;
5583
+ },
5584
+ rootClass() {
5585
+ return [
5586
+ "djm-spin",
5587
+ "djm-spin-" + this.size,
5588
+ {
5589
+ "djm-spin-wrap": this.wrapped && !this.fullscreen,
5590
+ "djm-spin-inline": !this.wrapped && !this.fullscreen,
5591
+ "djm-spin-fullscreen": this.fullscreen
5592
+ }
5593
+ ];
5407
5594
  }
5408
5595
  },
5409
5596
  template: `
5410
5597
  <div
5411
- v-if="wrapped"
5412
- class="djm-spin-wrap"
5413
- :class="'djm-spin-' + size"
5414
- :aria-busy="String(spinning)"
5598
+ v-if="fullscreen || wrapped || visible"
5599
+ :class="rootClass"
5600
+ :aria-busy="String(visible)"
5601
+ :role="visible ? 'status' : undefined"
5602
+ :aria-label="!wrapped && !fullscreen && !tip && visible ? '\u52A0\u8F7D\u4E2D' : undefined"
5415
5603
  >
5416
- <slot />
5417
- <div v-if="spinning" class="djm-spin-mask" role="status">
5418
- <span class="djm-spinner"></span>
5604
+ <slot v-if="wrapped && !fullscreen" />
5605
+ <div v-if="visible" class="djm-spin-mask">
5606
+ <span class="djm-spin-indicator" :class="'djm-spin-' + type" :style="color ? { color } : null">
5607
+ <slot name="indicator">
5608
+ <i v-if="type === 'ring'" class="djm-spinner"></i>
5609
+ <template v-else-if="type === 'dots'">
5610
+ <i></i><i></i><i></i>
5611
+ </template>
5612
+ <template v-else-if="type === 'bars'">
5613
+ <i></i><i></i><i></i><i></i>
5614
+ </template>
5615
+ <i v-else class="djm-spin-core"></i>
5616
+ </slot>
5617
+ </span>
5419
5618
  <span v-if="tip" class="djm-spin-tip">{{ tip }}</span>
5420
5619
  </div>
5421
5620
  </div>
5422
- <span
5423
- v-else
5424
- class="djm-spin-inline"
5425
- :class="'djm-spin-' + size"
5426
- role="status"
5427
- :aria-label="tip ? undefined : '\u52A0\u8F7D\u4E2D'"
5428
- >
5429
- <span class="djm-spinner"></span>
5430
- <span v-if="tip" class="djm-spin-tip">{{ tip }}</span>
5431
- </span>
5432
5621
  `
5433
5622
  };
5434
5623
 
5435
5624
  // src/components/popconfirm/index.js
5436
- var import_vue7 = require("vue");
5625
+ var import_vue8 = require("vue");
5437
5626
  var popconfirm_default = {
5438
5627
  name: "DjmPopconfirm",
5439
5628
  components: { DjmIcon: icon_default },
@@ -5449,10 +5638,10 @@ var popconfirm_default = {
5449
5638
  },
5450
5639
  emits: ["confirm", "cancel", "visible-change"],
5451
5640
  setup(props, { emit }) {
5452
- const open = (0, import_vue7.ref)(false);
5453
- const root = (0, import_vue7.ref)(null);
5454
- const panelEl = (0, import_vue7.ref)(null);
5455
- const panelStyle = (0, import_vue7.ref)({});
5641
+ const open = (0, import_vue8.ref)(false);
5642
+ const root = (0, import_vue8.ref)(null);
5643
+ const panelEl = (0, import_vue8.ref)(null);
5644
+ const panelStyle = (0, import_vue8.ref)({});
5456
5645
  const PANEL_WIDTH = 244;
5457
5646
  let detachPanel = null;
5458
5647
  function syncTriggerA11y() {
@@ -5467,8 +5656,8 @@ var popconfirm_default = {
5467
5656
  target.setAttribute("aria-haspopup", "dialog");
5468
5657
  target.setAttribute("aria-expanded", String(open.value));
5469
5658
  }
5470
- (0, import_vue7.onMounted)(() => (0, import_vue7.nextTick)(syncTriggerA11y));
5471
- (0, import_vue7.watch)(open, () => (0, import_vue7.nextTick)(syncTriggerA11y));
5659
+ (0, import_vue8.onMounted)(() => (0, import_vue8.nextTick)(syncTriggerA11y));
5660
+ (0, import_vue8.watch)(open, () => (0, import_vue8.nextTick)(syncTriggerA11y));
5472
5661
  function updatePosition() {
5473
5662
  if (!open.value || !root.value) return;
5474
5663
  const rect = root.value.getBoundingClientRect();
@@ -5491,7 +5680,7 @@ var popconfirm_default = {
5491
5680
  onReposition: updatePosition
5492
5681
  });
5493
5682
  requestAnimationFrame(updatePosition);
5494
- (0, import_vue7.nextTick)(() => {
5683
+ (0, import_vue8.nextTick)(() => {
5495
5684
  const first = panelEl.value && panelEl.value.querySelector("button");
5496
5685
  if (first) first.focus();
5497
5686
  });
@@ -5507,7 +5696,7 @@ var popconfirm_default = {
5507
5696
  detachPanel = null;
5508
5697
  }
5509
5698
  if (hadFocus) {
5510
- (0, import_vue7.nextTick)(() => {
5699
+ (0, import_vue8.nextTick)(() => {
5511
5700
  const wrapper = root.value && root.value.querySelector(".djm-popconfirm-trigger");
5512
5701
  const target = wrapper && (wrapper.querySelector('button, a[href], [role="button"]') || wrapper);
5513
5702
  if (target) target.focus();
@@ -5527,7 +5716,7 @@ var popconfirm_default = {
5527
5716
  emit("cancel");
5528
5717
  close2();
5529
5718
  }
5530
- (0, import_vue7.onBeforeUnmount)(close2);
5719
+ (0, import_vue8.onBeforeUnmount)(close2);
5531
5720
  return { open, root, panelEl, panelStyle, toggle, close: close2, confirm, cancel };
5532
5721
  },
5533
5722
  template: `
@@ -5571,7 +5760,7 @@ var popconfirm_default = {
5571
5760
  };
5572
5761
 
5573
5762
  // src/components/anchor/index.js
5574
- var import_vue8 = require("vue");
5763
+ var import_vue9 = require("vue");
5575
5764
  var anchor_default = {
5576
5765
  name: "DjmAnchor",
5577
5766
  props: {
@@ -5584,8 +5773,8 @@ var anchor_default = {
5584
5773
  },
5585
5774
  emits: ["change"],
5586
5775
  setup(props, { emit }) {
5587
- const root = (0, import_vue8.ref)(null);
5588
- const activeKey = (0, import_vue8.ref)("");
5776
+ const root = (0, import_vue9.ref)(null);
5777
+ const activeKey = (0, import_vue9.ref)("");
5589
5778
  let scrollEl = null;
5590
5779
  let target = null;
5591
5780
  function resolveContainer() {
@@ -5639,9 +5828,9 @@ var anchor_default = {
5639
5828
  activeKey.value = item.href;
5640
5829
  emit("change", item.href);
5641
5830
  }
5642
- (0, import_vue8.onMounted)(bind);
5643
- (0, import_vue8.watch)(() => props.container, bind);
5644
- (0, import_vue8.onBeforeUnmount)(unbind);
5831
+ (0, import_vue9.onMounted)(bind);
5832
+ (0, import_vue9.watch)(() => props.container, bind);
5833
+ (0, import_vue9.onBeforeUnmount)(unbind);
5645
5834
  return { root, activeKey, go };
5646
5835
  },
5647
5836
  template: `
@@ -5663,7 +5852,7 @@ var anchor_default = {
5663
5852
  };
5664
5853
 
5665
5854
  // src/components/backtop/index.js
5666
- var import_vue9 = require("vue");
5855
+ var import_vue10 = require("vue");
5667
5856
  var backtop_default = {
5668
5857
  name: "DjmBacktop",
5669
5858
  components: { DjmIcon: icon_default },
@@ -5676,8 +5865,8 @@ var backtop_default = {
5676
5865
  },
5677
5866
  emits: ["click"],
5678
5867
  setup(props, { emit }) {
5679
- const visible = (0, import_vue9.ref)(false);
5680
- const root = (0, import_vue9.ref)(null);
5868
+ const visible = (0, import_vue10.ref)(false);
5869
+ const root = (0, import_vue10.ref)(null);
5681
5870
  let target = null;
5682
5871
  let scrollEl = null;
5683
5872
  function resolveContainer() {
@@ -5710,8 +5899,8 @@ var backtop_default = {
5710
5899
  else target.scrollTo({ top: 0, behavior });
5711
5900
  emit("click");
5712
5901
  }
5713
- (0, import_vue9.onMounted)(bind);
5714
- (0, import_vue9.onBeforeUnmount)(unbind);
5902
+ (0, import_vue10.onMounted)(bind);
5903
+ (0, import_vue10.onBeforeUnmount)(unbind);
5715
5904
  return { visible, root, toTop };
5716
5905
  },
5717
5906
  template: `
@@ -5788,7 +5977,7 @@ var space_default = {
5788
5977
  };
5789
5978
 
5790
5979
  // src/components/affix/index.js
5791
- var import_vue10 = require("vue");
5980
+ var import_vue11 = require("vue");
5792
5981
  var affix_default = {
5793
5982
  name: "DjmAffix",
5794
5983
  props: {
@@ -5799,10 +5988,10 @@ var affix_default = {
5799
5988
  zIndex: { type: Number, default: 900 }
5800
5989
  },
5801
5990
  setup(props) {
5802
- const root = (0, import_vue10.ref)(null);
5803
- const fixed = (0, import_vue10.ref)(false);
5804
- const affixStyle = (0, import_vue10.ref)({});
5805
- const holderStyle = (0, import_vue10.ref)({});
5991
+ const root = (0, import_vue11.ref)(null);
5992
+ const fixed = (0, import_vue11.ref)(false);
5993
+ const affixStyle = (0, import_vue11.ref)({});
5994
+ const holderStyle = (0, import_vue11.ref)({});
5806
5995
  let target = null;
5807
5996
  let scrollEl = null;
5808
5997
  function resolveContainer() {
@@ -5857,8 +6046,8 @@ var affix_default = {
5857
6046
  scrollEl = null;
5858
6047
  target = null;
5859
6048
  }
5860
- (0, import_vue10.onMounted)(bind);
5861
- (0, import_vue10.onBeforeUnmount)(unbind);
6049
+ (0, import_vue11.onMounted)(bind);
6050
+ (0, import_vue11.onBeforeUnmount)(unbind);
5862
6051
  return { root, fixed, affixStyle, holderStyle };
5863
6052
  },
5864
6053
  template: `
@@ -5909,7 +6098,7 @@ var segmented_default = {
5909
6098
  };
5910
6099
 
5911
6100
  // src/components/image/index.js
5912
- var import_vue11 = require("vue");
6101
+ var import_vue12 = require("vue");
5913
6102
 
5914
6103
  // src/utils/scroll-lock.js
5915
6104
  var count = 0;
@@ -5956,11 +6145,11 @@ var image_default = {
5956
6145
  preview: { type: Boolean, default: true }
5957
6146
  },
5958
6147
  setup(props) {
5959
- const failed = (0, import_vue11.ref)(false);
5960
- const open = (0, import_vue11.ref)(false);
5961
- const zoomRef = (0, import_vue11.ref)(null);
5962
- const closeRef = (0, import_vue11.ref)(null);
5963
- (0, import_vue11.watch)(() => props.src, () => {
6148
+ const failed = (0, import_vue12.ref)(false);
6149
+ const open = (0, import_vue12.ref)(false);
6150
+ const zoomRef = (0, import_vue12.ref)(null);
6151
+ const closeRef = (0, import_vue12.ref)(null);
6152
+ (0, import_vue12.watch)(() => props.src, () => {
5964
6153
  failed.value = false;
5965
6154
  });
5966
6155
  function toSize(value) {
@@ -5974,7 +6163,7 @@ var image_default = {
5974
6163
  open.value = true;
5975
6164
  lockScroll();
5976
6165
  document.addEventListener("keydown", onKeydown);
5977
- await (0, import_vue11.nextTick)();
6166
+ await (0, import_vue12.nextTick)();
5978
6167
  if (closeRef.value) closeRef.value.focus();
5979
6168
  }
5980
6169
  function closePreview() {
@@ -5984,7 +6173,7 @@ var image_default = {
5984
6173
  document.removeEventListener("keydown", onKeydown);
5985
6174
  if (zoomRef.value) zoomRef.value.focus();
5986
6175
  }
5987
- (0, import_vue11.onBeforeUnmount)(closePreview);
6176
+ (0, import_vue12.onBeforeUnmount)(closePreview);
5988
6177
  return { failed, open, zoomRef, closeRef, toSize, openPreview, closePreview, t };
5989
6178
  },
5990
6179
  template: `
@@ -6039,13 +6228,15 @@ var image_default = {
6039
6228
  };
6040
6229
 
6041
6230
  // src/components/watermark/index.js
6042
- var import_vue13 = require("vue");
6231
+ var import_vue14 = require("vue");
6043
6232
 
6044
6233
  // src/theme/index.js
6045
- var import_vue12 = require("vue");
6234
+ var import_vue13 = require("vue");
6046
6235
  var KEY = "djm-theme";
6047
6236
  var COLOR_KEY = "djm-primary";
6048
- var theme = (0, import_vue12.ref)("light");
6237
+ var GLASS_KEY = "djm-glass";
6238
+ var theme = (0, import_vue13.ref)("light");
6239
+ var glass = (0, import_vue13.ref)(false);
6049
6240
  var PRESET_COLORS = [
6050
6241
  { name: "\u9ED8\u8BA4\u84DD", value: "#1a6fc4" },
6051
6242
  { name: "\u79D1\u6280\u84DD", value: "#2563eb" },
@@ -6056,7 +6247,7 @@ var PRESET_COLORS = [
6056
6247
  { name: "\u6731\u7802\u7EA2", value: "#c0392b" },
6057
6248
  { name: "\u77F3\u58A8\u7070", value: "#4b5b6b" }
6058
6249
  ];
6059
- var primaryColor = (0, import_vue12.ref)("");
6250
+ var primaryColor = (0, import_vue13.ref)("");
6060
6251
  var BRAND_VARS = [
6061
6252
  "--djm-brand-50",
6062
6253
  "--djm-brand-100",
@@ -6178,6 +6369,15 @@ function setTheme(name) {
6178
6369
  function toggleTheme() {
6179
6370
  setTheme(theme.value === "dark" ? "light" : "dark");
6180
6371
  }
6372
+ function setGlass(enabled) {
6373
+ glass.value = !!enabled;
6374
+ document.documentElement.dataset.djmGlass = glass.value ? "on" : "";
6375
+ try {
6376
+ if (glass.value) localStorage.setItem(GLASS_KEY, "1");
6377
+ else localStorage.removeItem(GLASS_KEY);
6378
+ } catch (error) {
6379
+ }
6380
+ }
6181
6381
  function initTheme() {
6182
6382
  let saved = "";
6183
6383
  try {
@@ -6197,9 +6397,16 @@ function initTheme() {
6197
6397
  } catch (error) {
6198
6398
  color = "";
6199
6399
  }
6400
+ let glassSaved = false;
6401
+ try {
6402
+ glassSaved = localStorage.getItem(GLASS_KEY) === "1";
6403
+ } catch (error) {
6404
+ glassSaved = false;
6405
+ }
6200
6406
  if (color) primaryColor.value = color;
6201
6407
  const next = param === "dark" || param === "light" ? param : saved || "light";
6202
6408
  setTheme(next);
6409
+ setGlass(glassSaved);
6203
6410
  }
6204
6411
 
6205
6412
  // src/components/watermark/index.js
@@ -6215,7 +6422,7 @@ var watermark_default = {
6215
6422
  zIndex: { type: Number, default: 10 }
6216
6423
  },
6217
6424
  setup(props) {
6218
- const dataUrl = (0, import_vue13.ref)("");
6425
+ const dataUrl = (0, import_vue14.ref)("");
6219
6426
  let canvasEl = null;
6220
6427
  function build() {
6221
6428
  const lines = (Array.isArray(props.content) ? props.content : [props.content]).filter(Boolean);
@@ -6252,13 +6459,13 @@ var watermark_default = {
6252
6459
  });
6253
6460
  dataUrl.value = canvasEl.toDataURL("image/png");
6254
6461
  }
6255
- const layerStyle = (0, import_vue13.computed)(() => ({
6462
+ const layerStyle = (0, import_vue14.computed)(() => ({
6256
6463
  backgroundImage: dataUrl.value ? "url(" + dataUrl.value + ")" : "none",
6257
6464
  zIndex: props.zIndex
6258
6465
  }));
6259
- (0, import_vue13.onMounted)(build);
6260
- (0, import_vue13.watch)(() => [props.content, props.gap, props.fontSize, props.color, props.rotate, theme.value], build, { deep: true });
6261
- (0, import_vue13.onBeforeUnmount)(() => {
6466
+ (0, import_vue14.onMounted)(build);
6467
+ (0, import_vue14.watch)(() => [props.content, props.gap, props.fontSize, props.color, props.rotate, theme.value], build, { deep: true });
6468
+ (0, import_vue14.onBeforeUnmount)(() => {
6262
6469
  canvasEl = null;
6263
6470
  });
6264
6471
  return { layerStyle };
@@ -6448,7 +6655,7 @@ var autocomplete_default = {
6448
6655
  };
6449
6656
 
6450
6657
  // src/components/splitter/index.js
6451
- var import_vue14 = require("vue");
6658
+ var import_vue15 = require("vue");
6452
6659
  var splitter_default = {
6453
6660
  name: "DjmSplitter",
6454
6661
  props: {
@@ -6461,9 +6668,9 @@ var splitter_default = {
6461
6668
  },
6462
6669
  emits: ["update:modelValue", "change"],
6463
6670
  setup(props, { emit }) {
6464
- const root = (0, import_vue14.ref)(null);
6465
- const dragging = (0, import_vue14.ref)(false);
6466
- const ratio = (0, import_vue14.computed)(() => {
6671
+ const root = (0, import_vue15.ref)(null);
6672
+ const dragging = (0, import_vue15.ref)(false);
6673
+ const ratio = (0, import_vue15.computed)(() => {
6467
6674
  const value = Number(props.modelValue);
6468
6675
  const safe = Number.isFinite(value) ? value : 50;
6469
6676
  return Math.min(props.max, Math.max(props.min, safe));
@@ -6507,7 +6714,7 @@ var splitter_default = {
6507
6714
  commit(ratio.value + step);
6508
6715
  }
6509
6716
  }
6510
- (0, import_vue14.onBeforeUnmount)(stopDrag);
6717
+ (0, import_vue15.onBeforeUnmount)(stopDrag);
6511
6718
  return { root, dragging, ratio, startDrag, onKeydown };
6512
6719
  },
6513
6720
  template: `
@@ -6544,7 +6751,7 @@ var splitter_default = {
6544
6751
  };
6545
6752
 
6546
6753
  // src/components/carousel/index.js
6547
- var import_vue15 = require("vue");
6754
+ var import_vue16 = require("vue");
6548
6755
  var carousel_default = {
6549
6756
  name: "DjmCarousel",
6550
6757
  components: { DjmIcon: icon_default },
@@ -6558,7 +6765,7 @@ var carousel_default = {
6558
6765
  },
6559
6766
  emits: ["change"],
6560
6767
  setup(props, { emit }) {
6561
- const index = (0, import_vue15.ref)(0);
6768
+ const index = (0, import_vue16.ref)(0);
6562
6769
  let timer = null;
6563
6770
  const boxStyle = () => ({
6564
6771
  height: typeof props.height === "number" ? props.height + "px" : props.height
@@ -6595,15 +6802,15 @@ var carousel_default = {
6595
6802
  next();
6596
6803
  }
6597
6804
  }
6598
- (0, import_vue15.onMounted)(start);
6599
- (0, import_vue15.watch)(() => [props.autoplay, props.interval, props.items.length], start);
6805
+ (0, import_vue16.onMounted)(start);
6806
+ (0, import_vue16.watch)(() => [props.autoplay, props.interval, props.items.length], start);
6600
6807
  function pause() {
6601
6808
  if (props.autoplay) stop();
6602
6809
  }
6603
6810
  function resume() {
6604
6811
  if (props.autoplay) start();
6605
6812
  }
6606
- (0, import_vue15.onBeforeUnmount)(stop);
6813
+ (0, import_vue16.onBeforeUnmount)(stop);
6607
6814
  return { index, boxStyle, go, next, prev, onKeydown, pause, resume };
6608
6815
  },
6609
6816
  template: `
@@ -6663,7 +6870,7 @@ var carousel_default = {
6663
6870
  };
6664
6871
 
6665
6872
  // src/components/tour/index.js
6666
- var import_vue16 = require("vue");
6873
+ var import_vue17 = require("vue");
6667
6874
  var tour_default = {
6668
6875
  name: "DjmTour",
6669
6876
  components: { DjmIcon: icon_default },
@@ -6675,11 +6882,11 @@ var tour_default = {
6675
6882
  },
6676
6883
  emits: ["update:modelValue", "change", "finish"],
6677
6884
  setup(props, { emit }) {
6678
- const current = (0, import_vue16.ref)(0);
6679
- const highlight = (0, import_vue16.ref)({ top: "0px", left: "0px", width: "0px", height: "0px" });
6680
- const cardStyle = (0, import_vue16.ref)({ position: "fixed", left: "0px", top: "0px", visibility: "hidden" });
6681
- const card = (0, import_vue16.ref)(null);
6682
- const step = (0, import_vue16.computed)(() => props.steps[current.value] || null);
6885
+ const current = (0, import_vue17.ref)(0);
6886
+ const highlight = (0, import_vue17.ref)({ top: "0px", left: "0px", width: "0px", height: "0px" });
6887
+ const cardStyle = (0, import_vue17.ref)({ position: "fixed", left: "0px", top: "0px", visibility: "hidden" });
6888
+ const card = (0, import_vue17.ref)(null);
6889
+ const step = (0, import_vue17.computed)(() => props.steps[current.value] || null);
6683
6890
  function update() {
6684
6891
  const scene = step.value;
6685
6892
  if (!scene) return;
@@ -6709,7 +6916,7 @@ var tour_default = {
6709
6916
  document.addEventListener("keydown", onKeydown);
6710
6917
  window.addEventListener("resize", update);
6711
6918
  window.addEventListener("scroll", update, true);
6712
- (0, import_vue16.nextTick)(() => {
6919
+ (0, import_vue17.nextTick)(() => {
6713
6920
  update();
6714
6921
  if (card.value) card.value.focus({ preventScroll: true });
6715
6922
  });
@@ -6731,22 +6938,22 @@ var tour_default = {
6731
6938
  }
6732
6939
  current.value += 1;
6733
6940
  emit("change", current.value);
6734
- (0, import_vue16.nextTick)(update);
6941
+ (0, import_vue17.nextTick)(update);
6735
6942
  }
6736
6943
  function prev() {
6737
6944
  if (current.value === 0) return;
6738
6945
  current.value -= 1;
6739
6946
  emit("change", current.value);
6740
- (0, import_vue16.nextTick)(update);
6947
+ (0, import_vue17.nextTick)(update);
6741
6948
  }
6742
- (0, import_vue16.watch)(() => props.modelValue, (value) => {
6949
+ (0, import_vue17.watch)(() => props.modelValue, (value) => {
6743
6950
  if (value) startScene();
6744
6951
  else stopScene();
6745
6952
  });
6746
- (0, import_vue16.onMounted)(() => {
6953
+ (0, import_vue17.onMounted)(() => {
6747
6954
  if (props.modelValue) startScene();
6748
6955
  });
6749
- (0, import_vue16.onBeforeUnmount)(stopScene);
6956
+ (0, import_vue17.onBeforeUnmount)(stopScene);
6750
6957
  return { current, step, highlight, cardStyle, card, close: close2, next, prev, t };
6751
6958
  },
6752
6959
  template: `
@@ -6784,7 +6991,7 @@ var tour_default = {
6784
6991
  };
6785
6992
 
6786
6993
  // src/components/calendar/index.js
6787
- var import_vue17 = require("vue");
6994
+ var import_vue18 = require("vue");
6788
6995
  function pad2(num) {
6789
6996
  return String(num).padStart(2, "0");
6790
6997
  }
@@ -6814,16 +7021,16 @@ var calendar_default = {
6814
7021
  const today = /* @__PURE__ */ new Date();
6815
7022
  const todayKey = toKey(today.getFullYear(), today.getMonth(), today.getDate());
6816
7023
  const initial = parse(props.modelValue);
6817
- const viewYear = (0, import_vue17.ref)(initial ? initial.year : today.getFullYear());
6818
- const viewMonth = (0, import_vue17.ref)(initial ? initial.month : today.getMonth());
6819
- const weekNames = (0, import_vue17.computed)(() => {
7024
+ const viewYear = (0, import_vue18.ref)(initial ? initial.year : today.getFullYear());
7025
+ const viewMonth = (0, import_vue18.ref)(initial ? initial.month : today.getMonth());
7026
+ const weekNames = (0, import_vue18.computed)(() => {
6820
7027
  const base = ["\u65E5", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D"];
6821
7028
  return base.slice(props.firstDay).concat(base.slice(0, props.firstDay));
6822
7029
  });
6823
- const markSet = (0, import_vue17.computed)(() => new Set(
7030
+ const markSet = (0, import_vue18.computed)(() => new Set(
6824
7031
  props.marks.map((item) => typeof item === "string" ? item : item.date).filter(Boolean)
6825
7032
  ));
6826
- const cells = (0, import_vue17.computed)(() => {
7033
+ const cells = (0, import_vue18.computed)(() => {
6827
7034
  const first = new Date(viewYear.value, viewMonth.value, 1);
6828
7035
  const offset = (first.getDay() - props.firstDay + 7) % 7;
6829
7036
  const start = new Date(viewYear.value, viewMonth.value, 1 - offset);
@@ -6838,7 +7045,7 @@ var calendar_default = {
6838
7045
  }
6839
7046
  return list;
6840
7047
  });
6841
- const weeks = (0, import_vue17.computed)(() => {
7048
+ const weeks = (0, import_vue18.computed)(() => {
6842
7049
  const list = cells.value;
6843
7050
  return Array.from({ length: 6 }, (_, index) => list.slice(index * 7, index * 7 + 7));
6844
7051
  });
@@ -6881,7 +7088,7 @@ var calendar_default = {
6881
7088
  event.preventDefault();
6882
7089
  list[next].focus();
6883
7090
  }
6884
- (0, import_vue17.watch)(() => props.modelValue, (value) => {
7091
+ (0, import_vue18.watch)(() => props.modelValue, (value) => {
6885
7092
  const parts = parse(value);
6886
7093
  if (parts && (parts.year !== viewYear.value || parts.month !== viewMonth.value)) {
6887
7094
  viewYear.value = parts.year;
@@ -6935,7 +7142,7 @@ var calendar_default = {
6935
7142
  };
6936
7143
 
6937
7144
  // src/components/float-button/index.js
6938
- var import_vue18 = require("vue");
7145
+ var import_vue19 = require("vue");
6939
7146
  var float_button_default = {
6940
7147
  name: "DjmFloatButton",
6941
7148
  components: { DjmIcon: icon_default },
@@ -6951,7 +7158,7 @@ var float_button_default = {
6951
7158
  },
6952
7159
  emits: ["click", "select"],
6953
7160
  setup(props, { emit }) {
6954
- const open = (0, import_vue18.ref)(false);
7161
+ const open = (0, import_vue19.ref)(false);
6955
7162
  function onKeydown(event) {
6956
7163
  if (event.key === "Escape") close2();
6957
7164
  }
@@ -6986,7 +7193,7 @@ var float_button_default = {
6986
7193
  emit("select", item);
6987
7194
  if (typeof item.onClick === "function") item.onClick(item);
6988
7195
  }
6989
- (0, import_vue18.onBeforeUnmount)(close2);
7196
+ (0, import_vue19.onBeforeUnmount)(close2);
6990
7197
  return { open, onMainClick, choose };
6991
7198
  },
6992
7199
  template: `
@@ -7021,7 +7228,7 @@ var float_button_default = {
7021
7228
  };
7022
7229
 
7023
7230
  // src/components/mentions/index.js
7024
- var import_vue19 = require("vue");
7231
+ var import_vue20 = require("vue");
7025
7232
  var uidSeed3 = 0;
7026
7233
  var mentions_default = {
7027
7234
  name: "DjmMentions",
@@ -7036,26 +7243,26 @@ var mentions_default = {
7036
7243
  },
7037
7244
  emits: ["update:modelValue", "input", "select"],
7038
7245
  setup(props, { emit }) {
7039
- const root = (0, import_vue19.ref)(null);
7040
- const input = (0, import_vue19.ref)(null);
7041
- const text = (0, import_vue19.ref)(props.modelValue);
7042
- const open = (0, import_vue19.ref)(false);
7043
- const keyword = (0, import_vue19.ref)("");
7044
- const activeIndex = (0, import_vue19.ref)(-1);
7246
+ const root = (0, import_vue20.ref)(null);
7247
+ const input = (0, import_vue20.ref)(null);
7248
+ const text = (0, import_vue20.ref)(props.modelValue);
7249
+ const open = (0, import_vue20.ref)(false);
7250
+ const keyword = (0, import_vue20.ref)("");
7251
+ const activeIndex = (0, import_vue20.ref)(-1);
7045
7252
  const listId = "djm-mentions-" + ++uidSeed3;
7046
- const panelStyle = (0, import_vue19.ref)({ ...PANEL_HIDDEN_STYLE });
7253
+ const panelStyle = (0, import_vue20.ref)({ ...PANEL_HIDDEN_STYLE });
7047
7254
  let triggerIndex = -1;
7048
7255
  let detachPanel = null;
7049
- (0, import_vue19.watch)(() => props.modelValue, (value) => {
7256
+ (0, import_vue20.watch)(() => props.modelValue, (value) => {
7050
7257
  text.value = value;
7051
7258
  });
7052
- const normalized = (0, import_vue19.computed)(() => props.options.map((item) => typeof item === "string" ? { value: item, label: item } : item));
7053
- const filtered = (0, import_vue19.computed)(() => {
7259
+ const normalized = (0, import_vue20.computed)(() => props.options.map((item) => typeof item === "string" ? { value: item, label: item } : item));
7260
+ const filtered = (0, import_vue20.computed)(() => {
7054
7261
  const key = keyword.value.trim().toLowerCase();
7055
7262
  const list = key ? normalized.value.filter((item) => String(item.label).toLowerCase().indexOf(key) > -1) : normalized.value;
7056
7263
  return list.slice(0, 6);
7057
7264
  });
7058
- const activeId = (0, import_vue19.computed)(() => activeIndex.value > -1 ? listId + "-" + activeIndex.value : void 0);
7265
+ const activeId = (0, import_vue20.computed)(() => activeIndex.value > -1 ? listId + "-" + activeIndex.value : void 0);
7059
7266
  function updatePosition() {
7060
7267
  if (!open.value || !root.value) return;
7061
7268
  const rect = root.value.getBoundingClientRect();
@@ -7075,7 +7282,7 @@ var mentions_default = {
7075
7282
  onReposition: updatePosition,
7076
7283
  esc: false
7077
7284
  });
7078
- (0, import_vue19.nextTick)(updatePosition);
7285
+ (0, import_vue20.nextTick)(updatePosition);
7079
7286
  }
7080
7287
  function closePanel() {
7081
7288
  if (!open.value) return;
@@ -7102,7 +7309,7 @@ var mentions_default = {
7102
7309
  keyword.value = match[1];
7103
7310
  activeIndex.value = -1;
7104
7311
  if (!open.value) openPanel();
7105
- else (0, import_vue19.nextTick)(updatePosition);
7312
+ else (0, import_vue20.nextTick)(updatePosition);
7106
7313
  }
7107
7314
  function onKeydown(event) {
7108
7315
  if (!open.value) return;
@@ -7132,14 +7339,14 @@ var mentions_default = {
7132
7339
  emit("update:modelValue", next);
7133
7340
  emit("select", item);
7134
7341
  closePanel();
7135
- (0, import_vue19.nextTick)(() => {
7342
+ (0, import_vue20.nextTick)(() => {
7136
7343
  if (!input.value) return;
7137
7344
  const pos = triggerIndex + item.label.length + 2;
7138
7345
  input.value.focus();
7139
7346
  input.value.setSelectionRange(pos, pos);
7140
7347
  });
7141
7348
  }
7142
- (0, import_vue19.onBeforeUnmount)(closePanel);
7349
+ (0, import_vue20.onBeforeUnmount)(closePanel);
7143
7350
  return {
7144
7351
  root,
7145
7352
  input,
@@ -7413,7 +7620,7 @@ var input_tag_default = {
7413
7620
  };
7414
7621
 
7415
7622
  // src/components/password/index.js
7416
- var import_vue20 = require("vue");
7623
+ var import_vue21 = require("vue");
7417
7624
  var password_default = {
7418
7625
  name: "DjmPassword",
7419
7626
  components: { DjmIcon: icon_default },
@@ -7427,8 +7634,8 @@ var password_default = {
7427
7634
  },
7428
7635
  emits: ["update:modelValue", "input", "change", "enter", "focus", "blur"],
7429
7636
  setup(props, { emit }) {
7430
- const visible = (0, import_vue20.ref)(false);
7431
- const score = (0, import_vue20.computed)(() => {
7637
+ const visible = (0, import_vue21.ref)(false);
7638
+ const score = (0, import_vue21.computed)(() => {
7432
7639
  const value = props.modelValue || "";
7433
7640
  if (!value) return 0;
7434
7641
  let total = 0;
@@ -7438,12 +7645,12 @@ var password_default = {
7438
7645
  if (/[^a-zA-Z\d]/.test(value)) total += 1;
7439
7646
  return total;
7440
7647
  });
7441
- const level = (0, import_vue20.computed)(() => {
7648
+ const level = (0, import_vue21.computed)(() => {
7442
7649
  if (score.value <= 1) return 1;
7443
7650
  if (score.value <= 3) return 2;
7444
7651
  return 3;
7445
7652
  });
7446
- const label = (0, import_vue20.computed)(() => {
7653
+ const label = (0, import_vue21.computed)(() => {
7447
7654
  const key = ["", "password.weak", "password.medium", "password.strong"][level.value];
7448
7655
  return t(key);
7449
7656
  });
@@ -7493,7 +7700,7 @@ var password_default = {
7493
7700
  };
7494
7701
 
7495
7702
  // src/components/command-palette/index.js
7496
- var import_vue21 = require("vue");
7703
+ var import_vue22 = require("vue");
7497
7704
 
7498
7705
  // src/utils/focus-trap.js
7499
7706
  var FOCUSABLE = [
@@ -7546,14 +7753,14 @@ var command_palette_default = {
7546
7753
  },
7547
7754
  emits: ["update:modelValue", "run"],
7548
7755
  setup(props, { emit }) {
7549
- const open = (0, import_vue21.ref)(false);
7550
- const keyword = (0, import_vue21.ref)("");
7551
- const activeIndex = (0, import_vue21.ref)(-1);
7552
- const searchInput = (0, import_vue21.ref)(null);
7553
- const panelEl = (0, import_vue21.ref)(null);
7756
+ const open = (0, import_vue22.ref)(false);
7757
+ const keyword = (0, import_vue22.ref)("");
7758
+ const activeIndex = (0, import_vue22.ref)(-1);
7759
+ const searchInput = (0, import_vue22.ref)(null);
7760
+ const panelEl = (0, import_vue22.ref)(null);
7554
7761
  const listId = "djm-command-list-" + ++uidSeed4;
7555
7762
  let releaseTrap = null;
7556
- const filtered = (0, import_vue21.computed)(() => {
7763
+ const filtered = (0, import_vue22.computed)(() => {
7557
7764
  const key = keyword.value.trim().toLowerCase();
7558
7765
  if (!key) return props.commands;
7559
7766
  return props.commands.filter((item) => {
@@ -7561,7 +7768,7 @@ var command_palette_default = {
7561
7768
  return text.indexOf(key) > -1;
7562
7769
  });
7563
7770
  });
7564
- const activeId = (0, import_vue21.computed)(() => activeIndex.value > -1 ? listId + "-" + activeIndex.value : void 0);
7771
+ const activeId = (0, import_vue22.computed)(() => activeIndex.value > -1 ? listId + "-" + activeIndex.value : void 0);
7565
7772
  function show() {
7566
7773
  if (open.value) return;
7567
7774
  open.value = true;
@@ -7570,7 +7777,7 @@ var command_palette_default = {
7570
7777
  emit("update:modelValue", true);
7571
7778
  lockScroll();
7572
7779
  document.addEventListener("keydown", onDocumentKeydown);
7573
- (0, import_vue21.nextTick)(() => {
7780
+ (0, import_vue22.nextTick)(() => {
7574
7781
  releaseTrap = trapFocus(panelEl.value);
7575
7782
  if (searchInput.value) searchInput.value.focus();
7576
7783
  });
@@ -7633,12 +7840,12 @@ var command_palette_default = {
7633
7840
  if (typeof item.run === "function") item.run(item);
7634
7841
  hide();
7635
7842
  }
7636
- (0, import_vue21.watch)(() => props.modelValue, (value) => {
7843
+ (0, import_vue22.watch)(() => props.modelValue, (value) => {
7637
7844
  if (value) show();
7638
7845
  else hide();
7639
7846
  });
7640
- (0, import_vue21.onMounted)(() => window.addEventListener("keydown", onGlobalKeydown));
7641
- (0, import_vue21.onBeforeUnmount)(() => {
7847
+ (0, import_vue22.onMounted)(() => window.addEventListener("keydown", onGlobalKeydown));
7848
+ (0, import_vue22.onBeforeUnmount)(() => {
7642
7849
  window.removeEventListener("keydown", onGlobalKeydown);
7643
7850
  hide();
7644
7851
  });
@@ -7690,7 +7897,7 @@ var command_palette_default = {
7690
7897
  };
7691
7898
 
7692
7899
  // src/components/qrcode/index.js
7693
- var import_vue22 = require("vue");
7900
+ var import_vue23 = require("vue");
7694
7901
  var qrcode_default = {
7695
7902
  name: "DjmQRCode",
7696
7903
  props: {
@@ -7705,8 +7912,8 @@ var qrcode_default = {
7705
7912
  alt: { type: String, default: "\u4E8C\u7EF4\u7801" }
7706
7913
  },
7707
7914
  setup(props) {
7708
- const src = (0, import_vue22.ref)("");
7709
- const error = (0, import_vue22.ref)("");
7915
+ const src = (0, import_vue23.ref)("");
7916
+ const error = (0, import_vue23.ref)("");
7710
7917
  let lib = null;
7711
7918
  let seq2 = 0;
7712
7919
  async function ensureLib() {
@@ -7742,8 +7949,8 @@ var qrcode_default = {
7742
7949
  error.value = "\u4E8C\u7EF4\u7801\u751F\u6210\u5931\u8D25";
7743
7950
  }
7744
7951
  }
7745
- (0, import_vue22.onMounted)(render);
7746
- (0, import_vue22.watch)(() => [props.value, props.size, props.level, props.margin, props.dark, props.light], render);
7952
+ (0, import_vue23.onMounted)(render);
7953
+ (0, import_vue23.watch)(() => [props.value, props.size, props.level, props.margin, props.dark, props.light], render);
7747
7954
  return { src, error };
7748
7955
  },
7749
7956
  template: `
@@ -7782,7 +7989,7 @@ var status_default = {
7782
7989
  };
7783
7990
 
7784
7991
  // src/components/tooltip/index.js
7785
- var import_vue23 = require("vue");
7992
+ var import_vue24 = require("vue");
7786
7993
  var uid2 = 0;
7787
7994
  var tooltip_default = {
7788
7995
  name: "DjmTooltip",
@@ -7793,11 +8000,11 @@ var tooltip_default = {
7793
8000
  delay: { type: Number, default: 80 }
7794
8001
  },
7795
8002
  setup(props) {
7796
- const visible = (0, import_vue23.ref)(false);
7797
- const rootRef = (0, import_vue23.ref)(null);
7798
- const contentRef = (0, import_vue23.ref)(null);
7799
- const actualPlacement = (0, import_vue23.ref)(props.placement);
7800
- const panelStyle = (0, import_vue23.ref)({});
8003
+ const visible = (0, import_vue24.ref)(false);
8004
+ const rootRef = (0, import_vue24.ref)(null);
8005
+ const contentRef = (0, import_vue24.ref)(null);
8006
+ const actualPlacement = (0, import_vue24.ref)(props.placement);
8007
+ const panelStyle = (0, import_vue24.ref)({});
7801
8008
  const tipId = "djm-tooltip-" + ++uid2;
7802
8009
  let timer = null;
7803
8010
  function triggerEl() {
@@ -7855,7 +8062,7 @@ var tooltip_default = {
7855
8062
  window.clearTimeout(timer);
7856
8063
  timer = window.setTimeout(async () => {
7857
8064
  visible.value = true;
7858
- await (0, import_vue23.nextTick)();
8065
+ await (0, import_vue24.nextTick)();
7859
8066
  position();
7860
8067
  bindTrigger(true);
7861
8068
  bindReposition(true);
@@ -7868,7 +8075,7 @@ var tooltip_default = {
7868
8075
  bindTrigger(false);
7869
8076
  bindReposition(false);
7870
8077
  }
7871
- (0, import_vue23.onBeforeUnmount)(() => {
8078
+ (0, import_vue24.onBeforeUnmount)(() => {
7872
8079
  window.clearTimeout(timer);
7873
8080
  bindReposition(false);
7874
8081
  });
@@ -7893,7 +8100,7 @@ var tooltip_default = {
7893
8100
  };
7894
8101
 
7895
8102
  // src/components/dropdown/index.js
7896
- var import_vue24 = require("vue");
8103
+ var import_vue25 = require("vue");
7897
8104
  var dropdown_default = {
7898
8105
  name: "DjmDropdown",
7899
8106
  components: { DjmIcon: icon_default },
@@ -7910,10 +8117,10 @@ var dropdown_default = {
7910
8117
  },
7911
8118
  emits: ["select", "visible-change"],
7912
8119
  setup(props, { emit }) {
7913
- const open = (0, import_vue24.ref)(false);
7914
- const root = (0, import_vue24.ref)(null);
7915
- const menuEl = (0, import_vue24.ref)(null);
7916
- const panelStyle = (0, import_vue24.ref)({});
8120
+ const open = (0, import_vue25.ref)(false);
8121
+ const root = (0, import_vue25.ref)(null);
8122
+ const menuEl = (0, import_vue25.ref)(null);
8123
+ const panelStyle = (0, import_vue25.ref)({});
7917
8124
  let detachPanel = null;
7918
8125
  function syncTriggerA11y() {
7919
8126
  const wrapper = root.value && root.value.querySelector(".djm-dropdown-trigger");
@@ -7926,8 +8133,8 @@ var dropdown_default = {
7926
8133
  if (props.disabled) target.setAttribute("aria-disabled", "true");
7927
8134
  else target.removeAttribute("aria-disabled");
7928
8135
  }
7929
- (0, import_vue24.onMounted)(() => (0, import_vue24.nextTick)(syncTriggerA11y));
7930
- (0, import_vue24.watch)(open, () => (0, import_vue24.nextTick)(syncTriggerA11y));
8136
+ (0, import_vue25.onMounted)(() => (0, import_vue25.nextTick)(syncTriggerA11y));
8137
+ (0, import_vue25.watch)(open, () => (0, import_vue25.nextTick)(syncTriggerA11y));
7931
8138
  function updatePosition() {
7932
8139
  if (!open.value || !root.value) return;
7933
8140
  const rect = root.value.getBoundingClientRect();
@@ -7971,7 +8178,7 @@ var dropdown_default = {
7971
8178
  returnFocus();
7972
8179
  }
7973
8180
  function focusFirstItem() {
7974
- (0, import_vue24.nextTick)(() => {
8181
+ (0, import_vue25.nextTick)(() => {
7975
8182
  const el = menuEl.value && menuEl.value.querySelector(".djm-dropdown-item:not(:disabled)");
7976
8183
  if (el) el.focus();
7977
8184
  });
@@ -8030,7 +8237,7 @@ var dropdown_default = {
8030
8237
  emit("select", item);
8031
8238
  if (props.closeOnSelect) close2();
8032
8239
  }
8033
- (0, import_vue24.onBeforeUnmount)(() => {
8240
+ (0, import_vue25.onBeforeUnmount)(() => {
8034
8241
  window.clearTimeout(hoverTimer);
8035
8242
  close2();
8036
8243
  });
@@ -8095,7 +8302,7 @@ var dropdown_default = {
8095
8302
  };
8096
8303
 
8097
8304
  // src/components/drawer/index.js
8098
- var import_vue25 = require("vue");
8305
+ var import_vue26 = require("vue");
8099
8306
  var uid3 = 0;
8100
8307
  var drawer_default = {
8101
8308
  name: "DjmDrawer",
@@ -8108,11 +8315,13 @@ var drawer_default = {
8108
8315
  // 点击遮罩关闭
8109
8316
  maskClosable: { type: Boolean, default: true },
8110
8317
  showClose: { type: Boolean, default: true },
8111
- closeOnEsc: { type: Boolean, default: true }
8318
+ closeOnEsc: { type: Boolean, default: true },
8319
+ // 毛玻璃底
8320
+ glass: { type: Boolean, default: false }
8112
8321
  },
8113
8322
  emits: ["update:modelValue", "open", "close"],
8114
8323
  setup(props, { emit }) {
8115
- const panelRef = (0, import_vue25.ref)(null);
8324
+ const panelRef = (0, import_vue26.ref)(null);
8116
8325
  const titleId = `djm-drawer-title-${++uid3}`;
8117
8326
  let locked = false;
8118
8327
  let releaseTrap = null;
@@ -8133,7 +8342,7 @@ var drawer_default = {
8133
8342
  lockScroll();
8134
8343
  locked = true;
8135
8344
  emit("open");
8136
- await (0, import_vue25.nextTick)();
8345
+ await (0, import_vue26.nextTick)();
8137
8346
  releaseTrap = trapFocus(panelRef.value);
8138
8347
  }
8139
8348
  function deactivate() {
@@ -8145,14 +8354,14 @@ var drawer_default = {
8145
8354
  }
8146
8355
  emit("close");
8147
8356
  }
8148
- (0, import_vue25.watch)(() => props.modelValue, (open) => {
8357
+ (0, import_vue26.watch)(() => props.modelValue, (open) => {
8149
8358
  if (open) activate();
8150
8359
  else deactivate();
8151
8360
  });
8152
- (0, import_vue25.onMounted)(() => {
8361
+ (0, import_vue26.onMounted)(() => {
8153
8362
  if (props.modelValue) activate();
8154
8363
  });
8155
- (0, import_vue25.onBeforeUnmount)(() => {
8364
+ (0, import_vue26.onBeforeUnmount)(() => {
8156
8365
  document.removeEventListener("keydown", onKeydown);
8157
8366
  release();
8158
8367
  if (locked) unlockScroll();
@@ -8171,7 +8380,7 @@ var drawer_default = {
8171
8380
  <aside
8172
8381
  ref="panelRef"
8173
8382
  class="djm-drawer"
8174
- :class="'djm-drawer-' + placement"
8383
+ :class="['djm-drawer-' + placement, { 'djm-is-glass': glass }]"
8175
8384
  :style="panelStyle"
8176
8385
  role="dialog"
8177
8386
  aria-modal="true"
@@ -8206,7 +8415,7 @@ var drawer_default = {
8206
8415
  };
8207
8416
 
8208
8417
  // src/components/modal/index.js
8209
- var import_vue26 = require("vue");
8418
+ var import_vue27 = require("vue");
8210
8419
  var uid4 = 0;
8211
8420
  var modal_default = {
8212
8421
  name: "DjmModal",
@@ -8221,11 +8430,13 @@ var modal_default = {
8221
8430
  // 是否允许 Esc 关闭
8222
8431
  closeOnEsc: { type: Boolean, default: true },
8223
8432
  // 全屏铺满,适合配置类大表单
8224
- fullscreen: { type: Boolean, default: false }
8433
+ fullscreen: { type: Boolean, default: false },
8434
+ // 毛玻璃底:需要显示背后页面时使用
8435
+ glass: { type: Boolean, default: false }
8225
8436
  },
8226
8437
  emits: ["update:modelValue", "open", "close"],
8227
8438
  setup(props, { emit }) {
8228
- const dialogRef = (0, import_vue26.ref)(null);
8439
+ const dialogRef = (0, import_vue27.ref)(null);
8229
8440
  const titleId = `djm-modal-title-${++uid4}`;
8230
8441
  let locked = false;
8231
8442
  let releaseTrap = null;
@@ -8246,7 +8457,7 @@ var modal_default = {
8246
8457
  lockScroll();
8247
8458
  locked = true;
8248
8459
  emit("open");
8249
- await (0, import_vue26.nextTick)();
8460
+ await (0, import_vue27.nextTick)();
8250
8461
  releaseTrap = trapFocus(dialogRef.value);
8251
8462
  }
8252
8463
  function deactivate() {
@@ -8258,14 +8469,14 @@ var modal_default = {
8258
8469
  }
8259
8470
  emit("close");
8260
8471
  }
8261
- (0, import_vue26.watch)(() => props.modelValue, (open) => {
8472
+ (0, import_vue27.watch)(() => props.modelValue, (open) => {
8262
8473
  if (open) activate();
8263
8474
  else deactivate();
8264
8475
  });
8265
- (0, import_vue26.onMounted)(() => {
8476
+ (0, import_vue27.onMounted)(() => {
8266
8477
  if (props.modelValue) activate();
8267
8478
  });
8268
- (0, import_vue26.onBeforeUnmount)(() => {
8479
+ (0, import_vue27.onBeforeUnmount)(() => {
8269
8480
  document.removeEventListener("keydown", onKey);
8270
8481
  release();
8271
8482
  if (locked) unlockScroll();
@@ -8275,7 +8486,7 @@ var modal_default = {
8275
8486
  dialogRef,
8276
8487
  titleId,
8277
8488
  t,
8278
- dialogStyle: (0, import_vue26.computed)(
8489
+ dialogStyle: (0, import_vue27.computed)(
8279
8490
  () => props.fullscreen ? { width: "calc(100vw - 32px)", height: "calc(100vh - 48px)" } : { width: props.width }
8280
8491
  )
8281
8492
  };
@@ -8287,7 +8498,7 @@ var modal_default = {
8287
8498
  <div
8288
8499
  ref="dialogRef"
8289
8500
  class="djm-modal"
8290
- :class="{ 'djm-is-fullscreen': fullscreen }"
8501
+ :class="{ 'djm-is-fullscreen': fullscreen, 'djm-is-glass': glass }"
8291
8502
  :style="dialogStyle"
8292
8503
  role="dialog"
8293
8504
  aria-modal="true"
@@ -8385,7 +8596,7 @@ var confirm_dialog_default = {
8385
8596
  };
8386
8597
 
8387
8598
  // src/components/pagination/index.js
8388
- var import_vue27 = require("vue");
8599
+ var import_vue28 = require("vue");
8389
8600
  var pagination_default = {
8390
8601
  name: "DjmPagination",
8391
8602
  components: { Icon: icon_default },
@@ -8397,10 +8608,10 @@ var pagination_default = {
8397
8608
  },
8398
8609
  emits: ["update:page", "update:pageSize", "change"],
8399
8610
  setup(props, { emit }) {
8400
- const jumpText = (0, import_vue27.ref)("");
8401
- const pageCount = (0, import_vue27.computed)(() => Math.max(1, Math.ceil(props.total / Math.max(1, props.pageSize))));
8402
- const current = (0, import_vue27.computed)(() => Math.min(Math.max(1, props.page), pageCount.value));
8403
- const pages = (0, import_vue27.computed)(() => {
8611
+ const jumpText = (0, import_vue28.ref)("");
8612
+ const pageCount = (0, import_vue28.computed)(() => Math.max(1, Math.ceil(props.total / Math.max(1, props.pageSize))));
8613
+ const current = (0, import_vue28.computed)(() => Math.min(Math.max(1, props.page), pageCount.value));
8614
+ const pages = (0, import_vue28.computed)(() => {
8404
8615
  const count2 = pageCount.value;
8405
8616
  const currentPage = current.value;
8406
8617
  if (count2 <= 7) {
@@ -8497,7 +8708,7 @@ var pagination_default = {
8497
8708
  };
8498
8709
 
8499
8710
  // src/components/tabs/index.js
8500
- var import_vue28 = require("vue");
8711
+ var import_vue29 = require("vue");
8501
8712
  var uid5 = 0;
8502
8713
  var tabs_default = {
8503
8714
  name: "DjmTabs",
@@ -8513,7 +8724,7 @@ var tabs_default = {
8513
8724
  emits: ["update:modelValue", "close"],
8514
8725
  setup(props, { emit }) {
8515
8726
  const panelId = `djm-tabs-panel-${++uid5}`;
8516
- const activeItem = (0, import_vue28.computed)(
8727
+ const activeItem = (0, import_vue29.computed)(
8517
8728
  () => props.items.find((item) => item.key === props.modelValue) || { label: String(props.modelValue) }
8518
8729
  );
8519
8730
  function tabId(item) {
@@ -8617,7 +8828,7 @@ var tabs_default = {
8617
8828
  };
8618
8829
 
8619
8830
  // src/components/context-menu/index.js
8620
- var import_vue29 = require("vue");
8831
+ var import_vue30 = require("vue");
8621
8832
  var context_menu_default = {
8622
8833
  name: "DjmContextMenu",
8623
8834
  components: { Icon: icon_default },
@@ -8629,8 +8840,8 @@ var context_menu_default = {
8629
8840
  },
8630
8841
  emits: ["update:modelValue", "select"],
8631
8842
  setup(props, { emit }) {
8632
- const menuRef = (0, import_vue29.ref)(null);
8633
- const pos = (0, import_vue29.ref)({ left: 0, top: 0 });
8843
+ const menuRef = (0, import_vue30.ref)(null);
8844
+ const pos = (0, import_vue30.ref)({ left: 0, top: 0 });
8634
8845
  const margin = 8;
8635
8846
  function close2() {
8636
8847
  emit("update:modelValue", false);
@@ -8650,7 +8861,7 @@ var context_menu_default = {
8650
8861
  }
8651
8862
  async function openAtCursor() {
8652
8863
  pos.value = { left: props.x, top: props.y };
8653
- await (0, import_vue29.nextTick)();
8864
+ await (0, import_vue30.nextTick)();
8654
8865
  place();
8655
8866
  const first = menuRef.value && menuRef.value.querySelector(".djm-context-menu-item:not(:disabled)");
8656
8867
  if (first) first.focus();
@@ -8692,7 +8903,7 @@ var context_menu_default = {
8692
8903
  detach = null;
8693
8904
  }
8694
8905
  }
8695
- (0, import_vue29.watch)(
8906
+ (0, import_vue30.watch)(
8696
8907
  () => props.modelValue,
8697
8908
  (open) => {
8698
8909
  if (open) {
@@ -8703,10 +8914,10 @@ var context_menu_default = {
8703
8914
  }
8704
8915
  }
8705
8916
  );
8706
- (0, import_vue29.watch)([() => props.x, () => props.y], () => {
8917
+ (0, import_vue30.watch)([() => props.x, () => props.y], () => {
8707
8918
  if (props.modelValue) openAtCursor();
8708
8919
  });
8709
- (0, import_vue29.onBeforeUnmount)(unbind);
8920
+ (0, import_vue30.onBeforeUnmount)(unbind);
8710
8921
  return { menuRef, pos, close: close2, onSelect, onKeydown, t };
8711
8922
  },
8712
8923
  template: `
@@ -8745,7 +8956,7 @@ var context_menu_default = {
8745
8956
  };
8746
8957
 
8747
8958
  // src/components/date-picker/index.js
8748
- var import_vue30 = require("vue");
8959
+ var import_vue31 = require("vue");
8749
8960
  var uidSeed5 = 0;
8750
8961
  function pad3(value) {
8751
8962
  return String(value).padStart(2, "0");
@@ -8780,36 +8991,36 @@ var date_picker_default = {
8780
8991
  },
8781
8992
  emits: ["update:modelValue", "change", "visible-change"],
8782
8993
  setup(props, { emit }) {
8783
- const open = (0, import_vue30.ref)(false);
8784
- (0, import_vue30.watch)(open, (value) => emit("visible-change", value));
8785
- const root = (0, import_vue30.ref)(null);
8786
- const panel = (0, import_vue30.ref)(null);
8994
+ const open = (0, import_vue31.ref)(false);
8995
+ (0, import_vue31.watch)(open, (value) => emit("visible-change", value));
8996
+ const root = (0, import_vue31.ref)(null);
8997
+ const panel = (0, import_vue31.ref)(null);
8787
8998
  const panelId = "djm-date-panel-" + ++uidSeed5;
8788
- const panelStyle = (0, import_vue30.ref)({ ...PANEL_HIDDEN_STYLE });
8999
+ const panelStyle = (0, import_vue31.ref)({ ...PANEL_HIDDEN_STYLE });
8789
9000
  let detachPanel = null;
8790
9001
  const today = /* @__PURE__ */ new Date();
8791
9002
  const todayKey = toKey2(today.getFullYear(), today.getMonth(), today.getDate());
8792
- const values = (0, import_vue30.computed)(() => {
9003
+ const values = (0, import_vue31.computed)(() => {
8793
9004
  if (props.range) return Array.isArray(props.modelValue) ? props.modelValue : [];
8794
9005
  return props.modelValue ? [props.modelValue] : [];
8795
9006
  });
8796
- const displayText = (0, import_vue30.computed)(() => {
9007
+ const displayText = (0, import_vue31.computed)(() => {
8797
9008
  if (!props.range) return values.value[0] || "";
8798
9009
  const [start, end] = values.value;
8799
9010
  if (!start) return "";
8800
9011
  return end ? `${start} ~ ${end}` : `${start} ~ ${t("datePicker.rangeEnd")}`;
8801
9012
  });
8802
9013
  const initial = parse2(values.value[0]);
8803
- const viewYear = (0, import_vue30.ref)(initial ? initial.year : today.getFullYear());
8804
- const viewMonth = (0, import_vue30.ref)(initial ? initial.month : today.getMonth());
8805
- const pendingStart = (0, import_vue30.ref)(values.value[0] || "");
8806
- const pendingEnd = (0, import_vue30.ref)(values.value[1] || "");
8807
- const placeholderText = (0, import_vue30.computed)(() => {
9014
+ const viewYear = (0, import_vue31.ref)(initial ? initial.year : today.getFullYear());
9015
+ const viewMonth = (0, import_vue31.ref)(initial ? initial.month : today.getMonth());
9016
+ const pendingStart = (0, import_vue31.ref)(values.value[0] || "");
9017
+ const pendingEnd = (0, import_vue31.ref)(values.value[1] || "");
9018
+ const placeholderText = (0, import_vue31.computed)(() => {
8808
9019
  if (props.placeholder) return props.placeholder;
8809
9020
  return t(props.range ? "datePicker.rangePlaceholder" : "datePicker.placeholder");
8810
9021
  });
8811
- const weeks = (0, import_vue30.computed)(() => t("datePicker.weeks").split(","));
8812
- const narrow = (0, import_vue30.ref)(false);
9022
+ const weeks = (0, import_vue31.computed)(() => t("datePicker.weeks").split(","));
9023
+ const narrow = (0, import_vue31.ref)(false);
8813
9024
  let media = null;
8814
9025
  const onMediaChange = (event) => {
8815
9026
  narrow.value = event.matches;
@@ -8820,14 +9031,14 @@ var date_picker_default = {
8820
9031
  if (media.addEventListener) media.addEventListener("change", onMediaChange);
8821
9032
  else media.addListener(onMediaChange);
8822
9033
  }
8823
- (0, import_vue30.onBeforeUnmount)(() => {
9034
+ (0, import_vue31.onBeforeUnmount)(() => {
8824
9035
  if (!media) return;
8825
9036
  if (media.removeEventListener) media.removeEventListener("change", onMediaChange);
8826
9037
  else media.removeListener(onMediaChange);
8827
9038
  });
8828
- const panelCount = (0, import_vue30.computed)(() => props.range ? Math.min(narrow.value ? 1 : 2, Math.max(1, props.panels)) : 1);
8829
- const hoverKey = (0, import_vue30.ref)("");
8830
- const hoverRange = (0, import_vue30.computed)(() => {
9039
+ const panelCount = (0, import_vue31.computed)(() => props.range ? Math.min(narrow.value ? 1 : 2, Math.max(1, props.panels)) : 1);
9040
+ const hoverKey = (0, import_vue31.ref)("");
9041
+ const hoverRange = (0, import_vue31.computed)(() => {
8831
9042
  if (!props.range || !pendingStart.value || pendingEnd.value || !hoverKey.value) return null;
8832
9043
  const a = pendingStart.value;
8833
9044
  const b = hoverKey.value;
@@ -8863,7 +9074,7 @@ var date_picker_default = {
8863
9074
  };
8864
9075
  });
8865
9076
  }
8866
- const panels = (0, import_vue30.computed)(
9077
+ const panels = (0, import_vue31.computed)(
8867
9078
  () => Array.from({ length: panelCount.value }, (_, offset) => {
8868
9079
  const { year, month } = monthAt(offset);
8869
9080
  return {
@@ -8878,7 +9089,7 @@ var date_picker_default = {
8878
9089
  if (props.max && key > props.max) return true;
8879
9090
  return typeof props.disabledDate === "function" ? Boolean(props.disabledDate(key)) : false;
8880
9091
  }
8881
- const presetList = (0, import_vue30.computed)(() => {
9092
+ const presetList = (0, import_vue31.computed)(() => {
8882
9093
  if (!props.range) return [];
8883
9094
  return (props.presets || []).map((preset) => {
8884
9095
  const value = typeof preset.value === "function" ? preset.value() : preset.value;
@@ -9006,7 +9217,7 @@ var date_picker_default = {
9006
9217
  pendingEnd.value = "";
9007
9218
  closePanel();
9008
9219
  }
9009
- (0, import_vue30.onBeforeUnmount)(() => {
9220
+ (0, import_vue31.onBeforeUnmount)(() => {
9010
9221
  if (detachPanel) {
9011
9222
  detachPanel();
9012
9223
  detachPanel = null;
@@ -9135,7 +9346,7 @@ var date_picker_default = {
9135
9346
  };
9136
9347
 
9137
9348
  // src/components/tree-select/index.js
9138
- var import_vue31 = require("vue");
9349
+ var import_vue32 = require("vue");
9139
9350
  function collectLeaves(node, keyOf2, out = []) {
9140
9351
  if (node.children && node.children.length) {
9141
9352
  node.children.forEach((child) => collectLeaves(child, keyOf2, out));
@@ -9171,13 +9382,13 @@ var tree_select_default = {
9171
9382
  },
9172
9383
  emits: ["update:modelValue", "change", "visible-change"],
9173
9384
  setup(props, { emit }) {
9174
- const open = (0, import_vue31.ref)(false);
9175
- const root = (0, import_vue31.ref)(null);
9176
- const panel = (0, import_vue31.ref)(null);
9177
- const searchInput = (0, import_vue31.ref)(null);
9178
- const search = (0, import_vue31.ref)("");
9179
- const temp = (0, import_vue31.ref)([]);
9180
- const panelStyle = (0, import_vue31.ref)({ ...PANEL_HIDDEN_STYLE });
9385
+ const open = (0, import_vue32.ref)(false);
9386
+ const root = (0, import_vue32.ref)(null);
9387
+ const panel = (0, import_vue32.ref)(null);
9388
+ const searchInput = (0, import_vue32.ref)(null);
9389
+ const search = (0, import_vue32.ref)("");
9390
+ const temp = (0, import_vue32.ref)([]);
9391
+ const panelStyle = (0, import_vue32.ref)({ ...PANEL_HIDDEN_STYLE });
9181
9392
  let detachPanel = null;
9182
9393
  function keyOf2(node) {
9183
9394
  return node ? node[props.nodeKey] : void 0;
@@ -9186,26 +9397,26 @@ var tree_select_default = {
9186
9397
  const value = node ? node[props.labelKey] : "";
9187
9398
  return value === null || value === void 0 ? "" : String(value);
9188
9399
  }
9189
- const expandedIds = (0, import_vue31.ref)(
9400
+ const expandedIds = (0, import_vue32.ref)(
9190
9401
  new Set(
9191
9402
  collectNodes(props.options).filter((node) => node.children && node.children.length).map((node) => keyOf2(node))
9192
9403
  )
9193
9404
  );
9194
- const nodeMap = (0, import_vue31.computed)(() => {
9405
+ const nodeMap = (0, import_vue32.computed)(() => {
9195
9406
  const map = /* @__PURE__ */ new Map();
9196
9407
  collectNodes(props.options).forEach((node) => map.set(keyOf2(node), node));
9197
9408
  return map;
9198
9409
  });
9199
- (0, import_vue31.watch)(() => props.options, (options) => {
9410
+ (0, import_vue32.watch)(() => props.options, (options) => {
9200
9411
  if (!options || !options.length || expandedIds.value.size) return;
9201
9412
  expandedIds.value = new Set(
9202
9413
  collectNodes(options).filter((node) => node.children && node.children.length).map((node) => keyOf2(node))
9203
9414
  );
9204
9415
  });
9205
- const selectedNodes = (0, import_vue31.computed)(
9416
+ const selectedNodes = (0, import_vue32.computed)(
9206
9417
  () => props.modelValue.map((id) => nodeMap.value.get(id)).filter(Boolean).map((node) => ({ key: keyOf2(node), label: labelOf(node) }))
9207
9418
  );
9208
- const searchState = (0, import_vue31.computed)(() => {
9419
+ const searchState = (0, import_vue32.computed)(() => {
9209
9420
  const text = search.value.trim().toLowerCase();
9210
9421
  if (!text) return null;
9211
9422
  const visible = /* @__PURE__ */ new Set();
@@ -9224,7 +9435,7 @@ var tree_select_default = {
9224
9435
  walk(props.options);
9225
9436
  return visible;
9226
9437
  });
9227
- const rows = (0, import_vue31.computed)(() => {
9438
+ const rows = (0, import_vue32.computed)(() => {
9228
9439
  const result = [];
9229
9440
  const walk = (nodes, depth) => {
9230
9441
  nodes.forEach((node) => {
@@ -9299,7 +9510,7 @@ var tree_select_default = {
9299
9510
  onClose: closePanel,
9300
9511
  onReposition: updatePosition
9301
9512
  });
9302
- (0, import_vue31.nextTick)(() => {
9513
+ (0, import_vue32.nextTick)(() => {
9303
9514
  updatePosition();
9304
9515
  if (searchInput.value) searchInput.value.focus();
9305
9516
  });
@@ -9355,7 +9566,7 @@ var tree_select_default = {
9355
9566
  emit("change", []);
9356
9567
  temp.value = [];
9357
9568
  }
9358
- (0, import_vue31.onBeforeUnmount)(() => {
9569
+ (0, import_vue32.onBeforeUnmount)(() => {
9359
9570
  if (detachPanel) {
9360
9571
  detachPanel();
9361
9572
  detachPanel = null;
@@ -9494,174 +9705,797 @@ var tree_select_default = {
9494
9705
  };
9495
9706
 
9496
9707
  // src/components/rich-editor/index.js
9497
- var import_vue32 = require("vue");
9708
+ var import_vue34 = require("vue");
9498
9709
 
9499
- // src/utils/sanitize-html.js
9500
- var TAGS = /* @__PURE__ */ new Set([
9501
- "p",
9502
- "br",
9503
- "div",
9504
- "span",
9505
- "strong",
9506
- "b",
9507
- "em",
9508
- "i",
9509
- "u",
9510
- "s",
9511
- "del",
9512
- "sub",
9513
- "sup",
9514
- "h1",
9515
- "h2",
9516
- "h3",
9517
- "h4",
9518
- "h5",
9519
- "h6",
9520
- "ul",
9521
- "ol",
9522
- "li",
9523
- "blockquote",
9524
- "pre",
9525
- "code",
9526
- "hr",
9527
- "a",
9528
- "img",
9529
- "table",
9530
- "thead",
9531
- "tbody",
9532
- "tfoot",
9533
- "tr",
9534
- "th",
9535
- "td"
9536
- ]);
9537
- var GLOBAL_ATTRS = /* @__PURE__ */ new Set(["class", "title"]);
9538
- var TAG_ATTRS = {
9539
- a: /* @__PURE__ */ new Set(["href", "target", "rel"]),
9540
- img: /* @__PURE__ */ new Set(["src", "alt", "width", "height"]),
9541
- ol: /* @__PURE__ */ new Set(["start"]),
9542
- th: /* @__PURE__ */ new Set(["colspan", "rowspan", "scope"]),
9543
- td: /* @__PURE__ */ new Set(["colspan", "rowspan"])
9544
- };
9545
- function safeUrl(value, tag) {
9546
- const url = String(value || "").replace(/[\u0000-\u0020]+/g, "").toLowerCase();
9547
- if (url.startsWith("javascript:") || url.startsWith("vbscript:")) return false;
9548
- if (url.startsWith("data:")) return tag === "img" && url.startsWith("data:image/");
9549
- return true;
9550
- }
9551
- function cleanNode(node) {
9552
- const children = [...node.childNodes];
9553
- children.forEach((child) => {
9554
- if (child.nodeType === 8) {
9555
- child.remove();
9556
- return;
9557
- }
9558
- if (child.nodeType !== 1) return;
9559
- const tag = child.tagName.toLowerCase();
9560
- if (!TAGS.has(tag)) {
9561
- child.remove();
9562
- return;
9563
- }
9564
- const allowed = TAG_ATTRS[tag];
9565
- [...child.attributes].forEach((attr) => {
9566
- const name = attr.name.toLowerCase();
9567
- const keep = GLOBAL_ATTRS.has(name) || allowed && allowed.has(name);
9568
- if (!keep) {
9569
- child.removeAttribute(attr.name);
9570
- return;
9571
- }
9572
- if ((name === "href" || name === "src") && !safeUrl(attr.value, tag)) {
9573
- child.removeAttribute(attr.name);
9574
- }
9710
+ // src/components/media-picker/index.js
9711
+ var import_vue33 = require("vue");
9712
+ var media_picker_default = {
9713
+ name: "DjmMediaPicker",
9714
+ components: { DjmModal: modal_default, DjmPagination: pagination_default, DjmIcon: icon_default },
9715
+ props: {
9716
+ modelValue: { type: [Array, String, Number], default: "" },
9717
+ items: { type: Array, default: () => [] },
9718
+ multiple: { type: Boolean, default: false },
9719
+ // 最多选几个,0 表示不限
9720
+ limit: { type: Number, default: 0 },
9721
+ // image 只显示图片,file 只显示非图片,空串不过滤
9722
+ accept: { type: String, default: "" },
9723
+ title: { type: String, default: "" },
9724
+ triggerText: { type: String, default: "" },
9725
+ pageSize: { type: Number, default: 12 },
9726
+ disabled: { type: Boolean, default: false }
9727
+ },
9728
+ emits: ["update:modelValue", "change"],
9729
+ setup(props, { emit }) {
9730
+ const open = (0, import_vue33.ref)(false);
9731
+ const keyword = (0, import_vue33.ref)("");
9732
+ const page = (0, import_vue33.ref)(1);
9733
+ const temp = (0, import_vue33.ref)([]);
9734
+ const selectedIds = (0, import_vue33.computed)(() => {
9735
+ if (props.multiple) return Array.isArray(props.modelValue) ? props.modelValue : [];
9736
+ if (props.modelValue === "" || props.modelValue === null || props.modelValue === void 0) return [];
9737
+ return [props.modelValue];
9575
9738
  });
9576
- if (tag === "a" && child.getAttribute("target") === "_blank") {
9577
- child.setAttribute("rel", "noopener noreferrer");
9739
+ function isImage(item) {
9740
+ if (item.type) return item.type === "image";
9741
+ return /\.(png|jpe?g|gif|webp|svg|avif)$/i.test(item.url || "");
9578
9742
  }
9579
- cleanNode(child);
9580
- });
9581
- }
9582
- function sanitizeHtml(html) {
9583
- if (!html) return "";
9584
- const doc = new DOMParser().parseFromString('<div id="djm-sanitize-root">' + html + "</div>", "text/html");
9585
- const root = doc.getElementById("djm-sanitize-root");
9586
- if (!root) return "";
9743
+ const filtered = (0, import_vue33.computed)(() => {
9744
+ const key = keyword.value.trim().toLowerCase();
9745
+ return props.items.filter((item) => {
9746
+ if (props.accept === "image" && !isImage(item)) return false;
9747
+ if (props.accept === "file" && isImage(item)) return false;
9748
+ if (key && !String(item.name || "").toLowerCase().includes(key)) return false;
9749
+ return true;
9750
+ });
9751
+ });
9752
+ const paged = (0, import_vue33.computed)(() => {
9753
+ const start = (page.value - 1) * props.pageSize;
9754
+ return filtered.value.slice(start, start + props.pageSize);
9755
+ });
9756
+ (0, import_vue33.watch)(keyword, () => {
9757
+ page.value = 1;
9758
+ });
9759
+ (0, import_vue33.watch)(
9760
+ () => filtered.value.length,
9761
+ () => {
9762
+ const max = Math.max(1, Math.ceil(filtered.value.length / props.pageSize));
9763
+ if (page.value > max) page.value = max;
9764
+ }
9765
+ );
9766
+ function isChecked(id) {
9767
+ return temp.value.includes(id);
9768
+ }
9769
+ function atLimit() {
9770
+ return props.limit > 0 && temp.value.length >= props.limit;
9771
+ }
9772
+ function toggle(item) {
9773
+ if (props.multiple) {
9774
+ if (isChecked(item.id)) {
9775
+ temp.value = temp.value.filter((id) => id !== item.id);
9776
+ return;
9777
+ }
9778
+ if (atLimit()) return;
9779
+ temp.value = [...temp.value, item.id];
9780
+ return;
9781
+ }
9782
+ temp.value = [item.id];
9783
+ }
9784
+ function openPanel() {
9785
+ if (props.disabled) return;
9786
+ temp.value = [...selectedIds.value];
9787
+ keyword.value = "";
9788
+ page.value = 1;
9789
+ open.value = true;
9790
+ }
9791
+ function commit() {
9792
+ const next = props.multiple ? [...temp.value] : temp.value[0] !== void 0 ? temp.value[0] : "";
9793
+ emit("update:modelValue", next);
9794
+ emit("change", next);
9795
+ open.value = false;
9796
+ }
9797
+ function cancel() {
9798
+ temp.value = [...selectedIds.value];
9799
+ open.value = false;
9800
+ }
9801
+ return {
9802
+ open,
9803
+ keyword,
9804
+ page,
9805
+ temp,
9806
+ selectedIds,
9807
+ filtered,
9808
+ paged,
9809
+ isImage,
9810
+ isChecked,
9811
+ atLimit,
9812
+ toggle,
9813
+ openPanel,
9814
+ commit,
9815
+ cancel,
9816
+ t
9817
+ };
9818
+ },
9819
+ template: `
9820
+ <span class="djm-media-picker">
9821
+ <slot name="trigger" :open="openPanel" :count="selectedIds.length">
9822
+ <button
9823
+ class="djm-btn"
9824
+ type="button"
9825
+ :disabled="disabled"
9826
+ @click="openPanel"
9827
+ >{{ triggerText || t('mediaPicker.select') }}<span v-if="selectedIds.length" class="djm-media-picker-count">{{ selectedIds.length }}</span></button>
9828
+ </slot>
9829
+
9830
+ <DjmModal
9831
+ :model-value="open"
9832
+ :title="title || t('mediaPicker.title')"
9833
+ width="760px"
9834
+ @update:model-value="cancel"
9835
+ >
9836
+ <div class="djm-media-toolbar">
9837
+ <label class="djm-media-search">
9838
+ <DjmIcon name="search" :size="13" />
9839
+ <input
9840
+ v-model="keyword"
9841
+ class="djm-media-search-input"
9842
+ type="text"
9843
+ :placeholder="t('mediaPicker.search')"
9844
+ :aria-label="t('mediaPicker.search')"
9845
+ />
9846
+ </label>
9847
+ <span class="djm-media-toolbar-slot">
9848
+ <slot name="toolbar"></slot>
9849
+ </span>
9850
+ </div>
9851
+
9852
+ <div class="djm-media-grid" role="listbox" :aria-multiselectable="multiple ? 'true' : 'false'">
9853
+ <div
9854
+ v-for="item in paged"
9855
+ :key="item.id"
9856
+ class="djm-media-item"
9857
+ :class="{
9858
+ 'djm-is-checked': isChecked(item.id),
9859
+ 'djm-is-disabled': multiple && atLimit() && !isChecked(item.id)
9860
+ }"
9861
+ role="option"
9862
+ tabindex="0"
9863
+ :aria-selected="String(isChecked(item.id))"
9864
+ @click="toggle(item)"
9865
+ @keydown.enter.prevent="toggle(item)"
9866
+ @keydown.space.prevent="toggle(item)"
9867
+ >
9868
+ <div class="djm-media-thumb">
9869
+ <img v-if="isImage(item)" :src="item.url" :alt="item.name" loading="lazy" />
9870
+ <DjmIcon v-else name="folder" :size="26" />
9871
+ <span v-if="isChecked(item.id)" class="djm-media-check">
9872
+ <DjmIcon name="check" :size="11" />
9873
+ </span>
9874
+ </div>
9875
+ <div class="djm-media-name" :title="item.name">{{ item.name }}</div>
9876
+ </div>
9877
+ <div v-if="!paged.length" class="djm-media-empty">{{ t('mediaPicker.empty') }}</div>
9878
+ </div>
9879
+
9880
+ <div class="djm-media-foot">
9881
+ <span class="djm-media-total">
9882
+ {{ t('mediaPicker.total', { total: filtered.length }) }}
9883
+ <em v-if="multiple && limit > 0">{{ t('mediaPicker.limit', { limit }) }}</em>
9884
+ </span>
9885
+ <DjmPagination
9886
+ v-if="filtered.length > pageSize"
9887
+ v-model:page="page"
9888
+ :page-size="pageSize"
9889
+ :total="filtered.length"
9890
+ />
9891
+ </div>
9892
+
9893
+ <template #footer>
9894
+ <button class="djm-btn" type="button" @click="cancel">{{ t('common.cancel') }}</button>
9895
+ <button class="djm-btn djm-btn-primary" type="button" @click="commit">{{ t('common.confirm') }}</button>
9896
+ </template>
9897
+ </DjmModal>
9898
+ </span>
9899
+ `
9900
+ };
9901
+
9902
+ // src/utils/sanitize-html.js
9903
+ var TAGS = /* @__PURE__ */ new Set([
9904
+ "p",
9905
+ "br",
9906
+ "div",
9907
+ "span",
9908
+ "strong",
9909
+ "b",
9910
+ "em",
9911
+ "i",
9912
+ "u",
9913
+ "s",
9914
+ "del",
9915
+ "sub",
9916
+ "sup",
9917
+ "h1",
9918
+ "h2",
9919
+ "h3",
9920
+ "h4",
9921
+ "h5",
9922
+ "h6",
9923
+ "ul",
9924
+ "ol",
9925
+ "li",
9926
+ "blockquote",
9927
+ "pre",
9928
+ "code",
9929
+ "hr",
9930
+ "a",
9931
+ "img",
9932
+ "table",
9933
+ "thead",
9934
+ "tbody",
9935
+ "tfoot",
9936
+ "tr",
9937
+ "th",
9938
+ "td"
9939
+ ]);
9940
+ var GLOBAL_ATTRS = /* @__PURE__ */ new Set(["class", "title", "style"]);
9941
+ var STYLE_PROPS = /* @__PURE__ */ new Set([
9942
+ "color",
9943
+ "background-color",
9944
+ "font-size",
9945
+ "font-weight",
9946
+ "font-style",
9947
+ "text-decoration",
9948
+ "text-align",
9949
+ "text-indent",
9950
+ "line-height"
9951
+ ]);
9952
+ var TAG_ATTRS = {
9953
+ a: /* @__PURE__ */ new Set(["href", "target", "rel"]),
9954
+ img: /* @__PURE__ */ new Set(["src", "alt", "width", "height"]),
9955
+ ol: /* @__PURE__ */ new Set(["start"]),
9956
+ th: /* @__PURE__ */ new Set(["colspan", "rowspan", "scope"]),
9957
+ td: /* @__PURE__ */ new Set(["colspan", "rowspan"])
9958
+ };
9959
+ function cleanStyle(value) {
9960
+ return String(value || "").split(";").map((item) => {
9961
+ const index = item.indexOf(":");
9962
+ if (index === -1) return "";
9963
+ const name = item.slice(0, index).trim().toLowerCase();
9964
+ const val = item.slice(index + 1).trim();
9965
+ if (!STYLE_PROPS.has(name)) return "";
9966
+ if (/url\s*\(|expression\s*\(|javascript:/i.test(val)) return "";
9967
+ return name + ": " + val;
9968
+ }).filter(Boolean).join("; ");
9969
+ }
9970
+ var SAFE_SCHEMES = /* @__PURE__ */ new Set(["http", "https", "mailto", "tel"]);
9971
+ function safeUrl(value, tag) {
9972
+ const url = String(value || "").replace(/[\u0000-\u0020]+/g, "");
9973
+ const scheme = url.match(/^([a-z][a-z0-9+.-]*):/i);
9974
+ if (!scheme) return true;
9975
+ const name = scheme[1].toLowerCase();
9976
+ if (SAFE_SCHEMES.has(name)) return true;
9977
+ if (tag === "img") {
9978
+ if (name === "blob") return true;
9979
+ if (name === "data" && /^data:image\//i.test(url)) return true;
9980
+ }
9981
+ return false;
9982
+ }
9983
+ function cleanNode(node) {
9984
+ const children = [...node.childNodes];
9985
+ children.forEach((child) => {
9986
+ if (child.nodeType === 8) {
9987
+ child.remove();
9988
+ return;
9989
+ }
9990
+ if (child.nodeType !== 1) return;
9991
+ const tag = child.tagName.toLowerCase();
9992
+ if (!TAGS.has(tag)) {
9993
+ child.remove();
9994
+ return;
9995
+ }
9996
+ const allowed = TAG_ATTRS[tag];
9997
+ [...child.attributes].forEach((attr) => {
9998
+ const name = attr.name.toLowerCase();
9999
+ const keep = GLOBAL_ATTRS.has(name) || allowed && allowed.has(name);
10000
+ if (!keep) {
10001
+ child.removeAttribute(attr.name);
10002
+ return;
10003
+ }
10004
+ if (name === "style") {
10005
+ const style = cleanStyle(attr.value);
10006
+ if (style) child.setAttribute("style", style);
10007
+ else child.removeAttribute("style");
10008
+ return;
10009
+ }
10010
+ if ((name === "href" || name === "src") && !safeUrl(attr.value, tag)) {
10011
+ child.removeAttribute(attr.name);
10012
+ }
10013
+ });
10014
+ if (tag === "a" && child.getAttribute("target") === "_blank") {
10015
+ child.setAttribute("rel", "noopener noreferrer");
10016
+ }
10017
+ cleanNode(child);
10018
+ });
10019
+ }
10020
+ function sanitizeHtml(html) {
10021
+ if (!html) return "";
10022
+ const doc = new DOMParser().parseFromString('<div id="djm-sanitize-root">' + html + "</div>", "text/html");
10023
+ const root = doc.getElementById("djm-sanitize-root");
10024
+ if (!root) return "";
9587
10025
  cleanNode(root);
9588
10026
  return root.innerHTML;
9589
10027
  }
9590
10028
 
9591
10029
  // src/components/rich-editor/index.js
10030
+ var BLOCKS = [
10031
+ { value: "p", label: "paragraph" },
10032
+ { value: "h1", label: "heading1" },
10033
+ { value: "h2", label: "heading2" },
10034
+ { value: "h3", label: "heading3" },
10035
+ { value: "blockquote", label: "quote" },
10036
+ { value: "pre", label: "codeBlock" }
10037
+ ];
10038
+ var SIZES = [
10039
+ { value: "", label: "defaultSize" },
10040
+ { value: "12px", label: "12px" },
10041
+ { value: "14px", label: "14px" },
10042
+ { value: "16px", label: "16px" },
10043
+ { value: "18px", label: "18px" },
10044
+ { value: "24px", label: "24px" }
10045
+ ];
10046
+ var COLORS = ["#1f2d3d", "#5a6b7d", "#2b86d9", "#2fa36b", "#d97706", "#dc2626", "#7c3aed", "#ffffff"];
10047
+ var TOOLBAR_PRESETS = {
10048
+ simple: ["history", "inline", "list", "insert"],
10049
+ basic: ["history", "format", "inline", "align", "list", "insert", "view"],
10050
+ full: ["history", "format", "inline", "color", "align", "list", "insert", "view"]
10051
+ };
10052
+ function isSafeImageUrl(url) {
10053
+ const value = String(url || "").replace(/[\u0000-\u0020]+/g, "");
10054
+ if (!value) return false;
10055
+ const scheme = value.match(/^([a-z][a-z0-9+.-]*):/i);
10056
+ if (!scheme) return true;
10057
+ const name = scheme[1].toLowerCase();
10058
+ if (name === "http" || name === "https" || name === "blob") return true;
10059
+ return name === "data" && /^data:image\//i.test(value);
10060
+ }
10061
+ function isSafeLink(url) {
10062
+ const value = String(url || "").trim();
10063
+ if (!value) return false;
10064
+ const scheme = value.replace(/[\u0000-\u0020]+/g, "").match(/^([a-z][a-z0-9+.-]*):/i);
10065
+ if (!scheme) return true;
10066
+ return ["http", "https", "mailto", "tel"].indexOf(scheme[1].toLowerCase()) > -1;
10067
+ }
9592
10068
  var rich_editor_default = {
9593
10069
  name: "DjmRichEditor",
9594
- components: { Icon: icon_default },
10070
+ components: { Icon: icon_default, MediaPicker: media_picker_default },
9595
10071
  props: {
9596
10072
  modelValue: { type: String, default: "" },
9597
10073
  placeholder: { type: String, default: "" },
9598
10074
  minHeight: { type: Number, default: 200 },
9599
- // 开启后对外输出的 HTML 会走白名单清洗
9600
- sanitize: { type: Boolean, default: false },
9601
- disabled: { type: Boolean, default: false }
10075
+ // 默认开启:对外输出的 HTML 走白名单清洗,内容里不会带出脚本
10076
+ sanitize: { type: Boolean, default: true },
10077
+ disabled: { type: Boolean, default: false },
10078
+ // 工具条:simple / basic / full,或传分组数组(history / format / inline / color / align / list / insert / view)
10079
+ toolbar: { type: [String, Array], default: "full" },
10080
+ // 自定义上传:接收 File,返回图片地址(或 { url }),不传则转成 dataURL 本地预览
10081
+ uploadImage: { type: Function, default: null },
10082
+ // 已上传图片,提供后工具栏出现「从素材库选择」:字符串或 { url, name }
10083
+ media: { type: Array, default: () => [] },
10084
+ accept: { type: String, default: "image/*" },
10085
+ // 单张图片大小上限(MB)
10086
+ maxImageSize: { type: Number, default: 5 },
10087
+ // 是否允许一次选多张
10088
+ multiple: { type: Boolean, default: true },
10089
+ showCount: { type: Boolean, default: true }
9602
10090
  },
9603
- emits: ["update:modelValue"],
10091
+ emits: ["update:modelValue", "upload-error"],
9604
10092
  setup(props, { emit }) {
9605
- const editor = (0, import_vue32.ref)(null);
9606
- const sourceMode = (0, import_vue32.ref)(false);
9607
- const source = (0, import_vue32.ref)(props.modelValue);
9608
- const formats = (0, import_vue32.ref)({ bold: false, italic: false, underline: false, strike: false });
10093
+ const editor = (0, import_vue34.ref)(null);
10094
+ const fileInput = (0, import_vue34.ref)(null);
10095
+ const sourceMode = (0, import_vue34.ref)(false);
10096
+ const source = (0, import_vue34.ref)(props.modelValue);
10097
+ const fullscreen = (0, import_vue34.ref)(false);
10098
+ const panel = (0, import_vue34.ref)("");
10099
+ const uploadCount = (0, import_vue34.ref)(0);
10100
+ const textColor = (0, import_vue34.ref)(COLORS[0]);
10101
+ const bgColor = (0, import_vue34.ref)("#fdf3c4");
10102
+ const fontSize = (0, import_vue34.ref)("");
10103
+ const count2 = (0, import_vue34.ref)(0);
10104
+ const formats = (0, import_vue34.ref)({
10105
+ bold: false,
10106
+ italic: false,
10107
+ underline: false,
10108
+ strike: false,
10109
+ code: false,
10110
+ block: "p",
10111
+ align: "",
10112
+ list: ""
10113
+ });
10114
+ let savedRange = null;
10115
+ const ready = (0, import_vue34.computed)(() => !props.disabled && !sourceMode.value);
10116
+ const toolbarGroups = (0, import_vue34.computed)(() => {
10117
+ const list = Array.isArray(props.toolbar) ? props.toolbar : TOOLBAR_PRESETS[props.toolbar] || TOOLBAR_PRESETS.full;
10118
+ return new Set(list);
10119
+ });
10120
+ function has(group) {
10121
+ return toolbarGroups.value.has(group);
10122
+ }
10123
+ const mediaLibrary = (0, import_vue34.computed)(
10124
+ () => (props.media || []).map((item, index) => {
10125
+ if (typeof item === "string") {
10126
+ return { id: "media-" + index, url: item, name: "", type: "image" };
10127
+ }
10128
+ return {
10129
+ id: item && item.id !== void 0 ? String(item.id) : "media-" + index,
10130
+ url: item && (item.url || item.src) || "",
10131
+ name: item && (item.name || item.alt) || "",
10132
+ type: "image"
10133
+ };
10134
+ }).filter((item) => !!item.url)
10135
+ );
9609
10136
  function clean(html) {
9610
10137
  return props.sanitize ? sanitizeHtml(html) : html;
9611
10138
  }
10139
+ function plainText(html) {
10140
+ return String(html || "").replace(/<[^>]*>/g, "").replace(/&nbsp;/g, " ").replace(/&[a-z]+;/gi, " ");
10141
+ }
9612
10142
  function syncFromDom() {
9613
10143
  if (!editor.value) return;
9614
- emit("update:modelValue", clean(editor.value.innerHTML));
10144
+ const html = clean(editor.value.innerHTML);
10145
+ count2.value = plainText(html).trim().length;
10146
+ emit("update:modelValue", html);
9615
10147
  }
9616
- function onPaste(event) {
9617
- const data = event.clipboardData;
9618
- const html = data && data.getData("text/html");
9619
- if (!html) return;
9620
- event.preventDefault();
9621
- document.execCommand("insertHTML", false, sanitizeHtml(html));
10148
+ function currentRange() {
10149
+ const selection = window.getSelection();
10150
+ if (!selection || !selection.rangeCount || !editor.value) return null;
10151
+ const range = selection.getRangeAt(0);
10152
+ return editor.value.contains(range.commonAncestorContainer) ? range : null;
10153
+ }
10154
+ function rememberRange() {
10155
+ const range = currentRange();
10156
+ savedRange = range ? range.cloneRange() : null;
10157
+ }
10158
+ function focusAt(range) {
10159
+ if (!editor.value) return;
10160
+ editor.value.focus();
10161
+ const selection = window.getSelection();
10162
+ selection.removeAllRanges();
10163
+ if (range) {
10164
+ selection.addRange(range);
10165
+ return;
10166
+ }
10167
+ const end = document.createRange();
10168
+ end.selectNodeContents(editor.value);
10169
+ end.collapse(false);
10170
+ selection.addRange(end);
10171
+ }
10172
+ function insertNodeAt(range, node) {
10173
+ if (!editor.value) return;
10174
+ focusAt(range);
10175
+ const selection = window.getSelection();
10176
+ if (selection.rangeCount) selection.getRangeAt(0).insertNode(node);
10177
+ else editor.value.appendChild(node);
9622
10178
  syncFromDom();
10179
+ syncFormats();
10180
+ }
10181
+ function ensureRange() {
10182
+ const range = currentRange();
10183
+ if (range) return range;
10184
+ if (!savedRange) return null;
10185
+ focusAt(savedRange);
10186
+ return currentRange();
9623
10187
  }
9624
10188
  function exec(command, value = null) {
9625
- if (props.disabled || sourceMode.value) return;
10189
+ if (!ready.value) return;
10190
+ if (typeof document.execCommand !== "function") return;
10191
+ ensureRange();
10192
+ document.execCommand("styleWithCSS", false, true);
9626
10193
  document.execCommand(command, false, value);
9627
10194
  if (editor.value) editor.value.focus();
9628
10195
  syncFromDom();
9629
10196
  syncFormats();
9630
10197
  }
9631
- function formatBlock(tag) {
9632
- exec("formatBlock", tag);
10198
+ function setBlock(value) {
10199
+ panel.value = "";
10200
+ exec("formatBlock", "<" + value + ">");
10201
+ }
10202
+ function setFontSize(size) {
10203
+ panel.value = "";
10204
+ if (!ready.value || !editor.value) return;
10205
+ fontSize.value = size;
10206
+ const range = ensureRange();
10207
+ if (!range || range.collapsed) return;
10208
+ if (!size) {
10209
+ const walker = document.createTreeWalker(editor.value, NodeFilter.SHOW_ELEMENT);
10210
+ const targets = [];
10211
+ while (walker.nextNode()) {
10212
+ const el = walker.currentNode;
10213
+ if (el.style && el.style.fontSize && range.intersectsNode(el)) targets.push(el);
10214
+ }
10215
+ targets.forEach((el) => {
10216
+ el.style.fontSize = "";
10217
+ });
10218
+ syncFromDom();
10219
+ return;
10220
+ }
10221
+ const span = document.createElement("span");
10222
+ span.style.fontSize = size;
10223
+ span.appendChild(range.extractContents());
10224
+ range.insertNode(span);
10225
+ const selection = window.getSelection();
10226
+ const after = document.createRange();
10227
+ after.setStartAfter(span);
10228
+ after.collapse(true);
10229
+ selection.removeAllRanges();
10230
+ selection.addRange(after);
10231
+ syncFromDom();
10232
+ syncFormats();
10233
+ }
10234
+ function applyColor(kind, color) {
10235
+ panel.value = "";
10236
+ if (kind === "text") textColor.value = color;
10237
+ else bgColor.value = color;
10238
+ if (!ready.value) return;
10239
+ if (typeof document.execCommand !== "function") return;
10240
+ document.execCommand("styleWithCSS", false, true);
10241
+ const command = kind === "text" ? "foreColor" : "hiliteColor";
10242
+ if (!document.execCommand(command, false, color) && kind === "bg") {
10243
+ document.execCommand("backColor", false, color);
10244
+ }
10245
+ if (editor.value) editor.value.focus();
10246
+ syncFromDom();
10247
+ syncFormats();
10248
+ }
10249
+ function togglePanel(name) {
10250
+ if (!ready.value) return;
10251
+ panel.value = panel.value === name ? "" : name;
10252
+ }
10253
+ function toggleInlineCode() {
10254
+ if (!ready.value || !editor.value) return;
10255
+ const range = currentRange();
10256
+ if (!range) return;
10257
+ const anchor = range.commonAncestorContainer;
10258
+ const node = anchor.nodeType === 1 ? anchor : anchor.parentElement;
10259
+ const code = node && node.closest ? node.closest("code") : null;
10260
+ if (code && editor.value.contains(code)) {
10261
+ const parent = code.parentNode;
10262
+ while (code.firstChild) parent.insertBefore(code.firstChild, code);
10263
+ parent.removeChild(code);
10264
+ syncFromDom();
10265
+ return;
10266
+ }
10267
+ if (range.collapsed) return;
10268
+ const wrapper = document.createElement("code");
10269
+ wrapper.appendChild(range.extractContents());
10270
+ range.insertNode(wrapper);
10271
+ const selection = window.getSelection();
10272
+ const after = document.createRange();
10273
+ after.setStartAfter(wrapper);
10274
+ after.collapse(true);
10275
+ selection.removeAllRanges();
10276
+ selection.addRange(after);
10277
+ syncFromDom();
10278
+ syncFormats();
9633
10279
  }
9634
10280
  function addLink() {
10281
+ if (!ready.value) return;
9635
10282
  const url = window.prompt(t("richEditor.linkPrompt"), "https://");
9636
- if (url) exec("createLink", url);
10283
+ if (!url) return;
10284
+ if (!isSafeLink(url)) {
10285
+ window.alert(t("richEditor.linkInvalid"));
10286
+ return;
10287
+ }
10288
+ const range = currentRange();
10289
+ if (range && range.collapsed) {
10290
+ const link = document.createElement("a");
10291
+ link.href = url;
10292
+ link.target = "_blank";
10293
+ link.rel = "noopener noreferrer";
10294
+ link.textContent = url;
10295
+ insertNodeAt(range, link);
10296
+ return;
10297
+ }
10298
+ exec("createLink", url);
10299
+ if (editor.value) {
10300
+ editor.value.querySelectorAll("a[href]").forEach((link) => {
10301
+ if (!link.getAttribute("target")) link.setAttribute("target", "_blank");
10302
+ link.setAttribute("rel", "noopener noreferrer");
10303
+ });
10304
+ }
10305
+ syncFromDom();
10306
+ }
10307
+ function readAsDataUrl(file) {
10308
+ return new Promise((resolve, reject) => {
10309
+ const reader = new FileReader();
10310
+ reader.onload = () => resolve(reader.result);
10311
+ reader.onerror = () => reject(reader.error || new Error("read failed"));
10312
+ reader.readAsDataURL(file);
10313
+ });
10314
+ }
10315
+ async function uploadOne(file) {
10316
+ if (props.uploadImage) {
10317
+ const result = await props.uploadImage(file);
10318
+ const url = typeof result === "string" ? result : result && result.url;
10319
+ if (!url) throw new Error(t("richEditor.imageUrlInvalid"));
10320
+ if (!isSafeImageUrl(url)) throw new Error(t("richEditor.imageUrlInvalid"));
10321
+ return String(url).trim();
10322
+ }
10323
+ return readAsDataUrl(file);
10324
+ }
10325
+ function isImage(file) {
10326
+ return file && /^image\//.test(file.type);
10327
+ }
10328
+ function pickImage(allowMultiple) {
10329
+ if (!ready.value || !fileInput.value) return;
10330
+ rememberRange();
10331
+ fileInput.value.multiple = !!allowMultiple && props.multiple;
10332
+ fileInput.value.click();
10333
+ }
10334
+ function insertMedia(ids) {
10335
+ if (!ready.value) return;
10336
+ const picked = (Array.isArray(ids) ? ids : [ids]).map((id) => mediaLibrary.value.find((item) => item.id === String(id))).filter(Boolean);
10337
+ const safe = picked.filter((item) => {
10338
+ if (isSafeImageUrl(item.url)) return true;
10339
+ emit("upload-error", { file: null, message: t("richEditor.imageUrlInvalid") });
10340
+ return false;
10341
+ });
10342
+ if (!safe.length) return;
10343
+ focusAt(savedRange);
10344
+ const fragment = document.createDocumentFragment();
10345
+ safe.forEach((item) => {
10346
+ const img = document.createElement("img");
10347
+ img.src = item.url;
10348
+ img.alt = item.name || "image";
10349
+ img.className = "djm-rich-editor-img";
10350
+ fragment.appendChild(img);
10351
+ });
10352
+ const selection = window.getSelection();
10353
+ if (selection.rangeCount) selection.getRangeAt(0).insertNode(fragment);
10354
+ else editor.value.appendChild(fragment);
10355
+ syncFromDom();
10356
+ syncFormats();
10357
+ }
10358
+ function insertImages(files) {
10359
+ if (!files.length || !editor.value) return;
10360
+ uploadCount.value = files.length;
10361
+ const holder = document.createElement("span");
10362
+ holder.className = "djm-rich-editor-uploading";
10363
+ holder.textContent = t("richEditor.uploading", { count: files.length });
10364
+ const anchor = savedRange && editor.value.contains(savedRange.commonAncestorContainer) ? savedRange : null;
10365
+ focusAt(anchor);
10366
+ const selection = window.getSelection();
10367
+ if (selection.rangeCount) selection.getRangeAt(0).insertNode(holder);
10368
+ else editor.value.appendChild(holder);
10369
+ Promise.all(files.map(async (file) => {
10370
+ if (!isImage(file)) return { file, error: t("richEditor.imageTypeError") };
10371
+ if (props.maxImageSize > 0 && file.size > props.maxImageSize * 1024 * 1024) {
10372
+ return { file, error: t("richEditor.imageSizeError", { size: props.maxImageSize }) };
10373
+ }
10374
+ try {
10375
+ return { file, url: await uploadOne(file) };
10376
+ } catch (error) {
10377
+ return { file, error: error && error.message || t("richEditor.uploadFailed") };
10378
+ }
10379
+ })).then((results) => {
10380
+ uploadCount.value = 0;
10381
+ const done = results.filter((item) => item.url);
10382
+ const failed = results.filter((item) => item.error);
10383
+ const alive = editor.value && editor.value.contains(holder);
10384
+ if (done.length && editor.value) {
10385
+ done.forEach((item) => {
10386
+ const img = document.createElement("img");
10387
+ img.src = item.url;
10388
+ img.alt = item.file.name || "image";
10389
+ img.className = "djm-rich-editor-img";
10390
+ if (alive) holder.parentNode.insertBefore(img, holder);
10391
+ else editor.value.appendChild(img);
10392
+ });
10393
+ }
10394
+ if (alive) holder.remove();
10395
+ failed.forEach((item) => emit("upload-error", { file: item.file, message: item.error }));
10396
+ syncFromDom();
10397
+ });
10398
+ }
10399
+ function onFilesChange(event) {
10400
+ const files = Array.from(event.target.files || []);
10401
+ event.target.value = "";
10402
+ insertImages(files);
10403
+ }
10404
+ function onPaste(event) {
10405
+ const data = event.clipboardData;
10406
+ if (!data) return;
10407
+ const images = Array.from(data.files || []).filter(isImage);
10408
+ if (images.length) {
10409
+ event.preventDefault();
10410
+ insertImages(images);
10411
+ return;
10412
+ }
10413
+ const html = data.getData("text/html");
10414
+ if (!html) return;
10415
+ event.preventDefault();
10416
+ document.execCommand("insertHTML", false, sanitizeHtml(html));
10417
+ syncFromDom();
10418
+ }
10419
+ function onDragOver(event) {
10420
+ if (!ready.value) return;
10421
+ if (event.dataTransfer && Array.from(event.dataTransfer.types || []).includes("Files")) {
10422
+ event.preventDefault();
10423
+ }
10424
+ }
10425
+ function onDrop(event) {
10426
+ if (!ready.value) return;
10427
+ const files = Array.from(event.dataTransfer && event.dataTransfer.files || []).filter(isImage);
10428
+ if (!files.length) return;
10429
+ event.preventDefault();
10430
+ rememberRange();
10431
+ insertImages(files);
10432
+ }
10433
+ function closestTag(node, tag) {
10434
+ const el = node && (node.nodeType === 1 ? node : node.parentElement);
10435
+ return el && el.closest ? el.closest(tag) : null;
10436
+ }
10437
+ function detectBlock() {
10438
+ const selection = window.getSelection();
10439
+ if (!selection || !selection.anchorNode) return "p";
10440
+ let node = selection.anchorNode;
10441
+ if (node.nodeType !== 1) node = node.parentElement;
10442
+ while (node && node !== editor.value) {
10443
+ const tag = node.tagName.toLowerCase();
10444
+ if (["p", "h1", "h2", "h3", "blockquote", "pre"].includes(tag)) return tag;
10445
+ node = node.parentElement;
10446
+ }
10447
+ return "p";
9637
10448
  }
9638
10449
  function syncFormats() {
9639
- if (props.disabled || sourceMode.value) return;
9640
- if (!editor.value || !editor.value.contains(document.activeElement)) return;
10450
+ if (props.disabled || sourceMode.value || !editor.value) return;
10451
+ if (!editor.value.contains(document.activeElement)) return;
10452
+ const selection = window.getSelection();
9641
10453
  formats.value = {
9642
10454
  bold: document.queryCommandState("bold"),
9643
10455
  italic: document.queryCommandState("italic"),
9644
10456
  underline: document.queryCommandState("underline"),
9645
- strike: document.queryCommandState("strikeThrough")
10457
+ strike: document.queryCommandState("strikeThrough"),
10458
+ code: !!closestTag(selection.anchorNode, "code"),
10459
+ block: detectBlock(),
10460
+ align: document.queryCommandState("justifyCenter") ? "center" : document.queryCommandState("justifyRight") ? "right" : document.queryCommandState("justifyFull") ? "justify" : "left",
10461
+ list: document.queryCommandState("insertOrderedList") ? "ol" : document.queryCommandState("insertUnorderedList") ? "ul" : ""
9646
10462
  };
9647
10463
  }
9648
10464
  function onSourceInput() {
10465
+ count2.value = plainText(source.value).trim().length;
9649
10466
  emit("update:modelValue", clean(source.value));
9650
10467
  }
9651
10468
  function toggleSource() {
9652
10469
  if (props.disabled) return;
10470
+ panel.value = "";
9653
10471
  if (sourceMode.value) {
9654
10472
  emit("update:modelValue", clean(source.value));
9655
10473
  sourceMode.value = false;
9656
10474
  requestAnimationFrame(() => {
9657
10475
  if (editor.value) editor.value.innerHTML = clean(source.value);
10476
+ syncFromDom();
9658
10477
  });
9659
10478
  } else {
9660
10479
  source.value = editor.value ? editor.value.innerHTML : props.modelValue;
9661
10480
  sourceMode.value = true;
9662
10481
  }
9663
10482
  }
9664
- (0, import_vue32.watch)(
10483
+ function toggleFullscreen() {
10484
+ if (props.disabled) return;
10485
+ fullscreen.value = !fullscreen.value;
10486
+ panel.value = "";
10487
+ }
10488
+ function onDocumentClick(event) {
10489
+ if (!panel.value) return;
10490
+ if (!(event.target.closest && event.target.closest(".djm-rich-editor-color"))) panel.value = "";
10491
+ }
10492
+ function onKeydown(event) {
10493
+ if (event.key === "Escape" && fullscreen.value) {
10494
+ fullscreen.value = false;
10495
+ panel.value = "";
10496
+ }
10497
+ }
10498
+ (0, import_vue34.watch)(
9665
10499
  () => props.modelValue,
9666
10500
  (value) => {
9667
10501
  if (sourceMode.value) {
@@ -9670,40 +10504,117 @@ var rich_editor_default = {
9670
10504
  }
9671
10505
  const next = clean(value);
9672
10506
  if (editor.value && editor.value.innerHTML !== next) editor.value.innerHTML = next;
10507
+ count2.value = plainText(next).trim().length;
9673
10508
  }
9674
10509
  );
9675
- (0, import_vue32.onMounted)(() => {
10510
+ (0, import_vue34.onMounted)(() => {
9676
10511
  if (editor.value) editor.value.innerHTML = clean(props.modelValue);
10512
+ count2.value = plainText(props.modelValue).trim().length;
9677
10513
  document.addEventListener("selectionchange", syncFormats);
10514
+ document.addEventListener("click", onDocumentClick);
10515
+ document.addEventListener("keydown", onKeydown);
10516
+ });
10517
+ (0, import_vue34.onBeforeUnmount)(() => {
10518
+ document.removeEventListener("selectionchange", syncFormats);
10519
+ document.removeEventListener("click", onDocumentClick);
10520
+ document.removeEventListener("keydown", onKeydown);
9678
10521
  });
9679
- (0, import_vue32.onBeforeUnmount)(() => document.removeEventListener("selectionchange", syncFormats));
9680
10522
  return {
9681
10523
  editor,
10524
+ fileInput,
9682
10525
  sourceMode,
9683
10526
  source,
10527
+ fullscreen,
10528
+ panel,
10529
+ uploadCount,
10530
+ textColor,
10531
+ bgColor,
10532
+ fontSize,
10533
+ count: count2,
9684
10534
  formats,
10535
+ blocks: BLOCKS,
10536
+ sizes: SIZES,
10537
+ colors: COLORS,
10538
+ mediaLibrary,
10539
+ has,
9685
10540
  exec,
9686
- formatBlock,
10541
+ setBlock,
10542
+ setFontSize,
10543
+ applyColor,
10544
+ togglePanel,
10545
+ toggleInlineCode,
9687
10546
  addLink,
9688
- onSourceInput,
10547
+ pickImage,
10548
+ insertMedia,
10549
+ onFilesChange,
9689
10550
  onPaste,
10551
+ onDragOver,
10552
+ onDrop,
10553
+ rememberRange,
10554
+ onSourceInput,
9690
10555
  toggleSource,
10556
+ toggleFullscreen,
9691
10557
  syncFromDom,
9692
10558
  syncFormats,
9693
10559
  t
9694
10560
  };
9695
10561
  },
9696
10562
  template: `
9697
- <div class="djm-rich-editor" :class="{ 'djm-is-disabled': disabled }">
9698
- <div class="djm-rich-editor-toolbar">
9699
- <div class="djm-rich-editor-group">
10563
+ <div
10564
+ class="djm-rich-editor"
10565
+ :class="{ 'djm-is-disabled': disabled, 'djm-is-fullscreen': fullscreen }"
10566
+ >
10567
+ <div class="djm-rich-editor-toolbar" role="toolbar" :aria-label="t('richEditor.toolbar')" @mousedown="rememberRange">
10568
+ <div class="djm-rich-editor-group" v-if="has('history')">
10569
+ <button
10570
+ class="djm-rich-editor-btn"
10571
+ type="button"
10572
+ :title="t('richEditor.undo')"
10573
+ :aria-label="t('richEditor.undo')"
10574
+ :disabled="disabled || sourceMode"
10575
+ @mousedown.prevent
10576
+ @click="exec('undo')"
10577
+ ><Icon name="undo" :size="13" /></button>
10578
+ <button
10579
+ class="djm-rich-editor-btn"
10580
+ type="button"
10581
+ :title="t('richEditor.redo')"
10582
+ :aria-label="t('richEditor.redo')"
10583
+ :disabled="disabled || sourceMode"
10584
+ @mousedown.prevent
10585
+ @click="exec('redo')"
10586
+ ><Icon name="redo" :size="13" /></button>
10587
+ </div>
10588
+
10589
+ <div class="djm-rich-editor-group" v-if="has('format')">
10590
+ <select
10591
+ class="djm-rich-editor-select"
10592
+ :value="formats.block"
10593
+ :aria-label="t('richEditor.block')"
10594
+ :disabled="disabled || sourceMode"
10595
+ @change="setBlock($event.target.value)"
10596
+ >
10597
+ <option v-for="item in blocks" :key="item.value" :value="item.value">{{ t('richEditor.' + item.label) }}</option>
10598
+ </select>
10599
+ <select
10600
+ class="djm-rich-editor-select djm-rich-editor-select-size"
10601
+ :value="fontSize"
10602
+ :aria-label="t('richEditor.fontSize')"
10603
+ :disabled="disabled || sourceMode"
10604
+ @change="setFontSize($event.target.value)"
10605
+ >
10606
+ <option v-for="item in sizes" :key="item.value" :value="item.value">{{ t('richEditor.' + item.label) }}</option>
10607
+ </select>
10608
+ </div>
10609
+
10610
+ <div class="djm-rich-editor-group" v-if="has('inline')">
9700
10611
  <button
9701
10612
  class="djm-rich-editor-btn djm-rich-editor-btn-bold"
9702
10613
  type="button"
9703
10614
  :title="t('richEditor.bold')"
9704
10615
  :aria-label="t('richEditor.bold')"
9705
10616
  :aria-pressed="String(formats.bold)"
9706
- :disabled="disabled"
10617
+ :disabled="disabled || sourceMode"
9707
10618
  @mousedown.prevent
9708
10619
  @click="exec('bold')"
9709
10620
  >B</button>
@@ -9713,7 +10624,7 @@ var rich_editor_default = {
9713
10624
  :title="t('richEditor.italic')"
9714
10625
  :aria-label="t('richEditor.italic')"
9715
10626
  :aria-pressed="String(formats.italic)"
9716
- :disabled="disabled"
10627
+ :disabled="disabled || sourceMode"
9717
10628
  @mousedown.prevent
9718
10629
  @click="exec('italic')"
9719
10630
  >I</button>
@@ -9723,7 +10634,7 @@ var rich_editor_default = {
9723
10634
  :title="t('richEditor.underline')"
9724
10635
  :aria-label="t('richEditor.underline')"
9725
10636
  :aria-pressed="String(formats.underline)"
9726
- :disabled="disabled"
10637
+ :disabled="disabled || sourceMode"
9727
10638
  @mousedown.prevent
9728
10639
  @click="exec('underline')"
9729
10640
  >U</button>
@@ -9733,46 +10644,130 @@ var rich_editor_default = {
9733
10644
  :title="t('richEditor.strike')"
9734
10645
  :aria-label="t('richEditor.strike')"
9735
10646
  :aria-pressed="String(formats.strike)"
9736
- :disabled="disabled"
10647
+ :disabled="disabled || sourceMode"
9737
10648
  @mousedown.prevent
9738
10649
  @click="exec('strikeThrough')"
9739
10650
  >S</button>
10651
+ <button
10652
+ class="djm-rich-editor-btn"
10653
+ type="button"
10654
+ :title="t('richEditor.inlineCode')"
10655
+ :aria-label="t('richEditor.inlineCode')"
10656
+ :aria-pressed="String(formats.code)"
10657
+ :disabled="disabled || sourceMode"
10658
+ @mousedown.prevent
10659
+ @click="toggleInlineCode"
10660
+ ><Icon name="code" :size="13" /></button>
9740
10661
  </div>
9741
10662
 
9742
- <div class="djm-rich-editor-group">
9743
- <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.heading')" :disabled="disabled" @mousedown.prevent @click="formatBlock('h2')">H2</button>
9744
- <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.paragraph')" :disabled="disabled" @mousedown.prevent @click="formatBlock('p')">{{ t('richEditor.paragraph') }}</button>
9745
- </div>
9746
-
9747
- <div class="djm-rich-editor-group">
9748
- <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.bulletList')" :disabled="disabled" @mousedown.prevent @click="exec('insertUnorderedList')">
9749
- <span class="djm-rich-editor-glyph">\u2022 \u2261</span>
9750
- </button>
9751
- <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.numberList')" :disabled="disabled" @mousedown.prevent @click="exec('insertOrderedList')">
9752
- <span class="djm-rich-editor-glyph">1. \u2261</span>
10663
+ <div class="djm-rich-editor-group djm-rich-editor-color" v-if="has('color')">
10664
+ <button
10665
+ class="djm-rich-editor-btn"
10666
+ type="button"
10667
+ :title="t('richEditor.textColor')"
10668
+ :aria-label="t('richEditor.textColor')"
10669
+ :aria-expanded="String(panel === 'text')"
10670
+ :disabled="disabled || sourceMode"
10671
+ @mousedown.prevent
10672
+ @click.stop="togglePanel('text')"
10673
+ >
10674
+ <span class="djm-rich-editor-letter" :style="{ borderBottomColor: textColor }">A</span>
9753
10675
  </button>
9754
- <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.link')" :aria-label="t('richEditor.link')" :disabled="disabled" @mousedown.prevent @click="addLink">
9755
- <Icon name="link" :size="13" />
10676
+ <button
10677
+ class="djm-rich-editor-btn"
10678
+ type="button"
10679
+ :title="t('richEditor.bgColor')"
10680
+ :aria-label="t('richEditor.bgColor')"
10681
+ :aria-expanded="String(panel === 'bg')"
10682
+ :disabled="disabled || sourceMode"
10683
+ @mousedown.prevent
10684
+ @click.stop="togglePanel('bg')"
10685
+ >
10686
+ <span class="djm-rich-editor-letter djm-rich-editor-letter-bg" :style="{ background: bgColor }">A</span>
9756
10687
  </button>
10688
+ <div v-if="panel === 'text' || panel === 'bg'" class="djm-rich-editor-panel" role="group" :aria-label="t('richEditor.textColor')">
10689
+ <button
10690
+ v-for="color in colors"
10691
+ :key="color"
10692
+ class="djm-rich-editor-swatch"
10693
+ type="button"
10694
+ :title="color"
10695
+ :aria-label="color"
10696
+ :style="{ background: color }"
10697
+ @mousedown.prevent
10698
+ @click="applyColor(panel, color)"
10699
+ ></button>
10700
+ </div>
9757
10701
  </div>
9758
10702
 
9759
- <div class="djm-rich-editor-group">
9760
- <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.clearFormat')" :disabled="disabled" @mousedown.prevent @click="exec('removeFormat')">{{ t('richEditor.clearFormat') }}</button>
9761
- <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.undo')" :aria-label="t('richEditor.undo')" :disabled="disabled" @mousedown.prevent @click="exec('undo')">\u21B6</button>
9762
- <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.redo')" :aria-label="t('richEditor.redo')" :disabled="disabled" @mousedown.prevent @click="exec('redo')">\u21B7</button>
10703
+ <div class="djm-rich-editor-group" v-if="has('align')">
10704
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.alignLeft')" :aria-label="t('richEditor.alignLeft')" :aria-pressed="String(formats.align === 'left')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('justifyLeft')"><Icon name="align-left" :size="13" /></button>
10705
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.alignCenter')" :aria-label="t('richEditor.alignCenter')" :aria-pressed="String(formats.align === 'center')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('justifyCenter')"><Icon name="align-center" :size="13" /></button>
10706
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.alignRight')" :aria-label="t('richEditor.alignRight')" :aria-pressed="String(formats.align === 'right')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('justifyRight')"><Icon name="align-right" :size="13" /></button>
10707
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.alignJustify')" :aria-label="t('richEditor.alignJustify')" :aria-pressed="String(formats.align === 'justify')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('justifyFull')"><Icon name="align-justify" :size="13" /></button>
9763
10708
  </div>
9764
10709
 
9765
- <div class="djm-rich-editor-spacer"></div>
9766
- <button
9767
- class="djm-rich-editor-btn"
9768
- :class="{ 'djm-is-active': sourceMode }"
9769
- type="button"
9770
- :aria-pressed="String(sourceMode)"
9771
- :disabled="disabled"
9772
- @click="toggleSource"
9773
- >
9774
- <Icon name="code" :size="13" />{{ sourceMode ? t('richEditor.visual') : t('richEditor.source') }}
9775
- </button>
10710
+ <div class="djm-rich-editor-group" v-if="has('list')">
10711
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.bulletList')" :aria-label="t('richEditor.bulletList')" :aria-pressed="String(formats.list === 'ul')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('insertUnorderedList')"><Icon name="list" :size="13" /></button>
10712
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.numberList')" :aria-label="t('richEditor.numberList')" :aria-pressed="String(formats.list === 'ol')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('insertOrderedList')"><Icon name="list-ordered" :size="13" /></button>
10713
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.outdent')" :aria-label="t('richEditor.outdent')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('outdent')"><Icon name="outdent" :size="13" /></button>
10714
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.indent')" :aria-label="t('richEditor.indent')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('indent')"><Icon name="indent" :size="13" /></button>
10715
+ </div>
10716
+
10717
+ <div class="djm-rich-editor-group" v-if="has('insert')">
10718
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.link')" :aria-label="t('richEditor.link')" :disabled="disabled || sourceMode" @mousedown.prevent @click="addLink"><Icon name="link" :size="13" /></button>
10719
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.unlink')" :aria-label="t('richEditor.unlink')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('unlink')"><Icon name="unlink" :size="13" /></button>
10720
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.singleImage')" :aria-label="t('richEditor.singleImage')" :disabled="disabled || sourceMode" @mousedown.prevent @click="pickImage(false)"><Icon name="image" :size="13" /></button>
10721
+ <button v-if="multiple" class="djm-rich-editor-btn" type="button" :title="t('richEditor.multiImage')" :aria-label="t('richEditor.multiImage')" :disabled="disabled || sourceMode" @mousedown.prevent @click="pickImage(true)"><Icon name="images" :size="13" /></button>
10722
+ <MediaPicker
10723
+ v-if="mediaLibrary.length"
10724
+ class="djm-rich-editor-picker"
10725
+ multiple
10726
+ accept="image"
10727
+ :items="mediaLibrary"
10728
+ :title="t('richEditor.mediaLibrary')"
10729
+ :disabled="disabled || sourceMode"
10730
+ @change="insertMedia"
10731
+ >
10732
+ <template #trigger="{ open }">
10733
+ <button
10734
+ class="djm-rich-editor-btn"
10735
+ type="button"
10736
+ :title="t('richEditor.mediaLibrary')"
10737
+ :aria-label="t('richEditor.mediaLibrary')"
10738
+ :disabled="disabled || sourceMode"
10739
+ @mousedown.prevent="rememberRange"
10740
+ @click="open"
10741
+ ><Icon name="grid" :size="13" /></button>
10742
+ </template>
10743
+ </MediaPicker>
10744
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.hr')" :aria-label="t('richEditor.hr')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('insertHorizontalRule')">\u2014</button>
10745
+ <button class="djm-rich-editor-btn" type="button" :title="t('richEditor.clearFormat')" :aria-label="t('richEditor.clearFormat')" :disabled="disabled || sourceMode" @mousedown.prevent @click="exec('removeFormat')"><span class="djm-rich-editor-glyph">T\xD7</span></button>
10746
+ </div>
10747
+
10748
+ <div class="djm-rich-editor-spacer" v-if="has('view')"></div>
10749
+ <div class="djm-rich-editor-group djm-rich-editor-group-end" v-if="has('view')">
10750
+ <button
10751
+ class="djm-rich-editor-btn"
10752
+ :class="{ 'djm-is-active': sourceMode }"
10753
+ type="button"
10754
+ :title="sourceMode ? t('richEditor.visual') : t('richEditor.source')"
10755
+ :aria-label="sourceMode ? t('richEditor.visual') : t('richEditor.source')"
10756
+ :aria-pressed="String(sourceMode)"
10757
+ :disabled="disabled"
10758
+ @click="toggleSource"
10759
+ ><Icon name="code" :size="13" /></button>
10760
+ <button
10761
+ class="djm-rich-editor-btn"
10762
+ :class="{ 'djm-is-active': fullscreen }"
10763
+ type="button"
10764
+ :title="fullscreen ? t('richEditor.exitFullscreen') : t('richEditor.fullscreen')"
10765
+ :aria-label="fullscreen ? t('richEditor.exitFullscreen') : t('richEditor.fullscreen')"
10766
+ :aria-pressed="String(fullscreen)"
10767
+ :disabled="disabled"
10768
+ @click="toggleFullscreen"
10769
+ ><Icon :name="fullscreen ? 'minimize' : 'maximize'" :size="13" /></button>
10770
+ </div>
9776
10771
  </div>
9777
10772
 
9778
10773
  <div
@@ -9788,6 +10783,8 @@ var rich_editor_default = {
9788
10783
  :style="{ minHeight: minHeight + 'px' }"
9789
10784
  @input="syncFromDom"
9790
10785
  @paste="onPaste"
10786
+ @dragover="onDragOver"
10787
+ @drop="onDrop"
9791
10788
  ></div>
9792
10789
 
9793
10790
  <textarea
@@ -9800,12 +10797,27 @@ var rich_editor_default = {
9800
10797
  spellcheck="false"
9801
10798
  @input="onSourceInput"
9802
10799
  ></textarea>
10800
+
10801
+ <div v-if="showCount" class="djm-rich-editor-foot">
10802
+ <span v-if="uploadCount" class="djm-rich-editor-foot-item">{{ t('richEditor.uploading', { count: uploadCount }) }}</span>
10803
+ <span class="djm-rich-editor-foot-item">{{ t('richEditor.wordCount', { count }) }}</span>
10804
+ </div>
10805
+
10806
+ <input
10807
+ ref="fileInput"
10808
+ class="djm-rich-editor-file"
10809
+ type="file"
10810
+ :accept="accept"
10811
+ tabindex="-1"
10812
+ aria-hidden="true"
10813
+ @change="onFilesChange"
10814
+ />
9803
10815
  </div>
9804
10816
  `
9805
10817
  };
9806
10818
 
9807
10819
  // src/components/floating-window/index.js
9808
- var import_vue33 = require("vue");
10820
+ var import_vue35 = require("vue");
9809
10821
  function clamp(value, min, max) {
9810
10822
  return Math.min(Math.max(value, min), Math.max(min, max));
9811
10823
  }
@@ -9823,12 +10835,12 @@ var floating_window_default = {
9823
10835
  },
9824
10836
  emits: ["close", "focus"],
9825
10837
  setup(props, { emit }) {
9826
- const root = (0, import_vue33.ref)(null);
9827
- const pos = (0, import_vue33.ref)({ x: props.initialX, y: props.initialY });
9828
- const size = (0, import_vue33.ref)({ w: props.width, h: props.height });
9829
- const minimized = (0, import_vue33.ref)(false);
9830
- const maximized = (0, import_vue33.ref)(false);
9831
- const saved = (0, import_vue33.ref)(null);
10838
+ const root = (0, import_vue35.ref)(null);
10839
+ const pos = (0, import_vue35.ref)({ x: props.initialX, y: props.initialY });
10840
+ const size = (0, import_vue35.ref)({ w: props.width, h: props.height });
10841
+ const minimized = (0, import_vue35.ref)(false);
10842
+ const maximized = (0, import_vue35.ref)(false);
10843
+ const saved = (0, import_vue35.ref)(null);
9832
10844
  let drag = null;
9833
10845
  let resize = null;
9834
10846
  function stage() {
@@ -9916,7 +10928,7 @@ var floating_window_default = {
9916
10928
  }
9917
10929
  emit("focus");
9918
10930
  }
9919
- (0, import_vue33.onBeforeUnmount)(() => {
10931
+ (0, import_vue35.onBeforeUnmount)(() => {
9920
10932
  window.removeEventListener("pointermove", onDrag);
9921
10933
  window.removeEventListener("pointerup", endDrag);
9922
10934
  window.removeEventListener("pointermove", onResize);
@@ -9964,7 +10976,7 @@ var floating_window_default = {
9964
10976
  };
9965
10977
 
9966
10978
  // src/components/upload/index.js
9967
- var import_vue34 = require("vue");
10979
+ var import_vue36 = require("vue");
9968
10980
  var uidSeed6 = 0;
9969
10981
  function extension(name) {
9970
10982
  const index = name.lastIndexOf(".");
@@ -10014,11 +11026,11 @@ var upload_default = {
10014
11026
  },
10015
11027
  emits: ["update:modelValue", "change", "success", "error", "remove", "exceed"],
10016
11028
  setup(props, { emit }) {
10017
- const files = (0, import_vue34.ref)([]);
10018
- const dragActive = (0, import_vue34.ref)(false);
10019
- const inputRef = (0, import_vue34.ref)(null);
11029
+ const files = (0, import_vue36.ref)([]);
11030
+ const dragActive = (0, import_vue36.ref)(false);
11031
+ const inputRef = (0, import_vue36.ref)(null);
10020
11032
  const tasks = /* @__PURE__ */ new Map();
10021
- (0, import_vue34.watch)(
11033
+ (0, import_vue36.watch)(
10022
11034
  () => props.modelValue,
10023
11035
  (list) => {
10024
11036
  const next = list || [];
@@ -10112,7 +11124,7 @@ var upload_default = {
10112
11124
  if (pass === false) continue;
10113
11125
  }
10114
11126
  uidSeed6 += 1;
10115
- const item = (0, import_vue34.reactive)({
11127
+ const item = (0, import_vue36.reactive)({
10116
11128
  uid: uidSeed6,
10117
11129
  name: raw.name,
10118
11130
  size: raw.size,
@@ -10172,7 +11184,7 @@ var upload_default = {
10172
11184
  files.value = [];
10173
11185
  emitList();
10174
11186
  }
10175
- (0, import_vue34.onBeforeUnmount)(() => {
11187
+ (0, import_vue36.onBeforeUnmount)(() => {
10176
11188
  files.value.forEach((item) => {
10177
11189
  if (item.url) URL.revokeObjectURL(item.url);
10178
11190
  });
@@ -10320,7 +11332,7 @@ var upload_default = {
10320
11332
  };
10321
11333
 
10322
11334
  // src/components/tree/index.js
10323
- var import_vue35 = require("vue");
11335
+ var import_vue37 = require("vue");
10324
11336
  var tree_default = {
10325
11337
  name: "DjmTree",
10326
11338
  components: { Icon: icon_default },
@@ -10352,17 +11364,17 @@ var tree_default = {
10352
11364
  },
10353
11365
  emits: ["update:checked", "update:expanded", "node-click", "check", "node-drop", "load-error"],
10354
11366
  setup(props, { emit }) {
10355
- const lazyChildren = (0, import_vue35.ref)({});
10356
- const loadingKeys = (0, import_vue35.ref)([]);
10357
- const innerExpanded = (0, import_vue35.ref)([...props.expanded]);
10358
- const innerChecked = (0, import_vue35.ref)([...props.checked]);
10359
- (0, import_vue35.watch)(
11367
+ const lazyChildren = (0, import_vue37.ref)({});
11368
+ const loadingKeys = (0, import_vue37.ref)([]);
11369
+ const innerExpanded = (0, import_vue37.ref)([...props.expanded]);
11370
+ const innerChecked = (0, import_vue37.ref)([...props.checked]);
11371
+ (0, import_vue37.watch)(
10360
11372
  () => props.expanded,
10361
11373
  (value) => {
10362
11374
  if (Array.isArray(value)) innerExpanded.value = value;
10363
11375
  }
10364
11376
  );
10365
- (0, import_vue35.watch)(
11377
+ (0, import_vue37.watch)(
10366
11378
  () => props.checked,
10367
11379
  (value) => {
10368
11380
  if (Array.isArray(value)) innerChecked.value = value;
@@ -10400,7 +11412,7 @@ var tree_default = {
10400
11412
  });
10401
11413
  return out;
10402
11414
  }
10403
- (0, import_vue35.watch)(
11415
+ (0, import_vue37.watch)(
10404
11416
  () => props.data,
10405
11417
  () => {
10406
11418
  if (props.defaultExpandAll) innerExpanded.value = collectExpandable(props.data);
@@ -10417,7 +11429,7 @@ var tree_default = {
10417
11429
  const children = childrenOf(node);
10418
11430
  return Boolean(children && children.some((child) => matchSubtree(child)));
10419
11431
  }
10420
- const rows = (0, import_vue35.computed)(() => {
11432
+ const rows = (0, import_vue37.computed)(() => {
10421
11433
  const result = [];
10422
11434
  const walk = (nodes, level) => {
10423
11435
  nodes.forEach((node) => {
@@ -10488,8 +11500,8 @@ var tree_default = {
10488
11500
  function isActive(node) {
10489
11501
  return props.activeKey !== "" && node[props.nodeKey] === props.activeKey;
10490
11502
  }
10491
- const rootEl = (0, import_vue35.ref)(null);
10492
- const focusIndex = (0, import_vue35.ref)(-1);
11503
+ const rootEl = (0, import_vue37.ref)(null);
11504
+ const focusIndex = (0, import_vue37.ref)(-1);
10493
11505
  function tabIndexOf(index) {
10494
11506
  return (focusIndex.value === -1 ? 0 : focusIndex.value) === index ? 0 : -1;
10495
11507
  }
@@ -10546,9 +11558,9 @@ var tree_default = {
10546
11558
  function rowClassOf(node, level) {
10547
11559
  return typeof props.rowClass === "function" ? props.rowClass(node, level) : props.rowClass;
10548
11560
  }
10549
- const dragKey = (0, import_vue35.ref)("");
10550
- const dropKey = (0, import_vue35.ref)("");
10551
- const dropPosition = (0, import_vue35.ref)("");
11561
+ const dragKey = (0, import_vue37.ref)("");
11562
+ const dropKey = (0, import_vue37.ref)("");
11563
+ const dropPosition = (0, import_vue37.ref)("");
10552
11564
  function findNodeByKey(key, nodes = props.data) {
10553
11565
  for (const node of nodes) {
10554
11566
  if (node[props.nodeKey] === key) return node;
@@ -10660,7 +11672,7 @@ var tree_default = {
10660
11672
  onDrop,
10661
11673
  onDragEnd,
10662
11674
  labelOf,
10663
- emptyLabel: (0, import_vue35.computed)(() => props.emptyText || t("tree.empty")),
11675
+ emptyLabel: (0, import_vue37.computed)(() => props.emptyText || t("tree.empty")),
10664
11676
  t
10665
11677
  };
10666
11678
  },
@@ -10729,7 +11741,7 @@ var tree_default = {
10729
11741
  };
10730
11742
 
10731
11743
  // src/components/editable-table/index.js
10732
- var import_vue36 = require("vue");
11744
+ var import_vue38 = require("vue");
10733
11745
  var ACTIONS_KEY = "__editable_actions";
10734
11746
  function isEmpty(value) {
10735
11747
  if (value === "" || value === null || value === void 0) return true;
@@ -10752,13 +11764,13 @@ var editable_table_default = {
10752
11764
  },
10753
11765
  emits: ["edit", "save", "cancel"],
10754
11766
  setup(props, { emit }) {
10755
- const slots = (0, import_vue36.useSlots)();
10756
- const editingKey = (0, import_vue36.ref)("");
10757
- const draft = (0, import_vue36.reactive)({});
10758
- const errors = (0, import_vue36.reactive)({});
10759
- const tableRef = (0, import_vue36.ref)(null);
10760
- const editableColumns = (0, import_vue36.computed)(() => props.columns.filter((column) => column.editor));
10761
- const renderColumns = (0, import_vue36.computed)(() => {
11767
+ const slots = (0, import_vue38.useSlots)();
11768
+ const editingKey = (0, import_vue38.ref)("");
11769
+ const draft = (0, import_vue38.reactive)({});
11770
+ const errors = (0, import_vue38.reactive)({});
11771
+ const tableRef = (0, import_vue38.ref)(null);
11772
+ const editableColumns = (0, import_vue38.computed)(() => props.columns.filter((column) => column.editor));
11773
+ const renderColumns = (0, import_vue38.computed)(() => {
10762
11774
  if (!props.showActions) return props.columns;
10763
11775
  return props.columns.concat({
10764
11776
  key: ACTIONS_KEY,
@@ -10770,7 +11782,7 @@ var editable_table_default = {
10770
11782
  exportable: false
10771
11783
  });
10772
11784
  });
10773
- const forwardedSlotNames = (0, import_vue36.computed)(() => {
11785
+ const forwardedSlotNames = (0, import_vue38.computed)(() => {
10774
11786
  const taken = new Set(editableColumns.value.map((column) => "cell-" + column.key));
10775
11787
  taken.add("cell-" + ACTIONS_KEY);
10776
11788
  return Object.keys(slots).filter((name) => !taken.has(name));
@@ -10845,7 +11857,7 @@ var editable_table_default = {
10845
11857
  return false;
10846
11858
  }
10847
11859
  if (!validate()) {
10848
- (0, import_vue36.nextTick)(() => {
11860
+ (0, import_vue38.nextTick)(() => {
10849
11861
  const el = tableRef.value && tableRef.value.$el ? tableRef.value.$el.querySelector(".djm-cell-error") : null;
10850
11862
  if (el) el.scrollIntoView({ block: "nearest" });
10851
11863
  });
@@ -10865,7 +11877,7 @@ var editable_table_default = {
10865
11877
  clearErrors();
10866
11878
  return true;
10867
11879
  }
10868
- (0, import_vue36.watch)(
11880
+ (0, import_vue38.watch)(
10869
11881
  () => props.rows,
10870
11882
  () => {
10871
11883
  if (editingKey.value && !findRow(editingKey.value)) {
@@ -11001,8 +12013,8 @@ var descriptions_default = {
11001
12013
  };
11002
12014
 
11003
12015
  // src/components/message/index.js
11004
- var import_vue37 = require("vue");
11005
- var djmMessages = (0, import_vue37.reactive)([]);
12016
+ var import_vue39 = require("vue");
12017
+ var djmMessages = (0, import_vue39.reactive)([]);
11006
12018
  var seq = 0;
11007
12019
  function close(id) {
11008
12020
  const index = djmMessages.findIndex((item) => item.id === id);
@@ -11047,7 +12059,7 @@ var message_default = {
11047
12059
  };
11048
12060
 
11049
12061
  // src/components/org-picker/index.js
11050
- var import_vue38 = require("vue");
12062
+ var import_vue40 = require("vue");
11051
12063
  var org_picker_default = {
11052
12064
  name: "DjmOrgPicker",
11053
12065
  components: { DjmIcon: icon_default },
@@ -11066,13 +12078,13 @@ var org_picker_default = {
11066
12078
  },
11067
12079
  emits: ["update:modelValue", "change", "visible-change"],
11068
12080
  setup(props, { emit }) {
11069
- const open = (0, import_vue38.ref)(false);
11070
- const root = (0, import_vue38.ref)(null);
11071
- const searchRef = (0, import_vue38.ref)(null);
11072
- const keyword = (0, import_vue38.ref)("");
11073
- const activeDept = (0, import_vue38.ref)("");
11074
- const temp = (0, import_vue38.ref)([]);
11075
- const expandedIds = (0, import_vue38.ref)(/* @__PURE__ */ new Set());
12081
+ const open = (0, import_vue40.ref)(false);
12082
+ const root = (0, import_vue40.ref)(null);
12083
+ const searchRef = (0, import_vue40.ref)(null);
12084
+ const keyword = (0, import_vue40.ref)("");
12085
+ const activeDept = (0, import_vue40.ref)("");
12086
+ const temp = (0, import_vue40.ref)([]);
12087
+ const expandedIds = (0, import_vue40.ref)(/* @__PURE__ */ new Set());
11076
12088
  let detachPanel = null;
11077
12089
  function collectDeptIds(nodes, out = []) {
11078
12090
  nodes.forEach((node) => {
@@ -11102,22 +12114,22 @@ var org_picker_default = {
11102
12114
  walk([root2]);
11103
12115
  return ids;
11104
12116
  }
11105
- const staffMap = (0, import_vue38.computed)(() => {
12117
+ const staffMap = (0, import_vue40.computed)(() => {
11106
12118
  const map = /* @__PURE__ */ new Map();
11107
12119
  props.staff.forEach((item) => map.set(item.id, item));
11108
12120
  return map;
11109
12121
  });
11110
- const appliedStaff = (0, import_vue38.computed)(
12122
+ const appliedStaff = (0, import_vue40.computed)(
11111
12123
  () => props.modelValue.map((id) => staffMap.value.get(id)).filter(Boolean)
11112
12124
  );
11113
- const visibleTags = (0, import_vue38.computed)(() => {
12125
+ const visibleTags = (0, import_vue40.computed)(() => {
11114
12126
  if (props.maxTagCount <= 0) return appliedStaff.value;
11115
12127
  return appliedStaff.value.slice(0, props.maxTagCount);
11116
12128
  });
11117
- const restTagCount = (0, import_vue38.computed)(
12129
+ const restTagCount = (0, import_vue40.computed)(
11118
12130
  () => Math.max(0, appliedStaff.value.length - visibleTags.value.length)
11119
12131
  );
11120
- const visibleStaff = (0, import_vue38.computed)(() => {
12132
+ const visibleStaff = (0, import_vue40.computed)(() => {
11121
12133
  const key = keyword.value.trim().toLowerCase();
11122
12134
  if (key) {
11123
12135
  return props.staff.filter(
@@ -11128,7 +12140,7 @@ var org_picker_default = {
11128
12140
  const scope = deptScope(activeDept.value);
11129
12141
  return props.staff.filter((item) => scope.has(item.deptId));
11130
12142
  });
11131
- const deptRows = (0, import_vue38.computed)(() => {
12143
+ const deptRows = (0, import_vue40.computed)(() => {
11132
12144
  const rows = [];
11133
12145
  const walk = (nodes, depth) => {
11134
12146
  nodes.forEach((node) => {
@@ -11140,11 +12152,11 @@ var org_picker_default = {
11140
12152
  walk(props.departments, 0);
11141
12153
  return rows;
11142
12154
  });
11143
- const selectedCount = (0, import_vue38.computed)(() => temp.value.length);
11144
- const placeholderText = (0, import_vue38.computed)(() => props.placeholder || t("orgPicker.placeholder"));
11145
- const emptyLabel = (0, import_vue38.computed)(() => props.emptyText || t("orgPicker.empty"));
11146
- const panel = (0, import_vue38.ref)(null);
11147
- const panelStyle = (0, import_vue38.ref)({ ...PANEL_HIDDEN_STYLE });
12155
+ const selectedCount = (0, import_vue40.computed)(() => temp.value.length);
12156
+ const placeholderText = (0, import_vue40.computed)(() => props.placeholder || t("orgPicker.placeholder"));
12157
+ const emptyLabel = (0, import_vue40.computed)(() => props.emptyText || t("orgPicker.empty"));
12158
+ const panel = (0, import_vue40.ref)(null);
12159
+ const panelStyle = (0, import_vue40.ref)({ ...PANEL_HIDDEN_STYLE });
11148
12160
  const PANEL_HEIGHT = 342;
11149
12161
  function updatePosition() {
11150
12162
  if (!open.value || !root.value) return;
@@ -11161,7 +12173,7 @@ var org_picker_default = {
11161
12173
  expandedIds.value = new Set(collectDeptIds(props.departments));
11162
12174
  }
11163
12175
  expandAll();
11164
- (0, import_vue38.watch)(() => props.departments, () => {
12176
+ (0, import_vue40.watch)(() => props.departments, () => {
11165
12177
  expandedIds.value = /* @__PURE__ */ new Set([...expandedIds.value, ...collectDeptIds(props.departments)]);
11166
12178
  });
11167
12179
  function initialOf(item) {
@@ -11250,7 +12262,7 @@ var org_picker_default = {
11250
12262
  function clearTemp() {
11251
12263
  temp.value = [];
11252
12264
  }
11253
- (0, import_vue38.onBeforeUnmount)(() => {
12265
+ (0, import_vue40.onBeforeUnmount)(() => {
11254
12266
  if (detachPanel) {
11255
12267
  detachPanel();
11256
12268
  detachPanel = null;
@@ -11436,7 +12448,7 @@ var org_picker_default = {
11436
12448
  };
11437
12449
 
11438
12450
  // src/components/schema-form/index.js
11439
- var import_vue39 = require("vue");
12451
+ var import_vue41 = require("vue");
11440
12452
  var CONTROL_MAP = {
11441
12453
  input: input_default,
11442
12454
  number: input_number_default,
@@ -11472,26 +12484,26 @@ var schema_form_default = {
11472
12484
  },
11473
12485
  emits: ["update:modelValue", "change"],
11474
12486
  setup(props, { emit }) {
11475
- const innerForm = (0, import_vue39.ref)(null);
11476
- const model = (0, import_vue39.reactive)({ ...props.modelValue });
11477
- (0, import_vue39.watch)(() => props.fields, (fields) => {
12487
+ const innerForm = (0, import_vue41.ref)(null);
12488
+ const model = (0, import_vue41.reactive)({ ...props.modelValue });
12489
+ (0, import_vue41.watch)(() => props.fields, (fields) => {
11478
12490
  fields.forEach((field) => {
11479
12491
  if (model[field.key] === void 0 && field.default !== void 0) {
11480
12492
  model[field.key] = typeof field.default === "function" ? field.default() : field.default;
11481
12493
  }
11482
12494
  });
11483
12495
  }, { immediate: true, deep: true });
11484
- (0, import_vue39.watch)(() => props.modelValue, (value) => {
12496
+ (0, import_vue41.watch)(() => props.modelValue, (value) => {
11485
12497
  if (!value) return;
11486
12498
  Object.keys(value).forEach((key) => {
11487
12499
  if (model[key] !== value[key]) model[key] = value[key];
11488
12500
  });
11489
12501
  }, { deep: true });
11490
- (0, import_vue39.watch)(model, () => {
12502
+ (0, import_vue41.watch)(model, () => {
11491
12503
  emit("update:modelValue", { ...model });
11492
12504
  emit("change", { ...model });
11493
12505
  }, { deep: true });
11494
- const formRules = (0, import_vue39.computed)(() => {
12506
+ const formRules = (0, import_vue41.computed)(() => {
11495
12507
  const merged = { ...props.rules };
11496
12508
  props.fields.forEach((field) => {
11497
12509
  if (!field.required && !field.rules) return;
@@ -11504,7 +12516,7 @@ var schema_form_default = {
11504
12516
  });
11505
12517
  return merged;
11506
12518
  });
11507
- const visibleFields = (0, import_vue39.computed)(
12519
+ const visibleFields = (0, import_vue41.computed)(
11508
12520
  () => props.fields.filter((field) => {
11509
12521
  if (typeof field.visibleWhen !== "function") return true;
11510
12522
  return Boolean(field.visibleWhen(model));
@@ -11698,7 +12710,7 @@ var approval_flow_default = {
11698
12710
  };
11699
12711
 
11700
12712
  // src/components/query-filter/index.js
11701
- var import_vue40 = require("vue");
12713
+ var import_vue42 = require("vue");
11702
12714
  var CONTROL_MAP2 = {
11703
12715
  input: input_default,
11704
12716
  number: input_number_default,
@@ -11723,26 +12735,26 @@ var query_filter_default = {
11723
12735
  },
11724
12736
  emits: ["update:modelValue", "search", "reset"],
11725
12737
  setup(props, { emit }) {
11726
- const expanded = (0, import_vue40.ref)(false);
11727
- const model = (0, import_vue40.reactive)({ ...props.modelValue });
11728
- (0, import_vue40.watch)(() => props.fields, (fields) => {
12738
+ const expanded = (0, import_vue42.ref)(false);
12739
+ const model = (0, import_vue42.reactive)({ ...props.modelValue });
12740
+ (0, import_vue42.watch)(() => props.fields, (fields) => {
11729
12741
  fields.forEach((field) => {
11730
12742
  if (model[field.key] === void 0 && field.default !== void 0) {
11731
12743
  model[field.key] = typeof field.default === "function" ? field.default() : field.default;
11732
12744
  }
11733
12745
  });
11734
12746
  }, { immediate: true, deep: true });
11735
- (0, import_vue40.watch)(() => props.modelValue, (value) => {
12747
+ (0, import_vue42.watch)(() => props.modelValue, (value) => {
11736
12748
  if (!value) return;
11737
12749
  Object.keys(value).forEach((key) => {
11738
12750
  if (model[key] !== value[key]) model[key] = value[key];
11739
12751
  });
11740
12752
  }, { deep: true });
11741
- (0, import_vue40.watch)(model, () => {
12753
+ (0, import_vue42.watch)(model, () => {
11742
12754
  emit("update:modelValue", { ...model });
11743
12755
  }, { deep: true });
11744
- const collapsible = (0, import_vue40.computed)(() => props.fields.length > props.visibleCount);
11745
- const visibleFields = (0, import_vue40.computed)(() => {
12756
+ const collapsible = (0, import_vue42.computed)(() => props.fields.length > props.visibleCount);
12757
+ const visibleFields = (0, import_vue42.computed)(() => {
11746
12758
  if (!collapsible.value || expanded.value) return props.fields;
11747
12759
  return props.fields.slice(0, props.visibleCount);
11748
12760
  });
@@ -11871,200 +12883,8 @@ var filter_tags_default = {
11871
12883
  `
11872
12884
  };
11873
12885
 
11874
- // src/components/media-picker/index.js
11875
- var import_vue41 = require("vue");
11876
- var media_picker_default = {
11877
- name: "DjmMediaPicker",
11878
- components: { DjmModal: modal_default, DjmPagination: pagination_default, DjmIcon: icon_default },
11879
- props: {
11880
- modelValue: { type: [Array, String, Number], default: "" },
11881
- items: { type: Array, default: () => [] },
11882
- multiple: { type: Boolean, default: false },
11883
- // 最多选几个,0 表示不限
11884
- limit: { type: Number, default: 0 },
11885
- // image 只显示图片,file 只显示非图片,空串不过滤
11886
- accept: { type: String, default: "" },
11887
- title: { type: String, default: "" },
11888
- triggerText: { type: String, default: "" },
11889
- pageSize: { type: Number, default: 12 },
11890
- disabled: { type: Boolean, default: false }
11891
- },
11892
- emits: ["update:modelValue", "change"],
11893
- setup(props, { emit }) {
11894
- const open = (0, import_vue41.ref)(false);
11895
- const keyword = (0, import_vue41.ref)("");
11896
- const page = (0, import_vue41.ref)(1);
11897
- const temp = (0, import_vue41.ref)([]);
11898
- const selectedIds = (0, import_vue41.computed)(() => {
11899
- if (props.multiple) return Array.isArray(props.modelValue) ? props.modelValue : [];
11900
- if (props.modelValue === "" || props.modelValue === null || props.modelValue === void 0) return [];
11901
- return [props.modelValue];
11902
- });
11903
- function isImage(item) {
11904
- if (item.type) return item.type === "image";
11905
- return /\.(png|jpe?g|gif|webp|svg|avif)$/i.test(item.url || "");
11906
- }
11907
- const filtered = (0, import_vue41.computed)(() => {
11908
- const key = keyword.value.trim().toLowerCase();
11909
- return props.items.filter((item) => {
11910
- if (props.accept === "image" && !isImage(item)) return false;
11911
- if (props.accept === "file" && isImage(item)) return false;
11912
- if (key && !String(item.name || "").toLowerCase().includes(key)) return false;
11913
- return true;
11914
- });
11915
- });
11916
- const paged = (0, import_vue41.computed)(() => {
11917
- const start = (page.value - 1) * props.pageSize;
11918
- return filtered.value.slice(start, start + props.pageSize);
11919
- });
11920
- (0, import_vue41.watch)(keyword, () => {
11921
- page.value = 1;
11922
- });
11923
- (0, import_vue41.watch)(
11924
- () => filtered.value.length,
11925
- () => {
11926
- const max = Math.max(1, Math.ceil(filtered.value.length / props.pageSize));
11927
- if (page.value > max) page.value = max;
11928
- }
11929
- );
11930
- function isChecked(id) {
11931
- return temp.value.includes(id);
11932
- }
11933
- function atLimit() {
11934
- return props.limit > 0 && temp.value.length >= props.limit;
11935
- }
11936
- function toggle(item) {
11937
- if (props.multiple) {
11938
- if (isChecked(item.id)) {
11939
- temp.value = temp.value.filter((id) => id !== item.id);
11940
- return;
11941
- }
11942
- if (atLimit()) return;
11943
- temp.value = [...temp.value, item.id];
11944
- return;
11945
- }
11946
- temp.value = [item.id];
11947
- }
11948
- function openPanel() {
11949
- if (props.disabled) return;
11950
- temp.value = [...selectedIds.value];
11951
- keyword.value = "";
11952
- page.value = 1;
11953
- open.value = true;
11954
- }
11955
- function commit() {
11956
- const next = props.multiple ? [...temp.value] : temp.value[0] !== void 0 ? temp.value[0] : "";
11957
- emit("update:modelValue", next);
11958
- emit("change", next);
11959
- open.value = false;
11960
- }
11961
- function cancel() {
11962
- temp.value = [...selectedIds.value];
11963
- open.value = false;
11964
- }
11965
- return {
11966
- open,
11967
- keyword,
11968
- page,
11969
- temp,
11970
- selectedIds,
11971
- filtered,
11972
- paged,
11973
- isImage,
11974
- isChecked,
11975
- atLimit,
11976
- toggle,
11977
- openPanel,
11978
- commit,
11979
- cancel,
11980
- t
11981
- };
11982
- },
11983
- template: `
11984
- <span class="djm-media-picker">
11985
- <slot name="trigger" :open="openPanel" :count="selectedIds.length">
11986
- <button
11987
- class="djm-btn"
11988
- type="button"
11989
- :disabled="disabled"
11990
- @click="openPanel"
11991
- >{{ triggerText || t('mediaPicker.select') }}<span v-if="selectedIds.length" class="djm-media-picker-count">{{ selectedIds.length }}</span></button>
11992
- </slot>
11993
-
11994
- <DjmModal
11995
- :model-value="open"
11996
- :title="title || t('mediaPicker.title')"
11997
- width="760px"
11998
- @update:model-value="cancel"
11999
- >
12000
- <div class="djm-media-toolbar">
12001
- <label class="djm-media-search">
12002
- <DjmIcon name="search" :size="13" />
12003
- <input
12004
- v-model="keyword"
12005
- class="djm-media-search-input"
12006
- type="text"
12007
- :placeholder="t('mediaPicker.search')"
12008
- :aria-label="t('mediaPicker.search')"
12009
- />
12010
- </label>
12011
- <span class="djm-media-toolbar-slot">
12012
- <slot name="toolbar"></slot>
12013
- </span>
12014
- </div>
12015
-
12016
- <div class="djm-media-grid" role="listbox" :aria-multiselectable="multiple ? 'true' : 'false'">
12017
- <div
12018
- v-for="item in paged"
12019
- :key="item.id"
12020
- class="djm-media-item"
12021
- :class="{
12022
- 'djm-is-checked': isChecked(item.id),
12023
- 'djm-is-disabled': multiple && atLimit() && !isChecked(item.id)
12024
- }"
12025
- role="option"
12026
- tabindex="0"
12027
- :aria-selected="String(isChecked(item.id))"
12028
- @click="toggle(item)"
12029
- @keydown.enter.prevent="toggle(item)"
12030
- @keydown.space.prevent="toggle(item)"
12031
- >
12032
- <div class="djm-media-thumb">
12033
- <img v-if="isImage(item)" :src="item.url" :alt="item.name" loading="lazy" />
12034
- <DjmIcon v-else name="folder" :size="26" />
12035
- <span v-if="isChecked(item.id)" class="djm-media-check">
12036
- <DjmIcon name="check" :size="11" />
12037
- </span>
12038
- </div>
12039
- <div class="djm-media-name" :title="item.name">{{ item.name }}</div>
12040
- </div>
12041
- <div v-if="!paged.length" class="djm-media-empty">{{ t('mediaPicker.empty') }}</div>
12042
- </div>
12043
-
12044
- <div class="djm-media-foot">
12045
- <span class="djm-media-total">
12046
- {{ t('mediaPicker.total', { total: filtered.length }) }}
12047
- <em v-if="multiple && limit > 0">{{ t('mediaPicker.limit', { limit }) }}</em>
12048
- </span>
12049
- <DjmPagination
12050
- v-if="filtered.length > pageSize"
12051
- v-model:page="page"
12052
- :page-size="pageSize"
12053
- :total="filtered.length"
12054
- />
12055
- </div>
12056
-
12057
- <template #footer>
12058
- <button class="djm-btn" type="button" @click="cancel">{{ t('common.cancel') }}</button>
12059
- <button class="djm-btn djm-btn-primary" type="button" @click="commit">{{ t('common.confirm') }}</button>
12060
- </template>
12061
- </DjmModal>
12062
- </span>
12063
- `
12064
- };
12065
-
12066
12886
  // src/components/kanban/index.js
12067
- var import_vue42 = require("vue");
12887
+ var import_vue43 = require("vue");
12068
12888
  function cloneColumns(list) {
12069
12889
  return (list || []).map((col) => ({ ...col, cards: (col.cards || []).slice() }));
12070
12890
  }
@@ -12081,15 +12901,15 @@ var kanban_default = {
12081
12901
  },
12082
12902
  emits: ["update:columns", "change", "card-move", "card-click", "card-add"],
12083
12903
  setup(props, { emit }) {
12084
- const inner = (0, import_vue42.ref)(cloneColumns(props.columns));
12085
- (0, import_vue42.watch)(
12904
+ const inner = (0, import_vue43.ref)(cloneColumns(props.columns));
12905
+ (0, import_vue43.watch)(
12086
12906
  () => props.columns,
12087
12907
  (list) => {
12088
12908
  inner.value = cloneColumns(list);
12089
12909
  }
12090
12910
  );
12091
- const dragCard = (0, import_vue42.ref)(null);
12092
- const dropTarget = (0, import_vue42.ref)(null);
12911
+ const dragCard = (0, import_vue43.ref)(null);
12912
+ const dropTarget = (0, import_vue43.ref)(null);
12093
12913
  function columnOf(key) {
12094
12914
  return inner.value.find((col) => col.key === key);
12095
12915
  }
@@ -12252,7 +13072,7 @@ var kanban_default = {
12252
13072
  };
12253
13073
 
12254
13074
  // src/components/attachment-list/index.js
12255
- var import_vue43 = require("vue");
13075
+ var import_vue44 = require("vue");
12256
13076
  var IMAGE_EXTS = ["png", "jpg", "jpeg", "gif", "webp", "bmp", "svg"];
12257
13077
  function extOf(file) {
12258
13078
  if (file.ext) return String(file.ext).toLowerCase();
@@ -12276,14 +13096,14 @@ var attachment_list_default = {
12276
13096
  },
12277
13097
  emits: ["preview", "download", "remove"],
12278
13098
  setup(props, { emit }) {
12279
- const list = (0, import_vue43.computed)(
13099
+ const list = (0, import_vue44.computed)(
12280
13100
  () => props.files.map((file, index) => {
12281
13101
  const ext = extOf(file);
12282
13102
  const isImage = file.type === "image" || IMAGE_EXTS.includes(ext);
12283
13103
  return { ...file, _key: file.uid !== void 0 ? file.uid : index, _ext: ext, _isImage: isImage };
12284
13104
  })
12285
13105
  );
12286
- const emptyLabel = (0, import_vue43.computed)(() => props.emptyText || t("attachment.empty"));
13106
+ const emptyLabel = (0, import_vue44.computed)(() => props.emptyText || t("attachment.empty"));
12287
13107
  function onPreview(file) {
12288
13108
  emit("preview", file);
12289
13109
  }
@@ -12389,7 +13209,7 @@ var attachment_list_default = {
12389
13209
  };
12390
13210
 
12391
13211
  // src/components/notification/index.js
12392
- var import_vue44 = require("vue");
13212
+ var import_vue45 = require("vue");
12393
13213
  var TYPE_MAP = {
12394
13214
  info: { icon: "info", cls: "djm-is-info" },
12395
13215
  success: { icon: "check", cls: "djm-is-success" },
@@ -12409,8 +13229,8 @@ var notification_default = {
12409
13229
  },
12410
13230
  emits: ["click", "read", "read-all", "remove", "clear"],
12411
13231
  setup(props, { emit }) {
12412
- const unreadCount = (0, import_vue44.computed)(() => props.items.filter((item) => !item.read).length);
12413
- const emptyLabel = (0, import_vue44.computed)(() => props.emptyText || t("notification.empty"));
13232
+ const unreadCount = (0, import_vue45.computed)(() => props.items.filter((item) => !item.read).length);
13233
+ const emptyLabel = (0, import_vue45.computed)(() => props.emptyText || t("notification.empty"));
12414
13234
  function typeOf(item) {
12415
13235
  return TYPE_MAP[item.type] || TYPE_MAP.info;
12416
13236
  }
@@ -12421,7 +13241,7 @@ var notification_default = {
12421
13241
  function onReadAll() {
12422
13242
  emit("read-all");
12423
13243
  }
12424
- const clearing = (0, import_vue44.ref)(false);
13244
+ const clearing = (0, import_vue45.ref)(false);
12425
13245
  let clearTimer = null;
12426
13246
  function onClear() {
12427
13247
  if (!clearing.value) {
@@ -12435,7 +13255,7 @@ var notification_default = {
12435
13255
  clearing.value = false;
12436
13256
  emit("clear");
12437
13257
  }
12438
- (0, import_vue44.onBeforeUnmount)(() => window.clearTimeout(clearTimer));
13258
+ (0, import_vue45.onBeforeUnmount)(() => window.clearTimeout(clearTimer));
12439
13259
  function onRemove(item) {
12440
13260
  emit("remove", item);
12441
13261
  }
@@ -12510,7 +13330,7 @@ var notification_default = {
12510
13330
  };
12511
13331
 
12512
13332
  // src/components/config-provider/index.js
12513
- var import_vue45 = require("vue");
13333
+ var import_vue46 = require("vue");
12514
13334
  var SIZE_HEIGHT = { xs: "24px", sm: "28px", md: "30px", lg: "34px" };
12515
13335
  var config_provider_default = {
12516
13336
  name: "DjmConfigProvider",
@@ -12520,7 +13340,7 @@ var config_provider_default = {
12520
13340
  },
12521
13341
  setup(props) {
12522
13342
  if (props.locale) setLocale(props.locale);
12523
- (0, import_vue45.watch)(
13343
+ (0, import_vue46.watch)(
12524
13344
  () => props.locale,
12525
13345
  (code) => {
12526
13346
  if (code) setLocale(code);
@@ -12542,7 +13362,7 @@ var config_provider_default = {
12542
13362
  };
12543
13363
 
12544
13364
  // src/components/date-time-picker/index.js
12545
- var import_vue46 = require("vue");
13365
+ var import_vue47 = require("vue");
12546
13366
  var uidSeed7 = 0;
12547
13367
  var pad4 = (value) => String(value).padStart(2, "0");
12548
13368
  function toDateKey(year, month, day) {
@@ -12575,31 +13395,31 @@ var date_time_picker_default = {
12575
13395
  },
12576
13396
  emits: ["update:modelValue", "change", "visible-change"],
12577
13397
  setup(props, { emit }) {
12578
- const open = (0, import_vue46.ref)(false);
12579
- (0, import_vue46.watch)(open, (value) => emit("visible-change", value));
12580
- const root = (0, import_vue46.ref)(null);
12581
- const panel = (0, import_vue46.ref)(null);
13398
+ const open = (0, import_vue47.ref)(false);
13399
+ (0, import_vue47.watch)(open, (value) => emit("visible-change", value));
13400
+ const root = (0, import_vue47.ref)(null);
13401
+ const panel = (0, import_vue47.ref)(null);
12582
13402
  const panelId = "djm-datetime-panel-" + ++uidSeed7;
12583
- const panelStyle = (0, import_vue46.ref)({ ...PANEL_HIDDEN_STYLE });
13403
+ const panelStyle = (0, import_vue47.ref)({ ...PANEL_HIDDEN_STYLE });
12584
13404
  let detachPanel = null;
12585
13405
  const today = /* @__PURE__ */ new Date();
12586
13406
  const todayKey = toDateKey(today.getFullYear(), today.getMonth(), today.getDate());
12587
- const hasSeconds = (0, import_vue46.computed)(() => props.format.indexOf("ss") > -1);
12588
- const draft = (0, import_vue46.ref)({ date: "", h: "00", m: "00", s: "00" });
13407
+ const hasSeconds = (0, import_vue47.computed)(() => props.format.indexOf("ss") > -1);
13408
+ const draft = (0, import_vue47.ref)({ date: "", h: "00", m: "00", s: "00" });
12589
13409
  const initial = parseDate(parseValue(props.modelValue).date);
12590
- const viewYear = (0, import_vue46.ref)(initial ? initial.year : today.getFullYear());
12591
- const viewMonth = (0, import_vue46.ref)(initial ? initial.month : today.getMonth());
12592
- const displayText = (0, import_vue46.computed)(() => props.modelValue || "");
12593
- const placeholderText = (0, import_vue46.computed)(() => props.placeholder || t("dateTimePicker.placeholder"));
12594
- const weeks = (0, import_vue46.computed)(() => t("datePicker.weeks").split(","));
12595
- const hours = (0, import_vue46.computed)(() => Array.from({ length: 24 }, (_, index) => pad4(index)));
12596
- const minutes = (0, import_vue46.computed)(() => {
13410
+ const viewYear = (0, import_vue47.ref)(initial ? initial.year : today.getFullYear());
13411
+ const viewMonth = (0, import_vue47.ref)(initial ? initial.month : today.getMonth());
13412
+ const displayText = (0, import_vue47.computed)(() => props.modelValue || "");
13413
+ const placeholderText = (0, import_vue47.computed)(() => props.placeholder || t("dateTimePicker.placeholder"));
13414
+ const weeks = (0, import_vue47.computed)(() => t("datePicker.weeks").split(","));
13415
+ const hours = (0, import_vue47.computed)(() => Array.from({ length: 24 }, (_, index) => pad4(index)));
13416
+ const minutes = (0, import_vue47.computed)(() => {
12597
13417
  const list = [];
12598
13418
  for (let value = 0; value < 60; value += Math.max(1, props.minuteStep)) list.push(pad4(value));
12599
13419
  return list;
12600
13420
  });
12601
- const seconds = (0, import_vue46.computed)(() => Array.from({ length: 60 }, (_, index) => pad4(index)));
12602
- const timeCols = (0, import_vue46.computed)(() => {
13421
+ const seconds = (0, import_vue47.computed)(() => Array.from({ length: 60 }, (_, index) => pad4(index)));
13422
+ const timeCols = (0, import_vue47.computed)(() => {
12603
13423
  const cols = [
12604
13424
  { key: "h", list: hours.value },
12605
13425
  { key: "m", list: minutes.value }
@@ -12607,8 +13427,8 @@ var date_time_picker_default = {
12607
13427
  if (hasSeconds.value) cols.push({ key: "s", list: seconds.value });
12608
13428
  return cols;
12609
13429
  });
12610
- const monthLabel = (0, import_vue46.computed)(() => t("datePicker.title", { year: viewYear.value, month: viewMonth.value + 1 }));
12611
- const cells = (0, import_vue46.computed)(() => {
13430
+ const monthLabel = (0, import_vue47.computed)(() => t("datePicker.title", { year: viewYear.value, month: viewMonth.value + 1 }));
13431
+ const cells = (0, import_vue47.computed)(() => {
12612
13432
  const first = new Date(viewYear.value, viewMonth.value, 1);
12613
13433
  const offset = (first.getDay() + 6) % 7;
12614
13434
  const start = new Date(viewYear.value, viewMonth.value, 1 - offset);
@@ -12744,7 +13564,7 @@ var date_time_picker_default = {
12744
13564
  emit("change", "");
12745
13565
  closePanel();
12746
13566
  }
12747
- (0, import_vue46.onBeforeUnmount)(() => {
13567
+ (0, import_vue47.onBeforeUnmount)(() => {
12748
13568
  if (detachPanel) {
12749
13569
  detachPanel();
12750
13570
  detachPanel = null;
@@ -12869,7 +13689,7 @@ var date_time_picker_default = {
12869
13689
  };
12870
13690
 
12871
13691
  // src/components/virtual-list/index.js
12872
- var import_vue47 = require("vue");
13692
+ var import_vue48 = require("vue");
12873
13693
  var virtual_list_default = {
12874
13694
  name: "DjmVirtualList",
12875
13695
  props: {
@@ -12886,14 +13706,14 @@ var virtual_list_default = {
12886
13706
  },
12887
13707
  emits: ["scroll", "reach-bottom", "item-click"],
12888
13708
  setup(props, { emit, expose }) {
12889
- const viewport = (0, import_vue47.ref)(null);
12890
- const scrollTop = (0, import_vue47.ref)(0);
12891
- const viewHeight = (0, import_vue47.ref)(typeof props.height === "number" ? props.height : 320);
13709
+ const viewport = (0, import_vue48.ref)(null);
13710
+ const scrollTop = (0, import_vue48.ref)(0);
13711
+ const viewHeight = (0, import_vue48.ref)(typeof props.height === "number" ? props.height : 320);
12892
13712
  let bottomFired = false;
12893
13713
  function rowHeight(item, index) {
12894
13714
  return typeof props.itemHeight === "function" ? Math.max(1, Number(props.itemHeight(item, index)) || 1) : Math.max(1, props.itemHeight);
12895
13715
  }
12896
- const offsets = (0, import_vue47.computed)(() => {
13716
+ const offsets = (0, import_vue48.computed)(() => {
12897
13717
  const list = [0];
12898
13718
  let sum = 0;
12899
13719
  props.items.forEach((item, index) => {
@@ -12902,7 +13722,7 @@ var virtual_list_default = {
12902
13722
  });
12903
13723
  return list;
12904
13724
  });
12905
- const totalHeight = (0, import_vue47.computed)(() => offsets.value[offsets.value.length - 1]);
13725
+ const totalHeight = (0, import_vue48.computed)(() => offsets.value[offsets.value.length - 1]);
12906
13726
  function findStart(top) {
12907
13727
  const list = offsets.value;
12908
13728
  let low = 0;
@@ -12914,7 +13734,7 @@ var virtual_list_default = {
12914
13734
  }
12915
13735
  return Math.max(0, low - 1);
12916
13736
  }
12917
- const range = (0, import_vue47.computed)(() => {
13737
+ const range = (0, import_vue48.computed)(() => {
12918
13738
  const total = props.items.length;
12919
13739
  if (!total) return { start: 0, end: 0 };
12920
13740
  const start = Math.max(0, findStart(scrollTop.value) - props.overscan);
@@ -12923,7 +13743,7 @@ var virtual_list_default = {
12923
13743
  while (end < total && offsets.value[end] < limit) end += 1;
12924
13744
  return { start, end: Math.min(total, end + props.overscan) };
12925
13745
  });
12926
- const visibleRows = (0, import_vue47.computed)(() => {
13746
+ const visibleRows = (0, import_vue48.computed)(() => {
12927
13747
  const { start, end } = range.value;
12928
13748
  return props.items.slice(start, end).map((item, index) => {
12929
13749
  const realIndex = start + index;
@@ -12958,7 +13778,7 @@ var virtual_list_default = {
12958
13778
  else if (start < el.scrollTop) el.scrollTop = start;
12959
13779
  else if (end > el.scrollTop + el.clientHeight) el.scrollTop = end - el.clientHeight;
12960
13780
  }
12961
- (0, import_vue47.watch)(
13781
+ (0, import_vue48.watch)(
12962
13782
  () => props.height,
12963
13783
  () => {
12964
13784
  if (viewport.value) viewHeight.value = viewport.value.clientHeight;
@@ -12968,14 +13788,14 @@ var virtual_list_default = {
12968
13788
  if (viewport.value) viewHeight.value = viewport.value.clientHeight;
12969
13789
  }
12970
13790
  let resizeObserver = null;
12971
- (0, import_vue47.onMounted)(() => {
13791
+ (0, import_vue48.onMounted)(() => {
12972
13792
  measure();
12973
13793
  if (window.ResizeObserver && viewport.value) {
12974
13794
  resizeObserver = new ResizeObserver(() => measure());
12975
13795
  resizeObserver.observe(viewport.value);
12976
13796
  }
12977
13797
  });
12978
- (0, import_vue47.onBeforeUnmount)(() => {
13798
+ (0, import_vue48.onBeforeUnmount)(() => {
12979
13799
  if (resizeObserver) resizeObserver.disconnect();
12980
13800
  });
12981
13801
  function onItemClick(row) {
@@ -13020,7 +13840,7 @@ var virtual_list_default = {
13020
13840
  };
13021
13841
 
13022
13842
  // src/components/batch-bar/index.js
13023
- var import_vue48 = require("vue");
13843
+ var import_vue49 = require("vue");
13024
13844
  var batch_bar_default = {
13025
13845
  name: "DjmBatchBar",
13026
13846
  props: {
@@ -13035,8 +13855,8 @@ var batch_bar_default = {
13035
13855
  },
13036
13856
  emits: ["clear", "select-all"],
13037
13857
  setup(props, { emit }) {
13038
- const text = (0, import_vue48.computed)(() => props.label || t("batchBar.selected", { count: props.count }));
13039
- const canSelectAll = (0, import_vue48.computed)(() => props.total > props.count);
13858
+ const text = (0, import_vue49.computed)(() => props.label || t("batchBar.selected", { count: props.count }));
13859
+ const canSelectAll = (0, import_vue49.computed)(() => props.total > props.count);
13040
13860
  return {
13041
13861
  text,
13042
13862
  canSelectAll,
@@ -13064,7 +13884,7 @@ var batch_bar_default = {
13064
13884
  };
13065
13885
 
13066
13886
  // src/components/import-wizard/index.js
13067
- var import_vue49 = require("vue");
13887
+ var import_vue50 = require("vue");
13068
13888
  function matchAccept2(name, accept) {
13069
13889
  if (!accept) return true;
13070
13890
  const ext = "." + String(name).split(".").pop().toLowerCase();
@@ -13091,19 +13911,19 @@ var import_wizard_default = {
13091
13911
  },
13092
13912
  emits: ["update:step", "update:mapping", "file-change", "submit", "retry"],
13093
13913
  setup(props, { emit }) {
13094
- const innerStep = (0, import_vue49.ref)(props.step || 1);
13095
- (0, import_vue49.watch)(
13914
+ const innerStep = (0, import_vue50.ref)(props.step || 1);
13915
+ (0, import_vue50.watch)(
13096
13916
  () => props.step,
13097
13917
  (value) => {
13098
13918
  if (value) innerStep.value = value;
13099
13919
  }
13100
13920
  );
13101
- const file = (0, import_vue49.ref)(null);
13102
- const fileError = (0, import_vue49.ref)("");
13103
- const mappingError = (0, import_vue49.ref)("");
13104
- const fileInput = (0, import_vue49.ref)(null);
13105
- const innerMapping = (0, import_vue49.ref)({ ...props.mapping });
13106
- (0, import_vue49.watch)(
13921
+ const file = (0, import_vue50.ref)(null);
13922
+ const fileError = (0, import_vue50.ref)("");
13923
+ const mappingError = (0, import_vue50.ref)("");
13924
+ const fileInput = (0, import_vue50.ref)(null);
13925
+ const innerMapping = (0, import_vue50.ref)({ ...props.mapping });
13926
+ (0, import_vue50.watch)(
13107
13927
  () => props.mapping,
13108
13928
  (value) => {
13109
13929
  innerMapping.value = { ...value };
@@ -13114,7 +13934,7 @@ var import_wizard_default = {
13114
13934
  innerStep.value = next;
13115
13935
  emit("update:step", next);
13116
13936
  }
13117
- const steps = (0, import_vue49.computed)(() => [
13937
+ const steps = (0, import_vue50.computed)(() => [
13118
13938
  { index: 1, title: t("importWizard.stepFile") },
13119
13939
  { index: 2, title: t("importWizard.stepMapping") },
13120
13940
  { index: 3, title: t("importWizard.stepResult") }
@@ -13156,7 +13976,7 @@ var import_wizard_default = {
13156
13976
  mappingError.value = "";
13157
13977
  emit("update:mapping", next);
13158
13978
  }
13159
- const missingRequired = (0, import_vue49.computed)(
13979
+ const missingRequired = (0, import_vue50.computed)(
13160
13980
  () => props.columns.filter((col) => col.required && !innerMapping.value[col.key])
13161
13981
  );
13162
13982
  function submit() {
@@ -13168,7 +13988,7 @@ var import_wizard_default = {
13168
13988
  }
13169
13989
  emit("submit", { ...innerMapping.value });
13170
13990
  }
13171
- (0, import_vue49.watch)(
13991
+ (0, import_vue50.watch)(
13172
13992
  () => props.result,
13173
13993
  (value) => {
13174
13994
  if (value && (value.total || value.success || value.failed || value.errors && value.errors.length)) {
@@ -13189,7 +14009,7 @@ var import_wizard_default = {
13189
14009
  emit("retry");
13190
14010
  goStep(2);
13191
14011
  }
13192
- const stats = (0, import_vue49.computed)(() => {
14012
+ const stats = (0, import_vue50.computed)(() => {
13193
14013
  const data = props.result || {};
13194
14014
  return {
13195
14015
  total: data.total || 0,
@@ -13335,7 +14155,7 @@ var import_wizard_default = {
13335
14155
  };
13336
14156
 
13337
14157
  // src/components/diff/index.js
13338
- var import_vue50 = require("vue");
14158
+ var import_vue51 = require("vue");
13339
14159
 
13340
14160
  // src/utils/text-diff.js
13341
14161
  var MAX_CELLS = 1e6;
@@ -13399,8 +14219,8 @@ var diff_default = {
13399
14219
  afterLabel: { type: String, default: "" }
13400
14220
  },
13401
14221
  setup(props) {
13402
- const rows = (0, import_vue50.computed)(() => diffLines(props.before, props.after));
13403
- const stats = (0, import_vue50.computed)(() => {
14222
+ const rows = (0, import_vue51.computed)(() => diffLines(props.before, props.after));
14223
+ const stats = (0, import_vue51.computed)(() => {
13404
14224
  let add = 0;
13405
14225
  let remove = 0;
13406
14226
  rows.value.forEach((row) => {
@@ -13409,11 +14229,11 @@ var diff_default = {
13409
14229
  });
13410
14230
  return { add, remove };
13411
14231
  });
13412
- const expandedBlocks = (0, import_vue50.ref)([]);
14232
+ const expandedBlocks = (0, import_vue51.ref)([]);
13413
14233
  function expand(index) {
13414
14234
  expandedBlocks.value = expandedBlocks.value.concat(index);
13415
14235
  }
13416
- const displayRows = (0, import_vue50.computed)(() => {
14236
+ const displayRows = (0, import_vue51.computed)(() => {
13417
14237
  const ctx = Math.max(0, props.context);
13418
14238
  const list = rows.value;
13419
14239
  if (!ctx) return list;
@@ -13444,7 +14264,7 @@ var diff_default = {
13444
14264
  }
13445
14265
  return out;
13446
14266
  });
13447
- const splitRows = (0, import_vue50.computed)(() => {
14267
+ const splitRows = (0, import_vue51.computed)(() => {
13448
14268
  const list = displayRows.value;
13449
14269
  const out = [];
13450
14270
  let i = 0;
@@ -13469,8 +14289,8 @@ var diff_default = {
13469
14289
  }
13470
14290
  return out;
13471
14291
  });
13472
- const beforeLabelText = (0, import_vue50.computed)(() => props.beforeLabel || t("diff.before"));
13473
- const afterLabelText = (0, import_vue50.computed)(() => props.afterLabel || t("diff.after"));
14292
+ const beforeLabelText = (0, import_vue51.computed)(() => props.beforeLabel || t("diff.before"));
14293
+ const afterLabelText = (0, import_vue51.computed)(() => props.afterLabel || t("diff.after"));
13474
14294
  return {
13475
14295
  stats,
13476
14296
  displayRows,
@@ -13536,7 +14356,7 @@ var diff_default = {
13536
14356
  };
13537
14357
 
13538
14358
  // src/components/tree-table/index.js
13539
- var import_vue51 = require("vue");
14359
+ var import_vue52 = require("vue");
13540
14360
  function keyOf(row, rowKey) {
13541
14361
  return row && row[rowKey] !== void 0 ? row[rowKey] : row && row.id;
13542
14362
  }
@@ -13575,23 +14395,23 @@ var tree_table_default = {
13575
14395
  eachNode(props.data, (row) => keys.push(keyOf(row, props.rowKey)));
13576
14396
  return keys;
13577
14397
  }
13578
- const innerExpanded = (0, import_vue51.ref)(
14398
+ const innerExpanded = (0, import_vue52.ref)(
13579
14399
  props.expandedKeys ? props.expandedKeys.slice() : props.defaultExpandAll ? allKeys() : []
13580
14400
  );
13581
- (0, import_vue51.watch)(
14401
+ (0, import_vue52.watch)(
13582
14402
  () => props.expandedKeys,
13583
14403
  (value) => {
13584
14404
  if (value) innerExpanded.value = value.slice();
13585
14405
  }
13586
14406
  );
13587
- const innerChecked = (0, import_vue51.ref)(props.checkedKeys ? props.checkedKeys.slice() : []);
13588
- (0, import_vue51.watch)(
14407
+ const innerChecked = (0, import_vue52.ref)(props.checkedKeys ? props.checkedKeys.slice() : []);
14408
+ (0, import_vue52.watch)(
13589
14409
  () => props.checkedKeys,
13590
14410
  (value) => {
13591
14411
  if (value) innerChecked.value = value.slice();
13592
14412
  }
13593
14413
  );
13594
- const rows = (0, import_vue51.computed)(() => {
14414
+ const rows = (0, import_vue52.computed)(() => {
13595
14415
  const out = [];
13596
14416
  function walk(list, level, parentKey) {
13597
14417
  ;
@@ -13606,7 +14426,7 @@ var tree_table_default = {
13606
14426
  walk(props.data, 1, null);
13607
14427
  return out;
13608
14428
  });
13609
- const descendantMap = (0, import_vue51.computed)(() => {
14429
+ const descendantMap = (0, import_vue52.computed)(() => {
13610
14430
  const map = {};
13611
14431
  function collect(row) {
13612
14432
  const key = keyOf(row, props.rowKey);
@@ -13621,16 +14441,16 @@ var tree_table_default = {
13621
14441
  (props.data || []).forEach(collect);
13622
14442
  return map;
13623
14443
  });
13624
- const leafKeys = (0, import_vue51.computed)(() => {
14444
+ const leafKeys = (0, import_vue52.computed)(() => {
13625
14445
  const keys = [];
13626
14446
  eachNode(props.data, (row) => {
13627
14447
  if (!row.children || !row.children.length) keys.push(keyOf(row, props.rowKey));
13628
14448
  });
13629
14449
  return keys;
13630
14450
  });
13631
- const checkedSet = (0, import_vue51.computed)(() => new Set(innerChecked.value));
13632
- const allChecked = (0, import_vue51.computed)(() => leafKeys.value.length > 0 && leafKeys.value.every((key) => checkedSet.value.has(key)));
13633
- const someChecked = (0, import_vue51.computed)(() => !allChecked.value && leafKeys.value.some((key) => checkedSet.value.has(key)));
14451
+ const checkedSet = (0, import_vue52.computed)(() => new Set(innerChecked.value));
14452
+ const allChecked = (0, import_vue52.computed)(() => leafKeys.value.length > 0 && leafKeys.value.every((key) => checkedSet.value.has(key)));
14453
+ const someChecked = (0, import_vue52.computed)(() => !allChecked.value && leafKeys.value.some((key) => checkedSet.value.has(key)));
13634
14454
  function isIndeterminate(row) {
13635
14455
  if (!props.selectable || props.checkStrictly) return false;
13636
14456
  const desc = descendantMap.value[keyOf(row, props.rowKey)] || [];
@@ -13664,7 +14484,7 @@ var tree_table_default = {
13664
14484
  }
13665
14485
  emitChecked(Array.from(set));
13666
14486
  }
13667
- const nodeMap = (0, import_vue51.computed)(() => {
14487
+ const nodeMap = (0, import_vue52.computed)(() => {
13668
14488
  const map = {};
13669
14489
  eachNode(props.data, (row, level, parentKey) => {
13670
14490
  map[keyOf(row, props.rowKey)] = { row, parentKey };
@@ -13711,11 +14531,11 @@ var tree_table_default = {
13711
14531
  function onRowClick(item) {
13712
14532
  emit("row-click", item.row, item);
13713
14533
  }
13714
- const scrollStyle = (0, import_vue51.computed)(() => {
14534
+ const scrollStyle = (0, import_vue52.computed)(() => {
13715
14535
  if (!props.maxHeight) return null;
13716
14536
  return { maxHeight: typeof props.maxHeight === "number" ? props.maxHeight + "px" : props.maxHeight };
13717
14537
  });
13718
- const emptyLabel = (0, import_vue51.computed)(() => props.emptyText || t("treeTable.empty"));
14538
+ const emptyLabel = (0, import_vue52.computed)(() => props.emptyText || t("treeTable.empty"));
13719
14539
  return {
13720
14540
  rows,
13721
14541
  innerExpanded,
@@ -13817,7 +14637,7 @@ var tree_table_default = {
13817
14637
  };
13818
14638
 
13819
14639
  // src/components/schedule/index.js
13820
- var import_vue52 = require("vue");
14640
+ var import_vue53 = require("vue");
13821
14641
  var pad5 = (value) => String(value).padStart(2, "0");
13822
14642
  function toKey3(date) {
13823
14643
  return `${date.getFullYear()}-${pad5(date.getMonth() + 1)}-${pad5(date.getDate())}`;
@@ -13849,13 +14669,13 @@ var schedule_default = {
13849
14669
  emits: ["update:modelValue", "event-click", "slot-click", "week-change"],
13850
14670
  setup(props, { emit }) {
13851
14671
  const todayKey = toKey3(/* @__PURE__ */ new Date());
13852
- const nowMinutes = (0, import_vue52.ref)((/* @__PURE__ */ new Date()).getHours() * 60 + (/* @__PURE__ */ new Date()).getMinutes());
14672
+ const nowMinutes = (0, import_vue53.ref)((/* @__PURE__ */ new Date()).getHours() * 60 + (/* @__PURE__ */ new Date()).getMinutes());
13853
14673
  const timer = window.setInterval(() => {
13854
14674
  const now = /* @__PURE__ */ new Date();
13855
14675
  nowMinutes.value = now.getHours() * 60 + now.getMinutes();
13856
14676
  }, 6e4);
13857
- const anchor = (0, import_vue52.ref)(props.modelValue || todayKey);
13858
- (0, import_vue52.watch)(
14677
+ const anchor = (0, import_vue53.ref)(props.modelValue || todayKey);
14678
+ (0, import_vue53.watch)(
13859
14679
  () => props.modelValue,
13860
14680
  (value) => {
13861
14681
  if (value) anchor.value = value;
@@ -13867,8 +14687,8 @@ var schedule_default = {
13867
14687
  const offset = (day + 6) % 7;
13868
14688
  return new Date(date.getFullYear(), date.getMonth(), date.getDate() - offset);
13869
14689
  }
13870
- const weekStartDate = (0, import_vue52.computed)(() => startOfWeek(anchor.value));
13871
- const weekdays = (0, import_vue52.computed)(() => t("schedule.weekdays").split(","));
14690
+ const weekStartDate = (0, import_vue53.computed)(() => startOfWeek(anchor.value));
14691
+ const weekdays = (0, import_vue53.computed)(() => t("schedule.weekdays").split(","));
13872
14692
  function layoutDay(list) {
13873
14693
  const sorted = list.map((item) => {
13874
14694
  const startMin = toMinutes(item.start, props.startHour * 60);
@@ -13901,7 +14721,7 @@ var schedule_default = {
13901
14721
  };
13902
14722
  });
13903
14723
  }
13904
- const days = (0, import_vue52.computed)(() => {
14724
+ const days = (0, import_vue53.computed)(() => {
13905
14725
  const start = weekStartDate.value;
13906
14726
  const list = Array.from({ length: 7 }, (_, index) => {
13907
14727
  const date = new Date(start.getFullYear(), start.getMonth(), start.getDate() + index);
@@ -13919,20 +14739,20 @@ var schedule_default = {
13919
14739
  });
13920
14740
  return props.showWeekend ? list : list.slice(0, 5);
13921
14741
  });
13922
- const hours = (0, import_vue52.computed)(() => {
14742
+ const hours = (0, import_vue53.computed)(() => {
13923
14743
  const list = [];
13924
14744
  for (let hour = props.startHour; hour < props.endHour; hour++) list.push(hour);
13925
14745
  return list;
13926
14746
  });
13927
- const bodyHeight = (0, import_vue52.computed)(() => (props.endHour - props.startHour) * props.hourHeight);
13928
- const gridStyle = (0, import_vue52.computed)(() => ({
14747
+ const bodyHeight = (0, import_vue53.computed)(() => (props.endHour - props.startHour) * props.hourHeight);
14748
+ const gridStyle = (0, import_vue53.computed)(() => ({
13929
14749
  gridTemplateColumns: "56px repeat(" + Math.max(1, days.value.length) + ", minmax(0, 1fr))"
13930
14750
  }));
13931
- const nowTop = (0, import_vue52.computed)(() => (nowMinutes.value - props.startHour * 60) / 60 * props.hourHeight);
13932
- const showNowLine = (0, import_vue52.computed)(
14751
+ const nowTop = (0, import_vue53.computed)(() => (nowMinutes.value - props.startHour * 60) / 60 * props.hourHeight);
14752
+ const showNowLine = (0, import_vue53.computed)(
13933
14753
  () => nowMinutes.value >= props.startHour * 60 && nowMinutes.value <= props.endHour * 60 && days.value.some((day) => day.today)
13934
14754
  );
13935
- const rangeLabel = (0, import_vue52.computed)(() => {
14755
+ const rangeLabel = (0, import_vue53.computed)(() => {
13936
14756
  const list = days.value;
13937
14757
  if (!list.length) return "";
13938
14758
  const first = list[0];
@@ -13962,7 +14782,7 @@ var schedule_default = {
13962
14782
  const minute = minutes % 60;
13963
14783
  emit("slot-click", { date: day.key, time: `${pad5(hour)}:${pad5(minute)}` });
13964
14784
  }
13965
- (0, import_vue52.onBeforeUnmount)(() => window.clearInterval(timer));
14785
+ (0, import_vue53.onBeforeUnmount)(() => window.clearInterval(timer));
13966
14786
  return {
13967
14787
  days,
13968
14788
  hours,
@@ -14062,7 +14882,7 @@ var schedule_default = {
14062
14882
  };
14063
14883
 
14064
14884
  // src/components/comment/index.js
14065
- var import_vue53 = require("vue");
14885
+ var import_vue54 = require("vue");
14066
14886
  var comment_default = {
14067
14887
  name: "DjmComment",
14068
14888
  components: { DjmAvatar: avatar_default, DjmIcon: icon_default },
@@ -14079,16 +14899,16 @@ var comment_default = {
14079
14899
  },
14080
14900
  emits: ["submit", "reply", "remove"],
14081
14901
  setup(props, { emit }) {
14082
- const content = (0, import_vue53.ref)("");
14083
- const replyTarget = (0, import_vue53.ref)(null);
14084
- const placeholderText = (0, import_vue53.computed)(() => {
14902
+ const content = (0, import_vue54.ref)("");
14903
+ const replyTarget = (0, import_vue54.ref)(null);
14904
+ const placeholderText = (0, import_vue54.computed)(() => {
14085
14905
  if (replyTarget.value) return t("comment.replyPlaceholder", { name: replyTarget.value.author });
14086
14906
  return props.placeholder || t("comment.placeholder");
14087
14907
  });
14088
- const submitLabel = (0, import_vue53.computed)(() => props.submitText || t("comment.submit"));
14089
- const emptyLabel = (0, import_vue53.computed)(() => props.emptyText || t("comment.empty"));
14090
- const overLimit = (0, import_vue53.computed)(() => content.value.length > props.maxLength);
14091
- const canSubmit = (0, import_vue53.computed)(() => content.value.trim().length > 0 && !overLimit.value && !props.disabled && !props.loading);
14908
+ const submitLabel = (0, import_vue54.computed)(() => props.submitText || t("comment.submit"));
14909
+ const emptyLabel = (0, import_vue54.computed)(() => props.emptyText || t("comment.empty"));
14910
+ const overLimit = (0, import_vue54.computed)(() => content.value.length > props.maxLength);
14911
+ const canSubmit = (0, import_vue54.computed)(() => content.value.trim().length > 0 && !overLimit.value && !props.disabled && !props.loading);
14092
14912
  function onInput(event) {
14093
14913
  content.value = event.target.value;
14094
14914
  }
@@ -14193,7 +15013,7 @@ var comment_default = {
14193
15013
  };
14194
15014
 
14195
15015
  // src/components/signature/index.js
14196
- var import_vue54 = require("vue");
15016
+ var import_vue55 = require("vue");
14197
15017
  var signature_default = {
14198
15018
  name: "DjmSignature",
14199
15019
  props: {
@@ -14207,10 +15027,10 @@ var signature_default = {
14207
15027
  },
14208
15028
  emits: ["update:modelValue", "change", "start", "end", "clear"],
14209
15029
  setup(props, { emit }) {
14210
- const canvas = (0, import_vue54.ref)(null);
14211
- const root = (0, import_vue54.ref)(null);
14212
- const strokes = (0, import_vue54.ref)([]);
14213
- const hasImage = (0, import_vue54.ref)(false);
15030
+ const canvas = (0, import_vue55.ref)(null);
15031
+ const root = (0, import_vue55.ref)(null);
15032
+ const strokes = (0, import_vue55.ref)([]);
15033
+ const hasImage = (0, import_vue55.ref)(false);
14214
15034
  let imageCache = null;
14215
15035
  let drawing = false;
14216
15036
  let current = null;
@@ -14325,7 +15145,7 @@ var signature_default = {
14325
15145
  return canvas.value ? canvas.value.toDataURL("image/png") : "";
14326
15146
  }
14327
15147
  const isEmpty2 = () => strokes.value.length === 0 && !hasImage.value;
14328
- (0, import_vue54.watch)(
15148
+ (0, import_vue55.watch)(
14329
15149
  () => props.modelValue,
14330
15150
  (value) => {
14331
15151
  if (value === lastEmitted) return;
@@ -14347,7 +15167,7 @@ var signature_default = {
14347
15167
  img.src = value;
14348
15168
  }
14349
15169
  );
14350
- (0, import_vue54.onMounted)(() => {
15170
+ (0, import_vue55.onMounted)(() => {
14351
15171
  setupCanvas();
14352
15172
  if (props.modelValue) {
14353
15173
  const img = new Image();
@@ -14363,7 +15183,7 @@ var signature_default = {
14363
15183
  if (root.value) observer.observe(root.value);
14364
15184
  }
14365
15185
  });
14366
- (0, import_vue54.onBeforeUnmount)(() => {
15186
+ (0, import_vue55.onBeforeUnmount)(() => {
14367
15187
  if (observer) observer.disconnect();
14368
15188
  });
14369
15189
  return {
@@ -14403,7 +15223,7 @@ var signature_default = {
14403
15223
  };
14404
15224
 
14405
15225
  // src/components/print/index.js
14406
- var import_vue55 = require("vue");
15226
+ var import_vue56 = require("vue");
14407
15227
  function escapeHtml(text) {
14408
15228
  return String(text).replace(/[&<>"]/g, (ch) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[ch]);
14409
15229
  }
@@ -14419,8 +15239,8 @@ var print_default = {
14419
15239
  },
14420
15240
  emits: ["before-print", "after-print"],
14421
15241
  setup(props, { emit }) {
14422
- const content = (0, import_vue55.ref)(null);
14423
- const label = (0, import_vue55.computed)(() => props.buttonText || t("print.button"));
15242
+ const content = (0, import_vue56.ref)(null);
15243
+ const label = (0, import_vue56.computed)(() => props.buttonText || t("print.button"));
14424
15244
  function collectStyles() {
14425
15245
  return Array.from(document.querySelectorAll('link[rel="stylesheet"], style')).map((el) => el.outerHTML).join("");
14426
15246
  }
@@ -14469,7 +15289,7 @@ var print_default = {
14469
15289
  };
14470
15290
 
14471
15291
  // src/components/gantt/index.js
14472
- var import_vue56 = require("vue");
15292
+ var import_vue57 = require("vue");
14473
15293
  var DAY = 864e5;
14474
15294
  var pad6 = (value) => String(value).padStart(2, "0");
14475
15295
  function parseDate3(value) {
@@ -14505,7 +15325,7 @@ var gantt_default = {
14505
15325
  emits: ["task-click"],
14506
15326
  setup(props, { emit }) {
14507
15327
  const todayKey = toKey4(/* @__PURE__ */ new Date());
14508
- const range = (0, import_vue56.computed)(() => {
15328
+ const range = (0, import_vue57.computed)(() => {
14509
15329
  const starts = props.tasks.map((task) => task.start).filter(Boolean).sort();
14510
15330
  const ends = props.tasks.map((task) => task.end || task.start).filter(Boolean).sort();
14511
15331
  let start = props.startDate || starts[0] || todayKey;
@@ -14518,7 +15338,7 @@ var gantt_default = {
14518
15338
  }
14519
15339
  return { start, end };
14520
15340
  });
14521
- const days = (0, import_vue56.computed)(() => {
15341
+ const days = (0, import_vue57.computed)(() => {
14522
15342
  const total = dayDiff(range.value.end, range.value.start) + 1;
14523
15343
  const base = parseDate3(range.value.start);
14524
15344
  return Array.from({ length: total }, (_, index) => {
@@ -14535,9 +15355,9 @@ var gantt_default = {
14535
15355
  };
14536
15356
  });
14537
15357
  });
14538
- const trackWidth = (0, import_vue56.computed)(() => days.value.length * props.dayWidth);
14539
- const innerWidth = (0, import_vue56.computed)(() => props.nameWidth + trackWidth.value);
14540
- const bars = (0, import_vue56.computed)(
15358
+ const trackWidth = (0, import_vue57.computed)(() => days.value.length * props.dayWidth);
15359
+ const innerWidth = (0, import_vue57.computed)(() => props.nameWidth + trackWidth.value);
15360
+ const bars = (0, import_vue57.computed)(
14541
15361
  () => props.tasks.map((task, index) => {
14542
15362
  const start = task.start || range.value.start;
14543
15363
  const end = task.end || start;
@@ -14553,12 +15373,12 @@ var gantt_default = {
14553
15373
  };
14554
15374
  })
14555
15375
  );
14556
- const todayLeft = (0, import_vue56.computed)(() => {
15376
+ const todayLeft = (0, import_vue57.computed)(() => {
14557
15377
  const index = days.value.findIndex((day) => day.today);
14558
15378
  if (index === -1) return null;
14559
15379
  return props.nameWidth + index * props.dayWidth + props.dayWidth / 2;
14560
15380
  });
14561
- const emptyLabel = (0, import_vue56.computed)(() => props.emptyText || t("gantt.empty"));
15381
+ const emptyLabel = (0, import_vue57.computed)(() => props.emptyText || t("gantt.empty"));
14562
15382
  function onClick(bar) {
14563
15383
  emit("task-click", bar.task);
14564
15384
  }
@@ -14640,7 +15460,7 @@ var gantt_default = {
14640
15460
  };
14641
15461
 
14642
15462
  // src/components/field-list/index.js
14643
- var import_vue57 = require("vue");
15463
+ var import_vue58 = require("vue");
14644
15464
  var uidSeed8 = 0;
14645
15465
  var field_list_default = {
14646
15466
  name: "DjmFieldList",
@@ -14660,7 +15480,7 @@ var field_list_default = {
14660
15480
  },
14661
15481
  emits: ["update:modelValue", "add", "remove", "change"],
14662
15482
  setup(props, { emit }) {
14663
- const uids = (0, import_vue57.ref)([]);
15483
+ const uids = (0, import_vue58.ref)([]);
14664
15484
  function syncUids() {
14665
15485
  const length = props.modelValue.length;
14666
15486
  if (uids.value.length === length) return;
@@ -14669,12 +15489,12 @@ var field_list_default = {
14669
15489
  uids.value = next;
14670
15490
  }
14671
15491
  syncUids();
14672
- (0, import_vue57.watch)(() => props.modelValue.length, syncUids);
14673
- const errors = (0, import_vue57.ref)({});
14674
- const addLabel = (0, import_vue57.computed)(() => props.addText || t("fieldList.add"));
14675
- const emptyLabel = (0, import_vue57.computed)(() => props.emptyText || t("fieldList.empty"));
14676
- const canAdd = (0, import_vue57.computed)(() => !props.disabled && (!props.max || props.modelValue.length < props.max));
14677
- const canRemove = (0, import_vue57.computed)(() => !props.disabled && props.modelValue.length > props.min);
15492
+ (0, import_vue58.watch)(() => props.modelValue.length, syncUids);
15493
+ const errors = (0, import_vue58.ref)({});
15494
+ const addLabel = (0, import_vue58.computed)(() => props.addText || t("fieldList.add"));
15495
+ const emptyLabel = (0, import_vue58.computed)(() => props.emptyText || t("fieldList.empty"));
15496
+ const canAdd = (0, import_vue58.computed)(() => !props.disabled && (!props.max || props.modelValue.length < props.max));
15497
+ const canRemove = (0, import_vue58.computed)(() => !props.disabled && props.modelValue.length > props.min);
14678
15498
  function commit(list) {
14679
15499
  emit("update:modelValue", list);
14680
15500
  emit("change", list);
@@ -14836,7 +15656,7 @@ var field_list_default = {
14836
15656
  };
14837
15657
 
14838
15658
  // src/components/chat/index.js
14839
- var import_vue58 = require("vue");
15659
+ var import_vue59 = require("vue");
14840
15660
  var chat_default = {
14841
15661
  name: "DjmChat",
14842
15662
  components: { DjmAvatar: avatar_default },
@@ -14853,19 +15673,19 @@ var chat_default = {
14853
15673
  },
14854
15674
  emits: ["submit"],
14855
15675
  setup(props, { emit }) {
14856
- const content = (0, import_vue58.ref)("");
14857
- const listRef = (0, import_vue58.ref)(null);
14858
- const placeholderText = (0, import_vue58.computed)(() => props.placeholder || t("chat.placeholder"));
14859
- const sendLabel = (0, import_vue58.computed)(() => props.sendText || t("chat.send"));
14860
- const emptyLabel = (0, import_vue58.computed)(() => props.emptyText || t("chat.empty"));
14861
- const canSend = (0, import_vue58.computed)(() => content.value.trim().length > 0 && !props.disabled && !props.loading);
15676
+ const content = (0, import_vue59.ref)("");
15677
+ const listRef = (0, import_vue59.ref)(null);
15678
+ const placeholderText = (0, import_vue59.computed)(() => props.placeholder || t("chat.placeholder"));
15679
+ const sendLabel = (0, import_vue59.computed)(() => props.sendText || t("chat.send"));
15680
+ const emptyLabel = (0, import_vue59.computed)(() => props.emptyText || t("chat.empty"));
15681
+ const canSend = (0, import_vue59.computed)(() => content.value.trim().length > 0 && !props.disabled && !props.loading);
14862
15682
  function scrollToBottom() {
14863
15683
  const el = listRef.value;
14864
15684
  if (el) el.scrollTop = el.scrollHeight;
14865
15685
  }
14866
- (0, import_vue58.watch)(
15686
+ (0, import_vue59.watch)(
14867
15687
  () => props.messages.length,
14868
- () => (0, import_vue58.nextTick)(scrollToBottom)
15688
+ () => (0, import_vue59.nextTick)(scrollToBottom)
14869
15689
  );
14870
15690
  function onInput(event) {
14871
15691
  content.value = event.target.value;
@@ -14976,7 +15796,7 @@ var chat_default = {
14976
15796
  };
14977
15797
 
14978
15798
  // src/components/org-chart/index.js
14979
- var import_vue59 = require("vue");
15799
+ var import_vue60 = require("vue");
14980
15800
  var org_chart_default = {
14981
15801
  name: "DjmOrgChart",
14982
15802
  components: { DjmAvatar: avatar_default, DjmIcon: icon_default },
@@ -15009,11 +15829,11 @@ var org_chart_default = {
15009
15829
  walk(node);
15010
15830
  return keys;
15011
15831
  }
15012
- const collapsed = (0, import_vue59.ref)(props.defaultExpandAll ? [] : collapsedByDefault(props.data));
15013
- (0, import_vue59.watch)(() => props.data, (data) => {
15832
+ const collapsed = (0, import_vue60.ref)(props.defaultExpandAll ? [] : collapsedByDefault(props.data));
15833
+ (0, import_vue60.watch)(() => props.data, (data) => {
15014
15834
  collapsed.value = props.defaultExpandAll ? [] : collapsedByDefault(data);
15015
15835
  });
15016
- const layout = (0, import_vue59.computed)(() => {
15836
+ const layout = (0, import_vue60.computed)(() => {
15017
15837
  if (!props.data) return { nodes: [], links: [], width: 0, height: 0 };
15018
15838
  const rowH = props.nodeHeight + props.verticalGap;
15019
15839
  let cursor = 0;
@@ -15078,7 +15898,7 @@ var org_chart_default = {
15078
15898
  function onClick(item) {
15079
15899
  emit("node-click", item.node);
15080
15900
  }
15081
- const emptyLabel = (0, import_vue59.computed)(() => props.emptyText || t("orgChart.empty"));
15901
+ const emptyLabel = (0, import_vue60.computed)(() => props.emptyText || t("orgChart.empty"));
15082
15902
  return {
15083
15903
  layout,
15084
15904
  toggle,
@@ -15139,7 +15959,7 @@ var org_chart_default = {
15139
15959
  };
15140
15960
 
15141
15961
  // src/components/page-tabs/index.js
15142
- var import_vue60 = require("vue");
15962
+ var import_vue61 = require("vue");
15143
15963
  var page_tabs_default = {
15144
15964
  name: "DjmPageTabs",
15145
15965
  components: { DjmIcon: icon_default },
@@ -15150,7 +15970,7 @@ var page_tabs_default = {
15150
15970
  },
15151
15971
  emits: ["update:modelValue", "change", "close"],
15152
15972
  setup(props, { emit }) {
15153
- const label = (0, import_vue60.computed)(() => t("pageTabs.label"));
15973
+ const label = (0, import_vue61.computed)(() => t("pageTabs.label"));
15154
15974
  function canClose(tab) {
15155
15975
  return tab.closable === void 0 ? props.closable : tab.closable;
15156
15976
  }
@@ -15260,8 +16080,8 @@ function moveRows(rows, dragIndex, dropIndex, position = "before") {
15260
16080
  }
15261
16081
 
15262
16082
  // src/utils/permission.js
15263
- var import_vue61 = require("vue");
15264
- var state2 = (0, import_vue61.reactive)({
16083
+ var import_vue62 = require("vue");
16084
+ var state2 = (0, import_vue62.reactive)({
15265
16085
  codes: /* @__PURE__ */ new Set()
15266
16086
  });
15267
16087
  function setPermissions(list) {
@@ -15403,7 +16223,7 @@ var components = [
15403
16223
  org_chart_default,
15404
16224
  page_tabs_default
15405
16225
  ];
15406
- var version = "0.67.4";
16226
+ var version = "0.73.0";
15407
16227
  function install(app, options = {}) {
15408
16228
  if (options.locale) setLocale(options.locale);
15409
16229
  components.forEach((component) => app.component(component.name, component));
@@ -15525,6 +16345,7 @@ var index_default = { install, version };
15525
16345
  djmMessage,
15526
16346
  djmMessages,
15527
16347
  getLocale,
16348
+ glass,
15528
16349
  hasPermission,
15529
16350
  initTheme,
15530
16351
  install,
@@ -15534,6 +16355,7 @@ var index_default = { install, version };
15534
16355
  primaryColor,
15535
16356
  resetPrimaryColor,
15536
16357
  sanitizeHtml,
16358
+ setGlass,
15537
16359
  setLocale,
15538
16360
  setPermissions,
15539
16361
  setPrimaryColor,