@xeplr/ui-factory 1.6.0 → 1.7.1

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
@@ -382,6 +382,13 @@ const flows = createFlowsApi({ fetch: authFetch, base: '/api/workflow' })
382
382
  - Approvals (another person's turn, with an assignee and a timeout) are not
383
383
  part of this designer.
384
384
 
385
+ An app page needs only its two API clients — the flow and the forms are
386
+ loaded for it:
387
+
388
+ ```jsx
389
+ <FlowDesignerPage factory={factory} flows={flows} flowKey={key} urlKey="flow" />
390
+ ```
391
+
385
392
  Controllers, for a design of your own: `useFlowBuilder` (the flow, plus
386
393
  `navigationOf` / `setNavigation`), `useScreenEvents` (one screen's events,
387
394
  `adopt` to share its draft with a builder), `useFunctionCatalog` (the app's
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xeplr/ui-factory",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
4
4
  "description": "Design data-entry screens on @xeplr/ui-canvas, save them as JSON, run them as auto-saving forms with lists of saved records — built for Claude to draft and people to refine",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -31,4 +31,4 @@ export { BuilderSample, ScreenSample, ListView, ScreenModal, FlowRunnerSample, F
31
31
  export { FactoryHooks } from './hooks.js'
32
32
 
33
33
  // Ready-made
34
- export { FactoryBuilder, FactoryScreen, FlowRunner, FlowBuilder, FlowDesigner } from './pages.jsx'
34
+ export { FactoryBuilder, FactoryScreen, FlowRunner, FlowBuilder, FlowDesigner, FlowDesignerPage } from './pages.jsx'
package/src/pages.jsx CHANGED
@@ -1,4 +1,4 @@
1
- import { useRef } from 'react'
1
+ import { useEffect, useRef, useState } from 'react'
2
2
  import { useFactoryBuilder } from './useFactoryBuilder.js'
3
3
  import { useFactoryScreen } from './useFactoryScreen.js'
4
4
  import { useFlowRun } from './useFlowRun.js'
@@ -6,6 +6,7 @@ import { useFlowBuilder } from './useFlowBuilder.js'
6
6
  import { useScreenEvents } from './useScreenEvents.js'
7
7
  import { useFunctionCatalog } from './useFunctionCatalog.js'
8
8
  import { useUrlTab } from './useUrlPlaces.js'
9
+ import { loadScreens } from './screenSource.js'
9
10
  import { BuilderSample, ScreenSample, ScreenModal, FlowRunnerSample, FlowBuilderSample, FlowDesignerSample } from './designs/index.js'
10
11
 
11
12
  /**
@@ -269,3 +270,52 @@ export function FlowDesigner(props) {
269
270
  />
270
271
  )
271
272
  }
273
+
274
+ /**
275
+ * <FlowDesigner>, wired to an app's two API clients — what an app's
276
+ * /configure/flows/:key page renders, so the wiring lives here and not, copied
277
+ * and drifting, in every generated app.
278
+ *
279
+ * Loads the flow and the app's FORMS (screens with fields of their own — a
280
+ * step shows one to be filled in) and hands everything else straight on.
281
+ *
282
+ * @prop factory createFactoryApi(…) — screens, drafts, publish, the app's functions
283
+ * @prop flows createFlowsApi(…) — load, save, publish the flow
284
+ * @prop flowKey the flow to open
285
+ * @prop urlKey keep the selected step and tab in the URL
286
+ */
287
+ export function FlowDesignerPage({ factory, flows, flowKey, urlKey, className, style }) {
288
+ const [flow, setFlow] = useState(null)
289
+ const [screens, setScreens] = useState(null)
290
+ const [error, setError] = useState(null)
291
+ useEffect(() => {
292
+ let gone = false
293
+ setFlow(null); setError(null)
294
+ Promise.all([flows.loadFlow(flowKey), loadScreens(factory)]).then(([f, list]) => {
295
+ if (gone) return
296
+ setFlow(f)
297
+ setScreens(list.filter((s) => s.fields && s.fields.length).map((s) => ({ id: s.key, name: s.name })))
298
+ }, (e) => { if (!gone) setError(e.message || `Could not open "${flowKey}"`) })
299
+ return () => { gone = true }
300
+ }, [factory, flows, flowKey])
301
+
302
+ if (error) return <div className="xeplr-factory-invalid" role="alert">{error}</div>
303
+ if (!flow || !screens) return <div className="xeplr-factory-hint">Opening the flow…</div>
304
+ return (
305
+ <FlowDesigner
306
+ flow={flow}
307
+ screens={screens}
308
+ loadScreen={factory.loadScreen}
309
+ onSave={flows.saveFlow}
310
+ onPublish={flows.publishFlow}
311
+ listFunctions={factory.listFunctions}
312
+ loadDraft={factory.loadDraft}
313
+ saveDraft={factory.saveDraft}
314
+ publishScreen={factory.publish}
315
+ builderProps={factory.builderProps}
316
+ urlKey={urlKey}
317
+ className={className}
318
+ style={style}
319
+ />
320
+ )
321
+ }