pict-section-form 1.1.0 → 1.1.2

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.
Files changed (45) hide show
  1. package/docs/_cover.md +3 -0
  2. package/docs/_sidebar.md +5 -0
  3. package/docs/_version.json +3 -3
  4. package/docs/examples/README.md +3 -0
  5. package/docs/examples/change_tracking/change_tracking.js +9437 -9427
  6. package/docs/examples/diagram_form/README.md +116 -0
  7. package/docs/examples/diagram_form/diagram_form_example.min.js +42 -0
  8. package/docs/examples/diagram_form/excalidraw-iframe-host.html +25 -0
  9. package/docs/examples/diagram_form/excalidraw-wrapper.css +1 -0
  10. package/docs/examples/diagram_form/excalidraw-wrapper.min.js +3327 -0
  11. package/docs/examples/diagram_form/index.html +116 -0
  12. package/docs/examples/diagram_form/manifest.json +13 -0
  13. package/docs/examples/diagram_form/react-vendor.min.js +9 -0
  14. package/docs/examples/dynamic_analysis/dynamic_analysis_application.js +6549 -6550
  15. package/docs/examples/gradebook/gradebook_application.min.js +2 -2
  16. package/docs/examples/ndt_field_test/ndt_field_test.js +9437 -9427
  17. package/docs/examples/richtext_form/README.md +132 -0
  18. package/docs/examples/richtext_form/index.html +82 -0
  19. package/docs/examples/richtext_form/richtext_form_example.min.js +42 -0
  20. package/docs/examples/scope_mathematics/scope_mathematics.js +9437 -9427
  21. package/docs/examples/simple_table/simple_tabular_application.min.js +2 -2
  22. package/docs/examples/superhero_studio/README.md +199 -0
  23. package/docs/examples/superhero_studio/excalidraw-iframe-host.html +25 -0
  24. package/docs/examples/superhero_studio/excalidraw-wrapper.css +1 -0
  25. package/docs/examples/superhero_studio/excalidraw-wrapper.min.js +3327 -0
  26. package/docs/examples/superhero_studio/index.html +166 -0
  27. package/docs/examples/superhero_studio/manifest.json +13 -0
  28. package/docs/examples/superhero_studio/react-vendor.min.js +9 -0
  29. package/docs/examples/superhero_studio/superhero_studio_example.min.js +42 -0
  30. package/docs/index.html +2 -2
  31. package/docs/retold-catalog.json +45 -1
  32. package/docs/retold-keyword-index.json +11843 -7677
  33. package/example_applications/diagram_form/DiagramForm-Example-Application.js +145 -0
  34. package/example_applications/diagram_form/html/index.html +116 -0
  35. package/example_applications/diagram_form/package.json +29 -0
  36. package/example_applications/richtext_form/RichTextForm-Example-Application.js +176 -0
  37. package/example_applications/richtext_form/html/index.html +82 -0
  38. package/example_applications/richtext_form/package.json +28 -0
  39. package/example_applications/superhero_studio/SuperheroStudio-Example-Application.js +313 -0
  40. package/example_applications/superhero_studio/html/index.html +166 -0
  41. package/example_applications/superhero_studio/package.json +29 -0
  42. package/example_applications/superhero_studio/superheroes/Superheroes.js +386 -0
  43. package/package.json +3 -9
  44. package/source/providers/inputs/Pict-Provider-Input-Diagram.js +1 -31
  45. package/source/providers/inputs/Pict-Provider-Input-RichText.js +1 -32
@@ -0,0 +1,313 @@
1
+ /**
2
+ * SuperheroStudio-Example-Application.js
3
+ *
4
+ * The "Superhero Studio" — a pict-section-form showcase that exercises both
5
+ * new complex InputTypes in one place:
6
+ *
7
+ * - RichText (origin story) — markdown editor / rendered markdown
8
+ * - Diagram (portrait) — Excalidraw / inline themed SVG
9
+ *
10
+ * Plus a bunch of stock inputs (Text, Number, Select, TextArea) so the form
11
+ * feels like a real character-sheet UI.
12
+ *
13
+ * A dropdown at the top loads one of five pre-baked superheroes — their
14
+ * stats, portraits, and origin stories all flow into the form via
15
+ * marshalDataFromAppDataToDynamicViews(). Try toggling the portrait or origin into
16
+ * edit mode and editing them — the rest of the form keeps working.
17
+ */
18
+
19
+ const libPictApplication = require('pict-application');
20
+ const libPictSectionForm = require('../../source/Pict-Section-Form.js');
21
+
22
+ const libSuperheroes = require('./superheroes/Superheroes.js');
23
+
24
+ // ----- Form manifest -------------------------------------------------------
25
+
26
+ const _PowerOptions =
27
+ [
28
+ { id: 'Telepathy', text: 'Telepathy' },
29
+ { id: 'Manifestation', text: 'Manifestation' },
30
+ { id: 'Syntax Highlighting', text: 'Syntax Highlighting' },
31
+ { id: 'Z-Index Manipulation',text: 'Z-Index Manipulation' },
32
+ { id: 'Snap to Grid', text: 'Snap to Grid' },
33
+ { id: 'Flight', text: 'Flight' },
34
+ { id: 'Super Strength', text: 'Super Strength' },
35
+ { id: 'Invisibility', text: 'Invisibility' },
36
+ { id: 'Time Travel', text: 'Time Travel' },
37
+ { id: 'Pyrokinesis', text: 'Pyrokinesis' }
38
+ ];
39
+
40
+ const _ColorOptions =
41
+ [
42
+ { id: 'Red', text: 'Red' },
43
+ { id: 'Blue', text: 'Blue' },
44
+ { id: 'Green', text: 'Green' },
45
+ { id: 'Black', text: 'Black' },
46
+ { id: 'Yellow', text: 'Yellow' },
47
+ { id: 'Purple', text: 'Purple' }
48
+ ];
49
+
50
+ const _Descriptors =
51
+ {
52
+ // ---- Identity ----
53
+ 'Name': {
54
+ Name: 'Name', Hash: 'Name', DataType: 'String',
55
+ PictForm: { Section: 'Identity', Row: 1, Width: 6, InputType: 'Text' }
56
+ },
57
+ 'AlterEgo': {
58
+ Name: 'Alter Ego', Hash: 'AlterEgo', DataType: 'String',
59
+ PictForm: { Section: 'Identity', Row: 1, Width: 6, InputType: 'Text' }
60
+ },
61
+ 'ShoeSize': {
62
+ Name: 'Shoe Size (US)', Hash: 'ShoeSize', DataType: 'Number',
63
+ PictForm: { Section: 'Identity', Row: 2, Width: 3, InputType: 'Number', Min: 1, Max: 22, Step: 0.5 }
64
+ },
65
+ 'OriginYear': {
66
+ Name: 'Year of Origin', Hash: 'OriginYear', DataType: 'Number',
67
+ PictForm: { Section: 'Identity', Row: 2, Width: 3, InputType: 'Number', Min: 1900, Max: 2099 }
68
+ },
69
+ 'CoffeeCupsPerDay': {
70
+ Name: 'Coffee Cups / Day', Hash: 'CoffeeCupsPerDay', DataType: 'Number',
71
+ PictForm: { Section: 'Identity', Row: 2, Width: 3, InputType: 'Number', Min: 0, Max: 99 }
72
+ },
73
+ 'NumberOfSidekicks': {
74
+ Name: 'Active Sidekicks', Hash: 'NumberOfSidekicks', DataType: 'Number',
75
+ PictForm: { Section: 'Identity', Row: 2, Width: 3, InputType: 'Number', Min: 0, Max: 99 }
76
+ },
77
+
78
+ // ---- Powers ----
79
+ 'PowerLevel': {
80
+ Name: 'Power Level (1–10)', Hash: 'PowerLevel', DataType: 'Number',
81
+ PictForm: { Section: 'Powers', Row: 1, Width: 3, InputType: 'Number', Min: 1, Max: 10 }
82
+ },
83
+ 'PrimaryPower': {
84
+ Name: 'Primary Power', Hash: 'PrimaryPower', DataType: 'String',
85
+ PictForm: { Section: 'Powers', Row: 1, Width: 5, InputType: 'Option', SelectOptions: _PowerOptions }
86
+ },
87
+ 'ThemeColor': {
88
+ Name: 'Theme Color', Hash: 'ThemeColor', DataType: 'String',
89
+ PictForm: { Section: 'Powers', Row: 1, Width: 4, InputType: 'Option', SelectOptions: _ColorOptions }
90
+ },
91
+ 'Weakness': {
92
+ Name: 'Known Weakness', Hash: 'Weakness', DataType: 'String',
93
+ PictForm: { Section: 'Powers', Row: 2, Width: 6, InputType: 'Text' }
94
+ },
95
+ 'FavoriteSnack': {
96
+ Name: 'Favorite Snack', Hash: 'FavoriteSnack', DataType: 'String',
97
+ PictForm: { Section: 'Powers', Row: 2, Width: 6, InputType: 'Text' }
98
+ },
99
+ 'Catchphrase': {
100
+ Name: 'Signature Catchphrase', Hash: 'Catchphrase', DataType: 'String',
101
+ PictForm: { Section: 'Powers', Row: 3, Width: 12, InputType: 'TextArea', TextAreaRows: 2 }
102
+ },
103
+
104
+ // ---- Portrait (Diagram InputType) ----
105
+ 'Portrait': {
106
+ Name: 'Portrait', Hash: 'Portrait', DataType: 'String',
107
+ PictForm:
108
+ {
109
+ Section: 'Portrait', Row: 1, Width: 12,
110
+ InputType: 'Diagram',
111
+ Diagram:
112
+ {
113
+ ThemeColors: true,
114
+ Height: '320px',
115
+ EditorImplementation: 'react'
116
+ }
117
+ }
118
+ },
119
+
120
+ // ---- Origin Story (RichText InputType) ----
121
+ 'OriginStory': {
122
+ Name: 'Origin Story', Hash: 'OriginStory', DataType: 'String',
123
+ PictForm:
124
+ {
125
+ Section: 'OriginStory', Row: 1, Width: 12,
126
+ InputType: 'RichText',
127
+ RichText:
128
+ {
129
+ AllowImages: true,
130
+ ImageUploader: 'uploadImage',
131
+ Height: '380px'
132
+ }
133
+ }
134
+ }
135
+ };
136
+
137
+ const _FormManifest =
138
+ {
139
+ Scope: 'SuperheroForm',
140
+ Sections:
141
+ [
142
+ { Hash: 'Identity', Name: 'Identity' },
143
+ { Hash: 'Powers', Name: 'Powers & Loadout' },
144
+ { Hash: 'Portrait', Name: 'Portrait' },
145
+ { Hash: 'OriginStory', Name: 'Origin Story' }
146
+ ],
147
+ Descriptors: _Descriptors
148
+ };
149
+
150
+ // ----- Application ---------------------------------------------------------
151
+
152
+ class SuperheroStudioApplication extends libPictSectionForm.PictFormApplication
153
+ {
154
+ constructor(pFable, pOptions, pServiceHash)
155
+ {
156
+ super(pFable, pOptions, pServiceHash);
157
+
158
+ // Register the RichText input provider (from pict-section-markdowneditor).
159
+ // Both complex InputType providers live in pict-section-form. The heavy
160
+ // editor deps (markdowneditor → CodeMirror, excalidraw → vendor bundle)
161
+ // lazy-load on the first setMode('edit'), so this view-by-default form
162
+ // pays for neither editor at boot.
163
+ let libRichTextInput = libPictSectionForm.RichTextInput;
164
+ this.pict.addProvider(
165
+ libRichTextInput.default_configuration.ProviderIdentifier,
166
+ libRichTextInput.default_configuration,
167
+ libRichTextInput);
168
+
169
+ let libDiagramInput = libPictSectionForm.DiagramInput;
170
+ this.pict.addProvider(
171
+ libDiagramInput.default_configuration.ProviderIdentifier,
172
+ libDiagramInput.default_configuration,
173
+ libDiagramInput);
174
+
175
+ // Seed with the first hero so the form has data on load.
176
+ this._currentHeroSlug = 'captain-verbose';
177
+ this.pict.AppData.SuperheroForm =
178
+ JSON.parse(JSON.stringify(libSuperheroes[this._currentHeroSlug]));
179
+ }
180
+
181
+ onAfterInitializeAsync(fCallback)
182
+ {
183
+ // Point the form metacontroller at our AppData branch BEFORE super so
184
+ // the initial render reads from the right place.
185
+ if (this.pict.views.PictFormMetacontroller)
186
+ {
187
+ this.pict.views.PictFormMetacontroller.viewMarshalDestination = 'AppData.SuperheroForm';
188
+ }
189
+ super.onAfterInitializeAsync(() =>
190
+ {
191
+ try { this.marshalDataFromAppDataToDynamicViews(); }
192
+ catch (pErr) { if (this.log) this.log.warn('[superhero_studio] initial marshal failed', { error: pErr.message }); }
193
+ return fCallback();
194
+ });
195
+ }
196
+
197
+ // -----------------------------------------------------------------
198
+ // Dropdown / page handlers (called from index.html inline onclick)
199
+ // -----------------------------------------------------------------
200
+
201
+ demo_loadHero(pSlug)
202
+ {
203
+ let tmpHero = libSuperheroes[pSlug];
204
+ if (!tmpHero) return;
205
+ this._currentHeroSlug = pSlug;
206
+
207
+ // Tear down any currently-open editor instances so the swap doesn't
208
+ // leave a stale CodeMirror/Excalidraw painting yesterday's hero.
209
+ this._foldAllEditors();
210
+
211
+ // Replace the form's source-of-truth record.
212
+ this.pict.AppData.SuperheroForm = JSON.parse(JSON.stringify(tmpHero));
213
+
214
+ // Push the new record into the rendered form.
215
+ try { this.marshalDataFromAppDataToDynamicViews(); }
216
+ catch (pErr) { if (this.log) this.log.warn('[superhero_studio] marshal failed', { error: pErr.message }); }
217
+
218
+ this._refreshToggleLabels();
219
+ }
220
+
221
+ demo_toggleMode(pInputHash)
222
+ {
223
+ let tmpProvider = this._providerForInput(pInputHash);
224
+ if (!tmpProvider) return;
225
+ tmpProvider.toggleMode(pInputHash, (pErr) =>
226
+ {
227
+ if (pErr && this.log) this.log.warn('[superhero_studio] toggleMode error',
228
+ { error: pErr.message, inputHash: pInputHash });
229
+ this._refreshToggleLabels();
230
+ });
231
+ }
232
+
233
+ /**
234
+ * Demo image uploader for the RichText origin-story field. In a real app
235
+ * this would POST to your image-storage endpoint and call back with the
236
+ * permanent URL. Here we mint a fake CDN URL after a brief delay.
237
+ */
238
+ uploadImage(pFile, pInputDescriptor, fCallback)
239
+ {
240
+ setTimeout(() =>
241
+ {
242
+ let tmpFakeURL = '/uploads/heroes/' + Date.now() + '-' +
243
+ (pFile.name || 'image.png').replace(/[^A-Za-z0-9._-]/g, '_');
244
+ fCallback(null, tmpFakeURL);
245
+ if (this.log) this.log.info('[superhero_studio] uploadImage resolved', { url: tmpFakeURL });
246
+ }, 600);
247
+ return true;
248
+ }
249
+
250
+ // -----------------------------------------------------------------
251
+ // Internals
252
+ // -----------------------------------------------------------------
253
+
254
+ _providerForInput(pInputHash)
255
+ {
256
+ let tmpDescriptor = _Descriptors[pInputHash];
257
+ if (!tmpDescriptor) return null;
258
+ let tmpType = tmpDescriptor.PictForm && tmpDescriptor.PictForm.InputType;
259
+ if (tmpType === 'RichText') return this.pict.providers['Pict-Input-RichText'];
260
+ if (tmpType === 'Diagram') return this.pict.providers['Pict-Input-Diagram'];
261
+ return null;
262
+ }
263
+
264
+ _foldAllEditors()
265
+ {
266
+ let tmpHashes = ['Portrait', 'OriginStory'];
267
+ for (let i = 0; i < tmpHashes.length; i++)
268
+ {
269
+ let tmpProvider = this._providerForInput(tmpHashes[i]);
270
+ if (tmpProvider && tmpProvider.getMode(tmpHashes[i]) === 'edit')
271
+ {
272
+ try { tmpProvider.setMode(tmpHashes[i], 'view', () => {}); }
273
+ catch (pErr) { /* swallow — happens if not yet mounted */ }
274
+ }
275
+ }
276
+ }
277
+
278
+ _refreshToggleLabels()
279
+ {
280
+ if (typeof document === 'undefined') return;
281
+ let tmpHashes = ['Portrait', 'OriginStory'];
282
+ for (let i = 0; i < tmpHashes.length; i++)
283
+ {
284
+ let tmpHash = tmpHashes[i];
285
+ let tmpProvider = this._providerForInput(tmpHash);
286
+ let tmpBtn = document.getElementById('toggle-' + tmpHash);
287
+ if (!tmpBtn) continue;
288
+ let tmpMode = tmpProvider ? tmpProvider.getMode(tmpHash) : null;
289
+ tmpBtn.textContent = (tmpMode === 'edit') ? 'Done' : 'Edit';
290
+ }
291
+ }
292
+ }
293
+
294
+ module.exports = SuperheroStudioApplication;
295
+
296
+ // Extend the parent's default_configuration so MainViewportViewIdentifier
297
+ // (= "PictFormMetacontroller") survives — without it the form has no
298
+ // auto-render target and the page comes up blank.
299
+ module.exports.default_configuration = Object.assign({},
300
+ libPictSectionForm.PictFormApplication.default_configuration,
301
+ {
302
+ Name: 'Superhero Studio',
303
+ Hash: 'SuperheroStudio',
304
+ pict_configuration:
305
+ {
306
+ Product: 'SuperheroStudio-Example',
307
+ DefaultFormManifest: _FormManifest
308
+ }
309
+ });
310
+
311
+ // Expose the slug list so the HTML dropdown can render its options dynamically.
312
+ module.exports.HeroSlugs = Object.keys(libSuperheroes);
313
+ module.exports.Heroes = libSuperheroes;
@@ -0,0 +1,166 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Superhero Studio — Pict Example</title>
7
+
8
+ <style id="PICT-CSS"></style>
9
+ <style id="diagram-theme">
10
+ :root
11
+ {
12
+ --diagram-ink: #1B1F23;
13
+ --diagram-paper: #FDFCF7;
14
+ --diagram-accent: #E66C2C;
15
+ --diagram-highlight: #FFD966;
16
+ --diagram-deemphasis: #A0A0A0;
17
+ --diagram-link: #2E7D74;
18
+ }
19
+ </style>
20
+ <style>
21
+ *, *::before, *::after { box-sizing: border-box; }
22
+ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; background: #F4F1ED; color: #2A2520; }
23
+
24
+ .pict-example-header { display: flex; align-items: stretch; background: #264653; border-bottom: 3px solid #E76F51; }
25
+ .pict-example-badge { background: #E76F51; color: #FAEDCD; padding: 0.6rem 1rem; font-size: 0.72rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.1em; }
26
+ .pict-example-app-name { padding: 0.6rem 1rem; color: #FAEDCD; font-size: 1.1rem; font-weight: 600; }
27
+ .pict-example-module { margin-left: auto; padding: 0.6rem 1rem; color: #D4A373; font-size: 0.75rem; letter-spacing: 0.03em; align-self: center; }
28
+
29
+ .page-content { padding: 1.6rem 2rem 4rem; max-width: 1080px; margin: 0 auto; }
30
+
31
+ .hero-bar
32
+ {
33
+ background: #FFFFFF; border: 1px solid #D4C4A8; border-radius: 8px;
34
+ padding: 16px 20px; margin-bottom: 22px;
35
+ display: flex; flex-wrap: wrap; gap: 14px; align-items: center;
36
+ box-shadow: 0 1px 3px rgba(0,0,0,0.04);
37
+ }
38
+ .hero-bar label { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.08em; color: #5A4A3C; font-weight: 600; }
39
+ .hero-bar select
40
+ {
41
+ padding: 6px 12px; border: 1px solid #D4C4A8; border-radius: 4px;
42
+ background: #FBF7EE; font-size: 0.95rem; min-width: 220px;
43
+ }
44
+ .hero-bar .theme-group { margin-left: auto; display: flex; gap: 8px; align-items: center; }
45
+ .hero-bar .swatch
46
+ {
47
+ width: 22px; height: 22px; border-radius: 4px; cursor: pointer;
48
+ border: 2px solid rgba(0,0,0,0.1); transition: transform 0.08s ease;
49
+ }
50
+ .hero-bar .swatch:hover { transform: scale(1.1); border-color: #2E7D74; }
51
+
52
+ .field-action-bar
53
+ {
54
+ display: flex; align-items: center; gap: 10px;
55
+ margin-top: -8px; margin-bottom: 12px; padding: 0 4px;
56
+ }
57
+ .field-action-bar button
58
+ {
59
+ padding: 4px 12px; font-size: 0.78rem; font-weight: 600;
60
+ color: #FAEDCD; background: #264653; border: none; border-radius: 4px;
61
+ cursor: pointer;
62
+ }
63
+ .field-action-bar button:hover { background: #E76F51; }
64
+ .field-action-bar .hint { font-size: 0.72rem; color: #8A7F72; }
65
+
66
+ #Pict-Form-Container
67
+ {
68
+ background: #FFFFFF; border: 1px solid #D4C4A8; border-radius: 8px;
69
+ padding: 24px 26px; box-shadow: 0 1px 3px rgba(0,0,0,0.04);
70
+ }
71
+
72
+ .notes
73
+ {
74
+ margin-top: 24px; padding: 14px 18px;
75
+ background: #FFF8E7; border-left: 3px solid #E9C46A; border-radius: 4px;
76
+ font-size: 0.85rem; color: #5A4A3C;
77
+ }
78
+ .notes strong { color: #2A2520; }
79
+ .notes code { font-family: 'SFMono-Regular', Menlo, monospace; background: #F0E8DA; padding: 1px 5px; border-radius: 3px; font-size: 0.9em; }
80
+ </style>
81
+ </head>
82
+ <body>
83
+ <header class="pict-example-header">
84
+ <span class="pict-example-badge">Pict Example</span>
85
+ <span class="pict-example-app-name">Superhero Studio</span>
86
+ <span class="pict-example-module">pict-section-excalidraw &times; pict-section-markdowneditor</span>
87
+ </header>
88
+
89
+ <main class="page-content">
90
+ <div class="hero-bar">
91
+ <label for="hero-select">Load Superhero</label>
92
+ <select id="hero-select" onchange="_Pict.PictApplication.demo_loadHero(this.value)">
93
+ <option value="captain-verbose">Captain Verbose</option>
94
+ <option value="the-notebook">The Notebook</option>
95
+ <option value="markdown-marauder">Markdown Marauder</option>
96
+ <option value="the-modal-avenger">The Modal Avenger</option>
97
+ <option value="vector-vince">Vector Vince</option>
98
+ </select>
99
+
100
+ <div class="theme-group">
101
+ <span style="font-size:0.78rem; text-transform:uppercase; letter-spacing:0.08em; color:#5A4A3C; font-weight:600;">Portrait theme</span>
102
+ <span class="swatch" title="Notebook" style="background:#FDFCF7; border-color:#1B1F23;" onclick="window.applyTheme('notebook')"></span>
103
+ <span class="swatch" title="Dark" style="background:#1B1F23;" onclick="window.applyTheme('dark')"></span>
104
+ <span class="swatch" title="Blueprint" style="background:#5DA9E9;" onclick="window.applyTheme('blueprint')"></span>
105
+ <span class="swatch" title="Sepia" style="background:#B08968;" onclick="window.applyTheme('sepia')"></span>
106
+ </div>
107
+ </div>
108
+
109
+ <div class="field-action-bar">
110
+ <button id="toggle-Portrait" onclick="_Pict.PictApplication.demo_toggleMode('Portrait')">Edit</button>
111
+ <span class="hint">Toggle the Portrait field into Excalidraw — first click lazy-loads the editor bundle.</span>
112
+
113
+ <button id="toggle-OriginStory" onclick="_Pict.PictApplication.demo_toggleMode('OriginStory')" style="margin-left:18px;">Edit</button>
114
+ <span class="hint">Toggle the Origin Story field into the markdown editor.</span>
115
+ </div>
116
+
117
+ <div id="Pict-Form-Container"></div>
118
+
119
+ <div class="notes">
120
+ <strong>What's happening:</strong>
121
+ Stock inputs (<code>Text</code>, <code>Number</code>, <code>Option</code>, <code>TextArea</code>) sit next to two complex InputTypes —
122
+ <code>Diagram</code> (Portrait) and <code>RichText</code> (Origin Story) — in the same form, all driven by the same
123
+ <code>marshalDataFromAppDataToView</code> pipeline. The portrait SVGs use <code>var(--diagram-ink, …)</code> with hex fallbacks,
124
+ so swapping the theme swatches recolors them live without re-rendering. Loading a new hero from the dropdown folds any open editors back
125
+ into view mode first, so the swap doesn't strand CodeMirror or Excalidraw on yesterday's character.
126
+ </div>
127
+ </main>
128
+
129
+ <link rel="stylesheet" href="./excalidraw-wrapper.css">
130
+ <script src="./pict.min.js"></script>
131
+ <!-- Excalidraw vendor bundle (React + Excalidraw). The Diagram InputType
132
+ looks for window.PictSectionExcalidrawVendor when the Portrait field
133
+ flips to edit; without these tags Excalidraw won't mount. -->
134
+ <script src="./react-vendor.min.js"></script>
135
+ <script src="./excalidraw-wrapper.min.js"></script>
136
+ <script src="./superhero_studio_example.min.js"></script>
137
+ <script>
138
+ const _Themes =
139
+ {
140
+ notebook: { ink:'#1B1F23', paper:'#FDFCF7', accent:'#E66C2C', highlight:'#FFD966', deemphasis:'#A0A0A0', link:'#2E7D74' },
141
+ dark: { ink:'#EAEAEA', paper:'#1B1F23', accent:'#FFB570', highlight:'#FFD966', deemphasis:'#666666', link:'#7FC4BD' },
142
+ blueprint: { ink:'#08296B', paper:'#E5F0FB', accent:'#5DA9E9', highlight:'#F4D35E', deemphasis:'#8AA3B6', link:'#1F77B4' },
143
+ sepia: { ink:'#3D2B1F', paper:'#F1E3C9', accent:'#B07043', highlight:'#E2C58B', deemphasis:'#A48A6E', link:'#7A5A36' }
144
+ };
145
+ window.applyTheme = function(pName)
146
+ {
147
+ let tmpStyle = document.getElementById('diagram-theme');
148
+ let tmpT = _Themes[pName] || _Themes.notebook;
149
+ tmpStyle.textContent =
150
+ ':root { ' +
151
+ '--diagram-ink:' + tmpT.ink + ';' +
152
+ '--diagram-paper:' + tmpT.paper + ';' +
153
+ '--diagram-accent:' + tmpT.accent + ';' +
154
+ '--diagram-highlight:' + tmpT.highlight + ';' +
155
+ '--diagram-deemphasis:' + tmpT.deemphasis + ';' +
156
+ '--diagram-link:' + tmpT.link + ';' +
157
+ ' }';
158
+ };
159
+
160
+ Pict.safeOnDocumentReady(() =>
161
+ {
162
+ Pict.safeLoadPictApplication(window.SuperheroStudioExample, 1);
163
+ });
164
+ </script>
165
+ </body>
166
+ </html>
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "superhero_studio_example",
3
+ "version": "1.0.0",
4
+ "description": "Pict-section-form showcase that exercises both new complex InputTypes (RichText for the origin story, Diagram for the portrait) inside a superhero character-sheet form.",
5
+ "main": "SuperheroStudio-Example-Application.js",
6
+ "scripts": {
7
+ "start": "node SuperheroStudio-Example-Application.js",
8
+ "build": "npx quack build && npx quack copy"
9
+ },
10
+ "author": "steven velozo <steven@velozo.com>",
11
+ "license": "MIT",
12
+ "devDependencies": {},
13
+ "copyFilesSettings": {
14
+ "whenFileExists": "overwrite"
15
+ },
16
+ "copyFiles": [
17
+ { "from": "./html/*", "to": "./dist/" },
18
+ { "from": "../../node_modules/pict/dist/*", "to": "./dist/" },
19
+ { "from": "../../node_modules/pict-section-excalidraw/vendor/excalidraw-built/*", "to": "./dist/" }
20
+ ],
21
+ "retold": {
22
+ "ExampleApplication": {
23
+ "Stage": true,
24
+ "Title": "Superhero Studio",
25
+ "Summary": "A character-sheet form that combines both new complex InputTypes — RichText for the origin story (markdown editor + rendered view) and Diagram for the portrait (Excalidraw + inline themed SVG) — alongside stock inputs (Text, Number, Option, TextArea). A dropdown at the top loads five hand-drawn superheroes; each one's portrait recolors when you swap themes. Boots in view-mode, edit on demand.",
26
+ "Complexity": "Advanced"
27
+ }
28
+ }
29
+ }