@pipe0/react 0.0.8 → 0.0.10
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/CHANGELOG.md +16 -0
- package/dist/components/defaults/layout/section.mjs +1 -1
- package/dist/components/defaults/layout/section.mjs.map +1 -1
- package/dist/components/ui/button.d.mts +1 -1
- package/dist/styles/pipe0-form.css +74 -0
- package/dist/widgets/avatar-group.mjs +2 -2
- package/dist/widgets/avatar-group.mjs.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @pipe0/elements-react
|
|
2
2
|
|
|
3
|
+
## 0.0.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fix unprefixed classes
|
|
8
|
+
- Updated dependencies
|
|
9
|
+
- @pipe0/base@0.0.10
|
|
10
|
+
|
|
11
|
+
## 0.0.9
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- v1 preparations
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- @pipe0/base@0.0.9
|
|
18
|
+
|
|
3
19
|
## 0.0.8
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -10,7 +10,7 @@ function DefaultSection({ section, children, className, render, hideLabel, ...pr
|
|
|
10
10
|
const hasErrors = section.groups.some((g) => g.errorCount > 0);
|
|
11
11
|
const defaultContent = /* @__PURE__ */ jsxs(Fragment, { children: [!hideLabel && section.label && /* @__PURE__ */ jsxs("div", {
|
|
12
12
|
"data-p0": "section-header",
|
|
13
|
-
className: classNames?.sectionLabel ?? "pz:flex pz:items-center pz:gap-2.5 pz:px-1 mb-0.5 mt-2 pz:select-none",
|
|
13
|
+
className: classNames?.sectionLabel ?? "pz:flex pz:items-center pz:gap-2.5 pz:px-1 pz:mb-0.5 pz:mt-2 pz:select-none",
|
|
14
14
|
children: [/* @__PURE__ */ jsx("h2", {
|
|
15
15
|
className: cn("pz:text-[10.5px] pz:font-medium pz:tracking-[0.12em] pz:uppercase pz:text-muted-foreground pz:m-0 pz:whitespace-nowrap"),
|
|
16
16
|
children: section.label
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"section.mjs","names":[],"sources":["../../../../src/components/defaults/layout/section.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { useFormConfig } from \"../../../context/form-context.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport type { FormGroupHandle, FormSectionHandle } from \"../../../types/form-handle.js\";\n\nexport interface DefaultSectionState {\n groups: ReadonlyArray<FormGroupHandle>;\n hasErrors: boolean;\n}\n\nexport interface DefaultSectionProps extends useRender.ComponentProps<\"div\", DefaultSectionState> {\n section: FormSectionHandle;\n /**\n * Suppress the section's own header. Set when several consecutive sections\n * share an umbrella label so the label only renders above the first\n * section in the cluster (the renderer in `pipe-form/content.tsx` and\n * `search-form/content.tsx` handles this automatically).\n */\n hideLabel?: boolean;\n}\n\nexport function DefaultSection({\n section,\n children,\n className,\n render,\n hideLabel,\n ...props\n}: DefaultSectionProps) {\n const { classNames } = useFormConfig();\n const hasErrors = section.groups.some((g) => g.errorCount > 0);\n\n // Section descriptions are intentionally not rendered — the umbrella label\n // alone is enough signal, and per-section descriptions add noise once\n // multiple sections sit under one umbrella. Field-level descriptions cover\n // the cases where copy is actually load-bearing.\n const defaultContent = (\n <>\n {!hideLabel && section.label && (\n <div\n data-p0=\"section-header\"\n className={\n classNames?.sectionLabel ??\n \"pz:flex pz:items-center pz:gap-2.5 pz:px-1 mb-0.5 mt-2 pz:select-none\"\n }\n >\n <h2\n className={cn(\n \"pz:text-[10.5px] pz:font-medium pz:tracking-[0.12em] pz:uppercase pz:text-muted-foreground pz:m-0 pz:whitespace-nowrap\",\n )}\n >\n {section.label}\n </h2>\n <span aria-hidden className=\"pz:flex-1 pz:h-px pz:bg-border\" />\n </div>\n )}\n {children}\n </>\n );\n\n return useRender({\n defaultTagName: \"div\",\n render,\n state: { groups: section.groups, hasErrors },\n stateAttributesMapping: {\n groups: () => null,\n },\n props: mergeProps<\"div\">(\n {\n className: cn(classNames?.section ?? \"pz:flex pz:flex-col pz:gap-2\", className),\n children: defaultContent,\n ...({\n \"data-p0\": \"section\",\n \"data-p0-section\": section.key,\n } as Record<string, string>),\n },\n props,\n ),\n });\n}\n"],"mappings":";;;;;;;AAsBA,SAAgB,eAAe,EAC7B,SACA,UACA,WACA,QACA,WACA,GAAG,SACmB;CACtB,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,YAAY,QAAQ,OAAO,MAAM,MAAM,EAAE,aAAa,EAAE;CAM9D,MAAM,iBACJ,4CACG,CAAC,aAAa,QAAQ,SACrB,qBAAC,OAAD;EACE,WAAQ;EACR,WACE,YAAY,gBACZ;YAJJ,CAOE,oBAAC,MAAD;GACE,WAAW,GACT,yHACD;aAEA,QAAQ;GACN,GACL,oBAAC,QAAD;GAAM;GAAY,WAAU;GAAmC,EAC3D;KAEP,SACA;AAGL,QAAO,UAAU;EACf,gBAAgB;EAChB;EACA,OAAO;GAAE,QAAQ,QAAQ;GAAQ;GAAW;EAC5C,wBAAwB,EACtB,cAAc,MACf;EACD,OAAO,WACL;GACE,WAAW,GAAG,YAAY,WAAW,gCAAgC,UAAU;GAC/E,UAAU;GAER,WAAW;GACX,mBAAmB,QAAQ;GAE9B,EACD,MACD;EACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"section.mjs","names":[],"sources":["../../../../src/components/defaults/layout/section.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { useFormConfig } from \"../../../context/form-context.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport type { FormGroupHandle, FormSectionHandle } from \"../../../types/form-handle.js\";\n\nexport interface DefaultSectionState {\n groups: ReadonlyArray<FormGroupHandle>;\n hasErrors: boolean;\n}\n\nexport interface DefaultSectionProps extends useRender.ComponentProps<\"div\", DefaultSectionState> {\n section: FormSectionHandle;\n /**\n * Suppress the section's own header. Set when several consecutive sections\n * share an umbrella label so the label only renders above the first\n * section in the cluster (the renderer in `pipe-form/content.tsx` and\n * `search-form/content.tsx` handles this automatically).\n */\n hideLabel?: boolean;\n}\n\nexport function DefaultSection({\n section,\n children,\n className,\n render,\n hideLabel,\n ...props\n}: DefaultSectionProps) {\n const { classNames } = useFormConfig();\n const hasErrors = section.groups.some((g) => g.errorCount > 0);\n\n // Section descriptions are intentionally not rendered — the umbrella label\n // alone is enough signal, and per-section descriptions add noise once\n // multiple sections sit under one umbrella. Field-level descriptions cover\n // the cases where copy is actually load-bearing.\n const defaultContent = (\n <>\n {!hideLabel && section.label && (\n <div\n data-p0=\"section-header\"\n className={\n classNames?.sectionLabel ??\n \"pz:flex pz:items-center pz:gap-2.5 pz:px-1 pz:mb-0.5 pz:mt-2 pz:select-none\"\n }\n >\n <h2\n className={cn(\n \"pz:text-[10.5px] pz:font-medium pz:tracking-[0.12em] pz:uppercase pz:text-muted-foreground pz:m-0 pz:whitespace-nowrap\",\n )}\n >\n {section.label}\n </h2>\n <span aria-hidden className=\"pz:flex-1 pz:h-px pz:bg-border\" />\n </div>\n )}\n {children}\n </>\n );\n\n return useRender({\n defaultTagName: \"div\",\n render,\n state: { groups: section.groups, hasErrors },\n stateAttributesMapping: {\n groups: () => null,\n },\n props: mergeProps<\"div\">(\n {\n className: cn(classNames?.section ?? \"pz:flex pz:flex-col pz:gap-2\", className),\n children: defaultContent,\n ...({\n \"data-p0\": \"section\",\n \"data-p0-section\": section.key,\n } as Record<string, string>),\n },\n props,\n ),\n });\n}\n"],"mappings":";;;;;;;AAsBA,SAAgB,eAAe,EAC7B,SACA,UACA,WACA,QACA,WACA,GAAG,SACmB;CACtB,MAAM,EAAE,eAAe,eAAe;CACtC,MAAM,YAAY,QAAQ,OAAO,MAAM,MAAM,EAAE,aAAa,EAAE;CAM9D,MAAM,iBACJ,4CACG,CAAC,aAAa,QAAQ,SACrB,qBAAC,OAAD;EACE,WAAQ;EACR,WACE,YAAY,gBACZ;YAJJ,CAOE,oBAAC,MAAD;GACE,WAAW,GACT,yHACD;aAEA,QAAQ;GACN,GACL,oBAAC,QAAD;GAAM;GAAY,WAAU;GAAmC,EAC3D;KAEP,SACA;AAGL,QAAO,UAAU;EACf,gBAAgB;EAChB;EACA,OAAO;GAAE,QAAQ,QAAQ;GAAQ;GAAW;EAC5C,wBAAwB,EACtB,cAAc,MACf;EACD,OAAO,WACL;GACE,WAAW,GAAG,YAAY,WAAW,gCAAgC,UAAU;GAC/E,UAAU;GAER,WAAW;GACX,mBAAmB,QAAQ;GAE9B,EACD,MACD;EACF,CAAC"}
|
|
@@ -5,7 +5,7 @@ import * as _$class_variance_authority_types0 from "class-variance-authority/typ
|
|
|
5
5
|
|
|
6
6
|
//#region src/components/ui/button.d.ts
|
|
7
7
|
declare const buttonVariants: (props?: ({
|
|
8
|
-
variant?: "
|
|
8
|
+
variant?: "default" | "link" | "outline" | "secondary" | "ghost" | "destructive" | null | undefined;
|
|
9
9
|
size?: "default" | "icon" | "xs" | "sm" | "lg" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
|
|
10
10
|
} & _$class_variance_authority_types0.ClassProp) | undefined) => string;
|
|
11
11
|
declare function Button$1({
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
--pz-font-weight-normal: 400;
|
|
61
61
|
--pz-font-weight-medium: 500;
|
|
62
62
|
--pz-font-weight-semibold: 600;
|
|
63
|
+
--pz-tracking-tight: -0.025em;
|
|
63
64
|
--pz-tracking-normal: 0em;
|
|
64
65
|
--pz-tracking-wide: 0.025em;
|
|
65
66
|
--pz-tracking-widest: 0.1em;
|
|
@@ -171,6 +172,9 @@
|
|
|
171
172
|
.pz\:mt-1 {
|
|
172
173
|
margin-top: calc(var(--pz-spacing) * 1);
|
|
173
174
|
}
|
|
175
|
+
.pz\:mt-2 {
|
|
176
|
+
margin-top: calc(var(--pz-spacing) * 2);
|
|
177
|
+
}
|
|
174
178
|
.pz\:mt-4 {
|
|
175
179
|
margin-top: calc(var(--pz-spacing) * 4);
|
|
176
180
|
}
|
|
@@ -180,6 +184,12 @@
|
|
|
180
184
|
.pz\:-mb-4 {
|
|
181
185
|
margin-bottom: calc(var(--pz-spacing) * -4);
|
|
182
186
|
}
|
|
187
|
+
.pz\:mb-0\.5 {
|
|
188
|
+
margin-bottom: calc(var(--pz-spacing) * 0.5);
|
|
189
|
+
}
|
|
190
|
+
.pz\:mb-2 {
|
|
191
|
+
margin-bottom: calc(var(--pz-spacing) * 2);
|
|
192
|
+
}
|
|
183
193
|
.pz\:-ml-1 {
|
|
184
194
|
margin-left: calc(var(--pz-spacing) * -1);
|
|
185
195
|
}
|
|
@@ -496,6 +506,9 @@
|
|
|
496
506
|
.pz\:rotate-45 {
|
|
497
507
|
rotate: 45deg;
|
|
498
508
|
}
|
|
509
|
+
.pz\:rotate-180 {
|
|
510
|
+
rotate: 180deg;
|
|
511
|
+
}
|
|
499
512
|
.pz\:animate-pulse {
|
|
500
513
|
animation: var(--pz-animate-pulse);
|
|
501
514
|
}
|
|
@@ -684,6 +697,10 @@
|
|
|
684
697
|
.pz\:rounded-tl-lg {
|
|
685
698
|
border-top-left-radius: var(--p0-radius);
|
|
686
699
|
}
|
|
700
|
+
.pz\:rounded-b-md {
|
|
701
|
+
border-bottom-right-radius: calc(var(--p0-radius) - 2px);
|
|
702
|
+
border-bottom-left-radius: calc(var(--p0-radius) - 2px);
|
|
703
|
+
}
|
|
687
704
|
.pz\:rounded-b-xl {
|
|
688
705
|
border-bottom-right-radius: calc(var(--p0-radius) + 4px);
|
|
689
706
|
border-bottom-left-radius: calc(var(--p0-radius) + 4px);
|
|
@@ -860,6 +877,12 @@
|
|
|
860
877
|
background-color: color-mix(in oklab, var(--p0-muted) 20%, transparent);
|
|
861
878
|
}
|
|
862
879
|
}
|
|
880
|
+
.pz\:bg-muted\/30 {
|
|
881
|
+
background-color: var(--p0-muted);
|
|
882
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
883
|
+
background-color: color-mix(in oklab, var(--p0-muted) 30%, transparent);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
863
886
|
.pz\:bg-muted\/40 {
|
|
864
887
|
background-color: var(--p0-muted);
|
|
865
888
|
@supports (color: color-mix(in lab, red, red)) {
|
|
@@ -1034,6 +1057,9 @@
|
|
|
1034
1057
|
.pz\:pb-3 {
|
|
1035
1058
|
padding-bottom: calc(var(--pz-spacing) * 3);
|
|
1036
1059
|
}
|
|
1060
|
+
.pz\:pb-3\.5 {
|
|
1061
|
+
padding-bottom: calc(var(--pz-spacing) * 3.5);
|
|
1062
|
+
}
|
|
1037
1063
|
.pz\:pl-0 {
|
|
1038
1064
|
padding-left: calc(var(--pz-spacing) * 0);
|
|
1039
1065
|
}
|
|
@@ -1144,6 +1170,10 @@
|
|
|
1144
1170
|
--tw-tracking: var(--pz-tracking-normal);
|
|
1145
1171
|
letter-spacing: var(--pz-tracking-normal);
|
|
1146
1172
|
}
|
|
1173
|
+
.pz\:tracking-tight {
|
|
1174
|
+
--tw-tracking: var(--pz-tracking-tight);
|
|
1175
|
+
letter-spacing: var(--pz-tracking-tight);
|
|
1176
|
+
}
|
|
1147
1177
|
.pz\:tracking-wide {
|
|
1148
1178
|
--tw-tracking: var(--pz-tracking-wide);
|
|
1149
1179
|
letter-spacing: var(--pz-tracking-wide);
|
|
@@ -1729,6 +1759,16 @@
|
|
|
1729
1759
|
}
|
|
1730
1760
|
}
|
|
1731
1761
|
}
|
|
1762
|
+
.pz\:hover\:bg-muted\/80 {
|
|
1763
|
+
&:hover {
|
|
1764
|
+
@media (hover: hover) {
|
|
1765
|
+
background-color: var(--p0-muted);
|
|
1766
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
1767
|
+
background-color: color-mix(in oklab, var(--p0-muted) 80%, transparent);
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1732
1772
|
.pz\:hover\:bg-primary {
|
|
1733
1773
|
&:hover {
|
|
1734
1774
|
@media (hover: hover) {
|
|
@@ -1812,6 +1852,14 @@
|
|
|
1812
1852
|
}
|
|
1813
1853
|
}
|
|
1814
1854
|
}
|
|
1855
|
+
.pz\:hover\:shadow-sm {
|
|
1856
|
+
&:hover {
|
|
1857
|
+
@media (hover: hover) {
|
|
1858
|
+
--tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
|
1859
|
+
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1815
1863
|
.pz\:focus\:bg-accent {
|
|
1816
1864
|
&:focus {
|
|
1817
1865
|
background-color: var(--p0-accent);
|
|
@@ -2278,6 +2326,16 @@
|
|
|
2278
2326
|
height: calc(var(--pz-spacing) * 0);
|
|
2279
2327
|
}
|
|
2280
2328
|
}
|
|
2329
|
+
.pz\:data-\[active\]\:bg-accent {
|
|
2330
|
+
&[data-active] {
|
|
2331
|
+
background-color: var(--p0-accent);
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
.pz\:data-\[active\]\:text-accent-foreground {
|
|
2335
|
+
&[data-active] {
|
|
2336
|
+
color: var(--p0-accent-foreground);
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2281
2339
|
.pz\:data-\[align-trigger\=true\]\:animate-none {
|
|
2282
2340
|
&[data-align-trigger="true"] {
|
|
2283
2341
|
animation: none;
|
|
@@ -2695,6 +2753,16 @@
|
|
|
2695
2753
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
2696
2754
|
}
|
|
2697
2755
|
}
|
|
2756
|
+
.pz\:dark\:block {
|
|
2757
|
+
&:is(:is(.p0-dark, .dark) *) {
|
|
2758
|
+
display: block;
|
|
2759
|
+
}
|
|
2760
|
+
}
|
|
2761
|
+
.pz\:dark\:hidden {
|
|
2762
|
+
&:is(:is(.p0-dark, .dark) *) {
|
|
2763
|
+
display: none;
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2698
2766
|
.pz\:dark\:border-input {
|
|
2699
2767
|
&:is(:is(.p0-dark, .dark) *) {
|
|
2700
2768
|
border-color: var(--p0-input);
|
|
@@ -3169,6 +3237,12 @@
|
|
|
3169
3237
|
height: calc(var(--pz-spacing) * 2);
|
|
3170
3238
|
}
|
|
3171
3239
|
}
|
|
3240
|
+
.pz\:\[\&_svg\]\:size-3 {
|
|
3241
|
+
& svg {
|
|
3242
|
+
width: calc(var(--pz-spacing) * 3);
|
|
3243
|
+
height: calc(var(--pz-spacing) * 3);
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3172
3246
|
.pz\:\[\&_svg\]\:shrink-0 {
|
|
3173
3247
|
& svg {
|
|
3174
3248
|
flex-shrink: 0;
|
|
@@ -86,11 +86,11 @@ function ProviderTile({ provider, size, first }) {
|
|
|
86
86
|
title: entry?.label ?? provider,
|
|
87
87
|
children: [bg ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
88
88
|
"aria-hidden": "true",
|
|
89
|
-
className: "pz:absolute pz:inset-0 dark:
|
|
89
|
+
className: "pz:absolute pz:inset-0 pz:dark:hidden",
|
|
90
90
|
style: { backgroundColor: bg.light }
|
|
91
91
|
}), /* @__PURE__ */ jsx("div", {
|
|
92
92
|
"aria-hidden": "true",
|
|
93
|
-
className: "pz:absolute pz:inset-0 pz:hidden dark:
|
|
93
|
+
className: "pz:absolute pz:inset-0 pz:hidden pz:dark:block",
|
|
94
94
|
style: { backgroundColor: bg.dark }
|
|
95
95
|
})] }) : /* @__PURE__ */ jsx("div", {
|
|
96
96
|
"aria-hidden": "true",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"avatar-group.mjs","names":[],"sources":["../../src/widgets/avatar-group.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { getProviderEntry, type ProviderName } from \"@pipe0/base\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { type CSSProperties, forwardRef } from \"react\";\nimport { cn } from \"../lib/utils.js\";\n\nconst avatarGroupVariants = cva(\"pz:relative pz:inline-flex pz:items-center\", {\n variants: {\n size: {\n sm: \"\",\n md: \"\",\n lg: \"\",\n },\n },\n defaultVariants: { size: \"md\" },\n});\n\nconst tileSize = {\n sm: \"pz:h-5 pz:w-5\",\n md: \"pz:h-8 pz:w-8\",\n lg: \"pz:h-12 pz:w-12\",\n} as const;\n\nconst tileLogoSize = {\n sm: \"pz:size-3\",\n md: \"pz:size-5\",\n lg: \"pz:size-7\",\n} as const;\n\nconst tileOverlap = {\n sm: \"pz:-ml-1\",\n md: \"pz:-ml-1.5\",\n lg: \"pz:-ml-2\",\n} as const;\n\nconst overflowText = {\n sm: \"pz:text-[9px]\",\n md: \"pz:text-xs\",\n lg: \"pz:text-sm\",\n} as const;\n\nconst DEFAULT_MAX_TILES = 4;\n\nexport interface AvatarGroupState {\n overflows: boolean;\n remaining: number;\n}\n\nexport interface AvatarGroupProps\n extends VariantProps<typeof avatarGroupVariants>,\n useRender.ComponentProps<\"div\", AvatarGroupState> {\n providers: readonly ProviderName[];\n /** Maximum tile slots before the overflow indicator. Default 4. */\n max?: number;\n /** Show the +N overflow tile when providers exceed `max`. Default true. */\n showCount?: boolean;\n}\n\n/**\n * Horizontal stack of provider tiles. Each tile is a brand-colored rectangle\n * with the provider's logo on top; tiles overlap slightly to read as a group.\n * Defaults to a maximum of 4 tiles, then a \"+N\" overflow tile.\n *\n * Pure visual — no popover. For a hover-card with cost-per-provider, see\n * `<CatalogProviderAvatars>`.\n */\nexport const AvatarGroup = forwardRef<HTMLDivElement, AvatarGroupProps>(function AvatarGroup(\n { providers, size, max = DEFAULT_MAX_TILES, showCount = true, className, render, ...rest },\n ref,\n) {\n const sizeKey = size ?? \"md\";\n const overflows = providers.length > max;\n const renderOverflow = overflows && showCount;\n const visibleSlots = renderOverflow ? max - 1 : max;\n const shown = providers.slice(0, visibleSlots);\n const remaining = providers.length - shown.length;\n\n const element = useRender({\n ref,\n defaultTagName: \"div\",\n render,\n state: { overflows, remaining },\n props: mergeProps<\"div\">(\n {\n className: cn(avatarGroupVariants({ size }), className),\n children: (\n <>\n {shown.map((provider, i) => (\n <ProviderTile key={provider} provider={provider} size={sizeKey} first={i === 0} />\n ))}\n {renderOverflow ? (\n <OverflowTile size={sizeKey} count={remaining} first={shown.length === 0} />\n ) : null}\n </>\n ),\n ...({ \"data-p0\": \"avatar-group\" } as Record<string, string>),\n },\n rest as Record<string, unknown>,\n ),\n });\n\n if (!providers.length) return null;\n return element;\n});\n\nconst tileBase =\n \"pz:relative pz:flex pz:items-center pz:justify-center pz:rounded-md pz:overflow-hidden pz:ring-2 pz:ring-background pz:shrink-0\";\n\nfunction ProviderTile({\n provider,\n size,\n first,\n}: {\n provider: ProviderName;\n size: \"sm\" | \"md\" | \"lg\";\n first: boolean;\n}) {\n const entry = getProviderEntry(provider);\n const bg = entry?.background;\n return (\n <div\n data-p0=\"avatar-group-tile\"\n className={cn(tileBase, tileSize[size], first ? undefined : tileOverlap[size])}\n title={entry?.label ?? provider}\n >\n {bg ? (\n <>\n <div\n aria-hidden=\"true\"\n className=\"pz:absolute pz:inset-0 dark:
|
|
1
|
+
{"version":3,"file":"avatar-group.mjs","names":[],"sources":["../../src/widgets/avatar-group.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { getProviderEntry, type ProviderName } from \"@pipe0/base\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { type CSSProperties, forwardRef } from \"react\";\nimport { cn } from \"../lib/utils.js\";\n\nconst avatarGroupVariants = cva(\"pz:relative pz:inline-flex pz:items-center\", {\n variants: {\n size: {\n sm: \"\",\n md: \"\",\n lg: \"\",\n },\n },\n defaultVariants: { size: \"md\" },\n});\n\nconst tileSize = {\n sm: \"pz:h-5 pz:w-5\",\n md: \"pz:h-8 pz:w-8\",\n lg: \"pz:h-12 pz:w-12\",\n} as const;\n\nconst tileLogoSize = {\n sm: \"pz:size-3\",\n md: \"pz:size-5\",\n lg: \"pz:size-7\",\n} as const;\n\nconst tileOverlap = {\n sm: \"pz:-ml-1\",\n md: \"pz:-ml-1.5\",\n lg: \"pz:-ml-2\",\n} as const;\n\nconst overflowText = {\n sm: \"pz:text-[9px]\",\n md: \"pz:text-xs\",\n lg: \"pz:text-sm\",\n} as const;\n\nconst DEFAULT_MAX_TILES = 4;\n\nexport interface AvatarGroupState {\n overflows: boolean;\n remaining: number;\n}\n\nexport interface AvatarGroupProps\n extends VariantProps<typeof avatarGroupVariants>,\n useRender.ComponentProps<\"div\", AvatarGroupState> {\n providers: readonly ProviderName[];\n /** Maximum tile slots before the overflow indicator. Default 4. */\n max?: number;\n /** Show the +N overflow tile when providers exceed `max`. Default true. */\n showCount?: boolean;\n}\n\n/**\n * Horizontal stack of provider tiles. Each tile is a brand-colored rectangle\n * with the provider's logo on top; tiles overlap slightly to read as a group.\n * Defaults to a maximum of 4 tiles, then a \"+N\" overflow tile.\n *\n * Pure visual — no popover. For a hover-card with cost-per-provider, see\n * `<CatalogProviderAvatars>`.\n */\nexport const AvatarGroup = forwardRef<HTMLDivElement, AvatarGroupProps>(function AvatarGroup(\n { providers, size, max = DEFAULT_MAX_TILES, showCount = true, className, render, ...rest },\n ref,\n) {\n const sizeKey = size ?? \"md\";\n const overflows = providers.length > max;\n const renderOverflow = overflows && showCount;\n const visibleSlots = renderOverflow ? max - 1 : max;\n const shown = providers.slice(0, visibleSlots);\n const remaining = providers.length - shown.length;\n\n const element = useRender({\n ref,\n defaultTagName: \"div\",\n render,\n state: { overflows, remaining },\n props: mergeProps<\"div\">(\n {\n className: cn(avatarGroupVariants({ size }), className),\n children: (\n <>\n {shown.map((provider, i) => (\n <ProviderTile key={provider} provider={provider} size={sizeKey} first={i === 0} />\n ))}\n {renderOverflow ? (\n <OverflowTile size={sizeKey} count={remaining} first={shown.length === 0} />\n ) : null}\n </>\n ),\n ...({ \"data-p0\": \"avatar-group\" } as Record<string, string>),\n },\n rest as Record<string, unknown>,\n ),\n });\n\n if (!providers.length) return null;\n return element;\n});\n\nconst tileBase =\n \"pz:relative pz:flex pz:items-center pz:justify-center pz:rounded-md pz:overflow-hidden pz:ring-2 pz:ring-background pz:shrink-0\";\n\nfunction ProviderTile({\n provider,\n size,\n first,\n}: {\n provider: ProviderName;\n size: \"sm\" | \"md\" | \"lg\";\n first: boolean;\n}) {\n const entry = getProviderEntry(provider);\n const bg = entry?.background;\n return (\n <div\n data-p0=\"avatar-group-tile\"\n className={cn(tileBase, tileSize[size], first ? undefined : tileOverlap[size])}\n title={entry?.label ?? provider}\n >\n {bg ? (\n <>\n <div\n aria-hidden=\"true\"\n className=\"pz:absolute pz:inset-0 pz:dark:hidden\"\n style={{ backgroundColor: bg.light } as CSSProperties}\n />\n <div\n aria-hidden=\"true\"\n className=\"pz:absolute pz:inset-0 pz:hidden pz:dark:block\"\n style={{ backgroundColor: bg.dark } as CSSProperties}\n />\n </>\n ) : (\n <div aria-hidden=\"true\" className=\"pz:absolute pz:inset-0 pz:bg-muted\" />\n )}\n {entry?.logoUrl ? (\n <img\n src={entry.logoUrl}\n alt={entry.label ?? provider}\n className={cn(\"pz:relative pz:object-contain\", tileLogoSize[size])}\n />\n ) : null}\n </div>\n );\n}\n\nfunction OverflowTile({\n size,\n count,\n first,\n}: {\n size: \"sm\" | \"md\" | \"lg\";\n count: number;\n first: boolean;\n}) {\n return (\n <div\n data-p0=\"avatar-group-overflow\"\n className={cn(\n tileBase,\n \"pz:bg-muted pz:text-muted-foreground pz:font-medium\",\n tileSize[size],\n overflowText[size],\n first ? undefined : tileOverlap[size],\n )}\n >\n +{count}\n </div>\n );\n}\n\nexport { avatarGroupVariants, tileSize as avatarSize };\n"],"mappings":";;;;;;;;;AAOA,MAAM,sBAAsB,IAAI,8CAA8C;CAC5E,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;EACL,EACF;CACD,iBAAiB,EAAE,MAAM,MAAM;CAChC,CAAC;AAEF,MAAM,WAAW;CACf,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,eAAe;CACnB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,cAAc;CAClB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,eAAe;CACnB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,MAAM,oBAAoB;;;;;;;;;AAyB1B,MAAa,cAAc,WAA6C,SAAS,YAC/E,EAAE,WAAW,MAAM,MAAM,mBAAmB,YAAY,MAAM,WAAW,QAAQ,GAAG,QACpF,KACA;CACA,MAAM,UAAU,QAAQ;CACxB,MAAM,YAAY,UAAU,SAAS;CACrC,MAAM,iBAAiB,aAAa;CACpC,MAAM,eAAe,iBAAiB,MAAM,IAAI;CAChD,MAAM,QAAQ,UAAU,MAAM,GAAG,aAAa;CAC9C,MAAM,YAAY,UAAU,SAAS,MAAM;CAE3C,MAAM,UAAU,UAAU;EACxB;EACA,gBAAgB;EAChB;EACA,OAAO;GAAE;GAAW;GAAW;EAC/B,OAAO,WACL;GACE,WAAW,GAAG,oBAAoB,EAAE,MAAM,CAAC,EAAE,UAAU;GACvD,UACE,8CACG,MAAM,KAAK,UAAU,MACpB,oBAAC,cAAD;IAAuC;IAAU,MAAM;IAAS,OAAO,MAAM;IAAK,EAA/D,SAA+D,CAClF,EACD,iBACC,oBAAC,cAAD;IAAc,MAAM;IAAS,OAAO;IAAW,OAAO,MAAM,WAAW;IAAK,IAC1E,KACH;GAEC,WAAW;GAClB,EACD,KACD;EACF,CAAC;AAEF,KAAI,CAAC,UAAU,OAAQ,QAAO;AAC9B,QAAO;EACP;AAEF,MAAM,WACJ;AAEF,SAAS,aAAa,EACpB,UACA,MACA,SAKC;CACD,MAAM,QAAQ,iBAAiB,SAAS;CACxC,MAAM,KAAK,OAAO;AAClB,QACE,qBAAC,OAAD;EACE,WAAQ;EACR,WAAW,GAAG,UAAU,SAAS,OAAO,QAAQ,SAAY,YAAY,MAAM;EAC9E,OAAO,OAAO,SAAS;YAHzB,CAKG,KACC,8CACE,oBAAC,OAAD;GACE,eAAY;GACZ,WAAU;GACV,OAAO,EAAE,iBAAiB,GAAG,OAAO;GACpC,GACF,oBAAC,OAAD;GACE,eAAY;GACZ,WAAU;GACV,OAAO,EAAE,iBAAiB,GAAG,MAAM;GACnC,EACD,MAEH,oBAAC,OAAD;GAAK,eAAY;GAAO,WAAU;GAAuC,GAE1E,OAAO,UACN,oBAAC,OAAD;GACE,KAAK,MAAM;GACX,KAAK,MAAM,SAAS;GACpB,WAAW,GAAG,iCAAiC,aAAa,MAAM;GAClE,IACA,KACA;;;AAIV,SAAS,aAAa,EACpB,MACA,OACA,SAKC;AACD,QACE,qBAAC,OAAD;EACE,WAAQ;EACR,WAAW,GACT,UACA,uDACA,SAAS,OACT,aAAa,OACb,QAAQ,SAAY,YAAY,MACjC;YARH,CASC,KACG,MACE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pipe0/react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"description": "React component library for building forms and catalogs powered by pipe0 pipes and searches.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "pipe0",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"lucide-react": "^0.475.0",
|
|
88
88
|
"swr": "^2.4.1",
|
|
89
89
|
"tailwind-merge": "^3.3.1",
|
|
90
|
-
"@pipe0/base": "0.0.
|
|
90
|
+
"@pipe0/base": "0.0.10"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
93
|
"@dnd-kit/core": "^6.3.1",
|