@brilo/base-blocks 0.1.0

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 (254) hide show
  1. package/.editorconfig +12 -0
  2. package/.prettierrc +8 -0
  3. package/README.md +59 -0
  4. package/USAGE.md +263 -0
  5. package/biome.json +38 -0
  6. package/bun.lock +1392 -0
  7. package/docs/block-anatomy.md +73 -0
  8. package/docs/conventions.md +204 -0
  9. package/docs/new-block.md +179 -0
  10. package/package.json +41 -0
  11. package/src/blocks/column/column-group/edit.tsx +56 -0
  12. package/src/blocks/column/column-group/editor.scss +7 -0
  13. package/src/blocks/column/column-group/factory.tsx +29 -0
  14. package/src/blocks/column/column-group/index.ts +14 -0
  15. package/src/blocks/column/column-group/types.ts +8 -0
  16. package/src/blocks/column/column-item/constants.ts +1 -0
  17. package/src/blocks/column/column-item/edit.tsx +48 -0
  18. package/src/blocks/column/column-item/editor.scss +34 -0
  19. package/src/blocks/column/column-item/factory.tsx +25 -0
  20. package/src/blocks/column/column-item/index.ts +10 -0
  21. package/src/blocks/column/column-item/types.ts +7 -0
  22. package/src/blocks/compare/compare-group/constants.ts +1 -0
  23. package/src/blocks/compare/compare-group/edit.tsx +52 -0
  24. package/src/blocks/compare/compare-group/factory.tsx +29 -0
  25. package/src/blocks/compare/compare-group/icon.tsx +7 -0
  26. package/src/blocks/compare/compare-group/index.ts +13 -0
  27. package/src/blocks/compare/compare-group/types.ts +12 -0
  28. package/src/blocks/compare/compare-item/edit.tsx +38 -0
  29. package/src/blocks/compare/compare-item/editor.scss +15 -0
  30. package/src/blocks/compare/compare-item/factory.tsx +28 -0
  31. package/src/blocks/compare/compare-item/icon.tsx +9 -0
  32. package/src/blocks/compare/compare-item/index.ts +13 -0
  33. package/src/blocks/compare/compare-item/types.ts +9 -0
  34. package/src/blocks/compare/compare-option/constants.ts +7 -0
  35. package/src/blocks/compare/compare-option/edit.tsx +64 -0
  36. package/src/blocks/compare/compare-option/editor.scss +26 -0
  37. package/src/blocks/compare/compare-option/factory.tsx +35 -0
  38. package/src/blocks/compare/compare-option/icon.tsx +7 -0
  39. package/src/blocks/compare/compare-option/index.ts +8 -0
  40. package/src/blocks/compare/compare-option/types.ts +12 -0
  41. package/src/blocks/contact/contact-group/constants.ts +3 -0
  42. package/src/blocks/contact/contact-group/edit.tsx +57 -0
  43. package/src/blocks/contact/contact-group/editor.scss +20 -0
  44. package/src/blocks/contact/contact-group/factory.tsx +35 -0
  45. package/src/blocks/contact/contact-group/index.ts +12 -0
  46. package/src/blocks/contact/contact-group/types.ts +12 -0
  47. package/src/blocks/contact/contact-item/constants.ts +17 -0
  48. package/src/blocks/contact/contact-item/edit.tsx +93 -0
  49. package/src/blocks/contact/contact-item/editor.scss +38 -0
  50. package/src/blocks/contact/contact-item/factory.tsx +35 -0
  51. package/src/blocks/contact/contact-item/index.ts +23 -0
  52. package/src/blocks/contact/contact-item/types.ts +21 -0
  53. package/src/blocks/core/basic-button/constants.ts +17 -0
  54. package/src/blocks/core/basic-button/edit.tsx +107 -0
  55. package/src/blocks/core/basic-button/editor.scss +80 -0
  56. package/src/blocks/core/basic-button/factory.tsx +54 -0
  57. package/src/blocks/core/basic-button/index.ts +8 -0
  58. package/src/blocks/core/basic-button/types.ts +29 -0
  59. package/src/blocks/core/basic-heading/constants.ts +1 -0
  60. package/src/blocks/core/basic-heading/edit.tsx +76 -0
  61. package/src/blocks/core/basic-heading/editor.scss +8 -0
  62. package/src/blocks/core/basic-heading/factory.tsx +40 -0
  63. package/src/blocks/core/basic-heading/index.ts +8 -0
  64. package/src/blocks/core/basic-heading/types.ts +20 -0
  65. package/src/blocks/core/basic-overline/edit.tsx +28 -0
  66. package/src/blocks/core/basic-overline/editor.scss +14 -0
  67. package/src/blocks/core/basic-overline/factory.tsx +22 -0
  68. package/src/blocks/core/basic-overline/index.ts +8 -0
  69. package/src/blocks/core/basic-overline/types.ts +7 -0
  70. package/src/blocks/faq/faq-group/constants.ts +11 -0
  71. package/src/blocks/faq/faq-group/edit.tsx +55 -0
  72. package/src/blocks/faq/faq-group/editor.scss +11 -0
  73. package/src/blocks/faq/faq-group/factory.tsx +39 -0
  74. package/src/blocks/faq/faq-group/index.ts +11 -0
  75. package/src/blocks/faq/faq-group/types.ts +14 -0
  76. package/src/blocks/faq/faq-item/edit.tsx +50 -0
  77. package/src/blocks/faq/faq-item/editor.scss +57 -0
  78. package/src/blocks/faq/faq-item/factory.tsx +24 -0
  79. package/src/blocks/faq/faq-item/index.ts +9 -0
  80. package/src/blocks/faq/faq-item/types.ts +7 -0
  81. package/src/blocks/form/form-field/constants.ts +14 -0
  82. package/src/blocks/form/form-field/edit.tsx +178 -0
  83. package/src/blocks/form/form-field/editor.scss +71 -0
  84. package/src/blocks/form/form-field/factory.tsx +32 -0
  85. package/src/blocks/form/form-field/index.ts +10 -0
  86. package/src/blocks/form/form-field/types.ts +18 -0
  87. package/src/blocks/form/form-group/constants.ts +16 -0
  88. package/src/blocks/form/form-group/edit.tsx +190 -0
  89. package/src/blocks/form/form-group/editor.scss +41 -0
  90. package/src/blocks/form/form-group/factory.tsx +35 -0
  91. package/src/blocks/form/form-group/index.ts +18 -0
  92. package/src/blocks/form/form-group/types.ts +22 -0
  93. package/src/blocks/groups/banner-group/constants.ts +15 -0
  94. package/src/blocks/groups/banner-group/edit.tsx +122 -0
  95. package/src/blocks/groups/banner-group/editor.scss +18 -0
  96. package/src/blocks/groups/banner-group/factory.tsx +64 -0
  97. package/src/blocks/groups/banner-group/icon.tsx +13 -0
  98. package/src/blocks/groups/banner-group/index.ts +11 -0
  99. package/src/blocks/groups/banner-group/types.ts +30 -0
  100. package/src/blocks/groups/basic-header-group/constants.ts +9 -0
  101. package/src/blocks/groups/basic-header-group/edit.tsx +99 -0
  102. package/src/blocks/groups/basic-header-group/editor.scss +35 -0
  103. package/src/blocks/groups/basic-header-group/factory.tsx +46 -0
  104. package/src/blocks/groups/basic-header-group/icon.tsx +17 -0
  105. package/src/blocks/groups/basic-header-group/index.ts +9 -0
  106. package/src/blocks/groups/basic-header-group/types.ts +27 -0
  107. package/src/blocks/groups/button-group/constants.ts +7 -0
  108. package/src/blocks/groups/button-group/edit.tsx +52 -0
  109. package/src/blocks/groups/button-group/editor.scss +23 -0
  110. package/src/blocks/groups/button-group/factory.tsx +34 -0
  111. package/src/blocks/groups/button-group/index.ts +11 -0
  112. package/src/blocks/groups/button-group/types.ts +12 -0
  113. package/src/blocks/groups/text-and-media-group/constants.ts +43 -0
  114. package/src/blocks/groups/text-and-media-group/edit.tsx +241 -0
  115. package/src/blocks/groups/text-and-media-group/editor.scss +123 -0
  116. package/src/blocks/groups/text-and-media-group/factory.tsx +100 -0
  117. package/src/blocks/groups/text-and-media-group/icon.tsx +37 -0
  118. package/src/blocks/groups/text-and-media-group/index.ts +18 -0
  119. package/src/blocks/groups/text-and-media-group/types.ts +60 -0
  120. package/src/blocks/hero/hero-group/constants.ts +23 -0
  121. package/src/blocks/hero/hero-group/edit.tsx +85 -0
  122. package/src/blocks/hero/hero-group/editor.scss +0 -0
  123. package/src/blocks/hero/hero-group/factory.tsx +45 -0
  124. package/src/blocks/hero/hero-group/icon.tsx +28 -0
  125. package/src/blocks/hero/hero-group/index.ts +11 -0
  126. package/src/blocks/hero/hero-group/types.ts +22 -0
  127. package/src/blocks/hero/hero-item/constants.ts +15 -0
  128. package/src/blocks/hero/hero-item/edit.tsx +107 -0
  129. package/src/blocks/hero/hero-item/editor.scss +87 -0
  130. package/src/blocks/hero/hero-item/factory.tsx +49 -0
  131. package/src/blocks/hero/hero-item/index.ts +10 -0
  132. package/src/blocks/hero/hero-item/types.ts +38 -0
  133. package/src/blocks/map/map-group/constants.ts +20 -0
  134. package/src/blocks/map/map-group/edit.tsx +108 -0
  135. package/src/blocks/map/map-group/editor.scss +24 -0
  136. package/src/blocks/map/map-group/factory.tsx +51 -0
  137. package/src/blocks/map/map-group/index.ts +9 -0
  138. package/src/blocks/map/map-group/types.ts +16 -0
  139. package/src/blocks/newsletter/newsletter-form/constants.ts +5 -0
  140. package/src/blocks/newsletter/newsletter-form/edit.tsx +194 -0
  141. package/src/blocks/newsletter/newsletter-form/editor.scss +68 -0
  142. package/src/blocks/newsletter/newsletter-form/factory.tsx +59 -0
  143. package/src/blocks/newsletter/newsletter-form/index.ts +11 -0
  144. package/src/blocks/newsletter/newsletter-form/types.ts +45 -0
  145. package/src/blocks/post/post-slider-group/constants.ts +3 -0
  146. package/src/blocks/post/post-slider-group/edit.tsx +76 -0
  147. package/src/blocks/post/post-slider-group/factory.tsx +43 -0
  148. package/src/blocks/post/post-slider-group/icon.tsx +13 -0
  149. package/src/blocks/post/post-slider-group/index.ts +9 -0
  150. package/src/blocks/post/post-slider-group/types.ts +20 -0
  151. package/src/blocks/responsive-grid/responsive-grid-group/edit.tsx +95 -0
  152. package/src/blocks/responsive-grid/responsive-grid-group/factory.tsx +33 -0
  153. package/src/blocks/responsive-grid/responsive-grid-group/index.ts +13 -0
  154. package/src/blocks/responsive-grid/responsive-grid-group/types.ts +9 -0
  155. package/src/blocks/responsive-grid/responsive-grid-item/edit.tsx +19 -0
  156. package/src/blocks/responsive-grid/responsive-grid-item/factory.tsx +20 -0
  157. package/src/blocks/responsive-grid/responsive-grid-item/index.ts +9 -0
  158. package/src/blocks/responsive-grid/responsive-grid-item/types.ts +5 -0
  159. package/src/blocks/sections/base-section/attributes.ts +17 -0
  160. package/src/blocks/sections/base-section/constants.ts +18 -0
  161. package/src/blocks/sections/base-section/controls.tsx +70 -0
  162. package/src/blocks/sections/base-section/edit.tsx +34 -0
  163. package/src/blocks/sections/base-section/editor.scss +24 -0
  164. package/src/blocks/sections/base-section/factory.tsx +47 -0
  165. package/src/blocks/sections/base-section/icon.tsx +6 -0
  166. package/src/blocks/sections/base-section/index.ts +14 -0
  167. package/src/blocks/sections/base-section/types.ts +26 -0
  168. package/src/blocks/signpost/signpost-group/constants.ts +3 -0
  169. package/src/blocks/signpost/signpost-group/edit.tsx +75 -0
  170. package/src/blocks/signpost/signpost-group/editor.scss +0 -0
  171. package/src/blocks/signpost/signpost-group/factory.tsx +40 -0
  172. package/src/blocks/signpost/signpost-group/icon.tsx +19 -0
  173. package/src/blocks/signpost/signpost-group/index.ts +15 -0
  174. package/src/blocks/signpost/signpost-group/types.ts +9 -0
  175. package/src/blocks/signpost/signpost-item/constants.ts +4 -0
  176. package/src/blocks/signpost/signpost-item/edit.tsx +90 -0
  177. package/src/blocks/signpost/signpost-item/editor.scss +25 -0
  178. package/src/blocks/signpost/signpost-item/factory.tsx +29 -0
  179. package/src/blocks/signpost/signpost-item/icon.tsx +7 -0
  180. package/src/blocks/signpost/signpost-item/index.ts +10 -0
  181. package/src/blocks/signpost/signpost-item/types.ts +12 -0
  182. package/src/blocks/step/step-group/constants.ts +6 -0
  183. package/src/blocks/step/step-group/edit.tsx +64 -0
  184. package/src/blocks/step/step-group/editor.scss +19 -0
  185. package/src/blocks/step/step-group/factory.tsx +36 -0
  186. package/src/blocks/step/step-group/icon.tsx +27 -0
  187. package/src/blocks/step/step-group/index.ts +15 -0
  188. package/src/blocks/step/step-group/types.ts +13 -0
  189. package/src/blocks/step/step-item/constants.ts +6 -0
  190. package/src/blocks/step/step-item/edit.tsx +60 -0
  191. package/src/blocks/step/step-item/editor.scss +18 -0
  192. package/src/blocks/step/step-item/factory.tsx +27 -0
  193. package/src/blocks/step/step-item/index.ts +11 -0
  194. package/src/blocks/step/step-item/types.ts +12 -0
  195. package/src/blocks/testimonial/testimonial-group/constants.ts +27 -0
  196. package/src/blocks/testimonial/testimonial-group/edit.tsx +74 -0
  197. package/src/blocks/testimonial/testimonial-group/editor.scss +38 -0
  198. package/src/blocks/testimonial/testimonial-group/factory.tsx +44 -0
  199. package/src/blocks/testimonial/testimonial-group/icon.tsx +33 -0
  200. package/src/blocks/testimonial/testimonial-group/index.ts +15 -0
  201. package/src/blocks/testimonial/testimonial-group/types.ts +19 -0
  202. package/src/blocks/testimonial/testimonial-item/edit.tsx +48 -0
  203. package/src/blocks/testimonial/testimonial-item/editor.scss +20 -0
  204. package/src/blocks/testimonial/testimonial-item/factory.tsx +35 -0
  205. package/src/blocks/testimonial/testimonial-item/index.ts +9 -0
  206. package/src/blocks/testimonial/testimonial-item/types.ts +9 -0
  207. package/src/blocks/text-and-form/text-and-form-group/constants.ts +6 -0
  208. package/src/blocks/text-and-form/text-and-form-group/edit.tsx +59 -0
  209. package/src/blocks/text-and-form/text-and-form-group/editor.scss +21 -0
  210. package/src/blocks/text-and-form/text-and-form-group/factory.tsx +38 -0
  211. package/src/blocks/text-and-form/text-and-form-group/icon.tsx +23 -0
  212. package/src/blocks/text-and-form/text-and-form-group/index.ts +9 -0
  213. package/src/blocks/text-and-form/text-and-form-group/types.ts +23 -0
  214. package/src/blocks/text-and-form/text-and-form-text-column/constants.ts +10 -0
  215. package/src/blocks/text-and-form/text-and-form-text-column/edit.tsx +94 -0
  216. package/src/blocks/text-and-form/text-and-form-text-column/editor.scss +29 -0
  217. package/src/blocks/text-and-form/text-and-form-text-column/factory.tsx +41 -0
  218. package/src/blocks/text-and-form/text-and-form-text-column/index.ts +18 -0
  219. package/src/blocks/text-and-form/text-and-form-text-column/types.ts +23 -0
  220. package/src/blocks/usp/usp-group/constants.ts +54 -0
  221. package/src/blocks/usp/usp-group/edit.tsx +197 -0
  222. package/src/blocks/usp/usp-group/editor.scss +24 -0
  223. package/src/blocks/usp/usp-group/factory.tsx +113 -0
  224. package/src/blocks/usp/usp-group/icon.tsx +18 -0
  225. package/src/blocks/usp/usp-group/index.ts +15 -0
  226. package/src/blocks/usp/usp-group/types.ts +70 -0
  227. package/src/blocks/usp/usp-item/constants.ts +7 -0
  228. package/src/blocks/usp/usp-item/edit.tsx +65 -0
  229. package/src/blocks/usp/usp-item/editor.scss +17 -0
  230. package/src/blocks/usp/usp-item/factory.tsx +30 -0
  231. package/src/blocks/usp/usp-item/index.ts +11 -0
  232. package/src/blocks/usp/usp-item/types.ts +17 -0
  233. package/src/components/IconControl/IconControl.tsx +55 -0
  234. package/src/components/IconControl/editor.scss +53 -0
  235. package/src/components/IconControl/index.ts +2 -0
  236. package/src/components/IconControl/index.tsx +1 -0
  237. package/src/components/ImagePicker/ImagePicker.tsx +124 -0
  238. package/src/components/ImagePicker/editor.scss +79 -0
  239. package/src/components/ImagePicker/index.ts +2 -0
  240. package/src/components/ImagePicker/index.tsx +1 -0
  241. package/src/components/ItemIconControl/ItemIconControl.tsx +72 -0
  242. package/src/components/ItemIconControl/ItemIconModal.tsx +12 -0
  243. package/src/components/ItemIconControl/ItemIconPreview.tsx +93 -0
  244. package/src/components/ItemIconControl/editor.scss +52 -0
  245. package/src/components/ItemIconControl/index.ts +2 -0
  246. package/src/components/ItemIconControl/types.d.ts +30 -0
  247. package/src/constants.ts +20 -0
  248. package/src/editor.scss +34 -0
  249. package/src/globals.scss +237 -0
  250. package/src/hooks/useGroupBlock.ts +53 -0
  251. package/src/index.ts +122 -0
  252. package/src/types.ts +33 -0
  253. package/src/utils/createEditAdapter.ts +11 -0
  254. package/tsconfig.json +21 -0
@@ -0,0 +1,32 @@
1
+ import type {BlockConfiguration} from '@wordpress/blocks'
2
+ import {__} from '@wordpress/i18n'
3
+ import {FIELD_COLUMNS_DEFAULT} from './constants'
4
+ import {createFormFieldEdit} from './edit'
5
+ import type {FormFieldAttributes, FormFieldOptions} from './types'
6
+
7
+ export type {FormFieldAttributes, FormFieldOptions}
8
+
9
+ export function createFormFieldBlock(options: FormFieldOptions): BlockConfiguration<FormFieldAttributes> {
10
+ return {
11
+ name: options.name,
12
+ title: options.title ?? __('Pole formuláře', 'brilo-blocks'),
13
+ description: options.description,
14
+ category: options.category ?? 'layout',
15
+ ...(options.parent && {parent: options.parent}),
16
+ icon: options.icon ?? 'forms',
17
+ supports: {html: false, customClassName: false, reusable: false},
18
+ attributes: {
19
+ type: {type: 'string', default: 'text'},
20
+ columns: {type: 'number', default: FIELD_COLUMNS_DEFAULT},
21
+ label: {type: 'string', default: ''},
22
+ name: {type: 'string', default: ''},
23
+ placeholder: {type: 'string', default: ''},
24
+ required: {type: 'boolean', default: false},
25
+ options: {type: 'array', default: []},
26
+ defaultValue: {type: 'string', default: ''},
27
+ value: {type: 'string', default: ''},
28
+ },
29
+ edit: createFormFieldEdit(options),
30
+ save: () => null,
31
+ } as unknown as BlockConfiguration<FormFieldAttributes>
32
+ }
@@ -0,0 +1,10 @@
1
+ export type {FormFieldAttributes, FormFieldOptions, FormFieldType} from './types'
2
+ export {createFormFieldBlock} from './factory'
3
+ export {FIELD_TYPES, FIELD_COLUMNS_RANGE, FIELD_COLUMNS_DEFAULT} from './constants'
4
+
5
+ import type {FormFieldOptions} from './types'
6
+
7
+ export const formFieldDefaults: FormFieldOptions = {
8
+ name: 'brilo/form-field',
9
+ parent: ['brilo/form-group'],
10
+ }
@@ -0,0 +1,18 @@
1
+ import {FIELD_TYPE_VALUES} from './constants'
2
+ import type {BriloBlockType} from '~/types'
3
+
4
+ export type FormFieldType = (typeof FIELD_TYPE_VALUES)[number]
5
+
6
+ export interface FormFieldAttributes extends Record<string, unknown> {
7
+ type: FormFieldType
8
+ columns: number
9
+ label: string
10
+ name: string
11
+ placeholder: string
12
+ required: boolean
13
+ options: string[]
14
+ defaultValue: string
15
+ value: string
16
+ }
17
+
18
+ export interface FormFieldOptions extends BriloBlockType {}
@@ -0,0 +1,16 @@
1
+ import {__} from '@wordpress/i18n'
2
+
3
+ export const PROCESSING_MODES = [
4
+ {value: 'internal', label: __('Interní', 'brilo-blocks')},
5
+ {value: 'external', label: __('Externí', 'brilo-blocks')},
6
+ ] as const
7
+
8
+ export const EXTERNAL_METHODS = [
9
+ {value: 'POST', label: 'POST'},
10
+ {value: 'GET', label: 'GET'},
11
+ ] as const
12
+
13
+ export const INTERNAL_SUBMIT_BEHAVIORS = [
14
+ {value: 'stay', label: __('Zůstat na stránce', 'brilo-blocks')},
15
+ {value: 'redirect', label: __('Přesměrovat na děkovnou stránku', 'brilo-blocks')},
16
+ ] as const
@@ -0,0 +1,190 @@
1
+ import {InspectorControls, RichText} from '@wordpress/block-editor'
2
+ import {FormTokenField, Notice, PanelBody, SelectControl, TextControl, ToggleControl} from '@wordpress/components'
3
+ import {useDispatch} from '@wordpress/data'
4
+ import {__} from '@wordpress/i18n'
5
+ import clsx from 'clsx'
6
+ import {useEffect} from 'react'
7
+ import {useGroupBlock} from '~/hooks/useGroupBlock'
8
+ import {EXTERNAL_METHODS, INTERNAL_SUBMIT_BEHAVIORS, PROCESSING_MODES} from './constants'
9
+ import type {ExternalMethod, FormGroupAttributes, FormGroupOptions, InternalSubmitBehavior, ProcessingMode} from './types'
10
+
11
+ const ALLOWED_BLOCKS = ['brilo/form-field']
12
+
13
+ export function createFormGroupEdit(options: FormGroupOptions) {
14
+ return function Edit({
15
+ attributes,
16
+ setAttributes,
17
+ clientId,
18
+ }: {
19
+ attributes: FormGroupAttributes
20
+ setAttributes: (a: Partial<FormGroupAttributes>) => void
21
+ clientId: string
22
+ }) {
23
+ const {lockPostSaving, unlockPostSaving} = useDispatch('core/editor') as unknown as {
24
+ lockPostSaving: (lockName: string) => void
25
+ unlockPostSaving: (lockName: string) => void
26
+ }
27
+
28
+ const processingMode = attributes.processingMode ?? 'internal'
29
+ const isInternal = processingMode === 'internal'
30
+ const isExternal = processingMode === 'external'
31
+ const recipients = Array.isArray(attributes.senders) ? attributes.senders : []
32
+ const isRecipientsMissing = isInternal && recipients.length === 0
33
+ const isExternalUrlMissing = isExternal && (attributes.externalUrl ?? '').trim() === ''
34
+
35
+ useEffect(() => {
36
+ const lockName = `brilo-form-group-${clientId}`
37
+
38
+ if (isRecipientsMissing || isExternalUrlMissing) {
39
+ lockPostSaving(lockName)
40
+ } else {
41
+ unlockPostSaving(lockName)
42
+ }
43
+
44
+ return () => unlockPostSaving(lockName)
45
+ }, [clientId, isRecipientsMissing, isExternalUrlMissing, lockPostSaving, unlockPostSaving])
46
+
47
+ const {blockProps, innerBlocksProps} = useGroupBlock({
48
+ blockClassName: clsx(options.blockClassName ?? 'g-form wp-block-section'),
49
+ containerClassName: [options.containerClassName ?? 'g-form__fields'],
50
+ allowedBlocks: options.allowedBlocks ?? ALLOWED_BLOCKS,
51
+ template: options.template,
52
+ orientation: 'horizontal',
53
+ layout: {type: 'default'},
54
+ })
55
+
56
+ return (
57
+ <>
58
+ <InspectorControls>
59
+ <PanelBody title={__('Formulář', 'brilo-blocks')}>
60
+ <TextControl
61
+ label={__('Název formuláře (volitelné)', 'brilo-blocks')}
62
+ value={attributes.formName ?? ''}
63
+ placeholder={__('Např. Kontaktní formulář', 'brilo-blocks')}
64
+ onChange={(formName) => setAttributes({formName})}
65
+ />
66
+
67
+ <SelectControl
68
+ label={__('Zpracování', 'brilo-blocks')}
69
+ value={processingMode}
70
+ options={PROCESSING_MODES.map((m) => ({label: m.label, value: m.value}))}
71
+ onChange={(mode) => setAttributes({processingMode: mode as ProcessingMode})}
72
+ />
73
+
74
+ {isExternal && (
75
+ <>
76
+ <SelectControl
77
+ label={__('Metoda odeslání', 'brilo-blocks')}
78
+ value={attributes.externalMethod ?? 'POST'}
79
+ options={EXTERNAL_METHODS.map((m) => ({label: m.label, value: m.value}))}
80
+ onChange={(externalMethod) => setAttributes({externalMethod: externalMethod as ExternalMethod})}
81
+ />
82
+
83
+ <TextControl
84
+ label={__('Externí URL', 'brilo-blocks')}
85
+ value={attributes.externalUrl ?? ''}
86
+ onChange={(externalUrl) => setAttributes({externalUrl})}
87
+ />
88
+
89
+ {isExternalUrlMissing && (
90
+ <Notice status="warning" isDismissible={false}>
91
+ {__('Pole „Externí URL“ je povinné pro externí zpracování.', 'brilo-blocks')}
92
+ </Notice>
93
+ )}
94
+ </>
95
+ )}
96
+
97
+ {isInternal && (
98
+ <>
99
+ <FormTokenField
100
+ label={__('Komu (příjemci)', 'brilo-blocks')}
101
+ value={recipients}
102
+ __next40pxDefaultSize
103
+ onChange={(senders) =>
104
+ setAttributes({
105
+ senders: (senders ?? [])
106
+ .map((item) => (typeof item === 'string' ? item.trim() : ''))
107
+ .filter((item): item is string => item.length > 0),
108
+ })
109
+ }
110
+ />
111
+
112
+ {isRecipientsMissing && (
113
+ <Notice status="warning" isDismissible={false}>
114
+ {__('Pole „Komu (příjemci)“ je povinné. Vyplňte alespoň jeden e-mail příjemce.', 'brilo-blocks')}
115
+ </Notice>
116
+ )}
117
+
118
+ <TextControl
119
+ label={__('Od koho (From email)', 'brilo-blocks')}
120
+ value={attributes.fromEmail ?? ''}
121
+ onChange={(fromEmail) => setAttributes({fromEmail})}
122
+ />
123
+
124
+ <TextControl
125
+ label={__('Předmět emailu', 'brilo-blocks')}
126
+ value={attributes.subject ?? ''}
127
+ placeholder={__('Potvrzení odeslaného formuláře', 'brilo-blocks')}
128
+ onChange={(subject) => setAttributes({subject})}
129
+ />
130
+
131
+ <SelectControl
132
+ label={__('Po odeslání', 'brilo-blocks')}
133
+ value={attributes.internalSubmitBehavior ?? 'stay'}
134
+ options={INTERNAL_SUBMIT_BEHAVIORS.map((b) => ({label: b.label, value: b.value}))}
135
+ onChange={(internalSubmitBehavior) =>
136
+ setAttributes({internalSubmitBehavior: internalSubmitBehavior as InternalSubmitBehavior})
137
+ }
138
+ />
139
+
140
+ {(attributes.internalSubmitBehavior ?? 'stay') === 'redirect' && (
141
+ <TextControl
142
+ label={__('URL děkovné stránky', 'brilo-blocks')}
143
+ value={attributes.internalRedirectUrl ?? ''}
144
+ onChange={(internalRedirectUrl) => setAttributes({internalRedirectUrl})}
145
+ />
146
+ )}
147
+
148
+ <TextControl
149
+ label={__('Úspěšná zpráva', 'brilo-blocks')}
150
+ value={attributes.successMessage ?? ''}
151
+ onChange={(successMessage) => setAttributes({successMessage})}
152
+ />
153
+ </>
154
+ )}
155
+
156
+ <TextControl
157
+ label={__('Titulek tlačítka odeslání', 'brilo-blocks')}
158
+ value={attributes.submit?.label ?? 'Odeslat'}
159
+ onChange={(label) => setAttributes({submit: {label}})}
160
+ />
161
+ </PanelBody>
162
+ </InspectorControls>
163
+
164
+ <div {...blockProps}>
165
+ <div {...innerBlocksProps} />
166
+
167
+ <div className="g-form__gdpr">
168
+ <div className="g-form__gdpr-header">
169
+ <strong>{__('GDPR obsah', 'brilo-blocks')}</strong>
170
+ <ToggleControl
171
+ label={__('S checkboxem?', 'brilo-blocks')}
172
+ checked={attributes.gdpr?.checkbox ?? true}
173
+ onChange={(checkbox) => setAttributes({gdpr: {content: attributes.gdpr?.content ?? '', checkbox}})}
174
+ />
175
+ </div>
176
+
177
+ <RichText
178
+ className="g-form__gdpr-content"
179
+ tagName="div"
180
+ value={attributes.gdpr?.content ?? ''}
181
+ allowedFormats={['core/bold', 'core/link']}
182
+ onChange={(content) => setAttributes({gdpr: {content, checkbox: attributes.gdpr?.checkbox ?? true}})}
183
+ placeholder={__('Text GDPR souhlasu…', 'brilo-blocks')}
184
+ />
185
+ </div>
186
+ </div>
187
+ </>
188
+ )
189
+ }
190
+ }
@@ -0,0 +1,41 @@
1
+ .g-form {
2
+ width: 100%;
3
+
4
+ &__fields {
5
+ display: grid;
6
+ grid-template-columns: repeat(12, minmax(0, 1fr));
7
+ gap: 16px;
8
+ padding: 16px;
9
+ padding-bottom: 56px;
10
+ outline: 1px dashed #ddd;
11
+
12
+ > * {
13
+ max-width: 100%;
14
+ }
15
+ }
16
+
17
+ &__gdpr {
18
+ margin-top: 16px;
19
+ padding: 16px;
20
+ border: 1px solid #ddd;
21
+ border-radius: 4px;
22
+ background: #fff;
23
+ }
24
+
25
+ &__gdpr-header {
26
+ display: flex;
27
+ flex-wrap: wrap;
28
+ justify-content: space-between;
29
+ align-items: center;
30
+ gap: 12px;
31
+ margin-bottom: 12px;
32
+ }
33
+
34
+ &__gdpr-content {
35
+ min-height: 56px;
36
+ padding: 10px 12px;
37
+ border: 1px solid #ddd;
38
+ border-radius: 4px;
39
+ background: #fff;
40
+ }
41
+ }
@@ -0,0 +1,35 @@
1
+ import {InnerBlocks} from '@wordpress/block-editor'
2
+ import type {BlockConfiguration} from '@wordpress/blocks'
3
+ import {__} from '@wordpress/i18n'
4
+ import {createFormGroupEdit} from './edit'
5
+ import type {FormGroupAttributes, FormGroupOptions} from './types'
6
+
7
+ export type {FormGroupAttributes, FormGroupOptions}
8
+
9
+ export function createFormGroupBlock(options: FormGroupOptions): BlockConfiguration<FormGroupAttributes> {
10
+ return {
11
+ name: options.name,
12
+ title: options.title ?? __('Formulář', 'brilo-blocks'),
13
+ description: options.description,
14
+ category: options.category ?? 'layout',
15
+ ...(options.parent && {parent: options.parent}),
16
+ icon: options.icon ?? 'feedback',
17
+ supports: {html: false, customClassName: false},
18
+ attributes: {
19
+ formName: {type: 'string', default: ''},
20
+ processingMode: {type: 'string', default: 'internal'},
21
+ externalMethod: {type: 'string', default: 'POST'},
22
+ externalUrl: {type: 'string', default: ''},
23
+ internalSubmitBehavior: {type: 'string', default: 'stay'},
24
+ internalRedirectUrl: {type: 'string', default: ''},
25
+ fromEmail: {type: 'string', default: ''},
26
+ senders: {type: 'array', default: []},
27
+ subject: {type: 'string', default: ''},
28
+ submit: {type: 'object', default: {label: 'Odeslat'}},
29
+ gdpr: {type: 'object', default: {content: '', checkbox: true}},
30
+ successMessage: {type: 'string', default: 'Formulář byl úspěšně odeslán.'},
31
+ },
32
+ edit: createFormGroupEdit(options),
33
+ save: () => <InnerBlocks.Content />,
34
+ } as unknown as BlockConfiguration<FormGroupAttributes>
35
+ }
@@ -0,0 +1,18 @@
1
+ export type {
2
+ ExternalMethod,
3
+ FormGroupAttributes,
4
+ FormGroupOptions,
5
+ InternalSubmitBehavior,
6
+ ProcessingMode,
7
+ } from './types'
8
+ export {createFormGroupBlock} from './factory'
9
+ export {EXTERNAL_METHODS, INTERNAL_SUBMIT_BEHAVIORS, PROCESSING_MODES} from './constants'
10
+
11
+ import type {FormGroupOptions} from './types'
12
+
13
+ export const formGroupDefaults: FormGroupOptions = {
14
+ name: 'brilo/form-group',
15
+ parent: ['brilo/base-section'],
16
+ allowedBlocks: ['brilo/form-field'],
17
+ template: [['brilo/form-field', {type: 'text'}]],
18
+ }
@@ -0,0 +1,22 @@
1
+ import type {BriloBlockType} from '~/types'
2
+
3
+ export type ProcessingMode = 'internal' | 'external'
4
+ export type ExternalMethod = 'POST' | 'GET'
5
+ export type InternalSubmitBehavior = 'stay' | 'redirect'
6
+
7
+ export interface FormGroupAttributes extends Record<string, unknown> {
8
+ formName: string
9
+ processingMode: ProcessingMode
10
+ externalMethod: ExternalMethod
11
+ externalUrl: string
12
+ internalSubmitBehavior: InternalSubmitBehavior
13
+ internalRedirectUrl: string
14
+ fromEmail: string
15
+ senders: string[]
16
+ subject: string
17
+ submit: {label: string}
18
+ gdpr: {content: string; checkbox: boolean}
19
+ successMessage: string
20
+ }
21
+
22
+ export interface FormGroupOptions extends BriloBlockType {}
@@ -0,0 +1,15 @@
1
+ import {__} from '@wordpress/i18n'
2
+ import {HEADING_STYLES} from '~/constants'
3
+
4
+ export const DEFAULT_HEADING_STYLES = HEADING_STYLES
5
+
6
+ export const DEFAULT_VARIANTS = [
7
+ {
8
+ value: 'default',
9
+ label: __('Výchozí', 'brilo-blocks'),
10
+ },
11
+ {
12
+ value: 'full-width',
13
+ label: __('Na plnou šířku', 'brilo-blocks'),
14
+ },
15
+ ] as const
@@ -0,0 +1,122 @@
1
+ import {InspectorControls, RichText} from '@wordpress/block-editor'
2
+ import {
3
+ PanelBody,
4
+ __experimentalToggleGroupControl as ToggleGroupControl,
5
+ __experimentalToggleGroupControlOption as ToggleGroupControlOption,
6
+ ColorPalette,
7
+ ToggleControl,
8
+ BaseControl,
9
+ } from '@wordpress/components'
10
+ import {__} from '@wordpress/i18n'
11
+ import {ImagePickerBody, ImagePickerControl} from '~/components/ImagePicker'
12
+ import {useGroupBlock} from '~/hooks/useGroupBlock'
13
+ import {DEFAULT_HEADING_STYLES, DEFAULT_VARIANTS} from './constants'
14
+ import {HEADING_LEVELS} from '~/constants'
15
+ import type {BannerGroupAttributes, BannerGroupOptions, HeadingLevels, HeadingStyles, Variants} from './types'
16
+ import clsx from 'clsx'
17
+
18
+ export function createBannerGroupEdit(options: BannerGroupOptions) {
19
+ const VARIANTS = options.variants ?? DEFAULT_VARIANTS
20
+ const HEADING_STYLES = options.headingStyles ?? DEFAULT_HEADING_STYLES
21
+
22
+ return function Edit({
23
+ attributes,
24
+ setAttributes,
25
+ }: {
26
+ attributes: BannerGroupAttributes
27
+ setAttributes: (a: Partial<BannerGroupAttributes>) => void
28
+ }) {
29
+ const {header, img, description, variant, hasBackgroundColor, backgroundColor, textColor} = attributes
30
+
31
+ const {blockProps, innerBlocksProps} = useGroupBlock({
32
+ blockClassName: [options.blockClassName ?? 'g-banner wp-block-section', `--variant-${variant}`],
33
+ containerClassName: options.containerClassName ?? 'g-banner__inner-blocks',
34
+ allowedBlocks: options.allowedBlocks,
35
+ template: options.template,
36
+ })
37
+
38
+ return (
39
+ <>
40
+ <InspectorControls>
41
+ <PanelBody title={__('Vzhled', 'brilo-blocks')}>
42
+ <ToggleGroupControl
43
+ label={__('Varianta', 'brilo-blocks')}
44
+ value={variant}
45
+ onChange={(value) => setAttributes({variant: value as Variants})}
46
+ isBlock
47
+ >
48
+ {VARIANTS.map((v) => (
49
+ <ToggleGroupControlOption key={v.value} value={v.value} label={v.label} />
50
+ ))}
51
+ </ToggleGroupControl>
52
+ </PanelBody>
53
+
54
+ <PanelBody title={__('Nadpis', 'brilo-blocks')} initialOpen={false}>
55
+ <ToggleGroupControl
56
+ label={__('Úroveň nadpisu', 'brilo-blocks')}
57
+ value={String(header.heading.level)}
58
+ onChange={(value) =>
59
+ setAttributes({header: {...header, heading: {...header.heading, level: Number(value) as HeadingLevels}}})
60
+ }
61
+ isBlock
62
+ >
63
+ {HEADING_LEVELS.map((l) => (
64
+ <ToggleGroupControlOption key={l} value={String(l)} label={`H${l}`} />
65
+ ))}
66
+ </ToggleGroupControl>
67
+ <ToggleGroupControl
68
+ label={__('Styl nadpisu', 'brilo-blocks')}
69
+ value={header.heading.style}
70
+ onChange={(value) => setAttributes({header: {...header, heading: {...header.heading, style: value as HeadingStyles}}})}
71
+ isBlock
72
+ >
73
+ {HEADING_STYLES.map((s) => (
74
+ <ToggleGroupControlOption key={s} value={s} label={s} />
75
+ ))}
76
+ </ToggleGroupControl>
77
+ </PanelBody>
78
+
79
+ <PanelBody title={__('Obrázek v pozadí', 'brilo-blocks')}>
80
+ <ImagePickerControl value={img} onChange={(val) => setAttributes({img: val})} />
81
+ </PanelBody>
82
+
83
+ <PanelBody title={__('Vzhled', 'brilo-blocks')}>
84
+ <ToggleControl
85
+ label={__('Použít barvu pozadí', 'brilo-blocks')}
86
+ checked={hasBackgroundColor}
87
+ onChange={(value) => setAttributes({hasBackgroundColor: value})}
88
+ />
89
+ {hasBackgroundColor && (
90
+ <BaseControl label={__('Barva pozadí', 'brilo-blocks')}>
91
+ <ColorPalette value={backgroundColor} onChange={(value) => setAttributes({backgroundColor: value})} enableAlpha={true} />
92
+ </BaseControl>
93
+ )}
94
+ <BaseControl label={__('Barva textu', 'brilo-blocks')}>
95
+ <ColorPalette value={textColor} onChange={(value) => setAttributes({textColor: value})} />
96
+ </BaseControl>
97
+ </PanelBody>
98
+ </InspectorControls>
99
+ <div {...blockProps}>
100
+ <div className="g-banner__content">
101
+ <RichText
102
+ tagName={`h${header.heading.level}` as HeadingStyles}
103
+ className={clsx('g-banner__heading', `--heading-style-${header.heading.style}`, 'u-text-editable')}
104
+ value={header.heading.title}
105
+ onChange={(value: string) => setAttributes({header: {...header, heading: {...header.heading, title: value}}})}
106
+ placeholder={__('Nadpis...', 'brilo-blocks')}
107
+ allowedFormats={['core/bold', 'core/italic']}
108
+ />
109
+ <RichText
110
+ tagName="div"
111
+ className="g-banner__description u-text-editable"
112
+ value={description}
113
+ onChange={(value: string) => setAttributes({description: value})}
114
+ placeholder={__('Popis...', 'brilo-blocks')}
115
+ />
116
+ </div>
117
+ <div {...innerBlocksProps} />
118
+ </div>
119
+ </>
120
+ )
121
+ }
122
+ }
@@ -0,0 +1,18 @@
1
+ .g-banner {
2
+ display: flex;
3
+ flex-wrap: wrap;
4
+ gap: 16px;
5
+ align-items: center;
6
+ }
7
+
8
+ .g-banner__content {
9
+ flex-grow: 1;
10
+ }
11
+
12
+ .g-banner__inner-blocks {
13
+ flex-shrink: 0;
14
+
15
+ .g-button-group {
16
+ padding: 16px;
17
+ }
18
+ }
@@ -0,0 +1,64 @@
1
+ import {InnerBlocks} from '@wordpress/block-editor'
2
+ import type {BlockConfiguration} from '@wordpress/blocks'
3
+ import {__} from '@wordpress/i18n'
4
+ import type {OptionArray, StringArray} from '~/types'
5
+ import {DEFAULT_VARIANTS, DEFAULT_HEADING_STYLES} from './constants'
6
+ import {createBannerGroupEdit} from './edit'
7
+ import type {BannerGroupAttributes, BannerGroupOptions} from './types'
8
+ import {HEADING_LEVELS} from '~/constants'
9
+ import {icon as defaultIcon} from './icon'
10
+
11
+ export type {BannerGroupAttributes, BannerGroupOptions}
12
+
13
+ export function createBannerGroupBlock<
14
+ TVariants extends OptionArray = typeof DEFAULT_VARIANTS,
15
+ THeadingStyles extends StringArray = typeof DEFAULT_HEADING_STYLES,
16
+ >(
17
+ options: BannerGroupOptions<TVariants, THeadingStyles>,
18
+ ): BlockConfiguration<BannerGroupAttributes<TVariants[number]['value'], THeadingStyles[number]>> {
19
+ const variants = options.variants ?? DEFAULT_VARIANTS
20
+ const headingStyles = options.headingStyles ?? DEFAULT_HEADING_STYLES
21
+
22
+ return {
23
+ name: options.name,
24
+ title: options.title ?? __('Banner', 'brilo-blocks'),
25
+ description: options.description,
26
+ category: options.category ?? 'layout',
27
+ icon: options.icon ?? defaultIcon,
28
+ ...(options.parent && {parent: options.parent}),
29
+ supports: {html: false, customClassName: false},
30
+ attributes: {
31
+ title: {
32
+ type: 'string',
33
+ default: '',
34
+ },
35
+ header: {
36
+ type: 'object',
37
+ default: {
38
+ heading: {title: '', level: HEADING_LEVELS[1], style: headingStyles[1] ?? headingStyles[0]},
39
+ },
40
+ },
41
+ img: {
42
+ type: 'object',
43
+ default: {
44
+ id: 0,
45
+ alt: '',
46
+ },
47
+ },
48
+ description: {
49
+ type: 'string',
50
+ default: '',
51
+ },
52
+ variant: {
53
+ type: 'string',
54
+ default: variants[0].value,
55
+ enum: variants.map((v) => v.value),
56
+ },
57
+ hasBackgroundColor: {type: 'boolean', default: false},
58
+ backgroundColor: {type: 'string', default: ''},
59
+ textColor: {type: 'string', default: ''},
60
+ },
61
+ edit: createBannerGroupEdit(options as unknown as BannerGroupOptions),
62
+ save: () => <InnerBlocks.Content />,
63
+ } as unknown as BlockConfiguration<BannerGroupAttributes<TVariants[number]['value'], THeadingStyles[number]>>
64
+ }
@@ -0,0 +1,13 @@
1
+ export const icon = (
2
+ <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
3
+ <rect x="0.5" y="5.5" width="19" height="8" stroke="black" fill="none" />
4
+ <path d="M2 8H8V9H2V8Z" fill="black" />
5
+ <path d="M2 10H9V11H2V10Z" fill="black" />
6
+ <path
7
+ fill-rule="evenodd"
8
+ clip-rule="evenodd"
9
+ d="M11.5 8C10.6716 8 10 8.67157 10 9.5C10 10.3284 10.6716 11 11.5 11H16.5C17.3284 11 18 10.3284 18 9.5C18 8.67157 17.3284 8 16.5 8H11.5ZM16 9H12V10H16V9Z"
10
+ fill="#357AB5"
11
+ />
12
+ </svg>
13
+ )
@@ -0,0 +1,11 @@
1
+ import {BannerGroupOptions} from '~/blocks/groups/banner-group/types'
2
+
3
+ export type {BannerGroupAttributes, BannerGroupOptions} from './factory'
4
+ export {createBannerGroupBlock} from './factory'
5
+
6
+ export const bannerGroupDefaults: BannerGroupOptions = {
7
+ name: 'brilo/banner-group',
8
+ parent: ['brilo/base-section'],
9
+ allowedBlocks: ['brilo/button-group'],
10
+ template: [['brilo/button-group', {}]],
11
+ }
@@ -0,0 +1,30 @@
1
+ import type {BriloBlockType, Media, OptionArray, StringArray} from '~/types'
2
+ import {DEFAULT_HEADING_STYLES, DEFAULT_VARIANTS} from './constants'
3
+ import {HEADING_LEVELS} from '~/constants'
4
+
5
+ export type Variants = (typeof DEFAULT_VARIANTS)[number]['value']
6
+ export type HeadingLevels = (typeof HEADING_LEVELS)[number]
7
+ export type HeadingStyles = (typeof DEFAULT_HEADING_STYLES)[number]
8
+
9
+ export interface BannerGroupAttributes<TVariant extends string = Variants, THeadingStyle extends string = HeadingStyles>
10
+ extends Record<string, unknown> {
11
+ title: string
12
+ header: {
13
+ heading: {title: string; level: HeadingLevels; style: THeadingStyle}
14
+ }
15
+ img: Media
16
+ hasBackgroundColor: boolean
17
+ backgroundColor: string
18
+ textColor: string
19
+ description: string
20
+ variant: TVariant
21
+ }
22
+
23
+ export interface BannerGroupOptions<
24
+ TVariants extends OptionArray = typeof DEFAULT_VARIANTS,
25
+ THeadingStyles extends StringArray = typeof DEFAULT_HEADING_STYLES,
26
+ > extends BriloBlockType {
27
+ variants?: TVariants
28
+ headingStyles?: THeadingStyles
29
+ headingLevels?: HeadingLevels
30
+ }