@godxjp/ui 31.27.0 → 31.28.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 (52) hide show
  1. package/agent/START-HERE.md +7 -7
  2. package/agent/components/BlockEditor.json +8 -0
  3. package/agent/components/CommandPalette.json +5 -0
  4. package/agent/components/EmojiPicker.json +78 -0
  5. package/agent/components/Markdown.json +11 -0
  6. package/agent/components/PageContainer.json +11 -1
  7. package/agent/components/PageCover.json +75 -0
  8. package/agent/components/Tree.json +6 -0
  9. package/agent/components-index.json +10 -0
  10. package/agent/components.json +194 -1
  11. package/agent/index.json +8 -8
  12. package/agent/llms.txt +7 -7
  13. package/agent/tokens.json +79 -1
  14. package/dist/components/data-display/tree.js +5 -0
  15. package/dist/components/data-entry/command-palette.d.ts +5 -0
  16. package/dist/components/data-entry/command-palette.js +1 -0
  17. package/dist/components/data-entry/emoji-data.d.ts +43 -0
  18. package/dist/components/data-entry/emoji-data.js +54 -0
  19. package/dist/components/data-entry/emoji-picker.d.ts +13 -0
  20. package/dist/components/data-entry/emoji-picker.js +272 -0
  21. package/dist/components/data-entry/index.d.ts +2 -0
  22. package/dist/components/data-entry/index.js +2 -0
  23. package/dist/components/layout/index.d.ts +2 -0
  24. package/dist/components/layout/index.js +2 -0
  25. package/dist/components/layout/page-container.d.ts +1 -1
  26. package/dist/components/layout/page-container.js +8 -1
  27. package/dist/components/layout/page-cover.d.ts +14 -0
  28. package/dist/components/layout/page-cover.js +127 -0
  29. package/dist/contracts/measurement.json +1 -1
  30. package/dist/i18n/messages/en.json +25 -0
  31. package/dist/i18n/messages/ja.json +25 -0
  32. package/dist/i18n/messages/vi.json +25 -0
  33. package/dist/props/components/data-display.prop.d.ts +6 -0
  34. package/dist/props/components/data-entry.prop.d.ts +26 -0
  35. package/dist/props/components/layout.prop.d.ts +49 -2
  36. package/dist/props/registry.d.ts +85 -1
  37. package/dist/props/registry.js +95 -1
  38. package/dist/styles/control.css +81 -0
  39. package/dist/styles/data-display-layout.css +94 -0
  40. package/dist/styles/focus-ring.css +2 -0
  41. package/dist/styles/layers.json +17 -1
  42. package/dist/styles/layout.css +113 -0
  43. package/dist/tokens/components/control.css +10 -0
  44. package/dist/tokens/components/data-display.css +1 -0
  45. package/dist/tokens/semantic/layout.css +14 -0
  46. package/docs/FRAME-COVERAGE-REPORT.md +4 -2
  47. package/docs/data-entry/emoji-picker.tsx +35 -0
  48. package/docs/i18n/messages/en.json +16 -0
  49. package/docs/i18n/messages/ja.json +16 -0
  50. package/docs/i18n/messages/vi.json +16 -0
  51. package/docs/layout/page-cover.tsx +56 -0
  52. package/package.json +5 -2
@@ -1,4 +1,5 @@
1
1
  import { PageContainer } from "./page-container.js";
2
+ import { PageCover } from "./page-cover.js";
2
3
  import { Flex } from "./flex.js";
3
4
  import { SpaceCompact } from "./space-compact.js";
4
5
  import { ResizablePanel, ResizablePanelGroup, ResizableHandle } from "./resizable.js";
@@ -55,6 +56,7 @@ export {
55
56
  NavList,
56
57
  OrgSwitcher,
57
58
  PageContainer,
59
+ PageCover,
58
60
  ResizableHandle,
59
61
  ResizablePanel,
60
62
  ResizablePanelGroup,
@@ -2,7 +2,7 @@ import type { PageContainerProp, PageInsetProp } from "../../props/components/la
2
2
  export type { PageContainerProp, PageContainerProp as PageContainerProps, PageContainerExtraProp, } from "../../props/components/layout.prop.js";
3
3
  export type { BreadcrumbItemProp, BreadcrumbItemProp as BreadcrumbItem, } from "../../props/vocabulary/navigation.prop.js";
4
4
  export declare function PageContainerInset({ className, children, ...props }: PageInsetProp): import("react").JSX.Element;
5
- declare function PageContainerRoot({ title, subtitle, status, extra, toolbar, footer, toolbarPad, footerPad, breadcrumb, breadcrumbLabel, breadcrumbAriaLabel, linkComponent: LinkComponent, headerLoading, titleRef, density, variant, preset, headerLayout, headerScale, measure, stickyFooter, footerReveal, fill, children, className, }: PageContainerProp): import("react").JSX.Element;
5
+ declare function PageContainerRoot({ title, subtitle, status, extra, toolbar, footer, toolbarPad, footerPad, breadcrumb, breadcrumbLabel, breadcrumbAriaLabel, linkComponent: LinkComponent, headerLoading, titleRef, density, variant, preset, headerLayout, headerScale, icon, cover, measure, stickyFooter, footerReveal, fill, children, className, }: PageContainerProp): import("react").JSX.Element;
6
6
  export declare const PageContainer: typeof PageContainerRoot & {
7
7
  Inset: typeof PageContainerInset;
8
8
  };
@@ -51,6 +51,8 @@ function PageContainerRoot({
51
51
  preset = "default",
52
52
  headerLayout = "stack",
53
53
  headerScale = "document",
54
+ icon,
55
+ cover,
54
56
  measure = "default",
55
57
  stickyFooter = false,
56
58
  footerReveal = "always",
@@ -63,12 +65,14 @@ function PageContainerRoot({
63
65
  const { t } = useTranslation();
64
66
  const { start: extraStart, end: extraEnd } = resolvePageExtra(extra);
65
67
  const titleFocus = titleRef === void 0 ? void 0 : { ref: titleRef, tabIndex: -1 };
68
+ const coverVariant = cover == null || cover === false ? void 0 : isValidElement(cover) && cover.props.variant === "eyecatch" ? "eyecatch" : "banner";
66
69
  return /* @__PURE__ */ jsxs(
67
70
  "div",
68
71
  {
69
72
  "data-preset": preset,
70
73
  "data-measure": measure,
71
- "data-header-scale": headerScale === "chrome" ? "chrome" : void 0,
74
+ "data-header-scale": headerScale === "document" ? void 0 : headerScale,
75
+ "data-cover": coverVariant,
72
76
  "data-revealed": revealed ? "true" : void 0,
73
77
  className: cn(
74
78
  "ui-page-container",
@@ -82,6 +86,7 @@ function PageContainerRoot({
82
86
  className
83
87
  ),
84
88
  children: [
89
+ coverVariant === "banner" ? /* @__PURE__ */ jsx("div", { className: "ui-page-cover-slot", children: cover }) : null,
85
90
  /* @__PURE__ */ jsxs(
86
91
  "header",
87
92
  {
@@ -134,8 +139,10 @@ function PageContainerRoot({
134
139
  }) })
135
140
  }
136
141
  ),
142
+ coverVariant === "eyecatch" ? /* @__PURE__ */ jsx("div", { className: "ui-page-cover-slot", children: cover }) : null,
137
143
  /* @__PURE__ */ jsxs("div", { className: "ui-page-header-row", children: [
138
144
  /* @__PURE__ */ jsxs("div", { className: "ui-page-header-heading", children: [
145
+ icon != null && icon !== false ? /* @__PURE__ */ jsx("div", { className: "ui-page-header-icon", children: icon }) : null,
139
146
  headerLoading ? /* @__PURE__ */ jsx(
140
147
  "h1",
141
148
  {
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ import type { PageCoverProp } from "../../props/components/layout.prop.js";
3
+ export type { PageCoverProp, PageCoverProp as PageCoverProps, } from "../../props/components/layout.prop.js";
4
+ /**
5
+ * PageCover (gh#1160) — a page's cover image: Notion's banner across the top, or note.com's
6
+ * eyecatch in the reading column (`variant="eyecatch"`, ~1.91:1, rounded). Put it in
7
+ * `PageContainer cover`, which places it and lets the page `icon` overlap its bottom edge.
8
+ *
9
+ * The focal point is `positionY` (0 top – 100 bottom), applied as `object-position: 50% y%`.
10
+ * While `repositioning`, the image IS the control: a vertical WAI-ARIA slider that follows a drag
11
+ * (pixels map to percent through the image's real overflow, so the picture tracks the pointer)
12
+ * and the slider keys (arrows ±1, PageUp / PageDown ±10, Home / End); Enter or Escape ends it.
13
+ */
14
+ export declare const PageCover: React.ForwardRefExoticComponent<PageCoverProp & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,127 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { useTranslation } from "../../i18n/use-translation.js";
5
+ import { cn } from "../../lib/utils.js";
6
+ const clamp = (value) => Math.min(100, Math.max(0, Math.round(value)));
7
+ const PageCover = React.forwardRef(function PageCover2({
8
+ src,
9
+ alt,
10
+ positionY = 50,
11
+ onPositionChange,
12
+ repositioning = false,
13
+ onRepositioningChange,
14
+ variant = "banner",
15
+ height = "md",
16
+ actions,
17
+ id,
18
+ className
19
+ }, ref) {
20
+ const { t } = useTranslation();
21
+ const frameRef = React.useRef(null);
22
+ const imageRef = React.useRef(null);
23
+ const drag = React.useRef(null);
24
+ const y = clamp(positionY);
25
+ const overflow = () => {
26
+ const frame = frameRef.current;
27
+ const image = imageRef.current;
28
+ if (!frame || !image || !image.naturalWidth) return 0;
29
+ const rendered = frame.clientWidth / image.naturalWidth * image.naturalHeight;
30
+ return Math.max(0, rendered - frame.clientHeight);
31
+ };
32
+ const onKeyDown = (event) => {
33
+ if (!repositioning) return;
34
+ const step = {
35
+ ArrowUp: 1,
36
+ ArrowRight: 1,
37
+ ArrowDown: -1,
38
+ ArrowLeft: -1,
39
+ PageUp: 10,
40
+ PageDown: -10
41
+ }[event.key];
42
+ let next = null;
43
+ if (step !== void 0) next = clamp(y + step);
44
+ else if (event.key === "Home") next = 0;
45
+ else if (event.key === "End") next = 100;
46
+ else if (event.key === "Enter" || event.key === "Escape") {
47
+ event.preventDefault();
48
+ onRepositioningChange?.(false);
49
+ return;
50
+ }
51
+ if (next === null) return;
52
+ event.preventDefault();
53
+ if (next !== y) onPositionChange?.(next);
54
+ };
55
+ const onPointerDown = (event) => {
56
+ if (!repositioning || event.button !== 0) return;
57
+ event.currentTarget.setPointerCapture(event.pointerId);
58
+ drag.current = { pointer: event.pointerId, startY: event.clientY, startValue: y };
59
+ };
60
+ const onPointerMove = (event) => {
61
+ const active = drag.current;
62
+ if (!active || active.pointer !== event.pointerId) return;
63
+ const travel = overflow();
64
+ if (travel <= 0) return;
65
+ const next = clamp(active.startValue - (event.clientY - active.startY) / travel * 100);
66
+ if (next !== y) onPositionChange?.(next);
67
+ };
68
+ const endDrag = (event) => {
69
+ if (drag.current?.pointer === event.pointerId) drag.current = null;
70
+ };
71
+ const slider = repositioning ? {
72
+ role: "slider",
73
+ tabIndex: 0,
74
+ "aria-orientation": "vertical",
75
+ "aria-valuemin": 0,
76
+ "aria-valuemax": 100,
77
+ "aria-valuenow": y,
78
+ "aria-valuetext": t("layout.pageCover.valueText", { value: y }),
79
+ "aria-label": t("layout.pageCover.position")
80
+ } : {};
81
+ return /* @__PURE__ */ jsxs(
82
+ "div",
83
+ {
84
+ ref,
85
+ id,
86
+ "data-slot": "page-cover",
87
+ "data-variant": variant,
88
+ "data-height": variant === "banner" ? height : void 0,
89
+ "data-repositioning": repositioning ? "" : void 0,
90
+ className: cn("ui-page-cover", className),
91
+ children: [
92
+ /* @__PURE__ */ jsxs(
93
+ "div",
94
+ {
95
+ ref: frameRef,
96
+ className: "ui-page-cover-frame ui-focus-ring",
97
+ onKeyDown,
98
+ onPointerDown,
99
+ onPointerMove,
100
+ onPointerUp: endDrag,
101
+ onPointerCancel: endDrag,
102
+ ...slider,
103
+ children: [
104
+ /* @__PURE__ */ jsx(
105
+ "img",
106
+ {
107
+ ref: imageRef,
108
+ className: "ui-page-cover-image",
109
+ src,
110
+ alt,
111
+ draggable: false,
112
+ style: { objectPosition: `50% ${y}%` }
113
+ }
114
+ ),
115
+ repositioning ? /* @__PURE__ */ jsx("span", { className: "ui-page-cover-hint", "aria-hidden": "true", children: t("layout.pageCover.hint") }) : null
116
+ ]
117
+ }
118
+ ),
119
+ actions != null ? /* @__PURE__ */ jsx("div", { className: "ui-page-cover-actions", children: actions }) : null
120
+ ]
121
+ }
122
+ );
123
+ });
124
+ PageCover.displayName = "PageCover";
125
+ export {
126
+ PageCover
127
+ };
@@ -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": "31.27.0",
3
+ "version": "31.28.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,
@@ -212,6 +212,26 @@
212
212
  "openDialog": "Choose from list",
213
213
  "openSearch": "Search",
214
214
  "suggestions": "Suggestions"
215
+ },
216
+ "emojiPicker": {
217
+ "trigger": "Choose an icon",
218
+ "search": "Search emoji",
219
+ "recent": "Recently used",
220
+ "remove": "Remove icon",
221
+ "empty": "No emoji found",
222
+ "loading": "Loading emoji…",
223
+ "grid": "Emoji",
224
+ "categories": {
225
+ "smileys": "Smileys & emotion",
226
+ "people": "People & body",
227
+ "animals": "Animals & nature",
228
+ "food": "Food & drink",
229
+ "travel": "Travel & places",
230
+ "activities": "Activities",
231
+ "objects": "Objects",
232
+ "symbols": "Symbols",
233
+ "flags": "Flags"
234
+ }
215
235
  }
216
236
  },
217
237
  "feedback": {
@@ -301,6 +321,11 @@
301
321
  },
302
322
  "draggablePanel": {
303
323
  "moveLabel": "Move panel. Use the arrow keys to move it, or hold Shift for larger steps."
324
+ },
325
+ "pageCover": {
326
+ "position": "Cover position",
327
+ "hint": "Drag the image, or use the arrow keys, to reposition it",
328
+ "valueText": "{value}% from the top"
304
329
  }
305
330
  },
306
331
  "dataDisplay": {
@@ -208,6 +208,26 @@
208
208
  "openDialog": "一覧から選択",
209
209
  "openSearch": "検索",
210
210
  "suggestions": "候補"
211
+ },
212
+ "emojiPicker": {
213
+ "trigger": "アイコンを選ぶ",
214
+ "search": "絵文字を検索",
215
+ "recent": "最近使った絵文字",
216
+ "remove": "アイコンを削除",
217
+ "empty": "該当する絵文字がありません",
218
+ "loading": "絵文字を読み込み中…",
219
+ "grid": "絵文字",
220
+ "categories": {
221
+ "smileys": "顔と感情",
222
+ "people": "人と体",
223
+ "animals": "動物と自然",
224
+ "food": "食べ物と飲み物",
225
+ "travel": "旅行と場所",
226
+ "activities": "活動",
227
+ "objects": "もの",
228
+ "symbols": "記号",
229
+ "flags": "旗"
230
+ }
211
231
  }
212
232
  },
213
233
  "feedback": {
@@ -294,6 +314,11 @@
294
314
  },
295
315
  "draggablePanel": {
296
316
  "moveLabel": "パネルを移動。矢印キーで移動、Shift キーを押しながらで大きく移動します。"
317
+ },
318
+ "pageCover": {
319
+ "position": "カバー画像の位置",
320
+ "hint": "画像をドラッグするか矢印キーで位置を調整",
321
+ "valueText": "上から {value}%"
297
322
  }
298
323
  },
299
324
  "dataDisplay": {
@@ -209,6 +209,26 @@
209
209
  "openDialog": "Chọn từ danh sách",
210
210
  "openSearch": "Tìm kiếm",
211
211
  "suggestions": "Gợi ý"
212
+ },
213
+ "emojiPicker": {
214
+ "trigger": "Chọn biểu tượng",
215
+ "search": "Tìm emoji",
216
+ "recent": "Dùng gần đây",
217
+ "remove": "Gỡ biểu tượng",
218
+ "empty": "Không tìm thấy emoji",
219
+ "loading": "Đang tải emoji…",
220
+ "grid": "Emoji",
221
+ "categories": {
222
+ "smileys": "Mặt cười & cảm xúc",
223
+ "people": "Con người & cơ thể",
224
+ "animals": "Động vật & thiên nhiên",
225
+ "food": "Đồ ăn & thức uống",
226
+ "travel": "Du lịch & địa điểm",
227
+ "activities": "Hoạt động",
228
+ "objects": "Đồ vật",
229
+ "symbols": "Ký hiệu",
230
+ "flags": "Cờ"
231
+ }
212
232
  }
213
233
  },
214
234
  "feedback": {
@@ -295,6 +315,11 @@
295
315
  },
296
316
  "draggablePanel": {
297
317
  "moveLabel": "Di chuyển bảng. Dùng phím mũi tên để dời, giữ Shift để bước dài hơn."
318
+ },
319
+ "pageCover": {
320
+ "position": "Vị trí ảnh bìa",
321
+ "hint": "Kéo ảnh hoặc dùng phím mũi tên để chỉnh vị trí",
322
+ "valueText": "{value}% tính từ trên"
298
323
  }
299
324
  },
300
325
  "dataDisplay": {
@@ -781,6 +781,12 @@ export type TreeProp = {
781
781
  onExpandedValuesChange?: (values: string[]) => void;
782
782
  /** Start with every branch open (antd `defaultExpandAll`). Seeded once, never re-applied. */
783
783
  defaultExpandAll?: boolean;
784
+ /**
785
+ * Expand a parent by clicking its ROW, not only its switcher (antd `DirectoryTree expandAction`,
786
+ * gh#1162): `"click"` selects AND toggles, `"doubleClick"` toggles on a double click. Default
787
+ * `false` — the switcher alone expands. The keyboard keeps the APG map (→ / ← expand).
788
+ */
789
+ expandAction?: false | "click" | "doubleClick";
784
790
  /**
785
791
  * Lazy children (antd `loadData`). Called when a branch with no `children` and
786
792
  * `isLeaf !== true` is expanded, and never again once its promise RESOLVES; push the fetched
@@ -2360,3 +2360,29 @@ export type AttachmentsRefProp = {
2360
2360
  multiple?: boolean;
2361
2361
  }) => void;
2362
2362
  };
2363
+ /**
2364
+ * @see EmojiPicker — a page icon / reaction picker (gh#1164): search by ja / en / vi keywords
2365
+ * (emojibase-data, loaded for the active locale on first open), categories, per-user recents, a
2366
+ * WAI-ARIA grid, and "remove icon". No skin tones.
2367
+ */
2368
+ export type EmojiPickerProp = {
2369
+ /** The chosen emoji (a Unicode string), or null for none. Controlled with `onValueChange`. */
2370
+ value?: ValueProp<string | null>;
2371
+ defaultValue?: DefaultValueProp<string | null>;
2372
+ /** Called with the picked emoji, or null when "remove icon" is chosen. */
2373
+ onValueChange?: OnValueChangeProp<string | null>;
2374
+ open?: OpenProp;
2375
+ defaultOpen?: DefaultOpenProp;
2376
+ onOpenChange?: OnOpenChangeProp;
2377
+ /** Offer "remove icon" while a value is set. Default true. */
2378
+ removable?: boolean;
2379
+ /** localStorage key for the per-user recents. Default `godxjp-ui:emoji-recents`. */
2380
+ recentsKey?: string;
2381
+ size?: SizeProp;
2382
+ disabled?: DisabledProp;
2383
+ /** Replace the default trigger button (it must accept a ref and onClick). */
2384
+ trigger?: React.ReactNode;
2385
+ "aria-label"?: string;
2386
+ id?: IdProp;
2387
+ className?: ClassNameProp;
2388
+ };
@@ -21,7 +21,7 @@ export type PageContainerMeasureProp = "default" | "narrow" | "medium";
21
21
  * What the page's top row IS — the question that decides its type step, not how big you want it.
22
22
  * `document` (default) — the row is the page's TITLE: a record, a form, a collection, a report.
23
23
  */
24
- export type PageContainerHeaderScaleProp = "document" | "chrome";
24
+ export type PageContainerHeaderScaleProp = "document" | "chrome" | "display";
25
25
  /**
26
26
  * @see PageContainer — the header's trailing slot, one node or two named sub-slots.
27
27
  *
@@ -99,9 +99,22 @@ export type PageContainerProp = {
99
99
  /**
100
100
  * Whether the page's top row is a DOCUMENT TITLE or the surface's own CHROME. Pass `chrome` when
101
101
  * the row names the thing the user is already inside rather than announcing a document: a chat
102
- * channel, a mail thread, an IDE tab.
102
+ * channel, a mail thread, an IDE tab. Pass `display` for an ARTICLE whose title is the page's
103
+ * headline (a Notion / note.com page): a larger, token-owned step that scales from phone to
104
+ * desktop, a CJK-friendly line height, and balanced wrapping (gh#1160).
103
105
  */
104
106
  headerScale?: PageContainerHeaderScaleProp;
107
+ /**
108
+ * The page's icon — an emoji or a glyph — drawn large above the title, overlapping a banner
109
+ * `cover`'s bottom edge (gh#1160). Decorative by default reading: give it `aria-hidden` unless
110
+ * it is itself a control (a "change icon" button).
111
+ */
112
+ icon?: React.ReactNode;
113
+ /**
114
+ * A `PageCover`. The banner variant spans the page edge to edge above the header; the
115
+ * `eyecatch` variant sits inside the header's reading column, above the title (gh#1160).
116
+ */
117
+ cover?: React.ReactNode;
105
118
  /**
106
119
  * Bounded page measure shared by the header and the body. `narrow` (624px surface) / `medium`
107
120
  * (720px surface) cap BOTH bands to one token-owned measure (`--page-measure-{narrow,medium}`),
@@ -970,6 +983,40 @@ export type ErrorSurfaceMaintenanceProp = {
970
983
  * All product COPY stays consumer-owned (`title` / `description` / `action` come from the app's own
971
984
  * `t()`); the surface owns only its own metadata labels, which it localizes itself.
972
985
  */
986
+ /** @see PageCover — banner across the page top, or an article's eyecatch in the reading column. */
987
+ export type PageCoverVariantProp = "banner" | "eyecatch";
988
+ /** @see PageCover — the banner's token-owned height step (phone → desktop). */
989
+ export type PageCoverHeightProp = "md" | "lg";
990
+ /**
991
+ * @see PageCover — a page's cover image (gh#1160): Notion's banner above the title, or note.com's
992
+ * eyecatch in the reading column. The focal point is a vertical position, and the cover can be
993
+ * repositioned by drag OR keyboard: while `repositioning`, the image is a WAI-ARIA slider.
994
+ */
995
+ export type PageCoverProp = {
996
+ /** The image URL. */
997
+ src: string;
998
+ /** Alternative text; `""` for a purely decorative cover. */
999
+ alt: string;
1000
+ /** Vertical focal point, 0 (top) – 100 (bottom): the image's `object-position` y. Default 50. */
1001
+ positionY?: number;
1002
+ /** Called while repositioning with the new focal point (drag, arrows, Home / End). */
1003
+ onPositionChange?: (positionY: number) => void;
1004
+ /** Reposition mode: the image becomes a vertical slider (drag + keyboard). Controlled. */
1005
+ repositioning?: boolean;
1006
+ /** Reposition mode ended from inside the cover (Enter / Escape). */
1007
+ onRepositioningChange?: (repositioning: boolean) => void;
1008
+ /** `banner` (default) spans the page above the header; `eyecatch` sits in the reading column. */
1009
+ variant?: PageCoverVariantProp;
1010
+ /** Banner height step, token-owned for phone and desktop. Default `md`. */
1011
+ height?: PageCoverHeightProp;
1012
+ /**
1013
+ * Cover actions (change / reposition / remove). Over the cover's bottom edge on a wide screen,
1014
+ * BELOW the image on a narrow one, so they never sit on the focal area.
1015
+ */
1016
+ actions?: React.ReactNode;
1017
+ id?: IdProp;
1018
+ className?: ClassNameProp;
1019
+ };
973
1020
  export type ErrorSurfaceProp = {
974
1021
  /** Where the surface lives — `application` = AppShell body (400/403/404), `system` = own page (500/503). */
975
1022
  mode: ErrorSurfaceModeProp;
@@ -784,7 +784,15 @@ export declare const COMPONENT_PROP_REGISTRY: {
784
784
  }, {
785
785
  readonly field: "headerScale";
786
786
  readonly local: true;
787
- readonly reason: "What the page's top row IS — a document title or the surface's own chrome (document | chrome) — which selects the title's type step via --page-title-font-size-chrome AND opens the page flush with the frame via --page-pad-block-start-chrome (chrome sits on the edge; a document title gets the page's top margin). A fourth orthogonal axis: PageContainerVariantProp owns chrome WEIGHT (ghost drops the divider and header pad), headerLayout owns the header ARRANGEMENT, measure owns the inline cap; none of them can say that the h1 is a channel name rather than a headline.";
787
+ readonly reason: "What the page's top row IS — a document title, the surface's own chrome, or an article headline (document | chrome | display; display = gh#1160) — which selects the title's type step via --page-title-font-size-chrome AND opens the page flush with the frame via --page-pad-block-start-chrome (chrome sits on the edge; a document title gets the page's top margin). A fourth orthogonal axis: PageContainerVariantProp owns chrome WEIGHT (ghost drops the divider and header pad), headerLayout owns the header ARRANGEMENT, measure owns the inline cap; none of them can say that the h1 is a channel name rather than a headline.";
788
+ }, {
789
+ readonly field: "icon";
790
+ readonly local: true;
791
+ readonly reason: "The PAGE's icon (an emoji or glyph) drawn large above the h1 and over a banner cover's edge — a page identity slot, not the small IconProp glyph a control carries (gh#1160).";
792
+ }, {
793
+ readonly field: "cover";
794
+ readonly local: true;
795
+ readonly reason: "Slot for a PageCover; the container reads its variant to place it full-bleed above the header (banner) or in the reading column (eyecatch) (gh#1160).";
788
796
  }, {
789
797
  readonly field: "measure";
790
798
  readonly local: true;
@@ -1187,6 +1195,57 @@ export declare const COMPONENT_PROP_REGISTRY: {
1187
1195
  readonly reason: "Server-sent 0–100 completion of the maintenance window; deriving it from the client clock would break hydration.";
1188
1196
  }];
1189
1197
  };
1198
+ readonly PageCoverVariantProp: {
1199
+ readonly group: "layout";
1200
+ readonly file: "components/layout.prop.ts";
1201
+ readonly vocabulary: readonly [];
1202
+ };
1203
+ readonly PageCoverHeightProp: {
1204
+ readonly group: "layout";
1205
+ readonly file: "components/layout.prop.ts";
1206
+ readonly vocabulary: readonly [];
1207
+ };
1208
+ readonly PageCoverProp: {
1209
+ readonly group: "layout";
1210
+ readonly file: "components/layout.prop.ts";
1211
+ readonly vocabulary: readonly ["IdProp", "ClassNameProp", {
1212
+ readonly field: "src";
1213
+ readonly local: true;
1214
+ readonly reason: "The native img src attribute.";
1215
+ }, {
1216
+ readonly field: "alt";
1217
+ readonly local: true;
1218
+ readonly reason: "The native img alt attribute.";
1219
+ }, {
1220
+ readonly field: "positionY";
1221
+ readonly local: true;
1222
+ readonly reason: "The cover's vertical FOCAL POINT, 0–100, applied as object-position y — a geometric value of this image, not a ValueProp a form submits (gh#1160).";
1223
+ }, {
1224
+ readonly field: "onPositionChange";
1225
+ readonly local: true;
1226
+ readonly reason: "Paired change handler of positionY, named after the value it reports (drag / slider keys).";
1227
+ }, {
1228
+ readonly field: "repositioning";
1229
+ readonly local: true;
1230
+ readonly reason: "Controlled MODE flag: while true the image is a vertical WAI-ARIA slider. Not OpenProp — nothing opens; the cover becomes a control.";
1231
+ }, {
1232
+ readonly field: "onRepositioningChange";
1233
+ readonly local: true;
1234
+ readonly reason: "Paired change handler of repositioning, called when Enter / Escape ends the mode from inside.";
1235
+ }, {
1236
+ readonly field: "variant";
1237
+ readonly local: true;
1238
+ readonly reason: "PageCoverVariantProp (banner | eyecatch) — WHERE the cover sits and its shape, not a tone or a visual style variant.";
1239
+ }, {
1240
+ readonly field: "height";
1241
+ readonly local: true;
1242
+ readonly reason: "PageCoverHeightProp (md | lg) — the banner's token-owned viewport-scaled height step; SizeProp means control density, not this.";
1243
+ }, {
1244
+ readonly field: "actions";
1245
+ readonly local: true;
1246
+ readonly reason: "Slot for the host's cover controls (change / reposition / remove), laid out off the focal area — a ReactNode slot, not the ActionsProp item list.";
1247
+ }];
1248
+ };
1190
1249
  readonly ErrorSurfaceProp: {
1191
1250
  readonly group: "layout";
1192
1251
  readonly file: "components/layout.prop.ts";
@@ -3253,10 +3312,35 @@ export declare const COMPONENT_PROP_REGISTRY: {
3253
3312
  readonly reason: "antd `onDrop` info: true when it lands as a sibling, false inside.";
3254
3313
  }];
3255
3314
  };
3315
+ readonly EmojiPickerProp: {
3316
+ readonly group: "data-entry";
3317
+ readonly file: "components/data-entry.prop.ts";
3318
+ readonly vocabulary: readonly ["ValueProp", "DefaultValueProp", "OnValueChangeProp", "OpenProp", "DefaultOpenProp", "OnOpenChangeProp", "SizeProp", "DisabledProp", "IdProp", "ClassNameProp", {
3319
+ readonly field: "removable";
3320
+ readonly local: true;
3321
+ readonly reason: "Whether \"remove icon\" is offered while a value is set — a picker for an OPTIONAL icon (gh#1164), not AllowClearProp's inline ✕ on a field.";
3322
+ }, {
3323
+ readonly field: "recentsKey";
3324
+ readonly local: true;
3325
+ readonly reason: "localStorage key the per-user recents are kept under, so two pickers (page icons, reactions) can keep separate lists.";
3326
+ }, {
3327
+ readonly field: "trigger";
3328
+ readonly local: true;
3329
+ readonly reason: "Replaces the default trigger button (a page icon drawn large, a reaction chip) — a ReactNode slot, not a TriggerProp mode.";
3330
+ }, {
3331
+ readonly field: "aria-label";
3332
+ readonly local: true;
3333
+ readonly reason: "Accessible name of the trigger and the popover.";
3334
+ }];
3335
+ };
3256
3336
  readonly TreeProp: {
3257
3337
  readonly group: "data-display";
3258
3338
  readonly file: "components/data-display.prop.ts";
3259
3339
  readonly vocabulary: readonly ["ValueProp", "DefaultValueProp", "OnValueChangeProp", "DisabledProp", "SizeProp", "ClassNameProp", "IdProp", {
3340
+ readonly field: "expandAction";
3341
+ readonly local: true;
3342
+ readonly reason: "antd DirectoryTree's `expandAction` (false | click | doubleClick): whether a ROW click / double click also toggles a parent's expansion, beside the switcher (gh#1162). An interaction mode of the tree, not an OpenProp.";
3343
+ }, {
3260
3344
  readonly field: "divided";
3261
3345
  readonly local: true;
3262
3346
  readonly reason: "Rules between the rows — a hairline on every node's block-start but the outline's first, full row width at every depth (gh#732). Default false, because chrome defaults quiet here (#44). Not antd's spelling: antd's Tree has no such capability, and `bordered` already means a grid's frame plus column rules on Table / Calendar / RangeTimeline; see docs/DESIGN-AUTHORITY.md.";