Skip to content

Commit 1a52a83

Browse files
committed
Initial Release
1 parent eecb604 commit 1a52a83

File tree

11 files changed

+1363
-1187
lines changed

11 files changed

+1363
-1187
lines changed

CHANGELOG.md

Lines changed: 1 addition & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -7,76 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
### Changed
11-
- Update node version via `.npmrc`
12-
- Update Node CI workflow
13-
- Install & use `@shgysk8zer0/eslint-config`
14-
- Add support for `node --test`, including ignoring tests for publishing
15-
- Update ESLint & super-linter
16-
- Switch to more basic Rollup config
17-
- Update `exports` and `main` accordingly
18-
19-
### Fixed
20-
- Fix missed renaming in README
21-
22-
## Removed
23-
- Remove old ESLint config files
24-
25-
## [v1.1.1] - 2023-09-24
26-
27-
### Added
28-
- Add `unpkg` to `package.json`
29-
- Add badges in README
30-
31-
### Changed
32-
- Update `exports` to `package.json` to handle wider variety
33-
34-
### Fixed
35-
- Fix typo in `fix:js` script
36-
37-
### [v1.1.0] - 2023-07-03
38-
39-
### Changed
40-
- Update to node 20
41-
- Update npm publishing GH Action
42-
43-
## [v1.0.5] - 2023-07-02
44-
45-
### Added
46-
- Add `funding`
47-
48-
### Changed
49-
- Updated GitHub Actions workflows
50-
- Update versioning & lock-file scripts
51-
- Update `.npmignore` & `.gitignore`
52-
53-
## [v1.0.4] - 2023-06-08
54-
55-
### Added
56-
- Install `@shgysk8zer0/npm-utils`
57-
- Add `exports` to package config
58-
59-
### Removed
60-
- Uninstall `rollup`, `eslint`
61-
62-
### Changed
63-
- Use `getConfig()` from `@shgysk8zer0/js-utils/rollup` for rollup config
64-
65-
## [v1.0.3] - 2023-06-01
66-
67-
### Fixed
68-
- Revert to old Release Action, now with permissions & link to changelog
69-
70-
## [v1.0.2] - 2023-06-01
71-
72-
### Fixed
73-
- Fix `changelog-entry` to match `[$version]` instead of `$version`
74-
75-
## [v1.0.1] - 2023-05-31
76-
77-
### Fixed
78-
- Update GitHub Release workflow to use [Auto Release](https://github.com/marketplace/actions/auto-release)
79-
80-
## [v1.0.0] - 2023-05-31
10+
## [v1.0.0] - 2025-04-30
8111

8212
Initial Release

README.md

Lines changed: 98 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
# npm-template
1+
# `@aegisjsproject/md-editor`
22

3-
A template repo for npm packages
3+
A custom Markdown editor component with preview as a form input element
44

5-
[![CodeQL](https://github.com/shgysk8zer0/npm-template/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/shgysk8zer0/npm-template/actions/workflows/codeql-analysis.yml)
6-
![Node CI](https://github.com/shgysk8zer0/npm-template/workflows/Node%20CI/badge.svg)
7-
![Lint Code Base](https://github.com/shgysk8zer0/npm-template/workflows/Lint%20Code%20Base/badge.svg)
5+
[![CodeQL](https://github.com/AegisJSProject/md-editor/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/AegisJSProject/md-editor/actions/workflows/codeql-analysis.yml)
6+
![Node CI](https://github.com/AegisJSProject/md-editor/workflows/Node%20CI/badge.svg)
7+
![Lint Code Base](https://github.com/AegisJSProject/md-editor/workflows/Lint%20Code%20Base/badge.svg)
88

9-
[![GitHub license](https://img.shields.io/github/license/shgysk8zer0/npm-template.svg)](https://github.com/shgysk8zer0/npm-template/blob/master/LICENSE)
10-
[![GitHub last commit](https://img.shields.io/github/last-commit/shgysk8zer0/npm-template.svg)](https://github.com/shgysk8zer0/npm-template/commits/master)
11-
[![GitHub release](https://img.shields.io/github/release/shgysk8zer0/npm-template?logo=github)](https://github.com/shgysk8zer0/npm-template/releases)
9+
[![GitHub license](https://img.shields.io/github/license/AegisJSProject/md-editor.svg)](https://github.com/AegisJSProject/md-editor/blob/master/LICENSE)
10+
[![GitHub last commit](https://img.shields.io/github/last-commit/AegisJSProject/md-editor.svg)](https://github.com/AegisJSProject/md-editor/commits/master)
11+
[![GitHub release](https://img.shields.io/github/release/AegisJSProject/md-editor?logo=github)](https://github.com/AegisJSProject/md-editor/releases)
1212
[![GitHub Sponsors](https://img.shields.io/github/sponsors/shgysk8zer0?logo=github)](https://github.com/sponsors/shgysk8zer0)
1313

14-
[![npm](https://img.shields.io/npm/v/@shgysk8zer0/npm-template)](https://www.npmjs.com/package/@shgysk8zer0/npm-template)
15-
![node-current](https://img.shields.io/node/v/@shgysk8zer0/npm-template)
16-
![npm bundle size gzipped](https://img.shields.io/bundlephobia/minzip/@shgysk8zer0/npm-template)
17-
[![npm](https://img.shields.io/npm/dw/@shgysk8zer0/npm-template?logo=npm)](https://www.npmjs.com/package/@shgysk8zer0/npm-template)
14+
[![npm](https://img.shields.io/npm/v/@aegisjsproject/md-editor)](https://www.npmjs.com/package/@aegisjsproject/md-editor)
15+
![node-current](https://img.shields.io/node/v/@aegisjsproject/md-editor)
16+
![npm bundle size gzipped](https://img.shields.io/bundlephobia/minzip/@aegisjsproject/md-editor)
17+
[![npm](https://img.shields.io/npm/dw/@aegisjsproject/md-editor?logo=npm)](https://www.npmjs.com/package/@aegisjsproject/md-editor)
1818

19-
[![GitHub followers](https://img.shields.io/github/followers/shgysk8zer0.svg?style=social)](https://github.com/shgysk8zer0)
20-
![GitHub forks](https://img.shields.io/github/forks/shgysk8zer0/npm-template.svg?style=social)
21-
![GitHub stars](https://img.shields.io/github/stars/shgysk8zer0/npm-template.svg?style=social)
19+
[![GitHub followers](https://img.shields.io/github/followers/AegisJSProject.svg?style=social)](https://github.com/AegisJSProject)
20+
![GitHub forks](https://img.shields.io/github/forks/AegisJSProject/md-editor.svg?style=social)
21+
![GitHub stars](https://img.shields.io/github/stars/AegisJSProject/md-editor.svg?style=social)
2222
[![Twitter Follow](https://img.shields.io/twitter/follow/shgysk8zer0.svg?style=social)](https://twitter.com/shgysk8zer0)
2323

2424
[![Donate using Liberapay](https://img.shields.io/liberapay/receives/shgysk8zer0.svg?logo=liberapay)](https://liberapay.com/shgysk8zer0/donate "Donate using Liberapay")
@@ -27,3 +27,86 @@ A template repo for npm packages
2727
- [Code of Conduct](./.github/CODE_OF_CONDUCT.md)
2828
- [Contributing](./.github/CONTRIBUTING.md)
2929
<!-- - [Security Policy](./.github/SECURITY.md) -->
30+
## Installation
31+
32+
### Node Instructions
33+
```bash
34+
npm i @aegisjsproject/md-editor
35+
```
36+
37+
### Using [`<script type="importmap">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type/importmap) and a CDN
38+
39+
```html
40+
<script type="importmap">
41+
{
42+
"imports": {
43+
"@aegisjsproject/md-editor": "https://unpkg.com/@aegisjsproject/md-editor@1.0.0/md-editor.min.js"
44+
}
45+
}
46+
</script>
47+
```
48+
49+
### Just Using a `<script>`
50+
51+
```html
52+
<script src="https://unpkg.com/@aegisjsproject/md-editor@1.0.0/md-editor.min.js" crossorigin="anonymous" referrerpolicy="no-referrer" defer=""></script>
53+
```
54+
55+
## Example Usage
56+
57+
### Just using HTML
58+
59+
```html
60+
<form id="post">
61+
<label for="content">Content</label>
62+
<!-- This behaves basically like a textarea or any input -->
63+
<md-editor name="content" id="content" minlength="40" mode="editor" required="">
64+
# Hello, World!
65+
![foo](/img/foo.png)
66+
</md-editor>
67+
<!-- Rest of form stuff -->
68+
</form>
69+
```
70+
71+
### Creating through Scripting
72+
73+
```js
74+
// Need to import if not already added
75+
import '@aegisjsproject/md-editor';
76+
77+
// Get the component class
78+
const HTMLMarkdownEditorElement = customElements.get('md-editor');
79+
80+
// Create and setup the element
81+
const editor = new HTMLMarkdownEditorElement();
82+
editor.name = 'content';
83+
editor.id = 'content';
84+
85+
// Optionally bind to `history.state[whatever]
86+
editor.textContent = history.state?.content;
87+
editor.addEventListener('change', ({ target }) => history.replaceState({ content: target.value }, '', location.href), { passive: true });
88+
89+
// Add to the form, after its `<label>`
90+
document.querySelector(`label[for="${editor.id}"]`).after(editor);
91+
```
92+
93+
## Usage Notes and Browser APIs
94+
95+
This component utilizes some proposed and experimental APIs including `Element.prototype.setHTML` (this [Sanitizer API](https://github.com/WICG/sanitizer-api))
96+
and [`String.dedent`](https://github.com/tc39/proposal-string-dedent). These APIs **MUST** be polyfilled. You may find
97+
the required polyfills in [`@shgysk8zer0/polyfills`](https://npmjs.com/package/@shgysk8zer0/polyfills) or provide your own.
98+
99+
## Security
100+
101+
Like all `@aegisjsproject` libraries, this component is indended to be safe and compatible in highly secure contexts. It
102+
is designed to work with a very restricted [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy)
103+
as well as [the Trusted Types API](https://developer.mozilla.org/en-US/docs/Web/API/Trusted_Types_API).
104+
105+
### Example CSP
106+
107+
Note the [SRI](https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/SRI) Integrity used
108+
for a `<script type="importmap">` and the Trusted Types Policy of `aegis-sanitizer#html` (required for the Sanitizer API polyfill).
109+
110+
```
111+
Content-Security-Policy: default-src 'self'; script-src 'self' https://unpkg.com/@shgysk8zer0/ https://unpkg.com/@aegisjsproject/ 'sha384-XYouuKGvd2BSrapxPZFWENl9b0loR7EVyC2cls6tQ/Oa+3R/uWw6TQ+nWa4/zt9l'; style-src 'self' https://unpkg.com/@highlightjs/ https://unpkg.com/@aegisjsproject/; img-src 'self'; trusted-types aegis-sanitizer#html; require-trusted-types-for 'script';
112+
```

consts.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

eslint.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import { node } from '@shgysk8zer0/eslint-config';
1+
import { browser } from '@shgysk8zer0/eslint-config';
22

3-
export default node({ files: ['**/*.js'], ignores: ['**/*.min.js', '**/*.cjs', '**/*.mjs'] });
3+
export default browser({ files: ['**/*.js'], ignores: ['**/*.min.js', '**/*.cjs', '**/*.mjs'] });

http.config.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { importmap, getImportmapScript, getImportmapIntegrity } from '@shgysk8zer0/importmap';
2+
3+
const integrity = await getImportmapIntegrity();
4+
const csp = [
5+
'default-src \'self\'',
6+
`script-src 'self' https://unpkg.com/@shgysk8zer0/ https://unpkg.com/@aegisjsproject/ '${integrity}'`,
7+
'style-src \'self\' https://unpkg.com/@highlightjs/ https://unpkg.com/@aegisjsproject/',
8+
'img-src \'self\' https://cdn.kernvalley.us/img/',
9+
'trusted-types aegis-sanitizer#html',
10+
'require-trusted-types-for \'script\'',
11+
].join('; ');
12+
13+
console.log(csp);
14+
15+
const style = sheet => `<link rel="stylesheet" href="${importmap.imports['@aegisjsproject/styles/']}css/${sheet}.css" crossorigin="anonymous" referrerpolicy="no-referrer" />`;
16+
17+
const script = `
18+
import './md-editor.js';
19+
20+
const HTMLMarkdownEditorElement = customElements.get('md-editor');
21+
const editor = new HTMLMarkdownEditorElement();
22+
editor.name = 'content';
23+
editor.id = 'content';
24+
editor.textContent = history.state?.content;
25+
editor.addEventListener('change', ({ target }) => history.replaceState({ content: target.value }, '', location.href), { passive: true });
26+
document.querySelector('label[for="content"]').after(editor);
27+
document.forms.post.addEventListener('submit', event => {
28+
event.preventDefault();
29+
const data = new FormData(event.target);
30+
document.getElementById('result').textContent = JSON.stringify(Object.fromEntries(data), null, 4);
31+
document.getElementById('popover').showPopover();
32+
});
33+
`;
34+
35+
const doc = `<!DOCTYPE html>
36+
<html lang="en" dir="ltr">
37+
<head>
38+
<meta charset="utf-8" />
39+
<meta name="viewport" content="width=device-width" />
40+
<meta name="color-scheme" content="light dark" />
41+
<title>@aegisjsproject/md-editor</title>
42+
${style('properties')}
43+
${style('reset')}
44+
${style('theme')}
45+
${style('button')}
46+
${style('misc')}
47+
${style('forms')}
48+
${style('scrollbar')}
49+
${style('animations')}
50+
${await getImportmapScript()}
51+
<script defer="" referrerpolicy="no-referrer" fetchpriority="high" crossorigin="anonymous" integrity="sha384-X8d55dt38lBIY87GNkg6Upb9pjtwYlhEoKtw9Sfsbj/XCDV4W+g0kdx4X1Bo/EaO" src="https://unpkg.com/@shgysk8zer0/polyfills@0.4.11/browser.min.js"></script>
52+
<script src="./index.js" type="module" referrerpolicy="no-referrer"></script>
53+
</head>
54+
<body>
55+
<form id="post">
56+
<fieldset class="no-border">
57+
<legend>Create a Post</legend>
58+
<div class="form-group">
59+
<label for="title" class="input-label required">Title</label>
60+
<input type="text" name="title" id="title" class="input" placeholder="Post Title" required />
61+
</div>
62+
<div class="form-group">
63+
<label for="content" class="input-label required">Content</label>
64+
<!-- MD Editor here -->
65+
</div>
66+
</fieldset>
67+
<div>
68+
<button type="submit" class="btn btn-success">Submit</button>
69+
<button type="reset" class="btn btn-danger">Reset</button>
70+
</div>
71+
</form>
72+
<div id="popover" popover="auto">
73+
<pre><code id="result"></code></pre>
74+
</div>
75+
</body>
76+
</html>`;
77+
78+
const headers = new Headers({
79+
'Content-Type': 'text/html',
80+
'Content-Security-Policy': csp,
81+
});
82+
83+
export default {
84+
routes: {
85+
'/': () => new Response(doc, { headers }),
86+
'/index.js': () => new Response(script, { headers: { 'Content-Type': 'application/javascript' }}),
87+
},
88+
port: 8123,
89+
open: true,
90+
};

index.js

Lines changed: 0 additions & 2 deletions
This file was deleted.

index.test.js

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)