@roottale/cms-renderer-next 0.48.0 → 0.51.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/CHANGELOG.md +56 -0
- package/dist/blog-filter-BKCGM0qd.d.ts +29 -0
- package/dist/{chunk-6MFHA555.js → chunk-27RT6B3O.js} +1 -1
- package/dist/chunk-27RT6B3O.js.map +1 -0
- package/dist/chunk-2QU4JU46.js +3927 -0
- package/dist/chunk-2QU4JU46.js.map +1 -0
- package/dist/chunk-4RQ3SEDL.js +106 -0
- package/dist/chunk-4RQ3SEDL.js.map +1 -0
- package/dist/{chunk-OMXEU4LS.js → chunk-QYNEOFL7.js} +140 -136
- package/dist/chunk-QYNEOFL7.js.map +1 -0
- package/dist/concerns-client.d.ts +1 -1
- package/dist/expertise-client.d.ts +1 -1
- package/dist/expertise-client.js +1 -1
- package/dist/hero-carousel-client.js +1 -1
- package/dist/routes.d.ts +334 -20
- package/dist/routes.js +249 -68
- package/dist/routes.js.map +1 -1
- package/dist/seo-asset-hosts.d.ts +36 -0
- package/dist/seo-asset-hosts.js +391 -0
- package/dist/seo-asset-hosts.js.map +1 -0
- package/dist/server.d.ts +23 -241
- package/dist/server.js +6 -6
- package/dist/{site-config-Dicv57oY.d.ts → site-config-DNpvlqA5.d.ts} +201 -201
- package/dist/spaces-client.d.ts +1 -1
- package/dist/team-expanding-stage-client.d.ts +1 -1
- package/dist/team-expanding-stage-client.js +1 -1
- package/dist/templates.d.ts +64 -25
- package/dist/templates.js +13 -6
- package/dist/templates.js.map +1 -1
- package/package.json +7 -2
- package/dist/chunk-6MFHA555.js.map +0 -1
- package/dist/chunk-FZK3EXYZ.js +0 -103
- package/dist/chunk-FZK3EXYZ.js.map +0 -1
- package/dist/chunk-LIBSVC4M.js +0 -3642
- package/dist/chunk-LIBSVC4M.js.map +0 -1
- package/dist/chunk-OMXEU4LS.js.map +0 -1
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/templates/team-expanding-stage-client.tsx
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { useReducedMotion } from "motion/react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
function memberInitials(name) {
|
|
8
|
+
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
9
|
+
if (parts.length === 0) return "?";
|
|
10
|
+
const initials = parts.slice(0, 2).map((part) => part.at(0) ?? "").join("");
|
|
11
|
+
return initials || "?";
|
|
12
|
+
}
|
|
13
|
+
function TeamExpandingStageClient({
|
|
14
|
+
members
|
|
15
|
+
}) {
|
|
16
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
17
|
+
const reducedMotion = useReducedMotion();
|
|
18
|
+
if (members.length === 0) return null;
|
|
19
|
+
const activate = (index) => setActiveIndex(index);
|
|
20
|
+
const onItemKeyDown = (event, index) => {
|
|
21
|
+
if ((event.key === "Enter" || event.key === " ") && index !== activeIndex) {
|
|
22
|
+
event.preventDefault();
|
|
23
|
+
activate(index);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
return /* @__PURE__ */ jsx(
|
|
27
|
+
"ul",
|
|
28
|
+
{
|
|
29
|
+
className: "rt-tpl-team-expanding-stage",
|
|
30
|
+
"data-reduced-motion": reducedMotion ? "true" : "false",
|
|
31
|
+
children: members.map((member, index) => {
|
|
32
|
+
const active = index === activeIndex;
|
|
33
|
+
return (
|
|
34
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- hover 는 마우스 보조 경로다(키보드는 아래 onFocus 가 받는다).
|
|
35
|
+
/* @__PURE__ */ jsxs(
|
|
36
|
+
"li",
|
|
37
|
+
{
|
|
38
|
+
className: "rt-tpl-team-expanding-item",
|
|
39
|
+
"data-active": active ? "true" : "false",
|
|
40
|
+
tabIndex: 0,
|
|
41
|
+
onMouseEnter: () => activate(index),
|
|
42
|
+
onFocus: () => activate(index),
|
|
43
|
+
onClick: (event) => {
|
|
44
|
+
if (!active) event.preventDefault();
|
|
45
|
+
activate(index);
|
|
46
|
+
},
|
|
47
|
+
onKeyDown: (event) => onItemKeyDown(event, index),
|
|
48
|
+
children: [
|
|
49
|
+
/* @__PURE__ */ jsx("span", { className: "rt-tpl-team-expanding-index", "aria-hidden": "true", children: String(index + 1).padStart(2, "0") }),
|
|
50
|
+
member.photoSrc ? /* @__PURE__ */ jsx(
|
|
51
|
+
"img",
|
|
52
|
+
{
|
|
53
|
+
className: "rt-tpl-team-expanding-photo",
|
|
54
|
+
src: member.photoSrc,
|
|
55
|
+
alt: member.photoAlt ?? "",
|
|
56
|
+
loading: "lazy"
|
|
57
|
+
}
|
|
58
|
+
) : /* @__PURE__ */ jsx(
|
|
59
|
+
"div",
|
|
60
|
+
{
|
|
61
|
+
className: "rt-tpl-team-expanding-photo rt-tpl-team-expanding-photo--initials",
|
|
62
|
+
"aria-hidden": "true",
|
|
63
|
+
children: memberInitials(member.name)
|
|
64
|
+
}
|
|
65
|
+
),
|
|
66
|
+
/* @__PURE__ */ jsxs("div", { className: "rt-tpl-team-expanding-name", "aria-hidden": "true", children: [
|
|
67
|
+
/* @__PURE__ */ jsx("b", { children: member.name }),
|
|
68
|
+
/* @__PURE__ */ jsx("span", { children: member.title })
|
|
69
|
+
] }),
|
|
70
|
+
/* @__PURE__ */ jsxs("div", { className: "rt-tpl-team-expanding-detail", children: [
|
|
71
|
+
/* @__PURE__ */ jsx("p", { className: "rt-tpl-team-expanding-role", children: member.title }),
|
|
72
|
+
/* @__PURE__ */ jsx("h3", { className: "rt-tpl-team-name", children: member.name }),
|
|
73
|
+
member.specialties ? /* @__PURE__ */ jsx(
|
|
74
|
+
"ul",
|
|
75
|
+
{
|
|
76
|
+
className: "rt-tpl-team-specialties",
|
|
77
|
+
"aria-label": `${member.name} \uC804\uBB38 \uBD84\uC57C`,
|
|
78
|
+
children: member.specialties.map((specialty) => /* @__PURE__ */ jsx("li", { children: specialty }, specialty))
|
|
79
|
+
}
|
|
80
|
+
) : null,
|
|
81
|
+
member.credentials ? /* @__PURE__ */ jsx("ul", { className: "rt-tpl-team-credentials", children: member.credentials.map((credential) => /* @__PURE__ */ jsx("li", { children: credential }, credential)) }) : null,
|
|
82
|
+
member.bio ? /* @__PURE__ */ jsx("p", { className: "rt-tpl-team-bio", children: member.bio }) : null,
|
|
83
|
+
member.href ? /* @__PURE__ */ jsx(
|
|
84
|
+
"a",
|
|
85
|
+
{
|
|
86
|
+
className: "rt-tpl-team-cta",
|
|
87
|
+
href: member.href,
|
|
88
|
+
tabIndex: active ? 0 : -1,
|
|
89
|
+
children: member.ctaLabel ?? "\uD504\uB85C\uD544 \uBCF4\uAE30"
|
|
90
|
+
}
|
|
91
|
+
) : null
|
|
92
|
+
] })
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
member.name
|
|
96
|
+
)
|
|
97
|
+
);
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export {
|
|
104
|
+
TeamExpandingStageClient
|
|
105
|
+
};
|
|
106
|
+
//# sourceMappingURL=chunk-4RQ3SEDL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/templates/team-expanding-stage-client.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, type KeyboardEvent, type ReactElement } from \"react\";\nimport { useReducedMotion } from \"motion/react\";\n\nimport type { TeamSection } from \"./site-config.js\";\n\ntype TeamMember = TeamSection[\"props\"][\"members\"][number];\n\nfunction memberInitials(name: string): string {\n const parts = name.trim().split(/\\s+/).filter(Boolean);\n if (parts.length === 0) return \"?\";\n const initials = parts\n .slice(0, 2)\n .map((part) => part.at(0) ?? \"\")\n .join(\"\");\n return initials || \"?\";\n}\n\n/**\n * `team` `expanding-stage` variant 의 실모션 client island (D3 크래프트).\n * chambarun `.staff-stage`/`.staff-panel` 스펙(mockup/assets/site.js·site.css)\n * 이식 — hover/focus/tap 한 인물이 확장되며 자격 정보가 드러난다.\n *\n * 현재 `sections.tsx` `TemplateTeamExpandingStage` 는 이 컴포넌트를 아직\n * import 하지 않는다(정적 격자만 렌더) — `sections.tsx` 는 이 작업 소유 밖이라\n * 와이어링은 별도 보고 대상(README/보고 참조). 이 파일은 그 자리에 그대로\n * 끼워 넣을 수 있도록 `members` 하나만 받는 독립 컴포넌트로 설계했다.\n *\n * 접근성(계약, DESIGN.md \"Medical Staff Cards\" 원칙 확장):\n * - 각 패널은 `tabIndex=0` 컨테이너(hover/focus/click 시 확장) — chambarun\n * 원본과 동일하게 명시적 role 은 두지 않는다(내부에 실제 CTA 링크가 있어\n * `role=\"button\"` 을 얹으면 중첩 인터랙티브 요소가 된다).\n * - 자격정보·경력·CTA 는 접힌 상태에서도 DOM 에 그대로 존재한다(opacity 로만\n * 가림) — 스크린리더는 hover 없이 전체 내용을 읽을 수 있다(\"decorative hover\n * layers do not replace content\").\n * - CTA 링크는 비활성 패널일 때 `tabIndex=-1` — 보이지 않는 링크가 키보드\n * 포커스를 가로채지 않는다(chambarun 원본에는 없던, React 상태로만 가능한\n * 개선).\n * - `prefers-reduced-motion: reduce` → 전환 자체가 CSS 에서 제거된다\n * (templates.css, `@media (prefers-reduced-motion: no-preference)` 안에만\n * transition 선언 — ADR-0073 K3 C1 과 동일 관행). `data-reduced-motion`\n * 속성은 시각 회귀 테스트/QA 스크린샷 식별용.\n */\nexport function TeamExpandingStageClient({\n members,\n}: {\n readonly members: readonly TeamMember[];\n}): ReactElement | null {\n const [activeIndex, setActiveIndex] = useState(0);\n const reducedMotion = useReducedMotion();\n\n if (members.length === 0) return null;\n\n const activate = (index: number) => setActiveIndex(index);\n\n const onItemKeyDown = (event: KeyboardEvent<HTMLLIElement>, index: number) => {\n if ((event.key === \"Enter\" || event.key === \" \") && index !== activeIndex) {\n event.preventDefault();\n activate(index);\n }\n };\n\n return (\n <ul\n className=\"rt-tpl-team-expanding-stage\"\n data-reduced-motion={reducedMotion ? \"true\" : \"false\"}\n >\n {members.map((member, index) => {\n const active = index === activeIndex;\n return (\n // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- hover 는 마우스 보조 경로다(키보드는 아래 onFocus 가 받는다).\n <li\n key={member.name}\n className=\"rt-tpl-team-expanding-item\"\n data-active={active ? \"true\" : \"false\"}\n // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- 키보드 사용자가 팀원 카드를 넘겨보려면 초점을 받아야 한다(WCAG 2.1.1).\n tabIndex={0}\n onMouseEnter={() => activate(index)}\n onFocus={() => activate(index)}\n onClick={(event) => {\n // 첫 탭(hover/focus 없이 바로 터치)은 확장만 — CTA 로 즉시\n // 이동하지 않는다. 이미 활성(=두 번째 탭)이면 기본 클릭 동작\n // (링크 없는 li 자체는 아무 것도 안 함, 내부 CTA 는 그대로 이동).\n if (!active) event.preventDefault();\n activate(index);\n }}\n onKeyDown={(event) => onItemKeyDown(event, index)}\n >\n <span className=\"rt-tpl-team-expanding-index\" aria-hidden=\"true\">\n {String(index + 1).padStart(2, \"0\")}\n </span>\n {member.photoSrc ? (\n <img\n className=\"rt-tpl-team-expanding-photo\"\n src={member.photoSrc}\n alt={member.photoAlt ?? \"\"}\n loading=\"lazy\"\n />\n ) : (\n <div\n className=\"rt-tpl-team-expanding-photo rt-tpl-team-expanding-photo--initials\"\n aria-hidden=\"true\"\n >\n {memberInitials(member.name)}\n </div>\n )}\n <div className=\"rt-tpl-team-expanding-name\" aria-hidden=\"true\">\n <b>{member.name}</b>\n <span>{member.title}</span>\n </div>\n <div className=\"rt-tpl-team-expanding-detail\">\n <p className=\"rt-tpl-team-expanding-role\">{member.title}</p>\n <h3 className=\"rt-tpl-team-name\">{member.name}</h3>\n {member.specialties ? (\n <ul\n className=\"rt-tpl-team-specialties\"\n aria-label={`${member.name} 전문 분야`}\n >\n {member.specialties.map((specialty) => (\n <li key={specialty}>{specialty}</li>\n ))}\n </ul>\n ) : null}\n {member.credentials ? (\n <ul className=\"rt-tpl-team-credentials\">\n {member.credentials.map((credential) => (\n <li key={credential}>{credential}</li>\n ))}\n </ul>\n ) : null}\n {member.bio ? <p className=\"rt-tpl-team-bio\">{member.bio}</p> : null}\n {member.href ? (\n <a\n className=\"rt-tpl-team-cta\"\n href={member.href}\n tabIndex={active ? 0 : -1}\n >\n {member.ctaLabel ?? \"프로필 보기\"}\n </a>\n ) : null}\n </div>\n </li>\n );\n })}\n </ul>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -236,6 +236,7 @@ function HeroCarouselViewport({
|
|
|
236
236
|
}
|
|
237
237
|
emblaApi?.scrollTo(index, reducedMotion);
|
|
238
238
|
},
|
|
239
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- 위와 같은 이유(안정화된 메서드만 의존).
|
|
239
240
|
[isCurtain, curtain.goTo, emblaApi, reducedMotion]
|
|
240
241
|
);
|
|
241
242
|
const onKeyDown = useCallback3(
|
|
@@ -262,153 +263,156 @@ function HeroCarouselViewport({
|
|
|
262
263
|
onSelect: scrollTo,
|
|
263
264
|
orientation: "horizontal"
|
|
264
265
|
});
|
|
265
|
-
return
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
{
|
|
301
|
-
type: "button",
|
|
302
|
-
className: "rt-tpl-hero-carousel-arrow rt-tpl-hero-carousel-arrow--prev",
|
|
303
|
-
"aria-label": "\uC774\uC804 \uC2AC\uB77C\uC774\uB4DC",
|
|
304
|
-
onClick: scrollPrev,
|
|
305
|
-
children: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx3("path", { d: "M15 5 8 12l7 7", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
|
|
306
|
-
}
|
|
307
|
-
),
|
|
308
|
-
/* @__PURE__ */ jsx3(
|
|
309
|
-
"button",
|
|
310
|
-
{
|
|
311
|
-
type: "button",
|
|
312
|
-
className: "rt-tpl-hero-carousel-arrow rt-tpl-hero-carousel-arrow--next",
|
|
313
|
-
"aria-label": "\uB2E4\uC74C \uC2AC\uB77C\uC774\uB4DC",
|
|
314
|
-
onClick: scrollNext,
|
|
315
|
-
children: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx3("path", { d: "m9 5 7 7-7 7", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
|
|
316
|
-
}
|
|
317
|
-
),
|
|
318
|
-
hasSlidePanel && selectedSlide ? /* @__PURE__ */ jsxs2(
|
|
319
|
-
"div",
|
|
320
|
-
{
|
|
321
|
-
className: "rt-tpl-hero-carousel-slide-panel",
|
|
322
|
-
children: [
|
|
323
|
-
selectedSlide.eyebrow ? /* @__PURE__ */ jsx3("p", { className: "rt-tpl-hero-carousel-slide-eyebrow", children: selectedSlide.eyebrow }) : null,
|
|
324
|
-
selectedSlide.title ? /* @__PURE__ */ jsx3("p", { className: "rt-tpl-hero-carousel-slide-title", children: selectedSlide.title }) : null,
|
|
325
|
-
selectedSlide.subtitle ? /* @__PURE__ */ jsx3("p", { className: "rt-tpl-hero-carousel-slide-subtitle", children: selectedSlide.subtitle }) : null,
|
|
326
|
-
selectedSlide.description ? /* @__PURE__ */ jsx3("p", { className: "rt-tpl-hero-carousel-slide-desc", children: selectedSlide.description }) : null,
|
|
327
|
-
selectedSlide.metrics && selectedSlide.metrics.length > 0 ? /* @__PURE__ */ jsx3("dl", { className: "rt-tpl-hero-carousel-slide-metrics", children: selectedSlide.metrics.map((metric) => /* @__PURE__ */ jsxs2("div", { children: [
|
|
328
|
-
/* @__PURE__ */ jsx3("dt", { children: metric.label }),
|
|
329
|
-
/* @__PURE__ */ jsxs2("dd", { children: [
|
|
330
|
-
metric.value,
|
|
331
|
-
metric.unit ? /* @__PURE__ */ jsx3("span", { children: metric.unit }) : null
|
|
332
|
-
] }),
|
|
333
|
-
metric.source ? /* @__PURE__ */ jsx3("dd", { children: metric.source }) : null
|
|
334
|
-
] }, `${metric.value}-${metric.label}`)) }) : null,
|
|
335
|
-
selectedSlide.primaryCta || selectedSlide.secondaryCta ? /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-hero-carousel-slide-actions", children: [
|
|
336
|
-
selectedSlide.primaryCta ? /* @__PURE__ */ jsx3(
|
|
337
|
-
"a",
|
|
338
|
-
{
|
|
339
|
-
className: "rt-tpl-btn rt-tpl-btn--primary",
|
|
340
|
-
href: selectedSlide.primaryCta.href,
|
|
341
|
-
"data-track": "cta_hero",
|
|
342
|
-
children: selectedSlide.primaryCta.label
|
|
343
|
-
}
|
|
344
|
-
) : null,
|
|
345
|
-
selectedSlide.secondaryCta ? /* @__PURE__ */ jsx3(
|
|
346
|
-
"a",
|
|
347
|
-
{
|
|
348
|
-
className: "rt-tpl-btn rt-tpl-btn--secondary",
|
|
349
|
-
href: selectedSlide.secondaryCta.href,
|
|
350
|
-
"data-track": "cta_hero",
|
|
351
|
-
children: selectedSlide.secondaryCta.label
|
|
352
|
-
}
|
|
353
|
-
) : null
|
|
354
|
-
] }) : null
|
|
355
|
-
]
|
|
356
|
-
},
|
|
357
|
-
isCurtain ? `panel-${selectedIndex}` : "panel"
|
|
358
|
-
) : null,
|
|
359
|
-
/* @__PURE__ */ jsxs2("div", { className: "rt-tpl-hero-carousel-controls", children: [
|
|
266
|
+
return (
|
|
267
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- WAI-ARIA 캐러셀 패턴. region 이 좌우 키·포인터를 받고 실제 이동은 안쪽 컨트롤이 담당한다.
|
|
268
|
+
/* @__PURE__ */ jsxs2(
|
|
269
|
+
"div",
|
|
270
|
+
{
|
|
271
|
+
ref: rootRef,
|
|
272
|
+
className: "rt-tpl-hero-carousel",
|
|
273
|
+
role: "region",
|
|
274
|
+
"aria-roledescription": "carousel",
|
|
275
|
+
"aria-label": "\uBC30\uACBD \uC774\uBBF8\uC9C0 \uCE90\uB7EC\uC140",
|
|
276
|
+
tabIndex: 0,
|
|
277
|
+
onKeyDown,
|
|
278
|
+
"data-reduced-motion": reducedMotion ? "true" : "false",
|
|
279
|
+
"data-scrim": scrim ?? "soft",
|
|
280
|
+
"data-transition": transition,
|
|
281
|
+
onMouseEnter: autoplayGate.rootHandlers.onMouseEnter,
|
|
282
|
+
onMouseLeave: autoplayGate.rootHandlers.onMouseLeave,
|
|
283
|
+
onFocus: autoplayGate.rootHandlers.onFocus,
|
|
284
|
+
onBlur: autoplayGate.rootHandlers.onBlur,
|
|
285
|
+
children: [
|
|
286
|
+
isCurtain ? /* @__PURE__ */ jsx3(
|
|
287
|
+
CurtainTrack,
|
|
288
|
+
{
|
|
289
|
+
slides,
|
|
290
|
+
selectedIndex: curtain.selectedIndex,
|
|
291
|
+
leavingIndex: curtain.leavingIndex
|
|
292
|
+
}
|
|
293
|
+
) : /* @__PURE__ */ jsx3(
|
|
294
|
+
SlideTrack,
|
|
295
|
+
{
|
|
296
|
+
viewportRef: emblaRef,
|
|
297
|
+
slides,
|
|
298
|
+
selectedIndex: emblaSelectedIndex
|
|
299
|
+
}
|
|
300
|
+
),
|
|
360
301
|
/* @__PURE__ */ jsx3(
|
|
361
|
-
"
|
|
302
|
+
"button",
|
|
362
303
|
{
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
"aria-label": "\uC2AC\uB77C\uC774\uB4DC
|
|
366
|
-
|
|
367
|
-
children:
|
|
368
|
-
"button",
|
|
369
|
-
{
|
|
370
|
-
...getTabProps(index),
|
|
371
|
-
type: "button",
|
|
372
|
-
role: "tab",
|
|
373
|
-
className: "rt-tpl-hero-carousel-dot",
|
|
374
|
-
"aria-selected": index === selectedIndex,
|
|
375
|
-
"aria-label": `${index + 1}\uBC88 \uC2AC\uB77C\uC774\uB4DC\uB85C \uC774\uB3D9`,
|
|
376
|
-
"data-active": index === selectedIndex ? "true" : "false",
|
|
377
|
-
onClick: () => scrollTo(index),
|
|
378
|
-
children: hasTabLabels ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
379
|
-
/* @__PURE__ */ jsx3("span", { children: _slide.tabLabel ?? `${index + 1}` }),
|
|
380
|
-
_slide.tabMeta ? /* @__PURE__ */ jsx3("small", { children: _slide.tabMeta }) : null
|
|
381
|
-
] }) : null
|
|
382
|
-
},
|
|
383
|
-
index
|
|
384
|
-
))
|
|
304
|
+
type: "button",
|
|
305
|
+
className: "rt-tpl-hero-carousel-arrow rt-tpl-hero-carousel-arrow--prev",
|
|
306
|
+
"aria-label": "\uC774\uC804 \uC2AC\uB77C\uC774\uB4DC",
|
|
307
|
+
onClick: scrollPrev,
|
|
308
|
+
children: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx3("path", { d: "M15 5 8 12l7 7", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
|
|
385
309
|
}
|
|
386
310
|
),
|
|
387
|
-
/* @__PURE__ */
|
|
388
|
-
|
|
389
|
-
|
|
311
|
+
/* @__PURE__ */ jsx3(
|
|
312
|
+
"button",
|
|
313
|
+
{
|
|
314
|
+
type: "button",
|
|
315
|
+
className: "rt-tpl-hero-carousel-arrow rt-tpl-hero-carousel-arrow--next",
|
|
316
|
+
"aria-label": "\uB2E4\uC74C \uC2AC\uB77C\uC774\uB4DC",
|
|
317
|
+
onClick: scrollNext,
|
|
318
|
+
children: /* @__PURE__ */ jsx3("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx3("path", { d: "m9 5 7 7-7 7", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
|
|
319
|
+
}
|
|
320
|
+
),
|
|
321
|
+
hasSlidePanel && selectedSlide ? /* @__PURE__ */ jsxs2(
|
|
322
|
+
"div",
|
|
323
|
+
{
|
|
324
|
+
className: "rt-tpl-hero-carousel-slide-panel",
|
|
325
|
+
children: [
|
|
326
|
+
selectedSlide.eyebrow ? /* @__PURE__ */ jsx3("p", { className: "rt-tpl-hero-carousel-slide-eyebrow", children: selectedSlide.eyebrow }) : null,
|
|
327
|
+
selectedSlide.title ? /* @__PURE__ */ jsx3("p", { className: "rt-tpl-hero-carousel-slide-title", children: selectedSlide.title }) : null,
|
|
328
|
+
selectedSlide.subtitle ? /* @__PURE__ */ jsx3("p", { className: "rt-tpl-hero-carousel-slide-subtitle", children: selectedSlide.subtitle }) : null,
|
|
329
|
+
selectedSlide.description ? /* @__PURE__ */ jsx3("p", { className: "rt-tpl-hero-carousel-slide-desc", children: selectedSlide.description }) : null,
|
|
330
|
+
selectedSlide.metrics && selectedSlide.metrics.length > 0 ? /* @__PURE__ */ jsx3("dl", { className: "rt-tpl-hero-carousel-slide-metrics", children: selectedSlide.metrics.map((metric) => /* @__PURE__ */ jsxs2("div", { children: [
|
|
331
|
+
/* @__PURE__ */ jsx3("dt", { children: metric.label }),
|
|
332
|
+
/* @__PURE__ */ jsxs2("dd", { children: [
|
|
333
|
+
metric.value,
|
|
334
|
+
metric.unit ? /* @__PURE__ */ jsx3("span", { children: metric.unit }) : null
|
|
335
|
+
] }),
|
|
336
|
+
metric.source ? /* @__PURE__ */ jsx3("dd", { children: metric.source }) : null
|
|
337
|
+
] }, `${metric.value}-${metric.label}`)) }) : null,
|
|
338
|
+
selectedSlide.primaryCta || selectedSlide.secondaryCta ? /* @__PURE__ */ jsxs2("div", { className: "rt-tpl-hero-carousel-slide-actions", children: [
|
|
339
|
+
selectedSlide.primaryCta ? /* @__PURE__ */ jsx3(
|
|
340
|
+
"a",
|
|
341
|
+
{
|
|
342
|
+
className: "rt-tpl-btn rt-tpl-btn--primary",
|
|
343
|
+
href: selectedSlide.primaryCta.href,
|
|
344
|
+
"data-track": "cta_hero",
|
|
345
|
+
children: selectedSlide.primaryCta.label
|
|
346
|
+
}
|
|
347
|
+
) : null,
|
|
348
|
+
selectedSlide.secondaryCta ? /* @__PURE__ */ jsx3(
|
|
349
|
+
"a",
|
|
350
|
+
{
|
|
351
|
+
className: "rt-tpl-btn rt-tpl-btn--secondary",
|
|
352
|
+
href: selectedSlide.secondaryCta.href,
|
|
353
|
+
"data-track": "cta_hero",
|
|
354
|
+
children: selectedSlide.secondaryCta.label
|
|
355
|
+
}
|
|
356
|
+
) : null
|
|
357
|
+
] }) : null
|
|
358
|
+
]
|
|
359
|
+
},
|
|
360
|
+
isCurtain ? `panel-${selectedIndex}` : "panel"
|
|
361
|
+
) : null,
|
|
362
|
+
/* @__PURE__ */ jsxs2("div", { className: "rt-tpl-hero-carousel-controls", children: [
|
|
363
|
+
/* @__PURE__ */ jsx3(
|
|
364
|
+
"div",
|
|
390
365
|
{
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
"aria-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
366
|
+
className: hasTabLabels ? "rt-tpl-hero-carousel-dots rt-tpl-hero-carousel-dots--tabs" : "rt-tpl-hero-carousel-dots",
|
|
367
|
+
role: "tablist",
|
|
368
|
+
"aria-label": "\uC2AC\uB77C\uC774\uB4DC \uC120\uD0DD",
|
|
369
|
+
onKeyDown: onTablistKeyDown,
|
|
370
|
+
children: slides.map((_slide, index) => /* @__PURE__ */ jsx3(
|
|
371
|
+
"button",
|
|
372
|
+
{
|
|
373
|
+
...getTabProps(index),
|
|
374
|
+
type: "button",
|
|
375
|
+
role: "tab",
|
|
376
|
+
className: "rt-tpl-hero-carousel-dot",
|
|
377
|
+
"aria-selected": index === selectedIndex,
|
|
378
|
+
"aria-label": `${index + 1}\uBC88 \uC2AC\uB77C\uC774\uB4DC\uB85C \uC774\uB3D9`,
|
|
379
|
+
"data-active": index === selectedIndex ? "true" : "false",
|
|
380
|
+
onClick: () => scrollTo(index),
|
|
381
|
+
children: hasTabLabels ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
382
|
+
/* @__PURE__ */ jsx3("span", { children: _slide.tabLabel ?? `${index + 1}` }),
|
|
383
|
+
_slide.tabMeta ? /* @__PURE__ */ jsx3("small", { children: _slide.tabMeta }) : null
|
|
384
|
+
] }) : null
|
|
385
|
+
},
|
|
386
|
+
index
|
|
387
|
+
))
|
|
397
388
|
}
|
|
398
|
-
)
|
|
399
|
-
/* @__PURE__ */ jsxs2("
|
|
400
|
-
/* @__PURE__ */ jsx3(
|
|
401
|
-
|
|
402
|
-
|
|
389
|
+
),
|
|
390
|
+
/* @__PURE__ */ jsxs2("div", { className: "rt-tpl-hero-carousel-controls-right", children: [
|
|
391
|
+
showPlayPause ? /* @__PURE__ */ jsx3(
|
|
392
|
+
"button",
|
|
393
|
+
{
|
|
394
|
+
type: "button",
|
|
395
|
+
className: "rt-tpl-hero-carousel-playpause",
|
|
396
|
+
"aria-pressed": autoplayGate.userPaused,
|
|
397
|
+
"aria-label": autoplayGate.userPaused ? "\uC790\uB3D9 \uC804\uD658 \uC7AC\uC0DD" : "\uC790\uB3D9 \uC804\uD658 \uC77C\uC2DC\uC815\uC9C0",
|
|
398
|
+
onClick: autoplayGate.togglePaused,
|
|
399
|
+
children: autoplayGate.userPaused ? /* @__PURE__ */ jsx3(PlayIcon, {}) : /* @__PURE__ */ jsx3(PauseIcon, {})
|
|
400
|
+
}
|
|
401
|
+
) : null,
|
|
402
|
+
/* @__PURE__ */ jsxs2("p", { className: "rt-tpl-hero-carousel-counter", "aria-hidden": "true", children: [
|
|
403
|
+
/* @__PURE__ */ jsx3("span", { className: "rt-tpl-hero-carousel-counter-current", children: selectedIndex + 1 }),
|
|
404
|
+
"/",
|
|
405
|
+
/* @__PURE__ */ jsx3("span", { className: "rt-tpl-hero-carousel-counter-total", children: slides.length })
|
|
406
|
+
] })
|
|
403
407
|
] })
|
|
404
408
|
] })
|
|
405
|
-
]
|
|
406
|
-
|
|
407
|
-
|
|
409
|
+
]
|
|
410
|
+
}
|
|
411
|
+
)
|
|
408
412
|
);
|
|
409
413
|
}
|
|
410
414
|
|
|
411
415
|
export {
|
|
412
416
|
HeroCarouselViewport
|
|
413
417
|
};
|
|
414
|
-
//# sourceMappingURL=chunk-
|
|
418
|
+
//# sourceMappingURL=chunk-QYNEOFL7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/templates/hero-carousel-client.tsx","../src/templates/hero-carousel-curtain.tsx","../src/templates/hero-carousel-hooks.ts","../src/templates/hero-carousel-slide-track.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * `hero` `carousel` variant — 배경 사진 전환 메커니즘만 담당하는 client\n * island (M6 서버 우선: 인터랙션 최소 단위 격리). 카피 오버레이(h1/subtitle/\n * eyebrow/CTA)는 `TemplateHero`(RSC, sections.tsx)가 서버에서 그린다 — 이\n * 컴포넌트는 배경 슬라이드 + 도트 + 화살표 + \"N/M\" 카운터만 렌더한다.\n *\n * 빌드 계약: 본 파일은 tsup 의 독립 entry(`hero-carousel-client`)로 번들되고\n * `esbuild-plugin-preserve-directives` 가 \"use client\" 지시어를 해당 청크\n * 최상단에 보존한다 — `templates.js`(서버 전용, 나머지 4개 hero variant +\n * rich-text/services/faq/cta-banner/trust/contact) 로 병합되지 않는다\n * (tsup.config.ts 참고).\n *\n * 모션 규율(M5 + ADR-0086 P2 D3/D4, ds-rule-pack.md):\n * - `transition`: \"slide\"(기본, embla 가로 스크롤) | \"curtain\"(clip-path 와이프\n * — chambarun 이식, `hero-carousel-curtain.tsx`). variant 는 그대로\n * \"carousel\" 하나 — \"variant=구조, motion=인상\" 규칙(신규 variant 금지).\n * - `prefers-reduced-motion: reduce` → autoplay 강제 off + 전환은 즉시(embla\n * `jump=true` 무전환 / curtain 은 leaving 단계 생략) + Ken Burns·신 스윕·카피\n * 스태거 없음.\n * - autoplay 정지 사유 4종(D4): hover, focus-within, pause/재생 버튼, Page\n * Visibility API(탭 비활성). 합성은 `hero-carousel-hooks.ts`\n * `useAutoplayGate`.\n * - 좌/우 화살표 키보드 이동(포커스가 캐러셀 안에 있을 때), 도트는\n * `role=\"tablist\"`/`role=\"tab\"` + roving tabindex(방향키/Home/End, D4) —\n * 공용 `useRovingTablist`(`expertise-client.tsx` 와 동일 계약 재사용).\n * - WAI-ARIA carousel 패턴: 컨테이너 `role=\"region\"` +\n * `aria-roledescription=\"carousel\"`, 슬라이드별 `aria-roledescription=\"slide\"`\n * + `aria-label=\"Slide N of M\"`.\n */\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { KeyboardEvent, ReactElement } from \"react\";\nimport useEmblaCarousel from \"embla-carousel-react\";\n\nimport { useCurtainCarousel, CurtainTrack } from \"./hero-carousel-curtain.js\";\nimport { useAutoplayGate, usePrefersReducedMotion } from \"./hero-carousel-hooks.js\";\nimport { SlideTrack } from \"./hero-carousel-slide-track.js\";\nimport type { HeroCarouselViewportProps } from \"./hero-carousel-types.js\";\nimport { useRovingTablist } from \"./use-roving-tablist.js\";\n\nexport type {\n HeroCarouselSlideInput,\n HeroCarouselTransition,\n HeroCarouselViewportProps,\n} from \"./hero-carousel-types.js\";\n\nfunction PauseIcon(): ReactElement {\n return (\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <rect x=\"6\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" fill=\"currentColor\" />\n <rect x=\"14\" y=\"5\" width=\"4\" height=\"14\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n );\n}\n\nfunction PlayIcon(): ReactElement {\n return (\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M8 5v14l11-7z\" fill=\"currentColor\" />\n </svg>\n );\n}\n\nexport function HeroCarouselViewport({\n slides,\n autoplay,\n intervalMs,\n scrim,\n transition = \"slide\",\n}: HeroCarouselViewportProps) {\n const isCurtain = transition === \"curtain\";\n const reducedMotion = usePrefersReducedMotion();\n const rootRef = useRef<HTMLDivElement | null>(null);\n\n const [emblaRef, emblaApi] = useEmblaCarousel({\n loop: true,\n duration: reducedMotion ? 1 : 20,\n });\n const [emblaSelectedIndex, setEmblaSelectedIndex] = useState(0);\n const curtain = useCurtainCarousel(slides.length, reducedMotion);\n\n const onEmblaSelect = useCallback(() => {\n if (!emblaApi) return;\n setEmblaSelectedIndex(emblaApi.selectedScrollSnap());\n }, [emblaApi]);\n\n useEffect(() => {\n if (!emblaApi) return;\n // eslint-disable-next-line react-hooks/set-state-in-effect -- 캐러셀 인스턴스가 준비된 뒤 현재 위치를 한 번 읽어 맞춘다(이후는 select 이벤트가 갱신). 외부 라이브러리 상태 구독이다.\n onEmblaSelect();\n emblaApi.on(\"select\", onEmblaSelect);\n emblaApi.on(\"reInit\", onEmblaSelect);\n return () => {\n emblaApi.off(\"select\", onEmblaSelect);\n emblaApi.off(\"reInit\", onEmblaSelect);\n };\n }, [emblaApi, onEmblaSelect]);\n\n const selectedIndex = isCurtain ? curtain.selectedIndex : emblaSelectedIndex;\n\n const autoplayGate = useAutoplayGate({ autoplay, reducedMotion, rootRef });\n\n useEffect(() => {\n if (!autoplayGate.shouldAutoplay) return;\n if (!isCurtain && !emblaApi) return;\n const id = window.setInterval(() => {\n if (isCurtain) curtain.next();\n else emblaApi?.scrollNext();\n }, intervalMs);\n return () => window.clearInterval(id);\n // curtain 객체 전체가 아니라 쓰는 메서드만 의존성에 둔다 — 메서드는\n // useCallback 으로 안정화돼 있고(hero-carousel-curtain.tsx), 객체는 매 렌더\n // 새로 만들어져 전체를 넣으면 타이머가 매번 다시 걸린다.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [autoplayGate.shouldAutoplay, intervalMs, isCurtain, curtain.next, emblaApi]);\n\n const scrollPrev = useCallback(() => {\n if (isCurtain) {\n curtain.prev();\n return;\n }\n emblaApi?.scrollPrev(reducedMotion);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- 위와 같은 이유(안정화된 메서드만 의존).\n }, [isCurtain, curtain.prev, emblaApi, reducedMotion]);\n\n const scrollNext = useCallback(() => {\n if (isCurtain) {\n curtain.next();\n return;\n }\n emblaApi?.scrollNext(reducedMotion);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- 위와 같은 이유(안정화된 메서드만 의존).\n }, [isCurtain, curtain.next, emblaApi, reducedMotion]);\n\n const scrollTo = useCallback(\n (index: number) => {\n if (isCurtain) {\n curtain.goTo(index);\n return;\n }\n emblaApi?.scrollTo(index, reducedMotion);\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps -- 위와 같은 이유(안정화된 메서드만 의존).\n [isCurtain, curtain.goTo, emblaApi, reducedMotion],\n );\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n scrollPrev();\n } else if (event.key === \"ArrowRight\") {\n event.preventDefault();\n scrollNext();\n }\n },\n [scrollPrev, scrollNext],\n );\n\n const selectedSlide = slides[selectedIndex];\n const hasSlidePanel = Boolean(\n selectedSlide &&\n (selectedSlide.eyebrow ||\n selectedSlide.title ||\n selectedSlide.subtitle ||\n selectedSlide.description ||\n selectedSlide.primaryCta ||\n selectedSlide.secondaryCta ||\n (selectedSlide.metrics && selectedSlide.metrics.length > 0)),\n );\n const hasTabLabels = slides.some((slide) => slide.tabLabel || slide.tabMeta);\n const showPlayPause = autoplay && !reducedMotion;\n\n const { getTabProps, onKeyDown: onTablistKeyDown } = useRovingTablist<HTMLButtonElement>({\n count: slides.length,\n selectedIndex,\n onSelect: scrollTo,\n orientation: \"horizontal\",\n });\n\n return (\n // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- WAI-ARIA 캐러셀 패턴. region 이 좌우 키·포인터를 받고 실제 이동은 안쪽 컨트롤이 담당한다.\n <div\n ref={rootRef}\n className=\"rt-tpl-hero-carousel\"\n role=\"region\"\n aria-roledescription=\"carousel\"\n aria-label=\"배경 이미지 캐러셀\"\n tabIndex={0}\n onKeyDown={onKeyDown}\n data-reduced-motion={reducedMotion ? \"true\" : \"false\"}\n data-scrim={scrim ?? \"soft\"}\n data-transition={transition}\n onMouseEnter={autoplayGate.rootHandlers.onMouseEnter}\n onMouseLeave={autoplayGate.rootHandlers.onMouseLeave}\n onFocus={autoplayGate.rootHandlers.onFocus}\n onBlur={autoplayGate.rootHandlers.onBlur}\n >\n {isCurtain ? (\n <CurtainTrack\n slides={slides}\n selectedIndex={curtain.selectedIndex}\n leavingIndex={curtain.leavingIndex}\n />\n ) : (\n <SlideTrack\n viewportRef={emblaRef}\n slides={slides}\n selectedIndex={emblaSelectedIndex}\n />\n )}\n\n <button\n type=\"button\"\n className=\"rt-tpl-hero-carousel-arrow rt-tpl-hero-carousel-arrow--prev\"\n aria-label=\"이전 슬라이드\"\n onClick={scrollPrev}\n >\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <path d=\"M15 5 8 12l7 7\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n <button\n type=\"button\"\n className=\"rt-tpl-hero-carousel-arrow rt-tpl-hero-carousel-arrow--next\"\n aria-label=\"다음 슬라이드\"\n onClick={scrollNext}\n >\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <path d=\"m9 5 7 7-7 7\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n </button>\n\n {hasSlidePanel && selectedSlide ? (\n <div\n key={isCurtain ? `panel-${selectedIndex}` : \"panel\"}\n className=\"rt-tpl-hero-carousel-slide-panel\"\n >\n {selectedSlide.eyebrow ? (\n <p className=\"rt-tpl-hero-carousel-slide-eyebrow\">\n {selectedSlide.eyebrow}\n </p>\n ) : null}\n {selectedSlide.title ? (\n <p className=\"rt-tpl-hero-carousel-slide-title\">\n {selectedSlide.title}\n </p>\n ) : null}\n {selectedSlide.subtitle ? (\n <p className=\"rt-tpl-hero-carousel-slide-subtitle\">\n {selectedSlide.subtitle}\n </p>\n ) : null}\n {selectedSlide.description ? (\n <p className=\"rt-tpl-hero-carousel-slide-desc\">\n {selectedSlide.description}\n </p>\n ) : null}\n {selectedSlide.metrics && selectedSlide.metrics.length > 0 ? (\n <dl className=\"rt-tpl-hero-carousel-slide-metrics\">\n {selectedSlide.metrics.map((metric) => (\n <div key={`${metric.value}-${metric.label}`}>\n <dt>{metric.label}</dt>\n <dd>\n {metric.value}\n {metric.unit ? <span>{metric.unit}</span> : null}\n </dd>\n {metric.source ? <dd>{metric.source}</dd> : null}\n </div>\n ))}\n </dl>\n ) : null}\n {selectedSlide.primaryCta || selectedSlide.secondaryCta ? (\n <div className=\"rt-tpl-hero-carousel-slide-actions\">\n {selectedSlide.primaryCta ? (\n <a\n className=\"rt-tpl-btn rt-tpl-btn--primary\"\n href={selectedSlide.primaryCta.href}\n data-track=\"cta_hero\"\n >\n {selectedSlide.primaryCta.label}\n </a>\n ) : null}\n {selectedSlide.secondaryCta ? (\n <a\n className=\"rt-tpl-btn rt-tpl-btn--secondary\"\n href={selectedSlide.secondaryCta.href}\n data-track=\"cta_hero\"\n >\n {selectedSlide.secondaryCta.label}\n </a>\n ) : null}\n </div>\n ) : null}\n </div>\n ) : null}\n\n <div className=\"rt-tpl-hero-carousel-controls\">\n {/* eslint-disable-next-line jsx-a11y/interactive-supports-focus -- WAI-ARIA 탭 패턴(roving tabindex). 초점은 개별 인디케이터가 갖고 컨테이너는 키 이벤트만 위임받는다. */}\n <div\n className={\n hasTabLabels\n ? \"rt-tpl-hero-carousel-dots rt-tpl-hero-carousel-dots--tabs\"\n : \"rt-tpl-hero-carousel-dots\"\n }\n role=\"tablist\"\n aria-label=\"슬라이드 선택\"\n onKeyDown={onTablistKeyDown}\n >\n {slides.map((_slide, index) => (\n <button\n key={index}\n {...getTabProps(index)}\n type=\"button\"\n role=\"tab\"\n className=\"rt-tpl-hero-carousel-dot\"\n aria-selected={index === selectedIndex}\n aria-label={`${index + 1}번 슬라이드로 이동`}\n data-active={index === selectedIndex ? \"true\" : \"false\"}\n onClick={() => scrollTo(index)}\n >\n {hasTabLabels ? (\n <>\n <span>{_slide.tabLabel ?? `${index + 1}`}</span>\n {_slide.tabMeta ? <small>{_slide.tabMeta}</small> : null}\n </>\n ) : null}\n </button>\n ))}\n </div>\n <div className=\"rt-tpl-hero-carousel-controls-right\">\n {showPlayPause ? (\n <button\n type=\"button\"\n className=\"rt-tpl-hero-carousel-playpause\"\n aria-pressed={autoplayGate.userPaused}\n aria-label={\n autoplayGate.userPaused ? \"자동 전환 재생\" : \"자동 전환 일시정지\"\n }\n onClick={autoplayGate.togglePaused}\n >\n {autoplayGate.userPaused ? <PlayIcon /> : <PauseIcon />}\n </button>\n ) : null}\n <p className=\"rt-tpl-hero-carousel-counter\" aria-hidden=\"true\">\n <span className=\"rt-tpl-hero-carousel-counter-current\">\n {selectedIndex + 1}\n </span>\n /\n <span className=\"rt-tpl-hero-carousel-counter-total\">{slides.length}</span>\n </p>\n </div>\n </div>\n </div>\n );\n}\n","\"use client\";\n\n/**\n * `curtain` transition — chambarun 이식(ADR-0086 P2 D3).\n * 모션 스펙 원본: chambarun mockup `assets/site.css` `@keyframes curtainReveal`\n * (clip-path 와이프) + `.curtain-sheen`(신 스윕) + `.hero-copy>*` 스태거, 엔진은\n * `assets/site.js` 36-85행 `show(n)`(is-active/is-leaving 상태 머신, 980ms 뒤\n * is-leaving 정리). 타이밍·이징·클립 경로는 원본 값을 그대로 유지하고 색은\n * 하드코딩 헥스 대신 `--rt-*` 토큰으로 치환했다(CSS, `templates.css` 참고).\n *\n * embla 를 쓰지 않는다 — embla 는 가로 스크롤 트랙 물리 이동이 전제라\n * clip-path 와이프(절대배치 스택)와 구조가 다르다. `hero-carousel-client.tsx`\n * 400줄 상한 분할.\n */\nimport { useCallback, useRef, useState } from \"react\";\nimport type { ReactElement } from \"react\";\n\nimport type { HeroCarouselSlideInput } from \"./hero-carousel-types.js\";\n\n/** chambarun site.js — is-leaving 클래스 정리 타이밍(커튼 리빌 .92s + 여유). */\nconst LEAVING_CLEAR_MS = 980;\n\nexport interface CurtainCarouselController {\n readonly selectedIndex: number;\n readonly leavingIndex: number | null;\n readonly goTo: (index: number) => void;\n readonly next: () => void;\n readonly prev: () => void;\n}\n\n/**\n * `curtain` 전용 인덱스 상태 머신 — chambarun `show(n)` 이식. `reducedMotion`\n * 이면 leaving 단계를 만들지 않는다(D4 — 커튼 대신 즉시 전환).\n */\nexport function useCurtainCarousel(\n slideCount: number,\n reducedMotion: boolean,\n): CurtainCarouselController {\n const [selectedIndex, setSelectedIndex] = useState(0);\n const [leavingIndex, setLeavingIndex] = useState<number | null>(null);\n const selectedRef = useRef(0);\n const runRef = useRef(0);\n const clearTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n const goTo = useCallback(\n (nextRaw: number) => {\n if (slideCount < 1) return;\n const nextIndex = ((nextRaw % slideCount) + slideCount) % slideCount;\n const prevIndex = selectedRef.current;\n if (nextIndex === prevIndex) return;\n selectedRef.current = nextIndex;\n setSelectedIndex(nextIndex);\n clearTimeout(clearTimerRef.current);\n if (reducedMotion) {\n setLeavingIndex(null);\n return;\n }\n setLeavingIndex(prevIndex);\n runRef.current += 1;\n const runId = runRef.current;\n clearTimerRef.current = setTimeout(() => {\n if (runId === runRef.current) setLeavingIndex(null);\n }, LEAVING_CLEAR_MS);\n },\n [slideCount, reducedMotion],\n );\n\n const next = useCallback(() => goTo(selectedRef.current + 1), [goTo]);\n const prev = useCallback(() => goTo(selectedRef.current - 1), [goTo]);\n\n return { selectedIndex, leavingIndex, goTo, next, prev };\n}\n\nexport interface CurtainTrackProps {\n readonly slides: readonly HeroCarouselSlideInput[];\n readonly selectedIndex: number;\n readonly leavingIndex: number | null;\n}\n\n/**\n * 절대배치 스택 트랙(chambarun `.slide{position:absolute;inset:0}`) — 각\n * 슬라이드가 `data-active`/`data-leaving` 로 clip-path 와이프·오버랩을\n * 제어한다(CSS `templates.css` `[data-transition=\"curtain\"]` 스코프). 활성\n * 슬라이드에만 신 스윕 엘리먼트를 렌더(비활성 슬라이드는 DOM 비용 절감).\n */\nexport function CurtainTrack({\n slides,\n selectedIndex,\n leavingIndex,\n}: CurtainTrackProps): ReactElement {\n return (\n <div className=\"rt-tpl-hero-carousel-viewport\">\n <div className=\"rt-tpl-hero-carousel-track\">\n {slides.map((slide, index) => {\n const active = index === selectedIndex;\n const leaving = index === leavingIndex;\n return (\n <div\n key={`${slide.image}-${index}`}\n className=\"rt-tpl-hero-carousel-slide\"\n aria-roledescription=\"slide\"\n aria-label={`Slide ${index + 1} of ${slides.length}`}\n aria-hidden={active ? undefined : true}\n data-active={active ? \"true\" : \"false\"}\n data-leaving={leaving ? \"true\" : \"false\"}\n >\n <img\n className=\"rt-tpl-hero-carousel-img\"\n src={slide.image}\n alt={slide.alt}\n data-active={active ? \"true\" : \"false\"}\n loading={index === 0 ? \"eager\" : \"lazy\"}\n />\n {active ? (\n <span className=\"rt-tpl-hero-carousel-sheen\" aria-hidden=\"true\" />\n ) : null}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n","\"use client\";\n\n/**\n * `hero` `carousel` 공유 훅 — reduced-motion·document visibility·autoplay\n * 정지 사유 합성(D4 접근성 계약, ADR-0086 P2). `hero-carousel-client.tsx` 400줄\n * 상한 분할.\n */\nimport { useCallback, useState } from \"react\";\nimport type { FocusEvent, RefObject } from \"react\";\nimport { useEffect } from \"react\";\n\nexport function usePrefersReducedMotion(): boolean {\n const [reduced, setReduced] = useState(false);\n useEffect(() => {\n const query = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n setReduced(query.matches);\n const onChange = (event: MediaQueryListEvent) => setReduced(event.matches);\n query.addEventListener(\"change\", onChange);\n return () => query.removeEventListener(\"change\", onChange);\n }, []);\n return reduced;\n}\n\nexport function useDocumentVisible(): boolean {\n const [visible, setVisible] = useState(true);\n useEffect(() => {\n const onVisibility = () => setVisible(document.visibilityState === \"visible\");\n onVisibility();\n document.addEventListener(\"visibilitychange\", onVisibility);\n return () => document.removeEventListener(\"visibilitychange\", onVisibility);\n }, []);\n return visible;\n}\n\nexport interface AutoplayGate {\n /** 실제 autoplay 인터벌을 걸어도 되는지 — 모든 정지 사유의 합성 결과. */\n readonly shouldAutoplay: boolean;\n /** pause/재생 버튼이 반영하는 사용자 의도(수동 일시정지). */\n readonly userPaused: boolean;\n readonly togglePaused: () => void;\n /** 루트 엘리먼트에 그대로 스프레드 — hover/focus-within 일시정지. */\n readonly rootHandlers: {\n readonly onMouseEnter: () => void;\n readonly onMouseLeave: () => void;\n readonly onFocus: () => void;\n readonly onBlur: (event: FocusEvent<HTMLElement>) => void;\n };\n}\n\n/**\n * autoplay pause 사유 4종(D4): hover, focus-within, 사용자 버튼, 문서 비가시.\n * `reducedMotion` 은 autoplay 자체를 아예 시작하지 않는 별도 계약이라 이 훅\n * 밖(`autoplay && !reducedMotion`)에서 이미 걸러지지만, 재확인 차원에서 인자로\n * 받아 합성식에도 포함한다.\n */\nexport function useAutoplayGate(params: {\n readonly autoplay: boolean;\n readonly reducedMotion: boolean;\n readonly rootRef: RefObject<HTMLElement | null>;\n}): AutoplayGate {\n const { autoplay, reducedMotion, rootRef } = params;\n const tabVisible = useDocumentVisible();\n const [hovered, setHovered] = useState(false);\n const [focusedWithin, setFocusedWithin] = useState(false);\n const [userPaused, setUserPaused] = useState(false);\n\n const onBlur = useCallback(\n (event: FocusEvent<HTMLElement>) => {\n const next = event.relatedTarget as Node | null;\n if (!next || !rootRef.current?.contains(next)) {\n setFocusedWithin(false);\n }\n },\n [rootRef],\n );\n\n const shouldAutoplay =\n autoplay &&\n !reducedMotion &&\n tabVisible &&\n !userPaused &&\n !hovered &&\n !focusedWithin;\n\n return {\n shouldAutoplay,\n userPaused,\n togglePaused: () => setUserPaused((value) => !value),\n rootHandlers: {\n onMouseEnter: () => setHovered(true),\n onMouseLeave: () => setHovered(false),\n onFocus: () => setFocusedWithin(true),\n onBlur,\n },\n };\n}\n","\"use client\";\n\n/**\n * `slide` transition(기본값) 트랙 — 기존 embla 가로 스크롤 배경 전환, 회귀 없음.\n * `hero-carousel-client.tsx` 400줄 상한 분할(`curtain` transition 은\n * `hero-carousel-curtain.tsx`).\n */\nimport type { ReactElement } from \"react\";\nimport type { EmblaViewportRefType } from \"embla-carousel-react\";\n\nimport type { HeroCarouselSlideInput } from \"./hero-carousel-types.js\";\n\nexport interface SlideTrackProps {\n readonly viewportRef: EmblaViewportRefType;\n readonly slides: readonly HeroCarouselSlideInput[];\n readonly selectedIndex: number;\n}\n\nexport function SlideTrack({\n viewportRef,\n slides,\n selectedIndex,\n}: SlideTrackProps): ReactElement {\n return (\n <div className=\"rt-tpl-hero-carousel-viewport\" ref={viewportRef}>\n <div className=\"rt-tpl-hero-carousel-track\">\n {slides.map((slide, index) => (\n <div\n key={`${slide.image}-${index}`}\n className=\"rt-tpl-hero-carousel-slide\"\n aria-roledescription=\"slide\"\n aria-label={`Slide ${index + 1} of ${slides.length}`}\n aria-hidden={index === selectedIndex ? undefined : true}\n >\n <img\n className=\"rt-tpl-hero-carousel-img\"\n src={slide.image}\n alt={slide.alt}\n data-active={index === selectedIndex ? \"true\" : \"false\"}\n loading={index === 0 ? \"eager\" : \"lazy\"}\n />\n </div>\n ))}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","useCallback","useState","jsx","jsx","jsxs","useRef","useState","useCallback","useEffect"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { C as ConcernsSection } from './site-config-
|
|
2
|
+
import { C as ConcernsSection } from './site-config-DNpvlqA5.js';
|
|
3
3
|
import 'zod';
|
|
4
4
|
|
|
5
5
|
type ConcernRegion = ConcernsSection["props"]["regions"][number];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { E as ExpertiseSection } from './site-config-
|
|
2
|
+
import { E as ExpertiseSection } from './site-config-DNpvlqA5.js';
|
|
3
3
|
import 'zod';
|
|
4
4
|
|
|
5
5
|
type ExpertiseItem = ExpertiseSection["props"]["items"][number];
|
package/dist/expertise-client.js
CHANGED