@brilo/base-blocks 0.1.44 → 0.1.45

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 (160) hide show
  1. package/build/.tsbuildinfo +1 -1
  2. package/build/blocks/compare/compare-item/index.js +1 -1
  3. package/build/blocks/faq/faq-group/edit.d.ts.map +1 -1
  4. package/build/blocks/faq/faq-group/edit.js +4 -2
  5. package/build/blocks/faq/faq-group/factory.d.ts.map +1 -1
  6. package/build/blocks/faq/faq-group/factory.js +2 -0
  7. package/build/blocks/faq/faq-group/types.d.ts +1 -0
  8. package/build/blocks/faq/faq-group/types.d.ts.map +1 -1
  9. package/build/blocks/gallery/gallery-group/edit.d.ts.map +1 -1
  10. package/build/blocks/gallery/gallery-group/edit.js +4 -2
  11. package/build/blocks/gallery/gallery-group/factory.d.ts.map +1 -1
  12. package/build/blocks/gallery/gallery-group/factory.js +2 -0
  13. package/build/blocks/gallery/gallery-group/types.d.ts +1 -0
  14. package/build/blocks/gallery/gallery-group/types.d.ts.map +1 -1
  15. package/build/blocks/groups/text-and-media-group/index.d.ts.map +1 -1
  16. package/build/blocks/groups/text-and-media-group/index.js +1 -0
  17. package/build/blocks/list/list-group/constants.d.ts +21 -0
  18. package/build/blocks/list/list-group/constants.d.ts.map +1 -0
  19. package/build/blocks/list/list-group/constants.js +12 -0
  20. package/build/blocks/list/list-group/edit.d.ts +6 -0
  21. package/build/blocks/list/list-group/edit.d.ts.map +1 -0
  22. package/build/blocks/list/list-group/edit.js +30 -0
  23. package/build/blocks/list/list-group/factory.d.ts +7 -0
  24. package/build/blocks/list/list-group/factory.d.ts.map +1 -0
  25. package/build/blocks/list/list-group/factory.js +29 -0
  26. package/build/blocks/list/list-group/icon.d.ts +2 -0
  27. package/build/blocks/list/list-group/icon.d.ts.map +1 -0
  28. package/build/blocks/list/list-group/icon.js +2 -0
  29. package/build/blocks/list/list-group/index.d.ts +5 -0
  30. package/build/blocks/list/list-group/index.d.ts.map +1 -0
  31. package/build/blocks/list/list-group/index.js +11 -0
  32. package/build/blocks/list/list-group/types.d.ts +22 -0
  33. package/build/blocks/list/list-group/types.d.ts.map +1 -0
  34. package/build/blocks/list/list-group/types.js +1 -0
  35. package/build/blocks/list/list-item/buildPreviewStyle.d.ts +20 -0
  36. package/build/blocks/list/list-item/buildPreviewStyle.d.ts.map +1 -0
  37. package/build/blocks/list/list-item/buildPreviewStyle.js +18 -0
  38. package/build/blocks/list/list-item/constants.d.ts +36 -0
  39. package/build/blocks/list/list-item/constants.d.ts.map +1 -0
  40. package/build/blocks/list/list-item/constants.js +16 -0
  41. package/build/blocks/list/list-item/edit.d.ts +11 -0
  42. package/build/blocks/list/list-item/edit.d.ts.map +1 -0
  43. package/build/blocks/list/list-item/edit.js +18 -0
  44. package/build/blocks/list/list-item/factory.d.ts +5 -0
  45. package/build/blocks/list/list-item/factory.d.ts.map +1 -0
  46. package/build/blocks/list/list-item/factory.js +29 -0
  47. package/build/blocks/list/list-item/index.d.ts +5 -0
  48. package/build/blocks/list/list-item/index.d.ts.map +1 -0
  49. package/build/blocks/list/list-item/index.js +7 -0
  50. package/build/blocks/list/list-item/types.d.ts +21 -0
  51. package/build/blocks/list/list-item/types.d.ts.map +1 -0
  52. package/build/blocks/list/list-item/types.js +1 -0
  53. package/build/blocks/priceplan/priceplan-group/edit.d.ts +5 -2
  54. package/build/blocks/priceplan/priceplan-group/edit.d.ts.map +1 -1
  55. package/build/blocks/priceplan/priceplan-group/edit.js +7 -3
  56. package/build/blocks/priceplan/priceplan-group/factory.d.ts.map +1 -1
  57. package/build/blocks/priceplan/priceplan-group/factory.js +2 -1
  58. package/build/blocks/priceplan/priceplan-group/types.d.ts +1 -0
  59. package/build/blocks/priceplan/priceplan-group/types.d.ts.map +1 -1
  60. package/build/blocks/review/review-group/edit.d.ts.map +1 -1
  61. package/build/blocks/review/review-group/edit.js +4 -3
  62. package/build/blocks/review/review-group/factory.d.ts.map +1 -1
  63. package/build/blocks/review/review-group/factory.js +2 -0
  64. package/build/blocks/review/review-group/types.d.ts +1 -0
  65. package/build/blocks/review/review-group/types.d.ts.map +1 -1
  66. package/build/blocks/sections/base-section/constants.d.ts +35 -0
  67. package/build/blocks/sections/base-section/constants.d.ts.map +1 -1
  68. package/build/blocks/sections/base-section/constants.js +10 -0
  69. package/build/blocks/sections/base-section/controls.d.ts.map +1 -1
  70. package/build/blocks/sections/base-section/controls.js +26 -12
  71. package/build/blocks/sections/base-section/edit.d.ts.map +1 -1
  72. package/build/blocks/sections/base-section/edit.js +12 -4
  73. package/build/blocks/sections/base-section/types.d.ts +9 -1
  74. package/build/blocks/sections/base-section/types.d.ts.map +1 -1
  75. package/build/blocks/signpost/signpost-group/edit.d.ts.map +1 -1
  76. package/build/blocks/signpost/signpost-group/edit.js +4 -2
  77. package/build/blocks/signpost/signpost-group/factory.d.ts.map +1 -1
  78. package/build/blocks/signpost/signpost-group/factory.js +2 -0
  79. package/build/blocks/signpost/signpost-group/types.d.ts +1 -0
  80. package/build/blocks/signpost/signpost-group/types.d.ts.map +1 -1
  81. package/build/blocks/step/step-group/edit.d.ts.map +1 -1
  82. package/build/blocks/step/step-group/edit.js +4 -3
  83. package/build/blocks/step/step-group/factory.d.ts.map +1 -1
  84. package/build/blocks/step/step-group/factory.js +2 -0
  85. package/build/blocks/step/step-group/types.d.ts +1 -0
  86. package/build/blocks/step/step-group/types.d.ts.map +1 -1
  87. package/build/blocks/text-and-form/text-and-form-text-column/index.d.ts.map +1 -1
  88. package/build/blocks/text-and-form/text-and-form-text-column/index.js +1 -0
  89. package/build/blocks/usp/usp-group/edit.d.ts.map +1 -1
  90. package/build/blocks/usp/usp-group/edit.js +4 -3
  91. package/build/blocks/usp/usp-group/factory.d.ts.map +1 -1
  92. package/build/blocks/usp/usp-group/factory.js +2 -0
  93. package/build/blocks/usp/usp-group/types.d.ts +1 -0
  94. package/build/blocks/usp/usp-group/types.d.ts.map +1 -1
  95. package/build/blocks/video/video-group/constants.d.ts +1 -0
  96. package/build/blocks/video/video-group/constants.d.ts.map +1 -1
  97. package/build/blocks/video/video-group/constants.js +1 -0
  98. package/build/blocks/video/video-group/edit.d.ts.map +1 -1
  99. package/build/blocks/video/video-group/edit.js +7 -5
  100. package/build/blocks/video/video-group/factory.d.ts.map +1 -1
  101. package/build/blocks/video/video-group/factory.js +5 -1
  102. package/build/blocks/video/video-group/types.d.ts +1 -0
  103. package/build/blocks/video/video-group/types.d.ts.map +1 -1
  104. package/build/components/ItemSpacingControl/index.d.ts +23 -0
  105. package/build/components/ItemSpacingControl/index.d.ts.map +1 -0
  106. package/build/components/ItemSpacingControl/index.js +32 -0
  107. package/build/index.d.ts +4 -0
  108. package/build/index.d.ts.map +1 -1
  109. package/build/index.js +2 -0
  110. package/package.json +1 -1
  111. package/src/blocks/compare/compare-item/index.ts +1 -1
  112. package/src/blocks/faq/faq-group/edit.tsx +4 -1
  113. package/src/blocks/faq/faq-group/factory.tsx +2 -0
  114. package/src/blocks/faq/faq-group/types.ts +1 -0
  115. package/src/blocks/gallery/gallery-group/edit.tsx +4 -1
  116. package/src/blocks/gallery/gallery-group/factory.tsx +2 -0
  117. package/src/blocks/gallery/gallery-group/types.ts +1 -0
  118. package/src/blocks/groups/text-and-media-group/index.ts +1 -0
  119. package/src/blocks/list/list-group/constants.ts +15 -0
  120. package/src/blocks/list/list-group/edit.tsx +102 -0
  121. package/src/blocks/list/list-group/editor.scss +14 -0
  122. package/src/blocks/list/list-group/factory.tsx +35 -0
  123. package/src/blocks/list/list-group/icon.tsx +11 -0
  124. package/src/blocks/list/list-group/index.ts +15 -0
  125. package/src/blocks/list/list-group/types.ts +21 -0
  126. package/src/blocks/list/list-item/buildPreviewStyle.ts +52 -0
  127. package/src/blocks/list/list-item/constants.ts +18 -0
  128. package/src/blocks/list/list-item/edit.tsx +108 -0
  129. package/src/blocks/list/list-item/editor.scss +108 -0
  130. package/src/blocks/list/list-item/factory.tsx +33 -0
  131. package/src/blocks/list/list-item/index.ts +11 -0
  132. package/src/blocks/list/list-item/types.ts +23 -0
  133. package/src/blocks/priceplan/priceplan-group/edit.tsx +21 -5
  134. package/src/blocks/priceplan/priceplan-group/factory.tsx +2 -1
  135. package/src/blocks/priceplan/priceplan-group/types.ts +3 -1
  136. package/src/blocks/review/review-group/edit.tsx +4 -2
  137. package/src/blocks/review/review-group/factory.tsx +2 -0
  138. package/src/blocks/review/review-group/types.ts +1 -0
  139. package/src/blocks/sections/base-section/constants.ts +14 -0
  140. package/src/blocks/sections/base-section/controls.tsx +93 -9
  141. package/src/blocks/sections/base-section/edit.tsx +10 -2
  142. package/src/blocks/sections/base-section/types.ts +14 -1
  143. package/src/blocks/signpost/signpost-group/edit.tsx +4 -1
  144. package/src/blocks/signpost/signpost-group/factory.tsx +2 -0
  145. package/src/blocks/signpost/signpost-group/types.ts +1 -0
  146. package/src/blocks/step/step-group/edit.tsx +4 -2
  147. package/src/blocks/step/step-group/factory.tsx +2 -0
  148. package/src/blocks/step/step-group/types.ts +1 -0
  149. package/src/blocks/text-and-form/text-and-form-text-column/index.ts +1 -0
  150. package/src/blocks/usp/usp-group/edit.tsx +4 -2
  151. package/src/blocks/usp/usp-group/factory.tsx +2 -0
  152. package/src/blocks/usp/usp-group/types.ts +1 -0
  153. package/src/blocks/video/video-group/constants.ts +2 -0
  154. package/src/blocks/video/video-group/edit.tsx +26 -2
  155. package/src/blocks/video/video-group/editor.scss +6 -1
  156. package/src/blocks/video/video-group/factory.tsx +5 -1
  157. package/src/blocks/video/video-group/types.ts +1 -0
  158. package/src/components/ItemSpacingControl/index.tsx +59 -0
  159. package/src/editor.scss +2 -0
  160. package/src/index.ts +4 -0
@@ -11,6 +11,7 @@ import {
11
11
  } from '@wordpress/components'
12
12
  import {__} from '@wordpress/i18n'
13
13
  import clsx from 'clsx'
14
+ import {ItemSpacingPanel, itemSpacingStyle} from '~/components/ItemSpacingControl'
14
15
  import {useGroupBlock} from '~/hooks/useGroupBlock'
15
16
  import {useTenantColorPalette} from '~/hooks/useTenantColorPalette'
16
17
  import {COLUMNS, DEFAULT_SHADOWS, VARIANTS} from './constants'
@@ -21,7 +22,7 @@ export function createReviewGroupEdit(options: ReviewGroupOptions) {
21
22
  const exclude = options.exclude ?? []
22
23
 
23
24
  return function ReviewGroupEdit({attributes, setAttributes}: BlockEditProps<ReviewGroupAttributes>) {
24
- const {columns, image, variant, style} = attributes
25
+ const {columns, image, variant, style, spacing} = attributes
25
26
  const {paletteColors} = useTenantColorPalette()
26
27
 
27
28
  const {blockProps, innerBlocksProps} = useGroupBlock({
@@ -31,7 +32,7 @@ export function createReviewGroupEdit(options: ReviewGroupOptions) {
31
32
  image === 'none' && '--image-none',
32
33
  ),
33
34
  containerClassName: [options.containerClassName ?? 'u-grid-responsive-blocks-list', `--col-${columns}`],
34
- containerStyle: {'--grid-max-col-count': columns},
35
+ containerStyle: {'--grid-max-col-count': columns, ...itemSpacingStyle(spacing)},
35
36
  allowedBlocks: options.allowedBlocks ?? ['brilo/review-item'],
36
37
  template: options.template ?? [
37
38
  ['brilo/review-item', {}],
@@ -106,6 +107,7 @@ export function createReviewGroupEdit(options: ReviewGroupOptions) {
106
107
  </BaseControl>
107
108
  </PanelBody>
108
109
  )}
110
+ <ItemSpacingPanel spacing={spacing} onChange={(v) => setAttributes({spacing: v})} />
109
111
  </InspectorControls>
110
112
  <div {...blockProps}>
111
113
  <div {...innerBlocksProps} />
@@ -1,6 +1,7 @@
1
1
  import {InnerBlocks} from '@wordpress/block-editor'
2
2
  import type {BlockConfiguration} from '@wordpress/blocks'
3
3
  import {__} from '@wordpress/i18n'
4
+ import {ITEM_SPACING_ATTRIBUTE} from '~/components/ItemSpacingControl'
4
5
  import type {OptionArray} from '~/types'
5
6
  import {COLUMNS, DEFAULT_SHADOWS, VARIANTS} from './constants'
6
7
  import {createReviewGroupEdit} from './edit'
@@ -29,6 +30,7 @@ export function createReviewGroupBlock<TVariants extends OptionArray = typeof VA
29
30
  type: 'string',
30
31
  default: 'none',
31
32
  },
33
+ ...ITEM_SPACING_ATTRIBUTE,
32
34
  }
33
35
 
34
36
  if (!exclude.includes('colors')) {
@@ -19,6 +19,7 @@ export interface ReviewGroupAttributes<TVariant extends string = Variant> extend
19
19
  backgroundColor: string
20
20
  textColor: string
21
21
  }
22
+ spacing?: number
22
23
  }
23
24
 
24
25
  export interface ReviewGroupOptions<TVariants extends OptionArray = typeof VARIANTS> extends BriloBlockType {
@@ -58,6 +58,20 @@ export const DECORATION_OFFSET_UNITS = [
58
58
  export const BACKGROUND_IMAGE_FITS = [
59
59
  {value: 'cover', label: __('Vyplnit (cover)', 'brilo-blocks')},
60
60
  {value: 'contain', label: __('Celý obrázek (contain)', 'brilo-blocks')},
61
+ {value: 'custom', label: __('Vlastní (px)', 'brilo-blocks')},
62
+ ] as const
63
+
64
+ export const FLUID_DECORATION_FITS = [{value: 'auto', label: __('Automaticky (výška)', 'brilo-blocks')}, ...BACKGROUND_IMAGE_FITS] as const
65
+
66
+ export const BACKGROUND_IMAGE_SIZE_VALUE_DEFAULT = '32px'
67
+
68
+ export const BACKGROUND_IMAGE_SIZE_UNITS = [{value: 'px', label: 'px', default: 32}]
69
+
70
+ export const BACKGROUND_IMAGE_REPEATS = [
71
+ {value: 'no-repeat', label: __('Žádné', 'brilo-blocks')},
72
+ {value: 'repeat-x', label: __('Vodorovně (X)', 'brilo-blocks')},
73
+ {value: 'repeat-y', label: __('Svisle (Y)', 'brilo-blocks')},
74
+ {value: 'repeat', label: __('Obojí', 'brilo-blocks')},
61
75
  ] as const
62
76
 
63
77
  export const BACKGROUND_IMAGE_POSITIONS = [
@@ -18,6 +18,7 @@ import type {
18
18
  BackgroundImage,
19
19
  BackgroundImageFit,
20
20
  BackgroundImagePosition,
21
+ BackgroundImageRepeat,
21
22
  BaseBlockAttributes,
22
23
  Border,
23
24
  Decoration,
@@ -27,12 +28,16 @@ import type {
27
28
  DecorationTranslate,
28
29
  ExcludableBaseAttr,
29
30
  FluidDecoration,
31
+ FluidDecorationFit,
30
32
  FluidDecorationImage,
31
33
  } from './types'
32
34
  import {
33
35
  BACKGROUND_IMAGE_FITS,
34
36
  BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT,
35
37
  BACKGROUND_IMAGE_POSITIONS,
38
+ BACKGROUND_IMAGE_REPEATS,
39
+ BACKGROUND_IMAGE_SIZE_UNITS,
40
+ BACKGROUND_IMAGE_SIZE_VALUE_DEFAULT,
36
41
  DECORATION_DEPTHS,
37
42
  DECORATION_MAX_WIDTH_DEFAULT,
38
43
  DECORATION_MAX_WIDTH_UNITS,
@@ -41,25 +46,41 @@ import {
41
46
  DECORATION_POSITIONS,
42
47
  DECORATION_TRANSLATES,
43
48
  FLUID_DECORATION_DEFAULT_HEIGHT,
49
+ FLUID_DECORATION_FITS,
44
50
  FLUID_DECORATION_HEIGHT_PRESETS,
45
51
  FLUID_DECORATION_UNITS,
46
52
  SPACING_POSITIONS,
47
53
  SPACING_SIZES,
48
54
  } from './constants'
49
55
 
56
+ // Shared shape behind every control's `update(patch)`: fill in defaults, layer the current
57
+ // value on top, then the patch — so a patch only needs to name the field(s) actually changing.
58
+ function mergeUpdate<T>(defaults: T, value: T | undefined, patch: Partial<T>): T {
59
+ return {...defaults, ...value, ...patch}
60
+ }
61
+
50
62
  interface FluidDecorationControlProps {
51
63
  label: string
64
+ placement: 'top' | 'bottom'
52
65
  value?: FluidDecoration
53
66
  onChange: (value: FluidDecoration | undefined) => void
54
67
  }
55
68
 
56
- function FluidDecorationControl({label, value, onChange}: FluidDecorationControlProps) {
69
+ function FluidDecorationControl({label, placement, value, onChange}: FluidDecorationControlProps) {
57
70
  const img = value?.img
58
71
  const height = value?.height ?? FLUID_DECORATION_DEFAULT_HEIGHT
72
+ const fit = value?.fit ?? 'auto'
73
+ const sizeValue = value?.sizeValue ?? BACKGROUND_IMAGE_SIZE_VALUE_DEFAULT
74
+ // Matches the twig template's per-side default (top/bottom left) so the field only starts
75
+ // overriding the frontend once the editor actually writes an explicit value.
76
+ const bgPosition = value?.bgPosition ?? (placement === 'bottom' ? 'left bottom' : 'left top')
77
+ const repeat = value?.repeat ?? 'repeat-x'
78
+
79
+ const update = (patch: Partial<FluidDecoration>) => onChange(mergeUpdate({img, height, fit, bgPosition, repeat}, value, patch))
59
80
 
60
81
  const handleSelect = (media: {id: number; url: string; alt: string; width?: number; height?: number}) => {
61
82
  const nextImg: FluidDecorationImage = {id: media.id, src: media.url, alt: media.alt ?? '', width: media.width, height: media.height}
62
- onChange({img: nextImg, height})
83
+ update({img: nextImg})
63
84
  }
64
85
 
65
86
  const handleRemove = () => onChange(undefined)
@@ -93,15 +114,49 @@ function FluidDecorationControl({label, value, onChange}: FluidDecorationControl
93
114
  label={__('Výška', 'brilo-blocks')}
94
115
  value={height}
95
116
  units={FLUID_DECORATION_UNITS}
96
- onChange={(next) => onChange({img, height: (next as string) ?? FLUID_DECORATION_DEFAULT_HEIGHT})}
117
+ onChange={(next) => update({height: (next as string) ?? FLUID_DECORATION_DEFAULT_HEIGHT})}
97
118
  />
98
119
  <ButtonGroup>
99
120
  {FLUID_DECORATION_HEIGHT_PRESETS.map((preset) => (
100
- <Button key={preset} variant="secondary" size="small" onClick={() => onChange({img, height: `${preset}px`})}>
121
+ <Button key={preset} variant="secondary" size="small" onClick={() => update({height: `${preset}px`})}>
101
122
  {preset}
102
123
  </Button>
103
124
  ))}
104
125
  </ButtonGroup>
126
+
127
+ <ToggleGroupControl
128
+ label={__('Přizpůsobení', 'brilo-blocks')}
129
+ value={fit}
130
+ onChange={(next) => update({fit: next as FluidDecorationFit})}
131
+ isBlock
132
+ >
133
+ {FLUID_DECORATION_FITS.map((f) => (
134
+ <ToggleGroupControlOption key={f.value} value={f.value} label={f.label} />
135
+ ))}
136
+ </ToggleGroupControl>
137
+
138
+ {fit === 'custom' && (
139
+ <UnitControl
140
+ label={__('Velikost', 'brilo-blocks')}
141
+ value={sizeValue}
142
+ units={BACKGROUND_IMAGE_SIZE_UNITS}
143
+ onChange={(next) => update({sizeValue: (next as string) ?? BACKGROUND_IMAGE_SIZE_VALUE_DEFAULT})}
144
+ />
145
+ )}
146
+
147
+ <SelectControl<string>
148
+ label={__('Pozice obrázku', 'brilo-blocks')}
149
+ value={bgPosition}
150
+ options={[...BACKGROUND_IMAGE_POSITIONS]}
151
+ onChange={(next) => update({bgPosition: next as BackgroundImagePosition})}
152
+ />
153
+
154
+ <SelectControl<string>
155
+ label={__('Opakování', 'brilo-blocks')}
156
+ value={repeat}
157
+ options={[...BACKGROUND_IMAGE_REPEATS]}
158
+ onChange={(next) => update({repeat: next as BackgroundImageRepeat})}
159
+ />
105
160
  </>
106
161
  )}
107
162
  </BaseControl>
@@ -122,7 +177,8 @@ function DecorationControl({value, onChange}: DecorationControlProps) {
122
177
  const offsetX = value?.offsetX ?? DECORATION_OFFSET_DEFAULT
123
178
  const offsetY = value?.offsetY ?? DECORATION_OFFSET_DEFAULT
124
179
 
125
- const update = (patch: Partial<Decoration>) => onChange({img, position, depth, translate, maxWidth, offsetX, offsetY, ...value, ...patch})
180
+ const update = (patch: Partial<Decoration>) =>
181
+ onChange(mergeUpdate({img, position, depth, translate, maxWidth, offsetX, offsetY}, value, patch))
126
182
 
127
183
  const handleSelect = (media: {id: number; url: string; alt: string; width?: number; height?: number}) => {
128
184
  const nextImg: DecorationImage = {id: media.id, src: media.url, alt: media.alt ?? '', width: media.width, height: media.height}
@@ -234,11 +290,14 @@ function BackgroundImageControl({value, onChange}: BackgroundImageControlProps)
234
290
  const {paletteColors} = useTenantColorPalette()
235
291
  const img = value?.img
236
292
  const fit = value?.fit ?? 'cover'
293
+ const sizeValue = value?.sizeValue ?? BACKGROUND_IMAGE_SIZE_VALUE_DEFAULT
237
294
  const position = value?.position ?? 'center center'
295
+ const repeat = value?.repeat ?? 'no-repeat'
238
296
  const overlayColor = value?.overlay?.color
239
297
  const overlayOpacity = value?.overlay?.opacity ?? BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT
240
298
 
241
- const update = (patch: Partial<BackgroundImage>) => onChange({img, fit, position, overlay: value?.overlay, ...value, ...patch})
299
+ const update = (patch: Partial<BackgroundImage>) =>
300
+ onChange(mergeUpdate({img, fit, position, repeat, overlay: value?.overlay}, value, patch))
242
301
 
243
302
  const handleSelect = (media: {id: number; url: string; alt: string; width?: number; height?: number}) => {
244
303
  const nextImg: FluidDecorationImage = {id: media.id, src: media.url, alt: media.alt ?? '', width: media.width, height: media.height}
@@ -283,6 +342,15 @@ function BackgroundImageControl({value, onChange}: BackgroundImageControlProps)
283
342
  ))}
284
343
  </ToggleGroupControl>
285
344
 
345
+ {fit === 'custom' && (
346
+ <UnitControl
347
+ label={__('Velikost', 'brilo-blocks')}
348
+ value={sizeValue}
349
+ units={BACKGROUND_IMAGE_SIZE_UNITS}
350
+ onChange={(next) => update({sizeValue: (next as string) ?? BACKGROUND_IMAGE_SIZE_VALUE_DEFAULT})}
351
+ />
352
+ )}
353
+
286
354
  <SelectControl<string>
287
355
  label={__('Pozice', 'brilo-blocks')}
288
356
  value={position}
@@ -290,9 +358,15 @@ function BackgroundImageControl({value, onChange}: BackgroundImageControlProps)
290
358
  onChange={(next) => update({position: next as BackgroundImagePosition})}
291
359
  />
292
360
 
361
+ <SelectControl<string>
362
+ label={__('Opakování', 'brilo-blocks')}
363
+ value={repeat}
364
+ options={[...BACKGROUND_IMAGE_REPEATS]}
365
+ onChange={(next) => update({repeat: next as BackgroundImageRepeat})}
366
+ />
367
+
293
368
  <BaseControl
294
369
  label={__('Překryv barvou', 'brilo-blocks')}
295
- __nextHasNoMarginBottom
296
370
  help={__('Ztmavení/zabarvení obrázku pro lepší čitelnost textu.', 'brilo-blocks')}
297
371
  >
298
372
  <ColorPalette
@@ -463,8 +537,18 @@ export function BaseControls({attributes, setAttributes, exclude}: BaseControlsP
463
537
 
464
538
  {!exclude.includes('decorations') && (
465
539
  <PanelBody title={__('Fluidní dekorace', 'brilo-blocks')} initialOpen={false}>
466
- <FluidDecorationControl label={__('Nahoře', 'brilo-blocks')} value={fluid.top} onChange={(value) => setFluid('top', value)} />
467
- <FluidDecorationControl label={__('Dole', 'brilo-blocks')} value={fluid.bottom} onChange={(value) => setFluid('bottom', value)} />
540
+ <FluidDecorationControl
541
+ label={__('Nahoře', 'brilo-blocks')}
542
+ placement="top"
543
+ value={fluid.top}
544
+ onChange={(value) => setFluid('top', value)}
545
+ />
546
+ <FluidDecorationControl
547
+ label={__('Dole', 'brilo-blocks')}
548
+ placement="bottom"
549
+ value={fluid.bottom}
550
+ onChange={(value) => setFluid('bottom', value)}
551
+ />
468
552
  </PanelBody>
469
553
  )}
470
554
 
@@ -3,6 +3,7 @@ import type {BlockEditProps} from '@wordpress/blocks'
3
3
  import type {CSSProperties} from 'react'
4
4
  import type {BaseBlockAttributes, BaseSectionOptions} from './types'
5
5
  import {BaseControls} from './controls'
6
+ import {BACKGROUND_IMAGE_SIZE_VALUE_DEFAULT} from './constants'
6
7
 
7
8
  export function createBaseSectionEdit<TExtra extends Record<string, unknown> = Record<string, never>>(options: BaseSectionOptions<TExtra>) {
8
9
  const EXCLUDE = options.exclude ?? []
@@ -25,11 +26,18 @@ export function createBaseSectionEdit<TExtra extends Record<string, unknown> = R
25
26
  ...(bgImageSrc
26
27
  ? {
27
28
  backgroundImage: [tintLayer, `url(${bgImageSrc})`].filter(Boolean).join(', '),
28
- backgroundSize: [tintLayer ? '100% 100%' : null, backgroundImage?.fit ?? 'cover'].filter(Boolean).join(', '),
29
+ backgroundSize: [
30
+ tintLayer ? '100% 100%' : null,
31
+ backgroundImage?.fit === 'custom'
32
+ ? (backgroundImage?.sizeValue ?? BACKGROUND_IMAGE_SIZE_VALUE_DEFAULT)
33
+ : (backgroundImage?.fit ?? 'cover'),
34
+ ]
35
+ .filter(Boolean)
36
+ .join(', '),
29
37
  backgroundPosition: [tintLayer ? 'center center' : null, backgroundImage?.position ?? 'center center']
30
38
  .filter(Boolean)
31
39
  .join(', '),
32
- backgroundRepeat: 'no-repeat',
40
+ backgroundRepeat: [tintLayer ? 'no-repeat' : null, backgroundImage?.repeat ?? 'no-repeat'].filter(Boolean).join(', '),
33
41
  padding: '16px',
34
42
  }
35
43
  : {}),
@@ -13,6 +13,12 @@ export interface FluidDecorationImage {
13
13
  export interface FluidDecoration {
14
14
  img?: FluidDecorationImage
15
15
  height: string
16
+ fit?: FluidDecorationFit
17
+ sizeValue?: string
18
+ // Named bgPosition (not "position") — the twig include merges its own top/bottom placement
19
+ // key as "position" on top of this object, which would silently clobber a same-named field.
20
+ bgPosition?: BackgroundImagePosition
21
+ repeat?: BackgroundImageRepeat
16
22
  }
17
23
 
18
24
  export type DecorationImage = FluidDecorationImage
@@ -31,7 +37,12 @@ export interface Decoration {
31
37
  offsetY?: string
32
38
  }
33
39
 
34
- export type BackgroundImageFit = 'cover' | 'contain'
40
+ export type BackgroundImageFit = 'cover' | 'contain' | 'custom'
41
+
42
+ // Fluid decorations additionally support 'auto' (original height-driven sizing, no crop/fit).
43
+ export type FluidDecorationFit = BackgroundImageFit | 'auto'
44
+
45
+ export type BackgroundImageRepeat = 'no-repeat' | 'repeat' | 'repeat-x' | 'repeat-y'
35
46
 
36
47
  export type BackgroundImagePosition =
37
48
  | 'left top'
@@ -52,7 +63,9 @@ export interface BackgroundImageOverlay {
52
63
  export interface BackgroundImage {
53
64
  img?: FluidDecorationImage
54
65
  fit?: BackgroundImageFit
66
+ sizeValue?: string
55
67
  position?: BackgroundImagePosition
68
+ repeat?: BackgroundImageRepeat
56
69
  overlay?: BackgroundImageOverlay
57
70
  }
58
71
 
@@ -10,6 +10,7 @@ import {
10
10
  } from '@wordpress/components'
11
11
  import {__} from '@wordpress/i18n'
12
12
  import clsx from 'clsx'
13
+ import {ItemSpacingPanel, itemSpacingStyle} from '~/components/ItemSpacingControl'
13
14
  import {useGroupBlock} from '~/hooks/useGroupBlock'
14
15
  import {useTenantColorPalette} from '~/hooks/useTenantColorPalette'
15
16
  import {
@@ -34,7 +35,7 @@ export function createSignpostGroupEdit(options: SignpostGroupOptions) {
34
35
  attributes: SignpostGroupAttributes
35
36
  setAttributes: (a: Partial<SignpostGroupAttributes>) => void
36
37
  }) {
37
- const {columns, headingLevel, ratio, img, style, padding} = attributes
38
+ const {columns, headingLevel, ratio, img, style, padding, spacing} = attributes
38
39
  const clipPath = img?.clipPath ?? 'none'
39
40
  const {paletteColors} = useTenantColorPalette()
40
41
 
@@ -45,6 +46,7 @@ export function createSignpostGroupEdit(options: SignpostGroupOptions) {
45
46
  '--grid-max-col-count': columns,
46
47
  // Inherited by every signpost item inside the container.
47
48
  ...(IMAGE_CLIP_PATH_VALUES[clipPath] && {'--signpost-image-clip-path': IMAGE_CLIP_PATH_VALUES[clipPath]}),
49
+ ...itemSpacingStyle(spacing),
48
50
  },
49
51
  allowedBlocks: options.allowedBlocks,
50
52
  orientation: 'horizontal',
@@ -162,6 +164,7 @@ export function createSignpostGroupEdit(options: SignpostGroupOptions) {
162
164
  />
163
165
  </PanelBody>
164
166
  )}
167
+ <ItemSpacingPanel spacing={spacing} onChange={(v) => setAttributes({spacing: v})} />
165
168
  </InspectorControls>
166
169
  <div {...blockProps}>
167
170
  <div {...innerBlocksProps} />
@@ -1,6 +1,7 @@
1
1
  import {InnerBlocks} from '@wordpress/block-editor'
2
2
  import type {BlockConfiguration} from '@wordpress/blocks'
3
3
  import {__} from '@wordpress/i18n'
4
+ import {ITEM_SPACING_ATTRIBUTE} from '~/components/ItemSpacingControl'
4
5
  import {COLUMNS, DEFAULT_IMAGE_CLIP_PATHS, DEFAULT_SHADOWS, HEADING_LEVELS, RATIOS, TEXT_ALIGNS} from './constants'
5
6
  import {createSignpostGroupEdit} from './edit'
6
7
  import {icon as defaultIcon} from './icon'
@@ -31,6 +32,7 @@ export function createSignpostGroupBlock(options: SignpostGroupOptions): BlockCo
31
32
  type: 'object',
32
33
  default: {clipPath: DEFAULT_IMAGE_CLIP_PATHS[0].value},
33
34
  },
35
+ ...ITEM_SPACING_ATTRIBUTE,
34
36
  }
35
37
 
36
38
  if (!exclude.includes('colors')) {
@@ -23,6 +23,7 @@ export interface SignpostGroupAttributes extends Record<string, unknown> {
23
23
  textAlign: SignpostTextAlign
24
24
  }
25
25
  padding: {value: number}
26
+ spacing?: number
26
27
  }
27
28
 
28
29
  export interface SignpostGroupOptions extends BriloBlockType {
@@ -7,6 +7,7 @@ import {
7
7
  } from '@wordpress/components'
8
8
  import {__} from '@wordpress/i18n'
9
9
  import clsx from 'clsx'
10
+ import {ItemSpacingPanel, itemSpacingStyle} from '~/components/ItemSpacingControl'
10
11
  import {useGroupBlock} from '~/hooks/useGroupBlock'
11
12
  import type {OptionArray} from '~/types'
12
13
  import type {StepGroupAttributes, StepGroupOptions, StepVariant} from './types'
@@ -22,12 +23,12 @@ export function createStepGroupEdit<TVariants extends OptionArray = typeof DEFAU
22
23
  attributes: StepGroupAttributes
23
24
  setAttributes: (a: Partial<StepGroupAttributes>) => void
24
25
  }) {
25
- const {variant, disableIcon} = attributes
26
+ const {variant, disableIcon, spacing} = attributes
26
27
 
27
28
  const {blockProps, innerBlocksProps} = useGroupBlock({
28
29
  blockClassName: clsx(options.blockClassName ?? 'g-step wp-block-section', `--variant-${variant}`, disableIcon && '--disable-icon'),
29
30
  containerClassName: [options.containerClassName ?? 'g-step__container', 'u-grid-responsive', '--cols-3'],
30
- containerStyle: {'--grid-max-col-count': 3},
31
+ containerStyle: {'--grid-max-col-count': 3, ...itemSpacingStyle(spacing)},
31
32
  allowedBlocks: options.allowedBlocks,
32
33
  orientation: 'horizontal',
33
34
  template: options.template,
@@ -54,6 +55,7 @@ export function createStepGroupEdit<TVariants extends OptionArray = typeof DEFAU
54
55
  onChange={(v) => setAttributes({disableIcon: v})}
55
56
  />
56
57
  </PanelBody>
58
+ <ItemSpacingPanel spacing={spacing} onChange={(v) => setAttributes({spacing: v})} />
57
59
  </InspectorControls>
58
60
  <div {...blockProps}>
59
61
  <div {...innerBlocksProps} />
@@ -5,6 +5,7 @@ import {DEFAULT_VARIANTS} from './constants'
5
5
  import {createStepGroupEdit} from './edit'
6
6
  import type {StepGroupAttributes, StepGroupOptions} from './types'
7
7
  import {icon} from '~/blocks/step/step-group/icon'
8
+ import {ITEM_SPACING_ATTRIBUTE} from '~/components/ItemSpacingControl'
8
9
  import type {OptionArray} from '~/types'
9
10
 
10
11
  export function createStepGroupBlock<TVariants extends OptionArray = typeof DEFAULT_VARIANTS>(
@@ -29,6 +30,7 @@ export function createStepGroupBlock<TVariants extends OptionArray = typeof DEFA
29
30
  type: 'boolean',
30
31
  default: false,
31
32
  },
33
+ ...ITEM_SPACING_ATTRIBUTE,
32
34
  },
33
35
  edit: createStepGroupEdit(options as unknown as StepGroupOptions),
34
36
  save: () => <InnerBlocks.Content />,
@@ -6,6 +6,7 @@ export type StepVariant = (typeof DEFAULT_VARIANTS)[number]['value']
6
6
  export interface StepGroupAttributes<TVariant extends string = StepVariant> extends Record<string, unknown> {
7
7
  variant: TVariant
8
8
  disableIcon: boolean
9
+ spacing?: number
9
10
  }
10
11
 
11
12
  export interface StepGroupOptions<TVariants extends OptionArray = typeof DEFAULT_VARIANTS> extends BriloBlockType {
@@ -14,5 +14,6 @@ export const textAndFormTextColumnDefaults: TextAndFormTextColumnOptions = {
14
14
  'core/heading',
15
15
  'core/list',
16
16
  'core/paragraph',
17
+ 'brilo/list-group',
17
18
  ],
18
19
  }
@@ -11,6 +11,7 @@ import {
11
11
  } from '@wordpress/components'
12
12
  import {__} from '@wordpress/i18n'
13
13
  import clsx from 'clsx'
14
+ import {ItemSpacingPanel, itemSpacingStyle} from '~/components/ItemSpacingControl'
14
15
  import {useGroupBlock} from '~/hooks/useGroupBlock'
15
16
  import {useTenantColorPalette} from '~/hooks/useTenantColorPalette'
16
17
  import {
@@ -89,7 +90,7 @@ export function createUspGroupEdit(options: UspGroupOptions) {
89
90
  attributes: UspGroupAttributes
90
91
  setAttributes: (a: Partial<UspGroupAttributes>) => void
91
92
  }) {
92
- const {columns, headingSettings, content, style} = attributes
93
+ const {columns, headingSettings, content, style, spacing} = attributes
93
94
  const {paletteColors} = useTenantColorPalette()
94
95
 
95
96
  const {blockProps, innerBlocksProps} = useGroupBlock({
@@ -100,7 +101,7 @@ export function createUspGroupEdit(options: UspGroupOptions) {
100
101
  style.shadow !== 'none' && `--shadow-${style.shadow}`,
101
102
  ),
102
103
  containerClassName: [options.containerClassName ?? 'u-grid-responsive', `--cols-${columns}`],
103
- containerStyle: {'--grid-max-col-count': columns},
104
+ containerStyle: {'--grid-max-col-count': columns, ...itemSpacingStyle(spacing)},
104
105
  allowedBlocks: options.allowedBlocks,
105
106
  orientation: 'horizontal',
106
107
  template: options.template,
@@ -285,6 +286,7 @@ export function createUspGroupEdit(options: UspGroupOptions) {
285
286
  />
286
287
  )}
287
288
  </PanelBody>
289
+ <ItemSpacingPanel spacing={spacing} onChange={(v) => setAttributes({spacing: v})} />
288
290
  </InspectorControls>
289
291
  <div {...blockProps}>
290
292
  <div {...innerBlocksProps} />
@@ -1,6 +1,7 @@
1
1
  import {InnerBlocks} from '@wordpress/block-editor'
2
2
  import type {BlockConfiguration} from '@wordpress/blocks'
3
3
  import {__} from '@wordpress/i18n'
4
+ import {ITEM_SPACING_ATTRIBUTE} from '~/components/ItemSpacingControl'
4
5
  import type {NumberArray, OptionArray} from '~/types'
5
6
  import {
6
7
  DEFAULT_ALIGNMENTS,
@@ -91,6 +92,7 @@ export function createUspGroupBlock<
91
92
  },
92
93
  },
93
94
  },
95
+ ...ITEM_SPACING_ATTRIBUTE,
94
96
  },
95
97
  edit: createUspGroupEdit(options as unknown as UspGroupOptions),
96
98
  save: () => <InnerBlocks.Content />,
@@ -55,6 +55,7 @@ export interface UspGroupAttributes<
55
55
  borderWidth: number
56
56
  }
57
57
  }
58
+ spacing?: number
58
59
  }
59
60
 
60
61
  export interface UspGroupOptions<
@@ -9,3 +9,5 @@ export const SIZES = [
9
9
  {value: 'md', label: __('Střední', 'brilo-blocks')},
10
10
  {value: 'lg', label: __('Velký', 'brilo-blocks')},
11
11
  ] as const
12
+
13
+ export const DEFAULT_OVERLAY_COLOR = 'rgba(0, 0, 0, 0.25)'
@@ -1,7 +1,9 @@
1
1
  import {InspectorControls, MediaUpload, MediaUploadCheck, RichText, useBlockProps} from '@wordpress/block-editor'
2
2
  import type {BlockEditProps} from '@wordpress/blocks'
3
3
  import {
4
+ BaseControl,
4
5
  Button,
6
+ ColorPalette,
5
7
  PanelBody,
6
8
  TextControl,
7
9
  __experimentalToggleGroupControl as ToggleGroupControl,
@@ -9,7 +11,8 @@ import {
9
11
  } from '@wordpress/components'
10
12
  import {__} from '@wordpress/i18n'
11
13
  import clsx from 'clsx'
12
- import {SIZES, VIDEO_TYPES} from './constants'
14
+ import {useTenantColorPalette} from '~/hooks/useTenantColorPalette'
15
+ import {DEFAULT_OVERLAY_COLOR, SIZES, VIDEO_TYPES} from './constants'
13
16
  import type {VideoGroupAttributes, VideoGroupOptions, VideoSize, VideoType} from './types'
14
17
 
15
18
  function extractYoutubeId(url: string): string | null {
@@ -19,7 +22,8 @@ function extractYoutubeId(url: string): string | null {
19
22
 
20
23
  export function createVideoGroupEdit(_options: VideoGroupOptions) {
21
24
  return function VideoGroupEdit({attributes, setAttributes}: BlockEditProps<VideoGroupAttributes>) {
22
- const {type, url, mediaId, caption, size, poster, playButtonTitle} = attributes
25
+ const {type, url, mediaId, caption, size, poster, playButtonTitle, overlayColor} = attributes
26
+ const {paletteColors} = useTenantColorPalette()
23
27
 
24
28
  const youtubeId = type === 'youtube' ? extractYoutubeId(url) : null
25
29
  const youtubeThumbnail = youtubeId ? `https://img.youtube.com/vi/${youtubeId}/maxresdefault.jpg` : null
@@ -92,6 +96,24 @@ export function createVideoGroupEdit(_options: VideoGroupOptions) {
92
96
  </MediaUploadCheck>
93
97
  </PanelBody>
94
98
 
99
+ <PanelBody title={__('Barevná vrstva', 'brilo-blocks')} initialOpen={false}>
100
+ <BaseControl
101
+ label={__('Barva překrytí náhledu', 'brilo-blocks')}
102
+ help={__('Ztmaví náhled videa, aby tlačítko přehrát více vyniklo. Výchozí je černá s 25% průhledností.', 'brilo-blocks')}
103
+ >
104
+ <ColorPalette
105
+ colors={paletteColors}
106
+ value={overlayColor || undefined}
107
+ onChange={(value) => setAttributes({overlayColor: value ?? ''})}
108
+ enableAlpha
109
+ clearable
110
+ />
111
+ </BaseControl>
112
+ <Button onClick={() => setAttributes({overlayColor: DEFAULT_OVERLAY_COLOR})} variant="tertiary" size="small">
113
+ {__('Obnovit výchozí barvu', 'brilo-blocks')}
114
+ </Button>
115
+ </PanelBody>
116
+
95
117
  <PanelBody title={__('Rozložení', 'brilo-blocks')} initialOpen={false}>
96
118
  <ToggleGroupControl
97
119
  label={__('Velikost', 'brilo-blocks')}
@@ -112,6 +134,7 @@ export function createVideoGroupEdit(_options: VideoGroupOptions) {
112
134
  youtubeThumbnail ? (
113
135
  <div className="g-video__youtube-preview">
114
136
  <img src={youtubeThumbnail} alt="" />
137
+ <div className="g-video__overlay" style={overlayColor ? {backgroundColor: overlayColor} : undefined} />
115
138
  <div className="g-video__play-icon" />
116
139
  </div>
117
140
  ) : (
@@ -135,6 +158,7 @@ export function createVideoGroupEdit(_options: VideoGroupOptions) {
135
158
  <video src={url} poster={poster?.src || undefined}>
136
159
  <track kind="captions" />
137
160
  </video>
161
+ <div className="g-video__overlay" style={overlayColor ? {backgroundColor: overlayColor} : undefined} />
138
162
  <Button onClick={open} variant="primary" className="g-video__change-btn">
139
163
  {__('Změnit video', 'brilo-blocks')}
140
164
  </Button>
@@ -23,13 +23,18 @@
23
23
  }
24
24
  }
25
25
 
26
+ .g-video__overlay {
27
+ position: absolute;
28
+ inset: 0;
29
+ pointer-events: none;
30
+ }
31
+
26
32
  .g-video__play-icon {
27
33
  position: absolute;
28
34
  inset: 0;
29
35
  display: flex;
30
36
  align-items: center;
31
37
  justify-content: center;
32
- background: rgba(0, 0, 0, 0.2);
33
38
  pointer-events: none;
34
39
 
35
40
  &::after {
@@ -1,6 +1,6 @@
1
1
  import type {BlockConfiguration} from '@wordpress/blocks'
2
2
  import {__} from '@wordpress/i18n'
3
- import {SIZES, VIDEO_TYPES} from './constants'
3
+ import {DEFAULT_OVERLAY_COLOR, SIZES, VIDEO_TYPES} from './constants'
4
4
  import {createVideoGroupEdit} from './edit'
5
5
  import {icon as defaultIcon} from './icon'
6
6
  import type {VideoGroupAttributes, VideoGroupOptions} from './types'
@@ -48,6 +48,10 @@ export function createVideoGroupBlock(options: VideoGroupOptions): BlockConfigur
48
48
  type: 'string',
49
49
  default: __('Přehrát video', 'brilo-blocks'),
50
50
  },
51
+ overlayColor: {
52
+ type: 'string',
53
+ default: DEFAULT_OVERLAY_COLOR,
54
+ },
51
55
  },
52
56
  edit: createVideoGroupEdit(options),
53
57
  save: () => null,
@@ -17,6 +17,7 @@ export interface VideoGroupAttributes extends Record<string, unknown> {
17
17
  size: VideoSize
18
18
  poster: VideoPoster
19
19
  playButtonTitle: string
20
+ overlayColor: string
20
21
  }
21
22
 
22
23
  export interface VideoGroupOptions extends BriloBlockType {}