rj-grid 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/rj-grid.js CHANGED
@@ -564,6 +564,9 @@ function useColumnState(sourceColumns) {
564
564
  widthMap.set(colIdOf(c), clampWidth(Math.round(cur[i] * factor), c));
565
565
  });
566
566
  }
567
+ function clearWidths() {
568
+ widthMap.clear();
569
+ }
567
570
  function moveColumn(dragId, targetId) {
568
571
  if (dragId === targetId)
569
572
  return;
@@ -637,6 +640,7 @@ function useColumnState(sourceColumns) {
637
640
  setAutoWidth,
638
641
  hasSizedWidth,
639
642
  sizeToFit,
643
+ clearWidths,
640
644
  moveColumn,
641
645
  togglePin,
642
646
  toggleHide,
@@ -4058,6 +4062,7 @@ const zhCN = {
4058
4062
  expServerNoPdf: "后端导出不含 PDF(浏览器打印属前端渲染),已改用前端范围",
4059
4063
  expServerMissing: "未接入后端导出:请设置 serverExport 回调",
4060
4064
  expFailed: "导出失败",
4065
+ printCap: "数据量较大:仅打印前 {n} 行(共 {total} 行)。请缩小范围或走后端导出获取全量",
4061
4066
  resetState: "重置列状态",
4062
4067
  groupBanner: "⬇ 将列标题拖到此处进行行分组(或点面板“分组”页签)",
4063
4068
  // 加载 / 空态
@@ -4222,6 +4227,7 @@ const zhCN = {
4222
4227
  querySearch: "查询",
4223
4228
  queryReset: "重置",
4224
4229
  querySaveView: "存为视图",
4230
+ queryRemove: "移除该条件",
4225
4231
  queryInput: "请输入",
4226
4232
  // 行编辑弹窗与内置确认框(查询栏操作按钮)
4227
4233
  rowFormTitle: "编辑行",
@@ -4294,6 +4300,7 @@ const enUS = {
4294
4300
  expServerNoPdf: "Server export has no PDF (browser printing is front-end); fell back to a front-end range",
4295
4301
  expServerMissing: "No server export wired up: provide a serverExport callback",
4296
4302
  expFailed: "Export failed",
4303
+ printCap: "Large data set: printing the first {n} of {total} rows only. Narrow the range or use Server export for the full set",
4297
4304
  resetState: "Reset column state",
4298
4305
  groupBanner: "⬇ Drag column headers here to group rows (or Panel → Group)",
4299
4306
  loading: "Loading…",
@@ -4444,6 +4451,7 @@ const enUS = {
4444
4451
  querySearch: "Search",
4445
4452
  queryReset: "Reset",
4446
4453
  querySaveView: "Save as view",
4454
+ queryRemove: "Remove this condition",
4447
4455
  queryInput: "Enter",
4448
4456
  // Row edit dialog & built-in confirm (query bar action buttons)
4449
4457
  rowFormTitle: "Edit Row",
@@ -4879,7 +4887,9 @@ function parseNLQ(text, columns) {
4879
4887
  return { ...empty, message: "empty" };
4880
4888
  const result = { ok: false, filters: [], clauses: [] };
4881
4889
  let buf = raw;
4882
- const lim = buf.match(/(?:前|取|返回|最多|top)\s*(\d+)\s*(?:行|条|个|名|件)?/i);
4890
+ const lim = buf.match(
4891
+ /(?:前|取|返回|最多|top|first|limit|show(?:\s+me)?|give\s+me)\s*(?:the\s+)?(\d+)\s*(?:行|条|个|名|件|rows?|records?|items?|results?)?/i
4892
+ );
4883
4893
  if (lim) {
4884
4894
  result.limit = parseInt(lim[1], 10);
4885
4895
  buf = blank(buf, lim.index, lim[0].length);
@@ -4903,6 +4913,7 @@ function parseNLQ(text, columns) {
4903
4913
  if (col) {
4904
4914
  result.groupBy = col.field || col.title || col.colId;
4905
4915
  result.groupColId = col.colId;
4916
+ result.groupTitle = col.title || col.field || col.colId;
4906
4917
  buf = blank(buf, g.start, g.len);
4907
4918
  }
4908
4919
  }
@@ -4911,14 +4922,21 @@ function parseNLQ(text, columns) {
4911
4922
  /sort\s*by\s+([^,,、;;]+)/i,
4912
4923
  /([^,,、;;\s]+?)(?:升序|降序|倒序|从大到小|从小到大)/i,
4913
4924
  // 比较级:X最高/最低/最大/最小/最贵/最便宜/最多/最少(可带尾随「的」一并消费,避免泄漏进相邻筛选值)
4914
- /([^,,、;;\s]+?)最(?:高|低|大|小|贵|便宜|多|少)的?/i
4925
+ /([^,,、;;\s]+?)最(?:高|低|大|小|贵|便宜|多|少)的?/i,
4926
+ // 英文比较级(后缀式):X highest / X most expensive / X cheapest(不含裸 most/least,以免吞掉 at most/at least)
4927
+ /([a-z][a-z ]*?)\s+(?:the\s+)?(?:highest|lowest|largest|biggest|smallest|most expensive|least expensive|cheapest)\b/i,
4928
+ // 英文比较级(前缀式):highest X / cheapest X
4929
+ /\b(?:highest|lowest|largest|biggest|smallest|most expensive|cheapest|least expensive)\s+(?:the\s+)?([a-z][a-z ]*?)(?=$|[,,、;;.]|\s+(?:and|by|of)\b)/i
4915
4930
  ]);
4916
4931
  if (s) {
4917
4932
  const col = resolveColumn(s.name, columns);
4918
4933
  if (col) {
4919
4934
  const dirWord = (s.word || "").toLowerCase();
4920
- const desc = /降序|倒序|从大到小|desc|最高|最大|最贵|最多/.test(dirWord);
4935
+ const desc = /降序|倒序|从大到小|desc|最高|最大|最贵|最多|highest|largest|biggest|most expensive/.test(
4936
+ dirWord
4937
+ );
4921
4938
  result.sort = { field: col.field || col.colId, dir: desc ? "desc" : "asc" };
4939
+ result.sortTitle = col.title || col.field || col.colId;
4922
4940
  buf = blank(buf, s.start, s.len);
4923
4941
  }
4924
4942
  }
@@ -5154,21 +5172,72 @@ function mergeClauses(clauses, columns) {
5154
5172
  }
5155
5173
  return out;
5156
5174
  }
5157
- function explainNLQ(r) {
5175
+ const OP_LABEL = {
5176
+ zh: {
5177
+ eq: "=",
5178
+ ne: "≠",
5179
+ gt: ">",
5180
+ gte: "≥",
5181
+ lt: "<",
5182
+ lte: "≤",
5183
+ contains: "包含",
5184
+ notContains: "不包含",
5185
+ startsWith: "开头是",
5186
+ endsWith: "结尾为",
5187
+ blank: "为空",
5188
+ notBlank: "非空",
5189
+ in: "属于",
5190
+ notIn: "不属于",
5191
+ inRange: "介于"
5192
+ },
5193
+ en: {
5194
+ eq: "=",
5195
+ ne: "≠",
5196
+ gt: ">",
5197
+ gte: "≥",
5198
+ lt: "<",
5199
+ lte: "≤",
5200
+ contains: "contains",
5201
+ notContains: "not contains",
5202
+ startsWith: "starts with",
5203
+ endsWith: "ends with",
5204
+ blank: "is empty",
5205
+ notBlank: "is not empty",
5206
+ in: "is",
5207
+ notIn: "not",
5208
+ inRange: "between"
5209
+ }
5210
+ };
5211
+ function explainNLQ(r, lang = "zh") {
5212
+ const en = lang === "en";
5213
+ const labels = OP_LABEL[lang];
5158
5214
  const parts = [];
5159
5215
  for (const c of r.clauses) {
5160
- const val = c.value2 != null ? `${c.value1}~${c.value2}` : c.value1 ?? "";
5161
- parts.push(`${c.title || c.field || c.colId} ${c.op} ${val}`.trim());
5216
+ const opLabel = labels[c.op] || c.op;
5217
+ const name = c.title || c.field || c.colId;
5218
+ let val;
5219
+ if (c.op === "blank" || c.op === "notBlank")
5220
+ val = "";
5221
+ else if (c.value2 != null)
5222
+ val = `${c.value1}~${c.value2}`;
5223
+ else if (Array.isArray(c.value1))
5224
+ val = c.value1.join(en ? " / " : "、");
5225
+ else
5226
+ val = String(c.value1 ?? "");
5227
+ const glue = en || /^[=<>≤≥≠]/.test(opLabel) ? " " : "";
5228
+ parts.push(`${name} ${opLabel}${glue}${val}`.trim());
5162
5229
  }
5163
5230
  if (r.sort)
5164
- parts.push(`sort ${r.sort.field} ${r.sort.dir}`);
5231
+ parts.push(
5232
+ en ? `sort by ${r.sortTitle || r.sort.field} ${r.sort.dir}` : `按${r.sortTitle || r.sort.field} ${r.sort.dir === "desc" ? "降序" : "升序"}`
5233
+ );
5165
5234
  if (r.groupBy)
5166
- parts.push(`group ${r.groupBy}`);
5235
+ parts.push(en ? `group by ${r.groupTitle || r.groupBy}` : `按${r.groupTitle || r.groupBy}分组`);
5167
5236
  if (r.limit)
5168
- parts.push(`top ${r.limit}`);
5237
+ parts.push(en ? `top ${r.limit}` : `前${r.limit}`);
5169
5238
  if (r.search)
5170
- parts.push(`search "${r.search}"`);
5171
- return parts.join(" | ");
5239
+ parts.push(en ? `search "${r.search}"` : `搜索“${r.search}”`);
5240
+ return parts.join(" · ");
5172
5241
  }
5173
5242
  const csvCell = (v) => {
5174
5243
  if (v == null)
@@ -7694,7 +7763,7 @@ const _sfc_main$a = /* @__PURE__ */ defineComponent({
7694
7763
  onMounted(() => {
7695
7764
  const el = menuRef.value;
7696
7765
  if (el)
7697
- emit("reposition", el.offsetHeight);
7766
+ emit("reposition", el.offsetHeight, el.offsetWidth);
7698
7767
  });
7699
7768
  const hoverIdx = ref(-1);
7700
7769
  function onClick(item) {
@@ -9026,7 +9095,7 @@ const _hoisted_3$4 = ["value", "onChange"];
9026
9095
  const _hoisted_4$3 = ["value"];
9027
9096
  const _hoisted_5$3 = ["value", "placeholder", "onInput"];
9028
9097
  const _hoisted_6$3 = ["value", "placeholder", "onInput"];
9029
- const _hoisted_7$2 = ["onClick"];
9098
+ const _hoisted_7$2 = ["title", "onClick"];
9030
9099
  const _hoisted_8$2 = {
9031
9100
  value: "",
9032
9101
  disabled: ""
@@ -9259,7 +9328,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
9259
9328
  }, null, 40, _hoisted_6$3)),
9260
9329
  createElementVNode("span", {
9261
9330
  class: "rj-query-del",
9262
- title: "移除",
9331
+ title: unref(t)("queryRemove"),
9263
9332
  onClick: ($event) => remove(i)
9264
9333
  }, "✕", 8, _hoisted_7$2)
9265
9334
  ]);
@@ -9849,6 +9918,7 @@ function buildPrintHtml(input, opts = {}) {
9849
9918
  const headBg = o.headerDark ? "#4472c4" : "#eef1f6";
9850
9919
  const headColor = o.headerDark ? "#ffffff" : "#1f2329";
9851
9920
  const zebraRule = o.zebra ? "tbody tr:nth-child(even) td{background:#f7f9fc}" : "";
9921
+ const rowBreakRule = input.matrix.length > 300 ? "tr { break-inside: auto; page-break-inside: auto; }" : "tr { page-break-inside: avoid; break-inside: avoid; }";
9852
9922
  const style = `
9853
9923
  @page { ${pageBox} margin: ${o.margins}mm; }
9854
9924
  ${o.pageNumbers ? `@page { @bottom-center { content: ${pageContentCss(o.pageNumberText)}; font-size: 10px; color: #999; } }` : ""}
@@ -9860,7 +9930,7 @@ body { font-family: -apple-system, "Segoe UI", "Microsoft YaHei", Arial, sans-se
9860
9930
  .rj-print-sub { font-size: 12px; color: #666; margin: 0 0 10px; }
9861
9931
  table { border-collapse: collapse; width: 100%; table-layout: ${o.scaleToFit ? "auto" : "fixed"}; font-size: 12px; }
9862
9932
  thead { display: table-header-group; }
9863
- tr { page-break-inside: avoid; break-inside: avoid; }
9933
+ ${rowBreakRule}
9864
9934
  th, td { border: ${border}; padding: 4px 8px; text-align: left; vertical-align: top; word-break: break-word; }
9865
9935
  thead th { background: ${headBg}; color: ${headColor}; font-weight: 600; text-align: center; }
9866
9936
  ${zebraRule}
@@ -9948,19 +10018,19 @@ const _hoisted_7 = {
9948
10018
  };
9949
10019
  const _hoisted_8 = { key: 0 };
9950
10020
  const _hoisted_9 = ["onClick"];
9951
- const _hoisted_10 = ["title"];
9952
- const _hoisted_11 = ["title"];
9953
- const _hoisted_12 = ["title"];
9954
- const _hoisted_13 = ["title"];
10021
+ const _hoisted_10 = ["data-tip", "aria-label"];
10022
+ const _hoisted_11 = ["data-tip", "aria-label"];
10023
+ const _hoisted_12 = ["data-tip", "aria-label"];
10024
+ const _hoisted_13 = ["data-tip", "aria-label"];
9955
10025
  const _hoisted_14 = {
9956
10026
  key: 5,
9957
10027
  class: "rj-export-group"
9958
10028
  };
9959
- const _hoisted_15 = ["title"];
9960
- const _hoisted_16 = ["title"];
9961
- const _hoisted_17 = ["title"];
9962
- const _hoisted_18 = ["title"];
9963
- const _hoisted_19 = ["title"];
10029
+ const _hoisted_15 = ["data-tip"];
10030
+ const _hoisted_16 = ["data-tip"];
10031
+ const _hoisted_17 = ["data-tip"];
10032
+ const _hoisted_18 = ["data-tip"];
10033
+ const _hoisted_19 = ["data-tip", "aria-label"];
9964
10034
  const _hoisted_20 = { style: { "display": "flex", "flex": "1", "min-height": "0" } };
9965
10035
  const _hoisted_21 = ["role"];
9966
10036
  const _hoisted_22 = ["aria-rowindex", "aria-selected", "data-rk"];
@@ -10079,9 +10149,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
10079
10149
  showGroupPanel: { type: Boolean, default: true },
10080
10150
  chartable: { type: Boolean, default: true },
10081
10151
  exportable: { type: Boolean, default: true },
10152
+ showPrint: { type: Boolean, default: true },
10153
+ showCsv: { type: Boolean, default: true },
10154
+ showPdf: { type: Boolean, default: true },
10155
+ showExcel: { type: Boolean, default: true },
10082
10156
  colReorder: { type: Boolean, default: true },
10083
10157
  resizable: { type: Boolean, default: true },
10084
10158
  rowSelection: { type: [Boolean, String], default: false },
10159
+ selectOnCellClick: { type: Boolean, default: true },
10085
10160
  keepSelectionCrossPage: { type: Boolean },
10086
10161
  editable: { type: Boolean, default: false },
10087
10162
  rangeSelection: { type: Boolean, default: true },
@@ -10112,6 +10187,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
10112
10187
  exportRange: { default: "auto" },
10113
10188
  serverExport: {},
10114
10189
  exportFileName: {},
10190
+ printMaxRows: { default: 1e3 },
10115
10191
  exportRawValues: { type: Boolean },
10116
10192
  statusBar: { type: Boolean, default: true },
10117
10193
  statusAggregations: { default: () => ["sum", "avg", "count", "min", "max"] },
@@ -10508,6 +10584,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
10508
10584
  const quickPop = ref(null);
10509
10585
  const quickInputRef = ref();
10510
10586
  function toggleQuickPop(ev) {
10587
+ tip.value = null;
10511
10588
  if (quickPop.value) {
10512
10589
  quickPop.value = null;
10513
10590
  return;
@@ -10827,6 +10904,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
10827
10904
  }
10828
10905
  notifySelection();
10829
10906
  }
10907
+ function selectRowByClick(d) {
10908
+ if (selection.size === 1 && selection.has(d.key))
10909
+ return;
10910
+ selection.clear();
10911
+ if (props.keepSelectionCrossPage)
10912
+ preserveMap.clear();
10913
+ selection.add(d.key);
10914
+ if (props.keepSelectionCrossPage)
10915
+ preserveMap.set(d.key, d.data);
10916
+ notifySelection();
10917
+ }
10830
10918
  function selectedRows() {
10831
10919
  const rows = rowModel.processed.value.displayRows.filter((d) => selection.has(d.key)).map((d) => d.data);
10832
10920
  Array.from(preserveMap.values()).forEach((r) => {
@@ -11947,6 +12035,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
11947
12035
  colIndex: pos.c,
11948
12036
  column: leaf.col
11949
12037
  });
12038
+ if (props.selectOnCellClick && e.button === 0 && !e.ctrlKey && !e.metaKey && !e.shiftKey && !e.altKey && drow && drow.type === "row" && !(e.target instanceof Element && e.target.closest(".rj-checkbox")))
12039
+ selectRowByClick(drow);
11950
12040
  }
11951
12041
  if (!props.rangeSelection || e.button !== 0 || !pos)
11952
12042
  return;
@@ -12590,25 +12680,50 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
12590
12680
  }));
12591
12681
  });
12592
12682
  const menu = ref(null);
12593
- function openMenuAt(x, y, items, above) {
12683
+ const tip = ref(null);
12684
+ function onTipOver(e) {
12685
+ var _a2, _b;
12686
+ const host = e.currentTarget;
12687
+ const el = (_b = (_a2 = e.target) == null ? void 0 : _a2.closest) == null ? void 0 : _b.call(_a2, "[data-tip]");
12688
+ if (!el || !host.contains(el))
12689
+ return;
12690
+ const r = el.getBoundingClientRect();
12691
+ tip.value = { text: el.getAttribute("data-tip") || "", x: r.right, y: r.bottom + 6 };
12692
+ }
12693
+ function onTipOut(e) {
12694
+ var _a2, _b;
12695
+ const el = (_b = (_a2 = e.target) == null ? void 0 : _a2.closest) == null ? void 0 : _b.call(_a2, "[data-tip]");
12696
+ const to = e.relatedTarget;
12697
+ if (el && to && el.contains(to))
12698
+ return;
12699
+ tip.value = null;
12700
+ }
12701
+ function openMenuAt(x, y, items, above, estW = 220) {
12594
12702
  if (!items.length)
12595
12703
  return;
12704
+ tip.value = null;
12596
12705
  const est = items.length * 28 + 16;
12597
12706
  const bottom = window.innerHeight - 8;
12707
+ const xc = Math.max(8, Math.min(x, window.innerWidth - estW - 8));
12598
12708
  if (y + est <= bottom) {
12599
- menu.value = { items, x, y, limit: bottom };
12709
+ menu.value = { items, x: xc, y, limit: bottom };
12600
12710
  return;
12601
12711
  }
12602
12712
  const lim = (above ?? y) - 6;
12603
- menu.value = { items, x, y: Math.max(8, (above ?? y) - est - 8), limit: lim };
12713
+ menu.value = { items, x: xc, y: Math.max(8, (above ?? y) - est - 8), limit: lim };
12604
12714
  }
12605
- function onMenuReposition(h2) {
12715
+ function onMenuReposition(h2, w) {
12606
12716
  const m = menu.value;
12607
12717
  if (!m)
12608
12718
  return;
12609
12719
  const lim = m.limit ?? window.innerHeight - 8;
12720
+ const next = { ...m };
12610
12721
  if (m.y + h2 > lim)
12611
- menu.value = { ...m, y: Math.max(8, lim - h2) };
12722
+ next.y = Math.max(8, lim - h2);
12723
+ if (w && m.x + w > window.innerWidth - 8)
12724
+ next.x = Math.max(8, window.innerWidth - 8 - w);
12725
+ if (next.y !== m.y || next.x !== m.x)
12726
+ menu.value = next;
12612
12727
  }
12613
12728
  function onMenuSelect(item) {
12614
12729
  var _a2;
@@ -12890,7 +13005,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
12890
13005
  { isSeparator: true },
12891
13006
  { name: t("scopeServer"), action: () => callServerExport(fmt) }
12892
13007
  );
12893
- openMenuAt(ev.clientX, ev.clientY, items);
13008
+ const el = ev.currentTarget;
13009
+ const r = el.getBoundingClientRect();
13010
+ openMenuAt(r.left, r.bottom + 6, items, r.top);
12894
13011
  }
12895
13012
  function runFormat(fmt, scope) {
12896
13013
  if (fmt === "print")
@@ -13010,7 +13127,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
13010
13127
  return v.join(" ");
13011
13128
  return displayOf(col, v, row, 0);
13012
13129
  }
13013
- function buildPrintInput(params) {
13130
+ function buildPrintInput(params, limit = 0) {
13014
13131
  const cols = exportColumnsOf(params);
13015
13132
  const columns = cols.map((c) => {
13016
13133
  var _a2;
@@ -13022,26 +13139,32 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
13022
13139
  });
13023
13140
  const matrix = [];
13024
13141
  const rowStyles = [];
13142
+ const capped = limit > 0;
13143
+ const full = () => capped && matrix.length >= limit;
13025
13144
  const pushRow = (d, kind) => {
13026
13145
  matrix.push(cols.map((c) => printTextOf(c, d.data)));
13027
13146
  rowStyles.push(kind);
13028
13147
  };
13029
13148
  const scope = scopeOf(params);
13030
13149
  if (scope === "view") {
13031
- rowModel.processed.value.displayRows.forEach((d) => {
13150
+ for (const d of rowModel.processed.value.displayRows) {
13151
+ if (full())
13152
+ break;
13032
13153
  if (d.type === "group" && !d.isFooter)
13033
13154
  pushRow(d, 1);
13034
13155
  else if (d.type === "row")
13035
13156
  pushRow(d, 0);
13036
- });
13157
+ }
13037
13158
  } else {
13038
- pickExportRows(scope, exportRowSource(), false).forEach((r) => {
13159
+ for (const r of pickExportRows(scope, exportRowSource(), false)) {
13160
+ if (full())
13161
+ break;
13039
13162
  matrix.push(cols.map((c) => printTextOf(c, r)));
13040
13163
  rowStyles.push(0);
13041
- });
13164
+ }
13042
13165
  }
13043
13166
  const srow = rowModel.summaryRow.value;
13044
- if (scope === "view" && props.showSummary && srow) {
13167
+ if (scope === "view" && props.showSummary && srow && !full()) {
13045
13168
  matrix.push(
13046
13169
  cols.map((c) => {
13047
13170
  const raw = srow[colIdOf(c)] ?? cellRawValue(c, srow);
@@ -13079,8 +13202,22 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
13079
13202
  warnIfLoadedOnly(scopeOf(params));
13080
13203
  withExportBusy(() => runPrint(params));
13081
13204
  }
13205
+ function printRowEstimate(scope) {
13206
+ if (scope === "view")
13207
+ return rowModel.processed.value.displayRows.reduce(
13208
+ (n, d) => n + (d.type === "row" || d.type === "group" && !d.isFooter ? 1 : 0),
13209
+ 0
13210
+ );
13211
+ return pickExportRows(scope, exportRowSource(), false).length;
13212
+ }
13082
13213
  function runPrint(params) {
13083
- printHtml(buildPrintInput(params), printOpts(params));
13214
+ const cap = props.printMaxRows;
13215
+ const total = printRowEstimate(scopeOf(params));
13216
+ const limit = cap > 0 && total > cap ? cap : 0;
13217
+ const input = buildPrintInput(params, limit);
13218
+ if (limit)
13219
+ showToast(t("printCap", { n: cap, total }));
13220
+ printHtml(input, printOpts(params));
13084
13221
  }
13085
13222
  const rowGroupPayload = computed(() => {
13086
13223
  void aggRev.value;
@@ -13575,6 +13712,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
13575
13712
  scheduleSave();
13576
13713
  dispatchEvent("columnEverythingChanged", {});
13577
13714
  },
13715
+ /** 清除宽度覆盖:把列宽还原到列定义/内容自适应默认值(配合 autoSizeAll 做「自适应↔还原」切换) */
13716
+ resetColumnWidths: () => {
13717
+ colState.clearWidths();
13718
+ applyDefaultAutoWidths();
13719
+ scheduleSave();
13720
+ dispatchEvent("columnEverythingChanged", {});
13721
+ },
13578
13722
  // 主题 / i18n(运行时切换)
13579
13723
  setTheme: (params) => {
13580
13724
  themeState.value = { ...params };
@@ -13816,18 +13960,24 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
13816
13960
  onDragover: _cache[21] || (_cache[21] = withModifiers(() => {
13817
13961
  }, ["stop"])),
13818
13962
  onDrop: _cache[22] || (_cache[22] = withModifiers(() => {
13819
- }, ["stop"]))
13963
+ }, ["stop"])),
13964
+ onPointerover: onTipOver,
13965
+ onPointerout: onTipOut,
13966
+ onFocusin: onTipOver,
13967
+ onFocusout: onTipOut
13820
13968
  }, [
13821
13969
  _ctx.quickFilterEnabled ? (openBlock(), createElementBlock("button", {
13822
13970
  key: 0,
13823
13971
  class: normalizeClass(["rj-btn rj-tool-btn rj-quick-btn", { "is-active": !!unref(rowModel).quickFilter.value }]),
13824
- title: t("quickBtn"),
13972
+ "data-tip": t("quickBtn"),
13973
+ "aria-label": t("quickBtn"),
13825
13974
  onClick: _cache[9] || (_cache[9] = ($event) => toggleQuickPop($event))
13826
13975
  }, "🔍", 10, _hoisted_10)) : createCommentVNode("", true),
13827
13976
  _ctx.viewable ? (openBlock(), createElementBlock("button", {
13828
13977
  key: 1,
13829
13978
  class: normalizeClass(["rj-btn rj-tool-btn rj-view-btn", { "is-active": !!currentViewId.value }]),
13830
- title: t("viewBtn"),
13979
+ "data-tip": t("viewBtn"),
13980
+ "aria-label": t("viewBtn"),
13831
13981
  onClick: _cache[10] || (_cache[10] = ($event) => openViewMenu($event))
13832
13982
  }, "◈", 10, _hoisted_11)) : createCommentVNode("", true),
13833
13983
  showExpandCollapse.value ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [
@@ -13847,12 +13997,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
13847
13997
  }, toDisplayString(t("chart")), 1)) : createCommentVNode("", true),
13848
13998
  createElementVNode("button", {
13849
13999
  class: "rj-btn",
13850
- title: t("density") + " · " + DENSITY_LABELS.value[densityIdx.value],
14000
+ "data-tip": t("density") + " · " + DENSITY_LABELS.value[densityIdx.value],
14001
+ "aria-label": t("density"),
13851
14002
  onClick: _cache[14] || (_cache[14] = ($event) => densityIdx.value = (densityIdx.value + 1) % 3)
13852
14003
  }, toDisplayString(["▤", "☰", "▥"][densityIdx.value]), 9, _hoisted_12),
13853
14004
  createElementVNode("button", {
13854
14005
  class: "rj-btn",
13855
- title: dark.value ? t("toLight") : t("toDark"),
14006
+ "data-tip": dark.value ? t("toLight") : t("toDark"),
14007
+ "aria-label": dark.value ? t("toLight") : t("toDark"),
13856
14008
  onClick: _cache[15] || (_cache[15] = ($event) => toggleDark())
13857
14009
  }, toDisplayString(dark.value ? "☀" : "🌙"), 9, _hoisted_13),
13858
14010
  _ctx.toolPanel ? (openBlock(), createElementBlock("button", {
@@ -13860,32 +14012,37 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
13860
14012
  class: normalizeClass(["rj-btn", { "is-active": panelOpen.value }]),
13861
14013
  onClick: _cache[16] || (_cache[16] = ($event) => panelOpen.value = !panelOpen.value)
13862
14014
  }, toDisplayString(t("panel")), 3)) : createCommentVNode("", true),
13863
- _ctx.exportable ? (openBlock(), createElementBlock("div", _hoisted_14, [
13864
- createElementVNode("button", {
14015
+ _ctx.exportable && (_ctx.showPrint || _ctx.showCsv || _ctx.showPdf || _ctx.showExcel) ? (openBlock(), createElementBlock("div", _hoisted_14, [
14016
+ _ctx.showPrint ? (openBlock(), createElementBlock("button", {
14017
+ key: 0,
13865
14018
  class: "rj-btn rj-btn-export rj-export-btn",
13866
- title: t("printTip"),
14019
+ "data-tip": t("printTip"),
13867
14020
  onClick: _cache[17] || (_cache[17] = ($event) => openRangeMenu($event, "print"))
13868
- }, toDisplayString(t("printBtn")), 9, _hoisted_15),
13869
- createElementVNode("button", {
14021
+ }, toDisplayString(t("printBtn")), 9, _hoisted_15)) : createCommentVNode("", true),
14022
+ _ctx.showCsv ? (openBlock(), createElementBlock("button", {
14023
+ key: 1,
13870
14024
  class: "rj-btn rj-btn-export rj-export-btn",
13871
- title: t("csvTip"),
14025
+ "data-tip": t("csvTip"),
13872
14026
  onClick: _cache[18] || (_cache[18] = ($event) => openRangeMenu($event, "csv"))
13873
- }, " CSV ", 8, _hoisted_16),
13874
- createElementVNode("button", {
14027
+ }, " CSV ", 8, _hoisted_16)) : createCommentVNode("", true),
14028
+ _ctx.showPdf ? (openBlock(), createElementBlock("button", {
14029
+ key: 2,
13875
14030
  class: "rj-btn rj-btn-export rj-export-btn",
13876
- title: t("pdfTip"),
14031
+ "data-tip": t("pdfTip"),
13877
14032
  onClick: _cache[19] || (_cache[19] = ($event) => openRangeMenu($event, "pdf"))
13878
- }, " PDF ", 8, _hoisted_17),
13879
- createElementVNode("button", {
14033
+ }, " PDF ", 8, _hoisted_17)) : createCommentVNode("", true),
14034
+ _ctx.showExcel ? (openBlock(), createElementBlock("button", {
14035
+ key: 3,
13880
14036
  class: "rj-btn rj-btn-export rj-export-btn",
13881
- title: t("excelTip"),
14037
+ "data-tip": t("excelTip"),
13882
14038
  onClick: _cache[20] || (_cache[20] = ($event) => openRangeMenu($event, "excel"))
13883
- }, " Excel ", 8, _hoisted_18)
14039
+ }, " Excel ", 8, _hoisted_18)) : createCommentVNode("", true)
13884
14040
  ])) : createCommentVNode("", true),
13885
14041
  _ctx.stateKey ? (openBlock(), createElementBlock("button", {
13886
14042
  key: 6,
13887
14043
  class: "rj-btn",
13888
- title: t("resetState"),
14044
+ "data-tip": t("resetState"),
14045
+ "aria-label": t("resetState"),
13889
14046
  onClick: resetState
13890
14047
  }, "↺", 8, _hoisted_19)) : createCommentVNode("", true)
13891
14048
  ], 32)) : createCommentVNode("", true)
@@ -14452,8 +14609,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
14452
14609
  onClear: clearAdvancedFilter,
14453
14610
  onClose: _cache[43] || (_cache[43] = ($event) => advDialog.value = null)
14454
14611
  }, null, 8, ["model", "columns", "x", "y"])) : createCommentVNode("", true),
14455
- menu.value ? (openBlock(), createBlock(_sfc_main$a, {
14612
+ tip.value ? (openBlock(), createElementBlock("div", {
14456
14613
  key: 8,
14614
+ class: "rj-tip",
14615
+ role: "tooltip",
14616
+ style: normalizeStyle({ left: tip.value.x + "px", top: tip.value.y + "px" })
14617
+ }, toDisplayString(tip.value.text), 5)) : createCommentVNode("", true),
14618
+ menu.value ? (openBlock(), createBlock(_sfc_main$a, {
14619
+ key: 9,
14457
14620
  items: menu.value.items,
14458
14621
  x: menu.value.x,
14459
14622
  y: menu.value.y,
@@ -14461,7 +14624,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
14461
14624
  onReposition: onMenuReposition
14462
14625
  }, null, 8, ["items", "x", "y"])) : createCommentVNode("", true),
14463
14626
  colMenu.value ? (openBlock(), createBlock(_sfc_main$9, {
14464
- key: 9,
14627
+ key: 10,
14465
14628
  col: colMenu.value.col,
14466
14629
  "col-id": colMenu.value.colId,
14467
14630
  x: colMenu.value.x,
@@ -14489,13 +14652,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
14489
14652
  onColDrop
14490
14653
  }, null, 8, ["col", "col-id", "x", "y", "can-sort", "can-filter", "can-group", "sort-dir", "pinned", "filter-type", "filter-model", "unique-values", "columns"])) : createCommentVNode("", true),
14491
14654
  chartOpen.value ? (openBlock(), createBlock(_sfc_main$6, {
14492
- key: 10,
14655
+ key: 11,
14493
14656
  columns: pipelineCols.value,
14494
14657
  rows: chartRows.value,
14495
14658
  onClose: _cache[44] || (_cache[44] = ($event) => chartOpen.value = false)
14496
14659
  }, null, 8, ["columns", "rows"])) : createCommentVNode("", true),
14497
14660
  rowFormDlg.value ? (openBlock(), createBlock(_sfc_main$3, {
14498
- key: 11,
14661
+ key: 12,
14499
14662
  fields: rowFormDlg.value.fields,
14500
14663
  rows: rowFormDlg.value.rows,
14501
14664
  mode: rowFormDlg.value.mode,
@@ -14505,13 +14668,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
14505
14668
  onClose: _cache[45] || (_cache[45] = ($event) => rowFormDlg.value = null)
14506
14669
  }, null, 8, ["fields", "rows", "mode", "title", "width"])) : createCommentVNode("", true),
14507
14670
  confirmDlg.value ? (openBlock(), createBlock(_sfc_main$2, {
14508
- key: 12,
14671
+ key: 13,
14509
14672
  message: confirmDlg.value.message,
14510
14673
  onOk: onConfirmOk,
14511
14674
  onCancel: _cache[46] || (_cache[46] = ($event) => confirmDlg.value = null)
14512
14675
  }, null, 8, ["message"])) : createCommentVNode("", true),
14513
14676
  dragGhost.value ? (openBlock(), createElementBlock("div", {
14514
- key: 13,
14677
+ key: 14,
14515
14678
  ref_key: "dragGhostRef",
14516
14679
  ref: dragGhostRef,
14517
14680
  class: "rj-drag-ghost",
@@ -14532,7 +14695,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
14532
14695
  !dragGhost.value.cells.length ? (openBlock(), createElementBlock("span", _hoisted_51, toDisplayString(t("dragRow")), 1)) : createCommentVNode("", true)
14533
14696
  ], 4)) : createCommentVNode("", true),
14534
14697
  imgPreview.value ? (openBlock(), createElementBlock("div", {
14535
- key: 14,
14698
+ key: 15,
14536
14699
  class: "rj-img-viewer",
14537
14700
  role: "dialog",
14538
14701
  "aria-modal": "true",
package/dist/style.css CHANGED
@@ -10,7 +10,7 @@
10
10
  --rj-text-secondary: #909399;
11
11
  --rj-primary: #3b76f6;
12
12
  --rj-primary-bg: #eaf1fe;
13
- --rj-hover-bg: #f2f6fd;
13
+ --rj-hover-bg: #e6edf9;
14
14
  --rj-selected-bg: #e2edfd;
15
15
  --rj-range-bg: rgba(59, 118, 246, 0.1);
16
16
  --rj-fill-bg: rgba(59, 118, 246, 0.16);
@@ -52,7 +52,7 @@
52
52
  --rj-text-secondary: #8a919f;
53
53
  --rj-primary: #5c8dfb;
54
54
  --rj-primary-bg: #24324d;
55
- --rj-hover-bg: #272d3a;
55
+ --rj-hover-bg: #313a4d;
56
56
  --rj-selected-bg: #2a3a5c;
57
57
  --rj-mask: rgba(30, 34, 42, 0.75);
58
58
  --rj-flash-bg: #5a4c1e;
@@ -509,6 +509,25 @@
509
509
  font-weight: 500;
510
510
  }
511
511
 
512
+ .rj-tip {
513
+ position: fixed;
514
+ z-index: 3100;
515
+ width: max-content;
516
+ max-width: 240px;
517
+ padding: 3px 8px;
518
+ font-size: 12px;
519
+ font-weight: 400;
520
+ line-height: 1.4;
521
+ color: var(--rj-bg);
522
+ text-align: left;
523
+ white-space: normal;
524
+ pointer-events: none;
525
+ background: var(--rj-text);
526
+ border-radius: var(--rj-radius);
527
+ box-shadow: var(--rj-shadow);
528
+ transform: translateX(-100%);
529
+ }
530
+
512
531
  .rj-pager {
513
532
  display: flex;
514
533
  align-items: center;
@@ -5,14 +5,14 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
5
5
  y: number;
6
6
  }>>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
7
7
  select: (item: RjMenuItem) => void;
8
- reposition: (h: number) => void;
8
+ reposition: (h: number, w: number) => void;
9
9
  }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToRuntimeProps<{
10
10
  items: RjMenuItem[];
11
11
  x: number;
12
12
  y: number;
13
13
  }>>> & Readonly<{
14
14
  onSelect?: ((item: RjMenuItem) => any) | undefined;
15
- onReposition?: ((h: number) => any) | undefined;
15
+ onReposition?: ((h: number, w: number) => any) | undefined;
16
16
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
17
17
  export default _default;
18
18
  type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;