@brilo/base-blocks 0.1.35 → 0.1.36

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.
@@ -26,5 +26,12 @@ export declare const baseAttributes: {
26
26
  readonly type: 'object';
27
27
  readonly default: {};
28
28
  };
29
+ readonly backgroundImage: {
30
+ readonly type: 'object';
31
+ readonly default: {
32
+ readonly fit: 'cover';
33
+ readonly position: 'center center';
34
+ };
35
+ };
29
36
  };
30
37
  //# sourceMappingURL=attributes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../../../src/blocks/sections/base-section/attributes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;aACzB,EAAE;iBACA,IAAI,EAAE,QAAQ;iBACd,OAAO,EAAE,EAAE;;aAEb,OAAO;iBACL,IAAI,EAAE,QAAQ;iBACd,OAAO;qBACL,QAAQ,EAAE,SAAS;qBACnB,IAAI,EAAE,SAAS;;;aAGnB,UAAU;iBACR,IAAI,EAAE,QAAQ;iBACd,OAAO,EAAE,EAAE;;aAEb,SAAS;iBACP,IAAI,EAAE,QAAQ;iBACd,OAAO,EAAE,EAAE;;aAEb,UAAU;iBACR,IAAI,EAAE,QAAQ;iBACd,OAAO;;aAET,WAAW;iBACT,IAAI,EAAE,QAAQ;iBACd,OAAO;;CAED,CAAA"}
1
+ {"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../../../src/blocks/sections/base-section/attributes.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,cAAc;aACzB,EAAE;iBACA,IAAI,EAAE,QAAQ;iBACd,OAAO,EAAE,EAAE;;aAEb,OAAO;iBACL,IAAI,EAAE,QAAQ;iBACd,OAAO;qBACL,QAAQ,EAAE,SAAS;qBACnB,IAAI,EAAE,SAAS;;;aAGnB,UAAU;iBACR,IAAI,EAAE,QAAQ;iBACd,OAAO,EAAE,EAAE;;aAEb,SAAS;iBACP,IAAI,EAAE,QAAQ;iBACd,OAAO,EAAE,EAAE;;aAEb,UAAU;iBACR,IAAI,EAAE,QAAQ;iBACd,OAAO;;aAET,WAAW;iBACT,IAAI,EAAE,QAAQ;iBACd,OAAO;;aAET,eAAe;iBACb,IAAI,EAAE,QAAQ;iBACd,OAAO;qBACL,GAAG,EAAE,OAAO;qBACZ,QAAQ,EAAE,eAAe;;;CAGrB,CAAA"}
@@ -26,4 +26,11 @@ export const baseAttributes = {
26
26
  type: 'object',
27
27
  default: {},
28
28
  },
29
+ backgroundImage: {
30
+ type: 'object',
31
+ default: {
32
+ fit: 'cover',
33
+ position: 'center center',
34
+ },
35
+ },
29
36
  };
@@ -67,4 +67,40 @@ export declare const DECORATION_OFFSET_UNITS: {
67
67
  label: string;
68
68
  default: number;
69
69
  }[];
70
+ export declare const BACKGROUND_IMAGE_FITS: readonly [{
71
+ readonly value: 'cover';
72
+ readonly label: import("@wordpress/i18n").TransformedText<"Vyplnit (cover)">;
73
+ }, {
74
+ readonly value: 'contain';
75
+ readonly label: import("@wordpress/i18n").TransformedText<"Celý obrázek (contain)">;
76
+ }];
77
+ export declare const BACKGROUND_IMAGE_POSITIONS: readonly [{
78
+ readonly value: 'left top';
79
+ readonly label: import("@wordpress/i18n").TransformedText<"Vlevo nahoře">;
80
+ }, {
81
+ readonly value: 'center top';
82
+ readonly label: import("@wordpress/i18n").TransformedText<"Nahoře">;
83
+ }, {
84
+ readonly value: 'right top';
85
+ readonly label: import("@wordpress/i18n").TransformedText<"Vpravo nahoře">;
86
+ }, {
87
+ readonly value: 'left center';
88
+ readonly label: import("@wordpress/i18n").TransformedText<"Vlevo">;
89
+ }, {
90
+ readonly value: 'center center';
91
+ readonly label: import("@wordpress/i18n").TransformedText<"Uprostřed">;
92
+ }, {
93
+ readonly value: 'right center';
94
+ readonly label: import("@wordpress/i18n").TransformedText<"Vpravo">;
95
+ }, {
96
+ readonly value: 'left bottom';
97
+ readonly label: import("@wordpress/i18n").TransformedText<"Vlevo dole">;
98
+ }, {
99
+ readonly value: 'center bottom';
100
+ readonly label: import("@wordpress/i18n").TransformedText<"Dole">;
101
+ }, {
102
+ readonly value: 'right bottom';
103
+ readonly label: import("@wordpress/i18n").TransformedText<"Vpravo dole">;
104
+ }];
105
+ export declare const BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT = 40;
70
106
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/blocks/sections/base-section/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB;aAC3B,KAAK,EAAE,SAAS;aAAE,KAAK;;aACvB,KAAK,EAAE,MAAM;aAAE,KAAK;;aACpB,KAAK,EAAE,UAAU;aAAE,KAAK;;aACxB,KAAK,EAAE,OAAO;aAAE,KAAK;EACd,CAAA;AAEV,eAAO,MAAM,aAAa,YAAI,SAAS,EAAE,IAAI,EAAE,IAAI,CAAU,CAAA;AAE7D,eAAO,MAAM,+BAA+B,YAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAU,CAAA;AAEzE,eAAO,MAAM,+BAA+B,SAAS,CAAA;AAErD,eAAO,MAAM,sBAAsB;;;;GAIlC,CAAA;AAED,eAAO,MAAM,oBAAoB;aAC9B,KAAK,EAAE,UAAU;aAAE,KAAK;;aACxB,KAAK,EAAE,WAAW;aAAE,KAAK;;aACzB,KAAK,EAAE,aAAa;aAAE,KAAK;;aAC3B,KAAK,EAAE,cAAc;aAAE,KAAK;;aAC5B,KAAK,EAAE,aAAa;aAAE,KAAK;;aAC3B,KAAK,EAAE,cAAc;aAAE,KAAK;EACrB,CAAA;AAEV,eAAO,MAAM,iBAAiB;aAC3B,KAAK,EAAE,OAAO;aAAE,KAAK;;aACrB,KAAK,EAAE,OAAO;aAAE,KAAK;EACd,CAAA;AAEV,eAAO,MAAM,qBAAqB;aAC/B,KAAK,EAAE,IAAI;aAAE,KAAK;;aAClB,KAAK,EAAE,QAAQ;aAAE,KAAK;;aACtB,KAAK,EAAE,KAAK;aAAE,KAAK;EACZ,CAAA;AAEV,eAAO,MAAM,4BAA4B,UAAU,CAAA;AAEnD,eAAO,MAAM,0BAA0B;;;;GAItC,CAAA;AAED,eAAO,MAAM,yBAAyB,QAAQ,CAAA;AAE9C,eAAO,MAAM,uBAAuB;;;;GAInC,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/blocks/sections/base-section/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB;aAC3B,KAAK,EAAE,SAAS;aAAE,KAAK;;aACvB,KAAK,EAAE,MAAM;aAAE,KAAK;;aACpB,KAAK,EAAE,UAAU;aAAE,KAAK;;aACxB,KAAK,EAAE,OAAO;aAAE,KAAK;EACd,CAAA;AAEV,eAAO,MAAM,aAAa,YAAI,SAAS,EAAE,IAAI,EAAE,IAAI,CAAU,CAAA;AAE7D,eAAO,MAAM,+BAA+B,YAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAU,CAAA;AAEzE,eAAO,MAAM,+BAA+B,SAAS,CAAA;AAErD,eAAO,MAAM,sBAAsB;;;;GAIlC,CAAA;AAED,eAAO,MAAM,oBAAoB;aAC9B,KAAK,EAAE,UAAU;aAAE,KAAK;;aACxB,KAAK,EAAE,WAAW;aAAE,KAAK;;aACzB,KAAK,EAAE,aAAa;aAAE,KAAK;;aAC3B,KAAK,EAAE,cAAc;aAAE,KAAK;;aAC5B,KAAK,EAAE,aAAa;aAAE,KAAK;;aAC3B,KAAK,EAAE,cAAc;aAAE,KAAK;EACrB,CAAA;AAEV,eAAO,MAAM,iBAAiB;aAC3B,KAAK,EAAE,OAAO;aAAE,KAAK;;aACrB,KAAK,EAAE,OAAO;aAAE,KAAK;EACd,CAAA;AAEV,eAAO,MAAM,qBAAqB;aAC/B,KAAK,EAAE,IAAI;aAAE,KAAK;;aAClB,KAAK,EAAE,QAAQ;aAAE,KAAK;;aACtB,KAAK,EAAE,KAAK;aAAE,KAAK;EACZ,CAAA;AAEV,eAAO,MAAM,4BAA4B,UAAU,CAAA;AAEnD,eAAO,MAAM,0BAA0B;;;;GAItC,CAAA;AAED,eAAO,MAAM,yBAAyB,QAAQ,CAAA;AAE9C,eAAO,MAAM,uBAAuB;;;;GAInC,CAAA;AAED,eAAO,MAAM,qBAAqB;aAC/B,KAAK,EAAE,OAAO;aAAE,KAAK;;aACrB,KAAK,EAAE,SAAS;aAAE,KAAK;EAChB,CAAA;AAEV,eAAO,MAAM,0BAA0B;aACpC,KAAK,EAAE,UAAU;aAAE,KAAK;;aACxB,KAAK,EAAE,YAAY;aAAE,KAAK;;aAC1B,KAAK,EAAE,WAAW;aAAE,KAAK;;aACzB,KAAK,EAAE,aAAa;aAAE,KAAK;;aAC3B,KAAK,EAAE,eAAe;aAAE,KAAK;;aAC7B,KAAK,EAAE,cAAc;aAAE,KAAK;;aAC5B,KAAK,EAAE,aAAa;aAAE,KAAK;;aAC3B,KAAK,EAAE,eAAe;aAAE,KAAK;;aAC7B,KAAK,EAAE,cAAc;aAAE,KAAK;EACrB,CAAA;AAEV,eAAO,MAAM,wCAAwC,KAAK,CAAA"}
@@ -42,3 +42,19 @@ export const DECORATION_OFFSET_UNITS = [
42
42
  { value: 'rem', label: 'rem', default: 0 },
43
43
  { value: '%', label: '%', default: 0 },
44
44
  ];
45
+ export const BACKGROUND_IMAGE_FITS = [
46
+ { value: 'cover', label: __('Vyplnit (cover)', 'brilo-blocks') },
47
+ { value: 'contain', label: __('Celý obrázek (contain)', 'brilo-blocks') },
48
+ ];
49
+ export const BACKGROUND_IMAGE_POSITIONS = [
50
+ { value: 'left top', label: __('Vlevo nahoře', 'brilo-blocks') },
51
+ { value: 'center top', label: __('Nahoře', 'brilo-blocks') },
52
+ { value: 'right top', label: __('Vpravo nahoře', 'brilo-blocks') },
53
+ { value: 'left center', label: __('Vlevo', 'brilo-blocks') },
54
+ { value: 'center center', label: __('Uprostřed', 'brilo-blocks') },
55
+ { value: 'right center', label: __('Vpravo', 'brilo-blocks') },
56
+ { value: 'left bottom', label: __('Vlevo dole', 'brilo-blocks') },
57
+ { value: 'center bottom', label: __('Dole', 'brilo-blocks') },
58
+ { value: 'right bottom', label: __('Vpravo dole', 'brilo-blocks') },
59
+ ];
60
+ export const BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT = 40;
@@ -1 +1 @@
1
- {"version":3,"file":"controls.d.ts","sourceRoot":"","sources":["../../../../src/blocks/sections/base-section/controls.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,mBAAmB,EAMnB,kBAAkB,EAGnB,MAAM,SAAS,CAAA;AAqMhB,UAAU,iBAAiB;IACzB,UAAU,EAAE,mBAAmB,CAAA;IAC/B,aAAa,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAA;IAC5D,OAAO,EAAE,kBAAkB,EAAE,CAAA;CAC9B;AAED,wBAAgB,YAAY,CAAC,EAAC,UAAU,EAAE,aAAa,EAAE,OAAO,EAAC,EAAE,iBAAiB,+BA4EnF"}
1
+ {"version":3,"file":"controls.d.ts","sourceRoot":"","sources":["../../../../src/blocks/sections/base-section/controls.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAIV,mBAAmB,EAMnB,kBAAkB,EAGnB,MAAM,SAAS,CAAA;AA+RhB,UAAU,iBAAiB;IACzB,UAAU,EAAE,mBAAmB,CAAA;IAC/B,aAAa,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAA;IAC5D,OAAO,EAAE,kBAAkB,EAAE,CAAA;CAC9B;AAED,wBAAgB,YAAY,CAAC,EAAC,UAAU,EAAE,aAAa,EAAE,OAAO,EAAC,EAAE,iBAAiB,+BAkFnF"}
@@ -1,9 +1,9 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ColorPalette, ContrastChecker, MediaUpload, MediaUploadCheck } from '@wordpress/block-editor';
3
- import { BaseControl, Button, ButtonGroup, PanelBody, PanelRow, SelectControl, TextControl, __experimentalToggleGroupControl as ToggleGroupControl, __experimentalToggleGroupControlOption as ToggleGroupControlOption, __experimentalUnitControl as UnitControl, } from '@wordpress/components';
3
+ import { BaseControl, Button, ButtonGroup, PanelBody, PanelRow, RangeControl, SelectControl, TextControl, __experimentalToggleGroupControl as ToggleGroupControl, __experimentalToggleGroupControlOption as ToggleGroupControlOption, __experimentalUnitControl as UnitControl, } from '@wordpress/components';
4
4
  import { __ } from '@wordpress/i18n';
5
5
  import { useTenantColorPalette } from '../../../hooks/useTenantColorPalette';
6
- import { DECORATION_DEPTHS, DECORATION_MAX_WIDTH_DEFAULT, DECORATION_MAX_WIDTH_UNITS, DECORATION_OFFSET_DEFAULT, DECORATION_OFFSET_UNITS, DECORATION_POSITIONS, DECORATION_TRANSLATES, FLUID_DECORATION_DEFAULT_HEIGHT, FLUID_DECORATION_HEIGHT_PRESETS, FLUID_DECORATION_UNITS, SPACING_POSITIONS, SPACING_SIZES, } from './constants';
6
+ import { BACKGROUND_IMAGE_FITS, BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT, BACKGROUND_IMAGE_POSITIONS, DECORATION_DEPTHS, DECORATION_MAX_WIDTH_DEFAULT, DECORATION_MAX_WIDTH_UNITS, DECORATION_OFFSET_DEFAULT, DECORATION_OFFSET_UNITS, DECORATION_POSITIONS, DECORATION_TRANSLATES, FLUID_DECORATION_DEFAULT_HEIGHT, FLUID_DECORATION_HEIGHT_PRESETS, FLUID_DECORATION_UNITS, SPACING_POSITIONS, SPACING_SIZES, } from './constants';
7
7
  function FluidDecorationControl({ label, value, onChange }) {
8
8
  var _a;
9
9
  const img = value === null || value === void 0 ? void 0 : value.img;
@@ -34,14 +34,32 @@ function DecorationControl({ value, onChange }) {
34
34
  const handleRemove = () => onChange(undefined);
35
35
  return (_jsxs(BaseControl, { label: __('Obrázek', 'brilo-blocks'), __nextHasNoMarginBottom: true, children: [_jsx(MediaUploadCheck, { children: _jsx(MediaUpload, { onSelect: handleSelect, allowedTypes: ['image'], value: (img === null || img === void 0 ? void 0 : img.id) || 0, render: ({ open }) => (_jsxs(PanelRow, { children: [(img === null || img === void 0 ? void 0 : img.src) && _jsx("img", { src: img.src, alt: img.alt, style: { maxWidth: 48, maxHeight: 48, objectFit: 'contain' } }), _jsx(Button, { onClick: open, variant: "secondary", size: "small", children: (img === null || img === void 0 ? void 0 : img.src) ? __('Změnit', 'brilo-blocks') : __('Vybrat obrázek', 'brilo-blocks') }), !!(img === null || img === void 0 ? void 0 : img.src) && (_jsx(Button, { onClick: handleRemove, variant: "tertiary", size: "small", isDestructive: true, children: __('Odebrat', 'brilo-blocks') }))] })) }) }), !!(img === null || img === void 0 ? void 0 : img.src) && (_jsxs(_Fragment, { children: [_jsx(BaseControl, { label: __('Pozice', 'brilo-blocks'), __nextHasNoMarginBottom: true, children: _jsx("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 4 }, children: DECORATION_POSITIONS.map((p) => (_jsx(Button, { variant: "secondary", size: "small", isPressed: position === p.value, onClick: () => update({ position: p.value }), children: p.label }, p.value))) }) }), _jsx(ToggleGroupControl, { label: __('Vrstva', 'brilo-blocks'), value: depth, onChange: (next) => update({ depth: next }), isBlock: true, children: DECORATION_DEPTHS.map((d) => (_jsx(ToggleGroupControlOption, { value: d.value, label: d.label }, d.value))) }), _jsx(ToggleGroupControl, { label: __('Přesah', 'brilo-blocks'), value: translate, onChange: (next) => update({ translate: next }), isBlock: true, children: DECORATION_TRANSLATES.map((t) => (_jsx(ToggleGroupControlOption, { value: t.value, label: t.label }, t.value))) }), _jsx(UnitControl, { label: __('Max. šířka obrázku', 'brilo-blocks'), value: maxWidth, units: DECORATION_MAX_WIDTH_UNITS, onChange: (next) => { var _a; return update({ maxWidth: (_a = next) !== null && _a !== void 0 ? _a : DECORATION_MAX_WIDTH_DEFAULT }); } }), _jsxs(BaseControl, { label: __('Doladění pozice', 'brilo-blocks'), __nextHasNoMarginBottom: true, help: __('Ruční posun obrázku navíc k vybrané pozici.', 'brilo-blocks'), children: [_jsx(UnitControl, { label: __('Posun X', 'brilo-blocks'), value: offsetX, units: DECORATION_OFFSET_UNITS, onChange: (next) => { var _a; return update({ offsetX: (_a = next) !== null && _a !== void 0 ? _a : DECORATION_OFFSET_DEFAULT }); } }), _jsx(UnitControl, { label: __('Posun Y', 'brilo-blocks'), value: offsetY, units: DECORATION_OFFSET_UNITS, onChange: (next) => { var _a; return update({ offsetY: (_a = next) !== null && _a !== void 0 ? _a : DECORATION_OFFSET_DEFAULT }); } })] })] }))] }));
36
36
  }
37
+ function BackgroundImageControl({ value, onChange }) {
38
+ var _a, _b;
39
+ var _c, _d, _e;
40
+ const { paletteColors } = useTenantColorPalette();
41
+ const img = value === null || value === void 0 ? void 0 : value.img;
42
+ const fit = (_c = value === null || value === void 0 ? void 0 : value.fit) !== null && _c !== void 0 ? _c : 'cover';
43
+ const position = (_d = value === null || value === void 0 ? void 0 : value.position) !== null && _d !== void 0 ? _d : 'center center';
44
+ const overlayColor = (_a = value === null || value === void 0 ? void 0 : value.overlay) === null || _a === void 0 ? void 0 : _a.color;
45
+ const overlayOpacity = (_e = (_b = value === null || value === void 0 ? void 0 : value.overlay) === null || _b === void 0 ? void 0 : _b.opacity) !== null && _e !== void 0 ? _e : BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT;
46
+ const update = (patch) => onChange({ img, fit, position, overlay: value === null || value === void 0 ? void 0 : value.overlay, ...value, ...patch });
47
+ const handleSelect = (media) => {
48
+ var _a;
49
+ const nextImg = { id: media.id, src: media.url, alt: (_a = media.alt) !== null && _a !== void 0 ? _a : '', width: media.width, height: media.height };
50
+ update({ img: nextImg });
51
+ };
52
+ const handleRemove = () => onChange(undefined);
53
+ return (_jsxs(BaseControl, { label: __('Obrázek pozadí', 'brilo-blocks'), __nextHasNoMarginBottom: true, children: [_jsx(MediaUploadCheck, { children: _jsx(MediaUpload, { onSelect: handleSelect, allowedTypes: ['image'], value: (img === null || img === void 0 ? void 0 : img.id) || 0, render: ({ open }) => (_jsxs(PanelRow, { children: [(img === null || img === void 0 ? void 0 : img.src) && _jsx("img", { src: img.src, alt: img.alt, style: { maxWidth: 48, maxHeight: 48, objectFit: 'contain' } }), _jsx(Button, { onClick: open, variant: "secondary", size: "small", children: (img === null || img === void 0 ? void 0 : img.src) ? __('Změnit', 'brilo-blocks') : __('Vybrat obrázek', 'brilo-blocks') }), !!(img === null || img === void 0 ? void 0 : img.src) && (_jsx(Button, { onClick: handleRemove, variant: "tertiary", size: "small", isDestructive: true, children: __('Odebrat', 'brilo-blocks') }))] })) }) }), !!(img === null || img === void 0 ? void 0 : img.src) && (_jsxs(_Fragment, { children: [_jsx(ToggleGroupControl, { label: __('Přizpůsobení', 'brilo-blocks'), value: fit, onChange: (next) => update({ fit: next }), isBlock: true, children: BACKGROUND_IMAGE_FITS.map((f) => (_jsx(ToggleGroupControlOption, { value: f.value, label: f.label }, f.value))) }), _jsx(SelectControl, { label: __('Pozice', 'brilo-blocks'), value: position, options: [...BACKGROUND_IMAGE_POSITIONS], onChange: (next) => update({ position: next }) }), _jsxs(BaseControl, { label: __('Překryv barvou', 'brilo-blocks'), __nextHasNoMarginBottom: true, help: __('Ztmavení/zabarvení obrázku pro lepší čitelnost textu.', 'brilo-blocks'), children: [_jsx(ColorPalette, { colors: paletteColors, value: overlayColor || undefined, onChange: (next) => update({ overlay: { color: next !== null && next !== void 0 ? next : undefined, opacity: overlayOpacity } }) }), !!overlayColor && (_jsx(RangeControl, { label: __('Krytí překryvu', 'brilo-blocks'), value: overlayOpacity, min: 0, max: 100, onChange: (next) => update({ overlay: { color: overlayColor, opacity: next !== null && next !== void 0 ? next : BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT } }) }))] })] }))] }));
54
+ }
37
55
  export function BaseControls({ attributes, setAttributes, exclude }) {
38
56
  var _a;
39
- const { id, spacing, background, textColor, decoration, decorations } = attributes;
57
+ const { id, spacing, background, textColor, decoration, decorations, backgroundImage } = attributes;
40
58
  const { paletteColors, resolveHex } = useTenantColorPalette();
41
59
  const fluid = (_a = decorations === null || decorations === void 0 ? void 0 : decorations.fluid) !== null && _a !== void 0 ? _a : {};
42
60
  const setFluid = (position, value) => {
43
61
  const nextFluid = { ...fluid, [position]: value };
44
62
  setAttributes({ decorations: { ...decorations, fluid: nextFluid } });
45
63
  };
46
- return (_jsxs(_Fragment, { children: [!exclude.includes('spacing') && (_jsxs(PanelBody, { title: __('Rozestupy', 'brilo-blocks'), children: [_jsx(SelectControl, { label: __('Pozice', 'brilo-blocks'), value: spacing.position, options: [...SPACING_POSITIONS], onChange: (value) => setAttributes({ spacing: { ...spacing, position: value } }) }), _jsx(ToggleGroupControl, { label: __('Velikost', 'brilo-blocks'), value: spacing.size, onChange: (value) => setAttributes({ spacing: { ...spacing, size: value } }), isBlock: true, children: SPACING_SIZES.map((s) => (_jsx(ToggleGroupControlOption, { value: s, label: s === 'default' ? __('Výchozí', 'brilo-blocks') : s.toUpperCase() }, s))) })] })), !exclude.includes('background') && (_jsxs(PanelBody, { title: __('Barvy', 'brilo-blocks'), children: [_jsx("p", { children: __('Pozadí', 'brilo-blocks') }), _jsx(ColorPalette, { colors: paletteColors, value: background || undefined, onChange: (value) => setAttributes({ background: value !== null && value !== void 0 ? value : '' }) }), _jsx("p", { children: __('Barva textu', 'brilo-blocks') }), _jsx(ColorPalette, { colors: paletteColors, value: textColor || undefined, onChange: (value) => setAttributes({ textColor: value !== null && value !== void 0 ? value : '' }) }), !!background && !!textColor && _jsx(ContrastChecker, { backgroundColor: resolveHex(background), textColor: resolveHex(textColor) })] })), !exclude.includes('decoration') && (_jsx(PanelBody, { title: __('Dekorace', 'brilo-blocks'), initialOpen: false, children: _jsx(DecorationControl, { value: decoration, onChange: (value) => setAttributes({ decoration: value !== null && value !== void 0 ? value : {} }) }) })), !exclude.includes('decorations') && (_jsxs(PanelBody, { title: __('Fluidní dekorace', 'brilo-blocks'), initialOpen: false, children: [_jsx(FluidDecorationControl, { label: __('Nahoře', 'brilo-blocks'), value: fluid.top, onChange: (value) => setFluid('top', value) }), _jsx(FluidDecorationControl, { label: __('Dole', 'brilo-blocks'), value: fluid.bottom, onChange: (value) => setFluid('bottom', value) })] })), !exclude.includes('id') && (_jsx(PanelBody, { title: __('Kotva', 'brilo-blocks'), initialOpen: false, children: _jsx(TextControl, { label: __('ID sekce', 'brilo-blocks'), value: id !== null && id !== void 0 ? id : '', onChange: (value) => setAttributes({ id: value }), help: __('Použije se jako HTML atribut id pro kotevní odkaz.', 'brilo-blocks') }) }))] }));
64
+ return (_jsxs(_Fragment, { children: [!exclude.includes('spacing') && (_jsxs(PanelBody, { title: __('Rozestupy', 'brilo-blocks'), children: [_jsx(SelectControl, { label: __('Pozice', 'brilo-blocks'), value: spacing.position, options: [...SPACING_POSITIONS], onChange: (value) => setAttributes({ spacing: { ...spacing, position: value } }) }), _jsx(ToggleGroupControl, { label: __('Velikost', 'brilo-blocks'), value: spacing.size, onChange: (value) => setAttributes({ spacing: { ...spacing, size: value } }), isBlock: true, children: SPACING_SIZES.map((s) => (_jsx(ToggleGroupControlOption, { value: s, label: s === 'default' ? __('Výchozí', 'brilo-blocks') : s.toUpperCase() }, s))) })] })), !exclude.includes('background') && (_jsxs(PanelBody, { title: __('Barvy', 'brilo-blocks'), children: [_jsx("p", { children: __('Pozadí', 'brilo-blocks') }), _jsx(ColorPalette, { colors: paletteColors, value: background || undefined, onChange: (value) => setAttributes({ background: value !== null && value !== void 0 ? value : '' }) }), _jsx("p", { children: __('Barva textu', 'brilo-blocks') }), _jsx(ColorPalette, { colors: paletteColors, value: textColor || undefined, onChange: (value) => setAttributes({ textColor: value !== null && value !== void 0 ? value : '' }) }), !!background && !!textColor && _jsx(ContrastChecker, { backgroundColor: resolveHex(background), textColor: resolveHex(textColor) })] })), !exclude.includes('backgroundImage') && (_jsx(PanelBody, { title: __('Obrázek pozadí', 'brilo-blocks'), initialOpen: false, children: _jsx(BackgroundImageControl, { value: backgroundImage, onChange: (value) => setAttributes({ backgroundImage: value !== null && value !== void 0 ? value : {} }) }) })), !exclude.includes('decoration') && (_jsx(PanelBody, { title: __('Dekorace', 'brilo-blocks'), initialOpen: false, children: _jsx(DecorationControl, { value: decoration, onChange: (value) => setAttributes({ decoration: value !== null && value !== void 0 ? value : {} }) }) })), !exclude.includes('decorations') && (_jsxs(PanelBody, { title: __('Fluidní dekorace', 'brilo-blocks'), initialOpen: false, children: [_jsx(FluidDecorationControl, { label: __('Nahoře', 'brilo-blocks'), value: fluid.top, onChange: (value) => setFluid('top', value) }), _jsx(FluidDecorationControl, { label: __('Dole', 'brilo-blocks'), value: fluid.bottom, onChange: (value) => setFluid('bottom', value) })] })), !exclude.includes('id') && (_jsx(PanelBody, { title: __('Kotva', 'brilo-blocks'), initialOpen: false, children: _jsx(TextControl, { label: __('ID sekce', 'brilo-blocks'), value: id !== null && id !== void 0 ? id : '', onChange: (value) => setAttributes({ id: value }), help: __('Použije se jako HTML atribut id pro kotevní odkaz.', 'brilo-blocks') }) }))] }));
47
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../../../src/blocks/sections/base-section/edit.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,mBAAmB,CAAA;AACrD,OAAO,KAAK,EAAC,mBAAmB,EAAE,kBAAkB,EAAC,MAAM,SAAS,CAAA;AAGpE,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,WAG3G,cAAc,CAAC,mBAAmB,GAAG,MAAM,CAAC,iCAiCzE"}
1
+ {"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../../../src/blocks/sections/base-section/edit.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,mBAAmB,CAAA;AAErD,OAAO,KAAK,EAAC,mBAAmB,EAAE,kBAAkB,EAAC,MAAM,SAAS,CAAA;AAGpE,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,kBAAkB,CAAC,MAAM,CAAC,WAG3G,cAAc,CAAC,mBAAmB,GAAG,MAAM,CAAC,iCAgDzE"}
@@ -5,15 +5,31 @@ export function createBaseSectionEdit(options) {
5
5
  var _a;
6
6
  const EXCLUDE = (_a = options.exclude) !== null && _a !== void 0 ? _a : [];
7
7
  return function Edit(props) {
8
- var _a;
8
+ var _a, _b;
9
+ var _c, _d;
9
10
  const { attributes, setAttributes } = props;
10
- const { background, textColor, gradient } = attributes;
11
+ const { background, textColor, gradient, backgroundImage } = attributes;
12
+ const bgImageSrc = (_a = backgroundImage === null || backgroundImage === void 0 ? void 0 : backgroundImage.img) === null || _a === void 0 ? void 0 : _a.src;
13
+ // A plain background-color/gradient always paints behind an image, so it can never tint it. To preview a
14
+ // translucent color/gradient sitting on top of the image (matching frontend), stack it as its own layer
15
+ // in front of the `url(...)` layer instead of setting backgroundColor separately.
16
+ const tintLayer = background ? `linear-gradient(${background}, ${background})` : gradient;
11
17
  const blockProps = useBlockProps({
12
18
  className: options.blockClassName,
13
19
  style: {
14
- ...(background ? { backgroundColor: background, padding: '16px' } : {}),
15
- ...(gradient ? { background: gradient, padding: '16px' } : {}),
20
+ position: 'relative',
21
+ ...(background && !bgImageSrc ? { backgroundColor: background, padding: '16px' } : {}),
22
+ ...(gradient && !bgImageSrc ? { background: gradient, padding: '16px' } : {}),
16
23
  ...(textColor ? { color: textColor } : {}),
24
+ ...(bgImageSrc
25
+ ? {
26
+ backgroundImage: [tintLayer, `url(${bgImageSrc})`].filter(Boolean).join(', '),
27
+ backgroundSize: [tintLayer ? '100% 100%' : null, (_c = backgroundImage === null || backgroundImage === void 0 ? void 0 : backgroundImage.fit) !== null && _c !== void 0 ? _c : 'cover'].filter(Boolean).join(', '),
28
+ backgroundPosition: [tintLayer ? 'center center' : null, (_d = backgroundImage === null || backgroundImage === void 0 ? void 0 : backgroundImage.position) !== null && _d !== void 0 ? _d : 'center center'].filter(Boolean).join(', '),
29
+ backgroundRepeat: 'no-repeat',
30
+ padding: '16px',
31
+ }
32
+ : {}),
17
33
  },
18
34
  });
19
35
  const innerBlocksProps = useInnerBlocksProps({ className: options.containerClassName }, {
@@ -21,6 +37,6 @@ export function createBaseSectionEdit(options) {
21
37
  orientation: 'vertical',
22
38
  layout: { type: 'default' },
23
39
  });
24
- return (_jsxs(_Fragment, { children: [_jsxs(InspectorControls, { children: [_jsx(BaseControls, { attributes: attributes, setAttributes: setAttributes, exclude: EXCLUDE }), (_a = options.extraControls) === null || _a === void 0 ? void 0 : _a.call(options, props)] }), _jsx("div", { ...blockProps, children: _jsx("div", { ...innerBlocksProps }) })] }));
40
+ return (_jsxs(_Fragment, { children: [_jsxs(InspectorControls, { children: [_jsx(BaseControls, { attributes: attributes, setAttributes: setAttributes, exclude: EXCLUDE }), (_b = options.extraControls) === null || _b === void 0 ? void 0 : _b.call(options, props)] }), _jsx("div", { ...blockProps, children: _jsx("div", { ...innerBlocksProps }) })] }));
25
41
  };
26
42
  }
@@ -25,6 +25,18 @@ export interface Decoration {
25
25
  offsetX?: string;
26
26
  offsetY?: string;
27
27
  }
28
+ export type BackgroundImageFit = 'cover' | 'contain';
29
+ export type BackgroundImagePosition = 'left top' | 'center top' | 'right top' | 'left center' | 'center center' | 'right center' | 'left bottom' | 'center bottom' | 'right bottom';
30
+ export interface BackgroundImageOverlay {
31
+ color?: string;
32
+ opacity?: number;
33
+ }
34
+ export interface BackgroundImage {
35
+ img?: FluidDecorationImage;
36
+ fit?: BackgroundImageFit;
37
+ position?: BackgroundImagePosition;
38
+ overlay?: BackgroundImageOverlay;
39
+ }
28
40
  export interface BaseBlockAttributes extends Record<string, unknown> {
29
41
  id: string;
30
42
  spacing: {
@@ -40,8 +52,9 @@ export interface BaseBlockAttributes extends Record<string, unknown> {
40
52
  bottom?: FluidDecoration;
41
53
  };
42
54
  };
55
+ backgroundImage: BackgroundImage;
43
56
  }
44
- export type ExcludableBaseAttr = 'spacing' | 'background' | 'id' | 'decorations' | 'decoration';
57
+ export type ExcludableBaseAttr = 'spacing' | 'background' | 'id' | 'decorations' | 'decoration' | 'backgroundImage';
45
58
  export interface BaseSectionOptions<TExtra extends Record<string, unknown> = Record<string, never>> extends BriloBlockType {
46
59
  supports?: BlockConfiguration['supports'];
47
60
  extraAttributes?: {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/blocks/sections/base-section/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,kBAAkB,EAAE,cAAc,EAAC,MAAM,mBAAmB,CAAA;AACzE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAA;AACpC,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,SAAS,CAAA;AAE3C,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,oBAAoB,CAAA;IAC1B,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,MAAM,eAAe,GAAG,oBAAoB,CAAA;AAElD,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,GAAG,aAAa,GAAG,cAAc,CAAA;AAC3H,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,CAAA;AAC/C,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG,QAAQ,GAAG,KAAK,CAAA;AAEzD,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,eAAe,CAAA;IACrB,QAAQ,CAAC,EAAE,kBAAkB,CAAA;IAC7B,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,SAAS,CAAC,EAAE,mBAAmB,CAAA;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,mBAAoB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAClE,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAA;QAChB,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,UAAU,CAAA;IACtB,WAAW,EAAE;QACX,KAAK,CAAC,EAAE;YACN,GAAG,CAAC,EAAE,eAAe,CAAA;YACrB,MAAM,CAAC,EAAE,eAAe,CAAA;SACzB,CAAA;KACF,CAAA;CACF;AAED,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,YAAY,GAAG,IAAI,GAAG,aAAa,GAAG,YAAY,CAAA;AAE/F,MAAM,WAAW,kBAAkB,CAAC,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAE,SAAQ,cAAc;IACxH,QAAQ,CAAC,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAA;IACzC,eAAe,CAAC,EAAE;SACf,CAAC,IAAI,MAAM,MAAM,GAAG;YACnB,IAAI,EAAE,MAAM,CAAA;YACZ,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;SACnB;KACF,CAAA;IACD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,CAAC,mBAAmB,GAAG,MAAM,CAAC,KAAK,SAAS,CAAA;IAClF,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAA;CAC/B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/blocks/sections/base-section/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brilo/base-blocks",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "author": "Brilo",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -26,4 +26,11 @@ export const baseAttributes = {
26
26
  type: 'object',
27
27
  default: {},
28
28
  },
29
+ backgroundImage: {
30
+ type: 'object',
31
+ default: {
32
+ fit: 'cover',
33
+ position: 'center center',
34
+ },
35
+ },
29
36
  } as const
@@ -54,3 +54,22 @@ export const DECORATION_OFFSET_UNITS = [
54
54
  {value: 'rem', label: 'rem', default: 0},
55
55
  {value: '%', label: '%', default: 0},
56
56
  ]
57
+
58
+ export const BACKGROUND_IMAGE_FITS = [
59
+ {value: 'cover', label: __('Vyplnit (cover)', 'brilo-blocks')},
60
+ {value: 'contain', label: __('Celý obrázek (contain)', 'brilo-blocks')},
61
+ ] as const
62
+
63
+ export const BACKGROUND_IMAGE_POSITIONS = [
64
+ {value: 'left top', label: __('Vlevo nahoře', 'brilo-blocks')},
65
+ {value: 'center top', label: __('Nahoře', 'brilo-blocks')},
66
+ {value: 'right top', label: __('Vpravo nahoře', 'brilo-blocks')},
67
+ {value: 'left center', label: __('Vlevo', 'brilo-blocks')},
68
+ {value: 'center center', label: __('Uprostřed', 'brilo-blocks')},
69
+ {value: 'right center', label: __('Vpravo', 'brilo-blocks')},
70
+ {value: 'left bottom', label: __('Vlevo dole', 'brilo-blocks')},
71
+ {value: 'center bottom', label: __('Dole', 'brilo-blocks')},
72
+ {value: 'right bottom', label: __('Vpravo dole', 'brilo-blocks')},
73
+ ] as const
74
+
75
+ export const BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT = 40
@@ -5,6 +5,7 @@ import {
5
5
  ButtonGroup,
6
6
  PanelBody,
7
7
  PanelRow,
8
+ RangeControl,
8
9
  SelectControl,
9
10
  TextControl,
10
11
  __experimentalToggleGroupControl as ToggleGroupControl,
@@ -14,6 +15,9 @@ import {
14
15
  import {__} from '@wordpress/i18n'
15
16
  import {useTenantColorPalette} from '~/hooks/useTenantColorPalette'
16
17
  import type {
18
+ BackgroundImage,
19
+ BackgroundImageFit,
20
+ BackgroundImagePosition,
17
21
  BaseBlockAttributes,
18
22
  Decoration,
19
23
  DecorationDepth,
@@ -25,6 +29,9 @@ import type {
25
29
  FluidDecorationImage,
26
30
  } from './types'
27
31
  import {
32
+ BACKGROUND_IMAGE_FITS,
33
+ BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT,
34
+ BACKGROUND_IMAGE_POSITIONS,
28
35
  DECORATION_DEPTHS,
29
36
  DECORATION_MAX_WIDTH_DEFAULT,
30
37
  DECORATION_MAX_WIDTH_UNITS,
@@ -217,6 +224,93 @@ function DecorationControl({value, onChange}: DecorationControlProps) {
217
224
  )
218
225
  }
219
226
 
227
+ interface BackgroundImageControlProps {
228
+ value?: BackgroundImage
229
+ onChange: (value: BackgroundImage | undefined) => void
230
+ }
231
+
232
+ function BackgroundImageControl({value, onChange}: BackgroundImageControlProps) {
233
+ const {paletteColors} = useTenantColorPalette()
234
+ const img = value?.img
235
+ const fit = value?.fit ?? 'cover'
236
+ const position = value?.position ?? 'center center'
237
+ const overlayColor = value?.overlay?.color
238
+ const overlayOpacity = value?.overlay?.opacity ?? BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT
239
+
240
+ const update = (patch: Partial<BackgroundImage>) => onChange({img, fit, position, overlay: value?.overlay, ...value, ...patch})
241
+
242
+ const handleSelect = (media: {id: number; url: string; alt: string; width?: number; height?: number}) => {
243
+ const nextImg: FluidDecorationImage = {id: media.id, src: media.url, alt: media.alt ?? '', width: media.width, height: media.height}
244
+ update({img: nextImg})
245
+ }
246
+
247
+ const handleRemove = () => onChange(undefined)
248
+
249
+ return (
250
+ <BaseControl label={__('Obrázek pozadí', 'brilo-blocks')} __nextHasNoMarginBottom>
251
+ <MediaUploadCheck>
252
+ <MediaUpload
253
+ onSelect={handleSelect}
254
+ allowedTypes={['image']}
255
+ value={img?.id || 0}
256
+ render={({open}: {open: () => void}) => (
257
+ <PanelRow>
258
+ {img?.src && <img src={img.src} alt={img.alt} style={{maxWidth: 48, maxHeight: 48, objectFit: 'contain'}} />}
259
+ <Button onClick={open} variant="secondary" size="small">
260
+ {img?.src ? __('Změnit', 'brilo-blocks') : __('Vybrat obrázek', 'brilo-blocks')}
261
+ </Button>
262
+ {!!img?.src && (
263
+ <Button onClick={handleRemove} variant="tertiary" size="small" isDestructive>
264
+ {__('Odebrat', 'brilo-blocks')}
265
+ </Button>
266
+ )}
267
+ </PanelRow>
268
+ )}
269
+ />
270
+ </MediaUploadCheck>
271
+
272
+ {!!img?.src && (
273
+ <>
274
+ <ToggleGroupControl
275
+ label={__('Přizpůsobení', 'brilo-blocks')}
276
+ value={fit}
277
+ onChange={(next) => update({fit: next as BackgroundImageFit})}
278
+ isBlock
279
+ >
280
+ {BACKGROUND_IMAGE_FITS.map((f) => (
281
+ <ToggleGroupControlOption key={f.value} value={f.value} label={f.label} />
282
+ ))}
283
+ </ToggleGroupControl>
284
+
285
+ <SelectControl<string>
286
+ label={__('Pozice', 'brilo-blocks')}
287
+ value={position}
288
+ options={[...BACKGROUND_IMAGE_POSITIONS]}
289
+ onChange={(next) => update({position: next as BackgroundImagePosition})}
290
+ />
291
+
292
+ <BaseControl label={__('Překryv barvou', 'brilo-blocks')} __nextHasNoMarginBottom help={__('Ztmavení/zabarvení obrázku pro lepší čitelnost textu.', 'brilo-blocks')}>
293
+ <ColorPalette
294
+ colors={paletteColors}
295
+ value={overlayColor || undefined}
296
+ onChange={(next) => update({overlay: {color: next ?? undefined, opacity: overlayOpacity}})}
297
+ />
298
+ {!!overlayColor && (
299
+ <RangeControl
300
+ label={__('Krytí překryvu', 'brilo-blocks')}
301
+ value={overlayOpacity}
302
+ min={0}
303
+ max={100}
304
+ onChange={(next) => update({overlay: {color: overlayColor, opacity: next ?? BACKGROUND_IMAGE_OVERLAY_OPACITY_DEFAULT}})}
305
+ />
306
+ )}
307
+ </BaseControl>
308
+ </>
309
+ )}
310
+ </BaseControl>
311
+ )
312
+ }
313
+
220
314
  type SpacingPosition = BaseBlockAttributes['spacing']['position']
221
315
  type SpacingSize = BaseBlockAttributes['spacing']['size']
222
316
 
@@ -227,7 +321,7 @@ interface BaseControlsProps {
227
321
  }
228
322
 
229
323
  export function BaseControls({attributes, setAttributes, exclude}: BaseControlsProps) {
230
- const {id, spacing, background, textColor, decoration, decorations} = attributes
324
+ const {id, spacing, background, textColor, decoration, decorations, backgroundImage} = attributes
231
325
  const {paletteColors, resolveHex} = useTenantColorPalette()
232
326
  const fluid = decorations?.fluid ?? {}
233
327
 
@@ -277,6 +371,12 @@ export function BaseControls({attributes, setAttributes, exclude}: BaseControlsP
277
371
  </PanelBody>
278
372
  )}
279
373
 
374
+ {!exclude.includes('backgroundImage') && (
375
+ <PanelBody title={__('Obrázek pozadí', 'brilo-blocks')} initialOpen={false}>
376
+ <BackgroundImageControl value={backgroundImage} onChange={(value) => setAttributes({backgroundImage: value ?? {}})} />
377
+ </PanelBody>
378
+ )}
379
+
280
380
  {!exclude.includes('decoration') && (
281
381
  <PanelBody title={__('Dekorace', 'brilo-blocks')} initialOpen={false}>
282
382
  <DecorationControl value={decoration} onChange={(value) => setAttributes({decoration: value ?? {}})} />
@@ -1,5 +1,6 @@
1
1
  import {InspectorControls, useBlockProps, useInnerBlocksProps} from '@wordpress/block-editor'
2
2
  import type {BlockEditProps} from '@wordpress/blocks'
3
+ import type {CSSProperties} from 'react'
3
4
  import type {BaseBlockAttributes, BaseSectionOptions} from './types'
4
5
  import {BaseControls} from './controls'
5
6
 
@@ -8,13 +9,28 @@ export function createBaseSectionEdit<TExtra extends Record<string, unknown> = R
8
9
 
9
10
  return function Edit(props: BlockEditProps<BaseBlockAttributes & TExtra>) {
10
11
  const {attributes, setAttributes} = props
11
- const {background, textColor, gradient} = attributes as BaseBlockAttributes & {gradient?: string}
12
+ const {background, textColor, gradient, backgroundImage} = attributes as BaseBlockAttributes & {gradient?: string}
13
+ const bgImageSrc = backgroundImage?.img?.src
14
+ // A plain background-color/gradient always paints behind an image, so it can never tint it. To preview a
15
+ // translucent color/gradient sitting on top of the image (matching frontend), stack it as its own layer
16
+ // in front of the `url(...)` layer instead of setting backgroundColor separately.
17
+ const tintLayer = background ? `linear-gradient(${background}, ${background})` : gradient
12
18
  const blockProps = useBlockProps({
13
19
  className: options.blockClassName,
14
20
  style: {
15
- ...(background ? {backgroundColor: background, padding: '16px'} : {}),
16
- ...(gradient ? {background: gradient, padding: '16px'} : {}),
21
+ position: 'relative' as CSSProperties['position'],
22
+ ...(background && !bgImageSrc ? {backgroundColor: background, padding: '16px'} : {}),
23
+ ...(gradient && !bgImageSrc ? {background: gradient, padding: '16px'} : {}),
17
24
  ...(textColor ? {color: textColor} : {}),
25
+ ...(bgImageSrc
26
+ ? {
27
+ backgroundImage: [tintLayer, `url(${bgImageSrc})`].filter(Boolean).join(', '),
28
+ backgroundSize: [tintLayer ? '100% 100%' : null, backgroundImage?.fit ?? 'cover'].filter(Boolean).join(', '),
29
+ backgroundPosition: [tintLayer ? 'center center' : null, backgroundImage?.position ?? 'center center'].filter(Boolean).join(', '),
30
+ backgroundRepeat: 'no-repeat',
31
+ padding: '16px',
32
+ }
33
+ : {}),
18
34
  },
19
35
  })
20
36
  const innerBlocksProps = useInnerBlocksProps({className: options.containerClassName}, {
@@ -31,6 +31,25 @@ export interface Decoration {
31
31
  offsetY?: string
32
32
  }
33
33
 
34
+ export type BackgroundImageFit = 'cover' | 'contain'
35
+
36
+ export type BackgroundImagePosition =
37
+ | 'left top' | 'center top' | 'right top'
38
+ | 'left center' | 'center center' | 'right center'
39
+ | 'left bottom' | 'center bottom' | 'right bottom'
40
+
41
+ export interface BackgroundImageOverlay {
42
+ color?: string
43
+ opacity?: number
44
+ }
45
+
46
+ export interface BackgroundImage {
47
+ img?: FluidDecorationImage
48
+ fit?: BackgroundImageFit
49
+ position?: BackgroundImagePosition
50
+ overlay?: BackgroundImageOverlay
51
+ }
52
+
34
53
  export interface BaseBlockAttributes extends Record<string, unknown> {
35
54
  id: string
36
55
  spacing: {
@@ -46,9 +65,10 @@ export interface BaseBlockAttributes extends Record<string, unknown> {
46
65
  bottom?: FluidDecoration
47
66
  }
48
67
  }
68
+ backgroundImage: BackgroundImage
49
69
  }
50
70
 
51
- export type ExcludableBaseAttr = 'spacing' | 'background' | 'id' | 'decorations' | 'decoration'
71
+ export type ExcludableBaseAttr = 'spacing' | 'background' | 'id' | 'decorations' | 'decoration' | 'backgroundImage'
52
72
 
53
73
  export interface BaseSectionOptions<TExtra extends Record<string, unknown> = Record<string, never>> extends BriloBlockType {
54
74
  supports?: BlockConfiguration['supports']