@growgroup/visual-editor 0.7.1 → 0.8.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 +18 -1
- package/dist/editor.css +1 -1
- package/package.json +1 -1
- package/src/editor/FrontendVisualEditor.tsx +1 -1
- package/src/editor/components/EditorCanvas.tsx +4 -8
- package/src/editor/components/EditorFooter.tsx +4 -1
- package/src/editor/components/EditorHeader.tsx +1 -4
- package/src/editor/components/EditorPropertyPanel.tsx +6 -9
- package/src/editor/components/ppt/PptChrome.tsx +20 -6
- package/src/editor/components/property-panel/BorderSection.tsx +3 -1
- package/src/editor/hooks/useIframeInitializer.ts +1 -5
- package/src/editor/hooks/useLinkNavigation.ts +2 -2
- package/src/editor/hooks/useMediaLibrary.ts +1 -1
- package/src/editor/types.ts +5 -1
- package/src/editor/utils/border-sides.ts +112 -0
- package/src/editor/utils/dom-utils.ts +18 -2
- package/src/editor/utils/link-navigation.ts +61 -29
- package/src/editor/utils/style-utils.ts +10 -4
- package/src/editor/utils/tailwind-mappings.ts +2 -7
- package/src/editor/utils/tailwind-utils.ts +105 -0
- package/src/version.ts +1 -1
|
@@ -294,6 +294,80 @@ function isTextColorClass(cls: string): boolean {
|
|
|
294
294
|
return false;
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
+
// ------------------------------------------------------------
|
|
298
|
+
// 線(border-*)のクラスの見分け
|
|
299
|
+
// ------------------------------------------------------------
|
|
300
|
+
// border- で始まるクラスには、太さ(border-2 / border-l-2)・色(border-wf-ink)・
|
|
301
|
+
// スタイル(border-dashed)・表(border-collapse)が混ざっている。
|
|
302
|
+
// 以前は線色・線幅の変更で「border- で始まるもの」を全部消していたので、
|
|
303
|
+
// 左だけの線(border-l-2)や色・破線まで消えていた。tailwind-merge と同じ見分け方にする
|
|
304
|
+
// (太さ・スタイル・表の形でないものを色とみなす。テーマの色名を名簿で持たずに済む)
|
|
305
|
+
|
|
306
|
+
const BORDER_STYLE_CLASSES = new Set([
|
|
307
|
+
'border-solid',
|
|
308
|
+
'border-dashed',
|
|
309
|
+
'border-dotted',
|
|
310
|
+
'border-double',
|
|
311
|
+
'border-hidden',
|
|
312
|
+
'border-none',
|
|
313
|
+
]);
|
|
314
|
+
|
|
315
|
+
const isBorderTableClass = (cls: string) => /^border-(collapse|separate|spacing(-|$))/.test(cls);
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* important の印を外す(`border-2!` / `!border-2`)。付いていても種類は同じなので、
|
|
319
|
+
* 判定の前に外して、消すときも同じ種類として消す(付いたまま残ると、新しい太さが !important に負ける)
|
|
320
|
+
*/
|
|
321
|
+
const stripImportant = (cls: string) => cls.replace(/^!/, '').replace(/!$/, '');
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* 太さの値: 数字(border-2)、長さの任意値(border-[2px] / border-[length:var(--w)] /
|
|
325
|
+
* border-[min(2px,1vw)])、太さのキーワード(border-[thin] など。`border-[mediumblue]` は色なので厳密一致)、
|
|
326
|
+
* border-(length:--w)
|
|
327
|
+
*/
|
|
328
|
+
const BORDER_WIDTH_VALUE = String.raw`(-\d+|-\[(?:thin|medium|thick)\]|-\[(?:\d|\.|calc\(|min\(|max\(|clamp\(|length:)[^\]]*\]|-\(length:[^)]*\))?`;
|
|
329
|
+
|
|
330
|
+
/** 辺の指定。`bs` / `be`(書字方向の始め・終わり)も Tailwind では辺の太さ */
|
|
331
|
+
const BORDER_SIDE_TOKENS = '(?:[trblxyse]|bs|be)';
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* 太さのクラス。side を渡すとその辺だけ(border-l / border-l-2 / border-l-[3px])、
|
|
335
|
+
* '' なら四辺まとめての指定だけ(border / border-2)。渡さなければ全部の辺と各辺
|
|
336
|
+
*/
|
|
337
|
+
/** 辺を表す文字。`s` / `e` は書字方向、`bs` / `be` はブロック方向 */
|
|
338
|
+
export type SideLetter = 't' | 'r' | 'b' | 'l' | 'x' | 'y' | 's' | 'e' | 'bs' | 'be';
|
|
339
|
+
|
|
340
|
+
export function isBorderWidthClass(cls: string, side?: SideLetter | ''): boolean {
|
|
341
|
+
const sides = side === undefined ? `(-${BORDER_SIDE_TOKENS})?` : side ? `-${side}` : '';
|
|
342
|
+
return new RegExp(`^border${sides}${BORDER_WIDTH_VALUE}$`).test(stripImportant(cls));
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** スタイルのクラス(border-solid / border-dashed!) */
|
|
346
|
+
const isBorderStyleClass = (cls: string) => BORDER_STYLE_CLASSES.has(stripImportant(cls));
|
|
347
|
+
|
|
348
|
+
/** 太さ 0 の指定(border-0 / border-l-0 / border-[0px])。「線がある」の判定では数えない */
|
|
349
|
+
export function isZeroBorderWidthClass(cls: string): boolean {
|
|
350
|
+
return new RegExp(`^border(-${BORDER_SIDE_TOKENS})?-(0|\\[0(?:px|rem|em)?\\])$`).test(stripImportant(cls));
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/** 色のクラス(border-wf-ink / border-l-wf-ink / border-[#fff] / border-[var(--x)] / border-wf-ink/50) */
|
|
354
|
+
function isBorderColorClass(cls: string): boolean {
|
|
355
|
+
const bare = stripImportant(cls);
|
|
356
|
+
return (
|
|
357
|
+
bare.startsWith('border-') &&
|
|
358
|
+
!BORDER_STYLE_CLASSES.has(bare) &&
|
|
359
|
+
!isBorderTableClass(bare) &&
|
|
360
|
+
!isBorderWidthClass(bare)
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const BORDER_SIDE_WIDTH_PROPERTIES: Record<string, 't' | 'r' | 'b' | 'l'> = {
|
|
365
|
+
borderTopWidth: 't',
|
|
366
|
+
borderRightWidth: 'r',
|
|
367
|
+
borderBottomWidth: 'b',
|
|
368
|
+
borderLeftWidth: 'l',
|
|
369
|
+
};
|
|
370
|
+
|
|
297
371
|
/**
|
|
298
372
|
* 競合するクラスを要素から削除
|
|
299
373
|
*
|
|
@@ -322,6 +396,26 @@ export function removeConflictingClasses(
|
|
|
322
396
|
return;
|
|
323
397
|
}
|
|
324
398
|
|
|
399
|
+
// 線の太さ・色・スタイルは、同じ種類のクラスだけを消す(太さを変えても色・破線は残す。色を変えても左だけの線は残す)。
|
|
400
|
+
// スタイルもここで消すのは、important 付き(border-dashed!)を名前の一致では拾えないため
|
|
401
|
+
if (
|
|
402
|
+
property === 'borderWidth' ||
|
|
403
|
+
property === 'borderColor' ||
|
|
404
|
+
property === 'borderStyle' ||
|
|
405
|
+
property in BORDER_SIDE_WIDTH_PROPERTIES
|
|
406
|
+
) {
|
|
407
|
+
const side = BORDER_SIDE_WIDTH_PROPERTIES[property];
|
|
408
|
+
const conflicts =
|
|
409
|
+
property === 'borderColor'
|
|
410
|
+
? isBorderColorClass
|
|
411
|
+
: property === 'borderStyle'
|
|
412
|
+
? isBorderStyleClass
|
|
413
|
+
: (cls: string) => isBorderWidthClass(cls, side);
|
|
414
|
+
const currentClasses = getElementClassName(element).split(/\s+/).filter(Boolean);
|
|
415
|
+
setElementClassName(element, currentClasses.filter((cls) => !conflicts(cls)).join(' '));
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
|
|
325
419
|
if (!conflictPrefixes || conflictPrefixes.length === 0) return;
|
|
326
420
|
|
|
327
421
|
const currentClasses = getElementClassName(element).split(/\s+/).filter(Boolean);
|
|
@@ -379,6 +473,17 @@ const LAYOUT_CRITICAL_PROPERTIES = new Set([
|
|
|
379
473
|
'maxWidth',
|
|
380
474
|
'minHeight',
|
|
381
475
|
'maxHeight',
|
|
476
|
+
// 線のスタイル(なし / 実線 / 破線 / 点線)も同じ理由でインラインを残す。
|
|
477
|
+
// 紙面の CSS はファイルに書かれたクラスの分しか作られない(Vite の @source 走査)ので、
|
|
478
|
+
// 付けたばかりの border-none / border-solid にはルールが無く、紙面が変わらない。
|
|
479
|
+
// 右パネルは紙面の computed style を読み直すため、「なし」を選んでも「実線」に戻って見えていた
|
|
480
|
+
'borderStyle',
|
|
481
|
+
// 線幅も同じ。border-0 / border-l-0 などは紙面の CSS に無いことが多い(構成ラフの殻で実測)
|
|
482
|
+
'borderWidth',
|
|
483
|
+
'borderTopWidth',
|
|
484
|
+
'borderRightWidth',
|
|
485
|
+
'borderBottomWidth',
|
|
486
|
+
'borderLeftWidth',
|
|
382
487
|
'display',
|
|
383
488
|
'flexDirection',
|
|
384
489
|
'flexWrap',
|
package/src/version.ts
CHANGED