@brilo/base-blocks 0.1.50 → 0.1.53

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 (73) hide show
  1. package/build/.tsbuildinfo +1 -1
  2. package/build/blocks/accordion/accordion-group/edit.d.ts.map +1 -1
  3. package/build/blocks/accordion/accordion-group/edit.js +8 -2
  4. package/build/blocks/accordion/accordion-group/factory.d.ts.map +1 -1
  5. package/build/blocks/accordion/accordion-group/factory.js +20 -11
  6. package/build/blocks/accordion/accordion-group/index.d.ts +2 -1
  7. package/build/blocks/accordion/accordion-group/index.d.ts.map +1 -1
  8. package/build/blocks/accordion/accordion-group/index.js +1 -0
  9. package/build/blocks/accordion/accordion-group/types.d.ts +8 -0
  10. package/build/blocks/accordion/accordion-group/types.d.ts.map +1 -1
  11. package/build/blocks/contact/contact-group/factory.d.ts.map +1 -1
  12. package/build/blocks/contact/contact-group/types.d.ts.map +1 -1
  13. package/build/blocks/contact/contact-item/edit.d.ts.map +1 -1
  14. package/build/blocks/faq/faq-group/constants.d.ts +0 -10
  15. package/build/blocks/faq/faq-group/constants.d.ts.map +1 -1
  16. package/build/blocks/faq/faq-group/constants.js +0 -5
  17. package/build/blocks/faq/faq-group/edit.d.ts.map +1 -1
  18. package/build/blocks/faq/faq-group/edit.js +6 -4
  19. package/build/blocks/faq/faq-group/factory.d.ts.map +1 -1
  20. package/build/blocks/faq/faq-group/factory.js +9 -10
  21. package/build/blocks/faq/faq-group/types.d.ts +6 -7
  22. package/build/blocks/faq/faq-group/types.d.ts.map +1 -1
  23. package/build/blocks/layout/box/constants.d.ts +12 -0
  24. package/build/blocks/layout/box/constants.d.ts.map +1 -0
  25. package/build/blocks/layout/box/constants.js +15 -0
  26. package/build/blocks/layout/box/controls.d.ts.map +1 -1
  27. package/build/blocks/layout/box/controls.js +6 -5
  28. package/build/blocks/layout/box/deprecated.d.ts +71 -0
  29. package/build/blocks/layout/box/deprecated.d.ts.map +1 -0
  30. package/build/blocks/layout/box/deprecated.js +100 -0
  31. package/build/blocks/layout/box/edit.d.ts.map +1 -1
  32. package/build/blocks/layout/box/edit.js +14 -18
  33. package/build/blocks/layout/box/factory.d.ts.map +1 -1
  34. package/build/blocks/layout/box/factory.js +4 -2
  35. package/build/blocks/layout/box/index.d.ts +1 -1
  36. package/build/blocks/layout/box/index.d.ts.map +1 -1
  37. package/build/blocks/layout/box/types.d.ts +5 -14
  38. package/build/blocks/layout/box/types.d.ts.map +1 -1
  39. package/build/blocks/sections/base-section/controls.d.ts.map +1 -1
  40. package/build/blocks/sections/base-section/controls.js +4 -3
  41. package/build/blocks/sections/base-section/types.d.ts +1 -0
  42. package/build/blocks/sections/base-section/types.d.ts.map +1 -1
  43. package/build/blocks/step/step-group/edit.d.ts.map +1 -1
  44. package/build/components/SurfaceStyleControl/index.d.ts +53 -0
  45. package/build/components/SurfaceStyleControl/index.d.ts.map +1 -0
  46. package/build/components/SurfaceStyleControl/index.js +36 -0
  47. package/build/index.d.ts +5 -3
  48. package/build/index.d.ts.map +1 -1
  49. package/build/index.js +2 -1
  50. package/package.json +1 -1
  51. package/src/blocks/accordion/accordion-group/edit.tsx +16 -1
  52. package/src/blocks/accordion/accordion-group/factory.tsx +19 -7
  53. package/src/blocks/accordion/accordion-group/index.ts +8 -1
  54. package/src/blocks/accordion/accordion-group/types.ts +11 -1
  55. package/src/blocks/contact/contact-group/factory.tsx +1 -6
  56. package/src/blocks/contact/contact-group/types.ts +1 -7
  57. package/src/blocks/contact/contact-item/edit.tsx +1 -4
  58. package/src/blocks/faq/faq-group/constants.ts +0 -6
  59. package/src/blocks/faq/faq-group/edit.tsx +11 -56
  60. package/src/blocks/faq/faq-group/factory.tsx +6 -6
  61. package/src/blocks/faq/faq-group/types.ts +6 -7
  62. package/src/blocks/layout/box/constants.ts +19 -0
  63. package/src/blocks/layout/box/controls.tsx +42 -21
  64. package/src/blocks/layout/box/deprecated.tsx +146 -0
  65. package/src/blocks/layout/box/edit.tsx +15 -18
  66. package/src/blocks/layout/box/factory.tsx +4 -2
  67. package/src/blocks/layout/box/index.ts +1 -1
  68. package/src/blocks/layout/box/types.ts +5 -14
  69. package/src/blocks/sections/base-section/controls.tsx +10 -1
  70. package/src/blocks/sections/base-section/types.ts +1 -0
  71. package/src/blocks/step/step-group/edit.tsx +11 -11
  72. package/src/components/SurfaceStyleControl/index.tsx +114 -0
  73. package/src/index.ts +11 -3
@@ -1,27 +1,12 @@
1
1
  import {InspectorControls} from '@wordpress/block-editor'
2
- import {
3
- BaseControl,
4
- Button,
5
- ColorPalette,
6
- PanelBody,
7
- RangeControl,
8
- SelectControl,
9
- __experimentalToggleGroupControl as ToggleGroupControl,
10
- __experimentalToggleGroupControlOption as ToggleGroupControlOption,
11
- } from '@wordpress/components'
2
+ import {BaseControl, Button, ColorPalette, PanelBody, RangeControl, SelectControl} from '@wordpress/components'
12
3
  import {__} from '@wordpress/i18n'
13
4
  import {ItemSpacingPanel, itemSpacingStyle} from '~/components/ItemSpacingControl'
5
+ import {DEFAULT_SURFACE_SHADOWS, SurfaceStylePanel} from '~/components/SurfaceStyleControl'
14
6
  import {useGroupBlock} from '~/hooks/useGroupBlock'
15
7
  import {useTenantColorPalette} from '~/hooks/useTenantColorPalette'
16
- import {
17
- DEFAULT_ICON_SIZE_PRESETS,
18
- DEFAULT_ICON_VARIANTS,
19
- DEFAULT_SHADOWS,
20
- FAQ_HEADING_LEVELS,
21
- ICON_SIZE_MAX,
22
- ICON_SIZE_MIN,
23
- } from './constants'
24
- import type {FaqGroupAttributes, FaqGroupOptions, FaqHeadingLevel, FaqIconVariant, FaqShadow, FaqSizePreset} from './types'
8
+ import {DEFAULT_ICON_SIZE_PRESETS, DEFAULT_ICON_VARIANTS, FAQ_HEADING_LEVELS, ICON_SIZE_MAX, ICON_SIZE_MIN} from './constants'
9
+ import type {FaqGroupAttributes, FaqGroupOptions, FaqHeadingLevel, FaqIconVariant, FaqSizePreset} from './types'
25
10
 
26
11
  function PresetSizeControl({
27
12
  label,
@@ -56,6 +41,7 @@ export function createFaqGroupEdit(options: FaqGroupOptions) {
56
41
  const ICON_VARIANTS = options.iconVariants ?? DEFAULT_ICON_VARIANTS
57
42
  const ICON_SIZE_PRESETS = options.iconSizePresets ?? DEFAULT_ICON_SIZE_PRESETS
58
43
  const exclude = options.exclude ?? []
44
+ const shadows = options.shadows ?? DEFAULT_SURFACE_SHADOWS
59
45
 
60
46
  return function Edit({
61
47
  attributes,
@@ -123,43 +109,12 @@ export function createFaqGroupEdit(options: FaqGroupOptions) {
123
109
  )}
124
110
  </PanelBody>
125
111
  {!exclude.includes('colors') && style && (
126
- <PanelBody title={__('Styl', 'brilo-blocks')}>
127
- <ToggleGroupControl
128
- isBlock
129
- label={__('Stín', 'brilo-blocks')}
130
- value={style.shadow}
131
- onChange={(v) => setAttributes({style: {...style, shadow: v as FaqShadow}})}
132
- >
133
- {DEFAULT_SHADOWS.map((s) => (
134
- <ToggleGroupControlOption key={s.value} value={s.value} label={s.label} />
135
- ))}
136
- </ToggleGroupControl>
137
- <BaseControl
138
- label={__('Barva okraje', 'brilo-blocks')}
139
- help={__('Bez vybrané barvy se okraj nevykreslí.', 'brilo-blocks')}
140
- id="faq-group-border-color"
141
- >
142
- <ColorPalette
143
- colors={paletteColors}
144
- value={style.borderColor || undefined}
145
- onChange={(value) => setAttributes({style: {...style, borderColor: value ?? ''}})}
146
- />
147
- </BaseControl>
148
- <BaseControl label={__('Barva pozadí', 'brilo-blocks')} id="faq-group-background-color">
149
- <ColorPalette
150
- colors={paletteColors}
151
- value={style.backgroundColor || undefined}
152
- onChange={(value) => setAttributes({style: {...style, backgroundColor: value ?? ''}})}
153
- />
154
- </BaseControl>
155
- <BaseControl label={__('Barva textu', 'brilo-blocks')} id="faq-group-text-color">
156
- <ColorPalette
157
- colors={paletteColors}
158
- value={style.textColor || undefined}
159
- onChange={(value) => setAttributes({style: {...style, textColor: value ?? ''}})}
160
- />
161
- </BaseControl>
162
- </PanelBody>
112
+ <SurfaceStylePanel
113
+ style={style}
114
+ shadows={shadows}
115
+ idPrefix="faq-group"
116
+ onChange={(next) => setAttributes({style: {...style, ...next}})}
117
+ />
163
118
  )}
164
119
  <ItemSpacingPanel spacing={spacing} onChange={(v) => setAttributes({spacing: v})} />
165
120
  </InspectorControls>
@@ -3,7 +3,8 @@ import type {BlockConfiguration} from '@wordpress/blocks'
3
3
  import {__} from '@wordpress/i18n'
4
4
  import {ITEM_SPACING_ATTRIBUTE} from '~/components/ItemSpacingControl'
5
5
  import type {OptionArray} from '~/types'
6
- import {DEFAULT_ICON_SIZE, DEFAULT_ICON_VARIANTS, DEFAULT_SHADOWS, FAQ_HEADING_LEVELS} from './constants'
6
+ import {DEFAULT_SURFACE_SHADOWS, surfaceStyleAttribute} from '~/components/SurfaceStyleControl'
7
+ import {DEFAULT_ICON_SIZE, DEFAULT_ICON_VARIANTS, FAQ_HEADING_LEVELS} from './constants'
7
8
  import {createFaqGroupEdit} from './edit'
8
9
  import type {FaqGroupAttributes, FaqGroupOptions} from './types'
9
10
 
@@ -30,13 +31,12 @@ export function createFaqGroupBlock<TIconVariants extends OptionArray = typeof D
30
31
  }
31
32
 
32
33
  if (!exclude.includes('colors')) {
34
+ const surfaceStyle = surfaceStyleAttribute(options.shadows ?? DEFAULT_SURFACE_SHADOWS)
35
+
33
36
  attributes.style = {
34
- type: 'object',
37
+ ...surfaceStyle,
35
38
  default: {
36
- shadow: DEFAULT_SHADOWS[0].value,
37
- borderColor: '',
38
- backgroundColor: '',
39
- textColor: '',
39
+ ...surfaceStyle.default,
40
40
  icon: {
41
41
  color: '',
42
42
  background: '',
@@ -1,9 +1,10 @@
1
+ import type {SurfaceShadowOption, SurfaceStyle} from '~/components/SurfaceStyleControl'
1
2
  import type {BriloBlockType, OptionArray} from '~/types'
2
- import type {DEFAULT_ICON_VARIANTS, DEFAULT_SHADOWS, FAQ_HEADING_LEVELS} from './constants'
3
+ import type {DEFAULT_ICON_VARIANTS, FAQ_HEADING_LEVELS} from './constants'
3
4
 
4
5
  export type FaqHeadingLevel = (typeof FAQ_HEADING_LEVELS)[number]
5
6
  export type FaqIconVariant = (typeof DEFAULT_ICON_VARIANTS)[number]['value']
6
- export type FaqShadow = (typeof DEFAULT_SHADOWS)[number]['value']
7
+ export type FaqShadow = SurfaceStyle['shadow']
7
8
 
8
9
  export type ExcludableFaqAttr = 'colors'
9
10
 
@@ -15,11 +16,7 @@ export interface FaqSizePreset {
15
16
  export interface FaqGroupAttributes<TIconVariant extends string = FaqIconVariant> extends Record<string, unknown> {
16
17
  headingLevel: FaqHeadingLevel
17
18
  iconVariant: TIconVariant
18
- style: {
19
- shadow: FaqShadow
20
- borderColor: string
21
- backgroundColor: string
22
- textColor: string
19
+ style: SurfaceStyle<string> & {
23
20
  icon: {
24
21
  color: string
25
22
  background: string
@@ -33,4 +30,6 @@ export interface FaqGroupOptions<TIconVariants extends OptionArray = typeof DEFA
33
30
  iconVariants?: TIconVariants
34
31
  iconSizePresets?: readonly FaqSizePreset[]
35
32
  exclude?: ExcludableFaqAttr[]
33
+ /** Overrides the shared shadow presets — see `DEFAULT_SURFACE_SHADOWS`. */
34
+ shadows?: readonly SurfaceShadowOption[]
36
35
  }
@@ -0,0 +1,19 @@
1
+ import {__} from '@wordpress/i18n'
2
+ import {justifyBottom, justifyLeft, justifyRight, justifyTop} from '@wordpress/icons'
3
+ import type {ReactElement} from 'react'
4
+ import type {BoxSpacingSide} from './types'
5
+
6
+ /** Sides shared by the padding and margin panels, in CSS shorthand order. */
7
+ export const BOX_SPACING_SIDES: readonly {value: BoxSpacingSide; label: string; icon: ReactElement}[] = [
8
+ {value: 'top', label: __('Nahoře', 'brilo-blocks'), icon: justifyTop},
9
+ {value: 'right', label: __('Vpravo', 'brilo-blocks'), icon: justifyRight},
10
+ {value: 'bottom', label: __('Dole', 'brilo-blocks'), icon: justifyBottom},
11
+ {value: 'left', label: __('Vlevo', 'brilo-blocks'), icon: justifyLeft},
12
+ ] as const
13
+
14
+ // All box lengths are plain pixel numbers — the same convention as the shared
15
+ // `spacing` attribute — so the editor needs no unit picker and the template
16
+ // appends the unit.
17
+ export const BOX_SPACING_MAX = 120
18
+ export const BOX_BORDER_WIDTH_MAX = 20
19
+ export const BOX_BORDER_RADIUS_MAX = 64
@@ -1,43 +1,55 @@
1
- import * as blockEditor from '@wordpress/block-editor'
2
1
  import {ColorPalette, ContrastChecker} from '@wordpress/block-editor'
3
- import {BoxControl, PanelBody, __experimentalUnitControl as UnitControl} from '@wordpress/components'
2
+ import {PanelBody, RangeControl} from '@wordpress/components'
4
3
  import {__} from '@wordpress/i18n'
5
- import type {ComponentType} from 'react'
6
4
  import {useTenantColorPalette} from '~/hooks/useTenantColorPalette'
7
- import type {BoxAttributes, BoxBorderRadius} from './types'
8
-
9
- // `__experimentalBorderRadiusControl` is a real runtime export of @wordpress/block-editor (see
10
- // packages/block-editor/src/components/border-radius-control) but isn't covered by the community
11
- // @types/wordpress__block-editor typings, so it's pulled off the namespace import and cast by hand.
12
- interface BorderRadiusControlProps {
13
- values?: string | BoxBorderRadius
14
- onChange: (next: string | BoxBorderRadius | undefined) => void
15
- }
16
- const BorderRadiusControl = (blockEditor as unknown as {__experimentalBorderRadiusControl: ComponentType<BorderRadiusControlProps>})
17
- .__experimentalBorderRadiusControl
5
+ import {BOX_BORDER_RADIUS_MAX, BOX_BORDER_WIDTH_MAX, BOX_SPACING_MAX, BOX_SPACING_SIDES} from './constants'
6
+ import type {BoxAttributes, BoxSpacing} from './types'
18
7
 
19
8
  interface BoxControlsProps {
20
9
  attributes: BoxAttributes
21
10
  setAttributes: (attrs: Partial<BoxAttributes>) => void
22
11
  }
23
12
 
13
+ function SpacingPanel({title, values, onChange}: {title: string; values: BoxSpacing; onChange: (next: BoxSpacing) => void}) {
14
+ return (
15
+ <PanelBody title={title}>
16
+ {BOX_SPACING_SIDES.map((side) => (
17
+ <RangeControl
18
+ key={side.value}
19
+ label={side.label}
20
+ beforeIcon={side.icon}
21
+ value={values?.[side.value]}
22
+ onChange={(v) => onChange({...values, [side.value]: v})}
23
+ min={0}
24
+ max={BOX_SPACING_MAX}
25
+ step={1}
26
+ allowReset
27
+ withInputField
28
+ />
29
+ ))}
30
+ </PanelBody>
31
+ )
32
+ }
33
+
24
34
  export function BoxControls({attributes, setAttributes}: BoxControlsProps) {
25
35
  const {padding, margin, borderRadius, borderWidth, borderColor, background, textColor} = attributes
26
36
  const {paletteColors, resolveHex} = useTenantColorPalette()
27
37
 
28
38
  return (
29
39
  <>
30
- <PanelBody title={__('Rozestupy', 'brilo-blocks')}>
31
- <BoxControl label={__('Padding', 'brilo-blocks')} values={padding} onChange={(next) => setAttributes({padding: next})} />
32
- <BoxControl label={__('Margin', 'brilo-blocks')} values={margin} onChange={(next) => setAttributes({margin: next})} />
33
- </PanelBody>
40
+ <SpacingPanel title={__('Padding', 'brilo-blocks')} values={padding} onChange={(next) => setAttributes({padding: next})} />
41
+ <SpacingPanel title={__('Margin', 'brilo-blocks')} values={margin} onChange={(next) => setAttributes({margin: next})} />
34
42
 
35
43
  <PanelBody title={__('Ohraničení', 'brilo-blocks')}>
36
- <UnitControl
44
+ <RangeControl
37
45
  label={__('Šířka okraje', 'brilo-blocks')}
38
46
  value={borderWidth}
47
+ onChange={(v) => setAttributes({borderWidth: v ?? 0})}
39
48
  min={0}
40
- onChange={(next) => setAttributes({borderWidth: (next as string) ?? ''})}
49
+ max={BOX_BORDER_WIDTH_MAX}
50
+ step={1}
51
+ allowReset
52
+ withInputField
41
53
  />
42
54
  <p>{__('Barva okraje', 'brilo-blocks')}</p>
43
55
  <ColorPalette
@@ -45,7 +57,16 @@ export function BoxControls({attributes, setAttributes}: BoxControlsProps) {
45
57
  value={borderColor || undefined}
46
58
  onChange={(value) => setAttributes({borderColor: value ?? ''})}
47
59
  />
48
- <BorderRadiusControl values={borderRadius} onChange={(next) => setAttributes({borderRadius: next ?? ''})} />
60
+ <RangeControl
61
+ label={__('Zaoblení rohů', 'brilo-blocks')}
62
+ value={borderRadius}
63
+ onChange={(v) => setAttributes({borderRadius: v ?? 0})}
64
+ min={0}
65
+ max={BOX_BORDER_RADIUS_MAX}
66
+ step={1}
67
+ allowReset
68
+ withInputField
69
+ />
49
70
  </PanelBody>
50
71
 
51
72
  <PanelBody title={__('Barvy', 'brilo-blocks')}>
@@ -0,0 +1,146 @@
1
+ import {InnerBlocks} from '@wordpress/block-editor'
2
+ import type {BoxSpacing, BoxSpacingSide} from './types'
3
+
4
+ /**
5
+ * v1 stored every length as a CSS string (`"16px"`, `"1rem"`) and allowed a
6
+ * per-corner `borderRadius` object. v2 stores plain pixel numbers, so posts
7
+ * saved by v1 have to be migrated — the save output is unchanged
8
+ * (`<InnerBlocks.Content />`), which means block validation never fails and
9
+ * would otherwise leave the legacy values in place, silently rendering
10
+ * `16pxpx`. `isEligible` is what forces the migration.
11
+ */
12
+
13
+ const BOX_SIDES: readonly BoxSpacingSide[] = ['top', 'right', 'bottom', 'left']
14
+
15
+ interface LegacySpacing {
16
+ top?: string
17
+ right?: string
18
+ bottom?: string
19
+ left?: string
20
+ }
21
+
22
+ interface LegacyBorderRadius {
23
+ topLeft?: string
24
+ topRight?: string
25
+ bottomLeft?: string
26
+ bottomRight?: string
27
+ }
28
+
29
+ export interface LegacyBoxAttributes extends Record<string, unknown> {
30
+ padding: LegacySpacing
31
+ margin: LegacySpacing
32
+ borderRadius: string | LegacyBorderRadius
33
+ borderWidth: string
34
+ borderColor: string
35
+ background: string
36
+ textColor: string
37
+ }
38
+
39
+ /**
40
+ * Parses a v1 CSS length into pixels. `rem`/`em` are approximated at the
41
+ * 16px browser default; anything else unitless-or-px is taken at face value.
42
+ * Unparseable values become 0, which renders as "no declaration".
43
+ */
44
+ function toPixels(value: unknown): number {
45
+ if (typeof value === 'number') {
46
+ return Number.isFinite(value) ? value : 0
47
+ }
48
+
49
+ if (typeof value !== 'string') {
50
+ return 0
51
+ }
52
+
53
+ const match = value.trim().match(/^(-?\d*\.?\d+)\s*(px|rem|em)?$/)
54
+
55
+ if (!match) {
56
+ return 0
57
+ }
58
+
59
+ const amount = Number.parseFloat(match[1])
60
+
61
+ if (!Number.isFinite(amount)) {
62
+ return 0
63
+ }
64
+
65
+ return match[2] === 'rem' || match[2] === 'em' ? Math.round(amount * 16) : Math.round(amount)
66
+ }
67
+
68
+ function migrateSpacing(spacing: LegacySpacing | undefined): BoxSpacing {
69
+ const next: BoxSpacing = {}
70
+
71
+ for (const side of BOX_SIDES) {
72
+ const pixels = toPixels(spacing?.[side])
73
+
74
+ if (pixels !== 0) {
75
+ next[side] = pixels
76
+ }
77
+ }
78
+
79
+ return next
80
+ }
81
+
82
+ /**
83
+ * v1 could set each corner separately; v2 has a single radius. The first
84
+ * non-zero corner wins — lossy by design, and only for content that actually
85
+ * used per-corner radii.
86
+ */
87
+ function migrateBorderRadius(radius: string | LegacyBorderRadius | undefined): number {
88
+ if (radius && typeof radius === 'object') {
89
+ for (const corner of ['topLeft', 'topRight', 'bottomRight', 'bottomLeft'] as const) {
90
+ const pixels = toPixels(radius[corner])
91
+
92
+ if (pixels !== 0) {
93
+ return pixels
94
+ }
95
+ }
96
+
97
+ return 0
98
+ }
99
+
100
+ return toPixels(radius)
101
+ }
102
+
103
+ /** A v1 value still needing conversion: a non-empty string, or a corner object. */
104
+ function isLegacyLength(value: unknown): boolean {
105
+ return (typeof value === 'string' && value !== '') || (!!value && typeof value === 'object')
106
+ }
107
+
108
+ function hasLegacyLengths(attributes: LegacyBoxAttributes): boolean {
109
+ for (const spacing of [attributes.padding, attributes.margin]) {
110
+ for (const side of BOX_SIDES) {
111
+ if (isLegacyLength(spacing?.[side])) {
112
+ return true
113
+ }
114
+ }
115
+ }
116
+
117
+ return isLegacyLength(attributes.borderWidth) || isLegacyLength(attributes.borderRadius)
118
+ }
119
+
120
+ export const boxDeprecated = [
121
+ {
122
+ attributes: {
123
+ padding: {type: 'object', default: {}},
124
+ margin: {type: 'object', default: {}},
125
+ borderRadius: {type: ['string', 'object'], default: ''},
126
+ borderWidth: {type: 'string', default: ''},
127
+ borderColor: {type: 'string', default: ''},
128
+ background: {type: 'string', default: ''},
129
+ textColor: {type: 'string', default: ''},
130
+ },
131
+ supports: {html: false, customClassName: false},
132
+ isEligible: (attributes: Record<string, unknown>) => hasLegacyLengths(attributes as LegacyBoxAttributes),
133
+ migrate: (attributes: Record<string, unknown>) => {
134
+ const legacy = attributes as LegacyBoxAttributes
135
+
136
+ return {
137
+ ...legacy,
138
+ padding: migrateSpacing(legacy.padding),
139
+ margin: migrateSpacing(legacy.margin),
140
+ borderRadius: migrateBorderRadius(legacy.borderRadius),
141
+ borderWidth: toPixels(legacy.borderWidth),
142
+ }
143
+ },
144
+ save: () => <InnerBlocks.Content />,
145
+ },
146
+ ]
@@ -4,29 +4,26 @@ import type {CSSProperties} from 'react'
4
4
  import {BoxControls} from './controls'
5
5
  import type {BoxAttributes, BoxOptions} from './types'
6
6
 
7
+ /** Lengths are stored as plain pixel numbers; the unit is added on render. */
8
+ function px(value: number | undefined): string | undefined {
9
+ return typeof value === 'number' && value !== 0 ? `${value}px` : undefined
10
+ }
11
+
7
12
  export function createBoxEdit(options: BoxOptions) {
8
13
  return function Edit({attributes, setAttributes}: BlockEditProps<BoxAttributes>) {
9
14
  const {padding, margin, borderRadius, borderWidth, borderColor, background, textColor} = attributes
10
15
 
11
16
  const style: CSSProperties = {
12
- ...(padding?.top && {paddingTop: padding.top}),
13
- ...(padding?.right && {paddingRight: padding.right}),
14
- ...(padding?.bottom && {paddingBottom: padding.bottom}),
15
- ...(padding?.left && {paddingLeft: padding.left}),
16
- ...(margin?.top && {marginTop: margin.top}),
17
- ...(margin?.right && {marginRight: margin.right}),
18
- ...(margin?.bottom && {marginBottom: margin.bottom}),
19
- ...(margin?.left && {marginLeft: margin.left}),
20
- ...(typeof borderRadius === 'string' && borderRadius && {borderRadius}),
21
- ...(typeof borderRadius === 'object' && borderRadius !== null
22
- ? {
23
- ...(borderRadius.topLeft && {borderTopLeftRadius: borderRadius.topLeft}),
24
- ...(borderRadius.topRight && {borderTopRightRadius: borderRadius.topRight}),
25
- ...(borderRadius.bottomLeft && {borderBottomLeftRadius: borderRadius.bottomLeft}),
26
- ...(borderRadius.bottomRight && {borderBottomRightRadius: borderRadius.bottomRight}),
27
- }
28
- : {}),
29
- ...(borderWidth && {borderWidth, borderStyle: 'solid' as CSSProperties['borderStyle']}),
17
+ ...(px(padding?.top) && {paddingTop: px(padding?.top)}),
18
+ ...(px(padding?.right) && {paddingRight: px(padding?.right)}),
19
+ ...(px(padding?.bottom) && {paddingBottom: px(padding?.bottom)}),
20
+ ...(px(padding?.left) && {paddingLeft: px(padding?.left)}),
21
+ ...(px(margin?.top) && {marginTop: px(margin?.top)}),
22
+ ...(px(margin?.right) && {marginRight: px(margin?.right)}),
23
+ ...(px(margin?.bottom) && {marginBottom: px(margin?.bottom)}),
24
+ ...(px(margin?.left) && {marginLeft: px(margin?.left)}),
25
+ ...(px(borderRadius) && {borderRadius: px(borderRadius)}),
26
+ ...(px(borderWidth) && {borderWidth: px(borderWidth), borderStyle: 'solid' as CSSProperties['borderStyle']}),
30
27
  ...(borderColor && {borderColor}),
31
28
  ...(background && {backgroundColor: background}),
32
29
  ...(textColor && {color: textColor}),
@@ -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 {boxDeprecated} from './deprecated'
4
5
  import {createBoxEdit} from './edit'
5
6
  import {icon as defaultIcon} from './icon'
6
7
  import type {BoxAttributes, BoxOptions} from './types'
@@ -19,12 +20,13 @@ export function createBoxBlock(options: BoxOptions): BlockConfiguration<BoxAttri
19
20
  attributes: {
20
21
  padding: {type: 'object', default: {}},
21
22
  margin: {type: 'object', default: {}},
22
- borderRadius: {type: ['string', 'object'], default: ''},
23
- borderWidth: {type: 'string', default: ''},
23
+ borderRadius: {type: 'number', default: 0},
24
+ borderWidth: {type: 'number', default: 0},
24
25
  borderColor: {type: 'string', default: ''},
25
26
  background: {type: 'string', default: ''},
26
27
  textColor: {type: 'string', default: ''},
27
28
  },
29
+ deprecated: boxDeprecated,
28
30
  edit: createBoxEdit(options),
29
31
  save: () => <InnerBlocks.Content />,
30
32
  } as BlockConfiguration<BoxAttributes>
@@ -1,4 +1,4 @@
1
- export type {BoxAttributes, BoxBorderRadius, BoxOptions, BoxSpacing} from './types'
1
+ export type {BoxAttributes, BoxOptions, BoxSpacing, BoxSpacingSide} from './types'
2
2
  export {createBoxBlock} from './factory'
3
3
 
4
4
  import type {BoxOptions} from './types'
@@ -1,24 +1,15 @@
1
1
  import type {BriloBlockType} from '~/types'
2
2
 
3
- export interface BoxSpacing {
4
- top?: string
5
- right?: string
6
- bottom?: string
7
- left?: string
8
- }
3
+ export type BoxSpacingSide = 'top' | 'right' | 'bottom' | 'left'
9
4
 
10
- export interface BoxBorderRadius {
11
- topLeft?: string
12
- topRight?: string
13
- bottomLeft?: string
14
- bottomRight?: string
15
- }
5
+ /** Per-side spacing in pixels. An unset side means "no declaration". */
6
+ export type BoxSpacing = Partial<Record<BoxSpacingSide, number>>
16
7
 
17
8
  export interface BoxAttributes extends Record<string, unknown> {
18
9
  padding: BoxSpacing
19
10
  margin: BoxSpacing
20
- borderRadius: string | BoxBorderRadius
21
- borderWidth: string
11
+ borderRadius: number
12
+ borderWidth: number
22
13
  borderColor: string
23
14
  background: string
24
15
  textColor: string
@@ -76,8 +76,9 @@ function FluidDecorationControl({label, placement, value, onChange}: FluidDecora
76
76
  // overriding the frontend once the editor actually writes an explicit value.
77
77
  const bgPosition = value?.bgPosition ?? (placement === 'bottom' ? 'left bottom' : 'left top')
78
78
  const repeat = value?.repeat ?? 'repeat-x'
79
+ const opacity = value?.opacity ?? BACKGROUND_IMAGE_OPACITY_DEFAULT
79
80
 
80
- const update = (patch: Partial<FluidDecoration>) => onChange(mergeUpdate({img, height, fit, bgPosition, repeat}, value, patch))
81
+ const update = (patch: Partial<FluidDecoration>) => onChange(mergeUpdate({img, height, fit, bgPosition, repeat, opacity}, value, patch))
81
82
 
82
83
  const handleSelect = (media: {id: number; url: string; alt: string; width?: number; height?: number}) => {
83
84
  const nextImg: FluidDecorationImage = {id: media.id, src: media.url, alt: media.alt ?? '', width: media.width, height: media.height}
@@ -158,6 +159,14 @@ function FluidDecorationControl({label, placement, value, onChange}: FluidDecora
158
159
  options={[...BACKGROUND_IMAGE_REPEATS]}
159
160
  onChange={(next) => update({repeat: next as BackgroundImageRepeat})}
160
161
  />
162
+
163
+ <RangeControl
164
+ label={__('Průhlednost obrázku', 'brilo-blocks')}
165
+ value={opacity}
166
+ min={0}
167
+ max={100}
168
+ onChange={(next) => update({opacity: next ?? BACKGROUND_IMAGE_OPACITY_DEFAULT})}
169
+ />
161
170
  </>
162
171
  )}
163
172
  </BaseControl>
@@ -19,6 +19,7 @@ export interface FluidDecoration {
19
19
  // key as "position" on top of this object, which would silently clobber a same-named field.
20
20
  bgPosition?: BackgroundImagePosition
21
21
  repeat?: BackgroundImageRepeat
22
+ opacity?: number
22
23
  }
23
24
 
24
25
  export type DecorationImage = FluidDecorationImage
@@ -51,14 +51,14 @@ function normaliseStyle(saved: Partial<StepGroupAttributes['style']> | undefined
51
51
  }
52
52
 
53
53
  function PresetSizeControl({
54
- label,
55
- id,
56
- value,
57
- presets,
58
- min,
59
- max,
60
- onChange,
61
- }: {
54
+ label,
55
+ id,
56
+ value,
57
+ presets,
58
+ min,
59
+ max,
60
+ onChange,
61
+ }: {
62
62
  label: string
63
63
  id: string
64
64
  value: number
@@ -85,9 +85,9 @@ export function createStepGroupEdit<TVariants extends OptionArray = typeof DEFAU
85
85
  const VARIANTS = options.variants ?? DEFAULT_VARIANTS
86
86
 
87
87
  return function Edit({
88
- attributes,
89
- setAttributes,
90
- }: {
88
+ attributes,
89
+ setAttributes,
90
+ }: {
91
91
  attributes: StepGroupAttributes
92
92
  setAttributes: (a: Partial<StepGroupAttributes>) => void
93
93
  }) {