@gramlot/gramlot-examples 0.2.10 → 0.2.12
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 +4 -3
- package/package.json +3 -3
- package/src/gramlot_examples/catalog.json +42 -3
- package/src/gramlot_examples/gallery/dist/frame.js +1473 -5
- package/src/gramlot_examples/gallery/dist/gallery.js +3822 -17162
- package/src/gramlot_examples/gallery/dist/notices.json +2 -22
- package/src/gramlot_examples/gallery/dist/theme-styles.js +2 -0
- package/src/gramlot_examples/gallery/gallery-page.js +38 -67
- package/src/gramlot_examples/gallery/gallery.css +22 -94
- package/src/gramlot_examples/index.js +2 -1
- package/src/gramlot_examples/pages/README.md +87 -4
- package/src/gramlot_examples/pages/binding/01_pointers.js +9 -0
- package/src/gramlot_examples/pages/binding/01_pointers.md +56 -9
- package/src/gramlot_examples/pages/binding/02_variable_datapath.md +50 -4
- package/src/gramlot_examples/pages/binding/03_setters_and_defaults.md +45 -6
- package/src/gramlot_examples/pages/binding/04_native_editing.md +48 -6
- package/src/gramlot_examples/pages/binding/05_checkbox_radio.md +44 -4
- package/src/gramlot_examples/pages/binding/06_style_and_visibility.md +40 -6
- package/src/gramlot_examples/pages/binding/07_bound_svg.md +48 -3
- package/src/gramlot_examples/pages/binding/08_freeze.js +1 -1
- package/src/gramlot_examples/pages/binding/08_freeze.md +44 -6
- package/src/gramlot_examples/pages/binding/09_forms.js +2 -1
- package/src/gramlot_examples/pages/binding/09_forms.md +53 -7
- package/src/gramlot_examples/pages/binding/10_svg_shapes.md +50 -5
- package/src/gramlot_examples/pages/binding/11_complete_page.md +53 -7
- package/src/gramlot_examples/pages/binding/README.md +34 -0
- package/src/gramlot_examples/pages/controllers/01_formula.md +48 -7
- package/src/gramlot_examples/pages/controllers/02_controller.js +24 -2
- package/src/gramlot_examples/pages/controllers/02_controller.md +61 -6
- package/src/gramlot_examples/pages/controllers/03_named_logic.md +63 -7
- package/src/gramlot_examples/pages/controllers/04_inline_expressions.md +50 -7
- package/src/gramlot_examples/pages/controllers/05_node_methods.md +41 -7
- package/src/gramlot_examples/pages/controllers/06_button_controller.md +49 -6
- package/src/gramlot_examples/pages/controllers/07_events.md +45 -6
- package/src/gramlot_examples/pages/controllers/08_end_to_end.js +26 -1
- package/src/gramlot_examples/pages/controllers/08_end_to_end.md +138 -9
- package/src/gramlot_examples/pages/controllers/09_endpoint.md +47 -7
- package/src/gramlot_examples/pages/controllers/10_call_on_change.md +48 -8
- package/src/gramlot_examples/pages/controllers/11_call_on_click.js +6 -0
- package/src/gramlot_examples/pages/controllers/11_call_on_click.md +58 -6
- package/src/gramlot_examples/pages/controllers/12_remote.js +33 -0
- package/src/gramlot_examples/pages/controllers/12_remote.md +60 -0
- package/src/gramlot_examples/pages/controllers/13_cached_remote.js +44 -0
- package/src/gramlot_examples/pages/controllers/13_cached_remote.md +67 -0
- package/src/gramlot_examples/pages/controllers/14_data_remote.js +39 -0
- package/src/gramlot_examples/pages/controllers/14_data_remote.md +69 -0
- package/src/gramlot_examples/pages/controllers/15_lifecycle.js +51 -0
- package/src/gramlot_examples/pages/controllers/15_lifecycle.md +59 -0
- package/src/gramlot_examples/pages/controllers/16_attribute_projection.js +25 -0
- package/src/gramlot_examples/pages/controllers/16_attribute_projection.md +58 -0
- package/src/gramlot_examples/pages/controllers/17_data_exchange.js +51 -0
- package/src/gramlot_examples/pages/controllers/17_data_exchange.md +61 -0
- package/src/gramlot_examples/pages/controllers/README.md +57 -3
- package/src/gramlot_examples/pages/html_svg/01_hello_world.md +48 -4
- package/src/gramlot_examples/pages/html_svg/02_text_and_links.md +42 -4
- package/src/gramlot_examples/pages/html_svg/03_lists.md +45 -4
- package/src/gramlot_examples/pages/html_svg/04_semantic_page.md +44 -4
- package/src/gramlot_examples/pages/html_svg/05_tables.md +46 -4
- package/src/gramlot_examples/pages/html_svg/06_forms.md +48 -4
- package/src/gramlot_examples/pages/html_svg/07_native_disclosure.md +41 -4
- package/src/gramlot_examples/pages/html_svg/08_svg_shapes.md +45 -4
- package/src/gramlot_examples/pages/html_svg/09_svg_composition.md +44 -4
- package/src/gramlot_examples/pages/html_svg/10_cards_with_icons.md +42 -15
- package/src/gramlot_examples/pages/html_svg/11_static_report.md +37 -4
- package/src/gramlot_examples/pages/html_svg/12_complete_page.md +41 -4
- package/src/gramlot_examples/pages/html_svg/13_live_source.md +47 -16
- package/src/gramlot_examples/pages/html_svg/README.md +36 -0
|
@@ -1,9 +1,55 @@
|
|
|
1
1
|
# 02 · Variable datapath
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
One card can show different records. Change its Data context and watch all its fields switch together: you learn how a variable `datapath` avoids rebuilding the card.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Uses:** Source, Data, pointers and native binding — core 0.2.0. No endpoint calls.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<details>
|
|
8
|
+
<summary>More detail</summary>
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
**Release stage:** Data binding and browser behavior (core 0.2.0).
|
|
12
|
+
|
|
13
|
+
**Goal:** Retarget a whole card by changing its Data context.
|
|
14
|
+
|
|
15
|
+
**Before this lesson:** [b01 · Pointers](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/01_pointers.md), [b04 · Native editing](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/04_native_editing.md). These prerequisites support the release sequence; later comparisons are explicitly labelled below.
|
|
16
|
+
|
|
17
|
+
**Open and edit:** select **b02 · Variable datapath** in your environment’s gallery. For source changes, copy/edit the matching page in your own project using the [setup guide](https://github.com/gramlot-org/gramlot/blob/main/docs/public/025-try.md); the gallery is a source viewer. Save, then reload/reopen as that guide explains. The snippets below are excerpts/edits within that Page, not standalone launch commands.
|
|
18
|
+
|
|
19
|
+
## Read the page
|
|
20
|
+
|
|
21
|
+
The select stores a **path string**, such as `people.alan`, in `current`. The card’s `datapath="^current"` follows that choice; all `.name`, `.field` and `.born` references resolve within the selected record.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
card = pane.article(datapath="^current", class_="card stack")
|
|
25
|
+
card.h2("^.name", id="name")
|
|
26
|
+
card.input(value="^.name", id="name-field")
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The dictionary becomes a nested Data Bag through `dataSetter`.
|
|
30
|
+
|
|
31
|
+
Python builds Source on the server; its JavaScript counterpart builds it on Node/Bun or in a standalone Worker. Bindings, actions and any Logic execute in the browser; Python strings containing JavaScript are not executed by Python.
|
|
32
|
+
|
|
33
|
+
## Try it and predict the result
|
|
34
|
+
|
|
35
|
+
1. Start with Ada Lovelace, Mathematics, 1815.
|
|
36
|
+
2. Choose Alan, edit his name to “A. M. Turing”, and leave the field.
|
|
37
|
+
3. Choose Grace, then Alan again: his edited name remains; Grace’s record is unchanged.
|
|
38
|
+
|
|
39
|
+
## Change it and check yourself
|
|
40
|
+
|
|
41
|
+
Add another person to `PEOPLE` with `name`, `field` and `born`; reload and choose them.
|
|
42
|
+
|
|
43
|
+
**Answer:** the existing select loop adds an option and the same card shows the new record. No separate handlers are needed for the three displays or edit field.
|
|
44
|
+
|
|
45
|
+
## The same example across stages
|
|
46
|
+
|
|
47
|
+
Compared with b01’s fixed context, one variable `datapath` retargets the same declarations together. In the later 0.2.16 c13 lesson this very technique selects a product while remote rules depend only on its category.
|
|
48
|
+
|
|
49
|
+
## Limits and next step
|
|
50
|
+
|
|
51
|
+
The selected value must be a Data path, not a record object. Reload reconstructs the initial records; local edits are not persistence. Empty/null contexts are an advanced reference case, not a new record editor.
|
|
52
|
+
|
|
53
|
+
Continue with [b03 · Setters and defaults](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/03_setters_and_defaults.md). The [authoring reference](https://github.com/gramlot-org/gramlot/blob/main/docs/public/095-writing-pages.md) explains the full contract.
|
|
54
|
+
|
|
55
|
+
</details>
|
|
@@ -1,10 +1,49 @@
|
|
|
1
1
|
# 03 · Setters and defaults
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Fields start with values supplied by setters and defaults. You learn when those values are applied and why an existing zero differs from a missing value.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- A dictionary (Python) or a plain object (JavaScript) becomes a Bag: `.shipping.city` reads inside it.
|
|
7
|
-
- A control fills an empty value path with its `default`. `default_value` wins over `default`. Only a null or missing value is empty: `0`, `false` and `''` are values.
|
|
8
|
-
- `attr_currency='EUR'` sets the attribute `currency` on the Data node of the control's value, after the defaults. `^.price?currency` reads it.
|
|
5
|
+
**Uses:** Source, Data, pointers and native binding — core 0.2.0. No endpoint calls.
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
<details>
|
|
8
|
+
<summary>More detail</summary>
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
**Release stage:** Data binding and browser behavior (core 0.2.0).
|
|
12
|
+
|
|
13
|
+
**Goal:** Predict initialization order and distinguish an absent value from zero.
|
|
14
|
+
|
|
15
|
+
**Before this lesson:** [b01 · Pointers](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/01_pointers.md). These prerequisites support the release sequence; later comparisons are explicitly labelled below.
|
|
16
|
+
|
|
17
|
+
**Open and edit:** select **b03 · Setters and defaults** in your environment’s gallery. For source changes, copy/edit the matching page in your own project using the [setup guide](https://github.com/gramlot-org/gramlot/blob/main/docs/public/025-try.md); the gallery is a source viewer. Save, then reload/reopen as that guide explains. The snippets below are excerpts/edits within that Page, not standalone launch commands.
|
|
18
|
+
|
|
19
|
+
## Read the page
|
|
20
|
+
|
|
21
|
+
Setters run before first render, parents before descendants in Source order. The later `.customer` setter wins, so the first display is Grace Hopper. The nested shipping dictionary supplies London.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
form.input(type="number", value="^.quantity", default=1, id="quantity")
|
|
25
|
+
form.input(value="^.note", default_value="No note", default="Never used", id="note")
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`default_value` wins over `default`; defaults fill null/missing paths, not `0`, `False` or `""`. `attr_currency="EUR"` sets metadata on the price Data node; `^.price?currency` reads it.
|
|
29
|
+
|
|
30
|
+
Python builds Source on the server; its JavaScript counterpart builds it on Node/Bun or in a standalone Worker. Bindings, actions and any Logic execute in the browser; Python strings containing JavaScript are not executed by Python.
|
|
31
|
+
|
|
32
|
+
## Try it and predict the result
|
|
33
|
+
|
|
34
|
+
1. Before editing, predict Customer = Grace Hopper, Quantity = 1, Note = No note, Price = 12.5, Currency = EUR and City = London.
|
|
35
|
+
2. Find the later setter below the form: visual position does not delay initialization.
|
|
36
|
+
|
|
37
|
+
## Change it and check yourself
|
|
38
|
+
|
|
39
|
+
Remove only the later `.customer` setter and add `pane.dataSetter(".quantity", 0)`.
|
|
40
|
+
|
|
41
|
+
**Answer:** after reload Customer is Ada Lovelace and Quantity is 0. The earlier customer setter now wins; the quantity default cannot overwrite a real zero.
|
|
42
|
+
|
|
43
|
+
## Limits and next step
|
|
44
|
+
|
|
45
|
+
These are build-time defaults, not record/new-record defaults or automatic refill whenever a user clears a control. Destination paths are bare Data paths, not `^` pointers or `?attr` destinations.
|
|
46
|
+
|
|
47
|
+
Continue with [b04 · Native editing](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/04_native_editing.md). The [authoring reference](https://github.com/gramlot-org/gramlot/blob/main/docs/public/095-writing-pages.md) explains the full contract.
|
|
48
|
+
|
|
49
|
+
</details>
|
|
@@ -1,11 +1,53 @@
|
|
|
1
1
|
# 04 · Native editing
|
|
2
2
|
|
|
3
|
-
A control
|
|
3
|
+
A form displays the Data written by each control. Switch **live** on and off: you learn when typing updates Data and whether each control writes text, a number or a list.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- A single select writes the chosen value; a multiple select writes a list.
|
|
7
|
-
- With `live` false a field writes at `change`, when you leave it or press Enter. With `live` true text, textarea, number and range write at every `input`. Here `live='^.live'` follows the checkbox, without rebuilding the fields.
|
|
5
|
+
**Uses:** Source, Data, pointers and native binding — core 0.2.0. No endpoint calls.
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
<details>
|
|
8
|
+
<summary>More detail</summary>
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
**Release stage:** Data binding and browser behavior (core 0.2.0).
|
|
12
|
+
|
|
13
|
+
**Goal:** Observe when a control writes Data and which type it writes.
|
|
14
|
+
|
|
15
|
+
**Before this lesson:** [e06 · Forms](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/html_svg/06_forms.md), [b01 · Pointers](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/01_pointers.md). These prerequisites support the release sequence; later comparisons are explicitly labelled below.
|
|
16
|
+
|
|
17
|
+
**Open and edit:** select **b04 · Native editing** in your environment’s gallery. For source changes, copy/edit the matching page in your own project using the [setup guide](https://github.com/gramlot-org/gramlot/blob/main/docs/public/025-try.md); the gallery is a source viewer. Save, then reload/reopen as that guide explains. The snippets below are excerpts/edits within that Page, not standalone launch commands.
|
|
18
|
+
|
|
19
|
+
## Read the page
|
|
20
|
+
|
|
21
|
+
Text and textarea write strings; number/range write numbers or null for an empty value; dates keep their string representation. Single select writes one value, multiple select a list. The checkbox controls `live` for the other fields.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
form.input(type=kind, value=f"^.{key}", live="^.live", id=key)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The right-hand values read those same paths. There is no application input-scraping handler.
|
|
28
|
+
|
|
29
|
+
Python builds Source on the server; its JavaScript counterpart builds it on Node/Bun or in a standalone Worker. Bindings, actions and any Logic execute in the browser; Python strings containing JavaScript are not executed by Python.
|
|
30
|
+
|
|
31
|
+
## Try it and predict the result
|
|
32
|
+
|
|
33
|
+
1. With live unchecked, type in Text without leaving it: the Data display stays “Edit me”. Leave the field: it updates.
|
|
34
|
+
2. Check live and type again: the display follows each input event.
|
|
35
|
+
3. Choose size L and change Topics: the Data stores a value and a list respectively.
|
|
36
|
+
|
|
37
|
+
## Change it and check yourself
|
|
38
|
+
|
|
39
|
+
Clear Number while live is on, then enter 7.
|
|
40
|
+
|
|
41
|
+
**Answer:** the empty control writes null (its display is empty), then numeric 7. It does not write the strings `"null"` or `"7"`. A date is still a date string; editing does not make it a Python datetime.
|
|
42
|
+
|
|
43
|
+
## The same example across stages
|
|
44
|
+
|
|
45
|
+
In e06 the browser edits native control values only. Here `value="^.text"` plus a Data setter replaces the literal default and connects editing to application state. The mirrored display needs only another pointer; no per-control copying routine is introduced.
|
|
46
|
+
|
|
47
|
+
## Limits and next step
|
|
48
|
+
|
|
49
|
+
Use `change`/leaving the field for the non-live trial; do not rely on Enter having identical behavior in every native control. Browser validation and picker presentation vary.
|
|
50
|
+
|
|
51
|
+
Continue with [b05 · Checkbox and radio](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/05_checkbox_radio.md). The [authoring reference](https://github.com/gramlot-org/gramlot/blob/main/docs/public/095-writing-pages.md) explains the full contract.
|
|
52
|
+
|
|
53
|
+
</details>
|
|
@@ -1,9 +1,49 @@
|
|
|
1
1
|
# 05 · Checkbox and radio
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Checkboxes and radio buttons control boolean values. You learn how to represent yes/no choices and how radio buttons keep a single choice selected.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Uses:** Source, Data, pointers and native binding — core 0.2.0. No endpoint calls.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<details>
|
|
8
|
+
<summary>More detail</summary>
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
**Release stage:** Data binding and browser behavior (core 0.2.0).
|
|
12
|
+
|
|
13
|
+
**Goal:** Model checkboxes and a radio group as boolean Data.
|
|
14
|
+
|
|
15
|
+
**Before this lesson:** [b04 · Native editing](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/04_native_editing.md). These prerequisites support the release sequence; later comparisons are explicitly labelled below.
|
|
16
|
+
|
|
17
|
+
**Open and edit:** select **b05 · Checkbox and radio** in your environment’s gallery. For source changes, copy/edit the matching page in your own project using the [setup guide](https://github.com/gramlot-org/gramlot/blob/main/docs/public/025-try.md); the gallery is a source viewer. Save, then reload/reopen as that guide explains. The snippets below are excerpts/edits within that Page, not standalone launch commands.
|
|
18
|
+
|
|
19
|
+
## Read the page
|
|
20
|
+
|
|
21
|
+
A checkbox’s bound `value` is boolean. Each radio has a separate boolean path; `group="plan"` makes them mutually exclusive. The runtime supplies the DOM group name.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
row.input(type="radio", group="plan", value=f"^.plan.{key}", id=key)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Only `.plan.plus` starts true. Basic and Team begin null; selecting one writes it true and writes the previously selected path false.
|
|
28
|
+
|
|
29
|
+
Python builds Source on the server; its JavaScript counterpart builds it on Node/Bun or in a standalone Worker. Bindings, actions and any Logic execute in the browser; Python strings containing JavaScript are not executed by Python.
|
|
30
|
+
|
|
31
|
+
## Try it and predict the result
|
|
32
|
+
|
|
33
|
+
1. Newsletter is checked, Paper invoice is off and Plus is selected.
|
|
34
|
+
2. Choose Team: Plus becomes false, Team true, Basic remains empty.
|
|
35
|
+
3. Choose Basic: Basic becomes true, Team false, Plus stays false.
|
|
36
|
+
|
|
37
|
+
## Change it and check yourself
|
|
38
|
+
|
|
39
|
+
Add `("pro", "Pro")` to `PLANS` and include `plan.pro` in the displayed key list.
|
|
40
|
+
|
|
41
|
+
**Answer:** the new radio joins the same group. On selection it becomes true and the old selection becomes false. No manual loop clearing all radio paths is necessary.
|
|
42
|
+
|
|
43
|
+
## Limits and next step
|
|
44
|
+
|
|
45
|
+
A radio’s bound value is not a string enum. Unselected paths need not all have been written false. Use the existing `group` contract rather than assigning a shared native name manually.
|
|
46
|
+
|
|
47
|
+
Continue with [b06 · Style and visibility](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/06_style_and_visibility.md). The [authoring reference](https://github.com/gramlot-org/gramlot/blob/main/docs/public/095-writing-pages.md) explains the full contract.
|
|
48
|
+
|
|
49
|
+
</details>
|
|
@@ -1,11 +1,45 @@
|
|
|
1
1
|
# 06 · Style and visibility
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Controls change an element’s appearance and visibility. You learn how Data drives styles and classes, and how hiding content differs from removing its space in the layout.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- The style shortcuts `color`, `background_color`, `font_size`, `padding` and the macro `rounded` compose one `style` attribute with `style` itself. A shortcut wins over the same property written in `style`; a null shortcut drops only its own property.
|
|
7
|
-
- `visible` false sets `visibility: hidden`: the box disappears and keeps its space. `hidden` is the native attribute: the box leaves the layout.
|
|
5
|
+
**Uses:** Source, Data, pointers and native binding — core 0.2.0. No endpoint calls.
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
<details>
|
|
8
|
+
<summary>More detail</summary>
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
**Release stage:** Data binding and browser behavior (core 0.2.0).
|
|
12
|
+
|
|
13
|
+
**Goal:** Predict attribute precedence and distinguish visibility from layout removal.
|
|
14
|
+
|
|
15
|
+
**Before this lesson:** [b04 · Native editing](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/04_native_editing.md), [b05 · Checkbox and radio](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/05_checkbox_radio.md). These prerequisites support the release sequence; later comparisons are explicitly labelled below.
|
|
16
|
+
|
|
17
|
+
**Open and edit:** select **b06 · Style and visibility** in your environment’s gallery. For source changes, copy/edit the matching page in your own project using the [setup guide](https://github.com/gramlot-org/gramlot/blob/main/docs/public/025-try.md); the gallery is a source viewer. Save, then reload/reopen as that guide explains. The snippets below are excerpts/edits within that Page, not standalone launch commands.
|
|
18
|
+
|
|
19
|
+
## Read the page
|
|
20
|
+
|
|
21
|
+
The box binds class, style, color, background, size, radius and visibility to Data. Supported class/style values are strings or null. CSS shortcuts compose the style and take precedence over a duplicate property in `style`.
|
|
22
|
+
|
|
23
|
+
`visible=False` sets hidden visibility but retains space; native `hidden=True` removes the box from layout. Use CSS units such as `1.5rem` for font size.
|
|
24
|
+
|
|
25
|
+
Python builds Source on the server; its JavaScript counterpart builds it on Node/Bun or in a standalone Worker. Bindings, actions and any Logic execute in the browser; Python strings containing JavaScript are not executed by Python.
|
|
26
|
+
|
|
27
|
+
## Try it and predict the result
|
|
28
|
+
|
|
29
|
+
1. Expect a blue box, white text, dashed border, 1.5rem font and rounded corners.
|
|
30
|
+
2. Replace the style field with `color: red` and leave it: the color shortcut still makes the text white; replacing the style string also removes its old border declaration.
|
|
31
|
+
3. Uncheck visible: the space remains. Then check hidden: the space collapses.
|
|
32
|
+
|
|
33
|
+
## Change it and check yourself
|
|
34
|
+
|
|
35
|
+
Restore visible, clear hidden and choose 2rem with 24px corners.
|
|
36
|
+
|
|
37
|
+
**Answer:** the same box changes appearance from Data; its text and Source structure are unchanged. A null shortcut removes its own property, not every other style declaration.
|
|
38
|
+
|
|
39
|
+
## Limits and next step
|
|
40
|
+
|
|
41
|
+
Stay with the agreed string/null contract. The development review has a pending renderer-parity correction for rejection of unsupported class/style types; this lesson does not teach object coercions or rely on them.
|
|
42
|
+
|
|
43
|
+
Continue with [b07 · Bound SVG](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/07_bound_svg.md). The [authoring reference](https://github.com/gramlot-org/gramlot/blob/main/docs/public/095-writing-pages.md) explains the full contract.
|
|
44
|
+
|
|
45
|
+
</details>
|
|
@@ -1,7 +1,52 @@
|
|
|
1
1
|
# 07 · Bound SVG
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Controls and an SVG drawing share the same values. Change a value and watch the shape follow: binding works for SVG geometry as well as HTML text.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Uses:** Source, Data, pointers and native binding — core 0.2.0. No endpoint calls.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<details>
|
|
8
|
+
<summary>More detail</summary>
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
**Release stage:** Data binding and browser behavior (core 0.2.0).
|
|
12
|
+
|
|
13
|
+
**Goal:** Use the same Data value for a native control and SVG geometry.
|
|
14
|
+
|
|
15
|
+
**Before this lesson:** [e08 · SVG shapes](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/html_svg/08_svg_shapes.md), [b04 · Native editing](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/04_native_editing.md). These prerequisites support the release sequence; later comparisons are explicitly labelled below.
|
|
16
|
+
|
|
17
|
+
**Open and edit:** select **b07 · Bound SVG** in your environment’s gallery. For source changes, copy/edit the matching page in your own project using the [setup guide](https://github.com/gramlot-org/gramlot/blob/main/docs/public/025-try.md); the gallery is a source viewer. Save, then reload/reopen as that guide explains. The snippets below are excerpts/edits within that Page, not standalone launch commands.
|
|
18
|
+
|
|
19
|
+
## Read the page
|
|
20
|
+
|
|
21
|
+
The circle’s radius/fill and bar’s width/fill are pointers; their controls write the same paths. Radius and width ranges are live. SVG `fill` and `stroke` are presentation attributes, not HTML style shortcuts.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
controls.input(type="range", min=5, max=80, value="^.radius", live=True, id="radius")
|
|
25
|
+
art.circle(cx=100, cy=100, r="^.radius", fill="^.fill", id="circle")
|
|
26
|
+
art.text("^.radius", x=100, y=190, text_anchor="middle", fill="currentColor", id="radius-label")
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Python builds Source on the server; its JavaScript counterpart builds it on Node/Bun or in a standalone Worker. Bindings, actions and any Logic execute in the browser; Python strings containing JavaScript are not executed by Python.
|
|
30
|
+
|
|
31
|
+
## Try it and predict the result
|
|
32
|
+
|
|
33
|
+
1. The circle begins at radius 40; its numeric label also shows 40. The bar width is 160.
|
|
34
|
+
2. Drag Radius to 60: both circle and label follow, while the bar remains unchanged.
|
|
35
|
+
|
|
36
|
+
## Change it and check yourself
|
|
37
|
+
|
|
38
|
+
Add a range bound to `.cy` (min 40, max 160), initialize it with `pane.dataSetter(".cy", 100)`, and replace the circle’s `cy=100` with `cy="^.cy"`.
|
|
39
|
+
|
|
40
|
+
**Answer:** moving the new range moves the same circle vertically; radius remains controlled independently. There is no new Source lookup or attribute-setting action.
|
|
41
|
+
|
|
42
|
+
## The same example across stages
|
|
43
|
+
|
|
44
|
+
Earlier e13 explicitly called `setAttr` on a Source node for each animated coordinate. For user-controlled geometry here, one pointer replaces repeated update calls. The two lessons solve different triggers: this is a simplification of value synchronization, not an identical animation.
|
|
45
|
+
|
|
46
|
+
## Limits and next step
|
|
47
|
+
|
|
48
|
+
The range has to remain compatible with the viewBox; a large radius near an edge can be clipped. This lesson changes geometry, not SVG structure.
|
|
49
|
+
|
|
50
|
+
Continue with [b08 · Freeze](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/08_freeze.md). The [authoring reference](https://github.com/gramlot-org/gramlot/blob/main/docs/public/095-writing-pages.md) explains the full contract.
|
|
51
|
+
|
|
52
|
+
</details>
|
|
@@ -8,7 +8,7 @@ export class Page extends BasePage {
|
|
|
8
8
|
const pane = root.div({class: 'example-page stack', datapath: 'board'});
|
|
9
9
|
pane.h1('Freeze');
|
|
10
10
|
const actions = pane.div({class: 'actions'});
|
|
11
|
-
for (const [label, method] of [['Freeze', 'freeze'], ['
|
|
11
|
+
for (const [label, method] of [['Freeze', 'freeze'], ['Increment Data count', 'add'],
|
|
12
12
|
['Remove last item', 'removeLast'], ['Thaw', 'thaw']]) {
|
|
13
13
|
actions.button(label, {id: method}).dataController({func: method});
|
|
14
14
|
}
|
|
@@ -1,11 +1,49 @@
|
|
|
1
1
|
# 08 · Freeze
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Freeze a list, add or remove items, then thaw it. You learn that structural changes can wait while existing Data bindings keep working. Return here after **Named logic** and **Button controller**.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Uses:** Source freeze/thaw, Data binding and local controllers (0.2.0); shared Page/Logic module layout from 0.2.5.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- **Thaw** builds the branch once, with every removal applied.
|
|
7
|
+
<details>
|
|
8
|
+
<summary>More detail</summary>
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
**Release stage:** Data binding and browser behavior (core 0.2.0). The maintained Page/Logic module arrangement is from 0.2.5; it does not move the original behavior into a later release.
|
|
12
|
+
|
|
13
|
+
**Goal:** Observe immediate Data updates and deferred structural rendering separately.
|
|
14
|
+
|
|
15
|
+
**Before this lesson:** [e10 · Cards with icons](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/html_svg/10_cards_with_icons.md), [b01 · Pointers](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/01_pointers.md), [c03 · Named logic](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/controllers/03_named_logic.md), [c06 · Button controller](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/controllers/06_button_controller.md). These prerequisites support the release sequence; later comparisons are explicitly labelled below.
|
|
16
|
+
|
|
17
|
+
**Open and edit:** select **b08 · Freeze** in your environment’s gallery. For source changes, copy/edit the matching page in your own project using the [setup guide](https://github.com/gramlot-org/gramlot/blob/main/docs/public/025-try.md); the gallery is a source viewer. Save, then reload/reopen as that guide explains. The snippets below are excerpts/edits within that Page, not standalone launch commands.
|
|
18
|
+
|
|
19
|
+
## Read the page
|
|
20
|
+
|
|
21
|
+
The buttons call named `Logic` methods through nested `dataController` declarations. Freeze targets the `board` Source node. `add` increments `.count`; despite the method’s short name, it does **not** create a list item. `removeLast` deletes a Source child.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
actions.button(label, id=method).dataController(func=method)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Existing Data bindings continue while the branch is frozen. Source removal takes effect semantically at once; DOM rebuilding waits until unfreeze.
|
|
28
|
+
|
|
29
|
+
Python builds Source on the server; its JavaScript counterpart builds it on Node/Bun or in a standalone Worker. Bindings, actions and any Logic execute in the browser; Python strings containing JavaScript are not executed by Python. Read the gallery’s **logic.js** tab (the Logic class from `08_freeze.js`) beside the Python source.
|
|
30
|
+
|
|
31
|
+
## Try it and predict the result
|
|
32
|
+
|
|
33
|
+
1. Start with count 0, frozen false and three items. Click Freeze.
|
|
34
|
+
2. Click Increment Data count: count becomes 1 immediately. Remove last item twice: three items are still visible.
|
|
35
|
+
3. Click Thaw: only Item 1 remains; count is still 1 and frozen is false.
|
|
36
|
+
|
|
37
|
+
## Change it and check yourself
|
|
38
|
+
|
|
39
|
+
Reload, freeze, increment twice, remove once, then thaw.
|
|
40
|
+
|
|
41
|
+
**Answer:** count 2 is visible before thaw; two list items are visible after thaw. The Data counter is deliberately independent of list length, so it must not be used as an item count.
|
|
42
|
+
|
|
43
|
+
## Limits and next step
|
|
44
|
+
|
|
45
|
+
Freeze is not a transaction, a Data pause or a persistence mechanism. Removed nodes stop participating even while old DOM waits for thaw. Avoid adding arbitrary DOM operations to “force” the visual change.
|
|
46
|
+
|
|
47
|
+
Continue with [b09 · Forms with binding](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/09_forms.md). The [authoring reference](https://github.com/gramlot-org/gramlot/blob/main/docs/public/095-writing-pages.md) explains the full contract.
|
|
48
|
+
|
|
49
|
+
</details>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {Page as BasePage} from '@gramlot/gramlot/page';
|
|
2
2
|
|
|
3
3
|
const RECORD = {name: 'Ada Lovelace', quantity: 3, accent: '#456bc4', intensity: 60,
|
|
4
|
-
region: 'south',
|
|
4
|
+
region: 'south', note: 'A native multiline field.', updates: true};
|
|
5
5
|
const SHOWN = ['name', 'email', 'search', 'website', 'telephone', 'quantity', 'date', 'time', 'month',
|
|
6
6
|
'week', 'accent', 'intensity', 'region', 'topics', 'note', 'updates'];
|
|
7
7
|
|
|
@@ -69,6 +69,7 @@ export class Page extends BasePage {
|
|
|
69
69
|
facts.dd('^.frequency.weekly', {id: 'out-weekly'});
|
|
70
70
|
|
|
71
71
|
pane.dataSetter({destination_path: 'form', value: RECORD});
|
|
72
|
+
pane.dataSetter({destination_path: '.topics', value: ['html']});
|
|
72
73
|
pane.dataSetter({destination_path: '.frequency.weekly', value: true});
|
|
73
74
|
}
|
|
74
75
|
|
|
@@ -1,12 +1,58 @@
|
|
|
1
1
|
# 09 · Forms with binding
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The form from **Native forms** returns with its fields connected to one Data record. Edit a value and watch other views follow. You learn how binding replaces code that would otherwise copy values between controls and displays.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- Each field writes its own type: numbers for quantity and intensity, a list for the topics, booleans for the checkbox and the two radio buttons.
|
|
7
|
-
- The record on the right reads the same paths, so it changes while you edit. Intensity has `live` true and follows the slider.
|
|
8
|
-
- The password is bound but not shown, and the file field stays native: a file has no Data value.
|
|
5
|
+
**Uses:** Source, Data, pointers and native binding — core 0.2.0. No endpoint calls.
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
<details>
|
|
8
|
+
<summary>More detail</summary>
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
|
|
11
|
+
**Release stage:** Data binding and browser behavior (core 0.2.0).
|
|
12
|
+
|
|
13
|
+
**Goal:** Revisit the native form with one authoritative Data record.
|
|
14
|
+
|
|
15
|
+
**Before this lesson:** [e06 · Forms](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/html_svg/06_forms.md), [b03 · Setters and defaults](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/03_setters_and_defaults.md), [b04 · Native editing](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/04_native_editing.md), [b05 · Checkbox and radio](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/05_checkbox_radio.md). These prerequisites support the release sequence; later comparisons are explicitly labelled below.
|
|
16
|
+
|
|
17
|
+
**Open and edit:** select **b09 · Forms with binding** in your environment’s gallery. For source changes, copy/edit the matching page in your own project using the [setup guide](https://github.com/gramlot-org/gramlot/blob/main/docs/public/025-try.md); the gallery is a source viewer. Save, then reload/reopen as that guide explains. The snippets below are excerpts/edits within that Page, not standalone launch commands.
|
|
18
|
+
|
|
19
|
+
## Read the page
|
|
20
|
+
|
|
21
|
+
The fieldsets are inherited conceptually from e06. Most initial values now live in `RECORD`; `dataSetter("form", RECORD)` populates it. The multiple select needs a list: `dataSetter(".topics", ["html"])` sets it directly. Putting that list inside `RECORD` would convert it recursively into a Bag. Each control and each summary entry bind to the same relative path. Intensity is live; ordinary text fields update on change.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
parent.input(type=kind, id=key, name=key, value=f"^.{key}", **attrs)
|
|
25
|
+
record.h2("The Data record")
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Password is bound but deliberately absent from the summary; the file input stays native. Boolean radio paths use the `frequency` group.
|
|
29
|
+
|
|
30
|
+
Python builds Source on the server; its JavaScript counterpart builds it on Node/Bun or in a standalone Worker. Bindings, actions and any Logic execute in the browser; Python strings containing JavaScript are not executed by Python.
|
|
31
|
+
|
|
32
|
+
## Try it and predict the result
|
|
33
|
+
|
|
34
|
+
1. Compare initial Name, Quantity, Region and Topics with e06. They still describe Ada, 3, South and HTML.
|
|
35
|
+
2. Change Name and leave the field: the Data record shows the edit. Drag Intensity: its summary follows live.
|
|
36
|
+
3. Choose daily: weekly becomes false in Data.
|
|
37
|
+
|
|
38
|
+
## Change it and check yourself
|
|
39
|
+
|
|
40
|
+
Change `RECORD["quantity"]` from 3 to 5 and reload.
|
|
41
|
+
|
|
42
|
+
**Answer:** both Quantity and its summary begin at 5. You edit the initial record once; neither the input declaration nor its summary contains another copied numeric default.
|
|
43
|
+
|
|
44
|
+
## The same example across stages
|
|
45
|
+
|
|
46
|
+
**Earlier, e06:** the field call supplies `value="Ada Lovelace"`; checkbox/option declarations carry `checked`/`selected` flags.
|
|
47
|
+
|
|
48
|
+
**Later, 0.2.0:** the shared field helper supplies `value=f"^.{key}"`; defaults move to `RECORD`. A select supplies `value="^.region"` and its options no longer choose the selection individually.
|
|
49
|
+
|
|
50
|
+
The same initial information is declared centrally and reflected in multiple places. This removes duplicated state/update responsibility; it does not claim fewer total lines after adding the summary and interaction.
|
|
51
|
+
|
|
52
|
+
## Limits and next step
|
|
53
|
+
|
|
54
|
+
No native Reset is offered: native reset does not emit the input/change events needed to synchronize Data. Submit remains disabled. File selection has no bound Data value or upload; this is not a record/form persistence framework.
|
|
55
|
+
|
|
56
|
+
Continue with [b10 · SVG shapes with binding](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/10_svg_shapes.md). The [authoring reference](https://github.com/gramlot-org/gramlot/blob/main/docs/public/095-writing-pages.md) explains the full contract.
|
|
57
|
+
|
|
58
|
+
</details>
|
|
@@ -1,9 +1,54 @@
|
|
|
1
1
|
# 10 · SVG shapes with binding
|
|
2
2
|
|
|
3
|
-
The SVG
|
|
3
|
+
The six shapes from **SVG shapes** now have editable dimensions and stroke settings. You learn how pointers connect controls to the drawing without a separate update routine for each shape.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- The color field paints the triangle; the text field rewrites the label.
|
|
7
|
-
- Every control has `live` true, so the drawing follows while you drag or type.
|
|
5
|
+
**Uses:** Source, Data, pointers and native binding — core 0.2.0. No endpoint calls.
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
<details>
|
|
8
|
+
<summary>More detail</summary>
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
**Release stage:** Data binding and browser behavior (core 0.2.0).
|
|
12
|
+
|
|
13
|
+
**Goal:** Revisit the six-shape SVG with bound dimensions and shared stroke state.
|
|
14
|
+
|
|
15
|
+
**Before this lesson:** [e08 · SVG shapes](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/html_svg/08_svg_shapes.md), [b04 · Native editing](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/04_native_editing.md), [b07 · Bound SVG](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/07_bound_svg.md). These prerequisites support the release sequence; later comparisons are explicitly labelled below.
|
|
16
|
+
|
|
17
|
+
**Open and edit:** select **b10 · SVG shapes with binding** in your environment’s gallery. For source changes, copy/edit the matching page in your own project using the [setup guide](https://github.com/gramlot-org/gramlot/blob/main/docs/public/025-try.md); the gallery is a source viewer. Save, then reload/reopen as that guide explains. The snippets below are excerpts/edits within that Page, not standalone launch commands.
|
|
18
|
+
|
|
19
|
+
## Read the page
|
|
20
|
+
|
|
21
|
+
The six shapes retain their positions. Width, radius, ellipse height, shared stroke, triangle color and caption now read Data. The ranges and caption text use `live=True`; the color field uses its native change behavior.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
art.circle(cx=172, cy=58, r="^.radius", fill="var(--gramlot-warning)", id="circle")
|
|
25
|
+
pane.dataSetter(".radius", 38)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Line and polyline both read `.stroke`. Their initial shared width is 7; e08 originally used 8 for the line and 7 for the polyline, so this is an explicit small visual change, not exact pixel identity.
|
|
29
|
+
|
|
30
|
+
Python builds Source on the server; its JavaScript counterpart builds it on Node/Bun or in a standalone Worker. Bindings, actions and any Logic execute in the browser; Python strings containing JavaScript are not executed by Python.
|
|
31
|
+
|
|
32
|
+
## Try it and predict the result
|
|
33
|
+
|
|
34
|
+
1. Begin with rectangle width 95, radius 38 and ellipse height 38.
|
|
35
|
+
2. Move Stroke width to 10: both line and polyline change together.
|
|
36
|
+
3. Type a new Label: the SVG caption follows each keystroke; changing Triangle color changes only the polygon.
|
|
37
|
+
|
|
38
|
+
## Change it and check yourself
|
|
39
|
+
|
|
40
|
+
Add a range for `.cx`, initialize it to 172, and replace only the circle’s `cx=172` with `cx="^.cx"`.
|
|
41
|
+
|
|
42
|
+
**Answer:** the control moves that circle without moving the ellipse or rectangle. No code for finding/updating the circle in DOM is needed.
|
|
43
|
+
|
|
44
|
+
## The same example across stages
|
|
45
|
+
|
|
46
|
+
Compare e08’s `r=38` with this page’s `r="^.radius"` and one setter. Static structure stays; the range and circle now share Data. For stroke, one `.stroke` replaces two independently authored widths. The additional controls add code, while the binding removes the need to author separate synchronization behavior.
|
|
47
|
+
|
|
48
|
+
## Limits and next step
|
|
49
|
+
|
|
50
|
+
Not every control is live: the color field uses change. SVG presentation values retain their own types/units. This is a maintained current-API comparison, not an old-package installation exercise.
|
|
51
|
+
|
|
52
|
+
Continue with [b11 · Complete page with binding](https://github.com/gramlot-org/gramlot-examples/blob/main/src/gramlot_examples/pages/binding/11_complete_page.md). The [authoring reference](https://github.com/gramlot-org/gramlot/blob/main/docs/public/095-writing-pages.md) explains the full contract.
|
|
53
|
+
|
|
54
|
+
</details>
|