itmar-block-packages 1.0.0

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.
@@ -0,0 +1,11 @@
1
+ import { Suspense } from '@wordpress/element';
2
+
3
+ function BlockEditWrapper({ lazyComponent: LazyComponent, ...props }) {
4
+ return (
5
+ <Suspense fallback={<div>Loading...</div>}>
6
+ <LazyComponent {...props} />
7
+ </Suspense>
8
+ );
9
+ }
10
+
11
+ export default BlockEditWrapper;
@@ -0,0 +1,139 @@
1
+ import { useEffect, useRef } from '@wordpress/element';
2
+ import { __ } from '@wordpress/i18n';
3
+
4
+ import {
5
+ Button,
6
+ PanelBody,
7
+ PanelRow,
8
+ __experimentalUnitControl as UnitControl
9
+ } from '@wordpress/components';
10
+
11
+ export const useDraggingMove = (isMovable, blockRef, position, onPositionChange) => {
12
+ const elmposition = useRef({ x: 0, y: 0 });
13
+ const isDragging = useRef(false);
14
+ const mousePosition = useRef({ x: 0, y: 0 });
15
+
16
+ useEffect(() => {
17
+ const element = blockRef.current;
18
+
19
+ if (!isMovable) {
20
+ if (element) {
21
+ element.classList.remove('itmar_isDraggable');//移動カーソル表示クラス削除
22
+ }
23
+ return; // 移動許可がある場合のみ、後続のロジックを実行
24
+ }
25
+ //positionの変化に合わせて現在位置を変更
26
+ const pos_value_x = position.x.match(/(-?\d+)([%a-zA-Z]+)/);
27
+ const pos_value_y = position.y.match(/(-?\d+)([%a-zA-Z]+)/);
28
+ elmposition.current = { x: parseInt(pos_value_x[1]), y: parseInt(pos_value_y[1]) }
29
+
30
+ //イベントハンドラ
31
+ const handleMouseDown = (event) => {
32
+ // 移動カーソル表示クラス名を追加します。
33
+ element.classList.add('itmar_isDraggable');
34
+ //ドラッグの開始フラグオン
35
+ isDragging.current = true;
36
+ //ドラッグ開始の絶対位置
37
+ mousePosition.current = { x: event.clientX, y: event.clientY };
38
+ };
39
+
40
+ const handleMouseMove = (event) => {
41
+ if (!isDragging.current) return;//ドラッグ中でなければ処理を中止
42
+ const dx = event.clientX - mousePosition.current.x;
43
+ const dy = event.clientY - mousePosition.current.y;
44
+ //ドラッグ後の位置を保存
45
+ const newPosition = {
46
+ x: elmposition.current.x + dx,
47
+ y: elmposition.current.y + dy,
48
+ };
49
+ elmposition.current = newPosition;
50
+ mousePosition.current = { x: event.clientX, y: event.clientY };//マウス位置の保存
51
+ //ドラッグによるブロックの一時的移動
52
+ element.style.transform = `translate(${elmposition.current.x}px, ${elmposition.current.y}px)`;
53
+ };
54
+
55
+ const handleMouseUp = () => {
56
+ isDragging.current = false;
57
+ element.style.transform = null;
58
+ //呼出しもとに要素の位置を返す
59
+ onPositionChange({ x: `${elmposition.current.x}px`, y: `${elmposition.current.y}px` });
60
+ };
61
+ const handleMouseLeave = () => {
62
+ isDragging.current = false;
63
+ };
64
+
65
+ if (element) {
66
+ // クラス名を追加します。
67
+ element.classList.add('itmar_isDraggable');
68
+ }
69
+ // イベントハンドラを追加します。
70
+ element.addEventListener('mousedown', handleMouseDown);
71
+ element.addEventListener('mousemove', handleMouseMove);
72
+ element.addEventListener('mouseup', handleMouseUp);
73
+ element.addEventListener('mouseleave', handleMouseLeave);
74
+
75
+ // イベントリスナーを削除するクリーンアップ関数を返します。
76
+ return () => {
77
+ element.removeEventListener('mousedown', handleMouseDown);
78
+ element.removeEventListener('mousemove', handleMouseMove);
79
+ element.removeEventListener('mouseup', handleMouseUp);
80
+ element.removeEventListener('mouseleave', handleMouseLeave);
81
+ element.style.transform = null;
82
+ };
83
+ }, [isMovable, blockRef, position, onPositionChange]); // 依存配列に isMovable を含めます
84
+ }
85
+
86
+ export default function DraggableBox(props) {
87
+
88
+ const position = props.attributes
89
+
90
+ //インスペクター内のコントロールからの移動操作
91
+ const chagePosition = (value, cordinate) => {
92
+ if (value) {
93
+ const newPos = { ...position, [cordinate]: value };
94
+ props.onPositionChange(newPos);
95
+ }
96
+ }
97
+
98
+ //リセット
99
+ const resetPos = () => {
100
+ const newPos = { "x": "0px", "y": "0px" };
101
+ props.onPositionChange(newPos);
102
+ }
103
+
104
+ return (
105
+ <>
106
+ <PanelBody
107
+ title={__("Position Setting", 'block-collections')}
108
+ initialOpen={true}
109
+ >
110
+ <PanelRow
111
+ className='distance_row'
112
+ >
113
+ <UnitControl
114
+ dragDirection="e"
115
+ onChange={(value) => chagePosition(value, 'x')}
116
+ label={__("Vertical", 'block-collections')}
117
+ value={position?.x || 0}
118
+ />
119
+ <UnitControl
120
+ dragDirection="e"
121
+ onChange={(value) => chagePosition(value, 'y')}
122
+ label={__("Horizen", 'block-collections')}
123
+ value={position?.y || 0}
124
+ />
125
+ </PanelRow>
126
+ <PanelRow
127
+ className='reset_row'
128
+ >
129
+ <Button
130
+ variant="secondary"
131
+ onClick={() => resetPos()}
132
+ >
133
+ {__("Reset", 'block-collections')}
134
+ </Button>
135
+ </PanelRow>
136
+ </PanelBody>
137
+ </>
138
+ )
139
+ }
package/ShadowStyle.js ADDED
@@ -0,0 +1,520 @@
1
+ import { __ } from "@wordpress/i18n";
2
+ import { __experimentalPanelColorGradientSettings as PanelColorGradientSettings } from "@wordpress/block-editor";
3
+ import {
4
+ PanelBody,
5
+ PanelRow,
6
+ ToggleControl,
7
+ RangeControl,
8
+ RadioControl,
9
+ } from "@wordpress/components";
10
+ import { useState, useEffect } from "@wordpress/element";
11
+ import { dispatch } from "@wordpress/data";
12
+ import { hslToRgb16, HexToRGB, rgb16ToHsl } from "./hslToRgb";
13
+
14
+ //方向と距離
15
+ const dirctionDigit = (direction, distance) => {
16
+ let destTopLeft, destTopRight, destBottomLeft, destBottomRight;
17
+ switch (direction) {
18
+ case "top_left":
19
+ destTopLeft = distance;
20
+ destTopRight = distance;
21
+ destBottomLeft = distance * -1;
22
+ destBottomRight = distance * -1;
23
+ break;
24
+ case "top_right":
25
+ destTopLeft = distance * -1;
26
+ destTopRight = distance;
27
+ destBottomLeft = distance;
28
+ destBottomRight = distance * -1;
29
+ break;
30
+ case "bottom_left":
31
+ destTopLeft = distance;
32
+ destTopRight = distance * -1;
33
+ destBottomLeft = distance * -1;
34
+ destBottomRight = distance;
35
+ break;
36
+ case "bottom_right":
37
+ destTopLeft = distance * -1;
38
+ destTopRight = distance * -1;
39
+ destBottomLeft = distance;
40
+ destBottomRight = distance;
41
+ break;
42
+ case "right_bottom":
43
+ destTopLeft = distance;
44
+ destTopRight = distance * -1;
45
+ destBottomLeft = distance * -1;
46
+ destBottomRight = distance;
47
+ break;
48
+ case "top":
49
+ destTopLeft = 0;
50
+ destTopRight = 0;
51
+ destBottomLeft = distance * -1;
52
+ destBottomRight = distance;
53
+ break;
54
+ }
55
+ return {
56
+ topLeft: destTopLeft,
57
+ topRight: destTopRight,
58
+ bottomLeft: destBottomLeft,
59
+ bottmRight: destBottomRight,
60
+ };
61
+ };
62
+
63
+ // グラデーションの色値は通常'linear-gradient'または'radial-gradient'で始まるので、
64
+ // これらのキーワードを探すことでグラデーションかどうかを判断します。
65
+ function isGradient(colorValue) {
66
+ return (
67
+ colorValue.includes("linear-gradient") ||
68
+ colorValue.includes("radial-gradient")
69
+ );
70
+ }
71
+
72
+ export const ShadowElm = (shadowState) => {
73
+ //let baseColor;
74
+ const {
75
+ shadowType,
76
+ spread,
77
+ lateral,
78
+ longitude,
79
+ nomalBlur,
80
+ shadowColor,
81
+ blur,
82
+ intensity,
83
+ distance,
84
+ newDirection,
85
+ clayDirection,
86
+ embos,
87
+ opacity,
88
+ depth,
89
+ bdBlur,
90
+ expand,
91
+ glassblur,
92
+ glassopa,
93
+ hasOutline,
94
+ baseColor,
95
+ } = shadowState;
96
+
97
+ //ノーマル
98
+ if (shadowType === "nomal") {
99
+ //boxshadowの生成
100
+ const ShadowStyle =
101
+ embos === "dent"
102
+ ? {
103
+ style: {
104
+ boxShadow: `${lateral}px ${longitude}px ${nomalBlur}px ${spread}px transparent, inset ${lateral}px ${longitude}px ${nomalBlur}px ${spread}px ${shadowColor}`,
105
+ },
106
+ }
107
+ : {
108
+ style: {
109
+ boxShadow: `${lateral}px ${longitude}px ${nomalBlur}px ${spread}px ${shadowColor}, inset ${lateral}px ${longitude}px ${nomalBlur}px ${spread}px transparent`,
110
+ },
111
+ };
112
+ //Shadowのスタイルを返す
113
+ return ShadowStyle;
114
+ }
115
+ //ニューモフィズム
116
+ else if (shadowType === "newmor") {
117
+ //背景がグラデーションのときはセットしない
118
+ if (isGradient(baseColor)) {
119
+ dispatch("core/notices").createNotice(
120
+ "error",
121
+ __(
122
+ "Neumorphism cannot be set when the background color is a gradient. ",
123
+ "itmar_guest_contact_block"
124
+ ),
125
+ { type: "snackbar", isDismissible: true }
126
+ );
127
+ return null;
128
+ }
129
+ //ボタン背景色のHSL値
130
+ const hslValue = rgb16ToHsl(baseColor);
131
+ //影の明るさを変更
132
+ const lightVal =
133
+ hslValue.lightness + intensity < 100
134
+ ? hslValue.lightness + intensity
135
+ : 100;
136
+ const darkVal =
137
+ hslValue.lightness - intensity > 0 ? hslValue.lightness - intensity : 0;
138
+ const lightValue = hslToRgb16(hslValue.hue, hslValue.saturation, lightVal);
139
+ const darkValue = hslToRgb16(hslValue.hue, hslValue.saturation, darkVal);
140
+ //boxshadowの生成
141
+ //立体の方向
142
+ const dircObj = dirctionDigit(newDirection, distance);
143
+
144
+ const baseStyle = {
145
+ style: {
146
+ border: "none",
147
+ background: baseColor,
148
+ },
149
+ };
150
+
151
+ const newmorStyle =
152
+ embos === "swell"
153
+ ? {
154
+ style: {
155
+ ...baseStyle.style,
156
+ boxShadow: `${dircObj.topLeft}px ${dircObj.topRight}px ${blur}px ${darkValue}, ${dircObj.bottomLeft}px ${dircObj.bottmRight}px ${blur}px ${lightValue}, inset ${dircObj.topLeft}px ${dircObj.topRight}px ${blur}px transparent, inset ${dircObj.bottomLeft}px ${dircObj.bottmRight}px ${blur}px transparent`,
157
+ },
158
+ }
159
+ : {
160
+ style: {
161
+ ...baseStyle.style,
162
+ boxShadow: `${dircObj.topLeft}px ${dircObj.topRight}px ${blur}px transparent, ${dircObj.bottomLeft}px ${dircObj.bottmRight}px ${blur}px transparent, inset ${dircObj.topLeft}px ${dircObj.topRight}px ${blur}px ${darkValue}, inset ${dircObj.bottomLeft}px ${dircObj.bottmRight}px ${blur}px ${lightValue}`,
163
+ },
164
+ };
165
+
166
+ //Shadowのスタイルを返す
167
+ return newmorStyle;
168
+ }
169
+
170
+ //クレイモーフィズム
171
+ else if (shadowType === "claymor") {
172
+ //背景がグラデーションのときはセットしない
173
+ if (isGradient(baseColor)) {
174
+ dispatch("core/notices").createNotice(
175
+ "error",
176
+ __(
177
+ "claymorphism cannot be set when the background color is a gradient. ",
178
+ "itmar_guest_contact_block"
179
+ ),
180
+ { type: "snackbar", isDismissible: true }
181
+ );
182
+ return null;
183
+ }
184
+ const rgbValue = HexToRGB(baseColor);
185
+ const outsetObj = dirctionDigit(clayDirection, expand);
186
+ const insetObj = dirctionDigit(clayDirection, depth);
187
+ const baseStyle = {
188
+ style: {
189
+ background: `rgba(255, 255, 255, ${opacity})`,
190
+ backdropFilter: `blur(${bdBlur}px)`,
191
+ border: "none",
192
+ },
193
+ };
194
+ const claymorStyle = {
195
+ ...baseStyle,
196
+ style: {
197
+ ...baseStyle.style,
198
+ boxShadow: `${outsetObj.topLeft}px ${outsetObj.bottmRight}px ${
199
+ expand * 2
200
+ }px 0px rgba(${rgbValue.red}, ${rgbValue.green}, ${
201
+ rgbValue.blue
202
+ }, 0.5), inset ${insetObj.topRight}px ${
203
+ insetObj.bottomLeft
204
+ }px 16px 0px rgba(${rgbValue.red}, ${rgbValue.green}, ${
205
+ rgbValue.blue
206
+ }, 0.6), inset 0px 11px 28px 0px rgb(255, 255, 255)`,
207
+ },
208
+ };
209
+ //attributesに保存
210
+ return claymorStyle;
211
+ }
212
+
213
+ //グラスモーフィズム
214
+ else if (shadowType === "glassmor") {
215
+ const baseStyle = {
216
+ style: {
217
+ backgroundColor: `rgba(255, 255, 255, ${glassopa})`,
218
+ ...(hasOutline ? { border: `1px solid rgba(255, 255, 255, 0.4)` } : {}),
219
+ borderRightColor: `rgba(255, 255, 255, 0.2)`,
220
+ borderBottomColor: `rgba(255, 255, 255, 0.2)`,
221
+ backdropFilter: `blur( ${glassblur}px )`,
222
+ },
223
+ };
224
+ const glassmorStyle =
225
+ embos === "swell"
226
+ ? {
227
+ ...baseStyle,
228
+ style: {
229
+ ...baseStyle.style,
230
+ boxShadow: `0 8px 12px 0 rgba( 31, 38, 135, 0.37 ), inset 0 8px 12px 0 transparent`,
231
+ },
232
+ }
233
+ : {
234
+ ...baseStyle,
235
+ style: {
236
+ ...baseStyle.style,
237
+ boxShadow: `0 8px 12px 0 transparent, inset 0 8px 12px 0 rgba( 31, 38, 135, 0.37 )`,
238
+ },
239
+ };
240
+
241
+ //attributesに保存
242
+ return glassmorStyle;
243
+ }
244
+ };
245
+
246
+ const ShadowStyle = ({ shadowStyle, onChange }) => {
247
+ const [shadowState, setShadowState] = useState(shadowStyle);
248
+
249
+ const {
250
+ shadowType,
251
+ spread,
252
+ lateral,
253
+ longitude,
254
+ nomalBlur,
255
+ shadowColor,
256
+ blur,
257
+ intensity,
258
+ distance,
259
+ newDirection,
260
+ clayDirection,
261
+ embos,
262
+ opacity,
263
+ depth,
264
+ bdBlur,
265
+ expand,
266
+ glassblur,
267
+ glassopa,
268
+ hasOutline,
269
+ } = shadowState;
270
+
271
+ //シャドーのスタイル変更と背景色変更に伴う親コンポーネントの変更
272
+ useEffect(() => {
273
+ const shadowElm = ShadowElm(shadowState);
274
+ if (shadowElm) onChange(shadowElm, shadowState);
275
+ }, [shadowState]);
276
+
277
+ return (
278
+ <>
279
+ <PanelBody
280
+ title={__("Shadow Type", "block-collections")}
281
+ initialOpen={true}
282
+ >
283
+ <div className="itmar_shadow_type">
284
+ <RadioControl
285
+ selected={shadowType}
286
+ options={[
287
+ { label: __("Nomal", "block-collections"), value: "nomal" },
288
+ {
289
+ label: __("Neumorphism", "block-collections"),
290
+ value: "newmor",
291
+ },
292
+ {
293
+ label: __("Claymorphism", "block-collections"),
294
+ value: "claymor",
295
+ },
296
+ {
297
+ label: __("Grassmophism", "block-collections"),
298
+ value: "glassmor",
299
+ },
300
+ ]}
301
+ onChange={(changeOption) =>
302
+ setShadowState({ ...shadowState, shadowType: changeOption })
303
+ }
304
+ />
305
+ </div>
306
+ {shadowType !== "claymor" && (
307
+ <div className="embos">
308
+ <RadioControl
309
+ label={__("unevenness", "block-collections")}
310
+ selected={embos}
311
+ options={[{ value: "swell" }, { value: "dent" }]}
312
+ onChange={(changeOption) =>
313
+ setShadowState({ ...shadowState, embos: changeOption })
314
+ }
315
+ />
316
+ </div>
317
+ )}
318
+ </PanelBody>
319
+
320
+ {shadowType === "nomal" && (
321
+ <PanelBody
322
+ title={__("Nomal settings", "block-collections")}
323
+ initialOpen={false}
324
+ >
325
+ <RangeControl
326
+ value={spread}
327
+ label={__("Spread", "block-collections")}
328
+ max={50}
329
+ min={0}
330
+ onChange={(val) => setShadowState({ ...shadowState, spread: val })}
331
+ withInputField={false}
332
+ />
333
+ <RangeControl
334
+ value={lateral}
335
+ label={__("Lateral direction", "block-collections")}
336
+ max={50}
337
+ min={0}
338
+ onChange={(val) => setShadowState({ ...shadowState, lateral: val })}
339
+ withInputField={false}
340
+ />
341
+ <RangeControl
342
+ value={longitude}
343
+ label={__("Longitudinal direction", "block-collections")}
344
+ max={50}
345
+ min={0}
346
+ onChange={(val) =>
347
+ setShadowState({ ...shadowState, longitude: val })
348
+ }
349
+ withInputField={false}
350
+ />
351
+ <RangeControl
352
+ value={nomalBlur}
353
+ label={__("Blur", "block-collections")}
354
+ max={20}
355
+ min={0}
356
+ onChange={(val) =>
357
+ setShadowState({ ...shadowState, nomalBlur: val })
358
+ }
359
+ withInputField={false}
360
+ />
361
+ <PanelColorGradientSettings
362
+ title={__("Shadow Color Setting", "block-collections")}
363
+ settings={[
364
+ {
365
+ colorValue: shadowColor,
366
+ label: __("Choose Shadow color", "block-collections"),
367
+ onColorChange: (newValue) =>
368
+ setShadowState({ ...shadowState, shadowColor: newValue }),
369
+ },
370
+ ]}
371
+ />
372
+ </PanelBody>
373
+ )}
374
+
375
+ {shadowType === "newmor" && (
376
+ <PanelBody
377
+ title={__("Neumorphism settings", "block-collections")}
378
+ initialOpen={false}
379
+ >
380
+ <RangeControl
381
+ value={distance}
382
+ label={__("Distance", "block-collections")}
383
+ max={50}
384
+ min={0}
385
+ onChange={(val) =>
386
+ setShadowState({ ...shadowState, distance: val })
387
+ }
388
+ withInputField={false}
389
+ />
390
+ <RangeControl
391
+ value={intensity}
392
+ label={__("Intensity", "block-collections")}
393
+ max={100}
394
+ min={0}
395
+ onChange={(val) =>
396
+ setShadowState({ ...shadowState, intensity: val })
397
+ }
398
+ withInputField={false}
399
+ />
400
+ <RangeControl
401
+ value={blur}
402
+ label={__("Blur", "block-collections")}
403
+ max={20}
404
+ min={0}
405
+ onChange={(val) => setShadowState({ ...shadowState, blur: val })}
406
+ withInputField={false}
407
+ />
408
+ <PanelRow>
409
+ <div className="light_direction">
410
+ <RadioControl
411
+ selected={newDirection}
412
+ options={[
413
+ { value: "top_left" },
414
+ { value: "top_right" },
415
+ { value: "bottom_left" },
416
+ { value: "bottom_right" },
417
+ ]}
418
+ onChange={(changeOption) =>
419
+ setShadowState({ ...shadowState, newDirection: changeOption })
420
+ }
421
+ />
422
+ </div>
423
+ </PanelRow>
424
+ </PanelBody>
425
+ )}
426
+ {shadowType === "claymor" && (
427
+ <PanelBody
428
+ title={__("Claymorphism settings", "block-collections")}
429
+ initialOpen={false}
430
+ >
431
+ <RangeControl
432
+ value={opacity}
433
+ label={__("Opacity", "block-collections")}
434
+ max={1}
435
+ min={0}
436
+ step={0.1}
437
+ onChange={(val) => setShadowState({ ...shadowState, opacity: val })}
438
+ withInputField={false}
439
+ />
440
+ <RangeControl
441
+ value={depth}
442
+ label="Depth"
443
+ max={20}
444
+ min={0}
445
+ onChange={(val) => setShadowState({ ...shadowState, depth: val })}
446
+ withInputField={false}
447
+ />
448
+ <RangeControl
449
+ value={expand}
450
+ label="Expand"
451
+ max={50}
452
+ min={0}
453
+ onChange={(val) => setShadowState({ ...shadowState, expand: val })}
454
+ withInputField={false}
455
+ />
456
+ <RangeControl
457
+ value={bdBlur}
458
+ label="Background Blur"
459
+ max={10}
460
+ min={0}
461
+ onChange={(val) => setShadowState({ ...shadowState, bdBlur: val })}
462
+ withInputField={false}
463
+ />
464
+ <div className="light_direction claymor">
465
+ <RadioControl
466
+ selected={clayDirection}
467
+ options={[
468
+ { value: "right_bottom" },
469
+ { value: "top_right" },
470
+ { value: "top" },
471
+ ]}
472
+ onChange={(changeOption) =>
473
+ setShadowState({ ...shadowState, clayDirection: changeOption })
474
+ }
475
+ />
476
+ </div>
477
+ </PanelBody>
478
+ )}
479
+
480
+ {shadowType === "glassmor" && (
481
+ <PanelBody
482
+ title={__("Grassmophism settings", "block-collections")}
483
+ initialOpen={false}
484
+ >
485
+ <RangeControl
486
+ value={glassblur}
487
+ label={__("Glass blur", "block-collections")}
488
+ max={20}
489
+ min={0}
490
+ onChange={(val) =>
491
+ setShadowState({ ...shadowState, glassblur: val })
492
+ }
493
+ withInputField={false}
494
+ />
495
+ <RangeControl
496
+ value={glassopa}
497
+ label={__("Glass Opacity", "block-collections")}
498
+ max={1}
499
+ min={0}
500
+ step={0.1}
501
+ onChange={(val) =>
502
+ setShadowState({ ...shadowState, glassopa: val })
503
+ }
504
+ withInputField={false}
505
+ />
506
+ <fieldset>
507
+ <ToggleControl
508
+ label={__("Show outline", "block-collections")}
509
+ checked={hasOutline}
510
+ onChange={() =>
511
+ setShadowState({ ...shadowState, hasOutline: !hasOutline })
512
+ }
513
+ />
514
+ </fieldset>
515
+ </PanelBody>
516
+ )}
517
+ </>
518
+ );
519
+ };
520
+ export default ShadowStyle;
@@ -0,0 +1,113 @@
1
+ import { css } from "styled-components";
2
+
3
+ //角丸のパラメータを返す
4
+ export const radius_prm = (radius) => {
5
+ const ret_radius_prm =
6
+ radius && Object.keys(radius).length === 1
7
+ ? radius.value
8
+ : `${(radius && radius.topLeft) || ""} ${
9
+ (radius && radius.topRight) || ""
10
+ } ${(radius && radius.bottomRight) || ""} ${
11
+ (radius && radius.bottomLeft) || ""
12
+ }`;
13
+ return ret_radius_prm;
14
+ };
15
+ //スペースのパラメータを返す
16
+ export const space_prm = (space) => {
17
+ const ret_space_prm = space
18
+ ? `${space.top} ${space.right} ${space.bottom} ${space.left}`
19
+ : "";
20
+ return ret_space_prm;
21
+ };
22
+ //ブロック幅を返す
23
+ export const max_width_prm = (width, free_val) => {
24
+ const ret_width_prm =
25
+ width === "wideSize"
26
+ ? " width: 100%; max-width: var(--wp--style--global--wide-size);"
27
+ : width === "contentSize"
28
+ ? " width: 100%; max-width: var(--wp--style--global--content-size);"
29
+ : width === "free"
30
+ ? ` width: 100%; max-width: ${free_val}px; `
31
+ : " width: fit-content;";
32
+ return ret_width_prm;
33
+ };
34
+
35
+ export const width_prm = (width, free_val) => {
36
+ const ret_width_prm =
37
+ width === "wideSize"
38
+ ? " width: var(--wp--style--global--wide-size);"
39
+ : width === "contentSize"
40
+ ? " width: var(--wp--style--global--content-size);"
41
+ : width === "free"
42
+ ? ` width: ${free_val}px; `
43
+ : " width: fit-content;";
44
+ return ret_width_prm;
45
+ };
46
+ //配置を返す
47
+ export const align_prm = (align) => {
48
+ const ret_align_prm =
49
+ align === "center"
50
+ ? "margin-left: auto; margin-right: auto;"
51
+ : align === "right"
52
+ ? "margin-left: auto; margin-right: 0"
53
+ : "margin-right: auto; margin-left: 0";
54
+
55
+ return ret_align_prm;
56
+ };
57
+
58
+ //スタイルオブジェクト変換関数
59
+ export const convertToScss = (styleObject) => {
60
+ let scss = "";
61
+ for (const prop in styleObject) {
62
+ if (styleObject.hasOwnProperty(prop)) {
63
+ const scssProp = prop.replace(/([A-Z])/g, "-$1").toLowerCase();
64
+ scss += `${scssProp}: ${styleObject[prop]};\n`;
65
+ }
66
+ }
67
+ return scss;
68
+ };
69
+
70
+ export const borderProperty = (borderObj) => {
71
+ if (borderObj) {
72
+ //borderObjがundefinedでない
73
+
74
+ let keys = ["top", "bottom", "left", "right"];
75
+ let ret_prop = null;
76
+ let doesKeyExist = keys.some((key) => key in borderObj);
77
+ if (doesKeyExist) {
78
+ //'top', 'bottom', 'left', 'right'が別設定
79
+ let cssString = "";
80
+ for (let side in borderObj) {
81
+ const sideData = borderObj[side];
82
+ const startsWithZero = String(sideData.width || "").match(/^0/);
83
+ if (startsWithZero) {
84
+ //widthが0ならCSS設定しない
85
+ continue;
86
+ }
87
+ const border_style = sideData.style || "solid";
88
+ cssString += `border-${side}: ${sideData.width} ${border_style} ${sideData.color};\n`;
89
+ }
90
+ ret_prop = css`
91
+ ${cssString}
92
+ `;
93
+ return ret_prop;
94
+ } else {
95
+ //同一のボーダー
96
+ const startsWithZero = String(borderObj.width || "").match(/^0/);
97
+
98
+ if (startsWithZero) {
99
+ //widthが0ならnoneを返す
100
+ return css`
101
+ border: none;
102
+ `;
103
+ }
104
+ const border_style = borderObj.style || "solid";
105
+ ret_prop = css`
106
+ border: ${borderObj.width} ${border_style} ${borderObj.color};
107
+ `;
108
+ return ret_prop;
109
+ }
110
+ } else {
111
+ return null;
112
+ }
113
+ };
package/customFooks.js ADDED
@@ -0,0 +1,143 @@
1
+ import { useRef, useEffect, useState } from "@wordpress/element";
2
+ import isEqual from "lodash/isEqual";
3
+
4
+ //useRefで参照したDOM要素の大きさを取得するカスタムフック
5
+ export function useElementWidth() {
6
+ const ref = useRef(null);
7
+ const [width, setWidth] = useState(0);
8
+
9
+ useEffect(() => {
10
+ const resizeObserver = new ResizeObserver((entries) => {
11
+ for (let entry of entries) {
12
+ setWidth(entry.contentRect.width);
13
+ }
14
+ });
15
+
16
+ if (ref.current) {
17
+ resizeObserver.observe(ref.current);
18
+ }
19
+
20
+ return () => {
21
+ resizeObserver.disconnect();
22
+ };
23
+ }, []);
24
+
25
+ return [ref, width];
26
+ }
27
+
28
+ //ViewPortの大きさでモバイルを判断(767px以下がモバイル)するカスタムフック
29
+ export function useIsMobile() {
30
+ const [isMobile, setIsMobile] = useState(false);
31
+
32
+ useEffect(() => {
33
+ if (typeof window !== "undefined") {
34
+ const handleResize = () => {
35
+ setIsMobile(window.innerWidth <= 767);
36
+ };
37
+
38
+ window.addEventListener("resize", handleResize);
39
+
40
+ return () => {
41
+ window.removeEventListener("resize", handleResize);
42
+ };
43
+ }
44
+ }, []);
45
+
46
+ return isMobile;
47
+ }
48
+
49
+ //モバイル表示か否かを判定するフック
50
+ export function useIsIframeMobile() {
51
+ const [isMobile, setIsMobile] = useState(false);
52
+
53
+ useEffect(() => {
54
+ // iframeのcontentWindowを監視する関数
55
+ const checkIframeSize = () => {
56
+ const iframeInstance = document.getElementsByName("editor-canvas")[0];
57
+ if (iframeInstance && iframeInstance.contentWindow) {
58
+ setIsMobile(iframeInstance.contentWindow.innerWidth <= 767);
59
+ }
60
+ };
61
+
62
+ // iframeのcontentWindowのリサイズイベントにリスナーを追加
63
+ const iframeInstance = document.getElementsByName("editor-canvas")[0];
64
+ if (iframeInstance && iframeInstance.contentWindow) {
65
+ iframeInstance.contentWindow.addEventListener("resize", checkIframeSize);
66
+ }
67
+
68
+ // 初期チェックを実行
69
+ checkIframeSize();
70
+
71
+ // クリーンアップ関数
72
+ return () => {
73
+ if (iframeInstance && iframeInstance.contentWindow) {
74
+ iframeInstance.contentWindow.removeEventListener(
75
+ "resize",
76
+ checkIframeSize
77
+ );
78
+ }
79
+ };
80
+ }, []);
81
+
82
+ return isMobile;
83
+ }
84
+
85
+ //ブロックの背景色を取得するカスタムフック
86
+ export function useElementBackgroundColor(blockRef, style) {
87
+ const [baseColor, setBaseColor] = useState("");
88
+
89
+ useEffect(() => {
90
+ if (blockRef.current && style) {
91
+ if (
92
+ style.backgroundColor &&
93
+ !style.backgroundColor.startsWith("var(--wp")
94
+ ) {
95
+ //backgroundColorが設定されており、それがカスタムプロパティでない
96
+ setBaseColor(style.backgroundColor);
97
+ } else {
98
+ //レンダリング結果から背景色を取得
99
+ if (blockRef.current) {
100
+ const computedStyles = getComputedStyle(blockRef.current);
101
+ setBaseColor(computedStyles.backgroundColor);
102
+ }
103
+ }
104
+ }
105
+ }, [style, blockRef]);
106
+
107
+ return baseColor;
108
+ }
109
+
110
+ //たくさんの要素をもつオブジェクトや配列の内容の変化で発火するuseEffect
111
+ export function useDeepCompareEffect(callback, dependencies) {
112
+ const dependenciesRef = useRef();
113
+
114
+ if (!isEqual(dependencies, dependenciesRef.current)) {
115
+ dependenciesRef.current = dependencies;
116
+ }
117
+
118
+ useEffect(() => {
119
+ return callback();
120
+ }, [dependenciesRef.current]);
121
+ }
122
+
123
+ export function useFontawesomeIframe() {
124
+ //iframeにfontawesomeを読み込む
125
+ useEffect(() => {
126
+ const iframeInstance = document.getElementsByName("editor-canvas")[0];
127
+
128
+ if (iframeInstance) {
129
+ const iframeDocument =
130
+ iframeInstance.contentDocument || iframeInstance.contentWindow.document;
131
+ const scriptElement = iframeDocument.createElement("script");
132
+ scriptElement.setAttribute("src", "../../../assets/fontawesome.js");
133
+ //scriptElement.setAttribute("crossorigin", "anonymous");
134
+
135
+ iframeDocument.body.appendChild(scriptElement);
136
+
137
+ // Return a cleanup function to remove the script tag
138
+ return () => {
139
+ iframeDocument.body?.removeChild(scriptElement);
140
+ };
141
+ }
142
+ }, []);
143
+ }
package/hslToRgb.js ADDED
@@ -0,0 +1,162 @@
1
+ const createRGB = (inputStr) => {
2
+ //16進数変換の関数
3
+ function componentToHex(c) {
4
+ const hex = parseInt(c, 10).toString(16);
5
+ return hex.length === 1 ? "0" + hex : hex;
6
+ }
7
+
8
+ let resultStr;
9
+ let rgb = [];
10
+
11
+ // #000000 形式の場合
12
+ if (/^#[0-9a-fA-F]{6}$/.test(inputStr)) {
13
+ rgb = [
14
+ inputStr.slice(1, 3),
15
+ inputStr.slice(3, 5),
16
+ inputStr.slice(5, 7)
17
+ ];
18
+ }
19
+ // rgb(0,0,0) 形式の場合
20
+ else if ((resultStr = inputStr.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/))) {
21
+ rgb = [
22
+ componentToHex(resultStr[1]),
23
+ componentToHex(resultStr[2]),
24
+ componentToHex(resultStr[3])
25
+ ];
26
+ } else {
27
+ // サポートされていない形式の場合はデフォルトの値を設定する
28
+ rgb = ["ff", "ff", "ff"];
29
+ }
30
+ return rgb;
31
+ }
32
+
33
+ export function hslToRgb16(hue, saturation, lightness) {
34
+ var result = false;
35
+
36
+ if (((hue || hue === 0) && hue <= 360) && ((saturation || saturation === 0) && saturation <= 100) && ((lightness || lightness === 0) && lightness <= 100)) {
37
+ var red = 0,
38
+ green = 0,
39
+ blue = 0,
40
+ q = 0,
41
+ p = 0,
42
+ hueToRgb;
43
+
44
+ hue = Number(hue) / 360;
45
+ saturation = Number(saturation) / 100;
46
+ lightness = Number(lightness) / 100;
47
+
48
+ if (saturation === 0) {
49
+ red = lightness;
50
+ green = lightness;
51
+ blue = lightness;
52
+ } else {
53
+ hueToRgb = function (p, q, t) {
54
+ if (t < 0) t += 1;
55
+ if (t > 1) t -= 1;
56
+
57
+ if (t < 1 / 6) {
58
+ p += (q - p) * 6 * t;
59
+ } else if (t < 1 / 2) {
60
+ p = q;
61
+ } else if (t < 2 / 3) {
62
+ p += (q - p) * (2 / 3 - t) * 6;
63
+ }
64
+
65
+ return p;
66
+ };
67
+
68
+ if (lightness < 0.5) {
69
+ q = lightness * (1 + saturation);
70
+ } else {
71
+ q = lightness + saturation - lightness * saturation;
72
+ }
73
+ p = 2 * lightness - q;
74
+
75
+ red = hueToRgb(p, q, hue + 1 / 3);
76
+ green = hueToRgb(p, q, hue);
77
+ blue = hueToRgb(p, q, hue - 1 / 3);
78
+ }
79
+
80
+ result = `#${Math.round(red * 255).toString(16).padStart(2, '0')}${Math.round(green * 255).toString(16).padStart(2, '0')}${Math.round(blue * 255).toString(16).padStart(2, '0')}`;
81
+
82
+ }
83
+
84
+ return result;
85
+ };
86
+
87
+ export function rgb16ToHsl(strRgb16) {
88
+ let rgb = createRGB(strRgb16);
89
+ let red = rgb[0];
90
+ let green = rgb[1];
91
+ let blue = rgb[2];
92
+ let result = false;
93
+
94
+ if (((red || red === 0) && String(red).match(/^[0-9a-f]{2}$/i)) && ((green || green === 0) && String(green).match(/^[0-9a-f]{2}$/i)) && ((blue || blue === 0) && String(blue).match(/^[0-9a-f]{2}$/i))) {
95
+ let hue = 0,
96
+ saturation = 0,
97
+ lightness = 0,
98
+ max = 0,
99
+ min = 0,
100
+ diff = 0;
101
+
102
+ red = parseInt(red, 16) / 255;
103
+ green = parseInt(green, 16) / 255;
104
+ blue = parseInt(blue, 16) / 255;
105
+ max = Math.max(red, green, blue);
106
+ min = Math.min(red, green, blue);
107
+ lightness = (max + min) / 2;
108
+
109
+ if (max !== min) {
110
+ diff = max - min;
111
+
112
+ if (lightness > 0.5) {
113
+ saturation = diff / (2 - max - min);
114
+ } else {
115
+ saturation = diff / (max + min);
116
+ }
117
+
118
+ if (max === red) {
119
+ hue = (green - blue) / diff;
120
+ } else if (max === green) {
121
+ hue = 2 + (blue - red) / diff;
122
+ } else {
123
+ hue = 4 + (red - green) / diff;
124
+ }
125
+
126
+ hue /= 6;
127
+ }
128
+
129
+ result = {
130
+ hue: Math.round(hue * 360),
131
+ saturation: Math.round(saturation * 100),
132
+ lightness: Math.round(lightness * 100)
133
+ };
134
+ }
135
+
136
+ return result;
137
+ };
138
+
139
+ export function HexToRGB(strRgb16) {
140
+ let rgb = createRGB(strRgb16);
141
+ let red = rgb[0];
142
+ let green = rgb[1];
143
+ let blue = rgb[2];
144
+ let result = false;
145
+
146
+ if (((red || red === 0) && String(red).match(/^[0-9a-f]{2}$/i)) && ((green || green === 0) && String(green).match(/^[0-9a-f]{2}$/i)) && ((blue || blue === 0) && String(blue).match(/^[0-9a-f]{2}$/i))) {
147
+
148
+
149
+ red = parseInt(red, 16);
150
+ green = parseInt(green, 16);
151
+ blue = parseInt(blue, 16);
152
+
153
+
154
+ result = {
155
+ red: Math.round(red),
156
+ green: Math.round(green),
157
+ blue: Math.round(blue)
158
+ };
159
+ }
160
+
161
+ return result;
162
+ };
package/index.js ADDED
@@ -0,0 +1,35 @@
1
+ //カスタムフック(一般)
2
+ export {
3
+ useIsIframeMobile,
4
+ useElementBackgroundColor,
5
+ useElementWidth,
6
+ useIsMobile,
7
+ useDeepCompareEffect,
8
+ useFontawesomeIframe,
9
+ } from "./customFooks";
10
+
11
+ //styled-componet用のcssプロパティ生成関数
12
+ export {
13
+ radius_prm,
14
+ space_prm,
15
+ max_width_prm,
16
+ width_prm,
17
+ align_prm,
18
+ convertToScss,
19
+ borderProperty,
20
+ } from "./cssPropertes";
21
+
22
+ //疑似要素を設定するコントロール
23
+ export { default as PseudoElm, Arrow } from "./pseudo";
24
+
25
+ //メディアライブラリから複数の画像を選択するコントロール
26
+ export { MultiImageSelect } from "./mediaUpload";
27
+
28
+ //ボックスシャドーを設定するコントロール
29
+ export { default as ShadowStyle, ShadowElm } from "./ShadowStyle";
30
+
31
+ //ブロックのドラッガブルを設定するコントロール
32
+ export { default as DraggableBox, useDraggingMove } from "./DraggableBox";
33
+
34
+ //ブロックをlazy Loadさせるためのラッパーモジュール
35
+ export { default as BlockEditWrapper } from "./BlockEditWrapper";
package/mediaUpload.js ADDED
@@ -0,0 +1,90 @@
1
+ import { MediaUpload, MediaUploadCheck } from '@wordpress/block-editor';
2
+ import { __ } from '@wordpress/i18n';
3
+ import {
4
+ Button,
5
+ PanelBody,
6
+ } from '@wordpress/components';
7
+
8
+ export function MultiImageSelect(props) {
9
+ const {
10
+ attributes,
11
+ label
12
+ } = props;
13
+ const {
14
+ mediaID,
15
+ media
16
+ } = attributes;
17
+
18
+ //URL の配列から画像を生成
19
+ const getImages = (media) => {
20
+ //メディアオブジェクトの配列をループ処理
21
+ let imagesArray = media.map((image) => {
22
+ return (
23
+ <figure>
24
+ <img
25
+ src={image.url}
26
+ className="image"
27
+ alt="アップロード画像"
28
+ />
29
+ <figcaption className="block-image-caption">
30
+ {image.caption ? image.caption : ''}
31
+ </figcaption>
32
+ </figure>
33
+ );
34
+ });
35
+ return imagesArray;
36
+ }
37
+
38
+ //メディアライブラリを開くボタンをレンダリングする関数
39
+ const getImageButton = (open) => {
40
+ if (media.length > 0) {
41
+ return (
42
+ <div onClick={open} className="block-container">
43
+ {getImages(media)}
44
+ </div>
45
+ )
46
+ }
47
+ else {
48
+ return (
49
+ <div className="button-container">
50
+ <Button
51
+ onClick={open}
52
+ className="button button-large"
53
+ >
54
+ {__("Image Upload", 'slide-blocks')}
55
+ </Button>
56
+ </div>
57
+ );
58
+ }
59
+ };
60
+
61
+ return (
62
+ <PanelBody
63
+ title={label}
64
+ initialOpen={true}
65
+ className='itmar_image_display'
66
+ >
67
+ <MediaUploadCheck>
68
+ <MediaUpload
69
+ multiple={true}
70
+ gallery={true} //追加
71
+ onSelect={(media) => props.onSelectChange(media)}
72
+ allowedTypes={['image']}
73
+ value={mediaID}
74
+ render={({ open }) => getImageButton(open)}
75
+ />
76
+ </MediaUploadCheck>
77
+ {media.length != 0 && //メディアオブジェクト(配列の長さ)で判定
78
+ <MediaUploadCheck>
79
+ <Button
80
+ onClick={() => props.onAllDelete()}
81
+ variant="secondary"
82
+ isDestructive
83
+ className="removeImage">
84
+ {__("Delete All", 'slide-blocks')}
85
+ </Button>
86
+ </MediaUploadCheck>
87
+ }
88
+ </PanelBody>
89
+ );
90
+ }
package/package.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "itmar-block-packages",
3
+ "version": "1.0.0",
4
+ "description": "We have put together a package of common React components used for WordPress custom blocks.",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "author": "Web Creator ITmaroon",
10
+ "license": "ISC",
11
+ "dependencies": {
12
+ "lodash": "^4.17.21",
13
+ "styled-components": "^6.1.8"
14
+ }
15
+ }
package/pseudo.js ADDED
@@ -0,0 +1,55 @@
1
+ import { __ } from '@wordpress/i18n';
2
+ import { css } from 'styled-components';
3
+ import {
4
+ RadioControl
5
+ } from '@wordpress/components';
6
+
7
+ // 矢印の向きに応じたスタイルを生成するヘルパー関数
8
+ const arrowDirectionStyles = (direction) => {
9
+ switch (direction) {
10
+ case 'left':
11
+ return 'transform: translate(-50%, -50%) rotate(-135deg);';
12
+ case 'right':
13
+ return 'transform: translate(-50%, -50%) rotate(45deg);';
14
+ case 'upper':
15
+ return 'transform: translate(-50%, -50%) rotate(-45deg);';
16
+ case 'under':
17
+ return 'transform: translate(-50%, -50%) rotate(135deg);';
18
+ default:
19
+ return 'transform: translate(-50%, -50%) rotate(45deg);'; // default to 'down'
20
+ }
21
+ };
22
+
23
+ // 矢印のスタイルを適用するコンポーネント
24
+ export const Arrow = ({ direction = 'down' }) => css`
25
+ &::after {
26
+ content: "";
27
+ position: absolute;
28
+ display: block;
29
+ width: 15%;
30
+ height: 15%;
31
+ border-top: 3px solid var(--wp--preset--color--accent-2);
32
+ border-right: 3px solid var(--wp--preset--color--accent-2);
33
+ top: 50%;
34
+ left: 50%;
35
+ ${arrowDirectionStyles(direction)}
36
+ }
37
+ `;
38
+
39
+ //擬似要素の出力を選択させるインスペクターコントロール
40
+ const PseudoElm = ({ direction, onChange }) => {
41
+ return (
42
+ <RadioControl
43
+ selected={direction}
44
+ options={[
45
+ { label: __("Upper", 'itmar_block_collections'), value: 'upper' },
46
+ { label: __("Left", 'itmar_block_collections'), value: 'left' },
47
+ { label: __("Right", 'itmar_block_collections'), value: 'right' },
48
+ { label: __("Under", 'itmar_block_collections'), value: 'under' },
49
+ ]}
50
+ onChange={(changeOption) => { onChange(changeOption) }
51
+ }
52
+ />
53
+ )
54
+ }
55
+ export default PseudoElm;