tosijs 1.5.2 → 1.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -77
- package/dist/by-path.d.ts +1 -0
- package/dist/component.d.ts +11 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +8 -8
- package/dist/index.js.map +6 -6
- package/dist/main.js +8 -8
- package/dist/main.js.map +6 -6
- package/dist/module.js +8 -8
- package/dist/module.js.map +6 -6
- package/dist/version.d.ts +1 -1
- package/dist/xin-proxy.d.ts +1 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -28,7 +28,8 @@ If you want to build a web-application that's performant, robust, and maintainab
|
|
|
28
28
|
|
|
29
29
|
- build user-interfaces with pure javascript/typescript—no JSX, complex tooling, or spooky action-at-a-distance
|
|
30
30
|
- manage application state almost effortlessly—eliminate most binding code
|
|
31
|
-
-
|
|
31
|
+
- bind application state to the UI and services without locking yourself into a specific framework
|
|
32
|
+
- work in Typescript or Javascript
|
|
32
33
|
- use web-components, build your own web-components quickly and easily
|
|
33
34
|
- manage CSS efficiently and flexibly using CSS variables and Color computations
|
|
34
35
|
- leverage existing business logic and libraries without complex wrappers
|
|
@@ -54,7 +55,7 @@ const { h4, ul, template, li, label, input } = elements
|
|
|
54
55
|
preview.append(
|
|
55
56
|
h4('To Do List'),
|
|
56
57
|
ul(
|
|
57
|
-
...readmeTodoDemo.list.
|
|
58
|
+
...readmeTodoDemo.list.listBinding(
|
|
58
59
|
({ li, button }, item) =>
|
|
59
60
|
li(
|
|
60
61
|
item.reminder,
|
|
@@ -92,7 +93,7 @@ and simplicity as you get with highly-refined React-centric toolchains, but with
|
|
|
92
93
|
domain-specific-languages, or other tricks that provide "convenience" at the cost of becoming locked-in
|
|
93
94
|
to React, a specific state-management system (which permeates your business logic), and usually a specific UI framework.
|
|
94
95
|
|
|
95
|
-
`tosijs` lets you work with pure HTML and web-
|
|
96
|
+
`tosijs` lets you work with pure HTML and web-components as cleanly—more cleanly—and efficiently than
|
|
96
97
|
React toolchains let you work with JSX.
|
|
97
98
|
|
|
98
99
|
export default function App() {
|
|
@@ -114,7 +115,7 @@ Becomes:
|
|
|
114
115
|
)
|
|
115
116
|
|
|
116
117
|
Except this reusable component outputs native DOM nodes. No transpilation, spooky magic at a distance,
|
|
117
|
-
or virtual DOM required. And it all works just as well with web-components. This is you get when
|
|
118
|
+
or virtual DOM required. And it all works just as well with web-components. This is what you get when
|
|
118
119
|
you run App() in the console:
|
|
119
120
|
|
|
120
121
|
▼ <div class="App">
|
|
@@ -140,13 +141,13 @@ more compactly than with `jsx` (and without a virtual DOM).
|
|
|
140
141
|
|
|
141
142
|
import { Component, elements, css } from 'tosijs'
|
|
142
143
|
|
|
143
|
-
const {
|
|
144
|
+
const { h1, slot } = elements
|
|
144
145
|
export class MyComponent extends Component {
|
|
145
|
-
|
|
146
|
+
static shadowStyleSpec = css({
|
|
146
147
|
h1: {
|
|
147
148
|
color: 'blue'
|
|
148
149
|
}
|
|
149
|
-
})
|
|
150
|
+
})
|
|
150
151
|
content = [ h1('hello world'), slot() ]
|
|
151
152
|
}
|
|
152
153
|
|
|
@@ -161,9 +162,9 @@ and are natively supported by all modern browsers.
|
|
|
161
162
|
`tosijs` tracks the state of objects you assign to it using `paths` allowing economical
|
|
162
163
|
and direct updates to application state.
|
|
163
164
|
|
|
164
|
-
import {
|
|
165
|
+
import { tosi, observe } from 'tosijs'
|
|
165
166
|
|
|
166
|
-
const { app } =
|
|
167
|
+
const { app } = tosi({
|
|
167
168
|
app: {
|
|
168
169
|
prefs: {
|
|
169
170
|
darkmode: false
|
|
@@ -179,29 +180,28 @@ and direct updates to application state.
|
|
|
179
180
|
})
|
|
180
181
|
|
|
181
182
|
observe('app.prefs.darkmode', () => {
|
|
182
|
-
document.body.classList.toggle('dark-mode', app.prefs.darkmode)
|
|
183
|
+
document.body.classList.toggle('dark-mode', app.prefs.darkmode.value)
|
|
183
184
|
})
|
|
184
185
|
|
|
185
186
|
observe('app.docs', () => {
|
|
186
187
|
// render docs
|
|
187
188
|
})
|
|
188
189
|
|
|
189
|
-
> #### What does `
|
|
190
|
+
> #### What does `tosi` do, and what is a `BoxedProxy`?
|
|
190
191
|
>
|
|
191
|
-
> `
|
|
192
|
-
> and then getting it back out
|
|
192
|
+
> `tosi` is syntax sugar for assigning something to `xin` (which is a proxy over
|
|
193
|
+
> the central registry) and then getting it back out as a `BoxedProxy`.
|
|
193
194
|
>
|
|
194
|
-
> A `
|
|
195
|
+
> A `BoxedProxy` is an [ES Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
|
|
195
196
|
> wrapped around an `object` (which in Javascript means anything
|
|
196
197
|
> that has a `constructor` which in particular includes `Array`s, `class` instances, `function`s
|
|
197
198
|
> and so on, but not "scalars" like `number`s, `string`s, `boolean`s, `null`, and `undefined`)
|
|
198
199
|
>
|
|
199
|
-
> All you need to know about a `
|
|
200
|
+
> All you need to know about a `BoxedProxy` is that it's a Proxy wrapped around your original
|
|
200
201
|
> object that allows you to interact with the object normally, but which allows `tosijs` to
|
|
201
202
|
> **observe** changes made to the wrapped object and tell interested parties about the changes.
|
|
202
203
|
>
|
|
203
|
-
> If you want
|
|
204
|
-
> to unwrap it.
|
|
204
|
+
> If you want the original object back you can use `.value` on any proxy to unwrap it.
|
|
205
205
|
|
|
206
206
|
### No Tax, No Packaging
|
|
207
207
|
|
|
@@ -209,17 +209,17 @@ and direct updates to application state.
|
|
|
209
209
|
with a `Proxy` and then if you use `xin` to make changes to those objects,
|
|
210
210
|
`tosijs` will notify any interested observers.
|
|
211
211
|
|
|
212
|
-
**Note** `
|
|
212
|
+
**Note** `tosi({foo: {...}})` is syntax sugar for `xin.foo = {...}`.
|
|
213
213
|
|
|
214
|
-
import {
|
|
215
|
-
const { foo } =
|
|
214
|
+
import { tosi, observe } from 'tosijs'
|
|
215
|
+
const { foo } = tosi({
|
|
216
216
|
foo: {
|
|
217
217
|
bar: 17
|
|
218
218
|
}
|
|
219
219
|
})
|
|
220
220
|
|
|
221
|
-
observe('foo.bar',
|
|
222
|
-
console.log('foo.bar was changed to',
|
|
221
|
+
observe('foo.bar', (path) => {
|
|
222
|
+
console.log('foo.bar was changed to', foo.bar.value)
|
|
223
223
|
})
|
|
224
224
|
|
|
225
225
|
foo.bar = 17 // does not trigger the observer
|
|
@@ -230,13 +230,13 @@ with a `Proxy` and then if you use `xin` to make changes to those objects,
|
|
|
230
230
|
`xin` is designed to behave just like a JavaScript `Object`. What you put
|
|
231
231
|
into it is what you get out of it:
|
|
232
232
|
|
|
233
|
-
import { xin
|
|
233
|
+
import { xin } from 'tosijs'
|
|
234
234
|
|
|
235
235
|
const foo = {bar: 'baz'}
|
|
236
236
|
xin.foo = foo
|
|
237
237
|
|
|
238
|
-
// xin.foo returns
|
|
239
|
-
|
|
238
|
+
// xin.foo returns the value directly
|
|
239
|
+
xin.foo.bar === 'baz'
|
|
240
240
|
|
|
241
241
|
// really, it's just the original object
|
|
242
242
|
xin.foo.bar = 'lurman'
|
|
@@ -251,9 +251,9 @@ into it is what you get out of it:
|
|
|
251
251
|
It's very common to deal with arrays of objects that have unique id values,
|
|
252
252
|
so `tosijs` supports the idea of id-paths
|
|
253
253
|
|
|
254
|
-
import {
|
|
254
|
+
import { tosi, xin } from 'tosijs'
|
|
255
255
|
|
|
256
|
-
const { app } =
|
|
256
|
+
const { app } = tosi({
|
|
257
257
|
app: {
|
|
258
258
|
list: [
|
|
259
259
|
{
|
|
@@ -270,7 +270,7 @@ so `tosijs` supports the idea of id-paths
|
|
|
270
270
|
|
|
271
271
|
console.log(app.list[0].text) // hello world
|
|
272
272
|
console.log(app.list['id=5678efgh']) // so long, redux
|
|
273
|
-
console.log(xin['app.list[id=1234abcd'])
|
|
273
|
+
console.log(xin['app.list[id=1234abcd]']) // hello world
|
|
274
274
|
|
|
275
275
|
### Telling `xin` about changes using `touch()`
|
|
276
276
|
|
|
@@ -281,7 +281,7 @@ When you want to trigger updates, simply touch the path.
|
|
|
281
281
|
|
|
282
282
|
const foo = { bar: 17 }
|
|
283
283
|
xin.foo = foo
|
|
284
|
-
observe('foo.bar', path => console.log(path, '->', xin[path])
|
|
284
|
+
observe('foo.bar', (path) => console.log(path, '->', xin[path]))
|
|
285
285
|
xin.foo.bar = -2 // console will show: foo.bar -> -2
|
|
286
286
|
|
|
287
287
|
foo.bar = 100 // nothing happens
|
|
@@ -320,37 +320,35 @@ elements are reused (no teardown/recreation).
|
|
|
320
320
|
|
|
321
321
|
`tosijs` includes utilities for working with css.
|
|
322
322
|
|
|
323
|
-
import {css, vars
|
|
324
|
-
const cssVars = {
|
|
325
|
-
textFont: 'sans-serif'
|
|
326
|
-
color: '#111'
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
`initVars()` processes an object changing its keys from camelCase to --kabob-case:
|
|
330
|
-
|
|
331
|
-
initVars(cssVars) // emits { --text-font: "sans-serif", --color: "#111" }
|
|
332
|
-
|
|
333
|
-
`darkMode()` processes an object, taking only the color properties and inverting their luminance values:
|
|
334
|
-
darkMode(cssVars) // emits { color: '#ededed' }
|
|
323
|
+
import { css, vars } from 'tosijs'
|
|
335
324
|
|
|
336
|
-
The `vars`
|
|
325
|
+
The `vars` proxy converts camelCase properties into css variable references:
|
|
337
326
|
|
|
338
327
|
vars.fooBar // emits 'var(--foo-bar)'
|
|
339
|
-
calc(
|
|
328
|
+
`calc(${vars.width} + 2 * ${vars.spacing})` // emits 'calc(var(--width) + 2 * var(--spacing))'
|
|
340
329
|
|
|
341
|
-
`css()` processes an object, rendering it as CSS
|
|
330
|
+
`css()` processes an object, rendering it as CSS:
|
|
342
331
|
|
|
343
332
|
css({
|
|
344
333
|
'.container': {
|
|
345
|
-
|
|
334
|
+
position: 'relative'
|
|
346
335
|
}
|
|
347
336
|
}) // emits .container { position: relative; }
|
|
348
337
|
|
|
338
|
+
CSS variables can be declared using `_` and `__` prefixes in `css()` objects:
|
|
339
|
+
|
|
340
|
+
css({
|
|
341
|
+
':root': {
|
|
342
|
+
_textFont: 'sans-serif', // emits --text-font: sans-serif
|
|
343
|
+
_color: '#111', // emits --color: #111
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
|
|
349
347
|
## Color
|
|
350
348
|
|
|
351
349
|
`tosijs` includes a powerful `Color` class for manipulating colors.
|
|
352
350
|
|
|
353
|
-
import {Color} from 'tosijs
|
|
351
|
+
import { Color } from 'tosijs'
|
|
354
352
|
const translucentBlue = new Color(0, 0, 255, 0.5) // r, g, b, a parameters
|
|
355
353
|
const postItBackground = Color.fromCss('#e7e79d')
|
|
356
354
|
const darkGrey = Color.fromHsl(0, 0, 0.2)
|
|
@@ -358,13 +356,15 @@ The `vars` simply converts its camelCase properties into css variable references
|
|
|
358
356
|
The color objects have computed properties for rendering the color in different ways,
|
|
359
357
|
making adjustments, blending colors, and so forth.
|
|
360
358
|
|
|
359
|
+
Use `invertLuminance()` to generate dark-mode equivalents of color values.
|
|
360
|
+
|
|
361
361
|
## Hot Reload
|
|
362
362
|
|
|
363
363
|
One of the nice things about working with the React toolchain is hot reloading.
|
|
364
364
|
`tosijs` supports hot reloading (and not just in development!) via the `hotReload()`
|
|
365
365
|
function:
|
|
366
366
|
|
|
367
|
-
import {xin, hotReload} from 'tosijs'
|
|
367
|
+
import { xin, hotReload } from 'tosijs'
|
|
368
368
|
|
|
369
369
|
xin.app = {
|
|
370
370
|
...
|
|
@@ -381,42 +381,21 @@ Only top-level properties in `xin` that pass the test will be persisted.
|
|
|
381
381
|
|
|
382
382
|
To completely reset the app, run `localStorage.clear()` in the console.
|
|
383
383
|
|
|
384
|
-
### Types
|
|
385
|
-
|
|
386
|
-
`tosijs` [type-by-example](https://www.npmjs.com/package/type-by-example) has been
|
|
387
|
-
broken out into a separate standalone library. (Naturally it works very well with
|
|
388
|
-
tosijs but they are completely independent.)
|
|
389
|
-
|
|
390
384
|
## Development Notes
|
|
391
385
|
|
|
392
|
-
You'll need to install [bun](https://bun.sh/) and
|
|
393
|
-
and then run `npm install` and `bun install`. `bun` is used because it's
|
|
394
|
-
**fast** and is a really nice test-runner.
|
|
395
|
-
|
|
396
|
-
To work interactively on the demo code, use `bun start`. This runs the demo
|
|
397
|
-
site on localhost.
|
|
398
|
-
|
|
399
|
-
To build everything run `bun run make` which builds production versions of the
|
|
400
|
-
demo site (in `www`) and the `dist` and `cdn` directories.
|
|
401
|
-
|
|
402
|
-
To create a local package (for experimenting with a build) run `bun pack`.
|
|
403
|
-
|
|
404
|
-
### Parcel Occasionally Gets Screwed Up
|
|
386
|
+
You'll need to install [bun](https://bun.sh/) and then run `bun install`.
|
|
405
387
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
388
|
+
bun start # dev server with hot reload (https://localhost:8018)
|
|
389
|
+
bun test # run all tests
|
|
390
|
+
bun run dev.ts --build # production build (runs tests, then bundles)
|
|
391
|
+
bun run format # lint and format (ESLint + Prettier)
|
|
392
|
+
bun pack # create local package tarball
|
|
410
393
|
|
|
411
394
|
## Related Libraries
|
|
412
395
|
|
|
413
|
-
-
|
|
414
|
-
|
|
415
|
-
-
|
|
416
|
-
is a library for declaring types in pure javascript, allowing run-time type-checking.
|
|
417
|
-
- filter-shapes [github](https://github.com/tonioloewald/filter-shapes) | [npm](https://www.npmjs.com/package/filter-shapes)
|
|
418
|
-
is a library for filtering objects (and arrays of objects) to specific shapes (e.g. to reduce storage / bandwidth costs).
|
|
419
|
-
It is built on top of type-by-example.
|
|
396
|
+
- [tosijs-ui](https://ui.tosijs.net) — a web-component library built on tosijs `Component`
|
|
397
|
+
- [tosijs-3d](https://3d.tosijs.net) — 3D graphics library built on tosijs
|
|
398
|
+
- [react-tosijs](https://github.com/tonioloewald/react-tosijs#readme) — use tosijs's path-observer model in [React](https://reactjs.org) apps
|
|
420
399
|
|
|
421
400
|
## Credits
|
|
422
401
|
|
package/dist/by-path.d.ts
CHANGED
package/dist/component.d.ts
CHANGED
|
@@ -100,7 +100,7 @@ export declare abstract class Component<T = PartsMap> extends HTMLElement {
|
|
|
100
100
|
interface SlotParts extends PartsMap {
|
|
101
101
|
slotty: HTMLSlotElement;
|
|
102
102
|
}
|
|
103
|
-
declare class
|
|
103
|
+
declare class TosiSlot extends Component<SlotParts> {
|
|
104
104
|
static preferredTagName: string;
|
|
105
105
|
static initAttributes: {
|
|
106
106
|
name: string;
|
|
@@ -108,5 +108,15 @@ declare class XinSlot extends Component<SlotParts> {
|
|
|
108
108
|
content: null;
|
|
109
109
|
static replaceSlot(slot: HTMLSlotElement): void;
|
|
110
110
|
}
|
|
111
|
+
export declare const tosiSlot: ElementCreator<TosiSlot>;
|
|
112
|
+
declare class XinSlot extends Component<SlotParts> {
|
|
113
|
+
static preferredTagName: string;
|
|
114
|
+
static initAttributes: {
|
|
115
|
+
name: string;
|
|
116
|
+
};
|
|
117
|
+
content: null;
|
|
118
|
+
constructor();
|
|
119
|
+
static replaceSlot: typeof TosiSlot.replaceSlot;
|
|
120
|
+
}
|
|
111
121
|
export declare const xinSlot: ElementCreator<XinSlot>;
|
|
112
122
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { css, invertLuminance, initVars, vars, varDefault, StyleSheet, onStylesh
|
|
|
4
4
|
export type { ColorScheme, ContrastPreference, ThemePreferences } from './css';
|
|
5
5
|
export type { XinStyleSheet, XinStyleMap, XinStyleRule } from './css-types';
|
|
6
6
|
export { Color } from './color';
|
|
7
|
-
export { Component } from './component';
|
|
7
|
+
export { Component, tosiSlot, xinSlot } from './component';
|
|
8
8
|
export { validateAgainstConstraints, type FormValidation, } from './form-validation';
|
|
9
9
|
export { elements, svgElements, mathML, bindParts } from './elements';
|
|
10
10
|
export type { ElementsProxy } from './elements-types';
|
|
@@ -24,4 +24,4 @@ export { version } from './version';
|
|
|
24
24
|
export { xin, boxed, observe, unobserve, touch, updates } from './xin';
|
|
25
25
|
export { tosiBlueprint, tosiLoader, blueprint, Blueprint, blueprintLoader, BlueprintLoader, } from './blueprint-loader';
|
|
26
26
|
export * from './xin-types';
|
|
27
|
-
export { tosi, xinProxy, boxedProxy } from './xin-proxy';
|
|
27
|
+
export { tosi, tosiUnique, xinProxy, boxedProxy } from './xin-proxy';
|