@gramlot/gramlot-examples 0.3.6 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ npm install @gramlot/gramlot-examples
|
|
|
12
12
|
[](https://pypi.org/project/gramlot-examples/)
|
|
13
13
|
[](https://www.npmjs.com/package/@gramlot/gramlot-examples)
|
|
14
14
|
|
|
15
|
-
Current release: 0.3.
|
|
15
|
+
Current release: 0.3.8.
|
|
16
16
|
|
|
17
17
|
[Documentation and learning sequence](https://gramlot-examples.readthedocs.io/en/latest/)
|
|
18
18
|
include every lesson, its Python and JavaScript source, and the gallery guide.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gramlot/gramlot-examples",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "Gramlot example pages, the gallery page and its catalogue.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"prepack": "node scripts/build-browser.mjs"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@gramlot/gramlot": ">=0.3.
|
|
17
|
+
"@gramlot/gramlot": ">=0.3.5"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@genrojs/bag": ">=0.11.0",
|
|
@@ -24299,6 +24299,19 @@ var rangeParameters = {
|
|
|
24299
24299
|
};
|
|
24300
24300
|
function rangeEditor(vertical) {
|
|
24301
24301
|
return (Base) => class extends Base {
|
|
24302
|
+
#sourceContext;
|
|
24303
|
+
#correcting = false;
|
|
24304
|
+
setSourceContext(context) {
|
|
24305
|
+
this.#sourceContext = context;
|
|
24306
|
+
}
|
|
24307
|
+
projectAttributes(attrs, adapt) {
|
|
24308
|
+
const previous = this.parameters;
|
|
24309
|
+
const rest = super.projectAttributes(attrs, adapt);
|
|
24310
|
+
if (previous && ["min", "max", "step"].some((name) => previous[name] !== this.parameters[name])) {
|
|
24311
|
+
this.writeControlValue(this.parameters.value);
|
|
24312
|
+
}
|
|
24313
|
+
return rest;
|
|
24314
|
+
}
|
|
24302
24315
|
createControl() {
|
|
24303
24316
|
const control = this.ownerDocument.createElement("input");
|
|
24304
24317
|
control.type = "range";
|
|
@@ -24312,7 +24325,16 @@ function rangeEditor(vertical) {
|
|
|
24312
24325
|
return this.control.valueAsNumber;
|
|
24313
24326
|
}
|
|
24314
24327
|
writeControlValue(value) {
|
|
24315
|
-
|
|
24328
|
+
this.control.value = String(value);
|
|
24329
|
+
const corrected = this.control.valueAsNumber;
|
|
24330
|
+
if (!this.#correcting && Number.isFinite(value) && Number.isFinite(corrected) && corrected !== value) {
|
|
24331
|
+
this.#correcting = true;
|
|
24332
|
+
try {
|
|
24333
|
+
this.#sourceContext.writeParameter("value", corrected);
|
|
24334
|
+
} finally {
|
|
24335
|
+
this.#correcting = false;
|
|
24336
|
+
}
|
|
24337
|
+
}
|
|
24316
24338
|
}
|
|
24317
24339
|
};
|
|
24318
24340
|
}
|
|
@@ -24322,6 +24344,7 @@ var HorizontalSlider = defineComponent({
|
|
|
24322
24344
|
base: NativeControl,
|
|
24323
24345
|
mixins: [Labelbox, FieldState],
|
|
24324
24346
|
parameters: rangeParameters,
|
|
24347
|
+
sourceContext: true,
|
|
24325
24348
|
implementation: rangeEditor(false)
|
|
24326
24349
|
});
|
|
24327
24350
|
var VerticalSlider = defineComponent({
|
|
@@ -24330,6 +24353,7 @@ var VerticalSlider = defineComponent({
|
|
|
24330
24353
|
base: NativeControl,
|
|
24331
24354
|
mixins: [Labelbox, FieldState],
|
|
24332
24355
|
parameters: rangeParameters,
|
|
24356
|
+
sourceContext: true,
|
|
24333
24357
|
implementation: rangeEditor(true)
|
|
24334
24358
|
});
|
|
24335
24359
|
var NumberTextBox = defineComponent({
|
|
@@ -253,7 +253,7 @@ var SIDES = ["top", "bottom", "left", "right"];
|
|
|
253
253
|
var REGIONS = [...SIDES, "center"];
|
|
254
254
|
var borderRegions = /* @__PURE__ */ new WeakMap();
|
|
255
255
|
var horizontal = (side) => side === "top" || side === "bottom";
|
|
256
|
-
function projectBorderChild(element, attrs, { adapt, invoke, publish, publishParent }) {
|
|
256
|
+
function projectBorderChild(element, attrs, { adapt, invoke, publish, publishParent, writeParameter }) {
|
|
257
257
|
const rest = { ...attrs }, splitter = {}, drawer = {};
|
|
258
258
|
for (const [name, value] of Object.entries(rest)) {
|
|
259
259
|
for (const [prefix, group] of [["splitter_", splitter], ["drawer_", drawer]]) {
|
|
@@ -272,7 +272,15 @@ function projectBorderChild(element, attrs, { adapt, invoke, publish, publishPar
|
|
|
272
272
|
if (![void 0, null, false, true, "close"].includes(rest.drawer)) throw new TypeError("drawer must be true, false or close");
|
|
273
273
|
const probe = element.ownerDocument.createElement("div");
|
|
274
274
|
probe.style.cssText = rest.style ?? "";
|
|
275
|
-
const
|
|
275
|
+
const dimension = horizontal(region) ? "height" : "width";
|
|
276
|
+
const numeric = typeof rest[dimension] === "number";
|
|
277
|
+
if (numeric) {
|
|
278
|
+
if (!Number.isFinite(rest[dimension]) || rest[dimension] < 0) throw new TypeError("Border numeric dimensions must be finite nonnegative pixels");
|
|
279
|
+
probe.style[dimension] = `${rest[dimension]}px`;
|
|
280
|
+
}
|
|
281
|
+
const size = probe.style[dimension];
|
|
282
|
+
delete rest.width;
|
|
283
|
+
delete rest.height;
|
|
276
284
|
probe.style.width = "100%";
|
|
277
285
|
probe.style.height = "100%";
|
|
278
286
|
rest.style = probe.style.cssText;
|
|
@@ -297,6 +305,9 @@ function projectBorderChild(element, attrs, { adapt, invoke, publish, publishPar
|
|
|
297
305
|
label,
|
|
298
306
|
icon,
|
|
299
307
|
minimize,
|
|
308
|
+
writeParameter: (size2) => {
|
|
309
|
+
if (numeric) writeParameter(dimension, size2);
|
|
310
|
+
},
|
|
300
311
|
notifications: {
|
|
301
312
|
closableChange: (payload) => publish("closable_change", payload),
|
|
302
313
|
splitterResize: (payload) => publishParent("splitter_resize", payload)
|
|
@@ -334,7 +345,7 @@ var BorderContainer = defineComponent({
|
|
|
334
345
|
tag: "gramlot-border-container",
|
|
335
346
|
base: Container,
|
|
336
347
|
subTags: "*",
|
|
337
|
-
childParameters: { region: { required: true, enum: REGIONS, unique: true }, drawer_onclick: { inline: ["evt", "show"] } },
|
|
348
|
+
childParameters: { region: { required: true, enum: REGIONS, unique: true }, width: {}, height: {}, drawer_onclick: { inline: ["evt", "show"] } },
|
|
338
349
|
parameters: {
|
|
339
350
|
design: { dtype: "T", default: "headline", binding: "read", enum: ["headline", "sidebar"] },
|
|
340
351
|
persist: { dtype: "B", default: false, binding: "read" }
|
|
@@ -636,6 +647,7 @@ var BorderContainer = defineComponent({
|
|
|
636
647
|
const size = Math.max(Math.min(c.min, available), Math.min(desired, c.max, available));
|
|
637
648
|
state.size = `${size}px`;
|
|
638
649
|
this.#render(side);
|
|
650
|
+
c.writeParameter(size);
|
|
639
651
|
}
|
|
640
652
|
#keyResize(side, evt) {
|
|
641
653
|
const state = this.#regions.get(side);
|
|
@@ -82,7 +82,7 @@ export class Page extends BasePage {
|
|
|
82
82
|
});
|
|
83
83
|
const header = outer.contentPane({
|
|
84
84
|
region: 'top',
|
|
85
|
-
height: '^regions.outer.top
|
|
85
|
+
height: '^regions.outer.top',
|
|
86
86
|
minSize: 40,
|
|
87
87
|
maxSize: 110,
|
|
88
88
|
drawer_label: 'Header',
|
|
@@ -94,7 +94,7 @@ export class Page extends BasePage {
|
|
|
94
94
|
header.span('^customer');
|
|
95
95
|
const footer = outer.contentPane({
|
|
96
96
|
region: 'bottom',
|
|
97
|
-
height: '^regions.outer.bottom
|
|
97
|
+
height: '^regions.outer.bottom',
|
|
98
98
|
minSize: 35,
|
|
99
99
|
maxSize: 130,
|
|
100
100
|
drawer_label: 'Status',
|
|
@@ -107,7 +107,7 @@ export class Page extends BasePage {
|
|
|
107
107
|
const nav = outer.borderContainer({
|
|
108
108
|
id: 'lab-navigation',
|
|
109
109
|
region: 'left',
|
|
110
|
-
width: '^regions.outer.left
|
|
110
|
+
width: '^regions.outer.left',
|
|
111
111
|
minSize: 90,
|
|
112
112
|
maxSize: 240,
|
|
113
113
|
drawer_label: 'Navigation',
|
|
@@ -129,7 +129,7 @@ export class Page extends BasePage {
|
|
|
129
129
|
const details = outer.borderContainer({
|
|
130
130
|
id: 'lab-details',
|
|
131
131
|
region: 'right',
|
|
132
|
-
width: '^regions.outer.right
|
|
132
|
+
width: '^regions.outer.right',
|
|
133
133
|
minSize: 90,
|
|
134
134
|
maxSize: 240,
|
|
135
135
|
drawer_label: 'Details',
|
|
@@ -159,7 +159,7 @@ export class Page extends BasePage {
|
|
|
159
159
|
});
|
|
160
160
|
const tools = work.contentPane({
|
|
161
161
|
region: 'left',
|
|
162
|
-
width: '^regions.workspace.left
|
|
162
|
+
width: '^regions.workspace.left',
|
|
163
163
|
minSize: 70,
|
|
164
164
|
maxSize: 200,
|
|
165
165
|
drawer_label: 'Tools',
|
|
@@ -172,7 +172,7 @@ export class Page extends BasePage {
|
|
|
172
172
|
tools.checkbox({ value: '^readonly', lbl: 'Editor', label: 'Read only' });
|
|
173
173
|
const preview = work.contentPane({
|
|
174
174
|
region: 'bottom',
|
|
175
|
-
height: '^regions.workspace.bottom
|
|
175
|
+
height: '^regions.workspace.bottom',
|
|
176
176
|
minSize: 50,
|
|
177
177
|
maxSize: 180,
|
|
178
178
|
drawer_label: 'Preview',
|
|
@@ -213,7 +213,7 @@ export class Page extends BasePage {
|
|
|
213
213
|
fields.numberTextBox({ id: 'lab-quantity', value: '^quantity', lbl: 'Quantity', width: '100%' });
|
|
214
214
|
const notes = editor.contentPane({
|
|
215
215
|
region: 'bottom',
|
|
216
|
-
height: '^regions.editor.bottom
|
|
216
|
+
height: '^regions.editor.bottom',
|
|
217
217
|
minSize: 60,
|
|
218
218
|
maxSize: 180,
|
|
219
219
|
drawer_label: 'Notes',
|
|
@@ -8,6 +8,8 @@ If the page looks complicated at first, start with just one slider. You do not n
|
|
|
8
8
|
|
|
9
9
|
Move one region-size slider a little, then back again. Follow the boundary that moves. Does it belong to the outer workspace, or to a layout inside it? Repeat with a slider for a different level.
|
|
10
10
|
|
|
11
|
+
Next, drag the same separator. Its slider moves immediately: both controls update the same number. Open the Inspector on Data to follow `regions.outer.left` while moving either the Navigation width slider or its separator. Try a nested region too.
|
|
12
|
+
|
|
11
13
|
Now enter a customer name and a note. Change a date or delivery option too. Look for the places where those values are repeated. They are views of shared Data, not separate copies of the customer.
|
|
12
14
|
|
|
13
15
|
Move the sliders again. The regions become wider, narrower, taller or shorter while your edits remain. Close one drawer, rearrange another area, and reopen it. Hiding a panel has not discarded its contents.
|
|
@@ -16,7 +18,21 @@ Finally, try the design and corner-radius controls. These change presentation wh
|
|
|
16
18
|
|
|
17
19
|
## How a number becomes a size
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
The slider and the region both use a plain pointer to the same number. Numeric region widths and heights are pixels; the borderContainer converts them to CSS internally. Dragging the splitter writes back the constrained number through the binding, so the slider follows immediately.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
sliders.horizontalSlider(value="^regions.outer.left", min=90, max=240, step=1, live=True)
|
|
25
|
+
nav = outer.borderContainer(region="left", width="^regions.outer.left",
|
|
26
|
+
splitter=True, minSize=90, maxSize=240)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Each size slider uses `step=1`. It also corrects numbers received through the binding:
|
|
30
|
+
a fractional splitter measurement such as `176.73` becomes `177` in Data, then the
|
|
31
|
+
panel and label follow that same value. In Inspector, set `regions.outer.left`
|
|
32
|
+
to `176.73` and observe it settle at `177`. The slider writes only when correction
|
|
33
|
+
is needed; a number already on the step grid is not written again.
|
|
34
|
+
|
|
35
|
+
There is no formatting suffix or synchronization controller. `regions` is just the Data branch chosen by this example; it is not a special container parameter. You can find all seven shared size bindings in **Code**.
|
|
20
36
|
|
|
21
37
|
The nested containers still have a simple responsibility: each lays out its own immediate children. The outer container does not calculate the positions of every field inside the editor.
|
|
22
38
|
|