diff --git a/.bomlint.json b/.bomlint.json new file mode 100644 index 0000000..345d648 --- /dev/null +++ b/.bomlint.json @@ -0,0 +1,7 @@ +{ + "@types/react": "^16.7.22", + "tea-cup-core": "2.3.0", + "react-tea-cup": "2.3.0", + "ts-jest": "^24.1.0", + "bomlint": "1.2.3" +} \ No newline at end of file diff --git a/.circleci/config.yml b/.circleci/config.yml index 4d27435..4ee8a13 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,9 +1,11 @@ -version: 2 +version: 2.1 +orbs: + browser-tools: circleci/browser-tools@1.1.1 defaults: &defaults working_directory: ~/repo docker: - - image: circleci/node:erbium + - image: circleci/node:gallium jobs: build: @@ -16,6 +18,31 @@ jobs: root: ~/repo paths: . + webtests: + working_directory: ~/repo + docker: + - image: circleci/openjdk:11-jdk-browsers + environment: + DISPLAY: :99 + + steps: + - run: sudo Xvfb :99 -screen 0 1920x1200x24 > /dev/null 2>&1 & + - attach_workspace: + at: ~/repo + - browser-tools/install-chrome + - browser-tools/install-chromedriver + - run: + command: | + google-chrome --version + chromedriver --version + ps -efa | grep Xvfb + name: Check install + - run: cd webtests && export DISPLAY=:99 && mvn clean install -Dwebdriver.chrome.driver=/usr/local/bin/chromedriver + - store_artifacts: + path: ~/repo/webtests/target/surefire-reports + - store_artifacts: + path: ~/repo/webtests/target/videos + deploy: <<: *defaults steps: @@ -34,9 +61,13 @@ workflows: filters: tags: only: /\d+\.\d+\.\d+/ + - webtests: + requires: + - build - deploy: requires: - build + - webtests filters: tags: only: /\d+\.\d+\.\d+/ diff --git a/CHANGELOG.md b/CHANGELOG.md index d9c3f3c..9369af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## v2.2.2 (24/04/2023) + +#### closed + +- [**closed**] DocSub async dispatch [#93](https://github.com/vankeisb/react-tea-cup/pull/93) +- [**closed**] Fix model undef check, update README [#88](https://github.com/vankeisb/react-tea-cup/pull/88) + +#### dependencies + +- [**dependencies**] Bump decode-uri-component from 0.2.0 to 0.2.2 [#89](https://github.com/vankeisb/react-tea-cup/pull/89) +- [**dependencies**] Bump qs from 6.5.2 to 6.5.3 [#90](https://github.com/vankeisb/react-tea-cup/pull/90) +- [**dependencies**] Bump express from 4.17.1 to 4.18.2 [#91](https://github.com/vankeisb/react-tea-cup/pull/91) +- [**dependencies**] Bump json5 from 1.0.1 to 1.0.2 [#92](https://github.com/vankeisb/react-tea-cup/pull/92) +- [**dependencies**] Bump async from 2.6.3 to 2.6.4 [#80](https://github.com/vankeisb/react-tea-cup/pull/80) +- [**dependencies**] Bump minimist from 1.2.5 to 1.2.6 [#79](https://github.com/vankeisb/react-tea-cup/pull/79) +- [**dependencies**] Bump cross-fetch from 2.2.3 to 2.2.6 [#81](https://github.com/vankeisb/react-tea-cup/pull/81) +- [**dependencies**] Bump eventsource from 1.0.7 to 1.1.1 [#82](https://github.com/vankeisb/react-tea-cup/pull/82) +- [**dependencies**] Bump jsdom from 16.4.0 to 16.5.0 [#84](https://github.com/vankeisb/react-tea-cup/pull/84) +- [**dependencies**] Bump terser from 4.8.0 to 4.8.1 [#85](https://github.com/vankeisb/react-tea-cup/pull/85) + +--- + ## v2.2.1 (02/09/2022) #### closed diff --git a/build.sh b/build.sh index eae3844..c622159 100755 --- a/build.sh +++ b/build.sh @@ -1,7 +1,9 @@ yarn install && \ +yarn bomlint && \ cd core && \ ./build.sh && \ cd ../tea-cup && \ ./build.sh && \ cd ../samples && \ -yarn test --watchAll=false +yarn test --watchAll=false && \ +yarn build diff --git a/bump-version.js b/bump-version.js index 57a88a0..1a19679 100644 --- a/bump-version.js +++ b/bump-version.js @@ -2,26 +2,25 @@ const fs = require('fs'); const VERSION = process.env.VERSION; -console.log("Bumping to " + VERSION); +console.log('Bumping to ' + VERSION); function withJsonFile(name, callback) { - const text = fs.readFileSync(name); - const json = JSON.parse(text); - callback(json) - fs.writeFileSync(name, JSON.stringify(json, null, " ")) + const text = fs.readFileSync(name); + const json = JSON.parse(text); + callback(json); + fs.writeFileSync(name, JSON.stringify(json, null, ' ')); } -withJsonFile("./core/package.json", j => { - j.version = VERSION; +withJsonFile('./core/package.json', (j) => { + j.version = VERSION; }); -withJsonFile("./tea-cup/package.json", j => { - j.version = VERSION; - j.peerDependencies['tea-cup-core'] = '^' + VERSION; +withJsonFile('./tea-cup/package.json', (j) => { + j.version = VERSION; + j.peerDependencies['tea-cup-core'] = VERSION; }); -withJsonFile('./samples/package.json', j => { - j.dependencies['tea-cup-core'] = VERSION; - j.dependencies['react-tea-cup'] = VERSION; +withJsonFile('./samples/package.json', (j) => { + j.dependencies['tea-cup-core'] = VERSION; + j.dependencies['react-tea-cup'] = VERSION; }); - diff --git a/core/package.json b/core/package.json index bd7e76a..0cfbd58 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "tea-cup-core", - "version": "2.2.2", + "version": "2.3.0", "description": "react-tea-cup core classes and utilities (Maybe etc)", "author": "Rémi Van Keisbelck ", "license": "MIT", diff --git a/core/src/TeaCup/Animation.ts b/core/src/TeaCup/Animation.ts index 5437341..129abdd 100644 --- a/core/src/TeaCup/Animation.ts +++ b/core/src/TeaCup/Animation.ts @@ -25,20 +25,6 @@ import { Sub } from './Sub'; -let subs: Array> = []; - -let ticking = false; - -function tick() { - if (!ticking) { - ticking = true; - requestAnimationFrame((t: number) => { - subs.forEach((s) => s.trigger(t)); - ticking = false; - }); - } -} - class RafSub extends Sub { readonly mapper: (t: number) => M; @@ -49,13 +35,9 @@ class RafSub extends Sub { protected onInit() { super.onInit(); - subs.push(this); - tick(); - } - - protected onRelease() { - super.onRelease(); - subs = subs.filter((s) => s !== this); + setTimeout(() => { + this.isActive() && requestAnimationFrame((t) => this.trigger(t)); + }); } trigger(t: number) { diff --git a/core/src/TeaCup/Sub.ts b/core/src/TeaCup/Sub.ts index 663d11e..88e9922 100644 --- a/core/src/TeaCup/Sub.ts +++ b/core/src/TeaCup/Sub.ts @@ -27,6 +27,7 @@ import { Dispatcher } from './Dispatcher'; export abstract class Sub { protected dispatcher: Dispatcher | undefined; + private active: boolean = false; static none(): Sub { return new SubNone(); @@ -38,16 +39,21 @@ export abstract class Sub { init(dispatch: Dispatcher): void { this.dispatcher = dispatch; + this.active = true; this.onInit(); } release(): void { - this.dispatcher = undefined; + this.active = false; this.onRelease(); } + isActive() { + return this.active; + } + protected dispatch(m: Msg): void { - this.dispatcher && this.dispatcher(m); + this.dispatcher?.(m); } protected onInit() {} diff --git a/package.json b/package.json index edcc7c5..f735955 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,13 @@ "jest": "24.9.0", "prettier": "2.0.5", "rimraf": "^2.6.3", - "ts-jest": "24.0.2", - "typescript": "~3.9.7" + "ts-jest": "^24.1.0", + "typescript": "~3.9.7", + "bomlint": "1.2.3" }, "scripts": { "release:gh": "gren release", - "release:changelog": "gren changelog --tags all --generate --override" + "release:changelog": "gren changelog --tags all --generate --override", + "bomlint": "bomlint --allow-conflicts react package.json ./core/package.json ./tea-cup/package.json ./samples/package.json" } } \ No newline at end of file diff --git a/samples/package.json b/samples/package.json index 686901e..14f8675 100644 --- a/samples/package.json +++ b/samples/package.json @@ -5,14 +5,14 @@ "proxy": "https://api.github.com", "dependencies": { "@types/node": "10.12.19", - "@types/react": "16.7.22", + "@types/react": "^16.7.22", "@types/react-dom": "16.0.11", "jest-enzyme": "^7.1.1", "react": "^16.7.0", "react-dom": "^16.7.0", "react-scripts": "3.4.3", - "react-tea-cup": "2.2.2", - "tea-cup-core": "2.2.2" + "react-tea-cup": "2.3.0", + "tea-cup-core": "2.3.0" }, "scripts": { "start": "react-scripts start", @@ -36,7 +36,6 @@ "enzyme": "^3.10.0", "enzyme-adapter-react-16": "^1.15.1", "enzyme-to-json": "^3.4.2", - "jest-fetch-mock": "^2.1.2", - "ts-jest": "^24.1.0" + "jest-fetch-mock": "^2.1.2" } } \ No newline at end of file diff --git a/samples/src/App.tsx b/samples/src/App.tsx index 07227bd..3297dd5 100755 --- a/samples/src/App.tsx +++ b/samples/src/App.tsx @@ -24,18 +24,7 @@ */ import React from 'react'; -import { - Cmd, - Dispatcher, - just, - map, - Maybe, - maybeOf, - noCmd, - nothing, - Sub, - Task, -} from 'tea-cup-core'; +import { Cmd, Dispatcher, just, map, Maybe, maybeOf, noCmd, nothing, Sub, Task } from 'tea-cup-core'; import { DevTools, newUrl, @@ -60,7 +49,7 @@ import * as TimeSample from './Samples/TimeSample'; import * as EventsSample from './Samples/EventsSample'; import * as SelectSample from './Samples/SelectSample'; import * as PortsSample from './Samples/PortsSample'; -import { appSamplePorts } from "./Samples/PortsSample"; +import { appSamplePorts } from './Samples/PortsSample'; enum Tab { All, @@ -367,7 +356,7 @@ function mapPortsSample(m: PortsSample.Msg): Msg { return { type: 'portsSample', child: m, - } + }; } function view(dispatch: Dispatcher, model: Model) { @@ -464,16 +453,16 @@ function viewTodos(dispatch: Dispatcher, todoMvc: TodoMvc) { {active ? ( {label} ) : ( - { - e.preventDefault(); - dispatch({ type: 'tabClicked', tab: t }); - }} - > - {label} - - )} + { + e.preventDefault(); + dispatch({ type: 'tabClicked', tab: t }); + }} + > + {label} + + )} ); } @@ -485,46 +474,46 @@ function viewTodos(dispatch: Dispatcher, todoMvc: TodoMvc) { {todos.length === 0 ? (

You have nothing to do ! Neat !!

) : ( -
-
    - {viewTab(Tab.All)} - {viewTab(Tab.Open)} - {viewTab(Tab.Closed)} -
- -
- )} +
+
    + {viewTab(Tab.All)} + {viewTab(Tab.Open)} + {viewTab(Tab.Closed)} +
+ +
+ )} ); } @@ -566,7 +555,6 @@ function viewSamples(dispatch: Dispatcher, samples: Samples) { return (
{backToHome(dispatch)} -

Samples

This is the samples app for react-tea-cup.

@@ -594,10 +582,14 @@ function viewSamples(dispatch: Dispatcher, samples: Samples) { {SelectSample.view(map(dispatch, mapSelectSample), samples.select)}

Ports

{PortsSample.view(map(dispatch, mapPortsSample), samples.ports)} - +
); } @@ -661,7 +653,7 @@ function update(msg: Msg, model: Model): [Model, Cmd] { const macTime = TimeSample.update(msg.child, s.time); return [{ ...s, time: macTime[0] }, macTime[1].map(mapTimeSample)]; }); - case "portsSample": + case 'portsSample': return mapSample((s: Samples) => { const mac = PortsSample.update(msg.child, s.ports); return [{ ...s, ports: mac[0] }, mac[1].map(mapPortsSample)]; diff --git a/samples/src/Samples/Counter.tsx b/samples/src/Samples/Counter.tsx index 8480c1a..d4bae77 100644 --- a/samples/src/Samples/Counter.tsx +++ b/samples/src/Samples/Counter.tsx @@ -42,10 +42,14 @@ export function init(): [Model, Cmd] { // need this "dispatch" arg, so that you can emit Msgs export function view(dispatch: Dispatcher, model: Model) { return ( -
- - {model} - +
+ + {model} +
); } diff --git a/samples/src/Samples/EventsSample.tsx b/samples/src/Samples/EventsSample.tsx index 8de1622..305d520 100644 --- a/samples/src/Samples/EventsSample.tsx +++ b/samples/src/Samples/EventsSample.tsx @@ -25,37 +25,41 @@ import * as React from 'react'; import { Dispatcher, Cmd, Sub, noCmd, nothing, just, Maybe } from 'tea-cup-core'; -import {DocumentEvents, WindowEvents} from "react-tea-cup"; +import { DocumentEvents, WindowEvents } from 'react-tea-cup'; export type Model = { - clicked: Maybe - moved: Maybe - scrolled: Maybe - nbResizeLeft: number - nbResizeRight: number + clicked: Maybe; + moved: Maybe; + scrolled: Maybe; + nbResizeLeft: number; + nbResizeRight: number; }; type MousePosition = { pos: Position; page: Position; offset: Position; -} +}; -type Position = [number, number] +type Position = [number, number]; -export type Msg = { - type: 'clicked', - position: MousePosition -} | { - type: 'moved', - position: MousePosition -} | { - type: 'resized', - left: boolean -} | { - type: 'scrolled', - scroll: Position -}; +export type Msg = + | { + type: 'clicked'; + position: MousePosition; + } + | { + type: 'moved'; + position: MousePosition; + } + | { + type: 'resized'; + left: boolean; + } + | { + type: 'scrolled'; + scroll: Position; + }; export function init(): [Model, Cmd] { return noCmd({ @@ -69,22 +73,19 @@ export function init(): [Model, Cmd] { export function view(dispatch: Dispatcher, model: Model) { return ( -
+ {model.clicked .map(viewMousePosition('Clicked')) - .withDefault(
Waiting for click ...
) - } - {model.moved - .map(viewMousePosition('Moved')) - .withDefault(
Waiting for move ...
) - } - {model.scrolled - .map(viewPosition('Scrolled')) - .withDefault(
Waiting for move ...
) - } -
resized left : {model.nbResizeLeft}
-
resized right : {model.nbResizeRight}
-
+ .withDefault(
Waiting for click ...
)} + {model.moved.map(viewMousePosition('Moved')).withDefault(
Waiting for move ...
)} + {model.scrolled.map(viewPosition('Scrolled')).withDefault(
Waiting for move ...
)} +
+ resized left : {model.nbResizeLeft} +
+
+ resized right : {model.nbResizeRight} +
+ ); } @@ -93,21 +94,21 @@ export function update(msg: Msg, model: Model): [Model, Cmd] { case 'clicked': { const model1: Model = { ...model, - clicked: just(msg.position) + clicked: just(msg.position), }; return [model1, Cmd.none()]; } case 'moved': { const model1: Model = { ...model, - moved: just(msg.position) + moved: just(msg.position), }; return [model1, Cmd.none()]; } case 'scrolled': { const model1: Model = { ...model, - scrolled: just(msg.scroll) + scrolled: just(msg.scroll), }; return [model1, Cmd.none()]; } @@ -126,40 +127,46 @@ const windowEvents = new WindowEvents(); export function subscriptions(model: Model): Sub { return Sub.batch([ - documentEvents.on('click', (e: MouseEvent) => ( - { - type: 'clicked', - position: { - pos: [e.x, e.y], - page: [e.pageX, e.pageY], - offset: [e.offsetX, e.offsetY] - } - } as Msg - )), - documentEvents.on('mousemove', (e: MouseEvent) => ({ - type: 'moved', - position: { - pos: [e.x, e.y], - page: [e.pageX, e.pageY], - offset: [e.offsetX, e.offsetY] - } - } as Msg)), + documentEvents.on( + 'click', + (e: MouseEvent) => + ({ + type: 'clicked', + position: { + pos: [e.x, e.y], + page: [e.pageX, e.pageY], + offset: [e.offsetX, e.offsetY], + }, + } as Msg), + ), + documentEvents.on( + 'mousemove', + (e: MouseEvent) => + ({ + type: 'moved', + position: { + pos: [e.x, e.y], + page: [e.pageX, e.pageY], + offset: [e.offsetX, e.offsetY], + }, + } as Msg), + ), windowEvents.on('scroll', (e: Event) => { return { type: 'scrolled', - scroll: [window.scrollX, window.scrollY] + scroll: [window.scrollX, window.scrollY], } as Msg; }), windowEvents.on('resize', () => { return { type: 'resized', - left: true + left: true, } as Msg; }), windowEvents.on('resize', () => { return { type: 'resized', - left: false + left: false, } as Msg; }), ]); @@ -167,14 +174,17 @@ export function subscriptions(model: Model): Sub { function viewMousePosition(title: string) { return (position: MousePosition) => { - return (
- {title}: - {viewPosition('Position')(position.pos)}  - {viewPosition('Page')(position.page)}  - {viewPosition('Offset')(position.offset)} -
+ return ( +
+ + {title}:{' '} + + {viewPosition('Position')(position.pos)}  + {viewPosition('Page')(position.page)}  + {viewPosition('Offset')(position.offset)} +
); - } + }; } function viewPosition(title: string) { @@ -184,5 +194,5 @@ function viewPosition(title: string) { {title} {position[0]},{position[1]}  ); - } + }; } diff --git a/samples/src/Samples/PortsSample.tsx b/samples/src/Samples/PortsSample.tsx index 379ea0f..2f534d2 100644 --- a/samples/src/Samples/PortsSample.tsx +++ b/samples/src/Samples/PortsSample.tsx @@ -53,7 +53,6 @@ export function init(): [Model, Cmd] { export function view(dispatch: Dispatcher, model: Model) { return (
-

Counter with ports

Value = {model}
diff --git a/samples/src/Samples/Raf.tsx b/samples/src/Samples/Raf.tsx index b6c2ebf..25e1701 100644 --- a/samples/src/Samples/Raf.tsx +++ b/samples/src/Samples/Raf.tsx @@ -23,22 +23,28 @@ * */ -import { Dispatcher, Cmd, noCmd, Sub, onAnimationFrame } from 'tea-cup-core'; +import { Cmd, Dispatcher, noCmd, onAnimationFrame, Sub } from 'tea-cup-core'; import * as React from 'react'; export interface Model { readonly started: boolean; readonly t: number; + readonly t2: number; readonly fps: number; readonly animText: string; } -export type Msg = { type: 'raf'; t: number } | { type: 'toggle' } | { type: 'text-changed'; text: string }; +export type Msg = + | { type: 'raf'; t: number } + | { type: 'toggle' } + | { type: 'text-changed'; text: string } + | { type: 'raf2'; t: number }; export function init() { return noCmd({ started: false, t: 0, + t2: 0, fps: 0, animText: 'This text gets animated...', }); @@ -54,6 +60,7 @@ export function view(dispatch: Dispatcher, model: Model) {
@@ -64,8 +71,17 @@ export function view(dispatch: Dispatcher, model: Model) { } />
- Time = {Math.round(model.t)} - + + Time = {Math.round(model.t)} + +
+ + t2 = {Math.round(model.t2)} + +
+ {fps} {anim}
@@ -102,17 +118,22 @@ export function update(msg: Msg, model: Model): [Model, Cmd] { switch (msg.type) { case 'toggle': return noCmd({ ...model, started: !model.started }); - case 'raf': + case 'raf': { const delta = msg.t - model.t; - const fps = delta === 0 - ? model.fps - : 1000 / delta; + const fps = delta === 0 ? model.fps : 1000 / delta; return noCmd({ ...model, t: msg.t, fps: fps, }); + } + case 'raf2': { + return noCmd({ + ...model, + t2: msg.t, + }); + } case 'text-changed': return noCmd({ ...model, @@ -121,11 +142,16 @@ export function update(msg: Msg, model: Model): [Model, Cmd] { } } -export function subscriptions(model: Model) { +export function subscriptions(model: Model): Sub { if (model.started) { - return onAnimationFrame((t: number) => { - return { type: 'raf', t: t } as Msg; - }); + return Sub.batch([ + onAnimationFrame((t: number) => { + return { type: 'raf', t: t } as Msg; + }), + onAnimationFrame((t: number) => { + return { type: 'raf2', t: t } as Msg; + }), + ]); } else { return Sub.none(); } diff --git a/samples/src/Samples/__snapshots__/Counter.test.ts.snap b/samples/src/Samples/__snapshots__/Counter.test.ts.snap index 7d900f9..6ade472 100644 --- a/samples/src/Samples/__snapshots__/Counter.test.ts.snap +++ b/samples/src/Samples/__snapshots__/Counter.test.ts.snap @@ -3,16 +3,21 @@ exports[`Test Counter view state snapshot 1`] = `
- + 1313 - + 0 - + 0 - + 0