PluginProbe ʕ •ᴥ•ʔ
VK Blocks / 1.126.3
VK Blocks v1.126.3
1.126.4 1.126.3 1.126.1 1.126.2 1.126.0 1.125.0 1.124.0 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 / blocks / button / index.js
vk-blocks / src / blocks / button Last commit date
deprecated 1 week ago block.json 1 week ago component.js 2 weeks ago edit.js 1 week ago icon.svg 3 months ago index.js 1 week ago index.php 3 months ago save.js 1 week ago style.scss 1 week ago transforms.js 3 months ago
index.js
323 lines
1 /**
2 * Button block type
3 *
4 */
5 import { ReactComponent as Icon } from './icon.svg';
6 import { title, iconName, url, iconUser } from '@vkblocks/utils/example-data';
7 import edit from './edit';
8 import metadata from './block.json';
9 import save from './save';
10 import { deprecated } from './deprecated/save/';
11 import deprecatedHooks from './deprecated/hooks';
12 import transforms from './transforms';
13 import { addFilter } from '@wordpress/hooks';
14 import { createHigherOrderComponent } from '@wordpress/compose';
15 import { isHexColor } from '@vkblocks/utils/is-hex-color';
16 import { sanitizeSlug } from '@vkblocks/utils/sanitizeSlug';
17
18 const { name } = metadata;
19
20 export { metadata, name };
21
22 export const settings = {
23 icon: <Icon />,
24 example: {
25 attributes: {
26 content: iconName,
27 subCaption: title,
28 buttonUrl: url,
29 buttonTarget: false,
30 buttonSize: 'md',
31 buttonType: '0',
32 buttonEffect: '',
33 buttonColor: 'primary',
34 buttonTextColorCustom: 'undefined',
35 buttonColorCustom: 'undefined',
36 buttonAlign: 'left',
37 buttonWidthMobile: 0,
38 buttonWidthTablet: 0,
39 outerGap: null,
40 buttonWidth: 0,
41 fontAwesomeIconBefore: iconUser,
42 fontAwesomeIconAfter: iconUser,
43 iconSizeBefore: null,
44 iconSizeAfter: null,
45 },
46 },
47 edit,
48 save,
49 deprecated,
50 transforms,
51 };
52
53 /**
54 * カラーのCSS値を取得する / Returns a CSS color value.
55 * @param {string} value - HEX、rgba、またはパレットスラッグ / A HEX, rgba, or palette slug.
56 * @return {string|null} CSS で使用できる色、または null / A CSS color value or null.
57 */
58 const getColorCssValue = (value) => {
59 if (value === undefined || value === '' || value === null) {
60 return null;
61 }
62 // HEX カラーの場合
63 if (isHexColor(value)) {
64 return value;
65 }
66 // rgba / rgb / hsla / hsl カラーの場合(厳格にバリデーション)
67 const cssFuncColorPattern = /^(rgba?|hsla?)\(\s*[\d.%\s,/]+\s*\)$/;
68 if (cssFuncColorPattern.test(value)) {
69 return value;
70 }
71 // パレットのスラッグ → sanitize して CSS 変数参�
72 �(hover / 枠線で�
73 �用)
74 // Sanitize palette slugs before embedding them in CSS custom properties.
75 const safeSlug = sanitizeSlug(value);
76 if (!safeSlug) {
77 return null;
78 }
79 return `var(--wp--preset--color--${safeSlug})`;
80 };
81
82 const generateInlineCss = (attributes) => {
83 const {
84 buttonTextColorCustom,
85 buttonColorCustom,
86 buttonBorderColorCustom,
87 buttonHoverBorderColorCustom,
88 buttonHoverBgColorCustom,
89 buttonHoverTextColorCustom,
90 buttonType,
91 blockId,
92 } = attributes;
93 let inlineCss = '';
94
95 // 枠線色が有効なときは塗り/アウトライン側の同色 border を出さない。
96 // エディタでは特異性の差で buttonColorCustom 側の border が勝つことがあるため。
97 // When a custom border color is active, skip the matching border from fill/outline styles.
98 // In the editor, buttonColorCustom border rules can win due to specificity differences.
99 const borderColorCssValue = getColorCssValue(buttonBorderColorCustom);
100 const hoverBorderColorCssValue = getColorCssValue(
101 buttonHoverBorderColorCustom
102 );
103 const isBorderStyleType =
104 buttonType === '0' || buttonType === null || buttonType === '1';
105 const hasCustomBorderColor = !!(borderColorCssValue && isBorderStyleType);
106 const hasCustomHoverBorderColor = !!(
107 hoverBorderColorCssValue && isBorderStyleType
108 );
109
110 // カスタムカラーの場合
111 if (buttonColorCustom !== undefined && isHexColor(buttonColorCustom)) {
112 // 枠線色未設定時のみ、ボタン色と同色の border を出す(後方互換)。
113 // Emit a matching border only when no custom border color is set (backward compatibility).
114 const colorBorderCss = hasCustomBorderColor
115 ? ''
116 : `\n\t\t\t\tborder: 1px solid ${buttonColorCustom};`;
117 // 塗り
118 if (buttonType === '0' || buttonType === null) {
119 inlineCss += `.vk_button-${blockId} .has-background {
120 background-color: ${buttonColorCustom};${colorBorderCss}
121 }`;
122 }
123 // アウトライン
124 if (buttonType === '1') {
125 inlineCss += `.vk_button-${blockId} .has-text-color.is-style-outline {
126 background-color: transparent;${colorBorderCss}
127 color: ${buttonColorCustom};
128 }
129 .vk_button-${blockId} .has-text-color.is-style-outline:hover {
130 background-color: ${buttonColorCustom};${colorBorderCss}
131 color: #fff;
132 }`;
133 }
134 // テキストのみ
135 if (buttonType === '2') {
136 inlineCss = `.vk_button-${blockId} .has-text-color.vk_button_link-type-text {
137 color: ${buttonColorCustom};
138 }`;
139 }
140 }
141
142 // 文字色がカスタムカラーの場合
143 if (
144 buttonTextColorCustom !== undefined &&
145 isHexColor(buttonTextColorCustom)
146 ) {
147 if (buttonType === '0' || buttonType === null) {
148 inlineCss += ` .vk_button-${blockId} .has-text-color {
149 color: ${buttonTextColorCustom};
150 }`;
151 }
152 }
153
154 // ホバー時の背景色が設定されている場合
155 // WP コアが .has-*-background-color に !important を付与するため
156 // !important で上書きする�
157 要がある
158 // filter: none でテーマの brightness/saturate フィルタをリセット
159 const hoverBgCssValue = getColorCssValue(buttonHoverBgColorCustom);
160 if (hoverBgCssValue) {
161 inlineCss += ` .vk_button.vk_button-${blockId} .vk_button_link:hover {
162 background-color: ${hoverBgCssValue} !important;
163 border-color: ${hoverBgCssValue} !important;
164 box-shadow: none !important;
165 opacity: 1 !important;
166 filter: none !important;
167 }`;
168 }
169
170 // ホバー時のテキスト色が設定されている場合
171 const hoverTextCssValue = getColorCssValue(buttonHoverTextColorCustom);
172 if (hoverTextCssValue) {
173 inlineCss += ` .vk_button.vk_button-${blockId} .vk_button_link:hover {
174 color: ${hoverTextCssValue} !important;
175 }`;
176 inlineCss += ` .vk_button.vk_button-${blockId} .vk_button_link:hover .vk_button_link_txt,
177 .vk_button.vk_button-${blockId} .vk_button_link:hover .vk_button_link_subCaption,
178 .vk_button.vk_button-${blockId} .vk_button_link:hover .vk_button_link_before,
179 .vk_button.vk_button-${blockId} .vk_button_link:hover .vk_button_link_after {
180 color: ${hoverTextCssValue} !important;
181 }`;
182 }
183
184 if (hasCustomBorderColor) {
185 // 枠線色は背景色・文字色から独立させる。
186 // 通常時は width/style ごと指定する(テーマ側 .btn に border が無い場合でも見えるように)。
187 // エディタでは .editor-styles-wrapper .vk_button .has-text-color.is-style-outline
188 // (特異性 0,4,0 / border-color:currentColor)が
189 // `.vk_button.vk_button-{id} .vk_button_link`(0,3,0)より勝つため、
190 // `.editor-styles-wrapper` 付きセレクタを併記する。
191 // Keep border color independent from background/text colors.
192 // Specify width/style in the default state so borders remain visible even when the theme .btn has none.
193 // In the editor, pair selectors with .editor-styles-wrapper to match outline specificity (0,4,0).
194 inlineCss += ` .vk_button.vk_button-${blockId} .vk_button_link,
195 .editor-styles-wrapper .vk_button.vk_button-${blockId} .vk_button_link {
196 border: 1px solid ${borderColorCssValue};
197 }`;
198 }
199
200 // ホバー時の枠線色:
201 // - Hover Border Color があればそれを使う
202 // - 無ければ通常の Border Color を維持(未設定ならホバー背景色側の border-color に任せる)
203 // ホバーは border-color のみ !important(�
204 �行する hover 背景色ルールの border-color !important に勝つため)。
205 // Hover border color:
206 // - Use Hover Border Color when set
207 // - Otherwise keep Border Color (or defer to hover background border-color when unset)
208 // Use border-color with !important so this rule wins over the hover background rule above.
209 const hoverBorderCssValue =
210 (hasCustomHoverBorderColor && hoverBorderColorCssValue) ||
211 (hasCustomBorderColor && borderColorCssValue) ||
212 '';
213 if (hoverBorderCssValue) {
214 inlineCss += ` .vk_button.vk_button-${blockId} .vk_button_link:hover,
215 .editor-styles-wrapper .vk_button.vk_button-${blockId} .vk_button_link:hover {
216 border-color: ${hoverBorderCssValue} !important;
217 }`;
218 }
219
220 return inlineCss;
221 };
222
223 const generateInlineGapCss = (attributes, isSave) => {
224 const {
225 buttonWidthMobile,
226 buttonWidthTablet,
227 buttonWidth,
228 outerGap,
229 blockId,
230 } = attributes;
231 let inlineCss = '';
232 const propaty = isSave
233 ? '.vk_button'
234 : '.vk_buttons .vk_buttons_col .block-editor-block-list__layout .vk_button';
235
236 // 親ブロックのギャップを反映
237 if (outerGap) {
238 if (buttonWidthMobile) {
239 inlineCss += `@media (max-width: 575.98px) {
240 ${propaty}.vk_button-${blockId} {
241 width: calc(${buttonWidthMobile}% - calc(${outerGap} - calc(${outerGap} / (100 / ${buttonWidthMobile}))) - 1px);
242 }
243 }`;
244 }
245 if (buttonWidthTablet) {
246 inlineCss += `@media(min-width: 576px) and (max-width: 991.98px) {
247 ${propaty}.vk_button-${blockId} {
248 width: calc(${buttonWidthTablet}% - calc(${outerGap} - calc(${outerGap} / (100 / ${buttonWidthTablet}))) - 1px);
249 }
250 }`;
251 }
252 if (buttonWidth) {
253 inlineCss += `@media (min-width: 992px) {
254 ${propaty}.vk_button-${blockId} {
255 width: calc(${buttonWidth}% - calc(${outerGap} - calc(${outerGap} / (100 / ${buttonWidth}))) - 1px );
256 }
257 }`;
258 }
259 }
260
261 return inlineCss;
262 };
263
264 const VKButtonInlineEditorCss = createHigherOrderComponent((BlockEdit) => {
265 return (props) => {
266 const { attributes } = props;
267
268 if ('vk-blocks/button' === props.name) {
269 const cssTag = generateInlineCss(attributes);
270 const cssEditor = generateInlineGapCss(attributes, false);
271 if (cssTag !== '' || cssEditor !== '') {
272 return (
273 <>
274 <BlockEdit {...props} />
275 <style type="text/css">
276 {cssTag} {cssEditor}
277 </style>
278 </>
279 );
280 }
281 return <BlockEdit {...props} />;
282 }
283 return <BlockEdit {...props} />;
284 };
285 }, 'VKButtonInlineEditorCss');
286 addFilter('editor.BlockEdit', 'vk-blocks/button', VKButtonInlineEditorCss);
287
288 const VKButtonInlineCss = (el, type, attributes) => {
289 if ('vk-blocks/button' === type.name) {
290 //現在実行されている deprecated�
291 save関数のindexを取得
292 const deprecatedFuncIndex = deprecated.findIndex(
293 (item) => item.save === type.save
294 );
295
296 // 最新版
297 if (-1 === deprecatedFuncIndex) {
298 // NOTE: useBlockProps + style要素を挿�
299 �する場合、useBlockPropsを使った要素が最初(上)にこないと、
300 // カスタムクラスを追加する処理が失敗する[
301 const cssTag = generateInlineCss(attributes);
302 const cssEditor = generateInlineGapCss(attributes, true);
303 if (cssTag !== '' || cssEditor !== '') {
304 return (
305 <>
306 {el}
307 <style type="text/css">
308 {cssTag} {cssEditor}
309 </style>
310 </>
311 );
312 }
313 return el;
314
315 //後方互換
316 }
317 const DeprecatedHook = deprecatedHooks[deprecatedFuncIndex];
318 return <DeprecatedHook el={el} attributes={attributes} />;
319 }
320 return el;
321 };
322 addFilter('blocks.getSaveElement', 'vk-blocks/button', VKButtonInlineCss, 11);
323