tosijs-ui 1.5.6 → 1.5.8
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/dist/doc-browser.js +77 -66
- package/dist/form.d.ts +1 -0
- package/dist/form.js +20 -2
- package/dist/icon-data.js +2 -2
- package/dist/icons.d.ts +4 -1
- package/dist/icons.js +186 -136
- package/dist/iife.js +36 -36
- package/dist/iife.js.map +8 -8
- package/dist/notifications.d.ts +1 -5
- package/dist/notifications.js +3 -12
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
package/dist/doc-browser.js
CHANGED
|
@@ -288,8 +288,8 @@ export function createDocBrowser(options) {
|
|
|
288
288
|
}
|
|
289
289
|
testResultsResolve(allResults);
|
|
290
290
|
testResultsResolve = undefined;
|
|
291
|
-
// Post results to dev server on localhost
|
|
292
|
-
if (isLocalhost) {
|
|
291
|
+
// Post results to dev server on localhost (not from test iframes)
|
|
292
|
+
if (isLocalhost && !isTestFrame) {
|
|
293
293
|
fetch('/report', {
|
|
294
294
|
method: 'POST',
|
|
295
295
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -680,17 +680,46 @@ export function createDocBrowser(options) {
|
|
|
680
680
|
lines.unshift(`**Summary: ${totalPassed} passed, ${totalFailed} failed**`, '');
|
|
681
681
|
return lines.join('\n');
|
|
682
682
|
}
|
|
683
|
+
// Detect if running as background test iframe
|
|
684
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
685
|
+
const isTestFrame = searchParams.get('_testMode') === '1';
|
|
686
|
+
const testFrameFilename = isTestFrame
|
|
687
|
+
? window.location.search.substring(1).split('&')[0]
|
|
688
|
+
: null;
|
|
683
689
|
// Listen for test completion events
|
|
684
690
|
container.addEventListener('testcomplete', ((event) => {
|
|
685
691
|
handleTestComplete(event);
|
|
686
692
|
updateTestWidget();
|
|
693
|
+
// If running in test iframe, post results to parent
|
|
694
|
+
if (isTestFrame && window.parent !== window && testFrameFilename) {
|
|
695
|
+
const { results } = event.detail;
|
|
696
|
+
window.parent.postMessage({ type: 'tosi-test-results', filename: testFrameFilename, results }, '*');
|
|
697
|
+
}
|
|
687
698
|
}));
|
|
699
|
+
// If running as test iframe, signal when all tests on this page are done
|
|
700
|
+
if (isTestFrame && testFrameFilename) {
|
|
701
|
+
const signalDone = () => {
|
|
702
|
+
const examples = container.querySelectorAll('tosi-example');
|
|
703
|
+
const withTests = [...examples].filter((ex) => ex.classList.contains('-has-tests'));
|
|
704
|
+
const running = withTests.filter((ex) => ex.classList.contains('-test-running'));
|
|
705
|
+
if (withTests.length > 0 && running.length === 0) {
|
|
706
|
+
window.parent.postMessage({ type: 'tosi-tests-done', filename: testFrameFilename }, '*');
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
setTimeout(signalDone, 100);
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
// Give time for examples to start running
|
|
713
|
+
setTimeout(signalDone, 500);
|
|
714
|
+
}
|
|
688
715
|
// Background test runner for all doc pages
|
|
689
716
|
const runBackgroundTests = async () => {
|
|
690
717
|
if (backgroundTestsStarted)
|
|
691
718
|
return;
|
|
692
719
|
if (!testManager.enabled.value)
|
|
693
720
|
return;
|
|
721
|
+
if (isTestFrame)
|
|
722
|
+
return; // Don't run background tests in test iframe
|
|
694
723
|
backgroundTestsStarted = true;
|
|
695
724
|
// Find all docs that have test blocks
|
|
696
725
|
const docsWithTests = docs.filter((doc) => doc.text.includes('```test'));
|
|
@@ -699,89 +728,71 @@ export function createDocBrowser(options) {
|
|
|
699
728
|
setTestWidgetRunning();
|
|
700
729
|
}
|
|
701
730
|
if (pagesWithTests === 0) {
|
|
702
|
-
// No tests to run, resolve immediately
|
|
703
731
|
if (testResultsResolve) {
|
|
704
732
|
testResultsResolve({ passed: 0, failed: 0, pages: {} });
|
|
705
733
|
testResultsResolve = undefined;
|
|
706
734
|
}
|
|
707
735
|
return;
|
|
708
736
|
}
|
|
709
|
-
|
|
737
|
+
const currentFilename = String(app.currentDoc.filename);
|
|
738
|
+
// Create a hidden iframe that loads the full page
|
|
710
739
|
const testFrame = document.createElement('iframe');
|
|
711
740
|
testFrame.style.cssText =
|
|
712
741
|
'position: fixed; left: 0; top: 0; width: 800px; height: 600px; opacity: 0; pointer-events: none;';
|
|
713
742
|
document.body.appendChild(testFrame);
|
|
714
|
-
|
|
743
|
+
// Listen for test results posted from the iframe
|
|
744
|
+
const messageHandler = (event) => {
|
|
745
|
+
if (event.data?.type !== 'tosi-test-results')
|
|
746
|
+
return;
|
|
747
|
+
const { filename, results } = event.data;
|
|
748
|
+
if (!pageTestResults[filename]) {
|
|
749
|
+
pageTestResults[filename] = {
|
|
750
|
+
passed: true,
|
|
751
|
+
tests: [],
|
|
752
|
+
totalPassed: 0,
|
|
753
|
+
totalFailed: 0,
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
const pageResults = pageTestResults[filename];
|
|
757
|
+
pageResults.tests.push(...results.tests);
|
|
758
|
+
pageResults.totalPassed += results.passed;
|
|
759
|
+
pageResults.totalFailed += results.failed;
|
|
760
|
+
pageResults.passed = pageResults.totalFailed === 0;
|
|
761
|
+
updateDocTestStatus(filename);
|
|
762
|
+
updateTestWidget();
|
|
763
|
+
};
|
|
764
|
+
window.addEventListener('message', messageHandler);
|
|
715
765
|
for (const doc of docsWithTests) {
|
|
716
|
-
// Skip current page
|
|
717
|
-
if (doc.filename === currentFilename)
|
|
766
|
+
// Skip current page — it runs tests naturally
|
|
767
|
+
if (doc.filename === currentFilename)
|
|
718
768
|
continue;
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
769
|
+
// Navigate iframe to the page
|
|
770
|
+
const base = window.location.origin + window.location.pathname;
|
|
771
|
+
testFrame.src = `${base}?${doc.filename}&_testMode=1`;
|
|
772
|
+
// Wait for the iframe to signal it's done (max 30s per page)
|
|
773
|
+
await new Promise((resolve) => {
|
|
774
|
+
const deadline = Date.now() + 30_000;
|
|
775
|
+
const onDone = (event) => {
|
|
776
|
+
if (event.data?.type === 'tosi-tests-done' &&
|
|
777
|
+
event.data.filename === doc.filename) {
|
|
778
|
+
window.removeEventListener('message', onDone);
|
|
779
|
+
resolve();
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
window.addEventListener('message', onDone);
|
|
783
|
+
setTimeout(() => {
|
|
784
|
+
window.removeEventListener('message', onDone);
|
|
785
|
+
resolve();
|
|
786
|
+
}, deadline - Date.now());
|
|
734
787
|
});
|
|
735
|
-
testContainer.appendChild(viewer);
|
|
736
|
-
// Listen for test results from this container
|
|
737
|
-
const handleBgTest = (event) => {
|
|
738
|
-
const { results } = event.detail;
|
|
739
|
-
const pageResults = pageTestResults[doc.filename];
|
|
740
|
-
pageResults.tests.push(...results.tests);
|
|
741
|
-
pageResults.totalPassed += results.passed;
|
|
742
|
-
pageResults.totalFailed += results.failed;
|
|
743
|
-
pageResults.passed = pageResults.totalFailed === 0;
|
|
744
|
-
updateDocTestStatus(doc.filename);
|
|
745
|
-
updateTestWidget();
|
|
746
|
-
};
|
|
747
|
-
testContainer.addEventListener('testcomplete', handleBgTest);
|
|
748
|
-
// Append to iframe for execution
|
|
749
|
-
const frameDoc = testFrame.contentDocument;
|
|
750
|
-
if (frameDoc) {
|
|
751
|
-
frameDoc.body.innerHTML = '';
|
|
752
|
-
frameDoc.body.appendChild(testContainer);
|
|
753
|
-
// Wait for all live examples with tests to finish (max 30s per page)
|
|
754
|
-
await new Promise((resolve) => {
|
|
755
|
-
const deadline = Date.now() + 30_000;
|
|
756
|
-
const checkDone = () => {
|
|
757
|
-
if (Date.now() > deadline) {
|
|
758
|
-
resolve();
|
|
759
|
-
return;
|
|
760
|
-
}
|
|
761
|
-
const examples = testContainer.querySelectorAll('tosi-example');
|
|
762
|
-
const withTests = [...examples].filter((ex) => ex.classList.contains('-has-tests'));
|
|
763
|
-
const running = withTests.filter((ex) => ex.classList.contains('-test-running'));
|
|
764
|
-
if (withTests.length > 0 && running.length === 0) {
|
|
765
|
-
resolve();
|
|
766
|
-
}
|
|
767
|
-
else {
|
|
768
|
-
setTimeout(checkDone, 100);
|
|
769
|
-
}
|
|
770
|
-
};
|
|
771
|
-
// Give initial render time to start
|
|
772
|
-
setTimeout(checkDone, 200);
|
|
773
|
-
});
|
|
774
|
-
}
|
|
775
788
|
markPageTested(doc.filename);
|
|
776
789
|
}
|
|
777
790
|
// Clean up
|
|
791
|
+
window.removeEventListener('message', messageHandler);
|
|
778
792
|
testFrame.remove();
|
|
779
793
|
// Mark current page as tested if it has tests
|
|
780
794
|
if (docsWithTests.some((d) => d.filename === currentFilename)) {
|
|
781
|
-
|
|
782
|
-
setTimeout(() => {
|
|
783
|
-
markPageTested(currentFilename);
|
|
784
|
-
}, 1000);
|
|
795
|
+
setTimeout(() => markPageTested(currentFilename), 1000);
|
|
785
796
|
}
|
|
786
797
|
};
|
|
787
798
|
// Run background tests when enabled (initially or when toggled on)
|
package/dist/form.d.ts
CHANGED
|
@@ -96,6 +96,7 @@ export declare class TosiForm extends XinComponent {
|
|
|
96
96
|
}, isValid: boolean) => void;
|
|
97
97
|
connectedCallback(): void;
|
|
98
98
|
private handleElementChange;
|
|
99
|
+
private syncFieldValues;
|
|
99
100
|
private initializeNamedElements;
|
|
100
101
|
}
|
|
101
102
|
/** @deprecated Use TosiField instead */
|
package/dist/form.js
CHANGED
|
@@ -669,7 +669,8 @@ export class TosiForm extends XinComponent {
|
|
|
669
669
|
handleSubmit = (event) => {
|
|
670
670
|
event.preventDefault();
|
|
671
671
|
event.stopPropagation();
|
|
672
|
-
//
|
|
672
|
+
// Sync field values before submitting
|
|
673
|
+
this.syncFieldValues();
|
|
673
674
|
const value = this.fields;
|
|
674
675
|
this.submitCallback(value, this.isValid);
|
|
675
676
|
};
|
|
@@ -696,13 +697,30 @@ export class TosiForm extends XinComponent {
|
|
|
696
697
|
this.fields[name] = target.value;
|
|
697
698
|
}
|
|
698
699
|
};
|
|
700
|
+
syncFieldValues() {
|
|
701
|
+
const formValue = this.fields;
|
|
702
|
+
const namedElements = this.querySelectorAll('[name], [key]');
|
|
703
|
+
for (const el of namedElements) {
|
|
704
|
+
const key = el.getAttribute('name') || el.getAttribute('key');
|
|
705
|
+
if (!key)
|
|
706
|
+
continue;
|
|
707
|
+
if (formValue[key] === undefined) {
|
|
708
|
+
const val = el.value ?? el.getAttribute('value');
|
|
709
|
+
if (val != null) {
|
|
710
|
+
formValue[key] = val;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
699
715
|
initializeNamedElements() {
|
|
700
716
|
const formValue = this.fields;
|
|
701
717
|
// Handle both 'name' (formAssociated) and 'key' (tosi-field) attributes
|
|
702
718
|
const namedElements = this.querySelectorAll('[name], [key]');
|
|
703
719
|
for (const el of namedElements) {
|
|
704
720
|
const key = el.getAttribute('name') || el.getAttribute('key');
|
|
705
|
-
if (key
|
|
721
|
+
if (!key)
|
|
722
|
+
continue;
|
|
723
|
+
if (formValue[key] !== undefined) {
|
|
706
724
|
;
|
|
707
725
|
el.value = formValue[key];
|
|
708
726
|
}
|
package/dist/icon-data.js
CHANGED
|
@@ -68,7 +68,7 @@ export default {
|
|
|
68
68
|
zapOff: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><polyline points=\"12.41 6.75 13 2 10.57 4.92\"></polyline><polyline points=\"18.57 12.91 21 10 15.66 10\"></polyline><polyline points=\"8 8 3 14 12 14 11 22 16 16\"></polyline><line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\"></line></svg>",
|
|
69
69
|
x: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg>",
|
|
70
70
|
barChart: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><line x1=\"12\" y1=\"20\" x2=\"12\" y2=\"10\"></line><line x1=\"18\" y1=\"20\" x2=\"18\" y2=\"4\"></line><line x1=\"6\" y1=\"20\" x2=\"6\" y2=\"16\"></line></svg>",
|
|
71
|
-
lock: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path></svg>",
|
|
71
|
+
lock: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><rect x=\"3\" y=\"11\" width=\"18\" height=\"11\" rx=\"2\" ry=\"2\"></rect><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"></path></svg> ",
|
|
72
72
|
logIn: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><path d=\"M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4\"></path><polyline points=\"10 17 15 12 10 7\"></polyline><line x1=\"15\" y1=\"12\" x2=\"3\" y2=\"12\"></line></svg>",
|
|
73
73
|
shoppingBag: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><path d=\"M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z\"></path><line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"></line><path d=\"M16 10a4 4 0 0 1-8 0\"></path></svg>",
|
|
74
74
|
divide: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"6\" r=\"2\"></circle><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line><circle cx=\"12\" cy=\"18\" r=\"2\"></circle></svg>",
|
|
@@ -142,7 +142,7 @@ export default {
|
|
|
142
142
|
rss: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><path d=\"M4 11a9 9 0 0 1 9 9\"></path><path d=\"M4 4a16 16 0 0 1 16 16\"></path><circle cx=\"5\" cy=\"19\" r=\"1\"></circle></svg>",
|
|
143
143
|
wifi: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><path d=\"M5 12.55a11 11 0 0 1 14.08 0\"></path><path d=\"M1.42 9a16 16 0 0 1 21.16 0\"></path><path d=\"M8.53 16.11a6 6 0 0 1 6.95 0\"></path><line x1=\"12\" y1=\"20\" x2=\"12.01\" y2=\"20\"></line></svg>",
|
|
144
144
|
watch: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"7\"></circle><polyline points=\"12 9 12 12 13.5 13.5\"></polyline><path d=\"M16.51 17.35l-.35 3.83a2 2 0 0 1-2 1.82H9.83a2 2 0 0 1-2-1.82l-.35-3.83m.01-10.7l.35-3.83A2 2 0 0 1 9.83 1h4.35a2 2 0 0 1 2 1.82l.35 3.83\"></path></svg>",
|
|
145
|
-
info: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12
|
|
145
|
+
info: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"7.75\"></line></svg>",
|
|
146
146
|
userX: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><path d=\"M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2\"></path><circle cx=\"8.5\" cy=\"7\" r=\"4\"></circle><line x1=\"18\" y1=\"8\" x2=\"23\" y2=\"13\"></line><line x1=\"23\" y1=\"8\" x2=\"18\" y2=\"13\"></line></svg>",
|
|
147
147
|
loader: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"6\"></line><line x1=\"12\" y1=\"18\" x2=\"12\" y2=\"22\"></line><line x1=\"4.93\" y1=\"4.93\" x2=\"7.76\" y2=\"7.76\"></line><line x1=\"16.24\" y1=\"16.24\" x2=\"19.07\" y2=\"19.07\"></line><line x1=\"2\" y1=\"12\" x2=\"6\" y2=\"12\"></line><line x1=\"18\" y1=\"12\" x2=\"22\" y2=\"12\"></line><line x1=\"4.93\" y1=\"19.07\" x2=\"7.76\" y2=\"16.24\"></line><line x1=\"16.24\" y1=\"7.76\" x2=\"19.07\" y2=\"4.93\"></line></svg>",
|
|
148
148
|
folderPlus: "<svg class=\"stroked\" viewBox=\"0 0 24 24\"><path d=\"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z\"></path><line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"17\"></line><line x1=\"9\" y1=\"14\" x2=\"15\" y2=\"14\"></line></svg>",
|
package/dist/icons.d.ts
CHANGED
|
@@ -6,8 +6,10 @@ export declare const defineIcons: (newIcons: {
|
|
|
6
6
|
export declare const svg2DataUrl: (icon: Element, fill?: string, stroke?: string, strokeWidth?: number) => string;
|
|
7
7
|
export interface IconRule {
|
|
8
8
|
prefix: string | RegExp;
|
|
9
|
-
apply: (baseName: string, match: RegExpMatchArray | string, parts: ElementPart[]) => Element | null;
|
|
9
|
+
apply: (baseName: string, match: RegExpMatchArray | string, parts: ElementPart[]) => Element | string | null;
|
|
10
10
|
}
|
|
11
|
+
/** Returns icon name safe for suffix concatenation (appends _ if name ends in digit) */
|
|
12
|
+
export declare const safeIconSuffix: (name: string) => string;
|
|
11
13
|
export declare const iconRules: IconRule[];
|
|
12
14
|
export declare const icons: SVGIconMap;
|
|
13
15
|
export declare class SvgIcon extends WebComponent {
|
|
@@ -20,6 +22,7 @@ export declare class SvgIcon extends WebComponent {
|
|
|
20
22
|
'--tosi-icon-stroke-linecap': string;
|
|
21
23
|
'--tosi-icon-fill': string;
|
|
22
24
|
display: string;
|
|
25
|
+
verticalAlign: string;
|
|
23
26
|
stroke: string;
|
|
24
27
|
strokeWidth: string;
|
|
25
28
|
strokeLinejoin: string;
|