Skip to content

Commit

Permalink
Merge branch 'develop' into feature/hiccup-svg-deref-attribs
Browse files Browse the repository at this point in the history
* develop: (38 commits)
  Publish
  feat(csp): update Mult/PubSub unsub handling, add docs
  minor(csp): rename MAX_QUEUE => MAX_WRITES
  docs(csp): add various doc strings
  fix(csp): update select()
  docs(csp): add docs for all Channel ops
  docs(csp): update readme example
  docs(csp): update/extend readme (update example)
  docs(csp): update/extend readme
  Publish
  docs: update main readme
  docs: regen readmes
  docs(csp): update readme (example, doc links)
  refactor(examples): update csp-bus
  feat(csp): add into() to feed (async) iterables into a channel
  feat(meta-css): add color-scheme, light-dark() and appearance rules/tpls
  fix(rdom): update $compile() async-iterable attrib handling
  feat(csp): add opt. generics for PubSub.subscribe()/unsubscribe()
  feat(examples): add csp-bus example
  docs(examples): update table
  ...
  • Loading branch information
postspectacular committed Apr 28, 2024
2 parents 0ad9289 + 85861eb commit 46ddf39
Show file tree
Hide file tree
Showing 190 changed files with 2,819 additions and 2,663 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ jobs:
node-version: ">=20.0.0"
cache: "yarn"
- uses: goto-bus-stop/setup-zig@v2
with:
version: 0.12.0
- uses: oven-sh/setup-bun@v1
with:
bun-version: latest
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,11 +255,16 @@ feature or `develop` branches)

### Latest updates

As of: 2024-04-23
As of: 2024-04-26

| Status | Package | Version | Changelog |
|:-------------------------------------------------|:----------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------|
| ![](https://img.shields.io/badge/-feat-green) | [`@thi.ng/csp`](./packages/csp) | [![version](https://img.shields.io/npm/v/@thi.ng/csp.svg)](https://www.npmjs.com/package/@thi.ng/csp) | [changelog](./packages/csp/CHANGELOG.md) |
| ![](https://img.shields.io/badge/-feat-green) | [`@thi.ng/file-io`](./packages/file-io) | [![version](https://img.shields.io/npm/v/@thi.ng/file-io.svg)](https://www.npmjs.com/package/@thi.ng/file-io) | [changelog](./packages/file-io/CHANGELOG.md) |
| ![](https://img.shields.io/badge/-feat-green) | [`@thi.ng/hiccup`](./packages/hiccup) | [![version](https://img.shields.io/npm/v/@thi.ng/hiccup.svg)](https://www.npmjs.com/package/@thi.ng/hiccup) | [changelog](./packages/hiccup/CHANGELOG.md) |
| ![](https://img.shields.io/badge/-feat-green) | [`@thi.ng/meta-css`](./packages/meta-css) | [![version](https://img.shields.io/npm/v/@thi.ng/meta-css.svg)](https://www.npmjs.com/package/@thi.ng/meta-css) | [changelog](./packages/meta-css/CHANGELOG.md) |
| ![](https://img.shields.io/badge/-fix-orange) | [`@thi.ng/rdom`](./packages/rdom) | [![version](https://img.shields.io/npm/v/@thi.ng/rdom.svg)](https://www.npmjs.com/package/@thi.ng/rdom) | [changelog](./packages/rdom/CHANGELOG.md) |
| ![](https://img.shields.io/badge/-refactor-cyan) | [`@thi.ng/rstream-csp`](./packages/rstream-csp) | [![version](https://img.shields.io/npm/v/@thi.ng/rstream-csp.svg)](https://www.npmjs.com/package/@thi.ng/rstream-csp) | [changelog](./packages/rstream-csp/CHANGELOG.md) |
| ![](https://img.shields.io/badge/-feat-green) | [`@thi.ng/wasm-api`](./packages/wasm-api) | [![version](https://img.shields.io/npm/v/@thi.ng/wasm-api.svg)](https://www.npmjs.com/package/@thi.ng/wasm-api) | [changelog](./packages/wasm-api/CHANGELOG.md) |
| ![](https://img.shields.io/badge/-feat-green) | [`@thi.ng/wasm-api-bindgen`](./packages/wasm-api-bindgen) | [![version](https://img.shields.io/npm/v/@thi.ng/wasm-api-bindgen.svg)](https://www.npmjs.com/package/@thi.ng/wasm-api-bindgen) | [changelog](./packages/wasm-api-bindgen/CHANGELOG.md) |
| ![](https://img.shields.io/badge/-refactor-cyan) | [`@thi.ng/wasm-api-dom`](./packages/wasm-api-dom) | [![version](https://img.shields.io/npm/v/@thi.ng/wasm-api-dom.svg)](https://www.npmjs.com/package/@thi.ng/wasm-api-dom) | [changelog](./packages/wasm-api-dom/CHANGELOG.md) |
Expand Down
Binary file added assets/examples/csp-bus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
288 changes: 145 additions & 143 deletions examples/README.md

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions examples/csp-bus/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# csp-bus

![screenshot](https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/csp-bus.png)

[Live demo](http://demo.thi.ng/umbrella/csp-bus/)

## Developing & building

Please refer to the instructions on the wiki:

- [Development](https://github.com/thi-ng/umbrella/wiki/Development-mode-for-examples-using-thi.ng-meta%E2%80%90css)
- [Production build](https://github.com/thi-ng/umbrella/wiki/Example-build-instructions)

## Authors

- Karsten Schmidt

## License

© 2024 Karsten Schmidt // Apache Software License 2.0
7 changes: 7 additions & 0 deletions examples/csp-bus/css/custom.mcss.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tables": {},
"vars": {},
"decls": [],
"specs": [],
"templates": []
}
2 changes: 2 additions & 0 deletions examples/csp-bus/css/includes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// list of CSS class names to force-include in generated CSS
// (one class per line, basic wildcards supported)
22 changes: 22 additions & 0 deletions examples/csp-bus/css/style.mcss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// thi.ng/meta-css stylesheet
// see package readme for more details/usage
// use `yarn css:build` or `yarn css:watch` to transpile to CSS
// also see component-specific *.mcss files in /src folder

:root {
color-scheme-light-dark
bg=#fff
text=#000
log=#777
dark:bg=#000
dark:text=#fff
dark:log=#999
}

body { system-sans-serif ma3 bg-color(bg) color(text) }

textarea[disabled] { w-100 pa2 bw0 bg-color(bg) color(log) }

button.stop { db w-100 bg-color-orange color-white h2 bw0 mb3 cursor-pointer }

a.link { color(text) }
21 changes: 21 additions & 0 deletions examples/csp-bus/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link
rel="icon"
href='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><text y=".9em" font-size="90">⛱️</text></svg>'
/>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>csp-bus · @thi.ng/umbrella</title>
<link href="/css/style.css" rel="stylesheet">
<script>window.goatcounter = { path: (p) => location.host + p };</script>
<script data-goatcounter="https://thing.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
</head>
<body>
<div id="app"></div>
<div><a class="link" href="https://github.com/thi-ng/umbrella/tree/develop/examples/csp-bus">Source code</a></div>
<script type="module" src="/src/index.ts"></script>
</body>
</html>
46 changes: 46 additions & 0 deletions examples/csp-bus/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "@example/csp-bus",
"version": "0.0.1",
"private": true,
"description": "CSP channel-based event handling, async transducers & reactive UI components",
"repository": "https://github.com/thi-ng/umbrella",
"author": "Karsten Schmidt <k+npm@thi.ng>",
"license": "Apache-2.0",
"scripts": {
"start": "yarn css:build && yarn start:only",
"start:only": "vite --host --open",
"css:watch": "../../node_modules/.bin/metacss develop --bundle --watch --pretty --out-specs css/framework.json --out-css css/style.css --force @css/includes.txt ../../packages/meta-css/specs/*.mcss.json css/*.mcss.json css/*.mcss src/*.mcss",
"css:build": "../../node_modules/.bin/metacss develop --bundle --out-specs css/framework.json --out-css css/style.css --force @css/includes.txt ../../packages/meta-css/specs/*.mcss.json css/*.mcss.json css/*.mcss src/*.mcss",
"build": "yarn css:build && tsc && vite build --base='./'",
"preview": "vite preview --host --open"
},
"devDependencies": {
"@thi.ng/meta-css": "workspace:^",
"typescript": "^5.4.3",
"vite": "^5.2.6"
},
"dependencies": {
"@thi.ng/api": "workspace:^",
"@thi.ng/csp": "workspace:^",
"@thi.ng/date": "workspace:^",
"@thi.ng/hiccup-html": "workspace:^",
"@thi.ng/rdom": "workspace:^",
"@thi.ng/system": "workspace:^",
"@thi.ng/transducers": "workspace:^",
"@thi.ng/transducers-async": "workspace:^"
},
"browser": {
"process": false
},
"thi.ng": {
"readme": [
"csp",
"date",
"hiccup-html",
"rdom",
"system",
"transducers-async"
],
"screenshot": "examples/csp-bus.png"
}
}
19 changes: 19 additions & 0 deletions examples/csp-bus/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Channel, PubSub } from "@thi.ng/csp";
import type { ILifecycle } from "@thi.ng/system";
import type { Counter, CounterGroup } from "./counter.js";

export type StartCounterEvent = ["start-counter", Counter];
export type StopAllEvent = ["stop"];
export type LogEvent = ["log", string];

export type Event = StartCounterEvent | StopAllEvent | LogEvent;

export type EventBus = PubSub<Event>;

// our app consists of multiple app components
export interface App {
bus: EventBus;
counters: CounterGroup;
logger: Channel<string>;
ui: ILifecycle;
}
41 changes: 41 additions & 0 deletions examples/csp-bus/src/counter.mcss
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// put component specific thi.ng/meta-css style defs here...
// these will be included in the generated CSS via the `css:build`
// and `css:watch` script aliases in `package.json`

.counter {
bg=#ccc
text=#333
bt-bg=#000
bt-text=#fff
bt-bg-disabled=#aaa
bt-text-disabled=#ccc
prog-bg=#99a
prog-val=#d5008f

dark:bg=#333
dark:text=#ccc
dark:bt-bg=#fff
dark:bt-text=#000
dark:bt-bg-disabled=#555
dark:bt-text-disabled=#333
dark:prog-bg=#556
dark:prog-val=#ff41b4

pa2 mb2 grid grid-cols(4rem 1fr 4rem)
bg-color(bg) color(text)
{
button {
bg-color(bt-bg) color(bt-text) bw0 h2 pa2 mr3 cursor-pointer
{ &[disabled] { bg-color(bt-bg-disabled) color(bt-text-disabled) cursor-auto } }
}
progress {
w-100 h2 ma0 pa0 mr3 bw0 appearance(none) bg-color(prog-bg)
{
[value]::-webkit-progress-value { bg-color(prog-val) }
[value]::-webkit-progress-bar { bg-color(prog-bg) }
[value]::-moz-progress-bar { bg-color(prog-val) }
}
}
>span { mt2 tr }
}
}
65 changes: 65 additions & 0 deletions examples/csp-bus/src/counter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { Maybe } from "@thi.ng/api";
import { Channel, Mult, channel, mult } from "@thi.ng/csp";
import { button, div, progress } from "@thi.ng/hiccup-html";
import { Component, type NumOrElement } from "@thi.ng/rdom";
import { map } from "@thi.ng/transducers-async";
import type { EventBus } from "./api.js";

// counter component with local state in the form of CSP channels
export class Counter extends Component {
value: Mult<number>;
disabled: Channel<boolean>;

constructor(public bus: EventBus, public delay: number, public id: number) {
super();
this.value = mult<any>();
this.disabled = channel<boolean>();
this.value.write(0);
this.disabled.write(false);
}

// thi.ng/rdom component lifecycle hook
// called when this component is mounted in the browser DOM
async mount(parent: ParentNode, index?: Maybe<NumOrElement>) {
return (this.el = await this.$compile(
div(
".counter",
{},
button(
{
disabled: this.disabled,
onclick: () => this.bus.write(["start-counter", this]),
},
"start"
),
progress({
max: 100,
value: this.value.subscribe(),
}),
map((x) => `${x}%`, this.value.subscribe())
)
).mount(parent, index));
}
}

// simple wrapper component for multiple counters (configurable number)
export class CounterGroup extends Component {
constructor(public config: number[], public bus: EventBus) {
super();
}

async mount(parent: ParentNode, index?: Maybe<NumOrElement>) {
return (this.el = await this.$compile(
div(
{},
...this.config.map(
(delay, i) => new Counter(this.bus, delay, i + 1)
)
)
).mount(parent, index));
}
}

// syntax sugar for CounterGroup ctor
export const initCounters = async (config: number[], bus: EventBus) =>
new CounterGroup(config, bus);
76 changes: 76 additions & 0 deletions examples/csp-bus/src/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { consumeWith, into, pubsub } from "@thi.ng/csp";
import { FMT_HHmmss, FMT_yyyyMMdd } from "@thi.ng/date";
import { concat, delayed, range } from "@thi.ng/transducers-async";
import type {
App,
Event,
EventBus,
LogEvent,
StartCounterEvent,
StopAllEvent,
} from "./api";

export const initEvents = async ({ logger }: App) => {
// the event bus is a simple pubsub CSP channel construct
// events are triggered by writing a new value in this channel

// event handlers (below) are subscribing to specific topics (via filtered
// topic based CSP channels) and each handler is running in its own channel
// consumer... the topic function used here simply extracts the event name
// from incoming event tuples (see event definition in /api.ts)
const bus: EventBus = pubsub<Event>((x) => x[0]);

// async event handler & channel consumer to handle counter events in the
// form: `["start-counter", counterInstance]`
consumeWith(
// create a topic subscription channel for this specific event type
bus.subscribeTopic<StartCounterEvent>("start-counter"),
// this function is called for side effects of each counter event received,
// we make it async here to simplify animating the counter
async ([_, { value, disabled, id, delay }]) => {
// we *could* use the logger directly here, but instead utilize the
// bus for demo purposes and trigger a logging event (its handler is
// further below)
bus.write(["log", `starting counter #${id}`]);
// temporarily disable the counter button
disabled.write(true);
// animate by feeding an async iterable into the counter's value channel
await into(
value,
// concatenate multiple async iterables to animate value
concat(
// count [0..100]
range(101, delay),
// short wait
(async function* () {
yield await delayed(100, 500);
})(),
// (faster) countdown to 0
range(100, -1, -10, 10)
)
);
// re-enable counter button
disabled.write(false);
// another logging event
bus.write(["log", `counter #${id} done`]);
}
);

// stop the entire event bus if the `stop` event has been triggered. once
// the bus channel is closed, all further events will be ignored and all
// topic subscriptions should have been closed too (automatically)
consumeWith(bus.subscribeTopic<StopAllEvent>("stop"), async () => {
await bus.write(["log", "stopping event bus..."]);
bus.close();
});

// to avoid direct dependencies on the logger in other parts of the app
// enable logging via sending events to the bus
consumeWith(bus.subscribeTopic<LogEvent>("log"), ([_, msg]) =>
logger.write(`${FMT_yyyyMMdd()} ${FMT_HHmmss()}: ${msg}`)
);

bus.write(["log", "eventbus ready..."]);

return bus;
};
18 changes: 18 additions & 0 deletions examples/csp-bus/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { defSystem } from "@thi.ng/system";
import type { App } from "./api.js";
import { initCounters } from "./counter.js";
import { initEvents } from "./events.js";
import { initLogger } from "./logger.js";
import { initUI } from "./ui.js";

// initialize the app components in dependency order
// see thi.ng/system readme for details
defSystem<App>({
logger: { factory: initLogger },
bus: { factory: initEvents, deps: ["logger"] },
ui: { factory: initUI, deps: ["bus", "counters", "logger"] },
counters: {
factory: async ({ bus }) => initCounters([50, 10, 25], bus),
deps: ["bus"],
},
}).start();
4 changes: 4 additions & 0 deletions examples/csp-bus/src/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { channel } from "@thi.ng/csp";

// app logger component is a simple CSP channel
export const initLogger = async () => channel<string>();
Loading

0 comments on commit 46ddf39

Please sign in to comment.