@danxbot/ui 1.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.
Files changed (183) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +126 -0
  3. package/dist/fonts/bricolage-grotesque-0.woff2 +0 -0
  4. package/dist/fonts/bricolage-grotesque-1.woff2 +0 -0
  5. package/dist/fonts/bricolage-grotesque-2.woff2 +0 -0
  6. package/dist/fonts/figtree-0.woff2 +0 -0
  7. package/dist/fonts/figtree-1.woff2 +0 -0
  8. package/dist/fonts/figtree-2.woff2 +0 -0
  9. package/dist/fonts/figtree-3.woff2 +0 -0
  10. package/dist/fonts/jetbrains-mono-0.woff2 +0 -0
  11. package/dist/fonts/jetbrains-mono-1.woff2 +0 -0
  12. package/dist/fonts/jetbrains-mono-10.woff2 +0 -0
  13. package/dist/fonts/jetbrains-mono-11.woff2 +0 -0
  14. package/dist/fonts/jetbrains-mono-2.woff2 +0 -0
  15. package/dist/fonts/jetbrains-mono-3.woff2 +0 -0
  16. package/dist/fonts/jetbrains-mono-4.woff2 +0 -0
  17. package/dist/fonts/jetbrains-mono-5.woff2 +0 -0
  18. package/dist/fonts/jetbrains-mono-6.woff2 +0 -0
  19. package/dist/fonts/jetbrains-mono-7.woff2 +0 -0
  20. package/dist/fonts/jetbrains-mono-8.woff2 +0 -0
  21. package/dist/fonts/jetbrains-mono-9.woff2 +0 -0
  22. package/dist/fonts.css +187 -0
  23. package/dist/index.js +42425 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/styles.css +190 -0
  26. package/dist/types/components/Accordion.d.ts +15 -0
  27. package/dist/types/components/AppShell.d.ts +58 -0
  28. package/dist/types/components/Avatar.d.ts +154 -0
  29. package/dist/types/components/Badge.d.ts +73 -0
  30. package/dist/types/components/Button.d.ts +103 -0
  31. package/dist/types/components/Card.d.ts +193 -0
  32. package/dist/types/components/Choice.d.ts +112 -0
  33. package/dist/types/components/CodeEditor.d.ts +86 -0
  34. package/dist/types/components/Combobox.d.ts +37 -0
  35. package/dist/types/components/CommandPalette.d.ts +33 -0
  36. package/dist/types/components/DatePicker.d.ts +20 -0
  37. package/dist/types/components/Dialog.d.ts +117 -0
  38. package/dist/types/components/DragDrop.d.ts +60 -0
  39. package/dist/types/components/ErrorBoundary.d.ts +16 -0
  40. package/dist/types/components/Field.d.ts +37 -0
  41. package/dist/types/components/FileUpload.d.ts +22 -0
  42. package/dist/types/components/Icon.d.ts +40 -0
  43. package/dist/types/components/Input.d.ts +120 -0
  44. package/dist/types/components/Loading.d.ts +83 -0
  45. package/dist/types/components/MarkdownEditor.d.ts +24 -0
  46. package/dist/types/components/Menu.d.ts +57 -0
  47. package/dist/types/components/Navigation.d.ts +46 -0
  48. package/dist/types/components/NumberInput.d.ts +88 -0
  49. package/dist/types/components/OTPInput.d.ts +11 -0
  50. package/dist/types/components/Panel.d.ts +94 -0
  51. package/dist/types/components/Popover.d.ts +64 -0
  52. package/dist/types/components/Progress.d.ts +178 -0
  53. package/dist/types/components/Select.d.ts +53 -0
  54. package/dist/types/components/Slider.d.ts +203 -0
  55. package/dist/types/components/Spinner.d.ts +29 -0
  56. package/dist/types/components/Stat.d.ts +98 -0
  57. package/dist/types/components/StatusSelect.d.ts +23 -0
  58. package/dist/types/components/Surface.d.ts +110 -0
  59. package/dist/types/components/Table.d.ts +46 -0
  60. package/dist/types/components/Tabs.d.ts +84 -0
  61. package/dist/types/components/ThemeMenu.d.ts +4 -0
  62. package/dist/types/components/Toast.d.ts +46 -0
  63. package/dist/types/components/Toggle.d.ts +65 -0
  64. package/dist/types/components/Tree.d.ts +20 -0
  65. package/dist/types/components/calendar/CalendarMonth.d.ts +33 -0
  66. package/dist/types/components/calendar/CalendarTimeGrid.d.ts +75 -0
  67. package/dist/types/components/calendar/EventActions.d.ts +17 -0
  68. package/dist/types/components/calendar/format.d.ts +43 -0
  69. package/dist/types/components/calendar/index.d.ts +9 -0
  70. package/dist/types/components/calendar/palette.d.ts +17 -0
  71. package/dist/types/components/calendar/use-calendar-drag.d.ts +54 -0
  72. package/dist/types/components/calendar/use-event-keyboard.d.ts +24 -0
  73. package/dist/types/components/calendar/use-grid-navigation.d.ts +47 -0
  74. package/dist/types/components/calendar/use-now.d.ts +20 -0
  75. package/dist/types/components/chat/Attachment.d.ts +49 -0
  76. package/dist/types/components/chat/Chat.d.ts +60 -0
  77. package/dist/types/components/chat/Composer.d.ts +29 -0
  78. package/dist/types/components/chat/ContextMeter.d.ts +55 -0
  79. package/dist/types/components/chat/EffortControl.d.ts +23 -0
  80. package/dist/types/components/chat/Markdown.d.ts +22 -0
  81. package/dist/types/components/chat/Message.d.ts +59 -0
  82. package/dist/types/components/chat/MessageScroller.d.ts +13 -0
  83. package/dist/types/components/chat/ModelSelector.d.ts +44 -0
  84. package/dist/types/components/chat/types.d.ts +155 -0
  85. package/dist/types/components/code-editor/context.d.ts +32 -0
  86. package/dist/types/components/code-editor/editing.d.ts +39 -0
  87. package/dist/types/components/code-editor/highlight.d.ts +20 -0
  88. package/dist/types/components/code-editor/recipe.d.ts +109 -0
  89. package/dist/types/components/code-editor/state.d.ts +14 -0
  90. package/dist/types/components/drag-drop/context.d.ts +45 -0
  91. package/dist/types/components/drag-drop/recipe.d.ts +121 -0
  92. package/dist/types/components/drag-drop/shift.d.ts +66 -0
  93. package/dist/types/components/markdown/Affordances.d.ts +76 -0
  94. package/dist/types/components/rbac/AccountMenu.d.ts +8 -0
  95. package/dist/types/components/rbac/DevToolsPopover.d.ts +5 -0
  96. package/dist/types/components/rbac/ProfilePage.d.ts +1 -0
  97. package/dist/types/components/rbac/RBACProvider.d.ts +64 -0
  98. package/dist/types/components/rbac/RolePermissionMatrix.d.ts +6 -0
  99. package/dist/types/components/rbac/RolesPermissionsPage.d.ts +1 -0
  100. package/dist/types/components/rbac/index.d.ts +7 -0
  101. package/dist/types/components/rbac/types.d.ts +26 -0
  102. package/dist/types/components/roadmap/PhaseManager.d.ts +19 -0
  103. package/dist/types/components/roadmap/RoadmapItemCard.d.ts +45 -0
  104. package/dist/types/components/roadmap/RoadmapPage.d.ts +9 -0
  105. package/dist/types/components/roadmap/RoadmapSwimlaneBoard.d.ts +9 -0
  106. package/dist/types/components/roadmap/UseCaseCard.d.ts +14 -0
  107. package/dist/types/components/roadmap/UseCaseLedgerPage.d.ts +21 -0
  108. package/dist/types/components/roadmap/chip-tones.d.ts +2 -0
  109. package/dist/types/components/roadmap/derive.d.ts +12 -0
  110. package/dist/types/components/roadmap/index.d.ts +9 -0
  111. package/dist/types/components/roadmap/types.d.ts +54 -0
  112. package/dist/types/icons/data.d.ts +1318 -0
  113. package/dist/types/index.d.ts +97 -0
  114. package/dist/types/lib/calendar/band-packer.d.ts +53 -0
  115. package/dist/types/lib/calendar/drag.d.ts +125 -0
  116. package/dist/types/lib/calendar/index.d.ts +4 -0
  117. package/dist/types/lib/calendar/lane-packer.d.ts +88 -0
  118. package/dist/types/lib/calendar/segments.d.ts +91 -0
  119. package/dist/types/lib/calendar/types.d.ts +166 -0
  120. package/dist/types/lib/cn.d.ts +7 -0
  121. package/dist/types/lib/dnd/announce.d.ts +132 -0
  122. package/dist/types/lib/dnd/autoscroll.d.ts +88 -0
  123. package/dist/types/lib/dnd/geometry.d.ts +78 -0
  124. package/dist/types/lib/dnd/index.d.ts +16 -0
  125. package/dist/types/lib/dnd/sensors/gesture.d.ts +37 -0
  126. package/dist/types/lib/dnd/sensors/keyboard.d.ts +50 -0
  127. package/dist/types/lib/dnd/sensors/pointer.d.ts +59 -0
  128. package/dist/types/lib/dnd/session.d.ts +99 -0
  129. package/dist/types/lib/dnd/types.d.ts +162 -0
  130. package/dist/types/lib/dnd/use-drag.d.ts +56 -0
  131. package/dist/types/lib/icons.d.ts +40 -0
  132. package/dist/types/lib/markdown/caret-map.d.ts +48 -0
  133. package/dist/types/lib/markdown/caret.d.ts +6 -0
  134. package/dist/types/lib/markdown/commands.d.ts +170 -0
  135. package/dist/types/lib/markdown/convert.d.ts +82 -0
  136. package/dist/types/lib/markdown/dom.d.ts +67 -0
  137. package/dist/types/lib/markdown/edit.d.ts +16 -0
  138. package/dist/types/lib/markdown/history.d.ts +47 -0
  139. package/dist/types/lib/markdown/hotkeys.d.ts +39 -0
  140. package/dist/types/lib/markdown/input.d.ts +15 -0
  141. package/dist/types/lib/markdown/keys.d.ts +34 -0
  142. package/dist/types/lib/markdown/paste.d.ts +9 -0
  143. package/dist/types/lib/markdown/position.d.ts +43 -0
  144. package/dist/types/lib/markdown/project.d.ts +88 -0
  145. package/dist/types/lib/markdown/reconcile.d.ts +63 -0
  146. package/dist/types/lib/markdown/surface.d.ts +177 -0
  147. package/dist/types/lib/persist.d.ts +40 -0
  148. package/dist/types/lib/preferences.d.ts +80 -0
  149. package/dist/types/lib/sim/createSimStore.d.ts +18 -0
  150. package/dist/types/lib/sim/index.d.ts +5 -0
  151. package/dist/types/lib/sim/latency.d.ts +10 -0
  152. package/dist/types/lib/sim/registry.d.ts +14 -0
  153. package/dist/types/lib/sim/settings.d.ts +11 -0
  154. package/dist/types/lib/sim/types.d.ts +3 -0
  155. package/dist/types/lib/syntax/index.d.ts +16 -0
  156. package/dist/types/lib/syntax/languages/bash.d.ts +1 -0
  157. package/dist/types/lib/syntax/languages/css.d.ts +1 -0
  158. package/dist/types/lib/syntax/languages/html.d.ts +17 -0
  159. package/dist/types/lib/syntax/languages/index.d.ts +33 -0
  160. package/dist/types/lib/syntax/languages/javascript.d.ts +22 -0
  161. package/dist/types/lib/syntax/languages/json.d.ts +1 -0
  162. package/dist/types/lib/syntax/languages/mongodb.d.ts +1 -0
  163. package/dist/types/lib/syntax/languages/plain.d.ts +9 -0
  164. package/dist/types/lib/syntax/languages/sql.d.ts +4 -0
  165. package/dist/types/lib/syntax/languages/vue.d.ts +1 -0
  166. package/dist/types/lib/syntax/languages/yaml.d.ts +1 -0
  167. package/dist/types/lib/syntax/markdown/frames.d.ts +145 -0
  168. package/dist/types/lib/syntax/markdown/grammar.d.ts +1 -0
  169. package/dist/types/lib/syntax/markdown/index.d.ts +4 -0
  170. package/dist/types/lib/syntax/markdown/inline.d.ts +21 -0
  171. package/dist/types/lib/syntax/markdown/parse.d.ts +11 -0
  172. package/dist/types/lib/syntax/markdown/render.d.ts +19 -0
  173. package/dist/types/lib/syntax/markdown/spans.d.ts +84 -0
  174. package/dist/types/lib/syntax/markdown/types.d.ts +108 -0
  175. package/dist/types/lib/syntax/registry.d.ts +37 -0
  176. package/dist/types/lib/syntax/tokenize.d.ts +17 -0
  177. package/dist/types/lib/syntax/types.d.ts +119 -0
  178. package/dist/types/lib/time/index.d.ts +3 -0
  179. package/dist/types/lib/time/plain.d.ts +61 -0
  180. package/dist/types/lib/time/types.d.ts +87 -0
  181. package/dist/types/lib/time/zone.d.ts +97 -0
  182. package/dist/types/lib/use-media-query.d.ts +29 -0
  183. package/package.json +130 -0
@@ -0,0 +1,119 @@
1
+ /**
2
+ * The token contract. Every grammar in this system produces this shape and
3
+ * nothing else — the highlighter, the editor overlay, the markdown renderer and
4
+ * the tests all read it.
5
+ *
6
+ * WHY A FLAT TOKEN LIST AND NOT AN HTML STRING. The obvious design (and the one
7
+ * the Vue original uses) is `highlight(code) -> "<span class=…>…"`, one function
8
+ * per language. It cannot do the two things this component exists to do:
9
+ *
10
+ * 1. EDITING. The editor is a transparent `<textarea>` sitting exactly on top
11
+ * of a `<pre>` of the same text. That only works if the rendered text is
12
+ * character-for-character the source — same characters, same order, same
13
+ * length. A list of offsets into the original string makes that checkable;
14
+ * a string of markup makes it a promise nobody can verify.
15
+ * 2. NESTING. A fenced code block inside markdown, or `<style>` inside a Vue
16
+ * SFC, is a region of one language inside another. With offsets, an inner
17
+ * grammar's tokens splice into the outer stream and everything downstream
18
+ * is unaware anything happened. With strings you are concatenating markup
19
+ * and hoping the escaping survives.
20
+ *
21
+ * The invariant that makes both work, asserted by `tokenize`'s own tests:
22
+ * tokens are non-overlapping, ascending, and cover the whole input with no
23
+ * gaps. `src.slice(t.start, t.end)` joined over every token IS the source.
24
+ */
25
+ /**
26
+ * Token categories. Deliberately a closed set: each one maps to exactly one CSS
27
+ * custom property in `src/styles/syntax.css`, so a language cannot invent a
28
+ * colour, and adding a category is a visible, one-place decision.
29
+ *
30
+ * Named for ROLE rather than for any one language's grammar — `property` covers
31
+ * a JSON key, a CSS declaration name and a JS object key, because all three are
32
+ * "the name on the left" and should read the same way in every language.
33
+ */
34
+ export type TokenType = "text" | "comment" | "punctuation" | "operator" | "string" | "escape" | "number" | "boolean" | "null" | "regex" | "keyword" | "property" | "variable" | "function" | "type" | "constant" | "tag" | "attribute" | "selector" | "atrule" | "heading" | "emphasis" | "strong" | "strike" | "link" | "url" | "marker" | "quote" | "invalid";
35
+ /** A run of source text with one category. Half-open range: `[start, end)`. */
36
+ export interface Token {
37
+ /** Offset into the ORIGINAL source string, never into a nested substring. */
38
+ start: number;
39
+ end: number;
40
+ type: TokenType;
41
+ /**
42
+ * The grammar that produced this token. An embedded region carries the INNER
43
+ * language's name, which is what lets a consumer style a fenced block
44
+ * differently from the markdown around it — and what makes a nesting bug
45
+ * visible in a test rather than merely wrong on screen.
46
+ */
47
+ lang: string;
48
+ }
49
+ /**
50
+ * One scanning rule, tried in order at the current position.
51
+ *
52
+ * `match` MUST carry the sticky flag. A non-sticky regex searches forward from
53
+ * the position and can match text the scanner has not reached, silently
54
+ * swallowing the characters in between — the failure looks like "highlighting
55
+ * is slightly off" and is very hard to trace back. `defineGrammar` throws on a
56
+ * non-sticky pattern rather than letting that ship.
57
+ */
58
+ export interface Rule {
59
+ match: RegExp;
60
+ /** Category for the entire match. Mutually exclusive with `groups`. */
61
+ token?: TokenType;
62
+ /**
63
+ * Category per capture group, for a rule that matches several things at once
64
+ * (`key` `:` in JSON, `<` `div` in HTML). `null` leaves a group as plain
65
+ * text. Anything between groups is emitted as `text`, so coverage holds.
66
+ */
67
+ groups?: (TokenType | null)[];
68
+ /** Enter another state of the SAME grammar (a string body, a comment). */
69
+ push?: string;
70
+ /** Leave the current state. Applied after the token is emitted. */
71
+ pop?: true;
72
+ /**
73
+ * Enter ANOTHER grammar for the region that follows, until `until` matches.
74
+ * A string names it outright (`<style>` -> css); a function reads it off the
75
+ * match, which is how a fence takes its language from its own info string and
76
+ * how `<script lang="ts">` differs from `<script>`.
77
+ *
78
+ * Returning null (unknown language) is not an error — the region is scanned
79
+ * as plain text and still terminates correctly at `until`. An unrecognised
80
+ * language must never break the document containing it.
81
+ */
82
+ embed?: string | ((match: RegExpExecArray) => string | null);
83
+ /** Required with `embed`: the pattern that ends the embedded region. */
84
+ until?: RegExp;
85
+ /** Category for the terminator itself. Defaults to `punctuation`. */
86
+ untilToken?: TokenType;
87
+ }
88
+ /**
89
+ * A language. `states.root` is the entry point; other states are pushed by
90
+ * rules. Most grammars need only `root` plus a state per multi-line construct.
91
+ */
92
+ export interface Grammar {
93
+ name: string;
94
+ aliases?: readonly string[];
95
+ states: Record<string, Rule[]>;
96
+ /**
97
+ * Full override for a language the rule stack genuinely cannot express.
98
+ * Markdown is the only one: its structure is by BLOCK (a list item's content
99
+ * is decided by indentation relative to its marker, several lines later),
100
+ * which no positional rule stack can see. It parses properly and emits this
101
+ * same token shape, so every consumer stays unaware of the difference.
102
+ *
103
+ * A grammar with `tokenize` may leave `states` empty.
104
+ */
105
+ tokenize?: (source: string, ctx: TokenizeContext) => Token[];
106
+ }
107
+ /**
108
+ * Handed to a `tokenize` override so it can highlight regions of other
109
+ * languages — a fenced block, YAML front matter — without importing the
110
+ * registry itself and creating a cycle.
111
+ */
112
+ export interface TokenizeContext {
113
+ /**
114
+ * Tokenize `source` as `language`, with every offset shifted by `offset` so
115
+ * the result splices into the caller's stream. An unknown language yields one
116
+ * `text` token, never an error.
117
+ */
118
+ sub(source: string, language: string | null, offset: number): Token[];
119
+ }
@@ -0,0 +1,3 @@
1
+ export { AmbiguousTimeError, isoDateString, isoDateTimeString, type CalendarDuration, type Disambiguation, type Instant, type PlainDate, type PlainDateTime, type TimeZone, } from "./types";
2
+ export { addDuration, dayFraction, dayLengthMs, hoursInDay, instantAtFraction, instantToPlainDate, instantToPlainDateTime, nextDay, offsetAt, plainDateTimeToInstant, startOfDay, } from "./zone";
3
+ export { addDays, addMonths, atMidnight, atTime, comparePlainDate, dayOfWeek, daysBetween, daysInMonth, endOfMonth, isSameDate, monthGridDays, parsePlainDate, startOfMonth, startOfWeek, weekDays, } from "./plain";
@@ -0,0 +1,61 @@
1
+ import { isoDateString, type PlainDate, type PlainDateTime } from "./types";
2
+ /** Days in `month` of `year`, leap years included. */
3
+ export declare function daysInMonth(year: number, month: number): number;
4
+ /** `date` moved by `days`, which may be negative, rolling months and years. */
5
+ export declare function addDays(date: PlainDate, days: number): PlainDate;
6
+ /**
7
+ * `date` moved by `months`, clamping the day to the target month's length.
8
+ *
9
+ * CLAMPING, NOT ROLLING: one month after the 31st of January is the 28th or
10
+ * 29th of February, never the 3rd of March. Rolling is what `Date.setMonth`
11
+ * does natively and it is why "next month" buttons skip February.
12
+ */
13
+ export declare function addMonths(date: PlainDate, months: number): PlainDate;
14
+ /** Whole days from `a` to `b`; negative when `b` is earlier. */
15
+ export declare function daysBetween(a: PlainDate, b: PlainDate): number;
16
+ /** Negative when `a` is earlier, 0 when equal, positive when later. */
17
+ export declare function comparePlainDate(a: PlainDate, b: PlainDate): number;
18
+ export declare function isSameDate(a: PlainDate, b: PlainDate): boolean;
19
+ /** 0 = Sunday … 6 = Saturday, matching `Date.getUTCDay` and `Intl`'s weekday order. */
20
+ export declare function dayOfWeek(date: PlainDate): number;
21
+ /**
22
+ * The first day of the week `date` falls in.
23
+ *
24
+ * `weekStartsOn` IS A PARAMETER WITH NO DEFAULT ANYWHERE UP THE STACK, because
25
+ * there is no correct global answer: Sunday in the US and Japan, Monday across
26
+ * Europe and by ISO 8601, Saturday in much of the Middle East. A component that
27
+ * picks one silently is wrong for most of the world, so the calendar surfaces
28
+ * it and this function simply obeys.
29
+ */
30
+ export declare function startOfWeek(date: PlainDate, weekStartsOn: number): PlainDate;
31
+ /** The 1st of `date`'s month. */
32
+ export declare function startOfMonth(date: PlainDate): PlainDate;
33
+ /** The last day of `date`'s month. */
34
+ export declare function endOfMonth(date: PlainDate): PlainDate;
35
+ /**
36
+ * Every day a month grid shows, INCLUDING the leading and trailing days that
37
+ * belong to the neighbouring months.
38
+ *
39
+ * Always whole weeks, so the result is a multiple of seven and the grid never
40
+ * has a ragged edge. The count varies — a 28-day February beginning on the
41
+ * week's first day needs four rows, and a 31-day month beginning on its last
42
+ * day needs six. Callers that assume six rows draw an empty one eleven months
43
+ * a year; callers that assume five are simply wrong twice a year.
44
+ */
45
+ export declare function monthGridDays(date: PlainDate, weekStartsOn: number): PlainDate[];
46
+ /** The seven days of the week `date` falls in. */
47
+ export declare function weekDays(date: PlainDate, weekStartsOn: number): PlainDate[];
48
+ /**
49
+ * Parse `YYYY-MM-DD`.
50
+ *
51
+ * FAILS LOUDLY on anything else, including the shapes `Date` accepts and
52
+ * silently reinterprets. `new Date("2026-2-30")` yields the 2nd of March, which
53
+ * is a data error becoming a rendered event on the wrong day with nothing
54
+ * anywhere reporting a problem.
55
+ */
56
+ export declare function parsePlainDate(iso: string): PlainDate;
57
+ export { isoDateString };
58
+ /** A `PlainDateTime` at midnight on `date` — the wall reading, not an instant. */
59
+ export declare function atMidnight(date: PlainDate): PlainDateTime;
60
+ /** A `PlainDateTime` at `hour`:`minute` on `date`. */
61
+ export declare function atTime(date: PlainDate, hour: number, minute?: number): PlainDateTime;
@@ -0,0 +1,87 @@
1
+ /**
2
+ * A point on the timeline, as milliseconds since the epoch.
3
+ *
4
+ * NOT a `Date`. A `Date` is a mutable object that prints itself in the host's
5
+ * local zone, and every calendar bug in the survey behind this component
6
+ * involved someone reading a `Date`'s local fields when they meant a specific
7
+ * zone's. A number cannot be misread that way — it has no fields to read.
8
+ */
9
+ export type Instant = number;
10
+ /** An IANA time zone identifier, e.g. `"America/New_York"`. */
11
+ export type TimeZone = string;
12
+ /**
13
+ * A calendar day. No time, no zone, no offset — just which square on the wall.
14
+ *
15
+ * `month` IS ONE-BASED, matching `Temporal` and matching how every human writes
16
+ * a date. `Date`'s zero-based month is the single most common off-by-one in
17
+ * date code and it is not reproduced here.
18
+ */
19
+ export interface PlainDate {
20
+ readonly year: number;
21
+ /** 1–12. */
22
+ readonly month: number;
23
+ /** 1–31. */
24
+ readonly day: number;
25
+ }
26
+ /**
27
+ * A wall-clock reading. What a clock on the wall says, with no claim about
28
+ * which wall.
29
+ *
30
+ * This is the type that makes the ambiguity explicit rather than accidental:
31
+ * `2026-11-01T01:30` in New York happened TWICE, and `2026-03-08T02:30` never
32
+ * happened at all. A `PlainDateTime` can represent both, which is precisely why
33
+ * turning one into an `Instant` requires saying what to do about it.
34
+ */
35
+ export interface PlainDateTime extends PlainDate {
36
+ /** 0–23. */
37
+ readonly hour: number;
38
+ /** 0–59. */
39
+ readonly minute: number;
40
+ /** 0–59. */
41
+ readonly second: number;
42
+ /** 0–999. */
43
+ readonly millisecond: number;
44
+ }
45
+ /**
46
+ * How much to move, in CALENDAR units rather than elapsed time.
47
+ *
48
+ * THE DISTINCTION IS THE WHOLE POINT, and getting it wrong is the bug in every
49
+ * library surveyed. "One day later" is not "86,400,000 ms later": across a
50
+ * spring-forward boundary it is 23 hours, and across a fall-back it is 25. A
51
+ * user dragging an event from Saturday to Sunday expects it to keep its
52
+ * wall-clock time, so the move has to be expressed as `{ days: 1 }` and
53
+ * resolved against the zone — never added as a number.
54
+ *
55
+ * `hours` and `minutes` ARE exact elapsed time, and that is correct: dragging
56
+ * an event down by two hours means two hours of real duration.
57
+ */
58
+ export interface CalendarDuration {
59
+ readonly days?: number;
60
+ readonly hours?: number;
61
+ readonly minutes?: number;
62
+ }
63
+ /**
64
+ * What to do when a wall-clock reading does not name exactly one instant.
65
+ *
66
+ * Spelled as `Temporal.ZonedDateTime.from`'s option of the same name, with the
67
+ * same meanings, so this is one more thing that becomes a deletion later.
68
+ *
69
+ * - `compatible` — what every other date library does, and the default.
70
+ * In a GAP (spring forward) move forward by the size of the gap; in an
71
+ * OVERLAP (fall back) take the first of the two.
72
+ * - `earlier` / `later` — take that side explicitly.
73
+ * - `reject` — throw. For a parser or an import, where a time that never
74
+ * existed is a fact about bad input rather than something to paper over.
75
+ */
76
+ export type Disambiguation = "compatible" | "earlier" | "later" | "reject";
77
+ /** Thrown by `reject` disambiguation, and never by anything else. */
78
+ export declare class AmbiguousTimeError extends Error {
79
+ readonly wall: PlainDateTime;
80
+ readonly zone: TimeZone;
81
+ readonly kind: "gap" | "overlap";
82
+ constructor(wall: PlainDateTime, zone: TimeZone, kind: "gap" | "overlap");
83
+ }
84
+ /** `2026-03-08T02:30:00.000` — used in errors, and by the ISO helpers. */
85
+ export declare function isoDateTimeString(wall: PlainDateTime): string;
86
+ /** `2026-03-08`. */
87
+ export declare function isoDateString(date: PlainDate): string;
@@ -0,0 +1,97 @@
1
+ import { type Disambiguation, type Instant, type PlainDate, type PlainDateTime, type TimeZone } from "./types";
2
+ /** The wall-clock reading in `zone` at `instant`. */
3
+ export declare function instantToPlainDateTime(zone: TimeZone, instant: Instant): PlainDateTime;
4
+ /**
5
+ * `zone`'s offset from UTC at `instant`, in milliseconds. East is positive.
6
+ *
7
+ * THE ONE PRIMITIVE. Read by asking the browser what the wall clock says at
8
+ * that instant and subtracting: if it is 07:00 UTC and the clock in New York
9
+ * reads 02:00, the offset is −5 hours. No table, no parsing of a zone name, no
10
+ * assumption that an offset is a whole number of hours — `Pacific/Chatham` sits
11
+ * at +12:45, and `Asia/Kathmandu` at +5:45.
12
+ */
13
+ export declare function offsetAt(zone: TimeZone, instant: Instant): number;
14
+ /**
15
+ * The instant at which `zone`'s clock reads `wall`.
16
+ *
17
+ * See `Disambiguation` for what happens when that is not exactly one instant.
18
+ * The default is `compatible`, which is what `Temporal` and every other date
19
+ * library do, so the surprising cases are the ones you have to ask for.
20
+ */
21
+ export declare function plainDateTimeToInstant(zone: TimeZone, wall: PlainDateTime, disambiguation?: Disambiguation): Instant;
22
+ /** The calendar day `instant` falls on, in `zone`. */
23
+ export declare function instantToPlainDate(zone: TimeZone, instant: Instant): PlainDate;
24
+ /**
25
+ * The first instant of `date` in `zone`.
26
+ *
27
+ * NOT "midnight". In `America/Santiago` on 2026-09-06 the clock jumps from
28
+ * 00:00 to 01:00, so the day's first instant reads 01:00 — and a grid that
29
+ * assumes its own origin is midnight puts every event on that day an hour out.
30
+ * `America/Havana` and `Asia/Beirut` do the same thing on their own dates.
31
+ *
32
+ * Implemented by asking for midnight and, when the clock skipped it, walking
33
+ * forward a minute at a time until a reading exists. The walk is bounded: no
34
+ * transition in the IANA database exceeds two hours, so 180 iterations cannot
35
+ * be reached by real data, and the bound exists to fail loudly rather than spin
36
+ * if that ever stops being true.
37
+ */
38
+ export declare function startOfDay(zone: TimeZone, date: PlainDate): Instant;
39
+ /** The day after `date` on the calendar, ignoring zones entirely. */
40
+ export declare function nextDay(date: PlainDate): PlainDate;
41
+ /**
42
+ * How long `date` actually lasts in `zone`, in milliseconds.
43
+ *
44
+ * Measured as the distance between one day's first instant and the next day's,
45
+ * which is true by construction for every case — 23 hours, 25 hours, the 30
46
+ * minutes of Lord Howe, and a day that starts at 01:00 — with no special case
47
+ * for any of them. That is the entire reason positions in the grid are a RATIO
48
+ * of this number rather than `hour × rowHeight`.
49
+ */
50
+ export declare function dayLengthMs(zone: TimeZone, date: PlainDate): number;
51
+ /**
52
+ * How many hours `date` lasts in `zone` — 23, 24, 25, or 23.5.
53
+ *
54
+ * Fractional by design. `Australia/Lord_Howe` shifts by thirty minutes, so a
55
+ * signature returning an integer would be lying about a real zone, and any
56
+ * caller branching on `=== 23` is already broken.
57
+ */
58
+ export declare function hoursInDay(zone: TimeZone, date: PlainDate): number;
59
+ /**
60
+ * Where `instant` sits within `date`, as a fraction from 0 to 1.
61
+ *
62
+ * THE LOAD-BEARING FUNCTION. A 23-hour day compresses and a 25-hour day
63
+ * stretches with no branch anywhere, because the divisor is the day's real
64
+ * length. Values outside 0–1 mean the instant is not on this day and are
65
+ * returned rather than clamped — the layout core needs to know by how much in
66
+ * order to clip a multi-day span.
67
+ */
68
+ export declare function dayFraction(zone: TimeZone, date: PlainDate, instant: Instant): number;
69
+ /**
70
+ * The exact inverse of `dayFraction`.
71
+ *
72
+ * IT MUST BE EXACT, and that is not a stylistic preference. Rendering maps an
73
+ * instant to a position and hit-testing maps a position back to an instant; if
74
+ * the two disagree by even a rounding step, an event lands one slot away from
75
+ * where it was dropped. FullCalendar's Australia selection bug is exactly this
76
+ * pair drifting apart. `dayFraction(z, d, instantAtFraction(z, d, f)) === f`
77
+ * for every zone in the corpus, and there is a test that says so.
78
+ */
79
+ export declare function instantAtFraction(zone: TimeZone, date: PlainDate, fraction: number): Instant;
80
+ /**
81
+ * Move `instant` by a CALENDAR duration.
82
+ *
83
+ * Days are applied on the calendar and then re-anchored to the same wall-clock
84
+ * time, so an event dragged from Saturday to Sunday across a transition keeps
85
+ * reading 09:00 rather than becoming 08:00 or 10:00. Hours and minutes are
86
+ * applied afterwards as exact elapsed time, because dragging an event down the
87
+ * grid by two hours does mean two hours.
88
+ *
89
+ * ORDER MATTERS AND IS FIXED: days first, then time. The other order makes
90
+ * "one day and two hours later" depend on which side of a transition the
91
+ * intermediate value happened to land on.
92
+ */
93
+ export declare function addDuration(zone: TimeZone, instant: Instant, duration: {
94
+ days?: number;
95
+ hours?: number;
96
+ minutes?: number;
97
+ }, disambiguation?: Disambiguation): Instant;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Subscribes to a CSS media query and re-renders when it changes.
3
+ *
4
+ * WHY A HOOK AND NOT A CSS CLASS. Almost everything responsive in this system
5
+ * belongs in CSS, where it costs nothing and works before hydration. This
6
+ * exists for the case CSS cannot reach: a layout whose measurements are written
7
+ * as INLINE STYLE from application state — a resizable panel group being the
8
+ * one that matters here. A utility class cannot override `style="flex-grow:3"`,
9
+ * so the component has to know the width to write a different value.
10
+ *
11
+ * Reach for a `lg:` variant first. This is the exception, not the pattern.
12
+ *
13
+ * `useSyncExternalStore` rather than `useState` + `useEffect`: it reads the
14
+ * value during render on the client and returns the server snapshot during SSR,
15
+ * so there is no first paint at the wrong breakpoint and no hydration mismatch
16
+ * warning. The effect version renders once with a guess and then corrects
17
+ * itself, which is a visible layout jump on exactly the devices this is for.
18
+ */
19
+ export declare function useMediaQuery(query: string, serverFallback?: boolean): boolean;
20
+ /** Tailwind's own breakpoints, so a JS check and a `lg:` class agree. */
21
+ export declare const BREAKPOINTS: {
22
+ readonly sm: 640;
23
+ readonly md: 768;
24
+ readonly lg: 1024;
25
+ readonly xl: 1280;
26
+ };
27
+ export type Breakpoint = keyof typeof BREAKPOINTS;
28
+ /** True below the named breakpoint — the JS twin of `max-<bp>:`. */
29
+ export declare function useBelow(breakpoint: Breakpoint, serverFallback?: boolean): boolean;
package/package.json ADDED
@@ -0,0 +1,130 @@
1
+ {
2
+ "name": "@danxbot/ui",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "Danxbot — a domain-agnostic React design system with motion as a first-class primitive.",
6
+ "license": "MIT",
7
+ "author": "Dan Newman",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/newms87/danxbot.git",
11
+ "directory": "design-system"
12
+ },
13
+ "bugs": "https://github.com/newms87/danxbot/issues",
14
+ "keywords": [
15
+ "react",
16
+ "design-system",
17
+ "component-library",
18
+ "tailwindcss",
19
+ "accessible",
20
+ "animation",
21
+ "ui"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "engines": {
27
+ "node": ">=20"
28
+ },
29
+ "module": "./dist/index.js",
30
+ "types": "./dist/types/index.d.ts",
31
+ "sideEffects": [
32
+ "*.css"
33
+ ],
34
+ "exports": {
35
+ ".": {
36
+ "types": "./dist/types/index.d.ts",
37
+ "import": "./dist/index.js"
38
+ },
39
+ "./styles.css": "./dist/styles.css",
40
+ "./fonts.css": "./dist/fonts.css",
41
+ "./package.json": "./package.json"
42
+ },
43
+ "files": [
44
+ "dist"
45
+ ],
46
+ "scripts": {
47
+ "gen:api": "node scripts/gen-api-manifest.mjs",
48
+ "predev": "npm run gen:api",
49
+ "pretypecheck": "npm run gen:api",
50
+ "pretest": "npm run gen:api",
51
+ "prebuild:demo": "npm run gen:api",
52
+ "dev": "vite",
53
+ "typecheck": "tsc --noEmit",
54
+ "typecheck:previews": "tsc -p tsconfig.previews.json",
55
+ "audit:previews": "node scripts/audit-preview-classes.mjs",
56
+ "audit:cards": "node scripts/audit-card-theme.mjs",
57
+ "audit:hover": "node scripts/audit-hover.mjs",
58
+ "test": "vitest run",
59
+ "build:lib": "vite build --config vite.lib.config.ts && node scripts/postbuild-css.mjs && npm run build:types",
60
+ "fonts": "node scripts/fetch-fonts.mjs",
61
+ "icons": "node scripts/build-icons.mjs",
62
+ "build:types": "tsc -p tsconfig.build.json",
63
+ "build:demo": "vite build",
64
+ "build": "npm run build:lib && npm run build:demo",
65
+ "verify": "npm run typecheck && npm run test && npm run build && npm run typecheck:previews",
66
+ "preview": "vite preview",
67
+ "preview:built": "vite preview --outDir demo-dist --port 5801 --strictPort",
68
+ "gates": "npm run shoot && npm run a11y && node scripts/shoot-overlays.mjs && npm run probe",
69
+ "a11y": "node scripts/a11y-scan.mjs",
70
+ "shoot": "node scripts/shoot.mjs",
71
+ "probe": "node scripts/probe-scale.mjs && node scripts/probe-switch.mjs && node scripts/probe-panel.mjs && node scripts/probe-popover-width.mjs && node scripts/probe-api.mjs && node scripts/probe-api-live.mjs",
72
+ "sync": "node scripts/sync.mjs",
73
+ "visual": "node scripts/visual-docker.mjs",
74
+ "visual:update": "node scripts/visual-docker.mjs --update-snapshots",
75
+ "visual:host": "playwright test",
76
+ "visual:report": "playwright show-report",
77
+ "audit:arrows": "node scripts/audit-arrows.mjs",
78
+ "audit:motion": "node scripts/audit-motion.mjs",
79
+ "audit:responsive": "node scripts/audit-responsive.mjs",
80
+ "audit:dnd": "node scripts/audit-dnd.mjs && node scripts/probe-dnd-sensors.mjs && node scripts/probe-dnd-a11y.mjs",
81
+ "audit:axtree": "node scripts/audit-axtree.mjs",
82
+ "audit:mutations": "node scripts/audit-mutations.mjs",
83
+ "audit:palette": "node scripts/audit-palette.mjs",
84
+ "probe:calendar": "node scripts/probe-calendar.mjs",
85
+ "audit": "npm run audit:previews && npm run audit:cards && npm run audit:arrows && npm run audit:axtree && npm run audit:palette && npm run audit:motion && npm run audit:responsive && npm run audit:hover && npm run a11y && npm run probe:calendar && npm run probe:calendar-drag && npm run audit:dnd && npm run probe:markdown",
86
+ "probe:calendar-drag": "node scripts/probe-calendar-drag.mjs",
87
+ "audit:conventions": "node scripts/audit-conventions.mjs",
88
+ "audit:component-exports": "node scripts/audit-component-exports.mjs",
89
+ "probe:markdown": "node scripts/probe-markdown-caret.mjs && node scripts/probe-markdown-component.mjs && node scripts/probe-markdown-affordances.mjs",
90
+ "release": "node --no-deprecation scripts/publish.mjs"
91
+ },
92
+ "peerDependencies": {
93
+ "react": "^19",
94
+ "react-dom": "^19"
95
+ },
96
+ "dependencies": {
97
+ "@base-ui/react": "^1.7.0",
98
+ "@tanstack/react-table": "^8.21.3",
99
+ "clsx": "^2.1.1",
100
+ "tailwind-merge": "^3.3.1",
101
+ "tailwind-variants": "^3.3.1"
102
+ },
103
+ "devDependencies": {
104
+ "@axe-core/playwright": "^4.13.0",
105
+ "@playwright/test": "^1.62.1",
106
+ "@tailwindcss/vite": "^4.1.14",
107
+ "@testing-library/dom": "^10.4.1",
108
+ "@testing-library/react": "^16.3.2",
109
+ "@types/node": "^26.2.0",
110
+ "@types/react": "^19.2.2",
111
+ "@types/react-dom": "^19.2.1",
112
+ "@vitejs/plugin-react": "^5.0.4",
113
+ "axe-core": "^4.13.0",
114
+ "fumadocs-core": "^16.14.5",
115
+ "fumadocs-mdx": "^15.3.0",
116
+ "happy-dom": "^20.11.2",
117
+ "lucide-react": "^0.545.0",
118
+ "playwright": "^1.62.1",
119
+ "react": "^19.2.0",
120
+ "react-dom": "^19.2.0",
121
+ "tailwindcss": "^4.1.14",
122
+ "typescript": "^5.9.3",
123
+ "vite": "^7.1.9",
124
+ "vitest": "^4.1.11",
125
+ "zod": "^4.4.3"
126
+ },
127
+ "allowScripts": {
128
+ "esbuild@0.28.2": true
129
+ }
130
+ }