@hai3/framework 0.2.0-alpha.0 → 0.2.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
@@ -837,22 +837,53 @@ function layout() {
837
837
  // src/plugins/navigation.ts
838
838
  import { eventBus as eventBus3 } from "@hai3/state";
839
839
  import { i18nRegistry } from "@hai3/i18n";
840
+
841
+ // src/utils/basePath.ts
842
+ function normalizeBase(base) {
843
+ if (!base) {
844
+ return "/";
845
+ }
846
+ let normalized = base.startsWith("/") ? base : `/${base}`;
847
+ if (normalized !== "/" && normalized.endsWith("/")) {
848
+ normalized = normalized.slice(0, -1);
849
+ }
850
+ return normalized;
851
+ }
852
+ function stripBase(pathname, base) {
853
+ if (base === "/") {
854
+ return pathname;
855
+ }
856
+ if (!pathname.startsWith(base)) {
857
+ return null;
858
+ }
859
+ const nextChar = pathname.charAt(base.length);
860
+ if (nextChar && nextChar !== "/") {
861
+ return null;
862
+ }
863
+ return pathname.slice(base.length) || "/";
864
+ }
865
+ function prependBase(path, base) {
866
+ if (base === "/") {
867
+ return path;
868
+ }
869
+ const cleanPath = path.startsWith("/") ? path : `/${path}`;
870
+ return `${base}${cleanPath}`;
871
+ }
872
+ function resolveBase(pluginConfig, appConfig) {
873
+ const rawBase = pluginConfig?.base ?? appConfig?.base ?? "/";
874
+ return normalizeBase(rawBase);
875
+ }
876
+
877
+ // src/plugins/navigation.ts
840
878
  var screenActions4 = screenActions;
841
879
  var menuActions3 = menuActions;
842
- function buildMenuItems(screenset) {
843
- return screenset.menu.map((item) => ({
844
- id: item.menuItem.screenId ?? item.menuItem.id,
845
- label: item.menuItem.label,
846
- icon: item.menuItem.icon
847
- }));
848
- }
849
880
  function navigateToScreen2(payload) {
850
881
  eventBus3.emit("navigation/screen/navigated", payload);
851
882
  }
852
883
  function navigateToScreenset(payload) {
853
884
  eventBus3.emit("navigation/screenset/navigated", payload);
854
885
  }
855
- function navigation() {
886
+ function navigation(config) {
856
887
  return {
857
888
  name: "navigation",
858
889
  dependencies: ["screensets"],
@@ -864,33 +895,66 @@ function navigation() {
864
895
  },
865
896
  onInit(app) {
866
897
  const dispatch = app.store.dispatch;
898
+ const base = resolveBase(config, app.config);
867
899
  let currentScreensetId = null;
868
- async function loadScreensetTranslations(screensetId, language) {
869
- await i18nRegistry.loadScreensetTranslations(screensetId, language);
870
- }
871
- function updateMenuForScreenset(screensetId) {
872
- if (screensetId === currentScreensetId) return;
900
+ const loadScreensetTranslations = async (screensetId, language) => {
901
+ await i18nRegistry.loadScreensetTranslations(
902
+ screensetId,
903
+ language
904
+ );
905
+ };
906
+ const updateScreensetMenu = (screenset) => {
907
+ const menuItems = screenset.menu.map((item) => ({
908
+ id: item.menuItem.screenId ?? item.menuItem.id,
909
+ label: item.menuItem.label,
910
+ icon: item.menuItem.icon
911
+ }));
912
+ dispatch(menuActions3.setMenuItems(menuItems));
913
+ };
914
+ const activateScreenset = (screensetId) => {
915
+ if (screensetId === currentScreensetId) {
916
+ return;
917
+ }
873
918
  const screenset = app.screensetRegistry.get(screensetId);
874
- if (!screenset) return;
919
+ if (!screenset) {
920
+ return;
921
+ }
875
922
  currentScreensetId = screensetId;
876
923
  loadScreensetTranslations(screensetId).catch((err) => {
877
924
  console.warn(`[HAI3] Failed to load translations for screenset ${screensetId}:`, err);
878
925
  });
879
- const menuItems = buildMenuItems(screenset);
880
- dispatch(menuActions3.setMenuItems(menuItems));
881
- }
926
+ updateScreensetMenu(screenset);
927
+ };
928
+ const extractScreenId = () => {
929
+ const internalPath = stripBase(window.location.pathname, base);
930
+ if (!internalPath) {
931
+ return null;
932
+ }
933
+ const parts = internalPath.split("/").filter(Boolean);
934
+ return parts[0] || null;
935
+ };
936
+ const activateScreen = (screenId) => {
937
+ const screensetId = app.routeRegistry?.getScreensetForScreen(screenId);
938
+ if (!screensetId) {
939
+ return;
940
+ }
941
+ activateScreenset(screensetId);
942
+ dispatch(screenActions4.navigateTo(screenId));
943
+ };
882
944
  eventBus3.on("navigation/screen/navigated", (payload) => {
883
- if (app.routeRegistry && !app.routeRegistry.hasScreen(payload.screensetId, payload.screenId)) {
945
+ if (!app.routeRegistry?.hasScreen(payload.screensetId, payload.screenId)) {
884
946
  console.warn(
885
947
  `Screen "${payload.screenId}" in screenset "${payload.screensetId}" not found.`
886
948
  );
887
949
  return;
888
950
  }
889
- updateMenuForScreenset(payload.screensetId);
951
+ activateScreenset(payload.screensetId);
890
952
  dispatch(screenActions4.navigateTo(payload.screenId));
891
953
  if (typeof window !== "undefined") {
892
- const url = `/${payload.screenId}`;
893
- window.history.pushState(null, "", url);
954
+ const url = prependBase(`/${payload.screenId}`, base);
955
+ if (window.location.pathname !== url) {
956
+ window.history.pushState(null, "", url);
957
+ }
894
958
  }
895
959
  });
896
960
  eventBus3.on("navigation/screenset/navigated", (payload) => {
@@ -907,15 +971,18 @@ function navigation() {
907
971
  let lastLoadedLanguage = null;
908
972
  i18nRegistry.subscribe(() => {
909
973
  const currentLanguage = i18nRegistry.getLanguage();
910
- if (!currentLanguage || currentLanguage === lastLoadedLanguage) return;
911
- if (!currentScreensetId) return;
974
+ if (!currentLanguage || currentLanguage === lastLoadedLanguage) {
975
+ return;
976
+ }
977
+ if (!currentScreensetId) {
978
+ return;
979
+ }
912
980
  const screenset = app.screensetRegistry.get(currentScreensetId);
913
- if (!screenset) return;
981
+ if (!screenset) {
982
+ return;
983
+ }
914
984
  lastLoadedLanguage = currentLanguage;
915
- loadScreensetTranslations(currentScreensetId, currentLanguage).then(() => {
916
- const menuItems = buildMenuItems(screenset);
917
- dispatch(menuActions3.setMenuItems(menuItems));
918
- }).catch((err) => {
985
+ loadScreensetTranslations(currentScreensetId, currentLanguage).then(() => updateScreensetMenu(screenset)).catch((err) => {
919
986
  console.warn(
920
987
  `[HAI3] Failed to reload translations for screenset ${currentScreensetId}:`,
921
988
  err
@@ -924,31 +991,15 @@ function navigation() {
924
991
  });
925
992
  if (typeof window !== "undefined") {
926
993
  window.addEventListener("popstate", () => {
927
- const path2 = window.location.pathname;
928
- const parts2 = path2.split("/").filter(Boolean);
929
- if (parts2.length >= 1) {
930
- const screenId = parts2[0];
931
- const screensetId = app.routeRegistry?.getScreensetForScreen(screenId);
932
- if (screensetId) {
933
- updateMenuForScreenset(screensetId);
934
- dispatch(screenActions4.navigateTo(screenId));
935
- }
994
+ const screenId2 = extractScreenId();
995
+ if (screenId2) {
996
+ activateScreen(screenId2);
936
997
  }
937
998
  });
938
- const path = window.location.pathname;
939
- const parts = path.split("/").filter(Boolean);
999
+ const screenId = extractScreenId();
940
1000
  const autoNavigate = app.config.autoNavigate !== false;
941
- if (parts.length >= 1) {
942
- const screenId = parts[0];
943
- const screensetId = app.routeRegistry?.getScreensetForScreen(screenId);
944
- if (screensetId) {
945
- navigateToScreen2({ screensetId, screenId });
946
- } else if (autoNavigate) {
947
- const screensets2 = app.screensetRegistry.getAll();
948
- if (screensets2.length > 0) {
949
- navigateToScreenset({ screensetId: screensets2[0].id });
950
- }
951
- }
1001
+ if (screenId) {
1002
+ activateScreen(screenId);
952
1003
  } else if (autoNavigate) {
953
1004
  const screensets2 = app.screensetRegistry.getAll();
954
1005
  if (screensets2.length > 0) {