@danxbot/ui 8.0.0 → 9.0.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.
@@ -0,0 +1,7 @@
1
+ /** The shared "no value" reading for a blank field — a date, a number, a
2
+ * phone number, a currency amount: nothing recorded. Shared by every
3
+ * formatter that reads absence this way, so the glyph itself never drifts
4
+ * between them (DX-3254). `formatBoolean` does NOT use this — see its own
5
+ * module doc for why a tri-state boolean reads absence as "Unknown"
6
+ * instead. */
7
+ export declare const ABSENT = "\u2014";
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * `NaN` / `Infinity` are not real amounts either and render as the em dash —
5
5
  * grouped with absence rather than with a malformed string, because unlike
6
- * `formatDate`/`formatPhone`'s malformed-input case, there is no ORIGINAL
6
+ * `formatDate`'s malformed-input case, there is no ORIGINAL
7
7
  * user-facing string to show back: the caller already has a `number`, and a
8
8
  * non-finite one is a computation defect upstream, not a typo to surface.
9
9
  */
@@ -1,8 +1,5 @@
1
1
  export { formatDate, parseDate } from "./date";
2
2
  export { formatDateTime, parseDateTime, type FormatDateTimeOptions, type ParseDateTimeOptions } from "./datetime";
3
3
  export { formatCurrency, parseCurrency } from "./currency";
4
- export { formatPhone, parsePhone, digitsOfPhoneInProgress, formatPhonePartial } from "./phone";
5
4
  export { formatNumber, parseNumber, type FormatNumberOptions } from "./number";
6
5
  export { formatBoolean, parseBoolean, type FormatBooleanOptions } from "./boolean";
7
- export { isValidEmail } from "./email";
8
- export { isValidUrl } from "./url";
@@ -39,5 +39,5 @@
39
39
  * about this is a migration and no existing import has to change.
40
40
  */
41
41
  export { formatBytes, formatTokens, formatCompactNumber } from "./lib/format";
42
- export { formatDate, parseDate, formatDateTime, parseDateTime, type FormatDateTimeOptions, type ParseDateTimeOptions, formatCurrency, parseCurrency, formatPhone, parsePhone, digitsOfPhoneInProgress, formatPhonePartial, formatNumber, parseNumber, type FormatNumberOptions, formatBoolean, parseBoolean, type FormatBooleanOptions, isValidEmail, isValidUrl, } from "./lib/values";
42
+ export { formatDate, parseDate, formatDateTime, parseDateTime, type FormatDateTimeOptions, type ParseDateTimeOptions, formatCurrency, parseCurrency, formatNumber, parseNumber, type FormatNumberOptions, formatBoolean, parseBoolean, type FormatBooleanOptions, } from "./lib/values";
43
43
  export { confidenceLevel, CONFIDENCE_LEVEL_LABELS, type ConfidenceLevel } from "./lib/confidence";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danxbot/ui",
3
- "version": "8.0.0",
3
+ "version": "9.0.0",
4
4
  "type": "module",
5
5
  "description": "Danxbot — a domain-agnostic React design system with motion as a first-class primitive.",
6
6
  "license": "MIT",
@@ -1,34 +0,0 @@
1
- import { type CSSProperties, type Key, type ReactNode, type Ref, type RefObject } from "react";
2
- export interface InfiniteScrollerHandle {
3
- /** Mount everything up to `index` (if not already mounted), then scroll that item into view. */
4
- reveal: (index: number, options?: ScrollIntoViewOptions) => void;
5
- }
6
- export interface InfiniteScrollerProps<T> {
7
- /** Every item. Only a window of them is mounted. */
8
- items: readonly T[];
9
- renderItem: (item: T, index: number) => ReactNode;
10
- /** A stable React key per item. */
11
- getKey: (item: T, index: number) => Key;
12
- /** How many items are mounted at first. Default 20. */
13
- initialCount?: number;
14
- /** How many more mount each time the end comes into range. Default `initialCount`. */
15
- batchSize?: number;
16
- /** Lay items out as a CSS grid with this many equal columns. Omit for a plain vertical list. */
17
- columns?: number;
18
- /** How far outside the scroll viewport the end may be before more mount. Default "200px". */
19
- rootMargin?: string;
20
- /**
21
- * The scrolling element to observe against. Default: the nearest ancestor whose `overflow-y`
22
- * scrolls, else the viewport.
23
- */
24
- root?: RefObject<Element | null>;
25
- /** Changing this puts the window back to `initialCount` (a genuinely different list). */
26
- resetKey?: unknown;
27
- /** Classes for the list/grid element — gaps, padding. */
28
- className?: string;
29
- style?: CSSProperties;
30
- ref?: Ref<InfiniteScrollerHandle>;
31
- /** Accessible name for the list, when it needs one. */
32
- "aria-label"?: string;
33
- }
34
- export declare function InfiniteScroller<T>({ items, renderItem, getKey, initialCount, batchSize, columns, rootMargin, root, resetKey, className, style, ref, "aria-label": ariaLabel, }: InfiniteScrollerProps<T>): import("react").JSX.Element;
@@ -1,17 +0,0 @@
1
- export interface PhoneFieldProps {
2
- /** The stored ten-digit form, or null for none. */
3
- value: string | null;
4
- /** Reports the new ten-digit value, or null when the person cleared it. Only on commit. */
5
- onValueChange: (value: string | null) => void;
6
- /** Told while the box has focus — i.e. while the person's own in-progress digits are on screen. */
7
- onEditingChange?: (editing: boolean) => void;
8
- /** The accessible name — required, same reasoning as `DateField`'s. */
9
- "aria-label": string;
10
- /** @default "(555) 123-4567" */
11
- placeholder?: string;
12
- disabled?: boolean;
13
- /** The sentence shown for a committed value that is not ten digits. */
14
- invalidMessage?: string;
15
- className?: string;
16
- }
17
- export declare function PhoneField({ value, onValueChange, onEditingChange, "aria-label": ariaLabel, placeholder, disabled, invalidMessage, className, }: PhoneFieldProps): import("react").JSX.Element;
@@ -1,9 +0,0 @@
1
- export { CalendarMonth, type CalendarMonthProps } from "./CalendarMonth";
2
- export { CalendarTimeGrid, type CalendarTimeGridProps } from "./CalendarTimeGrid";
3
- export { useNow, type UseNowOptions } from "./use-now";
4
- export { EventActions, type EventActionsProps } from "./EventActions";
5
- export { useCalendarDrag, type CalendarDragOptions, type CalendarDragState, } from "./use-calendar-drag";
6
- export { useEventKeyboard, type EventKeyboardOptions, type EventKeyboardState, } from "./use-event-keyboard";
7
- export { EVENT_PALETTE, DEFAULT_PALETTE_KEY, isPaletteKey, paletteFor } from "./palette";
8
- export { cellLabel, dayNumber, eventLabel, formatDateRange, longDate, monthTitle, timeOfDay, weekdayName, zoneLabel, } from "./format";
9
- export { initialFocusDay, isInMonth, nextDayForKey, useGridNavigation, type GridNavigation, type GridNavigationOptions, } from "./use-grid-navigation";
@@ -1,12 +0,0 @@
1
- /**
2
- * Whether `value` reads as a plausible email address. An empty (or
3
- * whitespace-only) value is treated as VALID — clearing the field is not a
4
- * typo, and a required-field rule belongs to the caller, not this check.
5
- *
6
- * SG-909 review fix: the previous regex (`/^[^\s@]+@[^\s@]+\.[^\s@]+$/`)
7
- * matched the domain half non-specifically, so `"a@b..com"` (an empty label
8
- * between two dots) passed, and it never looked at trailing punctuation at
9
- * all, so `"jane@example.com."` and `"jane@example.com,"` — the shape a typo
10
- * or a sentence's own full stop produces — both passed too.
11
- */
12
- export declare function isValidEmail(value: string): boolean;
@@ -1,68 +0,0 @@
1
- /**
2
- * Ten stored digits → `"(555) 123-4567"`. `null` / `undefined` / `""` → `"—"`.
3
- *
4
- * A non-empty value that is not exactly ten digits after parsing is returned
5
- * UNCHANGED — the same "show the corruption, don't hide it behind absence"
6
- * rule `formatDate` documents. A stored value should already be `parsePhone`'s
7
- * output; if it is not, that is a data problem worth seeing in the row, not
8
- * a blank field that looks like nobody ever entered a number.
9
- *
10
- * Reuses `formatPhonePartial` for the ten-digit case (SG-909 review) rather
11
- * than repeating the same three-slice punctuation a second time — passing it
12
- * exactly ten digits always produces the identical `"(XXX) XXX-XXXX"` string,
13
- * since `formatPhonePartial` only ever appends a raw, unformatted tail past
14
- * the tenth digit and there is no tail here.
15
- */
16
- export declare function formatPhone(value: string | null | undefined): string;
17
- /**
18
- * A human-typed phone number → ten stored digits, or `null`.
19
- *
20
- * Strips everything but digits, so `"(555) 123-4567"`, `"555.123.4567"`,
21
- * `"555-123-4567 "` and `"5551234567"` all normalise the same way. A leading
22
- * US country code (`"1"`, making 11 digits total) is dropped — `"+1 (555)
23
- * 123-4567"` is the same number as `"(555) 123-4567"` and should be stored
24
- * identically. Anything that is not exactly 10 digits after that — too few,
25
- * too many, or an 11-digit number NOT starting with `1` (a foreign number
26
- * mis-typed into a US field, not a US number with an extra digit) — returns
27
- * `null` rather than truncating or padding a guess into place.
28
- *
29
- * THIS is the one place in the file the 11-digit-leading-`1` rule is written
30
- * (SG-909 review — it used to also live in `digitsOfPhoneInProgress`, which
31
- * no longer transforms digits at all; see that function's own doc for why).
32
- */
33
- export declare function parsePhone(input: string): string | null;
34
- /**
35
- * Every non-digit stripped — nothing else. `PhoneField` (SG-909) keeps this
36
- * as ITS state while a person is still typing.
37
- *
38
- * Deliberately NOT capped at ten and NOT country-code-aware, unlike an
39
- * earlier revision of this function. That revision silently dropped every
40
- * digit past the tenth and stripped a leading `"1"` off an 11-digit run —
41
- * which meant pasting `"555-123-4567 x12"` or `"44 20 7946 0958"` (a UK
42
- * number) landed at commit as `parsePhone` accepting whatever ten-or-eleven
43
- * digits happened to survive the cap, saving a DIFFERENT phone number than
44
- * the one actually typed, with no error and no visible sign anything had
45
- * been thrown away. `PhoneField` now keeps the full digit sequence — see its
46
- * own module comment for how it is FORMATTED (first ten punctuated, any rest
47
- * appended raw) and how `parsePhone` alone decides, at commit, whether the
48
- * full sequence resolves to a real ten-digit number.
49
- */
50
- export declare function digitsOfPhoneInProgress(input: string): string;
51
- /**
52
- * A digit sequence of any length → what the box shows WHILE TYPING —
53
- * progressively punctuated as each of the first ten digits lands, with any
54
- * digit past the tenth appended after a space, UNFORMATTED, rather than
55
- * silently dropped (SG-909 review). `formatPhone` above is the too-late-to-
56
- * use-here sibling: it takes the STORED ten-digit form and either renders it
57
- * or hands back a non-ten-digit value unchanged, which would show a partial
58
- * number completely unpunctuated until the last digit arrived, and would
59
- * have nowhere to put an eleventh digit at all.
60
- *
61
- * The trailing digits past ten are shown, not hidden, specifically so a
62
- * too-long paste or a stray extra keystroke stays visible for the person to
63
- * see and correct — `parsePhone` will refuse anything that is not exactly
64
- * ten digits (or eleven with a leading `1`) at commit, and a refusal against
65
- * a box that visibly still has extra digits in it is legible; a refusal
66
- * against a box that silently ate them is not.
67
- */
68
- export declare function formatPhonePartial(digits: string): string;
@@ -1,6 +0,0 @@
1
- /**
2
- * Whether `value` reads as a plausible web address. An empty (or
3
- * whitespace-only) value is treated as VALID — see `isValidEmail`'s identical
4
- * reasoning.
5
- */
6
- export declare function isValidUrl(value: string): boolean;