@skhema/web-component 0.0.17 → 0.0.19
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/components/SkhemaElement.d.ts +9 -0
- package/dist/components/SkhemaElement.d.ts.map +1 -1
- package/dist/index.cjs +223 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +223 -45
- package/dist/index.es.js.map +1 -1
- package/dist/utils/analytics.d.ts.map +1 -1
- package/dist/web-component.min.js +1 -1
- package/dist/web-component.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,21 +4,30 @@ export declare class SkhemaElement extends HTMLElement {
|
|
|
4
4
|
private contentData;
|
|
5
5
|
private componentConnected;
|
|
6
6
|
private hasTrackedLoad;
|
|
7
|
+
private themeObserver;
|
|
8
|
+
private mediaQueryListener;
|
|
7
9
|
constructor();
|
|
8
10
|
static get observedAttributes(): (keyof SkhemaElementAttributes)[];
|
|
9
11
|
connectedCallback(): void;
|
|
12
|
+
disconnectedCallback(): void;
|
|
10
13
|
attributeChangedCallback(_name: keyof SkhemaElementAttributes, oldValue: string | null, newValue: string | null): void;
|
|
11
14
|
private render;
|
|
12
15
|
private getContent;
|
|
13
16
|
private renderContent;
|
|
17
|
+
private getActualTheme;
|
|
14
18
|
private formatContributorName;
|
|
15
19
|
private getInitials;
|
|
20
|
+
private addPreconnectHints;
|
|
21
|
+
private renderSkeleton;
|
|
16
22
|
private renderError;
|
|
17
23
|
private addStructuredData;
|
|
18
24
|
private trackLoad;
|
|
19
25
|
private handleSaveClick;
|
|
20
26
|
getContentData(): ContentData | null;
|
|
21
27
|
refresh(): void;
|
|
28
|
+
private setupThemeListeners;
|
|
29
|
+
private cleanupThemeListeners;
|
|
30
|
+
private updateTheme;
|
|
22
31
|
}
|
|
23
32
|
declare global {
|
|
24
33
|
interface HTMLElementEventMap extends SkhemaElementEventMap {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkhemaElement.d.ts","sourceRoot":"","sources":["../../src/components/SkhemaElement.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EACV,WAAW,EAEX,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"SkhemaElement.d.ts","sourceRoot":"","sources":["../../src/components/SkhemaElement.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EACV,WAAW,EAEX,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,YAAY,CAAA;AAuXnB,qBAAa,aAAc,SAAQ,WAAW;IAC5C,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,aAAa,CAAgC;IACrD,OAAO,CAAC,kBAAkB,CAA8B;;IASxD,MAAM,KAAK,kBAAkB,IAAI,CAAC,MAAM,uBAAuB,CAAC,EAAE,CASjE;IAED,iBAAiB;IAmBjB,oBAAoB;IAIpB,wBAAwB,CACtB,KAAK,EAAE,MAAM,uBAAuB,EACpC,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,QAAQ,EAAE,MAAM,GAAG,IAAI;IAOzB,OAAO,CAAC,MAAM;IAwCd,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,aAAa;IA0ErB,OAAO,CAAC,cAAc;IAmDtB,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,kBAAkB;IAyB1B,OAAO,CAAC,cAAc;IAyBtB,OAAO,CAAC,WAAW;IAyBnB,OAAO,CAAC,iBAAiB;YA0BX,SAAS;YAiCT,eAAe;IAkBtB,cAAc,IAAI,WAAW,GAAG,IAAI;IAIpC,OAAO,IAAI,IAAI;IAItB,OAAO,CAAC,mBAAmB;IA6B3B,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,WAAW;CAYpB;AAGD,OAAO,CAAC,MAAM,CAAC;IAEb,UAAU,mBAAoB,SAAQ,qBAAqB;KAAG;IAE9D,UAAU,gBAAiB,SAAQ,OAAO,CAAC,uBAAuB,CAAC;QACjE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KACvB;IAGD,UAAU,oBAAoB;QAC5B,gBAAgB,EAAE,gBAAgB,CAAA;KACnC;CACF"}
|
package/dist/index.cjs
CHANGED
|
@@ -94,9 +94,10 @@ class AnalyticsBatcher {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
async sendEmbeds(embeds) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
if (embeds.length === 0) return;
|
|
98
|
+
try {
|
|
99
|
+
const payload = {
|
|
100
|
+
embeds: embeds.map((embed) => ({
|
|
100
101
|
contributor_id: embed.contributorId,
|
|
101
102
|
element_type: embed.elementType,
|
|
102
103
|
content_hash: embed.contentHash,
|
|
@@ -105,22 +106,24 @@ class AnalyticsBatcher {
|
|
|
105
106
|
page_title: embed.pageTitle || "",
|
|
106
107
|
timestamp: embed.timestamp.toString(),
|
|
107
108
|
user_agent: embed.userAgent || ""
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
109
|
+
})),
|
|
110
|
+
batch_size: embeds.length,
|
|
111
|
+
batch_timestamp: Date.now()
|
|
112
|
+
};
|
|
113
|
+
if (navigator.sendBeacon) {
|
|
114
|
+
navigator.sendBeacon(
|
|
115
|
+
"https://api.skhema.com/api:XGdoUqHx/component/embed",
|
|
116
|
+
new Blob([JSON.stringify(payload)], { type: "application/json" })
|
|
117
|
+
);
|
|
118
|
+
} else {
|
|
119
|
+
await sendWithRetry(
|
|
120
|
+
"https://api.skhema.com/api:XGdoUqHx/component/embed",
|
|
121
|
+
payload,
|
|
122
|
+
"json"
|
|
123
|
+
);
|
|
123
124
|
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.debug("Embed tracking failed:", error);
|
|
124
127
|
}
|
|
125
128
|
}
|
|
126
129
|
async sendClicks(clicks) {
|
|
@@ -133,11 +136,18 @@ class AnalyticsBatcher {
|
|
|
133
136
|
source_url: click.source_url,
|
|
134
137
|
timestamp: click.timestamp
|
|
135
138
|
};
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
139
|
+
if (navigator.sendBeacon) {
|
|
140
|
+
navigator.sendBeacon(
|
|
141
|
+
"https://api.skhema.com/api:XGdoUqHx/component/click",
|
|
142
|
+
new Blob([JSON.stringify(data)], { type: "application/json" })
|
|
143
|
+
);
|
|
144
|
+
} else {
|
|
145
|
+
await sendWithRetry(
|
|
146
|
+
"https://api.skhema.com/api:XGdoUqHx/component/click",
|
|
147
|
+
data,
|
|
148
|
+
"json"
|
|
149
|
+
);
|
|
150
|
+
}
|
|
141
151
|
} catch (error) {
|
|
142
152
|
console.debug("Click tracking failed:", error);
|
|
143
153
|
}
|
|
@@ -415,8 +425,9 @@ const styles = `
|
|
|
415
425
|
color: var(--skhema-text);
|
|
416
426
|
}
|
|
417
427
|
|
|
418
|
-
|
|
419
|
-
|
|
428
|
+
/* Dark mode styles - applied via data-theme attribute */
|
|
429
|
+
.skhema-insight-card[data-theme="dark"],
|
|
430
|
+
.skhema-skeleton[data-theme="dark"] {
|
|
420
431
|
--skhema-bg: hsl(222.2 84% 4.9%);
|
|
421
432
|
--skhema-card: hsl(222.2 84% 4.9%);
|
|
422
433
|
--skhema-border: hsl(217.2 32.6% 17.5%);
|
|
@@ -635,26 +646,81 @@ const styles = `
|
|
|
635
646
|
padding-left: 16px;
|
|
636
647
|
}
|
|
637
648
|
|
|
638
|
-
/*
|
|
639
|
-
.skhema-
|
|
640
|
-
background: var(--skhema-
|
|
649
|
+
/* Skeleton loading state */
|
|
650
|
+
.skhema-skeleton {
|
|
651
|
+
background: var(--skhema-card);
|
|
641
652
|
border: 1px solid var(--skhema-border);
|
|
642
|
-
|
|
653
|
+
border-radius: calc(var(--skhema-radius) * 2);
|
|
654
|
+
padding: 16px;
|
|
655
|
+
box-shadow: var(--skhema-shadow);
|
|
656
|
+
max-width: 600px;
|
|
657
|
+
margin: 8px 0;
|
|
658
|
+
animation: skeletonPulse 1.5s ease-in-out infinite;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.skhema-skeleton-header {
|
|
662
|
+
display: flex;
|
|
663
|
+
align-items: center;
|
|
664
|
+
gap: 12px;
|
|
665
|
+
margin-bottom: 12px;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.skhema-skeleton-avatar {
|
|
669
|
+
width: 32px;
|
|
670
|
+
height: 32px;
|
|
671
|
+
border-radius: 50%;
|
|
672
|
+
background: linear-gradient(90deg,
|
|
673
|
+
var(--skhema-border) 25%,
|
|
674
|
+
var(--skhema-accent) 50%,
|
|
675
|
+
var(--skhema-border) 75%);
|
|
676
|
+
background-size: 200% 100%;
|
|
677
|
+
animation: shimmer 1.5s infinite;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
.skhema-skeleton-text {
|
|
681
|
+
flex: 1;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
.skhema-skeleton-line {
|
|
685
|
+
height: 12px;
|
|
686
|
+
background: linear-gradient(90deg,
|
|
687
|
+
var(--skhema-border) 25%,
|
|
688
|
+
var(--skhema-accent) 50%,
|
|
689
|
+
var(--skhema-border) 75%);
|
|
690
|
+
background-size: 200% 100%;
|
|
691
|
+
animation: shimmer 1.5s infinite;
|
|
643
692
|
border-radius: var(--skhema-radius);
|
|
644
|
-
|
|
645
|
-
font-size: 13px;
|
|
646
|
-
text-align: center;
|
|
693
|
+
margin: 6px 0;
|
|
647
694
|
}
|
|
648
695
|
|
|
649
|
-
.skhema-
|
|
650
|
-
|
|
651
|
-
animation: loading 1.5s infinite;
|
|
696
|
+
.skhema-skeleton-line.short {
|
|
697
|
+
width: 40%;
|
|
652
698
|
}
|
|
653
699
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
700
|
+
.skhema-skeleton-line.medium {
|
|
701
|
+
width: 70%;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
.skhema-skeleton-content {
|
|
705
|
+
margin: 16px 0;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
@keyframes skeletonPulse {
|
|
709
|
+
0%, 100% {
|
|
710
|
+
opacity: 1;
|
|
711
|
+
}
|
|
712
|
+
50% {
|
|
713
|
+
opacity: 0.8;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
@keyframes shimmer {
|
|
718
|
+
0% {
|
|
719
|
+
background-position: -200% 0;
|
|
720
|
+
}
|
|
721
|
+
100% {
|
|
722
|
+
background-position: 200% 0;
|
|
723
|
+
}
|
|
658
724
|
}
|
|
659
725
|
|
|
660
726
|
/* Responsive design */
|
|
@@ -707,7 +773,10 @@ class SkhemaElement extends HTMLElement {
|
|
|
707
773
|
this.contentData = null;
|
|
708
774
|
this.componentConnected = false;
|
|
709
775
|
this.hasTrackedLoad = false;
|
|
776
|
+
this.themeObserver = null;
|
|
777
|
+
this.mediaQueryListener = null;
|
|
710
778
|
this.shadow = this.attachShadow({ mode: "closed" });
|
|
779
|
+
this.renderSkeleton();
|
|
711
780
|
}
|
|
712
781
|
static get observedAttributes() {
|
|
713
782
|
return [
|
|
@@ -723,12 +792,19 @@ class SkhemaElement extends HTMLElement {
|
|
|
723
792
|
if (this.componentConnected) return;
|
|
724
793
|
this.componentConnected = true;
|
|
725
794
|
try {
|
|
726
|
-
this.
|
|
727
|
-
|
|
795
|
+
this.addPreconnectHints();
|
|
796
|
+
requestAnimationFrame(() => {
|
|
797
|
+
this.render();
|
|
798
|
+
this.trackLoad();
|
|
799
|
+
this.setupThemeListeners();
|
|
800
|
+
});
|
|
728
801
|
} catch (error) {
|
|
729
802
|
this.renderError("Failed to initialize component", error);
|
|
730
803
|
}
|
|
731
804
|
}
|
|
805
|
+
disconnectedCallback() {
|
|
806
|
+
this.cleanupThemeListeners();
|
|
807
|
+
}
|
|
732
808
|
attributeChangedCallback(_name, oldValue, newValue) {
|
|
733
809
|
if (oldValue !== newValue && this.componentConnected) {
|
|
734
810
|
this.render();
|
|
@@ -779,7 +855,8 @@ class SkhemaElement extends HTMLElement {
|
|
|
779
855
|
element_type,
|
|
780
856
|
contributor_id
|
|
781
857
|
);
|
|
782
|
-
const
|
|
858
|
+
const themeAttribute = this.getAttribute("theme") || "auto";
|
|
859
|
+
const actualTheme = this.getActualTheme(themeAttribute);
|
|
783
860
|
const displayName = this.formatContributorName(contributor_id);
|
|
784
861
|
const initials = this.getInitials(displayName);
|
|
785
862
|
const ariaAttrs = createAriaAttributes(element_type);
|
|
@@ -788,8 +865,8 @@ class SkhemaElement extends HTMLElement {
|
|
|
788
865
|
});
|
|
789
866
|
this.shadow.innerHTML = `
|
|
790
867
|
<style>${styles}</style>
|
|
791
|
-
|
|
792
|
-
<div class="skhema-insight-card" data-theme="${
|
|
868
|
+
|
|
869
|
+
<div class="skhema-insight-card" data-theme="${actualTheme}">
|
|
793
870
|
<div class="skhema-header">
|
|
794
871
|
<div class="skhema-contributor">
|
|
795
872
|
<div class="skhema-avatar" title="${displayName}">
|
|
@@ -832,17 +909,78 @@ class SkhemaElement extends HTMLElement {
|
|
|
832
909
|
});
|
|
833
910
|
}
|
|
834
911
|
}
|
|
912
|
+
getActualTheme(themeAttribute) {
|
|
913
|
+
if (themeAttribute === "light" || themeAttribute === "dark") {
|
|
914
|
+
return themeAttribute;
|
|
915
|
+
}
|
|
916
|
+
const htmlElement = document.documentElement;
|
|
917
|
+
const bodyElement = document.body;
|
|
918
|
+
const htmlTheme = htmlElement.getAttribute("data-theme") || htmlElement.getAttribute("theme") || htmlElement.className.match(/theme-(\w+)/)?.[1];
|
|
919
|
+
const bodyTheme = bodyElement.getAttribute("data-theme") || bodyElement.getAttribute("theme") || bodyElement.className.match(/theme-(\w+)/)?.[1];
|
|
920
|
+
const hasDarkClass = htmlElement.classList.contains("dark") || bodyElement.classList.contains("dark") || htmlElement.classList.contains("dark-mode") || bodyElement.classList.contains("dark-mode");
|
|
921
|
+
if (hasDarkClass || htmlTheme === "dark" || bodyTheme === "dark") {
|
|
922
|
+
return "dark";
|
|
923
|
+
}
|
|
924
|
+
const computedStyles = window.getComputedStyle(htmlElement);
|
|
925
|
+
const colorScheme = computedStyles.getPropertyValue("color-scheme");
|
|
926
|
+
if (colorScheme && colorScheme.includes("dark")) {
|
|
927
|
+
return "dark";
|
|
928
|
+
}
|
|
929
|
+
if (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
930
|
+
return "dark";
|
|
931
|
+
}
|
|
932
|
+
return "light";
|
|
933
|
+
}
|
|
835
934
|
formatContributorName(contributorId) {
|
|
836
935
|
return contributorId.split(/[_-]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
|
|
837
936
|
}
|
|
838
937
|
getInitials(name) {
|
|
839
938
|
return name.split(" ").map((word) => word.charAt(0)).join("").toUpperCase().substring(0, 2);
|
|
840
939
|
}
|
|
940
|
+
addPreconnectHints() {
|
|
941
|
+
if (document.querySelector('link[rel="preconnect"][href*="api.skhema.com"]')) {
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
try {
|
|
945
|
+
const preconnectApi = document.createElement("link");
|
|
946
|
+
preconnectApi.rel = "preconnect";
|
|
947
|
+
preconnectApi.href = "https://api.skhema.com";
|
|
948
|
+
document.head.appendChild(preconnectApi);
|
|
949
|
+
const dnsPrefetch = document.createElement("link");
|
|
950
|
+
dnsPrefetch.rel = "dns-prefetch";
|
|
951
|
+
dnsPrefetch.href = "https://skhema.com";
|
|
952
|
+
document.head.appendChild(dnsPrefetch);
|
|
953
|
+
} catch (error) {
|
|
954
|
+
console.debug("Failed to add preconnect hints:", error);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
renderSkeleton() {
|
|
958
|
+
const themeAttribute = this.getAttribute("theme") || "auto";
|
|
959
|
+
const actualTheme = this.getActualTheme(themeAttribute);
|
|
960
|
+
this.shadow.innerHTML = `
|
|
961
|
+
<style>${styles}</style>
|
|
962
|
+
|
|
963
|
+
<div class="skhema-skeleton" data-theme="${actualTheme}">
|
|
964
|
+
<div class="skhema-skeleton-header">
|
|
965
|
+
<div class="skhema-skeleton-avatar"></div>
|
|
966
|
+
<div class="skhema-skeleton-text">
|
|
967
|
+
<div class="skhema-skeleton-line medium"></div>
|
|
968
|
+
<div class="skhema-skeleton-line short"></div>
|
|
969
|
+
</div>
|
|
970
|
+
</div>
|
|
971
|
+
<div class="skhema-skeleton-content">
|
|
972
|
+
<div class="skhema-skeleton-line"></div>
|
|
973
|
+
<div class="skhema-skeleton-line"></div>
|
|
974
|
+
<div class="skhema-skeleton-line medium"></div>
|
|
975
|
+
</div>
|
|
976
|
+
</div>
|
|
977
|
+
`;
|
|
978
|
+
}
|
|
841
979
|
renderError(title, errors) {
|
|
842
980
|
const errorList = Array.isArray(errors) ? errors : [String(errors)];
|
|
843
981
|
this.shadow.innerHTML = `
|
|
844
982
|
<style>${styles}</style>
|
|
845
|
-
|
|
983
|
+
|
|
846
984
|
<div class="skhema-insight-card">
|
|
847
985
|
<div class="skhema-error">
|
|
848
986
|
<div class="skhema-error-title">Skhema Component Error: ${title}</div>
|
|
@@ -920,6 +1058,46 @@ class SkhemaElement extends HTMLElement {
|
|
|
920
1058
|
refresh() {
|
|
921
1059
|
this.render();
|
|
922
1060
|
}
|
|
1061
|
+
setupThemeListeners() {
|
|
1062
|
+
const themeAttribute = this.getAttribute("theme");
|
|
1063
|
+
if (themeAttribute === "auto" || !themeAttribute) {
|
|
1064
|
+
if (window.matchMedia) {
|
|
1065
|
+
this.mediaQueryListener = window.matchMedia(
|
|
1066
|
+
"(prefers-color-scheme: dark)"
|
|
1067
|
+
);
|
|
1068
|
+
const handleThemeChange = () => this.updateTheme();
|
|
1069
|
+
this.mediaQueryListener.addEventListener("change", handleThemeChange);
|
|
1070
|
+
}
|
|
1071
|
+
this.themeObserver = new MutationObserver(() => this.updateTheme());
|
|
1072
|
+
this.themeObserver.observe(document.documentElement, {
|
|
1073
|
+
attributes: true,
|
|
1074
|
+
attributeFilter: ["class", "data-theme", "theme"]
|
|
1075
|
+
});
|
|
1076
|
+
this.themeObserver.observe(document.body, {
|
|
1077
|
+
attributes: true,
|
|
1078
|
+
attributeFilter: ["class", "data-theme", "theme"]
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
cleanupThemeListeners() {
|
|
1083
|
+
if (this.themeObserver) {
|
|
1084
|
+
this.themeObserver.disconnect();
|
|
1085
|
+
this.themeObserver = null;
|
|
1086
|
+
}
|
|
1087
|
+
if (this.mediaQueryListener) {
|
|
1088
|
+
this.mediaQueryListener = null;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
updateTheme() {
|
|
1092
|
+
const themeAttribute = this.getAttribute("theme") || "auto";
|
|
1093
|
+
if (themeAttribute === "auto") {
|
|
1094
|
+
const card = this.shadow.querySelector(".skhema-insight-card");
|
|
1095
|
+
if (card) {
|
|
1096
|
+
const newTheme = this.getActualTheme("auto");
|
|
1097
|
+
card.setAttribute("data-theme", newTheme);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
923
1101
|
}
|
|
924
1102
|
function registerSkhemaElement() {
|
|
925
1103
|
if (typeof window !== "undefined" && !customElements.get("skhema-element")) {
|