kempo-ui 0.0.43 → 0.0.62
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/.github/copilot-instructions.md +11 -0
- package/.github/workflows/publish.yml +66 -0
- package/CONTRIBUTING.md +70 -0
- package/dist/components/Dialog.js +9 -8
- package/dist/components/HtmlEditor.js +91 -0
- package/dist/components/Icon.js +2 -2
- package/dist/components/ShadowComponent.js +1 -1
- package/dist/components/SideMenu.js +1 -1
- package/dist/components/SidePanel.js +40 -30
- package/dist/components/htmlEditorControls/AlignCenter.js +12 -0
- package/dist/components/htmlEditorControls/AlignJustify.js +12 -0
- package/dist/components/htmlEditorControls/AlignLeft.js +12 -0
- package/dist/components/htmlEditorControls/AlignRight.js +12 -0
- package/dist/components/htmlEditorControls/Bold.js +12 -0
- package/dist/components/htmlEditorControls/BulletList.js +12 -0
- package/dist/components/htmlEditorControls/CharacterCount.js +18 -0
- package/dist/components/htmlEditorControls/ClearFormatting.js +12 -0
- package/dist/components/htmlEditorControls/CodeBlock.js +12 -0
- package/dist/components/htmlEditorControls/ControlGroup.js +14 -0
- package/dist/components/htmlEditorControls/ControlSpacer.js +6 -0
- package/dist/components/htmlEditorControls/CreateLink.js +15 -0
- package/dist/components/htmlEditorControls/DropdownControl.js +57 -0
- package/dist/components/htmlEditorControls/FormatBlock.js +12 -0
- package/dist/components/htmlEditorControls/HtmlEditorControl.js +44 -0
- package/dist/components/htmlEditorControls/InlineCode.js +12 -0
- package/dist/components/htmlEditorControls/InsertTable.js +15 -0
- package/dist/components/htmlEditorControls/Italic.js +12 -0
- package/dist/components/htmlEditorControls/Mode.js +9 -0
- package/dist/components/htmlEditorControls/NumberList.js +12 -0
- package/dist/components/htmlEditorControls/Strikethrough.js +12 -0
- package/dist/components/htmlEditorControls/TextBackgroundColor.js +97 -0
- package/dist/components/htmlEditorControls/TextColor.js +97 -0
- package/dist/components/htmlEditorControls/Underline.js +12 -0
- package/dist/components/htmlEditorControls/WordCount.js +18 -0
- package/dist/utils/formatCode.js +1 -0
- package/docs/components/dropdown.html +2 -2
- package/docs/components/html-editor.html +442 -0
- package/docs/components/icon.html +2 -7
- package/docs/components/photo-viewer.html +14 -14
- package/docs/components/side-menu.html +32 -0
- package/docs/components/side-panel-dual.html +70 -0
- package/docs/components/side-panel-scroll.html +176 -0
- package/docs/components/side-panel.html +41 -1
- package/docs/icons/arrow_drop_down.svg +1 -0
- package/docs/icons/circle.svg +1 -0
- package/docs/icons/code.svg +1 -0
- package/docs/icons/code_blocks.svg +1 -0
- package/docs/icons/copy.svg +1 -0
- package/docs/icons/dot.svg +1 -0
- package/docs/icons/format_align_center.svg +1 -0
- package/docs/icons/format_align_justify.svg +1 -0
- package/docs/icons/format_align_left.svg +1 -0
- package/docs/icons/format_align_right.svg +1 -0
- package/docs/icons/format_bold.svg +1 -0
- package/docs/icons/format_clear.svg +1 -0
- package/docs/icons/format_color_fill.svg +1 -0
- package/docs/icons/format_color_text.svg +1 -0
- package/docs/icons/format_h1.svg +1 -0
- package/docs/icons/format_h2.svg +1 -0
- package/docs/icons/format_h3.svg +1 -0
- package/docs/icons/format_h4.svg +1 -0
- package/docs/icons/format_h5.svg +1 -0
- package/docs/icons/format_h6.svg +1 -0
- package/docs/icons/format_italic.svg +1 -0
- package/docs/icons/format_list_bulleted.svg +1 -0
- package/docs/icons/format_list_numbered.svg +1 -0
- package/docs/icons/format_paragraph.svg +1 -0
- package/docs/icons/format_underlined.svg +1 -0
- package/docs/icons/help.svg +1 -0
- package/docs/icons/link.svg +1 -0
- package/docs/icons/more_vert.svg +1 -0
- package/docs/icons/strikethrough_s.svg +1 -0
- package/docs/icons/table.svg +1 -0
- package/docs/icons/wysiwyg.svg +1 -0
- package/docs/index.html +6 -0
- package/docs/nav-1.inc.html +1 -0
- package/docs/nav.inc.html +1 -0
- package/docs/src/components/Dialog.js +9 -8
- package/docs/src/components/HtmlEditor.js +91 -0
- package/docs/src/components/Icon.js +2 -2
- package/docs/src/components/ShadowComponent.js +1 -1
- package/docs/src/components/SideMenu.js +1 -1
- package/docs/src/components/SidePanel.js +40 -30
- package/docs/src/components/htmlEditorControls/AlignCenter.js +12 -0
- package/docs/src/components/htmlEditorControls/AlignJustify.js +12 -0
- package/docs/src/components/htmlEditorControls/AlignLeft.js +12 -0
- package/docs/src/components/htmlEditorControls/AlignRight.js +12 -0
- package/docs/src/components/htmlEditorControls/Bold.js +12 -0
- package/docs/src/components/htmlEditorControls/BulletList.js +12 -0
- package/docs/src/components/htmlEditorControls/CharacterCount.js +18 -0
- package/docs/src/components/htmlEditorControls/ClearFormatting.js +12 -0
- package/docs/src/components/htmlEditorControls/CodeBlock.js +12 -0
- package/docs/src/components/htmlEditorControls/ControlGroup.js +14 -0
- package/docs/src/components/htmlEditorControls/ControlSpacer.js +6 -0
- package/docs/src/components/htmlEditorControls/CreateLink.js +15 -0
- package/docs/src/components/htmlEditorControls/DropdownControl.js +57 -0
- package/docs/src/components/htmlEditorControls/FormatBlock.js +12 -0
- package/docs/src/components/htmlEditorControls/HtmlEditorControl.js +44 -0
- package/docs/src/components/htmlEditorControls/InlineCode.js +12 -0
- package/docs/src/components/htmlEditorControls/InsertTable.js +15 -0
- package/docs/src/components/htmlEditorControls/Italic.js +12 -0
- package/docs/src/components/htmlEditorControls/Mode.js +9 -0
- package/docs/src/components/htmlEditorControls/NumberList.js +12 -0
- package/docs/src/components/htmlEditorControls/Strikethrough.js +12 -0
- package/docs/src/components/htmlEditorControls/TextBackgroundColor.js +97 -0
- package/docs/src/components/htmlEditorControls/TextColor.js +97 -0
- package/docs/src/components/htmlEditorControls/Underline.js +12 -0
- package/docs/src/components/htmlEditorControls/WordCount.js +18 -0
- package/docs/src/utils/formatCode.js +1 -0
- package/icons/arrow_drop_down.svg +1 -0
- package/icons/circle.svg +1 -0
- package/icons/code.svg +1 -0
- package/icons/code_blocks.svg +1 -0
- package/icons/copy.svg +1 -0
- package/icons/dot.svg +1 -0
- package/icons/format_align_center.svg +1 -0
- package/icons/format_align_justify.svg +1 -0
- package/icons/format_align_left.svg +1 -0
- package/icons/format_align_right.svg +1 -0
- package/icons/format_bold.svg +1 -0
- package/icons/format_clear.svg +1 -0
- package/icons/format_color_fill.svg +1 -0
- package/icons/format_color_text.svg +1 -0
- package/icons/format_h1.svg +1 -0
- package/icons/format_h2.svg +1 -0
- package/icons/format_h3.svg +1 -0
- package/icons/format_h4.svg +1 -0
- package/icons/format_h5.svg +1 -0
- package/icons/format_h6.svg +1 -0
- package/icons/format_italic.svg +1 -0
- package/icons/format_list_bulleted.svg +1 -0
- package/icons/format_list_numbered.svg +1 -0
- package/icons/format_paragraph.svg +1 -0
- package/icons/format_underlined.svg +1 -0
- package/icons/help.svg +1 -0
- package/icons/link.svg +1 -0
- package/icons/more_vert.svg +1 -0
- package/icons/strikethrough_s.svg +1 -0
- package/icons/table.svg +1 -0
- package/icons/wysiwyg.svg +1 -0
- package/package.json +6 -5
- package/scripts/getIcon.js +52 -0
- package/src/components/Dialog.js +25 -10
- package/src/components/HtmlEditor.js +1548 -0
- package/src/components/Icon.js +6 -3
- package/src/components/Main.js +22 -23
- package/src/components/ShadowComponent.js +0 -1
- package/src/components/SideMenu.js +10 -0
- package/src/components/SidePanel.js +78 -35
- package/src/components/htmlEditorControls/AlignCenter.js +65 -0
- package/src/components/htmlEditorControls/AlignJustify.js +65 -0
- package/src/components/htmlEditorControls/AlignLeft.js +65 -0
- package/src/components/htmlEditorControls/AlignRight.js +65 -0
- package/src/components/htmlEditorControls/Bold.js +65 -0
- package/src/components/htmlEditorControls/BulletList.js +65 -0
- package/src/components/htmlEditorControls/CharacterCount.js +75 -0
- package/src/components/htmlEditorControls/ClearFormatting.js +65 -0
- package/src/components/htmlEditorControls/CodeBlock.js +72 -0
- package/src/components/htmlEditorControls/ControlGroup.js +95 -0
- package/src/components/htmlEditorControls/ControlSpacer.js +23 -0
- package/src/components/htmlEditorControls/CreateLink.js +121 -0
- package/src/components/htmlEditorControls/DropdownControl.js +149 -0
- package/src/components/htmlEditorControls/FormatBlock.js +108 -0
- package/src/components/htmlEditorControls/HtmlEditorControl.js +126 -0
- package/src/components/htmlEditorControls/InlineCode.js +77 -0
- package/src/components/htmlEditorControls/InsertTable.js +171 -0
- package/src/components/htmlEditorControls/Italic.js +65 -0
- package/src/components/htmlEditorControls/Mode.js +66 -0
- package/src/components/htmlEditorControls/NumberList.js +65 -0
- package/src/components/htmlEditorControls/Strikethrough.js +65 -0
- package/src/components/htmlEditorControls/TextBackgroundColor.js +195 -0
- package/src/components/htmlEditorControls/TextColor.js +195 -0
- package/src/components/htmlEditorControls/Underline.js +65 -0
- package/src/components/htmlEditorControls/WordCount.js +76 -0
- package/src/utils/formatCode.js +87 -0
- package/tests/components/Main.browser-test.js +166 -105
- package/tests/components/SidePanel.browser-test.js +62 -8
- package/.github/workflows/publish-major.yml +0 -39
- package/.github/workflows/publish-minor.yml +0 -39
- package/.github/workflows/publish-patch.yml +0 -45
- package/docs/icons/arrow-back.svg +0 -1
- package/docs/icons/arrow-down-double.svg +0 -1
- package/docs/icons/arrow-down.svg +0 -1
- package/docs/icons/arrow-forward.svg +0 -1
- package/docs/icons/arrow-menu-close.svg +0 -1
- package/docs/icons/arrow-menu-open.svg +0 -1
- package/docs/icons/arrow-right.svg +0 -1
- package/docs/icons/arrow-up-double.svg +0 -1
- package/docs/icons/arrow-up.svg +0 -1
- package/docs/icons/chevron-left.svg +0 -1
- package/docs/icons/chevron-right.svg +0 -1
- package/docs/icons/chevron-up.svg +0 -1
|
@@ -150,6 +150,17 @@ export default class MyComponent extends HybridComponent {
|
|
|
150
150
|
|
|
151
151
|
## Development Workflow
|
|
152
152
|
|
|
153
|
+
### Icons
|
|
154
|
+
- All icons are stored in the `icons/` directory as SVG files
|
|
155
|
+
- Icons should have no `width` or `height` attributes, and use `fill="currentColor"` for theming
|
|
156
|
+
- To download new Material Icons from Google's CDN:
|
|
157
|
+
```bash
|
|
158
|
+
npm run geticon icon_name
|
|
159
|
+
```
|
|
160
|
+
Example: `npm run geticon format_bold`
|
|
161
|
+
- The script automatically formats the icon with proper attributes
|
|
162
|
+
- Browse available icons at [Google Material Symbols](https://fonts.google.com/icons)
|
|
163
|
+
|
|
153
164
|
### Local Development Server
|
|
154
165
|
- **DO NOT** start a development server - one is already running
|
|
155
166
|
- Default port: **8083**
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: Publish to npmjs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
version-type:
|
|
10
|
+
description: 'Version bump type'
|
|
11
|
+
required: true
|
|
12
|
+
type: choice
|
|
13
|
+
options:
|
|
14
|
+
- patch
|
|
15
|
+
- minor
|
|
16
|
+
- major
|
|
17
|
+
default: patch
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
publish:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
permissions:
|
|
23
|
+
contents: write
|
|
24
|
+
id-token: write
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
with:
|
|
28
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
29
|
+
|
|
30
|
+
- uses: actions/setup-node@v4
|
|
31
|
+
with:
|
|
32
|
+
node-version: '20.x'
|
|
33
|
+
|
|
34
|
+
- run: npm ci
|
|
35
|
+
|
|
36
|
+
- name: Set version type
|
|
37
|
+
id: version
|
|
38
|
+
run: |
|
|
39
|
+
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
|
40
|
+
echo "type=${{ inputs.version-type }}" >> $GITHUB_OUTPUT
|
|
41
|
+
else
|
|
42
|
+
echo "type=patch" >> $GITHUB_OUTPUT
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
- name: Bump ${{ steps.version.outputs.type }} version
|
|
46
|
+
run: |
|
|
47
|
+
git config --global user.name "github-actions"
|
|
48
|
+
git config --global user.email "github-actions@github.com"
|
|
49
|
+
npm version ${{ steps.version.outputs.type }} --no-git-tag-version
|
|
50
|
+
git add package.json package-lock.json || true
|
|
51
|
+
git commit -m "ci: bump ${{ steps.version.outputs.type }} version [skip ci]" || echo "No changes to commit"
|
|
52
|
+
git push origin HEAD:main || echo "No changes to push"
|
|
53
|
+
env:
|
|
54
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
55
|
+
|
|
56
|
+
- name: Setup .npmrc for OIDC
|
|
57
|
+
run: |
|
|
58
|
+
cat << EOF > ~/.npmrc
|
|
59
|
+
//registry.npmjs.org/:_authToken=\${NPM_TOKEN}
|
|
60
|
+
registry=https://registry.npmjs.org/
|
|
61
|
+
always-auth=true
|
|
62
|
+
EOF
|
|
63
|
+
|
|
64
|
+
- run: npm publish --access public
|
|
65
|
+
env:
|
|
66
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/CONTRIBUTING.md
CHANGED
|
@@ -147,3 +147,73 @@ export default class MyComponent extends HybridComponent {
|
|
|
147
147
|
- Wrap dependent components inside a parent `ktf-test-framework` element. Children find it via `closest('ktf-test-framework')` and call its methods. The framework can query its subtree to orchestrate children.
|
|
148
148
|
|
|
149
149
|
- Avoid `window` globals and global custom events for coordination. If broadcast is needed, scope events to the framework element; reserve window events for global, non-visual concerns (e.g., settings changes).
|
|
150
|
+
|
|
151
|
+
## Development Workflow
|
|
152
|
+
|
|
153
|
+
### NPM Scripts
|
|
154
|
+
|
|
155
|
+
#### Build
|
|
156
|
+
```bash
|
|
157
|
+
npm run build
|
|
158
|
+
```
|
|
159
|
+
Compiles and minifies source files from `src/` and copies all necessary files to the `docs/` directory for GitHub Pages deployment.
|
|
160
|
+
|
|
161
|
+
#### Documentation Server
|
|
162
|
+
```bash
|
|
163
|
+
npm run docs
|
|
164
|
+
```
|
|
165
|
+
Starts a local development server and opens the documentation site. Automatically runs the build script first.
|
|
166
|
+
|
|
167
|
+
**Variants:**
|
|
168
|
+
- `npm run docs:src` - Serves from `src/` instead of `docs/` for development
|
|
169
|
+
- `npm run docs:no-build` - Skips the build step and serves existing `docs/`
|
|
170
|
+
|
|
171
|
+
#### Testing
|
|
172
|
+
```bash
|
|
173
|
+
npm test # Run all tests
|
|
174
|
+
npm run test:gui # Run tests with GUI interface
|
|
175
|
+
npm run test:browser # Run browser-only tests
|
|
176
|
+
npm run test:node # Run Node.js-only tests
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### Update Kempo CSS
|
|
180
|
+
```bash
|
|
181
|
+
npm run update-kempo-css
|
|
182
|
+
```
|
|
183
|
+
Downloads the latest version of Kempo CSS from the CDN and updates local files.
|
|
184
|
+
|
|
185
|
+
### Adding Icons
|
|
186
|
+
|
|
187
|
+
Use the `geticon` script to download icons from [Google Material Symbols](https://fonts.google.com/icons). The script automatically formats icons and triggers a build.
|
|
188
|
+
|
|
189
|
+
#### Basic Usage
|
|
190
|
+
```bash
|
|
191
|
+
npm run geticon <icon_name>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Example:
|
|
195
|
+
```bash
|
|
196
|
+
npm run geticon format_bold
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
This downloads the icon and saves it as `format_bold.svg` in the `icons/` directory.
|
|
200
|
+
|
|
201
|
+
#### Custom Naming
|
|
202
|
+
|
|
203
|
+
Rename icons when downloading by providing a second argument:
|
|
204
|
+
```bash
|
|
205
|
+
npm run geticon <icon_name> <custom_name>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Example - download `content_copy` but save as `copy.svg`:
|
|
209
|
+
```bash
|
|
210
|
+
npm run geticon content_copy copy
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
#### What the Script Does
|
|
214
|
+
|
|
215
|
+
- Downloads the specified icon from Google's Material Symbols CDN
|
|
216
|
+
- Removes `width` and `height` attributes
|
|
217
|
+
- Adds `fill="currentColor"` to all `<path>` elements
|
|
218
|
+
- Saves the formatted SVG to the `icons/` directory
|
|
219
|
+
- Automatically runs the build script to copy the icon to `docs/`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";import{boolExists}from"../utils/propConverters.js";import"./Icon.js";import"./FocusCapture.js";const firstFocusable=e=>e.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')[0];export default class Dialog extends ShadowComponent{static properties={opened:{type:Boolean,reflect:!0,converter:boolExists},closeBtn:{type:Boolean,reflect:!0,attribute:"close-btn",converter:boolExists},overlayClose:{type:Boolean,reflect:!0,attribute:"overlay-close",converter:boolExists},disableKeyboardClose:{type:Boolean,reflect:!0,attribute:"disable-keyboard-close",converter:boolExists},confirmText:{type:String,reflect:!0,attribute:"confirm-text"},confirmClasses:{type:String,reflect:!0,attribute:"confirm-classes"},cancelText:{type:String,reflect:!0,attribute:"cancel-text"},cancelClasses:{type:String,reflect:!0,attribute:"cancel-classes"}};constructor(){super(),this.opened=!1,this.closeBtn=!0,this.overlayClose=!0,this.disableKeyboardClose=!1,this.confirmText="",this.confirmClasses="success ml",this.cancelText="",this.cancelClasses="",this.confirmAction=()=>{},this.cancelAction=()=>{},this.closeCallback=()=>{},this.previousFocus=null}handleClick=e=>{const{target:t}=e,o=t.id||t.closest("[id]")?.id;"overlay"===o&&this.overlayClose||"close"===o?this.close():"cancel"===o
|
|
1
|
+
import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";import{boolExists}from"../utils/propConverters.js";import"./Icon.js";import"./FocusCapture.js";const firstFocusable=e=>e.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])')[0];export default class Dialog extends ShadowComponent{static properties={opened:{type:Boolean,reflect:!0,converter:boolExists},closeBtn:{type:Boolean,reflect:!0,attribute:"close-btn",converter:boolExists},overlayClose:{type:Boolean,reflect:!0,attribute:"overlay-close",converter:boolExists},disableKeyboardClose:{type:Boolean,reflect:!0,attribute:"disable-keyboard-close",converter:boolExists},confirmText:{type:String,reflect:!0,attribute:"confirm-text"},confirmClasses:{type:String,reflect:!0,attribute:"confirm-classes"},cancelText:{type:String,reflect:!0,attribute:"cancel-text"},cancelClasses:{type:String,reflect:!0,attribute:"cancel-classes"}};constructor(){super(),this.opened=!1,this.closeBtn=!0,this.overlayClose=!0,this.disableKeyboardClose=!1,this.confirmText="",this.confirmClasses="success ml",this.cancelText="",this.cancelClasses="",this.confirmAction=()=>{},this.cancelAction=()=>{},this.closeCallback=()=>{},this.previousFocus=null}handleClick=e=>{const{target:t}=e,o=t.id||t.closest("[id]")?.id;"overlay"===o&&this.overlayClose||"close"===o?this.close():"cancel"===o&&(this.cancelAction(e),e.defaultPrevented||this.close())};handleSubmit=e=>{e.preventDefault(),this.confirmAction(e),e.keepDialogOpen||this.close()};handleSlotKeydown=e=>{if("Enter"===e.key&&this.confirmText){const t=e.target;if("INPUT"===t.tagName||"TEXTAREA"===t.tagName){e.preventDefault();const t=this.shadowRoot.querySelector("form");t&&t.requestSubmit()}}};handleKeydown=e=>{this.disableKeyboardClose||27!==e.keyCode||this.close()};connectedCallback(){super.connectedCallback()}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("keydown",this.handleKeydown)}updated(e){super.updated(e),e.has("opened")&&this.dispatchEvent(new CustomEvent(this.opened?"opened":"close"))}open(){this.opened=!0,window.addEventListener("keydown",this.handleKeydown),document.body.classList.add("no-scroll");const e=this.updateComplete||this.requestUpdate();e&&e.then?e.then(()=>{const e=this.shadowRoot.querySelector("[autofocus]")||firstFocusable(this.shadowRoot);e&&e.focus()}):setTimeout(()=>{const e=this.shadowRoot.querySelector("[autofocus]")||firstFocusable(this.shadowRoot);e&&e.focus()},0)}close(){this.opened=!1,this.blur(),this.closeCallback(),window.removeEventListener("keydown",this.handleKeydown),document.body.classList.remove("no-scroll")}toggle(){this.opened?this.close():this.open()}focus(){const e=firstFocusable(this.shadowRoot);e&&(this.previousFocus=document.activeElement,e.focus())}blur(){this.previousFocus&&this.previousFocus.focus()}hasTitle(){return!!this.querySelector('[slot="title"]')}static styles=css`
|
|
2
2
|
:host {
|
|
3
3
|
position: fixed;
|
|
4
4
|
top: 0;
|
|
@@ -75,14 +75,15 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
75
75
|
padding: var(--spacer_h);
|
|
76
76
|
}
|
|
77
77
|
`;render(){return html`
|
|
78
|
-
<button id="overlay" aria-label="Close the Dialog" @click=${this.handleClick}></button>
|
|
78
|
+
<button id="overlay" type="button" aria-label="Close the Dialog" @click=${this.handleClick}></button>
|
|
79
79
|
<div id="wrapper">
|
|
80
80
|
<k-focus-capture>
|
|
81
|
-
<
|
|
81
|
+
<form
|
|
82
82
|
id="dialog"
|
|
83
83
|
role="dialog"
|
|
84
84
|
aria-modal="true"
|
|
85
85
|
aria-labelledby="title"
|
|
86
|
+
@submit=${this.handleSubmit}
|
|
86
87
|
>
|
|
87
88
|
<div
|
|
88
89
|
id="header"
|
|
@@ -92,29 +93,29 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
92
93
|
<slot name="title"></slot>
|
|
93
94
|
</div>
|
|
94
95
|
${this.closeBtn?html`
|
|
95
|
-
<button id="close" @click=${this.handleClick}>
|
|
96
|
+
<button id="close" type="button" @click=${this.handleClick}>
|
|
96
97
|
<k-icon name="close"></k-icon>
|
|
97
98
|
</button>
|
|
98
99
|
`:""}
|
|
99
100
|
</div>
|
|
100
101
|
<div id="body">
|
|
101
|
-
<slot></slot>
|
|
102
|
+
<slot @keydown=${this.handleSlotKeydown}></slot>
|
|
102
103
|
</div>
|
|
103
104
|
${this.cancelText||this.confirmText?html`
|
|
104
105
|
<div id="footer">
|
|
105
106
|
${this.cancelText?html`
|
|
106
|
-
<button id="cancel" class="${this.cancelClasses}" @click=${this.handleClick}>
|
|
107
|
+
<button id="cancel" type="button" class="${this.cancelClasses}" @click=${this.handleClick}>
|
|
107
108
|
${this.cancelText}
|
|
108
109
|
</button>
|
|
109
110
|
`:""}
|
|
110
111
|
${this.confirmText?html`
|
|
111
|
-
<button id="confirm" class="${this.confirmClasses}"
|
|
112
|
+
<button id="confirm" type="submit" class="${this.confirmClasses}">
|
|
112
113
|
${this.confirmText}
|
|
113
114
|
</button>
|
|
114
115
|
`:""}
|
|
115
116
|
</div>
|
|
116
117
|
`:""}
|
|
117
|
-
</
|
|
118
|
+
</form>
|
|
118
119
|
</k-focus-capture>
|
|
119
120
|
</div>
|
|
120
121
|
`}static create(e="",t={}){!1!==t.closeExisting&&document.querySelectorAll("k-dialog").forEach(e=>e.close());const{removeOnClose:o=!0,closeCallback:s=()=>{},title:i="",titleClasses:l="pyh px m0"}=t,a=new Dialog;if(Object.assign(a,{opened:!0,...t,closeCallback:(...e)=>{o&&a.remove(),s(...e)}}),i){const e=document.createElement("h5");e.slot="title",e.className=l,i instanceof HTMLElement?e.appendChild(i):e.innerHTML=i,a.appendChild(e)}if(e instanceof HTMLElement||e instanceof DocumentFragment)a.appendChild(e);else if(e){if(/<[^>]+>/.test(e))a.innerHTML+=e;else{const t=document.createElement("p");t.className="p",t.textContent=e,a.appendChild(t)}}return t.width&&a.style.setProperty("--width",t.width),t.minWidth&&a.style.setProperty("--min_width",t.minWidth),t.maxWidth&&a.style.setProperty("--max_width",t.maxWidth),t.height&&a.style.setProperty("--height",t.height),t.minHeight&&a.style.setProperty("--min_height",t.minHeight),t.maxHeight&&a.style.setProperty("--max_height",t.maxHeight),document.body.appendChild(a),a.open(),a}static confirm(e,t,o={}){return Dialog.create(e,{title:o.title||"Confirm",closeBtn:!1,overlayClose:!1,disableKeyboardClose:!0,confirmText:"Yes",confirmClasses:"success ml",confirmAction:()=>t(!0),cancelText:"No",cancelClasses:"danger",cancelAction:()=>t(!1),...o})}static alert(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Alert",closeCallback:t,cancelText:"Ok",...o})}static error(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Error",titleClasses:"pyh px m0 tc-danger",closeCallback:t,cancelText:"Ok",...o})}static success(e,t=()=>{},o={}){return Dialog.create(e,{title:o.title||"Success",titleClasses:"pyh px m0 tc-success",closeCallback:t,cancelText:"Ok",...o})}}customElements.define("k-dialog",Dialog);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import{html,css}from"../lit-all.min.js";import ShadowComponent from"./ShadowComponent.js";import formatCode from"../utils/formatCode.js";import debounce from"../utils/debounce.js";export default class HtmlEditor extends ShadowComponent{static formAssociated=!0;static properties={name:{type:String,reflect:!0},value:{type:String,reflect:!0},selection:{type:Object,state:!0},mode:{type:String,reflect:!0},hasTopToolbar:{type:Boolean,state:!0},hasBottomToolbar:{type:Boolean,state:!0}};constructor(){super(),this.internals=this.attachInternals(),this.name="",this.value="",this.selection=null,this.cursor=null,this.mode="visual",this.hasTopToolbar=!1,this.hasBottomToolbar=!1,this.skipSync=!1,this.savedSelection=null,this.debouncedDispatchChange=debounce(()=>{this.value=this.editorEl.innerHTML},300)}connectedCallback(){super.connectedCallback(),this.hasAttribute("value")&&(this.value=this.getAttribute("value")),this.slotObserver=new MutationObserver(()=>{this.updateToolbarVisibility()}),this.slotObserver.observe(this,{childList:!0,subtree:!0}),this.updateToolbarVisibility()}disconnectedCallback(){super.disconnectedCallback(),this.slotObserver?.disconnect(),this.boundUpdateSelection&&(this.shadowRoot.removeEventListener("selectionchange",this.boundUpdateSelection),this.editorEl&&(this.editorEl.removeEventListener("mouseup",this.boundUpdateSelection),this.editorEl.removeEventListener("keyup",this.boundUpdateSelection),this.editorEl.removeEventListener("focus",this.boundUpdateSelection)))}updateToolbarVisibility(){const e=Array.from(this.children).filter(e=>"toolbar-top"===e.getAttribute("slot")),t=Array.from(this.children).filter(e=>"toolbar-bottom"===e.getAttribute("slot"));this.hasTopToolbar=e.length>0,this.hasBottomToolbar=t.length>0}updated(e){super.updated(e),e.has("value")&&(this.syncContent(),this.updateFormValue(),this.dispatchEvent(new CustomEvent("change",{detail:{value:this.value},bubbles:!0}))),e.has("mode")&&(this.syncContent(),this.dispatchEvent(new CustomEvent("mode-changed",{detail:{mode:this.mode},bubbles:!0})))}firstUpdated(){this.editorEl=this.shadowRoot.querySelector(".editor"),this.textareaEl=this.shadowRoot.querySelector("textarea"),this.value&&this.syncContent(),this.boundUpdateSelection=this.updateSelection.bind(this),this.shadowRoot.addEventListener("selectionchange",this.boundUpdateSelection),this.editorEl.addEventListener("mouseup",this.boundUpdateSelection),this.editorEl.addEventListener("keyup",this.boundUpdateSelection),this.editorEl.addEventListener("focus",this.boundUpdateSelection),this.editorEl.addEventListener("keydown",this.handleTableNavigation),this.dispatchEvent(new CustomEvent("ready",{detail:{value:this.value},bubbles:!0}))}updateFormValue(){this.internals.setFormValue(this.getValue())}formResetCallback(){this.value=""}formStateRestoreCallback(e){this.value=e}handleTableNavigation=e=>{if("Tab"!==e.key&&"Enter"!==e.key)return;if("visual"!==this.mode)return;const t=this.shadowRoot.getSelection()||window.getSelection();if(!t.rangeCount)return;let n=t.getRangeAt(0).startContainer;n.nodeType===Node.TEXT_NODE&&(n=n.parentElement);const o=n.closest("td, th");if(o)if(e.preventDefault(),"Tab"===e.key){const n=o.parentElement,i=Array.from(n.cells),r=i.indexOf(o);if(e.shiftKey){let e=i[r-1];if(!e){const t=n.previousElementSibling;t&&(e=t.cells[t.cells.length-1])}if(e){const n=document.createRange();n.selectNodeContents(e),n.collapse(!1),t.removeAllRanges(),t.addRange(n),e.focus()}}else{let e=i[r+1];if(!e){const t=n.nextElementSibling;t&&(e=t.cells[0])}if(e){const n=document.createRange();n.selectNodeContents(e),n.collapse(!1),t.removeAllRanges(),t.addRange(n),e.focus()}}}else if("Enter"===e.key){const n=o.parentElement,i=Array.from(n.cells).indexOf(o);if(e.shiftKey){const e=n.previousElementSibling;if(e&&e.cells[i]){const n=e.cells[i],o=document.createRange();o.selectNodeContents(n),o.collapse(!1),t.removeAllRanges(),t.addRange(o),n.focus()}}else{const e=n.nextElementSibling;if(e&&e.cells[i]){const n=e.cells[i],o=document.createRange();o.selectNodeContents(n),o.collapse(!1),t.removeAllRanges(),t.addRange(o),n.focus()}else{const e=o.closest("table");if(e){const n=document.createElement("p");n.innerHTML="<br>",e.nextSibling?e.parentNode.insertBefore(n,e.nextSibling):e.parentNode.appendChild(n);const o=document.createRange();o.setStart(n,0),o.setEnd(n,0),t.removeAllRanges(),t.addRange(o),n.focus()}}}}};updateSelection=()=>{if("visual"!==this.mode)return void(this.selection=null);const e=this.shadowRoot.getSelection()||window.getSelection();if(!e.rangeCount)return void(this.selection=null);const t=e.getRangeAt(0),n=this.editorEl.contains(t.startContainer)||this.editorEl===t.startContainer,o=this.editorEl.contains(t.endContainer)||this.editorEl===t.endContainer;if(!n||!o)return void(this.selection=null);const i=t.toString();t.collapsed?(this.selection=null,this.cursor={container:t.startContainer,offset:t.startOffset}):(this.cursor=null,this.selection={startContainer:t.startContainer,startOffset:t.startOffset,endContainer:t.endContainer,endOffset:t.endOffset,text:i,collapsed:!1})};handleEditorInput=()=>{this.debouncedDispatchChange(),this.dispatchEvent(new CustomEvent("input",{detail:{value:this.editorEl.innerHTML}}))};handleTextareaInput=e=>{"code"===this.mode&&(this.value=e.target.value)};handleEditorPaste=e=>{e.preventDefault();const t=e.clipboardData.getData("text/plain");document.execCommand("insertText",!1,t)};handleEditorBlur=()=>{if("visual"===this.mode){const e=this.shadowRoot.getSelection()||window.getSelection();if(e.rangeCount>0){const t=e.getRangeAt(0);this.editorEl.contains(t.commonAncestorContainer)&&(this.savedSelection={startContainer:t.startContainer,startOffset:t.startOffset,endContainer:t.endContainer,endOffset:t.endOffset,collapsed:t.collapsed})}const t=this.cleanupHtml(this.editorEl.innerHTML);t!==this.value&&(this.value=t,this.syncContent())}};setMode(e){return["visual","code"].includes(e)&&("visual"===this.mode&&"code"===e&&(this.value=this.cleanupHtml(this.editorEl.innerHTML)),this.mode=e),this}toggleMode(){const e="visual"===this.mode?"code":"visual";return this.setMode(e),this}getValue(){if("visual"===this.mode){return(this.editorEl?this.editorEl.innerHTML:this.value).replace(/\u200B/g,"")}return this.value}setValue(e){return this.value=e,this.syncContent(),this}clear(){return this.value="",this.syncContent(),this}cleanupHtml(e){const t=document.createElement("div");t.innerHTML=e;const n=(e,t)=>{e.querySelectorAll(t).forEach(n=>{let o=n.parentElement;for(;o&&o!==e;){if(o.tagName.toLowerCase()===t){for(;n.firstChild;)n.parentNode.insertBefore(n.firstChild,n);n.parentNode.removeChild(n);break}o=o.parentElement}})};return["code","a","span","strong","em","b","i","u","s"].forEach(e=>n(t,e)),["pre","div","p","h1","h2","h3","h4","h5","h6","blockquote"].forEach(e=>n(t,e)),t.querySelectorAll("*").forEach(e=>{if(!e.hasAttribute("style"))return;const t=e.style,n=["inherit","rgba(0, 0, 0, 0)","transparent","initial","unset"];["font-size","font-family","background-color","line-height","font-weight","font-style"].forEach(e=>{const o=t.getPropertyValue(e);o&&n.some(e=>o.includes(e))&&t.removeProperty(e)}),0===t.length&&e.removeAttribute("style")}),(e=>{e.querySelectorAll("span").forEach(e=>{if(!e.className&&!e.id&&!e.hasAttribute("style")){for(;e.firstChild;)e.parentNode.insertBefore(e.firstChild,e);e.parentNode.removeChild(e)}})})(t),(e=>{const t=document.createTreeWalker(e,NodeFilter.SHOW_TEXT,null),n=[];for(;t.nextNode();)n.push(t.currentNode);n.forEach(e=>{e.textContent=e.textContent.replace(/\u00A0/g," ")})})(t),t.innerHTML}bold(){return this.execCommand("bold"),this}italic(){return this.execCommand("italic"),this}underline(){return this.execCommand("underline"),this}strikethrough(){return this.execCommand("strikeThrough"),this}orderedList(){return this.execCommand("insertOrderedList"),this}unorderedList(){return this.execCommand("insertUnorderedList"),this}alignLeft(){return this.execCommand("justifyLeft"),this}alignCenter(){return this.execCommand("justifyCenter"),this}alignRight(){return this.execCommand("justifyRight"),this}alignJustify(){return this.execCommand("justifyFull"),this}setTextColor(e){return this.execCommand("foreColor",e),this}removeTextColor(){return this.execCommand("removeFormat"),this}setTextBackgroundColor(e){return this.execCommand("backColor",e),this}removeTextBackgroundColor(){const e=this.shadowRoot.getSelection();if(!e||0===e.rangeCount)return this;const t=e.getRangeAt(0);if(t.collapsed)return this;const n=t.extractContents(),o=document.createTreeWalker(n,NodeFilter.SHOW_ELEMENT,null),i=e=>{e.style&&(e.style.backgroundColor="",e.style.cssText||e.removeAttribute("style"))};let r;for(;r=o.nextNode();)i(r);return i(n.firstChild),t.insertNode(n),this.editorEl.dispatchEvent(new Event("input",{bubbles:!0})),this}removeFormat(){if("visual"!==this.mode)return this;if(this.selection)return this.execCommand("removeFormat"),this;const e=this.shadowRoot.getSelection()||window.getSelection();if(!e.rangeCount)return this;let t=e.getRangeAt(0).startContainer;t.nodeType===Node.TEXT_NODE&&(t=t.parentElement);const n=t.closest(["B","I","U","S","STRONG","EM","CODE","MARK","SUB","SUP","SPAN"].map(e=>e.toLowerCase()).join(","));if(n&&this.editorEl.contains(n)){const t=n.textContent,o=document.createTextNode(t);n.replaceWith(o);const i=document.createRange();i.setStart(o,t.length),i.setEnd(o,t.length),e.removeAllRanges(),e.addRange(i),this.value=this.editorEl.innerHTML}return this}formatBlock(e){return this.execCommand("formatBlock",e),this}insertHTML(e){return this.execCommand("insertHTML",e),this}insertTable(e,t,n=!1,o=null){if("visual"!==this.mode)return this;const i=this.getValueWithSelectionMarkers();let r=i.html;const s=document.createElement("table");if(s.style.cssText="border-collapse: collapse; width: 100%;",n){const e=document.createElement("thead"),n=document.createElement("tr");for(let e=0;e<t;e++){const t=document.createElement("th");t.style.cssText="border: 1px solid var(--border-color, #ccc); padding: 0.5rem; text-align: left; background-color: var(--background-secondary, #f5f5f5);",o&&o[0]&&void 0!==o[0][e]?t.innerHTML=o[0][e]:t.innerHTML=`Header ${e+1}`,n.appendChild(t)}e.appendChild(n),s.appendChild(e)}const l=document.createElement("tbody"),a=n?1:0;for(let n=0;n<e;n++){const e=document.createElement("tr");for(let i=0;i<t;i++){const t=document.createElement("td");t.style.cssText="border: 1px solid var(--border-color, #ccc); padding: 0.5rem;",o&&o[n+a]&&void 0!==o[n+a][i]?t.innerHTML=o[n+a][i]:t.innerHTML="",e.appendChild(t)}l.appendChild(e)}s.appendChild(l);const d=document.createElement("div");d.appendChild(s);const c=d.innerHTML,h=document.createElement("p");h.innerHTML="<br>";const u=c+h.outerHTML;i.hasCursor?r=r.replace("",u+""):i.hasSelection?(r=r.replace(i.selectionStart,"").replace(i.selectionEnd,""),r+=u):r+=u;const m={hasCursor:i.hasCursor,hasSelection:!1,cursorMarker:""};return this.setValueFromSelectionMarkers(r,m),this}insertElementAtCursor(e,t=!0){if("visual"!==this.mode)return this;const n=this.getValueWithSelectionMarkers();let o=n.html;t&&(e.textContent=""+(e.textContent||"")+"");const i=e.outerHTML;if(n.hasCursor)o=o.replace("",i);else{const t=["code","a","span","strong","em","b","i","u","s","mark","sub","sup"],n=e.tagName.toLowerCase();t.includes(n)?o=o+"<p>"+i+"</p>":o+=i}const r={hasCursor:!1,hasSelection:t,selectionStart:"",selectionEnd:"",selectedText:e.textContent||""};return this.setValueFromSelectionMarkers(o,r),this}replaceSelectionWithElement(e,t=!0){if("visual"!==this.mode)return this;const n=this.getValueWithSelectionMarkers();if(!n.hasSelection)return this;let o=n.html;t&&(e.textContent=""+e.textContent+"");const i=e.outerHTML,r=""+n.selectedText+"";o=o.replace(r,i);const s={hasCursor:!1,hasSelection:t,selectionStart:"",selectionEnd:"",selectedText:n.selectedText};return this.setValueFromSelectionMarkers(o,s),this}getSelection(){if("visual"!==this.mode)return null;this.editorEl.focus();const e=window.getSelection();if(!e.rangeCount)return null;const t=e.getRangeAt(0);return this.editorEl.contains(t.commonAncestorContainer)?{text:e.toString(),html:t.cloneContents().textContent?(new XMLSerializer).serializeToString(t.cloneContents()):"",range:t,selection:e}:null}getSelectedText(){const e=this.getSelection();return e?e.text:""}getSelectedHTML(){const e=this.getSelection();return e?e.html:""}setSelection(e,t,n,o){if("visual"!==this.mode)return this;this.editorEl.focus();const i=window.getSelection(),r=document.createRange();return r.setStart(e,t),r.setEnd(n,o),i.removeAllRanges(),i.addRange(r),this}selectAll(){return"visual"===this.mode?this.execCommand("selectAll"):this.textareaEl.select(),this}replaceSelection(e){if("visual"!==this.mode)return this;const t=this.getSelection();if(!t)return this;t.range.deleteContents();const n=t.range.createContextualFragment(e);return t.range.insertNode(n),this.value=this.editorEl.innerHTML,this}deleteSelection(){if("visual"===this.mode)this.execCommand("delete");else{const e=this.textareaEl.selectionStart,t=this.textareaEl.selectionEnd;this.textareaEl.value=this.textareaEl.value.substring(0,e)+this.textareaEl.value.substring(t),this.value=this.textareaEl.value}return this}getTextPosition(e,t){const n=document.createTreeWalker(e,NodeFilter.SHOW_TEXT,null);let o=0;for(;n.nextNode();){const e=n.currentNode;if(t.contains(e))return o;o+=e.textContent.length}return o}wrapSelection(e,t,n=null){if("visual"!==this.mode)return this;let o;if(n)o=n;else{const e=window.getSelection();if(!e.rangeCount||e.isCollapsed)return this;const t=e.getRangeAt(0);if(!this.editorEl.contains(t.commonAncestorContainer))return this;o=e.toString()}if(!o)return this;this.editorEl.focus();const i=e.match(/<([a-zA-Z]+)/);if(!i)return this;const r=i[1],s=document.createElement("div");s.innerHTML=this.getValue();const l=s.textContent.indexOf(o);if(-1===l)return this;const a=document.createTreeWalker(s,NodeFilter.SHOW_TEXT|NodeFilter.SHOW_ELEMENT,null);let d=0,c=null,h=0,u=null,m=0;const f=[];for(;a.nextNode();){const e=a.currentNode;if(e.nodeType===Node.ELEMENT_NODE){if(e.tagName.toLowerCase()===r){const t=this.getTextPosition(s,e),n=t+e.textContent.length,i=l+o.length;!(n<=l||t>=i)&&f.push(e)}continue}const t=e.textContent.length,n=d,i=d+t;if(!c&&i>l&&(c=e,h=l-n),i>=l+o.length){u=e,m=l+o.length-n;break}d+=t}if(f.length>0)f.forEach(e=>{const t=e.parentNode,n="pre"===e.tagName.toLowerCase(),o=[],i=e=>{o.push(e),Array.from(e.children).forEach(e=>i(e))};if(i(e),n){const n=document.createElement("p");for(;e.firstChild;)n.appendChild(e.firstChild);t.replaceChild(n,e)}else o.reverse().forEach(e=>{if(e.parentNode){for(;e.firstChild;)e.parentNode.insertBefore(e.firstChild,e);e.parentNode.removeChild(e)}})});else if(c&&u){const n=document.createRange();n.setStart(c,h),n.setEnd(u,m);const o=n.extractContents(),i=document.createElement("div");i.innerHTML=e+t;const l=i.firstChild;let a=l;for(;a.firstChild&&a.firstChild.nodeType===Node.ELEMENT_NODE;)a=a.firstChild;if(a.appendChild(o),n.insertNode(l),"pre"===r){let e=l.parentNode;for(;e&&e!==s;){if(e.tagName&&"p"===e.tagName.toLowerCase()){const t=[];let n=l.nextSibling;for(;n;){const e=n.nextSibling;t.push(n),n=e}if(e.parentNode.insertBefore(l,e.nextSibling),t.length>0&&t.some(e=>e.textContent.trim())){const e=document.createElement("p");t.forEach(t=>e.appendChild(t)),l.parentNode.insertBefore(e,l.nextSibling)}break}e=e.parentNode}}}return this.setValue(s.innerHTML),this.editorEl.focus(),setTimeout(()=>{const e=this.editorEl.textContent.indexOf(o);if(-1===e)return;const t=document.createTreeWalker(this.editorEl,NodeFilter.SHOW_TEXT,null);let n=0,i=null,r=0,s=null,l=0;for(;t.nextNode();){const a=t.currentNode,d=a.textContent.length,c=n,h=n+d;if(null===i&&h>e&&(i=a,r=e-c),h>=e+o.length){s=a,l=e+o.length-c;break}n+=d}if(i&&s){const e=document.createRange();e.setStart(i,r),e.setEnd(s,l);const t=window.getSelection();t.removeAllRanges(),t.addRange(e)}},0),this}insertAtCursor(e){return this.insertHTML(e),this}createLink(e){return this.execCommand("createLink",e),this}unlink(){return this.execCommand("unlink"),this}insertImage(e){return this.execCommand("insertImage",e),this}undo(){return this.execCommand("undo"),this}redo(){return this.execCommand("redo"),this}execCommand(e,t=null){"visual"===this.mode&&(this.editorEl.focus(),document.execCommand(e,!1,t),this.value=this.editorEl.innerHTML)}captureSelection(){if("visual"!==this.mode)return null;const e=window.getSelection();if(!e.rangeCount)return null;const t=e.getRangeAt(0);if(!this.editorEl.contains(t.commonAncestorContainer))return null;const n=t.toString();return t.collapsed?null:{startContainer:t.startContainer,startOffset:t.startOffset,endContainer:t.endContainer,endOffset:t.endOffset,text:n,collapsed:t.collapsed}}restoreSavedSelection(){if(!this.savedSelection)return!1;const e=this.shadowRoot.getSelection()||window.getSelection(),t=document.createRange();try{return t.setStart(this.savedSelection.startContainer,this.savedSelection.startOffset),t.setEnd(this.savedSelection.endContainer,this.savedSelection.endOffset),e.removeAllRanges(),e.addRange(t),!0}catch(e){return this.savedSelection=null,!1}}clearSavedSelection(){this.savedSelection=null}getValueWithSelectionMarkers(){if("visual"!==this.mode)return{html:this.value,hasCursor:!1,hasSelection:!1};const e=this.shadowRoot.getSelection()||window.getSelection();if(!e.rangeCount&&!this.restoreSavedSelection())return{html:this.editorEl.innerHTML,hasCursor:!1,hasSelection:!1};if(!e.rangeCount)return{html:this.editorEl.innerHTML,hasCursor:!1,hasSelection:!1};const t=e.getRangeAt(0);if(!this.editorEl.contains(t.commonAncestorContainer))return{html:this.editorEl.innerHTML,hasCursor:!1,hasSelection:!1};const n=t.toString();if(t.collapsed){const e=document.createTextNode(""),n=document.createRange();n.setStart(t.startContainer,t.startOffset),n.insertNode(e);const o=this.editorEl.innerHTML;return e.remove(),{html:o,hasCursor:!0,hasSelection:!1,cursorMarker:"",selectedText:""}}{const e=document.createTextNode(""),o=document.createTextNode(""),i=document.createRange();i.setStart(t.endContainer,t.endOffset),i.insertNode(o),i.setStart(t.startContainer,t.startOffset),i.insertNode(e);const r=this.editorEl.innerHTML;return e.remove(),o.remove(),{html:r,hasCursor:!1,hasSelection:!0,selectionStart:"",selectionEnd:"",selectedText:n}}}setValueFromSelectionMarkers(e,t){if("visual"!==this.mode)return this;const n=t.cursorMarker||"",o=t.selectionStart||"",i=t.selectionEnd||"";if(this.editorEl.innerHTML=e,t.hasCursor){const e=document.createTreeWalker(this.editorEl,NodeFilter.SHOW_TEXT,null);for(;e.nextNode();){const t=e.currentNode,o=t.textContent.indexOf(n);if(-1!==o){t.textContent=t.textContent.replace(n,"");const e=document.createRange();e.setStart(t,o),e.setEnd(t,o);const i=this.shadowRoot.getSelection()||window.getSelection();i.removeAllRanges(),i.addRange(e);break}}}else if(t.hasSelection){const e=document.createTreeWalker(this.editorEl,NodeFilter.SHOW_TEXT,null);let t=null,n=0,r=null,s=0;for(;e.nextNode();){const l=e.currentNode,a=l.textContent.indexOf(o);-1!==a&&(t=l,n=a,l.textContent=l.textContent.replace(o,""));const d=l.textContent.indexOf(i);if(-1!==d&&(r=l,s=d,l.textContent=l.textContent.replace(i,"")),t&&r)break}if(t&&r){const e=document.createRange();e.setStart(t,n),e.setEnd(r,s);const o=this.shadowRoot.getSelection()||window.getSelection();o.removeAllRanges(),o.addRange(e)}}return this.editorEl.focus(),this}syncContent(){if(this.editorEl&&this.textareaEl&&!this.skipSync)if("visual"===this.mode)this.editorEl.innerHTML!==this.value&&(this.editorEl.innerHTML=this.value);else{const e=formatCode(this.value);this.textareaEl.value!==e&&(this.textareaEl.value=e)}}static styles=css`
|
|
2
|
+
:host {
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: 0;
|
|
6
|
+
height: 300px;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.toolbar-top,
|
|
10
|
+
.toolbar-bottom {
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-wrap: wrap;
|
|
13
|
+
align-items: center;
|
|
14
|
+
gap: 0;
|
|
15
|
+
background: var(--bg-secondary);
|
|
16
|
+
min-height: 40px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.editor-container {
|
|
20
|
+
position: relative;
|
|
21
|
+
flex: 1;
|
|
22
|
+
min-height: 0;
|
|
23
|
+
overflow: hidden;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.editor,
|
|
27
|
+
textarea {
|
|
28
|
+
width: 100%;
|
|
29
|
+
height: 100%;
|
|
30
|
+
padding: 1rem;
|
|
31
|
+
border: 1px solid var(--border-color);
|
|
32
|
+
background: var(--bg-primary);
|
|
33
|
+
color: var(--text-primary);
|
|
34
|
+
font-family: inherit;
|
|
35
|
+
font-size: inherit;
|
|
36
|
+
line-height: 1.5;
|
|
37
|
+
overflow: auto;
|
|
38
|
+
box-sizing: border-box;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.editor {
|
|
42
|
+
outline: none;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.editor:focus {
|
|
46
|
+
border-color: var(--primary-color);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
textarea {
|
|
50
|
+
resize: none;
|
|
51
|
+
font-family: monospace;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
textarea:focus {
|
|
55
|
+
outline: none;
|
|
56
|
+
border-color: var(--primary-color);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.editor[hidden],
|
|
60
|
+
textarea[hidden] {
|
|
61
|
+
display: none;
|
|
62
|
+
}
|
|
63
|
+
`;render(){return html`
|
|
64
|
+
${this.hasTopToolbar?html`
|
|
65
|
+
<div class="toolbar-top bb">
|
|
66
|
+
<slot name="toolbar-top"></slot>
|
|
67
|
+
</div>
|
|
68
|
+
`:""}
|
|
69
|
+
|
|
70
|
+
<div class="editor-container">
|
|
71
|
+
<div
|
|
72
|
+
class="editor"
|
|
73
|
+
contenteditable="true"
|
|
74
|
+
?hidden=${"visual"!==this.mode}
|
|
75
|
+
@input=${this.handleEditorInput}
|
|
76
|
+
@paste=${this.handleEditorPaste}
|
|
77
|
+
@blur=${this.handleEditorBlur}
|
|
78
|
+
></div>
|
|
79
|
+
|
|
80
|
+
<textarea
|
|
81
|
+
?hidden=${"code"!==this.mode}
|
|
82
|
+
@input=${this.handleTextareaInput}
|
|
83
|
+
></textarea>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
${this.hasBottomToolbar?html`
|
|
87
|
+
<div class="toolbar-bottom bt">
|
|
88
|
+
<slot name="toolbar-bottom"></slot>
|
|
89
|
+
</div>
|
|
90
|
+
`:""}
|
|
91
|
+
`}}customElements.define("k-html-editor",HtmlEditor);
|
package/dist/components/Icon.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import ShadowComponent from"./ShadowComponent.js";import{html,css,unsafeHTML}from"../lit-all.min.js";const cache={},getIconByPath=async t=>(cache[t]||(cache[t]=new Promise(async(n
|
|
1
|
+
import ShadowComponent from"./ShadowComponent.js";import{html,css,unsafeHTML}from"../lit-all.min.js";const cache={},getIconByPath=async t=>(cache[t]||(cache[t]=new Promise(async(e,n)=>{const i=(new AbortController).signal;try{const n=await fetch(t,{signal:i});200===n.status?e(await n.text()):e(null)}catch(t){"AbortError"!==t.name&&n(t)}}).catch(()=>null)),await cache[t]),getIconByName=t=>{const e=async e=>{const n=e.endsWith("/")?e.slice(0,-1):e;return getIconByPath(`${n}/${t}.svg`)};return new Promise(async(t,n)=>{let i;const o=window.kempo?.pathsToIcons||["./icons","/icons","../icons","../../icons"];for(let t=0;t<o.length&&!i;t++)try{i=await e(o[t])}catch(t){}t(i||null)})};export default class Icon extends ShadowComponent{static properties={src:{type:String,reflect:!0},name:{type:String,reflect:!0},rotation:{type:String,reflect:!0},direction:{type:String,reflect:!0},animation:{type:String,reflect:!0},iconContent:{type:String}};constructor(t=""){super(),this.src="",this.name=t,this.rotation="",this.direction="",this.animation="",this.iconContent=""}updated(t){super.updated(),(t.has("src")||t.has("name"))&&this.loadIcon()}async loadIcon(){let t;if(this.src?t=await getIconByPath(this.src):this.name&&(t=await getIconByName(this.name)),t)this.iconContent=this.fixSVG(t),this.requestUpdate();else{const t=this.innerHTML.trim();t?(this.iconContent=this.fixSVG(t),this.requestUpdate()):(this.iconContent=window.kempo?.fallbackIcon||'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M480-79q-16 0-30.5-6T423-102L102-423q-11-12-17-26.5T79-480q0-16 6-31t17-26l321-321q12-12 26.5-17.5T480-881q16 0 31 5.5t26 17.5l321 321q12 11 17.5 26t5.5 31q0 16-5.5 30.5T858-423L537-102q-11 11-26 17t-31 6Zm0-80 321-321-321-321-321 321 321 321Zm-40-281h80v-240h-80v240Zm40 120q17 0 28.5-11.5T520-360q0-17-11.5-28.5T480-400q-17 0-28.5 11.5T440-360q0 17 11.5 28.5T480-320Zm0-160Z"/></svg>',this.requestUpdate())}}fixSVG(t){if(!t)return t;const e=(new DOMParser).parseFromString(t,"image/svg+xml").querySelector("svg");return e?(e.removeAttribute("width"),e.removeAttribute("height"),e.querySelectorAll("path, rect, circle").forEach(t=>{t.setAttribute("fill","currentColor")}),(new XMLSerializer).serializeToString(e)):t}getRotationDegrees(){if(this.rotation)return this.rotation;return{down:"90",left:"180",up:"270"}[this.direction]||"0"}static styles=css`
|
|
2
2
|
:host {
|
|
3
3
|
display: inline-block;
|
|
4
4
|
vertical-align: bottom;
|
|
@@ -39,4 +39,4 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css,unsafeHTML}fro
|
|
|
39
39
|
0%, 100% { transform: scale(1); }
|
|
40
40
|
50% { transform: scale(1.2); }
|
|
41
41
|
}
|
|
42
|
-
`;render(){const t=this.getRotationDegrees(),
|
|
42
|
+
`;render(){const t=this.getRotationDegrees(),e="0"!==t?`--icon-rotation: ${t}deg;`:"";return this.iconContent?html`<div style="${e}">${unsafeHTML(this.iconContent)}</div>`:html`<div style="${e}"><slot></slot></div>`}}window.customElements.define("k-icon",Icon);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{LitElement}from"../lit-all.min.js";export default class ShadowComponent extends LitElement{#e;connectedCallback(){super.connectedCallback(),this.#e=new MutationObserver(()=>{
|
|
1
|
+
import{LitElement}from"../lit-all.min.js";export default class ShadowComponent extends LitElement{#e;connectedCallback(){super.connectedCallback(),this.#e=new MutationObserver(()=>{this.childrenUpdated(),this.requestUpdate()}),this.#e.observe(this,{childList:!0})}disconnectedCallback(){super.disconnectedCallback(),this.#e?.disconnect()}childrenUpdated(){}createRenderRoot(){const e=this.attachShadow({mode:"open"}),t=document.createElement("link");t.rel="stylesheet",t.href=window.kempo?.pathToStylesheet||"https://cdn.jsdelivr.net/npm/kempo-css@1.3.2/dist/kempo.min.css",e.appendChild(t);const n=this.constructor.styles;if(n){const t=document.createElement("style");Array.isArray(n)?t.textContent=n.map(e=>e.cssText||e).join("\n"):t.textContent=n.cssText||n,e.appendChild(t)}const s=document.createElement("div");return s.style.display="contents",e.appendChild(s),s}}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";import{boolTrueFalse}from"../utils/propConverters.js";import"./FocusCapture.js";import"./Icon.js";export default class SideMenu extends ShadowComponent{static properties={opened:{type:Boolean,reflect:!0},overlayClose:{type:Boolean,reflect:!0,attribute:"overlay-close",converter:boolTrueFalse},side:{type:String,reflect:!0}};constructor(){super(),this.opened=!1,this.overlayClose=!0,this.side="left"}overlayClick=()=>{this.overlayClose&&this.close()};updated(e){super.updated(e),e.has("opened")&&(this.opened?(document.body.classList.add("no-scroll"),this.dispatchEvent(new CustomEvent("change",{detail:"open"})),this.dispatchEvent(new CustomEvent("open"))):(document.body.classList.remove("no-scroll"),this.dispatchEvent(new CustomEvent("change",{detail:"close"})),this.dispatchEvent(new CustomEvent("close"))))}open(){this.opened=!0}close(){this.opened=!1}toggle(){this.opened?this.close():this.open(),this.dispatchEvent(new CustomEvent("toggle"))}render(){return html`
|
|
1
|
+
import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";import{boolTrueFalse}from"../utils/propConverters.js";import"./FocusCapture.js";import"./Icon.js";export default class SideMenu extends ShadowComponent{static properties={opened:{type:Boolean,reflect:!0},overlayClose:{type:Boolean,reflect:!0,attribute:"overlay-close",converter:boolTrueFalse},escClose:{type:Boolean,reflect:!0,attribute:"esc-close",converter:boolTrueFalse},side:{type:String,reflect:!0}};constructor(){super(),this.opened=!1,this.overlayClose=!0,this.escClose=!0,this.side="left"}overlayClick=()=>{this.overlayClose&&this.close()};handleKeyDown=e=>{this.escClose&&"Escape"===e.key&&this.close()};updated(e){super.updated(e),e.has("opened")&&(this.opened?(document.body.classList.add("no-scroll"),document.addEventListener("keydown",this.handleKeyDown),this.dispatchEvent(new CustomEvent("change",{detail:"open"})),this.dispatchEvent(new CustomEvent("open"))):(document.body.classList.remove("no-scroll"),document.removeEventListener("keydown",this.handleKeyDown),this.dispatchEvent(new CustomEvent("change",{detail:"close"})),this.dispatchEvent(new CustomEvent("close"))))}open(){this.opened=!0}close(){this.opened=!1}toggle(){this.opened?this.close():this.open(),this.dispatchEvent(new CustomEvent("toggle"))}render(){return html`
|
|
2
2
|
<k-focus-capture>
|
|
3
3
|
<div id="container">
|
|
4
4
|
<button id="overlay" @click=${this.overlayClick}>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-all.min.js";import"./Icon.js";class SidePanel extends ShadowComponent{static properties={collapsed:{type:Boolean,reflect:!0},side:{type:String,reflect:!0}};constructor(){super(),this.collapsed=!1,this.side="left"}toggleClick=()=>this.toggle();updated(e){if(super.updated(e),e.has("collapsed")){const e=this.collapsed?"collapse":"expand";this.dispatchEvent(new CustomEvent(e)),this.dispatchEvent(new CustomEvent("change",{detail:e})),window.dispatchEvent(new CustomEvent("side-panel-change",{detail:{collapsed:this.collapsed,width:this.collapsed?"3.5rem":"16rem",side:this.side}}))}}expand=()=>this.collapsed=!1;collapse=()=>this.collapsed=!0;toggle(){this.collapsed=!this.collapsed,this.dispatchEvent(new CustomEvent("toggle"))}render(){return html`
|
|
1
|
+
import ShadowComponent from"./ShadowComponent.js";import{html,css,nothing}from"../lit-all.min.js";import"./Icon.js";class SidePanel extends ShadowComponent{static properties={collapsed:{type:Boolean,reflect:!0},side:{type:String,reflect:!0}};constructor(){super(),this.collapsed=!1,this.side="left"}toggleClick=()=>this.toggle();updated(e){if(super.updated(e),e.has("collapsed")){const e=this.collapsed?"collapse":"expand";this.dispatchEvent(new CustomEvent(e)),this.dispatchEvent(new CustomEvent("change",{detail:e})),window.dispatchEvent(new CustomEvent("side-panel-change",{detail:{collapsed:this.collapsed,width:this.collapsed?"3.5rem":"16rem",side:this.side}}))}}expand=()=>this.collapsed=!1;collapse=()=>this.collapsed=!0;toggle(){this.collapsed=!this.collapsed,this.dispatchEvent(new CustomEvent("toggle"))}render(){return html`
|
|
2
2
|
<div id="header">
|
|
3
3
|
<slot name="logo"></slot>
|
|
4
4
|
<button id="toggle" @click=${this.toggleClick} aria-label="${this.collapsed?"Expand panel":"Collapse panel"}">
|
|
@@ -12,7 +12,6 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
12
12
|
:host {
|
|
13
13
|
--bg: var(--c_bg);
|
|
14
14
|
--width-expanded: 16rem;
|
|
15
|
-
--width-collapsed: 3.5rem;
|
|
16
15
|
--transition-duration: var(--animation_ms, 256ms);
|
|
17
16
|
display: block;
|
|
18
17
|
position: fixed;
|
|
@@ -26,7 +25,7 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
26
25
|
z-index: 1000;
|
|
27
26
|
}
|
|
28
27
|
:host([collapsed]) {
|
|
29
|
-
width:
|
|
28
|
+
width: auto;
|
|
30
29
|
}
|
|
31
30
|
:host([side="right"]) {
|
|
32
31
|
left: auto;
|
|
@@ -52,9 +51,7 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
52
51
|
transition: opacity var(--transition-duration);
|
|
53
52
|
}
|
|
54
53
|
:host([collapsed]) ::slotted([slot="logo"]) {
|
|
55
|
-
|
|
56
|
-
width: 0;
|
|
57
|
-
overflow: hidden;
|
|
54
|
+
display: none;
|
|
58
55
|
}
|
|
59
56
|
#toggle {
|
|
60
57
|
flex-shrink: 0;
|
|
@@ -79,17 +76,24 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
79
76
|
display: flex;
|
|
80
77
|
flex-direction: column;
|
|
81
78
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
:host([collapsed]) #content {
|
|
80
|
+
align-items: flex-start;
|
|
81
|
+
}
|
|
82
|
+
:host(:not([collapsed])) #content {
|
|
83
|
+
/* scrollbar-gutter: stable; */
|
|
84
|
+
}
|
|
85
|
+
`}class SidePanelItem extends ShadowComponent{static properties={icon:{type:String},href:{type:String},active:{type:Boolean,reflect:!0},collapsed:{type:Boolean,reflect:!0},"no-expand":{type:Boolean,attribute:"no-expand"},"hide-when-collapsed":{type:Boolean,attribute:"hide-when-collapsed"}};constructor(){super(),this.icon="",this.href="#",this.active=!1,this.collapsed=!1,this["no-expand"]=!1,this["hide-when-collapsed"]=!1}connectedCallback(){super.connectedCallback(),this.panel=this.closest("k-side-panel"),this.panel&&(this.collapsed=this.panel.collapsed,this.panel.addEventListener("collapse",this.handleCollapse),this.panel.addEventListener("expand",this.handleExpand))}disconnectedCallback(){super.disconnectedCallback(),this.panel&&(this.panel.removeEventListener("collapse",this.handleCollapse),this.panel.removeEventListener("expand",this.handleExpand))}handleCollapse=()=>{this.collapsed=!0,this.requestUpdate()};handleExpand=()=>{this.collapsed=!1,this.requestUpdate()};handleClick=e=>{this.collapsed&&!this["no-expand"]&&this.panel&&(e.preventDefault(),this.panel.expand())};render(){return html`
|
|
86
|
+
<a href="${this.href}" class="item ${this.active?"active bg-primary":""}" @click=${this.handleClick}>
|
|
87
|
+
${this.icon?html`<k-icon name="${this.icon}"></k-icon>`:this.collapsed?html`<k-icon name="dot"></k-icon>`:nothing}
|
|
88
|
+
${this.collapsed?nothing:html`<span class="label"><slot></slot></span>`}
|
|
88
89
|
</a>
|
|
89
90
|
`}static styles=css`
|
|
90
91
|
:host {
|
|
91
92
|
display: block;
|
|
92
93
|
}
|
|
94
|
+
:host([collapsed][hide-when-collapsed]) {
|
|
95
|
+
display: none;
|
|
96
|
+
}
|
|
93
97
|
.item {
|
|
94
98
|
display: flex;
|
|
95
99
|
align-items: center;
|
|
@@ -102,6 +106,8 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
102
106
|
transition: background var(--animation_ms), color var(--animation_ms);
|
|
103
107
|
white-space: nowrap;
|
|
104
108
|
}
|
|
109
|
+
:host([collapsed]) .item {
|
|
110
|
+
}
|
|
105
111
|
.item:hover {
|
|
106
112
|
background: var(--c_bg_hover);
|
|
107
113
|
}
|
|
@@ -119,18 +125,16 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
119
125
|
min-width: 0;
|
|
120
126
|
overflow: hidden;
|
|
121
127
|
text-overflow: ellipsis;
|
|
122
|
-
opacity: 1;
|
|
123
|
-
transition: opacity var(--animation_ms);
|
|
124
128
|
}
|
|
125
|
-
|
|
126
|
-
opacity: 0;
|
|
127
|
-
width: 0;
|
|
128
|
-
}
|
|
129
|
-
`}class SidePanelLabel extends ShadowComponent{constructor(){super(),this.collapsed=!1}connectedCallback(){super.connectedCallback(),this.panel=this.closest("k-side-panel"),this.panel&&(this.collapsed=this.panel.collapsed,this.panel.addEventListener("collapse",this.handleCollapse),this.panel.addEventListener("expand",this.handleExpand))}disconnectedCallback(){super.disconnectedCallback(),this.panel&&(this.panel.removeEventListener("collapse",this.handleCollapse),this.panel.removeEventListener("expand",this.handleExpand))}handleCollapse=()=>{this.collapsed=!0,this.requestUpdate()};handleExpand=()=>{this.collapsed=!1,this.requestUpdate()};render(){return this.collapsed?html`<hr>`:html`<div class="label"><slot></slot></div>`}static styles=css`
|
|
129
|
+
`}class SidePanelLabel extends ShadowComponent{static properties={collapsed:{type:Boolean,reflect:!0}};constructor(){super(),this.collapsed=!1}connectedCallback(){super.connectedCallback(),this.panel=this.closest("k-side-panel"),this.panel&&(this.collapsed=this.panel.collapsed,this.panel.addEventListener("collapse",this.handleCollapse),this.panel.addEventListener("expand",this.handleExpand))}disconnectedCallback(){super.disconnectedCallback(),this.panel&&(this.panel.removeEventListener("collapse",this.handleCollapse),this.panel.removeEventListener("expand",this.handleExpand))}handleCollapse=()=>{this.collapsed=!0,this.requestUpdate()};handleExpand=()=>{this.collapsed=!1,this.requestUpdate()};render(){return this.collapsed?html`<hr>`:html`<div class="label"><slot></slot></div>`}static styles=css`
|
|
130
130
|
:host {
|
|
131
131
|
display: block;
|
|
132
132
|
margin: var(--spacer_h) 0;
|
|
133
133
|
}
|
|
134
|
+
:host([collapsed]) {
|
|
135
|
+
margin: 0 var(--spacer_h);
|
|
136
|
+
align-self: stretch;
|
|
137
|
+
}
|
|
134
138
|
.label {
|
|
135
139
|
padding: 0 var(--spacer);
|
|
136
140
|
font-size: 0.75rem;
|
|
@@ -144,12 +148,15 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
144
148
|
border-top: 1px solid var(--c_border);
|
|
145
149
|
margin: var(--spacer_h) var(--spacer);
|
|
146
150
|
}
|
|
147
|
-
|
|
151
|
+
:host([collapsed]) hr {
|
|
152
|
+
margin: var(--spacer_h) 0;
|
|
153
|
+
}
|
|
154
|
+
`}class SidePanelMenu extends ShadowComponent{static properties={icon:{type:String},label:{type:String},open:{type:Boolean,reflect:!0},collapsed:{type:Boolean,reflect:!0},"no-expand":{type:Boolean,attribute:"no-expand"},"hide-when-collapsed":{type:Boolean,attribute:"hide-when-collapsed"}};constructor(){super(),this.icon="",this.label="",this.open=!1,this.collapsed=!1,this["no-expand"]=!1,this["hide-when-collapsed"]=!1}connectedCallback(){super.connectedCallback(),this.panel=this.closest("k-side-panel"),this.panel&&(this.collapsed=this.panel.collapsed,this.panel.addEventListener("collapse",this.handleCollapse),this.panel.addEventListener("expand",this.handleExpand))}disconnectedCallback(){super.disconnectedCallback(),this.panel&&(this.panel.removeEventListener("collapse",this.handleCollapse),this.panel.removeEventListener("expand",this.handleExpand))}handleCollapse=()=>{this.collapsed=!0,this.open=!1,this.requestUpdate()};handleExpand=()=>{this.collapsed=!1,this.requestUpdate()};toggleMenu=()=>{this.collapsed&&!this["no-expand"]&&this.panel?this.panel.expand():this.collapsed||(this.open=!this.open)};render(){return html`
|
|
148
155
|
<div class="menu-container">
|
|
149
|
-
<button class="menu-header ${this.open?"open":""}" @click=${this.toggleMenu}>
|
|
150
|
-
${this.icon?html`<k-icon name="${this.icon}"></k-icon>`:""}
|
|
151
|
-
|
|
152
|
-
${this.collapsed?
|
|
156
|
+
<button class="no-btn menu-header ${this.open?"open":""}" @click=${this.toggleMenu}>
|
|
157
|
+
${this.icon?html`<k-icon name="${this.icon}"></k-icon>`:this.collapsed?html`<k-icon name="dot"></k-icon>`:nothing}
|
|
158
|
+
${this.collapsed?nothing:html`<span class="label">${this.label}</span>`}
|
|
159
|
+
${this.collapsed?nothing:html`<k-icon class="chevron" name="chevron" direction="${this.open?"down":"right"}"></k-icon>`}
|
|
153
160
|
</button>
|
|
154
161
|
<div class="menu-content ${this.open&&!this.collapsed?"open":""}">
|
|
155
162
|
<slot></slot>
|
|
@@ -159,6 +166,9 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
159
166
|
:host {
|
|
160
167
|
display: block;
|
|
161
168
|
}
|
|
169
|
+
:host([collapsed][hide-when-collapsed]) {
|
|
170
|
+
display: none;
|
|
171
|
+
}
|
|
162
172
|
.menu-container {
|
|
163
173
|
margin: 0;
|
|
164
174
|
}
|
|
@@ -181,6 +191,9 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
181
191
|
white-space: nowrap;
|
|
182
192
|
transition: background var(--animation_ms);
|
|
183
193
|
}
|
|
194
|
+
:host([collapsed]) .menu-header {
|
|
195
|
+
width: auto;
|
|
196
|
+
}
|
|
184
197
|
.menu-header:hover {
|
|
185
198
|
background: var(--c_bg_hover);
|
|
186
199
|
}
|
|
@@ -192,12 +205,6 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
192
205
|
min-width: 0;
|
|
193
206
|
overflow: hidden;
|
|
194
207
|
text-overflow: ellipsis;
|
|
195
|
-
opacity: 1;
|
|
196
|
-
transition: opacity var(--animation_ms);
|
|
197
|
-
}
|
|
198
|
-
.label.hidden {
|
|
199
|
-
opacity: 0;
|
|
200
|
-
width: 0;
|
|
201
208
|
}
|
|
202
209
|
.chevron {
|
|
203
210
|
transition: transform var(--animation_ms);
|
|
@@ -208,6 +215,9 @@ import ShadowComponent from"./ShadowComponent.js";import{html,css}from"../lit-al
|
|
|
208
215
|
transition: max-height var(--animation_ms);
|
|
209
216
|
padding-left: calc(var(--spacer_h) * 2);
|
|
210
217
|
}
|
|
218
|
+
:host([collapsed]) .menu-content {
|
|
219
|
+
padding-left: 0;
|
|
220
|
+
}
|
|
211
221
|
.menu-content.open {
|
|
212
222
|
max-height: 500px;
|
|
213
223
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import HtmlEditorControl from"./HtmlEditorControl.js";import{html,css}from"../../lit-all.min.js";import"../Icon.js";export default class AlignCenter extends HtmlEditorControl{static properties={editorMode:{type:String,state:!0}};static styles=[HtmlEditorControl.styles,css`
|
|
2
|
+
:host {
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
}
|
|
5
|
+
`];connectedCallback(){super.connectedCallback(),this.updateEditorMode(),this.editor?.addEventListener("mode-changed",()=>this.updateEditorMode())}handleClick=()=>{this.editor&&this.editor.alignCenter()};updateEditorMode(){this.editor&&(this.editorMode=this.editor.mode)}render(){return this.hidden="code"===this.editorMode,html`
|
|
6
|
+
<button class="${this.buttonClasses}" @click="${this.handleClick}">
|
|
7
|
+
<slot name="icon">
|
|
8
|
+
<k-icon name="format_align_center"></k-icon>
|
|
9
|
+
</slot>
|
|
10
|
+
<slot></slot>
|
|
11
|
+
</button>
|
|
12
|
+
`}}customElements.define("k-hec-align-center",AlignCenter);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import HtmlEditorControl from"./HtmlEditorControl.js";import{html,css}from"../../lit-all.min.js";import"../Icon.js";export default class AlignJustify extends HtmlEditorControl{static properties={editorMode:{type:String,state:!0}};static styles=[HtmlEditorControl.styles,css`
|
|
2
|
+
:host {
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
}
|
|
5
|
+
`];connectedCallback(){super.connectedCallback(),this.updateEditorMode(),this.editor?.addEventListener("mode-changed",()=>this.updateEditorMode())}handleClick=()=>{this.editor&&this.editor.alignJustify()};updateEditorMode(){this.editor&&(this.editorMode=this.editor.mode)}render(){return this.hidden="code"===this.editorMode,html`
|
|
6
|
+
<button class="${this.buttonClasses}" @click="${this.handleClick}">
|
|
7
|
+
<slot name="icon">
|
|
8
|
+
<k-icon name="format_align_justify"></k-icon>
|
|
9
|
+
</slot>
|
|
10
|
+
<slot></slot>
|
|
11
|
+
</button>
|
|
12
|
+
`}}customElements.define("k-hec-align-justify",AlignJustify);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import HtmlEditorControl from"./HtmlEditorControl.js";import{html,css}from"../../lit-all.min.js";import"../Icon.js";export default class AlignLeft extends HtmlEditorControl{static properties={editorMode:{type:String,state:!0}};static styles=[HtmlEditorControl.styles,css`
|
|
2
|
+
:host {
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
}
|
|
5
|
+
`];connectedCallback(){super.connectedCallback(),this.updateEditorMode(),this.editor?.addEventListener("mode-changed",()=>this.updateEditorMode())}handleClick=()=>{this.editor&&this.editor.alignLeft()};updateEditorMode(){this.editor&&(this.editorMode=this.editor.mode)}render(){return this.hidden="code"===this.editorMode,html`
|
|
6
|
+
<button class="${this.buttonClasses}" @click="${this.handleClick}">
|
|
7
|
+
<slot name="icon">
|
|
8
|
+
<k-icon name="format_align_left"></k-icon>
|
|
9
|
+
</slot>
|
|
10
|
+
<slot></slot>
|
|
11
|
+
</button>
|
|
12
|
+
`}}customElements.define("k-hec-align-left",AlignLeft);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import HtmlEditorControl from"./HtmlEditorControl.js";import{html,css}from"../../lit-all.min.js";import"../Icon.js";export default class AlignRight extends HtmlEditorControl{static properties={editorMode:{type:String,state:!0}};static styles=[HtmlEditorControl.styles,css`
|
|
2
|
+
:host {
|
|
3
|
+
display: inline-flex;
|
|
4
|
+
}
|
|
5
|
+
`];connectedCallback(){super.connectedCallback(),this.updateEditorMode(),this.editor?.addEventListener("mode-changed",()=>this.updateEditorMode())}handleClick=()=>{this.editor&&this.editor.alignRight()};updateEditorMode(){this.editor&&(this.editorMode=this.editor.mode)}render(){return this.hidden="code"===this.editorMode,html`
|
|
6
|
+
<button class="${this.buttonClasses}" @click="${this.handleClick}">
|
|
7
|
+
<slot name="icon">
|
|
8
|
+
<k-icon name="format_align_right"></k-icon>
|
|
9
|
+
</slot>
|
|
10
|
+
<slot></slot>
|
|
11
|
+
</button>
|
|
12
|
+
`}}customElements.define("k-hec-align-right",AlignRight);
|