azamat-ui-kit-cli 0.3.13 → 0.3.15

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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/dist/index.cjs +807 -107
  3. package/package.json +1 -1
  4. package/vendor/src/components/data-table/data-table-pagination.tsx +1 -1
  5. package/vendor/src/components/data-table/data-table-toolbar.tsx +13 -12
  6. package/vendor/src/components/data-table/data-table.tsx +14 -14
  7. package/vendor/src/components/display/smart-card.tsx +17 -14
  8. package/vendor/src/components/form/form-input.tsx +3 -1
  9. package/vendor/src/components/form/form-textarea.tsx +15 -12
  10. package/vendor/src/components/inputs/async-select.tsx +106 -47
  11. package/vendor/src/components/inputs/clearable-input.tsx +1 -0
  12. package/vendor/src/components/inputs/input-chrome.tsx +1 -1
  13. package/vendor/src/components/inputs/input-decorator.tsx +16 -8
  14. package/vendor/src/components/inputs/simple-select.tsx +28 -28
  15. package/vendor/src/components/layout/app-sidebar.tsx +454 -154
  16. package/vendor/src/components/layout/breadcrumbs.tsx +67 -22
  17. package/vendor/src/components/layout/sidebar-nav.tsx +316 -128
  18. package/vendor/src/components/overlay/confirm-dialog.tsx +31 -20
  19. package/vendor/src/components/patterns/form-builder-presets.ts +13 -131
  20. package/vendor/src/components/patterns/form-builder.tsx +118 -9
  21. package/vendor/src/components/patterns/index.ts +3 -4
  22. package/vendor/src/components/patterns/public.ts +0 -1
  23. package/vendor/src/components/ui/badge.tsx +33 -32
  24. package/vendor/src/components/ui/button.tsx +15 -17
  25. package/vendor/src/components/ui/card.tsx +26 -25
  26. package/vendor/src/components/ui/dialog.tsx +6 -3
  27. package/vendor/src/components/ui/dropdown-menu.tsx +9 -9
  28. package/vendor/src/components/ui/input-primitive.tsx +1 -1
  29. package/vendor/src/components/ui/input.tsx +105 -2
  30. package/vendor/src/components/ui/popover.tsx +1 -1
  31. package/vendor/src/components/ui/select.tsx +3 -3
  32. package/vendor/src/components/ui/table.tsx +4 -4
  33. package/vendor/src/components/ui/tabs.tsx +2 -2
  34. package/vendor/src/families/form-family.ts +0 -2
  35. package/vendor/src/families/member-metadata.ts +3 -3
  36. package/vendor/src/families/member-snippets.ts +3 -3
  37. package/vendor/templates/styles/globals.css +706 -6
@@ -1,6 +1,7 @@
1
1
  import * as React from "react"
2
2
 
3
3
  import { InputPrimitive, type InputPrimitiveProps } from "@/components/ui/input-primitive"
4
+ import { InputDecorator } from "@/components/inputs/input-decorator"
4
5
  import { ClearableInput, type ClearableInputProps } from "@/components/inputs/clearable-input"
5
6
  import { DateInput, type DateInputProps } from "@/components/inputs/date-input"
6
7
  import { DateRangeInput, type DateRangeInputProps } from "@/components/inputs/date-range-input"
@@ -11,6 +12,7 @@ import { PasswordInput, type PasswordInputProps } from "@/components/inputs/pass
11
12
  import { PhoneInput, type PhoneInputProps } from "@/components/inputs/phone-input"
12
13
  import { QuantityInput, type QuantityInputProps } from "@/components/inputs/quantity-input"
13
14
  import { SearchInput, type SearchInputProps } from "@/components/inputs/search-input"
15
+ import { cn } from "@/lib/utils"
14
16
 
15
17
  export type InputKind =
16
18
  | "text"
@@ -28,6 +30,17 @@ export type InputKind =
28
30
  export type InputTextProps = Omit<InputPrimitiveProps, "value"> & {
29
31
  kind?: "text"
30
32
  value?: string | number | readonly string[] | null
33
+ leading?: React.ReactNode
34
+ trailing?: React.ReactNode
35
+ helperText?: React.ReactNode
36
+ errorText?: React.ReactNode
37
+ showCharacterCount?: boolean
38
+ countFormatter?: (currentLength: number, maxLength?: number) => React.ReactNode
39
+ wrapperClassName?: string
40
+ inputClassName?: string
41
+ helperClassName?: string
42
+ leadingPointerEvents?: boolean
43
+ trailingPointerEvents?: boolean
31
44
  }
32
45
 
33
46
  export type InputClearableProps = Omit<ClearableInputProps, "kind"> & {
@@ -85,6 +98,13 @@ export type InputProps =
85
98
  | InputDateProps
86
99
  | InputDateRangeProps
87
100
 
101
+ function getInputTextLength(value: InputTextProps["value"] | InputTextProps["defaultValue"]) {
102
+ if (typeof value === "string") return value.length
103
+ if (typeof value === "number") return String(value).length
104
+ if (Array.isArray(value)) return value.join("").length
105
+ return 0
106
+ }
107
+
88
108
  const Input = React.forwardRef<HTMLInputElement | HTMLDivElement, InputProps>((props, ref) => {
89
109
  const kind = props.kind ?? "text"
90
110
 
@@ -174,17 +194,100 @@ const Input = React.forwardRef<HTMLInputElement | HTMLDivElement, InputProps>((p
174
194
  }
175
195
 
176
196
  const inputProps = props as Omit<InputTextProps, "kind">
177
- const { value, defaultValue, ...restInputProps } = inputProps
197
+ const {
198
+ value,
199
+ defaultValue,
200
+ leading,
201
+ trailing,
202
+ helperText,
203
+ errorText,
204
+ showCharacterCount = false,
205
+ countFormatter,
206
+ wrapperClassName,
207
+ inputClassName,
208
+ helperClassName,
209
+ leadingPointerEvents = false,
210
+ trailingPointerEvents = true,
211
+ onChange,
212
+ maxLength,
213
+ className,
214
+ ...restInputProps
215
+ } = inputProps
216
+ const isControlled = value !== undefined
217
+ const [uncontrolledLength, setUncontrolledLength] = React.useState(() => getInputTextLength(defaultValue))
218
+ const currentLength = isControlled ? getInputTextLength(value) : uncontrolledLength
219
+ const helperMessage = errorText ?? helperText
220
+ const helperTone = errorText ? "text-destructive" : "text-muted-foreground"
178
221
 
179
- return (
222
+ const handleChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
223
+ if (!isControlled) {
224
+ setUncontrolledLength(event.target.value.length)
225
+ }
226
+ onChange?.(event)
227
+ }
228
+
229
+ const textInput = leading || trailing ? (
230
+ <InputDecorator
231
+ ref={ref as React.ForwardedRef<HTMLInputElement>}
232
+ value={value ?? undefined}
233
+ defaultValue={value === undefined ? defaultValue : undefined}
234
+ type={restInputProps.type ?? "text"}
235
+ leading={leading}
236
+ trailing={trailing}
237
+ leadingPointerEvents={leadingPointerEvents}
238
+ trailingPointerEvents={trailingPointerEvents}
239
+ wrapperClassName={wrapperClassName}
240
+ inputClassName={inputClassName}
241
+ className={className}
242
+ onChange={handleChange}
243
+ maxLength={maxLength}
244
+ {...(restInputProps as React.ComponentProps<typeof InputDecorator>)}
245
+ />
246
+ ) : (
180
247
  <InputPrimitive
181
248
  ref={ref as React.ForwardedRef<HTMLInputElement>}
182
249
  value={value ?? undefined}
183
250
  defaultValue={value === undefined ? defaultValue : undefined}
184
251
  type={restInputProps.type ?? "text"}
252
+ className={cn(inputClassName, className)}
253
+ onChange={handleChange}
254
+ maxLength={maxLength}
185
255
  {...(restInputProps as React.ComponentProps<typeof InputPrimitive>)}
186
256
  />
187
257
  )
258
+
259
+ if (!helperMessage && !showCharacterCount) {
260
+ return textInput
261
+ }
262
+
263
+ return (
264
+ <div data-slot="input-field" className="grid gap-1.5">
265
+ {textInput}
266
+ <div
267
+ data-slot="input-meta"
268
+ className="flex items-start justify-between gap-3 px-1"
269
+ >
270
+ <div
271
+ data-slot="input-helper"
272
+ className={cn("min-w-0 text-xs leading-5", helperTone, helperClassName)}
273
+ >
274
+ {helperMessage}
275
+ </div>
276
+ {showCharacterCount ? (
277
+ <div
278
+ data-slot="input-count"
279
+ className={cn(
280
+ "shrink-0 text-[11px] font-medium tabular-nums",
281
+ errorText ? "text-destructive" : "text-muted-foreground"
282
+ )}
283
+ >
284
+ {countFormatter?.(currentLength, maxLength) ??
285
+ (typeof maxLength === "number" ? `${currentLength}/${maxLength}` : currentLength)}
286
+ </div>
287
+ ) : null}
288
+ </div>
289
+ </div>
290
+ )
188
291
  })
189
292
  Input.displayName = "Input"
190
293
 
@@ -37,7 +37,7 @@ function PopoverContent({
37
37
  <PopoverPrimitive.Popup
38
38
  data-slot="popover-content"
39
39
  className={cn(
40
- "z-50 flex w-80 origin-(--transform-origin) flex-col gap-3 rounded-[var(--radius-2xl)] border border-border/70 bg-[linear-gradient(180deg,color-mix(in_oklch,var(--popover),white_8%),var(--popover))] p-4 text-sm text-popover-foreground shadow-[0_18px_54px_color-mix(in_oklch,var(--foreground),transparent_88%)] ring-1 ring-foreground/6 backdrop-blur outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
40
+ "z-50 flex w-80 origin-(--transform-origin) flex-col gap-3 rounded-[var(--radius-2xl)] border p-4 text-sm text-popover-foreground outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
41
41
  className
42
42
  )}
43
43
  {...props}
@@ -41,7 +41,7 @@ function SelectTrigger({
41
41
  data-slot="select-trigger"
42
42
  data-size={size}
43
43
  className={cn(
44
- "flex w-fit items-center justify-between gap-2 rounded-[min(var(--radius-xl),16px)] border border-input/88 bg-background py-2 pr-3 pl-3 text-sm whitespace-nowrap text-foreground shadow-[inset_0_1px_0_rgba(255,255,255,0.10)] transition-[background-color,border-color,box-shadow,color] outline-none select-none hover:border-ring/30 hover:bg-background focus-visible:border-ring focus-visible:bg-background focus-visible:shadow-[0_0_0_1px_color-mix(in_oklch,var(--ring),transparent_45%),0_10px_24px_rgba(15,23,42,0.08)] focus-visible:ring-3 focus-visible:ring-ring/45 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-10 data-[size=sm]:h-9 data-[size=sm]:rounded-[min(var(--radius-lg),12px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:border-white/12 dark:bg-white/[0.04] dark:hover:bg-white/[0.08] dark:focus-visible:bg-white/[0.08] dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
44
+ "flex w-fit items-center justify-between gap-2 rounded-[min(var(--radius-xl),16px)] border py-2 pr-3 pl-3 text-sm whitespace-nowrap text-foreground transition-[background-color,border-color,box-shadow,color] outline-none select-none focus-visible:ring-0 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive data-placeholder:text-muted-foreground data-[size=default]:h-10 data-[size=sm]:h-9 data-[size=sm]:rounded-[min(var(--radius-lg),12px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
45
45
  className
46
46
  )}
47
47
  {...props}
@@ -83,7 +83,7 @@ function SelectContent({
83
83
  <SelectPrimitive.Popup
84
84
  data-slot="select-content"
85
85
  data-align-trigger={alignItemWithTrigger}
86
- className={cn("relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-44 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-[var(--radius-2xl)] border border-border/76 bg-popover p-1.5 text-popover-foreground shadow-[0_18px_48px_rgba(15,23,42,0.14)] ring-1 ring-foreground/6 backdrop-blur duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className)}
86
+ className={cn("relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-44 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-[var(--radius-2xl)] border p-1.5 text-popover-foreground backdrop-blur duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className)}
87
87
  {...props}
88
88
  >
89
89
  <SelectScrollUpButton />
@@ -117,7 +117,7 @@ function SelectItem({
117
117
  <SelectPrimitive.Item
118
118
  data-slot="select-item"
119
119
  className={cn(
120
- "relative flex w-full cursor-default items-center gap-1.5 rounded-[min(var(--radius-xl),16px)] border border-transparent py-2.5 pr-9 pl-3 text-sm outline-hidden select-none transition-[background-color,border-color,color,box-shadow,transform] focus:border-border/80 focus:bg-accent/76 focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-[selected]:border-primary/16 data-[selected]:bg-primary/8 data-[selected]:text-foreground data-[selected]:shadow-none data-disabled:pointer-events-none data-disabled:opacity-50 dark:data-[selected]:border-white/8 dark:data-[selected]:bg-white/6 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
120
+ "relative flex w-full cursor-default items-center gap-1.5 rounded-[min(var(--radius-xl),16px)] border border-transparent py-2.5 pr-9 pl-3 text-sm outline-hidden select-none transition-[background-color,border-color,color,box-shadow,transform] data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
121
121
  className
122
122
  )}
123
123
  {...props}
@@ -11,7 +11,7 @@ function Table({ className, containerClassName, ...props }: TableProps) {
11
11
  <div
12
12
  data-slot="table-container"
13
13
  className={cn(
14
- "relative w-full overflow-x-auto rounded-[var(--radius-2xl)] border border-border/75 bg-[linear-gradient(180deg,color-mix(in_oklch,var(--card),white_12%),var(--card))] shadow-sm ring-1 ring-foreground/5",
14
+ "relative w-full overflow-x-auto rounded-[var(--radius-2xl)] border",
15
15
  containerClassName
16
16
  )}
17
17
  >
@@ -28,7 +28,7 @@ function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
28
28
  return (
29
29
  <thead
30
30
  data-slot="table-header"
31
- className={cn("bg-muted/30 [&_tr]:border-b", className)}
31
+ className={cn("[&_tr]:border-b", className)}
32
32
  {...props}
33
33
  />
34
34
  )
@@ -49,7 +49,7 @@ function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
49
49
  <tfoot
50
50
  data-slot="table-footer"
51
51
  className={cn(
52
- "border-t bg-muted/58 font-medium [&>tr]:last:border-b-0",
52
+ "border-t font-medium [&>tr]:last:border-b-0",
53
53
  className
54
54
  )}
55
55
  {...props}
@@ -62,7 +62,7 @@ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
62
62
  <tr
63
63
  data-slot="table-row"
64
64
  className={cn(
65
- "border-b border-border/70 transition-colors hover:bg-muted/28 has-aria-expanded:bg-muted/36 data-[state=selected]:bg-primary/8",
65
+ "border-b transition-colors",
66
66
  className
67
67
  )}
68
68
  {...props}
@@ -13,7 +13,7 @@ const TabsList = React.forwardRef<
13
13
  ref={ref}
14
14
  data-slot="tabs-list"
15
15
  className={cn(
16
- "inline-flex min-h-11 items-center justify-center gap-1 rounded-[var(--radius-2xl)] border border-border/72 bg-muted/34 p-1 text-muted-foreground shadow-[inset_0_1px_0_rgba(255,255,255,0.04),0_8px_24px_rgba(15,23,42,0.04)] backdrop-blur",
16
+ "inline-flex min-h-11 items-center justify-center gap-1 rounded-[var(--radius-2xl)] border p-1 text-muted-foreground backdrop-blur",
17
17
  className
18
18
  )}
19
19
  {...props}
@@ -29,7 +29,7 @@ const TabsTrigger = React.forwardRef<
29
29
  ref={ref}
30
30
  data-slot="tabs-trigger"
31
31
  className={cn(
32
- "inline-flex min-h-9 items-center justify-center whitespace-nowrap rounded-[calc(var(--radius-xl)-2px)] border border-transparent px-3.5 py-1.5 text-sm font-medium text-muted-foreground ring-offset-background transition-[background-color,color,box-shadow,border-color] hover:bg-background/52 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[selected]:border-border/72 data-[selected]:bg-background data-[selected]:text-foreground data-[selected]:shadow-[0_1px_0_rgba(255,255,255,0.18),0_8px_20px_rgba(15,23,42,0.06)] dark:data-[selected]:border-white/10 dark:data-[selected]:bg-white/7 dark:data-[selected]:shadow-[0_1px_0_rgba(255,255,255,0.06),0_10px_24px_rgba(0,0,0,0.18)]",
32
+ "inline-flex min-h-9 items-center justify-center whitespace-nowrap rounded-[calc(var(--radius-xl)-2px)] border border-transparent px-3.5 py-1.5 text-sm font-medium ring-offset-background transition-[background-color,color,box-shadow,border-color] focus-visible:outline-none focus-visible:ring-0 disabled:pointer-events-none disabled:opacity-50",
33
33
  className
34
34
  )}
35
35
  {...props}
@@ -18,7 +18,6 @@ import {
18
18
  SmartFormShell,
19
19
  } from "@/components/form"
20
20
  import { FormBuilder } from "@/components/patterns/form-builder"
21
- import * as FormBuilderPresets from "@/components/patterns/form-builder-presets"
22
21
 
23
22
  const FormFamily = {
24
23
  Field: FormFieldShell,
@@ -39,7 +38,6 @@ const FormFamily = {
39
38
  DatePicker: FormDatePicker,
40
39
  DateRangePicker: FormDateRangePicker,
41
40
  Builder: FormBuilder,
42
- Presets: FormBuilderPresets,
43
41
  } as const
44
42
 
45
43
  export { FormFamily }
@@ -242,7 +242,7 @@ export const componentMemberMetadata: ComponentMemberMetadata[] = [
242
242
  section: "presets",
243
243
  maturity: "member",
244
244
  summary: "Remote-search single select.",
245
- useWhen: "Use when options are loaded on demand from a server or large local source.",
245
+ useWhen: "Use when options are loaded on demand from a server or large local source, including cases where search and creation should stay in one remote-aware flow.",
246
246
  },
247
247
  {
248
248
  component: "AsyncMultiSelect",
@@ -250,7 +250,7 @@ export const componentMemberMetadata: ComponentMemberMetadata[] = [
250
250
  section: "presets",
251
251
  maturity: "member",
252
252
  summary: "Remote-search multi select.",
253
- useWhen: "Use when users need to pick many remote items and review selected tags inline.",
253
+ useWhen: "Use when users need to pick many remote items, review selected tags inline, or create new items without leaving the remote-search flow.",
254
254
  },
255
255
  {
256
256
  component: "Combobox",
@@ -258,7 +258,7 @@ export const componentMemberMetadata: ComponentMemberMetadata[] = [
258
258
  section: "presets",
259
259
  maturity: "member",
260
260
  summary: "Searchable command-style select surface.",
261
- useWhen: "Use when fast keyboard filtering matters more than strict select semantics.",
261
+ useWhen: "Use when fast local keyboard filtering matters more than strict select semantics; avoid using it as the main remote or creatable select path.",
262
262
  },
263
263
  {
264
264
  component: "FormSelect",
@@ -703,10 +703,10 @@ const actionsColumn = createDataTableActionsColumn({
703
703
  },
704
704
  {
705
705
  component: "Input",
706
- title: "CLI install",
707
- description: "Install the package before consuming family-first docs routes.",
706
+ title: "CLI add",
707
+ description: "Copy the input source into your app.",
708
708
  language: "cli",
709
709
  variant: "cli",
710
- code: `npm install azamat-ui-kit`,
710
+ code: `npx azamat-ui-kit-cli add input`,
711
711
  },
712
712
  ] as const