@brightweblabs/ui 1.4.7 → 1.4.9

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@brightweblabs/ui",
3
3
  "private": false,
4
- "version": "1.4.7",
4
+ "version": "1.4.9",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
7
7
  "files": [
@@ -16,6 +16,8 @@ import { cn } from "../lib/utils"
16
16
  import { Button } from "./button"
17
17
  import { buttonVariants, type ButtonVariantProps } from "./button-variants"
18
18
 
19
+ const DEFAULT_FUTURE_YEAR_RANGE = 25
20
+
19
21
  function Calendar({
20
22
  className,
21
23
  classNames,
@@ -29,6 +31,21 @@ function Calendar({
29
31
  buttonVariant?: ButtonVariantProps["variant"]
30
32
  }) {
31
33
  const defaultClassNames = getDefaultClassNames()
34
+ const hasYearDropdown =
35
+ captionLayout === "dropdown" || captionLayout === "dropdown-years"
36
+ const hasExplicitEndMonth =
37
+ props.endMonth !== undefined ||
38
+ props.toMonth !== undefined ||
39
+ props.toYear !== undefined
40
+ const defaultEndMonth =
41
+ hasYearDropdown && !hasExplicitEndMonth
42
+ ? new Date(
43
+ (props.today ?? new Date()).getFullYear() +
44
+ DEFAULT_FUTURE_YEAR_RANGE,
45
+ 11,
46
+ 31
47
+ )
48
+ : undefined
32
49
 
33
50
  return (
34
51
  <DayPicker
@@ -176,6 +193,7 @@ function Calendar({
176
193
  ...components,
177
194
  }}
178
195
  {...props}
196
+ endMonth={props.endMonth ?? defaultEndMonth}
179
197
  />
180
198
  )
181
199
  }
@@ -23,21 +23,26 @@ function flagEmoji(iso2: string) {
23
23
  return iso2.toUpperCase().split("").map((character) => String.fromCodePoint(0x1f1e6 - 0x41 + character.charCodeAt(0))).join("");
24
24
  }
25
25
 
26
- export function PhoneInput({ value, onChange, defaultCountry = "pt", disabled = false, className, placeholder = "912 345 678", ...inputProps }: PhoneInputProps) {
26
+ function normalizePhoneValue(phone: string, dialCode: string) {
27
+ return phone === `+${dialCode}` ? "" : phone;
28
+ }
29
+
30
+ export function PhoneInput({ value, onChange, defaultCountry = "pt", disabled = false, className, placeholder = "912 345 678", name, "aria-describedby": ariaDescribedBy, ...inputProps }: PhoneInputProps) {
27
31
  const inputRef = useRef<HTMLInputElement | null>(null);
28
32
  const triggerRef = useRef<HTMLButtonElement | null>(null);
29
33
  const dropdownRef = useRef<HTMLDivElement | null>(null);
30
34
  const optionRefs = useRef<Array<HTMLButtonElement | null>>([]);
31
35
  const countryListId = useId();
36
+ const phonePrefixId = useId();
32
37
  const [open, setOpen] = useState(false);
33
38
  const [search, setSearch] = useState("");
34
39
  const [activeIndex, setActiveIndex] = useState(0);
35
40
 
36
- const { inputValue, handlePhoneValueChange, country, setCountry } = usePhoneInput({
41
+ const { phone, inputValue, handlePhoneValueChange, country, setCountry } = usePhoneInput({
37
42
  defaultCountry,
38
43
  value,
39
- forceDialCode: true,
40
- onChange: ({ phone }) => onChange(phone),
44
+ disableDialCodeAndPrefix: true,
45
+ onChange: ({ phone: nextPhone, country: nextCountry }) => onChange(normalizePhoneValue(nextPhone, nextCountry.dialCode)),
41
46
  inputRef,
42
47
  });
43
48
 
@@ -123,7 +128,7 @@ export function PhoneInput({ value, onChange, defaultCountry = "pt", disabled =
123
128
  aria-controls={countryListId}
124
129
  aria-expanded={open}
125
130
  aria-haspopup="listbox"
126
- aria-label="Choose country code"
131
+ aria-label={`Choose country code, current ${country.name} +${country.dialCode}`}
127
132
  >
128
133
  <span className="text-body-lg leading-none">{flagEmoji(country.iso2)}</span>
129
134
  <svg className="size-2.5 text-foreground/40" viewBox="0 0 10 6" fill="none" aria-hidden>
@@ -181,7 +186,9 @@ export function PhoneInput({ value, onChange, defaultCountry = "pt", disabled =
181
186
  ) : null}
182
187
 
183
188
  <span className="h-4 w-px shrink-0 bg-foreground/15" />
184
- <input {...inputProps} ref={inputRef} value={inputValue} onChange={handlePhoneValueChange} disabled={disabled} placeholder={placeholder} type="tel" className="h-7 flex-1 border-0 bg-transparent pl-2 text-body text-foreground outline-none placeholder:text-foreground-muted-accessible disabled:pointer-events-none disabled:opacity-100" />
189
+ <span id={phonePrefixId} className="select-none pl-2 text-body text-foreground">+{country.dialCode}</span>
190
+ <input {...inputProps} aria-describedby={[ariaDescribedBy, phonePrefixId].filter(Boolean).join(" ")} ref={inputRef} value={inputValue} onChange={handlePhoneValueChange} disabled={disabled} placeholder={placeholder} type="tel" className="h-7 flex-1 border-0 bg-transparent pl-1 text-body text-foreground outline-none placeholder:text-foreground-muted-accessible disabled:pointer-events-none disabled:opacity-100" />
191
+ {name ? <input type="hidden" name={name} value={normalizePhoneValue(phone, country.dialCode)} disabled={disabled} form={inputProps.form} /> : null}
185
192
  </div>
186
193
  );
187
194
  }