@rufous/ui 0.3.61 → 0.3.62

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/main.cjs CHANGED
@@ -2424,6 +2424,7 @@ var BaseDialog = ({
2424
2424
  showCloseButton = true,
2425
2425
  buttonAlign = "flex-end",
2426
2426
  showCancelButton = true,
2427
+ showConfirmButton = true,
2427
2428
  formatTitle = true,
2428
2429
  fullWidth = false,
2429
2430
  className,
@@ -2500,7 +2501,7 @@ var BaseDialog = ({
2500
2501
  type: "button"
2501
2502
  },
2502
2503
  cancelText
2503
- ), form ? /* @__PURE__ */ React140.createElement(
2504
+ ), showConfirmButton && (form ? /* @__PURE__ */ React140.createElement(
2504
2505
  "button",
2505
2506
  {
2506
2507
  className: "btn-confirm",
@@ -2532,7 +2533,7 @@ var BaseDialog = ({
2532
2533
  },
2533
2534
  /* @__PURE__ */ React140.createElement("span", { style: { visibility: isButtonLoading ? "hidden" : "visible" } }, confirmText),
2534
2535
  isButtonLoading && /* @__PURE__ */ React140.createElement("span", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center" } }, /* @__PURE__ */ React140.createElement(circularProgress_default, { size: 18, color: "#ffffff80" }))
2535
- ));
2536
+ )));
2536
2537
  const containerClass = ["dialog-container", size ? `size-${size}` : "", sxClass, className].filter(Boolean).join(" ");
2537
2538
  const containerStyle = { minWidth, minHeight };
2538
2539
  const dialogInner = /* @__PURE__ */ React140.createElement(React140.Fragment, null, !hideHeader && /* @__PURE__ */ React140.createElement(React140.Fragment, null, customHeader ?? /* @__PURE__ */ React140.createElement("div", { className: "dialog-title" }, /* @__PURE__ */ React140.createElement("h2", null, formatTitle ? title?.charAt(0).toUpperCase() + title?.slice(1) : title), showCloseButton && /* @__PURE__ */ React140.createElement("button", { className: "btn-close", type: "button", onClick: onClose }, /* @__PURE__ */ React140.createElement(
@@ -4713,29 +4714,46 @@ var DateField = ({
4713
4714
  if (!rect) return {};
4714
4715
  const PICKER_H = 420;
4715
4716
  const GAP2 = 6;
4716
- const spaceBelow = window.innerHeight - rect.bottom - GAP2;
4717
+ const MARGIN = 8;
4718
+ const vw = window.innerWidth;
4719
+ const vh = window.innerHeight;
4720
+ const naturalW = isSideVariant ? 470 : 320;
4721
+ const avail = vw - MARGIN * 2;
4722
+ const scale = naturalW > avail ? avail / naturalW : 1;
4723
+ const scaledW = naturalW * scale;
4724
+ let left = rect.left;
4725
+ const maxLeft = vw - scaledW - MARGIN;
4726
+ if (left > maxLeft) left = maxLeft;
4727
+ if (left < MARGIN) left = MARGIN;
4728
+ const spaceBelow = vh - rect.bottom - GAP2;
4717
4729
  const spaceAbove = rect.top - GAP2;
4718
- const useDropUp = spaceBelow < PICKER_H && spaceAbove > spaceBelow;
4730
+ const useDropUp = spaceBelow < PICKER_H * scale && spaceAbove > spaceBelow;
4731
+ const common = {
4732
+ position: "fixed",
4733
+ left,
4734
+ width: naturalW,
4735
+ transform: scale === 1 ? void 0 : `scale(${scale})`,
4736
+ overflowY: "auto",
4737
+ zIndex: 99999
4738
+ };
4719
4739
  if (useDropUp) {
4720
4740
  return {
4721
- position: "fixed",
4722
- left: rect.left,
4741
+ ...common,
4723
4742
  // bottom anchors picker's bottom edge exactly to field top — no gap regardless of actual height
4724
- bottom: window.innerHeight - rect.top + GAP2,
4725
- // prevent going above viewport
4726
- maxHeight: rect.top - GAP2 - 4,
4727
- overflowY: "auto",
4728
- zIndex: 99999,
4729
- animationName: "rf-date-picker-appear-up",
4743
+ bottom: vh - rect.top + GAP2,
4744
+ // unscaled max-height — visual height after scaling fits the gap above
4745
+ maxHeight: (rect.top - GAP2 - MARGIN) / scale,
4746
+ // skip the scale-animating keyframes when we apply a static scale (they'd flash full-size)
4747
+ animationName: scale === 1 ? "rf-date-picker-appear-up" : "none",
4730
4748
  transformOrigin: "bottom left"
4731
4749
  };
4732
4750
  }
4733
4751
  return {
4734
- position: "fixed",
4735
- left: rect.left,
4752
+ ...common,
4736
4753
  top: rect.bottom + GAP2,
4737
- zIndex: 99999,
4738
- animationName: "rf-date-picker-appear",
4754
+ // unscaled max-height — visual height after scaling fits below the field
4755
+ maxHeight: (vh - rect.bottom - GAP2 - MARGIN) / scale,
4756
+ animationName: scale === 1 ? "rf-date-picker-appear" : "none",
4739
4757
  transformOrigin: "top left"
4740
4758
  };
4741
4759
  })(),
@@ -5111,6 +5129,43 @@ var DateRangeField = ({
5111
5129
  const [leftViewMonth, setLeftViewMonth] = (0, import_react16.useState)(() => today2.getMonth());
5112
5130
  const containerRef = (0, import_react16.useRef)(null);
5113
5131
  const inputId = (0, import_react16.useRef)(`rf-dr-${Math.random().toString(36).substr(2, 9)}`).current;
5132
+ const [mobileStyle, setMobileStyle] = (0, import_react16.useState)({});
5133
+ (0, import_react16.useEffect)(() => {
5134
+ if (!open) {
5135
+ setMobileStyle({});
5136
+ return;
5137
+ }
5138
+ const compute = () => {
5139
+ const vw = window.innerWidth;
5140
+ const vh = window.innerHeight;
5141
+ const MARGIN = 8;
5142
+ const GAP2 = 6;
5143
+ const naturalW = pickerType === "panel" ? 520 : 640;
5144
+ const avail = vw - MARGIN * 2;
5145
+ if (naturalW <= avail) {
5146
+ setMobileStyle({});
5147
+ return;
5148
+ }
5149
+ const scale = avail / naturalW;
5150
+ const rect = containerRef.current?.getBoundingClientRect();
5151
+ const top = rect ? rect.bottom + GAP2 : 60;
5152
+ setMobileStyle({
5153
+ position: "fixed",
5154
+ top,
5155
+ left: "50%",
5156
+ transform: `translateX(-50%) scale(${scale})`,
5157
+ transformOrigin: "top center",
5158
+ width: naturalW,
5159
+ maxHeight: (vh - top - MARGIN) / scale,
5160
+ overflowY: "auto",
5161
+ animation: "none",
5162
+ zIndex: 99999
5163
+ });
5164
+ };
5165
+ compute();
5166
+ window.addEventListener("resize", compute);
5167
+ return () => window.removeEventListener("resize", compute);
5168
+ }, [open, pickerType]);
5114
5169
  (0, import_react16.useEffect)(() => {
5115
5170
  const s2 = value?.start ? isoToDate2(value.start) : null;
5116
5171
  const e = value?.end ? isoToDate2(value.end) : null;
@@ -5308,7 +5363,7 @@ var DateRangeField = ({
5308
5363
  variant === "outlined" && /* @__PURE__ */ import_react16.default.createElement("fieldset", { className: "rf-text-field__notch" }, label ? /* @__PURE__ */ import_react16.default.createElement("legend", { className: "rf-text-field__legend" }, /* @__PURE__ */ import_react16.default.createElement("span", null, label, required ? " *" : "")) : /* @__PURE__ */ import_react16.default.createElement("legend", { className: "rf-text-field__legend--empty" }))
5309
5364
  ), open && !disabled && (pickerType === "panel" ? (
5310
5365
  /* ── Panel Mode ── */
5311
- /* @__PURE__ */ import_react16.default.createElement("div", { className: "rf-dr-picker rf-dr-picker--panel", onMouseDown: (e) => e.preventDefault() }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "rf-dr-picker__presets" }, PRESETS.map((p, i) => /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, { key: p.id }, i > 0 && /* @__PURE__ */ import_react16.default.createElement("div", { className: "rf-dr-picker__preset-sep" }), /* @__PURE__ */ import_react16.default.createElement(
5366
+ /* @__PURE__ */ import_react16.default.createElement("div", { className: "rf-dr-picker rf-dr-picker--panel", style: mobileStyle, onMouseDown: (e) => e.preventDefault() }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "rf-dr-picker__presets" }, PRESETS.map((p, i) => /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, { key: p.id }, i > 0 && /* @__PURE__ */ import_react16.default.createElement("div", { className: "rf-dr-picker__preset-sep" }), /* @__PURE__ */ import_react16.default.createElement(
5312
5367
  "button",
5313
5368
  {
5314
5369
  type: "button",
@@ -5428,7 +5483,7 @@ var DateRangeField = ({
5428
5483
  ))), /* @__PURE__ */ import_react16.default.createElement("div", { style: { flex: 1 } }), /* @__PURE__ */ import_react16.default.createElement("div", { className: "rf-dr-picker__footer" }, /* @__PURE__ */ import_react16.default.createElement("button", { type: "button", className: "rf-dr-picker__close-btn", onClick: handleClose }, "CLOSE"), /* @__PURE__ */ import_react16.default.createElement("button", { type: "button", className: "rf-dr-picker__apply-btn", onClick: handleApply }, "APPLY"))))
5429
5484
  ) : (
5430
5485
  /* ── Calendar Mode ── */
5431
- /* @__PURE__ */ import_react16.default.createElement("div", { className: "rf-dr-picker rf-dr-picker--calendar", onMouseDown: (e) => e.preventDefault() }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "rf-dr-picker__calendars" }, /* @__PURE__ */ import_react16.default.createElement(
5486
+ /* @__PURE__ */ import_react16.default.createElement("div", { className: "rf-dr-picker rf-dr-picker--calendar", style: mobileStyle, onMouseDown: (e) => e.preventDefault() }, /* @__PURE__ */ import_react16.default.createElement("div", { className: "rf-dr-picker__calendars" }, /* @__PURE__ */ import_react16.default.createElement(
5432
5487
  RangeCalendarBody,
5433
5488
  {
5434
5489
  viewYear: leftViewYear,
@@ -5831,6 +5886,7 @@ function DataGrid({
5831
5886
  const menuRef = (0, import_react17.useRef)(null);
5832
5887
  const [showManageColumns, setShowManageColumns] = (0, import_react17.useState)(false);
5833
5888
  const [showAdvancedFilter, setShowAdvancedFilter] = (0, import_react17.useState)(false);
5889
+ const [mobileToolbarExpanded, setMobileToolbarExpanded] = (0, import_react17.useState)(false);
5834
5890
  const [focusFilterIdx, setFocusFilterIdx] = (0, import_react17.useState)(-1);
5835
5891
  const filterableColumnsProp = initialColumnsProp.filter((c) => c.filterable !== false);
5836
5892
  const initialFilterCol = String(filterableColumnsProp[0]?.field || filterableColumnsProp[0]?.key || "");
@@ -6320,14 +6376,24 @@ function DataGrid({
6320
6376
  onClick: () => setShowAdvancedFilter(true)
6321
6377
  },
6322
6378
  /* @__PURE__ */ import_react17.default.createElement(Funnel, { size: 16 })
6323
- )), showColumnsBtn && /* @__PURE__ */ import_react17.default.createElement(Tooltip, { title: "Manage Columns", placement: "top" }, /* @__PURE__ */ import_react17.default.createElement(
6379
+ )), /* @__PURE__ */ import_react17.default.createElement("div", { className: `dg-actions-overflow${mobileToolbarExpanded ? " dg-actions-overflow--expanded" : ""}` }, showColumnsBtn && /* @__PURE__ */ import_react17.default.createElement(Tooltip, { title: "Manage Columns", placement: "top" }, /* @__PURE__ */ import_react17.default.createElement(
6324
6380
  "button",
6325
6381
  {
6326
6382
  className: "dg-icon-btn",
6327
6383
  onClick: () => setShowManageColumns(true)
6328
6384
  },
6329
6385
  /* @__PURE__ */ import_react17.default.createElement(Columns2, { size: 16 })
6330
- )), showExportBtn && /* @__PURE__ */ import_react17.default.createElement("button", { className: "dg-action-btn", onClick: handleExport, disabled: loading }, /* @__PURE__ */ import_react17.default.createElement(Download, { size: 14 }), " Export CSV"), slotAt("after-actions"));
6386
+ )), showExportBtn && /* @__PURE__ */ import_react17.default.createElement("button", { className: "dg-action-btn", onClick: handleExport, disabled: loading }, /* @__PURE__ */ import_react17.default.createElement(Download, { size: 14 }), " Export CSV"), slotAt("after-actions")), (showColumnsBtn || showExportBtn || slots.some((s2) => s2.position === "after-actions" || !s2.position)) && /* @__PURE__ */ import_react17.default.createElement(
6387
+ "button",
6388
+ {
6389
+ type: "button",
6390
+ className: `dg-toolbar-toggle${mobileToolbarExpanded ? " dg-toolbar-toggle--expanded" : ""}`,
6391
+ onClick: () => setMobileToolbarExpanded((v) => !v),
6392
+ "aria-label": mobileToolbarExpanded ? "Hide toolbar options" : "Show all toolbar options",
6393
+ "aria-expanded": mobileToolbarExpanded
6394
+ },
6395
+ /* @__PURE__ */ import_react17.default.createElement(ChevronDown, { size: 18 })
6396
+ ));
6331
6397
  })())), !tOpts.hideHeader && /* @__PURE__ */ import_react17.default.createElement("div", { className: `dg-toolbar ${alignClass(toolbarContent?.align)}` }, toolbarContent?.content || ""), isGroupingActive && /* @__PURE__ */ import_react17.default.createElement("div", { className: "dg-grouping-bar" }, /* @__PURE__ */ import_react17.default.createElement("span", { className: "dg-grouping-bar-label" }, "Grouped by"), activeGroupingModel.map((gField) => {
6332
6398
  const col = resolvedColumns.find((c) => String(c.field) === gField || String(c.key) === gField);
6333
6399
  return /* @__PURE__ */ import_react17.default.createElement("div", { key: gField, className: "dg-group-chip" }, /* @__PURE__ */ import_react17.default.createElement(Layers, { size: 11 }), /* @__PURE__ */ import_react17.default.createElement("span", null, col?.header ?? col?.headerName ?? gField), !disableRowGrouping && /* @__PURE__ */ import_react17.default.createElement(
package/dist/main.css CHANGED
@@ -97,6 +97,7 @@
97
97
  flex-direction: column;
98
98
  box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.15), 0 10px 10px -5px rgba(0, 0, 0, 0.08);
99
99
  width: 685px !important;
100
+ max-width: 95vw;
100
101
  transition: background-color 0.3s, color 0.3s;
101
102
  }
102
103
  .dialog-container.size-sm {
@@ -495,6 +496,57 @@
495
496
  color: var(--primary-color);
496
497
  background: var(--hover-color);
497
498
  }
499
+ .dg-actions-overflow {
500
+ display: contents;
501
+ }
502
+ .dg-toolbar-toggle {
503
+ display: none;
504
+ align-items: center;
505
+ justify-content: center;
506
+ width: 36px;
507
+ height: 36px;
508
+ padding: 0;
509
+ border: 1px solid var(--border-color);
510
+ border-radius: 8px;
511
+ background: var(--surface-color);
512
+ color: var(--text-secondary);
513
+ cursor: pointer;
514
+ flex-shrink: 0;
515
+ outline: none;
516
+ transition:
517
+ border-color 0.2s,
518
+ color 0.2s,
519
+ background-color 0.2s;
520
+ }
521
+ .dg-toolbar-toggle:hover {
522
+ border-color: var(--primary-color);
523
+ color: var(--primary-color);
524
+ background: var(--hover-color);
525
+ }
526
+ .dg-toolbar-toggle > svg {
527
+ transition: transform 0.2s ease;
528
+ }
529
+ .dg-toolbar-toggle--expanded > svg {
530
+ transform: rotate(180deg);
531
+ }
532
+ @media (max-width: 600px) {
533
+ .dg-toolbar-toggle {
534
+ display: inline-flex;
535
+ margin-left: auto;
536
+ }
537
+ .dg-actions-overflow {
538
+ display: none;
539
+ }
540
+ .dg-actions-overflow--expanded {
541
+ display: flex;
542
+ align-items: center;
543
+ gap: 10px;
544
+ flex-wrap: wrap;
545
+ flex-basis: 100%;
546
+ order: 99;
547
+ margin-top: 4px;
548
+ }
549
+ }
498
550
  .dg-table-wrap {
499
551
  border-top: 2px solid var(--border-color);
500
552
  border-bottom: 1px solid var(--border-color);
package/dist/main.d.cts CHANGED
@@ -907,6 +907,8 @@ interface BaseDialogProps {
907
907
  showCloseButton?: boolean;
908
908
  buttonAlign?: "flex-start" | "flex-end" | "center";
909
909
  showCancelButton?: boolean;
910
+ /** Show/hide the confirm (or submit) button. Defaults to true. */
911
+ showConfirmButton?: boolean;
910
912
  formatTitle?: boolean;
911
913
  fullWidth?: boolean;
912
914
  className?: string;
package/dist/main.d.ts CHANGED
@@ -907,6 +907,8 @@ interface BaseDialogProps {
907
907
  showCloseButton?: boolean;
908
908
  buttonAlign?: "flex-start" | "flex-end" | "center";
909
909
  showCancelButton?: boolean;
910
+ /** Show/hide the confirm (or submit) button. Defaults to true. */
911
+ showConfirmButton?: boolean;
910
912
  formatTitle?: boolean;
911
913
  fullWidth?: boolean;
912
914
  className?: string;
package/dist/main.js CHANGED
@@ -2122,6 +2122,7 @@ var BaseDialog = ({
2122
2122
  showCloseButton = true,
2123
2123
  buttonAlign = "flex-end",
2124
2124
  showCancelButton = true,
2125
+ showConfirmButton = true,
2125
2126
  formatTitle = true,
2126
2127
  fullWidth = false,
2127
2128
  className,
@@ -2198,7 +2199,7 @@ var BaseDialog = ({
2198
2199
  type: "button"
2199
2200
  },
2200
2201
  cancelText
2201
- ), form ? /* @__PURE__ */ React140.createElement(
2202
+ ), showConfirmButton && (form ? /* @__PURE__ */ React140.createElement(
2202
2203
  "button",
2203
2204
  {
2204
2205
  className: "btn-confirm",
@@ -2230,7 +2231,7 @@ var BaseDialog = ({
2230
2231
  },
2231
2232
  /* @__PURE__ */ React140.createElement("span", { style: { visibility: isButtonLoading ? "hidden" : "visible" } }, confirmText),
2232
2233
  isButtonLoading && /* @__PURE__ */ React140.createElement("span", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center" } }, /* @__PURE__ */ React140.createElement(circularProgress_default, { size: 18, color: "#ffffff80" }))
2233
- ));
2234
+ )));
2234
2235
  const containerClass = ["dialog-container", size ? `size-${size}` : "", sxClass, className].filter(Boolean).join(" ");
2235
2236
  const containerStyle = { minWidth, minHeight };
2236
2237
  const dialogInner = /* @__PURE__ */ React140.createElement(React140.Fragment, null, !hideHeader && /* @__PURE__ */ React140.createElement(React140.Fragment, null, customHeader ?? /* @__PURE__ */ React140.createElement("div", { className: "dialog-title" }, /* @__PURE__ */ React140.createElement("h2", null, formatTitle ? title?.charAt(0).toUpperCase() + title?.slice(1) : title), showCloseButton && /* @__PURE__ */ React140.createElement("button", { className: "btn-close", type: "button", onClick: onClose }, /* @__PURE__ */ React140.createElement(
@@ -4434,29 +4435,46 @@ var DateField = ({
4434
4435
  if (!rect) return {};
4435
4436
  const PICKER_H = 420;
4436
4437
  const GAP2 = 6;
4437
- const spaceBelow = window.innerHeight - rect.bottom - GAP2;
4438
+ const MARGIN = 8;
4439
+ const vw = window.innerWidth;
4440
+ const vh = window.innerHeight;
4441
+ const naturalW = isSideVariant ? 470 : 320;
4442
+ const avail = vw - MARGIN * 2;
4443
+ const scale = naturalW > avail ? avail / naturalW : 1;
4444
+ const scaledW = naturalW * scale;
4445
+ let left = rect.left;
4446
+ const maxLeft = vw - scaledW - MARGIN;
4447
+ if (left > maxLeft) left = maxLeft;
4448
+ if (left < MARGIN) left = MARGIN;
4449
+ const spaceBelow = vh - rect.bottom - GAP2;
4438
4450
  const spaceAbove = rect.top - GAP2;
4439
- const useDropUp = spaceBelow < PICKER_H && spaceAbove > spaceBelow;
4451
+ const useDropUp = spaceBelow < PICKER_H * scale && spaceAbove > spaceBelow;
4452
+ const common = {
4453
+ position: "fixed",
4454
+ left,
4455
+ width: naturalW,
4456
+ transform: scale === 1 ? void 0 : `scale(${scale})`,
4457
+ overflowY: "auto",
4458
+ zIndex: 99999
4459
+ };
4440
4460
  if (useDropUp) {
4441
4461
  return {
4442
- position: "fixed",
4443
- left: rect.left,
4462
+ ...common,
4444
4463
  // bottom anchors picker's bottom edge exactly to field top — no gap regardless of actual height
4445
- bottom: window.innerHeight - rect.top + GAP2,
4446
- // prevent going above viewport
4447
- maxHeight: rect.top - GAP2 - 4,
4448
- overflowY: "auto",
4449
- zIndex: 99999,
4450
- animationName: "rf-date-picker-appear-up",
4464
+ bottom: vh - rect.top + GAP2,
4465
+ // unscaled max-height — visual height after scaling fits the gap above
4466
+ maxHeight: (rect.top - GAP2 - MARGIN) / scale,
4467
+ // skip the scale-animating keyframes when we apply a static scale (they'd flash full-size)
4468
+ animationName: scale === 1 ? "rf-date-picker-appear-up" : "none",
4451
4469
  transformOrigin: "bottom left"
4452
4470
  };
4453
4471
  }
4454
4472
  return {
4455
- position: "fixed",
4456
- left: rect.left,
4473
+ ...common,
4457
4474
  top: rect.bottom + GAP2,
4458
- zIndex: 99999,
4459
- animationName: "rf-date-picker-appear",
4475
+ // unscaled max-height — visual height after scaling fits below the field
4476
+ maxHeight: (vh - rect.bottom - GAP2 - MARGIN) / scale,
4477
+ animationName: scale === 1 ? "rf-date-picker-appear" : "none",
4460
4478
  transformOrigin: "top left"
4461
4479
  };
4462
4480
  })(),
@@ -4836,6 +4854,43 @@ var DateRangeField = ({
4836
4854
  const [leftViewMonth, setLeftViewMonth] = useState9(() => today2.getMonth());
4837
4855
  const containerRef = useRef8(null);
4838
4856
  const inputId = useRef8(`rf-dr-${Math.random().toString(36).substr(2, 9)}`).current;
4857
+ const [mobileStyle, setMobileStyle] = useState9({});
4858
+ useEffect8(() => {
4859
+ if (!open) {
4860
+ setMobileStyle({});
4861
+ return;
4862
+ }
4863
+ const compute = () => {
4864
+ const vw = window.innerWidth;
4865
+ const vh = window.innerHeight;
4866
+ const MARGIN = 8;
4867
+ const GAP2 = 6;
4868
+ const naturalW = pickerType === "panel" ? 520 : 640;
4869
+ const avail = vw - MARGIN * 2;
4870
+ if (naturalW <= avail) {
4871
+ setMobileStyle({});
4872
+ return;
4873
+ }
4874
+ const scale = avail / naturalW;
4875
+ const rect = containerRef.current?.getBoundingClientRect();
4876
+ const top = rect ? rect.bottom + GAP2 : 60;
4877
+ setMobileStyle({
4878
+ position: "fixed",
4879
+ top,
4880
+ left: "50%",
4881
+ transform: `translateX(-50%) scale(${scale})`,
4882
+ transformOrigin: "top center",
4883
+ width: naturalW,
4884
+ maxHeight: (vh - top - MARGIN) / scale,
4885
+ overflowY: "auto",
4886
+ animation: "none",
4887
+ zIndex: 99999
4888
+ });
4889
+ };
4890
+ compute();
4891
+ window.addEventListener("resize", compute);
4892
+ return () => window.removeEventListener("resize", compute);
4893
+ }, [open, pickerType]);
4839
4894
  useEffect8(() => {
4840
4895
  const s2 = value?.start ? isoToDate2(value.start) : null;
4841
4896
  const e = value?.end ? isoToDate2(value.end) : null;
@@ -5033,7 +5088,7 @@ var DateRangeField = ({
5033
5088
  variant === "outlined" && /* @__PURE__ */ React148.createElement("fieldset", { className: "rf-text-field__notch" }, label ? /* @__PURE__ */ React148.createElement("legend", { className: "rf-text-field__legend" }, /* @__PURE__ */ React148.createElement("span", null, label, required ? " *" : "")) : /* @__PURE__ */ React148.createElement("legend", { className: "rf-text-field__legend--empty" }))
5034
5089
  ), open && !disabled && (pickerType === "panel" ? (
5035
5090
  /* ── Panel Mode ── */
5036
- /* @__PURE__ */ React148.createElement("div", { className: "rf-dr-picker rf-dr-picker--panel", onMouseDown: (e) => e.preventDefault() }, /* @__PURE__ */ React148.createElement("div", { className: "rf-dr-picker__presets" }, PRESETS.map((p, i) => /* @__PURE__ */ React148.createElement(React148.Fragment, { key: p.id }, i > 0 && /* @__PURE__ */ React148.createElement("div", { className: "rf-dr-picker__preset-sep" }), /* @__PURE__ */ React148.createElement(
5091
+ /* @__PURE__ */ React148.createElement("div", { className: "rf-dr-picker rf-dr-picker--panel", style: mobileStyle, onMouseDown: (e) => e.preventDefault() }, /* @__PURE__ */ React148.createElement("div", { className: "rf-dr-picker__presets" }, PRESETS.map((p, i) => /* @__PURE__ */ React148.createElement(React148.Fragment, { key: p.id }, i > 0 && /* @__PURE__ */ React148.createElement("div", { className: "rf-dr-picker__preset-sep" }), /* @__PURE__ */ React148.createElement(
5037
5092
  "button",
5038
5093
  {
5039
5094
  type: "button",
@@ -5153,7 +5208,7 @@ var DateRangeField = ({
5153
5208
  ))), /* @__PURE__ */ React148.createElement("div", { style: { flex: 1 } }), /* @__PURE__ */ React148.createElement("div", { className: "rf-dr-picker__footer" }, /* @__PURE__ */ React148.createElement("button", { type: "button", className: "rf-dr-picker__close-btn", onClick: handleClose }, "CLOSE"), /* @__PURE__ */ React148.createElement("button", { type: "button", className: "rf-dr-picker__apply-btn", onClick: handleApply }, "APPLY"))))
5154
5209
  ) : (
5155
5210
  /* ── Calendar Mode ── */
5156
- /* @__PURE__ */ React148.createElement("div", { className: "rf-dr-picker rf-dr-picker--calendar", onMouseDown: (e) => e.preventDefault() }, /* @__PURE__ */ React148.createElement("div", { className: "rf-dr-picker__calendars" }, /* @__PURE__ */ React148.createElement(
5211
+ /* @__PURE__ */ React148.createElement("div", { className: "rf-dr-picker rf-dr-picker--calendar", style: mobileStyle, onMouseDown: (e) => e.preventDefault() }, /* @__PURE__ */ React148.createElement("div", { className: "rf-dr-picker__calendars" }, /* @__PURE__ */ React148.createElement(
5157
5212
  RangeCalendarBody,
5158
5213
  {
5159
5214
  viewYear: leftViewYear,
@@ -5556,6 +5611,7 @@ function DataGrid({
5556
5611
  const menuRef = useRef10(null);
5557
5612
  const [showManageColumns, setShowManageColumns] = useState10(false);
5558
5613
  const [showAdvancedFilter, setShowAdvancedFilter] = useState10(false);
5614
+ const [mobileToolbarExpanded, setMobileToolbarExpanded] = useState10(false);
5559
5615
  const [focusFilterIdx, setFocusFilterIdx] = useState10(-1);
5560
5616
  const filterableColumnsProp = initialColumnsProp.filter((c) => c.filterable !== false);
5561
5617
  const initialFilterCol = String(filterableColumnsProp[0]?.field || filterableColumnsProp[0]?.key || "");
@@ -6045,14 +6101,24 @@ function DataGrid({
6045
6101
  onClick: () => setShowAdvancedFilter(true)
6046
6102
  },
6047
6103
  /* @__PURE__ */ React151.createElement(Funnel, { size: 16 })
6048
- )), showColumnsBtn && /* @__PURE__ */ React151.createElement(Tooltip, { title: "Manage Columns", placement: "top" }, /* @__PURE__ */ React151.createElement(
6104
+ )), /* @__PURE__ */ React151.createElement("div", { className: `dg-actions-overflow${mobileToolbarExpanded ? " dg-actions-overflow--expanded" : ""}` }, showColumnsBtn && /* @__PURE__ */ React151.createElement(Tooltip, { title: "Manage Columns", placement: "top" }, /* @__PURE__ */ React151.createElement(
6049
6105
  "button",
6050
6106
  {
6051
6107
  className: "dg-icon-btn",
6052
6108
  onClick: () => setShowManageColumns(true)
6053
6109
  },
6054
6110
  /* @__PURE__ */ React151.createElement(Columns2, { size: 16 })
6055
- )), showExportBtn && /* @__PURE__ */ React151.createElement("button", { className: "dg-action-btn", onClick: handleExport, disabled: loading }, /* @__PURE__ */ React151.createElement(Download, { size: 14 }), " Export CSV"), slotAt("after-actions"));
6111
+ )), showExportBtn && /* @__PURE__ */ React151.createElement("button", { className: "dg-action-btn", onClick: handleExport, disabled: loading }, /* @__PURE__ */ React151.createElement(Download, { size: 14 }), " Export CSV"), slotAt("after-actions")), (showColumnsBtn || showExportBtn || slots.some((s2) => s2.position === "after-actions" || !s2.position)) && /* @__PURE__ */ React151.createElement(
6112
+ "button",
6113
+ {
6114
+ type: "button",
6115
+ className: `dg-toolbar-toggle${mobileToolbarExpanded ? " dg-toolbar-toggle--expanded" : ""}`,
6116
+ onClick: () => setMobileToolbarExpanded((v) => !v),
6117
+ "aria-label": mobileToolbarExpanded ? "Hide toolbar options" : "Show all toolbar options",
6118
+ "aria-expanded": mobileToolbarExpanded
6119
+ },
6120
+ /* @__PURE__ */ React151.createElement(ChevronDown, { size: 18 })
6121
+ ));
6056
6122
  })())), !tOpts.hideHeader && /* @__PURE__ */ React151.createElement("div", { className: `dg-toolbar ${alignClass(toolbarContent?.align)}` }, toolbarContent?.content || ""), isGroupingActive && /* @__PURE__ */ React151.createElement("div", { className: "dg-grouping-bar" }, /* @__PURE__ */ React151.createElement("span", { className: "dg-grouping-bar-label" }, "Grouped by"), activeGroupingModel.map((gField) => {
6057
6123
  const col = resolvedColumns.find((c) => String(c.field) === gField || String(c.key) === gField);
6058
6124
  return /* @__PURE__ */ React151.createElement("div", { key: gField, className: "dg-group-chip" }, /* @__PURE__ */ React151.createElement(Layers, { size: 11 }), /* @__PURE__ */ React151.createElement("span", null, col?.header ?? col?.headerName ?? gField), !disableRowGrouping && /* @__PURE__ */ React151.createElement(
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rufous/ui",
3
3
  "private": false,
4
- "version": "0.3.61",
4
+ "version": "0.3.62",
5
5
  "type": "module",
6
6
  "description": "Experimental: A lightweight React UI component library (Beta)",
7
7
  "style": "./dist/main.css",