@tomehq/theme 0.3.1 → 0.3.2

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.
Files changed (57) hide show
  1. package/dist/{chunk-YXKONM3A.js → chunk-2AXAEADQ.js} +471 -138
  2. package/dist/entry.js +1 -1
  3. package/dist/index.d.ts +21 -1
  4. package/dist/index.js +1 -1
  5. package/package.json +5 -5
  6. package/src/Shell.test.tsx +183 -0
  7. package/src/Shell.tsx +231 -21
  8. package/src/entry.tsx +173 -4
  9. package/src/global.d.ts +11 -0
  10. package/dist/chunk-2APCPR2Y.js +0 -2110
  11. package/dist/chunk-37JI6XGT.js +0 -1720
  12. package/dist/chunk-3A2LPGUL.js +0 -1991
  13. package/dist/chunk-3I2QTWTW.js +0 -1948
  14. package/dist/chunk-45M5UIAB.js +0 -2110
  15. package/dist/chunk-462AGU3S.js +0 -1959
  16. package/dist/chunk-7MUTU5D4.js +0 -1720
  17. package/dist/chunk-ABNPB6BB.js +0 -2133
  18. package/dist/chunk-BZGWSKT2.js +0 -573
  19. package/dist/chunk-CMQCNCSY.js +0 -2127
  20. package/dist/chunk-CTPOZMMK.js +0 -1703
  21. package/dist/chunk-DO544M3G.js +0 -1702
  22. package/dist/chunk-DPKZBFQP.js +0 -1777
  23. package/dist/chunk-EK7PZUEB.js +0 -2147
  24. package/dist/chunk-FMOLIHQF.js +0 -2182
  25. package/dist/chunk-FWBTK5TL.js +0 -1444
  26. package/dist/chunk-GDQIBNX5.js +0 -1962
  27. package/dist/chunk-GHQ2MODM.js +0 -2127
  28. package/dist/chunk-GR2WCRGK.js +0 -2182
  29. package/dist/chunk-HNLKDQ64.js +0 -2139
  30. package/dist/chunk-INUMUXN5.js +0 -2095
  31. package/dist/chunk-IW3NHNOQ.js +0 -2187
  32. package/dist/chunk-JA4PMX6M.js +0 -1500
  33. package/dist/chunk-JSPFS7G5.js +0 -2102
  34. package/dist/chunk-JZRT4WNC.js +0 -1441
  35. package/dist/chunk-KQBY2JDB.js +0 -2112
  36. package/dist/chunk-LIMYFTPC.js +0 -1468
  37. package/dist/chunk-MEP7P6A7.js +0 -1500
  38. package/dist/chunk-NOZBIES7.js +0 -1948
  39. package/dist/chunk-O4GH3KYX.js +0 -1712
  40. package/dist/chunk-OEXM3BEC.js +0 -1702
  41. package/dist/chunk-Q7PYTVW3.js +0 -1771
  42. package/dist/chunk-QCWZYABW.js +0 -1468
  43. package/dist/chunk-RDF25WB2.js +0 -2085
  44. package/dist/chunk-RKTT3ZEX.js +0 -1500
  45. package/dist/chunk-S47BRMNQ.js +0 -1715
  46. package/dist/chunk-S4ZH5F56.js +0 -1949
  47. package/dist/chunk-SRD7NJHS.js +0 -1949
  48. package/dist/chunk-SWFYJO5H.js +0 -2187
  49. package/dist/chunk-TQDWPSTO.js +0 -2087
  50. package/dist/chunk-TTRXRPP6.js +0 -1941
  51. package/dist/chunk-UKYFJSUA.js +0 -509
  52. package/dist/chunk-VKEQHP2E.js +0 -2133
  53. package/dist/chunk-VUT2FMSI.js +0 -1937
  54. package/dist/chunk-VVCC5JHK.js +0 -1949
  55. package/dist/chunk-W732TVBK.js +0 -1944
  56. package/dist/chunk-X4VQYPKO.js +0 -1768
  57. package/dist/chunk-YZ3P3TNS.js +0 -1760
package/dist/entry.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  entry_default
3
- } from "./chunk-YXKONM3A.js";
3
+ } from "./chunk-2AXAEADQ.js";
4
4
  export {
5
5
  entry_default as default
6
6
  };
package/dist/index.d.ts CHANGED
@@ -10,6 +10,7 @@ interface I18nInfo {
10
10
  defaultLocale: string;
11
11
  locales: string[];
12
12
  localeNames?: Record<string, string>;
13
+ localeDirs?: Record<string, "ltr" | "rtl">;
13
14
  }
14
15
  interface ShellProps {
15
16
  config: {
@@ -49,6 +50,12 @@ interface ShellProps {
49
50
  link?: string;
50
51
  dismissible?: boolean;
51
52
  };
53
+ socialLinks?: Array<{
54
+ platform: string;
55
+ url: string;
56
+ label?: string;
57
+ icon?: string;
58
+ }>;
52
59
  [key: string]: unknown;
53
60
  };
54
61
  navigation: Array<{
@@ -58,6 +65,10 @@ interface ShellProps {
58
65
  id: string;
59
66
  urlPath: string;
60
67
  icon?: string;
68
+ badge?: {
69
+ text: string;
70
+ variant: string;
71
+ };
61
72
  }>;
62
73
  }>;
63
74
  currentPageId: string;
@@ -101,8 +112,17 @@ interface ShellProps {
101
112
  content: string;
102
113
  }>;
103
114
  basePath?: string;
115
+ isDraft?: boolean;
116
+ dir?: "ltr" | "rtl";
117
+ overrides?: {
118
+ Header?: React.ComponentType<any>;
119
+ Footer?: React.ComponentType<any>;
120
+ Sidebar?: React.ComponentType<any>;
121
+ Toc?: React.ComponentType<any>;
122
+ PageFooter?: React.ComponentType<any>;
123
+ };
104
124
  }
105
- declare function Shell({ config, navigation, currentPageId, pageHtml, pageComponent, mdxComponents, pageTitle, pageDescription, headings, tocEnabled, editUrl, lastUpdated, changelogEntries, onNavigate, allPages, versioning, currentVersion, i18n, currentLocale, docContext, basePath, }: ShellProps): react_jsx_runtime.JSX.Element;
125
+ declare function Shell({ config, navigation, currentPageId, pageHtml, pageComponent, mdxComponents, pageTitle, pageDescription, headings, tocEnabled, editUrl, lastUpdated, changelogEntries, onNavigate, allPages, versioning, currentVersion, i18n, currentLocale, docContext, basePath, isDraft, dir: dirProp, overrides, }: ShellProps): react_jsx_runtime.JSX.Element;
106
126
 
107
127
  interface AiChatProps {
108
128
  provider: "openai" | "anthropic" | "custom";
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  Shell,
4
4
  THEME_PRESETS,
5
5
  entry_default
6
- } from "./chunk-YXKONM3A.js";
6
+ } from "./chunk-2AXAEADQ.js";
7
7
  export {
8
8
  AiChat,
9
9
  entry_default as App,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomehq/theme",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Tome default theme and React app shell",
5
5
  "type": "module",
6
6
  "main": "./src/index.tsx",
@@ -9,8 +9,8 @@
9
9
  "./entry": "./src/entry.tsx"
10
10
  },
11
11
  "dependencies": {
12
- "@tomehq/components": "0.3.1",
13
- "@tomehq/core": "0.3.1"
12
+ "@tomehq/components": "0.3.2",
13
+ "@tomehq/core": "0.3.2"
14
14
  },
15
15
  "peerDependencies": {
16
16
  "react": "^18.0.0 || ^19.0.0",
@@ -41,11 +41,11 @@
41
41
  "license": "MIT",
42
42
  "repository": {
43
43
  "type": "git",
44
- "url": "https://github.com/vxcozy/tome.git",
44
+ "url": "https://github.com/tomehq/tome.git",
45
45
  "directory": "packages/theme"
46
46
  },
47
47
  "scripts": {
48
- "build": "tsup src/index.tsx src/entry.tsx --format esm --dts --external react --external react-dom --external 'virtual:tome/config' --external 'virtual:tome/routes' --external 'virtual:tome/page-loader' --external 'virtual:tome/doc-context' --external '@tomehq/components'",
48
+ "build": "tsup src/index.tsx src/entry.tsx --format esm --dts --external react --external react-dom --external 'virtual:tome/config' --external 'virtual:tome/routes' --external 'virtual:tome/page-loader' --external 'virtual:tome/doc-context' --external 'virtual:tome/overrides' --external '@tomehq/components'",
49
49
  "dev": "tsup src/index.tsx src/entry.tsx --format esm --dts --external react --external react-dom --external 'virtual:tome/config' --external 'virtual:tome/routes' --external 'virtual:tome/page-loader' --external 'virtual:tome/doc-context' --external '@tomehq/components' --watch",
50
50
  "clean": "rm -rf dist"
51
51
  }
@@ -860,6 +860,115 @@ describe("Shell feedback widget", () => {
860
860
  });
861
861
  });
862
862
 
863
+ // ── Breadcrumbs ──────────────────────────────────────────
864
+
865
+ describe("Shell breadcrumbs", () => {
866
+ const multiSectionNav = [
867
+ {
868
+ section: "Getting Started",
869
+ pages: [
870
+ { id: "intro", title: "Introduction", urlPath: "/intro" },
871
+ { id: "quickstart", title: "Quick Start", urlPath: "/quickstart" },
872
+ ],
873
+ },
874
+ {
875
+ section: "Guides",
876
+ pages: [
877
+ { id: "search", title: "Search", urlPath: "/search" },
878
+ { id: "deploy", title: "Deploy", urlPath: "/deploy" },
879
+ ],
880
+ },
881
+ ];
882
+
883
+ const multiSectionAllPages = [
884
+ { id: "intro", title: "Introduction" },
885
+ { id: "quickstart", title: "Quick Start" },
886
+ { id: "search", title: "Search" },
887
+ { id: "deploy", title: "Deploy" },
888
+ ];
889
+
890
+ it("renders breadcrumbs for a non-index page", () => {
891
+ renderShell({
892
+ navigation: multiSectionNav,
893
+ allPages: multiSectionAllPages,
894
+ currentPageId: "quickstart",
895
+ pageTitle: "Quick Start",
896
+ });
897
+ const breadcrumbs = screen.getByTestId("breadcrumbs");
898
+ expect(breadcrumbs).toBeInTheDocument();
899
+ expect(within(breadcrumbs).getByText("Getting Started")).toBeInTheDocument();
900
+ expect(within(breadcrumbs).getByText("Quick Start")).toBeInTheDocument();
901
+ });
902
+
903
+ it("does not render breadcrumbs on the index page", () => {
904
+ renderShell({
905
+ currentPageId: "index",
906
+ pageTitle: "Home",
907
+ });
908
+ expect(screen.queryByTestId("breadcrumbs")).not.toBeInTheDocument();
909
+ });
910
+
911
+ it("renders section name as a link", () => {
912
+ renderShell({
913
+ navigation: multiSectionNav,
914
+ allPages: multiSectionAllPages,
915
+ currentPageId: "deploy",
916
+ pageTitle: "Deploy",
917
+ });
918
+ const breadcrumbs = screen.getByTestId("breadcrumbs");
919
+ const sectionLink = within(breadcrumbs).getByText("Guides");
920
+ expect(sectionLink.tagName).toBe("A");
921
+ });
922
+
923
+ it("renders current page as plain text (not a link)", () => {
924
+ renderShell({
925
+ navigation: multiSectionNav,
926
+ allPages: multiSectionAllPages,
927
+ currentPageId: "deploy",
928
+ pageTitle: "Deploy",
929
+ });
930
+ const breadcrumbs = screen.getByTestId("breadcrumbs");
931
+ const currentPage = within(breadcrumbs).getByText("Deploy");
932
+ expect(currentPage.tagName).toBe("SPAN");
933
+ });
934
+
935
+ it("clicking section link calls onNavigate with first page id", () => {
936
+ const onNavigate = vi.fn();
937
+ renderShell({
938
+ navigation: multiSectionNav,
939
+ allPages: multiSectionAllPages,
940
+ currentPageId: "deploy",
941
+ pageTitle: "Deploy",
942
+ onNavigate,
943
+ });
944
+ const breadcrumbs = screen.getByTestId("breadcrumbs");
945
+ fireEvent.click(within(breadcrumbs).getByText("Guides"));
946
+ expect(onNavigate).toHaveBeenCalledWith("search");
947
+ });
948
+
949
+ it("renders separator between breadcrumb items", () => {
950
+ renderShell({
951
+ navigation: multiSectionNav,
952
+ allPages: multiSectionAllPages,
953
+ currentPageId: "quickstart",
954
+ pageTitle: "Quick Start",
955
+ });
956
+ const breadcrumbs = screen.getByTestId("breadcrumbs");
957
+ expect(breadcrumbs.textContent).toContain("\u203A");
958
+ });
959
+
960
+ it("has proper aria-label for accessibility", () => {
961
+ renderShell({
962
+ navigation: multiSectionNav,
963
+ allPages: multiSectionAllPages,
964
+ currentPageId: "quickstart",
965
+ pageTitle: "Quick Start",
966
+ });
967
+ const nav = screen.getByRole("navigation", { name: "Breadcrumbs" });
968
+ expect(nav).toBeInTheDocument();
969
+ });
970
+ });
971
+
863
972
  // ── Image zoom ───────────────────────────────────────────
864
973
 
865
974
  describe("Shell image zoom", () => {
@@ -869,3 +978,77 @@ describe("Shell image zoom", () => {
869
978
  expect(zoomOverlay).toBeNull();
870
979
  });
871
980
  });
981
+
982
+ // ── RTL support ──────────────────────────────────────────
983
+
984
+ describe("Shell RTL support", () => {
985
+ it("sets dir='rtl' on root element when dir prop is 'rtl'", () => {
986
+ const { container } = renderShell({ dir: "rtl" });
987
+ const root = container.querySelector("[dir='rtl']");
988
+ expect(root).not.toBeNull();
989
+ });
990
+
991
+ it("sets dir='ltr' on root element by default", () => {
992
+ const { container } = renderShell();
993
+ const root = container.querySelector("[dir='ltr']");
994
+ expect(root).not.toBeNull();
995
+ });
996
+
997
+ it("sets dir='ltr' when dir prop is explicitly 'ltr'", () => {
998
+ const { container } = renderShell({ dir: "ltr" });
999
+ const root = container.querySelector("[dir='ltr']");
1000
+ expect(root).not.toBeNull();
1001
+ expect(container.querySelector("[dir='rtl']")).toBeNull();
1002
+ });
1003
+
1004
+ it("resolves dir from i18n.localeDirs when dir prop is not set", () => {
1005
+ const { container } = renderShell({
1006
+ i18n: {
1007
+ defaultLocale: "en",
1008
+ locales: ["en", "ar"],
1009
+ localeDirs: { ar: "rtl" },
1010
+ },
1011
+ currentLocale: "ar",
1012
+ });
1013
+ const root = container.querySelector("[dir='rtl']");
1014
+ expect(root).not.toBeNull();
1015
+ });
1016
+
1017
+ it("defaults to ltr when locale has no entry in localeDirs", () => {
1018
+ const { container } = renderShell({
1019
+ i18n: {
1020
+ defaultLocale: "en",
1021
+ locales: ["en", "ar"],
1022
+ localeDirs: { ar: "rtl" },
1023
+ },
1024
+ currentLocale: "en",
1025
+ });
1026
+ const root = container.querySelector("[dir='ltr']");
1027
+ expect(root).not.toBeNull();
1028
+ });
1029
+
1030
+ it("reverses main layout flex direction for RTL", () => {
1031
+ const { container } = renderShell({ dir: "rtl" });
1032
+ const flexRow = container.querySelector('[style*="flex-direction: row-reverse"]');
1033
+ expect(flexRow).not.toBeNull();
1034
+ });
1035
+
1036
+ it("uses normal row direction for LTR", () => {
1037
+ const { container } = renderShell({ dir: "ltr" });
1038
+ const flexRowReverse = container.querySelector('[style*="flex-direction: row-reverse"]');
1039
+ expect(flexRowReverse).toBeNull();
1040
+ });
1041
+
1042
+ it("mirrors sidebar border to borderLeft for RTL", () => {
1043
+ const { container } = renderShell({ dir: "rtl" });
1044
+ const aside = container.querySelector("aside");
1045
+ expect(aside).not.toBeNull();
1046
+ expect(aside!.style.borderLeft).toContain("1px solid");
1047
+ });
1048
+
1049
+ it("renders without errors in RTL mode", () => {
1050
+ expect(() =>
1051
+ renderShell({ dir: "rtl" })
1052
+ ).not.toThrow();
1053
+ });
1054
+ });