@giddaa-housing/ui 3.3.0 → 3.5.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/css/generated/shared.css +1 -1
- package/css/theme.css +20 -0
- package/dist/accordion.js +1 -1
- package/dist/activity-timeline.js +1 -1
- package/dist/alert.js +1 -1
- package/dist/auth-layout.js +1 -1
- package/dist/avatar.js +1 -1
- package/dist/badge.js +6 -1
- package/dist/bar-chart.js +1 -1
- package/dist/breadcrumb.js +1 -1
- package/dist/bullet-chart.js +1 -1
- package/dist/button-group.js +1 -1
- package/dist/button.js +1 -1
- package/dist/calendar.js +2 -2
- package/dist/call-card.js +1 -1
- package/dist/card.js +1 -1
- package/dist/carousel.js +2 -2
- package/dist/chart.js +1 -1
- package/dist/chat.js +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/collapsible.js +1 -1
- package/dist/combobox-B7cKFJ9V.js +398 -0
- package/dist/combobox.d.ts +2 -2
- package/dist/combobox.js +1 -308
- package/dist/cta.js +1 -1
- package/dist/currency-selector.js +2 -2
- package/dist/data-table.d.ts +1 -1
- package/dist/data-table.js +1 -1
- package/dist/date-picker.d.ts +4 -3
- package/dist/date-picker.js +7 -17
- package/dist/details-card.js +1 -1
- package/dist/dialog.js +1 -1
- package/dist/dropdown-menu.js +1 -1
- package/dist/dropzone.js +1 -1
- package/dist/editorial-card.js +2 -4
- package/dist/empty-state.js +1 -1
- package/dist/field.js +1 -1
- package/dist/file-upload.js +1 -1
- package/dist/filter.js +1 -1
- package/dist/footer.js +1 -1
- package/dist/funnel-chart.js +1 -1
- package/dist/gallery-indicator.js +1 -1
- package/dist/icons-C9JXR5Xv.d.ts +111 -0
- package/dist/icons.d.ts +2 -93
- package/dist/icons.js +37 -1
- package/dist/image.d.ts +59 -0
- package/dist/image.js +53 -0
- package/dist/infinite-scroll.js +3 -29
- package/dist/infotip.js +1 -1
- package/dist/input-group.js +1 -1
- package/dist/input-otp.js +1 -1
- package/dist/input.js +1 -1
- package/dist/item.js +1 -1
- package/dist/kpi-card.js +1 -1
- package/dist/label.js +1 -1
- package/dist/line-chart.js +1 -1
- package/dist/list-item.js +1 -1
- package/dist/map-indicator.js +1 -1
- package/dist/match.js +1 -1
- package/dist/media-gallery-hero.js +6 -3
- package/dist/media-player.js +5 -13
- package/dist/message.js +2 -12
- package/dist/mobile-sidebar.js +1 -1
- package/dist/multi-step-form.js +2 -2
- package/dist/number-input.js +1 -1
- package/dist/page-header.js +1 -1
- package/dist/pagination.js +1 -1
- package/dist/password-input.js +1 -1
- package/dist/phone-input.js +11 -17
- package/dist/photo-gallery.js +6 -3
- package/dist/picker-CsnHtbe4.d.ts +14 -0
- package/dist/{picker-xSTzeYhc.js → picker-DmIiQKLJ.js} +2 -7
- package/dist/pie-chart.js +1 -1
- package/dist/popover-DSlPeH7x.d.ts +20 -0
- package/dist/popover.d.ts +1 -19
- package/dist/popover.js +1 -1
- package/dist/price-tag.d.ts +80 -12
- package/dist/price-tag.js +139 -70
- package/dist/progress.js +1 -1
- package/dist/property-listing-card.d.ts +63 -1
- package/dist/property-listing-card.js +97 -28
- package/dist/purchase-option-card.js +1 -1
- package/dist/radar-chart.js +1 -1
- package/dist/radio-group.js +1 -1
- package/dist/review-block.js +1 -1
- package/dist/rich-text-editor.js +1 -1
- package/dist/scatter-chart.js +1 -1
- package/dist/scroll-spy.d.ts +16 -1
- package/dist/scroll-spy.js +28 -5
- package/dist/search-input.js +1 -1
- package/dist/select.js +1 -1
- package/dist/separator.js +1 -1
- package/dist/sheet.js +1 -1
- package/dist/sidebar.js +3 -16
- package/dist/skeleton.js +1 -1
- package/dist/slider.js +1 -1
- package/dist/sonar.d.ts +51 -0
- package/dist/sonar.js +117 -0
- package/dist/sparkline.js +1 -1
- package/dist/stepper.js +1 -1
- package/dist/styles.css +85 -2
- package/dist/switch.js +1 -1
- package/dist/table-card.js +1 -1
- package/dist/table.js +1 -1
- package/dist/tabs.js +1 -1
- package/dist/tag.js +1 -1
- package/dist/testimonial-block.js +1 -1
- package/dist/textarea.js +1 -1
- package/dist/theme-switcher.js +1 -1
- package/dist/time-picker.d.ts +3 -2
- package/dist/time-picker.js +5 -7
- package/dist/toast.js +1 -1
- package/dist/tooltip.js +1 -1
- package/dist/top-navbar.js +1 -1
- package/dist/tree-map.js +1 -1
- package/dist/utils/cn.d.ts +5 -0
- package/dist/utils/cn.js +33 -0
- package/dist/utils/format.d.ts +45 -0
- package/dist/utils/format.js +70 -0
- package/dist/utils/phone.d.ts +98 -0
- package/dist/utils/phone.js +93 -0
- package/dist/utils/use-intersection.d.ts +9 -0
- package/dist/utils/use-intersection.js +29 -0
- package/dist/utils/use-is-mobile.d.ts +5 -0
- package/dist/utils/use-is-mobile.js +16 -0
- package/dist/utils/use-reduced-motion.d.ts +5 -0
- package/dist/{use-reduced-motion-BDvOK14x.js → utils/use-reduced-motion.js} +2 -2
- package/dist/utils/use-uncontrolled.d.ts +11 -0
- package/dist/{use-uncontrolled-CLfM1XbB.js → utils/use-uncontrolled.js} +2 -2
- package/dist/video-player-dialog.d.ts +12 -2
- package/dist/video-player-dialog.js +47 -7
- package/dist/waterfall-chart.js +1 -1
- package/package.json +13 -1
- package/dist/cn-BI_4DMBf.js +0 -23
package/dist/multi-step-form.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Check } from "./icons.js";
|
|
3
|
-
import {
|
|
4
|
-
import { t as useUncontrolled } from "./use-uncontrolled-CLfM1XbB.js";
|
|
3
|
+
import { cn } from "./utils/cn.js";
|
|
5
4
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./select.js";
|
|
5
|
+
import { useUncontrolled } from "./utils/use-uncontrolled.js";
|
|
6
6
|
import { Progress, ProgressIndicator, ProgressTrack } from "./progress.js";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import * as React from "react";
|
package/dist/number-input.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Minus, Plus } from "./icons.js";
|
|
3
|
-
import {
|
|
3
|
+
import { cn } from "./utils/cn.js";
|
|
4
4
|
import { SizeProvider, useComponentSize } from "./size-context.js";
|
|
5
5
|
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "./input-group.js";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
package/dist/page-header.js
CHANGED
package/dist/pagination.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ChevronLeft, ChevronRight, MoreHorizontal } from "./icons.js";
|
|
2
|
-
import {
|
|
2
|
+
import { cn } from "./utils/cn.js";
|
|
3
3
|
import { Button, ButtonLink } from "./button.js";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { cva } from "class-variance-authority";
|
package/dist/password-input.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Eye, EyeOff } from "./icons.js";
|
|
3
|
-
import {
|
|
3
|
+
import { cn } from "./utils/cn.js";
|
|
4
4
|
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "./input-group.js";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import * as React from "react";
|
package/dist/phone-input.js
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Check, ChevronDown, Search } from "./icons.js";
|
|
3
|
-
import {
|
|
3
|
+
import { cn } from "./utils/cn.js";
|
|
4
4
|
import { useComponentSize } from "./size-context.js";
|
|
5
5
|
import { Separator } from "./separator.js";
|
|
6
6
|
import { InputGroup, InputGroupAddon, InputGroupInput } from "./input-group.js";
|
|
7
7
|
import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
|
|
8
|
+
import { getPhoneCountries } from "./utils/phone.js";
|
|
8
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
10
|
import * as React from "react";
|
|
10
|
-
import { AsYouType,
|
|
11
|
+
import { AsYouType, getCountryCallingCode, parsePhoneNumberFromString } from "libphonenumber-js";
|
|
11
12
|
import flags from "react-phone-number-input/flags";
|
|
12
13
|
//#region src/phone-input.tsx
|
|
13
|
-
const
|
|
14
|
-
const COUNTRIES = getCountries().map((code) => ({
|
|
15
|
-
code,
|
|
16
|
-
name: regionNames?.of(code) ?? code,
|
|
17
|
-
calling: getCountryCallingCode(code)
|
|
18
|
-
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
14
|
+
const COUNTRIES = getPhoneCountries();
|
|
19
15
|
function getNationalDigits(value) {
|
|
20
16
|
return value.replace(/\D/g, "");
|
|
21
17
|
}
|
|
@@ -29,13 +25,11 @@ function toE164(digits, country) {
|
|
|
29
25
|
}
|
|
30
26
|
function parseValue(value) {
|
|
31
27
|
if (!value) return { digits: "" };
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
};
|
|
38
|
-
} catch {}
|
|
28
|
+
const parsed = parsePhoneNumberFromString(value);
|
|
29
|
+
if (parsed?.nationalNumber) return {
|
|
30
|
+
country: parsed.country,
|
|
31
|
+
digits: parsed.nationalNumber
|
|
32
|
+
};
|
|
39
33
|
return { digits: "" };
|
|
40
34
|
}
|
|
41
35
|
const flagSizeVariants = {
|
|
@@ -107,7 +101,7 @@ function CountryList({ items, country, onSelect }) {
|
|
|
107
101
|
}),
|
|
108
102
|
/* @__PURE__ */ jsxs("span", {
|
|
109
103
|
className: "shrink-0 text-fg-secondary",
|
|
110
|
-
children: ["+", entry.
|
|
104
|
+
children: ["+", entry.callingCode]
|
|
111
105
|
}),
|
|
112
106
|
selected && /* @__PURE__ */ jsx(Check, { className: "size-4 shrink-0 text-fg-brand" })
|
|
113
107
|
]
|
|
@@ -124,7 +118,7 @@ function CountrySelect({ country, size, disabled, onSelect, finalFocusRef }) {
|
|
|
124
118
|
const q = query.trim().toLowerCase();
|
|
125
119
|
if (!q) return COUNTRIES;
|
|
126
120
|
const normalized = q.replace(/^\+/, "");
|
|
127
|
-
return COUNTRIES.filter((entry) => entry.name.toLowerCase().includes(q) || entry.
|
|
121
|
+
return COUNTRIES.filter((entry) => entry.name.toLowerCase().includes(q) || entry.callingCode.includes(normalized) || entry.code.toLowerCase().includes(q));
|
|
128
122
|
}, [query]);
|
|
129
123
|
function handleOpenChange(next) {
|
|
130
124
|
setOpen(next);
|
package/dist/photo-gallery.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { ChevronLeft, ChevronRight, Fullscreen, X } from "./icons.js";
|
|
3
|
-
import {
|
|
3
|
+
import { cn } from "./utils/cn.js";
|
|
4
4
|
import { Button } from "./button.js";
|
|
5
5
|
import { Carousel, CarouselContent, CarouselItem } from "./carousel.js";
|
|
6
|
+
import { Image } from "./image.js";
|
|
6
7
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
8
|
import * as React from "react";
|
|
8
9
|
import { Dialog } from "@base-ui/react/dialog";
|
|
@@ -60,7 +61,8 @@ function GalleryFrame({ image, fit = "cover", className }) {
|
|
|
60
61
|
return /* @__PURE__ */ jsx("div", {
|
|
61
62
|
"data-slot": "photo-gallery-frame",
|
|
62
63
|
className: cn("relative flex size-full items-center justify-center overflow-hidden", className),
|
|
63
|
-
children: image?.src ? /* @__PURE__ */ jsx(
|
|
64
|
+
children: image?.src ? /* @__PURE__ */ jsx(Image, {
|
|
65
|
+
slot: "photo-gallery-image",
|
|
64
66
|
src: image.src,
|
|
65
67
|
alt: image.alt ?? "Property image",
|
|
66
68
|
className: cn(fit === "contain" ? "max-h-full max-w-full rounded-lg object-contain" : "size-full object-cover"),
|
|
@@ -168,7 +170,8 @@ function GalleryThumbnails({ images, selectedIndex, onSelect, colsClassName, cla
|
|
|
168
170
|
onClick: () => onSelect(index),
|
|
169
171
|
style: { width: "calc((100% - (var(--gallery-cols) - 1) * var(--gallery-gap)) / var(--gallery-cols))" },
|
|
170
172
|
className: cn("relative aspect-4/3 shrink-0 overflow-hidden rounded-lg border-2 bg-surface-raised transition-[border-color,opacity] outline-none focus-visible:border-line-focus focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)]", isActive ? "border-line-focus" : "border-transparent opacity-80 hover:opacity-100"),
|
|
171
|
-
children: image.src ? /* @__PURE__ */ jsx(
|
|
173
|
+
children: image.src ? /* @__PURE__ */ jsx(Image, {
|
|
174
|
+
slot: "photo-gallery-thumbnail-image",
|
|
172
175
|
src: image.src,
|
|
173
176
|
alt: image.alt ?? `Property image ${index + 1}`,
|
|
174
177
|
className: "size-full object-cover",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import "./input-size-context-C-SFx9sx.js";
|
|
2
|
+
import { r as PopoverContent } from "./popover-DSlPeH7x.js";
|
|
3
|
+
import "./icons-C9JXR5Xv.js";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
//#region src/lib/picker.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Where a picker's panel goes. Every one of these is a preference the
|
|
8
|
+
* positioner is free to overrule when the panel would otherwise overflow —
|
|
9
|
+
* which is the point, a calendar being tall enough that the room below a
|
|
10
|
+
* trigger often isn't the room it needs.
|
|
11
|
+
*/
|
|
12
|
+
type PickerPlacementProps = Pick<React.ComponentProps<typeof PopoverContent>, "side" | "sideOffset" | "align" | "alignOffset" | "collisionAvoidance">;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { PickerPlacementProps as t };
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cn } from "./utils/cn.js";
|
|
2
2
|
import { Button } from "./button.js";
|
|
3
3
|
import { useInputComponentSize } from "./input-size-context.js";
|
|
4
4
|
import { PopoverTrigger } from "./popover.js";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
import { cva } from "class-variance-authority";
|
|
7
7
|
//#region src/lib/picker.tsx
|
|
8
|
-
const PICKER_COLLISION_AVOIDANCE = {
|
|
9
|
-
side: "flip",
|
|
10
|
-
align: "shift",
|
|
11
|
-
fallbackAxisSide: "none"
|
|
12
|
-
};
|
|
13
8
|
const pickerTriggerVariants = cva("flex w-full items-center justify-between rounded-full border transition-[border-color,box-shadow] outline-none", {
|
|
14
9
|
variants: { size: {
|
|
15
10
|
sm: "h-8 px-3 text-gdt-xs [&_svg]:size-3.5",
|
|
@@ -47,4 +42,4 @@ function PickerFooter({ secondaryLabel, onSecondary, onApply }) {
|
|
|
47
42
|
});
|
|
48
43
|
}
|
|
49
44
|
//#endregion
|
|
50
|
-
export {
|
|
45
|
+
export { PickerTrigger as n, PickerFooter as t };
|
package/dist/pie-chart.js
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { t as ComponentSize } from "./size-context-BX6kAdVj.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Popover } from "@base-ui/react/popover";
|
|
4
|
+
//#region src/popover.d.ts
|
|
5
|
+
declare function Popover$1({ ...props }: Popover.Root.Props): React.JSX.Element;
|
|
6
|
+
declare function PopoverTrigger({ ...props }: Popover.Trigger.Props): React.JSX.Element;
|
|
7
|
+
type PopoverContentProps = Popover.Popup.Props & Pick<Popover.Positioner.Props, "align" | "alignOffset" | "collisionAvoidance" | "side" | "sideOffset"> & {
|
|
8
|
+
showArrow?: boolean;
|
|
9
|
+
size?: ComponentSize;
|
|
10
|
+
};
|
|
11
|
+
declare function PopoverContent({ className, align, alignOffset, collisionAvoidance, side, sideOffset, showArrow, size, children, ...props }: PopoverContentProps): React.JSX.Element;
|
|
12
|
+
declare function PopoverHeader({ className, border, ...props }: React.ComponentProps<"div"> & {
|
|
13
|
+
border?: boolean;
|
|
14
|
+
}): React.JSX.Element;
|
|
15
|
+
declare function PopoverBody({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
16
|
+
declare function PopoverFooter({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
17
|
+
declare function PopoverTitle({ className, ...props }: Popover.Title.Props): React.JSX.Element;
|
|
18
|
+
declare function PopoverDescription({ className, ...props }: Popover.Description.Props): React.JSX.Element;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { PopoverFooter as a, PopoverTrigger as c, PopoverDescription as i, PopoverBody as n, PopoverHeader as o, PopoverContent as r, PopoverTitle as s, Popover$1 as t };
|
package/dist/popover.d.ts
CHANGED
|
@@ -1,20 +1,2 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import * as React from "react";
|
|
3
|
-
import { Popover as Popover$1 } from "@base-ui/react/popover";
|
|
4
|
-
//#region src/popover.d.ts
|
|
5
|
-
declare function Popover({ ...props }: Popover$1.Root.Props): React.JSX.Element;
|
|
6
|
-
declare function PopoverTrigger({ ...props }: Popover$1.Trigger.Props): React.JSX.Element;
|
|
7
|
-
type PopoverContentProps = Popover$1.Popup.Props & Pick<Popover$1.Positioner.Props, "align" | "alignOffset" | "collisionAvoidance" | "side" | "sideOffset"> & {
|
|
8
|
-
showArrow?: boolean;
|
|
9
|
-
size?: ComponentSize;
|
|
10
|
-
};
|
|
11
|
-
declare function PopoverContent({ className, align, alignOffset, collisionAvoidance, side, sideOffset, showArrow, size, children, ...props }: PopoverContentProps): React.JSX.Element;
|
|
12
|
-
declare function PopoverHeader({ className, border, ...props }: React.ComponentProps<"div"> & {
|
|
13
|
-
border?: boolean;
|
|
14
|
-
}): React.JSX.Element;
|
|
15
|
-
declare function PopoverBody({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
16
|
-
declare function PopoverFooter({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
17
|
-
declare function PopoverTitle({ className, ...props }: Popover$1.Title.Props): React.JSX.Element;
|
|
18
|
-
declare function PopoverDescription({ className, ...props }: Popover$1.Description.Props): React.JSX.Element;
|
|
19
|
-
//#endregion
|
|
1
|
+
import { a as PopoverFooter, c as PopoverTrigger, i as PopoverDescription, n as PopoverBody, o as PopoverHeader, r as PopoverContent, s as PopoverTitle, t as Popover } from "./popover-DSlPeH7x.js";
|
|
20
2
|
export { Popover, PopoverBody, PopoverContent, PopoverDescription, PopoverFooter, PopoverHeader, PopoverTitle, PopoverTrigger };
|
package/dist/popover.js
CHANGED
package/dist/price-tag.d.ts
CHANGED
|
@@ -3,32 +3,100 @@ import * as React from "react";
|
|
|
3
3
|
//#region src/price-tag.d.ts
|
|
4
4
|
declare const priceTagVariants: (props?: ({
|
|
5
5
|
size?: "lg" | "md" | "sm" | "xs" | "xxs" | null | undefined;
|
|
6
|
+
hasDescription?: boolean | null | undefined;
|
|
6
7
|
hasMonthlyPayment?: boolean | null | undefined;
|
|
7
8
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
8
9
|
type PriceTagSize = NonNullable<VariantProps<typeof priceTagVariants>["size"]>;
|
|
10
|
+
/**
|
|
11
|
+
* A currency in the dropdown.
|
|
12
|
+
*
|
|
13
|
+
* `currency`, `value` and `description` are all PriceTag needs, and none of
|
|
14
|
+
* them are interpreted — `description` in particular is printed as given, so
|
|
15
|
+
* the wording is yours. The rest are legacy and go in the next major.
|
|
16
|
+
*/
|
|
9
17
|
type PriceTagCurrencyOption = {
|
|
10
|
-
|
|
11
|
-
|
|
18
|
+
/** Shown at the leading edge, and matched against `selectedCurrency`. */
|
|
19
|
+
currency?: string;
|
|
20
|
+
/** The price, exactly as it should read. */
|
|
21
|
+
value?: React.ReactNode;
|
|
22
|
+
/** A second line under the price. Your words, printed as given. */
|
|
23
|
+
description?: React.ReactNode;
|
|
24
|
+
/** @deprecated Use `currency`. Removed in the next major. */
|
|
25
|
+
code?: string;
|
|
26
|
+
/** @deprecated Use `value`. Removed in the next major. */
|
|
27
|
+
amount?: string;
|
|
28
|
+
/** @deprecated Format before you pass it. Removed in the next major. */
|
|
12
29
|
shortAmount?: string;
|
|
30
|
+
/** @deprecated Use `description`. Removed in the next major. */
|
|
13
31
|
monthlyPayment?: string;
|
|
32
|
+
/** @deprecated Use `description`. Removed in the next major. */
|
|
14
33
|
monthlyPaymentLabel?: string;
|
|
15
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* A currency option after the legacy fields have been folded in — what
|
|
37
|
+
* `onCurrencyChange` and `renderMenuOption` receive. The original object is
|
|
38
|
+
* spread in, so code still reading `code` or `amount` off it keeps working.
|
|
39
|
+
*
|
|
40
|
+
* Generic over your own option type, which `PriceTag` infers from `currencies`.
|
|
41
|
+
* Anything extra you hang on an option — a rate, an id, a flag — arrives here
|
|
42
|
+
* typed, so `renderMenuOption` can use it without a cast.
|
|
43
|
+
*/
|
|
44
|
+
type PriceTagMenuOption<TOption extends PriceTagCurrencyOption = PriceTagCurrencyOption> = TOption & {
|
|
45
|
+
currency: string;
|
|
46
|
+
value: React.ReactNode;
|
|
47
|
+
description?: React.ReactNode;
|
|
48
|
+
/** Whether this is the row `selectedCurrency` points at. */
|
|
49
|
+
selected: boolean;
|
|
50
|
+
};
|
|
51
|
+
/** @deprecated Format before you pass it. Removed in the next major. */
|
|
16
52
|
type PriceTagFormat = "full" | "shortened";
|
|
17
|
-
type PriceTagProps = Omit<React.ComponentProps<"button">, "children"> & {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
53
|
+
type PriceTagProps<TOption extends PriceTagCurrencyOption = PriceTagCurrencyOption> = Omit<React.ComponentProps<"button">, "children" | "value"> & {
|
|
54
|
+
/** The price, exactly as it should read. */
|
|
55
|
+
value?: React.ReactNode;
|
|
56
|
+
/** A second line under the price. Your words, printed as given. */
|
|
57
|
+
description?: React.ReactNode;
|
|
21
58
|
size?: PriceTagSize;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Providing this turns the tag into a dropdown trigger. Options carry
|
|
61
|
+
* whatever else you need — `TOption` is inferred from here, and the
|
|
62
|
+
* callbacks below receive it intact.
|
|
63
|
+
*/
|
|
64
|
+
currencies?: TOption[];
|
|
25
65
|
selectedCurrency?: string;
|
|
26
|
-
onCurrencyChange?: (
|
|
66
|
+
onCurrencyChange?: (option: PriceTagMenuOption<NoInfer<TOption>>) => void;
|
|
67
|
+
/**
|
|
68
|
+
* Replace a row's contents. PriceTag keeps the button, its selected state
|
|
69
|
+
* and its keyboard behaviour, so a custom row can't quietly lose them.
|
|
70
|
+
*/
|
|
71
|
+
renderMenuOption?: (option: PriceTagMenuOption<NoInfer<TOption>>) => React.ReactNode;
|
|
27
72
|
open?: boolean;
|
|
28
73
|
defaultOpen?: boolean;
|
|
29
74
|
onOpenChange?: (open: boolean) => void;
|
|
30
75
|
popoverClassName?: string;
|
|
76
|
+
/** @deprecated Use `value`. Removed in the next major. */
|
|
77
|
+
amount?: string;
|
|
78
|
+
/** @deprecated Format before you pass it. Removed in the next major. */
|
|
79
|
+
shortAmount?: string;
|
|
80
|
+
/** @deprecated Format before you pass it. Removed in the next major. */
|
|
81
|
+
format?: PriceTagFormat;
|
|
82
|
+
/** @deprecated Use `description`. Removed in the next major. */
|
|
83
|
+
monthlyPayment?: string;
|
|
84
|
+
/** @deprecated Use `description`. Removed in the next major. */
|
|
85
|
+
monthlyPaymentLabel?: string;
|
|
31
86
|
};
|
|
32
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Rounded-box price display, optionally a trigger for a currency dropdown.
|
|
89
|
+
*
|
|
90
|
+
* Display only: it prints `value` and `description` as given and never
|
|
91
|
+
* composes a sentence, picks a format, or decides that a line is too small to
|
|
92
|
+
* be worth showing. Wording, currency conversion and number formatting all
|
|
93
|
+
* belong to the app, which is the only place that knows the locale, the
|
|
94
|
+
* product's voice, and what the second line is actually for.
|
|
95
|
+
*
|
|
96
|
+
* The legacy `amount` / `shortAmount` / `format` / `monthlyPayment` props still
|
|
97
|
+
* work and keep their old behaviour exactly, including the size threshold that
|
|
98
|
+
* hid the monthly line below `md`. They go in the next major.
|
|
99
|
+
*/
|
|
100
|
+
declare function PriceTag<TOption extends PriceTagCurrencyOption = PriceTagCurrencyOption>({ value, description, size, currencies, selectedCurrency, onCurrencyChange, renderMenuOption, open, defaultOpen, onOpenChange, className, popoverClassName, type, amount, shortAmount, format, monthlyPayment, monthlyPaymentLabel, ...props }: PriceTagProps<TOption>): React.JSX.Element;
|
|
33
101
|
//#endregion
|
|
34
|
-
export { PriceTag, type PriceTagCurrencyOption, type PriceTagFormat, type PriceTagProps, type PriceTagSize, priceTagVariants };
|
|
102
|
+
export { PriceTag, type PriceTagCurrencyOption, type PriceTagFormat, type PriceTagMenuOption, type PriceTagProps, type PriceTagSize, priceTagVariants };
|
package/dist/price-tag.js
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Check, ChevronDown } from "./icons.js";
|
|
3
|
-
import {
|
|
4
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "./utils/cn.js";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { cva } from "class-variance-authority";
|
|
6
6
|
import { Popover } from "@base-ui/react/popover";
|
|
7
7
|
//#region src/price-tag.tsx
|
|
8
|
-
const priceTagVariants = cva("group/price-tag inline-flex w-fit shrink-0 items-center justify-center
|
|
8
|
+
const priceTagVariants = cva("group/price-tag inline-flex w-fit shrink-0 items-center justify-center bg-surface-brand font-bold whitespace-nowrap text-fg-on-brand shadow-none transition-[background-color,box-shadow] outline-none data-[interactive=true]:cursor-pointer data-[interactive=true]:hover:bg-action-primary-hover data-[interactive=true]:focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] data-[interactive=true]:active:bg-action-primary-pressed", {
|
|
9
9
|
variants: {
|
|
10
10
|
size: {
|
|
11
|
-
xxs: "min-h-7 gap-1 px-2.5 py-0.75 text-gdt-subtext [
|
|
12
|
-
xs: "min-h-7.5 gap-1 px-3 py-1 text-gdt-xs [
|
|
13
|
-
sm: "min-h-9 gap-1.5 px-4 py-1.5 text-gdt-sm [
|
|
14
|
-
md: "min-h-10.5 gap-1.5 px-5 py-2 text-gdt-md [
|
|
15
|
-
lg: "min-h-13 gap-2 px-7 py-3 text-gdt-lg [
|
|
11
|
+
xxs: "min-h-7 gap-1 rounded-lg px-2.5 py-0.75 text-gdt-subtext leading-none [&_svg]:size-3",
|
|
12
|
+
xs: "min-h-7.5 gap-1 rounded-lg px-3 py-1 text-gdt-xs leading-none [&_svg]:size-3.5",
|
|
13
|
+
sm: "min-h-9 gap-1.5 rounded-xl px-4 py-1.5 text-gdt-sm leading-none [&_svg]:size-3.5",
|
|
14
|
+
md: "min-h-10.5 gap-1.5 rounded-xl px-5 py-2 text-gdt-md leading-none [&_svg]:size-4",
|
|
15
|
+
lg: "min-h-13 gap-2 rounded-2xl px-7 py-3 text-gdt-lg leading-none [&_svg]:size-4.5"
|
|
16
16
|
},
|
|
17
|
+
/** Two lines sit top-aligned against the chevron rather than centred. */
|
|
18
|
+
hasDescription: {
|
|
19
|
+
true: "items-start",
|
|
20
|
+
false: ""
|
|
21
|
+
},
|
|
22
|
+
/** @deprecated Use `hasDescription`. Removed in the next major. */
|
|
17
23
|
hasMonthlyPayment: {
|
|
18
24
|
true: "items-start",
|
|
19
25
|
false: ""
|
|
@@ -21,95 +27,158 @@ const priceTagVariants = cva("group/price-tag inline-flex w-fit shrink-0 items-c
|
|
|
21
27
|
},
|
|
22
28
|
defaultVariants: {
|
|
23
29
|
size: "md",
|
|
24
|
-
|
|
30
|
+
hasDescription: false
|
|
25
31
|
}
|
|
26
32
|
});
|
|
33
|
+
/** The space between the price and its description, 4px through 12px. */
|
|
34
|
+
const lineGapClassName = {
|
|
35
|
+
xxs: "gap-1",
|
|
36
|
+
xs: "gap-1",
|
|
37
|
+
sm: "gap-1.5",
|
|
38
|
+
md: "gap-2",
|
|
39
|
+
lg: "gap-3"
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The least space the chevron will sit at from the price. It is usually pushed
|
|
43
|
+
* further out than this, to the trailing edge of the wider description.
|
|
44
|
+
*/
|
|
45
|
+
const chevronGapClassName = {
|
|
46
|
+
xxs: "gap-2",
|
|
47
|
+
xs: "gap-2",
|
|
48
|
+
sm: "gap-3",
|
|
49
|
+
md: "gap-3",
|
|
50
|
+
lg: "gap-4"
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* The description is quieter than the price, and quietest at the largest size.
|
|
54
|
+
* `leading-none` trails the text size here for the same reason it does above.
|
|
55
|
+
*/
|
|
56
|
+
const descriptionSizeClassName = {
|
|
57
|
+
xxs: "text-gdt-subtext leading-none",
|
|
58
|
+
xs: "text-gdt-subtext leading-none",
|
|
59
|
+
sm: "text-gdt-subtext leading-none",
|
|
60
|
+
md: "text-gdt-subtext leading-none",
|
|
61
|
+
lg: "text-gdt-xs leading-none"
|
|
62
|
+
};
|
|
27
63
|
function getDisplayAmount({ amount, shortAmount, format }) {
|
|
28
64
|
return format === "shortened" && shortAmount ? shortAmount : amount;
|
|
29
65
|
}
|
|
30
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Folds the legacy fields into the current three. New fields win outright, so
|
|
68
|
+
* an option can be migrated one at a time.
|
|
69
|
+
*/
|
|
70
|
+
function resolveMenuOption(option, format, selectedCurrency) {
|
|
71
|
+
const currency = option.currency ?? option.code ?? "";
|
|
72
|
+
const value = option.value ?? getDisplayAmount({
|
|
73
|
+
amount: option.amount,
|
|
74
|
+
shortAmount: option.shortAmount,
|
|
75
|
+
format
|
|
76
|
+
});
|
|
77
|
+
const description = option.description ?? (option.monthlyPayment ? `${option.monthlyPaymentLabel ?? "As low as"} ${option.monthlyPayment} per month` : void 0);
|
|
78
|
+
return {
|
|
79
|
+
...option,
|
|
80
|
+
currency,
|
|
81
|
+
value,
|
|
82
|
+
description,
|
|
83
|
+
selected: currency === selectedCurrency
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function DefaultMenuOption({ option }) {
|
|
87
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
88
|
+
/* @__PURE__ */ jsx("span", {
|
|
89
|
+
className: "min-w-10 text-gdt-sm font-semibold text-fg-brand",
|
|
90
|
+
children: option.currency
|
|
91
|
+
}),
|
|
92
|
+
/* @__PURE__ */ jsxs("span", {
|
|
93
|
+
className: "ml-auto flex min-w-0 flex-col items-end",
|
|
94
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
95
|
+
className: "text-gdt-sm font-bold text-fg-primary",
|
|
96
|
+
children: option.value
|
|
97
|
+
}), option.description ? /* @__PURE__ */ jsx("span", {
|
|
98
|
+
className: "text-gdt-xs text-fg-secondary",
|
|
99
|
+
children: option.description
|
|
100
|
+
}) : null]
|
|
101
|
+
}),
|
|
102
|
+
option.selected ? /* @__PURE__ */ jsx(Check, {
|
|
103
|
+
"aria-hidden": "true",
|
|
104
|
+
className: "size-4 shrink-0 text-fg-brand"
|
|
105
|
+
}) : null
|
|
106
|
+
] });
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Rounded-box price display, optionally a trigger for a currency dropdown.
|
|
110
|
+
*
|
|
111
|
+
* Display only: it prints `value` and `description` as given and never
|
|
112
|
+
* composes a sentence, picks a format, or decides that a line is too small to
|
|
113
|
+
* be worth showing. Wording, currency conversion and number formatting all
|
|
114
|
+
* belong to the app, which is the only place that knows the locale, the
|
|
115
|
+
* product's voice, and what the second line is actually for.
|
|
116
|
+
*
|
|
117
|
+
* The legacy `amount` / `shortAmount` / `format` / `monthlyPayment` props still
|
|
118
|
+
* work and keep their old behaviour exactly, including the size threshold that
|
|
119
|
+
* hid the monthly line below `md`. They go in the next major.
|
|
120
|
+
*/
|
|
121
|
+
function PriceTag({ value, description, size = "md", currencies, selectedCurrency, onCurrencyChange, renderMenuOption, open, defaultOpen, onOpenChange, className, popoverClassName, type = "button", amount, shortAmount, format = "full", monthlyPayment, monthlyPaymentLabel = "Low as", ...props }) {
|
|
31
122
|
const hasDropdown = Boolean(currencies?.length);
|
|
32
|
-
const
|
|
123
|
+
const resolvedValue = value ?? getDisplayAmount({
|
|
124
|
+
amount,
|
|
125
|
+
shortAmount,
|
|
126
|
+
format
|
|
127
|
+
});
|
|
128
|
+
const legacyDescription = monthlyPayment && (size === "md" || size === "lg") ? `${monthlyPaymentLabel} ${monthlyPayment} monthly` : void 0;
|
|
129
|
+
const resolvedDescription = description ?? legacyDescription;
|
|
33
130
|
const pill = /* @__PURE__ */ jsxs("span", {
|
|
34
|
-
className: "flex min-w-0 flex-col
|
|
35
|
-
children: [/* @__PURE__ */
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
})
|
|
44
|
-
|
|
131
|
+
className: cn("flex min-w-0 flex-col text-start", lineGapClassName[size]),
|
|
132
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
133
|
+
className: cn("flex items-center justify-between", chevronGapClassName[size]),
|
|
134
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
135
|
+
className: "min-w-0",
|
|
136
|
+
children: resolvedValue
|
|
137
|
+
}), hasDropdown ? /* @__PURE__ */ jsx(ChevronDown, {
|
|
138
|
+
"aria-hidden": "true",
|
|
139
|
+
className: "shrink-0 transition-transform group-data-popup-open/price-tag:rotate-180"
|
|
140
|
+
}) : null]
|
|
141
|
+
}), resolvedDescription ? /* @__PURE__ */ jsx("span", {
|
|
142
|
+
className: cn("font-medium opacity-90", descriptionSizeClassName[size]),
|
|
143
|
+
children: resolvedDescription
|
|
45
144
|
}) : null]
|
|
46
145
|
});
|
|
146
|
+
const pillClassName = cn(priceTagVariants({
|
|
147
|
+
size,
|
|
148
|
+
hasDescription: Boolean(resolvedDescription)
|
|
149
|
+
}), className);
|
|
47
150
|
if (!hasDropdown) return /* @__PURE__ */ jsx("span", {
|
|
48
151
|
"data-slot": "price-tag",
|
|
49
|
-
className:
|
|
50
|
-
|
|
51
|
-
hasMonthlyPayment: Boolean(displayMonthlyPayment)
|
|
52
|
-
}), className),
|
|
152
|
+
className: pillClassName,
|
|
153
|
+
...props,
|
|
53
154
|
children: pill
|
|
54
155
|
});
|
|
156
|
+
const options = (currencies ?? []).map((currency) => resolveMenuOption(currency, format, selectedCurrency));
|
|
55
157
|
return /* @__PURE__ */ jsxs(Popover.Root, {
|
|
56
158
|
open,
|
|
57
159
|
defaultOpen,
|
|
58
160
|
onOpenChange,
|
|
59
|
-
children: [/* @__PURE__ */
|
|
161
|
+
children: [/* @__PURE__ */ jsx(Popover.Trigger, {
|
|
60
162
|
"data-slot": "price-tag",
|
|
61
163
|
"data-interactive": "true",
|
|
62
164
|
type,
|
|
63
|
-
className:
|
|
64
|
-
size,
|
|
65
|
-
hasMonthlyPayment: Boolean(displayMonthlyPayment)
|
|
66
|
-
}), className),
|
|
165
|
+
className: pillClassName,
|
|
67
166
|
...props,
|
|
68
|
-
children:
|
|
69
|
-
"aria-hidden": "true",
|
|
70
|
-
className: "transition-transform group-data-popup-open/price-tag:rotate-180"
|
|
71
|
-
})]
|
|
167
|
+
children: pill
|
|
72
168
|
}), /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, {
|
|
73
169
|
sideOffset: 10,
|
|
74
170
|
align: "start",
|
|
75
171
|
children: /* @__PURE__ */ jsx(Popover.Popup, {
|
|
76
172
|
"data-slot": "price-tag-popover",
|
|
77
173
|
className: cn("z-50 flex w-[17.25rem] max-w-[calc(100vw-2rem)] origin-(--transform-origin) flex-col rounded-xl border border-line-subtle bg-surface-overlay p-2 text-fg-primary shadow-3 outline-hidden transition-[opacity,scale,translate] duration-[var(--duration-motion-popup)] ease-gdt-out data-starting-style:opacity-0 data-starting-style:scale-95 data-ending-style:opacity-0 data-ending-style:scale-95 data-[side=bottom]:data-starting-style:translate-y-2 data-[side=bottom]:data-ending-style:translate-y-2 data-[side=top]:data-starting-style:-translate-y-2 data-[side=top]:data-ending-style:-translate-y-2 motion-reduce:data-starting-style:scale-100 motion-reduce:data-ending-style:scale-100 motion-reduce:data-[side=bottom]:data-starting-style:translate-y-0 motion-reduce:data-[side=bottom]:data-ending-style:translate-y-0 motion-reduce:data-[side=top]:data-starting-style:translate-y-0 motion-reduce:data-[side=top]:data-ending-style:translate-y-0", popoverClassName),
|
|
78
|
-
children:
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
return /* @__PURE__ */ jsxs("button", {
|
|
87
|
-
type: "button",
|
|
88
|
-
"data-active": active ? "true" : void 0,
|
|
89
|
-
className: "flex min-h-14 w-full items-center gap-3 rounded-lg px-3 text-start outline-none transition-colors hover:bg-surface-brand-subtle focus-visible:bg-surface-brand-subtle focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] data-[active=true]:bg-surface-brand-subtle",
|
|
90
|
-
onClick: () => onCurrencyChange?.(currency),
|
|
91
|
-
children: [
|
|
92
|
-
/* @__PURE__ */ jsx("span", {
|
|
93
|
-
className: "min-w-10 text-gdt-sm font-semibold text-fg-brand",
|
|
94
|
-
children: currency.code
|
|
95
|
-
}),
|
|
96
|
-
/* @__PURE__ */ jsxs("span", {
|
|
97
|
-
className: "ml-auto flex min-w-0 flex-col items-end",
|
|
98
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
99
|
-
className: "text-gdt-sm font-bold text-fg-primary",
|
|
100
|
-
children: optionAmount
|
|
101
|
-
}), optionMonthlyPayment ? /* @__PURE__ */ jsx("span", {
|
|
102
|
-
className: "text-gdt-xs text-fg-secondary",
|
|
103
|
-
children: optionMonthlyPayment
|
|
104
|
-
}) : null]
|
|
105
|
-
}),
|
|
106
|
-
active ? /* @__PURE__ */ jsx(Check, {
|
|
107
|
-
"aria-hidden": "true",
|
|
108
|
-
className: "size-4 shrink-0 text-fg-brand"
|
|
109
|
-
}) : null
|
|
110
|
-
]
|
|
111
|
-
}, currency.code);
|
|
112
|
-
})
|
|
174
|
+
children: options.map((option) => /* @__PURE__ */ jsx("button", {
|
|
175
|
+
type: "button",
|
|
176
|
+
"data-slot": "price-tag-option",
|
|
177
|
+
"data-active": option.selected ? "true" : void 0,
|
|
178
|
+
className: "flex min-h-14 w-full items-center gap-3 rounded-lg px-3 text-start outline-none transition-colors hover:bg-surface-brand-subtle focus-visible:bg-surface-brand-subtle focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] data-[active=true]:bg-surface-brand-subtle",
|
|
179
|
+
onClick: () => onCurrencyChange?.(option),
|
|
180
|
+
children: renderMenuOption ? renderMenuOption(option) : /* @__PURE__ */ jsx(DefaultMenuOption, { option })
|
|
181
|
+
}, option.currency))
|
|
113
182
|
})
|
|
114
183
|
}) })]
|
|
115
184
|
});
|
package/dist/progress.js
CHANGED