Skip to content

Commit

Permalink
[duoyun-ui] Export React component
Browse files Browse the repository at this point in the history
  • Loading branch information
mantou132 committed Dec 7, 2023
1 parent f76a9d4 commit d44a747
Show file tree
Hide file tree
Showing 19 changed files with 213 additions and 20 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
packages/*/dist
packages/*/react
packages/*/bin
packages/*/coverage
packages/*/extension
1 change: 1 addition & 0 deletions .github/workflows/duoyun-ui-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
node-version: 18.x

- run: yarn
- run: yarn --cwd packages/duoyun-ui build:react

- uses: JS-DevTools/npm-publish@v1
with:
Expand Down
1 change: 1 addition & 0 deletions packages/duoyun-ui/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Compiler output
/lib/
/elements/
/react/
/locales/
/coverage/

Expand Down
3 changes: 3 additions & 0 deletions packages/duoyun-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@
"description": "WebComponts UI",
"exports": {
"./elements/*": "./elements/*.js",
"./react/*": "./react/*.js",
"./lib/*": "./lib/*.js",
"./locales/*": "./locales/*.js"
},
"files": [
"/elements/",
"/react/",
"/lib/",
"/locales/"
],
"scripts": {
"docs": "node scripts/hack-gbp-example && gem-book docs --plugin node_modules/gbp-example-hack",
"docs:remote": "gem-book docs --plugin example",
"build:docs": "gem-book docs --build --plugin example",
"build:react": "gem-port src/elements",
"clean": "node -e \"fs.readdirSync('src').map(dir => require('rimraf').sync(dir))\"",
"build": "yarn clean && tsc -p tsconfig.build.json",
"start": "yarn build --watch",
Expand Down
8 changes: 5 additions & 3 deletions packages/duoyun-ui/src/elements/cascader-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,14 @@ export class DuoyunCascaderPickElement extends GemElement implements BasePickerE
${isEmpty
? this.placeholder
: this.multiple
? this.#renderMultipleValue(this.value as (string | number)[][])
: this.#renderValue(this.value as (string | number)[])}
? this.#renderMultipleValue(this.value as (string | number)[][])
: this.#renderValue(this.value as (string | number)[])}
</div>
<dy-use class="icon" .element=${icons.expand}></dy-use>
`;
};

showPicker = () => this.#onOpen();
showPicker() {
this.#onOpen();
}
}
4 changes: 2 additions & 2 deletions packages/duoyun-ui/src/elements/color-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class DuoyunColorPickElement extends GemElement implements BasePickerElem
`;
};

showPicker = () => {
showPicker() {
this.popoverRef.element?.click();
};
}
}
4 changes: 3 additions & 1 deletion packages/duoyun-ui/src/elements/date-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,5 +174,7 @@ export class DuoyunDatePickElement extends GemElement implements BasePickerEleme
`;
};

showPicker = () => this.#onOpen();
showPicker() {
this.#onOpen();
}
}
4 changes: 3 additions & 1 deletion packages/duoyun-ui/src/elements/date-range-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,5 +177,7 @@ export class DuoyunDateRangePickElement extends GemElement implements BasePicker
`;
};

showPicker = () => this.#onOpen();
showPicker() {
this.#onOpen();
}
}
4 changes: 2 additions & 2 deletions packages/duoyun-ui/src/elements/file-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ export class DuoyunFilePickElement extends GemElement implements BasePickerEleme
`;
};

showPicker = () => {
showPicker() {
this.inputRef.element!.click();
};
}
}
4 changes: 3 additions & 1 deletion packages/duoyun-ui/src/elements/picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,5 +178,7 @@ export class DuoyunPickElement extends GemElement implements BasePickerElement {
`;
};

showPicker = () => this.#onOpen();
showPicker() {
this.#onOpen();
}
}
12 changes: 7 additions & 5 deletions packages/duoyun-ui/src/elements/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ export class DuoyunSelectElement extends GemElement<State> implements BasePicker
return this.multiple && Array.isArray(this.value)
? this.value
: isNotNullish(this.value)
? [this.value]
: undefined;
? [this.value]
: undefined;
}

constructor() {
Expand Down Expand Up @@ -397,8 +397,8 @@ export class DuoyunSelectElement extends GemElement<State> implements BasePicker
</dy-tag>
`
: this.renderTag
? this.renderTag(this.#valueOptions![index])
: label,
? this.renderTag(this.#valueOptions![index])
: label,
)}
`
: this.#valueOptions![0].label}
Expand Down Expand Up @@ -447,5 +447,7 @@ export class DuoyunSelectElement extends GemElement<State> implements BasePicker
`;
};

showPicker = () => this.#open();
showPicker() {
this.#open();
}
}
4 changes: 2 additions & 2 deletions packages/duoyun-ui/src/elements/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export class DuoyunTabsElement extends GemElement {
return html`
<div part=${DuoyunTabsElement.tabs} class="tabs">
${this.data.map(({ value, tab, icon, getContent }, index) => {
const isCurrent = (value ?? index) === this.value;
const isCurrent: boolean = (value ?? index) === this.value;
if (isCurrent) currentContent = getContent?.() || '';
return html`
<div
Expand Down Expand Up @@ -186,7 +186,7 @@ const panelStyle = createCSSSheet(css`
*/
@customElement('dy-tab-panel')
@adoptedStyle(panelStyle)
export class DyTabPanelElement extends DuoyunScrollBaseElement {
export class DuoyunTabPanelElement extends DuoyunScrollBaseElement {
@state vertical: boolean;

constructor() {
Expand Down
2 changes: 1 addition & 1 deletion packages/duoyun-ui/src/elements/text-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type MaskParseValue = TemplateResult | string | number;
*/
@customElement('dy-text-mask')
@adoptedStyle(style)
export class DyTextMaskElement extends GemElement {
export class DuoyunTextMaskElement extends GemElement {
@attribute origin: string;
@attribute placeholder: string;
@attribute replacer: string;
Expand Down
4 changes: 3 additions & 1 deletion packages/duoyun-ui/src/elements/time-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,5 +155,7 @@ export class DuoyunTimePickElement extends GemElement implements BasePickerEleme
`;
};

showPicker = () => this.#onOpen();
showPicker() {
this.#onOpen();
}
}
1 change: 1 addition & 0 deletions packages/gem-port/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/bin/
41 changes: 41 additions & 0 deletions packages/gem-port/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "gem-port",
"version": "0.0.1",
"description": "Export React component",
"keywords": [
"gem",
"react",
"generator"
],
"bin": {
"gem-port": "bin/index.js"
},
"files": [
"/bin/"
],
"scripts": {
"build": "esbuild ./src/index.ts --outdir=./bin --bundle --platform=node --minify --sourcemap --external:typescript",
"start": "yarn build --watch",
"prepublishOnly": "yarn build"
},
"dependencies": {
"@gemjs/config": "^1.6.11",
"commander": "^7.2.0",
"gem-analyzer": "^1.7.0",
"ts-morph": "^13.0.0",
"typescript": "^4.5.0"
},
"devDependencies": {
},
"author": "mantou132",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/mantou132/gem.git",
"directory": "packages/gem-port"
},
"bugs": {
"url": "https://github.com/mantou132/gem/issues"
},
"homepage": "https://github.com/mantou132/gem#readme"
}
125 changes: 125 additions & 0 deletions packages/gem-port/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/usr/bin/env node

import path from 'path';
import { readdirSync, readFileSync, statSync } from 'fs';

import { getElements } from 'gem-analyzer';
import { Project } from 'ts-morph';
import * as ts from 'typescript';
import program from 'commander';

import { name, description, version } from '../package.json';

const cliOptions = {
outDir: './',
};

function createReactSourceFile(elementFilePath: string, outDir: string) {
const content = readFileSync(elementFilePath, { encoding: 'utf-8' });
const project = new Project({ useInMemoryFileSystem: true });
const file = project.createSourceFile(elementFilePath, content);
const basename = path.basename(elementFilePath, path.extname(elementFilePath));
// FIXME
const relativePath = path.relative(path.resolve(outDir), path.dirname(elementFilePath)).replace('src/', '');
return Object.fromEntries(
getElements(file).map(({ name: tag, constructorName, properties, methods, events }) => {
const componentName = constructorName.replace('Element', '');
const componentPropsName = `${componentName}Props`;
const componentMethodsName = `${componentName}Methods`;
return [
componentName + '.tsx',
`
import React, { ForwardRefExoticComponent, HTMLAttributes, RefAttributes, forwardRef, useImperativeHandle, useRef } from 'react';
import { TemplateResult } from '@mantou/gem/lib/element';
import { ${constructorName} } from '${relativePath}/${basename}';
export { ${constructorName} };
export type ${componentPropsName} = HTMLAttributes<HTMLDivElement> & RefAttributes<${constructorName}> & {
${properties
.map(({ name, attribute, reactive }) =>
!reactive ? '' : [name, attribute ? 'string' : 'any'].join('?:'),
)
.join(';')}
${events.map((event) => [`on${event}`, `(arg: CustomEvent<any>) => any`].join('?:')).join(';')}
};
export type ${componentMethodsName} = {
${methods.map(({ name }) => [name, `typeof ${constructorName}.prototype.${name}`].join(': ')).join(';')}
}
declare global {
namespace JSX {
interface IntrinsicElements {
'${tag}': ${componentPropsName};
}
}
}
const ${componentName}: ForwardRefExoticComponent<Omit<${componentPropsName}, "ref"> & RefAttributes<${componentMethodsName}>> = forwardRef<${componentMethodsName}, ${componentPropsName}>(function (props, ref): JSX.Element {
const elementRef = useRef<${constructorName}>(null);
useImperativeHandle(ref, () => {
return {
${methods
.map(
({ name }) => `
${name}(...args) {
elementRef.current?.${name}(...args)
}
`,
)
.join(',')}
};
}, []);
return <${tag} ref={elementRef} {...props}></${tag}>;
})
export default ${componentName};
`,
];
}),
);
}

function createSourceFiles(elementsDir: string, outDir: string) {
const fileSystem: Record<string, string> = {};
readdirSync(elementsDir).forEach((filename) => {
const elementFilePath = path.resolve(elementsDir, filename);
if (statSync(elementFilePath).isFile()) {
// if (!elementFilePath.includes('color-pick') && !elementFilePath.includes('card')) return;
Object.assign(fileSystem, createReactSourceFile(elementFilePath, outDir));
}
});
return fileSystem;
}

function compile(elementsDir: string): void {
const outDir = path.resolve(cliOptions.outDir, 'react');
const options: ts.CompilerOptions = {
jsx: ts.JsxEmit.React,
target: ts.ScriptTarget.ES2020,
declaration: true,
outDir,
};
const fileSystem = createSourceFiles(elementsDir, outDir);
const host = ts.createCompilerHost(options);
const originReadFile = host.readFile;
host.readFile = (filename: string) => {
if (filename in fileSystem) return fileSystem[filename];
return originReadFile(filename);
};
const program = ts.createProgram(Object.keys(fileSystem), options, host);
program.emit();
}

program
.name(name)
.description(description)
.version(version, '-v, --version')
.option('-o, --outdir <path>', `specify out dir`, (outdir: string) => (cliOptions.outDir = outdir), cliOptions.outDir)
.arguments('<dir>')
.action((dir: string) => {
compile(dir);
process.exit(0);
});

program.parse(process.argv).outputHelp();
8 changes: 8 additions & 0 deletions packages/gem-port/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "@gemjs/config/tsconfig",
"compilerOptions": {
"module": "commonjs"
},
"include": ["src"],
"exclude": []
}
2 changes: 1 addition & 1 deletion packages/gem/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ export interface StyledKeyValuePair {
// https://bugzilla.mozilla.org/show_bug.cgi?id=1520690
// https://bugs.webkit.org/show_bug.cgi?id=228684
export let useNativeCSSStyleSheet = true;
let CSSStyleSheet = window.CSSStyleSheet;
let CSSStyleSheet = globalThis.CSSStyleSheet;
try {
new (CSSStyleSheet as any)();
} catch {
Expand Down

0 comments on commit d44a747

Please sign in to comment.