@hai3/studio 0.1.0-alpha.1 → 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.
package/dist/index.js CHANGED
@@ -1,9 +1,8 @@
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';
1
+ import React4, { createContext, useContext, useState, useEffect, useCallback, useRef } from 'react';
2
+ import { I18nRegistry, Language, i18nRegistry, ScreensetCategory, eventBus, useTranslation, useNavigation, screensetRegistry, useTheme, getLanguageMetadata, LanguageDisplayMode, SUPPORTED_LANGUAGES, TextDirection, apiRegistry } from '@hai3/react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { Card, Button, ButtonSize, ButtonVariant, DropdownMenu, DropdownMenuTrigger, DropdownButton, DropdownMenuContent, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuItem, Switch } from '@hai3/uikit';
5
5
  import { clamp, upperFirst } from 'lodash';
6
- import { ButtonVariant as ButtonVariant$1 } from '@hai3/uikit-contracts';
7
6
 
8
7
  var __create = Object.create;
9
8
  var __defProp = Object.defineProperty;
@@ -1052,25 +1051,23 @@ var useResizable = () => {
1052
1051
  var ThemeSelector = ({
1053
1052
  className = ""
1054
1053
  }) => {
1055
- const dispatch = useAppDispatch();
1056
- const currentTheme = useAppSelector((state) => state.uicore.layout.theme);
1054
+ const { currentTheme, themes, setTheme } = useTheme();
1057
1055
  const { portalContainer } = useStudioContext();
1058
1056
  const { t } = useTranslation();
1059
1057
  const formatThemeName = (themeName) => {
1060
1058
  return themeName.split("-").map((word) => upperFirst(word)).join(" ");
1061
1059
  };
1062
- const availableThemes = themeRegistry.getThemeNames();
1063
1060
  return /* @__PURE__ */ jsxs("div", { className: `flex items-center justify-between ${className}`, children: [
1064
1061
  /* @__PURE__ */ jsx("label", { className: "text-sm text-muted-foreground whitespace-nowrap", children: t("studio:controls.theme") }),
1065
1062
  /* @__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(
1063
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownButton, { variant: ButtonVariant.Outline, children: formatThemeName(currentTheme || "") }) }),
1064
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: themes.map((theme) => /* @__PURE__ */ jsx(
1068
1065
  DropdownMenuItem,
1069
1066
  {
1070
- onClick: () => dispatch(changeTheme(themeName)),
1071
- children: formatThemeName(themeName)
1067
+ onClick: () => setTheme(theme.id),
1068
+ children: formatThemeName(theme.name || theme.id)
1072
1069
  },
1073
- themeName
1070
+ theme.id
1074
1071
  )) })
1075
1072
  ] })
1076
1073
  ] });
@@ -1083,7 +1080,7 @@ var ScreensetSelector = ({
1083
1080
  className = ""
1084
1081
  }) => {
1085
1082
  const { portalContainer } = useStudioContext();
1086
- const { t, direction } = useTranslation();
1083
+ const { t, isRTL } = useTranslation();
1087
1084
  const formatName = (name) => {
1088
1085
  return name.split(/[-_]/).map((word) => upperFirst(word)).join(" ");
1089
1086
  };
@@ -1099,8 +1096,8 @@ var ScreensetSelector = ({
1099
1096
  };
1100
1097
  return /* @__PURE__ */ jsxs("div", { className: `flex items-center justify-between ${className}`, children: [
1101
1098
  /* @__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()) }) }),
1099
+ /* @__PURE__ */ jsxs(DropdownMenu, { dir: isRTL ? "rtl" : "ltr", children: [
1100
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownButton, { variant: ButtonVariant.Outline, children: formatName(getCurrentDisplay()) }) }),
1104
1101
  /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: options.map((categoryGroup) => /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
1105
1102
  /* @__PURE__ */ jsx(DropdownMenuSubTrigger, { disabled: categoryGroup.screensets.length === 0, children: formatName(categoryGroup.category) }),
1106
1103
  /* @__PURE__ */ jsx(DropdownMenuSubContent, { container: portalContainer, className: "z-[99999] pointer-events-auto", children: categoryGroup.screensets.map((item) => /* @__PURE__ */ jsx(
@@ -1121,18 +1118,17 @@ var RTL_INDICATOR_SUFFIX = " (RTL)";
1121
1118
  function LanguageSelector({
1122
1119
  displayMode = LanguageDisplayMode.Native
1123
1120
  } = {}) {
1124
- const { t, language, changeLanguage, getSupportedLanguages } = useTranslation();
1121
+ const { t, language, setLanguage } = useTranslation();
1125
1122
  const { portalContainer } = useStudioContext();
1126
- const languages = getSupportedLanguages();
1127
- const currentLanguage = languages.find((lang) => lang.code === language);
1123
+ const currentLanguage = language ? getLanguageMetadata(language) : null;
1128
1124
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1129
1125
  /* @__PURE__ */ jsx("label", { className: "text-sm text-muted-foreground whitespace-nowrap", children: t("studio:controls.language") }),
1130
1126
  /* @__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(
1127
+ /* @__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 }) }),
1128
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", container: portalContainer, className: "z-[99999] pointer-events-auto", children: SUPPORTED_LANGUAGES.map((lang) => /* @__PURE__ */ jsxs(
1133
1129
  DropdownMenuItem,
1134
1130
  {
1135
- onClick: () => changeLanguage(lang.code),
1131
+ onClick: () => setLanguage(lang.code),
1136
1132
  children: [
1137
1133
  displayMode === LanguageDisplayMode.Native ? lang.name : lang.englishName,
1138
1134
  lang.direction === TextDirection.RightToLeft && RTL_INDICATOR_SUFFIX
@@ -1144,8 +1140,12 @@ function LanguageSelector({
1144
1140
  ] });
1145
1141
  }
1146
1142
  var ApiModeToggle = ({ className }) => {
1147
- const useMockApi = useAppSelector((state) => state.uicore.app.useMockApi);
1143
+ const [useMockApi, setUseMockApi] = useState(true);
1148
1144
  const { t } = useTranslation();
1145
+ const handleToggle = (checked) => {
1146
+ setUseMockApi(checked);
1147
+ apiRegistry.setMockMode(checked);
1148
+ };
1149
1149
  return /* @__PURE__ */ jsxs("div", { className: `flex items-center justify-between h-9 ${className}`, children: [
1150
1150
  /* @__PURE__ */ jsx(
1151
1151
  "label",
@@ -1160,7 +1160,7 @@ var ApiModeToggle = ({ className }) => {
1160
1160
  {
1161
1161
  id: "api-mode-toggle",
1162
1162
  checked: useMockApi,
1163
- onCheckedChange: (checked) => setApiMode(checked)
1163
+ onCheckedChange: handleToggle
1164
1164
  }
1165
1165
  )
1166
1166
  ] });
@@ -1168,20 +1168,35 @@ var ApiModeToggle = ({ className }) => {
1168
1168
  ApiModeToggle.displayName = "ApiModeToggle";
1169
1169
  var ALL_CATEGORIES = [ScreensetCategory.Drafts, ScreensetCategory.Mockups, ScreensetCategory.Production];
1170
1170
  var buildScreensetOptions = () => {
1171
+ const allScreensets = screensetRegistry.getAll();
1171
1172
  return ALL_CATEGORIES.map((category) => ({
1172
1173
  category,
1173
- screensets: screensetRegistry.getMetadataByCategory(category)
1174
+ screensets: allScreensets.filter((s) => s.category === category).map((s) => ({
1175
+ id: s.id,
1176
+ name: s.name
1177
+ }))
1174
1178
  }));
1175
1179
  };
1176
1180
  var ControlPanel = () => {
1177
- const dispatch = useAppDispatch();
1178
- const currentScreenset = useAppSelector((state) => state.uicore.layout.currentScreenset);
1181
+ const { currentScreenset, navigateToScreenset } = useNavigation();
1179
1182
  const [screensetOptions, setScreensetOptions] = useState([]);
1180
1183
  const { t } = useTranslation();
1181
1184
  useEffect(() => {
1182
1185
  const options = buildScreensetOptions();
1183
1186
  setScreensetOptions(options);
1184
1187
  }, []);
1188
+ const getCurrentValue = () => {
1189
+ if (!currentScreenset) return "";
1190
+ const screenset = screensetRegistry.get(currentScreenset);
1191
+ if (!screenset) return "";
1192
+ return `${screenset.category}:${screenset.id}`;
1193
+ };
1194
+ const handleScreensetChange = (value) => {
1195
+ const [, screensetId] = value.split(":");
1196
+ if (screensetId) {
1197
+ navigateToScreenset(screensetId);
1198
+ }
1199
+ };
1185
1200
  return /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
1186
1201
  /* @__PURE__ */ jsx("h3", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: t("studio:controls.heading") }),
1187
1202
  /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
@@ -1189,8 +1204,8 @@ var ControlPanel = () => {
1189
1204
  ScreensetSelector,
1190
1205
  {
1191
1206
  options: screensetOptions,
1192
- currentValue: currentScreenset,
1193
- onChange: (value) => dispatch(selectScreenset(value))
1207
+ currentValue: getCurrentValue(),
1208
+ onChange: handleScreensetChange
1194
1209
  }
1195
1210
  ),
1196
1211
  /* @__PURE__ */ jsx(ApiModeToggle, {}),
@@ -1203,13 +1218,13 @@ ControlPanel.displayName = "ControlPanel";
1203
1218
  var StudioPanel = () => {
1204
1219
  const { toggleCollapsed, setPortalContainer } = useStudioContext();
1205
1220
  const { t } = useTranslation();
1206
- const portalRef = React3.useRef(null);
1221
+ const portalRef = React4.useRef(null);
1207
1222
  const { size, handleMouseDown: handleResizeMouseDown } = useResizable();
1208
1223
  const { position, isDragging, handleMouseDown: handleDragMouseDown } = useDraggable({
1209
1224
  panelSize: size,
1210
1225
  storageKey: STORAGE_KEYS.POSITION
1211
1226
  });
1212
- React3.useEffect(() => {
1227
+ React4.useEffect(() => {
1213
1228
  setPortalContainer(portalRef.current);
1214
1229
  return () => setPortalContainer(null);
1215
1230
  }, [setPortalContainer]);