@elytracms/studio 0.0.67 → 0.0.69
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/dist/components/assets/asset-detail.d.ts +4 -2
- package/dist/components/assets/asset-detail.js +4 -2
- package/dist/components/assets/asset-detail.js.map +1 -1
- package/dist/components/assets/assets-collection-view-source.d.ts +30 -19
- package/dist/components/assets/assets-collection-view-source.js +55 -23
- package/dist/components/assets/assets-collection-view-source.js.map +1 -1
- package/dist/components/builder/canvas-chrome-css.js +6 -1
- package/dist/components/builder/canvas-chrome-css.js.map +1 -1
- package/dist/components/builder/property-inspector.d.ts +0 -21
- package/dist/components/builder/property-inspector.js +5 -22
- package/dist/components/builder/property-inspector.js.map +1 -1
- package/dist/components/builder/selection-overlay.d.ts +17 -4
- package/dist/components/builder/selection-overlay.js +17 -15
- package/dist/components/builder/selection-overlay.js.map +1 -1
- package/dist/components/builder/spacing-handles.d.ts +26 -1
- package/dist/components/builder/spacing-handles.js +66 -3
- package/dist/components/builder/spacing-handles.js.map +1 -1
- package/dist/components/cms/asset-picker-core.d.ts +52 -0
- package/dist/components/cms/asset-picker-core.js +69 -0
- package/dist/components/cms/asset-picker-core.js.map +1 -0
- package/dist/components/cms/asset-picker.d.ts +16 -4
- package/dist/components/cms/asset-picker.js +34 -50
- package/dist/components/cms/asset-picker.js.map +1 -1
- package/dist/components/cms/bulk-bar.d.ts +11 -1
- package/dist/components/cms/bulk-bar.js +10 -3
- package/dist/components/cms/bulk-bar.js.map +1 -1
- package/dist/components/cms/collection-table.js +19 -2
- package/dist/components/cms/collection-table.js.map +1 -1
- package/dist/components/cms/detail-editor.js +45 -54
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/field-control.js +5 -1
- package/dist/components/cms/field-control.js.map +1 -1
- package/dist/components/cms/prop-fields.js +5 -1
- package/dist/components/cms/prop-fields.js.map +1 -1
- package/dist/components/cms/prop-visibility.d.ts +3 -0
- package/dist/components/cms/prop-visibility.js +31 -0
- package/dist/components/cms/prop-visibility.js.map +1 -0
- package/dist/components/cms/reference-confirm.js +5 -1
- package/dist/components/cms/reference-confirm.js.map +1 -1
- package/dist/components/cms/rich-text/component-embed.d.ts +8 -6
- package/dist/components/cms/rich-text/component-embed.js +21 -62
- package/dist/components/cms/rich-text/component-embed.js.map +1 -1
- package/dist/components/cms/rich-text/editor.d.ts +33 -4
- package/dist/components/cms/rich-text/editor.js +52 -22
- package/dist/components/cms/rich-text/editor.js.map +1 -1
- package/dist/components/cms/rich-text/embed-props.d.ts +60 -27
- package/dist/components/cms/rich-text/embed-props.js +102 -45
- package/dist/components/cms/rich-text/embed-props.js.map +1 -1
- package/dist/components/rail-view-source.d.ts +50 -1
- package/dist/components/rail-view-source.js +56 -2
- package/dist/components/rail-view-source.js.map +1 -1
- package/dist/components/redirects/redirects-collection-view-source.d.ts +3 -2
- package/dist/components/redirects/redirects-collection-view-source.js +4 -3
- package/dist/components/redirects/redirects-collection-view-source.js.map +1 -1
- package/dist/components/users/users-collection-view-source.js +1 -1
- package/dist/components/users/users-collection-view-source.js.map +1 -1
- package/dist/lib/collection-view/collection-view-source.d.ts +12 -0
- package/dist/lib/collection-view/collection-view-source.js.map +1 -1
- package/dist/lib/dnd/gap-drag.d.ts +8 -1
- package/dist/lib/dnd/gap-drag.js +4 -0
- package/dist/lib/dnd/gap-drag.js.map +1 -1
- package/dist/lib/i18n/messages.de.js +3 -2
- package/dist/lib/i18n/messages.de.js.map +1 -1
- package/dist/lib/i18n/messages.en.d.ts +1 -1
- package/dist/lib/i18n/messages.en.js +4 -2
- package/dist/lib/i18n/messages.en.js.map +1 -1
- package/dist/lib/references/references-store.d.ts +8 -1
- package/dist/lib/references/references-store.js +12 -2
- package/dist/lib/references/references-store.js.map +1 -1
- package/dist/ui/expandable-surface.d.ts +35 -25
- package/dist/ui/expandable-surface.js +41 -21
- package/dist/ui/expandable-surface.js.map +1 -1
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +1 -0
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/surface-geometry.d.ts +71 -0
- package/dist/ui/surface-geometry.js +64 -0
- package/dist/ui/surface-geometry.js.map +1 -0
- package/package.json +2 -2
- package/src/styles/studio.css +30 -0
- package/dist/components/cms/rich-text/embed-inspector-context.d.ts +0 -50
- package/dist/components/cms/rich-text/embed-inspector-context.js +0 -12
- package/dist/components/cms/rich-text/embed-inspector-context.js.map +0 -1
- package/dist/components/cms/rich-text/embed-inspector.d.ts +0 -25
- package/dist/components/cms/rich-text/embed-inspector.js +0 -48
- package/dist/components/cms/rich-text/embed-inspector.js.map +0 -1
- package/dist/components/cms/use-embed-inspector-host.d.ts +0 -12
- package/dist/components/cms/use-embed-inspector-host.js +0 -17
- package/dist/components/cms/use-embed-inspector-host.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field-control.js","sourceRoot":"","sources":["../../../src/components/cms/field-control.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,cAAc,CAAA;AAC9E,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC5D,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAOjF,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,eAAe,GAChB,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AACzE,OAAO,EACL,MAAM,EACN,KAAK,EACL,GAAG,EACH,OAAO,EACP,MAAM,EACN,KAAK,EACL,IAAI,GACL,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,EAAE,EAAE,MAAM,6BAA6B,CAAA;AAChD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAA;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAA;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAClD,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,kBAAkB,CAAA;AAUzB;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,YAAY,CAAC,KAAwB;IACnD,MAAM,SAAS,GAAG,iBAAiB,EAAE,CAAA;IACrC,MAAM,OAAO,GAAG,KAAC,mBAAmB,OAAK,KAAK,GAAI,CAAA;IAClD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAA;IACzC,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC3D,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CACL,KAAC,qBAAqB,IACpB,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,KAAC,kBAAkB,IAAC,OAAO,EAAE,SAAS,CAAC,2BAA2B,CAAC,GAAI,YAE9E,KAAC,MAAM,OAAK,KAAK,GAAI,GACC,CACzB,CAAA;IACH,CAAC;IACD,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,CAAA;QACvE,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,CACL,MAAC,KAAK,IAAC,GAAG,EAAC,GAAG,aACZ,KAAC,kBAAkB,IAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,GAAI,EAChD,OAAO,IACF,CACT,CAAA;QACH,CAAC;QACD,2EAA2E;QAC3E,gFAAgF;QAChF,IAAI,CAAE,sBAA4C,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACrE,OAAO,CACL,MAAC,KAAK,IAAC,GAAG,EAAC,GAAG,aACZ,KAAC,kBAAkB,IAAC,OAAO,EAAE,SAAS,CAAC,sBAAsB,EAAE,EAAE,OAAO,EAAE,CAAC,GAAI,EAC9E,OAAO,IACF,CACT,CAAA;QACH,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,oFAAoF;AACpF,MAAM,eAAe,GAAG,MAAM,CAAA;AAC9B,2FAA2F;AAC3F,MAAM,YAAY,GAAG,MAAM,CAAA;AAE3B;;;;GAIG;AACH,SAAS,aAAa,CAAC,KAAe;IACpC,OAAO,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,KAAK,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,CAAC,CAAA;AAC1G,CAAC;AAED,SAAS,mBAAmB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAqB;IACtF,iFAAiF;IACjF,mFAAmF;IACnF,mFAAmF;IACnF,wDAAwD;IACxD,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAC,SAAS,IAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,GAAI,CAAA;IAClG,CAAC;IACD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,SAAS;YACZ,OAAO,CACL,iBAAO,SAAS,EAAC,qCAAqC,aACpD,gBACE,EAAE,EAAE,EAAE,EACN,IAAI,EAAC,UAAU,EACf,OAAO,EAAE,KAAK,KAAK,IAAI,EACvB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAC3C,SAAS,EAAC,2CAA2C,GACrD,EACF,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,YACzB,SAAS,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,cAAc,CAAC,GACtD,IACD,CACT,CAAA;QACH,KAAK,QAAQ;YACX,OAAO,CACL,KAAC,KAAK,IACJ,EAAE,EAAE,EAAE,EACN,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAC7C,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GACrF,CACH,CAAA;QACH,KAAK,MAAM;YACT,OAAO,CACL,KAAC,KAAK,IACJ,EAAE,EAAE,EAAE,EACN,IAAI,EAAC,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAC1D,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,GACzF,CACH,CAAA;QACH,KAAK,QAAQ;YACX,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACnB,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,KAAkB,CAAC,CAAC,CAAC,EAAE,CAAA;gBAChE,OAAO,CACL,KAAC,GAAG,IAAC,GAAG,EAAC,GAAG,EAAC,IAAI,kBACd,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;wBACzB,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;wBACvC,OAAO,CACL,iBAAuB,SAAS,EAAC,mCAAmC,aAClE,gBACE,IAAI,EAAC,UAAU,EACf,OAAO,EAAE,EAAE,EACX,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,GAAG,EAAE,CACb,QAAQ,CACN,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,EAAE,GAAG,CAAC,KAAK,CAAC,CACxE,EAEH,SAAS,EAAC,uBAAuB,GACjC,EACD,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,KAZ3B,GAAG,CAAC,KAAK,CAab,CACT,CAAA;oBACH,CAAC,CAAC,GACE,CACP,CAAA;YACH,CAAC;YACD,4EAA4E;YAC5E,kEAAkE;YAClE,IAAI,KAAK,CAAC,IAAI,EAAE,OAAO,KAAK,SAAS,EAAE,CAAC;gBACtC,OAAO,CACL,KAAC,gBAAgB,IAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,GAAI,CACjG,CAAA;YACH,CAAC;YACD,OAAO,CACL,MAAC,MAAM,IACL,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAC7C,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS,CAAC,aAEtD,iBAAQ,KAAK,EAAC,EAAE,uBAAW,EAC1B,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAC1B,iBAAwB,KAAK,EAAE,GAAG,CAAC,KAAK,YACrC,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,IAD1B,GAAG,CAAC,KAAK,CAEb,CACV,CAAC,IACK,CACV,CAAA;QACH,KAAK,UAAU;YACb,OAAO,CACL,KAAC,cAAc,IAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,GAAI,CACrG,CAAA;QACH,KAAK,UAAU;YACb,OAAO,KAAC,aAAa,IAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAI,CAAA;QAC9F,KAAK,OAAO;YACV,OAAO,KAAC,UAAU,IAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAI,CAAA;QAC3F,KAAK,QAAQ;YACX,OAAO,KAAC,WAAW,IAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,GAAI,CAAA;QACpG;YACE,OAAO,CACL,KAAC,KAAK,IACJ,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAC7C,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS,CAAC,GACtD,CACH,CAAA;IACL,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAS,SAAS,CAAC,EACjB,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,EAAE,GAOH;IACC,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAA;IAClC,MAAM,MAAM,GAAG,yBAAyB,EAAE,CAAA;IAC1C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAmC,CAAA;IAC5D,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,EAAE,OAAO,KAAK,YAAY,CAAA;IACrD,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAA;IAClC,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAA;IAExC,gFAAgF;IAChF,uEAAuE;IACvE,mFAAmF;IACnF,4EAA4E;IAC5E,iFAAiF;IACjF,MAAM,MAAM,GAAG,uBAAuB,EAAE,CAAA;IACxC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,KAAK,MAAM,CAAC,YAAY,CAAC,CAAA;IAEnF,MAAM,KAAK,GAAG,MAAM,EAAE,KAAK,CAAA;IAC3B,+EAA+E;IAC/E,MAAM,MAAM,GAAG,OAAO,CACpB,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EACtD,CAAC,KAAK,EAAE,MAAM,CAAC,CAChB,CAAA;IACD,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,eAAe,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAE5F,+EAA+E;IAC/E,mFAAmF;IACnF,sEAAsE;IACtE,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IACjF,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IACpC,WAAW,CAAC,OAAO,GAAG,QAAQ,CAAA;IAC9B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,QAAQ,IAAI,cAAc;YAAE,OAAM;QACtC,IAAI,OAAO,IAAI,OAAO,KAAK,OAAO;YAAE,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAClE,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAA;IAEhD,8EAA8E;IAC9E,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAChD,kFAAkF;IAClF,kFAAkF;IAClF,iFAAiF;IACjF,oFAAoF;IACpF,MAAM,KAAK,GACT,KAAK,IAAI,QAAQ;QACf,CAAC,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QACvF,CAAC,CAAC,SAAS,CAAA;IACf,oFAAoF;IACpF,iFAAiF;IACjF,mFAAmF;IACnF,sFAAsF;IACtF,MAAM,eAAe,GACnB,KAAK,IAAI,QAAQ;QACf,CAAC,CAAC,kBAAkB,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,CAC7F,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAC5B;QACH,CAAC,CAAC,EAAE,CAAA;IACR,MAAM,WAAW,GAAG,eAAe,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAE/D,4EAA4E;IAC5E,MAAM,qBAAqB,GAAG,OAAO,CAAgB,GAAG,EAAE;QACxD,IAAI,UAAU,EAAE,MAAM,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAA;QAC9B,IAAI,OAAO,KAAK,EAAE;YAAE,OAAO,IAAI,CAAA;QAC/B,MAAM,GAAG,GAAG,iBAAiB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,EAAE;YAChE,UAAU,EAAE,MAAM,CAAC,MAAM;YACzB,MAAM;YACN,YAAY;SACb,CAAC,CAAA;QACF,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,YAAY,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACrF,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC,CAAA;IAE9D,0DAA0D;IAC1D,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACnD,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,MAAM,GAAG,UAAU,EAAE,MAAM,CAAA;QACjC,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;YACtB,aAAa,CAAC,KAAK,CAAC,CAAA;YACpB,OAAM;QACR,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAA;QAC9B,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;YACnB,aAAa,CAAC,KAAK,CAAC,CAAA;YACpB,OAAM;QACR,CAAC;QACD,IAAI,SAAS,GAAG,KAAK,CAAA;QACrB,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;aACxF,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE;YACX,IAAI,CAAC,SAAS;gBAAE,aAAa,CAAC,EAAE,KAAK,KAAK,CAAC,CAAA;QAC7C,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,IAAI,CAAC,SAAS;gBAAE,aAAa,CAAC,KAAK,CAAC,CAAA;QACtC,CAAC,CAAC,CAAA;QACJ,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAA;QAClB,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAEhD,MAAM,gBAAgB,GAAG,UAAU,EAAE,MAAM;QACzC,CAAC,CAAC,UAAU;YACV,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC;YAC1C,CAAC,CAAC,SAAS;QACb,CAAC,CAAC,qBAAqB;YACrB,CAAC,CAAC,SAAS,CAAC,sBAAsB,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC;YACrE,CAAC,CAAC,SAAS,CAAA;IAEf,SAAS,WAAW,CAAC,IAAY;QAC/B,QAAQ,CAAC,IAAI,IAAI,SAAS,CAAC,CAAA;QAC3B,6EAA6E;QAC7E,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IACvC,CAAC;IAED,SAAS,UAAU;QACjB,iBAAiB,CAAC,KAAK,CAAC,CAAA;QACxB,MAAM,IAAI,GAAG,YAAY,CAAC,UAAU,EAAE,eAAe,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;QACzF,QAAQ,CAAC,IAAI,IAAI,SAAS,CAAC,CAAA;IAC7B,CAAC;IAED,gFAAgF;IAChF,+EAA+E;IAC/E,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,OAAO,CACL,KAAC,KAAK,IACJ,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,SAAS,CAAC,GACtD,CACH,CAAA;IACH,CAAC;IAED,MAAM,KAAK,GAAG,CACZ,KAAC,KAAK,IACJ,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,OAAO,IAAI,SAAS,EACjC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAC5C,SAAS,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,yDAAyD,CAAC,CAAC,CAAC,QAAQ,CAAC,GAC3F,CACH,CAAA;IACD,MAAM,gBAAgB,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CACnC,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,SAAS,EACd,OAAO,EAAE,UAAU,gBACP,SAAS,CAAC,2BAA2B,CAAC,EAClD,KAAK,EAAE,SAAS,CAAC,2BAA2B,CAAC,YAE7C,KAAC,QAAQ,KAAG,GACL,CACV,CAAC,CAAC,CAAC,IAAI,CAAA;IAER,uFAAuF;IACvF,kFAAkF;IAClF,iFAAiF;IACjF,gFAAgF;IAChF,sFAAsF;IACtF,MAAM,WAAW,GACf,KAAK,EAAE,IAAI;QACX,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;IAE1F,OAAO,CACL,MAAC,KAAK,IAAC,GAAG,EAAC,GAAG,aACX,KAAK,CAAC,CAAC,CAAC,CACP,MAAC,GAAG,IAAC,GAAG,EAAC,GAAG,EAAC,KAAK,EAAC,QAAQ,iBAAa,oBAAoB,aAC1D,eACE,SAAS,EAAC,iJAAiJ,EAC3J,KAAK,EAAE,WAAW,iBACN,aAAa,YAExB,eAAe,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC9B,oCAAkB,SAAS,EAAC,0BAA0B,kBAE/C,CACR,CAAC,CAAC,CAAC,CACF,8BACE,oCAAkB,SAAS,EAAC,0BAA0B,YACnD,eAAe,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GACnC,EACN,WAAW,CAAC,CAAC,CAAC,CACb,KAAC,kBAAkB,IACjB,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,MAAM,EAAE,SAAS,EAC5B,YAAY,EAAE,MAAM,CAAC,YAAY,GACjC,CACH,CAAC,CAAC,CAAC,IAAI,EACR,oCAAkB,SAAS,EAAC,0BAA0B,kBAE/C,IACN,CACJ,GACI,EACN,KAAK,EACL,gBAAgB,IACb,CACP,CAAC,CAAC,CAAC,CACF,MAAC,GAAG,IAAC,GAAG,EAAC,GAAG,EAAC,KAAK,EAAC,QAAQ,aACxB,KAAK,EACL,gBAAgB,IACb,CACP,EAEA,gBAAgB,CAAC,CAAC,CAAC,CAClB,MAAC,GAAG,IAAC,GAAG,EAAC,GAAG,EAAC,KAAK,EAAC,QAAQ,iBAAa,gBAAgB,aACtD,KAAC,aAAa,IAAC,SAAS,EAAC,gCAAgC,wBAAe,EACxE,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,YACzB,gBAAgB,GACZ,IACH,CACP,CAAC,CAAC,CAAC,IAAI,IACF,CACT,CAAA;AACH,CAAC;AAED,SAAS,aAAa,CAAC,EACrB,KAAK,EACL,KAAK,EACL,QAAQ,EACR,QAAQ,GAMT;IACC,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAA;IAClC,MAAM,MAAM,GAAG,yBAAyB,EAAE,CAAA;IAC1C,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACvC,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAA;IAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAA;IAElC,yEAAyE;IACzE,gFAAgF;IAChF,6EAA6E;IAC7E,6EAA6E;IAC7E,+EAA+E;IAC/E,MAAM,UAAU,GAAG,OAAO,CAA0B,GAAG,EAAE;QACvD,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,UAAU,CAAC,EAAE;YAAE,OAAO,SAAS,CAAA;QACtE,IAAI,mBAAmB,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,IAAI,KAAK,KAAK,CAAC,IAAI;YAAE,OAAO,SAAS,CAAA;QACjF,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA;QAC7F,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QACzB,OAAO,GAAG,CAAA;IACZ,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;IAE9C,SAAS,KAAK,CAAC,IAAmB;QAChC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAA;IAC1D,CAAC;IAED,OAAO,CACL,MAAC,KAAK,IAAC,GAAG,EAAC,GAAG,aACX,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CACjB,KAAC,KAAK,IAAC,GAAG,EAAC,GAAG,YACX,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;oBACnB,4EAA4E;oBAC5E,0EAA0E;oBAC1E,uEAAuE;oBACvE,sEAAsE;oBACtE,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;oBACjC,MAAM,KAAK,GAAG,CACZ,gBAAM,SAAS,EAAC,0CAA0C,aACxD,KAAC,KAAK,IAAC,SAAS,EAAC,yCAAyC,GAAG,EAC7D,eAAM,SAAS,EAAC,kBAAkB,YAAE,KAAK,GAAQ,IAC5C,CACR,CAAA;oBACD,OAAO,CACL,KAAC,OAAO,mBAEM,gBAAgB,EAC5B,OAAO,EACL,CAAC,QAAQ,CAAC,CAAC,CAAC,CACV,8BACG,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,CAC1B,KAAC,MAAM,IACL,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,SAAS,gBACF,SAAS,CAAC,qBAAqB,CAAC,EAC5C,KAAK,EAAE,SAAS,CAAC,qBAAqB,CAAC,EACvC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,YAE5B,KAAC,MAAM,KAAG,GACH,CACV,CAAC,CAAC,CAAC,IAAI,EACR,KAAC,MAAM,IACL,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,SAAS,gBACF,SAAS,CAAC,eAAe,CAAC,EACtC,KAAK,EAAE,SAAS,CAAC,eAAe,CAAC,EACjC,SAAS,EAAC,wBAAwB,EAClC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,YAEzD,KAAC,CAAC,KAAG,GACE,IACR,CACJ,CAAC,CAAC,CAAC,SAAS,YAGd,SAAS,CAAC,CAAC,CAAC,CACX,KAAC,IAAI,IACH,EAAE,EAAE,oBAAoB,EACxB,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,EAC7E,KAAK,EAAE,SAAS,CAAC,wBAAwB,EAAE,EAAE,KAAK,EAAE,CAAC,EACrD,SAAS,EAAC,wDAAwD,YAEjE,KAAK,GACD,CACR,CAAC,CAAC,CAAC,CACF,KAAC,IAAI,IAAC,EAAE,EAAC,MAAM,EAAC,IAAI,EAAC,IAAI,EAAC,MAAM,EAAC,QAAQ,YACtC,KAAK,GACD,CACR,IA3CI,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,CA4Cb,CACX,CAAA;gBACH,CAAC,CAAC,GACI,CACT,CAAC,CAAC,CAAC,IAAI,EACP,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CACpD,KAAC,GAAG,cACF,MAAC,MAAM,IAAC,OAAO,EAAC,SAAS,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,aAC9D,KAAC,IAAI,KAAG,OAAE,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,IAC/E,GACL,CACP,CAAC,CAAC,CAAC,IAAI,EACR,KAAC,cAAc,IACb,gBAAgB,EAAE,KAAK,CAAC,MAAM,EAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACxB,KAAK,EAAE,IAAI,EACX,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,OAAO,EACrB,QAAQ,EAAE,KAAK,EACf,UAAU,EAAE,UAAU,GACtB,IACI,CACT,CAAA;AACH,CAAC","sourcesContent":["import { AlertTriangle, Link2, Pencil, Plus, RotateCw, X } from 'lucide-react'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport type {\n DocumentRef,\n FieldDef,\n RelationFieldDef,\n UrlSegment,\n} from '@elytracms/core/cms-core'\nimport {\n BUILTIN_FIELD_CONTROLS,\n applySlugify,\n descendantIds,\n findSlugCollision,\n parentRelationField,\n resolveSlugPath,\n resolveUrlSegments,\n slugSourceValue,\n} from '@elytracms/core/cms-core'\nimport type { SlugFieldConfig, SlugPathParts } from '@elytracms/core/cms-core'\nimport { resolveDeploymentRoutes } from '@elytracms/studio/lib/workspace'\nimport {\n Button,\n Input,\n Row,\n RowItem,\n Select,\n Stack,\n Text,\n} from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { activeLocaleValues } from '@elytracms/studio/lib/locale'\nimport { useCollectionView } from '../collection-view/collection-view-context'\nimport { useOptionalDocumentEditor } from './document-editor-context'\nimport { toRefArray } from './cell'\nimport { RelationPicker } from './relation-picker'\nimport { RichTextEditor } from './rich-text'\nimport { DocumentUrlSegment } from './document-url-path'\nimport { AssetField } from './asset-field'\nimport { SegmentedOptions } from './field-control-lib'\nimport { ObjectField } from './object-array-field'\nimport {\n FieldRendererBoundary,\n FieldRendererIssue,\n useFieldRenderers,\n} from './field-renderer'\n\ninterface FieldControlProps {\n field: FieldDef\n value: unknown\n onChange: (value: unknown) => void\n readOnly: boolean\n id: string\n}\n\n/**\n * The document-editor field control. Resolves a project's custom renderer by the\n * field's `form.control` (EC-238, customization seam EC-236) and falls back to the\n * built-in control for the field's datatype: a registered renderer renders inside\n * an error boundary (a throw → the built-in + a visible issue); a rejected\n * registration (non-component) shows the built-in with the issue above it; a field\n * naming a control with NO renderer and NO built-in name (a typo) shows the\n * built-in with a loud issue — never a silent fall-through; otherwise the built-in\n * renders alone.\n *\n * EC-330 split: the asset-field family lives in `asset-field.tsx`, the object /\n * repeater editors in `object-array-field.tsx`, and their pure companions\n * (reorder/summary/depth/table decisions, the `options` segmented control) in\n * `field-control-lib.tsx` — this file keeps the dispatcher plus the slug and\n * relation controls.\n */\nexport function FieldControl(props: FieldControlProps) {\n const renderers = useFieldRenderers()\n const builtIn = <BuiltInFieldControl {...props} />\n const control = props.field.form?.control\n const Custom = control ? renderers.get(control) : undefined\n if (Custom) {\n return (\n <FieldRendererBoundary\n fallback={builtIn}\n issue={<FieldRendererIssue message={translate('cms.field.rendererCrashed')} />}\n >\n <Custom {...props} />\n </FieldRendererBoundary>\n )\n }\n if (control) {\n const rejected = renderers.issues.find((issue) => issue.id === control)\n if (rejected) {\n return (\n <Stack gap=\"1\">\n <FieldRendererIssue message={rejected.message} />\n {builtIn}\n </Stack>\n )\n }\n // The field asks for a control with no registered renderer and no built-in\n // name — surface it (a typo'd `control` would otherwise read as a plain input).\n if (!(BUILTIN_FIELD_CONTROLS as readonly string[]).includes(control)) {\n return (\n <Stack gap=\"1\">\n <FieldRendererIssue message={translate('cms.field.noRenderer', { control })} />\n {builtIn}\n </Stack>\n )\n }\n }\n return builtIn\n}\n\n/** The conventional slug field name (mirrors `url-for-document`'s `SLUG_FIELD`). */\nconst SLUG_FIELD_NAME = 'slug'\n/** The built-in control name that opts any `text` field into the slug control (EC-315). */\nconst SLUG_CONTROL = 'slug'\n\n/**\n * EC-315: a `text` field is rendered by the smart slug control when it opts in via\n * `form.control: 'slug'`, OR (the default auto-upgrade) when it is simply named\n * `slug` — the long-standing convention `url-for-document`/hierarchy already key off.\n */\nfunction isSlugControl(field: FieldDef): boolean {\n return field.type === 'text' && (field.form?.control === SLUG_CONTROL || field.name === SLUG_FIELD_NAME)\n}\n\nfunction BuiltInFieldControl({ field, value, onChange, readOnly, id }: FieldControlProps) {\n // EC-315: the smart slug control (composed path, auto-slug, per-locale segments)\n // subsumes the old inline `slug` input + PathPreview. It degrades to a plain input\n // when the collection isn't routable (name-based auto-upgrade only) or no document\n // editor context is present (e.g. a table-cell picker).\n if (isSlugControl(field)) {\n return <SlugField field={field} value={value} onChange={onChange} readOnly={readOnly} id={id} />\n }\n switch (field.type) {\n case 'boolean':\n return (\n <label className=\"flex h-8 items-center gap-2 text-sm\">\n <input\n id={id}\n type=\"checkbox\"\n checked={value === true}\n disabled={readOnly}\n onChange={(e) => onChange(e.target.checked)}\n className=\"size-4 accent-primary disabled:opacity-50\"\n />\n <Text size=\"sm\" tone=\"muted\">\n {translate(value === true ? 'common.true' : 'common.false')}\n </Text>\n </label>\n )\n case 'number':\n return (\n <Input\n id={id}\n type=\"number\"\n disabled={readOnly}\n value={typeof value === 'number' ? value : ''}\n onChange={(e) => onChange(e.target.value === '' ? undefined : Number(e.target.value))}\n />\n )\n case 'date':\n return (\n <Input\n id={id}\n type=\"date\"\n disabled={readOnly}\n value={typeof value === 'string' ? value.slice(0, 10) : ''}\n onChange={(e) => onChange(e.target.value ? `${e.target.value}T00:00:00.000Z` : undefined)}\n />\n )\n case 'select':\n if (field.multiple) {\n const selected = Array.isArray(value) ? (value as string[]) : []\n return (\n <Row gap=\"2\" wrap>\n {field.options.map((opt) => {\n const on = selected.includes(opt.value)\n return (\n <label key={opt.value} className=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"checkbox\"\n checked={on}\n disabled={readOnly}\n onChange={() =>\n onChange(\n on ? selected.filter((v) => v !== opt.value) : [...selected, opt.value],\n )\n }\n className=\"size-4 accent-primary\"\n />\n {localizedLabel(opt.label, opt.value)}\n </label>\n )\n })}\n </Row>\n )\n }\n // EC-295: the `options` control renders a small fixed enumeration as inline\n // segmented buttons instead of the dropdown (single-select only).\n if (field.form?.control === 'options') {\n return (\n <SegmentedOptions field={field} value={value} onChange={onChange} readOnly={readOnly} id={id} />\n )\n }\n return (\n <Select\n id={id}\n disabled={readOnly}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value || undefined)}\n >\n <option value=\"\">—</option>\n {field.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {localizedLabel(opt.label, opt.value)}\n </option>\n ))}\n </Select>\n )\n case 'richText':\n return (\n <RichTextEditor value={value} onChange={onChange} readOnly={readOnly} id={id} allow={field.allow} />\n )\n case 'relation':\n return <RelationField field={field} value={value} onChange={onChange} readOnly={readOnly} />\n case 'asset':\n return <AssetField field={field} value={value} onChange={onChange} readOnly={readOnly} />\n case 'object':\n return <ObjectField field={field} value={value} onChange={onChange} readOnly={readOnly} id={id} />\n default:\n return (\n <Input\n id={id}\n disabled={readOnly}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value || undefined)}\n />\n )\n }\n}\n\n/**\n * EC-315 — the smart slug / URL-segment control. A `text` field named `slug` (or any\n * `text` field with `form.control: 'slug'`) renders here instead of a bare input:\n *\n * - **Composed path**: the route-derived URL, decomposed by {@link resolveSlugPath}\n * into read-only parent/context segments + the editable slug segment inline + the\n * locale prefix (non-default locales). Reuses the same `urlForDocument` the live\n * site uses, so the preview matches what visitors get. Draft-derived (updates as\n * you type); the live \"View live\" button in the header stays the published open.\n * - **Auto-slug**: while the slug is empty or was last produced by auto-derivation,\n * it live-derives from the source field (default: the collection's `titleField`).\n * A manual edit stops the auto-fill; the ↻ button always re-derives.\n * - **Per-locale**: reads/writes through the shared `value`/`onChange` seam, so a\n * `localized` slug edits the active locale's segment with no bespoke locale code.\n * - **Uniqueness**: an inline warning when the candidate collides with a sibling in\n * the same scope (same parent when hierarchical, same locale). A custom\n * `slug.unique` hook replaces the default sibling scan.\n *\n * Degrades to a plain input when there is no document editor context (a table-cell\n * picker) or when a name-based auto-upgrade lands on a non-routable collection.\n */\nfunction SlugField({\n field,\n value,\n onChange,\n readOnly,\n id,\n}: {\n field: FieldDef\n value: unknown\n onChange: (value: unknown) => void\n readOnly: boolean\n id: string\n}) {\n const source = useCollectionView()\n const editor = useOptionalDocumentEditor()\n const slugConfig = field.slug as SlugFieldConfig | undefined\n const explicit = field.form?.control === SLUG_CONTROL\n const current = typeof value === 'string' ? value : ''\n const locale = source.activeLocale\n const localeConfig = source.localeConfig\n\n // 0.0.39 regression fix: resolve the deployment routes on EVERY render (a cheap\n // synchronous accessor), never freeze them at first paint. The earlier\n // `useMemo(() => resolveDeploymentRoutes(), [])` captured the EMPTY route set from\n // before the workspace/config finished loading — so the composed path never\n // appeared once routes arrived, and a stale set could paint a misleading prefix.\n const routes = resolveDeploymentRoutes()\n const routable = routes.some((r) => r.document?.collection === source.collectionId)\n\n const draft = editor?.draft\n // The active-locale value bag the auto-slug source derives from (title, etc.).\n const values = useMemo<Record<string, unknown>>(\n () => (draft ? activeLocaleValues(draft, locale) : {}),\n [draft, locale],\n )\n const derived = applySlugify(slugConfig, slugSourceValue(slugConfig, source.schema, values))\n\n // Track whether the slug was manually set — auto-derive stays active while the\n // slug is empty or was last produced by auto-derivation (never overwrites a manual\n // slug). Seeded true when the loaded document already carries a slug.\n const [manuallyEdited, setManuallyEdited] = useState(() => current.trim() !== '')\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n useEffect(() => {\n if (readOnly || manuallyEdited) return\n if (derived && derived !== current) onChangeRef.current(derived)\n }, [derived, manuallyEdited, readOnly, current])\n\n // The composed path parts (routable collections with a document editor only).\n const siblings = draft ? source.documents() : []\n // Draft-derived (routes + locale only, no `frontendUrl`) — the composed path is a\n // read-only preview that updates as you type, mirroring the detail editor's draft\n // URL. The header's published-gated \"View live\" stays the sole open-live action,\n // so the draft/live distinction is preserved (an unpublished slug never links out).\n const parts: SlugPathParts | undefined =\n draft && routable\n ? resolveSlugPath({ routes, localeConfig }, source.schema, draft, { siblings, locale })\n : undefined\n // The classified context segments (0.0.42, round 3) — the same `resolveUrlSegments`\n // the header URL row uses, so the slug prefix and the header path attribute each\n // segment identically. Everything before this document's own `current` slug is the\n // context prefix; its LAST segment is the immediate parent shown in the compact pill.\n const contextSegments: UrlSegment[] =\n draft && routable\n ? resolveUrlSegments({ routes, localeConfig }, source.schema, draft, { siblings, locale }).filter(\n (s) => s.kind !== 'current',\n )\n : []\n const lastContext = contextSegments[contextSegments.length - 1]\n\n // Default (sync) uniqueness — the first colliding sibling's title, or null.\n const defaultCollisionTitle = useMemo<string | null>(() => {\n if (slugConfig?.unique || !draft) return null\n const trimmed = current.trim()\n if (trimmed === '') return null\n const hit = findSlugCollision(trimmed, draft, source.documents(), {\n collection: source.schema,\n locale,\n localeConfig,\n })\n return hit ? source.titleOf({ collection: source.collectionId, id: hit.id }) : null\n }, [current, draft, slugConfig, locale, localeConfig, source])\n\n // Custom (possibly async) uniqueness hook — race-guarded.\n const [asyncTaken, setAsyncTaken] = useState(false)\n useEffect(() => {\n const unique = slugConfig?.unique\n if (!unique || !draft) {\n setAsyncTaken(false)\n return\n }\n const trimmed = current.trim()\n if (trimmed === '') {\n setAsyncTaken(false)\n return\n }\n let cancelled = false\n Promise.resolve(unique(trimmed, { document: draft, locale, siblings: source.documents() }))\n .then((ok) => {\n if (!cancelled) setAsyncTaken(ok === false)\n })\n .catch(() => {\n if (!cancelled) setAsyncTaken(false)\n })\n return () => {\n cancelled = true\n }\n }, [current, slugConfig, draft, locale, source])\n\n const collisionMessage = slugConfig?.unique\n ? asyncTaken\n ? translate('cms.field.slug.takenGeneric')\n : undefined\n : defaultCollisionTitle\n ? translate('cms.field.slug.taken', { title: defaultCollisionTitle })\n : undefined\n\n function handleInput(next: string) {\n onChange(next || undefined)\n // Clearing re-enables auto-derive; any non-empty entry is a manual override.\n setManuallyEdited(next.trim() !== '')\n }\n\n function regenerate() {\n setManuallyEdited(false)\n const next = applySlugify(slugConfig, slugSourceValue(slugConfig, source.schema, values))\n onChange(next || undefined)\n }\n\n // No document editor (a picker), or a name-based auto-upgrade on a non-routable\n // collection: keep the historical plain input, no slug chrome (no regression).\n if (!editor || (!explicit && !routable)) {\n return (\n <Input\n id={id}\n disabled={readOnly}\n value={current}\n onChange={(e) => onChange(e.target.value || undefined)}\n />\n )\n }\n\n const input = (\n <Input\n id={id}\n disabled={readOnly}\n value={current}\n placeholder={derived || undefined}\n onChange={(e) => handleInput(e.target.value)}\n className={cn(parts ? 'h-7 min-w-[10ch] flex-1 bg-background font-mono text-xs' : 'flex-1')}\n />\n )\n const regenerateButton = !readOnly ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={regenerate}\n aria-label={translate('cms.field.slug.regenerate')}\n title={translate('cms.field.slug.regenerate')}\n >\n <RotateCw />\n </Button>\n ) : null\n\n // The compact, ellipsized read-only prefix (0.0.39 \"hybrid split\", round-3 clickable):\n // only the LAST context segment (`…/produkte/`) so a deep path can't overflow the\n // narrow Details sidebar — but that shown segment is now CLICKABLE with the same\n // navigation semantics as the header URL row (an ancestor DOCUMENT links to its\n // editor; a static route literal stays plain). The full composed path is the tooltip.\n const prefixTitle =\n parts?.path ??\n (contextSegments.length > 0 ? `/${contextSegments.map((s) => s.text).join('/')}/` : '/')\n\n return (\n <Stack gap=\"2\">\n {parts ? (\n <Row gap=\"1\" align=\"center\" data-testid=\"slug-composed-path\">\n <span\n className=\"inline-flex min-w-0 shrink-0 items-center rounded bg-muted/40 px-1.5 py-1 font-mono text-xs text-muted-foreground ring-1 ring-inset ring-border\"\n title={prefixTitle}\n data-testid=\"slug-prefix\"\n >\n {contextSegments.length === 0 ? (\n <span aria-hidden className=\"text-muted-foreground/50\">\n /\n </span>\n ) : (\n <>\n <span aria-hidden className=\"text-muted-foreground/50\">\n {contextSegments.length > 1 ? '…/' : '/'}\n </span>\n {lastContext ? (\n <DocumentUrlSegment\n segment={lastContext}\n projectId={editor?.projectId}\n collectionId={source.collectionId}\n />\n ) : null}\n <span aria-hidden className=\"text-muted-foreground/50\">\n /\n </span>\n </>\n )}\n </span>\n {input}\n {regenerateButton}\n </Row>\n ) : (\n <Row gap=\"1\" align=\"center\">\n {input}\n {regenerateButton}\n </Row>\n )}\n\n {collisionMessage ? (\n <Row gap=\"1\" align=\"center\" data-testid=\"slug-collision\">\n <AlertTriangle className=\"size-3.5 shrink-0 text-warning\" aria-hidden />\n <Text size=\"xs\" tone=\"muted\">\n {collisionMessage}\n </Text>\n </Row>\n ) : null}\n </Stack>\n )\n}\n\nfunction RelationField({\n field,\n value,\n onChange,\n readOnly,\n}: {\n field: RelationFieldDef\n value: unknown\n onChange: (value: unknown) => void\n readOnly: boolean\n}) {\n const source = useCollectionView()\n const editor = useOptionalDocumentEditor()\n const [open, setOpen] = useState(false)\n const refs = toRefArray(value)\n const projectId = source.projectId\n\n // EC-218: for the editing document's `parent` self-relation, exclude the\n // document itself and its descendants from the picker — choosing one would make\n // the page its own ancestor (a cycle). Only applies to the parent field of a\n // hierarchical collection; ordinary relations (and other self-relations) are\n // unrestricted. validateDocument is the backstop where this context is absent.\n const excludeIds = useMemo<Set<string> | undefined>(() => {\n if (!editor || field.target !== editor.collection.id) return undefined\n if (parentRelationField(editor.collection)?.name !== field.name) return undefined\n const ids = descendantIds(editor.docRef.id, source.referenceCandidates(editor.collection.id))\n ids.add(editor.docRef.id)\n return ids\n }, [editor, field.target, field.name, source])\n\n function apply(next: DocumentRef[]) {\n onChange(field.multiple ? next : (next[0] ?? undefined))\n }\n\n return (\n <Stack gap=\"2\">\n {refs.length > 0 ? (\n <Stack gap=\"1\">\n {refs.map((ref, i) => {\n // EC-296: the relation title navigates to the referenced document (autosave\n // keeps the current edit safe). Without a projectId (no persistence, e.g.\n // fixtures) it stays plain text. EC-246c: full-width row, not a pill —\n // long titles wrap awkwardly in a pill and a narrow field crushes it.\n const title = source.titleOf(ref)\n const label = (\n <span className=\"inline-flex min-w-0 items-center gap-1.5\">\n <Link2 className=\"size-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 truncate\">{title}</span>\n </span>\n )\n return (\n <RowItem\n key={`${ref.id}-${i}`}\n data-testid=\"relation-value\"\n actions={\n !readOnly ? (\n <>\n {field.multiple === false ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={translate('cms.relation.change')}\n title={translate('cms.relation.change')}\n onClick={() => setOpen(true)}\n >\n <Pencil />\n </Button>\n ) : null}\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={translate('common.remove')}\n title={translate('common.remove')}\n className=\"hover:text-destructive\"\n onClick={() => apply(refs.filter((r) => r.id !== ref.id))}\n >\n <X />\n </Button>\n </>\n ) : undefined\n }\n >\n {projectId ? (\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.cmsDocument(ref.collection, ref.id) }}\n title={translate('cms.relation.openTitle', { title })}\n className=\"text-sm font-medium hover:text-primary hover:underline\"\n >\n {label}\n </Link>\n ) : (\n <Text as=\"span\" size=\"sm\" weight=\"medium\">\n {label}\n </Text>\n )}\n </RowItem>\n )\n })}\n </Stack>\n ) : null}\n {!readOnly && (refs.length === 0 || field.multiple) ? (\n <Row>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setOpen(true)}>\n <Plus /> {refs.length === 0 ? translate('cms.relation.pick') : translate('common.add')}\n </Button>\n </Row>\n ) : null}\n <RelationPicker\n targetCollection={field.target}\n multiple={field.multiple}\n value={refs}\n open={open}\n onOpenChange={setOpen}\n onChange={apply}\n excludeIds={excludeIds}\n />\n </Stack>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"field-control.js","sourceRoot":"","sources":["../../../src/components/cms/field-control.tsx"],"names":[],"mappings":"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","sourcesContent":["import { AlertTriangle, Link2, Pencil, Plus, RotateCw, X } from 'lucide-react'\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport type {\n DocumentRef,\n FieldDef,\n RelationFieldDef,\n UrlSegment,\n} from '@elytracms/core/cms-core'\nimport {\n BUILTIN_FIELD_CONTROLS,\n applySlugify,\n descendantIds,\n findSlugCollision,\n parentRelationField,\n resolveSlugPath,\n resolveUrlSegments,\n slugSourceValue,\n} from '@elytracms/core/cms-core'\nimport type { SlugFieldConfig, SlugPathParts } from '@elytracms/core/cms-core'\nimport { resolveDeploymentRoutes } from '@elytracms/studio/lib/workspace'\nimport {\n Button,\n Input,\n Row,\n RowItem,\n Select,\n Stack,\n Text,\n} from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { activeLocaleValues } from '@elytracms/studio/lib/locale'\nimport { useCollectionView } from '../collection-view/collection-view-context'\nimport { fieldLabel } from './cms-labels'\nimport { useOptionalDocumentEditor } from './document-editor-context'\nimport { toRefArray } from './cell'\nimport { RelationPicker } from './relation-picker'\nimport { RichTextEditor } from './rich-text'\nimport { DocumentUrlSegment } from './document-url-path'\nimport { AssetField } from './asset-field'\nimport { SegmentedOptions } from './field-control-lib'\nimport { ObjectField } from './object-array-field'\nimport {\n FieldRendererBoundary,\n FieldRendererIssue,\n useFieldRenderers,\n} from './field-renderer'\n\ninterface FieldControlProps {\n field: FieldDef\n value: unknown\n onChange: (value: unknown) => void\n readOnly: boolean\n id: string\n}\n\n/**\n * The document-editor field control. Resolves a project's custom renderer by the\n * field's `form.control` (EC-238, customization seam EC-236) and falls back to the\n * built-in control for the field's datatype: a registered renderer renders inside\n * an error boundary (a throw → the built-in + a visible issue); a rejected\n * registration (non-component) shows the built-in with the issue above it; a field\n * naming a control with NO renderer and NO built-in name (a typo) shows the\n * built-in with a loud issue — never a silent fall-through; otherwise the built-in\n * renders alone.\n *\n * EC-330 split: the asset-field family lives in `asset-field.tsx`, the object /\n * repeater editors in `object-array-field.tsx`, and their pure companions\n * (reorder/summary/depth/table decisions, the `options` segmented control) in\n * `field-control-lib.tsx` — this file keeps the dispatcher plus the slug and\n * relation controls.\n */\nexport function FieldControl(props: FieldControlProps) {\n const renderers = useFieldRenderers()\n const builtIn = <BuiltInFieldControl {...props} />\n const control = props.field.form?.control\n const Custom = control ? renderers.get(control) : undefined\n if (Custom) {\n return (\n <FieldRendererBoundary\n fallback={builtIn}\n issue={<FieldRendererIssue message={translate('cms.field.rendererCrashed')} />}\n >\n <Custom {...props} />\n </FieldRendererBoundary>\n )\n }\n if (control) {\n const rejected = renderers.issues.find((issue) => issue.id === control)\n if (rejected) {\n return (\n <Stack gap=\"1\">\n <FieldRendererIssue message={rejected.message} />\n {builtIn}\n </Stack>\n )\n }\n // The field asks for a control with no registered renderer and no built-in\n // name — surface it (a typo'd `control` would otherwise read as a plain input).\n if (!(BUILTIN_FIELD_CONTROLS as readonly string[]).includes(control)) {\n return (\n <Stack gap=\"1\">\n <FieldRendererIssue message={translate('cms.field.noRenderer', { control })} />\n {builtIn}\n </Stack>\n )\n }\n }\n return builtIn\n}\n\n/** The conventional slug field name (mirrors `url-for-document`'s `SLUG_FIELD`). */\nconst SLUG_FIELD_NAME = 'slug'\n/** The built-in control name that opts any `text` field into the slug control (EC-315). */\nconst SLUG_CONTROL = 'slug'\n\n/**\n * EC-315: a `text` field is rendered by the smart slug control when it opts in via\n * `form.control: 'slug'`, OR (the default auto-upgrade) when it is simply named\n * `slug` — the long-standing convention `url-for-document`/hierarchy already key off.\n */\nfunction isSlugControl(field: FieldDef): boolean {\n return field.type === 'text' && (field.form?.control === SLUG_CONTROL || field.name === SLUG_FIELD_NAME)\n}\n\nfunction BuiltInFieldControl({ field, value, onChange, readOnly, id }: FieldControlProps) {\n // EC-315: the smart slug control (composed path, auto-slug, per-locale segments)\n // subsumes the old inline `slug` input + PathPreview. It degrades to a plain input\n // when the collection isn't routable (name-based auto-upgrade only) or no document\n // editor context is present (e.g. a table-cell picker).\n if (isSlugControl(field)) {\n return <SlugField field={field} value={value} onChange={onChange} readOnly={readOnly} id={id} />\n }\n switch (field.type) {\n case 'boolean':\n return (\n <label className=\"flex h-8 items-center gap-2 text-sm\">\n <input\n id={id}\n type=\"checkbox\"\n checked={value === true}\n disabled={readOnly}\n onChange={(e) => onChange(e.target.checked)}\n className=\"size-4 accent-primary disabled:opacity-50\"\n />\n <Text size=\"sm\" tone=\"muted\">\n {translate(value === true ? 'common.true' : 'common.false')}\n </Text>\n </label>\n )\n case 'number':\n return (\n <Input\n id={id}\n type=\"number\"\n disabled={readOnly}\n value={typeof value === 'number' ? value : ''}\n onChange={(e) => onChange(e.target.value === '' ? undefined : Number(e.target.value))}\n />\n )\n case 'date':\n return (\n <Input\n id={id}\n type=\"date\"\n disabled={readOnly}\n value={typeof value === 'string' ? value.slice(0, 10) : ''}\n onChange={(e) => onChange(e.target.value ? `${e.target.value}T00:00:00.000Z` : undefined)}\n />\n )\n case 'select':\n if (field.multiple) {\n const selected = Array.isArray(value) ? (value as string[]) : []\n return (\n <Row gap=\"2\" wrap>\n {field.options.map((opt) => {\n const on = selected.includes(opt.value)\n return (\n <label key={opt.value} className=\"flex items-center gap-1.5 text-sm\">\n <input\n type=\"checkbox\"\n checked={on}\n disabled={readOnly}\n onChange={() =>\n onChange(\n on ? selected.filter((v) => v !== opt.value) : [...selected, opt.value],\n )\n }\n className=\"size-4 accent-primary\"\n />\n {localizedLabel(opt.label, opt.value)}\n </label>\n )\n })}\n </Row>\n )\n }\n // EC-295: the `options` control renders a small fixed enumeration as inline\n // segmented buttons instead of the dropdown (single-select only).\n if (field.form?.control === 'options') {\n return (\n <SegmentedOptions field={field} value={value} onChange={onChange} readOnly={readOnly} id={id} />\n )\n }\n return (\n <Select\n id={id}\n disabled={readOnly}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value || undefined)}\n >\n <option value=\"\">—</option>\n {field.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {localizedLabel(opt.label, opt.value)}\n </option>\n ))}\n </Select>\n )\n case 'richText':\n return (\n <RichTextEditor\n value={value}\n onChange={onChange}\n readOnly={readOnly}\n id={id}\n allow={field.allow}\n // EC-436: the SAME resolved localized label the field row renders (the\n // EC-241 `fieldLabel` path) — titles the expand stage \"<label> — Rich text\".\n label={fieldLabel(field)}\n />\n )\n case 'relation':\n return <RelationField field={field} value={value} onChange={onChange} readOnly={readOnly} />\n case 'asset':\n return <AssetField field={field} value={value} onChange={onChange} readOnly={readOnly} />\n case 'object':\n return <ObjectField field={field} value={value} onChange={onChange} readOnly={readOnly} id={id} />\n default:\n return (\n <Input\n id={id}\n disabled={readOnly}\n value={typeof value === 'string' ? value : ''}\n onChange={(e) => onChange(e.target.value || undefined)}\n />\n )\n }\n}\n\n/**\n * EC-315 — the smart slug / URL-segment control. A `text` field named `slug` (or any\n * `text` field with `form.control: 'slug'`) renders here instead of a bare input:\n *\n * - **Composed path**: the route-derived URL, decomposed by {@link resolveSlugPath}\n * into read-only parent/context segments + the editable slug segment inline + the\n * locale prefix (non-default locales). Reuses the same `urlForDocument` the live\n * site uses, so the preview matches what visitors get. Draft-derived (updates as\n * you type); the live \"View live\" button in the header stays the published open.\n * - **Auto-slug**: while the slug is empty or was last produced by auto-derivation,\n * it live-derives from the source field (default: the collection's `titleField`).\n * A manual edit stops the auto-fill; the ↻ button always re-derives.\n * - **Per-locale**: reads/writes through the shared `value`/`onChange` seam, so a\n * `localized` slug edits the active locale's segment with no bespoke locale code.\n * - **Uniqueness**: an inline warning when the candidate collides with a sibling in\n * the same scope (same parent when hierarchical, same locale). A custom\n * `slug.unique` hook replaces the default sibling scan.\n *\n * Degrades to a plain input when there is no document editor context (a table-cell\n * picker) or when a name-based auto-upgrade lands on a non-routable collection.\n */\nfunction SlugField({\n field,\n value,\n onChange,\n readOnly,\n id,\n}: {\n field: FieldDef\n value: unknown\n onChange: (value: unknown) => void\n readOnly: boolean\n id: string\n}) {\n const source = useCollectionView()\n const editor = useOptionalDocumentEditor()\n const slugConfig = field.slug as SlugFieldConfig | undefined\n const explicit = field.form?.control === SLUG_CONTROL\n const current = typeof value === 'string' ? value : ''\n const locale = source.activeLocale\n const localeConfig = source.localeConfig\n\n // 0.0.39 regression fix: resolve the deployment routes on EVERY render (a cheap\n // synchronous accessor), never freeze them at first paint. The earlier\n // `useMemo(() => resolveDeploymentRoutes(), [])` captured the EMPTY route set from\n // before the workspace/config finished loading — so the composed path never\n // appeared once routes arrived, and a stale set could paint a misleading prefix.\n const routes = resolveDeploymentRoutes()\n const routable = routes.some((r) => r.document?.collection === source.collectionId)\n\n const draft = editor?.draft\n // The active-locale value bag the auto-slug source derives from (title, etc.).\n const values = useMemo<Record<string, unknown>>(\n () => (draft ? activeLocaleValues(draft, locale) : {}),\n [draft, locale],\n )\n const derived = applySlugify(slugConfig, slugSourceValue(slugConfig, source.schema, values))\n\n // Track whether the slug was manually set — auto-derive stays active while the\n // slug is empty or was last produced by auto-derivation (never overwrites a manual\n // slug). Seeded true when the loaded document already carries a slug.\n const [manuallyEdited, setManuallyEdited] = useState(() => current.trim() !== '')\n const onChangeRef = useRef(onChange)\n onChangeRef.current = onChange\n useEffect(() => {\n if (readOnly || manuallyEdited) return\n if (derived && derived !== current) onChangeRef.current(derived)\n }, [derived, manuallyEdited, readOnly, current])\n\n // The composed path parts (routable collections with a document editor only).\n const siblings = draft ? source.documents() : []\n // Draft-derived (routes + locale only, no `frontendUrl`) — the composed path is a\n // read-only preview that updates as you type, mirroring the detail editor's draft\n // URL. The header's published-gated \"View live\" stays the sole open-live action,\n // so the draft/live distinction is preserved (an unpublished slug never links out).\n const parts: SlugPathParts | undefined =\n draft && routable\n ? resolveSlugPath({ routes, localeConfig }, source.schema, draft, { siblings, locale })\n : undefined\n // The classified context segments (0.0.42, round 3) — the same `resolveUrlSegments`\n // the header URL row uses, so the slug prefix and the header path attribute each\n // segment identically. Everything before this document's own `current` slug is the\n // context prefix; its LAST segment is the immediate parent shown in the compact pill.\n const contextSegments: UrlSegment[] =\n draft && routable\n ? resolveUrlSegments({ routes, localeConfig }, source.schema, draft, { siblings, locale }).filter(\n (s) => s.kind !== 'current',\n )\n : []\n const lastContext = contextSegments[contextSegments.length - 1]\n\n // Default (sync) uniqueness — the first colliding sibling's title, or null.\n const defaultCollisionTitle = useMemo<string | null>(() => {\n if (slugConfig?.unique || !draft) return null\n const trimmed = current.trim()\n if (trimmed === '') return null\n const hit = findSlugCollision(trimmed, draft, source.documents(), {\n collection: source.schema,\n locale,\n localeConfig,\n })\n return hit ? source.titleOf({ collection: source.collectionId, id: hit.id }) : null\n }, [current, draft, slugConfig, locale, localeConfig, source])\n\n // Custom (possibly async) uniqueness hook — race-guarded.\n const [asyncTaken, setAsyncTaken] = useState(false)\n useEffect(() => {\n const unique = slugConfig?.unique\n if (!unique || !draft) {\n setAsyncTaken(false)\n return\n }\n const trimmed = current.trim()\n if (trimmed === '') {\n setAsyncTaken(false)\n return\n }\n let cancelled = false\n Promise.resolve(unique(trimmed, { document: draft, locale, siblings: source.documents() }))\n .then((ok) => {\n if (!cancelled) setAsyncTaken(ok === false)\n })\n .catch(() => {\n if (!cancelled) setAsyncTaken(false)\n })\n return () => {\n cancelled = true\n }\n }, [current, slugConfig, draft, locale, source])\n\n const collisionMessage = slugConfig?.unique\n ? asyncTaken\n ? translate('cms.field.slug.takenGeneric')\n : undefined\n : defaultCollisionTitle\n ? translate('cms.field.slug.taken', { title: defaultCollisionTitle })\n : undefined\n\n function handleInput(next: string) {\n onChange(next || undefined)\n // Clearing re-enables auto-derive; any non-empty entry is a manual override.\n setManuallyEdited(next.trim() !== '')\n }\n\n function regenerate() {\n setManuallyEdited(false)\n const next = applySlugify(slugConfig, slugSourceValue(slugConfig, source.schema, values))\n onChange(next || undefined)\n }\n\n // No document editor (a picker), or a name-based auto-upgrade on a non-routable\n // collection: keep the historical plain input, no slug chrome (no regression).\n if (!editor || (!explicit && !routable)) {\n return (\n <Input\n id={id}\n disabled={readOnly}\n value={current}\n onChange={(e) => onChange(e.target.value || undefined)}\n />\n )\n }\n\n const input = (\n <Input\n id={id}\n disabled={readOnly}\n value={current}\n placeholder={derived || undefined}\n onChange={(e) => handleInput(e.target.value)}\n className={cn(parts ? 'h-7 min-w-[10ch] flex-1 bg-background font-mono text-xs' : 'flex-1')}\n />\n )\n const regenerateButton = !readOnly ? (\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={regenerate}\n aria-label={translate('cms.field.slug.regenerate')}\n title={translate('cms.field.slug.regenerate')}\n >\n <RotateCw />\n </Button>\n ) : null\n\n // The compact, ellipsized read-only prefix (0.0.39 \"hybrid split\", round-3 clickable):\n // only the LAST context segment (`…/produkte/`) so a deep path can't overflow the\n // narrow Details sidebar — but that shown segment is now CLICKABLE with the same\n // navigation semantics as the header URL row (an ancestor DOCUMENT links to its\n // editor; a static route literal stays plain). The full composed path is the tooltip.\n const prefixTitle =\n parts?.path ??\n (contextSegments.length > 0 ? `/${contextSegments.map((s) => s.text).join('/')}/` : '/')\n\n return (\n <Stack gap=\"2\">\n {parts ? (\n <Row gap=\"1\" align=\"center\" data-testid=\"slug-composed-path\">\n <span\n className=\"inline-flex min-w-0 shrink-0 items-center rounded bg-muted/40 px-1.5 py-1 font-mono text-xs text-muted-foreground ring-1 ring-inset ring-border\"\n title={prefixTitle}\n data-testid=\"slug-prefix\"\n >\n {contextSegments.length === 0 ? (\n <span aria-hidden className=\"text-muted-foreground/50\">\n /\n </span>\n ) : (\n <>\n <span aria-hidden className=\"text-muted-foreground/50\">\n {contextSegments.length > 1 ? '…/' : '/'}\n </span>\n {lastContext ? (\n <DocumentUrlSegment\n segment={lastContext}\n projectId={editor?.projectId}\n collectionId={source.collectionId}\n />\n ) : null}\n <span aria-hidden className=\"text-muted-foreground/50\">\n /\n </span>\n </>\n )}\n </span>\n {input}\n {regenerateButton}\n </Row>\n ) : (\n <Row gap=\"1\" align=\"center\">\n {input}\n {regenerateButton}\n </Row>\n )}\n\n {collisionMessage ? (\n <Row gap=\"1\" align=\"center\" data-testid=\"slug-collision\">\n <AlertTriangle className=\"size-3.5 shrink-0 text-warning\" aria-hidden />\n <Text size=\"xs\" tone=\"muted\">\n {collisionMessage}\n </Text>\n </Row>\n ) : null}\n </Stack>\n )\n}\n\nfunction RelationField({\n field,\n value,\n onChange,\n readOnly,\n}: {\n field: RelationFieldDef\n value: unknown\n onChange: (value: unknown) => void\n readOnly: boolean\n}) {\n const source = useCollectionView()\n const editor = useOptionalDocumentEditor()\n const [open, setOpen] = useState(false)\n const refs = toRefArray(value)\n const projectId = source.projectId\n\n // EC-218: for the editing document's `parent` self-relation, exclude the\n // document itself and its descendants from the picker — choosing one would make\n // the page its own ancestor (a cycle). Only applies to the parent field of a\n // hierarchical collection; ordinary relations (and other self-relations) are\n // unrestricted. validateDocument is the backstop where this context is absent.\n const excludeIds = useMemo<Set<string> | undefined>(() => {\n if (!editor || field.target !== editor.collection.id) return undefined\n if (parentRelationField(editor.collection)?.name !== field.name) return undefined\n const ids = descendantIds(editor.docRef.id, source.referenceCandidates(editor.collection.id))\n ids.add(editor.docRef.id)\n return ids\n }, [editor, field.target, field.name, source])\n\n function apply(next: DocumentRef[]) {\n onChange(field.multiple ? next : (next[0] ?? undefined))\n }\n\n return (\n <Stack gap=\"2\">\n {refs.length > 0 ? (\n <Stack gap=\"1\">\n {refs.map((ref, i) => {\n // EC-296: the relation title navigates to the referenced document (autosave\n // keeps the current edit safe). Without a projectId (no persistence, e.g.\n // fixtures) it stays plain text. EC-246c: full-width row, not a pill —\n // long titles wrap awkwardly in a pill and a narrow field crushes it.\n const title = source.titleOf(ref)\n const label = (\n <span className=\"inline-flex min-w-0 items-center gap-1.5\">\n <Link2 className=\"size-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 truncate\">{title}</span>\n </span>\n )\n return (\n <RowItem\n key={`${ref.id}-${i}`}\n data-testid=\"relation-value\"\n actions={\n !readOnly ? (\n <>\n {field.multiple === false ? (\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={translate('cms.relation.change')}\n title={translate('cms.relation.change')}\n onClick={() => setOpen(true)}\n >\n <Pencil />\n </Button>\n ) : null}\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n aria-label={translate('common.remove')}\n title={translate('common.remove')}\n className=\"hover:text-destructive\"\n onClick={() => apply(refs.filter((r) => r.id !== ref.id))}\n >\n <X />\n </Button>\n </>\n ) : undefined\n }\n >\n {projectId ? (\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.cmsDocument(ref.collection, ref.id) }}\n title={translate('cms.relation.openTitle', { title })}\n className=\"text-sm font-medium hover:text-primary hover:underline\"\n >\n {label}\n </Link>\n ) : (\n <Text as=\"span\" size=\"sm\" weight=\"medium\">\n {label}\n </Text>\n )}\n </RowItem>\n )\n })}\n </Stack>\n ) : null}\n {!readOnly && (refs.length === 0 || field.multiple) ? (\n <Row>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setOpen(true)}>\n <Plus /> {refs.length === 0 ? translate('cms.relation.pick') : translate('common.add')}\n </Button>\n </Row>\n ) : null}\n <RelationPicker\n targetCollection={field.target}\n multiple={field.multiple}\n value={refs}\n open={open}\n onOpenChange={setOpen}\n onChange={apply}\n excludeIds={excludeIds}\n />\n </Stack>\n )\n}\n"]}
|
|
@@ -138,7 +138,11 @@ export function PropValueControl({ id, name, spec, value, onSet, onClear }) {
|
|
|
138
138
|
// preview surface (no provider, nothing to edit against) degrades to the same
|
|
139
139
|
// read-only value display the sibling controls use, instead of crashing with
|
|
140
140
|
// "useCollectionView must be used within a <CollectionViewProvider>".
|
|
141
|
-
control = hasWorkspaceContext ? (_jsx(RichTextEditor, { id: id, value: current, onChange: (next) => applyRichTextPropChange(next, { onSet, onClear }), allow: spec.type === 'richText' ? spec.allow : undefined, readOnly: readOnly
|
|
141
|
+
control = hasWorkspaceContext ? (_jsx(RichTextEditor, { id: id, value: current, onChange: (next) => applyRichTextPropChange(next, { onSet, onClear }), allow: spec.type === 'richText' ? spec.allow : undefined, readOnly: readOnly,
|
|
142
|
+
// EC-436: the SAME resolved localized label the prop row renders (the
|
|
143
|
+
// property inspector / embed form's `Field label`) — titles the expand
|
|
144
|
+
// stage "<label> — Rich text".
|
|
145
|
+
label: localizedLabel(spec.form?.label, name) })) : (_jsx(WorkspaceValueFallback, { value: current }));
|
|
142
146
|
}
|
|
143
147
|
else if (kind === 'textarea') {
|
|
144
148
|
control = (_jsx("textarea", { id: id, rows: 2, disabled: readOnly, value: typeof current === 'string' ? current : '', onChange: (e) => onSet(e.target.value), className: "flex w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-sm text-foreground shadow-sm focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40 outline-none disabled:cursor-not-allowed disabled:opacity-50" }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prop-fields.js","sourceRoot":"","sources":["../../../src/components/cms/prop-fields.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useState } from 'react'\nimport { isStaticProp } from '@elytracms/core/project-graph'\nimport type { JsonValue, PropValue } from '@elytracms/core/project-graph'\nimport type { PropField } from '@elytracms/core/component-registry'\nimport { fieldValueValidator } from '@elytracms/core/cms-core'\nimport type { FieldDef, SelectFieldDef, SelectOption } from '@elytracms/core/cms-core'\nimport { Input, Row, Select, Stack, Text } from '@elytracms/studio/ui'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { FieldControl } from './field-control'\nimport { SegmentedOptions } from './field-control-lib'\nimport { FieldDensityProvider } from './field-density'\nimport { RichTextEditor } from './rich-text'\nimport { useOptionalCollectionView } from '../collection-view/collection-view-context'\n\n/**\n * The EC-190 \"props-as-fields\" value control — the single renderer for a\n * manifest-declared prop field, shared by the canvas property inspector\n * (`builder/property-inspector.tsx`) and the rich-text component-embed prop editor\n * (`rich-text/embed-props.tsx`). Extracted here so both surfaces render prop fields\n * through *one* control set (asset → library picker, relation → document picker,\n * object → nested form, …) rather than two parallel form systems.\n *\n * It is deliberately store-agnostic: it reads a prop's current value and reports\n * edits through `onSet(rawValue)` / `onClear()`. The caller owns *where* the value\n * lands — the inspector dispatches a builder command; the embed editor rewrites a\n * ProseMirror node attr — and is responsible for wrapping the raw value in a\n * `staticProp` envelope.\n */\n\n/**\n * The inspector control to render for a prop field-def. The `control.kind`\n * vocabulary derives from the field `type` plus the optional `form.control`\n * presentation hint on `text` fields.\n */\nexport type ControlKind =\n | 'text'\n | 'textarea'\n | 'number'\n | 'boolean'\n | 'select'\n | 'options'\n | 'json'\n | 'color'\n | 'richtext'\n | 'asset'\n | 'object'\n | 'relation'\n\nexport function controlKind(spec: PropField): ControlKind {\n switch (spec.type) {\n case 'boolean':\n return 'boolean'\n case 'number':\n return 'number'\n case 'select':\n // EC-393: a single-select prop opting into `form.control: 'options'` renders the\n // SAME segmented button group the document form uses (EC-295), not the native\n // dropdown — parity with `field-control.tsx`. Segmented is single-select only,\n // so a `multiple` select stays on the native control (mirroring field-control).\n if (spec.form?.control === 'options' && !spec.multiple) return 'options'\n return 'select'\n case 'richText':\n return 'richtext'\n // EC-195: an `asset`-typed prop (e.g. the Image `src`) picks from the asset\n // library — never a raw asset id typed into a text box (the EC-192 persona).\n case 'asset':\n return 'asset'\n // EC-253: an `object`/repeater prop reuses the CMS repeater control below.\n case 'object':\n return 'object'\n // EC-262: a `relation`-typed prop (e.g. a ProductGrid's `category`) reuses the\n // CMS relation picker — never a text box that stringifies the ref to \"[object Object]\".\n case 'relation':\n return 'relation'\n case 'text': {\n const c = spec.form?.control\n if (c === 'textarea') return 'textarea'\n if (c === 'color') return 'color'\n if (c === 'json') return 'json'\n return 'text'\n }\n default:\n return 'text'\n }\n}\n\n/**\n * EC-387: route a rich-text editor emission to the prop value callbacks.\n *\n * The shared {@link RichTextEditor} emits either an emptied-editor `undefined`, the\n * exact stored envelope (an untouched/reverted edit), or a fresh `{ version, doc }`\n * value — never a plain string. An `undefined` clears the prop (reverting to the\n * manifest default, matching the asset/relation/object controls); anything else is a\n * structured `JsonValue` envelope set verbatim. Extracted pure so the wiring — the\n * exact bug the retired textarea stub had (it wrote a bare string over the envelope) —\n * is regression-pinned without driving TipTap.\n */\nexport function applyRichTextPropChange(\n next: unknown,\n handlers: { onSet: (value: JsonValue) => void; onClear: () => void },\n): void {\n if (next === undefined) handlers.onClear()\n else handlers.onSet(next as JsonValue)\n}\n\nexport interface PropValueControlProps {\n /** DOM id for the control's primary input (label `htmlFor` target). */\n id: string\n /** The prop's field name — needed to synthesize the `FieldDef` for reused controls. */\n name: string\n /** The manifest prop field-def driving the control kind + validation. */\n spec: PropField\n /** The prop's current value envelope (or `undefined` when unset). */\n value: PropValue | undefined\n /** Commit a new raw value (the caller wraps it in a `staticProp`). */\n onSet: (value: JsonValue) => void\n /** Remove the prop (revert to the manifest default). */\n onClear: () => void\n}\n\n/**\n * Render + edit a single manifest prop value. Store-agnostic: emits through\n * `onSet`/`onClear`. Shows a validation issue when the current value fails the\n * prop's field-def validator.\n */\nexport function PropValueControl({ id, name, spec, value, onSet, onClear }: PropValueControlProps) {\n const current = isStaticProp(value) ? value.value : (spec.default as JsonValue | undefined)\n // The `asset`/`relation`/`object` controls delegate to the CMS `FieldControl`,\n // which reads the ambient `CollectionViewSource` (asset library, relation\n // candidates, nested form). The component-registry preview surface has no\n // document/collection context, so outside a provider those controls must degrade\n // to a read-only value display instead of throwing \"useCollectionView must be\n // used within a <CollectionViewProvider>\" (the Konditorei Components-view crash).\n const hasWorkspaceContext = useOptionalCollectionView() != null\n\n // EC-190: validate with the prop's field-def value validator.\n const valid = current === undefined || fieldValueValidator({ ...spec, name } as FieldDef)(current)\n // EC-190: derive the editor control from the field `type` + optional `form.control`.\n const kind = controlKind(spec)\n // Select options live on the `select` field-def.\n const options: readonly SelectOption[] = spec.type === 'select' ? spec.options : []\n // EC-395: `form.readOnly` parity with the document form. `cms-store.tsx`'s\n // `isFieldReadOnly` reads the identical `field.form?.readOnly === true` check —\n // every control kind below (including the delegated `FieldControl`/\n // `SegmentedOptions` mounts, which previously hardcoded `readOnly={false}`)\n // degrades to the SAME disabled/inert interaction the document form's\n // `FieldControl` renders for a read-only field, not a parallel treatment.\n const readOnly = spec.form?.readOnly === true\n\n let control\n if (kind === 'boolean') {\n control = (\n <label className=\"flex h-8 items-center gap-2 text-sm\">\n <input\n id={id}\n type=\"checkbox\"\n checked={current === true}\n disabled={readOnly}\n onChange={(e) => onSet(e.target.checked)}\n className=\"size-4 accent-primary disabled:opacity-50\"\n />\n <Text size=\"sm\" tone=\"muted\">\n {current === true ? translate('common.true') : translate('common.false')}\n </Text>\n </label>\n )\n } else if (kind === 'select') {\n control = (\n <Select\n id={id}\n disabled={readOnly}\n value={String(current ?? '')}\n onChange={(e) => {\n // EC-190: select option values are strings (field-def `options`).\n const opt = options.find((o) => o.value === e.target.value)\n onSet(opt ? opt.value : e.target.value)\n }}\n >\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {localizedLabel(opt.label, opt.value)}\n </option>\n ))}\n </Select>\n )\n } else if (kind === 'options') {\n // EC-393: reuse the EC-295 segmented control the document form renders (via\n // `field-control.tsx`) — delegation over a parallel dropdown. It reads the\n // field-def's own `options` (label + per-option `description` tooltip); single-\n // select only (picks one, no unset — an unset select keeps the native dropdown).\n control = (\n <SegmentedOptions\n id={id}\n field={{ ...spec, name } as SelectFieldDef}\n value={current}\n onChange={(v) => onSet(v as JsonValue)}\n readOnly={readOnly}\n />\n )\n } else if (kind === 'number') {\n control = (\n <NumberControl id={id} current={current} onSet={onSet} onClear={onClear} readOnly={readOnly} />\n )\n } else if (kind === 'json') {\n control = <JsonControl id={id} current={current} onSet={onSet} readOnly={readOnly} />\n } else if (kind === 'color') {\n control = (\n <Row gap=\"2\">\n <input\n id={id}\n type=\"color\"\n disabled={readOnly}\n value={typeof current === 'string' && /^#[0-9a-f]{6}$/i.test(current) ? current : '#000000'}\n onChange={(e) => onSet(e.target.value)}\n className=\"h-8 w-10 shrink-0 rounded-md border border-input bg-background disabled:opacity-50\"\n />\n <Input\n disabled={readOnly}\n value={typeof current === 'string' ? current : ''}\n onChange={(e) => onSet(e.target.value)}\n />\n </Row>\n )\n } else if (kind === 'richtext') {\n // EC-387: a richText PROP now uses the SAME real editor as the collection-field\n // path (`field-control.tsx` `case 'richText'`) — one editing surface, one\n // `{ version, doc }` value contract, never a second implementation. The retired\n // textarea stub read `typeof current === 'string'`, so a stored envelope showed\n // EMPTY and any edit clobbered the structured document with a bare string\n // (silent data destruction). The editor reads the envelope (or a legacy string,\n // or empty), always emits an envelope, and routes an emptied editor's `undefined`\n // to a prop clear via {@link applyRichTextPropChange}.\n //\n // Like the asset/relation/object controls below, the editor needs the ambient\n // workspace — its asset-image picker reads the REQUIRED collection-view context.\n // The block property inspector (the EC-387 target) is inside the detail editor's\n // `CollectionViewProvider`, so it gets the full editor; the component-registry\n // preview surface (no provider, nothing to edit against) degrades to the same\n // read-only value display the sibling controls use, instead of crashing with\n // \"useCollectionView must be used within a <CollectionViewProvider>\".\n control = hasWorkspaceContext ? (\n <RichTextEditor\n id={id}\n value={current}\n onChange={(next) => applyRichTextPropChange(next, { onSet, onClear })}\n allow={spec.type === 'richText' ? spec.allow : undefined}\n readOnly={readOnly}\n />\n ) : (\n <WorkspaceValueFallback value={current} />\n )\n } else if (kind === 'textarea') {\n control = (\n <textarea\n id={id}\n rows={2}\n disabled={readOnly}\n value={typeof current === 'string' ? current : ''}\n onChange={(e) => onSet(e.target.value)}\n className=\"flex w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-sm text-foreground shadow-sm focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40 outline-none disabled:cursor-not-allowed disabled:opacity-50\"\n />\n )\n } else if (kind === 'asset' || kind === 'object' || kind === 'relation') {\n // EC-195/EC-253/EC-262: reuse the CMS field control. `asset` = library picker +\n // preview; `object` = the nested/repeater form; `relation` = the document picker\n // (resolves the ref to its title, instead of stringifying it to \"[object Object]\").\n // All edit a structured static prop value through the same shared control documents use.\n // Without a workspace context (the Components preview), degrade to a read-only\n // value display so the pane renders instead of throwing.\n control = hasWorkspaceContext ? (\n <FieldDensityProvider density=\"compact\">\n <FieldControl\n id={id}\n field={{ ...spec, name } as FieldDef}\n value={current}\n onChange={(v) => (v === undefined || v === null ? onClear() : onSet(v as JsonValue))}\n readOnly={readOnly}\n />\n </FieldDensityProvider>\n ) : (\n <WorkspaceValueFallback value={current} />\n )\n } else {\n control = (\n <Input\n id={id}\n disabled={readOnly}\n value={typeof current === 'string' ? current : String(current ?? '')}\n onChange={(e) => onSet(e.target.value)}\n />\n )\n }\n\n return (\n <Stack gap=\"1\">\n {control}\n {/* EC-395: a read-only prop's value can't be fixed here — suppress the\n invalid-value flag exactly like the document form suppresses its field\n error on a read-only row (`detail-editor.tsx`'s\n `error={fieldReadOnly ? undefined : ...}`). */}\n {!valid && !readOnly ? (\n <Text size=\"xs\" className=\"text-destructive\">\n {translate('builder.inspector.invalidValue')}\n </Text>\n ) : null}\n </Stack>\n )\n}\n\n/**\n * Read-only stand-in for an `asset`/`relation`/`object` prop when there is no\n * ambient `CollectionViewSource` (the component-registry preview, which has no\n * document/collection context). Shows the current value and a hint that it is\n * editable inside a document — never the live picker, which needs a workspace.\n */\nfunction WorkspaceValueFallback({ value }: { value: JsonValue | undefined }) {\n const text =\n value === undefined || value === null\n ? '—'\n : typeof value === 'string'\n ? value\n : JSON.stringify(value)\n return (\n <Stack gap=\"1\">\n <div className=\"truncate rounded-md border border-input bg-muted/30 px-2.5 py-1.5 text-sm text-muted-foreground\">\n {text}\n </div>\n <Text size=\"xs\" tone=\"muted\">\n {translate('components.preview.propNeedsDocument')}\n </Text>\n </Stack>\n )\n}\n\n/** Number input with a local buffer: commits only finite values, never NaN; empty clears the prop. */\nfunction NumberControl({\n id,\n current,\n onSet,\n onClear,\n readOnly,\n}: {\n id: string\n current: JsonValue | undefined\n onSet: (v: number) => void\n onClear: () => void\n readOnly: boolean\n}) {\n const [raw, setRaw] = useState(typeof current === 'number' ? String(current) : '')\n useEffect(() => {\n setRaw(typeof current === 'number' ? String(current) : '')\n }, [current])\n return (\n <Input\n id={id}\n type=\"number\"\n disabled={readOnly}\n value={raw}\n onChange={(e) => {\n const v = e.target.value\n setRaw(v)\n if (v.trim() === '') {\n onClear()\n return\n }\n const n = Number(v)\n if (Number.isFinite(n)) onSet(n)\n }}\n />\n )\n}\n\n/** JSON textarea with a local buffer: commits only when the text parses; flags parse errors. */\nfunction JsonControl({\n id,\n current,\n onSet,\n readOnly,\n}: {\n id: string\n current: JsonValue | undefined\n onSet: (v: JsonValue) => void\n readOnly: boolean\n}) {\n const [raw, setRaw] = useState(() => JSON.stringify(current ?? null))\n const [error, setError] = useState<string | null>(null)\n useEffect(() => {\n setRaw(JSON.stringify(current ?? null))\n setError(null)\n }, [current])\n return (\n <Stack gap=\"1\">\n <textarea\n id={id}\n rows={3}\n disabled={readOnly}\n value={raw}\n onChange={(e) => {\n const v = e.target.value\n setRaw(v)\n try {\n onSet(JSON.parse(v) as JsonValue)\n setError(null)\n } catch {\n setError(translate('builder.inspector.invalidJson'))\n }\n }}\n className=\"flex w-full rounded-md border border-input bg-background px-2.5 py-1.5 font-mono text-xs text-foreground shadow-sm focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40 outline-none disabled:cursor-not-allowed disabled:opacity-50\"\n />\n {error ? (\n <Text size=\"xs\" className=\"text-destructive\">\n {error}\n </Text>\n ) : null}\n </Stack>\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"prop-fields.js","sourceRoot":"","sources":["../../../src/components/cms/prop-fields.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useState } from 'react'\nimport { isStaticProp } from '@elytracms/core/project-graph'\nimport type { JsonValue, PropValue } from '@elytracms/core/project-graph'\nimport type { PropField } from '@elytracms/core/component-registry'\nimport { fieldValueValidator } from '@elytracms/core/cms-core'\nimport type { FieldDef, SelectFieldDef, SelectOption } from '@elytracms/core/cms-core'\nimport { Input, Row, Select, Stack, Text } from '@elytracms/studio/ui'\nimport { localizedLabel, translate } from '@elytracms/studio/lib/i18n'\nimport { FieldControl } from './field-control'\nimport { SegmentedOptions } from './field-control-lib'\nimport { FieldDensityProvider } from './field-density'\nimport { RichTextEditor } from './rich-text'\nimport { useOptionalCollectionView } from '../collection-view/collection-view-context'\n\n/**\n * The EC-190 \"props-as-fields\" value control — the single renderer for a\n * manifest-declared prop field, shared by the canvas property inspector\n * (`builder/property-inspector.tsx`) and the rich-text component-embed prop editor\n * (`rich-text/embed-props.tsx`). Extracted here so both surfaces render prop fields\n * through *one* control set (asset → library picker, relation → document picker,\n * object → nested form, …) rather than two parallel form systems.\n *\n * It is deliberately store-agnostic: it reads a prop's current value and reports\n * edits through `onSet(rawValue)` / `onClear()`. The caller owns *where* the value\n * lands — the inspector dispatches a builder command; the embed editor rewrites a\n * ProseMirror node attr — and is responsible for wrapping the raw value in a\n * `staticProp` envelope.\n */\n\n/**\n * The inspector control to render for a prop field-def. The `control.kind`\n * vocabulary derives from the field `type` plus the optional `form.control`\n * presentation hint on `text` fields.\n */\nexport type ControlKind =\n | 'text'\n | 'textarea'\n | 'number'\n | 'boolean'\n | 'select'\n | 'options'\n | 'json'\n | 'color'\n | 'richtext'\n | 'asset'\n | 'object'\n | 'relation'\n\nexport function controlKind(spec: PropField): ControlKind {\n switch (spec.type) {\n case 'boolean':\n return 'boolean'\n case 'number':\n return 'number'\n case 'select':\n // EC-393: a single-select prop opting into `form.control: 'options'` renders the\n // SAME segmented button group the document form uses (EC-295), not the native\n // dropdown — parity with `field-control.tsx`. Segmented is single-select only,\n // so a `multiple` select stays on the native control (mirroring field-control).\n if (spec.form?.control === 'options' && !spec.multiple) return 'options'\n return 'select'\n case 'richText':\n return 'richtext'\n // EC-195: an `asset`-typed prop (e.g. the Image `src`) picks from the asset\n // library — never a raw asset id typed into a text box (the EC-192 persona).\n case 'asset':\n return 'asset'\n // EC-253: an `object`/repeater prop reuses the CMS repeater control below.\n case 'object':\n return 'object'\n // EC-262: a `relation`-typed prop (e.g. a ProductGrid's `category`) reuses the\n // CMS relation picker — never a text box that stringifies the ref to \"[object Object]\".\n case 'relation':\n return 'relation'\n case 'text': {\n const c = spec.form?.control\n if (c === 'textarea') return 'textarea'\n if (c === 'color') return 'color'\n if (c === 'json') return 'json'\n return 'text'\n }\n default:\n return 'text'\n }\n}\n\n/**\n * EC-387: route a rich-text editor emission to the prop value callbacks.\n *\n * The shared {@link RichTextEditor} emits either an emptied-editor `undefined`, the\n * exact stored envelope (an untouched/reverted edit), or a fresh `{ version, doc }`\n * value — never a plain string. An `undefined` clears the prop (reverting to the\n * manifest default, matching the asset/relation/object controls); anything else is a\n * structured `JsonValue` envelope set verbatim. Extracted pure so the wiring — the\n * exact bug the retired textarea stub had (it wrote a bare string over the envelope) —\n * is regression-pinned without driving TipTap.\n */\nexport function applyRichTextPropChange(\n next: unknown,\n handlers: { onSet: (value: JsonValue) => void; onClear: () => void },\n): void {\n if (next === undefined) handlers.onClear()\n else handlers.onSet(next as JsonValue)\n}\n\nexport interface PropValueControlProps {\n /** DOM id for the control's primary input (label `htmlFor` target). */\n id: string\n /** The prop's field name — needed to synthesize the `FieldDef` for reused controls. */\n name: string\n /** The manifest prop field-def driving the control kind + validation. */\n spec: PropField\n /** The prop's current value envelope (or `undefined` when unset). */\n value: PropValue | undefined\n /** Commit a new raw value (the caller wraps it in a `staticProp`). */\n onSet: (value: JsonValue) => void\n /** Remove the prop (revert to the manifest default). */\n onClear: () => void\n}\n\n/**\n * Render + edit a single manifest prop value. Store-agnostic: emits through\n * `onSet`/`onClear`. Shows a validation issue when the current value fails the\n * prop's field-def validator.\n */\nexport function PropValueControl({ id, name, spec, value, onSet, onClear }: PropValueControlProps) {\n const current = isStaticProp(value) ? value.value : (spec.default as JsonValue | undefined)\n // The `asset`/`relation`/`object` controls delegate to the CMS `FieldControl`,\n // which reads the ambient `CollectionViewSource` (asset library, relation\n // candidates, nested form). The component-registry preview surface has no\n // document/collection context, so outside a provider those controls must degrade\n // to a read-only value display instead of throwing \"useCollectionView must be\n // used within a <CollectionViewProvider>\" (the Konditorei Components-view crash).\n const hasWorkspaceContext = useOptionalCollectionView() != null\n\n // EC-190: validate with the prop's field-def value validator.\n const valid = current === undefined || fieldValueValidator({ ...spec, name } as FieldDef)(current)\n // EC-190: derive the editor control from the field `type` + optional `form.control`.\n const kind = controlKind(spec)\n // Select options live on the `select` field-def.\n const options: readonly SelectOption[] = spec.type === 'select' ? spec.options : []\n // EC-395: `form.readOnly` parity with the document form. `cms-store.tsx`'s\n // `isFieldReadOnly` reads the identical `field.form?.readOnly === true` check —\n // every control kind below (including the delegated `FieldControl`/\n // `SegmentedOptions` mounts, which previously hardcoded `readOnly={false}`)\n // degrades to the SAME disabled/inert interaction the document form's\n // `FieldControl` renders for a read-only field, not a parallel treatment.\n const readOnly = spec.form?.readOnly === true\n\n let control\n if (kind === 'boolean') {\n control = (\n <label className=\"flex h-8 items-center gap-2 text-sm\">\n <input\n id={id}\n type=\"checkbox\"\n checked={current === true}\n disabled={readOnly}\n onChange={(e) => onSet(e.target.checked)}\n className=\"size-4 accent-primary disabled:opacity-50\"\n />\n <Text size=\"sm\" tone=\"muted\">\n {current === true ? translate('common.true') : translate('common.false')}\n </Text>\n </label>\n )\n } else if (kind === 'select') {\n control = (\n <Select\n id={id}\n disabled={readOnly}\n value={String(current ?? '')}\n onChange={(e) => {\n // EC-190: select option values are strings (field-def `options`).\n const opt = options.find((o) => o.value === e.target.value)\n onSet(opt ? opt.value : e.target.value)\n }}\n >\n {options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {localizedLabel(opt.label, opt.value)}\n </option>\n ))}\n </Select>\n )\n } else if (kind === 'options') {\n // EC-393: reuse the EC-295 segmented control the document form renders (via\n // `field-control.tsx`) — delegation over a parallel dropdown. It reads the\n // field-def's own `options` (label + per-option `description` tooltip); single-\n // select only (picks one, no unset — an unset select keeps the native dropdown).\n control = (\n <SegmentedOptions\n id={id}\n field={{ ...spec, name } as SelectFieldDef}\n value={current}\n onChange={(v) => onSet(v as JsonValue)}\n readOnly={readOnly}\n />\n )\n } else if (kind === 'number') {\n control = (\n <NumberControl id={id} current={current} onSet={onSet} onClear={onClear} readOnly={readOnly} />\n )\n } else if (kind === 'json') {\n control = <JsonControl id={id} current={current} onSet={onSet} readOnly={readOnly} />\n } else if (kind === 'color') {\n control = (\n <Row gap=\"2\">\n <input\n id={id}\n type=\"color\"\n disabled={readOnly}\n value={typeof current === 'string' && /^#[0-9a-f]{6}$/i.test(current) ? current : '#000000'}\n onChange={(e) => onSet(e.target.value)}\n className=\"h-8 w-10 shrink-0 rounded-md border border-input bg-background disabled:opacity-50\"\n />\n <Input\n disabled={readOnly}\n value={typeof current === 'string' ? current : ''}\n onChange={(e) => onSet(e.target.value)}\n />\n </Row>\n )\n } else if (kind === 'richtext') {\n // EC-387: a richText PROP now uses the SAME real editor as the collection-field\n // path (`field-control.tsx` `case 'richText'`) — one editing surface, one\n // `{ version, doc }` value contract, never a second implementation. The retired\n // textarea stub read `typeof current === 'string'`, so a stored envelope showed\n // EMPTY and any edit clobbered the structured document with a bare string\n // (silent data destruction). The editor reads the envelope (or a legacy string,\n // or empty), always emits an envelope, and routes an emptied editor's `undefined`\n // to a prop clear via {@link applyRichTextPropChange}.\n //\n // Like the asset/relation/object controls below, the editor needs the ambient\n // workspace — its asset-image picker reads the REQUIRED collection-view context.\n // The block property inspector (the EC-387 target) is inside the detail editor's\n // `CollectionViewProvider`, so it gets the full editor; the component-registry\n // preview surface (no provider, nothing to edit against) degrades to the same\n // read-only value display the sibling controls use, instead of crashing with\n // \"useCollectionView must be used within a <CollectionViewProvider>\".\n control = hasWorkspaceContext ? (\n <RichTextEditor\n id={id}\n value={current}\n onChange={(next) => applyRichTextPropChange(next, { onSet, onClear })}\n allow={spec.type === 'richText' ? spec.allow : undefined}\n readOnly={readOnly}\n // EC-436: the SAME resolved localized label the prop row renders (the\n // property inspector / embed form's `Field label`) — titles the expand\n // stage \"<label> — Rich text\".\n label={localizedLabel(spec.form?.label, name)}\n />\n ) : (\n <WorkspaceValueFallback value={current} />\n )\n } else if (kind === 'textarea') {\n control = (\n <textarea\n id={id}\n rows={2}\n disabled={readOnly}\n value={typeof current === 'string' ? current : ''}\n onChange={(e) => onSet(e.target.value)}\n className=\"flex w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-sm text-foreground shadow-sm focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40 outline-none disabled:cursor-not-allowed disabled:opacity-50\"\n />\n )\n } else if (kind === 'asset' || kind === 'object' || kind === 'relation') {\n // EC-195/EC-253/EC-262: reuse the CMS field control. `asset` = library picker +\n // preview; `object` = the nested/repeater form; `relation` = the document picker\n // (resolves the ref to its title, instead of stringifying it to \"[object Object]\").\n // All edit a structured static prop value through the same shared control documents use.\n // Without a workspace context (the Components preview), degrade to a read-only\n // value display so the pane renders instead of throwing.\n control = hasWorkspaceContext ? (\n <FieldDensityProvider density=\"compact\">\n <FieldControl\n id={id}\n field={{ ...spec, name } as FieldDef}\n value={current}\n onChange={(v) => (v === undefined || v === null ? onClear() : onSet(v as JsonValue))}\n readOnly={readOnly}\n />\n </FieldDensityProvider>\n ) : (\n <WorkspaceValueFallback value={current} />\n )\n } else {\n control = (\n <Input\n id={id}\n disabled={readOnly}\n value={typeof current === 'string' ? current : String(current ?? '')}\n onChange={(e) => onSet(e.target.value)}\n />\n )\n }\n\n return (\n <Stack gap=\"1\">\n {control}\n {/* EC-395: a read-only prop's value can't be fixed here — suppress the\n invalid-value flag exactly like the document form suppresses its field\n error on a read-only row (`detail-editor.tsx`'s\n `error={fieldReadOnly ? undefined : ...}`). */}\n {!valid && !readOnly ? (\n <Text size=\"xs\" className=\"text-destructive\">\n {translate('builder.inspector.invalidValue')}\n </Text>\n ) : null}\n </Stack>\n )\n}\n\n/**\n * Read-only stand-in for an `asset`/`relation`/`object` prop when there is no\n * ambient `CollectionViewSource` (the component-registry preview, which has no\n * document/collection context). Shows the current value and a hint that it is\n * editable inside a document — never the live picker, which needs a workspace.\n */\nfunction WorkspaceValueFallback({ value }: { value: JsonValue | undefined }) {\n const text =\n value === undefined || value === null\n ? '—'\n : typeof value === 'string'\n ? value\n : JSON.stringify(value)\n return (\n <Stack gap=\"1\">\n <div className=\"truncate rounded-md border border-input bg-muted/30 px-2.5 py-1.5 text-sm text-muted-foreground\">\n {text}\n </div>\n <Text size=\"xs\" tone=\"muted\">\n {translate('components.preview.propNeedsDocument')}\n </Text>\n </Stack>\n )\n}\n\n/** Number input with a local buffer: commits only finite values, never NaN; empty clears the prop. */\nfunction NumberControl({\n id,\n current,\n onSet,\n onClear,\n readOnly,\n}: {\n id: string\n current: JsonValue | undefined\n onSet: (v: number) => void\n onClear: () => void\n readOnly: boolean\n}) {\n const [raw, setRaw] = useState(typeof current === 'number' ? String(current) : '')\n useEffect(() => {\n setRaw(typeof current === 'number' ? String(current) : '')\n }, [current])\n return (\n <Input\n id={id}\n type=\"number\"\n disabled={readOnly}\n value={raw}\n onChange={(e) => {\n const v = e.target.value\n setRaw(v)\n if (v.trim() === '') {\n onClear()\n return\n }\n const n = Number(v)\n if (Number.isFinite(n)) onSet(n)\n }}\n />\n )\n}\n\n/** JSON textarea with a local buffer: commits only when the text parses; flags parse errors. */\nfunction JsonControl({\n id,\n current,\n onSet,\n readOnly,\n}: {\n id: string\n current: JsonValue | undefined\n onSet: (v: JsonValue) => void\n readOnly: boolean\n}) {\n const [raw, setRaw] = useState(() => JSON.stringify(current ?? null))\n const [error, setError] = useState<string | null>(null)\n useEffect(() => {\n setRaw(JSON.stringify(current ?? null))\n setError(null)\n }, [current])\n return (\n <Stack gap=\"1\">\n <textarea\n id={id}\n rows={3}\n disabled={readOnly}\n value={raw}\n onChange={(e) => {\n const v = e.target.value\n setRaw(v)\n try {\n onSet(JSON.parse(v) as JsonValue)\n setError(null)\n } catch {\n setError(translate('builder.inspector.invalidJson'))\n }\n }}\n className=\"flex w-full rounded-md border border-input bg-background px-2.5 py-1.5 font-mono text-xs text-foreground shadow-sm focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/40 outline-none disabled:cursor-not-allowed disabled:opacity-50\"\n />\n {error ? (\n <Text size=\"xs\" className=\"text-destructive\">\n {error}\n </Text>\n ) : null}\n </Stack>\n )\n}\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ComponentNode } from '@elytracms/core/project-graph';
|
|
2
|
+
import type { ComponentManifest, PropField } from '@elytracms/core/component-registry';
|
|
3
|
+
export declare function visiblePropFields(manifest: ComponentManifest, node: ComponentNode, exclude?: ReadonlySet<string>): [string, PropField][];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { effectivePropValues } from '@elytracms/core/component-registry';
|
|
2
|
+
import { isFieldHidden } from '@elytracms/core/cms-core';
|
|
3
|
+
/**
|
|
4
|
+
* EC-393's visible-prop-row mechanism, extracted to its pure core (EC-430) so
|
|
5
|
+
* every prop form renders through ONE implementation: the canvas property
|
|
6
|
+
* inspector (`builder/property-inspector.tsx`) and the rich-text embed stage
|
|
7
|
+
* form (`rich-text/embed-props.tsx`). It decides which manifest props render as
|
|
8
|
+
* form rows for a component instance — manifest props MINUS:
|
|
9
|
+
*
|
|
10
|
+
* - explicitly excluded names (the inspector's layout-managed props, which
|
|
11
|
+
* render in its dedicated Layout section instead — EC-162);
|
|
12
|
+
* - `blocks` props (child regions/composition — edited on the canvas, never a
|
|
13
|
+
* form row, EC-190);
|
|
14
|
+
* - any prop hidden RIGHT NOW by its `form.hidden` — static `true`, or a
|
|
15
|
+
* predicate over the SIBLING prop values.
|
|
16
|
+
*
|
|
17
|
+
* The predicate's context is the component instance's EFFECTIVE prop values
|
|
18
|
+
* ({@link effectivePropValues} — static values with manifest defaults filled),
|
|
19
|
+
* the prop analogue of the document form's active-locale draft values
|
|
20
|
+
* (`isFieldHidden` there). So a conditional row shows/hides live as a sibling
|
|
21
|
+
* prop changes and unmounts exactly like a document-form field. Pure (no store)
|
|
22
|
+
* so the behaviour is testable.
|
|
23
|
+
*/
|
|
24
|
+
const NO_EXCLUDED_PROPS = new Set();
|
|
25
|
+
export function visiblePropFields(manifest, node, exclude = NO_EXCLUDED_PROPS) {
|
|
26
|
+
const ctx = { values: effectivePropValues(manifest, node) };
|
|
27
|
+
return Object.entries(manifest.props).filter(([name, spec]) => !exclude.has(name) &&
|
|
28
|
+
spec.type !== 'blocks' &&
|
|
29
|
+
!isFieldHidden({ ...spec, name }, ctx));
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=prop-visibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prop-visibility.js","sourceRoot":"","sources":["../../../src/components/cms/prop-visibility.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAGxD;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,iBAAiB,GAAwB,IAAI,GAAG,EAAE,CAAA;AAExD,MAAM,UAAU,iBAAiB,CAC/B,QAA2B,EAC3B,IAAmB,EACnB,UAA+B,iBAAiB;IAEhD,MAAM,GAAG,GAA0B,EAAE,MAAM,EAAE,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAA;IAClF,OAAO,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,CAC1C,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CACf,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QAClB,IAAI,CAAC,IAAI,KAAK,QAAQ;QACtB,CAAC,aAAa,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAc,EAAE,GAAG,CAAC,CACrD,CAAA;AACH,CAAC","sourcesContent":["import type { ComponentNode } from '@elytracms/core/project-graph'\nimport type { ComponentManifest, PropField } from '@elytracms/core/component-registry'\nimport { effectivePropValues } from '@elytracms/core/component-registry'\nimport { isFieldHidden } from '@elytracms/core/cms-core'\nimport type { FieldConditionContext, FieldDef } from '@elytracms/core/cms-core'\n\n/**\n * EC-393's visible-prop-row mechanism, extracted to its pure core (EC-430) so\n * every prop form renders through ONE implementation: the canvas property\n * inspector (`builder/property-inspector.tsx`) and the rich-text embed stage\n * form (`rich-text/embed-props.tsx`). It decides which manifest props render as\n * form rows for a component instance — manifest props MINUS:\n *\n * - explicitly excluded names (the inspector's layout-managed props, which\n * render in its dedicated Layout section instead — EC-162);\n * - `blocks` props (child regions/composition — edited on the canvas, never a\n * form row, EC-190);\n * - any prop hidden RIGHT NOW by its `form.hidden` — static `true`, or a\n * predicate over the SIBLING prop values.\n *\n * The predicate's context is the component instance's EFFECTIVE prop values\n * ({@link effectivePropValues} — static values with manifest defaults filled),\n * the prop analogue of the document form's active-locale draft values\n * (`isFieldHidden` there). So a conditional row shows/hides live as a sibling\n * prop changes and unmounts exactly like a document-form field. Pure (no store)\n * so the behaviour is testable.\n */\n\nconst NO_EXCLUDED_PROPS: ReadonlySet<string> = new Set()\n\nexport function visiblePropFields(\n manifest: ComponentManifest,\n node: ComponentNode,\n exclude: ReadonlySet<string> = NO_EXCLUDED_PROPS,\n): [string, PropField][] {\n const ctx: FieldConditionContext = { values: effectivePropValues(manifest, node) }\n return Object.entries(manifest.props).filter(\n ([name, spec]) =>\n !exclude.has(name) &&\n spec.type !== 'blocks' &&\n !isFieldHidden({ ...spec, name } as FieldDef, ctx),\n )\n}\n"]}
|
|
@@ -29,7 +29,11 @@ export function ReferenceConfirmDialog({ projectId, action, targets, open, busy
|
|
|
29
29
|
// Queued session mutations (and the persisted baseline) must land
|
|
30
30
|
// before the pre-flight query — the index is maintained on write.
|
|
31
31
|
await source.flush?.();
|
|
32
|
-
|
|
32
|
+
// The source knows how its records are addressed in the reference
|
|
33
|
+
// index (EC-433): documents by default, `{ type: 'asset' }` for the
|
|
34
|
+
// assets rail — so this pre-flight counts the SAME references the
|
|
35
|
+
// rail's detail surface does.
|
|
36
|
+
const views = await loadInboundReferenceViews(projectId, targets, source.referenceTarget);
|
|
33
37
|
if (cancelled)
|
|
34
38
|
return;
|
|
35
39
|
setImpact(buildReferenceImpact(source.collections, action, views));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reference-confirm.js","sourceRoot":"","sources":["../../../src/components/cms/reference-confirm.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport { AlertTriangle, ShieldAlert } from 'lucide-react'\nimport { useEffect, useMemo, useState } from 'react'\nimport { documentKey } from '@elytracms/core/cms-core'\nimport type { DocumentRef } from '@elytracms/core/cms-core'\nimport { buildReferenceImpact, loadInboundReferenceViews } from '@elytracms/studio/lib/references'\nimport type {\n DocumentReferenceImpact,\n ReferenceAction,\n ReferenceDeepLink,\n ReferenceEntryView,\n ReferenceImpact,\n} from '@elytracms/studio/lib/references'\nimport {\n Badge,\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Row,\n Stack,\n Text,\n} from '@elytracms/studio/ui'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { useCollectionView } from '../collection-view/collection-view-context'\n\n/**\n * The EC-173 reference-aware confirmation dialog for unpublish/delete —\n * single documents (detail editor) and bulk selections (EC-169 bulk bar)\n * alike. It inverts the industry default, visibly:\n *\n * 1. *Before* the action it enumerates every inbound reference that will\n * break (published variant for unpublish, both variants for delete), with\n * the EC-172 labels and deep links to the exact field/node.\n * 2. Proceeding is allowed — weak references are the default. Zero references\n * render a plain confirm; breakage renders \"You can … — N places will show\n * a fallback\".\n * 3. Strict opt-in relation fields (`strict: true`) flip the same dialog into\n * a real block: the proceed button is disabled and every blocking referrer\n * is named and linked. The `@elytracms/core/operations` layer enforces the same\n * rule server-side (structured conflict error) — this dialog is the\n * friendly face, not the only guard.\n *\n * Pre-flight data goes through operations reference queries only (EC-155\n * index, flushed); impact semantics live in `lib/references/impact.ts`.\n */\n\ntype ImpactStatus = 'loading' | 'ready' | 'unavailable'\n\nconst ACTION_LABELS: Record<ReferenceAction, string> = {\n unpublish: translate('cms.editor.unpublish'),\n delete: translate('common.delete'),\n}\n\nexport function ReferenceConfirmDialog({\n projectId,\n action,\n targets,\n open,\n busy = false,\n onOpenChange,\n onConfirm,\n}: {\n projectId: string\n action: ReferenceAction\n /** The documents being acted on (a stable snapshot taken when opening). */\n targets: readonly DocumentRef[]\n open: boolean\n busy?: boolean\n onOpenChange: (open: boolean) => void\n onConfirm: () => void\n}) {\n const source = useCollectionView()\n const [status, setStatus] = useState<ImpactStatus>('loading')\n const [impact, setImpact] = useState<ReferenceImpact | null>(null)\n\n // A stable identity for the acted-on set, so the effect re-runs exactly\n // when the selection (not the array instance) changes.\n const targetsKey = targets.map((ref) => documentKey(ref)).join('\\n')\n\n useEffect(() => {\n if (!open || targets.length === 0) return\n let cancelled = false\n setStatus('loading')\n setImpact(null)\n void (async () => {\n try {\n // Queued session mutations (and the persisted baseline) must land\n // before the pre-flight query — the index is maintained on write.\n await source.flush?.()\n const views = await loadInboundReferenceViews(projectId, targets)\n if (cancelled) return\n setImpact(buildReferenceImpact(source.collections, action, views))\n setStatus('ready')\n } catch {\n // The index being unreachable must not trap the editor: degrade to a\n // plain confirm with an explicit \"could not check\" warning.\n if (!cancelled) setStatus('unavailable')\n }\n })()\n return () => {\n cancelled = true\n }\n // `targetsKey` stands in for `targets` (stable identity for the acted-on set).\n }, [open, action, targetsKey, projectId])\n\n const actionLabel = ACTION_LABELS[action]\n const subject = useMemo(() => {\n if (targets.length === 1) {\n const ref = targets[0]!\n return `“${source.titleOf(ref)}”`\n }\n return translate('cms.reference.documentCount', { count: targets.length })\n }, [targets, source])\n\n const blocked = status === 'ready' && (impact?.totalBlocking ?? 0) > 0\n const totalBroken = impact?.totalBroken ?? 0\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent data-testid=\"reference-confirm\" className=\"max-h-[80vh] overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>\n {translate('cms.reference.confirmTitle', { action: actionLabel, subject })}\n </DialogTitle>\n <DialogDescription data-testid=\"reference-confirm-summary\">\n {status === 'loading' ? (\n translate('cms.reference.checking')\n ) : status === 'unavailable' ? (\n translate('cms.reference.checkUnavailable')\n ) : blocked ? (\n translate(\n impact!.totalBlocking === 1\n ? 'cms.reference.blocked.one'\n : 'cms.reference.blocked.other',\n { count: impact!.totalBlocking },\n )\n ) : totalBroken === 0 ? (\n <>\n {translate('cms.reference.notReferenced')}\n {action === 'delete'\n ? ` ${translate(\n targets.length === 1\n ? 'cms.reference.permanentDelete.one'\n : 'cms.reference.permanentDelete.other',\n { count: targets.length },\n )}`\n : ''}\n </>\n ) : (\n translate('cms.reference.canProceed', {\n action: translate(\n action === 'unpublish'\n ? 'cms.reference.verb.unpublish'\n : 'cms.reference.verb.delete',\n ),\n summary: impactSummary(targets.length, totalBroken),\n })\n )}\n </DialogDescription>\n </DialogHeader>\n\n {status === 'ready' && impact !== null && totalBroken > 0 ? (\n <ImpactList projectId={projectId} impact={impact} onNavigate={() => onOpenChange(false)} />\n ) : null}\n {status === 'unavailable' ? (\n <Row gap=\"2\" data-testid=\"reference-confirm-unavailable\">\n <AlertTriangle className=\"size-4 shrink-0 text-warning\" />\n <Text size=\"xs\" tone=\"muted\">\n {translate('cms.reference.proceedUnavailable')}\n </Text>\n </Row>\n ) : null}\n\n <DialogFooter>\n <Button\n variant=\"outline\"\n data-testid=\"reference-confirm-cancel\"\n onClick={() => onOpenChange(false)}\n >\n {translate('common.cancel')}\n </Button>\n <Button\n variant={action === 'delete' ? 'destructive' : 'default'}\n disabled={status === 'loading' || blocked || busy}\n data-testid=\"reference-confirm-proceed\"\n onClick={onConfirm}\n >\n {totalBroken > 0 && !blocked\n ? translate('cms.reference.proceedAnyway', { action: actionLabel })\n : actionLabel}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n\nfunction impactSummary(targetCount: number, totalBroken: number): string {\n const places = translate(\n totalBroken === 1 ? 'cms.reference.placeCount.one' : 'cms.reference.placeCount.other',\n { count: totalBroken },\n )\n // The bulk aggregate: \"N documents, M inbound references will break.\"\n return targetCount > 1\n ? translate('cms.reference.bulkSummary', { count: targetCount, places })\n : places\n}\n\n/**\n * The enumerated impact: flat for a single target, grouped per target for\n * bulk selections (per-item detail, EC-169 honesty rules).\n */\nfunction ImpactList({\n projectId,\n impact,\n onNavigate,\n}: {\n projectId: string\n impact: ReferenceImpact\n onNavigate: () => void\n}) {\n const affected = impact.documents.filter((doc) => doc.broken.length > 0)\n return (\n <Stack gap=\"3\" data-testid=\"reference-confirm-impact\">\n {affected.map((doc) => (\n <ImpactGroup\n key={documentKey(doc.ref)}\n projectId={projectId}\n doc={doc}\n grouped={impact.documents.length > 1}\n onNavigate={onNavigate}\n />\n ))}\n </Stack>\n )\n}\n\nfunction ImpactGroup({\n projectId,\n doc,\n grouped,\n onNavigate,\n}: {\n projectId: string\n doc: DocumentReferenceImpact\n grouped: boolean\n onNavigate: () => void\n}) {\n const source = useCollectionView()\n const blockingKeys = new Set(doc.blocking.map((entry) => entry.key))\n return (\n <Stack gap=\"2\" data-testid={`reference-confirm-doc-${doc.ref.id}`}>\n {grouped ? (\n <Row gap=\"2\">\n <Text size=\"xs\" weight=\"semibold\" tone=\"muted\" className=\"uppercase tracking-wide\">\n {source.titleOf(doc.ref)}\n </Text>\n <Badge variant=\"outline\">{doc.broken.length}</Badge>\n </Row>\n ) : null}\n {doc.broken.map((entry) => (\n <ImpactEntryRow\n key={entry.key}\n projectId={projectId}\n entry={entry}\n blocking={blockingKeys.has(entry.key)}\n onNavigate={onNavigate}\n />\n ))}\n </Stack>\n )\n}\n\n/**\n * The shared EC-173 impact rows: one deep-linked row per broken inbound\n * reference, strict-blocking ones flagged. Rendered by the document\n * confirmation dialog (above) and the asset-delete dialog (EC-202) alike — both\n * reduce to \"these places reference the thing you're removing\", so both lean on\n * the same row + deep-link rendering (which already handles asset link kinds).\n */\nexport function ReferenceImpactRows({\n projectId,\n broken,\n blocking = [],\n onNavigate,\n}: {\n projectId: string\n broken: readonly ReferenceEntryView[]\n blocking?: readonly ReferenceEntryView[]\n onNavigate: () => void\n}) {\n const blockingKeys = new Set(blocking.map((entry) => entry.key))\n return (\n <Stack gap=\"2\" data-testid=\"reference-impact-rows\">\n {broken.map((entry) => (\n <ImpactEntryRow\n key={entry.key}\n projectId={projectId}\n entry={entry}\n blocking={blockingKeys.has(entry.key)}\n onNavigate={onNavigate}\n />\n ))}\n </Stack>\n )\n}\n\n/**\n * One affected place: the EC-172 labels with a working deep link to the exact\n * field/node, the entry kind, draft/published visibility — and a strict\n * marker when this entry is what blocks the action.\n */\nfunction ImpactEntryRow({\n projectId,\n entry,\n blocking,\n onNavigate,\n}: {\n projectId: string\n entry: ReferenceEntryView\n blocking: boolean\n onNavigate: () => void\n}) {\n return (\n <Row\n gap=\"2\"\n className={\n blocking\n ? 'rounded-md border border-destructive/50 bg-destructive/5 px-2.5 py-2'\n : 'rounded-md border border-border/70 bg-background/40 px-2.5 py-2'\n }\n data-testid=\"reference-confirm-entry\"\n >\n <Stack gap=\"1\" className=\"min-w-0 flex-1\">\n <ImpactDeepLink\n projectId={projectId}\n link={entry.sourceLink}\n label={entry.sourceLabel}\n primary\n onNavigate={onNavigate}\n />\n <Row gap=\"1\" className=\"min-w-0\">\n <Text size=\"xs\" tone=\"muted\" className=\"shrink-0\">\n {translate('cms.reference.atLocation')}\n </Text>\n <ImpactDeepLink\n projectId={projectId}\n link={entry.sourceLink}\n label={entry.locationLabel}\n onNavigate={onNavigate}\n />\n </Row>\n </Stack>\n {blocking ? (\n <Badge variant=\"error\" data-testid=\"reference-confirm-strict\">\n <ShieldAlert className=\"size-3\" /> {translate('cms.reference.strictBadge')}\n </Badge>\n ) : null}\n <Badge variant=\"outline\" className=\"shrink-0\">\n {entry.kindLabel}\n </Badge>\n <Row gap=\"1\" className=\"shrink-0\">\n {entry.draft ? <Badge variant=\"warning\">{translate('cms.reference.draftBadge')}</Badge> : null}\n {entry.published ? (\n <Badge variant=\"success\">{translate('cms.reference.publishedBadge')}</Badge>\n ) : null}\n </Row>\n </Row>\n )\n}\n\n/** A deep link to the exact source location; closes the dialog on navigate. */\nfunction ImpactDeepLink({\n projectId,\n link,\n label,\n primary = false,\n onNavigate,\n}: {\n projectId: string\n link: ReferenceDeepLink | null\n label: string\n primary?: boolean\n onNavigate: () => void\n}) {\n const className = primary\n ? 'min-w-0 truncate text-sm font-medium text-foreground hover:text-primary hover:underline'\n : 'min-w-0 truncate text-xs text-muted-foreground hover:text-primary hover:underline'\n if (link === null) {\n return primary ? (\n <Text size=\"sm\" weight=\"medium\" className=\"min-w-0 truncate\">\n {label}\n </Text>\n ) : (\n <Text size=\"xs\" tone=\"muted\" className=\"min-w-0 truncate\">\n {label}\n </Text>\n )\n }\n switch (link.kind) {\n case 'cms-field':\n return (\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.cmsDocument(link.collectionId, link.documentId) }}\n search={link.fieldPath !== undefined ? { field: link.fieldPath } : {}}\n className={className}\n data-testid=\"reference-confirm-link\"\n onClick={onNavigate}\n >\n {label}\n </Link>\n )\n case 'builder-node':\n // The builder redirect (EC-187) only reads `?page=`; the page-graph-only\n // `node` has no home in the document editor and is dropped.\n return (\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.builder() }}\n search={link.pageId !== undefined ? { page: link.pageId } : {}}\n className={className}\n data-testid=\"reference-confirm-link\"\n onClick={onNavigate}\n >\n {label}\n </Link>\n )\n case 'component':\n return (\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.component(link.componentId) }}\n className={className}\n data-testid=\"reference-confirm-link\"\n onClick={onNavigate}\n >\n {label}\n </Link>\n )\n case 'asset':\n return (\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.assets() }}\n search={{ asset: link.assetId }}\n className={className}\n data-testid=\"reference-confirm-link\"\n onClick={onNavigate}\n >\n {label}\n </Link>\n )\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"reference-confirm.js","sourceRoot":"","sources":["../../../src/components/cms/reference-confirm.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AACjF,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAEtD,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAA;AAQlG,OAAO,EACL,KAAK,EACL,MAAM,EACN,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,GAAG,EACH,KAAK,EACL,IAAI,GACL,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAA;AAyB9E,MAAM,aAAa,GAAoC;IACrD,SAAS,EAAE,SAAS,CAAC,sBAAsB,CAAC;IAC5C,MAAM,EAAE,SAAS,CAAC,eAAe,CAAC;CACnC,CAAA;AAED,MAAM,UAAU,sBAAsB,CAAC,EACrC,SAAS,EACT,MAAM,EACN,OAAO,EACP,IAAI,EACJ,IAAI,GAAG,KAAK,EACZ,YAAY,EACZ,SAAS,GAUV;IACC,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAA;IAClC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAe,SAAS,CAAC,CAAA;IAC7D,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAyB,IAAI,CAAC,CAAA;IAElE,wEAAwE;IACxE,uDAAuD;IACvD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEpE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QACzC,IAAI,SAAS,GAAG,KAAK,CAAA;QACrB,SAAS,CAAC,SAAS,CAAC,CAAA;QACpB,SAAS,CAAC,IAAI,CAAC,CAAA;QACf,KAAK,CAAC,KAAK,IAAI,EAAE;YACf,IAAI,CAAC;gBACH,kEAAkE;gBAClE,kEAAkE;gBAClE,MAAM,MAAM,CAAC,KAAK,EAAE,EAAE,CAAA;gBACtB,kEAAkE;gBAClE,oEAAoE;gBACpE,kEAAkE;gBAClE,8BAA8B;gBAC9B,MAAM,KAAK,GAAG,MAAM,yBAAyB,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,eAAe,CAAC,CAAA;gBACzF,IAAI,SAAS;oBAAE,OAAM;gBACrB,SAAS,CAAC,oBAAoB,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAA;gBAClE,SAAS,CAAC,OAAO,CAAC,CAAA;YACpB,CAAC;YAAC,MAAM,CAAC;gBACP,qEAAqE;gBACrE,4DAA4D;gBAC5D,IAAI,CAAC,SAAS;oBAAE,SAAS,CAAC,aAAa,CAAC,CAAA;YAC1C,CAAC;QACH,CAAC,CAAC,EAAE,CAAA;QACJ,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAA;QAClB,CAAC,CAAA;QACD,+EAA+E;IACjF,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAA;IAEzC,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,CAAC,CAAA;IACzC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE;QAC3B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAE,CAAA;YACvB,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAA;QACnC,CAAC;QACD,OAAO,SAAS,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAC5E,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;IAErB,MAAM,OAAO,GAAG,MAAM,KAAK,OAAO,IAAI,CAAC,MAAM,EAAE,aAAa,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;IACtE,MAAM,WAAW,GAAG,MAAM,EAAE,WAAW,IAAI,CAAC,CAAA;IAE5C,OAAO,CACL,KAAC,MAAM,IAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,YAC5C,MAAC,aAAa,mBAAa,mBAAmB,EAAC,SAAS,EAAC,8BAA8B,aACrF,MAAC,YAAY,eACX,KAAC,WAAW,cACT,SAAS,CAAC,4BAA4B,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,GAC9D,EACd,KAAC,iBAAiB,mBAAa,2BAA2B,YACvD,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,CACtB,SAAS,CAAC,wBAAwB,CAAC,CACpC,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,CAC7B,SAAS,CAAC,gCAAgC,CAAC,CAC5C,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CACZ,SAAS,CACP,MAAO,CAAC,aAAa,KAAK,CAAC;gCACzB,CAAC,CAAC,2BAA2B;gCAC7B,CAAC,CAAC,6BAA6B,EACjC,EAAE,KAAK,EAAE,MAAO,CAAC,aAAa,EAAE,CACjC,CACF,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,CACtB,8BACG,SAAS,CAAC,6BAA6B,CAAC,EACxC,MAAM,KAAK,QAAQ;wCAClB,CAAC,CAAC,IAAI,SAAS,CACX,OAAO,CAAC,MAAM,KAAK,CAAC;4CAClB,CAAC,CAAC,mCAAmC;4CACrC,CAAC,CAAC,qCAAqC,EACzC,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,CAC1B,EAAE;wCACL,CAAC,CAAC,EAAE,IACL,CACJ,CAAC,CAAC,CAAC,CACF,SAAS,CAAC,0BAA0B,EAAE;gCACpC,MAAM,EAAE,SAAS,CACf,MAAM,KAAK,WAAW;oCACpB,CAAC,CAAC,8BAA8B;oCAChC,CAAC,CAAC,2BAA2B,CAChC;gCACD,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,CAAC;6BACpD,CAAC,CACH,GACiB,IACP,EAEd,MAAM,KAAK,OAAO,IAAI,MAAM,KAAK,IAAI,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,CAC1D,KAAC,UAAU,IAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,GAAI,CAC5F,CAAC,CAAC,CAAC,IAAI,EACP,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,CAC1B,MAAC,GAAG,IAAC,GAAG,EAAC,GAAG,iBAAa,+BAA+B,aACtD,KAAC,aAAa,IAAC,SAAS,EAAC,8BAA8B,GAAG,EAC1D,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,YACzB,SAAS,CAAC,kCAAkC,CAAC,GACzC,IACH,CACP,CAAC,CAAC,CAAC,IAAI,EAER,MAAC,YAAY,eACX,KAAC,MAAM,IACL,OAAO,EAAC,SAAS,iBACL,0BAA0B,EACtC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,YAEjC,SAAS,CAAC,eAAe,CAAC,GACpB,EACT,KAAC,MAAM,IACL,OAAO,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,EACxD,QAAQ,EAAE,MAAM,KAAK,SAAS,IAAI,OAAO,IAAI,IAAI,iBACrC,2BAA2B,EACvC,OAAO,EAAE,SAAS,YAEjB,WAAW,GAAG,CAAC,IAAI,CAAC,OAAO;gCAC1B,CAAC,CAAC,SAAS,CAAC,6BAA6B,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;gCACnE,CAAC,CAAC,WAAW,GACR,IACI,IACD,GACT,CACV,CAAA;AACH,CAAC;AAED,SAAS,aAAa,CAAC,WAAmB,EAAE,WAAmB;IAC7D,MAAM,MAAM,GAAG,SAAS,CACtB,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,gCAAgC,EACrF,EAAE,KAAK,EAAE,WAAW,EAAE,CACvB,CAAA;IACD,sEAAsE;IACtE,OAAO,WAAW,GAAG,CAAC;QACpB,CAAC,CAAC,SAAS,CAAC,2BAA2B,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;QACxE,CAAC,CAAC,MAAM,CAAA;AACZ,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CAAC,EAClB,SAAS,EACT,MAAM,EACN,UAAU,GAKX;IACC,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACxE,OAAO,CACL,KAAC,KAAK,IAAC,GAAG,EAAC,GAAG,iBAAa,0BAA0B,YAClD,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACrB,KAAC,WAAW,IAEV,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EACpC,UAAU,EAAE,UAAU,IAJjB,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAKzB,CACH,CAAC,GACI,CACT,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,EACnB,SAAS,EACT,GAAG,EACH,OAAO,EACP,UAAU,GAMX;IACC,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAA;IAClC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;IACpE,OAAO,CACL,MAAC,KAAK,IAAC,GAAG,EAAC,GAAG,iBAAc,yBAAyB,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,aAC9D,OAAO,CAAC,CAAC,CAAC,CACT,MAAC,GAAG,IAAC,GAAG,EAAC,GAAG,aACV,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,MAAM,EAAC,UAAU,EAAC,IAAI,EAAC,OAAO,EAAC,SAAS,EAAC,yBAAyB,YAC/E,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GACnB,EACP,KAAC,KAAK,IAAC,OAAO,EAAC,SAAS,YAAE,GAAG,CAAC,MAAM,CAAC,MAAM,GAAS,IAChD,CACP,CAAC,CAAC,CAAC,IAAI,EACP,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACzB,KAAC,cAAc,IAEb,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EACrC,UAAU,EAAE,UAAU,IAJjB,KAAK,CAAC,GAAG,CAKd,CACH,CAAC,IACI,CACT,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAClC,SAAS,EACT,MAAM,EACN,QAAQ,GAAG,EAAE,EACb,UAAU,GAMX;IACC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAA;IAChE,OAAO,CACL,KAAC,KAAK,IAAC,GAAG,EAAC,GAAG,iBAAa,uBAAuB,YAC/C,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACrB,KAAC,cAAc,IAEb,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EACrC,UAAU,EAAE,UAAU,IAJjB,KAAK,CAAC,GAAG,CAKd,CACH,CAAC,GACI,CACT,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,EACtB,SAAS,EACT,KAAK,EACL,QAAQ,EACR,UAAU,GAMX;IACC,OAAO,CACL,MAAC,GAAG,IACF,GAAG,EAAC,GAAG,EACP,SAAS,EACP,QAAQ;YACN,CAAC,CAAC,sEAAsE;YACxE,CAAC,CAAC,iEAAiE,iBAE3D,yBAAyB,aAErC,MAAC,KAAK,IAAC,GAAG,EAAC,GAAG,EAAC,SAAS,EAAC,gBAAgB,aACvC,KAAC,cAAc,IACb,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,KAAK,CAAC,UAAU,EACtB,KAAK,EAAE,KAAK,CAAC,WAAW,EACxB,OAAO,QACP,UAAU,EAAE,UAAU,GACtB,EACF,MAAC,GAAG,IAAC,GAAG,EAAC,GAAG,EAAC,SAAS,EAAC,SAAS,aAC9B,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAC,SAAS,EAAC,UAAU,YAC9C,SAAS,CAAC,0BAA0B,CAAC,GACjC,EACP,KAAC,cAAc,IACb,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,KAAK,CAAC,UAAU,EACtB,KAAK,EAAE,KAAK,CAAC,aAAa,EAC1B,UAAU,EAAE,UAAU,GACtB,IACE,IACA,EACP,QAAQ,CAAC,CAAC,CAAC,CACV,MAAC,KAAK,IAAC,OAAO,EAAC,OAAO,iBAAa,0BAA0B,aAC3D,KAAC,WAAW,IAAC,SAAS,EAAC,QAAQ,GAAG,OAAE,SAAS,CAAC,2BAA2B,CAAC,IACpE,CACT,CAAC,CAAC,CAAC,IAAI,EACR,KAAC,KAAK,IAAC,OAAO,EAAC,SAAS,EAAC,SAAS,EAAC,UAAU,YAC1C,KAAK,CAAC,SAAS,GACV,EACR,MAAC,GAAG,IAAC,GAAG,EAAC,GAAG,EAAC,SAAS,EAAC,UAAU,aAC9B,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAC,KAAK,IAAC,OAAO,EAAC,SAAS,YAAE,SAAS,CAAC,0BAA0B,CAAC,GAAS,CAAC,CAAC,CAAC,IAAI,EAC7F,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CACjB,KAAC,KAAK,IAAC,OAAO,EAAC,SAAS,YAAE,SAAS,CAAC,8BAA8B,CAAC,GAAS,CAC7E,CAAC,CAAC,CAAC,IAAI,IACJ,IACF,CACP,CAAA;AACH,CAAC;AAED,+EAA+E;AAC/E,SAAS,cAAc,CAAC,EACtB,SAAS,EACT,IAAI,EACJ,KAAK,EACL,OAAO,GAAG,KAAK,EACf,UAAU,GAOX;IACC,MAAM,SAAS,GAAG,OAAO;QACvB,CAAC,CAAC,yFAAyF;QAC3F,CAAC,CAAC,mFAAmF,CAAA;IACvF,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,OAAO,OAAO,CAAC,CAAC,CAAC,CACf,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,MAAM,EAAC,QAAQ,EAAC,SAAS,EAAC,kBAAkB,YACzD,KAAK,GACD,CACR,CAAC,CAAC,CAAC,CACF,KAAC,IAAI,IAAC,IAAI,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAC,SAAS,EAAC,kBAAkB,YACtD,KAAK,GACD,CACR,CAAA;IACH,CAAC;IACD,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,WAAW;YACd,OAAO,CACL,KAAC,IAAI,IACH,EAAE,EAAE,oBAAoB,EACxB,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC,EAAE,EACzF,MAAM,EAAE,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,EACrE,SAAS,EAAE,SAAS,iBACR,wBAAwB,EACpC,OAAO,EAAE,UAAU,YAElB,KAAK,GACD,CACR,CAAA;QACH,KAAK,cAAc;YACjB,yEAAyE;YACzE,4DAA4D;YAC5D,OAAO,CACL,KAAC,IAAI,IACH,EAAE,EAAE,oBAAoB,EACxB,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,OAAO,EAAE,EAAE,EACnD,MAAM,EAAE,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAC9D,SAAS,EAAE,SAAS,iBACR,wBAAwB,EACpC,OAAO,EAAE,UAAU,YAElB,KAAK,GACD,CACR,CAAA;QACH,KAAK,WAAW;YACd,OAAO,CACL,KAAC,IAAI,IACH,EAAE,EAAE,oBAAoB,EACxB,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,EACrE,SAAS,EAAE,SAAS,iBACR,wBAAwB,EACpC,OAAO,EAAE,UAAU,YAElB,KAAK,GACD,CACR,CAAA;QACH,KAAK,OAAO;YACV,OAAO,CACL,KAAC,IAAI,IACH,EAAE,EAAE,oBAAoB,EACxB,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,EAAE,EAClD,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,EAC/B,SAAS,EAAE,SAAS,iBACR,wBAAwB,EACpC,OAAO,EAAE,UAAU,YAElB,KAAK,GACD,CACR,CAAA;IACL,CAAC;AACH,CAAC","sourcesContent":["import { Link, STUDIO_PROJECT_ROUTE, studioPath } from '@elytracms/studio/router'\nimport { AlertTriangle, ShieldAlert } from 'lucide-react'\nimport { useEffect, useMemo, useState } from 'react'\nimport { documentKey } from '@elytracms/core/cms-core'\nimport type { DocumentRef } from '@elytracms/core/cms-core'\nimport { buildReferenceImpact, loadInboundReferenceViews } from '@elytracms/studio/lib/references'\nimport type {\n DocumentReferenceImpact,\n ReferenceAction,\n ReferenceDeepLink,\n ReferenceEntryView,\n ReferenceImpact,\n} from '@elytracms/studio/lib/references'\nimport {\n Badge,\n Button,\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n Row,\n Stack,\n Text,\n} from '@elytracms/studio/ui'\nimport { translate } from '@elytracms/studio/lib/i18n'\nimport { useCollectionView } from '../collection-view/collection-view-context'\n\n/**\n * The EC-173 reference-aware confirmation dialog for unpublish/delete —\n * single documents (detail editor) and bulk selections (EC-169 bulk bar)\n * alike. It inverts the industry default, visibly:\n *\n * 1. *Before* the action it enumerates every inbound reference that will\n * break (published variant for unpublish, both variants for delete), with\n * the EC-172 labels and deep links to the exact field/node.\n * 2. Proceeding is allowed — weak references are the default. Zero references\n * render a plain confirm; breakage renders \"You can … — N places will show\n * a fallback\".\n * 3. Strict opt-in relation fields (`strict: true`) flip the same dialog into\n * a real block: the proceed button is disabled and every blocking referrer\n * is named and linked. The `@elytracms/core/operations` layer enforces the same\n * rule server-side (structured conflict error) — this dialog is the\n * friendly face, not the only guard.\n *\n * Pre-flight data goes through operations reference queries only (EC-155\n * index, flushed); impact semantics live in `lib/references/impact.ts`.\n */\n\ntype ImpactStatus = 'loading' | 'ready' | 'unavailable'\n\nconst ACTION_LABELS: Record<ReferenceAction, string> = {\n unpublish: translate('cms.editor.unpublish'),\n delete: translate('common.delete'),\n}\n\nexport function ReferenceConfirmDialog({\n projectId,\n action,\n targets,\n open,\n busy = false,\n onOpenChange,\n onConfirm,\n}: {\n projectId: string\n action: ReferenceAction\n /** The documents being acted on (a stable snapshot taken when opening). */\n targets: readonly DocumentRef[]\n open: boolean\n busy?: boolean\n onOpenChange: (open: boolean) => void\n onConfirm: () => void\n}) {\n const source = useCollectionView()\n const [status, setStatus] = useState<ImpactStatus>('loading')\n const [impact, setImpact] = useState<ReferenceImpact | null>(null)\n\n // A stable identity for the acted-on set, so the effect re-runs exactly\n // when the selection (not the array instance) changes.\n const targetsKey = targets.map((ref) => documentKey(ref)).join('\\n')\n\n useEffect(() => {\n if (!open || targets.length === 0) return\n let cancelled = false\n setStatus('loading')\n setImpact(null)\n void (async () => {\n try {\n // Queued session mutations (and the persisted baseline) must land\n // before the pre-flight query — the index is maintained on write.\n await source.flush?.()\n // The source knows how its records are addressed in the reference\n // index (EC-433): documents by default, `{ type: 'asset' }` for the\n // assets rail — so this pre-flight counts the SAME references the\n // rail's detail surface does.\n const views = await loadInboundReferenceViews(projectId, targets, source.referenceTarget)\n if (cancelled) return\n setImpact(buildReferenceImpact(source.collections, action, views))\n setStatus('ready')\n } catch {\n // The index being unreachable must not trap the editor: degrade to a\n // plain confirm with an explicit \"could not check\" warning.\n if (!cancelled) setStatus('unavailable')\n }\n })()\n return () => {\n cancelled = true\n }\n // `targetsKey` stands in for `targets` (stable identity for the acted-on set).\n }, [open, action, targetsKey, projectId])\n\n const actionLabel = ACTION_LABELS[action]\n const subject = useMemo(() => {\n if (targets.length === 1) {\n const ref = targets[0]!\n return `“${source.titleOf(ref)}”`\n }\n return translate('cms.reference.documentCount', { count: targets.length })\n }, [targets, source])\n\n const blocked = status === 'ready' && (impact?.totalBlocking ?? 0) > 0\n const totalBroken = impact?.totalBroken ?? 0\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent data-testid=\"reference-confirm\" className=\"max-h-[80vh] overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>\n {translate('cms.reference.confirmTitle', { action: actionLabel, subject })}\n </DialogTitle>\n <DialogDescription data-testid=\"reference-confirm-summary\">\n {status === 'loading' ? (\n translate('cms.reference.checking')\n ) : status === 'unavailable' ? (\n translate('cms.reference.checkUnavailable')\n ) : blocked ? (\n translate(\n impact!.totalBlocking === 1\n ? 'cms.reference.blocked.one'\n : 'cms.reference.blocked.other',\n { count: impact!.totalBlocking },\n )\n ) : totalBroken === 0 ? (\n <>\n {translate('cms.reference.notReferenced')}\n {action === 'delete'\n ? ` ${translate(\n targets.length === 1\n ? 'cms.reference.permanentDelete.one'\n : 'cms.reference.permanentDelete.other',\n { count: targets.length },\n )}`\n : ''}\n </>\n ) : (\n translate('cms.reference.canProceed', {\n action: translate(\n action === 'unpublish'\n ? 'cms.reference.verb.unpublish'\n : 'cms.reference.verb.delete',\n ),\n summary: impactSummary(targets.length, totalBroken),\n })\n )}\n </DialogDescription>\n </DialogHeader>\n\n {status === 'ready' && impact !== null && totalBroken > 0 ? (\n <ImpactList projectId={projectId} impact={impact} onNavigate={() => onOpenChange(false)} />\n ) : null}\n {status === 'unavailable' ? (\n <Row gap=\"2\" data-testid=\"reference-confirm-unavailable\">\n <AlertTriangle className=\"size-4 shrink-0 text-warning\" />\n <Text size=\"xs\" tone=\"muted\">\n {translate('cms.reference.proceedUnavailable')}\n </Text>\n </Row>\n ) : null}\n\n <DialogFooter>\n <Button\n variant=\"outline\"\n data-testid=\"reference-confirm-cancel\"\n onClick={() => onOpenChange(false)}\n >\n {translate('common.cancel')}\n </Button>\n <Button\n variant={action === 'delete' ? 'destructive' : 'default'}\n disabled={status === 'loading' || blocked || busy}\n data-testid=\"reference-confirm-proceed\"\n onClick={onConfirm}\n >\n {totalBroken > 0 && !blocked\n ? translate('cms.reference.proceedAnyway', { action: actionLabel })\n : actionLabel}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n )\n}\n\nfunction impactSummary(targetCount: number, totalBroken: number): string {\n const places = translate(\n totalBroken === 1 ? 'cms.reference.placeCount.one' : 'cms.reference.placeCount.other',\n { count: totalBroken },\n )\n // The bulk aggregate: \"N documents, M inbound references will break.\"\n return targetCount > 1\n ? translate('cms.reference.bulkSummary', { count: targetCount, places })\n : places\n}\n\n/**\n * The enumerated impact: flat for a single target, grouped per target for\n * bulk selections (per-item detail, EC-169 honesty rules).\n */\nfunction ImpactList({\n projectId,\n impact,\n onNavigate,\n}: {\n projectId: string\n impact: ReferenceImpact\n onNavigate: () => void\n}) {\n const affected = impact.documents.filter((doc) => doc.broken.length > 0)\n return (\n <Stack gap=\"3\" data-testid=\"reference-confirm-impact\">\n {affected.map((doc) => (\n <ImpactGroup\n key={documentKey(doc.ref)}\n projectId={projectId}\n doc={doc}\n grouped={impact.documents.length > 1}\n onNavigate={onNavigate}\n />\n ))}\n </Stack>\n )\n}\n\nfunction ImpactGroup({\n projectId,\n doc,\n grouped,\n onNavigate,\n}: {\n projectId: string\n doc: DocumentReferenceImpact\n grouped: boolean\n onNavigate: () => void\n}) {\n const source = useCollectionView()\n const blockingKeys = new Set(doc.blocking.map((entry) => entry.key))\n return (\n <Stack gap=\"2\" data-testid={`reference-confirm-doc-${doc.ref.id}`}>\n {grouped ? (\n <Row gap=\"2\">\n <Text size=\"xs\" weight=\"semibold\" tone=\"muted\" className=\"uppercase tracking-wide\">\n {source.titleOf(doc.ref)}\n </Text>\n <Badge variant=\"outline\">{doc.broken.length}</Badge>\n </Row>\n ) : null}\n {doc.broken.map((entry) => (\n <ImpactEntryRow\n key={entry.key}\n projectId={projectId}\n entry={entry}\n blocking={blockingKeys.has(entry.key)}\n onNavigate={onNavigate}\n />\n ))}\n </Stack>\n )\n}\n\n/**\n * The shared EC-173 impact rows: one deep-linked row per broken inbound\n * reference, strict-blocking ones flagged. Rendered by the document\n * confirmation dialog (above) and the asset-delete dialog (EC-202) alike — both\n * reduce to \"these places reference the thing you're removing\", so both lean on\n * the same row + deep-link rendering (which already handles asset link kinds).\n */\nexport function ReferenceImpactRows({\n projectId,\n broken,\n blocking = [],\n onNavigate,\n}: {\n projectId: string\n broken: readonly ReferenceEntryView[]\n blocking?: readonly ReferenceEntryView[]\n onNavigate: () => void\n}) {\n const blockingKeys = new Set(blocking.map((entry) => entry.key))\n return (\n <Stack gap=\"2\" data-testid=\"reference-impact-rows\">\n {broken.map((entry) => (\n <ImpactEntryRow\n key={entry.key}\n projectId={projectId}\n entry={entry}\n blocking={blockingKeys.has(entry.key)}\n onNavigate={onNavigate}\n />\n ))}\n </Stack>\n )\n}\n\n/**\n * One affected place: the EC-172 labels with a working deep link to the exact\n * field/node, the entry kind, draft/published visibility — and a strict\n * marker when this entry is what blocks the action.\n */\nfunction ImpactEntryRow({\n projectId,\n entry,\n blocking,\n onNavigate,\n}: {\n projectId: string\n entry: ReferenceEntryView\n blocking: boolean\n onNavigate: () => void\n}) {\n return (\n <Row\n gap=\"2\"\n className={\n blocking\n ? 'rounded-md border border-destructive/50 bg-destructive/5 px-2.5 py-2'\n : 'rounded-md border border-border/70 bg-background/40 px-2.5 py-2'\n }\n data-testid=\"reference-confirm-entry\"\n >\n <Stack gap=\"1\" className=\"min-w-0 flex-1\">\n <ImpactDeepLink\n projectId={projectId}\n link={entry.sourceLink}\n label={entry.sourceLabel}\n primary\n onNavigate={onNavigate}\n />\n <Row gap=\"1\" className=\"min-w-0\">\n <Text size=\"xs\" tone=\"muted\" className=\"shrink-0\">\n {translate('cms.reference.atLocation')}\n </Text>\n <ImpactDeepLink\n projectId={projectId}\n link={entry.sourceLink}\n label={entry.locationLabel}\n onNavigate={onNavigate}\n />\n </Row>\n </Stack>\n {blocking ? (\n <Badge variant=\"error\" data-testid=\"reference-confirm-strict\">\n <ShieldAlert className=\"size-3\" /> {translate('cms.reference.strictBadge')}\n </Badge>\n ) : null}\n <Badge variant=\"outline\" className=\"shrink-0\">\n {entry.kindLabel}\n </Badge>\n <Row gap=\"1\" className=\"shrink-0\">\n {entry.draft ? <Badge variant=\"warning\">{translate('cms.reference.draftBadge')}</Badge> : null}\n {entry.published ? (\n <Badge variant=\"success\">{translate('cms.reference.publishedBadge')}</Badge>\n ) : null}\n </Row>\n </Row>\n )\n}\n\n/** A deep link to the exact source location; closes the dialog on navigate. */\nfunction ImpactDeepLink({\n projectId,\n link,\n label,\n primary = false,\n onNavigate,\n}: {\n projectId: string\n link: ReferenceDeepLink | null\n label: string\n primary?: boolean\n onNavigate: () => void\n}) {\n const className = primary\n ? 'min-w-0 truncate text-sm font-medium text-foreground hover:text-primary hover:underline'\n : 'min-w-0 truncate text-xs text-muted-foreground hover:text-primary hover:underline'\n if (link === null) {\n return primary ? (\n <Text size=\"sm\" weight=\"medium\" className=\"min-w-0 truncate\">\n {label}\n </Text>\n ) : (\n <Text size=\"xs\" tone=\"muted\" className=\"min-w-0 truncate\">\n {label}\n </Text>\n )\n }\n switch (link.kind) {\n case 'cms-field':\n return (\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.cmsDocument(link.collectionId, link.documentId) }}\n search={link.fieldPath !== undefined ? { field: link.fieldPath } : {}}\n className={className}\n data-testid=\"reference-confirm-link\"\n onClick={onNavigate}\n >\n {label}\n </Link>\n )\n case 'builder-node':\n // The builder redirect (EC-187) only reads `?page=`; the page-graph-only\n // `node` has no home in the document editor and is dropped.\n return (\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.builder() }}\n search={link.pageId !== undefined ? { page: link.pageId } : {}}\n className={className}\n data-testid=\"reference-confirm-link\"\n onClick={onNavigate}\n >\n {label}\n </Link>\n )\n case 'component':\n return (\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.component(link.componentId) }}\n className={className}\n data-testid=\"reference-confirm-link\"\n onClick={onNavigate}\n >\n {label}\n </Link>\n )\n case 'asset':\n return (\n <Link\n to={STUDIO_PROJECT_ROUTE}\n params={{ projectId, _splat: studioPath.assets() }}\n search={{ asset: link.assetId }}\n className={className}\n data-testid=\"reference-confirm-link\"\n onClick={onNavigate}\n >\n {label}\n </Link>\n )\n }\n}\n"]}
|
|
@@ -12,12 +12,14 @@ import { Node } from '@tiptap/react';
|
|
|
12
12
|
* preview would need the runtime renderer + resolvers; deferred). Insertion is wired
|
|
13
13
|
* from the toolbar / slash menu.
|
|
14
14
|
*
|
|
15
|
-
* Prop editing (
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
15
|
+
* Prop editing (EC-430/AD-D): "Edit settings" on the card opens the
|
|
16
|
+
* {@link EmbedPropsStage} — the ONE prop form, identical wherever the rich-text
|
|
17
|
+
* editor is mounted (a document field in the form view, a richText PROP in the
|
|
18
|
+
* canvas-tab property inspector, or the expanded rich-text stage). It replaced the
|
|
19
|
+
* 0.0.41 host-sidebar/modal fork, whose sidebar half only rendered in the form view
|
|
20
|
+
* and left the canvas tab's edit affordance dead. Edits rewrite `attrs.node` through
|
|
21
|
+
* a proper ProseMirror transaction (undoable), immediately per prop change.
|
|
22
|
+
* `readOnly` renders an inert card (no edit/delete).
|
|
21
23
|
*/
|
|
22
24
|
export declare const ComponentEmbed: Node<any, any>;
|
|
23
25
|
/**
|