@suphark/ui 0.4.0 → 0.4.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  รูปแบบตาม [Keep a Changelog](https://keepachangelog.com/) · semver: patch = หน้าตา/บั๊ก, minor = component/prop ใหม่, major = เปลี่ยน/ลบ props
4
4
 
5
+ ## [0.4.1] — 2026-09-19
6
+
7
+ ### Added
8
+
9
+ - **`SwitcherChevron`** (barrel) — ลูกศร ⇅ มาตรฐานท้าย trigger แบบ switcher/select: `ChevronsUpDown` ขนาด `size-3` (12px) `shrink-0 text-muted-foreground opacity-70` aria-hidden (เล็กบางแบบ Clerk) รับ `className` ทับได้ — ใช้ตัวเดียวทั้งแพ็กเกจ/แอป (`OrganizationSwitcher` ใน @suphark/auth-ui จะย้ายมาใช้ด้วย)
10
+
11
+ ### Fixed
12
+
13
+ - `HeaderCrumb`: ลูกศรใหญ่ 24px ในแอปปลายทาง (Pi Auth) — เดิมใช้ `size-3.5!` ซึ่ง Tailwind ของแอปที่ scan ผ่าน `@source` ไม่ generate class แบบ `!` → svg ไม่มีขนาดจึงตกไป 24px ของ lucide; เปลี่ยนเป็น `SwitcherChevron` (ไม่ใช้ `!`)
14
+
15
+ ### Changed
16
+
17
+ - ลูกศรของ `UserMenu`, `Combobox`, `MultiSelectCombobox`, `FormFieldCombobox`, `FormFieldSelect` เปลี่ยนมาใช้ `SwitcherChevron` (เดิม h-4 w-4 opacity-50 ปนกันหลายขนาด) — ทุกจุดได้ 12px จางเท่ากัน; ไอคอน sort ใน `DataTableColumnHeader` ไม่ใช่ switcher คงเดิม; `components/ui/searchable-select.tsx` เป็นไฟล์ shadcn ไม่แตะ
18
+ - นโยบาย: หลีกเลี่ยง `!` บน utility ในแพ็กเกจถ้าไม่จำเป็น (เหลือเฉพาะ `group-data-[collapsible=icon]:p-0!` ใน `AppBrand` ซึ่ง `sidebar.tsx` ของ shadcn generate class เดียวกันอยู่แล้ว)
19
+
5
20
  ## [0.4.0] — 2026-09-19
6
21
 
7
22
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suphark/ui",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Design system กลางของ Suphark apps: shadcn/ui (base-nova, Base UI, Tailwind v4) + shared components + token/ฟอนต์ Noto Sans Thai Looped — ส่งเป็น source ให้แอป Next transpile เอง",
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
+ import { SwitcherChevron } from "@suphark/ui/components/shared/switcher-chevron";
3
4
  import { cn } from "@suphark/ui/lib/utils";
4
- import { ChevronsUpDown } from "lucide-react";
5
5
  import { type ComponentProps, Fragment, type ReactNode } from "react";
6
6
 
7
7
  /**
@@ -50,7 +50,7 @@ export function HeaderCrumb({
50
50
  </span>
51
51
  )}
52
52
  {children}
53
- {chevron && <ChevronsUpDown className="size-3.5! text-muted-foreground" aria-hidden="true" />}
53
+ {chevron && <SwitcherChevron />}
54
54
  </button>
55
55
  );
56
56
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { Initials } from "@suphark/ui/components/shared/initials";
4
+ import { SwitcherChevron } from "@suphark/ui/components/shared/switcher-chevron";
4
5
  import { Button } from "@suphark/ui/components/ui/button";
5
6
  import {
6
7
  DropdownMenu,
@@ -12,7 +13,7 @@ import {
12
13
  DropdownMenuTrigger,
13
14
  } from "@suphark/ui/components/ui/dropdown-menu";
14
15
  import { cn } from "@suphark/ui/lib/utils";
15
- import { ChevronsUpDown, LogOut } from "lucide-react";
16
+ import { LogOut } from "lucide-react";
16
17
  import { type ReactNode, useTransition } from "react";
17
18
 
18
19
  export interface UserMenuUser {
@@ -82,10 +83,8 @@ export function UserMenu({
82
83
  <span className="truncate text-muted-foreground text-xs">{description}</span>
83
84
  )}
84
85
  </span>
85
- <ChevronsUpDown
86
- aria-hidden="true"
86
+ <SwitcherChevron
87
87
  className={cn(
88
- "text-muted-foreground",
89
88
  variant === "sidebar" ? "group-data-[collapsible=icon]:hidden" : "hidden xl:block",
90
89
  )}
91
90
  />
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
 
3
+ import { SwitcherChevron } from "@suphark/ui/components/shared/switcher-chevron";
3
4
  import { Button } from "@suphark/ui/components/ui/button";
4
5
  import {
5
6
  Command,
@@ -11,7 +12,7 @@ import {
11
12
  } from "@suphark/ui/components/ui/command";
12
13
  import { Popover, PopoverContent, PopoverTrigger } from "@suphark/ui/components/ui/popover";
13
14
  import { cn } from "@suphark/ui/lib/utils";
14
- import { Check, ChevronsUpDown } from "lucide-react";
15
+ import { Check } from "lucide-react";
15
16
  import * as React from "react";
16
17
 
17
18
  interface ComboboxProps {
@@ -75,12 +76,8 @@ export function Combobox({
75
76
  >
76
77
  {value ? options.find((option) => option.value === value)?.label : placeholder}
77
78
  </span>
78
- <ChevronsUpDown
79
- className={cn(
80
- "ml-2 h-4 w-4 shrink-0 opacity-50 print:hidden",
81
- wrapText && "self-start",
82
- disabled && "hidden",
83
- )}
79
+ <SwitcherChevron
80
+ className={cn("ml-2 print:hidden", wrapText && "self-start", disabled && "hidden")}
84
81
  />
85
82
  </PopoverTrigger>
86
83
  <PopoverContent className="w-[--anchor-width] p-0">
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
 
3
+ import { SwitcherChevron } from "@suphark/ui/components/shared/switcher-chevron";
3
4
  import { Button } from "@suphark/ui/components/ui/button";
4
5
  import {
5
6
  Command,
@@ -18,7 +19,7 @@ import {
18
19
  } from "@suphark/ui/components/ui/form";
19
20
  import { Popover, PopoverContent, PopoverTrigger } from "@suphark/ui/components/ui/popover";
20
21
  import { cn } from "@suphark/ui/lib/utils";
21
- import { Check, ChevronsUpDown } from "lucide-react";
22
+ import { Check } from "lucide-react";
22
23
  import * as React from "react";
23
24
  import { useEffect, useState, useTransition } from "react";
24
25
  import type { FieldValues, Path } from "react-hook-form";
@@ -119,7 +120,7 @@ export function FormFieldCombobox<T extends FieldValues>({
119
120
  ? "Loading..."
120
121
  : placeholder}
121
122
  </span>
122
- <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
123
+ <SwitcherChevron className="ml-2" />
123
124
  </PopoverTrigger>
124
125
  <PopoverContent className="w-[--anchor-width] p-0">
125
126
  <Command>
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  import { MultiSelectCombobox } from "@suphark/ui/components/shared/multi-select-combobox";
4
+ import { SwitcherChevron } from "@suphark/ui/components/shared/switcher-chevron";
4
5
  import { Button } from "@suphark/ui/components/ui/button";
5
6
  import {
6
7
  Command,
@@ -26,7 +27,7 @@ import {
26
27
  SelectValue,
27
28
  } from "@suphark/ui/components/ui/select";
28
29
  import { cn } from "@suphark/ui/lib/utils";
29
- import { Check, ChevronsUpDown } from "lucide-react";
30
+ import { Check } from "lucide-react";
30
31
  import * as React from "react";
31
32
  import type { ControllerRenderProps, FieldValues, Path, PathValue } from "react-hook-form";
32
33
 
@@ -126,7 +127,7 @@ function ComboboxContent<T extends FieldValues>({
126
127
  disabled={disabled}
127
128
  >
128
129
  <span className="truncate">{selectedLabel}</span>
129
- <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
130
+ <SwitcherChevron className="ml-2" />
130
131
  </Button>
131
132
  </PopoverTrigger>
132
133
  <PopoverContent className="w-[--anchor-width] p-0">
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
 
3
+ import { SwitcherChevron } from "@suphark/ui/components/shared/switcher-chevron";
3
4
  import { Badge } from "@suphark/ui/components/ui/badge";
4
5
  import { Button } from "@suphark/ui/components/ui/button";
5
6
  import {
@@ -13,7 +14,7 @@ import {
13
14
  } from "@suphark/ui/components/ui/command";
14
15
  import { Popover, PopoverContent, PopoverTrigger } from "@suphark/ui/components/ui/popover";
15
16
  import { cn } from "@suphark/ui/lib/utils";
16
- import { Check, ChevronsUpDown, Plus, X } from "lucide-react";
17
+ import { Check, Plus, X } from "lucide-react";
17
18
  import * as React from "react";
18
19
 
19
20
  export interface MultiSelectOption {
@@ -259,9 +260,7 @@ export function MultiSelectCombobox({
259
260
  <X className="size-3.5" />
260
261
  </span>
261
262
  )}
262
- <ChevronsUpDown
263
- className={cn("size-4 shrink-0 opacity-50 print:hidden", disabled && "hidden")}
264
- />
263
+ <SwitcherChevron className={cn("print:hidden", disabled && "hidden")} />
265
264
  </div>
266
265
  </PopoverTrigger>
267
266
  <PopoverContent className="w-[--anchor-width] min-w-[220px] p-0" align="start">
@@ -0,0 +1,19 @@
1
+ import { cn } from "@suphark/ui/lib/utils";
2
+ import { ChevronsUpDown } from "lucide-react";
3
+ import type { ComponentProps } from "react";
4
+
5
+ /**
6
+ * ลูกศร ⇅ มาตรฐานท้าย trigger แบบ switcher/select (HeaderCrumb, UserMenu, Combobox, OrganizationSwitcher …)
7
+ * เล็กบางแบบ Clerk: 12px จาง — ใช้ตัวเดียวทั้งแพ็กเกจเพื่อให้ขนาดเท่ากันทุกจุด
8
+ * ไม่ใช้ `!` บน utility (แอปที่ scan ผ่าน @source อาจไม่ generate class นั้น); ปุ่มที่มี
9
+ * `[&_svg:not([class*='size-'])]:size-4` จะไม่ทับเพราะ class มี `size-3` อยู่แล้ว
10
+ */
11
+ export function SwitcherChevron({ className, ...props }: ComponentProps<typeof ChevronsUpDown>) {
12
+ return (
13
+ <ChevronsUpDown
14
+ aria-hidden="true"
15
+ className={cn("size-3 shrink-0 text-muted-foreground opacity-70", className)}
16
+ {...props}
17
+ />
18
+ );
19
+ }
package/src/index.ts CHANGED
@@ -63,6 +63,7 @@ export { SecretReveal } from "./components/shared/secret-reveal";
63
63
  export { SectionCard } from "./components/shared/section-card";
64
64
  export { Stat } from "./components/shared/stat";
65
65
  export { StatusBadge, statusTone, type Tone } from "./components/shared/status-badge";
66
+ export { SwitcherChevron } from "./components/shared/switcher-chevron";
66
67
  export {
67
68
  PrimarySecondaryText,
68
69
  type PrimarySecondaryTextProps,