62 lines
1.8 KiB
TypeScript
62 lines
1.8 KiB
TypeScript
import React from 'react';
|
||
import { createRoot, type Root } from 'react-dom/client';
|
||
import { Dashboard } from './Dashboard';
|
||
import { PluginContext, makeClient } from './client';
|
||
|
||
// 把 build 出来的 CSS 当字符串收入,作为 ConstructableStyleSheet 注入到 shadow root,
|
||
// 既能享受 shadow DOM 的样式隔离,也不需要额外的 fetch 步骤。
|
||
import css from './styles.css?inline';
|
||
|
||
const TAG = 'plugin-data-analytics';
|
||
|
||
class DataAnalyticsElement extends HTMLElement {
|
||
private root?: Root;
|
||
private mount?: HTMLDivElement;
|
||
|
||
static get observedAttributes() {
|
||
return ['token', 'api-base'];
|
||
}
|
||
|
||
connectedCallback() {
|
||
const shadow = this.attachShadow({ mode: 'open' });
|
||
|
||
// 用 <style> 注入 CSS(ConstructableStyleSheet 兼容性更好但 vite 注入字符串更直接)
|
||
const style = document.createElement('style');
|
||
style.textContent = css;
|
||
shadow.appendChild(style);
|
||
|
||
this.mount = document.createElement('div');
|
||
this.mount.style.cssText = 'height:100%;width:100%';
|
||
shadow.appendChild(this.mount);
|
||
|
||
this.root = createRoot(this.mount);
|
||
this.render();
|
||
}
|
||
|
||
attributeChangedCallback() {
|
||
if (this.root) this.render();
|
||
}
|
||
|
||
disconnectedCallback() {
|
||
this.root?.unmount();
|
||
this.root = undefined;
|
||
}
|
||
|
||
private render() {
|
||
const token = this.getAttribute('token') ?? '';
|
||
const apiBase = this.getAttribute('api-base') ?? '';
|
||
const client = makeClient(token, apiBase);
|
||
this.root!.render(
|
||
<React.StrictMode>
|
||
<PluginContext.Provider value={{ client, token, apiBase }}>
|
||
<Dashboard pluginName="data_analytics" />
|
||
</PluginContext.Provider>
|
||
</React.StrictMode>,
|
||
);
|
||
}
|
||
}
|
||
|
||
if (!customElements.get(TAG)) {
|
||
customElements.define(TAG, DataAnalyticsElement);
|
||
}
|