tosijs 1.0.3

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/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2022, Tonio Loewald
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,385 @@
1
+ # tosijs
2
+
3
+ <!--{ "pin": "top" }-->
4
+
5
+ > `tosijs` is being renamed `tosijs`. This is a work-in-progress.
6
+
7
+ [tosijs.net](https://tosijs.net) | [tosijs-ui](https://ui.tosijs.net) | [github](https://github.com/tonioloewald/tosijs) | [npm](https://www.npmjs.com/package/tosijs) | [cdn](https://www.jsdelivr.com/package/npm/tosijs) | [react-tosijs](https://github.com/tonioloewald/react-tosijs#readme) | [discord](https://discord.gg/ramJ9rgky5)
8
+
9
+ [![tosijs is on NPM](https://badge.fury.io/js/tosijs.svg)](https://www.npmjs.com/package/tosijs)
10
+ [![tosijs is about 10kB gzipped](https://deno.bundlejs.com/?q=tosijs&badge=)](https://bundlejs.com/?q=tosijs&badge=)
11
+ [![tosijs on jsdelivr](https://data.jsdelivr.com/v1/package/npm/tosijs/badge)](https://www.jsdelivr.com/package/npm/tosijs)
12
+
13
+ <div style="text-align: center; margin: 20px">
14
+ <img style="width: 250px; max-width: 80%" class="logo" alt="tosijs logo" src="https://tosijs.net/favicon.svg">
15
+ </div>
16
+
17
+ > For a pretty thorough overview of tosijs, you might like to start with [What is tosijs?](https://loewald.com/blog/2025/6/4/what-is-tosijs-).
18
+ > To understand the thinking behind tosijs, there's [What should a front-end framework do?](https://loewald.com/blog/2025/6/4/what-should-a-front-end-framework-do).
19
+
20
+ ### Build UIs with less code
21
+
22
+ If you want to build a web-application that's performant, robust, and maintainable,
23
+ `tosijs` lets you:
24
+
25
+ - build user-interfaces with pure javascript/typescript—no JSX, complex tooling, or spooky action-at-a-distance
26
+ - manage application state almost effortlessly—eliminate most binding code
27
+ - written in Typescript, Javascript-friendly
28
+ - use web-components, build your own web-components quickly and easily
29
+ - manage CSS efficiently and flexibly using CSS variables and Color computations
30
+ - leverage existing business logic and libraries without complex wrappers
31
+
32
+ ```js
33
+ const { elements, tosi, touch } = tosijs
34
+
35
+ const todo = {
36
+ list: [],
37
+ addItem(reminder) {
38
+ if (reminder.trim()) {
39
+ todo.list.push(reminder)
40
+ }
41
+ }
42
+ }
43
+
44
+ const { readmeTodoDemo } = tosi({ readmeTodoDemo: todo })
45
+
46
+ const { h4, ul, template, li, label, input } = elements
47
+ preview.append(
48
+ h4('To Do List'),
49
+ ul(
50
+ {
51
+ bindList: {
52
+ value: readmeTodoDemo.list
53
+ }
54
+ },
55
+ template(li({ bindText: '^' }))
56
+ ),
57
+ label(
58
+ 'Reminder',
59
+ input({
60
+ placeholder: 'enter a reminder',
61
+ onKeydown(event) {
62
+ if (event.key === 'Enter') {
63
+ event.preventDefault()
64
+ readmeTodoDemo.addItem(event.target.value.trim())
65
+ event.target.value = ''
66
+ touch(readmeTodoDemo)
67
+ }
68
+ }
69
+ })
70
+ )
71
+ )
72
+ ```
73
+
74
+ In general, `tosijs` is able to accomplish the same or better compactness, expressiveness,
75
+ and simplicity as you get with highly-refined React-centric toolchains, but without transpilation,
76
+ domain-specific-languages, or other tricks that provide "convenience" at the cost of becoming locked-in
77
+ to React, a specific state-management system (which permeates your business logic), and usually a specific UI framework.
78
+
79
+ `tosijs` lets you work with pure HTML and web-component as cleanly—more cleanly—and efficiently than
80
+ React toolchains let you work with JSX.
81
+
82
+ export default function App() {
83
+ return (
84
+ <div className="App">
85
+ <h1>Hello React</h1>
86
+ <h2>Start editing to see some magic happen!</h2>
87
+ </div>
88
+ );
89
+ }
90
+
91
+ Becomes:
92
+
93
+ const { div, h1, h2 } = elements // exported from tosijs
94
+ export const App = () => div(
95
+ { class: 'App' },
96
+ h1('Hello tosijs'),
97
+ h2('Start editing to see some magic happen!')
98
+ )
99
+
100
+ Except this reusable component outputs native DOM nodes. No transpilation, spooky magic at a distance,
101
+ or virtual DOM required. And it all works just as well with web-components. This is you get when
102
+ you run App() in the console:
103
+
104
+ ▼ <div class="App">
105
+ <h1>Hello tosijs</h1>
106
+ <h2>Start editing to see some magic happen!</h2>
107
+ </div>
108
+
109
+ The ▼ is there to show that's **DOM nodes**, not HTML.
110
+
111
+ `tosijs` lets you lean into web-standards and native browser functionality while writing less code that's
112
+ easier to run, debug, deploy, and maintain. Bind data direct to standard input elements—without having
113
+ to fight their basic behavior—and now you're using _native_ functionality with _deep accessibility_ support
114
+ as opposed to whatever the folks who wrote the library you're using have gotten around to implementing.
115
+
116
+ > **Aside**: `tosijs` will also probably work perfectly well with `Angular`, `Vue`, et al, but I haven't
117
+ > bothered digging into it and don't want to deal with `ngZone` stuff unless someone is paying
118
+ > me.
119
+
120
+ If you want to build your own `web-components` versus use something off-the-rack like
121
+ [Shoelace](https://shoelace.style), `tosijs` offers a `Component` base class that, along with
122
+ its `elements` and `css` libraries allows you to implement component views in pure Javascript
123
+ more compactly than with `jsx` (and without a virtual DOM).
124
+
125
+ import { Component, elements, css } from 'tosijs'
126
+
127
+ const { style, h1, slot } = elements
128
+ export class MyComponent extends Component {
129
+ styleNode = style(css({
130
+ h1: {
131
+ color: 'blue'
132
+ }
133
+ }))
134
+ content = [ h1('hello world'), slot() ]
135
+ }
136
+
137
+ The difference is that `web-components` are drop-in replacements for standard HTML elements
138
+ and interoperate happily with one-another and other libraries, load asynchronously,
139
+ and are natively supported by all modern browsers.
140
+
141
+ ## What `tosijs` does
142
+
143
+ ### Observe Object State
144
+
145
+ `tosijs` tracks the state of objects you assign to it using `paths` allowing economical
146
+ and direct updates to application state.
147
+
148
+ import { xinProxy, observe } from 'tosijs'
149
+
150
+ const { app } = xinProxy({
151
+ app: {
152
+ prefs: {
153
+ darkmode: false
154
+ },
155
+ docs: [
156
+ {
157
+ id: 1234,
158
+ title: 'title',
159
+ body: 'markdown goes here'
160
+ }
161
+ ]
162
+ }
163
+ })
164
+
165
+ observe('app.prefs.darkmode', () => {
166
+ document.body.classList.toggle('dark-mode', app.prefs.darkmode)
167
+ })
168
+
169
+ observe('app.docs', () => {
170
+ // render docs
171
+ })
172
+
173
+ > #### What does `xinProxy` do, and what is a `XinProxy`?
174
+ >
175
+ > `xinProxy` is syntax sugar for assigning something to `xin` (which is a `XinProxyObject`)
176
+ > and then getting it back out again.
177
+ >
178
+ > A `XinProxy` is an [ES Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
179
+ > wrapped around an `object` (which in Javascript means anything
180
+ > that has a `constructor` which in particular includes `Array`s, `class` instances, `function`s
181
+ > and so on, but not "scalars" like `number`s, `string`s, `boolean`s, `null`, and `undefined`)
182
+ >
183
+ > All you need to know about a `XinProxy` is that it's Proxy wrapped around your original
184
+ > object that allows you to interact with the object normally, but which allows `tosijs` to
185
+ > **observe** changes made to the wrapped object and tell interested parties about the changes.
186
+ >
187
+ > If you want to original object back you can just hold on to a reference or use `xinValue(someProxy)`
188
+ > to unwrap it.
189
+
190
+ ### No Tax, No Packaging
191
+
192
+ `tosijs` does not modify the stuff you hand over to it… it just wraps objects
193
+ with a `Proxy` and then if you use `xin` to make changes to those objects,
194
+ `tosijs` will notify any interested observers.
195
+
196
+ **Note** `xinProxy({foo: {...}})` is syntax sugar for `xin.foo = {...}`.
197
+
198
+ import { xinProxy, observe } from 'tosijs'
199
+ const { foo } = xinProxy({
200
+ foo: {
201
+ bar: 17
202
+ }
203
+ })
204
+
205
+ observe('foo.bar', v => {
206
+ console.log('foo.bar was changed to', xin.foo.bar)
207
+ })
208
+
209
+ foo.bar = 17 // does not trigger the observer
210
+ foo.bar = Math.PI // triggers the observer
211
+
212
+ ### Paths are like JavaScript
213
+
214
+ `xin` is designed to behave just like a JavaScript `Object`. What you put
215
+ into it is what you get out of it:
216
+
217
+ import { xin, xinValue } from 'tosijs'
218
+
219
+ const foo = {bar: 'baz'}
220
+ xin.foo = foo
221
+
222
+ // xin.foo returns a Proxy wrapped around foo (without touching foo)
223
+ xinValue(xin.foo) === foo
224
+
225
+ // really, it's just the original object
226
+ xin.foo.bar = 'lurman'
227
+ foo.bar === 'lurman' // true
228
+
229
+ // seriously, it's just the original object
230
+ foo.bar = 'luhrman'
231
+ xin.foo.bar === 'luhrman' // true
232
+
233
+ ### …but better!
234
+
235
+ It's very common to deal with arrays of objects that have unique id values,
236
+ so `tosijs` supports the idea of id-paths
237
+
238
+ import { xinProxy, xin } from 'tosijs
239
+
240
+ const { app } = xinProxy ({
241
+ app: {
242
+ list: [
243
+ {
244
+ id: '1234abcd',
245
+ text: 'hello world'
246
+ },
247
+ {
248
+ id: '5678efgh',
249
+ text: 'so long, redux'
250
+ }
251
+ ]
252
+ }
253
+ })
254
+
255
+ console.log(app.list[0].text) // hello world
256
+ console.log(app.list['id=5678efgh']) // so long, redux
257
+ console.log(xin['app.list[id=1234abcd']) // hello world
258
+
259
+ ### Telling `xin` about changes using `touch()`
260
+
261
+ Sometimes you will modify an object behind `xin`'s back (e.g. for efficiency).
262
+ When you want to trigger updates, simply touch the path.
263
+
264
+ import { xin, observe, touch } from 'tosijs'
265
+
266
+ const foo = { bar: 17 }
267
+ xin.foo = foo
268
+ observe('foo.bar', path => console.log(path, '->', xin[path])
269
+ xin.foo.bar = -2 // console will show: foo.bar -> -2
270
+
271
+ foo.bar = 100 // nothing happens
272
+ touch('foo.bar') // console will show: foo.bar -> 100
273
+
274
+ ### CSS
275
+
276
+ `tosijs` includes utilities for working with css.
277
+
278
+ import {css, vars, initVars, darkMode} from 'tosijs'
279
+ const cssVars = {
280
+ textFont: 'sans-serif'
281
+ color: '#111'
282
+ }
283
+
284
+ `initVars()` processes an object changing its keys from camelCase to --kabob-case:
285
+
286
+ initVars(cssVars) // emits { --text-font: "sans-serif", --color: "#111" }
287
+
288
+ `darkMode()` processes an object, taking only the color properties and inverting their luminance values:
289
+ darkMode(cssVars) // emits { color: '#ededed' }
290
+
291
+ The `vars` simply converts its camelCase properties into css variable references
292
+
293
+ vars.fooBar // emits 'var(--foo-bar)'
294
+ calc(`${vars.width} + 2 * ${vars.spacing}`) // emits 'calc(var(--width) + 2 * var(--spacing))'
295
+
296
+ `css()` processes an object, rendering it as CSS
297
+
298
+ css({
299
+ '.container': {
300
+ 'position', 'relative'
301
+ }
302
+ }) // emits .container { position: relative; }
303
+
304
+ ## Color
305
+
306
+ `tosijs` includes a powerful `Color` class for manipulating colors.
307
+
308
+ import {Color} from 'tosijs
309
+ const translucentBlue = new Color(0, 0, 255, 0.5) // r, g, b, a parameters
310
+ const postItBackground = Color.fromCss('#e7e79d')
311
+ const darkGrey = Color.fromHsl(0, 0, 0.2)
312
+
313
+ The color objects have computed properties for rendering the color in different ways,
314
+ making adjustments, blending colors, and so forth.
315
+
316
+ ## Hot Reload
317
+
318
+ One of the nice things about working with the React toolchain is hot reloading.
319
+ `tosijs` supports hot reloading (and not just in development!) via the `hotReload()`
320
+ function:
321
+
322
+ import {xin, hotReload} from 'tosijs'
323
+
324
+ xin.app = {
325
+ ...
326
+ }
327
+
328
+ hotReload()
329
+
330
+ `hotReload` stores serializable state managed by `xin` in localStorage and restores
331
+ it (by overlay) on reload. Because any functions (for example) won't be persisted,
332
+ simply call `hotReload` after initializing your app state and you're good to go.
333
+
334
+ `hotReload` accepts a test function (path => boolean) as a parameter.
335
+ Only top-level properties in `xin` that pass the test will be persisted.
336
+
337
+ To completely reset the app, run `localStorage.clear()` in the console.
338
+
339
+ ### Types
340
+
341
+ `tosijs` [type-by-example](https://www.npmjs.com/package/type-by-example) has been
342
+ broken out into a separate standalone library. (Naturally it works very well with
343
+ tosijs but they are completely independent.)
344
+
345
+ ## Development Notes
346
+
347
+ You'll need to install [bun](https://bun.sh/) and [nodejs](https://nodejs.org)),
348
+ and then run `npm install` and `bun install`. `bun` is used because it's
349
+ **fast** and is a really nice test-runner.
350
+
351
+ To work interactively on the demo code, use `bun start`. This runs the demo
352
+ site on localhost.
353
+
354
+ To build everything run `bun run make` which builds production versions of the
355
+ demo site (in `www`) and the `dist` and `cdn` directories.
356
+
357
+ To create a local package (for experimenting with a build) run `bun pack`.
358
+
359
+ ### Parcel Occasionally Gets Screwed Up
360
+
361
+ - remove all the parcel transformer dependencies @parcel/\*
362
+ - rm -rf node_modules
363
+ - run the update script
364
+ - npx parcel build (which restores needed parcel transformers)
365
+
366
+ ## Related Libraries
367
+
368
+ - react-tosijs [react-tosijs](https://github.com/tonioloewald/react-tosijs#readme)
369
+ allows you to use xin's path-observer model in React [ReactJS](https://reactjs.org) apps
370
+ - type-by-example [github](https://github.com/tonioloewald/type-by-example) | [npm](https://www.npmjs.com/package/type-by-example)
371
+ is a library for declaring types in pure javascript, allowing run-time type-checking.
372
+ - filter-shapes [github](https://github.com/tonioloewald/filter-shapes) | [npm](https://www.npmjs.com/package/filter-shapes)
373
+ is a library for filtering objects (and arrays of objects) to specific shapes (e.g. to reduce storage / bandwidth costs).
374
+ It is built on top of type-by-example.
375
+
376
+ ## Credits
377
+
378
+ `tosijs` is in essence a highly incompatible update to `b8rjs` with the goal
379
+ of removing cruft, supporting more use-cases, and eliminating functionality
380
+ that has been made redundant by improvements to the JavaScript language and
381
+ DOM APIs.
382
+
383
+ `tosijs` is being developed using [bun](https://bun.sh/).
384
+ `bun` is crazy fast (based on Webkit's JS engine, vs. V8), does a lot of stuff
385
+ natively, and runs TypeScript (with import and require) directly.
package/dist/bind.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { XinEventHandler, XinTouchableType, XinBinding, XinBindingSpec, EventType } from './xin-types';
2
+ export declare const touchElement: (element: Element, changedPath?: string) => void;
3
+ interface BindingOptions {
4
+ [key: string]: any;
5
+ }
6
+ export declare function bind<T extends Element = Element>(element: T, what: XinTouchableType | XinBindingSpec, binding: XinBinding<T>, options?: BindingOptions): T;
7
+ type RemoveListener = VoidFunction;
8
+ export declare function on<E extends HTMLElement, K extends EventType>(element: E, eventType: K, eventHandler: XinEventHandler<HTMLElementEventMap[K], E>): RemoveListener;
9
+ export {};
@@ -0,0 +1,4 @@
1
+ import { XinBinding } from './xin-types';
2
+ export declare const bindings: {
3
+ [key: string | symbol]: XinBinding<Element>;
4
+ };
@@ -0,0 +1,19 @@
1
+ import { Component } from './component';
2
+ import { XinPackagedComponent } from './make-component';
3
+ export declare class Blueprint extends Component {
4
+ tag: string;
5
+ src: string;
6
+ property: string;
7
+ loaded?: XinPackagedComponent;
8
+ blueprintLoaded: (_package: XinPackagedComponent) => void;
9
+ packaged(): Promise<XinPackagedComponent>;
10
+ constructor();
11
+ }
12
+ export declare const blueprint: import("./xin-types").ElementCreator<Component<import("./xin-types").PartsMap>>;
13
+ export declare class BlueprintLoader extends Component {
14
+ allLoaded: () => void;
15
+ constructor();
16
+ private load;
17
+ connectedCallback(): void;
18
+ }
19
+ export declare const blueprintLoader: import("./xin-types").ElementCreator<Component<import("./xin-types").PartsMap>>;
@@ -0,0 +1,8 @@
1
+ import { XinObject, XinArray } from './xin-types';
2
+ type Part = string | string[];
3
+ type PartArray = Part[];
4
+ declare function pathParts(path: string | PartArray): PartArray;
5
+ declare function getByPath(obj: XinObject | XinArray, path: string): any;
6
+ declare function setByPath(orig: XinObject | XinArray, path: string, val: any): boolean;
7
+ declare function deleteByPath(orig: XinObject, path: string): void;
8
+ export { getByPath, setByPath, deleteByPath, pathParts };
@@ -0,0 +1,46 @@
1
+ import { CSSSystemColor } from './css-system-color';
2
+ declare class HslColor {
3
+ h: number;
4
+ s: number;
5
+ l: number;
6
+ constructor(r: number, g: number, b: number);
7
+ }
8
+ export declare class Color {
9
+ r: number;
10
+ g: number;
11
+ b: number;
12
+ a: number;
13
+ static fromVar(varName: string, element?: HTMLElement): Color;
14
+ static fromCss(spec: CSSSystemColor | string): Color;
15
+ static fromHsl(h: number, s: number, l: number, a?: number): Color;
16
+ static black: Color;
17
+ static white: Color;
18
+ constructor(r: number, g: number, b: number, a?: number);
19
+ get inverse(): Color;
20
+ get inverseLuminance(): Color;
21
+ contrasting(amount?: number): Color;
22
+ get rgb(): string;
23
+ get rgba(): string;
24
+ get RGBA(): number[];
25
+ get ARGB(): number[];
26
+ private hslCached?;
27
+ get _hsl(): HslColor;
28
+ get hsl(): string;
29
+ get hsla(): string;
30
+ get mono(): Color;
31
+ get brightness(): number;
32
+ get html(): string;
33
+ toString(): string;
34
+ brighten(amount: number): Color;
35
+ darken(amount: number): Color;
36
+ saturate(amount: number): Color;
37
+ desaturate(amount: number): Color;
38
+ rotate(amount: number): Color;
39
+ opacity(alpha: number): Color;
40
+ swatch(): Color;
41
+ blend(otherColor: Color, t: number): Color;
42
+ static blendHue(a: number, b: number, t: number): number;
43
+ mix(otherColor: Color, t: number): Color;
44
+ colorMix(otherColor: Color, t: number): Color;
45
+ }
46
+ export {};
@@ -0,0 +1,37 @@
1
+ import { XinStyleSheet } from './css-types';
2
+ import { ElementsProxy } from './elements';
3
+ import { ElementCreator, ContentType, PartsMap } from './xin-types';
4
+ interface ElementCreatorOptions extends ElementDefinitionOptions {
5
+ tag?: string;
6
+ styleSpec?: XinStyleSheet;
7
+ }
8
+ export declare abstract class Component<T = PartsMap> extends HTMLElement {
9
+ static elements: ElementsProxy;
10
+ private static _elementCreator?;
11
+ instanceId: string;
12
+ styleNode?: HTMLStyleElement;
13
+ static styleSpec?: XinStyleSheet;
14
+ static styleNode?: HTMLStyleElement;
15
+ content: ContentType | (() => ContentType) | null;
16
+ isSlotted?: boolean;
17
+ private static _tagName;
18
+ static get tagName(): null | string;
19
+ [key: string]: any;
20
+ static StyleNode(styleSpec: XinStyleSheet): HTMLStyleElement;
21
+ static elementCreator(options?: ElementCreatorOptions): ElementCreator<Component>;
22
+ initAttributes(...attributeNames: string[]): void;
23
+ private initValue;
24
+ private _parts?;
25
+ get parts(): T;
26
+ constructor();
27
+ connectedCallback(): void;
28
+ disconnectedCallback(): void;
29
+ private _changeQueued;
30
+ private _renderQueued;
31
+ queueRender(triggerChangeEvent?: boolean): void;
32
+ private _hydrated;
33
+ private hydrate;
34
+ render(): void;
35
+ }
36
+ export declare const xinSlot: ElementCreator<Component<PartsMap>>;
37
+ export {};
@@ -0,0 +1,3 @@
1
+ export declare const cssColors: {
2
+ [key: string]: string;
3
+ };
@@ -0,0 +1 @@
1
+ export type CSSSystemColor = 'aliceblue' | 'antiquewhite' | 'aqua' | 'aquamarine' | 'azure' | 'beige' | 'bisque' | 'black' | 'blanchedalmond' | 'blue' | 'blueviolet' | 'brown' | 'burlywood' | 'cadetblue' | 'chartreuse' | 'chocolate' | 'coral' | 'cornflowerblue' | 'cornsilk' | 'crimson' | 'cyan' | 'darkblue' | 'darkcyan' | 'darkgoldenrod' | 'darkgray' | 'darkgreen' | 'darkgrey' | 'darkkhaki' | 'darkmagenta' | 'darkolivegreen' | 'darkorange' | 'darkorchid' | 'darkred' | 'darksalmon' | 'darkseagreen' | 'darkslateblue' | 'darkslategray' | 'darkslategrey' | 'darkturquoise' | 'darkviolet' | 'deeppink' | 'deepskyblue' | 'dimgray' | 'dimgrey' | 'dodgerblue' | 'firebrick' | 'floralwhite' | 'forestgreen' | 'fuchsia' | 'gainsboro' | 'ghostwhite' | 'gold' | 'goldenrod' | 'gray' | 'green' | 'greenyellow' | 'grey' | 'honeydew' | 'hotpink' | 'indianred' | 'indigo' | 'ivory' | 'khaki' | 'lavender' | 'lavenderblush' | 'lawngreen' | 'lemonchiffon' | 'lightblue' | 'lightcoral' | 'lightcyan' | 'lightgoldenrodyellow' | 'lightgray' | 'lightgreen' | 'lightgrey' | 'lightpink' | 'lightsalmon' | 'lightseagreen' | 'lightskyblue' | 'lightslategray' | 'lightslategrey' | 'lightsteelblue' | 'lightyellow' | 'lime' | 'limegreen' | 'linen' | 'magenta' | 'maroon' | 'mediumaquamarine' | 'mediumblue' | 'mediumorchid' | 'mediumpurple' | 'mediumseagreen' | 'mediumslateblue' | 'mediumspringgreen' | 'mediumturquoise' | 'mediumvioletred' | 'midnightblue' | 'mintcream' | 'mistyrose' | 'moccasin' | 'navajowhite' | 'navy' | 'oldlace' | 'olive' | 'olivedrab' | 'orange' | 'orangered' | 'orchid' | 'palegoldenrod' | 'palegreen' | 'paleturquoise' | 'palevioletred' | 'papayawhip' | 'peachpuff' | 'peru' | 'pink' | 'plum' | 'powderblue' | 'purple' | 'red' | 'rosybrown' | 'royalblue' | 'saddlebrown' | 'salmon' | 'sandybrown' | 'seagreen' | 'seashell' | 'sienna' | 'silver' | 'skyblue' | 'slateblue' | 'slategray' | 'slategrey' | 'snow' | 'springgreen' | 'steelblue' | 'tan' | 'teal' | 'thistle' | 'tomato' | 'turquoise' | 'violet' | 'wheat' | 'white' | 'whitesmoke' | 'yellow' | 'yellowgreen';