itmar-block-packages 1.7.0 → 1.7.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "itmar-block-packages",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "description": "We have put together a package of common React components used for WordPress custom blocks.",
5
5
  "main": "build/index.js",
6
6
  "scripts": {
package/src/BlockPlace.js CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  ToolbarGroup,
12
12
  ToolbarItem,
13
13
  RangeControl,
14
+ TextControl,
14
15
  RadioControl,
15
16
  ToggleControl,
16
17
  Modal,
@@ -59,6 +60,8 @@ export default function BlockPlace(props) {
59
60
  const center_cross =
60
61
  sel_pos.direction === "vertical" ? justifyCenter : middle;
61
62
  const end_cross = sel_pos.direction === "vertical" ? justifyRight : lower;
63
+ const stretch =
64
+ sel_pos.direction === "vertical" ? justifyStretch : vert_between;
62
65
  const between_icon =
63
66
  sel_pos.direction === "vertical" ? vert_between : justifyStretch;
64
67
  const around_icon =
@@ -82,12 +85,14 @@ export default function BlockPlace(props) {
82
85
  : __("lower alignment", "block-collections");
83
86
 
84
87
  const [isContainer, setIsContainer] = useState(false);
88
+ const [isFlexItem, setIsFlexItem] = useState(false);
85
89
  const [direction, setDirection] = useState("row");
86
90
  useEffect(() => {
87
91
  if (blockRef.current) {
88
92
  const element = blockRef.current;
89
93
  const parentElement = element.parentElement;
90
94
  const grandparentElement = parentElement?.parentElement;
95
+
91
96
  const computedStyle = getComputedStyle(grandparentElement);
92
97
  //親要素がFlex又はGridコンテナか
93
98
  if (
@@ -103,6 +108,7 @@ export default function BlockPlace(props) {
103
108
  computedStyle.display === "flex" ||
104
109
  computedStyle.display === "inline-flex"
105
110
  ) {
111
+ setIsFlexItem(true);
106
112
  if (
107
113
  computedStyle.flexDirection === "row" ||
108
114
  computedStyle.flexDirection === "row-reverse"
@@ -270,7 +276,7 @@ export default function BlockPlace(props) {
270
276
  props.onFlexChange("space-between", "inner_align")
271
277
  } //親コンポーネントに通知
272
278
  icon={between_icon}
273
- label={__("beteen stretch", "block-collections")}
279
+ label={__("stretch", "block-collections")}
274
280
  />
275
281
  )}
276
282
  </ToolbarItem>
@@ -335,6 +341,17 @@ export default function BlockPlace(props) {
335
341
  />
336
342
  )}
337
343
  </ToolbarItem>
344
+ <ToolbarItem>
345
+ {(itemProps) => (
346
+ <Button
347
+ {...itemProps}
348
+ isPressed={sel_pos.inner_items === "stretch"}
349
+ onClick={() => props.onFlexChange("stretch", "inner_items")} //親コンポーネントに通知
350
+ icon={stretch}
351
+ label={__("beteen stretch", "block-collections")}
352
+ />
353
+ )}
354
+ </ToolbarItem>
338
355
  </ToolbarGroup>
339
356
  )}
340
357
  {isContainer && (
@@ -413,6 +430,21 @@ export default function BlockPlace(props) {
413
430
  />
414
431
  )}
415
432
  </ToolbarItem>
433
+ <ToolbarItem>
434
+ {(itemProps) => (
435
+ <Button
436
+ {...itemProps}
437
+ isPressed={sel_pos.outer_vertical === "stretch"}
438
+ onClick={
439
+ direction === "row"
440
+ ? () => props.onVerticalChange("stretch")
441
+ : () => props.onAlignChange("stretch")
442
+ }
443
+ icon={direction === "row" ? vert_between : justifyStretch}
444
+ label={__("stretch", "block-collections")}
445
+ />
446
+ )}
447
+ </ToolbarItem>
416
448
  </ToolbarGroup>
417
449
  </>
418
450
  )}
@@ -427,6 +459,50 @@ export default function BlockPlace(props) {
427
459
  }
428
460
  />
429
461
 
462
+ {isFlexItem && (
463
+ <PanelRow className="position_row">
464
+ <TextControl
465
+ label={__("grow", "block-collections")}
466
+ labelPosition="left"
467
+ value={sel_pos.flex?.grow}
468
+ onChange={(newValue) => {
469
+ const flexObj = {
470
+ grow: newValue,
471
+ shrink: sel_pos.flex?.shrink,
472
+ basis: sel_pos.flex?.basis,
473
+ };
474
+ props.onFlexItemChange(flexObj);
475
+ }}
476
+ />
477
+ <TextControl
478
+ label={__("shrink", "block-collections")}
479
+ labelPosition="left"
480
+ value={sel_pos.flex?.shrink}
481
+ onChange={(newValue) => {
482
+ const flexObj = {
483
+ grow: sel_pos.flex?.grow,
484
+ shrink: newValue,
485
+ basis: sel_pos.flex?.basis,
486
+ };
487
+ props.onFlexItemChange(flexObj);
488
+ }}
489
+ />
490
+ <TextControl
491
+ label={__("basis", "block-collections")}
492
+ labelPosition="left"
493
+ value={sel_pos.flex?.basis}
494
+ onChange={(newValue) => {
495
+ const flexObj = {
496
+ grow: sel_pos.flex?.grow,
497
+ shrink: sel_pos.flex?.shrink,
498
+ basis: newValue,
499
+ };
500
+ props.onFlexItemChange(flexObj);
501
+ }}
502
+ />
503
+ </PanelRow>
504
+ )}
505
+
430
506
  <BlockHeight
431
507
  attributes={attributes}
432
508
  isMobile={isMobile}
@@ -603,7 +679,7 @@ export default function BlockPlace(props) {
603
679
  }
604
680
 
605
681
  export function BlockWidth(props) {
606
- const { attributes, isMobile, isSubmenu } = props;
682
+ const { attributes, isMobile, flexDirection, isSubmenu } = props;
607
683
  const { default_val, mobile_val } = attributes;
608
684
 
609
685
  //モバイルかデスクトップか
@@ -805,6 +881,16 @@ export function BlockHeight(props) {
805
881
  />
806
882
  )}
807
883
  </ToolbarItem>
884
+ <ToolbarItem>
885
+ {(itemProps) => (
886
+ <Button
887
+ {...itemProps}
888
+ isPressed={sel_pos.height_val === "auto"}
889
+ onClick={() => props.onHeightChange("auto")}
890
+ text="auto"
891
+ />
892
+ )}
893
+ </ToolbarItem>
808
894
  </ToolbarGroup>
809
895
  {sel_pos.height_val === "free" && (
810
896
  <UnitControl
package/src/blockStore.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { useSelect } from "@wordpress/data";
2
2
  import { store as blockEditorStore } from "@wordpress/block-editor";
3
+ import { createBlock } from "@wordpress/blocks";
3
4
 
4
5
  export const useTargetBlocks = (
5
6
  clientId,
@@ -52,3 +53,23 @@ export const flattenBlocks = (blocks) => {
52
53
  return acc;
53
54
  }, []);
54
55
  };
56
+
57
+ // 再帰的にブロック構造をシリアライズする関数
58
+ export const serializeBlockTree = (block) => {
59
+ return {
60
+ blockName: block.name,
61
+ attributes: block.attributes,
62
+ innerBlocks:
63
+ block.innerBlocks.length > 0
64
+ ? block.innerBlocks.map(serializeBlockTree)
65
+ : [],
66
+ };
67
+ };
68
+ // シリアライズしたブロックデータをもとの階層構造に戻す関数
69
+ export const createBlockTree = (blockData) => {
70
+ const inner = Array.isArray(blockData.innerBlocks)
71
+ ? blockData.innerBlocks.map(createBlockTree)
72
+ : [];
73
+
74
+ return createBlock(blockData.blockName, blockData.attributes, inner);
75
+ };
@@ -90,7 +90,9 @@ export const width_prm = (width, free_val) => {
90
90
  ? ` width: ${free_val}; `
91
91
  : width === "full"
92
92
  ? " width: 100%;"
93
- : " width: fit-content;";
93
+ : width === "fit"
94
+ ? " width: fit-content;"
95
+ : " width: auto;";
94
96
  return ret_width_prm;
95
97
  };
96
98
 
@@ -98,9 +100,11 @@ export const height_prm = (height, free_val) => {
98
100
  const ret_height_prm =
99
101
  height === "fit"
100
102
  ? " height: fit-content;"
103
+ : height === "full"
104
+ ? ` height: 100%; `
101
105
  : height === "free"
102
106
  ? ` height: ${free_val}; `
103
- : "height: 100%;";
107
+ : "height: auto;";
104
108
  return ret_height_prm;
105
109
  };
106
110
  //配置を返す
package/src/index.js CHANGED
@@ -48,7 +48,13 @@ export { default as ShadowStyle, ShadowElm } from "./ShadowStyle";
48
48
  export { default as PseudoElm, Arrow } from "./PseudoElm";
49
49
 
50
50
  //メディアライブラリから複数の画像を選択するコントロール
51
- export { SingleImageSelect, MultiImageSelect } from "./mediaUpload";
51
+ export {
52
+ SingleImageSelect,
53
+ MultiImageSelect,
54
+ getMediaType,
55
+ getImageAspectRatio,
56
+ getVideoAspectRatio,
57
+ } from "./mediaUpload";
52
58
 
53
59
  //ブロックのドラッガブルを設定するコントロール
54
60
  export { default as DraggableBox, useDraggingMove } from "./DraggableBox";
@@ -89,7 +95,12 @@ export {
89
95
  } from "./DateElm";
90
96
 
91
97
  //インナーブロック関連の関数
92
- export { flattenBlocks, useTargetBlocks } from "./blockStore";
98
+ export {
99
+ flattenBlocks,
100
+ useTargetBlocks,
101
+ serializeBlockTree,
102
+ createBlockTree,
103
+ } from "./blockStore";
93
104
 
94
105
  //バリデーションチェック関連の関数
95
106
  export { isValidUrlWithUrlApi } from "./validationCheck";
@@ -113,3 +113,66 @@ export function MultiImageSelect(props) {
113
113
  </PanelBody>
114
114
  );
115
115
  }
116
+
117
+ //静止画か動画かを判定する関数
118
+ export function getMediaType(url) {
119
+ const imageExtensions = [
120
+ ".jpg",
121
+ ".jpeg",
122
+ ".png",
123
+ ".gif",
124
+ ".webp",
125
+ ".bmp",
126
+ ".svg",
127
+ ];
128
+ const videoExtensions = [".mp4", ".webm", ".ogg", ".mov", ".m4v"];
129
+
130
+ // クエリストリング(?以降)を除去
131
+ const cleanUrl = url.split("?")[0].toLowerCase();
132
+
133
+ const isImage = imageExtensions.some((ext) => cleanUrl.endsWith(ext));
134
+ const isVideo = videoExtensions.some((ext) => cleanUrl.endsWith(ext));
135
+
136
+ if (isImage) {
137
+ return "image";
138
+ } else if (isVideo) {
139
+ return "video";
140
+ } else {
141
+ // 拡張子で判別できない → HEADリクエストでContent-Type判定 or fallback
142
+ return undefined;
143
+ }
144
+ }
145
+ //静止画のアスペクト比を返す関数
146
+ export function getImageAspectRatio(url) {
147
+ return new Promise((resolve, reject) => {
148
+ const img = new Image();
149
+ img.onload = function () {
150
+ const aspectRatio = img.naturalWidth / img.naturalHeight;
151
+ resolve(aspectRatio);
152
+ };
153
+ img.onerror = function () {
154
+ reject(new Error("画像の読み込みに失敗しました: " + url));
155
+ };
156
+ img.src = url;
157
+ });
158
+ }
159
+ //動画のアスペクト比を返す関数
160
+ export function getVideoAspectRatio(url) {
161
+ return new Promise((resolve, reject) => {
162
+ const video = document.createElement("video");
163
+
164
+ video.preload = "metadata";
165
+ video.src = url;
166
+ video.muted = true; // 一部のブラウザで安全に動作させるため
167
+ video.playsInline = true;
168
+
169
+ video.onloadedmetadata = function () {
170
+ const aspectRatio = video.videoWidth / video.videoHeight;
171
+ resolve(aspectRatio);
172
+ };
173
+
174
+ video.onerror = function () {
175
+ reject(new Error("動画の読み込みに失敗しました: " + url));
176
+ };
177
+ });
178
+ }