@iris-ui-kit/vue 0.2.29 → 0.2.30

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 (53) hide show
  1. package/dist/admin.cjs +29 -3
  2. package/dist/admin.cjs.map +1 -1
  3. package/dist/admin.js +3 -3
  4. package/dist/{chunk-X7Y35UUL.js → chunk-3547J6IN.js} +3 -3
  5. package/dist/{chunk-X7Y35UUL.js.map → chunk-3547J6IN.js.map} +1 -1
  6. package/dist/{chunk-BVKOOTXG.js → chunk-IAG64CHL.js} +3 -3
  7. package/dist/chunk-IAG64CHL.js.map +1 -0
  8. package/dist/{chunk-KSJZLFAT.js → chunk-MO7AAXA6.js} +6 -6
  9. package/dist/chunk-MO7AAXA6.js.map +1 -0
  10. package/dist/{chunk-EZUDM4TM.js → chunk-PT6X4543.js} +31 -5
  11. package/dist/chunk-PT6X4543.js.map +1 -0
  12. package/dist/{chunk-W3JMJVEK.js → chunk-TCAXRWT6.js} +3 -3
  13. package/dist/chunk-TCAXRWT6.js.map +1 -0
  14. package/dist/{chunk-KAOPZNZF.js → chunk-UPC4GN3F.js} +3 -3
  15. package/dist/chunk-UPC4GN3F.js.map +1 -0
  16. package/dist/{chunk-X5UOY4IV.js → chunk-W64OMUBD.js} +3 -3
  17. package/dist/{chunk-X5UOY4IV.js.map → chunk-W64OMUBD.js.map} +1 -1
  18. package/dist/{chunk-OH4YSGFK.js → chunk-ZTPIXL7Q.js} +3 -3
  19. package/dist/chunk-ZTPIXL7Q.js.map +1 -0
  20. package/dist/error-boundary.cjs +1 -1
  21. package/dist/error-boundary.cjs.map +1 -1
  22. package/dist/error-boundary.js +2 -2
  23. package/dist/form.cjs +1 -1
  24. package/dist/form.cjs.map +1 -1
  25. package/dist/form.js +1 -1
  26. package/dist/i18n.cjs +1 -1
  27. package/dist/i18n.cjs.map +1 -1
  28. package/dist/i18n.js +1 -1
  29. package/dist/index.cjs +437 -42
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.d.cts +28 -3
  32. package/dist/index.d.ts +28 -3
  33. package/dist/index.js +416 -47
  34. package/dist/index.js.map +1 -1
  35. package/dist/provider.cjs +4 -4
  36. package/dist/provider.cjs.map +1 -1
  37. package/dist/provider.js +4 -4
  38. package/dist/skeletons.cjs +1 -1
  39. package/dist/skeletons.cjs.map +1 -1
  40. package/dist/skeletons.js +2 -2
  41. package/dist/skins.cjs +1 -1
  42. package/dist/skins.cjs.map +1 -1
  43. package/dist/skins.js +1 -1
  44. package/dist/theme.cjs +1 -1
  45. package/dist/theme.cjs.map +1 -1
  46. package/dist/theme.js +1 -1
  47. package/package.json +15 -15
  48. package/dist/chunk-BVKOOTXG.js.map +0 -1
  49. package/dist/chunk-EZUDM4TM.js.map +0 -1
  50. package/dist/chunk-KAOPZNZF.js.map +0 -1
  51. package/dist/chunk-KSJZLFAT.js.map +0 -1
  52. package/dist/chunk-OH4YSGFK.js.map +0 -1
  53. package/dist/chunk-W3JMJVEK.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -55,7 +55,7 @@ function useDisposableScope() {
55
55
  });
56
56
  return scope;
57
57
  }
58
- var IrisThemeKey = Symbol("IrisTheme");
58
+ var IrisThemeKey = /* @__PURE__ */ Symbol("IrisTheme");
59
59
  var ThemeProvider = vue.defineComponent({
60
60
  name: "IrisThemeProvider",
61
61
  props: {
@@ -164,7 +164,7 @@ function useColorScheme() {
164
164
  vue.onBeforeUnmount(stop);
165
165
  return scheme;
166
166
  }
167
- var IrisSkinKey = Symbol("IrisSkin");
167
+ var IrisSkinKey = /* @__PURE__ */ Symbol("IrisSkin");
168
168
  var SkinProvider = vue.defineComponent({
169
169
  name: "IrisSkinProvider",
170
170
  props: {
@@ -243,7 +243,7 @@ function useMachine(machine, options = {}) {
243
243
  );
244
244
  return { state, send: machine.send };
245
245
  }
246
- var FormInjectionKey = Symbol("IrisForm");
246
+ var FormInjectionKey = /* @__PURE__ */ Symbol("IrisForm");
247
247
  function useFormContext() {
248
248
  const form = vue.inject(FormInjectionKey, null);
249
249
  if (!form) {
@@ -367,7 +367,7 @@ function useFieldArray(name) {
367
367
  }
368
368
 
369
369
  // src/i18n/context.ts
370
- var I18nInjectionKey = Symbol("IrisI18n");
370
+ var I18nInjectionKey = /* @__PURE__ */ Symbol("IrisI18n");
371
371
 
372
372
  // src/i18n/I18nProvider.ts
373
373
  var IrisI18nProvider = vue.defineComponent({
@@ -1030,6 +1030,32 @@ var CSS2 = `
1030
1030
  background: var(--iris-nav-item-active-hover, color-mix(in srgb, var(--iris-primary) 88%, black));
1031
1031
  }
1032
1032
 
1033
+ /* \u6C34\u5E73\u6A21\u5F0F\uFF1Aantd \u98CE\u683C\u9009\u4E2D\u6001\uFF08\u4E0B\u5212\u7EBF + \u6587\u5B57\u8272 + \u900F\u660E\u80CC\u666F\uFF09\uFF0C\u800C\u975E
1034
+ vertical \u7684\u6574\u5757 primary \u80CC\u666F\u3002hover \u4E00\u5F8B\u6D45\u80CC\u666F\uFF08active \u9879\u4E5F\u54CD\u5E94\uFF09\u3002 */
1035
+ :where(.iris-nav-menu--horizontal .iris-nav-menu-group > .iris-nav-menu-item) {
1036
+ position: relative;
1037
+ }
1038
+ :where(.iris-nav-menu--horizontal .iris-nav-menu-group > .iris-nav-menu-item):hover {
1039
+ background: var(--iris-nav-item-hover);
1040
+ }
1041
+ :where(.iris-nav-menu--horizontal .iris-nav-menu-group > .iris-nav-menu-item[data-active='true']) {
1042
+ background: transparent;
1043
+ color: var(--iris-primary);
1044
+ font-weight: 600;
1045
+ }
1046
+ :where(.iris-nav-menu--horizontal .iris-nav-menu-group > .iris-nav-menu-item[data-active='true'])::after {
1047
+ content: '';
1048
+ position: absolute;
1049
+ inset-inline: 12px;
1050
+ bottom: 2px;
1051
+ height: 2px;
1052
+ border-radius: 1px;
1053
+ background: var(--iris-primary);
1054
+ }
1055
+ :where(.iris-nav-menu--horizontal .iris-nav-menu-group > .iris-nav-menu-item[data-active='true']):hover {
1056
+ background: var(--iris-nav-item-hover);
1057
+ }
1058
+
1033
1059
  :where(.iris-nav-menu-item[data-active-trail='true']) {
1034
1060
  color: var(--iris-primary);
1035
1061
  font-weight: 600;
@@ -2013,7 +2039,7 @@ function useTabsNav(nav) {
2013
2039
  }
2014
2040
 
2015
2041
  // src/primitives/dropdown/context.ts
2016
- var DropdownContextKey = Symbol("IrisDropdown");
2042
+ var DropdownContextKey = /* @__PURE__ */ Symbol("IrisDropdown");
2017
2043
 
2018
2044
  // src/primitives/dropdown/Dropdown.ts
2019
2045
  var IrisDropdown = vue.defineComponent({
@@ -3430,7 +3456,7 @@ function useUndoStack(options) {
3430
3456
  }
3431
3457
 
3432
3458
  // src/provider/context.ts
3433
- var PluginStoreContextKey = Symbol("IrisPluginStore");
3459
+ var PluginStoreContextKey = /* @__PURE__ */ Symbol("IrisPluginStore");
3434
3460
 
3435
3461
  // src/provider/IrisProvider.ts
3436
3462
  var DEFAULT_LOCALE = "en-US";
@@ -3839,7 +3865,7 @@ var IrisButton = vue.defineComponent({
3839
3865
  });
3840
3866
 
3841
3867
  // src/primitives/popover/context.ts
3842
- var PopoverContextKey = Symbol("IrisPopover");
3868
+ var PopoverContextKey = /* @__PURE__ */ Symbol("IrisPopover");
3843
3869
 
3844
3870
  // src/primitives/popover/Popover.ts
3845
3871
  var IrisPopover = vue.defineComponent({
@@ -4170,12 +4196,12 @@ var IrisTooltip = vue.defineComponent({
4170
4196
  const triggerListeners = {
4171
4197
  onPointerenter: handleEnter,
4172
4198
  onPointerleave: handleLeave,
4173
- onFocus: () => {
4199
+ onFocus: (() => {
4174
4200
  if (!props.disabled) hi.open();
4175
- },
4176
- onBlur: () => {
4201
+ }),
4202
+ onBlur: (() => {
4177
4203
  if (!props.disabled) hi.close();
4178
- }
4204
+ })
4179
4205
  };
4180
4206
  const captureTriggerRef = (el) => {
4181
4207
  triggerRef.value = el ?? null;
@@ -4244,7 +4270,7 @@ var IrisTooltip = vue.defineComponent({
4244
4270
  });
4245
4271
 
4246
4272
  // src/primitives/dialog/context.ts
4247
- var DialogContextKey = Symbol("IrisDialog");
4273
+ var DialogContextKey = /* @__PURE__ */ Symbol("IrisDialog");
4248
4274
 
4249
4275
  // src/primitives/dialog/Dialog.ts
4250
4276
  var IrisDialog = vue.defineComponent({
@@ -4702,7 +4728,7 @@ var IrisDialogClose = vue.defineComponent({
4702
4728
  });
4703
4729
 
4704
4730
  // src/primitives/drawer/context.ts
4705
- var DrawerContextKey = Symbol("IrisDrawer");
4731
+ var DrawerContextKey = /* @__PURE__ */ Symbol("IrisDrawer");
4706
4732
 
4707
4733
  // src/primitives/drawer/Drawer.ts
4708
4734
  var IrisDrawer = vue.defineComponent({
@@ -6712,7 +6738,7 @@ var IrisCheckbox = vue.defineComponent({
6712
6738
  );
6713
6739
  }
6714
6740
  });
6715
- var RadioGroupKey = Symbol("IrisRadioGroup");
6741
+ var RadioGroupKey = /* @__PURE__ */ Symbol("IrisRadioGroup");
6716
6742
  var IrisRadioGroup = vue.defineComponent({
6717
6743
  name: "IrisRadioGroup",
6718
6744
  props: {
@@ -7990,8 +8016,8 @@ var IrisSkeleton = vue.defineComponent({
7990
8016
  vue.onMounted(installSkeletonStyles);
7991
8017
  const style = vue.computed(() => {
7992
8018
  const w = props.width !== void 0 ? toCss(props.width) : defaultWidth(props.shape);
7993
- const h136 = props.height !== void 0 ? toCss(props.height) : defaultHeight(props.shape, props.width);
7994
- return { width: w, height: h136 };
8019
+ const h137 = props.height !== void 0 ? toCss(props.height) : defaultHeight(props.shape, props.width);
8020
+ return { width: w, height: h137 };
7995
8021
  });
7996
8022
  return () => vue.h("div", {
7997
8023
  ...attrs,
@@ -9102,7 +9128,7 @@ var IrisChip = vue.defineComponent({
9102
9128
  });
9103
9129
 
9104
9130
  // src/primitives/accordion/context.ts
9105
- var AccordionContextKey = Symbol("IrisAccordion");
9131
+ var AccordionContextKey = /* @__PURE__ */ Symbol("IrisAccordion");
9106
9132
 
9107
9133
  // src/primitives/accordion/Accordion.ts
9108
9134
  var IrisAccordion = vue.defineComponent({
@@ -9340,7 +9366,7 @@ var IrisAccordionItem = vue.defineComponent({
9340
9366
  });
9341
9367
 
9342
9368
  // src/primitives/stepper/context.ts
9343
- var StepperContextKey = Symbol("IrisStepper");
9369
+ var StepperContextKey = /* @__PURE__ */ Symbol("IrisStepper");
9344
9370
 
9345
9371
  // src/primitives/stepper/Stepper.ts
9346
9372
  var IrisStepper = vue.defineComponent({
@@ -9588,7 +9614,7 @@ var IrisStepperStep = vue.defineComponent({
9588
9614
  });
9589
9615
 
9590
9616
  // src/primitives/toggle-group/context.ts
9591
- var ToggleGroupContextKey = Symbol("IrisToggleGroup");
9617
+ var ToggleGroupContextKey = /* @__PURE__ */ Symbol("IrisToggleGroup");
9592
9618
  var SIZE_PADDING = {
9593
9619
  sm: "4px 10px",
9594
9620
  md: "6px 14px",
@@ -10640,6 +10666,24 @@ var tableProps = {
10640
10666
  type: Object,
10641
10667
  default: void 0
10642
10668
  },
10669
+ /** Audit log (batch EN, iris 独有 — mirror react batch AT): when true,
10670
+ * every mutation commit appends ONE entry to a bounded (200) ring —
10671
+ * inline/row cell edits (recorded directly at the commit point, type
10672
+ * 'edit' + rowKey + column + old→new) and the row-list funnels available
10673
+ * here (removeRows — list diff, type 'remove'; loadData — list diff, type
10674
+ * 'edit', react commitRowList default parity). External re-feeds (parent
10675
+ * data / proxy refetch / rowDrag reorder) re-baseline the diff snapshot
10676
+ * and never record. The toolbar gains an audit trigger
10677
+ * (`data-iris-audit-trigger`) opening a floating panel
10678
+ * (`data-iris-audit-panel`, like the filter/context panels — Esc /
10679
+ * outside / scroll close) listing newest-first entries (seq +
10680
+ * `formatClock` time + type + rowKey + column + muted old→new);
10681
+ * `getAuditLog()` / `clearAuditLog()` on the exposed handle access the
10682
+ * trail programmatically (the seq never resets on clear — audit
10683
+ * integrity). Requires a toolbar render (the gate admits `auditLog` like
10684
+ * `densityToggle`). Additive — default off; off = zero push.
10685
+ */
10686
+ auditLog: { type: Boolean, default: false },
10643
10687
  columnVisibility: {
10644
10688
  type: Object,
10645
10689
  default: void 0
@@ -10690,10 +10734,28 @@ var DRAG_COL_WIDTH = 40;
10690
10734
  var DEFAULT_COL_WIDTH = 140;
10691
10735
  var DEFAULT_MIN_WIDTH = 60;
10692
10736
  var RESIZE_STEP = 16;
10737
+ function isEditableColumn(column) {
10738
+ return !!column.editable && !column.formula;
10739
+ }
10693
10740
  function getCellValue(row, column) {
10741
+ if (column.formula) return core.memoizedFormulaValue(column.formula, row);
10694
10742
  const key = column.dataIndex ?? column.key;
10695
10743
  return row[key];
10696
10744
  }
10745
+ function withComputedFormulaCells(rows, columns) {
10746
+ const formulaCols = columns.filter((c) => c.formula);
10747
+ if (formulaCols.length === 0) return rows;
10748
+ return rows.map((row) => {
10749
+ let shadow = null;
10750
+ for (const col of formulaCols) {
10751
+ const key = col.dataIndex ?? col.key;
10752
+ const next = shadow ?? { ...row };
10753
+ next[key] = core.memoizedFormulaValue(col.formula, row);
10754
+ shadow = next;
10755
+ }
10756
+ return shadow;
10757
+ });
10758
+ }
10697
10759
  function resolveSpan(occupied, rowIndex, columnIndex, method) {
10698
10760
  if (!method) return { rowspan: 1, colspan: 1 };
10699
10761
  const key = `${rowIndex}:${columnIndex}`;
@@ -11055,7 +11117,7 @@ var toolbarBtnStyle = {
11055
11117
  };
11056
11118
  function renderToolbarSection(ctx) {
11057
11119
  const tb = ctx.toolbar;
11058
- if (!tb && !ctx.densityToggle) return null;
11120
+ if (!tb && !ctx.densityToggle && !ctx.auditLog) return null;
11059
11121
  const toolChildren = [];
11060
11122
  if (tb?.title) {
11061
11123
  toolChildren.push(
@@ -11209,6 +11271,28 @@ function renderToolbarSection(ctx) {
11209
11271
  )
11210
11272
  );
11211
11273
  }
11274
+ if (ctx.auditLog) {
11275
+ toolChildren.push(
11276
+ vue.h(
11277
+ "button",
11278
+ {
11279
+ ref: (el) => {
11280
+ ctx.auditAnchorRef.value = el ?? null;
11281
+ },
11282
+ type: "button",
11283
+ "data-iris-audit-trigger": "",
11284
+ "aria-label": ctx.t("table.audit"),
11285
+ title: ctx.t("table.audit"),
11286
+ onClick: ctx.onAuditToggle,
11287
+ style: {
11288
+ ...toolbarBtnStyle,
11289
+ color: ctx.auditOpen.value ? "var(--iris-foreground)" : "var(--iris-muted)"
11290
+ }
11291
+ },
11292
+ "\u2630"
11293
+ )
11294
+ );
11295
+ }
11212
11296
  return vue.h(
11213
11297
  "div",
11214
11298
  {
@@ -11429,6 +11513,233 @@ function renderFilterPanelSection(ctx) {
11429
11513
  );
11430
11514
  return vue.h(vue.Teleport, { to: "body" }, [node]);
11431
11515
  }
11516
+ function auditDiff(prev, next, resolveKey) {
11517
+ const len = Math.max(prev.length, next.length);
11518
+ for (let i = 0; i < len; i += 1) {
11519
+ const a = prev[i];
11520
+ const b = next[i];
11521
+ if (a === b) continue;
11522
+ if (!a || !b) return { rowKey: a ? resolveKey(a, i) : resolveKey(b, i) };
11523
+ const ka = resolveKey(a, i);
11524
+ const kb = resolveKey(b, i);
11525
+ if (ka !== kb) {
11526
+ return { rowKey: prev.length > next.length ? ka : kb };
11527
+ }
11528
+ const fields = /* @__PURE__ */ new Set();
11529
+ Object.keys(a).forEach((f) => fields.add(f));
11530
+ Object.keys(b).forEach((f) => fields.add(f));
11531
+ for (const f of fields) {
11532
+ if (a[f] !== b[f]) {
11533
+ return { rowKey: ka, column: f, oldValue: a[f], newValue: b[f] };
11534
+ }
11535
+ }
11536
+ }
11537
+ return void 0;
11538
+ }
11539
+ function renderAuditPanelSection(ctx) {
11540
+ if (!ctx.open.value) return null;
11541
+ return vue.h(vue.Teleport, { to: "body" }, [
11542
+ vue.h(TableAuditPanel, {
11543
+ audit: ctx.audit,
11544
+ styles: ctx.styles.value,
11545
+ panelRef: ctx.panelRef,
11546
+ onClear: ctx.onClear,
11547
+ t: ctx.t
11548
+ })
11549
+ ]);
11550
+ }
11551
+ var TableAuditPanel = vue.defineComponent({
11552
+ name: "TableAuditPanel",
11553
+ props: {
11554
+ audit: { type: Object, required: true },
11555
+ styles: { type: Object, required: true },
11556
+ panelRef: { type: Object, required: true },
11557
+ onClear: { type: Function, required: true },
11558
+ t: { type: Function, required: true }
11559
+ },
11560
+ setup(props) {
11561
+ const entries = vue.ref(props.audit.list());
11562
+ let unsubscribe = null;
11563
+ vue.onMounted(() => {
11564
+ unsubscribe = props.audit.subscribe(() => {
11565
+ entries.value = props.audit.list();
11566
+ });
11567
+ });
11568
+ vue.onScopeDispose(() => {
11569
+ unsubscribe?.();
11570
+ unsubscribe = null;
11571
+ });
11572
+ return () => {
11573
+ const items = entries.value;
11574
+ return vue.h(
11575
+ "div",
11576
+ {
11577
+ ref: (el) => {
11578
+ props.panelRef.value = el ?? null;
11579
+ },
11580
+ role: "dialog",
11581
+ "aria-label": props.t("table.audit"),
11582
+ "data-iris-audit-panel": "",
11583
+ style: {
11584
+ ...props.styles,
11585
+ zIndex: "var(--iris-z-popover, 1000)",
11586
+ background: "var(--iris-surface-floating, var(--iris-surface))",
11587
+ color: "var(--iris-foreground)",
11588
+ border: "1px solid var(--iris-border)",
11589
+ borderRadius: "var(--iris-radius-md, 6px)",
11590
+ boxShadow: "var(--iris-shadow-lg)",
11591
+ padding: "var(--iris-space-sm, 12px)",
11592
+ minWidth: 280,
11593
+ maxWidth: 360,
11594
+ display: "flex",
11595
+ flexDirection: "column",
11596
+ gap: "var(--iris-space-xs, 8px)",
11597
+ fontSize: "var(--iris-font-size-sm, 13px)"
11598
+ }
11599
+ },
11600
+ [
11601
+ vue.h(
11602
+ "div",
11603
+ { style: { display: "flex", alignItems: "center", gap: "var(--iris-space-xs, 8px)" } },
11604
+ [
11605
+ vue.h("span", { style: { fontWeight: 600, flex: 1 } }, props.t("table.audit")),
11606
+ items.length > 0 ? vue.h(
11607
+ "button",
11608
+ {
11609
+ type: "button",
11610
+ "data-iris-audit-clear": "",
11611
+ onClick: props.onClear,
11612
+ style: {
11613
+ border: "1px solid var(--iris-border)",
11614
+ borderRadius: "var(--iris-radius-sm, 4px)",
11615
+ background: "transparent",
11616
+ color: "var(--iris-muted)",
11617
+ cursor: "pointer",
11618
+ padding: "var(--iris-space-xxs, 4px) var(--iris-space-xs, 8px)",
11619
+ fontSize: "var(--iris-font-size-xs, 12px)"
11620
+ }
11621
+ },
11622
+ props.t("table.audit.clear")
11623
+ ) : null
11624
+ ]
11625
+ ),
11626
+ items.length === 0 ? vue.h(
11627
+ "div",
11628
+ {
11629
+ "data-iris-audit-empty": "",
11630
+ style: {
11631
+ color: "var(--iris-muted)",
11632
+ textAlign: "center",
11633
+ padding: "var(--iris-space-sm, 12px)"
11634
+ }
11635
+ },
11636
+ props.t("table.audit.empty")
11637
+ ) : vue.h(
11638
+ "div",
11639
+ {
11640
+ "data-iris-audit-entries": "",
11641
+ style: {
11642
+ display: "flex",
11643
+ flexDirection: "column",
11644
+ gap: "var(--iris-space-xxs, 4px)",
11645
+ maxHeight: 240,
11646
+ overflowY: "auto"
11647
+ }
11648
+ },
11649
+ items.map(
11650
+ (e) => vue.h(
11651
+ "div",
11652
+ {
11653
+ key: e.seq,
11654
+ "data-iris-audit-entry": "",
11655
+ style: {
11656
+ display: "flex",
11657
+ alignItems: "baseline",
11658
+ gap: "var(--iris-space-xs, 8px)",
11659
+ padding: "var(--iris-space-xxs, 4px) 0",
11660
+ borderBottom: "1px solid var(--iris-border-subtle, var(--iris-border))",
11661
+ fontSize: "var(--iris-font-size-xs, 12px)"
11662
+ }
11663
+ },
11664
+ [
11665
+ vue.h(
11666
+ "span",
11667
+ {
11668
+ "data-iris-audit-seq": "",
11669
+ style: { color: "var(--iris-muted)", minWidth: 30 }
11670
+ },
11671
+ `#${e.seq}`
11672
+ ),
11673
+ vue.h(
11674
+ "span",
11675
+ {
11676
+ "data-iris-audit-time": "",
11677
+ style: { color: "var(--iris-muted)", minWidth: 64 }
11678
+ },
11679
+ core.formatClock(new Date(e.at))
11680
+ ),
11681
+ vue.h(
11682
+ "span",
11683
+ {
11684
+ "data-iris-audit-type": "",
11685
+ style: {
11686
+ color: "var(--iris-primary)",
11687
+ fontWeight: 600,
11688
+ textTransform: "uppercase"
11689
+ }
11690
+ },
11691
+ e.type
11692
+ ),
11693
+ vue.h(
11694
+ "span",
11695
+ {
11696
+ "data-iris-audit-rowkey": "",
11697
+ style: { color: "var(--iris-foreground)" }
11698
+ },
11699
+ e.rowKey !== void 0 ? String(e.rowKey) : "\u2014"
11700
+ ),
11701
+ e.column !== void 0 ? vue.h(
11702
+ "span",
11703
+ {
11704
+ "data-iris-audit-cell": "",
11705
+ style: { color: "var(--iris-muted)", flex: 1 }
11706
+ },
11707
+ [
11708
+ e.column,
11709
+ vue.h(
11710
+ "span",
11711
+ {
11712
+ style: {
11713
+ display: "inline-flex",
11714
+ gap: "var(--iris-space-xxs, 4px)",
11715
+ marginInlineStart: "var(--iris-space-xs, 8px)"
11716
+ }
11717
+ },
11718
+ [
11719
+ vue.h(
11720
+ "span",
11721
+ { "data-iris-audit-old": "" },
11722
+ String(e.oldValue ?? "")
11723
+ ),
11724
+ vue.h("span", { "aria-hidden": "true" }, "\u2192"),
11725
+ vue.h(
11726
+ "span",
11727
+ { "data-iris-audit-new": "" },
11728
+ String(e.newValue ?? "")
11729
+ )
11730
+ ]
11731
+ )
11732
+ ]
11733
+ ) : null
11734
+ ]
11735
+ )
11736
+ )
11737
+ )
11738
+ ]
11739
+ );
11740
+ };
11741
+ }
11742
+ });
11432
11743
  function renderImportPreviewSection(ctx) {
11433
11744
  if (!ctx.rows) return null;
11434
11745
  const columns = core.previewColumnsFromRows(ctx.rows);
@@ -11756,9 +12067,10 @@ function createTableKeyboard(options) {
11756
12067
  const range = activeCellRange();
11757
12068
  const clip = options.clipConfig();
11758
12069
  if (!range || clip?.copy === false) return;
12070
+ const rows = withComputedFormulaCells(options.rows(), options.columns());
11759
12071
  void core.writeClipboardText(
11760
12072
  core.serializeTableRange(
11761
- options.rows(),
12073
+ rows,
11762
12074
  options.columns(),
11763
12075
  range,
11764
12076
  clip?.copyFormat,
@@ -12702,10 +13014,9 @@ var IrisTable = vue.defineComponent({
12702
13014
  detectTypesDone.value = true;
12703
13015
  const next = {};
12704
13016
  for (const column of core.flattenLeafColumns(props.columns)) {
12705
- const candidate = column;
12706
- if (candidate.formula) continue;
13017
+ if (column.formula) continue;
12707
13018
  next[column.key] = core.detectColumnType(
12708
- tableData.value.map((row) => getCellValue(row, candidate))
13019
+ tableData.value.map((row) => getCellValue(row, column))
12709
13020
  );
12710
13021
  }
12711
13022
  detectedTypes.value = next;
@@ -12842,6 +13153,17 @@ var IrisTable = vue.defineComponent({
12842
13153
  if (typeof v === "string" || typeof v === "number") return v;
12843
13154
  return index;
12844
13155
  };
13156
+ const audit = core.createAuditLog();
13157
+ const auditRowsRef = vue.ref(tableData.value);
13158
+ vue.watch(tableData, (next) => {
13159
+ auditRowsRef.value = next;
13160
+ });
13161
+ const recordAudit = (next, type) => {
13162
+ if (!props.auditLog) return;
13163
+ const entry = auditDiff(auditRowsRef.value, next, (r, i) => rowId(r, i));
13164
+ if (entry) audit.push({ type, ...entry });
13165
+ auditRowsRef.value = next;
13166
+ };
12845
13167
  const treeMode = vue.computed(() => props.getSubRows !== void 0 || props.lazyLoad !== void 0);
12846
13168
  const lazyChildren = vue.ref(/* @__PURE__ */ new Map());
12847
13169
  const lazyLoading = vue.ref(/* @__PURE__ */ new Set());
@@ -12991,7 +13313,7 @@ var IrisTable = vue.defineComponent({
12991
13313
  const editError = vue.ref(null);
12992
13314
  const editorInputRef = vue.ref(null);
12993
13315
  const beginEdit = (row, column, rowIdent) => {
12994
- if (!column.editable) return;
13316
+ if (!isEditableColumn(column)) return;
12995
13317
  editingCellId.value = cellId(rowIdent, column.key);
12996
13318
  editingColumnKey.value = column.key;
12997
13319
  const current = getCellValue(row, column);
@@ -13031,6 +13353,15 @@ var IrisTable = vue.defineComponent({
13031
13353
  };
13032
13354
  const writeCellValue = (row, column, rowIndex, oldValue, newValue) => {
13033
13355
  if (newValue === oldValue) return;
13356
+ if (props.auditLog) {
13357
+ audit.push({
13358
+ type: "edit",
13359
+ rowKey: rowId(row, rowIndex),
13360
+ column: column.dataIndex ?? column.key,
13361
+ oldValue,
13362
+ newValue
13363
+ });
13364
+ }
13034
13365
  emit("cellEdit", { row, column, oldValue, newValue, rowIndex });
13035
13366
  if (proxyCtrl.proxy.value) {
13036
13367
  const id = rowId(row, rowIndex);
@@ -13064,7 +13395,7 @@ var IrisTable = vue.defineComponent({
13064
13395
  const currentRowFor = (k) => bodyData.value.find((r, i) => rowId(r, i) === k);
13065
13396
  const beginRowEdit = (row, rowIndex, focusColKey) => {
13066
13397
  const k = rowId(row, rowIndex);
13067
- const editableCols = leafColumns.value.filter((c) => c.editable);
13398
+ const editableCols = leafColumns.value.filter(isEditableColumn);
13068
13399
  if (editableCols.length === 0) return;
13069
13400
  const sessions = /* @__PURE__ */ new Map();
13070
13401
  for (const col of editableCols) {
@@ -13135,7 +13466,7 @@ var IrisTable = vue.defineComponent({
13135
13466
  const handleRowModeCellClick = (row, col, index, k) => {
13136
13467
  if (rowEditing.value?.k === k) {
13137
13468
  const id = cellId(k, col.key);
13138
- if (col.editable && !rowSessions.value.has(id)) {
13469
+ if (isEditableColumn(col) && !rowSessions.value.has(id)) {
13139
13470
  const current = getCellValue(row, col);
13140
13471
  rowSessions.value.set(id, {
13141
13472
  draft: current == null ? "" : String(current),
@@ -13551,6 +13882,7 @@ var IrisTable = vue.defineComponent({
13551
13882
  const spanOccupy = /* @__PURE__ */ new Set();
13552
13883
  const tableExpose = {
13553
13884
  loadData: (rows) => {
13885
+ recordAudit(rows, "edit");
13554
13886
  if (proxyCtrl.proxy.value) proxyCtrl.liveData.value = rows;
13555
13887
  else localRowsOverride.value = rows;
13556
13888
  props.onDataChange?.(rows);
@@ -13569,6 +13901,7 @@ var IrisTable = vue.defineComponent({
13569
13901
  removeRows: (keys) => {
13570
13902
  const { rows, removedKeys } = core.removeRowsFromList(tableData.value, props.rowKey, keys);
13571
13903
  if (removedKeys.size === 0) return;
13904
+ recordAudit(rows, "remove");
13572
13905
  if (proxyCtrl.proxy.value) proxyCtrl.liveData.value = rows;
13573
13906
  else localRowsOverride.value = rows;
13574
13907
  const selected = displaySelection.value;
@@ -13580,9 +13913,15 @@ var IrisTable = vue.defineComponent({
13580
13913
  props.onDataChange?.(rows);
13581
13914
  },
13582
13915
  getFilteredData: () => [...bodyData.value],
13583
- exportCurrentViewCsv: () => exportCsv(bodyData.value, leafColumns.value),
13916
+ exportCurrentViewCsv: () => exportCsv(
13917
+ withComputedFormulaCells(bodyData.value, leafColumns.value),
13918
+ leafColumns.value
13919
+ ),
13584
13920
  exportMultiCsv: () => {
13585
- const current = exportCsv(bodyData.value, leafColumns.value);
13921
+ const current = exportCsv(
13922
+ withComputedFormulaCells(bodyData.value, leafColumns.value),
13923
+ leafColumns.value
13924
+ );
13586
13925
  const names = props.exportNames;
13587
13926
  if (!names || names.length === 0) return current;
13588
13927
  const segments = [`# current${current ? `
@@ -13597,7 +13936,14 @@ ${refCsv}` : ""}`);
13597
13936
  },
13598
13937
  compareStates: core.compareStates,
13599
13938
  scrollToRow,
13600
- goToRow
13939
+ goToRow,
13940
+ // Batch EN (iris 独有): audit trail programmatic access — a snapshot
13941
+ // (newest-first entries) and a wipe, both against the ref-once
13942
+ // controller; the seq counter never resets on clear (audit integrity).
13943
+ getAuditLog: () => audit.list(),
13944
+ clearAuditLog: () => {
13945
+ audit.clear();
13946
+ }
13601
13947
  };
13602
13948
  expose(tableExpose);
13603
13949
  const buildFormSection = () => renderFormSection({
@@ -13608,6 +13954,48 @@ ${refCsv}` : ""}`);
13608
13954
  handleFormSubmit,
13609
13955
  handleFormReset
13610
13956
  });
13957
+ const auditOpen = vue.ref(false);
13958
+ const auditAnchorRef = vue.ref(null);
13959
+ const auditPanelRef = vue.ref(null);
13960
+ const toggleAuditPanel = () => {
13961
+ auditOpen.value = !auditOpen.value;
13962
+ };
13963
+ const closeAuditPanel = () => {
13964
+ auditOpen.value = false;
13965
+ };
13966
+ const clearAudit = () => {
13967
+ audit.clear();
13968
+ };
13969
+ const { floatingStyles: auditPanelStyles } = useFloating({
13970
+ anchor: auditAnchorRef,
13971
+ floating: auditPanelRef,
13972
+ open: auditOpen,
13973
+ placement: "bottom-end",
13974
+ flip: false,
13975
+ shift: true
13976
+ });
13977
+ useDismiss({
13978
+ enabled: auditOpen,
13979
+ exclude: [auditPanelRef, auditAnchorRef],
13980
+ onDismiss: closeAuditPanel
13981
+ });
13982
+ vue.watch(auditOpen, (open) => {
13983
+ if (typeof document === "undefined") return;
13984
+ if (open) document.addEventListener("scroll", closeAuditPanel, true);
13985
+ else document.removeEventListener("scroll", closeAuditPanel, true);
13986
+ });
13987
+ vue.onScopeDispose(() => {
13988
+ if (typeof document === "undefined") return;
13989
+ document.removeEventListener("scroll", closeAuditPanel, true);
13990
+ });
13991
+ const buildAuditPanelSection = () => renderAuditPanelSection({
13992
+ open: auditOpen,
13993
+ audit,
13994
+ styles: auditPanelStyles,
13995
+ panelRef: auditPanelRef,
13996
+ onClear: clearAudit,
13997
+ t
13998
+ });
13611
13999
  const buildToolbarSection = () => renderToolbarSection({
13612
14000
  toolbar: props.toolbar,
13613
14001
  selectable: props.selectable,
@@ -13618,7 +14006,13 @@ ${refCsv}` : ""}`);
13618
14006
  onImportFile: importController.handleImportFile,
13619
14007
  densityToggle: props.densityToggle,
13620
14008
  effectiveDensity: effectiveDensity.value,
13621
- onDensityToggle: cycleDensity
14009
+ onDensityToggle: cycleDensity,
14010
+ // Batch EN: the built-in audit trigger rides the toolbar (react
14011
+ // parity — the toolbar gate admits auditLog on its own).
14012
+ auditLog: props.auditLog,
14013
+ auditOpen,
14014
+ auditAnchorRef,
14015
+ onAuditToggle: toggleAuditPanel
13622
14016
  });
13623
14017
  const buildPagerSection = () => renderPagerSection({ proxyCtrl, proxyConfig: props.proxyConfig });
13624
14018
  const contextMenuState = vue.ref(null);
@@ -14187,7 +14581,7 @@ ${refCsv}` : ""}`);
14187
14581
  rowSessions.value.get(editCellId)
14188
14582
  ) : buildCellEditContent(row, col, index, editCellId);
14189
14583
  } else {
14190
- content = cellSlot?.({ row, index, value: getCellValue(row, col) }) ?? core.tableDisplayText(row, col);
14584
+ content = cellSlot?.({ row, index, value: getCellValue(row, col) }) ?? core.tableDisplayText(row, col, getCellValue);
14191
14585
  }
14192
14586
  const treeIndent = treeMeta && ci === 0 ? buildTreeIndent(treeMeta, row) : null;
14193
14587
  const cellChildren = treeIndent ? [treeIndent, ...Array.isArray(content) ? content : [content]] : content;
@@ -14199,7 +14593,7 @@ ${refCsv}` : ""}`);
14199
14593
  role: "cell",
14200
14594
  "data-iris-table-cell": col.key,
14201
14595
  "data-iris-table-pinned": col.pinned,
14202
- "data-editable": col.editable ? "" : void 0,
14596
+ "data-editable": isEditableColumn(col) ? "" : void 0,
14203
14597
  "data-editing": isEditing ? "" : void 0,
14204
14598
  "data-iris-input-hint": patternHint ? "true" : void 0,
14205
14599
  // Grid keyboard navigation (opt-in): grid coords + roving tabindex
@@ -14225,11 +14619,11 @@ ${refCsv}` : ""}`);
14225
14619
  }
14226
14620
  }
14227
14621
  } : {},
14228
- onDblclick: rowMode.value ? () => switchRowEdit(row, index, col.key) : col.editable ? () => beginEdit(row, col, id) : void 0,
14622
+ onDblclick: rowMode.value ? () => switchRowEdit(row, index, col.key) : isEditableColumn(col) ? () => beginEdit(row, col, id) : void 0,
14229
14623
  onClick: rowMode.value ? () => handleRowModeCellClick(row, col, index, id) : props.cellRange ? (e) => {
14230
14624
  if (e.shiftKey) cellRangeCtrl.extendRange(index, ci);
14231
14625
  else cellRangeCtrl.startRange(index, ci);
14232
- } : col.editable && props.editConfig?.trigger === "click" ? () => beginEdit(row, col, id) : void 0,
14626
+ } : isEditableColumn(col) && props.editConfig?.trigger === "click" ? () => beginEdit(row, col, id) : void 0,
14233
14627
  onContextmenu: props.contextMenu ? (e) => handleContextMenu(e, row, col, index, ci) : void 0,
14234
14628
  style: {
14235
14629
  display: "flex",
@@ -14243,7 +14637,7 @@ ${refCsv}` : ""}`);
14243
14637
  whiteSpace: "nowrap",
14244
14638
  overflow: "hidden",
14245
14639
  textOverflow: "ellipsis",
14246
- cursor: col.editable ? "cell" : "default",
14640
+ cursor: isEditableColumn(col) ? "cell" : "default",
14247
14641
  ...props.cellRange && isInRange(index, ci) ? { background: "var(--iris-surface-selected, rgba(99,102,241,0.12))" } : {},
14248
14642
  ...visibleColSet.value ? { gridColumnStart: String(colTrack(ci)) } : {},
14249
14643
  ...colspan > 1 ? { gridColumnEnd: `span ${colspan}` } : {},
@@ -14465,7 +14859,8 @@ ${refCsv}` : ""}`);
14465
14859
  [vue.h("span", { "aria-hidden": "true" }, "\u21C6"), vue.h("span", t("table.scrollHint"))]
14466
14860
  ) : null,
14467
14861
  buildContextMenuSection(),
14468
- buildFilterPanelSection()
14862
+ buildFilterPanelSection(),
14863
+ buildAuditPanelSection()
14469
14864
  ].filter((n) => n !== null);
14470
14865
  return rootNodes.length === 1 ? rootNodes[0] : rootNodes;
14471
14866
  };
@@ -14491,7 +14886,7 @@ async function downloadExcel(filename, xml) {
14491
14886
  }
14492
14887
 
14493
14888
  // src/primitives/tabs/context.ts
14494
- var TabsContextKey = Symbol("IrisTabs");
14889
+ var TabsContextKey = /* @__PURE__ */ Symbol("IrisTabs");
14495
14890
 
14496
14891
  // src/primitives/tabs/Tabs.ts
14497
14892
  var IrisTabs = vue.defineComponent({
@@ -14791,7 +15186,7 @@ var IrisTabsContent = vue.defineComponent({
14791
15186
  });
14792
15187
 
14793
15188
  // src/primitives/menu/context.ts
14794
- var MenuContextKey = Symbol("IrisMenu");
15189
+ var MenuContextKey = /* @__PURE__ */ Symbol("IrisMenu");
14795
15190
 
14796
15191
  // src/primitives/menu/Menu.ts
14797
15192
  var IrisMenu = vue.defineComponent({
@@ -21263,12 +21658,12 @@ function defaultFilter(query, item) {
21263
21658
  if (!q) return 0;
21264
21659
  const haystacks = [item.label, ...item.keywords ?? []].map((s) => s.toLowerCase());
21265
21660
  let best = null;
21266
- for (const h136 of haystacks) {
21661
+ for (const h137 of haystacks) {
21267
21662
  let qi = 0;
21268
21663
  let lastIdx = -1;
21269
21664
  let score = 0;
21270
- for (let i = 0; i < h136.length && qi < q.length; i += 1) {
21271
- if (h136[i] === q[qi]) {
21665
+ for (let i = 0; i < h137.length && qi < q.length; i += 1) {
21666
+ if (h137[i] === q[qi]) {
21272
21667
  score += lastIdx === -1 ? i : i - lastIdx - 1;
21273
21668
  lastIdx = i;
21274
21669
  qi += 1;