@godxjp/ui 27.4.1 → 27.6.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 (36) hide show
  1. package/dist/components/data-display/range-timeline.js +9 -6
  2. package/dist/components/data-entry/upload-file-kind.d.ts +25 -0
  3. package/dist/components/data-entry/upload-file-kind.js +88 -0
  4. package/dist/components/data-entry/upload.d.ts +2 -2
  5. package/dist/components/data-entry/upload.js +10 -6
  6. package/dist/components/ui/avatar.d.ts +1 -1
  7. package/dist/components/ui/avatar.js +2 -0
  8. package/dist/components/ui/segmented.d.ts +7 -2
  9. package/dist/components/ui/toggle.d.ts +2 -2
  10. package/dist/components/ui/toggle.js +4 -0
  11. package/dist/contracts/measurement.json +1 -1
  12. package/dist/props/components/data-display.prop.d.ts +14 -0
  13. package/dist/props/components/data-entry.prop.d.ts +28 -2
  14. package/dist/props/registry.d.ts +6 -1
  15. package/dist/props/registry.js +6 -1
  16. package/dist/styles/control.css +18 -6
  17. package/dist/styles/data-display-layout.css +40 -8
  18. package/dist/styles/data-entry-layout.css +22 -0
  19. package/dist/tokens/components/control.css +1 -0
  20. package/dist/tokens/components/data-display.css +26 -0
  21. package/dist/tokens/components/segmented.css +4 -0
  22. package/dist/tokens/components/upload.css +4 -0
  23. package/docs/CUSTOMER-THEMING.md +26 -0
  24. package/docs/data-display/avatar.tsx +128 -11
  25. package/docs/data-display/prose.tsx +64 -0
  26. package/docs/data-display/timeline.tsx +36 -0
  27. package/docs/data-entry/calendar.tsx +2 -3
  28. package/docs/data-entry/segmented.tsx +55 -5
  29. package/docs/data-entry/toggle-group.tsx +15 -3
  30. package/docs/data-entry/toggle.tsx +39 -1
  31. package/docs/data-entry/upload.tsx +38 -0
  32. package/package.json +2 -2
  33. package/scripts/_agent-setup.mjs +80 -1
  34. package/scripts/cli.mjs +5 -1
  35. package/scripts/init-agent-kit.mjs +3 -0
  36. package/scripts/postinstall.mjs +5 -0
@@ -44,7 +44,10 @@ const RangeTimeline = React.forwardRef(
44
44
  "div",
45
45
  {
46
46
  className: "ui-range-timeline-canvas",
47
- style: { "--range-timeline-columns": Math.max(1, columns.length) },
47
+ style: {
48
+ "--range-timeline-columns": Math.max(1, columns.length),
49
+ "--range-timeline-units": units
50
+ },
48
51
  children: [
49
52
  bands && bands.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-header", children: [
50
53
  /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-label", "aria-hidden": "true" }),
@@ -52,7 +55,7 @@ const RangeTimeline = React.forwardRef(
52
55
  "div",
53
56
  {
54
57
  className: "ui-range-timeline-column",
55
- style: { flex: band.units },
58
+ style: { gridColumn: `span ${band.units}` },
56
59
  children: /* @__PURE__ */ jsx(Text, { size: "xs", weight: "medium", children: band.label })
57
60
  },
58
61
  index
@@ -64,15 +67,15 @@ const RangeTimeline = React.forwardRef(
64
67
  "div",
65
68
  {
66
69
  className: "ui-range-timeline-column",
67
- style: { flex: column.units },
70
+ style: { gridColumn: `span ${column.units}` },
68
71
  children: /* @__PURE__ */ jsx(Text, { size: "xs", children: column.label })
69
72
  },
70
73
  index
71
74
  )) })
72
75
  ] }),
73
76
  /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-body", children: [
74
- (bordered || columns.some((column) => column.muted)) && // Decorative: the same flex/units layout as the header columns, laid once behind every
75
- // row so each vertical rule runs the full body height exactly under its header column.
77
+ (bordered || columns.some((column) => column.muted)) && // Decorative: the same unit tracks as the header columns, laid once behind every row so
78
+ // each vertical rule runs the full body height exactly under its header column.
76
79
  /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-grid", "aria-hidden": "true", children: [
77
80
  /* @__PURE__ */ jsx("div", {}),
78
81
  /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-columns", children: columns.map((column, index) => /* @__PURE__ */ jsx(
@@ -80,7 +83,7 @@ const RangeTimeline = React.forwardRef(
80
83
  {
81
84
  className: "ui-range-timeline-grid-column",
82
85
  "data-muted": column.muted ? "true" : void 0,
83
- style: { flex: column.units }
86
+ style: { gridColumn: `span ${column.units}` }
84
87
  },
85
88
  index
86
89
  )) })
@@ -0,0 +1,25 @@
1
+ /**
2
+ * What a listed file IS, at the coarseness a row can actually draw (gh#720).
3
+ *
4
+ * A picture list shows a thumbnail for an image and a glyph for everything else, so the buckets
5
+ * are exactly the marks we have: five, not one per MIME type. The kind is also written onto the
6
+ * row as `data-file-kind`, so a service can retint a bucket without forking the component.
7
+ */
8
+ export type UploadFileKind = "image" | "pdf" | "archive" | "text" | "file";
9
+ /** The kind of one listed file, from its MIME type when it has one and its extension otherwise. */
10
+ export declare function uploadFileKind(item: {
11
+ name?: string;
12
+ mimeType?: string;
13
+ }): UploadFileKind;
14
+ /**
15
+ * The mark per kind. PDF takes the prose-lines document (`FileText`) because lucide ships no PDF
16
+ * glyph, which is also why plain/structured text takes the `</>` mark rather than the same one: a
17
+ * `.pdf` and a `.json` on adjacent rows must not draw identically.
18
+ */
19
+ export declare const UPLOAD_FILE_KIND_GLYPHS: {
20
+ readonly image: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
21
+ readonly pdf: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
22
+ readonly archive: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
23
+ readonly text: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
24
+ readonly file: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
25
+ };
@@ -0,0 +1,88 @@
1
+ import { File as FileGlyph, FileArchive, FileCode, FileImage, FileText } from "lucide-react";
2
+ const MIME_KINDS = {
3
+ "application/pdf": "pdf",
4
+ "application/x-pdf": "pdf",
5
+ "application/zip": "archive",
6
+ "application/x-zip-compressed": "archive",
7
+ "application/x-7z-compressed": "archive",
8
+ "application/vnd.rar": "archive",
9
+ "application/x-rar-compressed": "archive",
10
+ "application/gzip": "archive",
11
+ "application/x-tar": "archive",
12
+ "application/x-bzip": "archive",
13
+ "application/x-bzip2": "archive",
14
+ "application/json": "text",
15
+ "application/ld+json": "text",
16
+ "application/xml": "text",
17
+ "application/yaml": "text",
18
+ "application/x-yaml": "text"
19
+ };
20
+ const EXTENSION_KINDS = {
21
+ png: "image",
22
+ jpg: "image",
23
+ jpeg: "image",
24
+ gif: "image",
25
+ webp: "image",
26
+ avif: "image",
27
+ svg: "image",
28
+ bmp: "image",
29
+ ico: "image",
30
+ heic: "image",
31
+ heif: "image",
32
+ tif: "image",
33
+ tiff: "image",
34
+ pdf: "pdf",
35
+ zip: "archive",
36
+ tar: "archive",
37
+ gz: "archive",
38
+ tgz: "archive",
39
+ rar: "archive",
40
+ "7z": "archive",
41
+ bz2: "archive",
42
+ xz: "archive",
43
+ zst: "archive",
44
+ txt: "text",
45
+ md: "text",
46
+ markdown: "text",
47
+ json: "text",
48
+ jsonl: "text",
49
+ csv: "text",
50
+ tsv: "text",
51
+ log: "text",
52
+ xml: "text",
53
+ yml: "text",
54
+ yaml: "text",
55
+ html: "text",
56
+ htm: "text",
57
+ css: "text",
58
+ js: "text",
59
+ ts: "text"
60
+ };
61
+ function uploadFileKind(item) {
62
+ const mime = item.mimeType?.trim().toLowerCase();
63
+ if (mime) {
64
+ if (mime.startsWith("image/")) return "image";
65
+ if (mime.startsWith("text/")) return "text";
66
+ const known = MIME_KINDS[mime];
67
+ if (known) return known;
68
+ }
69
+ const name = item.name ?? "";
70
+ const dot = name.lastIndexOf(".");
71
+ if (dot > 0) {
72
+ const extension = name.slice(dot + 1).toLowerCase();
73
+ const known = EXTENSION_KINDS[extension];
74
+ if (known) return known;
75
+ }
76
+ return "file";
77
+ }
78
+ const UPLOAD_FILE_KIND_GLYPHS = {
79
+ image: FileImage,
80
+ pdf: FileText,
81
+ archive: FileArchive,
82
+ text: FileCode,
83
+ file: FileGlyph
84
+ };
85
+ export {
86
+ UPLOAD_FILE_KIND_GLYPHS,
87
+ uploadFileKind
88
+ };
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
2
  import type { UploadProp } from "../../props/components/data-entry.prop.js";
3
- export type { UploadProp, UploadProp as UploadProps, UploadFileItemProp, UploadVariantProp, } from "../../props/components/data-entry.prop.js";
3
+ export type { UploadProp, UploadProp as UploadProps, UploadFileItemProp, UploadVariantProp, UploadListTypeProp, } from "../../props/components/data-entry.prop.js";
4
4
  export type { UploadFileItem, UploadVariant, UploadCommitAction } from "./upload-types.js";
5
5
  export { collectUploadCommitActions, createUploadItem, UPLOAD_LIST_IGNORE } from "./upload-types.js";
6
6
  export { useUploadDraft } from "./use-upload-draft.js";
7
- export declare function Upload({ variant, triggerSize, triggerVariant, value, defaultValue, onValueChange, accept: acceptProp, multiple: multipleProp, maxCount: maxCountProp, maxSizeBytes, disabled: disabledProp, readOnly, directory, pastable, openFileDialogOnClick, name, action, method, headers, data, withCredentials, beforeUpload, onReject, onRemove, onPreview, onDownload, previewFile, onDrop, showUploadList, itemRender, removable, onUpload, id, className, children, ...ariaProps }: UploadProp): React.JSX.Element;
7
+ export declare function Upload({ variant, listType, triggerSize, triggerVariant, value, defaultValue, onValueChange, accept: acceptProp, multiple: multipleProp, maxCount: maxCountProp, maxSizeBytes, disabled: disabledProp, readOnly, directory, pastable, openFileDialogOnClick, name, action, method, headers, data, withCredentials, beforeUpload, onReject, onRemove, onPreview, onDownload, previewFile, onDrop, showUploadList, itemRender, removable, onUpload, id, className, children, ...ariaProps }: UploadProp): React.JSX.Element;
@@ -15,9 +15,10 @@ import { useTranslation } from "../../i18n/use-translation.js";
15
15
  import { formatBytes } from "../../lib/format.js";
16
16
  import { cn } from "../../lib/utils.js";
17
17
  import { resolveFieldA11y } from "../../lib/field-a11y.js";
18
- import { controlIconClass } from "../../lib/control-styles.js";
19
18
  import { Button } from "../general/button.js";
19
+ import { Icon } from "../general/icon.js";
20
20
  import { UploadCropDialog } from "./upload-crop-dialog.js";
21
+ import { UPLOAD_FILE_KIND_GLYPHS, uploadFileKind } from "./upload-file-kind.js";
21
22
  import {
22
23
  UPLOAD_LIST_IGNORE,
23
24
  createUploadItem,
@@ -66,6 +67,7 @@ function useUploadList(controlled, defaultValue, onValueChange) {
66
67
  }
67
68
  function Upload({
68
69
  variant = "dropzone",
70
+ listType,
69
71
  triggerSize,
70
72
  triggerVariant = "outline",
71
73
  value,
@@ -109,6 +111,7 @@ function Upload({
109
111
  triggerOwnsAriaLabel ? { ...ariaProps, "aria-label": void 0 } : ariaProps,
110
112
  t("dataEntry.upload.inputLabel")
111
113
  );
114
+ const resolvedListType = listType ?? (variant === "picture" ? "picture" : "text");
112
115
  const accept = acceptProp ?? defaultAcceptForVariant(variant);
113
116
  const maxCount = maxCountProp ?? defaultMaxCount(variant);
114
117
  const multiple = multipleProp ?? (maxCount === 1 ? false : true);
@@ -380,7 +383,7 @@ function Upload({
380
383
  hasCustomPreview: Boolean(onPreview),
381
384
  onDownload,
382
385
  itemRender,
383
- showThumbnails: variant === "picture"
386
+ listType: resolvedListType
384
387
  }
385
388
  ) : null;
386
389
  const hiddenInput = /* @__PURE__ */ jsx(
@@ -571,7 +574,7 @@ function Upload({
571
574
  onClick: openPicker,
572
575
  className: "ui-upload-picture-empty",
573
576
  children: [
574
- /* @__PURE__ */ jsx(ImagePlus, { className: controlIconClass, "aria-hidden": "true" }),
577
+ /* @__PURE__ */ jsx(ImagePlus, { className: "ui-upload-picture-empty-icon", "aria-hidden": "true" }),
575
578
  /* @__PURE__ */ jsx("span", { className: "ui-upload-picture-empty-label", children: t("dataEntry.upload.addImage") })
576
579
  ]
577
580
  }
@@ -621,7 +624,7 @@ function Upload({
621
624
  className: "ui-upload-avatar ui-focus-ring",
622
625
  "aria-label": t("dataEntry.upload.avatarLabel"),
623
626
  children: [
624
- !showPlaceholder && item?.previewUrl ? /* @__PURE__ */ jsx("img", { src: item.previewUrl, alt: "", className: "ui-upload-avatar-image" }) : /* @__PURE__ */ jsx("span", { className: "ui-upload-avatar-placeholder", children: /* @__PURE__ */ jsx(Camera, { className: controlIconClass, "aria-hidden": "true" }) }),
627
+ !showPlaceholder && item?.previewUrl ? /* @__PURE__ */ jsx("img", { src: item.previewUrl, alt: "", className: "ui-upload-avatar-image" }) : /* @__PURE__ */ jsx("span", { className: "ui-upload-avatar-placeholder", children: /* @__PURE__ */ jsx(Camera, { className: "ui-upload-avatar-icon", "aria-hidden": "true" }) }),
625
628
  !disabled && /* @__PURE__ */ jsx("span", { className: "ui-upload-avatar-change", children: t("dataEntry.upload.change") })
626
629
  ]
627
630
  }
@@ -750,12 +753,13 @@ function UploadFileList({
750
753
  hasCustomPreview,
751
754
  onDownload,
752
755
  itemRender,
753
- showThumbnails
756
+ listType
754
757
  }) {
755
758
  const { t } = useTranslation();
756
759
  return /* @__PURE__ */ jsx("ul", { className: "ui-stack-xs", children: items.map((item) => {
760
+ const kind = uploadFileKind(item);
757
761
  const node = /* @__PURE__ */ jsxs("div", { className: "ui-upload-row", children: [
758
- showThumbnails && item.previewUrl && /* @__PURE__ */ jsx("img", { src: item.previewUrl, alt: "", className: "ui-upload-list-thumb" }),
762
+ listType === "picture" && (item.previewUrl ? /* @__PURE__ */ jsx("img", { src: item.previewUrl, alt: "", className: "ui-upload-list-thumb" }) : /* @__PURE__ */ jsx("span", { className: "ui-upload-list-glyph", "data-file-kind": kind, children: /* @__PURE__ */ jsx(Icon, { as: UPLOAD_FILE_KIND_GLYPHS[kind], size: "lg" }) })),
759
763
  /* @__PURE__ */ jsxs("div", { className: "ui-upload-row-main", children: [
760
764
  /* @__PURE__ */ jsx("div", { className: "truncate font-medium", children: item.name }),
761
765
  /* @__PURE__ */ jsxs("div", { className: "text-muted-foreground text-xs", children: [
@@ -19,7 +19,7 @@ import type { AvatarProp } from "../../props/components/data-display.prop.js";
19
19
  type ImageLoadingStatus = "idle" | "loading" | "loaded" | "error";
20
20
  export declare const Avatar: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & {
21
21
  asChild?: boolean;
22
- } & Pick<AvatarProp, "appearance" | "presence" | "presenceLabel" | "shape"> & React.RefAttributes<HTMLSpanElement>>;
22
+ } & Pick<AvatarProp, "appearance" | "presence" | "presenceLabel" | "shape" | "size"> & React.RefAttributes<HTMLSpanElement>>;
23
23
  export declare const AvatarImage: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>, "ref"> & {
24
24
  asChild?: boolean;
25
25
  onLoadingStatusChange?: (status: ImageLoadingStatus) => void;
@@ -53,6 +53,7 @@ const Avatar = React.forwardRef(
53
53
  ({
54
54
  className,
55
55
  shape = "circle",
56
+ size = "md",
56
57
  appearance = "default",
57
58
  presence,
58
59
  presenceLabel,
@@ -73,6 +74,7 @@ const Avatar = React.forwardRef(
73
74
  ref,
74
75
  "data-slot": "avatar",
75
76
  "data-shape": shape === "square" ? "square" : void 0,
77
+ "data-size": size === "md" ? void 0 : size,
76
78
  "data-appearance": appearance === "tinted" ? "tinted" : void 0,
77
79
  "data-presence": presence,
78
80
  className: cn("ui-avatar", className),
@@ -42,8 +42,13 @@ export type SegmentedProp = {
42
42
  block?: boolean;
43
43
  /** antd `vertical` — stack the choices in a column. Arrow keys follow the axis. */
44
44
  vertical?: boolean;
45
- /** Control height tier: `md` (default), `sm` or `lg` — the same tiers as every other control. */
46
- size?: "sm" | "md" | "lg";
45
+ /**
46
+ * Control height tier: `md` (default), `xs`, `sm` or `lg` — the same `--control-height-*` tier
47
+ * every other control reads. `xs` is the fourth step (gh#719, the one Toggle/ToggleGroup took in
48
+ * gh#716): a 24px-dense row can carry a real segmented control instead of a hand-rolled row of
49
+ * Buttons.
50
+ */
51
+ size?: "xs" | "sm" | "md" | "lg";
47
52
  /** Disable the whole group. */
48
53
  disabled?: boolean;
49
54
  /** Form field name — submits the selected value with the form. */
@@ -2,7 +2,7 @@ import * as React from "react";
2
2
  import { type VariantProps } from "class-variance-authority";
3
3
  declare const toggleVariants: (props?: ({
4
4
  variant?: "default" | "outline" | null | undefined;
5
- size?: "lg" | "md" | "sm" | null | undefined;
5
+ size?: "lg" | "md" | "sm" | "xs" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  /**
8
8
  * Not exported on its own — it is folded into `ToggleProp` and `ToggleGroupItemProp` so there is
@@ -69,7 +69,7 @@ export type ToggleProp = React.ComponentPropsWithoutRef<"button"> & TogglePresse
69
69
  export type ToggleProps = ToggleProp;
70
70
  export declare const Toggle: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & TogglePressedFields & VariantProps<(props?: ({
71
71
  variant?: "default" | "outline" | null | undefined;
72
- size?: "lg" | "md" | "sm" | null | undefined;
72
+ size?: "lg" | "md" | "sm" | "xs" | null | undefined;
73
73
  } & import("class-variance-authority/types").ClassProp) | undefined) => string> & ToggleCountFields & React.RefAttributes<HTMLButtonElement>>;
74
74
  export { toggleVariants, useCounterPill, restoreDomProps };
75
75
  export type { ToggleCountFields, TogglePressedFields };
@@ -13,6 +13,10 @@ const toggleVariants = cva("ui-toggle", {
13
13
  outline: "ui-toggle-outline"
14
14
  },
15
15
  size: {
16
+ // The fourth step of the shared control ladder (gh#716): 24px, `--control-height-xs`, the
17
+ // same tier `Button size="xs"` reads — so a 24px-dense row can carry a segmented control
18
+ // instead of someone hand-rolling one out of Buttons.
19
+ xs: "ui-toggle-xs",
16
20
  sm: "ui-toggle-sm",
17
21
  md: "ui-toggle-default-size",
18
22
  lg: "ui-toggle-lg"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
3
- "version": "27.4.1",
3
+ "version": "27.6.0",
4
4
  "targetSize": {
5
5
  "standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
6
6
  "min": 24,
@@ -208,6 +208,20 @@ export type DescriptionsItemProp = {
208
208
  */
209
209
  export type AvatarProp = React.ComponentPropsWithoutRef<"span"> & {
210
210
  shape?: AvatarShapeProp;
211
+ /**
212
+ * Box size on the shared control ladder — `md` (default) is `--control-height`, and `xs`/`sm`/
213
+ * `lg` are `--control-height-xs/-sm/-lg`, the SAME tier Button and Input read. State it when the
214
+ * mark has to sit in a row the row's height already decided: inside an `icon-sm` trigger, in a
215
+ * 24px dense table row, beside a `size="sm"` Button. Before gh#716 the box was welded to
216
+ * `--control-height`, so a 32px mark inside a 28px trigger overflowed it and the only legal move
217
+ * left was raising the whole row.
218
+ *
219
+ * The initials' type step and a glyph's box move with the box — one step of the type scale and
220
+ * one step of the `--icon-size-*` scale per step — so a small mark is small, not clipped.
221
+ * `shape="square"` rides the identical ladder. Beyond the ladder (a 96px profile mark) is a
222
+ * `className` size utility, exactly as before; the ladder is for the control row.
223
+ */
224
+ size?: SizeProp;
211
225
  appearance?: AvatarAppearanceProp;
212
226
  /**
213
227
  * Presence — WHO is reachable right now, drawn as an indicator at the block-end/inline-end
@@ -745,8 +745,9 @@ export type CalendarProp = DayPickerProps & CalendarFooterProp & {
745
745
  *
746
746
  * Default `true` — the owner's call, from a real screen: with no ruling the month read as a
747
747
  * cloud of numbers and was "very hard to read". Pass `bordered={false}` for the floating-button
748
- * look. The line colour is `--calendar-grid-border-color` (default `--input`, the ≥3:1 tier;
749
- * the decorative `--border` measured 1.15:1 and was invisible as a 1px ruling).
748
+ * look. The line colour is `--calendar-grid-border-color` (default `--input` at 0.5 alpha,
749
+ * 1.74:1 light / 1.95:1 dark on the popover; the full `--input` read too dark, and the
750
+ * decorative `--border` measured 1.15:1 and was invisible as a 1px ruling).
750
751
  */
751
752
  bordered?: boolean;
752
753
  /** Decorate a day cell — 祝日, a booked day, a deadline. @see CalendarCellRenderProp */
@@ -1464,9 +1465,34 @@ export type SelectDataProp = SearchSelectBaseProp & {
1464
1465
  export type UploadFileItemProp = UploadFileItem;
1465
1466
  /** @see Upload */
1466
1467
  export type UploadVariantProp = "dropzone" | "button" | "picture-card" | "picture" | "avatar" | "avatar-crop";
1468
+ /**
1469
+ * Upload `listType` — HOW THE CHOSEN FILES ARE LISTED, ported from antd (gh#720).
1470
+ *
1471
+ * antd separates two axes and this component had only one: `variant` says how a file is PICKED
1472
+ * (drag area, button, tile grid, avatar), `listType` says how the picked ones are DRAWN. Welding
1473
+ * the second onto the first meant a `variant="dropzone"` could not show a thumbnail even for an
1474
+ * item that already carried a `previewUrl`, and its rows carried no per-type mark at all — a
1475
+ * drawer listing a `.png` beside a `.json` and a `.txt` could draw only three identical
1476
+ * name-and-size rows.
1477
+ *
1478
+ * - `text` — name, size, actions. The row every dropzone/button list has always drawn.
1479
+ * - `picture` — a leading box on every row: the thumbnail when the item has a `previewUrl`, and
1480
+ * otherwise the glyph for its file kind (image / pdf / archive / text / generic). Both boxes are
1481
+ * the same size, so a mixed list keeps one row height.
1482
+ *
1483
+ * antd's third value, `picture-card`, is `variant="picture-card"` here: in that variant the tile
1484
+ * grid IS the picker (the add tile sits inside the grid), so it is not a listing that can be put
1485
+ * under a different trigger. It is deliberately not offered as a `listType`.
1486
+ */
1487
+ export type UploadListTypeProp = "text" | "picture";
1467
1488
  /** @see Upload — presentational; wire `onUpload` to media-service in app api.ts */
1468
1489
  export type UploadProp = FieldA11yProps & {
1469
1490
  variant?: UploadVariantProp;
1491
+ /**
1492
+ * @see UploadListTypeProp — an axis of its own, independent of `variant`. Defaults to the
1493
+ * listing each variant already drew: `picture` for `variant="picture"`, `text` everywhere else.
1494
+ */
1495
+ listType?: UploadListTypeProp;
1470
1496
  value?: ValueProp<UploadFileItemProp[]>;
1471
1497
  defaultValue?: DefaultValueProp<UploadFileItemProp[]>;
1472
1498
  onValueChange?: OnValueChangeProp<UploadFileItemProp[]>;
@@ -1650,6 +1650,11 @@ export declare const COMPONENT_PROP_REGISTRY: {
1650
1650
  readonly file: "components/data-entry.prop.ts";
1651
1651
  readonly vocabulary: readonly [];
1652
1652
  };
1653
+ readonly UploadListTypeProp: {
1654
+ readonly group: "data-entry";
1655
+ readonly file: "components/data-entry.prop.ts";
1656
+ readonly vocabulary: readonly [];
1657
+ };
1653
1658
  readonly TreeOptionProp: {
1654
1659
  readonly group: "data-entry";
1655
1660
  readonly file: "components/data-entry.prop.ts";
@@ -1708,7 +1713,7 @@ export declare const COMPONENT_PROP_REGISTRY: {
1708
1713
  readonly AvatarProp: {
1709
1714
  readonly group: "data-display";
1710
1715
  readonly file: "components/data-display.prop.ts";
1711
- readonly vocabulary: readonly ["AvatarShapeProp", "LabelProp", "ChildrenProp", "ClassNameProp"];
1716
+ readonly vocabulary: readonly ["AvatarShapeProp", "SizeProp", "LabelProp", "ChildrenProp", "ClassNameProp"];
1712
1717
  };
1713
1718
  readonly AvatarAppearanceProp: {
1714
1719
  readonly group: "data-display";
@@ -1935,6 +1935,11 @@ const COMPONENT_PROP_REGISTRY = {
1935
1935
  vocabulary: []
1936
1936
  },
1937
1937
  UploadVariantProp: { group: "data-entry", file: "components/data-entry.prop.ts", vocabulary: [] },
1938
+ UploadListTypeProp: {
1939
+ group: "data-entry",
1940
+ file: "components/data-entry.prop.ts",
1941
+ vocabulary: []
1942
+ },
1938
1943
  TreeOptionProp: {
1939
1944
  group: "data-entry",
1940
1945
  file: "components/data-entry.prop.ts",
@@ -2042,7 +2047,7 @@ const COMPONENT_PROP_REGISTRY = {
2042
2047
  AvatarProp: {
2043
2048
  group: "data-display",
2044
2049
  file: "components/data-display.prop.ts",
2045
- vocabulary: ["AvatarShapeProp", "LabelProp", "ChildrenProp", "ClassNameProp"]
2050
+ vocabulary: ["AvatarShapeProp", "SizeProp", "LabelProp", "ChildrenProp", "ClassNameProp"]
2046
2051
  },
2047
2052
  AvatarAppearanceProp: {
2048
2053
  group: "data-display",
@@ -31,6 +31,12 @@
31
31
  padding-inline: var(--space-3);
32
32
  }
33
33
 
34
+ .ui-toggle-xs {
35
+ min-height: var(--control-height-xs);
36
+ padding-inline: var(--space-1);
37
+ font-size: var(--toggle-xs-font-size);
38
+ }
39
+
34
40
  .ui-toggle-sm {
35
41
  min-height: var(--control-height-sm);
36
42
  padding-inline: var(--space-2);
@@ -2223,13 +2229,13 @@
2223
2229
 
2224
2230
  .ui-calendar[data-bordered="true"] .ui-calendar-day,
2225
2231
  .ui-calendar[data-bordered="true"] .ui-calendar-weekday {
2226
- border-inline-start: 1px solid var(--calendar-grid-border-color, hsl(var(--input)));
2227
- border-block-start: 1px solid var(--calendar-grid-border-color, hsl(var(--input)));
2232
+ border-inline-start: 1px solid var(--calendar-grid-border-color, hsl(var(--input) / 0.5));
2233
+ border-block-start: 1px solid var(--calendar-grid-border-color, hsl(var(--input) / 0.5));
2228
2234
  }
2229
2235
 
2230
2236
  .ui-calendar[data-bordered="true"] .ui-calendar-week,
2231
2237
  .ui-calendar[data-bordered="true"] .ui-calendar-weekdays {
2232
- border-inline-end: 1px solid var(--calendar-grid-border-color, hsl(var(--input)));
2238
+ border-inline-end: 1px solid var(--calendar-grid-border-color, hsl(var(--input) / 0.5));
2233
2239
  }
2234
2240
 
2235
2241
  .ui-calendar[data-bordered="true"] .ui-calendar-weekday {
@@ -2241,7 +2247,7 @@
2241
2247
  }
2242
2248
 
2243
2249
  .ui-calendar[data-bordered="true"] .ui-calendar-grid {
2244
- border-block-end: 1px solid var(--calendar-grid-border-color, hsl(var(--input)));
2250
+ border-block-end: 1px solid var(--calendar-grid-border-color, hsl(var(--input) / 0.5));
2245
2251
  }
2246
2252
 
2247
2253
  .ui-calendar[data-bordered="true"] .ui-calendar-day.invisible {
@@ -2262,8 +2268,8 @@
2262
2268
 
2263
2269
  .ui-calendar[data-bordered="true"] .ui-calendar-week-number,
2264
2270
  .ui-calendar[data-bordered="true"] .ui-calendar-week-number-header {
2265
- border-inline-start: 1px solid var(--calendar-grid-border-color, hsl(var(--input)));
2266
- border-block-start: 1px solid var(--calendar-grid-border-color, hsl(var(--input)));
2271
+ border-inline-start: 1px solid var(--calendar-grid-border-color, hsl(var(--input) / 0.5));
2272
+ border-block-start: 1px solid var(--calendar-grid-border-color, hsl(var(--input) / 0.5));
2267
2273
  }
2268
2274
 
2269
2275
  .ui-calendar[data-bordered="true"] .ui-calendar-day {
@@ -3135,6 +3141,12 @@
3135
3141
  justify-content: flex-start;
3136
3142
  }
3137
3143
 
3144
+ .ui-segmented[data-size="xs"] {
3145
+ --control-height: var(--control-height-xs);
3146
+ --segmented-item-padding-inline: var(--segmented-xs-item-padding-inline);
3147
+ font-size: var(--segmented-xs-font-size);
3148
+ }
3149
+
3138
3150
  .ui-segmented[data-size="sm"] {
3139
3151
  --control-height: var(--control-height-sm);
3140
3152
  }
@@ -2,8 +2,8 @@
2
2
  .ui-avatar {
3
3
  position: relative;
4
4
  display: inline-flex;
5
- width: var(--control-height);
6
- height: var(--control-height);
5
+ width: var(--avatar-size);
6
+ height: var(--avatar-size);
7
7
  flex-shrink: 0;
8
8
  align-items: center;
9
9
  justify-content: center;
@@ -13,7 +13,7 @@
13
13
  linear-gradient(var(--avatar-tint), var(--avatar-tint)),
14
14
  var(--avatar-background, hsl(var(--muted)));
15
15
  color: hsl(var(--muted-foreground));
16
- font-size: var(--font-size-base);
16
+ font-size: var(--avatar-font-size);
17
17
  font-weight: var(--font-weight-medium);
18
18
  }
19
19
 
@@ -36,6 +36,36 @@
36
36
  flex: none;
37
37
  }
38
38
 
39
+ .ui-avatar[data-size="xs"] {
40
+ --avatar-size: var(--avatar-size-xs);
41
+ --avatar-square-size: var(--avatar-size-xs);
42
+ --avatar-font-size: var(--avatar-font-size-xs);
43
+ --avatar-glyph-size: var(--avatar-glyph-size-xs);
44
+ --avatar-tinted-glyph-size: var(--avatar-glyph-size-xs);
45
+ }
46
+
47
+ .ui-avatar[data-size="sm"] {
48
+ --avatar-size: var(--avatar-size-sm);
49
+ --avatar-square-size: var(--avatar-size-sm);
50
+ --avatar-font-size: var(--avatar-font-size-sm);
51
+ --avatar-glyph-size: var(--avatar-glyph-size-sm);
52
+ --avatar-tinted-glyph-size: var(--avatar-glyph-size-sm);
53
+ }
54
+
55
+ .ui-avatar[data-size="lg"] {
56
+ --avatar-size: var(--avatar-size-lg);
57
+ --avatar-square-size: var(--avatar-size-lg);
58
+ --avatar-font-size: var(--avatar-font-size-lg);
59
+ --avatar-glyph-size: var(--avatar-glyph-size-lg);
60
+ --avatar-tinted-glyph-size: var(--avatar-glyph-size-lg);
61
+ }
62
+
63
+ .ui-avatar[data-size] svg {
64
+ inline-size: var(--avatar-glyph-size);
65
+ block-size: var(--avatar-glyph-size);
66
+ flex: none;
67
+ }
68
+
39
69
  .ui-avatar-image {
40
70
  width: 100%;
41
71
  height: 100%;
@@ -1066,8 +1096,8 @@
1066
1096
  }
1067
1097
 
1068
1098
  .ui-prose a {
1069
- color: hsl(var(--primary));
1070
- text-decoration: underline;
1099
+ color: hsl(var(--prose-link-color, var(--primary)));
1100
+ text-decoration-line: var(--prose-link-decoration-line);
1071
1101
  }
1072
1102
 
1073
1103
  .ui-prose table {
@@ -1321,8 +1351,10 @@
1321
1351
  padding: var(--space-2);
1322
1352
  border-inline-end: 1px solid hsl(var(--range-timeline-border-color));
1323
1353
  }
1354
+
1324
1355
  .ui-range-timeline-columns {
1325
- display: flex;
1356
+ display: grid;
1357
+ grid-template-columns: repeat(var(--range-timeline-units, 1), minmax(0, 1fr));
1326
1358
  }
1327
1359
  .ui-range-timeline-column {
1328
1360
  min-inline-size: 0;
@@ -1360,12 +1392,12 @@
1360
1392
  .ui-range-timeline[data-bordered="true"] .ui-range-timeline-column,
1361
1393
  .ui-range-timeline[data-bordered="true"] .ui-range-timeline-label,
1362
1394
  .ui-range-timeline[data-bordered="true"] .ui-range-timeline-grid-column {
1363
- border-inline-end-color: var(--range-timeline-grid-color, hsl(var(--input)));
1395
+ border-inline-end-color: var(--range-timeline-grid-color, hsl(var(--input) / 0.5));
1364
1396
  }
1365
1397
  .ui-range-timeline[data-bordered="true"] .ui-range-timeline-header + .ui-range-timeline-header,
1366
1398
  .ui-range-timeline[data-bordered="true"] .ui-range-timeline-row {
1367
1399
  border-block-start: var(--range-timeline-grid-width) solid
1368
- var(--range-timeline-grid-color, hsl(var(--input)));
1400
+ var(--range-timeline-grid-color, hsl(var(--input) / 0.5));
1369
1401
  }
1370
1402
  .ui-range-timeline-outside {
1371
1403
  position: absolute;
@@ -199,6 +199,18 @@
199
199
  flex-shrink: 0;
200
200
  }
201
201
 
202
+ .ui-upload-list-glyph {
203
+ display: flex;
204
+ align-items: center;
205
+ justify-content: center;
206
+ inline-size: var(--control-height-lg);
207
+ block-size: var(--control-height-lg);
208
+ border-radius: var(--radius);
209
+ background-color: hsl(var(--muted));
210
+ color: hsl(var(--muted-foreground));
211
+ flex-shrink: 0;
212
+ }
213
+
202
214
  .ui-upload-picture-item {
203
215
  inline-size: var(--upload-tile-size);
204
216
  overflow-wrap: anywhere;
@@ -336,6 +348,11 @@
336
348
  border-color: hsl(var(--primary));
337
349
  }
338
350
 
351
+ .ui-upload-picture-empty-icon {
352
+ inline-size: var(--upload-picture-icon-size);
353
+ block-size: var(--upload-picture-icon-size);
354
+ }
355
+
339
356
  .ui-upload-picture-empty-label {
340
357
  margin-block-start: var(--upload-picture-empty-label-space-block-start);
341
358
  font-size: var(--upload-picture-empty-label-font-size);
@@ -370,6 +387,11 @@
370
387
  color: hsl(var(--muted-foreground));
371
388
  }
372
389
 
390
+ .ui-upload-avatar-icon {
391
+ inline-size: var(--upload-avatar-icon-size);
392
+ block-size: var(--upload-avatar-icon-size);
393
+ }
394
+
373
395
  .ui-upload-avatar-change {
374
396
  position: absolute;
375
397
  inset-inline: 0;
@@ -166,6 +166,7 @@
166
166
  --search-input-label-font-size: var(--font-size-xs);
167
167
  --tag-input-chip-font-size: var(--font-size-xs);
168
168
  --toggle-sm-font-size: var(--font-size-xs);
169
+ --toggle-xs-font-size: var(--font-size-xs);
169
170
  --button-sm-font-size: var(--font-size-xs);
170
171
  }
171
172