@hjmds/design-contracts 0.8.2

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 (353) hide show
  1. package/README.md +208 -0
  2. package/dist/alert-dialog.d.ts +102 -0
  3. package/dist/alert-dialog.d.ts.map +1 -0
  4. package/dist/alert-dialog.js +136 -0
  5. package/dist/alert-dialog.js.map +1 -0
  6. package/dist/base-recipes.d.ts +184 -0
  7. package/dist/base-recipes.d.ts.map +1 -0
  8. package/dist/base-recipes.js +129 -0
  9. package/dist/base-recipes.js.map +1 -0
  10. package/dist/behaviors.d.ts +1254 -0
  11. package/dist/behaviors.d.ts.map +1 -0
  12. package/dist/behaviors.js +972 -0
  13. package/dist/behaviors.js.map +1 -0
  14. package/dist/bottom-navigation-defaults.d.ts +13 -0
  15. package/dist/bottom-navigation-defaults.d.ts.map +1 -0
  16. package/dist/bottom-navigation-defaults.js +10 -0
  17. package/dist/bottom-navigation-defaults.js.map +1 -0
  18. package/dist/bottom-navigation.d.ts +114 -0
  19. package/dist/bottom-navigation.d.ts.map +1 -0
  20. package/dist/bottom-navigation.js +223 -0
  21. package/dist/bottom-navigation.js.map +1 -0
  22. package/dist/breadcrumb.d.ts +97 -0
  23. package/dist/breadcrumb.d.ts.map +1 -0
  24. package/dist/breadcrumb.js +99 -0
  25. package/dist/breadcrumb.js.map +1 -0
  26. package/dist/calendar.d.ts +285 -0
  27. package/dist/calendar.d.ts.map +1 -0
  28. package/dist/calendar.js +297 -0
  29. package/dist/calendar.js.map +1 -0
  30. package/dist/card.d.ts +39 -0
  31. package/dist/card.d.ts.map +1 -0
  32. package/dist/card.js +50 -0
  33. package/dist/card.js.map +1 -0
  34. package/dist/carousel.d.ts +180 -0
  35. package/dist/carousel.d.ts.map +1 -0
  36. package/dist/carousel.js +172 -0
  37. package/dist/carousel.js.map +1 -0
  38. package/dist/catalog.d.ts +7158 -0
  39. package/dist/catalog.d.ts.map +1 -0
  40. package/dist/catalog.js +220 -0
  41. package/dist/catalog.js.map +1 -0
  42. package/dist/collection.d.ts +123 -0
  43. package/dist/collection.d.ts.map +1 -0
  44. package/dist/collection.js +211 -0
  45. package/dist/collection.js.map +1 -0
  46. package/dist/color-references.d.ts +46 -0
  47. package/dist/color-references.d.ts.map +1 -0
  48. package/dist/color-references.js +39 -0
  49. package/dist/color-references.js.map +1 -0
  50. package/dist/colors.d.ts +56 -0
  51. package/dist/colors.d.ts.map +1 -0
  52. package/dist/colors.js +90 -0
  53. package/dist/colors.js.map +1 -0
  54. package/dist/command-palette.d.ts +240 -0
  55. package/dist/command-palette.d.ts.map +1 -0
  56. package/dist/command-palette.js +97 -0
  57. package/dist/command-palette.js.map +1 -0
  58. package/dist/component-contracts.d.ts +137 -0
  59. package/dist/component-contracts.d.ts.map +1 -0
  60. package/dist/component-contracts.js +53 -0
  61. package/dist/component-contracts.js.map +1 -0
  62. package/dist/component-definitions.d.ts +135 -0
  63. package/dist/component-definitions.d.ts.map +1 -0
  64. package/dist/component-definitions.js +142 -0
  65. package/dist/component-definitions.js.map +1 -0
  66. package/dist/component-recipes.d.ts +3583 -0
  67. package/dist/component-recipes.d.ts.map +1 -0
  68. package/dist/component-recipes.js +1503 -0
  69. package/dist/component-recipes.js.map +1 -0
  70. package/dist/component-references.d.ts +416 -0
  71. package/dist/component-references.d.ts.map +1 -0
  72. package/dist/component-references.js +140 -0
  73. package/dist/component-references.js.map +1 -0
  74. package/dist/content-state.d.ts +104 -0
  75. package/dist/content-state.d.ts.map +1 -0
  76. package/dist/content-state.js +116 -0
  77. package/dist/content-state.js.map +1 -0
  78. package/dist/counter-badge-recipe.d.ts +80 -0
  79. package/dist/counter-badge-recipe.d.ts.map +1 -0
  80. package/dist/counter-badge-recipe.js +44 -0
  81. package/dist/counter-badge-recipe.js.map +1 -0
  82. package/dist/counter-badge.d.ts +12 -0
  83. package/dist/counter-badge.d.ts.map +1 -0
  84. package/dist/counter-badge.js +21 -0
  85. package/dist/counter-badge.js.map +1 -0
  86. package/dist/data-table.d.ts +203 -0
  87. package/dist/data-table.d.ts.map +1 -0
  88. package/dist/data-table.js +182 -0
  89. package/dist/data-table.js.map +1 -0
  90. package/dist/date-picker.d.ts +268 -0
  91. package/dist/date-picker.d.ts.map +1 -0
  92. package/dist/date-picker.js +168 -0
  93. package/dist/date-picker.js.map +1 -0
  94. package/dist/description-list.d.ts +68 -0
  95. package/dist/description-list.d.ts.map +1 -0
  96. package/dist/description-list.js +85 -0
  97. package/dist/description-list.js.map +1 -0
  98. package/dist/design-system-provider.d.ts +80 -0
  99. package/dist/design-system-provider.d.ts.map +1 -0
  100. package/dist/design-system-provider.js +147 -0
  101. package/dist/design-system-provider.js.map +1 -0
  102. package/dist/evidence.d.ts +49 -0
  103. package/dist/evidence.d.ts.map +1 -0
  104. package/dist/evidence.js +133 -0
  105. package/dist/evidence.js.map +1 -0
  106. package/dist/file-picker.d.ts +183 -0
  107. package/dist/file-picker.d.ts.map +1 -0
  108. package/dist/file-picker.js +224 -0
  109. package/dist/file-picker.js.map +1 -0
  110. package/dist/floating-action-button.d.ts +143 -0
  111. package/dist/floating-action-button.d.ts.map +1 -0
  112. package/dist/floating-action-button.js +149 -0
  113. package/dist/floating-action-button.js.map +1 -0
  114. package/dist/form.d.ts +143 -0
  115. package/dist/form.d.ts.map +1 -0
  116. package/dist/form.js +206 -0
  117. package/dist/form.js.map +1 -0
  118. package/dist/foundations.d.ts +300 -0
  119. package/dist/foundations.d.ts.map +1 -0
  120. package/dist/foundations.js +238 -0
  121. package/dist/foundations.js.map +1 -0
  122. package/dist/grid.d.ts +75 -0
  123. package/dist/grid.d.ts.map +1 -0
  124. package/dist/grid.js +133 -0
  125. package/dist/grid.js.map +1 -0
  126. package/dist/icon-button-recipe.d.ts +99 -0
  127. package/dist/icon-button-recipe.d.ts.map +1 -0
  128. package/dist/icon-button-recipe.js +53 -0
  129. package/dist/icon-button-recipe.js.map +1 -0
  130. package/dist/icon.d.ts +41 -0
  131. package/dist/icon.d.ts.map +1 -0
  132. package/dist/icon.js +147 -0
  133. package/dist/icon.js.map +1 -0
  134. package/dist/image.d.ts +82 -0
  135. package/dist/image.d.ts.map +1 -0
  136. package/dist/image.js +100 -0
  137. package/dist/image.js.map +1 -0
  138. package/dist/index.d.ts +58 -0
  139. package/dist/index.d.ts.map +1 -0
  140. package/dist/index.js +66 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/layout.d.ts +118 -0
  143. package/dist/layout.d.ts.map +1 -0
  144. package/dist/layout.js +118 -0
  145. package/dist/layout.js.map +1 -0
  146. package/dist/link.d.ts +57 -0
  147. package/dist/link.d.ts.map +1 -0
  148. package/dist/link.js +142 -0
  149. package/dist/link.js.map +1 -0
  150. package/dist/load-more.d.ts +64 -0
  151. package/dist/load-more.d.ts.map +1 -0
  152. package/dist/load-more.js +124 -0
  153. package/dist/load-more.js.map +1 -0
  154. package/dist/mentions.d.ts +67 -0
  155. package/dist/mentions.d.ts.map +1 -0
  156. package/dist/mentions.js +107 -0
  157. package/dist/mentions.js.map +1 -0
  158. package/dist/number-field.d.ts +208 -0
  159. package/dist/number-field.d.ts.map +1 -0
  160. package/dist/number-field.js +247 -0
  161. package/dist/number-field.js.map +1 -0
  162. package/dist/otp-field.d.ts +152 -0
  163. package/dist/otp-field.d.ts.map +1 -0
  164. package/dist/otp-field.js +117 -0
  165. package/dist/otp-field.js.map +1 -0
  166. package/dist/pagination.d.ts +181 -0
  167. package/dist/pagination.d.ts.map +1 -0
  168. package/dist/pagination.js +226 -0
  169. package/dist/pagination.js.map +1 -0
  170. package/dist/password-field.d.ts +187 -0
  171. package/dist/password-field.d.ts.map +1 -0
  172. package/dist/password-field.js +120 -0
  173. package/dist/password-field.js.map +1 -0
  174. package/dist/popover.d.ts +152 -0
  175. package/dist/popover.d.ts.map +1 -0
  176. package/dist/popover.js +137 -0
  177. package/dist/popover.js.map +1 -0
  178. package/dist/progress-recipe.d.ts +43 -0
  179. package/dist/progress-recipe.d.ts.map +1 -0
  180. package/dist/progress-recipe.js +16 -0
  181. package/dist/progress-recipe.js.map +1 -0
  182. package/dist/recipes.d.ts +31 -0
  183. package/dist/recipes.d.ts.map +1 -0
  184. package/dist/recipes.js +46 -0
  185. package/dist/recipes.js.map +1 -0
  186. package/dist/responsive.d.ts +27 -0
  187. package/dist/responsive.d.ts.map +1 -0
  188. package/dist/responsive.js +66 -0
  189. package/dist/responsive.js.map +1 -0
  190. package/dist/result.d.ts +111 -0
  191. package/dist/result.d.ts.map +1 -0
  192. package/dist/result.js +97 -0
  193. package/dist/result.js.map +1 -0
  194. package/dist/selection-helpers.d.ts +16 -0
  195. package/dist/selection-helpers.d.ts.map +1 -0
  196. package/dist/selection-helpers.js +52 -0
  197. package/dist/selection-helpers.js.map +1 -0
  198. package/dist/semantic-colors.d.ts +275 -0
  199. package/dist/semantic-colors.d.ts.map +1 -0
  200. package/dist/semantic-colors.js +84 -0
  201. package/dist/semantic-colors.js.map +1 -0
  202. package/dist/sheet.d.ts +51 -0
  203. package/dist/sheet.d.ts.map +1 -0
  204. package/dist/sheet.js +69 -0
  205. package/dist/sheet.js.map +1 -0
  206. package/dist/showcase.d.ts +153 -0
  207. package/dist/showcase.d.ts.map +1 -0
  208. package/dist/showcase.js +210 -0
  209. package/dist/showcase.js.map +1 -0
  210. package/dist/side-panel.d.ts +199 -0
  211. package/dist/side-panel.d.ts.map +1 -0
  212. package/dist/side-panel.js +111 -0
  213. package/dist/side-panel.js.map +1 -0
  214. package/dist/slider.d.ts +138 -0
  215. package/dist/slider.d.ts.map +1 -0
  216. package/dist/slider.js +150 -0
  217. package/dist/slider.js.map +1 -0
  218. package/dist/splitter.d.ts +113 -0
  219. package/dist/splitter.d.ts.map +1 -0
  220. package/dist/splitter.js +99 -0
  221. package/dist/splitter.js.map +1 -0
  222. package/dist/statistic.d.ts +41 -0
  223. package/dist/statistic.d.ts.map +1 -0
  224. package/dist/statistic.js +76 -0
  225. package/dist/statistic.js.map +1 -0
  226. package/dist/steps.d.ts +196 -0
  227. package/dist/steps.d.ts.map +1 -0
  228. package/dist/steps.js +160 -0
  229. package/dist/steps.js.map +1 -0
  230. package/dist/tag.d.ts +128 -0
  231. package/dist/tag.d.ts.map +1 -0
  232. package/dist/tag.js +93 -0
  233. package/dist/tag.js.map +1 -0
  234. package/dist/timeline.d.ts +147 -0
  235. package/dist/timeline.d.ts.map +1 -0
  236. package/dist/timeline.js +127 -0
  237. package/dist/timeline.js.map +1 -0
  238. package/dist/toast.d.ts +164 -0
  239. package/dist/toast.d.ts.map +1 -0
  240. package/dist/toast.js +529 -0
  241. package/dist/toast.js.map +1 -0
  242. package/dist/tokens.d.ts +9 -0
  243. package/dist/tokens.d.ts.map +1 -0
  244. package/dist/tokens.js +9 -0
  245. package/dist/tokens.js.map +1 -0
  246. package/dist/tooltip.d.ts +44 -0
  247. package/dist/tooltip.d.ts.map +1 -0
  248. package/dist/tooltip.js +88 -0
  249. package/dist/tooltip.js.map +1 -0
  250. package/dist/tour.d.ts +218 -0
  251. package/dist/tour.d.ts.map +1 -0
  252. package/dist/tour.js +211 -0
  253. package/dist/tour.js.map +1 -0
  254. package/dist/transfer-list.d.ts +207 -0
  255. package/dist/transfer-list.d.ts.map +1 -0
  256. package/dist/transfer-list.js +193 -0
  257. package/dist/transfer-list.js.map +1 -0
  258. package/dist/tree-select.d.ts +78 -0
  259. package/dist/tree-select.d.ts.map +1 -0
  260. package/dist/tree-select.js +132 -0
  261. package/dist/tree-select.js.map +1 -0
  262. package/dist/tree.d.ts +206 -0
  263. package/dist/tree.d.ts.map +1 -0
  264. package/dist/tree.js +223 -0
  265. package/dist/tree.js.map +1 -0
  266. package/dist/upload-item.d.ts +173 -0
  267. package/dist/upload-item.d.ts.map +1 -0
  268. package/dist/upload-item.js +156 -0
  269. package/dist/upload-item.js.map +1 -0
  270. package/dist/version.d.ts +3 -0
  271. package/dist/version.d.ts.map +1 -0
  272. package/dist/version.js +3 -0
  273. package/dist/version.js.map +1 -0
  274. package/docs/affix.md +63 -0
  275. package/docs/anchor.md +59 -0
  276. package/docs/ant-design-coverage.md +119 -0
  277. package/docs/app-provider.md +50 -0
  278. package/docs/app-rn-adoption.md +227 -0
  279. package/docs/architecture.md +320 -0
  280. package/docs/authoring-brief.md +87 -0
  281. package/docs/border-beam.md +66 -0
  282. package/docs/bottom-navigation.md +127 -0
  283. package/docs/breadcrumb.md +82 -0
  284. package/docs/calendar.md +154 -0
  285. package/docs/carousel.md +130 -0
  286. package/docs/cascader.md +93 -0
  287. package/docs/catalog-decision-status.md +306 -0
  288. package/docs/color-picker.md +72 -0
  289. package/docs/command-palette.md +116 -0
  290. package/docs/confirm-popover.md +93 -0
  291. package/docs/consistency-audit.md +383 -0
  292. package/docs/consumer-release-gate.md +90 -0
  293. package/docs/content-state.md +156 -0
  294. package/docs/context-panel.md +88 -0
  295. package/docs/cross-platform-core-normalization.md +118 -0
  296. package/docs/data-table.md +79 -0
  297. package/docs/date-picker.md +84 -0
  298. package/docs/description-list.md +75 -0
  299. package/docs/design-system-provider.md +139 -0
  300. package/docs/dropdown.md +78 -0
  301. package/docs/expansion-roadmap.md +285 -0
  302. package/docs/file-picker.md +59 -0
  303. package/docs/floating-action-button.md +111 -0
  304. package/docs/form.md +134 -0
  305. package/docs/generated/component-maturity.md +103 -0
  306. package/docs/generated/renderer-evidence.json +5597 -0
  307. package/docs/generated/renderer-evidence.md +132 -0
  308. package/docs/generated/showcase-manifest.json +3732 -0
  309. package/docs/icon.md +22 -0
  310. package/docs/identity.md +121 -0
  311. package/docs/image.md +84 -0
  312. package/docs/implementation-0.5.md +85 -0
  313. package/docs/layout-primitives.md +107 -0
  314. package/docs/layout.md +83 -0
  315. package/docs/library-reference-decisions.md +123 -0
  316. package/docs/link.md +67 -0
  317. package/docs/load-more.md +31 -0
  318. package/docs/mentions.md +82 -0
  319. package/docs/migration-0.2.md +108 -0
  320. package/docs/migration-0.3.md +72 -0
  321. package/docs/migration-0.5.md +82 -0
  322. package/docs/migration-0.6.md +197 -0
  323. package/docs/notification.md +54 -0
  324. package/docs/number-field.md +82 -0
  325. package/docs/otp-field.md +103 -0
  326. package/docs/pagination.md +139 -0
  327. package/docs/password-field.md +98 -0
  328. package/docs/popover.md +124 -0
  329. package/docs/promotion-candidates.md +169 -0
  330. package/docs/qr-code.md +69 -0
  331. package/docs/rating.md +58 -0
  332. package/docs/responsive-grid.md +90 -0
  333. package/docs/result.md +96 -0
  334. package/docs/showcase.md +97 -0
  335. package/docs/side-panel.md +71 -0
  336. package/docs/slider.md +79 -0
  337. package/docs/splitter.md +55 -0
  338. package/docs/statistic.md +16 -0
  339. package/docs/steps.md +115 -0
  340. package/docs/tag.md +57 -0
  341. package/docs/time-picker.md +88 -0
  342. package/docs/timeline.md +146 -0
  343. package/docs/toast.md +127 -0
  344. package/docs/tooltip.md +58 -0
  345. package/docs/tour.md +136 -0
  346. package/docs/transfer-list.md +94 -0
  347. package/docs/tree-select.md +101 -0
  348. package/docs/tree.md +123 -0
  349. package/docs/upload-item.md +68 -0
  350. package/docs/utility.md +53 -0
  351. package/docs/virtual-list.md +70 -0
  352. package/docs/watermark.md +58 -0
  353. package/package.json +402 -0
@@ -0,0 +1,124 @@
1
+ export const loadMoreBehaviorDefaults = {
2
+ mode: "automatic",
3
+ };
4
+ function assertNonEmpty(value, field) {
5
+ if (value.trim().length === 0) {
6
+ throw new TypeError(`LoadMore ${field} must not be empty`);
7
+ }
8
+ }
9
+ export function validateLoadMoreState(state) {
10
+ const runtimeStatus = state.status;
11
+ if (runtimeStatus !== "ready" &&
12
+ runtimeStatus !== "loading" &&
13
+ runtimeStatus !== "error" &&
14
+ runtimeStatus !== "complete") {
15
+ throw new TypeError(`Unsupported LoadMore status: ${String(runtimeStatus)}`);
16
+ }
17
+ if (state.status === "complete")
18
+ return;
19
+ assertNonEmpty(state.requestKey, "requestKey");
20
+ if (state.requestKey !== state.requestKey.trim()) {
21
+ throw new TypeError("LoadMore requestKey must not start or end with whitespace");
22
+ }
23
+ if (state.status === "error")
24
+ assertNonEmpty(state.message, "message");
25
+ }
26
+ export function validateLoadMoreLabels(labels) {
27
+ if (labels === null || typeof labels !== "object") {
28
+ throw new TypeError("LoadMore labels must be an object");
29
+ }
30
+ for (const field of ["loadMore", "loading", "retry", "complete"]) {
31
+ const value = labels[field];
32
+ if (typeof value !== "string" || value.trim().length === 0) {
33
+ throw new TypeError(`LoadMore labels.${field} must not be empty`);
34
+ }
35
+ }
36
+ }
37
+ export function validateLoadMoreDescriptor(descriptor) {
38
+ validateLoadMoreState(descriptor.state);
39
+ validateLoadMoreLabels(descriptor.labels);
40
+ }
41
+ export function canRequestLoadMore(state, mode, reason) {
42
+ validateLoadMoreState(state);
43
+ if (mode !== "automatic" && mode !== "manual") {
44
+ throw new TypeError(`Unsupported LoadMore mode: ${String(mode)}`);
45
+ }
46
+ if (reason !== "viewport" && reason !== "manual" && reason !== "retry") {
47
+ throw new TypeError(`Unsupported LoadMore request reason: ${String(reason)}`);
48
+ }
49
+ if (reason === "viewport") {
50
+ return mode === "automatic" && state.status === "ready";
51
+ }
52
+ if (reason === "manual")
53
+ return state.status === "ready";
54
+ return state.status === "error";
55
+ }
56
+ /**
57
+ * Prevents duplicate and out-of-order page requests without owning collection
58
+ * data. Query state remains product-owned; this controller only gates events.
59
+ */
60
+ export function createLoadMoreController(options) {
61
+ const mode = options.mode ?? loadMoreBehaviorDefaults.mode;
62
+ if (mode !== "automatic" && mode !== "manual") {
63
+ throw new TypeError(`Unsupported LoadMore mode: ${String(mode)}`);
64
+ }
65
+ if (typeof options.onLoadMore !== "function") {
66
+ throw new TypeError("LoadMore onLoadMore must be a function");
67
+ }
68
+ let inFlightRequestKey = null;
69
+ let disposed = false;
70
+ let cachedSnapshot = null;
71
+ const snapshot = () => {
72
+ cachedSnapshot ??= { mode, inFlightRequestKey, disposed };
73
+ return cachedSnapshot;
74
+ };
75
+ const invalidate = () => {
76
+ cachedSnapshot = null;
77
+ };
78
+ return {
79
+ getSnapshot: snapshot,
80
+ async request(state, reason) {
81
+ if (disposed)
82
+ throw new Error("Cannot use a disposed LoadMore controller");
83
+ if (!canRequestLoadMore(state, mode, reason)) {
84
+ return reason === "viewport" && mode === "manual"
85
+ ? "blocked-by-mode"
86
+ : "blocked-by-state";
87
+ }
88
+ // `canRequestLoadMore` rejects complete, but keep the discriminant local
89
+ // so emitted types never treat its absent requestKey as a valid cursor.
90
+ if (state.status === "complete")
91
+ return "blocked-by-state";
92
+ if (inFlightRequestKey !== null)
93
+ return "already-requesting";
94
+ const requestKey = state.requestKey;
95
+ inFlightRequestKey = requestKey;
96
+ invalidate();
97
+ try {
98
+ const pending = options.onLoadMore({ requestKey, reason });
99
+ if (pending === null ||
100
+ typeof pending !== "object" ||
101
+ typeof pending.then !== "function") {
102
+ throw new TypeError("LoadMore onLoadMore must return a Promise that settles with the page request");
103
+ }
104
+ await pending;
105
+ return "started";
106
+ }
107
+ finally {
108
+ if (inFlightRequestKey === requestKey) {
109
+ inFlightRequestKey = null;
110
+ invalidate();
111
+ }
112
+ }
113
+ },
114
+ dispose() {
115
+ if (disposed)
116
+ return false;
117
+ disposed = true;
118
+ inFlightRequestKey = null;
119
+ invalidate();
120
+ return true;
121
+ },
122
+ };
123
+ }
124
+ //# sourceMappingURL=load-more.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-more.js","sourceRoot":"","sources":["../src/load-more.ts"],"names":[],"mappings":"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","sourcesContent":["export type LoadMoreMode = \"automatic\" | \"manual\";\nexport type LoadMoreRequestReason = \"viewport\" | \"manual\" | \"retry\";\n\nexport type LoadMoreReadyState = Readonly<{\n status: \"ready\";\n requestKey: string;\n}>;\n\nexport type LoadMoreLoadingState = Readonly<{\n status: \"loading\";\n requestKey: string;\n}>;\n\nexport type LoadMoreErrorState = Readonly<{\n status: \"error\";\n requestKey: string;\n message: string;\n}>;\n\nexport type LoadMoreCompleteState = Readonly<{\n status: \"complete\";\n requestKey?: never;\n}>;\n\n/** Existing collection items stay mounted while this footer state changes. */\nexport type LoadMoreState =\n | LoadMoreReadyState\n | LoadMoreLoadingState\n | LoadMoreErrorState\n | LoadMoreCompleteState;\n\nexport type LoadMoreRequest = Readonly<{\n requestKey: string;\n reason: LoadMoreRequestReason;\n}>;\n\nexport type LoadMoreLabels = Readonly<{\n loadMore: string;\n loading: string;\n retry: string;\n complete: string;\n}>;\n\nexport type LoadMoreDescriptor = Readonly<{\n state: LoadMoreState;\n labels: LoadMoreLabels;\n}>;\n\nexport type LoadMoreRequestHandler = (\n request: LoadMoreRequest,\n) => Promise<void>;\n\nexport type LoadMoreRequestOutcome =\n | \"started\"\n | \"blocked-by-mode\"\n | \"blocked-by-state\"\n | \"already-requesting\";\n\nexport type LoadMoreControllerOptions = Readonly<{\n mode?: LoadMoreMode;\n onLoadMore: LoadMoreRequestHandler;\n}>;\n\nexport type LoadMoreControllerSnapshot = Readonly<{\n mode: LoadMoreMode;\n inFlightRequestKey: string | null;\n disposed: boolean;\n}>;\n\nexport type LoadMoreController = Readonly<{\n getSnapshot(): LoadMoreControllerSnapshot;\n request(\n state: LoadMoreState,\n reason: LoadMoreRequestReason,\n ): Promise<LoadMoreRequestOutcome>;\n dispose(): boolean;\n}>;\n\nexport const loadMoreBehaviorDefaults = {\n mode: \"automatic\",\n} as const satisfies Readonly<{ mode: LoadMoreMode }>;\n\nfunction assertNonEmpty(value: string, field: string): void {\n if (value.trim().length === 0) {\n throw new TypeError(`LoadMore ${field} must not be empty`);\n }\n}\n\nexport function validateLoadMoreState(state: LoadMoreState): void {\n const runtimeStatus = (state as Readonly<{ status?: unknown }>).status;\n if (\n runtimeStatus !== \"ready\" &&\n runtimeStatus !== \"loading\" &&\n runtimeStatus !== \"error\" &&\n runtimeStatus !== \"complete\"\n ) {\n throw new TypeError(`Unsupported LoadMore status: ${String(runtimeStatus)}`);\n }\n if (state.status === \"complete\") return;\n assertNonEmpty(state.requestKey, \"requestKey\");\n if (state.requestKey !== state.requestKey.trim()) {\n throw new TypeError(\"LoadMore requestKey must not start or end with whitespace\");\n }\n if (state.status === \"error\") assertNonEmpty(state.message, \"message\");\n}\n\nexport function validateLoadMoreLabels(labels: LoadMoreLabels): void {\n if (labels === null || typeof labels !== \"object\") {\n throw new TypeError(\"LoadMore labels must be an object\");\n }\n for (const field of [\"loadMore\", \"loading\", \"retry\", \"complete\"] as const) {\n const value = labels[field];\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new TypeError(`LoadMore labels.${field} must not be empty`);\n }\n }\n}\n\nexport function validateLoadMoreDescriptor(descriptor: LoadMoreDescriptor): void {\n validateLoadMoreState(descriptor.state);\n validateLoadMoreLabels(descriptor.labels);\n}\n\nexport function canRequestLoadMore(\n state: LoadMoreState,\n mode: LoadMoreMode,\n reason: LoadMoreRequestReason,\n): boolean {\n validateLoadMoreState(state);\n if (mode !== \"automatic\" && mode !== \"manual\") {\n throw new TypeError(`Unsupported LoadMore mode: ${String(mode)}`);\n }\n if (reason !== \"viewport\" && reason !== \"manual\" && reason !== \"retry\") {\n throw new TypeError(`Unsupported LoadMore request reason: ${String(reason)}`);\n }\n if (reason === \"viewport\") {\n return mode === \"automatic\" && state.status === \"ready\";\n }\n if (reason === \"manual\") return state.status === \"ready\";\n return state.status === \"error\";\n}\n\n/**\n * Prevents duplicate and out-of-order page requests without owning collection\n * data. Query state remains product-owned; this controller only gates events.\n */\nexport function createLoadMoreController(\n options: LoadMoreControllerOptions,\n): LoadMoreController {\n const mode = options.mode ?? loadMoreBehaviorDefaults.mode;\n if (mode !== \"automatic\" && mode !== \"manual\") {\n throw new TypeError(`Unsupported LoadMore mode: ${String(mode)}`);\n }\n if (typeof options.onLoadMore !== \"function\") {\n throw new TypeError(\"LoadMore onLoadMore must be a function\");\n }\n\n let inFlightRequestKey: string | null = null;\n let disposed = false;\n let cachedSnapshot: LoadMoreControllerSnapshot | null = null;\n\n const snapshot = (): LoadMoreControllerSnapshot => {\n cachedSnapshot ??= { mode, inFlightRequestKey, disposed };\n return cachedSnapshot;\n };\n const invalidate = () => {\n cachedSnapshot = null;\n };\n\n return {\n getSnapshot: snapshot,\n async request(state, reason) {\n if (disposed) throw new Error(\"Cannot use a disposed LoadMore controller\");\n if (!canRequestLoadMore(state, mode, reason)) {\n return reason === \"viewport\" && mode === \"manual\"\n ? \"blocked-by-mode\"\n : \"blocked-by-state\";\n }\n // `canRequestLoadMore` rejects complete, but keep the discriminant local\n // so emitted types never treat its absent requestKey as a valid cursor.\n if (state.status === \"complete\") return \"blocked-by-state\";\n if (inFlightRequestKey !== null) return \"already-requesting\";\n\n const requestKey = state.requestKey;\n inFlightRequestKey = requestKey;\n invalidate();\n try {\n const pending = options.onLoadMore({ requestKey, reason });\n if (\n pending === null ||\n typeof pending !== \"object\" ||\n typeof (pending as Readonly<{ then?: unknown }>).then !== \"function\"\n ) {\n throw new TypeError(\n \"LoadMore onLoadMore must return a Promise that settles with the page request\",\n );\n }\n await pending;\n return \"started\";\n } finally {\n if (inFlightRequestKey === requestKey) {\n inFlightRequestKey = null;\n invalidate();\n }\n }\n },\n dispose() {\n if (disposed) return false;\n disposed = true;\n inFlightRequestKey = null;\n invalidate();\n return true;\n },\n };\n}\n"]}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `docs/mentions.md`'s "이게 새 컴포넌트인가" verdict: Mentions is a `TextArea`
3
+ * whose candidate popup is Combobox's existing listbox contract
4
+ * (`comboboxRecipe`, `behaviorRegistry.combobox`) verbatim — arrow-key
5
+ * navigation, typeahead-free filtering, loading/empty/error announcement are
6
+ * already owned there and this module does not redeclare them. The one piece
7
+ * neither owns is *finding the trigger inside free-form text and computing
8
+ * what range gets replaced on commit* — that is genuinely new, and it is all
9
+ * this module contains.
10
+ */
11
+ export type MentionTriggerConfig<TriggerId extends string = string> = Readonly<{
12
+ id: TriggerId;
13
+ /** Exactly one non-whitespace character, e.g. "@" or "#". */
14
+ trigger: string;
15
+ }>;
16
+ export type MentionMatch<TriggerId extends string = string> = Readonly<{
17
+ triggerId: TriggerId;
18
+ trigger: string;
19
+ /** UTF-16 code unit offset of the trigger character itself in `text`. */
20
+ triggerStart: number;
21
+ /** Text between the trigger and the cursor — drives candidate filtering. */
22
+ query: string;
23
+ }>;
24
+ /**
25
+ * Rejects the configuration shapes a naive Mentions implementation would
26
+ * accept and then fail on later: an empty trigger list (nothing to detect),
27
+ * a multi-character or whitespace trigger (the scan below assumes exactly one
28
+ * non-whitespace code unit), and two configs racing on the same character or
29
+ * id.
30
+ */
31
+ export declare function validateMentionTriggers<TriggerId extends string>(triggers: readonly MentionTriggerConfig<TriggerId>[]): void;
32
+ /**
33
+ * Scans left from the cursor for the nearest trigger character that starts a
34
+ * token (start-of-text or preceded by whitespace) with no whitespace between
35
+ * it and the cursor. The whitespace-between check is what must reject
36
+ * `"user@example.com"` — the char before `@` is `r`, not whitespace/start —
37
+ * and cancel an already-open mention the moment the user types a space, the
38
+ * same convention every mention UI (Slack, Discord, GitHub) uses so the query
39
+ * can never run away across word boundaries. Operating on the resolved text
40
+ * value and a single cursor offset (never individual keystrokes) is also why
41
+ * Hangul composition needs no special-casing here: a composing jamo is
42
+ * already a valid code point in that string the moment `onChange` fires,
43
+ * composed or not.
44
+ */
45
+ export declare function findActiveMentionTrigger<TriggerId extends string>(text: string, cursorPosition: number, triggers: readonly MentionTriggerConfig<TriggerId>[]): MentionMatch<TriggerId> | null;
46
+ export type MentionInsertionResult = Readonly<{
47
+ text: string;
48
+ /** Caret offset immediately after the inserted mention and its trailing space. */
49
+ cursorPosition: number;
50
+ }>;
51
+ /**
52
+ * Replaces `[match.triggerStart, cursorPosition)` — the trigger character
53
+ * through wherever the caret sits now — with the trigger plus the product's
54
+ * display text plus a trailing space, so typing can continue without fusing
55
+ * into the mention. The trigger character is always prepended here, not by
56
+ * the caller, so it can never be forgotten or duplicated.
57
+ */
58
+ export declare function resolveMentionInsertion<TriggerId extends string>(text: string, match: MentionMatch<TriggerId>, cursorPosition: number, insertedText: string): MentionInsertionResult;
59
+ /**
60
+ * No new recipe or behaviorRegistry entry: the popup is
61
+ * `behaviorRegistry.combobox` verbatim (roles, keyboard, dismiss, the
62
+ * `ime-composition-does-not-prematurely-filter-or-commit` scenario already
63
+ * covers composed text), layered on a plain `TextArea`. These scenarios are
64
+ * the trigger-detection slice combobox's list does not already cover.
65
+ */
66
+ export declare const mentionsBehaviorScenarios: readonly ["trigger-preceded-by-a-non-whitespace-character-does-not-open-the-popup", "typing-a-space-after-the-trigger-closes-the-popup-without-committing", "empty-query-right-after-the-trigger-is-a-valid-active-match", "ime-composition-updates-the-query-like-any-other-text-change-no-special-casing-needed", "commit-always-inserts-the-trigger-character-exactly-once", "commit-replaces-exactly-the-trigger-through-the-current-cursor-nothing-before-or-after", "two-configured-triggers-never-share-a-character-or-an-id", "the-nearer-trigger-to-the-cursor-wins-when-an-earlier-token-also-looks-like-a-trigger"];
67
+ //# sourceMappingURL=mentions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mentions.d.ts","sourceRoot":"","sources":["../src/mentions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,oBAAoB,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IAC7E,EAAE,EAAE,SAAS,CAAC;IACd,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,CAAC;AAEH,MAAM,MAAM,YAAY,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IACrE,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,YAAY,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAMH;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,SAAS,MAAM,EAC9D,QAAQ,EAAE,SAAS,oBAAoB,CAAC,SAAS,CAAC,EAAE,GACnD,IAAI,CAwBN;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,SAAS,MAAM,EAC/D,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,QAAQ,EAAE,SAAS,oBAAoB,CAAC,SAAS,CAAC,EAAE,GACnD,YAAY,CAAC,SAAS,CAAC,GAAG,IAAI,CAmBhC;AAED,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,SAAS,MAAM,EAC9D,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,YAAY,CAAC,SAAS,CAAC,EAC9B,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,GACnB,sBAAsB,CAcxB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,gmBAS5B,CAAC"}
@@ -0,0 +1,107 @@
1
+ function isWhitespace(char) {
2
+ return char !== undefined && /\s/.test(char);
3
+ }
4
+ /**
5
+ * Rejects the configuration shapes a naive Mentions implementation would
6
+ * accept and then fail on later: an empty trigger list (nothing to detect),
7
+ * a multi-character or whitespace trigger (the scan below assumes exactly one
8
+ * non-whitespace code unit), and two configs racing on the same character or
9
+ * id.
10
+ */
11
+ export function validateMentionTriggers(triggers) {
12
+ if (triggers.length === 0) {
13
+ throw new TypeError("Mentions must configure at least one trigger");
14
+ }
15
+ const chars = new Set();
16
+ const ids = new Set();
17
+ for (const config of triggers) {
18
+ if (config.trigger.length !== 1) {
19
+ throw new TypeError(`Mentions trigger must be exactly one character: ${JSON.stringify(config.trigger)}`);
20
+ }
21
+ if (isWhitespace(config.trigger)) {
22
+ throw new TypeError("Mentions trigger must not be whitespace");
23
+ }
24
+ if (chars.has(config.trigger)) {
25
+ throw new TypeError(`Duplicate Mentions trigger character: ${config.trigger}`);
26
+ }
27
+ chars.add(config.trigger);
28
+ if (ids.has(config.id)) {
29
+ throw new TypeError(`Duplicate Mentions trigger id: ${config.id}`);
30
+ }
31
+ ids.add(config.id);
32
+ }
33
+ }
34
+ /**
35
+ * Scans left from the cursor for the nearest trigger character that starts a
36
+ * token (start-of-text or preceded by whitespace) with no whitespace between
37
+ * it and the cursor. The whitespace-between check is what must reject
38
+ * `"user@example.com"` — the char before `@` is `r`, not whitespace/start —
39
+ * and cancel an already-open mention the moment the user types a space, the
40
+ * same convention every mention UI (Slack, Discord, GitHub) uses so the query
41
+ * can never run away across word boundaries. Operating on the resolved text
42
+ * value and a single cursor offset (never individual keystrokes) is also why
43
+ * Hangul composition needs no special-casing here: a composing jamo is
44
+ * already a valid code point in that string the moment `onChange` fires,
45
+ * composed or not.
46
+ */
47
+ export function findActiveMentionTrigger(text, cursorPosition, triggers) {
48
+ validateMentionTriggers(triggers);
49
+ if (cursorPosition < 0 || cursorPosition > text.length) {
50
+ throw new RangeError("Mentions cursorPosition must be within the text bounds");
51
+ }
52
+ for (let index = cursorPosition - 1; index >= 0; index -= 1) {
53
+ const char = text[index];
54
+ if (isWhitespace(char))
55
+ return null;
56
+ const config = triggers.find((candidate) => candidate.trigger === char);
57
+ if (config && (index === 0 || isWhitespace(text[index - 1]))) {
58
+ return {
59
+ triggerId: config.id,
60
+ trigger: config.trigger,
61
+ triggerStart: index,
62
+ query: text.slice(index + 1, cursorPosition),
63
+ };
64
+ }
65
+ }
66
+ return null;
67
+ }
68
+ /**
69
+ * Replaces `[match.triggerStart, cursorPosition)` — the trigger character
70
+ * through wherever the caret sits now — with the trigger plus the product's
71
+ * display text plus a trailing space, so typing can continue without fusing
72
+ * into the mention. The trigger character is always prepended here, not by
73
+ * the caller, so it can never be forgotten or duplicated.
74
+ */
75
+ export function resolveMentionInsertion(text, match, cursorPosition, insertedText) {
76
+ if (insertedText.trim().length === 0) {
77
+ throw new TypeError("Mentions insertedText must not be empty");
78
+ }
79
+ if (cursorPosition < match.triggerStart || cursorPosition > text.length) {
80
+ throw new RangeError("Mentions cursorPosition must be at or after the matched trigger");
81
+ }
82
+ const before = text.slice(0, match.triggerStart);
83
+ const after = text.slice(cursorPosition);
84
+ const inserted = `${match.trigger}${insertedText} `;
85
+ return {
86
+ text: `${before}${inserted}${after}`,
87
+ cursorPosition: before.length + inserted.length,
88
+ };
89
+ }
90
+ /**
91
+ * No new recipe or behaviorRegistry entry: the popup is
92
+ * `behaviorRegistry.combobox` verbatim (roles, keyboard, dismiss, the
93
+ * `ime-composition-does-not-prematurely-filter-or-commit` scenario already
94
+ * covers composed text), layered on a plain `TextArea`. These scenarios are
95
+ * the trigger-detection slice combobox's list does not already cover.
96
+ */
97
+ export const mentionsBehaviorScenarios = [
98
+ "trigger-preceded-by-a-non-whitespace-character-does-not-open-the-popup",
99
+ "typing-a-space-after-the-trigger-closes-the-popup-without-committing",
100
+ "empty-query-right-after-the-trigger-is-a-valid-active-match",
101
+ "ime-composition-updates-the-query-like-any-other-text-change-no-special-casing-needed",
102
+ "commit-always-inserts-the-trigger-character-exactly-once",
103
+ "commit-replaces-exactly-the-trigger-through-the-current-cursor-nothing-before-or-after",
104
+ "two-configured-triggers-never-share-a-character-or-an-id",
105
+ "the-nearer-trigger-to-the-cursor-wins-when-an-earlier-token-also-looks-like-a-trigger",
106
+ ];
107
+ //# sourceMappingURL=mentions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mentions.js","sourceRoot":"","sources":["../src/mentions.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `docs/mentions.md`'s \"이게 새 컴포넌트인가\" verdict: Mentions is a `TextArea`\n * whose candidate popup is Combobox's existing listbox contract\n * (`comboboxRecipe`, `behaviorRegistry.combobox`) verbatim — arrow-key\n * navigation, typeahead-free filtering, loading/empty/error announcement are\n * already owned there and this module does not redeclare them. The one piece\n * neither owns is *finding the trigger inside free-form text and computing\n * what range gets replaced on commit* — that is genuinely new, and it is all\n * this module contains.\n */\nexport type MentionTriggerConfig<TriggerId extends string = string> = Readonly<{\n id: TriggerId;\n /** Exactly one non-whitespace character, e.g. \"@\" or \"#\". */\n trigger: string;\n}>;\n\nexport type MentionMatch<TriggerId extends string = string> = Readonly<{\n triggerId: TriggerId;\n trigger: string;\n /** UTF-16 code unit offset of the trigger character itself in `text`. */\n triggerStart: number;\n /** Text between the trigger and the cursor — drives candidate filtering. */\n query: string;\n}>;\n\nfunction isWhitespace(char: string | undefined): boolean {\n return char !== undefined && /\\s/.test(char);\n}\n\n/**\n * Rejects the configuration shapes a naive Mentions implementation would\n * accept and then fail on later: an empty trigger list (nothing to detect),\n * a multi-character or whitespace trigger (the scan below assumes exactly one\n * non-whitespace code unit), and two configs racing on the same character or\n * id.\n */\nexport function validateMentionTriggers<TriggerId extends string>(\n triggers: readonly MentionTriggerConfig<TriggerId>[],\n): void {\n if (triggers.length === 0) {\n throw new TypeError(\"Mentions must configure at least one trigger\");\n }\n const chars = new Set<string>();\n const ids = new Set<TriggerId>();\n for (const config of triggers) {\n if (config.trigger.length !== 1) {\n throw new TypeError(\n `Mentions trigger must be exactly one character: ${JSON.stringify(config.trigger)}`,\n );\n }\n if (isWhitespace(config.trigger)) {\n throw new TypeError(\"Mentions trigger must not be whitespace\");\n }\n if (chars.has(config.trigger)) {\n throw new TypeError(`Duplicate Mentions trigger character: ${config.trigger}`);\n }\n chars.add(config.trigger);\n if (ids.has(config.id)) {\n throw new TypeError(`Duplicate Mentions trigger id: ${config.id}`);\n }\n ids.add(config.id);\n }\n}\n\n/**\n * Scans left from the cursor for the nearest trigger character that starts a\n * token (start-of-text or preceded by whitespace) with no whitespace between\n * it and the cursor. The whitespace-between check is what must reject\n * `\"user@example.com\"` — the char before `@` is `r`, not whitespace/start —\n * and cancel an already-open mention the moment the user types a space, the\n * same convention every mention UI (Slack, Discord, GitHub) uses so the query\n * can never run away across word boundaries. Operating on the resolved text\n * value and a single cursor offset (never individual keystrokes) is also why\n * Hangul composition needs no special-casing here: a composing jamo is\n * already a valid code point in that string the moment `onChange` fires,\n * composed or not.\n */\nexport function findActiveMentionTrigger<TriggerId extends string>(\n text: string,\n cursorPosition: number,\n triggers: readonly MentionTriggerConfig<TriggerId>[],\n): MentionMatch<TriggerId> | null {\n validateMentionTriggers(triggers);\n if (cursorPosition < 0 || cursorPosition > text.length) {\n throw new RangeError(\"Mentions cursorPosition must be within the text bounds\");\n }\n for (let index = cursorPosition - 1; index >= 0; index -= 1) {\n const char = text[index]!;\n if (isWhitespace(char)) return null;\n const config = triggers.find((candidate) => candidate.trigger === char);\n if (config && (index === 0 || isWhitespace(text[index - 1]))) {\n return {\n triggerId: config.id,\n trigger: config.trigger,\n triggerStart: index,\n query: text.slice(index + 1, cursorPosition),\n };\n }\n }\n return null;\n}\n\nexport type MentionInsertionResult = Readonly<{\n text: string;\n /** Caret offset immediately after the inserted mention and its trailing space. */\n cursorPosition: number;\n}>;\n\n/**\n * Replaces `[match.triggerStart, cursorPosition)` — the trigger character\n * through wherever the caret sits now — with the trigger plus the product's\n * display text plus a trailing space, so typing can continue without fusing\n * into the mention. The trigger character is always prepended here, not by\n * the caller, so it can never be forgotten or duplicated.\n */\nexport function resolveMentionInsertion<TriggerId extends string>(\n text: string,\n match: MentionMatch<TriggerId>,\n cursorPosition: number,\n insertedText: string,\n): MentionInsertionResult {\n if (insertedText.trim().length === 0) {\n throw new TypeError(\"Mentions insertedText must not be empty\");\n }\n if (cursorPosition < match.triggerStart || cursorPosition > text.length) {\n throw new RangeError(\"Mentions cursorPosition must be at or after the matched trigger\");\n }\n const before = text.slice(0, match.triggerStart);\n const after = text.slice(cursorPosition);\n const inserted = `${match.trigger}${insertedText} `;\n return {\n text: `${before}${inserted}${after}`,\n cursorPosition: before.length + inserted.length,\n };\n}\n\n/**\n * No new recipe or behaviorRegistry entry: the popup is\n * `behaviorRegistry.combobox` verbatim (roles, keyboard, dismiss, the\n * `ime-composition-does-not-prematurely-filter-or-commit` scenario already\n * covers composed text), layered on a plain `TextArea`. These scenarios are\n * the trigger-detection slice combobox's list does not already cover.\n */\nexport const mentionsBehaviorScenarios = [\n \"trigger-preceded-by-a-non-whitespace-character-does-not-open-the-popup\",\n \"typing-a-space-after-the-trigger-closes-the-popup-without-committing\",\n \"empty-query-right-after-the-trigger-is-a-valid-active-match\",\n \"ime-composition-updates-the-query-like-any-other-text-change-no-special-casing-needed\",\n \"commit-always-inserts-the-trigger-character-exactly-once\",\n \"commit-replaces-exactly-the-trigger-through-the-current-cursor-nothing-before-or-after\",\n \"two-configured-triggers-never-share-a-character-or-an-id\",\n \"the-nearer-trigger-to-the-cursor-wins-when-an-earlier-token-also-looks-like-a-trigger\",\n] as const;\n"]}
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Shared by NumberField and Slider: both solve "pick a number within a range."
3
+ * Keeping min/max/step/value judgment in one place keeps the two components
4
+ * from drifting into two different meanings of the same numeric domain.
5
+ */
6
+ export type NumericRangeConfig = Readonly<{
7
+ min: number;
8
+ max: number;
9
+ step?: number;
10
+ }>;
11
+ export declare const numericRangeDefaults: {
12
+ readonly step: 1;
13
+ };
14
+ export declare function assertFiniteNumber(value: number, field: string): void;
15
+ export declare function validateNumericRangeConfig(config: NumericRangeConfig): void;
16
+ export declare function clampToRange(value: number, config: NumericRangeConfig): number;
17
+ /** Snaps to the nearest step from `min`, then clamps into [min, max]. */
18
+ export declare function snapToStep(value: number, config: NumericRangeConfig): number;
19
+ /** Move to the next valid grid boundary in the requested direction. */
20
+ export declare function stepNumericValue(value: number, config: NumericRangeConfig, direction: "increment" | "decrement"): number;
21
+ /**
22
+ * `null` means no value has been entered yet — distinct from any in-range
23
+ * number, including `min`. Products decide whether empty is allowed to submit.
24
+ */
25
+ export type NumberFieldValue = number | null;
26
+ /**
27
+ * Parses the renderer's editable text without guessing at locale, currency,
28
+ * or unit formatting. Empty text is a first-class `null` value; `undefined`
29
+ * means the draft is not a complete finite decimal number yet.
30
+ *
31
+ * Exponent notation is accepted because `String(number)` may produce it for
32
+ * very small or large finite values. Renderers keep incomplete drafts such as
33
+ * `-` or `1e` locally and only commit once this parser succeeds.
34
+ */
35
+ export declare function parseNumberFieldInput(input: string): NumberFieldValue | undefined;
36
+ /**
37
+ * Turns an editable draft into a model value at blur/submit boundaries.
38
+ * Direct input is clamped and snapped with the same range math used by the
39
+ * steppers and Slider. Invalid/incomplete text remains `undefined`, allowing a
40
+ * renderer to restore the last committed value without inventing an error.
41
+ */
42
+ export declare function commitNumberFieldInput(input: string, config: NumericRangeConfig): NumberFieldValue | undefined;
43
+ export type NumberFieldDescriptor = Readonly<{
44
+ value: NumberFieldValue;
45
+ min: number;
46
+ max: number;
47
+ step?: number;
48
+ }>;
49
+ export type ResolvedNumberFieldDescriptor = Omit<NumberFieldDescriptor, "step"> & Readonly<{
50
+ step: number;
51
+ }>;
52
+ export declare function validateNumberFieldDescriptor(descriptor: NumberFieldDescriptor): void;
53
+ export declare function resolveNumberFieldDescriptor(descriptor: NumberFieldDescriptor): ResolvedNumberFieldDescriptor;
54
+ export type NumberFieldStepperState = Readonly<{
55
+ incrementDisabled: boolean;
56
+ decrementDisabled: boolean;
57
+ }>;
58
+ /** Empty has no boundary yet, so neither stepper direction is disabled. */
59
+ export declare function resolveNumberFieldStepperState(descriptor: NumberFieldDescriptor): NumberFieldStepperState;
60
+ /** Resolve stepper availability from the visible draft, falling back safely. */
61
+ export declare function resolveNumberFieldInputStepperState(input: string, descriptor: NumberFieldDescriptor): NumberFieldStepperState;
62
+ /** Stepping from empty lands on the boundary you are moving toward. */
63
+ export declare function stepNumberFieldValue(descriptor: NumberFieldDescriptor, direction: "increment" | "decrement"): number;
64
+ /**
65
+ * Resolves a step action from the editable draft without first snapping and
66
+ * then stepping a second time. Off-grid drafts move to the next valid boundary
67
+ * in the requested direction; invalid drafts fall back to the committed model.
68
+ */
69
+ export declare function stepNumberFieldInput(input: string, descriptor: NumberFieldDescriptor, direction: "increment" | "decrement"): number;
70
+ export type NumberFieldSize = "medium" | "large";
71
+ /**
72
+ * Reuses the Field frame (`fieldFrameContract`) and form support copy
73
+ * (`formSupportContract`) verbatim — a second field frame would drift from
74
+ * Field the first time either one's border or height changes.
75
+ */
76
+ export declare const numberFieldRecipe: {
77
+ readonly slots: readonly ["root", "frame", "input", "decrement", "increment", "description", "error"];
78
+ readonly defaults: {
79
+ readonly size: "medium";
80
+ };
81
+ readonly frame: {
82
+ readonly background: Readonly<{
83
+ source: "theme";
84
+ key: "surface";
85
+ alpha?: number;
86
+ }>;
87
+ readonly border: Readonly<{
88
+ source: "theme";
89
+ key: "textMuted";
90
+ alpha?: number;
91
+ }>;
92
+ readonly focusBorder: Readonly<{
93
+ source: "theme";
94
+ key: "contentBrand";
95
+ alpha?: number;
96
+ }>;
97
+ readonly invalidBorder: Readonly<{
98
+ source: "theme";
99
+ key: "danger";
100
+ alpha?: number;
101
+ }>;
102
+ readonly radius: "md";
103
+ readonly borderWidth: 1;
104
+ readonly minHeight: 44;
105
+ readonly paddingHorizontal: 16;
106
+ };
107
+ readonly support: {
108
+ readonly label: {
109
+ readonly color: Readonly<{
110
+ source: "theme";
111
+ key: "textBody";
112
+ alpha?: number;
113
+ }>;
114
+ readonly textVariant: "body";
115
+ readonly fontWeight: "600";
116
+ };
117
+ readonly hint: {
118
+ readonly color: Readonly<{
119
+ source: "theme";
120
+ key: "textMuted";
121
+ alpha?: number;
122
+ }>;
123
+ readonly textVariant: "label";
124
+ };
125
+ readonly error: {
126
+ readonly color: Readonly<{
127
+ source: "theme";
128
+ key: "danger";
129
+ alpha?: number;
130
+ }>;
131
+ readonly textVariant: "label";
132
+ };
133
+ readonly gap: 8;
134
+ };
135
+ readonly sizes: {
136
+ readonly medium: {
137
+ readonly minHeight: 44;
138
+ readonly paddingHorizontal: 16;
139
+ readonly textVariant: "body";
140
+ readonly stepperDiameter: 44;
141
+ };
142
+ readonly large: {
143
+ readonly minHeight: 52;
144
+ readonly paddingHorizontal: 20;
145
+ readonly textVariant: "bodyLarge";
146
+ readonly stepperDiameter: 44;
147
+ };
148
+ };
149
+ readonly value: {
150
+ readonly color: Readonly<{
151
+ source: "theme";
152
+ key: "textBody";
153
+ alpha?: number;
154
+ }>;
155
+ readonly numericVariant: "tabular";
156
+ };
157
+ readonly stepper: {
158
+ readonly color: Readonly<{
159
+ source: "theme";
160
+ key: "textMuted";
161
+ alpha?: number;
162
+ }>;
163
+ readonly minTarget: 44;
164
+ };
165
+ readonly states: {
166
+ readonly focus: {
167
+ readonly color: Readonly<{
168
+ source: "theme";
169
+ key: "contentBrand";
170
+ alpha?: number;
171
+ }>;
172
+ readonly width: 2;
173
+ readonly offset: 2;
174
+ };
175
+ readonly invalidBorder: Readonly<{
176
+ source: "theme";
177
+ key: "danger";
178
+ alpha?: number;
179
+ }>;
180
+ readonly disabledOpacity: 0.5;
181
+ };
182
+ };
183
+ /**
184
+ * Held-repeat on the stepper buttons is deliberately not part of this
185
+ * contract: no product using NumberField has measured demand for press-and-
186
+ * hold, and adding it now would mean guessing at a repeat-rate/acceleration
187
+ * curve nobody has validated. A single activation per press only.
188
+ */
189
+ export declare const numberFieldBehavior: {
190
+ readonly controlled: readonly ["value", "defaultValue", "onValueChange"];
191
+ readonly stateAxes: {
192
+ readonly availability: readonly ["enabled", "disabled", "readOnly"];
193
+ readonly value: readonly ["empty", "filled"];
194
+ readonly validation: readonly ["valid", "invalid"];
195
+ };
196
+ readonly web: {
197
+ readonly roles: readonly ["spinbutton"];
198
+ readonly keyboard: readonly ["Tab", "ArrowUp", "ArrowDown"];
199
+ readonly focus: "native";
200
+ };
201
+ readonly native: {
202
+ readonly roles: readonly ["text", "button"];
203
+ readonly states: readonly ["disabled"];
204
+ readonly actions: readonly ["focus", "setText", "increment", "decrement"];
205
+ };
206
+ readonly scenarios: readonly ["value-and-range-are-independent-controlled-inputs", "stepper-buttons-disable-at-min-and-max", "empty-disables-neither-stepper-direction", "keyboard-arrow-up-down-step-like-the-stepper-buttons", "invalid-is-a-numberfield-only-axis-independent-of-range", "held-repeat-is-not-part-of-the-contract"];
207
+ };
208
+ //# sourceMappingURL=number-field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"number-field.d.ts","sourceRoot":"","sources":["../src/number-field.ts"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH,eAAO,MAAM,oBAAoB;;CAEc,CAAC;AAEhD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAIrE;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI,CAc3E;AA2BD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAI9E;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAO5E;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,kBAAkB,EAC1B,SAAS,EAAE,WAAW,GAAG,WAAW,GACnC,MAAM,CAOR;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,IAAI,CAAC;AAE7C;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAQjF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,kBAAkB,GACzB,gBAAgB,GAAG,SAAS,CAK9B;AAED,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,KAAK,EAAE,gBAAgB,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,6BAA6B,GAAG,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,GAC7E,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE7B,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,qBAAqB,GAAG,IAAI,CAQrF;AAED,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,qBAAqB,GAChC,6BAA6B,CAG/B;AAED,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC7C,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;CAC5B,CAAC,CAAC;AAEH,2EAA2E;AAC3E,wBAAgB,8BAA8B,CAC5C,UAAU,EAAE,qBAAqB,GAChC,uBAAuB,CASzB;AAED,gFAAgF;AAChF,wBAAgB,mCAAmC,CACjD,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,qBAAqB,GAChC,uBAAuB,CAWzB;AAED,uEAAuE;AACvE,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,qBAAqB,EACjC,SAAS,EAAE,WAAW,GAAG,WAAW,GACnC,MAAM,CAMR;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,qBAAqB,EACjC,SAAS,EAAE,WAAW,GAAG,WAAW,GACnC,MAAM,CAQR;AAED,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEjD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqE7B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;CAyBK,CAAC"}