kempo 1.0.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 (194) hide show
  1. package/.gitattributes +2 -0
  2. package/LICENSE +21 -0
  3. package/README.md +2 -0
  4. package/dist/components/Card.js +1 -0
  5. package/dist/components/CodeEditor.js +1 -0
  6. package/dist/components/Component.js +1 -0
  7. package/dist/components/Dialog.js +1 -0
  8. package/dist/components/FocusCapture.js +1 -0
  9. package/dist/components/Icon.js +1 -0
  10. package/dist/components/Import.js +1 -0
  11. package/dist/components/LazyComponent.js +1 -0
  12. package/dist/components/ReactiveComponent.js +1 -0
  13. package/dist/components/ReactiveLazyComponent.js +1 -0
  14. package/dist/components/Resize.js +1 -0
  15. package/dist/components/Search.js +1 -0
  16. package/dist/components/ShowMore.js +1 -0
  17. package/dist/components/SideMenu.js +1 -0
  18. package/dist/components/Split.js +1 -0
  19. package/dist/components/Tabs.js +1 -0
  20. package/dist/components/ThemeSwitcher.js +1 -0
  21. package/dist/components/Timestamp.js +1 -0
  22. package/dist/components/WebSnippetEditor.js +1 -0
  23. package/dist/index.js +1 -0
  24. package/dist/kempo-hljs.css +1 -0
  25. package/dist/kempo-styles.css +1 -0
  26. package/dist/kempo-vars.css +1 -0
  27. package/dist/kempo.css +1 -0
  28. package/dist/kempo.js +1 -0
  29. package/dist/utils/cli.js +1 -0
  30. package/dist/utils/cookie.js +1 -0
  31. package/dist/utils/debounce.js +1 -0
  32. package/dist/utils/drag.js +1 -0
  33. package/dist/utils/element.js +1 -0
  34. package/dist/utils/formatTimestamp.js +1 -0
  35. package/dist/utils/fuzzyMatch.js +1 -0
  36. package/dist/utils/getPreferredTheme.js +1 -0
  37. package/dist/utils/loadCss.js +1 -0
  38. package/dist/utils/loadScript.js +1 -0
  39. package/dist/utils/object.js +1 -0
  40. package/dist/utils/string.js +1 -0
  41. package/dist/utils/toFunction.js +1 -0
  42. package/dist/utils/type.js +1 -0
  43. package/dist/utils/waitFrames.js +1 -0
  44. package/docs/components/_template.html +22 -0
  45. package/docs/components/card.html +35 -0
  46. package/docs/components/codeeditor.html +29 -0
  47. package/docs/components/component.html +88 -0
  48. package/docs/components/dialog.html +89 -0
  49. package/docs/components/icon.html +73 -0
  50. package/docs/components/import.html +34 -0
  51. package/docs/components/lazycomponent.html +50 -0
  52. package/docs/components/resize.html +107 -0
  53. package/docs/components/show-more.html +92 -0
  54. package/docs/components/sidemenu.html +97 -0
  55. package/docs/components/split.html +70 -0
  56. package/docs/components/tabs.html +33 -0
  57. package/docs/components/websnippeteditor.html +42 -0
  58. package/docs/index.html +17 -0
  59. package/docs/kempo/components/Card.js +1 -0
  60. package/docs/kempo/components/CodeEditor.js +1 -0
  61. package/docs/kempo/components/Collapse.js +1 -0
  62. package/docs/kempo/components/Component.js +1 -0
  63. package/docs/kempo/components/Dialog.js +1 -0
  64. package/docs/kempo/components/FocusCapture.js +1 -0
  65. package/docs/kempo/components/Icon.js +1 -0
  66. package/docs/kempo/components/Import.js +1 -0
  67. package/docs/kempo/components/LazyComponent.js +1 -0
  68. package/docs/kempo/components/ReactiveComponent.js +1 -0
  69. package/docs/kempo/components/ReactiveLazyComponent.js +1 -0
  70. package/docs/kempo/components/Resize.js +1 -0
  71. package/docs/kempo/components/Search.js +1 -0
  72. package/docs/kempo/components/ShowMore.js +1 -0
  73. package/docs/kempo/components/SideMenu.js +1 -0
  74. package/docs/kempo/components/Split.js +1 -0
  75. package/docs/kempo/components/Tabs.js +1 -0
  76. package/docs/kempo/components/ThemeSwitcher.js +1 -0
  77. package/docs/kempo/components/Timestamp.js +1 -0
  78. package/docs/kempo/components/WebSnippetEditor.js +1 -0
  79. package/docs/kempo/icons/arrow-down-double.svg +1 -0
  80. package/docs/kempo/icons/arrow-up-double.svg +1 -0
  81. package/docs/kempo/icons/close.svg +2 -0
  82. package/docs/kempo/icons/compare.svg +1 -0
  83. package/docs/kempo/icons/dark-mode.svg +1 -0
  84. package/docs/kempo/icons/delete.svg +1 -0
  85. package/docs/kempo/icons/filter-off.svg +1 -0
  86. package/docs/kempo/icons/filter.svg +1 -0
  87. package/docs/kempo/icons/light-mode.svg +1 -0
  88. package/docs/kempo/icons/menu.svg +1 -0
  89. package/docs/kempo/icons/pause.svg +1 -0
  90. package/docs/kempo/icons/play.svg +1 -0
  91. package/docs/kempo/icons/search.svg +1 -0
  92. package/docs/kempo/icons/settings.svg +1 -0
  93. package/docs/kempo/icons/storage.svg +1 -0
  94. package/docs/kempo/icons/trash-x.svg +1 -0
  95. package/docs/kempo/index.js +1 -0
  96. package/docs/kempo/kempo-hljs.css +1 -0
  97. package/docs/kempo/kempo-styles.css +1 -0
  98. package/docs/kempo/kempo-vars.css +1 -0
  99. package/docs/kempo/kempo.css +1 -0
  100. package/docs/kempo/kempo.js +1 -0
  101. package/docs/kempo/utils/cli.js +1 -0
  102. package/docs/kempo/utils/cookie.js +1 -0
  103. package/docs/kempo/utils/debounce.js +1 -0
  104. package/docs/kempo/utils/drag.js +1 -0
  105. package/docs/kempo/utils/element.js +1 -0
  106. package/docs/kempo/utils/formatTimestamp.js +1 -0
  107. package/docs/kempo/utils/fuzzyMatch.js +1 -0
  108. package/docs/kempo/utils/getPreferredTheme.js +1 -0
  109. package/docs/kempo/utils/loadCss.js +1 -0
  110. package/docs/kempo/utils/loadScript.js +1 -0
  111. package/docs/kempo/utils/object.js +1 -0
  112. package/docs/kempo/utils/string.js +1 -0
  113. package/docs/kempo/utils/toFunction.js +1 -0
  114. package/docs/kempo/utils/type.js +1 -0
  115. package/docs/kempo/utils/waitFrames.js +1 -0
  116. package/docs/nav-1.inc.html +66 -0
  117. package/docs/nav.inc.html +66 -0
  118. package/docs/search.json +94 -0
  119. package/docs/styles/_template.html +22 -0
  120. package/docs/styles/borders-spacing.html +193 -0
  121. package/docs/styles/buttons.html +113 -0
  122. package/docs/styles/colors.html +65 -0
  123. package/docs/styles/displays-layouts.html +156 -0
  124. package/docs/styles/embed-1.html +35 -0
  125. package/docs/styles/inputs.html +89 -0
  126. package/docs/styles/tables.html +143 -0
  127. package/docs/styles/typography.html +116 -0
  128. package/icons/arrow-down-double.svg +1 -0
  129. package/icons/arrow-up-double.svg +1 -0
  130. package/icons/close.svg +2 -0
  131. package/icons/compare.svg +1 -0
  132. package/icons/dark-mode.svg +1 -0
  133. package/icons/delete.svg +1 -0
  134. package/icons/filter-off.svg +1 -0
  135. package/icons/filter.svg +1 -0
  136. package/icons/light-mode.svg +1 -0
  137. package/icons/menu.svg +1 -0
  138. package/icons/pause.svg +1 -0
  139. package/icons/play.svg +1 -0
  140. package/icons/search.svg +1 -0
  141. package/icons/settings.svg +1 -0
  142. package/icons/storage.svg +1 -0
  143. package/icons/trash-x.svg +1 -0
  144. package/kempo/components/Card.js +65 -0
  145. package/kempo/components/CodeEditor.js +141 -0
  146. package/kempo/components/Component.js +109 -0
  147. package/kempo/components/Dialog.js +277 -0
  148. package/kempo/components/FocusCapture.js +30 -0
  149. package/kempo/components/Icon.js +60 -0
  150. package/kempo/components/Import.js +40 -0
  151. package/kempo/components/LazyComponent.js +40 -0
  152. package/kempo/components/ReactiveComponent.js +11 -0
  153. package/kempo/components/ReactiveLazyComponent.js +11 -0
  154. package/kempo/components/Resize.js +168 -0
  155. package/kempo/components/Search.js +136 -0
  156. package/kempo/components/ShowMore.js +82 -0
  157. package/kempo/components/SideMenu.js +156 -0
  158. package/kempo/components/Split.js +133 -0
  159. package/kempo/components/Tabs.js +254 -0
  160. package/kempo/components/ThemeSwitcher.js +77 -0
  161. package/kempo/components/Timestamp.js +25 -0
  162. package/kempo/components/WebSnippetEditor.js +159 -0
  163. package/kempo/kempo-hljs.css +145 -0
  164. package/kempo/kempo-styles.css +893 -0
  165. package/kempo/kempo-vars.css +154 -0
  166. package/kempo/kempo.js +48 -0
  167. package/kempo/utils/cli.js +54 -0
  168. package/kempo/utils/cookie.js +16 -0
  169. package/kempo/utils/debounce.js +9 -0
  170. package/kempo/utils/drag.js +74 -0
  171. package/kempo/utils/element.js +69 -0
  172. package/kempo/utils/formatTimestamp.js +11 -0
  173. package/kempo/utils/fuzzyMatch.js +55 -0
  174. package/kempo/utils/getPreferredTheme.js +1 -0
  175. package/kempo/utils/loadCss.js +10 -0
  176. package/kempo/utils/loadScript.js +10 -0
  177. package/kempo/utils/object.js +177 -0
  178. package/kempo/utils/string.js +54 -0
  179. package/kempo/utils/toFunction.js +24 -0
  180. package/kempo/utils/type.js +8 -0
  181. package/kempo/utils/waitFrames.js +17 -0
  182. package/package.json +33 -0
  183. package/scripts/build.js +131 -0
  184. package/scripts/docs.js +14 -0
  185. package/test/components/SuiteList.js +26 -0
  186. package/test/components/Test.js +357 -0
  187. package/test/index.html +49 -0
  188. package/test/index.js +25 -0
  189. package/test/suite.html +45 -0
  190. package/test/suites.inc.html +4 -0
  191. package/test/tests/components/Component.test.js +138 -0
  192. package/test/tests/utils/cli.test.js +113 -0
  193. package/test/tests/utils/cookie.test.js +87 -0
  194. package/test/tests/utils/debounce.test.js +71 -0
@@ -0,0 +1,277 @@
1
+ import Component from './Component.js';
2
+ import './FocusCapture.js';
3
+ import './Icon.js';
4
+ import {
5
+ firstFocusable,
6
+ onEvent,
7
+ offEvent,
8
+ dispatchEvent
9
+ } from '../utils/element.js';
10
+
11
+ export default class Dialog extends Component {
12
+ constructor({
13
+ opened = false,
14
+ closeBtn = true,
15
+ overlayClose = true,
16
+ confirmText = '',
17
+ confirmClasses = 'success ml',
18
+ confirmAction = () => {},
19
+ cancelText = '',
20
+ cancelClasses = '',
21
+ cancelAction = () => {},
22
+ closeCallback = () => {}
23
+ } = {}){
24
+ super();
25
+
26
+ this.registerAttributes({
27
+ opened,
28
+ closeBtn,
29
+ overlayClose,
30
+ confirmText,
31
+ confirmClasses,
32
+ cancelText,
33
+ cancelClasses
34
+ });
35
+ this.registerProps({
36
+ confirmAction,
37
+ cancelAction,
38
+ closeCallback,
39
+ previousFocus: null,
40
+ _clickHandler: (event) => {
41
+ const {target: { id }} = event;
42
+ if(
43
+ (id == 'overlay' && this.overlayClose) ||
44
+ id == 'close'
45
+ ){
46
+ this.close();
47
+ } else if(id == 'cancel'){
48
+ this.cancelAction(event);
49
+ if(!event.defaultPrevented) this.close();
50
+ } else if(id == 'confirm'){
51
+ this.confirmAction(event);
52
+ if(!event.defaultPrevented) this.close();
53
+ }
54
+ },
55
+ _keydownHandler: ({ keyCode }) => {
56
+ if(keyCode === 27){
57
+ this.close();
58
+ }
59
+ },
60
+ _hasTitle: () => !!this.querySelector('[slot="title"]')
61
+ });
62
+ }
63
+ connectedCallback(){
64
+ super.connectedCallback();
65
+ onEvent(this.shadowRoot, 'click', this._clickHandler);
66
+ }
67
+ disconnectedCallback(){
68
+ super.connectedCallback();
69
+ offEvent(this.shadowRoot, 'click', this._clickHandler);
70
+ offEvent(window, 'keydown', this._keydownHandler); // just in case this was removed without being closed first
71
+ }
72
+ attributeChangedCallback(n, oV, nV){
73
+ super.attributeChangedCallback(n, oV, nV);
74
+ if(name === 'opened'){
75
+ dispatchEvent(this, nV?'opened':'closed');
76
+ }
77
+ }
78
+ open(){
79
+ this.opened = true;
80
+ const $toFucus = this.shadowRoot.querySelector('[autofocus]') || firstFocusable(this.shadowRoot);
81
+ if($toFucus) $toFucus.focus();
82
+ onEvent(window, 'keydown', this._keydownHandler);
83
+ }
84
+ close(){
85
+ this.opened = false;
86
+ this.blur();
87
+ this.closeCallback();
88
+ offEvent(window, 'keydown', this._keydownHandler);
89
+ }
90
+ toggle(){
91
+ this.opened?this.close():this.open();
92
+ }
93
+ focus(){
94
+ const $firstFocus = firstFocusable(this.shadowRoot);
95
+ if($firstFocus){
96
+ this.previousFocus = document.activeElement;
97
+ $firstFocus.focus();
98
+ }
99
+ }
100
+ blur(){
101
+ if(this.previousFocus){
102
+ this.previousFocus.focus();
103
+ }
104
+ }
105
+
106
+ get shadowTemplate(){
107
+ return /*html*/`
108
+ <k-focus-capture>
109
+ <button id="overlay" aria-label="Close the Dialog"></button>
110
+ <div id="wrapper">
111
+ <div
112
+ id="dialog"
113
+ role="dialog"
114
+ aria-modal="true"
115
+ aria-labelledby="title"
116
+ >
117
+ <div
118
+ id="header"
119
+ class="${this._hasTitle()?'has-title':''}"
120
+ >
121
+ <div
122
+ id="title"
123
+ ><slot name="title"></slot></div>
124
+ ${this.renderIf(this.closeBtn, /*html*/`
125
+ <button
126
+ id="close"
127
+ >
128
+ <k-icon name="close"></k-icon>
129
+ </button>
130
+ `)}
131
+ </div>
132
+ <div id="body">
133
+ ${super.shadowTemplate}
134
+ </div>
135
+ ${this.renderIf(this.cancelText || this.confirmText, /*html*/`
136
+ <div id="footer">
137
+ ${this.renderIf(this.cancelText, /*html*/`
138
+ <button id="cancel" class="${this.cancelClasses}">
139
+ ${this.cancelText}
140
+ </button>
141
+ `)}
142
+ ${this.renderIf(this.confirmText, /*html*/`
143
+ <button id="confirm" class="${this.confirmClasses}">
144
+ ${this.confirmText}
145
+ </button>
146
+ `)}
147
+ </div>
148
+ `)}
149
+ </div>
150
+ </div>
151
+ </k-focus-capture>
152
+ `;
153
+ }
154
+ get shadowStyles(){
155
+ return /*css*/`
156
+ ${super.shadowStyles}
157
+ :host {
158
+ display: inline;
159
+ height: 0;
160
+ width: 0;
161
+ }
162
+ :host(:not([opened])){
163
+ display: none;
164
+ }
165
+ #overlay {
166
+ position: fixed;
167
+ width: 100vw;
168
+ height: 100vh;
169
+ top: 0;
170
+ left: 0;
171
+ background-color: var(--c_overlay);
172
+ z-index: 100;
173
+ border: 0px solid transparent;
174
+ box-shadow: 0 0 0 transparent;
175
+ }
176
+ #wrapper {
177
+ display: flex;
178
+ justify-content: center;
179
+ align-items: center;
180
+ position: fixed;
181
+ width: 100vw;
182
+ height: 100vh;
183
+ top: 0;
184
+ left: 0;
185
+ z-index: 101;
186
+ pointer-events: none;
187
+ }
188
+ #dialog {
189
+ display: flex;
190
+ flex-direction: column;
191
+ min-width: var(--min_width, 20rem);
192
+ width: var(--width, fit-content);
193
+ max-width: var(--max_width, calc(100vw - 2rem));
194
+ min-height: var(--min_height, 12rem);
195
+ height: var(--height, fit-content);
196
+ max-height: var(--max_height, calc(100vh - 2rem));
197
+ background-color: var(--c_bg);
198
+ box-shadow: var(--drop_shadow);
199
+ border-radius: var(--radius);
200
+ pointer-events: all;
201
+ }
202
+ #header {
203
+ display: flex;
204
+ align-items: center;
205
+ }
206
+ #header.has-title {
207
+ border-bottom: 1px solid var(--c_border);
208
+ }
209
+ #title {
210
+ flex: 1 1 auto;
211
+ }
212
+ #close {
213
+ border: 0px;
214
+ background: transparent;
215
+ box-shadow: 0 0 0 transparent;
216
+ color: var(--tc);
217
+ }
218
+ #close k-icon {
219
+ pointer-events: none;
220
+ }
221
+ #body {
222
+ flex: 1 1 auto;
223
+ }
224
+ #footer {
225
+ display: flex;
226
+ justify-content: flex-end;
227
+ padding: var(--spacer_h);
228
+ }
229
+ `;
230
+ }
231
+
232
+ static renderOnChange = [
233
+ 'opened',
234
+ 'closeBtn',
235
+ 'overlayClose',
236
+ 'title',
237
+ 'confirmText',
238
+ 'cancelText'
239
+ ];
240
+
241
+ static create(contents = '', options = {}){
242
+ const $dialog = new Dialog({
243
+ opened: true,
244
+ ...options
245
+ });
246
+ onEvent($dialog, 'close', $dialog.remove);
247
+ if(contents instanceof HTMLElement || contents instanceof DocumentFragment){
248
+ $dialog.appendChild(contents);
249
+ } else if(contents instanceof NodeList){
250
+ contents.forEach( $el => $dialog.appendChild($el));
251
+ } else {
252
+ $dialog.innerHTML = contents;
253
+ }
254
+ document.body.appendChild($dialog);
255
+ }
256
+ static confirm(text, responseCallback, options){
257
+ Dialog.create(`
258
+ <h5 slot="title" class="pyh px m0">Confirm Event Deletion</h5>
259
+ <p class="p">${text}</p>
260
+ `, {
261
+ ...options,
262
+ closeBtn: false,
263
+ overlayClose: false,
264
+ confirmText: 'Yes',
265
+ confirmClasses: 'success ml',
266
+ confirmAction: () => {
267
+ return responseCallback(true);
268
+ },
269
+ cancelText: 'No',
270
+ cancelClasses: 'danger',
271
+ cancelAction: () => {
272
+ return responseCallback(false);
273
+ }
274
+ });
275
+ }
276
+ }
277
+ window.customElements.define('k-dialog', Dialog);
@@ -0,0 +1,30 @@
1
+ import LazyComponent from './LazyComponent.js';
2
+
3
+ export default class FocusCapture extends LazyComponent {
4
+ constructor(){
5
+ super({
6
+ delegatesFocus: true
7
+ });
8
+ }
9
+ render(){
10
+ super.render();
11
+ this.shadowRoot.getElementById('after').addEventListener('focus', () => {
12
+ this.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])').focus();
13
+ });
14
+ }
15
+
16
+ get shadowTemplate(){
17
+ return /*html*/`
18
+ ${super.shadowTemplate}
19
+ <div id="after" tabindex="0"></div>
20
+ `;
21
+ }
22
+ get shadowStyles(){
23
+ return /*css*/`
24
+ :host {
25
+ display: inline-block;
26
+ }
27
+ `;
28
+ }
29
+ }
30
+ window.customElements.define('k-focus-capture', FocusCapture);
@@ -0,0 +1,60 @@
1
+ import Component from './Component.js';
2
+
3
+ export default class Icon extends Component {
4
+ constructor(){
5
+ super();
6
+ this.registerAttributes({
7
+ src: '',
8
+ name: ''
9
+ });
10
+ }
11
+ async render(force){
12
+ if(await super.render(force)){
13
+ if(this.src){
14
+ this.innerHTML = await (await fetch(this.src)).text();
15
+ this.fixSVG();
16
+ } else if(this.name){
17
+ this.innerHTML = await (await fetch(`${Icon.pathToIcons}/${this.name}.svg`)).text();
18
+ this.fixSVG();
19
+ } else {
20
+ this.rendered = false;
21
+ this.innerHTML = '';
22
+ }
23
+ return true;
24
+ }
25
+ return false;
26
+ }
27
+ attributeChangedCallback(n, oV, nV){
28
+ if(['src', 'name'].includes(n)){
29
+ this.render(true);
30
+ }
31
+ }
32
+ fixSVG(){
33
+ const $svg = this.querySelector('svg');
34
+ $svg.removeAttribute('width');
35
+ $svg.removeAttribute('height');
36
+ $svg.querySelectorAll('path, rect, circle').forEach( $path => {
37
+ $path.setAttribute('fill', 'currentColor');
38
+ });
39
+ }
40
+ get shadowStyles(){
41
+ return /*css*/`
42
+ :host {
43
+ display: inline-block;
44
+ vertical-align: bottom;
45
+ }
46
+ ::slotted(svg){
47
+ height: 1.35em;
48
+ vertical-align: middle;
49
+ }
50
+ `;
51
+ }
52
+
53
+ static observedAttributes = [
54
+ 'name',
55
+ 'src'
56
+ ];
57
+
58
+ static pathToIcons = '/icons';
59
+ }
60
+ window.customElements.define('k-icon', Icon);
@@ -0,0 +1,40 @@
1
+ import Component from './Component.js';
2
+
3
+ export default class Import extends Component {
4
+ constructor(){
5
+ super();
6
+ this.registerAttribute('src');
7
+ }
8
+ attributeChangedCallback(n, oV, nV){
9
+ if(n === 'src' && oV !== nV){
10
+ this.render(true);
11
+ }
12
+ }
13
+ async render(force){
14
+ const src = this.src;
15
+ if(src && await super.render(force)){
16
+ this.innerHTML = await (await fetch(src)).text();
17
+ this.querySelectorAll('script').forEach( $badScript => {
18
+ const $goodScript = document.createElement('script');
19
+ if($badScript.getAttribute('type')) $goodScript.type = $badScript.getAttribute('type');
20
+ if($badScript.getAttribute('src')) $goodScript.src = $badScript.getAttribute('src');
21
+ if($badScript.textContent) $goodScript.textContent = $badScript.textContent;
22
+ $badScript.parentElement.replaceChild($goodScript, $badScript);
23
+ });
24
+
25
+ }
26
+ }
27
+
28
+ get shadowStyles(){
29
+ return /*css*/`
30
+ :host {
31
+ display: inline;
32
+ }
33
+ `;
34
+ }
35
+
36
+ static get renderOnAttributes(){
37
+ retur ['src'];
38
+ }
39
+ }
40
+ window.customElements.define('k-import', Import);
@@ -0,0 +1,40 @@
1
+ import Component from './Component.js';
2
+ import { isInView } from '../utils/element.js';
3
+
4
+
5
+ export default class LazyComponent extends Component {
6
+ constructor(shadowDetails){
7
+ super(shadowDetails);
8
+ (new IntersectionObserver(([comp]) => {
9
+ if(comp.intersectionRatio > 0 && !this.rendered){
10
+ this.inViewCallback();
11
+ } else {
12
+ this.outOfViewCallback();
13
+ }
14
+ })).observe(this);
15
+
16
+ this.registerAttribute('unrender', false);
17
+ }
18
+ async connectedCallback(){
19
+ // Do not do super.connectedCallback() because it will render the component prematurely
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
+ }
24
+ }
25
+ async inViewCallback(){
26
+ await this.render();
27
+ }
28
+ async outOfViewCallback(){
29
+ if(this.unrender){
30
+ await this.renderSkelton();
31
+ }
32
+ }
33
+ async renderSkelton(){
34
+ this.shadowRoot.innerHTML = `<link rel="stylesheet" href="../kempo/kempo-vars.css" /><link rel="stylesheet" href="../kempo/kempo-styles.css" />${this.skeletonTemplate}<style>${this.shadowStyles}</style>`;
35
+ this.rendered = false;
36
+ }
37
+ get skeletonTemplate(){
38
+ return /*html*/`<div style="height: var(--skeleton_height, 1rem)"></div>`;
39
+ }
40
+ }
@@ -0,0 +1,11 @@
1
+ import Component from './Component.js';
2
+
3
+ export default class ReactiveComponent extends Component {
4
+ attributeChangedCallback(n, oV, nV){
5
+ super.attributeChangedCallback(n, oV, nV);
6
+ if(this.constructor.renderOnChange.includes(n)){
7
+ this.render(true);
8
+ }
9
+ }
10
+ static renderOnChange = [];
11
+ }
@@ -0,0 +1,11 @@
1
+ import LazyComponent from './LazyComponent.js';
2
+
3
+ export default class ReactiveComponent extends LazyComponent {
4
+ attributeChangedCallback(n, oV, nV){
5
+ super.attributeChangedCallback(n, oV, nV);
6
+ if(this.constructor.renderOnChange.includes(n)){
7
+ this.render(true);
8
+ }
9
+ }
10
+ static renderOnChange = [];
11
+ }
@@ -0,0 +1,168 @@
1
+ import Component from './Component.js';
2
+ import drag from '../utils/drag.js';
3
+
4
+ const startSize = Symbol('startSize'),
5
+ dragStartHandler = Symbol('dragStartHandler'),
6
+ dragEndHandler = Symbol('dragEndHandler'),
7
+ dragSideHandler = Symbol('dragSideHandler'),
8
+ dragBottomHandler = Symbol('dragBottomHandler'),
9
+ dragCornerHandler = Symbol('dragCornerHandler'),
10
+ cleanupFuncs = Symbol('cleanupFuncs');
11
+ export default class Resize extends Component {
12
+ constructor(){
13
+ super();
14
+
15
+ this[startSize] = {width: 0, height: 0};
16
+
17
+ this[dragStartHandler] = ({element}) => {
18
+ const { width, height } = this.getBoundingClientRect();
19
+ this[startSize].width = width;
20
+ this[startSize].height = height;
21
+ this.resizing = element.id;
22
+ }
23
+ this[dragEndHandler] = () => {
24
+ this.resizing = '';
25
+ }
26
+ this[dragSideHandler] = ({x}) => {
27
+ this.style.width = this[startSize].width + x + 'px';
28
+ }
29
+ this[dragBottomHandler] = ({y}) => {
30
+ this.style.height = this[startSize].height + y + 'px';
31
+ }
32
+ this[dragCornerHandler] = ({x, y}) => {
33
+ this.style.width = this[startSize].width + x + 'px';
34
+ this.style.height = this[startSize].height + y + 'px';
35
+ }
36
+ this[cleanupFuncs] = [];
37
+
38
+ this.registerAttribute('resizing', '');
39
+ }
40
+ async render(force){
41
+ if(await super.render(force)){
42
+ this[cleanupFuncs].push(drag({
43
+ element: this.shadowRoot.getElementById('side'),
44
+ startCallback: this[dragStartHandler],
45
+ endCallback: this[dragEndHandler],
46
+ callback: this[dragSideHandler],
47
+ preventScroll: true
48
+ }));
49
+ this[cleanupFuncs].push(drag({
50
+ element: this.shadowRoot.getElementById('bottom'),
51
+ startCallback: this[dragStartHandler],
52
+ endCallback: this[dragEndHandler],
53
+ callback: this[dragBottomHandler],
54
+ preventScroll: true
55
+ }));
56
+ this[cleanupFuncs].push(drag({
57
+ element: this.shadowRoot.getElementById('corner'),
58
+ startCallback: this[dragStartHandler],
59
+ endCallback: this[dragEndHandler],
60
+ callback: this[dragCornerHandler],
61
+ preventScroll: true
62
+ }));
63
+ return true;
64
+ }
65
+ return false;
66
+ }
67
+ disconnectedCallback(){
68
+ super.disconnectedCallback();
69
+ this[cleanupFuncs].forEach( cleanup => cleanup());
70
+ }
71
+ get shadowTemplate(){
72
+ return /*html*/`
73
+ <div id="main">
74
+ ${super.shadowTemplate}
75
+ </div>
76
+ <div id="side" class="handle">
77
+ <svg viewBox="0 0 15 64" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="m 15.000001,3 c 0,-1.661998 -1.115001,-3 -2.5,-3 -1.384999,0 -2.5,1.338002 -2.5,3 v 58 c 0,1.661998 1.115001,3 2.5,3 1.384999,0 2.5,-1.338002 2.5,-3 z M 5.0000008,3 c 0,-1.661998 -1.115001,-3 -2.5,-3 C 1.1150018,0 7.5891117e-7,1.338002 7.5891117e-7,3 v 58 c 0,1.661998 1.11500104108883,3 2.50000004108883,3 1.384999,0 2.5,-1.338002 2.5,-3 z" /></svg>
78
+ </div>
79
+ <div id="bottom" class="handle">
80
+ <svg viewBox="0 0 64 15" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M 3,0 C 1.3380017,0 0,1.1150014 0,2.5 0,3.8849986 1.3380017,5 3,5 H 61 C 62.661998,5 64,3.8849986 64,2.5 64,1.1150014 62.661998,0 61,0 Z M 3,10 C 1.3380017,10 0,11.115001 0,12.5 0,13.884999 1.3380017,15 3,15 h 58 c 1.661998,0 3,-1.115001 3,-2.5 C 64,11.115001 62.661998,10 61,10 Z" /></svg>
81
+ </div>
82
+ <div id="corner" class="handle">
83
+ <svg version="1.1" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="m12.735 3.0095e-4c-0.77288 0.011702-1.6098 0.36368-2.2773 1.0313l-9.4258 9.4258c-1.1868 1.1868-1.3772 2.908-0.42773 3.8574 0.94943 0.94943 2.6687 0.7571 3.8555-0.42969l9.4258-9.4258c1.1868-1.1868 1.3772-2.906 0.42774-3.8555-0.41537-0.41537-0.977-0.61262-1.5781-0.60352zm0 8.5684c-0.77288 0.011702-1.6098 0.36564-2.2773 1.0332l-0.85744 0.85546c-1.1868 1.1868-1.3772 2.908-0.42773 3.8574 0.94943 0.94943 2.6687 0.7571 3.8555-0.42969l0.85742-0.85742c1.1868-1.1868 1.3772-2.906 0.42773-3.8555-0.41537-0.41537-0.977-0.61262-1.5781-0.60352z" /></svg>
84
+ </div>
85
+ `;
86
+ }
87
+ get shadowStyles(){
88
+ return /*css*/`
89
+ ${super.shadowStyles}
90
+ :host {
91
+ --handle_size: 1rem;
92
+
93
+ display: grid;
94
+ grid-template-columns: 1fr var(--handle_size);
95
+ grid-template-rows: 1fr var(--handle_size);
96
+ border: 1px solid var(--c_border);
97
+ border-radius: var(--radius);
98
+ min-width: 10rem;
99
+ max-width: 100%;
100
+ min-height: 10rem;
101
+ max-height: 100%;
102
+ }
103
+ :host([dimention="height"]){
104
+ grid-template-columns: 1fr;
105
+ }
106
+ :host([dimention="width"]){
107
+ grid-template-rows: 1fr;
108
+ }
109
+ #main {
110
+ grid-row: 1;
111
+ grid-column: 1;
112
+ overflow: auto;
113
+ }
114
+ #side {
115
+ grid-row: 1;
116
+ grid-column: 2;
117
+ cursor: ew-resize;
118
+ }
119
+ #bottom {
120
+ grid-row: 2;
121
+ grid-column: 1;
122
+ text-align: center;
123
+ cursor: ns-resize;
124
+ }
125
+ #corner {
126
+ grid-row: 2;
127
+ grid-column: 2;
128
+ overflow: hidden;
129
+ cursor: nwse-resize;
130
+ }
131
+ .handle {
132
+ display: flex;
133
+ align-items: center;
134
+ justify-content: center;
135
+ }
136
+ .handle svg {
137
+ transform: scale(0.5);
138
+ }
139
+ #bottom svg {
140
+ height: var(--handle_size);
141
+ }
142
+ #side svg {
143
+ width: var(--handle_size);
144
+ }
145
+ #corner svg {
146
+ width: var(--handle_size);
147
+ height: var(--handle_size);
148
+ }
149
+ :host(:not([resizing=""])) #main {
150
+ pointer-events: none;
151
+ }
152
+ :host([resizing="side"]) #side,
153
+ :host([resizing="corner"]) #side,
154
+ :host([resizing="corner"]) #corner,
155
+ :host([resizing="corner"]) #bottom,
156
+ :host([resizing="bottom"]) #bottom {
157
+ background-color: var(--c_highlight);
158
+ }
159
+ :host([dimention="height"]) #side,
160
+ :host([dimention="height"]) #corner,
161
+ :host([dimention="width"]) #bottom,
162
+ :host([dimention="width"]) #corner {
163
+ display: none;
164
+ }
165
+ `;
166
+ }
167
+ }
168
+ window.customElements.define('k-resize', Resize);