@volksverpetzer/ui-web 0.12.1 → 0.13.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/PillGroup.css +52 -0
- package/dist/PillGroup.d.ts +25 -0
- package/dist/PillGroup.js +45 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/styles.css +53 -0
- package/package.json +3 -3
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
.vvp-ui-pill-group {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
flex-wrap: wrap;
|
|
4
|
+
gap: var(--vvp-spacing-sm, 8px);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.vvp-ui-pill-group__option {
|
|
8
|
+
display: inline-flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
border: 2px solid var(--vvp-surface, #e2f0f5);
|
|
12
|
+
border-radius: var(--vvp-radius-full, 9999px);
|
|
13
|
+
background: var(--vvp-background, #fff);
|
|
14
|
+
color: var(--vvp-text, #111);
|
|
15
|
+
font-family: inherit;
|
|
16
|
+
font-weight: 700;
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
transition:
|
|
19
|
+
background-color 0.15s ease,
|
|
20
|
+
border-color 0.15s ease,
|
|
21
|
+
color 0.15s ease;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.vvp-ui-pill-group[data-size="md"] .vvp-ui-pill-group__option {
|
|
25
|
+
padding: var(--vvp-spacing-md, 10px) var(--vvp-spacing-xl, 20px);
|
|
26
|
+
font-size: var(--vvp-font-size-base, 16px);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.vvp-ui-pill-group[data-size="sm"] .vvp-ui-pill-group__option {
|
|
30
|
+
padding: var(--vvp-spacing-sm, 8px) var(--vvp-spacing-lg, 16px);
|
|
31
|
+
font-size: var(--vvp-font-size-sm, 14px);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.vvp-ui-pill-group__option:hover:not(:disabled) {
|
|
35
|
+
border-color: var(--vvp-primary-muted, #3893c0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.vvp-ui-pill-group__option:focus-visible {
|
|
39
|
+
outline: 2px solid var(--vvp-primary-muted, #3893c0);
|
|
40
|
+
outline-offset: 2px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.vvp-ui-pill-group__option:disabled {
|
|
44
|
+
opacity: 0.6;
|
|
45
|
+
cursor: not-allowed;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.vvp-ui-pill-group__option[aria-checked="true"] {
|
|
49
|
+
background: var(--vvp-primary, #1b7194);
|
|
50
|
+
border-color: var(--vvp-primary, #1b7194);
|
|
51
|
+
color: var(--vvp-on-primary, #fff);
|
|
52
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import "./PillGroup.css";
|
|
2
|
+
export interface PillGroupOption {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface PillGroupProps {
|
|
8
|
+
/** Visually hidden unless `label` is also rendered by the consumer via `aria-labelledby` — falls back to this as the accessible name. */
|
|
9
|
+
"aria-label"?: string;
|
|
10
|
+
options: PillGroupOption[];
|
|
11
|
+
value: string;
|
|
12
|
+
onChange: (value: string) => void;
|
|
13
|
+
size?: "sm" | "md";
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A row of pill-shaped options for choosing one of a small, fixed set of
|
|
19
|
+
* values — the house alternative to a native `<select>` (see vvp_app's
|
|
20
|
+
* "pills over dropdowns" convention, now ported to web). Implements the
|
|
21
|
+
* ARIA APG radiogroup pattern: one `role="radio"` per pill, roving
|
|
22
|
+
* tabindex, and Left/Right (and Up/Down) arrow keys move both focus and
|
|
23
|
+
* selection, matching native `<select>`/radio-group keyboard behavior.
|
|
24
|
+
*/
|
|
25
|
+
export declare function PillGroup({ "aria-label": ariaLabel, options, value, onChange, size, disabled, className, }: PillGroupProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useId } from "react";
|
|
3
|
+
import "./PillGroup.css";
|
|
4
|
+
/**
|
|
5
|
+
* A row of pill-shaped options for choosing one of a small, fixed set of
|
|
6
|
+
* values — the house alternative to a native `<select>` (see vvp_app's
|
|
7
|
+
* "pills over dropdowns" convention, now ported to web). Implements the
|
|
8
|
+
* ARIA APG radiogroup pattern: one `role="radio"` per pill, roving
|
|
9
|
+
* tabindex, and Left/Right (and Up/Down) arrow keys move both focus and
|
|
10
|
+
* selection, matching native `<select>`/radio-group keyboard behavior.
|
|
11
|
+
*/
|
|
12
|
+
export function PillGroup({ "aria-label": ariaLabel, options, value, onChange, size = "md", disabled = false, className, }) {
|
|
13
|
+
const groupId = useId();
|
|
14
|
+
const selectNext = (fromIndex, direction) => {
|
|
15
|
+
const enabled = options
|
|
16
|
+
.map((opt, i) => ({ opt, i }))
|
|
17
|
+
.filter(({ opt }) => !opt.disabled);
|
|
18
|
+
if (enabled.length === 0)
|
|
19
|
+
return;
|
|
20
|
+
const currentPos = enabled.findIndex(({ i }) => i === fromIndex);
|
|
21
|
+
const nextPos = (currentPos + direction + enabled.length) % enabled.length;
|
|
22
|
+
const next = enabled[nextPos];
|
|
23
|
+
if (next)
|
|
24
|
+
onChange(next.opt.value);
|
|
25
|
+
};
|
|
26
|
+
const handleKeyDown = (e, i) => {
|
|
27
|
+
switch (e.key) {
|
|
28
|
+
case "ArrowRight":
|
|
29
|
+
case "ArrowDown":
|
|
30
|
+
e.preventDefault();
|
|
31
|
+
selectNext(i, 1);
|
|
32
|
+
break;
|
|
33
|
+
case "ArrowLeft":
|
|
34
|
+
case "ArrowUp":
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
selectNext(i, -1);
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const classes = ["vvp-ui-pill-group", className].filter(Boolean).join(" ");
|
|
41
|
+
return (_jsx("div", { role: "radiogroup", "aria-label": ariaLabel, className: classes, "data-size": size, children: options.map((option, i) => {
|
|
42
|
+
const checked = option.value === value;
|
|
43
|
+
return (_jsx("button", { id: `${groupId}-${option.value}`, type: "button", role: "radio", "aria-checked": checked, disabled: disabled || option.disabled, tabIndex: checked ? 0 : -1, className: "vvp-ui-pill-group__option", onClick: () => onChange(option.value), onKeyDown: (e) => handleKeyDown(e, i), children: option.label }, option.value));
|
|
44
|
+
}) }));
|
|
45
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,4 +8,5 @@ export { Alert, type AlertProps, type AlertVariant } from "./Alert";
|
|
|
8
8
|
export { Slider, type SliderProps } from "./Slider";
|
|
9
9
|
export { ThemeToggle } from "./ThemeToggle";
|
|
10
10
|
export { InputButton, type InputButtonProps } from "./InputButton";
|
|
11
|
+
export { PillGroup, type PillGroupProps, type PillGroupOption, } from "./PillGroup";
|
|
11
12
|
export { ToolPage, type ToolPageProps, type ToolPageTag } from "./ToolPage";
|
package/dist/index.js
CHANGED
package/dist/styles.css
CHANGED
|
@@ -309,6 +309,59 @@
|
|
|
309
309
|
);
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
+
.vvp-ui-pill-group {
|
|
313
|
+
display: inline-flex;
|
|
314
|
+
flex-wrap: wrap;
|
|
315
|
+
gap: var(--vvp-spacing-sm, 8px);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.vvp-ui-pill-group__option {
|
|
319
|
+
display: inline-flex;
|
|
320
|
+
align-items: center;
|
|
321
|
+
justify-content: center;
|
|
322
|
+
border: 2px solid var(--vvp-surface, #e2f0f5);
|
|
323
|
+
border-radius: var(--vvp-radius-full, 9999px);
|
|
324
|
+
background: var(--vvp-background, #fff);
|
|
325
|
+
color: var(--vvp-text, #111);
|
|
326
|
+
font-family: inherit;
|
|
327
|
+
font-weight: 700;
|
|
328
|
+
cursor: pointer;
|
|
329
|
+
transition:
|
|
330
|
+
background-color 0.15s ease,
|
|
331
|
+
border-color 0.15s ease,
|
|
332
|
+
color 0.15s ease;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.vvp-ui-pill-group[data-size="md"] .vvp-ui-pill-group__option {
|
|
336
|
+
padding: var(--vvp-spacing-md, 10px) var(--vvp-spacing-xl, 20px);
|
|
337
|
+
font-size: var(--vvp-font-size-base, 16px);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.vvp-ui-pill-group[data-size="sm"] .vvp-ui-pill-group__option {
|
|
341
|
+
padding: var(--vvp-spacing-sm, 8px) var(--vvp-spacing-lg, 16px);
|
|
342
|
+
font-size: var(--vvp-font-size-sm, 14px);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.vvp-ui-pill-group__option:hover:not(:disabled) {
|
|
346
|
+
border-color: var(--vvp-primary-muted, #3893c0);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.vvp-ui-pill-group__option:focus-visible {
|
|
350
|
+
outline: 2px solid var(--vvp-primary-muted, #3893c0);
|
|
351
|
+
outline-offset: 2px;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.vvp-ui-pill-group__option:disabled {
|
|
355
|
+
opacity: 0.6;
|
|
356
|
+
cursor: not-allowed;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.vvp-ui-pill-group__option[aria-checked="true"] {
|
|
360
|
+
background: var(--vvp-primary, #1b7194);
|
|
361
|
+
border-color: var(--vvp-primary, #1b7194);
|
|
362
|
+
color: var(--vvp-on-primary, #fff);
|
|
363
|
+
}
|
|
364
|
+
|
|
312
365
|
.vvp-ui-progress {
|
|
313
366
|
width: 100%;
|
|
314
367
|
text-align: center;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volksverpetzer/ui-web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Shared brand-visible React components (Button, Badge, Card, ProgressBar, Input, Alert, Slider, ThemeToggle, InputButton) for vvp_link_shortener, vvp_divi5_extensions, crowdfunding, and vectorcrawl. Plain, hand-scoped CSS (vvp-ui-* class prefix) consuming the --vvp-* custom properties emitted by @volksverpetzer/design-tokens — no Tailwind classes, so it drops into a Tailwind app and Divi's WordPress-embedded CSS alike.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"react": ">=19"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@types/react": "^19.
|
|
31
|
-
"react": "^19.
|
|
30
|
+
"@types/react": "^19.3.0",
|
|
31
|
+
"react": "^19.3.0",
|
|
32
32
|
"typescript": "^6.0.3"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|