@jay-framework/runtime 0.5.0
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/dist/index.d.ts +481 -0
- package/dist/index.js +836 -0
- package/docs/context.md +85 -0
- package/docs/jay-element.md +81 -0
- package/docs/kindergarten.md +51 -0
- package/docs/refs.md +200 -0
- package/docs/runtime.md +310 -0
- package/package.json +43 -0
- package/readme.md +113 -0
package/docs/context.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Context API Implementation
|
|
2
|
+
|
|
3
|
+
These functions provide a mechanism for managing and sharing context within a hierarchical structure,
|
|
4
|
+
used with `JayElement`s.
|
|
5
|
+
|
|
6
|
+
> The functions are intended to be an internal API for `@jay-framework/runtime` and `@jay-framework/component`.
|
|
7
|
+
> The `@jay-framework/component` library defines the public Jay context API in [provide-context.md](../../component/docs/provide-context.md)
|
|
8
|
+
> and [provide-reactive-context.md](../../component/docs/provide-reactive-context.md).
|
|
9
|
+
|
|
10
|
+
## `createJayContext`
|
|
11
|
+
|
|
12
|
+
Creates a unique symbol (a `ContextMarker`) to identify a specific context type.
|
|
13
|
+
|
|
14
|
+
### Returns:
|
|
15
|
+
|
|
16
|
+
A `ContextMarker` symbol.
|
|
17
|
+
|
|
18
|
+
## `withContext`
|
|
19
|
+
|
|
20
|
+
Temporarily establishes a new context for a given block of code.
|
|
21
|
+
|
|
22
|
+
### Parameters:
|
|
23
|
+
|
|
24
|
+
- `marker`: The `ContextMarker` identifying the context type.
|
|
25
|
+
- `context`: The actual context value to be provided. \* `callback`: The function to execute within the new context.
|
|
26
|
+
|
|
27
|
+
### Returns:
|
|
28
|
+
|
|
29
|
+
The return value of the `callback` function.
|
|
30
|
+
|
|
31
|
+
## `useContext`
|
|
32
|
+
|
|
33
|
+
Retrieves the current context value for a given `ContextMarker`.
|
|
34
|
+
|
|
35
|
+
### Parameters:
|
|
36
|
+
|
|
37
|
+
- `marker`: The `ContextMarker` identifying the context type.
|
|
38
|
+
|
|
39
|
+
### Returns:
|
|
40
|
+
|
|
41
|
+
The current context value.
|
|
42
|
+
|
|
43
|
+
## `findContext`
|
|
44
|
+
|
|
45
|
+
Searches the current context stack for a context matching the given predicate.
|
|
46
|
+
|
|
47
|
+
### Parameters:
|
|
48
|
+
|
|
49
|
+
- `predicate`: A function that takes a `ContextMarker` and returns a boolean indicating whether it's the desired context.
|
|
50
|
+
|
|
51
|
+
### Returns:
|
|
52
|
+
|
|
53
|
+
The found context value, or `undefined` if not found.
|
|
54
|
+
|
|
55
|
+
## `saveContext`
|
|
56
|
+
|
|
57
|
+
Saves the current context stack for later restoration. The function is used internally by JayComponent update collection
|
|
58
|
+
to ensure passing the right context to newly created child components.
|
|
59
|
+
|
|
60
|
+
### Returns:
|
|
61
|
+
|
|
62
|
+
The saved context stack.
|
|
63
|
+
|
|
64
|
+
## # `restoreContext`
|
|
65
|
+
|
|
66
|
+
Restores a previously saved context stack. The function is used internally by JayComponent update collection
|
|
67
|
+
to ensure passing the right context to newly created child components.
|
|
68
|
+
|
|
69
|
+
### Parameters:
|
|
70
|
+
|
|
71
|
+
- `savedContext`: The saved context stack to restore.
|
|
72
|
+
- `callback`: The function to execute within the restored context.
|
|
73
|
+
|
|
74
|
+
### Returns:
|
|
75
|
+
|
|
76
|
+
The return value of the `callback` function.
|
|
77
|
+
|
|
78
|
+
# How it Works internally:
|
|
79
|
+
|
|
80
|
+
1. **Context Markers:** Unique symbols are created to identify different context types.
|
|
81
|
+
2. **Context Stack:** A stack-like data structure is used to manage the current context and its parent contexts.
|
|
82
|
+
3. **`withContext`:** Pushes a new context onto the stack, executes the callback, and then pops the context off the stack.
|
|
83
|
+
4. **`useContext`:** Searches the current context stack for the specified context marker and returns its associated value.
|
|
84
|
+
5. **`findContext`:** Searches the context stack for a context matching the given predicate.
|
|
85
|
+
6. **`saveContext` and `restoreContext`:** Allow for saving and restoring the current context stack, enabling complex context management scenarios.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Generated JayElement
|
|
2
|
+
|
|
3
|
+
> note: this is an "how it works doc"
|
|
4
|
+
|
|
5
|
+
The `@jay-framework/compiler` compiles `jay-html` into `JayElement<ViewState, Refs>` implementation code files, discussed here.
|
|
6
|
+
|
|
7
|
+
Taking the example from the [readme.md](../readme.md), the `jay-html` is
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<html>
|
|
11
|
+
<head>
|
|
12
|
+
<script type="application/yaml-jay">
|
|
13
|
+
data:
|
|
14
|
+
count: number
|
|
15
|
+
</script>
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<div>
|
|
19
|
+
<button ref="subtracter">-</button>
|
|
20
|
+
<span style="margin: 0 16px">{count}</span>
|
|
21
|
+
<button ref="adder-button">+</button>
|
|
22
|
+
</div>
|
|
23
|
+
</body>
|
|
24
|
+
</html>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
and the generated jay element is
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import {
|
|
31
|
+
JayElement,
|
|
32
|
+
element as e,
|
|
33
|
+
dynamicText as dt,
|
|
34
|
+
RenderElement,
|
|
35
|
+
ReferencesManager,
|
|
36
|
+
ConstructContext,
|
|
37
|
+
HTMLElementProxy,
|
|
38
|
+
RenderElementOptions,
|
|
39
|
+
} from '@jay-framework/runtime';
|
|
40
|
+
|
|
41
|
+
export interface CounterViewState {
|
|
42
|
+
count: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface CounterElementRefs {
|
|
46
|
+
subtracter: HTMLElementProxy<CounterViewState, HTMLButtonElement>;
|
|
47
|
+
adderButton: HTMLElementProxy<CounterViewState, HTMLButtonElement>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type CounterElement = JayElement<CounterViewState, CounterElementRefs>;
|
|
51
|
+
export type CounterElementRender = RenderElement<
|
|
52
|
+
CounterViewState,
|
|
53
|
+
CounterElementRefs,
|
|
54
|
+
CounterElement
|
|
55
|
+
>;
|
|
56
|
+
export type CounterElementPreRender = [CounterElementRefs, CounterElementRender];
|
|
57
|
+
|
|
58
|
+
export function render(options?: RenderElementOptions): CounterElementPreRender {
|
|
59
|
+
const [refManager, [refSubtracter, refAdderButton]] = ReferencesManager.for(
|
|
60
|
+
options,
|
|
61
|
+
['subtracter', 'adderButton'],
|
|
62
|
+
[],
|
|
63
|
+
[],
|
|
64
|
+
[],
|
|
65
|
+
);
|
|
66
|
+
const render = (viewState: CounterViewState) =>
|
|
67
|
+
ConstructContext.withRootContext(viewState, refManager, () =>
|
|
68
|
+
e('div', {}, [
|
|
69
|
+
e('button', {}, ['-'], refSubtracter()),
|
|
70
|
+
e('span', { style: { cssText: 'margin: 0 16px' } }, [dt((vs) => vs.count)]),
|
|
71
|
+
e('button', {}, ['+'], refAdderButton()),
|
|
72
|
+
]),
|
|
73
|
+
) as CounterElement;
|
|
74
|
+
return [refManager.getPublicAPI() as CounterElementRefs, render];
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The generated file can use any of set of jay element creation functions - `element`, `dynamicElement`, `dynamicText`,
|
|
79
|
+
`dynamicAttribute`, `dynamicProperty`, `childComp`, `forEach`, `conditional`.
|
|
80
|
+
|
|
81
|
+
- See the [Runtime Implementation](./runtime.md) for the details of the jay-element constructor functions.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# The kindergarten
|
|
2
|
+
|
|
3
|
+
The kindergarten is a software library that manages the children of an HTML node.
|
|
4
|
+
It provides a high level abstraction over the APIs of the HTML node itself,
|
|
5
|
+
key to manage different groups of children, each group with a different logic.
|
|
6
|
+
|
|
7
|
+
Consider a node who has one conditional child, another set of children bound to an array
|
|
8
|
+
and a 3rd conditional child. The logic of binding the elements of the array to the nodes
|
|
9
|
+
needs to use the node indexes, which are dependent on the first conditional node.
|
|
10
|
+
The second conditional node depends on the first and the array.
|
|
11
|
+
|
|
12
|
+
The kindergarten manages this logic for us. It models the above as
|
|
13
|
+
|
|
14
|
+
| group | nodes | group offset |
|
|
15
|
+
| ----- | ----------------------------------------------- | ----------------------------------------- |
|
|
16
|
+
| 1 | zero or one element, depending on the condition | 0 |
|
|
17
|
+
| 2 | zero to N elements, depending on the array | #(group 1 elements) |
|
|
18
|
+
| 3 | zero or one element, depending on the condition | #(group 1 elements) + #(group 2 elements) |
|
|
19
|
+
|
|
20
|
+
The kindergarten API is
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
declare class Kindergarten {
|
|
24
|
+
readonly parentNode: HTMLElement;
|
|
25
|
+
constructor(parentNode: HTMLElement);
|
|
26
|
+
newGroup(): KindergartenGroup;
|
|
27
|
+
getOffsetFor(group: KindergartenGroup): number;
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
which allows to create groups and get the index offset of a group.
|
|
32
|
+
|
|
33
|
+
The KindergartenGroup API is
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
declare class KindergartenGroup {
|
|
37
|
+
children: Set<Node>;
|
|
38
|
+
constructor(kindergarten: Kindergarten);
|
|
39
|
+
addListener(groupListener: KindergardenGroupListener): void;
|
|
40
|
+
ensureNode(node: Node, atIndex?: number): void;
|
|
41
|
+
removeNode(node: Node): void;
|
|
42
|
+
removeNodeAt(pos: number): void;
|
|
43
|
+
moveNode(from: number, to: number): void;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- ensureNode - makes sure the provided node is at the provided index, relative to the group offset
|
|
48
|
+
- removeNode - removes the HTML node
|
|
49
|
+
- removeNodeAt - removes the node based on it's index relative to the group offset
|
|
50
|
+
- moveNode - moves the node from an index to an index, both relative to the group offset
|
|
51
|
+
- addListener - adds a listener to for the group mutations, to listen on adding and removing nodes from the group
|
package/docs/refs.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Refs
|
|
2
|
+
|
|
3
|
+
The `Refs` type is one of the generated types for a `jay-html`.
|
|
4
|
+
For each `ref` attribute in the `jay-html`, a member is created in the `refs` type.
|
|
5
|
+
|
|
6
|
+
## Examples of Refs Types
|
|
7
|
+
|
|
8
|
+
```typescript
|
|
9
|
+
export interface TodoElementRefs {
|
|
10
|
+
newTodo: HTMLElementProxy<TodoViewState, HTMLInputElement>;
|
|
11
|
+
toggleAll: HTMLElementProxy<TodoViewState, HTMLInputElement>;
|
|
12
|
+
items: ItemRefs<ShownTodo>;
|
|
13
|
+
filterAll: HTMLElementProxy<TodoViewState, HTMLAnchorElement>;
|
|
14
|
+
filterActive: HTMLElementProxy<TodoViewState, HTMLAnchorElement>;
|
|
15
|
+
filterCompleted: HTMLElementProxy<TodoViewState, HTMLAnchorElement>;
|
|
16
|
+
clearCompleted: HTMLElementProxy<TodoViewState, HTMLButtonElement>;
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Jay runtime includes 4 type of Refs - `HTMLElementProxy`, `HTMLElementCollectionProxy`,
|
|
21
|
+
`the component`, `ComponentCollectionProxy`. The first are used directly, while the latter are use indirectly via
|
|
22
|
+
a generated `component-refs.ts` file.
|
|
23
|
+
|
|
24
|
+
The generated `component-refs.ts` file, for example for the `items` property above is
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { EventEmitter, ComponentCollectionProxy, EventTypeFrom } from '@jay-framework/runtime';
|
|
28
|
+
import { Item } from './item';
|
|
29
|
+
|
|
30
|
+
export type ItemComponentType<ParentVS> = ReturnType<typeof Item<ParentVS>>;
|
|
31
|
+
|
|
32
|
+
export interface ItemRefs<ParentVS>
|
|
33
|
+
extends ComponentCollectionProxy<ParentVS, ItemComponentType<ParentVS>> {
|
|
34
|
+
onCompletedToggle: EventEmitter<
|
|
35
|
+
EventTypeFrom<ItemComponentType<ParentVS>['onCompletedToggle']>,
|
|
36
|
+
ParentVS
|
|
37
|
+
>;
|
|
38
|
+
onRemove: EventEmitter<EventTypeFrom<ItemComponentType<ParentVS>['onRemove']>, ParentVS>;
|
|
39
|
+
onTitleChanged: EventEmitter<
|
|
40
|
+
EventTypeFrom<ItemComponentType<ParentVS>['onTitleChanged']>,
|
|
41
|
+
ParentVS
|
|
42
|
+
>;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
And the component type is `ItemComponentType` while the `ComponentCollectionProxy` type is `ItemRefs`.
|
|
47
|
+
|
|
48
|
+
## JayEventHandler
|
|
49
|
+
|
|
50
|
+
The `refs` enable to listen on events from elements or components.
|
|
51
|
+
All Jay Events are using the `JayEventHandler` type
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
export type Coordinate = string[];
|
|
55
|
+
export interface JayEvent<EventType, ViewState> {
|
|
56
|
+
event: EventType;
|
|
57
|
+
viewState: ViewState;
|
|
58
|
+
coordinate: Coordinate;
|
|
59
|
+
}
|
|
60
|
+
export type JayEventHandler<EventType, ViewState, Returns> = (
|
|
61
|
+
event: JayEvent<EventType, ViewState>,
|
|
62
|
+
) => Returns;
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- `JayEventHandler`: the event callback function, called when an event is emitted.
|
|
66
|
+
- `event: JayEvent<EventType, ViewState>`: the parameter of the handler, holding all the event data and context
|
|
67
|
+
- `event.event: EventType`: the type of the event. For DOM elements, this is the native browser event
|
|
68
|
+
(if allowed by access security patterns). For components, this is the emitted component event.
|
|
69
|
+
- `event.viewState: ViewState`: the ViewState at the location of the element or component. Useful to get the context
|
|
70
|
+
of repeated items
|
|
71
|
+
- `coordinate: Coordinate`: an array of id's from nested `forEach` element structures, to get the logical location
|
|
72
|
+
of the element or component who triggered the event.
|
|
73
|
+
|
|
74
|
+
## HTMLElementProxy
|
|
75
|
+
|
|
76
|
+
The `HTMLElementProxy` is a proxy for a single dom element ref.
|
|
77
|
+
The `HTMLElementProxy` effective type (simplified view) is
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
interface HTMLElementProxy<ViewState, ElementType extends HTMLElement>
|
|
81
|
+
extends GlobalJayEvents<ViewState> {
|
|
82
|
+
addEventListener<E extends Event>(
|
|
83
|
+
type: string,
|
|
84
|
+
handler: JayEventHandler<E, ViewState, any>,
|
|
85
|
+
options?: boolean | AddEventListenerOptions,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
removeEventListener<E extends Event>(
|
|
89
|
+
type: string,
|
|
90
|
+
handler: JayEventHandler<E, ViewState, any>,
|
|
91
|
+
options?: EventListenerOptions | boolean,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
exec$<ResultType>(
|
|
95
|
+
handler: JayNativeFunction<ElementType, ViewState, ResultType>,
|
|
96
|
+
): Promise<ResultType>;
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
- `onclick`, `oninput`, `on...`: named event handlers to register new event handlers.
|
|
101
|
+
- `addEventListener`: registers a new event handlers.
|
|
102
|
+
- `removeEventListener`: registers a new event handlers.
|
|
103
|
+
- `exec$`: runs a code function against the DOM element. The function must match compiler patterns (see the compiler security section)
|
|
104
|
+
to be property run in secure applications. In non-secure applications, the function just runs with the DOM element.
|
|
105
|
+
|
|
106
|
+
## HTMLElementCollectionProxy
|
|
107
|
+
|
|
108
|
+
The `HTMLElementCollectionProxy` is a proxy for a collection of DOM elements with the same ref, normally
|
|
109
|
+
children of one or more `forEach` element creator functions or `jay-html` directives.
|
|
110
|
+
The `HTMLElementCollectionProxy` effective type (simplified view) is
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
interface HTMLElementCollectionProxy<ViewState, ElementType extends HTMLElement>
|
|
114
|
+
extends GlobalJayEvents<ViewState> {
|
|
115
|
+
addEventListener<E extends Event>(
|
|
116
|
+
type: string,
|
|
117
|
+
handler: JayEventHandler<E, ViewState, any>,
|
|
118
|
+
options?: boolean | AddEventListenerOptions,
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
removeEventListener<E extends Event>(
|
|
122
|
+
type: string,
|
|
123
|
+
handler: JayEventHandler<E, ViewState, any>,
|
|
124
|
+
options?: EventListenerOptions | boolean,
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
find(
|
|
128
|
+
predicate: (t: ViewState, c: Coordinate) => boolean,
|
|
129
|
+
): HTMLNativeExec<ViewState, ElementType> | undefined;
|
|
130
|
+
|
|
131
|
+
map<ResultType>(
|
|
132
|
+
handler: (
|
|
133
|
+
element: HTMLNativeExec<ViewState, ElementType>,
|
|
134
|
+
viewState: ViewState,
|
|
135
|
+
coordinate: Coordinate,
|
|
136
|
+
) => ResultType,
|
|
137
|
+
): Array<ResultType>;
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
- `onclick`, `oninput`, `on...`: named event handlers to register new event handlers for all the underlying elements.
|
|
142
|
+
- `addEventListener`: registers a new event handlers for all the referenced elements.
|
|
143
|
+
- `removeEventListener`: registers a new event handlers for all the referenced elements.
|
|
144
|
+
- `find`: finds the first DOM element who matches the predicate by the element view state or coordinate.
|
|
145
|
+
Once found, the element can be interacted with the `exec$` function of `HTMLElementProxy`.
|
|
146
|
+
- `map`: similar to an array map, this function runs for all the referenced DOM elements, given the
|
|
147
|
+
view state, coordinate and the element proxy with the `exec$` function of `HTMLElementProxy`.
|
|
148
|
+
|
|
149
|
+
> understanding nested ViewState and Coordinate:
|
|
150
|
+
> when using nested forEach structures, forEach mandates that each array element has an id property named by matchBy.
|
|
151
|
+
> the element of the array is the ViewState, and the coordinate holds the id's path.
|
|
152
|
+
> for a single forEach, the array item will be the view state, while the id of the item will be the coordinate.
|
|
153
|
+
> for nested forEach, the most nested array item will be the view state, while the id's of all parents will be the coordinate.
|
|
154
|
+
|
|
155
|
+
## The component
|
|
156
|
+
|
|
157
|
+
For a single component (not under `forEach`), the ref is just a proxy to the component directly and has the same interface
|
|
158
|
+
as the component.
|
|
159
|
+
|
|
160
|
+
**One important note - while the component constructor is running, the component ref is not initialized yet as the
|
|
161
|
+
component was not rendered yet. It is safe to set event handlers on the component, but calling the component APIs is only
|
|
162
|
+
supported on later times, such as event handlers or async code.**
|
|
163
|
+
|
|
164
|
+
## ComponentCollectionProxy
|
|
165
|
+
|
|
166
|
+
For a collection of components, components nested under `forEach`, Jay generates a type for each component based on
|
|
167
|
+
`ComponentCollectionProxy`, adding to it the component named event handlers.
|
|
168
|
+
|
|
169
|
+
The actual refs type is then `ComponentRefs` extending the `ComponentCollectionProxy` type
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
interface ComponentRefs<ParentVS>
|
|
173
|
+
extends ComponentCollectionProxy<ParentVS, ComponentType<ParentVS>> {}
|
|
174
|
+
|
|
175
|
+
interface ComponentCollectionProxy<ViewState, ComponentType extends JayComponent<any, any, any>> {
|
|
176
|
+
addEventListener(
|
|
177
|
+
type: string,
|
|
178
|
+
handler: JayEventHandler<any, ViewState, void>,
|
|
179
|
+
options?: boolean | AddEventListenerOptions,
|
|
180
|
+
): void;
|
|
181
|
+
removeEventListener(
|
|
182
|
+
type: string,
|
|
183
|
+
handler: JayEventHandler<any, ViewState, void>,
|
|
184
|
+
options?: EventListenerOptions | boolean,
|
|
185
|
+
): void;
|
|
186
|
+
|
|
187
|
+
map<ResultType>(
|
|
188
|
+
handler: (comp: ComponentType, viewState: ViewState, coordinate: Coordinate) => ResultType,
|
|
189
|
+
): Array<ResultType>;
|
|
190
|
+
find(predicate: (t: ViewState) => boolean): ComponentType | undefined;
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
- `named event handlers`: The named event handlers of the component
|
|
195
|
+
- `addEventListener`: registers a new event handlers for all the referenced components.
|
|
196
|
+
- `removeEventListener`: registers a new event handlers for all the referenced components.
|
|
197
|
+
- `find`: finds the first component who matches the predicate by the component view state or coordinate.
|
|
198
|
+
Once found, the component can be interacted with directly.
|
|
199
|
+
- `map`: similar to an array map, this function runs for all the referenced components , given the
|
|
200
|
+
view state, coordinate and the component.
|