react-markdown-table-ts 1.3.0 → 1.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.
package/src/index.tsx DELETED
@@ -1,176 +0,0 @@
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 DELETED
@@ -1,6 +0,0 @@
1
- declare module 'prismjs' {
2
- const Prism: {
3
- highlightElement: (element: HTMLElement) => void;
4
- };
5
- export default Prism;
6
- }
@@ -1,212 +0,0 @@
1
- /**
2
- * @fileoverview Storybook stories for the MarkdownTable component, demonstrating
3
- * various configurations and use cases for markdown table generation and display.
4
- */
5
-
6
- import type { Meta, StoryObj } from '@storybook/react';
7
- import { MarkdownTable } from '../index'
8
-
9
- const meta = {
10
- title: 'Components/MarkdownTable',
11
- component: MarkdownTable,
12
- parameters: {
13
- layout: 'centered'
14
- },
15
- tags: ['autodocs'],
16
- args: {
17
- inputData: null,
18
- columnAlignments: [],
19
- isCompact: false,
20
- hasPadding: true,
21
- hasTabs: false,
22
- hasHeader: true,
23
- convertLineBreaks: false,
24
- topPadding: 16,
25
- theme: 'light' as const,
26
- showLineNumbers: true
27
- },
28
- argTypes: {
29
- inputData: {
30
- control: {
31
- type: 'object'
32
- },
33
- description: 'The outer array represents rows. The inner array represent cells within each row.',
34
- table: {
35
- category: 'Core Data Props',
36
- type: {
37
- summary: 'string[][] | null'
38
- }
39
- }
40
- },
41
- columnAlignments: {
42
- control: {
43
- type: 'object'
44
- },
45
- description: 'An array specifying the alignment for each column.',
46
- table: {
47
- category: 'Core Data Props',
48
- type: {
49
- summary: 'readonly Alignment[]',
50
- detail: 'export type Alignment = "left" | "right" | "center" | "none";'
51
- }
52
- }
53
- },
54
- isCompact: {
55
- control: 'boolean',
56
- description: 'Disables column width alignment to provide a more compact markdown table string.',
57
- table: {
58
- category: 'Configuration Props',
59
- type: {
60
- summary: 'boolean'
61
- }
62
- }
63
- },
64
- hasPadding: {
65
- control: 'boolean',
66
- description: 'Optional flag to add a single space around cell content in the markdown table.',
67
- table: {
68
- category: 'Configuration Props',
69
- type: {
70
- summary: 'boolean'
71
- }
72
- }
73
- },
74
- hasTabs: {
75
- control: 'boolean',
76
- description: 'Optional flag to add tabs as additional padding between column pipes.',
77
- table: {
78
- category: 'Configuration Props',
79
- type: {
80
- summary: 'boolean'
81
- }
82
- }
83
- },
84
- hasHeader: {
85
- control: 'boolean',
86
- description: 'Indicates whether the first row of `data` is a header.',
87
- table: {
88
- category: 'Configuration Props',
89
- type: {
90
- summary: 'boolean'
91
- }
92
- }
93
- },
94
- convertLineBreaks: {
95
- control: 'boolean',
96
- description: 'Optional flag to replace newlines with `<br>` tags in table cells.',
97
- table: {
98
- category: 'Configuration Props',
99
- type: {
100
- summary: 'boolean'
101
- }
102
- }
103
- },
104
- topPadding: {
105
- control: {
106
- type: 'number'
107
- },
108
- description: 'Controls the padding-top (in pixels) of the pre element display.',
109
- table: {
110
- category: 'Visual/UI Props',
111
- type: {
112
- summary: 'number'
113
- }
114
- }
115
- },
116
- theme: {
117
- options: ['light', 'dark'],
118
- control: { type: 'select' },
119
- description: 'Switch between light and dark mode.',
120
- table: {
121
- category: 'Visual/UI Props',
122
- type: {
123
- summary: "'light' | 'dark'"
124
- },
125
- defaultValue: { summary: 'light' }
126
- }
127
- },
128
- className: {
129
- control: 'text',
130
- description: 'Optional CSS class for styling the rendered Markdown table.',
131
- table: {
132
- category: 'Visual/UI Props',
133
- type: {
134
- summary: 'string'
135
- }
136
- }
137
- },
138
- preStyle: {
139
- control: {
140
- type: 'object'
141
- },
142
- description: 'Optional inline styles for the pre element.',
143
- table: {
144
- category: 'Visual/UI Props',
145
- type: {
146
- summary: 'React.CSSProperties'
147
- }
148
- }
149
- },
150
- minWidth: {
151
- control: {
152
- type: 'number'
153
- },
154
- description: 'Optional minimum width in pixels for the table container.',
155
- table: {
156
- category: 'Visual/UI Props',
157
- type: {
158
- summary: 'number'
159
- }
160
- }
161
- },
162
- showLineNumbers: {
163
- control: 'boolean',
164
- description: 'Optional flag to show or hide line numbers in the Prism syntax highlighting.',
165
- table: {
166
- category: 'Visual/UI Props',
167
- type: {
168
- summary: 'boolean'
169
- },
170
- defaultValue: { summary: 'true' }
171
- }
172
- },
173
- onGenerate: {
174
- description: 'Callback function that receives the generated Markdown table string.',
175
- table: {
176
- category: 'Callbacks',
177
- type: {
178
- summary: '(markdownTableString: string) => void'
179
- }
180
- }
181
- }
182
- }
183
- } satisfies Meta<typeof MarkdownTable>
184
-
185
- export default meta
186
- type Story = StoryObj<typeof MarkdownTable>
187
-
188
- // Move sample data before its usage
189
- const sampleData = [
190
- ['Package ID', 'Weight (kg)', 'Status', 'Destination'],
191
- ['PKG-2024-001', '12.50', 'In Transit', 'Dublin, IE'],
192
- ['PKG-2024-002', '3.75', 'Delivered', 'New York, US'],
193
- ['PKG-2024-003', '8.20', 'Processing', 'Frankfurt, DE'],
194
- ['PKG-2024-004', '5.60', 'In Transit', 'London, GB']
195
- ]
196
-
197
- export const Default: Story = {
198
- args: {
199
- inputData: sampleData,
200
- columnAlignments: ['left', 'right', 'center', 'none'],
201
- isCompact: false,
202
- hasPadding: true,
203
- hasTabs: false,
204
- hasHeader: true,
205
- convertLineBreaks: false,
206
- topPadding: 16,
207
- theme: 'light',
208
- className: 'markdown-table-pre',
209
- preStyle: {borderRadius: '8px'},
210
- minWidth: 450
211
- }
212
- }
@@ -1,2 +0,0 @@
1
- module.exports = {};
2
-