diff --git a/packages/omi-vue/package-lock.json b/packages/omi-vue/package-lock.json index 63c6ab3bc9..bbef648d58 100644 --- a/packages/omi-vue/package-lock.json +++ b/packages/omi-vue/package-lock.json @@ -8,7 +8,7 @@ "name": "my-vue-app", "version": "0.0.0", "dependencies": { - "omi": "^7.3.8", + "omi": "^7.4.5", "omi-weui": "^0.0.10", "vue": "^3.3.8" }, @@ -754,9 +754,9 @@ } }, "node_modules/omi": { - "version": "7.3.9", - "resolved": "https://registry.npmjs.org/omi/-/omi-7.3.9.tgz", - "integrity": "sha512-KWSYS2aCzZfLG5ttpyqyb2ROp9qjBZwXpqPIKxXHXamoFxwvJTyYs4sxjQzy+YnHKeEJWmUiaY8NrLYPZ1EY3w==", + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/omi/-/omi-7.4.5.tgz", + "integrity": "sha512-TYoZehSrzyxycVhoq4Sp1w0KewqKHvatvt3zpzZeA5qu4gmnW+whtKfVi4St0O8lQeEor9q9RX1zU8KcyiY10Q==", "dependencies": { "construct-style-sheets-polyfill": "3.0.1", "weakmap-polyfill": "2.0.4" @@ -1343,9 +1343,9 @@ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" }, "omi": { - "version": "7.3.9", - "resolved": "https://registry.npmjs.org/omi/-/omi-7.3.9.tgz", - "integrity": "sha512-KWSYS2aCzZfLG5ttpyqyb2ROp9qjBZwXpqPIKxXHXamoFxwvJTyYs4sxjQzy+YnHKeEJWmUiaY8NrLYPZ1EY3w==", + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/omi/-/omi-7.4.5.tgz", + "integrity": "sha512-TYoZehSrzyxycVhoq4Sp1w0KewqKHvatvt3zpzZeA5qu4gmnW+whtKfVi4St0O8lQeEor9q9RX1zU8KcyiY10Q==", "requires": { "construct-style-sheets-polyfill": "3.0.1", "weakmap-polyfill": "2.0.4" diff --git a/packages/omi-vue/package.json b/packages/omi-vue/package.json index f0e41d83a3..ae55b9c900 100644 --- a/packages/omi-vue/package.json +++ b/packages/omi-vue/package.json @@ -10,7 +10,7 @@ "preview": "vite preview" }, "dependencies": { - "omi": "^7.3.8", + "omi": "^7.4.5", "omi-weui": "^0.0.10", "vue": "^3.3.8" }, diff --git a/packages/omi-vue/src/components/my-counter.ts b/packages/omi-vue/src/components/my-counter.ts index 450f4bbac4..0dec18ba29 100644 --- a/packages/omi-vue/src/components/my-counter.ts +++ b/packages/omi-vue/src/components/my-counter.ts @@ -2,15 +2,15 @@ import { define, Component, h } from 'omi' define('my-counter', class extends Component { - static propTypes = { - count: Number - } - - static observedAttributes = ['count'] - - attributeChangedCallback(name, oldValue, newValue) { - this.state[name] = newValue - this.update() + static props = { + count: { + type: Number, + default: 0, + changed(newValue, oldValue) { + this.state.count = newValue + this.update() + } + } } state = { diff --git a/packages/omi/README.md b/packages/omi/README.md index 37df9288b6..945ea2fbb2 100644 --- a/packages/omi/README.md +++ b/packages/omi/README.md @@ -353,15 +353,15 @@ import { define, Component, h } from 'omi' define('my-counter', class extends Component { - static propTypes = { - count: Number - } - - static observedAttributes = ['count'] - - attributeChangedCallback(name, oldValue, newValue) { - this.state[name] = newValue - this.update() + static props = { + count: { + type: Number, + default: 0, + changed(newValue, oldValue) { + this.state.count = newValue + this.update() + } + } } state = { diff --git a/packages/omi/examples/static-props.tsx b/packages/omi/examples/static-props.tsx new file mode 100644 index 0000000000..f4510d3ebf --- /dev/null +++ b/packages/omi/examples/static-props.tsx @@ -0,0 +1,69 @@ +import { render, tag, Component, h, bind } from '@/index' + +@tag('counter-demo') +class CounterDemo extends Component { + static props = { + count: { + count: Number, + // count: [Number, String, Array], + default: 20, + reflect: true, + // or reflect(value) {} + changed(newValue, oldValue) { + console.log('changed', newValue, oldValue) + } + } + } + + state = { + count: 0 + } + + install() { + this.state.count = this.props.count + } + + receiveProps(): void { + if (this.props.count === this.state.count) { + return false + } + + this.state.count = this.props.count + } + + @bind + add() { + this.state.count++ + this.update() + this.fire('change', this.state.count) + } + + render() { + return ( + <> + {this.state.count} + + ) + } +} + + +@tag('my-app') +class MyApp extends Component { + count = 10 + + @bind + onChange(evt) { + this.count = evt.detail + this.update() + } + + render() { + return ( + + + + ) + } +} +render(, document.body) \ No newline at end of file diff --git a/packages/omi/omi.d.ts b/packages/omi/omi.d.ts index 48cd552e2f..470d06e723 100644 --- a/packages/omi/omi.d.ts +++ b/packages/omi/omi.d.ts @@ -89,6 +89,8 @@ declare namespace Omi { css?: (() => string) | string; } + type PropType = String | Number | Boolean | Array | Object | Array; + abstract class WeElement

{ constructor(); @@ -97,7 +99,15 @@ declare namespace Omi { static css?: string | CSSStyleSheet | (string | CSSStyleSheet)[] static tagName: string static define(name: string): void - + static props?: { + [key: string]: { + type?: PropType; + default?: any; + reflect?: boolean | ((value: any) => any); + changed?: (newValue: any, oldValue: any) => void; + } + } + props: OmiProps

| P prevProps: OmiProps

| P rootElement?: HTMLElement @@ -134,6 +144,14 @@ declare namespace Omi { static css?: string | CSSStyleSheet | (string | CSSStyleSheet)[] static tagName: string static define(name: string): void + static props?: { + [key: string]: { + type?: PropType; + default?: any; + reflect?: boolean | ((value: any) => any); + changed?: (newValue: any, oldValue: any) => void; + } + } props: OmiProps

| P prevProps: OmiProps

| P diff --git a/packages/omi/package.json b/packages/omi/package.json index c69a7b1e41..03a20555d0 100644 --- a/packages/omi/package.json +++ b/packages/omi/package.json @@ -1,6 +1,6 @@ { "name": "omi", - "version": "7.4.4", + "version": "7.4.5", "scripts": { "start": "vite", "dev-vite": "vite", diff --git a/packages/omi/src/component.ts b/packages/omi/src/component.ts index 83d04f627f..025bdb5faf 100644 --- a/packages/omi/src/component.ts +++ b/packages/omi/src/component.ts @@ -50,6 +50,25 @@ export class Component extends HTMLElement { constructor() { super() + + if (!this.constructor.defaultProps) { + this.constructor.defaultProps = {} + } + if (!this.constructor.propTypes) { + this.constructor.propTypes = {} + } + if (!this.constructor.reflectProps) { + this.constructor.reflectProps = {} + } + if (this.constructor.props) { + for (const propName in this.constructor.props) { + const prop = this.constructor.props[propName] + this.constructor.defaultProps[propName] = prop.default + this.constructor.propTypes[propName] = prop.type + this.constructor.reflectProps[propName] = prop.reflect + } + } + // @ts-ignore fix lazy load props missing this.props = Object.assign( {}, @@ -61,6 +80,19 @@ export class Component extends HTMLElement { this.rootElement = null } + attributeChangedCallback(name, oldValue, newValue) { + if (this.constructor.props && this.constructor.props[name]) { + const prop = this.constructor.props[name] + if (prop.changed) { + prop.changed.call(this, newValue, oldValue) + } + } + } + + static get observedAttributes() { + return this.props ? Object.keys(this.props) : [] + } + injectObject() { let p: ExtendedElement = this.parentNode as ExtendedElement // @ts-ignore deprecated diff --git a/packages/omi/src/index.ts b/packages/omi/src/index.ts index 0f3c4a6f4d..7402f29855 100644 --- a/packages/omi/src/index.ts +++ b/packages/omi/src/index.ts @@ -18,4 +18,4 @@ export { Signal } from './signal' export { css } from './css-tag' export { mixin } from './options' export { registerDirective } from './directive' -export const version = '7.4.4' +export const version = '7.4.5' diff --git a/packages/omi/test/props.test.jsx b/packages/omi/test/props.test.jsx index a1d3ac313a..21f3437dd7 100644 --- a/packages/omi/test/props.test.jsx +++ b/packages/omi/test/props.test.jsx @@ -7,6 +7,7 @@ import { getHost, h } from '@/index' +import { genNode } from './gen-node' describe('props', () => { let parentElement @@ -145,5 +146,48 @@ describe('props', () => { expect(valA === valB).toBe(true) }) + it('static props 1', () => { + let a = true + class Ele extends Component { + static props = { + count: { + default: 1 + } + } + + render(props) { + return ( +

{props.count}
+ ) + } + } + let node = genNode() + define(node.name, Ele) + render(, parentElement) + expect(parentElement.firstChild.shadowRoot.innerHTML).toBe('
1
') + + }) + + it('static props 2', () => { + let a = true + class Ele extends Component { + static props = { + count: { + default: 1, + } + } + + render(props) { + return ( +
{props.count}
+ ) + } + } + let node = genNode() + define(node.name, Ele) + render(, parentElement) + expect(parentElement.firstChild.shadowRoot.innerHTML).toBe('
2
') + + }) }) \ No newline at end of file