slice-machine-ui 2.2.2-beta.1 → 2.2.2-beta.10

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 (107) hide show
  1. package/next.config.mjs +11 -1
  2. package/out/404.html +1 -1
  3. package/out/_next/static/75dY8fp3JqJwdHRXfu9LV/_buildManifest.js +1 -0
  4. package/out/_next/static/chunks/18539003-7b839478e0b5720a.js +22 -0
  5. package/out/_next/static/chunks/{66-d37d30551288858b.js → 210-565d01ee9777d1a1.js} +2 -2
  6. package/out/_next/static/chunks/{212-cbaa35389c0aacf1.js → 212-b6a2b8d9d16ef3c5.js} +1 -1
  7. package/out/_next/static/chunks/448-a0de8b21d55d4da3.js +1 -0
  8. package/out/_next/static/chunks/{465-47a6d2a5f66f521e.js → 465-d5dd75edd8e6bb65.js} +1 -1
  9. package/out/_next/static/chunks/574-319271e279f042bc.js +1 -0
  10. package/out/_next/static/chunks/59b4e022-8e544a511d670317.js +1 -0
  11. package/out/_next/static/chunks/695-603bd96af31f4302.js +12 -0
  12. package/out/_next/static/chunks/{816-68d4db26c0adab2e.js → 816-17afd84d2642f4c4.js} +1 -1
  13. package/out/_next/static/chunks/f36c6662-1f3a854183168b10.js +1 -0
  14. package/out/_next/static/chunks/pages/_app-d25e4ad1db4fc327.js +544 -0
  15. package/out/_next/static/chunks/pages/{changelog-d309ea186a0e56bf.js → changelog-1d15a7ef498f499a.js} +1 -1
  16. package/out/_next/static/chunks/pages/{changes-1bb1a7b784a22151.js → changes-0af2a1a5244418f9.js} +1 -1
  17. package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-74be2c0ac9c854c7.js → [customTypeId]-a6ff1618238b3510.js} +1 -1
  18. package/out/_next/static/chunks/pages/{index-785a0ab6e2a4fc27.js → index-2610e550d79c5bb1.js} +1 -1
  19. package/out/_next/static/chunks/pages/{labs-2e4f3a5f68e65b93.js → labs-240ba57bfdabe998.js} +1 -1
  20. package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-d35c87b9aaec445a.js → [pageTypeId]-c300f963db847451.js} +1 -1
  21. package/out/_next/static/chunks/pages/{settings-25eb02893ed871b7.js → settings-039476a9a63d25a1.js} +1 -1
  22. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/{simulator-b47a72d5e94bd946.js → simulator-cfc19e3e799745bb.js} +1 -1
  23. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-58e6cb0f278ea03c.js +1 -0
  24. package/out/_next/static/chunks/pages/{slices-cc44eeccd58d23a9.js → slices-9894ce968d74baf6.js} +1 -1
  25. package/out/_next/static/css/82c8c4f05b25d3af.css +1 -0
  26. package/out/changelog.html +1 -1
  27. package/out/changes.html +1 -1
  28. package/out/custom-types/[customTypeId].html +1 -1
  29. package/out/custom-types.html +1 -1
  30. package/out/index.html +1 -1
  31. package/out/labs.html +1 -1
  32. package/out/page-types/[pageTypeId].html +1 -1
  33. package/out/settings.html +1 -1
  34. package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
  35. package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
  36. package/out/slices.html +1 -1
  37. package/package.json +11 -10
  38. package/src/domain/fields.ts +223 -0
  39. package/src/features/builder/AddFieldDropdown.tsx +119 -0
  40. package/src/features/onboarding/OnboardingGuide.tsx +45 -0
  41. package/src/features/onboarding/OnboardingProgressStepper.tsx +71 -0
  42. package/src/features/onboarding/OnboardingProvider.tsx +82 -0
  43. package/src/features/onboarding/OnboardingStepDialog/OnboardingStepDialog.tsx +46 -0
  44. package/src/features/onboarding/OnboardingStepDialog/OnboardingStepDialogContent.tsx +38 -0
  45. package/src/features/onboarding/OnboardingStepDialog/index.ts +1 -0
  46. package/src/features/onboarding/content.tsx +115 -0
  47. package/src/features/onboarding/types.ts +32 -0
  48. package/src/features/onboarding/useOnboardingExperiment.ts +6 -0
  49. package/src/hooks/useNestedGroupExperiment.ts +8 -0
  50. package/src/hooks/usePersistedState.ts +20 -3
  51. package/src/legacy/components/ListItem/index.tsx +1 -1
  52. package/src/legacy/components/Navigation/index.tsx +2 -0
  53. package/src/legacy/lib/builders/CustomTypeBuilder/TabZone/index.tsx +22 -4
  54. package/src/legacy/lib/builders/SliceBuilder/FieldZones/index.tsx +23 -8
  55. package/src/legacy/lib/builders/SliceBuilder/VariationsList/index.tsx +5 -2
  56. package/src/legacy/lib/builders/SliceBuilder/index.tsx +1 -1
  57. package/src/legacy/lib/builders/common/EditModal/index.jsx +1 -1
  58. package/src/legacy/lib/builders/common/Zone/Card/components/Hints/index.tsx +8 -1
  59. package/src/legacy/lib/builders/common/Zone/Card/components/NewField.tsx +1 -1
  60. package/src/legacy/lib/builders/common/Zone/Card/index.jsx +3 -1
  61. package/src/legacy/lib/builders/common/Zone/components/ZoneEmptyState/ZoneEmptyState.tsx +4 -13
  62. package/src/legacy/lib/builders/common/Zone/index.jsx +26 -31
  63. package/src/legacy/lib/builders/utils/index.ts +8 -0
  64. package/src/legacy/lib/models/common/Group.ts +51 -28
  65. package/src/legacy/lib/models/common/widgets/Boolean/index.ts +2 -4
  66. package/src/legacy/lib/models/common/widgets/Color/index.ts +2 -4
  67. package/src/legacy/lib/models/common/widgets/ContentRelationship/index.ts +0 -2
  68. package/src/legacy/lib/models/common/widgets/Date/index.ts +0 -2
  69. package/src/legacy/lib/models/common/widgets/Embed/index.ts +2 -4
  70. package/src/legacy/lib/models/common/widgets/GeoPoint/index.ts +2 -4
  71. package/src/legacy/lib/models/common/widgets/Group/ListItem/index.jsx +46 -26
  72. package/src/legacy/lib/models/common/widgets/Group/createGroupWidget.ts +81 -0
  73. package/src/legacy/lib/models/common/widgets/Group/index.tsx +72 -0
  74. package/src/legacy/lib/models/common/widgets/Image/index.ts +2 -4
  75. package/src/legacy/lib/models/common/widgets/Link/index.ts +2 -4
  76. package/src/legacy/lib/models/common/widgets/LinkToMedia/index.ts +2 -4
  77. package/src/legacy/lib/models/common/widgets/NestedGroup/index.tsx +40 -0
  78. package/src/legacy/lib/models/common/widgets/Number/index.ts +2 -4
  79. package/src/legacy/lib/models/common/widgets/Select/index.ts +2 -4
  80. package/src/legacy/lib/models/common/widgets/StructuredText/index.ts +0 -2
  81. package/src/legacy/lib/models/common/widgets/Text/index.ts +0 -2
  82. package/src/legacy/lib/models/common/widgets/Timestamp/index.ts +2 -4
  83. package/src/legacy/lib/models/common/widgets/UID/index.ts +2 -4
  84. package/src/legacy/lib/models/common/widgets/Widget.ts +10 -3
  85. package/src/legacy/lib/models/common/widgets/groupWidgets.ts +7 -0
  86. package/src/legacy/lib/models/common/widgets/index.ts +7 -31
  87. package/src/legacy/lib/models/common/widgets/nonGroupWidgets.ts +33 -0
  88. package/test/lib/builders/buildersUtils.test.ts +1 -1
  89. package/test/lib/models/common/widgets/index.test.ts +1 -1
  90. package/out/_next/static/JGphUg6eFq0-W11Pa7cMU/_buildManifest.js +0 -1
  91. package/out/_next/static/chunks/18539003-eda642ad962ef598.js +0 -22
  92. package/out/_next/static/chunks/264-4bb6f3fb14863ef3.js +0 -1
  93. package/out/_next/static/chunks/574-6039c48fbc93b4a8.js +0 -1
  94. package/out/_next/static/chunks/59b4e022-7a3b5554b806349f.js +0 -1
  95. package/out/_next/static/chunks/756-1e44fe84bedc262b.js +0 -10
  96. package/out/_next/static/chunks/f36c6662-03bb5e9d9aa0b0aa.js +0 -1
  97. package/out/_next/static/chunks/pages/_app-05ac13d573829b68.js +0 -532
  98. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-996e20b9b295a912.js +0 -1
  99. package/out/_next/static/css/b3bb731ce567d63f.css +0 -1
  100. package/src/legacy/lib/builders/common/SelectFieldTypeModal/FieldTypeCard.jsx +0 -51
  101. package/src/legacy/lib/builders/common/SelectFieldTypeModal/index.jsx +0 -84
  102. package/src/legacy/lib/models/common/widgets/Group/index.ts +0 -44
  103. package/src/legacy/lib/models/common/widgets/ctBuilderArray.ts +0 -20
  104. package/src/legacy/lib/models/common/widgets/groupBuilderArray.ts +0 -18
  105. package/src/legacy/lib/models/common/widgets/sliceBuilderArray.ts +0 -19
  106. package/src/legacy/lib/models/common/widgets/withGroup.ts +0 -2
  107. /package/out/_next/static/{JGphUg6eFq0-W11Pa7cMU → 75dY8fp3JqJwdHRXfu9LV}/_ssgManifest.js +0 -0
package/out/settings.html CHANGED
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/b3bb731ce567d63f.css" as="style"/><link rel="stylesheet" href="/_next/static/css/b3bb731ce567d63f.css" data-n-g=""/><link rel="preload" href="/_next/static/css/ca32882a5d2d8d88.css" as="style"/><link rel="stylesheet" href="/_next/static/css/ca32882a5d2d8d88.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-207ecb3e9b995dd9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-05ac13d573829b68.js" defer=""></script><script src="/_next/static/chunks/pages/settings-25eb02893ed871b7.js" defer=""></script><script src="/_next/static/JGphUg6eFq0-W11Pa7cMU/_buildManifest.js" defer=""></script><script src="/_next/static/JGphUg6eFq0-W11Pa7cMU/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/settings","query":{},"buildId":"JGphUg6eFq0-W11Pa7cMU","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/82c8c4f05b25d3af.css" as="style"/><link rel="stylesheet" href="/_next/static/css/82c8c4f05b25d3af.css" data-n-g=""/><link rel="preload" href="/_next/static/css/ca32882a5d2d8d88.css" as="style"/><link rel="stylesheet" href="/_next/static/css/ca32882a5d2d8d88.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-207ecb3e9b995dd9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-d25e4ad1db4fc327.js" defer=""></script><script src="/_next/static/chunks/pages/settings-039476a9a63d25a1.js" defer=""></script><script src="/_next/static/75dY8fp3JqJwdHRXfu9LV/_buildManifest.js" defer=""></script><script src="/_next/static/75dY8fp3JqJwdHRXfu9LV/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/settings","query":{},"buildId":"75dY8fp3JqJwdHRXfu9LV","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/b3bb731ce567d63f.css" as="style"/><link rel="stylesheet" href="/_next/static/css/b3bb731ce567d63f.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-207ecb3e9b995dd9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-05ac13d573829b68.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/72585f70-28b4d7d5384b3703.js" defer=""></script><script src="/_next/static/chunks/18539003-eda642ad962ef598.js" defer=""></script><script src="/_next/static/chunks/756-1e44fe84bedc262b.js" defer=""></script><script src="/_next/static/chunks/pages/slices/%5Blib%5D/%5BsliceName%5D/%5Bvariation%5D/simulator-b47a72d5e94bd946.js" defer=""></script><script src="/_next/static/JGphUg6eFq0-W11Pa7cMU/_buildManifest.js" defer=""></script><script src="/_next/static/JGphUg6eFq0-W11Pa7cMU/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices/[lib]/[sliceName]/[variation]/simulator","query":{},"buildId":"JGphUg6eFq0-W11Pa7cMU","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/82c8c4f05b25d3af.css" as="style"/><link rel="stylesheet" href="/_next/static/css/82c8c4f05b25d3af.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-207ecb3e9b995dd9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-d25e4ad1db4fc327.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/72585f70-28b4d7d5384b3703.js" defer=""></script><script src="/_next/static/chunks/18539003-7b839478e0b5720a.js" defer=""></script><script src="/_next/static/chunks/695-603bd96af31f4302.js" defer=""></script><script src="/_next/static/chunks/pages/slices/%5Blib%5D/%5BsliceName%5D/%5Bvariation%5D/simulator-cfc19e3e799745bb.js" defer=""></script><script src="/_next/static/75dY8fp3JqJwdHRXfu9LV/_buildManifest.js" defer=""></script><script src="/_next/static/75dY8fp3JqJwdHRXfu9LV/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices/[lib]/[sliceName]/[variation]/simulator","query":{},"buildId":"75dY8fp3JqJwdHRXfu9LV","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/b3bb731ce567d63f.css" as="style"/><link rel="stylesheet" href="/_next/static/css/b3bb731ce567d63f.css" data-n-g=""/><link rel="preload" href="/_next/static/css/8d1871dce67a3b49.css" as="style"/><link rel="stylesheet" href="/_next/static/css/8d1871dce67a3b49.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-207ecb3e9b995dd9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-05ac13d573829b68.js" defer=""></script><script src="/_next/static/chunks/59b4e022-7a3b5554b806349f.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/f36c6662-03bb5e9d9aa0b0aa.js" defer=""></script><script src="/_next/static/chunks/4c744e84-e3161d754618373f.js" defer=""></script><script src="/_next/static/chunks/065a3ddb-9a38ca0d60f0bf2f.js" defer=""></script><script src="/_next/static/chunks/1cc2734a-2c5b6c0367fcde86.js" defer=""></script><script src="/_next/static/chunks/183-6ad1d7303abecd2b.js" defer=""></script><script src="/_next/static/chunks/50-8d014b6d3cc35e30.js" defer=""></script><script src="/_next/static/chunks/543-f8766685f7f451e2.js" defer=""></script><script src="/_next/static/chunks/696-b992b9e1ce75777e.js" defer=""></script><script src="/_next/static/chunks/816-68d4db26c0adab2e.js" defer=""></script><script src="/_next/static/chunks/574-6039c48fbc93b4a8.js" defer=""></script><script src="/_next/static/chunks/152-c40fcb226b0df27f.js" defer=""></script><script src="/_next/static/chunks/pages/slices/%5Blib%5D/%5BsliceName%5D/%5Bvariation%5D-996e20b9b295a912.js" defer=""></script><script src="/_next/static/JGphUg6eFq0-W11Pa7cMU/_buildManifest.js" defer=""></script><script src="/_next/static/JGphUg6eFq0-W11Pa7cMU/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices/[lib]/[sliceName]/[variation]","query":{},"buildId":"JGphUg6eFq0-W11Pa7cMU","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/82c8c4f05b25d3af.css" as="style"/><link rel="stylesheet" href="/_next/static/css/82c8c4f05b25d3af.css" data-n-g=""/><link rel="preload" href="/_next/static/css/8d1871dce67a3b49.css" as="style"/><link rel="stylesheet" href="/_next/static/css/8d1871dce67a3b49.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-207ecb3e9b995dd9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-d25e4ad1db4fc327.js" defer=""></script><script src="/_next/static/chunks/59b4e022-8e544a511d670317.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/f36c6662-1f3a854183168b10.js" defer=""></script><script src="/_next/static/chunks/4c744e84-e3161d754618373f.js" defer=""></script><script src="/_next/static/chunks/065a3ddb-9a38ca0d60f0bf2f.js" defer=""></script><script src="/_next/static/chunks/1cc2734a-2c5b6c0367fcde86.js" defer=""></script><script src="/_next/static/chunks/183-6ad1d7303abecd2b.js" defer=""></script><script src="/_next/static/chunks/50-8d014b6d3cc35e30.js" defer=""></script><script src="/_next/static/chunks/543-f8766685f7f451e2.js" defer=""></script><script src="/_next/static/chunks/696-b992b9e1ce75777e.js" defer=""></script><script src="/_next/static/chunks/816-17afd84d2642f4c4.js" defer=""></script><script src="/_next/static/chunks/574-319271e279f042bc.js" defer=""></script><script src="/_next/static/chunks/152-c40fcb226b0df27f.js" defer=""></script><script src="/_next/static/chunks/pages/slices/%5Blib%5D/%5BsliceName%5D/%5Bvariation%5D-58e6cb0f278ea03c.js" defer=""></script><script src="/_next/static/75dY8fp3JqJwdHRXfu9LV/_buildManifest.js" defer=""></script><script src="/_next/static/75dY8fp3JqJwdHRXfu9LV/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices/[lib]/[sliceName]/[variation]","query":{},"buildId":"75dY8fp3JqJwdHRXfu9LV","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
package/out/slices.html CHANGED
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/b3bb731ce567d63f.css" as="style"/><link rel="stylesheet" href="/_next/static/css/b3bb731ce567d63f.css" data-n-g=""/><link rel="preload" href="/_next/static/css/f01f60095c76c7fb.css" as="style"/><link rel="stylesheet" href="/_next/static/css/f01f60095c76c7fb.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-207ecb3e9b995dd9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-05ac13d573829b68.js" defer=""></script><script src="/_next/static/chunks/59b4e022-7a3b5554b806349f.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/50-8d014b6d3cc35e30.js" defer=""></script><script src="/_next/static/chunks/816-68d4db26c0adab2e.js" defer=""></script><script src="/_next/static/chunks/152-c40fcb226b0df27f.js" defer=""></script><script src="/_next/static/chunks/pages/slices-cc44eeccd58d23a9.js" defer=""></script><script src="/_next/static/JGphUg6eFq0-W11Pa7cMU/_buildManifest.js" defer=""></script><script src="/_next/static/JGphUg6eFq0-W11Pa7cMU/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices","query":{},"buildId":"JGphUg6eFq0-W11Pa7cMU","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/82c8c4f05b25d3af.css" as="style"/><link rel="stylesheet" href="/_next/static/css/82c8c4f05b25d3af.css" data-n-g=""/><link rel="preload" href="/_next/static/css/f01f60095c76c7fb.css" as="style"/><link rel="stylesheet" href="/_next/static/css/f01f60095c76c7fb.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-207ecb3e9b995dd9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-d25e4ad1db4fc327.js" defer=""></script><script src="/_next/static/chunks/59b4e022-8e544a511d670317.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/50-8d014b6d3cc35e30.js" defer=""></script><script src="/_next/static/chunks/816-17afd84d2642f4c4.js" defer=""></script><script src="/_next/static/chunks/152-c40fcb226b0df27f.js" defer=""></script><script src="/_next/static/chunks/pages/slices-9894ce968d74baf6.js" defer=""></script><script src="/_next/static/75dY8fp3JqJwdHRXfu9LV/_buildManifest.js" defer=""></script><script src="/_next/static/75dY8fp3JqJwdHRXfu9LV/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices","query":{},"buildId":"75dY8fp3JqJwdHRXfu9LV","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slice-machine-ui",
3
- "version": "2.2.2-beta.1",
3
+ "version": "2.2.2-beta.10",
4
4
  "license": "MIT",
5
5
  "description": "A visual builder for your Slice Models with all the tools you need to generate data models and mock CMS content locally.",
6
6
  "repository": {
@@ -35,20 +35,20 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@radix-ui/react-visually-hidden": "1.0.3",
38
- "@slicemachine/manager": "0.19.4-beta.1",
39
- "start-slicemachine": "0.12.23-beta.1"
38
+ "@slicemachine/manager": "0.19.4-beta.10",
39
+ "start-slicemachine": "0.12.23-beta.10"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@emotion/react": "11.11.1",
43
43
  "@extractus/oembed-extractor": "3.1.8",
44
- "@prismicio/client": "7.5.0",
45
- "@prismicio/editor-fields": "0.4.28",
46
- "@prismicio/editor-support": "0.4.28",
47
- "@prismicio/editor-ui": "0.4.28",
44
+ "@prismicio/client": "7.6.0",
45
+ "@prismicio/editor-fields": "0.4.32",
46
+ "@prismicio/editor-support": "0.4.32",
47
+ "@prismicio/editor-ui": "0.4.32",
48
48
  "@prismicio/mock": "0.3.3",
49
- "@prismicio/mocks": "2.2.0",
49
+ "@prismicio/mocks": "2.3.0",
50
50
  "@prismicio/simulator": "0.1.4",
51
- "@prismicio/types-internal": "2.4.1",
51
+ "@prismicio/types-internal": "2.5.0",
52
52
  "@radix-ui/react-hover-card": "1.0.6",
53
53
  "@radix-ui/react-tabs": "1.0.4",
54
54
  "@reach/menu-button": "0.18.0",
@@ -134,7 +134,8 @@
134
134
  "typescript": "4.9.5",
135
135
  "vite": "4.3.9",
136
136
  "vitest": "0.32.0",
137
- "yup": "0.32.11"
137
+ "yup": "0.32.11",
138
+ "zod": "3.23.8"
138
139
  },
139
140
  "stableVersion": "2.2.1"
140
141
  }
@@ -0,0 +1,223 @@
1
+ import { IconName } from "@prismicio/editor-ui";
2
+ import {
3
+ FieldType,
4
+ NestableFieldTypes,
5
+ } from "@prismicio/types-internal/lib/customtypes";
6
+
7
+ interface BaseField {
8
+ description: string;
9
+ icon: IconName;
10
+ name: string;
11
+ thumbnail: string;
12
+ type: FieldType;
13
+ variant?: FieldVariant;
14
+ }
15
+
16
+ export type NestableFieldVariant = "ContentRelationship" | "LinkToMedia";
17
+ export type GroupFieldVariant = "NestedGroup";
18
+ export type FieldVariant = NestableFieldVariant | GroupFieldVariant;
19
+
20
+ export interface NestableField extends BaseField {
21
+ type: NestableFieldTypes;
22
+ variant?: NestableFieldVariant;
23
+ }
24
+
25
+ export interface UIDField extends BaseField {
26
+ type: "UID";
27
+ variant?: never;
28
+ }
29
+
30
+ export interface GroupField extends BaseField {
31
+ type: "Group";
32
+ variant?: "NestedGroup";
33
+ }
34
+
35
+ export type Field = NestableField | UIDField | GroupField;
36
+
37
+ /**
38
+ * Nestable fields
39
+ */
40
+
41
+ export const booleanField: NestableField = {
42
+ name: "Boolean",
43
+ description: "A true or false toggle.",
44
+ icon: "toggleOff",
45
+ thumbnail:
46
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295526/DEV_TOOLS/SM_FIELDS/Type_Boolean_cbwg8k.png",
47
+ type: "Boolean",
48
+ };
49
+
50
+ export const colorField: NestableField = {
51
+ name: "Color",
52
+ description: "A color in hex format.",
53
+ icon: "colorLens",
54
+ thumbnail:
55
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295521/DEV_TOOLS/SM_FIELDS/Type_Color_nyoeit.png",
56
+ type: "Color",
57
+ };
58
+
59
+ export const dateField: NestableField = {
60
+ name: "Date",
61
+ description: "A date without time.",
62
+ icon: "dateRange",
63
+ thumbnail:
64
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295525/DEV_TOOLS/SM_FIELDS/Type_Date_dsuaeq.png",
65
+ type: "Date",
66
+ };
67
+
68
+ export const embedField: NestableField = {
69
+ name: "Embed",
70
+ description: "A video, song, or oEmbed link.",
71
+ icon: "code",
72
+ thumbnail:
73
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295523/DEV_TOOLS/SM_FIELDS/Type_Embed_wwssvd.png",
74
+ type: "Embed",
75
+ };
76
+
77
+ export const geoPointField: NestableField = {
78
+ name: "Geopoint",
79
+ description: "A geographical coordinate.",
80
+ icon: "place",
81
+ thumbnail:
82
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295522/DEV_TOOLS/SM_FIELDS/Type_GeoPoint_lpq0sm.png",
83
+ type: "GeoPoint",
84
+ };
85
+
86
+ export const imageField: NestableField = {
87
+ name: "Image",
88
+ description: "A responsive image.",
89
+ icon: "image",
90
+ thumbnail:
91
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295520/DEV_TOOLS/SM_FIELDS/Type_Image_zyatxy.png",
92
+ type: "Image",
93
+ };
94
+
95
+ export const LinkField: NestableField = {
96
+ name: "Link",
97
+ description: "A link to a website, asset, or document.",
98
+ icon: "link",
99
+ thumbnail:
100
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295528/DEV_TOOLS/SM_FIELDS/Type_Link_bgslgy.png",
101
+ type: "Link",
102
+ };
103
+
104
+ export const contentRelationshipField: NestableField = {
105
+ name: "Content Relationship",
106
+ description: "A reference to a Prismic document.",
107
+ icon: "settingsEthernet",
108
+ thumbnail:
109
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295527/DEV_TOOLS/SM_FIELDS/Type_Content_RelationShip_s4z4nh.png",
110
+ type: "Link",
111
+ variant: "ContentRelationship",
112
+ };
113
+
114
+ export const LinkToMediaField: NestableField = {
115
+ name: "Link To Media",
116
+ description: "A link to a media asset.",
117
+ icon: "attachFile",
118
+ thumbnail:
119
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295519/DEV_TOOLS/SM_FIELDS/Type_LinkToMedia_m2p0ce.png",
120
+ type: "Link",
121
+ variant: "LinkToMedia",
122
+ };
123
+
124
+ export const numberField: NestableField = {
125
+ name: "Number",
126
+ description: "An integer or float.",
127
+ icon: "pin",
128
+ thumbnail:
129
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295522/DEV_TOOLS/SM_FIELDS/Type_Number_o3olop.png",
130
+ type: "Number",
131
+ };
132
+
133
+ export const selectField: NestableField = {
134
+ name: "Select",
135
+ description: "A dropdown of options.",
136
+ icon: "arrowDropDownCircle",
137
+ thumbnail:
138
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295527/DEV_TOOLS/SM_FIELDS/Type_Select_bedjei.png",
139
+ type: "Select",
140
+ };
141
+
142
+ export const richTextField: NestableField = {
143
+ name: "Rich Text",
144
+ description: "Text with formatting options.",
145
+ icon: "textFields",
146
+ thumbnail:
147
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295530/DEV_TOOLS/SM_FIELDS/Type_Rich_Text_fxdyar.png",
148
+ type: "StructuredText",
149
+ };
150
+
151
+ export const textField: NestableField = {
152
+ name: "Text",
153
+ description: "A text string without formatting.",
154
+ icon: "title",
155
+ thumbnail:
156
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295529/DEV_TOOLS/SM_FIELDS/Type_Key_Text_xrqf45.png",
157
+ type: "Text",
158
+ };
159
+
160
+ export const timestampField: NestableField = {
161
+ name: "Timestamp",
162
+ description: "A date and time.",
163
+ icon: "schedule",
164
+ thumbnail:
165
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295524/DEV_TOOLS/SM_FIELDS/Type_Timestamp_fkr5iw.png",
166
+ type: "Timestamp",
167
+ };
168
+
169
+ export const nestableFields: NestableField[] = [
170
+ imageField,
171
+ textField,
172
+ richTextField,
173
+ booleanField,
174
+ numberField,
175
+ selectField,
176
+ LinkField,
177
+ LinkToMediaField,
178
+ colorField,
179
+ dateField,
180
+ timestampField,
181
+ embedField,
182
+ geoPointField,
183
+ contentRelationshipField,
184
+ ];
185
+
186
+ /**
187
+ * UID
188
+ */
189
+
190
+ export const UIDField: UIDField = {
191
+ name: "UID",
192
+ description: "Unique Identifier",
193
+ icon: "tag",
194
+ thumbnail:
195
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295519/DEV_TOOLS/SM_FIELDS/Type_UID_hrwzug.png",
196
+ type: "UID",
197
+ };
198
+
199
+ /**
200
+ * Group
201
+ */
202
+
203
+ export const groupField: GroupField = {
204
+ name: "Repeatable Group",
205
+ description: "A set of fields that editors can repeat.",
206
+ icon: "createNewFolder",
207
+ thumbnail:
208
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721314577/DEV_TOOLS/SM_FIELDS/Type_Group_uwwco0.png",
209
+ type: "Group",
210
+ };
211
+
212
+ export const nestedGroupField: GroupField = {
213
+ ...groupField,
214
+ variant: "NestedGroup",
215
+ };
216
+
217
+ export const groupFields: GroupField[] = [groupField, nestedGroupField];
218
+
219
+ /**
220
+ * All fields
221
+ */
222
+
223
+ export const fields = [...nestableFields, UIDField, ...groupFields];
@@ -0,0 +1,119 @@
1
+ import {
2
+ Button,
3
+ DropdownMenu,
4
+ DropdownMenuContent,
5
+ DropdownMenuItem,
6
+ DropdownMenuLabel,
7
+ DropdownMenuTrigger,
8
+ Icon,
9
+ Image,
10
+ Text,
11
+ Tooltip,
12
+ } from "@prismicio/editor-ui";
13
+ import { FieldType } from "@prismicio/types-internal/lib/customtypes";
14
+
15
+ import {
16
+ Field,
17
+ FieldVariant,
18
+ groupField,
19
+ nestableFields,
20
+ UIDField,
21
+ } from "@/domain/fields";
22
+
23
+ interface AddFieldDropdownProps {
24
+ disabled: boolean;
25
+ onSelectField: (fieldType: FieldType | FieldVariant) => void;
26
+ fields: Field[];
27
+ triggerDataTestId?: string;
28
+ }
29
+
30
+ export function AddFieldDropdown(props: AddFieldDropdownProps) {
31
+ const {
32
+ disabled,
33
+ onSelectField,
34
+ fields,
35
+ triggerDataTestId = "add-field",
36
+ } = props;
37
+
38
+ const singleFieldsToRender = fields.filter(
39
+ (field) =>
40
+ nestableFields.some(
41
+ (nestableField) => nestableField.name === field.name,
42
+ ) || field.name === UIDField.name,
43
+ );
44
+ const groupFieldToRender = fields.find(
45
+ (field) => field.name === groupField.name,
46
+ );
47
+
48
+ return (
49
+ <DropdownMenu>
50
+ <DropdownMenuTrigger disabled={disabled}>
51
+ <Button startIcon="add" color="grey" data-testid={triggerDataTestId}>
52
+ Add a field
53
+ </Button>
54
+ </DropdownMenuTrigger>
55
+ <DropdownMenuContent align="end" maxHeight={400} collisionPadding={8}>
56
+ <DropdownMenuLabel>Single fields</DropdownMenuLabel>
57
+ {singleFieldsToRender.map((field) => (
58
+ <AddFieldDropdownItem field={field} onSelectField={onSelectField} />
59
+ ))}
60
+
61
+ {groupFieldToRender && (
62
+ <>
63
+ <DropdownMenuLabel>Set of fields</DropdownMenuLabel>
64
+ {
65
+ <AddFieldDropdownItem
66
+ field={groupFieldToRender}
67
+ onSelectField={onSelectField}
68
+ />
69
+ }
70
+ </>
71
+ )}
72
+ </DropdownMenuContent>
73
+ </DropdownMenu>
74
+ );
75
+ }
76
+
77
+ interface AddFieldDropdownItemProps {
78
+ onSelectField: AddFieldDropdownProps["onSelectField"];
79
+ field: Field;
80
+ }
81
+
82
+ function AddFieldDropdownItem(props: AddFieldDropdownItemProps) {
83
+ const { field, onSelectField } = props;
84
+ const { type, variant, name, icon, description, thumbnail } = field;
85
+
86
+ return (
87
+ <DropdownMenuItem
88
+ key={`${type}${variant ? `-${variant}` : ""}`}
89
+ startIcon={<Icon name={icon} size="large" />}
90
+ description={description}
91
+ onSelect={() => onSelectField(variant ?? type)}
92
+ renderTooltip={(trigger) => (
93
+ <Tooltip
94
+ visible
95
+ variant="custom"
96
+ content={
97
+ <>
98
+ <Image
99
+ src={thumbnail}
100
+ sx={{
101
+ height: 170,
102
+ width: 278,
103
+ borderRadius: 4,
104
+ }}
105
+ />
106
+ <Text color="white">How it will look for content editors.</Text>
107
+ </>
108
+ }
109
+ side="left"
110
+ sideOffset={4}
111
+ >
112
+ {trigger}
113
+ </Tooltip>
114
+ )}
115
+ >
116
+ {name}
117
+ </DropdownMenuItem>
118
+ );
119
+ }
@@ -0,0 +1,45 @@
1
+ import { Card, CardContent, Text } from "@prismicio/editor-ui";
2
+
3
+ import { OnboardingProgressStepper } from "@/features/onboarding/OnboardingProgressStepper";
4
+ import {
5
+ OnboardingProvider,
6
+ useOnboardingContext,
7
+ } from "@/features/onboarding/OnboardingProvider";
8
+ import { useOnboardingExperiment } from "@/features/onboarding/useOnboardingExperiment";
9
+
10
+ const OnboardingGuideContent = () => {
11
+ const { steps, completedStepCount, isComplete } = useOnboardingContext();
12
+
13
+ if (isComplete) return null;
14
+
15
+ return (
16
+ <Card color="grey2" variant="outlined" paddingBlock={16}>
17
+ <CardContent>
18
+ <div>
19
+ <Text variant="bold" color="grey12">
20
+ Welcome
21
+ </Text>
22
+ <Text color="grey11" variant="small">
23
+ Get started in {steps.length} steps
24
+ </Text>
25
+ </div>
26
+ <Text color="grey11" variant="small" align="end">
27
+ {completedStepCount}/{steps.length}
28
+ </Text>
29
+ <OnboardingProgressStepper />
30
+ </CardContent>
31
+ </Card>
32
+ );
33
+ };
34
+
35
+ export const OnboardingGuide = () => {
36
+ const { eligible } = useOnboardingExperiment();
37
+
38
+ if (!eligible) return null;
39
+
40
+ return (
41
+ <OnboardingProvider>
42
+ <OnboardingGuideContent />
43
+ </OnboardingProvider>
44
+ );
45
+ };
@@ -0,0 +1,71 @@
1
+ import {
2
+ Button,
3
+ DropdownMenu,
4
+ DropdownMenuContent,
5
+ DropdownMenuItem,
6
+ DropdownMenuLabel,
7
+ DropdownMenuTrigger,
8
+ Icon,
9
+ } from "@prismicio/editor-ui";
10
+ import { useState } from "react";
11
+
12
+ import { useOnboardingContext } from "@/features/onboarding/OnboardingProvider";
13
+ import { OnboardingStepDialog } from "@/features/onboarding/OnboardingStepDialog";
14
+ import type { OnboardingStep } from "@/features/onboarding/types";
15
+
16
+ const EndCtaIcon = () => <Icon name="playCircle" size="small" color="grey11" />;
17
+
18
+ export const OnboardingProgressStepper = () => {
19
+ const { completedStepCount, steps, isStepComplete } = useOnboardingContext();
20
+
21
+ const [isDialogOpen, setDialogOpen] = useState(false);
22
+ const [activeStep, setActiveStep] = useState(steps[0]);
23
+
24
+ const showStep = (step: OnboardingStep) => {
25
+ setActiveStep(step);
26
+ setDialogOpen(true);
27
+ };
28
+
29
+ return (
30
+ <>
31
+ <OnboardingStepDialog
32
+ step={activeStep}
33
+ isOpen={isDialogOpen}
34
+ onClose={() => setDialogOpen(false)}
35
+ />
36
+ <DropdownMenu>
37
+ <DropdownMenuTrigger>
38
+ <Button
39
+ color="grey"
40
+ sx={{ width: "100%" }}
41
+ renderEndIcon={EndCtaIcon}
42
+ >
43
+ {completedStepCount > 0 ? "Continue" : "Start"}
44
+ </Button>
45
+ </DropdownMenuTrigger>
46
+ <DropdownMenuContent align="start">
47
+ <DropdownMenuLabel>Progress</DropdownMenuLabel>
48
+ {steps.map((step) => {
49
+ const isCompleted = isStepComplete(step.id);
50
+
51
+ return (
52
+ <DropdownMenuItem
53
+ key={step.id}
54
+ onSelect={() => showStep(step)}
55
+ startIcon={
56
+ <Icon
57
+ color={isCompleted ? "green10" : "currentColor"}
58
+ name={isCompleted ? "checkBox" : "checkBoxOutlinedBlank"}
59
+ />
60
+ }
61
+ description={step.title}
62
+ >
63
+ {step.title}
64
+ </DropdownMenuItem>
65
+ );
66
+ })}
67
+ </DropdownMenuContent>
68
+ </DropdownMenu>
69
+ </>
70
+ );
71
+ };
@@ -0,0 +1,82 @@
1
+ import { createContext, ReactNode, useContext } from "react";
2
+
3
+ import { onboardingSteps as steps } from "@/features/onboarding/content";
4
+ import {
5
+ type OnboardingStep,
6
+ type OnboardingStepStatuses,
7
+ onboardingStepStatusesSchema,
8
+ type OnboardingStepType,
9
+ } from "@/features/onboarding/types";
10
+ import { usePersistedState } from "@/hooks/usePersistedState";
11
+
12
+ type OnboardingContext = {
13
+ steps: OnboardingStep[];
14
+ completedStepCount: number;
15
+ toggleStepComplete: (step: OnboardingStepType) => void;
16
+ getStepIndex: (stepId: OnboardingStepType) => number;
17
+ isStepComplete: (stepId: OnboardingStepType) => boolean;
18
+ isComplete: boolean;
19
+ };
20
+
21
+ export const OnboardingContext = createContext<OnboardingContext | undefined>(
22
+ undefined,
23
+ );
24
+
25
+ const getInitialState = (): OnboardingStepStatuses => {
26
+ // if the old guide was dismissed, all steps start as complete
27
+ const wasOldGuideDismissed =
28
+ localStorage.getItem("slice-machine_isInAppGuideOpen") === "false";
29
+
30
+ return Object.fromEntries(
31
+ steps.map((step) => [step.id, wasOldGuideDismissed]),
32
+ ) as OnboardingStepStatuses;
33
+ };
34
+
35
+ export const OnboardingProvider = ({ children }: { children: ReactNode }) => {
36
+ const [stepStatus, setStepStatus] = usePersistedState(
37
+ "onboardingSteps",
38
+ getInitialState(),
39
+ { schema: onboardingStepStatusesSchema },
40
+ );
41
+
42
+ const toggleStepComplete = (step: OnboardingStepType) => {
43
+ setStepStatus((current) => ({ ...current, [step]: !current[step] }));
44
+ };
45
+
46
+ const getStepIndex = (stepId: OnboardingStepType) => {
47
+ return steps.findIndex(({ id }) => id === stepId);
48
+ };
49
+
50
+ const isStepComplete = (stepId: OnboardingStepType) => {
51
+ return stepStatus[stepId] ?? false;
52
+ };
53
+
54
+ const completedStepCount = Object.values(stepStatus).filter(Boolean).length;
55
+
56
+ return (
57
+ <OnboardingContext.Provider
58
+ value={{
59
+ steps,
60
+ toggleStepComplete,
61
+ isStepComplete,
62
+ getStepIndex,
63
+ completedStepCount,
64
+ isComplete: completedStepCount === steps.length,
65
+ }}
66
+ >
67
+ {children}
68
+ </OnboardingContext.Provider>
69
+ );
70
+ };
71
+
72
+ export const useOnboardingContext = () => {
73
+ const context = useContext(OnboardingContext);
74
+
75
+ if (context == null) {
76
+ throw new Error(
77
+ "useOnboardingContext must be used within an OnboardingProvider",
78
+ );
79
+ }
80
+
81
+ return context;
82
+ };