@webikon/webentor-core 0.9.12

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 (132) hide show
  1. package/.husky/pre-commit +40 -0
  2. package/.prettierrc.js +5 -0
  3. package/CHANGELOG.md +88 -0
  4. package/LICENCE.md +7 -0
  5. package/README.md +26 -0
  6. package/core-js/_alpine.ts +20 -0
  7. package/core-js/_slider.ts +232 -0
  8. package/core-js/_utils.ts +126 -0
  9. package/core-js/blocks-components/block-appender.tsx +36 -0
  10. package/core-js/blocks-components/button.tsx +424 -0
  11. package/core-js/blocks-components/custom-image-sizes-panel.tsx +197 -0
  12. package/core-js/blocks-components/index.ts +4 -0
  13. package/core-js/blocks-components/typography-picker-select.tsx +31 -0
  14. package/core-js/blocks-filters/_filter-core-typography.tsx +108 -0
  15. package/core-js/blocks-filters/_slider-settings.tsx +283 -0
  16. package/core-js/blocks-filters/index.ts +3 -0
  17. package/core-js/blocks-filters/responsive-settings/components/DisabledSliderInfo.tsx +10 -0
  18. package/core-js/blocks-filters/responsive-settings/constants.ts +11 -0
  19. package/core-js/blocks-filters/responsive-settings/index.tsx +196 -0
  20. package/core-js/blocks-filters/responsive-settings/settings/block-link/index.ts +1 -0
  21. package/core-js/blocks-filters/responsive-settings/settings/block-link/panel.tsx +47 -0
  22. package/core-js/blocks-filters/responsive-settings/settings/border/border/index.tsx +1 -0
  23. package/core-js/blocks-filters/responsive-settings/settings/border/border/properties.ts +27 -0
  24. package/core-js/blocks-filters/responsive-settings/settings/border/border/settings.tsx +310 -0
  25. package/core-js/blocks-filters/responsive-settings/settings/border/border-radius/index.tsx +1 -0
  26. package/core-js/blocks-filters/responsive-settings/settings/border/border-radius/properties.ts +31 -0
  27. package/core-js/blocks-filters/responsive-settings/settings/border/border-radius/settings.tsx +211 -0
  28. package/core-js/blocks-filters/responsive-settings/settings/border/index.ts +1 -0
  29. package/core-js/blocks-filters/responsive-settings/settings/border/panel.tsx +54 -0
  30. package/core-js/blocks-filters/responsive-settings/settings/container/display/index.ts +2 -0
  31. package/core-js/blocks-filters/responsive-settings/settings/container/display/properties.ts +167 -0
  32. package/core-js/blocks-filters/responsive-settings/settings/container/display/settings.tsx +73 -0
  33. package/core-js/blocks-filters/responsive-settings/settings/container/flexbox/index.ts +2 -0
  34. package/core-js/blocks-filters/responsive-settings/settings/container/flexbox/properties.ts +187 -0
  35. package/core-js/blocks-filters/responsive-settings/settings/container/flexbox/settings.tsx +131 -0
  36. package/core-js/blocks-filters/responsive-settings/settings/container/grid/index.ts +2 -0
  37. package/core-js/blocks-filters/responsive-settings/settings/container/grid/properties.ts +187 -0
  38. package/core-js/blocks-filters/responsive-settings/settings/container/grid/settings.tsx +132 -0
  39. package/core-js/blocks-filters/responsive-settings/settings/container/index.ts +4 -0
  40. package/core-js/blocks-filters/responsive-settings/settings/container/panel.tsx +92 -0
  41. package/core-js/blocks-filters/responsive-settings/settings/spacing/index.ts +3 -0
  42. package/core-js/blocks-filters/responsive-settings/settings/spacing/panel.tsx +45 -0
  43. package/core-js/blocks-filters/responsive-settings/settings/spacing/properties.ts +74 -0
  44. package/core-js/blocks-filters/responsive-settings/settings/spacing/settings.tsx +85 -0
  45. package/core-js/blocks-filters/responsive-settings/types/index.ts +68 -0
  46. package/core-js/blocks-filters/responsive-settings/utils.ts +321 -0
  47. package/core-js/blocks-utils/_use-block-parent.ts +27 -0
  48. package/core-js/blocks-utils/_use-post-types.ts +43 -0
  49. package/core-js/blocks-utils/_use-taxonomies.ts +29 -0
  50. package/core-js/blocks-utils/index.ts +3 -0
  51. package/core-js/config/webentor-config.ts +718 -0
  52. package/core-js/index.ts +14 -0
  53. package/core-js/types/_block-components.ts +7 -0
  54. package/core-js/types/_webentor-config.ts +182 -0
  55. package/package.json +98 -0
  56. package/resources/blocks/e-accordion/block.json +34 -0
  57. package/resources/blocks/e-accordion/e-accordion.block.tsx +125 -0
  58. package/resources/blocks/e-accordion/script.ts +1 -0
  59. package/resources/blocks/e-accordion/style.css +8 -0
  60. package/resources/blocks/e-accordion-group/block.json +56 -0
  61. package/resources/blocks/e-accordion-group/e-accordion-group.block.tsx +99 -0
  62. package/resources/blocks/e-breadcrumbs/block.json +41 -0
  63. package/resources/blocks/e-breadcrumbs/e-breadcrumbs.block.tsx +53 -0
  64. package/resources/blocks/e-button/block.json +32 -0
  65. package/resources/blocks/e-button/e-button.block.tsx +55 -0
  66. package/resources/blocks/e-gallery/block.json +90 -0
  67. package/resources/blocks/e-gallery/e-gallery.block.tsx +316 -0
  68. package/resources/blocks/e-icon-picker/block.json +37 -0
  69. package/resources/blocks/e-icon-picker/e-icon-picker.block.tsx +230 -0
  70. package/resources/blocks/e-icon-picker/style.css +17 -0
  71. package/resources/blocks/e-image/block.json +78 -0
  72. package/resources/blocks/e-image/e-image.block.tsx +331 -0
  73. package/resources/blocks/e-picker-query-loop/block.json +25 -0
  74. package/resources/blocks/e-picker-query-loop/e-picker-query-loop.block.tsx +189 -0
  75. package/resources/blocks/e-post-template/block.json +25 -0
  76. package/resources/blocks/e-post-template/e-post-template.block.tsx +100 -0
  77. package/resources/blocks/e-query-loop/block.json +36 -0
  78. package/resources/blocks/e-query-loop/constants.tsx +8 -0
  79. package/resources/blocks/e-query-loop/e-query-loop.block.tsx +270 -0
  80. package/resources/blocks/e-query-loop/taxonomy-controls.tsx +184 -0
  81. package/resources/blocks/e-slider/block.json +42 -0
  82. package/resources/blocks/e-slider/e-slider.block.tsx +100 -0
  83. package/resources/blocks/e-svg/block.json +37 -0
  84. package/resources/blocks/e-svg/e-svg.block.tsx +156 -0
  85. package/resources/blocks/e-tab-container/block.json +49 -0
  86. package/resources/blocks/e-tab-container/e-tab-container.block.tsx +123 -0
  87. package/resources/blocks/e-table/block.json +30 -0
  88. package/resources/blocks/e-table/e-table.block.tsx +120 -0
  89. package/resources/blocks/e-table/script.ts +48 -0
  90. package/resources/blocks/e-table-cell/block.json +40 -0
  91. package/resources/blocks/e-table-cell/e-table-cell.block.tsx +180 -0
  92. package/resources/blocks/e-table-row/block.json +28 -0
  93. package/resources/blocks/e-table-row/e-table-row.block.tsx +118 -0
  94. package/resources/blocks/e-tabs/block.json +27 -0
  95. package/resources/blocks/e-tabs/e-tabs.block.tsx +90 -0
  96. package/resources/blocks/l-404/block.json +51 -0
  97. package/resources/blocks/l-404/l-404.block.tsx +75 -0
  98. package/resources/blocks/l-flexible-container/block.json +34 -0
  99. package/resources/blocks/l-flexible-container/l-flexible-container.block.tsx +97 -0
  100. package/resources/blocks/l-footer/block.json +23 -0
  101. package/resources/blocks/l-footer/l-footer.block.tsx +51 -0
  102. package/resources/blocks/l-formatted-content/block.json +28 -0
  103. package/resources/blocks/l-formatted-content/l-formatted-content.block.tsx +97 -0
  104. package/resources/blocks/l-header/block.json +26 -0
  105. package/resources/blocks/l-header/l-header.block.tsx +100 -0
  106. package/resources/blocks/l-mobile-nav/block.json +15 -0
  107. package/resources/blocks/l-mobile-nav/l-mobile-nav.block.tsx +56 -0
  108. package/resources/blocks/l-mobile-nav/style.css +54 -0
  109. package/resources/blocks/l-nav-menu/block.json +27 -0
  110. package/resources/blocks/l-nav-menu/l-nav-menu.block.tsx +109 -0
  111. package/resources/blocks/l-nav-menu/style.css +134 -0
  112. package/resources/blocks/l-post-card/block.json +13 -0
  113. package/resources/blocks/l-post-card/l-post-card.block.tsx +52 -0
  114. package/resources/blocks/l-section/block.json +89 -0
  115. package/resources/blocks/l-section/l-section.block.tsx +316 -0
  116. package/resources/blocks/l-site-logo/block.json +15 -0
  117. package/resources/blocks/l-site-logo/l-site-logo.block.tsx +54 -0
  118. package/resources/core-components/slider/slider.script.ts +11 -0
  119. package/resources/core-components/slider/slider.style.css +134 -0
  120. package/resources/scripts/editor.ts +29 -0
  121. package/resources/styles/app.css +21 -0
  122. package/resources/styles/common/_editor.css +86 -0
  123. package/resources/styles/common/_form.css +83 -0
  124. package/resources/styles/common/_global.css +73 -0
  125. package/resources/styles/common/_theme.css +75 -0
  126. package/resources/styles/common/_utilities.css +33 -0
  127. package/resources/styles/common/_wordpress.css +110 -0
  128. package/resources/styles/components/_table.css +102 -0
  129. package/resources/styles/editor.css +16 -0
  130. package/resources/styles/partials/.gitkeep +0 -0
  131. package/resources/styles/partials/_header.css +21 -0
  132. package/resources/styles/partials/_pagination.css +35 -0
@@ -0,0 +1,189 @@
1
+ import { ContentPicker } from '@10up/block-components';
2
+ import {
3
+ InnerBlocks,
4
+ InspectorControls,
5
+ useBlockProps,
6
+ useInnerBlocksProps,
7
+ } from '@wordpress/block-editor';
8
+ import {
9
+ BlockEditProps,
10
+ registerBlockType,
11
+ TemplateArray,
12
+ } from '@wordpress/blocks';
13
+ import {
14
+ Notice,
15
+ PanelBody,
16
+ SelectControl,
17
+ TextControl,
18
+ } from '@wordpress/components';
19
+ import { applyFilters } from '@wordpress/hooks';
20
+ import { __ } from '@wordpress/i18n';
21
+
22
+ import { useBlockParent } from '@webentorCore/blocks-utils/_use-block-parent';
23
+ import { usePostTypes } from '@webentorCore/blocks-utils/_use-post-types';
24
+
25
+ import block from './block.json';
26
+
27
+ /**
28
+ * Edit component.
29
+ * See https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-edit-save/#edit
30
+ *
31
+ * @param {object} props The block props.
32
+ * @returns {Function} Render the edit screen
33
+ */
34
+
35
+ type AttributesType = {
36
+ coverImage: string;
37
+ query: {
38
+ postType: string[];
39
+ posts: [];
40
+ queryId: string;
41
+ };
42
+ template?: TemplateArray;
43
+ };
44
+
45
+ const BlockEdit: React.FC<BlockEditProps<AttributesType>> = (props) => {
46
+ const { attributes, setAttributes } = props;
47
+ const { query } = attributes;
48
+ const { postType, posts, queryId } = query;
49
+
50
+ const blockProps = useBlockProps();
51
+ const parentBlockProps = useBlockParent();
52
+
53
+ /**
54
+ * Filter allowed blocks used in webentor/e-query-loop inner block
55
+ */
56
+ const allowedBlocks = applyFilters(
57
+ 'webentor.core.e-picker-query-loop.allowedBlocks',
58
+ // Allow only singular 'e-post-template' block to be added as child.
59
+ ['webentor/e-post-template'],
60
+ blockProps,
61
+ parentBlockProps,
62
+ ) as string[];
63
+
64
+ /**
65
+ * Filter template used in webentor/e-query-loop inner block
66
+ */
67
+ const defaultTemplate: TemplateArray = attributes?.template ?? [
68
+ ['webentor/e-post-template', ['webentor/l-post-card']],
69
+ ];
70
+ const template = applyFilters(
71
+ 'webentor.core.e-picker-query-loop.template',
72
+ defaultTemplate,
73
+ blockProps,
74
+ parentBlockProps,
75
+ ) as TemplateArray;
76
+
77
+ const { children, ...innerBlocksProps } = useInnerBlocksProps(blockProps, {
78
+ allowedBlocks,
79
+ template,
80
+ templateLock: 'all',
81
+ });
82
+
83
+ const { postTypesSelectOptions } = usePostTypes();
84
+
85
+ const setQuery = (newQuery) =>
86
+ setAttributes({ query: { ...query, ...newQuery } });
87
+
88
+ const onPostTypeChange = (newValue) => {
89
+ const updateQuery = { postType: newValue };
90
+
91
+ setQuery(updateQuery);
92
+ };
93
+
94
+ // Preview image for block inserter
95
+ if (attributes.coverImage) {
96
+ return <img src={attributes.coverImage} width="468" />;
97
+ }
98
+
99
+ return (
100
+ <>
101
+ <InspectorControls>
102
+ <PanelBody title="Loop Settings" initialOpen={true}>
103
+ {/* TODO: Maybe rework to nicer UI */}
104
+ <SelectControl
105
+ __nextHasNoMarginBottom
106
+ options={postTypesSelectOptions}
107
+ value={Array.isArray(postType) ? postType : [postType]}
108
+ label={__('Post type')}
109
+ multiple
110
+ onChange={onPostTypeChange}
111
+ help={__(
112
+ 'First select post type(s) from which you would be able to pick posts',
113
+ 'webentor',
114
+ )}
115
+ />
116
+
117
+ <div className="wbtr:mb-3 wbtr:w-full wbtr:border wbtr:border-editor-border wbtr:p-2">
118
+ <p>
119
+ {__('Posts which would be displayed in the loop', 'webentor')}
120
+ </p>
121
+ {postType?.length > 0 ? (
122
+ <ContentPicker
123
+ onPickChange={(pickedContent) => {
124
+ setQuery({
125
+ posts: pickedContent,
126
+ });
127
+ }}
128
+ content={posts || []}
129
+ mode="post"
130
+ maxContentItems={20}
131
+ isOrderable
132
+ label={__('Select posts', 'webentor')}
133
+ contentTypes={Array.isArray(postType) ? postType : [postType]}
134
+ />
135
+ ) : (
136
+ <Notice status="error" isDismissible={false}>
137
+ {__(
138
+ 'Post type selection is required to select posts',
139
+ 'webentor',
140
+ )}
141
+ </Notice>
142
+ )}
143
+ </div>
144
+
145
+ <TextControl
146
+ label={__('Query ID', 'webentor')}
147
+ value={queryId}
148
+ onChange={(value) => {
149
+ setQuery({
150
+ queryId: value,
151
+ });
152
+ }}
153
+ help={__(
154
+ 'This can be used to filter query params via `webentor/query_loop_args` hook.',
155
+ )}
156
+ />
157
+ </PanelBody>
158
+ </InspectorControls>
159
+
160
+ <div
161
+ {...innerBlocksProps}
162
+ className={`${innerBlocksProps.className} wbtr:relative wbtr:p-2 wbtr:pt-4`}
163
+ >
164
+ <div className="wbtr:pointer-events-none wbtr:absolute wbtr:inset-0 wbtr:h-full wbtr:w-full wbtr:border wbtr:border-editor-border wbtr:p-2 wbtr:pt-4"></div>
165
+
166
+ <div className="wbtr:absolute wbtr:top-[2px] wbtr:left-2 wbtr:mb-1 wbtr:text-10 wbtr:opacity-50">
167
+ {__('Picker Query Loop', 'webentor')}
168
+ </div>
169
+
170
+ {children}
171
+ </div>
172
+ </>
173
+ );
174
+ };
175
+
176
+ /**
177
+ * See https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-edit-save/#save
178
+ *
179
+ * @return {null} Dynamic blocks do not save the HTML.
180
+ */
181
+ const BlockSave = () => <InnerBlocks.Content />;
182
+
183
+ /**
184
+ * Register block.
185
+ */
186
+ registerBlockType(block, {
187
+ edit: BlockEdit,
188
+ save: BlockSave,
189
+ });
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "../../../schemas/webentor-block.json",
3
+ "apiVersion": 3,
4
+ "name": "webentor/e-post-template",
5
+ "title": "Webentor Post Template",
6
+ "description": "Post template used in Webentor Query Loop.",
7
+ "category": "webentor-elements",
8
+ "icon": "layout",
9
+ "keywords": ["query"],
10
+ "attributes": {
11
+ "template": {
12
+ "type": "array",
13
+ "default": null
14
+ }
15
+ },
16
+ "example": {
17
+ "attributes": {
18
+ "mode": "preview",
19
+ "data": {
20
+ "preview_image_help": true
21
+ }
22
+ }
23
+ },
24
+ "supports": {}
25
+ }
@@ -0,0 +1,100 @@
1
+ import {
2
+ InnerBlocks,
3
+ useBlockProps,
4
+ useInnerBlocksProps,
5
+ } from '@wordpress/block-editor';
6
+ import {
7
+ BlockEditProps,
8
+ registerBlockType,
9
+ TemplateArray,
10
+ } from '@wordpress/blocks';
11
+ import { applyFilters } from '@wordpress/hooks';
12
+ import { __ } from '@wordpress/i18n';
13
+
14
+ import { useBlockParent } from '@webentorCore/blocks-utils/_use-block-parent';
15
+
16
+ import block from './block.json';
17
+
18
+ /**
19
+ * Edit component.
20
+ * See https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-edit-save/#edit
21
+ *
22
+ * @param {object} props The block props.
23
+ * @returns {Function} Render the edit screen
24
+ */
25
+
26
+ type AttributesType = {
27
+ coverImage: string;
28
+ template?: TemplateArray;
29
+ };
30
+
31
+ const BlockEdit: React.FC<BlockEditProps<AttributesType>> = (props) => {
32
+ const { attributes } = props;
33
+
34
+ const blockProps = useBlockProps();
35
+ const parentBlockProps = useBlockParent();
36
+
37
+ /**
38
+ * Filter allowed blocks used in webentor/e-post-template inner block
39
+ */
40
+ const allowedBlocks: string[] = applyFilters(
41
+ 'webentor.core.e-post-template.allowedBlocks',
42
+ ['webentor/l-post-card'],
43
+ blockProps,
44
+ parentBlockProps,
45
+ );
46
+
47
+ /**
48
+ * Filter template used in webentor/e-post-template inner block
49
+ */
50
+ const defaultTemplate: TemplateArray = attributes?.template ?? [
51
+ ['webentor/l-post-card'],
52
+ ];
53
+ const template: TemplateArray = applyFilters(
54
+ 'webentor.core.e-post-template.template',
55
+ defaultTemplate,
56
+ blockProps,
57
+ parentBlockProps,
58
+ );
59
+
60
+ const { children, ...innerBlocksProps } = useInnerBlocksProps(blockProps, {
61
+ allowedBlocks,
62
+ template,
63
+ templateLock: false,
64
+ });
65
+
66
+ // Preview image for block inserter
67
+ if (attributes.coverImage) {
68
+ return <img src={attributes.coverImage} width="468" />;
69
+ }
70
+
71
+ return (
72
+ <div
73
+ {...innerBlocksProps}
74
+ className={`${innerBlocksProps.className} wbtr:relative wbtr:p-2 wbtr:pt-4`}
75
+ >
76
+ <div className="wbtr:pointer-events-none wbtr:absolute wbtr:inset-0 wbtr:h-full wbtr:w-full wbtr:border wbtr:border-editor-border wbtr:p-2 wbtr:pt-4"></div>
77
+
78
+ <div className="wbtr:absolute wbtr:top-[2px] wbtr:left-2 wbtr:mb-1 wbtr:text-10 wbtr:opacity-50">
79
+ {__('Post Template', 'webentor')}
80
+ </div>
81
+
82
+ {children}
83
+ </div>
84
+ );
85
+ };
86
+
87
+ /**
88
+ * See https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-edit-save/#save
89
+ *
90
+ * @return {null} Dynamic blocks do not save the HTML.
91
+ */
92
+ const BlockSave = () => <InnerBlocks.Content />;
93
+
94
+ /**
95
+ * Register block.
96
+ */
97
+ registerBlockType(block, {
98
+ edit: BlockEdit,
99
+ save: BlockSave,
100
+ });
@@ -0,0 +1,36 @@
1
+ {
2
+ "$schema": "../../../schemas/webentor-block.json",
3
+ "apiVersion": 3,
4
+ "name": "webentor/e-query-loop",
5
+ "title": "Webentor Query Loop",
6
+ "description": "Display posts in a loop with various query configuration. Don't work with pagination yet!",
7
+ "category": "webentor-elements",
8
+ "icon": "update",
9
+ "keywords": ["loop", "query", "slider"],
10
+ "attributes": {
11
+ "query": {
12
+ "type": "object",
13
+ "default": {
14
+ "perPage": null,
15
+ "pages": 0,
16
+ "offset": 0,
17
+ "postType": ["post"],
18
+ "order": "desc",
19
+ "orderBy": "date",
20
+ "author": "",
21
+ "search": "",
22
+ "exclude": [],
23
+ "sticky": "",
24
+ "inherit": true,
25
+ "taxQuery": null,
26
+ "parents": [],
27
+ "queryId": ""
28
+ }
29
+ },
30
+ "template": {
31
+ "type": "array",
32
+ "default": null
33
+ }
34
+ },
35
+ "supports": {}
36
+ }
@@ -0,0 +1,8 @@
1
+ // The following dropdown menu props aim to provide a consistent offset and
2
+ // placement for ToolsPanel menus for block controls to match color popovers.
3
+ export const TOOLSPANEL_DROPDOWNMENU_PROPS = {
4
+ popoverProps: {
5
+ placement: 'left-start',
6
+ offset: 259, // Inner sidebar width (248px) - button width (24px) - border (1px) + padding (16px) + spacing (20px)
7
+ },
8
+ };
@@ -0,0 +1,270 @@
1
+ import {
2
+ InnerBlocks,
3
+ InspectorControls,
4
+ useBlockProps,
5
+ useInnerBlocksProps,
6
+ } from '@wordpress/block-editor';
7
+ import {
8
+ BlockEditProps,
9
+ registerBlockType,
10
+ TemplateArray,
11
+ } from '@wordpress/blocks';
12
+ import {
13
+ __experimentalNumberControl as NumberControl,
14
+ PanelBody,
15
+ SelectControl,
16
+ TextControl,
17
+ __experimentalToolsPanel as ToolsPanel,
18
+ __experimentalToolsPanelItem as ToolsPanelItem,
19
+ } from '@wordpress/components';
20
+ import { applyFilters } from '@wordpress/hooks';
21
+ import { __ } from '@wordpress/i18n';
22
+
23
+ import { useBlockParent } from '@webentorCore/blocks-utils/_use-block-parent';
24
+ import { usePostTypes } from '@webentorCore/blocks-utils/_use-post-types';
25
+
26
+ import block from './block.json';
27
+ import { TOOLSPANEL_DROPDOWNMENU_PROPS } from './constants';
28
+ import { TaxonomyControls } from './taxonomy-controls';
29
+
30
+ /**
31
+ * Edit component.
32
+ * See https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-edit-save/#edit
33
+ *
34
+ * @param {object} props The block props.
35
+ * @returns {Function} Render the edit screen
36
+ */
37
+
38
+ type AttributesType = {
39
+ coverImage: string;
40
+ query: {
41
+ perPage: number;
42
+ postType: string[];
43
+ queryId: string;
44
+ taxQuery: Record<string, string[]>;
45
+ parents: number[];
46
+ };
47
+ template?: TemplateArray;
48
+ };
49
+
50
+ const BlockEdit: React.FC<BlockEditProps<AttributesType>> = (props) => {
51
+ const { attributes, setAttributes } = props;
52
+ const { query } = attributes;
53
+ const {
54
+ // order,
55
+ // orderBy,
56
+ // author: authorIds,
57
+ postType,
58
+ // sticky,
59
+ // inherit,
60
+ taxQuery,
61
+ // parents,
62
+ } = query;
63
+
64
+ const blockProps = useBlockProps();
65
+ const parentBlockProps = useBlockParent();
66
+
67
+ /**
68
+ * Filter allowed blocks used in webentor/e-query-loop inner block
69
+ */
70
+ const allowedBlocks: string[] = applyFilters(
71
+ 'webentor.core.e-query-loop.allowedBlocks',
72
+ // Allow only singular 'e-post-template' block to be added as child.
73
+ ['webentor/e-post-template'],
74
+ blockProps,
75
+ parentBlockProps,
76
+ );
77
+
78
+ /**
79
+ * Filter template used in webentor/e-query-loop inner block
80
+ */
81
+ const defaultTemplate: TemplateArray = attributes?.template ?? [
82
+ ['webentor/e-post-template', ['webentor/l-post-card']],
83
+ ];
84
+ const template: TemplateArray = applyFilters(
85
+ 'webentor.core.e-query-loop.template',
86
+ defaultTemplate,
87
+ blockProps,
88
+ parentBlockProps,
89
+ );
90
+
91
+ const { children, ...innerBlocksProps } = useInnerBlocksProps(blockProps, {
92
+ allowedBlocks,
93
+ template,
94
+ templateLock: 'all',
95
+ });
96
+
97
+ const { postTypesTaxonomiesMap, postTypesSelectOptions } = usePostTypes();
98
+
99
+ // TODO: add settings for these
100
+ const showTaxControl = true;
101
+ // const showAuthorControl = false;
102
+ // const showSearchControl = false;
103
+
104
+ const setQuery = (newQuery) =>
105
+ setAttributes({ query: { ...query, ...newQuery } });
106
+
107
+ const onPostTypeChange = (newValue) => {
108
+ // Taxonomies are supported only for single post type, so we need to handle that
109
+ const singlePostType =
110
+ Array.isArray(newValue) && newValue.length === 1 ? newValue[0] : newValue;
111
+
112
+ const updateQuery = { postType: singlePostType };
113
+ // We need to dynamically update the `taxQuery` property,
114
+ // by removing any not supported taxonomy from the query.
115
+ const supportedTaxonomies = postTypesTaxonomiesMap[singlePostType];
116
+ const updatedTaxQuery = Object.entries(taxQuery || {}).reduce(
117
+ (accumulator, [taxonomySlug, terms]) => {
118
+ if (supportedTaxonomies.includes(taxonomySlug)) {
119
+ accumulator[taxonomySlug] = terms;
120
+ }
121
+ return accumulator;
122
+ },
123
+ {},
124
+ );
125
+ updateQuery.taxQuery = Object.keys(updatedTaxQuery).length
126
+ ? updatedTaxQuery
127
+ : undefined;
128
+
129
+ if (singlePostType !== 'post') {
130
+ updateQuery.sticky = '';
131
+ }
132
+ // We need to reset `parents` because they are tied to each post type.
133
+ updateQuery.parents = [];
134
+ setQuery(updateQuery);
135
+ };
136
+
137
+ // Preview image for block inserter
138
+ if (attributes.coverImage) {
139
+ return <img src={attributes.coverImage} width="468" />;
140
+ }
141
+
142
+ return (
143
+ <>
144
+ <InspectorControls>
145
+ <PanelBody title="Loop Settings" initialOpen={true}>
146
+ <NumberControl
147
+ label={__('Posts Per Page', 'webentor')}
148
+ min={1}
149
+ max={20}
150
+ step="1"
151
+ value={query.perPage}
152
+ onChange={(value) => {
153
+ if (isNaN(value) || value < 1 || value > 100) {
154
+ return;
155
+ }
156
+ setQuery({
157
+ perPage: value,
158
+ });
159
+ }}
160
+ />
161
+
162
+ <SelectControl
163
+ __nextHasNoMarginBottom
164
+ options={postTypesSelectOptions}
165
+ value={Array.isArray(postType) ? postType : [postType]}
166
+ label={__('Post type')}
167
+ multiple
168
+ onChange={onPostTypeChange}
169
+ help={__(
170
+ 'WordPress contains different types of content and they are divided into collections called “Post types”. By default there are a few different ones such as blog posts and pages, but plugins could add more.',
171
+ )}
172
+ />
173
+
174
+ <TextControl
175
+ label={__('Query ID', 'webentor')}
176
+ value={query.queryId}
177
+ onChange={(value) => {
178
+ setQuery({
179
+ queryId: value,
180
+ });
181
+ }}
182
+ help={__(
183
+ 'This can be used to filter query params via `webentor/query_loop_args` hook.',
184
+ )}
185
+ />
186
+ </PanelBody>
187
+
188
+ <ToolsPanel
189
+ className="block-library-query-toolspanel__filters"
190
+ label={__('Filters')}
191
+ resetAll={() => {
192
+ setQuery({
193
+ author: '',
194
+ parents: [],
195
+ search: '',
196
+ taxQuery: null,
197
+ });
198
+ // setQuerySearch('');
199
+ }}
200
+ dropdownMenuProps={TOOLSPANEL_DROPDOWNMENU_PROPS}
201
+ >
202
+ {showTaxControl && !Array.isArray(query.postType) && (
203
+ <ToolsPanelItem
204
+ label={__('Taxonomies')}
205
+ hasValue={() =>
206
+ Object.values(taxQuery || {}).some((terms) => !!terms.length)
207
+ }
208
+ onDeselect={() => setQuery({ taxQuery: null })}
209
+ >
210
+ <TaxonomyControls onChange={setQuery} query={query} />
211
+ </ToolsPanelItem>
212
+ )}
213
+
214
+ {/* {showAuthorControl && (
215
+ <ToolsPanelItem
216
+ hasValue={() => !!authorIds}
217
+ label={__('Authors')}
218
+ onDeselect={() => setQuery({ author: '' })}
219
+ >
220
+ <AuthorControl value={authorIds} onChange={setQuery} />
221
+ </ToolsPanelItem>
222
+ )} */}
223
+
224
+ {/* {showSearchControl && (
225
+ <ToolsPanelItem
226
+ hasValue={() => !!querySearch}
227
+ label={__('Keyword')}
228
+ onDeselect={() => setQuerySearch('')}
229
+ >
230
+ <TextControl
231
+ __nextHasNoMarginBottom
232
+ label={__('Keyword')}
233
+ value={querySearch}
234
+ onChange={setQuerySearch}
235
+ />
236
+ </ToolsPanelItem>
237
+ )} */}
238
+ </ToolsPanel>
239
+ </InspectorControls>
240
+
241
+ <div
242
+ {...innerBlocksProps}
243
+ className={`${innerBlocksProps.className} wbtr:relative wbtr:p-2 wbtr:pt-4`}
244
+ >
245
+ <div className="wbtr:pointer-events-none wbtr:absolute wbtr:inset-0 wbtr:h-full wbtr:w-full wbtr:border wbtr:border-editor-border wbtr:p-2 wbtr:pt-4"></div>
246
+
247
+ <div className="wbtr:absolute wbtr:top-[2px] wbtr:left-2 wbtr:mb-1 wbtr:text-10 wbtr:opacity-50">
248
+ {__('Query Loop', 'webentor')}
249
+ </div>
250
+
251
+ {children}
252
+ </div>
253
+ </>
254
+ );
255
+ };
256
+
257
+ /**
258
+ * See https://wordpress.org/gutenberg/handbook/designers-developers/developers/block-api/block-edit-save/#save
259
+ *
260
+ * @return {null} Dynamic blocks do not save the HTML.
261
+ */
262
+ const BlockSave = () => <InnerBlocks.Content />;
263
+
264
+ /**
265
+ * Register block.
266
+ */
267
+ registerBlockType(block, {
268
+ edit: BlockEdit,
269
+ save: BlockSave,
270
+ });