kempo-ui 0.0.2 → 0.0.4
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 +149 -149
- package/.github/workflows/publish-major.yml +39 -0
- package/.github/workflows/publish-minor.yml +39 -0
- package/.github/workflows/{publish-npm.yml → publish-patch.yml} +44 -44
- package/.vscode/settings.json +2 -0
- package/CONTRIBUTING.md +149 -149
- package/README.md +0 -0
- package/dist/kempo-hljs.css +1 -0
- package/dist/kempo-vars.css +0 -0
- package/dist/src/components/Accordion.js +36 -0
- package/dist/src/components/Card.js +37 -0
- package/dist/src/components/Collapsible.js +41 -0
- package/dist/src/components/ContentSlider.js +44 -0
- package/dist/src/components/Dialog.js +113 -0
- package/dist/src/components/FocusCapture.js +7 -0
- package/dist/src/components/Icon.js +10 -0
- package/dist/src/components/Import.js +1 -0
- package/dist/src/components/PersistantCollapsible.js +1 -0
- package/dist/src/components/PhotoViewer.js +135 -0
- package/dist/src/components/Resize.js +96 -0
- package/dist/src/components/ShadowComponent.js +1 -0
- package/dist/src/components/ShowMore.js +42 -0
- package/dist/src/components/SideMenu.js +97 -0
- package/dist/src/components/Split.js +84 -0
- package/dist/src/components/Tabs.js +155 -0
- package/dist/src/components/Tags.js +69 -0
- package/dist/src/components/ThemeSwitcher.js +23 -0
- package/dist/src/components/Timestamp.js +1 -0
- package/dist/src/lit-all.min.js +120 -0
- package/dist/src/utils/debounce.js +1 -0
- package/dist/src/utils/drag.js +1 -0
- package/dist/src/utils/formatTimestamp.js +1 -0
- package/dist/src/utils/propConverters.js +1 -0
- package/dist/src/utils/watchWindowSize.js +1 -0
- package/docs/components/accordion.html +166 -0
- package/docs/components/card.html +92 -0
- package/docs/components/collapsible.html +198 -0
- package/docs/components/content-slider.html +223 -0
- package/docs/components/dialog.html +251 -0
- package/docs/components/focus-capture.html +67 -0
- package/docs/components/icon.html +158 -0
- package/docs/components/import.html +73 -0
- package/docs/components/persistant-collapsible.html +123 -0
- package/docs/components/photo-viewer.html +226 -0
- package/docs/components/resize.html +178 -0
- package/docs/components/show-more.html +129 -0
- package/docs/components/side-menu.html +159 -0
- package/docs/components/split.html +147 -0
- package/docs/components/table.html +312 -0
- package/docs/components/tableControls.html +77 -0
- package/docs/components/tableCustomFields.html +113 -0
- package/docs/components/tableFetchRecords.html +114 -0
- package/docs/components/tableFieldSortHide.html +75 -0
- package/docs/components/tablePagination.html +100 -0
- package/docs/components/tableRecordEditing.html +144 -0
- package/docs/components/tableRecordFiltering.html +88 -0
- package/docs/components/tableRecordHiding.html +80 -0
- package/docs/components/tableRecordSearching.html +75 -0
- package/docs/components/tableRecordSelection.html +75 -0
- package/docs/components/tableRowControls.html +78 -0
- package/docs/components/tableSorting.html +73 -0
- package/docs/components/tabs.html +180 -0
- package/docs/components/tags.html +110 -0
- package/docs/components/theme-switcher.html +126 -0
- package/docs/components/timestamp.html +82 -0
- package/docs/components/toast.html +319 -0
- package/docs/components/toggle.html +156 -0
- package/docs/dev.config.json +20 -0
- package/docs/icons/add.svg +1 -0
- package/docs/icons/arrow-back.svg +1 -0
- package/docs/icons/arrow-down-double.svg +1 -0
- package/docs/icons/arrow-down.svg +1 -0
- package/docs/icons/arrow-forward.svg +1 -0
- package/docs/icons/arrow-up-double.svg +1 -0
- package/docs/icons/arrow-up.svg +1 -0
- package/docs/icons/cards.svg +1 -0
- package/docs/icons/check.svg +1 -0
- package/docs/icons/chevron-left.svg +1 -0
- package/docs/icons/chevron-right.svg +1 -0
- package/docs/icons/close.svg +2 -0
- package/docs/icons/compare.svg +1 -0
- package/docs/icons/delete.svg +1 -0
- package/docs/icons/drag-handle.svg +1 -0
- package/docs/icons/drawing2.svg +124 -0
- package/docs/icons/edit.svg +1 -0
- package/docs/icons/error.svg +1 -0
- package/docs/icons/export-file.svg +1 -0
- package/docs/icons/file-text.svg +1 -0
- package/docs/icons/file.svg +1 -0
- package/docs/icons/filter-off.svg +1 -0
- package/docs/icons/filter.svg +1 -0
- package/docs/icons/first.svg +1 -0
- package/docs/icons/folder-clear.svg +1 -0
- package/docs/icons/folder-create.svg +1 -0
- package/docs/icons/folder-open.svg +1 -0
- package/docs/icons/folder.svg +1 -0
- package/docs/icons/hide.svg +1 -0
- package/docs/icons/image.svg +1 -0
- package/docs/icons/label-add.svg +1 -0
- package/docs/icons/label.svg +1 -0
- package/docs/icons/last.svg +1 -0
- package/docs/icons/menu.svg +1 -0
- package/docs/icons/mode-auto.svg +1 -0
- package/docs/icons/mode-dark.svg +1 -0
- package/docs/icons/mode-light.svg +1 -0
- package/docs/icons/open-in-browser.svg +1 -0
- package/docs/icons/pause.svg +1 -0
- package/docs/icons/play.svg +1 -0
- package/docs/icons/refresh.svg +1 -0
- package/docs/icons/remove.svg +1 -0
- package/docs/icons/save.svg +1 -0
- package/docs/icons/search.svg +1 -0
- package/docs/icons/settings.svg +1 -0
- package/docs/icons/show.svg +1 -0
- package/docs/icons/storage.svg +1 -0
- package/docs/icons/table-visibility.svg +1 -0
- package/docs/icons/tag.svg +1 -0
- package/docs/icons/tools.svg +1 -0
- package/docs/icons/trash-x.svg +1 -0
- package/docs/icons/warning.svg +1 -0
- package/docs/index.html +28 -21
- package/docs/kempo-hljs.css +1 -0
- package/docs/media/civic.jpg +0 -0
- package/docs/media/corvette.jpg +0 -0
- package/docs/media/evo.jpg +0 -0
- package/docs/media/gtr.jpg +0 -0
- package/docs/media/nsx.jpg +0 -0
- package/docs/nav.inc.html +67 -0
- package/docs/nav.inc.js +4 -0
- package/{config/production.json → docs/prod.config.json} +20 -16
- package/docs/src/components/Accordion.js +36 -0
- package/docs/src/components/Card.js +37 -0
- package/docs/src/components/Collapsible.js +41 -0
- package/docs/src/components/ContentSlider.js +44 -0
- package/docs/src/components/Dialog.js +113 -0
- package/docs/src/components/FocusCapture.js +7 -0
- package/docs/src/components/HybridComponent.js +1 -0
- package/docs/src/components/Icon.js +10 -0
- package/docs/src/components/Import.js +1 -0
- package/docs/src/components/LightComponent.js +1 -0
- package/docs/src/components/PersistantCollapsible.js +1 -0
- package/docs/src/components/PhotoViewer.js +135 -0
- package/docs/src/components/Resize.js +96 -0
- package/docs/src/components/ShadowComponent.js +1 -0
- package/docs/src/components/ShowMore.js +42 -0
- package/docs/src/components/SideMenu.js +97 -0
- package/docs/src/components/Split.js +84 -0
- package/docs/src/components/Tabs.js +155 -0
- package/docs/src/components/Tags.js +69 -0
- package/docs/src/components/ThemeSwitcher.js +23 -0
- package/docs/src/components/Timestamp.js +1 -0
- package/docs/src/lit-all.min.js +120 -0
- package/docs/src/utils/debounce.js +1 -0
- package/docs/src/utils/drag.js +1 -0
- package/docs/src/utils/formatTimestamp.js +1 -0
- package/docs/src/utils/propConverters.js +1 -0
- package/docs/src/utils/watchWindowSize.js +1 -0
- package/docs/styles.css +6 -0
- package/docs/utils/debounce.html +78 -0
- package/docs/utils/drag.html +104 -0
- package/docs/utils/formatTimestamp.html +114 -0
- package/docs/utils/propConverters.html +132 -0
- package/docs/utils/watchWindowSize.html +166 -0
- package/icons/add.svg +1 -0
- package/icons/arrow-back.svg +1 -0
- package/icons/arrow-down-double.svg +1 -0
- package/icons/arrow-down.svg +1 -0
- package/icons/arrow-forward.svg +1 -0
- package/icons/arrow-up-double.svg +1 -0
- package/icons/arrow-up.svg +1 -0
- package/icons/cards.svg +1 -0
- package/icons/check.svg +1 -0
- package/icons/chevron-left.svg +1 -0
- package/icons/chevron-right.svg +1 -0
- package/icons/close.svg +2 -0
- package/icons/compare.svg +1 -0
- package/icons/delete.svg +1 -0
- package/icons/drag-handle.svg +1 -0
- package/icons/drawing2.svg +124 -0
- package/icons/edit.svg +1 -0
- package/icons/error.svg +1 -0
- package/icons/export-file.svg +1 -0
- package/icons/file-text.svg +1 -0
- package/icons/file.svg +1 -0
- package/icons/filter-off.svg +1 -0
- package/icons/filter.svg +1 -0
- package/icons/first.svg +1 -0
- package/icons/folder-clear.svg +1 -0
- package/icons/folder-create.svg +1 -0
- package/icons/folder-open.svg +1 -0
- package/icons/folder.svg +1 -0
- package/icons/hide.svg +1 -0
- package/icons/image.svg +1 -0
- package/icons/label-add.svg +1 -0
- package/icons/label.svg +1 -0
- package/icons/last.svg +1 -0
- package/icons/menu.svg +1 -0
- package/icons/mode-auto.svg +1 -0
- package/icons/mode-dark.svg +1 -0
- package/icons/mode-light.svg +1 -0
- package/icons/open-in-browser.svg +1 -0
- package/icons/pause.svg +1 -0
- package/icons/play.svg +1 -0
- package/icons/refresh.svg +1 -0
- package/icons/remove.svg +1 -0
- package/icons/save.svg +1 -0
- package/icons/search.svg +1 -0
- package/icons/settings.svg +1 -0
- package/icons/show.svg +1 -0
- package/icons/storage.svg +1 -0
- package/icons/table-visibility.svg +1 -0
- package/icons/tag.svg +1 -0
- package/icons/tools.svg +1 -0
- package/icons/trash-x.svg +1 -0
- package/icons/warning.svg +1 -0
- package/package.json +2 -2
- package/scripts/build.js +109 -138
- package/scripts/docs.js +62 -60
- package/src/components/Accordion.js +229 -0
- package/src/components/Card.js +66 -0
- package/src/components/Collapsible.js +109 -0
- package/src/components/ContentSlider.js +205 -0
- package/src/components/Dialog.js +368 -0
- package/src/components/FocusCapture.js +23 -0
- package/src/components/HybridComponent.js +40 -40
- package/src/components/Icon.js +155 -0
- package/src/components/Import.js +104 -0
- package/src/components/LightComponent.js +32 -32
- package/src/components/PersistantCollapsible.js +69 -0
- package/src/components/PhotoViewer.js +368 -0
- package/src/components/Resize.js +210 -0
- package/src/components/ShadowComponent.js +32 -17
- package/src/components/ShowMore.js +109 -0
- package/src/components/SideMenu.js +167 -0
- package/src/components/Sortable.js +193 -0
- package/src/components/Split.js +192 -0
- package/src/components/Table.js +1202 -0
- package/src/components/Tabs.js +428 -0
- package/src/components/Tags.js +253 -0
- package/src/components/ThemeSwitcher.js +108 -0
- package/src/components/Timestamp.js +31 -0
- package/src/components/Toast.js +454 -0
- package/src/components/Toggle.js +173 -0
- package/src/components/tableControls/DeleteRecord.js +29 -0
- package/src/components/tableControls/Edit.js +88 -0
- package/src/components/tableControls/ExportCSV.js +71 -0
- package/src/components/tableControls/ExportJson.js +55 -0
- package/src/components/tableControls/FieldSortHide.js +76 -0
- package/src/components/tableControls/Filters.js +114 -0
- package/src/components/tableControls/FirstPage.js +65 -0
- package/src/components/tableControls/HiddenCount.js +45 -0
- package/src/components/tableControls/Hide.js +34 -0
- package/src/components/tableControls/LastPage.js +65 -0
- package/src/components/tableControls/NextPage.js +65 -0
- package/src/components/tableControls/PageSelect.js +109 -0
- package/src/components/tableControls/PageSize.js +68 -0
- package/src/components/tableControls/PrevPage.js +65 -0
- package/src/components/tableControls/Search.js +58 -0
- package/src/components/tableControls/ShowAll.js +34 -0
- package/src/components/tableControls/TableControl.js +105 -0
- package/src/kempo-hljs.css +146 -0
- package/src/utils/debounce.js +9 -0
- package/src/utils/drag.js +80 -0
- package/src/utils/formatTimestamp.js +27 -0
- package/src/utils/propConverters.js +11 -0
- package/src/utils/toTitleCase.js +9 -0
- package/src/utils/watchWindowSize.js +16 -0
- package/tests/HybridComponent.browser-test.js +214 -214
- package/tests/LightComponent.browser-test.js +169 -169
- package/tests/ShadowComponent.browser-test.js +130 -130
- package/config/development.json +0 -14
- package/docs/components/ShadowComponent.js +0 -1
- package/src/utils/cli.js +0 -43
- package/src/utils/fs-utils.js +0 -41
- /package/{docs → dist/src}/components/HybridComponent.js +0 -0
- /package/{docs → dist/src}/components/LightComponent.js +0 -0
- /package/docs/{utils → src/utils}/cli.js +0 -0
- /package/docs/{utils → src/utils}/fs-utils.js +0 -0
|
@@ -1,214 +1,214 @@
|
|
|
1
|
-
import HybridComponent from '/src/components/HybridComponent.js';
|
|
2
|
-
import { html } from '/src/lit-all.min.js';
|
|
3
|
-
|
|
4
|
-
class TestHybridComponent extends HybridComponent {
|
|
5
|
-
render() {
|
|
6
|
-
return html`<p>Shadow content</p>`;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
renderLightDom() {
|
|
10
|
-
return html`<span>Light content</span>`;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
customElements.define('test-hybrid-component', TestHybridComponent);
|
|
15
|
-
|
|
16
|
-
export default {
|
|
17
|
-
'should inherit shadow root with stylesheet from ShadowComponent': async ({pass, fail, log}) => {
|
|
18
|
-
const component = new TestHybridComponent();
|
|
19
|
-
document.body.appendChild(component);
|
|
20
|
-
|
|
21
|
-
await new Promise(resolve => setTimeout(resolve, 0));
|
|
22
|
-
|
|
23
|
-
if(!component.shadowRoot) {
|
|
24
|
-
document.body.removeChild(component);
|
|
25
|
-
fail('Component should have shadow root');
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const stylesheetLink = component.shadowRoot.querySelector('link[href="/kempo.min.css"]');
|
|
30
|
-
if(!stylesheetLink) {
|
|
31
|
-
document.body.removeChild(component);
|
|
32
|
-
fail('Shadow root should contain kempo.min.css link');
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
log('✓ Inherited shadow root with stylesheet from ShadowComponent');
|
|
37
|
-
document.body.removeChild(component);
|
|
38
|
-
pass('HybridComponent inherits ShadowComponent functionality');
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
'should create light root for light DOM rendering': async ({pass, fail, log}) => {
|
|
42
|
-
const component = new TestHybridComponent();
|
|
43
|
-
document.body.appendChild(component);
|
|
44
|
-
|
|
45
|
-
await new Promise(resolve => setTimeout(resolve, 0));
|
|
46
|
-
|
|
47
|
-
if(!component.lightRoot) {
|
|
48
|
-
document.body.removeChild(component);
|
|
49
|
-
fail('Component should have lightRoot property');
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if(component.lightRoot.tagName !== 'DIV') {
|
|
54
|
-
document.body.removeChild(component);
|
|
55
|
-
fail('lightRoot should be a div element');
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if(component.lightRoot.style.display !== 'contents') {
|
|
60
|
-
document.body.removeChild(component);
|
|
61
|
-
fail('lightRoot should have display: contents');
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if(component.lightRoot.slot !== 'lightRoot') {
|
|
66
|
-
document.body.removeChild(component);
|
|
67
|
-
fail('lightRoot should have slot="lightRoot"');
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
log('✓ Light root properly configured for hybrid rendering');
|
|
72
|
-
document.body.removeChild(component);
|
|
73
|
-
pass('HybridComponent creates proper light root');
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
'should render shadow DOM content': async ({pass, fail, log}) => {
|
|
77
|
-
const component = new TestHybridComponent();
|
|
78
|
-
document.body.appendChild(component);
|
|
79
|
-
|
|
80
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
81
|
-
|
|
82
|
-
const shadowParagraph = component.renderRoot.querySelector('p');
|
|
83
|
-
if(!shadowParagraph) {
|
|
84
|
-
document.body.removeChild(component);
|
|
85
|
-
fail('Shadow DOM should contain paragraph element');
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if(shadowParagraph.textContent !== 'Shadow content') {
|
|
90
|
-
document.body.removeChild(component);
|
|
91
|
-
fail(`Expected "Shadow content", got "${shadowParagraph.textContent}"`);
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
log('✓ Shadow DOM content rendered correctly');
|
|
96
|
-
document.body.removeChild(component);
|
|
97
|
-
pass('HybridComponent renders shadow DOM content');
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
'should render light DOM content': async ({pass, fail, log}) => {
|
|
101
|
-
const component = new TestHybridComponent();
|
|
102
|
-
document.body.appendChild(component);
|
|
103
|
-
|
|
104
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
105
|
-
|
|
106
|
-
const lightSpan = component.lightRoot.querySelector('span');
|
|
107
|
-
if(!lightSpan) {
|
|
108
|
-
document.body.removeChild(component);
|
|
109
|
-
fail('Light DOM should contain span element');
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if(lightSpan.textContent !== 'Light content') {
|
|
114
|
-
document.body.removeChild(component);
|
|
115
|
-
fail(`Expected "Light content", got "${lightSpan.textContent}"`);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
log('✓ Light DOM content rendered correctly');
|
|
120
|
-
document.body.removeChild(component);
|
|
121
|
-
pass('HybridComponent renders light DOM content');
|
|
122
|
-
},
|
|
123
|
-
|
|
124
|
-
'should render both shadow and light DOM simultaneously': async ({pass, fail, log}) => {
|
|
125
|
-
const component = new TestHybridComponent();
|
|
126
|
-
document.body.appendChild(component);
|
|
127
|
-
|
|
128
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
129
|
-
|
|
130
|
-
const shadowContent = component.renderRoot.querySelector('p');
|
|
131
|
-
const lightContent = component.lightRoot.querySelector('span');
|
|
132
|
-
|
|
133
|
-
if(!shadowContent || shadowContent.textContent !== 'Shadow content') {
|
|
134
|
-
document.body.removeChild(component);
|
|
135
|
-
fail('Shadow content should be present');
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if(!lightContent || lightContent.textContent !== 'Light content') {
|
|
140
|
-
document.body.removeChild(component);
|
|
141
|
-
fail('Light content should be present');
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
log('✓ Both shadow and light content rendered simultaneously');
|
|
146
|
-
document.body.removeChild(component);
|
|
147
|
-
pass('HybridComponent renders both DOM types');
|
|
148
|
-
},
|
|
149
|
-
|
|
150
|
-
'should preserve natural children alongside hybrid content': async ({pass, fail, log}) => {
|
|
151
|
-
const component = new TestHybridComponent();
|
|
152
|
-
const naturalChild = document.createElement('div');
|
|
153
|
-
naturalChild.textContent = 'Natural child';
|
|
154
|
-
component.appendChild(naturalChild);
|
|
155
|
-
document.body.appendChild(component);
|
|
156
|
-
|
|
157
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
158
|
-
|
|
159
|
-
const foundNaturalChild = component.querySelector('div');
|
|
160
|
-
if(!foundNaturalChild || foundNaturalChild.textContent !== 'Natural child') {
|
|
161
|
-
document.body.removeChild(component);
|
|
162
|
-
fail('Natural child should be preserved');
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const shadowContent = component.renderRoot.querySelector('p');
|
|
167
|
-
const lightContent = component.lightRoot.querySelector('span');
|
|
168
|
-
|
|
169
|
-
if(!shadowContent || !lightContent) {
|
|
170
|
-
document.body.removeChild(component);
|
|
171
|
-
fail('Both rendered contents should be present with natural children');
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
log('✓ Natural children preserved alongside hybrid rendering');
|
|
176
|
-
document.body.removeChild(component);
|
|
177
|
-
pass('HybridComponent preserves natural children');
|
|
178
|
-
},
|
|
179
|
-
|
|
180
|
-
'should handle slot system for light root': async ({pass, fail, log}) => {
|
|
181
|
-
const component = new TestHybridComponent();
|
|
182
|
-
document.body.appendChild(component);
|
|
183
|
-
|
|
184
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
185
|
-
await component.updateComplete;
|
|
186
|
-
|
|
187
|
-
// The slot should be in the render root (which is the div container)
|
|
188
|
-
const slot = component.renderRoot.querySelector('slot[name="lightRoot"]');
|
|
189
|
-
const lightContent = component.lightRoot.querySelector('span');
|
|
190
|
-
|
|
191
|
-
if(!slot && !lightContent) {
|
|
192
|
-
document.body.removeChild(component);
|
|
193
|
-
fail('Either slot should exist or light content should be rendered via slotting');
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if(component.lightRoot.slot !== 'lightRoot') {
|
|
198
|
-
document.body.removeChild(component);
|
|
199
|
-
fail('lightRoot should be assigned to lightRoot slot');
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Check that light content is actually rendered
|
|
204
|
-
if(!lightContent || lightContent.textContent !== 'Light content') {
|
|
205
|
-
document.body.removeChild(component);
|
|
206
|
-
fail('Light content should be rendered through slot system');
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
log('✓ Slot system working - light content rendered');
|
|
211
|
-
document.body.removeChild(component);
|
|
212
|
-
pass('HybridComponent implements proper slot system');
|
|
213
|
-
}
|
|
214
|
-
};
|
|
1
|
+
import HybridComponent from '/src/components/HybridComponent.js';
|
|
2
|
+
import { html } from '/src/lit-all.min.js';
|
|
3
|
+
|
|
4
|
+
class TestHybridComponent extends HybridComponent {
|
|
5
|
+
render() {
|
|
6
|
+
return html`<p>Shadow content</p>`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
renderLightDom() {
|
|
10
|
+
return html`<span>Light content</span>`;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
customElements.define('test-hybrid-component', TestHybridComponent);
|
|
15
|
+
|
|
16
|
+
export default {
|
|
17
|
+
'should inherit shadow root with stylesheet from ShadowComponent': async ({pass, fail, log}) => {
|
|
18
|
+
const component = new TestHybridComponent();
|
|
19
|
+
document.body.appendChild(component);
|
|
20
|
+
|
|
21
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
22
|
+
|
|
23
|
+
if(!component.shadowRoot) {
|
|
24
|
+
document.body.removeChild(component);
|
|
25
|
+
fail('Component should have shadow root');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const stylesheetLink = component.shadowRoot.querySelector('link[href="/kempo.min.css"]');
|
|
30
|
+
if(!stylesheetLink) {
|
|
31
|
+
document.body.removeChild(component);
|
|
32
|
+
fail('Shadow root should contain kempo.min.css link');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
log('✓ Inherited shadow root with stylesheet from ShadowComponent');
|
|
37
|
+
document.body.removeChild(component);
|
|
38
|
+
pass('HybridComponent inherits ShadowComponent functionality');
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
'should create light root for light DOM rendering': async ({pass, fail, log}) => {
|
|
42
|
+
const component = new TestHybridComponent();
|
|
43
|
+
document.body.appendChild(component);
|
|
44
|
+
|
|
45
|
+
await new Promise(resolve => setTimeout(resolve, 0));
|
|
46
|
+
|
|
47
|
+
if(!component.lightRoot) {
|
|
48
|
+
document.body.removeChild(component);
|
|
49
|
+
fail('Component should have lightRoot property');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if(component.lightRoot.tagName !== 'DIV') {
|
|
54
|
+
document.body.removeChild(component);
|
|
55
|
+
fail('lightRoot should be a div element');
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if(component.lightRoot.style.display !== 'contents') {
|
|
60
|
+
document.body.removeChild(component);
|
|
61
|
+
fail('lightRoot should have display: contents');
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if(component.lightRoot.slot !== 'lightRoot') {
|
|
66
|
+
document.body.removeChild(component);
|
|
67
|
+
fail('lightRoot should have slot="lightRoot"');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
log('✓ Light root properly configured for hybrid rendering');
|
|
72
|
+
document.body.removeChild(component);
|
|
73
|
+
pass('HybridComponent creates proper light root');
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
'should render shadow DOM content': async ({pass, fail, log}) => {
|
|
77
|
+
const component = new TestHybridComponent();
|
|
78
|
+
document.body.appendChild(component);
|
|
79
|
+
|
|
80
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
81
|
+
|
|
82
|
+
const shadowParagraph = component.renderRoot.querySelector('p');
|
|
83
|
+
if(!shadowParagraph) {
|
|
84
|
+
document.body.removeChild(component);
|
|
85
|
+
fail('Shadow DOM should contain paragraph element');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if(shadowParagraph.textContent !== 'Shadow content') {
|
|
90
|
+
document.body.removeChild(component);
|
|
91
|
+
fail(`Expected "Shadow content", got "${shadowParagraph.textContent}"`);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
log('✓ Shadow DOM content rendered correctly');
|
|
96
|
+
document.body.removeChild(component);
|
|
97
|
+
pass('HybridComponent renders shadow DOM content');
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
'should render light DOM content': async ({pass, fail, log}) => {
|
|
101
|
+
const component = new TestHybridComponent();
|
|
102
|
+
document.body.appendChild(component);
|
|
103
|
+
|
|
104
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
105
|
+
|
|
106
|
+
const lightSpan = component.lightRoot.querySelector('span');
|
|
107
|
+
if(!lightSpan) {
|
|
108
|
+
document.body.removeChild(component);
|
|
109
|
+
fail('Light DOM should contain span element');
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if(lightSpan.textContent !== 'Light content') {
|
|
114
|
+
document.body.removeChild(component);
|
|
115
|
+
fail(`Expected "Light content", got "${lightSpan.textContent}"`);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
log('✓ Light DOM content rendered correctly');
|
|
120
|
+
document.body.removeChild(component);
|
|
121
|
+
pass('HybridComponent renders light DOM content');
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
'should render both shadow and light DOM simultaneously': async ({pass, fail, log}) => {
|
|
125
|
+
const component = new TestHybridComponent();
|
|
126
|
+
document.body.appendChild(component);
|
|
127
|
+
|
|
128
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
129
|
+
|
|
130
|
+
const shadowContent = component.renderRoot.querySelector('p');
|
|
131
|
+
const lightContent = component.lightRoot.querySelector('span');
|
|
132
|
+
|
|
133
|
+
if(!shadowContent || shadowContent.textContent !== 'Shadow content') {
|
|
134
|
+
document.body.removeChild(component);
|
|
135
|
+
fail('Shadow content should be present');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if(!lightContent || lightContent.textContent !== 'Light content') {
|
|
140
|
+
document.body.removeChild(component);
|
|
141
|
+
fail('Light content should be present');
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
log('✓ Both shadow and light content rendered simultaneously');
|
|
146
|
+
document.body.removeChild(component);
|
|
147
|
+
pass('HybridComponent renders both DOM types');
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
'should preserve natural children alongside hybrid content': async ({pass, fail, log}) => {
|
|
151
|
+
const component = new TestHybridComponent();
|
|
152
|
+
const naturalChild = document.createElement('div');
|
|
153
|
+
naturalChild.textContent = 'Natural child';
|
|
154
|
+
component.appendChild(naturalChild);
|
|
155
|
+
document.body.appendChild(component);
|
|
156
|
+
|
|
157
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
158
|
+
|
|
159
|
+
const foundNaturalChild = component.querySelector('div');
|
|
160
|
+
if(!foundNaturalChild || foundNaturalChild.textContent !== 'Natural child') {
|
|
161
|
+
document.body.removeChild(component);
|
|
162
|
+
fail('Natural child should be preserved');
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const shadowContent = component.renderRoot.querySelector('p');
|
|
167
|
+
const lightContent = component.lightRoot.querySelector('span');
|
|
168
|
+
|
|
169
|
+
if(!shadowContent || !lightContent) {
|
|
170
|
+
document.body.removeChild(component);
|
|
171
|
+
fail('Both rendered contents should be present with natural children');
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
log('✓ Natural children preserved alongside hybrid rendering');
|
|
176
|
+
document.body.removeChild(component);
|
|
177
|
+
pass('HybridComponent preserves natural children');
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
'should handle slot system for light root': async ({pass, fail, log}) => {
|
|
181
|
+
const component = new TestHybridComponent();
|
|
182
|
+
document.body.appendChild(component);
|
|
183
|
+
|
|
184
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
185
|
+
await component.updateComplete;
|
|
186
|
+
|
|
187
|
+
// The slot should be in the render root (which is the div container)
|
|
188
|
+
const slot = component.renderRoot.querySelector('slot[name="lightRoot"]');
|
|
189
|
+
const lightContent = component.lightRoot.querySelector('span');
|
|
190
|
+
|
|
191
|
+
if(!slot && !lightContent) {
|
|
192
|
+
document.body.removeChild(component);
|
|
193
|
+
fail('Either slot should exist or light content should be rendered via slotting');
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if(component.lightRoot.slot !== 'lightRoot') {
|
|
198
|
+
document.body.removeChild(component);
|
|
199
|
+
fail('lightRoot should be assigned to lightRoot slot');
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Check that light content is actually rendered
|
|
204
|
+
if(!lightContent || lightContent.textContent !== 'Light content') {
|
|
205
|
+
document.body.removeChild(component);
|
|
206
|
+
fail('Light content should be rendered through slot system');
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
log('✓ Slot system working - light content rendered');
|
|
211
|
+
document.body.removeChild(component);
|
|
212
|
+
pass('HybridComponent implements proper slot system');
|
|
213
|
+
}
|
|
214
|
+
};
|