@hai3/studio 0.1.0-alpha.0 → 0.2.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,14 @@
1
- import React3, { createContext, useContext, useState, useEffect, useCallback, useRef } from 'react';
2
- import { I18nRegistry, Language, i18nRegistry, ScreensetCategory, eventBus, useTranslation, useAppDispatch, useAppSelector, selectScreenset, screensetRegistry, setApiMode, themeRegistry, changeTheme, LanguageDisplayMode, TextDirection } from '@hai3/uicore';
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';
5
- import { clamp, upperFirst } from 'lodash';
6
- import { ButtonVariant as ButtonVariant$1 } from '@hai3/uikit-contracts';
1
+ 'use strict';
2
+
3
+ var React4 = require('react');
4
+ var react = require('@hai3/react');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var uikit = require('@hai3/uikit');
7
+ var lodash = require('lodash');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var React4__default = /*#__PURE__*/_interopDefault(React4);
7
12
 
8
13
  var __create = Object.create;
9
14
  var __defProp = Object.defineProperty;
@@ -27,7 +32,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
32
  // file that has been converted to a CommonJS file using a Babel-
28
33
  // compatible transform (i.e. "__esModule" has not been set), then set
29
34
  // "default" to the CommonJS "module.exports" for node compatibility.
30
- !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
35
+ __defProp(target, "default", { value: mod, enumerable: true }) ,
31
36
  mod
32
37
  ));
33
38
 
@@ -835,19 +840,19 @@ var StudioEvents = {
835
840
 
836
841
  // src/effects/persistenceEffects.ts
837
842
  var initPersistenceEffects = () => {
838
- const positionSubscription = eventBus.on(
843
+ const positionSubscription = react.eventBus.on(
839
844
  StudioEvents.PositionChanged,
840
845
  ({ position }) => {
841
846
  saveStudioState(STORAGE_KEYS.POSITION, position);
842
847
  }
843
848
  );
844
- const sizeSubscription = eventBus.on(
849
+ const sizeSubscription = react.eventBus.on(
845
850
  StudioEvents.SizeChanged,
846
851
  ({ size }) => {
847
852
  saveStudioState(STORAGE_KEYS.SIZE, size);
848
853
  }
849
854
  );
850
- const buttonPositionSubscription = eventBus.on(
855
+ const buttonPositionSubscription = react.eventBus.on(
851
856
  StudioEvents.ButtonPositionChanged,
852
857
  ({ position }) => {
853
858
  saveStudioState(STORAGE_KEYS.BUTTON_POSITION, position);
@@ -859,70 +864,70 @@ var initPersistenceEffects = () => {
859
864
  buttonPositionSubscription.unsubscribe();
860
865
  };
861
866
  };
862
- var studioTranslations = I18nRegistry.createLoader({
863
- [Language.English]: () => Promise.resolve().then(() => __toESM(require_en())),
864
- [Language.Arabic]: () => Promise.resolve().then(() => __toESM(require_ar())),
865
- [Language.Bengali]: () => Promise.resolve().then(() => __toESM(require_bn())),
866
- [Language.Czech]: () => Promise.resolve().then(() => __toESM(require_cs())),
867
- [Language.Danish]: () => Promise.resolve().then(() => __toESM(require_da())),
868
- [Language.German]: () => Promise.resolve().then(() => __toESM(require_de())),
869
- [Language.Greek]: () => Promise.resolve().then(() => __toESM(require_el())),
870
- [Language.Spanish]: () => Promise.resolve().then(() => __toESM(require_es())),
871
- [Language.Persian]: () => Promise.resolve().then(() => __toESM(require_fa())),
872
- [Language.Finnish]: () => Promise.resolve().then(() => __toESM(require_fi())),
873
- [Language.French]: () => Promise.resolve().then(() => __toESM(require_fr())),
874
- [Language.Hebrew]: () => Promise.resolve().then(() => __toESM(require_he())),
875
- [Language.Hindi]: () => Promise.resolve().then(() => __toESM(require_hi())),
876
- [Language.Hungarian]: () => Promise.resolve().then(() => __toESM(require_hu())),
877
- [Language.Indonesian]: () => Promise.resolve().then(() => __toESM(require_id())),
878
- [Language.Italian]: () => Promise.resolve().then(() => __toESM(require_it())),
879
- [Language.Japanese]: () => Promise.resolve().then(() => __toESM(require_ja())),
880
- [Language.Korean]: () => Promise.resolve().then(() => __toESM(require_ko())),
881
- [Language.Malay]: () => Promise.resolve().then(() => __toESM(require_ms())),
882
- [Language.Dutch]: () => Promise.resolve().then(() => __toESM(require_nl())),
883
- [Language.Norwegian]: () => Promise.resolve().then(() => __toESM(require_no())),
884
- [Language.Polish]: () => Promise.resolve().then(() => __toESM(require_pl())),
885
- [Language.Portuguese]: () => Promise.resolve().then(() => __toESM(require_pt())),
886
- [Language.Romanian]: () => Promise.resolve().then(() => __toESM(require_ro())),
887
- [Language.Russian]: () => Promise.resolve().then(() => __toESM(require_ru())),
888
- [Language.Swedish]: () => Promise.resolve().then(() => __toESM(require_sv())),
889
- [Language.Swahili]: () => Promise.resolve().then(() => __toESM(require_sw())),
890
- [Language.Tamil]: () => Promise.resolve().then(() => __toESM(require_ta())),
891
- [Language.Thai]: () => Promise.resolve().then(() => __toESM(require_th())),
892
- [Language.Tagalog]: () => Promise.resolve().then(() => __toESM(require_tl())),
893
- [Language.Turkish]: () => Promise.resolve().then(() => __toESM(require_tr())),
894
- [Language.Ukrainian]: () => Promise.resolve().then(() => __toESM(require_uk())),
895
- [Language.Urdu]: () => Promise.resolve().then(() => __toESM(require_ur())),
896
- [Language.Vietnamese]: () => Promise.resolve().then(() => __toESM(require_vi())),
897
- [Language.ChineseTraditional]: () => Promise.resolve().then(() => __toESM(require_zh_TW())),
898
- [Language.ChineseSimplified]: () => Promise.resolve().then(() => __toESM(require_zh()))
867
+ var studioTranslations = react.I18nRegistry.createLoader({
868
+ [react.Language.English]: () => Promise.resolve().then(() => __toESM(require_en())),
869
+ [react.Language.Arabic]: () => Promise.resolve().then(() => __toESM(require_ar())),
870
+ [react.Language.Bengali]: () => Promise.resolve().then(() => __toESM(require_bn())),
871
+ [react.Language.Czech]: () => Promise.resolve().then(() => __toESM(require_cs())),
872
+ [react.Language.Danish]: () => Promise.resolve().then(() => __toESM(require_da())),
873
+ [react.Language.German]: () => Promise.resolve().then(() => __toESM(require_de())),
874
+ [react.Language.Greek]: () => Promise.resolve().then(() => __toESM(require_el())),
875
+ [react.Language.Spanish]: () => Promise.resolve().then(() => __toESM(require_es())),
876
+ [react.Language.Persian]: () => Promise.resolve().then(() => __toESM(require_fa())),
877
+ [react.Language.Finnish]: () => Promise.resolve().then(() => __toESM(require_fi())),
878
+ [react.Language.French]: () => Promise.resolve().then(() => __toESM(require_fr())),
879
+ [react.Language.Hebrew]: () => Promise.resolve().then(() => __toESM(require_he())),
880
+ [react.Language.Hindi]: () => Promise.resolve().then(() => __toESM(require_hi())),
881
+ [react.Language.Hungarian]: () => Promise.resolve().then(() => __toESM(require_hu())),
882
+ [react.Language.Indonesian]: () => Promise.resolve().then(() => __toESM(require_id())),
883
+ [react.Language.Italian]: () => Promise.resolve().then(() => __toESM(require_it())),
884
+ [react.Language.Japanese]: () => Promise.resolve().then(() => __toESM(require_ja())),
885
+ [react.Language.Korean]: () => Promise.resolve().then(() => __toESM(require_ko())),
886
+ [react.Language.Malay]: () => Promise.resolve().then(() => __toESM(require_ms())),
887
+ [react.Language.Dutch]: () => Promise.resolve().then(() => __toESM(require_nl())),
888
+ [react.Language.Norwegian]: () => Promise.resolve().then(() => __toESM(require_no())),
889
+ [react.Language.Polish]: () => Promise.resolve().then(() => __toESM(require_pl())),
890
+ [react.Language.Portuguese]: () => Promise.resolve().then(() => __toESM(require_pt())),
891
+ [react.Language.Romanian]: () => Promise.resolve().then(() => __toESM(require_ro())),
892
+ [react.Language.Russian]: () => Promise.resolve().then(() => __toESM(require_ru())),
893
+ [react.Language.Swedish]: () => Promise.resolve().then(() => __toESM(require_sv())),
894
+ [react.Language.Swahili]: () => Promise.resolve().then(() => __toESM(require_sw())),
895
+ [react.Language.Tamil]: () => Promise.resolve().then(() => __toESM(require_ta())),
896
+ [react.Language.Thai]: () => Promise.resolve().then(() => __toESM(require_th())),
897
+ [react.Language.Tagalog]: () => Promise.resolve().then(() => __toESM(require_tl())),
898
+ [react.Language.Turkish]: () => Promise.resolve().then(() => __toESM(require_tr())),
899
+ [react.Language.Ukrainian]: () => Promise.resolve().then(() => __toESM(require_uk())),
900
+ [react.Language.Urdu]: () => Promise.resolve().then(() => __toESM(require_ur())),
901
+ [react.Language.Vietnamese]: () => Promise.resolve().then(() => __toESM(require_vi())),
902
+ [react.Language.ChineseTraditional]: () => Promise.resolve().then(() => __toESM(require_zh_TW())),
903
+ [react.Language.ChineseSimplified]: () => Promise.resolve().then(() => __toESM(require_zh()))
899
904
  });
900
- i18nRegistry.registerLoader("studio", studioTranslations);
901
- var StudioContext = createContext(void 0);
905
+ react.i18nRegistry.registerLoader("studio", studioTranslations);
906
+ var StudioContext = React4.createContext(void 0);
902
907
  var useStudioContext = () => {
903
- const context = useContext(StudioContext);
908
+ const context = React4.useContext(StudioContext);
904
909
  if (!context) {
905
910
  throw new Error("useStudioContext must be used within StudioProvider");
906
911
  }
907
912
  return context;
908
913
  };
909
914
  var StudioProvider = ({ children }) => {
910
- const [collapsed, setCollapsed] = useState(
915
+ const [collapsed, setCollapsed] = React4.useState(
911
916
  () => loadStudioState(STORAGE_KEYS.COLLAPSED, false)
912
917
  );
913
- const [portalContainer, setPortalContainer] = useState(null);
914
- useEffect(() => {
918
+ const [portalContainer, setPortalContainer] = React4.useState(null);
919
+ React4.useEffect(() => {
915
920
  const cleanup = initPersistenceEffects();
916
921
  return cleanup;
917
922
  }, []);
918
- const toggleCollapsed = useCallback(() => {
923
+ const toggleCollapsed = React4.useCallback(() => {
919
924
  setCollapsed((prev) => {
920
925
  const newValue = !prev;
921
926
  saveStudioState(STORAGE_KEYS.COLLAPSED, newValue);
922
927
  return newValue;
923
928
  });
924
929
  }, []);
925
- return /* @__PURE__ */ jsx(
930
+ return /* @__PURE__ */ jsxRuntime.jsx(
926
931
  StudioContext.Provider,
927
932
  {
928
933
  value: {
@@ -941,27 +946,27 @@ var useDraggable = ({ panelSize, storageKey = STORAGE_KEYS.POSITION }) => {
941
946
  x: window.innerWidth - panelSize.width - 20,
942
947
  y: window.innerHeight - panelSize.height - 20
943
948
  });
944
- const [position, setPosition] = useState(
949
+ const [position, setPosition] = React4.useState(
945
950
  () => loadStudioState(storageKey, getDefaultPosition())
946
951
  );
947
- const [isDragging, setIsDragging] = useState(false);
948
- const dragStartPos = useRef({ x: 0, y: 0 });
949
- const handleMouseDown = useCallback((e) => {
952
+ const [isDragging, setIsDragging] = React4.useState(false);
953
+ const dragStartPos = React4.useRef({ x: 0, y: 0 });
954
+ const handleMouseDown = React4.useCallback((e) => {
950
955
  setIsDragging(true);
951
956
  dragStartPos.current = {
952
957
  x: e.clientX - position.x,
953
958
  y: e.clientY - position.y
954
959
  };
955
960
  }, [position]);
956
- useEffect(() => {
961
+ React4.useEffect(() => {
957
962
  if (!isDragging) return;
958
963
  const handleMouseMove = (e) => {
959
- const newX = clamp(
964
+ const newX = lodash.clamp(
960
965
  e.clientX - dragStartPos.current.x,
961
966
  0,
962
967
  window.innerWidth - panelSize.width
963
968
  );
964
- const newY = clamp(
969
+ const newY = lodash.clamp(
965
970
  e.clientY - dragStartPos.current.y,
966
971
  0,
967
972
  window.innerHeight - panelSize.height
@@ -969,7 +974,7 @@ var useDraggable = ({ panelSize, storageKey = STORAGE_KEYS.POSITION }) => {
969
974
  const newPosition = { x: newX, y: newY };
970
975
  setPosition(newPosition);
971
976
  const eventName = storageKey === STORAGE_KEYS.BUTTON_POSITION ? StudioEvents.ButtonPositionChanged : StudioEvents.PositionChanged;
972
- eventBus.emit(eventName, { position: newPosition });
977
+ react.eventBus.emit(eventName, { position: newPosition });
973
978
  };
974
979
  const handleMouseUp = () => {
975
980
  setIsDragging(false);
@@ -988,15 +993,15 @@ var useDraggable = ({ panelSize, storageKey = STORAGE_KEYS.POSITION }) => {
988
993
  };
989
994
  };
990
995
  var useResizable = () => {
991
- const [size, setSize] = useState(
996
+ const [size, setSize] = React4.useState(
992
997
  () => loadStudioState(STORAGE_KEYS.SIZE, {
993
998
  width: PANEL_CONSTRAINTS.DEFAULT_WIDTH,
994
999
  height: PANEL_CONSTRAINTS.DEFAULT_HEIGHT
995
1000
  })
996
1001
  );
997
- const [isResizing, setIsResizing] = useState(false);
998
- const resizeStartRef = useRef(null);
999
- const handleMouseDown = useCallback((e) => {
1002
+ const [isResizing, setIsResizing] = React4.useState(false);
1003
+ const resizeStartRef = React4.useRef(null);
1004
+ const handleMouseDown = React4.useCallback((e) => {
1000
1005
  e.stopPropagation();
1001
1006
  resizeStartRef.current = {
1002
1007
  mouseX: e.clientX,
@@ -1006,7 +1011,7 @@ var useResizable = () => {
1006
1011
  };
1007
1012
  setIsResizing(true);
1008
1013
  }, [size.width, size.height]);
1009
- useEffect(() => {
1014
+ React4.useEffect(() => {
1010
1015
  if (!isResizing || !resizeStartRef.current) return;
1011
1016
  const startState = resizeStartRef.current;
1012
1017
  document.body.style.userSelect = "none";
@@ -1014,19 +1019,19 @@ var useResizable = () => {
1014
1019
  const handleMouseMove = (e) => {
1015
1020
  const deltaX = e.clientX - startState.mouseX;
1016
1021
  const deltaY = e.clientY - startState.mouseY;
1017
- const newWidth = clamp(
1022
+ const newWidth = lodash.clamp(
1018
1023
  startState.width + deltaX,
1019
1024
  PANEL_CONSTRAINTS.MIN_WIDTH,
1020
1025
  PANEL_CONSTRAINTS.MAX_WIDTH
1021
1026
  );
1022
- const newHeight = clamp(
1027
+ const newHeight = lodash.clamp(
1023
1028
  startState.height + deltaY,
1024
1029
  PANEL_CONSTRAINTS.MIN_HEIGHT,
1025
1030
  PANEL_CONSTRAINTS.MAX_HEIGHT
1026
1031
  );
1027
1032
  const newSize = { width: newWidth, height: newHeight };
1028
1033
  setSize(newSize);
1029
- eventBus.emit(StudioEvents.SizeChanged, { size: newSize });
1034
+ react.eventBus.emit(StudioEvents.SizeChanged, { size: newSize });
1030
1035
  };
1031
1036
  const handleMouseUp = () => {
1032
1037
  setIsResizing(false);
@@ -1052,25 +1057,23 @@ var useResizable = () => {
1052
1057
  var ThemeSelector = ({
1053
1058
  className = ""
1054
1059
  }) => {
1055
- const dispatch = useAppDispatch();
1056
- const currentTheme = useAppSelector((state) => state.uicore.layout.theme);
1060
+ const { currentTheme, themes, setTheme } = react.useTheme();
1057
1061
  const { portalContainer } = useStudioContext();
1058
- const { t } = useTranslation();
1062
+ const { t } = react.useTranslation();
1059
1063
  const formatThemeName = (themeName) => {
1060
- return themeName.split("-").map((word) => upperFirst(word)).join(" ");
1064
+ return themeName.split("-").map((word) => lodash.upperFirst(word)).join(" ");
1061
1065
  };
1062
- const availableThemes = themeRegistry.getThemeNames();
1063
- return /* @__PURE__ */ jsxs("div", { className: `flex items-center justify-between ${className}`, children: [
1064
- /* @__PURE__ */ jsx("label", { className: "text-sm text-muted-foreground whitespace-nowrap", children: t("studio:controls.theme") }),
1065
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
1066
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownButton, { variant: ButtonVariant$1.Outline, children: formatThemeName(currentTheme) }) }),
1067
- /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: availableThemes.map((themeName) => /* @__PURE__ */ jsx(
1068
- DropdownMenuItem,
1066
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center justify-between ${className}`, children: [
1067
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm text-muted-foreground whitespace-nowrap", children: t("studio:controls.theme") }),
1068
+ /* @__PURE__ */ jsxRuntime.jsxs(uikit.DropdownMenu, { children: [
1069
+ /* @__PURE__ */ jsxRuntime.jsx(uikit.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(uikit.DropdownButton, { variant: uikit.ButtonVariant.Outline, children: formatThemeName(currentTheme || "") }) }),
1070
+ /* @__PURE__ */ jsxRuntime.jsx(uikit.DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: themes.map((theme) => /* @__PURE__ */ jsxRuntime.jsx(
1071
+ uikit.DropdownMenuItem,
1069
1072
  {
1070
- onClick: () => dispatch(changeTheme(themeName)),
1071
- children: formatThemeName(themeName)
1073
+ onClick: () => setTheme(theme.id),
1074
+ children: formatThemeName(theme.name || theme.id)
1072
1075
  },
1073
- themeName
1076
+ theme.id
1074
1077
  )) })
1075
1078
  ] })
1076
1079
  ] });
@@ -1083,9 +1086,9 @@ var ScreensetSelector = ({
1083
1086
  className = ""
1084
1087
  }) => {
1085
1088
  const { portalContainer } = useStudioContext();
1086
- const { t, direction } = useTranslation();
1089
+ const { t, isRTL } = react.useTranslation();
1087
1090
  const formatName = (name) => {
1088
- return name.split(/[-_]/).map((word) => upperFirst(word)).join(" ");
1091
+ return name.split(/[-_]/).map((word) => lodash.upperFirst(word)).join(" ");
1089
1092
  };
1090
1093
  const getCurrentDisplay = () => {
1091
1094
  const [category, itemId] = currentValue.split(":");
@@ -1097,14 +1100,14 @@ var ScreensetSelector = ({
1097
1100
  const handleItemClick = (category, itemId) => {
1098
1101
  onChange(`${category}:${itemId}`);
1099
1102
  };
1100
- return /* @__PURE__ */ jsxs("div", { className: `flex items-center justify-between ${className}`, children: [
1101
- /* @__PURE__ */ jsx("label", { className: "text-sm text-muted-foreground whitespace-nowrap", children: t("studio:controls.screenset") }),
1102
- /* @__PURE__ */ jsxs(DropdownMenu, { dir: direction, children: [
1103
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownButton, { variant: ButtonVariant$1.Outline, children: formatName(getCurrentDisplay()) }) }),
1104
- /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: options.map((categoryGroup) => /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
1105
- /* @__PURE__ */ jsx(DropdownMenuSubTrigger, { disabled: categoryGroup.screensets.length === 0, children: formatName(categoryGroup.category) }),
1106
- /* @__PURE__ */ jsx(DropdownMenuSubContent, { container: portalContainer, className: "z-[99999] pointer-events-auto", children: categoryGroup.screensets.map((item) => /* @__PURE__ */ jsx(
1107
- DropdownMenuItem,
1103
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center justify-between ${className}`, children: [
1104
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm text-muted-foreground whitespace-nowrap", children: t("studio:controls.screenset") }),
1105
+ /* @__PURE__ */ jsxRuntime.jsxs(uikit.DropdownMenu, { dir: isRTL ? "rtl" : "ltr", children: [
1106
+ /* @__PURE__ */ jsxRuntime.jsx(uikit.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(uikit.DropdownButton, { variant: uikit.ButtonVariant.Outline, children: formatName(getCurrentDisplay()) }) }),
1107
+ /* @__PURE__ */ jsxRuntime.jsx(uikit.DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: options.map((categoryGroup) => /* @__PURE__ */ jsxRuntime.jsxs(uikit.DropdownMenuSub, { children: [
1108
+ /* @__PURE__ */ jsxRuntime.jsx(uikit.DropdownMenuSubTrigger, { disabled: categoryGroup.screensets.length === 0, children: formatName(categoryGroup.category) }),
1109
+ /* @__PURE__ */ jsxRuntime.jsx(uikit.DropdownMenuSubContent, { container: portalContainer, className: "z-[99999] pointer-events-auto", children: categoryGroup.screensets.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
1110
+ uikit.DropdownMenuItem,
1108
1111
  {
1109
1112
  onClick: () => handleItemClick(categoryGroup.category, item.id),
1110
1113
  children: formatName(item.name)
@@ -1119,23 +1122,22 @@ ScreensetSelector.displayName = "ScreensetSelector";
1119
1122
  var FALLBACK_SELECT_LANGUAGE_TEXT = "Select language";
1120
1123
  var RTL_INDICATOR_SUFFIX = " (RTL)";
1121
1124
  function LanguageSelector({
1122
- displayMode = LanguageDisplayMode.Native
1125
+ displayMode = react.LanguageDisplayMode.Native
1123
1126
  } = {}) {
1124
- const { t, language, changeLanguage, getSupportedLanguages } = useTranslation();
1127
+ const { t, language, setLanguage } = react.useTranslation();
1125
1128
  const { portalContainer } = useStudioContext();
1126
- const languages = getSupportedLanguages();
1127
- const currentLanguage = languages.find((lang) => lang.code === language);
1128
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1129
- /* @__PURE__ */ jsx("label", { className: "text-sm text-muted-foreground whitespace-nowrap", children: t("studio:controls.language") }),
1130
- /* @__PURE__ */ jsxs(DropdownMenu, { children: [
1131
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: ButtonVariant$1.Outline, children: currentLanguage ? displayMode === LanguageDisplayMode.Native ? currentLanguage.name : currentLanguage.englishName : FALLBACK_SELECT_LANGUAGE_TEXT }) }),
1132
- /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: languages.map((lang) => /* @__PURE__ */ jsxs(
1133
- DropdownMenuItem,
1129
+ const currentLanguage = language ? react.getLanguageMetadata(language) : null;
1130
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
1131
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm text-muted-foreground whitespace-nowrap", children: t("studio:controls.language") }),
1132
+ /* @__PURE__ */ jsxRuntime.jsxs(uikit.DropdownMenu, { children: [
1133
+ /* @__PURE__ */ jsxRuntime.jsx(uikit.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(uikit.Button, { variant: uikit.ButtonVariant.Outline, children: currentLanguage ? displayMode === react.LanguageDisplayMode.Native ? currentLanguage.name : currentLanguage.englishName : FALLBACK_SELECT_LANGUAGE_TEXT }) }),
1134
+ /* @__PURE__ */ jsxRuntime.jsx(uikit.DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: react.SUPPORTED_LANGUAGES.map((lang) => /* @__PURE__ */ jsxRuntime.jsxs(
1135
+ uikit.DropdownMenuItem,
1134
1136
  {
1135
- onClick: () => changeLanguage(lang.code),
1137
+ onClick: () => setLanguage(lang.code),
1136
1138
  children: [
1137
- displayMode === LanguageDisplayMode.Native ? lang.name : lang.englishName,
1138
- lang.direction === TextDirection.RightToLeft && RTL_INDICATOR_SUFFIX
1139
+ displayMode === react.LanguageDisplayMode.Native ? lang.name : lang.englishName,
1140
+ lang.direction === react.TextDirection.RightToLeft && RTL_INDICATOR_SUFFIX
1139
1141
  ]
1140
1142
  },
1141
1143
  lang.code
@@ -1144,10 +1146,14 @@ function LanguageSelector({
1144
1146
  ] });
1145
1147
  }
1146
1148
  var ApiModeToggle = ({ className }) => {
1147
- const useMockApi = useAppSelector((state) => state.uicore.app.useMockApi);
1148
- const { t } = useTranslation();
1149
- return /* @__PURE__ */ jsxs("div", { className: `flex items-center justify-between h-9 ${className}`, children: [
1150
- /* @__PURE__ */ jsx(
1149
+ const [useMockApi, setUseMockApi] = React4.useState(true);
1150
+ const { t } = react.useTranslation();
1151
+ const handleToggle = (checked) => {
1152
+ setUseMockApi(checked);
1153
+ react.apiRegistry.setMockMode(checked);
1154
+ };
1155
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-center justify-between h-9 ${className}`, children: [
1156
+ /* @__PURE__ */ jsxRuntime.jsx(
1151
1157
  "label",
1152
1158
  {
1153
1159
  htmlFor: "api-mode-toggle",
@@ -1155,73 +1161,88 @@ var ApiModeToggle = ({ className }) => {
1155
1161
  children: t("studio:controls.mockApi")
1156
1162
  }
1157
1163
  ),
1158
- /* @__PURE__ */ jsx(
1159
- Switch,
1164
+ /* @__PURE__ */ jsxRuntime.jsx(
1165
+ uikit.Switch,
1160
1166
  {
1161
1167
  id: "api-mode-toggle",
1162
1168
  checked: useMockApi,
1163
- onCheckedChange: (checked) => setApiMode(checked)
1169
+ onCheckedChange: handleToggle
1164
1170
  }
1165
1171
  )
1166
1172
  ] });
1167
1173
  };
1168
1174
  ApiModeToggle.displayName = "ApiModeToggle";
1169
- var ALL_CATEGORIES = [ScreensetCategory.Drafts, ScreensetCategory.Mockups, ScreensetCategory.Production];
1175
+ var ALL_CATEGORIES = [react.ScreensetCategory.Drafts, react.ScreensetCategory.Mockups, react.ScreensetCategory.Production];
1170
1176
  var buildScreensetOptions = () => {
1177
+ const allScreensets = react.screensetRegistry.getAll();
1171
1178
  return ALL_CATEGORIES.map((category) => ({
1172
1179
  category,
1173
- screensets: screensetRegistry.getMetadataByCategory(category)
1180
+ screensets: allScreensets.filter((s) => s.category === category).map((s) => ({
1181
+ id: s.id,
1182
+ name: s.name
1183
+ }))
1174
1184
  }));
1175
1185
  };
1176
1186
  var ControlPanel = () => {
1177
- const dispatch = useAppDispatch();
1178
- const currentScreenset = useAppSelector((state) => state.uicore.layout.currentScreenset);
1179
- const [screensetOptions, setScreensetOptions] = useState([]);
1180
- const { t } = useTranslation();
1181
- useEffect(() => {
1187
+ const { currentScreenset, navigateToScreenset } = react.useNavigation();
1188
+ const [screensetOptions, setScreensetOptions] = React4.useState([]);
1189
+ const { t } = react.useTranslation();
1190
+ React4.useEffect(() => {
1182
1191
  const options = buildScreensetOptions();
1183
1192
  setScreensetOptions(options);
1184
1193
  }, []);
1185
- return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1186
- /* @__PURE__ */ jsx("h3", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: t("studio:controls.heading") }),
1187
- /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1188
- screensetOptions.length > 0 && /* @__PURE__ */ jsx(
1194
+ const getCurrentValue = () => {
1195
+ if (!currentScreenset) return "";
1196
+ const screenset = react.screensetRegistry.get(currentScreenset);
1197
+ if (!screenset) return "";
1198
+ return `${screenset.category}:${screenset.id}`;
1199
+ };
1200
+ const handleScreensetChange = (value) => {
1201
+ const [, screensetId] = value.split(":");
1202
+ if (screensetId) {
1203
+ navigateToScreenset(screensetId);
1204
+ }
1205
+ };
1206
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
1207
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: t("studio:controls.heading") }),
1208
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
1209
+ screensetOptions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1189
1210
  ScreensetSelector,
1190
1211
  {
1191
1212
  options: screensetOptions,
1192
- currentValue: currentScreenset,
1193
- onChange: (value) => dispatch(selectScreenset(value))
1213
+ currentValue: getCurrentValue(),
1214
+ onChange: handleScreensetChange
1194
1215
  }
1195
1216
  ),
1196
- /* @__PURE__ */ jsx(ApiModeToggle, {}),
1197
- /* @__PURE__ */ jsx(ThemeSelector, {}),
1198
- /* @__PURE__ */ jsx(LanguageSelector, {})
1217
+ /* @__PURE__ */ jsxRuntime.jsx(ApiModeToggle, {}),
1218
+ /* @__PURE__ */ jsxRuntime.jsx(ThemeSelector, {}),
1219
+ /* @__PURE__ */ jsxRuntime.jsx(LanguageSelector, {})
1199
1220
  ] })
1200
1221
  ] }) });
1201
1222
  };
1202
1223
  ControlPanel.displayName = "ControlPanel";
1203
1224
  var StudioPanel = () => {
1204
1225
  const { toggleCollapsed, setPortalContainer } = useStudioContext();
1205
- const { t } = useTranslation();
1206
- const portalRef = React3.useRef(null);
1226
+ const { t } = react.useTranslation();
1227
+ const portalRef = React4__default.default.useRef(null);
1207
1228
  const { size, handleMouseDown: handleResizeMouseDown } = useResizable();
1208
1229
  const { position, isDragging, handleMouseDown: handleDragMouseDown } = useDraggable({
1209
1230
  panelSize: size,
1210
1231
  storageKey: STORAGE_KEYS.POSITION
1211
1232
  });
1212
- React3.useEffect(() => {
1233
+ React4__default.default.useEffect(() => {
1213
1234
  setPortalContainer(portalRef.current);
1214
1235
  return () => setPortalContainer(null);
1215
1236
  }, [setPortalContainer]);
1216
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1217
- /* @__PURE__ */ jsx(
1237
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1238
+ /* @__PURE__ */ jsxRuntime.jsx(
1218
1239
  "div",
1219
1240
  {
1220
1241
  ref: portalRef,
1221
1242
  className: "studio-portal-container fixed z-[99999] pointer-events-none"
1222
1243
  }
1223
1244
  ),
1224
- /* @__PURE__ */ jsx(
1245
+ /* @__PURE__ */ jsxRuntime.jsx(
1225
1246
  "div",
1226
1247
  {
1227
1248
  className: "studio-panel fixed z-[10000]",
@@ -1231,32 +1252,32 @@ var StudioPanel = () => {
1231
1252
  width: `${size.width}px`,
1232
1253
  height: `${size.height}px`
1233
1254
  },
1234
- children: /* @__PURE__ */ jsxs(Card, { className: "h-full w-full flex flex-col overflow-hidden bg-white/20 dark:bg-black/50 backdrop-blur-md backdrop-saturate-[180%] border border-white/30 dark:border-white/20 shadow-[0_8px_32px_rgba(0,0,0,0.2)]", children: [
1235
- /* @__PURE__ */ jsxs(
1255
+ children: /* @__PURE__ */ jsxRuntime.jsxs(uikit.Card, { className: "h-full w-full flex flex-col overflow-hidden bg-white/20 dark:bg-black/50 backdrop-blur-md backdrop-saturate-[180%] border border-white/30 dark:border-white/20 shadow-[0_8px_32px_rgba(0,0,0,0.2)]", children: [
1256
+ /* @__PURE__ */ jsxRuntime.jsxs(
1236
1257
  "div",
1237
1258
  {
1238
1259
  className: "studio-header px-4 py-3 border-b border-border/50 select-none flex items-center justify-between",
1239
1260
  onMouseDown: handleDragMouseDown,
1240
1261
  style: { cursor: isDragging ? "grabbing" : "grab" },
1241
1262
  children: [
1242
- /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-foreground", children: t("studio:title") }),
1243
- /* @__PURE__ */ jsx(
1244
- Button,
1263
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm font-semibold text-foreground", children: t("studio:title") }),
1264
+ /* @__PURE__ */ jsxRuntime.jsx(
1265
+ uikit.Button,
1245
1266
  {
1246
- variant: ButtonVariant.Ghost,
1247
- size: ButtonSize.Sm,
1267
+ variant: uikit.ButtonVariant.Ghost,
1268
+ size: uikit.ButtonSize.Sm,
1248
1269
  onClick: toggleCollapsed,
1249
1270
  className: "h-7 w-7 p-0",
1250
1271
  "aria-label": t("studio:aria.collapseButton"),
1251
1272
  title: t("studio:aria.collapseButton"),
1252
- children: /* @__PURE__ */ jsx(
1273
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1253
1274
  "svg",
1254
1275
  {
1255
1276
  className: "w-4 h-4",
1256
1277
  fill: "none",
1257
1278
  stroke: "currentColor",
1258
1279
  viewBox: "0 0 24 24",
1259
- children: /* @__PURE__ */ jsx(
1280
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1260
1281
  "path",
1261
1282
  {
1262
1283
  strokeLinecap: "round",
@@ -1272,8 +1293,8 @@ var StudioPanel = () => {
1272
1293
  ]
1273
1294
  }
1274
1295
  ),
1275
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto p-4", children: /* @__PURE__ */ jsx(ControlPanel, {}) }),
1276
- /* @__PURE__ */ jsx(
1296
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto p-4", children: /* @__PURE__ */ jsxRuntime.jsx(ControlPanel, {}) }),
1297
+ /* @__PURE__ */ jsxRuntime.jsx(
1277
1298
  "div",
1278
1299
  {
1279
1300
  className: "studio-resize-handle absolute bottom-1 right-1 w-5 h-5 cursor-nwse-resize",
@@ -1282,13 +1303,13 @@ var StudioPanel = () => {
1282
1303
  "aria-label": t("studio:aria.resizeHandle"),
1283
1304
  title: t("studio:aria.resizeHandle"),
1284
1305
  tabIndex: 0,
1285
- children: /* @__PURE__ */ jsx(
1306
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1286
1307
  "svg",
1287
1308
  {
1288
1309
  className: "w-5 h-5 text-muted-foreground/70 hover:text-muted-foreground transition-colors",
1289
1310
  fill: "currentColor",
1290
1311
  viewBox: "0 0 24 24",
1291
- children: /* @__PURE__ */ jsx("path", { d: "M22 22H20V20H22V22ZM22 18H20V16H22V18ZM18 22H16V20H18V22ZM18 18H16V16H18V18ZM14 22H12V20H14V22Z" })
1312
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M22 22H20V20H22V22ZM22 18H20V16H22V18ZM18 22H16V20H18V22ZM18 18H16V16H18V18ZM14 22H12V20H14V22Z" })
1292
1313
  }
1293
1314
  )
1294
1315
  }
@@ -1300,7 +1321,7 @@ var StudioPanel = () => {
1300
1321
  };
1301
1322
  StudioPanel.displayName = "StudioPanel";
1302
1323
  var useKeyboardShortcut = (handler) => {
1303
- useEffect(() => {
1324
+ React4.useEffect(() => {
1304
1325
  const handleKeyDown = (e) => {
1305
1326
  if (e.shiftKey && e.code === "Backquote") {
1306
1327
  e.preventDefault();
@@ -1320,10 +1341,10 @@ var GlassmorphicButton = ({
1320
1341
  title,
1321
1342
  isDragging = false
1322
1343
  }) => {
1323
- return /* @__PURE__ */ jsx(
1324
- Button,
1344
+ return /* @__PURE__ */ jsxRuntime.jsx(
1345
+ uikit.Button,
1325
1346
  {
1326
- variant: ButtonVariant.Ghost,
1347
+ variant: uikit.ButtonVariant.Ghost,
1327
1348
  onMouseDown,
1328
1349
  onClick,
1329
1350
  title,
@@ -1335,14 +1356,14 @@ var GlassmorphicButton = ({
1335
1356
  };
1336
1357
  GlassmorphicButton.displayName = "GlassmorphicButton";
1337
1358
  var StudioIcon = ({ className = "" }) => {
1338
- return /* @__PURE__ */ jsx(
1359
+ return /* @__PURE__ */ jsxRuntime.jsx(
1339
1360
  "svg",
1340
1361
  {
1341
1362
  className,
1342
1363
  fill: "none",
1343
1364
  stroke: "currentColor",
1344
1365
  viewBox: "0 0 24 24",
1345
- children: /* @__PURE__ */ jsx(
1366
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1346
1367
  "path",
1347
1368
  {
1348
1369
  strokeLinecap: "round",
@@ -1355,12 +1376,12 @@ var StudioIcon = ({ className = "" }) => {
1355
1376
  );
1356
1377
  };
1357
1378
  var CollapsedButton = ({ toggleCollapsed }) => {
1358
- const { t } = useTranslation();
1379
+ const { t } = react.useTranslation();
1359
1380
  const { position, isDragging, handleMouseDown } = useDraggable({
1360
1381
  panelSize: BUTTON_SIZE,
1361
1382
  storageKey: STORAGE_KEYS.BUTTON_POSITION
1362
1383
  });
1363
- const dragStartPosition = useRef(null);
1384
+ const dragStartPosition = React4.useRef(null);
1364
1385
  const handleButtonMouseDown = (e) => {
1365
1386
  dragStartPosition.current = { x: e.clientX, y: e.clientY };
1366
1387
  handleMouseDown(e);
@@ -1374,7 +1395,7 @@ var CollapsedButton = ({ toggleCollapsed }) => {
1374
1395
  }
1375
1396
  }
1376
1397
  };
1377
- return /* @__PURE__ */ jsx(
1398
+ return /* @__PURE__ */ jsxRuntime.jsx(
1378
1399
  "div",
1379
1400
  {
1380
1401
  className: "fixed z-[10000]",
@@ -1382,10 +1403,10 @@ var CollapsedButton = ({ toggleCollapsed }) => {
1382
1403
  left: `${position.x}px`,
1383
1404
  top: `${position.y}px`
1384
1405
  },
1385
- children: /* @__PURE__ */ jsx(
1406
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1386
1407
  GlassmorphicButton,
1387
1408
  {
1388
- icon: /* @__PURE__ */ jsx(StudioIcon, { className: "w-6 h-6 text-foreground" }),
1409
+ icon: /* @__PURE__ */ jsxRuntime.jsx(StudioIcon, { className: "w-6 h-6 text-foreground" }),
1389
1410
  onMouseDown: handleButtonMouseDown,
1390
1411
  onClick: handleButtonClick,
1391
1412
  title: t("studio:aria.openButton"),
@@ -1400,15 +1421,17 @@ var StudioContent = () => {
1400
1421
  const { collapsed, toggleCollapsed } = useStudioContext();
1401
1422
  useKeyboardShortcut(toggleCollapsed);
1402
1423
  if (collapsed) {
1403
- return /* @__PURE__ */ jsx(CollapsedButton, { toggleCollapsed });
1424
+ return /* @__PURE__ */ jsxRuntime.jsx(CollapsedButton, { toggleCollapsed });
1404
1425
  }
1405
- return /* @__PURE__ */ jsx(StudioPanel, {});
1426
+ return /* @__PURE__ */ jsxRuntime.jsx(StudioPanel, {});
1406
1427
  };
1407
1428
  var StudioOverlay = () => {
1408
- return /* @__PURE__ */ jsx(StudioProvider, { children: /* @__PURE__ */ jsx(StudioContent, {}) });
1429
+ return /* @__PURE__ */ jsxRuntime.jsx(StudioProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(StudioContent, {}) });
1409
1430
  };
1410
1431
  StudioOverlay.displayName = "StudioOverlay";
1411
1432
 
1412
- export { StudioOverlay, StudioProvider, useStudioContext };
1413
- //# sourceMappingURL=index.mjs.map
1414
- //# sourceMappingURL=index.mjs.map
1433
+ exports.StudioOverlay = StudioOverlay;
1434
+ exports.StudioProvider = StudioProvider;
1435
+ exports.useStudioContext = useStudioContext;
1436
+ //# sourceMappingURL=index.cjs.map
1437
+ //# sourceMappingURL=index.cjs.map