@multiplatform.one/markdown 7.7.4 → 7.8.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.
Files changed (60) hide show
  1. package/dist/cjs/Aside/index.native.js.map +1 -1
  2. package/dist/cjs/ExternalIcon/index.native.js.map +1 -1
  3. package/dist/cjs/Hr/index.native.js.map +1 -1
  4. package/dist/cjs/Li/index.native.js.map +1 -1
  5. package/dist/cjs/Markdown.native.js.map +1 -1
  6. package/dist/cjs/MarkdownSimpleTable/index.native.js.map +1 -1
  7. package/dist/cjs/Mdx/index.native.js +1 -1
  8. package/dist/cjs/Mdx/index.native.js.map +1 -1
  9. package/dist/cjs/MdxCodeBlock/index.native.js +1 -1
  10. package/dist/cjs/MdxCodeBlock/index.native.js.map +1 -1
  11. package/dist/cjs/MdxCodeBlock/mdxCodeBlockContext.native.js.map +1 -1
  12. package/dist/cjs/Notice/index.native.js.map +1 -1
  13. package/dist/cjs/Table/index.native.js.map +1 -1
  14. package/dist/cjs/Tabs/index.native.js.map +1 -1
  15. package/dist/cjs/Ul/index.native.js.map +1 -1
  16. package/dist/cjs/Video/index.native.js.map +1 -1
  17. package/dist/cjs/components/Blockquote.native.js.map +1 -1
  18. package/dist/cjs/components/Break.native.js.map +1 -1
  19. package/dist/cjs/components/CodeBlock.native.js.map +1 -1
  20. package/dist/cjs/components/Heading.native.js.map +1 -1
  21. package/dist/cjs/components/HorizontalRule.native.js.map +1 -1
  22. package/dist/cjs/components/Image.native.js.map +1 -1
  23. package/dist/cjs/components/InlineCode.native.js.map +1 -1
  24. package/dist/cjs/components/InlineStyles.native.js.map +1 -1
  25. package/dist/cjs/components/Link.native.js.map +1 -1
  26. package/dist/cjs/components/List.native.js +1 -1
  27. package/dist/cjs/components/List.native.js.map +1 -1
  28. package/dist/cjs/components/Paragraph.native.js.map +1 -1
  29. package/dist/cjs/components/Table.native.js.map +1 -1
  30. package/dist/cjs/components/index.native.js.map +1 -1
  31. package/dist/cjs/hooks/index.native.js.map +1 -1
  32. package/dist/cjs/hooks/useCompileAndEvaluateMdx.native.js.map +1 -1
  33. package/dist/cjs/hooks/useCompileMdx.native.js.map +1 -1
  34. package/dist/cjs/hooks/useEvaluateMdx.native.js.map +1 -1
  35. package/dist/cjs/icons/index.native.js.map +1 -1
  36. package/dist/cjs/index.native.js +15 -15
  37. package/dist/cjs/index.native.js.map +1 -1
  38. package/dist/cjs/mdxComponents.native.js +5 -5
  39. package/dist/cjs/mdxComponents.native.js.map +1 -1
  40. package/dist/cjs/mermaid/MermaidBlock.native.js +1 -1
  41. package/dist/cjs/mermaid/index.native.js.map +1 -1
  42. package/dist/cjs/mermaid/mountDiagramSvg.native.js.map +1 -1
  43. package/dist/cjs/parser.native.js.map +1 -1
  44. package/dist/cjs/renderer.native.js +1 -1
  45. package/dist/cjs/renderer.native.js.map +1 -1
  46. package/dist/cjs/shared/colorRamps.native.js.map +1 -1
  47. package/dist/cjs/shared/cutoffGradient.native.js.map +1 -1
  48. package/dist/cjs/shared/index.native.js.map +1 -1
  49. package/dist/cjs/shared/textRidesText.native.js.map +1 -1
  50. package/dist/cjs/shared/tokenPx.native.js.map +1 -1
  51. package/dist/cjs/shared/useMarkdownTableKnobs.native.js.map +1 -1
  52. package/dist/cjs/shiki/index.native.js.map +1 -1
  53. package/dist/cjs/types.native.js.map +1 -1
  54. package/dist/cjs/util/rehypeMetaAttributes.native.js.map +1 -1
  55. package/package.json +10 -9
  56. package/src/Table/MDXTable.spec.tsx +37 -0
  57. package/src/Tabs/MDXTabs.spec.tsx +73 -0
  58. package/src/Video/Video.spec.tsx +48 -0
  59. package/src/components/markdownPrimitives.spec.tsx +5 -70
  60. package/src/docBlocks.spec.tsx +2 -43
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@multiplatform.one/markdown",
3
- "version": "7.7.4",
3
+ "version": "7.8.0",
4
4
  "description": "Cross-platform markdown renderer with Shiki syntax highlighting for React and React Native",
5
5
  "keywords": [
6
6
  "cross-platform",
@@ -82,14 +82,15 @@
82
82
  "tamagui": "2.7.6",
83
83
  "unified": "^11.0.5",
84
84
  "unist-util-visit": "^5.1.0",
85
- "@multiplatform.one/components": "7.7.4",
86
- "@multiplatform.one/platform": "7.7.4",
87
- "@multiplatform.one/router": "7.7.4",
88
- "@multiplatform.one/table-primitives": "7.7.4",
89
- "@multiplatform.one/theme": "7.7.4"
85
+ "@multiplatform.one/router": "7.8.0",
86
+ "@multiplatform.one/components": "7.8.0",
87
+ "@multiplatform.one/platform": "7.8.0",
88
+ "@multiplatform.one/theme": "7.8.0",
89
+ "@multiplatform.one/table-primitives": "7.8.0"
90
90
  },
91
91
  "devDependencies": {
92
92
  "@tamagui/build": "2.7.6",
93
+ "@testing-library/jest-dom": "^6.9.1",
93
94
  "@testing-library/react": "^16.3.2",
94
95
  "@types/mdast": "^4.0.4",
95
96
  "@types/mdx": "^2.0.13",
@@ -98,9 +99,9 @@
98
99
  "react": "19.2.5",
99
100
  "react-dom": "19.2.5",
100
101
  "vitest": "^4.1.5",
101
- "@multiplatform.one/config": "7.7.4",
102
- "@multiplatform.one/storybook": "7.7.4",
103
- "@multiplatform.one/test-utils": "7.7.4"
102
+ "@multiplatform.one/storybook": "7.8.0",
103
+ "@multiplatform.one/config": "7.8.0",
104
+ "@multiplatform.one/test-utils": "7.8.0"
104
105
  },
105
106
  "peerDependencies": {
106
107
  "react": "^19.1.0",
@@ -0,0 +1,37 @@
1
+ /**
2
+ * MDXTable spec (MPO-177). Stories live in Markdown/Tables; this file is the
3
+ * colocated lock that the MDX table family still paints real table semantics.
4
+ */
5
+
6
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
7
+ import { describe, expect, it } from "vitest";
8
+ import {
9
+ MDXTable,
10
+ MDXTableBody,
11
+ MDXTableCell,
12
+ MDXTableHead,
13
+ MDXTableHeaderCell,
14
+ MDXTableRow,
15
+ } from "./index";
16
+
17
+ describe("MDXTable", () => {
18
+ it("renders the family into table/thead/tbody/tr/th/td", () => {
19
+ const { container } = renderWithProviders(
20
+ <MDXTable>
21
+ <MDXTableHead>
22
+ <MDXTableRow>
23
+ <MDXTableHeaderCell>Header</MDXTableHeaderCell>
24
+ </MDXTableRow>
25
+ </MDXTableHead>
26
+ <MDXTableBody>
27
+ <MDXTableRow>
28
+ <MDXTableCell>Data</MDXTableCell>
29
+ </MDXTableRow>
30
+ </MDXTableBody>
31
+ </MDXTable>,
32
+ );
33
+ expect(container.querySelector("table")).toBeTruthy();
34
+ expect(container.querySelector("thead th")?.textContent).toContain("Header");
35
+ expect(container.querySelector("tbody td")?.textContent).toContain("Data");
36
+ });
37
+ });
@@ -0,0 +1,73 @@
1
+ /**
2
+ * MDXTabs spec (MPO-177). Stories live in Markdown/Media; this file is the
3
+ * colocated lock that the LC-16 wrapper still paints a real tablist.
4
+ */
5
+
6
+ import { fireEvent, screen } from "@testing-library/react";
7
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
8
+ import { Text } from "tamagui";
9
+ import { describe, expect, it } from "vitest";
10
+ import { MDXTab, MDXTabs } from "./index";
11
+
12
+ describe("MDXTabs (canonical Tabs)", () => {
13
+ const renderTabs = (defaultValue?: string) =>
14
+ renderWithProviders(
15
+ <MDXTabs items={["npm", "pnpm"]} defaultValue={defaultValue}>
16
+ {[
17
+ <MDXTab key="npm">
18
+ <Text>npm panel</Text>
19
+ </MDXTab>,
20
+ <MDXTab key="pnpm">
21
+ <Text>pnpm panel</Text>
22
+ </MDXTab>,
23
+ ]}
24
+ </MDXTabs>,
25
+ );
26
+
27
+ it("renders a real tablist with aria-selected tabs", () => {
28
+ renderTabs();
29
+ expect(screen.getByRole("tablist")).toBeInTheDocument();
30
+ const tabs = screen.getAllByRole("tab");
31
+ expect(tabs).toHaveLength(2);
32
+ expect(tabs[0]).toHaveAttribute("aria-selected", "true");
33
+ expect(screen.getByText("npm panel")).toBeInTheDocument();
34
+ });
35
+
36
+ it("switches panels on click", () => {
37
+ renderTabs();
38
+ fireEvent.click(screen.getByText("pnpm"));
39
+ expect(screen.getByText("pnpm panel")).toBeInTheDocument();
40
+ const tabs = screen.getAllByRole("tab");
41
+ expect(tabs[1]).toHaveAttribute("aria-selected", "true");
42
+ });
43
+
44
+ it("respects defaultValue addressed by label", () => {
45
+ renderTabs("pnpm");
46
+ expect(screen.getByText("pnpm panel")).toBeInTheDocument();
47
+ });
48
+
49
+ it("handles duplicate labels via index-suffixed values", () => {
50
+ renderWithProviders(
51
+ <MDXTabs items={["same", "same"]}>
52
+ {[
53
+ <MDXTab key="a">
54
+ <Text>first panel</Text>
55
+ </MDXTab>,
56
+ <MDXTab key="b">
57
+ <Text>second panel</Text>
58
+ </MDXTab>,
59
+ ]}
60
+ </MDXTabs>,
61
+ );
62
+ const tabs = screen.getAllByRole("tab");
63
+ expect(tabs).toHaveLength(2);
64
+ fireEvent.click(tabs[1]!);
65
+ expect(screen.getByText("second panel")).toBeInTheDocument();
66
+ });
67
+
68
+ it("renders nothing dangerous for empty items", () => {
69
+ const { container } = renderWithProviders(<MDXTabs items={[]}>{[]}</MDXTabs>);
70
+ expect(container).toBeTruthy();
71
+ expect(screen.queryAllByRole("tab")).toHaveLength(0);
72
+ });
73
+ });
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Video spec (MPO-177). Stories live in Markdown/Media; this file is the
3
+ * colocated anatomy lock (web <video> + SB-M-1227 empty-src omission).
4
+ */
5
+
6
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
7
+ import { describe, expect, it } from "vitest";
8
+ import { Video } from "./index";
9
+
10
+ describe("Video (web)", () => {
11
+ it("renders a muted, autoplaying, looping inline <video> inside a figure", () => {
12
+ const { container } = renderWithProviders(<Video src="https://example.com/clip.mp4" />);
13
+ expect(container.querySelector("figure")).toBeTruthy();
14
+ const video = container.querySelector("video");
15
+ expect(video).toBeTruthy();
16
+ expect(video!.getAttribute("src")).toBe("https://example.com/clip.mp4");
17
+ // Boolean media attributes reflect the safe-autoplay defaults.
18
+ expect(video!.hasAttribute("autoplay")).toBe(true);
19
+ expect(video!.hasAttribute("loop")).toBe(true);
20
+ expect(video!.hasAttribute("playsinline")).toBe(true);
21
+ expect(video!.hasAttribute("controls")).toBe(false);
22
+ });
23
+
24
+ it("omits the <video> element entirely for an empty src (SB-M-1227)", () => {
25
+ const { container } = renderWithProviders(<Video src="" />);
26
+ expect(container.querySelector("video")).toBeNull();
27
+ expect(container.querySelector("figure")).toBeTruthy();
28
+ });
29
+
30
+ it("forwards controls/poster and renders children as a figcaption", () => {
31
+ const { container } = renderWithProviders(
32
+ <Video src="https://example.com/clip.mp4" controls poster="https://example.com/poster.png">
33
+ A demo caption
34
+ </Video>,
35
+ );
36
+ const video = container.querySelector("video");
37
+ expect(video!.hasAttribute("controls")).toBe(true);
38
+ expect(video!.getAttribute("poster")).toBe("https://example.com/poster.png");
39
+ const caption = container.querySelector("figcaption");
40
+ expect(caption).toBeTruthy();
41
+ expect(caption!.textContent).toBe("A demo caption");
42
+ });
43
+
44
+ it("renders no figcaption without children", () => {
45
+ const { container } = renderWithProviders(<Video src="https://example.com/clip.mp4" />);
46
+ expect(container.querySelector("figcaption")).toBeNull();
47
+ });
48
+ });
@@ -1,17 +1,15 @@
1
1
  /**
2
- * LC-16 wrapper specs — the markdown package renders code blocks, inline
3
- * code, and doc tabs through the canonical `@multiplatform.one/components`
4
- * implementations (census items #9 / #12); these tests pin the wrappers to
5
- * the canonical anatomy.
2
+ * LC-16 wrapper specs — the markdown package renders code blocks and inline
3
+ * code through the canonical `@multiplatform.one/components` implementations
4
+ * (census items #9 / #12); these tests pin the wrappers to that anatomy.
5
+ * Doc tabs live in Tabs/MDXTabs.spec.tsx (MPO-177).
6
6
  */
7
7
 
8
- import { fireEvent, screen, waitFor } from "@testing-library/react";
8
+ import { waitFor } from "@testing-library/react";
9
9
  import { renderWithProviders } from "@multiplatform.one/test-utils";
10
- import { Text } from "tamagui";
11
10
  import { describe, expect, it } from "vitest";
12
11
  import { CodeBlock } from "./CodeBlock";
13
12
  import { InlineCode } from "./InlineCode";
14
- import { MDXTab, MDXTabs } from "../Tabs";
15
13
 
16
14
  describe("markdown CodeBlock (canonical code family)", () => {
17
15
  it("renders code content inside a real <code> element", async () => {
@@ -56,66 +54,3 @@ describe("markdown InlineCode (canonical CodeInline)", () => {
56
54
  expect(code!.textContent).toBe("npm install");
57
55
  });
58
56
  });
59
-
60
- describe("MDXTabs (canonical Tabs)", () => {
61
- const renderTabs = (defaultValue?: string) =>
62
- renderWithProviders(
63
- <MDXTabs items={["npm", "pnpm"]} defaultValue={defaultValue}>
64
- {[
65
- <MDXTab key="npm">
66
- <Text>npm panel</Text>
67
- </MDXTab>,
68
- <MDXTab key="pnpm">
69
- <Text>pnpm panel</Text>
70
- </MDXTab>,
71
- ]}
72
- </MDXTabs>,
73
- );
74
-
75
- it("renders a real tablist with aria-selected tabs", () => {
76
- renderTabs();
77
- expect(screen.getByRole("tablist")).toBeInTheDocument();
78
- const tabs = screen.getAllByRole("tab");
79
- expect(tabs).toHaveLength(2);
80
- expect(tabs[0]).toHaveAttribute("aria-selected", "true");
81
- expect(screen.getByText("npm panel")).toBeInTheDocument();
82
- });
83
-
84
- it("switches panels on click", () => {
85
- renderTabs();
86
- fireEvent.click(screen.getByText("pnpm"));
87
- expect(screen.getByText("pnpm panel")).toBeInTheDocument();
88
- const tabs = screen.getAllByRole("tab");
89
- expect(tabs[1]).toHaveAttribute("aria-selected", "true");
90
- });
91
-
92
- it("respects defaultValue addressed by label", () => {
93
- renderTabs("pnpm");
94
- expect(screen.getByText("pnpm panel")).toBeInTheDocument();
95
- });
96
-
97
- it("handles duplicate labels via index-suffixed values", () => {
98
- renderWithProviders(
99
- <MDXTabs items={["same", "same"]}>
100
- {[
101
- <MDXTab key="a">
102
- <Text>first panel</Text>
103
- </MDXTab>,
104
- <MDXTab key="b">
105
- <Text>second panel</Text>
106
- </MDXTab>,
107
- ]}
108
- </MDXTabs>,
109
- );
110
- const tabs = screen.getAllByRole("tab");
111
- expect(tabs).toHaveLength(2);
112
- fireEvent.click(tabs[1]!);
113
- expect(screen.getByText("second panel")).toBeInTheDocument();
114
- });
115
-
116
- it("renders nothing dangerous for empty items", () => {
117
- const { container } = renderWithProviders(<MDXTabs items={[]}>{[]}</MDXTabs>);
118
- expect(container).toBeTruthy();
119
- expect(screen.queryAllByRole("tab")).toHaveLength(0);
120
- });
121
- });
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Doc building-block specs — the MDX-facing blocks docs compose directly:
3
- * `Video` (web <video> anatomy + SB-M-1227 empty-src omission), `MDXAside`
4
- * (cutoff + "Show more" expansion) and `MDXNote` (Alert-based note box).
3
+ * `MDXAside` (cutoff + "Show more" expansion) and `MDXNote` (Alert-based
4
+ * note box). Video anatomy lives in Video/Video.spec.tsx (MPO-177).
5
5
  */
6
6
 
7
7
  import { fireEvent, screen } from "@testing-library/react";
@@ -9,47 +9,6 @@ import { renderWithProviders } from "@multiplatform.one/test-utils";
9
9
  import { Text } from "tamagui";
10
10
  import { describe, expect, it } from "vitest";
11
11
  import { MDXAside, MDXNote } from "./Aside";
12
- import { Video } from "./Video";
13
-
14
- describe("Video (web)", () => {
15
- it("renders a muted, autoplaying, looping inline <video> inside a figure", () => {
16
- const { container } = renderWithProviders(<Video src="https://example.com/clip.mp4" />);
17
- expect(container.querySelector("figure")).toBeTruthy();
18
- const video = container.querySelector("video");
19
- expect(video).toBeTruthy();
20
- expect(video!.getAttribute("src")).toBe("https://example.com/clip.mp4");
21
- // Boolean media attributes reflect the safe-autoplay defaults.
22
- expect(video!.hasAttribute("autoplay")).toBe(true);
23
- expect(video!.hasAttribute("loop")).toBe(true);
24
- expect(video!.hasAttribute("playsinline")).toBe(true);
25
- expect(video!.hasAttribute("controls")).toBe(false);
26
- });
27
-
28
- it("omits the <video> element entirely for an empty src (SB-M-1227)", () => {
29
- const { container } = renderWithProviders(<Video src="" />);
30
- expect(container.querySelector("video")).toBeNull();
31
- expect(container.querySelector("figure")).toBeTruthy();
32
- });
33
-
34
- it("forwards controls/poster and renders children as a figcaption", () => {
35
- const { container } = renderWithProviders(
36
- <Video src="https://example.com/clip.mp4" controls poster="https://example.com/poster.png">
37
- A demo caption
38
- </Video>,
39
- );
40
- const video = container.querySelector("video");
41
- expect(video!.hasAttribute("controls")).toBe(true);
42
- expect(video!.getAttribute("poster")).toBe("https://example.com/poster.png");
43
- const caption = container.querySelector("figcaption");
44
- expect(caption).toBeTruthy();
45
- expect(caption!.textContent).toBe("A demo caption");
46
- });
47
-
48
- it("renders no figcaption without children", () => {
49
- const { container } = renderWithProviders(<Video src="https://example.com/clip.mp4" />);
50
- expect(container.querySelector("figcaption")).toBeNull();
51
- });
52
- });
53
12
 
54
13
  describe("MDXAside", () => {
55
14
  it("renders string content as a plain aside without a cutoff", () => {