@dfosco/storyboard 0.5.0-beta.44 → 0.5.0-beta.45

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dfosco/storyboard",
3
- "version": "0.5.0-beta.44",
3
+ "version": "0.5.0-beta.45",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Storyboard prototyping framework — core engine, React integration, and canvas",
@@ -164,6 +164,8 @@ export default function ArtifactForm({
164
164
  setErrors({})
165
165
  }
166
166
 
167
+ const [showAdvanced, setShowAdvanced] = useState(false)
168
+
167
169
  const visibleFields = useMemo(() => {
168
170
  if (!schema) return []
169
171
  if (compact) return schema.fields.filter(f => f.required)
@@ -182,6 +184,18 @@ export default function ArtifactForm({
182
184
  return fields
183
185
  }, [schema, compact, values])
184
186
 
187
+ // Split into basic/advanced. A field with no `tier` defaults to 'basic'
188
+ // (matches the old behaviour for any schema not yet annotated).
189
+ const { basicFields, advancedFields } = useMemo(() => {
190
+ const basic = []
191
+ const advanced = []
192
+ for (const f of visibleFields) {
193
+ if (f.tier === 'advanced') advanced.push(f)
194
+ else basic.push(f)
195
+ }
196
+ return { basicFields: basic, advancedFields: advanced }
197
+ }, [visibleFields])
198
+
185
199
  if (!schema) {
186
200
  return (
187
201
  <Flash variant="warning">
@@ -234,7 +248,7 @@ export default function ArtifactForm({
234
248
  )}
235
249
 
236
250
  <div className={styles.fields}>
237
- {visibleFields.map(field => {
251
+ {basicFields.map(field => {
238
252
  const options = field.dynamic ? dynamicOptions[field.dynamic] : field.options
239
253
  return (
240
254
  <FormControl key={field.name} required={field.required}>
@@ -257,6 +271,43 @@ export default function ArtifactForm({
257
271
  </FormControl>
258
272
  )
259
273
  })}
274
+
275
+ {advancedFields.length > 0 && (
276
+ <>
277
+ <Button
278
+ type="button"
279
+ variant="invisible"
280
+ size="small"
281
+ onClick={() => setShowAdvanced(s => !s)}
282
+ className={styles.advancedToggle}
283
+ >
284
+ {showAdvanced ? '− Hide advanced fields' : '+ Advanced fields'}
285
+ </Button>
286
+ {showAdvanced && advancedFields.map(field => {
287
+ const options = field.dynamic ? dynamicOptions[field.dynamic] : field.options
288
+ return (
289
+ <FormControl key={field.name} required={field.required}>
290
+ <FormControl.Label>{field.label}</FormControl.Label>
291
+ <FieldRenderer
292
+ field={field}
293
+ value={values[field.name]}
294
+ error={errors[field.name]}
295
+ onChange={val => handleChange(field.name, val)}
296
+ options={options}
297
+ />
298
+ {errors[field.name] && (
299
+ <FormControl.Validation variant="error">
300
+ {errors[field.name]}
301
+ </FormControl.Validation>
302
+ )}
303
+ {field.patternHint && !errors[field.name] && (
304
+ <FormControl.Caption>{field.patternHint}</FormControl.Caption>
305
+ )}
306
+ </FormControl>
307
+ )
308
+ })}
309
+ </>
310
+ )}
260
311
  </div>
261
312
 
262
313
  {errors._form && (
@@ -108,3 +108,9 @@
108
108
  padding-top: 0.75rem;
109
109
  border-top: 1px solid var(--borderColor-muted, #d8dee4);
110
110
  }
111
+
112
+ .advancedToggle {
113
+ align-self: flex-start;
114
+ margin-top: 4px;
115
+ color: var(--fgColor-muted);
116
+ }
@@ -14,17 +14,17 @@ export const ARTIFACT_SCHEMAS = {
14
14
  icon: '📐',
15
15
  description: 'Interactive prototype with pages and flows. Add a URL to make it external.',
16
16
  fields: [
17
- { name: 'name', label: 'Name', type: 'text', required: true, placeholder: 'my-app', pattern: NAME_PATTERN, patternHint: NAME_HINT, maxLength: 64 },
18
- { name: 'title', label: 'Title', type: 'text', placeholder: 'My App' },
19
- { name: 'description', label: 'Description', type: 'textarea', placeholder: 'What this prototype demonstrates…' },
20
- { name: 'author', label: 'Author', type: 'text', placeholder: 'dfosco (or comma-separated)' },
21
- { name: 'folder', label: 'Folder', type: 'text', placeholder: 'main (optional .folder grouping)' },
22
- { name: 'partial', label: 'Template / Recipe', type: 'select', placeholder: 'Blank prototype', dynamic: 'partials' },
23
- { name: 'icon', label: 'Icon', type: 'text', placeholder: 'rocket' },
24
- { name: 'tags', label: 'Tags', type: 'text', placeholder: 'design, exploration (comma-separated)' },
25
- { name: 'team', label: 'Team', type: 'text', placeholder: 'design-systems' },
26
- { name: 'url', label: 'External URL', type: 'url', placeholder: 'https://figma.com/… (makes it external)' },
27
- { name: 'flow', label: 'Create default flow', type: 'checkbox', checkboxLabel: 'Generate a default.flow.json' },
17
+ { name: 'name', label: 'Name', type: 'text', required: true, placeholder: 'my-app', pattern: NAME_PATTERN, patternHint: NAME_HINT, maxLength: 64, tier: 'basic' },
18
+ { name: 'title', label: 'Title', type: 'text', placeholder: 'My App', tier: 'basic' },
19
+ { name: 'description', label: 'Description', type: 'textarea', placeholder: 'What this prototype demonstrates…', tier: 'basic' },
20
+ { name: 'url', label: 'External URL', type: 'url', placeholder: 'https://figma.com/… (makes it external)', tier: 'basic' },
21
+ { name: 'partial', label: 'Template / Recipe', type: 'select', placeholder: 'Blank prototype', dynamic: 'partials', tier: 'basic' },
22
+ { name: 'author', label: 'Author', type: 'text', placeholder: 'dfosco (or comma-separated)', tier: 'advanced' },
23
+ { name: 'folder', label: 'Folder', type: 'text', placeholder: 'main (optional .folder grouping)', tier: 'advanced' },
24
+ { name: 'icon', label: 'Icon', type: 'text', placeholder: 'rocket', tier: 'advanced' },
25
+ { name: 'tags', label: 'Tags', type: 'text', placeholder: 'design, exploration (comma-separated)', tier: 'advanced' },
26
+ { name: 'team', label: 'Team', type: 'text', placeholder: 'design-systems', tier: 'advanced' },
27
+ { name: 'flow', label: 'Create default flow', type: 'checkbox', checkboxLabel: 'Generate a default.flow.json', tier: 'advanced' },
28
28
  ],
29
29
  operations: ['create', 'edit', 'delete', 'duplicate'],
30
30
  mutuallyExclusive: [['url', 'flow'], ['url', 'partial']],
@@ -35,10 +35,10 @@ export const ARTIFACT_SCHEMAS = {
35
35
  icon: '🎨',
36
36
  description: 'Freeform spatial canvas for exploration and planning',
37
37
  fields: [
38
- { name: 'name', label: 'Name', type: 'text', required: true, placeholder: 'design-system', pattern: NAME_PATTERN, patternHint: NAME_HINT, maxLength: 64 },
39
- { name: 'title', label: 'Title', type: 'text', placeholder: 'Design Exploration' },
40
- { name: 'description', label: 'Description', type: 'textarea', placeholder: 'Purpose of this canvas…' },
41
- { name: 'folder', label: 'Folder', type: 'text', placeholder: 'storyboarding (optional grouping)' },
38
+ { name: 'name', label: 'Name', type: 'text', required: true, placeholder: 'design-system', pattern: NAME_PATTERN, patternHint: NAME_HINT, maxLength: 64, tier: 'basic' },
39
+ { name: 'title', label: 'Title', type: 'text', placeholder: 'Design Exploration', tier: 'basic' },
40
+ { name: 'description', label: 'Description', type: 'textarea', placeholder: 'Purpose of this canvas…', tier: 'basic' },
41
+ { name: 'folder', label: 'Folder', type: 'text', placeholder: 'storyboarding (optional grouping)', tier: 'advanced' },
42
42
  ],
43
43
  operations: ['create', 'edit', 'delete', 'duplicate'],
44
44
  },
@@ -48,8 +48,8 @@ export const ARTIFACT_SCHEMAS = {
48
48
  icon: '🧩',
49
49
  description: 'Reusable UI component with story file',
50
50
  fields: [
51
- { name: 'name', label: 'Name', type: 'text', required: true, placeholder: 'LoginForm', pattern: '^[A-Z][A-Za-z0-9]+$', patternHint: 'PascalCase (e.g. LoginForm)', maxLength: 64 },
52
- { name: 'directory', label: 'Directory', type: 'text', placeholder: 'src/components (default)' },
51
+ { name: 'name', label: 'Name', type: 'text', required: true, placeholder: 'LoginForm', pattern: '^[A-Z][A-Za-z0-9]+$', patternHint: 'PascalCase (e.g. LoginForm)', maxLength: 64, tier: 'basic' },
52
+ { name: 'directory', label: 'Directory', type: 'text', placeholder: 'src/components (default)', tier: 'advanced' },
53
53
  ],
54
54
  operations: ['create', 'delete'],
55
55
  },
@@ -59,14 +59,14 @@ export const ARTIFACT_SCHEMAS = {
59
59
  icon: '🔀',
60
60
  description: 'Page data context — composes objects via $ref and $global',
61
61
  fields: [
62
- { name: 'name', label: 'Name', type: 'text', required: true, placeholder: 'default', pattern: NAME_PATTERN, patternHint: NAME_HINT, maxLength: 64 },
63
- { name: 'prototype', label: 'Prototype', type: 'select', required: true, options: [], dynamic: 'prototypes' },
64
- { name: 'title', label: 'Title', type: 'text', placeholder: 'Settings Flow' },
65
- { name: 'description', label: 'Description', type: 'textarea', placeholder: 'Data context for…' },
66
- { name: 'globals', label: '$global objects', type: 'text', placeholder: 'navigation, sidebar (comma-separated)' },
67
- { name: 'folder', label: 'Folder', type: 'text', placeholder: 'Optional subfolder' },
68
- { name: 'copyFrom', label: 'Copy from', type: 'text', placeholder: 'Existing flow name to duplicate' },
69
- { name: 'startingPage', label: 'Starting page', type: 'text', placeholder: 'Route to open with this flow' },
62
+ { name: 'name', label: 'Name', type: 'text', required: true, placeholder: 'default', pattern: NAME_PATTERN, patternHint: NAME_HINT, maxLength: 64, tier: 'basic' },
63
+ { name: 'prototype', label: 'Prototype', type: 'select', required: true, options: [], dynamic: 'prototypes', tier: 'basic' },
64
+ { name: 'title', label: 'Title', type: 'text', placeholder: 'Settings Flow', tier: 'basic' },
65
+ { name: 'description', label: 'Description', type: 'textarea', placeholder: 'Data context for…', tier: 'basic' },
66
+ { name: 'globals', label: '$global objects', type: 'text', placeholder: 'navigation, sidebar (comma-separated)', tier: 'advanced' },
67
+ { name: 'folder', label: 'Folder', type: 'text', placeholder: 'Optional subfolder', tier: 'advanced' },
68
+ { name: 'copyFrom', label: 'Copy from', type: 'text', placeholder: 'Existing flow name to duplicate', tier: 'advanced' },
69
+ { name: 'startingPage', label: 'Starting page', type: 'text', placeholder: 'Route to open with this flow', tier: 'advanced' },
70
70
  ],
71
71
  operations: ['create', 'edit', 'delete', 'duplicate'],
72
72
  },
@@ -76,9 +76,9 @@ export const ARTIFACT_SCHEMAS = {
76
76
  icon: '📦',
77
77
  description: 'Reusable data fragment — freeform JSON',
78
78
  fields: [
79
- { name: 'name', label: 'Name', type: 'text', required: true, placeholder: 'jane-doe', pattern: NAME_PATTERN, patternHint: NAME_HINT, maxLength: 64 },
80
- { name: 'folder', label: 'Folder', type: 'text', placeholder: 'Optional folder (or inside prototype for scoping)' },
81
- { name: 'body', label: 'JSON Body', type: 'code', placeholder: '{\n "name": "Jane Doe",\n "role": "admin"\n}', language: 'json' },
79
+ { name: 'name', label: 'Name', type: 'text', required: true, placeholder: 'jane-doe', pattern: NAME_PATTERN, patternHint: NAME_HINT, maxLength: 64, tier: 'basic' },
80
+ { name: 'body', label: 'JSON Body', type: 'code', placeholder: '{\n "name": "Jane Doe",\n "role": "admin"\n}', language: 'json', tier: 'basic' },
81
+ { name: 'folder', label: 'Folder', type: 'text', placeholder: 'Optional folder (or inside prototype for scoping)', tier: 'advanced' },
82
82
  ],
83
83
  operations: ['create', 'edit', 'delete', 'duplicate'],
84
84
  },
@@ -88,9 +88,9 @@ export const ARTIFACT_SCHEMAS = {
88
88
  icon: '📋',
89
89
  description: 'Collection of entries — array of objects with unique id',
90
90
  fields: [
91
- { name: 'name', label: 'Name', type: 'text', required: true, placeholder: 'posts', pattern: NAME_PATTERN, patternHint: NAME_HINT, maxLength: 64 },
92
- { name: 'folder', label: 'Folder', type: 'text', placeholder: 'Optional folder' },
93
- { name: 'body', label: 'Entries (JSON array)', type: 'code', placeholder: '[\n { "id": "first", "title": "First Entry" }\n]', language: 'json' },
91
+ { name: 'name', label: 'Name', type: 'text', required: true, placeholder: 'posts', pattern: NAME_PATTERN, patternHint: NAME_HINT, maxLength: 64, tier: 'basic' },
92
+ { name: 'body', label: 'Entries (JSON array)', type: 'code', placeholder: '[\n { "id": "first", "title": "First Entry" }\n]', language: 'json', tier: 'basic' },
93
+ { name: 'folder', label: 'Folder', type: 'text', placeholder: 'Optional folder', tier: 'advanced' },
94
94
  ],
95
95
  operations: ['create', 'edit', 'delete'],
96
96
  },
@@ -100,10 +100,10 @@ export const ARTIFACT_SCHEMAS = {
100
100
  icon: '📄',
101
101
  description: 'A page inside an existing prototype',
102
102
  fields: [
103
- { name: 'prototype', label: 'Prototype', type: 'select', required: true, options: [], dynamic: 'prototypes' },
104
- { name: 'path', label: 'Path', type: 'text', required: true, placeholder: 'settings/general', pattern: '^[a-z0-9][a-z0-9-/]*$', patternHint: 'Lowercase path with slashes (e.g. settings/general)' },
105
- { name: 'folder', label: 'Folder', type: 'text', placeholder: 'Optional subfolder within prototype' },
106
- { name: 'template', label: 'Template', type: 'text', placeholder: 'Template page to copy from' },
103
+ { name: 'prototype', label: 'Prototype', type: 'select', required: true, options: [], dynamic: 'prototypes', tier: 'basic' },
104
+ { name: 'path', label: 'Path', type: 'text', required: true, placeholder: 'settings/general', pattern: '^[a-z0-9][a-z0-9-/]*$', patternHint: 'Lowercase path with slashes (e.g. settings/general)', tier: 'basic' },
105
+ { name: 'folder', label: 'Folder', type: 'text', placeholder: 'Optional subfolder within prototype', tier: 'advanced' },
106
+ { name: 'template', label: 'Template', type: 'text', placeholder: 'Template page to copy from', tier: 'advanced' },
107
107
  ],
108
108
  operations: ['create', 'delete'],
109
109
  },