diff --git a/package-lock.json b/package-lock.json index c1ccae03d..a9fc82fff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "license": "Apache-2.0", "dependencies": { "@actions/core": "^1.10.0", - "@dcl/protocol": "1.0.0-6590614146.commit-db4a595", + "@dcl/protocol": "1.0.0-6721819745.commit-dd7b9dc", "@dcl/quickjs-emscripten": "^0.21.0-3680274614.commit-1808aa1", "@dcl/ts-proto": "1.153.0", "@types/fs-extra": "^9.0.12", @@ -577,9 +577,9 @@ } }, "node_modules/@dcl/protocol": { - "version": "1.0.0-6590614146.commit-db4a595", - "resolved": "https://registry.npmjs.org/@dcl/protocol/-/protocol-1.0.0-6590614146.commit-db4a595.tgz", - "integrity": "sha512-BaLAj9GPiAz/S4oNSgD28oEfdsDviDZgDOL8kPoZ+6NQ6H4FjnHTVr1AS7Sy7Evw1K77l3OfPPMjwN1IvaIygw==", + "version": "1.0.0-6721819745.commit-dd7b9dc", + "resolved": "https://registry.npmjs.org/@dcl/protocol/-/protocol-1.0.0-6721819745.commit-dd7b9dc.tgz", + "integrity": "sha512-IzygPKgFvd6ARKaPg0wgCMUMCPBRpUZthKzDND8tH7wNhqKKUj1AMLs+oiA+P9Y0k9XaMvxd5WJTqxLkjEvc6g==", "dependencies": { "@dcl/ts-proto": "1.154.0" } @@ -8134,9 +8134,9 @@ } }, "@dcl/protocol": { - "version": "1.0.0-6590614146.commit-db4a595", - "resolved": "https://registry.npmjs.org/@dcl/protocol/-/protocol-1.0.0-6590614146.commit-db4a595.tgz", - "integrity": "sha512-BaLAj9GPiAz/S4oNSgD28oEfdsDviDZgDOL8kPoZ+6NQ6H4FjnHTVr1AS7Sy7Evw1K77l3OfPPMjwN1IvaIygw==", + "version": "1.0.0-6721819745.commit-dd7b9dc", + "resolved": "https://registry.npmjs.org/@dcl/protocol/-/protocol-1.0.0-6721819745.commit-dd7b9dc.tgz", + "integrity": "sha512-IzygPKgFvd6ARKaPg0wgCMUMCPBRpUZthKzDND8tH7wNhqKKUj1AMLs+oiA+P9Y0k9XaMvxd5WJTqxLkjEvc6g==", "requires": { "@dcl/ts-proto": "1.154.0" }, diff --git a/package.json b/package.json index 13aac29b4..edcb6a93a 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "bugs": "https://github.com/decentraland/js-sdk-toolchain/issues", "dependencies": { "@actions/core": "^1.10.0", - "@dcl/protocol": "1.0.0-6590614146.commit-db4a595", + "@dcl/protocol": "1.0.0-6721819745.commit-dd7b9dc", "@dcl/quickjs-emscripten": "^0.21.0-3680274614.commit-1808aa1", "@dcl/ts-proto": "1.153.0", "@types/fs-extra": "^9.0.12", diff --git a/packages/@dcl/playground-assets/etc/playground-assets.api.md b/packages/@dcl/playground-assets/etc/playground-assets.api.md index 9f6638b2d..aeb8ffea0 100644 --- a/packages/@dcl/playground-assets/etc/playground-assets.api.md +++ b/packages/@dcl/playground-assets/etc/playground-assets.api.md @@ -1334,6 +1334,11 @@ export type IncludeUndefined = { // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-escape-greater-than) The ">" character should be escaped using a backslash to avoid confusion with an HTML tag +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag +// Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag // Warning: (tsdoc-escape-right-brace) The "}" character should be escaped using a backslash to avoid confusion with a TSDoc inline tag // Warning: (tsdoc-malformed-inline-tag) Expecting a TSDoc tag starting with "{@" @@ -2853,6 +2858,7 @@ export namespace PBUiInput { // @public (undocumented) export interface PBUiInputResult { + isSubmit?: boolean | undefined; // (undocumented) value: string; } @@ -3900,6 +3906,7 @@ export interface UiInputProps extends Omit { // (undocumented) font?: UiFontType; onChange?(value: string): void; + onSubmit?(value: string): void; // (undocumented) textAlign?: TextAlignType; } diff --git a/packages/@dcl/react-ecs/src/components/Input/index.tsx b/packages/@dcl/react-ecs/src/components/Input/index.tsx index 3f68cbb3e..bbbb86bbf 100644 --- a/packages/@dcl/react-ecs/src/components/Input/index.tsx +++ b/packages/@dcl/react-ecs/src/components/Input/index.tsx @@ -29,6 +29,9 @@ function parseUiInput(props: Partial): PBUiInput { onChange={(value) => { email = value }} + onSubmit={(value) => { + email = value + }} uiBackground={{ color: Color4.Red() }} uiTransform={{ width: 200, height: 36 }} value={textValue} diff --git a/packages/@dcl/react-ecs/src/components/Input/types.ts b/packages/@dcl/react-ecs/src/components/Input/types.ts index 6c138e99e..6bdb9d709 100644 --- a/packages/@dcl/react-ecs/src/components/Input/types.ts +++ b/packages/@dcl/react-ecs/src/components/Input/types.ts @@ -7,6 +7,8 @@ import { TextAlignType, UiFontType } from '../Label/types' export interface UiInputProps extends Omit { /** function to be called on value change */ onChange?(value: string): void + /** function to be called on text field submit */ + onSubmit?(value: string): void font?: UiFontType textAlign?: TextAlignType } diff --git a/packages/@dcl/react-ecs/src/reconciler/index.ts b/packages/@dcl/react-ecs/src/reconciler/index.ts index 18049198d..488d5f6f8 100644 --- a/packages/@dcl/react-ecs/src/reconciler/index.ts +++ b/packages/@dcl/react-ecs/src/reconciler/index.ts @@ -33,8 +33,10 @@ function getPointerEnum(pointerKey: keyof Listeners): PointerEventType { } type OnChangeState = { - fn?: (val?: T) => void + onChangeCallback?: (val?: T) => void + onSubmitCallback?: (val?: T) => void value?: T + isSubmit?: boolean } export function createReconciler( engine: Pick< @@ -121,11 +123,26 @@ export function createReconciler( componentName: K ) { const componentId = getComponentId[componentName] - if ('onChange' in props) { - const onChange = props['onChange'] as OnChangeState['fn'] - updateOnChange(instance.entity, componentId, { fn: onChange }) - delete props['onChange'] + + const onChangeExists = 'onChange' in props + const onSubmitExists = 'onSubmit' in props + const entityState = changeEvents.get(instance.entity)?.get(componentId) + const onChange = onChangeExists + ? (props['onChange'] as OnChangeState['onChangeCallback']) + : entityState?.onChangeCallback + const onSubmit = onSubmitExists + ? (props['onSubmit'] as OnChangeState['onSubmitCallback']) + : entityState?.onSubmitCallback + + if (onChangeExists || onSubmitExists) { + updateOnChange(instance.entity, componentId, { + onChangeCallback: onChange, + onSubmitCallback: onSubmit + }) + delete (props as any).onChange + delete (props as any).onSubmit } + // We check if there is any key pending to be changed to avoid updating the existing component if (!Object.keys(props).length) { return @@ -194,9 +211,11 @@ export function createReconciler( function updateOnChange(entity: Entity, componentId: number, state?: OnChangeState) { const event = changeEvents.get(entity) || changeEvents.set(entity, new Map()).get(entity)! const oldState = event.get(componentId) - const fn = state?.fn + const onChangeCallback = state?.onChangeCallback + const onSubmitCallback = state?.onSubmitCallback const value = state?.value ?? oldState?.value - event.set(componentId, { fn, value }) + const isSubmit = state?.isSubmit ?? oldState?.isSubmit + event.set(componentId, { onChangeCallback, onSubmitCallback, value, isSubmit }) } const hostConfig: HostConfig< @@ -311,17 +330,23 @@ export function createReconciler( // Maybe this could be something similar to Input system, but since we // are going to use this only here, i prefer to scope it here. - function handleOnChange(componentId: number, resultComponent: typeof UiInputResult | typeof UiDropdownResult) { + function handleOnChange(componentId: number, resultComponent: typeof UiDropdownResult | typeof UiInputResult) { for (const [entity, Result] of engine.getEntitiesWith(resultComponent)) { const entityState = changeEvents.get(entity)?.get(componentId) - if (entityState?.fn && Result.value !== entityState.value) { - // Call onChange callback and update internal timestamp - entityState.fn(Result.value) - updateOnChange(entity, componentId, { - fn: entityState.fn, - value: Result.value - }) + const isSubmit = !!(Result as any).isSubmit + if (entityState?.onChangeCallback && Result.value !== entityState.value) { + entityState.onChangeCallback(Result.value) } + if (entityState?.onSubmitCallback && isSubmit && !entityState.isSubmit) { + entityState.onSubmitCallback(Result.value) + } + + updateOnChange(entity, componentId, { + onChangeCallback: entityState?.onChangeCallback, + onSubmitCallback: entityState?.onSubmitCallback, + value: Result.value, + isSubmit + }) } } diff --git a/packages/@dcl/sdk-commands/package-lock.json b/packages/@dcl/sdk-commands/package-lock.json index 37849f890..bef5ae5ab 100644 --- a/packages/@dcl/sdk-commands/package-lock.json +++ b/packages/@dcl/sdk-commands/package-lock.json @@ -15,7 +15,7 @@ "@dcl/inspector": "file:../inspector", "@dcl/linker-dapp": "^0.11.0", "@dcl/mini-comms": "1.0.1-20230216163137.commit-a4c75be", - "@dcl/protocol": "1.0.0-6590614146.commit-db4a595", + "@dcl/protocol": "1.0.0-6721819745.commit-dd7b9dc", "@dcl/quests-client": "^1.0.3", "@dcl/quests-manager": "^0.1.4", "@dcl/rpc": "^1.1.1", @@ -234,9 +234,9 @@ } }, "node_modules/@dcl/protocol": { - "version": "1.0.0-6590614146.commit-db4a595", - "resolved": "https://registry.npmjs.org/@dcl/protocol/-/protocol-1.0.0-6590614146.commit-db4a595.tgz", - "integrity": "sha512-BaLAj9GPiAz/S4oNSgD28oEfdsDviDZgDOL8kPoZ+6NQ6H4FjnHTVr1AS7Sy7Evw1K77l3OfPPMjwN1IvaIygw==", + "version": "1.0.0-6721819745.commit-dd7b9dc", + "resolved": "https://registry.npmjs.org/@dcl/protocol/-/protocol-1.0.0-6721819745.commit-dd7b9dc.tgz", + "integrity": "sha512-IzygPKgFvd6ARKaPg0wgCMUMCPBRpUZthKzDND8tH7wNhqKKUj1AMLs+oiA+P9Y0k9XaMvxd5WJTqxLkjEvc6g==", "dependencies": { "@dcl/ts-proto": "1.154.0" } @@ -3213,9 +3213,9 @@ } }, "@dcl/protocol": { - "version": "1.0.0-6590614146.commit-db4a595", - "resolved": "https://registry.npmjs.org/@dcl/protocol/-/protocol-1.0.0-6590614146.commit-db4a595.tgz", - "integrity": "sha512-BaLAj9GPiAz/S4oNSgD28oEfdsDviDZgDOL8kPoZ+6NQ6H4FjnHTVr1AS7Sy7Evw1K77l3OfPPMjwN1IvaIygw==", + "version": "1.0.0-6721819745.commit-dd7b9dc", + "resolved": "https://registry.npmjs.org/@dcl/protocol/-/protocol-1.0.0-6721819745.commit-dd7b9dc.tgz", + "integrity": "sha512-IzygPKgFvd6ARKaPg0wgCMUMCPBRpUZthKzDND8tH7wNhqKKUj1AMLs+oiA+P9Y0k9XaMvxd5WJTqxLkjEvc6g==", "requires": { "@dcl/ts-proto": "1.154.0" } diff --git a/packages/@dcl/sdk-commands/package.json b/packages/@dcl/sdk-commands/package.json index 26a3087c8..ed4ffb3f7 100644 --- a/packages/@dcl/sdk-commands/package.json +++ b/packages/@dcl/sdk-commands/package.json @@ -13,7 +13,7 @@ "@dcl/inspector": "file:../inspector", "@dcl/linker-dapp": "^0.11.0", "@dcl/mini-comms": "1.0.1-20230216163137.commit-a4c75be", - "@dcl/protocol": "1.0.0-6590614146.commit-db4a595", + "@dcl/protocol": "1.0.0-6721819745.commit-dd7b9dc", "@dcl/quests-client": "^1.0.3", "@dcl/quests-manager": "^0.1.4", "@dcl/rpc": "^1.1.1", diff --git a/test/build-ecs/fixtures/ecs7-scene/src/index.ts b/test/build-ecs/fixtures/ecs7-scene/src/index.ts index d353cd65b..87508c69f 100644 --- a/test/build-ecs/fixtures/ecs7-scene/src/index.ts +++ b/test/build-ecs/fixtures/ecs7-scene/src/index.ts @@ -15,19 +15,6 @@ import { } from '@dcl/ecs' import { Vector3, Quaternion, Color4 } from '@dcl/sdk/math' -// // import { isServer } from '~system/runtime' -// import { createServerTransport } from '@dcl/sdk/crdt-server' - -// if (!isServer()) { -// createServerTransport('ws://boedo.com') -// } - -// // if (isServer) { - -// // } - -export * from '@dcl/sdk' - const Door = engine.defineComponent('door', { open: Schemas.Boolean }) export function getRandomHexColor(): string { @@ -84,15 +71,16 @@ function circularSystem(dt: number) { } } -// Init -const initEntity = createCube(8, 1, 8) +export function main() { + const initEntity = createCube(8, 1, 8) -pointerEventsSystem.onPointerDown( - { entity: initEntity, opts: { button: InputAction.IA_POINTER, hoverText: 'CASLA' } }, - function () { - createCube(1 + Math.random() * 8, Math.random() * 8, 1 + Math.random() * 8) - } -) + pointerEventsSystem.onPointerDown( + { entity: initEntity, opts: { button: InputAction.IA_POINTER, hoverText: 'CASLA' } }, + function () { + createCube(1 + Math.random() * 8, Math.random() * 8, 1 + Math.random() * 8) + } + ) -engine.addSystem(circularSystem) -engine.addSystem(changeColorSystem) + engine.addSystem(circularSystem) + engine.addSystem(changeColorSystem) +} diff --git a/test/build-ecs/fixtures/ecs7-ui-ethereum/src/ui.tsx b/test/build-ecs/fixtures/ecs7-ui-ethereum/src/ui.tsx index c47658980..050b6213b 100644 --- a/test/build-ecs/fixtures/ecs7-ui-ethereum/src/ui.tsx +++ b/test/build-ecs/fixtures/ecs7-ui-ethereum/src/ui.tsx @@ -60,6 +60,7 @@ const uiComponent = () => ( onChange={(value) => { console.log({ value }) }} + onSubmit={(value) => console.log('onSubmit', value)} uiBackground={{ color: Color4.Red() }} diff --git a/test/ecs/components/UiInputResult.spec.ts b/test/ecs/components/UiInputResult.spec.ts index 287cf6d50..6bf8eeba4 100644 --- a/test/ecs/components/UiInputResult.spec.ts +++ b/test/ecs/components/UiInputResult.spec.ts @@ -7,7 +7,8 @@ describe('UiInputResult component', () => { const UiInputResult = components.UiInputResult(newEngine) testComponentSerialization(UiInputResult, { - value: 'Boedo its carnaval' + value: 'Boedo its carnaval', + isSubmit: false }) }) }) diff --git a/test/react-ecs/dropdown.spec.tsx b/test/react-ecs/dropdown.spec.tsx index 7abd23353..2fb34a547 100644 --- a/test/react-ecs/dropdown.spec.tsx +++ b/test/react-ecs/dropdown.spec.tsx @@ -80,14 +80,13 @@ describe('UiDropdown React ECS', () => { it('put the conditional en true, so we have the onChange fn again', async () => { conditional = true await engine.update(1) + expect(onChange).toBeCalledTimes(0) }) - it('should call the fn because the previuos store value was 1 and now it has 2', async () => { - await engine.update(1) - expect(onChange).toBeCalledTimes(1) - UiDropdownResult.getMutable(uiEntity).value = 2 + it('should call the fn only if there is a new change on it', async () => { + UiDropdownResult.getMutable(uiEntity).value = 4 await engine.update(1) - expect(onChange).toBeCalledWith(2) + expect(onChange).toBeCalledWith(4) onChange.mockClear() }) diff --git a/test/react-ecs/input.spec.tsx b/test/react-ecs/input.spec.tsx index cf55ce0f7..68ad80e91 100644 --- a/test/react-ecs/input.spec.tsx +++ b/test/react-ecs/input.spec.tsx @@ -10,6 +10,7 @@ describe('Ui Listeners React Ecs', () => { const UiInputResult = components.UiInputResult(engine) const uiEntity = ((engine.addEntity() as number) + 1) as Entity const onChange: jest.Mock | undefined = jest.fn() + const onSubmit: jest.Mock | undefined = jest.fn() const undefinedChange: jest.Mock | undefined = undefined let conditional = true let removeComponent = false @@ -28,6 +29,7 @@ describe('Ui Listeners React Ecs', () => { font="sans-serif" fontSize={14} onChange={conditional ? onChange : undefinedChange} + onSubmit={onSubmit} /> ) ) @@ -62,6 +64,10 @@ describe('Ui Listeners React Ecs', () => { await engine.update(1) expect(onChange).toBeCalledWith('Casla - ') onChange.mockClear() + expect(onSubmit).toBeCalledTimes(0) + UiInputResult.getMutable(uiEntity).isSubmit = true + await engine.update(1) + expect(onSubmit).toBeCalledTimes(1) removeComponent = true await engine.update(1) UiInputResult.create(uiEntity, { value: 'BOEDO' })