feat: sync deployed v1.0.0-rc.38-custom.42
Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
This commit is contained in:
1 parent
aa6c3f50f4
commit
ceddfd3d6b
828 files changed
+122253
-13702
No files matched your search
@@ -18,6 +18,7 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
*/
|
||||
import { Add01Icon } from '@hugeicons/core-free-icons'
|
||||
import { HugeiconsIcon } from '@hugeicons/react'
|
||||
import { ArrowRightLeft } from 'lucide-react'
|
||||
import * as React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { toast } from 'sonner'
|
||||
@@ -41,6 +42,11 @@ import { cn } from '@/lib/utils'
|
||||
export type Option = {
|
||||
label: string
|
||||
value: string
|
||||
/**
|
||||
* Secondary text shown beside the option in the dropdown. Chips for hinted
|
||||
* values also carry a marker icon whose tooltip repeats the hint.
|
||||
*/
|
||||
hint?: string
|
||||
}
|
||||
|
||||
interface MultiSelectProps {
|
||||
@@ -139,6 +145,14 @@ export function MultiSelect(props: MultiSelectProps) {
|
||||
return map
|
||||
}, [props.options])
|
||||
|
||||
const hintMap = React.useMemo(() => {
|
||||
const map = new Map<string, string>()
|
||||
for (const option of props.options) {
|
||||
if (option.hint) map.set(option.value, option.hint)
|
||||
}
|
||||
return map
|
||||
}, [props.options])
|
||||
|
||||
const trimmedInput = inputValue.trim()
|
||||
const inputMatchesExisting =
|
||||
trimmedInput.length > 0 &&
|
||||
@@ -164,7 +178,7 @@ export function MultiSelect(props: MultiSelectProps) {
|
||||
if (canCreate) {
|
||||
set.add(trimmedInput)
|
||||
}
|
||||
return Array.from(set)
|
||||
return [...set]
|
||||
}, [props.options, props.selected, canCreate, trimmedInput])
|
||||
|
||||
const addValues = React.useCallback(
|
||||
@@ -198,6 +212,25 @@ export function MultiSelect(props: MultiSelectProps) {
|
||||
setInputValue(value)
|
||||
}
|
||||
|
||||
const handlePaste = (event: React.ClipboardEvent<HTMLInputElement>): void => {
|
||||
if (!props.allowCreate || props.disabled) return
|
||||
|
||||
const pasted = event.clipboardData.getData('text/plain')
|
||||
if (!COMMA_REGEX.test(pasted)) return
|
||||
|
||||
event.preventDefault()
|
||||
const input = event.currentTarget
|
||||
const value =
|
||||
input.value.slice(0, input.selectionStart ?? input.value.length) +
|
||||
pasted +
|
||||
input.value.slice(input.selectionEnd ?? input.value.length)
|
||||
|
||||
// A pasted batch is complete, including its final value. Read the clipboard
|
||||
// before the single-line input can strip newline separators.
|
||||
addValues(value.split(COMMA_REGEX))
|
||||
setInputValue('')
|
||||
}
|
||||
|
||||
const handleValueChange = (next: string[]) => {
|
||||
props.onChange(next)
|
||||
// When an item is picked (multiple mode), Base UI keeps the input but most
|
||||
@@ -282,6 +315,7 @@ export function MultiSelect(props: MultiSelectProps) {
|
||||
<>
|
||||
{visibleValues.map((value) => {
|
||||
const label = labelMap.get(value) ?? value
|
||||
const hint = hintMap.get(value)
|
||||
return (
|
||||
<ComboboxChip key={value}>
|
||||
{props.copyChipOnClick ? (
|
||||
@@ -299,6 +333,15 @@ export function MultiSelect(props: MultiSelectProps) {
|
||||
) : (
|
||||
<span className='max-w-[16rem] truncate'>{label}</span>
|
||||
)}
|
||||
{hint && (
|
||||
<span
|
||||
title={hint}
|
||||
aria-hidden='true'
|
||||
className='text-muted-foreground inline-flex shrink-0'
|
||||
>
|
||||
<ArrowRightLeft className='size-3' />
|
||||
</span>
|
||||
)}
|
||||
</ComboboxChip>
|
||||
)
|
||||
})}
|
||||
@@ -346,6 +389,7 @@ export function MultiSelect(props: MultiSelectProps) {
|
||||
: undefined
|
||||
}
|
||||
onKeyDown={handleKeyDown}
|
||||
onPaste={handlePaste}
|
||||
aria-label={placeholder}
|
||||
/>
|
||||
</ComboboxChips>
|
||||
@@ -356,11 +400,13 @@ export function MultiSelect(props: MultiSelectProps) {
|
||||
{(item: string) => {
|
||||
const isCreate = canCreate && item === trimmedInput
|
||||
const label = labelMap.get(item) ?? item
|
||||
const hint = hintMap.get(item)
|
||||
return (
|
||||
<ComboboxItem
|
||||
key={item}
|
||||
value={item}
|
||||
className={isCreate ? 'text-foreground' : undefined}
|
||||
aria-description={hint}
|
||||
>
|
||||
{isCreate ? (
|
||||
<>
|
||||
@@ -377,7 +423,17 @@ export function MultiSelect(props: MultiSelectProps) {
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<span className='truncate'>{label}</span>
|
||||
<>
|
||||
<span className='truncate'>{label}</span>
|
||||
{hint && (
|
||||
<span
|
||||
aria-hidden='true'
|
||||
className='text-muted-foreground ml-auto max-w-40 shrink-0 truncate text-xs'
|
||||
>
|
||||
{hint}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</ComboboxItem>
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user