@godxjp/ui 23.4.12 → 24.1.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.
- package/dist/brand/godx-artwork.generated.d.ts +10 -0
- package/dist/brand/godx-artwork.generated.js +24 -0
- package/dist/brand/godx-mark.d.ts +39 -0
- package/dist/brand/godx-mark.js +12 -0
- package/dist/components/general/logo.d.ts +1 -1
- package/dist/components/general/logo.js +25 -15
- package/dist/components/navigation/dropdown-menu.js +19 -2
- package/dist/contracts/measurement.json +1 -1
- package/dist/email/brand-mark.d.ts +2 -1
- package/dist/email/brand-mark.js +5 -5
- package/dist/email/tokens.generated.d.ts +16 -6
- package/dist/email/tokens.generated.js +14 -7
- package/dist/styles/logo-layout.css +48 -1
- package/dist/styles/shell-layout.css +11 -2
- package/dist/tokens/components/logo.css +10 -1
- package/dist/tokens/components/shell.css +2 -0
- package/dist/tokens/foundation.css +8 -8
- package/docs/DEVELOPMENT.md +20 -0
- package/docs/FRAME-A11Y-CI.md +135 -0
- package/docs/layout/topbar.tsx +19 -8
- package/package.json +5 -3
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const GODX_ARTWORK_ID_TOKEN = "__GXID__";
|
|
2
|
+
export interface BrandArtwork {
|
|
3
|
+
readonly viewBox: string;
|
|
4
|
+
/** Inner SVG markup — package-owned static artwork, never user input. */
|
|
5
|
+
readonly markup: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const GODX_LOCKUP_LIGHT: BrandArtwork;
|
|
8
|
+
export declare const GODX_LOCKUP_DARK: BrandArtwork;
|
|
9
|
+
export declare const GODX_MARK_LIGHT: BrandArtwork;
|
|
10
|
+
export declare const GODX_MARK_DARK: BrandArtwork;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const GODX_ARTWORK_ID_TOKEN = "__GXID__";
|
|
2
|
+
const GODX_LOCKUP_LIGHT = Object.freeze({
|
|
3
|
+
viewBox: "30 30 871.285714 182.000000",
|
|
4
|
+
markup: '<defs>\n <radialGradient id="__GXID__-gx-lockup-l-iconBodyGradient" gradientUnits="userSpaceOnUse" cx="58" cy="39" r="183">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="0.46" stop-color="#3700A6"/><stop offset="1" stop-color="#0B0F3B"/>\n </radialGradient>\n <linearGradient id="__GXID__-gx-lockup-l-arrowTopGradient" gradientUnits="userSpaceOnUse" x1="138" y1="100" x2="245" y2="148">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="1" stop-color="#980BFF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-l-arrowFoldGradient" gradientUnits="userSpaceOnUse" x1="230" y1="125" x2="165" y2="214">\n <stop offset="0" stop-color="#6500E5"/><stop offset="0.40" stop-color="#A611FF"/><stop offset="1" stop-color="#FF3DFF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-l-xMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#0B0F3B"/><stop offset="0.28" stop-color="#310077"/><stop offset="0.62" stop-color="#990DFF"/><stop offset="1" stop-color="#7A00FF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-l-xUpperGradient" gradientUnits="userSpaceOnUse" x1="747" y1="52" x2="795" y2="119">\n <stop offset="0" stop-color="#0B0F3B"/><stop offset="0.70" stop-color="#21005D"/><stop offset="1" stop-color="#7A00FF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-l-xLowerGradient" gradientUnits="userSpaceOnUse" x1="810" y1="125" x2="863" y2="188">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="0.55" stop-color="#21005D"/><stop offset="1" stop-color="#0B0F3B"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-l-reverseIconGradient" gradientUnits="userSpaceOnUse" x1="52" y1="40" x2="182" y2="211">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="0.6" stop-color="#9A45FF"/><stop offset="1" stop-color="#D8BCFF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-l-reverseXMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#E8DAFF"/><stop offset="0.46" stop-color="#B264FF"/><stop offset="1" stop-color="#7A00FF"/>\n </linearGradient>\n <clipPath id="__GXID__-gx-lockup-l-arrowClip"><path d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/></clipPath>\n</defs>\n\n<g id="__GXID__-gx-lockup-l-godx-logo" transform="translate(5 7)">\n<path id="__GXID__-gx-lockup-l-icon-body" fill="url(#__GXID__-gx-lockup-l-iconBodyGradient)" fill-rule="evenodd" d="M118 23 H183 C186 23 187 24 189 26 L222 64 Q226 69 220 69 H122 C96 69 75 91 75 117 C75 142 97 161 122 161 H151 Q157 161 153 166 L120 203 Q118 205 115 205 C90 205 69 194 50 174 C32 155 25 138 25 117 C25 92 36 75 56 54 C77 32 95 23 118 23 Z"/>\n<path id="__GXID__-gx-lockup-l-icon-arrow" fill="url(#__GXID__-gx-lockup-l-arrowTopGradient)" fill-rule="evenodd" d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/>\n<path id="__GXID__-gx-lockup-l-arrow-fold" clip-path="url(#__GXID__-gx-lockup-l-arrowClip)" fill="url(#__GXID__-gx-lockup-l-arrowFoldGradient)" d="M177.5,157 C205,133 238,109 267,120 L285,230 L110,230 Z"/>\n<path id="__GXID__-gx-lockup-l-letter-g" fill="#0B0F3B" fill-rule="evenodd" d="M428 76 L399 98 C391 86 378 79 365 79 C342 79 325 98 325 121 C325 144 343 163 365 163 C382 163 395 153 402 137 H362 V107 H442 V121 C442 165 409 198 365 198 C322 198 287 164 287 121 C287 78 322 44 365 44 C390 44 413 57 428 76 Z"/>\n<path id="__GXID__-gx-lockup-l-letter-o" fill="#0B0F3B" fill-rule="evenodd" d="M566 142.5 C566 173.704 539.585 199 507 199 C474.415 199 448 173.704 448 142.5 C448 111.296 474.415 86 507 86 C539.585 86 566 111.296 566 142.5 Z M533.5 142.5 C533.5 156.583 521.636 168 507 168 C492.364 168 480.5 156.583 480.5 142.5 C480.5 128.417 492.364 117 507 117 C521.636 117 533.5 128.417 533.5 142.5 Z"/>\n<path id="__GXID__-gx-lockup-l-letter-d" fill="#0B0F3B" fill-rule="evenodd" d="M574 44 H650 C698 44 732 75 732 121 C732 162 698 198 650 198 H574 Z M616.5 78 H649 C673 78 690 96 690 121 C690 146 673 164 649 164 H616.5 Z"/>\n<path id="__GXID__-gx-lockup-l-x-upper" fill="url(#__GXID__-gx-lockup-l-xUpperGradient)" fill-rule="evenodd" d="M715 44 H762 Q764 44 765 46 L801 86 L774 117 L713 47 Q711 44 715 44 Z"/>\n<path id="__GXID__-gx-lockup-l-x-diagonal" fill="url(#__GXID__-gx-lockup-l-xMainGradient)" fill-rule="evenodd" d="M844 42 H895 Q897 42 895 44 L761 196 Q759 198 757 198 H711 Q708 198 710 196 L841 44 Q843 42 844 42 Z"/>\n<path id="__GXID__-gx-lockup-l-x-lower" fill="url(#__GXID__-gx-lockup-l-xLowerGradient)" fill-rule="evenodd" d="M831 121 L895 196 Q898 199 894 199 H847 Q844 199 842 197 L805 153 Q803 151 805 149 Z"/>\n</g>'
|
|
5
|
+
});
|
|
6
|
+
const GODX_LOCKUP_DARK = Object.freeze({
|
|
7
|
+
viewBox: "30 30 871.285714 182.000000",
|
|
8
|
+
markup: '<defs>\n <radialGradient id="__GXID__-gx-lockup-d-iconBodyGradient" gradientUnits="userSpaceOnUse" cx="58" cy="39" r="183">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="0.46" stop-color="#3700A6"/><stop offset="1" stop-color="#0B0F3B"/>\n </radialGradient>\n <linearGradient id="__GXID__-gx-lockup-d-arrowTopGradient" gradientUnits="userSpaceOnUse" x1="138" y1="100" x2="245" y2="148">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="1" stop-color="#980BFF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-d-arrowFoldGradient" gradientUnits="userSpaceOnUse" x1="230" y1="125" x2="165" y2="214">\n <stop offset="0" stop-color="#6500E5"/><stop offset="0.40" stop-color="#A611FF"/><stop offset="1" stop-color="#FF3DFF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-d-xMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#0B0F3B"/><stop offset="0.28" stop-color="#310077"/><stop offset="0.62" stop-color="#990DFF"/><stop offset="1" stop-color="#7A00FF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-d-xUpperGradient" gradientUnits="userSpaceOnUse" x1="747" y1="52" x2="795" y2="119">\n <stop offset="0" stop-color="#0B0F3B"/><stop offset="0.70" stop-color="#21005D"/><stop offset="1" stop-color="#7A00FF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-d-xLowerGradient" gradientUnits="userSpaceOnUse" x1="810" y1="125" x2="863" y2="188">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="0.55" stop-color="#21005D"/><stop offset="1" stop-color="#0B0F3B"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-d-reverseIconGradient" gradientUnits="userSpaceOnUse" x1="52" y1="40" x2="182" y2="211">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="0.6" stop-color="#9A45FF"/><stop offset="1" stop-color="#D8BCFF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-lockup-d-reverseXMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#E8DAFF"/><stop offset="0.46" stop-color="#B264FF"/><stop offset="1" stop-color="#7A00FF"/>\n </linearGradient>\n <clipPath id="__GXID__-gx-lockup-d-arrowClip"><path d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/></clipPath>\n</defs>\n\n<g id="__GXID__-gx-lockup-d-godx-logo" transform="translate(5 7)">\n<path id="__GXID__-gx-lockup-d-icon-body" fill="url(#__GXID__-gx-lockup-d-reverseIconGradient)" fill-rule="evenodd" d="M118 23 H183 C186 23 187 24 189 26 L222 64 Q226 69 220 69 H122 C96 69 75 91 75 117 C75 142 97 161 122 161 H151 Q157 161 153 166 L120 203 Q118 205 115 205 C90 205 69 194 50 174 C32 155 25 138 25 117 C25 92 36 75 56 54 C77 32 95 23 118 23 Z"/>\n<path id="__GXID__-gx-lockup-d-icon-arrow" fill="url(#__GXID__-gx-lockup-d-arrowTopGradient)" fill-rule="evenodd" d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/>\n<path id="__GXID__-gx-lockup-d-arrow-fold" clip-path="url(#__GXID__-gx-lockup-d-arrowClip)" fill="url(#__GXID__-gx-lockup-d-arrowFoldGradient)" d="M177.5,157 C205,133 238,109 267,120 L285,230 L110,230 Z"/>\n<path id="__GXID__-gx-lockup-d-letter-g" fill="#FFFFFF" fill-rule="evenodd" d="M428 76 L399 98 C391 86 378 79 365 79 C342 79 325 98 325 121 C325 144 343 163 365 163 C382 163 395 153 402 137 H362 V107 H442 V121 C442 165 409 198 365 198 C322 198 287 164 287 121 C287 78 322 44 365 44 C390 44 413 57 428 76 Z"/>\n<path id="__GXID__-gx-lockup-d-letter-o" fill="#FFFFFF" fill-rule="evenodd" d="M566 142.5 C566 173.704 539.585 199 507 199 C474.415 199 448 173.704 448 142.5 C448 111.296 474.415 86 507 86 C539.585 86 566 111.296 566 142.5 Z M533.5 142.5 C533.5 156.583 521.636 168 507 168 C492.364 168 480.5 156.583 480.5 142.5 C480.5 128.417 492.364 117 507 117 C521.636 117 533.5 128.417 533.5 142.5 Z"/>\n<path id="__GXID__-gx-lockup-d-letter-d" fill="#FFFFFF" fill-rule="evenodd" d="M574 44 H650 C698 44 732 75 732 121 C732 162 698 198 650 198 H574 Z M616.5 78 H649 C673 78 690 96 690 121 C690 146 673 164 649 164 H616.5 Z"/>\n<path id="__GXID__-gx-lockup-d-x-upper" fill="#FFFFFF" fill-rule="evenodd" d="M715 44 H762 Q764 44 765 46 L801 86 L774 117 L713 47 Q711 44 715 44 Z"/>\n<path id="__GXID__-gx-lockup-d-x-diagonal" fill="url(#__GXID__-gx-lockup-d-reverseXMainGradient)" fill-rule="evenodd" d="M844 42 H895 Q897 42 895 44 L761 196 Q759 198 757 198 H711 Q708 198 710 196 L841 44 Q843 42 844 42 Z"/>\n<path id="__GXID__-gx-lockup-d-x-lower" fill="#FFFFFF" fill-rule="evenodd" d="M831 121 L895 196 Q898 199 894 199 H847 Q844 199 842 197 L805 153 Q803 151 805 149 Z"/>\n</g>'
|
|
9
|
+
});
|
|
10
|
+
const GODX_MARK_LIGHT = Object.freeze({
|
|
11
|
+
viewBox: "30 30 241.000000 182.000000",
|
|
12
|
+
markup: '<defs>\n <radialGradient id="__GXID__-gx-mark-l-iconBodyGradient" gradientUnits="userSpaceOnUse" cx="58" cy="39" r="183">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="0.46" stop-color="#3700A6"/><stop offset="1" stop-color="#0B0F3B"/>\n </radialGradient>\n <linearGradient id="__GXID__-gx-mark-l-arrowTopGradient" gradientUnits="userSpaceOnUse" x1="138" y1="100" x2="245" y2="148">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="1" stop-color="#980BFF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-l-arrowFoldGradient" gradientUnits="userSpaceOnUse" x1="230" y1="125" x2="165" y2="214">\n <stop offset="0" stop-color="#6500E5"/><stop offset="0.40" stop-color="#A611FF"/><stop offset="1" stop-color="#FF3DFF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-l-xMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#0B0F3B"/><stop offset="0.28" stop-color="#310077"/><stop offset="0.62" stop-color="#990DFF"/><stop offset="1" stop-color="#7A00FF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-l-xUpperGradient" gradientUnits="userSpaceOnUse" x1="747" y1="52" x2="795" y2="119">\n <stop offset="0" stop-color="#0B0F3B"/><stop offset="0.70" stop-color="#21005D"/><stop offset="1" stop-color="#7A00FF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-l-xLowerGradient" gradientUnits="userSpaceOnUse" x1="810" y1="125" x2="863" y2="188">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="0.55" stop-color="#21005D"/><stop offset="1" stop-color="#0B0F3B"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-l-reverseIconGradient" gradientUnits="userSpaceOnUse" x1="52" y1="40" x2="182" y2="211">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="0.6" stop-color="#9A45FF"/><stop offset="1" stop-color="#D8BCFF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-l-reverseXMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#E8DAFF"/><stop offset="0.46" stop-color="#B264FF"/><stop offset="1" stop-color="#7A00FF"/>\n </linearGradient>\n <clipPath id="__GXID__-gx-mark-l-arrowClip"><path d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/></clipPath>\n</defs>\n\n<g id="__GXID__-gx-mark-l-godx-icon" transform="translate(5 7)">\n<path id="__GXID__-gx-mark-l-icon-body" fill="url(#__GXID__-gx-mark-l-iconBodyGradient)" fill-rule="evenodd" d="M118 23 H183 C186 23 187 24 189 26 L222 64 Q226 69 220 69 H122 C96 69 75 91 75 117 C75 142 97 161 122 161 H151 Q157 161 153 166 L120 203 Q118 205 115 205 C90 205 69 194 50 174 C32 155 25 138 25 117 C25 92 36 75 56 54 C77 32 95 23 118 23 Z"/>\n<path id="__GXID__-gx-mark-l-icon-arrow" fill="url(#__GXID__-gx-mark-l-arrowTopGradient)" fill-rule="evenodd" d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/>\n<path id="__GXID__-gx-mark-l-arrow-fold" clip-path="url(#__GXID__-gx-mark-l-arrowClip)" fill="url(#__GXID__-gx-mark-l-arrowFoldGradient)" d="M177.5,157 C205,133 238,109 267,120 L285,230 L110,230 Z"/>\n</g>'
|
|
13
|
+
});
|
|
14
|
+
const GODX_MARK_DARK = Object.freeze({
|
|
15
|
+
viewBox: "30 30 241.000000 182.000000",
|
|
16
|
+
markup: '<defs>\n <radialGradient id="__GXID__-gx-mark-d-iconBodyGradient" gradientUnits="userSpaceOnUse" cx="58" cy="39" r="183">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="0.46" stop-color="#3700A6"/><stop offset="1" stop-color="#0B0F3B"/>\n </radialGradient>\n <linearGradient id="__GXID__-gx-mark-d-arrowTopGradient" gradientUnits="userSpaceOnUse" x1="138" y1="100" x2="245" y2="148">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="1" stop-color="#980BFF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-d-arrowFoldGradient" gradientUnits="userSpaceOnUse" x1="230" y1="125" x2="165" y2="214">\n <stop offset="0" stop-color="#6500E5"/><stop offset="0.40" stop-color="#A611FF"/><stop offset="1" stop-color="#FF3DFF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-d-xMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#0B0F3B"/><stop offset="0.28" stop-color="#310077"/><stop offset="0.62" stop-color="#990DFF"/><stop offset="1" stop-color="#7A00FF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-d-xUpperGradient" gradientUnits="userSpaceOnUse" x1="747" y1="52" x2="795" y2="119">\n <stop offset="0" stop-color="#0B0F3B"/><stop offset="0.70" stop-color="#21005D"/><stop offset="1" stop-color="#7A00FF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-d-xLowerGradient" gradientUnits="userSpaceOnUse" x1="810" y1="125" x2="863" y2="188">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="0.55" stop-color="#21005D"/><stop offset="1" stop-color="#0B0F3B"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-d-reverseIconGradient" gradientUnits="userSpaceOnUse" x1="52" y1="40" x2="182" y2="211">\n <stop offset="0" stop-color="#7A00FF"/><stop offset="0.6" stop-color="#9A45FF"/><stop offset="1" stop-color="#D8BCFF"/>\n </linearGradient>\n <linearGradient id="__GXID__-gx-mark-d-reverseXMainGradient" gradientUnits="userSpaceOnUse" x1="861" y1="48" x2="739" y2="202">\n <stop offset="0" stop-color="#E8DAFF"/><stop offset="0.46" stop-color="#B264FF"/><stop offset="1" stop-color="#7A00FF"/>\n </linearGradient>\n <clipPath id="__GXID__-gx-mark-d-arrowClip"><path d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/></clipPath>\n</defs>\n\n<g id="__GXID__-gx-mark-d-godx-icon" transform="translate(5 7)">\n<path id="__GXID__-gx-mark-d-icon-body" fill="url(#__GXID__-gx-mark-d-reverseIconGradient)" fill-rule="evenodd" d="M118 23 H183 C186 23 187 24 189 26 L222 64 Q226 69 220 69 H122 C96 69 75 91 75 117 C75 142 97 161 122 161 H151 Q157 161 153 166 L120 203 Q118 205 115 205 C90 205 69 194 50 174 C32 155 25 138 25 117 C25 92 36 75 56 54 C77 32 95 23 118 23 Z"/>\n<path id="__GXID__-gx-mark-d-icon-arrow" fill="url(#__GXID__-gx-mark-d-arrowTopGradient)" fill-rule="evenodd" d="M131 97 H244 Q247 97 249 100 L264 117 Q268 122 264 127 L194 201 Q190 205 185 205 H139 Q133 205 137 201 L176 160 Q179 157 176 154 L129 104 Q123 97 131 97 Z"/>\n<path id="__GXID__-gx-mark-d-arrow-fold" clip-path="url(#__GXID__-gx-mark-d-arrowClip)" fill="url(#__GXID__-gx-mark-d-arrowFoldGradient)" d="M177.5,157 C205,133 238,109 267,120 L285,230 L110,230 Z"/>\n</g>'
|
|
17
|
+
});
|
|
18
|
+
export {
|
|
19
|
+
GODX_ARTWORK_ID_TOKEN,
|
|
20
|
+
GODX_LOCKUP_DARK,
|
|
21
|
+
GODX_LOCKUP_LIGHT,
|
|
22
|
+
GODX_MARK_DARK,
|
|
23
|
+
GODX_MARK_LIGHT
|
|
24
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE FLAT GoDX MARK — the cut EMAIL paints. The web uses the master instead.
|
|
3
|
+
*
|
|
4
|
+
* Brand identity v2.3 requires the master SVG with its gradients and a light/dark variant
|
|
5
|
+
* (`brand/godx-artwork.generated.ts`), and forbids re-tinting it. An email cannot honour that:
|
|
6
|
+
* Outlook's Word renderer drops SVG gradients, `prefers-color-scheme` reaches only some clients,
|
|
7
|
+
* and a delivered message cannot swap a variant. So email paints the kit's own FLAT cut — a
|
|
8
|
+
* different brand ASSET, which is why the kit ships one — in a colour the template supplies.
|
|
9
|
+
*
|
|
10
|
+
* Brand identity v2.3. The coordinates are the kit's own normalised construction data
|
|
11
|
+
* (`02_Construction/GoDX/GoDX-geometry-v2_2.json`, origin already at 0,0), not a redraw and not a
|
|
12
|
+
* trace: a future artwork revision is a copy-paste of two `d` strings into this file.
|
|
13
|
+
*
|
|
14
|
+
* WHY IT IS STILL SHARED. `src/email` may only import its own siblings, so it receives a generated
|
|
15
|
+
* copy of these paths (`gen-email-tokens.mjs`). This file is the declaration both that generator
|
|
16
|
+
* and its `--check` guard compare against, so the email mark cannot drift from the package's own
|
|
17
|
+
* flat artwork — the drift that was caught once already.
|
|
18
|
+
*
|
|
19
|
+
* MONOCHROME. The kit also ships a gradient cut (#7A00FF → #3700A6 → #0B0F3B). It is deliberately
|
|
20
|
+
* not used: this mark is painted by a token (`--logo-godx-color` on the web, a colour argument in
|
|
21
|
+
* email) so it re-tints per theme and knocks out on dark surfaces. A baked gradient can do neither,
|
|
22
|
+
* and email clients are worse at gradients than they are at paths.
|
|
23
|
+
*/
|
|
24
|
+
/** The artwork's own coordinate space, before fitting. */
|
|
25
|
+
export declare const GODX_MARK_SOURCE: Readonly<{
|
|
26
|
+
width: 241;
|
|
27
|
+
height: 182;
|
|
28
|
+
}>;
|
|
29
|
+
/** The square box every renderer draws into. */
|
|
30
|
+
export declare const GODX_MARK_VIEW_BOX = "0 0 32 32";
|
|
31
|
+
/**
|
|
32
|
+
* Fits 241×182 into the square box, centred vertically.
|
|
33
|
+
* scale = 32 / 241 = 0.132780; y = (32 − 182 × scale) / 2 = 3.917.
|
|
34
|
+
*/
|
|
35
|
+
export declare const GODX_MARK_TRANSFORM = "translate(0 3.917) scale(0.132780)";
|
|
36
|
+
/** The "G" body. */
|
|
37
|
+
export declare const GODX_MARK_BODY_PATH = "M93.0 0.0H158.0C161.0 0.0 162.0 1.0 164.0 3.0L197.0 41.0Q201.0 46.0 195.0 46.0H97.0C71.0 46.0 50.0 68.0 50.0 94.0C50.0 119.0 72.0 138.0 97.0 138.0H126.0Q132.0 138.0 128.0 143.0L95.0 180.0Q93.0 182.0 90.0 182.0C65.0 182.0 44.0 171.0 25.0 151.0C7.0 132.0 0.0 115.0 0.0 94.0C0.0 69.0 11.0 52.0 31.0 31.0C52.0 9.0 70.0 0.0 93.0 0.0Z";
|
|
38
|
+
/** The arrow that crosses it. */
|
|
39
|
+
export declare const GODX_MARK_ARROW_PATH = "M106.0 74.0H219.0Q222.0 74.0 224.0 77.0L239.0 94.0Q243.0 99.0 239.0 104.0L169.0 178.0Q165.0 182.0 160.0 182.0H114.0Q108.0 182.0 112.0 178.0L151.0 137.0Q154.0 134.0 151.0 131.0L104.0 81.0Q98.0 74.0 106.0 74.0Z";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const GODX_MARK_SOURCE = Object.freeze({ width: 241, height: 182 });
|
|
2
|
+
const GODX_MARK_VIEW_BOX = "0 0 32 32";
|
|
3
|
+
const GODX_MARK_TRANSFORM = "translate(0 3.917) scale(0.132780)";
|
|
4
|
+
const GODX_MARK_BODY_PATH = "M93.0 0.0H158.0C161.0 0.0 162.0 1.0 164.0 3.0L197.0 41.0Q201.0 46.0 195.0 46.0H97.0C71.0 46.0 50.0 68.0 50.0 94.0C50.0 119.0 72.0 138.0 97.0 138.0H126.0Q132.0 138.0 128.0 143.0L95.0 180.0Q93.0 182.0 90.0 182.0C65.0 182.0 44.0 171.0 25.0 151.0C7.0 132.0 0.0 115.0 0.0 94.0C0.0 69.0 11.0 52.0 31.0 31.0C52.0 9.0 70.0 0.0 93.0 0.0Z";
|
|
5
|
+
const GODX_MARK_ARROW_PATH = "M106.0 74.0H219.0Q222.0 74.0 224.0 77.0L239.0 94.0Q243.0 99.0 239.0 104.0L169.0 178.0Q165.0 182.0 160.0 182.0H114.0Q108.0 182.0 112.0 178.0L151.0 137.0Q154.0 134.0 151.0 131.0L104.0 81.0Q98.0 74.0 106.0 74.0Z";
|
|
6
|
+
export {
|
|
7
|
+
GODX_MARK_ARROW_PATH,
|
|
8
|
+
GODX_MARK_BODY_PATH,
|
|
9
|
+
GODX_MARK_SOURCE,
|
|
10
|
+
GODX_MARK_TRANSFORM,
|
|
11
|
+
GODX_MARK_VIEW_BOX
|
|
12
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
export type LogoSize = "xs" | "sm" | "md" | "lg";
|
|
3
3
|
export type LogoTone = "primary" | "success";
|
|
4
|
-
export type LogoMark = "glyph" | "godx";
|
|
4
|
+
export type LogoMark = "glyph" | "godx" | "godx-lockup";
|
|
5
5
|
export interface LogoProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "children"> {
|
|
6
6
|
/**
|
|
7
7
|
* The brand glyph — a short mark (a letter/initials, default `"g"`) or a custom node such as an
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
3
|
import * as React from "react";
|
|
4
|
+
import {
|
|
5
|
+
GODX_ARTWORK_ID_TOKEN,
|
|
6
|
+
GODX_LOCKUP_DARK,
|
|
7
|
+
GODX_LOCKUP_LIGHT,
|
|
8
|
+
GODX_MARK_DARK,
|
|
9
|
+
GODX_MARK_LIGHT
|
|
10
|
+
} from "../../brand/godx-artwork.generated.js";
|
|
3
11
|
import { Slot } from "../../lib/slot.js";
|
|
4
12
|
import { cn } from "../../lib/utils.js";
|
|
5
13
|
const X_HEIGHT_TOP = /^[acegmnopqrsuvwxyz]+$/;
|
|
@@ -38,7 +46,13 @@ function logoGlyphAdvance(glyph) {
|
|
|
38
46
|
return counts;
|
|
39
47
|
}
|
|
40
48
|
function MarkArtwork({ mark, glyph }) {
|
|
41
|
-
|
|
49
|
+
const instanceId = React.useId().replace(/[^a-zA-Z0-9_-]/g, "");
|
|
50
|
+
const artwork = mark === "godx-lockup" ? [GODX_LOCKUP_LIGHT, GODX_LOCKUP_DARK] : [GODX_MARK_LIGHT, GODX_MARK_DARK];
|
|
51
|
+
const html = React.useMemo(
|
|
52
|
+
() => artwork.map((a) => a.markup.replaceAll(GODX_ARTWORK_ID_TOKEN, instanceId)),
|
|
53
|
+
[artwork, instanceId]
|
|
54
|
+
);
|
|
55
|
+
if (mark === "glyph") {
|
|
42
56
|
const advance = logoGlyphAdvance(glyph);
|
|
43
57
|
return /* @__PURE__ */ jsx(
|
|
44
58
|
"span",
|
|
@@ -56,25 +70,21 @@ function MarkArtwork({ mark, glyph }) {
|
|
|
56
70
|
}
|
|
57
71
|
);
|
|
58
72
|
}
|
|
59
|
-
return /* @__PURE__ */ jsx(
|
|
73
|
+
return /* @__PURE__ */ jsx(Fragment, { children: ["light", "dark"].map((scheme, index) => /* @__PURE__ */ jsx(
|
|
60
74
|
"svg",
|
|
61
75
|
{
|
|
62
76
|
"data-slot": "logo-artwork",
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
77
|
+
"data-artwork": mark,
|
|
78
|
+
"data-scheme": scheme,
|
|
79
|
+
viewBox: artwork[index].viewBox,
|
|
66
80
|
focusable: "false",
|
|
67
81
|
"aria-hidden": "true",
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
)
|
|
76
|
-
}
|
|
77
|
-
);
|
|
82
|
+
dangerouslySetInnerHTML: {
|
|
83
|
+
__html: html[index]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
scheme
|
|
87
|
+
)) });
|
|
78
88
|
}
|
|
79
89
|
const Logo = React.forwardRef(
|
|
80
90
|
({
|
|
@@ -29,6 +29,23 @@ const DROPDOWN_MENU_PLACEMENT = {
|
|
|
29
29
|
bottomStart: { side: "bottom", align: "start" },
|
|
30
30
|
bottomEnd: { side: "bottom", align: "end" }
|
|
31
31
|
};
|
|
32
|
+
class MenuCollectionBoundary extends React.Component {
|
|
33
|
+
state = { failed: false };
|
|
34
|
+
static getDerivedStateFromError() {
|
|
35
|
+
return { failed: true };
|
|
36
|
+
}
|
|
37
|
+
// Logged in EVERY build, not only development: "blank, with nothing in the console" is the half
|
|
38
|
+
// of gh#637 that cost the reporter a night of instrumenting `Object.prototype`.
|
|
39
|
+
componentDidCatch(error) {
|
|
40
|
+
console.error(
|
|
41
|
+
"[@godxjp/ui] DropdownMenu: the menu could not be built and was left empty; the rest of the application is unaffected. A menu's children must be collection nodes (DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuGroup, DropdownMenuSub) or components returning one \u2014 an icon or a text label belongs INSIDE an item, not beside it. Underlying error:",
|
|
42
|
+
error
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
render() {
|
|
46
|
+
return this.state.failed ? null : this.props.children;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
32
49
|
function borrowedTag(children, asChild) {
|
|
33
50
|
return asChild ? React.Children.only(children) : null;
|
|
34
51
|
}
|
|
@@ -357,7 +374,7 @@ function DropdownMenuContent({
|
|
|
357
374
|
)
|
|
358
375
|
),
|
|
359
376
|
children: [
|
|
360
|
-
/* @__PURE__ */ jsx(Menu, { shouldFocusWrap: loop, autoFocus: openedByHover.current ? false : void 0, children }),
|
|
377
|
+
/* @__PURE__ */ jsx(MenuCollectionBoundary, { children: /* @__PURE__ */ jsx(Menu, { shouldFocusWrap: loop, autoFocus: openedByHover.current ? false : void 0, children }) }),
|
|
361
378
|
arrow ? /* @__PURE__ */ jsx(OverlayArrow, { children: /* @__PURE__ */ jsx(
|
|
362
379
|
"svg",
|
|
363
380
|
{
|
|
@@ -601,7 +618,7 @@ function DropdownMenuSubContent({
|
|
|
601
618
|
}
|
|
602
619
|
)
|
|
603
620
|
),
|
|
604
|
-
children: /* @__PURE__ */ jsx(Menu, { shouldFocusWrap: loop, children })
|
|
621
|
+
children: /* @__PURE__ */ jsx(MenuCollectionBoundary, { children: /* @__PURE__ */ jsx(Menu, { shouldFocusWrap: loop, children }) })
|
|
605
622
|
}
|
|
606
623
|
);
|
|
607
624
|
}
|
|
@@ -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": "
|
|
3
|
+
"version": "24.1.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,
|
|
@@ -14,7 +14,8 @@ export interface EmailBrandMarkRect {
|
|
|
14
14
|
readonly radius: number;
|
|
15
15
|
}
|
|
16
16
|
/** Intrinsic coordinate space of the mark artwork. */
|
|
17
|
-
|
|
17
|
+
/** The component's box, read from the shared artwork so the two cannot drift. */
|
|
18
|
+
export declare const EMAIL_BRAND_MARK_VIEWBOX: "0 0 32 32";
|
|
18
19
|
/** The emerald capsule. */
|
|
19
20
|
export declare const EMAIL_BRAND_MARK_CAPSULE: EmailBrandMarkRect;
|
|
20
21
|
/** The internal light glyph bar inside the capsule. */
|
package/dist/email/brand-mark.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EMAIL_COLORS } from "./color.js";
|
|
2
|
-
import { EMAIL_GEOMETRY_SOURCE } from "./tokens.generated.js";
|
|
3
|
-
const EMAIL_BRAND_MARK_VIEWBOX =
|
|
2
|
+
import { EMAIL_GEOMETRY_SOURCE, EMAIL_MARK_SOURCE } from "./tokens.generated.js";
|
|
3
|
+
const EMAIL_BRAND_MARK_VIEWBOX = EMAIL_MARK_SOURCE.viewBox;
|
|
4
4
|
const EMAIL_BRAND_MARK_CAPSULE = Object.freeze({
|
|
5
5
|
x: 1,
|
|
6
6
|
y: 7,
|
|
@@ -22,8 +22,8 @@ function roundedRectPath({ x, y, width, height, radius }) {
|
|
|
22
22
|
const v = height - 2 * radius;
|
|
23
23
|
return `M${x + radius} ${y}h${h}${arc(radius, radius, radius)}v${v}${arc(radius, -radius, radius)}H${x + radius}${arc(radius, -radius, -radius)}v-${v}${arc(radius, radius, -radius)}Z`;
|
|
24
24
|
}
|
|
25
|
-
const CAPSULE_PATH =
|
|
26
|
-
const GLYPH_PATH =
|
|
25
|
+
const CAPSULE_PATH = EMAIL_MARK_SOURCE.bodyPath;
|
|
26
|
+
const GLYPH_PATH = EMAIL_MARK_SOURCE.arrowPath;
|
|
27
27
|
const DEFAULT_WIDTH = Number.parseFloat(EMAIL_GEOMETRY_SOURCE["--email-mark-width"]);
|
|
28
28
|
const DEFAULT_HEIGHT = Number.parseFloat(EMAIL_GEOMETRY_SOURCE["--email-mark-height"]);
|
|
29
29
|
function options(o = {}) {
|
|
@@ -39,7 +39,7 @@ const attr = (value) => value.replace(/&/g, "&").replace(/</g, "<").repla
|
|
|
39
39
|
function emailBrandMarkSvg(o = {}) {
|
|
40
40
|
const { width, height, color, glyphColor, label } = options(o);
|
|
41
41
|
const a11y = label ? ` role="img" aria-label="${attr(label)}"` : ` role="presentation" aria-hidden="true"`;
|
|
42
|
-
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="${EMAIL_BRAND_MARK_VIEWBOX}" focusable="false"${a11y} style="display:block;border:0;outline:none;text-decoration:none"><path fill="${color}" d="${CAPSULE_PATH}"/><path fill="${glyphColor}" d="${GLYPH_PATH}"/></svg>`;
|
|
42
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="${EMAIL_BRAND_MARK_VIEWBOX}" focusable="false"${a11y} style="display:block;border:0;outline:none;text-decoration:none"><g transform="${EMAIL_MARK_SOURCE.transform}" fill-rule="evenodd"><path fill="${color}" d="${CAPSULE_PATH}"/><path fill="${glyphColor}" d="${GLYPH_PATH}"/></g></svg>`;
|
|
43
43
|
}
|
|
44
44
|
function emailBrandMarkDataUri(o = {}) {
|
|
45
45
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(emailBrandMarkSvg(o))}`;
|
|
@@ -37,7 +37,7 @@ export declare const EMAIL_COLOR_SOURCE: {
|
|
|
37
37
|
};
|
|
38
38
|
readonly primary: {
|
|
39
39
|
readonly cssVar: "--primary";
|
|
40
|
-
readonly hsl: "
|
|
40
|
+
readonly hsl: "268.7 100% 50%";
|
|
41
41
|
};
|
|
42
42
|
readonly primaryForeground: {
|
|
43
43
|
readonly cssVar: "--primary-foreground";
|
|
@@ -45,11 +45,11 @@ export declare const EMAIL_COLOR_SOURCE: {
|
|
|
45
45
|
};
|
|
46
46
|
readonly focus: {
|
|
47
47
|
readonly cssVar: "--primary";
|
|
48
|
-
readonly hsl: "
|
|
48
|
+
readonly hsl: "268.7 100% 50%";
|
|
49
49
|
};
|
|
50
50
|
readonly brand: {
|
|
51
51
|
readonly cssVar: "--brand";
|
|
52
|
-
readonly hsl: "
|
|
52
|
+
readonly hsl: "268.7 100% 50%";
|
|
53
53
|
};
|
|
54
54
|
readonly brandForeground: {
|
|
55
55
|
readonly cssVar: "--brand-foreground";
|
|
@@ -96,7 +96,7 @@ export declare const EMAIL_COLOR_SOURCE_DARK: {
|
|
|
96
96
|
};
|
|
97
97
|
readonly primary: {
|
|
98
98
|
readonly cssVar: "--primary";
|
|
99
|
-
readonly hsl: "
|
|
99
|
+
readonly hsl: "268.7 100% 86.9%";
|
|
100
100
|
};
|
|
101
101
|
readonly primaryForeground: {
|
|
102
102
|
readonly cssVar: "--primary-foreground";
|
|
@@ -104,11 +104,11 @@ export declare const EMAIL_COLOR_SOURCE_DARK: {
|
|
|
104
104
|
};
|
|
105
105
|
readonly focus: {
|
|
106
106
|
readonly cssVar: "--primary";
|
|
107
|
-
readonly hsl: "
|
|
107
|
+
readonly hsl: "268.7 100% 86.9%";
|
|
108
108
|
};
|
|
109
109
|
readonly brand: {
|
|
110
110
|
readonly cssVar: "--brand";
|
|
111
|
-
readonly hsl: "
|
|
111
|
+
readonly hsl: "268.7 100% 86.9%";
|
|
112
112
|
};
|
|
113
113
|
readonly brandForeground: {
|
|
114
114
|
readonly cssVar: "--brand-foreground";
|
|
@@ -165,3 +165,13 @@ export declare const EMAIL_GEOMETRY_SOURCE: {
|
|
|
165
165
|
readonly "--email-mobile-heading-font-size": "16px";
|
|
166
166
|
readonly "--email-mobile-cta-width": "100%";
|
|
167
167
|
};
|
|
168
|
+
/**
|
|
169
|
+
* The GoDX identity artwork — the same two paths `<Logo mark="godx" />` paints, from
|
|
170
|
+
* `src/brand/godx-mark.ts`. Regenerate with the rest of this file; `--check` fails on drift.
|
|
171
|
+
*/
|
|
172
|
+
export declare const EMAIL_MARK_SOURCE: {
|
|
173
|
+
readonly viewBox: "0 0 32 32";
|
|
174
|
+
readonly transform: "translate(0 3.917) scale(0.132780)";
|
|
175
|
+
readonly bodyPath: "M93.0 0.0H158.0C161.0 0.0 162.0 1.0 164.0 3.0L197.0 41.0Q201.0 46.0 195.0 46.0H97.0C71.0 46.0 50.0 68.0 50.0 94.0C50.0 119.0 72.0 138.0 97.0 138.0H126.0Q132.0 138.0 128.0 143.0L95.0 180.0Q93.0 182.0 90.0 182.0C65.0 182.0 44.0 171.0 25.0 151.0C7.0 132.0 0.0 115.0 0.0 94.0C0.0 69.0 11.0 52.0 31.0 31.0C52.0 9.0 70.0 0.0 93.0 0.0Z";
|
|
176
|
+
readonly arrowPath: "M106.0 74.0H219.0Q222.0 74.0 224.0 77.0L239.0 94.0Q243.0 99.0 239.0 104.0L169.0 178.0Q165.0 182.0 160.0 182.0H114.0Q108.0 182.0 112.0 178.0L151.0 137.0Q154.0 134.0 151.0 131.0L104.0 81.0Q98.0 74.0 106.0 74.0Z";
|
|
177
|
+
};
|
|
@@ -29,7 +29,7 @@ const EMAIL_COLOR_SOURCE = {
|
|
|
29
29
|
},
|
|
30
30
|
"primary": {
|
|
31
31
|
"cssVar": "--primary",
|
|
32
|
-
"hsl": "
|
|
32
|
+
"hsl": "268.7 100% 50%"
|
|
33
33
|
},
|
|
34
34
|
"primaryForeground": {
|
|
35
35
|
"cssVar": "--primary-foreground",
|
|
@@ -37,11 +37,11 @@ const EMAIL_COLOR_SOURCE = {
|
|
|
37
37
|
},
|
|
38
38
|
"focus": {
|
|
39
39
|
"cssVar": "--primary",
|
|
40
|
-
"hsl": "
|
|
40
|
+
"hsl": "268.7 100% 50%"
|
|
41
41
|
},
|
|
42
42
|
"brand": {
|
|
43
43
|
"cssVar": "--brand",
|
|
44
|
-
"hsl": "
|
|
44
|
+
"hsl": "268.7 100% 50%"
|
|
45
45
|
},
|
|
46
46
|
"brandForeground": {
|
|
47
47
|
"cssVar": "--brand-foreground",
|
|
@@ -87,7 +87,7 @@ const EMAIL_COLOR_SOURCE_DARK = {
|
|
|
87
87
|
},
|
|
88
88
|
"primary": {
|
|
89
89
|
"cssVar": "--primary",
|
|
90
|
-
"hsl": "
|
|
90
|
+
"hsl": "268.7 100% 86.9%"
|
|
91
91
|
},
|
|
92
92
|
"primaryForeground": {
|
|
93
93
|
"cssVar": "--primary-foreground",
|
|
@@ -95,11 +95,11 @@ const EMAIL_COLOR_SOURCE_DARK = {
|
|
|
95
95
|
},
|
|
96
96
|
"focus": {
|
|
97
97
|
"cssVar": "--primary",
|
|
98
|
-
"hsl": "
|
|
98
|
+
"hsl": "268.7 100% 86.9%"
|
|
99
99
|
},
|
|
100
100
|
"brand": {
|
|
101
101
|
"cssVar": "--brand",
|
|
102
|
-
"hsl": "
|
|
102
|
+
"hsl": "268.7 100% 86.9%"
|
|
103
103
|
},
|
|
104
104
|
"brandForeground": {
|
|
105
105
|
"cssVar": "--brand-foreground",
|
|
@@ -155,8 +155,15 @@ const EMAIL_GEOMETRY_SOURCE = {
|
|
|
155
155
|
"--email-mobile-heading-font-size": "16px",
|
|
156
156
|
"--email-mobile-cta-width": "100%"
|
|
157
157
|
};
|
|
158
|
+
const EMAIL_MARK_SOURCE = {
|
|
159
|
+
"viewBox": "0 0 32 32",
|
|
160
|
+
"transform": "translate(0 3.917) scale(0.132780)",
|
|
161
|
+
"bodyPath": "M93.0 0.0H158.0C161.0 0.0 162.0 1.0 164.0 3.0L197.0 41.0Q201.0 46.0 195.0 46.0H97.0C71.0 46.0 50.0 68.0 50.0 94.0C50.0 119.0 72.0 138.0 97.0 138.0H126.0Q132.0 138.0 128.0 143.0L95.0 180.0Q93.0 182.0 90.0 182.0C65.0 182.0 44.0 171.0 25.0 151.0C7.0 132.0 0.0 115.0 0.0 94.0C0.0 69.0 11.0 52.0 31.0 31.0C52.0 9.0 70.0 0.0 93.0 0.0Z",
|
|
162
|
+
"arrowPath": "M106.0 74.0H219.0Q222.0 74.0 224.0 77.0L239.0 94.0Q243.0 99.0 239.0 104.0L169.0 178.0Q165.0 182.0 160.0 182.0H114.0Q108.0 182.0 112.0 178.0L151.0 137.0Q154.0 134.0 151.0 131.0L104.0 81.0Q98.0 74.0 106.0 74.0Z"
|
|
163
|
+
};
|
|
158
164
|
export {
|
|
159
165
|
EMAIL_COLOR_SOURCE,
|
|
160
166
|
EMAIL_COLOR_SOURCE_DARK,
|
|
161
|
-
EMAIL_GEOMETRY_SOURCE
|
|
167
|
+
EMAIL_GEOMETRY_SOURCE,
|
|
168
|
+
EMAIL_MARK_SOURCE
|
|
162
169
|
};
|
|
@@ -99,7 +99,6 @@
|
|
|
99
99
|
height: var(--logo-godx-size, var(--logo-godx-size-md));
|
|
100
100
|
border-radius: 0;
|
|
101
101
|
background: transparent;
|
|
102
|
-
color: hsl(var(--logo-godx-color, var(--brand)));
|
|
103
102
|
}
|
|
104
103
|
|
|
105
104
|
.ui-logo[data-mark="godx"][data-size="xs"] {
|
|
@@ -117,6 +116,31 @@
|
|
|
117
116
|
height: var(--logo-godx-size, var(--logo-godx-size-lg));
|
|
118
117
|
}
|
|
119
118
|
|
|
119
|
+
.ui-logo[data-mark="godx-lockup"] {
|
|
120
|
+
width: auto;
|
|
121
|
+
height: var(--logo-godx-size, var(--logo-godx-size-md));
|
|
122
|
+
border-radius: 0;
|
|
123
|
+
background: transparent;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.ui-logo[data-mark="godx-lockup"][data-size="xs"] {
|
|
127
|
+
height: var(--logo-godx-size, var(--logo-godx-size-xs));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.ui-logo[data-mark="godx-lockup"][data-size="sm"] {
|
|
131
|
+
height: var(--logo-godx-size, var(--logo-godx-size-sm));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.ui-logo[data-mark="godx-lockup"][data-size="lg"] {
|
|
135
|
+
height: var(--logo-godx-size, var(--logo-godx-size-lg));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.ui-logo[data-mark="godx-lockup"] [data-slot="logo-artwork"] {
|
|
139
|
+
display: block;
|
|
140
|
+
height: 100%;
|
|
141
|
+
width: auto;
|
|
142
|
+
}
|
|
143
|
+
|
|
120
144
|
.ui-logo[data-mark="godx"] [data-slot="logo-artwork"] {
|
|
121
145
|
display: block;
|
|
122
146
|
width: 100%;
|
|
@@ -156,3 +180,26 @@
|
|
|
156
180
|
color: hsl(var(--logo-wordmark-color, var(--logo-godx-color, var(--brand))));
|
|
157
181
|
}
|
|
158
182
|
}
|
|
183
|
+
|
|
184
|
+
[data-slot="logo-artwork"][data-scheme="dark"] {
|
|
185
|
+
display: none;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@media (prefers-color-scheme: dark) {
|
|
189
|
+
:root:not([data-theme="light"]) [data-slot="logo-artwork"][data-scheme="light"] {
|
|
190
|
+
display: none;
|
|
191
|
+
}
|
|
192
|
+
:root:not([data-theme="light"]) [data-slot="logo-artwork"][data-scheme="dark"] {
|
|
193
|
+
display: block;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.dark [data-slot="logo-artwork"][data-scheme="light"],
|
|
198
|
+
:root[data-theme="dark"] [data-slot="logo-artwork"][data-scheme="light"] {
|
|
199
|
+
display: none;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.dark [data-slot="logo-artwork"][data-scheme="dark"],
|
|
203
|
+
:root[data-theme="dark"] [data-slot="logo-artwork"][data-scheme="dark"] {
|
|
204
|
+
display: block;
|
|
205
|
+
}
|
|
@@ -2239,6 +2239,11 @@
|
|
|
2239
2239
|
}
|
|
2240
2240
|
|
|
2241
2241
|
@media (max-width: 768px) {
|
|
2242
|
+
|
|
2243
|
+
.ui-topbar-item {
|
|
2244
|
+
padding-inline: var(--topbar-item-padding-inline-compact);
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2242
2247
|
.tb-chip-sep,
|
|
2243
2248
|
.tb-search .kbd,
|
|
2244
2249
|
|
|
@@ -2250,8 +2255,12 @@
|
|
|
2250
2255
|
width: auto;
|
|
2251
2256
|
|
|
2252
2257
|
flex: 0 0 auto;
|
|
2253
|
-
min-inline-size: var(--control-height);
|
|
2254
|
-
min-width: var(--control-height);
|
|
2258
|
+
min-inline-size: var(--control-height-sm);
|
|
2259
|
+
min-width: var(--control-height-sm);
|
|
2260
|
+
inline-size: var(--control-height-sm);
|
|
2261
|
+
block-size: var(--control-height-sm);
|
|
2262
|
+
justify-content: center;
|
|
2263
|
+
padding-inline: 0;
|
|
2255
2264
|
}
|
|
2256
2265
|
|
|
2257
2266
|
.tb-search span {
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
--logo-success-foreground: initial;
|
|
15
15
|
--logo-godx-color: initial;
|
|
16
16
|
|
|
17
|
-
--logo-identity-foreground:
|
|
17
|
+
--logo-identity-foreground: 60 33% 99%;
|
|
18
|
+
|
|
19
|
+
--logo-godx-ink-color: 235 68.6% 13.7%;
|
|
18
20
|
|
|
19
21
|
--logo-glyph-cap-baseline-optical-offset: -0.01em;
|
|
20
22
|
--logo-glyph-cap-descender-optical-offset: -0.09em;
|
|
@@ -45,3 +47,10 @@
|
|
|
45
47
|
--logo-wordmark-font-family: initial;
|
|
46
48
|
--logo-wordmark-color: initial;
|
|
47
49
|
}
|
|
50
|
+
|
|
51
|
+
.dark,
|
|
52
|
+
:root[data-theme="dark"] {
|
|
53
|
+
--logo-identity-foreground: 48 9% 9%;
|
|
54
|
+
|
|
55
|
+
--logo-godx-ink-color: 140 23.1% 97.5%;
|
|
56
|
+
}
|
|
@@ -101,6 +101,8 @@
|
|
|
101
101
|
--topbar-center-compact-display: none;
|
|
102
102
|
|
|
103
103
|
--topbar-item-padding-inline: var(--space-3);
|
|
104
|
+
|
|
105
|
+
--topbar-item-padding-inline-compact: var(--space-2);
|
|
104
106
|
--topbar-item-gap: var(--space-2);
|
|
105
107
|
--topbar-item-min-width: var(--control-height);
|
|
106
108
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
--popover: 60 33% 99%;
|
|
10
10
|
--popover-foreground: 48 8% 13%;
|
|
11
11
|
|
|
12
|
-
--primary:
|
|
12
|
+
--primary: 268.7 100% 50%;
|
|
13
13
|
--primary-foreground: 60 33% 99%;
|
|
14
14
|
--secondary: 45 15% 95%;
|
|
15
15
|
--secondary-foreground: 48 8% 13%;
|
|
@@ -34,15 +34,15 @@
|
|
|
34
34
|
--attention: 25 99% 46%;
|
|
35
35
|
--attention-foreground: 60 33% 99%;
|
|
36
36
|
|
|
37
|
-
--brand:
|
|
37
|
+
--brand: 268.7 100% 50%;
|
|
38
38
|
--brand-foreground: 60 33% 99%;
|
|
39
39
|
|
|
40
40
|
--text-tertiary: 44 5% 55%;
|
|
41
41
|
--text-disabled: 40 6% 68%;
|
|
42
42
|
--text-link: 204 100% 39%;
|
|
43
|
-
--text-brand:
|
|
43
|
+
--text-brand: 268.3 100% 41.6%;
|
|
44
44
|
|
|
45
|
-
--text-primary:
|
|
45
|
+
--text-primary: 268 100% 34.5%;
|
|
46
46
|
--text-success: 152 84% 22%;
|
|
47
47
|
--text-warning: 36 100% 28%;
|
|
48
48
|
--text-info: 221 70% 38%;
|
|
@@ -321,7 +321,7 @@
|
|
|
321
321
|
--card-foreground: 60 20% 96%;
|
|
322
322
|
--popover: 48 8% 12%;
|
|
323
323
|
--popover-foreground: 60 20% 96%;
|
|
324
|
-
--primary:
|
|
324
|
+
--primary: 268.7 100% 86.9%;
|
|
325
325
|
--primary-foreground: 48 9% 9%;
|
|
326
326
|
--secondary: 45 6% 18%;
|
|
327
327
|
--secondary-foreground: 60 20% 96%;
|
|
@@ -346,15 +346,15 @@
|
|
|
346
346
|
--attention: 25 95% 56%;
|
|
347
347
|
--attention-foreground: 48 9% 9%;
|
|
348
348
|
|
|
349
|
-
--brand:
|
|
349
|
+
--brand: 268.7 100% 86.9%;
|
|
350
350
|
--brand-foreground: 48 9% 9%;
|
|
351
351
|
|
|
352
352
|
--text-tertiary: 44 6% 56%;
|
|
353
353
|
--text-disabled: 45 6% 40%;
|
|
354
354
|
--text-link: 204 90% 66%;
|
|
355
|
-
--text-brand:
|
|
355
|
+
--text-brand: 268.7 100% 86.9%;
|
|
356
356
|
|
|
357
|
-
--text-primary:
|
|
357
|
+
--text-primary: 262.7 100% 92.7%;
|
|
358
358
|
--text-success: 146 55% 64%;
|
|
359
359
|
--text-warning: 44 95% 62%;
|
|
360
360
|
--text-info: 221 70% 72%;
|
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -122,10 +122,30 @@ pnpm test # FULL suite — CI only, never from an agent loop
|
|
|
122
122
|
pnpm preview:build # integration test: examples + docs must build — at most once, pre-PR
|
|
123
123
|
pnpm audit # godxjp-ui-audit — 0 errors for touched files
|
|
124
124
|
pnpm check:mcp-sync # MCP registry ↔ library export drift guard
|
|
125
|
+
pnpm check:frame-axe # WCAG 2.2 AA over every frame — see FRAME-A11Y-CI.md
|
|
125
126
|
```
|
|
126
127
|
|
|
127
128
|
`pnpm verify` and `pnpm verify:release` run these together (verify:release also builds) — **both include the full suite, so both belong to CI.** Locally, run them at most once immediately before opening a PR, never inside an edit loop and never while other agents are working on the same machine. It needs `pnpm exec playwright install chromium` once locally; see [FRAME-A11Y-CI.md](./FRAME-A11Y-CI.md) for how to run/scope it, read the evidence, and regenerate its baseline after an accessibility fix.
|
|
128
129
|
|
|
130
|
+
### Reproducing one screen at one width — the frame routes
|
|
131
|
+
|
|
132
|
+
Three gates and every bug report start here, so the addressing is written down rather than guessed
|
|
133
|
+
(godx-jp/id#639 burned three attempts on `?frame=…`, which is not a thing):
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
pnpm preview # :6008
|
|
137
|
+
http://localhost:6008/isolate/<id> # the demo ALONE, at the real viewport — measure here
|
|
138
|
+
http://localhost:6008/frame/<id> # the same demo inside the device-preset chrome
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`<id>` is the demo's path under `docs/`, minus `.tsx`, with `/` turned into `-`:
|
|
142
|
+
`docs/layout/topbar.tsx` → `layout-topbar`, `docs/data-entry/date-picker.tsx` → `data-entry-date-picker`.
|
|
143
|
+
A file may override it with a `slug` in its frontmatter. Both routes accept
|
|
144
|
+
`?dir=rtl&density=compact&theme=dark&locale=ja`; `/frame/**` additionally takes `?preset=`/`?w=`/`?h=`/`?zoom=`.
|
|
145
|
+
|
|
146
|
+
For an axe measurement at a given width, drive `/isolate/<id>` with Playwright at that viewport —
|
|
147
|
+
that is what `scripts/topbar-collision-visual.mjs` and the other `test:visual:*` gates do.
|
|
148
|
+
|
|
129
149
|
All gates are **self-contained** — no internal/external tooling package required. The eslint, prettier, and vitest setup live in the package (`eslint.config.js`, `prettier.config.mjs`, `vitest.config.ts`, `src/test/`), so a fresh checkout can lint/type-check/test without anything beyond the declared devDependencies.
|
|
130
150
|
|
|
131
151
|
The app side additionally runs **`npm run ui:audit`** (the design-system linter) and must report 0 errors for touched files.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Per-frame accessibility CI — `check:frame-axe`
|
|
2
|
+
|
|
3
|
+
One ruler, run in the repository that owns the CSS.
|
|
4
|
+
|
|
5
|
+
## Why it exists (gh#643)
|
|
6
|
+
|
|
7
|
+
`scripts/visual-audit.mjs` carries **eight** rules. A consumer's nightly runs `@axe-core/playwright`
|
|
8
|
+
with **68**. Six of our eight are design-language opinions with no axe equivalent —
|
|
9
|
+
`oversaturated-accent`, `sibling-card-gap`, `row-content-starved`, `emoji-rendered`,
|
|
10
|
+
`alert-controls-misplaced`, `css-layers-missing` — and a design system **should** own those. The
|
|
11
|
+
other sixty (names, roles, `aria-*`, contrast, focus order, target size) were checked **nowhere in
|
|
12
|
+
this repository**, and only in a consumer that cannot fix the CSS, because the CSS is here.
|
|
13
|
+
|
|
14
|
+
gh#639 is what that costs. A topbar shipped; every gate here said green; `target-size` failed in
|
|
15
|
+
`godx-jp/id`'s nightly at 320px. And our own `target-size-min` could not have caught it at any
|
|
16
|
+
threshold — it measures a **painted box**, and that failure was an **obscured** target (axe:
|
|
17
|
+
`partiallyObscured`, 8×28). Two rulers, and the disagreement only ever surfaces downstream.
|
|
18
|
+
|
|
19
|
+
## What it does
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm check:frame-axe # every frame, 3 viewports
|
|
23
|
+
pnpm check:frame-axe -- --update # rewrite the baseline
|
|
24
|
+
pnpm check:frame-axe -- --scope=showcase # the 30 whole-page frames only, 30s
|
|
25
|
+
pnpm check:frame-axe -- /isolate/layout-topbar # one route, while fixing
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
| | |
|
|
29
|
+
| --------- | --------------------------------------------------------------------------------- |
|
|
30
|
+
| tool | `@axe-core/playwright` |
|
|
31
|
+
| tags | `wcag2a` · `wcag2aa` · `wcag21aa` · `wcag22aa` — **the consumer's set, verbatim** |
|
|
32
|
+
| routes | every `/isolate/<id>` in `window.__STORY_MANIFEST__` + every `/showcase/<id>` |
|
|
33
|
+
| viewports | 1440×900 · 375×667 · **320×568** |
|
|
34
|
+
|
|
35
|
+
320 is not decoration: it is WCAG 2.2 SC 1.4.10's reflow width, it is the width the consumer's
|
|
36
|
+
nightly runs, and it is the width gh#639 failed at while 390 passed.
|
|
37
|
+
|
|
38
|
+
Showcases are included on purpose. They are the only frames here shaped like a real screen — a whole
|
|
39
|
+
page, a landmark tree, a focus order — which is precisely the class the component frames cannot
|
|
40
|
+
reach and the consumer has been carrying alone.
|
|
41
|
+
|
|
42
|
+
## What it found on its first run
|
|
43
|
+
|
|
44
|
+
54 rows, **159 violation nodes**, on code that passed every other gate in this repository:
|
|
45
|
+
|
|
46
|
+
| nodes | rows | rule | what it means |
|
|
47
|
+
| ----: | ---: | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
48
|
+
| 62 | 17 | `color-contrast` | text under 4.5:1 (SC 1.4.3) |
|
|
49
|
+
| 28 | 16 | `target-size` | under 24×24 with no spacing exception (SC 2.5.8) — on `Carousel`, `Attachments`, `FilterBar` and `Toolbar`, at **every** width |
|
|
50
|
+
| 21 | 6 | `aria-prohibited-attr` | an `aria-*` on a role that does not allow it |
|
|
51
|
+
| 18 | 6 | `button-name` | **a button a screen reader announces as nothing** |
|
|
52
|
+
| 18 | 6 | `aria-valid-attr-value` | an `aria-*` pointing at an id that is not there |
|
|
53
|
+
| 12 | 3 | `aria-conditional-attr` | an `aria-*` that is invalid in the state it is in |
|
|
54
|
+
|
|
55
|
+
48 of those nodes are on `/isolate/**` — single components, this package's own output — and 111 on
|
|
56
|
+
`/showcase/**`. None of the six rules exists in `scripts/visual-audit.mjs`. The `target-size` rows
|
|
57
|
+
are the sharpest: our own `target-size-min` rule was running on those same frames and reporting them
|
|
58
|
+
clean, because it measures a painted box.
|
|
59
|
+
|
|
60
|
+
## The baseline is a debt ledger, not an allowlist
|
|
61
|
+
|
|
62
|
+
The package did not start compliant, and a gate that fails the whole build on its first day gets
|
|
63
|
+
deleted rather than obeyed. `frame-axe-baseline.json` records what was already failing when the gate
|
|
64
|
+
landed, keyed one row per `(route, viewport, rule)`:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
"/isolate/layout-topbar @320 target-size": { "count": 2, "help": "…" }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The gate fails on a key that is **not** in the baseline, and on a baselined key whose `count`
|
|
71
|
+
**grows**. A key that stops firing is reported so it can be dropped.
|
|
72
|
+
|
|
73
|
+
- **Delete rows as you fix them.** `--update` rewrites the file; the diff is the review.
|
|
74
|
+
- **Never add a row by hand to turn a red build green.** That is the one move this file exists to
|
|
75
|
+
make visible.
|
|
76
|
+
|
|
77
|
+
## What this gate does NOT do — stated, not hidden
|
|
78
|
+
|
|
79
|
+
The gate deleted in #492 did three things this one does not, and each is a real gap:
|
|
80
|
+
|
|
81
|
+
1. **No overlay scope.** It scans the frame as rendered. A menu, dialog, listbox or popover that is
|
|
82
|
+
closed at rest is never measured, so `aria-hidden-focus` and friends stay outside its field of
|
|
83
|
+
view. The old gate opened one overlay per frame from a `data-axe-open` attribute; that attribute
|
|
84
|
+
was removed from the demos along with the gate and would have to come back.
|
|
85
|
+
2. **No chrome/component split.** The old gate held the preview toolbar to zero violations and
|
|
86
|
+
allowlisted the component scope separately. `/isolate/**` renders the demo alone, so there is
|
|
87
|
+
little chrome to separate — but `/showcase/**` is scanned whole.
|
|
88
|
+
3. **No per-rule severity.** Every WCAG-tagged rule is treated alike.
|
|
89
|
+
|
|
90
|
+
## Determinism
|
|
91
|
+
|
|
92
|
+
Two consecutive sweeps of identical code first disagreed on five `color-contrast` rows: a fade-in
|
|
93
|
+
caught mid-flight renders text at partial opacity and axe scores whatever it finds. A gate that
|
|
94
|
+
disagrees with itself gets ignored, so each page is pinned before the scan —
|
|
95
|
+
`reducedMotion: "reduce"`, an injected stylesheet zeroing every animation and transition duration,
|
|
96
|
+
and `document.fonts.ready` (web fonts change glyph geometry, which changes which boxes overlap,
|
|
97
|
+
which changes what `color-contrast` resolves a background to). Two sweeps after that: identical.
|
|
98
|
+
|
|
99
|
+
## Cost
|
|
100
|
+
|
|
101
|
+
| | |
|
|
102
|
+
| ---------------------------------- | ----------------------------------------------------------------------------------- |
|
|
103
|
+
| full sweep | **3m20s** locally · **12m01s** on the self-hosted runner — 215 routes × 3 viewports |
|
|
104
|
+
| sequential | ~55 min — the three viewport passes run concurrently, which is the whole difference |
|
|
105
|
+
| showcase only (`--scope=showcase`) | 30s |
|
|
106
|
+
|
|
107
|
+
`--shard=i/n` is in the script for the day the sweep outgrows the lane. Using it adds check-run
|
|
108
|
+
names, which costs nothing here because none of them is in `REQUIRED_CI_CHECK_RUNS`.
|
|
109
|
+
|
|
110
|
+
## Where it runs
|
|
111
|
+
|
|
112
|
+
Two lanes, split on a **measurement taken on the runner, not on a laptop**:
|
|
113
|
+
|
|
114
|
+
| lane | what | when | measured |
|
|
115
|
+
| ----------------------------------------------------------------- | ----------------------------------------- | -------------------------------------------------------------- | -------------------------------------- |
|
|
116
|
+
| `ci-browser.yml` · `Per-frame axe (showcases, WCAG 2.2 AA)` | `--scope=showcase` — 30 whole-page frames | every push to `main` | 30s locally |
|
|
117
|
+
| `ci-browser-full.yml` · `Per-frame axe (all frames, WCAG 2.2 AA)` | the full 215-route sweep | nightly, `workflow_dispatch`, or a `run-browser` label on a PR | **12m01s on the pool** (3m20s locally) |
|
|
118
|
+
|
|
119
|
+
The full sweep went into the merge lane first, on the local 3m20s. On the pool's runner the same
|
|
120
|
+
job took **12m01s** — three times the local wall clock and more than twice CONTRACT.md L4's
|
|
121
|
+
five-minute budget for that whole lane. So the merge lane keeps the showcases, which are the only
|
|
122
|
+
frames here shaped like the screens a consumer ships, and the wide matrix moved to the lane this
|
|
123
|
+
repository already reserves for wide matrices.
|
|
124
|
+
|
|
125
|
+
**Not** the PR lane: that file's own header lists axe among what it deliberately excludes, at a
|
|
126
|
+
measured 653–745s, and that decision is not reopened here.
|
|
127
|
+
|
|
128
|
+
The job is not in `REQUIRED_CI_CHECK_RUNS` (#492 removed it from the release proof map and this does
|
|
129
|
+
not put it back). It still protects a release through `assertCiProvenance`'s collateral rule — **any**
|
|
130
|
+
red check run on the SHA being published refuses the publish.
|
|
131
|
+
|
|
132
|
+
## Related
|
|
133
|
+
|
|
134
|
+
- [FRAME-COVERAGE-STANDARD.md](./FRAME-COVERAGE-STANDARD.md) — which frames must exist at all.
|
|
135
|
+
- [DEVELOPMENT.md](./DEVELOPMENT.md) §5 — the `/isolate/<id>` · `/frame/<id>` addressing.
|
package/docs/layout/topbar.tsx
CHANGED
|
@@ -94,10 +94,18 @@ export default function Demo() {
|
|
|
94
94
|
>
|
|
95
95
|
{collapsed ? <PanelLeftOpen /> : <PanelLeftClose />}
|
|
96
96
|
</Button>
|
|
97
|
-
{/* Decorative mark — hidden below sm so the budget goes to the two real controls.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
{/* Decorative mark — hidden below sm so the budget goes to the two real controls. That was
|
|
98
|
+
only ever a COMMENT: nothing here hid anything, and at 320px the 32px mark was part of
|
|
99
|
+
why the switcher beside it was crushed to 0 visible px (gh#639). `hideBelow` is the
|
|
100
|
+
contract that makes the sentence true — a slot cannot shrink a control, so a bar that
|
|
101
|
+
does not fit has to drop one. */}
|
|
102
|
+
<Flex as="span" hideBelow="sm" gap="none">
|
|
103
|
+
<Avatar className="rounded-md">
|
|
104
|
+
<AvatarFallback className="bg-primary text-primary-foreground font-bold">
|
|
105
|
+
C
|
|
106
|
+
</AvatarFallback>
|
|
107
|
+
</Avatar>
|
|
108
|
+
</Flex>
|
|
101
109
|
<DropdownMenu>
|
|
102
110
|
<DropdownMenuTrigger asChild>
|
|
103
111
|
{/* Button ships `shrink-0`, and only the LAST child of the start slot gets the built-in
|
|
@@ -150,10 +158,13 @@ export default function Demo() {
|
|
|
150
158
|
// end · notifications + user menu, both consumer-composed.
|
|
151
159
|
const end = (
|
|
152
160
|
<>
|
|
153
|
-
{
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
161
|
+
{/* The environment marker is the end cluster's most optional item — 92px of a 320px bar, and
|
|
162
|
+
the single biggest reason the start cluster had nothing left. It goes first. */}
|
|
163
|
+
<Flex as="span" hideBelow="sm" gap="none">
|
|
164
|
+
<Badge tone="warning" className="text-xs">
|
|
165
|
+
ステージング
|
|
166
|
+
</Badge>
|
|
167
|
+
</Flex>
|
|
157
168
|
<TopbarItem
|
|
158
169
|
aria-label="通知"
|
|
159
170
|
badge={unread ? 12 : undefined}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@godxjp/ui",
|
|
3
|
-
"version": "
|
|
4
|
-
"godxUiMcp": "
|
|
3
|
+
"version": "24.1.0",
|
|
4
|
+
"godxUiMcp": "24.1.0",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"./styles/*": "./dist/styles/*.css",
|
|
53
53
|
"./theme/*": "./dist/theme/*",
|
|
54
54
|
"./tokens": "./dist/tokens/base.css",
|
|
55
|
-
|
|
55
|
+
"./contracts/measurement.json": "./dist/contracts/measurement.json",
|
|
56
56
|
"./admin": {
|
|
57
57
|
"types": "./dist/components/admin/index.d.ts",
|
|
58
58
|
"import": "./dist/components/admin/index.js"
|
|
@@ -322,6 +322,7 @@
|
|
|
322
322
|
"check:example-imports": "node scripts/check-example-imports.mjs",
|
|
323
323
|
"check:frame-coverage": "node scripts/frame-coverage.mjs",
|
|
324
324
|
"check:frame-coverage-report": "node scripts/frame-coverage.mjs --check",
|
|
325
|
+
"check:frame-axe": "node scripts/check-frame-axe.mjs",
|
|
325
326
|
"gen:frame-coverage-ledger": "node scripts/gen-frame-coverage-ledger.mjs",
|
|
326
327
|
"check:frame-coverage-ledger": "node scripts/gen-frame-coverage-ledger.mjs --check && node scripts/check-frame-coverage-ledger.mjs",
|
|
327
328
|
"check:screen-reader-evidence": "node scripts/check-screen-reader-evidence.mjs",
|
|
@@ -469,6 +470,7 @@
|
|
|
469
470
|
"vaul": "^1.1.2"
|
|
470
471
|
},
|
|
471
472
|
"devDependencies": {
|
|
473
|
+
"@axe-core/playwright": "^4.13.0",
|
|
472
474
|
"@eslint/js": "^10.0.1",
|
|
473
475
|
"@hookform/resolvers": "^5.9.1",
|
|
474
476
|
"@radix-ui/react-accordion": "^1.2.20",
|