md-editor-lite 0.1.4 → 0.1.6

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/dist/index.mjs CHANGED
@@ -1,42 +1,36 @@
1
1
  // src/components/EditorHeader.tsx
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import "./editor-AUU3A4EA.css";
3
3
  function EditorHeader({
4
4
  mode,
5
5
  setMode,
6
6
  insertMarkdown
7
7
  }) {
8
- return /* @__PURE__ */ jsxs("header", { className: "editor-header", children: [
9
- /* @__PURE__ */ jsx(EditorTab, { mode, setMode }),
10
- mode === "write" && /* @__PURE__ */ jsx(Toolbar, { insertMarkdown })
11
- ] });
8
+ return /* @__PURE__ */ React.createElement("header", { className: "editor-header" }, /* @__PURE__ */ React.createElement(EditorTab, { mode, setMode }), mode === "write" && /* @__PURE__ */ React.createElement(Toolbar, { insertMarkdown }));
12
9
  }
13
10
 
14
11
  // src/components/EditorTab.tsx
15
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
12
+ import "./editor-AUU3A4EA.css";
16
13
  function EditorTab({ mode, setMode }) {
17
- return /* @__PURE__ */ jsxs2("div", { className: "editor-tab-container", children: [
18
- /* @__PURE__ */ jsx2(
19
- "div",
20
- {
21
- className: `editor-tab ${mode === "write" ? "editor-tab--active" : ""}`,
22
- onClick: () => setMode("write"),
23
- children: "Write"
24
- }
25
- ),
26
- /* @__PURE__ */ jsx2(
27
- "div",
28
- {
29
- className: `editor-tab ${mode === "preview" ? "editor-tab--active" : ""}`,
30
- onClick: () => setMode("preview"),
31
- children: "Preview"
32
- }
33
- )
34
- ] });
14
+ return /* @__PURE__ */ React.createElement("div", { className: "editor-tab-container" }, /* @__PURE__ */ React.createElement(
15
+ "div",
16
+ {
17
+ className: `editor-tab ${mode === "write" ? "editor-tab--active" : ""}`,
18
+ onClick: () => setMode("write")
19
+ },
20
+ "Write"
21
+ ), /* @__PURE__ */ React.createElement(
22
+ "div",
23
+ {
24
+ className: `editor-tab ${mode === "preview" ? "editor-tab--active" : ""}`,
25
+ onClick: () => setMode("preview")
26
+ },
27
+ "Preview"
28
+ ));
35
29
  }
36
30
 
37
31
  // src/components/EditorTextarea.tsx
38
32
  import { forwardRef } from "react";
39
- import { jsx as jsx3 } from "react/jsx-runtime";
33
+ import "./editor-AUU3A4EA.css";
40
34
  var EditorTextarea = forwardRef(({ value, placeholder, setValue, onImageUpload }, ref) => {
41
35
  const handleDrop = async (e) => {
42
36
  e.preventDefault();
@@ -51,7 +45,7 @@ var EditorTextarea = forwardRef(({ value, placeholder, setValue, onImageUpload }
51
45
  `);
52
46
  }
53
47
  };
54
- return /* @__PURE__ */ jsx3(
48
+ return /* @__PURE__ */ React.createElement(
55
49
  "textarea",
56
50
  {
57
51
  ref,
@@ -98,7 +92,7 @@ function useMarkdownEditor({ value, setValue }) {
98
92
  }
99
93
 
100
94
  // src/components/MarkdownEditor.tsx
101
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
95
+ import "./editor-AUU3A4EA.css";
102
96
  function MarkdownEditor({
103
97
  value,
104
98
  onChange: setValue,
@@ -109,25 +103,22 @@ function MarkdownEditor({
109
103
  setValue
110
104
  });
111
105
  const [mode, setMode] = useState("write");
112
- return /* @__PURE__ */ jsxs3("div", { className: "editor", children: [
113
- /* @__PURE__ */ jsx4(
114
- EditorHeader,
115
- {
116
- mode,
117
- setMode,
118
- insertMarkdown
119
- }
120
- ),
121
- mode === "write" ? /* @__PURE__ */ jsx4(
122
- EditorTextarea,
123
- {
124
- ref: textareaRef,
125
- value,
126
- setValue,
127
- onImageUpload
128
- }
129
- ) : /* @__PURE__ */ jsx4(Preview, { value })
130
- ] });
106
+ return /* @__PURE__ */ React.createElement("div", { className: "editor" }, /* @__PURE__ */ React.createElement(
107
+ EditorHeader,
108
+ {
109
+ mode,
110
+ setMode,
111
+ insertMarkdown
112
+ }
113
+ ), mode === "write" ? /* @__PURE__ */ React.createElement(
114
+ EditorTextarea,
115
+ {
116
+ ref: textareaRef,
117
+ value,
118
+ setValue,
119
+ onImageUpload
120
+ }
121
+ ) : /* @__PURE__ */ React.createElement(Preview, { value }));
131
122
  }
132
123
 
133
124
  // src/utils/markdown.ts
@@ -135,7 +126,7 @@ function parseBold(text) {
135
126
  return text.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
136
127
  }
137
128
  function parseItalic(text) {
138
- return text.replace(/\*(.+?)\*/g, "<em>$1</em>");
129
+ return text.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "<em>$1</em>");
139
130
  }
140
131
  function parseInlineCode(text) {
141
132
  return text.replace(/`(.+?)`/g, "<code>$1</code>");
@@ -143,6 +134,15 @@ function parseInlineCode(text) {
143
134
  function parseBlockquote(text) {
144
135
  return text.replace(/^> (.+)$/gm, "<blockquote>$1</blockquote>");
145
136
  }
137
+ function parseStrikethrough(text) {
138
+ return text.replace(/~~(.+?)~~/g, "<del>$1</del>");
139
+ }
140
+ function parseUnderline(text) {
141
+ return text.replace(/__(.+?)__/g, "<u>$1</u>");
142
+ }
143
+ function parseHr(text) {
144
+ return text.replace(/^---$/gm, "<hr />");
145
+ }
146
146
  function parseImages(text) {
147
147
  return text.replace(
148
148
  /!\[(.*?)\]\(([^)]*?)\)/g,
@@ -181,23 +181,26 @@ function parseLineBreaks(text) {
181
181
  }
182
182
  function markdownToHtml(markdown) {
183
183
  let html = markdown;
184
+ html = parseHr(html);
185
+ html = parseHeadings(html);
186
+ html = parseBlockquote(html);
187
+ html = parseUnorderedList(html);
188
+ html = parseOrderedList(html);
184
189
  html = parseBold(html);
190
+ html = parseUnderline(html);
191
+ html = parseStrikethrough(html);
185
192
  html = parseItalic(html);
186
193
  html = parseInlineCode(html);
187
- html = parseBlockquote(html);
188
194
  html = parseImages(html);
189
195
  html = parseLinks(html);
190
- html = parseHeadings(html);
191
- html = parseUnorderedList(html);
192
- html = parseOrderedList(html);
193
196
  html = parseLineBreaks(html);
194
197
  return html;
195
198
  }
196
199
 
197
200
  // src/components/Preview.tsx
198
- import { jsx as jsx5 } from "react/jsx-runtime";
201
+ import "./preview-FACEHC73.css";
199
202
  function Preview({ value }) {
200
- return /* @__PURE__ */ jsx5(
203
+ return /* @__PURE__ */ React.createElement(
201
204
  "div",
202
205
  {
203
206
  className: "preview",
@@ -218,13 +221,19 @@ import {
218
221
  Heading3Icon,
219
222
  ListOrderedIcon,
220
223
  ListIcon,
221
- QuoteIcon
224
+ QuoteIcon,
225
+ StrikethroughIcon,
226
+ UnderlineIcon,
227
+ ListEndIcon
222
228
  } from "lucide-react";
223
229
  var TOOLBAR_BUTTONS = [
224
230
  { key: "bold", before: "**", after: "**", Icon: BoldIcon },
225
231
  { key: "italic", before: "*", after: "*", Icon: ItalicIcon },
226
232
  { key: "code", before: "`", after: "`", Icon: CodeIcon },
227
233
  { key: "blockquote", before: "> ", after: "", Icon: QuoteIcon },
234
+ { key: "strikethrough", before: "~~", after: "~~", Icon: StrikethroughIcon },
235
+ { key: "underline", before: "__", after: "__", Icon: UnderlineIcon },
236
+ { key: "horizontal rule", before: "\n---\n", after: "", Icon: ListEndIcon },
228
237
  { key: "link", before: "[", after: "]()", Icon: LinkIcon }
229
238
  ];
230
239
  var headingOptions = [
@@ -238,25 +247,21 @@ var listOptions = [
238
247
  ];
239
248
 
240
249
  // src/components/Toolbar.tsx
241
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
250
+ import "./toolbar-YQKH6EMS.css";
242
251
  function Toolbar({ insertMarkdown }) {
243
- return /* @__PURE__ */ jsxs4("menu", { className: "toolbar-menu", children: [
244
- TOOLBAR_BUTTONS.map(({ key, before, after, Icon }) => /* @__PURE__ */ jsx6(
245
- "button",
246
- {
247
- className: "toolbar-button",
248
- onClick: () => insertMarkdown(before, after),
249
- children: /* @__PURE__ */ jsx6(Icon, { size: 18 })
250
- },
251
- key
252
- )),
253
- /* @__PURE__ */ jsx6(ToolbarDropdownHeading, { insertMarkdown }),
254
- /* @__PURE__ */ jsx6(ToolbarDropdownList, { insertMarkdown })
255
- ] });
252
+ return /* @__PURE__ */ React.createElement("menu", { className: "toolbar-menu" }, TOOLBAR_BUTTONS.map(({ key, before, after, Icon }) => /* @__PURE__ */ React.createElement(
253
+ "button",
254
+ {
255
+ key,
256
+ className: "toolbar-button",
257
+ onClick: () => insertMarkdown(before, after)
258
+ },
259
+ /* @__PURE__ */ React.createElement(Icon, { size: 18 })
260
+ )), /* @__PURE__ */ React.createElement(ToolbarDropdownHeading, { insertMarkdown }), /* @__PURE__ */ React.createElement(ToolbarDropdownList, { insertMarkdown }));
256
261
  }
257
262
 
258
263
  // src/components/IconDropdown.tsx
259
- import React from "react";
264
+ import React2 from "react";
260
265
 
261
266
  // src/utils/cx.ts
262
267
  function cx(...classes) {
@@ -264,7 +269,7 @@ function cx(...classes) {
264
269
  }
265
270
 
266
271
  // src/components/IconDropdown.tsx
267
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
272
+ import "./dropdown-JYZ5KVXG.css";
268
273
  function IconDropdown({
269
274
  className,
270
275
  disabled,
@@ -273,12 +278,12 @@ function IconDropdown({
273
278
  triggerIcon,
274
279
  onChange
275
280
  }) {
276
- const [isOpen, setIsOpen] = React.useState(false);
277
- const dropdownRef = React.useRef(null);
281
+ const [isOpen, setIsOpen] = React2.useState(false);
282
+ const dropdownRef = React2.useRef(null);
278
283
  const toggle = () => {
279
284
  if (!disabled) setIsOpen((prev) => !prev);
280
285
  };
281
- React.useEffect(() => {
286
+ React2.useEffect(() => {
282
287
  const handleClickOutside = (e) => {
283
288
  if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
284
289
  setIsOpen(false);
@@ -287,52 +292,46 @@ function IconDropdown({
287
292
  document.addEventListener("mousedown", handleClickOutside);
288
293
  return () => document.removeEventListener("mousedown", handleClickOutside);
289
294
  }, []);
290
- return /* @__PURE__ */ jsxs5("div", { ref: dropdownRef, className: cx("md-dropdown", className), children: [
291
- /* @__PURE__ */ jsx7(
292
- "button",
293
- {
294
- type: "button",
295
- onClick: toggle,
296
- disabled,
297
- className: cx(
298
- "md-dropdown__trigger",
299
- disabled && "md-dropdown__trigger--disabled"
300
- ),
301
- children: triggerIcon
295
+ return /* @__PURE__ */ React2.createElement("div", { ref: dropdownRef, className: cx("md-dropdown", className) }, /* @__PURE__ */ React2.createElement(
296
+ "button",
297
+ {
298
+ type: "button",
299
+ onClick: toggle,
300
+ disabled,
301
+ className: cx(
302
+ "md-dropdown__trigger",
303
+ disabled && "md-dropdown__trigger--disabled"
304
+ )
305
+ },
306
+ triggerIcon
307
+ ), isOpen && /* @__PURE__ */ React2.createElement("ul", { className: "md-dropdown__menu" }, options.map((option) => /* @__PURE__ */ React2.createElement(
308
+ "li",
309
+ {
310
+ key: option.value,
311
+ className: cx(
312
+ "md-dropdown__item",
313
+ selected && "md-dropdown__item--selected"
314
+ ),
315
+ onClick: () => {
316
+ onChange(option.value);
317
+ setIsOpen(false);
302
318
  }
303
- ),
304
- isOpen && /* @__PURE__ */ jsx7("ul", { className: "md-dropdown__menu", children: options.map((option) => /* @__PURE__ */ jsxs5(
305
- "li",
306
- {
307
- className: cx(
308
- "md-dropdown__item",
309
- selected && "md-dropdown__item--selected"
310
- ),
311
- onClick: () => {
312
- onChange(option.value);
313
- setIsOpen(false);
314
- },
315
- children: [
316
- option.Icon && /* @__PURE__ */ jsx7("span", { className: "md-dropdown__icon", children: /* @__PURE__ */ jsx7(option.Icon, {}) }),
317
- option.label && /* @__PURE__ */ jsx7("span", { className: "md-dropdown__label", children: option.label })
318
- ]
319
- },
320
- option.value
321
- )) })
322
- ] });
319
+ },
320
+ option.Icon && /* @__PURE__ */ React2.createElement("span", { className: "md-dropdown__icon" }, /* @__PURE__ */ React2.createElement(option.Icon, null)),
321
+ option.label && /* @__PURE__ */ React2.createElement("span", { className: "md-dropdown__label" }, option.label)
322
+ ))));
323
323
  }
324
324
 
325
325
  // src/components/ToolbarDropdown.tsx
326
326
  import { Heading1Icon as Heading1Icon2, ListIcon as ListIcon2 } from "lucide-react";
327
- import { jsx as jsx8 } from "react/jsx-runtime";
328
327
  function ToolbarDropdownHeading({
329
328
  insertMarkdown
330
329
  }) {
331
- return /* @__PURE__ */ jsx8(
330
+ return /* @__PURE__ */ React.createElement(
332
331
  IconDropdown,
333
332
  {
334
333
  options: headingOptions,
335
- triggerIcon: /* @__PURE__ */ jsx8(Heading1Icon2, {}),
334
+ triggerIcon: /* @__PURE__ */ React.createElement(Heading1Icon2, null),
336
335
  onChange: (value) => {
337
336
  const option = headingOptions.find((o) => o.value === value);
338
337
  if (option) insertMarkdown(option.before);
@@ -341,11 +340,11 @@ function ToolbarDropdownHeading({
341
340
  );
342
341
  }
343
342
  function ToolbarDropdownList({ insertMarkdown }) {
344
- return /* @__PURE__ */ jsx8(
343
+ return /* @__PURE__ */ React.createElement(
345
344
  IconDropdown,
346
345
  {
347
346
  options: listOptions,
348
- triggerIcon: /* @__PURE__ */ jsx8(ListIcon2, {}),
347
+ triggerIcon: /* @__PURE__ */ React.createElement(ListIcon2, null),
349
348
  onChange: (value) => {
350
349
  const option = listOptions.find((o) => o.value === value);
351
350
  if (option) insertMarkdown(option.before);
@@ -0,0 +1,11 @@
1
+ .preview {
2
+ color: #111827;
3
+ width: 100%;
4
+ min-height: 200px;
5
+ padding: 16px;
6
+ border: none;
7
+ resize: none;
8
+ outline: none;
9
+ box-sizing: border-box;
10
+ list-style: decimal inside;
11
+ }
@@ -0,0 +1,25 @@
1
+ .toolbar-menu {
2
+ display: flex;
3
+ align-items: center;
4
+ margin: 0;
5
+ padding: 0;
6
+ gap: 16px;
7
+ box-sizing: border-box;
8
+ }
9
+
10
+ .toolbar-button {
11
+ background: none;
12
+ width: 28px;
13
+ height: 28px;
14
+ border: none;
15
+ cursor: pointer;
16
+ transition: background-color 0.2s;
17
+
18
+ &:hover {
19
+ background-color: #f3f4f6;
20
+ }
21
+
22
+ &:active {
23
+ background-color: #e5e7eb;
24
+ }
25
+ }
@@ -0,0 +1 @@
1
+ export declare function cx(...classes: (string | false | undefined)[]): string;
@@ -0,0 +1,2 @@
1
+ export * from "./cx";
2
+ export * from "./markdown";
@@ -0,0 +1 @@
1
+ export declare function markdownToHtml(markdown: string): string;
package/package.json CHANGED
@@ -10,17 +10,17 @@
10
10
  "lightweight",
11
11
  "textarea"
12
12
  ],
13
- "version": "0.1.4",
13
+ "version": "0.1.6",
14
14
  "exports": {
15
15
  ".": {
16
+ "types": "./dist/index.d.ts",
16
17
  "import": "./dist/index.mjs",
17
- "require": "./dist/index.js",
18
- "types": "./dist/index.d.ts"
18
+ "require": "./dist/index.js"
19
19
  },
20
20
  "./style.css": "./dist/style.css"
21
21
  },
22
22
  "scripts": {
23
- "build": "tsup src/index.ts --format esm,cjs --dts --clean --tsconfig tsconfig.build.json"
23
+ "build": "tsup && tsc -p tsconfig.build.json"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "react": ">=18"
@@ -40,5 +40,6 @@
40
40
  ],
41
41
  "sideEffects": [
42
42
  "*.css"
43
- ]
43
+ ],
44
+ "style": "dist/style.css"
44
45
  }
package/dist/index.css DELETED
@@ -1,181 +0,0 @@
1
- /* src/css/editor.css */
2
- .editor {
3
- display: flex;
4
- flex-direction: column;
5
- width: 100%;
6
- border: 1px solid #e5e7eb;
7
- border-radius: 8px;
8
- box-sizing: border-box;
9
- overflow: hidden;
10
- }
11
- .editor-header {
12
- display: flex;
13
- flex-direction: column;
14
- justify-content: space-evenly;
15
- height: 88px;
16
- padding: 0 16px;
17
- background-color: #f9fafb;
18
- border-bottom: 1px solid #e5e7eb;
19
- border-top-left-radius: 8px;
20
- border-top-right-radius: 8px;
21
- }
22
- @media (min-width: 768px) {
23
- .editor-header {
24
- flex-direction: row;
25
- align-items: center;
26
- justify-content: space-between;
27
- height: 48px;
28
- }
29
- }
30
- .editor-tab-container {
31
- display: flex;
32
- gap: 1rem;
33
- font-weight: 500;
34
- }
35
- .editor-tab {
36
- cursor: pointer;
37
- padding: 0.25rem 0.5rem;
38
- font-size: small;
39
- font-weight: 500;
40
- transition: color 0.2s;
41
- color: #4b5563;
42
- &:hover {
43
- color: #1f2937;
44
- }
45
- }
46
- .editor-tab--active {
47
- color: #111827;
48
- border-bottom: 2px solid #111827;
49
- }
50
- .editor-textarea {
51
- width: 100%;
52
- min-height: 200px;
53
- margin: 0;
54
- padding: 16px;
55
- border: none;
56
- resize: none;
57
- outline: none;
58
- box-sizing: border-box;
59
- }
60
-
61
- /* src/css/preview.css */
62
- .preview {
63
- color: #111827;
64
- width: 100%;
65
- min-height: 200px;
66
- padding: 16px;
67
- border: none;
68
- resize: none;
69
- outline: none;
70
- box-sizing: border-box;
71
- list-style: decimal inside;
72
- }
73
-
74
- /* src/css/toolbar.css */
75
- .toolbar-menu {
76
- display: flex;
77
- align-items: center;
78
- margin: 0;
79
- padding: 0;
80
- gap: 16px;
81
- box-sizing: border-box;
82
- }
83
- .toolbar-button {
84
- background: none;
85
- width: 28px;
86
- height: 28px;
87
- border: none;
88
- cursor: pointer;
89
- transition: background-color 0.2s;
90
- &:hover {
91
- background-color: #f3f4f6;
92
- }
93
- &:active {
94
- background-color: #e5e7eb;
95
- }
96
- }
97
-
98
- /* src/css/dropdown.css */
99
- .md-dropdown {
100
- position: relative;
101
- display: inline-flex;
102
- align-items: center;
103
- }
104
- .md-dropdown__trigger {
105
- display: flex;
106
- align-items: center;
107
- justify-content: center;
108
- width: 28px;
109
- height: 28px;
110
- background: transparent;
111
- border: none;
112
- cursor: pointer;
113
- transition: background-color 0.15s ease;
114
- }
115
- .md-dropdown__trigger:hover {
116
- background-color: #f3f4f6;
117
- }
118
- .md-dropdown__trigger--disabled {
119
- cursor: not-allowed;
120
- opacity: 0.5;
121
- }
122
- .md-dropdown__menu {
123
- position: absolute;
124
- top: 0;
125
- left: -35%;
126
- z-index: 50;
127
- margin-top: 4px;
128
- min-width: 40px;
129
- max-height: 240px;
130
- overflow-y: auto;
131
- background: #ffffff;
132
- border: 1px solid #e5e7eb;
133
- border-radius: 8px;
134
- padding: 4px 0;
135
- box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
136
- }
137
- .md-dropdown__item {
138
- display: flex;
139
- align-items: center;
140
- gap: 8px;
141
- padding: 10px 12px;
142
- font-size: 14px;
143
- cursor: pointer;
144
- user-select: none;
145
- transition: background-color 0.15s ease;
146
- }
147
- .md-dropdown__item:hover {
148
- background-color: #f3f4f6;
149
- }
150
- .md-dropdown__item--selected {
151
- background-color: #fefce8;
152
- color: #a16207;
153
- font-weight: 500;
154
- }
155
- .md-dropdown__icon {
156
- display: flex;
157
- color: #9ca3af;
158
- }
159
- .md-dropdown__label {
160
- white-space: nowrap;
161
- }
162
- .dropdown-item {
163
- color: #374151;
164
- background-color: #f3f4f6;
165
- position: relative;
166
- display: flex;
167
- cursor: pointer;
168
- align-items: center;
169
- gap: 0.5rem;
170
- padding-left: 0.75rem;
171
- padding-right: 0.75rem;
172
- padding-top: 0.625rem;
173
- padding-bottom: 0.625rem;
174
- font-size: 0.875rem;
175
- transition: all ease-in-out;
176
- }
177
- .dropdown-item--selected {
178
- background-color: #fefce8;
179
- color: #a16207;
180
- font-weight: 500;
181
- }