@levo-so/studio 0.1.107 → 0.1.109

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/{BillingStep-CJqmdIz2.js → BillingStep-DZeqbtfs.js} +1 -1
  2. package/{Button-DujHjtOV.js → Button-BMUB23Y7.js} +527 -91
  3. package/CollectionField-xa-jed3_.js +232 -0
  4. package/{DateTimeWidget-CbpvxQ9s.js → DateTimeWidget-DWbn_kXp.js} +4 -3
  5. package/{EntryCard-Drnobf4s.js → EntryCard-BNZ-0_Kv.js} +7 -4
  6. package/{LoginCard-B9HKjZEk.js → LoginCard-B1XlZfEU.js} +3 -3
  7. package/{LoginForm-DpgxFh89.js → LoginForm-NmDPe72V.js} +17 -17
  8. package/{LoginModal-CaqsScly.js → LoginModal-CVd08mNx.js} +2 -2
  9. package/{MessageCard-DojQRKnf.js → MessageCard-C2fU_Bo_.js} +2 -2
  10. package/{ModalManager-CaBZKQR2.js → ModalManager-Dqq7D60M.js} +1 -1
  11. package/{PendingApprovalCard-CrdOrMRu.js → PendingApprovalCard-CXOEpAbg.js} +3 -3
  12. package/{PhoneWidget-BxW2gL28.js → PhoneWidget-CtNIit2w.js} +4 -3
  13. package/{PopupRenderer-CV5HY1dP-hICGc5AG.js → PopupRenderer-SSn97BLs-DQfvcymq.js} +256 -260
  14. package/ProfileCard-CzL5uB2z.js +102 -0
  15. package/{RichTextWidget-DCzgJ9EA.js → RichTextWidget-DkRrKQqN.js} +4 -3
  16. package/{Toolbar-B5UZer_x.js → Toolbar-C3WDkSnO.js} +4 -4
  17. package/{VerifyButton-DFAg6STD.js → VerifyButton-TNkt-SDu.js} +1 -1
  18. package/{bookingCard-BgApvrcj.js → bookingCard-61Yx6JO-.js} +2 -2
  19. package/collection.d.ts +14 -6
  20. package/collection.js +8 -7
  21. package/dist-Cfv-YjpI.js +3469 -0
  22. package/getFieldValidations-CSkSV2hW.js +90 -0
  23. package/index.d.ts +235 -16
  24. package/index.js +1743 -1405
  25. package/{nodeAlignment-DKCIjzlR.js → nodeAlignment-BC_Uferw.js} +5 -5
  26. package/package.json +4 -4
  27. package/studio.css +1 -1
  28. package/{utils-CUqS5dMC.js → utils-BJLmuC5w.js} +1 -1
  29. package/widgets-K6ECnoJJ.js +335 -0
  30. package/CollectionField-BPl8E9MW.js +0 -318
  31. package/CollectionFormBuilder-BvFtiZeH.js +0 -3668
  32. package/dist-DZbXWctg.js +0 -97
  33. /package/{Beams-DboMUgCv.js → Beams-WJN38XSv.js} +0 -0
  34. /package/{CollectionInput-DcNJT5Pg.js → CollectionInput-CpNGIXJx.js} +0 -0
  35. /package/{Dots-a8xSboDv.js → Dots-DggLz5I7.js} +0 -0
  36. /package/{Gradient-NacpoDCM.js → Gradient-BSWJAu0a.js} +0 -0
  37. /package/{Grid-BJQvxnks.js → Grid-BFKl0MUt.js} +0 -0
  38. /package/{MessageFooter-C4qC8cem.js → MessageFooter-4qIEK91O.js} +0 -0
  39. /package/{Popover-DOvRAGzc.js → Popover-O1poOHk2.js} +0 -0
  40. /package/{Tooltip-CJINDx93.js → Tooltip-NEMQqPyr.js} +0 -0
  41. /package/{Waves-DUuT_IFr.js → Waves-BPEgTYoO.js} +0 -0
  42. /package/{authentication-ClOFcry8.js → authentication-hnV1BI8s.js} +0 -0
  43. /package/{card-E2LKF9nT.js → card-5ooLmYSr.js} +0 -0
@@ -0,0 +1,90 @@
1
+ import { FieldInterfaces as e } from "@levo-so/core";
2
+ import { isValidPhoneNumber as t } from "react-phone-number-input";
3
+ import * as n from "yup";
4
+ //#region ../../libraries/react-collection/dist/utils/getFieldValidations.js
5
+ var r = (r, i) => {
6
+ let a = (r?.label || r?.key || "")?.replace(/_/g, " ");
7
+ if (a?.endsWith("Id") && (a = a?.replace("Id", "")), a.includes(".")) {
8
+ let [e] = a.split(".");
9
+ e && (a = e);
10
+ }
11
+ let o = (e) => {
12
+ let t = e;
13
+ return r.max !== void 0 && r.max !== null && r.max !== "" && (t = t.max(Number(r.max), `The ${a} value is too large (max ${r.max})`)), r.min !== void 0 && r.min !== null && r.min !== "" && (t = t.min(Number(r.min), `The ${a} value is too small (min ${r.min})`)), t;
14
+ }, s;
15
+ switch (r.field_interface) {
16
+ case e.NumberWidget:
17
+ s = o(n.number());
18
+ break;
19
+ case e.ArrayWidget:
20
+ s = o(n.array().typeError("The field must be an array"));
21
+ break;
22
+ case e.RecordWidget:
23
+ s = n.object();
24
+ break;
25
+ case e.EmailWidget:
26
+ s = o(n.string().email("The email address is not valid"));
27
+ break;
28
+ case e.PhoneWidget:
29
+ s = o(n.string().test("phone", "The phone number has incorrect format", (e) => {
30
+ if (e) try {
31
+ return t(e);
32
+ } catch {
33
+ return !1;
34
+ }
35
+ return !0;
36
+ }));
37
+ break;
38
+ case e.URLWidget:
39
+ s = o(n.string().matches(/^(?:https?:\/\/)?(?:[a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+(?:\.[a-zA-Z]{2,})+(?:\/[^\s?#]*)?(?:\?[^\s]*)?$/, "The URL is not valid"));
40
+ break;
41
+ case e.ImageUploadWidget:
42
+ case e.FileUploadWidget:
43
+ case e.GeocoderWidget:
44
+ s = n.object();
45
+ break;
46
+ case e.MultiImageUploadWidget:
47
+ case e.MultiFileUploadWidget:
48
+ case e.MultiGeocoderWidget:
49
+ s = n.array().of(n.object());
50
+ break;
51
+ case e.JSONWidget:
52
+ case e.DropdownWidget:
53
+ s = n.string();
54
+ break;
55
+ case e.MultiTextWidget:
56
+ case e.MultiDropdownWidget:
57
+ case e.CheckboxWidget:
58
+ s = n.array().of(n.string());
59
+ break;
60
+ case e.ToggleCheckboxWidget:
61
+ s = n.boolean();
62
+ break;
63
+ case e.CollectionWidget:
64
+ s = r.options.current_have_many_connected ? n.array() : n.object();
65
+ break;
66
+ default:
67
+ s = o(n.string());
68
+ break;
69
+ }
70
+ if (r.options?.validationsPresets && Array.isArray(r.options.validationsPresets)) {
71
+ let t = r.options.validationsPresets;
72
+ (r.field_interface === e.TextWidget || r.field_interface === e.TextareaWidget) && (t.includes("exclude_special_chars") && (s = s.matches(/^[a-zA-Z0-9\s]*$/, "Special characters are not allowed")), t.includes("exclude_numbers") && (s = s.matches(/^[^0-9]*$/, "Numbers are not allowed")));
73
+ }
74
+ return {
75
+ required: {
76
+ value: !!r?.required,
77
+ message: `The ${a} field is required`
78
+ },
79
+ validate: (e) => {
80
+ if (r?.options?.disableValidation || e === "" || e == null) return !0;
81
+ try {
82
+ return s.validateSync(e), i ? i(e) : !0;
83
+ } catch (e) {
84
+ return e instanceof n.ValidationError ? e.message : !0;
85
+ }
86
+ }
87
+ };
88
+ };
89
+ //#endregion
90
+ export { r as t };
package/index.d.ts CHANGED
@@ -402,8 +402,6 @@ declare interface CarouselProps extends BaseElementProps {
402
402
  */
403
403
  export declare const CategoryFilter: React.FC<ICategoryFilterProps>;
404
404
 
405
- export declare const CollectionFormBuilder: default_2.FC<ICollectionFormBuilderProps>;
406
-
407
405
  export declare const colorOptions: {
408
406
  readonly brand: {
409
407
  readonly label: "Brand";
@@ -543,6 +541,39 @@ export declare const DATA_ATTRIBUTES: {
543
541
  readonly GROUP: "data-levo_group";
544
542
  };
545
543
 
544
+ /**
545
+ * Display kind — what facet of the moment is shown.
546
+ * `date` and `time` are self-explanatory; `datetime` shows both;
547
+ * `relative` renders distance-from-now (e.g. "2 days ago").
548
+ */
549
+ export declare const DATE_DISPLAYS: readonly ["date", "time", "datetime", "relative"];
550
+
551
+ /**
552
+ * Preset within a Display. Locked vocabulary so the picker is a finite list
553
+ * rather than a free-form format string.
554
+ */
555
+ export declare const DATE_FORMATS: {
556
+ date: readonly ["full", "day", "month", "year", "day-month", "month-year"];
557
+ time: readonly ["clock"];
558
+ datetime: readonly ["full", "compact"];
559
+ relative: readonly ["auto"];
560
+ };
561
+
562
+ /** Hour cycle preference — Auto defers to the active locale's convention. */
563
+ export declare const DATE_HOUR12_VALUES: readonly ["auto", "12", "24"];
564
+
565
+ /** Curated locale list — Auto means "host default". */
566
+ export declare const DATE_LOCALES: {
567
+ value: string;
568
+ label: string;
569
+ }[];
570
+
571
+ /** Style — visual length of the rendering. S/M/L/XL map to Intl widths. */
572
+ export declare const DATE_STYLES: readonly ["S", "M", "L", "XL"];
573
+
574
+ /** Serialize a spec back to args; trims trailing defaults to keep tokens lean. */
575
+ export declare const dateSpecToArgs: (spec: IDateFormatSpec) => TVariableLiteral[];
576
+
546
577
  declare type DeepConfig<T> = T extends Array<infer U> ? IFieldConfig & {
547
578
  [index: number]: DeepConfig<U>;
548
579
  } : T extends object ? IFieldConfig & {
@@ -561,6 +592,8 @@ declare type DeepStyles<T> = T extends Array<infer U> ? IStyles & {
561
592
  [K in keyof T]: DeepStyles<T[K]>;
562
593
  } : IStyles;
563
594
 
595
+ export declare const DEFAULT_DATE_SPEC: IDateFormatSpec;
596
+
564
597
  /** Default "from" state for entry/scroll animations */
565
598
  export declare const DEFAULT_FROM_STATE: AnimationProperties;
566
599
 
@@ -597,6 +630,9 @@ export declare interface EntryAnimationConfig {
597
630
  viewport?: ViewportConfig;
598
631
  }
599
632
 
633
+ /** Evaluate a parsed token against a flattened context dictionary. */
634
+ export declare const evaluateVariableToken: (parsed: IParsedVariableToken, context: Record<string, unknown>) => IEvaluatedVariable;
635
+
600
636
  /**
601
637
  * Extended props interface for useCommonProps return type
602
638
  */
@@ -629,6 +665,13 @@ export declare const fetchSource: ({ levoClient, source, workspace_id, slugs, pa
629
665
  */
630
666
  export declare const findFieldSchema: (contentSchema: IStudioWidget[] | undefined, fieldKey: string | undefined) => IStudioWidget | undefined;
631
667
 
668
+ /**
669
+ * Flattens a hierarchical variable tree to a list of matches filtered by
670
+ * `query`. Recursively walks `items[*].children` so leaves at any depth
671
+ * surface in picker results. Empty/whitespace queries return every leaf.
672
+ */
673
+ export declare const flattenVariableMatches: (groups: IVariableGroup[], query: string) => IFlatVariableMatch[];
674
+
632
675
  export declare const Form: WithBlockPropsComponent<BaseElementProps & {
633
676
  className?: string;
634
677
  initialValues?: Record<string, any>;
@@ -807,6 +850,8 @@ export declare const getInitialPageContent: ({ levoClient, pageData, site, query
807
850
  headCode: string;
808
851
  }>;
809
852
 
853
+ export declare function getKeysWithValue(obj: Record<string, any>, maxDepth?: number): Record<string, any>;
854
+
810
855
  /**
811
856
  * Utility function to safely access nested object properties
812
857
  *
@@ -1084,14 +1129,6 @@ export declare interface ICategoryFilterProps {
1084
1129
  className?: string;
1085
1130
  }
1086
1131
 
1087
- declare interface ICollectionFormBuilderProps extends Omit<ILevoFormContext, "schema"> {
1088
- formVariant?: FormVariantType;
1089
- collection_id: string;
1090
- hiddenFields?: string[];
1091
- workspace_id?: string;
1092
- account?: ILevoMembership.Account;
1093
- }
1094
-
1095
1132
  declare interface ICollectionTheme {
1096
1133
  form: {
1097
1134
  maxWidth: string;
@@ -1160,6 +1197,15 @@ declare interface ICreateForumPostProps {
1160
1197
  onPostCreated?: (post: IForumPost) => void;
1161
1198
  }
1162
1199
 
1200
+ export declare interface IDateFormatSpec {
1201
+ display: TDateDisplay;
1202
+ format: string;
1203
+ style: TDateStyle;
1204
+ locale: string;
1205
+ /** Only relevant for `time` / `datetime` displays — ignored elsewhere. */
1206
+ hour12: TDateHour12;
1207
+ }
1208
+
1163
1209
  declare interface IDevToolsPreviewProps {
1164
1210
  blockInstance: IBlockInstance;
1165
1211
  blocks: Record<string, BlockComponent>;
@@ -1175,6 +1221,13 @@ export declare interface IDevToolsProps {
1175
1221
 
1176
1222
  export declare type IElementStyle = Record<string, any>;
1177
1223
 
1224
+ export declare interface IEvaluatedVariable {
1225
+ output: string;
1226
+ rawValue: unknown;
1227
+ pathExists: boolean;
1228
+ conditionFailed: boolean;
1229
+ }
1230
+
1178
1231
  export declare interface IFieldConfig {
1179
1232
  selectedVariants?: Record<string, string>;
1180
1233
  enabled?: boolean;
@@ -1267,6 +1320,14 @@ export declare interface IFieldConfig {
1267
1320
  theme?: DeepPartial<ITheme_2 & IRteTheme & ICollectionTheme>;
1268
1321
  }
1269
1322
 
1323
+ export declare interface IFlatVariableMatch {
1324
+ group: string;
1325
+ /** Parent trail for nested values (e.g. Collection field with nested keys),
1326
+ * joined with " › ". Undefined for top-level leaves. */
1327
+ parent?: string;
1328
+ item: IVariableItem;
1329
+ }
1330
+
1270
1331
  /**
1271
1332
  * Forum context
1272
1333
  */
@@ -1400,7 +1461,15 @@ declare interface ILevoFormContext {
1400
1461
  cssReset?: boolean;
1401
1462
  };
1402
1463
  isLoggedIn?: boolean;
1403
- account?: ILevoMembership.Account;
1464
+ /**
1465
+ * Logged-in member's contact details, used only to prefill the schema's designated
1466
+ * email_field/mobile_field. Strictly the fields consumed — pass anything else via
1467
+ * externalInitialValues.
1468
+ */
1469
+ account?: {
1470
+ email?: string | null;
1471
+ mobile?: string | null;
1472
+ };
1404
1473
  externalInitialValues?: Record<string, any>;
1405
1474
  onSuccess?: (v: {
1406
1475
  schemaId: string;
@@ -1551,7 +1620,7 @@ export declare interface IPage {
1551
1620
  published_at: string | null;
1552
1621
  }
1553
1622
 
1554
- export declare type IPageAccess = (IPageAccessGating | IPageAccessAuthentication) & {
1623
+ export declare type IPageAccess = (IPageAccessGating | IPageAccessAuthentication | IPageAccessProfile) & {
1555
1624
  enabled: boolean;
1556
1625
  };
1557
1626
 
@@ -1577,9 +1646,9 @@ export declare interface IPageAccessAuthenticationOptions {
1577
1646
 
1578
1647
  export declare interface IPageAccessCheck {
1579
1648
  has_access: boolean;
1580
- code?: IPageAccessAuthenticationCodes | IPageAccessGatingCodes;
1649
+ code?: IPageAccessAuthenticationCodes | IPageAccessGatingCodes | IPageAccessProfileCodes;
1581
1650
  message: string;
1582
- options?: Pick<IPageAccessGatingOptions, "collection" | "field" | "content"> | IPageAccessAuthenticationOptions;
1651
+ options?: Pick<IPageAccessGatingOptions, "collection" | "field" | "content"> | Pick<IPageAccessProfileOptions, "hidden" | "content"> | IPageAccessAuthenticationOptions;
1583
1652
  }
1584
1653
 
1585
1654
  export declare type IPageAccessGating = {
@@ -1617,6 +1686,41 @@ export declare interface IPageAccessGatingOptions {
1617
1686
  };
1618
1687
  }
1619
1688
 
1689
+ export declare type IPageAccessProfile = {
1690
+ kind: "profile";
1691
+ options: IPageAccessProfileOptions;
1692
+ };
1693
+
1694
+ export declare type IPageAccessProfileCodes =
1695
+ /**
1696
+ * if the visitor is not logged in
1697
+ */
1698
+ "profile.NOT_LOGGED_IN"
1699
+ /**
1700
+ * logged in, but the account does not pass `options.condition` — render the
1701
+ * profile-completion form. An empty condition means "no rule" → always SUCCESS.
1702
+ * Named to mirror gating's ENTRY_CONDITION_NOT_FULFILLED — the criteria can fail on
1703
+ * a filled field that simply doesn't match, so "incomplete" would be misleading.
1704
+ */
1705
+ | "profile.CONDITION_NOT_FULFILLED" | "profile.SUCCESS";
1706
+
1707
+ /**
1708
+ * Profile gating is *account access*: login + the logged-in account must satisfy
1709
+ * `condition`. It is a sibling of `authentication`, not of `gating` — there is no
1710
+ * collection in the contract. The BE owns the membership account internally; the
1711
+ * runtime ProfileCard loads the account schema by its known key.
1712
+ */
1713
+ export declare interface IPageAccessProfileOptions {
1714
+ /** "Profile is completed when" — evaluated against the caller's own account. */
1715
+ condition?: LevoQuery.Where;
1716
+ /** Account fields to hide in the profile-completion form. */
1717
+ hidden?: string[];
1718
+ content?: {
1719
+ /** Message shown above the profile-completion form. */
1720
+ entryNotFound?: string;
1721
+ };
1722
+ }
1723
+
1620
1724
  export declare type IPageContext = Record<string, unknown>;
1621
1725
 
1622
1726
  export declare interface IPageDataContext {
@@ -1676,6 +1780,11 @@ export declare interface IPageStatMetric {
1676
1780
  change: number | null;
1677
1781
  }
1678
1782
 
1783
+ export declare interface IParsedVariableToken {
1784
+ path: string;
1785
+ transforms: IVariableTransform[];
1786
+ }
1787
+
1679
1788
  declare interface IPendingRequestStateProps {
1680
1789
  communityName?: string;
1681
1790
  className?: string;
@@ -1717,6 +1826,15 @@ declare type IPreviewDevice = "desktop" | "tablet" | "mobile";
1717
1826
  */
1718
1827
  export declare type IRenderMode = "live" | "studio.page" | "studio.block";
1719
1828
 
1829
+ /**
1830
+ * Per-content responsive override. Lives on the studio content value (not on
1831
+ * the shared IMediaObject) so the core type stays untouched.
1832
+ */
1833
+ declare interface IResponsiveImageContent {
1834
+ mobile?: IMediaObject;
1835
+ tablet?: IMediaObject;
1836
+ }
1837
+
1720
1838
  declare interface IRteTheme {
1721
1839
  baseSpacing: string;
1722
1840
  /** Background color for text selection and highlighted nodes. */
@@ -1790,6 +1908,10 @@ export declare interface ISite {
1790
1908
  twitter?: string;
1791
1909
  linkedin?: string;
1792
1910
  instagram?: string;
1911
+ youtube?: string;
1912
+ tiktok?: string;
1913
+ pinterest?: string;
1914
+ threads?: string;
1793
1915
  };
1794
1916
  [key: string]: any;
1795
1917
  };
@@ -2092,6 +2214,11 @@ export declare type IThemeFonts = {
2092
2214
  customFonts?: Record<string, string>;
2093
2215
  };
2094
2216
 
2217
+ declare interface ITransformDef {
2218
+ label: string;
2219
+ apply: (value: unknown, args: TVariableLiteral[]) => unknown;
2220
+ }
2221
+
2095
2222
  declare interface IUseDotButtonType {
2096
2223
  selectedIndex: number;
2097
2224
  scrollSnaps: number[];
@@ -2137,6 +2264,27 @@ export declare interface IUseStripePaymentReturn {
2137
2264
  onComplete: (() => void) | null;
2138
2265
  }
2139
2266
 
2267
+ export declare interface IVariableGroup {
2268
+ name: string;
2269
+ items: IVariableItem[];
2270
+ }
2271
+
2272
+ export declare interface IVariableItem {
2273
+ /** Display label */
2274
+ label: string;
2275
+ /** Token inserted into the editor (e.g. `context.collection.title`) */
2276
+ value: string;
2277
+ /** Optional muted preview shown under the label */
2278
+ preview?: string;
2279
+ /** Sub-fields for composite values — renders as a nested group */
2280
+ children?: IVariableItem[];
2281
+ }
2282
+
2283
+ export declare interface IVariableTransform {
2284
+ name: string;
2285
+ args: TVariableLiteral[];
2286
+ }
2287
+
2140
2288
  /**
2141
2289
  * Configuration for a single variant group within a component theme
2142
2290
  *
@@ -2221,7 +2369,10 @@ declare type MediaContent = {
2221
2369
  srcset?: {
2222
2370
  path: string;
2223
2371
  };
2224
- } | IMedia;
2372
+ responsive?: IResponsiveImageContent;
2373
+ } | (IMedia & {
2374
+ responsive?: IResponsiveImageContent;
2375
+ });
2225
2376
 
2226
2377
  declare type MediaContent_2 = {
2227
2378
  location: string;
@@ -2229,7 +2380,10 @@ declare type MediaContent_2 = {
2229
2380
  path: string;
2230
2381
  };
2231
2382
  type?: string;
2232
- } | IMedia;
2383
+ responsive?: IResponsiveImageContent;
2384
+ } | (IMedia & {
2385
+ responsive?: IResponsiveImageContent;
2386
+ });
2233
2387
 
2234
2388
  export declare type MediaHint = {
2235
2389
  orientation?: "landscape" | "portrait" | "square";
@@ -2244,6 +2398,10 @@ export declare const MESSAGE_TYPES: {
2244
2398
  readonly PREVIEW_MOUSE_LEAVE: "PREVIEW_MOUSE_LEAVE";
2245
2399
  readonly PREVIEW_UNDO: "PREVIEW_UNDO";
2246
2400
  readonly PREVIEW_REDO: "PREVIEW_REDO";
2401
+ readonly PREVIEW_MOVE_BLOCK: "PREVIEW_MOVE_BLOCK";
2402
+ readonly PREVIEW_DELETE_BLOCK: "PREVIEW_DELETE_BLOCK";
2403
+ readonly PREVIEW_DUPLICATE_BLOCK: "PREVIEW_DUPLICATE_BLOCK";
2404
+ readonly PREVIEW_OPEN_BLOCK_PANEL: "PREVIEW_OPEN_BLOCK_PANEL";
2247
2405
  readonly STUDIO_SELECT: "STUDIO_SELECT";
2248
2406
  readonly STUDIO_HOVER: "STUDIO_HOVER";
2249
2407
  readonly STUDIO_AUTH_OVERRIDE: "STUDIO_AUTH_OVERRIDE";
@@ -2307,6 +2465,9 @@ export declare const oklchToRGBA: (oklchColor: OKLCHColor) => string;
2307
2465
  */
2308
2466
  export declare const oklchToString: (oklchColor: OKLCHColor | string | undefined) => string;
2309
2467
 
2468
+ /** Read a structured spec out of pipe-syntax args, falling back to defaults. */
2469
+ export declare const parseDateSpec: (args: TVariableLiteral[]) => IDateFormatSpec | null;
2470
+
2310
2471
  /**
2311
2472
  * Parse element key to detect repeatable group context
2312
2473
  *
@@ -2352,6 +2513,9 @@ export declare const parseVariablesFromResolvedSource: ({ levoClient, block, res
2352
2513
  draft?: boolean;
2353
2514
  }) => Promise<[IBlockInstance, Record<string, IResponseMultiple<Record<string, unknown>>>]>;
2354
2515
 
2516
+ /** Parse the inner expression of a `{...}` token into a path + transforms. */
2517
+ export declare const parseVariableToken: (raw: string) => IParsedVariableToken;
2518
+
2355
2519
  /** Error code returned when account exists but is pending admin approval */
2356
2520
  export declare const PENDING_APPROVAL_ERROR_CODE = "membership.account.ACCOUNT_PENDING_APPROVAL";
2357
2521
 
@@ -2679,6 +2843,14 @@ export declare const SimpleTooltipWrapper: React_2.FC<{
2679
2843
 
2680
2844
  export declare function Skeleton({ className, ...props }: React.ComponentProps<"div">): JSX.Element;
2681
2845
 
2846
+ /**
2847
+ * Snap a style to the nearest valid option for the current (display, format).
2848
+ * Used when the user changes display/format and the previously-chosen style
2849
+ * is no longer offered — picks the available style with the smallest index
2850
+ * distance in the canonical S→M→L→XL order.
2851
+ */
2852
+ export declare const snapDateStyle: (style: TDateStyle, available: readonly TDateStyle[]) => TDateStyle;
2853
+
2682
2854
  export declare interface SourceFetchOptions {
2683
2855
  levoClient: ILevoClient;
2684
2856
  source: IStudioSource;
@@ -2739,6 +2911,15 @@ export declare const StudioWidgetList: readonly ["BoxWidget", "ButtonWidget", "L
2739
2911
 
2740
2912
  export declare const StudioWidgetMap: Record<"BoxWidget" | "ButtonWidget" | "LayoutWidget" | "HeadingWidget" | "IframeWidget" | "ImageWidget" | "IconWidget" | "MediaWidget" | "TypographyWidget" | "BlogContentWidget" | "CarouselWidget" | "FormWidget" | "ContainerWidget" | "UserMenuWidget" | "TabsListWidget" | "TabsTriggerWidget" | "TabsContentWidget" | "NavMenuWidget" | "CardWidget" | "TitleWidget" | "TextWidget" | "NumberWidget" | "URLWidget" | "ImageUploadWidget" | "MultiImageUploadWidget" | "TextareaWidget" | "RichTextWidget" | "DropdownWidget" | "SwitchWidget" | "DateWidget" | "ArrayWidget" | "RecordWidget", "BoxWidget" | "ButtonWidget" | "LayoutWidget" | "HeadingWidget" | "IframeWidget" | "ImageWidget" | "IconWidget" | "MediaWidget" | "TypographyWidget" | "BlogContentWidget" | "CarouselWidget" | "FormWidget" | "ContainerWidget" | "UserMenuWidget" | "TabsListWidget" | "TabsTriggerWidget" | "TabsContentWidget" | "NavMenuWidget" | "CardWidget" | "TitleWidget" | "TextWidget" | "NumberWidget" | "URLWidget" | "ImageUploadWidget" | "MultiImageUploadWidget" | "TextareaWidget" | "RichTextWidget" | "DropdownWidget" | "SwitchWidget" | "DateWidget" | "ArrayWidget" | "RecordWidget">;
2741
2913
 
2914
+ /**
2915
+ * Distinct Style values for a given (display, format). The four-step S/M/L/XL
2916
+ * vocabulary doesn't map cleanly to every Intl rendering — e.g. for `time`
2917
+ * S and M both produce "1:30 PM", and for `date / year` everything past S
2918
+ * just prints "2026". Exposing only the values that yield different output
2919
+ * keeps the toggle honest.
2920
+ */
2921
+ export declare const stylesFor: (display: TDateDisplay, format: string) => readonly TDateStyle[];
2922
+
2742
2923
  export declare const TabsContent: WithBlockPropsComponent<BaseTabsContentProps>;
2743
2924
 
2744
2925
  export declare const TabsList: WithBlockPropsComponent<BaseTabsListProps>;
@@ -2747,6 +2928,14 @@ export declare const TabsRoot: React_2.ForwardRefExoticComponent<Tabs.TabsProps
2747
2928
 
2748
2929
  export declare const TabsTrigger: WithBlockPropsComponent<BaseTabsTriggerProps>;
2749
2930
 
2931
+ export declare type TDateDisplay = (typeof DATE_DISPLAYS)[number];
2932
+
2933
+ export declare type TDateFormat<D extends TDateDisplay = TDateDisplay> = (typeof DATE_FORMATS)[D][number];
2934
+
2935
+ export declare type TDateHour12 = (typeof DATE_HOUR12_VALUES)[number];
2936
+
2937
+ export declare type TDateStyle = (typeof DATE_STYLES)[number];
2938
+
2750
2939
  export declare const Tooltip: React_2.FC<Tooltip_2.TooltipProps>;
2751
2940
 
2752
2941
  export declare const TooltipContent: React_2.ForwardRefExoticComponent<Omit<Tooltip_2.TooltipContentProps & React_2.RefAttributes<HTMLDivElement>, "ref"> & React_2.RefAttributes<HTMLDivElement>>;
@@ -2771,6 +2960,23 @@ export declare interface TransitionConfig {
2771
2960
  bounce?: number;
2772
2961
  }
2773
2962
 
2963
+ /**
2964
+ * Variable expression engine — parses and evaluates pipe-syntax tokens.
2965
+ *
2966
+ * Syntax: {path | transform:arg1:arg2 | transform:arg | …}
2967
+ * Examples: {user.name}
2968
+ * {user.name | default:"Guest" | upper | prefix:"Hi "}
2969
+ * {order.total | currency:INR}
2970
+ * {event.starts_at | date:date:day-month:L:auto}
2971
+ * {order.status | if:eq:"paid" | text:"Paid ✓"}
2972
+ *
2973
+ * Source of truth for the parser, transforms and date formatting. The
2974
+ * runtime renderer (`@levo-so/studio`) substitutes `{path}` tokens at page
2975
+ * render time; the dashboard's editor wires the same engine into a TipTap
2976
+ * NodeView so authoring and runtime stay in lockstep.
2977
+ */
2978
+ export declare type TVariableLiteral = string | number | boolean | null;
2979
+
2774
2980
  /** Available easing functions for tween transitions */
2775
2981
  export declare type TweenEase = "linear" | "easeIn" | "easeOut" | "easeInOut" | "circIn" | "circOut" | "circInOut" | "backIn" | "backOut" | "backInOut" | "anticipate";
2776
2982
 
@@ -2863,6 +3069,19 @@ export declare const UserMenu: WithBlockPropsComponent<BaseUserMenuProps>;
2863
3069
  */
2864
3070
  export declare const useStripePayment: () => IUseStripePaymentReturn;
2865
3071
 
3072
+ /** Single-token regex — matches a string that is ONLY a `{...}` token. */
3073
+ export declare const VARIABLE_SINGLE_TOKEN_REGEX: RegExp;
3074
+
3075
+ /** Token-matching regex — matches `{anything-not-a-brace}`. Nested braces
3076
+ * are not supported: avoiding them prevents adjacent-pill corruption when
3077
+ * the user types `{` next to a variable pill. */
3078
+ export declare const VARIABLE_TOKEN_REGEX: RegExp;
3079
+
3080
+ export declare const VARIABLE_TRANSFORMS: Record<string, ITransformDef>;
3081
+
3082
+ /** Serialize a parsed token back to pipe syntax (without the wrapping `{}`). */
3083
+ export declare const variableTokenToString: (t: IParsedVariableToken) => string;
3084
+
2866
3085
  /** Viewport trigger configuration for entry animations */
2867
3086
  export declare interface ViewportConfig {
2868
3087
  once?: boolean;