Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removes empty styles and adds ability to nest media rules #73

Merged
merged 17 commits into from
May 23, 2024
6 changes: 3 additions & 3 deletions examples/spring-dialog/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ const Dialog = component<DialogProps>(({ isOpen, width = '600px', height = '300p
{transition(({ spring }) => (
<Animated spring={spring} fn={styleFn(false, scope)}>
<Window $width={width} $height={height}>
<CloseButton onClick={onRequestClose} />
{slot}
<CloseButton onClick={onRequestClose} /> {/*should be last for tab focus*/}
</Window>
</Animated>
))}
Expand Down Expand Up @@ -104,8 +104,8 @@ type CloseButtonProps = {

const CloseButton = component<CloseButtonProps>(({ onClick }) => {
return (
<Button onClick={onClick}>
<svg width='24' height='24' viewBox='0 0 50 50'>
<Button onClick={onClick} aria-label='Close'>
<svg aria-hidden='true' width='24' height='24' viewBox='0 0 50 50'>
<path d='M 9.15625 6.3125 L 6.3125 9.15625 L 22.15625 25 L 6.21875 40.96875 L 9.03125 43.78125 L 25 27.84375 L 40.9375 43.78125 L 43.78125 40.9375 L 27.84375 25 L 43.6875 9.15625 L 40.84375 6.3125 L 25 22.15625 Z' />
</svg>
</Button>
Expand Down
26 changes: 0 additions & 26 deletions packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,6 @@ createRoot(document.getElementById('root')).render(content);

## JSX
JSX is a syntax extension for JavaScript that lets you write HTML-like markup inside a JavaScript file.
You can use it:

### via `jsx-runtime`

In your `tsconfig.json`, you must add these rows:

```json
Expand All @@ -152,28 +148,6 @@ In your `tsconfig.json`, you must add these rows:
```
The necessary functions will be automatically imported into your code.

If for some reason you don't want to use auto-imports, then you should use a different approach.

### via `h`

This is the function you need to enable JSX support. In your `tsconfig.json`:

```json
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment"
}
}
```

In this case, you will always have to import the `h` function and the `Fragment` component yourself.

```tsx
import { h, Fragment } from '@dark-engine/core';
```

```tsx
const content = (
<>
Expand Down
112 changes: 51 additions & 61 deletions packages/core/src/atom/atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import { type Hook } from '../fiber';
import { batch } from '../batch';

class Atom<T = unknown> {
private value: T;
private connections1: Map<Hook, Tuple<T>>;
private connections2: Map<T, Tuple<T>>;
private subjects: Set<ReadableAtom>;
private emitter: EventEmitter<'data', EmitterValue<T>>;

constructor(value: T) {
this.value = value;
private v: T; // value
private c1: Map<Hook, Tuple<T>>; // connnections 1
private c2: Map<T, Tuple<T>>; // connections 2
private s: Set<ReadableAtom>; // subjects
private e: EventEmitter<'data', EmitterValue<T>>;

constructor(x: T) {
this.v = x;
}

val(fn?: ShouldUpdate<T>, key?: T) {
Expand All @@ -30,92 +30,84 @@ class Atom<T = unknown> {
}
}

return this.value;
return this.v;
}

get() {
return this.value;
return this.v;
}

on(fn: SubscriberWithValue<EmitterValue<T>>) {
!this.emitter && (this.emitter = new EventEmitter());

return this.emitter.on('data', fn);
!this.e && (this.e = new EventEmitter());
return this.e.on('data', fn);
}

kill() {
if (this.connections1) {
for (const [hook, [_, __, ___, key]] of this.connections1) {
this.off(hook, key);
}
if (this.c1) {
for (const [hook, [_, __, ___, key]] of this.c1) this.off(hook, key);
}

if (this.connections2) {
for (const [key, [_, hook]] of this.connections2) {
this.off(hook, key);
}
if (this.c2) {
for (const [key, [_, hook]] of this.c2) this.off(hook, key);
}

this.connections1 = null;
this.connections2 = null;
this.emitter = null;
this.subjects = null;
this.c1 = null;
this.c2 = null;
this.e = null;
this.s = null;
}

toString() {
return String(this.value);
return String(this.v);
}

toJSON() {
return this.value;
return this.v;
}

valueOf() {
return this.value;
return this.v;
}

__connect(fn: ShouldUpdate<T>, key: T) {
const rootId = getRootId();
const fiber = $$scope().getCursorFiber();
const fiber = $$scope().getCursor();
const { hook } = fiber;
const disconnect = () => this.off(hook, key);

!hook.atoms && (hook.atoms = new Map());
hook.atoms.set(this, disconnect);
hook.atoms.set(this, this.off.bind(this, hook, key));
fiber.markHost(ATOM_HOST_MASK);

if (detectIsEmpty(key)) {
!this.connections1 && (this.connections1 = new Map());
this.connections1.set(hook, [rootId, hook, fn, key]);
!this.c1 && (this.c1 = new Map());
this.c1.set(hook, [rootId, hook, fn, key]);
} else {
!this.connections2 && (this.connections2 = new Map());
this.connections2.set(key, [rootId, hook, fn, key]);
!this.c2 && (this.c2 = new Map());
this.c2.set(key, [rootId, hook, fn, key]);
}

return disconnect;
}

__addSubject(atom$: ReadableAtom) {
!this.subjects && (this.subjects = new Set());
this.subjects.add(atom$);
!this.s && (this.s = new Set());
this.s.add(atom$);
}

__removeSubject(atom$: ReadableAtom) {
return this.subjects && this.subjects.delete(atom$);
return this.s && this.s.delete(atom$);
}

__getSize() {
const size1 = this.connections1 ? this.connections1.size : 0;
const size2 = this.connections2 ? this.connections2.size : 0;
const size3 = this.subjects ? this.subjects.size : 0;
const size4 = this.emitter ? this.emitter.__getSize() : 0;
const size1 = this.c1 ? this.c1.size : 0;
const size2 = this.c2 ? this.c2.size : 0;
const size3 = this.s ? this.s.size : 0;
const size4 = this.e ? this.e.__getSize() : 0;

return size1 + size2 + size3 + size4;
}

protected setValue(value: T | ((prevValue: T) => T)) {
const prev = this.value;
const next = detectIsFunction(value) ? value(this.value) : value;
const prev = this.v;
const next = detectIsFunction(value) ? value(this.v) : value;
const data: EmitterValue<T> = { prev, next };
const make = (tuple: Tuple<T>, prev: T, next: T) => {
const [rootId, hook, shouldUpdate, key] = tuple;
Expand All @@ -128,8 +120,8 @@ class Atom<T = unknown> {
const tools = createTools({
next,
get: () => prev,
set: () => (this.value = next),
reset: () => (this.value = prev),
set: () => (this.v = next),
reset: () => (this.v = prev),
});

update(tools);
Expand All @@ -139,29 +131,27 @@ class Atom<T = unknown> {
}
};

this.value = next;
this.v = next;

if (this.connections1) {
for (const [_, tuple] of this.connections1) {
make(tuple, prev, next);
}
if (this.c1) {
for (const [_, tuple] of this.c1) make(tuple, prev, next);
}

if (this.connections2) {
if (this.connections2.has(next)) {
make(this.connections2.get(next), prev, next);
this.connections2.has(prev) && make(this.connections2.get(prev), prev, next);
if (this.c2) {
if (this.c2.has(next)) {
make(this.c2.get(next), prev, next);
this.c2.has(prev) && make(this.c2.get(prev), prev, next);
}
}

this.emitter && this.emitter.emit('data', data);
this.subjects && this.subjects.forEach(x => x.__notify());
this.e && this.e.emit('data', data);
this.s && this.s.forEach(x => x.__notify());
}

private off(hook: Hook, key: T) {
hook.atoms.delete(this);
this.connections1 && this.connections1.delete(hook);
this.connections2 && this.connections2.delete(key);
this.c1 && this.c1.delete(hook);
this.c2 && this.c2.delete(key);
}
}

Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/batch/batch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { $$scope } from '../scope';
function batch(callback: () => void) {
const $scope = $$scope();

$scope.setIsBatchZone(true);
$scope.setIsBatch(true);
callback();
$scope.setIsBatchZone(false);
$scope.setIsBatch(false);
}

function addBatch(hook: Hook, callback: Callback, change: Callback) {
const $scope = $$scope();

if ($scope.getIsTransitionZone()) {
if ($scope.getIsTransition()) {
callback();
} else {
const batch = hook.getBatch() || { timer: null, changes: [] };
Expand Down
30 changes: 0 additions & 30 deletions packages/core/src/element/element.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/core/src/element/index.ts

This file was deleted.

14 changes: 6 additions & 8 deletions packages/core/src/fiber/fiber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ class Fiber<N = NativeElement> {

class Hook<T = unknown> {
idx = 0;
values: Array<T> = [];
values: Array<T> = null;
owner: Fiber = null;
atoms: Map<Atom, Callback> = null;
mask = 0;
box?: Box = null;
atoms?: Map<Atom, Callback> = null;

__getMask(mask: number) {
return Boolean(this.mask & mask);
Expand Down Expand Up @@ -128,7 +128,7 @@ class Hook<T = unknown> {
return this.box?.providers;
}

setProviders(x: Map<Context, ContextProvider>) {
setProviders(x: Box['providers']) {
this.__box();
this.box.providers = x;
}
Expand All @@ -137,7 +137,7 @@ class Hook<T = unknown> {
return this.box?.batch;
}

setBatch(x: Batch) {
setBatch(x: Box['batch']) {
this.__box();
this.box.batch = x;
}
Expand All @@ -146,7 +146,7 @@ class Hook<T = unknown> {
return detectIsFunction(this.box?.catch);
}

setCatch(x: Catch) {
setCatch(x: Box['catch']) {
this.__box();
this.box.catch = x;
}
Expand Down Expand Up @@ -207,7 +207,7 @@ function getHook(alt: Fiber, prevInst: Instance, nextInst: Instance): Hook | nul
type Box = {
providers?: Map<Context, ContextProvider>;
batch?: Batch;
catch?: Catch;
catch?: (error: Error) => void;
pendings?: number;
};

Expand All @@ -216,8 +216,6 @@ type Batch = {
changes: Array<Callback>;
};

type Catch = (error: Error) => void;

export type NativeElement = unknown;
export type HookValue<T = any> = { deps: Array<any>; value: T };

Expand Down
9 changes: 2 additions & 7 deletions packages/core/src/fragment/fragment.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createBrowserEnv, dom } from '@test-utils';
import { createBrowserEnv } from '@test-utils';

import { component } from '../component';
import { Fragment } from './fragment';
Expand All @@ -11,11 +11,6 @@ beforeEach(() => {

describe('@core/fragment', () => {
test('can render children correctly', () => {
const content = () => dom`
<div>1</div>
<div>2</div>
<div>3</div>
`;
const App = component(() => {
return (
<Fragment>
Expand All @@ -27,6 +22,6 @@ describe('@core/fragment', () => {
});

render(<App />);
expect(host.innerHTML).toBe(content());
expect(host.innerHTML).toMatchInlineSnapshot(`"<div>1</div><div>2</div><div>3</div>"`);
});
});
Loading