PluginProbe ʕ •ᴥ•ʔ
VK Blocks / trunk
VK Blocks vtrunk
1.123.0 1.122.0 1.121.0 1.120.0 1.119.2 1.119.1 1.119.0 1.118.7 1.82.0.0 1.82.0.1 1.83.0.0 1.83.0.1 1.84.0.0 1.84.0.1 1.85.0.2 1.85.0.3 1.85.1.0 1.85.1.1 1.86.0.0 1.86.0.1 1.86.1.0 1.87.0.0 1.87.0.1 1.88.0.1 1.88.0.2 1.89.0.0 1.9.2 1.90.0.0 1.90.0.1 1.90.1.1 1.91.0.0 1.91.1.1 1.92.0.0 1.92.0.1 1.92.1.0 1.92.1.1 1.93.0.0 trunk 1.93.0.1 0.1.1 1.93.1.0 0.10.3 1.93.1.1 0.11.0 1.94.0.0 0.12.6 1.94.0.1 0.15.1 1.94.1.0 0.16.2 1.94.2.1 0.17.6 1.94.2.2 0.2.2 1.95.0.3 0.22.4 1.95.0.4 0.26.7 1.96.2.0 0.3.2 1.96.2.1 0.31.0 1.97.0.1 0.35.5 1.97.0.2 0.37.5 1.99.0.0 0.38.8 1.99.0.1 0.39.4 0.4.7 0.41.0 0.42.0 0.44.13 0.45.2 0.46.1 0.47.0 0.48.0 0.49.8 0.5.2 0.50.3 0.51.0 0.52.2 0.53.2 0.54.0 0.55.0 0.56.2 0.56.3 0.57.6 0.58.10 0.59.0 0.6.0 0.60.1 0.61.2 0.7.1 0.8.2 1.0.16 1.10.0 1.100.0.0 1.100.0.1 1.102.0.0 1.102.0.1 1.103.0.0 1.104.0.0 1.104.0.1 1.105.1.0 1.105.1.1 1.106.0.0 1.106.0.1 1.107.0.0 1.107.0.1 1.107.0.2 1.108.0.0 1.108.0.1 1.109.0.0 1.109.0.1 1.11.4 1.110.0.0 1.110.0.1 1.111.0.0 1.111.0.1 1.111.0.2 1.112.0.0 1.112.0.1 1.113.0.0 1.113.0.1 1.114.0.0 1.114.0.1 1.114.2.0 1.114.2.1 1.115.0.0 1.115.0.1 1.115.1.0 1.115.1.1 1.115.2.0 1.115.2.1 1.116.0.0 1.116.0.1 1.116.1.0 1.116.1.1 1.116.2.0 1.117.0.0 1.117.0.1 1.117.1.0 1.118.2 1.118.5 1.12.0 1.13.2 1.14.1 1.15.1 1.16.11 1.17.0 1.18.6 1.19.0 1.19.1 1.2.3 1.20.7 1.21.0 1.22.4 1.23.0 1.24.5 1.25.1 1.26.2 1.27.7.2 1.28.0.1 1.29.2.0 1.3.9 1.30.0.1 1.31.0.1 1.32.0.2 1.33.2.1 1.36.1.5 1.37.0.0 1.39.2.1 1.4.6 1.40.0.1 1.40.1.0 1.40.1.1 1.41.0.0 1.41.0.1 1.41.2.2 1.41.2.3 1.43.0.0 1.43.0.1 1.43.0.2 1.44.0.0 1.44.0.1 1.45.0.0 1.45.0.1 1.46.0.0 1.46.0.1 1.47.0.0 1.47.0.1 1.47.1.0 1.48.0.0 1.48.0.1 1.48.0.2 1.48.1.0 1.48.1.1 1.5.0 1.50.0.0 1.50.0.1 1.51.0.0 1.51.0.1 1.52.0.0 1.52.0.1 1.53.0.0 1.53.0.1 1.54.0.0 1.54.0.1 1.55.0.0 1.55.0.1 1.56.0.0 1.56.0.1 1.57.0.0 1.57.0.2 1.57.0.3 1.57.0.4 1.57.0.5 1.57.1.0 1.57.1.1 1.57.1.2 1.58.0.0 1.58.0.1 1.59.0.0 1.59.0.1 1.6.0 1.60.0.0 1.60.0.1 1.63.0.0 1.63.0.1 1.64.0.0 1.64.0.1 1.64.1.0 1.64.1.2 1.67.0.0 1.67.0.1 1.68.0.0 1.68.0.1 1.69.0.0 1.69.0.1 1.69.1.1 1.69.1.2 1.7.1 1.70.0.0 1.70.0.1 1.71.0.0 1.71.0.1 1.72.0.0 1.72.1.0 1.72.1.1 1.73.0.0 1.73.0.1 1.74.0.0 1.74.0.1 1.75.0.0 1.75.1.0 1.75.1.1 1.76.0.0 1.76.0.1 1.76.1.0 1.76.1.1 1.76.2.0 1.76.2.1 1.77.0.0 1.77.0.1 1.78.0.0 1.78.0.1 1.79.0.0 1.79.0.1 1.79.0.2 1.79.0.3 1.79.1.0 1.79.1.1 1.8.2 1.80.1.0 1.80.1.1 1.80.1.2 1.81.0.1 1.81.0.2
vk-blocks / src / extensions / core / table / style.js
vk-blocks / src / extensions / core / table Last commit date
style.js 2 months ago style.scss 2 months ago
style.js
545 lines
1 import { useEffect } from 'react';
2 import { __ } from '@wordpress/i18n';
3 import { addFilter } from '@wordpress/hooks';
4 import { PanelBody, ToggleControl, SelectControl } from '@wordpress/components';
5 import { createHigherOrderComponent } from '@wordpress/compose';
6 import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
7 import HorizontalScrollControls, {
8 scrollbarAttributes,
9 applyScrollbarProps,
10 } from '@vkblocks/utils/horizontal-scroll-controls';
11
12 /**
13 * Internal dependencies
14 */
15 import { VkPanelIcon } from '@vkblocks/components/vk-icon';
16
17 const isValidBlockType = (name) => {
18 const validBlockTypes = ['core/table'];
19 return validBlockTypes.includes(name);
20 };
21
22 export const addAttribute = (settings) => {
23 if (isValidBlockType(settings.name)) {
24 settings.attributes = {
25 ...settings.attributes,
26 scrollable: {
27 type: 'boolean',
28 },
29 scrollBreakpoint: {
30 type: 'string',
31 default: 'table-scrollable-mobile',
32 },
33 showScrollMessage: {
34 type: 'boolean',
35 default: false,
36 },
37 scrollMessageText: {
38 type: 'string',
39 default: __('You can scroll', 'vk-blocks'),
40 },
41 scrollIconLeft: {
42 type: 'string',
43 default: 'fa-solid fa-caret-left',
44 },
45 scrollIconRight: {
46 type: 'string',
47 default: 'fa-solid fa-caret-right',
48 },
49 iconOutputLeft: {
50 type: 'boolean',
51 default: true,
52 },
53 iconOutputRight: {
54 type: 'boolean',
55 default: true,
56 },
57 cellVertical: {
58 type: 'boolean',
59 default: false,
60 },
61 cellVerticalBreakpoint: {
62 type: 'string',
63 default: 'table-cell-vertical-mobile',
64 },
65 ...scrollbarAttributes,
66 };
67 }
68 return settings;
69 };
70 addFilter('blocks.registerBlockType', 'vk-blocks/table-style', addAttribute);
71
72 export const addBlockControl = createHigherOrderComponent((BlockEdit) => {
73 return (props) => {
74 const { attributes, setAttributes, name, clientId } = props;
75 if (!isValidBlockType(name)) {
76 return <BlockEdit {...props} />;
77 }
78 const {
79 scrollable,
80 scrollBreakpoint,
81 showScrollMessage,
82 scrollMessageText,
83 scrollIconLeft,
84 scrollIconRight,
85 iconOutputLeft,
86 iconOutputRight,
87 cellVertical,
88 cellVerticalBreakpoint,
89 scrollbarVisible,
90 scrollbarColor,
91 scrollbarTrackColor,
92 } = attributes;
93
94 const blockProps = useBlockProps({
95 className:
96 `${scrollable ? 'is-style-vk-table-scrollable' : ''} ${cellVertical ? 'is-style-vk-table-cell-vertical' : ''}`.trim(),
97 ...(scrollable && { 'data-scroll-breakpoint': scrollBreakpoint }),
98 ...(scrollable &&
99 scrollbarVisible === false && {
100 'data-scrollbar-visible': 'false',
101 }),
102 ...(scrollable &&
103 scrollbarColor && {
104 'data-scrollbar-color': scrollbarColor,
105 }),
106 ...(scrollable &&
107 scrollbarTrackColor && {
108 'data-scrollbar-track-color': scrollbarTrackColor,
109 }),
110 ...(scrollable &&
111 (scrollbarColor || scrollbarTrackColor) && {
112 style: {
113 ...(scrollbarColor && {
114 '--vk-scrollbar-color': scrollbarColor,
115 }),
116 ...(scrollbarTrackColor && {
117 '--vk-scrollbar-track-color': scrollbarTrackColor,
118 }),
119 },
120 }),
121 ...(cellVertical && {
122 'data-cell-vertical-breakpoint': cellVerticalBreakpoint,
123 }),
124 });
125
126 // スクロール可能トグル変更のハンドル
127 const handleToggleChange = (checked) => {
128 setAttributes({ scrollable: checked });
129
130 if (!checked) {
131 setAttributes({
132 showScrollMessage: false,
133 scrollBreakpoint: 'table-scrollable-mobile',
134 scrollbarVisible: true,
135 scrollbarColor: '',
136 scrollbarTrackColor: '',
137 });
138 }
139 };
140
141 // ブレークポイント選択変更のハンドル
142 const handleSelectChange = (value) => {
143 setAttributes({ scrollBreakpoint: value });
144 };
145
146 // cellVerticalトグル変更のハンドル
147 const handleCellVerticalToggleChange = (checked) => {
148 setAttributes({ cellVertical: checked });
149
150 if (!checked) {
151 // OFF の場合、関連するクラスや属性をリセット
152 setAttributes({
153 cellVerticalBreakpoint: 'table-cell-vertical-mobile',
154 });
155 }
156 };
157
158 // cellVerticalブレークポイント選択変更のハンドル
159 const handleCellVerticalSelectChange = (value) => {
160 setAttributes({ cellVerticalBreakpoint: value });
161 };
162
163 // コンポーネントのマウントまたは更新後に属性を更新
164 useEffect(() => {
165 // 初期ロード時にクラスや属性を確認して scrollable を ON にする
166 const checkTableScrollAttributes = () => {
167 const blockRoot = document.querySelector(
168 `[data-block="${clientId}"]`
169 );
170 if (!blockRoot) {
171 return;
172 }
173 const tables = blockRoot.querySelectorAll('.wp-block-table');
174 tables.forEach((table) => {
175 const hasScrollableClass = table.classList.contains(
176 'is-style-vk-table-scrollable'
177 );
178 const hasBreakpointAttr = table.hasAttribute(
179 'data-scroll-breakpoint'
180 );
181 // もし is-style-vk-table-scrollable クラスや data-scroll-breakpoint 属性がついていたら scrollable を ON に設定
182 if (hasScrollableClass || hasBreakpointAttr) {
183 setAttributes({ scrollable: true });
184 }
185 });
186 };
187
188 // コンポーネントの初回レンダリング時に実行
189 checkTableScrollAttributes();
190 }, [clientId]); // 初期レンダリング時のみ実行
191
192 // scrollable、cellVertical の状�
193 �が確定したら処理を実行
194 useEffect(() => {
195 const updateTableAttributes = () => {
196 // clientId で現在のブロック root を特定してスコープを絞る
197 const blockRoot = document.querySelector(
198 `[data-block="${clientId}"]`
199 );
200 if (!blockRoot) {
201 return;
202 }
203 const tables = blockRoot.querySelectorAll('.wp-block-table');
204 tables.forEach((table) => {
205 // scrollable 状�
206 �に応じてクラスと属性を更新
207 if (!scrollable) {
208 table.classList.remove('is-style-vk-table-scrollable');
209 table.removeAttribute('data-scroll-breakpoint');
210 } else {
211 const breakpoint =
212 table.getAttribute('data-scroll-breakpoint') ||
213 'table-scrollable-mobile';
214 table.classList.add('is-style-vk-table-scrollable');
215 table.setAttribute(
216 'data-scroll-breakpoint',
217 breakpoint
218 );
219 }
220
221 table.setAttribute(
222 'data-output-scroll-hint',
223 showScrollMessage ? 'true' : 'false'
224 );
225
226 table.setAttribute(
227 'data-icon-output-left',
228 iconOutputLeft ? 'true' : 'false'
229 );
230
231 table.setAttribute(
232 'data-icon-output-right',
233 iconOutputRight ? 'true' : 'false'
234 );
235
236 // cellVertical 状�
237 �に応じたクラスと属性を更新
238 if (!cellVertical) {
239 // cellVertical が OFF の場合
240 table.classList.remove(
241 'is-style-vk-table-cell-vertical'
242 );
243 table.removeAttribute('data-cell-vertical-breakpoint');
244 } else {
245 // cellVertical が ON の場合
246 table.classList.add('is-style-vk-table-cell-vertical');
247 table.setAttribute(
248 'data-cell-vertical-breakpoint',
249 cellVerticalBreakpoint
250 );
251 }
252 // scrollbar visibility
253 if (scrollbarVisible === false) {
254 table.setAttribute('data-scrollbar-visible', 'false');
255 } else {
256 table.removeAttribute('data-scrollbar-visible');
257 }
258
259 // scrollbar color
260 if (scrollbarColor) {
261 table.setAttribute(
262 'data-scrollbar-color',
263 scrollbarColor
264 );
265 table.style.setProperty(
266 '--vk-scrollbar-color',
267 scrollbarColor
268 );
269 } else {
270 table.removeAttribute('data-scrollbar-color');
271 table.style.removeProperty('--vk-scrollbar-color');
272 }
273
274 // scrollbar track color
275 if (scrollbarTrackColor) {
276 table.setAttribute(
277 'data-scrollbar-track-color',
278 scrollbarTrackColor
279 );
280 table.style.setProperty(
281 '--vk-scrollbar-track-color',
282 scrollbarTrackColor
283 );
284 } else {
285 table.removeAttribute('data-scrollbar-track-color');
286 table.style.removeProperty(
287 '--vk-scrollbar-track-color'
288 );
289 }
290 });
291 };
292
293 // 状�
294 �が undefined でない場合のみ実行
295 if (typeof scrollable !== 'undefined') {
296 updateTableAttributes();
297 }
298 }, [
299 clientId,
300 scrollable,
301 scrollBreakpoint,
302 showScrollMessage,
303 scrollIconLeft,
304 scrollIconRight,
305 iconOutputLeft,
306 iconOutputRight,
307 cellVertical,
308 cellVerticalBreakpoint,
309 scrollbarVisible,
310 scrollbarColor,
311 scrollbarTrackColor,
312 ]);
313
314 if (props.isSelected) {
315 const blockEditContent = <BlockEdit {...props} />;
316
317 return (
318 <>
319 <div {...blockProps}>
320 {scrollable && showScrollMessage && (
321 <div
322 className="vk-scroll-hint"
323 data-scroll-breakpoint={scrollBreakpoint}
324 data-icon-output-left={
325 iconOutputLeft ? 'true' : 'false'
326 }
327 data-icon-output-right={
328 iconOutputRight ? 'true' : 'false'
329 }
330 data-hint-icon-left={
331 iconOutputLeft ? scrollIconLeft : ''
332 }
333 data-hint-icon-right={
334 iconOutputRight ? scrollIconRight : ''
335 }
336 >
337 {iconOutputLeft && (
338 <i
339 className={`${scrollIconLeft} left-icon`}
340 ></i>
341 )}
342 <span>{scrollMessageText}</span>
343 {iconOutputRight && (
344 <i
345 className={`${scrollIconRight} right-icon`}
346 ></i>
347 )}
348 </div>
349 )}
350 {blockEditContent}
351 </div>
352 <InspectorControls>
353 <PanelBody
354 title={__('Table Horizontal Scroll', 'vk-blocks')}
355 icon={<VkPanelIcon isActive={scrollable} />}
356 initialOpen={false}
357 >
358 <HorizontalScrollControls
359 scrollable={scrollable}
360 scrollBreakpoint={scrollBreakpoint}
361 onScrollableChange={handleToggleChange}
362 onBreakpointChange={handleSelectChange}
363 prefix="table-scrollable-"
364 scrollbarVisible={scrollbarVisible}
365 scrollbarColor={scrollbarColor}
366 scrollbarTrackColor={scrollbarTrackColor}
367 onScrollbarVisibleChange={(checked) => {
368 setAttributes({
369 scrollbarVisible: checked,
370 });
371 }}
372 onScrollbarColorChange={(color) => {
373 setAttributes({
374 scrollbarColor: color || '',
375 });
376 }}
377 onScrollbarTrackColorChange={(color) => {
378 setAttributes({
379 scrollbarTrackColor: color || '',
380 });
381 }}
382 scrollHintProps={{
383 showScrollMessage,
384 scrollMessageText,
385 scrollIconLeft,
386 scrollIconRight,
387 ...props,
388 }}
389 />
390 </PanelBody>
391 <PanelBody
392 title={__('Table Cell Vertical', 'vk-blocks')}
393 icon={<VkPanelIcon isActive={cellVertical} />}
394 initialOpen={false}
395 >
396 <ToggleControl
397 label={__('Cell Vertical', 'vk-blocks')}
398 checked={cellVertical}
399 onChange={handleCellVerticalToggleChange}
400 />
401 {cellVertical && (
402 <>
403 <SelectControl
404 label={__(
405 'Cell Vertical Breakpoint',
406 'vk-blocks'
407 )}
408 value={cellVerticalBreakpoint}
409 options={[
410 {
411 label: __(
412 'Mobile size',
413 'vk-blocks'
414 ),
415 value: 'table-cell-vertical-mobile',
416 },
417 {
418 label: __(
419 'Tablet size',
420 'vk-blocks'
421 ),
422 value: 'table-cell-vertical-tablet',
423 },
424 {
425 label: __(
426 'PC size',
427 'vk-blocks'
428 ),
429 value: 'table-cell-vertical-pc',
430 },
431 ]}
432 onChange={
433 handleCellVerticalSelectChange
434 }
435 />
436 </>
437 )}
438 </PanelBody>
439 </InspectorControls>
440 </>
441 );
442 }
443
444 return <BlockEdit {...props} />;
445 };
446 }, 'addMyCustomBlockControls');
447 addFilter('editor.BlockEdit', 'vk-blocks/table-style', addBlockControl);
448
449 // 保存時に追加のプロパティを設定
450 const addExtraProps = (saveElementProps, blockType, attributes) => {
451 if (isValidBlockType(blockType.name)) {
452 // 'scrollable' が true の場合のみ 'is-style-vk-table-scrollable' クラスと 'data-scroll-breakpoint' を設定
453 if (attributes.scrollable) {
454 saveElementProps.className =
455 `${saveElementProps.className || ''} is-style-vk-table-scrollable`.trim();
456 saveElementProps['data-scroll-breakpoint'] =
457 attributes.scrollBreakpoint;
458 }
459
460 // cellVerticalがtrueの場合にcellVerticalBreakpointを設定
461 if (attributes.cellVertical) {
462 saveElementProps.className += ` is-style-vk-table-cell-vertical`;
463 saveElementProps['data-cell-vertical-breakpoint'] =
464 attributes.cellVerticalBreakpoint;
465 } else {
466 // cellVerticalがfalseの場合、不要なクラスや属性を削除
467 saveElementProps.className = saveElementProps.className
468 .replace('is-style-vk-table-cell-vertical', '')
469 .trim();
470 delete saveElementProps['data-cell-vertical-breakpoint'];
471 }
472
473 // 'showScrollMessage' が true の場合のみ 'data-output-scroll-hint' を追加
474 if (attributes.showScrollMessage) {
475 saveElementProps['data-output-scroll-hint'] = 'true';
476 } else {
477 delete saveElementProps['data-output-scroll-hint'];
478 }
479
480 // iconOutputLeft が true の場合のみ属性を追加
481 if (attributes.iconOutputLeft && attributes.showScrollMessage) {
482 saveElementProps['data-icon-output-left'] = 'true';
483 } else {
484 delete saveElementProps['data-icon-output-left'];
485 }
486
487 // iconOutputRight が true の場合のみ属性を追加
488 if (attributes.iconOutputRight && attributes.showScrollMessage) {
489 saveElementProps['data-icon-output-right'] = 'true';
490 } else {
491 delete saveElementProps['data-icon-output-right'];
492 }
493
494 // scrollbar関連の属性を適用
495 applyScrollbarProps(saveElementProps, attributes);
496 } else if (blockType.name !== 'core/group') {
497 // 他のブロックでは不要な属性を削除
498 // core/group はグループブロック独自の横スクロール機能で data-scroll-breakpoint 等を使用するため除外
499 delete saveElementProps['data-scroll-breakpoint'];
500 delete saveElementProps['data-output-scroll-hint'];
501 delete saveElementProps['data-icon-output-left'];
502 delete saveElementProps['data-icon-output-right'];
503 delete saveElementProps['data-cell-vertical-breakpoint'];
504 }
505
506 return saveElementProps;
507 };
508 addFilter(
509 'blocks.getSaveContent.extraProps',
510 'vk-blocks/table-style',
511 addExtraProps
512 );
513
514 const removeVkTableMobileBlockFromEditor = createHigherOrderComponent(
515 (BlockListBlock) => {
516 return (props) => {
517 const { attributes, setAttributes } = props;
518
519 // `cellVertical` が `true` の場合のみ `.vk-table--mobile-block` を削除
520 if (
521 attributes?.cellVertical &&
522 attributes?.className?.includes('vk-table--mobile-block')
523 ) {
524 const updatedClassName = attributes.className
525 .replace(/\bvk-table--mobile-block\b/g, '')
526 .trim();
527
528 // `setAttributes` を使用して `className` を更新
529 if (updatedClassName !== attributes.className) {
530 setAttributes({ className: updatedClassName });
531 }
532 }
533
534 return <BlockListBlock {...props} />;
535 };
536 },
537 'withRemoveVkTableMobileBlock'
538 );
539
540 addFilter(
541 'editor.BlockListBlock',
542 'vk-blocks/remove-vk-table-mobile-block',
543 removeVkTableMobileBlockFromEditor
544 );
545