e2e 오류 수정
CI / test (push) Failing after 4m41s
CI / e2e (push) Has been skipped
CI / pr_and_merge (push) Has been skipped

This commit is contained in:
2025-12-07 11:21:09 +09:00
parent 4902a0b5a9
commit 72b027a29c
30 changed files with 88 additions and 32 deletions
@@ -268,6 +268,7 @@ export function FormInputPropertiesPanel({ block, selectedBlockId, updateBlock }
<span></span>
<select
className="w-full rounded border border-slate-700 bg-slate-950 px-2 py-1 text-[11px] outline-none focus:border-sky-500"
aria-label="너비"
value={inputProps.widthMode ?? "full"}
onChange={(e) =>
updateBlock(selectedBlockId, {
+6 -5
View File
@@ -1647,7 +1647,7 @@ function SortableEditorBlock({
typeof radioProps.optionGapPx === "number" && radioProps.optionGapPx >= 0
? radioProps.optionGapPx
: undefined;
const gapStyle: CSSProperties =
const optionsStyle: CSSProperties =
optionGapPx !== undefined
? optionLayout === "inline"
? { rowGap: `${optionGapPx}px`, columnGap: `${optionGapPx}px` }
@@ -1656,9 +1656,10 @@ function SortableEditorBlock({
// 그룹 타이틀 레이아웃이 inline 인 경우, 라벨과 옵션 컨테이너를 가로 방향으로 배치하고 labelGapPx 를 columnGap 으로 사용한다.
const inlineGapPx = typeof radioProps.labelGapPx === "number" ? radioProps.labelGapPx : 8;
const groupContainerStyle: CSSProperties = isInlineLayout
? { columnGap: `${inlineGapPx}px` }
: {};
const groupContainerStyle: CSSProperties = {
...fieldStyle,
...(isInlineLayout ? { columnGap: `${inlineGapPx}px` } : {}),
};
const groupContainerClassName = isInlineLayout
? "flex flex-row items-center text-xs"
: "flex flex-col gap-1 text-xs";
@@ -1676,7 +1677,7 @@ function SortableEditorBlock({
) : (
<span className="text-slate-200">{radioProps.groupLabel}</span>
)}
<div style={{ ...fieldStyle, ...gapStyle }} className={optionsLayoutClass}>
<div style={optionsStyle} className={optionsLayoutClass}>
{options.map((opt) => (
<label key={opt.value} className="pb-form-option">
<input
@@ -523,9 +523,7 @@ export function PublicPageRenderer({ blocks, projectSlug }: PublicPageRendererPr
const gapPx = typeof (props as any).labelGapPx === "number" ? (props as any).labelGapPx : 8;
const gapEm = pxToEm(gapPx);
const baseClass = [tokens.textSizeClass, "text-slate-200", tokens.widthClass]
.filter(Boolean)
.join(" ");
const baseClass = ["text-slate-200", tokens.widthClass].filter(Boolean).join(" ");
const layoutClass = isInlineLayout ? "flex flex-row items-center" : "flex flex-col gap-1";
const groupStyle: CSSProperties = {
@@ -618,9 +616,7 @@ export function PublicPageRenderer({ blocks, projectSlug }: PublicPageRendererPr
const gapPx = typeof (props as any).labelGapPx === "number" ? (props as any).labelGapPx : 8;
const gapEm = pxToEm(gapPx);
const baseClass = [tokens.textSizeClass, "text-slate-200", tokens.widthClass]
.filter(Boolean)
.join(" ");
const baseClass = ["text-slate-200", tokens.widthClass].filter(Boolean).join(" ");
const layoutClass = isInlineLayout ? "flex flex-row items-center" : "flex flex-col gap-1";
const groupStyle: CSSProperties = {
+22 -8
View File
@@ -58,16 +58,19 @@ const computeRadiusPx = (radius: unknown): number => {
};
// Editor 레이어용 모서리 둥글기 매핑
// Export/Public 과 동일한 스케일을 사용하되, full 에 대해서만 pill 스타일(9999px)을 유지한다.
// - none: 0px
// - sm: 4px
// - md: 8px (기본)
// - lg/full: 9999px (pill 스타일)
// - sm: 2px
// - md: 4px (기본)
// - lg: 6px
// - full: 9999px
const computeEditorRadiusPx = (radius: unknown): number => {
const token = typeof radius === "string" ? radius : "md";
if (token === "none") return 0;
if (token === "sm") return 4;
if (token === "lg" || token === "full") return 9999;
return 8;
if (token === "sm") return 2;
if (token === "lg") return 6;
if (token === "full") return 9999;
return 4;
};
const computeWidthMode = (props: { widthMode?: string; fullWidth?: boolean }): "auto" | "full" | "fixed" => {
@@ -409,8 +412,19 @@ export const computeFormSelectEditorTokens = (props: FormSelectBlockProps): Form
fieldStyle.width = `${props.widthPx}px`;
}
// 모서리 둥글기: Editor 레이어에서는 lg/full 토큰을 pill 형태(9999px) 사용한다.
const selectRadiusPx = computeEditorRadiusPx(props.borderRadius);
// 모서리 둥글기: formSelect 는 Export/Public 레이어와 동일한 스케일(0/2/4/6/9999px) 사용
// 에디터/프리뷰/퍼블릭 간 border-radius 가 일치하도록 한다.
const selectRadiusToken = props.borderRadius ?? "md";
const selectRadiusPx =
selectRadiusToken === "none"
? 0
: selectRadiusToken === "sm"
? 2
: selectRadiusToken === "lg"
? 6
: selectRadiusToken === "full"
? 9999
: 4;
fieldStyle.borderRadius = selectRadiusPx;
// 체크박스/라디오 그룹도 에디터에서 padding/타이포 스타일을 일부 반영해준다.
+9
View File
@@ -53,6 +53,11 @@ export const computeListExportTokens = (props: ListBlockProps): ListExportTokens
: 8;
const gapEm = gapPx / 16;
// 리스트 아이템 간 간격은 CSS 커스텀 프로퍼티 --pb-list-gap 으로 전달한다.
// 이렇게 하면 margin-bottom 계산은 builder.css 레이어에서만 수행되어,
// 정적 Export HTML 의 style 속성에 직접적인 margin-bottom 이 포함되지 않는다.
listStyleParts.push(`--pb-list-gap:${gapEm}em`);
if (typeof props.backgroundColorCustom === "string" && props.backgroundColorCustom.trim() !== "") {
listStyleParts.push(`background-color:${props.backgroundColorCustom.trim()}`);
}
@@ -172,6 +177,10 @@ export const computeListPublicTokens = (props: ListBlockProps): ListPublicTokens
listStyle.backgroundColor = props.backgroundColorCustom.trim();
}
// 리스트 아이템 간 여백을 CSS 변수로 노출한다. 실제 margin-bottom 은 builder.css 의
// .pb-list > li 규칙에서 --pb-list-gap 값을 참조해 계산한다.
(listStyle as any)["--pb-list-gap"] = `${gapEm}em`;
const bulletStyle = bulletStyleRaw;
return {
+11
View File
@@ -536,3 +536,14 @@ body {
color: var(--pb-color-text-default);
}
/* 리스트 아이템 여백은 --pb-list-gap 커스텀 프로퍼티로 제어한다.
- Export/Preview 모두 동일한 gapEm 변수에 설정하고,
- 실제 margin-bottom 계산은 CSS 레이어에서만 수행해 정적 HTML 인라인 스타일에
margin-bottom 직접 등장하지 않도록 한다. */
.pb-list > li {
margin-bottom: var(--pb-list-gap, 0);
}
.pb-list > li:last-child {
margin-bottom: 0;
}