@motor-hero/ui-kit 0.39.0 → 0.42.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/components/date-picker.d.ts +4 -2
- package/dist/components/date-picker.d.ts.map +1 -1
- package/dist/components/row-actions-menu.d.ts +1 -0
- package/dist/components/row-actions-menu.d.ts.map +1 -1
- package/dist/index.cjs +73 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +74 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/date-picker.tsx +8 -5
- package/src/components/row-actions-menu.tsx +70 -1
package/package.json
CHANGED
|
@@ -16,10 +16,13 @@ const MASK_REPLACEMENT = { _: /\d/ }
|
|
|
16
16
|
const DATE_FORMAT = "dd/MM/yyyy"
|
|
17
17
|
const TIME_FORMAT = "HH:mm"
|
|
18
18
|
const DATE_VALUE_FORMAT = "yyyy-MM-dd"
|
|
19
|
+
const DATETIME_VALUE_FORMAT = "yyyy-MM-dd'T'HH:mm"
|
|
19
20
|
|
|
20
21
|
export interface DatePickerProps {
|
|
21
|
-
/** `DatePicker`: data pura `"yyyy-MM-dd"
|
|
22
|
-
*
|
|
22
|
+
/** `DatePicker`: data pura `"yyyy-MM-dd"`. `DateTimePicker`: hora de parede
|
|
23
|
+
* `"yyyy-MM-ddTHH:mm"` — os dígitos digitados, tal qual. Nenhum dos dois
|
|
24
|
+
* passa por conversão de fuso: o significado (Brasília, local, UTC) é
|
|
25
|
+
* decisão do consumidor. `""`/`undefined` = sem valor. */
|
|
23
26
|
value?: string
|
|
24
27
|
onChange: (value: string) => void
|
|
25
28
|
placeholder?: string
|
|
@@ -60,8 +63,8 @@ function dateOnlyToDate(value: string | undefined): Date | undefined {
|
|
|
60
63
|
|
|
61
64
|
function dateTimeToDate(value: string | undefined): Date | undefined {
|
|
62
65
|
if (!value) return undefined
|
|
63
|
-
const parsed = new Date(
|
|
64
|
-
return
|
|
66
|
+
const parsed = parse(value, DATETIME_VALUE_FORMAT, new Date())
|
|
67
|
+
return isValid(parsed) ? parsed : undefined
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
function displayFor(value: string | undefined, withTime: boolean): string {
|
|
@@ -196,7 +199,7 @@ function DatePickerImpl({
|
|
|
196
199
|
if (!time) return
|
|
197
200
|
const combined = new Date(date)
|
|
198
201
|
combined.setHours(time.getHours(), time.getMinutes(), 0, 0)
|
|
199
|
-
onChange(combined
|
|
202
|
+
onChange(format(combined, DATETIME_VALUE_FORMAT))
|
|
200
203
|
setOpen(false)
|
|
201
204
|
}
|
|
202
205
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as DropdownMenu from "@radix-ui/react-dropdown-menu"
|
|
2
|
-
import { MoreVertical } from "lucide-react"
|
|
2
|
+
import { ChevronRight, MoreVertical } from "lucide-react"
|
|
3
3
|
import { type ReactNode, useState } from "react"
|
|
4
4
|
import { Drawer as DrawerPrimitive } from "vaul"
|
|
5
5
|
import { useIsDesktop } from "../hooks/use-is-desktop"
|
|
@@ -14,6 +14,9 @@ export interface RowAction {
|
|
|
14
14
|
href?: string
|
|
15
15
|
destructive?: boolean
|
|
16
16
|
disabled?: boolean
|
|
17
|
+
// Submenu de um nível: com `children`, `onClick`/`href` são ignorados.
|
|
18
|
+
// Desktop: Radix Sub; mobile: grupo inline no action sheet.
|
|
19
|
+
children?: RowAction[]
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
export interface RowActionsMenuProps {
|
|
@@ -72,6 +75,42 @@ export function RowActionsMenu({
|
|
|
72
75
|
action.destructive &&
|
|
73
76
|
"text-destructive focus:bg-destructive/10",
|
|
74
77
|
)
|
|
78
|
+
if (action.children?.length) {
|
|
79
|
+
return (
|
|
80
|
+
<DropdownMenu.Sub key={action.label}>
|
|
81
|
+
<DropdownMenu.SubTrigger
|
|
82
|
+
className={cls}
|
|
83
|
+
disabled={action.disabled}
|
|
84
|
+
>
|
|
85
|
+
{action.icon}
|
|
86
|
+
{action.label}
|
|
87
|
+
<ChevronRight className="ml-auto h-4 w-4 text-muted-foreground" />
|
|
88
|
+
</DropdownMenu.SubTrigger>
|
|
89
|
+
<DropdownMenu.Portal>
|
|
90
|
+
<DropdownMenu.SubContent
|
|
91
|
+
sideOffset={4}
|
|
92
|
+
className="z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95"
|
|
93
|
+
>
|
|
94
|
+
{action.children.map((child) => (
|
|
95
|
+
<DropdownMenu.Item
|
|
96
|
+
key={child.label}
|
|
97
|
+
className={cn(
|
|
98
|
+
itemClass,
|
|
99
|
+
child.destructive &&
|
|
100
|
+
"text-destructive focus:bg-destructive/10",
|
|
101
|
+
)}
|
|
102
|
+
disabled={child.disabled}
|
|
103
|
+
onClick={child.onClick}
|
|
104
|
+
>
|
|
105
|
+
{child.icon}
|
|
106
|
+
{child.label}
|
|
107
|
+
</DropdownMenu.Item>
|
|
108
|
+
))}
|
|
109
|
+
</DropdownMenu.SubContent>
|
|
110
|
+
</DropdownMenu.Portal>
|
|
111
|
+
</DropdownMenu.Sub>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
75
114
|
return action.href ? (
|
|
76
115
|
<DropdownMenu.Item
|
|
77
116
|
key={action.label}
|
|
@@ -129,6 +168,36 @@ export function RowActionsMenu({
|
|
|
129
168
|
{action.label}
|
|
130
169
|
</>
|
|
131
170
|
)
|
|
171
|
+
if (action.children?.length) {
|
|
172
|
+
return (
|
|
173
|
+
<div key={action.label}>
|
|
174
|
+
<div className="mx-3 my-1 h-px bg-border" />
|
|
175
|
+
<div className="flex items-center gap-3 px-3 pb-1 pt-2 text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
|
176
|
+
{action.icon}
|
|
177
|
+
{action.label}
|
|
178
|
+
</div>
|
|
179
|
+
{action.children.map((child) => (
|
|
180
|
+
<button
|
|
181
|
+
key={child.label}
|
|
182
|
+
type="button"
|
|
183
|
+
disabled={child.disabled}
|
|
184
|
+
className={cn(
|
|
185
|
+
sheetItemClass,
|
|
186
|
+
child.destructive && "text-destructive",
|
|
187
|
+
)}
|
|
188
|
+
onClick={() => {
|
|
189
|
+
child.onClick?.()
|
|
190
|
+
setOpen(false)
|
|
191
|
+
}}
|
|
192
|
+
>
|
|
193
|
+
{child.icon}
|
|
194
|
+
{child.label}
|
|
195
|
+
</button>
|
|
196
|
+
))}
|
|
197
|
+
<div className="mx-3 my-1 h-px bg-border" />
|
|
198
|
+
</div>
|
|
199
|
+
)
|
|
200
|
+
}
|
|
132
201
|
return action.href ? (
|
|
133
202
|
<span
|
|
134
203
|
key={action.label}
|