@open-mercato/ui 0.6.8-develop.7015.1.af90a2ddc7 → 0.6.8-develop.7016.1.4ed7b1e49d
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/.turbo/turbo-build.log +1 -1
- package/dist/backend/AppShell.js +4 -4
- package/dist/backend/AppShell.js.map +2 -2
- package/dist/backend/DataTable.js +3 -3
- package/dist/backend/DataTable.js.map +2 -2
- package/dist/backend/icons/lucideRegistry.generated.js +2 -0
- package/dist/backend/icons/lucideRegistry.generated.js.map +2 -2
- package/dist/primitives/icon-button.js +20 -1
- package/dist/primitives/icon-button.js.map +2 -2
- package/package.json +3 -3
- package/src/backend/AppShell.tsx +9 -11
- package/src/backend/DataTable.tsx +6 -3
- package/src/backend/__tests__/AppShell.test.tsx +46 -0
- package/src/backend/__tests__/DataTable.headerWrap.test.tsx +111 -0
- package/src/backend/icons/lucideRegistry.generated.tsx +2 -0
- package/src/primitives/__tests__/icon-button.test.tsx +70 -0
- package/src/primitives/icon-button.tsx +20 -1
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
AlertTriangle,
|
|
7
7
|
Apple,
|
|
8
8
|
Archive,
|
|
9
|
+
AtSign,
|
|
9
10
|
Award,
|
|
10
11
|
BadgeCheck,
|
|
11
12
|
Ban,
|
|
@@ -167,6 +168,7 @@ const LUCIDE_ICON_REGISTRY = {
|
|
|
167
168
|
"alert-triangle": AlertTriangle,
|
|
168
169
|
"apple": Apple,
|
|
169
170
|
"archive": Archive,
|
|
171
|
+
"at-sign": AtSign,
|
|
170
172
|
"award": Award,
|
|
171
173
|
"badge-check": BadgeCheck,
|
|
172
174
|
"ban": Ban,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/icons/lucideRegistry.generated.tsx"],
|
|
4
|
-
"sourcesContent": ["/* eslint-disable */\n// AUTO-GENERATED by @open-mercato/ui build. Do not edit by hand.\n// Generated from discovered icon string usages across the repo.\n\nimport type { LucideIcon } from 'lucide-react';\nimport {\n Activity,\n AlarmClock,\n AlertCircle,\n AlertOctagon,\n AlertTriangle,\n Apple,\n Archive,\n Award,\n BadgeCheck,\n Ban,\n Banknote,\n BarChart2,\n BarChart3,\n Bell,\n Bolt,\n Book,\n Bookmark,\n Box,\n Boxes,\n Briefcase,\n BriefcaseBusiness,\n Building,\n Building2,\n Calendar,\n CalendarCheck,\n CalendarClock,\n CalendarCog,\n CalendarMinus,\n CalendarOff,\n CalendarX,\n Check,\n CheckCircle,\n CheckCircle2,\n CheckSquare,\n Circle,\n ClipboardCheck,\n ClipboardList,\n Clock,\n Clock3,\n Coins,\n Copy,\n CopyX,\n CreditCard,\n Crown,\n Database,\n DollarSign,\n Download,\n ExternalLink,\n Eye,\n FileCheck,\n FileMinus,\n FilePenLine,\n Files,\n FileSpreadsheet,\n FileText,\n FilterX,\n Flag,\n Flame,\n FolderTree,\n Gauge,\n GitBranch,\n GitCompareArrows,\n GitPullRequestArrow,\n Globe,\n GraduationCap,\n Hammer,\n Hand,\n Handshake,\n Headphones,\n Heart,\n HelpCircle,\n Hourglass,\n Inbox,\n Key,\n KeyRound,\n Layers,\n Leaf,\n Lightbulb,\n LineChart,\n Link,\n List,\n ListX,\n Loader,\n Loader2,\n Lock,\n Mail,\n MailOpen,\n Map,\n MapPin,\n MapPinned,\n Megaphone,\n MessageCircle,\n MessageSquareReply,\n MinusCircle,\n Notebook,\n Package,\n PackageCheck,\n PackagePlus,\n PackageSearch,\n PackageX,\n PauseCircle,\n Percent,\n Phone,\n PhoneCall,\n PieChart,\n PlusSquare,\n Receipt,\n ReceiptText,\n RefreshCcw,\n RefreshCw,\n Repeat2,\n Reply,\n RotateCcw,\n Ruler,\n Send,\n Settings,\n Shapes,\n Share2,\n Shield,\n ShieldAlert,\n ShieldCheck,\n ShoppingBag,\n ShoppingCart,\n Shuffle,\n Sliders,\n Smartphone,\n Snowflake,\n Sparkles,\n Star,\n StickyNote,\n Store,\n Tag,\n Target,\n ThumbsUp,\n Ticket,\n Timer,\n Trash2,\n TrendingUp,\n TriangleAlert,\n Trophy,\n Truck,\n Undo,\n Undo2,\n Unlock,\n User,\n UserCheck,\n UserMinus,\n UserPlus,\n UserRound,\n Users,\n UserX,\n Wallet,\n Warehouse,\n Webhook,\n Workflow,\n Wrench,\n X,\n XCircle,\n ZapOff,\n} from 'lucide-react';\n\nexport const LUCIDE_ICON_REGISTRY: Record<string, LucideIcon> = {\n 'activity': Activity,\n 'alarm-clock': AlarmClock,\n 'alert-circle': AlertCircle,\n 'alert-octagon': AlertOctagon,\n 'alert-triangle': AlertTriangle,\n 'apple': Apple,\n 'archive': Archive,\n 'award': Award,\n 'badge-check': BadgeCheck,\n 'ban': Ban,\n 'banknote': Banknote,\n 'bar-chart-2': BarChart2,\n 'bar-chart-3': BarChart3,\n 'bell': Bell,\n 'bolt': Bolt,\n 'book': Book,\n 'bookmark': Bookmark,\n 'box': Box,\n 'boxes': Boxes,\n 'briefcase': Briefcase,\n 'briefcase-business': BriefcaseBusiness,\n 'building': Building,\n 'building2': Building2,\n 'calendar': Calendar,\n 'calendar-check': CalendarCheck,\n 'calendar-clock': CalendarClock,\n 'calendar-cog': CalendarCog,\n 'calendar-minus': CalendarMinus,\n 'calendar-off': CalendarOff,\n 'calendar-x': CalendarX,\n 'check': Check,\n 'check-circle': CheckCircle,\n 'check-circle-2': CheckCircle2,\n 'check-square': CheckSquare,\n 'circle': Circle,\n 'clipboard-check': ClipboardCheck,\n 'clipboard-list': ClipboardList,\n 'clock': Clock,\n 'clock-3': Clock3,\n 'coins': Coins,\n 'copy': Copy,\n 'copy-x': CopyX,\n 'credit-card': CreditCard,\n 'crown': Crown,\n 'database': Database,\n 'dollar-sign': DollarSign,\n 'download': Download,\n 'external-link': ExternalLink,\n 'eye': Eye,\n 'file-check': FileCheck,\n 'file-minus': FileMinus,\n 'file-pen-line': FilePenLine,\n 'file-spreadsheet': FileSpreadsheet,\n 'file-text': FileText,\n 'files': Files,\n 'filter-x': FilterX,\n 'flag': Flag,\n 'flame': Flame,\n 'folder-tree': FolderTree,\n 'gauge': Gauge,\n 'git-branch': GitBranch,\n 'git-compare-arrows': GitCompareArrows,\n 'git-pull-request-arrow': GitPullRequestArrow,\n 'globe': Globe,\n 'graduation-cap': GraduationCap,\n 'hammer': Hammer,\n 'hand': Hand,\n 'handshake': Handshake,\n 'headphones': Headphones,\n 'heart': Heart,\n 'help-circle': HelpCircle,\n 'hourglass': Hourglass,\n 'inbox': Inbox,\n 'key': Key,\n 'key-round': KeyRound,\n 'layers': Layers,\n 'leaf': Leaf,\n 'lightbulb': Lightbulb,\n 'line-chart': LineChart,\n 'link': Link,\n 'list': List,\n 'list-x': ListX,\n 'loader': Loader,\n 'loader-2': Loader2,\n 'lock': Lock,\n 'mail': Mail,\n 'mail-open': MailOpen,\n 'map': Map,\n 'map-pin': MapPin,\n 'map-pinned': MapPinned,\n 'megaphone': Megaphone,\n 'message-circle': MessageCircle,\n 'message-square-reply': MessageSquareReply,\n 'minus-circle': MinusCircle,\n 'notebook': Notebook,\n 'package': Package,\n 'package-check': PackageCheck,\n 'package-plus': PackagePlus,\n 'package-search': PackageSearch,\n 'package-x': PackageX,\n 'pause-circle': PauseCircle,\n 'percent': Percent,\n 'phone': Phone,\n 'phone-call': PhoneCall,\n 'pie-chart': PieChart,\n 'plus-square': PlusSquare,\n 'receipt': Receipt,\n 'receipt-text': ReceiptText,\n 'refresh-ccw': RefreshCcw,\n 'refresh-cw': RefreshCw,\n 'repeat-2': Repeat2,\n 'reply': Reply,\n 'rotate-ccw': RotateCcw,\n 'ruler': Ruler,\n 'send': Send,\n 'settings': Settings,\n 'shapes': Shapes,\n 'share-2': Share2,\n 'shield': Shield,\n 'shield-alert': ShieldAlert,\n 'shield-check': ShieldCheck,\n 'shopping-bag': ShoppingBag,\n 'shopping-cart': ShoppingCart,\n 'shuffle': Shuffle,\n 'sliders': Sliders,\n 'smartphone': Smartphone,\n 'snowflake': Snowflake,\n 'sparkles': Sparkles,\n 'star': Star,\n 'sticky-note': StickyNote,\n 'store': Store,\n 'tag': Tag,\n 'target': Target,\n 'thumbs-up': ThumbsUp,\n 'ticket': Ticket,\n 'timer': Timer,\n 'trash-2': Trash2,\n 'trending-up': TrendingUp,\n 'triangle-alert': TriangleAlert,\n 'trophy': Trophy,\n 'truck': Truck,\n 'undo': Undo,\n 'undo-2': Undo2,\n 'unlock': Unlock,\n 'user': User,\n 'user-check': UserCheck,\n 'user-minus': UserMinus,\n 'user-plus': UserPlus,\n 'user-round': UserRound,\n 'user-x': UserX,\n 'users': Users,\n 'wallet': Wallet,\n 'warehouse': Warehouse,\n 'webhook': Webhook,\n 'workflow': Workflow,\n 'wrench': Wrench,\n 'x': X,\n 'x-circle': XCircle,\n 'zap-off': ZapOff,\n};\n"],
|
|
5
|
-
"mappings": "AAKA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,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",
|
|
4
|
+
"sourcesContent": ["/* eslint-disable */\n// AUTO-GENERATED by @open-mercato/ui build. Do not edit by hand.\n// Generated from discovered icon string usages across the repo.\n\nimport type { LucideIcon } from 'lucide-react';\nimport {\n Activity,\n AlarmClock,\n AlertCircle,\n AlertOctagon,\n AlertTriangle,\n Apple,\n Archive,\n AtSign,\n Award,\n BadgeCheck,\n Ban,\n Banknote,\n BarChart2,\n BarChart3,\n Bell,\n Bolt,\n Book,\n Bookmark,\n Box,\n Boxes,\n Briefcase,\n BriefcaseBusiness,\n Building,\n Building2,\n Calendar,\n CalendarCheck,\n CalendarClock,\n CalendarCog,\n CalendarMinus,\n CalendarOff,\n CalendarX,\n Check,\n CheckCircle,\n CheckCircle2,\n CheckSquare,\n Circle,\n ClipboardCheck,\n ClipboardList,\n Clock,\n Clock3,\n Coins,\n Copy,\n CopyX,\n CreditCard,\n Crown,\n Database,\n DollarSign,\n Download,\n ExternalLink,\n Eye,\n FileCheck,\n FileMinus,\n FilePenLine,\n Files,\n FileSpreadsheet,\n FileText,\n FilterX,\n Flag,\n Flame,\n FolderTree,\n Gauge,\n GitBranch,\n GitCompareArrows,\n GitPullRequestArrow,\n Globe,\n GraduationCap,\n Hammer,\n Hand,\n Handshake,\n Headphones,\n Heart,\n HelpCircle,\n Hourglass,\n Inbox,\n Key,\n KeyRound,\n Layers,\n Leaf,\n Lightbulb,\n LineChart,\n Link,\n List,\n ListX,\n Loader,\n Loader2,\n Lock,\n Mail,\n MailOpen,\n Map,\n MapPin,\n MapPinned,\n Megaphone,\n MessageCircle,\n MessageSquareReply,\n MinusCircle,\n Notebook,\n Package,\n PackageCheck,\n PackagePlus,\n PackageSearch,\n PackageX,\n PauseCircle,\n Percent,\n Phone,\n PhoneCall,\n PieChart,\n PlusSquare,\n Receipt,\n ReceiptText,\n RefreshCcw,\n RefreshCw,\n Repeat2,\n Reply,\n RotateCcw,\n Ruler,\n Send,\n Settings,\n Shapes,\n Share2,\n Shield,\n ShieldAlert,\n ShieldCheck,\n ShoppingBag,\n ShoppingCart,\n Shuffle,\n Sliders,\n Smartphone,\n Snowflake,\n Sparkles,\n Star,\n StickyNote,\n Store,\n Tag,\n Target,\n ThumbsUp,\n Ticket,\n Timer,\n Trash2,\n TrendingUp,\n TriangleAlert,\n Trophy,\n Truck,\n Undo,\n Undo2,\n Unlock,\n User,\n UserCheck,\n UserMinus,\n UserPlus,\n UserRound,\n Users,\n UserX,\n Wallet,\n Warehouse,\n Webhook,\n Workflow,\n Wrench,\n X,\n XCircle,\n ZapOff,\n} from 'lucide-react';\n\nexport const LUCIDE_ICON_REGISTRY: Record<string, LucideIcon> = {\n 'activity': Activity,\n 'alarm-clock': AlarmClock,\n 'alert-circle': AlertCircle,\n 'alert-octagon': AlertOctagon,\n 'alert-triangle': AlertTriangle,\n 'apple': Apple,\n 'archive': Archive,\n 'at-sign': AtSign,\n 'award': Award,\n 'badge-check': BadgeCheck,\n 'ban': Ban,\n 'banknote': Banknote,\n 'bar-chart-2': BarChart2,\n 'bar-chart-3': BarChart3,\n 'bell': Bell,\n 'bolt': Bolt,\n 'book': Book,\n 'bookmark': Bookmark,\n 'box': Box,\n 'boxes': Boxes,\n 'briefcase': Briefcase,\n 'briefcase-business': BriefcaseBusiness,\n 'building': Building,\n 'building2': Building2,\n 'calendar': Calendar,\n 'calendar-check': CalendarCheck,\n 'calendar-clock': CalendarClock,\n 'calendar-cog': CalendarCog,\n 'calendar-minus': CalendarMinus,\n 'calendar-off': CalendarOff,\n 'calendar-x': CalendarX,\n 'check': Check,\n 'check-circle': CheckCircle,\n 'check-circle-2': CheckCircle2,\n 'check-square': CheckSquare,\n 'circle': Circle,\n 'clipboard-check': ClipboardCheck,\n 'clipboard-list': ClipboardList,\n 'clock': Clock,\n 'clock-3': Clock3,\n 'coins': Coins,\n 'copy': Copy,\n 'copy-x': CopyX,\n 'credit-card': CreditCard,\n 'crown': Crown,\n 'database': Database,\n 'dollar-sign': DollarSign,\n 'download': Download,\n 'external-link': ExternalLink,\n 'eye': Eye,\n 'file-check': FileCheck,\n 'file-minus': FileMinus,\n 'file-pen-line': FilePenLine,\n 'file-spreadsheet': FileSpreadsheet,\n 'file-text': FileText,\n 'files': Files,\n 'filter-x': FilterX,\n 'flag': Flag,\n 'flame': Flame,\n 'folder-tree': FolderTree,\n 'gauge': Gauge,\n 'git-branch': GitBranch,\n 'git-compare-arrows': GitCompareArrows,\n 'git-pull-request-arrow': GitPullRequestArrow,\n 'globe': Globe,\n 'graduation-cap': GraduationCap,\n 'hammer': Hammer,\n 'hand': Hand,\n 'handshake': Handshake,\n 'headphones': Headphones,\n 'heart': Heart,\n 'help-circle': HelpCircle,\n 'hourglass': Hourglass,\n 'inbox': Inbox,\n 'key': Key,\n 'key-round': KeyRound,\n 'layers': Layers,\n 'leaf': Leaf,\n 'lightbulb': Lightbulb,\n 'line-chart': LineChart,\n 'link': Link,\n 'list': List,\n 'list-x': ListX,\n 'loader': Loader,\n 'loader-2': Loader2,\n 'lock': Lock,\n 'mail': Mail,\n 'mail-open': MailOpen,\n 'map': Map,\n 'map-pin': MapPin,\n 'map-pinned': MapPinned,\n 'megaphone': Megaphone,\n 'message-circle': MessageCircle,\n 'message-square-reply': MessageSquareReply,\n 'minus-circle': MinusCircle,\n 'notebook': Notebook,\n 'package': Package,\n 'package-check': PackageCheck,\n 'package-plus': PackagePlus,\n 'package-search': PackageSearch,\n 'package-x': PackageX,\n 'pause-circle': PauseCircle,\n 'percent': Percent,\n 'phone': Phone,\n 'phone-call': PhoneCall,\n 'pie-chart': PieChart,\n 'plus-square': PlusSquare,\n 'receipt': Receipt,\n 'receipt-text': ReceiptText,\n 'refresh-ccw': RefreshCcw,\n 'refresh-cw': RefreshCw,\n 'repeat-2': Repeat2,\n 'reply': Reply,\n 'rotate-ccw': RotateCcw,\n 'ruler': Ruler,\n 'send': Send,\n 'settings': Settings,\n 'shapes': Shapes,\n 'share-2': Share2,\n 'shield': Shield,\n 'shield-alert': ShieldAlert,\n 'shield-check': ShieldCheck,\n 'shopping-bag': ShoppingBag,\n 'shopping-cart': ShoppingCart,\n 'shuffle': Shuffle,\n 'sliders': Sliders,\n 'smartphone': Smartphone,\n 'snowflake': Snowflake,\n 'sparkles': Sparkles,\n 'star': Star,\n 'sticky-note': StickyNote,\n 'store': Store,\n 'tag': Tag,\n 'target': Target,\n 'thumbs-up': ThumbsUp,\n 'ticket': Ticket,\n 'timer': Timer,\n 'trash-2': Trash2,\n 'trending-up': TrendingUp,\n 'triangle-alert': TriangleAlert,\n 'trophy': Trophy,\n 'truck': Truck,\n 'undo': Undo,\n 'undo-2': Undo2,\n 'unlock': Unlock,\n 'user': User,\n 'user-check': UserCheck,\n 'user-minus': UserMinus,\n 'user-plus': UserPlus,\n 'user-round': UserRound,\n 'user-x': UserX,\n 'users': Users,\n 'wallet': Wallet,\n 'warehouse': Warehouse,\n 'webhook': Webhook,\n 'workflow': Workflow,\n 'wrench': Wrench,\n 'x': X,\n 'x-circle': XCircle,\n 'zap-off': ZapOff,\n};\n"],
|
|
5
|
+
"mappings": "AAKA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -3,7 +3,26 @@ import { Slot } from "@radix-ui/react-slot";
|
|
|
3
3
|
import { cva } from "class-variance-authority";
|
|
4
4
|
import { cn } from "@open-mercato/shared/lib/utils";
|
|
5
5
|
const iconButtonVariants = cva(
|
|
6
|
-
|
|
6
|
+
// The pressed surface is repeated under `dark:` on purpose: the outline and
|
|
7
|
+
// ghost variants ship `dark:bg-input/30` / `dark:hover:bg-accent/50`, which
|
|
8
|
+
// otherwise outrank the un-prefixed `aria-pressed:` background while the
|
|
9
|
+
// `aria-pressed:text-primary-foreground` still applies — leaving a dark icon
|
|
10
|
+
// on a dark surface (invisible pressed star/bell buttons on the dark theme).
|
|
11
|
+
//
|
|
12
|
+
// Every pressed rule is additionally gated on `not-disabled:` because a toggle
|
|
13
|
+
// can be pressed AND disabled at the same time (an active editor tool while the
|
|
14
|
+
// document is read-only). Without the gate the pressed rules outrank the
|
|
15
|
+
// `disabled:` surface — `dark:aria-pressed:bg-primary` is more specific than
|
|
16
|
+
// `disabled:bg-bg-disabled` — and a control the user cannot operate renders
|
|
17
|
+
// as a primary, actionable button.
|
|
18
|
+
//
|
|
19
|
+
// The gate MUST stay `not-disabled:` (`&:not(:disabled)`) and not `enabled:`
|
|
20
|
+
// (`&:enabled`): the CSS `:enabled` pseudo-class only matches form elements,
|
|
21
|
+
// so on an `asChild` host — this primitive is routinely rendered onto a link —
|
|
22
|
+
// no pressed rule could ever match and the pressed state would not paint at
|
|
23
|
+
// all. `:not(:disabled)` gates the same way on a real `<button>` while leaving
|
|
24
|
+
// a non-form host styled.
|
|
25
|
+
"inline-flex items-center justify-center cursor-pointer transition-all outline-none disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled disabled:border-border-disabled disabled:shadow-none [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:outline-none focus-visible:shadow-focus not-disabled:aria-pressed:bg-primary not-disabled:aria-pressed:text-primary-foreground not-disabled:aria-pressed:hover:bg-primary-hover dark:not-disabled:aria-pressed:bg-primary dark:not-disabled:aria-pressed:hover:bg-primary-hover",
|
|
7
26
|
{
|
|
8
27
|
variants: {
|
|
9
28
|
variant: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/primitives/icon-button.tsx"],
|
|
4
|
-
"sourcesContent": ["import * as React from 'react'\nimport { Slot } from '@radix-ui/react-slot'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\nconst iconButtonVariants = cva(\n \"inline-flex items-center justify-center cursor-pointer transition-all outline-none disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled disabled:border-border-disabled disabled:shadow-none [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:outline-none focus-visible:shadow-focus aria-pressed:bg-primary aria-pressed:text-primary-foreground aria-pressed:hover:bg-primary-hover\",\n {\n variants: {\n variant: {\n primary:\n 'bg-primary text-primary-foreground shadow-xs hover:bg-primary-hover',\n destructive:\n 'bg-destructive text-white shadow-xs hover:bg-destructive/90',\n outline:\n 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',\n ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',\n white:\n 'bg-background text-muted-foreground shadow-xs hover:bg-accent hover:text-accent-foreground',\n modifiable:\n 'bg-transparent text-current hover:bg-foreground/10',\n },\n size: {\n xs: 'size-6',\n sm: 'size-7',\n default: 'size-8',\n lg: 'size-9',\n },\n fullRadius: {\n true: 'rounded-full',\n false: 'rounded-md',\n },\n },\n defaultVariants: {\n variant: 'outline',\n size: 'default',\n fullRadius: false,\n },\n }\n)\n\nexport function IconButton({\n className,\n variant,\n size,\n fullRadius,\n asChild = false,\n ...props\n}: React.ComponentProps<'button'> &\n VariantProps<typeof iconButtonVariants> & { asChild?: boolean }) {\n const Comp = asChild ? Slot : 'button'\n return (\n <Comp\n data-slot=\"icon-button\"\n type={asChild ? undefined : 'button'}\n className={cn(iconButtonVariants({ variant, size, fullRadius, className }))}\n {...props}\n />\n )\n}\n\nexport { iconButtonVariants }\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import * as React from 'react'\nimport { Slot } from '@radix-ui/react-slot'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@open-mercato/shared/lib/utils'\n\nconst iconButtonVariants = cva(\n // The pressed surface is repeated under `dark:` on purpose: the outline and\n // ghost variants ship `dark:bg-input/30` / `dark:hover:bg-accent/50`, which\n // otherwise outrank the un-prefixed `aria-pressed:` background while the\n // `aria-pressed:text-primary-foreground` still applies \u2014 leaving a dark icon\n // on a dark surface (invisible pressed star/bell buttons on the dark theme).\n //\n // Every pressed rule is additionally gated on `not-disabled:` because a toggle\n // can be pressed AND disabled at the same time (an active editor tool while the\n // document is read-only). Without the gate the pressed rules outrank the\n // `disabled:` surface \u2014 `dark:aria-pressed:bg-primary` is more specific than\n // `disabled:bg-bg-disabled` \u2014 and a control the user cannot operate renders\n // as a primary, actionable button.\n //\n // The gate MUST stay `not-disabled:` (`&:not(:disabled)`) and not `enabled:`\n // (`&:enabled`): the CSS `:enabled` pseudo-class only matches form elements,\n // so on an `asChild` host \u2014 this primitive is routinely rendered onto a link \u2014\n // no pressed rule could ever match and the pressed state would not paint at\n // all. `:not(:disabled)` gates the same way on a real `<button>` while leaving\n // a non-form host styled.\n \"inline-flex items-center justify-center cursor-pointer transition-all outline-none disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled disabled:border-border-disabled disabled:shadow-none [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:outline-none focus-visible:shadow-focus not-disabled:aria-pressed:bg-primary not-disabled:aria-pressed:text-primary-foreground not-disabled:aria-pressed:hover:bg-primary-hover dark:not-disabled:aria-pressed:bg-primary dark:not-disabled:aria-pressed:hover:bg-primary-hover\",\n {\n variants: {\n variant: {\n primary:\n 'bg-primary text-primary-foreground shadow-xs hover:bg-primary-hover',\n destructive:\n 'bg-destructive text-white shadow-xs hover:bg-destructive/90',\n outline:\n 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',\n ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',\n white:\n 'bg-background text-muted-foreground shadow-xs hover:bg-accent hover:text-accent-foreground',\n modifiable:\n 'bg-transparent text-current hover:bg-foreground/10',\n },\n size: {\n xs: 'size-6',\n sm: 'size-7',\n default: 'size-8',\n lg: 'size-9',\n },\n fullRadius: {\n true: 'rounded-full',\n false: 'rounded-md',\n },\n },\n defaultVariants: {\n variant: 'outline',\n size: 'default',\n fullRadius: false,\n },\n }\n)\n\nexport function IconButton({\n className,\n variant,\n size,\n fullRadius,\n asChild = false,\n ...props\n}: React.ComponentProps<'button'> &\n VariantProps<typeof iconButtonVariants> & { asChild?: boolean }) {\n const Comp = asChild ? Slot : 'button'\n return (\n <Comp\n data-slot=\"icon-button\"\n type={asChild ? undefined : 'button'}\n className={cn(iconButtonVariants({ variant, size, fullRadius, className }))}\n {...props}\n />\n )\n}\n\nexport { iconButtonVariants }\n"],
|
|
5
|
+
"mappings": "AAuEI;AAtEJ,SAAS,YAAY;AACrB,SAAS,WAA8B;AACvC,SAAS,UAAU;AAEnB,MAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBzB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SACE;AAAA,QACF,aACE;AAAA,QACF,SACE;AAAA,QACF,OAAO;AAAA,QACP,OACE;AAAA,QACF,YACE;AAAA,MACJ;AAAA,MACA,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,SAAS;AAAA,QACT,IAAI;AAAA,MACN;AAAA,MACA,YAAY;AAAA,QACV,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,MACN,YAAY;AAAA,IACd;AAAA,EACF;AACF;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,GAAG;AACL,GACmE;AACjE,QAAM,OAAO,UAAU,OAAO;AAC9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,MAAM,UAAU,SAAY;AAAA,MAC5B,WAAW,GAAG,mBAAmB,EAAE,SAAS,MAAM,YAAY,UAAU,CAAC,CAAC;AAAA,MACzE,GAAG;AAAA;AAAA,EACN;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/ui",
|
|
3
|
-
"version": "0.6.8-develop.
|
|
3
|
+
"version": "0.6.8-develop.7016.1.4ed7b1e49d",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -155,14 +155,14 @@
|
|
|
155
155
|
"remark-gfm": "^4.0.1"
|
|
156
156
|
},
|
|
157
157
|
"peerDependencies": {
|
|
158
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
158
|
+
"@open-mercato/shared": "0.6.8-develop.7016.1.4ed7b1e49d",
|
|
159
159
|
"react": ">=18.0.0",
|
|
160
160
|
"react-dom": ">=18.0.0",
|
|
161
161
|
"react-is": ">=18.0.0"
|
|
162
162
|
},
|
|
163
163
|
"devDependencies": {
|
|
164
164
|
"@figma/code-connect": "^1.3.4",
|
|
165
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
165
|
+
"@open-mercato/shared": "0.6.8-develop.7016.1.4ed7b1e49d",
|
|
166
166
|
"@testing-library/dom": "^10.4.1",
|
|
167
167
|
"@testing-library/jest-dom": "^7.0.0",
|
|
168
168
|
"@testing-library/react": "^16.3.1",
|
package/src/backend/AppShell.tsx
CHANGED
|
@@ -772,17 +772,9 @@ function AppShellBody({ productName, logo, email, canManageUpgradeActions = fals
|
|
|
772
772
|
setOpenGroups((prev) => (prev[key] === false ? { ...prev, [key]: true } : prev))
|
|
773
773
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
774
774
|
}, [pathname, navGroups])
|
|
775
|
-
//
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
setHeaderBreadcrumb(breadcrumb)
|
|
779
|
-
}, [currentTitle, breadcrumb])
|
|
780
|
-
// Clear breadcrumb on client-side navigation so stale state doesn't persist;
|
|
781
|
-
// the new page's ApplyBreadcrumb (if any) will set the correct values.
|
|
782
|
-
// Must be a layout effect: when a prefetched navigation commits the new
|
|
783
|
-
// pathname and the new page together, child passive effects (ApplyBreadcrumb)
|
|
784
|
-
// run before parent ones, so a passive clear here would wipe the value the
|
|
785
|
-
// incoming page just set.
|
|
775
|
+
// Reset stale header state before applying server props and before the new
|
|
776
|
+
// page's passive ApplyBreadcrumb effect. The ordering matters for layouts
|
|
777
|
+
// that persist across client-side navigation.
|
|
786
778
|
const prevPathname = React.useRef(pathname)
|
|
787
779
|
useIsomorphicLayoutEffect(() => {
|
|
788
780
|
if (pathname !== prevPathname.current) {
|
|
@@ -791,6 +783,12 @@ function AppShellBody({ productName, logo, email, canManageUpgradeActions = fals
|
|
|
791
783
|
setHeaderBreadcrumb(undefined)
|
|
792
784
|
}
|
|
793
785
|
}, [pathname])
|
|
786
|
+
// Keep header state in sync with props (server-side updates). A child page's
|
|
787
|
+
// ApplyBreadcrumb effect runs afterward and may refine this static trail.
|
|
788
|
+
useIsomorphicLayoutEffect(() => {
|
|
789
|
+
setHeaderTitle(currentTitle)
|
|
790
|
+
setHeaderBreadcrumb(breadcrumb)
|
|
791
|
+
}, [currentTitle, breadcrumb])
|
|
794
792
|
|
|
795
793
|
// Keep navGroups in sync when server-provided groups change
|
|
796
794
|
React.useEffect(() => {
|
|
@@ -3193,7 +3193,10 @@ export function DataTable<T extends RowData>({
|
|
|
3193
3193
|
const shouldRenderHeader = hasTitle || renderToolbarInline || shouldRenderActionsWrapper || shouldRenderToolbarBelow
|
|
3194
3194
|
const containerClassName = embedded ? '' : 'rounded-lg border bg-card mx-1 sm:mx-2'
|
|
3195
3195
|
const headerWrapperClassName = embedded ? 'pb-3' : 'px-4 py-3 border-b'
|
|
3196
|
-
|
|
3196
|
+
// The header row wraps once the actions no longer fit beside the title (the
|
|
3197
|
+
// title keeps a 12rem floor); before, the title collapsed to a sliver and
|
|
3198
|
+
// the wrapped action buttons rendered over it on narrow layouts.
|
|
3199
|
+
const headerContentClassName = 'flex flex-col gap-2 sm:flex-row sm:flex-wrap sm:items-center sm:justify-between'
|
|
3197
3200
|
const toolbarWrapperClassName = embedded ? 'mt-2' : 'mt-3 pt-3 border-t'
|
|
3198
3201
|
const tableScrollWrapperClassName = embedded ? '' : 'overflow-auto'
|
|
3199
3202
|
|
|
@@ -3249,11 +3252,11 @@ export function DataTable<T extends RowData>({
|
|
|
3249
3252
|
<div className={headerWrapperClassName}>
|
|
3250
3253
|
{(hasTitle || shouldRenderActionsWrapper || renderToolbarInline) && (
|
|
3251
3254
|
<div className={headerContentClassName}>
|
|
3252
|
-
<div className="flex-1 min-w-0">
|
|
3255
|
+
<div className="flex-1 min-w-0 sm:basis-48">
|
|
3253
3256
|
{renderToolbarInline ? builtToolbar : titleContent}
|
|
3254
3257
|
</div>
|
|
3255
3258
|
{shouldRenderActionsWrapper ? (
|
|
3256
|
-
<div className="flex flex-wrap items-center gap-2 min-h-[2.25rem]">
|
|
3259
|
+
<div className="flex flex-wrap items-center gap-2 min-h-[2.25rem] sm:ml-auto sm:justify-end">
|
|
3257
3260
|
{refreshButtonConfig ? (
|
|
3258
3261
|
<Button
|
|
3259
3262
|
type="button"
|
|
@@ -471,6 +471,52 @@ describe('AppShell', () => {
|
|
|
471
471
|
})
|
|
472
472
|
})
|
|
473
473
|
|
|
474
|
+
it('keeps the new page breadcrumb after client-side navigation', async () => {
|
|
475
|
+
mockPathname = '/backend/documents'
|
|
476
|
+
|
|
477
|
+
const { rerender } = renderWithProviders(
|
|
478
|
+
<AppShell
|
|
479
|
+
email="demo@example.com"
|
|
480
|
+
groups={groups}
|
|
481
|
+
currentTitle="Documents"
|
|
482
|
+
breadcrumb={[{ label: 'Documents' }]}
|
|
483
|
+
>
|
|
484
|
+
<ApplyBreadcrumb title="Documents" breadcrumb={[{ label: 'Documents' }]} />
|
|
485
|
+
<div>Documents list</div>
|
|
486
|
+
</AppShell>,
|
|
487
|
+
{ dict },
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
await waitFor(() => {
|
|
491
|
+
expect(within(screen.getByRole('navigation', { name: 'Breadcrumb' })).getByText('Documents')).toBeInTheDocument()
|
|
492
|
+
})
|
|
493
|
+
|
|
494
|
+
mockPathname = '/backend/documents/document-id'
|
|
495
|
+
rerender(
|
|
496
|
+
<AppShell
|
|
497
|
+
email="demo@example.com"
|
|
498
|
+
groups={groups}
|
|
499
|
+
currentTitle="Documents"
|
|
500
|
+
breadcrumb={[{ label: 'Documents' }]}
|
|
501
|
+
>
|
|
502
|
+
<ApplyBreadcrumb
|
|
503
|
+
title="Document"
|
|
504
|
+
breadcrumb={[
|
|
505
|
+
{ label: 'Documents', href: '/backend/documents' },
|
|
506
|
+
{ label: 'Document' },
|
|
507
|
+
]}
|
|
508
|
+
/>
|
|
509
|
+
<div>Document detail</div>
|
|
510
|
+
</AppShell>,
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
await waitFor(() => {
|
|
514
|
+
const breadcrumb = screen.getByRole('navigation', { name: 'Breadcrumb' })
|
|
515
|
+
expect(within(breadcrumb).getByRole('link', { name: 'Documents' })).toHaveAttribute('href', '/backend/documents')
|
|
516
|
+
expect(within(breadcrumb).getByText('Document')).toHaveAttribute('aria-current', 'page')
|
|
517
|
+
})
|
|
518
|
+
})
|
|
519
|
+
|
|
474
520
|
it('keeps settings parent item active on descendant routes outside explicit child list', async () => {
|
|
475
521
|
mockPathname = '/backend/entities/user/example%3Acalendar_entity'
|
|
476
522
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/** @jest-environment jsdom */
|
|
2
|
+
import * as React from 'react'
|
|
3
|
+
import { DataTable } from '../DataTable'
|
|
4
|
+
import type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'
|
|
5
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
6
|
+
import { I18nProvider } from '@open-mercato/shared/lib/i18n/context'
|
|
7
|
+
import { render } from '@testing-library/react'
|
|
8
|
+
|
|
9
|
+
jest.mock('next/navigation', () => ({
|
|
10
|
+
useRouter: () => ({ push: jest.fn(), replace: jest.fn(), prefetch: jest.fn() }),
|
|
11
|
+
}))
|
|
12
|
+
|
|
13
|
+
jest.mock('../injection/useInjectionDataWidgets', () => ({
|
|
14
|
+
useInjectionDataWidgets: () => ({ widgets: [], isLoading: false }),
|
|
15
|
+
}))
|
|
16
|
+
|
|
17
|
+
type Row = { id: string; title: string }
|
|
18
|
+
|
|
19
|
+
const tokensOf = (el: Element | null): string[] =>
|
|
20
|
+
(el?.getAttribute('class') ?? '').split(/\s+/).filter(Boolean)
|
|
21
|
+
|
|
22
|
+
// The header used to be a single non-wrapping `sm:flex-row` line. A title
|
|
23
|
+
// sitting next to a long action group (Create + Export + Refresh + injected
|
|
24
|
+
// toolbar buttons) had nothing but `min-w-0` holding it, so it collapsed to a
|
|
25
|
+
// sliver while the action buttons — which wrap on their own — spilled onto a
|
|
26
|
+
// second line and rendered over it. The row now wraps as a unit, the title
|
|
27
|
+
// keeps a 12rem floor, and the actions stay right-aligned in either layout.
|
|
28
|
+
describe('DataTable header row wrapping', () => {
|
|
29
|
+
function renderHeaderTable() {
|
|
30
|
+
const columns: ColumnDef<Row>[] = [{ accessorKey: 'title', header: 'Title' }]
|
|
31
|
+
const queryClient = new QueryClient({ defaultOptions: { queries: { gcTime: 0 } } })
|
|
32
|
+
const result = render(
|
|
33
|
+
<QueryClientProvider client={queryClient}>
|
|
34
|
+
<I18nProvider locale="en" dict={{}}>
|
|
35
|
+
<DataTable
|
|
36
|
+
title="Documents"
|
|
37
|
+
actions={<button type="button">Create document</button>}
|
|
38
|
+
columns={columns}
|
|
39
|
+
data={[{ id: '1', title: 'Solar rollout' }]}
|
|
40
|
+
/>
|
|
41
|
+
</I18nProvider>
|
|
42
|
+
</QueryClientProvider>,
|
|
43
|
+
)
|
|
44
|
+
return { ...result, queryClient }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function headerParts(container: HTMLElement) {
|
|
48
|
+
const headerContent = Array.from(container.querySelectorAll('div')).find((el) =>
|
|
49
|
+
tokensOf(el).includes('sm:flex-row'),
|
|
50
|
+
) ?? null
|
|
51
|
+
return {
|
|
52
|
+
headerContent,
|
|
53
|
+
titleSlot: headerContent?.firstElementChild ?? null,
|
|
54
|
+
actionsSlot: headerContent?.lastElementChild ?? null,
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
it('lets the header row wrap instead of crushing the title', () => {
|
|
59
|
+
const { container, queryClient } = renderHeaderTable()
|
|
60
|
+
try {
|
|
61
|
+
const { headerContent } = headerParts(container)
|
|
62
|
+
expect(headerContent).not.toBeNull()
|
|
63
|
+
expect(tokensOf(headerContent)).toEqual(
|
|
64
|
+
expect.arrayContaining([
|
|
65
|
+
'flex',
|
|
66
|
+
'flex-col',
|
|
67
|
+
'gap-2',
|
|
68
|
+
'sm:flex-row',
|
|
69
|
+
'sm:flex-wrap',
|
|
70
|
+
'sm:items-center',
|
|
71
|
+
'sm:justify-between',
|
|
72
|
+
]),
|
|
73
|
+
)
|
|
74
|
+
} finally {
|
|
75
|
+
queryClient.clear()
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('gives the title a wrap threshold instead of an unbounded shrink', () => {
|
|
80
|
+
const { container, queryClient } = renderHeaderTable()
|
|
81
|
+
try {
|
|
82
|
+
const { titleSlot } = headerParts(container)
|
|
83
|
+
expect(titleSlot?.textContent).toContain('Documents')
|
|
84
|
+
expect(tokensOf(titleSlot)).toEqual(
|
|
85
|
+
expect.arrayContaining(['flex-1', 'min-w-0', 'sm:basis-48']),
|
|
86
|
+
)
|
|
87
|
+
} finally {
|
|
88
|
+
queryClient.clear()
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('keeps the actions right-aligned once the row has wrapped', () => {
|
|
93
|
+
const { container, queryClient } = renderHeaderTable()
|
|
94
|
+
try {
|
|
95
|
+
const { actionsSlot } = headerParts(container)
|
|
96
|
+
expect(actionsSlot?.textContent).toContain('Create document')
|
|
97
|
+
expect(tokensOf(actionsSlot)).toEqual(
|
|
98
|
+
expect.arrayContaining([
|
|
99
|
+
'flex',
|
|
100
|
+
'flex-wrap',
|
|
101
|
+
'items-center',
|
|
102
|
+
'gap-2',
|
|
103
|
+
'sm:ml-auto',
|
|
104
|
+
'sm:justify-end',
|
|
105
|
+
]),
|
|
106
|
+
)
|
|
107
|
+
} finally {
|
|
108
|
+
queryClient.clear()
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
})
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
AlertTriangle,
|
|
12
12
|
Apple,
|
|
13
13
|
Archive,
|
|
14
|
+
AtSign,
|
|
14
15
|
Award,
|
|
15
16
|
BadgeCheck,
|
|
16
17
|
Ban,
|
|
@@ -173,6 +174,7 @@ export const LUCIDE_ICON_REGISTRY: Record<string, LucideIcon> = {
|
|
|
173
174
|
'alert-triangle': AlertTriangle,
|
|
174
175
|
'apple': Apple,
|
|
175
176
|
'archive': Archive,
|
|
177
|
+
'at-sign': AtSign,
|
|
176
178
|
'award': Award,
|
|
177
179
|
'badge-check': BadgeCheck,
|
|
178
180
|
'ban': Ban,
|
|
@@ -38,3 +38,73 @@ describe('IconButton solid variants', () => {
|
|
|
38
38
|
expect(className).not.toContain('dark:bg-input')
|
|
39
39
|
})
|
|
40
40
|
})
|
|
41
|
+
|
|
42
|
+
describe('IconButton pressed state', () => {
|
|
43
|
+
// The pressed surface must be restated under `dark:` for the same reason:
|
|
44
|
+
// `variant="outline"` (`dark:bg-input/30`) and `variant="ghost"`
|
|
45
|
+
// (`dark:hover:bg-accent/50`) otherwise outrank `aria-pressed:bg-primary`
|
|
46
|
+
// while `aria-pressed:text-primary-foreground` still applies, leaving a
|
|
47
|
+
// dark icon on a dark surface (invisible favorite/watch toggles).
|
|
48
|
+
it.each(['outline', 'ghost'] as const)('keeps the primary fill on a pressed %s button in dark mode', (variant) => {
|
|
49
|
+
const classes = iconButtonVariants({ variant })
|
|
50
|
+
expect(classes).toContain('not-disabled:aria-pressed:bg-primary')
|
|
51
|
+
expect(classes).toContain('dark:not-disabled:aria-pressed:bg-primary')
|
|
52
|
+
expect(classes).toContain('dark:not-disabled:aria-pressed:hover:bg-primary-hover')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
// A toggle can be pressed and disabled at once — an active editor tool on a
|
|
56
|
+
// read-only document. The pressed rules are more specific than the
|
|
57
|
+
// `disabled:` surface, so without a not-disabled gate the disabled control
|
|
58
|
+
// renders as a primary, actionable button in both themes.
|
|
59
|
+
it.each(['outline', 'ghost'] as const)(
|
|
60
|
+
'never lets the pressed surface outrank the disabled surface on a %s button',
|
|
61
|
+
(variant) => {
|
|
62
|
+
const classes = iconButtonVariants({ variant })
|
|
63
|
+
expect(classes).toContain('disabled:bg-bg-disabled')
|
|
64
|
+
expect(classes).toContain('disabled:text-text-disabled')
|
|
65
|
+
for (const pressed of classes.split(' ').filter((cls) => cls.includes('aria-pressed:'))) {
|
|
66
|
+
expect(pressed).toContain('not-disabled:aria-pressed:')
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
it('renders a pressed disabled toggle with only not-disabled-gated pressed rules', () => {
|
|
72
|
+
const { getByRole } = render(
|
|
73
|
+
<IconButton variant="outline" aria-label="Highlight" aria-pressed disabled>
|
|
74
|
+
<svg />
|
|
75
|
+
</IconButton>,
|
|
76
|
+
)
|
|
77
|
+
const classes = getByRole('button').className.split(' ')
|
|
78
|
+
expect(classes).toContain('disabled:bg-bg-disabled')
|
|
79
|
+
expect(classes).not.toContain('aria-pressed:bg-primary')
|
|
80
|
+
expect(classes).not.toContain('dark:aria-pressed:bg-primary')
|
|
81
|
+
expect(classes).toContain('not-disabled:aria-pressed:bg-primary')
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
// `enabled:` compiles to `&:enabled`, which the CSS spec restricts to form
|
|
85
|
+
// elements. `IconButton` supports `asChild` and is rendered onto links across
|
|
86
|
+
// the app (MessagesIcon, RoleAssignmentRow, DealsSection), so an `enabled:`
|
|
87
|
+
// gate would silently drop the pressed state on every one of those hosts.
|
|
88
|
+
// `not-disabled:` (`&:not(:disabled)`) matches a non-form host just fine.
|
|
89
|
+
it('keeps the pressed surface on an asChild anchor host', () => {
|
|
90
|
+
const { getByRole } = render(
|
|
91
|
+
<IconButton variant="ghost" asChild aria-pressed>
|
|
92
|
+
<a href="/inbox" aria-label="Messages">
|
|
93
|
+
<svg />
|
|
94
|
+
</a>
|
|
95
|
+
</IconButton>,
|
|
96
|
+
)
|
|
97
|
+
const anchor = getByRole('link')
|
|
98
|
+
const classes = anchor.className.split(' ')
|
|
99
|
+
expect(anchor.tagName).toBe('A')
|
|
100
|
+
expect(classes).toContain('not-disabled:aria-pressed:bg-primary')
|
|
101
|
+
expect(classes).toContain('not-disabled:aria-pressed:text-primary-foreground')
|
|
102
|
+
expect(classes).toContain('dark:not-disabled:aria-pressed:bg-primary')
|
|
103
|
+
// The whole point of the fix: no pressed rule may be gated on `:enabled`,
|
|
104
|
+
// which can never match an anchor.
|
|
105
|
+
for (const pressed of classes.filter((cls) => cls.includes('aria-pressed:'))) {
|
|
106
|
+
expect(pressed).not.toContain('enabled:aria-pressed:')
|
|
107
|
+
expect(pressed).toContain('not-disabled:aria-pressed:')
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
})
|
|
@@ -4,7 +4,26 @@ import { cva, type VariantProps } from 'class-variance-authority'
|
|
|
4
4
|
import { cn } from '@open-mercato/shared/lib/utils'
|
|
5
5
|
|
|
6
6
|
const iconButtonVariants = cva(
|
|
7
|
-
|
|
7
|
+
// The pressed surface is repeated under `dark:` on purpose: the outline and
|
|
8
|
+
// ghost variants ship `dark:bg-input/30` / `dark:hover:bg-accent/50`, which
|
|
9
|
+
// otherwise outrank the un-prefixed `aria-pressed:` background while the
|
|
10
|
+
// `aria-pressed:text-primary-foreground` still applies — leaving a dark icon
|
|
11
|
+
// on a dark surface (invisible pressed star/bell buttons on the dark theme).
|
|
12
|
+
//
|
|
13
|
+
// Every pressed rule is additionally gated on `not-disabled:` because a toggle
|
|
14
|
+
// can be pressed AND disabled at the same time (an active editor tool while the
|
|
15
|
+
// document is read-only). Without the gate the pressed rules outrank the
|
|
16
|
+
// `disabled:` surface — `dark:aria-pressed:bg-primary` is more specific than
|
|
17
|
+
// `disabled:bg-bg-disabled` — and a control the user cannot operate renders
|
|
18
|
+
// as a primary, actionable button.
|
|
19
|
+
//
|
|
20
|
+
// The gate MUST stay `not-disabled:` (`&:not(:disabled)`) and not `enabled:`
|
|
21
|
+
// (`&:enabled`): the CSS `:enabled` pseudo-class only matches form elements,
|
|
22
|
+
// so on an `asChild` host — this primitive is routinely rendered onto a link —
|
|
23
|
+
// no pressed rule could ever match and the pressed state would not paint at
|
|
24
|
+
// all. `:not(:disabled)` gates the same way on a real `<button>` while leaving
|
|
25
|
+
// a non-form host styled.
|
|
26
|
+
"inline-flex items-center justify-center cursor-pointer transition-all outline-none disabled:pointer-events-none disabled:bg-bg-disabled disabled:text-text-disabled disabled:border-border-disabled disabled:shadow-none [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:outline-none focus-visible:shadow-focus not-disabled:aria-pressed:bg-primary not-disabled:aria-pressed:text-primary-foreground not-disabled:aria-pressed:hover:bg-primary-hover dark:not-disabled:aria-pressed:bg-primary dark:not-disabled:aria-pressed:hover:bg-primary-hover",
|
|
8
27
|
{
|
|
9
28
|
variants: {
|
|
10
29
|
variant: {
|