@stealthscale/component-messaging 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,693 @@
1
+ import { FIELD_EDGE, PALETTES, axis, defineSlotRecipe, dense, flatVariants, onSlot, onSlots, paletteVariants, sizeVariants, surface, truncate, wrappedField, wrappedFieldVariants } from "@stealthscale/theme/authoring";
2
+ //#region src/attachment/recipe.ts
3
+ /**
4
+ * Declares the attachment's slot recipe: a file attached to a message or waiting in a composer, and
5
+ * the list that groups several.
6
+ *
7
+ * @remarks
8
+ * A horizontal attachment is a row: the media square, the title over the description, and the
9
+ * actions at the end. A vertical one is a tile: the media across the top, the words under it,
10
+ * and the actions over the media's corner. The root writes its state as `data-state`: an `idle`
11
+ * attachment, not yet sent, has a dashed edge, and a failed one has the error edge and inks its
12
+ * media and description in the error ink. The title and the description keep one line and end in
13
+ * an ellipsis, so a long file name never widens the list. A group stacks rows and wraps tiles.
14
+ */
15
+ /**
16
+ * Class name of the recipe, which a selector across parts reads.
17
+ */
18
+ const CLASS$1 = "attachment";
19
+ /**
20
+ * Selects the media of an attachment, from a rule on its root.
21
+ */
22
+ const MEDIA = `.${CLASS$1}__media`;
23
+ /**
24
+ * Selects the description of an attachment, from a rule on its root.
25
+ */
26
+ const DESCRIPTION = `.${CLASS$1}__description`;
27
+ /**
28
+ * Sizes the attachment offers.
29
+ */
30
+ const SIZES$2 = [
31
+ "xs",
32
+ "sm",
33
+ "md"
34
+ ];
35
+ /**
36
+ * Maps each size to its steps and text styles.
37
+ */
38
+ const METRICS$2 = {
39
+ md: {
40
+ detail: "body.xs",
41
+ gap: "sm",
42
+ inset: "sm",
43
+ media: "md",
44
+ text: "label.sm"
45
+ },
46
+ sm: {
47
+ detail: "body.xs",
48
+ gap: "sm",
49
+ inset: "xs",
50
+ media: "sm",
51
+ text: "label.xs"
52
+ },
53
+ xs: {
54
+ detail: "body.xs",
55
+ gap: "xs",
56
+ inset: "xs",
57
+ media: "xs",
58
+ text: "label.xs"
59
+ }
60
+ };
61
+ /**
62
+ * Styles a horizontal attachment at the middle size.
63
+ */
64
+ const recipe$4 = defineSlotRecipe({
65
+ base: {
66
+ actions: {
67
+ alignItems: "center",
68
+ display: "flex",
69
+ flexShrink: "0",
70
+ gap: dense("{spacing.gap.xs}")
71
+ },
72
+ content: {
73
+ display: "flex",
74
+ flex: "1",
75
+ flexDirection: "column",
76
+ minInlineSize: "0"
77
+ },
78
+ description: {
79
+ ...truncate(),
80
+ color: "fg.muted"
81
+ },
82
+ group: {
83
+ display: "flex",
84
+ gap: dense("{spacing.gap.sm}"),
85
+ listStyle: "none",
86
+ margin: "0",
87
+ minInlineSize: "0",
88
+ padding: "0"
89
+ },
90
+ media: {
91
+ "& > img": {
92
+ blockSize: "full",
93
+ inlineSize: "full",
94
+ objectFit: "cover"
95
+ },
96
+ "& > svg": {
97
+ blockSize: "50%",
98
+ inlineSize: "50%"
99
+ },
100
+ alignItems: "center",
101
+ aspectRatio: "square",
102
+ backgroundColor: "bg.muted",
103
+ borderRadius: "l1",
104
+ color: "fg.muted",
105
+ display: "flex",
106
+ flexShrink: "0",
107
+ justifyContent: "center",
108
+ overflow: "hidden"
109
+ },
110
+ root: {
111
+ "&[data-state=error]": {
112
+ [`& ${DESCRIPTION}, & ${MEDIA}`]: { color: "fg.error" },
113
+ borderColor: "border.error"
114
+ },
115
+ "&[data-state=idle]": { borderStyle: "dashed" },
116
+ alignItems: "center",
117
+ backgroundColor: "bg.panel",
118
+ borderColor: "border",
119
+ borderRadius: "l2",
120
+ borderStyle: "solid",
121
+ borderWidth: "hairline",
122
+ display: "flex",
123
+ maxInlineSize: "full",
124
+ minInlineSize: "0",
125
+ position: "relative"
126
+ },
127
+ title: {
128
+ ...truncate(),
129
+ color: "fg",
130
+ fontWeight: "medium"
131
+ }
132
+ },
133
+ className: CLASS$1,
134
+ compoundVariants: [{
135
+ css: { media: { inlineSize: "full" } },
136
+ name: "tiled",
137
+ orientation: "vertical"
138
+ }],
139
+ defaultVariants: {
140
+ orientation: "horizontal",
141
+ size: "md"
142
+ },
143
+ jsx: [/^Attachment\.\w+$/u],
144
+ slots: [
145
+ "group",
146
+ "root",
147
+ "media",
148
+ "content",
149
+ "title",
150
+ "description",
151
+ "actions"
152
+ ],
153
+ variants: {
154
+ /**
155
+ * Whether an attachment is a row or a tile, and whether a group stacks or wraps them.
156
+ */
157
+ orientation: {
158
+ horizontal: {
159
+ group: { flexDirection: "column" },
160
+ root: {
161
+ flexDirection: "row",
162
+ minInlineSize: "min({sizes.40}, 100%)"
163
+ }
164
+ },
165
+ vertical: {
166
+ actions: {
167
+ insetBlockStart: dense("{spacing.inset.xs}"),
168
+ insetInlineEnd: dense("{spacing.inset.xs}"),
169
+ position: "absolute"
170
+ },
171
+ group: {
172
+ flexDirection: "row",
173
+ flexWrap: "wrap"
174
+ },
175
+ root: {
176
+ alignItems: "stretch",
177
+ flexDirection: "column",
178
+ inlineSize: "{sizes.32}"
179
+ }
180
+ }
181
+ },
182
+ size: onSlots({
183
+ description: sizeVariants((size) => ({ textStyle: METRICS$2[size].detail }), SIZES$2),
184
+ media: sizeVariants((size) => ({ inlineSize: dense(`{sizes.control.${METRICS$2[size].media}}`) }), SIZES$2),
185
+ root: sizeVariants((size) => ({
186
+ gap: dense(`{spacing.gap.${METRICS$2[size].gap}}`),
187
+ padding: dense(`{spacing.inset.${METRICS$2[size].inset}}`)
188
+ }), SIZES$2),
189
+ title: sizeVariants((size) => ({ textStyle: METRICS$2[size].text }), SIZES$2)
190
+ })
191
+ }
192
+ });
193
+ //#endregion
194
+ //#region src/composer/recipe.ts
195
+ /**
196
+ * Declares the composer's slot recipe: the box a reader writes a message in, with a strip for the
197
+ * message it replies to, the attachments, the text and a row of controls.
198
+ *
199
+ * @remarks
200
+ * The root is the theme's wrapped field, so its edge, surface, focus ring and states come from
201
+ * the textarea inside it, as in the input group. The text is a bare `textarea` that grows with
202
+ * its content through `field-sizing: content` and stops at the number of lines the input writes
203
+ * as {@link ROWS}, after which it scrolls. While files are dragged over it the box takes the focus
204
+ * edge. The submit control is pushed to the end of the row of controls. The strip sizes its
205
+ * leading glyph to its text and pushes a control after its words, such as a dismiss button, to
206
+ * its end.
207
+ */
208
+ /**
209
+ * Custom property the input writes: the most lines it grows to before it scrolls.
210
+ */
211
+ const ROWS = "--composer-rows";
212
+ /**
213
+ * Custom property the size axis sets: the inset around the text and the controls.
214
+ */
215
+ const INSET = "--composer-inset";
216
+ /**
217
+ * The inset, read from {@link INSET}.
218
+ */
219
+ const PADDED = `var(${INSET})`;
220
+ /**
221
+ * Sizes the composer offers.
222
+ */
223
+ const SIZES$1 = [
224
+ "sm",
225
+ "md",
226
+ "lg"
227
+ ];
228
+ /**
229
+ * Maps each size to its inset and text style.
230
+ */
231
+ const METRICS$1 = {
232
+ lg: {
233
+ inset: "md",
234
+ text: "body.lg"
235
+ },
236
+ md: {
237
+ inset: "sm",
238
+ text: "body.md"
239
+ },
240
+ sm: {
241
+ inset: "xs",
242
+ text: "body.sm"
243
+ }
244
+ };
245
+ /**
246
+ * Styles an outlined composer at the middle size.
247
+ */
248
+ const recipe$3 = defineSlotRecipe({
249
+ base: {
250
+ attachments: {
251
+ paddingBlockStart: PADDED,
252
+ paddingInline: PADDED
253
+ },
254
+ context: {
255
+ "& > :not(button) + button": { marginInlineStart: "auto" },
256
+ "& > svg": {
257
+ blockSize: "1em",
258
+ flexShrink: "0",
259
+ inlineSize: "1em"
260
+ },
261
+ alignItems: "center",
262
+ backgroundColor: "bg.subtle",
263
+ borderStartEndRadius: "inherit",
264
+ borderStartStartRadius: "inherit",
265
+ color: "fg.muted",
266
+ display: "flex",
267
+ gap: dense("{spacing.gap.sm}"),
268
+ minInlineSize: "0",
269
+ paddingBlock: dense("{spacing.gap.xs}"),
270
+ paddingInline: PADDED,
271
+ textStyle: "label.sm"
272
+ },
273
+ detail: {
274
+ color: "fg.muted",
275
+ textStyle: "label.xs"
276
+ },
277
+ input: {
278
+ _placeholder: { color: "fg.muted" },
279
+ appearance: "none",
280
+ background: "transparent",
281
+ borderStyle: "none",
282
+ color: "fg",
283
+ display: "block",
284
+ fieldSizing: "content",
285
+ font: "inherit",
286
+ inlineSize: "full",
287
+ letterSpacing: "inherit",
288
+ maxBlockSize: `calc(var(${ROWS}) * 1lh + ${PADDED} * 2)`,
289
+ outline: "none",
290
+ padding: PADDED,
291
+ resize: "none"
292
+ },
293
+ root: {
294
+ ...wrappedField(),
295
+ "&[data-dragging]": { [FIELD_EDGE]: "{colors.border.focus}" },
296
+ borderRadius: "l3",
297
+ display: "flex",
298
+ flexDirection: "column",
299
+ inlineSize: "full",
300
+ margin: "0",
301
+ minInlineSize: "0",
302
+ position: "relative"
303
+ },
304
+ submit: { marginInlineStart: "auto" },
305
+ suggestion: {
306
+ "&[aria-selected=true]": {
307
+ _highContrast: {
308
+ background: "Highlight",
309
+ color: "HighlightText",
310
+ forcedColorAdjust: "none"
311
+ },
312
+ layerStyle: "fill.muted"
313
+ },
314
+ alignItems: "baseline",
315
+ borderRadius: "l1",
316
+ cursor: "option",
317
+ display: "flex",
318
+ gap: dense("{spacing.gap.sm}"),
319
+ paddingBlock: dense("{spacing.gap.xs}"),
320
+ paddingInline: dense("{spacing.inset.sm}"),
321
+ textStyle: "label.sm"
322
+ },
323
+ suggestions: {
324
+ ...surface("md"),
325
+ display: "flex",
326
+ flexDirection: "column",
327
+ insetBlockEnd: "100%",
328
+ insetInline: "0",
329
+ marginBlockEnd: dense("{spacing.gap.xs}"),
330
+ padding: dense("{spacing.inset.xs}"),
331
+ position: "absolute",
332
+ zIndex: "dropdown"
333
+ },
334
+ toolbar: {
335
+ alignItems: "center",
336
+ display: "flex",
337
+ gap: dense("{spacing.gap.xs}"),
338
+ paddingBlockEnd: PADDED,
339
+ paddingInline: PADDED
340
+ }
341
+ },
342
+ className: "composer",
343
+ defaultVariants: {
344
+ size: "md",
345
+ variant: "outline"
346
+ },
347
+ jsx: [/^Composer\.\w+$/u],
348
+ slots: [
349
+ "root",
350
+ "context",
351
+ "attachments",
352
+ "input",
353
+ "suggestions",
354
+ "suggestion",
355
+ "detail",
356
+ "toolbar",
357
+ "submit"
358
+ ],
359
+ variants: {
360
+ size: onSlots({
361
+ input: sizeVariants((size) => ({ textStyle: METRICS$1[size].text }), SIZES$1),
362
+ root: sizeVariants((size) => ({ [INSET]: dense(`{spacing.inset.${METRICS$1[size].inset}}`) }), SIZES$1)
363
+ }),
364
+ variant: onSlot("root", wrappedFieldVariants())
365
+ }
366
+ });
367
+ //#endregion
368
+ //#region src/conversation/recipe.ts
369
+ /**
370
+ * Declares the conversation's slot recipe: the transcript of turns, the control that jumps to the
371
+ * latest message, and the row that shows another person typing.
372
+ *
373
+ * @remarks
374
+ * The root and the viewport are the primitives scroll area's, so the bar, the focus ring and the
375
+ * keyboard scrolling are its own. The content stacks the turns in a column. The jump trigger is
376
+ * placed over the turns at the middle of the transcript's bottom edge. The viewport contains its
377
+ * overscroll, so a wheel at either end of the transcript leaves the page where it is. The typing
378
+ * row's three dots pulse at the theme's ambient pace, each 200ms after the one before, and rest
379
+ * under reduced motion. The dots fill with `CanvasText` under forced colors, which remove the
380
+ * dots' `currentcolor` fill in Chromium.
381
+ */
382
+ /**
383
+ * Styles a transcript of turns 16px apart at the foundation's metrics.
384
+ */
385
+ const recipe$2 = defineSlotRecipe({
386
+ base: {
387
+ content: {
388
+ display: "flex",
389
+ flexDirection: "column",
390
+ gap: dense("{spacing.gap.lg}")
391
+ },
392
+ dots: {
393
+ "& > span": {
394
+ _highContrast: {
395
+ background: "CanvasText",
396
+ forcedColorAdjust: "none"
397
+ },
398
+ _motionSafe: {
399
+ "&:nth-child(2)": { animationDelay: "{durations.moderate}" },
400
+ "&:nth-child(3)": { animationDelay: "{durations.slower}" }
401
+ },
402
+ animationStyle: "pulse",
403
+ backgroundColor: "currentcolor",
404
+ blockSize: "0.375em",
405
+ borderRadius: "full",
406
+ inlineSize: "0.375em"
407
+ },
408
+ alignItems: "center",
409
+ display: "inline-flex",
410
+ gap: "0.25em"
411
+ },
412
+ jumpTrigger: {
413
+ insetBlockEnd: dense("{spacing.inset.md}"),
414
+ left: "50%",
415
+ position: "absolute",
416
+ translate: "-50% 0",
417
+ zIndex: "docked"
418
+ },
419
+ root: { position: "relative" },
420
+ typing: {
421
+ alignItems: "center",
422
+ color: "fg.muted",
423
+ display: "flex",
424
+ gap: dense("{spacing.gap.sm}"),
425
+ textStyle: "label.sm"
426
+ },
427
+ viewport: { overscrollBehavior: "contain" }
428
+ },
429
+ className: "conversation",
430
+ jsx: [/^Conversation\.\w+$/u],
431
+ slots: [
432
+ "root",
433
+ "viewport",
434
+ "content",
435
+ "jumpTrigger",
436
+ "typing",
437
+ "dots"
438
+ ]
439
+ });
440
+ //#endregion
441
+ //#region src/message/recipe.ts
442
+ /**
443
+ * Declares the message's slot recipe, which lays out one turn of a conversation.
444
+ *
445
+ * @remarks
446
+ * A turn is the run of messages one person sent together. It has one avatar, one header and a
447
+ * bubble per message. `align="end"` puts the reader's own turns at the end of the line: the row
448
+ * runs the other way and the column aligns its bubbles to the end. A bubble takes the flat looks,
449
+ * because it is read and never pressed. It is at most 80% of the column wide, so the two sides of
450
+ * a conversation are apart. The plain look has no fill and no padding and takes the whole column,
451
+ * for an answer that reads as a document. A bubble has a hairline outline under forced colors,
452
+ * where every fill is replaced.
453
+ */
454
+ /**
455
+ * Class name of the recipe, which a selector across parts reads.
456
+ */
457
+ const CLASS = "message";
458
+ /**
459
+ * Selects the actions of a turn, from a rule on the root.
460
+ */
461
+ const ACTIONS = `.${CLASS}__actions`;
462
+ /**
463
+ * Sizes the message offers.
464
+ */
465
+ const SIZES = [
466
+ "sm",
467
+ "md",
468
+ "lg"
469
+ ];
470
+ /**
471
+ * Maps each size to its steps and text styles.
472
+ */
473
+ const METRICS = {
474
+ lg: {
475
+ gap: "lg",
476
+ inline: "md",
477
+ meta: "label.sm",
478
+ padding: "md",
479
+ text: "body.lg"
480
+ },
481
+ md: {
482
+ gap: "md",
483
+ inline: "sm",
484
+ meta: "label.xs",
485
+ padding: "sm",
486
+ text: "body.md"
487
+ },
488
+ sm: {
489
+ gap: "sm",
490
+ inline: "xs",
491
+ meta: "label.xs",
492
+ padding: "xs",
493
+ text: "body.sm"
494
+ }
495
+ };
496
+ /**
497
+ * Ends of the line a turn can belong to, in the order a documentation page shows them.
498
+ */
499
+ const SIDES = ["start", "end"];
500
+ /**
501
+ * Styles a turn at the start of the line in the neutral palette's subtle look, at the middle size.
502
+ */
503
+ const recipe$1 = defineSlotRecipe({
504
+ base: {
505
+ actions: {
506
+ alignItems: "center",
507
+ display: "flex",
508
+ gap: dense("{spacing.gap.xs}")
509
+ },
510
+ avatar: {
511
+ alignItems: "center",
512
+ display: "flex",
513
+ flexShrink: "0"
514
+ },
515
+ bubble: {
516
+ _highContrast: {
517
+ outlineColor: "CanvasText",
518
+ outlineStyle: "solid",
519
+ outlineWidth: "hairline"
520
+ },
521
+ "&[data-failed]": { colorPalette: "error" },
522
+ borderRadius: "l3",
523
+ maxInlineSize: "80%",
524
+ minInlineSize: "0",
525
+ overflowWrap: "anywhere"
526
+ },
527
+ content: {
528
+ display: "flex",
529
+ flex: "1",
530
+ flexDirection: "column",
531
+ gap: dense("{spacing.gap.xs}"),
532
+ minInlineSize: "0"
533
+ },
534
+ footer: {
535
+ alignItems: "center",
536
+ color: "fg.muted",
537
+ display: "flex",
538
+ flexWrap: "wrap",
539
+ gap: dense("{spacing.gap.sm}")
540
+ },
541
+ header: {
542
+ alignItems: "baseline",
543
+ color: "fg.muted",
544
+ display: "flex",
545
+ flexWrap: "wrap",
546
+ gap: dense("{spacing.gap.sm}")
547
+ },
548
+ root: {
549
+ alignItems: "flex-start",
550
+ display: "flex",
551
+ inlineSize: "full",
552
+ minInlineSize: "0"
553
+ },
554
+ status: {
555
+ "&[data-status=failed]": { color: "fg.error" },
556
+ "&[data-status=read]": {
557
+ color: "colorPalette.fg",
558
+ colorPalette: "primary"
559
+ },
560
+ "& > svg": {
561
+ blockSize: "1em",
562
+ flexShrink: "0",
563
+ inlineSize: "1em"
564
+ },
565
+ alignItems: "center",
566
+ display: "inline-flex",
567
+ gap: "0.25em"
568
+ }
569
+ },
570
+ className: CLASS,
571
+ compoundVariants: [{
572
+ css: { bubble: {
573
+ _highContrast: { outlineStyle: "none" },
574
+ maxInlineSize: "full",
575
+ paddingBlock: "0",
576
+ paddingInline: "0"
577
+ } },
578
+ look: "plain",
579
+ name: "document"
580
+ }],
581
+ defaultVariants: {
582
+ align: "start",
583
+ look: "subtle",
584
+ palette: "neutral",
585
+ reveal: "hover",
586
+ size: "md"
587
+ },
588
+ jsx: [/^Message\.\w+$/u],
589
+ slots: [
590
+ "root",
591
+ "avatar",
592
+ "content",
593
+ "header",
594
+ "bubble",
595
+ "footer",
596
+ "status",
597
+ "actions"
598
+ ],
599
+ staticCss: [{ palette: [...PALETTES] }],
600
+ variants: {
601
+ /**
602
+ * Which end of the line the turn belongs to: the row runs the other way at the end, and the
603
+ * column aligns its bubbles to that end.
604
+ */
605
+ align: onSlots({
606
+ content: axis(SIDES, (side) => ({ alignItems: side === "start" ? "flex-start" : "flex-end" }))(),
607
+ root: axis(SIDES, (side) => ({ flexDirection: side === "start" ? "row" : "row-reverse" }))()
608
+ }),
609
+ look: onSlot("bubble", flatVariants()),
610
+ palette: onSlot("root", paletteVariants()),
611
+ /**
612
+ * When the actions of the turn are visible.
613
+ *
614
+ * @remarks
615
+ * With `hover`, the actions are transparent until a pointer is over the turn or focus is
616
+ * inside it. A coarse pointer cannot hover, so under one they are always opaque. They are in
617
+ * the tab order under both values, so Tab reveals them.
618
+ */
619
+ reveal: {
620
+ always: { actions: { opacity: "1" } },
621
+ hover: {
622
+ actions: {
623
+ _touch: { opacity: "1" },
624
+ opacity: "0",
625
+ transitionDuration: "press",
626
+ transitionProperty: "common",
627
+ transitionTimingFunction: "press"
628
+ },
629
+ root: { [`&:focus-within ${ACTIONS}, &:hover ${ACTIONS}`]: { opacity: "1" } }
630
+ }
631
+ },
632
+ size: onSlots({
633
+ bubble: sizeVariants((size) => ({
634
+ paddingBlock: dense(`{spacing.gap.${METRICS[size].padding}}`),
635
+ paddingInline: dense(`{spacing.inset.${METRICS[size].inline}}`),
636
+ textStyle: METRICS[size].text
637
+ }), SIZES),
638
+ footer: sizeVariants((size) => ({ textStyle: METRICS[size].meta }), SIZES),
639
+ header: sizeVariants((size) => ({ textStyle: METRICS[size].meta }), SIZES),
640
+ root: sizeVariants((size) => ({ gap: dense(`{spacing.gap.${METRICS[size].gap}}`) }), SIZES)
641
+ })
642
+ }
643
+ });
644
+ //#endregion
645
+ //#region src/reactions/recipe.ts
646
+ /**
647
+ * Declares the reactions' slot recipe: a row of reactions under a message, and the choices of the
648
+ * picker that adds one.
649
+ *
650
+ * @remarks
651
+ * Each reaction and each choice is the actions `Button`, so its looks, its pressed state and its
652
+ * focus ring are the button's own. The recipe lays out the row and the choices, and sets the
653
+ * glyphs and counts inside the buttons. The root is a `fieldset`, whose border, margin and
654
+ * padding the recipe removes. A count is set in tabular figures, so a count that changes keeps
655
+ * its width.
656
+ */
657
+ /**
658
+ * Styles a row of reactions 4px apart at the foundation's metrics.
659
+ */
660
+ const recipe = defineSlotRecipe({
661
+ base: {
662
+ choices: {
663
+ display: "flex",
664
+ flexWrap: "wrap",
665
+ gap: dense("{spacing.gap.xs}")
666
+ },
667
+ count: { fontVariantNumeric: "tabular-nums" },
668
+ glyph: {
669
+ display: "inline-flex",
670
+ lineHeight: "1"
671
+ },
672
+ root: {
673
+ alignItems: "center",
674
+ borderWidth: "0",
675
+ display: "flex",
676
+ flexWrap: "wrap",
677
+ gap: dense("{spacing.gap.xs}"),
678
+ margin: "0",
679
+ minInlineSize: "0",
680
+ padding: "0"
681
+ }
682
+ },
683
+ className: "reactions",
684
+ jsx: [/^Reactions\.\w+$/u],
685
+ slots: [
686
+ "root",
687
+ "glyph",
688
+ "count",
689
+ "choices"
690
+ ]
691
+ });
692
+ //#endregion
693
+ export { recipe$3 as a, ROWS as i, recipe$1 as n, recipe$4 as o, recipe$2 as r, recipe as t };
@@ -0,0 +1,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll as t };
@@ -0,0 +1,11 @@
1
+ //#region src/theme.d.ts
2
+ /**
3
+ * Registers every recipe in the package in the preset an application's style compiler installs.
4
+ *
5
+ * @remarks
6
+ * The list is written by hand. `theme.spec.ts` fails when a recipe file is missing from it, so no
7
+ * generator writes it.
8
+ */
9
+ declare const _default: import("@stealthscale/theme/authoring").Preset;
10
+ //#endregion
11
+ export { _default as default };