@giddaa-housing/ui 3.5.0 → 3.7.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.
Files changed (108) hide show
  1. package/css/components.css +13 -0
  2. package/css/generated/shared.css +1 -1
  3. package/css/theme.css +11 -8
  4. package/dist/badge.d.ts +5 -1
  5. package/dist/badge.js +19 -5
  6. package/dist/bar-chart.d.ts +1 -1
  7. package/dist/bullet-chart.d.ts +1 -1
  8. package/dist/button-BS5KCibF.d.ts +33 -0
  9. package/dist/button-group.d.ts +1 -1
  10. package/dist/button.d.ts +1 -1
  11. package/dist/button.js +49 -21
  12. package/dist/calendar.js +1 -1
  13. package/dist/carousel.d.ts +4 -2
  14. package/dist/carousel.js +11 -14
  15. package/dist/chart.d.ts +1 -1
  16. package/dist/chat.d.ts +1 -1
  17. package/dist/checkbox.d.ts +2 -2
  18. package/dist/checkbox.js +20 -6
  19. package/dist/{combobox-B7cKFJ9V.js → combobox-D70DFHoM.js} +55 -10
  20. package/dist/combobox.d.ts +8 -3
  21. package/dist/combobox.js +2 -2
  22. package/dist/cta.d.ts +1 -1
  23. package/dist/data-table.d.ts +2 -2
  24. package/dist/date-picker.d.ts +3 -3
  25. package/dist/date-picker.js +1 -1
  26. package/dist/dialog.d.ts +6 -2
  27. package/dist/dialog.js +15 -12
  28. package/dist/dropdown-menu.d.ts +1 -1
  29. package/dist/field.d.ts +4 -1
  30. package/dist/field.js +28 -11
  31. package/dist/footer.d.ts +2 -2
  32. package/dist/funnel-chart.d.ts +1 -1
  33. package/dist/heatmap-chart.d.ts +1 -1
  34. package/dist/infotip.js +0 -1
  35. package/dist/input-group.d.ts +6 -6
  36. package/dist/input-group.js +43 -18
  37. package/dist/input-otp.d.ts +2 -2
  38. package/dist/input-otp.js +31 -14
  39. package/dist/input-size-context-BMhves-J.d.ts +13 -0
  40. package/dist/input-size-context.d.ts +2 -2
  41. package/dist/input-size-context.js +9 -2
  42. package/dist/input.d.ts +20 -2
  43. package/dist/input.js +30 -11
  44. package/dist/line-chart.d.ts +1 -1
  45. package/dist/mask-input.d.ts +1 -1
  46. package/dist/match.d.ts +14 -2
  47. package/dist/match.js +221 -48
  48. package/dist/media-gallery-hero.js +9 -7
  49. package/dist/media-player.js +3 -3
  50. package/dist/mobile-sidebar.js +7 -6
  51. package/dist/number-input.d.ts +2 -2
  52. package/dist/number-input.js +2 -2
  53. package/dist/pagination.d.ts +1 -1
  54. package/dist/phone-input.d.ts +20 -3
  55. package/dist/phone-input.js +137 -67
  56. package/dist/picker-BTXBrsl4.js +62 -0
  57. package/dist/{picker-CsnHtbe4.d.ts → picker-j3txxA5t.d.ts} +2 -2
  58. package/dist/pie-chart.d.ts +1 -1
  59. package/dist/{popover-DSlPeH7x.d.ts → popover-CNymD33m.d.ts} +1 -1
  60. package/dist/popover.d.ts +1 -1
  61. package/dist/property-listing-card.d.ts +7 -3
  62. package/dist/property-listing-card.js +25 -8
  63. package/dist/radar-chart.d.ts +1 -1
  64. package/dist/radio-group.d.ts +2 -2
  65. package/dist/radio-group.js +23 -9
  66. package/dist/rating.d.ts +60 -0
  67. package/dist/rating.js +187 -0
  68. package/dist/rich-text-editor.d.ts +1 -1
  69. package/dist/scatter-chart.d.ts +1 -1
  70. package/dist/scroll-spy.d.ts +8 -2
  71. package/dist/scroll-spy.js +13 -13
  72. package/dist/section-jumper.d.ts +31 -0
  73. package/dist/section-jumper.js +276 -0
  74. package/dist/select.d.ts +9 -4
  75. package/dist/select.js +148 -20
  76. package/dist/sheet.d.ts +5 -1
  77. package/dist/sheet.js +15 -12
  78. package/dist/sidebar.d.ts +2 -2
  79. package/dist/sidebar.js +1 -0
  80. package/dist/size-context-BVhHduLi.d.ts +33 -0
  81. package/dist/size-context.d.ts +2 -2
  82. package/dist/size-context.js +30 -1
  83. package/dist/slider.d.ts +5 -3
  84. package/dist/slider.js +25 -10
  85. package/dist/sonar.d.ts +4 -2
  86. package/dist/sonar.js +116 -28
  87. package/dist/sparkline.d.ts +1 -1
  88. package/dist/styles.css +1674 -252
  89. package/dist/switch.d.ts +2 -2
  90. package/dist/switch.js +20 -6
  91. package/dist/tabs.d.ts +1 -1
  92. package/dist/tag.d.ts +1 -1
  93. package/dist/textarea.d.ts +17 -1
  94. package/dist/textarea.js +23 -9
  95. package/dist/time-picker.d.ts +3 -3
  96. package/dist/time-picker.js +1 -1
  97. package/dist/tree-map.d.ts +1 -1
  98. package/dist/video-player-dialog.js +4 -3
  99. package/dist/waterfall-chart.d.ts +1 -1
  100. package/package.json +9 -1
  101. package/dist/button-DW5OijoR.d.ts +0 -17
  102. package/dist/dialog-nesting.d.ts +0 -9
  103. package/dist/dialog-nesting.js +0 -27
  104. package/dist/input-CfoEJ8A6.d.ts +0 -12
  105. package/dist/input-size-context-C-SFx9sx.d.ts +0 -10
  106. package/dist/picker-DmIiQKLJ.js +0 -45
  107. package/dist/size-context-BX6kAdVj.d.ts +0 -11
  108. package/dist/textarea-IS_D8pXf.d.ts +0 -11
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { Check, ChevronDown, Search } from "./icons.js";
3
3
  import { cn } from "./utils/cn.js";
4
- import { useComponentSize } from "./size-context.js";
4
+ import { resolveResponsiveComponentSize, useComponentSizeValue } 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";
@@ -10,28 +10,87 @@ import { jsx, jsxs } from "react/jsx-runtime";
10
10
  import * as React from "react";
11
11
  import { AsYouType, getCountryCallingCode, parsePhoneNumberFromString } from "libphonenumber-js";
12
12
  import flags from "react-phone-number-input/flags";
13
- //#region src/phone-input.tsx
14
- const COUNTRIES = getPhoneCountries();
15
- function getNationalDigits(value) {
16
- return value.replace(/\D/g, "");
13
+ //#region src/lib/phone-input-value.ts
14
+ const EMPTY = {
15
+ text: "",
16
+ national: "",
17
+ international: false,
18
+ value: void 0
19
+ };
20
+ /** Drops everything a phone number cannot contain, keeping a leading `+`. */
21
+ function sanitizePhoneText(input) {
22
+ const digits = input.replace(/\D/g, "");
23
+ return input.trimStart().startsWith("+") ? `+${digits}` : digits;
17
24
  }
18
- function formatNational(digits, country) {
19
- if (!digits) return "";
20
- return new AsYouType(country).input(digits);
25
+ /**
26
+ * Groups national digits that `AsYouType` handed back untouched.
27
+ *
28
+ * Most countries only publish a national format that assumes the trunk prefix,
29
+ * so `AsYouType("NG")` formats `08161827754` as `0816 182 7754` but hands
30
+ * `8161827754` straight back in one run — and it formats neither until enough
31
+ * digits have arrived. The same digits always group under the international
32
+ * pattern, so that grouping is borrowed and the calling code taken back off.
33
+ *
34
+ * Whatever the reader typed in front of the national digits is theirs, and goes
35
+ * back where they left it. This only ever inserts separators: typing `081`
36
+ * shows `081`, never `81`.
37
+ */
38
+ function groupNationalDigits(sanitized, national, country) {
39
+ if (!national || !sanitized.endsWith(national)) return "";
40
+ const callingCode = `+${getCountryCallingCode(country)}`;
41
+ const international = new AsYouType().input(`${callingCode}${national}`);
42
+ if (!international.startsWith(callingCode)) return "";
43
+ return sanitized.slice(0, sanitized.length - national.length) + international.slice(callingCode.length).trimStart();
21
44
  }
22
- function toE164(digits, country) {
23
- if (!digits) return void 0;
24
- return `+${getCountryCallingCode(country)}${digits}`;
45
+ /**
46
+ * Reads what is in the field after a keystroke.
47
+ *
48
+ * `country` is the currently selected country; it is only overridden when the
49
+ * text is international *and* the digits so far name exactly one country —
50
+ * `+1` is still both the US and Canada, so the selector holds still until it
51
+ * is not.
52
+ */
53
+ function derivePhoneValue(input, country) {
54
+ const sanitized = sanitizePhoneText(input);
55
+ const formatter = new AsYouType(country);
56
+ const formatted = formatter.input(sanitized);
57
+ const international = sanitized.startsWith("+");
58
+ const national = formatter.getNationalNumber();
59
+ return {
60
+ text: !international && formatted === sanitized && groupNationalDigits(sanitized, national, country) || formatted,
61
+ country: (international ? formatter.getCountry() : void 0) ?? country,
62
+ national,
63
+ international,
64
+ value: national ? formatter.getNumberValue() : void 0
65
+ };
25
66
  }
26
- function parseValue(value) {
27
- if (!value) return { digits: "" };
67
+ /** Reads an externally supplied value — a form's default, a fetched record. */
68
+ function readPhoneValue(value, fallback) {
69
+ if (!value) return {
70
+ ...EMPTY,
71
+ country: fallback
72
+ };
28
73
  const parsed = parsePhoneNumberFromString(value);
29
- if (parsed?.nationalNumber) return {
30
- country: parsed.country,
31
- digits: parsed.nationalNumber
74
+ if (!parsed?.nationalNumber) return derivePhoneValue(value, fallback);
75
+ if (!parsed.country) return derivePhoneValue(parsed.number, fallback);
76
+ return {
77
+ ...derivePhoneValue(parsed.formatNational(), parsed.country),
78
+ country: parsed.country
79
+ };
80
+ }
81
+ /**
82
+ * Rewrites the field for a country picked from the selector. The digits the
83
+ * reader typed are kept; only the code in front of them changes.
84
+ */
85
+ function selectPhoneCountry(current, next) {
86
+ return {
87
+ ...derivePhoneValue(current.international ? `+${getCountryCallingCode(next)}${current.national}` : current.national, next),
88
+ country: next
32
89
  };
33
- return { digits: "" };
34
90
  }
91
+ //#endregion
92
+ //#region src/phone-input.tsx
93
+ const COUNTRIES = getPhoneCountries();
35
94
  const flagSizeVariants = {
36
95
  sm: "h-3 w-[18px]",
37
96
  md: "h-3.5 w-5",
@@ -110,7 +169,7 @@ function CountryList({ items, country, onSelect }) {
110
169
  })
111
170
  });
112
171
  }
113
- function CountrySelect({ country, size, disabled, onSelect, finalFocusRef }) {
172
+ function CountrySelect({ country, size, disabled, showCallingCode, onSelect, finalFocusRef }) {
114
173
  const [open, setOpen] = React.useState(false);
115
174
  const [query, setQuery] = React.useState("");
116
175
  const searchRef = React.useRef(null);
@@ -140,7 +199,7 @@ function CountrySelect({ country, size, disabled, onSelect, finalFocusRef }) {
140
199
  country,
141
200
  size
142
201
  }),
143
- /* @__PURE__ */ jsxs("span", { children: ["+", getCountryCallingCode(country)] }),
202
+ showCallingCode ? /* @__PURE__ */ jsxs("span", { children: ["+", getCountryCallingCode(country)] }) : null,
144
203
  /* @__PURE__ */ jsx(ChevronDown, { className: cn("text-fg-secondary transition-transform", open && "rotate-180", size === "lg" ? "size-4" : "size-3.5") })
145
204
  ]
146
205
  }), /* @__PURE__ */ jsxs(PopoverContent, {
@@ -167,71 +226,82 @@ function CountrySelect({ country, size, disabled, onSelect, finalFocusRef }) {
167
226
  })]
168
227
  });
169
228
  }
170
- function PhoneInput({ value, onChange, defaultCountry = "NG", size, disabled = false, readOnly = false, placeholder = "(0000) 000-0000", className, id, name, ref, "aria-invalid": ariaInvalid }) {
171
- const resolvedSize = useComponentSize(size);
229
+ /**
230
+ * A phone field that takes a number written either way round.
231
+ *
232
+ * `0801 234 5678` and `+234 801 234 5678` are the same number, and both are
233
+ * accepted here: typing or pasting a leading `+` switches the field to
234
+ * international entry and moves the country selector to match, while a plain
235
+ * national number is read against the selected country, trunk prefix and all.
236
+ * `onChange` receives E.164 in both cases.
237
+ */
238
+ function PhoneInput({ value, onChange, defaultCountry = "NG", size, disabled = false, readOnly = false, placeholder = "(0000) 000-0000", rightAddon, className, id, name, ref, "aria-invalid": ariaInvalid }) {
239
+ const sizeValue = useComponentSizeValue(size);
240
+ const resolvedSize = resolveResponsiveComponentSize(sizeValue);
172
241
  const inputRef = React.useRef(null);
173
242
  const setInputRef = React.useCallback((node) => {
174
243
  inputRef.current = node;
175
244
  if (typeof ref === "function") ref(node);
176
245
  else if (ref) ref.current = node;
177
246
  }, [ref]);
178
- const initial = React.useMemo(() => parseValue(value), []);
179
- const [country, setCountry] = React.useState(initial.country ?? defaultCountry);
180
- const [national, setNational] = React.useState(() => formatNational(initial.digits, initial.country ?? defaultCountry));
247
+ const [phone, setPhone] = React.useState(() => readPhoneValue(value, defaultCountry));
181
248
  React.useEffect(() => {
182
- if (toE164(getNationalDigits(national), country) === value) return;
183
- const next = parseValue(value);
184
- const nextCountry = next.country ?? country;
185
- setCountry(nextCountry);
186
- setNational(formatNational(next.digits, nextCountry));
249
+ if (phone.value === value) return;
250
+ setPhone(readPhoneValue(value, phone.country));
187
251
  }, [value]);
188
- function emit(digits, nextCountry) {
189
- onChange?.(toE164(digits, nextCountry));
252
+ function commit(next) {
253
+ setPhone(next);
254
+ if (next.value !== phone.value) onChange?.(next.value);
190
255
  }
191
256
  function handleInputChange(event) {
192
- const digits = getNationalDigits(event.target.value);
193
- setNational(formatNational(digits, country));
194
- emit(digits, country);
257
+ commit(derivePhoneValue(event.target.value, phone.country));
195
258
  }
196
259
  function handleCountrySelect(nextCountry) {
197
- const digits = getNationalDigits(national);
198
- setCountry(nextCountry);
199
- setNational(formatNational(digits, nextCountry));
200
- emit(digits, nextCountry);
260
+ commit(selectPhoneCountry(phone, nextCountry));
201
261
  }
202
262
  const dividerStateClasses = cn("group-hover/input-group:bg-line-strong", "group-focus-within/input-group:bg-line-focus", "group-has-[[aria-invalid=true]]/input-group:bg-line-danger", "group-has-disabled/input-group:bg-line-subtle");
203
263
  return /* @__PURE__ */ jsxs(InputGroup, {
204
- size: resolvedSize,
264
+ size: sizeValue,
205
265
  className,
206
- children: [/* @__PURE__ */ jsxs(InputGroupAddon, {
207
- align: "inline-start",
208
- className: "gap-2 self-stretch py-0",
209
- children: [/* @__PURE__ */ jsx(CountrySelect, {
210
- country,
211
- size: resolvedSize,
266
+ children: [
267
+ /* @__PURE__ */ jsxs(InputGroupAddon, {
268
+ align: "inline-start",
269
+ className: "gap-2 self-stretch py-0",
270
+ children: [/* @__PURE__ */ jsx(CountrySelect, {
271
+ country: phone.country,
272
+ size: resolvedSize.base,
273
+ disabled,
274
+ showCallingCode: !phone.international,
275
+ onSelect: handleCountrySelect,
276
+ finalFocusRef: inputRef
277
+ }), /* @__PURE__ */ jsx(Separator, {
278
+ orientation: "vertical",
279
+ shade: "deep",
280
+ className: cn("self-stretch transition-colors", dividerStateClasses)
281
+ })]
282
+ }),
283
+ /* @__PURE__ */ jsx(InputGroupInput, {
284
+ ref: setInputRef,
285
+ id,
286
+ name,
287
+ type: "tel",
288
+ inputMode: "tel",
289
+ autoComplete: "tel",
290
+ value: phone.text,
291
+ onChange: handleInputChange,
292
+ placeholder,
212
293
  disabled,
213
- onSelect: handleCountrySelect,
214
- finalFocusRef: inputRef
215
- }), /* @__PURE__ */ jsx(Separator, {
216
- orientation: "vertical",
217
- shade: "deep",
218
- className: cn("self-stretch transition-colors", dividerStateClasses)
219
- })]
220
- }), /* @__PURE__ */ jsx(InputGroupInput, {
221
- ref: setInputRef,
222
- id,
223
- name,
224
- type: "tel",
225
- inputMode: "tel",
226
- autoComplete: "tel",
227
- value: national,
228
- onChange: handleInputChange,
229
- placeholder,
230
- disabled,
231
- readOnly,
232
- "aria-invalid": ariaInvalid || void 0,
233
- className: "pl-0"
234
- })]
294
+ readOnly,
295
+ "aria-invalid": ariaInvalid || void 0,
296
+ className: "pl-0"
297
+ }),
298
+ rightAddon ? /* @__PURE__ */ jsx(InputGroupAddon, {
299
+ align: "inline-end",
300
+ "data-slot": "phone-right-addon",
301
+ className: "gap-2 self-stretch py-0",
302
+ children: rightAddon
303
+ }) : null
304
+ ]
235
305
  });
236
306
  }
237
307
  //#endregion
@@ -0,0 +1,62 @@
1
+ import { cn } from "./utils/cn.js";
2
+ import { responsiveValueClasses } from "./size-context.js";
3
+ import { Button } from "./button.js";
4
+ import { useInputComponentSizeValue } from "./input-size-context.js";
5
+ import { PopoverTrigger } from "./popover.js";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { cva } from "class-variance-authority";
8
+ //#region src/lib/picker.tsx
9
+ const pickerTriggerSizeVariants = {
10
+ sm: "h-8 px-3 text-gdt-xs [&_svg]:size-3.5",
11
+ md: "h-10 px-3.5 text-gdt-sm [&_svg]:size-4",
12
+ lg: "h-12 px-4 text-gdt-md [&_svg]:size-4.5",
13
+ xl: "h-14 px-4.5 text-gdt-lg [&_svg]:size-5"
14
+ };
15
+ const pickerTriggerVariants = cva("flex w-full items-center justify-between rounded-full border transition-[border-color,box-shadow] outline-none", {
16
+ variants: { size: pickerTriggerSizeVariants },
17
+ defaultVariants: { size: "md" }
18
+ });
19
+ function PickerTrigger({ icon: Icon, displayValue, placeholder, disabled, open, size, className }) {
20
+ const resolvedSize = responsiveValueClasses(useInputComponentSizeValue(size), responsivePickerTriggerSizes);
21
+ return /* @__PURE__ */ jsxs(PopoverTrigger, {
22
+ disabled,
23
+ "data-size": resolvedSize.base,
24
+ className: cn(pickerTriggerVariants({ size: null }), resolvedSize.className, disabled ? "cursor-not-allowed border-line-subtle bg-surface text-fg-caption-placeholder" : open ? "border-line-focus bg-canvas text-fg-primary inset-ring-1 inset-ring-line-focus" : "border-line bg-canvas text-fg-primary hover:border-line-strong", className),
25
+ children: [/* @__PURE__ */ jsx("span", {
26
+ className: cn("min-w-0 truncate", !displayValue && "text-fg-caption-placeholder"),
27
+ children: displayValue || placeholder
28
+ }), /* @__PURE__ */ jsx(Icon, { className: cn("ml-2 shrink-0", disabled ? "text-fg-caption-placeholder" : "text-fg-secondary") })]
29
+ });
30
+ }
31
+ const responsivePickerTriggerSizes = {
32
+ base: pickerTriggerSizeVariants,
33
+ md: {
34
+ sm: "md:h-8 md:px-3 md:text-gdt-xs md:[&_svg]:size-3.5",
35
+ md: "md:h-10 md:px-3.5 md:text-gdt-sm md:[&_svg]:size-4",
36
+ lg: "md:h-12 md:px-4 md:text-gdt-md md:[&_svg]:size-4.5",
37
+ xl: "md:h-14 md:px-4.5 md:text-gdt-lg md:[&_svg]:size-5"
38
+ },
39
+ lg: {
40
+ sm: "lg:h-8 lg:px-3 lg:text-gdt-xs lg:[&_svg]:size-3.5",
41
+ md: "lg:h-10 lg:px-3.5 lg:text-gdt-sm lg:[&_svg]:size-4",
42
+ lg: "lg:h-12 lg:px-4 lg:text-gdt-md lg:[&_svg]:size-4.5",
43
+ xl: "lg:h-14 lg:px-4.5 lg:text-gdt-lg lg:[&_svg]:size-5"
44
+ }
45
+ };
46
+ function PickerFooter({ secondaryLabel, onSecondary, onApply }) {
47
+ return /* @__PURE__ */ jsxs("div", {
48
+ className: "flex w-full items-center justify-between border-t border-line-subtle px-4 py-3",
49
+ children: [/* @__PURE__ */ jsx(Button, {
50
+ variant: "tertiary-outline",
51
+ size: "sm",
52
+ onClick: onSecondary,
53
+ children: secondaryLabel
54
+ }), /* @__PURE__ */ jsx(Button, {
55
+ size: "sm",
56
+ onClick: onApply,
57
+ children: "Apply"
58
+ })]
59
+ });
60
+ }
61
+ //#endregion
62
+ export { PickerTrigger as n, PickerFooter as t };
@@ -1,5 +1,5 @@
1
- import "./input-size-context-C-SFx9sx.js";
2
- import { r as PopoverContent } from "./popover-DSlPeH7x.js";
1
+ import "./input-size-context-BMhves-J.js";
2
+ import { r as PopoverContent } from "./popover-CNymD33m.js";
3
3
  import "./icons-C9JXR5Xv.js";
4
4
  import * as React from "react";
5
5
  //#region src/lib/picker.d.ts
@@ -1,4 +1,4 @@
1
- import { t as ComponentSize } from "./size-context-BX6kAdVj.js";
1
+ import { t as ComponentSize } from "./size-context-BVhHduLi.js";
2
2
  import { ChartConfig } from "./chart.js";
3
3
  import * as React from "react";
4
4
  import { Pie, PieChart as PieChart$1 } from "recharts";
@@ -1,4 +1,4 @@
1
- import { t as ComponentSize } from "./size-context-BX6kAdVj.js";
1
+ import { t as ComponentSize } from "./size-context-BVhHduLi.js";
2
2
  import * as React from "react";
3
3
  import { Popover } from "@base-ui/react/popover";
4
4
  //#region src/popover.d.ts
package/dist/popover.d.ts CHANGED
@@ -1,2 +1,2 @@
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";
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-CNymD33m.js";
2
2
  export { Popover, PopoverBody, PopoverContent, PopoverDescription, PopoverFooter, PopoverHeader, PopoverTitle, PopoverTrigger };
@@ -1,5 +1,5 @@
1
- import { n as ButtonLink, t as Button } from "./button-DW5OijoR.js";
2
- import { Carousel, CarouselIndicator, CarouselItem } from "./carousel.js";
1
+ import { n as ButtonLink, t as Button } from "./button-BS5KCibF.js";
2
+ import { Carousel, CarouselIndicator, CarouselItem, CarouselNext, CarouselPrevious } from "./carousel.js";
3
3
  import { ImageProps } from "./image.js";
4
4
  import { useRender } from "@base-ui/react/use-render";
5
5
  import { VariantProps } from "class-variance-authority";
@@ -58,6 +58,10 @@ declare function PropertyListingCardMedia({ className, images, children, ...prop
58
58
  * carousel part works here, including `CarouselPrevious`/`CarouselNext`.
59
59
  */
60
60
  declare function PropertyListingCardCarousel({ className, opts, ...props }: React.ComponentProps<typeof Carousel>): React.JSX.Element;
61
+ /** Previous-photo control, revealed when the carousel is hovered or focused. */
62
+ declare function PropertyListingCardCarouselPrevious({ className, ...props }: React.ComponentProps<typeof CarouselPrevious>): React.JSX.Element;
63
+ /** Next-photo control, revealed when the carousel is hovered or focused. */
64
+ declare function PropertyListingCardCarouselNext({ className, ...props }: React.ComponentProps<typeof CarouselNext>): React.JSX.Element;
61
65
  declare function PropertyListingCardCarouselItem({ className, ...props }: React.ComponentProps<typeof CarouselItem>): React.JSX.Element;
62
66
  /**
63
67
  * The indicator, lifted clear of the options bar by default. That bar is
@@ -88,4 +92,4 @@ declare function PropertyListingCardActions({ className, ...props }: React.Compo
88
92
  declare function PropertyListingCardActionButton({ className, type, ...props }: React.ComponentProps<typeof Button>): React.JSX.Element;
89
93
  declare function PropertyListingCardActionButtonLink({ className, ...props }: React.ComponentProps<typeof ButtonLink>): React.JSX.Element;
90
94
  //#endregion
91
- export { PropertyListingCard, PropertyListingCardActionButton, PropertyListingCardActionButtonLink, PropertyListingCardActions, PropertyListingCardBadges, PropertyListingCardCarousel, PropertyListingCardCarouselIndicator, PropertyListingCardCarouselItem, PropertyListingCardDetails, PropertyListingCardImage, PropertyListingCardImagePlaceholder, PropertyListingCardMedia, PropertyListingCardMediaTop, PropertyListingCardOptionsBar, PropertyListingCardOverview, type PropertyListingCardProps, PropertyListingCardTitle, type PropertyListingImage, propertyListingCardVariants };
95
+ export { PropertyListingCard, PropertyListingCardActionButton, PropertyListingCardActionButtonLink, PropertyListingCardActions, PropertyListingCardBadges, PropertyListingCardCarousel, PropertyListingCardCarouselIndicator, PropertyListingCardCarouselItem, PropertyListingCardCarouselNext, PropertyListingCardCarouselPrevious, PropertyListingCardDetails, PropertyListingCardImage, PropertyListingCardImagePlaceholder, PropertyListingCardMedia, PropertyListingCardMediaTop, PropertyListingCardOptionsBar, PropertyListingCardOverview, type PropertyListingCardProps, PropertyListingCardTitle, type PropertyListingImage, propertyListingCardVariants };
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn } from "./utils/cn.js";
3
3
  import { Button, ButtonLink } from "./button.js";
4
- import { Carousel, CarouselContent, CarouselIndicator, CarouselItem } from "./carousel.js";
4
+ import { Carousel, CarouselContent, CarouselIndicator, CarouselItem, CarouselNext, CarouselPrevious } from "./carousel.js";
5
5
  import { Image } from "./image.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { mergeProps } from "@base-ui/react/merge-props";
@@ -53,7 +53,12 @@ function PropertyListingCardMedia({ className, images, children, ...props }) {
53
53
  }
54
54
  /** The backdrop the deprecated `images` prop builds, unchanged. */
55
55
  function PropertyListingCardMediaBackdrop({ images }) {
56
- if (images.length > 1) return /* @__PURE__ */ jsxs(PropertyListingCardCarousel, { children: [/* @__PURE__ */ jsx(CarouselContent, { children: images.map((carouselImage, index) => /* @__PURE__ */ jsx(PropertyListingCardCarouselItem, { children: /* @__PURE__ */ jsx(PropertyListingCardImage, { image: carouselImage }) }, carouselImage.id ?? carouselImage.src ?? carouselImage.alt ?? index)) }), /* @__PURE__ */ jsx(PropertyListingCardCarouselIndicator, {})] });
56
+ if (images.length > 1) return /* @__PURE__ */ jsxs(PropertyListingCardCarousel, { children: [
57
+ /* @__PURE__ */ jsx(CarouselContent, { children: images.map((carouselImage, index) => /* @__PURE__ */ jsx(PropertyListingCardCarouselItem, { children: /* @__PURE__ */ jsx(PropertyListingCardImage, { image: carouselImage }) }, carouselImage.id ?? carouselImage.src ?? carouselImage.alt ?? index)) }),
58
+ /* @__PURE__ */ jsx(PropertyListingCardCarouselIndicator, {}),
59
+ /* @__PURE__ */ jsx(PropertyListingCardCarouselPrevious, {}),
60
+ /* @__PURE__ */ jsx(PropertyListingCardCarouselNext, {})
61
+ ] });
57
62
  if (images[0]?.src) return /* @__PURE__ */ jsx(PropertyListingCardImage, {
58
63
  image: images[0],
59
64
  className: "absolute inset-0 -z-10"
@@ -69,11 +74,23 @@ function PropertyListingCardCarousel({ className, opts, ...props }) {
69
74
  return /* @__PURE__ */ jsx(Carousel, {
70
75
  "data-slot": "property-listing-card-carousel",
71
76
  imageSize: "full",
72
- opts: {
73
- loop: true,
74
- ...opts
75
- },
76
- className: cn("absolute inset-0 -z-10 size-full rounded-none bg-surface", className),
77
+ opts,
78
+ className: cn("group/property-listing-carousel absolute inset-0 -z-10 size-full rounded-none bg-surface", className),
79
+ ...props
80
+ });
81
+ }
82
+ const propertyListingCardCarouselControlClassName = "size-9 border-white/35 bg-black/50 text-white opacity-0 shadow-[0_4px_16px_rgb(0_0_0/0.28)] backdrop-blur-md transition-[background-color,opacity,scale] hover:scale-105 hover:bg-black/70 group-hover/property-listing-carousel:opacity-100 group-focus-within/property-listing-carousel:opacity-100 focus-visible:opacity-100 focus-visible:shadow-[0_0_0_2px_var(--color-line-focus),0_4px_16px_rgb(0_0_0/0.28)] active:hover:scale-[0.97] disabled:opacity-0 group-hover/property-listing-carousel:disabled:opacity-40 group-focus-within/property-listing-carousel:disabled:opacity-40 disabled:hover:scale-100 [&_svg]:mx-auto [&_svg]:size-[18px]";
83
+ /** Previous-photo control, revealed when the carousel is hovered or focused. */
84
+ function PropertyListingCardCarouselPrevious({ className, ...props }) {
85
+ return /* @__PURE__ */ jsx(CarouselPrevious, {
86
+ className: cn(propertyListingCardCarouselControlClassName, "left-3", className),
87
+ ...props
88
+ });
89
+ }
90
+ /** Next-photo control, revealed when the carousel is hovered or focused. */
91
+ function PropertyListingCardCarouselNext({ className, ...props }) {
92
+ return /* @__PURE__ */ jsx(CarouselNext, {
93
+ className: cn(propertyListingCardCarouselControlClassName, "right-3", className),
77
94
  ...props
78
95
  });
79
96
  }
@@ -184,4 +201,4 @@ function PropertyListingCardActionButtonLink({ className, ...props }) {
184
201
  });
185
202
  }
186
203
  //#endregion
187
- export { PropertyListingCard, PropertyListingCardActionButton, PropertyListingCardActionButtonLink, PropertyListingCardActions, PropertyListingCardBadges, PropertyListingCardCarousel, PropertyListingCardCarouselIndicator, PropertyListingCardCarouselItem, PropertyListingCardDetails, PropertyListingCardImage, PropertyListingCardImagePlaceholder, PropertyListingCardMedia, PropertyListingCardMediaTop, PropertyListingCardOptionsBar, PropertyListingCardOverview, PropertyListingCardTitle, propertyListingCardVariants };
204
+ export { PropertyListingCard, PropertyListingCardActionButton, PropertyListingCardActionButtonLink, PropertyListingCardActions, PropertyListingCardBadges, PropertyListingCardCarousel, PropertyListingCardCarouselIndicator, PropertyListingCardCarouselItem, PropertyListingCardCarouselNext, PropertyListingCardCarouselPrevious, PropertyListingCardDetails, PropertyListingCardImage, PropertyListingCardImagePlaceholder, PropertyListingCardMedia, PropertyListingCardMediaTop, PropertyListingCardOptionsBar, PropertyListingCardOverview, PropertyListingCardTitle, propertyListingCardVariants };
@@ -1,4 +1,4 @@
1
- import { t as ComponentSize } from "./size-context-BX6kAdVj.js";
1
+ import { t as ComponentSize } from "./size-context-BVhHduLi.js";
2
2
  import { ChartConfig } from "./chart.js";
3
3
  import * as React from "react";
4
4
  import { PolarAngleAxis, PolarGrid, PolarRadiusAxis, Radar, RadarChart as RadarChart$1 } from "recharts";
@@ -1,4 +1,4 @@
1
- import { VariantProps } from "class-variance-authority";
1
+ import { n as ComponentSizeValue } from "./size-context-BVhHduLi.js";
2
2
  import { Radio } from "@base-ui/react/radio";
3
3
  import { RadioGroup as RadioGroup$1 } from "@base-ui/react/radio-group";
4
4
  //#region src/radio-group.d.ts
@@ -6,7 +6,7 @@ declare function RadioGroup({ className, ...props }: RadioGroup$1.Props): import
6
6
  declare const radioVariants: (props?: ({
7
7
  size?: "lg" | "md" | "sm" | null | undefined;
8
8
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
9
- type RadioGroupItemSize = NonNullable<VariantProps<typeof radioVariants>["size"]>;
9
+ type RadioGroupItemSize = ComponentSizeValue;
10
10
  type RadioGroupItemProps<Value = unknown> = Radio.Root.Props<Value> & {
11
11
  size?: RadioGroupItemSize;
12
12
  };
@@ -1,11 +1,16 @@
1
1
  "use client";
2
2
  import { cn } from "./utils/cn.js";
3
- import { useComponentSize } from "./size-context.js";
3
+ import { responsiveValueClasses, useComponentSizeValue } from "./size-context.js";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import { cva } from "class-variance-authority";
6
6
  import { Radio } from "@base-ui/react/radio";
7
7
  import { RadioGroup as RadioGroup$1 } from "@base-ui/react/radio-group";
8
8
  //#region src/radio-group.tsx
9
+ const radioSizeVariants = {
10
+ sm: "size-4 [--radio-dot-size:0.625rem]",
11
+ md: "size-5 [--radio-dot-size:0.75rem]",
12
+ lg: "size-6 [--radio-dot-size:0.875rem]"
13
+ };
9
14
  function RadioGroup({ className, ...props }) {
10
15
  return /* @__PURE__ */ jsx(RadioGroup$1, {
11
16
  "data-slot": "radio-group",
@@ -13,11 +18,7 @@ function RadioGroup({ className, ...props }) {
13
18
  ...props
14
19
  });
15
20
  }
16
- const radioVariants = cva("group/radio-group-item peer relative flex aspect-square shrink-0 rounded-full border-2 bg-transparent text-transparent outline-none transition-[background-color,border-color,box-shadow,color,scale] duration-[var(--duration-motion-press)] ease-gdt-out active:scale-[0.97] motion-reduce:active:scale-100 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-line-focus focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] aria-invalid:border-line-danger aria-invalid:ring-3 aria-invalid:ring-line-danger/20 aria-invalid:focus-visible:border-line-danger aria-invalid:focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-danger)] border-line-strong data-checked:border-action-primary data-checked:text-action-primary data-disabled:cursor-not-allowed data-disabled:border-line-subtle data-disabled:bg-surface data-disabled:text-fg-caption-placeholder data-disabled:active:scale-100 size-5 [--radio-dot-size:0.75rem] group-data-[size=sm]/field:size-4 group-data-[size=sm]/field:[--radio-dot-size:0.625rem] group-data-[size=md]/field:size-5 group-data-[size=md]/field:[--radio-dot-size:0.75rem] group-data-[size=lg]/field:size-6 group-data-[size=lg]/field:[--radio-dot-size:0.875rem]", { variants: { size: {
17
- sm: "size-4 [--radio-dot-size:0.625rem]",
18
- md: "size-5 [--radio-dot-size:0.75rem]",
19
- lg: "size-6 [--radio-dot-size:0.875rem]"
20
- } } });
21
+ const radioVariants = cva("group/radio-group-item peer relative flex aspect-square shrink-0 rounded-full border-2 bg-transparent text-transparent outline-none transition-[background-color,border-color,box-shadow,color,scale] duration-[var(--duration-motion-press)] ease-gdt-out active:scale-[0.97] motion-reduce:active:scale-100 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-line-focus focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-focus)] aria-invalid:border-line-danger aria-invalid:ring-3 aria-invalid:ring-line-danger/20 aria-invalid:focus-visible:border-line-danger aria-invalid:focus-visible:shadow-[0px_0px_0px_2px_var(--color-line-danger)] border-line-strong data-checked:border-action-primary data-checked:text-action-primary data-disabled:cursor-not-allowed data-disabled:border-line-subtle data-disabled:bg-surface data-disabled:text-fg-caption-placeholder data-disabled:active:scale-100", { variants: { size: radioSizeVariants } });
21
22
  /**
22
23
  * Compose each radio item with the shared field primitives.
23
24
  *
@@ -34,11 +35,11 @@ const radioVariants = cva("group/radio-group-item peer relative flex aspect-squa
34
35
  * ```
35
36
  */
36
37
  function RadioGroupItem({ className, size, ...props }) {
37
- const resolvedSize = useComponentSize(size);
38
+ const resolvedSize = responsiveValueClasses(useComponentSizeValue(size), responsiveRadioSizes);
38
39
  return /* @__PURE__ */ jsx(Radio.Root, {
39
40
  "data-slot": "radio-group-item",
40
- "data-size": resolvedSize,
41
- className: cn(radioVariants({ size: resolvedSize }), className),
41
+ "data-size": resolvedSize.base,
42
+ className: cn(radioVariants({ size: null }), resolvedSize.className, className),
42
43
  ...props,
43
44
  children: /* @__PURE__ */ jsx(Radio.Indicator, {
44
45
  "data-slot": "radio-group-indicator",
@@ -47,5 +48,18 @@ function RadioGroupItem({ className, size, ...props }) {
47
48
  })
48
49
  });
49
50
  }
51
+ const responsiveRadioSizes = {
52
+ base: radioSizeVariants,
53
+ md: {
54
+ sm: "md:size-4 md:[--radio-dot-size:0.625rem]",
55
+ md: "md:size-5 md:[--radio-dot-size:0.75rem]",
56
+ lg: "md:size-6 md:[--radio-dot-size:0.875rem]"
57
+ },
58
+ lg: {
59
+ sm: "lg:size-4 lg:[--radio-dot-size:0.625rem]",
60
+ md: "lg:size-5 lg:[--radio-dot-size:0.75rem]",
61
+ lg: "lg:size-6 lg:[--radio-dot-size:0.875rem]"
62
+ }
63
+ };
50
64
  //#endregion
51
65
  export { RadioGroup, RadioGroupItem, radioVariants };
@@ -0,0 +1,60 @@
1
+ import { n as ComponentSizeValue } from "./size-context-BVhHduLi.js";
2
+ import { j as IconProps } from "./icons-C9JXR5Xv.js";
3
+ import * as React from "react";
4
+ //#region src/rating.d.ts
5
+ /** How finely a rating can be *set*. Display always honours the exact value. */
6
+ type RatingPrecision = 1 | 0.5;
7
+ type RatingIcon = React.ComponentType<IconProps>;
8
+ interface RatingProps {
9
+ /** Controlled rating. Fractions render as partially filled icons. */
10
+ value?: number;
11
+ /** Starting rating when the component owns its own state. */
12
+ defaultValue?: number;
13
+ onValueChange?: (value: number) => void;
14
+ /** How many icons to render. */
15
+ max?: number;
16
+ /** Smallest increment a reader can pick. Display is not rounded to it. */
17
+ precision?: RatingPrecision;
18
+ size?: ComponentSizeValue;
19
+ /** Renders the score as an image instead of a control. */
20
+ readOnly?: boolean;
21
+ disabled?: boolean;
22
+ required?: boolean;
23
+ /** Groups the radios and names the value in submitted form data. */
24
+ name?: string;
25
+ id?: string;
26
+ /** Accessible name for each option, e.g. `(value) => \`${value} stars\``. */
27
+ itemLabel?: (value: number, max: number) => string;
28
+ /** Swaps the glyph. Anything that takes SVG props and paints `currentColor`. */
29
+ icon?: RatingIcon;
30
+ /**
31
+ * Overrides the icon box for a size the `sm`/`md`/`lg` scale does not cover
32
+ * — `iconClassName="size-9"`. Merged after the scale, so it wins outright.
33
+ */
34
+ iconClassName?: string;
35
+ className?: string;
36
+ onBlur?: React.FocusEventHandler<HTMLElement>;
37
+ /** The `div` that groups the radios, or the `span` when `readOnly`. */
38
+ ref?: React.Ref<HTMLElement>;
39
+ "aria-label"?: string;
40
+ "aria-labelledby"?: string;
41
+ "aria-describedby"?: string;
42
+ "aria-invalid"?: boolean;
43
+ }
44
+ /**
45
+ * A star rating that reads and writes.
46
+ *
47
+ * Interactive ratings are a group of real radio inputs — one per selectable
48
+ * value — visually replaced by the icons. That is deliberate: it buys native
49
+ * arrow-key navigation, native form submission under `name`, and the
50
+ * "3 of 5, radio button 3 of 5" announcement, none of which a div with click
51
+ * handlers gets for free.
52
+ *
53
+ * ```tsx
54
+ * <Rating defaultValue={4} onValueChange={setRating} />
55
+ * <Rating value={4.3} readOnly />
56
+ * ```
57
+ */
58
+ declare function Rating({ value, defaultValue, onValueChange, max, precision, size, readOnly, disabled, required, name, id, itemLabel, icon, iconClassName, className, onBlur, ref, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, "aria-invalid": ariaInvalid }: RatingProps): React.JSX.Element;
59
+ //#endregion
60
+ export { Rating, type RatingIcon, type RatingPrecision, type RatingProps };