kerfjs 0.3.1 → 0.5.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.
@@ -1,3 +1,624 @@
1
+ /**
2
+ * JSX intrinsic-element types — kerf's per-tag attribute contracts.
3
+ *
4
+ * Replaces the previous `[elemName: string]: Record<string, unknown>`
5
+ * catch-all that allowed any tag and any prop. Now: known tags get focused
6
+ * attribute interfaces (typos fail to compile); unknown tags require
7
+ * declaration merging to opt in.
8
+ *
9
+ * Coverage is intentionally focused, not exhaustive. The most common ~30
10
+ * HTML elements + the SVG primitives that make up `toElement`'s fragment
11
+ * set are typed in detail. Rare attributes can be added in follow-ups, or
12
+ * extended on a per-project basis via declaration merging into the
13
+ * `kerfjs/jsx-runtime` JSX namespace (KF-100):
14
+ *
15
+ * import type { KerfBaseAttrs, KerfCustomElement } from 'kerfjs/jsx-runtime';
16
+ *
17
+ * declare module 'kerfjs/jsx-runtime' {
18
+ * namespace JSX {
19
+ * interface IntrinsicElements {
20
+ * 'my-element': KerfCustomElement & { foo?: string };
21
+ * }
22
+ * }
23
+ * }
24
+ *
25
+ * `IntrinsicElements` in `jsx-runtime` is an **interface** that extends the
26
+ * one defined here, which is what makes the merge above work — type aliases
27
+ * (the previous shape) couldn't be merged.
28
+ *
29
+ * Every attribute value is `AttrValue` — string / number / boolean / null /
30
+ * undefined / `SafeHtml`. Event-handler props (`onClick` etc.) are
31
+ * deliberately omitted: kerf renders to strings, so inline handlers do
32
+ * nothing. Use `delegate()` / `delegateCapture()` instead.
33
+ */
34
+
35
+ /** Every kerf attribute value resolves to one of these. */
36
+ type AttrValue = string | number | boolean | null | undefined | SafeHtml;
37
+ /** A typed-narrowing helper: `AttrLike<'a'|'b'>` accepts the literals plus the runtime fall-throughs. */
38
+ type AttrLike<T = string> = T | SafeHtml | null | undefined;
39
+ /**
40
+ * `data-*` and `aria-*` index signatures. Applied via `KerfBaseAttrs` so
41
+ * every typed element accepts them without per-element enumeration.
42
+ */
43
+ interface DataAriaAttrs {
44
+ [k: `data-${string}`]: AttrValue;
45
+ [k: `aria-${string}`]: AttrValue;
46
+ }
47
+ /** Attributes valid on essentially every HTML element. */
48
+ interface KerfBaseAttrs extends DataAriaAttrs {
49
+ id?: AttrLike;
50
+ className?: AttrLike;
51
+ style?: AttrLike;
52
+ title?: AttrLike;
53
+ lang?: AttrLike;
54
+ dir?: AttrLike<'ltr' | 'rtl' | 'auto'>;
55
+ hidden?: AttrLike<boolean>;
56
+ draggable?: AttrLike<boolean>;
57
+ contentEditable?: AttrLike<boolean | 'true' | 'false' | 'inherit'>;
58
+ inputMode?: AttrLike<'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search'>;
59
+ spellCheck?: AttrLike<boolean>;
60
+ tabIndex?: AttrLike<number>;
61
+ role?: AttrLike;
62
+ slot?: AttrLike;
63
+ is?: AttrLike;
64
+ autoCapitalize?: AttrLike<'off' | 'none' | 'on' | 'sentences' | 'words' | 'characters'>;
65
+ autoFocus?: AttrLike<boolean>;
66
+ accessKey?: AttrLike;
67
+ /** `data-morph-skip` opts a subtree out of kerf's diff. Any value (incl. `true`) is treated as set. */
68
+ 'data-morph-skip'?: AttrValue;
69
+ children?: unknown;
70
+ }
71
+ /** Element-specific attribute interfaces. Each extends `KerfBaseAttrs`. */
72
+ interface HTMLAnchorAttrs extends KerfBaseAttrs {
73
+ href?: AttrLike;
74
+ target?: AttrLike<'_self' | '_blank' | '_parent' | '_top'>;
75
+ rel?: AttrLike;
76
+ download?: AttrLike;
77
+ hrefLang?: AttrLike;
78
+ ping?: AttrLike;
79
+ referrerPolicy?: AttrLike;
80
+ type?: AttrLike;
81
+ }
82
+ interface HTMLAreaAttrs extends KerfBaseAttrs {
83
+ alt?: AttrLike;
84
+ coords?: AttrLike;
85
+ shape?: AttrLike<'rect' | 'circle' | 'poly' | 'default'>;
86
+ href?: AttrLike;
87
+ target?: AttrLike;
88
+ rel?: AttrLike;
89
+ }
90
+ interface HTMLImgAttrs extends KerfBaseAttrs {
91
+ src?: AttrLike;
92
+ alt?: AttrLike;
93
+ width?: AttrLike<number | string>;
94
+ height?: AttrLike<number | string>;
95
+ srcSet?: AttrLike;
96
+ sizes?: AttrLike;
97
+ loading?: AttrLike<'eager' | 'lazy'>;
98
+ decoding?: AttrLike<'sync' | 'async' | 'auto'>;
99
+ crossOrigin?: AttrLike<'anonymous' | 'use-credentials' | ''>;
100
+ referrerPolicy?: AttrLike;
101
+ useMap?: AttrLike;
102
+ fetchPriority?: AttrLike<'high' | 'low' | 'auto'>;
103
+ }
104
+ interface HTMLInputAttrs extends KerfBaseAttrs {
105
+ type?: AttrLike<'text' | 'password' | 'email' | 'number' | 'tel' | 'url' | 'search' | 'date' | 'datetime-local' | 'time' | 'month' | 'week' | 'color' | 'checkbox' | 'radio' | 'file' | 'hidden' | 'submit' | 'reset' | 'button' | 'image' | 'range'>;
106
+ name?: AttrLike;
107
+ value?: AttrLike;
108
+ defaultValue?: AttrLike;
109
+ placeholder?: AttrLike;
110
+ required?: AttrLike<boolean>;
111
+ disabled?: AttrLike<boolean>;
112
+ readOnly?: AttrLike<boolean>;
113
+ checked?: AttrLike<boolean>;
114
+ defaultChecked?: AttrLike<boolean>;
115
+ multiple?: AttrLike<boolean>;
116
+ pattern?: AttrLike;
117
+ min?: AttrLike<number | string>;
118
+ max?: AttrLike<number | string>;
119
+ step?: AttrLike<number | string>;
120
+ minLength?: AttrLike<number>;
121
+ maxLength?: AttrLike<number>;
122
+ size?: AttrLike<number>;
123
+ autoComplete?: AttrLike;
124
+ form?: AttrLike;
125
+ formAction?: AttrLike;
126
+ formMethod?: AttrLike<'get' | 'post' | 'dialog'>;
127
+ formTarget?: AttrLike;
128
+ formEncType?: AttrLike;
129
+ formNoValidate?: AttrLike<boolean>;
130
+ list?: AttrLike;
131
+ src?: AttrLike;
132
+ alt?: AttrLike;
133
+ width?: AttrLike<number | string>;
134
+ height?: AttrLike<number | string>;
135
+ accept?: AttrLike;
136
+ capture?: AttrLike<boolean | 'user' | 'environment'>;
137
+ }
138
+ interface HTMLButtonAttrs extends KerfBaseAttrs {
139
+ type?: AttrLike<'button' | 'submit' | 'reset'>;
140
+ name?: AttrLike;
141
+ value?: AttrLike;
142
+ disabled?: AttrLike<boolean>;
143
+ form?: AttrLike;
144
+ formAction?: AttrLike;
145
+ formMethod?: AttrLike;
146
+ formTarget?: AttrLike;
147
+ formEncType?: AttrLike;
148
+ formNoValidate?: AttrLike<boolean>;
149
+ }
150
+ interface HTMLFormAttrs extends KerfBaseAttrs {
151
+ action?: AttrLike;
152
+ method?: AttrLike<'get' | 'post' | 'dialog'>;
153
+ encType?: AttrLike;
154
+ target?: AttrLike;
155
+ name?: AttrLike;
156
+ noValidate?: AttrLike<boolean>;
157
+ acceptCharset?: AttrLike;
158
+ autoComplete?: AttrLike;
159
+ }
160
+ interface HTMLLabelAttrs extends KerfBaseAttrs {
161
+ htmlFor?: AttrLike;
162
+ form?: AttrLike;
163
+ }
164
+ interface HTMLOptionAttrs extends KerfBaseAttrs {
165
+ value?: AttrLike;
166
+ selected?: AttrLike<boolean>;
167
+ defaultSelected?: AttrLike<boolean>;
168
+ disabled?: AttrLike<boolean>;
169
+ label?: AttrLike;
170
+ }
171
+ interface HTMLOptgroupAttrs extends KerfBaseAttrs {
172
+ label?: AttrLike;
173
+ disabled?: AttrLike<boolean>;
174
+ }
175
+ interface HTMLSelectAttrs extends KerfBaseAttrs {
176
+ name?: AttrLike;
177
+ value?: AttrLike;
178
+ defaultValue?: AttrLike;
179
+ multiple?: AttrLike<boolean>;
180
+ required?: AttrLike<boolean>;
181
+ disabled?: AttrLike<boolean>;
182
+ size?: AttrLike<number>;
183
+ form?: AttrLike;
184
+ autoComplete?: AttrLike;
185
+ }
186
+ interface HTMLTextareaAttrs extends KerfBaseAttrs {
187
+ name?: AttrLike;
188
+ value?: AttrLike;
189
+ defaultValue?: AttrLike;
190
+ placeholder?: AttrLike;
191
+ rows?: AttrLike<number>;
192
+ cols?: AttrLike<number>;
193
+ required?: AttrLike<boolean>;
194
+ disabled?: AttrLike<boolean>;
195
+ readOnly?: AttrLike<boolean>;
196
+ maxLength?: AttrLike<number>;
197
+ minLength?: AttrLike<number>;
198
+ wrap?: AttrLike<'hard' | 'soft' | 'off'>;
199
+ autoComplete?: AttrLike;
200
+ form?: AttrLike;
201
+ }
202
+ interface HTMLTableAttrs extends KerfBaseAttrs {
203
+ cellPadding?: AttrLike<number | string>;
204
+ cellSpacing?: AttrLike<number | string>;
205
+ }
206
+ interface HTMLTableCellAttrs extends KerfBaseAttrs {
207
+ colSpan?: AttrLike<number>;
208
+ rowSpan?: AttrLike<number>;
209
+ headers?: AttrLike;
210
+ scope?: AttrLike<'row' | 'col' | 'rowgroup' | 'colgroup'>;
211
+ abbr?: AttrLike;
212
+ }
213
+ interface HTMLColAttrs extends KerfBaseAttrs {
214
+ span?: AttrLike<number>;
215
+ }
216
+ interface HTMLMetaAttrs extends KerfBaseAttrs {
217
+ name?: AttrLike;
218
+ content?: AttrLike;
219
+ charSet?: AttrLike;
220
+ httpEquiv?: AttrLike;
221
+ }
222
+ interface HTMLLinkAttrs extends KerfBaseAttrs {
223
+ href?: AttrLike;
224
+ rel?: AttrLike;
225
+ type?: AttrLike;
226
+ media?: AttrLike;
227
+ sizes?: AttrLike;
228
+ hrefLang?: AttrLike;
229
+ as?: AttrLike;
230
+ crossOrigin?: AttrLike;
231
+ integrity?: AttrLike;
232
+ referrerPolicy?: AttrLike;
233
+ fetchPriority?: AttrLike<'high' | 'low' | 'auto'>;
234
+ }
235
+ interface HTMLScriptAttrs extends KerfBaseAttrs {
236
+ src?: AttrLike;
237
+ type?: AttrLike;
238
+ async?: AttrLike<boolean>;
239
+ defer?: AttrLike<boolean>;
240
+ noModule?: AttrLike<boolean>;
241
+ integrity?: AttrLike;
242
+ crossOrigin?: AttrLike;
243
+ referrerPolicy?: AttrLike;
244
+ nonce?: AttrLike;
245
+ }
246
+ interface HTMLStyleAttrs extends KerfBaseAttrs {
247
+ type?: AttrLike;
248
+ media?: AttrLike;
249
+ scoped?: AttrLike<boolean>;
250
+ }
251
+ interface HTMLIframeAttrs extends KerfBaseAttrs {
252
+ src?: AttrLike;
253
+ srcDoc?: AttrLike;
254
+ name?: AttrLike;
255
+ sandbox?: AttrLike;
256
+ allow?: AttrLike;
257
+ allowFullScreen?: AttrLike<boolean>;
258
+ width?: AttrLike<number | string>;
259
+ height?: AttrLike<number | string>;
260
+ loading?: AttrLike<'eager' | 'lazy'>;
261
+ referrerPolicy?: AttrLike;
262
+ }
263
+ interface HTMLMediaAttrs extends KerfBaseAttrs {
264
+ src?: AttrLike;
265
+ controls?: AttrLike<boolean>;
266
+ autoPlay?: AttrLike<boolean>;
267
+ loop?: AttrLike<boolean>;
268
+ muted?: AttrLike<boolean>;
269
+ preload?: AttrLike<'auto' | 'metadata' | 'none' | ''>;
270
+ crossOrigin?: AttrLike;
271
+ }
272
+ interface HTMLVideoAttrs extends HTMLMediaAttrs {
273
+ poster?: AttrLike;
274
+ width?: AttrLike<number | string>;
275
+ height?: AttrLike<number | string>;
276
+ playsInline?: AttrLike<boolean>;
277
+ }
278
+ interface HTMLSourceAttrs extends KerfBaseAttrs {
279
+ src?: AttrLike;
280
+ type?: AttrLike;
281
+ srcSet?: AttrLike;
282
+ sizes?: AttrLike;
283
+ media?: AttrLike;
284
+ }
285
+ interface HTMLTrackAttrs extends KerfBaseAttrs {
286
+ src?: AttrLike;
287
+ kind?: AttrLike<'subtitles' | 'captions' | 'descriptions' | 'chapters' | 'metadata'>;
288
+ srcLang?: AttrLike;
289
+ label?: AttrLike;
290
+ default?: AttrLike<boolean>;
291
+ }
292
+ interface HTMLDetailsAttrs extends KerfBaseAttrs {
293
+ open?: AttrLike<boolean>;
294
+ }
295
+ interface HTMLDialogAttrs extends KerfBaseAttrs {
296
+ open?: AttrLike<boolean>;
297
+ }
298
+ interface HTMLOlAttrs extends KerfBaseAttrs {
299
+ reversed?: AttrLike<boolean>;
300
+ start?: AttrLike<number>;
301
+ type?: AttrLike<'1' | 'a' | 'A' | 'i' | 'I'>;
302
+ }
303
+ interface HTMLLiAttrs extends KerfBaseAttrs {
304
+ value?: AttrLike<number>;
305
+ }
306
+ interface HTMLProgressAttrs extends KerfBaseAttrs {
307
+ value?: AttrLike<number>;
308
+ max?: AttrLike<number>;
309
+ }
310
+ interface HTMLMeterAttrs extends KerfBaseAttrs {
311
+ value?: AttrLike<number>;
312
+ min?: AttrLike<number>;
313
+ max?: AttrLike<number>;
314
+ low?: AttrLike<number>;
315
+ high?: AttrLike<number>;
316
+ optimum?: AttrLike<number>;
317
+ }
318
+ interface HTMLCanvasAttrs extends KerfBaseAttrs {
319
+ width?: AttrLike<number | string>;
320
+ height?: AttrLike<number | string>;
321
+ }
322
+ interface HTMLBaseAttrs extends KerfBaseAttrs {
323
+ href?: AttrLike;
324
+ target?: AttrLike;
325
+ }
326
+ interface HTMLBlockquoteAttrs extends KerfBaseAttrs {
327
+ cite?: AttrLike;
328
+ }
329
+ interface HTMLQAttrs extends KerfBaseAttrs {
330
+ cite?: AttrLike;
331
+ }
332
+ /**
333
+ * SVG attribute set — focused on the elements `toElement`'s SVG path supports
334
+ * (the `SVG_FRAGMENT_TAGS` set in `src/toElement.ts`). Presentation attrs are
335
+ * shared via `SVGPresentationAttrs`.
336
+ */
337
+ interface SVGPresentationAttrs {
338
+ fill?: AttrLike;
339
+ fillOpacity?: AttrLike<number | string>;
340
+ fillRule?: AttrLike<'nonzero' | 'evenodd' | 'inherit'>;
341
+ stroke?: AttrLike;
342
+ strokeWidth?: AttrLike<number | string>;
343
+ strokeOpacity?: AttrLike<number | string>;
344
+ strokeLinecap?: AttrLike<'butt' | 'round' | 'square' | 'inherit'>;
345
+ strokeLinejoin?: AttrLike<'miter' | 'round' | 'bevel' | 'inherit'>;
346
+ strokeDasharray?: AttrLike;
347
+ strokeDashoffset?: AttrLike<number | string>;
348
+ strokeMiterlimit?: AttrLike<number | string>;
349
+ opacity?: AttrLike<number | string>;
350
+ vectorEffect?: AttrLike;
351
+ clipPath?: AttrLike;
352
+ clipRule?: AttrLike;
353
+ mask?: AttrLike;
354
+ filter?: AttrLike;
355
+ pointerEvents?: AttrLike;
356
+ shapeRendering?: AttrLike;
357
+ paintOrder?: AttrLike;
358
+ color?: AttrLike;
359
+ display?: AttrLike;
360
+ visibility?: AttrLike;
361
+ }
362
+ interface SVGCommonAttrs extends DataAriaAttrs, SVGPresentationAttrs {
363
+ id?: AttrLike;
364
+ className?: AttrLike;
365
+ style?: AttrLike;
366
+ transform?: AttrLike;
367
+ tabIndex?: AttrLike<number>;
368
+ role?: AttrLike;
369
+ xmlns?: AttrLike;
370
+ xmlnsXlink?: AttrLike;
371
+ children?: unknown;
372
+ }
373
+ interface SVGSvgAttrs extends SVGCommonAttrs {
374
+ width?: AttrLike<number | string>;
375
+ height?: AttrLike<number | string>;
376
+ viewBox?: AttrLike;
377
+ preserveAspectRatio?: AttrLike;
378
+ x?: AttrLike<number | string>;
379
+ y?: AttrLike<number | string>;
380
+ }
381
+ interface SVGPathAttrs extends SVGCommonAttrs {
382
+ d?: AttrLike;
383
+ pathLength?: AttrLike<number>;
384
+ }
385
+ interface SVGCircleAttrs extends SVGCommonAttrs {
386
+ cx?: AttrLike<number | string>;
387
+ cy?: AttrLike<number | string>;
388
+ r?: AttrLike<number | string>;
389
+ }
390
+ interface SVGRectAttrs extends SVGCommonAttrs {
391
+ x?: AttrLike<number | string>;
392
+ y?: AttrLike<number | string>;
393
+ width?: AttrLike<number | string>;
394
+ height?: AttrLike<number | string>;
395
+ rx?: AttrLike<number | string>;
396
+ ry?: AttrLike<number | string>;
397
+ }
398
+ interface SVGLineAttrs extends SVGCommonAttrs {
399
+ x1?: AttrLike<number | string>;
400
+ y1?: AttrLike<number | string>;
401
+ x2?: AttrLike<number | string>;
402
+ y2?: AttrLike<number | string>;
403
+ }
404
+ interface SVGEllipseAttrs extends SVGCommonAttrs {
405
+ cx?: AttrLike<number | string>;
406
+ cy?: AttrLike<number | string>;
407
+ rx?: AttrLike<number | string>;
408
+ ry?: AttrLike<number | string>;
409
+ }
410
+ interface SVGPolyAttrs extends SVGCommonAttrs {
411
+ points?: AttrLike;
412
+ }
413
+ interface SVGTextAttrs extends SVGCommonAttrs {
414
+ x?: AttrLike<number | string>;
415
+ y?: AttrLike<number | string>;
416
+ dx?: AttrLike<number | string>;
417
+ dy?: AttrLike<number | string>;
418
+ textAnchor?: AttrLike<'start' | 'middle' | 'end' | 'inherit'>;
419
+ dominantBaseline?: AttrLike;
420
+ fontFamily?: AttrLike;
421
+ fontSize?: AttrLike<number | string>;
422
+ fontStyle?: AttrLike;
423
+ fontWeight?: AttrLike<number | string>;
424
+ letterSpacing?: AttrLike<number | string>;
425
+ }
426
+ interface SVGUseAttrs extends SVGCommonAttrs {
427
+ xlinkHref?: AttrLike;
428
+ href?: AttrLike;
429
+ x?: AttrLike<number | string>;
430
+ y?: AttrLike<number | string>;
431
+ width?: AttrLike<number | string>;
432
+ height?: AttrLike<number | string>;
433
+ }
434
+ interface SVGImageAttrs extends SVGCommonAttrs {
435
+ href?: AttrLike;
436
+ xlinkHref?: AttrLike;
437
+ x?: AttrLike<number | string>;
438
+ y?: AttrLike<number | string>;
439
+ width?: AttrLike<number | string>;
440
+ height?: AttrLike<number | string>;
441
+ preserveAspectRatio?: AttrLike;
442
+ }
443
+ interface SVGForeignObjectAttrs extends SVGCommonAttrs {
444
+ x?: AttrLike<number | string>;
445
+ y?: AttrLike<number | string>;
446
+ width?: AttrLike<number | string>;
447
+ height?: AttrLike<number | string>;
448
+ }
449
+ /**
450
+ * Loose attribute set for custom elements / web components. Use via
451
+ * declaration merging into the `kerfjs/jsx-runtime` JSX namespace if your
452
+ * project uses tags not enumerated below:
453
+ *
454
+ * import type { KerfCustomElement } from 'kerfjs/jsx-runtime';
455
+ *
456
+ * declare module 'kerfjs/jsx-runtime' {
457
+ * namespace JSX {
458
+ * interface IntrinsicElements {
459
+ * 'my-component': KerfCustomElement & { foo?: string };
460
+ * }
461
+ * }
462
+ * }
463
+ *
464
+ * `KerfCustomElement` is re-exported from `kerfjs/jsx-runtime` (KF-100) so
465
+ * apps don't need to reach into the internal `kerfjs/jsx-types` path.
466
+ */
467
+ interface KerfCustomElement extends KerfBaseAttrs {
468
+ [k: string]: AttrValue | unknown;
469
+ }
470
+ interface IntrinsicElements {
471
+ html: KerfBaseAttrs;
472
+ head: KerfBaseAttrs;
473
+ body: KerfBaseAttrs;
474
+ div: KerfBaseAttrs;
475
+ span: KerfBaseAttrs;
476
+ section: KerfBaseAttrs;
477
+ article: KerfBaseAttrs;
478
+ header: KerfBaseAttrs;
479
+ footer: KerfBaseAttrs;
480
+ main: KerfBaseAttrs;
481
+ nav: KerfBaseAttrs;
482
+ aside: KerfBaseAttrs;
483
+ h1: KerfBaseAttrs;
484
+ h2: KerfBaseAttrs;
485
+ h3: KerfBaseAttrs;
486
+ h4: KerfBaseAttrs;
487
+ h5: KerfBaseAttrs;
488
+ h6: KerfBaseAttrs;
489
+ p: KerfBaseAttrs;
490
+ hr: KerfBaseAttrs;
491
+ br: KerfBaseAttrs;
492
+ pre: KerfBaseAttrs;
493
+ blockquote: HTMLBlockquoteAttrs;
494
+ q: HTMLQAttrs;
495
+ ol: HTMLOlAttrs;
496
+ ul: KerfBaseAttrs;
497
+ li: HTMLLiAttrs;
498
+ dl: KerfBaseAttrs;
499
+ dt: KerfBaseAttrs;
500
+ dd: KerfBaseAttrs;
501
+ figure: KerfBaseAttrs;
502
+ figcaption: KerfBaseAttrs;
503
+ a: HTMLAnchorAttrs;
504
+ em: KerfBaseAttrs;
505
+ strong: KerfBaseAttrs;
506
+ small: KerfBaseAttrs;
507
+ s: KerfBaseAttrs;
508
+ cite: KerfBaseAttrs;
509
+ code: KerfBaseAttrs;
510
+ kbd: KerfBaseAttrs;
511
+ samp: KerfBaseAttrs;
512
+ var: KerfBaseAttrs;
513
+ sub: KerfBaseAttrs;
514
+ sup: KerfBaseAttrs;
515
+ i: KerfBaseAttrs;
516
+ b: KerfBaseAttrs;
517
+ u: KerfBaseAttrs;
518
+ mark: KerfBaseAttrs;
519
+ abbr: KerfBaseAttrs;
520
+ time: KerfBaseAttrs & {
521
+ dateTime?: AttrLike;
522
+ };
523
+ img: HTMLImgAttrs;
524
+ picture: KerfBaseAttrs;
525
+ source: HTMLSourceAttrs;
526
+ track: HTMLTrackAttrs;
527
+ iframe: HTMLIframeAttrs;
528
+ embed: KerfBaseAttrs & {
529
+ src?: AttrLike;
530
+ type?: AttrLike;
531
+ width?: AttrLike<number | string>;
532
+ height?: AttrLike<number | string>;
533
+ };
534
+ object: KerfBaseAttrs & {
535
+ data?: AttrLike;
536
+ type?: AttrLike;
537
+ name?: AttrLike;
538
+ width?: AttrLike<number | string>;
539
+ height?: AttrLike<number | string>;
540
+ };
541
+ audio: HTMLMediaAttrs;
542
+ video: HTMLVideoAttrs;
543
+ canvas: HTMLCanvasAttrs;
544
+ area: HTMLAreaAttrs;
545
+ map: KerfBaseAttrs & {
546
+ name?: AttrLike;
547
+ };
548
+ form: HTMLFormAttrs;
549
+ input: HTMLInputAttrs;
550
+ button: HTMLButtonAttrs;
551
+ select: HTMLSelectAttrs;
552
+ optgroup: HTMLOptgroupAttrs;
553
+ option: HTMLOptionAttrs;
554
+ textarea: HTMLTextareaAttrs;
555
+ label: HTMLLabelAttrs;
556
+ fieldset: KerfBaseAttrs & {
557
+ name?: AttrLike;
558
+ form?: AttrLike;
559
+ disabled?: AttrLike<boolean>;
560
+ };
561
+ legend: KerfBaseAttrs;
562
+ datalist: KerfBaseAttrs;
563
+ output: KerfBaseAttrs & {
564
+ name?: AttrLike;
565
+ form?: AttrLike;
566
+ htmlFor?: AttrLike;
567
+ };
568
+ progress: HTMLProgressAttrs;
569
+ meter: HTMLMeterAttrs;
570
+ table: HTMLTableAttrs;
571
+ caption: KerfBaseAttrs;
572
+ colgroup: HTMLColAttrs;
573
+ col: HTMLColAttrs;
574
+ thead: KerfBaseAttrs;
575
+ tbody: KerfBaseAttrs;
576
+ tfoot: KerfBaseAttrs;
577
+ tr: KerfBaseAttrs;
578
+ td: HTMLTableCellAttrs;
579
+ th: HTMLTableCellAttrs;
580
+ meta: HTMLMetaAttrs;
581
+ link: HTMLLinkAttrs;
582
+ script: HTMLScriptAttrs;
583
+ style: HTMLStyleAttrs;
584
+ base: HTMLBaseAttrs;
585
+ title: KerfBaseAttrs;
586
+ details: HTMLDetailsAttrs;
587
+ summary: KerfBaseAttrs;
588
+ dialog: HTMLDialogAttrs;
589
+ template: KerfBaseAttrs;
590
+ slot: KerfBaseAttrs & {
591
+ name?: AttrLike;
592
+ };
593
+ svg: SVGSvgAttrs;
594
+ g: SVGCommonAttrs;
595
+ defs: SVGCommonAttrs;
596
+ symbol: SVGCommonAttrs;
597
+ use: SVGUseAttrs;
598
+ path: SVGPathAttrs;
599
+ circle: SVGCircleAttrs;
600
+ rect: SVGRectAttrs;
601
+ line: SVGLineAttrs;
602
+ ellipse: SVGEllipseAttrs;
603
+ polygon: SVGPolyAttrs;
604
+ polyline: SVGPolyAttrs;
605
+ text: SVGTextAttrs;
606
+ tspan: SVGTextAttrs;
607
+ image: SVGImageAttrs;
608
+ foreignObject: SVGForeignObjectAttrs;
609
+ clipPath: SVGCommonAttrs;
610
+ mask: SVGCommonAttrs;
611
+ pattern: SVGCommonAttrs;
612
+ marker: SVGCommonAttrs;
613
+ linearGradient: SVGCommonAttrs;
614
+ radialGradient: SVGCommonAttrs;
615
+ stop: SVGCommonAttrs & {
616
+ offset?: AttrLike<number | string>;
617
+ stopColor?: AttrLike;
618
+ stopOpacity?: AttrLike<number | string>;
619
+ };
620
+ }
621
+
1
622
  /**
2
623
  * `Segment` — kerf's structured render output.
3
624
  *
@@ -41,7 +662,45 @@ interface ListSegment {
41
662
  kind: 'list';
42
663
  id: string;
43
664
  items: ListItem[];
665
+ /**
666
+ * Optional granular patches (KF-92). When present, the list reconciler
667
+ * applies these directly to the existing binding instead of doing a
668
+ * full classify+reconcile pass. Emitted by `each()` when bound to an
669
+ * `arraySignal`. Mutually exclusive with the `items` snapshot in the
670
+ * sense that the snapshot is treated as informational/fall-back when
671
+ * patches are present.
672
+ */
673
+ patches?: ArrayPatchInternal[];
44
674
  }
675
+ /**
676
+ * Internal patch shape used inside list segments. Mirrors `ArrayPatch<T>`
677
+ * from `array-signal.ts` but typed against `object` so the segment layer
678
+ * doesn't need to be generic. `update` / `insert` patches carry the row's
679
+ * pre-rendered HTML — `each()` renders them at JSX-evaluation time inside a
680
+ * try/catch so a throwing render falls back to the snapshot path (KF-99)
681
+ * instead of leaving the signal and DOM divergent.
682
+ */
683
+ type ArrayPatchInternal = {
684
+ type: 'update';
685
+ index: number;
686
+ item: object;
687
+ html: string;
688
+ } | {
689
+ type: 'insert';
690
+ index: number;
691
+ item: object;
692
+ html: string;
693
+ } | {
694
+ type: 'remove';
695
+ index: number;
696
+ } | {
697
+ type: 'move';
698
+ from: number;
699
+ to: number;
700
+ } | {
701
+ type: 'replace';
702
+ items: readonly object[];
703
+ };
45
704
  interface MixedSegment {
46
705
  kind: 'mixed';
47
706
  parts: Segment[];
@@ -93,6 +752,19 @@ declare function raw(html: string): SafeHtml;
93
752
  * `each()` so the JSX runtime is the sole owner of `SafeHtml` construction.
94
753
  */
95
754
  declare function listSafeHtml(id: string, items: ListSegment['items']): SafeHtml;
755
+ /**
756
+ * Internal: build a `SafeHtml` representing a granular list segment with
757
+ * patches (KF-92). The reconciler applies the patches to the existing
758
+ * binding directly, skipping the per-item iteration that the snapshot
759
+ * `listSafeHtml` requires. `items` is included for fall-through paths
760
+ * (toString during SSR, fall-back when the binding doesn't exist yet).
761
+ *
762
+ * Patch HTML is rendered upstream (in `each()`) inside a try/catch — see
763
+ * KF-99 — so by the time we get here every `update` / `insert` patch
764
+ * already carries a `html` string, and the reconciler does no further
765
+ * row rendering.
766
+ */
767
+ declare function granularListSafeHtml(id: string, items: ListSegment['items'], patches: NonNullable<ListSegment['patches']>): SafeHtml;
96
768
  type Child = SafeHtml | string | number | boolean | null | undefined;
97
769
  type Children = Child | Children[];
98
770
  interface Props {
@@ -109,9 +781,8 @@ declare namespace JSX {
109
781
  interface ElementChildrenAttribute {
110
782
  children: unknown;
111
783
  }
112
- interface IntrinsicElements {
113
- [elemName: string]: Record<string, unknown>;
784
+ interface IntrinsicElements extends IntrinsicElements {
114
785
  }
115
786
  }
116
787
 
117
- export { Fragment, JSX, SafeHtml, isSafeHtml, jsx, jsx as jsxDEV, jsx as jsxs, listSafeHtml, raw };
788
+ export { type AttrLike, type AttrValue, type DataAriaAttrs, Fragment, JSX, type KerfBaseAttrs, type KerfCustomElement, SafeHtml, granularListSafeHtml, isSafeHtml, jsx, jsx as jsxDEV, jsx as jsxs, listSafeHtml, raw };
@@ -1,3 +1,3 @@
1
- export { Fragment, SafeHtml, isSafeHtml, jsx, jsx as jsxDEV, jsx as jsxs, listSafeHtml, raw } from './chunk-WK5D3OO7.js';
1
+ export { Fragment, SafeHtml, granularListSafeHtml, isSafeHtml, jsx, jsx as jsxDEV, jsx as jsxs, listSafeHtml, raw } from './chunk-WYJTMERY.js';
2
2
  //# sourceMappingURL=jsx-runtime.js.map
3
3
  //# sourceMappingURL=jsx-runtime.js.map
package/dist/testing.js CHANGED
@@ -1,3 +1,4 @@
1
- export { clearStoreRegistry } from './chunk-IZJIKRCE.js';
1
+ export { clearStoreRegistry } from './chunk-GQGJFCWL.js';
2
+ import './chunk-FN2ID4QO.js';
2
3
  //# sourceMappingURL=testing.js.map
3
4
  //# sourceMappingURL=testing.js.map