itmar-block-packages 1.9.0 → 1.10.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.
- package/README.md +5 -0
- package/build/index.asset.php +1 -1
- package/build/index.js +3 -3
- package/package.json +1 -1
- package/src/BrockInserter.js +247 -0
- package/src/MasonryControl.js +125 -0
- package/src/SwiperControl.js +265 -0
- package/src/customFooks.js +1 -0
- package/src/index.js +9 -0
- package/src/wordpressApi.js +197 -26
package/package.json
CHANGED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import {
|
|
2
|
+
serializeBlockTree,
|
|
3
|
+
createBlockTree,
|
|
4
|
+
flattenBlocks,
|
|
5
|
+
} from "./blockStore";
|
|
6
|
+
import { createBlock, getBlockType } from "@wordpress/blocks";
|
|
7
|
+
import { useEffect } from "@wordpress/element";
|
|
8
|
+
import { useSelect, useDispatch } from "@wordpress/data";
|
|
9
|
+
|
|
10
|
+
//フィールド生成用関数
|
|
11
|
+
const createBlockAttr = (selectedField) => {
|
|
12
|
+
let blockAttributes = {};
|
|
13
|
+
|
|
14
|
+
switch (selectedField.block) {
|
|
15
|
+
case "itmar/design-title":
|
|
16
|
+
const block_class = selectedField.key.startsWith("tax_")
|
|
17
|
+
? selectedField.key
|
|
18
|
+
: `sp_field_${selectedField.key}`;
|
|
19
|
+
blockAttributes = {
|
|
20
|
+
className: block_class,
|
|
21
|
+
headingContent: `[${selectedField.label}]`,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
break;
|
|
25
|
+
case "core/paragraph":
|
|
26
|
+
blockAttributes = {
|
|
27
|
+
className: `itmar_ex_block sp_field_${selectedField.key}`,
|
|
28
|
+
content: `[${selectedField.label}]`,
|
|
29
|
+
};
|
|
30
|
+
break;
|
|
31
|
+
case "core/image":
|
|
32
|
+
blockAttributes = {
|
|
33
|
+
className: `itmar_ex_block sp_field_${selectedField.key}`,
|
|
34
|
+
url: `${ec_relate_blocks.plugin_url}/assets/image/main_sample.png`,
|
|
35
|
+
};
|
|
36
|
+
break;
|
|
37
|
+
case "itmar/slide-mv":
|
|
38
|
+
const spaceAttributes = {
|
|
39
|
+
margin_val: {
|
|
40
|
+
type: "object",
|
|
41
|
+
default: {
|
|
42
|
+
top: "0em",
|
|
43
|
+
left: "0em",
|
|
44
|
+
bottom: "0em",
|
|
45
|
+
right: "0em",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
padding_val: {
|
|
49
|
+
type: "object",
|
|
50
|
+
default: {
|
|
51
|
+
top: "0em",
|
|
52
|
+
left: "0em",
|
|
53
|
+
bottom: "0em",
|
|
54
|
+
right: "0em",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const imageBlock = createBlock("core/image", {
|
|
60
|
+
className: "itmar_ex_block",
|
|
61
|
+
url: `${ec_relate_blocks.plugin_url}/assets/image/slide_sample.png`,
|
|
62
|
+
...spaceAttributes,
|
|
63
|
+
});
|
|
64
|
+
//Design Blockの初期設定を取得
|
|
65
|
+
const blockType = getBlockType("itmar/design-group");
|
|
66
|
+
const defaultValBase = blockType?.attributes?.default_val?.default ?? {};
|
|
67
|
+
const mobileValBase = blockType?.attributes?.mobile_val?.default ?? {};
|
|
68
|
+
const slideBlock = createBlock(
|
|
69
|
+
"itmar/design-group",
|
|
70
|
+
{
|
|
71
|
+
default_val: {
|
|
72
|
+
...defaultValBase,
|
|
73
|
+
width_val: "fit",
|
|
74
|
+
},
|
|
75
|
+
mobile_val: {
|
|
76
|
+
...mobileValBase,
|
|
77
|
+
width_val: "fit",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
[imageBlock]
|
|
81
|
+
);
|
|
82
|
+
//slideBlock をシリアライズ
|
|
83
|
+
const serializedSlide = serializeBlockTree(slideBlock);
|
|
84
|
+
// 同じスライドブロックを5つ複製(独立したブロックとして)
|
|
85
|
+
const slideBlocks = Array.from({ length: 5 }, () =>
|
|
86
|
+
createBlockTree(serializedSlide)
|
|
87
|
+
);
|
|
88
|
+
//子ブロック付きで返す
|
|
89
|
+
blockAttributes = {
|
|
90
|
+
attributes: { className: `sp_field_${selectedField.key}` },
|
|
91
|
+
slideBlocks: slideBlocks,
|
|
92
|
+
};
|
|
93
|
+
break;
|
|
94
|
+
default:
|
|
95
|
+
blockAttributes = {
|
|
96
|
+
className: `sp_field_${selectedField.key}`,
|
|
97
|
+
headingContent: `[${selectedField.label}]`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return blockAttributes;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
//表示フィールド変更によるインナーブロックの再構成
|
|
104
|
+
export const useRebuildChangeField = (
|
|
105
|
+
dispAttributeArray,
|
|
106
|
+
selectedFields,
|
|
107
|
+
pickupType,
|
|
108
|
+
dispTaxonomies,
|
|
109
|
+
sectionCount,
|
|
110
|
+
domType,
|
|
111
|
+
clientId,
|
|
112
|
+
insertId
|
|
113
|
+
) => {
|
|
114
|
+
// dispatch関数を取得
|
|
115
|
+
const { replaceInnerBlocks } = useDispatch("core/block-editor");
|
|
116
|
+
const pickupBlock = useSelect(
|
|
117
|
+
(select) => select("core/block-editor").getBlock(clientId),
|
|
118
|
+
[clientId]
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
//dispAttributeArray の個数調整
|
|
123
|
+
const blocksLength = dispAttributeArray.length;
|
|
124
|
+
|
|
125
|
+
if (blocksLength < sectionCount) {
|
|
126
|
+
// dispAttributeArrayの長さが短い場合、{}を追加する
|
|
127
|
+
const diff = sectionCount - blocksLength;
|
|
128
|
+
for (let i = 0; i < diff; i++) {
|
|
129
|
+
dispAttributeArray.push({});
|
|
130
|
+
}
|
|
131
|
+
} else {
|
|
132
|
+
// dispAttributeArrayの長さが長い場合、余分な要素を削除する
|
|
133
|
+
dispAttributeArray.splice(sectionCount);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// インナーブロックに差し込むブロック配列を生成
|
|
137
|
+
const blocksArray = dispAttributeArray.map((dispAttribute, unit_index) => {
|
|
138
|
+
// blocksAttributesArray属性で登録されたブロックのclassName一覧(sp_field_xxx を拾う)
|
|
139
|
+
const allBlocks = Array.isArray(dispAttribute.innerBlocks)
|
|
140
|
+
? flattenBlocks(dispAttribute.innerBlocks) //階層になったブロックを平坦化
|
|
141
|
+
: [];
|
|
142
|
+
|
|
143
|
+
const existingKeys = allBlocks
|
|
144
|
+
.map((block) => block.attributes?.className)
|
|
145
|
+
.filter(Boolean)
|
|
146
|
+
.map((cls) => {
|
|
147
|
+
// sp_field_◯◯ か tax_◯◯ のどちらかにマッチ
|
|
148
|
+
const match = cls.match(/sp_field_([\w-]+)|(tax_[\w-]+)/);
|
|
149
|
+
if (!match) return null;
|
|
150
|
+
|
|
151
|
+
// match[1] があれば sp_field_ のほう → プレフィックス除去
|
|
152
|
+
// match[2] があれば tax_ のほう → そのまま返す
|
|
153
|
+
return match[1] ?? match[2];
|
|
154
|
+
})
|
|
155
|
+
.filter(Boolean);
|
|
156
|
+
|
|
157
|
+
// dispTaxonomies からオブジェクトを作って selectedFieldsに加えてnewSelectedFieldsを生成
|
|
158
|
+
const newSelectedFields = [
|
|
159
|
+
...selectedFields,
|
|
160
|
+
...dispTaxonomies.map((tax) => ({
|
|
161
|
+
key: `tax_${tax}`, // 例: "tax_category"
|
|
162
|
+
label: tax, // 例: "category"
|
|
163
|
+
block: "itmar/design-title",
|
|
164
|
+
})),
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
// newSelectedFieldsのうち未挿入のものだけ追加
|
|
168
|
+
const autoGeneratedBlocks = newSelectedFields
|
|
169
|
+
.filter((field) => !existingKeys.includes(field.key))
|
|
170
|
+
.map((field) => {
|
|
171
|
+
const attr = createBlockAttr(field);
|
|
172
|
+
const blockName = field.block;
|
|
173
|
+
const blockAttributes = attr?.attributes ?? attr;
|
|
174
|
+
const innerBlocks = Array.isArray(attr?.slideBlocks)
|
|
175
|
+
? attr.slideBlocks
|
|
176
|
+
: [];
|
|
177
|
+
|
|
178
|
+
return createBlock(blockName, blockAttributes, innerBlocks);
|
|
179
|
+
});
|
|
180
|
+
// blocksAttributesArray属性で登録されたブロックの再構築
|
|
181
|
+
const selectedKeys = selectedFields.map((f) => f.key);
|
|
182
|
+
|
|
183
|
+
const filterBlocksRecursively = (blocks) => {
|
|
184
|
+
return blocks
|
|
185
|
+
.map((block) => {
|
|
186
|
+
const className = block.attributes?.className || "";
|
|
187
|
+
// 1. まず sp_field_ のパターンを探す
|
|
188
|
+
let match = className.match(/sp_field_([a-zA-Z0-9_]+)/);
|
|
189
|
+
// 2. 見つからなければ tax_○○ をチェック
|
|
190
|
+
if (className.startsWith("tax_")) {
|
|
191
|
+
const name = className.slice("tax_".length); // "tax_category" → "category"
|
|
192
|
+
|
|
193
|
+
// dispTaxonomies に含まれないものだけ有効とする
|
|
194
|
+
if (!dispTaxonomies.includes(name)) {
|
|
195
|
+
// 正規表現の match 結果っぽい形の配列を自分で作る
|
|
196
|
+
// [0] に全体一致, [1] にグループ1 というイメージ
|
|
197
|
+
match = [`tax_${name}`, name];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// 再帰的に innerBlocks をフィルタ
|
|
202
|
+
const filteredInner = block.innerBlocks
|
|
203
|
+
? filterBlocksRecursively(block.innerBlocks)
|
|
204
|
+
: [];
|
|
205
|
+
|
|
206
|
+
const isAutoGenerated = !!match;
|
|
207
|
+
const keep = !isAutoGenerated || selectedKeys.includes(match[1]);
|
|
208
|
+
|
|
209
|
+
if (!keep) return null;
|
|
210
|
+
|
|
211
|
+
// 構造を復元して返す
|
|
212
|
+
return {
|
|
213
|
+
...block,
|
|
214
|
+
innerBlocks: filteredInner,
|
|
215
|
+
};
|
|
216
|
+
})
|
|
217
|
+
.filter(Boolean); // null を除去
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const userBlocks = Array.isArray(dispAttribute.innerBlocks)
|
|
221
|
+
? filterBlocksRecursively(dispAttribute.innerBlocks).map(
|
|
222
|
+
createBlockTree
|
|
223
|
+
)
|
|
224
|
+
: [];
|
|
225
|
+
|
|
226
|
+
// autoGenerated(selectedFields) + userBlocks を合成
|
|
227
|
+
const innerBlocks = [...userBlocks, ...autoGeneratedBlocks];
|
|
228
|
+
|
|
229
|
+
const ret = createBlock(
|
|
230
|
+
"itmar/design-group",
|
|
231
|
+
{
|
|
232
|
+
...dispAttribute.attributes,
|
|
233
|
+
className: `unit_design_${unit_index}`,
|
|
234
|
+
domType: domType,
|
|
235
|
+
},
|
|
236
|
+
innerBlocks
|
|
237
|
+
);
|
|
238
|
+
return ret;
|
|
239
|
+
});
|
|
240
|
+
//挿入するブロックと自身のブロックが異なる場合(slide-mvにデータを入れる場合)
|
|
241
|
+
if (insertId !== clientId) {
|
|
242
|
+
blocksArray.push(pickupBlock);
|
|
243
|
+
}
|
|
244
|
+
// 既存のインナーブロックを一括置換
|
|
245
|
+
replaceInnerBlocks(insertId, blocksArray, false);
|
|
246
|
+
}, [selectedFields, pickupType, dispTaxonomies]);
|
|
247
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Masonry グリッドを初期化する共通関数
|
|
3
|
+
*
|
|
4
|
+
* @param {HTMLElement} gridEl - `.itmar-masonry-grid` のコンテナ要素
|
|
5
|
+
* @param {Array<{ url: string, alt?: string }>} images - 描画する画像リスト
|
|
6
|
+
* @param {Object} options
|
|
7
|
+
* @param {number} options.columns - カラム数
|
|
8
|
+
* @param {boolean} [options.renderItems=true]
|
|
9
|
+
* true: この関数内で gridEl をクリアして <figure><img> を追加する
|
|
10
|
+
* false: 既にある .itmar-masonry-item をそのまま使い、幅だけ更新する
|
|
11
|
+
*
|
|
12
|
+
* @returns {any|null} Masonry インスタンス(なければ null)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export default function MasonryControl(
|
|
16
|
+
gridEl,
|
|
17
|
+
images = [],
|
|
18
|
+
{ columns = 1, renderItems = true } = {}
|
|
19
|
+
) {
|
|
20
|
+
if (!gridEl) return null;
|
|
21
|
+
const columnWidthPercent = 100 / (columns || 1);
|
|
22
|
+
|
|
23
|
+
// 既存インスタンスがあれば破棄(再初期化に対応)
|
|
24
|
+
if (gridEl.__masonryInstance) {
|
|
25
|
+
try {
|
|
26
|
+
gridEl.__masonryInstance.destroy();
|
|
27
|
+
} catch (e) {
|
|
28
|
+
console.warn("Failed to destroy previous Masonry instance", e);
|
|
29
|
+
}
|
|
30
|
+
gridEl.__masonryInstance = null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ---------------------------
|
|
34
|
+
// 1) アイテムの DOM を構築 or 更新
|
|
35
|
+
// ---------------------------
|
|
36
|
+
if (renderItems) {
|
|
37
|
+
// ★ コンテナ全部は消さない。マソンリー用の要素だけを削除する
|
|
38
|
+
gridEl
|
|
39
|
+
.querySelectorAll(".itmar-masonry-sizer, .itmar-masonry-item")
|
|
40
|
+
.forEach((node) => node.remove());
|
|
41
|
+
|
|
42
|
+
// sizer 追加
|
|
43
|
+
const sizer = document.createElement("div");
|
|
44
|
+
sizer.className = "itmar-masonry-sizer";
|
|
45
|
+
sizer.style.width = `${columnWidthPercent}%`;
|
|
46
|
+
gridEl.appendChild(sizer);
|
|
47
|
+
|
|
48
|
+
// 画像アイテム追加
|
|
49
|
+
images.forEach((item, index) => {
|
|
50
|
+
const fig = document.createElement("figure");
|
|
51
|
+
fig.className = "itmar-masonry-item";
|
|
52
|
+
fig.style.width = `${columnWidthPercent}%`;
|
|
53
|
+
|
|
54
|
+
// クリック検知用の a タグ
|
|
55
|
+
const link = document.createElement("a");
|
|
56
|
+
link.href = "#";
|
|
57
|
+
link.className = "itmar-masonry-link";
|
|
58
|
+
link.dataset.masonryIndex = String(index);
|
|
59
|
+
//img要素
|
|
60
|
+
const img = document.createElement("img");
|
|
61
|
+
img.src = item.url;
|
|
62
|
+
img.alt = item.alt || "";
|
|
63
|
+
img.style.display = "block";
|
|
64
|
+
img.style.width = "100%";
|
|
65
|
+
img.style.height = "auto";
|
|
66
|
+
|
|
67
|
+
link.appendChild(img);
|
|
68
|
+
fig.appendChild(link);
|
|
69
|
+
gridEl.appendChild(fig);
|
|
70
|
+
});
|
|
71
|
+
} else {
|
|
72
|
+
// React 側(edit.js)みたいに、すでに <figure> が描画されている場合
|
|
73
|
+
// sizer がなければ作る
|
|
74
|
+
let sizer = gridEl.querySelector(".itmar-masonry-sizer");
|
|
75
|
+
if (!sizer) {
|
|
76
|
+
sizer = document.createElement("div");
|
|
77
|
+
sizer.className = "itmar-masonry-sizer";
|
|
78
|
+
gridEl.insertBefore(sizer, gridEl.firstChild || null);
|
|
79
|
+
}
|
|
80
|
+
sizer.style.width = `${columnWidthPercent}%`;
|
|
81
|
+
|
|
82
|
+
// 既存 item の幅だけ更新
|
|
83
|
+
gridEl.querySelectorAll(".itmar-masonry-item").forEach((fig) => {
|
|
84
|
+
fig.style.width = `${columnWidthPercent}%`;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ---------------------------
|
|
89
|
+
// 2) Masonry / imagesLoaded を iframe-aware に取得
|
|
90
|
+
// ---------------------------
|
|
91
|
+
let win = null;
|
|
92
|
+
|
|
93
|
+
if (gridEl.ownerDocument && gridEl.ownerDocument.defaultView) {
|
|
94
|
+
// サイトエディタ・ブロックエディタの iframe 内ならこっち
|
|
95
|
+
win = gridEl.ownerDocument.defaultView;
|
|
96
|
+
} else if (typeof window !== "undefined") {
|
|
97
|
+
// フロントなら普通に window
|
|
98
|
+
win = window;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!win || !win.Masonry || !win.imagesLoaded) {
|
|
102
|
+
// ライブラリが読み込まれていない場合は、
|
|
103
|
+
// DOM だけ作って終了(レイアウトはブラウザ任せ)
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const MasonryCtor = win.Masonry;
|
|
108
|
+
const imagesLoadedFn = win.imagesLoaded;
|
|
109
|
+
|
|
110
|
+
const msnry = new MasonryCtor(gridEl, {
|
|
111
|
+
itemSelector: ".itmar-masonry-item",
|
|
112
|
+
columnWidth: ".itmar-masonry-sizer",
|
|
113
|
+
percentPosition: true,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const imgLoad = imagesLoadedFn(gridEl);
|
|
117
|
+
imgLoad.on("progress", () => {
|
|
118
|
+
msnry.layout();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// 後から破棄できるように要素に紐付けておく
|
|
122
|
+
gridEl.__masonryInstance = msnry;
|
|
123
|
+
|
|
124
|
+
return msnry;
|
|
125
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
//Swiper初期化関数
|
|
2
|
+
// jQueryの $.data() 相当をざっくり再現(文字列→boolean/number/JSON を変換)
|
|
3
|
+
function coerceDataValue(val) {
|
|
4
|
+
if (val == null) return null;
|
|
5
|
+
if (typeof val !== "string") return val;
|
|
6
|
+
|
|
7
|
+
const t = val.trim();
|
|
8
|
+
if (t === "") return "";
|
|
9
|
+
|
|
10
|
+
if (t === "true") return true;
|
|
11
|
+
if (t === "false") return false;
|
|
12
|
+
if (t === "null") return null;
|
|
13
|
+
|
|
14
|
+
// JSONっぽければJSONとして読む(swiper-info など)
|
|
15
|
+
const looksJson =
|
|
16
|
+
(t.startsWith("{") && t.endsWith("}")) ||
|
|
17
|
+
(t.startsWith("[") && t.endsWith("]"));
|
|
18
|
+
if (looksJson) {
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(t);
|
|
21
|
+
} catch {
|
|
22
|
+
// JSONとして壊れてたら文字列のまま
|
|
23
|
+
return val;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 数値
|
|
28
|
+
const n = Number(t);
|
|
29
|
+
if (!Number.isNaN(n) && t !== "") return n;
|
|
30
|
+
|
|
31
|
+
return val;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function toDatasetKey(key) {
|
|
35
|
+
// "swiper-id" -> "swiperId" のように変換
|
|
36
|
+
return key.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getData(el, key) {
|
|
40
|
+
const dsKey = toDatasetKey(key);
|
|
41
|
+
|
|
42
|
+
// dataset優先
|
|
43
|
+
if (el?.dataset && Object.prototype.hasOwnProperty.call(el.dataset, dsKey)) {
|
|
44
|
+
return coerceDataValue(el.dataset[dsKey]);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// 念のため attribute も見ておく
|
|
48
|
+
const attr = el.getAttribute?.(`data-${key}`);
|
|
49
|
+
if (attr != null) return coerceDataValue(attr);
|
|
50
|
+
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// (任意)複数回呼ばれても関連付けできるように、モジュール内で保持
|
|
55
|
+
const swiperRegistry = new Map();
|
|
56
|
+
// 二重にイベントを張らないための印
|
|
57
|
+
const linkedPairs = new Set();
|
|
58
|
+
|
|
59
|
+
function linkSwipers(a, b) {
|
|
60
|
+
if (!a || !b) return;
|
|
61
|
+
|
|
62
|
+
const pairKey = `${a.swiper_id}__${b.swiper_id}`;
|
|
63
|
+
if (linkedPairs.has(pairKey)) return;
|
|
64
|
+
linkedPairs.add(pairKey);
|
|
65
|
+
|
|
66
|
+
// bがサムネならthumbs連携
|
|
67
|
+
if (b.is_thumbnail) {
|
|
68
|
+
a.instance.thumbs.swiper = b.instance;
|
|
69
|
+
a.instance.thumbs.init();
|
|
70
|
+
a.instance.thumbs.update(true);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// どちらもサムネじゃなければ相互同期
|
|
75
|
+
if (!a.is_thumbnail) {
|
|
76
|
+
a.instance.on("slideChangeTransitionStart", (slider) => {
|
|
77
|
+
b.instance.slideToLoop(slider.realIndex, undefined, false);
|
|
78
|
+
});
|
|
79
|
+
b.instance.on("slideChangeTransitionStart", (slider) => {
|
|
80
|
+
a.instance.slideToLoop(slider.realIndex, undefined, false);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function tryLink(swiperObj) {
|
|
86
|
+
// 自分が relate_id を持っていて、相手が既にいればリンク
|
|
87
|
+
if (swiperObj.relate_id && swiperRegistry.has(swiperObj.relate_id)) {
|
|
88
|
+
linkSwipers(swiperObj, swiperRegistry.get(swiperObj.relate_id));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 逆に「相手が自分を relate_id に指定していた」ケースも拾う
|
|
92
|
+
for (const other of swiperRegistry.values()) {
|
|
93
|
+
if (other.relate_id === swiperObj.swiper_id) {
|
|
94
|
+
linkSwipers(other, swiperObj);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function slideBlockSwiperInit(swiperElement) {
|
|
100
|
+
// 文字列セレクタでも渡せるようにしておく(好みで削除OK)
|
|
101
|
+
const el =
|
|
102
|
+
typeof swiperElement === "string"
|
|
103
|
+
? document.querySelector(swiperElement)
|
|
104
|
+
: swiperElement;
|
|
105
|
+
|
|
106
|
+
if (!el) return null;
|
|
107
|
+
|
|
108
|
+
const swiper_id = getData(el, "swiper-id");
|
|
109
|
+
const relate_id = getData(el, "relate-id");
|
|
110
|
+
const is_thumbnail = !!getData(el, "thumb-flg");
|
|
111
|
+
const swiper_info = getData(el, "swiper-info");
|
|
112
|
+
const parallax_obj = getData(el, "parallax-option");
|
|
113
|
+
|
|
114
|
+
if (!swiper_info || typeof swiper_info !== "object") {
|
|
115
|
+
throw new Error(
|
|
116
|
+
"data-swiper-info が見つからないか、JSONとして解釈できません。"
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const parallax_option = parallax_obj != null ? { parallax: true } : {};
|
|
121
|
+
|
|
122
|
+
const autoplayOption = swiper_info.is_autoplay
|
|
123
|
+
? {
|
|
124
|
+
freeMode: { enabled: true, momentum: false },
|
|
125
|
+
autoplay: {
|
|
126
|
+
delay: swiper_info.autoplay,
|
|
127
|
+
stopOnLastSlide: false,
|
|
128
|
+
disableOnInteraction: false,
|
|
129
|
+
},
|
|
130
|
+
}
|
|
131
|
+
: {};
|
|
132
|
+
|
|
133
|
+
const effectOption = {
|
|
134
|
+
none: {
|
|
135
|
+
centeredSlides: swiper_info.isActiveCenter,
|
|
136
|
+
direction: swiper_info.singleDirection,
|
|
137
|
+
speed: swiper_info.slideSpeed,
|
|
138
|
+
slidesPerView: swiper_info.mobilePerView,
|
|
139
|
+
spaceBetween: swiper_info.mobileBetween,
|
|
140
|
+
breakpoints: {
|
|
141
|
+
768: {
|
|
142
|
+
slidesPerView: swiper_info.defaultPerView,
|
|
143
|
+
spaceBetween: swiper_info.defaultBetween,
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
slide_single_view: {
|
|
148
|
+
direction: swiper_info.singleDirection,
|
|
149
|
+
loopAdditionalSlides: 1,
|
|
150
|
+
speed: swiper_info.slideSpeed,
|
|
151
|
+
allowTouchMove: false,
|
|
152
|
+
...parallax_option,
|
|
153
|
+
},
|
|
154
|
+
fade_single_view: {
|
|
155
|
+
speed: swiper_info.slideSpeed,
|
|
156
|
+
effect: "fade",
|
|
157
|
+
fadeEffect: { crossFade: true },
|
|
158
|
+
...parallax_option,
|
|
159
|
+
},
|
|
160
|
+
coverflow: {
|
|
161
|
+
centeredSlides: true,
|
|
162
|
+
slidesPerView: 3,
|
|
163
|
+
spaceBetween: swiper_info.mobileBetween,
|
|
164
|
+
effect: "coverflow",
|
|
165
|
+
coverflowEffect: {
|
|
166
|
+
rotate: 50,
|
|
167
|
+
depth: 100,
|
|
168
|
+
stretch: 0,
|
|
169
|
+
modifier: 1,
|
|
170
|
+
scale: 0.9,
|
|
171
|
+
slideShadows: true,
|
|
172
|
+
},
|
|
173
|
+
breakpoints: {
|
|
174
|
+
768: {
|
|
175
|
+
spaceBetween: swiper_info.defaultBetween,
|
|
176
|
+
coverflowEffect: { stretch: 0 },
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
coverflow_2: {
|
|
181
|
+
centeredSlides: true,
|
|
182
|
+
slidesPerView: "auto",
|
|
183
|
+
effect: "coverflow",
|
|
184
|
+
coverflowEffect: { rotate: 0, slideShadows: false, stretch: 100 },
|
|
185
|
+
breakpoints: { 768: { coverflowEffect: { stretch: 100 } } },
|
|
186
|
+
},
|
|
187
|
+
cube: {
|
|
188
|
+
speed: 800,
|
|
189
|
+
effect: "cube",
|
|
190
|
+
cubeEffect: {
|
|
191
|
+
slideShadows: true,
|
|
192
|
+
shadow: true,
|
|
193
|
+
shadowOffset: 40,
|
|
194
|
+
shadowScale: 0.94,
|
|
195
|
+
},
|
|
196
|
+
on: {
|
|
197
|
+
slideChangeTransitionStart: function () {
|
|
198
|
+
this.el.classList.remove("scale-in");
|
|
199
|
+
this.el.classList.add("scale-out");
|
|
200
|
+
},
|
|
201
|
+
slideChangeTransitionEnd: function () {
|
|
202
|
+
this.el.classList.remove("scale-out");
|
|
203
|
+
this.el.classList.add("scale-in");
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
flip: {
|
|
208
|
+
effect: "flip",
|
|
209
|
+
flipEffect: { limitRotation: true, slideShadows: true },
|
|
210
|
+
},
|
|
211
|
+
cards: {
|
|
212
|
+
effect: "cards",
|
|
213
|
+
cardsEffect: {
|
|
214
|
+
perSlideOffset: 8,
|
|
215
|
+
perSlideRotate: 2,
|
|
216
|
+
rotate: true,
|
|
217
|
+
slideShadows: true,
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
let swiperOptions = {
|
|
223
|
+
loop: swiper_info.loop,
|
|
224
|
+
...autoplayOption,
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
if (is_thumbnail) {
|
|
228
|
+
swiperOptions = {
|
|
229
|
+
...swiperOptions,
|
|
230
|
+
watchSlidesProgress: true,
|
|
231
|
+
watchSlidesVisibility: true,
|
|
232
|
+
freeMode: true,
|
|
233
|
+
slideToClickedSlide: true,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (swiper_info.navigation?.disp) {
|
|
238
|
+
swiperOptions.navigation = {
|
|
239
|
+
nextEl: `.${swiper_id}-next`,
|
|
240
|
+
prevEl: `.${swiper_id}-prev`,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (swiper_info.pagination?.disp) {
|
|
245
|
+
swiperOptions.pagination = { el: `.${swiper_id}-pagination` };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (swiper_info.scrollbar?.disp) {
|
|
249
|
+
swiperOptions.scrollbar = { el: `.${swiper_id}-scrollbar` };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (swiper_info.effect && effectOption[swiper_info.effect]) {
|
|
253
|
+
swiperOptions = { ...swiperOptions, ...effectOption[swiper_info.effect] };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ここが $swiperElement[0] -> el に変わる
|
|
257
|
+
const instance = new Swiper(el, swiperOptions);
|
|
258
|
+
|
|
259
|
+
const swiperObj = { instance, swiper_id, relate_id, is_thumbnail };
|
|
260
|
+
if (swiper_id) swiperRegistry.set(swiper_id, swiperObj);
|
|
261
|
+
|
|
262
|
+
tryLink(swiperObj);
|
|
263
|
+
|
|
264
|
+
return swiperObj;
|
|
265
|
+
}
|
package/src/customFooks.js
CHANGED
package/src/index.js
CHANGED
|
@@ -120,3 +120,12 @@ export {
|
|
|
120
120
|
redirectCustomerAuthorize,
|
|
121
121
|
sendRegistrationRequest,
|
|
122
122
|
} from "./shopfiApi";
|
|
123
|
+
|
|
124
|
+
//インナーブロック挿入のカスタムフック
|
|
125
|
+
export { useRebuildChangeField } from "./BrockInserter";
|
|
126
|
+
|
|
127
|
+
//Masonry グリッドを初期化する共通関数
|
|
128
|
+
export { default as MasonryControl } from "./MasonryControl";
|
|
129
|
+
|
|
130
|
+
//インナーブロック挿入のカスタムフック
|
|
131
|
+
export { slideBlockSwiperInit } from "./SwiperControl";
|