idml-ui 0.1.0

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.
@@ -0,0 +1,599 @@
1
+ import { z } from 'zod';
2
+ import React, { ReactNode } from 'react';
3
+ import * as next_link from 'next/link';
4
+
5
+ interface ColorToken {
6
+ name: string;
7
+ value: string;
8
+ darkValue?: string;
9
+ }
10
+ interface TypographyToken {
11
+ name: string;
12
+ fontFamily?: string;
13
+ fontSize: string;
14
+ fontWeight?: number | string;
15
+ lineHeight?: string;
16
+ letterSpacing?: string;
17
+ }
18
+ interface SpacingToken {
19
+ name: string;
20
+ value: string;
21
+ }
22
+ interface TokensDef {
23
+ colors: ColorToken[];
24
+ typography: TypographyToken[];
25
+ spacing: SpacingToken[];
26
+ }
27
+
28
+ type PercentageString = `${number}%`;
29
+ interface SizeDef {
30
+ width?: PercentageString;
31
+ height?: PercentageString;
32
+ minWidth?: PercentageString;
33
+ minHeight?: PercentageString;
34
+ maxWidth?: PercentageString;
35
+ maxHeight?: PercentageString;
36
+ }
37
+ type FlexDirection = 'row' | 'column' | 'row-reverse' | 'column-reverse';
38
+ type FlexWrap = 'nowrap' | 'wrap' | 'wrap-reverse';
39
+ type JustifyContent = 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly';
40
+ type AlignItems = 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline';
41
+ interface FlexDef {
42
+ type: 'flex';
43
+ direction: FlexDirection;
44
+ wrap?: FlexWrap;
45
+ justifyContent?: JustifyContent;
46
+ alignItems?: AlignItems;
47
+ gap?: string;
48
+ size?: SizeDef;
49
+ children: LayoutDef[];
50
+ componentId?: string;
51
+ idmlStyle?: Record<string, string>;
52
+ className?: string;
53
+ /** Dynamic `@method` class refs (resolved per render, like a component's, so a
54
+ * container can carry a state-driven class — e.g. a per-row colour). */
55
+ classRefs?: string[];
56
+ /** Conditional class blocks (`` `classes`?@ref ``) applied per render. */
57
+ condClasses?: ConditionalClass[];
58
+ visibility?: LayoutVisibility;
59
+ dynamicSize?: DynamicSize;
60
+ }
61
+ /** Reactive show/hide for a layout cell: render only when `ref` resolves truthy
62
+ * (a value path like `state.open`); `negate` flips the test. */
63
+ interface LayoutVisibility {
64
+ ref: string;
65
+ negate?: boolean;
66
+ }
67
+ /** A class block that applies only when `ref` is truthy (`negate` flips it) —
68
+ * i.e. `` `scale-100 opacity-100`?@state.open ``. Lets state-driven visuals (a
69
+ * pop-up's scale/opacity) live in the .idml rather than a method. */
70
+ interface ConditionalClass {
71
+ classes: string;
72
+ ref: string;
73
+ negate?: boolean;
74
+ }
75
+ /** Reactive width/height resolved per render (applied AFTER static `size`, so it
76
+ * wins — letting a cell resize on state, e.g. a collapsing sidebar). The change
77
+ * is animated by the renderer (Web Animations API). */
78
+ interface DynamicSize {
79
+ width?: DynamicDim;
80
+ height?: DynamicDim;
81
+ }
82
+ /** One reactive dimension. `ref` is a value path (`state.x` / method). With
83
+ * `whenTrue`/`whenFalse` it's a condition — the dim is `whenTrue` when the ref
84
+ * is truthy, else `whenFalse` (both inline CSS sizes from the .idml). Without
85
+ * them the ref's resolved value is the dim (bare number → `%`). */
86
+ interface DynamicDim {
87
+ ref: string;
88
+ whenTrue?: string;
89
+ whenFalse?: string;
90
+ }
91
+ interface GridDef {
92
+ type: 'grid';
93
+ columns: number;
94
+ rows?: number;
95
+ gap?: string;
96
+ size?: SizeDef;
97
+ children: LayoutDef[];
98
+ componentId?: string;
99
+ idmlStyle?: Record<string, string>;
100
+ className?: string;
101
+ /** Dynamic `@method` class refs (resolved per render, like a component's, so a
102
+ * container can carry a state-driven class — e.g. a per-row colour). */
103
+ classRefs?: string[];
104
+ /** Conditional class blocks (`` `classes`?@ref ``) applied per render. */
105
+ condClasses?: ConditionalClass[];
106
+ visibility?: LayoutVisibility;
107
+ dynamicSize?: DynamicSize;
108
+ }
109
+ type LayoutDef = FlexDef | GridDef;
110
+
111
+ interface DataBindingDef {
112
+ prop: string;
113
+ methodId: string;
114
+ /**
115
+ * How the binding is wired:
116
+ * - 'handler' (default): the method function is passed as the prop (e.g. onClick).
117
+ * - 'value': the method is called during render and its return value becomes the
118
+ * prop. If the method is a hook (e.g. wraps useQuery/useState) the component
119
+ * re-renders reactively when that value changes.
120
+ * - 'model': two-way binding to a form-state cell named by `methodId` — sets the
121
+ * prop to the current value AND an `onChange` that writes it back.
122
+ */
123
+ kind?: 'handler' | 'value' | 'model';
124
+ }
125
+ interface VisibilityDef {
126
+ methodId: string;
127
+ negate?: boolean;
128
+ }
129
+
130
+ type BuiltinComponentType = 'Text' | 'Heading' | 'Button' | 'Image' | 'List' | 'Card' | 'Divider' | 'Spacer' | 'Icon' | 'Table' | 'Input' | 'Textarea' | 'Select' | 'Option' | 'Checkbox' | 'Radio' | 'Label' | 'Children' | 'Repeat' | 'Form' | 'Modal';
131
+ interface ComponentDef {
132
+ id: string;
133
+ type: BuiltinComponentType | string;
134
+ props?: Record<string, unknown>;
135
+ tokenProps?: {
136
+ color?: string;
137
+ background?: string;
138
+ typography?: string;
139
+ padding?: string;
140
+ };
141
+ bindings?: DataBindingDef[];
142
+ visibility?: VisibilityDef;
143
+ children?: ComponentDef[];
144
+ idmlStyle?: Record<string, string>;
145
+ className?: string;
146
+ }
147
+
148
+ interface PageDef {
149
+ route: string;
150
+ title?: string;
151
+ layout: LayoutDef;
152
+ components: ComponentDef[];
153
+ meta?: {
154
+ description?: string;
155
+ ogTitle?: string;
156
+ };
157
+ }
158
+
159
+ interface UIConfig {
160
+ version: '1';
161
+ tokens: TokensDef;
162
+ pages: PageDef[];
163
+ userComponents?: string[];
164
+ }
165
+
166
+ declare const UIConfigSchema: z.ZodObject<{
167
+ version: z.ZodLiteral<"1">;
168
+ tokens: z.ZodObject<{
169
+ colors: z.ZodArray<z.ZodObject<{
170
+ name: z.ZodString;
171
+ value: z.ZodString;
172
+ darkValue: z.ZodOptional<z.ZodString>;
173
+ }, "strict", z.ZodTypeAny, {
174
+ value: string;
175
+ name: string;
176
+ darkValue?: string | undefined;
177
+ }, {
178
+ value: string;
179
+ name: string;
180
+ darkValue?: string | undefined;
181
+ }>, "many">;
182
+ typography: z.ZodArray<z.ZodObject<{
183
+ name: z.ZodString;
184
+ fontFamily: z.ZodOptional<z.ZodString>;
185
+ fontSize: z.ZodString;
186
+ fontWeight: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodString]>>;
187
+ lineHeight: z.ZodOptional<z.ZodString>;
188
+ letterSpacing: z.ZodOptional<z.ZodString>;
189
+ }, "strict", z.ZodTypeAny, {
190
+ name: string;
191
+ fontSize: string;
192
+ fontFamily?: string | undefined;
193
+ fontWeight?: string | number | undefined;
194
+ lineHeight?: string | undefined;
195
+ letterSpacing?: string | undefined;
196
+ }, {
197
+ name: string;
198
+ fontSize: string;
199
+ fontFamily?: string | undefined;
200
+ fontWeight?: string | number | undefined;
201
+ lineHeight?: string | undefined;
202
+ letterSpacing?: string | undefined;
203
+ }>, "many">;
204
+ spacing: z.ZodArray<z.ZodObject<{
205
+ name: z.ZodString;
206
+ value: z.ZodString;
207
+ }, "strict", z.ZodTypeAny, {
208
+ value: string;
209
+ name: string;
210
+ }, {
211
+ value: string;
212
+ name: string;
213
+ }>, "many">;
214
+ }, "strict", z.ZodTypeAny, {
215
+ colors: {
216
+ value: string;
217
+ name: string;
218
+ darkValue?: string | undefined;
219
+ }[];
220
+ typography: {
221
+ name: string;
222
+ fontSize: string;
223
+ fontFamily?: string | undefined;
224
+ fontWeight?: string | number | undefined;
225
+ lineHeight?: string | undefined;
226
+ letterSpacing?: string | undefined;
227
+ }[];
228
+ spacing: {
229
+ value: string;
230
+ name: string;
231
+ }[];
232
+ }, {
233
+ colors: {
234
+ value: string;
235
+ name: string;
236
+ darkValue?: string | undefined;
237
+ }[];
238
+ typography: {
239
+ name: string;
240
+ fontSize: string;
241
+ fontFamily?: string | undefined;
242
+ fontWeight?: string | number | undefined;
243
+ lineHeight?: string | undefined;
244
+ letterSpacing?: string | undefined;
245
+ }[];
246
+ spacing: {
247
+ value: string;
248
+ name: string;
249
+ }[];
250
+ }>;
251
+ pages: z.ZodArray<z.ZodObject<{
252
+ route: z.ZodString;
253
+ title: z.ZodOptional<z.ZodString>;
254
+ layout: z.ZodType<any, z.ZodTypeDef, any>;
255
+ components: z.ZodArray<z.ZodType<any, z.ZodTypeDef, any>, "many">;
256
+ meta: z.ZodOptional<z.ZodObject<{
257
+ description: z.ZodOptional<z.ZodString>;
258
+ ogTitle: z.ZodOptional<z.ZodString>;
259
+ }, "strict", z.ZodTypeAny, {
260
+ description?: string | undefined;
261
+ ogTitle?: string | undefined;
262
+ }, {
263
+ description?: string | undefined;
264
+ ogTitle?: string | undefined;
265
+ }>>;
266
+ }, "strict", z.ZodTypeAny, {
267
+ route: string;
268
+ components: any[];
269
+ title?: string | undefined;
270
+ layout?: any;
271
+ meta?: {
272
+ description?: string | undefined;
273
+ ogTitle?: string | undefined;
274
+ } | undefined;
275
+ }, {
276
+ route: string;
277
+ components: any[];
278
+ title?: string | undefined;
279
+ layout?: any;
280
+ meta?: {
281
+ description?: string | undefined;
282
+ ogTitle?: string | undefined;
283
+ } | undefined;
284
+ }>, "many">;
285
+ userComponents: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
286
+ }, "strict", z.ZodTypeAny, {
287
+ version: "1";
288
+ tokens: {
289
+ colors: {
290
+ value: string;
291
+ name: string;
292
+ darkValue?: string | undefined;
293
+ }[];
294
+ typography: {
295
+ name: string;
296
+ fontSize: string;
297
+ fontFamily?: string | undefined;
298
+ fontWeight?: string | number | undefined;
299
+ lineHeight?: string | undefined;
300
+ letterSpacing?: string | undefined;
301
+ }[];
302
+ spacing: {
303
+ value: string;
304
+ name: string;
305
+ }[];
306
+ };
307
+ pages: {
308
+ route: string;
309
+ components: any[];
310
+ title?: string | undefined;
311
+ layout?: any;
312
+ meta?: {
313
+ description?: string | undefined;
314
+ ogTitle?: string | undefined;
315
+ } | undefined;
316
+ }[];
317
+ userComponents?: string[] | undefined;
318
+ }, {
319
+ version: "1";
320
+ tokens: {
321
+ colors: {
322
+ value: string;
323
+ name: string;
324
+ darkValue?: string | undefined;
325
+ }[];
326
+ typography: {
327
+ name: string;
328
+ fontSize: string;
329
+ fontFamily?: string | undefined;
330
+ fontWeight?: string | number | undefined;
331
+ lineHeight?: string | undefined;
332
+ letterSpacing?: string | undefined;
333
+ }[];
334
+ spacing: {
335
+ value: string;
336
+ name: string;
337
+ }[];
338
+ };
339
+ pages: {
340
+ route: string;
341
+ components: any[];
342
+ title?: string | undefined;
343
+ layout?: any;
344
+ meta?: {
345
+ description?: string | undefined;
346
+ ogTitle?: string | undefined;
347
+ } | undefined;
348
+ }[];
349
+ userComponents?: string[] | undefined;
350
+ }>;
351
+ declare function validateConfig(raw: unknown): UIConfig;
352
+ declare function safeValidateConfig(raw: unknown): z.SafeParseReturnType<{
353
+ version: "1";
354
+ tokens: {
355
+ colors: {
356
+ value: string;
357
+ name: string;
358
+ darkValue?: string | undefined;
359
+ }[];
360
+ typography: {
361
+ name: string;
362
+ fontSize: string;
363
+ fontFamily?: string | undefined;
364
+ fontWeight?: string | number | undefined;
365
+ lineHeight?: string | undefined;
366
+ letterSpacing?: string | undefined;
367
+ }[];
368
+ spacing: {
369
+ value: string;
370
+ name: string;
371
+ }[];
372
+ };
373
+ pages: {
374
+ route: string;
375
+ components: any[];
376
+ title?: string | undefined;
377
+ layout?: any;
378
+ meta?: {
379
+ description?: string | undefined;
380
+ ogTitle?: string | undefined;
381
+ } | undefined;
382
+ }[];
383
+ userComponents?: string[] | undefined;
384
+ }, {
385
+ version: "1";
386
+ tokens: {
387
+ colors: {
388
+ value: string;
389
+ name: string;
390
+ darkValue?: string | undefined;
391
+ }[];
392
+ typography: {
393
+ name: string;
394
+ fontSize: string;
395
+ fontFamily?: string | undefined;
396
+ fontWeight?: string | number | undefined;
397
+ lineHeight?: string | undefined;
398
+ letterSpacing?: string | undefined;
399
+ }[];
400
+ spacing: {
401
+ value: string;
402
+ name: string;
403
+ }[];
404
+ };
405
+ pages: {
406
+ route: string;
407
+ components: any[];
408
+ title?: string | undefined;
409
+ layout?: any;
410
+ meta?: {
411
+ description?: string | undefined;
412
+ ogTitle?: string | undefined;
413
+ } | undefined;
414
+ }[];
415
+ userComponents?: string[] | undefined;
416
+ }>;
417
+
418
+ interface ConfigContextValue {
419
+ config: UIConfig;
420
+ darkMode: boolean;
421
+ setDarkMode: (value: boolean) => void;
422
+ tokenVars: Record<string, string>;
423
+ /**
424
+ * When true, structural Row/Col containers are drawn with a debug bounding-box
425
+ * outline. Off by default so rendered pages look like real pages; the editor
426
+ * preview can opt in to visualise layout structure.
427
+ */
428
+ debug: boolean;
429
+ }
430
+ declare function useConfigContext(): ConfigContextValue;
431
+ interface MethodRegistration {
432
+ id: string;
433
+ fn: (...args: unknown[]) => unknown;
434
+ }
435
+ interface ComponentRegistration {
436
+ name: string;
437
+ component: React.ComponentType<Record<string, unknown>>;
438
+ }
439
+ interface ConfigProviderProps {
440
+ config: UIConfig | unknown;
441
+ methods?: MethodRegistration[];
442
+ components?: ComponentRegistration[];
443
+ children: React.ReactNode;
444
+ onConfigInvalid?: (error: Error) => void;
445
+ /** Draw debug bounding boxes around structural containers. Default false. */
446
+ debug?: boolean;
447
+ }
448
+ declare function ConfigProvider({ config: rawConfig, methods, components, children, onConfigInvalid, debug, }: ConfigProviderProps): React.ReactElement | null;
449
+
450
+ interface ConfigRendererProps {
451
+ page: string;
452
+ }
453
+ declare function ConfigRenderer({ page }: ConfigRendererProps): React.ReactElement | null;
454
+
455
+ interface LayoutRendererProps {
456
+ layout: LayoutDef;
457
+ components: ComponentDef[];
458
+ }
459
+ declare function LayoutRenderer({ layout, components }: LayoutRendererProps): React.ReactElement | null;
460
+
461
+ interface ComponentRendererProps {
462
+ component: ComponentDef;
463
+ components: ComponentDef[];
464
+ /**
465
+ * Rendered children to place inside this component (the "slot"). Supplied by
466
+ * the LayoutRenderer when a layout node binds a component AND has layout
467
+ * children — e.g. a custom container like `Card`/`DefaultPageFormat`. When
468
+ * present it takes precedence over the component's own `children` defs.
469
+ */
470
+ slot?: React.ReactNode;
471
+ }
472
+ declare function ComponentRenderer({ component, components, slot, }: ComponentRendererProps): React.ReactElement | null;
473
+
474
+ declare function useRegisteredMethod(id: string): ((...args: unknown[]) => unknown) | undefined;
475
+
476
+ declare function useVisibility(rule: VisibilityDef | undefined): boolean;
477
+
478
+ type RegisteredMethod = (...args: unknown[]) => unknown;
479
+ declare function registerMethod(id: string, fn: RegisteredMethod): void;
480
+ declare function getMethod(id: string): RegisteredMethod | undefined;
481
+ declare function clearRegistry(): void;
482
+
483
+ type RegisteredComponent = React.ComponentType<Record<string, unknown>>;
484
+ declare function registerComponent(name: string, component: RegisteredComponent): void;
485
+ declare function getComponent(name: string): RegisteredComponent | undefined;
486
+ declare function clearComponentRegistry(): void;
487
+
488
+ interface ComponentProps {
489
+ [key: string]: any;
490
+ children?: ReactNode;
491
+ }
492
+ declare const BUILTIN_COMPONENTS: {
493
+ Text: ({ text, children, ...props }: ComponentProps) => React.DetailedReactHTMLElement<{
494
+ [key: string]: any;
495
+ }, HTMLElement>;
496
+ Heading: ({ level, text, children, ...props }: ComponentProps) => React.DOMElement<{
497
+ [key: string]: any;
498
+ }, Element>;
499
+ Button: ({ text, children, onClick, href, style, type, ...props }: ComponentProps) => React.FunctionComponentElement<Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, keyof next_link.LinkProps<any>> & next_link.LinkProps<any> & {
500
+ children?: React.ReactNode | undefined;
501
+ } & React.RefAttributes<HTMLAnchorElement>> | React.DetailedReactHTMLElement<{
502
+ type: any;
503
+ onClick: any;
504
+ style: any;
505
+ }, HTMLElement>;
506
+ Image: ({ src, alt, ...props }: ComponentProps) => React.DetailedReactHTMLElement<{
507
+ children?: ReactNode;
508
+ src: any;
509
+ alt: any;
510
+ }, HTMLElement>;
511
+ List: ({ items, children, ...props }: ComponentProps) => React.DetailedReactHTMLElement<{
512
+ [key: string]: any;
513
+ }, HTMLElement>;
514
+ Card: ({ children, ...props }: ComponentProps) => React.DetailedReactHTMLElement<{
515
+ [key: string]: any;
516
+ }, HTMLElement>;
517
+ Divider: (props: ComponentProps) => React.DetailedReactHTMLElement<ComponentProps, HTMLElement>;
518
+ Spacer: (props: ComponentProps) => React.DetailedReactHTMLElement<ComponentProps, HTMLElement>;
519
+ Icon: ({ name, ...props }: ComponentProps) => React.DetailedReactHTMLElement<{
520
+ [key: string]: any;
521
+ children?: ReactNode;
522
+ }, HTMLElement>;
523
+ Table: ({ children, ...props }: ComponentProps) => React.ReactElement<{
524
+ 'data-isd-table': string;
525
+ }, string | React.JSXElementConstructor<any>>;
526
+ Input: ({ type, value, onChange, placeholder, name, disabled, style, ...props }: ComponentProps) => React.DetailedReactHTMLElement<{
527
+ children?: ReactNode;
528
+ type: any;
529
+ value: any;
530
+ onChange: any;
531
+ placeholder: any;
532
+ name: any;
533
+ disabled: any;
534
+ style: any;
535
+ }, HTMLElement>;
536
+ Textarea: ({ value, onChange, placeholder, name, rows, style, ...props }: ComponentProps) => React.DetailedReactHTMLElement<{
537
+ children?: ReactNode;
538
+ value: any;
539
+ onChange: any;
540
+ placeholder: any;
541
+ name: any;
542
+ rows: any;
543
+ style: any;
544
+ }, HTMLElement>;
545
+ Select: ({ value, onChange, name, options, children, style, ...props }: ComponentProps) => React.DetailedReactHTMLElement<{
546
+ value: any;
547
+ onChange: any;
548
+ name: any;
549
+ style: any;
550
+ }, HTMLElement>;
551
+ Option: ({ value, label, children, ...props }: ComponentProps) => React.ReactElement<{
552
+ value: any;
553
+ }, string | React.JSXElementConstructor<any>>;
554
+ Checkbox: ({ checked, onChange, name, disabled, style, ...props }: ComponentProps) => React.DetailedReactHTMLElement<{
555
+ children?: ReactNode;
556
+ type: string;
557
+ checked: any;
558
+ onChange: any;
559
+ name: any;
560
+ disabled: any;
561
+ style: any;
562
+ }, HTMLElement>;
563
+ Radio: ({ checked, value, name, onChange, style, ...props }: ComponentProps) => React.DetailedReactHTMLElement<{
564
+ children?: ReactNode;
565
+ type: string;
566
+ checked: any;
567
+ value: any;
568
+ name: any;
569
+ onChange: any;
570
+ style: any;
571
+ }, HTMLElement>;
572
+ Label: ({ htmlFor, text, children, style, ...props }: ComponentProps) => React.DetailedReactHTMLElement<{
573
+ htmlFor: any;
574
+ style: any;
575
+ }, HTMLElement>;
576
+ Children: ({ slot, children, ...props }: ComponentProps) => React.FunctionComponentElement<React.FragmentProps>;
577
+ Repeat: ({ data, children, style, ...props }: ComponentProps) => React.DetailedReactHTMLElement<{
578
+ 'data-isd-repeat': string;
579
+ style: any;
580
+ }, HTMLElement>;
581
+ Form: ({ children, style, ...props }: ComponentProps) => React.FunctionComponentElement<{
582
+ initial?: Record<string, unknown>;
583
+ children: React.ReactNode;
584
+ }>;
585
+ Modal: ({ open, onClose, children, style, ...props }: ComponentProps) => React.ReactPortal | null;
586
+ };
587
+
588
+ declare function EditorPage(): React.ReactElement;
589
+
590
+ interface ParseOptions {
591
+ /**
592
+ * Called when an `import "./file.idml"` line is encountered.
593
+ * Should return the raw source of the imported file.
594
+ */
595
+ resolve?: (path: string) => string;
596
+ }
597
+ declare function parseIdml(source: string, options?: ParseOptions): UIConfig;
598
+
599
+ export { BUILTIN_COMPONENTS, type ColorToken, type ComponentDef, type ComponentRegistration, ComponentRenderer, type ConfigContextValue, ConfigProvider, type ConfigProviderProps, ConfigRenderer, type DataBindingDef, EditorPage, type FlexDef, type GridDef, type LayoutDef, LayoutRenderer, type MethodRegistration, type PageDef, type SizeDef, type SpacingToken, type TokensDef, type TypographyToken, type UIConfig, UIConfigSchema, type VisibilityDef, clearComponentRegistry, clearRegistry, getComponent, getMethod, parseIdml, registerComponent, registerMethod, safeValidateConfig, useConfigContext, useRegisteredMethod, useVisibility, validateConfig };