kempo 2.2.0 → 2.4.0

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.
Files changed (38) hide show
  1. package/dist/components/ContentSlider.js +1 -0
  2. package/dist/components/DirectoryViewer.js +1 -1
  3. package/dist/components/ShowMore.js +1 -1
  4. package/dist/components/ThemeSwitcher.js +1 -1
  5. package/dist/index.js +1 -1
  6. package/dist/kempo-hljs.css +1 -1
  7. package/dist/utils/element.js +1 -1
  8. package/docs/components/_template.html +2 -0
  9. package/docs/components/content-slider.html +185 -0
  10. package/docs/components/directory-viewer.html +3 -3
  11. package/docs/components/show-more.html +1 -2
  12. package/docs/kempo/components/ContentSlider.js +1 -0
  13. package/docs/kempo/components/DirectoryViewer.js +1 -1
  14. package/docs/kempo/components/ShowMore.js +1 -1
  15. package/docs/kempo/components/ThemeSwitcher.js +1 -1
  16. package/docs/kempo/index.js +1 -1
  17. package/docs/kempo/kempo-hljs.css +1 -1
  18. package/docs/kempo/utils/element.js +1 -1
  19. package/docs/nav-1.inc.html +3 -2
  20. package/docs/nav.inc.html +3 -4
  21. package/docs/search.json +9 -1
  22. package/icons/arrow-back.svg +1 -0
  23. package/icons/arrow-forward.svg +1 -0
  24. package/icons/drawing2.svg +124 -0
  25. package/icons/mode-auto.svg +1 -0
  26. package/icons/tools.svg +1 -0
  27. package/package.json +1 -1
  28. package/src/components/ContentSlider.js +192 -0
  29. package/src/components/DirectoryViewer.js +13 -8
  30. package/src/components/LazyComponent.js +8 -5
  31. package/src/components/ShowMore.js +23 -3
  32. package/src/components/ThemeSwitcher.js +21 -3
  33. package/src/kempo-hljs.css +1 -0
  34. package/src/utils/element.js +5 -2
  35. package/src/utils/raf.js +10 -0
  36. /package/docs/components/{lazycomponent.html → lazy-component.html} +0 -0
  37. /package/icons/{dark-mode.svg → mode-dark.svg} +0 -0
  38. /package/icons/{light-mode.svg → mode-light.svg} +0 -0
@@ -0,0 +1 @@
1
+ <svg viewBox="0 -960 960 960" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M 440 -920 L 440 -760 L 520 -760 L 520 -920 L 440 -920 z M 818.67969 -885.5332 L 583.66602 -651.38281 C 553.04363 -670.31258 518.55019 -680 480 -680 C 424.66678 -680 377.49992 -660.49992 338.5 -621.5 C 299.50008 -582.50008 280 -535.33322 280 -480 C 280 -441.71314 289.5643 -407.43184 308.23633 -376.96484 L 97.058594 -166.5625 L 168.59375 -92.332031 L 263.80078 -187.18945 C 267.09506 -183.63709 270.46257 -180.11555 273.9375 -176.64062 C 343.93736 -106.64077 428.9377 -71.640625 528.9375 -71.640625 C 628.9373 -71.640625 713.93764 -106.64077 783.9375 -176.64062 C 853.93736 -246.64049 888.9375 -331.64082 888.9375 -431.64062 C 888.9375 -440.97395 888.60417 -450.14064 887.9375 -459.14062 C 887.27083 -468.14062 886.27083 -476.97398 884.9375 -485.64062 C 865.60421 -458.30735 840.60411 -436.47393 809.9375 -420.14062 C 779.27089 -403.80733 745.60409 -395.64062 708.9375 -395.64062 C 648.93762 -395.64062 597.93742 -416.64072 555.9375 -458.64062 C 552.62172 -461.95641 549.47084 -465.3433 546.42188 -468.77344 L 890.21484 -811.30273 L 818.67969 -885.5332 z M 212 -806 L 155 -747 L 256 -650 L 308 -706 L 212 -806 z M 480 -600 C 495.83397 -600 510.50253 -597.28065 524.08008 -592.01562 L 367.83594 -436.34375 C 362.67843 -449.80488 360 -464.32853 360 -480 C 360 -513.33327 371.66671 -541.66671 395 -565 C 418.33329 -588.33329 446.66673 -600 480 -600 z M 40 -520 L 40 -440 L 200 -440 L 200 -520 L 40 -520 z M 489.73047 -412.28906 C 492.87534 -408.86757 496.09809 -405.48004 499.4375 -402.14062 C 557.10405 -344.47408 626.93766 -315.64062 708.9375 -315.64062 C 722.27081 -315.64062 735.60419 -316.64064 748.9375 -318.64062 C 762.27081 -320.64062 775.60419 -323.3073 788.9375 -326.64062 C 767.60421 -274.64074 733.60407 -232.4739 686.9375 -200.14062 C 640.27093 -167.80736 587.60405 -151.64062 528.9375 -151.64062 C 451.60432 -151.64062 385.60406 -178.97407 330.9375 -233.64062 C 327.48999 -237.08813 324.17746 -240.59082 320.95312 -244.13086 L 489.73047 -412.28906 z " /></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960"><path fill="currentColor" d="M756-120 537-339l84-84 219 219-84 84Zm-552 0-84-84 276-276-68-68-28 28-51-51v82l-28 28-121-121 28-28h82l-50-50 142-142q20-20 43-29t47-9q24 0 47 9t43 29l-92 92 50 50-28 28 68 68 90-90q-4-11-6.5-23t-2.5-24q0-59 40.5-99.5T701-841q15 0 28.5 3t27.5 9l-99 99 72 72 99-99q7 14 9.5 27.5T841-701q0 59-40.5 99.5T701-561q-12 0-24-2t-23-7L204-120Z"/></svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kempo",
3
- "version": "2.2.0",
3
+ "version": "2.4.0",
4
4
  "type": "module",
5
5
  "description": "A web component library",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,192 @@
1
+ import LazyComponent from './LazyComponent.js';
2
+ import {
3
+ onEvent,
4
+ offEvent,
5
+ dispatchEvent
6
+ } from '../utils/element.js';
7
+
8
+ const content = Symbol(),
9
+ prevClickHandler = Symbol(),
10
+ nextClickHandler = Symbol(),
11
+ keydownHandler = Symbol();
12
+ export default class ContentSlider extends LazyComponent {
13
+ constructor(_content = [], {
14
+ index = 0,
15
+ controls = true,
16
+ globalControls = false,
17
+ keyboardControls = true,
18
+ loop = false
19
+ } = {}){
20
+ super();
21
+
22
+ /* Private Members */
23
+ this[content] = [..._content];
24
+
25
+ /* Private Methods */
26
+ this[prevClickHandler] = () => this.previous();
27
+ this[nextClickHandler] = () => this.next();
28
+ this[keydownHandler] = (event) => {
29
+ if(event.code === 'ArrowLeft'){
30
+ event.preventDefault();
31
+ dispatchEvent(this, 'keyleft');
32
+ this.previous();
33
+ } else if(event.code === 'ArrowRight'){
34
+ event.preventDefault();
35
+ dispatchEvent(this, 'keyright');
36
+ this.next();
37
+ }
38
+ }
39
+
40
+ /* Init */
41
+ this.registerAttributes({
42
+ index,
43
+ controls,
44
+ keyboardControls,
45
+ globalControls,
46
+ loop
47
+ });
48
+ this.tabIndex = 0;
49
+ }
50
+
51
+ /* Lifecycle Callback */
52
+ connectedCallback(){
53
+ super.connectedCallback();
54
+ this[content] = [...this.querySelectorAll(':scope > *')];
55
+ }
56
+ async render(force){
57
+ if(await super.render(force)){
58
+ if(this.keyboardControls){ // add keyboard controls
59
+ if(this.globalControls){
60
+ onEvent(window, 'keydown', this[keydownHandler]);
61
+ } else {
62
+ onEvent(this, 'keydown', this[keydownHandler]);
63
+ onEvent(this.shadowRoot, 'keydown', this[keydownHandler]);
64
+ }
65
+ }
66
+ onEvent(this.shadowRoot.getElementById('prev'), 'click', this[prevClickHandler]);
67
+ onEvent(this.shadowRoot.getElementById('next'), 'click', this[nextClickHandler]);
68
+ this.renderContent();
69
+ return true;
70
+ }
71
+ return false;
72
+ }
73
+ attributeChangedCallback(n, oV, nV){
74
+ super.attributeChangedCallback(n, oV, nV);
75
+ if(n === 'index' && oV !== nV){
76
+ const newIndex = parseInt(nV);
77
+ const validNew = Math.max(Math.min(this[content].length-1, newIndex), 0);
78
+ if(newIndex !== validNew){
79
+ this.index = validNew;
80
+ } else {
81
+ dispatchEvent(this, 'change', {
82
+ index: validNew
83
+ });
84
+ this.renderContent();
85
+ }
86
+ } else if(n === 'keyboard-controls' && oV !== nV){
87
+ if(this.keyboardControls){ // add keyboard controls
88
+ if(this.globalControls){
89
+ onEvent(window, 'keydown', this[keydownHandler]);
90
+ } else {
91
+ onEvent(this, 'keydown', this[keydownHandler]);
92
+ onEvent(this.shadowRoot, 'keydown', this[keydownHandler]);
93
+ }
94
+ } else { // remove keyboard controls
95
+ offEvent(this.globalControls?window:this.shadowRoot, 'keydown', this[keydownHandler]);
96
+ }
97
+ }
98
+ }
99
+ renderContent(){
100
+ this.innerHTML = '';
101
+ this.appendChild(this[content][this.index]);
102
+ }
103
+ disconnectedCallback(){
104
+ super.disconnectedCallback();
105
+ offEvent(this.shadowRoot.getElementById('prev'), 'click', this[prevClickHandler]);
106
+ offEvent(this.shadowRoot.getElementById('next'), 'click', this[nextClickHandler]);
107
+ offEvent(window, 'keydown', this[keydownHandler]);
108
+ offEvent(this.shadowRoot, 'keydown', this[keydownHandler]);
109
+ offEvent(this, 'keydown', this[keydownHandler]);
110
+ }
111
+
112
+ /* Public Methods */
113
+ previous(){
114
+ let newIndex = this.index - 1;
115
+ if(this.loop){
116
+ if(newIndex < 0) newIndex = this[content].length - 1;
117
+ }
118
+ dispatchEvent(this, 'previous', {index: newIndex});
119
+ this.index = newIndex;
120
+ }
121
+ next(){
122
+ let newIndex = this.index + 1;
123
+ if(this.loop){
124
+ if(newIndex >= this[content].length) newIndex = 0;
125
+ }
126
+ dispatchEvent(this, 'next', {index: newIndex});
127
+ this.index = newIndex;
128
+ }
129
+ goto(newIndex){
130
+ dispatchEvent(this, 'goto', {index: newIndex});
131
+ this.index = newIndex;
132
+ }
133
+
134
+ /* Shadow DOM */
135
+ get shadowTemplate(){
136
+ return /*html*/`
137
+ <div id="content">
138
+ ${super.shadowTemplate}
139
+ </div>
140
+ <div id="controls">
141
+ <button
142
+ id="prev"
143
+ class="no-btn"
144
+ >
145
+ <slot name="prev">
146
+ <k-icon name="chevron-left"></k-icon>
147
+ </slot>
148
+ </button>
149
+ <button
150
+ id="next"
151
+ class="no-btn"
152
+ >
153
+ <slot name="next">
154
+ <k-icon name="chevron-right"></k-icon>
155
+ </slot>
156
+ </button>
157
+ </div>
158
+ `;
159
+ }
160
+ get shadowStyles(){
161
+ return /*css*/`
162
+ ${super.shadowStyles}
163
+ :host {
164
+ display: block;
165
+ position: relative;
166
+ outline: none;
167
+ }
168
+ #prev,
169
+ #next {
170
+ position: absolute;
171
+ top: 50%;
172
+ transform: translateY(-50%);
173
+ font-size: 2rem;
174
+ }
175
+ #next {
176
+ right: 0;
177
+ }
178
+ :host(:not([controls="true"])) #controls {
179
+ display: none;
180
+ }
181
+ `;
182
+ }
183
+
184
+ /* Static Members */
185
+ static observedAttributes = [
186
+ ...LazyComponent.observedAttributes,
187
+ 'index',
188
+ 'keyboard-controls',
189
+ 'global-controls'
190
+ ];
191
+ }
192
+ window.customElements.define('k-content-slider', ContentSlider);
@@ -3,12 +3,13 @@ import Component from './Component.js';
3
3
  import './Icon.js';
4
4
  import {
5
5
  onEvent,
6
- offEvent
6
+ offEvent,
7
+ dispatchEvent
7
8
  } from '../utils/element.js';
8
9
  import watchDirectoryHandle from '../utils/watchDirectoryHandle.js';
9
10
 
10
11
  const handle = Symbol(),
11
- selectDirectoryClickHandler = Symbol(),
12
+ loadDirectoryClickHandler = Symbol(),
12
13
  openToggleClickHandler = Symbol(),
13
14
  fileSelectedHandler = Symbol(),
14
15
  watchId = Symbol(),
@@ -24,7 +25,7 @@ export default class DirectoryViewer extends LazyComponent {
24
25
  this[filters] = [];
25
26
 
26
27
  /* Private Methods */
27
- this[selectDirectoryClickHandler] = () => this.selectDirectory();
28
+ this[loadDirectoryClickHandler] = () => this.loadDirectory();
28
29
  this[openToggleClickHandler] = () => {
29
30
  if(!this.root){
30
31
  this.toggleOpen();
@@ -51,7 +52,7 @@ export default class DirectoryViewer extends LazyComponent {
51
52
  async render(force){
52
53
  if(await super.render(force)){
53
54
  onEvent(this.shadowRoot, 'fileselected', this[fileSelectedHandler]);
54
- onEvent(this.shadowRoot.getElementById('selectDirectory'), 'click', this[selectDirectoryClickHandler]);
55
+ onEvent(this.shadowRoot.getElementById('loadDirectory'), 'click', this[loadDirectoryClickHandler]);
55
56
  onEvent(this.shadowRoot.getElementById('openToggle'), 'click', this[openToggleClickHandler]);
56
57
  this.renderDirectory();
57
58
  return true;
@@ -95,7 +96,7 @@ export default class DirectoryViewer extends LazyComponent {
95
96
  disconnectedCallback(){
96
97
  super.disconnectedCallback();
97
98
  offEvent(this.shadowRoot, 'fileselected', this[fileSelectedHandler]);
98
- offEvent(this.shadowRoot.getElementById('selectDirectory'), 'click', this[selectDirectoryClickHandler]);
99
+ offEvent(this.shadowRoot.getElementById('loadDirectory'), 'click', this[loadDirectoryClickHandler]);
99
100
  offEvent(this.shadowRoot.getElementById('openToggle'), 'click', this[openToggleClickHandler]);
100
101
  }
101
102
  attributeChangedCallback(n, oV, nV){
@@ -119,11 +120,15 @@ export default class DirectoryViewer extends LazyComponent {
119
120
 
120
121
 
121
122
  /* Public Methods */
122
- async selectDirectory(){
123
+ async loadDirectory(){
123
124
  if(window.showDirectoryPicker){
124
125
  this[handle] = await window.showDirectoryPicker();
125
126
  if(this[handle]){
126
127
  this.hasHandle = true;
128
+ dispatchEvent(this, 'directoryloaded', {
129
+ dirHandle: this[handle],
130
+ dirComponent: this
131
+ });
127
132
  this.renderDirectory();
128
133
  }
129
134
  }
@@ -200,7 +205,7 @@ export default class DirectoryViewer extends LazyComponent {
200
205
  get shadowTemplate(){
201
206
  return /*html*/`
202
207
  <button
203
- id="selectDirectory"
208
+ id="loadDirectory"
204
209
  >
205
210
  <slot name="selectButton">
206
211
  <k-icon name="folder-create"></k-icon> Select Directory
@@ -223,7 +228,7 @@ export default class DirectoryViewer extends LazyComponent {
223
228
  get shadowStyles(){
224
229
  return /*css*/`
225
230
  ${super.shadowStyles}
226
- :host([has-handle]) #selectDirectory,
231
+ :host([has-handle]) #loadDirectory,
227
232
  :host([opened]) #folder-closed,
228
233
  :host(:not([opened])) #folder-opened,
229
234
  :host(:not([has-handle])) #folder-closed,
@@ -1,6 +1,6 @@
1
1
  import Component from './Component.js';
2
2
  import { isInView } from '../utils/element.js';
3
-
3
+ import raf from '../utils/raf.js';
4
4
 
5
5
  export default class LazyComponent extends Component {
6
6
  constructor(shadowDetails){
@@ -18,21 +18,24 @@ export default class LazyComponent extends Component {
18
18
  async connectedCallback(){
19
19
  // Do not do super.connectedCallback() because it will render the component prematurely
20
20
  await this.renderSkelton(); // so that the skeleton height is rendered, which will give it the propert height so potentional LazyComponents below it will get out of the viewport as they normally would, before we then check if it is in View (which is delayed a few frames.
21
- if(await isInView(this)){
22
- await this.inViewCallback();
23
- }
21
+ raf(async ()=>{
22
+ if(await isInView(this)) await this.inViewCallback();
23
+ }, 2);
24
24
  }
25
25
  async inViewCallback(){
26
- await this.render();
26
+ return await this.render();
27
27
  }
28
28
  async outOfViewCallback(){
29
29
  if(this.unrender){
30
30
  await this.renderSkelton();
31
+ return true;
31
32
  }
33
+ return false;
32
34
  }
33
35
  async renderSkelton(){
34
36
  this.shadowRoot.innerHTML = `<link rel="stylesheet" href="${Component.pathToKempo}/kempo-styles.css" />${this.skeletonTemplate}<style>${this.shadowStyles}</style>`;
35
37
  this.rendered = false;
38
+ return true;
36
39
  }
37
40
  get skeletonTemplate(){
38
41
  return /*html*/`<div style="height: var(--skeleton_height, 1rem)"></div>`;
@@ -6,17 +6,37 @@ import {
6
6
  dispatchEvent
7
7
  } from '../utils/element.js';
8
8
 
9
+ const toggleClickHandler = Symbol();
9
10
  export default class ShowMore extends LazyComponent {
10
11
  constructor(){
11
12
  super();
12
13
 
14
+ this[toggleClickHandler] = () => this.toggle();
15
+
13
16
  this.registerAttribute('opened', false);
14
- this.registerProp('_toggleClickHandler', () => this.toggle());
15
17
  }
18
+
19
+ /* Lifecycle Callbacks */
16
20
  async render(force){
17
21
  await super.render(force);
18
- onEvent(this.shadowRoot.getElementById('toggle'), 'click', this._toggleClickHandler);
22
+ onEvent(this.shadowRoot.getElementById('toggle'), 'click', this[toggleClickHandler]);
23
+ }
24
+ disconnectedCallback(){
25
+ super.disconnectedCallback();
26
+ offEvent(this.shadowRoot.getElementById('toggle'), 'click', this[toggleClickHandler]);
19
27
  }
28
+ attributeChangedCallback(n, oV, nV){
29
+ super.attributeChangedCallback(n, oV, nV);
30
+ if(n === 'opened' && oV !== nV){
31
+ if(this.opened){
32
+ dispatchEvent(this, 'change opened');
33
+ } else {
34
+ dispatchEvent(this, 'change closed');
35
+ }
36
+ }
37
+ }
38
+
39
+ /* Public Methods */
20
40
  more(){
21
41
  this.opened = true;
22
42
  }
@@ -24,7 +44,7 @@ export default class ShowMore extends LazyComponent {
24
44
  this.opened = false;
25
45
  }
26
46
  toggle(){
27
- this.opened?this.less():this.more();
47
+ this.opened = !this.opened;
28
48
  }
29
49
 
30
50
  get shadowTemplate(){
@@ -15,7 +15,10 @@ export default class ThemeSwitcher extends Component {
15
15
  this.currentTheme = ThemeSwitcher.getCurrentTheme();
16
16
  }
17
17
  this[clickHandler] = () => {
18
- ThemeSwitcher.setTheme(ThemeSwitcher.getCurrentTheme()==='light'?'dark':'light');
18
+ const current = ThemeSwitcher.getCurrentTheme();
19
+ if(current === 'auto') ThemeSwitcher.setTheme('light');
20
+ if(current === 'light') ThemeSwitcher.setTheme('dark');
21
+ if(current === 'dark') ThemeSwitcher.setTheme('auto');
19
22
  }
20
23
  this.registerAttribute('currentTheme', ThemeSwitcher.getCurrentTheme());
21
24
  }
@@ -27,6 +30,10 @@ export default class ThemeSwitcher extends Component {
27
30
  }
28
31
  return false;
29
32
  }
33
+ disconnectedCallback(){
34
+ super.disconnectedCallback();
35
+ offEvent(this.shadowRoot.getElementById('toggle'), 'click', this[clickHandler]);
36
+ }
30
37
 
31
38
  get shadowTemplate(){
32
39
  return /*html*/`
@@ -34,13 +41,20 @@ export default class ThemeSwitcher extends Component {
34
41
  id="toggle"
35
42
  class="no-btn"
36
43
  >
44
+ <k-icon
45
+ id="autoMode"
46
+ name="mode-auto"
47
+ class="mode"
48
+ ></k-icon>
37
49
  <k-icon
38
50
  id="lightMode"
39
51
  name="light-mode"
52
+ class="mode"
40
53
  ></k-icon>
41
54
  <k-icon
42
55
  id="darkMode"
43
56
  name="dark-mode"
57
+ class="mode"
44
58
  ></k-icon>
45
59
  </button>
46
60
  `;
@@ -55,10 +69,14 @@ export default class ThemeSwitcher extends Component {
55
69
  #toggle {
56
70
  padding: var(--padding);
57
71
  }
58
- :host([current-theme="dark"]) #darkMode,
59
- :host([current-theme="light"]) #lightMode {
72
+ .mode {
60
73
  display: none;
61
74
  }
75
+ :host([current-theme="auto"]) #autoMode,
76
+ :host([current-theme="light"]) #lightMode,
77
+ :host([current-theme="dark"]) #darkMode {
78
+ display: block;
79
+ }
62
80
  `;
63
81
  }
64
82
 
@@ -18,6 +18,7 @@
18
18
  --c_deletion: #2b91af;
19
19
  --c_caret: black;
20
20
  }
21
+ [auto-theme="dark"]:not([theme="light"]),
21
22
  [theme="dark"] {
22
23
  --c_text: #DCDCDC;
23
24
  --c_keyword: #569CD6;
@@ -22,10 +22,13 @@ export const offEvent = (element, events, handler, scope = document) => {
22
22
  scope.querySelectorAll(element).forEach( el => offEvent(el, events, handler));
23
23
  }
24
24
  }
25
- export const dispatchEvent = (element, events, detail, scope = document) => {
25
+ export const dispatchEvent = (element, events, detail, {
26
+ scope = document,
27
+ bubbles = false
28
+ }={}) => {
26
29
  if(element instanceof EventTarget){
27
30
  events.toLowerCase().split(' ').forEach( event => {
28
- element.dispatchEvent(new CustomEvent(event, { detail } ));
31
+ element.dispatchEvent(new CustomEvent(event, { bubbles, detail } ));
29
32
  });
30
33
  } else if(element instanceof NodeList || element instanceof Array){
31
34
  element.forEach( el => dispatchEvent(el, events, handler));
@@ -0,0 +1,10 @@
1
+ const raf = (callback, frames = 1) => {
2
+ requestAnimationFrame(()=>{
3
+ if(frames === 1){
4
+ callback();
5
+ } else {
6
+ raf(callback, frames-1);
7
+ }
8
+ });
9
+ }
10
+ export default raf;
File without changes
File without changes