@universe-platform/ui 0.1.0-beta.17 → 0.1.0-beta.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -305,9 +305,14 @@ interface RelationFilterPopoverProps {
305
305
  }
306
306
  declare function RelationFilterPopover({ isOpen, onClose, column, triggerRect, options, filterValue, selectedValues, onSelectionChange, isLoading, }: RelationFilterPopoverProps): react_jsx_runtime.JSX.Element | null;
307
307
 
308
+ /**
309
+ * checkElementTruncation - Standard browser-accurate truncation detection using the Range API.
310
+ * Measures the exact unconstrained bounding box of rendered text without container padding interference.
311
+ */
312
+ declare const checkElementTruncation: (el: HTMLElement | null) => boolean;
308
313
  /**
309
314
  * useSmartTooltip - Reusable hook for detecting text truncation and rendering
310
- * a custom portal tooltip bubble strictly when content is clipped (scrollWidth > clientWidth).
315
+ * a custom portal tooltip bubble strictly when content is clipped (scrollWidth > el.clientWidth).
311
316
  */
312
317
  declare function useSmartTooltip<T extends HTMLElement = HTMLElement>(): {
313
318
  targetRef: react__default.RefObject<T | null>;
@@ -440,4 +445,4 @@ declare function ToastProvider({ children }: {
440
445
 
441
446
  declare function useToast(): ToastContextType;
442
447
 
443
- export { type BaseComponentProps, ColumnHeaderTitle, type ColumnHeaderTitleProps, type ComponentCommunication, type ComponentConfig, type ComponentData, type ComponentPermissions, type ComponentRegistry, type ComponentState, type CreateRecordPayload, CreateTemplateModal, type CreateTemplateModalProps, DatePickerCell, type DeleteRecordPayload, LinkPickerCell, type MetaTemplateComponent, type MetaWhatsAppTemplate, type OrgRole, PASTEL_PALETTES, type PastelPalette, type RelationFilterOption, type RelationFilterPayload, RelationFilterPopover, type RelationFilterPopoverProps, RelationPickerCell, type RolePermissions, type RowStatusType, SmartTextCell, type SplitTitleResult, TableBlock, type TableBlockProps, type TableConfig, type TableData, TimePickerCell, ToastContext, type ToastContextType, type ToastItem, ToastProvider, TruncatedTooltip, UNIVERSE_COMPONENTS, type UniverseComponentType, type UpdateRecordPayload, type UseColumnReorderOptions, type UseColumnResizeOptions, WhatsAppComponent, type WhatsAppComponentProps, type WhatsAppData, calculateMinColumnWidth, cn, formatConflictCellValue, formatPhoneDisplay, formatTimeInput, formatTimeIso, generateWhatsAppLink, getDeterministicPastelBadge, getRolePermissions, isValidPhoneNumber, measureTextWidth, normalizePhoneForWhatsApp, normalizeRelationValue, openWhatsAppChat, parseLinkValue, parseTimeParts, resolveProtocol, sanitizePhoneNumber, splitHeaderTitle, useColumnReorder, useColumnResize, useSmartTooltip, useToast };
448
+ export { type BaseComponentProps, ColumnHeaderTitle, type ColumnHeaderTitleProps, type ComponentCommunication, type ComponentConfig, type ComponentData, type ComponentPermissions, type ComponentRegistry, type ComponentState, type CreateRecordPayload, CreateTemplateModal, type CreateTemplateModalProps, DatePickerCell, type DeleteRecordPayload, LinkPickerCell, type MetaTemplateComponent, type MetaWhatsAppTemplate, type OrgRole, PASTEL_PALETTES, type PastelPalette, type RelationFilterOption, type RelationFilterPayload, RelationFilterPopover, type RelationFilterPopoverProps, RelationPickerCell, type RolePermissions, type RowStatusType, SmartTextCell, type SplitTitleResult, TableBlock, type TableBlockProps, type TableConfig, type TableData, TimePickerCell, ToastContext, type ToastContextType, type ToastItem, ToastProvider, TruncatedTooltip, UNIVERSE_COMPONENTS, type UniverseComponentType, type UpdateRecordPayload, type UseColumnReorderOptions, type UseColumnResizeOptions, WhatsAppComponent, type WhatsAppComponentProps, type WhatsAppData, calculateMinColumnWidth, checkElementTruncation, cn, formatConflictCellValue, formatPhoneDisplay, formatTimeInput, formatTimeIso, generateWhatsAppLink, getDeterministicPastelBadge, getRolePermissions, isValidPhoneNumber, measureTextWidth, normalizePhoneForWhatsApp, normalizeRelationValue, openWhatsAppChat, parseLinkValue, parseTimeParts, resolveProtocol, sanitizePhoneNumber, splitHeaderTitle, useColumnReorder, useColumnResize, useSmartTooltip, useToast };
package/dist/index.d.ts CHANGED
@@ -305,9 +305,14 @@ interface RelationFilterPopoverProps {
305
305
  }
306
306
  declare function RelationFilterPopover({ isOpen, onClose, column, triggerRect, options, filterValue, selectedValues, onSelectionChange, isLoading, }: RelationFilterPopoverProps): react_jsx_runtime.JSX.Element | null;
307
307
 
308
+ /**
309
+ * checkElementTruncation - Standard browser-accurate truncation detection using the Range API.
310
+ * Measures the exact unconstrained bounding box of rendered text without container padding interference.
311
+ */
312
+ declare const checkElementTruncation: (el: HTMLElement | null) => boolean;
308
313
  /**
309
314
  * useSmartTooltip - Reusable hook for detecting text truncation and rendering
310
- * a custom portal tooltip bubble strictly when content is clipped (scrollWidth > clientWidth).
315
+ * a custom portal tooltip bubble strictly when content is clipped (scrollWidth > el.clientWidth).
311
316
  */
312
317
  declare function useSmartTooltip<T extends HTMLElement = HTMLElement>(): {
313
318
  targetRef: react__default.RefObject<T | null>;
@@ -440,4 +445,4 @@ declare function ToastProvider({ children }: {
440
445
 
441
446
  declare function useToast(): ToastContextType;
442
447
 
443
- export { type BaseComponentProps, ColumnHeaderTitle, type ColumnHeaderTitleProps, type ComponentCommunication, type ComponentConfig, type ComponentData, type ComponentPermissions, type ComponentRegistry, type ComponentState, type CreateRecordPayload, CreateTemplateModal, type CreateTemplateModalProps, DatePickerCell, type DeleteRecordPayload, LinkPickerCell, type MetaTemplateComponent, type MetaWhatsAppTemplate, type OrgRole, PASTEL_PALETTES, type PastelPalette, type RelationFilterOption, type RelationFilterPayload, RelationFilterPopover, type RelationFilterPopoverProps, RelationPickerCell, type RolePermissions, type RowStatusType, SmartTextCell, type SplitTitleResult, TableBlock, type TableBlockProps, type TableConfig, type TableData, TimePickerCell, ToastContext, type ToastContextType, type ToastItem, ToastProvider, TruncatedTooltip, UNIVERSE_COMPONENTS, type UniverseComponentType, type UpdateRecordPayload, type UseColumnReorderOptions, type UseColumnResizeOptions, WhatsAppComponent, type WhatsAppComponentProps, type WhatsAppData, calculateMinColumnWidth, cn, formatConflictCellValue, formatPhoneDisplay, formatTimeInput, formatTimeIso, generateWhatsAppLink, getDeterministicPastelBadge, getRolePermissions, isValidPhoneNumber, measureTextWidth, normalizePhoneForWhatsApp, normalizeRelationValue, openWhatsAppChat, parseLinkValue, parseTimeParts, resolveProtocol, sanitizePhoneNumber, splitHeaderTitle, useColumnReorder, useColumnResize, useSmartTooltip, useToast };
448
+ export { type BaseComponentProps, ColumnHeaderTitle, type ColumnHeaderTitleProps, type ComponentCommunication, type ComponentConfig, type ComponentData, type ComponentPermissions, type ComponentRegistry, type ComponentState, type CreateRecordPayload, CreateTemplateModal, type CreateTemplateModalProps, DatePickerCell, type DeleteRecordPayload, LinkPickerCell, type MetaTemplateComponent, type MetaWhatsAppTemplate, type OrgRole, PASTEL_PALETTES, type PastelPalette, type RelationFilterOption, type RelationFilterPayload, RelationFilterPopover, type RelationFilterPopoverProps, RelationPickerCell, type RolePermissions, type RowStatusType, SmartTextCell, type SplitTitleResult, TableBlock, type TableBlockProps, type TableConfig, type TableData, TimePickerCell, ToastContext, type ToastContextType, type ToastItem, ToastProvider, TruncatedTooltip, UNIVERSE_COMPONENTS, type UniverseComponentType, type UpdateRecordPayload, type UseColumnReorderOptions, type UseColumnResizeOptions, WhatsAppComponent, type WhatsAppComponentProps, type WhatsAppData, calculateMinColumnWidth, checkElementTruncation, cn, formatConflictCellValue, formatPhoneDisplay, formatTimeInput, formatTimeIso, generateWhatsAppLink, getDeterministicPastelBadge, getRolePermissions, isValidPhoneNumber, measureTextWidth, normalizePhoneForWhatsApp, normalizeRelationValue, openWhatsAppChat, parseLinkValue, parseTimeParts, resolveProtocol, sanitizePhoneNumber, splitHeaderTitle, useColumnReorder, useColumnResize, useSmartTooltip, useToast };
package/dist/index.js CHANGED
@@ -81,6 +81,7 @@ __export(src_exports, {
81
81
  UNIVERSE_COMPONENTS: () => UNIVERSE_COMPONENTS,
82
82
  WhatsAppComponent: () => WhatsAppComponent,
83
83
  calculateMinColumnWidth: () => calculateMinColumnWidth,
84
+ checkElementTruncation: () => checkElementTruncation,
84
85
  cn: () => cn,
85
86
  extractUniqueVariableIndices: () => extractUniqueVariableIndices,
86
87
  extractVariableIndices: () => extractVariableIndices,
@@ -1397,6 +1398,31 @@ var import_lucide_react3 = require("lucide-react");
1397
1398
  var import_react4 = require("react");
1398
1399
  var import_react_dom = require("react-dom");
1399
1400
  var import_jsx_runtime3 = require("react/jsx-runtime");
1401
+ var checkElementTruncation = (el) => {
1402
+ if (!el) return false;
1403
+ const isInput = el instanceof HTMLInputElement || el.tagName === "INPUT";
1404
+ const text = isInput ? el.value : el.textContent;
1405
+ if (!text) return false;
1406
+ if (!isInput && typeof document !== "undefined" && document.createRange) {
1407
+ try {
1408
+ const range = document.createRange();
1409
+ range.selectNodeContents(el);
1410
+ const textWidth = range.getBoundingClientRect().width;
1411
+ let clientWidth = el.clientWidth;
1412
+ if (typeof window !== "undefined" && window.getComputedStyle) {
1413
+ const style = window.getComputedStyle(el);
1414
+ const paddingLeft = parseFloat(style.paddingLeft) || 0;
1415
+ const paddingRight = parseFloat(style.paddingRight) || 0;
1416
+ clientWidth = clientWidth - paddingLeft - paddingRight;
1417
+ }
1418
+ if (textWidth > 0 && clientWidth > 0) {
1419
+ return Math.ceil(textWidth) > Math.floor(clientWidth);
1420
+ }
1421
+ } catch (e) {
1422
+ }
1423
+ }
1424
+ return el.scrollWidth > el.clientWidth;
1425
+ };
1400
1426
  function useSmartTooltip() {
1401
1427
  const [isTruncated, setIsTruncated] = (0, import_react4.useState)(false);
1402
1428
  const [showBubble, setShowBubble] = (0, import_react4.useState)(false);
@@ -1405,14 +1431,14 @@ function useSmartTooltip() {
1405
1431
  const checkTruncation = (0, import_react4.useCallback)(() => {
1406
1432
  const el = targetRef.current;
1407
1433
  if (!el) return false;
1408
- const truncated = el.scrollWidth > el.clientWidth;
1434
+ const truncated = checkElementTruncation(el);
1409
1435
  setIsTruncated(truncated);
1410
1436
  return truncated;
1411
1437
  }, []);
1412
1438
  const handleMouseEnter = (0, import_react4.useCallback)(() => {
1413
1439
  const el = targetRef.current;
1414
1440
  if (!el) return;
1415
- const truncated = el.scrollWidth > el.clientWidth;
1441
+ const truncated = checkElementTruncation(el);
1416
1442
  setIsTruncated(truncated);
1417
1443
  if (truncated) {
1418
1444
  const rect = el.getBoundingClientRect();
@@ -1492,7 +1518,7 @@ var TruncatedTooltip = ({
1492
1518
  const handleMouseEnter = () => {
1493
1519
  const el = spanRef.current;
1494
1520
  if (!el) return;
1495
- const truncated = el.scrollWidth > el.clientWidth;
1521
+ const truncated = checkElementTruncation(el);
1496
1522
  setIsTruncated(truncated);
1497
1523
  if (truncated && tooltipContent.trim().length > 0) {
1498
1524
  const rect = el.getBoundingClientRect();
@@ -1583,12 +1609,21 @@ var SmartTextCell = ({
1583
1609
  const textValue = value !== void 0 && value !== null ? String(value) : "";
1584
1610
  const effectiveTooltip = tooltipText !== void 0 ? tooltipText : textValue;
1585
1611
  const checkTruncation = (0, import_react4.useCallback)(() => {
1612
+ if (!readOnly && inputRef.current && spanRef.current) {
1613
+ const inputEl = inputRef.current;
1614
+ let padding = 16;
1615
+ if (typeof window !== "undefined" && window.getComputedStyle) {
1616
+ const style = window.getComputedStyle(inputEl);
1617
+ padding = (parseFloat(style.paddingLeft) || 8) + (parseFloat(style.paddingRight) || 8);
1618
+ }
1619
+ spanRef.current.style.width = `${Math.max(0, inputEl.clientWidth - padding)}px`;
1620
+ }
1586
1621
  const el = spanRef.current || inputRef.current;
1587
1622
  if (!el) return false;
1588
- const truncated = el.scrollWidth > el.clientWidth;
1623
+ const truncated = checkElementTruncation(el);
1589
1624
  setIsTruncated(truncated);
1590
1625
  return truncated;
1591
- }, []);
1626
+ }, [readOnly]);
1592
1627
  const handleMouseEnter = () => {
1593
1628
  const truncated = checkTruncation();
1594
1629
  const targetEl = readOnly ? spanRef.current : inputRef.current || spanRef.current;
@@ -1701,7 +1736,9 @@ var SmartTextCell = ({
1701
1736
  "aria-hidden": "true",
1702
1737
  dir,
1703
1738
  className: "invisible pointer-events-none absolute truncate overflow-hidden text-ellipsis whitespace-nowrap max-w-full",
1704
- style: { width: inputRef.current ? `${inputRef.current.clientWidth}px` : void 0 },
1739
+ style: {
1740
+ width: inputRef.current ? `${Math.max(0, inputRef.current.clientWidth - 16)}px` : void 0
1741
+ },
1705
1742
  children: textValue
1706
1743
  }
1707
1744
  ),
@@ -7601,7 +7638,7 @@ var TableRow = import_react15.default.memo(function TableRow2({
7601
7638
  permissions
7602
7639
  }) {
7603
7640
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react15.default.Fragment, { children: [
7604
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { className: `hover:bg-blue-50/30 transition-colors group ${isSelected ? "bg-blue-50/40" : ""}`, children: [
7641
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { className: `transition-colors group hover:bg-blue-50 ${isSelected ? "bg-blue-50" : ""}`, children: [
7605
7642
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { className: "border-b border-l border-slate-200 p-1.5 text-center bg-white group-hover:bg-transparent", style: { width: 80, minWidth: 80, maxWidth: 80 }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center justify-center gap-1.5", children: [
7606
7643
  rowStatus && (() => {
7607
7644
  const status = typeof rowStatus === "string" ? rowStatus : rowStatus.status;
@@ -12573,6 +12610,7 @@ var UNIVERSE_COMPONENTS = {
12573
12610
  UNIVERSE_COMPONENTS,
12574
12611
  WhatsAppComponent,
12575
12612
  calculateMinColumnWidth,
12613
+ checkElementTruncation,
12576
12614
  cn,
12577
12615
  extractUniqueVariableIndices,
12578
12616
  extractVariableIndices,
package/dist/index.mjs CHANGED
@@ -1297,6 +1297,31 @@ import { Calendar as CalendarIcon, ChevronLeft, ChevronRight, X as X3 } from "lu
1297
1297
  import { useState as useState3, useRef as useRef3, useEffect as useEffect2, useCallback as useCallback2 } from "react";
1298
1298
  import { createPortal } from "react-dom";
1299
1299
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1300
+ var checkElementTruncation = (el) => {
1301
+ if (!el) return false;
1302
+ const isInput = el instanceof HTMLInputElement || el.tagName === "INPUT";
1303
+ const text = isInput ? el.value : el.textContent;
1304
+ if (!text) return false;
1305
+ if (!isInput && typeof document !== "undefined" && document.createRange) {
1306
+ try {
1307
+ const range = document.createRange();
1308
+ range.selectNodeContents(el);
1309
+ const textWidth = range.getBoundingClientRect().width;
1310
+ let clientWidth = el.clientWidth;
1311
+ if (typeof window !== "undefined" && window.getComputedStyle) {
1312
+ const style = window.getComputedStyle(el);
1313
+ const paddingLeft = parseFloat(style.paddingLeft) || 0;
1314
+ const paddingRight = parseFloat(style.paddingRight) || 0;
1315
+ clientWidth = clientWidth - paddingLeft - paddingRight;
1316
+ }
1317
+ if (textWidth > 0 && clientWidth > 0) {
1318
+ return Math.ceil(textWidth) > Math.floor(clientWidth);
1319
+ }
1320
+ } catch (e) {
1321
+ }
1322
+ }
1323
+ return el.scrollWidth > el.clientWidth;
1324
+ };
1300
1325
  function useSmartTooltip() {
1301
1326
  const [isTruncated, setIsTruncated] = useState3(false);
1302
1327
  const [showBubble, setShowBubble] = useState3(false);
@@ -1305,14 +1330,14 @@ function useSmartTooltip() {
1305
1330
  const checkTruncation = useCallback2(() => {
1306
1331
  const el = targetRef.current;
1307
1332
  if (!el) return false;
1308
- const truncated = el.scrollWidth > el.clientWidth;
1333
+ const truncated = checkElementTruncation(el);
1309
1334
  setIsTruncated(truncated);
1310
1335
  return truncated;
1311
1336
  }, []);
1312
1337
  const handleMouseEnter = useCallback2(() => {
1313
1338
  const el = targetRef.current;
1314
1339
  if (!el) return;
1315
- const truncated = el.scrollWidth > el.clientWidth;
1340
+ const truncated = checkElementTruncation(el);
1316
1341
  setIsTruncated(truncated);
1317
1342
  if (truncated) {
1318
1343
  const rect = el.getBoundingClientRect();
@@ -1392,7 +1417,7 @@ var TruncatedTooltip = ({
1392
1417
  const handleMouseEnter = () => {
1393
1418
  const el = spanRef.current;
1394
1419
  if (!el) return;
1395
- const truncated = el.scrollWidth > el.clientWidth;
1420
+ const truncated = checkElementTruncation(el);
1396
1421
  setIsTruncated(truncated);
1397
1422
  if (truncated && tooltipContent.trim().length > 0) {
1398
1423
  const rect = el.getBoundingClientRect();
@@ -1483,12 +1508,21 @@ var SmartTextCell = ({
1483
1508
  const textValue = value !== void 0 && value !== null ? String(value) : "";
1484
1509
  const effectiveTooltip = tooltipText !== void 0 ? tooltipText : textValue;
1485
1510
  const checkTruncation = useCallback2(() => {
1511
+ if (!readOnly && inputRef.current && spanRef.current) {
1512
+ const inputEl = inputRef.current;
1513
+ let padding = 16;
1514
+ if (typeof window !== "undefined" && window.getComputedStyle) {
1515
+ const style = window.getComputedStyle(inputEl);
1516
+ padding = (parseFloat(style.paddingLeft) || 8) + (parseFloat(style.paddingRight) || 8);
1517
+ }
1518
+ spanRef.current.style.width = `${Math.max(0, inputEl.clientWidth - padding)}px`;
1519
+ }
1486
1520
  const el = spanRef.current || inputRef.current;
1487
1521
  if (!el) return false;
1488
- const truncated = el.scrollWidth > el.clientWidth;
1522
+ const truncated = checkElementTruncation(el);
1489
1523
  setIsTruncated(truncated);
1490
1524
  return truncated;
1491
- }, []);
1525
+ }, [readOnly]);
1492
1526
  const handleMouseEnter = () => {
1493
1527
  const truncated = checkTruncation();
1494
1528
  const targetEl = readOnly ? spanRef.current : inputRef.current || spanRef.current;
@@ -1601,7 +1635,9 @@ var SmartTextCell = ({
1601
1635
  "aria-hidden": "true",
1602
1636
  dir,
1603
1637
  className: "invisible pointer-events-none absolute truncate overflow-hidden text-ellipsis whitespace-nowrap max-w-full",
1604
- style: { width: inputRef.current ? `${inputRef.current.clientWidth}px` : void 0 },
1638
+ style: {
1639
+ width: inputRef.current ? `${Math.max(0, inputRef.current.clientWidth - 16)}px` : void 0
1640
+ },
1605
1641
  children: textValue
1606
1642
  }
1607
1643
  ),
@@ -7501,7 +7537,7 @@ var TableRow = React12.memo(function TableRow2({
7501
7537
  permissions
7502
7538
  }) {
7503
7539
  return /* @__PURE__ */ jsxs12(React12.Fragment, { children: [
7504
- /* @__PURE__ */ jsxs12("tr", { className: `hover:bg-blue-50/30 transition-colors group ${isSelected ? "bg-blue-50/40" : ""}`, children: [
7540
+ /* @__PURE__ */ jsxs12("tr", { className: `transition-colors group hover:bg-blue-50 ${isSelected ? "bg-blue-50" : ""}`, children: [
7505
7541
  /* @__PURE__ */ jsx12("td", { className: "border-b border-l border-slate-200 p-1.5 text-center bg-white group-hover:bg-transparent", style: { width: 80, minWidth: 80, maxWidth: 80 }, children: /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-center gap-1.5", children: [
7506
7542
  rowStatus && (() => {
7507
7543
  const status = typeof rowStatus === "string" ? rowStatus : rowStatus.status;
@@ -12521,6 +12557,7 @@ export {
12521
12557
  UNIVERSE_COMPONENTS,
12522
12558
  WhatsAppComponent,
12523
12559
  calculateMinColumnWidth,
12560
+ checkElementTruncation,
12524
12561
  cn,
12525
12562
  extractUniqueVariableIndices,
12526
12563
  extractVariableIndices,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@universe-platform/ui",
3
- "version": "0.1.0-beta.17",
3
+ "version": "0.1.0-beta.18",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",