kempo-ui 0.1.6 → 0.2.2

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 (119) hide show
  1. package/.github/skills/highlight-code/SKILL.md +22 -6
  2. package/.github/skills/new-component/SKILL.md +68 -4
  3. package/AGENTS.md +11 -0
  4. package/bin/highlight_code.js +7 -15
  5. package/dist/components/Aside.js +326 -0
  6. package/dist/components/Dialog.js +1 -1
  7. package/dist/components/Dropdown.js +1 -1
  8. package/dist/components/Main.js +2 -2
  9. package/dist/components/Nav.js +27 -0
  10. package/dist/components/PhotoViewer.js +1 -1
  11. package/dist/components/ShadowComponent.js +1 -1
  12. package/dist/components/ThemeSwitcher.js +1 -0
  13. package/dist/components/Toast.js +1 -1
  14. package/docs/components/accordion.html +4 -3
  15. package/docs/components/aside-items.html +43 -0
  16. package/docs/components/aside-menu.html +43 -0
  17. package/docs/components/aside-push.html +26 -0
  18. package/docs/components/aside.html +567 -0
  19. package/docs/components/card.html +4 -3
  20. package/docs/components/color-picker.html +4 -3
  21. package/docs/components/content-slider.html +4 -3
  22. package/docs/components/dialog.html +4 -3
  23. package/docs/components/dropdown.html +4 -3
  24. package/docs/components/filter-list.html +4 -3
  25. package/docs/components/focus-capture.html +6 -5
  26. package/docs/components/html-editor.html +5 -4
  27. package/docs/components/hybrid-component.html +5 -4
  28. package/docs/components/icon.html +4 -3
  29. package/docs/components/import.html +5 -4
  30. package/docs/components/light-component.html +4 -3
  31. package/docs/components/nav.html +117 -0
  32. package/docs/components/photo-viewer.html +5 -4
  33. package/docs/components/resize.html +5 -4
  34. package/docs/components/shadow-component.html +4 -3
  35. package/docs/components/show-more.html +5 -4
  36. package/docs/components/sortable.html +4 -3
  37. package/docs/components/spinner.html +4 -3
  38. package/docs/components/split.html +5 -4
  39. package/docs/components/table.html +4 -3
  40. package/docs/components/tableControls.html +4 -3
  41. package/docs/components/tableCustomFields.html +4 -3
  42. package/docs/components/tableFetchRecords.html +5 -4
  43. package/docs/components/tableFieldSortHide.html +5 -4
  44. package/docs/components/tablePagination.html +4 -3
  45. package/docs/components/tableRecordEditing.html +4 -3
  46. package/docs/components/tableRecordFiltering.html +5 -4
  47. package/docs/components/tableRecordHiding.html +4 -3
  48. package/docs/components/tableRecordSearching.html +5 -4
  49. package/docs/components/tableRecordSelection.html +4 -3
  50. package/docs/components/tableRowControls.html +4 -3
  51. package/docs/components/tableServerSync.html +5 -4
  52. package/docs/components/tableSorting.html +5 -4
  53. package/docs/components/tabs.html +4 -3
  54. package/docs/components/tags.html +4 -3
  55. package/docs/components/theme-select.html +4 -3
  56. package/docs/components/theme-switcher.html +5 -4
  57. package/docs/components/timestamp.html +4 -3
  58. package/docs/components/toast.html +4 -3
  59. package/docs/components/toggle.html +5 -4
  60. package/docs/components/tree.html +5 -4
  61. package/docs/index.html +22 -21
  62. package/docs/nav-1.inc.html +18 -12
  63. package/docs/nav.inc.html +20 -13
  64. package/docs/nav.inc.js +1 -1
  65. package/docs/src/components/Aside.js +326 -0
  66. package/docs/src/components/Dialog.js +1 -1
  67. package/docs/src/components/Dropdown.js +1 -1
  68. package/docs/src/components/Main.js +2 -2
  69. package/docs/src/components/Nav.js +27 -0
  70. package/docs/src/components/PhotoViewer.js +1 -1
  71. package/docs/src/components/ShadowComponent.js +1 -1
  72. package/docs/src/components/ThemeSwitcher.js +1 -0
  73. package/docs/src/components/Toast.js +1 -1
  74. package/docs/utils/context.html +4 -3
  75. package/docs/utils/cookie.html +4 -3
  76. package/docs/utils/debounce.html +4 -3
  77. package/docs/utils/drag.html +4 -3
  78. package/docs/utils/elevation.html +156 -0
  79. package/docs/utils/formatTimestamp.html +4 -3
  80. package/docs/utils/object.html +4 -3
  81. package/docs/utils/propConverters.html +4 -3
  82. package/docs/utils/string.html +4 -3
  83. package/docs/utils/theme.html +4 -3
  84. package/docs/utils/toTitleCase.html +4 -3
  85. package/docs/utils/type.html +4 -3
  86. package/docs/utils/wait.html +4 -3
  87. package/llm.txt +247 -0
  88. package/package.json +3 -4
  89. package/src/components/Aside.js +726 -0
  90. package/src/components/Dialog.js +1 -1
  91. package/src/components/Dropdown.js +1 -1
  92. package/src/components/Main.js +34 -30
  93. package/src/components/Nav.js +53 -0
  94. package/src/components/PhotoViewer.js +1 -1
  95. package/src/components/ShadowComponent.js +1 -1
  96. package/src/components/ThemeSwitcher.js +1 -0
  97. package/src/components/Toast.js +1 -1
  98. package/tests/bin/get_icon.node-test.js +26 -0
  99. package/tests/bin/highlight_code.node-test.js +108 -0
  100. package/tests/bin/list_icons.node-test.js +26 -0
  101. package/tests/components/Aside.browser-test.js +778 -0
  102. package/tests/components/Main.browser-test.js +115 -283
  103. package/dist/components/SideMenu.js +0 -97
  104. package/dist/components/SidePanel.js +0 -236
  105. package/docs/components/side-menu.html +0 -189
  106. package/docs/components/side-panel-basic.html +0 -44
  107. package/docs/components/side-panel-dual.html +0 -70
  108. package/docs/components/side-panel-menu.html +0 -50
  109. package/docs/components/side-panel-persistent.html +0 -90
  110. package/docs/components/side-panel-scroll.html +0 -176
  111. package/docs/components/side-panel.html +0 -245
  112. package/docs/src/components/SideMenu.js +0 -97
  113. package/docs/src/components/SidePanel.js +0 -236
  114. package/scripts/update-kempo-css.js +0 -53
  115. package/src/components/SideMenu.js +0 -178
  116. package/src/components/SidePanel.js +0 -513
  117. package/tests/components/SideMenu.browser-test.js +0 -667
  118. package/tests/components/SidePanel.browser-test.js +0 -520
  119. package/tools/highlight.js +0 -51
@@ -244,7 +244,7 @@ export default class Dropdown extends ShadowComponent {
244
244
  display: none;
245
245
  position: fixed;
246
246
  position-anchor: --dropdown-trigger;
247
- z-index: 1000;
247
+ z-index: 70;
248
248
  min-width: anchor-size(width);
249
249
  background: var(--c_bg);
250
250
  border: 1px solid var(--c_border);
@@ -2,16 +2,9 @@ import ShadowComponent from './ShadowComponent.js';
2
2
  import { html, css } from '../lit-all.min.js';
3
3
 
4
4
  export default class Main extends ShadowComponent {
5
- static properties = {
6
- leftPanelWidth: { type: String, state: true },
7
- rightPanelWidth: { type: String, state: true }
8
- };
9
-
10
5
  constructor() {
11
6
  super();
12
- this.leftPanelWidth = '0px';
13
- this.rightPanelWidth = '0px';
14
- this.handlePanelChange = this.handlePanelChange.bind(this);
7
+ this.widthMap = new Map();
15
8
  }
16
9
 
17
10
  /*
@@ -19,33 +12,50 @@ export default class Main extends ShadowComponent {
19
12
  */
20
13
  connectedCallback() {
21
14
  super.connectedCallback();
22
- window.addEventListener('side-panel-change', this.handlePanelChange);
23
-
24
- const leftPanel = document.querySelector('k-side-panel:not([side="right"])');
25
- if(leftPanel){
26
- this.leftPanelWidth = leftPanel.collapsed ? '3.5rem' : '16rem';
27
- }
15
+ window.addEventListener('aside_state_change', this.handleAsideChange);
28
16
 
29
- const rightPanel = document.querySelector('k-side-panel[side="right"]');
30
- if(rightPanel){
31
- this.rightPanelWidth = rightPanel.collapsed ? '3.5rem' : '16rem';
32
- }
17
+ document.querySelectorAll('k-aside[main="push"]').forEach(aside => {
18
+ if(aside.state !== 'offscreen') {
19
+ const width = aside.getTargetWidth(aside.state);
20
+ if(width > 0) {
21
+ this.widthMap.set(aside, { side: aside.side || 'left', width });
22
+ }
23
+ }
24
+ });
25
+
26
+ this.recalculate();
33
27
  }
34
28
 
35
29
  disconnectedCallback() {
36
30
  super.disconnectedCallback();
37
- window.removeEventListener('side-panel-change', this.handlePanelChange);
31
+ window.removeEventListener('aside_state_change', this.handleAsideChange);
38
32
  }
39
33
 
40
34
  /*
41
35
  Event Handlers
42
36
  */
43
- handlePanelChange(event) {
44
- if(event.detail.side === 'right'){
45
- this.rightPanelWidth = event.detail.width;
46
- }else{
47
- this.leftPanelWidth = event.detail.width;
37
+ handleAsideChange = (event) => {
38
+ const { aside, state, main, width } = event.detail;
39
+ if(main === 'overlay' || state === 'offscreen') {
40
+ this.widthMap.delete(aside);
41
+ } else {
42
+ this.widthMap.set(aside, { side: aside.side || 'left', width });
48
43
  }
44
+ this.recalculate();
45
+ }
46
+
47
+ recalculate = () => {
48
+ let maxLeft = 0;
49
+ let maxRight = 0;
50
+ for(const [, { side, width }] of this.widthMap) {
51
+ if(side === 'right') {
52
+ maxRight = Math.max(maxRight, width);
53
+ } else {
54
+ maxLeft = Math.max(maxLeft, width);
55
+ }
56
+ }
57
+ this.style.setProperty('--left-panel-width', `${maxLeft}px`);
58
+ this.style.setProperty('--right-panel-width', `${maxRight}px`);
49
59
  }
50
60
 
51
61
  /*
@@ -75,12 +85,6 @@ export default class Main extends ShadowComponent {
75
85
  padding-right: var(--spacer);
76
86
  }
77
87
  `;
78
-
79
- updated() {
80
- super.updated();
81
- this.style.setProperty('--left-panel-width', this.leftPanelWidth);
82
- this.style.setProperty('--right-panel-width', this.rightPanelWidth);
83
- }
84
88
  }
85
89
 
86
90
  window.customElements.define('k-main', Main);
@@ -0,0 +1,53 @@
1
+ import { html, css } from '../lit-all.min.js';
2
+ import ShadowComponent from './ShadowComponent.js';
3
+
4
+ export default class Nav extends ShadowComponent {
5
+ static properties = {
6
+ fixed: { type: Boolean, reflect: true }
7
+ };
8
+
9
+ constructor() {
10
+ super();
11
+ this.fixed = false;
12
+ }
13
+
14
+ /*
15
+ Rendering
16
+ */
17
+ render() {
18
+ return html`<nav><slot></slot></nav>`;
19
+ }
20
+
21
+ /*
22
+ Styles
23
+ */
24
+ static styles = css`
25
+ :host {
26
+ display: block;
27
+ }
28
+ :host([fixed]) {
29
+ position: fixed;
30
+ top: 0;
31
+ left: 0;
32
+ right: 0;
33
+ z-index: 50;
34
+ }
35
+ nav {
36
+ display: flex;
37
+ align-items: center;
38
+ width: 100%;
39
+ }
40
+ ::slotted(a) {
41
+ display: inline-block;
42
+ padding: var(--spacer);
43
+ text-decoration: none !important;
44
+ }
45
+ ::slotted(.link) {
46
+ display: inline-block;
47
+ padding: var(--spacer) !important;
48
+ text-decoration: none !important;
49
+ }
50
+ `;
51
+ }
52
+
53
+ customElements.define('k-nav', Nav);
@@ -244,7 +244,7 @@ export default class PhotoViewer extends ShadowComponent {
244
244
  left: 0;
245
245
  right: 0;
246
246
  bottom: 0;
247
- z-index: 9999;
247
+ z-index: 80;
248
248
  background: rgba(0,0,0,0.9);
249
249
  padding: 2rem;
250
250
  display: none;
@@ -29,7 +29,7 @@ export default class ShadowComponent extends LitElement {
29
29
 
30
30
  const link = document.createElement('link');
31
31
  link.rel = 'stylesheet';
32
- link.href = window.kempo?.pathToStylesheet || 'https://cdn.jsdelivr.net/npm/kempo-css@1.3.11/dist/kempo.min.css';
32
+ link.href = window.kempo?.pathToStylesheet || 'https://cdn.jsdelivr.net/npm/kempo-css@2/dist/kempo.min.css';
33
33
  shadowRoot.appendChild(link);
34
34
 
35
35
  // Inject component styles if they exist
@@ -74,6 +74,7 @@ export default class ThemeSwitcher extends ShadowComponent {
74
74
  }
75
75
  button.no-btn {
76
76
  padding: var(--padding);
77
+ border-radius: var(--radius);
77
78
  }
78
79
  `;
79
80
 
@@ -384,7 +384,7 @@ class ToastContainer extends HTMLElement {
384
384
  display: flex;
385
385
  flex-direction: column;
386
386
  gap: 8px;
387
- z-index: 1000;
387
+ z-index: 90;
388
388
  pointer-events: auto;
389
389
  padding: 32px;
390
390
  box-sizing: border-box;
@@ -0,0 +1,26 @@
1
+ import { execFile } from 'child_process';
2
+
3
+ /*
4
+ Utility Functions
5
+ */
6
+
7
+ const run = (args) => new Promise((resolve) => {
8
+ const proc = execFile('node', ['bin/get_icon.js', ...args], (error, stdout, stderr) => {
9
+ resolve({ code: proc.exitCode ?? error?.code, stdout, stderr });
10
+ });
11
+ });
12
+
13
+ /*
14
+ Tests
15
+ */
16
+
17
+ export default {
18
+ 'should exit with error when no icon name provided': async ({pass, fail}) => {
19
+ const {code, stderr} = await run([]);
20
+ if(code !== 0 && stderr.includes('Usage')){
21
+ pass('Shows usage and exits with error');
22
+ } else {
23
+ fail(`Expected error exit with usage, got code=${code}, stderr="${stderr}"`);
24
+ }
25
+ },
26
+ };
@@ -0,0 +1,108 @@
1
+ import { execFile } from 'child_process';
2
+
3
+ /*
4
+ Utility Functions
5
+ */
6
+
7
+ const run = (args, stdin) => new Promise((resolve) => {
8
+ const proc = execFile('node', ['bin/highlight_code.js', ...args], (error, stdout, stderr) => {
9
+ resolve({ code: proc.exitCode ?? error?.code, stdout, stderr });
10
+ });
11
+ if(stdin !== undefined){
12
+ proc.stdin.write(stdin);
13
+ proc.stdin.end();
14
+ }
15
+ });
16
+
17
+ /*
18
+ Tests
19
+ */
20
+
21
+ export default {
22
+ 'should exit with error when no arguments provided': async ({pass, fail}) => {
23
+ const {code, stderr} = await run([]);
24
+ if(code !== 0 && stderr.includes('Usage')){
25
+ pass('Shows usage and exits with error');
26
+ } else {
27
+ fail(`Expected error exit with usage message, got code=${code}, stderr="${stderr}"`);
28
+ }
29
+ },
30
+
31
+ 'should exit with error for unknown language': async ({pass, fail}) => {
32
+ const {code, stderr} = await run(['fakeLang', 'code']);
33
+ if(code !== 0 && stderr.includes('Unknown language')){
34
+ pass('Shows unknown language error');
35
+ } else {
36
+ fail(`Expected unknown language error, got code=${code}, stderr="${stderr}"`);
37
+ }
38
+ },
39
+
40
+ 'should highlight JavaScript passed as argument': async ({pass, fail}) => {
41
+ const {stdout} = await run(['js', 'const x = 1;']);
42
+ if(stdout.includes('<pre><code class="hljs javascript">') &&
43
+ stdout.includes('</code></pre>') &&
44
+ stdout.includes('<span class="hljs-keyword">const</span>')){
45
+ pass('JavaScript highlighted correctly with wrapper');
46
+ } else {
47
+ fail(`Unexpected output: ${stdout}`);
48
+ }
49
+ },
50
+
51
+ 'should highlight HTML passed as argument': async ({pass, fail}) => {
52
+ const {stdout} = await run(['html', '<div>hello</div>']);
53
+ if(stdout.includes('<pre><code class="hljs html">') &&
54
+ stdout.includes('</code></pre>') &&
55
+ stdout.includes('hljs-name')){
56
+ pass('HTML highlighted correctly with wrapper');
57
+ } else {
58
+ fail(`Unexpected output: ${stdout}`);
59
+ }
60
+ },
61
+
62
+ 'should accept language aliases': async ({pass, fail}) => {
63
+ const {stdout} = await run(['js', 'let x = 1;']);
64
+ if(stdout.includes('class="hljs javascript"')){
65
+ pass('Alias "js" resolved to "javascript"');
66
+ } else {
67
+ fail(`Alias not resolved: ${stdout}`);
68
+ }
69
+ },
70
+
71
+ 'should read code from stdin': async ({pass, fail}) => {
72
+ const {stdout} = await run(['css'], 'body { color: red; }');
73
+ if(stdout.includes('<pre><code class="hljs css">') &&
74
+ stdout.includes('</code></pre>')){
75
+ pass('stdin input highlighted correctly');
76
+ } else {
77
+ fail(`Unexpected output: ${stdout}`);
78
+ }
79
+ },
80
+
81
+ 'should convert newlines to <br> tags': async ({pass, fail}) => {
82
+ const {stdout} = await run(['js'], 'const x = 1;\nconst y = 2;');
83
+ if(stdout.includes('<br>') && !stdout.includes('\n</code>')){
84
+ pass('Newlines converted to <br>');
85
+ } else {
86
+ fail(`Expected <br> tags: ${stdout}`);
87
+ }
88
+ },
89
+
90
+ 'should output a single line': async ({pass, fail}) => {
91
+ const {stdout} = await run(['html'], '<div>\n <p>hello</p>\n</div>');
92
+ const lines = stdout.trim().split('\n');
93
+ if(lines.length === 1){
94
+ pass('Output is a single line');
95
+ } else {
96
+ fail(`Expected 1 line, got ${lines.length}`);
97
+ }
98
+ },
99
+
100
+ 'should beautify code before highlighting': async ({pass, fail}) => {
101
+ const {stdout} = await run(['html', '<div><p>hello</p></div>']);
102
+ if(stdout.includes('<br>')){
103
+ pass('Beautifier added line breaks (converted to <br>)');
104
+ } else {
105
+ fail(`Expected beautified output with <br>: ${stdout}`);
106
+ }
107
+ },
108
+ };
@@ -0,0 +1,26 @@
1
+ import { execFile } from 'child_process';
2
+
3
+ /*
4
+ Utility Functions
5
+ */
6
+
7
+ const run = (args) => new Promise((resolve) => {
8
+ const proc = execFile('node', ['bin/list_icons.js', ...args], (error, stdout, stderr) => {
9
+ resolve({ code: proc.exitCode ?? error?.code, stdout, stderr });
10
+ });
11
+ });
12
+
13
+ /*
14
+ Tests
15
+ */
16
+
17
+ export default {
18
+ 'should exit with error when no search term provided': async ({pass, fail}) => {
19
+ const {code, stderr} = await run([]);
20
+ if(code !== 0 && stderr.includes('Usage')){
21
+ pass('Shows usage and exits with error');
22
+ } else {
23
+ fail(`Expected error exit with usage, got code=${code}, stderr="${stderr}"`);
24
+ }
25
+ },
26
+ };