Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions packages/site-components/src/__tests__/react-attributes.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { afterEach, describe, expect, it } from 'vitest';

import '../components/td-code';
import '../components/td-doc-copy';
import '../components/td-doc-demo';

async function waitForRender(): Promise<void> {
await new Promise((resolve) => setTimeout(resolve));
}

describe('React attribute integration', () => {
afterEach(() => {
document.body.innerHTML = '';
});

it('renders td-code created through innerHTML', async () => {
const container = document.createElement('div');
container.innerHTML = '<td-code text="Button"></td-code>';
document.body.appendChild(container);

await waitForRender();

const code = container.querySelector('td-code');
expect(code?.shadowRoot?.textContent).toContain('Button');
});

it('renders td-doc-demo code from React-style data attributes', async () => {
const demo = document.createElement('td-doc-demo');
demo.setAttribute('languages', 'TypeScript,JavaScript');
demo.setAttribute('data-TypeScript', 'const value: string = "TS";');
demo.setAttribute('data-JavaScript', 'const value = "JS";');
document.body.appendChild(demo);

await waitForRender();

const tabs = Array.from(demo.shadowRoot?.querySelectorAll('.TDesign-doc-demo-tabs__item') ?? []);
expect(tabs.map((tab) => tab.textContent?.trim())).toEqual(['TypeScript', 'JavaScript']);
expect(demo.shadowRoot?.querySelector('code')?.textContent).toContain('const value: string = "TS";');

demo.setAttribute('data-TypeScript', 'const updated: string = "TS";');
await waitForRender();

expect(demo.shadowRoot?.querySelector('code')?.textContent).toContain('const updated: string = "TS";');
});
});
51 changes: 51 additions & 0 deletions packages/site-components/src/__tests__/td-doc-badge.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { afterEach, describe, expect, it } from 'vitest';

import '../components/td-doc-badge';

async function waitForRender(): Promise<void> {
await new Promise((resolve) => setTimeout(resolve));
}

describe('td-doc-badge', () => {
afterEach(() => {
document.body.innerHTML = '';
});

it('reads attributes set after element creation', async () => {
const badge = document.createElement('td-doc-badge');
badge.setAttribute('label', 'statements');
badge.setAttribute('message', '87.5%');
document.body.appendChild(badge);

await waitForRender();

expect(badge.shadowRoot?.querySelector('img')?.getAttribute('src')).toBe(
'https://img.shields.io/badge/statements-87.5%25-yellow',
);
});

it('updates when an attribute changes', async () => {
const badge = document.createElement('td-doc-badge');
document.body.appendChild(badge);
await waitForRender();

badge.setAttribute('message', '95%');
await waitForRender();

expect(badge.shadowRoot?.querySelector('img')?.getAttribute('src')).toBe(
'https://img.shields.io/badge/coverage-95%25-brightgreen',
);
});

it('preserves properties set before connection', async () => {
const badge = document.createElement('td-doc-badge') as HTMLElement & { message: string };
badge.message = '72%';
document.body.appendChild(badge);

await waitForRender();

expect(badge.shadowRoot?.querySelector('img')?.getAttribute('src')).toBe(
'https://img.shields.io/badge/coverage-72%25-yellow',
);
});
});
4 changes: 3 additions & 1 deletion packages/site-components/src/__tests__/td-doc-popup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ vi.mock('hybrids', () => ({
}));

vi.mock('@popperjs/core', () => ({ createPopper: mockCreatePopper }));
vi.mock('@utils', () => ({ parseBoolean: vi.fn((value: unknown) => Boolean(value)) }));
vi.mock('@utils', () => ({
parseBoolean: vi.fn((value: unknown) => Boolean(value)),
}));
vi.mock('../components/td-doc-popup/style.less?inline', () => ({ default: '' }));

interface PortalContainerMock {
Expand Down
64 changes: 64 additions & 0 deletions packages/site-components/src/__tests__/td-select.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { afterEach, describe, expect, it } from 'vitest';

import '../components/td-select';

interface SelectElement extends HTMLElement {
borderless: boolean;
value: string | number;
options: Array<{ label: string; value: string | number }>;
}

async function waitForRender(): Promise<void> {
await new Promise((resolve) => setTimeout(resolve));
}

describe('td-select', () => {
afterEach(() => {
document.body.innerHTML = '';
});

it('reads attributes set after element creation', async () => {
const select = document.createElement('td-select') as SelectElement;
select.options = [
{ label: 'One', value: '1' },
{ label: 'Two', value: '2' },
];
select.setAttribute('value', '2');
select.setAttribute('borderless', '');
document.body.appendChild(select);

await waitForRender();

expect(select.shadowRoot?.querySelector('input')?.value).toBe('Two');
expect(select.shadowRoot?.querySelector('.TDesign-select-input')?.classList).toContain(
'TDesign-select-input--borderless',
);
});

it('updates when the value attribute changes', async () => {
const select = document.createElement('td-select') as SelectElement;
select.options = [
{ label: 'One', value: '1' },
{ label: 'Two', value: '2' },
];
document.body.appendChild(select);
await waitForRender();

select.setAttribute('value', '1');
await waitForRender();

expect(select.shadowRoot?.querySelector('input')?.value).toBe('One');
});

it('preserves properties set before connection', async () => {
const select = document.createElement('td-select') as SelectElement;
select.options = [{ label: 'Two', value: 2 }];
select.value = 2;
document.body.appendChild(select);

await waitForRender();

expect(select.value).toBe(2);
expect(select.shadowRoot?.querySelector('input')?.value).toBe('Two');
});
});
2 changes: 1 addition & 1 deletion packages/site-components/src/components/td-aegis/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* global Aegis */
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';

interface AegisProps {
aegisId: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';
import { createAISearchSDK } from './utils';
import style from './style.less?inline';

Expand Down
2 changes: 1 addition & 1 deletion packages/site-components/src/components/td-avatar/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';
import style from './style.less?inline';

interface AvatarProps {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';
import style from './style.less?inline';
import backTopIcon from '@images/backtop.svg?raw';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';
import style from './style.less?inline';
import Prism from 'prismjs';

Expand Down
2 changes: 1 addition & 1 deletion packages/site-components/src/components/td-code/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { define, html } from 'hybrids';
import { define, html } from '@utils/hybrids';
import style from './style.less?inline';

interface CodeProps {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';
import style from './style.less?inline';

const apiUrl = import.meta.env.VITE_CONTRIBUTORS_API_URL;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, dispatch, define, type Component } from 'hybrids';
import { html, dispatch, define, type Component } from '@utils/hybrids';
import menuFoldIcon from '@images/menu-fold.svg?raw';
import menuUnfoldIcon from '@images/menu-unfold.svg?raw';
import { patchShadowDomIntoDom } from '@utils';
Expand Down
26 changes: 4 additions & 22 deletions packages/site-components/src/components/td-doc-badge/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define, type Descriptor } from 'hybrids';
import { html, define } from '@utils/hybrids';
import style from './style.less?inline';

interface BadgeHost {
Expand All @@ -7,24 +7,6 @@ interface BadgeHost {
color: string;
}

function attribute(defaultValue: string): Descriptor<BadgeHost, string> {
return {
value: (_host, value) => value ?? defaultValue,
connect: (host, key) => {
const attributeName = key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
const syncAttribute = () => {
host[key] = host.getAttribute(attributeName) ?? defaultValue;
};
const observer = new MutationObserver(syncAttribute);

if (host.hasAttribute(attributeName)) syncAttribute();
observer.observe(host, { attributes: true, attributeFilter: [attributeName] });

return () => observer.disconnect();
},
};
}

function getColor(message: string): string {
const percentage = parseFloat(message);
if (percentage >= 90) {
Expand All @@ -38,9 +20,9 @@ function getColor(message: string): string {

export default define<BadgeHost>({
tag: 'td-doc-badge',
label: attribute('coverage'),
message: attribute('0%'),
color: attribute(''),
label: 'coverage',
message: '0%',
color: '',
render: (host) => {
const { label, message, color: defaultColor } = host;
let color = defaultColor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { define, html } from 'hybrids';
import { define, html } from '@utils/hybrids';
import { getLocale } from '@config/locale';
import closeIcon from '@images/close.svg?raw';
import { convert2PascalCase, isComponentPage, isEn, isGlobalConfigPage, parseBoolean } from '@utils';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';
import { mobileBodyStyle } from '@utils';
import style from './style.less?inline';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, dispatch, define } from 'hybrids';
import { html, dispatch, define } from '@utils/hybrids';
import style from './style.less?inline';
import copyIcon from '@images/copy.svg?raw';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define, dispatch } from 'hybrids';
import { html, define, dispatch } from '@utils/hybrids';
import Prism from 'prismjs';
import { parseBoolean } from '@utils';
import style from './style.less?inline';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';
import style from './style.less?inline';

interface EmptyHost {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';
import { getFooterConfig } from '@config/footer';
import { getLocale } from '@config/locale';
import { patchShadowDomIntoDom } from '@utils';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getLocale } from '@config/locale';
import splineConfig from '@config/spline';
import historyIcon from '@images/history.svg?raw';
import { isComponentPage, isGlobalConfigPage, mobileBodyStyle, parseBoolean, watchHtmlMode } from '@utils';
import { define, html } from 'hybrids';
import { define, html } from '@utils/hybrids';
import style from './style.less?inline';

interface DocInfo {
Expand Down Expand Up @@ -88,7 +88,7 @@ function iframeOnload(host: HeaderHost & HTMLElement): void {
export default define<HeaderHost>({
tag: 'td-doc-header',
spline: {
value: (_host, v) => v || '',
value: (_host, value) => value || '',
connect: (host) => {
const observer = watchHtmlMode((themeMode) => handleModeChange(themeMode, host));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';
import style from './style.less?inline';
import infoIcon from '@images/info.svg?raw';
import checkIcon from '@images/check.svg?raw';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';
import style from './style.less?inline';
import historyIcon from '@images/history.svg?raw';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';
import NProgress from 'nprogress';
import style from './style.less?inline';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define } from 'hybrids';
import { html, define } from '@utils/hybrids';
import QRCode from 'qrcode';
import style from './style.less?inline';
import qrcodeIcon from '@images/qrcode.svg?raw';
Expand Down
4 changes: 2 additions & 2 deletions packages/site-components/src/components/td-doc-popup/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define, dispatch } from 'hybrids';
import { html, define, dispatch } from '@utils/hybrids';
import { createPopper, type Instance, type Placement } from '@popperjs/core';
import { parseBoolean } from '@utils';
import style from './style.less?inline';
Expand Down Expand Up @@ -57,7 +57,7 @@ export default define<DocPopupProps>({
portal: null,
popper: null,
equalWidth: {
value: (_host, v) => parseBoolean(v, false),
value: (_host, value) => parseBoolean(value, false),
},
visible: {
value: (host, v) => v || false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* → views.js 根据最新 host 输出 html``
*/

import { define, html, type Descriptor } from 'hybrids';
import { define, html, type Descriptor } from '@utils/hybrids';

import style from './style.less?inline';
import {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* }
*/

import { html, type UpdateFunctionWithMethods } from 'hybrids';
import { html, type UpdateFunctionWithMethods } from '@utils/hybrids';
import SearchIcon from 'tdesign-icons-svg/src/search.svg?raw';
import CloseIcon from 'tdesign-icons-svg/src/close.svg?raw';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, dispatch, define } from 'hybrids';
import { html, dispatch, define } from '@utils/hybrids';
import { isEn } from '@utils';
import style from './style.less?inline';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, define, dispatch } from 'hybrids';
import { html, define, dispatch } from '@utils/hybrids';
import { parseBoolean } from '@utils';
import style from './style.less?inline';
import tipsIcon from '@images/tips.svg?raw';
Expand Down
Loading
Loading