@brilo/base-blocks 0.1.46 → 0.1.48

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 (48) hide show
  1. package/build/.tsbuildinfo +1 -1
  2. package/build/blocks/contact/contact-group/constants.d.ts +71 -0
  3. package/build/blocks/contact/contact-group/constants.d.ts.map +1 -1
  4. package/build/blocks/contact/contact-group/constants.js +35 -0
  5. package/build/blocks/contact/contact-group/edit.d.ts.map +1 -1
  6. package/build/blocks/contact/contact-group/edit.js +20 -8
  7. package/build/blocks/contact/contact-group/factory.d.ts +3 -3
  8. package/build/blocks/contact/contact-group/factory.d.ts.map +1 -1
  9. package/build/blocks/contact/contact-group/factory.js +33 -8
  10. package/build/blocks/contact/contact-group/index.d.ts +2 -2
  11. package/build/blocks/contact/contact-group/index.d.ts.map +1 -1
  12. package/build/blocks/contact/contact-group/index.js +1 -1
  13. package/build/blocks/contact/contact-group/types.d.ts +29 -6
  14. package/build/blocks/contact/contact-group/types.d.ts.map +1 -1
  15. package/build/blocks/contact/contact-item/buildPreviewStyle.d.ts +24 -0
  16. package/build/blocks/contact/contact-item/buildPreviewStyle.d.ts.map +1 -0
  17. package/build/blocks/contact/contact-item/buildPreviewStyle.js +31 -0
  18. package/build/blocks/contact/contact-item/edit.d.ts.map +1 -1
  19. package/build/blocks/contact/contact-item/edit.js +10 -8
  20. package/build/blocks/contact/contact-item/factory.js +2 -2
  21. package/build/blocks/sections/base-section/constants.d.ts +1 -0
  22. package/build/blocks/sections/base-section/constants.d.ts.map +1 -1
  23. package/build/blocks/sections/base-section/constants.js +1 -0
  24. package/build/blocks/sections/base-section/controls.d.ts.map +1 -1
  25. package/build/blocks/sections/base-section/controls.js +4 -3
  26. package/build/blocks/sections/base-section/edit.d.ts.map +1 -1
  27. package/build/blocks/sections/base-section/edit.js +23 -24
  28. package/build/blocks/sections/base-section/types.d.ts +1 -0
  29. package/build/blocks/sections/base-section/types.d.ts.map +1 -1
  30. package/build/index.d.ts +2 -2
  31. package/build/index.d.ts.map +1 -1
  32. package/build/index.js +1 -1
  33. package/package.json +1 -1
  34. package/src/blocks/contact/contact-group/constants.ts +42 -0
  35. package/src/blocks/contact/contact-group/edit.tsx +177 -20
  36. package/src/blocks/contact/contact-group/editor.scss +19 -0
  37. package/src/blocks/contact/contact-group/factory.tsx +61 -8
  38. package/src/blocks/contact/contact-group/index.ts +10 -2
  39. package/src/blocks/contact/contact-group/types.ts +48 -6
  40. package/src/blocks/contact/contact-item/buildPreviewStyle.ts +69 -0
  41. package/src/blocks/contact/contact-item/edit.tsx +17 -30
  42. package/src/blocks/contact/contact-item/editor.scss +136 -7
  43. package/src/blocks/contact/contact-item/factory.tsx +2 -2
  44. package/src/blocks/sections/base-section/constants.ts +2 -0
  45. package/src/blocks/sections/base-section/controls.tsx +10 -0
  46. package/src/blocks/sections/base-section/edit.tsx +24 -22
  47. package/src/blocks/sections/base-section/types.ts +1 -0
  48. package/src/index.ts +5 -0
@@ -1,6 +1,14 @@
1
- export type {ContactColumns, ContactGroupAttributes, ContactGroupOptions} from './types'
1
+ export type {
2
+ ContactColumns,
3
+ ContactDirection,
4
+ ContactGroupAttributes,
5
+ ContactGroupOptions,
6
+ ContactIconBackgroundShape,
7
+ ContactShadow,
8
+ ContactTextAlign,
9
+ } from './types'
2
10
  export {createContactGroupBlock} from './factory'
3
- export {CONTACT_COLUMNS, CONTACT_COLUMNS_CONTEXT} from './constants'
11
+ export {CONTACT_COLUMNS, CONTACT_COLUMNS_CONTEXT, CONTACT_STYLE_CONTEXT} from './constants'
4
12
 
5
13
  import type {ContactGroupOptions} from './types'
6
14
 
@@ -1,23 +1,65 @@
1
- import type {BriloBlockType, NumberArray} from '~/types'
2
- import type {CONTACT_COLUMNS, DEFAULT_SHADOWS, TEXT_ALIGNS} from './constants'
1
+ import type {BriloBlockType, NumberArray, OptionArray} from '~/types'
2
+ import type {
3
+ CONTACT_COLUMNS,
4
+ DEFAULT_DIRECTIONS,
5
+ DEFAULT_ICON_BACKGROUND_SHAPES,
6
+ DEFAULT_SHADOWS,
7
+ TEXT_ALIGNS,
8
+ } from './constants'
3
9
 
4
10
  export type ContactColumns = (typeof CONTACT_COLUMNS)[number]
5
11
 
6
12
  export type ContactShadow = (typeof DEFAULT_SHADOWS)[number]['value']
7
13
 
14
+ export type ContactDirection = (typeof DEFAULT_DIRECTIONS)[number]['value']
15
+
8
16
  export type ContactTextAlign = (typeof TEXT_ALIGNS)[number]['value']
9
17
 
10
- export interface ContactGroupAttributes<TColumns extends number = ContactColumns> extends Record<string, unknown> {
18
+ export type ContactIconBackgroundShape = (typeof DEFAULT_ICON_BACKGROUND_SHAPES)[number]['value']
19
+
20
+ export interface ContactSizePreset {
21
+ value: number
22
+ label: string
23
+ }
24
+
25
+ export interface ContactGroupAttributes<
26
+ TColumns extends number = ContactColumns,
27
+ TDirection extends string = ContactDirection,
28
+ TShadow extends string = ContactShadow,
29
+ TIconBackgroundShape extends string = ContactIconBackgroundShape,
30
+ > extends Record<string, unknown> {
11
31
  columns: TColumns
32
+ groupBackgroundColor: string
12
33
  style: {
13
- shadow: ContactShadow
34
+ shadow: TShadow
35
+ direction: TDirection
36
+ textAlign: ContactTextAlign
14
37
  borderColor: string
15
38
  backgroundColor: string
16
39
  textColor: string
17
- textAlign: ContactTextAlign
40
+ icon: {
41
+ size: number
42
+ color: string
43
+ background: string
44
+ backgroundSize: number
45
+ backgroundShape: TIconBackgroundShape
46
+ borderColor: string
47
+ borderWidth: number
48
+ }
18
49
  }
50
+ spacing?: number
19
51
  }
20
52
 
21
- export interface ContactGroupOptions<TColumns extends NumberArray = typeof CONTACT_COLUMNS> extends BriloBlockType {
53
+ export interface ContactGroupOptions<
54
+ TColumns extends NumberArray = typeof CONTACT_COLUMNS,
55
+ TDirections extends OptionArray = typeof DEFAULT_DIRECTIONS,
56
+ TShadows extends OptionArray = typeof DEFAULT_SHADOWS,
57
+ TIconBackgroundShapes extends OptionArray = typeof DEFAULT_ICON_BACKGROUND_SHAPES,
58
+ > extends BriloBlockType {
22
59
  columns?: TColumns
60
+ directions?: TDirections
61
+ shadows?: TShadows
62
+ iconSizePresets?: readonly ContactSizePreset[]
63
+ iconBackgroundSizePresets?: readonly ContactSizePreset[]
64
+ iconBackgroundShapes?: TIconBackgroundShapes
23
65
  }
@@ -0,0 +1,69 @@
1
+ import clsx from 'clsx'
2
+
3
+ export interface ContactSharedStyle {
4
+ direction?: string
5
+ textAlign?: string
6
+ shadow?: string
7
+ borderColor?: string
8
+ backgroundColor?: string
9
+ textColor?: string
10
+ icon?: {
11
+ size?: number
12
+ color?: string
13
+ background?: string
14
+ backgroundSize?: number
15
+ backgroundShape?: string
16
+ borderColor?: string
17
+ borderWidth?: number
18
+ }
19
+ }
20
+
21
+ export interface ContactPreviewStyle {
22
+ rootClassName: string
23
+ iconClassName: string
24
+ cssVars: Record<string, string>
25
+ }
26
+
27
+ export function buildContactPreviewStyle(
28
+ shared?: ContactSharedStyle,
29
+ resolveHex: (value: string) => string = (value) => value,
30
+ ): ContactPreviewStyle {
31
+ if (!shared) {
32
+ return {rootClassName: '', iconClassName: '', cssVars: {}}
33
+ }
34
+
35
+ const icon = shared.icon ?? {}
36
+
37
+ const rootClassName = clsx(
38
+ shared.direction && `--direction-${shared.direction}`,
39
+ shared.textAlign && `--align-${shared.textAlign}`,
40
+ shared.shadow && shared.shadow !== 'none' && `--shadow --shadow-${shared.shadow}`,
41
+ icon.background && icon.background !== 'none' && '--icon-background',
42
+ icon.color && icon.color !== 'none' && '--icon-color',
43
+ icon.borderColor && '--icon-bordered',
44
+ shared.backgroundColor && '--background-color',
45
+ shared.borderColor && '--border',
46
+ shared.textColor && '--text-color',
47
+ )
48
+
49
+ const iconClassName = clsx(
50
+ icon.backgroundShape && icon.backgroundShape !== 'none' && `--background-shape --background-shape-${icon.backgroundShape}`,
51
+ )
52
+
53
+ const cssVars: Record<string, string> = {}
54
+ if (shared.borderColor) cssVars['--border-color'] = resolveHex(shared.borderColor)
55
+ if (shared.backgroundColor) cssVars['--background-color'] = resolveHex(shared.backgroundColor)
56
+ if (shared.textColor) cssVars['--text-color'] = resolveHex(shared.textColor)
57
+ if (icon.background && icon.background !== 'none') cssVars['--icon-background-color'] = resolveHex(icon.background)
58
+ if (icon.color && icon.color !== 'none') cssVars['--icon-color'] = resolveHex(icon.color)
59
+ if (icon.size) cssVars['--icon-size'] = `${icon.size}px`
60
+ if (icon.background && icon.background !== 'none' && icon.backgroundSize) {
61
+ cssVars['--icon-background-size'] = `${icon.backgroundSize}px`
62
+ }
63
+ if (icon.borderColor) {
64
+ cssVars['--icon-outline-color'] = resolveHex(icon.borderColor)
65
+ cssVars['--icon-outline-width'] = `${icon.borderWidth || 1}px`
66
+ }
67
+
68
+ return {rootClassName, iconClassName, cssVars}
69
+ }
@@ -1,7 +1,6 @@
1
1
  import {InspectorControls} from '@wordpress/block-editor'
2
2
  import {
3
3
  PanelBody,
4
- RangeControl,
5
4
  __experimentalToggleGroupControl as ToggleGroupControl,
6
5
  __experimentalToggleGroupControlOption as ToggleGroupControlOption,
7
6
  } from '@wordpress/components'
@@ -10,9 +9,11 @@ import clsx from 'clsx'
10
9
  import type {CSSProperties} from 'react'
11
10
  import {ItemIconControl, ItemIconPreview} from '~/components/ItemIconControl'
12
11
  import {useGroupBlock} from '~/hooks/useGroupBlock'
13
- import {CONTACT_COLUMNS_CONTEXT} from '../contact-group/constants'
14
- import {CONTACT_ICON_SIZE_DEFAULT, CONTACT_ICON_SIZE_RANGE, CONTACT_ICON_SIZES, CONTACT_ICON_TYPES} from './constants'
15
- import type {ContactIconSizeVariant, ContactItemAttributes, ContactItemOptions} from './types'
12
+ import {useTenantColorPalette} from '~/hooks/useTenantColorPalette'
13
+ import {CONTACT_COLUMNS_CONTEXT, CONTACT_STYLE_CONTEXT} from '../contact-group/constants'
14
+ import {buildContactPreviewStyle, type ContactSharedStyle} from './buildPreviewStyle'
15
+ import {CONTACT_ICON_TYPES} from './constants'
16
+ import type {ContactItemAttributes, ContactItemOptions} from './types'
16
17
 
17
18
  export function createContactItemEdit(options: ContactItemOptions) {
18
19
  const iconOptions = {icons: options.icons ?? [], iconsSrc: options.iconsSrc ?? ''}
@@ -26,16 +27,18 @@ export function createContactItemEdit(options: ContactItemOptions) {
26
27
  setAttributes: (a: Partial<ContactItemAttributes>) => void
27
28
  context: Record<string, unknown>
28
29
  }) {
29
- const {colSpan, icon, iconSize} = attributes
30
+ const {colSpan, icon} = attributes
30
31
  const columns = Number(context[CONTACT_COLUMNS_CONTEXT] ?? 3)
31
32
  const span = Math.min(colSpan, columns)
32
33
 
33
- const sizePreset = CONTACT_ICON_SIZES.find((s) => s.value === iconSize.variant)
34
- const iconPx =
35
- iconSize.variant === 'custom' ? iconSize.custom : sizePreset && 'size' in sizePreset ? sizePreset.size : CONTACT_ICON_SIZE_DEFAULT
34
+ const {resolveHex} = useTenantColorPalette()
35
+ const {rootClassName, iconClassName, cssVars} = buildContactPreviewStyle(
36
+ context[CONTACT_STYLE_CONTEXT] as ContactSharedStyle | undefined,
37
+ resolveHex,
38
+ )
36
39
 
37
40
  const {blockProps, innerBlocksProps} = useGroupBlock({
38
- blockClassName: clsx(options.blockClassName ?? 'i-contact'),
41
+ blockClassName: clsx(options.blockClassName ?? 'i-contact', rootClassName),
39
42
  containerClassName: [options.containerClassName ?? 'i-contact__inner'],
40
43
  allowedBlocks: options.allowedBlocks,
41
44
  template: options.template,
@@ -60,29 +63,13 @@ export function createContactItemEdit(options: ContactItemOptions) {
60
63
  </PanelBody>
61
64
  <PanelBody title={__('Ikona', 'brilo-blocks')}>
62
65
  <ItemIconControl icon={icon} setAttributes={setAttributes} iconTypes={CONTACT_ICON_TYPES} options={iconOptions} />
63
- <ToggleGroupControl
64
- isBlock
65
- label={__('Velikost ikony', 'brilo-blocks')}
66
- value={iconSize.variant}
67
- onChange={(v) => setAttributes({iconSize: {...iconSize, variant: v as ContactIconSizeVariant}})}
68
- >
69
- {CONTACT_ICON_SIZES.map((s) => (
70
- <ToggleGroupControlOption key={s.value} value={s.value} label={s.label} />
71
- ))}
72
- </ToggleGroupControl>
73
- {iconSize.variant === 'custom' && (
74
- <RangeControl
75
- label={__('Vlastní velikost (px)', 'brilo-blocks')}
76
- value={iconSize.custom}
77
- min={CONTACT_ICON_SIZE_RANGE.min}
78
- max={CONTACT_ICON_SIZE_RANGE.max}
79
- onChange={(v) => setAttributes({iconSize: {...iconSize, custom: v ?? CONTACT_ICON_SIZE_RANGE.min}})}
80
- />
81
- )}
82
66
  </PanelBody>
83
67
  </InspectorControls>
84
- <div {...blockProps} style={{...(blockProps.style as CSSProperties), '--col-span': span} as CSSProperties}>
85
- <div className="i-contact__icon-wrap" style={{'--icon-size': `${iconPx}px`} as CSSProperties}>
68
+ <div
69
+ {...blockProps}
70
+ style={{...(blockProps.style as CSSProperties), ...cssVars, '--col-span': span} as CSSProperties}
71
+ >
72
+ <div className={clsx('i-contact__icon-wrap', iconClassName)}>
86
73
  <ItemIconPreview icon={icon} className="i-contact__icon" setAttributes={setAttributes} options={iconOptions} />
87
74
  </div>
88
75
  <div {...innerBlocksProps} />
@@ -9,18 +9,67 @@
9
9
  }
10
10
 
11
11
  .i-contact {
12
+ --icon-background-size: 0px;
13
+
12
14
  grid-column: span var(--col-span, 1);
13
15
  margin-inline: 0;
14
16
  width: 100%;
15
17
  box-sizing: border-box;
16
- border: 1px solid #eee;
18
+ display: flex;
19
+ flex-direction: column;
20
+ gap: 8px;
17
21
  padding: 8px;
22
+ border-radius: 4px;
23
+ align-items: var(--align-items, flex-start);
24
+ text-align: var(--text-align, left);
25
+
26
+ &.--direction-horizontal {
27
+ flex-direction: row;
28
+ }
29
+
30
+ &.--align-left {
31
+ --align-items: flex-start;
32
+ --text-align: left;
33
+ }
34
+
35
+ &.--align-center {
36
+ --align-items: center;
37
+ --text-align: center;
38
+ }
39
+
40
+ // Background size only reserves space when a background or outline is actually selected.
41
+ &.--icon-background,
42
+ &.--icon-bordered {
43
+ --icon-background-size: 88px;
44
+ }
45
+
46
+ &.--shadow {
47
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
48
+ }
49
+
50
+ &.--shadow-md {
51
+ box-shadow: 0 4px 14px rgba(0, 0, 0, 0.14);
52
+ }
53
+
54
+ &.--border {
55
+ border: 1px solid var(--border-color, transparent);
56
+ }
57
+
58
+ &.--background-color {
59
+ background-color: var(--background-color, transparent);
60
+ }
61
+
62
+ &.--text-color {
63
+ color: var(--text-color);
64
+ }
18
65
 
19
66
  .i-contact__inner {
20
67
  display: flex;
21
68
  flex-direction: column;
22
69
  gap: 8px;
23
- width: 100%;
70
+ flex: 1;
71
+ min-width: 0;
72
+ text-align: inherit;
24
73
 
25
74
  p,
26
75
  h3,
@@ -29,14 +78,94 @@
29
78
  margin-block: 4px;
30
79
  }
31
80
  }
81
+ }
82
+
83
+ .i-contact__icon-wrap {
84
+ --icon-box-size: max(var(--icon-background-size, 0px), var(--icon-size, 88px));
85
+
86
+ width: var(--icon-box-size);
87
+ height: var(--icon-box-size);
88
+ flex: 0 0 var(--icon-box-size);
89
+ display: grid;
90
+ grid-template-areas: "pile";
91
+ place-items: center;
92
+ isolation: isolate;
93
+
94
+ &::before,
95
+ &::after {
96
+ content: "";
97
+ grid-area: pile;
98
+ width: var(--icon-background-size, 0px);
99
+ height: var(--icon-background-size, 0px);
100
+ border-radius: inherit;
101
+ clip-path: var(--icon-background-shape, none);
102
+ }
32
103
 
33
- .i-contact__icon-wrap {
34
- --icon-size: 32px;
104
+ &::before {
105
+ z-index: 0;
106
+ background-color: var(--icon-outline-color, transparent);
35
107
  }
36
108
 
37
- .i-contact__icon img {
38
- width: var(--icon-size);
39
- height: var(--icon-size);
109
+ &::after {
110
+ z-index: 1;
111
+ width: calc(var(--icon-background-size, 0px) - var(--icon-outline-width, 0px) * 2);
112
+ height: calc(var(--icon-background-size, 0px) - var(--icon-outline-width, 0px) * 2);
113
+ background-color: var(--icon-background-color, transparent);
114
+ }
115
+
116
+ .i-contact__icon,
117
+ img,
118
+ svg {
119
+ grid-area: pile;
120
+ position: relative;
121
+ z-index: 2;
122
+ width: var(--icon-size, 88px);
123
+ height: var(--icon-size, 88px);
40
124
  object-fit: contain;
41
125
  }
126
+
127
+ svg path {
128
+ fill: var(--icon-color, currentcolor);
129
+ }
130
+
131
+ &.--background-shape-circle {
132
+ --icon-background-shape: circle(50% at 50% 50%);
133
+ }
134
+
135
+ &.--background-shape-triangle {
136
+ --icon-background-shape: polygon(50% 0%, 0% 100%, 100% 100%);
137
+ }
138
+
139
+ &.--background-shape-rhombus {
140
+ --icon-background-shape: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
141
+ }
142
+
143
+ &.--background-shape-octagon {
144
+ --icon-background-shape: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%);
145
+ }
146
+
147
+ &.--background-shape-bevel {
148
+ --icon-background-shape: polygon(20% 0%, 80% 0%, 100% 20%, 100% 80%, 80% 100%, 20% 100%, 0% 80%, 0% 20%);
149
+ }
150
+
151
+ &.--background-shape-rabbet {
152
+ --icon-background-shape: polygon(
153
+ 0% 15%,
154
+ 15% 15%,
155
+ 15% 0%,
156
+ 85% 0%,
157
+ 85% 15%,
158
+ 100% 15%,
159
+ 100% 85%,
160
+ 85% 85%,
161
+ 85% 100%,
162
+ 15% 100%,
163
+ 15% 85%,
164
+ 0% 85%
165
+ );
166
+ }
167
+
168
+ &.--background-shape-parallelogram {
169
+ --icon-background-shape: polygon(25% 0%, 100% 0%, 75% 100%, 0% 100%);
170
+ }
42
171
  }
@@ -3,7 +3,7 @@ import type {BlockConfiguration, BlockEditProps} from '@wordpress/blocks'
3
3
  import {__} from '@wordpress/i18n'
4
4
  import type {Icon} from '~/types'
5
5
  import type {IconType} from '~/components/IconControl/IconControl'
6
- import {CONTACT_COLUMNS_CONTEXT} from '../contact-group/constants'
6
+ import {CONTACT_COLUMNS_CONTEXT, CONTACT_STYLE_CONTEXT} from '../contact-group/constants'
7
7
  import {CONTACT_ICON_SIZE_DEFAULT, CONTACT_ICON_TYPES} from './constants'
8
8
  import type {ContactItemAttributes, ContactItemOptions} from './types'
9
9
 
@@ -24,7 +24,7 @@ export function createContactItemBlock<T extends ContactItemAttributes = Contact
24
24
  ...(options.parent && {parent: options.parent}),
25
25
  icon: options.icon ?? 'id-alt',
26
26
  supports: {html: false, customClassName: false},
27
- usesContext: [CONTACT_COLUMNS_CONTEXT],
27
+ usesContext: [CONTACT_COLUMNS_CONTEXT, CONTACT_STYLE_CONTEXT],
28
28
  attributes: {
29
29
  ...(options.attributes as any),
30
30
  colSpan: {type: 'number', default: 1},
@@ -87,3 +87,5 @@ export const BACKGROUND_IMAGE_POSITIONS = [
87
87
  ] as const
88
88
 
89
89
  export const BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT = 40
90
+
91
+ export const BACKGROUND_IMAGE_OPACITY_DEFAULT = 100
@@ -33,6 +33,7 @@ import type {
33
33
  } from './types'
34
34
  import {
35
35
  BACKGROUND_IMAGE_FITS,
36
+ BACKGROUND_IMAGE_OPACITY_DEFAULT,
36
37
  BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT,
37
38
  BACKGROUND_IMAGE_POSITIONS,
38
39
  BACKGROUND_IMAGE_REPEATS,
@@ -295,6 +296,7 @@ function BackgroundImageControl({value, onChange}: BackgroundImageControlProps)
295
296
  const repeat = value?.repeat ?? 'no-repeat'
296
297
  const overlayColor = value?.overlay?.color
297
298
  const overlayOpacity = value?.overlay?.opacity ?? BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT
299
+ const opacity = value?.opacity ?? BACKGROUND_IMAGE_OPACITY_DEFAULT
298
300
 
299
301
  const update = (patch: Partial<BackgroundImage>) =>
300
302
  onChange(mergeUpdate({img, fit, position, repeat, overlay: value?.overlay}, value, patch))
@@ -365,6 +367,14 @@ function BackgroundImageControl({value, onChange}: BackgroundImageControlProps)
365
367
  onChange={(next) => update({repeat: next as BackgroundImageRepeat})}
366
368
  />
367
369
 
370
+ <RangeControl
371
+ label={__('Průhlednost obrázku', 'brilo-blocks')}
372
+ value={opacity}
373
+ min={0}
374
+ max={100}
375
+ onChange={(next) => update({opacity: next ?? BACKGROUND_IMAGE_OPACITY_DEFAULT})}
376
+ />
377
+
368
378
  <BaseControl
369
379
  label={__('Překryv barvou', 'brilo-blocks')}
370
380
  help={__('Ztmavení/zabarvení obrázku pro lepší čitelnost textu.', 'brilo-blocks')}
@@ -3,7 +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
+ import {BACKGROUND_IMAGE_OPACITY_DEFAULT, BACKGROUND_IMAGE_SIZE_VALUE_DEFAULT} from './constants'
7
7
 
8
8
  export function createBaseSectionEdit<TExtra extends Record<string, unknown> = Record<string, never>>(options: BaseSectionOptions<TExtra>) {
9
9
  const EXCLUDE = options.exclude ?? []
@@ -12,9 +12,9 @@ export function createBaseSectionEdit<TExtra extends Record<string, unknown> = R
12
12
  const {attributes, setAttributes} = props
13
13
  const {background, textColor, gradient, backgroundImage} = attributes as BaseBlockAttributes & {gradient?: string}
14
14
  const bgImageSrc = backgroundImage?.img?.src
15
- // A plain background-color/gradient always paints behind an image, so it can never tint it. To preview a
16
- // translucent color/gradient sitting on top of the image (matching frontend), stack it as its own layer
17
- // in front of the `url(...)` layer instead of setting backgroundColor separately.
15
+ // A plain background-color/gradient always paints behind an image, so it can never tint it.
16
+ // To preview it sitting on top of the image (matching frontend), it renders as its own
17
+ // absolutely-positioned layer, separate from the image layer below it and the content above.
18
18
  const tintLayer = background ? `linear-gradient(${background}, ${background})` : gradient
19
19
  const blockProps = useBlockProps({
20
20
  className: options.blockClassName,
@@ -23,26 +23,26 @@ export function createBaseSectionEdit<TExtra extends Record<string, unknown> = R
23
23
  ...(background && !bgImageSrc ? {backgroundColor: background, padding: '16px'} : {}),
24
24
  ...(gradient && !bgImageSrc ? {background: gradient, padding: '16px'} : {}),
25
25
  ...(textColor ? {color: textColor} : {}),
26
- ...(bgImageSrc
27
- ? {
28
- backgroundImage: [tintLayer, `url(${bgImageSrc})`].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(', '),
37
- backgroundPosition: [tintLayer ? 'center center' : null, backgroundImage?.position ?? 'center center']
38
- .filter(Boolean)
39
- .join(', '),
40
- backgroundRepeat: [tintLayer ? 'no-repeat' : null, backgroundImage?.repeat ?? 'no-repeat'].filter(Boolean).join(', '),
41
- padding: '16px',
42
- }
43
- : {}),
26
+ ...(bgImageSrc ? {padding: '16px'} : {}),
44
27
  },
45
28
  })
29
+ // Opacity applies to the image alone — it must live on its own layer, not on blockProps,
30
+ // or it would fade the section's inner content (headings, buttons, ...) along with it.
31
+ const bgImageLayerStyle: CSSProperties = bgImageSrc
32
+ ? {
33
+ position: 'absolute',
34
+ inset: 0,
35
+ backgroundImage: `url(${bgImageSrc})`,
36
+ backgroundSize:
37
+ backgroundImage?.fit === 'custom'
38
+ ? (backgroundImage?.sizeValue ?? BACKGROUND_IMAGE_SIZE_VALUE_DEFAULT)
39
+ : (backgroundImage?.fit ?? 'cover'),
40
+ backgroundPosition: backgroundImage?.position ?? 'center center',
41
+ backgroundRepeat: backgroundImage?.repeat ?? 'no-repeat',
42
+ opacity: (backgroundImage?.opacity ?? BACKGROUND_IMAGE_OPACITY_DEFAULT) / 100,
43
+ }
44
+ : {}
45
+ const tintLayerStyle: CSSProperties = tintLayer ? {position: 'absolute', inset: 0, background: tintLayer} : {}
46
46
  const innerBlocksProps = useInnerBlocksProps({className: options.containerClassName}, {
47
47
  allowedBlocks: options.allowedBlocks,
48
48
  orientation: 'vertical',
@@ -60,6 +60,8 @@ export function createBaseSectionEdit<TExtra extends Record<string, unknown> = R
60
60
  {options.extraControls?.(props)}
61
61
  </InspectorControls>
62
62
  <div {...blockProps}>
63
+ {!!bgImageSrc && <div style={bgImageLayerStyle} />}
64
+ {!!bgImageSrc && !!tintLayer && <div style={tintLayerStyle} />}
63
65
  <div {...innerBlocksProps} />
64
66
  </div>
65
67
  </>
@@ -67,6 +67,7 @@ export interface BackgroundImage {
67
67
  position?: BackgroundImagePosition
68
68
  repeat?: BackgroundImageRepeat
69
69
  overlay?: BackgroundImageOverlay
70
+ opacity?: number
70
71
  }
71
72
 
72
73
  export interface Border {
package/src/index.ts CHANGED
@@ -11,12 +11,17 @@ export {
11
11
  } from './blocks/anchor/anchor-item'
12
12
  export type {
13
13
  ContactColumns,
14
+ ContactDirection,
14
15
  ContactGroupAttributes,
15
16
  ContactGroupOptions,
17
+ ContactIconBackgroundShape,
18
+ ContactShadow,
19
+ ContactTextAlign,
16
20
  } from './blocks/contact/contact-group'
17
21
  export {
18
22
  CONTACT_COLUMNS,
19
23
  CONTACT_COLUMNS_CONTEXT,
24
+ CONTACT_STYLE_CONTEXT,
20
25
  contactGroupDefaults,
21
26
  createContactGroupBlock,
22
27
  } from './blocks/contact/contact-group'