@kahitsan/ksui 0.13.2 → 0.14.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kahitsan/ksui",
3
- "version": "0.13.2",
3
+ "version": "0.14.0",
4
4
  "description": "ksui is a standalone set of SolidJS UI components for KahitSan/Hilinga and any SolidJS app. Published to the public npm registry and consumed as a normal dependency. Ships source under a `solid` export condition so the consumer's vite-plugin-solid compiles it with only solid-js externalized; it depends on nothing but solid-js + lucide-solid and injects its own CSS.",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -0,0 +1,31 @@
1
+ import AccountAvatar, { type AvatarAccount } from "./AccountAvatar";
2
+
3
+ export interface AvatarProps {
4
+ name: string;
5
+ image?: string | null;
6
+ size?: "xs" | "sm" | "md" | "lg";
7
+ class?: string;
8
+ }
9
+
10
+ const sizeMap: Record<string, number> = {
11
+ xs: 20,
12
+ sm: 24,
13
+ md: 28,
14
+ lg: 40,
15
+ };
16
+
17
+ /**
18
+ * Generic person/user avatar — a thin, domain-free wrapper over {@link AccountAvatar}'s
19
+ * user variant that accepts a name + optional image and a t-shirt size. Use this for
20
+ * people; use AccountAvatar directly for financial accounts.
21
+ */
22
+ export default function Avatar(props: AvatarProps) {
23
+ const account: AvatarAccount = {
24
+ id: 0,
25
+ type: "user",
26
+ name: props.name,
27
+ image: props.image,
28
+ };
29
+
30
+ return <AccountAvatar account={account} size={sizeMap[props.size ?? "md"]} class={props.class} />;
31
+ }
@@ -0,0 +1,52 @@
1
+ import ComboBox from "./ComboBox";
2
+ import Search from "lucide-solid/icons/search";
3
+
4
+ export interface SearchableOption {
5
+ value: string | number;
6
+ label: string;
7
+ description?: string;
8
+ }
9
+
10
+ export interface SearchableSelectProps {
11
+ value: string | number | null | undefined;
12
+ options: SearchableOption[];
13
+ onChange: (next: SearchableOption | null) => void | Promise<void>;
14
+ placeholder?: string;
15
+ disabled?: boolean;
16
+ }
17
+
18
+ /**
19
+ * Simple single-select dropdown with client-side fuzzy search over a static option
20
+ * list — a domain-free convenience wrapper over {@link ComboBox}. For richer behavior
21
+ * (async search, create-on-the-fly, multi-select) use ComboBox directly.
22
+ */
23
+ export default function SearchableSelect(props: SearchableSelectProps) {
24
+ const selected = () => {
25
+ if (props.value == null || props.value === "") return null;
26
+ return props.options.find((o) => String(o.value) === String(props.value)) ?? null;
27
+ };
28
+
29
+ return (
30
+ <ComboBox<SearchableOption>
31
+ search={async (q) => {
32
+ const trimmed = q.trim().toLowerCase();
33
+ if (!trimmed) return props.options;
34
+ return props.options.filter(
35
+ (o) =>
36
+ o.label.toLowerCase().includes(trimmed) ||
37
+ (o.description?.toLowerCase().includes(trimmed) ?? false),
38
+ );
39
+ }}
40
+ selected={selected()}
41
+ onChange={(next) => props.onChange(next)}
42
+ idOf={(o) => o.value}
43
+ labelOf={(o) => o.label}
44
+ secondaryOf={(o) => o.description ?? null}
45
+ icon={Search}
46
+ noun="option"
47
+ placeholder={props.placeholder ?? "Select..."}
48
+ disabled={props.disabled}
49
+ testIdPrefix="searchable-select"
50
+ />
51
+ );
52
+ }
package/src/index.ts CHANGED
@@ -40,6 +40,7 @@ export {
40
40
  buildInitialsSvg,
41
41
  } from "./components/base/AccountAvatar";
42
42
  export type { AvatarAccount } from "./components/base/AccountAvatar";
43
+ export { default as Avatar, type AvatarProps } from "./components/base/Avatar";
43
44
 
44
45
  export { default as ExistingAttachmentTile } from "./components/base/ExistingAttachmentTile";
45
46
  export type { ExistingAttachment } from "./components/base/ExistingAttachmentTile";
@@ -131,6 +132,11 @@ export type {
131
132
  ComboBoxSingleProps,
132
133
  ComboBoxMultiProps,
133
134
  } from "./components/composite/ComboBox";
135
+ export {
136
+ default as SearchableSelect,
137
+ type SearchableSelectProps,
138
+ type SearchableOption,
139
+ } from "./components/composite/SearchableSelect";
134
140
 
135
141
  // Shared domain option shapes for the common pickers, decoupled from any
136
142
  // component (still imported across transactions / counter / payees).