@pixel-point/toolcraft 0.0.16 → 0.0.18
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 +1 -1
- package/src/generate-performance-iteration-execution.test.mjs +2 -2
- package/src/generate-test-demand-only-lifecycle.mjs +14 -3
- package/src/generate-test-dependency-sandbox.mjs +42 -5
- package/src/generate-test-doc-assertions.mjs +109 -69
- package/src/generate-test-doc-assertions.test.mjs +65 -0
- package/src/generate-test-doc-policy-assertions.mjs +92 -0
- package/src/generate-test-file-assertions.mjs +36 -118
- package/src/generate-test-output-assertions.mjs +95 -0
- package/src/generate-test-package-assertions.mjs +6 -0
- package/src/generate-test-performance-boundary-assertions.mjs +45 -0
- package/src/generate-test-product-fixture.mjs +1 -0
- package/src/generate-test-product-fixture.test.mjs +18 -0
- package/src/generate-test-product-iteration.mjs +1 -0
- package/src/generate-test-product-iteration.test.mjs +18 -0
- package/src/generate-test-runtime-boundary-assertions.mjs +158 -0
- package/src/generate-test-standalone-assertions.mjs +10 -0
- package/src/generate-test-standalone-delivery-stages.mjs +14 -6
- package/src/generate.test.mjs +14 -0
- package/templates/runtime/contracts/component-contracts.choices.test.ts +59 -12
- package/templates/runtime/contracts/component-contracts.choices.ts +58 -12
- package/templates/runtime/contracts/component-contracts.inputs.test.ts +6 -6
- package/templates/runtime/contracts/component-contracts.inputs.ts +6 -6
- package/templates/runtime/contracts/component-contracts.media-custom.test.ts +8 -2
- package/templates/runtime/contracts/component-contracts.media-custom.ts +8 -2
- package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +21 -6
- package/templates/runtime/contracts/component-contracts.runtime-labels.test.ts +7 -1
- package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +4 -1
- package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +4 -1
- package/templates/runtime/contracts/component-contracts.runtime.ts +15 -10
- package/templates/runtime/contracts/component-contracts.test.ts +2 -0
- package/templates/runtime/contracts/decision-contracts.test.ts +43 -4
- package/templates/runtime/contracts/decision-contracts.ts +10 -10
- package/templates/runtime/contracts/performance-verification-policy.test.ts +59 -6
- package/templates/runtime/contracts/performance-verification-policy.ts +5 -2
- package/templates/runtime/export/artifact-download.test.ts +71 -0
- package/templates/runtime/export/artifact-download.ts +80 -0
- package/templates/runtime/export/artifact-export-request.ts +23 -0
- package/templates/runtime/export/artifact-export-settings.test.ts +75 -0
- package/templates/runtime/export/artifact-export-settings.ts +96 -0
- package/templates/runtime/export/artifact-frame-renderer.test.ts +107 -0
- package/templates/runtime/export/artifact-frame-renderer.ts +96 -0
- package/templates/runtime/export/artifact-frame-state.test.ts +54 -0
- package/templates/runtime/export/artifact-frame-state.ts +44 -0
- package/templates/runtime/export/artifact-scene-frame.test.ts +84 -0
- package/templates/runtime/export/artifact-scene-frame.ts +118 -0
- package/templates/runtime/export/export-background.ts +46 -0
- package/templates/runtime/export/export-error.ts +43 -0
- package/templates/runtime/export/export.test.ts +49 -226
- package/templates/runtime/export/image-artifact-export.test.ts +111 -0
- package/templates/runtime/export/image-artifact-export.ts +145 -0
- package/templates/runtime/export/index.ts +44 -3
- package/templates/runtime/export/product-export-renderer.test.ts +77 -0
- package/templates/runtime/export/product-export-renderer.ts +63 -0
- package/templates/runtime/export/video-artifact-export.test.ts +166 -0
- package/templates/runtime/export/video-artifact-export.ts +164 -0
- package/templates/runtime/export/video-encoding-backend.ts +124 -0
- package/templates/runtime/export/video-encoding-policy.test.ts +68 -0
- package/templates/runtime/export/video-encoding-policy.ts +86 -0
- package/templates/runtime/export/video-frame-schedule.test.ts +58 -0
- package/templates/runtime/export/video-frame-schedule.ts +42 -0
- package/templates/runtime/index.ts +3 -0
- package/templates/runtime/model-import/model-import-limits.ts +15 -4
- package/templates/runtime/react/app-shell/runtime-public-api-runtime.test.tsx +291 -0
- package/templates/runtime/react/app-shell/runtime-public-api-test-support.ts +21 -0
- package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +15 -304
- package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +41 -27
- package/templates/runtime/react/app-shell/toolcraft-app.tsx +39 -11
- package/templates/runtime/react/app-shell/toolcraft-source-asset-context.test.tsx +16 -57
- package/templates/runtime/react/app-shell/toolcraft-source-asset-context.tsx +75 -434
- package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.test.ts +194 -0
- package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.ts +227 -0
- package/templates/runtime/react/app-shell/toolcraft-source-asset-provider-ownership.test.tsx +243 -0
- package/templates/runtime/react/app-shell/toolcraft-source-asset-test-support.ts +51 -0
- package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.test.ts +138 -0
- package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.ts +378 -0
- package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +76 -0
- package/templates/runtime/react/canvas/canvas-shell-test-utils.tsx +13 -1
- package/templates/runtime/react/canvas/canvas-shell.tsx +16 -1
- package/templates/runtime/react/canvas/product-scene-surface.test.tsx +195 -0
- package/templates/runtime/react/canvas/product-scene-surface.tsx +155 -0
- package/templates/runtime/react/canvas/runtime-scene-export.ts +1 -1
- package/templates/runtime/react/controls-panel/__tests__/control-conditions.test.ts +61 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.collection-actions.test.tsx +89 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.control-visibility.test.tsx +40 -19
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.footer-actions.test.tsx +7 -12
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +18 -84
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +62 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +67 -0
- package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +43 -87
- package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +68 -0
- package/templates/runtime/react/controls-panel/conditions/control-conditions.ts +32 -119
- package/templates/runtime/react/controls-panel/layout/controls-panel-control-group.tsx +5 -2
- package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +10 -8
- package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +3 -3
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.test.tsx +63 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.tsx +138 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-items.tsx +104 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-renderer.tsx +115 -236
- package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.test.tsx +95 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.tsx +82 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.test.tsx +73 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.tsx +50 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.test.ts +1 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.ts +2 -1
- package/templates/runtime/react/controls-panel/values/controls-panel-collection-values.ts +38 -6
- package/templates/runtime/react/controls-panel/values/controls-panel-value-labels.ts +1 -0
- package/templates/runtime/react/index.ts +4 -0
- package/templates/runtime/react/model-rendering/model-export.ts +1 -1
- package/templates/runtime/react/orientation-gizmo/orientation-gizmo-selection.ts +5 -5
- package/templates/runtime/react/orientation-gizmo/use-toolcraft-orientation-control-selection.ts +2 -2
- package/templates/runtime/react/panel-host/panel-host-runtime-placement.test.tsx +30 -0
- package/templates/runtime/react/panel-host/panel-host.tsx +4 -0
- package/templates/runtime/scene/scene-bounds.test.ts +23 -0
- package/templates/runtime/scene/scene-bounds.ts +32 -19
- package/templates/runtime/schema/app-capabilities.test.ts +4 -0
- package/templates/runtime/schema/canvas-render-scale.ts +62 -0
- package/templates/runtime/schema/collection-item-controls.ts +29 -0
- package/templates/runtime/schema/control-applicability.test.ts +127 -0
- package/templates/runtime/schema/control-applicability.ts +433 -0
- package/templates/runtime/schema/control-schema-normalization.ts +177 -11
- package/templates/runtime/schema/controls-panel-actions.ts +2 -2
- package/templates/runtime/schema/controls-panel-section-id.test.ts +1 -1
- package/templates/runtime/schema/controls-panel-section-layout.ts +14 -9
- package/templates/runtime/schema/controls-panel-section-roundtrip.test.ts +62 -3
- package/templates/runtime/schema/define-toolcraft.collection-actions-item-controls.test.ts +127 -0
- package/templates/runtime/schema/define-toolcraft.control-sections.test.ts +10 -4
- package/templates/runtime/schema/define-toolcraft.file-drop-item-controls.test.ts +98 -0
- package/templates/runtime/schema/define-toolcraft.file-drop-normalization.test.ts +27 -0
- package/templates/runtime/schema/define-toolcraft.segmented-control-fit.test.ts +20 -2
- package/templates/runtime/schema/define-toolcraft.setup-background.test.ts +1 -1
- package/templates/runtime/schema/define-toolcraft.setup-canvas.test.ts +16 -3
- package/templates/runtime/schema/define-toolcraft.setup-render-scale-timeline.test.ts +71 -3
- package/templates/runtime/schema/define-toolcraft.source-collection.test.ts +79 -0
- package/templates/runtime/schema/define-toolcraft.ts +1 -1
- package/templates/runtime/schema/runtime-setup-section.ts +24 -5
- package/templates/runtime/schema/schema-resolvers.ts +0 -56
- package/templates/runtime/schema/types.ts +72 -17
- package/templates/runtime/state/canvas-background-state.ts +6 -0
- package/templates/runtime/testing/performance-render-plan-integration.test.ts +64 -0
- package/templates/runtime/testing/performance-renderer-pipeline-validation.ts +18 -1
- package/templates/starter/AGENTS.md +18 -15
- package/templates/starter/NOTICE.md +6 -0
- package/templates/starter/docs/toolcraft/README.md +2 -1
- package/templates/starter/docs/toolcraft/acceptance-testing.md +23 -35
- package/templates/starter/docs/toolcraft/agent-worklog.md +18 -3
- package/templates/starter/docs/toolcraft/assembly-workflow.md +13 -5
- package/templates/starter/docs/toolcraft/component-rules.md +8 -6
- package/templates/starter/docs/toolcraft/core/control-selection.md +9 -3
- package/templates/starter/docs/toolcraft/core/layout.md +7 -7
- package/templates/starter/docs/toolcraft/core/media-upload.md +4 -2
- package/templates/starter/docs/toolcraft/core/performance.md +14 -3
- package/templates/starter/docs/toolcraft/core/runtime-boundary.md +16 -3
- package/templates/starter/docs/toolcraft/core/setup-export.md +49 -19
- package/templates/starter/docs/toolcraft/core/timeline-animation.md +4 -4
- package/templates/starter/docs/toolcraft/custom-controls.md +6 -4
- package/templates/starter/docs/toolcraft/decision-contract.md +3 -1
- package/templates/starter/docs/toolcraft/performance.md +20 -6
- package/templates/starter/docs/toolcraft/renderer-technique.md +5 -1
- package/templates/starter/docs/toolcraft/schema-reference.md +23 -25
- package/templates/starter/docs/toolcraft/workflow.md +7 -2
- package/templates/starter/e2e/app-browser-control-applicability-requirements.spec.ts +163 -0
- package/templates/starter/e2e/app-browser-control-coverage.spec.ts +33 -0
- package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +50 -3
- package/templates/starter/e2e/app-browser-orientation-evidence.spec.ts +174 -21
- package/templates/starter/e2e/app-browser-render-scale-evidence.spec.ts +60 -6
- package/templates/starter/e2e/app-browser-render-scale-requirements.spec.ts +77 -1
- package/templates/starter/e2e/app-browser-runtime-provenance.spec.ts +8 -0
- package/templates/starter/e2e/app-browser-runtime-reporter.spec.ts +35 -0
- package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +5 -34
- package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +61 -16
- package/templates/starter/e2e/app-browser-shell.spec.ts +13 -5
- package/templates/starter/e2e/app-performance-path-adapters.ts +8 -1
- package/templates/starter/e2e/app-performance.spec.ts +16 -9
- package/templates/starter/e2e/{browser-conditional-output-evidence-helpers.ts → browser-background-output-evidence.ts} +0 -68
- package/templates/starter/e2e/browser-control-applicability-evidence.ts +114 -0
- package/templates/starter/e2e/browser-infinity-canvas-evidence.ts +29 -341
- package/templates/starter/e2e/browser-infinity-canvas-unavailable-image-evidence.ts +370 -0
- package/templates/starter/e2e/browser-media-export-evidence.spec.ts +77 -0
- package/templates/starter/e2e/browser-media-export-evidence.ts +208 -0
- package/templates/starter/e2e/browser-orientation-gizmo-evidence-helpers.ts +4 -0
- package/templates/starter/e2e/browser-orientation-gizmo-live-preconditions.ts +86 -0
- package/templates/starter/e2e/browser-render-scale-evidence.ts +37 -29
- package/templates/starter/e2e/browser-runtime-applicability-requirements.ts +84 -0
- package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +13 -3
- package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +72 -35
- package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +25 -0
- package/templates/starter/e2e/browser-standard-timeline-evidence.ts +106 -0
- package/templates/starter/e2e/decoded-pixel-observation.spec.ts +74 -0
- package/templates/starter/e2e/decoded-pixel-observation.ts +227 -0
- package/templates/starter/e2e/export-artifact-helpers.ts +206 -25
- package/templates/starter/e2e/image-artifact-inspection.spec.ts +41 -0
- package/templates/starter/e2e/image-artifact-inspection.ts +99 -0
- package/templates/starter/e2e/performance-canvas-helpers.ts +22 -21
- package/templates/starter/e2e/performance-canvas-quality-guard.spec.ts +312 -0
- package/templates/starter/e2e/performance-canvas-quality-guard.ts +196 -0
- package/templates/starter/e2e/performance-canvas-quality-observer.ts +351 -0
- package/templates/starter/e2e/performance-control-layout-helpers.ts +2 -2
- package/templates/starter/e2e/performance-path-adapter-contract.ts +4 -4
- package/templates/starter/e2e/performance-path-helpers.spec.ts +203 -70
- package/templates/starter/e2e/performance-path-helpers.ts +210 -91
- package/templates/starter/e2e/performance-pipeline-evidence-continuity.spec.ts +76 -0
- package/templates/starter/e2e/performance-pipeline-evidence-test-fixtures.ts +11 -2
- package/templates/starter/e2e/performance-pipeline-invariants.ts +47 -4
- package/templates/starter/e2e/performance-render-scale-runner.spec.ts +140 -38
- package/templates/starter/e2e/video-artifact-inspection.spec.ts +64 -0
- package/templates/starter/e2e/video-artifact-inspection.ts +281 -0
- package/templates/starter/gitignore +1 -0
- package/templates/starter/package.json +1 -0
- package/templates/starter/scripts/check-toolcraft-docs.mjs +17 -0
- package/templates/starter/scripts/toolcraft-contract-manifest.json +1 -0
- package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +60 -0
- package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +7 -2
- package/templates/starter/scripts/toolcraft-delivery-plan.mjs +7 -3
- package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +95 -103
- package/templates/starter/scripts/toolcraft-product-boundary-module-policy.mjs +101 -0
- package/templates/starter/scripts/toolcraft-product-boundary.mjs +12 -0
- package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +0 -26
- package/templates/starter/scripts/toolcraft-product-control-bindings.mjs +182 -0
- package/templates/starter/scripts/toolcraft-product-control-boundary.mjs +146 -0
- package/templates/starter/scripts/toolcraft-product-control-boundary.test.mjs +186 -0
- package/templates/starter/scripts/toolcraft-product-evidence-boundary.test.mjs +85 -20
- package/templates/starter/scripts/toolcraft-product-evidence-import-policy.mjs +43 -0
- package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +157 -0
- package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +196 -0
- package/templates/starter/scripts/toolcraft-typescript-analysis.d.mts +73 -0
- package/templates/starter/scripts/toolcraft-typescript-source-evidence-structure.test.mjs +20 -0
- package/templates/starter/scripts/toolcraft-typescript-source-evidence.mjs +1 -0
- package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade-test-helpers.mjs +318 -0
- package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade.test.mjs +157 -206
- package/templates/starter/scripts/toolcraft-verification-inventory.mjs +1 -0
- package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +51 -0
- package/templates/starter/scripts/toolcraft-vite-env-activation.test.mjs +128 -59
- package/templates/starter/src/app/acceptance/artifact-export-intent.ts +130 -0
- package/templates/starter/src/app/acceptance/conditions.ts +1 -1
- package/templates/starter/src/app/acceptance/control-acceptance-context.ts +2 -2
- package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +6 -20
- package/templates/starter/src/app/acceptance/control-acceptance-kind-rules.ts +24 -5
- package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +2 -13
- package/templates/starter/src/app/acceptance/control-applicability-cases.test.ts +321 -0
- package/templates/starter/src/app/acceptance/control-applicability-cases.ts +290 -0
- package/templates/starter/src/app/acceptance/control-applicability.ts +332 -0
- package/templates/starter/src/app/acceptance/control-layout-dependency-rules.ts +20 -9
- package/templates/starter/src/app/acceptance/control-layout-entity-rules.ts +4 -6
- package/templates/starter/src/app/acceptance/control-layout-model.ts +4 -4
- package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +3 -10
- package/templates/starter/src/app/acceptance/control-parts.ts +8 -0
- package/templates/starter/src/app/acceptance/control-section-entity-cohesion.test.ts +215 -0
- package/templates/starter/src/app/acceptance/control-section-entity-cohesion.ts +132 -0
- package/templates/starter/src/app/acceptance/control-section-inventory.test.ts +87 -0
- package/templates/starter/src/app/acceptance/control-section-inventory.ts +74 -44
- package/templates/starter/src/app/acceptance/custom-controls.ts +11 -3
- package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +113 -0
- package/templates/starter/src/app/acceptance/inline-layout.ts +64 -9
- package/templates/starter/src/app/acceptance/media-upload.ts +5 -1
- package/templates/starter/src/app/acceptance/orientation-gizmo.ts +18 -11
- package/templates/starter/src/app/acceptance/output-background-rules.ts +2 -2
- package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +18 -10
- package/templates/starter/src/app/acceptance/output-export-model.ts +54 -11
- package/templates/starter/src/app/acceptance/output-export.ts +35 -12
- package/templates/starter/src/app/acceptance/output-video-export-rules.ts +99 -0
- package/templates/starter/src/app/acceptance/types.ts +30 -8
- package/templates/starter/src/app/acceptance/validate-coverage.ts +20 -2
- package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +239 -0
- package/templates/starter/src/app/starter-acceptance.background-export.test.ts +33 -0
- package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +16 -1
- package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +65 -0
- package/templates/starter/src/app/starter-acceptance.contract-fixtures.test.ts +41 -0
- package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +112 -16
- package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +224 -0
- package/templates/starter/src/app/starter-acceptance.control-order.test.ts +58 -3
- package/templates/starter/src/app/starter-acceptance.control-state.test.ts +0 -111
- package/templates/starter/src/app/starter-acceptance.custom-control-collections.test.ts +3 -1
- package/templates/starter/src/app/starter-acceptance.custom-control-valid.test.ts +1 -1
- package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +131 -0
- package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +22 -0
- package/templates/starter/src/app/{starter-acceptance.image-video-export-settings.test.ts → starter-acceptance.image-export-settings.test.ts} +37 -9
- package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +12 -0
- package/templates/starter/src/app/starter-acceptance.keyframes.test.ts +14 -4
- package/templates/starter/src/app/starter-acceptance.media-upload.fixtures.ts +11 -1
- package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +28 -0
- package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +384 -0
- package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +46 -1
- package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +112 -105
- package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +12 -0
- package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +1 -1
- package/templates/starter/src/app/starter-acceptance.section-dependencies.test.ts +35 -24
- package/templates/starter/src/app/starter-acceptance.section-size.test.ts +72 -0
- package/templates/starter/src/app/starter-acceptance.ts +13 -2
- package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +336 -0
- package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +8 -0
- package/templates/starter/src/app/starter-performance-test-utils.ts +103 -0
- package/templates/starter/src/app/starter-performance.gates.test.ts +231 -278
- package/templates/starter/src/app/starter-performance.lifecycle.test.ts +261 -0
- package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +4 -2
- package/templates/starter/src/routes/index.tsx +2 -0
- package/templates/ui/components/composites/tabs.tsx +2 -2
- package/templates/ui/components/controls/collection-actions/collection-item-groups.test.tsx +38 -0
- package/templates/ui/components/controls/collection-actions/collection-item-groups.tsx +36 -0
- package/templates/ui/components/controls/collection-actions/index.ts +2 -0
- package/templates/ui/components/controls/file-drop/file-drop-collection-control.tsx +137 -0
- package/templates/ui/components/controls/file-drop/file-drop-control.test.tsx +189 -0
- package/templates/ui/components/controls/file-drop/file-drop-control.tsx +81 -88
- package/templates/ui/components/controls/file-drop/file-drop-presentation.tsx +131 -9
- package/templates/ui/components/controls/file-drop/file-drop-types.ts +36 -22
- package/templates/ui/components/controls/file-drop/index.ts +1 -0
- package/templates/ui/components/controls/index.ts +3 -0
- package/templates/ui/components/controls/range-slider/range-slider-control.tsx +1 -1
- package/templates/ui/components/controls/range-slider/range-slider-value.test.ts +14 -0
- package/templates/ui/components/controls/range-slider/range-slider-value.ts +3 -2
- package/templates/runtime/export/export.ts +0 -166
- package/templates/starter/src/app/acceptance/condition-exclusivity.test.ts +0 -60
- package/templates/starter/src/app/acceptance/condition-exclusivity.ts +0 -221
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ResolvedToolcraftAppSchema,
|
|
3
|
+
ToolcraftActionSchema,
|
|
4
|
+
} from "@repo/toolcraft-runtime";
|
|
5
|
+
|
|
6
|
+
import { getControlActions } from "./actions";
|
|
7
|
+
import type {
|
|
8
|
+
ToolcraftComponentAcceptance,
|
|
9
|
+
ToolcraftExportArtifactCoverage,
|
|
10
|
+
} from "./types";
|
|
11
|
+
|
|
12
|
+
const requiredCoverageByRole = {
|
|
13
|
+
"export-image": "all-required-image-export-behavior",
|
|
14
|
+
"export-video": "all-required-video-export-behavior",
|
|
15
|
+
} as const satisfies Record<
|
|
16
|
+
"export-image" | "export-video",
|
|
17
|
+
ToolcraftExportArtifactCoverage
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
function getCoverageValues(
|
|
21
|
+
entry: ToolcraftComponentAcceptance,
|
|
22
|
+
): readonly ToolcraftExportArtifactCoverage[] {
|
|
23
|
+
if (!entry.exportArtifactCoverage) return [];
|
|
24
|
+
return typeof entry.exportArtifactCoverage === "string"
|
|
25
|
+
? [entry.exportArtifactCoverage]
|
|
26
|
+
: entry.exportArtifactCoverage;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isMediaExportAction(
|
|
30
|
+
action: ToolcraftActionSchema | string,
|
|
31
|
+
): action is ToolcraftActionSchema & {
|
|
32
|
+
role: "export-image" | "export-video";
|
|
33
|
+
} {
|
|
34
|
+
return (
|
|
35
|
+
typeof action !== "string" &&
|
|
36
|
+
(action.role === "export-image" || action.role === "export-video")
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function collectMediaExportActions(schema: ResolvedToolcraftAppSchema) {
|
|
41
|
+
return (schema.panels.controls?.sections ?? []).flatMap((section) =>
|
|
42
|
+
Object.values(section.controls).flatMap((control) =>
|
|
43
|
+
control.type !== "panelActions" || !control.target
|
|
44
|
+
? []
|
|
45
|
+
: getControlActions(control)
|
|
46
|
+
.filter(isMediaExportAction)
|
|
47
|
+
.map((action) => ({
|
|
48
|
+
requiredCoverage: requiredCoverageByRole[action.role],
|
|
49
|
+
role: action.role,
|
|
50
|
+
target: control.target,
|
|
51
|
+
value: action.value,
|
|
52
|
+
})),
|
|
53
|
+
),
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function getToolcraftExportArtifactCoverageErrors({
|
|
58
|
+
acceptance,
|
|
59
|
+
schema,
|
|
60
|
+
}: Readonly<{
|
|
61
|
+
acceptance: readonly ToolcraftComponentAcceptance[];
|
|
62
|
+
schema: ResolvedToolcraftAppSchema;
|
|
63
|
+
}>): string[] {
|
|
64
|
+
const errors: string[] = [];
|
|
65
|
+
const exportActions = collectMediaExportActions(schema);
|
|
66
|
+
|
|
67
|
+
for (const entry of acceptance) {
|
|
68
|
+
const coverage = getCoverageValues(entry);
|
|
69
|
+
if (coverage.length === 0) continue;
|
|
70
|
+
if (entry.evidence !== "exported-bytes") {
|
|
71
|
+
errors.push(
|
|
72
|
+
`Acceptance "${entry.id}" declares exportArtifactCoverage but evidence is not "exported-bytes".`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
if (!entry.automated || !entry.browser) {
|
|
76
|
+
errors.push(
|
|
77
|
+
`Acceptance "${entry.id}" exportArtifactCoverage requires automated and browser proof.`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
for (const value of coverage) {
|
|
81
|
+
const hasMatchingAction = exportActions.some(
|
|
82
|
+
(action) =>
|
|
83
|
+
action.target === entry.target &&
|
|
84
|
+
action.requiredCoverage === value &&
|
|
85
|
+
(entry.actionCoverage ?? []).includes(action.value),
|
|
86
|
+
);
|
|
87
|
+
if (!hasMatchingAction) {
|
|
88
|
+
errors.push(
|
|
89
|
+
`Acceptance "${entry.id}" declares ${value} without a matching typed export action in target/actionCoverage.`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const action of exportActions) {
|
|
96
|
+
const hasCoverage = acceptance.some(
|
|
97
|
+
(entry) =>
|
|
98
|
+
entry.target === action.target &&
|
|
99
|
+
entry.evidence === "exported-bytes" &&
|
|
100
|
+
entry.automated &&
|
|
101
|
+
entry.browser &&
|
|
102
|
+
(entry.actionCoverage ?? []).includes(action.value) &&
|
|
103
|
+
getCoverageValues(entry).includes(action.requiredCoverage),
|
|
104
|
+
);
|
|
105
|
+
if (!hasCoverage) {
|
|
106
|
+
errors.push(
|
|
107
|
+
`Typed ${action.role} action "${action.value}" on "${action.target}" requires ${action.requiredCoverage} acceptance coverage.`,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return errors;
|
|
113
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
ResolvedToolcraftAppSchema,
|
|
3
|
-
ResolvedToolcraftControlSchema,
|
|
4
|
-
ToolcraftControlSchema,
|
|
1
|
+
import {
|
|
2
|
+
type ResolvedToolcraftAppSchema,
|
|
3
|
+
type ResolvedToolcraftControlSchema,
|
|
4
|
+
type ToolcraftControlSchema,
|
|
5
5
|
} from "@repo/toolcraft-runtime";
|
|
6
6
|
|
|
7
7
|
import {
|
|
@@ -9,10 +9,23 @@ import {
|
|
|
9
9
|
isToolcraftProductSectionControl,
|
|
10
10
|
} from "./controls";
|
|
11
11
|
import { getToolcraftSectionLabel } from "./sections";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
getToolcraftLooseTargetPrefix,
|
|
14
|
+
normalizeToolcraftSemanticText,
|
|
15
|
+
} from "./semantic";
|
|
13
16
|
|
|
14
17
|
const maxInlineSwitchLabelLength = 16;
|
|
15
18
|
const maxInlineSwitchLabelWordCount = 2;
|
|
19
|
+
const normalizedVideoExportSectionTitle =
|
|
20
|
+
normalizeToolcraftSemanticText("Video Export");
|
|
21
|
+
|
|
22
|
+
type ToolcraftControlsSection = NonNullable<
|
|
23
|
+
ResolvedToolcraftAppSchema["panels"]["controls"]
|
|
24
|
+
>["sections"][number];
|
|
25
|
+
|
|
26
|
+
type ToolcraftControlLayoutGroup = NonNullable<
|
|
27
|
+
ToolcraftControlsSection["layoutGroups"]
|
|
28
|
+
>[number];
|
|
16
29
|
|
|
17
30
|
function getInlineSwitchLabelText(
|
|
18
31
|
controlId: string,
|
|
@@ -56,8 +69,42 @@ function controlsShareToolcraftTargetEntity(
|
|
|
56
69
|
return Boolean(firstPrefix && firstPrefix === secondPrefix);
|
|
57
70
|
}
|
|
58
71
|
|
|
72
|
+
function isToolcraftVideoExportSegmentedInlinePair({
|
|
73
|
+
layoutGroup,
|
|
74
|
+
section,
|
|
75
|
+
segmentedControlId,
|
|
76
|
+
}: {
|
|
77
|
+
layoutGroup: ToolcraftControlLayoutGroup;
|
|
78
|
+
section: ToolcraftControlsSection;
|
|
79
|
+
segmentedControlId: string;
|
|
80
|
+
}): boolean {
|
|
81
|
+
if (
|
|
82
|
+
normalizeToolcraftSemanticText(section.title) !==
|
|
83
|
+
normalizedVideoExportSectionTitle ||
|
|
84
|
+
layoutGroup.columns !== 2 ||
|
|
85
|
+
layoutGroup.controls.length !== 2
|
|
86
|
+
) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const formatControl = section.controls[segmentedControlId];
|
|
91
|
+
const resolutionControlId = layoutGroup.controls.find(
|
|
92
|
+
(controlId) => controlId !== segmentedControlId,
|
|
93
|
+
);
|
|
94
|
+
const resolutionControl = resolutionControlId
|
|
95
|
+
? section.controls[resolutionControlId]
|
|
96
|
+
: undefined;
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
formatControl?.type === "segmented" &&
|
|
100
|
+
formatControl.target === "export.video.format" &&
|
|
101
|
+
resolutionControl?.type === "select" &&
|
|
102
|
+
resolutionControl.target === "export.video.resolution"
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
59
106
|
export function sectionHasInlineLayoutGroupForPair(
|
|
60
|
-
section:
|
|
107
|
+
section: ToolcraftControlsSection,
|
|
61
108
|
firstControlId: string,
|
|
62
109
|
secondControlId: string,
|
|
63
110
|
): boolean {
|
|
@@ -95,7 +142,13 @@ export function getToolcraftInlineLayoutErrors(
|
|
|
95
142
|
}
|
|
96
143
|
|
|
97
144
|
const segmentedIds = layoutGroup.controls.filter(
|
|
98
|
-
(controlId) =>
|
|
145
|
+
(controlId) =>
|
|
146
|
+
section.controls[controlId]?.type === "segmented" &&
|
|
147
|
+
!isToolcraftVideoExportSegmentedInlinePair({
|
|
148
|
+
layoutGroup,
|
|
149
|
+
section,
|
|
150
|
+
segmentedControlId: controlId,
|
|
151
|
+
}),
|
|
99
152
|
);
|
|
100
153
|
|
|
101
154
|
if (segmentedIds.length > 0) {
|
|
@@ -181,8 +234,10 @@ export function getToolcraftInlineLayoutErrors(
|
|
|
181
234
|
!secondControlId ||
|
|
182
235
|
!firstControl ||
|
|
183
236
|
!secondControl ||
|
|
184
|
-
firstControl.
|
|
185
|
-
|
|
237
|
+
firstControl.applicability.mode ===
|
|
238
|
+
"conditional" ||
|
|
239
|
+
secondControl.applicability.mode ===
|
|
240
|
+
"conditional" ||
|
|
186
241
|
!isBooleanControl(firstControl) ||
|
|
187
242
|
!isBooleanControl(secondControl) ||
|
|
188
243
|
!isInlineSwitchLabelSafe(firstControlId, firstControl) ||
|
|
@@ -148,7 +148,11 @@ export function getFileDropLifecycleCoverageErrors({
|
|
|
148
148
|
);
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
if (
|
|
151
|
+
if (
|
|
152
|
+
control.multiple === true &&
|
|
153
|
+
control.variant !== "collection-actions" &&
|
|
154
|
+
!layersOwnMediaManagement
|
|
155
|
+
) {
|
|
152
156
|
if (!coverage.has("reorder") || !coverage.has("order-output")) {
|
|
153
157
|
errors.push(
|
|
154
158
|
`${label} multiple fileDrop acceptance must prove thumbnail/file reorder updates runtime media order and that preview, renderer, or export consumes that order.`,
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ResolvedToolcraftAppSchema,
|
|
3
|
-
|
|
3
|
+
ResolvedToolcraftControlSchema,
|
|
4
|
+
} from "@repo/toolcraft-runtime";
|
|
5
|
+
import {
|
|
6
|
+
areToolcraftPredicateSetsProvablyExclusive,
|
|
7
|
+
getToolcraftApplicabilityPredicates,
|
|
4
8
|
} from "@repo/toolcraft-runtime";
|
|
5
9
|
|
|
6
10
|
import { isToolcraftProductSectionControl } from "./controls";
|
|
7
|
-
import { areToolcraftConditionSetsProvablyExclusive } from "./condition-exclusivity";
|
|
8
11
|
|
|
9
12
|
const vectorOrbitIntentPattern =
|
|
10
13
|
/\b(camera\s+orbit|object\s+orbit|model\s+orbit|3d\s+(?:orientation|rotation)|view\s+orientation|model\s+rotation|object\s+rotation)\b/i;
|
|
@@ -34,7 +37,7 @@ function getCrossLength(
|
|
|
34
37
|
);
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
function hasValidOrientationDefault(control:
|
|
40
|
+
function hasValidOrientationDefault(control: ResolvedToolcraftControlSchema): boolean {
|
|
38
41
|
if (!control.defaultValue || typeof control.defaultValue !== "object") {
|
|
39
42
|
return false;
|
|
40
43
|
}
|
|
@@ -55,7 +58,7 @@ function getOrientationControlErrors({
|
|
|
55
58
|
controlId,
|
|
56
59
|
sectionTitle,
|
|
57
60
|
}: {
|
|
58
|
-
control:
|
|
61
|
+
control: ResolvedToolcraftControlSchema;
|
|
59
62
|
controlId: string;
|
|
60
63
|
sectionTitle: string;
|
|
61
64
|
}): string[] {
|
|
@@ -112,16 +115,20 @@ export function getToolcraftOrientationGizmoErrors(
|
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
const leftConditions = [
|
|
115
|
-
left.section.visibleWhen,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
+
...(left.section.visibleWhen ? [left.section.visibleWhen] : []),
|
|
119
|
+
...getToolcraftApplicabilityPredicates(
|
|
120
|
+
left.control.applicability,
|
|
121
|
+
),
|
|
122
|
+
];
|
|
118
123
|
const rightConditions = [
|
|
119
|
-
right.section.visibleWhen,
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
...(right.section.visibleWhen ? [right.section.visibleWhen] : []),
|
|
125
|
+
...getToolcraftApplicabilityPredicates(
|
|
126
|
+
right.control.applicability,
|
|
127
|
+
),
|
|
128
|
+
];
|
|
122
129
|
|
|
123
130
|
if (
|
|
124
|
-
!
|
|
131
|
+
!areToolcraftPredicateSetsProvablyExclusive(
|
|
125
132
|
leftConditions,
|
|
126
133
|
rightConditions,
|
|
127
134
|
)
|
|
@@ -83,7 +83,7 @@ export function getToolcraftOutputBackgroundErrors({
|
|
|
83
83
|
|
|
84
84
|
if (!schemaHasOutputBackgroundColorControl(controls)) {
|
|
85
85
|
errors.push(
|
|
86
|
-
"Product apps with
|
|
86
|
+
"Product apps with artifact export must expose a user-facing background color control such as appearance.background or scene.background. Preview, image export, and video export must read that runtime value instead of hardcoding the product background.",
|
|
87
87
|
);
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -103,7 +103,7 @@ export function getToolcraftOutputBackgroundErrors({
|
|
|
103
103
|
|
|
104
104
|
if (!schemaHasOutputBackgroundToggleControl(controls)) {
|
|
105
105
|
errors.push(
|
|
106
|
-
'Product apps with
|
|
106
|
+
'Product apps with artifact export must expose export.includeBackground in runtime Setup as a Switch labeled "Background". Runtime artifact export owns image alpha and preserves the background for opaque image formats and video; bounded live preview must use shouldIncludeToolcraftPreviewBackground(state).',
|
|
107
107
|
);
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -1,20 +1,27 @@
|
|
|
1
|
+
import type { ToolcraftArtifactExportDelivery } from "./artifact-export-intent";
|
|
1
2
|
import type { ToolcraftOutputExportFacts } from "./output-export-model";
|
|
2
3
|
|
|
3
|
-
export function getToolcraftOutputExportLayoutErrors(
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
export function getToolcraftOutputExportLayoutErrors({
|
|
5
|
+
delivery,
|
|
6
|
+
facts,
|
|
7
|
+
}: {
|
|
8
|
+
delivery: ToolcraftArtifactExportDelivery;
|
|
9
|
+
facts: ToolcraftOutputExportFacts;
|
|
10
|
+
}): string[] {
|
|
11
|
+
if (!delivery.imageEnabled && !delivery.videoEnabled) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
|
|
6
15
|
const errors: string[] = [];
|
|
7
16
|
|
|
8
17
|
if (facts.backgroundSection) {
|
|
9
18
|
errors.push(
|
|
10
|
-
'Product apps with
|
|
19
|
+
'Product apps with artifact export must not render a separate "Background" section; runtime Setup owns Background, Infinity canvas, and Color.',
|
|
11
20
|
);
|
|
12
21
|
}
|
|
13
22
|
|
|
14
23
|
if (!facts.setupSection || facts.setupSectionIndex !== 0) {
|
|
15
|
-
errors.push(
|
|
16
|
-
"Runtime Setup must remain the first controls block.",
|
|
17
|
-
);
|
|
24
|
+
errors.push("Runtime Setup must remain the first controls block.");
|
|
18
25
|
}
|
|
19
26
|
|
|
20
27
|
if (
|
|
@@ -23,18 +30,19 @@ export function getToolcraftOutputExportLayoutErrors(
|
|
|
23
30
|
facts.finalExportSettingsIndex !== facts.panelActionsSectionIndex - 1
|
|
24
31
|
) {
|
|
25
32
|
errors.push(
|
|
26
|
-
|
|
33
|
+
"The final enabled artifact export settings section must sit directly above sticky footer actions.",
|
|
27
34
|
);
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
if (
|
|
31
|
-
|
|
38
|
+
delivery.imageEnabled &&
|
|
39
|
+
delivery.videoEnabled &&
|
|
32
40
|
facts.imageExportSectionIndex >= 0 &&
|
|
33
41
|
facts.videoExportSectionIndex >= 0 &&
|
|
34
42
|
facts.imageExportSectionIndex !== facts.videoExportSectionIndex - 1
|
|
35
43
|
) {
|
|
36
44
|
errors.push(
|
|
37
|
-
'
|
|
45
|
+
'Products with image and video delivery must place "Image Export" immediately before "Video Export".',
|
|
38
46
|
);
|
|
39
47
|
}
|
|
40
48
|
|
|
@@ -4,6 +4,10 @@ import type {
|
|
|
4
4
|
} from "@repo/toolcraft-runtime";
|
|
5
5
|
|
|
6
6
|
import { getControlLabelText } from "./controls";
|
|
7
|
+
import {
|
|
8
|
+
schemaHasPngExportPanelAction,
|
|
9
|
+
schemaHasVideoExportPanelAction,
|
|
10
|
+
} from "./output-export-actions";
|
|
7
11
|
import { normalizeToolcraftSemanticText } from "./semantic";
|
|
8
12
|
|
|
9
13
|
export type ToolcraftControlsSection = NonNullable<
|
|
@@ -14,6 +18,7 @@ export type ToolcraftOutputExportFacts = {
|
|
|
14
18
|
backgroundColorEntry: readonly [string, ToolcraftControlSchema] | undefined;
|
|
15
19
|
backgroundSection: ToolcraftControlsSection | undefined;
|
|
16
20
|
finalExportSettingsIndex: number;
|
|
21
|
+
hasImageExportAction: boolean;
|
|
17
22
|
hasVideoExportAction: boolean;
|
|
18
23
|
imageExportSection: ToolcraftControlsSection | undefined;
|
|
19
24
|
imageExportSectionIndex: number;
|
|
@@ -25,7 +30,10 @@ export type ToolcraftOutputExportFacts = {
|
|
|
25
30
|
setupSection: ToolcraftControlsSection | undefined;
|
|
26
31
|
setupSectionIndex: number;
|
|
27
32
|
timelineEntry: readonly [string, ToolcraftControlSchema] | undefined;
|
|
33
|
+
videoExportSection: ToolcraftControlsSection | undefined;
|
|
28
34
|
videoExportSectionIndex: number;
|
|
35
|
+
videoFormatEntry: readonly [string, ToolcraftControlSchema] | undefined;
|
|
36
|
+
videoResolutionEntry: readonly [string, ToolcraftControlSchema] | undefined;
|
|
29
37
|
};
|
|
30
38
|
|
|
31
39
|
export function getSearchableControlText({
|
|
@@ -47,9 +55,13 @@ export function getSearchableControlText({
|
|
|
47
55
|
.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
48
56
|
}
|
|
49
57
|
|
|
50
|
-
function getFirstPanelActionsSectionIndex(
|
|
58
|
+
function getFirstPanelActionsSectionIndex(
|
|
59
|
+
schema: ResolvedToolcraftAppSchema,
|
|
60
|
+
): number {
|
|
51
61
|
return (schema.panels.controls?.sections ?? []).findIndex((section) =>
|
|
52
|
-
Object.values(section.controls).some(
|
|
62
|
+
Object.values(section.controls).some(
|
|
63
|
+
(control) => control.type === "panelActions",
|
|
64
|
+
),
|
|
53
65
|
);
|
|
54
66
|
}
|
|
55
67
|
|
|
@@ -60,7 +72,8 @@ function getSchemaControlsSectionByTitle(
|
|
|
60
72
|
const normalizedTitle = normalizeToolcraftSemanticText(title);
|
|
61
73
|
|
|
62
74
|
return (schema.panels.controls?.sections ?? []).find(
|
|
63
|
-
(section) =>
|
|
75
|
+
(section) =>
|
|
76
|
+
normalizeToolcraftSemanticText(section.title) === normalizedTitle,
|
|
64
77
|
);
|
|
65
78
|
}
|
|
66
79
|
|
|
@@ -83,7 +96,9 @@ function getSectionControlEntryByTarget(
|
|
|
83
96
|
return undefined;
|
|
84
97
|
}
|
|
85
98
|
|
|
86
|
-
return Object.entries(section.controls).find(
|
|
99
|
+
return Object.entries(section.controls).find(
|
|
100
|
+
([, control]) => control.target === target,
|
|
101
|
+
);
|
|
87
102
|
}
|
|
88
103
|
|
|
89
104
|
function getOutputBackgroundColorEntry(
|
|
@@ -107,24 +122,43 @@ function getOutputBackgroundColorEntry(
|
|
|
107
122
|
}
|
|
108
123
|
|
|
109
124
|
export function buildToolcraftOutputExportFacts({
|
|
110
|
-
hasVideoExportAction,
|
|
111
125
|
schema,
|
|
112
126
|
}: {
|
|
113
|
-
hasVideoExportAction: boolean;
|
|
114
127
|
schema: ResolvedToolcraftAppSchema;
|
|
115
128
|
}): ToolcraftOutputExportFacts {
|
|
116
|
-
const backgroundSection = getSchemaControlsSectionByTitle(
|
|
129
|
+
const backgroundSection = getSchemaControlsSectionByTitle(
|
|
130
|
+
schema,
|
|
131
|
+
"Background",
|
|
132
|
+
);
|
|
117
133
|
const setupSection = getSchemaControlsSectionByTitle(schema, "Setup");
|
|
118
|
-
const imageExportSection = getSchemaControlsSectionByTitle(
|
|
119
|
-
|
|
120
|
-
|
|
134
|
+
const imageExportSection = getSchemaControlsSectionByTitle(
|
|
135
|
+
schema,
|
|
136
|
+
"Image Export",
|
|
137
|
+
);
|
|
138
|
+
const videoExportSection = getSchemaControlsSectionByTitle(
|
|
139
|
+
schema,
|
|
140
|
+
"Video Export",
|
|
141
|
+
);
|
|
142
|
+
const imageExportSectionIndex = getSchemaControlsSectionIndexByTitle(
|
|
143
|
+
schema,
|
|
144
|
+
"Image Export",
|
|
145
|
+
);
|
|
146
|
+
const videoExportSectionIndex = getSchemaControlsSectionIndexByTitle(
|
|
147
|
+
schema,
|
|
148
|
+
"Video Export",
|
|
149
|
+
);
|
|
150
|
+
const hasImageExportAction = schemaHasPngExportPanelAction(schema);
|
|
151
|
+
const hasVideoExportAction = schemaHasVideoExportPanelAction(schema);
|
|
121
152
|
|
|
122
153
|
return {
|
|
123
154
|
backgroundColorEntry: getOutputBackgroundColorEntry(setupSection),
|
|
124
155
|
backgroundSection,
|
|
125
156
|
finalExportSettingsIndex: hasVideoExportAction
|
|
126
157
|
? videoExportSectionIndex
|
|
127
|
-
:
|
|
158
|
+
: hasImageExportAction
|
|
159
|
+
? imageExportSectionIndex
|
|
160
|
+
: -1,
|
|
161
|
+
hasImageExportAction,
|
|
128
162
|
hasVideoExportAction,
|
|
129
163
|
imageExportSection,
|
|
130
164
|
imageExportSectionIndex,
|
|
@@ -151,6 +185,15 @@ export function buildToolcraftOutputExportFacts({
|
|
|
151
185
|
setupSection,
|
|
152
186
|
"panels.timeline.extended",
|
|
153
187
|
),
|
|
188
|
+
videoExportSection,
|
|
154
189
|
videoExportSectionIndex,
|
|
190
|
+
videoFormatEntry: getSectionControlEntryByTarget(
|
|
191
|
+
videoExportSection,
|
|
192
|
+
"export.video.format",
|
|
193
|
+
),
|
|
194
|
+
videoResolutionEntry: getSectionControlEntryByTarget(
|
|
195
|
+
videoExportSection,
|
|
196
|
+
"export.video.resolution",
|
|
197
|
+
),
|
|
155
198
|
};
|
|
156
199
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ResolvedToolcraftAppSchema } from "@repo/toolcraft-runtime";
|
|
2
2
|
|
|
3
|
+
import { validateToolcraftArtifactExportIntentCorrespondence } from "./artifact-export-intent";
|
|
3
4
|
import {
|
|
4
5
|
getToolcraftOutputBackgroundErrors,
|
|
5
6
|
isOutputBackgroundToggleControl,
|
|
@@ -11,7 +12,13 @@ import {
|
|
|
11
12
|
import { getToolcraftOutputExportLayoutErrors } from "./output-export-layout-rules";
|
|
12
13
|
import { buildToolcraftOutputExportFacts } from "./output-export-model";
|
|
13
14
|
import { getToolcraftImageExportErrors } from "./output-image-export-rules";
|
|
14
|
-
import
|
|
15
|
+
import { getToolcraftVideoExportErrors } from "./output-video-export-rules";
|
|
16
|
+
import { getToolcraftExportArtifactCoverageErrors } from "./export-artifact-coverage";
|
|
17
|
+
import type {
|
|
18
|
+
ToolcraftComponentAcceptance,
|
|
19
|
+
ToolcraftProductReadiness,
|
|
20
|
+
ToolcraftVisibleControl,
|
|
21
|
+
} from "./types";
|
|
15
22
|
|
|
16
23
|
export {
|
|
17
24
|
isOutputBackgroundToggleControl,
|
|
@@ -20,26 +27,42 @@ export {
|
|
|
20
27
|
};
|
|
21
28
|
|
|
22
29
|
export function getToolcraftOutputExportErrors({
|
|
30
|
+
acceptance,
|
|
23
31
|
controls,
|
|
32
|
+
productReadiness,
|
|
24
33
|
schema,
|
|
25
|
-
hasVideoExportAction = schemaHasVideoExportPanelAction(schema),
|
|
26
34
|
}: {
|
|
35
|
+
acceptance: readonly ToolcraftComponentAcceptance[];
|
|
27
36
|
controls: readonly ToolcraftVisibleControl[];
|
|
28
|
-
|
|
37
|
+
productReadiness: ToolcraftProductReadiness;
|
|
29
38
|
schema: ResolvedToolcraftAppSchema;
|
|
30
39
|
}): string[] {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const facts = buildToolcraftOutputExportFacts({
|
|
36
|
-
hasVideoExportAction,
|
|
40
|
+
const exportArtifactCoverageErrors = getToolcraftExportArtifactCoverageErrors({
|
|
41
|
+
acceptance,
|
|
37
42
|
schema,
|
|
38
43
|
});
|
|
44
|
+
if (productReadiness.mode === "starter") {
|
|
45
|
+
return exportArtifactCoverageErrors;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const facts = buildToolcraftOutputExportFacts({ schema });
|
|
49
|
+
const { delivery, errors: intentErrors } =
|
|
50
|
+
validateToolcraftArtifactExportIntentCorrespondence({
|
|
51
|
+
hasImageExportAction: facts.hasImageExportAction,
|
|
52
|
+
hasImageExportSection: facts.imageExportSection !== undefined,
|
|
53
|
+
hasVideoExportAction: facts.hasVideoExportAction,
|
|
54
|
+
hasVideoExportSection: facts.videoExportSection !== undefined,
|
|
55
|
+
intent: productReadiness.exportIntent,
|
|
56
|
+
});
|
|
39
57
|
|
|
40
58
|
return [
|
|
41
|
-
...
|
|
42
|
-
...
|
|
43
|
-
...
|
|
59
|
+
...intentErrors,
|
|
60
|
+
...(delivery.imageEnabled ? getToolcraftImageExportErrors(facts) : []),
|
|
61
|
+
...(delivery.videoEnabled ? getToolcraftVideoExportErrors(facts) : []),
|
|
62
|
+
...(delivery.imageEnabled || delivery.videoEnabled
|
|
63
|
+
? getToolcraftOutputBackgroundErrors({ controls, facts })
|
|
64
|
+
: []),
|
|
65
|
+
...getToolcraftOutputExportLayoutErrors({ delivery, facts }),
|
|
66
|
+
...exportArtifactCoverageErrors,
|
|
44
67
|
];
|
|
45
68
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { sectionHasInlineLayoutGroupForPair } from "./inline-layout";
|
|
2
|
+
import type { ToolcraftOutputExportFacts } from "./output-export-model";
|
|
3
|
+
|
|
4
|
+
function hasExactOptionValueSet(
|
|
5
|
+
actual: readonly string[],
|
|
6
|
+
expected: readonly string[],
|
|
7
|
+
): boolean {
|
|
8
|
+
return (
|
|
9
|
+
actual.length === expected.length &&
|
|
10
|
+
new Set(actual).size === expected.length &&
|
|
11
|
+
expected.every((value) => actual.includes(value))
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function getToolcraftVideoExportErrors(
|
|
16
|
+
facts: ToolcraftOutputExportFacts,
|
|
17
|
+
): string[] {
|
|
18
|
+
const errors: string[] = [];
|
|
19
|
+
const videoFormatControl = facts.videoFormatEntry?.[1];
|
|
20
|
+
const videoResolutionControl = facts.videoResolutionEntry?.[1];
|
|
21
|
+
const videoFormatOptionValues =
|
|
22
|
+
videoFormatControl?.options?.map((option) => option.value.toLowerCase()) ??
|
|
23
|
+
[];
|
|
24
|
+
const videoResolutionOptionValues =
|
|
25
|
+
videoResolutionControl?.options?.map((option) =>
|
|
26
|
+
option.value.toLowerCase(),
|
|
27
|
+
) ?? [];
|
|
28
|
+
|
|
29
|
+
if (!facts.videoExportSection) {
|
|
30
|
+
errors.push(
|
|
31
|
+
'Apps with Export Video must expose video export settings in a separate controls section titled "Video Export" directly above sticky footer export actions.',
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (!videoFormatControl) {
|
|
36
|
+
errors.push(
|
|
37
|
+
'The separate "Video Export" section must include a format control with target "export.video.format".',
|
|
38
|
+
);
|
|
39
|
+
} else {
|
|
40
|
+
if (
|
|
41
|
+
videoFormatControl.type !== "select" &&
|
|
42
|
+
videoFormatControl.type !== "segmented"
|
|
43
|
+
) {
|
|
44
|
+
errors.push("Video Export format must be a Select or Segmented control.");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!hasExactOptionValueSet(videoFormatOptionValues, ["mp4", "webm"])) {
|
|
48
|
+
errors.push(
|
|
49
|
+
'Video Export format options must be exactly "mp4" and "webm".',
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (videoFormatControl.defaultValue !== "mp4") {
|
|
54
|
+
errors.push('Video Export format must default to "mp4".');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!videoResolutionControl) {
|
|
59
|
+
errors.push(
|
|
60
|
+
'The separate "Video Export" section must include a resolution control with target "export.video.resolution".',
|
|
61
|
+
);
|
|
62
|
+
} else {
|
|
63
|
+
if (videoResolutionControl.type !== "select") {
|
|
64
|
+
errors.push("Video Export resolution must be a Select control.");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (
|
|
68
|
+
!hasExactOptionValueSet(videoResolutionOptionValues, ["current", "4k"])
|
|
69
|
+
) {
|
|
70
|
+
errors.push(
|
|
71
|
+
'Video Export resolution options must be exactly "current" and "4k".',
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (videoResolutionControl.defaultValue !== "current") {
|
|
76
|
+
errors.push('Video Export resolution must default to "current".');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const videoFormatControlId = facts.videoFormatEntry?.[0];
|
|
81
|
+
const videoResolutionControlId = facts.videoResolutionEntry?.[0];
|
|
82
|
+
const videoExportHasInlinePair =
|
|
83
|
+
facts.videoExportSection !== undefined &&
|
|
84
|
+
videoFormatControlId !== undefined &&
|
|
85
|
+
videoResolutionControlId !== undefined &&
|
|
86
|
+
sectionHasInlineLayoutGroupForPair(
|
|
87
|
+
facts.videoExportSection,
|
|
88
|
+
videoFormatControlId,
|
|
89
|
+
videoResolutionControlId,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (!videoExportHasInlinePair) {
|
|
93
|
+
errors.push(
|
|
94
|
+
"Video Export format and resolution must render as one exact two-column inline row.",
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return errors;
|
|
99
|
+
}
|