@mediquo/medicore 0.2.0 → 0.3.0
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/components/badge/badge.d.ts +7 -3
- package/dist/components/badge/badge.js +27 -4
- package/dist/components/badge/badge.js.map +1 -1
- package/dist/components/breadcrumb/breadcrumb.d.ts +2 -2
- package/dist/components/breadcrumb/breadcrumb.js +4 -4
- package/dist/components/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/button/button.js +9 -9
- package/dist/components/button/button.js.map +1 -1
- package/dist/components/chip/chip.d.ts +3 -0
- package/dist/components/chip/chip.js +41 -10
- package/dist/components/chip/chip.js.map +1 -1
- package/dist/components/input/control-styles.d.ts +1 -1
- package/dist/components/input/control-styles.js +4 -4
- package/dist/components/input/control-styles.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { ComponentProps } from "react";
|
|
2
2
|
export declare const badgeVariants: (props?: ({
|
|
3
|
-
variant?: "error" | "brand" | "neutral" | "success" | "warning" | "info" | null | undefined;
|
|
3
|
+
variant?: "outline" | "error" | "brand" | "neutral" | "success" | "warning" | "info" | null | undefined;
|
|
4
4
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
5
|
-
export type BadgeVariant = "neutral" | "brand" | "success" | "warning" | "error" | "info";
|
|
5
|
+
export type BadgeVariant = "neutral" | "outline" | "brand" | "success" | "warning" | "error" | "info";
|
|
6
6
|
export interface BadgeProps extends ComponentProps<"span"> {
|
|
7
7
|
variant?: BadgeVariant;
|
|
8
|
+
/** A coloured dot in front: for statuses ("Abierta", "Pagada"), not for categories. */
|
|
9
|
+
dot?: boolean;
|
|
8
10
|
}
|
|
9
11
|
/**
|
|
10
12
|
* Category or status tag (documents: Receta, Informe, Orden médica; program cards).
|
|
@@ -12,9 +14,11 @@ export interface BadgeProps extends ComponentProps<"span"> {
|
|
|
12
14
|
* it isn't a badge, it's text.
|
|
13
15
|
*
|
|
14
16
|
* - It is NOT a button: no click, no focus, no close icon. Removable → `Chip`.
|
|
17
|
+
* - `outline` is the quiet one for plain metadata (a clinic's name next to a
|
|
18
|
+
* professional); the tinted variants tell a state.
|
|
15
19
|
* - On a photo use `neutral` (solid). Never a translucent pill: its contrast depends
|
|
16
20
|
* on the photo.
|
|
17
21
|
* - `warning` keeps its text in text-primary: the orange-on-orange pair doesn't reach
|
|
18
22
|
* 4.5:1 with the current tokens.
|
|
19
23
|
*/
|
|
20
|
-
export declare function Badge({ variant, className, ...props }: BadgeProps): React.JSX.Element;
|
|
24
|
+
export declare function Badge({ variant, dot, className, children, ...props }: BadgeProps): React.JSX.Element;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cva } from "class-variance-authority";
|
|
3
3
|
import { cn } from "../../lib/cn.js";
|
|
4
4
|
const badgeVariants = cva(
|
|
5
|
-
"inline-flex h-6 w-fit shrink-0 items-center gap-1 whitespace-nowrap rounded-full px-2.5 text-label-small [&_svg]:size-icon-xs",
|
|
5
|
+
"inline-flex h-6 w-fit shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full px-2.5 text-label-small font-medium [&_svg]:size-icon-xs",
|
|
6
6
|
{
|
|
7
7
|
variants: {
|
|
8
8
|
variant: {
|
|
9
9
|
neutral: "bg-surface-raised text-text-primary",
|
|
10
|
+
outline: "bg-background text-text-secondary ring-1 ring-border ring-inset",
|
|
10
11
|
brand: "bg-brand-subtle text-text-brand",
|
|
11
12
|
success: "bg-success-subtle text-text-success",
|
|
12
13
|
// Token gap, not an aesthetic choice: warning-strong on warning-subtle is
|
|
@@ -21,17 +22,39 @@ const badgeVariants = cva(
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
);
|
|
25
|
+
const badgeDotVariants = cva("size-1.5 shrink-0 rounded-full", {
|
|
26
|
+
variants: {
|
|
27
|
+
variant: {
|
|
28
|
+
neutral: "bg-text-secondary",
|
|
29
|
+
outline: "bg-text-secondary",
|
|
30
|
+
brand: "bg-brand",
|
|
31
|
+
success: "bg-success",
|
|
32
|
+
warning: "bg-warning",
|
|
33
|
+
error: "bg-error",
|
|
34
|
+
info: "bg-info"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
defaultVariants: {
|
|
38
|
+
variant: "neutral"
|
|
39
|
+
}
|
|
40
|
+
});
|
|
24
41
|
function Badge({
|
|
25
42
|
variant,
|
|
43
|
+
dot = false,
|
|
26
44
|
className,
|
|
45
|
+
children,
|
|
27
46
|
...props
|
|
28
47
|
}) {
|
|
29
|
-
return /* @__PURE__ */
|
|
48
|
+
return /* @__PURE__ */ jsxs(
|
|
30
49
|
"span",
|
|
31
50
|
{
|
|
32
51
|
"data-slot": "badge",
|
|
33
52
|
className: cn(badgeVariants({ variant }), className),
|
|
34
|
-
...props
|
|
53
|
+
...props,
|
|
54
|
+
children: [
|
|
55
|
+
dot && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: badgeDotVariants({ variant }) }),
|
|
56
|
+
children
|
|
57
|
+
]
|
|
35
58
|
}
|
|
36
59
|
);
|
|
37
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"badge.js","sources":["../../../src/components/badge/badge.tsx"],"sourcesContent":["import { cva } from \"class-variance-authority\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\n\nexport const badgeVariants = cva(\n \"inline-flex h-6 w-fit shrink-0 items-center gap-1 whitespace-nowrap rounded-full px-2.5 text-label-small [&_svg]:size-icon-xs\",\n {\n variants: {\n variant: {\n neutral: \"bg-surface-raised text-text-primary\",\n brand: \"bg-brand-subtle text-text-brand\",\n success: \"bg-success-subtle text-text-success\",\n // Token gap, not an aesthetic choice: warning-strong on warning-subtle is\n // 3.93:1, so the text stays in text-primary and the orange lives in the fill.\n warning: \"bg-warning-subtle text-text-primary\",\n error: \"bg-error-subtle text-text-error\",\n info: \"bg-info-subtle text-text-info\",\n },\n },\n defaultVariants: {\n variant: \"neutral\",\n },\n },\n);\n\nexport type BadgeVariant =\n | \"neutral\"\n | \"brand\"\n | \"success\"\n | \"warning\"\n | \"error\"\n | \"info\";\n\nexport interface BadgeProps extends ComponentProps<\"span\"> {\n variant?: BadgeVariant;\n}\n\n/**\n * Category or status tag (documents: Receta, Informe, Orden médica; program cards).\n * 12px (Label/Small) because it is metadata: if people need to read it to decide,\n * it isn't a badge, it's text.\n *\n * - It is NOT a button: no click, no focus, no close icon. Removable → `Chip`.\n * - On a photo use `neutral` (solid). Never a translucent pill: its contrast depends\n * on the photo.\n * - `warning` keeps its text in text-primary: the orange-on-orange pair doesn't reach\n * 4.5:1 with the current tokens.\n */\nexport function Badge({\n variant,\n className,\n ...props\n}: BadgeProps): React.JSX.Element {\n return (\n <span\n data-slot=\"badge\"\n className={cn(badgeVariants({ variant }), className)}\n {...props}\n />\n );\n}\n"],"names":[],"mappings":";;;AAKO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAS;AAAA;AAAA;AAAA,QAGT,SAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM;AAAA,MAAA;AAAA,IACR;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,IAAA;AAAA,EACX;AAEJ;
|
|
1
|
+
{"version":3,"file":"badge.js","sources":["../../../src/components/badge/badge.tsx"],"sourcesContent":["import { cva } from \"class-variance-authority\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\n\nexport const badgeVariants = cva(\n \"inline-flex h-6 w-fit shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full px-2.5 text-label-small font-medium [&_svg]:size-icon-xs\",\n {\n variants: {\n variant: {\n neutral: \"bg-surface-raised text-text-primary\",\n outline:\n \"bg-background text-text-secondary ring-1 ring-border ring-inset\",\n brand: \"bg-brand-subtle text-text-brand\",\n success: \"bg-success-subtle text-text-success\",\n // Token gap, not an aesthetic choice: warning-strong on warning-subtle is\n // 3.93:1, so the text stays in text-primary and the orange lives in the fill.\n warning: \"bg-warning-subtle text-text-primary\",\n error: \"bg-error-subtle text-text-error\",\n info: \"bg-info-subtle text-text-info\",\n },\n },\n defaultVariants: {\n variant: \"neutral\",\n },\n },\n);\n\nconst badgeDotVariants = cva(\"size-1.5 shrink-0 rounded-full\", {\n variants: {\n variant: {\n neutral: \"bg-text-secondary\",\n outline: \"bg-text-secondary\",\n brand: \"bg-brand\",\n success: \"bg-success\",\n warning: \"bg-warning\",\n error: \"bg-error\",\n info: \"bg-info\",\n },\n },\n defaultVariants: {\n variant: \"neutral\",\n },\n});\n\nexport type BadgeVariant =\n | \"neutral\"\n | \"outline\"\n | \"brand\"\n | \"success\"\n | \"warning\"\n | \"error\"\n | \"info\";\n\nexport interface BadgeProps extends ComponentProps<\"span\"> {\n variant?: BadgeVariant;\n /** A coloured dot in front: for statuses (\"Abierta\", \"Pagada\"), not for categories. */\n dot?: boolean;\n}\n\n/**\n * Category or status tag (documents: Receta, Informe, Orden médica; program cards).\n * 12px (Label/Small) because it is metadata: if people need to read it to decide,\n * it isn't a badge, it's text.\n *\n * - It is NOT a button: no click, no focus, no close icon. Removable → `Chip`.\n * - `outline` is the quiet one for plain metadata (a clinic's name next to a\n * professional); the tinted variants tell a state.\n * - On a photo use `neutral` (solid). Never a translucent pill: its contrast depends\n * on the photo.\n * - `warning` keeps its text in text-primary: the orange-on-orange pair doesn't reach\n * 4.5:1 with the current tokens.\n */\nexport function Badge({\n variant,\n dot = false,\n className,\n children,\n ...props\n}: BadgeProps): React.JSX.Element {\n return (\n <span\n data-slot=\"badge\"\n className={cn(badgeVariants({ variant }), className)}\n {...props}\n >\n {dot && (\n <span aria-hidden=\"true\" className={badgeDotVariants({ variant })} />\n )}\n {children}\n </span>\n );\n}\n"],"names":[],"mappings":";;;AAKO,MAAM,gBAAgB;AAAA,EAC3B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,SACE;AAAA,QACF,OAAO;AAAA,QACP,SAAS;AAAA;AAAA;AAAA,QAGT,SAAS;AAAA,QACT,OAAO;AAAA,QACP,MAAM;AAAA,MAAA;AAAA,IACR;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,IAAA;AAAA,EACX;AAEJ;AAEA,MAAM,mBAAmB,IAAI,kCAAkC;AAAA,EAC7D,UAAU;AAAA,IACR,SAAS;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,IAAA;AAAA,EACR;AAAA,EAEF,iBAAiB;AAAA,IACf,SAAS;AAAA,EAAA;AAEb,CAAC;AA8BM,SAAS,MAAM;AAAA,EACpB;AAAA,EACA,MAAM;AAAA,EACN;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAkC;AAChC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,cAAc,EAAE,QAAA,CAAS,GAAG,SAAS;AAAA,MAClD,GAAG;AAAA,MAEH,UAAA;AAAA,QAAA,OACC,oBAAC,UAAK,eAAY,QAAO,WAAW,iBAAiB,EAAE,QAAA,CAAS,GAAG;AAAA,QAEpE;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGP;"}
|
|
@@ -17,8 +17,8 @@ export interface BreadcrumbProps extends ComponentProps<"nav"> {
|
|
|
17
17
|
* </Breadcrumb>
|
|
18
18
|
* ```
|
|
19
19
|
*
|
|
20
|
-
* The levels above are quiet (Label/
|
|
21
|
-
* a chevron in
|
|
20
|
+
* The levels above are quiet (Label/Default in text-secondary, brand on hover), with
|
|
21
|
+
* a chevron in border-strong between them, so the trail never competes with the
|
|
22
22
|
* page title under it. The links are not underlined: inside the breadcrumb landmark
|
|
23
23
|
* and its list, their position already tells they are links (WCAG 1.4.1 applies to
|
|
24
24
|
* links in running text).
|
|
@@ -22,7 +22,7 @@ function Breadcrumb({
|
|
|
22
22
|
"ol",
|
|
23
23
|
{
|
|
24
24
|
className: cn(
|
|
25
|
-
"flex flex-wrap items-center gap-
|
|
25
|
+
"flex flex-wrap items-center gap-2",
|
|
26
26
|
// Mobile: only the parent level (the second-to-last item) stays.
|
|
27
27
|
"max-lg:[&>li:not(:nth-last-child(2))]:hidden"
|
|
28
28
|
),
|
|
@@ -46,21 +46,21 @@ function BreadcrumbItem({
|
|
|
46
46
|
props: {
|
|
47
47
|
"data-slot": "breadcrumb-link",
|
|
48
48
|
className: cn(
|
|
49
|
-
"focus-ring touch-target inline-flex items-center gap-1 rounded-xs text-label-
|
|
49
|
+
"focus-ring touch-target inline-flex items-center gap-1 rounded-xs text-label-default text-text-secondary transition-colors hover:text-text-brand",
|
|
50
50
|
className
|
|
51
51
|
),
|
|
52
52
|
children,
|
|
53
53
|
...props
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
|
-
return /* @__PURE__ */ jsxs("li", { "data-slot": "breadcrumb-item", className: "flex items-center gap-
|
|
56
|
+
return /* @__PURE__ */ jsxs("li", { "data-slot": "breadcrumb-item", className: "flex items-center gap-2", children: [
|
|
57
57
|
/* @__PURE__ */ jsx(ChevronLeftIcon, { size: "sm", className: "text-text-secondary lg:hidden" }),
|
|
58
58
|
link,
|
|
59
59
|
/* @__PURE__ */ jsx(
|
|
60
60
|
ChevronRightIcon,
|
|
61
61
|
{
|
|
62
62
|
size: "sm",
|
|
63
|
-
className: "text-
|
|
63
|
+
className: "text-border-strong max-lg:hidden"
|
|
64
64
|
}
|
|
65
65
|
)
|
|
66
66
|
] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"breadcrumb.js","sources":["../../../src/components/breadcrumb/breadcrumb.tsx"],"sourcesContent":["import { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { ChevronLeftIcon, ChevronRightIcon } from \"../../icons\";\nimport { cn } from \"../../lib/cn\";\nimport { useMediCoreLabels } from \"../../provider\";\n\nexport interface BreadcrumbProps extends ComponentProps<\"nav\"> {\n /** `BreadcrumbItem`s for the levels above, then one `BreadcrumbPage` for the current one. */\n children: ReactNode;\n}\n\n/**\n * Breadcrumb for pages two or three levels deep (a programme inside \"Programas\n * especializados\"). A `<nav>` named \"Migas de pan\" (`breadcrumb` label) with an\n * `<ol>`: the levels above are links, the last one is plain text with\n * `aria-current=\"page\"`.\n *\n * ```tsx\n * <Breadcrumb>\n * <BreadcrumbItem render={<Link to=\"/programas\" />}>Programas especializados</BreadcrumbItem>\n * <BreadcrumbPage>Pérdida de peso</BreadcrumbPage>\n * </Breadcrumb>\n * ```\n *\n * The levels above are quiet (Label/
|
|
1
|
+
{"version":3,"file":"breadcrumb.js","sources":["../../../src/components/breadcrumb/breadcrumb.tsx"],"sourcesContent":["import { useRender } from \"@base-ui/react/use-render\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { ChevronLeftIcon, ChevronRightIcon } from \"../../icons\";\nimport { cn } from \"../../lib/cn\";\nimport { useMediCoreLabels } from \"../../provider\";\n\nexport interface BreadcrumbProps extends ComponentProps<\"nav\"> {\n /** `BreadcrumbItem`s for the levels above, then one `BreadcrumbPage` for the current one. */\n children: ReactNode;\n}\n\n/**\n * Breadcrumb for pages two or three levels deep (a programme inside \"Programas\n * especializados\"). A `<nav>` named \"Migas de pan\" (`breadcrumb` label) with an\n * `<ol>`: the levels above are links, the last one is plain text with\n * `aria-current=\"page\"`.\n *\n * ```tsx\n * <Breadcrumb>\n * <BreadcrumbItem render={<Link to=\"/programas\" />}>Programas especializados</BreadcrumbItem>\n * <BreadcrumbPage>Pérdida de peso</BreadcrumbPage>\n * </Breadcrumb>\n * ```\n *\n * The levels above are quiet (Label/Default in text-secondary, brand on hover), with\n * a chevron in border-strong between them, so the trail never competes with the\n * page title under it. The links are not underlined: inside the breadcrumb landmark\n * and its list, their position already tells they are links (WCAG 1.4.1 applies to\n * links in running text).\n *\n * Below the `lg` breakpoint only the level right above shows, as a way back with an\n * arrow (\"‹ Programas especializados\").\n */\nexport function Breadcrumb({\n \"aria-label\": ariaLabel,\n className,\n children,\n ...props\n}: BreadcrumbProps): React.JSX.Element {\n const labels = useMediCoreLabels();\n\n return (\n <nav\n data-slot=\"breadcrumb\"\n aria-label={ariaLabel ?? labels.breadcrumb}\n className={className}\n {...props}\n >\n <ol\n className={cn(\n \"flex flex-wrap items-center gap-2\",\n // Mobile: only the parent level (the second-to-last item) stays.\n \"max-lg:[&>li:not(:nth-last-child(2))]:hidden\",\n )}\n >\n {children}\n </ol>\n </nav>\n );\n}\n\nexport interface BreadcrumbItemProps extends useRender.ComponentProps<\"a\"> {\n /** The level's name, the same as the section or page it links to. */\n children: ReactNode;\n}\n\n/**\n * A level above the current page: a link (`href`, or the router's with `render`)\n * followed by a chevron. On mobile, the parent level gets a back arrow in front\n * instead.\n */\nexport function BreadcrumbItem({\n render,\n ref,\n className,\n children,\n ...props\n}: BreadcrumbItemProps): React.JSX.Element {\n const link = useRender({\n render,\n ref,\n defaultTagName: \"a\",\n props: {\n \"data-slot\": \"breadcrumb-link\",\n className: cn(\n \"focus-ring touch-target inline-flex items-center gap-1 rounded-xs text-label-default text-text-secondary transition-colors hover:text-text-brand\",\n className,\n ),\n children,\n ...props,\n },\n });\n\n return (\n <li data-slot=\"breadcrumb-item\" className=\"flex items-center gap-2\">\n <ChevronLeftIcon size=\"sm\" className=\"text-text-secondary lg:hidden\" />\n {link}\n <ChevronRightIcon\n size=\"sm\"\n className=\"text-border-strong max-lg:hidden\"\n />\n </li>\n );\n}\n\nexport interface BreadcrumbPageProps extends ComponentProps<\"span\"> {}\n\n/** The current level: text, not a link, with `aria-current=\"page\"`. Hidden on mobile. */\nexport function BreadcrumbPage({\n className,\n ...props\n}: BreadcrumbPageProps): React.JSX.Element {\n return (\n <li data-slot=\"breadcrumb-page\" className=\"flex items-center\">\n <span\n aria-current=\"page\"\n className={cn(\"text-label-strong text-text-primary\", className)}\n {...props}\n />\n </li>\n );\n}\n"],"names":[],"mappings":";;;;;;AAkCO,SAAS,WAAW;AAAA,EACzB,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAuC;AACrC,QAAM,SAAS,kBAAA;AAEf,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,cAAY,aAAa,OAAO;AAAA,MAChC;AAAA,MACC,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA;AAAA,YAEA;AAAA,UAAA;AAAA,UAGD;AAAA,QAAA;AAAA,MAAA;AAAA,IACH;AAAA,EAAA;AAGN;AAYO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA2C;AACzC,QAAM,OAAO,UAAU;AAAA,IACrB;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB,OAAO;AAAA,MACL,aAAa;AAAA,MACb,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MAAA;AAAA,MAEF;AAAA,MACA,GAAG;AAAA,IAAA;AAAA,EACL,CACD;AAED,SACE,qBAAC,MAAA,EAAG,aAAU,mBAAkB,WAAU,2BACxC,UAAA;AAAA,IAAA,oBAAC,iBAAA,EAAgB,MAAK,MAAK,WAAU,iCAAgC;AAAA,IACpE;AAAA,IACD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,MAAA;AAAA,IAAA;AAAA,EACZ,GACF;AAEJ;AAKO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA,GAAG;AACL,GAA2C;AACzC,SACE,oBAAC,MAAA,EAAG,aAAU,mBAAkB,WAAU,qBACxC,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,gBAAa;AAAA,MACb,WAAW,GAAG,uCAAuC,SAAS;AAAA,MAC7D,GAAG;AAAA,IAAA;AAAA,EAAA,GAER;AAEJ;"}
|
|
@@ -6,20 +6,20 @@ import { Spinner } from "../spinner/spinner.js";
|
|
|
6
6
|
const buttonVariants = cva(
|
|
7
7
|
[
|
|
8
8
|
"inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap",
|
|
9
|
-
"rounded-md border border-transparent text-label-strong transition-
|
|
9
|
+
"rounded-md border border-transparent text-label-strong transition-[color,background-color,border-color,box-shadow]",
|
|
10
10
|
"focus-ring touch-target",
|
|
11
11
|
"[&_svg]:shrink-0 [&_svg]:size-icon-sm",
|
|
12
|
-
"data-disabled:cursor-not-allowed aria-busy:cursor-progress"
|
|
12
|
+
"data-disabled:cursor-not-allowed data-disabled:shadow-none aria-busy:cursor-progress"
|
|
13
13
|
],
|
|
14
14
|
{
|
|
15
15
|
variants: {
|
|
16
16
|
variant: {
|
|
17
|
-
primary: "bg-brand text-text-inverse not-data-disabled:hover:bg-brand-strong",
|
|
18
|
-
secondary: "border-text-brand bg-brand-subtle text-text-brand not-data-disabled:hover:bg-
|
|
19
|
-
outline: "border-border
|
|
17
|
+
primary: "bg-brand text-text-inverse shadow-xs not-data-disabled:hover:bg-brand-strong",
|
|
18
|
+
secondary: "border-text-brand bg-brand-subtle text-text-brand not-data-disabled:hover:bg-background",
|
|
19
|
+
outline: "border-border bg-background text-text-primary shadow-xs not-data-disabled:hover:border-border-strong not-data-disabled:hover:bg-surface",
|
|
20
20
|
ghost: "bg-transparent text-text-primary not-data-disabled:hover:bg-surface",
|
|
21
|
-
destructive: "bg-error-strong text-text-inverse",
|
|
22
|
-
inverse: "bg-background text-text-brand not-data-disabled:hover:bg-surface",
|
|
21
|
+
destructive: "bg-error-strong text-text-inverse shadow-xs",
|
|
22
|
+
inverse: "bg-background text-text-brand shadow-xs not-data-disabled:hover:bg-surface",
|
|
23
23
|
"inverse-ghost": "bg-transparent text-text-inverse not-data-disabled:hover:bg-overlay-light"
|
|
24
24
|
},
|
|
25
25
|
size: {
|
|
@@ -37,12 +37,12 @@ const buttonVariants = cva(
|
|
|
37
37
|
{
|
|
38
38
|
variant: ["primary", "destructive"],
|
|
39
39
|
disabled: true,
|
|
40
|
-
className: "bg-surface text-text-disabled"
|
|
40
|
+
className: "bg-surface-raised text-text-disabled"
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
variant: ["secondary", "outline"],
|
|
44
44
|
disabled: true,
|
|
45
|
-
className: "border-border bg-surface text-text-disabled"
|
|
45
|
+
className: "border-border-subtle bg-surface text-text-disabled"
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
48
|
variant: "ghost",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.js","sources":["../../../src/components/button/button.tsx"],"sourcesContent":["import { Button as BaseButton } from \"@base-ui/react/button\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\nimport { Spinner } from \"../spinner\";\n\nexport const buttonVariants = cva(\n [\n \"inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap\",\n \"rounded-md border border-transparent text-label-strong transition-
|
|
1
|
+
{"version":3,"file":"button.js","sources":["../../../src/components/button/button.tsx"],"sourcesContent":["import { Button as BaseButton } from \"@base-ui/react/button\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/cn\";\nimport { Spinner } from \"../spinner\";\n\nexport const buttonVariants = cva(\n [\n \"inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap\",\n \"rounded-md border border-transparent text-label-strong transition-[color,background-color,border-color,box-shadow]\",\n \"focus-ring touch-target\",\n \"[&_svg]:shrink-0 [&_svg]:size-icon-sm\",\n \"data-disabled:cursor-not-allowed data-disabled:shadow-none aria-busy:cursor-progress\",\n ],\n {\n variants: {\n variant: {\n primary:\n \"bg-brand text-text-inverse shadow-xs not-data-disabled:hover:bg-brand-strong\",\n secondary:\n \"border-text-brand bg-brand-subtle text-text-brand not-data-disabled:hover:bg-background\",\n outline:\n \"border-border bg-background text-text-primary shadow-xs not-data-disabled:hover:border-border-strong not-data-disabled:hover:bg-surface\",\n ghost:\n \"bg-transparent text-text-primary not-data-disabled:hover:bg-surface\",\n destructive: \"bg-error-strong text-text-inverse shadow-xs\",\n inverse:\n \"bg-background text-text-brand shadow-xs not-data-disabled:hover:bg-surface\",\n \"inverse-ghost\":\n \"bg-transparent text-text-inverse not-data-disabled:hover:bg-overlay-light\",\n },\n size: {\n default: \"h-control-md px-4\",\n small: \"h-control-sm px-3\",\n },\n disabled: {\n true: \"\",\n false: \"\",\n },\n },\n // Disabled uses explicit colours, not opacity: an opacity can't be a token and it\n // also dims the border.\n compoundVariants: [\n {\n variant: [\"primary\", \"destructive\"],\n disabled: true,\n className: \"bg-surface-raised text-text-disabled\",\n },\n {\n variant: [\"secondary\", \"outline\"],\n disabled: true,\n className: \"border-border-subtle bg-surface text-text-disabled\",\n },\n {\n variant: \"ghost\",\n disabled: true,\n className: \"text-text-disabled\",\n },\n {\n variant: \"inverse\",\n disabled: true,\n className: \"bg-border-inverse text-text-inverse-secondary\",\n },\n {\n variant: \"inverse-ghost\",\n disabled: true,\n className: \"text-text-inverse-secondary\",\n },\n ],\n defaultVariants: {\n variant: \"primary\",\n size: \"default\",\n disabled: false,\n },\n },\n);\n\ntype ButtonVariantProps = Omit<VariantProps<typeof buttonVariants>, \"disabled\">;\n\nexport interface ButtonProps\n extends Omit<BaseButton.Props, \"className\">,\n ButtonVariantProps {\n /** Keeps the variant colour, shows a spinner and ignores clicks without losing focus. */\n loading?: boolean;\n leadingIcon?: ReactNode;\n trailingIcon?: ReactNode;\n className?: string;\n}\n\n/**\n * Action button. A button ACTS; to navigate use `Link` (or `render={<a href />}` when\n * it has to look like a button).\n *\n * Hierarchy, from most to least weight: primary → secondary → outline → ghost.\n * `destructive` is a warning, not a level. `inverse` and `inverse-ghost` are only\n * for dark surfaces (`bg-brand-dark`). One primary action per block.\n *\n * The drawing is 40px (36 small) but the hit area is always 44px. Full width: pass\n * `className=\"w-full\"`.\n */\nexport function Button({\n variant,\n size,\n disabled = false,\n loading = false,\n leadingIcon,\n trailingIcon,\n className,\n children,\n type = \"button\",\n ...props\n}: ButtonProps): React.JSX.Element {\n return (\n <BaseButton\n data-slot=\"button\"\n type={type}\n disabled={disabled || loading}\n focusableWhenDisabled={loading}\n aria-busy={loading || undefined}\n className={cn(buttonVariants({ variant, size, disabled }), className)}\n {...props}\n >\n {loading ? (\n <Spinner size={16} label={null} className=\"text-current\" />\n ) : (\n leadingIcon\n )}\n {children}\n {!loading && trailingIcon}\n </BaseButton>\n );\n}\n"],"names":["BaseButton"],"mappings":";;;;;AAOO,MAAM,iBAAiB;AAAA,EAC5B;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAEF;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SACE;AAAA,QACF,WACE;AAAA,QACF,SACE;AAAA,QACF,OACE;AAAA,QACF,aAAa;AAAA,QACb,SACE;AAAA,QACF,iBACE;AAAA,MAAA;AAAA,MAEJ,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,MAAA;AAAA,MAET,UAAU;AAAA,QACR,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,IACT;AAAA;AAAA;AAAA,IAIF,kBAAkB;AAAA,MAChB;AAAA,QACE,SAAS,CAAC,WAAW,aAAa;AAAA,QAClC,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,SAAS,CAAC,aAAa,SAAS;AAAA,QAChC,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,MAEb;AAAA,QACE,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAW;AAAA,MAAA;AAAA,IACb;AAAA,IAEF,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,MACN,UAAU;AAAA,IAAA;AAAA,EACZ;AAEJ;AAyBO,SAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,GAAG;AACL,GAAmC;AACjC,SACE;AAAA,IAACA;AAAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV;AAAA,MACA,UAAU,YAAY;AAAA,MACtB,uBAAuB;AAAA,MACvB,aAAW,WAAW;AAAA,MACtB,WAAW,GAAG,eAAe,EAAE,SAAS,MAAM,SAAA,CAAU,GAAG,SAAS;AAAA,MACnE,GAAG;AAAA,MAEH,UAAA;AAAA,QAAA,UACC,oBAAC,WAAQ,MAAM,IAAI,OAAO,MAAM,WAAU,gBAAe,IAEzD;AAAA,QAED;AAAA,QACA,CAAC,WAAW;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGnB;"}
|
|
@@ -14,6 +14,8 @@ interface ChipOwnProps {
|
|
|
14
14
|
size?: ChipSize;
|
|
15
15
|
/** A MediCore icon before the label. While selected the check takes its place. */
|
|
16
16
|
leadingIcon?: ReactNode;
|
|
17
|
+
/** Counter after the label ("Abiertas 5"): how many items the filter would show. */
|
|
18
|
+
count?: ReactNode;
|
|
17
19
|
className?: string;
|
|
18
20
|
}
|
|
19
21
|
export interface ChipToggleProps extends Omit<Toggle.Props<string>, "className">, ChipOwnProps {
|
|
@@ -40,6 +42,7 @@ export type ChipProps = ChipToggleProps | ChipRemovableProps;
|
|
|
40
42
|
* - It is a `<button aria-pressed>` (Base UI Toggle): `pressed` / `defaultPressed` /
|
|
41
43
|
* `onPressedChange`, or `value` inside a `ChipGroup`.
|
|
42
44
|
* - With `onRemove` it is a remove button for an applied filter instead.
|
|
45
|
+
* - `count` adds a counter pill at the end, brand-coloured while selected.
|
|
43
46
|
*/
|
|
44
47
|
export declare function Chip(props: ChipProps): React.JSX.Element;
|
|
45
48
|
export interface ChipGroupProps<Value extends string = string> extends Omit<ToggleGroup.Props<Value>, "className"> {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsxs, jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Button } from "@base-ui/react/button";
|
|
3
3
|
import { Toggle } from "@base-ui/react/toggle";
|
|
4
4
|
import { ToggleGroup } from "@base-ui/react/toggle-group";
|
|
@@ -10,15 +10,14 @@ import { useMediCoreLabels } from "../../provider/medicore-provider.js";
|
|
|
10
10
|
const chipVariants = cva(
|
|
11
11
|
[
|
|
12
12
|
"group/chip inline-flex shrink-0 cursor-pointer select-none items-center justify-center whitespace-nowrap",
|
|
13
|
-
|
|
14
|
-
"rounded-full border border-border-input bg-surface text-text-primary transition-colors",
|
|
13
|
+
"rounded-full border border-border bg-background text-text-primary shadow-xs transition-[color,background-color,border-color,box-shadow]",
|
|
15
14
|
// 32 (24 small) drawn, 44 hit area.
|
|
16
15
|
"focus-ring touch-target",
|
|
17
16
|
"[&_svg]:shrink-0",
|
|
18
|
-
"not-data-disabled:not-data-pressed:hover:bg-surface
|
|
19
|
-
// Selected is not just a colour: check in front,
|
|
20
|
-
"not-data-disabled:data-pressed:border-
|
|
21
|
-
"data-disabled:cursor-not-allowed data-disabled:border-border-subtle data-disabled:text-text-disabled"
|
|
17
|
+
"not-data-disabled:not-data-pressed:hover:border-border-strong not-data-disabled:not-data-pressed:hover:bg-surface",
|
|
18
|
+
// Selected is not just a colour: check in front, brand border, Medium label.
|
|
19
|
+
"not-data-disabled:data-pressed:border-brand not-data-disabled:data-pressed:bg-brand-subtle not-data-disabled:data-pressed:text-text-brand not-data-disabled:data-pressed:shadow-none",
|
|
20
|
+
"data-disabled:cursor-not-allowed data-disabled:border-border-subtle data-disabled:bg-surface data-disabled:text-text-disabled data-disabled:shadow-none"
|
|
22
21
|
],
|
|
23
22
|
{
|
|
24
23
|
variants: {
|
|
@@ -32,10 +31,40 @@ const chipVariants = cva(
|
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
33
|
);
|
|
34
|
+
const chipCountVariants = cva(
|
|
35
|
+
[
|
|
36
|
+
"inline-flex shrink-0 items-center justify-center rounded-full bg-surface-raised text-caption-default text-text-secondary tabular-nums transition-colors",
|
|
37
|
+
"group-data-pressed/chip:bg-brand group-data-pressed/chip:text-text-inverse",
|
|
38
|
+
"group-data-disabled/chip:bg-transparent group-data-disabled/chip:text-text-disabled"
|
|
39
|
+
],
|
|
40
|
+
{
|
|
41
|
+
variants: {
|
|
42
|
+
size: {
|
|
43
|
+
default: "-me-1 h-5 min-w-5 px-1.5",
|
|
44
|
+
small: "-me-0.5 h-4 min-w-4 px-1"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
defaultVariants: {
|
|
48
|
+
size: "default"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
function ChipCount({
|
|
53
|
+
size,
|
|
54
|
+
count
|
|
55
|
+
}) {
|
|
56
|
+
if (count === void 0 || count === null) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
60
|
+
" ",
|
|
61
|
+
/* @__PURE__ */ jsx("span", { "data-slot": "chip-count", className: chipCountVariants({ size }), children: count })
|
|
62
|
+
] });
|
|
63
|
+
}
|
|
35
64
|
function Chip(props) {
|
|
36
65
|
const labels = useMediCoreLabels();
|
|
37
66
|
if (props.onRemove) {
|
|
38
|
-
const { size: size2, leadingIcon: leadingIcon2, className: className2, children: children2, onRemove: onRemove2, ...rest2 } = props;
|
|
67
|
+
const { size: size2, leadingIcon: leadingIcon2, count: count2, className: className2, children: children2, onRemove: onRemove2, ...rest2 } = props;
|
|
39
68
|
return /* @__PURE__ */ jsxs(
|
|
40
69
|
Button,
|
|
41
70
|
{
|
|
@@ -50,12 +79,13 @@ function Chip(props) {
|
|
|
50
79
|
" "
|
|
51
80
|
] }),
|
|
52
81
|
children2,
|
|
82
|
+
/* @__PURE__ */ jsx(ChipCount, { size: size2, count: count2 }),
|
|
53
83
|
/* @__PURE__ */ jsx(XCloseIcon, {})
|
|
54
84
|
]
|
|
55
85
|
}
|
|
56
86
|
);
|
|
57
87
|
}
|
|
58
|
-
const { size, leadingIcon, className, children, onRemove, ...rest } = props;
|
|
88
|
+
const { size, leadingIcon, count, className, children, onRemove, ...rest } = props;
|
|
59
89
|
return /* @__PURE__ */ jsxs(
|
|
60
90
|
Toggle,
|
|
61
91
|
{
|
|
@@ -65,7 +95,8 @@ function Chip(props) {
|
|
|
65
95
|
children: [
|
|
66
96
|
/* @__PURE__ */ jsx(CheckIcon, { className: "hidden group-data-pressed/chip:block" }),
|
|
67
97
|
leadingIcon && /* @__PURE__ */ jsx("span", { className: "contents group-data-pressed/chip:hidden", children: leadingIcon }),
|
|
68
|
-
children
|
|
98
|
+
children,
|
|
99
|
+
/* @__PURE__ */ jsx(ChipCount, { size, count })
|
|
69
100
|
]
|
|
70
101
|
}
|
|
71
102
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chip.js","sources":["../../../src/components/chip/chip.tsx"],"sourcesContent":["import { Button as BaseButton } from \"@base-ui/react/button\";\nimport { Toggle } from \"@base-ui/react/toggle\";\nimport { ToggleGroup } from \"@base-ui/react/toggle-group\";\nimport { cva } from \"class-variance-authority\";\nimport type { ReactNode } from \"react\";\n\nimport { CheckIcon, XCloseIcon } from \"../../icons\";\nimport { cn } from \"../../lib/cn\";\nimport { useMediCoreLabels } from \"../../provider\";\n\nexport const chipVariants = cva(\n [\n \"group/chip inline-flex shrink-0 cursor-pointer select-none items-center justify-center whitespace-nowrap\",\n
|
|
1
|
+
{"version":3,"file":"chip.js","sources":["../../../src/components/chip/chip.tsx"],"sourcesContent":["import { Button as BaseButton } from \"@base-ui/react/button\";\nimport { Toggle } from \"@base-ui/react/toggle\";\nimport { ToggleGroup } from \"@base-ui/react/toggle-group\";\nimport { cva } from \"class-variance-authority\";\nimport type { ReactNode } from \"react\";\n\nimport { CheckIcon, XCloseIcon } from \"../../icons\";\nimport { cn } from \"../../lib/cn\";\nimport { useMediCoreLabels } from \"../../provider\";\n\nexport const chipVariants = cva(\n [\n \"group/chip inline-flex shrink-0 cursor-pointer select-none items-center justify-center whitespace-nowrap\",\n \"rounded-full border border-border bg-background text-text-primary shadow-xs transition-[color,background-color,border-color,box-shadow]\",\n // 32 (24 small) drawn, 44 hit area.\n \"focus-ring touch-target\",\n \"[&_svg]:shrink-0\",\n \"not-data-disabled:not-data-pressed:hover:border-border-strong not-data-disabled:not-data-pressed:hover:bg-surface\",\n // Selected is not just a colour: check in front, brand border, Medium label.\n \"not-data-disabled:data-pressed:border-brand not-data-disabled:data-pressed:bg-brand-subtle not-data-disabled:data-pressed:text-text-brand not-data-disabled:data-pressed:shadow-none\",\n \"data-disabled:cursor-not-allowed data-disabled:border-border-subtle data-disabled:bg-surface data-disabled:text-text-disabled data-disabled:shadow-none\",\n ],\n {\n variants: {\n size: {\n default:\n \"h-8 gap-1.5 px-3 text-label-default data-pressed:text-label-strong [&_svg]:size-icon-sm\",\n small: \"h-6 gap-1 px-2 text-label-small [&_svg]:size-icon-xs\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n },\n);\n\nconst chipCountVariants = cva(\n [\n \"inline-flex shrink-0 items-center justify-center rounded-full bg-surface-raised text-caption-default text-text-secondary tabular-nums transition-colors\",\n \"group-data-pressed/chip:bg-brand group-data-pressed/chip:text-text-inverse\",\n \"group-data-disabled/chip:bg-transparent group-data-disabled/chip:text-text-disabled\",\n ],\n {\n variants: {\n size: {\n default: \"-me-1 h-5 min-w-5 px-1.5\",\n small: \"-me-0.5 h-4 min-w-4 px-1\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n },\n);\n\nexport type ChipSize = \"default\" | \"small\";\n\ninterface ChipOwnProps {\n /**\n * `small` only for dense metadata, never as the main filter: at 24px it relies on\n * the invisible hit area to reach 44.\n */\n size?: ChipSize;\n /** A MediCore icon before the label. While selected the check takes its place. */\n leadingIcon?: ReactNode;\n /** Counter after the label (\"Abiertas 5\"): how many items the filter would show. */\n count?: ReactNode;\n className?: string;\n}\n\nexport interface ChipToggleProps\n extends Omit<Toggle.Props<string>, \"className\">,\n ChipOwnProps {\n onRemove?: undefined;\n}\n\nexport interface ChipRemovableProps\n extends Omit<BaseButton.Props, \"className\" | \"onClick\">,\n ChipOwnProps {\n /**\n * Turns the chip into a remove button for an applied filter: pressing anywhere on\n * it calls this. Its accessible name becomes \"Quitar <label>\" (`remove` label).\n * A removable chip is not a toggle.\n */\n onRemove: () => void;\n pressed?: undefined;\n defaultPressed?: undefined;\n onPressedChange?: undefined;\n}\n\nexport type ChipProps = ChipToggleProps | ChipRemovableProps;\n\nfunction ChipCount({\n size,\n count,\n}: {\n size: ChipSize | undefined;\n count: ReactNode;\n}): React.JSX.Element | null {\n if (count === undefined || count === null) {\n return null;\n }\n return (\n <>\n {\" \"}\n <span data-slot=\"chip-count\" className={chipCountVariants({ size })}>\n {count}\n </span>\n </>\n );\n}\n\n/**\n * Pressable filter (\"Dermatología\"). The filter row of lists and the admin.\n *\n * - **A Chip is not a Badge.** A Badge tells a state and can't be pressed\n * (\"Receta\", \"Cancelada\"); a Chip filters and is pressed. If it doesn't respond to\n * a tap, it's a Badge.\n * - It is a `<button aria-pressed>` (Base UI Toggle): `pressed` / `defaultPressed` /\n * `onPressedChange`, or `value` inside a `ChipGroup`.\n * - With `onRemove` it is a remove button for an applied filter instead.\n * - `count` adds a counter pill at the end, brand-coloured while selected.\n */\nexport function Chip(props: ChipProps): React.JSX.Element {\n const labels = useMediCoreLabels();\n\n if (props.onRemove) {\n const { size, leadingIcon, count, className, children, onRemove, ...rest } =\n props;\n\n return (\n <BaseButton\n data-slot=\"chip\"\n className={cn(chipVariants({ size }), className)}\n onClick={onRemove}\n {...rest}\n >\n {leadingIcon}\n <span className=\"sr-only\">{labels.remove} </span>\n {children}\n <ChipCount size={size} count={count} />\n <XCloseIcon />\n </BaseButton>\n );\n }\n\n const { size, leadingIcon, count, className, children, onRemove, ...rest } =\n props;\n\n return (\n <Toggle\n data-slot=\"chip\"\n className={cn(chipVariants({ size }), className)}\n {...rest}\n >\n <CheckIcon className=\"hidden group-data-pressed/chip:block\" />\n {leadingIcon && (\n <span className=\"contents group-data-pressed/chip:hidden\">\n {leadingIcon}\n </span>\n )}\n {children}\n <ChipCount size={size} count={count} />\n </Toggle>\n );\n}\n\nexport interface ChipGroupProps<Value extends string = string>\n extends Omit<ToggleGroup.Props<Value>, \"className\"> {\n /**\n * `wrap` (default) breaks into lines; `scroll` keeps one line that scrolls\n * sideways — the usual filter row on mobile.\n */\n overflow?: \"wrap\" | \"scroll\";\n className?: string;\n}\n\n/**\n * A row of filter chips with shared state: `value` is the array of pressed chips.\n * Multi-select by default (`multiple={false}` for one at a time — but an exclusive\n * choice between 2–3 options is a `SegmentedControl`). One tab stop; ←/→ move\n * between chips. Name it with `aria-label` (\"Filtrar por especialidad\").\n */\nexport function ChipGroup<Value extends string>({\n overflow = \"wrap\",\n multiple = true,\n className,\n ...props\n}: ChipGroupProps<Value>): React.JSX.Element {\n return (\n <ToggleGroup\n data-slot=\"chip-group\"\n multiple={multiple}\n className={cn(\n \"flex gap-2\",\n overflow === \"wrap\"\n ? \"flex-wrap\"\n : // Room for the hit area and the focus ring inside the scroll box.\n \"-m-1.5 overflow-x-auto p-1.5 [scrollbar-width:none]\",\n className,\n )}\n {...props}\n />\n );\n}\n"],"names":["size","leadingIcon","count","className","children","onRemove","rest","BaseButton"],"mappings":";;;;;;;;;AAUO,MAAM,eAAe;AAAA,EAC1B;AAAA,IACE;AAAA,IACA;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,EAAA;AAAA,EAEF;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,SACE;AAAA,QACF,OAAO;AAAA,MAAA;AAAA,IACT;AAAA,IAEF,iBAAiB;AAAA,MACf,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;AAEA,MAAM,oBAAoB;AAAA,EACxB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAEF;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,OAAO;AAAA,MAAA;AAAA,IACT;AAAA,IAEF,iBAAiB;AAAA,MACf,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;AAuCA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AACF,GAG6B;AAC3B,MAAI,UAAU,UAAa,UAAU,MAAM;AACzC,WAAO;AAAA,EACT;AACA,SACE,qBAAA,UAAA,EACG,UAAA;AAAA,IAAA;AAAA,IACD,oBAAC,QAAA,EAAK,aAAU,cAAa,WAAW,kBAAkB,EAAE,KAAA,CAAM,GAC/D,UAAA,MAAA,CACH;AAAA,EAAA,GACF;AAEJ;AAaO,SAAS,KAAK,OAAqC;AACxD,QAAM,SAAS,kBAAA;AAEf,MAAI,MAAM,UAAU;AAClB,UAAM,EAAE,MAAAA,OAAM,aAAAC,cAAa,OAAAC,QAAO,WAAAC,YAAW,UAAAC,WAAU,UAAAC,WAAU,GAAGC,UAClE;AAEF,WACE;AAAA,MAACC;AAAAA,MAAA;AAAA,QACC,aAAU;AAAA,QACV,WAAW,GAAG,aAAa,EAAE,MAAAP,MAAAA,CAAM,GAAGG,UAAS;AAAA,QAC/C,SAASE;AAAAA,QACR,GAAGC;AAAAA,QAEH,UAAA;AAAA,UAAAL;AAAAA,UACD,qBAAC,QAAA,EAAK,WAAU,WAAW,UAAA;AAAA,YAAA,OAAO;AAAA,YAAO;AAAA,UAAA,GAAC;AAAA,UACzCG;AAAAA,UACD,oBAAC,WAAA,EAAU,MAAMJ,OAAM,OAAOE,QAAO;AAAA,8BACpC,YAAA,CAAA,CAAW;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGlB;AAEA,QAAM,EAAE,MAAM,aAAa,OAAO,WAAW,UAAU,UAAU,GAAG,KAAA,IAClE;AAEF,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,aAAa,EAAE,KAAA,CAAM,GAAG,SAAS;AAAA,MAC9C,GAAG;AAAA,MAEJ,UAAA;AAAA,QAAA,oBAAC,WAAA,EAAU,WAAU,uCAAA,CAAuC;AAAA,QAC3D,eACC,oBAAC,QAAA,EAAK,WAAU,2CACb,UAAA,aACH;AAAA,QAED;AAAA,QACD,oBAAC,WAAA,EAAU,MAAY,MAAA,CAAc;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAG3C;AAkBO,SAAS,UAAgC;AAAA,EAC9C,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA,GAAG;AACL,GAA6C;AAC3C,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,aAAU;AAAA,MACV;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA,aAAa,SACT;AAAA;AAAA,UAEA;AAAA;AAAA,QACJ;AAAA,MAAA;AAAA,MAED,GAAG;AAAA,IAAA;AAAA,EAAA;AAGV;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Border, radius, fill and text colour of the box. */
|
|
2
|
-
export declare const controlBox = "w-full min-w-0 rounded-md border border-border
|
|
2
|
+
export declare const controlBox = "w-full min-w-0 rounded-md border border-border bg-background text-text-primary shadow-xs ring-1 ring-transparent ring-inset transition-[border-color,box-shadow]";
|
|
3
3
|
/** One-line content: 12px side padding, 8px between icon and text, Label/Default (14). */
|
|
4
4
|
export declare const controlRow = "flex items-center gap-2 px-3 text-label-default";
|
|
5
5
|
/** control-md (40) and control-sm (36): the same tokens as Button, so they line up. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const controlBox = "w-full min-w-0 rounded-md border border-border
|
|
1
|
+
const controlBox = "w-full min-w-0 rounded-md border border-border bg-background text-text-primary shadow-xs ring-1 ring-transparent ring-inset transition-[border-color,box-shadow]";
|
|
2
2
|
const controlRow = "flex items-center gap-2 px-3 text-label-default";
|
|
3
3
|
const controlHeight = {
|
|
4
4
|
default: "h-control-md",
|
|
@@ -7,17 +7,17 @@ const controlHeight = {
|
|
|
7
7
|
const wrappedControlStates = [
|
|
8
8
|
"has-[[aria-invalid=true]]:border-error has-[[aria-invalid=true]]:ring-error",
|
|
9
9
|
"has-[:focus:not(button)]:border-border-focus has-[:focus:not(button)]:ring-border-focus",
|
|
10
|
-
"has-[:is(input,select):disabled]:cursor-not-allowed has-[:is(input,select):disabled]:border-border has-[:is(input,select):disabled]:bg-surface has-[:is(input,select):disabled]:text-text-disabled"
|
|
10
|
+
"has-[:is(input,select):disabled]:cursor-not-allowed has-[:is(input,select):disabled]:border-border-subtle has-[:is(input,select):disabled]:bg-surface has-[:is(input,select):disabled]:text-text-disabled has-[:is(input,select):disabled]:shadow-none"
|
|
11
11
|
].join(" ");
|
|
12
12
|
const selfControlStates = [
|
|
13
13
|
"outline-none focus:border-border-focus focus:ring-border-focus",
|
|
14
14
|
"aria-invalid:not-focus:border-error aria-invalid:not-focus:ring-error",
|
|
15
|
-
"disabled:cursor-not-allowed disabled:border-border disabled:bg-surface disabled:text-text-disabled"
|
|
15
|
+
"disabled:cursor-not-allowed disabled:border-border-subtle disabled:bg-surface disabled:text-text-disabled disabled:shadow-none"
|
|
16
16
|
].join(" ");
|
|
17
17
|
const triggerControlStates = [
|
|
18
18
|
"outline-none focus:border-border-focus focus:ring-border-focus data-popup-open:border-border-focus data-popup-open:ring-border-focus",
|
|
19
19
|
"aria-invalid:not-focus:not-data-popup-open:border-error aria-invalid:not-focus:not-data-popup-open:ring-error",
|
|
20
|
-
"data-disabled:cursor-not-allowed data-disabled:border-border data-disabled:bg-surface data-disabled:text-text-disabled"
|
|
20
|
+
"data-disabled:cursor-not-allowed data-disabled:border-border-subtle data-disabled:bg-surface data-disabled:text-text-disabled data-disabled:shadow-none"
|
|
21
21
|
].join(" ");
|
|
22
22
|
const controlPlaceholder = "placeholder:text-text-secondary disabled:placeholder:text-text-disabled";
|
|
23
23
|
const controlIcon = "flex shrink-0 text-text-secondary [&_svg]:size-icon-sm group-has-[:is(input,select):disabled]/control:text-text-disabled group-data-disabled/control:text-text-disabled";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-styles.js","sources":["../../../src/components/input/control-styles.ts"],"sourcesContent":["/*\n * The box shared by Input, Textarea, Select, NativeSelect and PhoneInput. Figma draws\n * them as the same object on purpose: same radius, padding, border and states, so a\n * field and a dropdown in the same row only differ by the chevron.\n *\n * Focus and Error are a 2px border (border-thick), not just a colour change. The\n * second pixel is an inset ring, so the content never moves when the state changes.\n * Focus wins over Error: the message under the field keeps saying what is wrong.\n */\n\n/** Border, radius, fill and text colour of the box. */\nexport const controlBox =\n \"w-full min-w-0 rounded-md border border-border
|
|
1
|
+
{"version":3,"file":"control-styles.js","sources":["../../../src/components/input/control-styles.ts"],"sourcesContent":["/*\n * The box shared by Input, Textarea, Select, NativeSelect and PhoneInput. Figma draws\n * them as the same object on purpose: same radius, padding, border and states, so a\n * field and a dropdown in the same row only differ by the chevron.\n *\n * Focus and Error are a 2px border (border-thick), not just a colour change. The\n * second pixel is an inset ring, so the content never moves when the state changes.\n * Focus wins over Error: the message under the field keeps saying what is wrong.\n */\n\n/** Border, radius, fill and text colour of the box. */\nexport const controlBox =\n \"w-full min-w-0 rounded-md border border-border bg-background text-text-primary shadow-xs ring-1 ring-transparent ring-inset transition-[border-color,box-shadow]\";\n\n/** One-line content: 12px side padding, 8px between icon and text, Label/Default (14). */\nexport const controlRow = \"flex items-center gap-2 px-3 text-label-default\";\n\n/** control-md (40) and control-sm (36): the same tokens as Button, so they line up. */\nexport const controlHeight = {\n default: \"h-control-md\",\n small: \"h-control-sm\",\n} as const;\n\nexport type ControlSize = keyof typeof controlHeight;\n\n/**\n * States for a box that WRAPS the real control (Input, NativeSelect, the phone\n * prefix). Read from the control inside: `aria-invalid` (set by `invalid` or by\n * Field), `:focus` and `:disabled` (of the input/select only: a native select's\n * placeholder `<option disabled>` must not grey the box out). Buttons inside the box\n * (reveal password, clear) keep their own focus ring and don't light the box up.\n */\nexport const wrappedControlStates = [\n \"has-[[aria-invalid=true]]:border-error has-[[aria-invalid=true]]:ring-error\",\n \"has-[:focus:not(button)]:border-border-focus has-[:focus:not(button)]:ring-border-focus\",\n \"has-[:is(input,select):disabled]:cursor-not-allowed has-[:is(input,select):disabled]:border-border-subtle has-[:is(input,select):disabled]:bg-surface has-[:is(input,select):disabled]:text-text-disabled has-[:is(input,select):disabled]:shadow-none\",\n].join(\" \");\n\n/** States for a box that IS the control (Textarea). */\nexport const selfControlStates = [\n \"outline-none focus:border-border-focus focus:ring-border-focus\",\n \"aria-invalid:not-focus:border-error aria-invalid:not-focus:ring-error\",\n \"disabled:cursor-not-allowed disabled:border-border-subtle disabled:bg-surface disabled:text-text-disabled disabled:shadow-none\",\n].join(\" \");\n\n/**\n * States for a button box (Select trigger). It keeps the focus border while its popup\n * is open, because focus is inside the list then.\n */\nexport const triggerControlStates = [\n \"outline-none focus:border-border-focus focus:ring-border-focus data-popup-open:border-border-focus data-popup-open:ring-border-focus\",\n \"aria-invalid:not-focus:not-data-popup-open:border-error aria-invalid:not-focus:not-data-popup-open:ring-error\",\n \"data-disabled:cursor-not-allowed data-disabled:border-border-subtle data-disabled:bg-surface data-disabled:text-text-disabled data-disabled:shadow-none\",\n].join(\" \");\n\n/** Placeholder: the same Value node in text-secondary, never a variant. */\nexport const controlPlaceholder =\n \"placeholder:text-text-secondary disabled:placeholder:text-text-disabled\";\n\n/**\n * Leading / trailing icon slot: 16px in text-secondary (5.07:1), disabled with the\n * box. The box carries `group/control`.\n */\nexport const controlIcon =\n \"flex shrink-0 text-text-secondary [&_svg]:size-icon-sm group-has-[:is(input,select):disabled]/control:text-text-disabled group-data-disabled/control:text-text-disabled\";\n\n/** Small icon button inside the box (reveal password, clear). 44px hit area. */\nexport const controlAction =\n \"focus-ring touch-target -me-1 inline-flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-sm text-text-secondary transition-colors hover:text-text-primary disabled:cursor-not-allowed disabled:text-text-disabled [&_svg]:size-icon-sm\";\n"],"names":[],"mappings":"AAWO,MAAM,aACX;AAGK,MAAM,aAAa;AAGnB,MAAM,gBAAgB;AAAA,EAC3B,SAAS;AAAA,EACT,OAAO;AACT;AAWO,MAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AAGH,MAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AAMH,MAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AAGH,MAAM,qBACX;AAMK,MAAM,cACX;AAGK,MAAM,gBACX;"}
|