@monimesl/dot-core 0.1.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1059 @@
1
+ //#region src/view/component.ts
2
+ function defineComponent(manifest) {
3
+ return {
4
+ props: {},
5
+ events: [],
6
+ ...manifest
7
+ };
8
+ }
9
+ function eventProp(event) {
10
+ return `on${event.charAt(0).toUpperCase()}${event.slice(1)}`;
11
+ }
12
+ function isEventProp(name) {
13
+ const letterAfterOn = name.charAt(2);
14
+ return name.startsWith("on") && letterAfterOn >= "A" && letterAfterOn <= "Z";
15
+ }
16
+ function eventName(prop) {
17
+ const name = prop.slice(2);
18
+ return name.charAt(0).toLowerCase() + name.slice(1);
19
+ }
20
+ function componentRegistry(manifests) {
21
+ const registry = {};
22
+ for (const manifest of manifests) {
23
+ if (manifest.name in registry) throw new Error(`Component <${manifest.name}> is defined twice`);
24
+ registry[manifest.name] = manifest;
25
+ }
26
+ return registry;
27
+ }
28
+ //#endregion
29
+ //#region src/view/values.ts
30
+ function toText(value) {
31
+ switch (typeof value) {
32
+ case "string": return value;
33
+ case "number":
34
+ case "boolean":
35
+ case "bigint": return String(value);
36
+ case "object": return value === null ? "" : JSON.stringify(value);
37
+ default: return "";
38
+ }
39
+ }
40
+ function toList(value) {
41
+ if (Array.isArray(value)) return value;
42
+ if (typeof value === "object" && value !== null && Symbol.iterator in value) return Array.from(value);
43
+ return [];
44
+ }
45
+ //#endregion
46
+ //#region src/view/components/amount-input.ts
47
+ const AmountInput = defineComponent({
48
+ name: "AmountInput",
49
+ props: {
50
+ value: "number",
51
+ currency: "string",
52
+ minorUnits: "number",
53
+ unit: ["minor", "major"],
54
+ label: "string",
55
+ placeholder: "string",
56
+ hint: "string",
57
+ error: "string",
58
+ disabled: "boolean"
59
+ },
60
+ events: ["change"],
61
+ children: "none"
62
+ });
63
+ //#endregion
64
+ //#region src/view/components/button.ts
65
+ const Button = defineComponent({
66
+ name: "Button",
67
+ props: {
68
+ variant: ["primary", "secondary"],
69
+ disabled: "boolean",
70
+ loading: "boolean"
71
+ },
72
+ events: ["click"],
73
+ children: "text"
74
+ });
75
+ //#endregion
76
+ //#region src/view/components/options.ts
77
+ const SIZES = [
78
+ "small",
79
+ "medium",
80
+ "large"
81
+ ];
82
+ const SPACES = [
83
+ "none",
84
+ "small",
85
+ "medium",
86
+ "large"
87
+ ];
88
+ const PADDING_PROPS = {
89
+ padding: SPACES,
90
+ paddingTop: SPACES,
91
+ paddingStart: SPACES,
92
+ paddingEnd: SPACES,
93
+ paddingBottom: SPACES
94
+ };
95
+ const ASPECTS = [
96
+ "1:1",
97
+ "4:3",
98
+ "3:2",
99
+ "16:9",
100
+ "3:4",
101
+ "2:3",
102
+ "9:16"
103
+ ];
104
+ const TONES = [
105
+ "default",
106
+ "muted",
107
+ "info",
108
+ "success",
109
+ "warning",
110
+ "danger"
111
+ ];
112
+ const STATUS_TONES = [
113
+ "default",
114
+ "info",
115
+ "success",
116
+ "warning",
117
+ "danger"
118
+ ];
119
+ const ICON_NAMES = [
120
+ "arrow-down",
121
+ "arrow-left",
122
+ "arrow-right",
123
+ "arrow-up",
124
+ "bank",
125
+ "bell",
126
+ "bolt",
127
+ "calendar",
128
+ "card",
129
+ "cart",
130
+ "cash",
131
+ "check",
132
+ "chevron-down",
133
+ "chevron-left",
134
+ "chevron-right",
135
+ "chevron-up",
136
+ "clock",
137
+ "close",
138
+ "copy",
139
+ "download",
140
+ "edit",
141
+ "error",
142
+ "external-link",
143
+ "eye",
144
+ "eye-off",
145
+ "file",
146
+ "gift",
147
+ "globe",
148
+ "grid",
149
+ "headphones",
150
+ "heart",
151
+ "help",
152
+ "history",
153
+ "home",
154
+ "image",
155
+ "info",
156
+ "link",
157
+ "list",
158
+ "location",
159
+ "lock",
160
+ "logout",
161
+ "mail",
162
+ "microphone",
163
+ "minus",
164
+ "mobile",
165
+ "more",
166
+ "music",
167
+ "phone",
168
+ "playlist",
169
+ "plus",
170
+ "qr-code",
171
+ "receipt",
172
+ "refresh",
173
+ "search",
174
+ "send",
175
+ "settings",
176
+ "share",
177
+ "star",
178
+ "success",
179
+ "ticket",
180
+ "trash",
181
+ "upload",
182
+ "user",
183
+ "users",
184
+ "video",
185
+ "wallet",
186
+ "warning",
187
+ "water",
188
+ "wifi"
189
+ ];
190
+ //#endregion
191
+ //#region src/view/components/carousel.ts
192
+ const Carousel = defineComponent({
193
+ name: "Carousel",
194
+ props: {
195
+ autoplay: "boolean",
196
+ interval: "number",
197
+ loop: "boolean",
198
+ indicator: ["dots", "none"],
199
+ gap: SPACES,
200
+ effect: ["slide", "scale"],
201
+ index: "number",
202
+ ...PADDING_PROPS
203
+ },
204
+ events: ["change"],
205
+ children: "elements"
206
+ });
207
+ //#endregion
208
+ //#region src/view/components/chip.ts
209
+ const Chip = defineComponent({
210
+ name: "Chip",
211
+ props: {
212
+ label: "string",
213
+ icon: ICON_NAMES,
214
+ selected: "boolean",
215
+ disabled: "boolean"
216
+ },
217
+ events: ["tap"],
218
+ children: "none"
219
+ });
220
+ //#endregion
221
+ //#region src/view/components/code-input.ts
222
+ const CodeInput = defineComponent({
223
+ name: "CodeInput",
224
+ props: {
225
+ value: "string",
226
+ length: "number",
227
+ label: "string",
228
+ hint: "string",
229
+ error: "string",
230
+ secure: "boolean",
231
+ disabled: "boolean"
232
+ },
233
+ events: ["change", "complete"],
234
+ children: "none"
235
+ });
236
+ //#endregion
237
+ //#region src/view/components/detail-row.ts
238
+ const DetailRow = defineComponent({
239
+ name: "DetailRow",
240
+ props: {
241
+ label: "string",
242
+ value: "string",
243
+ tone: TONES,
244
+ weight: [
245
+ "regular",
246
+ "medium",
247
+ "bold"
248
+ ],
249
+ ...PADDING_PROPS
250
+ },
251
+ children: "none"
252
+ });
253
+ //#endregion
254
+ //#region src/view/components/divider.ts
255
+ const Divider = defineComponent({
256
+ name: "Divider",
257
+ children: "none"
258
+ });
259
+ //#endregion
260
+ //#region src/view/components/empty-state.ts
261
+ const EmptyState = defineComponent({
262
+ name: "EmptyState",
263
+ props: {
264
+ icon: ICON_NAMES,
265
+ title: "string",
266
+ text: "string",
267
+ ...PADDING_PROPS
268
+ },
269
+ children: "elements"
270
+ });
271
+ //#endregion
272
+ //#region src/view/components/feedback.ts
273
+ const Spinner = defineComponent({
274
+ name: "Spinner",
275
+ props: { size: SIZES },
276
+ children: "none"
277
+ });
278
+ const ProgressBar = defineComponent({
279
+ name: "ProgressBar",
280
+ props: { value: "number" },
281
+ children: "none"
282
+ });
283
+ const Notice = defineComponent({
284
+ name: "Notice",
285
+ props: {
286
+ tone: STATUS_TONES,
287
+ title: "string",
288
+ ...PADDING_PROPS
289
+ },
290
+ children: "text"
291
+ });
292
+ const Badge = defineComponent({
293
+ name: "Badge",
294
+ props: { tone: STATUS_TONES },
295
+ children: "text"
296
+ });
297
+ //#endregion
298
+ //#region src/view/components/footer.ts
299
+ const Footer = defineComponent({
300
+ name: "Footer",
301
+ props: PADDING_PROPS,
302
+ children: "elements"
303
+ });
304
+ //#endregion
305
+ //#region src/view/components/grid.ts
306
+ const Grid = defineComponent({
307
+ name: "Grid",
308
+ props: {
309
+ columns: "number",
310
+ gap: SPACES,
311
+ ...PADDING_PROPS
312
+ },
313
+ children: "elements"
314
+ });
315
+ const GridItem = defineComponent({
316
+ name: "GridItem",
317
+ props: {
318
+ label: "string",
319
+ icon: ICON_NAMES,
320
+ image: "string",
321
+ badge: "string"
322
+ },
323
+ events: ["tap"],
324
+ children: "none"
325
+ });
326
+ //#endregion
327
+ //#region src/view/components/icon.ts
328
+ const Icon = defineComponent({
329
+ name: "Icon",
330
+ props: {
331
+ name: ICON_NAMES,
332
+ size: SIZES,
333
+ tone: TONES
334
+ },
335
+ children: "none",
336
+ inline: true
337
+ });
338
+ //#endregion
339
+ //#region src/view/components/image.ts
340
+ const Image = defineComponent({
341
+ name: "Image",
342
+ props: {
343
+ src: "string",
344
+ alt: "string",
345
+ width: "number",
346
+ height: "number",
347
+ fit: ["cover", "contain"],
348
+ shape: [
349
+ "rounded",
350
+ "square",
351
+ "circle"
352
+ ],
353
+ aspect: ASPECTS
354
+ },
355
+ events: ["load", "error"],
356
+ children: "none",
357
+ overrides: [{
358
+ prop: "aspect",
359
+ ignores: "height",
360
+ because: "the aspect sets the height"
361
+ }]
362
+ });
363
+ //#endregion
364
+ //#region src/view/components/input.ts
365
+ const Input = defineComponent({
366
+ name: "Input",
367
+ props: {
368
+ value: "string",
369
+ placeholder: "string",
370
+ label: "string",
371
+ hint: "string",
372
+ error: "string",
373
+ prefix: "string",
374
+ suffix: "string",
375
+ type: [
376
+ "text",
377
+ "number",
378
+ "email",
379
+ "phone",
380
+ "password"
381
+ ],
382
+ maxLength: "number",
383
+ disabled: "boolean"
384
+ },
385
+ events: ["change", "submit"],
386
+ children: "none"
387
+ });
388
+ //#endregion
389
+ //#region src/view/components/link.ts
390
+ const Link = defineComponent({
391
+ name: "Link",
392
+ props: {
393
+ href: "string",
394
+ tone: TONES
395
+ },
396
+ events: ["tap"],
397
+ children: "text",
398
+ inline: true
399
+ });
400
+ //#endregion
401
+ //#region src/view/components/list.ts
402
+ const List = defineComponent({
403
+ name: "List",
404
+ props: {
405
+ size: ["sm", "md"],
406
+ ...PADDING_PROPS
407
+ },
408
+ events: ["endReached"],
409
+ children: "elements"
410
+ });
411
+ const ListItem = defineComponent({
412
+ name: "ListItem",
413
+ props: {
414
+ title: "string",
415
+ subtitle: "string",
416
+ value: "string",
417
+ icon: ICON_NAMES,
418
+ image: "string",
419
+ ...PADDING_PROPS
420
+ },
421
+ events: ["tap"],
422
+ children: "elements"
423
+ });
424
+ //#endregion
425
+ //#region src/view/components/overlays.ts
426
+ const Sheet = defineComponent({
427
+ name: "Sheet",
428
+ props: {
429
+ open: "boolean",
430
+ title: "string",
431
+ showCloseIcon: "boolean",
432
+ ...PADDING_PROPS
433
+ },
434
+ events: ["close"],
435
+ children: "elements"
436
+ });
437
+ const Toast = defineComponent({
438
+ name: "Toast",
439
+ props: {
440
+ message: "string",
441
+ tone: STATUS_TONES,
442
+ duration: "number"
443
+ },
444
+ events: ["hide"],
445
+ children: "none"
446
+ });
447
+ //#endregion
448
+ //#region src/view/components/qr-code.ts
449
+ const QRCode = defineComponent({
450
+ name: "QRCode",
451
+ props: {
452
+ value: "string",
453
+ size: "number",
454
+ label: "string"
455
+ },
456
+ children: "none"
457
+ });
458
+ //#endregion
459
+ //#region src/view/components/select.ts
460
+ const Select = defineComponent({
461
+ name: "Select",
462
+ props: {
463
+ value: "string",
464
+ label: "string",
465
+ placeholder: "string",
466
+ hint: "string",
467
+ error: "string",
468
+ disabled: "boolean"
469
+ },
470
+ events: ["change"],
471
+ children: "elements"
472
+ });
473
+ const Option = defineComponent({
474
+ name: "Option",
475
+ props: {
476
+ value: "string",
477
+ label: "string"
478
+ },
479
+ children: "none"
480
+ });
481
+ //#endregion
482
+ //#region src/view/components/scroll.ts
483
+ const Scroll = defineComponent({
484
+ name: "Scroll",
485
+ props: {
486
+ gap: SPACES,
487
+ snap: [
488
+ "none",
489
+ "start",
490
+ "center"
491
+ ],
492
+ index: "number",
493
+ ...PADDING_PROPS
494
+ },
495
+ events: ["change"],
496
+ children: "elements"
497
+ });
498
+ //#endregion
499
+ //#region src/view/components/skeleton.ts
500
+ const Skeleton = defineComponent({
501
+ name: "Skeleton",
502
+ props: {
503
+ shape: [
504
+ "text",
505
+ "circle",
506
+ "box"
507
+ ],
508
+ lines: "number",
509
+ height: "number"
510
+ },
511
+ children: "none"
512
+ });
513
+ //#endregion
514
+ //#region src/view/components/tabs.ts
515
+ const Tabs = defineComponent({
516
+ name: "Tabs",
517
+ props: {
518
+ value: "string",
519
+ variant: ["underline", "segmented"],
520
+ ...PADDING_PROPS
521
+ },
522
+ events: ["change"],
523
+ children: "elements"
524
+ });
525
+ const Tab = defineComponent({
526
+ name: "Tab",
527
+ props: {
528
+ value: "string",
529
+ label: "string",
530
+ badge: "number"
531
+ },
532
+ children: "none"
533
+ });
534
+ //#endregion
535
+ //#region src/view/components/text.ts
536
+ const Text = defineComponent({
537
+ name: "Text",
538
+ props: {
539
+ variant: [
540
+ "title",
541
+ "body",
542
+ "caption"
543
+ ],
544
+ tone: TONES,
545
+ weight: [
546
+ "regular",
547
+ "medium",
548
+ "bold"
549
+ ],
550
+ align: [
551
+ "start",
552
+ "center",
553
+ "end"
554
+ ],
555
+ maxLines: "number",
556
+ ...PADDING_PROPS
557
+ },
558
+ children: "text",
559
+ inline: true
560
+ });
561
+ //#endregion
562
+ //#region src/view/components/text-area.ts
563
+ const TextArea = defineComponent({
564
+ name: "TextArea",
565
+ props: {
566
+ value: "string",
567
+ placeholder: "string",
568
+ label: "string",
569
+ hint: "string",
570
+ error: "string",
571
+ rows: "number",
572
+ maxLength: "number",
573
+ disabled: "boolean"
574
+ },
575
+ events: ["change"],
576
+ children: "none"
577
+ });
578
+ //#endregion
579
+ //#region src/view/components/toggles.ts
580
+ const Switch = defineComponent({
581
+ name: "Switch",
582
+ props: {
583
+ checked: "boolean",
584
+ label: "string",
585
+ disabled: "boolean"
586
+ },
587
+ events: ["change"],
588
+ children: "none"
589
+ });
590
+ const Checkbox = defineComponent({
591
+ name: "Checkbox",
592
+ props: {
593
+ checked: "boolean",
594
+ label: "string",
595
+ disabled: "boolean"
596
+ },
597
+ events: ["change"],
598
+ children: "none"
599
+ });
600
+ const RadioGroup = defineComponent({
601
+ name: "RadioGroup",
602
+ props: {
603
+ value: "string",
604
+ label: "string",
605
+ disabled: "boolean"
606
+ },
607
+ events: ["change"],
608
+ children: "elements"
609
+ });
610
+ const Radio = defineComponent({
611
+ name: "Radio",
612
+ props: {
613
+ value: "string",
614
+ label: "string",
615
+ disabled: "boolean"
616
+ },
617
+ children: "none"
618
+ });
619
+ //#endregion
620
+ //#region src/view/components/view.ts
621
+ const View = defineComponent({
622
+ name: "View",
623
+ props: {
624
+ gap: SPACES,
625
+ direction: ["column", "row"],
626
+ align: [
627
+ "stretch",
628
+ "start",
629
+ "center",
630
+ "end"
631
+ ],
632
+ justify: [
633
+ "start",
634
+ "center",
635
+ "end",
636
+ "between"
637
+ ],
638
+ wrap: "boolean",
639
+ grow: "boolean",
640
+ ...PADDING_PROPS,
641
+ variant: ["plain", "card"]
642
+ },
643
+ events: ["tap"],
644
+ children: "elements"
645
+ });
646
+ //#endregion
647
+ //#region src/view/components/index.ts
648
+ const builtinComponents = {
649
+ AmountInput,
650
+ Badge,
651
+ Button,
652
+ Carousel,
653
+ Checkbox,
654
+ Chip,
655
+ CodeInput,
656
+ DetailRow,
657
+ Divider,
658
+ EmptyState,
659
+ Footer,
660
+ Grid,
661
+ GridItem,
662
+ Icon,
663
+ Image,
664
+ Input,
665
+ Link,
666
+ List,
667
+ ListItem,
668
+ Notice,
669
+ Option,
670
+ ProgressBar,
671
+ QRCode,
672
+ Radio,
673
+ RadioGroup,
674
+ Scroll,
675
+ Select,
676
+ Sheet,
677
+ Skeleton,
678
+ Spinner,
679
+ Switch,
680
+ Tab,
681
+ Tabs,
682
+ Text,
683
+ TextArea,
684
+ Toast,
685
+ View
686
+ };
687
+ const builtinRegistry = componentRegistry(Object.values(builtinComponents));
688
+ //#endregion
689
+ //#region src/source/location.ts
690
+ function createLocator(source) {
691
+ const lineStarts = [0];
692
+ for (let index = 0; index < source.length; index++) if (source[index] === "\n") lineStarts.push(index + 1);
693
+ return (offset) => {
694
+ let low = 0;
695
+ let high = lineStarts.length - 1;
696
+ while (low < high) {
697
+ const middle = Math.floor((low + high + 1) / 2);
698
+ if (lineStarts[middle] <= offset) low = middle;
699
+ else high = middle - 1;
700
+ }
701
+ return {
702
+ line: low + 1,
703
+ column: offset - lineStarts[low] + 1,
704
+ offset
705
+ };
706
+ };
707
+ }
708
+ function locationAt(source, offset) {
709
+ return createLocator(source)(offset);
710
+ }
711
+ function locatedMessage(message, file, location) {
712
+ const where = [
713
+ file,
714
+ location?.line,
715
+ location?.column
716
+ ].filter((part) => part !== void 0).join(":");
717
+ return where ? `${where}: ${message}` : message;
718
+ }
719
+ //#endregion
720
+ //#region src/source/error.ts
721
+ var SourceError = class extends Error {
722
+ reason;
723
+ file;
724
+ loc;
725
+ constructor(reason, file, location) {
726
+ super(locatedMessage(reason, file, location));
727
+ this.reason = reason;
728
+ this.file = file;
729
+ this.loc = location;
730
+ }
731
+ };
732
+ //#endregion
733
+ //#region src/event/emitter.ts
734
+ var EventEmitter = class {
735
+ #listeners = /* @__PURE__ */ new Map();
736
+ on(name, listener) {
737
+ const listeners = this.#listeners.get(name) ?? /* @__PURE__ */ new Set();
738
+ this.#listeners.set(name, listeners);
739
+ listeners.add(listener);
740
+ return () => listeners.delete(listener);
741
+ }
742
+ emit(name, ...args) {
743
+ this.#listeners.get(name)?.forEach((listener) => listener(...args));
744
+ }
745
+ };
746
+ //#endregion
747
+ //#region src/event/core.ts
748
+ function createEvent(type, detail = {}, data = {}) {
749
+ return {
750
+ type,
751
+ detail,
752
+ data
753
+ };
754
+ }
755
+ //#endregion
756
+ //#region src/host/host.ts
757
+ function hostTransport() {
758
+ const transport = globalThis.__hostTransport;
759
+ if (!transport) throw new Error("No Dot host found: `globalThis.__hostTransport` is not set. Run the dot in the Dash app, or in the simulator with `dotctl dev`.");
760
+ return transport;
761
+ }
762
+ //#endregion
763
+ //#region src/host/context.ts
764
+ const DEFAULT_SYSTEM_CONTEXT = {
765
+ scheme: "light",
766
+ appState: "active"
767
+ };
768
+ //#endregion
769
+ //#region src/host/calls.ts
770
+ var HostError = class extends Error {
771
+ name = "HostError";
772
+ code;
773
+ constructor(code, message) {
774
+ super(message);
775
+ this.code = code;
776
+ }
777
+ };
778
+ let connectedCaller = null;
779
+ function connectHost(caller) {
780
+ connectedCaller = caller;
781
+ }
782
+ function callHost(method, params, options = {}) {
783
+ if (!connectedCaller) {
784
+ const error = new HostError("unsupported", `Can't run "${method}" here: call Dash from the dot's logic`);
785
+ return createHostRequest(Promise.reject(error));
786
+ }
787
+ return connectedCaller(method, params, options);
788
+ }
789
+ function createHostRequest(promise, cancel = () => {}) {
790
+ const request = promise;
791
+ request.cancel = cancel;
792
+ return request;
793
+ }
794
+ //#endregion
795
+ //#region src/host/permissions.ts
796
+ const PERMISSIONS = ["account"];
797
+ function isPermission(value) {
798
+ return PERMISSIONS.includes(value);
799
+ }
800
+ //#endregion
801
+ //#region src/host/files.ts
802
+ const DOT_FILE_PATH_MAX_LENGTH = 512;
803
+ const MAX_NAME_LENGTH = 255;
804
+ function dotFilePathProblem(path, { allowRoot = false } = {}) {
805
+ if (path === "") return allowRoot ? null : "A path is needed, such as \"receipts/42.pdf\"";
806
+ if (path.length > 512) return `"${path.slice(0, 40)}…" is longer than 512 characters`;
807
+ if (path.startsWith("/")) return `"${path}" starts with "/". Start paths without it, such as "receipts/42.pdf"`;
808
+ if ([...path].some((char) => char === "\\" || char.charCodeAt(0) < 32)) return `"${path}" has a backslash or another character paths can't use`;
809
+ for (const name of path.split("/")) {
810
+ if (name === "" || name === "." || name === "..") return `"${path}" has an empty, "." or ".." part. Name each folder, such as "receipts/42.pdf"`;
811
+ if (name.length > MAX_NAME_LENGTH) return `"${path}" has a name longer than ${MAX_NAME_LENGTH} characters`;
812
+ }
813
+ return null;
814
+ }
815
+ //#endregion
816
+ //#region src/host/network.ts
817
+ const LABEL = "[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?";
818
+ const NETWORK_HOST_PATTERN = new RegExp(`^(?:\\*\\.${LABEL}(?:\\.${LABEL})+|${LABEL}(?:\\.${LABEL})*)$`);
819
+ const NETWORK_HOST_MAX_LENGTH = 253;
820
+ function isNetworkHost(value) {
821
+ return value.length <= 253 && NETWORK_HOST_PATTERN.test(value);
822
+ }
823
+ function allowsHost(hosts, host) {
824
+ const name = host.toLowerCase().replace(/\.$/, "");
825
+ return hosts.some((pattern) => pattern.startsWith("*.") ? name.endsWith(pattern.slice(1)) : name === pattern);
826
+ }
827
+ //#endregion
828
+ //#region src/version/semantic-version.ts
829
+ const SEMVER_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
830
+ function isSemanticVersion(value) {
831
+ return typeof value === "string" && SEMVER_PATTERN.test(value);
832
+ }
833
+ function majorVersion(version) {
834
+ return parseVersion(version).major;
835
+ }
836
+ function isVersionAtLeast(version, minimum) {
837
+ return compareVersions(version, minimum) >= 0;
838
+ }
839
+ function compareVersions(left, right) {
840
+ const leftVersion = parseVersion(left);
841
+ const rightVersion = parseVersion(right);
842
+ const differences = [
843
+ leftVersion.major - rightVersion.major,
844
+ leftVersion.minor - rightVersion.minor,
845
+ leftVersion.patch - rightVersion.patch
846
+ ];
847
+ for (const difference of differences) if (difference !== 0) return difference;
848
+ return comparePrereleases(leftVersion.prerelease, rightVersion.prerelease);
849
+ }
850
+ function parseVersion(version) {
851
+ const match = SEMVER_PATTERN.exec(version);
852
+ if (!match) throw new Error(`"${version}" is not a semantic version`);
853
+ const [, major, minor, patch, prerelease] = match;
854
+ return {
855
+ major: Number(major),
856
+ minor: Number(minor),
857
+ patch: Number(patch),
858
+ prerelease: prerelease === void 0 ? [] : prerelease.split(".")
859
+ };
860
+ }
861
+ function comparePrereleases(left, right) {
862
+ if (left.length === 0 || right.length === 0) return right.length - left.length;
863
+ const shared = Math.min(left.length, right.length);
864
+ for (let index = 0; index < shared; index++) {
865
+ const order = compareIdentifiers(left[index], right[index]);
866
+ if (order !== 0) return order;
867
+ }
868
+ return left.length - right.length;
869
+ }
870
+ function compareIdentifiers(left, right) {
871
+ const leftIsNumber = /^\d+$/.test(left);
872
+ const rightIsNumber = /^\d+$/.test(right);
873
+ if (leftIsNumber && rightIsNumber) return Number(left) - Number(right);
874
+ if (leftIsNumber) return -1;
875
+ if (rightIsNumber) return 1;
876
+ if (left < right) return -1;
877
+ if (left > right) return 1;
878
+ return 0;
879
+ }
880
+ //#endregion
881
+ //#region src/host/react.ts
882
+ const REACT_HOST_PATH = "/__dot/react/";
883
+ const REACT_HOST_MODULES = {
884
+ react: "react.js",
885
+ "react/jsx-runtime": "react-jsx-runtime.js",
886
+ "react-dom": "react-dom.js",
887
+ "react-dom/client": "react-dom-client.js"
888
+ };
889
+ function reactHostUrl(dotReactVersion, file) {
890
+ return `${REACT_HOST_PATH}${majorVersion(dotReactVersion)}/${file}`;
891
+ }
892
+ function isReactCompatible(hostVersion, dotVersion) {
893
+ return majorVersion(hostVersion) === majorVersion(dotVersion) && isVersionAtLeast(hostVersion, dotVersion);
894
+ }
895
+ function newestReactOfMajor(versions, major) {
896
+ return versions.filter((version) => majorVersion(version) === major).sort(compareVersions).at(-1);
897
+ }
898
+ //#endregion
899
+ //#region src/protocol/transport.ts
900
+ function createAdaptorTransport(adapter) {
901
+ return {
902
+ post: (message) => adapter.postMessage(message),
903
+ listen(listener) {
904
+ const onMessage = (event) => listener(event.data);
905
+ adapter.addEventListener("message", onMessage);
906
+ return () => adapter.removeEventListener("message", onMessage);
907
+ }
908
+ };
909
+ }
910
+ function createTransportPair() {
911
+ const firstListeners = /* @__PURE__ */ new Set();
912
+ const secondListeners = /* @__PURE__ */ new Set();
913
+ const createSide = (ownListeners, otherListeners) => ({
914
+ post: (message) => {
915
+ const copy = JSON.parse(JSON.stringify(message));
916
+ otherListeners.forEach((listener) => listener(copy));
917
+ },
918
+ listen(listener) {
919
+ ownListeners.add(listener);
920
+ return () => ownListeners.delete(listener);
921
+ }
922
+ });
923
+ return [createSide(firstListeners, secondListeners), createSide(secondListeners, firstListeners)];
924
+ }
925
+ const PAGE_HOOKS = Object.keys({
926
+ onLoad: true,
927
+ onShow: true,
928
+ onHide: true,
929
+ onUnload: true
930
+ });
931
+ //#endregion
932
+ //#region src/page/navigation.ts
933
+ const MAX_STACK_DEPTH = 8;
934
+ const PAGE_ID = /^[A-Za-z0-9_-]+(?:\/[A-Za-z0-9_-]+)*$/;
935
+ function isPageId(value) {
936
+ return PAGE_ID.test(value);
937
+ }
938
+ var NavigationStack = class {
939
+ limit;
940
+ #pages = [];
941
+ #nextInstanceId = 1;
942
+ constructor(limit = 8) {
943
+ this.limit = limit;
944
+ }
945
+ get pages() {
946
+ return this.#pages;
947
+ }
948
+ get top() {
949
+ return this.#pages.at(-1);
950
+ }
951
+ apply(navigation) {
952
+ switch (navigation.action) {
953
+ case "push":
954
+ if (this.#pages.length >= this.limit) return false;
955
+ break;
956
+ case "replace":
957
+ this.#pages.pop();
958
+ break;
959
+ case "reset":
960
+ this.#pages = [];
961
+ break;
962
+ case "back": {
963
+ const count = Math.min(navigation.delta, this.#pages.length - 1);
964
+ if (count < 1) return false;
965
+ this.#pages = this.#pages.slice(0, -count);
966
+ return true;
967
+ }
968
+ }
969
+ const { page, options } = navigation;
970
+ this.#pages = [...this.#pages, {
971
+ instanceId: this.#nextInstanceId++,
972
+ page,
973
+ options
974
+ }];
975
+ return true;
976
+ }
977
+ };
978
+ //#endregion
979
+ //#region src/page/state.ts
980
+ function applyChanges(state, changes) {
981
+ const next = { ...state };
982
+ for (const [key, value] of Object.entries(changes)) if (value !== void 0) next[key] = value;
983
+ return next;
984
+ }
985
+ //#endregion
986
+ //#region src/page/bars.ts
987
+ const HEX_COLOR = /^#[0-9a-fA-F]{6}$/;
988
+ function checkNavigationBar(options) {
989
+ const { title, hidden, backgroundColor, textColor } = options;
990
+ if (title !== void 0 && typeof title !== "string") throw new TypeError("The navigation bar's title must be text");
991
+ if (hidden !== void 0 && typeof hidden !== "boolean") throw new TypeError("The navigation bar's `hidden` must be true or false");
992
+ for (const [name, color] of Object.entries({
993
+ backgroundColor,
994
+ textColor
995
+ })) if (color !== void 0 && (typeof color !== "string" || !HEX_COLOR.test(color))) throw new TypeError(`The navigation bar's ${name} must be a color such as "#1A73E8"`);
996
+ }
997
+ function checkTabBar(options) {
998
+ if (options.hidden !== void 0 && typeof options.hidden !== "boolean") throw new TypeError("The tab bar's `hidden` must be true or false");
999
+ }
1000
+ function checkConfigs(configs) {
1001
+ checkNavigationBar(configs.navigationBar ?? {});
1002
+ checkTabBar(configs.tabBar ?? {});
1003
+ }
1004
+ function mergeConfigs(...configs) {
1005
+ const bars = {
1006
+ navigationBar: {},
1007
+ tabBar: {}
1008
+ };
1009
+ for (const config of configs) {
1010
+ bars.navigationBar = {
1011
+ ...bars.navigationBar,
1012
+ ...config?.navigationBar
1013
+ };
1014
+ bars.tabBar = {
1015
+ ...bars.tabBar,
1016
+ ...config?.tabBar
1017
+ };
1018
+ }
1019
+ return bars;
1020
+ }
1021
+ //#endregion
1022
+ //#region src/messageChannel.ts
1023
+ var MessageChannel = class {
1024
+ #transport;
1025
+ #handlers = /* @__PURE__ */ new Map();
1026
+ constructor(transport) {
1027
+ this.#transport = transport;
1028
+ }
1029
+ send(type, payload) {
1030
+ this.#transport.post({
1031
+ type,
1032
+ payload
1033
+ });
1034
+ }
1035
+ handle(type, handler) {
1036
+ const previous = this.#handlers.get(type);
1037
+ this.#handlers.set(type, handler);
1038
+ return previous;
1039
+ }
1040
+ listen(onError) {
1041
+ return this.#transport.listen((rawMessage) => {
1042
+ const message = rawMessage;
1043
+ const handler = this.#handlers.get(message.type);
1044
+ if (!handler) {
1045
+ onError(/* @__PURE__ */ new Error(`No handler for message "${message.type}"`), message);
1046
+ return;
1047
+ }
1048
+ try {
1049
+ handler(message.payload);
1050
+ } catch (error) {
1051
+ onError(error, message);
1052
+ }
1053
+ });
1054
+ }
1055
+ };
1056
+ //#endregion
1057
+ export { ASPECTS, AmountInput, Badge, Button, Carousel, Checkbox, Chip, CodeInput, DEFAULT_SYSTEM_CONTEXT, DOT_FILE_PATH_MAX_LENGTH, DetailRow, Divider, EmptyState, EventEmitter, Footer, Grid, GridItem, HostError, ICON_NAMES, Icon, Image, Input, Link, List, ListItem, MAX_STACK_DEPTH, MessageChannel, NETWORK_HOST_MAX_LENGTH, NETWORK_HOST_PATTERN, NavigationStack, Notice, Option, PADDING_PROPS, PAGE_HOOKS, PERMISSIONS, ProgressBar, QRCode, REACT_HOST_MODULES, REACT_HOST_PATH, Radio, RadioGroup, SEMVER_PATTERN, SIZES, SPACES, STATUS_TONES, Scroll, Select, Sheet, Skeleton, SourceError, Spinner, Switch, TONES, Tab, Tabs, Text, TextArea, Toast, View, allowsHost, applyChanges, builtinComponents, builtinRegistry, callHost, checkConfigs, checkNavigationBar, checkTabBar, compareVersions, componentRegistry, connectHost, createAdaptorTransport, createEvent, createHostRequest, createLocator, createTransportPair, defineComponent, dotFilePathProblem, eventName, eventProp, hostTransport, isEventProp, isNetworkHost, isPageId, isPermission, isReactCompatible, isSemanticVersion, isVersionAtLeast, locatedMessage, locationAt, majorVersion, mergeConfigs, newestReactOfMajor, reactHostUrl, toList, toText };
1058
+
1059
+ //# sourceMappingURL=index.js.map