@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,120 @@
1
+ import { fieldFrameContract, focusIndicatorContract, formSupportContract, } from "./component-contracts.js";
2
+ import { control, opacity, spacing } from "./foundations.js";
3
+ import { semanticColors } from "./semantic-colors.js";
4
+ function assertBoolean(value, field) {
5
+ if (typeof value !== "boolean") {
6
+ throw new TypeError(`PasswordField ${field} must be a boolean`);
7
+ }
8
+ }
9
+ export function validatePasswordFieldDescriptor(descriptor) {
10
+ assertBoolean(descriptor.revealed, "revealed");
11
+ if (descriptor.autofillHint !== "current" && descriptor.autofillHint !== "new") {
12
+ throw new TypeError(`Unsupported PasswordField autofillHint: ${String(descriptor.autofillHint)}`);
13
+ }
14
+ }
15
+ /**
16
+ * Toggling `revealed` only ever changes how the value is displayed — it
17
+ * never touches the value itself. That guarantee is why this resolver takes
18
+ * no value parameter at all: there is nothing here that could reach into it.
19
+ */
20
+ export function resolvePasswordFieldDescriptor(descriptor, options) {
21
+ validatePasswordFieldDescriptor(descriptor);
22
+ if (typeof options.composeToggleAccessibleName !== "function") {
23
+ throw new TypeError("PasswordField composeToggleAccessibleName must be a function");
24
+ }
25
+ const toggleAccessibleName = options.composeToggleAccessibleName({
26
+ willReveal: !descriptor.revealed,
27
+ });
28
+ if (typeof toggleAccessibleName !== "string" ||
29
+ toggleAccessibleName.trim().length === 0) {
30
+ throw new TypeError("PasswordField composeToggleAccessibleName must return a non-empty string");
31
+ }
32
+ return {
33
+ ...descriptor,
34
+ toggleAccessibleName,
35
+ webInputType: descriptor.revealed ? "text" : "password",
36
+ nativeSecureTextEntry: !descriptor.revealed,
37
+ };
38
+ }
39
+ /**
40
+ * Reuses Field's frame and form support copy verbatim — the same judgment
41
+ * NumberField already made (see src/number-field.ts) — and adds only the
42
+ * toggle slot, styled like SearchField's trailing clear button (same
43
+ * diameter/hit-slop convention) but with the visibility icon pair instead.
44
+ */
45
+ export const passwordFieldRecipe = {
46
+ slots: ["root", "frame", "input", "toggle", "description", "error"],
47
+ defaults: { size: "medium" },
48
+ frame: fieldFrameContract,
49
+ support: formSupportContract,
50
+ sizes: {
51
+ medium: {
52
+ minHeight: fieldFrameContract.minHeight,
53
+ paddingHorizontal: fieldFrameContract.paddingHorizontal,
54
+ textVariant: "body",
55
+ toggleDiameter: control.minTouchTarget,
56
+ },
57
+ large: {
58
+ minHeight: control.buttonHeight.large,
59
+ paddingHorizontal: spacing.lg,
60
+ textVariant: "bodyLarge",
61
+ toggleDiameter: control.minTouchTarget,
62
+ },
63
+ },
64
+ value: {
65
+ color: semanticColors.content.body,
66
+ },
67
+ toggle: {
68
+ /**
69
+ * Icon mirrors the same action-not-state judgment as the accessible
70
+ * name: concealed shows the "eye" (pressing reveals), revealed shows the
71
+ * "eye-off" (pressing conceals).
72
+ */
73
+ icons: {
74
+ concealed: "visibility",
75
+ revealed: "visibilityOff",
76
+ },
77
+ color: semanticColors.content.secondary,
78
+ },
79
+ states: {
80
+ focus: focusIndicatorContract,
81
+ invalidBorder: semanticColors.border.danger,
82
+ disabledOpacity: opacity.disabled,
83
+ },
84
+ };
85
+ export const passwordFieldBehavior = {
86
+ controlled: [
87
+ "value",
88
+ "defaultValue",
89
+ "onValueChange",
90
+ "revealed",
91
+ "defaultRevealed",
92
+ "onRevealedChange",
93
+ ],
94
+ inputs: ["autofillHint"],
95
+ stateAxes: {
96
+ availability: ["enabled", "disabled", "readOnly"],
97
+ value: ["empty", "filled"],
98
+ validation: ["valid", "invalid"],
99
+ },
100
+ web: {
101
+ roles: ["textbox", "button"],
102
+ keyboard: ["Tab", "Enter", "Space"],
103
+ focus: "native",
104
+ },
105
+ native: {
106
+ roles: ["text", "button"],
107
+ states: ["disabled"],
108
+ actions: ["focus", "setText", "toggleReveal"],
109
+ },
110
+ scenarios: [
111
+ "toggle-never-changes-the-controlled-value",
112
+ "toggle-and-value-are-independent-controlled-axes",
113
+ "toggle-accessible-name-describes-the-action-not-the-current-state",
114
+ "toggle-icon-mirrors-the-same-action-not-state-judgment",
115
+ "toggle-is-its-own-tab-stop-after-the-field-like-searchfields-clear-button",
116
+ "autofill-hint-is-a-required-product-decision-not-a-renderer-guess",
117
+ "strength-meter-is-out-of-scope-product-policy",
118
+ ],
119
+ };
120
+ //# sourceMappingURL=password-field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-field.js","sourceRoot":"","sources":["../src/password-field.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport type { ColorReference } from \"./color-references.js\";\nimport type { SemanticIconName } from \"./icon.js\";\nimport {\n fieldFrameContract,\n focusIndicatorContract,\n formSupportContract,\n} from \"./component-contracts.js\";\nimport { control, opacity, spacing, type TextVariant } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\n/**\n * PasswordField is Field's existing frame plus exactly one new problem: a\n * reveal toggle. It does not redeclare Field's own `value`/`onValueChange` —\n * a password's value is a plain string, identical to Field's, so there is\n * nothing new to contract there (unlike NumberField, whose value is a parsed\n * number). See docs/password-field.md.\n */\nexport type PasswordFieldAutofillHint = \"current\" | \"new\";\n\nexport type PasswordFieldDescriptor = Readonly<{\n revealed: boolean;\n /**\n * Which password-manager autofill bucket this field is for. Required, not\n * inferred — HJM cannot tell a login screen from a signup screen from the\n * descriptor alone, and guessing wrong actively harms the browser/OS\n * autofill suggestion. See docs/password-field.md for the platform\n * translation (Web autocomplete token, iOS textContentType, Android\n * autofill hint) — the exact attribute values are a renderer concern, not\n * asserted here.\n */\n autofillHint: PasswordFieldAutofillHint;\n}>;\n\nfunction assertBoolean(value: boolean, field: string): void {\n if (typeof value !== \"boolean\") {\n throw new TypeError(`PasswordField ${field} must be a boolean`);\n }\n}\n\nexport function validatePasswordFieldDescriptor(\n descriptor: PasswordFieldDescriptor,\n): void {\n assertBoolean(descriptor.revealed, \"revealed\");\n if (descriptor.autofillHint !== \"current\" && descriptor.autofillHint !== \"new\") {\n throw new TypeError(\n `Unsupported PasswordField autofillHint: ${String(descriptor.autofillHint)}`,\n );\n }\n}\n\nexport type PasswordToggleAccessibleNameInfo = Readonly<{\n /**\n * The action pressing the toggle will perform — not whether the password\n * is currently masked. See docs/password-field.md for why the name must\n * describe the action.\n */\n willReveal: boolean;\n}>;\n\nexport type ComposePasswordToggleAccessibleName = (\n info: PasswordToggleAccessibleNameInfo,\n) => string;\n\nexport type ResolvedPasswordFieldDescriptor = PasswordFieldDescriptor &\n Readonly<{\n toggleAccessibleName: string;\n webInputType: \"text\" | \"password\";\n nativeSecureTextEntry: boolean;\n }>;\n\nexport type ResolvePasswordFieldOptions = Readonly<{\n composeToggleAccessibleName: ComposePasswordToggleAccessibleName;\n}>;\n\n/**\n * Toggling `revealed` only ever changes how the value is displayed — it\n * never touches the value itself. That guarantee is why this resolver takes\n * no value parameter at all: there is nothing here that could reach into it.\n */\nexport function resolvePasswordFieldDescriptor(\n descriptor: PasswordFieldDescriptor,\n options: ResolvePasswordFieldOptions,\n): ResolvedPasswordFieldDescriptor {\n validatePasswordFieldDescriptor(descriptor);\n if (typeof options.composeToggleAccessibleName !== \"function\") {\n throw new TypeError(\n \"PasswordField composeToggleAccessibleName must be a function\",\n );\n }\n const toggleAccessibleName = options.composeToggleAccessibleName({\n willReveal: !descriptor.revealed,\n });\n if (\n typeof toggleAccessibleName !== \"string\" ||\n toggleAccessibleName.trim().length === 0\n ) {\n throw new TypeError(\n \"PasswordField composeToggleAccessibleName must return a non-empty string\",\n );\n }\n return {\n ...descriptor,\n toggleAccessibleName,\n webInputType: descriptor.revealed ? \"text\" : \"password\",\n nativeSecureTextEntry: !descriptor.revealed,\n };\n}\n\nexport type PasswordFieldSize = \"medium\" | \"large\";\n\n/**\n * Reuses Field's frame and form support copy verbatim — the same judgment\n * NumberField already made (see src/number-field.ts) — and adds only the\n * toggle slot, styled like SearchField's trailing clear button (same\n * diameter/hit-slop convention) but with the visibility icon pair instead.\n */\nexport const passwordFieldRecipe = {\n slots: [\"root\", \"frame\", \"input\", \"toggle\", \"description\", \"error\"] as const,\n defaults: { size: \"medium\" },\n frame: fieldFrameContract,\n support: formSupportContract,\n sizes: {\n medium: {\n minHeight: fieldFrameContract.minHeight,\n paddingHorizontal: fieldFrameContract.paddingHorizontal,\n textVariant: \"body\",\n toggleDiameter: control.minTouchTarget,\n },\n large: {\n minHeight: control.buttonHeight.large,\n paddingHorizontal: spacing.lg,\n textVariant: \"bodyLarge\",\n toggleDiameter: control.minTouchTarget,\n },\n },\n value: {\n color: semanticColors.content.body,\n },\n toggle: {\n /**\n * Icon mirrors the same action-not-state judgment as the accessible\n * name: concealed shows the \"eye\" (pressing reveals), revealed shows the\n * \"eye-off\" (pressing conceals).\n */\n icons: {\n concealed: \"visibility\",\n revealed: \"visibilityOff\",\n },\n color: semanticColors.content.secondary,\n },\n states: {\n focus: focusIndicatorContract,\n invalidBorder: semanticColors.border.danger,\n disabledOpacity: opacity.disabled,\n },\n} as const satisfies {\n slots: readonly string[];\n defaults: { size: PasswordFieldSize };\n frame: typeof fieldFrameContract;\n support: typeof formSupportContract;\n sizes: Record<\n PasswordFieldSize,\n {\n minHeight: number;\n paddingHorizontal: number;\n textVariant: TextVariant;\n toggleDiameter: number;\n }\n >;\n value: { color: ColorReference };\n toggle: {\n icons: Readonly<{ concealed: SemanticIconName; revealed: SemanticIconName }>;\n color: ColorReference;\n };\n states: {\n focus: typeof focusIndicatorContract;\n invalidBorder: ColorReference;\n disabledOpacity: number;\n };\n};\n\nexport const passwordFieldBehavior = {\n controlled: [\n \"value\",\n \"defaultValue\",\n \"onValueChange\",\n \"revealed\",\n \"defaultRevealed\",\n \"onRevealedChange\",\n ],\n inputs: [\"autofillHint\"],\n stateAxes: {\n availability: [\"enabled\", \"disabled\", \"readOnly\"],\n value: [\"empty\", \"filled\"],\n validation: [\"valid\", \"invalid\"],\n },\n web: {\n roles: [\"textbox\", \"button\"],\n keyboard: [\"Tab\", \"Enter\", \"Space\"],\n focus: \"native\",\n },\n native: {\n roles: [\"text\", \"button\"],\n states: [\"disabled\"],\n actions: [\"focus\", \"setText\", \"toggleReveal\"],\n },\n scenarios: [\n \"toggle-never-changes-the-controlled-value\",\n \"toggle-and-value-are-independent-controlled-axes\",\n \"toggle-accessible-name-describes-the-action-not-the-current-state\",\n \"toggle-icon-mirrors-the-same-action-not-state-judgment\",\n \"toggle-is-its-own-tab-stop-after-the-field-like-searchfields-clear-button\",\n \"autofill-hint-is-a-required-product-decision-not-a-renderer-guess\",\n \"strength-meter-is-out-of-scope-product-policy\",\n ],\n} as const satisfies BehaviorContract;\n"]}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Popover is the third corner of a triangle with Tooltip and Menu — all three
3
+ * are "a floating surface anchored to a trigger." Tooltip is explicitly
4
+ * plain-text and never receives focus (docs/tooltip.md: "interactive
5
+ * Popover로 확장하지 않는다"). Menu is a collection of actionable items with
6
+ * its own role/keyboard table (behaviorRegistry.menu). Popover is what is left:
7
+ * arbitrary *interactive* content (a small form, rich text with a link, a
8
+ * mixed layout) that is neither a single plain sentence nor an item list.
9
+ * Focus entering the surface is the decisive, testable difference from
10
+ * Tooltip — everything else here (dismiss reasons, non-modal posture) follows
11
+ * from that one fact.
12
+ */
13
+ export type PopoverPlacement = "top" | "bottom" | "start" | "end";
14
+ export type PopoverAlign = "start" | "center" | "end";
15
+ /**
16
+ * Popover is non-modal: it does not trap focus like Dialog/Sheet and does not
17
+ * block the rest of the page. So its dismiss vocabulary is deliberately
18
+ * narrower than SheetDismissReason — no "back" or "swipe" (this is a web-only
19
+ * surface), but it adds "outside-focus" because, unlike a modal, Tab can
20
+ * legitimately carry focus out of a non-modal surface and that departure is
21
+ * itself a dismiss signal distinct from a pointer click outside.
22
+ */
23
+ export type PopoverDismissReason = "close-action" | "outside-pointer" | "outside-focus" | "escape" | "programmatic";
24
+ /**
25
+ * 여는 사유는 `"trigger"`다. Sheet·SidePanel·CommandPalette가 모두 이 이름을 쓰고,
26
+ * `"trigger-activation"`은 `src/tooltip.ts`에서 **닫는** 사유(열려 있는 툴팁의
27
+ * 트리거를 눌러 닫는다)로 이미 쓰이고 있다. 한 문자열이 여는 뜻과 닫는 뜻을 겸하면
28
+ * 렌더러가 조용히 반대로 처리한다 — 컴파일러는 둘 다 유효한 문자열로만 본다.
29
+ */
30
+ export type PopoverOpenChangeReason = "trigger" | PopoverDismissReason;
31
+ export type PopoverOpenChangeDetails = Readonly<{
32
+ reason: PopoverOpenChangeReason;
33
+ }>;
34
+ export type PopoverDescriptor = Readonly<{
35
+ placement?: PopoverPlacement;
36
+ align?: PopoverAlign;
37
+ /**
38
+ * Only needed when the content has no visible heading the platform
39
+ * accessibility tree can already read as the surface's name. Most Popover
40
+ * content should carry its own heading; this is an escape hatch, not the
41
+ * default path.
42
+ */
43
+ accessibilityLabel?: string;
44
+ }>;
45
+ export type ResolvedPopoverDescriptor = Readonly<{
46
+ placement: PopoverPlacement;
47
+ align: PopoverAlign;
48
+ accessibilityLabel?: string;
49
+ }>;
50
+ export declare const popoverDescriptorDefaults: {
51
+ readonly placement: "bottom";
52
+ readonly align: "start";
53
+ };
54
+ /**
55
+ * A controlled owner's programmatic close always wins, exactly like
56
+ * SheetDismissPolicy/canDismissSheet. Popover has no `busy` axis: unlike
57
+ * Sheet/AlertDialog it is not modal, so there is no global "block every
58
+ * dismiss" state to defend — a form inside the content that wants to ignore
59
+ * Escape while submitting makes that call itself, at the content level.
60
+ */
61
+ export type PopoverDismissPolicy = Readonly<{
62
+ dismissible: boolean;
63
+ outsideDismiss: boolean;
64
+ escapeDismiss: boolean;
65
+ focusOutDismiss: boolean;
66
+ }>;
67
+ export declare const popoverBehaviorDefaults: {
68
+ readonly dismissible: true;
69
+ readonly outsideDismiss: true;
70
+ readonly escapeDismiss: true;
71
+ readonly focusOutDismiss: true;
72
+ };
73
+ export type ControlledPopoverOpenState = Readonly<{
74
+ open: boolean;
75
+ defaultOpen?: never;
76
+ onOpenChange(open: boolean, details: PopoverOpenChangeDetails): void;
77
+ }>;
78
+ export type UncontrolledPopoverOpenState = Readonly<{
79
+ open?: never;
80
+ defaultOpen?: boolean;
81
+ onOpenChange?: (open: boolean, details: PopoverOpenChangeDetails) => void;
82
+ }>;
83
+ export type PopoverOpenState = ControlledPopoverOpenState | UncontrolledPopoverOpenState;
84
+ /** Products own what page-change caused this; Popover only needs "did it happen and how." */
85
+ export type PopoverChangeHandler = PopoverOpenState["onOpenChange"];
86
+ export declare function validatePopoverDescriptor(descriptor: PopoverDescriptor): void;
87
+ export declare function resolvePopoverDescriptor(descriptor: PopoverDescriptor): ResolvedPopoverDescriptor;
88
+ export declare function validatePopoverOpenState(state: PopoverOpenState): void;
89
+ /**
90
+ * Resolves an attempted close without platform knowledge, mirroring
91
+ * canDismissSheet. Programmatic close is always an owner override.
92
+ */
93
+ export declare function canDismissPopover(reason: PopoverDismissReason, policy?: PopoverDismissPolicy): boolean;
94
+ /**
95
+ * Positioning boundary is identical to Tooltip's: HJM owns preferred
96
+ * placement, spacing, and motion; DOM measurement, portal, flip/shift, and
97
+ * RTL logical-to-physical translation stay in the product Web renderer's
98
+ * private AnchoredOverlay (see docs/tooltip.md "Positioning boundary"). This
99
+ * module never exposes that internal tool, so Popover cannot regress Tooltip's
100
+ * "no public collision/portal API" boundary.
101
+ */
102
+ export declare const popoverRecipe: {
103
+ readonly slots: readonly ["trigger", "content", "arrow", "closeAction"];
104
+ readonly surface: {
105
+ readonly background: Readonly<{
106
+ source: "theme";
107
+ key: "bg";
108
+ alpha?: number;
109
+ }>;
110
+ readonly border: Readonly<{
111
+ source: "theme";
112
+ key: "border";
113
+ alpha?: number;
114
+ }>;
115
+ readonly borderWidth: 1;
116
+ readonly radius: "md";
117
+ readonly shadow: {
118
+ readonly color: "#000000";
119
+ readonly opacity: 0.12;
120
+ readonly radius: 12;
121
+ readonly offsetY: 4;
122
+ };
123
+ readonly padding: 8;
124
+ };
125
+ readonly arrow: {
126
+ readonly size: 4;
127
+ readonly offset: 4;
128
+ };
129
+ readonly sideOffset: 8;
130
+ readonly collisionPadding: 8;
131
+ readonly minWidth: 240;
132
+ readonly maxWidth: 360;
133
+ readonly transition: {
134
+ readonly enter: {
135
+ readonly duration: 200;
136
+ readonly easing: "enter";
137
+ readonly reducedMotion: "opacity";
138
+ };
139
+ readonly exit: {
140
+ readonly duration: 120;
141
+ readonly easing: "exit";
142
+ readonly reducedMotion: "instant";
143
+ };
144
+ };
145
+ };
146
+ /**
147
+ * Literal scenario names for behaviorRegistry.popover (lead wires into
148
+ * src/behaviors.ts). Kept here, not there, so this module stays self-contained
149
+ * per the authoring brief.
150
+ */
151
+ export declare const popoverBehaviorScenarios: readonly ["focus-enters-surface-on-open", "escape-closes-and-restores-trigger-focus", "outside-pointer-close-does-not-cancel-the-original-interaction", "tabbing-past-last-focusable-child-closes-without-trapping", "controlled-owner-programmatic-close-always-wins", "close-action-inside-content-closes-exactly-once", "trigger-while-open-does-not-reopen", "one-visible-popover-per-trigger"];
152
+ //# sourceMappingURL=popover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popover.d.ts","sourceRoot":"","sources":["../src/popover.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAC;AAClE,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEtD;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAC5B,cAAc,GACd,iBAAiB,GACjB,eAAe,GACf,QAAQ,GACR,cAAc,CAAC;AAEnB;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,oBAAoB,CAAC;AAEvE,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,MAAM,EAAE,uBAAuB,CAAC;CACjC,CAAC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC,CAAC;AAEH,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAC/C,SAAS,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,YAAY,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;CAG6C,CAAC;AAEpF;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC;IAC1C,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC,CAAC;AAEH,eAAO,MAAM,uBAAuB;;;;;CAKK,CAAC;AAE1C,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,KAAK,CAAC;IACpB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAAC;CACtE,CAAC,CAAC;AAEH,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC;IAClD,IAAI,CAAC,EAAE,KAAK,CAAC;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CACb,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,wBAAwB,KAC9B,IAAI,CAAC;CACX,CAAC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GACxB,0BAA0B,GAC1B,4BAA4B,CAAC;AAEjC,6FAA6F;AAC7F,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,CAAC,cAAc,CAAC,CAAC;AAuBpE,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI,CA6B7E;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,iBAAiB,GAC5B,yBAAyB,CAS3B;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAgCtE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,oBAAoB,EAC5B,MAAM,GAAE,oBAA8C,GACrD,OAAO,CAOT;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkBzB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,qYAS3B,CAAC"}
@@ -0,0 +1,137 @@
1
+ import { floatingSurfaceContract } from "./component-contracts.js";
2
+ import { motionPreset, spacing } from "./foundations.js";
3
+ export const popoverDescriptorDefaults = {
4
+ placement: "bottom",
5
+ align: "start",
6
+ };
7
+ export const popoverBehaviorDefaults = {
8
+ dismissible: true,
9
+ outsideDismiss: true,
10
+ escapeDismiss: true,
11
+ focusOutDismiss: true,
12
+ };
13
+ const placements = new Set(["top", "bottom", "start", "end"]);
14
+ const alignments = new Set(["start", "center", "end"]);
15
+ const descriptorKeys = new Set(["placement", "align", "accessibilityLabel"]);
16
+ const openStateKeys = new Set(["open", "defaultOpen", "onOpenChange"]);
17
+ function isObject(value) {
18
+ return value !== null && typeof value === "object" && !Array.isArray(value);
19
+ }
20
+ function rejectUnknownKeys(value, allowed, field) {
21
+ for (const key of Object.keys(value)) {
22
+ if (!allowed.has(key)) {
23
+ throw new TypeError(`Unsupported Popover ${field} field: ${key}`);
24
+ }
25
+ }
26
+ }
27
+ export function validatePopoverDescriptor(descriptor) {
28
+ if (!isObject(descriptor)) {
29
+ throw new TypeError("Popover descriptor must be an object");
30
+ }
31
+ rejectUnknownKeys(descriptor, descriptorKeys, "descriptor");
32
+ if (descriptor.placement !== undefined &&
33
+ !placements.has(descriptor.placement)) {
34
+ throw new TypeError(`Unsupported Popover placement: ${String(descriptor.placement)}`);
35
+ }
36
+ if (descriptor.align !== undefined && !alignments.has(descriptor.align)) {
37
+ throw new TypeError(`Unsupported Popover align: ${String(descriptor.align)}`);
38
+ }
39
+ if (descriptor.accessibilityLabel !== undefined) {
40
+ if (typeof descriptor.accessibilityLabel !== "string" ||
41
+ descriptor.accessibilityLabel.trim().length === 0) {
42
+ throw new TypeError("Popover accessibilityLabel must not be empty");
43
+ }
44
+ if (descriptor.accessibilityLabel !== descriptor.accessibilityLabel.trim()) {
45
+ throw new TypeError("Popover accessibilityLabel must not start or end with whitespace");
46
+ }
47
+ }
48
+ }
49
+ export function resolvePopoverDescriptor(descriptor) {
50
+ validatePopoverDescriptor(descriptor);
51
+ return {
52
+ placement: descriptor.placement ?? popoverDescriptorDefaults.placement,
53
+ align: descriptor.align ?? popoverDescriptorDefaults.align,
54
+ ...(descriptor.accessibilityLabel !== undefined
55
+ ? { accessibilityLabel: descriptor.accessibilityLabel }
56
+ : {}),
57
+ };
58
+ }
59
+ export function validatePopoverOpenState(state) {
60
+ if (!isObject(state)) {
61
+ throw new TypeError("Popover open state must be an object");
62
+ }
63
+ rejectUnknownKeys(state, openStateKeys, "open state");
64
+ const runtime = state;
65
+ const hasOpen = Object.prototype.hasOwnProperty.call(runtime, "open");
66
+ const hasDefaultOpen = Object.prototype.hasOwnProperty.call(runtime, "defaultOpen");
67
+ if (hasOpen) {
68
+ if (typeof runtime.open !== "boolean") {
69
+ throw new TypeError("Popover open must be a boolean");
70
+ }
71
+ if (hasDefaultOpen) {
72
+ throw new TypeError("Controlled Popover must not provide defaultOpen");
73
+ }
74
+ if (typeof runtime.onOpenChange !== "function") {
75
+ throw new TypeError("Controlled Popover must provide onOpenChange");
76
+ }
77
+ return;
78
+ }
79
+ if (hasDefaultOpen && typeof runtime.defaultOpen !== "boolean") {
80
+ throw new TypeError("Popover defaultOpen must be a boolean");
81
+ }
82
+ if (runtime.onOpenChange !== undefined &&
83
+ typeof runtime.onOpenChange !== "function") {
84
+ throw new TypeError("Popover onOpenChange must be a function");
85
+ }
86
+ }
87
+ /**
88
+ * Resolves an attempted close without platform knowledge, mirroring
89
+ * canDismissSheet. Programmatic close is always an owner override.
90
+ */
91
+ export function canDismissPopover(reason, policy = popoverBehaviorDefaults) {
92
+ if (reason === "programmatic")
93
+ return true;
94
+ if (!policy.dismissible)
95
+ return false;
96
+ if (reason === "outside-pointer")
97
+ return policy.outsideDismiss;
98
+ if (reason === "outside-focus")
99
+ return policy.focusOutDismiss;
100
+ if (reason === "escape")
101
+ return policy.escapeDismiss;
102
+ return true;
103
+ }
104
+ /**
105
+ * Positioning boundary is identical to Tooltip's: HJM owns preferred
106
+ * placement, spacing, and motion; DOM measurement, portal, flip/shift, and
107
+ * RTL logical-to-physical translation stay in the product Web renderer's
108
+ * private AnchoredOverlay (see docs/tooltip.md "Positioning boundary"). This
109
+ * module never exposes that internal tool, so Popover cannot regress Tooltip's
110
+ * "no public collision/portal API" boundary.
111
+ */
112
+ export const popoverRecipe = {
113
+ slots: ["trigger", "content", "arrow", "closeAction"],
114
+ surface: floatingSurfaceContract,
115
+ arrow: { size: spacing.xxs, offset: spacing.xxs },
116
+ sideOffset: spacing.xs,
117
+ collisionPadding: spacing.xs,
118
+ minWidth: 240,
119
+ maxWidth: 360,
120
+ transition: { enter: motionPreset.enter, exit: motionPreset.exit },
121
+ };
122
+ /**
123
+ * Literal scenario names for behaviorRegistry.popover (lead wires into
124
+ * src/behaviors.ts). Kept here, not there, so this module stays self-contained
125
+ * per the authoring brief.
126
+ */
127
+ export const popoverBehaviorScenarios = [
128
+ "focus-enters-surface-on-open",
129
+ "escape-closes-and-restores-trigger-focus",
130
+ "outside-pointer-close-does-not-cancel-the-original-interaction",
131
+ "tabbing-past-last-focusable-child-closes-without-trapping",
132
+ "controlled-owner-programmatic-close-always-wins",
133
+ "close-action-inside-content-closes-exactly-once",
134
+ "trigger-while-open-does-not-reopen",
135
+ "one-visible-popover-per-trigger",
136
+ ];
137
+ //# sourceMappingURL=popover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"popover.js","sourceRoot":"","sources":["../src/popover.ts"],"names":[],"mappings":"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","sourcesContent":["import { floatingSurfaceContract } from \"./component-contracts.js\";\nimport { motionPreset, spacing } from \"./foundations.js\";\n\n/**\n * Popover is the third corner of a triangle with Tooltip and Menu — all three\n * are \"a floating surface anchored to a trigger.\" Tooltip is explicitly\n * plain-text and never receives focus (docs/tooltip.md: \"interactive\n * Popover로 확장하지 않는다\"). Menu is a collection of actionable items with\n * its own role/keyboard table (behaviorRegistry.menu). Popover is what is left:\n * arbitrary *interactive* content (a small form, rich text with a link, a\n * mixed layout) that is neither a single plain sentence nor an item list.\n * Focus entering the surface is the decisive, testable difference from\n * Tooltip — everything else here (dismiss reasons, non-modal posture) follows\n * from that one fact.\n */\nexport type PopoverPlacement = \"top\" | \"bottom\" | \"start\" | \"end\";\nexport type PopoverAlign = \"start\" | \"center\" | \"end\";\n\n/**\n * Popover is non-modal: it does not trap focus like Dialog/Sheet and does not\n * block the rest of the page. So its dismiss vocabulary is deliberately\n * narrower than SheetDismissReason — no \"back\" or \"swipe\" (this is a web-only\n * surface), but it adds \"outside-focus\" because, unlike a modal, Tab can\n * legitimately carry focus out of a non-modal surface and that departure is\n * itself a dismiss signal distinct from a pointer click outside.\n */\nexport type PopoverDismissReason =\n | \"close-action\"\n | \"outside-pointer\"\n | \"outside-focus\"\n | \"escape\"\n | \"programmatic\";\n\n/**\n * 여는 사유는 `\"trigger\"`다. Sheet·SidePanel·CommandPalette가 모두 이 이름을 쓰고,\n * `\"trigger-activation\"`은 `src/tooltip.ts`에서 **닫는** 사유(열려 있는 툴팁의\n * 트리거를 눌러 닫는다)로 이미 쓰이고 있다. 한 문자열이 여는 뜻과 닫는 뜻을 겸하면\n * 렌더러가 조용히 반대로 처리한다 — 컴파일러는 둘 다 유효한 문자열로만 본다.\n */\nexport type PopoverOpenChangeReason = \"trigger\" | PopoverDismissReason;\n\nexport type PopoverOpenChangeDetails = Readonly<{\n reason: PopoverOpenChangeReason;\n}>;\n\nexport type PopoverDescriptor = Readonly<{\n placement?: PopoverPlacement;\n align?: PopoverAlign;\n /**\n * Only needed when the content has no visible heading the platform\n * accessibility tree can already read as the surface's name. Most Popover\n * content should carry its own heading; this is an escape hatch, not the\n * default path.\n */\n accessibilityLabel?: string;\n}>;\n\nexport type ResolvedPopoverDescriptor = Readonly<{\n placement: PopoverPlacement;\n align: PopoverAlign;\n accessibilityLabel?: string;\n}>;\n\nexport const popoverDescriptorDefaults = {\n placement: \"bottom\",\n align: \"start\",\n} as const satisfies Readonly<{ placement: PopoverPlacement; align: PopoverAlign }>;\n\n/**\n * A controlled owner's programmatic close always wins, exactly like\n * SheetDismissPolicy/canDismissSheet. Popover has no `busy` axis: unlike\n * Sheet/AlertDialog it is not modal, so there is no global \"block every\n * dismiss\" state to defend — a form inside the content that wants to ignore\n * Escape while submitting makes that call itself, at the content level.\n */\nexport type PopoverDismissPolicy = Readonly<{\n dismissible: boolean;\n outsideDismiss: boolean;\n escapeDismiss: boolean;\n focusOutDismiss: boolean;\n}>;\n\nexport const popoverBehaviorDefaults = {\n dismissible: true,\n outsideDismiss: true,\n escapeDismiss: true,\n focusOutDismiss: true,\n} as const satisfies PopoverDismissPolicy;\n\nexport type ControlledPopoverOpenState = Readonly<{\n open: boolean;\n defaultOpen?: never;\n onOpenChange(open: boolean, details: PopoverOpenChangeDetails): void;\n}>;\n\nexport type UncontrolledPopoverOpenState = Readonly<{\n open?: never;\n defaultOpen?: boolean;\n onOpenChange?: (\n open: boolean,\n details: PopoverOpenChangeDetails,\n ) => void;\n}>;\n\nexport type PopoverOpenState =\n | ControlledPopoverOpenState\n | UncontrolledPopoverOpenState;\n\n/** Products own what page-change caused this; Popover only needs \"did it happen and how.\" */\nexport type PopoverChangeHandler = PopoverOpenState[\"onOpenChange\"];\n\nconst placements = new Set<PopoverPlacement>([\"top\", \"bottom\", \"start\", \"end\"]);\nconst alignments = new Set<PopoverAlign>([\"start\", \"center\", \"end\"]);\nconst descriptorKeys = new Set([\"placement\", \"align\", \"accessibilityLabel\"]);\nconst openStateKeys = new Set([\"open\", \"defaultOpen\", \"onOpenChange\"]);\n\nfunction isObject(value: unknown): value is Readonly<Record<string, unknown>> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction rejectUnknownKeys(\n value: Readonly<Record<string, unknown>>,\n allowed: ReadonlySet<string>,\n field: string,\n): void {\n for (const key of Object.keys(value)) {\n if (!allowed.has(key)) {\n throw new TypeError(`Unsupported Popover ${field} field: ${key}`);\n }\n }\n}\n\nexport function validatePopoverDescriptor(descriptor: PopoverDescriptor): void {\n if (!isObject(descriptor)) {\n throw new TypeError(\"Popover descriptor must be an object\");\n }\n rejectUnknownKeys(descriptor, descriptorKeys, \"descriptor\");\n if (\n descriptor.placement !== undefined &&\n !placements.has(descriptor.placement)\n ) {\n throw new TypeError(\n `Unsupported Popover placement: ${String(descriptor.placement)}`,\n );\n }\n if (descriptor.align !== undefined && !alignments.has(descriptor.align)) {\n throw new TypeError(`Unsupported Popover align: ${String(descriptor.align)}`);\n }\n if (descriptor.accessibilityLabel !== undefined) {\n if (\n typeof descriptor.accessibilityLabel !== \"string\" ||\n descriptor.accessibilityLabel.trim().length === 0\n ) {\n throw new TypeError(\"Popover accessibilityLabel must not be empty\");\n }\n if (descriptor.accessibilityLabel !== descriptor.accessibilityLabel.trim()) {\n throw new TypeError(\n \"Popover accessibilityLabel must not start or end with whitespace\",\n );\n }\n }\n}\n\nexport function resolvePopoverDescriptor(\n descriptor: PopoverDescriptor,\n): ResolvedPopoverDescriptor {\n validatePopoverDescriptor(descriptor);\n return {\n placement: descriptor.placement ?? popoverDescriptorDefaults.placement,\n align: descriptor.align ?? popoverDescriptorDefaults.align,\n ...(descriptor.accessibilityLabel !== undefined\n ? { accessibilityLabel: descriptor.accessibilityLabel }\n : {}),\n };\n}\n\nexport function validatePopoverOpenState(state: PopoverOpenState): void {\n if (!isObject(state)) {\n throw new TypeError(\"Popover open state must be an object\");\n }\n rejectUnknownKeys(state, openStateKeys, \"open state\");\n const runtime = state as Readonly<Record<string, unknown>>;\n const hasOpen = Object.prototype.hasOwnProperty.call(runtime, \"open\");\n const hasDefaultOpen = Object.prototype.hasOwnProperty.call(\n runtime,\n \"defaultOpen\",\n );\n if (hasOpen) {\n if (typeof runtime.open !== \"boolean\") {\n throw new TypeError(\"Popover open must be a boolean\");\n }\n if (hasDefaultOpen) {\n throw new TypeError(\"Controlled Popover must not provide defaultOpen\");\n }\n if (typeof runtime.onOpenChange !== \"function\") {\n throw new TypeError(\"Controlled Popover must provide onOpenChange\");\n }\n return;\n }\n if (hasDefaultOpen && typeof runtime.defaultOpen !== \"boolean\") {\n throw new TypeError(\"Popover defaultOpen must be a boolean\");\n }\n if (\n runtime.onOpenChange !== undefined &&\n typeof runtime.onOpenChange !== \"function\"\n ) {\n throw new TypeError(\"Popover onOpenChange must be a function\");\n }\n}\n\n/**\n * Resolves an attempted close without platform knowledge, mirroring\n * canDismissSheet. Programmatic close is always an owner override.\n */\nexport function canDismissPopover(\n reason: PopoverDismissReason,\n policy: PopoverDismissPolicy = popoverBehaviorDefaults,\n): boolean {\n if (reason === \"programmatic\") return true;\n if (!policy.dismissible) return false;\n if (reason === \"outside-pointer\") return policy.outsideDismiss;\n if (reason === \"outside-focus\") return policy.focusOutDismiss;\n if (reason === \"escape\") return policy.escapeDismiss;\n return true;\n}\n\n/**\n * Positioning boundary is identical to Tooltip's: HJM owns preferred\n * placement, spacing, and motion; DOM measurement, portal, flip/shift, and\n * RTL logical-to-physical translation stay in the product Web renderer's\n * private AnchoredOverlay (see docs/tooltip.md \"Positioning boundary\"). This\n * module never exposes that internal tool, so Popover cannot regress Tooltip's\n * \"no public collision/portal API\" boundary.\n */\nexport const popoverRecipe = {\n slots: [\"trigger\", \"content\", \"arrow\", \"closeAction\"] as const,\n surface: floatingSurfaceContract,\n arrow: { size: spacing.xxs, offset: spacing.xxs },\n sideOffset: spacing.xs,\n collisionPadding: spacing.xs,\n minWidth: 240,\n maxWidth: 360,\n transition: { enter: motionPreset.enter, exit: motionPreset.exit },\n} as const satisfies {\n slots: readonly string[];\n surface: typeof floatingSurfaceContract;\n arrow: { size: number; offset: number };\n sideOffset: number;\n collisionPadding: number;\n minWidth: number;\n maxWidth: number;\n transition: { enter: typeof motionPreset.enter; exit: typeof motionPreset.exit };\n};\n\n/**\n * Literal scenario names for behaviorRegistry.popover (lead wires into\n * src/behaviors.ts). Kept here, not there, so this module stays self-contained\n * per the authoring brief.\n */\nexport const popoverBehaviorScenarios = [\n \"focus-enters-surface-on-open\",\n \"escape-closes-and-restores-trigger-focus\",\n \"outside-pointer-close-does-not-cancel-the-original-interaction\",\n \"tabbing-past-last-focusable-child-closes-without-trapping\",\n \"controlled-owner-programmatic-close-always-wins\",\n \"close-action-inside-content-closes-exactly-once\",\n \"trigger-while-open-does-not-reopen\",\n \"one-visible-popover-per-trigger\",\n] as const;\n"]}
@@ -0,0 +1,43 @@
1
+ export declare const progressRecipe: {
2
+ readonly slots: readonly ["root", "track", "indicator", "label", "value"];
3
+ readonly defaults: {
4
+ readonly size: "medium";
5
+ readonly tone: "brand";
6
+ };
7
+ readonly sizes: {
8
+ readonly small: 4;
9
+ readonly medium: 8;
10
+ readonly large: 12;
11
+ };
12
+ readonly tones: {
13
+ readonly brand: Readonly<{
14
+ source: "theme";
15
+ key: "contentBrand";
16
+ alpha?: number;
17
+ }>;
18
+ readonly success: Readonly<{
19
+ source: "accent";
20
+ key: "success";
21
+ alpha?: number;
22
+ }>;
23
+ readonly warning: Readonly<{
24
+ source: "accent";
25
+ key: "warning";
26
+ alpha?: number;
27
+ }>;
28
+ readonly danger: Readonly<{
29
+ source: "theme";
30
+ key: "danger";
31
+ alpha?: number;
32
+ }>;
33
+ };
34
+ readonly track: Readonly<{
35
+ source: "theme";
36
+ key: "surfaceAlt";
37
+ alpha?: number;
38
+ }>;
39
+ readonly radius: "full";
40
+ };
41
+ export type ProgressSize = keyof typeof progressRecipe.sizes;
42
+ export type ProgressTone = keyof typeof progressRecipe.tones;
43
+ //# sourceMappingURL=progress-recipe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-recipe.d.ts","sourceRoot":"","sources":["../src/progress-recipe.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmB1B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,cAAc,CAAC,KAAK,CAAC;AAC7D,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,cAAc,CAAC,KAAK,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { radius } from "./foundations.js";
2
+ import { semanticColors } from "./semantic-colors.js";
3
+ export const progressRecipe = {
4
+ slots: ["root", "track", "indicator", "label", "value"],
5
+ defaults: { size: "medium", tone: "brand" },
6
+ sizes: { small: 4, medium: 8, large: 12 },
7
+ tones: {
8
+ brand: semanticColors.content.brand,
9
+ success: semanticColors.feedback.success.foreground,
10
+ warning: semanticColors.feedback.warning.foreground,
11
+ danger: semanticColors.content.danger,
12
+ },
13
+ track: semanticColors.surface.sunken,
14
+ radius: "full",
15
+ };
16
+ //# sourceMappingURL=progress-recipe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-recipe.js","sourceRoot":"","sources":["../src/progress-recipe.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,CAAU;IAChE,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE;IAC3C,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IACzC,KAAK,EAAE;QACL,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,KAAK;QACnC,OAAO,EAAE,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU;QACnD,OAAO,EAAE,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU;QACnD,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM;KACtC;IACD,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM;IACpC,MAAM,EAAE,MAAM;CAQf,CAAC","sourcesContent":["import type { ColorReference } from \"./color-references.js\";\nimport { radius } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\n\nexport const progressRecipe = {\n slots: [\"root\", \"track\", \"indicator\", \"label\", \"value\"] as const,\n defaults: { size: \"medium\", tone: \"brand\" },\n sizes: { small: 4, medium: 8, large: 12 },\n tones: {\n brand: semanticColors.content.brand,\n success: semanticColors.feedback.success.foreground,\n warning: semanticColors.feedback.warning.foreground,\n danger: semanticColors.content.danger,\n },\n track: semanticColors.surface.sunken,\n radius: \"full\",\n} as const satisfies {\n radius: keyof typeof radius;\n slots: readonly string[];\n defaults: { size: \"small\" | \"medium\" | \"large\"; tone: \"brand\" | \"success\" | \"warning\" | \"danger\" };\n sizes: Record<\"small\" | \"medium\" | \"large\", number>;\n tones: Record<\"brand\" | \"success\" | \"warning\" | \"danger\", ColorReference>;\n track: ColorReference;\n};\n\nexport type ProgressSize = keyof typeof progressRecipe.sizes;\nexport type ProgressTone = keyof typeof progressRecipe.tones;\n"]}
@@ -0,0 +1,31 @@
1
+ export { buttonRecipe, fieldRecipe, surfaceDefaults, surfaceGeometry, surfaceRecipe, type ButtonSize, type ButtonTone, type FieldShape, type FieldVariant, type SurfacePadding, type SurfaceRadius, type SurfaceTone, } from "./base-recipes.js";
2
+ export { accordionRecipe, alertDialogRecipe, avatarRecipe, badgeRecipe, bottomNavigationRecipe, bottomCtaRecipe, chipRecipe, comboboxRecipe, counterBadgeRecipe, dialogRecipe, dividerRecipe, emptyStateRecipe, formatCounterBadgeCount, iconButtonRecipe, iconRecipe, linkRecipe, listRecipe, listRowRecipe, loadMoreRecipe, menuRecipe, noticeRecipe, progressRecipe, searchFieldRecipe, selectRecipe, selectionGroupRecipe, sectionRecipe, segmentedControlRecipe, selectionControlRecipe, sheetRecipe, skeletonRecipe, spinnerRecipe, stackRecipe, statisticRecipe, switchRecipe, tabsRecipe, textRecipe, toastRecipe, tooltipRecipe, topBarRecipe, type AccordionDensity, type AlertDialogTone, type AvatarShape, type AvatarSize, type BadgeSize, type BadgeTone, type BadgeVariant, type BottomNavigationDensity, type BottomNavigationDistribution, type BottomNavigationPresentation, type ChipSize, type SelectDensity, type SelectSize, type CounterBadgeSize, type CounterBadgeTone, type CounterBadgeVariant, type DialogSize, type IconButtonShape, type IconButtonSize, type IconTone, type IconWeight, type LinkTone, type LinkVariant, type LoadMoreDensity, type ListRowDensity, type MenuDensity, type MenuItemTone, type NoticeTone, type ProgressSize, type ProgressTone, type SearchFieldSize, type SegmentedControlSize, type SelectionControlKind, type SelectionControlPresentation, type SelectionControlSize, type SelectionGroupOrientation, type SelectionGroupPresentation, type SpinnerSize, type SpinnerTone, type StackAlign, type StackAxis, type StackGap, type StackJustify, type StatisticDensity, type StatisticPresentation, type SwitchSize, type TabSize, type TabsLayout, type TabsOverflow, type TextEmphasis, type TextTone, type ToastPlacement, type ToastTone, type ToastToneMark, } from "./component-recipes.js";
3
+ export { breadcrumbRecipe } from "./breadcrumb.js";
4
+ export { cardRecipe, type CardHeadingLevel } from "./card.js";
5
+ export { calendarRecipe } from "./calendar.js";
6
+ export { carouselRecipe } from "./carousel.js";
7
+ export { commandPaletteRecipe } from "./command-palette.js";
8
+ export { dataTableRecipe } from "./data-table.js";
9
+ export { transferListRecipe } from "./transfer-list.js";
10
+ export { tourRecipe } from "./tour.js";
11
+ export { layoutRecipe } from "./layout.js";
12
+ export { otpFieldRecipe } from "./otp-field.js";
13
+ export { passwordFieldRecipe } from "./password-field.js";
14
+ export { splitterRecipe } from "./splitter.js";
15
+ export { datePickerRecipe } from "./date-picker.js";
16
+ export { descriptionListRecipe } from "./description-list.js";
17
+ export { filePickerRecipe } from "./file-picker.js";
18
+ export { formRecipe } from "./form.js";
19
+ export { imageRecipe } from "./image.js";
20
+ export { numberFieldRecipe } from "./number-field.js";
21
+ export { paginationRecipe } from "./pagination.js";
22
+ export { popoverRecipe } from "./popover.js";
23
+ export { resultRecipe } from "./result.js";
24
+ export { sliderRecipe } from "./slider.js";
25
+ export { stepsRecipe } from "./steps.js";
26
+ export { tagRecipe } from "./tag.js";
27
+ export { sidePanelRecipe } from "./side-panel.js";
28
+ export { timelineRecipe } from "./timeline.js";
29
+ export { treeRecipe } from "./tree.js";
30
+ export { uploadItemRecipe } from "./upload-item.js";
31
+ //# sourceMappingURL=recipes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recipes.d.ts","sourceRoot":"","sources":["../src/recipes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ export { buttonRecipe, fieldRecipe, surfaceDefaults, surfaceGeometry, surfaceRecipe, } from "./base-recipes.js";
2
+ export { accordionRecipe, alertDialogRecipe, avatarRecipe, badgeRecipe, bottomNavigationRecipe, bottomCtaRecipe, chipRecipe, comboboxRecipe, counterBadgeRecipe, dialogRecipe, dividerRecipe, emptyStateRecipe, formatCounterBadgeCount, iconButtonRecipe, iconRecipe, linkRecipe, listRecipe, listRowRecipe, loadMoreRecipe, menuRecipe, noticeRecipe, progressRecipe, searchFieldRecipe, selectRecipe, selectionGroupRecipe, sectionRecipe, segmentedControlRecipe, selectionControlRecipe, sheetRecipe, skeletonRecipe, spinnerRecipe, stackRecipe, statisticRecipe, switchRecipe, tabsRecipe, textRecipe, toastRecipe, tooltipRecipe, topBarRecipe, } from "./component-recipes.js";
3
+ /*
4
+ Batch 2 저작 모듈의 시각 recipe.
5
+
6
+ 각 컴포넌트의 계약·recipe·행동을 한 모듈에 자급자족으로 담고, 여기서는 **경로만**
7
+ 모은다(`docs/authoring-brief.md`). 여러 저작자가 병렬로 작업할 때 공유 레지스트리를
8
+ 각자 고치면 서로의 변경을 덮어쓰므로, 배선은 리드가 한 번에 한다.
9
+
10
+ recipe 본문을 `component-recipes.ts`로 옮기지 않는 이유: 그 파일은 이미 1,500줄이 넘고,
11
+ 계약(타입·validator·resolver)과 recipe가 **같은 컴포넌트를 두 파일로 갈라** 놓으면
12
+ 둘이 어긋날 자리가 생긴다. 한 컴포넌트는 한 모듈에 둔다.
13
+ */
14
+ export { breadcrumbRecipe } from "./breadcrumb.js";
15
+ export { cardRecipe } from "./card.js";
16
+ export { calendarRecipe } from "./calendar.js";
17
+ export { carouselRecipe } from "./carousel.js";
18
+ export { commandPaletteRecipe } from "./command-palette.js";
19
+ export { dataTableRecipe } from "./data-table.js";
20
+ export { transferListRecipe } from "./transfer-list.js";
21
+ // floatingActionButtonRecipe는 여기서 재수출하지 않는다. 이 모듈이 buttonRecipe를
22
+ // 정의하는데 floating-action-button.ts가 그것을 import하므로, 여기에 `export ... from`을
23
+ // 두면 순환이 된다 — ESM은 재수출을 본문보다 먼저 평가해서 buttonRecipe가 아직
24
+ // undefined인 채로 그 모듈이 실행된다. catalog.ts가 해당 모듈에서 직접 가져간다.
25
+ export { tourRecipe } from "./tour.js";
26
+ export { layoutRecipe } from "./layout.js";
27
+ export { otpFieldRecipe } from "./otp-field.js";
28
+ export { passwordFieldRecipe } from "./password-field.js";
29
+ export { splitterRecipe } from "./splitter.js";
30
+ export { datePickerRecipe } from "./date-picker.js";
31
+ export { descriptionListRecipe } from "./description-list.js";
32
+ export { filePickerRecipe } from "./file-picker.js";
33
+ export { formRecipe } from "./form.js";
34
+ export { imageRecipe } from "./image.js";
35
+ export { numberFieldRecipe } from "./number-field.js";
36
+ export { paginationRecipe } from "./pagination.js";
37
+ export { popoverRecipe } from "./popover.js";
38
+ export { resultRecipe } from "./result.js";
39
+ export { sliderRecipe } from "./slider.js";
40
+ export { stepsRecipe } from "./steps.js";
41
+ export { tagRecipe } from "./tag.js";
42
+ export { sidePanelRecipe } from "./side-panel.js";
43
+ export { timelineRecipe } from "./timeline.js";
44
+ export { treeRecipe } from "./tree.js";
45
+ export { uploadItemRecipe } from "./upload-item.js";
46
+ //# sourceMappingURL=recipes.js.map