itmar-block-packages 1.1.0 → 1.2.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.
@@ -7,6 +7,94 @@ import {
7
7
  __experimentalUnitControl as UnitControl,
8
8
  } from "@wordpress/components";
9
9
 
10
+ import { useEffect, useRef } from "@wordpress/element";
11
+
12
+ export const useDraggingMove = (
13
+ isMovable,
14
+ blockRef,
15
+ position,
16
+ onPositionChange
17
+ ) => {
18
+ const elmposition = useRef({ x: 0, y: 0 });
19
+ const isDragging = useRef(false);
20
+ const mousePosition = useRef({ x: 0, y: 0 });
21
+
22
+ useEffect(() => {
23
+ const element = blockRef.current;
24
+
25
+ if (!isMovable) {
26
+ if (element) {
27
+ element.classList.remove("itmar_isDraggable"); //移動カーソル表示クラス削除
28
+ }
29
+ return; // 移動許可がある場合のみ、後続のロジックを実行
30
+ }
31
+ //positionの変化に合わせて現在位置を変更
32
+ const pos_value_x = position.x.match(/(-?\d+)([%a-zA-Z]+)/);
33
+ const pos_value_y = position.y.match(/(-?\d+)([%a-zA-Z]+)/);
34
+ elmposition.current = {
35
+ x: parseInt(pos_value_x[1]),
36
+ y: parseInt(pos_value_y[1]),
37
+ };
38
+
39
+ //イベントハンドラ
40
+ const handleMouseDown = (event) => {
41
+ // 移動カーソル表示クラス名を追加します。
42
+ element.classList.add("itmar_isDraggable");
43
+ //ドラッグの開始フラグオン
44
+ isDragging.current = true;
45
+ //ドラッグ開始の絶対位置
46
+ mousePosition.current = { x: event.clientX, y: event.clientY };
47
+ };
48
+
49
+ const handleMouseMove = (event) => {
50
+ if (!isDragging.current) return; //ドラッグ中でなければ処理を中止
51
+ const dx = event.clientX - mousePosition.current.x;
52
+ const dy = event.clientY - mousePosition.current.y;
53
+ //ドラッグ後の位置を保存
54
+ const newPosition = {
55
+ x: elmposition.current.x + dx,
56
+ y: elmposition.current.y + dy,
57
+ };
58
+ elmposition.current = newPosition;
59
+ mousePosition.current = { x: event.clientX, y: event.clientY }; //マウス位置の保存
60
+ //ドラッグによるブロックの一時的移動
61
+ element.style.transform = `translate(${elmposition.current.x}px, ${elmposition.current.y}px)`;
62
+ };
63
+
64
+ const handleMouseUp = () => {
65
+ isDragging.current = false;
66
+ element.style.transform = null;
67
+ //呼出しもとに要素の位置を返す
68
+ onPositionChange({
69
+ x: `${elmposition.current.x}px`,
70
+ y: `${elmposition.current.y}px`,
71
+ });
72
+ };
73
+ const handleMouseLeave = () => {
74
+ isDragging.current = false;
75
+ };
76
+
77
+ if (element) {
78
+ // クラス名を追加します。
79
+ element.classList.add("itmar_isDraggable");
80
+ }
81
+ // イベントハンドラを追加します。
82
+ element.addEventListener("mousedown", handleMouseDown);
83
+ element.addEventListener("mousemove", handleMouseMove);
84
+ element.addEventListener("mouseup", handleMouseUp);
85
+ element.addEventListener("mouseleave", handleMouseLeave);
86
+
87
+ // イベントリスナーを削除するクリーンアップ関数を返します。
88
+ return () => {
89
+ element.removeEventListener("mousedown", handleMouseDown);
90
+ element.removeEventListener("mousemove", handleMouseMove);
91
+ element.removeEventListener("mouseup", handleMouseUp);
92
+ element.removeEventListener("mouseleave", handleMouseLeave);
93
+ element.style.transform = null;
94
+ };
95
+ }, [isMovable, blockRef, position, onPositionChange]); // 依存配列に isMovable を含めます
96
+ };
97
+
10
98
  export default function DraggableBox(props) {
11
99
  const position = props.attributes;
12
100
 
@@ -0,0 +1,403 @@
1
+ import {
2
+ Button,
3
+ Icon,
4
+ PanelRow,
5
+ ComboboxControl,
6
+ ToolbarDropdownMenu,
7
+ __experimentalNumberControl as NumberControl,
8
+ __experimentalUnitControl as UnitControl,
9
+ __experimentalInputControl as InputControl
10
+ } from '@wordpress/components';
11
+
12
+ import { useSelect, dispatch } from '@wordpress/data';
13
+ import { useState, useEffect, useRef } from '@wordpress/element';
14
+
15
+
16
+ import { __ } from '@wordpress/i18n';
17
+ import { justifyCenter, justifyLeft, justifyRight } from '@wordpress/icons';
18
+ //上よせアイコン
19
+ const upper = <Icon icon={justifyLeft} className="rotate-icon" />
20
+ //中央よせのアイコン
21
+ const middle = <Icon icon={justifyCenter} className="rotate-icon" />
22
+ //下よせのアイコン
23
+ const lower = <Icon icon={justifyRight} className="rotate-icon" />
24
+ // アイコンと文字列キーのマッピングを作成
25
+ const alignIconMap = {
26
+ left: justifyLeft,
27
+ center: justifyCenter,
28
+ right: justifyRight,
29
+ upper: upper,
30
+ middle: middle,
31
+ lower: lower
32
+ };
33
+
34
+ const units = [
35
+ { value: 'px', label: 'px' },
36
+ { value: 'em', label: 'em' },
37
+ { value: 'rem', label: 'rem' },
38
+ ];
39
+
40
+ const initializeUnitArray = (rowUnit, length) => {
41
+ if (!Array.isArray(rowUnit)) {
42
+ // rowUnit が配列ではない(undefined を含む)場合、全て "1fr" で埋めた配列を返す
43
+ return Array(length).fill("1fr");
44
+ }
45
+
46
+ return Array.from({ length }, (_, i) => rowUnit[i] || "1fr");
47
+ }
48
+
49
+ //r,cで与えられた座標がgridElmsのどの要素に含まれているかを返す
50
+ const findElementInGrid = (gridElms, r, c) => {
51
+ for (let i = 0; i < gridElms.length; i++) {
52
+ const { startCell, endCell } = gridElms[i];
53
+ // 各座標の最小値と最大値を決定
54
+ const minRow = Math.min(startCell?.rowInx, endCell?.rowInx);
55
+ const maxRow = Math.max(startCell?.rowInx, endCell?.rowInx);
56
+ const minCol = Math.min(startCell?.colInx, endCell?.colInx);
57
+ const maxCol = Math.max(startCell?.colInx, endCell?.colInx);
58
+
59
+ // 座標が範囲内にあるかどうかをチェック
60
+ if (r >= minRow && r <= maxRow && c >= minCol && c <= maxCol) {
61
+ return { index: i, elm: gridElms[i] };
62
+ }
63
+ }
64
+ return null;
65
+ }
66
+
67
+ //親にイベントを伝播させないラッパー
68
+ const StopPropagationWrapper = ({ children }) => {
69
+ const handleClick = (event) => {
70
+ // イベントの伝播を阻止
71
+ event.stopPropagation();
72
+ };
73
+
74
+ return (
75
+ <div className='itmar_event_stopper' onClick={handleClick}>
76
+ {children}
77
+ </div>
78
+ );
79
+ };
80
+
81
+ const GridControls = ({ attributes, clientId, onChange }) => {
82
+ const {
83
+ gridElms,
84
+ rowNum,
85
+ colNum,
86
+ rowGap,
87
+ colGap,
88
+ rowUnit,
89
+ colUnit
90
+ } = attributes;
91
+
92
+ //コンポーネント内の行列情報
93
+ const [rowCount, setRowCount] = useState(rowNum);
94
+ const [colCount, setColCount] = useState(colNum);
95
+
96
+ //マウント時検出用フラグ
97
+ const firstFlgRef = useRef(true);
98
+
99
+ //グリッドの配置指定用テーブル要素
100
+ const renderRows = () => {
101
+ //セルが埋まっているかどうかの判定配列
102
+
103
+ const occupied = new Array(rowCount).fill(0).map(() => new Array(colCount).fill(false));
104
+
105
+ let rows = [];
106
+ // 列単位入力行を追加
107
+ let headerCells = [<th key="header-corner"></th>]; // 左上の角の空白セル
108
+ for (let c = 0; c < colCount; c++) {
109
+ headerCells.push(
110
+ <th key={`header-${c}`}>
111
+ <InputControl
112
+ value={colUnit ? colUnit[c] : ""}
113
+ type="text"
114
+ isPressEnterToChange={true}
115
+ onChange={(newValue) => {
116
+ const newArray = [...colUnit.slice(0, c), newValue, ...colUnit.slice(c + 1)];
117
+ setUnitColArray(newArray);
118
+ }}
119
+ />
120
+ </th>
121
+ );
122
+ }
123
+ rows.push(<tr key="header-row">{headerCells}</tr>);
124
+
125
+ // 各行とセルの生成
126
+ for (let r = 0; r < rowCount; r++) {
127
+ let cells = [];
128
+ // 行行単位入力を追加
129
+ cells.push(
130
+ <th key={`row-header-${r}`}>
131
+ <InputControl
132
+ value={rowUnit ? rowUnit[r] : ""}
133
+ type="text"
134
+ isPressEnterToChange={true}
135
+ onChange={(newValue) => {
136
+ const newArray = [...rowUnit.slice(0, r), newValue, ...rowUnit.slice(r + 1)];
137
+ setUnitRowArray(newArray);
138
+ }}
139
+
140
+ />
141
+ </th>
142
+ );
143
+
144
+ // 各行に対するセルを生成
145
+ for (let c = 0; c < colCount; c++) {
146
+ if (occupied[r][c]) {
147
+ continue; // このセルは既に占められているのでスキップ
148
+ }
149
+ //複数のセルを占める設定があればセルの結合オブジェクトを生成
150
+ const setElm = findElementInGrid(gridElms, r, c);
151
+ const rowSpanValue = setElm ? Math.abs(setElm.elm.startCell.rowInx - setElm.elm.endCell.rowInx) : 0;
152
+ const colSpanValue = setElm ? Math.abs(setElm.elm.startCell.colInx - setElm.elm.endCell.colInx) : 0;
153
+ const cellSpan = {
154
+ ...(rowSpanValue !== 0 && { rowspan: rowSpanValue + 1 }),
155
+ ...(colSpanValue !== 0 && { colspan: colSpanValue + 1 })
156
+ };
157
+ // 占められるセルの位置を記録
158
+ for (let i = 0; i <= rowSpanValue; i++) {
159
+ for (let j = 0; j <= colSpanValue; j++) {
160
+ if (r + i < rowCount && c + j < colCount) {
161
+ occupied[r + i][c + j] = true;
162
+ }
163
+ }
164
+ }
165
+ //セルを生成
166
+ cells.push(<td
167
+ key={`cell-${r}-${c}`}
168
+ {...cellSpan}
169
+ className={isCellSelected(r, c) ? 'selected' : ''}
170
+ style={setElm ? { backgroundColor: `var(--wp--custom--color--area-${setElm.index})` } : undefined}
171
+ onClick={() => detectCellPosition(r, c)}
172
+ >
173
+ {setElm &&
174
+ <StopPropagationWrapper>
175
+ <ToolbarDropdownMenu
176
+ label={__('Lateral Alignment', 'block-collections')}
177
+ icon={setElm.elm.latAlign ? alignIconMap[setElm.elm.latAlign] : alignIconMap['left']}
178
+ controls={['left', 'center', 'right'].map(align => ({
179
+ icon: alignIconMap[align],
180
+ isActive: setElm.elm.latAlign === align,
181
+ onClick: () => updateAlignment(setElm.index, align, 'latAlign'),
182
+ }))}
183
+ />
184
+ <ToolbarDropdownMenu
185
+ label={__('Vertical Alignment', 'block-collections')}
186
+ icon={setElm.elm.vertAlign ? alignIconMap[setElm.elm.vertAlign] : alignIconMap['upper']}
187
+ controls={['upper', 'middle', 'lower'].map(align => ({
188
+ icon: alignIconMap[align],
189
+ isActive: setElm.elm.vertAlign === align,
190
+ onClick: () => updateAlignment(setElm.index, align, 'vertAlign'),
191
+ }))}
192
+ />
193
+ </StopPropagationWrapper>
194
+ }
195
+ </td>)
196
+ }
197
+ // 行の追加
198
+ rows.push(<tr key={`row-${r}`}>{cells}</tr>);
199
+ }
200
+ return rows;
201
+ };
202
+
203
+ //テーブルの位置選択関数
204
+ const detectCellPosition = (rowIndex, colIndex) => {
205
+ //インナーブロックの選択がなければリターン
206
+ if (!selBlock) {
207
+ dispatch('core/notices').createNotice(
208
+ 'error',
209
+ __('No blocks selected.', 'itmar_guest_contact_block'),
210
+ { type: 'snackbar', isDismissible: true, }
211
+ );
212
+ return;
213
+ }
214
+ //選択済みのセルが選択されたときはリターン
215
+ if (findElementInGrid(gridElms, rowIndex, colIndex)) {
216
+ dispatch('core/notices').createNotice(
217
+ 'error',
218
+ __('That cell is already selected by another block.', 'itmar_guest_contact_block'),
219
+ { type: 'snackbar', isDismissible: true, }
220
+ );
221
+ return;
222
+ }
223
+
224
+ //選択されたブロックのポジションを記録
225
+ const newBlock = !selBlock.startCell
226
+ ? { ...selBlock, startCell: { rowInx: rowIndex, colInx: colIndex }, endCell: { rowInx: rowIndex, colInx: colIndex } }
227
+ : { ...selBlock, endCell: { rowInx: rowIndex, colInx: colIndex } };
228
+
229
+ setSelBlock(newBlock);
230
+
231
+ //blockNamesの更新
232
+ const index = gridElms?.findIndex((block) => block.value === selBlock.value);
233
+ const setAreaBlock = [...blockNames.slice(0, index), newBlock, ...blockNames.slice(index + 1)];
234
+ setBlockNames(setAreaBlock);
235
+ };
236
+
237
+ // セルが選択されているか判断する関数
238
+ const isCellSelected = (rowIndex, colIndex) => {
239
+ if (selBlock) {
240
+ // 各座標の最小値と最大値を決定
241
+ const minRow = Math.min(selBlock.startCell?.rowInx, selBlock.endCell?.rowInx);
242
+ const maxRow = Math.max(selBlock.startCell?.rowInx, selBlock.endCell?.rowInx);
243
+ const minCol = Math.min(selBlock.startCell?.colInx, selBlock.endCell?.colInx);
244
+ const maxCol = Math.max(selBlock.startCell?.colInx, selBlock.endCell?.colInx);
245
+
246
+ // 座標が範囲内にあるかどうかをチェック
247
+ return (
248
+ rowIndex >= minRow && rowIndex <= maxRow &&
249
+ colIndex >= minCol && colIndex <= maxCol
250
+ );
251
+ } else {
252
+ return false;
253
+ }
254
+
255
+ };
256
+
257
+ //コンテンツ位置設定
258
+ const updateAlignment = (index, align, derection) => {
259
+ const alignBlock = { ...blockNames[index], [derection]: align };
260
+ const setAlignBlock = [...blockNames.slice(0, index), alignBlock, ...blockNames.slice(index + 1)];
261
+ setBlockNames(setAlignBlock);
262
+ }
263
+
264
+ //選択したインナーブロック
265
+ const [selBlock, setSelBlock] = useState(null);
266
+
267
+ //インナーブロックを取得
268
+ const parentBlocks = useSelect((select) => {
269
+ const innerBlocks = select('core/block-editor').getBlocks(clientId);
270
+ //インナーブロック入れ替えの際は既に登録したブロックの位置情報があれば、それを付加する。
271
+ const new_block_names = innerBlocks.map((block, index) => gridElms.length > index ? {
272
+ value: block.clientId,
273
+ label: block.name,
274
+ startCell: gridElms[index].startCell,
275
+ endCell: gridElms[index].endCell,
276
+ latAlign: gridElms[index].latAlign,
277
+ vertAlign: gridElms[index].vertAlign
278
+ } :
279
+ {
280
+ value: block.clientId,
281
+ label: block.name
282
+ }
283
+ );
284
+ return new_block_names
285
+ }, [clientId]);
286
+ const [blockNames, setBlockNames] = useState(parentBlocks);
287
+
288
+ //グリッド配置のクリア
289
+ const clear_placement = () => {
290
+ //ブロックの配置情報削除
291
+ const clear_block = blockNames.map((block) => ({
292
+ value: block.value,
293
+ label: block.label
294
+ }
295
+ ));
296
+ setBlockNames(clear_block);
297
+
298
+ }
299
+
300
+ //単位配列の初期化
301
+ const initRowUnitArray = initializeUnitArray(rowUnit, rowCount);
302
+ const [unitRowArray, setUnitRowArray] = useState(initRowUnitArray);
303
+ const initColUnitArray = initializeUnitArray(colUnit, colCount);;
304
+ const [unitColArray, setUnitColArray] = useState(initColUnitArray);
305
+
306
+ //親ブロックへの書き戻し
307
+ useEffect(() => {
308
+ const gridStyle = { ...attributes, gridElms: blockNames, rowNum: rowCount, colNum: colCount, rowUnit: unitRowArray, colUnit: unitColArray };
309
+
310
+ onChange(gridStyle);
311
+
312
+ }, [blockNames, unitRowArray, unitColArray]);
313
+
314
+ //行と列の数を変えた場合は位置情報を削除・単位の再編成
315
+ useEffect(() => {
316
+ if (!firstFlgRef.current) {//マウント時は実行しない
317
+ //ブロックの位置情報クリア
318
+ clear_placement();
319
+ //単位情報の再編成
320
+ const newRowUnitArray = initializeUnitArray(rowUnit, rowCount);
321
+ setUnitRowArray(newRowUnitArray);
322
+ const newColUnitArray = initializeUnitArray(colUnit, colCount);
323
+ setUnitColArray(newColUnitArray);
324
+ } else {
325
+ firstFlgRef.current = false
326
+ }
327
+
328
+ }, [rowCount, colCount]);
329
+
330
+ return (
331
+ <>
332
+ <PanelRow
333
+ className='distance_row'
334
+ >
335
+ <NumberControl
336
+ onChange={(newValue) => {
337
+ const input_val = typeof (newValue) === 'number' ? newValue : Number(newValue);
338
+ setRowCount(input_val);
339
+ }}
340
+ label={__('Number of Row ', 'block-collections')}
341
+ value={rowCount}
342
+ min={2}
343
+ />
344
+ <NumberControl
345
+ onChange={(newValue) => {
346
+ const input_val = typeof (newValue) === 'number' ? newValue : Number(newValue);
347
+ setColCount(input_val);
348
+ }}
349
+ label={__('Number of Colum', 'block-collections')}
350
+ value={colCount}
351
+ />
352
+ </PanelRow>
353
+ <PanelRow
354
+ className='distance_row'
355
+ >
356
+ <UnitControl
357
+ onChange={(newValue) => {
358
+ newValue = newValue != '' ? newValue : '0px'
359
+ const newStyle = { ...attributes, rowGap: newValue };
360
+ onChange(newStyle);
361
+ }}
362
+ label={__('Row Gap', 'block-collections')}
363
+ value={rowGap}
364
+ units={units}
365
+ />
366
+ <UnitControl
367
+ onChange={(newValue) => {
368
+ newValue = newValue != '' ? newValue : '0px'
369
+ const newStyle = { ...attributes, colGap: newValue };
370
+ onChange(newStyle);
371
+ }}
372
+ label={__('Colum Gap', 'block-collections')}
373
+ value={colGap}
374
+ units={units}
375
+ />
376
+
377
+ </PanelRow>
378
+
379
+ <PanelRow className='distance_row'>
380
+ <p>{__('Element placement', 'block-collections')}</p>
381
+ <Button variant="secondary" onClick={clear_placement}>
382
+ {__("Clear", 'block-collections')}
383
+ </Button>
384
+ </PanelRow>
385
+
386
+ <PanelRow className='grid_table' >
387
+ <table>
388
+ {renderRows()}
389
+ </table>
390
+ </PanelRow>
391
+ <ComboboxControl
392
+ label={__('InnerBlock Name', 'block-collections')}
393
+ options={blockNames}
394
+ value={selBlock ? selBlock.value : null}
395
+ onChange={(sel_id) => {
396
+ const matchedBlock = blockNames.find(block => block.value === sel_id);
397
+ setSelBlock(matchedBlock)
398
+ }}
399
+ />
400
+ </>
401
+ );
402
+ };
403
+ export default GridControls;
@@ -0,0 +1,139 @@
1
+
2
+ import { __ } from '@wordpress/i18n';
3
+
4
+ import {
5
+ TextControl,
6
+ PanelRow,
7
+ RadioControl,
8
+ ComboboxControl,
9
+ __experimentalUnitControl as UnitControl,
10
+ } from '@wordpress/components';
11
+
12
+ import {
13
+ PanelColorSettings
14
+ } from '@wordpress/block-editor';
15
+
16
+
17
+ const helpLink = createElement(
18
+ 'a',
19
+ { href: 'https://fontawesome.com/search', target: '_blank' },
20
+ 'FontAwesome'
21
+ );
22
+
23
+ const helpTextCode = createElement(
24
+ 'span',
25
+ {},
26
+ helpLink,
27
+ __('Select the icon from and enter Unicode (the upper right four digits of the selection dialog). ', 'block-collections')
28
+ );
29
+
30
+ const helpTextFamily = createElement(
31
+ 'span',
32
+ {},
33
+ helpLink,
34
+ __('Please select the first class name shown in the HTML code field of the selection dialog. ', 'block-collections')
35
+ );
36
+
37
+
38
+ const units = [
39
+ { value: 'px', label: 'px' },
40
+ { value: 'em', label: 'em' },
41
+ { value: 'rem', label: 'rem' },
42
+ ];
43
+
44
+ const family_option = [
45
+ { value: 'Font Awesome 6 Free', label: 'SOLID' },
46
+ { value: 'Font Awesome 6 Brands', label: 'BRANDS' },
47
+ ]
48
+
49
+ export default ({ iconStyle, onChange }) => {
50
+ const {
51
+ icon_name,
52
+ icon_pos,
53
+ icon_size,
54
+ icon_color,
55
+ icon_space,
56
+ icon_family
57
+ } = iconStyle;
58
+
59
+ return (
60
+ <>
61
+ <TextControl
62
+ label={__("icon name", 'block-collections')}
63
+ help={helpTextCode}
64
+ labelPosition="top"
65
+ value={icon_name}
66
+ isPressEnterToChange
67
+ onChange={(newValue) => {
68
+ const newStyle = { ...iconStyle, icon_name: newValue };
69
+ onChange(newStyle);
70
+ }}
71
+ />
72
+
73
+ <ComboboxControl
74
+ label={__('Icon Family', 'block-collections')}
75
+ help={helpTextFamily}
76
+ options={family_option}
77
+ value={icon_family ? icon_family : 'Font Awesome 6 Free'}
78
+ onChange={(newValue) => {
79
+ const newStyle = { ...iconStyle, icon_family: newValue };
80
+ onChange(newStyle);
81
+ }}
82
+ />
83
+
84
+ <PanelRow className='sizing_row'>
85
+ <UnitControl
86
+ dragDirection="e"
87
+ onChange={(newValue) => {
88
+ const newStyle = { ...iconStyle, icon_size: newValue };
89
+ onChange(newStyle);
90
+ }}
91
+ label={__("Size", 'block-collections')}
92
+ value={icon_size}
93
+ units={units}
94
+ />
95
+ <UnitControl
96
+ dragDirection="e"
97
+ onChange={(newValue) => {
98
+ const newStyle = { ...iconStyle, icon_space: newValue };
99
+ onChange(newStyle);
100
+ }}
101
+ label={__('spacing to end', 'block-collections')}
102
+ value={icon_space}
103
+ units={units}
104
+ />
105
+ </PanelRow>
106
+
107
+ <PanelColorSettings
108
+ title={__('Color settings', 'itmar_location')}
109
+ initialOpen={false}
110
+ colorSettings={[
111
+ {
112
+ value: icon_color,
113
+ onChange: (newValue) => {
114
+ const newStyle = { ...iconStyle, icon_color: newValue };
115
+ onChange(newStyle);
116
+ },
117
+ label: __('Icon color', 'itmar_location')
118
+ },
119
+
120
+ ]}
121
+ />
122
+ <label className="components-base-control__label">{__("Arrangement", 'block-collections')}</label>
123
+ <PanelRow className='itmar_position_row'>
124
+ <RadioControl
125
+ selected={icon_pos}
126
+ options={[
127
+ { label: __("left", 'block-collections'), value: "left" },
128
+ { label: __("right", 'block-collections'), value: "right" },
129
+ ]}
130
+ onChange={(newValue) => {
131
+ const newStyle = { ...iconStyle, icon_pos: newValue };
132
+ onChange(newStyle);
133
+ }}
134
+ />
135
+ </PanelRow>
136
+ </>
137
+
138
+ );
139
+ }
package/src/PseudoElm.js CHANGED
@@ -1,6 +1,39 @@
1
1
  import { __ } from "@wordpress/i18n";
2
+ import { css } from "styled-components";
2
3
  import { RadioControl } from "@wordpress/components";
3
4
 
5
+ // 矢印の向きに応じたスタイルを生成するヘルパー関数
6
+ const arrowDirectionStyles = (direction) => {
7
+ switch (direction) {
8
+ case "left":
9
+ return "transform: translate(-50%, -50%) rotate(-135deg);";
10
+ case "right":
11
+ return "transform: translate(-50%, -50%) rotate(45deg);";
12
+ case "upper":
13
+ return "transform: translate(-50%, -50%) rotate(-45deg);";
14
+ case "under":
15
+ return "transform: translate(-50%, -50%) rotate(135deg);";
16
+ default:
17
+ return "transform: translate(-50%, -50%) rotate(45deg);"; // default to 'down'
18
+ }
19
+ };
20
+
21
+ // 矢印のスタイルを適用するコンポーネント
22
+ export const Arrow = ({ direction = "down" }) => css`
23
+ &::after {
24
+ content: "";
25
+ position: absolute;
26
+ display: block;
27
+ width: 15%;
28
+ height: 15%;
29
+ border-top: 3px solid var(--wp--preset--color--accent-2);
30
+ border-right: 3px solid var(--wp--preset--color--accent-2);
31
+ top: 50%;
32
+ left: 50%;
33
+ ${arrowDirectionStyles(direction)}
34
+ }
35
+ `;
36
+
4
37
  //擬似要素の出力を選択させるインスペクターコントロール
5
38
  const PseudoElm = ({ direction, onChange }) => {
6
39
  return (