@open-mercato/ui 0.6.1-develop.3276.1.1fcd145078 β†’ 0.6.1-develop.3287.1.450f4ffb56

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 (131) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +23 -14
  3. package/dist/backend/AppShell.js +8 -32
  4. package/dist/backend/AppShell.js.map +2 -2
  5. package/dist/backend/CrudForm.js +18 -0
  6. package/dist/backend/CrudForm.js.map +2 -2
  7. package/dist/backend/DataTable.js +149 -53
  8. package/dist/backend/DataTable.js.map +2 -2
  9. package/dist/backend/FilterBar.js +11 -14
  10. package/dist/backend/FilterBar.js.map +2 -2
  11. package/dist/backend/columns/ColumnChooserPanel.js +4 -6
  12. package/dist/backend/columns/ColumnChooserPanel.js.map +2 -2
  13. package/dist/backend/filters/ActiveFilterChips.js +142 -0
  14. package/dist/backend/filters/ActiveFilterChips.js.map +7 -0
  15. package/dist/backend/filters/AdvancedFilterBuilder.js +689 -163
  16. package/dist/backend/filters/AdvancedFilterBuilder.js.map +2 -2
  17. package/dist/backend/filters/AdvancedFilterPanel.js +354 -0
  18. package/dist/backend/filters/AdvancedFilterPanel.js.map +7 -0
  19. package/dist/backend/filters/FilterEmptyState.js +41 -0
  20. package/dist/backend/filters/FilterEmptyState.js.map +7 -0
  21. package/dist/backend/filters/FilterFieldPicker.js +148 -0
  22. package/dist/backend/filters/FilterFieldPicker.js.map +7 -0
  23. package/dist/backend/filters/FilteredEmptyResults.js +26 -0
  24. package/dist/backend/filters/FilteredEmptyResults.js.map +7 -0
  25. package/dist/backend/filters/QuickFilters.js +41 -0
  26. package/dist/backend/filters/QuickFilters.js.map +7 -0
  27. package/dist/backend/filters/filterValidation.js +47 -0
  28. package/dist/backend/filters/filterValidation.js.map +7 -0
  29. package/dist/backend/filters/treeReducer.js +159 -0
  30. package/dist/backend/filters/treeReducer.js.map +7 -0
  31. package/dist/backend/hooks/useAdvancedFilter.js +82 -1
  32. package/dist/backend/hooks/useAdvancedFilter.js.map +2 -2
  33. package/dist/backend/inputs/ComboboxInput.js +11 -7
  34. package/dist/backend/inputs/ComboboxInput.js.map +2 -2
  35. package/dist/backend/inputs/EventPatternInput.js +5 -2
  36. package/dist/backend/inputs/EventPatternInput.js.map +2 -2
  37. package/dist/backend/inputs/EventSelect.js +10 -4
  38. package/dist/backend/inputs/EventSelect.js.map +2 -2
  39. package/dist/backend/inputs/LookupSelect.js +51 -47
  40. package/dist/backend/inputs/LookupSelect.js.map +2 -2
  41. package/dist/backend/inputs/PhoneNumberField.js +196 -45
  42. package/dist/backend/inputs/PhoneNumberField.js.map +2 -2
  43. package/dist/backend/inputs/SwitchableMarkdownInput.js.map +2 -2
  44. package/dist/backend/messages/message-compose-form-groups.js +2 -2
  45. package/dist/backend/messages/message-compose-form-groups.js.map +2 -2
  46. package/dist/backend/utils/api.js +18 -1
  47. package/dist/backend/utils/api.js.map +2 -2
  48. package/dist/backend/utils/serverErrors.js +6 -2
  49. package/dist/backend/utils/serverErrors.js.map +2 -2
  50. package/dist/backend/utils/useAutoDiscoveredFields.js +1 -0
  51. package/dist/backend/utils/useAutoDiscoveredFields.js.map +2 -2
  52. package/dist/backend/utils/useCurrentUserId.js +31 -0
  53. package/dist/backend/utils/useCurrentUserId.js.map +7 -0
  54. package/dist/portal/utils/nav.js +17 -0
  55. package/dist/portal/utils/nav.js.map +2 -2
  56. package/dist/primitives/amount-input.js +128 -0
  57. package/dist/primitives/amount-input.js.map +7 -0
  58. package/dist/primitives/button-input.js +47 -0
  59. package/dist/primitives/button-input.js.map +7 -0
  60. package/dist/primitives/card-input.js +133 -0
  61. package/dist/primitives/card-input.js.map +7 -0
  62. package/dist/primitives/dialog.js +7 -5
  63. package/dist/primitives/dialog.js.map +2 -2
  64. package/dist/primitives/email-input.js +29 -0
  65. package/dist/primitives/email-input.js.map +7 -0
  66. package/dist/primitives/password-input.js +64 -0
  67. package/dist/primitives/password-input.js.map +7 -0
  68. package/dist/primitives/search-input.js +57 -0
  69. package/dist/primitives/search-input.js.map +7 -0
  70. package/dist/primitives/select.js +43 -5
  71. package/dist/primitives/select.js.map +2 -2
  72. package/dist/primitives/tag.js +4 -2
  73. package/dist/primitives/tag.js.map +2 -2
  74. package/dist/primitives/website-input.js +56 -0
  75. package/dist/primitives/website-input.js.map +7 -0
  76. package/package.json +3 -3
  77. package/src/backend/AppShell.tsx +7 -30
  78. package/src/backend/CrudForm.tsx +17 -0
  79. package/src/backend/DataTable.tsx +307 -63
  80. package/src/backend/FilterBar.tsx +5 -6
  81. package/src/backend/__tests__/DataTable.extensions.test.tsx +170 -0
  82. package/src/backend/__tests__/serverErrors.test.ts +79 -1
  83. package/src/backend/columns/ColumnChooserPanel.tsx +4 -5
  84. package/src/backend/filters/ActiveFilterChips.tsx +179 -0
  85. package/src/backend/filters/AdvancedFilterBuilder.tsx +840 -237
  86. package/src/backend/filters/AdvancedFilterPanel.tsx +456 -0
  87. package/src/backend/filters/FilterEmptyState.tsx +51 -0
  88. package/src/backend/filters/FilterFieldPicker.tsx +139 -0
  89. package/src/backend/filters/FilteredEmptyResults.tsx +40 -0
  90. package/src/backend/filters/QuickFilters.tsx +62 -0
  91. package/src/backend/filters/__tests__/ActiveFilterChips.test.tsx +75 -0
  92. package/src/backend/filters/__tests__/AdvancedFilterBuilder.test.tsx +210 -0
  93. package/src/backend/filters/__tests__/AdvancedFilterPanel.test.tsx +212 -0
  94. package/src/backend/filters/__tests__/FilterEmptyState.test.tsx +31 -0
  95. package/src/backend/filters/__tests__/FilterFieldPicker.test.tsx +61 -0
  96. package/src/backend/filters/__tests__/FilteredEmptyResults.test.tsx +35 -0
  97. package/src/backend/filters/__tests__/QuickFilters.test.tsx +34 -0
  98. package/src/backend/filters/__tests__/filterValidation.test.ts +69 -0
  99. package/src/backend/filters/__tests__/treeReducer.test.ts +189 -0
  100. package/src/backend/filters/filterValidation.ts +61 -0
  101. package/src/backend/filters/treeReducer.ts +201 -0
  102. package/src/backend/hooks/__tests__/useAdvancedFilter.test.tsx +213 -0
  103. package/src/backend/hooks/useAdvancedFilter.ts +130 -0
  104. package/src/backend/inputs/ComboboxInput.tsx +32 -26
  105. package/src/backend/inputs/EventPatternInput.tsx +11 -2
  106. package/src/backend/inputs/EventSelect.tsx +13 -4
  107. package/src/backend/inputs/LookupSelect.tsx +75 -53
  108. package/src/backend/inputs/PhoneNumberField.tsx +237 -47
  109. package/src/backend/inputs/SwitchableMarkdownInput.tsx +30 -0
  110. package/src/backend/inputs/__tests__/ComboboxInput.test.tsx +4 -0
  111. package/src/backend/inputs/__tests__/PhoneNumberField.test.tsx +4 -0
  112. package/src/backend/messages/message-compose-form-groups.tsx +2 -2
  113. package/src/backend/utils/api.ts +27 -2
  114. package/src/backend/utils/serverErrors.ts +15 -8
  115. package/src/backend/utils/useAutoDiscoveredFields.ts +2 -0
  116. package/src/backend/utils/useCurrentUserId.ts +40 -0
  117. package/src/portal/utils/__tests__/nav.test.ts +80 -0
  118. package/src/portal/utils/nav.ts +23 -1
  119. package/src/primitives/__tests__/password-input.test.tsx +93 -0
  120. package/src/primitives/__tests__/search-input.test.tsx +95 -0
  121. package/src/primitives/__tests__/zindex-overlay.test.tsx +26 -0
  122. package/src/primitives/amount-input.tsx +184 -0
  123. package/src/primitives/button-input.tsx +68 -0
  124. package/src/primitives/card-input.tsx +193 -0
  125. package/src/primitives/dialog.tsx +18 -7
  126. package/src/primitives/email-input.tsx +36 -0
  127. package/src/primitives/password-input.tsx +100 -0
  128. package/src/primitives/search-input.tsx +87 -0
  129. package/src/primitives/select.tsx +98 -11
  130. package/src/primitives/tag.tsx +3 -1
  131. package/src/primitives/website-input.tsx +72 -0
@@ -0,0 +1,87 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import { Search, X } from 'lucide-react'
5
+ import type { VariantProps } from 'class-variance-authority'
6
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
7
+ import { cn } from '@open-mercato/shared/lib/utils'
8
+ import { inputWrapperVariants, inputElementVariants } from './input'
9
+
10
+ export type SearchInputProps = Omit<React.ComponentPropsWithoutRef<'input'>, 'size' | 'type' | 'onChange'> &
11
+ VariantProps<typeof inputWrapperVariants> & {
12
+ /** Controlled value. */
13
+ value: string
14
+ /** Called on every keystroke with the new value. */
15
+ onChange: (next: string) => void
16
+ /**
17
+ * Called when the user presses the trailing Γ— button.
18
+ * Defaults to `onChange('')` β€” pass an explicit handler to also reset adjacent state
19
+ * (e.g. cancel an in-flight request, reset paging).
20
+ */
21
+ onClear?: () => void
22
+ /** Show the trailing Γ— button when the value is non-empty. Defaults to `true`. */
23
+ clearable?: boolean
24
+ /** Optional className on the wrapper. */
25
+ className?: string
26
+ /** Optional className on the inner `<input>`. */
27
+ inputClassName?: string
28
+ /** Translated aria-label for the clear button. Defaults to `t('ui.inputs.searchInput.clear', 'Clear search')`. */
29
+ clearLabel?: string
30
+ }
31
+
32
+ /**
33
+ * Search input matching Figma `Text Input [1.1]` (node `266:5251`) **Search** variant β€” a leading
34
+ * `Search` icon, the text input, and an optional trailing `X` button to clear the field. Built on
35
+ * the shared `inputWrapperVariants` / `inputElementVariants` CVA so the visual contract stays in
36
+ * sync with the foundation `Input` primitive.
37
+ *
38
+ * The clear button is rendered as a proper `<button>` (not inside an `aria-hidden` decorative
39
+ * span), so it remains keyboard-focusable and screen-reader-accessible.
40
+ */
41
+ export const SearchInput = React.forwardRef<HTMLInputElement, SearchInputProps>(
42
+ ({ className, inputClassName, size, value, onChange, onClear, clearable = true, clearLabel, placeholder, disabled, ...props }, ref) => {
43
+ const t = useT()
44
+ const resolvedPlaceholder = placeholder ?? t('ui.inputs.searchInput.placeholder', 'Search…')
45
+ const resolvedClearLabel = clearLabel ?? t('ui.inputs.searchInput.clear', 'Clear search')
46
+ const showClear = clearable && value.length > 0 && !disabled
47
+
48
+ const handleClear = React.useCallback(() => {
49
+ if (onClear) onClear()
50
+ else onChange('')
51
+ }, [onChange, onClear])
52
+
53
+ return (
54
+ <div className={cn(inputWrapperVariants({ size }), className)} data-slot="search-input-wrapper">
55
+ <Search className="size-4 shrink-0 text-muted-foreground" aria-hidden="true" />
56
+ <input
57
+ ref={ref}
58
+ type="search"
59
+ inputMode="search"
60
+ autoComplete="off"
61
+ placeholder={resolvedPlaceholder}
62
+ value={value}
63
+ onChange={(event) => onChange(event.target.value)}
64
+ disabled={disabled}
65
+ className={cn(
66
+ inputElementVariants({ size }),
67
+ // Disable the native search clear button β€” we render our own.
68
+ '[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none',
69
+ inputClassName,
70
+ )}
71
+ {...props}
72
+ />
73
+ {showClear ? (
74
+ <button
75
+ type="button"
76
+ onClick={handleClear}
77
+ aria-label={resolvedClearLabel}
78
+ className="flex shrink-0 items-center justify-center rounded-sm text-muted-foreground transition-colors hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-ring/40"
79
+ >
80
+ <X className="size-4" aria-hidden="true" />
81
+ </button>
82
+ ) : null}
83
+ </div>
84
+ )
85
+ },
86
+ )
87
+ SearchInput.displayName = 'SearchInput'
@@ -44,6 +44,46 @@ const SelectTrigger = React.forwardRef<
44
44
  ))
45
45
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
46
46
 
47
+ /**
48
+ * Leading visual slot inside a `SelectTrigger` β€” render flags, avatars,
49
+ * provider logos, brand marks, or company icons before the `<SelectValue>`.
50
+ *
51
+ * Mirrors the Type variants in the Figma DS (Basic / Country / Avatar /
52
+ * Provider / Brand / Company β€” Figma `Select [1.1]`, node `270:1085`).
53
+ *
54
+ * Render inside `SelectTrigger`, BEFORE the `<SelectValue>`:
55
+ *
56
+ * ```tsx
57
+ * <SelectTrigger>
58
+ * <SelectTriggerLeading><Avatar size="sm" label={user.name} /></SelectTriggerLeading>
59
+ * <SelectValue placeholder="Select user" />
60
+ * </SelectTrigger>
61
+ * ```
62
+ *
63
+ * Sizing follows the trigger: icons render `size-4`, images render `size-5`
64
+ * by default β€” pass your own classes on the inner element when you need a
65
+ * different visual size (e.g. country flags `h-3 w-4`).
66
+ */
67
+ const SelectTriggerLeading = React.forwardRef<
68
+ HTMLSpanElement,
69
+ React.HTMLAttributes<HTMLSpanElement>
70
+ >(({ className, children, ...props }, ref) => (
71
+ <span
72
+ ref={ref}
73
+ data-slot="select-trigger-leading"
74
+ aria-hidden="true"
75
+ className={cn(
76
+ 'flex shrink-0 items-center justify-center',
77
+ '[&>svg]:size-4 [&>svg]:shrink-0 [&>img]:size-5 [&>img]:shrink-0',
78
+ className
79
+ )}
80
+ {...props}
81
+ >
82
+ {children}
83
+ </span>
84
+ ))
85
+ SelectTriggerLeading.displayName = 'SelectTriggerLeading'
86
+
47
87
  const SelectScrollUpButton = React.forwardRef<
48
88
  React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
49
89
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
@@ -92,7 +132,7 @@ const SelectContent = React.forwardRef<
92
132
  <SelectScrollUpButton />
93
133
  <SelectPrimitive.Viewport
94
134
  className={cn(
95
- 'p-1 max-h-[var(--radix-select-content-available-height)] overflow-y-auto',
135
+ 'p-2 max-h-[var(--radix-select-content-available-height)] overflow-y-auto',
96
136
  position === 'popper' && 'w-full min-w-[var(--radix-select-trigger-width)]'
97
137
  )}
98
138
  >
@@ -110,7 +150,11 @@ const SelectLabel = React.forwardRef<
110
150
  >(({ className, ...props }, ref) => (
111
151
  <SelectPrimitive.Label
112
152
  ref={ref}
113
- className={cn('px-2 py-1.5 text-overline uppercase text-muted-foreground', className)}
153
+ className={cn(
154
+ 'px-2 pt-2 pb-1 text-overline font-semibold uppercase tracking-wider text-muted-foreground/80',
155
+ 'select-none',
156
+ className
157
+ )}
114
158
  {...props}
115
159
  />
116
160
  ))
@@ -123,7 +167,7 @@ const SelectItem = React.forwardRef<
123
167
  <SelectPrimitive.Item
124
168
  ref={ref}
125
169
  className={cn(
126
- 'relative flex w-full cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none transition-colors',
170
+ 'relative flex w-full cursor-default select-none items-center gap-2 rounded-md p-2 text-sm outline-none transition-colors',
127
171
  'focus:bg-muted focus:text-foreground',
128
172
  'data-[state=checked]:bg-muted/70 data-[state=checked]:text-foreground',
129
173
  'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
@@ -132,18 +176,59 @@ const SelectItem = React.forwardRef<
132
176
  )}
133
177
  {...props}
134
178
  >
135
- <span className="flex-1 truncate">
136
- <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
137
- </span>
138
- <span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
139
- <SelectPrimitive.ItemIndicator>
140
- <Check className="size-4 text-foreground" aria-hidden="true" />
141
- </SelectPrimitive.ItemIndicator>
142
- </span>
179
+ <SelectPrimitive.ItemText asChild>
180
+ <span className="flex min-w-0 flex-1 items-center gap-2 truncate">
181
+ {children}
182
+ </span>
183
+ </SelectPrimitive.ItemText>
184
+ <SelectPrimitive.ItemIndicator className="ml-auto flex shrink-0 items-center justify-center">
185
+ <Check className="size-4 text-foreground" aria-hidden="true" />
186
+ </SelectPrimitive.ItemIndicator>
143
187
  </SelectPrimitive.Item>
144
188
  ))
145
189
  SelectItem.displayName = SelectPrimitive.Item.displayName
146
190
 
191
+ /**
192
+ * Leading visual slot inside a `SelectItem` β€” mirror of `SelectTriggerLeading`
193
+ * for dropdown rows. Compose with the DS `Avatar`, country flag images, or
194
+ * `lucide-react` icons.
195
+ *
196
+ * Render inside the `<SelectItem>` children, before the row label:
197
+ *
198
+ * ```tsx
199
+ * <SelectItem value="us">
200
+ * <SelectItemLeading><span className="h-3 w-4 rounded-sm overflow-hidden">πŸ‡ΊπŸ‡Έ</span></SelectItemLeading>
201
+ * United States
202
+ * </SelectItem>
203
+ * ```
204
+ *
205
+ * NOTE: `SelectPrimitive.ItemText` only reads the text node siblings for the
206
+ * trigger preview β€” wrap the leading slot OUTSIDE `ItemText` (which this
207
+ * primitive does by default, since `SelectItem`'s `children` are placed inside
208
+ * `<SelectPrimitive.ItemText>` only via the inner `<span className="flex-1
209
+ * truncate">`). Place the `SelectItemLeading` alongside the row text and the
210
+ * label will read correctly in the trigger preview.
211
+ */
212
+ const SelectItemLeading = React.forwardRef<
213
+ HTMLSpanElement,
214
+ React.HTMLAttributes<HTMLSpanElement>
215
+ >(({ className, children, ...props }, ref) => (
216
+ <span
217
+ ref={ref}
218
+ data-slot="select-item-leading"
219
+ aria-hidden="true"
220
+ className={cn(
221
+ 'flex shrink-0 items-center justify-center',
222
+ '[&>svg]:size-4 [&>svg]:shrink-0 [&>img]:size-5 [&>img]:shrink-0',
223
+ className
224
+ )}
225
+ {...props}
226
+ >
227
+ {children}
228
+ </span>
229
+ ))
230
+ SelectItemLeading.displayName = 'SelectItemLeading'
231
+
147
232
  const SelectSeparator = React.forwardRef<
148
233
  React.ElementRef<typeof SelectPrimitive.Separator>,
149
234
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
@@ -191,9 +276,11 @@ export {
191
276
  SelectGroup,
192
277
  SelectValue,
193
278
  SelectTrigger,
279
+ SelectTriggerLeading,
194
280
  SelectContent,
195
281
  SelectLabel,
196
282
  SelectItem,
283
+ SelectItemLeading,
197
284
  SelectSeparator,
198
285
  SelectScrollUpButton,
199
286
  SelectScrollDownButton,
@@ -15,6 +15,7 @@ const tagVariants = cva(
15
15
  info: 'border-status-info-border bg-status-info-bg text-status-info-text',
16
16
  neutral: 'border-status-neutral-border bg-status-neutral-bg text-status-neutral-text',
17
17
  brand: 'border-brand-violet/30 bg-brand-violet/10 text-brand-violet',
18
+ pink: 'border-status-pink-border bg-status-pink-bg text-status-pink-text',
18
19
  },
19
20
  shape: {
20
21
  pill: 'rounded-full px-2.5 py-0.5',
@@ -33,9 +34,10 @@ const dotColorMap: Record<TagVariant, string> = {
33
34
  info: 'bg-status-info-icon',
34
35
  neutral: 'bg-status-neutral-icon',
35
36
  brand: 'bg-brand-violet',
37
+ pink: 'bg-status-pink-icon',
36
38
  }
37
39
 
38
- export type TagVariant = 'default' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'brand'
40
+ export type TagVariant = 'default' | 'success' | 'warning' | 'error' | 'info' | 'neutral' | 'brand' | 'pink'
39
41
 
40
42
  export type TagShape = 'pill' | 'square'
41
43
 
@@ -0,0 +1,72 @@
1
+ "use client"
2
+
3
+ import * as React from 'react'
4
+ import type { VariantProps } from 'class-variance-authority'
5
+ import { useT } from '@open-mercato/shared/lib/i18n/context'
6
+ import { cn } from '@open-mercato/shared/lib/utils'
7
+ import { inputWrapperVariants, inputElementVariants } from './input'
8
+
9
+ export type WebsiteInputProps = Omit<React.ComponentPropsWithoutRef<'input'>, 'size' | 'type'> &
10
+ VariantProps<typeof inputWrapperVariants> & {
11
+ /** Protocol shown in the left prefix box. Defaults to `'https://'` per Figma. */
12
+ prefix?: string
13
+ /** Hide the prefix box entirely (consumer wants a bare URL input). */
14
+ showPrefix?: boolean
15
+ /** Optional className on the wrapper. */
16
+ className?: string
17
+ /** Optional className on the inner `<input>`. */
18
+ inputClassName?: string
19
+ }
20
+
21
+ /**
22
+ * Website input matching Figma `Text Input [1.1]` (node `266:5251`) **Website** variant β€” a left
23
+ * prefix box with the protocol text (default `'https://'`), a vertical divider, then the URL text
24
+ * input. Built on the shared `inputWrapperVariants` / `inputElementVariants` CVA so the visual
25
+ * contract matches the foundation `Input` primitive.
26
+ *
27
+ * The prefix is **display-only** β€” the inner `<input>` value contains ONLY the host/path portion
28
+ * (e.g. `'www.example.com/path'`). Compose the full URL at the consumer boundary if needed.
29
+ */
30
+ export const WebsiteInput = React.forwardRef<HTMLInputElement, WebsiteInputProps>(
31
+ ({ className, inputClassName, size, prefix = 'https://', showPrefix = true, placeholder, disabled, ...props }, ref) => {
32
+ const t = useT()
33
+ const resolvedPlaceholder = placeholder ?? t('ui.inputs.websiteInput.placeholder', 'www.example.com')
34
+ return (
35
+ <div
36
+ className={cn(
37
+ inputWrapperVariants({ size }),
38
+ // Override default px so prefix box can sit flush left.
39
+ 'px-0 overflow-hidden',
40
+ className,
41
+ )}
42
+ data-slot="website-input-wrapper"
43
+ >
44
+ {showPrefix ? (
45
+ <>
46
+ <span
47
+ className="flex shrink-0 items-center self-stretch border-r border-input px-3 text-sm text-muted-foreground select-none"
48
+ aria-hidden="true"
49
+ >
50
+ {prefix}
51
+ </span>
52
+ </>
53
+ ) : null}
54
+ <input
55
+ ref={ref}
56
+ type="url"
57
+ inputMode="url"
58
+ autoComplete="url"
59
+ placeholder={resolvedPlaceholder}
60
+ disabled={disabled}
61
+ className={cn(
62
+ inputElementVariants({ size }),
63
+ 'px-3',
64
+ inputClassName,
65
+ )}
66
+ {...props}
67
+ />
68
+ </div>
69
+ )
70
+ },
71
+ )
72
+ WebsiteInput.displayName = 'WebsiteInput'