@epa-wg/custom-element-dist 0.0.32 → 0.0.34
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/.claude/settings.local.json +18 -0
- package/.github/workflows/deploy.yml +59 -0
- package/.idea/copilot.data.migration.agent.xml +6 -0
- package/.idea/copilot.data.migration.ask.xml +6 -0
- package/.idea/copilot.data.migration.edit.xml +6 -0
- package/.idea/custom-element-dist.iml +2 -0
- package/.storybook/main.ts +20 -21
- package/.storybook/preview.ts +23 -25
- package/README.md +6 -4
- package/coverage/block-navigation.js +1 -1
- package/coverage/coverage-final.json +8 -18
- package/coverage/index.html +45 -30
- package/coverage/sorter.js +21 -7
- package/coverage/src/custom-element/coverage.svg +1 -1
- package/coverage/src/custom-element/custom-element.js/coverage.svg +1 -1
- package/coverage/src/custom-element/custom-element.js.html +687 -480
- package/coverage/src/custom-element/http-request.js/coverage.svg +1 -1
- package/coverage/src/custom-element/http-request.js.html +39 -18
- package/coverage/src/custom-element/index.html +35 -35
- package/coverage/src/custom-element/local-storage.js.html +1 -1
- package/coverage/src/custom-element/location-element.js.html +31 -31
- package/coverage/src/custom-element/module-url.js/coverage.svg +1 -1
- package/coverage/src/custom-element/module-url.js.html +20 -20
- package/coverage/src/index.html +1 -1
- package/coverage/src/{stories/local-storage.test.stories.ts → material/theme/colors.js}/coverage.svg +1 -1
- package/coverage/src/material/theme/colors.js.html +217 -0
- package/coverage/src/{stories/location-element.test.stories.ts → material/theme}/coverage.svg +1 -1
- package/coverage/src/material/theme/index.html +116 -0
- package/coverage/src/mocks/handlers.ts.html +1 -1
- package/coverage/src/mocks/index.html +1 -1
- package/coverage/src/stories/coverage.svg +1 -1
- package/coverage/src/stories/{external-template.test.stories.ts → frame.canvas.ts}/coverage.svg +1 -1
- package/coverage/src/stories/frame.canvas.ts.html +175 -0
- package/coverage/src/stories/http-request.stories.ts.html +1 -1
- package/coverage/src/stories/index.html +14 -179
- package/coverage/src/stories/testStoryBook.ts.html +12 -12
- package/coverage/src/sum.ts.html +1 -1
- package/dist/custom-element-BoYMoUtP.js +619 -0
- package/dist/custom-element-BqtjrCRF.cjs +97 -0
- package/dist/custom-element-bundle.cjs +1 -1
- package/dist/custom-element-bundle.js +3 -3
- package/dist/demo/a.html +10 -3
- package/dist/demo/a.svg +26 -26
- package/dist/demo/attributes.html +153 -0
- package/dist/demo/external-templates-sb-6.html +42 -0
- package/dist/demo/external-templates-sb-7.html +42 -0
- package/dist/demo/html-template.html +5 -4
- package/dist/demo/module-url-sb-2.html +46 -0
- package/dist/demo/module-url-sb-4.html +48 -0
- package/dist/demo/module-url-sb-5.html +53 -0
- package/dist/demo/s.xml +3859 -7
- package/dist/demo/s.xslt +13 -48
- package/dist/demo/s1.xml +3706 -0
- package/dist/demo/ss.html +13 -4
- package/dist/http-request-DSaowcG1.cjs +1 -0
- package/dist/{http-request-BOvP4KTl.js → http-request-DTCzZ1gc.js} +15 -9
- package/dist/mockServiceWorker.js +31 -8
- package/package.json +25 -26
- package/public/demo/a.html +10 -3
- package/public/demo/a.svg +26 -26
- package/public/demo/attributes.html +153 -0
- package/public/demo/external-templates-sb-6.html +42 -0
- package/public/demo/external-templates-sb-7.html +42 -0
- package/public/demo/html-template.html +5 -4
- package/public/demo/module-url-sb-2.html +46 -0
- package/public/demo/module-url-sb-4.html +48 -0
- package/public/demo/module-url-sb-5.html +53 -0
- package/public/demo/s.xml +3859 -7
- package/public/demo/s.xslt +13 -48
- package/public/demo/s1.xml +3706 -0
- package/public/demo/ss.html +13 -4
- package/public/mockServiceWorker.js +31 -8
- package/src/custom-element/custom-element.d.ts +4 -0
- package/src/custom-element/custom-element.js +119 -50
- package/src/custom-element/demo/a.html +10 -3
- package/src/custom-element/demo/a.svg +26 -26
- package/src/custom-element/demo/attributes.html +153 -0
- package/src/custom-element/demo/html-template.html +5 -4
- package/src/custom-element/demo/s.xml +3859 -7
- package/src/custom-element/demo/s.xslt +13 -48
- package/src/custom-element/demo/s1.xml +3706 -0
- package/src/custom-element/demo/ss.html +13 -4
- package/src/custom-element/http-request.js +7 -0
- package/src/custom-element/ide/web-types-dce.json +1 -1
- package/src/custom-element/ide/web-types-xsl.json +1 -1
- package/src/custom-element/index.html +1 -1
- package/src/material/angular.css +987 -987
- package/src/material/components/action.html +262 -0
- package/src/material/components/autocomplete.html +167 -239
- package/src/material/components/badge.html +239 -0
- package/src/material/components/dropdown.html +7 -13
- package/src/material/components/icon-link.html +160 -160
- package/src/material/components/icon.html +252 -0
- package/src/material/components/input.html +569 -362
- package/src/material/components/menu.html +235 -234
- package/src/material/components.html +157 -121
- package/src/material/demo.css +36 -36
- package/src/material/index.html +109 -110
- package/src/material/material.css +356 -356
- package/src/material/theme/Base-Principles.md +339 -0
- package/src/material/theme/README.md +298 -18
- package/src/material/theme/UI Domain Model in web applications.svg +1 -0
- package/src/material/theme/User Semantic Theme tokens.svg +1 -0
- package/src/material/theme/action-pending-poc.html +62 -0
- package/src/material/theme/actions-color.html +141 -0
- package/src/material/theme/colors-light.html +631 -0
- package/src/material/theme/colors-native.html +51 -0
- package/src/material/theme/colors-poc.html +66 -0
- package/src/material/theme/colors.html +297 -0
- package/src/material/theme/colors.js +44 -0
- package/src/material/theme/consumer-theme.css +745 -0
- package/src/material/theme/semantic.css +132 -113
- package/src/material/theme/style-bug.html +123 -0
- package/src/material/theme/theme-data.css +43 -0
- package/src/material/theme/theme-data.xhtml +2926 -0
- package/src/material/theme/todo.md +274 -0
- package/src/material/theme/tokens/action-colors.png +0 -0
- package/src/material/theme/tokens/cem-article-illustration-4x1-letterbox-2000x500.png +0 -0
- package/src/material/theme/tokens/cem-breakpoints.md +519 -0
- package/src/material/theme/tokens/cem-colors.md +715 -0
- package/src/material/theme/tokens/cem-consumerflow-typography-matrix.svg +198 -0
- package/src/material/theme/tokens/cem-coupling.md +372 -0
- package/src/material/theme/tokens/cem-data-vs-reading-numerals.svg +164 -0
- package/src/material/theme/tokens/cem-dimension.md +625 -0
- package/src/material/theme/tokens/cem-layering.md +562 -0
- package/src/material/theme/tokens/cem-m3-parity.md +343 -0
- package/src/material/theme/tokens/cem-responsive.md +238 -0
- package/src/material/theme/tokens/cem-shape.md +691 -0
- package/src/material/theme/tokens/cem-stroke-density-illustration-4to1-v3.svg +102 -0
- package/src/material/theme/tokens/cem-stroke.md +480 -0
- package/src/material/theme/tokens/cem-timing.md +198 -0
- package/src/material/theme/tokens/cem-typography-model-stack.svg +64 -0
- package/src/material/theme/tokens/cem-voice-fonts-typography.md +718 -0
- package/src/material/theme/tokens/cem-voice-ladder.svg +91 -0
- package/src/material/theme/tokens/chips.png +0 -0
- package/src/material/theme/tokens/columns-page.png +0 -0
- package/src/material/theme/tokens/initials.png +0 -0
- package/src/material/theme/tokens/nav-buttons.png +0 -0
- package/src/material/theme/tokens/script.png +0 -0
- package/src/material/theme/tokens/sufler.png +0 -0
- package/src/material/theme/tokens/typography-icons.png +0 -0
- package/src/mocks/versions.mock.ts +1 -1
- package/src/stories/__screenshots__/attributes.test.stories.ts +1 -0
- package/src/stories/__screenshots__/dom-merge.test.stories.ts/dom-merge-dom-merge-OrderPreservingOn2ndTransform-1.png +0 -0
- package/src/stories/__screenshots__/external-template.test.stories.ts +1 -0
- package/src/stories/__screenshots__/module-url.test.stories.ts +1 -0
- package/src/stories/__screenshots__/stories.test.ts/attributes-Attributes-definition-1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/attributes-Attributes-runtime-change-1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/attributes-Instance-Attributes-1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/attributes-Instance-Attributes-2.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/attributes-cloneAs-el-newTag--1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/attributes-mergeAttr--from--to---1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/attributes-mergeAttr--from--to---2.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/attributes-mergeAttr--from--to---3.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/attributes-mix-to-from--1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-Attributes-definition-1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-Attributes-runtime-change-1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-Instance-Attributes-1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-Instance-Attributes-2.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-cloneAs-el-newTag--1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-http-request-headers-and-response-status-and-headers-1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-http-request-with-delayed--5-seconds-response-1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-http-request-with-error-1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-mergeAttr--from--to---1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-mergeAttr--from--to---2.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-mergeAttr--from--to---3.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-mix-to-from--1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-url-and-slice-1.png +0 -0
- package/src/stories/__screenshots__/stories.test.ts/http-request-url-change-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-MultipleIfOrderingWorkaround-1.png +0 -0
- package/src/stories/attributes.test.stories.ts +83 -17
- package/src/stories/dom-merge.test.stories.ts +25 -1
- package/src/stories/external-template.test.stories.ts +16 -14
- package/src/stories/frame.canvas.ts +31 -0
- package/src/stories/module-url.test.stories.ts +29 -61
- package/src/stories/xslt-conditionals.test.stories.ts +492 -0
- package/src/stories/xslt-if.test.stories.ts +89 -0
- package/storybook-static/assets/Color-F6OSRLHC-CzTOSlqB.js +1 -0
- package/storybook-static/assets/Configure-7GqRsAoJ.js +165 -0
- package/storybook-static/assets/DocsRenderer-CFRXHY34-Duc5rSIm.js +2 -0
- package/storybook-static/assets/{attributes.test.stories-D1X6EBrd.js → attributes.test.stories-DYuxF8h1.js} +109 -38
- package/storybook-static/assets/{css.test.stories-Cp_g2hE1.js → css.test.stories-LOmvINyb.js} +1 -1
- package/storybook-static/assets/custom-element-Bwx7otrT.js +97 -0
- package/storybook-static/assets/{dom-merge.test.stories-hbpdCka0.js → dom-merge.test.stories-CEKhWjaS.js} +47 -6
- package/storybook-static/assets/entry-preview-BNCt9WBs.js +26 -0
- package/storybook-static/assets/entry-preview-docs-CbF8-81D.js +2 -0
- package/storybook-static/assets/{external-template.test.stories-BK89h6sk.js → external-template.test.stories-jHu0wsJ-.js} +38 -40
- package/storybook-static/assets/{form.test.stories-BfoLe_rw.js → form.test.stories-CUyUnmwP.js} +1 -1
- package/storybook-static/assets/frame.canvas-E5n9h6j1.js +1 -0
- package/storybook-static/assets/{handlers-yVPwH_Nz.js → handlers-F7GUfMqr.js} +17 -14
- package/storybook-static/assets/http-request-BWeEEBkP.js +1 -0
- package/storybook-static/assets/{http-request.stories-CBFJS2Ws.js → http-request.stories-wyX5-QOv.js} +1 -1
- package/storybook-static/assets/iframe-BS_DPWl0.js +199 -0
- package/storybook-static/assets/index-CGuyH0k-.js +240 -0
- package/storybook-static/assets/index-DB7LLObI.js +1 -0
- package/storybook-static/assets/index-DO1nmyvI.js +11 -0
- package/storybook-static/assets/index-V1EGs-wm.js +621 -0
- package/storybook-static/assets/{local-storage.test.stories-C0Yzy6Am.js → local-storage.test.stories-BxOhsf1k.js} +1 -1
- package/storybook-static/assets/{location-element.test.stories-DNFrEu5A.js → location-element.test.stories-DqhvvUoa.js} +1 -1
- package/storybook-static/assets/module-url.test.stories-C1gG9G7Y.js +142 -0
- package/storybook-static/assets/preview-1xJJ3sKE.js +1 -0
- package/storybook-static/assets/preview-Bn8igYMp.js +1 -0
- package/storybook-static/assets/preview-CTOeX_lO.js +1 -0
- package/storybook-static/assets/preview-Cwy1XFu2.js +2 -0
- package/storybook-static/assets/preview-D6sehqkw.js +50 -0
- package/storybook-static/assets/preview-DfTudP20.js +1 -0
- package/storybook-static/assets/{set-url.test.stories-BBfLxv2u.js → set-url.test.stories-BKQNdknJ.js} +1 -1
- package/storybook-static/assets/{slice-events.test.stories-HcXF8XQI.js → slice-events.test.stories-ChqULCeA.js} +1 -1
- package/storybook-static/assets/{slots.test.stories-i6mnIFM2.js → slots.test.stories-BlyLoCRe.js} +1 -1
- package/storybook-static/assets/{version-select.test.stories-BsUFH6Va.js → version-select.test.stories-CPGSh1tR.js} +1 -1
- package/storybook-static/assets/xslt-conditionals.test.stories-YC6QPqWZ.js +633 -0
- package/storybook-static/assets/xslt-if.test.stories-BRSWy2-x.js +71 -0
- package/storybook-static/demo/a.html +10 -3
- package/storybook-static/demo/a.svg +26 -26
- package/storybook-static/demo/attributes.html +153 -0
- package/storybook-static/demo/external-templates-sb-6.html +42 -0
- package/storybook-static/demo/external-templates-sb-7.html +42 -0
- package/storybook-static/demo/html-template.html +5 -4
- package/storybook-static/demo/module-url-sb-2.html +46 -0
- package/storybook-static/demo/module-url-sb-4.html +48 -0
- package/storybook-static/demo/module-url-sb-5.html +53 -0
- package/storybook-static/demo/s.xml +3859 -7
- package/storybook-static/demo/s.xslt +13 -48
- package/storybook-static/demo/s1.xml +3706 -0
- package/storybook-static/demo/ss.html +13 -4
- package/storybook-static/iframe.html +2 -2
- package/storybook-static/index.html +6 -10
- package/storybook-static/index.json +1 -1
- package/storybook-static/mockServiceWorker.js +31 -8
- package/storybook-static/project.json +1 -1
- package/storybook-static/sb-addons/essentials-actions-2/manager-bundle.js +3 -0
- package/storybook-static/sb-addons/essentials-backgrounds-4/manager-bundle.js +8 -8
- package/storybook-static/sb-addons/essentials-controls-1/manager-bundle.js +394 -0
- package/storybook-static/sb-addons/essentials-docs-3/manager-bundle.js +233 -0
- package/storybook-static/sb-addons/essentials-measure-7/manager-bundle.js +1 -1
- package/storybook-static/sb-addons/essentials-outline-8/manager-bundle.js +1 -1
- package/storybook-static/sb-addons/essentials-toolbars-6/manager-bundle.js +1 -1
- package/storybook-static/sb-addons/essentials-viewport-5/manager-bundle.js +1 -1
- package/storybook-static/sb-addons/interactions-9/manager-bundle.js +58 -58
- package/storybook-static/sb-manager/globals-module-info.js +9 -0
- package/storybook-static/sb-manager/globals-runtime.js +10719 -10473
- package/storybook-static/sb-manager/runtime.js +4944 -6321
- package/coverage/src/stories/attributes.test.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/attributes.test.stories.ts.html +0 -814
- package/coverage/src/stories/css.test.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/css.test.stories.ts.html +0 -460
- package/coverage/src/stories/dom-merge.test.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/dom-merge.test.stories.ts.html +0 -706
- package/coverage/src/stories/external-template.test.stories.ts.html +0 -865
- package/coverage/src/stories/form.test.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/form.test.stories.ts.html +0 -661
- package/coverage/src/stories/local-storage.test.stories.ts.html +0 -1315
- package/coverage/src/stories/location-element.test.stories.ts.html +0 -523
- package/coverage/src/stories/module-url.test.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/module-url.test.stories.ts.html +0 -640
- package/coverage/src/stories/set-url.test.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/set-url.test.stories.ts.html +0 -433
- package/coverage/src/stories/slice-events.test.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/slice-events.test.stories.ts.html +0 -952
- package/coverage/src/stories/slots.test.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/slots.test.stories.ts.html +0 -742
- package/coverage/src/stories/version-select.test.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/version-select.test.stories.ts.html +0 -397
- package/dist/custom-element-D2wf_rqP.js +0 -576
- package/dist/custom-element-Dtzhbjkc.cjs +0 -97
- package/dist/http-request-DPrY7mGh.cjs +0 -1
- package/storybook-static/assets/Color-F6OSRLHC-BU3iy8jH.js +0 -1
- package/storybook-static/assets/Configure-DN6ifayP.js +0 -165
- package/storybook-static/assets/DocsRenderer-CFRXHY34-BaVEufDj.js +0 -2
- package/storybook-static/assets/custom-element-uuAtIYWS.js +0 -97
- package/storybook-static/assets/entry-preview-DHVXbf3x.js +0 -26
- package/storybook-static/assets/entry-preview-docs-BbcIMweR.js +0 -2
- package/storybook-static/assets/http-request-DNq59pnj.js +0 -1
- package/storybook-static/assets/iframe-CJEL_4Nu.js +0 -2
- package/storybook-static/assets/index-BcZLpTeD.js +0 -8
- package/storybook-static/assets/index-CxRwF5Or.js +0 -234
- package/storybook-static/assets/index-D-8MO0q_.js +0 -1
- package/storybook-static/assets/index-D5fBh-7N.js +0 -1
- package/storybook-static/assets/index-DM-KBPdl.js +0 -1
- package/storybook-static/assets/index-RSFf30w1.js +0 -1
- package/storybook-static/assets/index-SnjB5uV8.js +0 -769
- package/storybook-static/assets/module-url.test.stories-CXibF5Ta.js +0 -208
- package/storybook-static/assets/preview-BhhEZcNS.js +0 -1
- package/storybook-static/assets/preview-Bnd0XhaF.js +0 -52
- package/storybook-static/assets/preview-CNKoaWES.js +0 -1
- package/storybook-static/assets/preview-DAeyCMnM.js +0 -1
- package/storybook-static/assets/preview-DHPc-V4N.js +0 -1
- package/storybook-static/assets/preview-DJMlNTk8.js +0 -2
- package/storybook-static/assets/preview-DYzi3Z2p.js +0 -1
- package/storybook-static/sb-addons/chromatic-com-storybook-10/manager-bundle.js +0 -333
- package/storybook-static/sb-addons/chromatic-com-storybook-10/manager-bundle.js.LEGAL.txt +0 -40
- package/storybook-static/sb-addons/essentials-actions-3/manager-bundle.js +0 -3
- package/storybook-static/sb-addons/essentials-controls-2/manager-bundle.js +0 -391
- package/storybook-static/sb-addons/links-1/manager-bundle.js +0 -3
- package/storybook-static/sb-preview/globals.js +0 -33
- package/storybook-static/sb-preview/runtime.js +0 -7174
- package/test-runner-jest.config.js +0 -15
- /package/storybook-static/sb-addons/{essentials-actions-3 → essentials-actions-2}/manager-bundle.js.LEGAL.txt +0 -0
- /package/storybook-static/sb-addons/{essentials-controls-2 → essentials-controls-1}/manager-bundle.js.LEGAL.txt +0 -0
- /package/storybook-static/sb-addons/{links-1 → essentials-docs-3}/manager-bundle.js.LEGAL.txt +0 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="3200" height="800" viewBox="0 0 3200 800">
|
|
3
|
+
|
|
4
|
+
<defs>
|
|
5
|
+
<filter id="shadow" x="-20%" y="-20%" width="140%" height="160%">
|
|
6
|
+
<feOffset dx="0" dy="10" result="off"/>
|
|
7
|
+
<feGaussianBlur in="off" stdDeviation="10" result="blur"/>
|
|
8
|
+
<feColorMatrix in="blur" type="matrix"
|
|
9
|
+
values="0 0 0 0 0
|
|
10
|
+
0 0 0 0 0
|
|
11
|
+
0 0 0 0 0
|
|
12
|
+
0 0 0 0.22 0" result="shadow"/>
|
|
13
|
+
<feBlend in="shadow" in2="SourceGraphic" mode="normal"/>
|
|
14
|
+
</filter>
|
|
15
|
+
<style>
|
|
16
|
+
.title { font: 700 54px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: black; }
|
|
17
|
+
.banner { font: 400 30px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: #13539b; }
|
|
18
|
+
.label { font: 700 30px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: #141416; }
|
|
19
|
+
.sub { font: 400 24px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: #4b4b52; }
|
|
20
|
+
.ui { font: 400 30px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: #141416; }
|
|
21
|
+
.ui-bold { font: 700 30px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: #141416; }
|
|
22
|
+
.small { font: 400 24px system-ui, -apple-system, Segoe UI, Arial, sans-serif; fill: #4b4b52; }
|
|
23
|
+
</style>
|
|
24
|
+
</defs>
|
|
25
|
+
|
|
26
|
+
<rect x="0" y="0" width="3200" height="800" fill="#ffffff"/>
|
|
27
|
+
<rect x="60" y="28" width="3080" height="78" rx="24" fill="#e8f1fc"/>
|
|
28
|
+
<text x="95" y="80" class="banner">Dense UI may need stronger strokes; Comfort UI can rely on whitespace for separation.</text>
|
|
29
|
+
<text x="1600.0" y="164" text-anchor="middle" class="title">Stroke thickness varies by density mode (semantics unchanged)</text>
|
|
30
|
+
<g filter="url(#shadow)"><rect x="90" y="216" width="1475" height="494" rx="32" fill="#ffffff"/></g>
|
|
31
|
+
<g filter="url(#shadow)"><rect x="1635" y="216" width="1475" height="494" rx="32" fill="#ffffff"/></g>
|
|
32
|
+
<text x="130" y="278" class="label">DENSE</text>
|
|
33
|
+
<text x="160" y="316" class="sub">Ink carries more of the separation load</text>
|
|
34
|
+
<text x="1675" y="278" class="label">COMFORT</text>
|
|
35
|
+
<text x="1698" y="316" class="sub">Space carries more of the separation load</text>
|
|
36
|
+
<rect x="130" y="336" width="1395" height="360" rx="28" fill="#f5f6f8" stroke="#37373c" stroke-width="5"/>
|
|
37
|
+
<rect x="135" y="341" width="1385" height="86" rx="22" fill="#ffffff"/>
|
|
38
|
+
<circle cx="173" cy="384.0" r="16" fill="#d2d4da" stroke="#5f5f66" stroke-width="1"/>
|
|
39
|
+
<text x="203" y="385" class="ui-bold">Settings</text>
|
|
40
|
+
<rect x="1388" y="366.0" width="110" height="36" rx="18" fill="#ebecf0" stroke="#8c8e94" stroke-width="1"/>
|
|
41
|
+
<circle cx="1480.0" cy="384.0" r="18.0" fill="#ffffff" stroke="#8c8e94" stroke-width="1"/>
|
|
42
|
+
<rect x="135" y="443" width="1385" height="78" fill="#ffffff"/>
|
|
43
|
+
<rect x="157" y="464.0" width="36" height="36" rx="6" fill="#ffffff" stroke="#787a80" stroke-width="2"/>
|
|
44
|
+
<text x="211" y="481" class="ui-bold">Option 1</text>
|
|
45
|
+
<text x="211" y="515" class="small">Supporting detail</text>
|
|
46
|
+
<line x1="1470" y1="474.0" x2="1478" y2="482.0" stroke="#787a80" stroke-width="3" stroke-linecap="round"/>
|
|
47
|
+
<line x1="1470" y1="490.0" x2="1478" y2="482.0" stroke="#787a80" stroke-width="3" stroke-linecap="round"/>
|
|
48
|
+
<line x1="135" y1="521" x2="1520" y2="521" stroke="#46484e" stroke-width="4" stroke-linecap="round"/>
|
|
49
|
+
<rect x="135" y="521" width="1385" height="78" fill="#fafbfd"/>
|
|
50
|
+
<rect x="157" y="542.0" width="36" height="36" rx="6" fill="#ffffff" stroke="#787a80" stroke-width="2"/>
|
|
51
|
+
<line x1="165" y1="560.0" x2="173" y2="570.0" stroke="#46484e" stroke-width="3" stroke-linecap="round"/>
|
|
52
|
+
<line x1="173" y1="570.0" x2="187" y2="550.0" stroke="#46484e" stroke-width="3" stroke-linecap="round"/>
|
|
53
|
+
<text x="211" y="559" class="ui">Option 2</text>
|
|
54
|
+
<text x="211" y="593" class="small">Supporting detail</text>
|
|
55
|
+
<line x1="1470" y1="552.0" x2="1478" y2="560.0" stroke="#787a80" stroke-width="3" stroke-linecap="round"/>
|
|
56
|
+
<line x1="1470" y1="568.0" x2="1478" y2="560.0" stroke="#787a80" stroke-width="3" stroke-linecap="round"/>
|
|
57
|
+
<line x1="135" y1="599" x2="1520" y2="599" stroke="#46484e" stroke-width="4" stroke-linecap="round"/>
|
|
58
|
+
<rect x="135" y="599" width="1385" height="78" fill="#ffffff"/>
|
|
59
|
+
<rect x="157" y="620.0" width="36" height="36" rx="6" fill="#ffffff" stroke="#787a80" stroke-width="2"/>
|
|
60
|
+
<text x="211" y="637" class="ui">Option 3</text>
|
|
61
|
+
<text x="211" y="671" class="small">Supporting detail</text>
|
|
62
|
+
<line x1="1470" y1="630.0" x2="1478" y2="638.0" stroke="#787a80" stroke-width="3" stroke-linecap="round"/>
|
|
63
|
+
<line x1="1470" y1="646.0" x2="1478" y2="638.0" stroke="#787a80" stroke-width="3" stroke-linecap="round"/>
|
|
64
|
+
<line x1="135" y1="677" x2="1520" y2="677" stroke="#46484e" stroke-width="2" stroke-linecap="round"/>
|
|
65
|
+
|
|
66
|
+
<line x1="152" y1="596" x2="392" y2="596" stroke="#28282d" stroke-width="4" stroke-linecap="round"/>
|
|
67
|
+
<text x="412" y="596" class="small" style="fill:#141416;">4px separator</text>
|
|
68
|
+
<rect x="1675" y="336" width="1395" height="360" rx="28" fill="#f5f6f8" stroke="#37373c" stroke-width="2"/>
|
|
69
|
+
<rect x="1677" y="338" width="1391" height="104" rx="22" fill="#ffffff"/>
|
|
70
|
+
<circle cx="1725" cy="390.0" r="18" fill="#d2d4da" stroke="#5f5f66" stroke-width="1"/>
|
|
71
|
+
<text x="1757" y="392" class="ui-bold">Settings</text>
|
|
72
|
+
<rect x="2928" y="372.0" width="110" height="36" rx="18" fill="#ebecf0" stroke="#8c8e94" stroke-width="1"/>
|
|
73
|
+
<circle cx="3020.0" cy="390.0" r="18.0" fill="#ffffff" stroke="#8c8e94" stroke-width="1"/>
|
|
74
|
+
<rect x="1677" y="464" width="1391" height="105" fill="#ffffff"/>
|
|
75
|
+
<rect x="1707" y="496.5" width="40" height="40" rx="6" fill="#ffffff" stroke="#787a80" stroke-width="1"/>
|
|
76
|
+
<text x="1765" y="512" class="ui-bold">Option 1</text>
|
|
77
|
+
<text x="1765" y="546" class="small">Supporting detail</text>
|
|
78
|
+
<line x1="3010" y1="508.5" x2="3018" y2="516.5" stroke="#787a80" stroke-width="2" stroke-linecap="round"/>
|
|
79
|
+
<line x1="3010" y1="524.5" x2="3018" y2="516.5" stroke="#787a80" stroke-width="2" stroke-linecap="round"/>
|
|
80
|
+
<line x1="1677" y1="569" x2="3068" y2="569" stroke="#96989e" stroke-width="1" stroke-linecap="round"/>
|
|
81
|
+
<rect x="1677" y="569" width="1391" height="105" fill="#fafbfd"/>
|
|
82
|
+
<rect x="1707" y="601.5" width="40" height="40" rx="6" fill="#ffffff" stroke="#787a80" stroke-width="1"/>
|
|
83
|
+
<line x1="1715" y1="621.5" x2="1725" y2="633.5" stroke="#46484e" stroke-width="2" stroke-linecap="round"/>
|
|
84
|
+
<line x1="1725" y1="633.5" x2="1741" y2="609.5" stroke="#46484e" stroke-width="2" stroke-linecap="round"/>
|
|
85
|
+
<text x="1765" y="617" class="ui">Option 2</text>
|
|
86
|
+
<text x="1765" y="651" class="small">Supporting detail</text>
|
|
87
|
+
<line x1="3010" y1="613.5" x2="3018" y2="621.5" stroke="#787a80" stroke-width="2" stroke-linecap="round"/>
|
|
88
|
+
<line x1="3010" y1="629.5" x2="3018" y2="621.5" stroke="#787a80" stroke-width="2" stroke-linecap="round"/>
|
|
89
|
+
<line x1="1677" y1="674" x2="3068" y2="674" stroke="#96989e" stroke-width="1" stroke-linecap="round"/>
|
|
90
|
+
<rect x="1707" y="811.5" width="40" height="40" rx="6" fill="#ffffff" stroke="#787a80" stroke-width="1"/>
|
|
91
|
+
<line x1="1705" y1="570" x2="1945" y2="570" stroke="#28282d" stroke-width="1" stroke-linecap="round"/>
|
|
92
|
+
<text x="1965" y="572" class="small" style="fill:#141416;">1px separator</text>
|
|
93
|
+
<text x="760.0" y="240" class="small" >Density mode</text>
|
|
94
|
+
<line x1="680.0" y1="278" x2="920.0" y2="278" stroke="#a0a2a8" stroke-width="6" stroke-linecap="round"/>
|
|
95
|
+
<line x1="680.0" y1="266" x2="680.0" y2="290" stroke="#a0a2a8" stroke-width="4" stroke-linecap="round"/>
|
|
96
|
+
<line x1="800.0" y1="266" x2="800.0" y2="290" stroke="#a0a2a8" stroke-width="4" stroke-linecap="round"/>
|
|
97
|
+
<line x1="920.0" y1="266" x2="920.0" y2="290" stroke="#a0a2a8" stroke-width="4" stroke-linecap="round"/>
|
|
98
|
+
<circle cx="730.0" cy="278" r="20" fill="#ffffff" stroke="#46484e" stroke-width="4"/>
|
|
99
|
+
<text x="674.0" y="328" class="small">Dense</text>
|
|
100
|
+
<text x="834.0" y="328" class="small">Comfort</text>
|
|
101
|
+
<text x="1600.0" y="770" text-anchor="middle" class="small">Non-breaking adjustment: tune stroke thickness per density mode; preserve semantic meaning of boundaries.</text>
|
|
102
|
+
</svg>
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
# CEM D5 Stroke & Separation — Boundaries, Dividers, and Focus Indicators
|
|
2
|
+
|
|
3
|
+
**Status:** Proposed (canonical CEM spec)
|
|
4
|
+
**Last updated:** December 19, 2025
|
|
5
|
+
|
|
6
|
+
**Taxonomy placement:** D5. Stroke & Separation (part of the 7-dimensional CEM token framework)
|
|
7
|
+
|
|
8
|
+
**Companion specs:**
|
|
9
|
+
- **D0. Color (Emotional Palette & System Color Mapping)** ([`cem-colors.md`](./cem-colors.md)) — defines separator/focus colors; D5 defines *thickness and geometry*
|
|
10
|
+
- **D1. Space & Rhythm** ([`cem-dimension.md`](./cem-dimension.md)) — inset/spacing rules that keep strokes readable without crowding
|
|
11
|
+
- **D2. Coupling & Compactness** ([`cem-coupling.md`](./cem-coupling.md)) — density modes that affect when thin strokes must become stronger
|
|
12
|
+
- **D3. Shape — Bend** ([`cem-shape.md`](./cem-shape.md)) — corner radii and rounding rules that strokes must follow
|
|
13
|
+
- **D4. Layering** ([`cem-layering.md`](./cem-layering.md)) — when to prefer shadow separation vs stroke separation
|
|
14
|
+
- **D7. Time & Motion** ([`cem-timing.md`](./cem-timing.md)) — animation timing for focus/selection transitions
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Contents
|
|
19
|
+
|
|
20
|
+
1. [What D5 controls](#1-what-d5-controls)
|
|
21
|
+
2. [Design goals](#2-design-goals)
|
|
22
|
+
3. [Minimal stroke basis](#3-minimal-stroke-basis)
|
|
23
|
+
4. [Semantic endpoints (product-facing contract)](#4-semantic-endpoints-product-facing-contract)
|
|
24
|
+
5. [Focus, selected, and target indicators](#5-focus-selected-and-target-indicators)
|
|
25
|
+
6. [Dividers and separators](#6-dividers-and-separators)
|
|
26
|
+
7. [Inter-dimension coupling](#7-inter-dimension-coupling)
|
|
27
|
+
8. [Accessibility and forced-colors requirements](#8-accessibility-and-forced-colors-requirements)
|
|
28
|
+
9. [Implementation guidance (CSS recipes)](#9-implementation-guidance-css-recipes)
|
|
29
|
+
10. [Framework mapping guidance (Angular Material, MUI)](#10-framework-mapping-guidance-angular-material-mui)
|
|
30
|
+
11. [Canonical token summary](#11-canonical-token-summary)
|
|
31
|
+
12. [Governance and versioning](#12-governance-and-versioning)
|
|
32
|
+
13. [References](#13-references)
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 1. What D5 controls
|
|
37
|
+
|
|
38
|
+
D5 defines the **geometry of separation**:
|
|
39
|
+
|
|
40
|
+
- **Stroke thickness**: borders, hairlines, dividers, gridlines, outlines.
|
|
41
|
+
- **Indicator geometry**: focus rings, selection rings, target indicators (including patterned outlines such as zebra).
|
|
42
|
+
- **Stroke placement**: whether an indicator is *inside* the component, *on the edge*, or *outside* the component.
|
|
43
|
+
|
|
44
|
+
D5 **does not** define:
|
|
45
|
+
- **Colors** (D0 defines `Canvas`, `CanvasText`, `SelectedItem`, emotional palettes, etc.).
|
|
46
|
+
- **Spacing and inset** (D1).
|
|
47
|
+
- **Component height or density rules** (D2).
|
|
48
|
+
- **Corner rounding** (D3).
|
|
49
|
+
- **Motion curves and timing** (D7).
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 2. Design goals
|
|
54
|
+
|
|
55
|
+
### 2.1 Consumer semantics first
|
|
56
|
+
|
|
57
|
+
Tokens must express *what the stroke means to the consumer*, not how it is implemented:
|
|
58
|
+
|
|
59
|
+
- “boundary” vs “divider” vs “focus indicator” vs “selection indicator”
|
|
60
|
+
- not “mdc notched-outline width” or “outlined input border width”
|
|
61
|
+
|
|
62
|
+
### 2.2 Bounded complexity
|
|
63
|
+
|
|
64
|
+
Stroke systems can explode into per-component and per-state width tokens. CEM avoids that by defining:
|
|
65
|
+
|
|
66
|
+
- a **small width basis** (few values)
|
|
67
|
+
- a **small set of semantic endpoints**
|
|
68
|
+
- and **mapping guidance** for frameworks that expose many internal variables.
|
|
69
|
+
|
|
70
|
+
### 2.3 No layout shift on interaction
|
|
71
|
+
|
|
72
|
+
Changing border width on focus is a common source of **layout shift** (e.g., label jumps in outlined text fields). Focus and selection indicators should be drawn using **outline** or **box-shadow**, or on a pseudo-element, rather than changing border-box geometry.
|
|
73
|
+
|
|
74
|
+
### 2.4 Accessibility as a hard constraint
|
|
75
|
+
|
|
76
|
+
D5 must support modern focus-indicator requirements (including minimum visible area/thickness and sufficient contrast in high-contrast themes). See §8.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 3. Minimal stroke basis
|
|
81
|
+
|
|
82
|
+
CEM D5 uses a **4-step stroke basis** that covers almost all UI needs without a large token surface.
|
|
83
|
+
|
|
84
|
+
### 3.1 Stroke basis tokens
|
|
85
|
+
|
|
86
|
+
> These tokens are *foundational*. Semantic endpoints map to them.
|
|
87
|
+
|
|
88
|
+
```css
|
|
89
|
+
:root {
|
|
90
|
+
/* Basis: keep small and stable */
|
|
91
|
+
--cem-stroke-none: 0px; /* no stroke */
|
|
92
|
+
--cem-stroke-hair: 1px; /* hairline separators, subtle boundaries */
|
|
93
|
+
--cem-stroke-standard: 2px; /* focus/selection indicators; high legibility */
|
|
94
|
+
--cem-stroke-strong: 3px; /* high-emphasis boundaries; contrast themes */
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Notes**
|
|
99
|
+
- `1px` remains device-independent (CSS px), and is appropriate for dividers and subtle component boundaries.
|
|
100
|
+
- `2px` is the default for **focus visibility** and state distinction.
|
|
101
|
+
- `3px` exists primarily for **high contrast** and “hard separation” contexts.
|
|
102
|
+
|
|
103
|
+
- Material Design component specs frequently use 1–2dp stroke thickness for outlines and focus indicators; in web CEM this maps cleanly onto `1px` hairlines and `2px` indicators (see References for representative component spec links and issue discussions).
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
### 3.2 Density coupling (D2 interaction)
|
|
107
|
+
|
|
108
|
+
Stroke thickness is allowed to vary *by density mode* as a **non-breaking** adjustment, as long as semantics stay intact:
|
|
109
|
+
|
|
110
|
+
- Dense UI may need **stronger strokes** because small targets and reduced whitespace reduce separability.
|
|
111
|
+
- Comfort UI can remain at hairline boundaries in more places because whitespace carries part of the separation work.
|
|
112
|
+

|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 4. Semantic endpoints (product-facing contract)
|
|
116
|
+
|
|
117
|
+
These are the **canonical semantic endpoints** that components consume.
|
|
118
|
+
|
|
119
|
+
### 4.1 Endpoints
|
|
120
|
+
|
|
121
|
+
```css
|
|
122
|
+
:root {
|
|
123
|
+
/* Canonical boundaries */
|
|
124
|
+
--cem-stroke-boundary: var(--cem-stroke-hair);
|
|
125
|
+
|
|
126
|
+
/* Canonical separators */
|
|
127
|
+
--cem-stroke-divider: var(--cem-stroke-hair);
|
|
128
|
+
|
|
129
|
+
/* Canonical indicators */
|
|
130
|
+
--cem-stroke-focus: var(--cem-stroke-standard);
|
|
131
|
+
--cem-stroke-selected: var(--cem-stroke-standard);
|
|
132
|
+
--cem-stroke-target: var(--cem-stroke-standard);
|
|
133
|
+
|
|
134
|
+
/* Placement */
|
|
135
|
+
--cem-stroke-indicator-offset: 2px; /* distance outside the edge, not thickness */
|
|
136
|
+
|
|
137
|
+
/* Optional convenience endpoints (aliases, not required by contract) */
|
|
138
|
+
--cem-stroke-grid: var(--cem-stroke-divider); /* tables / data grids */
|
|
139
|
+
--cem-stroke-boundary-strong: var(--cem-stroke-standard); /* dialogs / sheets when needed */
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 4.2 Semantics (normative)
|
|
144
|
+
|
|
145
|
+
- `--cem-stroke-boundary` is the default edge for **control containers** (text fields, chips, cards, tiles).
|
|
146
|
+
- `--cem-stroke-divider` separates **siblings** (list rows, table rows, sections).
|
|
147
|
+
- `--cem-stroke-focus` is for **keyboard focus** (and must meet §8).
|
|
148
|
+
- `--cem-stroke-selected` marks **selection** where background does not carry the whole burden of state (CEM preference).
|
|
149
|
+
- `--cem-stroke-target` marks a **deep-linked / navigated-to** target (e.g., URL fragment target, “jump to result”).
|
|
150
|
+
- `--cem-stroke-indicator-offset` prevents rings/indicators from visually merging with the component edge.
|
|
151
|
+
|
|
152
|
+
Optional convenience endpoints (aliases):
|
|
153
|
+
|
|
154
|
+
- `--cem-stroke-grid` is a readability alias for “divider inside structured content” (tables / data grids).
|
|
155
|
+
- `--cem-stroke-boundary-strong` is a stronger boundary used only when elevation/shadow is unavailable or insufficient.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
### 4.3 Component mapping matrix (informative)
|
|
160
|
+
|
|
161
|
+
The D5 contract intentionally avoids per-component thickness tokens (e.g., `--cem-input-outline`). Instead:
|
|
162
|
+
|
|
163
|
+
- Components bind to one of the **semantic endpoints** (boundary/divider/focus/selected/target).
|
|
164
|
+
- Component libraries may expose **adapter variables** with component-friendly names, but those adapter names are *not* part of the canonical CEM contract.
|
|
165
|
+
|
|
166
|
+
> Rule of thumb: **color is D0**, **thickness is D5**, **corner curvature is D3**, **spacing/insets is D1**, **density-mode overrides are D2**.
|
|
167
|
+
|
|
168
|
+
| Component family | Primary D5 endpoint(s) | Typical stroke usage | Notes |
|
|
169
|
+
|------------------------------------------|--------------------------------------------------------|--------------------------------|----------------------------------------------------------------------------------------------------------------------------|
|
|
170
|
+
| Dividers (horizontal/vertical) | `--cem-stroke-divider` | 1px hairline between siblings | Prefer inset patterns for lists; increase strength in dense or low-contrast contexts. |
|
|
171
|
+
| List item separators | `--cem-stroke-divider` (or `--cem-stroke-grid`) | Row separators | Treat dense “data-list” layouts as a grid for readability. |
|
|
172
|
+
| Table borders / grid lines | `--cem-stroke-grid` | Cell/row separators | Use `grid` to distinguish “structured separators” from generic dividers; same thickness by default. |
|
|
173
|
+
| Text field outline (outlined pattern) | `--cem-stroke-boundary` | Control container edge | Focus indication should be a ring (`--cem-stroke-focus`) rather than mutating border width. |
|
|
174
|
+
| Text field underline (filled pattern) | `--cem-stroke-boundary` or `--cem-stroke-divider` | Baseline boundary | Underline is a boundary of the control, not a sibling divider; map to divider only when visually used as “row separation”. |
|
|
175
|
+
| Outlined button border | `--cem-stroke-boundary` | Variant boundary | Use `boundary-strong` only for “hard separation” themes (e.g., low-elevation UIs). |
|
|
176
|
+
| Card / tile border | `--cem-stroke-boundary` (often `--cem-stroke-none`) | Optional edge | Prefer D4 elevation or D0 surface contrast; use boundary only when needed for scannability. |
|
|
177
|
+
| Checkbox / radio container border | `--cem-stroke-boundary` | Control boundary | The checkmark/dot is not a stroke token concern; it is icon geometry (D3) + color (D0). |
|
|
178
|
+
| Switch track outline (if any) | `--cem-stroke-boundary` | Track boundary | Track *height* is D2/D1, not D5; D5 only provides line weight if outlined. |
|
|
179
|
+
| Chip / badge border (bordered variant) | `--cem-stroke-boundary` | Subtle outline | In dense chips, consider mapping `boundary` → `standard` via D2 coupling if needed for separation. |
|
|
180
|
+
| Tabs / segmented control indicator | `--cem-stroke-selected` | Active underline/bar thickness | Avoid using `divider` for active indicators; indicators communicate state, not separation. |
|
|
181
|
+
| Focus ring (all controls) | `--cem-stroke-focus` + `--cem-stroke-indicator-offset` | External ring/outline | Must satisfy WCAG 2.2 focus appearance (§8.1). |
|
|
182
|
+
| Target highlight (deep link / “jump to”) | `--cem-stroke-target` | Temporary outline/ring | Distinct from focus: target is navigational, focus is interactive. |
|
|
183
|
+
| Menus / dropdowns / popovers (edge) | `--cem-stroke-boundary` (often none) | Optional border | Prefer D4 shadow separation; use boundary/boundary-strong in forced-colors or shadow-suppressed contexts. |
|
|
184
|
+
| Progress/slider tracks | (usually none) / `--cem-stroke-boundary` | Outline only if required | Track *thickness* (e.g., 8px) is a **dimension**; treat that as D2/D1, not D5. |
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
## 5. Focus, selected, and target indicators
|
|
188
|
+
|
|
189
|
+
CEM uses an **outline-driven indicator** model for states that must remain visible across backgrounds:
|
|
190
|
+
- focus (keyboard / focus-visible)
|
|
191
|
+
- selected
|
|
192
|
+
- target (e.g., anchor `:target`)
|
|
193
|
+
|
|
194
|
+
### 5.1 Zebra outline system (existing in `theme-data.xhtml`)
|
|
195
|
+
|
|
196
|
+
The current theme implementation uses a **zebra ring** composed of stacked outside strokes using `box-shadow` and zebra color variables:
|
|
197
|
+
|
|
198
|
+
- `--cem-zebra-strip-size`
|
|
199
|
+
- `--cem-zebra-color-0` … `--cem-zebra-color-3`
|
|
200
|
+
- `--cem-action-box-shadow` (used by `.action` components)
|
|
201
|
+
|
|
202
|
+
In normal themes, a 3-stripe ring is used; in contrast themes, a 4-stripe ring is used (intent + focus + selected + target).
|
|
203
|
+
|
|
204
|
+
### 5.2 Canonical zebra tokens (D5 contract)
|
|
205
|
+
|
|
206
|
+
D5 treats these as canonical *indicator-pattern tokens*:
|
|
207
|
+
|
|
208
|
+
```css
|
|
209
|
+
:root {
|
|
210
|
+
--cem-zebra-strip-size: 2px; /* thickness per stripe */
|
|
211
|
+
--cem-zebra-angle: 45deg; /* if stripes are rendered as gradients */
|
|
212
|
+
--cem-zebra-color-0: Canvas; /* intent / base stripe (contrast themes) */
|
|
213
|
+
--cem-zebra-color-1: CanvasText; /* focus stripe */
|
|
214
|
+
--cem-zebra-color-2: SelectedItem; /* selected stripe */
|
|
215
|
+
--cem-zebra-color-3: SelectedItem; /* target stripe (or themed alternative) */
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### 5.3 Recommended indicator composition (box-shadow ring)
|
|
220
|
+
|
|
221
|
+
```css
|
|
222
|
+
/* 3-stripe ring: focus/selected/target (normal themes) */
|
|
223
|
+
--cem-ring-zebra-3:
|
|
224
|
+
0 0 0 calc(1 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-1),
|
|
225
|
+
0 0 0 calc(2 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-2),
|
|
226
|
+
0 0 0 calc(3 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-3);
|
|
227
|
+
|
|
228
|
+
/* 4-stripe ring: intent + focus + selected + target (contrast themes) */
|
|
229
|
+
--cem-ring-zebra-4:
|
|
230
|
+
0 0 0 calc(1 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-0),
|
|
231
|
+
0 0 0 calc(2 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-1),
|
|
232
|
+
0 0 0 calc(3 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-2),
|
|
233
|
+
0 0 0 calc(4 * var(--cem-zebra-strip-size)) var(--cem-zebra-color-3);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Why `box-shadow`?**
|
|
237
|
+
- Avoids layout shift (unlike border-width changes).
|
|
238
|
+
- Works with rounded corners (D3) and can visually sit outside the component.
|
|
239
|
+
- Can be swapped to `outline` in forced-colors contexts (§8.2).
|
|
240
|
+
|
|
241
|
+
### 5.4 Focus heuristics
|
|
242
|
+
|
|
243
|
+
Prefer `:focus-visible` semantics. If the platform needs a polyfilled focus-ring behavior, align with heuristics similar to Material Web’s focus ring utilities (see references).
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 6. Dividers and separators
|
|
248
|
+
|
|
249
|
+
### 6.1 Divider role types
|
|
250
|
+
|
|
251
|
+
CEM recognizes three common divider roles (same thickness basis, different usage):
|
|
252
|
+
|
|
253
|
+
1. **Section divider**: separates groups (higher salience)
|
|
254
|
+
2. **Row divider**: list/table row hairlines
|
|
255
|
+
3. **Gridline**: dense tabular separation
|
|
256
|
+
|
|
257
|
+
All three should normally map to `--cem-stroke-divider` (hairline). Promote to `--cem-stroke-boundary-strong` when:
|
|
258
|
+
- the UI is dense (D2)
|
|
259
|
+
- the background is textured/animated
|
|
260
|
+
- or the consumer must not miss the separation (e.g., critical comparison tables).
|
|
261
|
+
|
|
262
|
+
### 6.2 Inset patterns (non-token guidance)
|
|
263
|
+
|
|
264
|
+
Avoid creating many inset tokens. Use a single **inset rule**:
|
|
265
|
+
- “Full-bleed dividers for full-bleed lists”
|
|
266
|
+
- “Inset dividers under leading avatar/icon to preserve grouping”
|
|
267
|
+
|
|
268
|
+
Spacing and inset should use D1 tokens.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## 7. Inter-dimension coupling
|
|
273
|
+
|
|
274
|
+
### 7.1 D3 shape coupling
|
|
275
|
+
|
|
276
|
+
Indicator rings should follow component rounding:
|
|
277
|
+
|
|
278
|
+
```css
|
|
279
|
+
border-radius: var(--cem-bend-control);
|
|
280
|
+
box-shadow: var(--cem-ring-zebra-3);
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
If the ring is outside, it may require a slightly larger radius:
|
|
284
|
+
|
|
285
|
+
```css
|
|
286
|
+
border-radius: calc(var(--cem-bend-control) + var(--cem-stroke-indicator-offset));
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### 7.2 D1 spacing coupling
|
|
290
|
+
|
|
291
|
+
Where indicators sit outside the edge, ensure surrounding layout provides enough breathing room. Prefer:
|
|
292
|
+
- container padding (D1)
|
|
293
|
+
- or internal “guard rails” around interactive controls (D2), including `--cem-coupling-guard-min`
|
|
294
|
+
and `--cem-coupling-halo`
|
|
295
|
+
|
|
296
|
+
Treat `--cem-coupling-guard-min` as the default clearance budget between adjacent operable zones.
|
|
297
|
+
If you increase any of the following, you must also increase surrounding D1 spacing and/or D2 guard/halo
|
|
298
|
+
(or accept overlap):
|
|
299
|
+
|
|
300
|
+
- zebra ring outset: `3 * --cem-zebra-strip-size` (normal) / `4 * --cem-zebra-strip-size` (contrast)
|
|
301
|
+
- outline outset: `--cem-stroke-indicator-offset + --cem-stroke-focus`
|
|
302
|
+
|
|
303
|
+
See the D2 compatibility rule in [`cem-coupling.md`](./cem-coupling.md) §4.1.1.
|
|
304
|
+
|
|
305
|
+
### 7.3 D4 elevation coupling
|
|
306
|
+
|
|
307
|
+
Elevation and stroke are substitutes:
|
|
308
|
+
- Use elevation for depth separation in normal themes where shadows are viable.
|
|
309
|
+
- Use stroke (including zebra) in contrast themes, where shadows can be insufficient.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## 8. Accessibility and forced-colors requirements
|
|
314
|
+
|
|
315
|
+
### 8.1 Focus appearance (WCAG 2.2)
|
|
316
|
+
|
|
317
|
+
The focus indicator must be large/visible enough to be reliably perceived. A robust default is a **2px** perimeter (or equivalent area) around the focused component, which D5’s `--cem-stroke-focus` supports.
|
|
318
|
+
|
|
319
|
+
### 8.2 Forced colors / high contrast
|
|
320
|
+
|
|
321
|
+
In `forced-colors: active` contexts:
|
|
322
|
+
- prefer `outline` (system colors) and avoid relying on subtle shadows
|
|
323
|
+
- avoid gradients that may be flattened
|
|
324
|
+
- ensure indicator uses `CanvasText` / `Highlight` as appropriate in D0 mapping
|
|
325
|
+
|
|
326
|
+
Suggested baseline:
|
|
327
|
+
|
|
328
|
+
```css
|
|
329
|
+
@media (forced-colors: active) {
|
|
330
|
+
.cem-focusable:focus-visible {
|
|
331
|
+
outline: var(--cem-stroke-focus) solid CanvasText;
|
|
332
|
+
outline-offset: var(--cem-stroke-indicator-offset);
|
|
333
|
+
box-shadow: none;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## 9. Implementation guidance (CSS recipes)
|
|
341
|
+
|
|
342
|
+
### 9.1 Prefer rings over border-width mutation
|
|
343
|
+
|
|
344
|
+
**Avoid**
|
|
345
|
+
```css
|
|
346
|
+
/* Causes layout shift */
|
|
347
|
+
.control:focus { border-width: 2px; }
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
**Prefer**
|
|
351
|
+
```css
|
|
352
|
+
.control:focus-visible {
|
|
353
|
+
outline: var(--cem-stroke-focus) solid currentColor;
|
|
354
|
+
outline-offset: var(--cem-stroke-indicator-offset);
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
or (for rounded geometry / zebra):
|
|
359
|
+
```css
|
|
360
|
+
.control:focus-visible {
|
|
361
|
+
box-shadow: var(--cem-ring-zebra-3);
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### 9.2 Layering order for multiple indicators
|
|
366
|
+
|
|
367
|
+
If multiple indicators can apply, compose in a stable order:
|
|
368
|
+
1. focus
|
|
369
|
+
2. selected
|
|
370
|
+
3. target
|
|
371
|
+
|
|
372
|
+
In zebra, this is naturally expressed as concentric stripes.
|
|
373
|
+
|
|
374
|
+
### 9.3 Action components (existing pattern)
|
|
375
|
+
|
|
376
|
+
Current implementation uses:
|
|
377
|
+
|
|
378
|
+
```css
|
|
379
|
+
.action { box-shadow: var(--cem-action-box-shadow); }
|
|
380
|
+
.action:hover { --cem-action-box-shadow: var(--cem-action-box-shadow-hover); }
|
|
381
|
+
.action:active { --cem-action-box-shadow: var(--cem-action-box-shadow-active); }
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
In contrast themes, `--cem-action-box-shadow` becomes the zebra ring.
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## 10. Framework mapping guidance (Angular Material, MUI)
|
|
389
|
+
|
|
390
|
+
This section is **non-normative**. It documents how to map framework tokens/variables into the CEM D5 semantic endpoints.
|
|
391
|
+
|
|
392
|
+
### 10.1 Angular Material (MDC-based) mapping
|
|
393
|
+
|
|
394
|
+
Common MDC variables (examples seen in Angular Material customization workflows):
|
|
395
|
+
|
|
396
|
+
- `--mdc-outlined-text-field-outline-width` → `--cem-stroke-boundary`
|
|
397
|
+
- `--mdc-outlined-text-field-focus-outline-width` → `--cem-stroke-focus` (or `--cem-stroke-boundary-strong`)
|
|
398
|
+
- `--mdc-filled-text-field-active-indicator-height` → `--cem-stroke-divider`
|
|
399
|
+
- `--mdc-filled-text-field-focus-active-indicator-height` → `--cem-stroke-focus`
|
|
400
|
+
- `--mdc-outlined-card-outline-width` → `--cem-stroke-boundary`
|
|
401
|
+
|
|
402
|
+
Angular Material also exposes higher-level variables in some setups, e.g.:
|
|
403
|
+
- `--mat-form-field-outlined-focus-outline-width` → `--cem-stroke-focus`
|
|
404
|
+
|
|
405
|
+
**Guidance:** map these variables *from* CEM tokens; do not treat them as canonical tokens in CEM.
|
|
406
|
+
|
|
407
|
+
### 10.2 MUI mapping
|
|
408
|
+
|
|
409
|
+
**MUI System**
|
|
410
|
+
- `sx={{ border: 1 }}` expresses a border thickness via the theme’s `borders` scale.
|
|
411
|
+
- Map `border: 1` (typical) to `--cem-stroke-boundary` (hairline).
|
|
412
|
+
|
|
413
|
+
**MUI Joy UI**
|
|
414
|
+
Joy exposes per-component CSS variables for focus ring geometry (examples):
|
|
415
|
+
- `--Input-focusedThickness` → `--cem-stroke-focus`
|
|
416
|
+
- `--Input-focusedInset` → whether focus is inset or outset (maps to indicator placement policy)
|
|
417
|
+
- `--Input-focusedOffset` → `--cem-stroke-indicator-offset`
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## 11. Canonical token summary
|
|
422
|
+
|
|
423
|
+
| Token | Category | Required | Meaning |
|
|
424
|
+
|------|----------|----------|---------|
|
|
425
|
+
| `--cem-stroke-none` | Basis | ✓ | No stroke |
|
|
426
|
+
| `--cem-stroke-hair` | Basis | ✓ | 1px hairline |
|
|
427
|
+
| `--cem-stroke-standard` | Basis | ✓ | 2px standard indicator |
|
|
428
|
+
| `--cem-stroke-strong` | Basis | ✓ | 3px strong separation |
|
|
429
|
+
| `--cem-stroke-boundary` | Semantic | ✓ | Default component boundary |
|
|
430
|
+
| `--cem-stroke-boundary-strong` | Semantic | Optional | Strong boundary for cases where elevation/shadow cannot carry separation |
|
|
431
|
+
| `--cem-stroke-divider` | Semantic | ✓ | Default separator/divider |
|
|
432
|
+
| `--cem-stroke-grid` | Semantic | Optional | Divider alias for structured content (tables/grids) |
|
|
433
|
+
| `--cem-stroke-focus` | Semantic | ✓ | Focus-visible indicator width |
|
|
434
|
+
| `--cem-stroke-selected` | Semantic | ✓ | Selection indicator width |
|
|
435
|
+
| `--cem-stroke-target` | Semantic | ✓ | Target indicator width |
|
|
436
|
+
| `--cem-stroke-indicator-offset` | Placement | ✓ | Ring/outline offset distance |
|
|
437
|
+
| `--cem-zebra-strip-size` | Pattern | Optional | Stripe thickness for zebra indicators |
|
|
438
|
+
| `--cem-zebra-angle` | Pattern | Optional | Stripe angle for gradient zebra |
|
|
439
|
+
| `--cem-zebra-color-0..3` | Pattern | Optional | Concentric zebra stripe colors (intent/focus/selected/target) |
|
|
440
|
+
| `--cem-action-box-shadow` | Adapter hook | Optional | Existing action indicator/shadow hook (implementation detail) |
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
## 12. Governance and versioning
|
|
445
|
+
|
|
446
|
+
### 12.1 What counts as breaking
|
|
447
|
+
|
|
448
|
+
Treat as **major** (breaking) if you:
|
|
449
|
+
|
|
450
|
+
- Rename or remove any **Required (✓)** D5 endpoint listed in §11.
|
|
451
|
+
- Change the semantic meaning of an endpoint (e.g., `--cem-stroke-focus` no longer representing focus thickness).
|
|
452
|
+
- Remove zebra token meanings that consumers rely on (e.g., swapping which stripe denotes focus).
|
|
453
|
+
|
|
454
|
+
### 12.2 What is non-breaking
|
|
455
|
+
|
|
456
|
+
Treat as **minor/patch** if you:
|
|
457
|
+
|
|
458
|
+
- Adjust numeric values within a theme while preserving semantics (e.g., `2px` → `3px` in contrast theme only).
|
|
459
|
+
- Add new optional endpoints that are clearly scoped.
|
|
460
|
+
- Clarify documentation, examples, or mapping guidance.
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
## 13. References
|
|
465
|
+
|
|
466
|
+
- W3C WCAG 2.2 Understanding: Focus Appearance (Minimum) — https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance.html
|
|
467
|
+
- MDN: `:focus-visible` — https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible
|
|
468
|
+
- Material Web focus ring documentation — https://github.com/material-components/material-web/blob/main/docs/components/focus-ring.md
|
|
469
|
+
- Material Design 3 component specs (stroke/focus indicator values are listed per component):
|
|
470
|
+
- Menus (specs) — https://m3.material.io/components/menus/specs
|
|
471
|
+
- Checkbox (specs) — https://m3.material.io/components/checkbox/specs
|
|
472
|
+
- Google issue tracker example referencing OutlinedTextField outline thickness in specs — https://issuetracker.google.com/issues/191543915
|
|
473
|
+
|
|
474
|
+
- Angular Material customization guidance — https://v12.material.angular.io/guide/customizing-component-styles
|
|
475
|
+
- Angular Material outlined form-field focus border width discussion (example) — https://github.com/angular/components/issues/28023
|
|
476
|
+
- Angular Material customization examples showing outline width variables (examples):
|
|
477
|
+
- https://www.fusonic.net/en/blog/angular-material-customization
|
|
478
|
+
- https://dev.to/dhutaryan/how-to-make-angular-material-inputs-look-like-simple-fields-3oe5
|
|
479
|
+
- MUI System borders utilities — https://mui.com/system/borders/
|
|
480
|
+
- MUI Joy UI Input variables (focus thickness/offset) — https://mui.com/joy-ui/react-input/
|