@delmaredigital/payload-puck 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE +21 -73
  2. package/README.md +1 -22
  3. package/package.json +3 -2
  4. package/dist/AccordionClient.js.map +0 -1
  5. package/dist/AccordionClient.mjs.map +0 -1
  6. package/dist/AnimatedWrapper.js.map +0 -1
  7. package/dist/AnimatedWrapper.mjs.map +0 -1
  8. package/dist/admin/client.js.map +0 -1
  9. package/dist/admin/client.mjs.map +0 -1
  10. package/dist/admin/index.js.map +0 -1
  11. package/dist/admin/index.mjs.map +0 -1
  12. package/dist/api/index.js.map +0 -1
  13. package/dist/api/index.mjs.map +0 -1
  14. package/dist/components/index.css.map +0 -1
  15. package/dist/components/index.js.map +0 -1
  16. package/dist/components/index.mjs.map +0 -1
  17. package/dist/config/config.editor.css.map +0 -1
  18. package/dist/config/config.editor.js.map +0 -1
  19. package/dist/config/config.editor.mjs.map +0 -1
  20. package/dist/config/index.js.map +0 -1
  21. package/dist/config/index.mjs.map +0 -1
  22. package/dist/editor/index.js.map +0 -1
  23. package/dist/editor/index.mjs.map +0 -1
  24. package/dist/fields/index.css.map +0 -1
  25. package/dist/fields/index.js.map +0 -1
  26. package/dist/fields/index.mjs.map +0 -1
  27. package/dist/index.js.map +0 -1
  28. package/dist/index.mjs.map +0 -1
  29. package/dist/layouts/index.js.map +0 -1
  30. package/dist/layouts/index.mjs.map +0 -1
  31. package/dist/plugin/index.js.map +0 -1
  32. package/dist/plugin/index.mjs.map +0 -1
  33. package/dist/render/index.js.map +0 -1
  34. package/dist/render/index.mjs.map +0 -1
  35. package/dist/theme/index.js.map +0 -1
  36. package/dist/theme/index.mjs.map +0 -1
  37. package/dist/utils/index.js.map +0 -1
  38. package/dist/utils/index.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/layouts/defaults.ts","../../src/layouts/utils.ts","../../src/fields/shared.ts","../../src/layouts/LayoutWrapper.tsx"],"names":[],"mappings":";;;AAYO,IAAM,aAAA,GAAkC;AAAA,EAC7C,KAAA,EAAO,SAAA;AAAA,EACP,KAAA,EAAO,SAAA;AAAA,EACP,WAAA,EAAa,mDAAA;AAAA,EACb,OAAA,EAAS;AAAA,IACP,OAAA,EAAS,EAAA;AAAA,IACT,SAAA,EAAW,8BAAA;AAAA,IACX,OAAA,EAAS;AAAA,GACX;AAAA,EACA,QAAA,EAAU,QAAA;AAAA,EACV,SAAA,EAAW;AACb;AAKO,IAAM,aAAA,GAAkC;AAAA,EAC7C,KAAA,EAAO,SAAA;AAAA,EACP,KAAA,EAAO,SAAA;AAAA,EACP,WAAA,EAAa,0DAAA;AAAA,EACb,OAAA,EAAS;AAAA,IACP,OAAA,EAAS,EAAA;AAAA,IACT,SAAA,EAAW,EAAA;AAAA,IACX,OAAA,EAAS;AAAA,GACX;AAAA,EACA,SAAA,EAAW;AACb;AAKO,IAAM,eAAA,GAAoC;AAAA,EAC/C,KAAA,EAAO,YAAA;AAAA,EACP,KAAA,EAAO,YAAA;AAAA,EACP,WAAA,EAAa,uCAAA;AAAA,EACb,OAAA,EAAS;AAAA,IACP,OAAA,EAAS,QAAA;AAAA,IACT,SAAA,EAAW,QAAA;AAAA,IACX,OAAA,EAAS;AAAA,GACX;AAAA,EACA,QAAA,EAAU,MAAA;AAAA,EACV,SAAA,EAAW;AACb;AAKO,IAAM,YAAA,GAAiC;AAAA,EAC5C,KAAA,EAAO,QAAA;AAAA,EACP,KAAA,EAAO,QAAA;AAAA,EACP,WAAA,EAAa,qDAAA;AAAA,EACb,OAAA,EAAS;AAAA,IACP,OAAA,EAAS,EAAA;AAAA,IACT,SAAA,EAAW,sBAAA;AAAA,IACX,OAAA,EAAS;AAAA,GACX;AAAA,EACA,QAAA,EAAU,OAAA;AAAA,EACV,SAAA,EAAW;AACb;AAKO,IAAM,UAAA,GAA+B;AAAA,EAC1C,KAAA,EAAO,MAAA;AAAA,EACP,KAAA,EAAO,MAAA;AAAA,EACP,WAAA,EAAa,gDAAA;AAAA,EACb,OAAA,EAAS;AAAA,IACP,OAAA,EAAS,EAAA;AAAA,IACT,SAAA,EAAW,8BAAA;AAAA,IACX,OAAA,EAAS;AAAA,GACX;AAAA,EACA,QAAA,EAAU,QAAA;AAAA,EACV,SAAA,EAAW;AACb;AAKO,IAAM,eAAA,GAAsC;AAAA,EACjD,aAAA;AAAA,EACA,aAAA;AAAA,EACA;AACF;AAKO,IAAM,gBAAA,GAAuC;AAAA,EAClD,aAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF;AAKO,IAAM,qBAAA,GAAsC;AAAA,EACjD,OAAA,EAAS,eAAA;AAAA,EACT,aAAA,EAAe;AACjB;;;ACtGO,SAAS,oBAAoB,MAAA,EAA8C;AAChF,EAAA,IAAI,CAAC,QAAQ,OAAO,qBAAA;AAEpB,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,OAAO,OAAA,IAAW,eAAA;AAAA,IAC3B,aAAA,EAAe,OAAO,aAAA,IAAiB;AAAA,GACzC;AACF;AAKO,SAAS,SAAA,CACd,OAAA,EACA,KAAA,EACA,QAAA,GAAW,SAAA,EACmB;AAC9B,EAAA,MAAM,SAAS,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,KAAK,CAAA;AACpD,EAAA,IAAI,QAAQ,OAAO,MAAA;AAGnB,EAAA,IAAI,UAAU,QAAA,EAAU;AACtB,IAAA,OAAO,QAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,QAAQ,CAAA;AAAA,EACjD;AAGA,EAAA,OAAO,QAAQ,CAAC,CAAA;AAClB;AAKO,SAAS,iBAAiB,OAAA,EAA6C;AAC5E,EAAA,OAAO,QAAQ,GAAA,CAAI,CAAC,EAAE,KAAA,EAAO,KAAA,EAAO,aAAY,MAAO;AAAA,IACrD,KAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,GACF,CAAE,CAAA;AACJ;AAKO,SAAS,wBACd,OAAA,EACyC;AACzC,EAAA,OAAO,QAAQ,GAAA,CAAI,CAAC,EAAE,KAAA,EAAO,OAAM,MAAO;AAAA,IACxC,KAAA;AAAA,IACA;AAAA,GACF,CAAE,CAAA;AACJ;AAKO,SAAS,aACd,MAAA,EAIkB;AAClB,EAAA,OAAO;AAAA,IACL,GAAG;AAAA,GACL;AACF;AAKO,SAAS,YAAA,CACd,IAAA,EACA,MAAA,EACA,OAAA,EAMoB;AACpB,EAAA,IAAI,SAAS,OAAA,EAAS;AACpB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI,MAAA,GAAS,CAAC,GAAG,IAAI,CAAA;AAGrB,EAAA,IAAI,SAAS,OAAA,EAAS;AACpB,IAAA,MAAA,GAAS,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,QAAQ,OAAA,CAAS,QAAA,CAAS,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,EACnE;AAGA,EAAA,KAAA,MAAW,gBAAgB,MAAA,EAAQ;AACjC,IAAA,MAAM,aAAA,GAAgB,OAAO,SAAA,CAAU,CAAC,MAAM,CAAA,CAAE,KAAA,KAAU,aAAa,KAAK,CAAA;AAC5E,IAAA,IAAI,iBAAiB,CAAA,EAAG;AACtB,MAAA,MAAA,CAAO,aAAa,CAAA,GAAI,YAAA;AAAA,IAC1B,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,KAAK,YAAY,CAAA;AAAA,IAC1B;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;;;ACglBA,SAAS,SAAS,GAAA,EAAyD;AACzE,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,OAAA,CAAQ,IAAA,EAAM,EAAE,CAAA;AAClC,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAE/B,EAAA,MAAM,IAAI,QAAA,CAAS,KAAA,CAAM,UAAU,CAAA,EAAG,CAAC,GAAG,EAAE,CAAA;AAC5C,EAAA,MAAM,IAAI,QAAA,CAAS,KAAA,CAAM,UAAU,CAAA,EAAG,CAAC,GAAG,EAAE,CAAA;AAC5C,EAAA,MAAM,IAAI,QAAA,CAAS,KAAA,CAAM,UAAU,CAAA,EAAG,CAAC,GAAG,EAAE,CAAA;AAE5C,EAAA,IAAI,KAAA,CAAM,CAAC,CAAA,IAAK,KAAA,CAAM,CAAC,CAAA,IAAK,KAAA,CAAM,CAAC,CAAA,EAAG,OAAO,IAAA;AAE7C,EAAA,OAAO,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAE;AACnB;AAKO,SAAS,gBAAgB,KAAA,EAA0D;AACxF,EAAA,IAAI,CAAC,KAAA,EAAO,GAAA,EAAK,OAAO,MAAA;AAExB,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA;AAC9B,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,KAAA,CAAM,GAAA;AAEvB,EAAA,MAAM,OAAA,GAAA,CAAW,KAAA,CAAM,OAAA,IAAW,GAAA,IAAO,GAAA;AAEzC,EAAA,IAAI,YAAY,CAAA,EAAG;AACjB,IAAA,OAAO,KAAA,CAAM,GAAA;AAAA,EACf;AAEA,EAAA,OAAO,CAAA,KAAA,EAAQ,GAAA,CAAI,CAAC,CAAA,EAAA,EAAK,GAAA,CAAI,CAAC,CAAA,EAAA,EAAK,GAAA,CAAI,CAAC,CAAA,EAAA,EAAK,OAAO,CAAA,CAAA,CAAA;AACtD;AAuQO,SAAS,mBAAmB,QAAA,EAAoD;AACrF,EAAA,IAAI,CAAC,QAAA,EAAU,KAAA,IAAS,QAAA,CAAS,KAAA,CAAM,WAAW,CAAA,EAAG;AACnD,IAAA,OAAO,aAAA;AAAA,EACT;AAGA,EAAA,MAAM,WAAA,GAAc,CAAC,GAAG,QAAA,CAAS,KAAK,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,CAAE,QAAA,GAAW,EAAE,QAAQ,CAAA;AAG9E,EAAA,MAAM,QAAA,GAAW,WAAA,CACd,GAAA,CAAI,CAAC,IAAA,KAAS;AACb,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,IAAA,CAAK,KAAK,CAAA,IAAK,aAAA;AAC7C,IAAA,OAAO,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,IAAA,CAAK,QAAQ,CAAA,CAAA,CAAA;AAAA,EAClC,CAAC,CAAA,CACA,IAAA,CAAK,IAAI,CAAA;AAEZ,EAAA,IAAI,QAAA,CAAS,SAAS,QAAA,EAAU;AAC9B,IAAA,MAAM,KAAA,GAAQ,SAAS,WAAA,IAAe,QAAA;AACtC,IAAA,MAAM,QAAA,GAAW,SAAS,cAAA,IAAkB,QAAA;AAC5C,IAAA,OAAO,CAAA,gBAAA,EAAmB,KAAK,CAAA,IAAA,EAAO,QAAQ,KAAK,QAAQ,CAAA,CAAA,CAAA;AAAA,EAC7D;AAGA,EAAA,OAAO,CAAA,gBAAA,EAAmB,QAAA,CAAS,KAAK,CAAA,KAAA,EAAQ,QAAQ,CAAA,CAAA,CAAA;AAC1D;AAKA,SAAS,cACP,QAAA,EACQ;AACR,EAAA,MAAM,WAAA,GAA6E;AAAA,IACjF,MAAA,EAAQ,QAAA;AAAA,IACR,GAAA,EAAK,KAAA;AAAA,IACL,MAAA,EAAQ,QAAA;AAAA,IACR,IAAA,EAAM,MAAA;AAAA,IACN,KAAA,EAAO,OAAA;AAAA,IACP,UAAA,EAAY,UAAA;AAAA,IACZ,WAAA,EAAa,WAAA;AAAA,IACb,aAAA,EAAe,aAAA;AAAA,IACf,cAAA,EAAgB;AAAA,GAClB;AACA,EAAA,OAAO,QAAA,GAAW,WAAA,CAAY,QAAQ,CAAA,IAAK,QAAA,GAAW,QAAA;AACxD;AAKA,SAAS,mBAAmB,SAAA,EAA8C;AACxE,EAAA,MAAM,YAAA,GAA0D;AAAA,IAC9D,QAAA,EAAU,QAAA;AAAA,IACV,WAAA,EAAa,WAAA;AAAA,IACb,SAAA,EAAW,SAAA;AAAA,IACX,UAAA,EAAY,UAAA;AAAA,IACZ,aAAA,EAAe,aAAA;AAAA,IACf,cAAA,EAAgB,cAAA;AAAA,IAChB,gBAAA,EAAkB,gBAAA;AAAA,IAClB,iBAAA,EAAmB,iBAAA;AAAA,IACnB,aAAA,EAAe;AAAA;AAAA,GACjB;AACA,EAAA,OAAO,YAAA,CAAa,SAAS,CAAA,IAAK,WAAA;AACpC;AAKA,SAAS,UAAU,IAAA,EAA4B;AAC7C,EAAA,MAAM,UAAA,GAAA,CAAc,IAAA,CAAK,YAAA,IAAgB,GAAA,IAAO,GAAA;AAChD,EAAA,MAAM,QAAA,GAAA,CAAY,IAAA,CAAK,UAAA,IAAc,CAAA,IAAK,GAAA;AAG1C,EAAA,IAAI,IAAA,CAAK,cAAc,aAAA,EAAe;AACpC,IAAA,OAAO,CAAA,6CAAA,EAAgD,UAAU,CAAA,EAAA,EAAK,IAAA,CAAK,aAAa,CAAA,cAAA,EAAiB,QAAQ,CAAA,EAAA,EAAK,IAAA,CAAK,WAAW,CAAA,EAAA,CAAA;AAAA,EACxI;AAGA,EAAA,MAAM,SAAA,GAAY,kBAAA,CAAmB,IAAA,CAAK,SAAS,CAAA;AACnD,EAAA,OAAO,CAAA,gBAAA,EAAmB,SAAS,CAAA,aAAA,EAAgB,UAAU,CAAA,EAAA,EAAK,IAAA,CAAK,aAAa,CAAA,cAAA,EAAiB,QAAQ,CAAA,EAAA,EAAK,IAAA,CAAK,WAAW,CAAA,EAAA,CAAA;AACpI;AAiBO,SAAS,qBACd,EAAA,EACqB;AACrB,EAAA,IAAI,CAAC,EAAA,IAAM,EAAA,CAAG,IAAA,KAAS,MAAA,EAAQ;AAC7B,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,QAA6B,EAAC;AAEpC,EAAA,QAAQ,GAAG,IAAA;AAAM,IACf,KAAK,OAAA;AACH,MAAA,IAAI,EAAA,CAAG,OAAO,GAAA,EAAK;AACjB,QAAA,KAAA,CAAM,eAAA,GAAkB,eAAA,CAAgB,EAAA,CAAG,KAAK,CAAA;AAAA,MAClD;AACA,MAAA;AAAA,IAEF,KAAK,UAAA;AACH,MAAA,IAAI,EAAA,CAAG,YAAY,EAAA,CAAG,QAAA,CAAS,SAAS,EAAA,CAAG,QAAA,CAAS,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AACpE,QAAA,KAAA,CAAM,UAAA,GAAa,kBAAA,CAAmB,EAAA,CAAG,QAAQ,CAAA;AAAA,MACnD;AACA,MAAA;AAAA,IAEF,KAAK,OAAA;AACH,MAAA,IAAI,EAAA,CAAG,KAAA,EAAO,KAAA,EAAO,GAAA,EAAK;AACxB,QAAA,MAAM,QAAA,GAAW,EAAA,CAAG,KAAA,CAAM,KAAA,CAAM,GAAA;AAChC,QAAA,MAAM,IAAA,GAAO,EAAA,CAAG,KAAA,CAAM,IAAA,IAAQ,OAAA;AAC9B,QAAA,MAAM,QAAA,GAAW,aAAA,CAAc,EAAA,CAAG,KAAA,CAAM,QAAQ,CAAA;AAChD,QAAA,MAAM,MAAA,GAAS,EAAA,CAAG,KAAA,CAAM,MAAA,IAAU,WAAA;AAClC,QAAA,MAAM,UAAA,GAAa,EAAA,CAAG,KAAA,CAAM,UAAA,IAAc,QAAA;AAG1C,QAAA,IAAI,EAAA,CAAG,SAAS,OAAA,EAAS;AAGvB,UAAA,MAAM,UAAA,GACJ,EAAA,CAAG,OAAA,CAAQ,IAAA,KAAS,OAAA,GAChB,eAAA,CAAgB,EAAA,CAAG,OAAA,CAAQ,KAAK,CAAA,GAChC,kBAAA,CAAmB,EAAA,CAAG,QAAQ,QAAQ,CAAA;AAI5C,UAAA,IAAI,EAAA,CAAG,OAAA,CAAQ,IAAA,KAAS,OAAA,IAAW,UAAA,EAAY;AAC7C,YAAA,KAAA,CAAM,kBAAkB,CAAA,gBAAA,EAAmB,UAAU,CAAA,EAAA,EAAK,UAAU,UAAU,QAAQ,CAAA,CAAA,CAAA;AAAA,UACxF,CAAA,MAAO;AACL,YAAA,KAAA,CAAM,eAAA,GAAkB,CAAA,EAAG,UAAU,CAAA,MAAA,EAAS,QAAQ,CAAA,CAAA,CAAA;AAAA,UACxD;AAEA,UAAA,KAAA,CAAM,cAAA,GAAiB,SAAS,IAAI,CAAA,CAAA;AACpC,UAAA,KAAA,CAAM,kBAAA,GAAqB,WAAW,QAAQ,CAAA,CAAA;AAC9C,UAAA,KAAA,CAAM,gBAAA,GAAmB,cAAc,MAAM,CAAA,CAAA;AAC7C,UAAA,KAAA,CAAM,oBAAA,GAAuB,WAAW,UAAU,CAAA,CAAA;AAAA,QACpD,CAAA,MAAO;AAEL,UAAA,KAAA,CAAM,eAAA,GAAkB,OAAO,QAAQ,CAAA,CAAA,CAAA;AACvC,UAAA,KAAA,CAAM,cAAA,GAAiB,IAAA;AACvB,UAAA,KAAA,CAAM,kBAAA,GAAqB,QAAA;AAC3B,UAAA,KAAA,CAAM,gBAAA,GAAmB,MAAA;AACzB,UAAA,KAAA,CAAM,oBAAA,GAAuB,UAAA;AAAA,QAC/B;AAGA,QAAA,IAAI,EAAA,CAAG,KAAA,CAAM,IAAA,EAAM,OAAA,EAAS;AAC1B,UAAA,MAAM,OAAA,GAAU,SAAA,CAAU,EAAA,CAAG,KAAA,CAAM,IAAI,CAAA;AACvC,UAAA,KAAA,CAAM,SAAA,GAAY,OAAA;AAEjB,UAAC,MAAiC,eAAA,GAAkB,OAAA;AAAA,QACvD;AAAA,MACF;AACA,MAAA;AAAA;AAGJ,EAAA,OAAO,KAAA;AACT;AC1mCA,IAAM,0BAAA,GAA4C;AAAA,EAChD,SAAA,EAAW,OAAA;AAAA,EACX,OAAA,EAAS,MAAA;AAAA,EACT,aAAA,EAAe;AACjB,CAAA;AAEA,IAAM,qBAAA,GAAuC;AAAA,EAC3C,IAAA,EAAM;AACR,CAAA;AAKO,SAAS,cAAc,EAAE,QAAA,EAAU,MAAA,EAAQ,SAAA,EAAW,WAAU,EAAuB;AAE5F,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,IAAI,WAAW,UAAA,EAAY;AACzB,MAAA,MAAM,QAAA,GAAW,oBAAA,CAAqB,SAAA,CAAU,UAAU,CAAA;AAC1D,MAAA,uBAAO,GAAA,CAAC,SAAI,KAAA,EAAO,EAAE,WAAW,OAAA,EAAS,GAAG,QAAA,EAAS,EAAI,QAAA,EAAS,CAAA;AAAA,IACpE;AACA,IAAA,uCAAU,QAAA,EAAS,CAAA;AAAA,EACrB;AAGA,EAAA,MAAM,SAAS,MAAA,CAAO,MAAA;AACtB,EAAA,MAAM,SAAS,MAAA,CAAO,MAAA;AAGtB,EAAA,MAAM,gBAAA,GACJ,SAAA,EAAW,UAAA,KAAe,MAAA,GACtB,KAAA,GACA,WAAW,UAAA,KAAe,MAAA,GACxB,IAAA,GACA,CAAC,CAAC,MAAA;AAEV,EAAA,MAAM,gBAAA,GACJ,SAAA,EAAW,UAAA,KAAe,MAAA,GACtB,KAAA,GACA,WAAW,UAAA,KAAe,MAAA,GACxB,IAAA,GACA,CAAC,CAAC,MAAA;AAGV,EAAA,MAAM,eAAA,GAAkB,OAAO,YAAA,KAAiB,KAAA;AAGhD,EAAA,MAAM,SAAA,GAA2B;AAAA,IAC/B,GAAI,OAAO,kBAAA,IAAsB,gBAAA,GAAmB,EAAE,UAAA,EAAY,MAAA,CAAO,kBAAA,EAAmB,GAAI,EAAC;AAAA,IACjG,GAAI,eAAA,GAAkB,qBAAA,GAAwB;AAAC,GACjD;AAIA,EAAA,MAAM,wBAAuC,SAAA,EAAW,UAAA,GACpD,oBAAA,CAAqB,SAAA,CAAU,UAAU,CAAA,GACzC;AAAA,IACE,GAAI,MAAA,CAAO,MAAA,EAAQ,OAAA,EAAS,UAAA,KAAe,MAAA,GACvC,EAAE,UAAA,EAAY,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,UAAA,KACpC,EAAC;AAAA,IACL,GAAI,MAAA,CAAO,MAAA,EAAQ,OAAA,EAAS,oBAAA,KAAyB,MAAA,GACjD,EAAE,oBAAA,EAAsB,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,oBAAA,KAC9C;AAAC,GACP;AAGJ,EAAA,MAAM,iBAAA,GACJ,WAAW,QAAA,IAAY,SAAA,CAAU,aAAa,SAAA,GAC1C,SAAA,CAAU,WACV,MAAA,CAAO,QAAA;AAGb,EAAA,MAAM,oBAAA,GAAuB,CAAC,OAAA,KAAuB;AACnD,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,uBACE,GAAA,CAAC,SAAI,KAAA,EAAO,EAAE,GAAG,0BAAA,EAA4B,GAAG,qBAAA,EAAsB,EACnE,QAAA,EAAA,OAAA,EACH,CAAA;AAAA,IAEJ;AAEA,IAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,IAAA,CAAK,qBAAqB,EAAE,MAAA,GAAS,CAAA;AAClE,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,uBAAO,GAAA,CAAC,SAAI,KAAA,EAAO,EAAE,WAAW,OAAA,EAAS,GAAG,qBAAA,EAAsB,EAAI,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,IAChF;AACA,IAAA,uCAAU,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,EACpB,CAAA;AAGA,EAAA,IAAI,OAAO,OAAA,EAAS;AAClB,IAAA,MAAM,gBAAgB,MAAA,CAAO,OAAA;AAC7B,IAAA,OAAO,oBAAA;AAAA,sBACL,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,QAAA,gBAAA,IAAoB,MAAA,wBAAW,MAAA,EAAA,EAAO,CAAA;AAAA,wBACvC,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAO,MAAA,CAAO,KAAK,SAAS,CAAA,CAAE,MAAA,GAAS,CAAA,GAAI,SAAA,GAAY,MAAA,EAC3D,QAAA,kBAAA,GAAA,CAAC,aAAA,EAAA,EAAe,UAAS,CAAA,EAC3B,CAAA;AAAA,QACC,gBAAA,IAAoB,MAAA,oBAAU,GAAA,CAAC,MAAA,EAAA,EAAO;AAAA,OAAA,EACzC;AAAA,KACF;AAAA,EACF;AAGA,EAAA,MAAM,YAAA,GAA8B;AAAA,IAClC,GAAG,OAAO,MAAA,EAAQ;AAAA,GACpB;AAGA,EAAA,MAAM,cAAA,GAAgC;AAAA,IACpC,GAAI,qBAAqB,CAAC,MAAA,CAAO,YAAY,EAAE,QAAA,EAAU,iBAAA,EAAkB,GAAI,EAAC;AAAA,IAChF,GAAG,OAAO,MAAA,EAAQ;AAAA,GACpB;AAGA,EAAA,MAAM,YAAA,GAA8B;AAAA,IAClC,GAAG,OAAO,MAAA,EAAQ;AAAA,GACpB;AAGA,EAAA,MAAM,SAAA,GAAoC;AAAA,IACxC,eAAe,MAAA,CAAO,KAAA;AAAA,IACtB,GAAG,MAAA,CAAO;AAAA,GACZ;AAGA,EAAA,IAAI,OAAO,SAAA,EAAW;AACpB,IAAA,OAAO,oBAAA;AAAA,sBACL,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,QAAA,gBAAA,IAAoB,MAAA,wBAAW,MAAA,EAAA,EAAO,CAAA;AAAA,wBACvC,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,CAAC,MAAA,CAAO,OAAA,EAAS,OAAA,EAAS,SAAS,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,IAAK,MAAA;AAAA,YAC7E,KAAA,EAAO;AAAA,cACL,GAAG,SAAA;AAAA,cACH,GAAI,OAAO,IAAA,CAAK,YAAY,EAAE,MAAA,GAAS,CAAA,GAAI,eAAe;AAAC,aAC7D;AAAA,YACC,GAAG,SAAA;AAAA,YAEH;AAAA;AAAA,SACH;AAAA,QACC,gBAAA,IAAoB,MAAA,oBAAU,GAAA,CAAC,MAAA,EAAA,EAAO;AAAA,OAAA,EACzC;AAAA,KACF;AAAA,EACF;AAGA,EAAA,OAAO,oBAAA;AAAA,oBACL,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,MAAA,gBAAA,IAAoB,MAAA,wBAAW,MAAA,EAAA,EAAO,CAAA;AAAA,sBACvC,GAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAW,MAAA,CAAO,OAAA,EAAS,OAAA,IAAW,MAAA;AAAA,UACtC,KAAA,EAAO;AAAA,YACL,GAAG,SAAA;AAAA,YACH,GAAI,OAAO,IAAA,CAAK,YAAY,EAAE,MAAA,GAAS,CAAA,GAAI,eAAe;AAAC,WAC7D;AAAA,UACC,GAAG,SAAA;AAAA,UAEJ,QAAA,kBAAA,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAW,CAAC,MAAA,CAAO,OAAA,EAAS,SAAA,EAAW,SAAS,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA,IAAK,MAAA;AAAA,cAC/E,OAAO,MAAA,CAAO,IAAA,CAAK,cAAc,CAAA,CAAE,MAAA,GAAS,IAAI,cAAA,GAAiB,MAAA;AAAA,cAEjE,QAAA,kBAAA,GAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBACC,SAAA,EAAW,MAAA,CAAO,OAAA,EAAS,OAAA,IAAW,MAAA;AAAA,kBACtC,OAAO,MAAA,CAAO,IAAA,CAAK,YAAY,CAAA,CAAE,MAAA,GAAS,IAAI,YAAA,GAAe,MAAA;AAAA,kBAE5D;AAAA;AAAA;AACH;AAAA;AACF;AAAA,OACF;AAAA,MACC,gBAAA,IAAoB,MAAA,oBAAU,GAAA,CAAC,MAAA,EAAA,EAAO;AAAA,KAAA,EACzC;AAAA,GACF;AACF","file":"index.mjs","sourcesContent":["/**\n * Default Layout Definitions\n *\n * These provide sensible defaults for common page layout patterns.\n * Users can override or extend these in their own configuration.\n */\n\nimport type { LayoutDefinition, LayoutConfig } from './types'\n\n/**\n * Default layout - standard content width with padding\n */\nexport const defaultLayout: LayoutDefinition = {\n value: 'default',\n label: 'Default',\n description: 'Standard page layout with contained content width',\n classes: {\n wrapper: '',\n container: 'mx-auto px-4 sm:px-6 lg:px-8',\n content: '',\n },\n maxWidth: '1200px',\n fullWidth: false,\n}\n\n/**\n * Landing layout - optimized for marketing/landing pages\n */\nexport const landingLayout: LayoutDefinition = {\n value: 'landing',\n label: 'Landing',\n description: 'Full-width sections with no global container constraints',\n classes: {\n wrapper: '',\n container: '',\n content: '',\n },\n fullWidth: true,\n}\n\n/**\n * Full width layout - edge-to-edge content\n */\nexport const fullWidthLayout: LayoutDefinition = {\n value: 'full-width',\n label: 'Full Width',\n description: 'Content spans the full viewport width',\n classes: {\n wrapper: 'w-full',\n container: 'w-full',\n content: '',\n },\n maxWidth: '100%',\n fullWidth: true,\n}\n\n/**\n * Narrow layout - ideal for blog posts and articles\n */\nexport const narrowLayout: LayoutDefinition = {\n value: 'narrow',\n label: 'Narrow',\n description: 'Narrow content width for optimal reading experience',\n classes: {\n wrapper: '',\n container: 'mx-auto px-4 sm:px-6',\n content: '',\n },\n maxWidth: '768px',\n fullWidth: false,\n}\n\n/**\n * Wide layout - extra wide content area\n */\nexport const wideLayout: LayoutDefinition = {\n value: 'wide',\n label: 'Wide',\n description: 'Wider content area for dashboards or galleries',\n classes: {\n wrapper: '',\n container: 'mx-auto px-4 sm:px-6 lg:px-8',\n content: '',\n },\n maxWidth: '1440px',\n fullWidth: false,\n}\n\n/**\n * Default layouts included with the plugin\n */\nexport const DEFAULT_LAYOUTS: LayoutDefinition[] = [\n defaultLayout,\n landingLayout,\n fullWidthLayout,\n]\n\n/**\n * Extended layouts for users who want more options\n */\nexport const EXTENDED_LAYOUTS: LayoutDefinition[] = [\n defaultLayout,\n landingLayout,\n fullWidthLayout,\n narrowLayout,\n wideLayout,\n]\n\n/**\n * Default layout configuration\n */\nexport const DEFAULT_LAYOUT_CONFIG: LayoutConfig = {\n layouts: DEFAULT_LAYOUTS,\n defaultLayout: 'default',\n}\n","/**\n * Layout Utilities\n *\n * Functions for working with layout configurations.\n */\n\nimport type { LayoutDefinition, LayoutConfig, LayoutOption } from './types'\nimport { DEFAULT_LAYOUTS, DEFAULT_LAYOUT_CONFIG } from './defaults'\n\n/**\n * Resolves a layout config, merging with defaults if needed\n */\nexport function resolveLayoutConfig(config?: Partial<LayoutConfig>): LayoutConfig {\n if (!config) return DEFAULT_LAYOUT_CONFIG\n\n return {\n layouts: config.layouts ?? DEFAULT_LAYOUTS,\n defaultLayout: config.defaultLayout ?? 'default',\n }\n}\n\n/**\n * Gets a layout definition by value\n */\nexport function getLayout(\n layouts: LayoutDefinition[],\n value: string,\n fallback = 'default'\n): LayoutDefinition | undefined {\n const layout = layouts.find((l) => l.value === value)\n if (layout) return layout\n\n // Try fallback\n if (value !== fallback) {\n return layouts.find((l) => l.value === fallback)\n }\n\n // Return first layout if nothing matches\n return layouts[0]\n}\n\n/**\n * Converts layout definitions to Puck select options\n */\nexport function layoutsToOptions(layouts: LayoutDefinition[]): LayoutOption[] {\n return layouts.map(({ value, label, description }) => ({\n value,\n label,\n description,\n }))\n}\n\n/**\n * Converts layout definitions to Payload select options\n */\nexport function layoutsToPayloadOptions(\n layouts: LayoutDefinition[]\n): Array<{ label: string; value: string }> {\n return layouts.map(({ value, label }) => ({\n label,\n value,\n }))\n}\n\n/**\n * Creates a custom layout definition\n */\nexport function createLayout(\n config: Omit<LayoutDefinition, 'value' | 'label'> & {\n value: string\n label: string\n }\n): LayoutDefinition {\n return {\n ...config,\n }\n}\n\n/**\n * Merges layout configurations\n */\nexport function mergeLayouts(\n base: LayoutDefinition[],\n custom: LayoutDefinition[],\n options?: {\n /** Replace base layouts instead of merging */\n replace?: boolean\n /** Exclude these layout values from base */\n exclude?: string[]\n }\n): LayoutDefinition[] {\n if (options?.replace) {\n return custom\n }\n\n let result = [...base]\n\n // Exclude specified layouts\n if (options?.exclude) {\n result = result.filter((l) => !options.exclude!.includes(l.value))\n }\n\n // Merge/override with custom layouts\n for (const customLayout of custom) {\n const existingIndex = result.findIndex((l) => l.value === customLayout.value)\n if (existingIndex >= 0) {\n result[existingIndex] = customLayout\n } else {\n result.push(customLayout)\n }\n }\n\n return result\n}\n","/**\n * Shared Puck Field Definitions\n *\n * Reusable field configurations and CSS utility maps for Puck components.\n * These ensure consistency across all components.\n */\n\nimport type { Field } from '@measured/puck'\nimport type React from 'react'\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Combines class names, filtering out falsy values\n * A simple alternative to clsx/classnames for bundling purposes\n */\nexport function cn(...classes: (string | boolean | undefined | null)[]): string {\n return classes.filter(Boolean).join(' ')\n}\n\n// =============================================================================\n// Custom Style Types\n// =============================================================================\n\nexport interface ColorValue {\n hex: string\n opacity?: number\n}\n\nexport interface PaddingValue {\n top: number\n right: number\n bottom: number\n left: number\n unit: 'px' | 'rem' | 'em' | '%'\n /** Whether all sides are linked (sync together). Defaults to true if not set. */\n linked?: boolean\n}\n\nexport interface BorderValue {\n style: 'none' | 'solid' | 'dashed' | 'dotted'\n width: number\n color: ColorValue | null\n radius: number\n sides: {\n top: boolean\n right: boolean\n bottom: boolean\n left: boolean\n }\n}\n\nexport interface WidthValue {\n mode: 'full' | 'contained' | 'custom'\n maxWidth: number\n unit: 'px' | 'rem' | '%' | 'vw'\n alignment: 'left' | 'center' | 'right'\n}\n\n// =============================================================================\n// Dimensions Types (Enhanced Width + Height)\n// =============================================================================\n\nexport type DimensionsUnit = 'px' | 'rem' | '%' | 'vw' | 'vh'\nexport type DimensionsMode = 'full' | 'contained' | 'custom'\nexport type ContentAlignment = 'left' | 'center' | 'right'\n\n/**\n * Represents a single dimension constraint (min or max for width or height)\n */\nexport interface DimensionConstraint {\n value: number\n unit: DimensionsUnit\n enabled: boolean\n}\n\n/**\n * Full dimensions configuration value - replaces/extends WidthValue\n * Supports min/max constraints for both width and height\n */\nexport interface DimensionsValue {\n /** Width mode: full (100%), contained (centered max-width), or custom */\n mode: DimensionsMode\n /** Content alignment within the container */\n alignment: ContentAlignment\n /** Minimum width constraint (optional) */\n minWidth?: DimensionConstraint | null\n /** Maximum width constraint (required for backward compat) */\n maxWidth: DimensionConstraint\n /** Minimum height constraint (optional) */\n minHeight?: DimensionConstraint | null\n /** Maximum height constraint (optional) */\n maxHeight?: DimensionConstraint | null\n /** UI state: whether advanced mode is expanded */\n advancedMode?: boolean\n}\n\n/**\n * Type guard to detect legacy WidthValue format\n */\nexport function isLegacyWidthValue(value: unknown): value is WidthValue {\n if (!value || typeof value !== 'object') return false\n const v = value as Record<string, unknown>\n return (\n typeof v.maxWidth === 'number' &&\n typeof v.unit === 'string' &&\n typeof v.mode === 'string' &&\n !('minWidth' in v) &&\n !('minHeight' in v) &&\n !('maxHeight' in v)\n )\n}\n\n/**\n * Migrate legacy WidthValue to new DimensionsValue format\n */\nexport function migrateWidthValue(legacy: WidthValue): DimensionsValue {\n return {\n mode: legacy.mode,\n alignment: legacy.alignment,\n maxWidth: {\n value: legacy.maxWidth,\n unit: legacy.unit,\n enabled: true,\n },\n advancedMode: false,\n }\n}\n\n// =============================================================================\n// Background Types\n// =============================================================================\n\nexport interface GradientStop {\n color: ColorValue\n position: number // 0-100%\n}\n\nexport interface GradientValue {\n type: 'linear' | 'radial'\n angle: number // 0-360 for linear\n stops: GradientStop[]\n radialShape?: 'circle' | 'ellipse'\n radialPosition?: 'center' | 'top' | 'bottom' | 'left' | 'right'\n}\n\n/**\n * Gradient mask for fading images to transparent\n */\nexport interface GradientMask {\n enabled: boolean\n direction:\n | 'to-top'\n | 'to-bottom'\n | 'to-left'\n | 'to-right'\n | 'to-top-left'\n | 'to-top-right'\n | 'to-bottom-left'\n | 'to-bottom-right'\n | 'from-center' // Radial gradient from center outward\n startOpacity: number // 0-100, typically 100 (fully visible)\n endOpacity: number // 0-100, typically 0 (fully transparent)\n startPosition: number // 0-100%, where fade begins\n endPosition: number // 0-100%, where fade ends\n}\n\nexport interface BackgroundImageValue {\n media: import('./MediaField').MediaReference | null\n size: 'cover' | 'contain' | 'auto'\n position:\n | 'center'\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right'\n repeat: 'no-repeat' | 'repeat' | 'repeat-x' | 'repeat-y'\n attachment: 'scroll' | 'fixed'\n /** Overall image opacity 0-100 (default 100) */\n opacity?: number\n /** Gradient mask for fade to transparent effect */\n mask?: GradientMask\n}\n\n/**\n * Overlay layer for images (Divi-style)\n * Renders a color or gradient on top of the background image\n */\nexport interface BackgroundOverlay {\n enabled: boolean\n type: 'solid' | 'gradient'\n solid?: ColorValue | null\n gradient?: GradientValue | null\n}\n\nexport interface BackgroundValue {\n type: 'none' | 'solid' | 'gradient' | 'image'\n solid?: ColorValue | null\n gradient?: GradientValue | null\n image?: BackgroundImageValue | null\n /** Overlay layer, only used when type === 'image' */\n overlay?: BackgroundOverlay | null\n}\n\n// =============================================================================\n// Visibility Field\n// =============================================================================\n\nexport const visibilityField: Field = {\n type: 'select',\n label: 'Visibility',\n options: [\n { label: 'Always Visible', value: 'always' },\n { label: 'Authenticated Users Only', value: 'authenticatedOnly' },\n { label: 'Guests Only', value: 'guestOnly' },\n ],\n}\n\n// =============================================================================\n// Button Style Field\n// =============================================================================\n\nexport const buttonStyleField: Field = {\n type: 'select',\n label: 'Button Style',\n options: [\n { label: 'Primary', value: 'primary' },\n { label: 'Secondary', value: 'secondary' },\n { label: 'Outline', value: 'outline' },\n { label: 'Ghost', value: 'ghost' },\n { label: 'Link', value: 'link' },\n ],\n}\n\n// =============================================================================\n// Button Variant Field\n// =============================================================================\n\nexport const buttonVariantField: Field = {\n type: 'select',\n label: 'Button Variant',\n options: [\n { label: 'Default', value: 'default' },\n { label: 'Destructive', value: 'destructive' },\n { label: 'Outline', value: 'outline' },\n { label: 'Secondary', value: 'secondary' },\n { label: 'Ghost', value: 'ghost' },\n { label: 'Link', value: 'link' },\n ],\n}\n\n// =============================================================================\n// Button Size Field\n// =============================================================================\n\nexport const buttonSizeField: Field = {\n type: 'select',\n label: 'Size',\n options: [\n { label: 'Small', value: 'sm' },\n { label: 'Default', value: 'default' },\n { label: 'Large', value: 'lg' },\n { label: 'Icon', value: 'icon' },\n ],\n}\n\n// =============================================================================\n// Background Color Field (Preset Palette)\n// =============================================================================\n\nexport const backgroundColorField: Field = {\n type: 'select',\n label: 'Background Color',\n options: [\n { label: 'None', value: 'none' },\n { label: 'Background', value: 'background' },\n { label: 'Card', value: 'card' },\n { label: 'Muted', value: 'muted' },\n { label: 'Primary', value: 'primary' },\n { label: 'Secondary', value: 'secondary' },\n { label: 'Accent', value: 'accent' },\n ],\n}\n\n// =============================================================================\n// Text Color Field (Preset Palette)\n// =============================================================================\n\nexport const textColorField: Field = {\n type: 'select',\n label: 'Text Color',\n options: [\n { label: 'Theme (Auto)', value: 'default' },\n { label: 'Foreground', value: 'foreground' },\n { label: 'Muted', value: 'muted-foreground' },\n { label: 'Primary', value: 'primary' },\n { label: 'Secondary', value: 'secondary-foreground' },\n ],\n}\n\n// =============================================================================\n// Gap/Spacing Field\n// =============================================================================\n\nexport const gapField: Field = {\n type: 'select',\n label: 'Gap',\n options: [\n { label: 'None', value: 'none' },\n { label: 'Extra Small', value: 'xs' },\n { label: 'Small', value: 'sm' },\n { label: 'Medium', value: 'md' },\n { label: 'Large', value: 'lg' },\n { label: 'Extra Large', value: 'xl' },\n { label: '2XL', value: '2xl' },\n ],\n}\n\n// =============================================================================\n// Shadow Field\n// =============================================================================\n\nexport const shadowField: Field = {\n type: 'select',\n label: 'Shadow',\n options: [\n { label: 'None', value: 'none' },\n { label: 'Small', value: 'sm' },\n { label: 'Medium', value: 'md' },\n { label: 'Large', value: 'lg' },\n { label: 'Extra Large', value: 'xl' },\n { label: '2XL', value: '2xl' },\n ],\n}\n\n// =============================================================================\n// Spacer Height Field\n// =============================================================================\n\nexport const spacerHeightField: Field = {\n type: 'select',\n label: 'Height',\n options: [\n { label: 'Extra Small (8px)', value: 'xs' },\n { label: 'Small (16px)', value: 'sm' },\n { label: 'Medium (32px)', value: 'md' },\n { label: 'Large (48px)', value: 'lg' },\n { label: 'Extra Large (64px)', value: 'xl' },\n { label: '2XL (96px)', value: '2xl' },\n { label: '3XL (128px)', value: '3xl' },\n ],\n}\n\n// =============================================================================\n// Heading Level Field\n// =============================================================================\n\nexport const headingLevelField: Field = {\n type: 'select',\n label: 'Heading Level',\n options: [\n { label: 'H1', value: 'h1' },\n { label: 'H2', value: 'h2' },\n { label: 'H3', value: 'h3' },\n { label: 'H4', value: 'h4' },\n { label: 'H5', value: 'h5' },\n { label: 'H6', value: 'h6' },\n ],\n}\n\n// =============================================================================\n// Text Size Field\n// =============================================================================\n\nexport const textSizeField: Field = {\n type: 'select',\n label: 'Text Size',\n options: [\n { label: 'Extra Small', value: 'xs' },\n { label: 'Small', value: 'sm' },\n { label: 'Base', value: 'base' },\n { label: 'Large', value: 'lg' },\n { label: 'Extra Large', value: 'xl' },\n { label: '2XL', value: '2xl' },\n ],\n}\n\n// =============================================================================\n// Aspect Ratio Field\n// =============================================================================\n\nexport const aspectRatioField: Field = {\n type: 'select',\n label: 'Aspect Ratio',\n options: [\n { label: 'Auto', value: 'auto' },\n { label: 'Square (1:1)', value: 'square' },\n { label: 'Video (16:9)', value: 'video' },\n { label: 'Portrait (3:4)', value: 'portrait' },\n { label: 'Landscape (4:3)', value: 'landscape' },\n { label: 'Wide (21:9)', value: 'wide' },\n ],\n}\n\n// =============================================================================\n// Divider Style Field\n// =============================================================================\n\nexport const dividerStyleField: Field = {\n type: 'select',\n label: 'Style',\n options: [\n { label: 'Solid', value: 'solid' },\n { label: 'Dashed', value: 'dashed' },\n { label: 'Dotted', value: 'dotted' },\n ],\n}\n\n// =============================================================================\n// Border Radius Field\n// =============================================================================\n\nexport const borderRadiusField: Field = {\n type: 'select',\n label: 'Border Radius',\n options: [\n { label: 'None', value: 'none' },\n { label: 'Small', value: 'sm' },\n { label: 'Medium', value: 'md' },\n { label: 'Large', value: 'lg' },\n { label: 'Extra Large', value: 'xl' },\n { label: '2XL', value: '2xl' },\n { label: 'Full', value: 'full' },\n ],\n}\n\n// =============================================================================\n// Columns Count Field\n// =============================================================================\n\nexport const columnsCountField: Field = {\n type: 'select',\n label: 'Columns',\n options: [\n { label: '1 Column', value: '1' },\n { label: '2 Columns', value: '2' },\n { label: '3 Columns', value: '3' },\n { label: '4 Columns', value: '4' },\n { label: '5 Columns', value: '5' },\n { label: '6 Columns', value: '6' },\n ],\n}\n\n// =============================================================================\n// Flex Direction Field\n// =============================================================================\n\nexport const flexDirectionField: Field = {\n type: 'select',\n label: 'Direction',\n options: [\n { label: 'Row (Horizontal)', value: 'row' },\n { label: 'Column (Vertical)', value: 'column' },\n { label: 'Row Reverse', value: 'row-reverse' },\n { label: 'Column Reverse', value: 'column-reverse' },\n ],\n}\n\n// =============================================================================\n// Flex Wrap Field\n// =============================================================================\n\nexport const flexWrapField: Field = {\n type: 'select',\n label: 'Wrap',\n options: [\n { label: 'No Wrap', value: 'nowrap' },\n { label: 'Wrap', value: 'wrap' },\n { label: 'Wrap Reverse', value: 'wrap-reverse' },\n ],\n}\n\n// =============================================================================\n// CSS Class Mappings\n// =============================================================================\n\n/**\n * Maps alignment values to Tailwind classes\n */\nexport const alignmentMap: Record<string, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n}\n\n/**\n * Maps background color values to Tailwind classes\n */\nexport const bgColorMap: Record<string, string> = {\n none: '',\n background: 'bg-background',\n card: 'bg-card',\n muted: 'bg-muted',\n primary: 'bg-primary',\n secondary: 'bg-secondary',\n accent: 'bg-accent',\n}\n\n/**\n * Maps text color values to Tailwind classes\n */\nexport const textColorMap: Record<string, string> = {\n default: 'text-inherit',\n foreground: 'text-foreground',\n 'muted-foreground': 'text-muted-foreground',\n primary: 'text-primary',\n 'secondary-foreground': 'text-secondary-foreground',\n}\n\n/**\n * Maps gap values to Tailwind classes\n */\nexport const gapMap: Record<string, string> = {\n none: 'gap-0',\n xs: 'gap-1',\n sm: 'gap-2',\n md: 'gap-4',\n lg: 'gap-6',\n xl: 'gap-8',\n '2xl': 'gap-12',\n}\n\n/**\n * Maps shadow values to Tailwind classes\n */\nexport const shadowMap: Record<string, string> = {\n none: '',\n sm: 'shadow-sm',\n md: 'shadow-md',\n lg: 'shadow-lg',\n xl: 'shadow-xl',\n '2xl': 'shadow-2xl',\n}\n\n/**\n * Maps spacer height values to Tailwind classes\n */\nexport const spacerHeightMap: Record<string, string> = {\n xs: 'h-2',\n sm: 'h-4',\n md: 'h-8',\n lg: 'h-12',\n xl: 'h-16',\n '2xl': 'h-24',\n '3xl': 'h-32',\n}\n\n/**\n * Maps heading level to Tailwind classes\n */\nexport const headingLevelMap: Record<string, string> = {\n h1: 'text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight',\n h2: 'text-3xl md:text-4xl font-bold tracking-tight',\n h3: 'text-2xl md:text-3xl font-semibold',\n h4: 'text-xl md:text-2xl font-semibold',\n h5: 'text-lg md:text-xl font-medium',\n h6: 'text-base md:text-lg font-medium',\n}\n\n/**\n * Maps text size to Tailwind classes\n */\nexport const textSizeMap: Record<string, string> = {\n xs: 'text-xs',\n sm: 'text-sm',\n base: 'text-base',\n lg: 'text-lg',\n xl: 'text-xl',\n '2xl': 'text-2xl',\n}\n\n/**\n * Maps aspect ratio to Tailwind classes\n */\nexport const aspectRatioMap: Record<string, string> = {\n auto: '',\n square: 'aspect-square',\n video: 'aspect-video',\n portrait: 'aspect-[3/4]',\n landscape: 'aspect-[4/3]',\n wide: 'aspect-[21/9]',\n}\n\n/**\n * Maps divider style to Tailwind classes\n */\nexport const dividerStyleMap: Record<string, string> = {\n solid: 'border-solid',\n dashed: 'border-dashed',\n dotted: 'border-dotted',\n}\n\n/**\n * Maps border radius to Tailwind classes\n */\nexport const borderRadiusMap: Record<string, string> = {\n none: 'rounded-none',\n sm: 'rounded-sm',\n md: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n full: 'rounded-full',\n}\n\n/**\n * Maps columns count to Tailwind grid classes (responsive)\n */\nexport const columnsCountMap: Record<string, string> = {\n '1': 'grid-cols-1',\n '2': 'grid-cols-1 md:grid-cols-2',\n '3': 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',\n '4': 'grid-cols-1 md:grid-cols-2 lg:grid-cols-4',\n '5': 'grid-cols-2 md:grid-cols-3 lg:grid-cols-5',\n '6': 'grid-cols-2 md:grid-cols-3 lg:grid-cols-6',\n}\n\n/**\n * Maps flex direction to Tailwind classes\n */\nexport const flexDirectionMap: Record<string, string> = {\n row: 'flex-row',\n column: 'flex-col',\n 'row-reverse': 'flex-row-reverse',\n 'column-reverse': 'flex-col-reverse',\n}\n\n/**\n * Maps justify content to Tailwind classes\n * Supports both short (start) and full (flex-start) values\n */\nexport const justifyContentMap: Record<string, string> = {\n start: 'justify-start',\n 'flex-start': 'justify-start',\n center: 'justify-center',\n end: 'justify-end',\n 'flex-end': 'justify-end',\n between: 'justify-between',\n 'space-between': 'justify-between',\n around: 'justify-around',\n 'space-around': 'justify-around',\n evenly: 'justify-evenly',\n 'space-evenly': 'justify-evenly',\n}\n\n/**\n * Maps align items to Tailwind classes\n * Supports both short (start) and full (flex-start) values\n */\nexport const alignItemsMap: Record<string, string> = {\n start: 'items-start',\n 'flex-start': 'items-start',\n center: 'items-center',\n end: 'items-end',\n 'flex-end': 'items-end',\n stretch: 'items-stretch',\n baseline: 'items-baseline',\n}\n\n/**\n * Maps self-alignment to Tailwind classes (for grid/flex item alignment)\n * Used by components like TextImageSplit for vertical self-alignment\n */\nexport const selfAlignmentMap: Record<string, string> = {\n start: 'self-start',\n 'flex-start': 'self-start',\n center: 'self-center',\n end: 'self-end',\n 'flex-end': 'self-end',\n stretch: 'self-stretch',\n auto: 'self-auto',\n}\n\n/**\n * Maps flex wrap to Tailwind classes\n */\nexport const flexWrapMap: Record<string, string> = {\n nowrap: 'flex-nowrap',\n wrap: 'flex-wrap',\n 'wrap-reverse': 'flex-wrap-reverse',\n}\n\n// =============================================================================\n// Custom Style Value Utilities\n// =============================================================================\n\n/**\n * Convert hex color to RGB components\n */\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } | null {\n const clean = hex.replace(/^#/, '')\n if (clean.length !== 6) return null\n\n const r = parseInt(clean.substring(0, 2), 16)\n const g = parseInt(clean.substring(2, 4), 16)\n const b = parseInt(clean.substring(4, 6), 16)\n\n if (isNaN(r) || isNaN(g) || isNaN(b)) return null\n\n return { r, g, b }\n}\n\n/**\n * Convert ColorValue to CSS rgba string\n */\nexport function colorValueToCSS(color: ColorValue | null | undefined): string | undefined {\n if (!color?.hex) return undefined\n\n const rgb = hexToRgb(color.hex)\n if (!rgb) return color.hex\n\n const opacity = (color.opacity ?? 100) / 100\n\n if (opacity === 1) {\n return color.hex\n }\n\n return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${opacity})`\n}\n\n/**\n * Convert PaddingValue to CSS padding string\n */\nexport function paddingValueToCSS(padding: PaddingValue | null | undefined): string | undefined {\n if (!padding) return undefined\n\n const { top, right, bottom, left, unit } = padding\n\n if (top === right && right === bottom && bottom === left) {\n return `${top}${unit}`\n }\n\n if (top === bottom && left === right) {\n return `${top}${unit} ${right}${unit}`\n }\n\n if (left === right) {\n return `${top}${unit} ${right}${unit} ${bottom}${unit}`\n }\n\n return `${top}${unit} ${right}${unit} ${bottom}${unit} ${left}${unit}`\n}\n\n/**\n * Convert PaddingValue to CSS margin string (same structure, different property)\n */\nexport function marginValueToCSS(margin: PaddingValue | null | undefined): string | undefined {\n if (!margin) return undefined\n\n const { top, right, bottom, left, unit } = margin\n\n if (top === right && right === bottom && bottom === left) {\n return `${top}${unit}`\n }\n\n if (top === bottom && left === right) {\n return `${top}${unit} ${right}${unit}`\n }\n\n if (left === right) {\n return `${top}${unit} ${right}${unit} ${bottom}${unit}`\n }\n\n return `${top}${unit} ${right}${unit} ${bottom}${unit} ${left}${unit}`\n}\n\n/**\n * Convert BorderValue to CSS properties object\n */\nexport function borderValueToCSS(border: BorderValue | null | undefined): React.CSSProperties | undefined {\n if (!border || border.style === 'none') return undefined\n\n const color = colorValueToCSS(border.color) || '#000000'\n const style: React.CSSProperties = {}\n\n if (border.sides.top) {\n style.borderTopWidth = `${border.width}px`\n style.borderTopStyle = border.style\n style.borderTopColor = color\n }\n\n if (border.sides.right) {\n style.borderRightWidth = `${border.width}px`\n style.borderRightStyle = border.style\n style.borderRightColor = color\n }\n\n if (border.sides.bottom) {\n style.borderBottomWidth = `${border.width}px`\n style.borderBottomStyle = border.style\n style.borderBottomColor = color\n }\n\n if (border.sides.left) {\n style.borderLeftWidth = `${border.width}px`\n style.borderLeftStyle = border.style\n style.borderLeftColor = color\n }\n\n if (border.radius > 0) {\n style.borderRadius = `${border.radius}px`\n }\n\n return Object.keys(style).length > 0 ? style : undefined\n}\n\n/**\n * Convert WidthValue to CSS properties object\n */\nexport function widthValueToCSS(width: WidthValue | null | undefined): React.CSSProperties | undefined {\n if (!width) return undefined\n\n const style: React.CSSProperties = {}\n\n if (width.mode === 'full') {\n style.width = '100%'\n style.maxWidth = '100%'\n } else {\n style.maxWidth = `${width.maxWidth}${width.unit}`\n style.width = '100%'\n }\n\n switch (width.alignment) {\n case 'left':\n style.marginLeft = '0'\n style.marginRight = 'auto'\n break\n case 'center':\n style.marginLeft = 'auto'\n style.marginRight = 'auto'\n break\n case 'right':\n style.marginLeft = 'auto'\n style.marginRight = '0'\n break\n }\n\n return style\n}\n\n/**\n * Convert DimensionsValue to CSS properties object\n * Handles both legacy WidthValue and new DimensionsValue formats\n */\nexport function dimensionsValueToCSS(\n dimensions: DimensionsValue | WidthValue | null | undefined\n): React.CSSProperties | undefined {\n if (!dimensions) return undefined\n\n // Handle legacy WidthValue format\n if (isLegacyWidthValue(dimensions)) {\n return widthValueToCSS(dimensions)\n }\n\n const dim = dimensions as DimensionsValue\n const style: React.CSSProperties = {}\n\n // Width handling based on mode\n if (dim.mode === 'full') {\n style.width = '100%'\n style.maxWidth = '100%'\n } else {\n style.width = '100%'\n\n // Max Width (required)\n if (dim.maxWidth?.enabled !== false && dim.maxWidth?.value > 0) {\n style.maxWidth = `${dim.maxWidth.value}${dim.maxWidth.unit}`\n }\n\n // Min Width (optional)\n if (dim.minWidth?.enabled && dim.minWidth.value > 0) {\n style.minWidth = `${dim.minWidth.value}${dim.minWidth.unit}`\n }\n }\n\n // Height handling (applies to all modes)\n if (dim.minHeight?.enabled && dim.minHeight.value > 0) {\n style.minHeight = `${dim.minHeight.value}${dim.minHeight.unit}`\n }\n\n if (dim.maxHeight?.enabled && dim.maxHeight.value > 0) {\n style.maxHeight = `${dim.maxHeight.value}${dim.maxHeight.unit}`\n }\n\n // Alignment (via margin)\n switch (dim.alignment) {\n case 'left':\n style.marginLeft = '0'\n style.marginRight = 'auto'\n break\n case 'center':\n style.marginLeft = 'auto'\n style.marginRight = 'auto'\n break\n case 'right':\n style.marginLeft = 'auto'\n style.marginRight = '0'\n break\n }\n\n return style\n}\n\n/**\n * Get human-readable summary of dimensions\n */\nexport function getDimensionsSummary(dim: DimensionsValue | null | undefined): string {\n if (!dim) return 'auto'\n\n if (dim.mode === 'full') return '100%'\n\n const parts: string[] = []\n\n if (dim.maxWidth?.enabled && dim.maxWidth.value > 0) {\n parts.push(`max: ${dim.maxWidth.value}${dim.maxWidth.unit}`)\n }\n\n if (dim.minWidth?.enabled && dim.minWidth.value > 0) {\n parts.push(`min: ${dim.minWidth.value}${dim.minWidth.unit}`)\n }\n\n if (dim.maxHeight?.enabled && dim.maxHeight.value > 0) {\n parts.push(`h-max: ${dim.maxHeight.value}${dim.maxHeight.unit}`)\n }\n\n if (dim.minHeight?.enabled && dim.minHeight.value > 0) {\n parts.push(`h-min: ${dim.minHeight.value}${dim.minHeight.unit}`)\n }\n\n return parts.length > 0 ? parts.join(' | ') : 'auto'\n}\n\n/**\n * Combined style generator for layout components\n */\nexport function getCustomStyleObject(options: {\n backgroundColor?: ColorValue | null\n textColor?: ColorValue | null\n padding?: PaddingValue | null\n margin?: PaddingValue | null\n border?: BorderValue | null\n width?: WidthValue | null\n}): React.CSSProperties {\n const style: React.CSSProperties = {}\n\n const bgColor = colorValueToCSS(options.backgroundColor)\n if (bgColor) {\n style.backgroundColor = bgColor\n }\n\n const txtColor = colorValueToCSS(options.textColor)\n if (txtColor) {\n style.color = txtColor\n }\n\n const paddingCSS = paddingValueToCSS(options.padding)\n if (paddingCSS) {\n style.padding = paddingCSS\n }\n\n const marginCSS = marginValueToCSS(options.margin)\n if (marginCSS) {\n style.margin = marginCSS\n }\n\n const borderCSS = borderValueToCSS(options.border)\n if (borderCSS) {\n Object.assign(style, borderCSS)\n }\n\n const widthCSS = widthValueToCSS(options.width)\n if (widthCSS) {\n Object.assign(style, widthCSS)\n }\n\n return style\n}\n\n/**\n * Convert GradientValue to CSS gradient string\n */\nexport function gradientValueToCSS(gradient: GradientValue | null | undefined): string {\n if (!gradient?.stops || gradient.stops.length === 0) {\n return 'transparent'\n }\n\n // Sort stops by position\n const sortedStops = [...gradient.stops].sort((a, b) => a.position - b.position)\n\n // Convert stops to CSS format\n const stopsCSS = sortedStops\n .map((stop) => {\n const color = colorValueToCSS(stop.color) || 'transparent'\n return `${color} ${stop.position}%`\n })\n .join(', ')\n\n if (gradient.type === 'radial') {\n const shape = gradient.radialShape || 'circle'\n const position = gradient.radialPosition || 'center'\n return `radial-gradient(${shape} at ${position}, ${stopsCSS})`\n }\n\n // Linear gradient\n return `linear-gradient(${gradient.angle}deg, ${stopsCSS})`\n}\n\n/**\n * Convert position value to CSS background-position\n */\nfunction positionToCSS(\n position: BackgroundImageValue['position'] | undefined\n): string {\n const positionMap: Record<NonNullable<BackgroundImageValue['position']>, string> = {\n center: 'center',\n top: 'top',\n bottom: 'bottom',\n left: 'left',\n right: 'right',\n 'top-left': 'top left',\n 'top-right': 'top right',\n 'bottom-left': 'bottom left',\n 'bottom-right': 'bottom right',\n }\n return position ? positionMap[position] || 'center' : 'center'\n}\n\n/**\n * Convert GradientMask direction to CSS gradient direction\n */\nfunction maskDirectionToCSS(direction: GradientMask['direction']): string {\n const directionMap: Record<GradientMask['direction'], string> = {\n 'to-top': 'to top',\n 'to-bottom': 'to bottom',\n 'to-left': 'to left',\n 'to-right': 'to right',\n 'to-top-left': 'to top left',\n 'to-top-right': 'to top right',\n 'to-bottom-left': 'to bottom left',\n 'to-bottom-right': 'to bottom right',\n 'from-center': 'radial', // Not used for linear, handled separately in maskToCSS\n }\n return directionMap[direction] || 'to bottom'\n}\n\n/**\n * Convert GradientMask to CSS mask-image string\n */\nfunction maskToCSS(mask: GradientMask): string {\n const startAlpha = (mask.startOpacity ?? 100) / 100\n const endAlpha = (mask.endOpacity ?? 0) / 100\n\n // Handle radial gradient for \"from-center\"\n if (mask.direction === 'from-center') {\n return `radial-gradient(circle at center, rgba(0,0,0,${startAlpha}) ${mask.startPosition}%, rgba(0,0,0,${endAlpha}) ${mask.endPosition}%)`\n }\n\n // Linear gradient for directional fades\n const direction = maskDirectionToCSS(mask.direction)\n return `linear-gradient(${direction}, rgba(0,0,0,${startAlpha}) ${mask.startPosition}%, rgba(0,0,0,${endAlpha}) ${mask.endPosition}%)`\n}\n\n/**\n * Result of background CSS conversion\n * Includes both styles and metadata for consumer components\n */\nexport interface BackgroundCSSResult {\n /** CSS properties to apply directly */\n styles: React.CSSProperties\n /** Image opacity (0-1) - consumer should apply via wrapper if needed */\n imageOpacity?: number\n}\n\n/**\n * Convert BackgroundValue to CSS properties object\n * Returns both styles and metadata for advanced features like image opacity\n */\nexport function backgroundValueToCSS(\n bg: BackgroundValue | null | undefined\n): React.CSSProperties {\n if (!bg || bg.type === 'none') {\n return {}\n }\n\n const style: React.CSSProperties = {}\n\n switch (bg.type) {\n case 'solid':\n if (bg.solid?.hex) {\n style.backgroundColor = colorValueToCSS(bg.solid)\n }\n break\n\n case 'gradient':\n if (bg.gradient && bg.gradient.stops && bg.gradient.stops.length > 0) {\n style.background = gradientValueToCSS(bg.gradient)\n }\n break\n\n case 'image':\n if (bg.image?.media?.url) {\n const imageUrl = bg.image.media.url\n const size = bg.image.size || 'cover'\n const position = positionToCSS(bg.image.position)\n const repeat = bg.image.repeat || 'no-repeat'\n const attachment = bg.image.attachment || 'scroll'\n\n // Check if overlay is enabled\n if (bg.overlay?.enabled) {\n // Layer overlay on top of image using CSS multiple backgrounds\n // Use only backgroundImage to avoid shorthand/longhand conflicts\n const overlayCSS =\n bg.overlay.type === 'solid'\n ? colorValueToCSS(bg.overlay.solid)\n : gradientValueToCSS(bg.overlay.gradient)\n\n // CSS background layering: first layer is on top\n // For solid color overlay, we need to use a gradient to make it a proper layer\n if (bg.overlay.type === 'solid' && overlayCSS) {\n style.backgroundImage = `linear-gradient(${overlayCSS}, ${overlayCSS}), url(${imageUrl})`\n } else {\n style.backgroundImage = `${overlayCSS}, url(${imageUrl})`\n }\n // Use comma-separated values for each layer\n style.backgroundSize = `auto, ${size}`\n style.backgroundPosition = `center, ${position}`\n style.backgroundRepeat = `no-repeat, ${repeat}`\n style.backgroundAttachment = `scroll, ${attachment}`\n } else {\n // No overlay, just the image\n style.backgroundImage = `url(${imageUrl})`\n style.backgroundSize = size\n style.backgroundPosition = position\n style.backgroundRepeat = repeat\n style.backgroundAttachment = attachment\n }\n\n // Apply gradient mask if enabled\n if (bg.image.mask?.enabled) {\n const maskCSS = maskToCSS(bg.image.mask)\n style.maskImage = maskCSS\n // Webkit prefix for Safari support\n ;(style as Record<string, string>).WebkitMaskImage = maskCSS\n }\n }\n break\n }\n\n return style\n}\n\n/**\n * Get image opacity from BackgroundValue (for consumer wrapper components)\n * Returns undefined if no image or opacity is 100%\n */\nexport function getBackgroundImageOpacity(\n bg: BackgroundValue | null | undefined\n): number | undefined {\n if (!bg || bg.type !== 'image' || !bg.image) return undefined\n const opacity = bg.image.opacity ?? 100\n return opacity < 100 ? opacity / 100 : undefined\n}\n\n/**\n * Check if any custom style values are set\n */\nexport function hasCustomStyles(options: {\n backgroundColor?: ColorValue | null\n textColor?: ColorValue | null\n padding?: PaddingValue | null\n margin?: PaddingValue | null\n border?: BorderValue | null\n width?: WidthValue | null\n}): boolean {\n return !!(\n options.backgroundColor?.hex ||\n options.textColor?.hex ||\n options.padding ||\n options.margin ||\n (options.border && options.border.style !== 'none') ||\n options.width\n )\n}\n\n// =============================================================================\n// Transform Types\n// =============================================================================\n\nexport type TransformOrigin =\n | 'center'\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right'\n\nexport interface TransformValue {\n rotate: number // -360 to 360\n scaleX: number // 0.1 to 3\n scaleY: number // 0.1 to 3\n scaleLocked: boolean // When true, X and Y sync\n skewX: number // -45 to 45\n skewY: number // -45 to 45\n translateX: number\n translateY: number\n translateUnit: 'px' | 'rem' | '%'\n origin: TransformOrigin\n\n // Optional 3D\n enable3D: boolean\n perspective?: number // 100-2000px\n rotateX?: number // -180 to 180\n rotateY?: number // -180 to 180\n}\n\n/**\n * Default transform value\n */\nexport const DEFAULT_TRANSFORM: TransformValue = {\n rotate: 0,\n scaleX: 1,\n scaleY: 1,\n scaleLocked: true,\n skewX: 0,\n skewY: 0,\n translateX: 0,\n translateY: 0,\n translateUnit: 'px',\n origin: 'center',\n enable3D: false,\n perspective: 1000,\n rotateX: 0,\n rotateY: 0,\n}\n\n/**\n * Convert TransformOrigin to CSS transform-origin value\n */\nfunction transformOriginToCSS(origin: TransformOrigin): string {\n const originMap: Record<TransformOrigin, string> = {\n center: 'center',\n top: 'top',\n bottom: 'bottom',\n left: 'left',\n right: 'right',\n 'top-left': 'top left',\n 'top-right': 'top right',\n 'bottom-left': 'bottom left',\n 'bottom-right': 'bottom right',\n }\n return originMap[origin] || 'center'\n}\n\n/**\n * Convert TransformValue to CSS properties object\n */\nexport function transformValueToCSS(\n transform: TransformValue | null | undefined\n): React.CSSProperties | undefined {\n if (!transform) return undefined\n\n const style: React.CSSProperties = {}\n const transforms: string[] = []\n\n // Handle 3D perspective\n if (transform.enable3D && transform.perspective) {\n style.perspective = `${transform.perspective}px`\n }\n\n // Build transform string\n // Translate\n if (transform.translateX !== 0 || transform.translateY !== 0) {\n transforms.push(\n `translate(${transform.translateX}${transform.translateUnit}, ${transform.translateY}${transform.translateUnit})`\n )\n }\n\n // Rotate (2D)\n if (transform.rotate !== 0) {\n transforms.push(`rotate(${transform.rotate}deg)`)\n }\n\n // 3D rotations\n if (transform.enable3D) {\n if (transform.rotateX && transform.rotateX !== 0) {\n transforms.push(`rotateX(${transform.rotateX}deg)`)\n }\n if (transform.rotateY && transform.rotateY !== 0) {\n transforms.push(`rotateY(${transform.rotateY}deg)`)\n }\n }\n\n // Scale\n if (transform.scaleX !== 1 || transform.scaleY !== 1) {\n if (transform.scaleX === transform.scaleY) {\n transforms.push(`scale(${transform.scaleX})`)\n } else {\n transforms.push(`scale(${transform.scaleX}, ${transform.scaleY})`)\n }\n }\n\n // Skew\n if (transform.skewX !== 0 || transform.skewY !== 0) {\n if (transform.skewX !== 0 && transform.skewY !== 0) {\n transforms.push(`skew(${transform.skewX}deg, ${transform.skewY}deg)`)\n } else if (transform.skewX !== 0) {\n transforms.push(`skewX(${transform.skewX}deg)`)\n } else {\n transforms.push(`skewY(${transform.skewY}deg)`)\n }\n }\n\n // Apply transform if we have any\n if (transforms.length > 0) {\n style.transform = transforms.join(' ')\n }\n\n // Transform origin\n if (transform.origin !== 'center') {\n style.transformOrigin = transformOriginToCSS(transform.origin)\n }\n\n // Add transform-style for 3D\n if (transform.enable3D) {\n style.transformStyle = 'preserve-3d'\n }\n\n return Object.keys(style).length > 0 ? style : undefined\n}\n\n// =============================================================================\n// Responsive Field Types\n// =============================================================================\n\nexport type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\n/**\n * Responsive value that can have different values at different breakpoints.\n * XS (extra small) is required, other breakpoints are optional overrides.\n */\nexport interface ResponsiveValue<T> {\n xs: T\n sm?: T\n md?: T\n lg?: T\n xl?: T\n}\n\n/**\n * Breakpoint configuration with labels and pixel values\n */\nexport const BREAKPOINTS: Array<{\n key: Breakpoint\n label: string\n minWidth: number | null\n}> = [\n { key: 'xs', label: 'XS', minWidth: null },\n { key: 'sm', label: 'SM', minWidth: 640 },\n { key: 'md', label: 'MD', minWidth: 768 },\n { key: 'lg', label: 'LG', minWidth: 1024 },\n { key: 'xl', label: 'XL', minWidth: 1280 },\n]\n\n// =============================================================================\n// Responsive CSS Helpers\n// =============================================================================\n\n/**\n * Type guard to check if a value is a ResponsiveValue (has breakpoint structure)\n */\nexport function isResponsiveValue<T>(value: unknown): value is ResponsiveValue<T> {\n if (!value || typeof value !== 'object') return false\n return 'xs' in value\n}\n\n/**\n * Converts a camelCase property name to kebab-case CSS property\n */\nfunction camelToKebab(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)\n}\n\n/**\n * Converts React.CSSProperties to a CSS string for use in style tags\n */\nexport function cssPropertiesToString(styles: React.CSSProperties): string {\n return Object.entries(styles)\n .filter(([, value]) => value !== undefined && value !== null && value !== '')\n .map(([key, value]) => `${camelToKebab(key)}: ${value}`)\n .join('; ')\n}\n\n/**\n * Result of converting a responsive value to CSS\n */\nexport interface ResponsiveCSSResult {\n /** Base styles to apply as inline styles */\n baseStyles: React.CSSProperties\n /** CSS media queries to render in a <style> tag */\n mediaQueryCSS: string\n}\n\n/**\n * Converts a ResponsiveValue to CSS with media queries.\n * Works with any value type that has a CSS converter function.\n *\n * @param value - The responsive or non-responsive value\n * @param converter - Function to convert the value type to CSSProperties\n * @param uniqueId - Unique class name for targeting in media queries\n * @returns Object with baseStyles (inline) and mediaQueryCSS (for <style> tag)\n *\n * @example\n * ```tsx\n * const { baseStyles, mediaQueryCSS } = responsiveValueToCSS(\n * dimensions,\n * dimensionsValueToCSS,\n * 'container-abc123'\n * )\n *\n * return (\n * <>\n * {mediaQueryCSS && <style>{mediaQueryCSS}</style>}\n * <div className=\"container-abc123\" style={baseStyles}>...</div>\n * </>\n * )\n * ```\n */\nexport function responsiveValueToCSS<T>(\n value: ResponsiveValue<T> | T | null | undefined,\n converter: (v: T) => React.CSSProperties | undefined,\n uniqueId: string\n): ResponsiveCSSResult {\n // Handle null/undefined\n if (value === null || value === undefined) {\n return { baseStyles: {}, mediaQueryCSS: '' }\n }\n\n // If not responsive (single value), return as base styles only\n if (!isResponsiveValue<T>(value)) {\n const styles = converter(value as T)\n return {\n baseStyles: styles || {},\n mediaQueryCSS: '',\n }\n }\n\n // Generate media queries for each breakpoint\n const mediaQueries: string[] = []\n let baseStyles: React.CSSProperties = {}\n\n BREAKPOINTS.forEach((bp) => {\n const bpValue = value[bp.key]\n if (bpValue === undefined) return\n\n const cssProps = converter(bpValue)\n if (!cssProps) return\n\n if (bp.key === 'xs') {\n baseStyles = cssProps\n } else {\n const styleString = cssPropertiesToString(cssProps)\n if (styleString) {\n mediaQueries.push(\n `@media (min-width: ${bp.minWidth}px) { .${uniqueId} { ${styleString} } }`\n )\n }\n }\n })\n\n return { baseStyles, mediaQueryCSS: mediaQueries.join('\\n') }\n}\n\n/**\n * Visibility value for show/hide per breakpoint\n */\nexport interface VisibilityValue {\n /** XS (extra small) visibility - true = visible, false = hidden (default: true) */\n xs: boolean\n /** Small screens (640px+) */\n sm?: boolean\n /** Override for medium screens (768px+) */\n md?: boolean\n /** Override for large screens (1024px+) */\n lg?: boolean\n /** Override for extra large screens (1280px+) */\n xl?: boolean\n}\n\n/**\n * Default visibility value (visible at all breakpoints)\n */\nexport const DEFAULT_VISIBILITY: VisibilityValue = {\n xs: true,\n sm: true,\n md: true,\n lg: true,\n xl: true,\n}\n\n/**\n * Converts a VisibilityValue to CSS with display: none media queries.\n * Each breakpoint is independent - generates targeted media queries for hidden breakpoints.\n *\n * @param visibility - The visibility settings per breakpoint\n * @param uniqueId - Unique class name for targeting in media queries\n * @returns CSS media queries string for hiding at specific breakpoints\n */\nexport function visibilityValueToCSS(\n visibility: VisibilityValue | null | undefined,\n uniqueId: string\n): string {\n if (!visibility) return ''\n\n const mediaQueries: string[] = []\n\n // Breakpoint min-widths for range calculations\n const breakpointWidths: Record<Breakpoint, number | null> = {\n xs: null, // 0px\n sm: 640,\n md: 768,\n lg: 1024,\n xl: 1280,\n }\n\n // Get next breakpoint's min-width for max-width calculation\n const getNextBreakpointWidth = (bp: Breakpoint): number | null => {\n const order: Breakpoint[] = ['xs', 'sm', 'md', 'lg', 'xl']\n const index = order.indexOf(bp)\n if (index === -1 || index === order.length - 1) return null\n return breakpointWidths[order[index + 1]]\n }\n\n // XS (0 to 639px)\n if (visibility.xs === false) {\n const nextWidth = getNextBreakpointWidth('xs')\n if (nextWidth) {\n mediaQueries.push(`@media (max-width: ${nextWidth - 1}px) { .${uniqueId} { display: none; } }`)\n } else {\n mediaQueries.push(`.${uniqueId} { display: none; }`)\n }\n }\n\n // Other breakpoints (sm, md, lg, xl)\n BREAKPOINTS.slice(1).forEach((bp) => {\n if (visibility[bp.key] === false) {\n const minWidth = breakpointWidths[bp.key]\n const maxWidth = getNextBreakpointWidth(bp.key)\n\n if (minWidth && maxWidth) {\n // Range query (e.g., sm: 640-767px)\n mediaQueries.push(\n `@media (min-width: ${minWidth}px) and (max-width: ${maxWidth - 1}px) { .${uniqueId} { display: none; } }`\n )\n } else if (minWidth) {\n // Last breakpoint (xl: 1280px+)\n mediaQueries.push(\n `@media (min-width: ${minWidth}px) { .${uniqueId} { display: none; } }`\n )\n }\n }\n })\n\n return mediaQueries.join('\\n')\n}\n\n// =============================================================================\n// Animation Types\n// =============================================================================\n\n/** Standard CSS easing functions */\nexport type EasingFunction = 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out'\n\n/** Advanced easing with spring/bounce effects via cubic-bezier approximations */\nexport type AdvancedEasingFunction =\n | EasingFunction\n | 'spring'\n | 'spring-gentle'\n | 'bounce'\n | 'bounce-in'\n | 'bounce-out'\n | 'back-in'\n | 'back-out'\n | 'back-in-out'\n | 'elastic'\n\n/** Map advanced easing to CSS cubic-bezier values */\nexport const EASING_CSS_MAP: Record<AdvancedEasingFunction, string> = {\n linear: 'linear',\n ease: 'ease',\n 'ease-in': 'ease-in',\n 'ease-out': 'ease-out',\n 'ease-in-out': 'ease-in-out',\n spring: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',\n 'spring-gentle': 'cubic-bezier(0.34, 1.56, 0.64, 1)',\n bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',\n 'bounce-in': 'cubic-bezier(0.6, -0.28, 0.735, 0.045)',\n 'bounce-out': 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',\n 'back-in': 'cubic-bezier(0.6, -0.28, 0.735, 0.045)',\n 'back-out': 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',\n 'back-in-out': 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',\n elastic: 'cubic-bezier(0.68, -0.6, 0.32, 1.6)',\n}\n\n/** Transform origin for animations (3x3 grid) */\nexport type AnimationOrigin =\n | 'center'\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right'\n\n/** Stagger direction for child animations */\nexport type StaggerDirection = 'forward' | 'reverse' | 'center' | 'edges'\n\n/** Configuration for staggered child animations */\nexport interface StaggerConfig {\n enabled: boolean\n /** Delay between each child element (ms) */\n delay: number\n /** Maximum total delay to prevent very long animations */\n maxDelay?: number\n /** Direction of stagger effect */\n direction: StaggerDirection\n}\n\n/** Animation categories for UI organization */\nexport type AnimationCategory =\n | 'fade'\n | 'scale'\n | 'slide'\n | 'blur'\n | 'rotate'\n | 'bounce'\n | 'flip'\n | 'zoom'\n\n/**\n * Extended entrance animation presets (27 total)\n * Organized by category for the UI dropdown\n */\nexport type EntranceAnimation =\n // None\n | 'none'\n // Fade (6)\n | 'fade-in'\n | 'fade-up'\n | 'fade-down'\n | 'fade-left'\n | 'fade-right'\n | 'fade-scale'\n // Scale (4)\n | 'scale-in'\n | 'scale-up'\n | 'scale-down'\n | 'scale-out'\n // Slide (4)\n | 'slide-up'\n | 'slide-down'\n | 'slide-left'\n | 'slide-right'\n // Blur (3)\n | 'blur-in'\n | 'blur-up'\n | 'blur-down'\n // Rotate (3)\n | 'rotate-in'\n | 'rotate-up'\n | 'rotate-down'\n // Bounce (3)\n | 'bounce-in'\n | 'bounce-up'\n | 'bounce-down'\n // Flip (2)\n | 'flip-x'\n | 'flip-y'\n // Zoom (2)\n | 'zoom-in'\n | 'zoom-out'\n\n/**\n * Animation presets organized by category for UI\n */\nexport const ANIMATION_CATEGORIES: Array<{\n category: AnimationCategory | 'none'\n label: string\n animations: EntranceAnimation[]\n}> = [\n { category: 'none', label: 'None', animations: ['none'] },\n { category: 'fade', label: 'Fade', animations: ['fade-in', 'fade-up', 'fade-down', 'fade-left', 'fade-right', 'fade-scale'] },\n { category: 'scale', label: 'Scale', animations: ['scale-in', 'scale-up', 'scale-down', 'scale-out'] },\n { category: 'slide', label: 'Slide', animations: ['slide-up', 'slide-down', 'slide-left', 'slide-right'] },\n { category: 'blur', label: 'Blur', animations: ['blur-in', 'blur-up', 'blur-down'] },\n { category: 'rotate', label: 'Rotate', animations: ['rotate-in', 'rotate-up', 'rotate-down'] },\n { category: 'bounce', label: 'Bounce', animations: ['bounce-in', 'bounce-up', 'bounce-down'] },\n { category: 'flip', label: 'Flip', animations: ['flip-x', 'flip-y'] },\n { category: 'zoom', label: 'Zoom', animations: ['zoom-in', 'zoom-out'] },\n]\n\nexport interface AnimationValue {\n mode: 'preset' | 'custom'\n\n // Preset mode\n entrance?: EntranceAnimation\n entranceDuration?: number // ms\n entranceDelay?: number // ms\n\n // Intensity controls (context-aware based on animation type)\n /** Distance for translate animations (8-200px) */\n distance?: number\n /** Starting scale for scale animations (0.1-2) */\n scaleFrom?: number\n /** Rotation angle for rotate animations (-180 to 180deg) */\n rotateAngle?: number\n /** Blur amount for blur animations (0-50px) */\n blurAmount?: number\n\n // Transform origin (affects scale/rotate)\n origin?: AnimationOrigin\n\n // Advanced easing\n easing?: AdvancedEasingFunction\n\n // Stagger for child elements\n stagger?: StaggerConfig\n\n // Custom transition mode\n duration?: number // 0-2000ms\n delay?: number // 0-2000ms\n\n // Scroll trigger\n triggerOnScroll?: boolean\n triggerThreshold?: number // 0-1\n triggerOnce?: boolean\n /** Margin around viewport for earlier/later triggering (e.g., \"0px 0px -100px 0px\") */\n triggerMargin?: string\n}\n\n// =============================================================================\n// Animation CSS Utilities\n// =============================================================================\n\n/**\n * Convert AnimationOrigin to CSS transform-origin value\n */\nfunction animationOriginToCSS(origin: AnimationOrigin | undefined): string {\n if (!origin) return 'center'\n const originMap: Record<AnimationOrigin, string> = {\n center: 'center',\n top: 'top',\n bottom: 'bottom',\n left: 'left',\n right: 'right',\n 'top-left': 'top left',\n 'top-right': 'top right',\n 'bottom-left': 'bottom left',\n 'bottom-right': 'bottom right',\n }\n return originMap[origin] || 'center'\n}\n\n/**\n * Convert AnimationValue to CSS transition property (for custom mode)\n * Returns undefined for preset mode - use getEntranceAnimationStyles instead\n */\nexport function animationValueToCSS(anim: AnimationValue | null): React.CSSProperties | undefined {\n if (!anim || anim.mode !== 'custom') return undefined\n\n const duration = anim.duration ?? 300\n const delay = anim.delay ?? 0\n const easing = anim.easing ?? 'ease'\n const easingCSS = EASING_CSS_MAP[easing] || 'ease'\n\n return {\n transition: `all ${duration}ms ${easingCSS} ${delay}ms`,\n transitionProperty: 'opacity, transform, filter, background-color, color, border-color, box-shadow',\n }\n}\n\n/**\n * Get initial and animate styles for entrance animations\n * Returns inline CSS style objects that work without Tailwind compilation\n * Supports all 27 animation presets with customizable intensity\n */\nexport function getEntranceAnimationStyles(anim: AnimationValue | null): {\n initial: React.CSSProperties\n animate: React.CSSProperties\n duration: number\n delay: number\n easing: string\n origin: string\n} {\n const defaultResult = {\n initial: {} as React.CSSProperties,\n animate: {} as React.CSSProperties,\n duration: 500,\n delay: 0,\n easing: 'ease',\n origin: 'center',\n }\n\n if (!anim || anim.mode !== 'preset' || anim.entrance === 'none') {\n return defaultResult\n }\n\n const duration = anim.entranceDuration ?? 500\n const delay = anim.entranceDelay ?? 0\n const easing = EASING_CSS_MAP[anim.easing ?? 'ease'] || 'ease'\n const origin = animationOriginToCSS(anim.origin)\n\n // Intensity values with defaults\n const distance = anim.distance ?? 24 // px\n const scaleFrom = anim.scaleFrom ?? 0.9\n const rotateAngle = anim.rotateAngle ?? 15 // degrees\n const blurAmount = anim.blurAmount ?? 8 // px\n\n // Build animation styles based on preset\n const entrance = anim.entrance ?? 'none'\n\n let initial: React.CSSProperties = {}\n let animate: React.CSSProperties = {}\n\n switch (entrance) {\n // ==================== FADE (6) ====================\n case 'fade-in':\n initial = { opacity: 0 }\n animate = { opacity: 1 }\n break\n\n case 'fade-up':\n initial = { opacity: 0, transform: `translateY(${distance}px)` }\n animate = { opacity: 1, transform: 'translateY(0)' }\n break\n\n case 'fade-down':\n initial = { opacity: 0, transform: `translateY(-${distance}px)` }\n animate = { opacity: 1, transform: 'translateY(0)' }\n break\n\n case 'fade-left':\n initial = { opacity: 0, transform: `translateX(${distance}px)` }\n animate = { opacity: 1, transform: 'translateX(0)' }\n break\n\n case 'fade-right':\n initial = { opacity: 0, transform: `translateX(-${distance}px)` }\n animate = { opacity: 1, transform: 'translateX(0)' }\n break\n\n case 'fade-scale':\n initial = { opacity: 0, transform: `scale(${scaleFrom})` }\n animate = { opacity: 1, transform: 'scale(1)' }\n break\n\n // ==================== SCALE (4) ====================\n case 'scale-in':\n initial = { opacity: 0, transform: `scale(${scaleFrom})` }\n animate = { opacity: 1, transform: 'scale(1)' }\n break\n\n case 'scale-up':\n initial = { opacity: 0, transform: `scale(${scaleFrom}) translateY(${distance}px)` }\n animate = { opacity: 1, transform: 'scale(1) translateY(0)' }\n break\n\n case 'scale-down':\n initial = { opacity: 0, transform: `scale(${scaleFrom}) translateY(-${distance}px)` }\n animate = { opacity: 1, transform: 'scale(1) translateY(0)' }\n break\n\n case 'scale-out':\n // Scales from larger to normal\n initial = { opacity: 0, transform: `scale(${2 - scaleFrom})` }\n animate = { opacity: 1, transform: 'scale(1)' }\n break\n\n // ==================== SLIDE (4) ====================\n case 'slide-up':\n initial = { transform: `translateY(${distance}px)` }\n animate = { transform: 'translateY(0)' }\n break\n\n case 'slide-down':\n initial = { transform: `translateY(-${distance}px)` }\n animate = { transform: 'translateY(0)' }\n break\n\n case 'slide-left':\n initial = { transform: `translateX(${distance}px)` }\n animate = { transform: 'translateX(0)' }\n break\n\n case 'slide-right':\n initial = { transform: `translateX(-${distance}px)` }\n animate = { transform: 'translateX(0)' }\n break\n\n // ==================== BLUR (3) ====================\n case 'blur-in':\n initial = { opacity: 0, filter: `blur(${blurAmount}px)` }\n animate = { opacity: 1, filter: 'blur(0)' }\n break\n\n case 'blur-up':\n initial = { opacity: 0, filter: `blur(${blurAmount}px)`, transform: `translateY(${distance}px)` }\n animate = { opacity: 1, filter: 'blur(0)', transform: 'translateY(0)' }\n break\n\n case 'blur-down':\n initial = { opacity: 0, filter: `blur(${blurAmount}px)`, transform: `translateY(-${distance}px)` }\n animate = { opacity: 1, filter: 'blur(0)', transform: 'translateY(0)' }\n break\n\n // ==================== ROTATE (3) ====================\n case 'rotate-in':\n initial = { opacity: 0, transform: `rotate(${rotateAngle}deg) scale(${scaleFrom})` }\n animate = { opacity: 1, transform: 'rotate(0) scale(1)' }\n break\n\n case 'rotate-up':\n initial = { opacity: 0, transform: `rotate(${rotateAngle}deg) translateY(${distance}px)` }\n animate = { opacity: 1, transform: 'rotate(0) translateY(0)' }\n break\n\n case 'rotate-down':\n initial = { opacity: 0, transform: `rotate(-${rotateAngle}deg) translateY(-${distance}px)` }\n animate = { opacity: 1, transform: 'rotate(0) translateY(0)' }\n break\n\n // ==================== BOUNCE (3) ====================\n // These use spring/bounce easing by default for the effect\n case 'bounce-in':\n initial = { opacity: 0, transform: `scale(${scaleFrom * 0.8})` }\n animate = { opacity: 1, transform: 'scale(1)' }\n break\n\n case 'bounce-up':\n initial = { opacity: 0, transform: `translateY(${distance * 1.5}px)` }\n animate = { opacity: 1, transform: 'translateY(0)' }\n break\n\n case 'bounce-down':\n initial = { opacity: 0, transform: `translateY(-${distance * 1.5}px)` }\n animate = { opacity: 1, transform: 'translateY(0)' }\n break\n\n // ==================== FLIP (2) ====================\n // Flip uses perspective in transform for proper 3D effect\n // Starts from -90deg (tilted back) so the flip motion is visible\n case 'flip-x':\n initial = {\n transform: 'perspective(1000px) rotateX(-90deg)',\n opacity: 0.2,\n backfaceVisibility: 'hidden',\n }\n animate = {\n transform: 'perspective(1000px) rotateX(0deg)',\n opacity: 1,\n backfaceVisibility: 'hidden',\n }\n break\n\n case 'flip-y':\n initial = {\n transform: 'perspective(1000px) rotateY(-90deg)',\n opacity: 0.2,\n backfaceVisibility: 'hidden',\n }\n animate = {\n transform: 'perspective(1000px) rotateY(0deg)',\n opacity: 1,\n backfaceVisibility: 'hidden',\n }\n break\n\n // ==================== ZOOM (2) ====================\n case 'zoom-in':\n // Starts small, zooms to full size\n initial = { opacity: 0, transform: `scale(${scaleFrom * 0.5})` }\n animate = { opacity: 1, transform: 'scale(1)' }\n break\n\n case 'zoom-out':\n // Starts large, zooms down to full size\n initial = { opacity: 0, transform: `scale(${2.5 - scaleFrom})` }\n animate = { opacity: 1, transform: 'scale(1)' }\n break\n\n default:\n break\n }\n\n return {\n initial,\n animate,\n duration,\n delay,\n easing,\n origin,\n }\n}\n\n/**\n * Get default easing for animation category\n * Bounce animations default to bounce easing, etc.\n */\nexport function getDefaultEasingForAnimation(entrance: EntranceAnimation): AdvancedEasingFunction {\n if (entrance.startsWith('bounce-')) return 'bounce'\n if (entrance.startsWith('flip-')) return 'back-out'\n if (entrance.startsWith('zoom-')) return 'ease-out'\n return 'ease'\n}\n\n/**\n * Get CSS custom properties for animation timing\n * Useful for CSS-only animations with custom properties\n */\nexport function getAnimationCSSVariables(anim: AnimationValue | null): Record<string, string> {\n if (!anim) return {}\n\n const isPreset = anim.mode === 'preset'\n const duration = isPreset ? (anim.entranceDuration ?? 500) : (anim.duration ?? 300)\n const delay = isPreset ? (anim.entranceDelay ?? 0) : (anim.delay ?? 0)\n const easing = anim.easing ?? 'ease'\n const easingCSS = EASING_CSS_MAP[easing] || 'ease'\n\n return {\n '--animation-duration': `${duration}ms`,\n '--animation-delay': `${delay}ms`,\n '--animation-easing': easingCSS,\n }\n}\n\n/**\n * Generate stagger delay for a specific child index\n * Accounts for direction (forward, reverse, center, edges)\n */\nexport function getStaggerDelay(config: StaggerConfig, index: number, totalChildren: number): number {\n if (!config.enabled || totalChildren <= 1) return 0\n\n let effectiveIndex: number\n\n switch (config.direction) {\n case 'forward':\n effectiveIndex = index\n break\n case 'reverse':\n effectiveIndex = totalChildren - 1 - index\n break\n case 'center': {\n // Center starts from middle, animates outward\n const center = (totalChildren - 1) / 2\n effectiveIndex = Math.abs(index - center)\n break\n }\n case 'edges': {\n // Edges starts from outside, animates inward\n const center = (totalChildren - 1) / 2\n effectiveIndex = center - Math.abs(index - center)\n break\n }\n default:\n effectiveIndex = index\n }\n\n const delay = effectiveIndex * config.delay\n\n // Cap at max delay if specified\n if (config.maxDelay && delay > config.maxDelay) {\n return config.maxDelay\n }\n\n return delay\n}\n\n/**\n * Generate CSS styles for staggered children\n * Returns an object with CSS custom properties for each child\n */\nexport function generateStaggerStyles(\n config: StaggerConfig | undefined,\n totalChildren: number\n): React.CSSProperties[] {\n if (!config?.enabled || totalChildren <= 1) {\n return Array(totalChildren).fill({})\n }\n\n return Array.from({ length: totalChildren }, (_, i) => {\n const delay = getStaggerDelay(config, i, totalChildren)\n return {\n '--stagger-delay': `${delay}ms`,\n transitionDelay: `${delay}ms`,\n } as React.CSSProperties\n })\n}\n\n/**\n * Check which intensity controls are relevant for an animation type\n */\nexport function getRelevantIntensityControls(entrance: EntranceAnimation): {\n showDistance: boolean\n showScale: boolean\n showRotate: boolean\n showBlur: boolean\n} {\n const hasTranslate = [\n 'fade-up', 'fade-down', 'fade-left', 'fade-right',\n 'scale-up', 'scale-down',\n 'slide-up', 'slide-down', 'slide-left', 'slide-right',\n 'blur-up', 'blur-down',\n 'rotate-up', 'rotate-down',\n 'bounce-up', 'bounce-down',\n ].includes(entrance)\n\n const hasScale = [\n 'fade-scale',\n 'scale-in', 'scale-up', 'scale-down', 'scale-out',\n 'rotate-in',\n 'bounce-in',\n 'zoom-in', 'zoom-out',\n ].includes(entrance)\n\n const hasRotate = [\n 'rotate-in', 'rotate-up', 'rotate-down',\n ].includes(entrance)\n\n const hasBlur = [\n 'blur-in', 'blur-up', 'blur-down',\n ].includes(entrance)\n\n return {\n showDistance: hasTranslate,\n showScale: hasScale,\n showRotate: hasRotate,\n showBlur: hasBlur,\n }\n}\n\n/**\n * Default animation value\n */\nexport const DEFAULT_ANIMATION: AnimationValue = {\n mode: 'preset',\n entrance: 'none',\n entranceDuration: 500,\n entranceDelay: 0,\n distance: 24,\n scaleFrom: 0.9,\n rotateAngle: 15,\n blurAmount: 8,\n origin: 'center',\n easing: 'ease',\n triggerOnScroll: true,\n triggerThreshold: 0.1,\n triggerOnce: true,\n}\n\n// =============================================================================\n// Layout Components Disallow List (prevent recursion in slots)\n// =============================================================================\n\nexport const layoutComponentsDisallow = [\n 'Container',\n 'Flex',\n 'Grid',\n 'Section',\n]\n\n","/**\n * Layout Wrapper Component\n *\n * Wraps page content with layout-specific styling and structure.\n */\n\nimport type { ReactNode, CSSProperties } from 'react'\nimport type { LayoutDefinition } from './types'\nimport { backgroundValueToCSS, type BackgroundValue } from '../fields/shared'\n\n/**\n * Page-level overrides for layout settings\n */\nexport interface PageOverrides {\n /** Override header visibility: 'default' uses layout, 'show'/'hide' overrides */\n showHeader?: 'default' | 'show' | 'hide'\n /** Override footer visibility: 'default' uses layout, 'show'/'hide' overrides */\n showFooter?: 'default' | 'show' | 'hide'\n /** Page background (overrides any layout background) */\n background?: BackgroundValue | null\n /** Page max width: 'default' uses layout, otherwise uses the value */\n maxWidth?: string\n}\n\nexport interface LayoutWrapperProps {\n children: ReactNode\n layout?: LayoutDefinition\n className?: string\n /** Page-level overrides from Puck root props */\n overrides?: PageOverrides\n}\n\n/**\n * Styles for sticky footer layout - pushes footer to bottom of viewport\n */\nconst stickyFooterContainerStyle: CSSProperties = {\n minHeight: '100vh',\n display: 'flex',\n flexDirection: 'column',\n}\n\nconst stickyFooterMainStyle: CSSProperties = {\n flex: 1,\n}\n\n/**\n * Applies layout configuration to page content\n */\nexport function LayoutWrapper({ children, layout, className, overrides }: LayoutWrapperProps) {\n // No layout - render children directly (but still apply background if set)\n if (!layout) {\n if (overrides?.background) {\n const bgStyles = backgroundValueToCSS(overrides.background)\n return <div style={{ minHeight: '100vh', ...bgStyles }}>{children}</div>\n }\n return <>{children}</>\n }\n\n // Get header/footer components\n const Header = layout.header\n const Footer = layout.footer\n\n // Determine header/footer visibility based on overrides\n const shouldShowHeader =\n overrides?.showHeader === 'hide'\n ? false\n : overrides?.showHeader === 'show'\n ? true\n : !!Header\n\n const shouldShowFooter =\n overrides?.showFooter === 'hide'\n ? false\n : overrides?.showFooter === 'show'\n ? true\n : !!Footer\n\n // Sticky footer is enabled by default - check for explicit false\n const useStickyFooter = layout.stickyFooter !== false\n\n // Calculate main content style with sticky header offset\n const mainStyle: CSSProperties = {\n ...(layout.stickyHeaderHeight && shouldShowHeader ? { paddingTop: layout.stickyHeaderHeight } : {}),\n ...(useStickyFooter ? stickyFooterMainStyle : {}),\n }\n\n // Build outer container background styles\n // Page override takes precedence, then falls back to layout wrapper background\n const outerBackgroundStyles: CSSProperties = overrides?.background\n ? backgroundValueToCSS(overrides.background)\n : {\n ...(layout.styles?.wrapper?.background !== undefined\n ? { background: layout.styles.wrapper.background }\n : {}),\n ...(layout.styles?.wrapper?.backgroundAttachment !== undefined\n ? { backgroundAttachment: layout.styles.wrapper.backgroundAttachment }\n : {}),\n }\n\n // Get effective max width (override or layout default)\n const effectiveMaxWidth =\n overrides?.maxWidth && overrides.maxWidth !== 'default'\n ? overrides.maxWidth\n : layout.maxWidth\n\n // Helper to wrap content with sticky footer container if needed\n const wrapWithStickyFooter = (content: ReactNode) => {\n if (useStickyFooter) {\n return (\n <div style={{ ...stickyFooterContainerStyle, ...outerBackgroundStyles }}>\n {content}\n </div>\n )\n }\n // Non-sticky-footer: still apply background if set\n const hasBackground = Object.keys(outerBackgroundStyles).length > 0\n if (hasBackground) {\n return <div style={{ minHeight: '100vh', ...outerBackgroundStyles }}>{content}</div>\n }\n return <>{content}</>\n }\n\n // Custom wrapper component takes precedence\n if (layout.wrapper) {\n const CustomWrapper = layout.wrapper\n return wrapWithStickyFooter(\n <>\n {shouldShowHeader && Header && <Header />}\n <main style={Object.keys(mainStyle).length > 0 ? mainStyle : undefined}>\n <CustomWrapper>{children}</CustomWrapper>\n </main>\n {shouldShowFooter && Footer && <Footer />}\n </>\n )\n }\n\n // Build wrapper styles\n const wrapperStyle: CSSProperties = {\n ...layout.styles?.wrapper,\n }\n\n // Build container styles with effective max width\n const containerStyle: CSSProperties = {\n ...(effectiveMaxWidth && !layout.fullWidth ? { maxWidth: effectiveMaxWidth } : {}),\n ...layout.styles?.container,\n }\n\n // Build content styles\n const contentStyle: CSSProperties = {\n ...layout.styles?.content,\n }\n\n // Build data attributes\n const dataAttrs: Record<string, string> = {\n 'data-layout': layout.value,\n ...layout.dataAttributes,\n }\n\n // For landing/full-width layouts, render without container constraints\n if (layout.fullWidth) {\n return wrapWithStickyFooter(\n <>\n {shouldShowHeader && Header && <Header />}\n <main\n className={[layout.classes?.wrapper, className].filter(Boolean).join(' ') || undefined}\n style={{\n ...mainStyle,\n ...(Object.keys(wrapperStyle).length > 0 ? wrapperStyle : {}),\n }}\n {...dataAttrs}\n >\n {children}\n </main>\n {shouldShowFooter && Footer && <Footer />}\n </>\n )\n }\n\n // Standard layout with container\n return wrapWithStickyFooter(\n <>\n {shouldShowHeader && Header && <Header />}\n <main\n className={layout.classes?.wrapper || undefined}\n style={{\n ...mainStyle,\n ...(Object.keys(wrapperStyle).length > 0 ? wrapperStyle : {}),\n }}\n {...dataAttrs}\n >\n <div\n className={[layout.classes?.container, className].filter(Boolean).join(' ') || undefined}\n style={Object.keys(containerStyle).length > 0 ? containerStyle : undefined}\n >\n <div\n className={layout.classes?.content || undefined}\n style={Object.keys(contentStyle).length > 0 ? contentStyle : undefined}\n >\n {children}\n </div>\n </div>\n </main>\n {shouldShowFooter && Footer && <Footer />}\n </>\n )\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/layouts/defaults.ts","../../src/layouts/utils.ts","../../src/plugin/fields/index.ts","../../src/plugin/collections/Pages.ts","../../src/collections/Templates.ts","../../src/plugin/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Default Layout Definitions\n *\n * These provide sensible defaults for common page layout patterns.\n * Users can override or extend these in their own configuration.\n */\n\nimport type { LayoutDefinition, LayoutConfig } from './types'\n\n/**\n * Default layout - standard content width with padding\n */\nexport const defaultLayout: LayoutDefinition = {\n value: 'default',\n label: 'Default',\n description: 'Standard page layout with contained content width',\n classes: {\n wrapper: '',\n container: 'mx-auto px-4 sm:px-6 lg:px-8',\n content: '',\n },\n maxWidth: '1200px',\n fullWidth: false,\n}\n\n/**\n * Landing layout - optimized for marketing/landing pages\n */\nexport const landingLayout: LayoutDefinition = {\n value: 'landing',\n label: 'Landing',\n description: 'Full-width sections with no global container constraints',\n classes: {\n wrapper: '',\n container: '',\n content: '',\n },\n fullWidth: true,\n}\n\n/**\n * Full width layout - edge-to-edge content\n */\nexport const fullWidthLayout: LayoutDefinition = {\n value: 'full-width',\n label: 'Full Width',\n description: 'Content spans the full viewport width',\n classes: {\n wrapper: 'w-full',\n container: 'w-full',\n content: '',\n },\n maxWidth: '100%',\n fullWidth: true,\n}\n\n/**\n * Narrow layout - ideal for blog posts and articles\n */\nexport const narrowLayout: LayoutDefinition = {\n value: 'narrow',\n label: 'Narrow',\n description: 'Narrow content width for optimal reading experience',\n classes: {\n wrapper: '',\n container: 'mx-auto px-4 sm:px-6',\n content: '',\n },\n maxWidth: '768px',\n fullWidth: false,\n}\n\n/**\n * Wide layout - extra wide content area\n */\nexport const wideLayout: LayoutDefinition = {\n value: 'wide',\n label: 'Wide',\n description: 'Wider content area for dashboards or galleries',\n classes: {\n wrapper: '',\n container: 'mx-auto px-4 sm:px-6 lg:px-8',\n content: '',\n },\n maxWidth: '1440px',\n fullWidth: false,\n}\n\n/**\n * Default layouts included with the plugin\n */\nexport const DEFAULT_LAYOUTS: LayoutDefinition[] = [\n defaultLayout,\n landingLayout,\n fullWidthLayout,\n]\n\n/**\n * Extended layouts for users who want more options\n */\nexport const EXTENDED_LAYOUTS: LayoutDefinition[] = [\n defaultLayout,\n landingLayout,\n fullWidthLayout,\n narrowLayout,\n wideLayout,\n]\n\n/**\n * Default layout configuration\n */\nexport const DEFAULT_LAYOUT_CONFIG: LayoutConfig = {\n layouts: DEFAULT_LAYOUTS,\n defaultLayout: 'default',\n}\n","/**\n * Layout Utilities\n *\n * Functions for working with layout configurations.\n */\n\nimport type { LayoutDefinition, LayoutConfig, LayoutOption } from './types'\nimport { DEFAULT_LAYOUTS, DEFAULT_LAYOUT_CONFIG } from './defaults'\n\n/**\n * Resolves a layout config, merging with defaults if needed\n */\nexport function resolveLayoutConfig(config?: Partial<LayoutConfig>): LayoutConfig {\n if (!config) return DEFAULT_LAYOUT_CONFIG\n\n return {\n layouts: config.layouts ?? DEFAULT_LAYOUTS,\n defaultLayout: config.defaultLayout ?? 'default',\n }\n}\n\n/**\n * Gets a layout definition by value\n */\nexport function getLayout(\n layouts: LayoutDefinition[],\n value: string,\n fallback = 'default'\n): LayoutDefinition | undefined {\n const layout = layouts.find((l) => l.value === value)\n if (layout) return layout\n\n // Try fallback\n if (value !== fallback) {\n return layouts.find((l) => l.value === fallback)\n }\n\n // Return first layout if nothing matches\n return layouts[0]\n}\n\n/**\n * Converts layout definitions to Puck select options\n */\nexport function layoutsToOptions(layouts: LayoutDefinition[]): LayoutOption[] {\n return layouts.map(({ value, label, description }) => ({\n value,\n label,\n description,\n }))\n}\n\n/**\n * Converts layout definitions to Payload select options\n */\nexport function layoutsToPayloadOptions(\n layouts: LayoutDefinition[]\n): Array<{ label: string; value: string }> {\n return layouts.map(({ value, label }) => ({\n label,\n value,\n }))\n}\n\n/**\n * Creates a custom layout definition\n */\nexport function createLayout(\n config: Omit<LayoutDefinition, 'value' | 'label'> & {\n value: string\n label: string\n }\n): LayoutDefinition {\n return {\n ...config,\n }\n}\n\n/**\n * Merges layout configurations\n */\nexport function mergeLayouts(\n base: LayoutDefinition[],\n custom: LayoutDefinition[],\n options?: {\n /** Replace base layouts instead of merging */\n replace?: boolean\n /** Exclude these layout values from base */\n exclude?: string[]\n }\n): LayoutDefinition[] {\n if (options?.replace) {\n return custom\n }\n\n let result = [...base]\n\n // Exclude specified layouts\n if (options?.exclude) {\n result = result.filter((l) => !options.exclude!.includes(l.value))\n }\n\n // Merge/override with custom layouts\n for (const customLayout of custom) {\n const existingIndex = result.findIndex((l) => l.value === customLayout.value)\n if (existingIndex >= 0) {\n result[existingIndex] = customLayout\n } else {\n result.push(customLayout)\n }\n }\n\n return result\n}\n","/**\n * Puck Field Utilities\n *\n * Provides reusable field definitions for adding Puck support to existing collections.\n * Use getPuckFields() for easy integration, or import individual fields for granular control.\n *\n * @example\n * ```typescript\n * // Option 1: Use getPuckFields() for recommended defaults\n * import { getPuckFields } from '@delmaredigital/payload-puck'\n *\n * const Pages: CollectionConfig = {\n * slug: 'pages',\n * fields: [\n * // Your existing fields...\n * ...getPuckFields({ includeSEO: false }),\n * ],\n * }\n *\n * // Option 2: Import individual fields\n * import { puckDataField, editorVersionField } from '@delmaredigital/payload-puck'\n *\n * const Pages: CollectionConfig = {\n * slug: 'pages',\n * fields: [\n * // Your existing fields...\n * puckDataField,\n * editorVersionField,\n * ],\n * }\n * ```\n */\n\nimport type { Field } from 'payload'\nimport type { GetPuckFieldsOptions, ConversionTypeOption } from './types'\nimport type { LayoutDefinition } from '../../layouts/types'\nimport { DEFAULT_LAYOUTS } from '../../layouts/defaults'\nimport { layoutsToPayloadOptions } from '../../layouts/utils'\n\n// =============================================================================\n// Core Fields\n// =============================================================================\n\n/**\n * Puck data field - stores the visual editor JSON data.\n * This field is always hidden in the admin UI as it's managed via the visual editor.\n */\nexport const puckDataField: Field = {\n name: 'puckData',\n type: 'json',\n admin: {\n hidden: true,\n description: 'Puck editor data - managed via visual editor',\n },\n}\n\n/**\n * Creates an editor version field with smart detection for hybrid setups.\n *\n * The field uses a beforeValidate hook to intelligently determine the editor version:\n * - New pages: Default to 'puck' (or custom defaultValue)\n * - Existing pages with legacy blocks but no puckData: Set to 'legacy'\n * - Existing pages with puckData: Set to 'puck'\n *\n * This prevents existing legacy content from being incorrectly marked as 'puck'\n * when the field is first added to a collection.\n *\n * @param defaultValue - The default editor version for NEW pages ('puck' or 'legacy')\n * @param sidebar - Whether to position in the sidebar (default: true)\n * @param legacyBlocksFieldName - Name of the legacy blocks field to check (default: 'layout')\n */\nexport function createEditorVersionField(\n defaultValue: 'legacy' | 'puck' = 'puck',\n sidebar: boolean = true,\n legacyBlocksFieldName: string = 'layout'\n): Field {\n return {\n name: 'editorVersion',\n type: 'select',\n // NO defaultValue here - we use the hook to intelligently detect the value\n // This prevents migrations from blindly setting 'puck' on legacy pages\n options: [\n { label: 'Legacy (Payload Blocks)', value: 'legacy' },\n { label: 'Puck Visual Editor', value: 'puck' },\n ],\n admin: {\n position: sidebar ? 'sidebar' : undefined,\n description: 'Which editor was used to create this page',\n },\n hooks: {\n beforeValidate: [\n ({ value, data, operation }) => {\n // If value is explicitly set (and not null/undefined), keep it\n if (value) return value\n\n // Detect based on content - works for both new and existing documents\n const legacyBlocks = data?.[legacyBlocksFieldName]\n const hasLegacyBlocks = Array.isArray(legacyBlocks) && legacyBlocks.length > 0\n\n const puckData = data?.puckData as { content?: unknown[] } | null | undefined\n const hasPuckData =\n puckData?.content && Array.isArray(puckData.content) && puckData.content.length > 0\n\n // If has legacy blocks but no puck data, it's a legacy page\n if (hasLegacyBlocks && !hasPuckData) {\n return 'legacy'\n }\n\n // If has puck data, it's a puck page\n if (hasPuckData) {\n return 'puck'\n }\n\n // For new documents with no content yet, use configured default\n // For existing documents with no content, also use default\n return defaultValue\n },\n ],\n },\n }\n}\n\n/**\n * Pre-configured editor version field with 'puck' as default.\n * Use createEditorVersionField() for custom configuration.\n */\nexport const editorVersionField: Field = createEditorVersionField('puck', true)\n\n/**\n * Creates a page layout field with custom layouts.\n *\n * @param layouts - Array of layout definitions (defaults to DEFAULT_LAYOUTS)\n * @param sidebar - Whether to position in the sidebar (default: true)\n */\nexport function createPageLayoutField(\n layouts: LayoutDefinition[] = DEFAULT_LAYOUTS,\n sidebar: boolean = true\n): Field {\n return {\n name: 'pageLayout',\n type: 'select',\n required: true,\n defaultValue: 'default',\n options: layoutsToPayloadOptions(layouts),\n admin: {\n position: sidebar ? 'sidebar' : undefined,\n description: 'Overall page structure and layout style',\n },\n }\n}\n\n/**\n * Pre-configured page layout field with DEFAULT_LAYOUTS.\n * Use createPageLayoutField() for custom layouts.\n */\nexport const pageLayoutField: Field = createPageLayoutField()\n\n/**\n * Homepage flag field - marks a page as the site homepage.\n */\nexport const isHomepageField: Field = {\n name: 'isHomepage',\n type: 'checkbox',\n defaultValue: false,\n admin: {\n position: 'sidebar',\n description: 'Mark this page as the homepage',\n },\n}\n\n// =============================================================================\n// Field Groups\n// =============================================================================\n\n/**\n * SEO/Meta field group with all metadata fields.\n * Uses the official @payloadcms/plugin-seo convention: meta.title, meta.description\n *\n * Includes: title, description, image, noindex, nofollow, excludeFromSitemap\n */\nexport const seoFieldGroup: Field = {\n name: 'meta',\n type: 'group',\n label: 'SEO',\n admin: {\n position: 'sidebar',\n },\n fields: [\n {\n name: 'title',\n type: 'text',\n label: 'Meta Title',\n admin: {\n description: 'Override the page title for search engines',\n },\n },\n {\n name: 'description',\n type: 'textarea',\n label: 'Meta Description',\n admin: {\n description: 'Description shown in search engine results',\n },\n },\n {\n name: 'image',\n type: 'upload',\n relationTo: 'media',\n label: 'Open Graph Image',\n admin: {\n description: 'Image shown when sharing on social media',\n },\n },\n {\n name: 'noindex',\n type: 'checkbox',\n label: 'No Index',\n defaultValue: false,\n admin: {\n description: 'Prevent search engines from indexing this page',\n },\n },\n {\n name: 'nofollow',\n type: 'checkbox',\n label: 'No Follow',\n defaultValue: false,\n admin: {\n description: 'Prevent search engines from following links on this page',\n },\n },\n {\n name: 'excludeFromSitemap',\n type: 'checkbox',\n label: 'Exclude from Sitemap',\n defaultValue: false,\n admin: {\n description: 'Exclude this page from the XML sitemap',\n },\n },\n ],\n}\n\n/**\n * Default conversion type options\n */\nexport const DEFAULT_CONVERSION_TYPES: ConversionTypeOption[] = [\n { label: 'Lead', value: 'lead' },\n { label: 'Registration', value: 'registration' },\n { label: 'Purchase', value: 'purchase' },\n { label: 'Donation', value: 'donation' },\n { label: 'Newsletter Signup', value: 'newsletter' },\n { label: 'Contact Form', value: 'contact' },\n { label: 'Custom', value: 'custom' },\n]\n\n/**\n * Creates a conversion tracking field group with custom options.\n *\n * @param conversionTypes - Custom conversion type options (defaults to DEFAULT_CONVERSION_TYPES)\n * @param sidebar - Whether to position in the sidebar (default: true)\n *\n * @example\n * ```typescript\n * // Use default conversion types\n * ...getPuckFields({ includeConversion: true })\n *\n * // Use custom conversion types\n * ...getPuckFields({\n * includeConversion: true,\n * conversionTypeOptions: [\n * { label: 'Registration', value: 'registration' },\n * { label: 'Donation', value: 'donation' },\n * { label: 'Course Start', value: 'course_start' },\n * { label: 'Custom', value: 'custom' },\n * ],\n * })\n * ```\n */\nexport function createConversionFieldGroup(\n conversionTypes: ConversionTypeOption[] = DEFAULT_CONVERSION_TYPES,\n sidebar: boolean = true\n): Field {\n return {\n name: 'conversionTracking',\n type: 'group',\n label: 'Conversion Tracking',\n admin: {\n position: sidebar ? 'sidebar' : undefined,\n description: 'Configure conversion tracking for analytics',\n },\n fields: [\n {\n name: 'isConversionPage',\n type: 'checkbox',\n label: 'Is Conversion Page',\n defaultValue: false,\n admin: {\n description:\n 'Check this if this page represents a completed conversion (e.g., thank you page)',\n },\n },\n {\n name: 'conversionType',\n type: 'select',\n label: 'Conversion Type',\n options: conversionTypes,\n admin: {\n description: 'Type of conversion this page represents',\n condition: (data, siblingData) => siblingData?.isConversionPage === true,\n },\n },\n {\n name: 'conversionValue',\n type: 'number',\n label: 'Conversion Value',\n defaultValue: 0,\n admin: {\n description: 'Monetary value of this conversion (0 for non-monetary conversions)',\n condition: (data, siblingData) => siblingData?.isConversionPage === true,\n },\n },\n ],\n }\n}\n\n/**\n * Pre-configured conversion tracking field group with default options.\n * Use createConversionFieldGroup() for custom conversion types.\n */\nexport const conversionFieldGroup: Field = createConversionFieldGroup()\n\n// =============================================================================\n// Main Utility Function\n// =============================================================================\n\n/**\n * Returns an array of Puck-related field definitions for hybrid collection integration.\n *\n * Use this when you have an existing collection with legacy Payload blocks and want\n * to ADD Puck support without replacing your entire collection configuration.\n *\n * @param options - Configuration options for which fields to include\n * @returns Array of Field definitions to spread into your collection's fields array\n *\n * @example\n * ```typescript\n * import { getPuckFields } from '@delmaredigital/payload-puck'\n *\n * export const Pages: CollectionConfig = {\n * slug: 'pages',\n * fields: [\n * // Your existing fields\n * { name: 'title', type: 'text', required: true },\n * { name: 'slug', type: 'text', required: true },\n *\n * // Legacy Payload blocks (keep these!)\n * { name: 'layout', type: 'blocks', blocks: [...] },\n *\n * // Add Puck fields for hybrid editing\n * ...getPuckFields({\n * includeSEO: false, // You have your own SEO fields\n * includeConversion: true, // Include conversion tracking\n * includeEditorVersion: true,\n * }),\n * ],\n * }\n * ```\n */\nexport function getPuckFields(options: GetPuckFieldsOptions = {}): Field[] {\n const {\n includeSEO = true,\n includeConversion = false,\n includeEditorVersion = true,\n includePageLayout = true,\n includeIsHomepage = false,\n layouts = DEFAULT_LAYOUTS,\n defaultEditorVersion = 'puck',\n legacyBlocksFieldName = 'layout',\n sidebarPosition = true,\n conversionTypeOptions,\n } = options\n\n const fields: Field[] = []\n\n // Core puckData field (always included - this is essential for Puck)\n fields.push(puckDataField)\n\n // Editor version field (discriminator for hybrid rendering)\n // Uses smart detection to preserve legacy pages when field is first added\n if (includeEditorVersion) {\n fields.push(createEditorVersionField(defaultEditorVersion, sidebarPosition, legacyBlocksFieldName))\n }\n\n // Page layout field\n if (includePageLayout) {\n fields.push(createPageLayoutField(layouts, sidebarPosition))\n }\n\n // Homepage flag\n if (includeIsHomepage) {\n fields.push(isHomepageField)\n }\n\n // SEO group\n if (includeSEO) {\n fields.push(seoFieldGroup)\n }\n\n // Conversion tracking group (with optional custom conversion types)\n if (includeConversion) {\n fields.push(createConversionFieldGroup(conversionTypeOptions, sidebarPosition))\n }\n\n return fields\n}\n\n// Re-export types\nexport type { GetPuckFieldsOptions, ConversionTypeOption } from './types'\n","import type { Access, CollectionConfig, Field } from 'payload'\nimport type { PuckPluginOptions } from '../../types'\nimport { DEFAULT_LAYOUTS } from '../../layouts/defaults'\nimport { layoutsToPayloadOptions } from '../../layouts/utils'\nimport {\n puckDataField,\n createEditorVersionField,\n createPageLayoutField,\n isHomepageField,\n seoFieldGroup,\n conversionFieldGroup,\n} from '../fields'\n\n/**\n * Default access function - allows all\n */\nconst defaultAccess: Access = () => true\n\n/**\n * Generates a Pages collection configuration for Puck\n */\nexport function generatePagesCollection(\n slug: string,\n options: PuckPluginOptions\n): CollectionConfig {\n const {\n collectionOverrides = {},\n access = {},\n layouts = DEFAULT_LAYOUTS,\n additionalFields = [],\n } = options\n\n const baseFields: Field[] = [\n // Core Fields (title and slug with duplication hooks - unique to collection generation)\n {\n name: 'title',\n type: 'text',\n required: true,\n hooks: {\n beforeDuplicate: [\n ({ value }) => {\n if (!value) return value\n const copyMatch = value.match(/^(.+) \\(Copy(?: (\\d+))?\\)$/)\n if (copyMatch) {\n const baseName = copyMatch[1]\n const copyNum = copyMatch[2] ? parseInt(copyMatch[2], 10) + 1 : 2\n return `${baseName} (Copy ${copyNum})`\n }\n return `${value} (Copy)`\n },\n ],\n },\n },\n {\n name: 'slug',\n type: 'text',\n required: true,\n unique: true,\n index: true,\n admin: {\n position: 'sidebar',\n description: 'URL path for this page (auto-generated from title)',\n },\n hooks: {\n beforeValidate: [\n ({ data, value }) => {\n if (data && !value && data.title) {\n return (data.title as string)\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n .trim()\n }\n return value\n },\n ],\n beforeDuplicate: [\n ({ value }) => {\n if (!value) return value\n const copyMatch = value.match(/^(.+)-copy(?:-(\\d+))?$/)\n if (copyMatch) {\n const baseName = copyMatch[1]\n const copyNum = copyMatch[2] ? parseInt(copyMatch[2], 10) + 1 : 2\n return `${baseName}-copy-${copyNum}`\n }\n return `${value}-copy`\n },\n ],\n },\n },\n\n // Page Layout\n createPageLayoutField(layouts, true),\n\n // Editor Version\n createEditorVersionField('puck', true),\n\n // Homepage Flag\n isHomepageField,\n\n // Puck Data (hidden - managed via visual editor)\n puckDataField,\n\n // SEO Fields\n seoFieldGroup,\n\n // Conversion Tracking Fields\n conversionFieldGroup,\n\n // Additional fields from options\n ...additionalFields,\n ]\n\n return {\n slug,\n admin: {\n useAsTitle: 'title',\n group: 'Content',\n defaultColumns: ['title', 'slug', '_status', 'updatedAt'],\n ...(collectionOverrides.admin ?? {}),\n },\n access: {\n read: access.read ?? defaultAccess,\n create: access.create ?? defaultAccess,\n update: access.update ?? defaultAccess,\n delete: access.delete ?? defaultAccess,\n ...(collectionOverrides.access ?? {}),\n },\n versions:\n typeof collectionOverrides.versions === 'object'\n ? { drafts: true, ...collectionOverrides.versions }\n : { drafts: true },\n fields: baseFields,\n ...collectionOverrides,\n // Ensure fields aren't overwritten by collectionOverrides\n ...(collectionOverrides.fields && {\n fields: [...baseFields, ...collectionOverrides.fields],\n }),\n }\n}\n\n// Note: puckDataField is now exported from '../fields' for hybrid collection integration\n// Re-export for backwards compatibility\nexport { puckDataField } from '../fields'\n","import type { CollectionConfig } from 'payload'\n\n/**\n * Templates Collection - Stores reusable Puck component configurations\n *\n * This collection stores serialized Puck component data that can be\n * loaded into Template components for reuse across pages.\n */\nexport const TemplatesCollection: CollectionConfig = {\n slug: 'puck-templates',\n admin: {\n useAsTitle: 'name',\n group: 'Puck',\n defaultColumns: ['name', 'category', 'updatedAt'],\n description: 'Reusable component templates for the visual editor',\n },\n access: {\n read: () => true,\n create: ({ req }) => !!req.user,\n update: ({ req }) => !!req.user,\n delete: ({ req }) => !!req.user,\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n required: true,\n admin: {\n description: 'A descriptive name for this template',\n },\n },\n {\n name: 'description',\n type: 'textarea',\n admin: {\n description: 'Optional description of what this template contains',\n },\n },\n {\n name: 'category',\n type: 'text',\n admin: {\n description: 'Category for organizing templates (e.g., \"Hero\", \"Footer\", \"CTA\")',\n },\n },\n {\n name: 'content',\n type: 'json',\n required: true,\n admin: {\n description: 'Serialized Puck component data',\n },\n },\n {\n name: 'thumbnail',\n type: 'text',\n admin: {\n description: 'Optional thumbnail URL for template preview',\n },\n },\n ],\n timestamps: true,\n}\n","import type { CollectionConfig, Config as PayloadConfig, Field, Plugin } from 'payload'\nimport type { PuckPluginOptions, PuckAdminConfig } from '../types'\nimport { generatePagesCollection } from './collections/Pages'\nimport { TemplatesCollection } from '../collections/Templates'\nimport { getPuckFields } from './fields'\n\n/**\n * Get all field names from a collection's fields array (including nested group fields and tabs)\n */\nfunction getExistingFieldNames(fields: Field[]): Set<string> {\n const names = new Set<string>()\n\n function addFieldNames(fieldsToCheck: Field[]) {\n for (const field of fieldsToCheck) {\n // Add the field name if it has one\n if ('name' in field && field.name) {\n names.add(field.name)\n }\n\n // Check nested fields in groups, rows, collapsibles, etc.\n if ('fields' in field && Array.isArray(field.fields)) {\n addFieldNames(field.fields)\n }\n\n // Check fields inside tabs\n if (field.type === 'tabs' && 'tabs' in field && Array.isArray(field.tabs)) {\n for (const tab of field.tabs) {\n if ('fields' in tab && Array.isArray(tab.fields)) {\n addFieldNames(tab.fields)\n }\n }\n }\n }\n }\n\n addFieldNames(fields)\n return names\n}\n\n/**\n * Filter out fields that already exist in the target collection\n */\nfunction filterExistingFields(fieldsToAdd: Field[], existingNames: Set<string>): Field[] {\n return fieldsToAdd.filter((field) => {\n if ('name' in field && field.name) {\n return !existingNames.has(field.name)\n }\n return true // Keep fields without names (like UI fields)\n })\n}\n\n/**\n * Generates the UI field configuration for the Edit with Puck button\n */\nfunction generatePuckEditField(\n collectionSlug: string,\n adminConfig: PuckAdminConfig = {}\n): Field {\n const {\n editorPathPattern = '/pages/{id}/edit',\n buttonLabel = 'Edit with Puck',\n buttonPosition, // undefined = main area (default), 'sidebar' = sidebar\n } = adminConfig\n\n return {\n name: 'puckEdit',\n type: 'ui',\n admin: {\n // Only set position if explicitly specified (sidebar)\n // undefined means main form area in Payload\n ...(buttonPosition && { position: buttonPosition }),\n components: {\n Field: '@delmaredigital/payload-puck/admin/client#EditWithPuckButton',\n Cell: '@delmaredigital/payload-puck/admin/client#EditWithPuckCell',\n },\n custom: {\n collectionSlug,\n editorPathPattern,\n label: buttonLabel,\n },\n },\n }\n}\n\n/**\n * Creates a Payload plugin that integrates Puck visual page builder\n *\n * This plugin:\n * - Generates a Pages collection with puckData field\n * - Adds an \"Edit with Puck\" button in the admin document view\n *\n * The Puck editor itself runs outside of Payload admin. Create your own\n * editor page (e.g., /pages/[id]/edit) using the PuckEditor component.\n *\n * @example\n * ```typescript\n * import { createPuckPlugin } from '@delmaredigital/payload-puck/plugin'\n *\n * export default buildConfig({\n * plugins: [\n * createPuckPlugin({\n * pagesCollection: 'pages',\n * access: {\n * read: () => true,\n * create: ({ req }) => !!req.user,\n * update: ({ req }) => !!req.user,\n * delete: ({ req }) => req.user?.role === 'admin',\n * },\n * admin: {\n * editorPathPattern: '/pages/{id}/edit',\n * buttonLabel: 'Visual Editor',\n * },\n * }),\n * ],\n * })\n * ```\n */\nexport function createPuckPlugin(options: PuckPluginOptions = {}): Plugin {\n const {\n pagesCollection = 'pages',\n autoGenerateCollection = true,\n admin: adminConfig = {},\n } = options\n\n const { addEditButton = true } = adminConfig\n\n return (incomingConfig: PayloadConfig): PayloadConfig => {\n // Generate Pages collection if auto-generate is enabled\n let collections = incomingConfig.collections || []\n\n // Always add the Templates collection if it doesn't exist\n const templatesCollectionExists = collections.some(\n (c) => c.slug === 'puck-templates'\n )\n if (!templatesCollectionExists) {\n collections = [...collections, TemplatesCollection]\n }\n\n if (autoGenerateCollection) {\n // Check if collection already exists\n const existingCollectionIndex = collections.findIndex(\n (c) => c.slug === pagesCollection\n )\n\n // Generate the edit button field if enabled\n const editButtonField = addEditButton\n ? [generatePuckEditField(pagesCollection, adminConfig)]\n : []\n\n if (existingCollectionIndex >= 0) {\n // Collection exists - only add Puck fields that don't already exist\n const existingCollection = collections[existingCollectionIndex]\n const existingFields = existingCollection.fields || []\n const existingFieldNames = getExistingFieldNames(existingFields)\n\n // Get Puck-specific fields (not the full collection with title/slug)\n // This avoids duplicating fields the user may have already defined\n const puckFields = getPuckFields({\n includeSEO: !existingFieldNames.has('meta'),\n includeConversion: !existingFieldNames.has('conversionTracking'),\n includeEditorVersion: !existingFieldNames.has('editorVersion'),\n includePageLayout: !existingFieldNames.has('pageLayout'),\n includeIsHomepage: !existingFieldNames.has('isHomepage'),\n layouts: options.layouts,\n })\n\n // Filter out any remaining duplicates (e.g., puckData if user already has it)\n const fieldsToAdd = filterExistingFields(puckFields, existingFieldNames)\n\n // Only add edit button if puckEdit doesn't exist\n const editFieldsToAdd = existingFieldNames.has('puckEdit') ? [] : editButtonField\n\n collections = [\n ...collections.slice(0, existingCollectionIndex),\n {\n ...existingCollection,\n // Ensure drafts are enabled for Puck\n versions:\n typeof existingCollection.versions === 'object'\n ? { drafts: true, ...existingCollection.versions }\n : existingCollection.versions ?? { drafts: true },\n fields: [\n ...existingFields,\n ...fieldsToAdd,\n ...editFieldsToAdd,\n ],\n },\n ...collections.slice(existingCollectionIndex + 1),\n ]\n } else {\n // Add new collection with edit button field\n const generatedCollection = generatePagesCollection(pagesCollection, options)\n collections = [\n ...collections,\n {\n ...generatedCollection,\n fields: [...generatedCollection.fields, ...editButtonField],\n },\n ]\n }\n }\n\n return {\n ...incomingConfig,\n collections,\n onInit: async (payload) => {\n // Call existing onInit if present\n if (incomingConfig.onInit) {\n await incomingConfig.onInit(payload)\n }\n },\n }\n }\n}\n\n// Re-export collection utilities\nexport { generatePagesCollection } from './collections/Pages'\nexport { TemplatesCollection } from '../collections/Templates'\n\n// Re-export field utilities for hybrid collection integration\nexport {\n getPuckFields,\n puckDataField,\n editorVersionField,\n createEditorVersionField,\n pageLayoutField,\n createPageLayoutField,\n isHomepageField,\n seoFieldGroup,\n conversionFieldGroup,\n} from './fields'\n\n// Export the edit button generator for hybrid collections\nexport { generatePuckEditField }\n\n// Re-export types\nexport type { PuckPluginOptions, PuckAdminConfig } from '../types'\nexport type { GetPuckFieldsOptions } from './fields/types'\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/layouts/defaults.ts","../../src/layouts/utils.ts","../../src/plugin/fields/index.ts","../../src/plugin/collections/Pages.ts","../../src/collections/Templates.ts","../../src/plugin/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Default Layout Definitions\n *\n * These provide sensible defaults for common page layout patterns.\n * Users can override or extend these in their own configuration.\n */\n\nimport type { LayoutDefinition, LayoutConfig } from './types'\n\n/**\n * Default layout - standard content width with padding\n */\nexport const defaultLayout: LayoutDefinition = {\n value: 'default',\n label: 'Default',\n description: 'Standard page layout with contained content width',\n classes: {\n wrapper: '',\n container: 'mx-auto px-4 sm:px-6 lg:px-8',\n content: '',\n },\n maxWidth: '1200px',\n fullWidth: false,\n}\n\n/**\n * Landing layout - optimized for marketing/landing pages\n */\nexport const landingLayout: LayoutDefinition = {\n value: 'landing',\n label: 'Landing',\n description: 'Full-width sections with no global container constraints',\n classes: {\n wrapper: '',\n container: '',\n content: '',\n },\n fullWidth: true,\n}\n\n/**\n * Full width layout - edge-to-edge content\n */\nexport const fullWidthLayout: LayoutDefinition = {\n value: 'full-width',\n label: 'Full Width',\n description: 'Content spans the full viewport width',\n classes: {\n wrapper: 'w-full',\n container: 'w-full',\n content: '',\n },\n maxWidth: '100%',\n fullWidth: true,\n}\n\n/**\n * Narrow layout - ideal for blog posts and articles\n */\nexport const narrowLayout: LayoutDefinition = {\n value: 'narrow',\n label: 'Narrow',\n description: 'Narrow content width for optimal reading experience',\n classes: {\n wrapper: '',\n container: 'mx-auto px-4 sm:px-6',\n content: '',\n },\n maxWidth: '768px',\n fullWidth: false,\n}\n\n/**\n * Wide layout - extra wide content area\n */\nexport const wideLayout: LayoutDefinition = {\n value: 'wide',\n label: 'Wide',\n description: 'Wider content area for dashboards or galleries',\n classes: {\n wrapper: '',\n container: 'mx-auto px-4 sm:px-6 lg:px-8',\n content: '',\n },\n maxWidth: '1440px',\n fullWidth: false,\n}\n\n/**\n * Default layouts included with the plugin\n */\nexport const DEFAULT_LAYOUTS: LayoutDefinition[] = [\n defaultLayout,\n landingLayout,\n fullWidthLayout,\n]\n\n/**\n * Extended layouts for users who want more options\n */\nexport const EXTENDED_LAYOUTS: LayoutDefinition[] = [\n defaultLayout,\n landingLayout,\n fullWidthLayout,\n narrowLayout,\n wideLayout,\n]\n\n/**\n * Default layout configuration\n */\nexport const DEFAULT_LAYOUT_CONFIG: LayoutConfig = {\n layouts: DEFAULT_LAYOUTS,\n defaultLayout: 'default',\n}\n","/**\n * Layout Utilities\n *\n * Functions for working with layout configurations.\n */\n\nimport type { LayoutDefinition, LayoutConfig, LayoutOption } from './types'\nimport { DEFAULT_LAYOUTS, DEFAULT_LAYOUT_CONFIG } from './defaults'\n\n/**\n * Resolves a layout config, merging with defaults if needed\n */\nexport function resolveLayoutConfig(config?: Partial<LayoutConfig>): LayoutConfig {\n if (!config) return DEFAULT_LAYOUT_CONFIG\n\n return {\n layouts: config.layouts ?? DEFAULT_LAYOUTS,\n defaultLayout: config.defaultLayout ?? 'default',\n }\n}\n\n/**\n * Gets a layout definition by value\n */\nexport function getLayout(\n layouts: LayoutDefinition[],\n value: string,\n fallback = 'default'\n): LayoutDefinition | undefined {\n const layout = layouts.find((l) => l.value === value)\n if (layout) return layout\n\n // Try fallback\n if (value !== fallback) {\n return layouts.find((l) => l.value === fallback)\n }\n\n // Return first layout if nothing matches\n return layouts[0]\n}\n\n/**\n * Converts layout definitions to Puck select options\n */\nexport function layoutsToOptions(layouts: LayoutDefinition[]): LayoutOption[] {\n return layouts.map(({ value, label, description }) => ({\n value,\n label,\n description,\n }))\n}\n\n/**\n * Converts layout definitions to Payload select options\n */\nexport function layoutsToPayloadOptions(\n layouts: LayoutDefinition[]\n): Array<{ label: string; value: string }> {\n return layouts.map(({ value, label }) => ({\n label,\n value,\n }))\n}\n\n/**\n * Creates a custom layout definition\n */\nexport function createLayout(\n config: Omit<LayoutDefinition, 'value' | 'label'> & {\n value: string\n label: string\n }\n): LayoutDefinition {\n return {\n ...config,\n }\n}\n\n/**\n * Merges layout configurations\n */\nexport function mergeLayouts(\n base: LayoutDefinition[],\n custom: LayoutDefinition[],\n options?: {\n /** Replace base layouts instead of merging */\n replace?: boolean\n /** Exclude these layout values from base */\n exclude?: string[]\n }\n): LayoutDefinition[] {\n if (options?.replace) {\n return custom\n }\n\n let result = [...base]\n\n // Exclude specified layouts\n if (options?.exclude) {\n result = result.filter((l) => !options.exclude!.includes(l.value))\n }\n\n // Merge/override with custom layouts\n for (const customLayout of custom) {\n const existingIndex = result.findIndex((l) => l.value === customLayout.value)\n if (existingIndex >= 0) {\n result[existingIndex] = customLayout\n } else {\n result.push(customLayout)\n }\n }\n\n return result\n}\n","/**\n * Puck Field Utilities\n *\n * Provides reusable field definitions for adding Puck support to existing collections.\n * Use getPuckFields() for easy integration, or import individual fields for granular control.\n *\n * @example\n * ```typescript\n * // Option 1: Use getPuckFields() for recommended defaults\n * import { getPuckFields } from '@delmaredigital/payload-puck'\n *\n * const Pages: CollectionConfig = {\n * slug: 'pages',\n * fields: [\n * // Your existing fields...\n * ...getPuckFields({ includeSEO: false }),\n * ],\n * }\n *\n * // Option 2: Import individual fields\n * import { puckDataField, editorVersionField } from '@delmaredigital/payload-puck'\n *\n * const Pages: CollectionConfig = {\n * slug: 'pages',\n * fields: [\n * // Your existing fields...\n * puckDataField,\n * editorVersionField,\n * ],\n * }\n * ```\n */\n\nimport type { Field } from 'payload'\nimport type { GetPuckFieldsOptions, ConversionTypeOption } from './types'\nimport type { LayoutDefinition } from '../../layouts/types'\nimport { DEFAULT_LAYOUTS } from '../../layouts/defaults'\nimport { layoutsToPayloadOptions } from '../../layouts/utils'\n\n// =============================================================================\n// Core Fields\n// =============================================================================\n\n/**\n * Puck data field - stores the visual editor JSON data.\n * This field is always hidden in the admin UI as it's managed via the visual editor.\n */\nexport const puckDataField: Field = {\n name: 'puckData',\n type: 'json',\n admin: {\n hidden: true,\n description: 'Puck editor data - managed via visual editor',\n },\n}\n\n/**\n * Creates an editor version field with smart detection for hybrid setups.\n *\n * The field uses a beforeValidate hook to intelligently determine the editor version:\n * - New pages: Default to 'puck' (or custom defaultValue)\n * - Existing pages with legacy blocks but no puckData: Set to 'legacy'\n * - Existing pages with puckData: Set to 'puck'\n *\n * This prevents existing legacy content from being incorrectly marked as 'puck'\n * when the field is first added to a collection.\n *\n * @param defaultValue - The default editor version for NEW pages ('puck' or 'legacy')\n * @param sidebar - Whether to position in the sidebar (default: true)\n * @param legacyBlocksFieldName - Name of the legacy blocks field to check (default: 'layout')\n */\nexport function createEditorVersionField(\n defaultValue: 'legacy' | 'puck' = 'puck',\n sidebar: boolean = true,\n legacyBlocksFieldName: string = 'layout'\n): Field {\n return {\n name: 'editorVersion',\n type: 'select',\n // NO defaultValue here - we use the hook to intelligently detect the value\n // This prevents migrations from blindly setting 'puck' on legacy pages\n options: [\n { label: 'Legacy (Payload Blocks)', value: 'legacy' },\n { label: 'Puck Visual Editor', value: 'puck' },\n ],\n admin: {\n position: sidebar ? 'sidebar' : undefined,\n description: 'Which editor was used to create this page',\n },\n hooks: {\n beforeValidate: [\n ({ value, data, operation }) => {\n // If value is explicitly set (and not null/undefined), keep it\n if (value) return value\n\n // Detect based on content - works for both new and existing documents\n const legacyBlocks = data?.[legacyBlocksFieldName]\n const hasLegacyBlocks = Array.isArray(legacyBlocks) && legacyBlocks.length > 0\n\n const puckData = data?.puckData as { content?: unknown[] } | null | undefined\n const hasPuckData =\n puckData?.content && Array.isArray(puckData.content) && puckData.content.length > 0\n\n // If has legacy blocks but no puck data, it's a legacy page\n if (hasLegacyBlocks && !hasPuckData) {\n return 'legacy'\n }\n\n // If has puck data, it's a puck page\n if (hasPuckData) {\n return 'puck'\n }\n\n // For new documents with no content yet, use configured default\n // For existing documents with no content, also use default\n return defaultValue\n },\n ],\n },\n }\n}\n\n/**\n * Pre-configured editor version field with 'puck' as default.\n * Use createEditorVersionField() for custom configuration.\n */\nexport const editorVersionField: Field = createEditorVersionField('puck', true)\n\n/**\n * Creates a page layout field with custom layouts.\n *\n * @param layouts - Array of layout definitions (defaults to DEFAULT_LAYOUTS)\n * @param sidebar - Whether to position in the sidebar (default: true)\n */\nexport function createPageLayoutField(\n layouts: LayoutDefinition[] = DEFAULT_LAYOUTS,\n sidebar: boolean = true\n): Field {\n return {\n name: 'pageLayout',\n type: 'select',\n required: true,\n defaultValue: 'default',\n options: layoutsToPayloadOptions(layouts),\n admin: {\n position: sidebar ? 'sidebar' : undefined,\n description: 'Overall page structure and layout style',\n },\n }\n}\n\n/**\n * Pre-configured page layout field with DEFAULT_LAYOUTS.\n * Use createPageLayoutField() for custom layouts.\n */\nexport const pageLayoutField: Field = createPageLayoutField()\n\n/**\n * Homepage flag field - marks a page as the site homepage.\n */\nexport const isHomepageField: Field = {\n name: 'isHomepage',\n type: 'checkbox',\n defaultValue: false,\n admin: {\n position: 'sidebar',\n description: 'Mark this page as the homepage',\n },\n}\n\n// =============================================================================\n// Field Groups\n// =============================================================================\n\n/**\n * SEO/Meta field group with all metadata fields.\n * Uses the official @payloadcms/plugin-seo convention: meta.title, meta.description\n *\n * Includes: title, description, image, noindex, nofollow, excludeFromSitemap\n */\nexport const seoFieldGroup: Field = {\n name: 'meta',\n type: 'group',\n label: 'SEO',\n admin: {\n position: 'sidebar',\n },\n fields: [\n {\n name: 'title',\n type: 'text',\n label: 'Meta Title',\n admin: {\n description: 'Override the page title for search engines',\n },\n },\n {\n name: 'description',\n type: 'textarea',\n label: 'Meta Description',\n admin: {\n description: 'Description shown in search engine results',\n },\n },\n {\n name: 'image',\n type: 'upload',\n relationTo: 'media',\n label: 'Open Graph Image',\n admin: {\n description: 'Image shown when sharing on social media',\n },\n },\n {\n name: 'noindex',\n type: 'checkbox',\n label: 'No Index',\n defaultValue: false,\n admin: {\n description: 'Prevent search engines from indexing this page',\n },\n },\n {\n name: 'nofollow',\n type: 'checkbox',\n label: 'No Follow',\n defaultValue: false,\n admin: {\n description: 'Prevent search engines from following links on this page',\n },\n },\n {\n name: 'excludeFromSitemap',\n type: 'checkbox',\n label: 'Exclude from Sitemap',\n defaultValue: false,\n admin: {\n description: 'Exclude this page from the XML sitemap',\n },\n },\n ],\n}\n\n/**\n * Default conversion type options\n */\nexport const DEFAULT_CONVERSION_TYPES: ConversionTypeOption[] = [\n { label: 'Lead', value: 'lead' },\n { label: 'Registration', value: 'registration' },\n { label: 'Purchase', value: 'purchase' },\n { label: 'Donation', value: 'donation' },\n { label: 'Newsletter Signup', value: 'newsletter' },\n { label: 'Contact Form', value: 'contact' },\n { label: 'Custom', value: 'custom' },\n]\n\n/**\n * Creates a conversion tracking field group with custom options.\n *\n * @param conversionTypes - Custom conversion type options (defaults to DEFAULT_CONVERSION_TYPES)\n * @param sidebar - Whether to position in the sidebar (default: true)\n *\n * @example\n * ```typescript\n * // Use default conversion types\n * ...getPuckFields({ includeConversion: true })\n *\n * // Use custom conversion types\n * ...getPuckFields({\n * includeConversion: true,\n * conversionTypeOptions: [\n * { label: 'Registration', value: 'registration' },\n * { label: 'Donation', value: 'donation' },\n * { label: 'Course Start', value: 'course_start' },\n * { label: 'Custom', value: 'custom' },\n * ],\n * })\n * ```\n */\nexport function createConversionFieldGroup(\n conversionTypes: ConversionTypeOption[] = DEFAULT_CONVERSION_TYPES,\n sidebar: boolean = true\n): Field {\n return {\n name: 'conversionTracking',\n type: 'group',\n label: 'Conversion Tracking',\n admin: {\n position: sidebar ? 'sidebar' : undefined,\n description: 'Configure conversion tracking for analytics',\n },\n fields: [\n {\n name: 'isConversionPage',\n type: 'checkbox',\n label: 'Is Conversion Page',\n defaultValue: false,\n admin: {\n description:\n 'Check this if this page represents a completed conversion (e.g., thank you page)',\n },\n },\n {\n name: 'conversionType',\n type: 'select',\n label: 'Conversion Type',\n options: conversionTypes,\n admin: {\n description: 'Type of conversion this page represents',\n condition: (data, siblingData) => siblingData?.isConversionPage === true,\n },\n },\n {\n name: 'conversionValue',\n type: 'number',\n label: 'Conversion Value',\n defaultValue: 0,\n admin: {\n description: 'Monetary value of this conversion (0 for non-monetary conversions)',\n condition: (data, siblingData) => siblingData?.isConversionPage === true,\n },\n },\n ],\n }\n}\n\n/**\n * Pre-configured conversion tracking field group with default options.\n * Use createConversionFieldGroup() for custom conversion types.\n */\nexport const conversionFieldGroup: Field = createConversionFieldGroup()\n\n// =============================================================================\n// Main Utility Function\n// =============================================================================\n\n/**\n * Returns an array of Puck-related field definitions for hybrid collection integration.\n *\n * Use this when you have an existing collection with legacy Payload blocks and want\n * to ADD Puck support without replacing your entire collection configuration.\n *\n * @param options - Configuration options for which fields to include\n * @returns Array of Field definitions to spread into your collection's fields array\n *\n * @example\n * ```typescript\n * import { getPuckFields } from '@delmaredigital/payload-puck'\n *\n * export const Pages: CollectionConfig = {\n * slug: 'pages',\n * fields: [\n * // Your existing fields\n * { name: 'title', type: 'text', required: true },\n * { name: 'slug', type: 'text', required: true },\n *\n * // Legacy Payload blocks (keep these!)\n * { name: 'layout', type: 'blocks', blocks: [...] },\n *\n * // Add Puck fields for hybrid editing\n * ...getPuckFields({\n * includeSEO: false, // You have your own SEO fields\n * includeConversion: true, // Include conversion tracking\n * includeEditorVersion: true,\n * }),\n * ],\n * }\n * ```\n */\nexport function getPuckFields(options: GetPuckFieldsOptions = {}): Field[] {\n const {\n includeSEO = true,\n includeConversion = false,\n includeEditorVersion = true,\n includePageLayout = true,\n includeIsHomepage = false,\n layouts = DEFAULT_LAYOUTS,\n defaultEditorVersion = 'puck',\n legacyBlocksFieldName = 'layout',\n sidebarPosition = true,\n conversionTypeOptions,\n } = options\n\n const fields: Field[] = []\n\n // Core puckData field (always included - this is essential for Puck)\n fields.push(puckDataField)\n\n // Editor version field (discriminator for hybrid rendering)\n // Uses smart detection to preserve legacy pages when field is first added\n if (includeEditorVersion) {\n fields.push(createEditorVersionField(defaultEditorVersion, sidebarPosition, legacyBlocksFieldName))\n }\n\n // Page layout field\n if (includePageLayout) {\n fields.push(createPageLayoutField(layouts, sidebarPosition))\n }\n\n // Homepage flag\n if (includeIsHomepage) {\n fields.push(isHomepageField)\n }\n\n // SEO group\n if (includeSEO) {\n fields.push(seoFieldGroup)\n }\n\n // Conversion tracking group (with optional custom conversion types)\n if (includeConversion) {\n fields.push(createConversionFieldGroup(conversionTypeOptions, sidebarPosition))\n }\n\n return fields\n}\n\n// Re-export types\nexport type { GetPuckFieldsOptions, ConversionTypeOption } from './types'\n","import type { Access, CollectionConfig, Field } from 'payload'\nimport type { PuckPluginOptions } from '../../types'\nimport { DEFAULT_LAYOUTS } from '../../layouts/defaults'\nimport { layoutsToPayloadOptions } from '../../layouts/utils'\nimport {\n puckDataField,\n createEditorVersionField,\n createPageLayoutField,\n isHomepageField,\n seoFieldGroup,\n conversionFieldGroup,\n} from '../fields'\n\n/**\n * Default access function - allows all\n */\nconst defaultAccess: Access = () => true\n\n/**\n * Generates a Pages collection configuration for Puck\n */\nexport function generatePagesCollection(\n slug: string,\n options: PuckPluginOptions\n): CollectionConfig {\n const {\n collectionOverrides = {},\n access = {},\n layouts = DEFAULT_LAYOUTS,\n additionalFields = [],\n } = options\n\n const baseFields: Field[] = [\n // Core Fields (title and slug with duplication hooks - unique to collection generation)\n {\n name: 'title',\n type: 'text',\n required: true,\n hooks: {\n beforeDuplicate: [\n ({ value }) => {\n if (!value) return value\n const copyMatch = value.match(/^(.+) \\(Copy(?: (\\d+))?\\)$/)\n if (copyMatch) {\n const baseName = copyMatch[1]\n const copyNum = copyMatch[2] ? parseInt(copyMatch[2], 10) + 1 : 2\n return `${baseName} (Copy ${copyNum})`\n }\n return `${value} (Copy)`\n },\n ],\n },\n },\n {\n name: 'slug',\n type: 'text',\n required: true,\n unique: true,\n index: true,\n admin: {\n position: 'sidebar',\n description: 'URL path for this page (auto-generated from title)',\n },\n hooks: {\n beforeValidate: [\n ({ data, value }) => {\n if (data && !value && data.title) {\n return (data.title as string)\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n .trim()\n }\n return value\n },\n ],\n beforeDuplicate: [\n ({ value }) => {\n if (!value) return value\n const copyMatch = value.match(/^(.+)-copy(?:-(\\d+))?$/)\n if (copyMatch) {\n const baseName = copyMatch[1]\n const copyNum = copyMatch[2] ? parseInt(copyMatch[2], 10) + 1 : 2\n return `${baseName}-copy-${copyNum}`\n }\n return `${value}-copy`\n },\n ],\n },\n },\n\n // Page Layout\n createPageLayoutField(layouts, true),\n\n // Editor Version\n createEditorVersionField('puck', true),\n\n // Homepage Flag\n isHomepageField,\n\n // Puck Data (hidden - managed via visual editor)\n puckDataField,\n\n // SEO Fields\n seoFieldGroup,\n\n // Conversion Tracking Fields\n conversionFieldGroup,\n\n // Additional fields from options\n ...additionalFields,\n ]\n\n return {\n slug,\n admin: {\n useAsTitle: 'title',\n group: 'Content',\n defaultColumns: ['title', 'slug', '_status', 'updatedAt'],\n ...(collectionOverrides.admin ?? {}),\n },\n access: {\n read: access.read ?? defaultAccess,\n create: access.create ?? defaultAccess,\n update: access.update ?? defaultAccess,\n delete: access.delete ?? defaultAccess,\n ...(collectionOverrides.access ?? {}),\n },\n versions:\n typeof collectionOverrides.versions === 'object'\n ? { drafts: true, ...collectionOverrides.versions }\n : { drafts: true },\n fields: baseFields,\n ...collectionOverrides,\n // Ensure fields aren't overwritten by collectionOverrides\n ...(collectionOverrides.fields && {\n fields: [...baseFields, ...collectionOverrides.fields],\n }),\n }\n}\n\n// Note: puckDataField is now exported from '../fields' for hybrid collection integration\n// Re-export for backwards compatibility\nexport { puckDataField } from '../fields'\n","import type { CollectionConfig } from 'payload'\n\n/**\n * Templates Collection - Stores reusable Puck component configurations\n *\n * This collection stores serialized Puck component data that can be\n * loaded into Template components for reuse across pages.\n */\nexport const TemplatesCollection: CollectionConfig = {\n slug: 'puck-templates',\n admin: {\n useAsTitle: 'name',\n group: 'Puck',\n defaultColumns: ['name', 'category', 'updatedAt'],\n description: 'Reusable component templates for the visual editor',\n },\n access: {\n read: () => true,\n create: ({ req }) => !!req.user,\n update: ({ req }) => !!req.user,\n delete: ({ req }) => !!req.user,\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n required: true,\n admin: {\n description: 'A descriptive name for this template',\n },\n },\n {\n name: 'description',\n type: 'textarea',\n admin: {\n description: 'Optional description of what this template contains',\n },\n },\n {\n name: 'category',\n type: 'text',\n admin: {\n description: 'Category for organizing templates (e.g., \"Hero\", \"Footer\", \"CTA\")',\n },\n },\n {\n name: 'content',\n type: 'json',\n required: true,\n admin: {\n description: 'Serialized Puck component data',\n },\n },\n {\n name: 'thumbnail',\n type: 'text',\n admin: {\n description: 'Optional thumbnail URL for template preview',\n },\n },\n ],\n timestamps: true,\n}\n","import type { CollectionConfig, Config as PayloadConfig, Field, Plugin } from 'payload'\nimport type { PuckPluginOptions, PuckAdminConfig } from '../types'\nimport { generatePagesCollection } from './collections/Pages'\nimport { TemplatesCollection } from '../collections/Templates'\nimport { getPuckFields } from './fields'\n\n/**\n * Get all field names from a collection's fields array (including nested group fields and tabs)\n */\nfunction getExistingFieldNames(fields: Field[]): Set<string> {\n const names = new Set<string>()\n\n function addFieldNames(fieldsToCheck: Field[]) {\n for (const field of fieldsToCheck) {\n // Add the field name if it has one\n if ('name' in field && field.name) {\n names.add(field.name)\n }\n\n // Check nested fields in groups, rows, collapsibles, etc.\n if ('fields' in field && Array.isArray(field.fields)) {\n addFieldNames(field.fields)\n }\n\n // Check fields inside tabs\n if (field.type === 'tabs' && 'tabs' in field && Array.isArray(field.tabs)) {\n for (const tab of field.tabs) {\n if ('fields' in tab && Array.isArray(tab.fields)) {\n addFieldNames(tab.fields)\n }\n }\n }\n }\n }\n\n addFieldNames(fields)\n return names\n}\n\n/**\n * Filter out fields that already exist in the target collection\n */\nfunction filterExistingFields(fieldsToAdd: Field[], existingNames: Set<string>): Field[] {\n return fieldsToAdd.filter((field) => {\n if ('name' in field && field.name) {\n return !existingNames.has(field.name)\n }\n return true // Keep fields without names (like UI fields)\n })\n}\n\n/**\n * Generates the UI field configuration for the Edit with Puck button\n */\nfunction generatePuckEditField(\n collectionSlug: string,\n adminConfig: PuckAdminConfig = {}\n): Field {\n const {\n editorPathPattern = '/pages/{id}/edit',\n buttonLabel = 'Edit with Puck',\n buttonPosition, // undefined = main area (default), 'sidebar' = sidebar\n } = adminConfig\n\n return {\n name: 'puckEdit',\n type: 'ui',\n admin: {\n // Only set position if explicitly specified (sidebar)\n // undefined means main form area in Payload\n ...(buttonPosition && { position: buttonPosition }),\n components: {\n Field: '@delmaredigital/payload-puck/admin/client#EditWithPuckButton',\n Cell: '@delmaredigital/payload-puck/admin/client#EditWithPuckCell',\n },\n custom: {\n collectionSlug,\n editorPathPattern,\n label: buttonLabel,\n },\n },\n }\n}\n\n/**\n * Creates a Payload plugin that integrates Puck visual page builder\n *\n * This plugin:\n * - Generates a Pages collection with puckData field\n * - Adds an \"Edit with Puck\" button in the admin document view\n *\n * The Puck editor itself runs outside of Payload admin. Create your own\n * editor page (e.g., /pages/[id]/edit) using the PuckEditor component.\n *\n * @example\n * ```typescript\n * import { createPuckPlugin } from '@delmaredigital/payload-puck/plugin'\n *\n * export default buildConfig({\n * plugins: [\n * createPuckPlugin({\n * pagesCollection: 'pages',\n * access: {\n * read: () => true,\n * create: ({ req }) => !!req.user,\n * update: ({ req }) => !!req.user,\n * delete: ({ req }) => req.user?.role === 'admin',\n * },\n * admin: {\n * editorPathPattern: '/pages/{id}/edit',\n * buttonLabel: 'Visual Editor',\n * },\n * }),\n * ],\n * })\n * ```\n */\nexport function createPuckPlugin(options: PuckPluginOptions = {}): Plugin {\n const {\n pagesCollection = 'pages',\n autoGenerateCollection = true,\n admin: adminConfig = {},\n } = options\n\n const { addEditButton = true } = adminConfig\n\n return (incomingConfig: PayloadConfig): PayloadConfig => {\n // Generate Pages collection if auto-generate is enabled\n let collections = incomingConfig.collections || []\n\n // Always add the Templates collection if it doesn't exist\n const templatesCollectionExists = collections.some(\n (c) => c.slug === 'puck-templates'\n )\n if (!templatesCollectionExists) {\n collections = [...collections, TemplatesCollection]\n }\n\n if (autoGenerateCollection) {\n // Check if collection already exists\n const existingCollectionIndex = collections.findIndex(\n (c) => c.slug === pagesCollection\n )\n\n // Generate the edit button field if enabled\n const editButtonField = addEditButton\n ? [generatePuckEditField(pagesCollection, adminConfig)]\n : []\n\n if (existingCollectionIndex >= 0) {\n // Collection exists - only add Puck fields that don't already exist\n const existingCollection = collections[existingCollectionIndex]\n const existingFields = existingCollection.fields || []\n const existingFieldNames = getExistingFieldNames(existingFields)\n\n // Get Puck-specific fields (not the full collection with title/slug)\n // This avoids duplicating fields the user may have already defined\n const puckFields = getPuckFields({\n includeSEO: !existingFieldNames.has('meta'),\n includeConversion: !existingFieldNames.has('conversionTracking'),\n includeEditorVersion: !existingFieldNames.has('editorVersion'),\n includePageLayout: !existingFieldNames.has('pageLayout'),\n includeIsHomepage: !existingFieldNames.has('isHomepage'),\n layouts: options.layouts,\n })\n\n // Filter out any remaining duplicates (e.g., puckData if user already has it)\n const fieldsToAdd = filterExistingFields(puckFields, existingFieldNames)\n\n // Only add edit button if puckEdit doesn't exist\n const editFieldsToAdd = existingFieldNames.has('puckEdit') ? [] : editButtonField\n\n collections = [\n ...collections.slice(0, existingCollectionIndex),\n {\n ...existingCollection,\n // Ensure drafts are enabled for Puck\n versions:\n typeof existingCollection.versions === 'object'\n ? { drafts: true, ...existingCollection.versions }\n : existingCollection.versions ?? { drafts: true },\n fields: [\n ...existingFields,\n ...fieldsToAdd,\n ...editFieldsToAdd,\n ],\n },\n ...collections.slice(existingCollectionIndex + 1),\n ]\n } else {\n // Add new collection with edit button field\n const generatedCollection = generatePagesCollection(pagesCollection, options)\n collections = [\n ...collections,\n {\n ...generatedCollection,\n fields: [...generatedCollection.fields, ...editButtonField],\n },\n ]\n }\n }\n\n return {\n ...incomingConfig,\n collections,\n onInit: async (payload) => {\n // Call existing onInit if present\n if (incomingConfig.onInit) {\n await incomingConfig.onInit(payload)\n }\n },\n }\n }\n}\n\n// Re-export collection utilities\nexport { generatePagesCollection } from './collections/Pages'\nexport { TemplatesCollection } from '../collections/Templates'\n\n// Re-export field utilities for hybrid collection integration\nexport {\n getPuckFields,\n puckDataField,\n editorVersionField,\n createEditorVersionField,\n pageLayoutField,\n createPageLayoutField,\n isHomepageField,\n seoFieldGroup,\n conversionFieldGroup,\n} from './fields'\n\n// Export the edit button generator for hybrid collections\nexport { generatePuckEditField }\n\n// Re-export types\nexport type { PuckPluginOptions, PuckAdminConfig } from '../types'\nexport type { GetPuckFieldsOptions } from './fields/types'\n"]}