@orieljs/view 0.1.0-alpha.6 → 0.1.0-alpha.7

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/NOTICE CHANGED
@@ -10,3 +10,7 @@ The Oriel name and logo are not covered by that license; see TRADEMARKS.md
10
10
 
11
11
  @orieljs/support (and @orieljs/framework, which bundles it) includes transliteration data from
12
12
  voku/portable-ascii (https://github.com/voku/portable-ascii), Copyright (C) 2019 Lars Moelleken, MIT License.
13
+
14
+ @orieljs/notifications (and @orieljs/framework, which bundles it) includes the HTML and CSS of
15
+ Laravel's default notification mail (laravel/framework, https://github.com/laravel/framework),
16
+ Copyright (c) Taylor Otwell, MIT License.
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # @orieljs/view
2
+
3
+ Server-rendered views for Oriel, written in TSX: a view is a function component that returns HTML, where Laravel uses Blade. It is part of `@orieljs/framework`, which every Oriel app already installs, and is re-exported from it. In an app, import it from `@orieljs/framework`; `@orieljs/view` is also published on its own.
4
+
5
+ ```bash
6
+ npm install @orieljs/framework
7
+ ```
8
+
9
+ ```tsx title="resources/views/posts/index.tsx"
10
+ import type { Post } from '../../../app/Models/Post'
11
+
12
+ export default function Index({ posts }: { posts: Post[] }) {
13
+ return (
14
+ <ul>
15
+ {posts.map((post) => (
16
+ <li>
17
+ <a href={`/posts/${post.slug}`}>{post.title}</a>
18
+ </li>
19
+ ))}
20
+ </ul>
21
+ )
22
+ }
23
+ ```
24
+
25
+ `view('posts.index', { posts })` renders `resources/views/posts/index.tsx` from a route or a controller. Text is escaped unless it is wrapped in `raw()`. `View.share()` and `View.composer()` add data to views, and `csrfField()` and `methodField()` write a form's hidden fields.
26
+
27
+ Documentation: https://orieljs.vercel.app/docs/views
28
+
29
+ Status: early alpha. APIs will change.
30
+
31
+ ## License
32
+
33
+ Oriel is open-source software licensed under the Apache License 2.0 (Apache-2.0; see `LICENSE` and `NOTICE`). The Oriel name and logo are trademarks; see `TRADEMARKS.md`.
34
+
35
+ Website: https://orieljs.vercel.app
package/TRADEMARKS.md ADDED
@@ -0,0 +1,33 @@
1
+ # Oriel trademark policy
2
+
3
+ The Oriel code is open source under the Apache License 2.0. The **Oriel name and logo** are not: the license covers
4
+ the code only (section 6 of the license says so), and the name and logo stay with the project. This page explains
5
+ what you can and can't do with them. The goal is simple: people should always be able to tell what is the real Oriel
6
+ and what isn't.
7
+
8
+ ## You can, without asking
9
+
10
+ - Use, change, ship and sell the code, as the license allows.
11
+ - Say that your app or package is "built with Oriel", "for Oriel" or "compatible with Oriel".
12
+ - Name a package `oriel-<something>` or `<something>-for-oriel` when it works with Oriel, as long as it is clear that
13
+ it is not official (for example, don't publish it under the `@orieljs` npm scope).
14
+ - Use the name and logo to write about Oriel, teach it, or link to it, in articles, talks, videos and courses.
15
+ - Use the unmodified logo to point to the project, as it is (no recolouring, cropping or
16
+ distortion).
17
+
18
+ ## You can't, without written permission
19
+
20
+ - Call a fork, a modified copy or a competing product "Oriel", or anything likely to be confused with it.
21
+ - Use the name or logo as the name, logo or domain of your own product, company or service.
22
+ - Suggest that the Oriel project made, endorses or supports your work when it doesn't.
23
+ - Sell merchandise with the name or logo.
24
+
25
+ ## Forks
26
+
27
+ Forks are welcome. Please give yours a different name and logo, keep the `LICENSE` and `NOTICE` files, and say that
28
+ it is based on Oriel.
29
+
30
+ ## Questions
31
+
32
+ Open an issue at https://github.com/orieljs/framework or email meeeet.dev@gmail.com. If you're unsure whether a use
33
+ is fine, ask; the answer is usually yes.
@@ -22,4 +22,4 @@ export {
22
22
  jsx,
23
23
  jsxs
24
24
  };
25
- //# sourceMappingURL=chunk-KIU7OKDI.js.map
25
+ //# sourceMappingURL=chunk-AXHMZAM6.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../Element.ts","../jsx-runtime.ts"],"sourcesContent":["import type { Htmlable } from '@orieljs/contracts'\n\n/** Marks the objects jsx() returns (Symbol.for, so two copies of the package agree). */\nexport const ELEMENT: unique symbol = Symbol.for('oriel:view.element')\n\nexport type Props = Record<string, unknown>\n\n/** Anything that can appear as a child: text is escaped, Htmlable is emitted as-is, promises are awaited. */\nexport type Renderable =\n | OrielElement\n | string\n | number\n | bigint\n | boolean\n | null\n | undefined\n | Htmlable\n | Promise<Renderable>\n | Iterable<Renderable>\n\n/** A function component. It may be async: the renderer awaits it. */\nexport type Component<P = Props> = (props: P) => Renderable | Promise<Renderable>\n\n/**\n * `<>…</>` and `<Fragment>`: renders its children only. A symbol at runtime; typed as a component so that\n * `<Fragment>` type-checks as a JSX tag.\n */\nexport const Fragment = Symbol.for('oriel:view.fragment') as unknown as (props: { children?: Renderable }) => Renderable\n\nexport type ElementType = string | Component<never>\n\n/** What `<div />` evaluates to: an inert description, rendered later by renderToString()/renderToStream(). */\nexport interface OrielElement {\n readonly [ELEMENT]: true\n readonly type: ElementType\n readonly props: Props\n readonly key: string | number | undefined\n}\n\nexport function createElement(type: ElementType, props: Props | null | undefined, key?: string | number): OrielElement {\n return { [ELEMENT]: true, type, props: props ?? {}, key }\n}\n\nexport function isElement(value: unknown): value is OrielElement {\n return typeof value === 'object' && value !== null && (value as Record<symbol, unknown>)[ELEMENT] === true\n}\n","/**\n * The automatic JSX runtime (`jsxImportSource: \"@orieljs/view\"`). jsx() only describes elements; rendering\n * (escaping, async components) happens in renderToString()/renderToStream().\n */\nimport type { ClassValue, StyleObject } from './attributes'\nimport { createElement, Fragment, type Component, type ElementType, type OrielElement, type Props, type Renderable } from './Element'\n\nexport { Fragment }\n\nexport function jsx(type: ElementType, props: Props | null, key?: string | number): OrielElement {\n return createElement(type, props, key)\n}\n\n/** Same as jsx(); the compiler uses it when there are several static children. */\nexport const jsxs = jsx\n\n/** Attributes every intrinsic element accepts. Unknown attributes (hx-*, x-*, o:click, …) are allowed. */\nexport interface HtmlAttributes {\n children?: Renderable\n class?: ClassValue\n className?: ClassValue\n style?: string | StyleObject\n dangerouslySetInnerHTML?: { __html: string }\n [attribute: string]: unknown\n}\n\nexport declare namespace JSX {\n type Element = OrielElement\n /** Lets components be async: `async function Posts() { … }` is a valid element type. */\n type ElementType = string | Component<never>\n interface ElementChildrenAttribute {\n children: unknown\n }\n interface IntrinsicAttributes {\n key?: string | number\n }\n interface IntrinsicElements {\n [element: string]: HtmlAttributes\n }\n}\n"],"mappings":";AAGO,IAAM,UAAyB,uBAAO,IAAI,oBAAoB;AAwB9D,IAAM,WAAW,uBAAO,IAAI,qBAAqB;AAYjD,SAAS,cAAc,MAAmB,OAAiC,KAAqC;AACrH,SAAO,EAAE,CAAC,OAAO,GAAG,MAAM,MAAM,OAAO,SAAS,CAAC,GAAG,IAAI;AAC1D;AAEO,SAAS,UAAU,OAAuC;AAC/D,SAAO,OAAO,UAAU,YAAY,UAAU,QAAS,MAAkC,OAAO,MAAM;AACxG;;;ACpCO,SAAS,IAAI,MAAmB,OAAqB,KAAqC;AAC/F,SAAO,cAAc,MAAM,OAAO,GAAG;AACvC;AAGO,IAAM,OAAO;","names":[]}
1
+ {"version":3,"sources":["../Element.ts","../jsx-runtime.ts"],"sourcesContent":["import type { Htmlable } from '@orieljs/contracts'\n\n/** Marks the objects jsx() returns (Symbol.for, so two copies of the package agree). */\nexport const ELEMENT: unique symbol = Symbol.for('oriel:view.element')\n\nexport type Props = Record<string, unknown>\n\n/** Anything that can appear as a child: text is escaped, Htmlable is emitted as-is, promises are awaited. */\nexport type Renderable =\n | OrielElement\n | string\n | number\n | bigint\n | boolean\n | null\n | undefined\n | Htmlable\n | Promise<Renderable>\n | Iterable<Renderable>\n\n/** A function component. It may be async: the renderer awaits it. */\nexport type Component<P = Props> = (props: P) => Renderable | Promise<Renderable>\n\n/**\n * `<>…</>` and `<Fragment>`: renders its children only. A symbol at runtime; typed as a component so that\n * `<Fragment>` type-checks as a JSX tag.\n */\nexport const Fragment = Symbol.for('oriel:view.fragment') as unknown as (props: { children?: Renderable }) => Renderable\n\nexport type ElementType = string | Component<never>\n\n/** What `<div />` evaluates to: an inert description, rendered later by renderToString()/renderToStream(). */\nexport interface OrielElement {\n readonly [ELEMENT]: true\n readonly type: ElementType\n readonly props: Props\n readonly key: string | number | undefined\n}\n\nexport function createElement(type: ElementType, props: Props | null | undefined, key?: string | number): OrielElement {\n return { [ELEMENT]: true, type, props: props ?? {}, key }\n}\n\nexport function isElement(value: unknown): value is OrielElement {\n return typeof value === 'object' && value !== null && (value as Record<symbol, unknown>)[ELEMENT] === true\n}\n","/**\n * The automatic JSX runtime (`jsxImportSource: \"@orieljs/view\"`). jsx() only describes elements; rendering\n * (escaping, async components) happens in renderToString()/renderToStream().\n */\nimport type { ClassValue, StyleObject } from './attributes'\nimport type { LiveDirectiveAttributes, LiveEventAttributes, OtherAttributes } from './directives'\nimport { createElement, Fragment, type Component, type ElementType, type OrielElement, type Props, type Renderable } from './Element'\n\nexport { Fragment }\n\nexport function jsx(type: ElementType, props: Props | null, key?: string | number): OrielElement {\n return createElement(type, props, key)\n}\n\n/** Same as jsx(); the compiler uses it when there are several static children. */\nexport const jsxs = jsx\n\n/**\n * Attributes every intrinsic element accepts. Any attribute is allowed (hx-*, x-*, data-*, …) except an `o:` name\n * that isn't a Live directive or `o:<event>` (directives.ts), so a typo such as `o:clik` doesn't compile. An `o:` form\n * with a `-` that the type doesn't list compiles unchecked (TypeScript doesn't check a hyphenated JSX name the type\n * leaves out), and a custom event name is spread: `<div {...{ 'o:saved': 'refresh' }} />`.\n */\nexport interface HtmlAttributes extends OtherAttributes, LiveDirectiveAttributes, LiveEventAttributes {\n children?: Renderable\n class?: ClassValue\n className?: ClassValue\n style?: string | StyleObject\n dangerouslySetInnerHTML?: { __html: string }\n}\n\nexport declare namespace JSX {\n type Element = OrielElement\n /** Lets components be async: `async function Posts() { … }` is a valid element type. */\n type ElementType = string | Component<never>\n interface ElementChildrenAttribute {\n children: unknown\n }\n interface IntrinsicAttributes {\n key?: string | number\n }\n interface IntrinsicElements {\n [element: string]: HtmlAttributes\n }\n}\n"],"mappings":";AAGO,IAAM,UAAyB,uBAAO,IAAI,oBAAoB;AAwB9D,IAAM,WAAW,uBAAO,IAAI,qBAAqB;AAYjD,SAAS,cAAc,MAAmB,OAAiC,KAAqC;AACrH,SAAO,EAAE,CAAC,OAAO,GAAG,MAAM,MAAM,OAAO,SAAS,CAAC,GAAG,IAAI;AAC1D;AAEO,SAAS,UAAU,OAAuC;AAC/D,SAAO,OAAO,UAAU,YAAY,UAAU,QAAS,MAAkC,OAAO,MAAM;AACxG;;;ACnCO,SAAS,IAAI,MAAmB,OAAqB,KAAqC;AAC/F,SAAO,cAAc,MAAM,OAAO,GAAG;AACvC;AAGO,IAAM,OAAO;","names":[]}
package/dist/index.d.ts CHANGED
@@ -53,6 +53,93 @@ declare function renderToString(node: Renderable): Promise<string>;
53
53
  /** Renders to a UTF-8 byte stream, sending everything rendered so far each time rendering waits on a promise. */
54
54
  declare function renderToStream(node: Renderable): ReadableStream<Uint8Array>;
55
55
 
56
+ /**
57
+ * The `o:` attributes of Live components, typed for TSX: a directive (`o:model`, `o:loading`, …) or an action on a DOM
58
+ * event (`o:click="save"`), with modifiers joined by `-` (`o:model-live`, `o:keydown-enter`). An `o:` name that is
59
+ * neither doesn't compile (`o:clik`, `o:modle`), and the forms listed here are completed by editors and have their
60
+ * values checked. TypeScript doesn't check JSX attribute names that contain a `-` unless the type lists them, so a
61
+ * form that isn't listed (a duration such as `o:model-live-debounce-500ms`, an event's modifiers) is accepted as
62
+ * written, and so is a misspelt one (`o:model-lvie`).
63
+ */
64
+ type ModelTrigger = 'live' | 'blur' | 'change' | 'lazy';
65
+ type ElementChange = 'remove' | 'class' | 'class-remove' | 'attr';
66
+ /**
67
+ * The directives that aren't DOM events, by name: the value each takes (`boolean` for one that can be written bare,
68
+ * `<a o:navigate>`, or from an expression, `o:navigate={external}`: `false` leaves it out) and its modifier forms, the
69
+ * `-`-joined text after the name (`never` for none). A new directive adds a member here, and its name to the Live
70
+ * client's reserved directives.
71
+ */
72
+ interface LiveDirectives {
73
+ /** o:model="title": binds an input to a public property, sent with the next request unless live, blur, change or lazy. */
74
+ model: {
75
+ value: string;
76
+ modifiers: ModelTrigger | 'number' | 'debounce' | 'live-debounce' | `${ModelTrigger}-number`;
77
+ };
78
+ /** o:loading: shown (or changed) while the component's request runs. */
79
+ loading: {
80
+ value: boolean | string;
81
+ modifiers: ElementChange | 'delay' | `delay-${ElementChange}`;
82
+ };
83
+ /** o:target="save,title": the actions or properties o:loading waits for. */
84
+ target: {
85
+ value: string;
86
+ modifiers: never;
87
+ };
88
+ /** o:poll="refresh": calls the method ($refresh without one) every 2.5 s, or every `o:poll-<n>s`. */
89
+ poll: {
90
+ value: boolean | string;
91
+ modifiers: 'keep-alive' | 'visible';
92
+ };
93
+ /** o:navigate on a link: fetches the page and swaps it in; `-hover` prefetches on hover. */
94
+ navigate: {
95
+ value: boolean;
96
+ modifiers: 'hover';
97
+ };
98
+ /** o:offline: shown (or changed) while the browser is offline. */
99
+ offline: {
100
+ value: boolean | string;
101
+ modifiers: ElementChange;
102
+ };
103
+ /** o:key: keeps an element's identity across re-renders. */
104
+ key: {
105
+ value: string | number;
106
+ modifiers: never;
107
+ };
108
+ /** o:confirm="Delete this tag?": asks before the element's action runs; `-prompt` asks for a typed answer. */
109
+ confirm: {
110
+ value: boolean | string;
111
+ modifiers: 'prompt';
112
+ };
113
+ /** o:announce on a status region: an action that leaves the same message announces it again. */
114
+ announce: {
115
+ value: boolean;
116
+ modifiers: never;
117
+ };
118
+ }
119
+ /**
120
+ * The DOM events `o:<event>` runs an action on. A name with a `-` can't be written in TSX (modifiers are `-`
121
+ * segments), and `offline` is the o:offline directive, not the event. An event this list doesn't have (a custom
122
+ * event a component dispatches) is spread: `<div {...{ 'o:saved': 'refresh' }} />`.
123
+ */
124
+ type LiveEvent = 'click' | 'dblclick' | 'auxclick' | 'contextmenu' | 'mousedown' | 'mouseup' | 'mousemove' | 'mouseover' | 'mouseout' | 'mouseenter' | 'mouseleave' | 'wheel' | 'pointerdown' | 'pointerup' | 'pointermove' | 'pointerover' | 'pointerout' | 'pointerenter' | 'pointerleave' | 'pointercancel' | 'gotpointercapture' | 'lostpointercapture' | 'keydown' | 'keyup' | 'keypress' | 'input' | 'beforeinput' | 'change' | 'submit' | 'reset' | 'invalid' | 'select' | 'formdata' | 'search' | 'focus' | 'blur' | 'focusin' | 'focusout' | 'copy' | 'cut' | 'paste' | 'drag' | 'dragstart' | 'dragend' | 'dragenter' | 'dragleave' | 'dragover' | 'drop' | 'touchstart' | 'touchend' | 'touchmove' | 'touchcancel' | 'compositionstart' | 'compositionupdate' | 'compositionend' | 'play' | 'pause' | 'playing' | 'ended' | 'timeupdate' | 'volumechange' | 'ratechange' | 'durationchange' | 'loadstart' | 'loadeddata' | 'loadedmetadata' | 'canplay' | 'canplaythrough' | 'seeking' | 'seeked' | 'waiting' | 'stalled' | 'suspend' | 'emptied' | 'progress' | 'abort' | 'error' | 'load' | 'animationstart' | 'animationend' | 'animationiteration' | 'animationcancel' | 'transitionstart' | 'transitionend' | 'transitionrun' | 'transitioncancel' | 'scroll' | 'scrollend' | 'resize' | 'toggle' | 'beforetoggle' | 'close' | 'cancel' | 'online' | 'popstate' | 'hashchange' | 'beforeunload' | 'pagehide' | 'pageshow' | 'storage' | 'message' | 'visibilitychange' | 'selectionchange' | 'fullscreenchange' | 'slotchange' | 'cuechange';
125
+ /** `o:model`, `o:model-live`, …: each directive and each of its modifier forms, with the directive's value. */
126
+ type LiveDirectiveAttributes = {
127
+ [N in keyof LiveDirectives as `o:${N}` | `o:${N}-${LiveDirectives[N]['modifiers']}`]?: LiveDirectives[N]['value'];
128
+ };
129
+ /** `o:click="save"`: an action (a method, `method(args)`, `$refresh`, `$set(…)`, `$dispatch(…)`) on a DOM event. */
130
+ type LiveEventAttributes = {
131
+ [E in LiveEvent as `o:${E}`]?: string;
132
+ };
133
+ type Letter = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';
134
+ type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
135
+ /**
136
+ * Every other attribute, with any value: each name that doesn't start with `o:` (`o`, `href`, `onclick`, `open`,
137
+ * `xlink:href`, `viewBox`; names with a `-`, such as `data-*`, `aria-*` and `hx-post`, are never checked).
138
+ */
139
+ type OtherAttributes = {
140
+ [K in 'o' | `${Exclude<Letter, 'o'> | Uppercase<Letter> | '_' | '$'}${string}` | `o${Letter | Uppercase<Letter> | Digit | '_' | '.' | '$'}${string}`]?: unknown;
141
+ };
142
+
56
143
  /**
57
144
  * The automatic JSX runtime (`jsxImportSource: "@orieljs/view"`). jsx() only describes elements; rendering
58
145
  * (escaping, async components) happens in renderToString()/renderToStream().
@@ -61,8 +148,13 @@ declare function renderToStream(node: Renderable): ReadableStream<Uint8Array>;
61
148
  declare function jsx(type: ElementType, props: Props | null, key?: string | number): OrielElement;
62
149
  /** Same as jsx(); the compiler uses it when there are several static children. */
63
150
  declare const jsxs: typeof jsx;
64
- /** Attributes every intrinsic element accepts. Unknown attributes (hx-*, x-*, o:click, …) are allowed. */
65
- interface HtmlAttributes {
151
+ /**
152
+ * Attributes every intrinsic element accepts. Any attribute is allowed (hx-*, x-*, data-*, …) except an `o:` name
153
+ * that isn't a Live directive or `o:<event>` (directives.ts), so a typo such as `o:clik` doesn't compile. An `o:` form
154
+ * with a `-` that the type doesn't list compiles unchecked (TypeScript doesn't check a hyphenated JSX name the type
155
+ * leaves out), and a custom event name is spread: `<div {...{ 'o:saved': 'refresh' }} />`.
156
+ */
157
+ interface HtmlAttributes extends OtherAttributes, LiveDirectiveAttributes, LiveEventAttributes {
66
158
  children?: Renderable;
67
159
  class?: ClassValue;
68
160
  className?: ClassValue;
@@ -70,7 +162,6 @@ interface HtmlAttributes {
70
162
  dangerouslySetInnerHTML?: {
71
163
  __html: string;
72
164
  };
73
- [attribute: string]: unknown;
74
165
  }
75
166
  declare namespace JSX {
76
167
  type Element = OrielElement;
@@ -207,4 +298,4 @@ declare class ViewServiceProvider extends ServiceProvider {
207
298
  register(): void;
208
299
  }
209
300
 
210
- export { type ClassValue, type Component, ELEMENT, Factory, FileViewFinder, Fragment, type HtmlAttributes, HtmlString, InvalidViewError, JSX, type OrielElement, type Props, type Renderable, type StyleObject, TsxView, View, type ViewEnvironment, ViewNotFoundError, ViewRenderError, ViewServiceProvider, classNames, createElement, csrfField, e, isElement, isHtmlable, jsx, jsxs, methodField, raw, renderToStream, renderToString, styleString, view };
301
+ export { type ClassValue, type Component, ELEMENT, Factory, FileViewFinder, Fragment, type HtmlAttributes, HtmlString, InvalidViewError, JSX, type LiveDirectiveAttributes, type LiveDirectives, type LiveEvent, type LiveEventAttributes, type OrielElement, type OtherAttributes, type Props, type Renderable, type StyleObject, TsxView, View, type ViewEnvironment, ViewNotFoundError, ViewRenderError, ViewServiceProvider, classNames, createElement, csrfField, e, isElement, isHtmlable, jsx, jsxs, methodField, raw, renderToStream, renderToString, styleString, view };
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  isElement,
6
6
  jsx,
7
7
  jsxs
8
- } from "./chunk-KIU7OKDI.js";
8
+ } from "./chunk-AXHMZAM6.js";
9
9
 
10
10
  // Html.ts
11
11
  var ESCAPES = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#039;" };
@@ -3,6 +3,93 @@ import { Htmlable } from '@orieljs/contracts';
3
3
  type ClassValue = string | number | null | undefined | false | ClassValue[] | Record<string, unknown>;
4
4
  type StyleObject = Record<string, string | number | null | undefined | false>;
5
5
 
6
+ /**
7
+ * The `o:` attributes of Live components, typed for TSX: a directive (`o:model`, `o:loading`, …) or an action on a DOM
8
+ * event (`o:click="save"`), with modifiers joined by `-` (`o:model-live`, `o:keydown-enter`). An `o:` name that is
9
+ * neither doesn't compile (`o:clik`, `o:modle`), and the forms listed here are completed by editors and have their
10
+ * values checked. TypeScript doesn't check JSX attribute names that contain a `-` unless the type lists them, so a
11
+ * form that isn't listed (a duration such as `o:model-live-debounce-500ms`, an event's modifiers) is accepted as
12
+ * written, and so is a misspelt one (`o:model-lvie`).
13
+ */
14
+ type ModelTrigger = 'live' | 'blur' | 'change' | 'lazy';
15
+ type ElementChange = 'remove' | 'class' | 'class-remove' | 'attr';
16
+ /**
17
+ * The directives that aren't DOM events, by name: the value each takes (`boolean` for one that can be written bare,
18
+ * `<a o:navigate>`, or from an expression, `o:navigate={external}`: `false` leaves it out) and its modifier forms, the
19
+ * `-`-joined text after the name (`never` for none). A new directive adds a member here, and its name to the Live
20
+ * client's reserved directives.
21
+ */
22
+ interface LiveDirectives {
23
+ /** o:model="title": binds an input to a public property, sent with the next request unless live, blur, change or lazy. */
24
+ model: {
25
+ value: string;
26
+ modifiers: ModelTrigger | 'number' | 'debounce' | 'live-debounce' | `${ModelTrigger}-number`;
27
+ };
28
+ /** o:loading: shown (or changed) while the component's request runs. */
29
+ loading: {
30
+ value: boolean | string;
31
+ modifiers: ElementChange | 'delay' | `delay-${ElementChange}`;
32
+ };
33
+ /** o:target="save,title": the actions or properties o:loading waits for. */
34
+ target: {
35
+ value: string;
36
+ modifiers: never;
37
+ };
38
+ /** o:poll="refresh": calls the method ($refresh without one) every 2.5 s, or every `o:poll-<n>s`. */
39
+ poll: {
40
+ value: boolean | string;
41
+ modifiers: 'keep-alive' | 'visible';
42
+ };
43
+ /** o:navigate on a link: fetches the page and swaps it in; `-hover` prefetches on hover. */
44
+ navigate: {
45
+ value: boolean;
46
+ modifiers: 'hover';
47
+ };
48
+ /** o:offline: shown (or changed) while the browser is offline. */
49
+ offline: {
50
+ value: boolean | string;
51
+ modifiers: ElementChange;
52
+ };
53
+ /** o:key: keeps an element's identity across re-renders. */
54
+ key: {
55
+ value: string | number;
56
+ modifiers: never;
57
+ };
58
+ /** o:confirm="Delete this tag?": asks before the element's action runs; `-prompt` asks for a typed answer. */
59
+ confirm: {
60
+ value: boolean | string;
61
+ modifiers: 'prompt';
62
+ };
63
+ /** o:announce on a status region: an action that leaves the same message announces it again. */
64
+ announce: {
65
+ value: boolean;
66
+ modifiers: never;
67
+ };
68
+ }
69
+ /**
70
+ * The DOM events `o:<event>` runs an action on. A name with a `-` can't be written in TSX (modifiers are `-`
71
+ * segments), and `offline` is the o:offline directive, not the event. An event this list doesn't have (a custom
72
+ * event a component dispatches) is spread: `<div {...{ 'o:saved': 'refresh' }} />`.
73
+ */
74
+ type LiveEvent = 'click' | 'dblclick' | 'auxclick' | 'contextmenu' | 'mousedown' | 'mouseup' | 'mousemove' | 'mouseover' | 'mouseout' | 'mouseenter' | 'mouseleave' | 'wheel' | 'pointerdown' | 'pointerup' | 'pointermove' | 'pointerover' | 'pointerout' | 'pointerenter' | 'pointerleave' | 'pointercancel' | 'gotpointercapture' | 'lostpointercapture' | 'keydown' | 'keyup' | 'keypress' | 'input' | 'beforeinput' | 'change' | 'submit' | 'reset' | 'invalid' | 'select' | 'formdata' | 'search' | 'focus' | 'blur' | 'focusin' | 'focusout' | 'copy' | 'cut' | 'paste' | 'drag' | 'dragstart' | 'dragend' | 'dragenter' | 'dragleave' | 'dragover' | 'drop' | 'touchstart' | 'touchend' | 'touchmove' | 'touchcancel' | 'compositionstart' | 'compositionupdate' | 'compositionend' | 'play' | 'pause' | 'playing' | 'ended' | 'timeupdate' | 'volumechange' | 'ratechange' | 'durationchange' | 'loadstart' | 'loadeddata' | 'loadedmetadata' | 'canplay' | 'canplaythrough' | 'seeking' | 'seeked' | 'waiting' | 'stalled' | 'suspend' | 'emptied' | 'progress' | 'abort' | 'error' | 'load' | 'animationstart' | 'animationend' | 'animationiteration' | 'animationcancel' | 'transitionstart' | 'transitionend' | 'transitionrun' | 'transitioncancel' | 'scroll' | 'scrollend' | 'resize' | 'toggle' | 'beforetoggle' | 'close' | 'cancel' | 'online' | 'popstate' | 'hashchange' | 'beforeunload' | 'pagehide' | 'pageshow' | 'storage' | 'message' | 'visibilitychange' | 'selectionchange' | 'fullscreenchange' | 'slotchange' | 'cuechange';
75
+ /** `o:model`, `o:model-live`, …: each directive and each of its modifier forms, with the directive's value. */
76
+ type LiveDirectiveAttributes = {
77
+ [N in keyof LiveDirectives as `o:${N}` | `o:${N}-${LiveDirectives[N]['modifiers']}`]?: LiveDirectives[N]['value'];
78
+ };
79
+ /** `o:click="save"`: an action (a method, `method(args)`, `$refresh`, `$set(…)`, `$dispatch(…)`) on a DOM event. */
80
+ type LiveEventAttributes = {
81
+ [E in LiveEvent as `o:${E}`]?: string;
82
+ };
83
+ type Letter = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';
84
+ type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
85
+ /**
86
+ * Every other attribute, with any value: each name that doesn't start with `o:` (`o`, `href`, `onclick`, `open`,
87
+ * `xlink:href`, `viewBox`; names with a `-`, such as `data-*`, `aria-*` and `hx-post`, are never checked).
88
+ */
89
+ type OtherAttributes = {
90
+ [K in 'o' | `${Exclude<Letter, 'o'> | Uppercase<Letter> | '_' | '$'}${string}` | `o${Letter | Uppercase<Letter> | Digit | '_' | '.' | '$'}${string}`]?: unknown;
91
+ };
92
+
6
93
  /** Marks the objects jsx() returns (Symbol.for, so two copies of the package agree). */
7
94
  declare const ELEMENT: unique symbol;
8
95
  type Props = Record<string, unknown>;
@@ -34,8 +121,13 @@ interface OrielElement {
34
121
  declare function jsx(type: ElementType, props: Props | null, key?: string | number): OrielElement;
35
122
  /** Same as jsx(); the compiler uses it when there are several static children. */
36
123
  declare const jsxs: typeof jsx;
37
- /** Attributes every intrinsic element accepts. Unknown attributes (hx-*, x-*, o:click, …) are allowed. */
38
- interface HtmlAttributes {
124
+ /**
125
+ * Attributes every intrinsic element accepts. Any attribute is allowed (hx-*, x-*, data-*, …) except an `o:` name
126
+ * that isn't a Live directive or `o:<event>` (directives.ts), so a typo such as `o:clik` doesn't compile. An `o:` form
127
+ * with a `-` that the type doesn't list compiles unchecked (TypeScript doesn't check a hyphenated JSX name the type
128
+ * leaves out), and a custom event name is spread: `<div {...{ 'o:saved': 'refresh' }} />`.
129
+ */
130
+ interface HtmlAttributes extends OtherAttributes, LiveDirectiveAttributes, LiveEventAttributes {
39
131
  children?: Renderable;
40
132
  class?: ClassValue;
41
133
  className?: ClassValue;
@@ -43,7 +135,6 @@ interface HtmlAttributes {
43
135
  dangerouslySetInnerHTML?: {
44
136
  __html: string;
45
137
  };
46
- [attribute: string]: unknown;
47
138
  }
48
139
  declare namespace JSX {
49
140
  type Element = OrielElement;
@@ -2,7 +2,7 @@ import {
2
2
  Fragment,
3
3
  jsx,
4
4
  jsxs
5
- } from "./chunk-KIU7OKDI.js";
5
+ } from "./chunk-AXHMZAM6.js";
6
6
  export {
7
7
  Fragment,
8
8
  jsx,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orieljs/view",
3
- "version": "0.1.0-alpha.6",
3
+ "version": "0.1.0-alpha.7",
4
4
  "description": "The Oriel View component.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -31,12 +31,13 @@
31
31
  "files": [
32
32
  "dist",
33
33
  "LICENSE",
34
- "NOTICE"
34
+ "NOTICE",
35
+ "TRADEMARKS.md"
35
36
  ],
36
37
  "dependencies": {
37
- "@orieljs/contracts": "0.1.0-alpha.6",
38
- "@orieljs/support": "0.1.0-alpha.6",
39
- "@orieljs/container": "0.1.0-alpha.6"
38
+ "@orieljs/contracts": "0.1.0-alpha.7",
39
+ "@orieljs/container": "0.1.0-alpha.7",
40
+ "@orieljs/support": "0.1.0-alpha.7"
40
41
  },
41
42
  "scripts": {
42
43
  "build": "tsup && node ../../../scripts/copy-license.mjs"