Files

92 lines
3.9 KiB
TypeScript

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { OrgChart, type OrgChartProps } from '@hm-design/org-chart-react';
import { JsonOrgChartDataSource, type OrgChartDataSource, type OrgChartState } from '@hm-design/org-chart';
import engineUrl from '@hm-design/org-chart/engine.css?url';
import coreUrl from '@hm-design/org-chart/style.css?url';
import v1 from '../org-chart/data-v1.json';
import v2 from '../org-chart/data-v2.json';
import './index.css';
// An independent production-built consumer of public package entries. This
// inspection seam exercises React Props only; it never reaches into the engine.
const events: { instance: string; callback: number; state: OrgChartState }[] = [];
const lifecycleErrors: string[] = [];
const requests: Record<string, { loads: number; aborts: number }> = {};
function track(name: string, source: OrgChartDataSource): OrgChartDataSource {
requests[name] = { loads: 0, aborts: 0 };
return {
load(options) {
requests[name].loads++;
options?.signal?.addEventListener('abort', () => { requests[name].aborts++; }, { once: true });
return source.load(options);
},
};
}
const noEmployees = structuredClone(v1);
noEmployees.employees = [];
for (const organization of noEmployees.organizations) organization.leaderId = null;
const noOrganizations = structuredClone(v1);
noOrganizations.organizations = [];
const sources = {
v1: track('v1', new JsonOrgChartDataSource(v1)),
v2: track('v2', new JsonOrgChartDataSource(v2)),
zeroEmployees: track('zeroEmployees', new JsonOrgChartDataSource(noEmployees)),
zeroOrganizations: track('zeroOrganizations', new JsonOrgChartDataSource(noOrganizations)),
error: track('error', { async load() { throw new Error('Fictitious source failure'); } }),
};
let releaseSlow: (() => void) | undefined;
const slowSource = track('slow', {
load() { return new Promise(resolve => { releaseSlow = () => resolve(structuredClone(v1)); }); },
});
type Configuration = {
sourceA: OrgChartDataSource;
sourceB: OrgChartDataSource;
mountedA: boolean;
mountedB: boolean;
callback: number;
aggregationPolicy: OrgChartProps['aggregationPolicy'];
stylesheetUrls: OrgChartProps['stylesheetUrls'];
className: string;
};
let configuration: Configuration = {
sourceA: sources.v1, sourceB: sources.v2, mountedA: true, mountedB: false,
callback: 1, aggregationPolicy: undefined,
stylesheetUrls: { engine: engineUrl, core: coreUrl }, className: 'consumer-chart',
};
const root = createRoot(document.getElementById('root')!);
function render(patch: Partial<Configuration> = {}) {
configuration = { ...configuration, ...patch };
const callback = configuration.callback;
const chart = (instance: 'A' | 'B', source: OrgChartDataSource) => (
<section key={instance} aria-label={`OrgChart ${instance}`} data-instance={instance}>
<OrgChart
dataSource={source}
aggregationPolicy={configuration.aggregationPolicy}
stylesheetUrls={configuration.stylesheetUrls}
className={configuration.className}
onStateChange={state => { events.push({ instance, callback, state }); }}
onLifecycleError={error => { lifecycleErrors.push(error instanceof Error ? error.message : String(error)); }}
/>
</section>
);
root.render(
<StrictMode>
<p className="consumer-note">가상 JSON 데이터 · React Strict Mode · 공개 OrgChart 패키지 사용</p>
<div className="consumer-charts">
{configuration.mountedA && chart('A', configuration.sourceA)}
{configuration.mountedB && chart('B', configuration.sourceB)}
</div>
</StrictMode>,
);
}
const demo = {
render, sources, slowSource, events, lifecycleErrors, requests,
releaseSlow: () => releaseSlow?.(),
get configuration() { return configuration; },
destroy: () => root.unmount(),
};
declare global { interface Window { OrgChartReactDemo: typeof demo } }
window.OrgChartReactDemo = demo;
render();