@proef/common-ui 2.2.0 → 2.2.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/dist/esm/index.js +26 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/legacy/components/molecules/DataTable/DataTable.js +1 -1
- package/dist/esm/legacy/components/molecules/DataTable/DataTable.js.map +1 -1
- package/dist/esm/v1/components/lists/ListFinder/ListFinder.js +111 -54
- package/dist/esm/v1/components/lists/ListFinder/ListFinder.js.map +1 -1
- package/dist/esm/v1/components/tables/Table/ColumnFilter.js +14 -14
- package/dist/esm/v1/components/tables/Table/ColumnFilter.js.map +1 -1
- package/dist/esm/v1/components/tables/Table/Table.js +9 -8
- package/dist/esm/v1/components/tables/Table/Table.js.map +1 -1
- package/dist/esm/v1/foundations/icons/icons.js +49 -0
- package/dist/esm/v1/foundations/icons/icons.js.map +1 -1
- package/dist/esm/v1/primitives/display/RichText/RichText.js +12 -0
- package/dist/esm/v1/primitives/display/RichText/RichText.js.map +1 -0
- package/dist/esm/v1/primitives/display/RichText/utils.js +56 -0
- package/dist/esm/v1/primitives/display/RichText/utils.js.map +1 -0
- package/dist/esm/v1/primitives/forms/RichTextEditor/RichTextEditor.js +253 -0
- package/dist/esm/v1/primitives/forms/RichTextEditor/RichTextEditor.js.map +1 -0
- package/dist/esm/v1/primitives/lists/ListItem/ListItem.js +45 -11
- 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/lists/ListFinder/ListFinder.d.ts +31 -5
- package/dist/types/v1/components/tables/Table/Table.d.ts +9 -1
- package/dist/types/v1/foundations/icons/icons.d.ts +20 -0
- package/dist/types/v1/index.d.ts +8 -3
- package/dist/types/v1/primitives/display/RichText/RichText.d.ts +17 -0
- package/dist/types/v1/primitives/display/RichText/utils.d.ts +22 -0
- package/dist/types/v1/primitives/forms/RichTextEditor/RichTextEditor.d.ts +64 -0
- package/dist/types/v1/primitives/lists/ListItem/ListItem.d.ts +39 -8
- package/package.json +6 -1
|
@@ -1,39 +1,73 @@
|
|
|
1
|
-
import { jsxs, jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment as Fragment$1 } from "react";
|
|
2
3
|
import Checkbox from "../../forms/Checkbox/Checkbox.js";
|
|
4
|
+
const LINHA_ESBATIDA = "bg-[linear-gradient(to_right,transparent,var(--color-slate-200)_15%,var(--color-slate-200)_85%,transparent)] bg-[length:100%_1px] bg-bottom bg-no-repeat last:bg-none";
|
|
5
|
+
const semAcento = (c) => c.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase();
|
|
6
|
+
function HighlightText({ text, terms }) {
|
|
7
|
+
const termos = (terms ?? []).map((t) => [...t].map(semAcento).join("")).filter(Boolean);
|
|
8
|
+
if (!termos.length) return /* @__PURE__ */ jsx(Fragment, { children: text });
|
|
9
|
+
const alvo = [...text].map((c) => semAcento(c).charAt(0) || c).join("");
|
|
10
|
+
const marcado = new Array(alvo.length).fill(false);
|
|
11
|
+
for (const t of termos) {
|
|
12
|
+
for (let i = alvo.indexOf(t); i >= 0; i = alvo.indexOf(t, i + 1)) {
|
|
13
|
+
for (let k = i; k < i + t.length; k++) marcado[k] = true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (!marcado.some(Boolean)) return /* @__PURE__ */ jsx(Fragment, { children: text });
|
|
17
|
+
const chars = [...text];
|
|
18
|
+
const partes = [];
|
|
19
|
+
chars.forEach((c, i) => {
|
|
20
|
+
const ultimo = partes[partes.length - 1];
|
|
21
|
+
if (ultimo && ultimo.hit === marcado[i]) ultimo.txt += c;
|
|
22
|
+
else partes.push({ txt: c, hit: marcado[i] });
|
|
23
|
+
});
|
|
24
|
+
return /* @__PURE__ */ jsx(Fragment, { children: partes.map((p, i) => p.hit ? /* @__PURE__ */ jsx("mark", { className: "rounded-sm bg-amber-200 font-bold text-amber-900", children: p.txt }, i) : /* @__PURE__ */ jsx(Fragment$1, { children: p.txt }, i)) });
|
|
25
|
+
}
|
|
3
26
|
function ListItem({
|
|
4
27
|
title,
|
|
5
28
|
code,
|
|
6
29
|
badges,
|
|
7
30
|
meta,
|
|
31
|
+
tag,
|
|
32
|
+
aside,
|
|
8
33
|
active = false,
|
|
9
34
|
onClick,
|
|
10
35
|
checked = false,
|
|
11
36
|
onCheckedChange,
|
|
12
37
|
checkboxLabel,
|
|
38
|
+
highlight,
|
|
13
39
|
className = ""
|
|
14
40
|
}) {
|
|
15
|
-
const fundo = active ? "bg-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
onCheckedChange && /* @__PURE__ */
|
|
41
|
+
const fundo = active ? "bg-blue-50" : checked ? "bg-proef-turquoise/5" : "hover:bg-slate-50";
|
|
42
|
+
const realcar = (n) => typeof n === "string" ? /* @__PURE__ */ jsx(HighlightText, { text: n, terms: highlight }) : n;
|
|
43
|
+
return /* @__PURE__ */ jsxs("li", { className: `v1-reset relative flex list-none items-start gap-1.5 px-3 py-3 transition-colors ${LINHA_ESBATIDA} ${fundo} ${className}`, children: [
|
|
44
|
+
onCheckedChange && /* @__PURE__ */ jsxs("span", { className: "flex w-7 shrink-0 flex-col items-center gap-1", children: [
|
|
45
|
+
/* @__PURE__ */ jsx(Checkbox, { checked, onChange: (e) => onCheckedChange(e.target.checked), "aria-label": checkboxLabel, className: "z-10 mt-0.5" }),
|
|
46
|
+
tag && /* @__PURE__ */ jsx("span", { className: "text-[8px] leading-none font-semibold text-slate-400", children: tag })
|
|
47
|
+
] }),
|
|
19
48
|
/* @__PURE__ */ jsxs(
|
|
20
49
|
"button",
|
|
21
50
|
{
|
|
22
51
|
type: "button",
|
|
23
52
|
onClick,
|
|
24
53
|
"aria-current": active || void 0,
|
|
25
|
-
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",
|
|
54
|
+
className: "min-w-0 flex-1 space-y-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",
|
|
26
55
|
children: [
|
|
27
|
-
badges && /* @__PURE__ */
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
56
|
+
(code || badges) && /* @__PURE__ */ jsxs("span", { className: "flex flex-wrap items-center gap-x-2 gap-y-0.5 leading-tight", children: [
|
|
57
|
+
code && /* @__PURE__ */ jsx("span", { className: "font-mono text-xs font-semibold text-slate-700", children: realcar(code) }),
|
|
58
|
+
badges
|
|
59
|
+
] }),
|
|
60
|
+
/* @__PURE__ */ jsx("span", { className: code ? "line-clamp-2 block text-[10px] leading-snug break-words text-slate-600" : "block truncate text-xs text-slate-700", children: realcar(title) }),
|
|
61
|
+
meta && /* @__PURE__ */ jsx("span", { className: "block truncate text-[9px] leading-tight text-slate-400", children: meta })
|
|
31
62
|
]
|
|
32
63
|
}
|
|
33
|
-
)
|
|
64
|
+
),
|
|
65
|
+
aside && /* @__PURE__ */ jsx("span", { className: "flex shrink-0 flex-col items-end gap-1", children: aside })
|
|
34
66
|
] });
|
|
35
67
|
}
|
|
36
68
|
export {
|
|
69
|
+
HighlightText,
|
|
70
|
+
LINHA_ESBATIDA,
|
|
37
71
|
ListItem as default
|
|
38
72
|
};
|
|
39
73
|
//# sourceMappingURL=ListItem.js.map
|
|
@@ -1 +1 @@
|
|
|
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 /**
|
|
1
|
+
{"version":3,"file":"ListItem.js","sources":["../../../../../../src/v1/primitives/lists/ListItem/ListItem.tsx"],"sourcesContent":["import React, { Fragment } 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 /** Por baixo do código: o que a linha é (ex: a descrição). Até duas linhas, cortada com \"…\" se não couber. */\r\n title: React.ReactNode\r\n /** O texto mais forte da linha, em letra de máquina (ex: o número ou código). */\r\n code?: React.ReactNode\r\n /** Na linha do código, logo a seguir a ele: indicadores e avisos curtos. */\r\n badges?: React.ReactNode\r\n /** Por baixo do título, pequeno e numa linha só (cortada com \"…\"): o resto do que se quer ver de relance, separado por \" · \" (ex: local · data). */\r\n meta?: React.ReactNode\r\n /**\r\n * Opcional, e só com caixa de marcar (`onCheckedChange`): uma etiqueta curta\r\n * (ex: a categoria) no espaço que a caixa abre por baixo dela. Sem caixa não\r\n * se mostra — não há coluna para ela.\r\n */\r\n tag?: React.ReactNode\r\n /** À direita, ao nível do código: marcas que se querem ver mesmo a correr a lista. */\r\n aside?: 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 /**\r\n * O que se procurou: realça-se no código e no título quando são texto (sem\r\n * acentos nem maiúsculas). O [ListFinder](?path=/docs/v1-components-lists-listfinder--docs) passa-o sozinho.\r\n */\r\n highlight?: string[]\r\n className?: string\r\n}\r\n\r\n/**\r\n * A linha entre linhas, esbatida nas pontas: uma risca de ponta a ponta\r\n * fechava cada linha numa caixa. Desenhada como fundo (e não com um ::after,\r\n * que o botão da linha já usa); a última linha não a leva.\r\n */\r\nexport const LINHA_ESBATIDA = 'bg-[linear-gradient(to_right,transparent,var(--color-slate-200)_15%,var(--color-slate-200)_85%,transparent)] bg-[length:100%_1px] bg-bottom bg-no-repeat last:bg-none'\r\n\r\nconst semAcento = (c: string) => c.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase()\r\n\r\n/**\r\n * Texto com os pedaços que batem com a pesquisa realçados: numa descrição\r\n * comprida, ou num número de dez dígitos, não se via onde é que o que se\r\n * escreveu bateu.\r\n */\r\nexport function HighlightText({ text, terms }: { text: string; terms?: string[] }) {\r\n const termos = (terms ?? []).map(t => [...t].map(semAcento).join('')).filter(Boolean)\r\n if (!termos.length) return <>{text}</>\r\n // Carácter a carácter, para as posições baterem com o texto original.\r\n const alvo = [...text].map(c => semAcento(c).charAt(0) || c).join('')\r\n const marcado = new Array<boolean>(alvo.length).fill(false)\r\n for (const t of termos) {\r\n for (let i = alvo.indexOf(t); i >= 0; i = alvo.indexOf(t, i + 1)) {\r\n for (let k = i; k < i + t.length; k++) marcado[k] = true\r\n }\r\n }\r\n if (!marcado.some(Boolean)) return <>{text}</>\r\n const chars = [...text]\r\n const partes: { txt: string; hit: boolean }[] = []\r\n chars.forEach((c, i) => {\r\n const ultimo = partes[partes.length - 1]\r\n if (ultimo && ultimo.hit === marcado[i]) ultimo.txt += c\r\n else partes.push({ txt: c, hit: marcado[i] })\r\n })\r\n return (\r\n <>\r\n {partes.map((p, i) => p.hit\r\n ? <mark key={i} className=\"rounded-sm bg-amber-200 font-bold text-amber-900\">{p.txt}</mark>\r\n : <Fragment key={i}>{p.txt}</Fragment>)}\r\n </>\r\n )\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 e o ListItem arruma-as sempre da\r\n * mesma forma. O código é o texto mais forte da linha, com os indicadores ao\r\n * lado; o título vem por baixo, mais pequeno, e o resto por baixo dele. Com\r\n * `onCheckedChange` leva uma caixa à esquerda, para marcar vários (um\r\n * [Checkbox](?path=/docs/v1-primitives-forms-checkbox--docs)), numa coluna de\r\n * largura fixa — senão os títulos começavam em sítios diferentes de linha para\r\n * linha — e, se se quiser, a `tag` por baixo dela.\r\n *\r\n * É um `<li>`: vai dentro de um `<ul>`.\r\n */\r\nexport default function ListItem({\r\n title, code, badges, meta, tag, aside, active = false, onClick, checked = false, onCheckedChange, checkboxLabel,\r\n highlight, className = '',\r\n}: ListItemProps) {\r\n const fundo = active ? 'bg-blue-50' : checked ? 'bg-proef-turquoise/5' : 'hover:bg-slate-50'\r\n const realcar = (n: React.ReactNode) => (typeof n === 'string' ? <HighlightText text={n} terms={highlight} /> : n)\r\n return (\r\n <li className={`v1-reset relative flex list-none items-start gap-1.5 px-3 py-3 transition-colors ${LINHA_ESBATIDA} ${fundo} ${className}`}>\r\n {onCheckedChange && (\r\n <span className=\"flex w-7 shrink-0 flex-col items-center gap-1\">\r\n <Checkbox checked={checked} onChange={e => onCheckedChange(e.target.checked)} aria-label={checkboxLabel} className=\"z-10 mt-0.5\" />\r\n {tag && <span className=\"text-[8px] leading-none font-semibold text-slate-400\">{tag}</span>}\r\n </span>\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 space-y-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 {(code || badges) && (\r\n <span className=\"flex flex-wrap items-center gap-x-2 gap-y-0.5 leading-tight\">\r\n {code && <span className=\"font-mono text-xs font-semibold text-slate-700\">{realcar(code)}</span>}\r\n {badges}\r\n </span>\r\n )}\r\n {/* Sem código, o título é a linha principal. */}\r\n <span className={code\r\n ? 'line-clamp-2 block text-[10px] leading-snug break-words text-slate-600'\r\n : 'block truncate text-xs text-slate-700'}>\r\n {realcar(title)}\r\n </span>\r\n {meta && <span className=\"block truncate text-[9px] leading-tight text-slate-400\">{meta}</span>}\r\n </button>\r\n {aside && <span className=\"flex shrink-0 flex-col items-end gap-1\">{aside}</span>}\r\n </li>\r\n )\r\n}\r\n"],"names":["Fragment"],"mappings":"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"}
|