@brilo/base-blocks 0.1.47 → 0.1.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/build/.tsbuildinfo +1 -1
  2. package/build/blocks/contact/contact-group/constants.d.ts +71 -0
  3. package/build/blocks/contact/contact-group/constants.d.ts.map +1 -1
  4. package/build/blocks/contact/contact-group/constants.js +35 -0
  5. package/build/blocks/contact/contact-group/edit.d.ts.map +1 -1
  6. package/build/blocks/contact/contact-group/edit.js +20 -8
  7. package/build/blocks/contact/contact-group/factory.d.ts +3 -3
  8. package/build/blocks/contact/contact-group/factory.d.ts.map +1 -1
  9. package/build/blocks/contact/contact-group/factory.js +33 -8
  10. package/build/blocks/contact/contact-group/index.d.ts +2 -2
  11. package/build/blocks/contact/contact-group/index.d.ts.map +1 -1
  12. package/build/blocks/contact/contact-group/index.js +1 -1
  13. package/build/blocks/contact/contact-group/types.d.ts +29 -6
  14. package/build/blocks/contact/contact-group/types.d.ts.map +1 -1
  15. package/build/blocks/contact/contact-item/buildPreviewStyle.d.ts +24 -0
  16. package/build/blocks/contact/contact-item/buildPreviewStyle.d.ts.map +1 -0
  17. package/build/blocks/contact/contact-item/buildPreviewStyle.js +31 -0
  18. package/build/blocks/contact/contact-item/edit.d.ts.map +1 -1
  19. package/build/blocks/contact/contact-item/edit.js +10 -8
  20. package/build/blocks/contact/contact-item/factory.js +2 -2
  21. package/build/index.d.ts +2 -2
  22. package/build/index.d.ts.map +1 -1
  23. package/build/index.js +1 -1
  24. package/package.json +1 -1
  25. package/src/blocks/contact/contact-group/constants.ts +42 -0
  26. package/src/blocks/contact/contact-group/edit.tsx +177 -20
  27. package/src/blocks/contact/contact-group/editor.scss +19 -0
  28. package/src/blocks/contact/contact-group/factory.tsx +61 -8
  29. package/src/blocks/contact/contact-group/index.ts +10 -2
  30. package/src/blocks/contact/contact-group/types.ts +48 -6
  31. package/src/blocks/contact/contact-item/buildPreviewStyle.ts +69 -0
  32. package/src/blocks/contact/contact-item/edit.tsx +17 -30
  33. package/src/blocks/contact/contact-item/editor.scss +136 -7
  34. package/src/blocks/contact/contact-item/factory.tsx +2 -2
  35. package/src/index.ts +5 -0
@@ -4,13 +4,55 @@ export const CONTACT_COLUMNS = [2, 3] as const
4
4
 
5
5
  export const CONTACT_COLUMNS_CONTEXT = 'brilo/contact-columns'
6
6
 
7
+ export const CONTACT_STYLE_CONTEXT = 'brilo/contact-style'
8
+
7
9
  export const DEFAULT_SHADOWS = [
8
10
  {value: 'none', label: __('Žádný', 'brilo-blocks')},
9
11
  {value: 'sm', label: __('Malý', 'brilo-blocks')},
10
12
  {value: 'md', label: __('Střední', 'brilo-blocks')},
11
13
  ] as const
12
14
 
15
+ export const DEFAULT_DIRECTIONS = [
16
+ {value: 'vertical', label: __('Vertikální', 'brilo-blocks')},
17
+ {value: 'horizontal', label: __('Horizontální', 'brilo-blocks')},
18
+ ] as const
19
+
13
20
  export const TEXT_ALIGNS = [
14
21
  {value: 'left', label: __('Vlevo', 'brilo-blocks')},
15
22
  {value: 'center', label: __('Na střed', 'brilo-blocks')},
16
23
  ] as const
24
+
25
+ export const DEFAULT_ICON_SIZE = 88
26
+ export const ICON_SIZE_MIN = 4
27
+ export const ICON_SIZE_MAX = 128
28
+
29
+ export const DEFAULT_ICON_SIZE_PRESETS = [
30
+ {value: 8, label: __('XS', 'brilo-blocks')},
31
+ {value: 16, label: __('SM', 'brilo-blocks')},
32
+ {value: 24, label: __('MD', 'brilo-blocks')},
33
+ {value: 32, label: __('LG', 'brilo-blocks')},
34
+ {value: 48, label: __('XL', 'brilo-blocks')},
35
+ ] as const
36
+
37
+ export const DEFAULT_ICON_BACKGROUND_SIZE = 88
38
+ export const ICON_BACKGROUND_SIZE_MIN = 16
39
+ export const ICON_BACKGROUND_SIZE_MAX = 240
40
+
41
+ export const DEFAULT_ICON_BACKGROUND_SIZE_PRESETS = [
42
+ {value: 48, label: __('XS', 'brilo-blocks')},
43
+ {value: 64, label: __('SM', 'brilo-blocks')},
44
+ {value: 88, label: __('Výchozí', 'brilo-blocks')},
45
+ {value: 104, label: __('LG', 'brilo-blocks')},
46
+ {value: 128, label: __('XL', 'brilo-blocks')},
47
+ ] as const
48
+
49
+ export const DEFAULT_ICON_BACKGROUND_SHAPES = [
50
+ {value: 'none', label: __('Žádný', 'brilo-blocks')},
51
+ {value: 'circle', label: __('Kruh', 'brilo-blocks')},
52
+ {value: 'triangle', label: __('Trojúhelník', 'brilo-blocks')},
53
+ {value: 'rhombus', label: __('Kosočtverec', 'brilo-blocks')},
54
+ {value: 'octagon', label: __('Osmiúhelník', 'brilo-blocks')},
55
+ {value: 'bevel', label: __('Zkosený', 'brilo-blocks')},
56
+ {value: 'rabbet', label: __('Drážkovaný', 'brilo-blocks')},
57
+ {value: 'parallelogram', label: __('Rovnoběžník', 'brilo-blocks')},
58
+ ] as const
@@ -1,20 +1,80 @@
1
1
  import {InspectorControls} from '@wordpress/block-editor'
2
2
  import {
3
3
  BaseControl,
4
+ Button,
4
5
  ColorPalette,
5
6
  PanelBody,
7
+ RangeControl,
8
+ SelectControl,
6
9
  __experimentalToggleGroupControl as ToggleGroupControl,
7
10
  __experimentalToggleGroupControlOption as ToggleGroupControlOption,
8
11
  } from '@wordpress/components'
9
12
  import {__} from '@wordpress/i18n'
10
13
  import clsx from 'clsx'
14
+ import type {CSSProperties} from 'react'
15
+ import {ItemSpacingPanel, itemSpacingStyle} from '~/components/ItemSpacingControl'
11
16
  import {useGroupBlock} from '~/hooks/useGroupBlock'
12
17
  import {useTenantColorPalette} from '~/hooks/useTenantColorPalette'
13
- import {CONTACT_COLUMNS, DEFAULT_SHADOWS, TEXT_ALIGNS} from './constants'
14
- import type {ContactColumns, ContactGroupAttributes, ContactGroupOptions, ContactShadow, ContactTextAlign} from './types'
18
+ import {
19
+ CONTACT_COLUMNS,
20
+ DEFAULT_DIRECTIONS,
21
+ DEFAULT_ICON_BACKGROUND_SHAPES,
22
+ DEFAULT_ICON_BACKGROUND_SIZE_PRESETS,
23
+ DEFAULT_ICON_SIZE_PRESETS,
24
+ DEFAULT_SHADOWS,
25
+ ICON_BACKGROUND_SIZE_MAX,
26
+ ICON_BACKGROUND_SIZE_MIN,
27
+ ICON_SIZE_MAX,
28
+ ICON_SIZE_MIN,
29
+ TEXT_ALIGNS,
30
+ } from './constants'
31
+ import type {
32
+ ContactColumns,
33
+ ContactDirection,
34
+ ContactGroupAttributes,
35
+ ContactGroupOptions,
36
+ ContactIconBackgroundShape,
37
+ ContactShadow,
38
+ ContactSizePreset,
39
+ ContactTextAlign,
40
+ } from './types'
41
+
42
+ function PresetSizeControl({
43
+ label,
44
+ value,
45
+ presets,
46
+ min,
47
+ max,
48
+ onChange,
49
+ }: {
50
+ label: string
51
+ value: number
52
+ presets: readonly ContactSizePreset[]
53
+ min: number
54
+ max: number
55
+ onChange: (v: number) => void
56
+ }) {
57
+ return (
58
+ <BaseControl label={label} id={`contact-group-size-${label}`}>
59
+ <div style={{display: 'flex', gap: 4, marginBottom: 8, flexWrap: 'wrap'}}>
60
+ {presets.map((p) => (
61
+ <Button key={p.label} variant={value === p.value ? 'primary' : 'secondary'} size="small" onClick={() => onChange(p.value)}>
62
+ {p.label}
63
+ </Button>
64
+ ))}
65
+ </div>
66
+ <RangeControl value={value} onChange={(v) => onChange(v ?? min)} min={min} max={max} step={1} withInputField />
67
+ </BaseControl>
68
+ )
69
+ }
15
70
 
16
71
  export function createContactGroupEdit(options: ContactGroupOptions) {
17
72
  const COLUMNS = options.columns ?? CONTACT_COLUMNS
73
+ const DIRECTIONS = options.directions ?? DEFAULT_DIRECTIONS
74
+ const SHADOWS = options.shadows ?? DEFAULT_SHADOWS
75
+ const ICON_SIZE_PRESETS = options.iconSizePresets ?? DEFAULT_ICON_SIZE_PRESETS
76
+ const ICON_BACKGROUND_SIZE_PRESETS = options.iconBackgroundSizePresets ?? DEFAULT_ICON_BACKGROUND_SIZE_PRESETS
77
+ const ICON_BACKGROUND_SHAPES = options.iconBackgroundShapes ?? DEFAULT_ICON_BACKGROUND_SHAPES
18
78
 
19
79
  return function Edit({
20
80
  attributes,
@@ -23,19 +83,30 @@ export function createContactGroupEdit(options: ContactGroupOptions) {
23
83
  attributes: ContactGroupAttributes
24
84
  setAttributes: (a: Partial<ContactGroupAttributes>) => void
25
85
  }) {
26
- const {columns, style} = attributes
27
- const {paletteColors} = useTenantColorPalette()
86
+ const {columns, groupBackgroundColor, style, spacing} = attributes
87
+ const {paletteColors, resolveHex} = useTenantColorPalette()
28
88
 
29
89
  const {blockProps, innerBlocksProps} = useGroupBlock({
30
- blockClassName: clsx(options.blockClassName ?? 'g-contact wp-block-section'),
90
+ blockClassName: clsx(
91
+ options.blockClassName ?? 'g-contact wp-block-section',
92
+ `--direction-${style.direction}`,
93
+ groupBackgroundColor && '--group-background',
94
+ spacing === 0 && '--connected',
95
+ ),
31
96
  containerClassName: [options.containerClassName ?? 'g-contact__items', `--cols-${columns}`],
32
- containerStyle: {'--grid-max-col-count': columns},
97
+ containerStyle: {'--grid-max-col-count': columns, ...itemSpacingStyle(spacing)},
33
98
  allowedBlocks: options.allowedBlocks,
34
99
  orientation: 'horizontal',
35
100
  template: options.template,
36
101
  layout: {type: 'default'},
37
102
  })
38
103
 
104
+ const groupStyle = (
105
+ groupBackgroundColor
106
+ ? {...(blockProps.style as CSSProperties), '--group-background-color': resolveHex(groupBackgroundColor)}
107
+ : (blockProps.style as CSSProperties)
108
+ ) as CSSProperties
109
+
39
110
  return (
40
111
  <>
41
112
  <InspectorControls>
@@ -50,20 +121,52 @@ export function createContactGroupEdit(options: ContactGroupOptions) {
50
121
  <ToggleGroupControlOption key={c} value={String(c)} label={String(c)} />
51
122
  ))}
52
123
  </ToggleGroupControl>
124
+ <ToggleGroupControl
125
+ isBlock
126
+ label={__('Směr', 'brilo-blocks')}
127
+ value={style.direction}
128
+ onChange={(v) => setAttributes({style: {...style, direction: v as ContactDirection}})}
129
+ >
130
+ {DIRECTIONS.map((d) => (
131
+ <ToggleGroupControlOption key={d.value} value={d.value} label={d.label} />
132
+ ))}
133
+ </ToggleGroupControl>
134
+ <ToggleGroupControl
135
+ isBlock
136
+ label={__('Zarovnání', 'brilo-blocks')}
137
+ help={__('Zarovná text i ikonu položky.', 'brilo-blocks')}
138
+ value={style.textAlign}
139
+ onChange={(v) => setAttributes({style: {...style, textAlign: v as ContactTextAlign}})}
140
+ >
141
+ {TEXT_ALIGNS.map((a) => (
142
+ <ToggleGroupControlOption key={a.value} value={a.value} label={a.label} />
143
+ ))}
144
+ </ToggleGroupControl>
53
145
  </PanelBody>
54
146
  <PanelBody title={__('Styl', 'brilo-blocks')}>
147
+ <BaseControl
148
+ label={__('Barva pozadí skupiny', 'brilo-blocks')}
149
+ help={__('Souvislé pozadí za všemi položkami. Vhodné s nulovou mezerou.', 'brilo-blocks')}
150
+ id="contact-group-group-background-color"
151
+ >
152
+ <ColorPalette
153
+ colors={paletteColors}
154
+ value={groupBackgroundColor || undefined}
155
+ onChange={(value) => setAttributes({groupBackgroundColor: value ?? ''})}
156
+ />
157
+ </BaseControl>
55
158
  <ToggleGroupControl
56
159
  isBlock
57
- label={__('Stín', 'brilo-blocks')}
160
+ label={__('Stín položek', 'brilo-blocks')}
58
161
  value={style.shadow}
59
162
  onChange={(v) => setAttributes({style: {...style, shadow: v as ContactShadow}})}
60
163
  >
61
- {DEFAULT_SHADOWS.map((s) => (
164
+ {SHADOWS.map((s) => (
62
165
  <ToggleGroupControlOption key={s.value} value={s.value} label={s.label} />
63
166
  ))}
64
167
  </ToggleGroupControl>
65
168
  <BaseControl
66
- label={__('Barva okraje', 'brilo-blocks')}
169
+ label={__('Barva okraje položek', 'brilo-blocks')}
67
170
  help={__('Bez vybrané barvy se okraj nevykreslí.', 'brilo-blocks')}
68
171
  id="contact-group-border-color"
69
172
  >
@@ -73,7 +176,7 @@ export function createContactGroupEdit(options: ContactGroupOptions) {
73
176
  onChange={(value) => setAttributes({style: {...style, borderColor: value ?? ''}})}
74
177
  />
75
178
  </BaseControl>
76
- <BaseControl label={__('Barva pozadí', 'brilo-blocks')} id="contact-group-background-color">
179
+ <BaseControl label={__('Barva pozadí položek', 'brilo-blocks')} id="contact-group-background-color">
77
180
  <ColorPalette
78
181
  colors={paletteColors}
79
182
  value={style.backgroundColor || undefined}
@@ -87,19 +190,73 @@ export function createContactGroupEdit(options: ContactGroupOptions) {
87
190
  onChange={(value) => setAttributes({style: {...style, textColor: value ?? ''}})}
88
191
  />
89
192
  </BaseControl>
90
- <ToggleGroupControl
91
- isBlock
92
- label={__('Zarovnání textu', 'brilo-blocks')}
93
- value={style.textAlign}
94
- onChange={(v) => setAttributes({style: {...style, textAlign: v as ContactTextAlign}})}
193
+ </PanelBody>
194
+ <PanelBody title={__('Ikona', 'brilo-blocks')} initialOpen={false}>
195
+ <PresetSizeControl
196
+ label={__('Velikost', 'brilo-blocks')}
197
+ value={style.icon.size}
198
+ presets={ICON_SIZE_PRESETS}
199
+ min={ICON_SIZE_MIN}
200
+ max={ICON_SIZE_MAX}
201
+ onChange={(v) => setAttributes({style: {...style, icon: {...style.icon, size: v}}})}
202
+ />
203
+ <BaseControl label={__('Barva', 'brilo-blocks')} id="contact-group-icon-color">
204
+ <ColorPalette
205
+ colors={paletteColors}
206
+ value={style.icon.color || undefined}
207
+ onChange={(value) => setAttributes({style: {...style, icon: {...style.icon, color: value ?? ''}}})}
208
+ />
209
+ </BaseControl>
210
+ <BaseControl label={__('Pozadí', 'brilo-blocks')} id="contact-group-icon-background-color">
211
+ <ColorPalette
212
+ colors={paletteColors}
213
+ value={style.icon.background || undefined}
214
+ onChange={(value) => setAttributes({style: {...style, icon: {...style.icon, background: value ?? ''}}})}
215
+ />
216
+ </BaseControl>
217
+ <PresetSizeControl
218
+ label={__('Velikost pozadí', 'brilo-blocks')}
219
+ value={style.icon.backgroundSize}
220
+ presets={ICON_BACKGROUND_SIZE_PRESETS}
221
+ min={ICON_BACKGROUND_SIZE_MIN}
222
+ max={ICON_BACKGROUND_SIZE_MAX}
223
+ onChange={(v) => setAttributes({style: {...style, icon: {...style.icon, backgroundSize: v}}})}
224
+ />
225
+ {style.icon.background && (
226
+ <SelectControl<string>
227
+ label={__('Tvar pozadí', 'brilo-blocks')}
228
+ value={style.icon.backgroundShape}
229
+ options={[...ICON_BACKGROUND_SHAPES]}
230
+ onChange={(v) =>
231
+ setAttributes({style: {...style, icon: {...style.icon, backgroundShape: v as ContactIconBackgroundShape}}})
232
+ }
233
+ />
234
+ )}
235
+ <BaseControl
236
+ label={__('Barva ohraničení', 'brilo-blocks')}
237
+ help={__('Bez vybrané barvy se okraj nevykreslí.', 'brilo-blocks')}
238
+ id="contact-group-icon-border-color"
95
239
  >
96
- {TEXT_ALIGNS.map((a) => (
97
- <ToggleGroupControlOption key={a.value} value={a.value} label={a.label} />
98
- ))}
99
- </ToggleGroupControl>
240
+ <ColorPalette
241
+ colors={paletteColors}
242
+ value={style.icon.borderColor || undefined}
243
+ onChange={(value) => setAttributes({style: {...style, icon: {...style.icon, borderColor: value ?? ''}}})}
244
+ />
245
+ </BaseControl>
246
+ {style.icon.borderColor && (
247
+ <RangeControl
248
+ label={__('Šířka ohraničení (px)', 'brilo-blocks')}
249
+ value={style.icon.borderWidth}
250
+ onChange={(v) => setAttributes({style: {...style, icon: {...style.icon, borderWidth: v ?? 0}}})}
251
+ min={0}
252
+ max={10}
253
+ step={1}
254
+ />
255
+ )}
100
256
  </PanelBody>
257
+ <ItemSpacingPanel spacing={spacing} onChange={(v) => setAttributes({spacing: v})} />
101
258
  </InspectorControls>
102
- <div {...blockProps}>
259
+ <div {...blockProps} style={groupStyle}>
103
260
  <div {...innerBlocksProps} />
104
261
  </div>
105
262
  </>
@@ -6,6 +6,25 @@
6
6
  gap: 16px;
7
7
  align-items: start;
8
8
  }
9
+
10
+ &.--group-background {
11
+ background-color: var(--group-background-color, transparent);
12
+ border-radius: 4px;
13
+ }
14
+
15
+ // With zero spacing the items sit flush; drop their individual rounding and
16
+ // clip to the group so the background reads as one connected surface.
17
+ &.--connected {
18
+ overflow: hidden;
19
+
20
+ .g-contact__items {
21
+ gap: 0;
22
+ }
23
+
24
+ .i-contact {
25
+ border-radius: 0;
26
+ }
27
+ }
9
28
  }
10
29
  }
11
30
 
@@ -1,17 +1,42 @@
1
1
  import {InnerBlocks} from '@wordpress/block-editor'
2
2
  import type {BlockConfiguration} from '@wordpress/blocks'
3
3
  import {__} from '@wordpress/i18n'
4
- import type {NumberArray} from '~/types'
5
- import {CONTACT_COLUMNS, CONTACT_COLUMNS_CONTEXT, DEFAULT_SHADOWS} from './constants'
4
+ import {ITEM_SPACING_ATTRIBUTE} from '~/components/ItemSpacingControl'
5
+ import type {NumberArray, OptionArray} from '~/types'
6
+ import {
7
+ CONTACT_COLUMNS,
8
+ CONTACT_COLUMNS_CONTEXT,
9
+ CONTACT_STYLE_CONTEXT,
10
+ DEFAULT_DIRECTIONS,
11
+ DEFAULT_ICON_BACKGROUND_SHAPES,
12
+ DEFAULT_ICON_BACKGROUND_SIZE,
13
+ DEFAULT_ICON_SIZE,
14
+ DEFAULT_SHADOWS,
15
+ } from './constants'
6
16
  import {createContactGroupEdit} from './edit'
7
17
  import type {ContactGroupAttributes, ContactGroupOptions} from './types'
8
18
 
9
19
  export type {ContactGroupAttributes, ContactGroupOptions}
10
20
 
11
- export function createContactGroupBlock<TColumns extends NumberArray = typeof CONTACT_COLUMNS>(
12
- options: ContactGroupOptions<TColumns>,
13
- ): BlockConfiguration<ContactGroupAttributes<TColumns[number]>> {
21
+ export function createContactGroupBlock<
22
+ TColumns extends NumberArray = typeof CONTACT_COLUMNS,
23
+ TDirections extends OptionArray = typeof DEFAULT_DIRECTIONS,
24
+ TShadows extends OptionArray = typeof DEFAULT_SHADOWS,
25
+ TIconBackgroundShapes extends OptionArray = typeof DEFAULT_ICON_BACKGROUND_SHAPES,
26
+ >(
27
+ options: ContactGroupOptions<TColumns, TDirections, TShadows, TIconBackgroundShapes>,
28
+ ): BlockConfiguration<
29
+ ContactGroupAttributes<
30
+ TColumns[number],
31
+ TDirections[number]['value'],
32
+ TShadows[number]['value'],
33
+ TIconBackgroundShapes[number]['value']
34
+ >
35
+ > {
14
36
  const columns = options.columns ?? CONTACT_COLUMNS
37
+ const directions = options.directions ?? DEFAULT_DIRECTIONS
38
+ const shadows = options.shadows ?? DEFAULT_SHADOWS
39
+ const iconBackgroundShapes = options.iconBackgroundShapes ?? DEFAULT_ICON_BACKGROUND_SHAPES
15
40
 
16
41
  return {
17
42
  name: options.name,
@@ -21,19 +46,47 @@ export function createContactGroupBlock<TColumns extends NumberArray = typeof CO
21
46
  ...(options.parent && {parent: options.parent}),
22
47
  icon: options.icon ?? 'id-alt',
23
48
  supports: {html: false, customClassName: false},
24
- providesContext: {[CONTACT_COLUMNS_CONTEXT]: 'columns'},
49
+ providesContext: {
50
+ [CONTACT_COLUMNS_CONTEXT]: 'columns',
51
+ [CONTACT_STYLE_CONTEXT]: 'style',
52
+ },
25
53
  attributes: {
26
54
  columns: {
27
55
  type: 'number',
28
56
  default: columns[1] ?? columns[0],
29
57
  enum: [...columns],
30
58
  },
59
+ groupBackgroundColor: {type: 'string', default: ''},
31
60
  style: {
32
61
  type: 'object',
33
- default: {shadow: DEFAULT_SHADOWS[0].value, borderColor: '', backgroundColor: '', textColor: '', textAlign: 'left'},
62
+ default: {
63
+ shadow: shadows[0].value,
64
+ direction: directions[0].value,
65
+ textAlign: 'left',
66
+ borderColor: '',
67
+ backgroundColor: '',
68
+ textColor: '',
69
+ icon: {
70
+ size: DEFAULT_ICON_SIZE,
71
+ color: '',
72
+ background: '',
73
+ backgroundSize: DEFAULT_ICON_BACKGROUND_SIZE,
74
+ backgroundShape: iconBackgroundShapes[0].value,
75
+ borderColor: '',
76
+ borderWidth: 1,
77
+ },
78
+ },
34
79
  },
80
+ ...ITEM_SPACING_ATTRIBUTE,
35
81
  },
36
82
  edit: createContactGroupEdit(options as unknown as ContactGroupOptions),
37
83
  save: () => <InnerBlocks.Content />,
38
- } as unknown as BlockConfiguration<ContactGroupAttributes<TColumns[number]>>
84
+ } as unknown as BlockConfiguration<
85
+ ContactGroupAttributes<
86
+ TColumns[number],
87
+ TDirections[number]['value'],
88
+ TShadows[number]['value'],
89
+ TIconBackgroundShapes[number]['value']
90
+ >
91
+ >
39
92
  }
@@ -1,6 +1,14 @@
1
- export type {ContactColumns, ContactGroupAttributes, ContactGroupOptions} from './types'
1
+ export type {
2
+ ContactColumns,
3
+ ContactDirection,
4
+ ContactGroupAttributes,
5
+ ContactGroupOptions,
6
+ ContactIconBackgroundShape,
7
+ ContactShadow,
8
+ ContactTextAlign,
9
+ } from './types'
2
10
  export {createContactGroupBlock} from './factory'
3
- export {CONTACT_COLUMNS, CONTACT_COLUMNS_CONTEXT} from './constants'
11
+ export {CONTACT_COLUMNS, CONTACT_COLUMNS_CONTEXT, CONTACT_STYLE_CONTEXT} from './constants'
4
12
 
5
13
  import type {ContactGroupOptions} from './types'
6
14
 
@@ -1,23 +1,65 @@
1
- import type {BriloBlockType, NumberArray} from '~/types'
2
- import type {CONTACT_COLUMNS, DEFAULT_SHADOWS, TEXT_ALIGNS} from './constants'
1
+ import type {BriloBlockType, NumberArray, OptionArray} from '~/types'
2
+ import type {
3
+ CONTACT_COLUMNS,
4
+ DEFAULT_DIRECTIONS,
5
+ DEFAULT_ICON_BACKGROUND_SHAPES,
6
+ DEFAULT_SHADOWS,
7
+ TEXT_ALIGNS,
8
+ } from './constants'
3
9
 
4
10
  export type ContactColumns = (typeof CONTACT_COLUMNS)[number]
5
11
 
6
12
  export type ContactShadow = (typeof DEFAULT_SHADOWS)[number]['value']
7
13
 
14
+ export type ContactDirection = (typeof DEFAULT_DIRECTIONS)[number]['value']
15
+
8
16
  export type ContactTextAlign = (typeof TEXT_ALIGNS)[number]['value']
9
17
 
10
- export interface ContactGroupAttributes<TColumns extends number = ContactColumns> extends Record<string, unknown> {
18
+ export type ContactIconBackgroundShape = (typeof DEFAULT_ICON_BACKGROUND_SHAPES)[number]['value']
19
+
20
+ export interface ContactSizePreset {
21
+ value: number
22
+ label: string
23
+ }
24
+
25
+ export interface ContactGroupAttributes<
26
+ TColumns extends number = ContactColumns,
27
+ TDirection extends string = ContactDirection,
28
+ TShadow extends string = ContactShadow,
29
+ TIconBackgroundShape extends string = ContactIconBackgroundShape,
30
+ > extends Record<string, unknown> {
11
31
  columns: TColumns
32
+ groupBackgroundColor: string
12
33
  style: {
13
- shadow: ContactShadow
34
+ shadow: TShadow
35
+ direction: TDirection
36
+ textAlign: ContactTextAlign
14
37
  borderColor: string
15
38
  backgroundColor: string
16
39
  textColor: string
17
- textAlign: ContactTextAlign
40
+ icon: {
41
+ size: number
42
+ color: string
43
+ background: string
44
+ backgroundSize: number
45
+ backgroundShape: TIconBackgroundShape
46
+ borderColor: string
47
+ borderWidth: number
48
+ }
18
49
  }
50
+ spacing?: number
19
51
  }
20
52
 
21
- export interface ContactGroupOptions<TColumns extends NumberArray = typeof CONTACT_COLUMNS> extends BriloBlockType {
53
+ export interface ContactGroupOptions<
54
+ TColumns extends NumberArray = typeof CONTACT_COLUMNS,
55
+ TDirections extends OptionArray = typeof DEFAULT_DIRECTIONS,
56
+ TShadows extends OptionArray = typeof DEFAULT_SHADOWS,
57
+ TIconBackgroundShapes extends OptionArray = typeof DEFAULT_ICON_BACKGROUND_SHAPES,
58
+ > extends BriloBlockType {
22
59
  columns?: TColumns
60
+ directions?: TDirections
61
+ shadows?: TShadows
62
+ iconSizePresets?: readonly ContactSizePreset[]
63
+ iconBackgroundSizePresets?: readonly ContactSizePreset[]
64
+ iconBackgroundShapes?: TIconBackgroundShapes
23
65
  }
@@ -0,0 +1,69 @@
1
+ import clsx from 'clsx'
2
+
3
+ export interface ContactSharedStyle {
4
+ direction?: string
5
+ textAlign?: string
6
+ shadow?: string
7
+ borderColor?: string
8
+ backgroundColor?: string
9
+ textColor?: string
10
+ icon?: {
11
+ size?: number
12
+ color?: string
13
+ background?: string
14
+ backgroundSize?: number
15
+ backgroundShape?: string
16
+ borderColor?: string
17
+ borderWidth?: number
18
+ }
19
+ }
20
+
21
+ export interface ContactPreviewStyle {
22
+ rootClassName: string
23
+ iconClassName: string
24
+ cssVars: Record<string, string>
25
+ }
26
+
27
+ export function buildContactPreviewStyle(
28
+ shared?: ContactSharedStyle,
29
+ resolveHex: (value: string) => string = (value) => value,
30
+ ): ContactPreviewStyle {
31
+ if (!shared) {
32
+ return {rootClassName: '', iconClassName: '', cssVars: {}}
33
+ }
34
+
35
+ const icon = shared.icon ?? {}
36
+
37
+ const rootClassName = clsx(
38
+ shared.direction && `--direction-${shared.direction}`,
39
+ shared.textAlign && `--align-${shared.textAlign}`,
40
+ shared.shadow && shared.shadow !== 'none' && `--shadow --shadow-${shared.shadow}`,
41
+ icon.background && icon.background !== 'none' && '--icon-background',
42
+ icon.color && icon.color !== 'none' && '--icon-color',
43
+ icon.borderColor && '--icon-bordered',
44
+ shared.backgroundColor && '--background-color',
45
+ shared.borderColor && '--border',
46
+ shared.textColor && '--text-color',
47
+ )
48
+
49
+ const iconClassName = clsx(
50
+ icon.backgroundShape && icon.backgroundShape !== 'none' && `--background-shape --background-shape-${icon.backgroundShape}`,
51
+ )
52
+
53
+ const cssVars: Record<string, string> = {}
54
+ if (shared.borderColor) cssVars['--border-color'] = resolveHex(shared.borderColor)
55
+ if (shared.backgroundColor) cssVars['--background-color'] = resolveHex(shared.backgroundColor)
56
+ if (shared.textColor) cssVars['--text-color'] = resolveHex(shared.textColor)
57
+ if (icon.background && icon.background !== 'none') cssVars['--icon-background-color'] = resolveHex(icon.background)
58
+ if (icon.color && icon.color !== 'none') cssVars['--icon-color'] = resolveHex(icon.color)
59
+ if (icon.size) cssVars['--icon-size'] = `${icon.size}px`
60
+ if (icon.background && icon.background !== 'none' && icon.backgroundSize) {
61
+ cssVars['--icon-background-size'] = `${icon.backgroundSize}px`
62
+ }
63
+ if (icon.borderColor) {
64
+ cssVars['--icon-outline-color'] = resolveHex(icon.borderColor)
65
+ cssVars['--icon-outline-width'] = `${icon.borderWidth || 1}px`
66
+ }
67
+
68
+ return {rootClassName, iconClassName, cssVars}
69
+ }