@forthtilliath/forth-ui 0.2.2 → 0.2.4

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.
@@ -5,6 +5,8 @@ export interface ColorPickerProps {
5
5
  onValueChange?: (value: string) => void;
6
6
  disabled?: boolean;
7
7
  className?: string;
8
+ /** Accessible name for the color swatch, which otherwise has no visible text. */
9
+ ariaLabel?: string;
8
10
  }
9
11
  /**
10
12
  * A color swatch + hex text input, kept in sync — built on the browser's
@@ -20,5 +22,5 @@ export interface ColorPickerProps {
20
22
  * @author Forth
21
23
  * @copyright 2026 Forth
22
24
  */
23
- export declare function ColorPicker({ value, defaultValue, onValueChange, disabled, className, }: ColorPickerProps): React.JSX.Element;
25
+ export declare function ColorPicker({ value, defaultValue, onValueChange, disabled, className, ariaLabel, }: ColorPickerProps): React.JSX.Element;
24
26
  //# sourceMappingURL=color-picker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"color-picker.d.ts","sourceRoot":"","sources":["../../../src/components/color-picker/color-picker.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,YAAwB,EACxB,aAAa,EACb,QAAgB,EAChB,SAAS,GACV,EAAE,gBAAgB,qBAmDlB"}
1
+ {"version":3,"file":"color-picker.d.ts","sourceRoot":"","sources":["../../../src/components/color-picker/color-picker.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,YAAwB,EACxB,aAAa,EACb,QAAgB,EAChB,SAAS,EACT,SAA0B,GAC3B,EAAE,gBAAgB,qBAoDlB"}
@@ -18,7 +18,7 @@ const HEX_PATTERN = /^#[0-9a-f]{6}$/i;
18
18
  * @author Forth
19
19
  * @copyright 2026 Forth
20
20
  */
21
- export function ColorPicker({ value, defaultValue = "#000000", onValueChange, disabled = false, className, }) {
21
+ export function ColorPicker({ value, defaultValue = "#000000", onValueChange, disabled = false, className, ariaLabel = "Choose color", }) {
22
22
  const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);
23
23
  const [textValue, setTextValue] = React.useState(defaultValue);
24
24
  const color = value ?? uncontrolledValue;
@@ -27,7 +27,7 @@ export function ColorPicker({ value, defaultValue = "#000000", onValueChange, di
27
27
  setTextValue(next);
28
28
  onValueChange?.(next);
29
29
  }
30
- return (_jsxs("div", { "data-slot": "color-picker", className: cn("flex items-center gap-2", className), children: [_jsx("label", { className: cn("border-input size-9 shrink-0 overflow-hidden rounded-md border shadow-xs", disabled && "pointer-events-none opacity-50"), style: { backgroundColor: color }, children: _jsx("input", { type: "color", value: color, disabled: disabled, onChange: (e) => {
30
+ return (_jsxs("div", { "data-slot": "color-picker", className: cn("flex items-center gap-2", className), children: [_jsx("label", { "aria-label": ariaLabel, className: cn("border-input size-9 shrink-0 overflow-hidden rounded-md border shadow-xs", disabled && "pointer-events-none opacity-50"), style: { backgroundColor: color }, children: _jsx("input", { type: "color", value: color, disabled: disabled, onChange: (e) => {
31
31
  commit(e.target.value);
32
32
  }, className: "size-full cursor-pointer opacity-0" }) }), _jsx(Input, { value: textValue, disabled: disabled, onChange: (e) => {
33
33
  setTextValue(e.target.value);
@@ -1 +1 @@
1
- {"version":3,"file":"multi-select.d.ts","sourceRoot":"","sources":["../../../src/components/combobox/multi-select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAqB/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAE/C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,KAAK,EACL,YAAY,EACZ,aAAa,EACb,WAAuB,EACvB,YAAkC,EAClC,QAAgB,EAChB,SAAS,GACV,EAAE,gBAAgB,qBA+GlB"}
1
+ {"version":3,"file":"multi-select.d.ts","sourceRoot":"","sources":["../../../src/components/combobox/multi-select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAqB/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAE/C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,KAAK,EACL,YAAY,EACZ,aAAa,EACb,WAAuB,EACvB,YAAkC,EAClC,QAAgB,EAChB,SAAS,GACV,EAAE,gBAAgB,qBAoHlB"}
@@ -23,6 +23,7 @@ import { Badge } from "../badge";
23
23
  * @copyright 2026 Forth
24
24
  */
25
25
  export function MultiSelect({ options, value, defaultValue, onValueChange, placeholder = "Select…", emptyMessage = "No results found.", disabled = false, className, }) {
26
+ const listboxId = React.useId();
26
27
  const [open, setOpen] = React.useState(false);
27
28
  const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue ?? []);
28
29
  const selected = value ?? uncontrolledValue;
@@ -36,7 +37,7 @@ export function MultiSelect({ options, value, defaultValue, onValueChange, place
36
37
  : [...selected, optionValue]);
37
38
  }
38
39
  const selectedOptions = options.filter((option) => selected.includes(option.value));
39
- return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("div", { role: "combobox", tabIndex: disabled ? -1 : 0, "aria-expanded": open, "aria-disabled": disabled, "data-disabled": disabled, onKeyDown: (e) => {
40
+ return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("div", { role: "combobox", tabIndex: disabled ? -1 : 0, "aria-expanded": open, "aria-controls": listboxId, "aria-disabled": disabled, "data-disabled": disabled, onKeyDown: (e) => {
40
41
  if (!disabled && (e.key === "Enter" || e.key === " ")) {
41
42
  e.preventDefault();
42
43
  setOpen((prev) => !prev);
@@ -45,7 +46,7 @@ export function MultiSelect({ options, value, defaultValue, onValueChange, place
45
46
  e.stopPropagation();
46
47
  }, onOpenChange: () => {
47
48
  toggle(option.value);
48
- }, children: option.label }, option.value)))) : (_jsx("span", { className: "text-muted-foreground font-normal", children: placeholder })) }), _jsx(ChevronsUpDownIcon, { className: "shrink-0 opacity-50" })] }) }), _jsx(PopoverContent, { className: "w-(--radix-popover-trigger-width) p-0", children: _jsxs(Command, { children: [_jsx(CommandInput, { placeholder: placeholder }), _jsxs(CommandList, { children: [_jsx(CommandEmpty, { children: emptyMessage }), _jsx(CommandGroup, { children: options.map((option) => (_jsxs(CommandItem, { value: option.label, disabled: option.disabled, onSelect: () => {
49
+ }, children: option.label }, option.value)))) : (_jsx("span", { className: "text-muted-foreground font-normal", children: placeholder })) }), _jsx(ChevronsUpDownIcon, { className: "shrink-0 opacity-50" })] }) }), _jsx(PopoverContent, { id: listboxId, className: "w-(--radix-popover-trigger-width) p-0", children: _jsxs(Command, { children: [_jsx(CommandInput, { placeholder: placeholder }), _jsxs(CommandList, { children: [_jsx(CommandEmpty, { children: emptyMessage }), _jsx(CommandGroup, { children: options.map((option) => (_jsxs(CommandItem, { value: option.label, disabled: option.disabled, onSelect: () => {
49
50
  toggle(option.value);
50
51
  }, children: [_jsx(CheckIcon, { className: cn("size-4", selected.includes(option.value)
51
52
  ? "opacity-100"
@@ -1 +1 @@
1
- {"version":3,"file":"rating.d.ts","sourceRoot":"","sources":["../../../src/components/rating/rating.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAQD;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,YAAgB,EAChB,aAAa,EACb,GAAO,EACP,QAAgB,EAChB,QAAgB,EAChB,IAAgB,EAChB,SAAS,GACV,EAAE,WAAW,qBA0Db"}
1
+ {"version":3,"file":"rating.d.ts","sourceRoot":"","sources":["../../../src/components/rating/rating.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAQD;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAK,EACL,YAAgB,EAChB,aAAa,EACb,GAAO,EACP,QAAgB,EAChB,QAAgB,EAChB,IAAgB,EAChB,SAAS,GACV,EAAE,WAAW,qBA+Db"}
@@ -27,7 +27,12 @@ export function Rating({ value, defaultValue = 0, onValueChange, max = 5, disabl
27
27
  setUncontrolledValue(next);
28
28
  onValueChange?.(next);
29
29
  }
30
- return (_jsx("div", { role: "radiogroup", "aria-disabled": disabled, "data-slot": "rating", className: cn("inline-flex items-center gap-0.5", (disabled || readOnly) && "pointer-events-none", className), onMouseLeave: () => {
30
+ return (_jsx("div", { role: "radiogroup",
31
+ // Not a Tab stop itself — focus lives on the roving `role="radio"`
32
+ // children below — but jsx-a11y wants an interactive-role element with
33
+ // a mouse handler (onMouseLeave, used only to clear the hover preview)
34
+ // to declare an explicit tabIndex.
35
+ tabIndex: -1, "aria-disabled": disabled, "data-slot": "rating", className: cn("inline-flex items-center gap-0.5", (disabled || readOnly) && "pointer-events-none", className), onMouseLeave: () => {
31
36
  setHoverValue(null);
32
37
  }, children: Array.from({ length: max }, (_, i) => i + 1).map((starValue) => (_jsx("button", { type: "button", role: "radio", "aria-checked": current === starValue, "aria-label": `${starValue.toString()} star${starValue > 1 ? "s" : ""}`, disabled: disabled, tabIndex: readOnly ? -1 : 0, onMouseEnter: () => {
33
38
  setHoverValue(starValue);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forthtilliath/forth-ui",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -24,8 +24,8 @@
24
24
  "react": "^19.2.8",
25
25
  "react-dom": "^19.2.8",
26
26
  "shiki": "^4.4.3",
27
- "@forthtilliath/react-kit": "0.2.0",
28
- "@forthtilliath/shadcn-ui": "0.2.0"
27
+ "@forthtilliath/shadcn-ui": "0.2.0",
28
+ "@forthtilliath/react-kit": "0.3.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@tailwindcss/postcss": "4.1.12",
@@ -38,9 +38,9 @@
38
38
  "eslint": "10.7.0",
39
39
  "tailwindcss": "4.1.12",
40
40
  "typescript": "^5.9.3",
41
- "@forthtilliath/eslint-config": "0.1.0",
42
- "@forthtilliath/ts-types": "0.1.0",
43
- "@forthtilliath/typescript-config": "0.0.0"
41
+ "@forthtilliath/ts-types": "0.2.0",
42
+ "@forthtilliath/typescript-config": "0.0.0",
43
+ "@forthtilliath/eslint-config": "0.4.2"
44
44
  },
45
45
  "files": [
46
46
  "dist"