@brilo/base-blocks 0.1.54 → 0.1.56

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 (59) hide show
  1. package/build/.tsbuildinfo +1 -1
  2. package/build/blocks/accordion/accordion-item/edit.d.ts.map +1 -1
  3. package/build/blocks/accordion/accordion-item/edit.js +4 -4
  4. package/build/blocks/accordion/accordion-item/factory.d.ts.map +1 -1
  5. package/build/blocks/accordion/accordion-item/factory.js +1 -0
  6. package/build/blocks/accordion/accordion-item/types.d.ts +1 -0
  7. package/build/blocks/accordion/accordion-item/types.d.ts.map +1 -1
  8. package/build/blocks/core/basic-icon/factory.d.ts.map +1 -1
  9. package/build/blocks/core/basic-icon/factory.js +2 -1
  10. package/build/blocks/faq/faq-group/factory.d.ts.map +1 -1
  11. package/build/blocks/faq/faq-group/factory.js +2 -1
  12. package/build/blocks/groups/banner-group/factory.d.ts.map +1 -1
  13. package/build/blocks/groups/banner-group/factory.js +2 -1
  14. package/build/blocks/groups/basic-header-group/factory.d.ts.map +1 -1
  15. package/build/blocks/groups/basic-header-group/factory.js +2 -1
  16. package/build/blocks/groups/content-group/index.js +1 -1
  17. package/build/blocks/groups/text-and-media-group/factory.d.ts.map +1 -1
  18. package/build/blocks/groups/text-and-media-group/factory.js +2 -1
  19. package/build/blocks/hero/hero-item/edit.d.ts +2 -4
  20. package/build/blocks/hero/hero-item/edit.d.ts.map +1 -1
  21. package/build/blocks/hero/hero-item/edit.js +7 -6
  22. package/build/blocks/hero/hero-item/factory.d.ts +1 -1
  23. package/build/blocks/hero/hero-item/factory.d.ts.map +1 -1
  24. package/build/blocks/hero/hero-item/factory.js +1 -0
  25. package/build/blocks/hero/hero-item/types.d.ts +10 -1
  26. package/build/blocks/hero/hero-item/types.d.ts.map +1 -1
  27. package/build/blocks/map/map-group/factory.d.ts.map +1 -1
  28. package/build/blocks/map/map-group/factory.js +2 -1
  29. package/build/blocks/newsletter/newsletter-form/factory.d.ts.map +1 -1
  30. package/build/blocks/newsletter/newsletter-form/factory.js +2 -1
  31. package/build/blocks/testimonial/testimonial-item/factory.d.ts.map +1 -1
  32. package/build/blocks/testimonial/testimonial-item/factory.js +2 -1
  33. package/build/blocks/text-and-form/text-and-form-text-column/factory.d.ts.map +1 -1
  34. package/build/blocks/text-and-form/text-and-form-text-column/factory.js +2 -1
  35. package/build/blocks/usp/usp-group/factory.d.ts.map +1 -1
  36. package/build/blocks/usp/usp-group/factory.js +2 -1
  37. package/build/utils/withObjectDefaults.d.ts +12 -0
  38. package/build/utils/withObjectDefaults.d.ts.map +1 -0
  39. package/build/utils/withObjectDefaults.js +37 -0
  40. package/package.json +1 -1
  41. package/src/blocks/accordion/accordion-item/edit.tsx +12 -3
  42. package/src/blocks/accordion/accordion-item/factory.tsx +1 -0
  43. package/src/blocks/accordion/accordion-item/types.ts +1 -0
  44. package/src/blocks/core/basic-button/editor.scss +11 -0
  45. package/src/blocks/core/basic-icon/factory.tsx +2 -1
  46. package/src/blocks/faq/faq-group/factory.tsx +2 -1
  47. package/src/blocks/groups/banner-group/factory.tsx +2 -1
  48. package/src/blocks/groups/basic-header-group/factory.tsx +2 -1
  49. package/src/blocks/groups/content-group/index.ts +1 -1
  50. package/src/blocks/groups/text-and-media-group/factory.tsx +2 -1
  51. package/src/blocks/hero/hero-item/edit.tsx +4 -7
  52. package/src/blocks/hero/hero-item/factory.tsx +6 -3
  53. package/src/blocks/hero/hero-item/types.ts +10 -1
  54. package/src/blocks/map/map-group/factory.tsx +2 -1
  55. package/src/blocks/newsletter/newsletter-form/factory.tsx +2 -1
  56. package/src/blocks/testimonial/testimonial-item/factory.tsx +2 -1
  57. package/src/blocks/text-and-form/text-and-form-text-column/factory.tsx +2 -1
  58. package/src/blocks/usp/usp-group/factory.tsx +2 -1
  59. package/src/utils/withObjectDefaults.tsx +37 -0
@@ -1,4 +1,5 @@
1
1
  import type {BlockConfiguration} from '@wordpress/blocks'
2
+ import {withObjectDefaults} from '~/utils/withObjectDefaults'
2
3
  import {__} from '@wordpress/i18n'
3
4
  import type {NumberArray, OptionArray, StringArray} from '~/types'
4
5
  import {DEFAULT_ALIGNMENTS, DEFAULT_LEVELS, DEFAULT_STYLES} from './constants'
@@ -40,7 +41,7 @@ export function createBasicHeaderGroupBlock<
40
41
  enum: alignments.map((a) => a.value),
41
42
  },
42
43
  },
43
- edit: createBasicHeaderGroupEdit(options as unknown as BasicHeaderGroupOptions),
44
+ edit: withObjectDefaults(createBasicHeaderGroupEdit(options as unknown as BasicHeaderGroupOptions)),
44
45
  save: () => null,
45
46
  } as unknown as BlockConfiguration<BasicHeaderGroupAttributes<TLevels[number], TStyles[number], TAlignments[number]['value']>>
46
47
  }
@@ -20,6 +20,6 @@ export const contentGroupDefaults: ContentGroupOptions = {
20
20
  'core/embed',
21
21
  'core/video',
22
22
  'core/file',
23
- 'brilo/link',
23
+ 'brilo/link-item',
24
24
  ],
25
25
  }
@@ -1,4 +1,5 @@
1
1
  import {InnerBlocks} from '@wordpress/block-editor'
2
+ import {withObjectDefaults} from '~/utils/withObjectDefaults'
2
3
  import type {BlockConfiguration} from '@wordpress/blocks'
3
4
  import {__} from '@wordpress/i18n'
4
5
  import type {OptionArray} from '~/types'
@@ -90,7 +91,7 @@ export function createTextAndMediaGroupBlock<
90
91
  },
91
92
  content: {type: 'object', default: {size: contentSizes[1]?.value ?? contentSizes[0].value}},
92
93
  },
93
- edit: createTextAndMediaGroupEdit(options as unknown as TextAndMediaGroupOptions),
94
+ edit: withObjectDefaults(createTextAndMediaGroupEdit(options as unknown as TextAndMediaGroupOptions)),
94
95
  save: () => <InnerBlocks.Content />,
95
96
  } as unknown as BlockConfiguration<
96
97
  TextAndMediaGroupAttributes<
@@ -1,4 +1,5 @@
1
1
  import {InspectorControls, RichText, useBlockProps, useInnerBlocksProps} from '@wordpress/block-editor'
2
+ import type {BlockEditProps} from '@wordpress/blocks'
2
3
  import {
3
4
  PanelBody,
4
5
  __experimentalToggleGroupControlOption as ToggleGroupControlOption,
@@ -18,13 +19,8 @@ import {useTenantColorPalette} from '~/hooks/useTenantColorPalette'
18
19
  import clsx from 'clsx'
19
20
 
20
21
  export function createHeroItemEdit(options: HeroItemOptions) {
21
- return function Edit({
22
- attributes,
23
- setAttributes,
24
- }: {
25
- attributes: HeroItemAttributes
26
- setAttributes: (a: Partial<HeroItemAttributes>) => void
27
- }) {
22
+ return function Edit(props: BlockEditProps<HeroItemAttributes>) {
23
+ const {attributes, setAttributes} = props
28
24
  const {title, titleColor, img, headingLevel, contentPosition, url, focalPoint, overline} = attributes
29
25
  const {paletteColors} = useTenantColorPalette()
30
26
 
@@ -110,6 +106,7 @@ export function createHeroItemEdit(options: HeroItemOptions) {
110
106
  onChange={(v) => setAttributes({url: {...url, blank: v}})}
111
107
  />
112
108
  </PanelBody>
109
+ {options.extraControls?.(props as unknown as Parameters<NonNullable<typeof options.extraControls>>[0])}
113
110
  </InspectorControls>
114
111
 
115
112
  <div {...blockProps}>
@@ -7,7 +7,9 @@ import {InnerBlocks} from '@wordpress/block-editor'
7
7
 
8
8
  export type {HeroItemAttributes, HeroItemOptions}
9
9
 
10
- export function createHeroItemBlock(options: HeroItemOptions): BlockConfiguration<HeroItemAttributes> {
10
+ export function createHeroItemBlock<TExtra extends Record<string, unknown> = Record<string, never>>(
11
+ options: HeroItemOptions<TExtra>,
12
+ ): BlockConfiguration<HeroItemAttributes & TExtra> {
11
13
  const contentPositions = options.contentPositions ?? CONTENT_POSITIONS
12
14
 
13
15
  return {
@@ -44,8 +46,9 @@ export function createHeroItemBlock(options: HeroItemOptions): BlockConfiguratio
44
46
  type: 'object',
45
47
  default: {point: 'center center', sm: {point: 'center center'}},
46
48
  },
49
+ ...options.extraAttributes,
47
50
  },
48
- edit: createHeroItemEdit(options),
51
+ edit: createHeroItemEdit(options as unknown as HeroItemOptions),
49
52
  save: () => <InnerBlocks.Content />,
50
- } as unknown as BlockConfiguration<HeroItemAttributes>
53
+ } as unknown as BlockConfiguration<HeroItemAttributes & TExtra>
51
54
  }
@@ -1,3 +1,5 @@
1
+ import type {BlockEditProps} from '@wordpress/blocks'
2
+ import type {ReactNode} from 'react'
1
3
  import type {BriloBlockType, Media, OptionArray} from '~/types'
2
4
  import type {CONTENT_POSITIONS, HEADING_LEVELS} from './constants'
3
5
 
@@ -36,6 +38,13 @@ export interface HeroItemAttributes extends Record<string, unknown> {
36
38
  focalPoint: HeroItemFocalPoint
37
39
  }
38
40
 
39
- export interface HeroItemOptions extends BriloBlockType {
41
+ export interface HeroItemOptions<TExtra extends Record<string, unknown> = Record<string, never>> extends BriloBlockType {
40
42
  contentPositions?: OptionArray
43
+ extraAttributes?: {
44
+ [K in keyof TExtra]: {
45
+ type: string
46
+ default: TExtra[K]
47
+ }
48
+ }
49
+ extraControls?: (props: BlockEditProps<HeroItemAttributes & TExtra>) => ReactNode
41
50
  }
@@ -1,4 +1,5 @@
1
1
  import type {BlockConfiguration} from '@wordpress/blocks'
2
+ import {withObjectDefaults} from '~/utils/withObjectDefaults'
2
3
  import {__} from '@wordpress/i18n'
3
4
  import {createMapGroupEdit} from './edit'
4
5
  import type {MapGroupAttributes, MapGroupOptions} from './types'
@@ -67,7 +68,7 @@ export function createMapGroupBlock<THeadingStyles extends StringArray = typeof
67
68
  default: '',
68
69
  },
69
70
  },
70
- edit: createMapGroupEdit(options as unknown as MapGroupOptions),
71
+ edit: withObjectDefaults(createMapGroupEdit(options as unknown as MapGroupOptions)),
71
72
  save: () => <InnerBlocks.Content />,
72
73
  } as unknown as BlockConfiguration<MapGroupAttributes<THeadingStyles[number]>>
73
74
  }
@@ -1,4 +1,5 @@
1
1
  import type {BlockConfiguration} from '@wordpress/blocks'
2
+ import {withObjectDefaults} from '~/utils/withObjectDefaults'
2
3
  import {__} from '@wordpress/i18n'
3
4
  import {DEFAULT_HEADING_STYLES, NEWSLETTER_LEVELS} from './constants'
4
5
  import {createNewsletterFormEdit} from './edit'
@@ -53,7 +54,7 @@ export function createNewsletterFormBlock(options: NewsletterFormOptions): Block
53
54
  },
54
55
  },
55
56
  },
56
- edit: createNewsletterFormEdit(options),
57
+ edit: withObjectDefaults(createNewsletterFormEdit(options)),
57
58
  save: () => null,
58
59
  } as unknown as BlockConfiguration<NewsletterFormAttributes>
59
60
  }
@@ -9,7 +9,8 @@ export function createTestimonialItemBlock(
9
9
  return {
10
10
  name: options.name,
11
11
  title: options.title ?? __('Reference - položka', 'brilo-blocks'),
12
- category: options.category ?? 'brilo',
12
+ category: options.category ?? 'layout',
13
+ ...(options.parent && {parent: options.parent}),
13
14
  supports: {html: false, customClassName: false},
14
15
  attributes: {
15
16
  title: {
@@ -1,4 +1,5 @@
1
1
  import {InnerBlocks} from '@wordpress/block-editor'
2
+ import {withObjectDefaults} from '~/utils/withObjectDefaults'
2
3
  import type {BlockConfiguration} from '@wordpress/blocks'
3
4
  import {__} from '@wordpress/i18n'
4
5
  import type {OptionArray} from '~/types'
@@ -35,7 +36,7 @@ export function createTextAndFormTextColumnBlock<
35
36
  },
36
37
  content: {type: 'object', default: {size: contentSizes[1]?.value ?? contentSizes[0].value}},
37
38
  },
38
- edit: createTextAndFormTextColumnEdit(options as unknown as TextAndFormTextColumnOptions),
39
+ edit: withObjectDefaults(createTextAndFormTextColumnEdit(options as unknown as TextAndFormTextColumnOptions)),
39
40
  save: () => <InnerBlocks.Content />,
40
41
  } as unknown as BlockConfiguration<TextAndFormTextColumnAttributes<THeadingStyles[number]['value'], TContentSizes[number]['value']>>
41
42
  }
@@ -1,4 +1,5 @@
1
1
  import {InnerBlocks} from '@wordpress/block-editor'
2
+ import {withObjectDefaults} from '~/utils/withObjectDefaults'
2
3
  import type {BlockConfiguration} from '@wordpress/blocks'
3
4
  import {__} from '@wordpress/i18n'
4
5
  import {ITEM_SPACING_ATTRIBUTE} from '~/components/ItemSpacingControl'
@@ -94,7 +95,7 @@ export function createUspGroupBlock<
94
95
  },
95
96
  ...ITEM_SPACING_ATTRIBUTE,
96
97
  },
97
- edit: createUspGroupEdit(options as unknown as UspGroupOptions),
98
+ edit: withObjectDefaults(createUspGroupEdit(options as unknown as UspGroupOptions)),
98
99
  save: () => <InnerBlocks.Content />,
99
100
  } as unknown as BlockConfiguration<
100
101
  UspGroupAttributes<
@@ -0,0 +1,37 @@
1
+ import {getBlockType} from '@wordpress/blocks'
2
+ import {useMemo} from '@wordpress/element'
3
+ import type {ComponentType} from 'react'
4
+
5
+ type PlainObject = Record<string, unknown>
6
+
7
+ const isPlainObject = (value: unknown): value is PlainObject => typeof value === 'object' && value !== null && !Array.isArray(value)
8
+
9
+ // keys present in the value win, missing ones are taken from the fallback (recursively)
10
+ function mergeMissing(fallback: unknown, value: unknown): unknown {
11
+ if (value === undefined) return fallback
12
+ if (!isPlainObject(fallback) || !isPlainObject(value)) return value
13
+ const merged: PlainObject = {...value}
14
+ for (const [key, fallbackValue] of Object.entries(fallback)) merged[key] = mergeMissing(fallbackValue, value[key])
15
+ return merged
16
+ }
17
+
18
+ /**
19
+ * Block markup can carry partial object attributes (e.g. generated content) and WP does not deep-merge
20
+ * them with the attribute default, so edit code reading nested keys would crash. Fills the missing
21
+ * nested keys from the registered defaults before the edit component reads them.
22
+ */
23
+ export function withObjectDefaults<Props extends {attributes: PlainObject}>(Edit: ComponentType<Props>) {
24
+ return function EditWithObjectDefaults(props: Props) {
25
+ const {name} = props as Props & {name?: string}
26
+ const attributes = useMemo(() => {
27
+ const definitions = (name ? getBlockType(name)?.attributes : undefined) ?? {}
28
+ const filled: PlainObject = {...props.attributes}
29
+ for (const [key, definition] of Object.entries(definitions as Record<string, {type?: unknown; default?: unknown}>)) {
30
+ if (definition.type === 'object' && isPlainObject(definition.default)) filled[key] = mergeMissing(definition.default, filled[key])
31
+ }
32
+ return filled as Props['attributes']
33
+ }, [name, props.attributes])
34
+
35
+ return <Edit {...props} attributes={attributes} />
36
+ }
37
+ }