@duskmoon-dev/el-markdown-input 1.1.1 → 1.1.3
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/cjs/index.js +168 -12
- package/dist/cjs/index.js.map +4 -4
- package/dist/cjs/register.js +168 -12
- package/dist/cjs/register.js.map +4 -4
- package/dist/esm/index.js +168 -12
- package/dist/esm/index.js.map +4 -4
- package/dist/esm/register.js +168 -12
- package/dist/esm/register.js.map +4 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/css.d.ts.map +1 -1
- package/dist/types/element.d.ts +11 -0
- package/dist/types/element.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/esm/register.js
CHANGED
|
@@ -254,6 +254,10 @@ var elementStyles = css`
|
|
|
254
254
|
padding: 0 0.5rem;
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
+
.toolbar[hidden] {
|
|
258
|
+
display: none;
|
|
259
|
+
}
|
|
260
|
+
|
|
257
261
|
.tab-btn {
|
|
258
262
|
padding: 0.5rem 0.875rem;
|
|
259
263
|
border: none;
|
|
@@ -492,6 +496,31 @@ var elementStyles = css`
|
|
|
492
496
|
gap: 0.5rem;
|
|
493
497
|
}
|
|
494
498
|
|
|
499
|
+
.status-bar-start,
|
|
500
|
+
.status-bar-end {
|
|
501
|
+
display: flex;
|
|
502
|
+
align-items: center;
|
|
503
|
+
gap: 0.5rem;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/* Allow slotted light-DOM children to inherit font and alignment */
|
|
507
|
+
.status-bar ::slotted(*),
|
|
508
|
+
.status-bar-start ::slotted(*),
|
|
509
|
+
.status-bar-end ::slotted(*) {
|
|
510
|
+
font-size: inherit;
|
|
511
|
+
font-family: inherit;
|
|
512
|
+
vertical-align: middle;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/* When slot="bottom" is used, the slotted element fills the bar */
|
|
516
|
+
.status-bar > slot[name="bottom"]::slotted(*) {
|
|
517
|
+
display: flex;
|
|
518
|
+
align-items: center;
|
|
519
|
+
justify-content: space-between;
|
|
520
|
+
flex: 1;
|
|
521
|
+
gap: 0.5rem;
|
|
522
|
+
}
|
|
523
|
+
|
|
495
524
|
.attach-btn {
|
|
496
525
|
display: inline-flex;
|
|
497
526
|
align-items: center;
|
|
@@ -526,7 +555,6 @@ var elementStyles = css`
|
|
|
526
555
|
}
|
|
527
556
|
|
|
528
557
|
.status-bar-count {
|
|
529
|
-
margin-left: auto;
|
|
530
558
|
white-space: nowrap;
|
|
531
559
|
}
|
|
532
560
|
|
|
@@ -655,6 +683,52 @@ var elementStyles = css`
|
|
|
655
683
|
white-space: nowrap;
|
|
656
684
|
}
|
|
657
685
|
|
|
686
|
+
/* ── Attached files (local form mode) ────────────────────────────── */
|
|
687
|
+
|
|
688
|
+
.upload-attached-row {
|
|
689
|
+
display: flex;
|
|
690
|
+
align-items: center;
|
|
691
|
+
gap: 0.5rem;
|
|
692
|
+
padding: 0.375rem 0.75rem;
|
|
693
|
+
border-top: 1px solid var(--md-border);
|
|
694
|
+
font-size: 0.75rem;
|
|
695
|
+
color: var(--md-text-muted);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.upload-attached-size {
|
|
699
|
+
white-space: nowrap;
|
|
700
|
+
color: var(--md-text-muted);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.upload-remove-btn {
|
|
704
|
+
display: inline-flex;
|
|
705
|
+
align-items: center;
|
|
706
|
+
justify-content: center;
|
|
707
|
+
width: 1.25rem;
|
|
708
|
+
height: 1.25rem;
|
|
709
|
+
margin-left: auto;
|
|
710
|
+
border: none;
|
|
711
|
+
background: transparent;
|
|
712
|
+
color: var(--md-text-muted);
|
|
713
|
+
font-size: 0.85rem;
|
|
714
|
+
line-height: 1;
|
|
715
|
+
cursor: pointer;
|
|
716
|
+
border-radius: 50%;
|
|
717
|
+
transition:
|
|
718
|
+
color 150ms ease,
|
|
719
|
+
background 150ms ease;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.upload-remove-btn:hover {
|
|
723
|
+
color: var(--md-color-error);
|
|
724
|
+
background: var(--md-bg-hover);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
.upload-remove-btn:focus-visible {
|
|
728
|
+
outline: 2px solid var(--md-accent);
|
|
729
|
+
outline-offset: 1px;
|
|
730
|
+
}
|
|
731
|
+
|
|
658
732
|
/* ── Resizable editor ──────────────────────────────────────────────── */
|
|
659
733
|
/* resize attribute mirrors the CSS resize property: vertical | horizontal | both */
|
|
660
734
|
:host([resize='vertical']) .editor {
|
|
@@ -999,6 +1073,13 @@ var coreMarkdownStyles = markdownBodyCSS.replace(/@layer\s+components\s*\{/, "")
|
|
|
999
1073
|
var markdownBodySheet = css2`
|
|
1000
1074
|
${coreMarkdownStyles}
|
|
1001
1075
|
`;
|
|
1076
|
+
function formatFileSize(bytes) {
|
|
1077
|
+
if (bytes < 1024)
|
|
1078
|
+
return `${bytes} B`;
|
|
1079
|
+
if (bytes < 1024 * 1024)
|
|
1080
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
1081
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
1082
|
+
}
|
|
1002
1083
|
|
|
1003
1084
|
class ElDmMarkdownInput extends BaseElement {
|
|
1004
1085
|
static formAssociated = true;
|
|
@@ -1016,7 +1097,8 @@ class ElDmMarkdownInput extends BaseElement {
|
|
|
1016
1097
|
debounce: { type: Number, reflect: true, default: 300 },
|
|
1017
1098
|
katexCssUrl: { type: String, reflect: true, attribute: "katex-css-url" },
|
|
1018
1099
|
mermaidSrc: { type: String, reflect: true, attribute: "mermaid-src" },
|
|
1019
|
-
resize: { type: String, reflect: true, default: "none" }
|
|
1100
|
+
resize: { type: String, reflect: true, default: "none" },
|
|
1101
|
+
noPreview: { type: Boolean, reflect: true, attribute: "no-preview" }
|
|
1020
1102
|
};
|
|
1021
1103
|
#internals;
|
|
1022
1104
|
#initialized = false;
|
|
@@ -1044,6 +1126,7 @@ class ElDmMarkdownInput extends BaseElement {
|
|
|
1044
1126
|
#lastRenderedSource = null;
|
|
1045
1127
|
#katexCssInjected = false;
|
|
1046
1128
|
#uploadIdCounter = 0;
|
|
1129
|
+
#attachedFiles = [];
|
|
1047
1130
|
constructor() {
|
|
1048
1131
|
super();
|
|
1049
1132
|
this.#internals = this.attachInternals();
|
|
@@ -1107,15 +1190,28 @@ class ElDmMarkdownInput extends BaseElement {
|
|
|
1107
1190
|
this.#renderPreview(ta.value);
|
|
1108
1191
|
}
|
|
1109
1192
|
}
|
|
1193
|
+
const noPreview = !!this.noPreview;
|
|
1194
|
+
const toolbar = this.shadowRoot.querySelector(".toolbar");
|
|
1195
|
+
if (noPreview) {
|
|
1196
|
+
toolbar?.setAttribute("hidden", "");
|
|
1197
|
+
if (this.#activeTab === "preview") {
|
|
1198
|
+
this.#activeTab = "write";
|
|
1199
|
+
this.#writeArea?.removeAttribute("hidden");
|
|
1200
|
+
this.#previewBody?.setAttribute("hidden", "");
|
|
1201
|
+
}
|
|
1202
|
+
} else {
|
|
1203
|
+
toolbar?.removeAttribute("hidden");
|
|
1204
|
+
}
|
|
1110
1205
|
this.#updateStatusBarNow();
|
|
1111
1206
|
}
|
|
1112
1207
|
render() {
|
|
1113
1208
|
const ph = this.placeholder ?? "Write markdown…";
|
|
1114
1209
|
const disabled = !!this.disabled;
|
|
1115
1210
|
const readonly = !!this.readonly;
|
|
1211
|
+
const noPreview = !!this.noPreview;
|
|
1116
1212
|
return `
|
|
1117
1213
|
<div class="editor">
|
|
1118
|
-
<div class="toolbar" role="tablist" aria-label="Editor mode">
|
|
1214
|
+
<div class="toolbar" role="tablist" aria-label="Editor mode" ${noPreview ? "hidden" : ""}>
|
|
1119
1215
|
<button
|
|
1120
1216
|
class="tab-btn"
|
|
1121
1217
|
id="tab-write"
|
|
@@ -1163,10 +1259,20 @@ class ElDmMarkdownInput extends BaseElement {
|
|
|
1163
1259
|
></div>
|
|
1164
1260
|
|
|
1165
1261
|
<div class="status-bar">
|
|
1166
|
-
<
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1262
|
+
<slot name="bottom">
|
|
1263
|
+
<div class="status-bar-start">
|
|
1264
|
+
<slot name="bottom-start">
|
|
1265
|
+
<button class="attach-btn" type="button" aria-label="Attach files" ${disabled || readonly ? "disabled" : ""}>
|
|
1266
|
+
📎 Attach files
|
|
1267
|
+
</button>
|
|
1268
|
+
</slot>
|
|
1269
|
+
</div>
|
|
1270
|
+
<div class="status-bar-end">
|
|
1271
|
+
<slot name="bottom-end">
|
|
1272
|
+
<span class="status-bar-count" aria-live="polite"></span>
|
|
1273
|
+
</slot>
|
|
1274
|
+
</div>
|
|
1275
|
+
</slot>
|
|
1170
1276
|
<input
|
|
1171
1277
|
type="file"
|
|
1172
1278
|
class="file-input"
|
|
@@ -1217,7 +1323,7 @@ class ElDmMarkdownInput extends BaseElement {
|
|
|
1217
1323
|
if (e.defaultPrevented)
|
|
1218
1324
|
return;
|
|
1219
1325
|
}
|
|
1220
|
-
if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === "P") {
|
|
1326
|
+
if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === "P" && !this.noPreview) {
|
|
1221
1327
|
e.preventDefault();
|
|
1222
1328
|
this.#switchTab(this.#activeTab === "write" ? "preview" : "write");
|
|
1223
1329
|
return;
|
|
@@ -1342,6 +1448,8 @@ class ElDmMarkdownInput extends BaseElement {
|
|
|
1342
1448
|
#switchTab(tab) {
|
|
1343
1449
|
if (tab === this.#activeTab)
|
|
1344
1450
|
return;
|
|
1451
|
+
if (tab === "preview" && this.noPreview)
|
|
1452
|
+
return;
|
|
1345
1453
|
this.#activeTab = tab;
|
|
1346
1454
|
const writeBtns = this.shadowRoot.querySelectorAll(".tab-btn");
|
|
1347
1455
|
writeBtns.forEach((btn) => {
|
|
@@ -1451,15 +1559,28 @@ class ElDmMarkdownInput extends BaseElement {
|
|
|
1451
1559
|
}, ms);
|
|
1452
1560
|
}
|
|
1453
1561
|
#syncFormValue() {
|
|
1454
|
-
this.#
|
|
1562
|
+
const text = this.#textarea?.value ?? "";
|
|
1563
|
+
if (this.#attachedFiles.length === 0) {
|
|
1564
|
+
this.#internals?.setFormValue(text);
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
const name = this.name || "markdown";
|
|
1568
|
+
const fd = new FormData;
|
|
1569
|
+
fd.append(name, text);
|
|
1570
|
+
for (const f of this.#attachedFiles) {
|
|
1571
|
+
fd.append(`${name}_files`, f, f.name);
|
|
1572
|
+
}
|
|
1573
|
+
this.#internals?.setFormValue(fd);
|
|
1455
1574
|
}
|
|
1456
1575
|
#startUpload(file) {
|
|
1457
1576
|
this.emit("upload-start", { file });
|
|
1458
1577
|
const id = `upload-${++this.#uploadIdCounter}`;
|
|
1459
1578
|
const uploadUrl = this.uploadUrl;
|
|
1460
1579
|
if (!uploadUrl) {
|
|
1461
|
-
this.
|
|
1462
|
-
this.#
|
|
1580
|
+
this.#attachedFiles.push(file);
|
|
1581
|
+
this.#addAttachedRow(file, this.#attachedFiles.length - 1, id);
|
|
1582
|
+
this.#syncFormValue();
|
|
1583
|
+
this.emit("upload-done", { file, url: "", markdown: "" });
|
|
1463
1584
|
return;
|
|
1464
1585
|
}
|
|
1465
1586
|
this.#addProgressRow(id, file.name);
|
|
@@ -1514,6 +1635,22 @@ class ElDmMarkdownInput extends BaseElement {
|
|
|
1514
1635
|
this.#uploadList.appendChild(row);
|
|
1515
1636
|
setTimeout(() => row.remove(), 4000);
|
|
1516
1637
|
}
|
|
1638
|
+
#addAttachedRow(file, index, id) {
|
|
1639
|
+
if (!this.#uploadList)
|
|
1640
|
+
return;
|
|
1641
|
+
const row = document.createElement("div");
|
|
1642
|
+
row.className = "upload-attached-row";
|
|
1643
|
+
row.id = id;
|
|
1644
|
+
row.innerHTML = `
|
|
1645
|
+
<span class="upload-filename">${escapeHtmlStr(file.name)}</span>
|
|
1646
|
+
<span class="upload-attached-size">${formatFileSize(file.size)}</span>
|
|
1647
|
+
<button type="button" class="upload-remove-btn" data-attach-index="${index}" aria-label="Remove ${escapeHtmlStr(file.name)}">×</button>
|
|
1648
|
+
`;
|
|
1649
|
+
row.querySelector(".upload-remove-btn").addEventListener("click", () => {
|
|
1650
|
+
this.removeFile(index);
|
|
1651
|
+
});
|
|
1652
|
+
this.#uploadList.appendChild(row);
|
|
1653
|
+
}
|
|
1517
1654
|
#handleAutocompleteInput() {
|
|
1518
1655
|
const ta = this.#textarea;
|
|
1519
1656
|
if (!ta)
|
|
@@ -1719,6 +1856,25 @@ class ElDmMarkdownInput extends BaseElement {
|
|
|
1719
1856
|
this.#acSelectedIndex = list.length > 0 ? 0 : -1;
|
|
1720
1857
|
this.#updateDropdown();
|
|
1721
1858
|
}
|
|
1859
|
+
getFiles() {
|
|
1860
|
+
return [...this.#attachedFiles];
|
|
1861
|
+
}
|
|
1862
|
+
removeFile(index) {
|
|
1863
|
+
if (index < 0 || index >= this.#attachedFiles.length)
|
|
1864
|
+
return;
|
|
1865
|
+
this.#attachedFiles.splice(index, 1);
|
|
1866
|
+
this.#rebuildAttachedRows();
|
|
1867
|
+
this.#syncFormValue();
|
|
1868
|
+
}
|
|
1869
|
+
#rebuildAttachedRows() {
|
|
1870
|
+
if (!this.#uploadList)
|
|
1871
|
+
return;
|
|
1872
|
+
this.#uploadList.querySelectorAll(".upload-attached-row").forEach((r) => r.remove());
|
|
1873
|
+
this.#attachedFiles.forEach((file, i) => {
|
|
1874
|
+
const id = `upload-${++this.#uploadIdCounter}`;
|
|
1875
|
+
this.#addAttachedRow(file, i, id);
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1722
1878
|
}
|
|
1723
1879
|
function escapeHtmlStr(s) {
|
|
1724
1880
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -1729,5 +1885,5 @@ if (!customElements.get("el-dm-markdown-input")) {
|
|
|
1729
1885
|
customElements.define("el-dm-markdown-input", ElDmMarkdownInput);
|
|
1730
1886
|
}
|
|
1731
1887
|
|
|
1732
|
-
//# debugId=
|
|
1888
|
+
//# debugId=D5D4120E3A9113D764756E2164756E21
|
|
1733
1889
|
//# sourceMappingURL=register.js.map
|