@godxjp/ui 28.9.0 → 28.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/agent/START-HERE.md +193 -0
  2. package/agent/anti-ai-tells.json +158 -0
  3. package/agent/components/Accordion.json +60 -0
  4. package/agent/components/AccountChip.json +59 -0
  5. package/agent/components/Actions.json +78 -0
  6. package/agent/components/Activity.json +80 -0
  7. package/agent/components/Affix.json +78 -0
  8. package/agent/components/Alert.json +65 -0
  9. package/agent/components/AlertDialog.json +109 -0
  10. package/agent/components/AlertDialogRoot.json +52 -0
  11. package/agent/components/Anchor.json +119 -0
  12. package/agent/components/AppLauncher.json +95 -0
  13. package/agent/components/AppProvider.json +105 -0
  14. package/agent/components/AppSettingPicker.json +88 -0
  15. package/agent/components/AppSettingToggle.json +70 -0
  16. package/agent/components/AppShell.json +159 -0
  17. package/agent/components/AreaChart.json +105 -0
  18. package/agent/components/AspectRatio.json +38 -0
  19. package/agent/components/Attachments.json +77 -0
  20. package/agent/components/AuthAccountSummary.json +64 -0
  21. package/agent/components/AuthDivider.json +35 -0
  22. package/agent/components/AuthFooter.json +48 -0
  23. package/agent/components/AuthIdentity.json +42 -0
  24. package/agent/components/AuthShell.json +108 -0
  25. package/agent/components/AuthStack.json +21 -0
  26. package/agent/components/Avatar.json +89 -0
  27. package/agent/components/Badge.json +96 -0
  28. package/agent/components/Banner.json +48 -0
  29. package/agent/components/BarChart.json +108 -0
  30. package/agent/components/BranchScopePicker.json +89 -0
  31. package/agent/components/Breadcrumb.json +54 -0
  32. package/agent/components/Button.json +133 -0
  33. package/agent/components/Calendar.json +259 -0
  34. package/agent/components/Callout.json +46 -0
  35. package/agent/components/Card.json +112 -0
  36. package/agent/components/CardBar.json +49 -0
  37. package/agent/components/CardContent.json +51 -0
  38. package/agent/components/Carousel.json +50 -0
  39. package/agent/components/Cascader.json +209 -0
  40. package/agent/components/CenteredShell.json +66 -0
  41. package/agent/components/ChatBubble.json +100 -0
  42. package/agent/components/ChatBubbleList.json +64 -0
  43. package/agent/components/ChatComposer.json +160 -0
  44. package/agent/components/ChatSuggestion.json +86 -0
  45. package/agent/components/Checkbox.json +68 -0
  46. package/agent/components/CheckboxGroup.json +96 -0
  47. package/agent/components/CodeBlock.json +64 -0
  48. package/agent/components/Collapsible.json +74 -0
  49. package/agent/components/ColorPicker.json +87 -0
  50. package/agent/components/Command.json +168 -0
  51. package/agent/components/CommandPalette.json +84 -0
  52. package/agent/components/CompactBarTrend.json +101 -0
  53. package/agent/components/Conversations.json +82 -0
  54. package/agent/components/CredentialReveal.json +93 -0
  55. package/agent/components/DataState.json +79 -0
  56. package/agent/components/DataTable.json +268 -0
  57. package/agent/components/DatePicker.json +275 -0
  58. package/agent/components/Descriptions.json +67 -0
  59. package/agent/components/Dialog.json +78 -0
  60. package/agent/components/DraggablePanel.json +106 -0
  61. package/agent/components/DropdownMenu.json +102 -0
  62. package/agent/components/EmptyState.json +83 -0
  63. package/agent/components/ErrorSurface.json +128 -0
  64. package/agent/components/FeatureList.json +43 -0
  65. package/agent/components/Field.json +64 -0
  66. package/agent/components/FilterBar.json +99 -0
  67. package/agent/components/Flex.json +153 -0
  68. package/agent/components/FloatButton.json +91 -0
  69. package/agent/components/Form.json +87 -0
  70. package/agent/components/FormErrors.json +51 -0
  71. package/agent/components/FormField.json +137 -0
  72. package/agent/components/FormFieldArray.json +39 -0
  73. package/agent/components/FormFieldControl.json +129 -0
  74. package/agent/components/FormRoot.json +122 -0
  75. package/agent/components/Heading.json +61 -0
  76. package/agent/components/HoverCard.json +55 -0
  77. package/agent/components/Icon.json +60 -0
  78. package/agent/components/InfiniteQueryState.json +58 -0
  79. package/agent/components/Input.json +122 -0
  80. package/agent/components/InputOTP.json +106 -0
  81. package/agent/components/Label.json +43 -0
  82. package/agent/components/LegalDocumentShell.json +102 -0
  83. package/agent/components/Legend.json +42 -0
  84. package/agent/components/LineChart.json +103 -0
  85. package/agent/components/Link.json +41 -0
  86. package/agent/components/ListRow.json +92 -0
  87. package/agent/components/Logo.json +85 -0
  88. package/agent/components/Marquee.json +91 -0
  89. package/agent/components/Masonry.json +82 -0
  90. package/agent/components/MasterDetail.json +95 -0
  91. package/agent/components/MegaMenu.json +120 -0
  92. package/agent/components/MobileShell.json +73 -0
  93. package/agent/components/NavList.json +63 -0
  94. package/agent/components/NumberInput.json +158 -0
  95. package/agent/components/OrgSwitcher.json +89 -0
  96. package/agent/components/OverlayPortalProvider.json +42 -0
  97. package/agent/components/PageContainer.json +181 -0
  98. package/agent/components/Pagination.json +132 -0
  99. package/agent/components/Paragraph.json +40 -0
  100. package/agent/components/PasswordInput.json +79 -0
  101. package/agent/components/PasswordStrength.json +51 -0
  102. package/agent/components/PermissionMatrix.json +81 -0
  103. package/agent/components/PieChart.json +99 -0
  104. package/agent/components/Popover.json +110 -0
  105. package/agent/components/PrefetchLink.json +65 -0
  106. package/agent/components/Progress.json +79 -0
  107. package/agent/components/Prose.json +57 -0
  108. package/agent/components/QrCode.json +62 -0
  109. package/agent/components/Radio.json +98 -0
  110. package/agent/components/RadioGroup.json +91 -0
  111. package/agent/components/RangeTimeline.json +80 -0
  112. package/agent/components/Rating.json +92 -0
  113. package/agent/components/ResizablePanel.json +69 -0
  114. package/agent/components/ResponsiveGrid.json +77 -0
  115. package/agent/components/Reveal.json +70 -0
  116. package/agent/components/ScrollArea.json +104 -0
  117. package/agent/components/SearchInput.json +98 -0
  118. package/agent/components/Segmented.json +96 -0
  119. package/agent/components/Select.json +397 -0
  120. package/agent/components/Separator.json +86 -0
  121. package/agent/components/ServiceCatalogCta.json +46 -0
  122. package/agent/components/ServiceLauncherCard.json +93 -0
  123. package/agent/components/ServiceRolePanel.json +83 -0
  124. package/agent/components/Sheet.json +85 -0
  125. package/agent/components/Sidebar.json +118 -0
  126. package/agent/components/Skeleton.json +57 -0
  127. package/agent/components/SkeletonArticle.json +71 -0
  128. package/agent/components/SkeletonAvatar.json +50 -0
  129. package/agent/components/SkeletonButton.json +57 -0
  130. package/agent/components/SkeletonForm.json +52 -0
  131. package/agent/components/SkeletonImage.json +37 -0
  132. package/agent/components/SkeletonInput.json +51 -0
  133. package/agent/components/SkeletonNode.json +42 -0
  134. package/agent/components/SkeletonRows.json +49 -0
  135. package/agent/components/SkeletonTable.json +45 -0
  136. package/agent/components/Slider.json +160 -0
  137. package/agent/components/SplitPane.json +66 -0
  138. package/agent/components/StatCard.json +83 -0
  139. package/agent/components/Steps.json +95 -0
  140. package/agent/components/Swatch.json +41 -0
  141. package/agent/components/Switch.json +81 -0
  142. package/agent/components/Table.json +112 -0
  143. package/agent/components/Tabs.json +158 -0
  144. package/agent/components/TagInput.json +105 -0
  145. package/agent/components/Text.json +201 -0
  146. package/agent/components/Textarea.json +126 -0
  147. package/agent/components/ThoughtChain.json +76 -0
  148. package/agent/components/Thumbnail.json +70 -0
  149. package/agent/components/TimePicker.json +200 -0
  150. package/agent/components/TimeRangePicker.json +90 -0
  151. package/agent/components/Timeline.json +47 -0
  152. package/agent/components/TimelineGrid.json +92 -0
  153. package/agent/components/Title.json +67 -0
  154. package/agent/components/Toaster.json +42 -0
  155. package/agent/components/Toggle.json +90 -0
  156. package/agent/components/ToggleGroup.json +102 -0
  157. package/agent/components/Toolbar.json +120 -0
  158. package/agent/components/Tooltip.json +110 -0
  159. package/agent/components/Topbar.json +83 -0
  160. package/agent/components/TopbarItem.json +79 -0
  161. package/agent/components/Transfer.json +141 -0
  162. package/agent/components/Tree.json +185 -0
  163. package/agent/components/TreeSelect.json +232 -0
  164. package/agent/components/TwoFactorSetup.json +79 -0
  165. package/agent/components/Typography.json +42 -0
  166. package/agent/components/Upload.json +221 -0
  167. package/agent/components/UploadCropDialog.json +60 -0
  168. package/agent/components/VisuallyHidden.json +20 -0
  169. package/agent/components/Welcome.json +65 -0
  170. package/agent/components/formatDate.json +46 -0
  171. package/agent/components/inertiaUpload.json +32 -0
  172. package/agent/components/useZodForm.json +39 -0
  173. package/agent/components-index.json +884 -0
  174. package/agent/components.json +15515 -0
  175. package/agent/index.json +56 -0
  176. package/agent/llms.txt +32 -0
  177. package/agent/patterns/account-recovery-settings.json +19 -0
  178. package/agent/patterns/async-data-state.json +20 -0
  179. package/agent/patterns/auth-recovery-panels.json +29 -0
  180. package/agent/patterns/badge-coloring.json +14 -0
  181. package/agent/patterns/common-fixes.json +16 -0
  182. package/agent/patterns/confirm-destructive.json +11 -0
  183. package/agent/patterns/data-table-page.json +18 -0
  184. package/agent/patterns/deferred-loading.json +12 -0
  185. package/agent/patterns/error-pages.json +28 -0
  186. package/agent/patterns/inertia-detail-page.json +13 -0
  187. package/agent/patterns/inertia-list-page.json +15 -0
  188. package/agent/patterns/inertia-persistent-layout.json +14 -0
  189. package/agent/patterns/organization-memberships.json +19 -0
  190. package/agent/patterns/page-sections.json +18 -0
  191. package/agent/patterns/settings-page-responsive.json +18 -0
  192. package/agent/patterns/settings-section-rows.json +23 -0
  193. package/agent/patterns/signup-form.json +13 -0
  194. package/agent/patterns/topbar-account-chip.json +18 -0
  195. package/agent/patterns/transactional-email.json +22 -0
  196. package/agent/patterns-index.json +323 -0
  197. package/agent/patterns.json +342 -0
  198. package/agent/rules.json +237 -0
  199. package/agent/tokens.json +8427 -0
  200. package/agent/vocabulary.json +198 -0
  201. package/dist/components/data-display/service-launcher-card.d.ts +19 -0
  202. package/dist/components/data-display/service-launcher-card.js +14 -1
  203. package/dist/components/data-entry/attachments.js +77 -33
  204. package/dist/components/data-entry/input.js +8 -1
  205. package/dist/components/layout/flex.d.ts +2 -2
  206. package/dist/components/layout/flex.js +2 -0
  207. package/dist/components/ui/avatar.d.ts +1 -18
  208. package/dist/components/ui/avatar.js +1 -36
  209. package/dist/components/ui/tag-input.d.ts +10 -0
  210. package/dist/components/ui/tag-input.js +35 -2
  211. package/dist/contracts/measurement.json +1 -1
  212. package/dist/i18n/messages/en.json +190 -1
  213. package/dist/i18n/messages/ja.json +188 -1
  214. package/dist/i18n/messages/vi.json +188 -1
  215. package/dist/lib/image-loading-status.d.ts +25 -0
  216. package/dist/lib/image-loading-status.js +41 -0
  217. package/dist/props/components/data-entry.prop.d.ts +21 -2
  218. package/dist/props/components/layout.prop.d.ts +42 -0
  219. package/dist/props/registry.d.ts +14 -1
  220. package/dist/props/registry.js +18 -1
  221. package/dist/styles/card-layout.css +10 -4
  222. package/dist/styles/control.css +33 -4
  223. package/dist/styles/data-display-layout.css +1 -1
  224. package/dist/styles/data-entry-layout.css +245 -2
  225. package/dist/styles/layout.css +17 -0
  226. package/dist/styles/navigation-layout.css +3 -1
  227. package/dist/styles/shell-layout.css +2 -0
  228. package/dist/styles/table-layout.css +50 -9
  229. package/dist/tokens/components/attachments.css +18 -9
  230. package/dist/tokens/components/segmented.css +7 -3
  231. package/dist/tokens/components/table.css +2 -1
  232. package/docs/COMPOSITION-VS-COMPONENT.md +41 -0
  233. package/docs/DESIGN-AUTHORITY.md +52 -0
  234. package/docs/DEVELOPMENT.md +81 -6
  235. package/docs/assets/service-mark-rose.svg +6 -0
  236. package/docs/assets/service-mark-teal.svg +5 -0
  237. package/docs/data-display/service-launcher-card.tsx +232 -92
  238. package/docs/data-entry/tag-input.tsx +37 -0
  239. package/docs/layout/flex.tsx +40 -0
  240. package/docs/roadmap/website-components.md +34 -0
  241. package/docs/showcase/marketing-page.tsx +54 -45
  242. package/docs/showcase/table-pagination.tsx +99 -18
  243. package/docs/showcase/theme-customization.tsx +25 -2
  244. package/package.json +8 -5
@@ -0,0 +1,41 @@
1
+ "use client";
2
+ import { useLayoutEffect } from "@react-aria/utils";
3
+ function getImageLoadingStatus(image) {
4
+ if (!image.complete) {
5
+ return "loading";
6
+ }
7
+ return image.naturalWidth > 0 ? "loaded" : "error";
8
+ }
9
+ function useImageLoadingStatus(src, {
10
+ loadingStatus,
11
+ setLoadingStatus,
12
+ referrerPolicy,
13
+ crossOrigin
14
+ }) {
15
+ useLayoutEffect(() => {
16
+ if (!src) {
17
+ setLoadingStatus("error");
18
+ return;
19
+ }
20
+ const image = new window.Image();
21
+ const handleLoad = (event) => setLoadingStatus(getImageLoadingStatus(event.currentTarget));
22
+ const handleError = () => setLoadingStatus("error");
23
+ image.addEventListener("load", handleLoad);
24
+ image.addEventListener("error", handleError);
25
+ if (referrerPolicy) {
26
+ image.referrerPolicy = referrerPolicy;
27
+ }
28
+ image.crossOrigin = crossOrigin ?? null;
29
+ image.src = src;
30
+ setLoadingStatus(getImageLoadingStatus(image));
31
+ return () => {
32
+ image.removeEventListener("load", handleLoad);
33
+ image.removeEventListener("error", handleError);
34
+ setLoadingStatus("idle");
35
+ };
36
+ }, [src, crossOrigin, referrerPolicy, setLoadingStatus]);
37
+ return loadingStatus;
38
+ }
39
+ export {
40
+ useImageLoadingStatus
41
+ };
@@ -157,9 +157,28 @@ export type InputProp = Omit<React.InputHTMLAttributes<HTMLInputElement>, "size"
157
157
  prefix?: React.ReactNode;
158
158
  /** antd `suffix` — content pinned INSIDE the end of the field (%, 円, a hint glyph). */
159
159
  suffix?: React.ReactNode;
160
- /** antd `addonBefore` — a segment welded OUTSIDE the start of the box (`https://`, a currency). */
160
+ /**
161
+ * antd `addonBefore` — a LABEL segment welded OUTSIDE the start of the box (`https://`, a
162
+ * currency code, a unit). For a glyph, use `prefix`: it sits INSIDE the field, so there is one
163
+ * box, one border and no seam to get wrong.
164
+ *
165
+ * KEPT, NOT DEPRECATED — the verdict gh#841 asked for, so the next reviewer does not re-litigate
166
+ * it. Verified in `ant-design@master`, not on the docs page: `components/input/Input.tsx` marks
167
+ * both addons `@deprecated Use Space.Compact instead` on the type AND fires a dev-time
168
+ * `devUseWarning('Input').deprecated(…)` for each, while still rendering them; both locale docs
169
+ * strike the rows through and the `addon` demo is flagged `debug`, i.e. hidden from the
170
+ * published page. So the deprecation is real, and it is a REFACTOR onto `Space.Compact` —
171
+ * a component this library does not have. Deprecating a prop whose replacement does not exist
172
+ * would leave the joined control with no supported spelling at all, and removing a public prop
173
+ * is breaking. `Input addonBefore` IS this library's joined control: it renders the
174
+ * `.ui-input-group` that squares the seam (gh#841). If a `Space`/compact primitive is ever
175
+ * ported, revisit this line — the antd steer is then followable and this becomes a migration.
176
+ */
161
177
  addonBefore?: React.ReactNode;
162
- /** antd `addonAfter` — a segment welded OUTSIDE the end of the box (`.com`, a unit, a button). */
178
+ /**
179
+ * antd `addonAfter` — a segment welded OUTSIDE the end of the box (`.com`, a unit, a button).
180
+ * Deprecated upstream alongside `addonBefore`, and kept for the reason written there.
181
+ */
163
182
  addonAfter?: React.ReactNode;
164
183
  /** Character counter — antd `count`. */
165
184
  count?: ControlCountProp;
@@ -126,6 +126,16 @@ export type FlexDirectionProp = "row" | "col";
126
126
  export type FlexMarkerProp = "disc" | "decimal" | "none";
127
127
  export type FlexAlignProp = "start" | "center" | "end" | "stretch" | "baseline";
128
128
  export type FlexJustifyProp = "start" | "center" | "end" | "between" | "around" | "evenly";
129
+ /**
130
+ * The bounded inline MEASURE of a centred column, named for the `--page-measure-*` token it reads
131
+ * — the same three words `PageContainer measure` uses, plus the marketing step that has no
132
+ * `PageContainer` branch (gh#839).
133
+ *
134
+ * It is the token family, not a new one: `narrow` (42rem) and `medium` (48rem) bracket
135
+ * Bringhurst's 45–75 character reading band, `wide` (72rem) is the MARKETING measure. Do not give
136
+ * a reading column `wide` — that rule is `--page-measure-wide`'s own, and it travels with the word.
137
+ */
138
+ export type FlexMeasureProp = "narrow" | "medium" | "wide";
129
139
  /** @see Flex */
130
140
  export type FlexProp = React.HTMLAttributes<HTMLElement> & {
131
141
  /**
@@ -295,6 +305,38 @@ export type FlexProp = React.HTMLAttributes<HTMLElement> & {
295
305
  * call site đều ĐẾM ĐƯỢC, nên một kho đang trôi khỏi thang tự lộ ra bằng con số.
296
306
  */
297
307
  width?: WidthProp;
308
+ /**
309
+ * CENTRE this box and CAP it at a page measure — the inner half of "full-bleed outside, measured
310
+ * column inside" (gh#839).
311
+ *
312
+ * ## Why it is here and not on `PageContainer`
313
+ *
314
+ * `--page-measure-wide` shipped in 28.8.0 with no prop that reads it, and `PageContainer
315
+ * measure="wide"` was deliberately refused: a marketing page is a stack of full-bleed
316
+ * `<section>`s, and `PageContainer` owns page padding plus a header/toolbar/footer scaffold, so
317
+ * the pages that are the prop's proof could not have consumed it. That reasoning holds and is
318
+ * not reopened here. What it left behind is that NOTHING owned the centred inner column, and
319
+ * three unrelated pages each hand-wrote the same four declarations for it —
320
+ * `docs/showcase/marketing-page.tsx` as an inline `style` constant, `acme-website.tsx` as
321
+ * `.tx-shell` and `futurelastic-web.tsx` as `.fl-shell`. By `docs/TOKENS.md` a shape that
322
+ * appears in more than one place is tier 1.
323
+ *
324
+ * ## What it does, and what it deliberately does NOT
325
+ *
326
+ * `margin-inline: auto` + `inline-size: 100%` + `max-inline-size: var(--page-measure-{value})`.
327
+ * It does **not** add a gutter: the page inset is `pad={{ inline: 6 }}`, which already exists,
328
+ * and two owners for one padding is how a measure and a gutter drift apart. It is a MAX, so
329
+ * below the cap the box is fluid and nothing binds at 390px.
330
+ *
331
+ * An explicit `width` wins (it lands in the style attribute), which is the right order: a fixed
332
+ * column is a stronger statement than a cap.
333
+ *
334
+ * ## When NOT to reach for it
335
+ *
336
+ * Inside a `Card`, a `Dialog` or any surface that already owns its measure. This is PAGE
337
+ * geometry; a Flex that is a row of controls has no business carrying it.
338
+ */
339
+ measure?: FlexMeasureProp;
298
340
  };
299
341
  /** Container column counts; omitted steps inherit from the previous step. Base defaults to 1. */
300
342
  export type ResponsiveGridColumnsProp = number | {
@@ -786,6 +786,11 @@ export declare const COMPONENT_PROP_REGISTRY: {
786
786
  readonly file: "components/layout.prop.ts";
787
787
  readonly vocabulary: readonly [];
788
788
  };
789
+ readonly FlexMeasureProp: {
790
+ readonly group: "layout";
791
+ readonly file: "components/layout.prop.ts";
792
+ readonly vocabulary: readonly [];
793
+ };
789
794
  readonly FlexProp: {
790
795
  readonly group: "layout";
791
796
  readonly file: "components/layout.prop.ts";
@@ -821,6 +826,10 @@ export declare const COMPONENT_PROP_REGISTRY: {
821
826
  readonly field: "hideFrom";
822
827
  readonly local: true;
823
828
  readonly reason: "Inverse of hideBelow — keeps a compact-only region off the wide layout.";
829
+ }, {
830
+ readonly field: "measure";
831
+ readonly local: true;
832
+ readonly reason: 'The CENTRED, CAPPED column (narrow | medium | wide), backed by --page-measure-* — the inner half of "full-bleed outside, measured column inside" (gh#839). Same word and same three token steps as PageContainer `measure`, on the primitive a full-bleed <section> can actually use: PageContainer owns page padding and a header scaffold, which is why measure="wide" was refused there, and the refusal left the centred column with no owner at all — three showcases hand-wrote the same four declarations. It adds NO gutter (that is `pad`), and an explicit `width` wins over it.';
824
833
  }];
825
834
  };
826
835
  readonly ResponsiveGridFlowProp: {
@@ -3161,7 +3170,11 @@ export declare const COMPONENT_PROP_REGISTRY: {
3161
3170
  readonly ServiceLauncherCardProp: {
3162
3171
  readonly group: "data-display";
3163
3172
  readonly file: "components/data-display/service-launcher-card.tsx";
3164
- readonly vocabulary: readonly ["TitleProp", "ToneProp", "IconProp", "ClassNameProp", "DisabledProp"];
3173
+ readonly vocabulary: readonly ["TitleProp", "ToneProp", "IconProp", "ClassNameProp", "DisabledProp", {
3174
+ readonly field: "logo";
3175
+ readonly local: true;
3176
+ readonly reason: "URL of the service's OWN uploaded mark, distinct from `icon` (the LucideIcon for its kind) and deliberately NOT folded into it: `icon` is the fallback the tile needs when the upload 404s or does not exist yet, so the two cannot be one prop. A `string` URL rather than a ReactNode because the medallion owns the box, the object-fit and the decode hint (gh#850).";
3177
+ }];
3165
3178
  };
3166
3179
  readonly ServiceCatalogCtaProp: {
3167
3180
  readonly group: "data-display";
@@ -795,6 +795,7 @@ const COMPONENT_PROP_REGISTRY = {
795
795
  FlexMarkerProp: { group: "layout", file: "components/layout.prop.ts", vocabulary: [] },
796
796
  FlexAlignProp: { group: "layout", file: "components/layout.prop.ts", vocabulary: [] },
797
797
  FlexJustifyProp: { group: "layout", file: "components/layout.prop.ts", vocabulary: [] },
798
+ FlexMeasureProp: { group: "layout", file: "components/layout.prop.ts", vocabulary: [] },
798
799
  FlexProp: {
799
800
  group: "layout",
800
801
  file: "components/layout.prop.ts",
@@ -824,6 +825,11 @@ const COMPONENT_PROP_REGISTRY = {
824
825
  field: "hideFrom",
825
826
  local: true,
826
827
  reason: "Inverse of hideBelow \u2014 keeps a compact-only region off the wide layout."
828
+ },
829
+ {
830
+ field: "measure",
831
+ local: true,
832
+ reason: 'The CENTRED, CAPPED column (narrow | medium | wide), backed by --page-measure-* \u2014 the inner half of "full-bleed outside, measured column inside" (gh#839). Same word and same three token steps as PageContainer `measure`, on the primitive a full-bleed <section> can actually use: PageContainer owns page padding and a header scaffold, which is why measure="wide" was refused there, and the refusal left the centred column with no owner at all \u2014 three showcases hand-wrote the same four declarations. It adds NO gutter (that is `pad`), and an explicit `width` wins over it.'
827
833
  }
828
834
  ]
829
835
  },
@@ -3757,7 +3763,18 @@ const COMPONENT_PROP_REGISTRY = {
3757
3763
  ServiceLauncherCardProp: {
3758
3764
  group: "data-display",
3759
3765
  file: "components/data-display/service-launcher-card.tsx",
3760
- vocabulary: ["TitleProp", "ToneProp", "IconProp", "ClassNameProp", "DisabledProp"]
3766
+ vocabulary: [
3767
+ "TitleProp",
3768
+ "ToneProp",
3769
+ "IconProp",
3770
+ "ClassNameProp",
3771
+ "DisabledProp",
3772
+ {
3773
+ field: "logo",
3774
+ local: true,
3775
+ reason: "URL of the service's OWN uploaded mark, distinct from `icon` (the LucideIcon for its kind) and deliberately NOT folded into it: `icon` is the fallback the tile needs when the upload 404s or does not exist yet, so the two cannot be one prop. A `string` URL rather than a ReactNode because the medallion owns the box, the object-fit and the decode hint (gh#850)."
3776
+ }
3777
+ ]
3761
3778
  },
3762
3779
  ServiceCatalogCtaProp: {
3763
3780
  group: "data-display",
@@ -264,13 +264,13 @@
264
264
  padding-bottom: var(--card-space-body-y);
265
265
  }
266
266
 
267
- [data-slot="card"]:has([data-slot="card-header"] [data-slot="card-action"])
268
- [data-slot="card-content"]:not([data-tight]):not([data-flush]) {
267
+ [data-slot="card-header"]:has([data-slot="card-action"])
268
+ + [data-slot="card-content"]:not([data-tight]):not([data-flush]) {
269
269
  padding-top: 0;
270
270
  }
271
271
 
272
- [data-slot="card"]:has([data-slot="card-header"] [data-slot="card-description"])
273
- [data-slot="card-content"]:not([data-tight]):not([data-flush]) {
272
+ [data-slot="card-header"]:has([data-slot="card-description"])
273
+ + [data-slot="card-content"]:not([data-tight]):not([data-flush]) {
274
274
  padding-top: var(--card-space-body-y);
275
275
  }
276
276
 
@@ -574,6 +574,12 @@
574
574
  height: var(--card-service-launcher-icon-glyph-size);
575
575
  }
576
576
 
577
+ [data-slot="service-launcher-logo"] {
578
+ width: var(--card-service-launcher-icon-glyph-size);
579
+ height: var(--card-service-launcher-icon-glyph-size);
580
+ object-fit: contain;
581
+ }
582
+
577
583
  [data-slot="service-launcher-identity"] {
578
584
  display: flex;
579
585
  min-width: 0;
@@ -560,7 +560,9 @@
560
560
 
561
561
  .ui-switch-thumb {
562
562
  pointer-events: none;
563
- display: block;
563
+
564
+ display: grid;
565
+ place-items: center;
564
566
  width: var(--switch-thumb-size);
565
567
  height: var(--switch-thumb-size);
566
568
  border-radius: var(--radius-pill);
@@ -1158,7 +1160,7 @@
1158
1160
  align-items: stretch;
1159
1161
  padding: var(--segmented-track-padding);
1160
1162
  border-radius: var(--segmented-track-radius);
1161
- background: hsl(var(--segmented-track-background));
1163
+ background: hsl(var(--segmented-track-background, var(--muted)));
1162
1164
  color: hsl(var(--segmented-item-color));
1163
1165
  font-size: var(--font-size-base);
1164
1166
  }
@@ -1194,9 +1196,14 @@
1194
1196
  }
1195
1197
 
1196
1198
  .ui-segmented-item[data-state="checked"] {
1197
- background: hsl(var(--segmented-item-selected-background));
1198
- box-shadow: var(--segmented-item-selected-shadow);
1199
+ background: hsl(var(--segmented-item-selected-background, var(--background)));
1200
+
1201
+ box-shadow:
1202
+ var(--segmented-item-selected-shadow),
1203
+ inset 0 0 0 1px hsl(var(--segmented-item-selected-border-color, var(--input)));
1199
1204
  color: hsl(var(--segmented-item-selected-color));
1205
+
1206
+ font-weight: var(--segmented-item-selected-font-weight);
1200
1207
  }
1201
1208
 
1202
1209
  .ui-segmented-item[data-disabled] {
@@ -1332,6 +1339,13 @@
1332
1339
  cursor: pointer;
1333
1340
  }
1334
1341
 
1342
+ .ui-toggle > svg,
1343
+ .ui-control-trigger > svg {
1344
+ inline-size: var(--control-icon-size);
1345
+ block-size: var(--control-icon-size);
1346
+ flex-shrink: 0;
1347
+ }
1348
+
1335
1349
  .ui-control-trigger:disabled,
1336
1350
  .ui-control-trigger[data-disabled] {
1337
1351
  cursor: not-allowed;
@@ -2102,6 +2116,13 @@
2102
2116
  color: hsl(var(--muted-foreground));
2103
2117
  }
2104
2118
 
2119
+ .ui-input-leading > svg,
2120
+ .ui-input-trailing > svg {
2121
+ inline-size: var(--control-icon-size);
2122
+ block-size: var(--control-icon-size);
2123
+ flex-shrink: 0;
2124
+ }
2125
+
2105
2126
  .ui-input-trailing {
2106
2127
  inset-inline-end: var(--control-inline-affix-inset-inline);
2107
2128
  }
@@ -2873,6 +2894,12 @@
2873
2894
  white-space: nowrap;
2874
2895
  }
2875
2896
 
2897
+ .ui-input-addon > svg {
2898
+ inline-size: var(--control-icon-size);
2899
+ block-size: var(--control-icon-size);
2900
+ flex-shrink: 0;
2901
+ }
2902
+
2876
2903
  .ui-input-group > [data-slot="input-addon-before"] {
2877
2904
  border-start-start-radius: var(--control-radius);
2878
2905
  border-end-start-radius: var(--control-radius);
@@ -2887,12 +2914,14 @@
2887
2914
 
2888
2915
  .ui-input-group:has(> [data-slot="input-addon-before"]) .ui-input,
2889
2916
  .ui-input-group:has(> [data-slot="input-addon-before"]) .ui-input-affix-wrapper {
2917
+ --input-radius-start: 0;
2890
2918
  border-start-start-radius: 0;
2891
2919
  border-end-start-radius: 0;
2892
2920
  }
2893
2921
 
2894
2922
  .ui-input-group:has(> [data-slot="input-addon-after"]) .ui-input,
2895
2923
  .ui-input-group:has(> [data-slot="input-addon-after"]) .ui-input-affix-wrapper {
2924
+ --input-radius-end: 0;
2896
2925
  border-start-end-radius: 0;
2897
2926
  border-end-end-radius: 0;
2898
2927
  }
@@ -1232,7 +1232,7 @@
1232
1232
 
1233
1233
  .ui-prose :is(th, td) {
1234
1234
  border: var(--stroke-hairline) solid hsl(var(--border));
1235
- padding: var(--table-cell-padding-y) var(--table-cell-space-x);
1235
+ padding: var(--table-cell-padding-y) var(--table-cell-space-x, var(--space-section-active));
1236
1236
  text-align: start;
1237
1237
  vertical-align: top;
1238
1238
  }
@@ -1,7 +1,250 @@
1
1
  @layer components {
2
2
 
3
- .ui-attachments-input {
4
- min-block-size: var(--touch-target-min);
3
+ .ui-attachments {
4
+ position: relative;
5
+ inline-size: 100%;
6
+ }
7
+
8
+ .ui-attachments-list {
9
+ display: flex;
10
+ align-items: stretch;
11
+ gap: var(--attachments-gap);
12
+ margin: 0;
13
+ padding: 0;
14
+ list-style: none;
15
+ }
16
+
17
+ .ui-attachments-list > li {
18
+ position: relative;
19
+ display: flex;
20
+ flex: none;
21
+ min-inline-size: 0;
22
+ }
23
+
24
+ .ui-attachments-list[data-overflow="wrap"] {
25
+ flex-wrap: wrap;
26
+ }
27
+
28
+ .ui-attachments-list[data-overflow="scrollX"] {
29
+ flex-wrap: nowrap;
30
+ overflow-x: auto;
31
+ overflow-y: hidden;
32
+ }
33
+
34
+ .ui-attachments-list[data-overflow="scrollY"] {
35
+ flex-wrap: wrap;
36
+ overflow-x: hidden;
37
+ overflow-y: auto;
38
+ max-block-size: var(--attachments-card-block-size);
39
+ }
40
+
41
+ .ui-attachments-card {
42
+ position: relative;
43
+ display: flex;
44
+ align-items: center;
45
+ gap: var(--attachments-card-gap);
46
+ inline-size: var(--attachments-card-size);
47
+
48
+ max-inline-size: 100%;
49
+ block-size: var(--attachments-card-block-size);
50
+ padding-block: var(--space-3);
51
+ padding-inline: var(--space-4);
52
+ border: var(--stroke-hairline) solid transparent;
53
+ border-radius: var(--attachments-card-radius);
54
+ background-color: hsl(var(--muted));
55
+ overflow: hidden;
56
+ }
57
+
58
+ .ui-attachments-card-preview,
59
+ .ui-attachments-card-placeholder {
60
+ flex: none;
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: center;
64
+ inline-size: var(--icon-size-2xl);
65
+ block-size: var(--icon-size-2xl);
66
+ }
67
+
68
+ .ui-attachments-card-preview {
69
+ border-radius: var(--radius-md);
70
+ object-fit: cover;
71
+ }
72
+
73
+ .ui-attachments-card-placeholder {
74
+ color: hsl(var(--muted-foreground));
75
+ }
76
+
77
+ .ui-attachments-card-placeholder > svg {
78
+ inline-size: var(--icon-size-2xl);
79
+ block-size: var(--icon-size-2xl);
80
+ }
81
+
82
+ .ui-attachments-card-content {
83
+ display: flex;
84
+ flex: 1 1 auto;
85
+ min-inline-size: 0;
86
+ flex-direction: column;
87
+ justify-content: center;
88
+ }
89
+
90
+ .ui-attachments-card-name {
91
+ display: flex;
92
+ max-inline-size: 100%;
93
+ font-size: var(--font-size-base);
94
+ color: hsl(var(--foreground));
95
+ }
96
+
97
+ .ui-attachments-card-name-prefix {
98
+ flex: 0 1 auto;
99
+ min-inline-size: 0;
100
+ overflow: hidden;
101
+ text-overflow: ellipsis;
102
+ white-space: nowrap;
103
+ }
104
+
105
+ .ui-attachments-card-name-suffix {
106
+ flex: none;
107
+ }
108
+
109
+ .ui-attachments-card-meta {
110
+ overflow: hidden;
111
+ font-size: var(--font-size-xs, calc(var(--font-size-base) / var(--font-size-ratio)));
112
+ color: hsl(var(--muted-foreground));
113
+ text-overflow: ellipsis;
114
+ white-space: nowrap;
115
+ }
116
+
117
+ .ui-attachments-card[data-status="error"] {
118
+ border-color: hsl(var(--text-error));
119
+ }
120
+
121
+ .ui-attachments-card[data-status="error"] .ui-attachments-card-meta {
122
+ color: hsl(var(--text-error));
123
+ }
124
+
125
+ .ui-attachments-card-progress {
126
+ position: absolute;
127
+ inset-inline: 0;
128
+ inset-block-end: 0;
129
+ display: block;
130
+ }
131
+
132
+ .ui-attachments-card-remove {
133
+ flex: none;
134
+ }
135
+
136
+ .ui-attachments-card-remove > svg {
137
+ inline-size: var(--attachments-remove-icon-size);
138
+ block-size: var(--attachments-remove-icon-size);
139
+ }
140
+
141
+ .ui-attachments-upload-btn {
142
+ display: flex;
143
+ align-items: center;
144
+ justify-content: center;
145
+
146
+ inline-size: var(--attachments-card-block-size);
147
+ block-size: var(--attachments-card-block-size);
148
+ border: var(--stroke-hairline) dashed hsl(var(--border));
149
+ border-radius: var(--attachments-card-radius);
150
+ background-color: transparent;
151
+ color: hsl(var(--muted-foreground));
152
+ cursor: pointer;
153
+ transition:
154
+ border-color 150ms ease,
155
+ color 150ms ease;
156
+ }
157
+
158
+ .ui-attachments-upload-btn:hover:not(:disabled) {
159
+ border-color: hsl(var(--primary));
160
+ color: hsl(var(--primary));
161
+ }
162
+
163
+ .ui-attachments-upload-btn:disabled {
164
+ cursor: not-allowed;
165
+ opacity: 0.5;
166
+ }
167
+
168
+ .ui-attachments-upload-btn > svg {
169
+ inline-size: var(--icon-size-xl);
170
+ block-size: var(--icon-size-xl);
171
+ }
172
+
173
+ .ui-attachments-placeholder {
174
+ display: flex;
175
+ flex-direction: column;
176
+ align-items: center;
177
+ justify-content: center;
178
+ gap: var(--attachments-placeholder-gap);
179
+ padding: var(--attachments-placeholder-space-inset);
180
+ border: var(--stroke-md) dashed hsl(var(--border));
181
+ border-radius: var(--attachments-placeholder-radius);
182
+ background-color: hsl(var(--muted) / 0.4);
183
+ text-align: center;
184
+ cursor: pointer;
185
+ transition:
186
+ border-color 150ms ease,
187
+ background-color 150ms ease;
188
+ }
189
+
190
+ .ui-attachments-placeholder[data-drag-active="true"] {
191
+ border-color: hsl(var(--primary));
192
+ background-color: hsl(var(--primary) / 0.05);
193
+ }
194
+
195
+ .ui-attachments-placeholder:not([data-drag-active="true"]):hover {
196
+ border-color: hsl(var(--primary) / 0.5);
197
+ }
198
+
199
+ .ui-attachments-placeholder[data-disabled="true"] {
200
+ cursor: not-allowed;
201
+ opacity: 0.25;
202
+ pointer-events: none;
203
+ }
204
+
205
+ .ui-attachments-placeholder-icon {
206
+ display: flex;
207
+ color: hsl(var(--muted-foreground));
208
+ }
209
+
210
+ .ui-attachments-placeholder-icon > svg {
211
+ inline-size: var(--attachments-placeholder-icon-size);
212
+ block-size: var(--attachments-placeholder-icon-size);
213
+ }
214
+
215
+ .ui-attachments-placeholder-title {
216
+ font-size: var(--attachments-placeholder-title-font-size);
217
+ font-weight: var(--font-weight-medium);
218
+ color: hsl(var(--foreground));
219
+ }
220
+
221
+ .ui-attachments-placeholder-description {
222
+ font-size: var(--attachments-placeholder-description-font-size);
223
+ color: hsl(var(--muted-foreground));
224
+ }
225
+
226
+ .ui-attachments-drop-layer {
227
+ position: absolute;
228
+ inset: 0;
229
+ z-index: 1;
230
+ border: var(--stroke-md) dashed hsl(var(--primary));
231
+ border-radius: var(--attachments-placeholder-radius);
232
+ background: var(
233
+ --attachments-drop-overlay-background,
234
+ color-mix(in srgb, hsl(var(--background)) 85%, transparent)
235
+ );
236
+ opacity: 0;
237
+ pointer-events: none;
238
+ transition: opacity 150ms ease;
239
+ }
240
+
241
+ .ui-attachments-drop-layer[data-active="true"] {
242
+ opacity: 1;
243
+ backdrop-filter: blur(10px);
244
+ }
245
+
246
+ .ui-attachments-drop-layer[data-scope="viewport"] {
247
+ position: fixed;
5
248
  }
6
249
 
7
250
  .ui-combobox-content {
@@ -142,6 +142,23 @@
142
142
  flex: none;
143
143
  }
144
144
 
145
+ .ui-flex[data-measure] {
146
+ margin-inline: auto;
147
+ inline-size: 100%;
148
+ }
149
+
150
+ .ui-flex[data-measure="narrow"] {
151
+ max-inline-size: var(--page-measure-narrow);
152
+ }
153
+
154
+ .ui-flex[data-measure="medium"] {
155
+ max-inline-size: var(--page-measure-medium);
156
+ }
157
+
158
+ .ui-flex[data-measure="wide"] {
159
+ max-inline-size: var(--page-measure-wide);
160
+ }
161
+
145
162
  .ui-flex[data-align="start"] {
146
163
  align-items: flex-start;
147
164
  }
@@ -441,7 +441,9 @@
441
441
  }
442
442
 
443
443
  .ui-pagination .ui-button svg,
444
- .ui-pagination .ui-pagination-link svg {
444
+ .ui-pagination .ui-pagination-link svg,
445
+
446
+ .ui-pagination .ui-pagination-ellipsis svg {
445
447
  inline-size: var(--pagination-icon-size);
446
448
  block-size: var(--pagination-icon-size);
447
449
  }
@@ -1741,6 +1741,8 @@
1741
1741
  .sb-nav-group-trigger .sb-chevron {
1742
1742
  margin-inline-start: auto;
1743
1743
  flex: 0 0 auto;
1744
+ inline-size: var(--sidebar-nav-icon-size);
1745
+ block-size: var(--sidebar-nav-icon-size);
1744
1746
  opacity: 0.6;
1745
1747
  transition: transform 150ms ease;
1746
1748
  }