@universe-platform/ui 0.1.0-beta.2 → 0.1.0-beta.20

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.ts CHANGED
@@ -1,7 +1,73 @@
1
1
  import { ClassValue } from 'clsx';
2
+ import { ColumnDef } from './columns';
3
+ export { BaseColumnDef, COLUMN_CAPABILITIES, COLUMN_DEFAULT_INPUT_CONFIG, COLUMN_TYPES, COLUMN_TYPE_LABELS, ColumnCapabilities, ColumnConfig, ColumnConfigMap, ColumnDef, ColumnDefaultInputConfig, ColumnInfo, ColumnType, CurrencyConfig, ExtendedColumnInfo, GoogleContactConfig, GoogleContactNamePart, PhoneConfig, RelationConfig, SubTableConfig, TEXT_REPRESENTABLE_TYPES, TextRepresentableColumnType, TypedColumnDef, isTextRepresentable } from './columns';
4
+ import { RecordData, CellValue } from './records';
5
+ export { CellValue, ColumnValueMap, DriveFileValue, GoogleContactValue, LinkValue, RecordData, SubTableEntryValue, SubTableResolvedEntryValue } from './records';
6
+ import { WhatsAppConfig } from './pages';
7
+ export { BaseComponent, ComponentType, EditorApp, EditorPage, PageComponent, PageInput, TableComponent, WhatsAppConfig } from './pages';
8
+ import { SchemaDef } from './schema';
9
+ export { SchemaDef, TableMeta } from './schema';
10
+ import { TemplateIdentity } from './whatsappValidation';
11
+ export * from './whatsappValidation';
12
+ export { StatusConfig, TemplateIdentity, TemplateValidationParams, TemplateValidationResult, extractUniqueVariableIndices, extractVariableIndices, findVariableAtPosition, formatFileSize, getNextVariableIndex, getStatusConfig, hasBracketSpaces, hasConsecutiveVariables, hasFloatingVariables, hasInsufficientContextBetweenVariables, isDuplicateTemplate, isDuplicateTemplateName, isValidTemplateName, isWordToken, reindexVariables, sanitizeTemplateNameInput, seamlessVariableEngine, validateSequentialVariables, validateTemplateBody, validateWhatsAppTemplate, validateWordToVariableRatio } from './whatsappValidation';
13
+ import * as react_jsx_runtime from 'react/jsx-runtime';
14
+ import * as react from 'react';
15
+ import react__default, { ReactNode } from 'react';
2
16
 
3
17
  declare function cn(...inputs: ClassValue[]): string;
4
18
 
19
+ /**
20
+ * WhatsApp opener and phone formatting utilities.
21
+ */
22
+ /**
23
+ * Robust WhatsApp Opener (Desktop App with Web Fallback).
24
+ * Tries the direct protocol first (whatsapp://) and falls back to WhatsApp Web
25
+ * if the app is not installed (window didn't lose focus).
26
+ */
27
+ declare function openWhatsAppChat(phone: string, defaultCountryCode?: string): void;
28
+ /**
29
+ * Formats a phone number for local UI display (e.g. Israeli 05X-XXX-XXXX format).
30
+ */
31
+ declare function formatPhoneDisplay(phone: string): string;
32
+
33
+ /**
34
+ * Phone number sanitization, validation, and WhatsApp link generation utilities.
35
+ * Pure functions with zero React or DOM dependencies for universal (server & client) usage.
36
+ */
37
+ /**
38
+ * Sanitizes phone numbers by stripping whitespace, dashes, and non-numeric characters,
39
+ * preserving a leading '+' if present.
40
+ */
41
+ declare function sanitizePhoneNumber(phone: string): string;
42
+ /**
43
+ * Validates whether a phone number is valid (after sanitization).
44
+ * Supports Israeli formats (e.g. 0501234567, 031234567) and international formats (+972..., 9-15 digits).
45
+ */
46
+ declare function isValidPhoneNumber(phone: string): boolean;
47
+ /**
48
+ * Generates an official wa.me WhatsApp direct message link.
49
+ *
50
+ * @param phone Raw or sanitized phone number
51
+ * @param defaultCountryCode Defaults to Israeli code '972'
52
+ * @returns WhatsApp URL or null if phone is empty
53
+ */
54
+ declare function generateWhatsAppLink(phone: string, defaultCountryCode?: string): string | null;
55
+ /**
56
+ * Normalizes a phone number for WhatsApp sending (E.164 without leading '+').
57
+ * - Strips spaces, dashes, and special characters.
58
+ * - If it starts with '05' (10 digits), replaces the leading '0' with '972' (e.g., '0586812807' -> '972586812807').
59
+ * - If it starts with '+', strips the '+'.
60
+ */
61
+ declare function normalizePhoneForWhatsApp(phone: string): string;
62
+
63
+ interface PastelPalette {
64
+ bg: string;
65
+ text: string;
66
+ border: string;
67
+ }
68
+ declare const PASTEL_PALETTES: PastelPalette[];
69
+ declare function getDeterministicPastelBadge(key: string): PastelPalette;
70
+
5
71
  /**
6
72
  * Core definitions for Universe UI components.
7
73
  * These interfaces define the standard contract that all generic visual components
@@ -41,7 +107,342 @@ interface BaseComponentProps<TData = any, TConfig = Record<string, any>> extends
41
107
  "data-testid"?: string;
42
108
  }
43
109
 
44
- declare const isUiLibraryReady = true;
45
- declare const isUiLibraryReadyNot = false;
110
+ type OrgRole = "OWNER" | "EDITOR" | "VIEWER";
111
+ interface RolePermissions {
112
+ permissions: ComponentPermissions;
113
+ readOnly: boolean;
114
+ }
115
+ declare function getRolePermissions(role?: OrgRole | null): RolePermissions;
116
+
117
+ interface TableConfig extends SchemaDef {
118
+ }
119
+ type TableData = RecordData[];
120
+ type RowStatusType = "success" | "failed" | "skipped" | "partial";
121
+ interface TableBlockProps extends Partial<BaseComponentProps<TableData, TableConfig>> {
122
+ exportAction?: (payload: any) => Promise<any>;
123
+ role?: OrgRole | null;
124
+ permissions?: ComponentPermissions;
125
+ readOnly?: boolean;
126
+ onSelectionChange?: (selectedIds: string[]) => void;
127
+ rowStatusMap?: Record<string, {
128
+ status: RowStatusType;
129
+ tooltip?: string;
130
+ } | RowStatusType>;
131
+ editModelUrl?: string;
132
+ }
133
+ interface CreateRecordPayload {
134
+ records: RecordData[];
135
+ }
136
+ interface UpdateRecordPayload {
137
+ modifications: Record<string, Record<string, any>>;
138
+ }
139
+ interface DeleteRecordPayload {
140
+ ids: string[];
141
+ }
142
+
143
+ declare function TableBlock(props: TableBlockProps): react_jsx_runtime.JSX.Element;
144
+
145
+ interface UseColumnResizeOptions {
146
+ storageKey: string;
147
+ defaultWidth?: number;
148
+ minWidth?: number;
149
+ maxWidth?: number;
150
+ getMinColWidth?: (colName: string) => number;
151
+ }
152
+ declare function useColumnResize({ storageKey, defaultWidth, minWidth, maxWidth, getMinColWidth, }: UseColumnResizeOptions): {
153
+ columnWidths: Record<string, number>;
154
+ setColumnWidths: react.Dispatch<react.SetStateAction<Record<string, number>>>;
155
+ resizingCol: {
156
+ name: string;
157
+ startWidth: number;
158
+ startX: number;
159
+ minWidth: number;
160
+ } | null;
161
+ startResize: (colName: string, currentWidth: number, clientX: number, customMinWidth?: number) => void;
162
+ getWidth: (colName: string, fallback?: number) => number;
163
+ minWidth: number;
164
+ };
165
+
166
+ interface UseColumnReorderOptions {
167
+ onReorder: (draggedName: string, dropTargetName: string) => void | Promise<void>;
168
+ disabled?: boolean;
169
+ }
170
+ declare function useColumnReorder({ onReorder, disabled, }: UseColumnReorderOptions): {
171
+ draggedColName: string | null;
172
+ dragOverColName: string | null;
173
+ isDragging: (colName: string) => boolean;
174
+ isDragOver: (colName: string) => boolean;
175
+ getHeaderDragProps: (colName: string) => {
176
+ draggable: boolean;
177
+ onDragStart?: undefined;
178
+ onDragOver?: undefined;
179
+ onDragLeave?: undefined;
180
+ onDrop?: undefined;
181
+ onDragEnd?: undefined;
182
+ } | {
183
+ draggable: boolean;
184
+ onDragStart: (e: React.DragEvent) => void;
185
+ onDragOver: (e: React.DragEvent) => void;
186
+ onDragLeave: () => void;
187
+ onDrop: (e: React.DragEvent) => void;
188
+ onDragEnd: () => void;
189
+ };
190
+ };
191
+
192
+ /**
193
+ * Measure the width of a given text string in canvas 2D context using the specified font.
194
+ */
195
+ declare function measureTextWidth(text: string, font?: string): number;
196
+ interface SplitTitleResult {
197
+ isSingleWord: boolean;
198
+ line1: string;
199
+ line2?: string;
200
+ }
201
+ /**
202
+ * Splits a header title:
203
+ * - 1 word: stays on 1 line.
204
+ * - 2 or more words: divided as equally as possible between 2 lines without cutting any word.
205
+ */
206
+ declare function splitHeaderTitle(name: string): SplitTitleResult;
207
+ /**
208
+ * Calculate the minimum column width needed to display the header title cleanly:
209
+ * - If 1 word: minimum width is that word + padding + icon.
210
+ * - If 2+ words: minimum width is the longest line + padding + icon.
211
+ * - For specialized field types like GOOGLE_CONTACT: ensures room for button.
212
+ * Words are NEVER cut or truncated with ellipsis.
213
+ */
214
+ declare function calculateMinColumnWidth(name: string, isSubTable?: boolean, colType?: string): number;
215
+ interface ColumnHeaderTitleProps {
216
+ name: string;
217
+ width?: number;
218
+ isSubTable?: boolean;
219
+ }
220
+ /**
221
+ * Header title component:
222
+ * - Default / when enough width: takes up entire line on 1 single row.
223
+ * - When column is shrunk below full-line width: divides evenly into 2 rows without cutting any word.
224
+ * - Single words always stay on 1 row.
225
+ */
226
+ declare function ColumnHeaderTitle({ name, width, isSubTable }: ColumnHeaderTitleProps): react_jsx_runtime.JSX.Element;
227
+
228
+ declare function formatConflictCellValue(rawVal: any, colDef?: ColumnDef | {
229
+ name: string;
230
+ type?: string;
231
+ config?: any;
232
+ }, relationOptionsMap?: Record<string, any[]>): react__default.ReactNode;
233
+
234
+ interface DatePickerCellProps {
235
+ value: CellValue<'DATE'> | Date | number;
236
+ onChange: (value: CellValue<'DATE'>) => void;
237
+ column?: ColumnDef;
238
+ readOnly?: boolean;
239
+ }
240
+ declare function DatePickerCell({ value, onChange, readOnly }: DatePickerCellProps): react_jsx_runtime.JSX.Element;
241
+
242
+ interface TimePickerCellProps {
243
+ value: CellValue<'TIME'> | Date;
244
+ onChange: (value: CellValue<'TIME'>) => void;
245
+ column?: ColumnDef;
246
+ readOnly?: boolean;
247
+ }
248
+ declare function parseTimeParts(val: any): {
249
+ hour: number;
250
+ minute: number;
251
+ } | null;
252
+ declare function formatTimeIso(hour: number, minute: number): string;
253
+ declare function formatTimeInput(input: string | null | undefined): string;
254
+ declare function TimePickerCell({ value, onChange, readOnly }: TimePickerCellProps): react_jsx_runtime.JSX.Element;
255
+
256
+ interface LinkPickerCellProps {
257
+ value: CellValue<'LINK'> | string;
258
+ onChange: (value: CellValue<'LINK'>) => void;
259
+ column?: ColumnDef;
260
+ readOnly?: boolean;
261
+ }
262
+ declare function parseLinkValue(val: CellValue<'LINK'> | string): {
263
+ url: string;
264
+ label: string;
265
+ };
266
+ declare function resolveProtocol(url: string): string;
267
+ declare function LinkPickerCell({ value, onChange, readOnly }: LinkPickerCellProps): react_jsx_runtime.JSX.Element;
268
+
269
+ interface RelationPickerCellProps {
270
+ value: CellValue<'RELATION'> | string;
271
+ onChange: (value: CellValue<'RELATION'>) => void;
272
+ column: ColumnDef<'RELATION'> | ColumnDef;
273
+ context?: any;
274
+ rowId?: string;
275
+ readOnly?: boolean;
276
+ }
277
+ /**
278
+ * Normalizes any relation value into a canonical string[] of record IDs.
279
+ * Handles legacy single-string records, empty strings, null/undefined, and object shapes.
280
+ */
281
+ declare function normalizeRelationValue(val: any): string[];
282
+ declare function RelationPickerCell({ value, onChange, column, context, rowId, readOnly, }: RelationPickerCellProps): react_jsx_runtime.JSX.Element;
283
+
284
+ interface RelationFilterOption {
285
+ id: string;
286
+ label: string;
287
+ }
288
+ type RelationFilterPayload = string[] | {
289
+ operator: 'notIn';
290
+ values: string[];
291
+ } | undefined;
292
+ interface RelationFilterPopoverProps {
293
+ isOpen: boolean;
294
+ onClose: () => void;
295
+ column: ColumnDef;
296
+ triggerRect: DOMRect | null;
297
+ options: RelationFilterOption[];
298
+ filterValue?: string[] | {
299
+ operator: 'notIn';
300
+ values: string[];
301
+ };
302
+ selectedValues?: string[];
303
+ onSelectionChange: (payload: RelationFilterPayload) => void;
304
+ isLoading?: boolean;
305
+ }
306
+ declare function RelationFilterPopover({ isOpen, onClose, column, triggerRect, options, filterValue, selectedValues, onSelectionChange, isLoading, }: RelationFilterPopoverProps): react_jsx_runtime.JSX.Element | null;
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;
313
+ /**
314
+ * useSmartTooltip - Reusable hook for detecting text truncation and rendering
315
+ * a custom portal tooltip bubble strictly when content is clipped (scrollWidth > el.clientWidth).
316
+ */
317
+ declare function useSmartTooltip<T extends HTMLElement = HTMLElement>(): {
318
+ targetRef: react__default.RefObject<T | null>;
319
+ checkTruncation: () => boolean;
320
+ handleMouseEnter: () => void;
321
+ handleMouseLeave: () => void;
322
+ hideBubble: () => void;
323
+ renderTooltip: (text?: string, dir?: "ltr" | "rtl" | "auto") => react__default.ReactPortal | null;
324
+ isTruncated: boolean;
325
+ showBubble: boolean;
326
+ };
327
+ interface TruncatedTooltipProps {
328
+ text: string;
329
+ tooltipText?: string;
330
+ dir?: 'ltr' | 'rtl' | 'auto';
331
+ className?: string;
332
+ wrapperClassName?: string;
333
+ children?: react__default.ReactNode;
334
+ }
335
+ /**
336
+ * TruncatedTooltip - A text container that applies ellipsis truncation
337
+ * and only displays a custom portal tooltip when text overflows horizontal bounds.
338
+ * Expands to full cell dimensions (w-full h-full min-h-[inherit]) for reliable hover detection.
339
+ * No native browser title attribute is rendered.
340
+ */
341
+ declare const TruncatedTooltip: react__default.FC<TruncatedTooltipProps>;
342
+ interface SmartTextCellProps {
343
+ value: any;
344
+ onChange?: (val: any) => void;
345
+ readOnly?: boolean;
346
+ type?: 'text' | 'number' | 'tel';
347
+ placeholder?: string;
348
+ className?: string;
349
+ prefix?: react__default.ReactNode;
350
+ suffix?: react__default.ReactNode;
351
+ dir?: 'ltr' | 'rtl' | 'auto';
352
+ tooltipText?: string;
353
+ step?: string;
354
+ onFocus?: (e: react__default.FocusEvent<HTMLInputElement>) => void;
355
+ onBlur?: (e: react__default.FocusEvent<HTMLInputElement>) => void;
356
+ }
357
+ /**
358
+ * SmartTextCell - Text cell with intelligent hover tooltip.
359
+ * Only displays the custom portal tooltip bubble if the text is actually
360
+ * clipped/truncated within its visible boundary (scrollWidth > clientWidth).
361
+ * Native title attributes are omitted to prevent duplicate tooltips.
362
+ */
363
+ declare const SmartTextCell: react__default.FC<SmartTextCellProps>;
364
+
365
+ interface MetaTemplateComponent {
366
+ type: "HEADER" | "BODY" | "FOOTER" | "BUTTONS" | string;
367
+ format?: "TEXT" | "IMAGE" | "DOCUMENT" | "VIDEO" | string;
368
+ text?: string;
369
+ example?: {
370
+ header_handle?: string[];
371
+ body_text?: string[][];
372
+ [key: string]: any;
373
+ };
374
+ [key: string]: any;
375
+ }
376
+ interface MetaWhatsAppTemplate {
377
+ id: string;
378
+ name: string;
379
+ status: "APPROVED" | "PENDING" | "IN_REVIEW" | "REJECTED" | "PAUSED" | string;
380
+ category: "MARKETING" | "UTILITY" | string;
381
+ language: string;
382
+ components?: MetaTemplateComponent[];
383
+ [key: string]: any;
384
+ }
385
+ type WhatsAppData = any;
386
+ interface WhatsAppComponentProps extends Partial<BaseComponentProps<WhatsAppData, WhatsAppConfig>> {
387
+ permissions?: ComponentPermissions;
388
+ orgId?: string;
389
+ organizationId?: string;
390
+ }
391
+
392
+ /**
393
+ * WhatsAppComponent
394
+ * High-level orchestrator for the WhatsApp messaging interface.
395
+ * Coordinates template selection, dynamic filters, recipient settings/actions,
396
+ * and the embedded data grid.
397
+ */
398
+ declare function WhatsAppComponent(props: WhatsAppComponentProps): react_jsx_runtime.JSX.Element;
399
+
400
+ interface CreateTemplateModalProps {
401
+ isOpen: boolean;
402
+ onClose: () => void;
403
+ onSuccess: () => void;
404
+ existingTemplateNames?: string[];
405
+ existingTemplates?: TemplateIdentity[];
406
+ executeAction?: (actionType: string, payload: Record<string, any>) => Promise<any>;
407
+ orgId?: string;
408
+ }
409
+ /**
410
+ * CreateTemplateModal
411
+ * Enterprise modal dialog for authoring and submitting WhatsApp message templates
412
+ * with atomic variable deletion, flexible editing, and strict word-to-variable ratio validation.
413
+ */
414
+ declare function CreateTemplateModal({ isOpen, onClose, onSuccess, existingTemplateNames, existingTemplates, executeAction, orgId, }: CreateTemplateModalProps): react_jsx_runtime.JSX.Element | null;
415
+
416
+ /**
417
+ * UNIVERSE_COMPONENTS
418
+ * Dynamic Component Registry dictionary mapping component type strings (e.g., "TABLE", "WHATSAPP")
419
+ * to their respective React component implementation.
420
+ */
421
+ declare const UNIVERSE_COMPONENTS: {
422
+ readonly TABLE: typeof TableBlock;
423
+ readonly WHATSAPP: typeof WhatsAppComponent;
424
+ };
425
+ type ComponentRegistry = typeof UNIVERSE_COMPONENTS;
426
+ type UniverseComponentType = keyof ComponentRegistry;
427
+
428
+ interface ToastItem {
429
+ id: string;
430
+ message: string;
431
+ type?: "error" | "success" | "info" | "warning";
432
+ title?: string;
433
+ duration?: number;
434
+ }
435
+ interface ToastContextType {
436
+ toasts: ToastItem[];
437
+ addToast: (toast: Omit<ToastItem, "id">) => string;
438
+ showError: (error: string | Error | null | undefined, title?: string) => void;
439
+ removeToast: (id: string) => void;
440
+ }
441
+ declare const ToastContext: react__default.Context<ToastContextType | undefined>;
442
+ declare function ToastProvider({ children }: {
443
+ children: ReactNode;
444
+ }): react_jsx_runtime.JSX.Element;
445
+
446
+ declare function useToast(): ToastContextType;
46
447
 
47
- export { type BaseComponentProps, type ComponentCommunication, type ComponentConfig, type ComponentData, type ComponentPermissions, type ComponentState, cn, isUiLibraryReady, isUiLibraryReadyNot };
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 };