@celestia-island/hikari 0.55.28 → 0.55.29
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/package.json
CHANGED
|
@@ -107,6 +107,7 @@
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
.hk-icon-group-item {
|
|
110
|
+
position: relative;
|
|
110
111
|
display: inline-flex;
|
|
111
112
|
align-items: center;
|
|
112
113
|
justify-content: center;
|
|
@@ -168,3 +169,29 @@
|
|
|
168
169
|
font-weight: 600;
|
|
169
170
|
line-height: 1;
|
|
170
171
|
}
|
|
172
|
+
|
|
173
|
+
/* Status marker (HkIconButtonGroupOption.marker) — a small dot pinned to
|
|
174
|
+
* the item's bottom-right corner. "success" = the theme's success green
|
|
175
|
+
* with a surface-colored ring so it stays legible on top of the icon's
|
|
176
|
+
* corner and across active/muted tints. Purely decorative: the accessible
|
|
177
|
+
* meaning lives in the option's label/tooltip the host controls. */
|
|
178
|
+
.hk-icon-group-item-marker {
|
|
179
|
+
position: absolute;
|
|
180
|
+
right: calc(var(--space-1, 0.25rem) / 2);
|
|
181
|
+
bottom: calc(var(--space-1, 0.25rem) / 2);
|
|
182
|
+
width: 0.5rem;
|
|
183
|
+
height: 0.5rem;
|
|
184
|
+
border-radius: 999px;
|
|
185
|
+
pointer-events: none;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.hk-icon-group-item-marker-success {
|
|
189
|
+
background: rgb(var(--color-success, 14 184 64));
|
|
190
|
+
box-shadow: 0 0 0 0.125rem rgb(var(--color-surface, 240 244 248));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/* Slider items already establish position:relative for the thumb stack —
|
|
194
|
+
* keep the marker above the gliding pill, not under it. */
|
|
195
|
+
.hk-icon-group-slider .hk-icon-group-item .hk-icon-group-item-marker {
|
|
196
|
+
z-index: 1;
|
|
197
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { afterEach, describe, expect, it } from "vitest";
|
|
3
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
4
4
|
import { createApp, defineComponent, h, nextTick, ref } from "vue";
|
|
5
5
|
|
|
6
6
|
import HkIconButtonGroup from "./HkIconButtonGroup";
|
|
@@ -303,3 +303,41 @@ describe("HkIconButtonGroup", () => {
|
|
|
303
303
|
});
|
|
304
304
|
});
|
|
305
305
|
});
|
|
306
|
+
describe("option markers", () => {
|
|
307
|
+
const baseOpts = (marker?: "success", disabled?: boolean) => [
|
|
308
|
+
{ key: "totp", label: "TOTP" },
|
|
309
|
+
{ key: "password", label: "Password", marker, disabled },
|
|
310
|
+
];
|
|
311
|
+
|
|
312
|
+
it("renders the success marker dot and data-marker attribute", () => {
|
|
313
|
+
const c = mountComp(() => h(HkIconButtonGroup, {
|
|
314
|
+
mode: "single",
|
|
315
|
+
variant: "slider",
|
|
316
|
+
options: baseOpts("success"),
|
|
317
|
+
modelValue: "totp",
|
|
318
|
+
}));
|
|
319
|
+
const item = c.querySelector('.hk-icon-group-item[data-key="password"]') as HTMLElement;
|
|
320
|
+
expect(item).toBeTruthy();
|
|
321
|
+
expect(item.getAttribute("data-marker")).toBe("success");
|
|
322
|
+
expect(item.querySelector(".hk-icon-group-item-marker-success")).toBeTruthy();
|
|
323
|
+
// The untouched sibling carries no marker.
|
|
324
|
+
const sibling = c.querySelector('.hk-icon-group-item[data-key="totp"]') as HTMLElement;
|
|
325
|
+
expect(sibling.getAttribute("data-marker")).toBeNull();
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it("ignores activation of a disabled marked option", async () => {
|
|
329
|
+
const onSelect = vi.fn();
|
|
330
|
+
const c = mountComp(() => h(HkIconButtonGroup, {
|
|
331
|
+
mode: "single",
|
|
332
|
+
variant: "slider",
|
|
333
|
+
options: baseOpts("success", true),
|
|
334
|
+
modelValue: "totp",
|
|
335
|
+
onSelect,
|
|
336
|
+
}));
|
|
337
|
+
const item = c.querySelector('.hk-icon-group-item[data-key="password"]') as HTMLButtonElement;
|
|
338
|
+
expect(item.getAttribute("disabled")).not.toBeNull();
|
|
339
|
+
item.click();
|
|
340
|
+
await Promise.resolve();
|
|
341
|
+
expect(onSelect).not.toHaveBeenCalled();
|
|
342
|
+
});
|
|
343
|
+
});
|
|
@@ -17,6 +17,11 @@ export interface HkIconButtonGroupOption {
|
|
|
17
17
|
* host's vue differs. Missing icons fall back to the label's initial. */
|
|
18
18
|
icon?: unknown;
|
|
19
19
|
disabled?: boolean;
|
|
20
|
+
/** Status dot pinned to the item's bottom-right corner. `"success"`
|
|
21
|
+
* draws a small green dot (step-proven factor, completed requirement);
|
|
22
|
+
* the dot is decorative — pair it with `disabled` and an updated
|
|
23
|
+
* tooltip when it means "this one is done". */
|
|
24
|
+
marker?: "success";
|
|
20
25
|
/** Tooltip text override; an EMPTY string suppresses the tooltip. */
|
|
21
26
|
tooltip?: string;
|
|
22
27
|
}
|
|
@@ -168,6 +173,7 @@ export default defineComponent({
|
|
|
168
173
|
class="hk-icon-group-item"
|
|
169
174
|
data-key={option.key}
|
|
170
175
|
data-active={active || undefined}
|
|
176
|
+
data-marker={option.marker || undefined}
|
|
171
177
|
role={props.mode === "single" ? "radio" : undefined}
|
|
172
178
|
aria-checked={props.mode === "single" ? active : undefined}
|
|
173
179
|
aria-pressed={props.mode === "multiple" ? active : undefined}
|
|
@@ -185,6 +191,12 @@ export default defineComponent({
|
|
|
185
191
|
</span>
|
|
186
192
|
)}
|
|
187
193
|
</span>
|
|
194
|
+
{option.marker && (
|
|
195
|
+
<span
|
|
196
|
+
class={`hk-icon-group-item-marker hk-icon-group-item-marker-${option.marker}`}
|
|
197
|
+
aria-hidden="true"
|
|
198
|
+
/>
|
|
199
|
+
)}
|
|
188
200
|
</button>
|
|
189
201
|
);
|
|
190
202
|
// An empty tooltip override suppresses the wrapper entirely.
|