hotwire-native-dev-tools 0.1.0-rc.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,1567 @@
1
+ var $ = Object.defineProperty;
2
+ var x = (i) => {
3
+ throw TypeError(i);
4
+ };
5
+ var I = (i, t, e) => t in i ? $(i, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : i[t] = e;
6
+ var l = (i, t, e) => I(i, typeof t != "symbol" ? t + "" : t, e), F = (i, t, e) => t.has(i) || x("Cannot " + e);
7
+ var b = (i, t, e) => (F(i, t, "read from private field"), e ? e.call(i) : t.get(i)), g = (i, t, e) => t.has(i) ? x("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(i) : t.set(i, e);
8
+ const H = () => `
9
+ :host {
10
+ all: initial;
11
+ font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
12
+ --font-size: 16px;
13
+ font-size: var(--font-size) !important;
14
+ }
15
+
16
+ * {
17
+ box-sizing: border-box;
18
+ }
19
+
20
+ p, span, h1, h2, h3, h4, h5, h6, div, a, button, input, label {
21
+ font-size: inherit;
22
+ }
23
+
24
+
25
+ a {
26
+ color: white;
27
+ }
28
+
29
+ h1, h2, h3, h4, h5, h6 {
30
+ margin: 0;
31
+ }
32
+
33
+ button {
34
+ user-select: none;
35
+ -webkit-user-select: none;
36
+ -webkit-tap-highlight-color: transparent;
37
+ }
38
+
39
+ input {
40
+ display: block;
41
+ padding: 3px;
42
+ box-sizing: border-box;
43
+ border: 1px solid #ccc;
44
+ border-radius: 4px;
45
+ }
46
+
47
+ input:focus {
48
+ outline: none;
49
+ }
50
+
51
+ .btn-icon {
52
+ background-color: transparent;
53
+ border: none;
54
+ color: white;
55
+ display: flex;
56
+ align-items: center;
57
+ justify-content: center;
58
+ padding: 0.5em;
59
+ height: 100%;
60
+ }
61
+
62
+ .btn-icon svg {
63
+ width: 1rem;
64
+ height: 1rem;
65
+ fill: white;
66
+ }
67
+
68
+ /* Dropdown */
69
+ .dropdown-content {
70
+ display: none;
71
+ position: absolute;
72
+ z-index: 1000;
73
+ background: white;
74
+ border: 1px solid #ddd;
75
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
76
+ min-width: 200px;
77
+ max-width: 300px;
78
+ opacity: 0;
79
+ transform: scale(0.9);
80
+ transition: opacity 0.2s, transform 0.2s;
81
+ user-select: none;
82
+ -webkit-user-select: none;
83
+ }
84
+
85
+ .dropdown-content.dropdown-open {
86
+ display: block;
87
+ opacity: 1;
88
+ transform: scale(1);
89
+ pointer-events: auto;
90
+ }
91
+
92
+ .dropdown-content > * {
93
+ padding: 12px;
94
+ }
95
+
96
+ .dropdown-content button,
97
+ .dropdown-content label {
98
+ color: black;
99
+ width: 100%;
100
+ border: none;
101
+ display: flex;
102
+ align-items: center;
103
+ }
104
+
105
+ .dropdown-content button:not(:first-child) {
106
+ border-top: 1px solid #cecdcd;
107
+ }
108
+
109
+ .settings-dropdown {
110
+ right: 0;
111
+ top: 2rem;
112
+ }
113
+
114
+ /* Floating bubble */
115
+ #floating-bubble {
116
+ display: flex;
117
+ background-color: hsl(0deg 0% 0% / 60%);
118
+ border-radius: 50%;
119
+ touch-action: none;
120
+ user-select: none;
121
+ z-index: 10000000;
122
+ position: fixed;
123
+ top: 10px;
124
+ left: 10px;
125
+
126
+ /* Remove tap highlight on iOS */
127
+ -webkit-user-select: none;
128
+ -webkit-tap-highlight-color: transparent;
129
+
130
+ /* Keep width, height, and border in sync with bubbleSize in FloatingBubble.js */
131
+ width: 4.75rem;
132
+ height: 4.75rem;
133
+ border: 0.3rem solid rgba(136, 136, 136, 0.5);
134
+ }
135
+
136
+ #floating-bubble svg {
137
+ transform: scale(0.6);
138
+ fill: #b1b1b1;
139
+ }
140
+
141
+ #floating-bubble .animation-container {
142
+ position: absolute;
143
+ top: 0;
144
+ left: 0;
145
+ width: 100%;
146
+ height: 100%;
147
+ pointer-events: none;
148
+ z-index: 1;
149
+ }
150
+
151
+ #floating-bubble .error-border {
152
+ position: absolute;
153
+ top: -30px;
154
+ left: -30px;
155
+ width: calc(100% + 60px);
156
+ height: calc(100% + 60px);
157
+ border-radius: 50%;
158
+ }
159
+
160
+ #floating-bubble .error-border circle {
161
+ transform-origin: center;
162
+ transform: rotate(-90deg);
163
+ }
164
+
165
+ #floating-bubble .error-border circle.animate {
166
+ animation: error-border-progress 0.8s ease-out forwards;
167
+ }
168
+
169
+ #floating-bubble .animation-container.fade-out {
170
+ animation: fade-out 0.4s ease-out forwards;
171
+ }
172
+
173
+ /*
174
+ The "stroke-dasharray" defines the start of the animation
175
+ The value is calculated by the formula: 2 * Math.PI * radius
176
+ In this case: 2 * Math.PI * 90 = 565
177
+ */
178
+ @keyframes error-border-progress {
179
+ from {
180
+ stroke-dashoffset: 565;
181
+ }
182
+ to {
183
+ stroke-dashoffset: 0;
184
+ }
185
+ }
186
+
187
+ @keyframes fade-out {
188
+ from {
189
+ opacity: 1;
190
+ }
191
+ to {
192
+ opacity: 0;
193
+ }
194
+ }
195
+
196
+ /* Bottom Sheet */
197
+ .bottom-sheet {
198
+ position: fixed;
199
+ bottom: 0;
200
+ left: 0;
201
+ width: 100%;
202
+ max-height: 100%;
203
+ display: flex;
204
+ opacity: 0;
205
+ pointer-events: none;
206
+ align-items: center;
207
+ flex-direction: column;
208
+ justify-content: flex-end;
209
+ transition: 0.1s linear;
210
+ z-index: 10000001;
211
+ }
212
+
213
+ .bottom-sheet .sheet-overlay.active {
214
+ position: fixed;
215
+ top: 0;
216
+ left: 0;
217
+ z-index: -1;
218
+ width: 100%;
219
+ height: 100%;
220
+ opacity: 0.2;
221
+ background: #000;
222
+ }
223
+
224
+ .bottom-sheet .content {
225
+ width: 100%;
226
+ height: 40vh;
227
+ position: relative;
228
+ color: white;
229
+ transform: translateY(100%);
230
+ border-radius: 12px 12px 0 0;
231
+ box-shadow: 0 10px 20px rgba(0, 0, 0, 0.03);
232
+ transition: 0.3s ease;
233
+ overflow-y: hidden;
234
+ }
235
+
236
+ .bottom-sheet .log-entry {
237
+ border-bottom: 1px solid #6c6c6c;
238
+ white-space: collapse;
239
+ }
240
+
241
+ .bottom-sheet .log-entry-icon svg {
242
+ width: 1rem;
243
+ fill: white;
244
+ }
245
+
246
+ .bottom-sheet.show {
247
+ opacity: 1;
248
+ pointer-events: auto;
249
+ }
250
+
251
+ .bottom-sheet.show .content {
252
+ transform: translateY(0%);
253
+ }
254
+
255
+ .bottom-sheet.dragging .content {
256
+ transition: none;
257
+ }
258
+ .bottom-sheet.fullscreen .content {
259
+ border-radius: 0;
260
+ overflow-y: hidden;
261
+ }
262
+
263
+ .bottom-sheet .log-entry-message.warn {
264
+ color: #f39c12;
265
+ }
266
+
267
+ .bottom-sheet .log-entry-message.error {
268
+ color: #ED4E4C;
269
+ }
270
+
271
+ .bottom-sheet .tab-action-bar {
272
+ display: none;
273
+ justify-content: space-between;
274
+ background-color: rgb(49, 54, 63);
275
+ padding: 0.5rem;
276
+ padding-right: 1rem;
277
+ padding-left: 1rem;
278
+ }
279
+
280
+ .bottom-sheet .tab-action-bar.active {
281
+ display: flex;
282
+ }
283
+
284
+ .bottom-sheet .tab-action-bar button:active svg {
285
+ fill: #6c6c6c;
286
+ }
287
+
288
+ .bottom-sheet .btn-clear-tab,
289
+ .bottom-sheet .btn-reload-tab {
290
+ margin-left: auto;
291
+ }
292
+
293
+ /* Bottom Sheet Tabs */
294
+ .tablist {
295
+ display: flex;
296
+ overflow: hidden;
297
+ background-color: #EEEEEE;
298
+ }
299
+
300
+ .tablist .tablink {
301
+ color: black;
302
+ background-color: inherit;
303
+ width: 100%;
304
+ border: none;
305
+ outline: none;
306
+ padding: 14px 16px;
307
+ font-size: 0.8em;
308
+ }
309
+
310
+ .tablist .tablink.active {
311
+ background-color: #31363f;
312
+ color: white;
313
+ }
314
+
315
+ .tab-contents {
316
+ height: 100%;
317
+ overflow: scroll;
318
+ }
319
+
320
+ .outer-tab-content {
321
+ display: none;
322
+ border-top: none;
323
+ height: 100%;
324
+ overflow: scroll;
325
+ background-color: hsl(0deg 0% 0% / 80%);
326
+ backdrop-filter: blur(3px) saturate(100%);
327
+ -webkit-backdrop-filter: blur(3px) saturate(100%);
328
+ padding-bottom: 7em;
329
+ }
330
+ .outer-tab-content.active {
331
+ display: block;
332
+ }
333
+ .inner-tab-content {
334
+ padding: 1rem;
335
+ overflow-x: auto;
336
+ white-space: nowrap;
337
+ }
338
+ .single-tab-content .inner-tab-content {
339
+ white-space: normal;
340
+ }
341
+
342
+ .tab-empty-content {
343
+ display: flex;
344
+ justify-content: center;
345
+ flex-direction: column;
346
+ align-items: center;
347
+ padding: 1em;
348
+ }
349
+
350
+ .bottom-sheet .tablink-dropdown {
351
+ border: none;
352
+ outline: none;
353
+ display: flex;
354
+ align-items: center;
355
+ justify-content: center;
356
+ padding: 0.5em;
357
+ width: 2rem;
358
+ }
359
+
360
+ .bottom-sheet .tablink-dropdown svg {
361
+ width: 1rem;
362
+ height: 1rem;
363
+ fill: #121212;
364
+ }
365
+
366
+ .bottom-sheet .tablink-dropdown:active {
367
+ background-color: #31363f;
368
+ }
369
+ .bottom-sheet .tablink-dropdown:active svg {
370
+ fill: white;
371
+ }
372
+
373
+ /* Bottom Sheet Stack Visualization */
374
+ .bottom-sheet .viewstack-card {
375
+ border: 1px solid #ddd;
376
+ border-radius: 8px;
377
+ padding: 10px;
378
+ margin: 10px 0;
379
+ background: white;
380
+ color: black;
381
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
382
+ overflow: auto;
383
+ }
384
+
385
+ .bottom-sheet .viewstack-card.current-view {
386
+ border: 2px solid #f1f208;
387
+ }
388
+
389
+ .bottom-sheet .tab-container {
390
+ background: #EEEEEE;
391
+ }
392
+
393
+ .bottom-sheet .main-view {
394
+ border-color: #4e6080;
395
+ background: #31363F;
396
+ }
397
+
398
+ .bottom-sheet .hotwire-view {
399
+ border-color: #6db1b5;
400
+ background: #76ABAE;
401
+ }
402
+
403
+ .bottom-sheet .child-container {
404
+ margin-left: 30px;
405
+ position: relative;
406
+ }
407
+
408
+ .bottom-sheet .child-container::before {
409
+ content: "";
410
+ position: absolute;
411
+ left: -15px;
412
+ top: 0;
413
+ bottom: 0;
414
+ width: 2px;
415
+ background: #ddd;
416
+ }
417
+
418
+ .bottom-sheet .view-title {
419
+ display: flex;
420
+ align-items: center;
421
+ gap: 0.5em;
422
+
423
+ font-weight: bold;
424
+ color: white;
425
+ margin-bottom: 5px;
426
+ }
427
+
428
+ .bottom-sheet .view-title-details {
429
+ color: #efefef;
430
+ font-size: 0.6em;
431
+ }
432
+
433
+ .bottom-sheet .tab-container .view-title-details {
434
+ color: #6c6c6c;
435
+ }
436
+
437
+ .bottom-sheet .view-url {
438
+ color: #000000;
439
+ font-size: 0.9em;
440
+ margin-top: 5px;
441
+ word-break: break-all;
442
+ }
443
+
444
+ .bottom-sheet .non-identified-view {
445
+ background: #EEEEEE;
446
+ }
447
+ .bottom-sheet .non-identified-view .view-title-details {
448
+ color: #6c6c6c;
449
+ }
450
+
451
+ .bottom-sheet .viewstack-card pre {
452
+ font-size: 0.8em;
453
+ }
454
+
455
+ /* Bottom Sheet Bridge Components */
456
+ .bottom-sheet .bridge-components-collapse-btn {
457
+ background: none;
458
+ border: none;
459
+ color: white;
460
+ width: 100%;
461
+ text-align: left;
462
+ border-bottom: 1px solid #eee;
463
+ padding: 0.5em 0em;
464
+ font-size: 0.9em;
465
+ }
466
+
467
+ .tab-content-bridge-components {
468
+ display: grid;
469
+ grid-template-columns: 1fr 1fr;
470
+ gap: 10px;
471
+ padding: 0.5em 0em;
472
+ }
473
+
474
+ .tab-content-bridge-components .bridge-component {
475
+ position: relative;
476
+ padding-left: 15px;
477
+ }
478
+
479
+ .tab-content-bridge-components .bridge-component::before {
480
+ content: "•";
481
+ color: #eee;
482
+ font-size: 1.5em;
483
+ position: absolute;
484
+ left: 0;
485
+ top: 50%;
486
+ transform: translateY(-50%);
487
+ }
488
+ .tab-content-bridge-components .bridge-component.connected::before {
489
+ color: #5cff00
490
+ }
491
+
492
+ /* Collapsibles */
493
+ .collapse-target {
494
+ display: none;
495
+ }
496
+
497
+ .collapse-target.active {
498
+ display: block;
499
+ }
500
+
501
+ .collapse:not(.no-chevron):after {
502
+ content: '\\25BC';
503
+ font-size: 13px;
504
+ color: #777;
505
+ float: right;
506
+ margin-left: 5px;
507
+ }
508
+
509
+ .collapse:not(.no-chevron).active:after {
510
+ content: "\\25B2";
511
+ }
512
+
513
+ /* Custom checkbox toggles */
514
+ .toggle {
515
+ display: inline-block;
516
+ user-select: none;
517
+ }
518
+
519
+ .toggle-switch {
520
+ display: inline-block;
521
+ background: #ccc;
522
+ border-radius: 16px;
523
+ width: 29px;
524
+ height: 16px;
525
+ position: relative;
526
+ vertical-align: middle;
527
+ transition: background 0.15s;
528
+ }
529
+ .toggle-switch:before,
530
+ .toggle-switch:after {
531
+ content: "";
532
+ }
533
+ .toggle-switch:before {
534
+ display: block;
535
+ background: linear-gradient(to bottom, #fff 0%, #eee 100%);
536
+ border-radius: 50%;
537
+ width: 12px;
538
+ height: 12px;
539
+ position: absolute;
540
+ top: 2px;
541
+ left: 2px;
542
+ transition: left 0.15s;
543
+ }
544
+ .toggle-checkbox:checked + .toggle-switch {
545
+ background: #56c080;
546
+ }
547
+ .toggle-checkbox:checked + .toggle-switch:before {
548
+ left: 15px;
549
+ }
550
+
551
+ .toggle-checkbox {
552
+ position: absolute;
553
+ visibility: hidden;
554
+ }
555
+
556
+ .toggle-label {
557
+ position: relative;
558
+ margin-left: 3px;
559
+ top: 2px;
560
+ }
561
+
562
+ /* Utility classes */
563
+ .d-none {
564
+ display: none;
565
+ }
566
+
567
+ .text-center {
568
+ text-align: center;
569
+ }
570
+
571
+ .text-ellipsis {
572
+ text-overflow: ellipsis;
573
+ white-space: nowrap;
574
+ overflow: hidden;
575
+ }
576
+
577
+ .d-flex {
578
+ display: flex;
579
+ }
580
+
581
+ .flex-column {
582
+ flex-direction: column;
583
+ }
584
+
585
+ .justify-content-between {
586
+ justify-content: space-between;
587
+ }
588
+
589
+ .justify-content-end {
590
+ justify-content: flex-end;
591
+ }
592
+
593
+ .align-items-center {
594
+ align-items: center;
595
+ }
596
+
597
+ .flex-grow-1 {
598
+ flex-grow: 1;
599
+ }
600
+
601
+ .border-bottom {
602
+ border-bottom: 1px solid #c5c1c1;
603
+ }
604
+
605
+ .no-wrap {
606
+ overflow: hidden;
607
+ white-space: nowrap;
608
+ }
609
+
610
+ .white-space-collapse {
611
+ white-space: collapse;
612
+ }
613
+
614
+ .overflow-auto {
615
+ overflow: auto;
616
+ }
617
+
618
+ .mt-1 {
619
+ margin-top: 0.25rem;
620
+ }
621
+
622
+ .mt-2 {
623
+ margin-top: 0.5rem;
624
+ }
625
+
626
+ .mt-4 {
627
+ margin-top: 1.5rem;
628
+ }
629
+
630
+ .ms-1 {
631
+ margin-left: 0.25rem;
632
+ }
633
+
634
+ .mb-2 {
635
+ margin-bottom: 0.5rem;
636
+ }
637
+
638
+ .mb-3 {
639
+ margin-bottom: 1rem;
640
+ }
641
+
642
+ .mb-4 {
643
+ margin-bottom: 1.5rem;
644
+ }
645
+
646
+ .gap-1 {
647
+ gap: 0.25rem;
648
+ }
649
+
650
+ .gap-3 {
651
+ gap: 1rem;
652
+ }
653
+
654
+ .pb-2 {
655
+ padding-bottom: 0.5rem;
656
+ }
657
+
658
+ .pt-2 {
659
+ padding-top: 0.5rem;
660
+ }
661
+
662
+ .w-100 {
663
+ width: 100%;
664
+ }
665
+
666
+ .w-80 {
667
+ width: 80%;
668
+ }
669
+ `;
670
+ var u, m, v;
671
+ class M {
672
+ constructor() {
673
+ l(this, "printWarning", (t, e = !0, ...o) => {
674
+ e && this.printedWarnings.includes(t) || (console.warn(`DevTools: ${t}`, ...o), this.printedWarnings.push(t));
675
+ });
676
+ l(this, "checkForWarnings", () => {
677
+ b(this, u).call(this), b(this, m).call(this), b(this, v).call(this);
678
+ });
679
+ g(this, u, () => {
680
+ var t;
681
+ window.Turbo ? ((t = window.Turbo) == null ? void 0 : t.session.drive) === !1 && setTimeout(() => {
682
+ var e;
683
+ ((e = window.Turbo) == null ? void 0 : e.session.drive) === !1 && this.printWarning("Turbo Drive is disabled. Hotwire Native will not work correctly without Turbo Drive");
684
+ }, 1e3) : setTimeout(() => {
685
+ window.Turbo || this.printWarning("Turbo is not detected. Hotwire Native will not work correctly without Turbo");
686
+ }, 1e3);
687
+ });
688
+ g(this, m, () => {
689
+ const t = this.turboFrameIds;
690
+ t.filter((o, s) => t.indexOf(o) !== s).forEach((o) => {
691
+ this.printWarning(`Multiple Turbo Frames with the same ID '${o}' detected. This can cause unexpected behavior. Ensure that each Turbo Frame has a unique ID.`);
692
+ });
693
+ });
694
+ g(this, v, () => {
695
+ const t = document.querySelectorAll("[data-turbo-permanent]");
696
+ t.length !== 0 && t.forEach((e) => {
697
+ const o = e.id;
698
+ if (o === "" && this.printWarning("Turbo Permanent Element detected without an ID. Turbo Permanent Elements must have a unique ID to work correctly.", !0, e), o && document.querySelectorAll(`#${o}`).length > 1) {
699
+ const n = `Turbo Permanent Element with ID '${o}' doesn't have a unique ID. Turbo Permanent Elements must have a unique ID to work correctly.`;
700
+ this.printWarning(n, !0, e);
701
+ }
702
+ });
703
+ });
704
+ this.printedWarnings = [];
705
+ }
706
+ get turboFrameIds() {
707
+ return Array.from(document.querySelectorAll("turbo-frame")).map((t) => t.id);
708
+ }
709
+ }
710
+ u = new WeakMap(), m = new WeakMap(), v = new WeakMap();
711
+ const c = (i) => JSON.parse(localStorage.getItem("hotwire-native-dev-tools") || "{}")[i], d = (i, t) => {
712
+ let e = JSON.parse(localStorage.getItem("hotwire-native-dev-tools") || "{}");
713
+ e[i] = t, localStorage.setItem("hotwire-native-dev-tools", JSON.stringify(e));
714
+ }, q = () => {
715
+ localStorage.removeItem("hotwire-native-dev-tools");
716
+ }, y = () => c("consoleFilterLevels") || {
717
+ warn: !0,
718
+ error: !0,
719
+ debug: !0,
720
+ info: !0,
721
+ log: !0
722
+ }, N = (i, t) => {
723
+ const e = y();
724
+ return e[i] = t, d("consoleFilterLevels", e), e;
725
+ }, p = (i, t) => {
726
+ let e = null;
727
+ return (...o) => {
728
+ const s = () => i.apply(void 0, o);
729
+ clearTimeout(e), e = setTimeout(s, t);
730
+ };
731
+ }, { userAgent: E } = window.navigator, z = /iOS/.test(E), A = /Android/.test(E), S = () => z ? "ios" : A ? "android" : "unknown", D = () => {
732
+ switch (S()) {
733
+ case "android":
734
+ return "Android";
735
+ case "ios":
736
+ return "iOS";
737
+ default:
738
+ return "<unknown>";
739
+ }
740
+ }, P = `
741
+ <svg width="100%" height="100%" viewBox="0 0 294 320">
742
+ <g transform="matrix(1,0,0,1,-28.38,-15.268)">
743
+ <g transform="matrix(1,0,0,1,-462.157,-144.417)">
744
+ <path d="M783.777,159.685L683.006,262.542L765.948,268.939L622.459,394.208L690.389,396.4L490.537,479.149L569.424,402.053L511.312,400.203L639.22,296.093L533.548,287.812L783.777,159.685Z"/>
745
+ </g>
746
+ </g>
747
+ </svg>
748
+ `, R = `
749
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
750
+ <!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
751
+ <path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM385 215c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-71-71L280 392c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-214.1-71 71c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9L239 103c9.4-9.4 24.6-9.4 33.9 0L385 215z"/>
752
+ </svg>
753
+ `, j = `
754
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
755
+ <!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
756
+ <path d="M256 0a256 256 0 1 0 0 512A256 256 0 1 0 256 0zM127 297c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l71 71L232 120c0-13.3 10.7-24 24-24s24 10.7 24 24l0 214.1 71-71c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9L273 409c-9.4 9.4-24.6 9.4-33.9 0L127 297z"/>
757
+ </svg>
758
+ `, C = `
759
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
760
+ <!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
761
+ <path d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.2 288 416 288c17.7 0 32-14.3 32-32s-14.3-32-32-32l-306.7 0L214.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/>
762
+ </svg>
763
+ `, f = `
764
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
765
+ <!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
766
+ <path d="M135.2 17.7L128 32 32 32C14.3 32 0 46.3 0 64S14.3 96 32 96l384 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-96 0-7.2-14.3C307.4 6.8 296.3 0 284.2 0L163.8 0c-12.1 0-23.2 6.8-28.6 17.7zM416 128L32 128 53.2 467c1.6 25.3 22.6 45 47.9 45l245.8 0c25.3 0 46.3-19.7 47.9-45L416 128z"/>
767
+ </svg>
768
+ `, O = `
769
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
770
+ <!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
771
+ <path d="M142.9 142.9c-17.5 17.5-30.1 38-37.8 59.8c-5.9 16.7-24.2 25.4-40.8 19.5s-25.4-24.2-19.5-40.8C55.6 150.7 73.2 122 97.6 97.6c87.2-87.2 228.3-87.5 315.8-1L455 55c6.9-6.9 17.2-8.9 26.2-5.2s14.8 12.5 14.8 22.2l0 128c0 13.3-10.7 24-24 24l-8.4 0c0 0 0 0 0 0L344 224c-9.7 0-18.5-5.8-22.2-14.8s-1.7-19.3 5.2-26.2l41.1-41.1c-62.6-61.5-163.1-61.2-225.3 1zM16 312c0-13.3 10.7-24 24-24l7.6 0 .7 0L168 288c9.7 0 18.5 5.8 22.2 14.8s1.7 19.3-5.2 26.2l-41.1 41.1c62.6 61.5 163.1 61.2 225.3-1c17.5-17.5 30.1-38 37.8-59.8c5.9-16.7 24.2-25.4 40.8-19.5s25.4 24.2 19.5 40.8c-10.8 30.6-28.4 59.3-52.9 83.8c-87.2 87.2-228.3 87.5-315.8 1L57 457c-6.9 6.9-17.2 8.9-26.2 5.2S16 449.7 16 440l0-119.6 0-.7 0-7.6z"/>
772
+ </svg>
773
+ `, V = `
774
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
775
+ <!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
776
+ <path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM169.8 165.3c7.9-22.3 29.1-37.3 52.8-37.3l58.3 0c34.9 0 63.1 28.3 63.1 63.1c0 22.6-12.1 43.5-31.7 54.8L280 264.4c-.2 13-10.9 23.6-24 23.6c-13.3 0-24-10.7-24-24l0-13.5c0-8.6 4.6-16.5 12.1-20.8l44.3-25.4c4.7-2.7 7.6-7.7 7.6-13.1c0-8.4-6.8-15.1-15.1-15.1l-58.3 0c-3.4 0-6.4 2.1-7.5 5.3l-.4 1.2c-4.4 12.5-18.2 19-30.6 14.6s-19-18.2-14.6-30.6l.4-1.2zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"/>
777
+ </svg>
778
+ `, Y = `
779
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
780
+ <!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
781
+ <path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352a144 144 0 1 0 0-288 144 144 0 1 0 0 288z"/>
782
+ </svg>
783
+ `, W = `
784
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
785
+ <!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
786
+ <path d="M3.9 54.9C10.5 40.9 24.5 32 40 32l432 0c15.5 0 29.5 8.9 36.1 22.9s4.6 30.5-5.2 42.5L320 320.9 320 448c0 12.1-6.8 23.2-17.7 28.6s-23.8 4.3-33.5-3l-64-48c-8.1-6-12.8-15.5-12.8-25.6l0-79.1L9 97.3C-.7 85.4-2.8 68.8 3.9 54.9z"/>
787
+ </svg>
788
+ `, X = `
789
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 512">
790
+ <!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
791
+ <path d="M64 360a56 56 0 1 0 0 112 56 56 0 1 0 0-112zm0-160a56 56 0 1 0 0 112 56 56 0 1 0 0-112zM120 96A56 56 0 1 0 8 96a56 56 0 1 0 112 0z"/>
792
+ </svg>
793
+ `;
794
+ class U {
795
+ constructor(t) {
796
+ l(this, "render", p(() => {
797
+ this.setPosition(), this.createDragItem(), this.setTranslate(this.initialX, this.initialY, this.dragItem), this.addEventListeners();
798
+ }, 50));
799
+ l(this, "animateErrorBorder", p(() => {
800
+ if (!this.dragItem || c("errorAnimationEnabled") === !1) return;
801
+ let t = this.dragItem.querySelector(".error-border"), e = this.dragItem.querySelector(".error-border circle");
802
+ t && t.remove();
803
+ const o = document.createElement("div");
804
+ o.className = "animation-container", o.innerHTML = `
805
+ <svg viewBox="0 0 180 180" xmlns="http://www.w3.org/2000/svg" class="error-border">
806
+ <defs>
807
+ <linearGradient id="errorGradient" gradientTransform="rotate(45)">
808
+ <stop offset="0%" stop-color="#e4241a" />
809
+ <stop offset="50%" stop-color="#dd1f15" />
810
+ <stop offset="100%" stop-color="#f6160a" />
811
+ </linearGradient>
812
+ </defs>
813
+ <circle cx="90" cy="90" r="90" fill="none" stroke="url(#errorGradient)" stroke-width="21"
814
+ stroke-dasharray="565" stroke-dashoffset="565" stroke-linecap="round" />
815
+ </svg>
816
+ `, this.dragItem.appendChild(o), e = this.dragItem.querySelector(".error-border circle"), e.classList.add("animate"), setTimeout(() => {
817
+ o.classList.add("fade-out");
818
+ }, 1300), setTimeout(() => {
819
+ o && o.parentNode && o.remove();
820
+ }, 1800);
821
+ }, 100));
822
+ this.devTools = t, this.bubbleSize = 4.75 * 16 + 0.3 * 16, this.minVisible = this.bubbleSize * 0.5, this.currentlyDragging = !1;
823
+ }
824
+ setPosition() {
825
+ this.settingKey = window.innerWidth < window.innerHeight ? "bubblePosPortrait" : "bubblePosLandscape";
826
+ const t = { x: window.innerWidth - 100, y: window.innerHeight - 100 }, { x: e, y: o } = c(this.settingKey) || t;
827
+ this.currentX = this.initialX = this.xOffset = e, this.currentY = this.initialY = this.yOffset = o;
828
+ }
829
+ createDragItem() {
830
+ var e;
831
+ const t = (e = this.devTools.shadowRoot) == null ? void 0 : e.getElementById("floating-bubble");
832
+ if (t) {
833
+ this.dragItem = t;
834
+ return;
835
+ }
836
+ this.dragItem = document.createElement("div"), this.dragItem.id = "floating-bubble", this.dragItem.innerHTML = P, this.devTools.shadowRoot.appendChild(this.dragItem);
837
+ }
838
+ addEventListeners() {
839
+ this.dragItem.hasEventListeners || (this.dragItem.addEventListener("click", this.click.bind(this), { passive: !0 }), this.dragItem.addEventListener("touchstart", this.dragStart.bind(this), { passive: !0 }), this.dragItem.addEventListener("touchend", this.dragEnd.bind(this), { passive: !0 }), this.dragItem.addEventListener("touchmove", this.drag.bind(this), { passive: !0 }), this.dragItem.hasEventListeners = !0);
840
+ }
841
+ click(t) {
842
+ this.clickCallback && this.clickCallback(t);
843
+ }
844
+ onClick(t) {
845
+ this.clickCallback = t;
846
+ }
847
+ dragStart(t) {
848
+ t.target.closest("#floating-bubble") && (this.currentlyDragging = !0, this.initialX = t.touches[0].clientX - this.xOffset, this.initialY = t.touches[0].clientY - this.yOffset);
849
+ }
850
+ dragEnd() {
851
+ this.initialX = this.currentX, this.initialY = this.currentY, this.currentlyDragging = !1, d(this.settingKey, { x: this.currentX, y: this.currentY });
852
+ }
853
+ drag(t) {
854
+ if (!this.currentlyDragging) return;
855
+ const e = t.touches[0], o = e.clientX - this.initialX, s = e.clientY - this.initialY;
856
+ this.currentX = Math.max(-this.bubbleSize + this.minVisible, Math.min(o, window.innerWidth - this.minVisible)), this.currentY = Math.max(-this.bubbleSize + this.minVisible, Math.min(s, window.innerHeight - this.minVisible)), this.xOffset = this.currentX, this.yOffset = this.currentY, this.animationFrame || (this.animationFrame = requestAnimationFrame(() => {
857
+ this.setTranslate(this.currentX, this.currentY, this.dragItem), this.animationFrame = null;
858
+ }));
859
+ }
860
+ setTranslate(t, e, o) {
861
+ o.style.transform = `translate3d(${t}px, ${e}px, 0)`;
862
+ }
863
+ }
864
+ class J {
865
+ constructor(t) {
866
+ l(this, "handleTabClick", (t) => {
867
+ const e = t.target.closest(".tablink");
868
+ if (!e) return;
869
+ const o = e.dataset.tabId;
870
+ this.devTools.state.setActiveTab(o), this.updateTabView(o);
871
+ });
872
+ this.devTools = t, this.state = t.state.state, this.sheetHeight = parseInt(c("bottomSheetHeight")) || 50;
873
+ }
874
+ render() {
875
+ this.createBottomSheet(), this.sheetContent = this.bottomSheet.querySelector(".content"), this.sheetOverlay = this.bottomSheet.querySelector(".sheet-overlay"), this.addEventListeners();
876
+ }
877
+ update(t) {
878
+ this.state = t, this.checkNativeFeatures(), this.renderConsoleLogs(), this.renderBridgeComponents(), this.renderBridgeLogs(), this.renderEvents(), this.renderNativeStack();
879
+ }
880
+ createBottomSheet() {
881
+ var n;
882
+ const t = (n = this.devTools.shadowRoot) == null ? void 0 : n.querySelector(".bottom-sheet");
883
+ if (t) {
884
+ this.bottomSheet = t;
885
+ return;
886
+ }
887
+ const e = this.state.activeTab, o = y(), s = this.state.consoleSearch;
888
+ this.bottomSheet = document.createElement("div"), this.bottomSheet.classList.add("bottom-sheet"), this.bottomSheet.innerHTML = `
889
+ <div class="sheet-overlay ${c("bottomSheetPinned") === !0 ? "" : "active"}"></div>
890
+ <div class="content">
891
+ <div class="top-part">
892
+ <div class="tablist">
893
+ <button class="tablink ${e === "tab-bridge-components" ? "active" : ""}" data-tab-id="tab-bridge-components">Bridge</button>
894
+ <button class="tablink ${e === "tab-console-logs" ? "active" : ""}" data-tab-id="tab-console-logs">Console</button>
895
+ <button class="tablink ${e === "tab-event-logs" ? "active" : ""}" data-tab-id="tab-event-logs">Events</button>
896
+ <button class="tablink ${e === "tab-native-stack" ? "active" : ""} d-none" data-tab-id="tab-native-stack">Stack</button>
897
+ <div class="dropdown d-flex">
898
+ <button class="dropdown-trigger tablink-dropdown">${X}</button>
899
+ <div class="dropdown-content settings-dropdown">
900
+ <button class="btn-switch-to-single-tab-sheet" data-tab-id="single-tab-settings">Settings</button>
901
+ <button class="pin-bottom-sheet">Pin Bottom Sheet</button>
902
+ </div>
903
+ </div>
904
+ </div>
905
+
906
+ <div class="tab-action-bars">
907
+ <div class="tab-action-bar tab-bridge-components ${e === "tab-bridge-components" ? "active" : ""}">
908
+ <button class="btn-icon btn-clear-tab btn-clear-bridge-logs">${f}</button>
909
+ </div>
910
+ <div class="tab-action-bar d-flex flex-column tab-console-logs ${e === "tab-console-logs" ? "active" : ""}">
911
+ <div class="d-flex">
912
+ <button class="btn-icon btn-search-console">${Y}</button>
913
+ <div class="dropdown">
914
+ <button class="dropdown-trigger btn-icon">${W}</button>
915
+ <div class="dropdown-content console-filter-levels">
916
+ <label><input type="checkbox" ${o.warn ? "checked" : ""} data-console-filter="warn" /> Warnings</label>
917
+ <label><input type="checkbox" ${o.error ? "checked" : ""} data-console-filter="error" /> Errors</label>
918
+ <label><input type="checkbox" ${o.debug ? "checked" : ""} data-console-filter="debug" /> Debug</label>
919
+ <label><input type="checkbox" ${o.info ? "checked" : ""} data-console-filter="info" /> Info</label>
920
+ <label><input type="checkbox" ${o.log ? "checked" : ""} data-console-filter="log" /> Logs</label>
921
+ </div>
922
+ </div>
923
+ <button class="btn-icon btn-clear-tab btn-clear-console-logs">${f}</button>
924
+ </div>
925
+
926
+ <div class="console-search mt-2 ${s ? "" : "d-none"}">
927
+ <input type="search" class="console-search-input" value="${s}" placeholder="Search console logs" />
928
+ </div>
929
+ </div>
930
+ <div class="tab-action-bar tab-event-logs ${e === "tab-event-logs" ? "active" : ""}">
931
+ <button class="btn-icon btn-clear-tab btn-clear-events">${f}</button>
932
+ </div>
933
+ <div class="tab-action-bar tab-native-stack ${e === "tab-native-stack" ? "active" : ""}">
934
+ <button class="btn-icon btn-reload-tab btn-reload-stack">${O}</button>
935
+ </div>
936
+ </div>
937
+ </div>
938
+
939
+ <div class="tab-contents">
940
+ <div id="tab-bridge-components" class="outer-tab-content ${e === "tab-bridge-components" ? "active" : ""}">
941
+ <div class="inner-tab-content">
942
+ <button class="collapse bridge-components-collapse-btn" type="button" data-collapse-target="bridge-components-collapse">
943
+ Registered Bridge Components: <span class="bridge-components-amount">${this.state.supportedBridgeComponents.length}</span>
944
+ </button>
945
+ <div id="bridge-components-collapse" class="collapse-target">
946
+ <div class="d-flex justify-content-between border-bottom">
947
+ <div class="tab-content-bridge-components flex-grow-1"></div>
948
+ <button class="btn-icon btn-help btn-switch-to-single-tab-sheet mt-1" data-tab-id="single-tab-bridge-component-help">${V}</button>
949
+ </div>
950
+ </div>
951
+
952
+ <div class="tab-content-bridge-logs">
953
+ </div>
954
+ </div>
955
+ </div>
956
+
957
+ <div id="tab-console-logs" class="outer-tab-content ${e === "tab-console-logs" ? "active" : ""}">
958
+ <div class="inner-tab-content tab-content-console-logs">
959
+ </div>
960
+ </div>
961
+
962
+ <div id="tab-event-logs" class="outer-tab-content ${e === "tab-event-logs" ? "active" : ""}">
963
+ <div class="inner-tab-content tab-content-event-logs">
964
+ </div>
965
+ </div>
966
+
967
+ <div id="tab-native-stack" class="outer-tab-content ${e === "tab-native-stack" ? "active" : ""}">
968
+ <div class="inner-tab-content tab-content-native-stack">
969
+ </div>
970
+ </div>
971
+
972
+ <div id="single-tab-bridge-component-help" class="single-tab-content outer-tab-content">
973
+ <div class="inner-tab-content">
974
+ <div class="d-flex align-items-center mb-3">
975
+ <button class="btn-icon btn-close-single-mode">${C}</button>
976
+ <h3 class="ms-1">Bridge Components</h3>
977
+ </div>
978
+ <p>This list shows all the bridge components that the ${D()} app supports. Components that are active on this page are marked with a green dot.</p>
979
+ <h3 class="mt-4">Why is my bridge component not on the list?</h3>
980
+ <p class="mt-2">Bridge components are automatically detected when they are registered in the native code. If your component is not on the list, make sure it is registered correctly.</p>
981
+ ${this.registerBridgeComponentExample()}
982
+ <p class"mt-1">For more information, check out the documentation:</p>
983
+ <a href="${this.registerBridgeComponentHelpURL()}">${this.registerBridgeComponentHelpURL()}</a>
984
+ </div>
985
+ </div>
986
+
987
+ <div id="single-tab-settings" class="single-tab-content outer-tab-content">
988
+ <div class="inner-tab-content">
989
+ <div class="d-flex align-items-center mb-3">
990
+ <button class="btn-icon btn-close-single-mode">${C}</button>
991
+ <h3 class="ms-1">Settings</h3>
992
+ </div>
993
+ <div class="mb-3">
994
+ <label for="bottom-sheet-height"> Bottom Sheet Height</label>
995
+ <input type="range" id="bottom-sheet-height" class="w-100" min="10" max="100" value="${this.sheetHeight}" step="1" />
996
+ </div>
997
+ <div class="mb-4">
998
+ <label for="font-size-input"> Font Size</label>
999
+ <input id="font-size-input" type="number" inputmode="numeric" class="w-100" value="${c("fontSize") || 16}" />
1000
+ </div>
1001
+ <div class="mb-3">
1002
+ <label class="toggle">
1003
+ <input class="toggle-checkbox" type="checkbox" id="console-error-animation-setting" ${c("errorAnimationEnabled") !== !1 ? "checked" : ""} />
1004
+ <div class="toggle-switch"></div>
1005
+ <span class="toggle-label">Console Error Animation</span>
1006
+ </label>
1007
+ </div>
1008
+ <div class="mb-3">
1009
+ <label class="toggle">
1010
+ <input class="toggle-checkbox" type="checkbox" id="auto-open-setting" ${c("autoOpen") === !0 ? "checked" : ""} />
1011
+ <div class="toggle-switch"></div>
1012
+ <span class="toggle-label">Auto Open</span>
1013
+ </label>
1014
+ </div>
1015
+ </div>
1016
+ </div>
1017
+ </div>
1018
+ </div>
1019
+ `, this.devTools.shadowRoot.appendChild(this.bottomSheet);
1020
+ }
1021
+ renderConsoleLogs() {
1022
+ const t = this.bottomSheet.querySelector(".tab-content-console-logs"), e = y(), o = this.state.consoleSearch;
1023
+ t.innerHTML = this.state.consoleLogs.length ? this.state.consoleLogs.filter((s) => e[s.type]).filter((s) => o ? s.message.toLowerCase().includes(o.toLowerCase()) : !0).map((s) => this.consoleLogHTML(s.type, s.message, s.time)).join("") : '<div class="tab-empty-content"><span>No console logs yet</span></div>';
1024
+ }
1025
+ renderBridgeComponents() {
1026
+ const t = this.state.supportedBridgeComponents.length;
1027
+ this.bottomSheet.querySelector(".bridge-components-amount").textContent = t;
1028
+ const e = this.bridgeComponentIdentifiers, o = this.bottomSheet.querySelector(".tab-content-bridge-components");
1029
+ o.innerHTML = t ? this.state.supportedBridgeComponents.map((s) => `<div class="bridge-component ${e.includes(s) ? "connected" : ""}">${s}</div>`).join("") : '<div class="tab-empty-content d-flex flex-column text-center"><span>No bridge components found</span></div>';
1030
+ }
1031
+ renderBridgeLogs() {
1032
+ const t = this.bottomSheet.querySelector(".tab-content-bridge-logs");
1033
+ t.innerHTML = this.state.bridgeLogs.length ? this.state.bridgeLogs.map((e) => this.bridgeLogHTML(e.direction, e.componentName, e.eventName, e.eventArgs, e.time)).join("") : `<div class="tab-empty-content d-flex flex-column text-center"><span>${this.state.bridgeIsConnected ? "No bridge communication yet" : "Bridge is not connected <br><small>(Neither window.HotwireNative nor window.Strada is defined)</small>"}</span></div>`;
1034
+ }
1035
+ renderEvents() {
1036
+ const t = this.bottomSheet.querySelector(".tab-content-event-logs");
1037
+ t.innerHTML = this.state.eventLogs.length ? this.state.eventLogs.map((e) => this.eventMessageHTML(e.eventName, e.time)).join("") : '<div class="tab-empty-content"><span>No events captured yet</span></div>';
1038
+ }
1039
+ renderNativeStack() {
1040
+ const t = this.bottomSheet.querySelector(".tab-content-native-stack");
1041
+ t.innerHTML = '<div class="native-stack-wrapper">' + (this.state.nativeStack.length ? this.state.nativeStack.map((e) => this.nativeViewStackHTML(e)).join("") : '<div class="tab-empty-content"><span>No native stack captured yet</span></div>') + "</div>";
1042
+ }
1043
+ bridgeLogHTML(t, e, o, s, n) {
1044
+ return `
1045
+ <div class="log-entry d-flex gap-3 pt-2 pb-2">
1046
+ <div class="log-entry-icon d-flex justify-content-center align-items-center">
1047
+ ${t === "send" ? j : R}
1048
+ </div>
1049
+ <div class="w-100 overflow-auto">
1050
+ <div class="d-flex justify-content-between">
1051
+ <strong class="w-80 text-ellipsis">${e}#${o}</strong>
1052
+ <small>${n}</small>
1053
+ </div>
1054
+ <div>
1055
+ ${Object.entries(s).map(([r, a]) => {
1056
+ const w = typeof a == "object" && a !== null ? JSON.stringify(a) : a;
1057
+ return `<div class="white-space-collapse">${r}: ${w}</div>`;
1058
+ }).join("")}
1059
+ </div>
1060
+ </div>
1061
+ </div>
1062
+ `;
1063
+ }
1064
+ consoleLogHTML(t, e, o) {
1065
+ return `
1066
+ <div class="log-entry pt-2 pb-2">
1067
+ <div class="w-100">
1068
+ <div class="d-flex justify-content-end">
1069
+ <small>${o}</small>
1070
+ </div>
1071
+ <div class="log-entry-message ${t}">
1072
+ ${e}
1073
+ </div>
1074
+ </div>
1075
+ </div>
1076
+ `;
1077
+ }
1078
+ eventMessageHTML(t, e) {
1079
+ return `
1080
+ <div class="log-entry pt-2 pb-2">
1081
+ <div class="w-100">
1082
+ <div class="d-flex justify-content-end">
1083
+ <small>${e}</small>
1084
+ </div>
1085
+ <div class="log-entry-message">
1086
+ ${t}
1087
+ </div>
1088
+ </div>
1089
+ </div>
1090
+ `;
1091
+ }
1092
+ nativeViewStackHTML(t) {
1093
+ var k;
1094
+ const e = ["UINavigationController", "NavigatorHost"].includes(t.type), o = t.type === "UITabBarController", s = ["VisitableViewController", "HotwireWebFragment", "BackStackEntry"].includes(t.type), r = `viewstack-card ${t.url === this.currentUrl ? "current-view" : ""} ${e ? "main-view" : s ? "hotwire-view" : o ? "tab-container" : "non-identified-view"}`, a = "viewstack-" + Math.random().toString(16).slice(2), w = t.url ? `<div class="view-url">
1095
+ ${(() => {
1096
+ try {
1097
+ return new URL(t.url).pathname;
1098
+ } catch {
1099
+ return t.url;
1100
+ }
1101
+ })()}
1102
+ </div>` : "", L = (() => {
1103
+ try {
1104
+ const h = t.pathConfigurationProperties;
1105
+ return JSON.stringify(typeof h == "string" ? JSON.parse(h) : h, null, 2);
1106
+ } catch {
1107
+ return t.pathConfigurationProperties;
1108
+ }
1109
+ })(), T = L ? `<pre class="view-path-configuration">${L}</pre>` : "", B = (k = t.children) != null && k.length ? `<div class="child-container">
1110
+ ${t.children.map((h) => this.nativeViewStackHTML(h)).join("")}
1111
+ </div>` : "";
1112
+ return `
1113
+ <div>
1114
+ <div class="${r} collapse no-chevron" data-collapse-target="path-configuration-properties-${a}">
1115
+ <div>
1116
+ <div class="view-title">
1117
+ ${t.title == "null" ? "" : t.title}
1118
+ <div class="view-title-details">${t.type}</div>
1119
+ </div>
1120
+ ${w}
1121
+ </div>
1122
+ <div id="path-configuration-properties-${a}" class="collapse-target">
1123
+ ${T}
1124
+ </div>
1125
+ </div>
1126
+ ${B}
1127
+ </div>
1128
+ `;
1129
+ }
1130
+ switchToSingleTabSheet(t) {
1131
+ this.sheetContent.querySelector(".top-part").classList.add("d-none"), this.devTools.shadowRoot.querySelectorAll(".outer-tab-content").forEach((e) => e.classList.remove("active")), this.devTools.shadowRoot.getElementById(t).classList.add("active");
1132
+ }
1133
+ switchToMultiTabSheet() {
1134
+ this.sheetContent.querySelector(".top-part").classList.remove("d-none"), this.devTools.shadowRoot.querySelectorAll(".outer-tab-content").forEach((t) => t.classList.remove("active")), this.devTools.shadowRoot.querySelectorAll(".tablink, .outer-tab-content").forEach((t) => {
1135
+ t.id == this.state.activeTab && t.classList.add("active");
1136
+ });
1137
+ }
1138
+ registerBridgeComponentExample() {
1139
+ switch (S()) {
1140
+ case "android":
1141
+ return `
1142
+ <pre class="overflow-auto">
1143
+ Hotwire.registerBridgeComponents(
1144
+ BridgeComponentFactory("my-component", ::MyComponent)
1145
+ )
1146
+ </pre>
1147
+ `;
1148
+ case "ios":
1149
+ return `
1150
+ <pre class="overflow-auto">
1151
+ Hotwire.registerBridgeComponents([
1152
+ MyComponent.self
1153
+ ])
1154
+ </pre>`;
1155
+ default:
1156
+ return "";
1157
+ }
1158
+ }
1159
+ registerBridgeComponentHelpURL() {
1160
+ switch (S()) {
1161
+ case "android":
1162
+ return "https://native.hotwired.dev/android/bridge-components";
1163
+ case "ios":
1164
+ return "https://native.hotwired.dev/ios/bridge-components";
1165
+ default:
1166
+ return "https://native.hotwired.dev";
1167
+ }
1168
+ }
1169
+ checkNativeFeatures() {
1170
+ this.state.supportsNativeStackView && this.bottomSheet.querySelector(".tablink[data-tab-id='tab-native-stack']").classList.remove("d-none");
1171
+ }
1172
+ addEventListeners() {
1173
+ this.bottomSheet.hasEventListeners || (this.sheetOverlay.addEventListener("click", () => {
1174
+ this.hideBottomSheet(), this.switchToMultiTabSheet();
1175
+ }), this.bottomSheet.querySelector(".tablist").addEventListener("click", (t) => this.handleTabClick(t)), this.bottomSheet.querySelector(".btn-clear-console-logs").addEventListener("click", () => {
1176
+ this.devTools.state.clearConsoleLogs(), this.renderConsoleLogs();
1177
+ }), this.bottomSheet.querySelector(".btn-clear-bridge-logs").addEventListener("click", () => {
1178
+ this.devTools.state.clearBridgeLogs(), this.renderBridgeLogs();
1179
+ }), this.bottomSheet.querySelector(".btn-clear-events").addEventListener("click", () => {
1180
+ this.devTools.state.clearEventLogs(), this.renderEvents();
1181
+ }), this.bottomSheet.querySelector(".btn-reload-stack").addEventListener("click", () => {
1182
+ this.bottomSheet.querySelector(".native-stack-wrapper").style.opacity = 0.5, this.devTools.refetchNativeStack();
1183
+ }), this.bottomSheet.querySelectorAll(".btn-switch-to-single-tab-sheet").forEach((t) => {
1184
+ t.addEventListener("click", (e) => {
1185
+ const o = e.target.closest("[data-tab-id]").dataset.tabId;
1186
+ o && this.switchToSingleTabSheet(o);
1187
+ });
1188
+ }), this.bottomSheet.querySelectorAll(".btn-close-single-mode").forEach((t) => {
1189
+ t.addEventListener("click", () => {
1190
+ this.switchToMultiTabSheet();
1191
+ });
1192
+ }), this.bottomSheet.querySelector(".top-part").addEventListener("touchstart", this.dragStart.bind(this), { passive: !0 }), this.bottomSheet.addEventListener("touchmove", this.dragging.bind(this), { passive: !0 }), this.bottomSheet.addEventListener("touchend", this.dragStop.bind(this), { passive: !0 }), this.bottomSheet.querySelector(".console-filter-levels").addEventListener("click", ({ target: t }) => {
1193
+ const e = t.closest("input[type='checkbox']");
1194
+ if (!e) return;
1195
+ const o = e.dataset.consoleFilter, s = e.checked;
1196
+ N(o, s), this.renderConsoleLogs();
1197
+ }), this.bottomSheet.querySelector(".btn-search-console").addEventListener("click", () => {
1198
+ const t = this.bottomSheet.querySelector(".console-search");
1199
+ t.classList.toggle("d-none"), t.querySelector("input").focus();
1200
+ }), this.bottomSheet.querySelector(".console-search-input").addEventListener("input", (t) => {
1201
+ this.devTools.state.setConsoleSearchValue(t.target.value.toLowerCase()), this.renderConsoleLogs();
1202
+ }), this.bottomSheet.querySelector("#bottom-sheet-height").addEventListener("change", (t) => {
1203
+ const e = t.target.value;
1204
+ this.sheetHeight = parseInt(e), d("bottomSheetHeight", e), this.updateSheetHeight(e);
1205
+ }), this.bottomSheet.querySelector("#console-error-animation-setting").addEventListener("change", (t) => {
1206
+ d("errorAnimationEnabled", t.target.checked);
1207
+ }), this.bottomSheet.querySelector("#font-size-input").addEventListener("change", (t) => {
1208
+ const e = t.target.value;
1209
+ d("fontSize", e), this.devTools.setCSSProperty("--font-size", `${e}px`);
1210
+ }), this.bottomSheet.querySelector("#auto-open-setting").addEventListener("change", (t) => {
1211
+ d("autoOpen", t.target.checked);
1212
+ }), this.bottomSheet.querySelector(".pin-bottom-sheet").addEventListener("click", () => {
1213
+ const t = c("bottomSheetPinned") === !0;
1214
+ d("bottomSheetPinned", !t), this.sheetOverlay.classList.toggle("active"), this.bottomSheet.querySelector(".settings-dropdown").classList.remove("dropdown-open");
1215
+ }), this.bottomSheet.addEventListener("click", (t) => {
1216
+ const e = t.target.closest(".collapse");
1217
+ if (e && this.bottomSheet.contains(e)) {
1218
+ const n = e.getAttribute("data-collapse-target"), r = this.bottomSheet.querySelector(`#${n}`);
1219
+ if (r) {
1220
+ const a = e.classList.toggle("active");
1221
+ r.classList.toggle("active", a);
1222
+ }
1223
+ return;
1224
+ }
1225
+ const o = t.target.closest(".dropdown-trigger");
1226
+ if (o) {
1227
+ t.preventDefault(), this.toggleDropdown(o);
1228
+ return;
1229
+ }
1230
+ this.bottomSheet.querySelectorAll(".dropdown-content.dropdown-open").forEach((n) => {
1231
+ n.closest(".dropdown").contains(t.target) || n.classList.remove("dropdown-open");
1232
+ });
1233
+ }), this.bottomSheet.hasEventListeners = !0);
1234
+ }
1235
+ toggleDropdown(t) {
1236
+ const e = t.nextElementSibling || t.closest(".dropdown").querySelector(".dropdown-content");
1237
+ this.bottomSheet.querySelectorAll(".dropdown-content.dropdown-open").forEach((o) => {
1238
+ o !== e && o.classList.remove("dropdown-open");
1239
+ }), e.classList.toggle("dropdown-open");
1240
+ }
1241
+ updateTabView(t) {
1242
+ this.devTools.shadowRoot.querySelectorAll(".tablink, .outer-tab-content").forEach((e) => e.classList.remove("active")), this.devTools.shadowRoot.querySelectorAll(".tab-action-bar").forEach((e) => e.classList.remove("active")), this.devTools.shadowRoot.querySelector(`[data-tab-id="${t}"]`).classList.add("active"), this.devTools.shadowRoot.getElementById(t).classList.add("active"), this.devTools.shadowRoot.querySelector(`.tab-action-bar.${t}`).classList.add("active");
1243
+ }
1244
+ showBottomSheet() {
1245
+ this.bottomSheet.classList.add("show"), document.body.style.overflow = "hidden", this.updateSheetHeight(this.sheetHeight);
1246
+ }
1247
+ updateSheetHeight(t) {
1248
+ this.sheetContent.style.height = `${t}vh`;
1249
+ }
1250
+ hideBottomSheet() {
1251
+ this.bottomSheet.classList.remove("show"), document.body.style.overflow = "auto";
1252
+ }
1253
+ updateSheetHeight(t) {
1254
+ this.sheetContent.style.height = `${t}vh`, this.bottomSheet.classList.toggle("fullscreen", t === 100);
1255
+ }
1256
+ dragStart(t) {
1257
+ var e;
1258
+ this.isDragging = !0, this.startY = t.pageY || ((e = t.touches) == null ? void 0 : e[0].pageY), this.startHeight = parseInt(this.sheetContent.style.height), this.bottomSheet.classList.add("dragging");
1259
+ }
1260
+ dragging(t) {
1261
+ var s;
1262
+ if (!this.isDragging) return;
1263
+ const e = this.startY - (t.pageY || ((s = t.touches) == null ? void 0 : s[0].pageY)), o = this.startHeight + e / window.innerHeight * 100;
1264
+ this.updateSheetHeight(o);
1265
+ }
1266
+ dragStop() {
1267
+ this.isDragging = !1, this.bottomSheet.classList.remove("dragging");
1268
+ const t = 10, e = parseInt(this.sheetContent.style.height), o = Math.max(0, this.sheetHeight - t), s = Math.min(100, this.sheetHeight + t);
1269
+ e < o ? this.hideBottomSheet() : e > s ? this.updateSheetHeight(100) : this.updateSheetHeight(this.sheetHeight);
1270
+ }
1271
+ // Helper function to log messages, without causing a rerender of the bottom sheet
1272
+ // (Messages with a `HotwireDevTools` prefix will not be logged in the bottom sheet)
1273
+ log(t) {
1274
+ console.log(`HotwireDevTools: ${t}`);
1275
+ }
1276
+ // Get all the `static component = "..."` from the bridge components
1277
+ get bridgeComponentIdentifiers() {
1278
+ var t;
1279
+ return ((t = window.Stimulus) == null ? void 0 : t.controllers.map((e) => e.component).filter((e) => e !== void 0)) || [];
1280
+ }
1281
+ get currentUrl() {
1282
+ return window.location.href;
1283
+ }
1284
+ }
1285
+ class G {
1286
+ constructor() {
1287
+ this.state = {
1288
+ consoleLogs: [],
1289
+ bridgeLogs: [],
1290
+ eventLogs: [],
1291
+ nativeStack: [],
1292
+ supportedBridgeComponents: [],
1293
+ bridgeIsConnected: !1,
1294
+ supportsNativeStackView: !1,
1295
+ consoleSearch: "",
1296
+ activeTab: c("activeTab") || "tab-bridge-components"
1297
+ }, this.listeners = [];
1298
+ }
1299
+ subscribe(t) {
1300
+ this.listeners.push(t);
1301
+ }
1302
+ notify() {
1303
+ this.listeners.forEach((t) => t(this.state));
1304
+ }
1305
+ addConsoleLog(t, e) {
1306
+ const o = { type: t, message: e, time: this.currentTime };
1307
+ this.state.consoleLogs.push(o), this.notify();
1308
+ }
1309
+ addBridgeLog(t, e, o, s) {
1310
+ const n = { direction: t, componentName: e, eventName: o, eventArgs: s, time: this.currentTime };
1311
+ this.state.bridgeLogs.push(n), this.notify();
1312
+ }
1313
+ addEventLog(t) {
1314
+ const e = { eventName: t, time: this.currentTime };
1315
+ this.state.eventLogs.push(e), this.notify();
1316
+ }
1317
+ setNativeStack(t) {
1318
+ this.state.nativeStack = t, this.notify();
1319
+ }
1320
+ setSupportsNativeStack(t) {
1321
+ this.state.supportsNativeStackView = t, this.notify();
1322
+ }
1323
+ setBridgeIsConnected(t) {
1324
+ this.state.bridgeIsConnected = t, this.notify();
1325
+ }
1326
+ setSupportedBridgeComponents(t) {
1327
+ this.state.supportedBridgeComponents = t, this.notify();
1328
+ }
1329
+ clearConsoleLogs() {
1330
+ this.state.consoleLogs = [], this.notify();
1331
+ }
1332
+ clearBridgeLogs() {
1333
+ this.state.bridgeLogs = [], this.notify();
1334
+ }
1335
+ clearEventLogs() {
1336
+ this.state.eventLogs = [], this.notify();
1337
+ }
1338
+ setActiveTab(t) {
1339
+ this.state.activeTab = t, d("activeTab", t);
1340
+ }
1341
+ setConsoleSearchValue(t) {
1342
+ this.state.consoleSearch = t;
1343
+ }
1344
+ get currentTime() {
1345
+ return (/* @__PURE__ */ new Date()).toLocaleTimeString();
1346
+ }
1347
+ }
1348
+ class K {
1349
+ bridgeIsConnected() {
1350
+ var t, e;
1351
+ return !!((t = window.HotwireNative) != null && t.web || (e = window.Strada) != null && e.web);
1352
+ }
1353
+ // Send a message to the native side
1354
+ send(t, e = {}, o = null) {
1355
+ if (!this.bridgeIsConnected())
1356
+ return Promise.reject("Bridge is not connected");
1357
+ const s = {
1358
+ ...e,
1359
+ metadata: {
1360
+ url: window.location.href
1361
+ }
1362
+ };
1363
+ return this.bridge.send({
1364
+ component: "dev-tools",
1365
+ event: t,
1366
+ data: s,
1367
+ callback: o
1368
+ });
1369
+ }
1370
+ isComponentSupported(t) {
1371
+ return this.bridgeIsConnected() ? this.bridge.supportsComponent(t) : !1;
1372
+ }
1373
+ getSupportedComponents() {
1374
+ var t;
1375
+ return ((t = document.documentElement.dataset.bridgeComponents) == null ? void 0 : t.split(" ")) || [];
1376
+ }
1377
+ get bridge() {
1378
+ var t, e;
1379
+ return ((t = window.HotwireNative) == null ? void 0 : t.web) || ((e = window.Strada) == null ? void 0 : e.web);
1380
+ }
1381
+ }
1382
+ class Z {
1383
+ constructor(t = {}) {
1384
+ l(this, "update", p((t) => {
1385
+ this.bottomSheet.update(t);
1386
+ }, 200));
1387
+ // Fetch the current stack from the native side
1388
+ // The debounce on this function is intentionally high,
1389
+ // to ensure the native side has enough time to set the ViewController / Fragment titles.
1390
+ // With a lower debounce, the view controller / fragment title would often be empty.
1391
+ l(this, "fetchNativeStack", p(() => {
1392
+ this.nativeBridge.send("currentStackInfo", {}, (t) => {
1393
+ this.state.setSupportsNativeStack(!0), this.state.setNativeStack(t.data.stack);
1394
+ });
1395
+ }, 1e3));
1396
+ l(this, "injectCSSToShadowRoot", async () => {
1397
+ if (this.shadowRoot.querySelector("style")) return;
1398
+ const t = document.createElement("style");
1399
+ t.textContent = H(), this.shadowRoot.appendChild(t);
1400
+ });
1401
+ this.options = {
1402
+ enabled: !0,
1403
+ reset: !1,
1404
+ ...t
1405
+ }, this.options.enabled && (this.options.reset && q(), this.state = new G(), this.bubble = new U(this), this.bottomSheet = new J(this), this.nativeBridge = new K(this), this.diagnosticsChecker = new M(), this.state.subscribe(this.update.bind(this)), this.listenForTurboEvents());
1406
+ }
1407
+ // Setup gets called initially and on every turbo:load event, eg. when navigating to a new page
1408
+ setup() {
1409
+ this.options.enabled && (this.setupShadowRoot(), this.bubble.render(), this.bottomSheet.render(), this.originalConsole || (this.originalConsole = window.console, this.addConsoleProxy()), this.originalBridge ? this.callNativeBridgeComponent() : window.HotwireNative || window.Strada ? this.nativeBridgeGotConnected() : document.addEventListener("web-bridge:ready", () => {
1410
+ this.nativeBridgeGotConnected();
1411
+ }), this.addEventListeners(), this.diagnosticsChecker.checkForWarnings(), this.bubble.onClick(() => {
1412
+ this.bottomSheet.showBottomSheet(), this.nativeBridge.send("vibrate");
1413
+ }), c("autoOpen") === !0 && this.bottomSheet.showBottomSheet());
1414
+ }
1415
+ nativeBridgeGotConnected() {
1416
+ var t, e;
1417
+ this.originalBridge || (this.originalBridge = ((t = window.HotwireNative) == null ? void 0 : t.web) || ((e = window.Strada) == null ? void 0 : e.web), this.addBridgeProxy(), this.state.setBridgeIsConnected(!0), this.callNativeBridgeComponent(), this.updateSupportedBridgeComponents(), this.startBridgeComponentObserver());
1418
+ }
1419
+ callNativeBridgeComponent() {
1420
+ this.nativeBridge.bridgeIsConnected() && this.nativeBridge.send("connect", {}, (t) => {
1421
+ this.fetchNativeStack();
1422
+ });
1423
+ }
1424
+ setupShadowRoot() {
1425
+ if (this.shadowContainer.shadowRoot) {
1426
+ this.shadowRoot = this.shadowContainer.shadowRoot, this.injectCSSToShadowRoot();
1427
+ return;
1428
+ }
1429
+ this.shadowRoot = this.shadowContainer.attachShadow({ mode: "open" }), this.setCSSProperty("--font-size", `${c("fontSize") || 16}px`), this.injectCSSToShadowRoot();
1430
+ }
1431
+ addBridgeProxy() {
1432
+ const t = () => ({
1433
+ get: (e, o, s) => {
1434
+ const n = Reflect.get(e, o, s);
1435
+ return typeof n == "function" && (o === "send" || o === "receive") ? (...r) => (this.interceptedBridgeMessage(o, r), n.apply(e, r)) : typeof n == "function" ? (...r) => n.apply(e, r) : n;
1436
+ }
1437
+ });
1438
+ window.Strada && (window.Strada.web = new Proxy(this.originalBridge, t())), window.HotwireNative && (window.HotwireNative.web = new Proxy(this.originalBridge, t()));
1439
+ }
1440
+ addConsoleProxy() {
1441
+ window.console = new Proxy(this.originalConsole, {
1442
+ get: (t, e, o) => {
1443
+ const s = Reflect.get(t, e, o);
1444
+ return (...n) => (this.interceptedConsoleMessage(e, n), s == null ? void 0 : s.apply(t, n));
1445
+ }
1446
+ });
1447
+ }
1448
+ interceptedBridgeMessage(t, e) {
1449
+ e.forEach((o) => {
1450
+ const s = o.component, n = o.event, { metadata: r, ...a } = o.data;
1451
+ s !== "dev-tools" && this.state.addBridgeLog(t, s, n, a);
1452
+ });
1453
+ }
1454
+ interceptedConsoleMessage(t, e) {
1455
+ const o = e.map((s) => {
1456
+ if (s instanceof Element) {
1457
+ const r = Array.from(s.attributes).map((a) => `${a.name}="${a.value}"`).join(" ");
1458
+ return `&lt;${s.tagName.toLowerCase()}${r ? " " + r : ""}&gt;&lt;/${s.tagName.toLowerCase()}&gt;`;
1459
+ }
1460
+ if (typeof s == "object")
1461
+ try {
1462
+ return `<pre>${JSON.stringify(s, null, 2)}</pre>`;
1463
+ } catch {
1464
+ return `<pre>${s}</pre>`;
1465
+ }
1466
+ return s.toString().replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
1467
+ }).join(" ");
1468
+ o.includes("hotwire-native-dev-tools") || o.includes("HotwireDevTools") || (this.state.addConsoleLog(t, o), t === "error" && this.bubble.animateErrorBorder());
1469
+ }
1470
+ refetchNativeStack() {
1471
+ this.nativeBridge.send("currentStackInfo", {}, (t) => {
1472
+ this.state.setNativeStack(t.data.stack);
1473
+ });
1474
+ }
1475
+ addEventListeners() {
1476
+ this.hasEventListeners || (window.addEventListener("error", (t) => {
1477
+ const { message: e, filename: o, lineno: s, colno: n } = t, r = `${e} at ${o}:${s}:${n}`;
1478
+ this.interceptedConsoleMessage("error", [r]);
1479
+ }), window.addEventListener("unhandledrejection", (t) => {
1480
+ var e;
1481
+ this.interceptedConsoleMessage("error", [(e = t.reason) == null ? void 0 : e.message]);
1482
+ }), window.addEventListener(
1483
+ "resize",
1484
+ () => {
1485
+ this.bubble.render();
1486
+ },
1487
+ { passive: !0 }
1488
+ ), this.hasEventListeners = !0);
1489
+ }
1490
+ listenForTurboEvents() {
1491
+ if (this.eventsRegistered) return;
1492
+ [
1493
+ "turbo:click",
1494
+ "turbo:before-visit",
1495
+ "turbo:visit",
1496
+ "turbo:before-cache",
1497
+ "turbo:before-render",
1498
+ "turbo:render",
1499
+ "turbo:load",
1500
+ "turbo:morph",
1501
+ "turbo:before-morph-element",
1502
+ "turbo:before-morph-attribute",
1503
+ "turbo:morph-element",
1504
+ "turbo:submit-start",
1505
+ "turbo:submit-end",
1506
+ "turbo:before-frame-render",
1507
+ "turbo:frame-render",
1508
+ "turbo:frame-load",
1509
+ "turbo:frame-missing",
1510
+ "turbo:before-stream-render",
1511
+ "turbo:before-fetch-request",
1512
+ "turbo:before-fetch-response",
1513
+ "turbo:before-prefetch",
1514
+ "turbo:fetch-request-error"
1515
+ ].forEach((e) => {
1516
+ window.addEventListener(
1517
+ e,
1518
+ (o) => {
1519
+ this.state.addEventLog(e);
1520
+ },
1521
+ { passive: !0 }
1522
+ );
1523
+ }), this.eventsRegistered = !0;
1524
+ }
1525
+ startBridgeComponentObserver() {
1526
+ this.bridgeComponentObserver || (this.bridgeComponentObserver = new MutationObserver((t) => {
1527
+ for (const e of t)
1528
+ e.type === "attributes" && e.attributeName === "data-bridge-components" && this.updateSupportedBridgeComponents();
1529
+ }), this.bridgeComponentObserver.observe(document.documentElement, {
1530
+ attributes: !0,
1531
+ attributeFilter: ["data-bridge-components"]
1532
+ }));
1533
+ }
1534
+ updateSupportedBridgeComponents() {
1535
+ this.state.setSupportedBridgeComponents(this.nativeBridge.getSupportedComponents().sort());
1536
+ }
1537
+ getCSSProperty(t) {
1538
+ return getComputedStyle(this.shadowContainer).getPropertyValue(t).trim();
1539
+ }
1540
+ setCSSProperty(t, e) {
1541
+ this.shadowContainer.style.setProperty(t, e);
1542
+ }
1543
+ get shadowContainer() {
1544
+ const t = document.getElementById("hotwire-native-dev-tools-shadow-container");
1545
+ if (t)
1546
+ return t;
1547
+ const e = document.createElement("div");
1548
+ return e.id = "hotwire-native-dev-tools-shadow-container", e.setAttribute("data-native-prevent-pull-to-refresh", ""), document.body.appendChild(e), e;
1549
+ }
1550
+ get currentTime() {
1551
+ return (/* @__PURE__ */ new Date()).toLocaleTimeString();
1552
+ }
1553
+ }
1554
+ const _ = (i = {}) => {
1555
+ const t = new Z(i);
1556
+ t.options.enabled && (t.setup(), document.addEventListener(
1557
+ "turbo:load",
1558
+ () => {
1559
+ t.setup();
1560
+ },
1561
+ { passive: !0 }
1562
+ ));
1563
+ };
1564
+ export {
1565
+ _ as setupDevTools
1566
+ };
1567
+ //# sourceMappingURL=hotwire-native-dev-tools.es.js.map