@tomehq/theme 0.3.0 → 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 (54) hide show
  1. package/dist/{chunk-GR2WCRGK.js → chunk-2AXAEADQ.js} +496 -153
  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 +207 -20
  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-HNLKDQ64.js +0 -2139
  29. package/dist/chunk-INUMUXN5.js +0 -2095
  30. package/dist/chunk-JA4PMX6M.js +0 -1500
  31. package/dist/chunk-JSPFS7G5.js +0 -2102
  32. package/dist/chunk-JZRT4WNC.js +0 -1441
  33. package/dist/chunk-KQBY2JDB.js +0 -2112
  34. package/dist/chunk-LIMYFTPC.js +0 -1468
  35. package/dist/chunk-MEP7P6A7.js +0 -1500
  36. package/dist/chunk-NOZBIES7.js +0 -1948
  37. package/dist/chunk-O4GH3KYX.js +0 -1712
  38. package/dist/chunk-OEXM3BEC.js +0 -1702
  39. package/dist/chunk-Q7PYTVW3.js +0 -1771
  40. package/dist/chunk-QCWZYABW.js +0 -1468
  41. package/dist/chunk-RDF25WB2.js +0 -2085
  42. package/dist/chunk-RKTT3ZEX.js +0 -1500
  43. package/dist/chunk-S47BRMNQ.js +0 -1715
  44. package/dist/chunk-S4ZH5F56.js +0 -1949
  45. package/dist/chunk-SRD7NJHS.js +0 -1949
  46. package/dist/chunk-TQDWPSTO.js +0 -2087
  47. package/dist/chunk-TTRXRPP6.js +0 -1941
  48. package/dist/chunk-UKYFJSUA.js +0 -509
  49. package/dist/chunk-VKEQHP2E.js +0 -2133
  50. package/dist/chunk-VUT2FMSI.js +0 -1937
  51. package/dist/chunk-VVCC5JHK.js +0 -1949
  52. package/dist/chunk-W732TVBK.js +0 -1944
  53. package/dist/chunk-X4VQYPKO.js +0 -1768
  54. 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-GR2WCRGK.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-GR2WCRGK.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.0",
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.0",
13
- "@tomehq/core": "0.3.0"
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
+ });