@ihabdevteam/core 0.167.0 → 0.169.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.
@@ -309,7 +309,7 @@ export declare type BadgeType = 'bar' | 'dot';
309
309
  * - 주(week): 'YYYY년 M월 N째주' 드롭다운 + 그 주의 요일(월~일) 막대
310
310
  * 원시 렌더링은 내부 BarChartCanvas가 담당한다.
311
311
  */
312
- export declare function BarChart({ size, barWidth, titleKey, data, colorA, colorB, labelAKey, labelBKey, showTotal, totalUnitKey, totalLabelKey, control: controlProp, hideControls, rate, rateAgg, tightMax, avgMode, totalFormat, series, seriesMode, loading, onDetail, headExtra, headSegment, icon, disc, detailSize, barGap, baseline, className, inGrid, }: BarChartProps): JSX.Element;
312
+ export declare function BarChart({ size, barWidth, titleKey, data, colorA, colorB, labelAKey, labelBKey, showTotal, totalUnitKey, totalLabelKey, control: controlProp, hideControls, rate, rateAgg, tightMax, avgMode, totalFormat, series, seriesMode, loading, onDetail, headExtra, headSegment, icon, disc, onClick, cardAriaLabel, detailSize, barGap, baseline, className, inGrid, }: BarChartProps): JSX.Element;
313
313
 
314
314
  /** @public */
315
315
  export declare interface BarChartControl {
@@ -413,6 +413,10 @@ export declare interface BarChartProps {
413
413
  /** 머리의 보기 고르개 — 넓으면 세그먼트, 카드가 좁으면 '⋯' 한 단추로 접히고 그 메뉴에 칸들과 '상세보기' 가 함께 든다.
414
414
  * `headExtra` 로 고르개를 손수 얹고 좁을 때를 따로 다루던 것을 대신한다(ChartSection 이 카드 제 폭으로 잰다). */
415
415
  headSegment?: ChartHeadSegment;
416
+ /** 카드 자체를 누를 수 있게 — 커서·hover 테두리·키보드까지 ChartSection 이 한 결로 붙인다(머리의 단추·고르개 누름은 카드를 열지 않는다) */
417
+ onClick?: () => void;
418
+ /** 누르는 카드의 이름(낭독기) — 안 주면 제목 */
419
+ cardAriaLabel?: string;
416
420
  /** 제목 왼쪽 아이콘 — Section·ChartSection 과 같은 자리·같은 색 */
417
421
  icon?: string;
418
422
  /** 제목 아래 설명 한 줄 */
@@ -1049,7 +1053,7 @@ export declare interface ChartPoint {
1049
1053
  * 공유하도록 두 컴포넌트가 내부적으로 사용한다.
1050
1054
  * @public
1051
1055
  */
1052
- export declare function ChartSection({ title, titleClassName, icon, disc, headRight, headSegment, headMenuItems, collapseBelow, subRow, className, inGrid, children }: ChartSectionProps): JSX.Element;
1056
+ export declare function ChartSection({ title, titleClassName, icon, disc, headRight, headSegment, headMenuItems, collapseBelow, onClick, ariaLabel, subRow, className, inGrid, children }: ChartSectionProps): JSX.Element;
1053
1057
 
1054
1058
  /** @public */
1055
1059
  export declare interface ChartSectionProps {
@@ -1072,6 +1076,11 @@ export declare interface ChartSectionProps {
1072
1076
  headMenuItems?: TooltipMenuColumnItem[];
1073
1077
  /** 고르개를 '⋯' 로 접는 카드 폭(px, 기본 420) */
1074
1078
  collapseBelow?: number;
1079
+ /** 카드 자체를 누를 수 있게 한다 — 커서·hover 테두리·키보드(Enter·Space)·role·tabIndex 를 한 결로 붙인다.
1080
+ * `StatChart onClick` 과 같은 모양이다(소비자가 감싸개를 만들어 흉내 내던 것). */
1081
+ onClick?: () => void;
1082
+ /** 누르는 카드의 이름(낭독기) — 안 주면 제목이 글자일 때 그것을 쓴다 */
1083
+ ariaLabel?: string;
1075
1084
  /** 총계(ChartTotal) + 범례(ChartLegend)를 담는 서브로우 */
1076
1085
  subRow?: ReactNode;
1077
1086
  /** 섹션 루트에 추가할 클래스 */
@@ -1541,7 +1550,7 @@ export declare function copyText(text: string): Promise<boolean>;
1541
1550
  *
1542
1551
  * 값은 손으로 적고 `test/coreVersion.test.ts` 가 package.json 과 어긋나면 운다.
1543
1552
  */
1544
- export declare const CORE_VERSION = "0.167.0";
1553
+ export declare const CORE_VERSION = "0.169.0";
1545
1554
 
1546
1555
  /** @public */
1547
1556
  declare const coreDefault: Record<string, unknown>;
@@ -4342,6 +4351,9 @@ export declare interface PopupListProps<T extends {
4342
4351
  columns: PopupListColumn<T>[];
4343
4352
  /** Table grid template columns (예: "20% 10% 22% 26% 22%") */
4344
4353
  gridTemplateColumns?: string;
4354
+ /** 좁은 화면(767px 이하)에서 쓸 칸 폭 — 창 안의 표도 같은 `Table` 이라 그대로 전한다.
4355
+ * 문턱을 달리 하려면 CSS 에서 `--table-grid-cols-override` 를 준다(창은 body 로 나가므로 창의 `className` 으로 좁힌다). */
4356
+ mobileGridTemplateColumns?: string;
4345
4357
  /** 검색 placeholder */
4346
4358
  searchPlaceholder?: string;
4347
4359
  /**
@@ -5329,7 +5341,7 @@ export declare function reviewTableName(original: string | ReviewSource, today:
5329
5341
  * 미지정 시에는 헤더 없는 순수 링만 렌더된다(크기/색상 데모 등).
5330
5342
  * @public
5331
5343
  */
5332
- export declare function RingChart({ titleKey, headRight, icon, showTotal, totalLabelKey, legend, loading, className, inGrid, ...ringProps }: RingChartProps): JSX.Element;
5344
+ export declare function RingChart({ titleKey, headRight, icon, showTotal, totalLabelKey, legend, loading, className, inGrid, onClick, ariaLabel, ...ringProps }: RingChartProps): JSX.Element;
5333
5345
 
5334
5346
  /** @public */
5335
5347
  export declare interface RingChartProps {
@@ -5382,6 +5394,10 @@ export declare interface RingChartProps {
5382
5394
  className?: string;
5383
5395
  /** CSS 격자 칸 안에 세운다 — 아래 여백·최소 폭을 풀고 링을 카드 바닥에 맞춘다. ChartSection `inGrid` 참고(titleKey 지정 시에만 사용) */
5384
5396
  inGrid?: boolean;
5397
+ /** 카드 자체를 누를 수 있게 — 커서·hover 테두리·키보드까지 ChartSection 이 한 결로 붙인다(titleKey 지정 시에만) */
5398
+ onClick?: () => void;
5399
+ /** 누르는 카드의 이름(낭독기) — 안 주면 제목 */
5400
+ ariaLabel?: string;
5385
5401
  }
5386
5402
 
5387
5403
  /** @public */
@@ -6197,7 +6213,7 @@ export declare function splitTrainingVariants(value: unknown): string[];
6197
6213
  * (도넛 breakdown은 RingChart segments 모드, 리스트는 페이지에서 직접 구성).
6198
6214
  * @public
6199
6215
  */
6200
- export declare function StatChart({ label, value, change, changeType, icon, tooltip, onClick }: StatChartProps): JSX.Element;
6216
+ export declare function StatChart({ label, value, change, changeType, icon, tooltip, onClick, children }: StatChartProps): JSX.Element;
6201
6217
 
6202
6218
  /** @public */
6203
6219
  export declare type StatChartChangeType = 'up' | 'down' | 'neutral';
@@ -6217,6 +6233,9 @@ export declare interface StatChartProps {
6217
6233
  /** 호버 시 표시할 툴팁 텍스트 */
6218
6234
  tooltip?: string;
6219
6235
  onClick?: () => void;
6236
+ /** 값 **아래** 에 붙는 자리 — 목록 몇 줄, "외 n건" 단추처럼 값을 풀어 보이는 것.
6237
+ * 이 자리가 없어 소비자가 카드 마크업(`manager-stat-card__*` 여덟 이름)을 통째로 베끼고 있었다(말귀 매니저 '금일 방문 예정'). */
6238
+ children?: ReactNode;
6220
6239
  }
6221
6240
 
6222
6241
  /**
@@ -13,4 +13,4 @@ import type { BarChartProps } from './barChartTypes';
13
13
  * - 주(week): 'YYYY년 M월 N째주' 드롭다운 + 그 주의 요일(월~일) 막대
14
14
  * 원시 렌더링은 내부 BarChartCanvas가 담당한다.
15
15
  */
16
- export default function BarChart({ size, barWidth, titleKey, data, colorA, colorB, labelAKey, labelBKey, showTotal, totalUnitKey, totalLabelKey, control: controlProp, hideControls, rate, rateAgg, tightMax, avgMode, totalFormat, series, seriesMode, loading, onDetail, headExtra, headSegment, icon, disc, detailSize, barGap, baseline, className, inGrid, }: BarChartProps): import("react").JSX.Element;
16
+ export default function BarChart({ size, barWidth, titleKey, data, colorA, colorB, labelAKey, labelBKey, showTotal, totalUnitKey, totalLabelKey, control: controlProp, hideControls, rate, rateAgg, tightMax, avgMode, totalFormat, series, seriesMode, loading, onDetail, headExtra, headSegment, icon, disc, onClick, cardAriaLabel, detailSize, barGap, baseline, className, inGrid, }: BarChartProps): import("react").JSX.Element;
@@ -261,7 +261,7 @@ const BAR_SIZE_PRESET = {
261
261
  * - 주(week): 'YYYY년 M월 N째주' 드롭다운 + 그 주의 요일(월~일) 막대
262
262
  * 원시 렌더링은 내부 BarChartCanvas가 담당한다.
263
263
  */
264
- export default function BarChart({ size = 'medium', barWidth, titleKey, data, colorA, colorB, labelAKey, labelBKey, showTotal = false, totalUnitKey, totalLabelKey, control: controlProp, hideControls = false, rate = false, rateAgg = 'dayMean', tightMax = false, avgMode = false, totalFormat, series, seriesMode = 'stack', loading = false, onDetail, headExtra, headSegment, icon, disc, detailSize = 32, barGap, baseline, className, inGrid = false, }) {
264
+ export default function BarChart({ size = 'medium', barWidth, titleKey, data, colorA, colorB, labelAKey, labelBKey, showTotal = false, totalUnitKey, totalLabelKey, control: controlProp, hideControls = false, rate = false, rateAgg = 'dayMean', tightMax = false, avgMode = false, totalFormat, series, seriesMode = 'stack', loading = false, onDetail, headExtra, headSegment, icon, disc, onClick, cardAriaLabel, detailSize = 32, barGap, baseline, className, inGrid = false, }) {
265
265
  const { t, i18n } = useTranslation();
266
266
  const sizePreset = BAR_SIZE_PRESET[size];
267
267
  // 외부 control 미지정 시 내부 컨트롤 사용 (단독 차트 하위 호환)
@@ -397,7 +397,7 @@ export default function BarChart({ size = 'medium', barWidth, titleKey, data, co
397
397
  const isLarge = size === 'large';
398
398
  const sectionClassName = [isSmall ? 'manager-section--compact' : isLarge ? 'manager-section--full' : undefined, className]
399
399
  .filter(Boolean).join(' ') || undefined;
400
- return (_jsx(ChartSection, { className: sectionClassName, inGrid: inGrid, icon: icon, disc: disc, headSegment: headSegment,
400
+ return (_jsx(ChartSection, { className: sectionClassName, inGrid: inGrid, icon: icon, disc: disc, onClick: onClick, ariaLabel: cardAriaLabel, headSegment: headSegment,
401
401
  /* 좁아 고르개가 '⋯' 로 접히면 상세보기도 그 메뉴로 들어간다 — 머리에 단추 둘이 남지 않게 */
402
402
  headMenuItems: onDetail ? [{ label: t('trainingStatus.detail', '상세보기'), icon: 'list', onClick: onDetail, closeOnSelect: true }] : undefined, title: t(titleKey), titleClassName: isSmall ? 'h5 chart-section-title--small' : undefined, headRight: isSmall ? (headExtra ?? undefined) : ({ collapsed }) => _jsxs(_Fragment, { children: [!hideControls && _jsx(BarChartControls, { control: control }), headExtra, onDetail && !collapsed && (_jsx("span", { className: "manager-bar-chart-detail-btn", children: _jsx(Button, { htmlType: "button", size: detailSize, type: "dot", icon: "list", ariaLabel: t('trainingStatus.detail', '상세보기'), showTooltipInfo: t('trainingStatus.detail', '상세보기'), onClick: onDetail }) }))] }), subRow: _jsxs(_Fragment, { children: [showTotal ? ((rate || avgMode || (!!totalLabelKey && !!totalFormat)) ? (
403
403
  // 진행률/평균 모드 또는 totalLabelKey+totalFormat 조합: 라벨(윗줄) + 값(아랫줄). size='small'은 라벨 생략
@@ -17,6 +17,16 @@
17
17
  /* 차트 카드 — inline 나열 가능하도록 최소 폭만 지정(최대 폭 제한 없음) */
18
18
  min-width: 320px;
19
19
  }
20
+ /* 누르는 카드 — StatChart 의 누르는 카드와 같은 결(커서·hover 테두리). 소비자가 감싸개로 흉내 내던 것 */
21
+ .manager-section--clickable {
22
+ cursor: pointer;
23
+ transition: box-shadow 120ms ease, border-color 120ms ease;
24
+ }
25
+ .manager-section--clickable:hover {
26
+ border-color: var(--color-main);
27
+ box-shadow: var(--shadow-dropdown);
28
+ }
29
+
20
30
  .manager-section__head {
21
31
  display: flex;
22
32
  justify-content: space-between;
@@ -56,6 +56,11 @@ export interface ChartSectionProps {
56
56
  headMenuItems?: TooltipMenuColumnItem[];
57
57
  /** 고르개를 '⋯' 로 접는 카드 폭(px, 기본 420) */
58
58
  collapseBelow?: number;
59
+ /** 카드 자체를 누를 수 있게 한다 — 커서·hover 테두리·키보드(Enter·Space)·role·tabIndex 를 한 결로 붙인다.
60
+ * `StatChart onClick` 과 같은 모양이다(소비자가 감싸개를 만들어 흉내 내던 것). */
61
+ onClick?: () => void;
62
+ /** 누르는 카드의 이름(낭독기) — 안 주면 제목이 글자일 때 그것을 쓴다 */
63
+ ariaLabel?: string;
59
64
  /** 총계(ChartTotal) + 범례(ChartLegend)를 담는 서브로우 */
60
65
  subRow?: ReactNode;
61
66
  /** 섹션 루트에 추가할 클래스 */
@@ -75,4 +80,4 @@ export interface ChartSectionProps {
75
80
  * 공유하도록 두 컴포넌트가 내부적으로 사용한다.
76
81
  * @public
77
82
  */
78
- export default function ChartSection({ title, titleClassName, icon, disc, headRight, headSegment, headMenuItems, collapseBelow, subRow, className, inGrid, children }: ChartSectionProps): import("react").JSX.Element;
83
+ export default function ChartSection({ title, titleClassName, icon, disc, headRight, headSegment, headMenuItems, collapseBelow, onClick, ariaLabel, subRow, className, inGrid, children }: ChartSectionProps): import("react").JSX.Element;
@@ -25,7 +25,7 @@ export function ChartTotal({ label, children }) {
25
25
  * 공유하도록 두 컴포넌트가 내부적으로 사용한다.
26
26
  * @public
27
27
  */
28
- export default function ChartSection({ title, titleClassName = 'h3', icon, disc, headRight, headSegment, headMenuItems, collapseBelow = 420, subRow, className, inGrid = false, children }) {
28
+ export default function ChartSection({ title, titleClassName = 'h3', icon, disc, headRight, headSegment, headMenuItems, collapseBelow = 420, onClick, ariaLabel, subRow, className, inGrid = false, children }) {
29
29
  const { t } = useTranslation();
30
30
  const secRef = useRef(null);
31
31
  /* 좁은지는 **카드 제 폭** 으로 잰다 — 부르는 쪽이 격자 칸 폭으로 대신 재면 두 칸을 차지하는 카드에서 틀린다.
@@ -66,7 +66,26 @@ export default function ChartSection({ title, titleClassName = 'h3', icon, disc,
66
66
  ...(headMenuItems ?? []).map((it, i) => (i === 0 ? { ...it, separatorBefore: true } : it)),
67
67
  ]
68
68
  : [];
69
+ /* 누르는 카드 — 머리의 단추·고르개를 눌렀을 때까지 카드가 열리면 안 된다(그 누름은 제 일을 한다) */
70
+ const 카드누름 = useCallback((e) => {
71
+ if (!onClick)
72
+ return;
73
+ const t = e.target;
74
+ if (t && typeof t.closest === 'function' && t.closest('button, a, input, select, textarea, [role="radiogroup"]'))
75
+ return;
76
+ onClick();
77
+ }, [onClick]);
78
+ const 카드키 = useCallback((e) => {
79
+ if (!onClick)
80
+ return;
81
+ if (e.target !== e.currentTarget)
82
+ return; // 안쪽 단추의 Enter·Space 는 그 단추 것
83
+ if (e.key === 'Enter' || e.key === ' ') {
84
+ e.preventDefault();
85
+ onClick();
86
+ }
87
+ }, [onClick]);
69
88
  const 오른쪽 = typeof headRight === 'function' ? headRight({ collapsed: 접힘 }) : headRight;
70
89
  const 머리오른쪽 = (오른쪽 || headSegment) ? (_jsxs("div", { className: "manager-section__head-right", children: [오른쪽, headSegment && (접힘 ? (_jsx(Button, { htmlType: "button", size: 32, type: "dot", icon: "ellipsis", ariaLabel: headSegment.ariaLabel ?? t('common.more', '더보기'), showTooltipInfo: headSegment.ariaLabel ?? t('common.more', '더보기'), "aria-haspopup": "menu", "aria-expanded": !!메뉴자리, onClick: 메뉴열기 })) : (_jsx(SegmentedControl, { size: 32, ariaLabel: headSegment.ariaLabel, options: headSegment.options.map(o => ({ key: o.key, label: o.label, disabled: o.disabled })), value: headSegment.value, onChange: headSegment.onChange })))] })) : null;
71
- return (_jsxs("section", { ref: secRef, className: ['manager-section', inGrid && 'manager-section--grid', className].filter(Boolean).join(' '), children: [_jsxs("div", { className: "manager-section__head", children: [_jsxs("div", { className: "manager-section__title-row", children: [icon && _jsx(Icon, { icon: icon, label: typeof title === 'string' ? title : undefined, className: "manager-section__icon" }), _jsx("div", { className: ['manager-section__title', titleClassName].filter(Boolean).join(' '), children: title })] }), 머리오른쪽, disc && _jsx("div", { className: "manager-section__disc body-3", children: disc })] }), subRow && _jsx("div", { className: "barchart-sub-row", children: subRow }), children, 메뉴자리 && (_jsx(Tooltip, { anchorRect: 메뉴자리, onClose: 메뉴닫기, ariaLabel: headSegment?.ariaLabel ?? t('tooltip.menu', '메뉴'), children: _jsx(MenuTooltip, { columns: [{ items: 메뉴항목 }], onClose: 메뉴닫기, size: "small" }) }))] }));
90
+ return (_jsxs("section", { ref: secRef, className: ['manager-section', inGrid && 'manager-section--grid', onClick && 'manager-section--clickable', className].filter(Boolean).join(' '), onClick: onClick ? 카드누름 : undefined, onKeyDown: onClick ? 카드키 : undefined, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, "aria-label": onClick ? (ariaLabel ?? (typeof title === 'string' ? title : undefined)) : undefined, children: [_jsxs("div", { className: "manager-section__head", children: [_jsxs("div", { className: "manager-section__title-row", children: [icon && _jsx(Icon, { icon: icon, label: typeof title === 'string' ? title : undefined, className: "manager-section__icon" }), _jsx("div", { className: ['manager-section__title', titleClassName].filter(Boolean).join(' '), children: title })] }), 머리오른쪽, disc && _jsx("div", { className: "manager-section__disc body-3", children: disc })] }), subRow && _jsx("div", { className: "barchart-sub-row", children: subRow }), children, 메뉴자리 && (_jsx(Tooltip, { anchorRect: 메뉴자리, onClose: 메뉴닫기, ariaLabel: headSegment?.ariaLabel ?? t('tooltip.menu', '메뉴'), children: _jsx(MenuTooltip, { columns: [{ items: 메뉴항목 }], onClose: 메뉴닫기, size: "small" }) }))] }));
72
91
  }
@@ -25,6 +25,9 @@ export interface PopupListProps<T extends {
25
25
  columns: PopupListColumn<T>[];
26
26
  /** Table grid template columns (예: "20% 10% 22% 26% 22%") */
27
27
  gridTemplateColumns?: string;
28
+ /** 좁은 화면(767px 이하)에서 쓸 칸 폭 — 창 안의 표도 같은 `Table` 이라 그대로 전한다.
29
+ * 문턱을 달리 하려면 CSS 에서 `--table-grid-cols-override` 를 준다(창은 body 로 나가므로 창의 `className` 으로 좁힌다). */
30
+ mobileGridTemplateColumns?: string;
28
31
  /** 검색 placeholder */
29
32
  searchPlaceholder?: string;
30
33
  /**
@@ -10,7 +10,7 @@ import { 칸순빈값뒤 } from '../../utils/textSort';
10
10
  import { cx } from '../../utils/cx';
11
11
  /** @public */
12
12
  export default function ListPopup(props) {
13
- const { title, items, columns, gridTemplateColumns, searchPlaceholder, searchFn, defaultSortKey, defaultSortAsc = true, selectedId, selectedIds, onSelect, onClose, pageSizeOptions = [10, 25, 50, 100], initialPageSize, emptyText, countLabel, topContent, className = '', } = props;
13
+ const { title, items, columns, gridTemplateColumns, mobileGridTemplateColumns, searchPlaceholder, searchFn, defaultSortKey, defaultSortAsc = true, selectedId, selectedIds, onSelect, onClose, pageSizeOptions = [10, 25, 50, 100], initialPageSize, emptyText, countLabel, topContent, className = '', } = props;
14
14
  const { t } = useTranslation();
15
15
  const resolvedSearchPlaceholder = searchPlaceholder ?? t('common.search', '검색');
16
16
  const resolvedEmptyText = emptyText ?? t('common.emptyList', '항목이 없습니다.');
@@ -98,7 +98,7 @@ export default function ListPopup(props) {
98
98
  sortDir: col.sortable !== false && sortKey === col.key ? (sortAsc ? 'asc' : 'desc') : null,
99
99
  })), [columns, sortKey, sortAsc, handleSort]);
100
100
  const pageSizeOpts = useMemo(() => pageSizeOptions.map(n => ({ value: String(n), label: t('common.pageSizeLabel', { n }) })), [pageSizeOptions, t]);
101
- return (_jsxs(Popup, { className: `popup-list ${className}`, title: title, onClose: onClose, children: [topContent, 'label' in countParts && _jsx("p", { className: "toolbar__count body-1", children: countParts.label }), _jsx(Toolbar, { count: 'label' in countParts ? undefined : { value: filtered.length, prefix: countParts.prefix, suffix: countParts.suffix }, search: searchEnabled ? { value: search, onChange: setSearch, placeholder: resolvedSearchPlaceholder } : undefined, pageSize: { options: pageSizeOpts, value: pageSize, onChange: setPageSize }, pagination: { page: 이쪽, total: totalPages, onChange: setPage } }), _jsx(Table, { size: "medium", gridTemplateColumns: gridTemplateColumns, resizable: true, fields: tableFields, items: paged, onRowClick: onSelect, renderRow: (it) => {
101
+ return (_jsxs(Popup, { className: `popup-list ${className}`, title: title, onClose: onClose, children: [topContent, 'label' in countParts && _jsx("p", { className: "toolbar__count body-1", children: countParts.label }), _jsx(Toolbar, { count: 'label' in countParts ? undefined : { value: filtered.length, prefix: countParts.prefix, suffix: countParts.suffix }, search: searchEnabled ? { value: search, onChange: setSearch, placeholder: resolvedSearchPlaceholder } : undefined, pageSize: { options: pageSizeOpts, value: pageSize, onChange: setPageSize }, pagination: { page: 이쪽, total: totalPages, onChange: setPage } }), _jsx(Table, { size: "medium", gridTemplateColumns: gridTemplateColumns, mobileGridTemplateColumns: mobileGridTemplateColumns, resizable: true, fields: tableFields, items: paged, onRowClick: onSelect, renderRow: (it) => {
102
102
  const isSelected = selectedIds != null
103
103
  ? (it.id != null && selectedIds.has(it.id))
104
104
  : (selectedId != null && it.id === selectedId);
@@ -60,6 +60,10 @@ export interface RingChartProps {
60
60
  className?: string;
61
61
  /** CSS 격자 칸 안에 세운다 — 아래 여백·최소 폭을 풀고 링을 카드 바닥에 맞춘다. ChartSection `inGrid` 참고(titleKey 지정 시에만 사용) */
62
62
  inGrid?: boolean;
63
+ /** 카드 자체를 누를 수 있게 — 커서·hover 테두리·키보드까지 ChartSection 이 한 결로 붙인다(titleKey 지정 시에만) */
64
+ onClick?: () => void;
65
+ /** 누르는 카드의 이름(낭독기) — 안 주면 제목 */
66
+ ariaLabel?: string;
63
67
  }
64
68
  /**
65
69
  * 도넛 링 차트 — 전체 대비 완료 비율을 원형 호로 표현.
@@ -67,4 +71,4 @@ export interface RingChartProps {
67
71
  * 미지정 시에는 헤더 없는 순수 링만 렌더된다(크기/색상 데모 등).
68
72
  * @public
69
73
  */
70
- export default function RingChart({ titleKey, headRight, icon, showTotal, totalLabelKey, legend, loading, className, inGrid, ...ringProps }: RingChartProps): import("react").JSX.Element;
74
+ export default function RingChart({ titleKey, headRight, icon, showTotal, totalLabelKey, legend, loading, className, inGrid, onClick, ariaLabel, ...ringProps }: RingChartProps): import("react").JSX.Element;
@@ -51,7 +51,7 @@ function RingChartCanvas({ done, total, segments, color = 'var(--color-main)', s
51
51
  * 미지정 시에는 헤더 없는 순수 링만 렌더된다(크기/색상 데모 등).
52
52
  * @public
53
53
  */
54
- export default function RingChart({ titleKey, headRight, icon, showTotal, totalLabelKey, legend, loading, className, inGrid = false, ...ringProps }) {
54
+ export default function RingChart({ titleKey, headRight, icon, showTotal, totalLabelKey, legend, loading, className, inGrid = false, onClick, ariaLabel, ...ringProps }) {
55
55
  const { t } = useTranslation();
56
56
  if (!titleKey)
57
57
  return _jsx(RingChartCanvas, { ...ringProps });
@@ -64,5 +64,5 @@ export default function RingChart({ titleKey, headRight, icon, showTotal, totalL
64
64
  .filter(Boolean).join(' ') || undefined;
65
65
  // StatChart(.manager-stat-card__icon)와 동일한 톤 — headRight 자리에 렌더(둘 중 하나만 사용)
66
66
  const iconNode = icon && (_jsx("span", { className: "chart-section-icon", children: _jsx(Icon, { icon: icon, className: "chart-section-icon-inner" }) }));
67
- return (_jsx(ChartSection, { className: sectionClassName, inGrid: inGrid, title: t(titleKey), titleClassName: isSmall ? 'h5 chart-section-title--small' : undefined, headRight: iconNode || (isSmall ? undefined : headRight), subRow: (showTotal || legend) && _jsxs(_Fragment, { children: [showTotal ? (_jsxs(ChartTotal, { label: !isSmall && totalLabelKey ? t(totalLabelKey) : undefined, children: [_jsx("span", { className: "barchart-total__num h0", children: pct }), _jsx("span", { className: "barchart-total__unit h5", children: "%" })] })) : _jsx("span", {}), legend && _jsx(ChartLegend, { items: legend })] }), children: loading ? (_jsx("div", { className: "manager-bar-chart-loading", children: _jsx(Loader, { size: 32 }) })) : (_jsx("div", { className: "ring-chart-section-body ring-chart-section-body--offset", children: _jsx(RingChartCanvas, { ...ringProps, hideCenter: ringProps.hideCenter ?? isSmall }) })) }));
67
+ return (_jsx(ChartSection, { className: sectionClassName, inGrid: inGrid, onClick: onClick, ariaLabel: ariaLabel, title: t(titleKey), titleClassName: isSmall ? 'h5 chart-section-title--small' : undefined, headRight: iconNode || (isSmall ? undefined : headRight), subRow: (showTotal || legend) && _jsxs(_Fragment, { children: [showTotal ? (_jsxs(ChartTotal, { label: !isSmall && totalLabelKey ? t(totalLabelKey) : undefined, children: [_jsx("span", { className: "barchart-total__num h0", children: pct }), _jsx("span", { className: "barchart-total__unit h5", children: "%" })] })) : _jsx("span", {}), legend && _jsx(ChartLegend, { items: legend })] }), children: loading ? (_jsx("div", { className: "manager-bar-chart-loading", children: _jsx(Loader, { size: 32 }) })) : (_jsx("div", { className: "ring-chart-section-body ring-chart-section-body--offset", children: _jsx(RingChartCanvas, { ...ringProps, hideCenter: ringProps.hideCenter ?? isSmall }) })) }));
68
68
  }
@@ -48,6 +48,16 @@
48
48
  flex: 1;
49
49
  justify-content: space-between;
50
50
  }
51
+ /* 값 아래 자리 — 목록·단추 등 카드가 값을 풀어 보이는 것 */
52
+ .manager-stat-card__body {
53
+ display: flex;
54
+ flex-direction: column;
55
+ align-items: stretch;
56
+ gap: 4px;
57
+ width: 100%;
58
+ text-align: left;
59
+ }
60
+
51
61
  .manager-stat-card__left {
52
62
  display: flex;
53
63
  flex-direction: row;
@@ -1,4 +1,5 @@
1
1
  import './StatChart.css';
2
+ import { type ReactNode } from 'react';
2
3
  /** @public */
3
4
  export type StatChartChangeType = 'up' | 'down' | 'neutral';
4
5
  /** @public */
@@ -16,6 +17,9 @@ export interface StatChartProps {
16
17
  /** 호버 시 표시할 툴팁 텍스트 */
17
18
  tooltip?: string;
18
19
  onClick?: () => void;
20
+ /** 값 **아래** 에 붙는 자리 — 목록 몇 줄, "외 n건" 단추처럼 값을 풀어 보이는 것.
21
+ * 이 자리가 없어 소비자가 카드 마크업(`manager-stat-card__*` 여덟 이름)을 통째로 베끼고 있었다(말귀 매니저 '금일 방문 예정'). */
22
+ children?: ReactNode;
19
23
  }
20
24
  /**
21
25
  * 순수 카운트 스탯 카드 — 제목+아이콘, 큰 숫자, 증감(선택) 만 보여준다.
@@ -23,4 +27,4 @@ export interface StatChartProps {
23
27
  * (도넛 breakdown은 RingChart segments 모드, 리스트는 페이지에서 직접 구성).
24
28
  * @public
25
29
  */
26
- export default function StatChart({ label, value, change, changeType, icon, tooltip, onClick }: StatChartProps): import("react").JSX.Element;
30
+ export default function StatChart({ label, value, change, changeType, icon, tooltip, onClick, children }: StatChartProps): import("react").JSX.Element;
@@ -11,7 +11,7 @@ import TooltipInfo from './Tooltip/InfoTooltip';
11
11
  * (도넛 breakdown은 RingChart segments 모드, 리스트는 페이지에서 직접 구성).
12
12
  * @public
13
13
  */
14
- export default function StatChart({ label, value, change, changeType, icon, tooltip, onClick }) {
14
+ export default function StatChart({ label, value, change, changeType, icon, tooltip, onClick, children }) {
15
15
  const cardRef = useRef(null);
16
16
  /* 앵커 상태는 공용 훅이 갖는다 — ManagerPage 의 VisitListCard 가 같은 것을 손으로
17
17
  한 벌 더 적고 있었다. 여는 조건(tooltip 이 있을 때만)만 여기 남긴다. */
@@ -37,5 +37,5 @@ export default function StatChart({ label, value, change, changeType, icon, tool
37
37
  bottom: anchorRect.bottom,
38
38
  width: anchorRect.width,
39
39
  height: anchorRect.height,
40
- }, text: tooltip })), _jsxs("div", { className: "manager-stat-card__label-row", children: [_jsx("span", { className: "manager-stat-card__label h5", children: label }), icon && (_jsx("span", { className: "manager-stat-card__icon", children: _jsx(Icon, { icon: icon, className: "manager-stat-card__icon-inner" }) }))] }), _jsx("div", { className: "manager-stat-card__content", children: _jsxs("div", { className: "manager-stat-card__left", children: [_jsx("div", { className: "manager-stat-card__value h2", children: value }), changeText && (_jsx("div", { className: `manager-stat-card__change manager-stat-card__change--${resolvedChangeType ?? 'neutral'} caption-1`, children: changeText }))] }) })] }));
40
+ }, text: tooltip })), _jsxs("div", { className: "manager-stat-card__label-row", children: [_jsx("span", { className: "manager-stat-card__label h5", children: label }), icon && (_jsx("span", { className: "manager-stat-card__icon", children: _jsx(Icon, { icon: icon, className: "manager-stat-card__icon-inner" }) }))] }), _jsxs("div", { className: "manager-stat-card__content", children: [_jsxs("div", { className: "manager-stat-card__left", children: [_jsx("div", { className: "manager-stat-card__value h2", children: value }), changeText && (_jsx("div", { className: `manager-stat-card__change manager-stat-card__change--${resolvedChangeType ?? 'neutral'} caption-1`, children: changeText }))] }), children && _jsx("div", { className: "manager-stat-card__body", children: children })] })] }));
41
41
  }
@@ -99,6 +99,10 @@ export interface BarChartProps {
99
99
  /** 머리의 보기 고르개 — 넓으면 세그먼트, 카드가 좁으면 '⋯' 한 단추로 접히고 그 메뉴에 칸들과 '상세보기' 가 함께 든다.
100
100
  * `headExtra` 로 고르개를 손수 얹고 좁을 때를 따로 다루던 것을 대신한다(ChartSection 이 카드 제 폭으로 잰다). */
101
101
  headSegment?: ChartHeadSegment;
102
+ /** 카드 자체를 누를 수 있게 — 커서·hover 테두리·키보드까지 ChartSection 이 한 결로 붙인다(머리의 단추·고르개 누름은 카드를 열지 않는다) */
103
+ onClick?: () => void;
104
+ /** 누르는 카드의 이름(낭독기) — 안 주면 제목 */
105
+ cardAriaLabel?: string;
102
106
  /** 제목 왼쪽 아이콘 — Section·ChartSection 과 같은 자리·같은 색 */
103
107
  icon?: string;
104
108
  /** 제목 아래 설명 한 줄 */
@@ -46,4 +46,4 @@
46
46
  *
47
47
  * 값은 손으로 적고 `test/coreVersion.test.ts` 가 package.json 과 어긋나면 운다.
48
48
  */
49
- export declare const CORE_VERSION = "0.167.0";
49
+ export declare const CORE_VERSION = "0.169.0";
@@ -46,4 +46,4 @@
46
46
  *
47
47
  * 값은 손으로 적고 `test/coreVersion.test.ts` 가 package.json 과 어긋나면 운다.
48
48
  */
49
- export const CORE_VERSION = '0.167.0';
49
+ export const CORE_VERSION = '0.169.0';