@gramlot/gramlot-examples 0.3.5 → 0.3.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/README.md +1 -1
- package/package.json +2 -2
- package/src/gramlot_examples/gallery/dist/gallery.js +113 -25
- package/src/gramlot_examples/gallery/dist/layout.js +15 -3
- package/src/gramlot_examples/gallery/gallery-page.js +3 -2
- package/src/gramlot_examples/pages/layout/05_nested_lab.js +7 -7
- package/src/gramlot_examples/pages/layout/05_nested_lab.md +11 -1
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.7.
|
|
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.7",
|
|
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.4"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@genrojs/bag": ">=0.11.0",
|
|
@@ -6879,11 +6879,101 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6879
6879
|
element.innerHTML = purifier.sanitize(markdown.parse(element.textContent), { USE_PROFILES: { html: true } });
|
|
6880
6880
|
}
|
|
6881
6881
|
|
|
6882
|
+
// src/gramlot_examples/gallery/browser/gallery-content.js
|
|
6883
|
+
var pending = /* @__PURE__ */ new WeakMap();
|
|
6884
|
+
function mountGalleryContent(renderer, root) {
|
|
6885
|
+
const document2 = renderer.destination.ownerDocument;
|
|
6886
|
+
const byId = (id) => document2.getElementById(id);
|
|
6887
|
+
const node = (element) => renderer.elements.get(element).node;
|
|
6888
|
+
const entries2 = /* @__PURE__ */ new Map();
|
|
6889
|
+
let disposed = false;
|
|
6890
|
+
function format({ key, view }) {
|
|
6891
|
+
if (view === "description") {
|
|
6892
|
+
const readme = byId(`readme-${key}`);
|
|
6893
|
+
readme.textContent = node(readme).value;
|
|
6894
|
+
renderReadme(readme);
|
|
6895
|
+
return;
|
|
6896
|
+
}
|
|
6897
|
+
const code = byId(`code-${key}`);
|
|
6898
|
+
code.textContent = node(code).value;
|
|
6899
|
+
highlightCode(code);
|
|
6900
|
+
const logic = byId(`logic-${key}`);
|
|
6901
|
+
if (logic) {
|
|
6902
|
+
const source = logicSource(node(logic).value);
|
|
6903
|
+
node(byId(`logic-panel-${key}`)).setAttr({ hidden: source === null });
|
|
6904
|
+
logic.textContent = source ?? "";
|
|
6905
|
+
if (source !== null) highlightCode(logic);
|
|
6906
|
+
}
|
|
6907
|
+
}
|
|
6908
|
+
async function load(entry) {
|
|
6909
|
+
if (entry.loading) return;
|
|
6910
|
+
entry.loading = true;
|
|
6911
|
+
const targetId = entry.view === "code" ? `code-tabs-${entry.key}` : entry.element.id;
|
|
6912
|
+
const target = node(byId(targetId));
|
|
6913
|
+
const current = () => {
|
|
6914
|
+
const element = byId(targetId);
|
|
6915
|
+
return element && renderer.elements.get(element)?.node === target ? element : null;
|
|
6916
|
+
};
|
|
6917
|
+
let request = pending.get(target);
|
|
6918
|
+
if (!request) {
|
|
6919
|
+
request = renderer.binding.gramlot.src.remoteSource(target, "lesson", { key: entry.key, view: entry.view });
|
|
6920
|
+
pending.set(target, request);
|
|
6921
|
+
}
|
|
6922
|
+
try {
|
|
6923
|
+
const mounted = await request;
|
|
6924
|
+
if (disposed || !current() || !mounted) return;
|
|
6925
|
+
format(entry);
|
|
6926
|
+
observer.unobserve(entry.element);
|
|
6927
|
+
entries2.delete(entry.element);
|
|
6928
|
+
} catch {
|
|
6929
|
+
if (disposed || !current()) return;
|
|
6930
|
+
const status = current().querySelector('[role="status"]');
|
|
6931
|
+
node(status).setValue("Could not load this content. Close and reopen the panel to retry.");
|
|
6932
|
+
} finally {
|
|
6933
|
+
if (pending.get(target) === request) pending.delete(target);
|
|
6934
|
+
entry.loading = false;
|
|
6935
|
+
}
|
|
6936
|
+
}
|
|
6937
|
+
const observer = new document2.defaultView.IntersectionObserver((records) => {
|
|
6938
|
+
for (const record of records) {
|
|
6939
|
+
const entry = entries2.get(record.target);
|
|
6940
|
+
if (!entry) continue;
|
|
6941
|
+
const visible = record.isIntersecting && record.intersectionRect.width > 0 && record.intersectionRect.height > 0;
|
|
6942
|
+
if (visible && !entry.visible) void load(entry);
|
|
6943
|
+
entry.visible = visible;
|
|
6944
|
+
}
|
|
6945
|
+
});
|
|
6946
|
+
const dispose = () => {
|
|
6947
|
+
disposed = true;
|
|
6948
|
+
observer.disconnect();
|
|
6949
|
+
entries2.clear();
|
|
6950
|
+
};
|
|
6951
|
+
renderer.onDispose(root, dispose);
|
|
6952
|
+
return {
|
|
6953
|
+
observe(key) {
|
|
6954
|
+
for (const [view, id, loaded] of [
|
|
6955
|
+
["code", `codepane-${key}`, `code-${key}`],
|
|
6956
|
+
["description", `description-${key}`, `readme-${key}`]
|
|
6957
|
+
]) {
|
|
6958
|
+
const element = byId(id);
|
|
6959
|
+
const entry = { key, view, element, visible: false, loading: false };
|
|
6960
|
+
if (byId(loaded)) format(entry);
|
|
6961
|
+
else if (!entries2.has(element)) {
|
|
6962
|
+
entries2.set(element, entry);
|
|
6963
|
+
observer.observe(element);
|
|
6964
|
+
}
|
|
6965
|
+
}
|
|
6966
|
+
},
|
|
6967
|
+
dispose
|
|
6968
|
+
};
|
|
6969
|
+
}
|
|
6970
|
+
|
|
6882
6971
|
// src/gramlot_examples/gallery/browser/gallery.js
|
|
6883
6972
|
function mountGallery(renderer, root, inspector) {
|
|
6884
6973
|
const state = root.builder.data.getItem("galleryIndex");
|
|
6885
6974
|
const settings = mountGallerySettings(renderer, root, state);
|
|
6886
6975
|
let guide = null;
|
|
6976
|
+
const content = mountGalleryContent(renderer, root);
|
|
6887
6977
|
const mobile = mountGalleryMobile(renderer, root, inspector, state, (visible) => {
|
|
6888
6978
|
if (!visible) guide?.pause();
|
|
6889
6979
|
});
|
|
@@ -6891,19 +6981,14 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6891
6981
|
inspector.update(entries2, active);
|
|
6892
6982
|
mobile.update(entries2, active);
|
|
6893
6983
|
guide?.update(entries2, active);
|
|
6894
|
-
}, (entry, { byId
|
|
6984
|
+
}, (entry, { byId }) => {
|
|
6895
6985
|
const { key } = entry;
|
|
6896
6986
|
if (key === "l04" && !guide) guide = mountGuidedDemo(renderer, root);
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
const logic = byId(`logic-${key}`);
|
|
6901
|
-
if (logic) {
|
|
6902
|
-
const source = logicSource(node(logic).value);
|
|
6903
|
-
set(byId(`logic-panel-${key}`), { hidden: source === null });
|
|
6904
|
-
logic.textContent = source ?? "";
|
|
6905
|
-
if (source !== null) highlightCode(logic);
|
|
6987
|
+
if (entry.panel.classList.contains("index-category")) {
|
|
6988
|
+
renderReadme(byId(`readme-${key}`));
|
|
6989
|
+
return;
|
|
6906
6990
|
}
|
|
6991
|
+
content.observe(entry.key);
|
|
6907
6992
|
}, {
|
|
6908
6993
|
containerLayout: true,
|
|
6909
6994
|
state,
|
|
@@ -6919,20 +7004,22 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6919
7004
|
hidden: true,
|
|
6920
7005
|
class: category ? "index-category" : "gallery-panel"
|
|
6921
7006
|
});
|
|
6922
|
-
const code = category ? null : source("gallery-code-pages").
|
|
7007
|
+
const code = category ? null : source("gallery-code-pages").div({
|
|
6923
7008
|
id: `codepane-${entry.key}`,
|
|
6924
|
-
class: "gallery-codepane
|
|
7009
|
+
class: "gallery-codepane",
|
|
6925
7010
|
hidden: true,
|
|
7011
|
+
height: "100%"
|
|
7012
|
+
});
|
|
7013
|
+
if (code) code.tabContainer({
|
|
7014
|
+
id: `code-tabs-${entry.key}`,
|
|
7015
|
+
class: "gallery-source-tabs",
|
|
6926
7016
|
height: "100%",
|
|
6927
7017
|
tabMode: "underline"
|
|
6928
|
-
});
|
|
7018
|
+
}).contentPane({ title: "Code" }).p("Loading code\u2026", { role: "status" });
|
|
6929
7019
|
try {
|
|
6930
7020
|
const runtime = renderer.binding.gramlot;
|
|
6931
|
-
const
|
|
6932
|
-
|
|
6933
|
-
...code ? [runtime.src.remoteSource(node(`codepane-${entry.key}`), "lesson", { key: entry.key, view: "code" })] : []
|
|
6934
|
-
]);
|
|
6935
|
-
if (results.some((mounted) => !mounted)) throw new Error("Lesson loading was cancelled");
|
|
7021
|
+
const mounted = await runtime.src.remoteSource(node(`panel-${entry.key}`), "lesson", { key: entry.key });
|
|
7022
|
+
if (!mounted) throw new Error("Lesson loading was cancelled");
|
|
6936
7023
|
} catch (error) {
|
|
6937
7024
|
for (const target of [pane, code]) if (target?.parentBag) target.parentBag.popNode(target.label);
|
|
6938
7025
|
throw error;
|
|
@@ -6945,6 +7032,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
6945
7032
|
});
|
|
6946
7033
|
return { dispose() {
|
|
6947
7034
|
guide?.dispose();
|
|
7035
|
+
content.dispose();
|
|
6948
7036
|
settings.dispose();
|
|
6949
7037
|
index.dispose();
|
|
6950
7038
|
mobile.dispose();
|
|
@@ -7550,11 +7638,11 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
7550
7638
|
this.error = error.message;
|
|
7551
7639
|
}
|
|
7552
7640
|
if (message.type === "result") {
|
|
7553
|
-
const
|
|
7554
|
-
if (
|
|
7641
|
+
const pending2 = this.#pending.get(message.id);
|
|
7642
|
+
if (pending2) {
|
|
7555
7643
|
this.#pending.delete(message.id);
|
|
7556
|
-
if (message.ok && !this.error)
|
|
7557
|
-
else
|
|
7644
|
+
if (message.ok && !this.error) pending2.resolve(message);
|
|
7645
|
+
else pending2.reject(new Error(message.error || this.error));
|
|
7558
7646
|
}
|
|
7559
7647
|
}
|
|
7560
7648
|
this.#notify();
|
|
@@ -7611,7 +7699,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
7611
7699
|
this.#port.removeEventListener("message", this.#receive);
|
|
7612
7700
|
this.#port.close();
|
|
7613
7701
|
this.state = "disposed";
|
|
7614
|
-
for (const
|
|
7702
|
+
for (const pending2 of this.#pending.values()) pending2.reject(new Error("Inspected page disconnected"));
|
|
7615
7703
|
this.#pending.clear();
|
|
7616
7704
|
this.#notify();
|
|
7617
7705
|
}
|
|
@@ -7690,9 +7778,9 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
7690
7778
|
_subscribe() {
|
|
7691
7779
|
if (this._store) this._store.subscribe(this._subId, { any: () => {
|
|
7692
7780
|
if (this._pendingRender) return;
|
|
7693
|
-
const
|
|
7781
|
+
const pending2 = this._pendingRender = {};
|
|
7694
7782
|
queueMicrotask(() => {
|
|
7695
|
-
if (this._pendingRender ===
|
|
7783
|
+
if (this._pendingRender === pending2 && this.isConnected) this._render();
|
|
7696
7784
|
});
|
|
7697
7785
|
} });
|
|
7698
7786
|
}
|
|
@@ -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);
|
|
@@ -102,6 +102,7 @@ export class GalleryPage extends IndexPage {
|
|
|
102
102
|
lesson(root, {key, view = 'example'}) {
|
|
103
103
|
const item = this.galleryItem(key);
|
|
104
104
|
if (view === 'code' && !item.examples) this.codePanel(root, item);
|
|
105
|
+
else if (view === 'description' && !item.examples) root.div(item.readme, {id: `readme-${key}`});
|
|
105
106
|
else if (view === 'example') {
|
|
106
107
|
if (item.examples) this.groupPanel(root, item);
|
|
107
108
|
else this.panel(root, item);
|
|
@@ -124,8 +125,8 @@ export class GalleryPage extends IndexPage {
|
|
|
124
125
|
guidedDemo(layout);
|
|
125
126
|
}
|
|
126
127
|
stage.iframe({title: `${example.title} preview`, name: `example-${key}`, id: `frame-${key}`});
|
|
127
|
-
preview.contentPane({title: 'Explanation', pageName: 'explanation', class: 'gallery-lesson', overflow: 'auto'})
|
|
128
|
-
.
|
|
128
|
+
preview.contentPane({title: 'Explanation', pageName: 'explanation', class: 'gallery-lesson', overflow: 'auto', id: `description-${key}`})
|
|
129
|
+
.p('Loading explanation…', {role: 'status'});
|
|
129
130
|
}
|
|
130
131
|
codePanel(parent, example) {
|
|
131
132
|
const key = example.key;
|
|
@@ -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,15 @@ 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, live=True)
|
|
25
|
+
nav = outer.borderContainer(region="left", width="^regions.outer.left",
|
|
26
|
+
splitter=True, minSize=90, maxSize=240)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
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
30
|
|
|
21
31
|
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
32
|
|