@nextelco/common-ui 2.1.105 → 2.1.106
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/esm/v1/components/forms/FormField/FormField.js.map +1 -1
- package/dist/esm/v1/components/forms/FormGrid/FormGrid.js.map +1 -1
- package/dist/esm/v1/components/lists/ListFinder/ListFinder.js +4 -4
- package/dist/esm/v1/components/lists/ListFinder/ListFinder.js.map +1 -1
- package/dist/esm/v1/components/overlays/Dialog/Dialog.js.map +1 -1
- package/dist/esm/v1/components/tables/PaginatedTable/PaginatedTable.js.map +1 -1
- package/dist/esm/v1/components/tables/Table/Table.js.map +1 -1
- package/dist/esm/v1/primitives/buttons/Button/Button.js.map +1 -1
- package/dist/esm/v1/primitives/forms/Checkbox/Checkbox.js +10 -5
- package/dist/esm/v1/primitives/forms/Checkbox/Checkbox.js.map +1 -1
- package/dist/esm/v1/primitives/forms/LookupInput/LookupInput.js.map +1 -1
- package/dist/esm/v1/primitives/forms/SelectInput/SelectInput.js.map +1 -1
- package/dist/esm/v1/primitives/forms/TextArea/TextArea.js.map +1 -1
- package/dist/esm/v1/primitives/lists/ListItem/ListItem.js +2 -2
- package/dist/esm/v1/primitives/lists/ListItem/ListItem.js.map +1 -1
- package/dist/style.components.css +1 -1
- package/dist/style.css +1 -1
- package/dist/style.layered.css +1 -1
- package/dist/types/v1/components/forms/FormField/FormField.d.ts +3 -3
- package/dist/types/v1/components/forms/FormGrid/FormGrid.d.ts +2 -0
- package/dist/types/v1/components/lists/ListFinder/ListFinder.d.ts +1 -1
- package/dist/types/v1/components/overlays/Dialog/Dialog.d.ts +3 -1
- package/dist/types/v1/components/tables/PaginatedTable/PaginatedTable.d.ts +1 -1
- package/dist/types/v1/components/tables/Table/Table.d.ts +1 -1
- package/dist/types/v1/primitives/buttons/Button/Button.d.ts +2 -0
- package/dist/types/v1/primitives/forms/Checkbox/Checkbox.d.ts +7 -0
- package/dist/types/v1/primitives/forms/LookupInput/LookupInput.d.ts +3 -0
- package/dist/types/v1/primitives/forms/SelectInput/SelectInput.d.ts +3 -0
- package/dist/types/v1/primitives/forms/TextArea/TextArea.d.ts +3 -0
- package/dist/types/v1/primitives/lists/ListItem/ListItem.d.ts +2 -1
- package/package.json +1 -1
- package/dist/esm/v1/primitives/lists/ListItem/ListCheckbox.js +0 -28
- package/dist/esm/v1/primitives/lists/ListItem/ListCheckbox.js.map +0 -1
- package/dist/types/v1/primitives/lists/ListItem/ListCheckbox.d.ts +0 -14
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.js","sources":["../../../../../../src/v1/primitives/buttons/Button/Button.tsx"],"sourcesContent":["import React, { forwardRef } from 'react'\r\n\r\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\r\n /** `primary`: a ação principal (navy, uma por ecrã). `secondary`: as outras (ex: Fechar). */\r\n variant?: 'primary' | 'secondary'\r\n /** Ícone antes do texto (ex: `<CheckIcon size={13} />`). */\r\n icon?: React.ReactNode\r\n /** A guardar/enviar: mostra uma roda no lugar do ícone e fica desativado. */\r\n loading?: boolean\r\n}\r\n\r\nconst VARIANTS = {\r\n primary: 'min-w-[120px] border-transparent bg-primary font-semibold text-primary-foreground hover:bg-primary/90',\r\n secondary: 'min-w-[100px] border-border bg-card font-medium text-muted-foreground hover:bg-muted hover:text-foreground',\r\n}\r\n\r\n/**\r\n * Botão de ação (ex: Confirmar, Fechar). Por omissão não submete formulários\r\n * (`type=\"button\"`); para submeter, passar `type=\"submit\"`.\r\n *\r\n * **Aceita os atributos HTML do [<button>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button)**, com o mesmo comportamento: `onClick`, `disabled`, `type`, `name`, `form`, `ref`, ...\r\n * Só os próprios do V1 aparecem na tabela abaixo.\r\n */\r\nconst Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(\r\n { variant = 'primary', icon, loading, disabled, type = 'button', className = '', children, ...props },\r\n ref,\r\n) {\r\n return (\r\n <button\r\n ref={ref}\r\n type={type}\r\n disabled={disabled || loading}\r\n aria-busy={loading || undefined}\r\n className={\r\n 'inline-flex h-9 cursor-pointer items-center justify-center gap-1.5 rounded-lg border px-5 text-control transition-colors duration-150 ' +\r\n 'focus-visible:ring-3 focus-visible:ring-primary/20 focus-visible:outline-none ' +\r\n `disabled:cursor-not-allowed disabled:opacity-50 ${VARIANTS[variant]} ${className}`\r\n }\r\n {...props}\r\n >\r\n {loading ? (\r\n <span aria-hidden className=\"inline-block h-[13px] w-[13px] animate-spin rounded-full border-2 border-current border-t-transparent opacity-80\" />\r\n ) : (\r\n icon\r\n )}\r\n {children}\r\n </button>\r\n )\r\n})\r\n\r\nexport default Button\r\n"],"names":["Button"],"mappings":";;AAWA,MAAM,WAAW;AAAA,EACf,SAAS;AAAA,EACT,WAAW;AACb;
|
|
1
|
+
{"version":3,"file":"Button.js","sources":["../../../../../../src/v1/primitives/buttons/Button/Button.tsx"],"sourcesContent":["import React, { forwardRef } from 'react'\r\n\r\nexport interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\r\n /** `primary`: a ação principal (navy, uma por ecrã). `secondary`: as outras (ex: Fechar). */\r\n variant?: 'primary' | 'secondary'\r\n /** Ícone antes do texto (ex: `<CheckIcon size={13} />`). */\r\n icon?: React.ReactNode\r\n /** A guardar/enviar: mostra uma roda no lugar do ícone e fica desativado. */\r\n loading?: boolean\r\n}\r\n\r\nconst VARIANTS = {\r\n primary: 'min-w-[120px] border-transparent bg-primary font-semibold text-primary-foreground hover:bg-primary/90',\r\n secondary: 'min-w-[100px] border-border bg-card font-medium text-muted-foreground hover:bg-muted hover:text-foreground',\r\n}\r\n\r\n/**\r\n * Botão de ação (ex: Confirmar, Fechar). Por omissão não submete formulários\r\n * (`type=\"button\"`); para submeter, passar `type=\"submit\"`.\r\n *\r\n * **Aceita os atributos HTML do [<button>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button)**, com o mesmo comportamento: `onClick`, `disabled`, `type`, `name`, `form`, `ref`, ...\r\n * Só os próprios do V1 aparecem na tabela abaixo.\r\n *\r\n * **Onde aparece:** no rodapé de um [Dialog](?path=/docs/v1-components-overlays-dialog--docs) (ver [Formulário em modal](?path=/docs/v1-patterns-forms-formulário-em-modal--docs)).\r\n */\r\nconst Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(\r\n { variant = 'primary', icon, loading, disabled, type = 'button', className = '', children, ...props },\r\n ref,\r\n) {\r\n return (\r\n <button\r\n ref={ref}\r\n type={type}\r\n disabled={disabled || loading}\r\n aria-busy={loading || undefined}\r\n className={\r\n 'inline-flex h-9 cursor-pointer items-center justify-center gap-1.5 rounded-lg border px-5 text-control transition-colors duration-150 ' +\r\n 'focus-visible:ring-3 focus-visible:ring-primary/20 focus-visible:outline-none ' +\r\n `disabled:cursor-not-allowed disabled:opacity-50 ${VARIANTS[variant]} ${className}`\r\n }\r\n {...props}\r\n >\r\n {loading ? (\r\n <span aria-hidden className=\"inline-block h-[13px] w-[13px] animate-spin rounded-full border-2 border-current border-t-transparent opacity-80\" />\r\n ) : (\r\n icon\r\n )}\r\n {children}\r\n </button>\r\n )\r\n})\r\n\r\nexport default Button\r\n"],"names":["Button"],"mappings":";;AAWA,MAAM,WAAW;AAAA,EACf,SAAS;AAAA,EACT,WAAW;AACb;AAWA,MAAM,SAAS,WAA2C,SAASA,QACjE,EAAE,UAAU,WAAW,MAAM,SAAS,UAAU,OAAO,UAAU,YAAY,IAAI,UAAU,GAAG,MAAA,GAC9F,KACA;AACA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,UAAU,YAAY;AAAA,MACtB,aAAW,WAAW;AAAA,MACtB,WACE,uQAEmD,SAAS,OAAO,CAAC,IAAI,SAAS;AAAA,MAElF,GAAG;AAAA,MAEH,UAAA;AAAA,QAAA,8BACE,QAAA,EAAK,eAAW,MAAC,WAAU,oHAAmH,IAE/I;AAAA,QAED;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGP,CAAC;"}
|
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef } from "react";
|
|
2
|
+
import { forwardRef, useRef, useImperativeHandle, useEffect } from "react";
|
|
3
3
|
import { CheckIcon } from "../../../foundations/icons/icons.js";
|
|
4
4
|
import { useField } from "../field.js";
|
|
5
|
-
const Checkbox = forwardRef(function Checkbox2({ invalid, className = "", id, required, ...props }, ref) {
|
|
5
|
+
const Checkbox = forwardRef(function Checkbox2({ invalid, indeterminate = false, className = "", id, required, ...props }, ref) {
|
|
6
6
|
const field = useField();
|
|
7
|
+
const caixa = useRef(null);
|
|
8
|
+
useImperativeHandle(ref, () => caixa.current);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (caixa.current) caixa.current.indeterminate = indeterminate;
|
|
11
|
+
});
|
|
7
12
|
return /* @__PURE__ */ jsxs("span", { className: `relative inline-flex size-4 shrink-0 ${className}`, children: [
|
|
8
13
|
/* @__PURE__ */ jsx(
|
|
9
14
|
"input",
|
|
10
15
|
{
|
|
11
|
-
ref,
|
|
16
|
+
ref: caixa,
|
|
12
17
|
type: "checkbox",
|
|
13
18
|
id: id ?? field.id,
|
|
14
19
|
required: required ?? field.required,
|
|
15
20
|
"aria-invalid": invalid || void 0,
|
|
16
|
-
className: "peer absolute inset-0 m-0 size-full cursor-pointer appearance-none rounded-sm border border-border bg-card outline-none transition-[background-color,border-color,box-shadow] duration-150 checked:border-primary checked:bg-primary focus-visible:ring-3 focus-visible:ring-primary/20 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/15 disabled:cursor-not-allowed disabled:bg-muted disabled:checked:border-border disabled:checked:bg-muted",
|
|
21
|
+
className: "peer absolute inset-0 m-0 size-full cursor-pointer appearance-none rounded-sm border border-border bg-card outline-none transition-[background-color,border-color,box-shadow] duration-150 checked:border-primary checked:bg-primary indeterminate:border-primary indeterminate:bg-primary focus-visible:ring-3 focus-visible:ring-primary/20 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/15 disabled:cursor-not-allowed disabled:bg-muted disabled:checked:border-border disabled:checked:bg-muted disabled:indeterminate:border-border disabled:indeterminate:bg-muted",
|
|
17
22
|
...props
|
|
18
23
|
}
|
|
19
24
|
),
|
|
20
|
-
/* @__PURE__ */ jsx(
|
|
25
|
+
indeterminate ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "pointer-events-none absolute inset-0 m-auto h-0.5 w-2 rounded-full bg-primary-foreground peer-disabled:bg-muted-foreground" }) : /* @__PURE__ */ jsx(
|
|
21
26
|
CheckIcon,
|
|
22
27
|
{
|
|
23
28
|
size: 12,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.js","sources":["../../../../../../src/v1/primitives/forms/Checkbox/Checkbox.tsx"],"sourcesContent":["import React, { forwardRef } from 'react'\r\nimport { CheckIcon } from '../../../foundations/icons/icons'\r\nimport { useField } from '../field'\r\n\r\nexport interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'> {\r\n /** Marca a caixa a vermelho (ex: aceitar os termos, por marcar ao submeter). */\r\n invalid?: boolean\r\n}\r\n\r\n/**\r\n * Caixa de marcar.\r\n *\r\n * Dentro de um [FormField](?path=/docs/v1-components-forms-formfield--docs) fica\r\n * ligada à etiqueta automaticamente. Fora dele, dar-lhe um `aria-label` ou\r\n * envolvê-la num `<label>`: sozinha não tem nome para os leitores de ecrã.\r\n *\r\n * **Aceita os atributos HTML do [<input type=\"checkbox\">](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/checkbox)**, com o mesmo comportamento: `checked`/`defaultChecked`, `onChange`, `required`, `disabled`, `name`, `value`, `ref`, ...\r\n * Só os próprios do V1 aparecem na tabela abaixo.\r\n * Diferenças: o `className` aplica-se à caixa à volta; o `type` é sempre `checkbox`.\r\n */\r\nconst Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(function Checkbox({ invalid, className = '', id, required, ...props }, ref) {\r\n const field = useField()\r\n return (\r\n <span className={`relative inline-flex size-4 shrink-0 ${className}`}>\r\n <input\r\n ref={
|
|
1
|
+
{"version":3,"file":"Checkbox.js","sources":["../../../../../../src/v1/primitives/forms/Checkbox/Checkbox.tsx"],"sourcesContent":["import React, { forwardRef, useEffect, useImperativeHandle, useRef } from 'react'\r\nimport { CheckIcon } from '../../../foundations/icons/icons'\r\nimport { useField } from '../field'\r\n\r\nexport interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'> {\r\n /** Marca a caixa a vermelho (ex: aceitar os termos, por marcar ao submeter). */\r\n invalid?: boolean\r\n /**\r\n * Meio marcada: um traço em vez do visto (ex: \"selecionar todos\" com só\r\n * algumas marcadas). Só o aspeto: ao clicar, o browser tira-o e a caixa passa\r\n * a marcada ou desmarcada pelo `onChange`, como sempre. Para leitores de ecrã é\r\n * \"parcialmente marcada\".\r\n */\r\n indeterminate?: boolean\r\n}\r\n\r\n/**\r\n * Caixa de marcar.\r\n *\r\n * Dentro de um [FormField](?path=/docs/v1-components-forms-formfield--docs) fica\r\n * ligada à etiqueta automaticamente. Fora dele, dar-lhe um `aria-label` ou\r\n * envolvê-la num `<label>`: sozinha não tem nome para os leitores de ecrã.\r\n *\r\n * **Aceita os atributos HTML do [<input type=\"checkbox\">](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/checkbox)**, com o mesmo comportamento: `checked`/`defaultChecked`, `onChange`, `required`, `disabled`, `name`, `value`, `ref`, ...\r\n * Só os próprios do V1 aparecem na tabela abaixo.\r\n * Diferenças: o `className` aplica-se à caixa à volta; o `type` é sempre `checkbox`.\r\n */\r\nconst Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(function Checkbox({ invalid, indeterminate = false, className = '', id, required, ...props }, ref) {\r\n const field = useField()\r\n // O meio-marcado não é atributo HTML, só propriedade do elemento: vai pela ref.\r\n const caixa = useRef<HTMLInputElement>(null)\r\n useImperativeHandle(ref, () => caixa.current!)\r\n // A cada render, e não só quando a prop muda: um clique tira-o no browser, e\r\n // se a app o mantiver, tem de voltar.\r\n useEffect(() => { if (caixa.current) caixa.current.indeterminate = indeterminate })\r\n return (\r\n <span className={`relative inline-flex size-4 shrink-0 ${className}`}>\r\n <input\r\n ref={caixa}\r\n type=\"checkbox\"\r\n id={id ?? field.id}\r\n required={required ?? field.required}\r\n aria-invalid={invalid || undefined}\r\n className={\r\n 'peer absolute inset-0 m-0 size-full cursor-pointer appearance-none rounded-sm border border-border bg-card outline-none ' +\r\n 'transition-[background-color,border-color,box-shadow] duration-150 ' +\r\n 'checked:border-primary checked:bg-primary indeterminate:border-primary indeterminate:bg-primary ' +\r\n 'focus-visible:ring-3 focus-visible:ring-primary/20 ' +\r\n 'aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/15 ' +\r\n 'disabled:cursor-not-allowed disabled:bg-muted disabled:checked:border-border disabled:checked:bg-muted disabled:indeterminate:border-border disabled:indeterminate:bg-muted'\r\n }\r\n {...props}\r\n />\r\n {indeterminate ? (\r\n <span aria-hidden className=\"pointer-events-none absolute inset-0 m-auto h-0.5 w-2 rounded-full bg-primary-foreground peer-disabled:bg-muted-foreground\" />\r\n ) : (\r\n <CheckIcon\r\n size={12}\r\n className=\"pointer-events-none absolute inset-0 m-auto hidden text-primary-foreground peer-checked:block peer-disabled:text-muted-foreground\"\r\n />\r\n )}\r\n </span>\r\n )\r\n})\r\n\r\nexport default Checkbox\r\n"],"names":["Checkbox"],"mappings":";;;;AA2BA,MAAM,WAAW,WAA4C,SAASA,UAAS,EAAE,SAAS,gBAAgB,OAAO,YAAY,IAAI,IAAI,UAAU,GAAG,MAAA,GAAS,KAAK;AAC9J,QAAM,QAAQ,SAAA;AAEd,QAAM,QAAQ,OAAyB,IAAI;AAC3C,sBAAoB,KAAK,MAAM,MAAM,OAAQ;AAG7C,YAAU,MAAM;AAAE,QAAI,MAAM,QAAS,OAAM,QAAQ,gBAAgB;AAAA,EAAc,CAAC;AAClF,SACE,qBAAC,QAAA,EAAK,WAAW,wCAAwC,SAAS,IAChE,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,IAAI,MAAM,MAAM;AAAA,QAChB,UAAU,YAAY,MAAM;AAAA,QAC5B,gBAAc,WAAW;AAAA,QACzB,WACE;AAAA,QAOD,GAAG;AAAA,MAAA;AAAA,IAAA;AAAA,IAEL,gBACC,oBAAC,QAAA,EAAK,eAAW,MAAC,WAAU,8HAA6H,IAEzJ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAM;AAAA,QACN,WAAU;AAAA,MAAA;AAAA,IAAA;AAAA,EACZ,GAEJ;AAEJ,CAAC;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LookupInput.js","sources":["../../../../../../src/v1/primitives/forms/LookupInput/LookupInput.tsx"],"sourcesContent":["import React from 'react'\r\nimport { SearchIcon } from '../../../foundations/icons/icons'\r\nimport { fieldClasses, readOnlyClasses, useField } from '../field'\r\n\r\nexport interface LookupInputProps {\r\n /** O que foi escolhido, como a app o quer mostrar (ex: \"PRJ-0001 - Projeto de exemplo\"). Vazio se nada. */\r\n value: string\r\n /** Chamado ao carregar na lupa: a app abre a sua pesquisa e, quando se escolhe algo, atualiza o `value`. */\r\n onLookup: () => void\r\n /** O que a lupa faz (ex: \"Pesquisar projeto\"). Lido pelos leitores de ecrã e mostrado ao passar o rato. */\r\n lookupLabel: string\r\n /** Texto quando não há nada escolhido (ex: \"Nenhum projeto\"). */\r\n placeholder?: string\r\n /** Marca o campo a vermelho (ex: obrigatório por escolher ao submeter). */\r\n invalid?: boolean\r\n disabled?: boolean\r\n id?: string\r\n /** Aplica-se à caixa à volta (para a largura, por exemplo). */\r\n className?: string\r\n}\r\n\r\n/**\r\n * Campo que **não se escreve**: o valor escolhe-se numa pesquisa, aberta pela\r\n * lupa ao lado (ex: escolher um projeto). A pesquisa é da app; este campo só\r\n * mostra o que foi escolhido.\r\n *\r\n * Não é como um `<input>` HTML: só aceita as props da tabela abaixo.\r\n */\r\nexport default function LookupInput({ value, onLookup, lookupLabel, placeholder, invalid, disabled, id, className = '' }: LookupInputProps) {\r\n const field = useField()\r\n return (\r\n <div className={`flex min-w-0 items-center gap-1.5 ${className}`}>\r\n <input\r\n id={id ?? field.id}\r\n readOnly\r\n required={field.required}\r\n disabled={disabled}\r\n value={value}\r\n placeholder={placeholder}\r\n aria-invalid={invalid || undefined}\r\n className={`h-control ${fieldClasses} ${readOnlyClasses}`}\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={onLookup}\r\n disabled={disabled}\r\n aria-label={lookupLabel}\r\n title={lookupLabel}\r\n className={\r\n 'flex h-control w-control flex-none cursor-pointer items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground ' +\r\n 'transition-colors duration-150 hover:border-primary/25 hover:bg-primary/5 hover:text-primary ' +\r\n 'focus-visible:border-primary/40 focus-visible:ring-3 focus-visible:ring-primary/10 focus-visible:outline-none ' +\r\n 'disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:border-border disabled:hover:bg-muted disabled:hover:text-muted-foreground'\r\n }\r\n >\r\n <SearchIcon size={14} />\r\n </button>\r\n </div>\r\n )\r\n}\r\n"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"LookupInput.js","sources":["../../../../../../src/v1/primitives/forms/LookupInput/LookupInput.tsx"],"sourcesContent":["import React from 'react'\r\nimport { SearchIcon } from '../../../foundations/icons/icons'\r\nimport { fieldClasses, readOnlyClasses, useField } from '../field'\r\n\r\nexport interface LookupInputProps {\r\n /** O que foi escolhido, como a app o quer mostrar (ex: \"PRJ-0001 - Projeto de exemplo\"). Vazio se nada. */\r\n value: string\r\n /** Chamado ao carregar na lupa: a app abre a sua pesquisa e, quando se escolhe algo, atualiza o `value`. */\r\n onLookup: () => void\r\n /** O que a lupa faz (ex: \"Pesquisar projeto\"). Lido pelos leitores de ecrã e mostrado ao passar o rato. */\r\n lookupLabel: string\r\n /** Texto quando não há nada escolhido (ex: \"Nenhum projeto\"). */\r\n placeholder?: string\r\n /** Marca o campo a vermelho (ex: obrigatório por escolher ao submeter). */\r\n invalid?: boolean\r\n disabled?: boolean\r\n id?: string\r\n /** Aplica-se à caixa à volta (para a largura, por exemplo). */\r\n className?: string\r\n}\r\n\r\n/**\r\n * Campo que **não se escreve**: o valor escolhe-se numa pesquisa, aberta pela\r\n * lupa ao lado (ex: escolher um projeto). A pesquisa é da app; este campo só\r\n * mostra o que foi escolhido.\r\n *\r\n * Dentro de um [FormField](?path=/docs/v1-components-forms-formfield--docs) fica\r\n * ligado à etiqueta automaticamente.\r\n *\r\n * Não é como um `<input>` HTML: só aceita as props da tabela abaixo.\r\n */\r\nexport default function LookupInput({ value, onLookup, lookupLabel, placeholder, invalid, disabled, id, className = '' }: LookupInputProps) {\r\n const field = useField()\r\n return (\r\n <div className={`flex min-w-0 items-center gap-1.5 ${className}`}>\r\n <input\r\n id={id ?? field.id}\r\n readOnly\r\n required={field.required}\r\n disabled={disabled}\r\n value={value}\r\n placeholder={placeholder}\r\n aria-invalid={invalid || undefined}\r\n className={`h-control ${fieldClasses} ${readOnlyClasses}`}\r\n />\r\n <button\r\n type=\"button\"\r\n onClick={onLookup}\r\n disabled={disabled}\r\n aria-label={lookupLabel}\r\n title={lookupLabel}\r\n className={\r\n 'flex h-control w-control flex-none cursor-pointer items-center justify-center rounded-lg border border-border bg-muted text-muted-foreground ' +\r\n 'transition-colors duration-150 hover:border-primary/25 hover:bg-primary/5 hover:text-primary ' +\r\n 'focus-visible:border-primary/40 focus-visible:ring-3 focus-visible:ring-primary/10 focus-visible:outline-none ' +\r\n 'disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:border-border disabled:hover:bg-muted disabled:hover:text-muted-foreground'\r\n }\r\n >\r\n <SearchIcon size={14} />\r\n </button>\r\n </div>\r\n )\r\n}\r\n"],"names":[],"mappings":";;;AA+BA,SAAwB,YAAY,EAAE,OAAO,UAAU,aAAa,aAAa,SAAS,UAAU,IAAI,YAAY,GAAA,GAAwB;AAC1I,QAAM,QAAQ,SAAA;AACd,SACE,qBAAC,OAAA,EAAI,WAAW,qCAAqC,SAAS,IAC5D,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,IAAI,MAAM,MAAM;AAAA,QAChB,UAAQ;AAAA,QACR,UAAU,MAAM;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA,gBAAc,WAAW;AAAA,QACzB,WAAW,aAAa,YAAY,IAAI,eAAe;AAAA,MAAA;AAAA,IAAA;AAAA,IAEzD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT;AAAA,QACA,cAAY;AAAA,QACZ,OAAO;AAAA,QACP,WACE;AAAA,QAMF,UAAA,oBAAC,YAAA,EAAW,MAAM,GAAA,CAAI;AAAA,MAAA;AAAA,IAAA;AAAA,EACxB,GACF;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectInput.js","sources":["../../../../../../src/v1/primitives/forms/SelectInput/SelectInput.tsx"],"sourcesContent":["import React, { forwardRef } from 'react'\r\nimport { ChevronDownIcon } from '../../../foundations/icons/icons'\r\nimport { fieldClasses, useField } from '../field'\r\n\r\nexport interface SelectInputProps extends React.SelectHTMLAttributes<HTMLSelectElement> {\r\n /** Marca o campo a vermelho (ex: obrigatório por escolher ao submeter). */\r\n invalid?: boolean\r\n /** Texto da primeira opção, vazia (ex: \"Selecionar\"). */\r\n placeholder?: string\r\n}\r\n\r\n/**\r\n * Lista de escolha (o `<select>` do browser, com o aspeto dos outros campos).\r\n * As opções são `<option>` como num `<select>` normal.\r\n *\r\n * O `className` aplica-se à caixa à volta (para a largura, por exemplo).\r\n *\r\n * **Aceita os atributos HTML do [<select>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/select)**, com o mesmo comportamento: `value`/`onChange`, `required`, `disabled`, `name`, `ref`, ...\r\n * Só os próprios do V1 aparecem na tabela abaixo.\r\n * Diferença: `placeholder` acrescenta uma primeira opção vazia (o `<select>` HTML não tem placeholder).\r\n */\r\nconst SelectInput = forwardRef<HTMLSelectElement, SelectInputProps>(function SelectInput(\r\n { invalid, placeholder, className = '', id, required, children, ...props },\r\n ref,\r\n) {\r\n const field = useField()\r\n return (\r\n <div className={`relative min-w-0 ${className}`}>\r\n <select\r\n ref={ref}\r\n id={id ?? field.id}\r\n required={required ?? field.required}\r\n aria-invalid={invalid || undefined}\r\n className={`h-control cursor-pointer appearance-none pr-7 ${fieldClasses}`}\r\n {...props}\r\n >\r\n {placeholder !== undefined && <option value=\"\">{placeholder}</option>}\r\n {children}\r\n </select>\r\n <ChevronDownIcon size={14} className=\"pointer-events-none absolute top-1/2 right-2 -translate-y-1/2 text-muted-foreground\" />\r\n </div>\r\n )\r\n})\r\n\r\nexport default SelectInput\r\n"],"names":["SelectInput"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"SelectInput.js","sources":["../../../../../../src/v1/primitives/forms/SelectInput/SelectInput.tsx"],"sourcesContent":["import React, { forwardRef } from 'react'\r\nimport { ChevronDownIcon } from '../../../foundations/icons/icons'\r\nimport { fieldClasses, useField } from '../field'\r\n\r\nexport interface SelectInputProps extends React.SelectHTMLAttributes<HTMLSelectElement> {\r\n /** Marca o campo a vermelho (ex: obrigatório por escolher ao submeter). */\r\n invalid?: boolean\r\n /** Texto da primeira opção, vazia (ex: \"Selecionar\"). */\r\n placeholder?: string\r\n}\r\n\r\n/**\r\n * Lista de escolha (o `<select>` do browser, com o aspeto dos outros campos).\r\n * As opções são `<option>` como num `<select>` normal.\r\n *\r\n * O `className` aplica-se à caixa à volta (para a largura, por exemplo).\r\n *\r\n * Dentro de um [FormField](?path=/docs/v1-components-forms-formfield--docs) fica\r\n * ligado à etiqueta automaticamente.\r\n *\r\n * **Aceita os atributos HTML do [<select>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/select)**, com o mesmo comportamento: `value`/`onChange`, `required`, `disabled`, `name`, `ref`, ...\r\n * Só os próprios do V1 aparecem na tabela abaixo.\r\n * Diferença: `placeholder` acrescenta uma primeira opção vazia (o `<select>` HTML não tem placeholder).\r\n */\r\nconst SelectInput = forwardRef<HTMLSelectElement, SelectInputProps>(function SelectInput(\r\n { invalid, placeholder, className = '', id, required, children, ...props },\r\n ref,\r\n) {\r\n const field = useField()\r\n return (\r\n <div className={`relative min-w-0 ${className}`}>\r\n <select\r\n ref={ref}\r\n id={id ?? field.id}\r\n required={required ?? field.required}\r\n aria-invalid={invalid || undefined}\r\n className={`h-control cursor-pointer appearance-none pr-7 ${fieldClasses}`}\r\n {...props}\r\n >\r\n {placeholder !== undefined && <option value=\"\">{placeholder}</option>}\r\n {children}\r\n </select>\r\n <ChevronDownIcon size={14} className=\"pointer-events-none absolute top-1/2 right-2 -translate-y-1/2 text-muted-foreground\" />\r\n </div>\r\n )\r\n})\r\n\r\nexport default SelectInput\r\n"],"names":["SelectInput"],"mappings":";;;;AAwBA,MAAM,cAAc,WAAgD,SAASA,aAC3E,EAAE,SAAS,aAAa,YAAY,IAAI,IAAI,UAAU,UAAU,GAAG,MAAA,GACnE,KACA;AACA,QAAM,QAAQ,SAAA;AACd,SACE,qBAAC,OAAA,EAAI,WAAW,oBAAoB,SAAS,IAC3C,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,IAAI,MAAM,MAAM;AAAA,QAChB,UAAU,YAAY,MAAM;AAAA,QAC5B,gBAAc,WAAW;AAAA,QACzB,WAAW,iDAAiD,YAAY;AAAA,QACvE,GAAG;AAAA,QAEH,UAAA;AAAA,UAAA,gBAAgB,UAAa,oBAAC,UAAA,EAAO,OAAM,IAAI,UAAA,aAAY;AAAA,UAC3D;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAEH,oBAAC,iBAAA,EAAgB,MAAM,IAAI,WAAU,sFAAA,CAAsF;AAAA,EAAA,GAC7H;AAEJ,CAAC;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextArea.js","sources":["../../../../../../src/v1/primitives/forms/TextArea/TextArea.tsx"],"sourcesContent":["import React, { forwardRef, useRef, useState } from 'react'\r\nimport { fieldClasses, readOnlyClasses, useField } from '../field'\r\n\r\nexport interface TextAreaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {\r\n /** Marca o campo a vermelho (ex: obrigatório por preencher ao submeter). */\r\n invalid?: boolean\r\n /** Mostra no canto quantos caracteres tem. Com `maxLength`, \"usados/máximo\", e fica âmbar perto do limite. */\r\n counter?: boolean\r\n /**\r\n * Deixar o texto passar o `maxLength`, e como o mostrar:\r\n * - sem `overflow` (por omissão): não passa. Tentar escrever ou colar a mais\r\n * avisa (`limitReachedLabel`, `truncatedLabel`).\r\n * - `warning`: passa, com aviso a âmbar. O campo continua válido.\r\n * - `error`: passa, com aviso a vermelho, e o campo fica inválido.\r\n *\r\n * Com `overflow`, o texto não é cortado: a app tem de verificar o tamanho\r\n * antes de guardar.\r\n */\r\n overflow?: 'warning' | 'error'\r\n /** Sem `overflow`: aviso ao tentar escrever com o campo cheio. Por omissão: \"Chegou ao limite de {maxLength} caracteres.\" */\r\n limitReachedLabel?: string\r\n /** Sem `overflow`: aviso quando um texto colado é cortado. Por omissão: \"Texto cortado: só cabem {maxLength} caracteres.\" */\r\n truncatedLabel?: string\r\n /** Com `overflow`: aviso enquanto o texto passa o limite. Por omissão: \"{a mais} caracteres a mais (máximo {maxLength}).\" */\r\n overflowLabel?: (excess: number, max: number) => string\r\n}\r\n\r\n/**\r\n * Texto em várias linhas. Pode ser esticado na vertical.\r\n *\r\n * Com `counter`, mostra quantos caracteres tem (e o máximo, se houver `maxLength`).\r\n * Com `maxLength`, o texto não passa do limite e o campo avisa quando se tenta\r\n * escrever ou colar a mais. Com `overflow`, pode passar, como aviso ou erro.\r\n *\r\n * **Aceita os atributos HTML do [<textarea>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/textarea)**, com o mesmo comportamento: `value`/`onChange`, `required`, `disabled`, `readOnly`, `name`, `placeholder`, `maxLength`, `minLength`, `ref`, ...\r\n * Só os próprios do V1 aparecem na tabela abaixo.\r\n * Diferenças: o `className` aplica-se à caixa à volta; com `overflow`, o `maxLength` deixa de ser imposto.\r\n */\r\nconst TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(function TextArea(\r\n {\r\n invalid,\r\n counter,\r\n overflow,\r\n limitReachedLabel,\r\n truncatedLabel,\r\n overflowLabel,\r\n maxLength: max,\r\n className = '',\r\n id,\r\n required,\r\n rows = 3,\r\n onChange,\r\n onPaste,\r\n onKeyDown,\r\n ...props\r\n },\r\n ref,\r\n) {\r\n const field = useField()\r\n // Para o contador sem `value` controlado pela app.\r\n const [typed, setTyped] = useState(String(props.defaultValue ?? ''))\r\n // Sem overflow: a última tentativa de passar o limite, até à edição seguinte.\r\n const [blocked, setBlocked] = useState<null | 'typed' | 'pasted'>(null)\r\n // O onChange que vem logo a seguir a um paste cortado não apaga o aviso.\r\n const pasting = useRef(false)\r\n const length = props.value !== undefined ? String(props.value).length : typed.length\r\n const limited = max !== undefined && !overflow\r\n const excess = max !== undefined && overflow ? Math.max(0, length - max) : 0\r\n const isError = excess > 0 && overflow === 'error'\r\n\r\n // Espaço livre se o texto selecionado for substituído.\r\n const room = (el: HTMLTextAreaElement) => max! - (el.value.length - (el.selectionEnd - el.selectionStart))\r\n\r\n const counterColor = isError\r\n ? 'text-destructive'\r\n : excess > 0 || blocked || (max !== undefined && length >= max * 0.87)\r\n ? 'text-risco'\r\n : length > 0\r\n ? 'text-muted-foreground'\r\n : 'text-muted-foreground/70'\r\n\r\n const message =\r\n blocked === 'pasted'\r\n ? (truncatedLabel ?? `Texto cortado: só cabem ${max} caracteres.`)\r\n : blocked === 'typed'\r\n ? (limitReachedLabel ?? `Chegou ao limite de ${max} caracteres.`)\r\n : excess > 0\r\n ? (overflowLabel?.(excess, max!) ?? `${excess} ${excess === 1 ? 'carácter' : 'caracteres'} a mais (máximo ${max}).`)\r\n : null\r\n\r\n return (\r\n <div className={`min-w-0 ${className}`}>\r\n <div className=\"relative\">\r\n <textarea\r\n ref={ref}\r\n id={id ?? field.id}\r\n required={required ?? field.required}\r\n rows={rows}\r\n // Só sem overflow o browser impõe o limite.\r\n maxLength={limited ? max : undefined}\r\n aria-invalid={invalid || isError || undefined}\r\n onKeyDown={(e) => {\r\n // Tecla que escreveria algo, com o campo cheio: o browser ignora-a em silêncio.\r\n const writes = (e.key.length === 1 || e.key === 'Enter') && !e.ctrlKey && !e.metaKey && !e.altKey\r\n if (limited && writes && room(e.currentTarget) <= 0) setBlocked('typed')\r\n onKeyDown?.(e)\r\n }}\r\n onPaste={(e) => {\r\n if (limited) {\r\n const free = room(e.currentTarget)\r\n const cut = e.clipboardData.getData('text').length > free\r\n // Campo já cheio: o browser não insere nada e não há onChange a seguir.\r\n pasting.current = cut && free > 0\r\n setBlocked(cut ? 'pasted' : null)\r\n }\r\n onPaste?.(e)\r\n }}\r\n onChange={(e) => {\r\n setTyped(e.target.value)\r\n if (pasting.current) pasting.current = false\r\n else setBlocked(null)\r\n onChange?.(e)\r\n }}\r\n className={`min-h-[62px] resize-y py-1.5 leading-normal ${counter ? 'pb-6' : ''} ${fieldClasses} ${readOnlyClasses}`}\r\n {...props}\r\n />\r\n {counter && (\r\n <span aria-hidden className={`pointer-events-none absolute right-2.5 bottom-2 rounded-full bg-muted px-1.5 py-px text-caption font-medium ${counterColor}`}>\r\n {max !== undefined ? `${length}/${max}` : length}\r\n </span>\r\n )}\r\n </div>\r\n {message && (\r\n <p role=\"status\" className={`m-0 mt-1 text-caption font-medium ${isError ? 'text-destructive' : 'text-risco'}`}>\r\n {message}\r\n </p>\r\n )}\r\n </div>\r\n )\r\n})\r\n\r\nexport default TextArea\r\n"],"names":["TextArea"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"TextArea.js","sources":["../../../../../../src/v1/primitives/forms/TextArea/TextArea.tsx"],"sourcesContent":["import React, { forwardRef, useRef, useState } from 'react'\r\nimport { fieldClasses, readOnlyClasses, useField } from '../field'\r\n\r\nexport interface TextAreaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {\r\n /** Marca o campo a vermelho (ex: obrigatório por preencher ao submeter). */\r\n invalid?: boolean\r\n /** Mostra no canto quantos caracteres tem. Com `maxLength`, \"usados/máximo\", e fica âmbar perto do limite. */\r\n counter?: boolean\r\n /**\r\n * Deixar o texto passar o `maxLength`, e como o mostrar:\r\n * - sem `overflow` (por omissão): não passa. Tentar escrever ou colar a mais\r\n * avisa (`limitReachedLabel`, `truncatedLabel`).\r\n * - `warning`: passa, com aviso a âmbar. O campo continua válido.\r\n * - `error`: passa, com aviso a vermelho, e o campo fica inválido.\r\n *\r\n * Com `overflow`, o texto não é cortado: a app tem de verificar o tamanho\r\n * antes de guardar.\r\n */\r\n overflow?: 'warning' | 'error'\r\n /** Sem `overflow`: aviso ao tentar escrever com o campo cheio. Por omissão: \"Chegou ao limite de {maxLength} caracteres.\" */\r\n limitReachedLabel?: string\r\n /** Sem `overflow`: aviso quando um texto colado é cortado. Por omissão: \"Texto cortado: só cabem {maxLength} caracteres.\" */\r\n truncatedLabel?: string\r\n /** Com `overflow`: aviso enquanto o texto passa o limite. Por omissão: \"{a mais} caracteres a mais (máximo {maxLength}).\" */\r\n overflowLabel?: (excess: number, max: number) => string\r\n}\r\n\r\n/**\r\n * Texto em várias linhas. Pode ser esticado na vertical.\r\n *\r\n * Com `counter`, mostra quantos caracteres tem (e o máximo, se houver `maxLength`).\r\n * Com `maxLength`, o texto não passa do limite e o campo avisa quando se tenta\r\n * escrever ou colar a mais. Com `overflow`, pode passar, como aviso ou erro.\r\n *\r\n * Dentro de um [FormField](?path=/docs/v1-components-forms-formfield--docs) fica\r\n * ligado à etiqueta automaticamente.\r\n *\r\n * **Aceita os atributos HTML do [<textarea>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/textarea)**, com o mesmo comportamento: `value`/`onChange`, `required`, `disabled`, `readOnly`, `name`, `placeholder`, `maxLength`, `minLength`, `ref`, ...\r\n * Só os próprios do V1 aparecem na tabela abaixo.\r\n * Diferenças: o `className` aplica-se à caixa à volta; com `overflow`, o `maxLength` deixa de ser imposto.\r\n */\r\nconst TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(function TextArea(\r\n {\r\n invalid,\r\n counter,\r\n overflow,\r\n limitReachedLabel,\r\n truncatedLabel,\r\n overflowLabel,\r\n maxLength: max,\r\n className = '',\r\n id,\r\n required,\r\n rows = 3,\r\n onChange,\r\n onPaste,\r\n onKeyDown,\r\n ...props\r\n },\r\n ref,\r\n) {\r\n const field = useField()\r\n // Para o contador sem `value` controlado pela app.\r\n const [typed, setTyped] = useState(String(props.defaultValue ?? ''))\r\n // Sem overflow: a última tentativa de passar o limite, até à edição seguinte.\r\n const [blocked, setBlocked] = useState<null | 'typed' | 'pasted'>(null)\r\n // O onChange que vem logo a seguir a um paste cortado não apaga o aviso.\r\n const pasting = useRef(false)\r\n const length = props.value !== undefined ? String(props.value).length : typed.length\r\n const limited = max !== undefined && !overflow\r\n const excess = max !== undefined && overflow ? Math.max(0, length - max) : 0\r\n const isError = excess > 0 && overflow === 'error'\r\n\r\n // Espaço livre se o texto selecionado for substituído.\r\n const room = (el: HTMLTextAreaElement) => max! - (el.value.length - (el.selectionEnd - el.selectionStart))\r\n\r\n const counterColor = isError\r\n ? 'text-destructive'\r\n : excess > 0 || blocked || (max !== undefined && length >= max * 0.87)\r\n ? 'text-risco'\r\n : length > 0\r\n ? 'text-muted-foreground'\r\n : 'text-muted-foreground/70'\r\n\r\n const message =\r\n blocked === 'pasted'\r\n ? (truncatedLabel ?? `Texto cortado: só cabem ${max} caracteres.`)\r\n : blocked === 'typed'\r\n ? (limitReachedLabel ?? `Chegou ao limite de ${max} caracteres.`)\r\n : excess > 0\r\n ? (overflowLabel?.(excess, max!) ?? `${excess} ${excess === 1 ? 'carácter' : 'caracteres'} a mais (máximo ${max}).`)\r\n : null\r\n\r\n return (\r\n <div className={`min-w-0 ${className}`}>\r\n <div className=\"relative\">\r\n <textarea\r\n ref={ref}\r\n id={id ?? field.id}\r\n required={required ?? field.required}\r\n rows={rows}\r\n // Só sem overflow o browser impõe o limite.\r\n maxLength={limited ? max : undefined}\r\n aria-invalid={invalid || isError || undefined}\r\n onKeyDown={(e) => {\r\n // Tecla que escreveria algo, com o campo cheio: o browser ignora-a em silêncio.\r\n const writes = (e.key.length === 1 || e.key === 'Enter') && !e.ctrlKey && !e.metaKey && !e.altKey\r\n if (limited && writes && room(e.currentTarget) <= 0) setBlocked('typed')\r\n onKeyDown?.(e)\r\n }}\r\n onPaste={(e) => {\r\n if (limited) {\r\n const free = room(e.currentTarget)\r\n const cut = e.clipboardData.getData('text').length > free\r\n // Campo já cheio: o browser não insere nada e não há onChange a seguir.\r\n pasting.current = cut && free > 0\r\n setBlocked(cut ? 'pasted' : null)\r\n }\r\n onPaste?.(e)\r\n }}\r\n onChange={(e) => {\r\n setTyped(e.target.value)\r\n if (pasting.current) pasting.current = false\r\n else setBlocked(null)\r\n onChange?.(e)\r\n }}\r\n className={`min-h-[62px] resize-y py-1.5 leading-normal ${counter ? 'pb-6' : ''} ${fieldClasses} ${readOnlyClasses}`}\r\n {...props}\r\n />\r\n {counter && (\r\n <span aria-hidden className={`pointer-events-none absolute right-2.5 bottom-2 rounded-full bg-muted px-1.5 py-px text-caption font-medium ${counterColor}`}>\r\n {max !== undefined ? `${length}/${max}` : length}\r\n </span>\r\n )}\r\n </div>\r\n {message && (\r\n <p role=\"status\" className={`m-0 mt-1 text-caption font-medium ${isError ? 'text-destructive' : 'text-risco'}`}>\r\n {message}\r\n </p>\r\n )}\r\n </div>\r\n )\r\n})\r\n\r\nexport default TextArea\r\n"],"names":["TextArea"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import Checkbox from "../../forms/Checkbox/Checkbox.js";
|
|
3
3
|
function ListItem({
|
|
4
4
|
title,
|
|
5
5
|
code,
|
|
@@ -15,7 +15,7 @@ function ListItem({
|
|
|
15
15
|
const fundo = active ? "bg-proef-blue/8" : checked ? "bg-slate-50" : "hover:bg-slate-50";
|
|
16
16
|
return /* @__PURE__ */ jsxs("li", { className: `v1-reset relative flex list-none items-start gap-2.5 border-b border-slate-100 px-3 py-2.5 transition-colors ${fundo} ${className}`, children: [
|
|
17
17
|
active && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "absolute inset-y-0 left-0 w-0.5 bg-proef-blue" }),
|
|
18
|
-
onCheckedChange && /* @__PURE__ */ jsx(
|
|
18
|
+
onCheckedChange && /* @__PURE__ */ jsx(Checkbox, { checked, onChange: (e) => onCheckedChange(e.target.checked), "aria-label": checkboxLabel, className: "z-10 mt-0.5" }),
|
|
19
19
|
/* @__PURE__ */ jsxs(
|
|
20
20
|
"button",
|
|
21
21
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListItem.js","sources":["../../../../../../src/v1/primitives/lists/ListItem/ListItem.tsx"],"sourcesContent":["import React from 'react'\r\nimport
|
|
1
|
+
{"version":3,"file":"ListItem.js","sources":["../../../../../../src/v1/primitives/lists/ListItem/ListItem.tsx"],"sourcesContent":["import React from 'react'\r\nimport Checkbox from '../../forms/Checkbox/Checkbox'\r\n\r\n/** O que se mostra num ListItem: o resto (ativo, marcado) é estado. */\r\nexport interface ListItemContent {\r\n /** A linha principal (ex: a descrição). Numa linha só, cortada com \"…\" se não couber. */\r\n title: React.ReactNode\r\n /** Por cima do título, pequeno e em letra de máquina (ex: o número ou código). */\r\n code?: React.ReactNode\r\n /** A primeira linha: etiquetas e avisos (ex: a categoria). */\r\n badges?: React.ReactNode\r\n /** Por baixo do título: o resto do que se quer ver de relance (local, data, indicadores). */\r\n meta?: React.ReactNode\r\n}\r\n\r\nexport interface ListItemProps extends ListItemContent {\r\n /** O que está aberto ao lado (fica realçado). */\r\n active?: boolean\r\n /** Ao clicar (ou Enter/Espaço com o foco nele): normalmente, abri-lo. */\r\n onClick?: () => void\r\n /** Marcado. Só há caixa de marcar se vier com `onCheckedChange`. */\r\n checked?: boolean\r\n onCheckedChange?: (checked: boolean) => void\r\n /** O nome da caixa de marcar, para leitores de ecrã (ex: \"Marcar P-020000\"). */\r\n checkboxLabel?: string\r\n className?: string\r\n}\r\n\r\n/**\r\n * Uma linha de uma lista para escolher: o cartão das listas do\r\n * [ListFinder](?path=/docs/v1-components-lists-listfinder--docs).\r\n *\r\n * Não sabe o que mostra: a app dá as partes (etiquetas, código, título,\r\n * detalhes) e o ListItem arruma-as sempre da mesma forma. Com\r\n * `onCheckedChange` leva uma caixa à esquerda, para marcar vários (um\r\n * [Checkbox](?path=/docs/v1-primitives-forms-checkbox--docs)).\r\n *\r\n * É um `<li>`: vai dentro de um `<ul>`.\r\n */\r\nexport default function ListItem({\r\n title, code, badges, meta, active = false, onClick, checked = false, onCheckedChange, checkboxLabel, className = '',\r\n}: ListItemProps) {\r\n const fundo = active ? 'bg-proef-blue/8' : checked ? 'bg-slate-50' : 'hover:bg-slate-50'\r\n return (\r\n <li className={`v1-reset relative flex list-none items-start gap-2.5 border-b border-slate-100 px-3 py-2.5 transition-colors ${fundo} ${className}`}>\r\n {/* O que está aberto leva também uma risca à esquerda: com o fundo só,\r\n perdia-se ao lado das linhas marcadas. */}\r\n {active && <span aria-hidden className=\"absolute inset-y-0 left-0 w-0.5 bg-proef-blue\" />}\r\n {onCheckedChange && (\r\n <Checkbox checked={checked} onChange={e => onCheckedChange(e.target.checked)} aria-label={checkboxLabel} className=\"z-10 mt-0.5\" />\r\n )}\r\n {/* O botão cobre a linha toda (o ::after), para se clicar em qualquer\r\n sítio; a caixa de marcar fica por cima dele. */}\r\n <button\r\n type=\"button\"\r\n onClick={onClick}\r\n aria-current={active || undefined}\r\n className=\"min-w-0 flex-1 text-left outline-none after:absolute after:inset-0 focus-visible:after:outline-2 focus-visible:after:-outline-offset-2 focus-visible:after:outline-primary\"\r\n >\r\n {badges && <span className=\"mb-1 flex flex-wrap items-center gap-1.5\">{badges}</span>}\r\n {code && <span className=\"block font-mono text-micro text-slate-400\">{code}</span>}\r\n <span className={`block truncate text-control ${active ? 'font-semibold text-slate-900' : 'text-slate-800'}`}>{title}</span>\r\n {meta && <span className=\"mt-0.5 flex flex-wrap items-center gap-x-2.5 gap-y-0.5 text-caption text-slate-500\">{meta}</span>}\r\n </button>\r\n </li>\r\n )\r\n}\r\n"],"names":[],"mappings":";;AAuCA,SAAwB,SAAS;AAAA,EAC/B;AAAA,EAAO;AAAA,EAAM;AAAA,EAAQ;AAAA,EAAM,SAAS;AAAA,EAAO;AAAA,EAAS,UAAU;AAAA,EAAO;AAAA,EAAiB;AAAA,EAAe,YAAY;AACnH,GAAkB;AAChB,QAAM,QAAQ,SAAS,oBAAoB,UAAU,gBAAgB;AACrE,8BACG,MAAA,EAAG,WAAW,gHAAgH,KAAK,IAAI,SAAS,IAG9I,UAAA;AAAA,IAAA,UAAU,oBAAC,QAAA,EAAK,eAAW,MAAC,WAAU,iDAAgD;AAAA,IACtF,mBACC,oBAAC,UAAA,EAAS,SAAkB,UAAU,CAAA,MAAK,gBAAgB,EAAE,OAAO,OAAO,GAAG,cAAY,eAAe,WAAU,eAAc;AAAA,IAInI;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL;AAAA,QACA,gBAAc,UAAU;AAAA,QACxB,WAAU;AAAA,QAET,UAAA;AAAA,UAAA,UAAU,oBAAC,QAAA,EAAK,WAAU,4CAA4C,UAAA,QAAO;AAAA,UAC7E,QAAQ,oBAAC,QAAA,EAAK,WAAU,6CAA6C,UAAA,MAAK;AAAA,UAC3E,oBAAC,UAAK,WAAW,+BAA+B,SAAS,iCAAiC,gBAAgB,IAAK,UAAA,MAAA,CAAM;AAAA,UACpH,QAAQ,oBAAC,QAAA,EAAK,WAAU,sFAAsF,UAAA,KAAA,CAAK;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EACtH,GACF;AAEJ;"}
|