@godxjp/ui 31.27.0 → 31.28.1

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 (53) 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/FORMS.md +5 -0
  47. package/docs/FRAME-COVERAGE-REPORT.md +4 -2
  48. package/docs/data-entry/emoji-picker.tsx +35 -0
  49. package/docs/i18n/messages/en.json +16 -0
  50. package/docs/i18n/messages/ja.json +16 -0
  51. package/docs/i18n/messages/vi.json +16 -0
  52. package/docs/layout/page-cover.tsx +56 -0
  53. package/package.json +5 -6
@@ -807,7 +807,17 @@ const COMPONENT_PROP_REGISTRY = {
807
807
  {
808
808
  field: "headerScale",
809
809
  local: true,
810
- reason: "What the page's top row IS \u2014 a document title or the surface's own chrome (document | chrome) \u2014 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."
810
+ reason: "What the page's top row IS \u2014 a document title, the surface's own chrome, or an article headline (document | chrome | display; display = gh#1160) \u2014 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."
811
+ },
812
+ {
813
+ field: "icon",
814
+ local: true,
815
+ reason: "The PAGE's icon (an emoji or glyph) drawn large above the h1 and over a banner cover's edge \u2014 a page identity slot, not the small IconProp glyph a control carries (gh#1160)."
816
+ },
817
+ {
818
+ field: "cover",
819
+ local: true,
820
+ 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)."
811
821
  },
812
822
  {
813
823
  field: "measure",
@@ -1263,6 +1273,53 @@ const COMPONENT_PROP_REGISTRY = {
1263
1273
  }
1264
1274
  ]
1265
1275
  },
1276
+ PageCoverVariantProp: { group: "layout", file: "components/layout.prop.ts", vocabulary: [] },
1277
+ PageCoverHeightProp: { group: "layout", file: "components/layout.prop.ts", vocabulary: [] },
1278
+ PageCoverProp: {
1279
+ group: "layout",
1280
+ file: "components/layout.prop.ts",
1281
+ vocabulary: [
1282
+ "IdProp",
1283
+ "ClassNameProp",
1284
+ { field: "src", local: true, reason: "The native img src attribute." },
1285
+ { field: "alt", local: true, reason: "The native img alt attribute." },
1286
+ {
1287
+ field: "positionY",
1288
+ local: true,
1289
+ reason: "The cover's vertical FOCAL POINT, 0\u2013100, applied as object-position y \u2014 a geometric value of this image, not a ValueProp a form submits (gh#1160)."
1290
+ },
1291
+ {
1292
+ field: "onPositionChange",
1293
+ local: true,
1294
+ reason: "Paired change handler of positionY, named after the value it reports (drag / slider keys)."
1295
+ },
1296
+ {
1297
+ field: "repositioning",
1298
+ local: true,
1299
+ reason: "Controlled MODE flag: while true the image is a vertical WAI-ARIA slider. Not OpenProp \u2014 nothing opens; the cover becomes a control."
1300
+ },
1301
+ {
1302
+ field: "onRepositioningChange",
1303
+ local: true,
1304
+ reason: "Paired change handler of repositioning, called when Enter / Escape ends the mode from inside."
1305
+ },
1306
+ {
1307
+ field: "variant",
1308
+ local: true,
1309
+ reason: "PageCoverVariantProp (banner | eyecatch) \u2014 WHERE the cover sits and its shape, not a tone or a visual style variant."
1310
+ },
1311
+ {
1312
+ field: "height",
1313
+ local: true,
1314
+ reason: "PageCoverHeightProp (md | lg) \u2014 the banner's token-owned viewport-scaled height step; SizeProp means control density, not this."
1315
+ },
1316
+ {
1317
+ field: "actions",
1318
+ local: true,
1319
+ reason: "Slot for the host's cover controls (change / reposition / remove), laid out off the focal area \u2014 a ReactNode slot, not the ActionsProp item list."
1320
+ }
1321
+ ]
1322
+ },
1266
1323
  ErrorSurfaceProp: {
1267
1324
  group: "layout",
1268
1325
  file: "components/layout.prop.ts",
@@ -3860,6 +3917,38 @@ const COMPONENT_PROP_REGISTRY = {
3860
3917
  }
3861
3918
  ]
3862
3919
  },
3920
+ EmojiPickerProp: {
3921
+ group: "data-entry",
3922
+ file: "components/data-entry.prop.ts",
3923
+ vocabulary: [
3924
+ "ValueProp",
3925
+ "DefaultValueProp",
3926
+ "OnValueChangeProp",
3927
+ "OpenProp",
3928
+ "DefaultOpenProp",
3929
+ "OnOpenChangeProp",
3930
+ "SizeProp",
3931
+ "DisabledProp",
3932
+ "IdProp",
3933
+ "ClassNameProp",
3934
+ {
3935
+ field: "removable",
3936
+ local: true,
3937
+ reason: `Whether "remove icon" is offered while a value is set \u2014 a picker for an OPTIONAL icon (gh#1164), not AllowClearProp's inline \u2715 on a field.`
3938
+ },
3939
+ {
3940
+ field: "recentsKey",
3941
+ local: true,
3942
+ reason: "localStorage key the per-user recents are kept under, so two pickers (page icons, reactions) can keep separate lists."
3943
+ },
3944
+ {
3945
+ field: "trigger",
3946
+ local: true,
3947
+ reason: "Replaces the default trigger button (a page icon drawn large, a reaction chip) \u2014 a ReactNode slot, not a TriggerProp mode."
3948
+ },
3949
+ { field: "aria-label", local: true, reason: "Accessible name of the trigger and the popover." }
3950
+ ]
3951
+ },
3863
3952
  TreeProp: {
3864
3953
  group: "data-display",
3865
3954
  file: "components/data-display.prop.ts",
@@ -3871,6 +3960,11 @@ const COMPONENT_PROP_REGISTRY = {
3871
3960
  "SizeProp",
3872
3961
  "ClassNameProp",
3873
3962
  "IdProp",
3963
+ {
3964
+ field: "expandAction",
3965
+ local: true,
3966
+ 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."
3967
+ },
3874
3968
  {
3875
3969
  field: "divided",
3876
3970
  local: true,
@@ -991,6 +991,87 @@
991
991
  min-width: 0;
992
992
  }
993
993
 
994
+ .ui-emoji-picker {
995
+ --popover-surface-inline-size: var(--emoji-picker-panel-inline-size);
996
+ display: flex;
997
+ flex-direction: column;
998
+ gap: var(--space-2);
999
+ }
1000
+
1001
+ .ui-emoji-picker-head {
1002
+ display: flex;
1003
+ align-items: center;
1004
+ gap: var(--space-1);
1005
+ }
1006
+
1007
+ .ui-emoji-picker-head > :first-child {
1008
+ flex: 1 1 auto;
1009
+ min-inline-size: 0;
1010
+ }
1011
+
1012
+ .ui-emoji-picker-tabs {
1013
+ display: flex;
1014
+ flex-wrap: wrap;
1015
+ gap: var(--space-0-5, var(--space-1));
1016
+ border-block-end: var(--stroke-hairline) solid hsl(var(--border));
1017
+ padding-block-end: var(--space-1);
1018
+ }
1019
+
1020
+ .ui-emoji-picker-tabs [data-state="active"] {
1021
+ background-color: hsl(var(--accent));
1022
+ }
1023
+
1024
+ .ui-emoji-picker-grid {
1025
+ display: flex;
1026
+ flex-direction: column;
1027
+ max-block-size: var(--emoji-picker-grid-max-block-size);
1028
+ overflow-y: auto;
1029
+ }
1030
+
1031
+ .ui-emoji-picker-row {
1032
+ display: grid;
1033
+ grid-template-columns: repeat(8, var(--emoji-picker-cell-size));
1034
+ }
1035
+
1036
+ .ui-emoji-picker-cell {
1037
+ display: grid;
1038
+ place-items: center;
1039
+ inline-size: var(--emoji-picker-cell-size);
1040
+ block-size: var(--emoji-picker-cell-size);
1041
+ border-radius: calc(var(--radius) / var(--radius-ratio));
1042
+ font-size: var(--emoji-picker-glyph-size);
1043
+ line-height: 1;
1044
+ cursor: pointer;
1045
+ }
1046
+
1047
+ .ui-emoji-picker-cell:hover,
1048
+ .ui-emoji-picker-cell[aria-selected="true"] {
1049
+ background-color: hsl(var(--accent));
1050
+ }
1051
+
1052
+ .ui-emoji-picker-state {
1053
+ padding-block: var(--space-4);
1054
+ text-align: center;
1055
+ }
1056
+
1057
+ .ui-emoji-picker-trigger[data-has-value] {
1058
+ font-size: var(--emoji-picker-glyph-size);
1059
+ }
1060
+
1061
+ .ui-command-palette-icon {
1062
+ display: inline-flex;
1063
+ flex-shrink: 0;
1064
+ align-items: center;
1065
+ justify-content: center;
1066
+ min-inline-size: var(--menu-icon-size);
1067
+ line-height: 1;
1068
+ }
1069
+
1070
+ .ui-command-palette-icon svg {
1071
+ inline-size: var(--menu-icon-size);
1072
+ block-size: var(--menu-icon-size);
1073
+ }
1074
+
994
1075
  .ui-command-palette-label {
995
1076
  min-width: 0;
996
1077
  }
@@ -1506,6 +1506,23 @@
1506
1506
  padding-inline-start: var(--block-editor-gutter-inline-size);
1507
1507
  }
1508
1508
 
1509
+ .ui-block-editor[data-appearance="framed"] {
1510
+ padding-block: var(--block-editor-frame-padding);
1511
+ padding-inline-end: var(--block-editor-frame-padding);
1512
+ border: var(--stroke-hairline) solid hsl(var(--input));
1513
+ border-radius: var(--control-radius, var(--radius));
1514
+ background-color: hsl(var(--background));
1515
+ transition: border-color var(--duration-fast);
1516
+ }
1517
+
1518
+ .ui-block-editor[data-appearance="framed"]:focus-within {
1519
+ border-color: hsl(var(--ring));
1520
+ }
1521
+
1522
+ .ui-block-editor[data-appearance="framed"][data-disabled] {
1523
+ background-color: hsl(var(--muted));
1524
+ }
1525
+
1509
1526
  .ui-block-editor-content {
1510
1527
  min-block-size: var(--block-editor-min-height);
1511
1528
  outline: none;
@@ -1648,6 +1665,83 @@
1648
1665
  margin-block-start: var(--space-2);
1649
1666
  }
1650
1667
 
1668
+ .ui-block-editor-callout-head,
1669
+ .ui-block-editor-columns-bar {
1670
+ display: flex;
1671
+ flex-wrap: wrap;
1672
+ align-items: center;
1673
+ gap: var(--space-1);
1674
+ margin-block-end: var(--space-2);
1675
+ }
1676
+
1677
+ .ui-block-editor-callout-title {
1678
+ flex: 1 1 auto;
1679
+ min-inline-size: 0;
1680
+ font-weight: var(--font-weight-medium);
1681
+ }
1682
+
1683
+ .ui-block-editor-columns {
1684
+ margin-block: var(--prose-space-block);
1685
+ }
1686
+
1687
+ .ui-block-editor-columns-content > [data-node-view-content-react] {
1688
+ display: flex;
1689
+ gap: var(--prose-columns-gap);
1690
+ }
1691
+
1692
+ @media (width < 40rem) {
1693
+ .ui-block-editor-columns-content > [data-node-view-content-react] {
1694
+ flex-direction: column;
1695
+ }
1696
+ }
1697
+
1698
+ .ui-block-editor-content [data-type="details"] {
1699
+ display: flex;
1700
+ gap: var(--space-1);
1701
+ margin-block: var(--prose-space-block);
1702
+ }
1703
+
1704
+ .ui-block-editor-content [data-type="details"] > div {
1705
+ flex: 1 1 auto;
1706
+ min-inline-size: 0;
1707
+ }
1708
+
1709
+ .ui-block-editor-content [data-type="detailsSummary"],
1710
+ .ui-block-editor-content [data-type="details"] summary {
1711
+ font-weight: var(--font-weight-medium);
1712
+ list-style: none;
1713
+ }
1714
+
1715
+ .ui-block-editor-toggle-button {
1716
+ display: inline-flex;
1717
+ flex-shrink: 0;
1718
+ align-items: center;
1719
+ justify-content: center;
1720
+ inline-size: var(--control-height-xs);
1721
+ block-size: var(--control-height-xs);
1722
+ padding: 0;
1723
+ border: 0;
1724
+ border-radius: calc(var(--radius) / var(--radius-ratio));
1725
+ background: transparent;
1726
+ color: hsl(var(--muted-foreground));
1727
+ cursor: pointer;
1728
+ }
1729
+
1730
+ .ui-block-editor-toggle-button::before {
1731
+ content: "";
1732
+ border-block: var(--stroke-lg) solid transparent;
1733
+ border-inline-start: calc(var(--stroke-lg) * 1.5) solid currentColor;
1734
+ transition: rotate var(--duration-fast);
1735
+ }
1736
+
1737
+ [data-type="details"].is-open > .ui-block-editor-toggle-button::before {
1738
+ rotate: 90deg;
1739
+ }
1740
+
1741
+ .ui-block-editor-toggle-button:hover {
1742
+ background-color: hsl(var(--accent));
1743
+ }
1744
+
1651
1745
  .ui-prose img[data-prose-preview] {
1652
1746
  cursor: zoom-in;
1653
1747
  }
@@ -38,6 +38,7 @@
38
38
  .ui-rating-star,
39
39
  .ui-prose img[data-prose-preview],
40
40
  .ui-prose .ui-prose-toggle-summary,
41
+ .ui-block-editor-toggle-button,
41
42
  a.ui-list-row,
42
43
 
43
44
  a[data-slot="card"],
@@ -109,6 +110,7 @@
109
110
  .ui-rating-star,
110
111
  .ui-prose img[data-prose-preview],
111
112
  .ui-prose .ui-prose-toggle-summary,
113
+ .ui-block-editor-toggle-button,
112
114
  a.ui-list-row,
113
115
  a[data-slot="card"],
114
116
  button[data-slot="card"],
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "31.27.0",
2
+ "version": "31.28.1",
3
3
  "generatedBy": "scripts/gen-style-layers.mjs — do not edit by hand; run `pnpm gen:style-layers`",
4
4
  "base": "base.css",
5
5
  "fonts": "fonts.css",
@@ -217,10 +217,14 @@
217
217
  },
218
218
  "BlockEditor": {
219
219
  "layers": [
220
+ "layout.css",
220
221
  "control.css",
221
222
  "toggle.css",
222
223
  "text-layout.css",
223
224
  "dialog-layout.css",
225
+ "alert-layout.css",
226
+ "data-display-layout.css",
227
+ "form-layout.css",
224
228
  "navigation-layout.css"
225
229
  ]
226
230
  },
@@ -469,6 +473,13 @@
469
473
  "navigation-layout.css"
470
474
  ]
471
475
  },
476
+ "EmojiPicker": {
477
+ "layers": [
478
+ "control.css",
479
+ "text-layout.css",
480
+ "dialog-layout.css"
481
+ ]
482
+ },
472
483
  "EmptyState": {
473
484
  "layers": [
474
485
  "layout.css"
@@ -736,6 +747,11 @@
736
747
  "dialog-layout.css"
737
748
  ]
738
749
  },
750
+ "PageCover": {
751
+ "layers": [
752
+ "layout.css"
753
+ ]
754
+ },
739
755
  "Pagination": {
740
756
  "layers": [
741
757
  "layout.css",
@@ -924,6 +924,119 @@
924
924
  font-size: var(--page-title-font-size-chrome);
925
925
  }
926
926
 
927
+ .ui-page-container[data-header-scale="display"] .ui-page-title,
928
+ .ui-page-container[data-header-scale="display"] .ui-page-header .ui-page-title {
929
+ font-size: var(--page-title-font-size-display);
930
+ font-weight: var(--font-weight-semibold);
931
+ line-height: var(--page-title-line-height-display);
932
+ text-wrap: balance;
933
+ overflow-wrap: normal;
934
+ }
935
+
936
+ .ui-page-header-icon {
937
+ display: flex;
938
+ align-items: center;
939
+ margin-block-end: var(--space-2);
940
+ font-size: var(--page-icon-size);
941
+ line-height: 1;
942
+ }
943
+
944
+ .ui-page-header-icon svg {
945
+ inline-size: var(--page-icon-size);
946
+ block-size: var(--page-icon-size);
947
+ }
948
+
949
+ .ui-page-container[data-cover="banner"] {
950
+ padding-block-start: 0;
951
+ }
952
+
953
+ .ui-page-container[data-cover="banner"] .ui-page-header-icon {
954
+ position: relative;
955
+ margin-block-start: calc(-1 * var(--page-icon-cover-overlap));
956
+ }
957
+
958
+ .ui-page-header .ui-page-cover-slot {
959
+ margin-block-end: var(--space-4);
960
+ }
961
+
962
+ .ui-page-cover {
963
+ position: relative;
964
+ }
965
+
966
+ .ui-page-cover-frame {
967
+ position: relative;
968
+ overflow: hidden;
969
+ block-size: var(--page-cover-block-size-md);
970
+ background-color: hsl(var(--muted));
971
+ }
972
+
973
+ .ui-page-cover[data-height="lg"] .ui-page-cover-frame {
974
+ block-size: var(--page-cover-block-size-lg);
975
+ }
976
+
977
+ .ui-page-cover[data-variant="eyecatch"] .ui-page-cover-frame {
978
+ block-size: auto;
979
+ aspect-ratio: var(--page-cover-eyecatch-aspect-ratio);
980
+ border-radius: var(--page-cover-radius, var(--card-radius, var(--radius)));
981
+ }
982
+
983
+ .ui-page-cover-image {
984
+ display: block;
985
+ inline-size: 100%;
986
+ block-size: 100%;
987
+ object-fit: cover;
988
+ user-select: none;
989
+ }
990
+
991
+ .ui-page-cover[data-repositioning] .ui-page-cover-frame {
992
+ cursor: grab;
993
+ touch-action: none;
994
+ }
995
+
996
+ .ui-page-cover[data-repositioning] .ui-page-cover-frame:active {
997
+ cursor: grabbing;
998
+ }
999
+
1000
+ .ui-page-cover-hint {
1001
+ position: absolute;
1002
+ inset-block-start: 50%;
1003
+ inset-inline: 0;
1004
+ margin-inline: auto;
1005
+ inline-size: fit-content;
1006
+ max-inline-size: calc(100% - 2 * var(--space-4));
1007
+ translate: 0 -50%;
1008
+ padding: var(--space-1) var(--space-3);
1009
+ border-radius: var(--radius-pill);
1010
+ background-color: hsl(var(--background) / 0.85);
1011
+ color: hsl(var(--foreground));
1012
+ font-size: var(--font-size-sm, var(--font-size-base));
1013
+ text-align: center;
1014
+ pointer-events: none;
1015
+ }
1016
+
1017
+ .ui-page-cover-actions {
1018
+ position: absolute;
1019
+ inset-block-end: var(--space-3);
1020
+ inset-inline-end: var(--space-3);
1021
+ display: flex;
1022
+ flex-wrap: wrap;
1023
+ gap: var(--space-1);
1024
+ }
1025
+
1026
+ @media (hover: hover) and (width >= 40rem) {
1027
+ .ui-page-cover:not(:hover):not(:focus-within) .ui-page-cover-actions {
1028
+ opacity: 0;
1029
+ }
1030
+ }
1031
+
1032
+ @media (width < 40rem) {
1033
+ .ui-page-cover-actions {
1034
+ position: static;
1035
+ justify-content: flex-end;
1036
+ padding: var(--space-2) var(--space-page-active-x, var(--space-4)) 0;
1037
+ }
1038
+ }
1039
+
927
1040
  @media (max-width: 720px) {
928
1041
  .ui-page-container {
929
1042
  --space-page-active-x: var(--space-page-compact-x);
@@ -460,6 +460,16 @@
460
460
  --control-status-warning-outline-color: initial;
461
461
  }
462
462
 
463
+ :root {
464
+ --emoji-picker-cell-size: var(--control-height-default);
465
+
466
+ --emoji-picker-panel-inline-size: calc(
467
+ 8 * var(--emoji-picker-cell-size) + 2 * var(--popover-space-inset, var(--space-3))
468
+ );
469
+ --emoji-picker-glyph-size: var(--icon-size-lg);
470
+ --emoji-picker-grid-max-block-size: 16rem;
471
+ }
472
+
463
473
  @media (pointer: coarse) {
464
474
  :root {
465
475
  --control-height-compact: var(--band-height-xl);
@@ -63,6 +63,7 @@
63
63
  --block-editor-gutter-inline-size: calc(2 * var(--control-height-xs) + var(--space-2));
64
64
  --block-editor-min-height: var(--band-height-3xl);
65
65
 
66
+ --block-editor-frame-padding: var(--space-3);
66
67
  --block-editor-menu-inline-size: 16rem;
67
68
  --block-editor-menu-max-block-size: 20rem;
68
69
  --prose-code-radius: initial;
@@ -91,6 +91,20 @@
91
91
 
92
92
  --page-title-font-size-chrome: var(--heading-h3, var(--font-size-base));
93
93
 
94
+ --page-title-font-size-display: var(
95
+ --font-size-4xl,
96
+ calc(var(--font-size-display) / var(--font-size-display-ratio))
97
+ );
98
+ --page-title-line-height-display: 1.4;
99
+
100
+ --page-icon-size: var(--icon-size-4xl);
101
+ --page-icon-cover-overlap: calc(var(--page-icon-size) * 0.6);
102
+
103
+ --page-cover-block-size-md: clamp(8rem, 24vw, 15rem);
104
+ --page-cover-block-size-lg: clamp(10rem, 32vw, 20rem);
105
+ --page-cover-eyecatch-aspect-ratio: 1.91;
106
+ --page-cover-radius: initial;
107
+
94
108
  --page-subtitle-font-size-chrome: var(
95
109
  --font-size-2xs,
96
110
  calc(var(--font-size-base) / var(--font-size-ratio) / var(--font-size-ratio))
package/docs/FORMS.md CHANGED
@@ -10,6 +10,11 @@ All forms in admin apps **must** use:
10
10
 
11
11
  Import from `@godxjp/ui/form` — **never** call `useForm()` without `zodResolver`.
12
12
 
13
+ Install all three with the kit: `npm i @godxjp/ui react-hook-form zod @hookform/resolvers`.
14
+ `@hookform/resolvers` is deliberately **not** a declared peer, so npm will not check its version
15
+ for you: keep it at ^5.2 (the first line with Zod 4 support). Declaring it made a plain
16
+ `npm install @godxjp/ui` fail with ERESOLVE, because npm walks its own optional peers (gh#1111).
17
+
13
18
  ## Quick start
14
19
 
15
20
  ```tsx
@@ -3,8 +3,8 @@
3
3
  > Generated by `scripts/frame-coverage.mjs` (issue #163). Do not edit by hand — run `pnpm check:frame-coverage`.
4
4
  > Standard: [FRAME-COVERAGE-STANDARD.md](./FRAME-COVERAGE-STANDARD.md). A missing dimension is **UNTESTED**, never a pass.
5
5
 
6
- - Public components: **182**
7
- - With ≥1 frame: **158** · zero-frame: **24**
6
+ - Public components: **184**
7
+ - With ≥1 frame: **160** · zero-frame: **24**
8
8
  - Fully covered (every contract axis declared): **0**
9
9
 
10
10
  ## UNTESTED — no `/frame/**` route
@@ -50,6 +50,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
50
50
  | VisuallyHidden | **✗** | N/A | N/A | N/A | · | · | · | · | · | · |
51
51
  | RangeTimeline | **✗** | · | N/A | N/A | · | · | · | · | · | · |
52
52
  | PageContainer | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
53
+ | PageCover | ✓ | · | N/A | N/A | · | · | · | · | · | · |
53
54
  | Flex | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
54
55
  | SpaceCompact | ✓ | · | N/A | N/A | · | · | · | · | · | · |
55
56
  | ResponsiveGrid | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
@@ -193,6 +194,7 @@ Legend: ✓ covered · N/A reasoned skip · · UNTESTED (blank cell = UNTESTED).
193
194
  | AreaChart | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
194
195
  | PieChart | ✓ | ✓ | N/A | N/A | · | · | · | · | · | · |
195
196
  | CommandPalette | ✓ | N/A | · | · | · | · | · | · | · | · |
197
+ | EmojiPicker | ✓ | · | · | · | · | · | · | · | · | · |
196
198
  | TwoFactorSetup | ✓ | N/A | · | · | · | · | · | · | · | · |
197
199
  | AuthDivider | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
198
200
  | AuthFooter | ✓ | N/A | N/A | N/A | · | · | · | · | · | · |
@@ -0,0 +1,35 @@
1
+ import * as React from "react";
2
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@godxjp/ui/data-display";
3
+ import { EmojiPicker, FormField } from "@godxjp/ui/data-entry";
4
+ import { Text } from "@godxjp/ui/general";
5
+ import { useTranslation } from "@godxjp/ui/i18n";
6
+ import { Flex, PageContainer } from "@godxjp/ui/layout";
7
+
8
+ /**
9
+ * EmojiPicker (gh#1164) — a page icon chosen from the active language's emoji keywords, with
10
+ * recents and "remove icon".
11
+ */
12
+ export default function Demo() {
13
+ const { t } = useTranslation();
14
+ const [icon, setIcon] = React.useState<string | null>(null);
15
+ return (
16
+ <PageContainer title="EmojiPicker" subtitle={t("emojiPickerDocs.subtitle")}>
17
+ <Card>
18
+ <CardHeader>
19
+ <CardTitle level={2}>{t("emojiPickerDocs.title")}</CardTitle>
20
+ <CardDescription>{t("emojiPickerDocs.description")}</CardDescription>
21
+ </CardHeader>
22
+ <CardContent>
23
+ <Flex direction="col" gap="sm">
24
+ <FormField id="page-icon" label={t("emojiPickerDocs.label")}>
25
+ <EmojiPicker value={icon} onValueChange={setIcon} />
26
+ </FormField>
27
+ <Text size="sm" tone="muted">
28
+ {icon ? t("emojiPickerDocs.chosen", { icon }) : t("emojiPickerDocs.none")}
29
+ </Text>
30
+ </Flex>
31
+ </CardContent>
32
+ </Card>
33
+ </PageContainer>
34
+ );
35
+ }
@@ -1622,5 +1622,21 @@
1622
1622
  "setup": "Setup",
1623
1623
  "release": "Release steps"
1624
1624
  }
1625
+ },
1626
+ "pageCoverDocs": {
1627
+ "title": "Quarterly planning notes",
1628
+ "icon": "Page icon",
1629
+ "reposition": "Reposition",
1630
+ "done": "Done",
1631
+ "body": "Drag the cover while repositioning, or use the arrow keys; the icon opens the emoji picker.",
1632
+ "position": "Focal point: {value}% from the top"
1633
+ },
1634
+ "emojiPickerDocs": {
1635
+ "subtitle": "Search in your language · categories · recents · keyboard grid",
1636
+ "title": "Choose a page icon",
1637
+ "description": "Type a keyword in the current language, or browse the categories. Arrow keys move through the grid; Enter picks.",
1638
+ "label": "Icon",
1639
+ "chosen": "Chosen: {icon}",
1640
+ "none": "No icon"
1625
1641
  }
1626
1642
  }
@@ -1615,5 +1615,21 @@
1615
1615
  "setup": "セットアップ",
1616
1616
  "release": "リリース手順"
1617
1617
  }
1618
+ },
1619
+ "pageCoverDocs": {
1620
+ "title": "四半期計画メモ",
1621
+ "icon": "ページアイコン",
1622
+ "reposition": "位置を調整",
1623
+ "done": "完了",
1624
+ "body": "位置を調整中はカバー画像をドラッグするか矢印キーで動かせます。アイコンを押すと絵文字ピッカーが開きます。",
1625
+ "position": "焦点: 上から {value}%"
1626
+ },
1627
+ "emojiPickerDocs": {
1628
+ "subtitle": "言語に合わせた検索 · カテゴリ · 最近使った絵文字 · キーボード操作",
1629
+ "title": "ページアイコンを選ぶ",
1630
+ "description": "表示中の言語でキーワードを入力するか、カテゴリから選びます。矢印キーで移動し、Enter で決定します。",
1631
+ "label": "アイコン",
1632
+ "chosen": "選択中: {icon}",
1633
+ "none": "アイコンなし"
1618
1634
  }
1619
1635
  }