@kubex/zinc 1.1.63 → 1.1.64
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/custom-elements.json +928 -3
- package/dist/vscode.html-custom-data.json +47 -0
- package/dist/web-types.json +109 -1
- package/dist/zn.d.ts +152 -0
- package/dist/zn.min.js +523 -418
- package/docs/pages/components/remarkd-editor.md +103 -0
- package/package.json +3 -2
- package/src/components/file/file.component.ts +16 -1
- package/src/components/query-builder/query-builder.component.ts +14 -6
- package/src/components/remarkd-editor/index.ts +12 -0
- package/src/components/remarkd-editor/remarkd-editor.component.ts +752 -0
- package/src/components/remarkd-editor/remarkd-editor.scss +241 -0
- package/src/components/remarkd-editor/remarkd-editor.test.ts +147 -0
- package/src/components/tabs/tabs.component.ts +9 -4
- package/src/components/tabs/tabs.test.ts +42 -1
- package/src/zinc.ts +1 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
meta:
|
|
3
|
+
title: Remarkd Editor
|
|
4
|
+
description: A Notion-style block editor for remarkd content — blocks render inline and are edited in place.
|
|
5
|
+
layout: component
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
`zn-remarkd-editor` is a Notion-style editor for
|
|
9
|
+
[remarkd](https://github.com/packaged/remarkd) content. The document is a list
|
|
10
|
+
of blocks rendered inline with remarkd — there is no separate preview. Click a
|
|
11
|
+
block to edit its raw remarkd source in place; it re-renders when you click
|
|
12
|
+
away (or press Escape / Ctrl+Enter). The `value` is always plain remarkd
|
|
13
|
+
source, submitted with the surrounding form.
|
|
14
|
+
|
|
15
|
+
```html:preview
|
|
16
|
+
<zn-remarkd-editor
|
|
17
|
+
name="content"
|
|
18
|
+
value="# Product Guide
|
|
19
|
+
|
|
20
|
+
This is a paragraph with **strong text**, __emphasis__, and a [link](https://example.com).
|
|
21
|
+
|
|
22
|
+
- [ ] Draft the guide
|
|
23
|
+
- [x] Review the output
|
|
24
|
+
|
|
25
|
+
NOTE: Click any block to edit its source."
|
|
26
|
+
></zn-remarkd-editor>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
30
|
+
|
|
31
|
+
### Adding and Moving Blocks
|
|
32
|
+
|
|
33
|
+
Hover a block to reveal its gutter actions: add a block below it, or grab the
|
|
34
|
+
handle to drag the block somewhere else in the document. Clicking the empty
|
|
35
|
+
area at the end of the document starts a new block. A block committed empty
|
|
36
|
+
is removed.
|
|
37
|
+
|
|
38
|
+
```html:preview
|
|
39
|
+
<zn-remarkd-editor
|
|
40
|
+
name="content"
|
|
41
|
+
value="Hover me to see the block actions."
|
|
42
|
+
></zn-remarkd-editor>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Images
|
|
46
|
+
|
|
47
|
+
Adding an image opens a dialog. With `attachment-url` set it contains a
|
|
48
|
+
`zn-file` drop area; the file's metadata is POSTed to the endpoint, which must
|
|
49
|
+
respond with `{uploadPath, uploadUrl}`; the file is then PUT to `uploadUrl`
|
|
50
|
+
and `uploadPath` is inserted as an image block. Without `attachment-url` the
|
|
51
|
+
dialog asks for an image URL instead. Dropping an image file straight onto the
|
|
52
|
+
editor uploads it directly.
|
|
53
|
+
|
|
54
|
+
```html
|
|
55
|
+
<zn-remarkd-editor name="content" attachment-url="/upload"></zn-remarkd-editor>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Remarkd Blocks
|
|
59
|
+
|
|
60
|
+
Remarkd's block syntax — hints, containers, code fences — renders with the
|
|
61
|
+
official remarkd styles. Fenced content stays a single block, blank lines and
|
|
62
|
+
all.
|
|
63
|
+
|
|
64
|
+
````html:preview
|
|
65
|
+
<zn-remarkd-editor name="content" value="TIP: Hint blocks are remarkd-specific.
|
|
66
|
+
|
|
67
|
+
====
|
|
68
|
+
An example **container** block.
|
|
69
|
+
====
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
a code fence
|
|
73
|
+
|
|
74
|
+
with a blank line inside
|
|
75
|
+
```"
|
|
76
|
+
></zn-remarkd-editor>
|
|
77
|
+
````
|
|
78
|
+
|
|
79
|
+
### Form Integration
|
|
80
|
+
|
|
81
|
+
`zn-remarkd-editor` is a [form control](/getting-started/form-controls); its
|
|
82
|
+
remarkd source is submitted under `name`, and `required` is supported.
|
|
83
|
+
|
|
84
|
+
```html:preview
|
|
85
|
+
<form class="remarkd-editor-form">
|
|
86
|
+
<zn-remarkd-editor name="content" required value="Edit me, then submit."></zn-remarkd-editor>
|
|
87
|
+
<br />
|
|
88
|
+
<zn-button type="submit" color="success">Submit</zn-button>
|
|
89
|
+
</form>
|
|
90
|
+
|
|
91
|
+
<script type="module">
|
|
92
|
+
const form = document.querySelector('.remarkd-editor-form');
|
|
93
|
+
|
|
94
|
+
await customElements.whenDefined('zn-button');
|
|
95
|
+
await customElements.whenDefined('zn-remarkd-editor');
|
|
96
|
+
|
|
97
|
+
form.addEventListener('submit', (e) => {
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
const data = Object.fromEntries(new FormData(form));
|
|
100
|
+
alert('Submitted!\n\n' + JSON.stringify(data, null, 2));
|
|
101
|
+
});
|
|
102
|
+
</script>
|
|
103
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubex/zinc",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.64",
|
|
4
4
|
"description": "A collection of web components for building web applications based off of @shoelace-style/Shoelace",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"web components",
|
|
@@ -55,7 +55,8 @@
|
|
|
55
55
|
"lit": "^3.3.3",
|
|
56
56
|
"lucide": "^1.17.0",
|
|
57
57
|
"marked": "^18.0.2",
|
|
58
|
-
"quill": "^2.0.3"
|
|
58
|
+
"quill": "^2.0.3",
|
|
59
|
+
"remarkd-js": "github:packaged/remarkd#fc482a4260740e0d61ab1cd50b056545fe195d94"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
62
|
"@custom-elements-manifest/analyzer": "^0.10.3",
|
|
@@ -76,9 +76,17 @@ export default class ZnFile extends ZincElement implements ZincFormControl {
|
|
|
76
76
|
|
|
77
77
|
private readonly formControlController = new FormControlController(this, {
|
|
78
78
|
assumeInteractionOn: ['zn-change'],
|
|
79
|
-
value
|
|
79
|
+
// An explicitly cleared control submits an empty value so the server can
|
|
80
|
+
// remove the stored upload; an untouched empty control submits nothing.
|
|
81
|
+
value: (el: ZnFile) => {
|
|
82
|
+
if (el.files?.length) return el.files;
|
|
83
|
+
return el.clearedByUser ? '' : undefined;
|
|
84
|
+
}
|
|
80
85
|
})
|
|
81
86
|
|
|
87
|
+
/** Set when the user clears the control; reset when a file is chosen. */
|
|
88
|
+
private clearedByUser = false;
|
|
89
|
+
|
|
82
90
|
private readonly hasSlotController = new HasSlotController(this, 'help-text', 'label');
|
|
83
91
|
|
|
84
92
|
private readonly localize = new LocalizeController(this);
|
|
@@ -110,6 +118,9 @@ export default class ZnFile extends ZincElement implements ZincFormControl {
|
|
|
110
118
|
set files(v: FileList | null) {
|
|
111
119
|
if (this.input) {
|
|
112
120
|
this.input.files = v;
|
|
121
|
+
if (v?.length) {
|
|
122
|
+
this.clearedByUser = false;
|
|
123
|
+
}
|
|
113
124
|
this.updatePreview();
|
|
114
125
|
}
|
|
115
126
|
}
|
|
@@ -481,6 +492,9 @@ export default class ZnFile extends ZincElement implements ZincFormControl {
|
|
|
481
492
|
const dataTransfer = new DataTransfer();
|
|
482
493
|
files.forEach(f => dataTransfer.items.add(f));
|
|
483
494
|
this.files = dataTransfer.files;
|
|
495
|
+
if (!dataTransfer.files.length) {
|
|
496
|
+
this.clearedByUser = true;
|
|
497
|
+
}
|
|
484
498
|
this.input.dispatchEvent(new Event('change'));
|
|
485
499
|
}
|
|
486
500
|
|
|
@@ -501,6 +515,7 @@ export default class ZnFile extends ZincElement implements ZincFormControl {
|
|
|
501
515
|
if (!hadLocalFile) {
|
|
502
516
|
this.src = '';
|
|
503
517
|
}
|
|
518
|
+
this.clearedByUser = true;
|
|
504
519
|
this.clearConfirmDialog?.hide();
|
|
505
520
|
this.input.dispatchEvent(new Event('change'));
|
|
506
521
|
this.emit('zn-clear');
|
|
@@ -167,6 +167,10 @@ export default class ZnQueryBuilder extends ZincElement implements ZincFormContr
|
|
|
167
167
|
}) showValues: string[] = [];
|
|
168
168
|
|
|
169
169
|
|
|
170
|
+
private get _usedFilterIds(): Set<string> {
|
|
171
|
+
return new Set([...this._selectedRules.values()].map(rule => rule.id));
|
|
172
|
+
}
|
|
173
|
+
|
|
170
174
|
get validationMessage(): string {
|
|
171
175
|
return '';
|
|
172
176
|
}
|
|
@@ -196,7 +200,7 @@ export default class ZnQueryBuilder extends ZincElement implements ZincFormContr
|
|
|
196
200
|
size="medium"
|
|
197
201
|
placeholder="Select Filter"
|
|
198
202
|
@zn-change="${this._addRule}">
|
|
199
|
-
${this.filters && this.filters.map(item => html`
|
|
203
|
+
${this.filters && this.filters.filter(item => !this._usedFilterIds.has(item.id)).map(item => html`
|
|
200
204
|
<zn-option value="${item.id}">
|
|
201
205
|
${item.name.charAt(0).toUpperCase() + item.name.slice(1)}
|
|
202
206
|
</zn-option>`)}
|
|
@@ -227,6 +231,7 @@ export default class ZnQueryBuilder extends ZincElement implements ZincFormContr
|
|
|
227
231
|
|
|
228
232
|
const filter: QueryBuilderItem | undefined = this.filters.find(item => item.id === id);
|
|
229
233
|
if (filter === undefined) return;
|
|
234
|
+
if (this._usedFilterIds.has(filter.id)) return;
|
|
230
235
|
|
|
231
236
|
const uniqueId = Math.random().toString(36).substring(7);
|
|
232
237
|
|
|
@@ -237,11 +242,12 @@ export default class ZnQueryBuilder extends ZincElement implements ZincFormContr
|
|
|
237
242
|
value: ''
|
|
238
243
|
});
|
|
239
244
|
|
|
245
|
+
const availableFilters = this.filters.filter(item => item.id === filter.id || !this._usedFilterIds.has(item.id));
|
|
240
246
|
const select = html`
|
|
241
247
|
<zn-select class="query-builder__key"
|
|
242
248
|
@zn-change="${(e: ZnChangeEvent) => this._changeRule(uniqueId, e)}"
|
|
243
249
|
value="${filter?.id}">
|
|
244
|
-
${
|
|
250
|
+
${availableFilters.map((item: QueryBuilderItem) => {
|
|
245
251
|
return html`
|
|
246
252
|
<zn-option value="${item.id}">
|
|
247
253
|
${item.name.charAt(0).toUpperCase() + item.name.slice(1)}
|
|
@@ -338,7 +344,7 @@ export default class ZnQueryBuilder extends ZincElement implements ZincFormContr
|
|
|
338
344
|
break;
|
|
339
345
|
}
|
|
340
346
|
case 'dateTime': {
|
|
341
|
-
input = this._createDateInput(uniqueId, true
|
|
347
|
+
input = this._createDateInput(uniqueId, true, filter.dateSubmitFormat);
|
|
342
348
|
break;
|
|
343
349
|
}
|
|
344
350
|
default: {
|
|
@@ -401,9 +407,9 @@ export default class ZnQueryBuilder extends ZincElement implements ZincFormContr
|
|
|
401
407
|
?time-picker="${hasTime}"
|
|
402
408
|
class="query-builder__value"
|
|
403
409
|
@zn-change="${(e: ZnChangeEvent) => this._updateDateValue(uniqueId, e, submitFormat)}"
|
|
404
|
-
|
|
410
|
+
>
|
|
405
411
|
</zn-datepicker>
|
|
406
|
-
|
|
412
|
+
`;
|
|
407
413
|
return litToHTML<ZnDatepicker>(input);
|
|
408
414
|
}
|
|
409
415
|
|
|
@@ -451,7 +457,9 @@ export default class ZnQueryBuilder extends ZincElement implements ZincFormContr
|
|
|
451
457
|
this._handleChange();
|
|
452
458
|
}
|
|
453
459
|
|
|
454
|
-
private _updateDateValue(id: string, event: Event | {
|
|
460
|
+
private _updateDateValue(id: string, event: Event | {
|
|
461
|
+
target: ZnDatepicker | HTMLDivElement
|
|
462
|
+
}, submitFormat: QueryBuilderDateSubmitFormat = 'legacy') {
|
|
455
463
|
const filter = this._selectedRules.get(id);
|
|
456
464
|
if (!filter) return;
|
|
457
465
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import ZnRemarkdEditor from './remarkd-editor.component';
|
|
2
|
+
|
|
3
|
+
export * from './remarkd-editor.component';
|
|
4
|
+
export default ZnRemarkdEditor;
|
|
5
|
+
|
|
6
|
+
ZnRemarkdEditor.define('zn-remarkd-editor');
|
|
7
|
+
|
|
8
|
+
declare global {
|
|
9
|
+
interface HTMLElementTagNameMap {
|
|
10
|
+
'zn-remarkd-editor': ZnRemarkdEditor;
|
|
11
|
+
}
|
|
12
|
+
}
|