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 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
- - written in Typescript, Javascript-friendly
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.tosiListBinding(
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-component as cleanly—more cleanly—and efficiently than
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 { style, h1, slot } = elements
144
+ const { h1, slot } = elements
144
145
  export class MyComponent extends Component {
145
- styleNode = style(css({
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 { xinProxy, observe } from 'tosijs'
165
+ import { tosi, observe } from 'tosijs'
165
166
 
166
- const { app } = xinProxy({
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 `xinProxy` do, and what is a `XinProxy`?
190
+ > #### What does `tosi` do, and what is a `BoxedProxy`?
190
191
  >
191
- > `xinProxy` is syntax sugar for assigning something to `xin` (which is a `XinProxyObject`)
192
- > and then getting it back out again.
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 `XinProxy` is an [ES Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
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 `XinProxy` is that it's Proxy wrapped around your original
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 to original object back you can just hold on to a reference or use `xinValue(someProxy)`
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** `xinProxy({foo: {...}})` is syntax sugar for `xin.foo = {...}`.
212
+ **Note** `tosi({foo: {...}})` is syntax sugar for `xin.foo = {...}`.
213
213
 
214
- import { xinProxy, observe } from 'tosijs'
215
- const { foo } = xinProxy({
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', v => {
222
- console.log('foo.bar was changed to', xin.foo.bar)
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, xinValue } from 'tosijs'
233
+ import { xin } from 'tosijs'
234
234
 
235
235
  const foo = {bar: 'baz'}
236
236
  xin.foo = foo
237
237
 
238
- // xin.foo returns a Proxy wrapped around foo (without touching foo)
239
- xinValue(xin.foo) === foo
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 { xinProxy, xin } from 'tosijs
254
+ import { tosi, xin } from 'tosijs'
255
255
 
256
- const { app } = xinProxy ({
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']) // hello world
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, initVars, darkMode} from 'tosijs'
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` simply converts its camelCase properties into css variable references
325
+ The `vars` proxy converts camelCase properties into css variable references:
337
326
 
338
327
  vars.fooBar // emits 'var(--foo-bar)'
339
- calc(`${vars.width} + 2 * ${vars.spacing}`) // emits 'calc(var(--width) + 2 * var(--spacing))'
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
- 'position', 'relative'
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 [nodejs](https://nodejs.org)),
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
- - remove all the parcel transformer dependencies @parcel/\*
407
- - rm -rf node_modules
408
- - run the update script
409
- - npx parcel build (which restores needed parcel transformers)
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
- - react-tosijs [react-tosijs](https://github.com/tonioloewald/react-tosijs#readme)
414
- allows you to use xin's path-observer model in React [ReactJS](https://reactjs.org) apps
415
- - type-by-example [github](https://github.com/tonioloewald/type-by-example) | [npm](https://www.npmjs.com/package/type-by-example)
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
@@ -1,4 +1,5 @@
1
1
  import { XinObject, XinArray } from './xin-types';
2
+ export declare const id: () => string;
2
3
  type Part = string | string[];
3
4
  type PartArray = Part[];
4
5
  declare function pathParts(path: string | PartArray): PartArray;
@@ -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 XinSlot extends Component<SlotParts> {
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';