@ihabdevteam/core 0.15.0 → 0.16.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/dist/components.cjs.js +165 -165
- package/dist/components.esm.css +1 -1
- package/dist/ihabdevteam-core.cjs.js +167 -167
- package/dist/ihabdevteam-core.d.ts +27 -2
- package/dist/packages/core/src/components/ShortcutBadge.css +10 -4
- package/dist/packages/core/src/components/ShortcutBadge.d.ts +12 -1
- package/dist/packages/core/src/components/ShortcutBadge.js +2 -2
- package/dist/packages/core/src/components/SoundCompass.css +2 -3
- package/dist/packages/core/src/components/SoundCompass.d.ts +16 -1
- package/dist/packages/core/src/components/SoundCompass.js +18 -8
- package/package.json +1 -1
|
@@ -4952,7 +4952,7 @@ export declare const SHORT_STORIES: unknown[];
|
|
|
4952
4952
|
* <ShortcutBadge keys={['Ctrl', 'S']} anchor="static" />
|
|
4953
4953
|
* @public
|
|
4954
4954
|
*/
|
|
4955
|
-
export declare function ShortcutBadge({ keys, anchor, className, }: ShortcutBadgeProps): JSX.Element;
|
|
4955
|
+
export declare function ShortcutBadge({ keys, anchor, scale, className, }: ShortcutBadgeProps): JSX.Element;
|
|
4956
4956
|
|
|
4957
4957
|
/** 부모 코너 배치. static 은 흐름 배치. @public */
|
|
4958
4958
|
export declare type ShortcutBadgeAnchor = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'static';
|
|
@@ -4966,6 +4966,17 @@ export declare interface ShortcutBadgeProps {
|
|
|
4966
4966
|
* 코너에서 살짝 안쪽으로 들어오게 얹힌다. static 이면 흐름 안에 배치.
|
|
4967
4967
|
*/
|
|
4968
4968
|
anchor?: ShortcutBadgeAnchor;
|
|
4969
|
+
/**
|
|
4970
|
+
* 배지 크기 배율. 1 이 기본(키캡 한 변 24px).
|
|
4971
|
+
*
|
|
4972
|
+
* 배지는 고정 크기라, 큰 버튼 위에 얹으면 잃어버리고 작은 버튼 위에서는 덮는다.
|
|
4973
|
+
* 그럴 때 부르는 쪽이 정한다.
|
|
4974
|
+
*
|
|
4975
|
+
* **`transform` 으로 키우지 말 것** — 배지가 모서리에 걸치는 `translate` 와 같은
|
|
4976
|
+
* 속성이라 한쪽이 다른 쪽을 통째로 지운다. 이 prop 은 `--shortcut-badge-scale` 로
|
|
4977
|
+
* 내려가고, 자리와 배율은 CSS 한 곳에서 합쳐 적힌다.
|
|
4978
|
+
*/
|
|
4979
|
+
scale?: number;
|
|
4969
4980
|
className?: string;
|
|
4970
4981
|
}
|
|
4971
4982
|
|
|
@@ -5108,7 +5119,7 @@ export declare interface SliderProps {
|
|
|
5108
5119
|
export declare function sortToValue(key: string, asc: boolean): string | undefined;
|
|
5109
5120
|
|
|
5110
5121
|
/** @public */
|
|
5111
|
-
export declare function SoundCompass({ speakers, size, viewT, activeSpeakerId, playedIds, selectedId, answerId, showFeedback, clickable, onSelectSpeaker, buttonSize, showIcon, }: SoundCompassProps): JSX.Element;
|
|
5122
|
+
export declare function SoundCompass({ speakers, size, viewT, activeSpeakerId, playedIds, selectedId, answerId, showFeedback, clickable, onSelectSpeaker, buttonSize, showIcon, shortcutAnchor, shortcutScale, }: SoundCompassProps): JSX.Element;
|
|
5112
5123
|
|
|
5113
5124
|
export declare interface SoundCompassExam {
|
|
5114
5125
|
/** `<SoundCompass {...bind} />` 로 펼쳐 넣는 제어 props */
|
|
@@ -5183,6 +5194,20 @@ export declare interface SoundCompassProps {
|
|
|
5183
5194
|
buttonSize?: number;
|
|
5184
5195
|
/** 스피커 버튼에 아이콘을 표시할지 여부. false면 숫자만 가운데 표시. 기본 true */
|
|
5185
5196
|
showIcon?: boolean;
|
|
5197
|
+
/**
|
|
5198
|
+
* `speakers[].shortcut` 배지가 버튼의 어느 모서리에 붙을지. 기본 우상단.
|
|
5199
|
+
*
|
|
5200
|
+
* 배지 전부에 같이 걸린다 — 스피커마다 다른 자리에 두면 눈이 규칙을 못 잡는다.
|
|
5201
|
+
*/
|
|
5202
|
+
shortcutAnchor?: ShortcutBadgeAnchor;
|
|
5203
|
+
/**
|
|
5204
|
+
* 배지 크기 배율. 안 주면 버튼 크기에서 스스로 정한다
|
|
5205
|
+
* (`clamp(0.75, buttonSize / 56, 3)` — 묶이지 않는 동안 버튼 대비 0.43 으로 일정).
|
|
5206
|
+
*
|
|
5207
|
+
* 스스로 정하는 값이 안 맞는 자리가 있다. 상한에 붙으면 더 큰 버튼에서 배지가
|
|
5208
|
+
* 작아지고, 상한을 올려도 다음 소비자가 또 그 끝에서 막힌다. 그럴 때 직접 준다.
|
|
5209
|
+
*/
|
|
5210
|
+
shortcutScale?: number;
|
|
5186
5211
|
}
|
|
5187
5212
|
|
|
5188
5213
|
/**
|
|
@@ -9,29 +9,35 @@
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/* 코너 배치 — 중심이 부모 코너에서 살짝 안쪽(25%)으로 들어오게 얹힌다. */
|
|
12
|
+
/* 배지를 키우려면 `--shortcut-badge-scale` 을 부모에 얹는다.
|
|
13
|
+
**transform 을 따로 걸면 안 된다** — 자리를 잡는 translate 와 같은 속성이라
|
|
14
|
+
뒤에 오는 쪽이 앞의 것을 통째로 지운다. 실제로 그 사고가 났다: SoundCompass 가
|
|
15
|
+
배지에 scale 을 따로 걸었더니 anchor 의 translate 가 사라져 배지가 모서리에
|
|
16
|
+
걸치지 않고 버튼 안으로 들어왔다(실측: 걸침 +6px → -3px). 그래서 배율을
|
|
17
|
+
변수로 받아 **여기 한 곳에서** 합쳐 적는다. */
|
|
12
18
|
.shortcut-badge--top-left {
|
|
13
19
|
position: absolute;
|
|
14
20
|
left: 0;
|
|
15
21
|
top: 0;
|
|
16
|
-
transform: translate(-25%, -25%);
|
|
22
|
+
transform: translate(-25%, -25%) scale(var(--shortcut-badge-scale, 1));
|
|
17
23
|
}
|
|
18
24
|
.shortcut-badge--top-right {
|
|
19
25
|
position: absolute;
|
|
20
26
|
right: 0;
|
|
21
27
|
top: 0;
|
|
22
|
-
transform: translate(25%, -25%);
|
|
28
|
+
transform: translate(25%, -25%) scale(var(--shortcut-badge-scale, 1));
|
|
23
29
|
}
|
|
24
30
|
.shortcut-badge--bottom-left {
|
|
25
31
|
position: absolute;
|
|
26
32
|
left: 0;
|
|
27
33
|
bottom: 0;
|
|
28
|
-
transform: translate(-25%, 25%);
|
|
34
|
+
transform: translate(-25%, 25%) scale(var(--shortcut-badge-scale, 1));
|
|
29
35
|
}
|
|
30
36
|
.shortcut-badge--bottom-right {
|
|
31
37
|
position: absolute;
|
|
32
38
|
right: 0;
|
|
33
39
|
bottom: 0;
|
|
34
|
-
transform: translate(25%, 25%);
|
|
40
|
+
transform: translate(25%, 25%) scale(var(--shortcut-badge-scale, 1));
|
|
35
41
|
}
|
|
36
42
|
/* static — 흐름 안에 배치(별도 규칙 없음, position: static 기본). */
|
|
37
43
|
|
|
@@ -10,6 +10,17 @@ export interface ShortcutBadgeProps {
|
|
|
10
10
|
* 코너에서 살짝 안쪽으로 들어오게 얹힌다. static 이면 흐름 안에 배치.
|
|
11
11
|
*/
|
|
12
12
|
anchor?: ShortcutBadgeAnchor;
|
|
13
|
+
/**
|
|
14
|
+
* 배지 크기 배율. 1 이 기본(키캡 한 변 24px).
|
|
15
|
+
*
|
|
16
|
+
* 배지는 고정 크기라, 큰 버튼 위에 얹으면 잃어버리고 작은 버튼 위에서는 덮는다.
|
|
17
|
+
* 그럴 때 부르는 쪽이 정한다.
|
|
18
|
+
*
|
|
19
|
+
* **`transform` 으로 키우지 말 것** — 배지가 모서리에 걸치는 `translate` 와 같은
|
|
20
|
+
* 속성이라 한쪽이 다른 쪽을 통째로 지운다. 이 prop 은 `--shortcut-badge-scale` 로
|
|
21
|
+
* 내려가고, 자리와 배율은 CSS 한 곳에서 합쳐 적힌다.
|
|
22
|
+
*/
|
|
23
|
+
scale?: number;
|
|
13
24
|
className?: string;
|
|
14
25
|
}
|
|
15
26
|
/**
|
|
@@ -28,4 +39,4 @@ export interface ShortcutBadgeProps {
|
|
|
28
39
|
* <ShortcutBadge keys={['Ctrl', 'S']} anchor="static" />
|
|
29
40
|
* @public
|
|
30
41
|
*/
|
|
31
|
-
export default function ShortcutBadge({ keys, anchor, className, }: ShortcutBadgeProps): import("react").JSX.Element;
|
|
42
|
+
export default function ShortcutBadge({ keys, anchor, scale, className, }: ShortcutBadgeProps): import("react").JSX.Element;
|
|
@@ -17,7 +17,7 @@ import './ShortcutBadge.css';
|
|
|
17
17
|
* <ShortcutBadge keys={['Ctrl', 'S']} anchor="static" />
|
|
18
18
|
* @public
|
|
19
19
|
*/
|
|
20
|
-
export default function ShortcutBadge({ keys, anchor = 'top-right', className = '', }) {
|
|
20
|
+
export default function ShortcutBadge({ keys, anchor = 'top-right', scale, className = '', }) {
|
|
21
21
|
const list = Array.isArray(keys) ? keys : [keys];
|
|
22
|
-
return (_jsx("span", { className: cx('shortcut-badge', `shortcut-badge--${anchor}`, className), children: list.map((key, index) => (_jsxs("span", { className: "shortcut-badge__group", children: [index > 0 && _jsx("span", { className: "shortcut-badge__plus", children: "+" }), _jsx("kbd", { className: "shortcut-badge__key", children: key })] }, `${key}-${index}`))) }));
|
|
22
|
+
return (_jsx("span", { className: cx('shortcut-badge', `shortcut-badge--${anchor}`, className), style: scale === undefined ? undefined : { ['--shortcut-badge-scale']: String(scale) }, children: list.map((key, index) => (_jsxs("span", { className: "shortcut-badge__group", children: [index > 0 && _jsx("span", { className: "shortcut-badge__plus", children: "+" }), _jsx("kbd", { className: "shortcut-badge__key", children: key })] }, `${key}-${index}`))) }));
|
|
23
23
|
}
|
|
@@ -162,9 +162,8 @@
|
|
|
162
162
|
.sound-compass__speaker-shortcut {
|
|
163
163
|
pointer-events: none;
|
|
164
164
|
z-index: 2;
|
|
165
|
-
/*
|
|
166
|
-
|
|
167
|
-
transform-origin: center;
|
|
165
|
+
/* 배율은 `--shortcut-badge-scale` 로 넘긴다. 여기서 transform 을 걸면 배지가
|
|
166
|
+
자리를 잡는 translate 를 지운다 — 같은 속성이라 뒤에 오는 쪽이 이긴다. */
|
|
168
167
|
}
|
|
169
168
|
|
|
170
169
|
.sound-compass__speaker-pos {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ShortcutBadgeAnchor } from './ShortcutBadge';
|
|
1
2
|
import type { SpeakerPos } from '../types/audio';
|
|
2
3
|
import './SoundCompass.css';
|
|
3
4
|
/** @public */
|
|
@@ -37,6 +38,20 @@ export interface SoundCompassProps {
|
|
|
37
38
|
buttonSize?: number;
|
|
38
39
|
/** 스피커 버튼에 아이콘을 표시할지 여부. false면 숫자만 가운데 표시. 기본 true */
|
|
39
40
|
showIcon?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* `speakers[].shortcut` 배지가 버튼의 어느 모서리에 붙을지. 기본 우상단.
|
|
43
|
+
*
|
|
44
|
+
* 배지 전부에 같이 걸린다 — 스피커마다 다른 자리에 두면 눈이 규칙을 못 잡는다.
|
|
45
|
+
*/
|
|
46
|
+
shortcutAnchor?: ShortcutBadgeAnchor;
|
|
47
|
+
/**
|
|
48
|
+
* 배지 크기 배율. 안 주면 버튼 크기에서 스스로 정한다
|
|
49
|
+
* (`clamp(0.75, buttonSize / 56, 3)` — 묶이지 않는 동안 버튼 대비 0.43 으로 일정).
|
|
50
|
+
*
|
|
51
|
+
* 스스로 정하는 값이 안 맞는 자리가 있다. 상한에 붙으면 더 큰 버튼에서 배지가
|
|
52
|
+
* 작아지고, 상한을 올려도 다음 소비자가 또 그 끝에서 막힌다. 그럴 때 직접 준다.
|
|
53
|
+
*/
|
|
54
|
+
shortcutScale?: number;
|
|
40
55
|
}
|
|
41
56
|
/** @public */
|
|
42
|
-
export default function SoundCompass({ speakers, size, viewT, activeSpeakerId, playedIds, selectedId, answerId, showFeedback, clickable, onSelectSpeaker, buttonSize, showIcon, }: SoundCompassProps): import("react").JSX.Element;
|
|
57
|
+
export default function SoundCompass({ speakers, size, viewT, activeSpeakerId, playedIds, selectedId, answerId, showFeedback, clickable, onSelectSpeaker, buttonSize, showIcon, shortcutAnchor, shortcutScale, }: SoundCompassProps): import("react").JSX.Element;
|
|
@@ -14,7 +14,7 @@ import ShortcutBadge from './ShortcutBadge';
|
|
|
14
14
|
import './SoundCompass.css';
|
|
15
15
|
const lerp = (a, b, t) => a + (b - a) * t;
|
|
16
16
|
/** @public */
|
|
17
|
-
export default function SoundCompass({ speakers, size = 300, viewT = 0, activeSpeakerId = null, playedIds, selectedId = null, answerId = null, showFeedback = false, clickable = false, onSelectSpeaker, buttonSize = 40, showIcon = true, }) {
|
|
17
|
+
export default function SoundCompass({ speakers, size = 300, viewT = 0, activeSpeakerId = null, playedIds, selectedId = null, answerId = null, showFeedback = false, clickable = false, onSelectSpeaker, buttonSize = 40, showIcon = true, shortcutAnchor = 'top-right', shortcutScale, }) {
|
|
18
18
|
const t = Math.max(0, Math.min(1, viewT));
|
|
19
19
|
const CENTER = size / 2;
|
|
20
20
|
// ── 탑뷰 좌표 ──────────────────────────────────────────────────────────
|
|
@@ -152,12 +152,22 @@ export default function SoundCompass({ speakers, size = 300, viewT = 0, activeSp
|
|
|
152
152
|
const state = getSpeakerState(sp);
|
|
153
153
|
const pulse = shouldPulse(sp);
|
|
154
154
|
const baseStyle = {
|
|
155
|
-
// 배지는 24px 고정인데 버튼은
|
|
156
|
-
//
|
|
157
|
-
//
|
|
158
|
-
// 0.
|
|
159
|
-
//
|
|
160
|
-
|
|
155
|
+
// 배지는 24px 고정인데 버튼은 크게 오간다. 그대로 두면 버튼 대비 비율이
|
|
156
|
+
// 세 배씩 흔들려, 작은 버튼에서는 배지가 버튼을 덮고 큰 버튼에서는
|
|
157
|
+
// 잃어버린다(실측). 버튼과 함께 키운다 — 24/56 이라 묶이지 않는 구간에서는
|
|
158
|
+
// 비율이 0.43 으로 **일정하다**.
|
|
159
|
+
//
|
|
160
|
+
// 상한은 3 이다. 처음엔 1.6 이었는데 buttonSize 89.6px 부터 붙어버려,
|
|
161
|
+
// 104~168px 을 쓰는 소비 앱에서 배지가 0.37 → 0.23 으로 다시 작아졌다.
|
|
162
|
+
// 3 이면 168px 까지 묶이지 않는다. 하한 0.75 는 배지가 읽히는 크기다.
|
|
163
|
+
//
|
|
164
|
+
// 그래도 이 식이 안 맞는 자리는 남는다 — 상한을 올려도 다음 소비자가 또
|
|
165
|
+
// 그 끝에서 막힌다. 그래서 `shortcutScale` 로 직접 줄 수 있게 열어 두고,
|
|
166
|
+
// 안 주면 이 식이 그대로 쓰인다.
|
|
167
|
+
//
|
|
168
|
+
// 배율은 transform 이 아니라 변수로 넘긴다 — 배지의 anchor 가 같은 속성에
|
|
169
|
+
// translate 를 걸고 있어, 여기서 transform 을 걸면 그것을 지운다.
|
|
170
|
+
['--shortcut-badge-scale']: String(shortcutScale ?? Math.max(0.75, Math.min(3, buttonSize / 56))),
|
|
161
171
|
pointerEvents: (clickable ? 'auto' : 'none'),
|
|
162
172
|
cursor: clickable ? 'pointer' : 'default',
|
|
163
173
|
// 호출된(=idle이 아닌) 스피커를 다른 스피커 위로 끌어올렸다가, 초기화되면 다시 낮춘다
|
|
@@ -169,6 +179,6 @@ export default function SoundCompass({ speakers, size = 300, viewT = 0, activeSp
|
|
|
169
179
|
const iconSize = Math.round(Math.max(10, Math.min(56, BTN * 0.38)));
|
|
170
180
|
const numberSize = Math.round(Math.max(7, Math.min(18, BTN * 0.2)));
|
|
171
181
|
const numberOnlySize = Math.round(Math.max(10, Math.min(56, BTN * 0.4)));
|
|
172
|
-
return (_jsxs("div", { className: "sound-compass__speaker-pos", style: { ...baseStyle, left: x - BTN / 2, top: y - BTN / 2 }, children: [pulse && _jsx("div", { className: "sound-compass__pulse", style: { width: BTN, height: BTN } }), _jsxs("button", { type: "button", tabIndex: clickable ? 0 : -1, "aria-disabled": clickable ? undefined : true, onClick: clickable ? () => onSelectSpeaker?.(sp.id) : undefined, className: `sound-compass__speaker-btn sound-compass__speaker-btn--${state}`, style: { width: BTN, height: BTN }, "aria-label": sp.label, children: [showIcon && getStateIcon(state, iconSize), _jsx("span", { className: "sound-compass__speaker-number", style: { fontSize: showIcon ? numberSize : numberOnlySize }, children: idx + 1 })] }), sp.shortcut && (_jsx(ShortcutBadge, { keys: sp.shortcut, anchor:
|
|
182
|
+
return (_jsxs("div", { className: "sound-compass__speaker-pos", style: { ...baseStyle, left: x - BTN / 2, top: y - BTN / 2 }, children: [pulse && _jsx("div", { className: "sound-compass__pulse", style: { width: BTN, height: BTN } }), _jsxs("button", { type: "button", tabIndex: clickable ? 0 : -1, "aria-disabled": clickable ? undefined : true, onClick: clickable ? () => onSelectSpeaker?.(sp.id) : undefined, className: `sound-compass__speaker-btn sound-compass__speaker-btn--${state}`, style: { width: BTN, height: BTN }, "aria-label": sp.label, children: [showIcon && getStateIcon(state, iconSize), _jsx("span", { className: "sound-compass__speaker-number", style: { fontSize: showIcon ? numberSize : numberOnlySize }, children: idx + 1 })] }), sp.shortcut && (_jsx(ShortcutBadge, { keys: sp.shortcut, anchor: shortcutAnchor, className: "sound-compass__speaker-shortcut" }))] }, sp.id));
|
|
173
183
|
})] }) }));
|
|
174
184
|
}
|