Skip to content

Commit

Permalink
Merge branch 'main' into unmarked-computed
Browse files Browse the repository at this point in the history
  • Loading branch information
developit authored Sep 15, 2022
2 parents 160ea77 + b70bc48 commit e187b63
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 68 deletions.
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://unpkg.com/@changesets/config@2.1.1/schema.json",
"changelog": "@changesets/cli/changelog",
"changelog": ["@changesets/changelog-github", { "repo": "preactjs/signals" }],
"commit": false,
"fixed": [],
"linked": [],
Expand Down
7 changes: 7 additions & 0 deletions .changeset/smooth-coins-warn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@preact/signals-core": patch
"@preact/signals": patch
"@preact/signals-react": patch
---

Move `types` field in `package.json` to the top of the entry list to ensure that TypeScript always finds it.
5 changes: 5 additions & 0 deletions .changeset/unlucky-rocks-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@preact/signals": patch
---

Optimize the performance of prop bindings in Preact
140 changes: 140 additions & 0 deletions docs/demos/animation/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { useEffect } from "preact/hooks";
import { useSignal, useComputed, Signal } from "@preact/signals";
import "./style.css";
import { setFlashingEnabled } from "../render-flasher";

const COUNT = 200;
const LOOPS = 6;

export default function Animation() {
const x = useSignal(0);
const y = useSignal(0);
const big = useSignal(false);
const counter = useSignal(0);

useEffect(() => {
let touch = navigator.maxTouchPoints > 1;

// set mouse position state on move:
function move(e: MouseEvent | TouchEvent) {
const pointer = "touches" in e ? e.touches[0] : e;
x.value = pointer.clientX;
y.value = pointer.clientY - 52;
}
// holding the mouse down enables big mode:
function setBig(e: Event) {
big.value = true;
e.preventDefault();
}
function notBig() {
big.value = false;
}
addEventListener(touch ? "touchmove" : "mousemove", move);
addEventListener(touch ? "touchstart" : "mousedown", setBig);
addEventListener(touch ? "touchend" : "mouseup", notBig);

let running = true;
function tick() {
if (running === false) return;
counter.value++;
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);

setFlashingEnabled(false);
setTimeout(() => setFlashingEnabled(false), 150);

return () => {
running = false;
setFlashingEnabled(true);
removeEventListener(touch ? "touchmove" : "mousemove", move);
removeEventListener(touch ? "touchstart" : "mousedown", setBig);
removeEventListener(touch ? "touchend" : "mouseup", notBig);
};
}, []);

const max = useComputed(() => {
return (
COUNT +
Math.round(Math.sin((counter.value / 90) * 2 * Math.PI) * COUNT * 0.5)
);
});

let circles = [];

// the advantage of JSX is that you can use the entirety of JS to "template":
for (let i = max.value; i--; ) {
circles[i] = (
<Circle i={i} x={x} y={y} big={big} max={max} counter={counter} />
);
}

return (
<div class="animation">
<Circle i={0} x={x} y={y} big={big} max={max} counter={counter} label />
{circles}
</div>
);
}

interface CircleProps {
i: number;
x: Signal<number>;
y: Signal<number>;
big: Signal<boolean>;
max: Signal<number>;
counter: Signal<number>;
label?: boolean;
}

/** Represents a single coloured dot. */
function Circle({ label, i, x, y, big, max, counter }: CircleProps) {
const hue = useComputed(() => {
let f = (i / max.value) * LOOPS;
return (f * 255 + counter.value * 10) % 255;
});

const offsetX = useComputed(() => {
let f = (i / max.value) * LOOPS;
let θ = f * 2 * Math.PI;
return Math.sin(θ) * (20 + i * 2);
});

const offsetY = useComputed(() => {
let f = (i / max.value) * LOOPS;
let θ = f * 2 * Math.PI;
return Math.cos(θ) * (20 + i * 2);
});

// For testing nested "computeds-only" components (for GC):
// return <CircleInner {...{ label, x, y, offsetX, offsetY, hue, big }} />;
// }
// function CircleInner({ label, x, y, offsetX, offsetY, hue, big }) {

const style = useComputed(() => {
let left = (x.value + offsetX.value) | 0;
let top = (y.value + offsetY.value) | 0;
return `left:${left}px; top:${top}px; border-color:hsl(${hue},100%,50%);`;
});

const cl = useComputed(() => {
let cl = "circle";
if (label) cl += " label";
if (big.value) cl += " big";
return cl;
});

return (
<div class={cl} style={style}>
{label && <Label x={x} y={y} />}
</div>
);
}

function Label({ x, y }: { x: Signal<number>; y: Signal<number> }) {
return (
<span class="label">
{x},{y}
</span>
);
}
49 changes: 49 additions & 0 deletions docs/demos/animation/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
.animation {
position: absolute;
left: 0;
top: 52px;
bottom: 0;
width: 100%;
background: #222;
color: #888;
text-rendering: optimizeSpeed;
touch-action: none;
overflow: hidden;
}

.circle {
position: absolute;
left: 0;
top: 0;
width: 8px;
height: 8px;
margin: -5px 0 0 -5px;
border: 2px solid #f00;
border-radius: 50%;
transform-origin: 50% 50%;
transition: all 250ms ease;
transition-property: width, height, margin;
pointer-events: none;
overflow: hidden;
font-size: 9px;
line-height: 25px;
text-indent: 15px;
white-space: nowrap;

&.label {
overflow: visible;
}

&.big {
width: 24px;
height: 24px;
margin: -13px 0 0 -13px;
}

& > .label {
position: absolute;
left: 0;
top: 0;
z-index: 10;
}
}
1 change: 1 addition & 0 deletions docs/demos/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const demos = {
GlobalCounter,
DuelingCounters,
Nesting: lazy(() => import("./nesting")),
Animation: lazy(() => import("./animation")),
};

function Demos() {
Expand Down
15 changes: 12 additions & 3 deletions docs/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,21 @@ function packages(prod: boolean) {

export default defineConfig(env => ({
plugins: [
preact({
exclude: /\breact/,
}),
process.env.DEBUG
? preact({
exclude: /\breact/,
})
: null,
multiSpa(["index.html", "demos/**/*.html"]),
unsetPreactAliases(),
],
esbuild: {
jsx: "automatic",
jsxImportSource: "preact",
},
optimizeDeps: {
include: ["preact/jsx-runtime", "preact/jsx-dev-runtime"],
},
build: {
polyfillModulePreload: false,
cssCodeSplit: false,
Expand Down
4 changes: 2 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
"source": "src/index.ts",
"exports": {
".": {
"types": "./dist/signals-core.d.ts",
"browser": "./dist/signals-core.module.js",
"umd": "./dist/signals-core.umd.js",
"import": "./dist/signals-core.mjs",
"require": "./dist/signals-core.js",
"types": "./dist/signals-core.d.ts"
"require": "./dist/signals-core.js"
}
},
"mangle": "../../mangle.json",
Expand Down
4 changes: 2 additions & 2 deletions packages/preact/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
"source": "src/index.ts",
"exports": {
".": {
"types": "./dist/signals.d.ts",
"browser": "./dist/signals.module.js",
"umd": "./dist/signals.umd.js",
"import": "./dist/signals.mjs",
"require": "./dist/signals.js",
"types": "./dist/signals.d.ts"
"require": "./dist/signals.js"
}
},
"mangle": "../../mangle.json",
Expand Down
Loading

0 comments on commit e187b63

Please sign in to comment.