@ihabdevteam/core 0.18.0 → 0.20.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 +164 -164
- package/dist/components.esm.css +1 -1
- package/dist/ihabdevteam-core.cjs.js +17 -17
- package/dist/ihabdevteam-core.d.ts +24 -1
- package/dist/packages/core/src/components/SoundCompass.css +39 -19
- package/dist/packages/core/src/components/SoundCompass.d.ts +24 -1
- package/dist/packages/core/src/components/SoundCompass.js +12 -2
- package/package.json +1 -1
|
@@ -5119,7 +5119,7 @@ export declare interface SliderProps {
|
|
|
5119
5119
|
export declare function sortToValue(key: string, asc: boolean): string | undefined;
|
|
5120
5120
|
|
|
5121
5121
|
/** @public */
|
|
5122
|
-
export declare function SoundCompass({ speakers, size, viewT, activeSpeakerId, playedIds, selectedId, answerId, showFeedback, pulseSelected, clickable, onSelectSpeaker, buttonSize, showIcon, shortcutAnchor, shortcutScale, scaleShortcut, }: SoundCompassProps): JSX.Element;
|
|
5122
|
+
export declare function SoundCompass({ speakers, size, viewT, activeSpeakerId, playedIds, selectedId, answerId, showFeedback, pulseSelected, pulseSelectedDuration, pulseScale, clickable, onSelectSpeaker, buttonSize, showIcon, shortcutAnchor, shortcutScale, scaleShortcut, }: SoundCompassProps): JSX.Element;
|
|
5123
5123
|
|
|
5124
5124
|
export declare interface SoundCompassExam {
|
|
5125
5125
|
/** `<SoundCompass {...bind} />` 로 펼쳐 넣는 제어 props */
|
|
@@ -5200,6 +5200,29 @@ export declare interface SoundCompassProps {
|
|
|
5200
5200
|
* 일어난 순간을 알리는 것이라 되풀이할 까닭이 없다.
|
|
5201
5201
|
*/
|
|
5202
5202
|
pulseSelected?: boolean;
|
|
5203
|
+
/**
|
|
5204
|
+
* 고른 자리 울림이 번지는 시간(ms). 기본 1000.
|
|
5205
|
+
*
|
|
5206
|
+
* 고른 상태를 짧게만 잡아 두는 검사에서는 울림이 중간에 끊긴다 — 소비 앱 실측:
|
|
5207
|
+
* 선택을 350ms 만 잡아 두니 울림이 35% 지점(퍼짐 1.6배)에서 통째로 사라져,
|
|
5208
|
+
* 가장 잘 보이는 확산 구간이 잘려 나갔다. 상태를 오래 잡아 두는 대신 울림을
|
|
5209
|
+
* 그 시간에 맞추는 편이 검사를 늘리지 않는다.
|
|
5210
|
+
*
|
|
5211
|
+
* 소리가 나는 동안의 울림(`activeSpeakerId`)은 1s 고정이다 — 그쪽은 이어지는
|
|
5212
|
+
* 상태를 알리는 것이라 짧을 까닭이 없다. 필요해지면 그때 연다.
|
|
5213
|
+
*/
|
|
5214
|
+
pulseSelectedDuration?: number;
|
|
5215
|
+
/**
|
|
5216
|
+
* 울림이 퍼지는 최대 배율. 기본 2.8.
|
|
5217
|
+
*
|
|
5218
|
+
* 얼마나 멀리 퍼져야 알맞은지는 **스피커 사이 거리**에 달렸다. 촘촘한 배치에서는
|
|
5219
|
+
* 2.8 배가 이웃 버튼 앞까지 밀고 들어온다 — 소비 앱 실측: 버튼 지름 90px 이면
|
|
5220
|
+
* 울림 지름이 252px 인데 이웃과의 중심 거리가 261px 이었다.
|
|
5221
|
+
*
|
|
5222
|
+
* 되풀이하는 울림과 한 번짜리 울림에 함께 걸린다. 둘의 퍼짐이 달라야 할 까닭이
|
|
5223
|
+
* 아직 없다 — 필요해지면 그때 가른다.
|
|
5224
|
+
*/
|
|
5225
|
+
pulseScale?: number;
|
|
5203
5226
|
/** 스피커 클릭 가능 여부. 기본 false */
|
|
5204
5227
|
clickable?: boolean;
|
|
5205
5228
|
/** 스피커 선택 시 호출 */
|
|
@@ -8,6 +8,27 @@
|
|
|
8
8
|
flex-direction: column;
|
|
9
9
|
align-items: center;
|
|
10
10
|
width: 100%;
|
|
11
|
+
|
|
12
|
+
/* 상태 색은 **뿌리에** 둔다. 예전에는 버튼 안에 선언돼 있었는데, 울림(pulse)은
|
|
13
|
+
버튼의 형제라 그 변수를 못 봤다 — 울림 색을 상태에 묶자마자 투명하게 나왔다
|
|
14
|
+
(실측: rgba(0,0,0,0)). 버튼과 울림이 함께 보려면 공통 조상에 있어야 한다. */
|
|
15
|
+
--scb-idle-bg: var(--color-deepWhite);
|
|
16
|
+
--scb-idle-border: var(--color-whiteLine);
|
|
17
|
+
--scb-idle-fg: var(--color-lightGray);
|
|
18
|
+
--scb-active-bg: var(--color-main);
|
|
19
|
+
--scb-active-border: var(--color-main);
|
|
20
|
+
--scb-active-fg: #ffffff;
|
|
21
|
+
--scb-played-bg: var(--color-sub);
|
|
22
|
+
--scb-played-border: var(--color-sub);
|
|
23
|
+
--scb-played-fg: #ffffff;
|
|
24
|
+
--scb-wrong-bg: #ef4444;
|
|
25
|
+
--scb-wrong-border: #ef4444;
|
|
26
|
+
--scb-wrong-fg: #ffffff;
|
|
27
|
+
/* 호버·포커스도 상태 색과 같은 방식으로 연다 — 소비자가 바꿔 끼울 수 있게. */
|
|
28
|
+
--scb-idle-hover-bg: var(--color-whiteLine);
|
|
29
|
+
--scb-idle-hover-border: var(--color-lightGray);
|
|
30
|
+
/* 호버의 글자색. 기본은 idle 과 같다 — 주지 않으면 예전 그대로다. */
|
|
31
|
+
--scb-idle-hover-fg: var(--scb-idle-fg);
|
|
11
32
|
}
|
|
12
33
|
|
|
13
34
|
.sound-compass__status {
|
|
@@ -43,23 +64,6 @@
|
|
|
43
64
|
border-style: solid;
|
|
44
65
|
transition: background-color .15s, border-color .15s, color .15s;
|
|
45
66
|
|
|
46
|
-
--scb-idle-bg: var(--color-deepWhite);
|
|
47
|
-
--scb-idle-border: var(--color-whiteLine);
|
|
48
|
-
--scb-idle-fg: var(--color-lightGray);
|
|
49
|
-
--scb-active-bg: var(--color-main);
|
|
50
|
-
--scb-active-border: var(--color-main);
|
|
51
|
-
--scb-active-fg: #ffffff;
|
|
52
|
-
--scb-played-bg: var(--color-sub);
|
|
53
|
-
--scb-played-border: var(--color-sub);
|
|
54
|
-
--scb-played-fg: #ffffff;
|
|
55
|
-
--scb-wrong-bg: #ef4444;
|
|
56
|
-
--scb-wrong-border: #ef4444;
|
|
57
|
-
--scb-wrong-fg: #ffffff;
|
|
58
|
-
/* 호버·포커스도 상태 색과 같은 방식으로 연다 — 소비자가 바꿔 끼울 수 있게. */
|
|
59
|
-
--scb-idle-hover-bg: var(--color-whiteLine);
|
|
60
|
-
--scb-idle-hover-border: var(--color-lightGray);
|
|
61
|
-
/* 호버의 글자색. 기본은 idle 과 같다 — 주지 않으면 예전 그대로다. */
|
|
62
|
-
--scb-idle-hover-fg: var(--scb-idle-fg);
|
|
63
67
|
--scb-focus-ring: var(--color-main);
|
|
64
68
|
}
|
|
65
69
|
|
|
@@ -124,7 +128,10 @@
|
|
|
124
128
|
@keyframes sound-compass-pulse {
|
|
125
129
|
0% { transform: scale(0.95); opacity: 0; }
|
|
126
130
|
8% { transform: scale(1.05); opacity: 0.45; }
|
|
127
|
-
|
|
131
|
+
/* 얼마나 멀리 퍼질지는 스피커 사이 거리에 달렸다 — 2.8 배는 촘촘한 배치에서
|
|
132
|
+
이웃 버튼 앞까지 밀고 들어간다(소비 앱 실측: 버튼 90px 이면 울림 지름 252px,
|
|
133
|
+
이웃과의 중심 거리 261px). keyframe 안의 var() 는 정적 값이라 잘 돈다. */
|
|
134
|
+
100% { transform: scale(var(--sc-pulse-scale, 2.8)); opacity: 0; }
|
|
128
135
|
}
|
|
129
136
|
|
|
130
137
|
.sound-compass__pulse {
|
|
@@ -132,14 +139,27 @@
|
|
|
132
139
|
top: 0; left: 0;
|
|
133
140
|
width: 40px; height: 40px;
|
|
134
141
|
border-radius: 50%;
|
|
135
|
-
|
|
142
|
+
/* 색은 **그 순간 버튼 색**을 따른다. 아래 상태별 규칙이 정하고, 여기 것은
|
|
143
|
+
상태를 못 붙였을 때의 바닥값이다. `--sc-pulse-color` 로 덮을 수 있다. */
|
|
144
|
+
background: var(--sc-pulse-color, var(--scb-active-bg));
|
|
136
145
|
pointer-events: none;
|
|
137
146
|
animation: sound-compass-pulse 1s cubic-bezier(0.33, 1, 0.68, 1) infinite;
|
|
138
147
|
}
|
|
139
148
|
/* 고른 순간을 알리는 울림은 한 번만 번진다. 마지막 프레임이 opacity 0 이라
|
|
140
149
|
되풀이를 끊는 것만으로 그대로 사라진다. */
|
|
150
|
+
/* 울림 색이 버튼 색과 갈리면 청록 버튼에서 파란 울림이 번진다(소비 앱 실측:
|
|
151
|
+
고른 직후 버튼은 --scb-played-bg 인데 울림은 --color-main 이었다). 상태를 그대로
|
|
152
|
+
따라가게 두면 `--scb-*` 를 바꿔 끼운 소비자도 저절로 맞는다. */
|
|
153
|
+
.sound-compass__pulse--idle { background: var(--sc-pulse-color, var(--scb-idle-bg)); }
|
|
154
|
+
.sound-compass__pulse--active { background: var(--sc-pulse-color, var(--scb-active-bg)); }
|
|
155
|
+
.sound-compass__pulse--played,
|
|
156
|
+
.sound-compass__pulse--correct { background: var(--sc-pulse-color, var(--scb-played-bg)); }
|
|
157
|
+
.sound-compass__pulse--wrong { background: var(--sc-pulse-color, var(--scb-wrong-bg)); }
|
|
158
|
+
|
|
141
159
|
.sound-compass__pulse--once {
|
|
142
160
|
animation-iteration-count: 1;
|
|
161
|
+
/* 고른 상태를 짧게만 잡아 두는 검사에서는 이 시간을 줄여야 울림이 안 끊긴다. */
|
|
162
|
+
animation-duration: var(--sc-pulse-duration-once, 1s);
|
|
143
163
|
}
|
|
144
164
|
|
|
145
165
|
/* 스피커 버튼 wrap의 정적 속성만 분리(나머지는 상태·좌표 기반 동적 값이라 인라인 유지) */
|
|
@@ -44,6 +44,29 @@ export interface SoundCompassProps {
|
|
|
44
44
|
* 일어난 순간을 알리는 것이라 되풀이할 까닭이 없다.
|
|
45
45
|
*/
|
|
46
46
|
pulseSelected?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* 고른 자리 울림이 번지는 시간(ms). 기본 1000.
|
|
49
|
+
*
|
|
50
|
+
* 고른 상태를 짧게만 잡아 두는 검사에서는 울림이 중간에 끊긴다 — 소비 앱 실측:
|
|
51
|
+
* 선택을 350ms 만 잡아 두니 울림이 35% 지점(퍼짐 1.6배)에서 통째로 사라져,
|
|
52
|
+
* 가장 잘 보이는 확산 구간이 잘려 나갔다. 상태를 오래 잡아 두는 대신 울림을
|
|
53
|
+
* 그 시간에 맞추는 편이 검사를 늘리지 않는다.
|
|
54
|
+
*
|
|
55
|
+
* 소리가 나는 동안의 울림(`activeSpeakerId`)은 1s 고정이다 — 그쪽은 이어지는
|
|
56
|
+
* 상태를 알리는 것이라 짧을 까닭이 없다. 필요해지면 그때 연다.
|
|
57
|
+
*/
|
|
58
|
+
pulseSelectedDuration?: number;
|
|
59
|
+
/**
|
|
60
|
+
* 울림이 퍼지는 최대 배율. 기본 2.8.
|
|
61
|
+
*
|
|
62
|
+
* 얼마나 멀리 퍼져야 알맞은지는 **스피커 사이 거리**에 달렸다. 촘촘한 배치에서는
|
|
63
|
+
* 2.8 배가 이웃 버튼 앞까지 밀고 들어온다 — 소비 앱 실측: 버튼 지름 90px 이면
|
|
64
|
+
* 울림 지름이 252px 인데 이웃과의 중심 거리가 261px 이었다.
|
|
65
|
+
*
|
|
66
|
+
* 되풀이하는 울림과 한 번짜리 울림에 함께 걸린다. 둘의 퍼짐이 달라야 할 까닭이
|
|
67
|
+
* 아직 없다 — 필요해지면 그때 가른다.
|
|
68
|
+
*/
|
|
69
|
+
pulseScale?: number;
|
|
47
70
|
/** 스피커 클릭 가능 여부. 기본 false */
|
|
48
71
|
clickable?: boolean;
|
|
49
72
|
/** 스피커 선택 시 호출 */
|
|
@@ -79,4 +102,4 @@ export interface SoundCompassProps {
|
|
|
79
102
|
scaleShortcut?: boolean;
|
|
80
103
|
}
|
|
81
104
|
/** @public */
|
|
82
|
-
export default function SoundCompass({ speakers, size, viewT, activeSpeakerId, playedIds, selectedId, answerId, showFeedback, pulseSelected, clickable, onSelectSpeaker, buttonSize, showIcon, shortcutAnchor, shortcutScale, scaleShortcut, }: SoundCompassProps): import("react").JSX.Element;
|
|
105
|
+
export default function SoundCompass({ speakers, size, viewT, activeSpeakerId, playedIds, selectedId, answerId, showFeedback, pulseSelected, pulseSelectedDuration, pulseScale, clickable, onSelectSpeaker, buttonSize, showIcon, shortcutAnchor, shortcutScale, scaleShortcut, }: 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, pulseSelected = false, clickable = false, onSelectSpeaker, buttonSize = 40, showIcon = true, shortcutAnchor = 'top-right', shortcutScale, scaleShortcut = false, }) {
|
|
17
|
+
export default function SoundCompass({ speakers, size = 300, viewT = 0, activeSpeakerId = null, playedIds, selectedId = null, answerId = null, showFeedback = false, pulseSelected = false, pulseSelectedDuration, pulseScale, clickable = false, onSelectSpeaker, buttonSize = 40, showIcon = true, shortcutAnchor = 'top-right', shortcutScale, scaleShortcut = false, }) {
|
|
18
18
|
const t = Math.max(0, Math.min(1, viewT));
|
|
19
19
|
const CENTER = size / 2;
|
|
20
20
|
// ── 탑뷰 좌표 ──────────────────────────────────────────────────────────
|
|
@@ -192,6 +192,16 @@ export default function SoundCompass({ speakers, size = 300, viewT = 0, activeSp
|
|
|
192
192
|
const iconSize = Math.round(Math.max(10, Math.min(56, BTN * 0.38)));
|
|
193
193
|
const numberSize = Math.round(Math.max(7, Math.min(18, BTN * 0.2)));
|
|
194
194
|
const numberOnlySize = Math.round(Math.max(10, Math.min(56, BTN * 0.4)));
|
|
195
|
-
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
|
|
195
|
+
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 sound-compass__pulse--${state}`
|
|
196
|
+
+ (pulse === 'once' ? ' sound-compass__pulse--once' : ''), style: {
|
|
197
|
+
width: BTN, height: BTN,
|
|
198
|
+
// 안 주면 아예 얹지 않는다 — CSS 의 기본값이 살아 있게.
|
|
199
|
+
...(pulse === 'once' && pulseSelectedDuration !== undefined
|
|
200
|
+
? { ['--sc-pulse-duration-once']: `${pulseSelectedDuration}ms` }
|
|
201
|
+
: null),
|
|
202
|
+
...(pulseScale !== undefined
|
|
203
|
+
? { ['--sc-pulse-scale']: String(pulseScale) }
|
|
204
|
+
: null),
|
|
205
|
+
} })), _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));
|
|
196
206
|
})] }) }));
|
|
197
207
|
}
|