@hai3/studio 0.3.0-alpha.2 → 0.4.0-alpha.1

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 CHANGED
@@ -1,8 +1,13 @@
1
- import React3, { createContext, useContext, useState, useEffect, useCallback, useRef } from 'react';
2
- import { I18nRegistry, Language, i18nRegistry, ScreensetCategory, eventBus, useTranslation, useNavigation, screensetRegistry, useAppSelector, useTheme, getLanguageMetadata, LanguageDisplayMode, SUPPORTED_LANGUAGES, TextDirection, toggleMockMode } from '@hai3/react';
3
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
- import { Card, Button, ButtonSize, ButtonVariant, DropdownMenu, DropdownMenuTrigger, DropdownButton, DropdownMenuContent, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuItem, Switch } from '@hai3/uikit';
1
+ import React2, { createContext, useContext, useState, useEffect, useCallback, useRef } from 'react';
2
+ import { I18nRegistry, Language, i18nRegistry, eventBus, useHAI3, useTranslation, HAI3_SCREEN_DOMAIN, HAI3_ACTION_MOUNT_EXT, useRegisteredPackages, useActivePackage, useAppSelector, useTheme, getLanguageMetadata, LanguageDisplayMode, SUPPORTED_LANGUAGES, TextDirection, toggleMockMode } from '@hai3/react';
3
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
+ import { clsx } from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
+ import { Slot } from '@radix-ui/react-slot';
7
+ import { cva } from 'class-variance-authority';
5
8
  import { clamp, upperFirst } from 'lodash';
9
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
10
+ import * as SwitchPrimitives from '@radix-ui/react-switch';
6
11
 
7
12
  var __create = Object.create;
8
13
  var __defProp = Object.defineProperty;
@@ -45,7 +50,8 @@ var require_en = __commonJS({
45
50
  screenset: "Screenset:",
46
51
  theme: "Theme:",
47
52
  language: "Language:",
48
- mockApi: "Mock API"
53
+ mockApi: "Mock API",
54
+ gts_package: "GTS Package"
49
55
  }
50
56
  };
51
57
  }
@@ -66,7 +72,8 @@ var require_ar = __commonJS({
66
72
  screenset: "\u0645\u062C\u0645\u0648\u0639\u0629 \u0627\u0644\u0634\u0627\u0634\u0627\u062A:",
67
73
  theme: "\u0627\u0644\u0633\u0645\u0629:",
68
74
  language: "\u0627\u0644\u0644\u063A\u0629:",
69
- mockApi: "\u0648\u0627\u062C\u0647\u0629 \u0628\u0631\u0645\u062C\u064A\u0629 \u0648\u0647\u0645\u064A\u0629"
75
+ mockApi: "\u0648\u0627\u062C\u0647\u0629 \u0628\u0631\u0645\u062C\u064A\u0629 \u0648\u0647\u0645\u064A\u0629",
76
+ gts_package: "GTS Package"
70
77
  }
71
78
  };
72
79
  }
@@ -87,7 +94,8 @@ var require_bn = __commonJS({
87
94
  screenset: "\u09B8\u09CD\u0995\u09CD\u09B0\u09BF\u09A8\u09B8\u09C7\u099F:",
88
95
  theme: "\u09A5\u09BF\u09AE:",
89
96
  language: "\u09AD\u09BE\u09B7\u09BE:",
90
- mockApi: "\u09AE\u0995 API"
97
+ mockApi: "\u09AE\u0995 API",
98
+ gts_package: "GTS Package"
91
99
  }
92
100
  };
93
101
  }
@@ -108,7 +116,8 @@ var require_cs = __commonJS({
108
116
  screenset: "Sada obrazovek:",
109
117
  theme: "Motiv:",
110
118
  language: "Jazyk:",
111
- mockApi: "Simulovan\xE9 API"
119
+ mockApi: "Simulovan\xE9 API",
120
+ gts_package: "GTS Package"
112
121
  }
113
122
  };
114
123
  }
@@ -129,7 +138,8 @@ var require_da = __commonJS({
129
138
  screenset: "Sk\xE6rms\xE6t:",
130
139
  theme: "Tema:",
131
140
  language: "Sprog:",
132
- mockApi: "Mock-API"
141
+ mockApi: "Mock-API",
142
+ gts_package: "GTS Package"
133
143
  }
134
144
  };
135
145
  }
@@ -150,7 +160,8 @@ var require_de = __commonJS({
150
160
  screenset: "Bildschirmset:",
151
161
  theme: "Design:",
152
162
  language: "Sprache:",
153
- mockApi: "Mock-API"
163
+ mockApi: "Mock-API",
164
+ gts_package: "GTS Package"
154
165
  }
155
166
  };
156
167
  }
@@ -171,7 +182,8 @@ var require_el = __commonJS({
171
182
  screenset: "\u03A3\u03CD\u03BD\u03BF\u03BB\u03BF \u039F\u03B8\u03BF\u03BD\u03CE\u03BD:",
172
183
  theme: "\u0398\u03AD\u03BC\u03B1:",
173
184
  language: "\u0393\u03BB\u03CE\u03C3\u03C3\u03B1:",
174
- mockApi: "Mock API"
185
+ mockApi: "Mock API",
186
+ gts_package: "GTS Package"
175
187
  }
176
188
  };
177
189
  }
@@ -192,7 +204,8 @@ var require_es = __commonJS({
192
204
  screenset: "Conjunto de Pantallas:",
193
205
  theme: "Tema:",
194
206
  language: "Idioma:",
195
- mockApi: "API Simulada"
207
+ mockApi: "API Simulada",
208
+ gts_package: "GTS Package"
196
209
  }
197
210
  };
198
211
  }
@@ -213,7 +226,8 @@ var require_fa = __commonJS({
213
226
  screenset: "\u0645\u062C\u0645\u0648\u0639\u0647 \u0635\u0641\u062D\u0647\u200C\u0646\u0645\u0627\u06CC\u0634:",
214
227
  theme: "\u067E\u0648\u0633\u062A\u0647:",
215
228
  language: "\u0632\u0628\u0627\u0646:",
216
- mockApi: "API \u0633\u0627\u062E\u062A\u06AF\u06CC"
229
+ mockApi: "API \u0633\u0627\u062E\u062A\u06AF\u06CC",
230
+ gts_package: "GTS Package"
217
231
  }
218
232
  };
219
233
  }
@@ -234,7 +248,8 @@ var require_fi = __commonJS({
234
248
  screenset: "N\xE4ytt\xF6sarja:",
235
249
  theme: "Teema:",
236
250
  language: "Kieli:",
237
- mockApi: "Mock-API"
251
+ mockApi: "Mock-API",
252
+ gts_package: "GTS Package"
238
253
  }
239
254
  };
240
255
  }
@@ -255,7 +270,8 @@ var require_fr = __commonJS({
255
270
  screenset: "Ensemble d'\xC9crans:",
256
271
  theme: "Th\xE8me:",
257
272
  language: "Langue:",
258
- mockApi: "API Simul\xE9e"
273
+ mockApi: "API Simul\xE9e",
274
+ gts_package: "GTS Package"
259
275
  }
260
276
  };
261
277
  }
@@ -276,7 +292,8 @@ var require_he = __commonJS({
276
292
  screenset: "\u05E2\u05E8\u05DB\u05EA \u05DE\u05E1\u05DB\u05D9\u05DD:",
277
293
  theme: "\u05E2\u05E8\u05DB\u05EA \u05E0\u05D5\u05E9\u05D0:",
278
294
  language: "\u05E9\u05E4\u05D4:",
279
- mockApi: "API \u05DE\u05D3\u05D5\u05DE\u05D4"
295
+ mockApi: "API \u05DE\u05D3\u05D5\u05DE\u05D4",
296
+ gts_package: "GTS Package"
280
297
  }
281
298
  };
282
299
  }
@@ -297,7 +314,8 @@ var require_hi = __commonJS({
297
314
  screenset: "\u0938\u094D\u0915\u094D\u0930\u0940\u0928\u0938\u0947\u091F:",
298
315
  theme: "\u0925\u0940\u092E:",
299
316
  language: "\u092D\u093E\u0937\u093E:",
300
- mockApi: "\u092E\u0949\u0915 API"
317
+ mockApi: "\u092E\u0949\u0915 API",
318
+ gts_package: "GTS Package"
301
319
  }
302
320
  };
303
321
  }
@@ -318,7 +336,8 @@ var require_hu = __commonJS({
318
336
  screenset: "K\xE9perny\u0151k\xE9szlet:",
319
337
  theme: "T\xE9ma:",
320
338
  language: "Nyelv:",
321
- mockApi: "Mock API"
339
+ mockApi: "Mock API",
340
+ gts_package: "GTS Package"
322
341
  }
323
342
  };
324
343
  }
@@ -339,7 +358,8 @@ var require_id = __commonJS({
339
358
  screenset: "Set Layar:",
340
359
  theme: "Tema:",
341
360
  language: "Bahasa:",
342
- mockApi: "API Tiruan"
361
+ mockApi: "API Tiruan",
362
+ gts_package: "GTS Package"
343
363
  }
344
364
  };
345
365
  }
@@ -360,7 +380,8 @@ var require_it = __commonJS({
360
380
  screenset: "Set di Schermate:",
361
381
  theme: "Tema:",
362
382
  language: "Lingua:",
363
- mockApi: "API Simulata"
383
+ mockApi: "API Simulata",
384
+ gts_package: "GTS Package"
364
385
  }
365
386
  };
366
387
  }
@@ -381,7 +402,8 @@ var require_ja = __commonJS({
381
402
  screenset: "\u30B9\u30AF\u30EA\u30FC\u30F3\u30BB\u30C3\u30C8:",
382
403
  theme: "\u30C6\u30FC\u30DE:",
383
404
  language: "\u8A00\u8A9E:",
384
- mockApi: "\u30E2\u30C3\u30AF API"
405
+ mockApi: "\u30E2\u30C3\u30AF API",
406
+ gts_package: "GTS Package"
385
407
  }
386
408
  };
387
409
  }
@@ -402,7 +424,8 @@ var require_ko = __commonJS({
402
424
  screenset: "\uD654\uBA74 \uC138\uD2B8:",
403
425
  theme: "\uD14C\uB9C8:",
404
426
  language: "\uC5B8\uC5B4:",
405
- mockApi: "\uBAA8\uC758 API"
427
+ mockApi: "\uBAA8\uC758 API",
428
+ gts_package: "GTS Package"
406
429
  }
407
430
  };
408
431
  }
@@ -423,7 +446,8 @@ var require_ms = __commonJS({
423
446
  screenset: "Set Skrin:",
424
447
  theme: "Tema:",
425
448
  language: "Bahasa:",
426
- mockApi: "API Palsu"
449
+ mockApi: "API Palsu",
450
+ gts_package: "GTS Package"
427
451
  }
428
452
  };
429
453
  }
@@ -444,7 +468,8 @@ var require_nl = __commonJS({
444
468
  screenset: "Schermset:",
445
469
  theme: "Thema:",
446
470
  language: "Taal:",
447
- mockApi: "Nep-API"
471
+ mockApi: "Nep-API",
472
+ gts_package: "GTS Package"
448
473
  }
449
474
  };
450
475
  }
@@ -465,7 +490,8 @@ var require_no = __commonJS({
465
490
  screenset: "Skjermsett:",
466
491
  theme: "Tema:",
467
492
  language: "Spr\xE5k:",
468
- mockApi: "Mock-API"
493
+ mockApi: "Mock-API",
494
+ gts_package: "GTS Package"
469
495
  }
470
496
  };
471
497
  }
@@ -486,7 +512,8 @@ var require_pl = __commonJS({
486
512
  screenset: "Zestaw ekran\xF3w:",
487
513
  theme: "Motyw:",
488
514
  language: "J\u0119zyk:",
489
- mockApi: "Fikcyjne API"
515
+ mockApi: "Fikcyjne API",
516
+ gts_package: "GTS Package"
490
517
  }
491
518
  };
492
519
  }
@@ -507,7 +534,8 @@ var require_pt = __commonJS({
507
534
  screenset: "Conjunto de Telas:",
508
535
  theme: "Tema:",
509
536
  language: "Idioma:",
510
- mockApi: "API Simulada"
537
+ mockApi: "API Simulada",
538
+ gts_package: "GTS Package"
511
539
  }
512
540
  };
513
541
  }
@@ -528,7 +556,8 @@ var require_ro = __commonJS({
528
556
  screenset: "Set de Ecrane:",
529
557
  theme: "Tem\u0103:",
530
558
  language: "Limb\u0103:",
531
- mockApi: "API Simulat"
559
+ mockApi: "API Simulat",
560
+ gts_package: "GTS Package"
532
561
  }
533
562
  };
534
563
  }
@@ -549,7 +578,8 @@ var require_ru = __commonJS({
549
578
  screenset: "\u041D\u0430\u0431\u043E\u0440 \u044D\u043A\u0440\u0430\u043D\u043E\u0432:",
550
579
  theme: "\u0422\u0435\u043C\u0430:",
551
580
  language: "\u042F\u0437\u044B\u043A:",
552
- mockApi: "\u0424\u0438\u043A\u0442\u0438\u0432\u043D\u044B\u0439 API"
581
+ mockApi: "\u0424\u0438\u043A\u0442\u0438\u0432\u043D\u044B\u0439 API",
582
+ gts_package: "GTS Package"
553
583
  }
554
584
  };
555
585
  }
@@ -570,7 +600,8 @@ var require_sv = __commonJS({
570
600
  screenset: "Sk\xE4rmupps\xE4ttning:",
571
601
  theme: "Tema:",
572
602
  language: "Spr\xE5k:",
573
- mockApi: "Mock-API"
603
+ mockApi: "Mock-API",
604
+ gts_package: "GTS Package"
574
605
  }
575
606
  };
576
607
  }
@@ -591,7 +622,8 @@ var require_sw = __commonJS({
591
622
  screenset: "Seti ya Skrini:",
592
623
  theme: "Mandhari:",
593
624
  language: "Lugha:",
594
- mockApi: "API ya Majaribio"
625
+ mockApi: "API ya Majaribio",
626
+ gts_package: "GTS Package"
595
627
  }
596
628
  };
597
629
  }
@@ -612,7 +644,8 @@ var require_ta = __commonJS({
612
644
  screenset: "\u0BA4\u0BBF\u0BB0\u0BC8\u0BA4\u0BCD \u0BA4\u0BCA\u0B95\u0BC1\u0BAA\u0BCD\u0BAA\u0BC1:",
613
645
  theme: "\u0BA4\u0BC0\u0BAE\u0BCD:",
614
646
  language: "\u0BAE\u0BCA\u0BB4\u0BBF:",
615
- mockApi: "\u0BAA\u0BCB\u0BB2\u0BBF API"
647
+ mockApi: "\u0BAA\u0BCB\u0BB2\u0BBF API",
648
+ gts_package: "GTS Package"
616
649
  }
617
650
  };
618
651
  }
@@ -633,7 +666,8 @@ var require_th = __commonJS({
633
666
  screenset: "\u0E0A\u0E38\u0E14\u0E2B\u0E19\u0E49\u0E32\u0E08\u0E2D:",
634
667
  theme: "\u0E18\u0E35\u0E21:",
635
668
  language: "\u0E20\u0E32\u0E29\u0E32:",
636
- mockApi: "API \u0E08\u0E33\u0E25\u0E2D\u0E07"
669
+ mockApi: "API \u0E08\u0E33\u0E25\u0E2D\u0E07",
670
+ gts_package: "GTS Package"
637
671
  }
638
672
  };
639
673
  }
@@ -654,7 +688,8 @@ var require_tl = __commonJS({
654
688
  screenset: "Hanay ng Screen:",
655
689
  theme: "Tema:",
656
690
  language: "Wika:",
657
- mockApi: "Mock API"
691
+ mockApi: "Mock API",
692
+ gts_package: "GTS Package"
658
693
  }
659
694
  };
660
695
  }
@@ -675,7 +710,8 @@ var require_tr = __commonJS({
675
710
  screenset: "Ekran Seti:",
676
711
  theme: "Tema:",
677
712
  language: "Dil:",
678
- mockApi: "Sahte API"
713
+ mockApi: "Sahte API",
714
+ gts_package: "GTS Package"
679
715
  }
680
716
  };
681
717
  }
@@ -696,7 +732,8 @@ var require_uk = __commonJS({
696
732
  screenset: "\u041D\u0430\u0431\u0456\u0440 \u0435\u043A\u0440\u0430\u043D\u0456\u0432:",
697
733
  theme: "\u0422\u0435\u043C\u0430:",
698
734
  language: "\u041C\u043E\u0432\u0430:",
699
- mockApi: "\u0424\u0456\u043A\u0442\u0438\u0432\u043D\u0438\u0439 API"
735
+ mockApi: "\u0424\u0456\u043A\u0442\u0438\u0432\u043D\u0438\u0439 API",
736
+ gts_package: "GTS Package"
700
737
  }
701
738
  };
702
739
  }
@@ -717,7 +754,8 @@ var require_ur = __commonJS({
717
754
  screenset: "\u0627\u0633\u06A9\u0631\u06CC\u0646 \u0633\u06CC\u0679:",
718
755
  theme: "\u062A\u06BE\u06CC\u0645:",
719
756
  language: "\u0632\u0628\u0627\u0646:",
720
- mockApi: "\u0641\u0631\u0636\u06CC API"
757
+ mockApi: "\u0641\u0631\u0636\u06CC API",
758
+ gts_package: "GTS Package"
721
759
  }
722
760
  };
723
761
  }
@@ -738,7 +776,8 @@ var require_vi = __commonJS({
738
776
  screenset: "B\u1ED9 M\xE0n h\xECnh:",
739
777
  theme: "Ch\u1EE7 \u0111\u1EC1:",
740
778
  language: "Ng\xF4n ng\u1EEF:",
741
- mockApi: "API Gi\u1EA3 l\u1EADp"
779
+ mockApi: "API Gi\u1EA3 l\u1EADp",
780
+ gts_package: "GTS Package"
742
781
  }
743
782
  };
744
783
  }
@@ -759,7 +798,8 @@ var require_zh_TW = __commonJS({
759
798
  screenset: "\u87A2\u5E55\u96C6:",
760
799
  theme: "\u4E3B\u984C:",
761
800
  language: "\u8A9E\u8A00:",
762
- mockApi: "\u6A21\u64EC API"
801
+ mockApi: "\u6A21\u64EC API",
802
+ gts_package: "GTS Package"
763
803
  }
764
804
  };
765
805
  }
@@ -780,7 +820,8 @@ var require_zh = __commonJS({
780
820
  screenset: "\u5C4F\u5E55\u96C6:",
781
821
  theme: "\u4E3B\u9898:",
782
822
  language: "\u8BED\u8A00:",
783
- mockApi: "\u6A21\u62DF API"
823
+ mockApi: "\u6A21\u62DF API",
824
+ gts_package: "GTS Package"
784
825
  }
785
826
  };
786
827
  }
@@ -822,14 +863,19 @@ var STORAGE_KEYS = {
822
863
  POSITION: `${STORAGE_PREFIX}position`,
823
864
  SIZE: `${STORAGE_PREFIX}size`,
824
865
  COLLAPSED: `${STORAGE_PREFIX}collapsed`,
825
- BUTTON_POSITION: `${STORAGE_PREFIX}buttonPosition`
866
+ BUTTON_POSITION: `${STORAGE_PREFIX}buttonPosition`,
867
+ THEME: `${STORAGE_PREFIX}theme`,
868
+ LANGUAGE: `${STORAGE_PREFIX}language`,
869
+ MOCK_ENABLED: `${STORAGE_PREFIX}mockEnabled`,
870
+ ACTIVE_PACKAGE_ID: `${STORAGE_PREFIX}activePackageId`
826
871
  };
827
872
 
828
873
  // src/events/studioEvents.ts
829
874
  var StudioEvents = {
830
875
  PositionChanged: "studio/positionChanged",
831
876
  SizeChanged: "studio/sizeChanged",
832
- ButtonPositionChanged: "studio/buttonPositionChanged"
877
+ ButtonPositionChanged: "studio/buttonPositionChanged",
878
+ ActivePackageChanged: "studio/activePackageChanged"
833
879
  };
834
880
 
835
881
  // src/effects/persistenceEffects.ts
@@ -852,12 +898,82 @@ var initPersistenceEffects = () => {
852
898
  saveStudioState(STORAGE_KEYS.BUTTON_POSITION, position);
853
899
  }
854
900
  );
901
+ const themeSubscription = eventBus.on("theme/changed", (payload) => {
902
+ saveStudioState(STORAGE_KEYS.THEME, payload.themeId);
903
+ });
904
+ const languageSubscription = eventBus.on("i18n/language/changed", (payload) => {
905
+ saveStudioState(STORAGE_KEYS.LANGUAGE, payload.language);
906
+ });
907
+ const mockSubscription = eventBus.on("mock/toggle", (payload) => {
908
+ saveStudioState(STORAGE_KEYS.MOCK_ENABLED, payload.enabled);
909
+ });
910
+ const activePackageSubscription = eventBus.on(
911
+ StudioEvents.ActivePackageChanged,
912
+ ({ activePackageId }) => {
913
+ saveStudioState(STORAGE_KEYS.ACTIVE_PACKAGE_ID, activePackageId);
914
+ }
915
+ );
855
916
  return () => {
856
917
  positionSubscription.unsubscribe();
857
918
  sizeSubscription.unsubscribe();
858
919
  buttonPositionSubscription.unsubscribe();
920
+ themeSubscription.unsubscribe();
921
+ languageSubscription.unsubscribe();
922
+ mockSubscription.unsubscribe();
923
+ activePackageSubscription.unsubscribe();
859
924
  };
860
925
  };
926
+ function isScreenExtension(ext) {
927
+ return "presentation" in ext && typeof ext.presentation === "object";
928
+ }
929
+ var useRestoreStudioSettings = () => {
930
+ const restoredRef = useRef(false);
931
+ useEffect(() => {
932
+ if (restoredRef.current) return;
933
+ restoredRef.current = true;
934
+ const themeId = loadStudioState(STORAGE_KEYS.THEME, null);
935
+ if (themeId != null && typeof themeId === "string" && themeId.length > 0) {
936
+ eventBus.emit("theme/changed", { themeId });
937
+ }
938
+ const language = loadStudioState(STORAGE_KEYS.LANGUAGE, null);
939
+ if (language != null && typeof language === "string" && language.length > 0) {
940
+ eventBus.emit("i18n/language/changed", { language });
941
+ }
942
+ const mockEnabled = loadStudioState(STORAGE_KEYS.MOCK_ENABLED, null);
943
+ if (typeof mockEnabled === "boolean") {
944
+ eventBus.emit("mock/toggle", { enabled: mockEnabled });
945
+ }
946
+ }, []);
947
+ };
948
+ var useRestoreGtsPackage = (registry) => {
949
+ const restoredRef = useRef(false);
950
+ useEffect(() => {
951
+ if (restoredRef.current || !registry) return;
952
+ const activePackageId = loadStudioState(STORAGE_KEYS.ACTIVE_PACKAGE_ID, null);
953
+ if (!activePackageId || typeof activePackageId !== "string") return;
954
+ restoredRef.current = true;
955
+ const restore = async () => {
956
+ try {
957
+ const extensions = registry.getExtensionsForPackage(activePackageId);
958
+ const screenExtensions = extensions.filter(
959
+ (ext) => ext.domain === HAI3_SCREEN_DOMAIN && isScreenExtension(ext)
960
+ );
961
+ if (screenExtensions.length === 0) return;
962
+ screenExtensions.sort((a, b) => (a.presentation.order ?? 0) - (b.presentation.order ?? 0));
963
+ const firstExtension = screenExtensions[0];
964
+ await registry.executeActionsChain({
965
+ action: {
966
+ type: HAI3_ACTION_MOUNT_EXT,
967
+ target: HAI3_SCREEN_DOMAIN,
968
+ payload: { extensionId: firstExtension.id }
969
+ }
970
+ });
971
+ } catch {
972
+ }
973
+ };
974
+ void restore();
975
+ }, [registry]);
976
+ };
861
977
  var studioTranslations = I18nRegistry.createLoader({
862
978
  [Language.English]: () => Promise.resolve().then(() => __toESM(require_en())),
863
979
  [Language.Arabic]: () => Promise.resolve().then(() => __toESM(require_ar())),
@@ -898,6 +1014,11 @@ var studioTranslations = I18nRegistry.createLoader({
898
1014
  });
899
1015
  i18nRegistry.registerLoader("studio", studioTranslations);
900
1016
  var StudioContext = createContext(void 0);
1017
+ var RestoreGtsPackageOnMount = () => {
1018
+ const app = useHAI3();
1019
+ useRestoreGtsPackage(app.screensetsRegistry);
1020
+ return null;
1021
+ };
901
1022
  var useStudioContext = () => {
902
1023
  const context = useContext(StudioContext);
903
1024
  if (!context) {
@@ -914,6 +1035,7 @@ var StudioProvider = ({ children }) => {
914
1035
  const cleanup = initPersistenceEffects();
915
1036
  return cleanup;
916
1037
  }, []);
1038
+ useRestoreStudioSettings();
917
1039
  const toggleCollapsed = useCallback(() => {
918
1040
  setCollapsed((prev) => {
919
1041
  const newValue = !prev;
@@ -921,7 +1043,7 @@ var StudioProvider = ({ children }) => {
921
1043
  return newValue;
922
1044
  });
923
1045
  }, []);
924
- return /* @__PURE__ */ jsx(
1046
+ return /* @__PURE__ */ jsxs(
925
1047
  StudioContext.Provider,
926
1048
  {
927
1049
  value: {
@@ -930,11 +1052,77 @@ var StudioProvider = ({ children }) => {
930
1052
  portalContainer,
931
1053
  setPortalContainer
932
1054
  },
933
- children
1055
+ children: [
1056
+ /* @__PURE__ */ jsx(RestoreGtsPackageOnMount, {}),
1057
+ children
1058
+ ]
934
1059
  }
935
1060
  );
936
1061
  };
937
1062
  StudioProvider.displayName = "StudioProvider";
1063
+ function cn(...inputs) {
1064
+ return twMerge(clsx(inputs));
1065
+ }
1066
+ var Card = ({
1067
+ ref,
1068
+ className,
1069
+ ...props
1070
+ }) => /* @__PURE__ */ jsx(
1071
+ "div",
1072
+ {
1073
+ ref,
1074
+ className: cn(
1075
+ "rounded-xl border bg-card text-card-foreground shadow",
1076
+ className
1077
+ ),
1078
+ ...props
1079
+ }
1080
+ );
1081
+ Card.displayName = "Card";
1082
+ var buttonVariants = cva(
1083
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
1084
+ {
1085
+ variants: {
1086
+ variant: {
1087
+ ["default" /* Default */]: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
1088
+ ["destructive" /* Destructive */]: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
1089
+ ["outline" /* Outline */]: "border border-input bg-background text-foreground shadow-sm hover:bg-accent data-[state=open]:bg-accent",
1090
+ ["secondary" /* Secondary */]: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
1091
+ ["ghost" /* Ghost */]: "hover:bg-accent data-[state=open]:bg-accent",
1092
+ ["link" /* Link */]: "text-primary underline-offset-4 hover:underline"
1093
+ },
1094
+ size: {
1095
+ ["default" /* Default */]: "h-9 px-4 py-2",
1096
+ ["sm" /* Sm */]: "h-8 rounded-md px-3 text-xs",
1097
+ ["lg" /* Lg */]: "h-10 rounded-md px-8",
1098
+ ["icon" /* Icon */]: "h-9 w-9"
1099
+ }
1100
+ },
1101
+ defaultVariants: {
1102
+ variant: "default" /* Default */,
1103
+ size: "default" /* Default */
1104
+ }
1105
+ }
1106
+ );
1107
+ var Button = ({
1108
+ ref,
1109
+ className,
1110
+ variant,
1111
+ size,
1112
+ asChild = false,
1113
+ ...props
1114
+ }) => {
1115
+ const Comp = asChild ? Slot : "button";
1116
+ return /* @__PURE__ */ jsx(
1117
+ Comp,
1118
+ {
1119
+ className: cn(buttonVariants({ variant, size, className })),
1120
+ ref,
1121
+ ...props
1122
+ }
1123
+ );
1124
+ };
1125
+ Button.displayName = "Button";
938
1126
  var VIEWPORT_MARGIN = 20;
939
1127
  function clampToViewport(pos, size) {
940
1128
  const maxX = Math.max(VIEWPORT_MARGIN, window.innerWidth - size.width - VIEWPORT_MARGIN);
@@ -1064,6 +1252,148 @@ var useResizable = () => {
1064
1252
  handleMouseDown
1065
1253
  };
1066
1254
  };
1255
+ var DropdownMenu = ({
1256
+ dir,
1257
+ ...props
1258
+ }) => /* @__PURE__ */ jsx(
1259
+ DropdownMenuPrimitive.Root,
1260
+ {
1261
+ ...props,
1262
+ dir
1263
+ }
1264
+ );
1265
+ DropdownMenu.displayName = "DropdownMenu";
1266
+ var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
1267
+ var DropdownMenuContent = ({
1268
+ ref,
1269
+ className,
1270
+ sideOffset = 4,
1271
+ container,
1272
+ ...props
1273
+ }) => /* @__PURE__ */ jsx(DropdownMenuPrimitive.Portal, { container: container ?? void 0, children: /* @__PURE__ */ jsx(
1274
+ DropdownMenuPrimitive.Content,
1275
+ {
1276
+ ref,
1277
+ sideOffset,
1278
+ style: { backgroundColor: "hsl(var(--background, 0 0% 100%))" },
1279
+ className: cn(
1280
+ "z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
1281
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
1282
+ className
1283
+ ),
1284
+ ...props
1285
+ }
1286
+ ) });
1287
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
1288
+ var DropdownMenuItem = ({
1289
+ ref,
1290
+ className,
1291
+ inset,
1292
+ ...props
1293
+ }) => /* @__PURE__ */ jsx(
1294
+ DropdownMenuPrimitive.Item,
1295
+ {
1296
+ ref,
1297
+ className: cn(
1298
+ "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
1299
+ inset && "pl-8",
1300
+ className
1301
+ ),
1302
+ ...props
1303
+ }
1304
+ );
1305
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
1306
+ var ChevronDownIcon = ({ className = "" }) => /* @__PURE__ */ jsx(
1307
+ "svg",
1308
+ {
1309
+ className,
1310
+ fill: "none",
1311
+ stroke: "currentColor",
1312
+ strokeWidth: 2,
1313
+ viewBox: "0 0 24 24",
1314
+ children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" })
1315
+ }
1316
+ );
1317
+ var DropdownButton = ({
1318
+ ref,
1319
+ children,
1320
+ variant = "outline" /* Outline */,
1321
+ className,
1322
+ ...props
1323
+ }) => {
1324
+ return /* @__PURE__ */ jsxs(
1325
+ Button,
1326
+ {
1327
+ ref,
1328
+ variant,
1329
+ className: cn("min-w-40 justify-between rtl:flex-row-reverse", className),
1330
+ ...props,
1331
+ children: [
1332
+ /* @__PURE__ */ jsx("span", { children }),
1333
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "h-4 w-4" })
1334
+ ]
1335
+ }
1336
+ );
1337
+ };
1338
+ DropdownButton.displayName = "DropdownButton";
1339
+ function isScreenExtension2(ext) {
1340
+ return "presentation" in ext && typeof ext.presentation === "object";
1341
+ }
1342
+ var MfePackageSelector = ({
1343
+ className = ""
1344
+ }) => {
1345
+ const app = useHAI3();
1346
+ const registry = app.screensetsRegistry;
1347
+ const { portalContainer } = useStudioContext();
1348
+ const { t } = useTranslation();
1349
+ const packages = useRegisteredPackages();
1350
+ const activePackage = useActivePackage();
1351
+ if (!registry) {
1352
+ return null;
1353
+ }
1354
+ const handlePackageChange = async (selectedPackageId) => {
1355
+ const extensions = registry.getExtensionsForPackage(selectedPackageId);
1356
+ const screenExtensions = extensions.filter(
1357
+ (ext) => ext.domain === HAI3_SCREEN_DOMAIN && isScreenExtension2(ext)
1358
+ );
1359
+ if (screenExtensions.length === 0) {
1360
+ console.warn(`No screen extensions found for package: ${selectedPackageId}`);
1361
+ return;
1362
+ }
1363
+ screenExtensions.sort((a, b) => (a.presentation.order ?? 0) - (b.presentation.order ?? 0));
1364
+ const firstExtension = screenExtensions[0];
1365
+ await registry.executeActionsChain({
1366
+ action: {
1367
+ type: HAI3_ACTION_MOUNT_EXT,
1368
+ target: HAI3_SCREEN_DOMAIN,
1369
+ payload: { extensionId: firstExtension.id }
1370
+ }
1371
+ });
1372
+ eventBus.emit(StudioEvents.ActivePackageChanged, { activePackageId: selectedPackageId });
1373
+ };
1374
+ return /* @__PURE__ */ jsxs("div", { className: `flex items-center justify-between ${className}`, children: [
1375
+ /* @__PURE__ */ jsx("label", { className: "text-sm text-muted-foreground whitespace-nowrap", children: t("studio:controls.gts_package") }),
1376
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
1377
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
1378
+ DropdownButton,
1379
+ {
1380
+ variant: "outline" /* Outline */,
1381
+ disabled: packages.length <= 1,
1382
+ children: activePackage || "No package"
1383
+ }
1384
+ ) }),
1385
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: packages.map((pkg) => /* @__PURE__ */ jsx(
1386
+ DropdownMenuItem,
1387
+ {
1388
+ onClick: () => handlePackageChange(pkg),
1389
+ children: pkg
1390
+ },
1391
+ pkg
1392
+ )) })
1393
+ ] })
1394
+ ] });
1395
+ };
1396
+ MfePackageSelector.displayName = "MfePackageSelector";
1067
1397
  var ThemeSelector = ({
1068
1398
  className = ""
1069
1399
  }) => {
@@ -1076,7 +1406,7 @@ var ThemeSelector = ({
1076
1406
  return /* @__PURE__ */ jsxs("div", { className: `flex items-center justify-between ${className}`, children: [
1077
1407
  /* @__PURE__ */ jsx("label", { className: "text-sm text-muted-foreground whitespace-nowrap", children: t("studio:controls.theme") }),
1078
1408
  /* @__PURE__ */ jsxs(DropdownMenu, { children: [
1079
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownButton, { variant: ButtonVariant.Outline, children: formatThemeName(currentTheme || "") }) }),
1409
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownButton, { variant: "outline" /* Outline */, children: formatThemeName(currentTheme || "") }) }),
1080
1410
  /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: themes.map((theme) => /* @__PURE__ */ jsx(
1081
1411
  DropdownMenuItem,
1082
1412
  {
@@ -1089,46 +1419,6 @@ var ThemeSelector = ({
1089
1419
  ] });
1090
1420
  };
1091
1421
  ThemeSelector.displayName = "ThemeSelector";
1092
- var ScreensetSelector = ({
1093
- options,
1094
- currentValue,
1095
- onChange,
1096
- className = ""
1097
- }) => {
1098
- const { portalContainer } = useStudioContext();
1099
- const { t, isRTL } = useTranslation();
1100
- const formatName = (name) => {
1101
- return name.split(/[-_]/).map((word) => upperFirst(word)).join(" ");
1102
- };
1103
- const getCurrentDisplay = () => {
1104
- const [category, itemId] = currentValue.split(":");
1105
- if (!category || !itemId) return "Select";
1106
- const categoryGroup = options.find((opt) => opt.category === category);
1107
- const item = categoryGroup?.screensets.find((i) => i.id === itemId);
1108
- return item ? item.name : "Select";
1109
- };
1110
- const handleItemClick = (category, itemId) => {
1111
- onChange(`${category}:${itemId}`);
1112
- };
1113
- return /* @__PURE__ */ jsxs("div", { className: `flex items-center justify-between ${className}`, children: [
1114
- /* @__PURE__ */ jsx("label", { className: "text-sm text-muted-foreground whitespace-nowrap", children: t("studio:controls.screenset") }),
1115
- /* @__PURE__ */ jsxs(DropdownMenu, { dir: isRTL ? "rtl" : "ltr", children: [
1116
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownButton, { variant: ButtonVariant.Outline, children: formatName(getCurrentDisplay()) }) }),
1117
- /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: options.map((categoryGroup) => /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
1118
- /* @__PURE__ */ jsx(DropdownMenuSubTrigger, { disabled: categoryGroup.screensets.length === 0, children: formatName(categoryGroup.category) }),
1119
- /* @__PURE__ */ jsx(DropdownMenuSubContent, { container: portalContainer, className: "z-[99999] pointer-events-auto", children: categoryGroup.screensets.map((item) => /* @__PURE__ */ jsx(
1120
- DropdownMenuItem,
1121
- {
1122
- onClick: () => handleItemClick(categoryGroup.category, item.id),
1123
- children: formatName(item.name)
1124
- },
1125
- item.id
1126
- )) })
1127
- ] }, categoryGroup.category)) })
1128
- ] })
1129
- ] });
1130
- };
1131
- ScreensetSelector.displayName = "ScreensetSelector";
1132
1422
  var FALLBACK_SELECT_LANGUAGE_TEXT = "Select language";
1133
1423
  var RTL_INDICATOR_SUFFIX = " (RTL)";
1134
1424
  function LanguageSelector({
@@ -1140,7 +1430,7 @@ function LanguageSelector({
1140
1430
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1141
1431
  /* @__PURE__ */ jsx("label", { className: "text-sm text-muted-foreground whitespace-nowrap", children: t("studio:controls.language") }),
1142
1432
  /* @__PURE__ */ jsxs(DropdownMenu, { children: [
1143
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: ButtonVariant.Outline, children: currentLanguage ? displayMode === LanguageDisplayMode.Native ? currentLanguage.name : currentLanguage.englishName : FALLBACK_SELECT_LANGUAGE_TEXT }) }),
1433
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "outline" /* Outline */, children: currentLanguage ? displayMode === LanguageDisplayMode.Native ? currentLanguage.name : currentLanguage.englishName : FALLBACK_SELECT_LANGUAGE_TEXT }) }),
1144
1434
  /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: SUPPORTED_LANGUAGES.map((lang) => /* @__PURE__ */ jsxs(
1145
1435
  DropdownMenuItem,
1146
1436
  {
@@ -1155,6 +1445,32 @@ function LanguageSelector({
1155
1445
  ] })
1156
1446
  ] });
1157
1447
  }
1448
+ var Switch = ({
1449
+ ref,
1450
+ className,
1451
+ ...props
1452
+ }) => /* @__PURE__ */ jsx(
1453
+ SwitchPrimitives.Root,
1454
+ {
1455
+ className: cn(
1456
+ "peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
1457
+ className
1458
+ ),
1459
+ ...props,
1460
+ ref,
1461
+ children: /* @__PURE__ */ jsx(
1462
+ SwitchPrimitives.Thumb,
1463
+ {
1464
+ className: cn(
1465
+ "pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform",
1466
+ "data-[state=checked]:ltr:translate-x-4 data-[state=checked]:rtl:-translate-x-4",
1467
+ "data-[state=unchecked]:translate-x-0"
1468
+ )
1469
+ }
1470
+ )
1471
+ }
1472
+ );
1473
+ Switch.displayName = SwitchPrimitives.Root.displayName;
1158
1474
  var ApiModeToggle = ({
1159
1475
  className
1160
1476
  }) => {
@@ -1186,48 +1502,12 @@ var ApiModeToggle = ({
1186
1502
  ] });
1187
1503
  };
1188
1504
  ApiModeToggle.displayName = "ApiModeToggle";
1189
- var ALL_CATEGORIES = [ScreensetCategory.Drafts, ScreensetCategory.Mockups, ScreensetCategory.Production];
1190
- var buildScreensetOptions = () => {
1191
- const allScreensets = screensetRegistry.getAll();
1192
- return ALL_CATEGORIES.map((category) => ({
1193
- category,
1194
- screensets: allScreensets.filter((s) => s.category === category).map((s) => ({
1195
- id: s.id,
1196
- name: s.name
1197
- }))
1198
- }));
1199
- };
1200
1505
  var ControlPanel = () => {
1201
- const { currentScreenset, navigateToScreenset } = useNavigation();
1202
- const [screensetOptions, setScreensetOptions] = useState([]);
1203
1506
  const { t } = useTranslation();
1204
- useEffect(() => {
1205
- const options = buildScreensetOptions();
1206
- setScreensetOptions(options);
1207
- }, []);
1208
- const getCurrentValue = () => {
1209
- if (!currentScreenset) return "";
1210
- const screenset = screensetRegistry.get(currentScreenset);
1211
- if (!screenset) return "";
1212
- return `${screenset.category}:${screenset.id}`;
1213
- };
1214
- const handleScreensetChange = (value) => {
1215
- const [, screensetId] = value.split(":");
1216
- if (screensetId) {
1217
- navigateToScreenset(screensetId);
1218
- }
1219
- };
1220
1507
  return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1221
1508
  /* @__PURE__ */ jsx("h3", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: t("studio:controls.heading") }),
1222
1509
  /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1223
- screensetOptions.length > 0 && /* @__PURE__ */ jsx(
1224
- ScreensetSelector,
1225
- {
1226
- options: screensetOptions,
1227
- currentValue: getCurrentValue(),
1228
- onChange: handleScreensetChange
1229
- }
1230
- ),
1510
+ /* @__PURE__ */ jsx(MfePackageSelector, {}),
1231
1511
  /* @__PURE__ */ jsx(ApiModeToggle, {}),
1232
1512
  /* @__PURE__ */ jsx(ThemeSelector, {}),
1233
1513
  /* @__PURE__ */ jsx(LanguageSelector, {})
@@ -1238,13 +1518,13 @@ ControlPanel.displayName = "ControlPanel";
1238
1518
  var StudioPanel = () => {
1239
1519
  const { toggleCollapsed, setPortalContainer } = useStudioContext();
1240
1520
  const { t } = useTranslation();
1241
- const portalRef = React3.useRef(null);
1521
+ const portalRef = React2.useRef(null);
1242
1522
  const { size, handleMouseDown: handleResizeMouseDown } = useResizable();
1243
1523
  const { position, isDragging, handleMouseDown: handleDragMouseDown } = useDraggable({
1244
1524
  panelSize: size,
1245
1525
  storageKey: STORAGE_KEYS.POSITION
1246
1526
  });
1247
- React3.useEffect(() => {
1527
+ React2.useEffect(() => {
1248
1528
  setPortalContainer(portalRef.current);
1249
1529
  return () => setPortalContainer(null);
1250
1530
  }, [setPortalContainer]);
@@ -1278,8 +1558,8 @@ var StudioPanel = () => {
1278
1558
  /* @__PURE__ */ jsx(
1279
1559
  Button,
1280
1560
  {
1281
- variant: ButtonVariant.Ghost,
1282
- size: ButtonSize.Sm,
1561
+ variant: "ghost" /* Ghost */,
1562
+ size: "sm" /* Sm */,
1283
1563
  onClick: toggleCollapsed,
1284
1564
  className: "h-7 w-7 p-0",
1285
1565
  "aria-label": t("studio:aria.collapseButton"),
@@ -1358,7 +1638,7 @@ var GlassmorphicButton = ({
1358
1638
  return /* @__PURE__ */ jsx(
1359
1639
  Button,
1360
1640
  {
1361
- variant: ButtonVariant.Ghost,
1641
+ variant: "ghost" /* Ghost */,
1362
1642
  onMouseDown,
1363
1643
  onClick,
1364
1644
  title,
@@ -1431,6 +1711,278 @@ var CollapsedButton = ({ toggleCollapsed }) => {
1431
1711
  );
1432
1712
  };
1433
1713
  CollapsedButton.displayName = "CollapsedButton";
1714
+
1715
+ // src/styles/studioStyles.ts
1716
+ var STUDIO_STYLE_ID = "hai3-studio-styles";
1717
+ var STUDIO_CSS = (
1718
+ /* css */
1719
+ `
1720
+ /* ============================================================
1721
+ HAI3 Studio \u2014 Self-contained utility styles
1722
+ ============================================================ */
1723
+
1724
+ /* --- Base normalization (Preflight may be absent in no-uikit hosts) ---
1725
+ :where() keeps specificity at 0-0-0 so utility classes always win. */
1726
+ .studio-panel,
1727
+ .studio-portal-container {
1728
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
1729
+ line-height: 1.5;
1730
+ }
1731
+ :where(.studio-panel *, .studio-portal-container *) { box-sizing: border-box; }
1732
+ :where(.studio-panel button, .studio-portal-container button) {
1733
+ font-family: inherit;
1734
+ font-size: inherit;
1735
+ line-height: inherit;
1736
+ color: inherit;
1737
+ border: 0 solid transparent;
1738
+ background: transparent;
1739
+ padding: 0;
1740
+ margin: 0;
1741
+ cursor: pointer;
1742
+ }
1743
+ :where(.studio-panel h2, .studio-panel h3, .studio-portal-container h2, .studio-portal-container h3) {
1744
+ font-size: inherit;
1745
+ font-weight: inherit;
1746
+ margin: 0;
1747
+ }
1748
+
1749
+ /* --- Layout --- */
1750
+ .fixed { position: fixed; }
1751
+ .absolute { position: absolute; }
1752
+ .relative { position: relative; }
1753
+ .flex { display: flex; }
1754
+ .inline-flex { display: inline-flex; }
1755
+ .block { display: block; }
1756
+ .peer { /* Radix peer marker \u2014 no CSS needed */ }
1757
+ .flex-col { flex-direction: column; }
1758
+ .flex-1 { flex: 1 1 0%; }
1759
+ .shrink-0 { flex-shrink: 0; }
1760
+ .items-center { align-items: center; }
1761
+ .justify-between { justify-content: space-between; }
1762
+ .justify-center { justify-content: center; }
1763
+ .gap-2 { gap: 0.5rem; }
1764
+ .overflow-hidden { overflow: hidden; }
1765
+ .overflow-y-auto { overflow-y: auto; }
1766
+ .overflow-x-hidden { overflow-x: hidden; }
1767
+
1768
+ /* --- Sizing --- */
1769
+ .h-full { height: 100%; }
1770
+ .w-full { width: 100%; }
1771
+ .h-4 { height: 1rem; }
1772
+ .w-4 { width: 1rem; }
1773
+ .h-5 { height: 1.25rem; }
1774
+ .w-5 { width: 1.25rem; }
1775
+ .w-9 { width: 2.25rem; }
1776
+ .h-6 { height: 1.5rem; }
1777
+ .w-6 { width: 1.5rem; }
1778
+ .h-7 { height: 1.75rem; }
1779
+ .w-7 { width: 1.75rem; }
1780
+ .h-8 { height: 2rem; }
1781
+ .h-9 { height: 2.25rem; }
1782
+ .h-10 { height: 2.5rem; }
1783
+ .h-12 { height: 3rem; }
1784
+ .w-12 { width: 3rem; }
1785
+ .min-w-\\[8rem\\] { min-width: 8rem; }
1786
+ .min-w-40 { min-width: 10rem; }
1787
+
1788
+ /* --- Spacing --- */
1789
+ .p-0 { padding: 0; }
1790
+ .p-1 { padding: 0.25rem; }
1791
+ .p-4 { padding: 1rem; }
1792
+ .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; }
1793
+ .px-3 { padding-left: 0.75rem; padding-right: 0.75rem; }
1794
+ .px-4 { padding-left: 1rem; padding-right: 1rem; }
1795
+ .px-8 { padding-left: 2rem; padding-right: 2rem; }
1796
+ .py-1\\.5 { padding-top: 0.375rem; padding-bottom: 0.375rem; }
1797
+ .py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }
1798
+ .py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; }
1799
+ .pl-8 { padding-left: 2rem; }
1800
+ .bottom-1 { bottom: 0.25rem; }
1801
+ .right-1 { right: 0.25rem; }
1802
+ .space-y-3 > :not([hidden]) ~ :not([hidden]) { margin-top: 0.75rem; }
1803
+ .space-y-4 > :not([hidden]) ~ :not([hidden]) { margin-top: 1rem; }
1804
+
1805
+ /* --- Typography --- */
1806
+ .text-xs { font-size: 0.75rem; line-height: 1rem; }
1807
+ .text-sm { font-size: 0.875rem; line-height: 1.25rem; }
1808
+ .font-medium { font-weight: 500; }
1809
+ .font-semibold { font-weight: 600; }
1810
+ .uppercase { text-transform: uppercase; }
1811
+ .tracking-wider { letter-spacing: 0.05em; }
1812
+ .whitespace-nowrap { white-space: nowrap; }
1813
+
1814
+ /* --- Colors (theme-aware via CSS variables) ---
1815
+ Some theme variables (--popover-foreground, --card-foreground) may have
1816
+ incorrect values in third-party themes. The Studio maps all component
1817
+ colors to --foreground / --background which are always correct (body uses them).
1818
+ :where() ensures host-app Tailwind utilities take precedence when available. */
1819
+ .text-foreground { color: hsl(var(--foreground)); }
1820
+ .text-muted-foreground { color: hsl(var(--muted-foreground)); }
1821
+ .text-muted-foreground\\/70 { color: hsl(var(--muted-foreground) / 0.7); }
1822
+ :where(.bg-popover) { background-color: hsl(var(--background)); }
1823
+ :where(.text-popover-foreground) { color: hsl(var(--foreground)); }
1824
+ :where(.bg-accent) { background-color: hsl(var(--foreground) / 0.1); }
1825
+ :where(.text-accent-foreground) { color: hsl(var(--foreground)); }
1826
+ :where(.bg-background) { background-color: hsl(var(--background)); }
1827
+ :where(.bg-card) { background-color: hsl(var(--background)); }
1828
+ :where(.text-card-foreground) { color: hsl(var(--foreground)); }
1829
+ :where(.bg-primary) { background-color: hsl(var(--foreground)); }
1830
+ :where(.text-primary-foreground) { color: hsl(var(--background)); }
1831
+ :where(.bg-input) { background-color: hsl(var(--foreground) / 0.15); }
1832
+ :where(.border-input) { border-color: hsl(var(--foreground) / 0.2); }
1833
+ :where(.ring-ring) { --tw-ring-color: hsl(var(--foreground) / 0.5); }
1834
+ .border-transparent { border-color: transparent; }
1835
+
1836
+ /* --- Borders --- */
1837
+ .border { border-width: 1px; }
1838
+ .border-2 { border-width: 2px; }
1839
+ .border-b { border-bottom-width: 1px; }
1840
+ :where(.border-border\\/50) { border-color: hsl(var(--foreground) / 0.15); }
1841
+ .rounded-full { border-radius: 9999px; }
1842
+ .rounded-xl { border-radius: 0.75rem; }
1843
+ .rounded-md { border-radius: calc(var(--radius, 0.5rem) - 2px); }
1844
+ .rounded-sm { border-radius: calc(var(--radius, 0.5rem) - 4px); }
1845
+
1846
+ /* --- Interaction --- */
1847
+ .select-none { -webkit-user-select: none; user-select: none; }
1848
+ .cursor-pointer { cursor: pointer; }
1849
+ .cursor-default { cursor: default; }
1850
+ .cursor-nwse-resize { cursor: nwse-resize; }
1851
+ .pointer-events-none { pointer-events: none; }
1852
+ .pointer-events-auto { pointer-events: auto; }
1853
+ .outline-none { outline: 2px solid transparent; outline-offset: 2px; }
1854
+ .transition-colors {
1855
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
1856
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1857
+ transition-duration: 150ms;
1858
+ }
1859
+ .transition-transform {
1860
+ transition-property: transform;
1861
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1862
+ transition-duration: 150ms;
1863
+ }
1864
+
1865
+ /* --- Z-index (arbitrary values) --- */
1866
+ .z-\\[10000\\] { z-index: 10000; }
1867
+ .z-\\[99999\\] { z-index: 99999; }
1868
+
1869
+ /* --- Glassmorphic: background with opacity --- */
1870
+ .bg-white\\/20 { background-color: rgb(255 255 255 / 0.2); }
1871
+ .bg-white\\/30 { background-color: rgb(255 255 255 / 0.3); }
1872
+ .dark .dark\\:bg-black\\/50 { background-color: rgb(0 0 0 / 0.5); }
1873
+ .dark .dark\\:bg-black\\/60 { background-color: rgb(0 0 0 / 0.6); }
1874
+
1875
+ /* --- Glassmorphic: border with opacity --- */
1876
+ .border-white\\/30 { border-color: rgb(255 255 255 / 0.3); }
1877
+ .dark .dark\\:border-white\\/20 { border-color: rgb(255 255 255 / 0.2); }
1878
+
1879
+ /* --- Glassmorphic: backdrop filters --- */
1880
+ .backdrop-blur-md {
1881
+ --tw-backdrop-blur: blur(12px);
1882
+ -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
1883
+ backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate, ) var(--tw-backdrop-sepia, );
1884
+ }
1885
+ .backdrop-saturate-\\[180\\%\\] {
1886
+ --tw-backdrop-saturate: saturate(1.8);
1887
+ -webkit-backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia, );
1888
+ backdrop-filter: var(--tw-backdrop-blur, ) var(--tw-backdrop-brightness, ) var(--tw-backdrop-contrast, ) var(--tw-backdrop-grayscale, ) var(--tw-backdrop-hue-rotate, ) var(--tw-backdrop-invert, ) var(--tw-backdrop-opacity, ) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia, );
1889
+ }
1890
+
1891
+ /* --- Glassmorphic: box shadow (arbitrary) --- */
1892
+ .shadow-\\[0_8px_32px_rgba\\(0\\,0\\,0\\,0\\.2\\)\\] {
1893
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
1894
+ }
1895
+
1896
+ /* --- Shadows --- */
1897
+ .shadow { box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); }
1898
+ .shadow-sm { box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); }
1899
+ .shadow-md { box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); }
1900
+ .shadow-lg { box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1); }
1901
+ .ring-0 { box-shadow: var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width, 0px)) var(--tw-ring-color, transparent); }
1902
+
1903
+ /* --- Hover states --- */
1904
+ .hover\\:bg-white\\/30:hover { background-color: rgb(255 255 255 / 0.3); }
1905
+ .dark .dark\\:hover\\:bg-black\\/60:hover { background-color: rgb(0 0 0 / 0.6); }
1906
+ .hover\\:text-muted-foreground:hover { color: hsl(var(--muted-foreground)); }
1907
+ :where(.hover\\:bg-accent:hover) { background-color: hsl(var(--foreground) / 0.1); }
1908
+ :where(.hover\\:bg-primary\\/90:hover) { background-color: hsl(var(--foreground) / 0.85); }
1909
+ :where(.hover\\:bg-secondary\\/80:hover) { background-color: hsl(var(--foreground) / 0.08); }
1910
+ :where(.hover\\:bg-destructive\\/90:hover) { background-color: hsl(0 60% 50% / 0.9); }
1911
+
1912
+ /* --- Focus states --- */
1913
+ :where(.focus\\:bg-accent:focus) { background-color: hsl(var(--foreground) / 0.1); }
1914
+ :where(.focus\\:text-foreground:focus) { color: hsl(var(--foreground)); }
1915
+ :where(.focus\\:text-accent-foreground:focus) { color: hsl(var(--foreground)); }
1916
+ .focus-visible\\:outline-none:focus-visible { outline: 2px solid transparent; outline-offset: 2px; }
1917
+ :where(.focus-visible\\:ring-1:focus-visible) {
1918
+ box-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width, 0px)) var(--tw-ring-color, hsl(var(--foreground) / 0.5));
1919
+ }
1920
+ :where(.focus-visible\\:ring-2:focus-visible) {
1921
+ box-shadow: var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width, 0px)) var(--tw-ring-color, hsl(var(--foreground) / 0.5));
1922
+ }
1923
+ :where(.focus-visible\\:ring-ring:focus-visible) { --tw-ring-color: hsl(var(--foreground) / 0.5); }
1924
+ :where(.focus-visible\\:ring-offset-2:focus-visible) { --tw-ring-offset-width: 2px; }
1925
+ :where(.focus-visible\\:ring-offset-background:focus-visible) { --tw-ring-offset-color: hsl(var(--background)); }
1926
+
1927
+ /* --- Data-attribute & disabled states --- */
1928
+ :where(.data-\\[state\\=open\\]\\:bg-accent[data-state=open]) { background-color: hsl(var(--foreground) / 0.1); }
1929
+ :where(.data-\\[state\\=checked\\]\\:bg-primary[data-state=checked]) { background-color: hsl(var(--foreground)); }
1930
+ :where(.data-\\[state\\=unchecked\\]\\:bg-input[data-state=unchecked]) { background-color: hsl(var(--foreground) / 0.15); }
1931
+ .data-\\[disabled\\]\\:pointer-events-none[data-disabled] { pointer-events: none; }
1932
+ .data-\\[disabled\\]\\:opacity-50[data-disabled] { opacity: 0.5; }
1933
+ .disabled\\:pointer-events-none:disabled { pointer-events: none; }
1934
+ .disabled\\:opacity-50:disabled { opacity: 0.5; }
1935
+ .disabled\\:cursor-not-allowed:disabled { cursor: not-allowed; }
1936
+
1937
+ /* --- SVG child selectors --- */
1938
+ [class*="[&>svg]:size-4"] > svg,
1939
+ [class*="[&_svg]:size-4"] svg { width: 1rem; height: 1rem; }
1940
+ [class*="[&>svg]:shrink-0"] > svg,
1941
+ [class*="[&_svg]:shrink-0"] svg { flex-shrink: 0; }
1942
+ [class*="[&_svg]:pointer-events-none"] svg { pointer-events: none; }
1943
+
1944
+ /* --- RTL support --- */
1945
+ .rtl\\:flex-row-reverse:where([dir=rtl], [dir=rtl] *) { flex-direction: row-reverse; }
1946
+ .data-\\[state\\=checked\\]\\:ltr\\:translate-x-4[data-state=checked]:where([dir=ltr], [dir=ltr] *) { transform: translateX(1rem); }
1947
+ .data-\\[state\\=checked\\]\\:rtl\\:-translate-x-4[data-state=checked]:where([dir=rtl], [dir=rtl] *) { transform: translateX(-1rem); }
1948
+ .data-\\[state\\=unchecked\\]\\:translate-x-0[data-state=unchecked] { transform: translateX(0); }
1949
+
1950
+ /* --- Radix animation (minimal enter/exit for dropdown) --- */
1951
+ @keyframes hai3-fade-in { from { opacity: 0; } to { opacity: 1; } }
1952
+ @keyframes hai3-fade-out { from { opacity: 1; } to { opacity: 0; } }
1953
+ @keyframes hai3-zoom-in { from { transform: scale(0.95); } to { transform: scale(1); } }
1954
+ @keyframes hai3-zoom-out { from { transform: scale(1); } to { transform: scale(0.95); } }
1955
+ .data-\\[state\\=open\\]\\:animate-in[data-state=open] { animation: hai3-fade-in 150ms ease-out, hai3-zoom-in 150ms ease-out; }
1956
+ .data-\\[state\\=closed\\]\\:animate-out[data-state=closed] { animation: hai3-fade-out 100ms ease-in, hai3-zoom-out 100ms ease-in; animation-fill-mode: forwards; }
1957
+
1958
+ /* --- Studio portal: scoped dropdown color overrides ---
1959
+ Dropdown content portaled here inherits host-app Tailwind utilities that
1960
+ may reference broken theme variables (e.g. --popover-foreground identical
1961
+ to --popover in some third-party themes). Scoped rules (specificity 0-2-0)
1962
+ beat host-app Tailwind (0-1-0) and map everything to --foreground / --background. */
1963
+ .studio-portal-container .bg-popover { background-color: hsl(var(--background, 0 0% 100%)); }
1964
+ .studio-portal-container .text-popover-foreground { color: hsl(var(--foreground, 0 0% 0%)); }
1965
+ .studio-portal-container .focus\\:bg-accent:focus { background-color: hsl(var(--foreground) / 0.1); }
1966
+ .studio-portal-container .focus\\:text-foreground:focus { color: hsl(var(--foreground)); }
1967
+
1968
+ /* --- Z-index (dropdown content) --- */
1969
+ .z-50 { z-index: 50; }
1970
+ `
1971
+ );
1972
+ function injectStudioStyles() {
1973
+ if (typeof document === "undefined") return () => {
1974
+ };
1975
+ let styleEl = document.getElementById(STUDIO_STYLE_ID);
1976
+ if (styleEl) return () => {
1977
+ };
1978
+ styleEl = document.createElement("style");
1979
+ styleEl.id = STUDIO_STYLE_ID;
1980
+ styleEl.textContent = STUDIO_CSS;
1981
+ document.head.appendChild(styleEl);
1982
+ return () => {
1983
+ styleEl?.remove();
1984
+ };
1985
+ }
1434
1986
  var StudioContent = () => {
1435
1987
  const { collapsed, toggleCollapsed } = useStudioContext();
1436
1988
  useKeyboardShortcut(toggleCollapsed);
@@ -1440,6 +1992,9 @@ var StudioContent = () => {
1440
1992
  return /* @__PURE__ */ jsx(StudioPanel, {});
1441
1993
  };
1442
1994
  var StudioOverlay = () => {
1995
+ useEffect(() => {
1996
+ return injectStudioStyles();
1997
+ }, []);
1443
1998
  return /* @__PURE__ */ jsx(StudioProvider, { children: /* @__PURE__ */ jsx(StudioContent, {}) });
1444
1999
  };
1445
2000
  StudioOverlay.displayName = "StudioOverlay";