@brilo/base-blocks 0.1.1 → 0.1.3

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 (250) hide show
  1. package/build/blocks/form/form-group/edit.d.ts.map +1 -1
  2. package/build/blocks/form/form-group/edit.js +17 -3
  3. package/build/blocks/form/form-group/factory.d.ts.map +1 -1
  4. package/build/blocks/form/form-group/factory.js +1 -0
  5. package/build/blocks/form/form-group/types.d.ts +1 -0
  6. package/build/blocks/form/form-group/types.d.ts.map +1 -1
  7. package/package.json +3 -2
  8. package/src/blocks/column/column-group/edit.tsx +56 -0
  9. package/src/blocks/column/column-group/editor.scss +7 -0
  10. package/src/blocks/column/column-group/factory.tsx +29 -0
  11. package/src/blocks/column/column-group/index.ts +14 -0
  12. package/src/blocks/column/column-group/types.ts +8 -0
  13. package/src/blocks/column/column-item/constants.ts +1 -0
  14. package/src/blocks/column/column-item/edit.tsx +48 -0
  15. package/src/blocks/column/column-item/editor.scss +34 -0
  16. package/src/blocks/column/column-item/factory.tsx +25 -0
  17. package/src/blocks/column/column-item/index.ts +10 -0
  18. package/src/blocks/column/column-item/types.ts +7 -0
  19. package/src/blocks/compare/compare-group/constants.ts +1 -0
  20. package/src/blocks/compare/compare-group/edit.tsx +52 -0
  21. package/src/blocks/compare/compare-group/factory.tsx +29 -0
  22. package/src/blocks/compare/compare-group/icon.tsx +7 -0
  23. package/src/blocks/compare/compare-group/index.ts +13 -0
  24. package/src/blocks/compare/compare-group/types.ts +12 -0
  25. package/src/blocks/compare/compare-item/edit.tsx +38 -0
  26. package/src/blocks/compare/compare-item/editor.scss +15 -0
  27. package/src/blocks/compare/compare-item/factory.tsx +28 -0
  28. package/src/blocks/compare/compare-item/icon.tsx +9 -0
  29. package/src/blocks/compare/compare-item/index.ts +13 -0
  30. package/src/blocks/compare/compare-item/types.ts +9 -0
  31. package/src/blocks/compare/compare-option/constants.ts +7 -0
  32. package/src/blocks/compare/compare-option/edit.tsx +64 -0
  33. package/src/blocks/compare/compare-option/editor.scss +26 -0
  34. package/src/blocks/compare/compare-option/factory.tsx +35 -0
  35. package/src/blocks/compare/compare-option/icon.tsx +7 -0
  36. package/src/blocks/compare/compare-option/index.ts +8 -0
  37. package/src/blocks/compare/compare-option/types.ts +12 -0
  38. package/src/blocks/contact/contact-group/constants.ts +3 -0
  39. package/src/blocks/contact/contact-group/edit.tsx +57 -0
  40. package/src/blocks/contact/contact-group/editor.scss +20 -0
  41. package/src/blocks/contact/contact-group/factory.tsx +35 -0
  42. package/src/blocks/contact/contact-group/index.ts +12 -0
  43. package/src/blocks/contact/contact-group/types.ts +12 -0
  44. package/src/blocks/contact/contact-item/constants.ts +17 -0
  45. package/src/blocks/contact/contact-item/edit.tsx +93 -0
  46. package/src/blocks/contact/contact-item/editor.scss +38 -0
  47. package/src/blocks/contact/contact-item/factory.tsx +35 -0
  48. package/src/blocks/contact/contact-item/index.ts +23 -0
  49. package/src/blocks/contact/contact-item/types.ts +21 -0
  50. package/src/blocks/core/basic-button/constants.ts +17 -0
  51. package/src/blocks/core/basic-button/edit.tsx +107 -0
  52. package/src/blocks/core/basic-button/editor.scss +80 -0
  53. package/src/blocks/core/basic-button/factory.tsx +54 -0
  54. package/src/blocks/core/basic-button/index.ts +8 -0
  55. package/src/blocks/core/basic-button/types.ts +29 -0
  56. package/src/blocks/core/basic-heading/constants.ts +1 -0
  57. package/src/blocks/core/basic-heading/edit.tsx +76 -0
  58. package/src/blocks/core/basic-heading/editor.scss +8 -0
  59. package/src/blocks/core/basic-heading/factory.tsx +40 -0
  60. package/src/blocks/core/basic-heading/index.ts +8 -0
  61. package/src/blocks/core/basic-heading/types.ts +20 -0
  62. package/src/blocks/core/basic-overline/edit.tsx +28 -0
  63. package/src/blocks/core/basic-overline/editor.scss +14 -0
  64. package/src/blocks/core/basic-overline/factory.tsx +22 -0
  65. package/src/blocks/core/basic-overline/index.ts +8 -0
  66. package/src/blocks/core/basic-overline/types.ts +7 -0
  67. package/src/blocks/faq/faq-group/constants.ts +11 -0
  68. package/src/blocks/faq/faq-group/edit.tsx +55 -0
  69. package/src/blocks/faq/faq-group/editor.scss +11 -0
  70. package/src/blocks/faq/faq-group/factory.tsx +39 -0
  71. package/src/blocks/faq/faq-group/index.ts +11 -0
  72. package/src/blocks/faq/faq-group/types.ts +14 -0
  73. package/src/blocks/faq/faq-item/edit.tsx +50 -0
  74. package/src/blocks/faq/faq-item/editor.scss +57 -0
  75. package/src/blocks/faq/faq-item/factory.tsx +24 -0
  76. package/src/blocks/faq/faq-item/index.ts +9 -0
  77. package/src/blocks/faq/faq-item/types.ts +7 -0
  78. package/src/blocks/form/form-field/constants.ts +14 -0
  79. package/src/blocks/form/form-field/edit.tsx +178 -0
  80. package/src/blocks/form/form-field/editor.scss +71 -0
  81. package/src/blocks/form/form-field/factory.tsx +32 -0
  82. package/src/blocks/form/form-field/index.ts +10 -0
  83. package/src/blocks/form/form-field/types.ts +18 -0
  84. package/src/blocks/form/form-group/constants.ts +16 -0
  85. package/src/blocks/form/form-group/edit.tsx +214 -0
  86. package/src/blocks/form/form-group/editor.scss +41 -0
  87. package/src/blocks/form/form-group/factory.tsx +36 -0
  88. package/src/blocks/form/form-group/index.ts +18 -0
  89. package/src/blocks/form/form-group/types.ts +23 -0
  90. package/src/blocks/groups/banner-group/constants.ts +15 -0
  91. package/src/blocks/groups/banner-group/edit.tsx +122 -0
  92. package/src/blocks/groups/banner-group/editor.scss +18 -0
  93. package/src/blocks/groups/banner-group/factory.tsx +64 -0
  94. package/src/blocks/groups/banner-group/icon.tsx +13 -0
  95. package/src/blocks/groups/banner-group/index.ts +11 -0
  96. package/src/blocks/groups/banner-group/types.ts +30 -0
  97. package/src/blocks/groups/basic-header-group/constants.ts +9 -0
  98. package/src/blocks/groups/basic-header-group/edit.tsx +99 -0
  99. package/src/blocks/groups/basic-header-group/editor.scss +35 -0
  100. package/src/blocks/groups/basic-header-group/factory.tsx +46 -0
  101. package/src/blocks/groups/basic-header-group/icon.tsx +17 -0
  102. package/src/blocks/groups/basic-header-group/index.ts +9 -0
  103. package/src/blocks/groups/basic-header-group/types.ts +27 -0
  104. package/src/blocks/groups/button-group/constants.ts +7 -0
  105. package/src/blocks/groups/button-group/edit.tsx +52 -0
  106. package/src/blocks/groups/button-group/editor.scss +23 -0
  107. package/src/blocks/groups/button-group/factory.tsx +34 -0
  108. package/src/blocks/groups/button-group/index.ts +11 -0
  109. package/src/blocks/groups/button-group/types.ts +12 -0
  110. package/src/blocks/groups/text-and-media-group/constants.ts +43 -0
  111. package/src/blocks/groups/text-and-media-group/edit.tsx +241 -0
  112. package/src/blocks/groups/text-and-media-group/editor.scss +123 -0
  113. package/src/blocks/groups/text-and-media-group/factory.tsx +100 -0
  114. package/src/blocks/groups/text-and-media-group/icon.tsx +37 -0
  115. package/src/blocks/groups/text-and-media-group/index.ts +18 -0
  116. package/src/blocks/groups/text-and-media-group/types.ts +60 -0
  117. package/src/blocks/hero/hero-group/constants.ts +23 -0
  118. package/src/blocks/hero/hero-group/edit.tsx +85 -0
  119. package/src/blocks/hero/hero-group/editor.scss +0 -0
  120. package/src/blocks/hero/hero-group/factory.tsx +45 -0
  121. package/src/blocks/hero/hero-group/icon.tsx +28 -0
  122. package/src/blocks/hero/hero-group/index.ts +11 -0
  123. package/src/blocks/hero/hero-group/types.ts +22 -0
  124. package/src/blocks/hero/hero-item/constants.ts +15 -0
  125. package/src/blocks/hero/hero-item/edit.tsx +107 -0
  126. package/src/blocks/hero/hero-item/editor.scss +87 -0
  127. package/src/blocks/hero/hero-item/factory.tsx +49 -0
  128. package/src/blocks/hero/hero-item/index.ts +10 -0
  129. package/src/blocks/hero/hero-item/types.ts +38 -0
  130. package/src/blocks/map/map-group/constants.ts +20 -0
  131. package/src/blocks/map/map-group/edit.tsx +108 -0
  132. package/src/blocks/map/map-group/editor.scss +24 -0
  133. package/src/blocks/map/map-group/factory.tsx +51 -0
  134. package/src/blocks/map/map-group/index.ts +9 -0
  135. package/src/blocks/map/map-group/types.ts +16 -0
  136. package/src/blocks/newsletter/newsletter-form/constants.ts +5 -0
  137. package/src/blocks/newsletter/newsletter-form/edit.tsx +194 -0
  138. package/src/blocks/newsletter/newsletter-form/editor.scss +68 -0
  139. package/src/blocks/newsletter/newsletter-form/factory.tsx +59 -0
  140. package/src/blocks/newsletter/newsletter-form/index.ts +11 -0
  141. package/src/blocks/newsletter/newsletter-form/types.ts +45 -0
  142. package/src/blocks/post/post-slider-group/constants.ts +3 -0
  143. package/src/blocks/post/post-slider-group/edit.tsx +76 -0
  144. package/src/blocks/post/post-slider-group/factory.tsx +43 -0
  145. package/src/blocks/post/post-slider-group/icon.tsx +13 -0
  146. package/src/blocks/post/post-slider-group/index.ts +9 -0
  147. package/src/blocks/post/post-slider-group/types.ts +20 -0
  148. package/src/blocks/responsive-grid/responsive-grid-group/edit.tsx +95 -0
  149. package/src/blocks/responsive-grid/responsive-grid-group/factory.tsx +33 -0
  150. package/src/blocks/responsive-grid/responsive-grid-group/index.ts +13 -0
  151. package/src/blocks/responsive-grid/responsive-grid-group/types.ts +9 -0
  152. package/src/blocks/responsive-grid/responsive-grid-item/edit.tsx +19 -0
  153. package/src/blocks/responsive-grid/responsive-grid-item/factory.tsx +20 -0
  154. package/src/blocks/responsive-grid/responsive-grid-item/index.ts +9 -0
  155. package/src/blocks/responsive-grid/responsive-grid-item/types.ts +5 -0
  156. package/src/blocks/sections/base-section/attributes.ts +17 -0
  157. package/src/blocks/sections/base-section/constants.ts +18 -0
  158. package/src/blocks/sections/base-section/controls.tsx +70 -0
  159. package/src/blocks/sections/base-section/edit.tsx +34 -0
  160. package/src/blocks/sections/base-section/editor.scss +24 -0
  161. package/src/blocks/sections/base-section/factory.tsx +47 -0
  162. package/src/blocks/sections/base-section/icon.tsx +6 -0
  163. package/src/blocks/sections/base-section/index.ts +14 -0
  164. package/src/blocks/sections/base-section/types.ts +26 -0
  165. package/src/blocks/signpost/signpost-group/constants.ts +3 -0
  166. package/src/blocks/signpost/signpost-group/edit.tsx +75 -0
  167. package/src/blocks/signpost/signpost-group/editor.scss +0 -0
  168. package/src/blocks/signpost/signpost-group/factory.tsx +40 -0
  169. package/src/blocks/signpost/signpost-group/icon.tsx +19 -0
  170. package/src/blocks/signpost/signpost-group/index.ts +15 -0
  171. package/src/blocks/signpost/signpost-group/types.ts +9 -0
  172. package/src/blocks/signpost/signpost-item/constants.ts +4 -0
  173. package/src/blocks/signpost/signpost-item/edit.tsx +90 -0
  174. package/src/blocks/signpost/signpost-item/editor.scss +25 -0
  175. package/src/blocks/signpost/signpost-item/factory.tsx +29 -0
  176. package/src/blocks/signpost/signpost-item/icon.tsx +7 -0
  177. package/src/blocks/signpost/signpost-item/index.ts +10 -0
  178. package/src/blocks/signpost/signpost-item/types.ts +12 -0
  179. package/src/blocks/step/step-group/constants.ts +6 -0
  180. package/src/blocks/step/step-group/edit.tsx +64 -0
  181. package/src/blocks/step/step-group/editor.scss +19 -0
  182. package/src/blocks/step/step-group/factory.tsx +36 -0
  183. package/src/blocks/step/step-group/icon.tsx +27 -0
  184. package/src/blocks/step/step-group/index.ts +15 -0
  185. package/src/blocks/step/step-group/types.ts +13 -0
  186. package/src/blocks/step/step-item/constants.ts +6 -0
  187. package/src/blocks/step/step-item/edit.tsx +60 -0
  188. package/src/blocks/step/step-item/editor.scss +18 -0
  189. package/src/blocks/step/step-item/factory.tsx +27 -0
  190. package/src/blocks/step/step-item/index.ts +11 -0
  191. package/src/blocks/step/step-item/types.ts +12 -0
  192. package/src/blocks/testimonial/testimonial-group/constants.ts +27 -0
  193. package/src/blocks/testimonial/testimonial-group/edit.tsx +74 -0
  194. package/src/blocks/testimonial/testimonial-group/editor.scss +38 -0
  195. package/src/blocks/testimonial/testimonial-group/factory.tsx +44 -0
  196. package/src/blocks/testimonial/testimonial-group/icon.tsx +33 -0
  197. package/src/blocks/testimonial/testimonial-group/index.ts +15 -0
  198. package/src/blocks/testimonial/testimonial-group/types.ts +19 -0
  199. package/src/blocks/testimonial/testimonial-item/edit.tsx +48 -0
  200. package/src/blocks/testimonial/testimonial-item/editor.scss +20 -0
  201. package/src/blocks/testimonial/testimonial-item/factory.tsx +35 -0
  202. package/src/blocks/testimonial/testimonial-item/index.ts +9 -0
  203. package/src/blocks/testimonial/testimonial-item/types.ts +9 -0
  204. package/src/blocks/text-and-form/text-and-form-group/constants.ts +6 -0
  205. package/src/blocks/text-and-form/text-and-form-group/edit.tsx +59 -0
  206. package/src/blocks/text-and-form/text-and-form-group/editor.scss +21 -0
  207. package/src/blocks/text-and-form/text-and-form-group/factory.tsx +38 -0
  208. package/src/blocks/text-and-form/text-and-form-group/icon.tsx +23 -0
  209. package/src/blocks/text-and-form/text-and-form-group/index.ts +9 -0
  210. package/src/blocks/text-and-form/text-and-form-group/types.ts +23 -0
  211. package/src/blocks/text-and-form/text-and-form-text-column/constants.ts +10 -0
  212. package/src/blocks/text-and-form/text-and-form-text-column/edit.tsx +94 -0
  213. package/src/blocks/text-and-form/text-and-form-text-column/editor.scss +29 -0
  214. package/src/blocks/text-and-form/text-and-form-text-column/factory.tsx +41 -0
  215. package/src/blocks/text-and-form/text-and-form-text-column/index.ts +18 -0
  216. package/src/blocks/text-and-form/text-and-form-text-column/types.ts +23 -0
  217. package/src/blocks/usp/usp-group/constants.ts +54 -0
  218. package/src/blocks/usp/usp-group/edit.tsx +197 -0
  219. package/src/blocks/usp/usp-group/editor.scss +24 -0
  220. package/src/blocks/usp/usp-group/factory.tsx +113 -0
  221. package/src/blocks/usp/usp-group/icon.tsx +18 -0
  222. package/src/blocks/usp/usp-group/index.ts +15 -0
  223. package/src/blocks/usp/usp-group/types.ts +70 -0
  224. package/src/blocks/usp/usp-item/constants.ts +7 -0
  225. package/src/blocks/usp/usp-item/edit.tsx +65 -0
  226. package/src/blocks/usp/usp-item/editor.scss +17 -0
  227. package/src/blocks/usp/usp-item/factory.tsx +30 -0
  228. package/src/blocks/usp/usp-item/index.ts +11 -0
  229. package/src/blocks/usp/usp-item/types.ts +17 -0
  230. package/src/components/IconControl/IconControl.tsx +55 -0
  231. package/src/components/IconControl/editor.scss +53 -0
  232. package/src/components/IconControl/index.ts +2 -0
  233. package/src/components/IconControl/index.tsx +1 -0
  234. package/src/components/ImagePicker/ImagePicker.tsx +124 -0
  235. package/src/components/ImagePicker/editor.scss +79 -0
  236. package/src/components/ImagePicker/index.ts +2 -0
  237. package/src/components/ImagePicker/index.tsx +1 -0
  238. package/src/components/ItemIconControl/ItemIconControl.tsx +72 -0
  239. package/src/components/ItemIconControl/ItemIconModal.tsx +12 -0
  240. package/src/components/ItemIconControl/ItemIconPreview.tsx +93 -0
  241. package/src/components/ItemIconControl/editor.scss +52 -0
  242. package/src/components/ItemIconControl/index.ts +2 -0
  243. package/src/components/ItemIconControl/types.d.ts +30 -0
  244. package/src/constants.ts +20 -0
  245. package/src/editor.scss +34 -0
  246. package/src/globals.scss +237 -0
  247. package/src/hooks/useGroupBlock.ts +53 -0
  248. package/src/index.ts +122 -0
  249. package/src/types.ts +33 -0
  250. package/src/utils/createEditAdapter.ts +11 -0
@@ -0,0 +1,65 @@
1
+ import {InspectorControls, RichText, useBlockProps} from '@wordpress/block-editor'
2
+ import {Modal, PanelBody, ToggleControl, TextControl} from '@wordpress/components'
3
+ import {useState} from '@wordpress/element'
4
+ import {__} from '@wordpress/i18n'
5
+ import clsx from 'clsx'
6
+ import {IconControl} from '~/components/IconControl'
7
+ import {ItemIconControl, ItemIconPreview} from '~/components/ItemIconControl'
8
+ import {ICON_TYPES} from './constants'
9
+ import type {UspItemAttributes, UspItemOptions} from './types'
10
+
11
+ export function createUspItemEdit(options: UspItemOptions) {
12
+ return function Edit({
13
+ attributes,
14
+ setAttributes,
15
+ }: {
16
+ attributes: UspItemAttributes
17
+ setAttributes: (a: Partial<UspItemAttributes>) => void
18
+ }) {
19
+ const {title, content, url, icon} = attributes
20
+
21
+ const blockProps = useBlockProps({className: 'i-usp'})
22
+
23
+ return (
24
+ <>
25
+ <InspectorControls>
26
+ <PanelBody title={__('Ikona', 'brilo-blocks')}>
27
+ <ItemIconControl icon={icon} setAttributes={setAttributes} iconTypes={ICON_TYPES} options={options} />
28
+ </PanelBody>
29
+ <PanelBody title={__('Odkaz', 'brilo-blocks')} initialOpen={false}>
30
+ <TextControl label={__('URL', 'brilo-blocks')} value={url.src} onChange={(v) => setAttributes({url: {...url, src: v}})} />
31
+ <ToggleControl
32
+ label={__('Otevřít v nové záložce', 'brilo-blocks')}
33
+ checked={url.blank}
34
+ onChange={(v) => setAttributes({url: {...url, blank: v}})}
35
+ />
36
+ </PanelBody>
37
+ </InspectorControls>
38
+
39
+ <div {...blockProps}>
40
+ <div className="i-usp__inner wp-block-inner">
41
+ <ItemIconPreview icon={icon} className="i-usp__icon" setAttributes={setAttributes} options={options} />
42
+
43
+ <div className={clsx('i-usp__body', 'grow')}>
44
+ <RichText
45
+ tagName="h3"
46
+ className="i-usp__title u-text-editable"
47
+ value={title}
48
+ onChange={(v) => setAttributes({title: v})}
49
+ placeholder={__('Nadpis...', 'brilo-blocks')}
50
+ allowedFormats={['core/bold', 'core/italic']}
51
+ />
52
+ <RichText
53
+ tagName="p"
54
+ className="i-usp__content u-text-editable"
55
+ value={content}
56
+ onChange={(v) => setAttributes({content: v})}
57
+ placeholder={__('Popis...', 'brilo-blocks')}
58
+ />
59
+ </div>
60
+ </div>
61
+ </div>
62
+ </>
63
+ )
64
+ }
65
+ }
@@ -0,0 +1,17 @@
1
+ .i-usp {
2
+ width: 100%;
3
+ margin-inline: 0;
4
+ }
5
+
6
+ .i-usp__title {
7
+ font-size: 16px;
8
+ font-weight: 600;
9
+ margin: 0;
10
+ }
11
+
12
+ .i-usp__content {
13
+ font-size: 14px;
14
+ color: #555;
15
+ margin: 0;
16
+ line-height: 1.5;
17
+ }
@@ -0,0 +1,30 @@
1
+ import type {BlockConfiguration} from '@wordpress/blocks'
2
+ import {__} from '@wordpress/i18n'
3
+ import {ICON_TYPES} from './constants'
4
+ import {createUspItemEdit} from './edit'
5
+ import type {UspItemAttributes, UspItemOptions} from './types'
6
+
7
+ export type {UspItemAttributes, UspItemOptions}
8
+
9
+ export function createUspItemBlock(options: UspItemOptions): BlockConfiguration<UspItemAttributes> {
10
+ return {
11
+ name: options.name,
12
+ title: options.title ?? __('USP položka', 'brilo-blocks'),
13
+ description: options.description,
14
+ category: options.category ?? 'layout',
15
+ ...(options.parent && {parent: options.parent}),
16
+ icon: options.icon ?? 'star-filled',
17
+ supports: {html: false, customClassName: false},
18
+ attributes: {
19
+ title: {type: 'string', default: ''},
20
+ content: {type: 'string', default: ''},
21
+ url: {type: 'object', default: {src: '', blank: false}},
22
+ icon: {
23
+ type: 'object',
24
+ default: {type: ICON_TYPES[0].value, src: '', media: {id: 0, alt: ''}},
25
+ },
26
+ },
27
+ edit: createUspItemEdit(options),
28
+ save: () => null,
29
+ } as unknown as BlockConfiguration<UspItemAttributes>
30
+ }
@@ -0,0 +1,11 @@
1
+ export type {UspItemAttributes, UspItemOptions} from './types'
2
+ export {createUspItemBlock} from './factory'
3
+
4
+ import type {UspItemOptions} from './types'
5
+
6
+ export const uspItemDefaults: UspItemOptions = {
7
+ name: 'brilo/usp-item',
8
+ parent: ['brilo/usp-group'],
9
+ icons: [],
10
+ iconsSrc: '',
11
+ }
@@ -0,0 +1,17 @@
1
+ import {BriloBlockType, Icon} from '~/types'
2
+ import type {IconType} from '~/components/IconControl'
3
+ import type {ICON_TYPES} from './constants'
4
+
5
+ export type UspIconType = (typeof ICON_TYPES)[number]['value']
6
+
7
+ export interface UspItemAttributes extends Record<string, unknown> {
8
+ title: string
9
+ content: string
10
+ url: {src: string; blank: boolean}
11
+ icon: Icon
12
+ }
13
+
14
+ export interface UspItemOptions extends BriloBlockType {
15
+ icons: IconType[]
16
+ iconsSrc: string
17
+ }
@@ -0,0 +1,55 @@
1
+ import {useState} from '@wordpress/element'
2
+ import {__} from '@wordpress/i18n'
3
+ import clsx from 'clsx'
4
+
5
+ export interface IconType {
6
+ value: string
7
+ label: string
8
+ }
9
+
10
+ interface IconControlProps {
11
+ value: string
12
+ label?: string
13
+ icons: IconType[]
14
+ iconsSrc: string
15
+ onChange: (icon: IconType) => void
16
+ }
17
+
18
+ export function IconControl({value, label, icons, iconsSrc, onChange}: IconControlProps) {
19
+ const getIconUrl = (name: string) => (name && name !== 'none' ? `${iconsSrc}${name}.svg` : '')
20
+ const [selectedIcon, setSelectedIcon] = useState<IconType>({
21
+ value,
22
+ label: label ?? '',
23
+ })
24
+
25
+ return (
26
+ <div className="icon-control flex column gap-4">
27
+ <div className="icon-control__hero-selected flex gap-4">
28
+ <div className="icon-control__hero-selected-img flex items-center justify-center">
29
+ {selectedIcon.value && <img src={getIconUrl(selectedIcon.value)} alt="" width={24} height={24} loading="lazy" />}
30
+ </div>
31
+ <div className="icon-control__hero-selected-body flex column gap-1">
32
+ <span>{__('Vybraná ikona', 'brilo-blocks')}</span>
33
+ <span className="icon-control__hero-selected-label">{selectedIcon.label}</span>
34
+ </div>
35
+ </div>
36
+ <div className="icon-control__group">
37
+ {icons.map((icon) => (
38
+ <button
39
+ key={icon.value}
40
+ type="button"
41
+ className={clsx('icon-control__item', 'flex', 'column', 'gap-2', 'items-center', 'justify-center', 'cursor-pointer', {
42
+ '--selected': selectedIcon.value === icon.value,
43
+ })}
44
+ onClick={() => {
45
+ onChange(icon)
46
+ setSelectedIcon(icon)
47
+ }}
48
+ >
49
+ <img src={getIconUrl(icon.value)} alt="" width={24} height={24} loading="lazy" />
50
+ </button>
51
+ ))}
52
+ </div>
53
+ </div>
54
+ )
55
+ }
@@ -0,0 +1,53 @@
1
+ @layer base {
2
+ .icon-control__group {
3
+ &.u-grid-responsive {
4
+ --grid-min-col-size: 64px;
5
+ --grid-gap: 2px;
6
+ }
7
+ }
8
+
9
+ .icon-control__item {
10
+ --border-color: #ddd;
11
+ --background-color: transparent;
12
+
13
+ width: 64px;
14
+ height: 64px;
15
+ border: 1px solid var(--border-color);
16
+ background-color: var(--background-color);
17
+ border-radius: 8px;
18
+ justify-self: center;
19
+ transition: border-color 0.3s ease;
20
+ transition-property: border-color, background-color;
21
+
22
+ img {
23
+ transition: filter 0.3s ease;
24
+ }
25
+
26
+ &.--selected {
27
+ --border-color: oklch(62.3% 0.214 259.815);
28
+ --background-color: oklch(62.3% 0.214 259.815);
29
+
30
+ img {
31
+ filter: invert(1);
32
+ }
33
+ }
34
+ }
35
+
36
+ .icon-control__hero-selected-img {
37
+ --border-color: #ddd;
38
+ --background-color: transparent;
39
+
40
+ width: 64px;
41
+ height: 64px;
42
+ border: 1px solid var(--border-color);
43
+ background-color: var(--background-color);
44
+ border-radius: 8px;
45
+ }
46
+
47
+ .icon-control__hero-selected {
48
+ padding-block: 8px;
49
+ position: sticky;
50
+ top: 0;
51
+ background-color: #fff;
52
+ }
53
+ }
@@ -0,0 +1,2 @@
1
+ export type {IconType} from './IconControl'
2
+ export {IconControl} from './IconControl'
@@ -0,0 +1 @@
1
+ // re-exported from index.ts — this file intentionally empty
@@ -0,0 +1,124 @@
1
+ import {MediaUpload, MediaUploadCheck} from '@wordpress/block-editor'
2
+ import {Button, TextControl} from '@wordpress/components'
3
+ import {useSelect} from '@wordpress/data'
4
+ import {__} from '@wordpress/i18n'
5
+ import {CSSProperties} from 'react'
6
+
7
+ export interface ImageValue {
8
+ id: number
9
+ alt: string
10
+ }
11
+
12
+ export interface ImageLabels {
13
+ select?: string
14
+ change?: string
15
+ remove?: string
16
+ }
17
+
18
+ interface ImagePickerProps {
19
+ value: ImageValue
20
+ onChange: (value: ImageValue) => void
21
+ allowedTypes?: string[]
22
+ placeholder?: string
23
+ labels?: ImageLabels
24
+ size?: [number, number]
25
+ }
26
+
27
+ export function useMediaUrl(id: number): string | undefined {
28
+ return useSelect(
29
+ (select) => {
30
+ if (!id) return undefined
31
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
32
+ const media = (select('core') as any).getMedia(id)
33
+ return media?.source_url as string | undefined
34
+ },
35
+ [id],
36
+ )
37
+ }
38
+
39
+ function useImagePicker(value: ImageValue, onChange: (v: ImageValue) => void, labels?: ImageLabels) {
40
+ const mediaUrl = useMediaUrl(value.id)
41
+ const selectLabel = labels?.select ?? __('Vybrat obrázek', 'brilo-blocks')
42
+ const changeLabel = labels?.change ?? __('Změnit', 'brilo-blocks')
43
+ const removeLabel = labels?.remove ?? __('Odebrat', 'brilo-blocks')
44
+ const handleSelect = (media: {id: number; alt: string}) => onChange({id: media.id, alt: media.alt ?? ''})
45
+ const handleRemove = () => onChange({id: 0, alt: ''})
46
+ return {mediaUrl, selectLabel, changeLabel, removeLabel, handleSelect, handleRemove}
47
+ }
48
+
49
+ export function ImagePickerBody({value, onChange, allowedTypes = ['image'], placeholder, labels}: ImagePickerProps) {
50
+ const {mediaUrl, selectLabel, changeLabel, removeLabel, handleSelect, handleRemove} = useImagePicker(value, onChange, labels)
51
+
52
+ return (
53
+ <MediaUploadCheck>
54
+ <MediaUpload
55
+ onSelect={handleSelect}
56
+ allowedTypes={allowedTypes}
57
+ value={value.id || 0}
58
+ render={({open}: {open: () => void}) =>
59
+ value.id ? (
60
+ <div className="c-image-picker-body">
61
+ <div className="c-image-picker-body__preview">{mediaUrl && <img src={mediaUrl} alt={value.alt} />}</div>
62
+ <div className="c-image-picker-body__actions">
63
+ <Button onClick={open} variant="secondary">
64
+ {changeLabel}
65
+ </Button>
66
+ <Button onClick={handleRemove} variant="tertiary" isDestructive>
67
+ {removeLabel}
68
+ </Button>
69
+ </div>
70
+ </div>
71
+ ) : (
72
+ <button type="button" className="c-image-picker-body__placeholder" onClick={open}>
73
+ {placeholder ?? selectLabel}
74
+ </button>
75
+ )
76
+ }
77
+ />
78
+ </MediaUploadCheck>
79
+ )
80
+ }
81
+
82
+ export function ImagePickerControl({value, onChange, allowedTypes = ['image'], placeholder, labels, size = [48, 48]}: ImagePickerProps) {
83
+ const {mediaUrl, selectLabel, changeLabel, removeLabel, handleSelect, handleRemove} = useImagePicker(value, onChange, labels)
84
+
85
+ return (
86
+ <div
87
+ className="c-image-picker-control"
88
+ style={
89
+ {
90
+ '--image-picker-width': `${size[0]}px`,
91
+ '--image-picker-height': `${size[1]}px`,
92
+ } as CSSProperties
93
+ }
94
+ >
95
+ <MediaUploadCheck>
96
+ <MediaUpload
97
+ onSelect={handleSelect}
98
+ allowedTypes={allowedTypes}
99
+ value={value.id || 0}
100
+ render={({open}: {open: () => void}) => (
101
+ <div className="c-image-picker-control__row">
102
+ {!!value.id && !!mediaUrl && (
103
+ <div className="c-image-picker-control__thumb">
104
+ <img src={mediaUrl} alt={value.alt} />
105
+ </div>
106
+ )}
107
+ <div className="c-image-picker-control__btns">
108
+ <Button onClick={open} variant="secondary" size="small">
109
+ {value.id ? changeLabel : (placeholder ?? selectLabel)}
110
+ </Button>
111
+ {!!value.id && (
112
+ <Button onClick={handleRemove} variant="tertiary" size="small" isDestructive>
113
+ {removeLabel}
114
+ </Button>
115
+ )}
116
+ </div>
117
+ </div>
118
+ )}
119
+ />
120
+ </MediaUploadCheck>
121
+ {!!value.id && <TextControl label={__('Alt text', 'brilo-blocks')} value={value.alt} onChange={(alt) => onChange({...value, alt})} />}
122
+ </div>
123
+ )
124
+ }
@@ -0,0 +1,79 @@
1
+ @layer base {
2
+ .c-image-picker-body {
3
+ width: 100%;
4
+ height: 100%;
5
+ display: flex;
6
+ flex-direction: column;
7
+ }
8
+
9
+ .c-image-picker-body__preview {
10
+ width: 100%;
11
+ height: 100%;
12
+
13
+ img {
14
+ width: 100%;
15
+ max-height: 100%;
16
+ height: auto;
17
+ display: block;
18
+ border-radius: 2px;
19
+ }
20
+ }
21
+
22
+ .c-image-picker-body__actions {
23
+ display: flex;
24
+ flex-wrap: wrap;
25
+ gap: 8px;
26
+ margin-top: 8px;
27
+ padding: 8px;
28
+ }
29
+
30
+ .c-image-picker-body__placeholder {
31
+ width: 100%;
32
+ min-height: 120px;
33
+ background: #e8ecf1;
34
+ border: 2px dashed #b0bec5;
35
+ border-radius: 4px;
36
+ cursor: pointer;
37
+ display: flex;
38
+ align-items: center;
39
+ justify-content: center;
40
+ font-size: 13px;
41
+ color: #546e7a;
42
+ padding: 16px;
43
+ box-sizing: border-box;
44
+ }
45
+
46
+ .c-image-picker-control {
47
+ width: 100%;
48
+ margin-bottom: 8px;
49
+ }
50
+
51
+ .c-image-picker-control__row {
52
+ display: flex;
53
+ align-items: center;
54
+ gap: 8px;
55
+ margin-bottom: 8px;
56
+ }
57
+
58
+ .c-image-picker-control__thumb {
59
+ width: var(--image-picker-width, 48px);
60
+ height: var(--image-picker-height, 48px);
61
+ flex-shrink: 0;
62
+ border-radius: 2px;
63
+ overflow: hidden;
64
+
65
+ img {
66
+ width: 100%;
67
+ height: 100%;
68
+ object-fit: cover;
69
+ display: block;
70
+ }
71
+ }
72
+
73
+ .c-image-picker-control__btns {
74
+ display: flex;
75
+ gap: 4px;
76
+ flex-wrap: wrap;
77
+ align-items: center;
78
+ }
79
+ }
@@ -0,0 +1,2 @@
1
+ export type {ImageLabels, ImageValue} from './ImagePicker'
2
+ export {ImagePickerBody, ImagePickerControl, useMediaUrl} from './ImagePicker'
@@ -0,0 +1 @@
1
+ // re-exported from index.ts — this file intentionally empty
@@ -0,0 +1,72 @@
1
+ import {
2
+ Button,
3
+ TextControl,
4
+ __experimentalToggleGroupControl as ToggleGroupControl,
5
+ __experimentalToggleGroupControlOption as ToggleGroupControlOption,
6
+ } from '@wordpress/components'
7
+ import {useState} from '@wordpress/element'
8
+ import {__} from '@wordpress/i18n'
9
+ import {ImagePickerControl} from '~/components/ImagePicker'
10
+ import type {ItemIconControlProps} from './types'
11
+ import {ItemIconModal} from './ItemIconModal'
12
+
13
+ export function ItemIconControl({icon, setAttributes, options, iconTypes}: ItemIconControlProps) {
14
+ const [isModalOpen, setModalOpen] = useState(false)
15
+ const preselectedIconUrl = icon.type === 'preselected' && icon.src ? `${options.iconsSrc}${icon.src}.svg` : ''
16
+
17
+ return (
18
+ <>
19
+ <ToggleGroupControl
20
+ label={__('Typ ikony', 'brilo-blocks')}
21
+ value={icon.type}
22
+ onChange={(v) => setAttributes({icon: {...icon, type: v as string}})}
23
+ isBlock
24
+ >
25
+ {iconTypes.map((t) => (
26
+ <ToggleGroupControlOption key={t.value} value={t.value} label={t.label} />
27
+ ))}
28
+ </ToggleGroupControl>
29
+
30
+ {icon.type === 'preselected' && (
31
+ <div className="i-item-icon__control-preselected">
32
+ {preselectedIconUrl && (
33
+ <div className="i-item-icon__preview">
34
+ <img src={preselectedIconUrl} alt="" width={32} height={32} />
35
+ </div>
36
+ )}
37
+ <Button variant="secondary" onClick={() => setModalOpen(true)}>
38
+ {icon.src ? __('Změnit ikonu', 'brilo-blocks') : __('Vybrat ikonu', 'brilo-blocks')}
39
+ </Button>
40
+ </div>
41
+ )}
42
+
43
+ {icon.type === 'media' && (
44
+ <ImagePickerControl
45
+ value={icon.media}
46
+ onChange={(val) => setAttributes({icon: {...icon, media: val}})}
47
+ labels={{
48
+ select: __('Vybrat ikonu', 'brilo-blocks'),
49
+ change: __('Změnit ikonu', 'brilo-blocks'),
50
+ remove: __('Odebrat ikonu', 'brilo-blocks'),
51
+ }}
52
+ />
53
+ )}
54
+
55
+ {icon.type === 'number' && (
56
+ <TextControl label={__('Číslo', 'brilo-blocks')} value={icon.src} onChange={(v) => setAttributes({icon: {...icon, src: v}})} />
57
+ )}
58
+
59
+ {isModalOpen && (
60
+ <ItemIconModal
61
+ icon={icon}
62
+ options={options}
63
+ onClose={() => setModalOpen(false)}
64
+ onChange={(selectedIcon) => {
65
+ setAttributes({icon: {...icon, src: selectedIcon.value}})
66
+ setModalOpen(false)
67
+ }}
68
+ />
69
+ )}
70
+ </>
71
+ )
72
+ }
@@ -0,0 +1,12 @@
1
+ import {Modal} from '@wordpress/components'
2
+ import {__} from '@wordpress/i18n'
3
+ import {IconControl} from '~/components/IconControl'
4
+ import type {ItemIconModalProps} from './types'
5
+
6
+ export function ItemIconModal({icon, options, onClose, onChange, className = 'i-item-icon__modal'}: ItemIconModalProps) {
7
+ return (
8
+ <Modal title={__('Vybrat ikonu', 'brilo-blocks')} onRequestClose={onClose} size="large" className={className}>
9
+ <IconControl value={icon.src} icons={options.icons} iconsSrc={options.iconsSrc} onChange={onChange} />
10
+ </Modal>
11
+ )
12
+ }
@@ -0,0 +1,93 @@
1
+ import clsx from 'clsx'
2
+ import {useState} from '@wordpress/element'
3
+ import {useMediaUrl} from '~/components/ImagePicker'
4
+ import type {ItemIconPreviewProps} from './types'
5
+ import {ItemIconModal} from './ItemIconModal'
6
+
7
+ export function ItemIconPreview({icon, className, options, setAttributes}: ItemIconPreviewProps) {
8
+ const [isModalOpen, setModalOpen] = useState(false)
9
+ const mediaIconUrl = useMediaUrl(icon.media.id)
10
+ const preselectedIconUrl = icon.type === 'preselected' && icon.src ? `${options.iconsSrc}${icon.src}.svg` : ''
11
+
12
+ const renderContent = () => {
13
+ if (icon.type === 'preselected') {
14
+ if (preselectedIconUrl) {
15
+ return (
16
+ <div className={clsx('i-item-icon', className)}>
17
+ <img
18
+ src={preselectedIconUrl}
19
+ alt=""
20
+ className={clsx(className ? `${className}-img` : 'i-item-icon__img')}
21
+ width={40}
22
+ height={40}
23
+ />
24
+ </div>
25
+ )
26
+ }
27
+ return (
28
+ <button
29
+ type="button"
30
+ className={clsx(
31
+ 'i-item-icon',
32
+ className ? `${className}-placeholder` : null,
33
+ 'i-item-icon__placeholder',
34
+ !isModalOpen && '--clickable',
35
+ )}
36
+ onClick={() => setModalOpen(true)}
37
+ >
38
+ <span>☆</span>
39
+ </button>
40
+ )
41
+ }
42
+
43
+ if (icon.type === 'media') {
44
+ if (icon.media.id && mediaIconUrl) {
45
+ return (
46
+ <div className={clsx('i-item-icon', className)}>
47
+ <img src={mediaIconUrl} alt={icon.media.alt} className={clsx(className ? `${className}-img` : null, 'i-item-icon__img')} />
48
+ </div>
49
+ )
50
+ }
51
+ return (
52
+ <div className={clsx('i-item-icon', className ? `${className}-placeholder` : 'i-item-icon__placeholder')}>
53
+ <span>☆</span>
54
+ </div>
55
+ )
56
+ }
57
+
58
+ if (icon.type === 'number') {
59
+ if (icon.src) {
60
+ return (
61
+ <div className={clsx('i-item-icon', className)}>
62
+ <span className={clsx(className ? `${className}-number` : 'i-item-icon__number')}>{icon.src}</span>
63
+ </div>
64
+ )
65
+ }
66
+ return (
67
+ <div className={clsx('i-item-icon', className ? `${className}-placeholder` : 'i-item-icon__placeholder')}>
68
+ <span>☆</span>
69
+ </div>
70
+ )
71
+ }
72
+
73
+ return null
74
+ }
75
+
76
+ return (
77
+ <>
78
+ {renderContent()}
79
+ {isModalOpen && (
80
+ <ItemIconModal
81
+ icon={icon}
82
+ options={options}
83
+ onClose={() => setModalOpen(false)}
84
+ onChange={(selectedIcon) => {
85
+ setAttributes({icon: {...icon, src: selectedIcon.value}})
86
+ setModalOpen(false)
87
+ }}
88
+ className="i-step__icon-modal"
89
+ />
90
+ )}
91
+ </>
92
+ )
93
+ }