@godxjp/ui 23.1.0 → 23.2.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 (56) hide show
  1. package/dist/components/data-display/card.d.ts +45 -2
  2. package/dist/components/data-display/card.js +4 -2
  3. package/dist/components/data-display/feature-list.d.ts +26 -0
  4. package/dist/components/data-display/feature-list.js +29 -0
  5. package/dist/components/data-display/index.d.ts +6 -0
  6. package/dist/components/data-display/index.js +6 -0
  7. package/dist/components/data-display/swatch.d.ts +24 -0
  8. package/dist/components/data-display/swatch.js +19 -0
  9. package/dist/components/data-display/thumbnail.d.ts +37 -0
  10. package/dist/components/data-display/thumbnail.js +20 -0
  11. package/dist/components/feedback/index.d.ts +2 -2
  12. package/dist/components/feedback/index.js +19 -1
  13. package/dist/components/feedback/skeleton.d.ts +33 -3
  14. package/dist/components/feedback/skeleton.js +154 -3
  15. package/dist/components/layout/flex.d.ts +1 -1
  16. package/dist/components/layout/flex.js +17 -5
  17. package/dist/components/layout/sidebar.js +9 -2
  18. package/dist/components/navigation/tabs-scroll.d.ts +27 -0
  19. package/dist/components/navigation/tabs-scroll.js +36 -1
  20. package/dist/components/navigation/tabs.d.ts +2 -2
  21. package/dist/components/navigation/tabs.js +44 -12
  22. package/dist/i18n/messages/en.json +5 -0
  23. package/dist/i18n/messages/ja.json +5 -0
  24. package/dist/i18n/messages/vi.json +5 -0
  25. package/dist/props/components/data-display.prop.d.ts +93 -0
  26. package/dist/props/components/feedback.prop.d.ts +85 -1
  27. package/dist/props/components/layout.prop.d.ts +72 -1
  28. package/dist/props/components/navigation.prop.d.ts +72 -1
  29. package/dist/props/registry.d.ts +118 -0
  30. package/dist/props/registry.js +134 -0
  31. package/dist/styles/alert-layout.css +139 -0
  32. package/dist/styles/card-layout.css +48 -0
  33. package/dist/styles/data-display-layout.css +88 -0
  34. package/dist/styles/navigation-layout.css +76 -3
  35. package/dist/styles/shell-layout.css +18 -0
  36. package/dist/tokens/components/card.css +2 -0
  37. package/dist/tokens/components/data-display.css +23 -0
  38. package/dist/tokens/components/feedback.css +18 -0
  39. package/dist/tokens/components/navigation.css +2 -0
  40. package/dist/tokens/foundation.css +18 -16
  41. package/docs/CONSUMER-RULES.md +1 -1
  42. package/docs/DESIGN-AUTHORITY.md +2 -1
  43. package/docs/FRAME-COVERAGE-REPORT.md +29 -3
  44. package/docs/assets/shot-landscape.svg +12 -0
  45. package/docs/assets/shot-portrait.svg +10 -0
  46. package/docs/data-display/card/index.tsx +40 -0
  47. package/docs/data-display/feature-list.tsx +159 -0
  48. package/docs/data-display/swatch.tsx +107 -0
  49. package/docs/data-display/thumbnail.tsx +128 -0
  50. package/docs/feedback/skeleton.tsx +57 -0
  51. package/docs/layout/flex.tsx +29 -0
  52. package/docs/layout/sidebar.tsx +66 -10
  53. package/docs/navigation/tabs.tsx +59 -0
  54. package/package.json +4 -7
  55. package/scripts/consumer-rule.md +16 -0
  56. package/scripts/ui-audit.mjs +3 -4
@@ -185,6 +185,47 @@ export type FlexProp = React.HTMLAttributes<HTMLElement> & {
185
185
  * only on the narrow side (a compact-only affordance). Omit for no attribute and no rule.
186
186
  */
187
187
  hideFrom?: BreakpointProp;
188
+ /**
189
+ * ESCAPE HATCH: the same drop, at a width in PIXELS that is off every step of the scale — the
190
+ * `gapRaw`/`padRaw` contract applied to the breakpoint axis (gh#528).
191
+ *
192
+ * ## Why the token form stays the default
193
+ *
194
+ * An off-scale breakpoint is a LOCAL EXCEPTION, not a new tier. `sm`/`md`/`lg`/`xl` are the
195
+ * package's canonical steps, shared with `--master-detail-collapse-below` and with every
196
+ * `collapseBelow`, so two regions asked to fold "at the same place" actually fold together.
197
+ * A raw width folds one region and nothing else; spend the four named steps FIRST, and reach
198
+ * here only when the canonical design specifies a width the scale does not have (a nav that
199
+ * becomes a hamburger at 900px).
200
+ *
201
+ * ## The price, and why it is the right one
202
+ *
203
+ * It leaves `data-hide-below-raw` on the DOM, exactly like `data-gap-raw`/`data-pad-raw`, so
204
+ * every escape is COUNTABLE — grep the source or scan the DOM and a repo drifting off the scale
205
+ * shows up as a number instead of a feeling. Before this prop the only move left was
206
+ * `className="hidden min-[901px]:flex"`, which `ui-audit` blocks and which counts as nothing.
207
+ *
208
+ * It also prints ONE media rule per distinct width (a media query cannot read a `var()`, so an
209
+ * off-scale width can only reach CSS as a literal).
210
+ *
211
+ * ## The seam
212
+ *
213
+ * `hideBelowRaw` hides while `width < N`, `hideFromRaw` hides while `width >= N` — the SAME pair
214
+ * of comparisons as the token steps, so the two are exact complements and at exactly N the
215
+ * `hideBelowRaw` region is the visible one. Do NOT reach for an inclusive `<= N` here: pairing
216
+ * `<= N` with `>= N` leaves BOTH regions hidden at exactly N, which is the one-pixel hole a
217
+ * consumer measured on a hand-rolled `max-[900px]:` pair (gh#528).
218
+ *
219
+ * When present it WINS over `hideBelow`, which then emits no attribute, so the two cannot both
220
+ * match at one width.
221
+ */
222
+ hideBelowRaw?: number;
223
+ /**
224
+ * The inverse of `hideBelowRaw` — drop the region FROM a raw pixel width upwards. Same contract,
225
+ * same price, same seam (`width >= N`); it wins over `hideFrom` and leaves `data-hide-from-raw`
226
+ * on the DOM.
227
+ */
228
+ hideFromRaw?: number;
188
229
  /**
189
230
  * Take the space the siblings leave — the Flex becomes the row's ELASTIC column.
190
231
  *
@@ -802,6 +843,21 @@ export type SidebarItemProp = {
802
843
  * merely unread: an @mention, a direct message, a failure waiting on them.
803
844
  */
804
845
  badgeTone?: SidebarBadgeToneProp;
846
+ /**
847
+ * TRAILING 16px glyph — the disclosure mark of a row that opens something (the `⌃⌄` of a
848
+ * workspace switcher, a `→` on a row that leaves the app). Pinned to the same box as `icon`,
849
+ * and hidden on the collapsed rail exactly like `badge`.
850
+ *
851
+ * It is NOT `badge`, and the difference is the pill: `badge` wraps whatever it is given in
852
+ * `.sb-badge` — a 9999px-radius `hsl(var(--secondary))` capsule sized for a COUNT — so a
853
+ * chevron passed there renders as a grey lozenge with a 24px SVG inside it (measured 36×24 with
854
+ * a 24×24 glyph, beside a 16×16 leading icon in the same 32px row). A glyph draws no surface,
855
+ * so it gets its own slot rather than a size tier on the count pill.
856
+ *
857
+ * Takes the COMPONENT, like `icon` — not an element. That is what lets the rail pin the size;
858
+ * a `ReactNode` hole is how `badge` ended up carrying an unsized 24px SVG.
859
+ */
860
+ trailingIcon?: ComponentType<SVGProps<SVGSVGElement>>;
805
861
  disabled?: boolean;
806
862
  /**
807
863
  * Destination of the row. It is the SOLE interactive element (no nested `<button>`), so
@@ -1164,7 +1220,22 @@ export type SidebarProp = {
1164
1220
  * canonical row.
1165
1221
  */
1166
1222
  renderItem?: (item: SidebarItemData, rowProps: SidebarRenderItemProp) => ReactNode;
1167
- footer?: ReactNode;
1223
+ /**
1224
+ * Footer slot pinned BELOW the scroll area — identity, status, a mode switch.
1225
+ *
1226
+ * Takes a FUNCTION for the same reason `brand` does, and it is the same reason twice because
1227
+ * both slots live INSIDE the collapsible rail: a plain node is built outside this component and
1228
+ * cannot see the EFFECTIVE collapsed state, so the consumer has no correct move. Reading their
1229
+ * own `collapsed` boolean renders a glyph-only footer inside the full-width drawer (`AppShell`
1230
+ * hands the same Sidebar to both surfaces and the drawer un-collapses); building a second
1231
+ * Sidebar for `AppShell.mobileNav` is the override that switches `railInDrawer` off; doing
1232
+ * neither leaves the expanded footer to reflow inside a 64px rail (measured: a two-line identity
1233
+ * block went 255×66 docked → 63×111 collapsed, wrapping the name across three lines).
1234
+ *
1235
+ * The function is called with the surface-effective value. A plain `ReactNode` still works
1236
+ * unchanged.
1237
+ */
1238
+ footer?: ReactNode | ((collapsed: boolean) => ReactNode);
1168
1239
  /** Override the nav landmark's accessible name. Defaults to a localized "Main navigation". */
1169
1240
  "aria-label"?: string;
1170
1241
  };
@@ -1,6 +1,6 @@
1
1
  /** Navigation component prop types — @see docs/COMPONENTS.md#navigation */
2
2
  import type * as React from "react";
3
- import type { ActionsProp, ChildrenProp, ClassNameProp, DisabledProp, ErrorProp, HasActiveFiltersProp, IdProp, LabelProp, OnClearFiltersProp, PendingProp, PlaceholderProp, StickyProp } from "../vocabulary/index.js";
3
+ import type { ActionsProp, ChildrenProp, ClassNameProp, DisabledProp, ErrorProp, HasActiveFiltersProp, IdProp, LabelProp, OnClearFiltersProp, PendingProp, PlaceholderProp, StickyProp, TextAlignProp } from "../vocabulary/index.js";
4
4
  import type { SearchSelectOptionProp } from "./data-entry.prop.js";
5
5
  /**
6
6
  * `wrap` (default) stacks on narrow viewports then wraps onto extra rows; `scroll` keeps ONE
@@ -330,6 +330,60 @@ export type TabsOverflowProp = "scroll" | "menu";
330
330
  * so an inline `(value, event) => void` leaks its second PARAMETER as a phantom prop.
331
331
  */
332
332
  export type TabsOnTabClickProp = (value: string, event: React.MouseEvent<HTMLButtonElement>) => void;
333
+ /**
334
+ * @see Tabs — Ant Design `animated`, same shape and same two switches.
335
+ *
336
+ * `inkBar` (default ON) is the `line` variant's active bar cross-fading between triggers.
337
+ * `tabPane` (default OFF, as in antd) fades the panel in when the selection moves.
338
+ *
339
+ * WHERE IT DIVERGES, and why: antd animates the PANE by laying every pane on one translated
340
+ * inline track and sliding it, which needs all of them mounted. This component destroys a hidden
341
+ * panel by default (`destroyOnHidden` — the opposite default from antd), so there is no track to
342
+ * slide; the pane animation is a token-owned fade-in on the panel that just became active
343
+ * (`--tabs-pane-motion-*`). The SWITCH is antd's, the motion is this library's, and both switches
344
+ * are additionally off under `prefers-reduced-motion` — which antd's is not.
345
+ */
346
+ export type TabsAnimatedProp = boolean | {
347
+ inkBar?: boolean;
348
+ tabPane?: boolean;
349
+ };
350
+ /**
351
+ * @see Tabs — Ant Design `indicator.size`, held to a NAMED axis instead of a pixel length.
352
+ *
353
+ * antd takes `number | (origin: number) => number` — a measured px length, or a function of the
354
+ * tab's own width. Neither can enter this library: a literal is what `no-arbitrary-spacing`
355
+ * exists to stop, and a function of the measured origin is the free-form escape hatch
356
+ * `docs/DESIGN-AUTHORITY.md` refuses by name. The two lengths that answer the actual request are
357
+ * named instead — `full` (the whole trigger, today's bar and the default) and `label` (the
358
+ * trigger's content box, i.e. minus its own inline padding), which is what
359
+ * `size: (origin) => origin - 2 * padding` is written to produce.
360
+ */
361
+ export type TabsIndicatorSizeProp = "full" | "label";
362
+ /**
363
+ * @see Tabs — Ant Design `indicator`. `align` keeps antd's own name AND its values, which are
364
+ * already logical, so it reads the shared `TextAlignProp` vocabulary rather than a second
365
+ * spelling of the same axis. It only has anything to place when `size` is shorter than the
366
+ * trigger, exactly as in antd.
367
+ */
368
+ export type TabsIndicatorProp = {
369
+ size?: TabsIndicatorSizeProp;
370
+ align?: TextAlignProp;
371
+ };
372
+ /**
373
+ * @see Tabs — the edge a scroll of the trigger strip moved TOWARDS, on the logical axis.
374
+ *
375
+ * antd reports `left | right | top | bottom`; those four cannot mirror for an RTL locale and two
376
+ * of them are just the other axis of the same event. `start`/`end` say the same thing on whichever
377
+ * axis the strip is on — the same override that makes `tabPlacement` logical.
378
+ */
379
+ export type TabsScrollDirectionProp = "start" | "end";
380
+ /**
381
+ * @see Tabs — Ant Design `onTabScroll`. A NAMED alias for the same reason as `TabsOnEditProp`.
382
+ * Only fires for the `items` API, which is the path that owns the strip element.
383
+ */
384
+ export type TabsOnScrollProp = (info: {
385
+ direction: TabsScrollDirectionProp;
386
+ }) => void;
333
387
  /** @see Tabs — high-level tabs with optional `items` array. */
334
388
  export type TabsProp = {
335
389
  items?: TabItemProp[];
@@ -391,6 +445,23 @@ export type TabsProp = {
391
445
  * "click" would be a fiction. Use `onValueChange` for selection, whatever moved it.
392
446
  */
393
447
  onTabClick?: TabsOnTabClickProp;
448
+ /**
449
+ * Ant Design `animated`. Default `{ inkBar: true, tabPane: false }` — antd's own default, and
450
+ * byte for byte what this strip already painted. @see TabsAnimatedProp
451
+ */
452
+ animated?: TabsAnimatedProp;
453
+ /**
454
+ * Ant Design `indicator`. Governs the `line` variant's active bar only — the other variants
455
+ * have no bar to place. @see TabsIndicatorProp
456
+ */
457
+ indicator?: TabsIndicatorProp;
458
+ /**
459
+ * Ant Design `more.icon` — the glyph on the `overflow="menu"` button, flat here for the same
460
+ * reason `addIcon` and `closeIcon` are flat: `overflow` names the BEHAVIOUR, the icon is a slot.
461
+ */
462
+ moreIcon?: React.ReactNode;
463
+ /** Ant Design `onTabScroll`, on the logical axis. @see TabsOnScrollProp */
464
+ onTabScroll?: TabsOnScrollProp;
394
465
  className?: ClassNameProp;
395
466
  listClassName?: ClassNameProp;
396
467
  contentClassName?: ClassNameProp;
@@ -1940,6 +1940,45 @@ export declare const COMPONENT_PROP_REGISTRY: {
1940
1940
  readonly file: "components/feedback.prop.ts";
1941
1941
  readonly vocabulary: readonly [];
1942
1942
  };
1943
+ readonly SkeletonProp: {
1944
+ readonly group: "feedback";
1945
+ readonly file: "components/feedback.prop.ts";
1946
+ readonly vocabulary: readonly ["ClassNameProp", "ChildrenProp"];
1947
+ };
1948
+ readonly SkeletonAvatarProp: {
1949
+ readonly group: "feedback";
1950
+ readonly file: "components/feedback.prop.ts";
1951
+ readonly vocabulary: readonly ["SizeProp", "ClassNameProp"];
1952
+ };
1953
+ readonly SkeletonButtonProp: {
1954
+ readonly group: "feedback";
1955
+ readonly file: "components/feedback.prop.ts";
1956
+ readonly vocabulary: readonly ["SizeProp", "ShapeProp", "ClassNameProp"];
1957
+ };
1958
+ readonly SkeletonInputProp: {
1959
+ readonly group: "feedback";
1960
+ readonly file: "components/feedback.prop.ts";
1961
+ readonly vocabulary: readonly ["SizeProp", "ClassNameProp"];
1962
+ };
1963
+ readonly SkeletonNodeProp: {
1964
+ readonly group: "feedback";
1965
+ readonly file: "components/feedback.prop.ts";
1966
+ readonly vocabulary: readonly ["ChildrenProp", "ClassNameProp"];
1967
+ };
1968
+ readonly SkeletonImageProp: {
1969
+ readonly group: "feedback";
1970
+ readonly file: "components/feedback.prop.ts";
1971
+ readonly vocabulary: readonly ["ClassNameProp"];
1972
+ };
1973
+ readonly SkeletonArticleProp: {
1974
+ readonly group: "feedback";
1975
+ readonly file: "components/feedback.prop.ts";
1976
+ readonly vocabulary: readonly ["ChildrenProp", "ClassNameProp", {
1977
+ readonly field: "title";
1978
+ readonly local: true;
1979
+ readonly reason: "antd's Skeleton `title` is the presence/measure of the HEADING LINE, not the string TitleProp names — `false` drops the line and `{ width }` re-measures it.";
1980
+ }];
1981
+ };
1943
1982
  readonly ToolbarProp: {
1944
1983
  readonly group: "navigation";
1945
1984
  readonly file: "components/navigation.prop.ts";
@@ -2080,6 +2119,35 @@ export declare const COMPONENT_PROP_REGISTRY: {
2080
2119
  readonly file: "components/navigation.prop.ts";
2081
2120
  readonly vocabulary: readonly [];
2082
2121
  };
2122
+ readonly TabsAnimatedProp: {
2123
+ readonly group: "navigation";
2124
+ readonly file: "components/navigation.prop.ts";
2125
+ readonly vocabulary: readonly [];
2126
+ };
2127
+ readonly TabsIndicatorSizeProp: {
2128
+ readonly group: "navigation";
2129
+ readonly file: "components/navigation.prop.ts";
2130
+ readonly vocabulary: readonly [];
2131
+ };
2132
+ readonly TabsIndicatorProp: {
2133
+ readonly group: "navigation";
2134
+ readonly file: "components/navigation.prop.ts";
2135
+ readonly vocabulary: readonly ["TextAlignProp", {
2136
+ readonly field: "size";
2137
+ readonly local: true;
2138
+ readonly reason: "The LENGTH of the active bar along the strip (Ant Design `indicator.size`), not a control tier — `SizeProp` is the sm/md/lg band and reusing it here would say something false. Values stay a closed named axis (`full` | `label`) so no pixel length or origin-function enters the API.";
2139
+ }];
2140
+ };
2141
+ readonly TabsScrollDirectionProp: {
2142
+ readonly group: "navigation";
2143
+ readonly file: "components/navigation.prop.ts";
2144
+ readonly vocabulary: readonly [];
2145
+ };
2146
+ readonly TabsOnScrollProp: {
2147
+ readonly group: "navigation";
2148
+ readonly file: "components/navigation.prop.ts";
2149
+ readonly vocabulary: readonly ["HandlerProp"];
2150
+ };
2083
2151
  readonly TabItemProp: {
2084
2152
  readonly group: "navigation";
2085
2153
  readonly file: "components/navigation.prop.ts";
@@ -2202,6 +2270,56 @@ export declare const COMPONENT_PROP_REGISTRY: {
2202
2270
  readonly file: "components/data-display.prop.ts";
2203
2271
  readonly vocabulary: readonly ["ClassNameProp"];
2204
2272
  };
2273
+ readonly SwatchProp: {
2274
+ readonly group: "data-display";
2275
+ readonly file: "components/data-display.prop.ts";
2276
+ readonly vocabulary: readonly ["ClassNameProp", {
2277
+ readonly field: "color";
2278
+ readonly local: true;
2279
+ readonly reason: "A CSS colour VALUE a person chose (a brand's primary_color, a tag tint) — DATA, the same axis as Badge's `color`, and deliberately not ToneProp: a tone is a closed set of meanings and this colour means only itself (gh#527).";
2280
+ }, {
2281
+ readonly field: "aria-label";
2282
+ readonly local: true;
2283
+ readonly reason: "The sample's accessible NAME, which is what lets a read-only colour be shown with no visible label. Absent, the mark is aria-hidden (Legend's rule) — so colour is never the sole carrier either way.";
2284
+ }];
2285
+ };
2286
+ readonly FeatureStateProp: {
2287
+ readonly group: "data-display";
2288
+ readonly file: "components/data-display.prop.ts";
2289
+ readonly vocabulary: readonly [];
2290
+ };
2291
+ readonly FeatureItemProp: {
2292
+ readonly group: "data-display";
2293
+ readonly file: "components/data-display.prop.ts";
2294
+ readonly vocabulary: readonly ["LabelProp", "DescriptionProp", {
2295
+ readonly field: "state";
2296
+ readonly local: true;
2297
+ readonly reason: "Inclusion axis (included/excluded/limited) — FeatureList's own, not a tone.";
2298
+ }];
2299
+ };
2300
+ readonly FeatureListProp: {
2301
+ readonly group: "data-display";
2302
+ readonly file: "components/data-display.prop.ts";
2303
+ readonly vocabulary: readonly ["ClassNameProp"];
2304
+ };
2305
+ readonly ThumbnailSizeProp: {
2306
+ readonly group: "data-display";
2307
+ readonly file: "components/data-display.prop.ts";
2308
+ readonly vocabulary: readonly ["SizeProp"];
2309
+ };
2310
+ readonly ThumbnailProp: {
2311
+ readonly group: "data-display";
2312
+ readonly file: "components/data-display.prop.ts";
2313
+ readonly vocabulary: readonly ["SizeProp", "ClassNameProp", {
2314
+ readonly field: "alt";
2315
+ readonly local: true;
2316
+ readonly reason: "The native img alt contract, made required so it cannot be forgotten.";
2317
+ }, {
2318
+ readonly field: "src";
2319
+ readonly local: true;
2320
+ readonly reason: "The native img src attribute.";
2321
+ }];
2322
+ };
2205
2323
  readonly CodeBlockProp: {
2206
2324
  readonly group: "data-display";
2207
2325
  readonly file: "components/data-display.prop.ts";
@@ -2239,6 +2239,49 @@ const COMPONENT_PROP_REGISTRY = {
2239
2239
  },
2240
2240
  SheetResponsiveProp: { group: "feedback", file: "components/feedback.prop.ts", vocabulary: [] },
2241
2241
  SkeletonRowsProp: { group: "feedback", file: "components/feedback.prop.ts", vocabulary: [] },
2242
+ SkeletonProp: {
2243
+ group: "feedback",
2244
+ file: "components/feedback.prop.ts",
2245
+ vocabulary: ["ClassNameProp", "ChildrenProp"]
2246
+ },
2247
+ SkeletonAvatarProp: {
2248
+ group: "feedback",
2249
+ file: "components/feedback.prop.ts",
2250
+ vocabulary: ["SizeProp", "ClassNameProp"]
2251
+ },
2252
+ SkeletonButtonProp: {
2253
+ group: "feedback",
2254
+ file: "components/feedback.prop.ts",
2255
+ vocabulary: ["SizeProp", "ShapeProp", "ClassNameProp"]
2256
+ },
2257
+ SkeletonInputProp: {
2258
+ group: "feedback",
2259
+ file: "components/feedback.prop.ts",
2260
+ vocabulary: ["SizeProp", "ClassNameProp"]
2261
+ },
2262
+ SkeletonNodeProp: {
2263
+ group: "feedback",
2264
+ file: "components/feedback.prop.ts",
2265
+ vocabulary: ["ChildrenProp", "ClassNameProp"]
2266
+ },
2267
+ SkeletonImageProp: {
2268
+ group: "feedback",
2269
+ file: "components/feedback.prop.ts",
2270
+ vocabulary: ["ClassNameProp"]
2271
+ },
2272
+ SkeletonArticleProp: {
2273
+ group: "feedback",
2274
+ file: "components/feedback.prop.ts",
2275
+ vocabulary: [
2276
+ "ChildrenProp",
2277
+ "ClassNameProp",
2278
+ {
2279
+ field: "title",
2280
+ local: true,
2281
+ reason: "antd's Skeleton `title` is the presence/measure of the HEADING LINE, not the string TitleProp names \u2014 `false` drops the line and `{ width }` re-measures it."
2282
+ }
2283
+ ]
2284
+ },
2242
2285
  ToolbarProp: {
2243
2286
  group: "navigation",
2244
2287
  file: "components/navigation.prop.ts",
@@ -2392,6 +2435,38 @@ const COMPONENT_PROP_REGISTRY = {
2392
2435
  file: "components/navigation.prop.ts",
2393
2436
  vocabulary: []
2394
2437
  },
2438
+ TabsAnimatedProp: {
2439
+ group: "navigation",
2440
+ file: "components/navigation.prop.ts",
2441
+ vocabulary: []
2442
+ },
2443
+ TabsIndicatorSizeProp: {
2444
+ group: "navigation",
2445
+ file: "components/navigation.prop.ts",
2446
+ vocabulary: []
2447
+ },
2448
+ TabsIndicatorProp: {
2449
+ group: "navigation",
2450
+ file: "components/navigation.prop.ts",
2451
+ vocabulary: [
2452
+ "TextAlignProp",
2453
+ {
2454
+ field: "size",
2455
+ local: true,
2456
+ reason: "The LENGTH of the active bar along the strip (Ant Design `indicator.size`), not a control tier \u2014 `SizeProp` is the sm/md/lg band and reusing it here would say something false. Values stay a closed named axis (`full` | `label`) so no pixel length or origin-function enters the API."
2457
+ }
2458
+ ]
2459
+ },
2460
+ TabsScrollDirectionProp: {
2461
+ group: "navigation",
2462
+ file: "components/navigation.prop.ts",
2463
+ vocabulary: []
2464
+ },
2465
+ TabsOnScrollProp: {
2466
+ group: "navigation",
2467
+ file: "components/navigation.prop.ts",
2468
+ vocabulary: ["HandlerProp"]
2469
+ },
2395
2470
  TabItemProp: {
2396
2471
  group: "navigation",
2397
2472
  file: "components/navigation.prop.ts",
@@ -2544,6 +2619,65 @@ const COMPONENT_PROP_REGISTRY = {
2544
2619
  file: "components/data-display.prop.ts",
2545
2620
  vocabulary: ["ClassNameProp"]
2546
2621
  },
2622
+ SwatchProp: {
2623
+ group: "data-display",
2624
+ file: "components/data-display.prop.ts",
2625
+ vocabulary: [
2626
+ "ClassNameProp",
2627
+ {
2628
+ field: "color",
2629
+ local: true,
2630
+ reason: "A CSS colour VALUE a person chose (a brand's primary_color, a tag tint) \u2014 DATA, the same axis as Badge's `color`, and deliberately not ToneProp: a tone is a closed set of meanings and this colour means only itself (gh#527)."
2631
+ },
2632
+ {
2633
+ field: "aria-label",
2634
+ local: true,
2635
+ reason: "The sample's accessible NAME, which is what lets a read-only colour be shown with no visible label. Absent, the mark is aria-hidden (Legend's rule) \u2014 so colour is never the sole carrier either way."
2636
+ }
2637
+ ]
2638
+ },
2639
+ FeatureStateProp: {
2640
+ group: "data-display",
2641
+ file: "components/data-display.prop.ts",
2642
+ vocabulary: []
2643
+ },
2644
+ FeatureItemProp: {
2645
+ group: "data-display",
2646
+ file: "components/data-display.prop.ts",
2647
+ vocabulary: [
2648
+ "LabelProp",
2649
+ "DescriptionProp",
2650
+ {
2651
+ field: "state",
2652
+ local: true,
2653
+ reason: "Inclusion axis (included/excluded/limited) \u2014 FeatureList's own, not a tone."
2654
+ }
2655
+ ]
2656
+ },
2657
+ FeatureListProp: {
2658
+ group: "data-display",
2659
+ file: "components/data-display.prop.ts",
2660
+ vocabulary: ["ClassNameProp"]
2661
+ },
2662
+ ThumbnailSizeProp: {
2663
+ group: "data-display",
2664
+ file: "components/data-display.prop.ts",
2665
+ vocabulary: ["SizeProp"]
2666
+ },
2667
+ ThumbnailProp: {
2668
+ group: "data-display",
2669
+ file: "components/data-display.prop.ts",
2670
+ vocabulary: [
2671
+ "SizeProp",
2672
+ "ClassNameProp",
2673
+ {
2674
+ field: "alt",
2675
+ local: true,
2676
+ reason: "The native img alt contract, made required so it cannot be forgotten."
2677
+ },
2678
+ { field: "src", local: true, reason: "The native img src attribute." }
2679
+ ]
2680
+ },
2547
2681
  CodeBlockProp: {
2548
2682
  group: "data-display",
2549
2683
  file: "components/data-display.prop.ts",
@@ -288,6 +288,145 @@
288
288
  }
289
289
  }
290
290
 
291
+ .ui-skeleton-block[data-active],
292
+ .ui-skeleton-article[data-active] .ui-skeleton-block {
293
+ background-image: var(
294
+ --skeleton-sweep-gradient,
295
+ linear-gradient(90deg, hsl(var(--muted)) 25%, hsl(var(--border)) 37%, hsl(var(--muted)) 63%)
296
+ );
297
+ background-size: 400% 100%;
298
+
299
+ animation: ui-skeleton-sweep var(--duration-loop, 1400ms) ease infinite;
300
+ }
301
+
302
+ @keyframes ui-skeleton-sweep {
303
+ from {
304
+ background-position: 100% 50%;
305
+ }
306
+ to {
307
+ background-position: 0 50%;
308
+ }
309
+ }
310
+
311
+ @media (prefers-reduced-motion: reduce) {
312
+ .ui-skeleton-block,
313
+ .ui-skeleton-block[data-active],
314
+ .ui-skeleton-article[data-active] .ui-skeleton-block {
315
+ animation: none;
316
+ }
317
+ }
318
+
319
+ [data-skeleton-element] {
320
+ --skeleton-element-block-size: var(--control-height);
321
+
322
+ display: inline-block;
323
+ vertical-align: top;
324
+ block-size: var(--skeleton-element-block-size);
325
+ border-radius: var(--skeleton-element-radius);
326
+ }
327
+
328
+ [data-skeleton-element][data-size="xs"] {
329
+ --skeleton-element-block-size: var(--control-height-xs);
330
+ }
331
+
332
+ [data-skeleton-element][data-size="sm"] {
333
+ --skeleton-element-block-size: var(--control-height-sm);
334
+ }
335
+
336
+ [data-skeleton-element][data-size="lg"] {
337
+ --skeleton-element-block-size: var(--control-height-lg);
338
+ }
339
+
340
+ [data-skeleton-element="avatar"] {
341
+ inline-size: var(--skeleton-element-block-size);
342
+ border-radius: var(--avatar-square-radius);
343
+ }
344
+
345
+ [data-skeleton-element="avatar"][data-shape="circle"] {
346
+ border-radius: var(--radius-pill);
347
+ }
348
+
349
+ [data-skeleton-element="button"] {
350
+ inline-size: calc(var(--skeleton-element-block-size) * var(--skeleton-button-width-ratio));
351
+ min-inline-size: calc(var(--skeleton-element-block-size) * var(--skeleton-button-width-ratio));
352
+ }
353
+
354
+ [data-skeleton-element="button"][data-shape="pill"] {
355
+ border-radius: var(--radius-pill);
356
+ }
357
+
358
+ [data-skeleton-element="button"][data-shape="sharp"] {
359
+ border-radius: var(--radius-sharp);
360
+ }
361
+
362
+ [data-skeleton-element="input"] {
363
+ inline-size: calc(var(--skeleton-element-block-size) * var(--skeleton-input-width-ratio));
364
+ min-inline-size: calc(var(--skeleton-element-block-size) * var(--skeleton-input-width-ratio));
365
+ }
366
+
367
+ [data-skeleton-element][data-block] {
368
+ display: block;
369
+ inline-size: 100%;
370
+ min-inline-size: 0;
371
+ }
372
+
373
+ [data-skeleton-element="node"],
374
+ [data-skeleton-element="image"] {
375
+ display: inline-flex;
376
+ align-items: center;
377
+ justify-content: center;
378
+ vertical-align: middle;
379
+ inline-size: var(--skeleton-node-size);
380
+ block-size: var(--skeleton-node-size);
381
+ }
382
+
383
+ .ui-skeleton-image-glyph {
384
+ inline-size: var(--skeleton-image-glyph-size);
385
+ block-size: var(--skeleton-image-glyph-size);
386
+ color: var(--skeleton-image-glyph-color, hsl(var(--muted-foreground) / 0.4));
387
+ }
388
+
389
+ .ui-skeleton-article {
390
+ display: flex;
391
+ align-items: flex-start;
392
+ gap: var(--skeleton-article-avatar-gap);
393
+ inline-size: 100%;
394
+ }
395
+
396
+ .ui-skeleton-article-header {
397
+ flex: 0 0 auto;
398
+ }
399
+
400
+ .ui-skeleton-article-section {
401
+ display: grid;
402
+ flex: 1 1 auto;
403
+ gap: var(--skeleton-article-title-gap);
404
+ min-inline-size: 0;
405
+ }
406
+
407
+ .ui-skeleton-article[data-avatar] .ui-skeleton-article-title {
408
+ margin-block-start: var(--skeleton-article-avatar-title-offset);
409
+ }
410
+
411
+ .ui-skeleton-article-paragraph {
412
+ display: grid;
413
+ gap: var(--skeleton-article-line-gap);
414
+ }
415
+
416
+ .ui-skeleton-article-title,
417
+ .ui-skeleton-article-line {
418
+ block-size: var(--skeleton-block-height);
419
+ inline-size: var(--skeleton-line-width, 100%);
420
+ }
421
+
422
+ .ui-skeleton-article-line:last-child:not(:first-child):not(:nth-child(2)) {
423
+ --skeleton-line-width: var(--skeleton-paragraph-last-width);
424
+ }
425
+
426
+ .ui-skeleton-article[data-round] .ui-skeleton-block {
427
+ border-radius: var(--radius-pill);
428
+ }
429
+
291
430
  @keyframes pulse {
292
431
  50% {
293
432
  opacity: 0.5;