@softize/opus 8.8.0 → 8.8.2
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/package.json
CHANGED
|
@@ -305,13 +305,27 @@ function CustomSelect(props: Exclude<SelectProps, SelectNativeProps>): React.Rea
|
|
|
305
305
|
* onde não existe seleção persistente pra exibir.
|
|
306
306
|
*/
|
|
307
307
|
const triggerText = selectedOption?.label ?? ''
|
|
308
|
-
/** `triggerLabel` pode ser JSX (a barra do composer mostra a chave curta), e `value` de
|
|
309
|
-
* input só aceita texto — então ele vai num `<span>` por cima, com o input `sr-only`
|
|
310
|
-
* guardando o `id` e o rótulo textual pro leitor de tela. */
|
|
311
|
-
const customTrigger = !props.multiple && selectedOption?.triggerLabel !== undefined
|
|
312
308
|
|
|
313
309
|
return (
|
|
314
|
-
<Popover
|
|
310
|
+
<Popover
|
|
311
|
+
open={open}
|
|
312
|
+
onOpenChange={(v) => {
|
|
313
|
+
// Fechar devolve o foco pro gatilho, e o gatilho abre AO RECEBER FOCO — sem
|
|
314
|
+
// guarda, o seletor reabre sozinho ("abre, fecha e abre de novo").
|
|
315
|
+
//
|
|
316
|
+
// A guarda vale UM FRAME, não até ser consumida. Fechar clicando noutro lugar da
|
|
317
|
+
// página não devolve o foco pra cá, então uma trava que espera esse retorno ficaria
|
|
318
|
+
// armada pra sempre e engoliria a PRÓXIMA abertura por teclado — trocando um
|
|
319
|
+
// defeito visível por um que só aparece pra quem navega por Tab.
|
|
320
|
+
if (!v) {
|
|
321
|
+
closingRef.current = true
|
|
322
|
+
requestAnimationFrame(() => {
|
|
323
|
+
closingRef.current = false
|
|
324
|
+
})
|
|
325
|
+
}
|
|
326
|
+
setOpen(v)
|
|
327
|
+
}}
|
|
328
|
+
>
|
|
315
329
|
<div ref={rootRef} data-slot="select" className={cn(ghost ? 'min-w-0' : 'min-w-40', className)}>
|
|
316
330
|
<CommandPrimitive data-slot="select-command" shouldFilter={canSearch && onSearch === undefined} className="overflow-visible">
|
|
317
331
|
<PopoverAnchor asChild>
|
|
@@ -361,13 +375,16 @@ function CustomSelect(props: Exclude<SelectProps, SelectNativeProps>): React.Rea
|
|
|
361
375
|
</span>
|
|
362
376
|
)
|
|
363
377
|
})}
|
|
364
|
-
{/*
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
{
|
|
369
|
-
|
|
370
|
-
|
|
378
|
+
{/* O rótulo é SEMPRE um `<span>`. Quando ele morava no `value` de um input,
|
|
379
|
+
o texto rolava pro fim ao ganhar foco (o browser leva o cursor pro final)
|
|
380
|
+
e o começo do título sumia — num campo estreito, a pessoa via o meio de
|
|
381
|
+
uma frase. `<span>` trunca com reticências, que é o certo. */}
|
|
382
|
+
{/* No MÚLTIPLO os chips ocupam o lugar do rótulo — mas quando não há nenhum,
|
|
383
|
+
o gatilho ficaria em branco (o input que carregava o placeholder virou
|
|
384
|
+
invisível). Campo mudo é pior que campo vazio: não diz nem o que é. */}
|
|
385
|
+
{(!props.multiple || selectedValues.length === 0) && (
|
|
386
|
+
<span data-slot="select-trigger-label" className={cn('min-w-0 flex-1 truncate text-left text-sm', selectedOption === undefined && 'text-muted-foreground')}>
|
|
387
|
+
{props.multiple ? placeholder : (selectedOption?.triggerLabel ?? selectedOption?.label ?? placeholder)}
|
|
371
388
|
</span>
|
|
372
389
|
)}
|
|
373
390
|
<input
|
|
@@ -404,10 +421,7 @@ function CustomSelect(props: Exclude<SelectProps, SelectNativeProps>): React.Rea
|
|
|
404
421
|
}
|
|
405
422
|
}}
|
|
406
423
|
placeholder={props.multiple && selectedValues.length > 0 ? '' : placeholder}
|
|
407
|
-
className=
|
|
408
|
-
'min-w-0 flex-1 cursor-pointer bg-transparent text-sm caret-transparent outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed',
|
|
409
|
-
customTrigger && 'sr-only',
|
|
410
|
-
)}
|
|
424
|
+
className="sr-only"
|
|
411
425
|
/>
|
|
412
426
|
{clearable === true && selectedValues.length > 0 && disabled !== true && (
|
|
413
427
|
<button
|
|
@@ -461,11 +475,16 @@ function CustomSelect(props: Exclude<SelectProps, SelectNativeProps>): React.Rea
|
|
|
461
475
|
'pointer-events-auto overflow-hidden p-0',
|
|
462
476
|
ghost ? 'w-auto min-w-56 max-w-80' : 'w-(--radix-popover-trigger-width) min-w-40',
|
|
463
477
|
)}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
478
|
+
/*
|
|
479
|
+
* O foco ao abrir é SEMPRE nosso — o Radix nunca mexe.
|
|
480
|
+
*
|
|
481
|
+
* Deixá-lo agir com busca parecia certo (ele focaria o primeiro elemento
|
|
482
|
+
* focável, que é a caixa), mas ele roda DEPOIS do nosso efeito e movia o foco
|
|
483
|
+
* pro contêiner do conteúdo: a busca ganhava o cursor e o perdia em seguida,
|
|
484
|
+
* que é exatamente o "ganha foco e some" relatado. Com dois donos do foco, o
|
|
485
|
+
* último a escrever vence — e quem é o último depende da ordem de montagem.
|
|
486
|
+
*/
|
|
487
|
+
onOpenAutoFocus={(e) => e.preventDefault()}
|
|
469
488
|
onCloseAutoFocus={(e) => e.preventDefault()}
|
|
470
489
|
onInteractOutside={(e) => {
|
|
471
490
|
const target = e.target as HTMLElement
|