react-markdown-table-ts 1.2.2 → 1.3.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.
@@ -0,0 +1,35 @@
1
+ name: build
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - name: Checkout code
15
+ uses: actions/checkout@v4
16
+ with:
17
+ fetch-depth: 0
18
+
19
+ - name: Setup Node.js
20
+ uses: actions/setup-node@v4
21
+ with:
22
+ node-version: 24
23
+ cache: 'npm'
24
+
25
+ - name: Install dependencies
26
+ run: npm ci
27
+
28
+ - name: Build Storybook
29
+ run: npm run build-storybook
30
+
31
+ - name: Publish to Chromatic
32
+ uses: chromaui/action@latest
33
+ with:
34
+ projectToken: ${{ secrets.CHROMATIC_TOKEN }}
35
+ storybookBuildDir: storybook-static
@@ -0,0 +1,31 @@
1
+ name: Publish to NPM
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ jobs:
7
+ publish:
8
+ runs-on: ubuntu-latest
9
+ steps:
10
+ - name: Checkout repository
11
+ uses: actions/checkout@v4
12
+
13
+ - name: Setup Node.js
14
+ uses: actions/setup-node@v4
15
+ with:
16
+ node-version: '22'
17
+ registry-url: 'https://registry.npmjs.org'
18
+
19
+ - name: Install dependencies
20
+ run: npm ci
21
+
22
+ - name: Run tests
23
+ run: npm test
24
+
25
+ - name: Build package
26
+ run: npx tsc
27
+
28
+ - name: Publish to NPM
29
+ run: npm publish
30
+ env:
31
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,42 @@
1
+ name: Test Coverage
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+
13
+ strategy:
14
+ matrix:
15
+ node-version: [20.x]
16
+
17
+ steps:
18
+ - name: Checkout code
19
+ uses: actions/checkout@v4
20
+
21
+ - name: Setup Node.js ${{ matrix.node-version }}
22
+ uses: actions/setup-node@v4
23
+ with:
24
+ node-version: ${{ matrix.node-version }}
25
+ cache: 'npm'
26
+
27
+ - name: Install dependencies
28
+ run: npm ci
29
+
30
+ - name: Run tests with coverage
31
+ run: npm run test:coverage
32
+
33
+ - name: Upload coverage to Codecov
34
+ uses: codecov/codecov-action@v4
35
+ with:
36
+ token: ${{ secrets.CODECOV_TOKEN }}
37
+ files: ./coverage/clover.xml,./coverage/lcov.info
38
+ flags: unittests
39
+ name: codecov-umbrella
40
+ fail_ci_if_error: true
41
+ verbose: true
42
+
package/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+
2
+ node_modules
3
+ dist
4
+ dist-ssr
5
+ package-lock.json
6
+ .*
7
+ !.github
8
+ !.storybook
9
+ !.gitignore
10
+ coverage/
11
+ *storybook.log
12
+ storybook-static
@@ -0,0 +1,13 @@
1
+ import type { StorybookConfig } from '@storybook/react-vite';
2
+
3
+ const config: StorybookConfig = {
4
+ "stories": [
5
+ "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"
6
+ ],
7
+ "addons": [],
8
+ "framework": {
9
+ "name": "@storybook/react-vite",
10
+ "options": {}
11
+ }
12
+ };
13
+ export default config;
@@ -0,0 +1,6 @@
1
+ import { addons } from "storybook/manager-api";
2
+ import theme from "./theme";
3
+
4
+ addons.setConfig({
5
+ theme: theme,
6
+ });
@@ -0,0 +1,14 @@
1
+ import type { Preview } from '@storybook/react-vite'
2
+
3
+ const preview: Preview = {
4
+ parameters: {
5
+ controls: {
6
+ matchers: {
7
+ color: /(background|color)$/i,
8
+ date: /Date$/i,
9
+ },
10
+ },
11
+ },
12
+ };
13
+
14
+ export default preview;
@@ -0,0 +1,8 @@
1
+ import { create } from "storybook/theming";
2
+
3
+ export default create({
4
+ base: "light",
5
+ brandTitle: "react-markdown-table-ts",
6
+ brandUrl: "https://github.com/keithwalsh/react-markdown-table-ts",
7
+ brandTarget: "_self",
8
+ });
package/README.md CHANGED
@@ -1,17 +1,18 @@
1
1
  # ⚛️ react-markdown-table-ts 🛡️
2
2
 
3
+ ![build](https://github.com/keithwalsh/react-markdown-table-ts/actions/workflows/build.yml/badge.svg)
3
4
  [![NPM Version](https://img.shields.io/npm/v/react-markdown-table-ts.svg)](https://www.npmjs.com/package/react-markdown-table-ts)
4
5
  [![codecov](https://codecov.io/gh/keithwalsh/react-markdown-table-ts/branch/main/graph/badge.svg)](https://codecov.io/gh/keithwalsh/react-markdown-table-ts)
5
- ![Build](https://github.com/keithwalsh/react-markdown-table-ts/actions/workflows/build.yml/badge.svg)
6
6
  [![Code Climate](https://codeclimate.com/github/keithwalsh/react-markdown-table-ts/badges/gpa.svg)](https://codeclimate.com/github/keithwalsh/react-markdown-table-ts)
7
- [![GitHub branch status](https://img.shields.io/github/checks-status/keithwalsh/react-markdown-table-ts/HEAD)](https://github.com/keithwalsh/react-markdown-table-ts/commits/HEAD/)
7
+ [![code quality](https://img.shields.io/codefactor/grade/github/keithwalsh/react-markdown-table-ts)](https://www.codefactor.io/repository/github/keithwalsh/react-markdown-table-ts)
8
+ ![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?style=flat-square&logo=typescript&logoColor=white)
8
9
 
9
10
  | ![Light Theme Example](public/light.png) | ![Dark Theme Example](public/dark.png) |
10
11
  |------------------------------------------|-----------------------------------------|
11
12
  | `'light'` theme | `'dark'` theme |
12
13
 
13
14
  ## Overview
14
- This library provides a React component for generating and displaying formatted Markdown tables with syntax highlighting. The core component is `MarkdownTable` which converts 2D array data into properly formatted Markdown table syntax. Columns of variable width maintain consistent spacing across all rows, ensuring vertical alignment of delimiters. For syntax highlighting and line numbering, Prism.js is used within a `<pre>` HTML element.
15
+ A React component for generating and displaying formatted Markdown tables with syntax highlighting. The core component is `MarkdownTable` which converts 2D array data into properly formatted Markdown table syntax. Columns of variable width maintain consistent spacing across all rows, ensuring vertical alignment of delimiters. For syntax highlighting and line numbering, Prism.js is used within a `<pre>` HTML element.
15
16
 
16
17
  ## API
17
18
  ```typescript
@@ -28,23 +29,25 @@ interface MarkdownTableProps {
28
29
  className?: string;
29
30
  preStyle?: React.CSSProperties;
30
31
  minWidth?: number;
32
+ showLineNumbers?: boolean;
31
33
  onGenerate?: (markdownTableString: string) => void;
32
34
  }
33
35
  ```
34
36
  | Prop | Type | Default | Description |
35
37
  |----------------------|-----------------------------------------|-------------|------------------------------------------------------------------------------------|
36
38
  | `inputData` | `string[][] \| null` | `null` | The outer array represents rows. The inner array represent cells within each row. |
37
- | `columnAlignments` | `readonly Alignment[]` | `[]` | Acceptable values are 'left', 'center', 'right', 'justify', or 'none'. Defaults to 'none' when unspecified. |
39
+ | `columnAlignments` | `readonly Alignment[]` | `[]` | Acceptable values are 'left', 'center', 'right', or 'none'. Defaults to 'none' when unspecified. |
38
40
  | `isCompact` | `boolean` | `false` | Disables column width alignment to provide a more compact markdown table string. |
39
41
  | `hasPadding` | `boolean` | `true` | One space added before and after the content in each cell. |
40
42
  | `hasTabs` | `boolean` | `false` | Adds a tab character after each \| and before the content. |
41
43
  | `hasHeader` | `boolean` | `true` | Indicates whether the first row of `data` is a header. |
42
44
  | `convertLineBreaks` | `boolean` | `false` | Replace newlines with <br> tags in table cells. |
43
45
  | `topPadding` | `number` | `16` | Controls the padding-top (in pixels) of the \<pre\> element display. |
44
- | `theme` | `'light' \| 'dark'` | `light` | Controls the color scheme of the \<pre\> element display. |
46
+ | `theme` | `'light' \| 'dark'` | `light` | Controls the colour scheme of the \<pre\> element display. |
45
47
  | `className` | `string` | `undefined` | Class will be applied to the \<pre\> element display. |
46
48
  | `preStyle` | `React.CSSProperties` | `undefined` | Allows direct styling of the display with CSS properties. |
47
49
  | `minWidth` | `number` | `undefined` | Optional minimum width in pixels for the table container. |
50
+ | `showLineNumbers` | `boolean` | `true` | Show or hide line numbers in the Prism syntax highlighting. |
48
51
  | `onGenerate` | `(markdownTableString: string) => void` | `undefined` | Callback to receive the generated Markdown table string. |
49
52
  ## Usage Patterns
50
53
 
@@ -61,7 +64,7 @@ interface MarkdownTableProps {
61
64
  ```typescript
62
65
  <MarkdownTable
63
66
  inputData={data}
64
- columnAlignments={['left', 'center', 'right', 'justify']}
67
+ columnAlignments={['left', 'center', 'right']}
65
68
  />
66
69
  ```
67
70
  3. **Auto-Generated Headers**:
@@ -78,20 +81,26 @@ interface MarkdownTableProps {
78
81
  minWidth={500} // Sets the minimum width of the table container to 500 pixels
79
82
  />
80
83
  ```
84
+ 5. **Hiding Line Numbers**:
85
+ ```typescript
86
+ <MarkdownTable
87
+ inputData={data}
88
+ showLineNumbers={false} // Hides line numbers in the code block
89
+ />
90
+ ```
81
91
 
82
- ## Behaviors
92
+ ## Behaviours
83
93
 
84
94
  1. **Input Validation**:
85
95
  - Input must be non-null 2D string array
86
96
  - All rows should contain string values
87
97
  - Empty arrays are not allowed
88
- - Column alignments must be valid ('left', 'center', 'right', 'justify', 'none')
98
+ - Column alignments must be valid ('left', 'center', 'right', 'none')
89
99
 
90
100
  2. **Column Width Handling**:
91
101
  - Default: Adjusts columns to fit content with 'none' alignment
92
102
  - `isCompact={true}`: Minimizes column widths
93
103
  - Maintains minimum width of 3 characters for alignment indicators
94
- - 'justify' alignment behaves same as 'none' for markdown compatibility
95
104
 
96
105
  3. **Error Handling**:
97
106
  - Returns error message string if validation fails
@@ -106,7 +115,7 @@ interface MarkdownTableProps {
106
115
  ## Common Transformations
107
116
 
108
117
  1. **Data Formatting**:
109
- - Newlines can be converted to `<br>` tags with `canReplaceNewlines`
118
+ - Newlines can be converted to `<br>` tags with `convertLineBreaks`
110
119
  - Padding can be controlled with `hasPadding`
111
120
  - Tab spacing available with `hasTabs`
112
121
 
package/jest.config.js ADDED
@@ -0,0 +1,38 @@
1
+ module.exports = {
2
+ preset: 'ts-jest',
3
+ testEnvironment: 'jsdom',
4
+ roots: ['<rootDir>/src'],
5
+ testMatch: ['**/__tests__/**/*.ts?(x)', '**/?(*.)+(spec|test).ts?(x)'],
6
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
7
+ setupFilesAfterEnv: ['<rootDir>/src/tests/setup.ts'],
8
+ collectCoverageFrom: [
9
+ 'src/**/*.{ts,tsx}',
10
+ '!src/**/*.d.ts',
11
+ '!src/stories/**',
12
+ '!src/tests/**',
13
+ ],
14
+ coverageThreshold: {
15
+ global: {
16
+ branches: 80,
17
+ functions: 80,
18
+ lines: 80,
19
+ statements: 80,
20
+ },
21
+ },
22
+ transform: {
23
+ '^.+\\.tsx?$': ['ts-jest', {
24
+ tsconfig: {
25
+ jsx: 'react-jsx',
26
+ esModuleInterop: true,
27
+ allowSyntheticDefaultImports: true,
28
+ verbatimModuleSyntax: false,
29
+ module: 'commonjs',
30
+ moduleResolution: 'node',
31
+ },
32
+ }],
33
+ },
34
+ moduleNameMapper: {
35
+ '\\.(css|less|scss|sass)$': '<rootDir>/src/tests/__mocks__/styleMock.js',
36
+ },
37
+ };
38
+
package/package.json CHANGED
@@ -1,88 +1,52 @@
1
1
  {
2
2
  "name": "react-markdown-table-ts",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
4
4
  "description": "A React component that converts structured data into Markdown table syntax and displays it within a `<pre>` tag.",
5
- "main": "dist/index.cjs.js",
6
- "module": "dist/index.esm.js",
7
- "types": "dist/index.d.ts",
8
- "files": [
9
- "dist"
10
- ],
11
- "scripts": {
12
- "build": "rollup -c",
13
- "type-check": "tsc --noEmit",
14
- "prepublishOnly": "npm run build",
15
- "prepare": "npm run build",
16
- "lint": "gts lint",
17
- "clean": "gts clean",
18
- "compile": "tsc",
19
- "fix": "gts fix",
20
- "pretest": "npm run compile",
21
- "posttest": "npm run lint",
22
- "test": "jest --config jest.config.js --coverage",
23
- "test:watch": "jest --config jest.config.js --watch",
24
- "test:ci": "jest --config jest.config.js --coverage --ci",
25
- "release": "standard-version",
26
- "storybook": "storybook dev -p 6006",
27
- "build-storybook": "storybook build",
28
- "chromatic": "npx chromatic --project-token=chpt_f61460f108c0eb8"
29
- },
30
5
  "keywords": [
31
6
  "markdown",
32
7
  "md",
33
8
  "table",
34
9
  "tables",
35
10
  "react",
36
- "ts",
37
- "typescript",
38
- "types",
39
- "typed",
40
11
  "generate",
41
12
  "generator",
42
13
  "convert",
43
14
  "converter"
44
15
  ],
45
- "author": "Keith Walsh",
46
- "license": "MIT",
47
- "repository": "https://github.com/keithwalsh/react-markdown-table-ts.git",
48
- "peerDependencies": {
49
- "react": "^18.2.0",
50
- "react-dom": "^18.2.0"
16
+ "homepage": "https://github.com/keithwalsh/react-markdown-table-ts#readme",
17
+ "bugs": {
18
+ "url": "https://github.com/keithwalsh/react-markdown-table-ts/issues"
19
+ },
20
+ "scripts": {
21
+ "dev": "vite",
22
+ "build": "tsc -b && vite build",
23
+ "preview": "vite preview",
24
+ "test": "jest",
25
+ "test:watch": "jest --watch",
26
+ "test:coverage": "jest --coverage",
27
+ "storybook": "storybook dev -p 6006",
28
+ "build-storybook": "storybook build"
29
+ },
30
+ "dependencies": {
31
+ "prismjs": "^1.30.0",
32
+ "react": "^19.1.1",
33
+ "react-dom": "^19.1.1"
51
34
  },
52
35
  "devDependencies": {
53
- "@chromatic-com/storybook": "^3.2.2",
54
- "@rollup/plugin-commonjs": "^26.0.3",
55
- "@rollup/plugin-node-resolve": "^15.3.0",
56
- "@rollup/plugin-typescript": "^11.1.6",
57
- "@storybook/addon-essentials": "^8.4.5",
58
- "@storybook/addon-interactions": "^8.4.5",
59
- "@storybook/addon-onboarding": "^8.4.5",
60
- "@storybook/blocks": "^8.4.5",
61
- "@storybook/react-vite": "^8.4.5",
62
- "@storybook/test": "^8.4.5",
63
- "@testing-library/jest-dom": "^6.5.0",
64
- "@testing-library/react": "^16.0.1",
65
- "@types/jest": "^29.5.13",
66
- "@types/node": "20.12.7",
67
- "@types/prismjs": "^1.26.4",
68
- "@types/react": "^18.3.8",
69
- "@types/react-dom": "^18.3.0",
70
- "chromatic": "^11.20.0",
71
- "eslint-plugin-storybook": "^0.11.1",
72
- "gts": "^5.3.1",
73
- "identity-obj-proxy": "^3.0.0",
36
+ "@storybook/react-vite": "^9.1.10",
37
+ "@testing-library/jest-dom": "^6.6.3",
38
+ "@testing-library/react": "^16.3.0",
39
+ "@types/jest": "^29.5.14",
40
+ "@types/node": "^24.6.0",
41
+ "@types/prismjs": "^1.26.5",
42
+ "@types/react": "^19.1.16",
43
+ "@types/react-dom": "^19.1.9",
44
+ "@vitejs/plugin-react-swc": "^4.1.0",
74
45
  "jest": "^29.7.0",
75
46
  "jest-environment-jsdom": "^29.7.0",
76
- "react": "^18.2.0",
77
- "react-dom": "^18.2.0",
78
- "rollup": "^2.79.1",
79
- "rollup-plugin-typescript2": "^0.36.0",
80
- "standard-version": "^9.5.0",
81
- "storybook": "^8.4.5",
47
+ "storybook": "^9.1.10",
82
48
  "ts-jest": "^29.2.5",
83
- "typescript": "^5.1.6"
84
- },
85
- "dependencies": {
86
- "prismjs": "^1.29.0"
49
+ "typescript": "~5.9.3",
50
+ "vite": "^7.1.7"
87
51
  }
88
52
  }
Binary file
Binary file
package/src/index.tsx ADDED
@@ -0,0 +1,176 @@
1
+ /**
2
+ * @fileoverview Main MarkdownTable component that generates and displays markdown
3
+ * table syntax with Prism.js syntax highlighting.
4
+ */
5
+
6
+ import { useEffect, useMemo, useRef, useDeferredValue, useTransition, useId } from 'react';
7
+ import Prism from 'prismjs';
8
+ import 'prismjs/components/prism-markdown';
9
+ import 'prismjs/plugins/line-numbers/prism-line-numbers';
10
+ import type { Alignment, MarkdownTableProps } from './types';
11
+ import { generateMarkdownTableString, generateAlphabetHeaders } from './utils';
12
+ import { validateInputData, MarkdownTableError } from './validation';
13
+
14
+ const LIGHT_THEME_CSS = `
15
+ code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}pre[class*=language-].line-numbers{position:relative;padding-left:2.4em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.5em;text-align:right}
16
+ `;
17
+
18
+ const DARK_THEME_CSS = `
19
+ code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#282a36}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}pre[class*=language-].line-numbers{position:relative;padding-left:2.4em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.5em;text-align:right}
20
+ `;
21
+
22
+ function getTableData(inputData: string[][], hasHeader: boolean) {
23
+ return hasHeader
24
+ ? { inputDataHeader: inputData[0], inputDataBody: inputData.slice(1) }
25
+ : { inputDataHeader: generateAlphabetHeaders(inputData[0].length), inputDataBody: inputData };
26
+ }
27
+
28
+ function generateTableSyntax(
29
+ inputData: string[][] | null,
30
+ hasHeader: boolean,
31
+ columnAlignments: readonly Alignment[],
32
+ adjustColumnWidths: boolean,
33
+ hasTabs: boolean,
34
+ canReplaceNewlines: boolean,
35
+ hasPadding: boolean
36
+ ): string {
37
+ try {
38
+ validateInputData(inputData);
39
+ const { inputDataHeader, inputDataBody } = getTableData(inputData as string[][], hasHeader);
40
+
41
+ return generateMarkdownTableString(
42
+ { inputDataHeader, inputDataBody },
43
+ columnAlignments,
44
+ adjustColumnWidths,
45
+ hasTabs,
46
+ canReplaceNewlines,
47
+ hasPadding
48
+ );
49
+ } catch (error) {
50
+ if (error instanceof MarkdownTableError) {
51
+ return `Error: ${error.message}`;
52
+ }
53
+ throw error;
54
+ }
55
+ }
56
+
57
+ export function MarkdownTable({
58
+ inputData = null,
59
+ hasHeader = true,
60
+ columnAlignments = [],
61
+ isCompact = false,
62
+ hasTabs = false,
63
+ hasPadding = true,
64
+ convertLineBreaks = false,
65
+ className,
66
+ onGenerate,
67
+ theme = 'light',
68
+ preStyle,
69
+ topPadding = 16,
70
+ minWidth,
71
+ showLineNumbers = true,
72
+ }: MarkdownTableProps) {
73
+ const preElementRef = useRef<HTMLPreElement>(null);
74
+ const id = useId();
75
+ const deferredInputData = useDeferredValue(inputData);
76
+ const [, startTransition] = useTransition();
77
+
78
+ const markdownTableSyntax = useMemo(() => generateTableSyntax(
79
+ deferredInputData,
80
+ hasHeader,
81
+ columnAlignments,
82
+ !isCompact,
83
+ hasTabs,
84
+ convertLineBreaks,
85
+ hasPadding
86
+ ), [
87
+ deferredInputData,
88
+ hasHeader,
89
+ columnAlignments,
90
+ isCompact,
91
+ hasTabs,
92
+ convertLineBreaks,
93
+ hasPadding,
94
+ ]);
95
+
96
+ useEffect(() => {
97
+ if (onGenerate) {
98
+ onGenerate(markdownTableSyntax);
99
+ }
100
+ }, [markdownTableSyntax, onGenerate]);
101
+
102
+ useEffect(() => {
103
+ const codeElement = preElementRef.current?.querySelector('code');
104
+ if (codeElement && markdownTableSyntax) {
105
+ startTransition(() => {
106
+ requestAnimationFrame(() => {
107
+ Prism.highlightElement(codeElement as HTMLElement);
108
+
109
+ // Remove line numbers if showLineNumbers is false
110
+ if (!showLineNumbers && preElementRef.current) {
111
+ const lineNumbersRows = preElementRef.current.querySelector('.line-numbers-rows');
112
+ if (lineNumbersRows) {
113
+ lineNumbersRows.remove();
114
+ }
115
+ }
116
+ });
117
+ });
118
+ }
119
+ }, [markdownTableSyntax, startTransition, showLineNumbers]);
120
+
121
+ return (
122
+ <>
123
+ <style>
124
+ {theme === 'light' ? LIGHT_THEME_CSS : DARK_THEME_CSS}
125
+ {`
126
+ pre {
127
+ position: relative;
128
+ padding-top: ${topPadding}px !important;
129
+ }
130
+ pre::before {
131
+ position: absolute;
132
+ top: 8px;
133
+ left: 12px;
134
+ color: ${theme === 'light' ? '#666' : '#999'};
135
+ letter-spacing: 2px;
136
+ font-size: 12px;
137
+ }
138
+ /* Hide line numbers when showLineNumbers is false */
139
+ pre:not(.line-numbers) .line-numbers-rows {
140
+ display: none !important;
141
+ }
142
+ /* Remove left padding when line numbers are hidden */
143
+ pre:not(.line-numbers) {
144
+ padding-left: 1em !important;
145
+ }
146
+ pre:not(.line-numbers) > code {
147
+ padding-left: 0 !important;
148
+ }
149
+ `}
150
+ </style>
151
+ <div
152
+ id={id}
153
+ style={{
154
+ position: 'relative',
155
+ isolation: 'isolate',
156
+ display: 'inline-block'
157
+ }}
158
+ >
159
+ <pre
160
+ ref={preElementRef}
161
+ className={`${className} language-markdown ${showLineNumbers ? 'line-numbers' : ''} ${theme === 'dark' ? 'dark-theme' : ''}`}
162
+ style={{
163
+ width: 'fit-content',
164
+ minWidth: minWidth ? `${minWidth}px` : 'min-content',
165
+ margin: 0,
166
+ ...preStyle
167
+ }}
168
+ >
169
+ <code className="language-markdown" role="code">
170
+ {markdownTableSyntax}
171
+ </code>
172
+ </pre>
173
+ </div>
174
+ </>
175
+ );
176
+ }
package/src/prism.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ declare module 'prismjs' {
2
+ const Prism: {
3
+ highlightElement: (element: HTMLElement) => void;
4
+ };
5
+ export default Prism;
6
+ }