diff --git a/packages/ckeditor5-basic-styles/theme/code.css b/packages/ckeditor5-basic-styles/theme/code.css index 57b2b9372c5..e57c8a66cd7 100644 --- a/packages/ckeditor5-basic-styles/theme/code.css +++ b/packages/ckeditor5-basic-styles/theme/code.css @@ -3,6 +3,7 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +/* content-layer: pending color palette */ .ck-content code { background-color: hsla(0, 0%, 78%, 0.3); padding: .15em; diff --git a/packages/ckeditor5-block-quote/theme/blockquote.css b/packages/ckeditor5-block-quote/theme/blockquote.css index d6b4adb0039..af79fd62a93 100644 --- a/packages/ckeditor5-block-quote/theme/blockquote.css +++ b/packages/ckeditor5-block-quote/theme/blockquote.css @@ -3,6 +3,7 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +/* content-layer: pending color palette */ .ck-content blockquote { /* See #12 */ overflow: hidden; diff --git a/packages/ckeditor5-bookmark/theme/bookmark.css b/packages/ckeditor5-bookmark/theme/bookmark.css index 25f683fbb1b..b41de866e57 100644 --- a/packages/ckeditor5-bookmark/theme/bookmark.css +++ b/packages/ckeditor5-bookmark/theme/bookmark.css @@ -5,7 +5,8 @@ :root { --ck-bookmark-icon-hover-fill-color: var(--ck-color-widget-hover-border); - --ck-bookmark-icon-selected-fill-color: var(--ck-color-focus-border); + /* Backward compatibility: falls back to legacy --ck-color-focus-border if overridden. */ + --ck-bookmark-icon-selected-fill-color: var(--ck-color-focus-border, var(--ck-color-interactive-focus-border)); --ck-bookmark-icon-animation-duration: var(--ck-widget-handler-animation-duration); --ck-bookmark-icon-animation-curve: var(--ck-widget-handler-animation-curve); } @@ -66,5 +67,5 @@ height: 100%; border-right: 1px solid var(--ck-color-base-text); margin-right: -1px; - outline: solid 1px hsla(0, 0%, 100%, .5); + outline: var(--ck-outline-fake-caret); } diff --git a/packages/ckeditor5-bookmark/theme/bookmarktoolbar.css b/packages/ckeditor5-bookmark/theme/bookmarktoolbar.css index f36c534ebb5..04eaf320ace 100644 --- a/packages/ckeditor5-bookmark/theme/bookmarktoolbar.css +++ b/packages/ckeditor5-bookmark/theme/bookmarktoolbar.css @@ -13,7 +13,7 @@ } .ck.ck-bookmark-toolbar__preview { - padding: 0 var(--ck-spacing-medium); + padding: 0 var(--ck-spacing-medium, var(--ck-spacing-md)); max-width: var(--ck-input-width); min-width: 3em; font-weight: normal; diff --git a/packages/ckeditor5-ckbox/theme/ckboximageedit.css b/packages/ckeditor5-ckbox/theme/ckboximageedit.css index abe3b0f9d5b..b5208d5944f 100644 --- a/packages/ckeditor5-ckbox/theme/ckboximageedit.css +++ b/packages/ckeditor5-ckbox/theme/ckboximageedit.css @@ -4,7 +4,7 @@ */ :root { - /* Based on default CKBox theme colors */ + /* Based on default CKBox theme colors — content-layer: pending color palette */ --ck-image-processing-highlight-color: hsl(220, 10%, 98%); --ck-image-processing-background-color: hsl(220, 10%, 90%); } diff --git a/packages/ckeditor5-clipboard/theme/clipboard.css b/packages/ckeditor5-clipboard/theme/clipboard.css index b182152ed88..56deeb05438 100644 --- a/packages/ckeditor5-clipboard/theme/clipboard.css +++ b/packages/ckeditor5-clipboard/theme/clipboard.css @@ -82,7 +82,8 @@ background: var(--ck-clipboard-drop-target-color); margin-top: -1px; position: absolute; - z-index: var(--ck-z-default); + /* Backward compatibility: falls back to legacy --ck-z-default if overridden. */ + z-index: var(--ck-z-default, var(--ck-z-base)); &::before { content: ''; diff --git a/packages/ckeditor5-code-block/theme/codeblock.css b/packages/ckeditor5-code-block/theme/codeblock.css index d6352d2085e..fbebaca2dfd 100644 --- a/packages/ckeditor5-code-block/theme/codeblock.css +++ b/packages/ckeditor5-code-block/theme/codeblock.css @@ -4,7 +4,7 @@ */ :root { - --ck-color-code-block-label-background: hsl(0, 0%, 46%); + --ck-color-code-block-label-background: var(--ck-color-base-text-light); } .ck.ck-editor__editable pre[data-language]::after { @@ -15,10 +15,11 @@ background: var(--ck-color-code-block-label-background); font-size: 10px; - font-family: var(--ck-font-face); + /* Backward compatibility: falls back to legacy --ck-font-face if overridden. */ + font-family: var(--ck-font-face, var(--ck-font-family)); line-height: 16px; - padding: var(--ck-spacing-tiny) var(--ck-spacing-medium); - color: hsl(0, 0%, 100%); + padding: var(--ck-spacing-tiny, var(--ck-spacing-xs)) var(--ck-spacing-medium, var(--ck-spacing-md)); + color: var(--ck-color-base-background); white-space: nowrap; } @@ -29,6 +30,7 @@ overflow-x: hidden; } +/* content-layer: pending color palette */ .ck-content pre { padding: 1em; color: hsl(0, 0%, 20.8%); diff --git a/packages/ckeditor5-editor-classic/theme/classiceditor.css b/packages/ckeditor5-editor-classic/theme/classiceditor.css index 01c95594061..9bd9ad0bb6f 100644 --- a/packages/ckeditor5-editor-classic/theme/classiceditor.css +++ b/packages/ckeditor5-editor-classic/theme/classiceditor.css @@ -8,7 +8,8 @@ .ck.ck-editor__main > .ck-editor__editable { /* https://github.com/ckeditor/ckeditor5/issues/3384 */ background: var(--ck-color-base-background); - border-radius: var(--ck-rounded-corners-radius); + /* Backward compatibility: falls back to legacy --ck-rounded-corners-radius if overridden. */ + border-radius: var(--ck-rounded-corners-radius, var(--ck-radius-corners)); border-top-left-radius: 0; border-top-right-radius: 0; @@ -25,6 +26,7 @@ & .ck-editor__top .ck-sticky-panel .ck-toolbar { /* https://github.com/ckeditor/ckeditor5-editor-classic/issues/62 */ - z-index: var(--ck-z-panel); + /* Backward compatibility: falls back to legacy --ck-z-panel if overridden. */ + z-index: var(--ck-z-panel, var(--ck-z-overlay)); } } diff --git a/packages/ckeditor5-emoji/theme/emojicategories.css b/packages/ckeditor5-emoji/theme/emojicategories.css index 79a8c7e7388..cfcfa3a6388 100644 --- a/packages/ckeditor5-emoji/theme/emojicategories.css +++ b/packages/ckeditor5-emoji/theme/emojicategories.css @@ -6,7 +6,7 @@ .ck.ck-emoji__categories-list { display: flex; justify-content: space-between; - margin: 0 var(--ck-spacing-large); + margin: 0 var(--ck-spacing-large, var(--ck-spacing-lg)); > .ck.ck-button.ck-button_with-text { border-width: 0; @@ -14,9 +14,9 @@ border-bottom-style: solid; border-bottom-color: transparent; padding: 0; - font-size: var(--ck-font-size-big); - min-width: var(--ck-font-size-big); - min-height: var(--ck-font-size-big); + font-size: var(--ck-font-size-big, var(--ck-font-size-lg)); + min-width: var(--ck-font-size-big, var(--ck-font-size-lg)); + min-height: var(--ck-font-size-big, var(--ck-font-size-lg)); &.ck-emoji__category-item.ck-on { border-bottom-color: var(--ck-color-base-active); diff --git a/packages/ckeditor5-emoji/theme/emojigrid.css b/packages/ckeditor5-emoji/theme/emojigrid.css index 5fc03d3ac1b..add90ffdfc8 100644 --- a/packages/ckeditor5-emoji/theme/emojigrid.css +++ b/packages/ckeditor5-emoji/theme/emojigrid.css @@ -19,8 +19,8 @@ & .ck-emoji__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--ck-emoji-grid-tile-size), 1fr)); - margin: var(--ck-spacing-standard) var(--ck-spacing-large); - grid-gap: var(--ck-spacing-small); + margin: var(--ck-spacing-standard, var(--ck-spacing-base)) var(--ck-spacing-large, var(--ck-spacing-lg)); + grid-gap: var(--ck-spacing-small, var(--ck-spacing-sm)); } & .ck-emoji__tile { @@ -41,7 +41,7 @@ &:hover:not(.ck-disabled) { /* Disable the default .ck-button's border ring. */ border: 0; - box-shadow: inset 0 0 0 1px var(--ck-color-base-background), 0 0 0 2px var(--ck-color-focus-border); + box-shadow: inset 0 0 0 1px var(--ck-color-base-background), 0 0 0 2px var(--ck-color-focus-border, var(--ck-color-interactive-focus-border)); } /* Make sure the glyph is rendered in the center of the button */ diff --git a/packages/ckeditor5-emoji/theme/emojipicker.css b/packages/ckeditor5-emoji/theme/emojipicker.css index 2e3e622e214..8a2bcb01337 100644 --- a/packages/ckeditor5-emoji/theme/emojipicker.css +++ b/packages/ckeditor5-emoji/theme/emojipicker.css @@ -9,8 +9,8 @@ .ck .ck.ck-emoji__search { display: flex; - padding: var(--ck-spacing-large); - padding-bottom: var(--ck-spacing-medium); + padding: var(--ck-spacing-large, var(--ck-spacing-lg)); + padding-bottom: var(--ck-spacing-medium, var(--ck-spacing-md)); justify-content: space-between; align-items: center; @@ -32,9 +32,10 @@ height: 100%; border-right: 1px solid var(--ck-color-base-text); margin-right: -1px; - outline: solid 1px hsla(0, 0%, 100%, .5); + outline: var(--ck-outline-fake-caret); } div.ck.ck-balloon-panel.ck-emoji-picker-balloon { - z-index: calc( var( --ck-z-dialog ) + 1 ); + /* Backward compatibility: falls back to legacy --ck-z-dialog if overridden. */ + z-index: calc( var( --ck-z-dialog, var(--ck-z-modal) ) + 1 ); } diff --git a/packages/ckeditor5-emoji/theme/emojitone.css b/packages/ckeditor5-emoji/theme/emojitone.css index bf508f8f8cd..a595384efd0 100644 --- a/packages/ckeditor5-emoji/theme/emojitone.css +++ b/packages/ckeditor5-emoji/theme/emojitone.css @@ -4,7 +4,7 @@ */ .ck.ck-emoji__skin-tone { - margin-left: var(--ck-spacing-standard); + margin-left: var(--ck-spacing-standard, var(--ck-spacing-base)); > .ck.ck-dropdown { diff --git a/packages/ckeditor5-find-and-replace/theme/findandreplace.css b/packages/ckeditor5-find-and-replace/theme/findandreplace.css index bfce5356268..7882f1a18a5 100644 --- a/packages/ckeditor5-find-and-replace/theme/findandreplace.css +++ b/packages/ckeditor5-find-and-replace/theme/findandreplace.css @@ -3,11 +3,15 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + --ck-color-find-result-selected: hsl(29, 100%, 60%); +} + .ck-find-result { background: var(--ck-color-highlight-background); color: var(--ck-color-text); } .ck-find-result_selected { - background: hsl(29, 100%, 60%); + background: var(--ck-color-find-result-selected); } diff --git a/packages/ckeditor5-find-and-replace/theme/findandreplaceform.css b/packages/ckeditor5-find-and-replace/theme/findandreplaceform.css index 426acd0f999..7f2b873f8b3 100644 --- a/packages/ckeditor5-find-and-replace/theme/findandreplaceform.css +++ b/packages/ckeditor5-find-and-replace/theme/findandreplaceform.css @@ -26,7 +26,7 @@ align-items: center; align-content: stretch; - padding: var(--ck-spacing-large); + padding: var(--ck-spacing-large, var(--ck-spacing-lg)); margin: 0; & > .ck-button { @@ -35,13 +35,13 @@ [dir="ltr"] & { & > * + * { - margin-left: var(--ck-spacing-standard); + margin-left: var(--ck-spacing-standard, var(--ck-spacing-base)); } } [dir="rtl"] & { & > * + * { - margin-right: var(--ck-spacing-standard); + margin-right: var(--ck-spacing-standard, var(--ck-spacing-base)); } } @@ -77,17 +77,17 @@ color: var(--ck-color-base-border); [dir="ltr"] & { - right: var(--ck-spacing-standard); + right: var(--ck-spacing-standard, var(--ck-spacing-base)); } [dir="rtl"] & { - left: var(--ck-spacing-standard); + left: var(--ck-spacing-standard, var(--ck-spacing-base)); } } & > .ck-labeled-field-replace { flex: 0 0 100%; - padding-top: var(--ck-spacing-standard); + padding-top: var(--ck-spacing-standard, var(--ck-spacing-base)); [dir="ltr"] & { margin-left: 0; @@ -103,15 +103,15 @@ & .ck-find-and-replace-form__actions { flex-wrap: wrap; justify-content: flex-end; - margin-top: calc( -1 * var(--ck-spacing-large) ); + margin-top: calc( -1 * var(--ck-spacing-large, var(--ck-spacing-lg)) ); & > .ck-button-find { font-weight: bold; /* Beef the find button up a little. It's the main action button in the form */ & .ck-button__label { - padding-left: var(--ck-spacing-large); - padding-right: var(--ck-spacing-large); + padding-left: var(--ck-spacing-large, var(--ck-spacing-lg)); + padding-right: var(--ck-spacing-large, var(--ck-spacing-lg)); } } } @@ -140,7 +140,7 @@ & .ck-labeled-field-view { flex: 1 0 auto; width: 100%; - margin-bottom: var(--ck-spacing-standard); + margin-bottom: var(--ck-spacing-standard, var(--ck-spacing-base)); } & > .ck-button { diff --git a/packages/ckeditor5-fullscreen/theme/fullscreen.css b/packages/ckeditor5-fullscreen/theme/fullscreen.css index 664cb1f61a6..9df4a54f650 100644 --- a/packages/ckeditor5-fullscreen/theme/fullscreen.css +++ b/packages/ckeditor5-fullscreen/theme/fullscreen.css @@ -11,9 +11,13 @@ body.ck-fullscreen { overflow: hidden; - --ck-z-default: calc(var(--ck-z-fullscreen) + 1); - --ck-z-panel: calc(var(--ck-z-default) + 999); - --ck-z-dialog: 100000; + /* Override both legacy and new z-index tokens for fullscreen mode. */ + --ck-z-default: calc(var(--ck-z-fullscreen) + 1); /* legacy */ + --ck-z-base: calc(var(--ck-z-fullscreen) + 1); + --ck-z-panel: calc(var(--ck-z-default) + 999); /* legacy */ + --ck-z-overlay: calc(var(--ck-z-default) + 999); + --ck-z-dialog: 100000; /* legacy */ + --ck-z-modal: 100000; /* CKBox wrappers have z-index of 9999, let's bump them over the dialog's to ensure visibility like outside fullscreen mode. */ & .ckbox:not(#n) { @@ -87,7 +91,8 @@ Fullscreen layout: border-top: 1px solid var(--ck-color-base-border); border-left: 1px solid var(--ck-color-base-border); border-right: 1px solid var(--ck-color-base-border); - border-radius: var(--ck-border-radius) 0; + /* Backward compatibility: falls back to legacy --ck-border-radius if overridden. */ + border-radius: var(--ck-border-radius, var(--ck-radius-base)) 0; } } @@ -134,8 +139,8 @@ Fullscreen layout: margin: 0; padding: 20mm 12mm; border: 1px var(--ck-color-base-border) solid; - background: hsl(0, 0%, 100%); - box-shadow: 0 2px 3px hsla(0, 0%, 0%, 0.078); + background: var(--ck-color-base-background); + box-shadow: var(--ck-shadow-md); } .ck-fullscreen__main-wrapper .ck-fullscreen__editable .ck-source-editing-area { @@ -165,11 +170,12 @@ Fullscreen layout: & .ck-button.ck-fullscreen__left-sidebar-toggle-button { --ck-icon-size: 20px; --ck-ui-component-min-height: 0px; + --ck-size-min-height: 0px; align-self: flex-start; padding-top: 0; margin-top: var(--ck-fullscreen-editor-top-margin); - margin-bottom: var(--ck-spacing-large); + margin-bottom: var(--ck-spacing-large, var(--ck-spacing-lg)); opacity: 0.5; border-radius: 100%; } @@ -205,8 +211,8 @@ Fullscreen layout: } .ck-fullscreen__left-sidebar-item { - padding: var(--ck-spacing-medium); - margin-bottom: var(--ck-spacing-medium); + padding: var(--ck-spacing-medium, var(--ck-spacing-md)); + margin-bottom: var(--ck-spacing-medium, var(--ck-spacing-md)); /* First header should not have top padding. */ &:first-child { @@ -238,7 +244,7 @@ Fullscreen layout: } .ck-fullscreen__presence-list { - margin-top: var(--ck-spacing-medium); + margin-top: var(--ck-spacing-medium, var(--ck-spacing-md)); } .ck-fullscreen__left-sidebar-item--no-margin { diff --git a/packages/ckeditor5-highlight/theme/highlight.css b/packages/ckeditor5-highlight/theme/highlight.css index beb373d5725..c9a3e53a02a 100644 --- a/packages/ckeditor5-highlight/theme/highlight.css +++ b/packages/ckeditor5-highlight/theme/highlight.css @@ -4,6 +4,7 @@ */ :root { + /* content-layer: pending color palette */ --ck-content-highlight-marker-yellow: hsl(60, 97%, 73%); --ck-content-highlight-marker-green: hsl(120, 93%, 68%); --ck-content-highlight-marker-pink: hsl(345, 96%, 73%); diff --git a/packages/ckeditor5-horizontal-line/theme/horizontalline.css b/packages/ckeditor5-horizontal-line/theme/horizontalline.css index d0d07aa7fc3..b3d64df00c2 100644 --- a/packages/ckeditor5-horizontal-line/theme/horizontalline.css +++ b/packages/ckeditor5-horizontal-line/theme/horizontalline.css @@ -9,6 +9,7 @@ display: flow-root; } +/* content-layer: pending color palette */ .ck-content hr { margin: 15px 0; height: 4px; diff --git a/packages/ckeditor5-html-embed/theme/htmlembed.css b/packages/ckeditor5-html-embed/theme/htmlembed.css index e95a4334e9d..87940048d0f 100644 --- a/packages/ckeditor5-html-embed/theme/htmlembed.css +++ b/packages/ckeditor5-html-embed/theme/htmlembed.css @@ -7,10 +7,10 @@ --ck-html-embed-content-width: calc(100% - 1.5 * var(--ck-icon-size)); --ck-html-embed-source-height: 10em; --ck-html-embed-unfocused-outline-width: 1px; - --ck-html-embed-content-min-height: calc(var(--ck-icon-size) + var(--ck-spacing-standard)); + --ck-html-embed-content-min-height: calc(var(--ck-icon-size) + var(--ck-spacing-standard, var(--ck-spacing-base))); --ck-html-embed-source-disabled-background: var(--ck-color-base-foreground); - --ck-html-embed-source-disabled-color: hsl(0deg 0% 45%); + --ck-html-embed-source-disabled-color: var(--ck-color-text-disabled); } /* The feature container. */ @@ -47,14 +47,14 @@ &::before { content: attr(data-html-embed-label); top: calc(-1 * var(--ck-html-embed-unfocused-outline-width)); - left: var(--ck-spacing-standard); - background: hsl(0deg 0% 60%); + left: var(--ck-spacing-standard, var(--ck-spacing-base)); + background: var(--ck-color-base-text-light); transition: background var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve); - padding: calc(var(--ck-spacing-tiny) + var(--ck-html-embed-unfocused-outline-width)) var(--ck-spacing-small) var(--ck-spacing-tiny); - border-radius: 0 0 var(--ck-border-radius) var(--ck-border-radius); + padding: calc(var(--ck-spacing-tiny, var(--ck-spacing-xs)) + var(--ck-html-embed-unfocused-outline-width)) var(--ck-spacing-small, var(--ck-spacing-sm)) var(--ck-spacing-tiny, var(--ck-spacing-xs)); + border-radius: 0 0 var(--ck-border-radius, var(--ck-radius-base)) var(--ck-border-radius, var(--ck-radius-base)); color: var(--ck-color-base-background); - font-size: var(--ck-font-size-tiny); - font-family: var(--ck-font-face); + font-size: var(--ck-font-size-tiny, var(--ck-font-size-xs)); + font-family: var(--ck-font-face, var(--ck-font-family)); position: absolute; /* Make sure the content does not cover the label. */ @@ -63,7 +63,7 @@ &[dir="rtl"]::before { left: auto; - right: var(--ck-spacing-standard); + right: var(--ck-spacing-standard, var(--ck-spacing-base)); } /* Make space for label but it only collides in LTR languages */ @@ -73,30 +73,30 @@ .ck.ck-editor__editable.ck-blurred &.ck-widget_selected::before { top: 0px; - padding: var(--ck-spacing-tiny) var(--ck-spacing-small); + padding: var(--ck-spacing-tiny, var(--ck-spacing-xs)) var(--ck-spacing-small, var(--ck-spacing-sm)); } .ck.ck-editor__editable:not(.ck-blurred) &.ck-widget_selected::before { top: 0; - padding: var(--ck-spacing-tiny) var(--ck-spacing-small); - background: var(--ck-color-focus-border); + padding: var(--ck-spacing-tiny, var(--ck-spacing-xs)) var(--ck-spacing-small, var(--ck-spacing-sm)); + background: var(--ck-color-focus-border, var(--ck-color-interactive-focus-border)); } .ck.ck-editor__editable &:not(.ck-widget_selected):hover::before { top: 0px; - padding: var(--ck-spacing-tiny) var(--ck-spacing-small); + padding: var(--ck-spacing-tiny, var(--ck-spacing-xs)) var(--ck-spacing-small, var(--ck-spacing-sm)); } /* ----- Emebed internals --------------------------------------------------------------------- */ & .raw-html-embed__content-wrapper { - padding: var(--ck-spacing-standard); + padding: var(--ck-spacing-standard, var(--ck-spacing-base)); } /* The switch mode button wrapper. */ & .raw-html-embed__buttons-wrapper { - top: var(--ck-spacing-standard); - right: var(--ck-spacing-standard); + top: var(--ck-spacing-standard, var(--ck-spacing-base)); + right: var(--ck-spacing-standard, var(--ck-spacing-base)); position: absolute; display: flex; @@ -109,13 +109,13 @@ } & .ck-button:not(:first-child) { - margin-top: var(--ck-spacing-small); + margin-top: var(--ck-spacing-small, var(--ck-spacing-sm)); } flex-direction: column } &[dir="rtl"] .raw-html-embed__buttons-wrapper { - left: var(--ck-spacing-standard); + left: var(--ck-spacing-standard, var(--ck-spacing-base)); right: auto; } @@ -126,7 +126,7 @@ width: var(--ck-html-embed-content-width); resize: none; min-width: 0; - padding: var(--ck-spacing-standard); + padding: var(--ck-spacing-standard, var(--ck-spacing-base)); font-family: monospace; tab-size: 4; diff --git a/packages/ckeditor5-html-support/theme/datafilter.css b/packages/ckeditor5-html-support/theme/datafilter.css index 70defeac6f4..bcaa2a5a71e 100644 --- a/packages/ckeditor5-html-support/theme/datafilter.css +++ b/packages/ckeditor5-html-support/theme/datafilter.css @@ -10,10 +10,12 @@ .ck-widget.html-object-embed { font-size: var(--ck-font-size-base); background-color: var(--ck-color-base-foreground); - padding: var(--ck-spacing-small); + /* Backward compatibility: falls back to legacy --ck-spacing-small if overridden. */ + padding: var(--ck-spacing-small, var(--ck-spacing-sm)); /* Leave space for label */ - padding-top: calc(var(--ck-font-size-tiny) + var(--ck-spacing-large)); - min-width: calc(76px + var(--ck-spacing-standard)); + padding-top: calc(var(--ck-font-size-tiny, var(--ck-font-size-xs)) + var(--ck-spacing-large, var(--ck-spacing-lg))); + /* Backward compatibility: falls back to legacy --ck-spacing-standard if overridden. */ + min-width: calc(76px + var(--ck-spacing-standard, var(--ck-spacing-base))); &:not(.ck-widget_selected):not(:hover) { outline: var(--ck-html-object-embed-unfocused-outline-width) dashed var(--ck-color-widget-blurred-border); @@ -25,14 +27,17 @@ position: absolute; content: attr(data-html-object-embed-label); top: 0; - left: var(--ck-spacing-standard); - background: hsl(0deg 0% 60%); + /* Backward compatibility: falls back to legacy --ck-spacing-standard if overridden. */ + left: var(--ck-spacing-standard, var(--ck-spacing-base)); + background: var(--ck-color-base-text-light); transition: background var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve); - padding: calc(var(--ck-spacing-tiny) + var(--ck-html-object-embed-unfocused-outline-width)) var(--ck-spacing-small) var(--ck-spacing-tiny); - border-radius: 0 0 var(--ck-border-radius) var(--ck-border-radius); + padding: calc(var(--ck-spacing-tiny, var(--ck-spacing-xs)) + var(--ck-html-object-embed-unfocused-outline-width)) var(--ck-spacing-small, var(--ck-spacing-sm)) var(--ck-spacing-tiny, var(--ck-spacing-xs)); + /* Backward compatibility: falls back to legacy --ck-border-radius if overridden. */ + border-radius: 0 0 var(--ck-border-radius, var(--ck-radius-base)) var(--ck-border-radius, var(--ck-radius-base)); color: var(--ck-color-base-background); - font-size: var(--ck-font-size-tiny); - font-family: var(--ck-font-face); + font-size: var(--ck-font-size-tiny, var(--ck-font-size-xs)); + /* Backward compatibility: falls back to legacy --ck-font-face if overridden. */ + font-family: var(--ck-font-face, var(--ck-font-family)); } /* Make space for label. */ diff --git a/packages/ckeditor5-image/theme/imagecaption.css b/packages/ckeditor5-image/theme/imagecaption.css index 77f6bbab0d9..90997b436e5 100644 --- a/packages/ckeditor5-image/theme/imagecaption.css +++ b/packages/ckeditor5-image/theme/imagecaption.css @@ -5,6 +5,7 @@ :root { + /* content-layer: pending color palette */ --ck-content-color-image-caption-background: hsl(0, 0%, 97%); --ck-content-color-image-caption-text: hsl(0, 0%, 20%); --ck-color-image-caption-highlighted-background: hsl(52deg 100% 50%); diff --git a/packages/ckeditor5-image/theme/imageinsert.css b/packages/ckeditor5-image/theme/imageinsert.css index a1c2aee1e0c..26fd020d8c1 100644 --- a/packages/ckeditor5-image/theme/imageinsert.css +++ b/packages/ckeditor5-image/theme/imageinsert.css @@ -6,6 +6,9 @@ :root { --ck-image-insert-insert-by-url-width: 250px; + + /* Spacing */ + --ck-image-insert-form-padding: 0; } .ck.ck-image-insert-url { @@ -13,8 +16,8 @@ width: 400px; & .ck-image-insert-url__action-row { - grid-column-gap: var(--ck-spacing-large); - margin-top: var(--ck-spacing-large); + grid-column-gap: var(--ck-spacing-large, var(--ck-spacing-lg)); + margin-top: var(--ck-spacing-large, var(--ck-spacing-lg)); display: grid; & .ck-button-save, @@ -28,10 +31,12 @@ } grid-template-columns: repeat(2, 1fr) } - padding: var(--ck-spacing-large) var(--ck-spacing-large) 0 + padding: var(--ck-spacing-large, var(--ck-spacing-lg)) var(--ck-spacing-large, var(--ck-spacing-lg)) 0 } .ck.ck-image-insert-form { + padding: var(--ck-image-insert-form-padding); + & > .ck.ck-button { display: block; width: 100%; @@ -60,7 +65,7 @@ /* This is the case when there are no other integrations configured than insert by URL */ & > .ck.ck-image-insert-url { min-width: var(--ck-image-insert-insert-by-url-width); - padding: var(--ck-spacing-large); + padding: var(--ck-spacing-large, var(--ck-spacing-lg)); } &:focus { diff --git a/packages/ckeditor5-image/theme/imageresize.css b/packages/ckeditor5-image/theme/imageresize.css index 3ac9347827f..9495df012d0 100644 --- a/packages/ckeditor5-image/theme/imageresize.css +++ b/packages/ckeditor5-image/theme/imageresize.css @@ -41,11 +41,11 @@ } [dir="ltr"] .ck.ck-button.ck-button_with-text.ck-resize-image-button .ck-button__icon { - margin-right: var(--ck-spacing-standard); + margin-right: var(--ck-spacing-standard, var(--ck-spacing-base)); } [dir="rtl"] .ck.ck-button.ck-button_with-text.ck-resize-image-button .ck-button__icon { - margin-left: var(--ck-spacing-standard); + margin-left: var(--ck-spacing-standard, var(--ck-spacing-base)); } .ck.ck-dropdown .ck-button.ck-resize-image-button .ck-button__label { diff --git a/packages/ckeditor5-image/theme/imageuploadicon.css b/packages/ckeditor5-image/theme/imageuploadicon.css index 931d0bf4d08..b1384bc6d29 100644 --- a/packages/ckeditor5-image/theme/imageuploadicon.css +++ b/packages/ckeditor5-image/theme/imageuploadicon.css @@ -4,8 +4,8 @@ */ :root { - --ck-color-image-upload-icon: hsl(0, 0%, 100%); - --ck-color-image-upload-icon-background: hsl(120, 100%, 27%); + --ck-color-image-upload-icon: var(--ck-color-base-background); + --ck-color-image-upload-icon-background: var(--ck-color-base-success); /* Match the icon size with the linked image indicator brought by the link image feature. */ --ck-image-upload-icon-size: 20; @@ -40,8 +40,8 @@ * Smaller images should have the icon closer to the border. * Match the icon position with the linked image indicator brought by the link image feature. */ - top: min(var(--ck-spacing-medium), 6%); - right: min(var(--ck-spacing-medium), 6%); + top: min(var(--ck-spacing-medium, var(--ck-spacing-md)), 6%); + right: min(var(--ck-spacing-medium, var(--ck-spacing-md)), 6%); border-radius: 50%; /* This is check icon element made from border-width mixed with animations. */ diff --git a/packages/ckeditor5-link/theme/link.css b/packages/ckeditor5-link/theme/link.css index 89ea331c74a..5a73ad31d2e 100644 --- a/packages/ckeditor5-link/theme/link.css +++ b/packages/ckeditor5-link/theme/link.css @@ -27,5 +27,5 @@ height: 100%; border-right: 1px solid var(--ck-color-base-text); margin-right: -1px; - outline: solid 1px hsla(0, 0%, 100%, .5); + outline: var(--ck-outline-fake-caret); } diff --git a/packages/ckeditor5-link/theme/linkform.css b/packages/ckeditor5-link/theme/linkform.css index d9bc86288e6..d638e395892 100644 --- a/packages/ckeditor5-link/theme/linkform.css +++ b/packages/ckeditor5-link/theme/linkform.css @@ -9,7 +9,7 @@ /* The height of the text inside the link providers list button. */ --ck-link-provider-list-item-text-height: calc(var(--ck-line-height-base) * var(--ck-font-size-base)); /* The height of the link providers list item contained paddings. */ - --ck-link-provider-list-item-height: calc(var(--ck-link-provider-list-item-text-height) + var(--ck-spacing-small) + var(--ck-spacing-small)); + --ck-link-provider-list-item-height: calc(var(--ck-link-provider-list-item-text-height) + var(--ck-spacing-small, var(--ck-spacing-sm)) + var(--ck-spacing-small, var(--ck-spacing-sm))); } @media screen and (max-width: 600px) { @@ -41,13 +41,13 @@ &:has(.ck-list__item:nth-child(n + 5)) { overflow: auto; /* Scroll should appear when there are more than 5 item on the list. - * var(--ck-spacing-large) - is a form padding. + * var(--ck-spacing-large, var(--ck-spacing-lg)) - is a form padding. * 1px - is a border width. */ - max-height: calc(var(--ck-link-provider-list-item-height) * 4 + var(--ck-spacing-large) + 1px); + max-height: calc(var(--ck-link-provider-list-item-height) * 4 + var(--ck-spacing-large, var(--ck-spacing-lg)) + 1px); } & .ck-link__button { - padding: var(--ck-spacing-small) var(--ck-spacing-large); + padding: var(--ck-spacing-small, var(--ck-spacing-sm)) var(--ck-spacing-large, var(--ck-spacing-lg)); border-radius: 0; & > .ck-button__label { diff --git a/packages/ckeditor5-link/theme/linkimage.css b/packages/ckeditor5-link/theme/linkimage.css index 177ba619801..0ebc571061a 100644 --- a/packages/ckeditor5-link/theme/linkimage.css +++ b/packages/ckeditor5-link/theme/linkimage.css @@ -20,8 +20,8 @@ * Smaller images should have the icon closer to the border. * Match the icon position with the upload indicator brought by the image upload feature. */ - top: min(var(--ck-spacing-medium), 6%); - right: min(var(--ck-spacing-medium), 6%); + top: min(var(--ck-spacing-medium, var(--ck-spacing-md)), 6%); + right: min(var(--ck-spacing-medium, var(--ck-spacing-md)), 6%); background-color: hsla(0, 0%, 0%, .4); background-image: url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjAgMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI2ZmZiIgZD0ibTExLjA3NyAxNSAuOTkxLTEuNDE2YS43NS43NSAwIDEgMSAxLjIyOS44NmwtMS4xNDggMS42NGEuNzQ4Ljc0OCAwIDAgMS0uMjE3LjIwNiA1LjI1MSA1LjI1MSAwIDAgMS04LjUwMy01Ljk1NS43NDEuNzQxIDAgMCAxIC4xMi0uMjc0bDEuMTQ3LTEuNjM5YS43NS43NSAwIDEgMSAxLjIyOC44Nkw0LjkzMyAxMC43bC4wMDYuMDAzYTMuNzUgMy43NSAwIDAgMCA2LjEzMiA0LjI5NGwuMDA2LjAwNHptNS40OTQtNS4zMzVhLjc0OC43NDggMCAwIDEtLjEyLjI3NGwtMS4xNDcgMS42MzlhLjc1Ljc1IDAgMSAxLTEuMjI4LS44NmwuODYtMS4yM2EzLjc1IDMuNzUgMCAwIDAtNi4xNDQtNC4zMDFsLS44NiAxLjIyOWEuNzUuNzUgMCAwIDEtMS4yMjktLjg2bDEuMTQ4LTEuNjRhLjc0OC43NDggMCAwIDEgLjIxNy0uMjA2IDUuMjUxIDUuMjUxIDAgMCAxIDguNTAzIDUuOTU1em0tNC41NjMtMi41MzJhLjc1Ljc1IDAgMCAxIC4xODQgMS4wNDVsLTMuMTU1IDQuNTA1YS43NS43NSAwIDEgMS0xLjIyOS0uODZsMy4xNTUtNC41MDZhLjc1Ljc1IDAgMCAxIDEuMDQ1LS4xODR6Ii8+PC9zdmc+"); diff --git a/packages/ckeditor5-link/theme/linkprovideritems.css b/packages/ckeditor5-link/theme/linkprovideritems.css index fbb185a597c..0ae88639e26 100644 --- a/packages/ckeditor5-link/theme/linkprovideritems.css +++ b/packages/ckeditor5-link/theme/linkprovideritems.css @@ -46,7 +46,7 @@ } & .ck-link__empty-list-info { - padding: calc( 2 * var(--ck-spacing-large) ) var(--ck-spacing-medium); + padding: calc( 2 * var(--ck-spacing-large, var(--ck-spacing-lg)) ) var(--ck-spacing-medium, var(--ck-spacing-md)); text-align: center; font-style: italic; } diff --git a/packages/ckeditor5-link/theme/linktoolbar.css b/packages/ckeditor5-link/theme/linktoolbar.css index 999660870ea..0f8e8abb4b5 100644 --- a/packages/ckeditor5-link/theme/linktoolbar.css +++ b/packages/ckeditor5-link/theme/linktoolbar.css @@ -15,7 +15,7 @@ } a.ck.ck-button.ck-link-toolbar__preview { - padding: 0 var(--ck-spacing-medium); + padding: 0 var(--ck-spacing-medium, var(--ck-spacing-md)); color: var(--ck-color-link-default); cursor: pointer; justify-content: center; @@ -49,18 +49,18 @@ a.ck.ck-button.ck-link-toolbar__preview { height: var(--ck-link-bookmark-icon-size); [dir="ltr"] & { - margin-right: var(--ck-spacing-tiny); - margin-left: var(--ck-spacing-small); + margin-right: var(--ck-spacing-tiny, var(--ck-spacing-xs)); + margin-left: var(--ck-spacing-small, var(--ck-spacing-sm)); } [dir="rtl"] & { - margin-left: var(--ck-spacing-tiny); - margin-right: var(--ck-spacing-small); + margin-left: var(--ck-spacing-tiny, var(--ck-spacing-xs)); + margin-right: var(--ck-spacing-small, var(--ck-spacing-sm)); } } &:has( .ck-icon ) { - padding-left: var(--ck-spacing-extra-tiny ); + padding-left: var(--ck-spacing-extra-tiny, var(--ck-spacing-2xs)); } } diff --git a/packages/ckeditor5-list/theme/listproperties.css b/packages/ckeditor5-list/theme/listproperties.css index 5ead79f91ef..15c6b1d9636 100644 --- a/packages/ckeditor5-list/theme/listproperties.css +++ b/packages/ckeditor5-list/theme/listproperties.css @@ -6,13 +6,13 @@ .ck.ck-list-properties { /* When there are no list styles and there is no collapsible. */ &.ck-list-properties_without-styles { - padding: var(--ck-spacing-large); + padding: var(--ck-spacing-large, var(--ck-spacing-lg)); & > * { min-width: 14em; & + * { - margin-top: var(--ck-spacing-standard); + margin-top: var(--ck-spacing-standard, var(--ck-spacing-base)); } } } @@ -28,14 +28,14 @@ /* When list styles are rendered and property fields are in a collapsible. */ & > .ck-collapsible { - border-top: 1px solid var(--ck-color-base-border); + border-top: var(--ck-border-width-thin) solid var(--ck-color-base-border); & > .ck-collapsible__children { & > * { width: 100%; & + * { - margin-top: var(--ck-spacing-standard); + margin-top: var(--ck-spacing-standard, var(--ck-spacing-base)); } } } @@ -51,7 +51,7 @@ background: transparent; padding-left: 0; padding-right: 0; - margin-bottom: calc(-1 * var(--ck-spacing-tiny)); + margin-bottom: calc(-1 * var(--ck-spacing-tiny, var(--ck-spacing-xs))); &:active, &:hover { box-shadow: none; diff --git a/packages/ckeditor5-list/theme/liststyles.css b/packages/ckeditor5-list/theme/liststyles.css index 4b9515c53aa..622ead512cf 100644 --- a/packages/ckeditor5-list/theme/liststyles.css +++ b/packages/ckeditor5-list/theme/liststyles.css @@ -9,9 +9,9 @@ .ck.ck-list-styles-list { grid-template-columns: repeat( 3, auto ); - row-gap: var(--ck-spacing-medium); - column-gap: var(--ck-spacing-medium); - padding: var(--ck-spacing-large); + row-gap: var(--ck-spacing-medium, var(--ck-spacing-md)); + column-gap: var(--ck-spacing-medium, var(--ck-spacing-md)); + padding: var(--ck-spacing-large, var(--ck-spacing-lg)); & .ck-button { /* Make the button look like a thumbnail (the icon "takes it all"). */ diff --git a/packages/ckeditor5-list/theme/todolist.css b/packages/ckeditor5-list/theme/todolist.css index baa2159faed..8e3aa6ec83a 100644 --- a/packages/ckeditor5-list/theme/todolist.css +++ b/packages/ckeditor5-list/theme/todolist.css @@ -4,6 +4,7 @@ */ :root { + /* content-layer: pending color palette */ --ck-content-todo-list-checkmark-size: 16px; } diff --git a/packages/ckeditor5-mention/theme/mention.css b/packages/ckeditor5-mention/theme/mention.css index d59f44ab733..37e74a233f2 100644 --- a/packages/ckeditor5-mention/theme/mention.css +++ b/packages/ckeditor5-mention/theme/mention.css @@ -4,6 +4,7 @@ */ :root { + /* content-layer: pending color palette */ --ck-content-color-mention-background: hsla(341, 100%, 30%, 0.1); --ck-content-color-mention-text: hsl(341, 100%, 30%); } diff --git a/packages/ckeditor5-mention/theme/mentionui.css b/packages/ckeditor5-mention/theme/mentionui.css index 27f37272a45..3c4fcb3fb19 100644 --- a/packages/ckeditor5-mention/theme/mentionui.css +++ b/packages/ckeditor5-mention/theme/mentionui.css @@ -27,5 +27,6 @@ } div.ck.ck-balloon-panel.ck-mention-balloon { - z-index: calc( var( --ck-z-dialog ) + 1 ); + /* Backward compatibility: falls back to legacy --ck-z-dialog if overridden. */ + z-index: calc( var( --ck-z-dialog, var(--ck-z-modal) ) + 1 ); } diff --git a/packages/ckeditor5-page-break/theme/pagebreak.css b/packages/ckeditor5-page-break/theme/pagebreak.css index 8d54aa3e87c..980d9f381d1 100644 --- a/packages/ckeditor5-page-break/theme/pagebreak.css +++ b/packages/ckeditor5-page-break/theme/pagebreak.css @@ -3,6 +3,7 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +/* content-layer: pending color palette */ .ck-content .page-break { position: relative; clear: both; diff --git a/packages/ckeditor5-restricted-editing/theme/restrictedediting.css b/packages/ckeditor5-restricted-editing/theme/restrictedediting.css index 9044531e4f1..f45d529026c 100644 --- a/packages/ckeditor5-restricted-editing/theme/restrictedediting.css +++ b/packages/ckeditor5-restricted-editing/theme/restrictedediting.css @@ -4,6 +4,7 @@ */ :root { + /* content-layer: pending color palette */ --ck-color-restricted-editing-exception-background: hsla(31, 100%, 65%, .2); --ck-color-restricted-editing-exception-hover-background: hsla(31, 100%, 65%, .35); --ck-color-restricted-editing-exception-brackets: hsla(31, 100%, 40%, .4); diff --git a/packages/ckeditor5-show-blocks/theme/showblocks.css b/packages/ckeditor5-show-blocks/theme/showblocks.css index 228e98c4e24..34e7f007ba8 100644 --- a/packages/ckeditor5-show-blocks/theme/showblocks.css +++ b/packages/ckeditor5-show-blocks/theme/showblocks.css @@ -4,7 +4,7 @@ */ :root { - --ck-show-blocks-border-color: hsl(0, 0%, 46%); + --ck-show-blocks-border-color: var(--ck-color-base-text-light); } .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) { diff --git a/packages/ckeditor5-source-editing/theme/sourceediting.css b/packages/ckeditor5-source-editing/theme/sourceediting.css index c2db6a41ae5..1939ea5c30b 100644 --- a/packages/ckeditor5-source-editing/theme/sourceediting.css +++ b/packages/ckeditor5-source-editing/theme/sourceediting.css @@ -10,11 +10,11 @@ .ck-source-editing-area::after, .ck-source-editing-area textarea { - padding: var(--ck-spacing-large); + padding: var(--ck-spacing-large, var(--ck-spacing-lg)); margin: 0; border: 1px solid transparent; line-height: var(--ck-line-height-base); - font-size: var(--ck-font-size-normal); + font-size: var(--ck-font-size-normal, var(--ck-font-size-md)); font-family: monospace; white-space: pre-wrap; } @@ -34,13 +34,13 @@ overflow: hidden; box-sizing: border-box; border-color: var(--ck-color-base-border); - border-radius: var(--ck-rounded-corners-radius); + border-radius: var(--ck-rounded-corners-radius, var(--ck-radius-corners)); border-top-left-radius: 0; border-top-right-radius: 0; &:not([readonly]):focus { outline: none; - border: var(--ck-focus-ring); - box-shadow: var(--ck-inner-shadow), 0 0; + border: var(--ck-focus-ring, var(--ck-interactive-focus-ring)); + box-shadow: var(--ck-inner-shadow, var(--ck-inset-shadow-sm)), 0 0; } } diff --git a/packages/ckeditor5-style/theme/stylegrid.css b/packages/ckeditor5-style/theme/stylegrid.css index a7230b5f73e..8378932d731 100644 --- a/packages/ckeditor5-style/theme/stylegrid.css +++ b/packages/ckeditor5-style/theme/stylegrid.css @@ -6,15 +6,15 @@ :root { --ck-style-panel-button-width: 120px; --ck-style-panel-button-height: 80px; - --ck-style-panel-button-label-background: hsl(0, 0%, 94.1%); + --ck-style-panel-button-label-background: var(--ck-color-base-hover); --ck-style-panel-button-hover-label-background: hsl(0, 0%, 92.1%); --ck-style-panel-button-hover-border-color: hsl(0, 0%, 70%); --ck-style-panel-columns: 3; } .ck.ck-style-panel .ck-style-grid { - row-gap: var(--ck-spacing-large); - column-gap: var(--ck-spacing-large); + row-gap: var(--ck-spacing-large, var(--ck-spacing-lg)); + column-gap: var(--ck-spacing-large, var(--ck-spacing-lg)); display: grid; grid-template-columns: repeat(var(--ck-style-panel-columns),auto); @@ -37,7 +37,7 @@ height: 22px; line-height: 22px; width: 100%; - padding: 0 var(--ck-spacing-medium); + padding: 0 var(--ck-spacing-medium, var(--ck-spacing-md)); overflow: hidden; text-overflow: ellipsis; flex-shrink: 0; @@ -48,7 +48,7 @@ overflow: hidden; opacity: .9; - padding: var(--ck-spacing-medium); + padding: var(--ck-spacing-medium, var(--ck-spacing-md)); background: var(--ck-color-base-background); border: 2px solid var(--ck-color-base-background); display: flex; diff --git a/packages/ckeditor5-style/theme/stylegroup.css b/packages/ckeditor5-style/theme/stylegroup.css index a8f190ec9fe..6afc557d9fa 100644 --- a/packages/ckeditor5-style/theme/stylegroup.css +++ b/packages/ckeditor5-style/theme/stylegroup.css @@ -5,7 +5,7 @@ .ck.ck-style-panel .ck-style-panel__style-group { & > .ck-label { - margin: var(--ck-spacing-large) 0; + margin: var(--ck-spacing-large, var(--ck-spacing-lg)) 0; } &:first-child { diff --git a/packages/ckeditor5-style/theme/stylepanel.css b/packages/ckeditor5-style/theme/stylepanel.css index 6d92f06ad2e..df794e9d9f5 100644 --- a/packages/ckeditor5-style/theme/stylepanel.css +++ b/packages/ckeditor5-style/theme/stylepanel.css @@ -8,7 +8,7 @@ } .ck.ck-style-panel { - padding: var(--ck-spacing-large); + padding: var(--ck-spacing-large, var(--ck-spacing-lg)); overflow-y: auto; max-height: var(--ck-style-panel-max-height); } diff --git a/packages/ckeditor5-table/theme/colorinput.css b/packages/ckeditor5-table/theme/colorinput.css index 35d16c29d8f..243d28d6bc7 100644 --- a/packages/ckeditor5-table/theme/colorinput.css +++ b/packages/ckeditor5-table/theme/colorinput.css @@ -53,7 +53,8 @@ } & > .ck.ck-input-color__button__preview { - border-radius: var(--ck-rounded-corners-radius); + /* Backward compatibility: falls back to legacy --ck-rounded-corners-radius if overridden. */ + border-radius: var(--ck-rounded-corners-radius, var(--ck-radius-corners)); width: 20px; height: 20px; border: 1px solid var(--ck-color-input-border); @@ -78,7 +79,7 @@ & .ck.ck-input-color__remove-color { width: 100%; - padding: calc(var(--ck-spacing-standard) / 2) var(--ck-spacing-standard); + padding: calc(var(--ck-spacing-standard, var(--ck-spacing-base)) / 2) var(--ck-spacing-standard, var(--ck-spacing-base)); border-bottom-left-radius: 0; border-bottom-right-radius: 0; @@ -96,11 +97,11 @@ } & .ck.ck-icon { - margin-right: var(--ck-spacing-standard); + margin-right: var(--ck-spacing-standard, var(--ck-spacing-base)); [dir="rtl"] & { margin-right: 0; - margin-left: var(--ck-spacing-standard); + margin-left: var(--ck-spacing-standard, var(--ck-spacing-base)); } } } diff --git a/packages/ckeditor5-table/theme/formrow.css b/packages/ckeditor5-table/theme/formrow.css index ba21c1ded9e..414c08f900f 100644 --- a/packages/ckeditor5-table/theme/formrow.css +++ b/packages/ckeditor5-table/theme/formrow.css @@ -8,7 +8,7 @@ /* Ignore labels that work as fieldset legends */ & > *:not(.ck-label) { & + * { - margin-inline-start: var(--ck-spacing-large); + margin-inline-start: var(--ck-spacing-large, var(--ck-spacing-lg)); } } @@ -18,7 +18,7 @@ } &.ck-table-form__action-row { - margin-top: var(--ck-spacing-large); + margin-top: var(--ck-spacing-large, var(--ck-spacing-lg)); justify-content: flex-end; & .ck-button-save, diff --git a/packages/ckeditor5-table/theme/inserttable.css b/packages/ckeditor5-table/theme/inserttable.css index 08a93a5cb30..d292bf9c9f8 100644 --- a/packages/ckeditor5-table/theme/inserttable.css +++ b/packages/ckeditor5-table/theme/inserttable.css @@ -8,6 +8,7 @@ --ck-insert-table-dropdown-box-height: 11px; --ck-insert-table-dropdown-box-width: 12px; --ck-insert-table-dropdown-box-margin: 1px; + --ck-insert-table-dropdown-box-border-radius: var(--ck-radius-xs); } .ck .ck-insert-table-dropdown__grid { @@ -28,8 +29,8 @@ min-width: var(--ck-insert-table-dropdown-box-width); min-height: var(--ck-insert-table-dropdown-box-height); margin: var(--ck-insert-table-dropdown-box-margin); - border: 1px solid var(--ck-color-base-border); - border-radius: 1px; + border: var(--ck-border-width-thin) solid var(--ck-color-base-border); + border-radius: var(--ck-insert-table-dropdown-box-border-radius); outline: none; transition: none; @@ -42,7 +43,7 @@ } &.ck-on { - border-color: var(--ck-color-focus-border); - background: var(--ck-color-focus-outer-shadow); + border-color: var(--ck-color-focus-border, var(--ck-color-interactive-focus-border)); + background: var(--ck-color-focus-outer-shadow, var(--ck-focus-shadow)); } } diff --git a/packages/ckeditor5-table/theme/tablecaption.css b/packages/ckeditor5-table/theme/tablecaption.css index 4bf60133127..c3bfcb8df9d 100644 --- a/packages/ckeditor5-table/theme/tablecaption.css +++ b/packages/ckeditor5-table/theme/tablecaption.css @@ -5,6 +5,7 @@ :root { + /* content-layer: pending color palette */ --ck-content-color-table-caption-background: hsl(0, 0%, 97%); --ck-content-color-table-caption-text: hsl(0, 0%, 20%); --ck-color-table-caption-highlighted-background: hsl(52deg 100% 50%); diff --git a/packages/ckeditor5-table/theme/tablecellproperties.css b/packages/ckeditor5-table/theme/tablecellproperties.css index c80eace6bc5..49b5a588453 100644 --- a/packages/ckeditor5-table/theme/tablecellproperties.css +++ b/packages/ckeditor5-table/theme/tablecellproperties.css @@ -18,10 +18,10 @@ background: none; /* Compensate for missing input label that would push the margin (toolbar has no inputs). */ - margin-top: var(--ck-spacing-standard); + margin-top: var(--ck-spacing-standard, var(--ck-spacing-base)); &.ck-table-cell-properties-form__horizontal-alignment-toolbar { - --ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large)); + --ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large, var(--ck-spacing-lg))); width: var(--ck-table-form-dimensions-input-width); max-width: var(--ck-table-form-dimensions-input-width); @@ -52,7 +52,7 @@ &.ck-table-form__border-row { & .ck-labeled-field-view { & > .ck-label { - font-size: var(--ck-font-size-tiny); + font-size: var(--ck-font-size-tiny, var(--ck-font-size-xs)); text-align: center; } } @@ -66,7 +66,7 @@ } &.ck-table-form__dimensions-row { - --ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large)); + --ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large, var(--ck-spacing-lg))); width: var(--ck-table-form-dimensions-input-width); max-width: var(--ck-table-form-dimensions-input-width); @@ -88,9 +88,9 @@ overflow: visible; align-self: flex-end; display: inline-block; - height: var(--ck-ui-component-min-height); - line-height: var(--ck-ui-component-min-height); - margin: 0 var(--ck-spacing-small); + height: var(--ck-ui-component-min-height, var(--ck-size-min-height)); + line-height: var(--ck-ui-component-min-height, var(--ck-size-min-height)); + margin: 0 var(--ck-spacing-small, var(--ck-spacing-sm)); } } @@ -105,7 +105,7 @@ } &.ck-table-form__cell-type-row { - --ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large)); + --ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large, var(--ck-spacing-lg))); width: var(--ck-table-form-dimensions-input-width); max-width: var(--ck-table-form-dimensions-input-width); diff --git a/packages/ckeditor5-table/theme/tablecolumnresize.css b/packages/ckeditor5-table/theme/tablecolumnresize.css index e39f039781f..ffd847cd401 100644 --- a/packages/ckeditor5-table/theme/tablecolumnresize.css +++ b/packages/ckeditor5-table/theme/tablecolumnresize.css @@ -37,7 +37,7 @@ width: var(--ck-table-column-resizer-width); cursor: col-resize; user-select: none; - z-index: var(--ck-z-default); + z-index: var(--ck-z-default, var(--ck-z-base)); } .ck.ck-editor__editable.ck-column-resize_disabled .table .ck-table-column-resizer { diff --git a/packages/ckeditor5-table/theme/tableediting.css b/packages/ckeditor5-table/theme/tableediting.css index c0d694c6e6f..2c28d64284c 100644 --- a/packages/ckeditor5-table/theme/tableediting.css +++ b/packages/ckeditor5-table/theme/tableediting.css @@ -8,7 +8,7 @@ --ck-table-content-default-border-color: hsl(0, 0%, 83%); --ck-table-border-none-helper-line-color: hsl(0, 0%, 83%); --ck-table-border-none-helper-line-style: dashed; - --ck-table-border-none-helper-line-width: 1px; + --ck-table-border-none-helper-line-width: var(--ck-border-width-thin); } .ck-widget.table { @@ -36,7 +36,7 @@ &:focus { /* A very slight background to highlight the focused cell */ background: var(--ck-color-table-focused-cell-background); - outline: 1px solid var(--ck-color-focus-border); + outline: 1px solid var(--ck-color-focus-border, var(--ck-color-interactive-focus-border)); outline-offset: -1px; /* progressive enhancement - no IE support */ } } diff --git a/packages/ckeditor5-table/theme/tableform.css b/packages/ckeditor5-table/theme/tableform.css index 3aa1997dab9..27c3f06206c 100644 --- a/packages/ckeditor5-table/theme/tableform.css +++ b/packages/ckeditor5-table/theme/tableform.css @@ -15,7 +15,7 @@ &.ck-table-form__border-row { & .ck-labeled-field-view { & > .ck-label { - font-size: var(--ck-font-size-tiny); + font-size: var(--ck-font-size-tiny, var(--ck-font-size-xs)); text-align: center; } } @@ -29,7 +29,7 @@ } &.ck-table-form__dimensions-row { - --ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large)); + --ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large, var(--ck-spacing-lg))); width: var(--ck-table-form-dimensions-input-width); max-width: var(--ck-table-form-dimensions-input-width); @@ -51,9 +51,9 @@ overflow: visible; align-self: flex-end; display: inline-block; - height: var(--ck-ui-component-min-height); - line-height: var(--ck-ui-component-min-height); - margin: 0 var(--ck-spacing-small); + height: var(--ck-ui-component-min-height, var(--ck-size-min-height)); + line-height: var(--ck-ui-component-min-height, var(--ck-size-min-height)); + margin: 0 var(--ck-spacing-small, var(--ck-spacing-sm)); } } &.ck-table-form__border-row, @@ -86,13 +86,13 @@ } & .ck.ck-labeled-field-view { - padding-top: var(--ck-spacing-standard); + padding-top: var(--ck-spacing-standard, var(--ck-spacing-base)); & .ck.ck-labeled-field-view__status { - border-radius: var(--ck-rounded-corners-radius); + border-radius: var(--ck-rounded-corners-radius, var(--ck-radius-corners)); background: var(--ck-color-base-error); color: var(--ck-color-base-background); - padding: var(--ck-spacing-small) var(--ck-spacing-medium); + padding: var(--ck-spacing-small, var(--ck-spacing-sm)) var(--ck-spacing-medium, var(--ck-spacing-md)); min-width: var(--ck-table-properties-min-error-width); text-align: center; diff --git a/packages/ckeditor5-table/theme/tablelayout.css b/packages/ckeditor5-table/theme/tablelayout.css index 766ee716ae6..d5ee7d93ada 100644 --- a/packages/ckeditor5-table/theme/tablelayout.css +++ b/packages/ckeditor5-table/theme/tablelayout.css @@ -97,7 +97,7 @@ outline-offset: -1px; &:focus { - outline: var(--ck-color-focus-border) 1px solid; + outline: var(--ck-color-focus-border, var(--ck-color-interactive-focus-border)) 1px solid; } } @@ -177,7 +177,7 @@ &:hover { /* To prevent the widget outline from being cut off at the bottom when the next cell or table has a background color, for example. */ - z-index: var(--ck-z-default); + z-index: var(--ck-z-default, var(--ck-z-base)); } &:hover > .ck-widget__selection-handle { @@ -200,7 +200,7 @@ &.ck-widget_selected { /* To prevent the widget outline from being cut off at the bottom when the next cell or table has a background color, for example. */ - z-index: var(--ck-z-default); + z-index: var(--ck-z-default, var(--ck-z-base)); } } display: table; @@ -211,7 +211,7 @@ &.ck-editor__editable_inline { & > .ck-widget.ck-widget_with-selection-handle.layout-table { &:first-child { - margin-top: var(--ck-spacing-large); + margin-top: var(--ck-spacing-large, var(--ck-spacing-lg)); } /* * This value should match with the default margins of the block elements (like .media, .image or .table) @@ -220,7 +220,7 @@ &:last-child, /* Fallback for hidden fake selection div */ &:nth-last-child(2):has( + .ck-fake-selection-container) { - margin-bottom: var(--ck-spacing-large); + margin-bottom: var(--ck-spacing-large, var(--ck-spacing-lg)); } } } diff --git a/packages/ckeditor5-table/theme/tableproperties.css b/packages/ckeditor5-table/theme/tableproperties.css index 476226bfc58..84b531eb123 100644 --- a/packages/ckeditor5-table/theme/tableproperties.css +++ b/packages/ckeditor5-table/theme/tableproperties.css @@ -17,7 +17,7 @@ background: none; /* Compensate for missing input label that would push the margin (toolbar has no inputs). */ - margin-top: var(--ck-spacing-standard); + margin-top: var(--ck-spacing-standard, var(--ck-spacing-base)); & .ck-toolbar__items > * { flex: 1; diff --git a/packages/ckeditor5-ui/docs/framework/external-ui.md b/packages/ckeditor5-ui/docs/framework/external-ui.md index a066da025eb..d5d7f022bb1 100644 --- a/packages/ckeditor5-ui/docs/framework/external-ui.md +++ b/packages/ckeditor5-ui/docs/framework/external-ui.md @@ -2,7 +2,7 @@ category: framework-deep-dive-ui meta-title: Third party UI | CKEditor 5 Framework Documentation meta-description: Discover how to create and integrate external UI components with CKEditor 5 for seamless editor extension and customization. -order: 20 +order: 30 --- # Third-party UI diff --git a/packages/ckeditor5-ui/docs/framework/theme-customization.md b/packages/ckeditor5-ui/docs/framework/theme-customization.md index 0260ab2346c..d7fd5d4c817 100644 --- a/packages/ckeditor5-ui/docs/framework/theme-customization.md +++ b/packages/ckeditor5-ui/docs/framework/theme-customization.md @@ -20,106 +20,104 @@ Below you can see a demo of an editor with the dark theme as a result of customi ## Customization with CSS variables -Assuming you finished our {@link getting-started/integrations-cdn/quick-start quick start} guide, and you have a running CKEditor 5 instance, let's use the full potential of CSS variables (custom properties). The customization explained in this guide will make the theme dark, with slightly bigger text and more rounded corners. +Assuming you finished our {@link getting-started/integrations-cdn/quick-start quick start} guide, and you have a running CKEditor 5 instance, you can customize the UI theme through CSS variables (custom properties). -The file containing custom variables can be named `custom.css` and it will look as below: - -```css -:root { - /* Helper variables to avoid duplication in the colors. */ - - --ck-custom-foreground: hsl(255, 3%, 18%); - --ck-custom-border: hsl(300, 1%, 22%); - --ck-custom-white: hsl(0, 0%, 100%); - - /* -- Overrides generic colors. ------------------------------------------------------------- */ - - --ck-content-font-color: var(--ck-custom-white); - - --ck-color-base-background: hsl(270, 1%, 29%); - --ck-color-base-border: hsl(240, 4%, 24%); - - --ck-color-focus-border: hsl(208, 90%, 62%); - --ck-color-text: hsl(0, 0%, 98%); - --ck-color-shadow-drop: hsla(0, 0%, 0%, 0.2); - --ck-color-shadow-inner: hsla(0, 0%, 0%, 0.1); - - /* -- Overrides the default .ck-button class colors. ---------------------------------------- */ - - --ck-color-button-default-hover-background: hsl(270, 1%, 22%); - --ck-color-button-default-active-background: hsl(270, 2%, 20%); - --ck-color-button-default-active-shadow: hsl(270, 2%, 23%); - - --ck-color-button-on-background: var(--ck-custom-foreground); - --ck-color-button-on-hover-background: hsl(255, 4%, 16%); - --ck-color-button-on-active-background: hsl(255, 4%, 14%); - --ck-color-button-on-active-shadow: hsl(240, 3%, 19%); - --ck-color-button-on-disabled-background: var(--ck-custom-foreground); - - --ck-color-button-action-background: hsl(168, 76%, 42%); - --ck-color-button-action-hover-background: hsl(168, 76%, 38%); - --ck-color-button-action-active-background: hsl(168, 76%, 36%); - --ck-color-button-action-active-shadow: hsl(168, 75%, 34%); - --ck-color-button-action-disabled-background: hsl(168, 76%, 42%); - --ck-color-button-action-text: var(--ck-custom-white); - - --ck-color-button-save: hsl(120, 100%, 46%); - --ck-color-button-cancel: hsl(15, 100%, 56%); - - /* -- Overrides the default .ck-dropdown class colors. -------------------------------------- */ - - --ck-color-dropdown-panel-border: var(--ck-custom-foreground); - - /* -- Overrides the default .ck-dialog class colors. ----------------------------------- */ - - --ck-color-dialog-form-header-border: var(--ck-custom-border); +The UI theme uses a 3-layer token model: - /* -- Overrides the default .ck-splitbutton class colors. ----------------------------------- */ +| Layer | Purpose | Typical usage | +| --- | --- | --- | +| Foundation | Low-level primitives (base colors, base radius, spacing scale). | Set global palette, density, and shape scale. | +| Semantic | Reusable UI roles (surface, border, interactive, text, layout). | Define design intent shared across many components. | +| Component | Tokens for a specific component contract. | Adjust one component without changing all others. | - --ck-color-split-button-hover-background: var(--ck-color-button-default-hover-background); - --ck-color-split-button-hover-border: var(--ck-custom-foreground); +A practical rule: +1. Start with semantic tokens. +2. Use component tokens for local exceptions. +3. Change foundation tokens when you want a global visual shift. - /* -- Overrides the default .ck-input class colors. ----------------------------------------- */ + + Legacy compatibility aliases are still available, but for new customizations prefer semantic and component tokens. + - --ck-color-input-border: hsl(257, 3%, 43%); - --ck-color-input-text: hsl(0, 0%, 98%); - --ck-color-input-disabled-background: hsl(255, 4%, 21%); - --ck-color-input-disabled-border: hsl(250, 3%, 38%); - --ck-color-input-disabled-text: hsl(0, 0%, 78%); - - /* -- Overrides the default .ck-list class colors. ------------------------------------------ */ - - --ck-color-list-button-hover-background: var(--ck-custom-foreground); - --ck-color-list-button-on-background: hsl(208, 88%, 52%); - --ck-color-list-button-on-text: var(--ck-custom-white); - - /* -- Overrides the default .ck-balloon-panel class colors. --------------------------------- */ - - --ck-color-panel-border: var(--ck-custom-border); - - /* -- Overrides the default .ck-toolbar class colors. --------------------------------------- */ - - --ck-color-toolbar-border: var(--ck-custom-border); - - /* -- Overrides the default .ck-tooltip class colors. --------------------------------------- */ - - --ck-color-tooltip-background: hsl(252, 7%, 14%); - --ck-color-tooltip-text: hsl(0, 0%, 93%); - - /* -- Overrides the default colors used by the ckeditor5-image package. --------------------- */ - - --ck-content-color-image-caption-background: hsl(0, 0%, 97%); - --ck-content-color-image-caption-text: hsl(0, 0%, 20%); - - /* -- Overrides the default colors used by the ckeditor5-widget package. -------------------- */ - - --ck-color-widget-blurred-border: hsl(0, 0%, 87%); - --ck-color-widget-hover-border: hsl(43, 100%, 68%); - --ck-color-widget-editable-focus-background: var(--ck-custom-white); +The file containing custom variables can be named `custom.css` and it will look as below: - /* -- Overrides the default colors used by the ckeditor5-link package. ---------------------- */ +```css +:root { + /* Optional app palette helpers (outside CKEditor token layers). */ + --app-surface-1: hsl(255, 3%, 18%); + --app-surface-2: hsl(255, 4%, 16%); + --app-surface-3: hsl(240, 4%, 24%); + --app-text-1: hsl(0, 0%, 98%); + --app-text-2: hsl(0, 0%, 78%); + --app-focus-hsl: 208, 90%, 62%; + --app-brand: hsl(168, 76%, 42%); + --app-brand-hover: hsl(168, 76%, 38%); + --app-brand-contrast: hsl(0, 0%, 100%); + + /* ----------------------------------------------------------------- + * 1) FOUNDATION TOKENS + * ----------------------------------------------------------------- */ + --ck-font-size-base: 14px; + --ck-spacing-unit: 0.65em; + --ck-radius-base: 6px; + + --ck-color-base-background: var(--app-surface-1); + --ck-color-base-border: var(--app-surface-3); + --ck-color-base-text: var(--app-text-1); + --ck-color-base-action: var(--app-brand); + --ck-color-base-error: hsl(10, 90%, 62%); + + /* ----------------------------------------------------------------- + * 2) SEMANTIC TOKENS + * ----------------------------------------------------------------- */ + --ck-color-surface-canvas: var(--app-surface-1); + --ck-color-surface-control: var(--app-surface-1); + --ck-color-surface-container: var(--app-surface-1); + --ck-color-surface-inverse: hsl(252, 7%, 14%); + + --ck-color-border-control: var(--app-surface-3); + --ck-color-border-container: var(--app-surface-3); + --ck-color-divider: var(--app-surface-3); + + --ck-color-text-primary: var(--app-text-1); + --ck-color-text-secondary: hsl(0, 0%, 86%); + --ck-color-text-disabled: var(--app-text-2); + --ck-color-text-inverse: var(--app-brand-contrast); + + --ck-color-interactive-focus-border-coordinates: var(--app-focus-hsl); + --ck-color-interactive-focus-shadow: hsla(208, 90%, 62%, .28); + --ck-color-interactive-hover-surface: var(--app-surface-2); + --ck-color-interactive-active-surface: hsl(255, 4%, 14%); + --ck-color-interactive-selected-surface: hsl(208, 40%, 20%); + --ck-color-interactive-selected-surface-hover: hsl(208, 42%, 24%); + --ck-color-interactive-selected-text: hsl(205, 100%, 74%); + --ck-color-interactive-primary-surface: var(--app-brand); + --ck-color-interactive-primary-surface-hover: var(--app-brand-hover); + --ck-color-interactive-primary-text: var(--app-brand-contrast); + + --ck-border-radius-control: 6px; + --ck-border-radius-surface: 8px; + --ck-shadow-surface-floating: 0 6px 18px 2px hsla(0, 0%, 0%, .35); + + /* ----------------------------------------------------------------- + * 3) COMPONENT TOKENS + * ----------------------------------------------------------------- */ + --ck-button-border-radius: var(--ck-border-radius-control); + --ck-input-border-radius: var(--ck-border-radius-control); + --ck-toolbar-border-radius: var(--ck-border-radius-surface); + --ck-dialog-border-radius: var(--ck-border-radius-surface); + --ck-dialog-background-color: var(--app-surface-1); + --ck-dialog-drop-shadow: 0 10px 24px 2px hsla(0, 0%, 0%, .35); +} - --ck-color-link-default: hsl(190, 100%, 75%); +/* Optional: feature-specific content tokens (outside @ckeditor/ckeditor5-ui theme layers). */ +:root { + --ck-content-color-image-caption-background: hsl(0, 0%, 97%); + --ck-content-color-image-caption-text: hsl(0, 0%, 20%); + --ck-color-widget-blurred-border: hsl(0, 0%, 87%); + --ck-color-widget-hover-border: hsl(43, 100%, 68%); + --ck-color-widget-editable-focus-background: hsl(0, 0%, 100%); + --ck-color-link-default: hsl(190, 100%, 75%); } /* Improve displaying links. */ diff --git a/packages/ckeditor5-ui/docs/framework/theme-token-naming.md b/packages/ckeditor5-ui/docs/framework/theme-token-naming.md new file mode 100644 index 00000000000..f2d1b009837 --- /dev/null +++ b/packages/ckeditor5-ui/docs/framework/theme-token-naming.md @@ -0,0 +1,207 @@ +--- +category: framework-deep-dive-ui +meta-title: Theme token naming guide | CKEditor 5 Framework Documentation +meta-description: Learn the naming conventions for foundation, semantic, and component CSS variables in the CKEditor 5 UI theme and apply them consistently. +order: 20 +--- + +# Theme token naming guide + +This guide defines naming conventions for CSS variables in `@ckeditor/ckeditor5-ui` theme files. + +The goal is to keep tokens: +- easy to scan, +- consistent across files, +- easy to map to design tools (for example Figma), +- easy to override by integrators. + +## Layer model + +Use three layers: + +| Layer | Purpose | Where | +| --- | --- | --- | +| Foundation | Low-level primitives (scale, base colors, base geometry). | `theme/globals/_*.css`, `theme/globals/colors/_foundation.css` | +| Semantic | Design-intent roles shared across components. | `theme/globals/_semantic-*.css`, `theme/globals/colors/_semantic-*.css` | +| Component | Component-specific API and variants. | `theme/components/**/**.css` | + +Legacy compatibility tokens are allowed only in dedicated legacy files. + +## Naming formats + +### Foundation + +Use primitive domain + value scale: + +`--ck-{domain}-{property?}-{scale}` + +Examples: +- `--ck-spacing-sm` +- `--ck-font-size-base` +- `--ck-font-weight-bold` +- `--ck-color-base-border` +- `--ck-color-base-hover` +- `--ck-color-base-success` +- `--ck-radius-base`, `--ck-radius-corners` +- `--ck-shadow-md` +- `--ck-z-overlay` +- `--ck-duration-fast` +- `--ck-ease-standard` + +Notes: +- No component names in foundation tokens. +- Keep names short and generic. + +### Semantic + +Use design intent and role, not component names. + +Preferred patterns: +- `--ck-{domain}-{role}-{property}` +- `--ck-{domain}-{role}-{state}-{property}` +- `--ck-{role}-{state}-{property}` (when domain is obvious from property, e.g. `focus`, `layer`) + +Examples: +- `--ck-color-interactive-hover-surface` +- `--ck-color-text-primary` +- `--ck-interactive-focus-ring` +- `--ck-interactive-focus-error-shadow` +- `--ck-spacing-region-padding-inline` +- `--ck-border-radius-uniform` +- `--ck-border-radius-surface-cut-top-left` +- `--ck-layer-panel-above` + +### Component + +Use component-first naming. + +Preferred pattern: +`--ck-{component}-{part?}-{state?}-{property}-{variant?}` + +Examples: +- `--ck-button-focus-border-color` +- `--ck-button-default-hover-background-color` +- `--ck-dialog-border-color` +- `--ck-dropdown-panel-uniform-border-radius` +- `--ck-form-header-label-font-size` + +Rule of thumb: +- If token is only used in one component, it must start with that component name. + +## Vocabulary rules + +### States + +Allowed state keywords: +- `hover` +- `active` +- `focus` +- `disabled` +- `error` +- `selected` +- `readonly` +- `on` +- `off` + +### Geometry variants + +Prefer descriptive corner names: +- `top-left`, `top-right`, `bottom-left`, `bottom-right` + +Short forms like `ne`, `sw`, etc. are allowed only when mirroring existing class/state naming in selectors. + +### Typography + +Use: +- `font-weight` (not shorthand like `weight`) +- semantic typography role tokens (`--ck-font-weight-ui-*`) +- component proxies for local override points + +### Important Naming Constraint: `content` + +In UI theme tokens, avoid `content` as a namespace because `.ck-content` already represents editable content styling in other packages. + +Use: +- `text` for textual semantics (`--ck-color-text-*`) +- `region` for UI container spacing (`--ck-spacing-region-*`) + +`region` is currently a provisional term and may be refined later. + +### Do / Avoid + +Do: +- `--ck-dialog-border-color` +- `--ck-labeled-field-label-background-color` +- `--ck-interactive-focus-disabled-shadow` + +Avoid: +- `--ck-color-dialog-border` +- `--ck-color-labeled-field-label-background` +- mixed ordering like `--ck-focus-shadow-disabled-interactive` + +## Migration Rules + +When renaming tokens: +1. Rename declaration and all usages in the same change. +2. Keep behavior identical (only naming changes). +3. If public API risk is high, add temporary alias only when needed. +4. Never introduce new literals if a matching semantic/component token exists. + +## Overriding Tokens + +### Global overrides (`:root`) + +Override tokens on `:root` to change values globally. Both legacy and new names work at this level: + +```css +:root { + /* Foundation — changes radius everywhere. */ + --ck-radius-base: 5px; + + /* Legacy name — also works globally via backward-compatible fallbacks. */ + --ck-border-radius: 5px; + + /* Component — changes only button padding. */ + --ck-button-padding: 5px; +} +``` + +### Scoped overrides (on a specific element or class) + +For scoped overrides, always use the **component token** directly — not a foundation or legacy name. + +All tokens are defined on `:root` and resolve there. A scoped override of a foundation or legacy token does **not** cascade through the semantic/component chain because the chain was already resolved at `:root`. + +Do: +```css +/* ✓ Directly sets the component token on the scoped element. */ +.my-small-button { + --ck-button-padding: 2px; + --ck-button-border-radius: 0; +} +``` + +Avoid: +```css +/* ✗ Won't affect --ck-button-padding — the chain resolved on :root. */ +.my-small-button { + --ck-spacing-control-padding-block: 2px; +} +``` + +The rule of thumb: the closer the token is to the property it controls, the better it works in scoped contexts. Component tokens are the safest choice for per-element customizations. + +## Quick Examples + +Foundation: +- `--ck-font-weight-bold: 700;` +- `--ck-color-base-success: hsl(120, 100%, 27%);` + +Semantic: +- `--ck-font-weight-ui-heading: var(--ck-font-weight-bold);` +- `--ck-interactive-focus-ring: var(--ck-focus-ring);` +- `--ck-color-feedback-success: var(--ck-color-base-success);` + +Component: +- `--ck-form-header-label-font-size: var(--ck-font-size-md);` +- `--ck-dropdown-panel-uniform-border-radius: var(--ck-border-radius-uniform);` diff --git a/packages/ckeditor5-ui/tests/manual/ui-customization/token-panel.js b/packages/ckeditor5-ui/tests/manual/ui-customization/token-panel.js new file mode 100644 index 00000000000..f9cc453e150 --- /dev/null +++ b/packages/ckeditor5-ui/tests/manual/ui-customization/token-panel.js @@ -0,0 +1,3698 @@ +/** + * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +/** + * Shared token panel module — used by ui-customization and all-features-ui-customization tests. + * Contains the token registry (FOUNDATION, SEMANTIC, COMPONENT), descriptions, refs, + * and the generatePanel() function that builds the interactive panel DOM. + */ + +/* eslint-disable max-len */ + +const FOUNDATION = { + 'Colors': [ + // Base surface & structure + '--ck-color-base-background', '--ck-color-base-foreground', '--ck-color-base-border', '--ck-color-base-border-light', + '--ck-color-base-text', '--ck-color-base-text-light', + // Interactive states (derived from base hues) + '--ck-color-base-hover', '--ck-color-base-active', '--ck-color-base-active-focus', + '--ck-color-base-selected', '--ck-color-base-selected-hover', + '--ck-color-base-focus', '--ck-color-base-focus-shadow', '--ck-color-base-focus-shadow-faded', + // Action (green) + '--ck-color-base-action', '--ck-color-base-action-hover', + // Feedback + '--ck-color-base-error', '--ck-color-base-error-shadow', + '--ck-color-base-warning', '--ck-color-base-success', '--ck-color-base-highlight', '--ck-color-base-attention', + // Shadow colors + '--ck-color-shadow-drop', '--ck-color-shadow-drop-active', '--ck-color-shadow-inner' + ], + 'Border & Radius': [ + '--ck-radius-xs', '--ck-radius-sm', '--ck-radius-base', '--ck-radius-md', '--ck-radius-lg', '--ck-radius-xl', + '--ck-radius-full', '--ck-radius-corners', + '--ck-border-width-thin', '--ck-border-width-thick' + ], + 'Spacing': [ + // Base unit first, then scale from largest to smallest + '--ck-spacing-unit', + '--ck-spacing-xl', '--ck-spacing-lg', '--ck-spacing-base', + '--ck-spacing-md', '--ck-spacing-ms', '--ck-spacing-sm', '--ck-spacing-xs', '--ck-spacing-2xs' + ], + 'Shadow': [ + '--ck-inset-shadow-sm', '--ck-shadow-md', '--ck-shadow-lg' + ], + 'Typography': [ + // Font family & base size + '--ck-font-family', '--ck-font-size-base', '--ck-line-height-base', + // Font size scale + '--ck-font-size-xs', '--ck-font-size-sm', '--ck-font-size-md', + '--ck-font-size-lg', '--ck-font-size-xl', + // Font weight scale + '--ck-font-weight-normal', '--ck-font-weight-medium', '--ck-font-weight-semibold', '--ck-font-weight-bold' + ], + 'Focus': [ + '--ck-focus-border-color', + '--ck-focus-shadow-geometry', + '--ck-focus-ring', + '--ck-focus-shadow', '--ck-focus-shadow-disabled', '--ck-focus-shadow-error', + '--ck-outline-fake-caret' + ], + 'Other': [ + '--ck-opacity-disabled', '--ck-size-min-height' + ], + 'Motion': [ + // Transition durations + '--ck-duration-fast', '--ck-duration-base', '--ck-duration-slow', '--ck-duration-slower', + // Easing functions + '--ck-ease-standard', '--ck-ease-interactive', '--ck-ease-emphasized', + // Animation durations + '--ck-animation-duration-fast', '--ck-animation-duration-base', '--ck-animation-duration-slow', + '--ck-animation-duration-emphasis', '--ck-animation-duration-reduced', + // Animation easing + '--ck-animation-ease-standard', '--ck-animation-ease-interactive', '--ck-animation-ease-linear', + // Animation misc + '--ck-animation-fill-both', '--ck-animation-repeat-infinite', + '--ck-animation-none', '--ck-transition-none' + ], + 'Layers': [ + '--ck-z-base', '--ck-z-overlay', '--ck-z-modal' + ] +}; + +const SEMANTIC = { + 'Colors \u2014 Surface': [ + // Base canvas, then derived surfaces + '--ck-color-surface-canvas', + '--ck-color-surface-control', '--ck-color-surface-container', '--ck-color-surface-inverse', + // Borders (derived from base-border) + '--ck-color-border-control', '--ck-color-border-container', '--ck-color-divider' + ], + 'Colors \u2014 Text': [ + // Base text, then variants + '--ck-color-text', '--ck-color-text-primary', + '--ck-color-text-secondary', '--ck-color-text-disabled', + '--ck-color-text-inverse', '--ck-color-text-error' + ], + 'Colors \u2014 Feedback': [ + '--ck-color-feedback-error', '--ck-color-feedback-warning', + '--ck-color-feedback-success', '--ck-color-feedback-highlight' + ], + 'Colors \u2014 Interactive': [ + // Hover/active states + '--ck-color-interactive-hover-surface', '--ck-color-interactive-active-surface', + // Selected states + '--ck-color-interactive-selected-surface', '--ck-color-interactive-selected-surface-hover', + '--ck-color-interactive-selected-text', + // Primary action + '--ck-color-interactive-primary-surface', '--ck-color-interactive-primary-surface-hover', + '--ck-color-interactive-primary-text', + // Focus (derived from base focus colors) + '--ck-color-interactive-focus-border-coordinates', + '--ck-color-interactive-focus-border', '--ck-color-interactive-focus-shadow', + '--ck-color-interactive-focus-disabled-shadow', '--ck-color-interactive-focus-error-shadow' + ], + 'Interactive Focus': [ + // Ring and border-color (base), then shadows (derived) + '--ck-interactive-focus-ring', '--ck-interactive-focus-border-color', + '--ck-interactive-focus-shadow', + '--ck-interactive-focus-disabled-shadow', '--ck-interactive-focus-error-shadow' + ], + 'Shape & Border': [ + // Border widths (base → derived) + '--ck-border-width-control', '--ck-border-width-surface', + '--ck-border-width-divider', '--ck-border-width-emphasis', + // Border shorthands (width + style + color) + '--ck-border-control', '--ck-border-surface', '--ck-border-divider', + // Radius: base roles first + '--ck-border-radius-control', '--ck-border-radius-surface', + // Radius: uniform opt-out (set to disable attached-corner behavior globally) + '--ck-border-radius-uniform', + // Radius: attached variants (derived from surface) + '--ck-border-radius-surface-attached', + '--ck-border-radius-surface-attached-top', '--ck-border-radius-surface-attached-bottom', + // Radius: cut variants (derived from attached) + '--ck-border-radius-surface-cut-top-left', '--ck-border-radius-surface-cut-top-right', + '--ck-border-radius-surface-cut-bottom-right', '--ck-border-radius-surface-cut-bottom-left' + ], + 'Spacing': [ + // Control spacing (buttons, inputs) + '--ck-spacing-control-padding-block', '--ck-spacing-control-padding-inline', + '--ck-spacing-control-padding-inline-compact', '--ck-spacing-control-padding-inline-start-compact', + '--ck-spacing-control-padding-block-regular', '--ck-spacing-control-padding-block-compact', + '--ck-spacing-control-icon-gap', '--ck-spacing-control-meta-gap', + // Surface spacing (toolbars, lists) + '--ck-spacing-surface-padding-inline', '--ck-spacing-surface-padding-block', + '--ck-spacing-surface-item-gap-inline', '--ck-spacing-surface-item-gap-block', + '--ck-spacing-surface-section-gap-block', + // Region spacing (containers) + '--ck-spacing-region-padding-inline', '--ck-spacing-region-padding-inline-wide', + '--ck-spacing-region-padding-block', '--ck-spacing-region-edge-margin-block' + ], + 'Typography': [ + '--ck-font-weight-ui-default', '--ck-font-weight-ui-strong', '--ck-font-weight-ui-heading', + '--ck-font-weight-ui-label', '--ck-font-weight-ui-emphasis', '--ck-font-weight-ui-muted', + '--ck-font-weight-ui-inherit' + ], + 'Layout': [ '--ck-size-control-min-height' ], + 'Shadow': [ '--ck-shadow-surface-floating' ], + 'Motion': [ + // Transition durations + '--ck-transition-duration-control-fast', '--ck-transition-duration-control', + '--ck-transition-duration-control-emphasized', '--ck-transition-duration-surface', + // Transition easing + '--ck-transition-timing-function-control', '--ck-transition-timing-function-control-emphasized', + '--ck-transition-timing-function-surface', + // Transition shorthands (property + duration + easing) + '--ck-transition-control', '--ck-transition-control-fast', + // Animation + '--ck-animation-duration-feedback', '--ck-animation-duration-surface-entrance', + '--ck-animation-duration-progress', '--ck-animation-duration-progress-reduced', + '--ck-animation-timing-function-feedback', '--ck-animation-timing-function-progress', + '--ck-animation-fill-mode-feedback' + ], + 'Layer': [ + '--ck-layer-base', '--ck-layer-control-raised', + '--ck-layer-panel', '--ck-layer-panel-above', '--ck-layer-panel-below', + '--ck-layer-dialog', '--ck-layer-tooltip', + '--ck-layer-balloon-arrow-back', '--ck-layer-balloon-arrow-front' + ] +}; + +const COMPONENT = { + // ---- Most customized components first ---- + 'Button': [ + '--ck-button-padding', + '--ck-button-border-radius', '--ck-button-border', + '--ck-button-default-background-color', '--ck-button-default-hover-background-color', + '--ck-button-default-active-background-color', '--ck-button-default-disabled-background-color', + '--ck-button-on-background-color', '--ck-button-on-hover-background-color', + '--ck-button-on-active-background-color', '--ck-button-on-disabled-background-color', + '--ck-button-on-text-color', + '--ck-button-action-background-color', '--ck-button-action-hover-background-color', + '--ck-button-action-active-background-color', '--ck-button-action-disabled-background-color', + '--ck-button-action-text-color', + '--ck-button-save-color', '--ck-button-cancel-color', + '--ck-button-focus-border-color', '--ck-button-opacity-disabled' + ], + 'Input': [ + '--ck-input-width', '--ck-input-padding', + '--ck-input-border-radius', '--ck-input-border', + '--ck-input-background-color', '--ck-input-border-color', '--ck-input-error-border-color', + '--ck-input-text-color', + '--ck-input-disabled-background-color', '--ck-input-disabled-border-color', '--ck-input-disabled-text-color', + '--ck-input-focus-border-color', '--ck-input-text-width' + ], + 'Toolbar': [ + '--ck-toolbar-item-gap-inline', '--ck-toolbar-padding', + '--ck-toolbar-border-radius', '--ck-toolbar-vertical-button-border-radius', + '--ck-toolbar-compact-uniform-border-radius', + '--ck-toolbar-background-color', '--ck-toolbar-border-color', + '--ck-toolbar-border' + ], + 'Block Toolbar': [ '--ck-block-toolbar-button-size' ], + 'Dropdown': [ + '--ck-dropdown-arrow-size', + '--ck-dropdown-panel-padding', + '--ck-dropdown-panel-border-radius', '--ck-dropdown-panel-uniform-border-radius', + '--ck-dropdown-panel-background-color', '--ck-dropdown-panel-border-color', '--ck-dropdown-list-background-color', + '--ck-dropdown-panel-border' + ], + 'List': [ + '--ck-list-item-min-width', '--ck-list-padding', '--ck-list-item-outer-padding', + '--ck-list-border-radius', + '--ck-list-background-color', '--ck-list-divider-color', + '--ck-list-button-hover-background-color', '--ck-list-button-on-background-color', '--ck-list-button-on-text-color', + '--ck-list-group-label-font-size' + ], + 'List Item Button': [ + '--ck-list-item-button-padding', '--ck-list-item-button-border-radius' + ], + 'List Dropdown': [ '--ck-list-dropdown-uniform-border-radius' ], + // ---- Dropdown sub-components ---- + 'Dropdown Menu Panel': [ + '--ck-dropdown-menu-panel-max-height', + '--ck-dropdown-menu-panel-border-radius', '--ck-dropdown-menu-panel-uniform-border-radius' + ], + 'Dropdown Menu List Item': [ + '--ck-dropdown-menu-menu-item-min-width', + '--ck-dropdown-menu-list-item-spinner-size' + ], + // ---- Menu bar ---- + 'Menu Bar Button': [ '--ck-menu-bar-button-border-radius' ], + 'Menu Bar Panel': [ + '--ck-menu-bar-panel-border-radius', '--ck-menu-bar-panel-uniform-border-radius', + '--ck-menu-bar-item-focus-border-color' + ], + 'Menu Bar List Item': [ '--ck-menu-bar-list-item-button-border-radius' ], + // ---- Dialogs & panels ---- + 'Dialog': [ + '--ck-dialog-max-height', '--ck-dialog-max-width', + '--ck-dialog-border-radius', '--ck-dialog-border', + '--ck-dialog-background-color', '--ck-dialog-overlay-background-color' + ], + 'Balloon Panel': [ + '--ck-balloon-panel-border-radius', + '--ck-balloon-panel-border', + '--ck-balloon-panel-background-color', '--ck-balloon-panel-border-color', + '--ck-balloon-panel-arrow-display' + ], + 'Sticky Panel': [ '--ck-sticky-panel-uniform-border-radius' ], + 'Tooltip': [ + '--ck-tooltip-max-width', '--ck-tooltip-padding', '--ck-tooltip-border', + '--ck-tooltip-background-color', '--ck-tooltip-text-color', '--ck-tooltip-text-font-size' + ], + // ---- Toggle & forms ---- + 'Switch Button': [ + '--ck-switch-button-toggle-border-radius', '--ck-switch-button-toggle-inner-border-radius', + '--ck-switch-button-off-background-color', '--ck-switch-button-off-hover-background-color', + '--ck-switch-button-on-background-color', '--ck-switch-button-on-hover-background-color', + '--ck-switch-button-inner-background-color' + ], + 'Form Header': [ + '--ck-form-header-height', '--ck-form-header-padding-block', '--ck-form-header-label-font-size' + ], + 'Form': [ '--ck-form-default-width', '--ck-form-padding' ], + 'Form Row': [ '--ck-form-row-padding' ], + 'Labeled Field': [ '--ck-labeled-field-label-background-color', '--ck-labeled-field-label-start-gap' ], + // ---- Editor & misc ---- + 'Editor UI': [ + '--ck-editor-editable-padding', + '--ck-editor-frame-border-radius', '--ck-editor-sticky-panel-border-radius', + '--ck-editor-frame-border', '--ck-editor-frame-border-color', + '--ck-editor-editable-focus-border-color' + ], + 'Accessibility Help': [ + '--ck-accessibility-help-dialog-max-height', '--ck-accessibility-help-dialog-max-width' + ], + 'Color Selector': [ + '--ck-color-selector-padding', '--ck-color-selector-uniform-border-radius', + '--ck-color-selector-color-picker-border-top' + ], + 'Color Grid': [ + '--ck-color-grid-tile-size', '--ck-color-grid-gap', '--ck-color-grid-margin', '--ck-color-grid-padding', + '--ck-color-grid-tile-border-radius', + '--ck-color-grid-tile-hover-transform', '--ck-color-grid-tile-hover-layer' + ], + 'Search': [ '--ck-search-results-info-padding' ], + 'Icon': [ '--ck-icon-size' ], + 'Spinner': [ '--ck-toolbar-spinner-size' ], + 'Collapsible': [ + '--ck-collapsible-children-padding', '--ck-collapsible-button-font-weight' + ], + 'Autocomplete': [ + '--ck-autocomplete-results-max-height', + '--ck-autocomplete-results-border-radius', '--ck-autocomplete-results-uniform-border-radius', + '--ck-autocomplete-results-border', + '--ck-autocomplete-results-background-color' + ], + 'Responsive Form': [ + '--ck-responsive-form-padding', '--ck-responsive-form-divider-border' + ] +}; + +// --------------------------------------------------------------------------- +// Token descriptions — short explanations for tokens with non-obvious behavior. +// Only tokens that need extra context are listed. The "i" icon appears only +// when a description exists. +// --------------------------------------------------------------------------- + +/* eslint-disable max-len */ +const TOKEN_DESCRIPTIONS = { + // ---- Foundation — Colors ---- + '--ck-color-base-background': 'Base background color for the entire editor UI.', + '--ck-color-base-foreground': 'Foreground color for elevated surfaces.', + '--ck-color-base-border': 'Default border color across the UI.', + '--ck-color-base-border-light': 'Lighter border variant for subtle separators.', + '--ck-color-base-text': 'Default text color for the editor UI.', + '--ck-color-base-text-light': 'Muted text color variant.', + '--ck-color-base-hover': 'Background color on hover states.', + '--ck-color-base-active': 'Background color on active/pressed states.', + '--ck-color-base-active-focus': 'Background color when both active and focused.', + '--ck-color-base-selected': 'Background for selected/toggled-on elements.', + '--ck-color-base-selected-hover': 'Background for selected elements on hover.', + '--ck-color-base-focus': 'Border/outline color for focused elements.', + '--ck-color-base-focus-shadow': 'Shadow color for focus rings.', + '--ck-color-base-focus-shadow-faded': 'Reduced-opacity focus shadow for disabled elements.', + '--ck-color-base-action': 'Primary action color (e.g. save buttons). Usually green.', + '--ck-color-base-action-hover': 'Hover state for primary action color.', + '--ck-color-base-error': 'Error/danger state color.', + '--ck-color-base-error-shadow': 'Shadow color for error focus rings.', + '--ck-color-base-warning': 'Warning feedback color.', + '--ck-color-base-success': 'Success feedback color.', + '--ck-color-base-highlight': 'Highlight/accent color for attention states.', + '--ck-color-base-attention': 'Attention/notice color (e.g. pending states).', + '--ck-color-shadow-drop': 'Base color for drop shadows.', + '--ck-color-shadow-drop-active': 'Stronger shadow color for active/elevated states.', + '--ck-color-shadow-inner': 'Color for inner/inset shadows.', + + // ---- Foundation — Border & Radius ---- + '--ck-radius-xs': 'Extra-small border-radius for tight corners.', + '--ck-radius-sm': 'Small border-radius. \u26A0 Not yet used by any semantic or component token.', + '--ck-radius-base': 'Default border-radius for the entire UI. Cascades to all semantic and component radius tokens.', + '--ck-radius-md': 'Medium border-radius. \u26A0 Not yet used by any semantic or component token.', + '--ck-radius-lg': 'Large border-radius. \u26A0 Not yet used by any semantic or component token.', + '--ck-radius-xl': 'Extra-large border-radius. \u26A0 Not yet used by any semantic or component token.', + '--ck-radius-full': 'Full circle radius (50%). Used for round elements like spinners.', + '--ck-radius-corners': 'Active only when .ck-rounded-corners class is present on the editor root. Maps to radius-base.', + '--ck-border-width-thin': 'Thin border width (e.g. 1px).', + '--ck-border-width-thick': 'Thick border width for emphasis.', + + // ---- Foundation — Spacing ---- + '--ck-spacing-unit': 'Base spacing multiplier. All spacing scale tokens (xs–xl) are derived from this value.', + '--ck-spacing-xl': 'Extra-large spacing. Derived from spacing-unit.', + '--ck-spacing-lg': 'Large spacing. Derived from spacing-unit.', + '--ck-spacing-base': 'Base spacing value. Derived from spacing-unit.', + '--ck-spacing-md': 'Medium spacing. Derived from spacing-unit.', + '--ck-spacing-ms': 'Medium-small spacing. Derived from spacing-unit.', + '--ck-spacing-sm': 'Small spacing. Derived from spacing-unit.', + '--ck-spacing-xs': 'Extra-small spacing. Derived from spacing-unit.', + '--ck-spacing-2xs': 'Double extra-small spacing. Derived from spacing-unit.', + + // ---- Foundation — Shadow ---- + '--ck-inset-shadow-sm': 'Small inset shadow for sunken elements.', + '--ck-shadow-md': 'Medium drop shadow for slightly elevated elements.', + '--ck-shadow-lg': 'Large drop shadow for floating/modal elements.', + + // ---- Foundation — Typography ---- + '--ck-font-family': 'Default font family for the entire editor UI.', + '--ck-font-size-base': 'Base font size in px. Used as the root for all relative em/rem calculations.', + '--ck-line-height-base': 'Base line-height for UI elements.', + '--ck-font-size-xs': 'Extra-small font size.', + '--ck-font-size-sm': 'Small font size.', + '--ck-font-size-md': 'Medium font size.', + '--ck-font-size-lg': 'Large font size.', + '--ck-font-size-xl': 'Extra-large font size.', + '--ck-font-weight-normal': 'Normal (400) font weight.', + '--ck-font-weight-medium': 'Medium (500) font weight.', + '--ck-font-weight-semibold': 'Semibold (600) font weight.', + '--ck-font-weight-bold': 'Bold (700) font weight.', + + // ---- Foundation — Focus ---- + '--ck-focus-border-color': 'Border color on focus. Use instead of focus-ring when component has customizable border-width.', + '--ck-focus-shadow-geometry': 'The spread geometry (offsets) of focus shadows. Shared by all focus shadow variants.', + '--ck-focus-ring': 'Complete border shorthand (width + style + color) for focused elements.', + '--ck-focus-shadow': 'Complete focus shadow (geometry + color).', + '--ck-focus-shadow-disabled': 'Reduced focus shadow for disabled elements.', + '--ck-focus-shadow-error': 'Focus shadow with error color.', + '--ck-outline-fake-caret': 'Contrast outline for fake collapsed selections and carets.', + + // ---- Foundation — Other ---- + '--ck-opacity-disabled': 'Global opacity for disabled UI elements.', + '--ck-size-min-height': 'Minimum height for UI components. Ensures consistent button height.', + + // ---- Foundation — Motion ---- + '--ck-duration-fast': 'Fast transition duration (e.g. 100ms).', + '--ck-duration-base': 'Base transition duration (e.g. 200ms).', + '--ck-duration-slow': 'Slow transition duration (e.g. 300ms).', + '--ck-duration-slower': 'Slower transition duration (e.g. 500ms).', + '--ck-ease-standard': 'Standard easing curve for UI transitions.', + '--ck-ease-interactive': 'Easing curve optimized for interactive elements.', + '--ck-ease-emphasized': 'Emphasized easing curve for dramatic transitions.', + '--ck-animation-duration-fast': 'Fast animation duration. Derived from duration-fast.', + '--ck-animation-duration-base': 'Base animation duration. Derived from duration-base.', + '--ck-animation-duration-slow': 'Slow animation duration. Derived from duration-slow.', + '--ck-animation-duration-emphasis': 'Duration for emphasis animations.', + '--ck-animation-duration-reduced': 'Animation duration for prefers-reduced-motion.', + '--ck-animation-ease-standard': 'Standard animation easing. Derived from ease-standard.', + '--ck-animation-ease-interactive': 'Interactive animation easing. Derived from ease-interactive.', + '--ck-animation-ease-linear': 'Linear animation timing (no easing).', + '--ck-animation-fill-both': 'fill-mode: both for animations.', + '--ck-animation-repeat-infinite': 'Infinite repeat count for looping animations.', + '--ck-animation-none': 'Resets animation to none (for disabling).', + '--ck-transition-none': 'Resets transition to none (for disabling).', + + // ---- Foundation — Layers ---- + '--ck-z-base': 'Base z-index layer.', + '--ck-z-overlay': 'Overlay z-index for panels above base content.', + '--ck-z-modal': 'Modal z-index for dialogs and top-level overlays.', + + // ---- Semantic — Colors — Surface ---- + '--ck-color-surface-canvas': 'Base canvas background. Other surfaces derive from this.', + '--ck-color-surface-control': 'Surface color for interactive controls.', + '--ck-color-surface-container': 'Surface color for container elements (panels, dropdowns).', + '--ck-color-surface-inverse': 'Inverted surface color (e.g. tooltip backgrounds).', + '--ck-color-border-control': 'Border color for interactive controls.', + '--ck-color-border-container': 'Border color for container elements.', + '--ck-color-divider': 'Color for divider lines between sections.', + + // ---- Semantic — Colors — Text ---- + '--ck-color-text': 'General UI text color.', + '--ck-color-text-primary': 'Primary text color for important content.', + '--ck-color-text-secondary': 'Secondary text color for supporting content.', + '--ck-color-text-disabled': 'Text color for disabled elements.', + '--ck-color-text-inverse': 'Text on inverted surfaces (e.g. tooltips).', + '--ck-color-text-error': 'Text color for error messages.', + + // ---- Semantic — Colors — Feedback ---- + '--ck-color-feedback-error': 'Error feedback color.', + '--ck-color-feedback-warning': 'Warning feedback color.', + '--ck-color-feedback-success': 'Success feedback color.', + '--ck-color-feedback-highlight': 'Highlight/accent feedback color.', + + // ---- Semantic — Colors — Interactive ---- + '--ck-color-interactive-hover-surface': 'Background on hover for interactive elements.', + '--ck-color-interactive-active-surface': 'Background on active/pressed for interactive elements.', + '--ck-color-interactive-selected-surface': 'Background for selected/toggled-on elements.', + '--ck-color-interactive-selected-surface-hover': 'Background for selected elements on hover.', + '--ck-color-interactive-selected-text': 'Text color for selected interactive elements.', + '--ck-color-interactive-primary-surface': 'Background for primary action buttons (e.g. save).', + '--ck-color-interactive-primary-surface-hover': 'Hover background for primary action buttons.', + '--ck-color-interactive-primary-text': 'Text color on primary action buttons.', + '--ck-color-interactive-focus-border-coordinates': 'Raw HSL coordinates for focus border. Used in hsla() for sonar-pulse animations.', + '--ck-color-interactive-focus-border': 'Focus border color for interactive elements.', + '--ck-color-interactive-focus-shadow': 'Focus shadow color for interactive elements.', + '--ck-color-interactive-focus-disabled-shadow': 'Focus shadow for disabled interactive elements.', + '--ck-color-interactive-focus-error-shadow': 'Focus shadow for error-state interactive elements.', + + // ---- Semantic — Interactive Focus ---- + '--ck-interactive-focus-ring': 'Complete focus ring border shorthand for interactive elements.', + '--ck-interactive-focus-border-color': 'Focus border color. Only changes color, preserving custom border-width.', + '--ck-interactive-focus-shadow': 'Box-shadow applied on focus for interactive elements.', + '--ck-interactive-focus-disabled-shadow': 'Focus box-shadow for disabled interactive elements.', + '--ck-interactive-focus-error-shadow': 'Focus box-shadow for error-state interactive elements.', + + // ---- Semantic — Shape & Border ---- + '--ck-border-width-control': 'Border width for interactive controls.', + '--ck-border-width-surface': 'Border width for surface/panel elements.', + '--ck-border-width-divider': 'Border width for divider lines.', + '--ck-border-width-emphasis': 'Thicker border width for emphasis.', + '--ck-border-control': 'Border shorthand for controls (width + solid + color). Used by buttons, inputs.', + '--ck-border-surface': 'Border shorthand for surfaces (width + solid + color). Used by panels, dropdowns.', + '--ck-border-divider': 'Border shorthand for dividers (width + solid + color). Used by form headers, separators.', + '--ck-border-radius-control': 'Border radius for interactive controls (buttons, inputs). Inherits from radius-base.', + '--ck-border-radius-surface': 'Border radius for elevated surfaces (panels, dropdowns). Inherits from radius-base.', + '--ck-border-radius-uniform': 'Set to a radius value to disable attached-corner behavior on all panels at once.', + '--ck-border-radius-surface-attached': 'Base radius for panels that visually attach to a trigger.', + '--ck-border-radius-surface-attached-top': 'Radius for panels attached at the top edge.', + '--ck-border-radius-surface-attached-bottom': 'Radius for panels attached at the bottom edge.', + '--ck-border-radius-surface-cut-top-left': 'Radius cut on top-left corner (e.g. split button open state).', + '--ck-border-radius-surface-cut-top-right': 'Radius cut on top-right corner.', + '--ck-border-radius-surface-cut-bottom-right': 'Radius cut on bottom-right corner.', + '--ck-border-radius-surface-cut-bottom-left': 'Radius cut on bottom-left corner.', + + // ---- Semantic — Spacing ---- + '--ck-spacing-control-padding-block': 'Vertical padding for controls (buttons, inputs).', + '--ck-spacing-control-padding-inline': 'Horizontal padding for controls.', + '--ck-spacing-control-padding-inline-compact': 'Reduced horizontal padding for compact controls.', + '--ck-spacing-control-padding-inline-start-compact': 'Reduced start-side padding for compact controls.', + '--ck-spacing-control-padding-block-regular': 'Regular vertical padding for controls.', + '--ck-spacing-control-padding-block-compact': 'Compact vertical padding for controls.', + '--ck-spacing-control-icon-gap': 'Gap between icon and label in controls.', + '--ck-spacing-control-meta-gap': 'Gap between label and meta info (e.g. keystroke).', + '--ck-spacing-surface-padding-inline': 'Horizontal padding inside surface containers.', + '--ck-spacing-surface-padding-block': 'Vertical padding inside surface containers.', + '--ck-spacing-surface-item-gap-inline': 'Horizontal gap between items in surface containers.', + '--ck-spacing-surface-item-gap-block': 'Vertical gap between items in surface containers.', + '--ck-spacing-surface-section-gap-block': 'Vertical gap between sections in surface containers.', + '--ck-spacing-region-padding-inline': 'Horizontal padding for region containers.', + '--ck-spacing-region-padding-inline-wide': 'Wider horizontal padding for region containers.', + '--ck-spacing-region-padding-block': 'Vertical padding for region containers.', + '--ck-spacing-region-edge-margin-block': 'Vertical margin at region edges.', + + // ---- Semantic — Typography ---- + '--ck-font-weight-ui-default': 'Default font weight for UI elements.', + '--ck-font-weight-ui-strong': 'Strong/emphasized font weight in UI.', + '--ck-font-weight-ui-heading': 'Font weight for UI headings/section titles.', + '--ck-font-weight-ui-label': 'Font weight for labels.', + '--ck-font-weight-ui-emphasis': 'Font weight for emphasized UI text.', + '--ck-font-weight-ui-muted': 'Font weight for de-emphasized/muted text.', + '--ck-font-weight-ui-inherit': 'Inherits font weight from parent. Used for pass-through.', + + // ---- Semantic — Layout ---- + '--ck-size-control-min-height': 'Shared min-height for controls. Ensures consistent sizing across buttons, inputs, etc.', + + // ---- Semantic — Shadow ---- + '--ck-shadow-surface-floating': 'Shadow for floating/elevated surfaces (dropdowns, balloons, dialogs).', + + // ---- Semantic — Motion ---- + '--ck-transition-duration-control-fast': 'Fast transition for controls.', + '--ck-transition-duration-control': 'Default transition duration for controls.', + '--ck-transition-duration-control-emphasized': 'Emphasized (slower) transition for controls.', + '--ck-transition-duration-surface': 'Transition duration for surface/panel elements.', + '--ck-transition-timing-function-control': 'Easing function for control transitions.', + '--ck-transition-timing-function-control-emphasized': 'Easing for emphasized control transitions.', + '--ck-transition-timing-function-surface': 'Easing function for surface transitions.', + '--ck-transition-control': 'Transition shorthand for controls (box-shadow + border with standard timing).', + '--ck-transition-control-fast': 'Fast transition shorthand for controls (box-shadow + border with fast timing).', + '--ck-animation-duration-feedback': 'Duration for feedback animations (e.g. success/error).', + '--ck-animation-duration-surface-entrance': 'Duration for surface entrance animations.', + '--ck-animation-duration-progress': 'Duration for progress/loading animations.', + '--ck-animation-duration-progress-reduced': 'Reduced-motion duration for progress animations.', + '--ck-animation-timing-function-feedback': 'Easing function for feedback animations.', + '--ck-animation-timing-function-progress': 'Easing function for progress animations.', + '--ck-animation-fill-mode-feedback': 'Fill mode for feedback animations.', + + // ---- Semantic — Layer ---- + '--ck-layer-base': 'Base stacking layer for UI elements.', + '--ck-layer-control-raised': 'Layer for raised controls (e.g. focused buttons).', + '--ck-layer-panel': 'Default layer for panels.', + '--ck-layer-panel-above': 'Layer for panels that stack above others.', + '--ck-layer-panel-below': 'Layer for panels that stack below others.', + '--ck-layer-dialog': 'Layer for modal dialogs.', + '--ck-layer-tooltip': 'Layer for tooltips (topmost UI layer).', + '--ck-layer-balloon-arrow-back': 'Layer for balloon panel arrow background.', + '--ck-layer-balloon-arrow-front': 'Layer for balloon panel arrow foreground.', + + // ---- Component — Button ---- + '--ck-button-padding': 'Padding inside buttons.', + '--ck-button-border-radius': 'Border radius for buttons.', + '--ck-button-border': 'Border shorthand for buttons.', + '--ck-button-default-background-color': 'Background for default button state.', + '--ck-button-default-hover-background-color': 'Background on hover for default buttons.', + '--ck-button-default-active-background-color': 'Background on active for default buttons.', + '--ck-button-default-disabled-background-color': 'Background for disabled default buttons.', + '--ck-button-on-background-color': 'Background for toggled-on buttons.', + '--ck-button-on-hover-background-color': 'Background on hover for toggled-on buttons.', + '--ck-button-on-active-background-color': 'Background on active for toggled-on buttons.', + '--ck-button-on-disabled-background-color': 'Background for disabled toggled-on buttons.', + '--ck-button-on-text-color': 'Text color for toggled-on buttons.', + '--ck-button-action-background-color': 'Background for primary action buttons.', + '--ck-button-action-hover-background-color': 'Background on hover for action buttons.', + '--ck-button-action-active-background-color': 'Background on active for action buttons.', + '--ck-button-action-disabled-background-color': 'Background for disabled action buttons.', + '--ck-button-action-text-color': 'Text color for action buttons.', + '--ck-button-save-color': 'Icon/text color for save buttons.', + '--ck-button-cancel-color': 'Icon/text color for cancel buttons.', + '--ck-button-focus-border-color': 'Border color on button focus. Only changes color, preserving custom border-width.', + '--ck-button-opacity-disabled': 'Opacity for disabled button icons and labels.', + + // ---- Component — Input ---- + '--ck-input-width': 'Default width for input fields.', + '--ck-input-padding': 'Padding inside input fields.', + '--ck-input-border-radius': 'Border radius for input fields.', + '--ck-input-border': 'Border shorthand for input fields.', + '--ck-input-background-color': 'Background color for input fields.', + '--ck-input-border-color': 'Border color for input fields.', + '--ck-input-error-border-color': 'Border color for inputs in error state.', + '--ck-input-text-color': 'Text color inside input fields.', + '--ck-input-disabled-background-color': 'Background for disabled inputs.', + '--ck-input-disabled-border-color': 'Border color for disabled inputs.', + '--ck-input-disabled-text-color': 'Text color for disabled inputs.', + '--ck-input-focus-border-color': 'Border color on input focus. Only changes color, preserving custom border-width.', + '--ck-input-text-width': 'Width for text-type input fields.', + + // ---- Component — Toolbar ---- + '--ck-toolbar-item-gap-inline': 'Horizontal gap between toolbar items.', + '--ck-toolbar-padding': 'Padding inside the toolbar.', + '--ck-toolbar-border-radius': 'Border radius for the toolbar container.', + '--ck-toolbar-vertical-button-border-radius': 'Border radius for buttons inside vertical toolbars. Defaults to 0.', + '--ck-toolbar-compact-uniform-border-radius': 'Uniform radius for compact toolbars. Disables cut-corner behavior.', + '--ck-toolbar-background-color': 'Background color for the toolbar.', + '--ck-toolbar-border-color': 'Border color for the toolbar.', + '--ck-toolbar-border': 'Border shorthand for the toolbar.', + + // ---- Component — Block Toolbar ---- + '--ck-block-toolbar-button-size': 'Size (width/height) of the block toolbar trigger button.', + + // ---- Component — Dropdown ---- + '--ck-dropdown-arrow-size': 'Size of the dropdown arrow icon.', + '--ck-dropdown-panel-padding': 'Inner padding of dropdown panels. Defaults to 0.', + '--ck-dropdown-panel-border-radius': 'Border radius for dropdown panels.', + '--ck-dropdown-panel-uniform-border-radius': 'Set to a radius value to disable attached-corner behavior on dropdown panels.', + '--ck-dropdown-panel-background-color': 'Background color for dropdown panels.', + '--ck-dropdown-panel-border-color': 'Border color for dropdown panels.', + '--ck-dropdown-list-background-color': 'Background of lists inside dropdown panels. Transparent by default to respect panel corners.', + '--ck-dropdown-panel-border': 'Border shorthand for dropdown panels.', + + // ---- Component — List ---- + '--ck-list-item-min-width': 'Minimum width for list items.', + '--ck-list-padding': 'Padding inside list containers.', + '--ck-list-item-outer-padding': 'Padding on the list item wrapper. Defaults to 0 — set to add spacing around items.', + '--ck-list-border-radius': 'Border radius for list containers.', + '--ck-list-background-color': 'Background color for list containers.', + '--ck-list-divider-color': 'Color of dividers between list items.', + '--ck-list-button-hover-background-color': 'Background on hover for list item buttons.', + '--ck-list-button-on-background-color': 'Background for selected list item buttons.', + '--ck-list-button-on-text-color': 'Text color for selected list item buttons.', + '--ck-list-group-label-font-size': 'Font size for list group labels/headers.', + + // ---- Component — List Item Button ---- + '--ck-list-item-button-padding': 'Padding inside list item buttons.', + '--ck-list-item-button-border-radius': 'Border radius for list item buttons. Defaults to 0 for seamless stacking.', + + // ---- Component — List Dropdown ---- + '--ck-list-dropdown-uniform-border-radius': 'Uniform radius for list dropdown panels and first/last item buttons.', + + // ---- Component — Dropdown Menu Panel ---- + '--ck-dropdown-menu-panel-max-height': 'Maximum height for dropdown menu panels.', + '--ck-dropdown-menu-panel-border-radius': 'Border radius for dropdown menu panels.', + '--ck-dropdown-menu-panel-uniform-border-radius': 'Uniform radius for nested dropdown menu panels.', + + // ---- Component — Dropdown Menu List Item ---- + '--ck-dropdown-menu-menu-item-min-width': 'Minimum width for dropdown menu items.', + '--ck-dropdown-menu-list-item-spinner-size': 'Size of spinner in dropdown menu list items.', + + // ---- Component — Menu Bar ---- + '--ck-menu-bar-button-border-radius': 'Border radius for sub-menu buttons in menu bar. Defaults to 0.', + '--ck-menu-bar-panel-border-radius': 'Border radius for menu bar panels.', + '--ck-menu-bar-panel-uniform-border-radius': 'Uniform radius for menu bar panels. Disables attached-corner behavior.', + '--ck-menu-bar-item-focus-border-color': 'Focus border color for menu bar items.', + '--ck-menu-bar-list-item-button-border-radius': 'Border radius for menu bar list item buttons. Defaults to 0.', + + // ---- Component — Menu Bar List Item (from group) ---- + '--ck-menu-bar-menu-item-min-width': 'Minimum width for menu bar menu items.', + + // ---- Component — Dialog ---- + '--ck-dialog-max-height': 'Maximum height for dialogs.', + '--ck-dialog-max-width': 'Maximum width for dialogs.', + '--ck-dialog-border-radius': 'Border radius for dialogs.', + '--ck-dialog-border': 'Border shorthand for dialogs.', + '--ck-dialog-background-color': 'Background color for dialogs.', + '--ck-dialog-overlay-background-color': 'Background color for the dialog overlay/backdrop.', + + // ---- Component — Balloon Panel ---- + '--ck-balloon-panel-border-radius': 'Border radius for balloon panels.', + '--ck-balloon-panel-border': 'Complete border shorthand for balloon panels.', + '--ck-balloon-panel-background-color': 'Background color for balloon panels.', + '--ck-balloon-panel-border-color': 'Border color for balloon panels.', + '--ck-balloon-panel-arrow-display': 'Arrow visibility. Set to "none" to hide all balloon arrows.', + + // ---- Component — Sticky Panel ---- + '--ck-sticky-panel-uniform-border-radius': 'Uniform radius for the sticky panel.', + + // ---- Component — Tooltip ---- + '--ck-tooltip-max-width': 'Maximum width for tooltips.', + '--ck-tooltip-padding': 'Padding inside tooltips.', + '--ck-tooltip-border': 'Border shorthand for tooltips. Defaults to transparent.', + '--ck-tooltip-background-color': 'Background color for tooltips.', + '--ck-tooltip-text-color': 'Text color for tooltips.', + '--ck-tooltip-text-font-size': 'Font size for tooltip text.', + + // ---- Component — Switch Button ---- + '--ck-switch-button-toggle-border-radius': 'Border radius for the switch toggle track.', + '--ck-switch-button-toggle-inner-border-radius': 'Border radius of the toggle handle inside switch buttons.', + '--ck-switch-button-off-background-color': 'Track background when switch is off.', + '--ck-switch-button-off-hover-background-color': 'Track background on hover when switch is off.', + '--ck-switch-button-on-background-color': 'Track background when switch is on.', + '--ck-switch-button-on-hover-background-color': 'Track background on hover when switch is on.', + '--ck-switch-button-inner-background-color': 'Background of the switch toggle handle.', + + // ---- Component — Form Header ---- + '--ck-form-header-height': 'Height of form section headers. Set to "auto" for content-driven height.', + '--ck-form-header-padding-block': 'Vertical padding for form headers.', + '--ck-form-header-label-font-size': 'Font size for form header labels.', + + // ---- Component — Form ---- + '--ck-form-default-width': 'Default width for form panels.', + '--ck-form-padding': 'Padding inside form panels.', + + // ---- Component — Form Row ---- + '--ck-form-row-padding': 'Padding inside form rows.', + + // ---- Component — Labeled Field ---- + '--ck-labeled-field-label-background-color': 'Background for floating labels on labeled fields.', + '--ck-labeled-field-label-start-gap': 'Start-side gap for labeled field labels.', + + // ---- Component — Editor UI ---- + '--ck-editor-editable-padding': 'Padding inside the editor editable area.', + '--ck-editor-frame-border-radius': 'Border radius for the editor frame.', + '--ck-editor-sticky-panel-border-radius': 'Border radius for the editor sticky panel.', + '--ck-editor-frame-border': 'Border shorthand for the editor frame.', + '--ck-editor-frame-border-color': 'Border color for the editor frame.', + '--ck-editor-editable-focus-border-color': 'Border color on editor editable focus. Only changes color, preserving border-width.', + + // ---- Component — Accessibility Help ---- + '--ck-accessibility-help-dialog-max-height': 'Max height for the accessibility help dialog.', + '--ck-accessibility-help-dialog-max-width': 'Max width for the accessibility help dialog.', + + // ---- Component — Color Selector ---- + '--ck-color-selector-padding': 'Root padding on the color selector component.', + '--ck-color-selector-uniform-border-radius': 'Uniform radius for the color selector picker button.', + '--ck-color-selector-color-picker-border-top': + 'Top border on the color picker button (unfocused). Set to "none" to remove the divider.', + + // ---- Component — Color Grid ---- + '--ck-color-grid-tile-size': 'Size (width/height) of color grid tiles.', + '--ck-color-grid-gap': 'Gap between color grid tiles.', + '--ck-color-grid-margin': 'Outer margin of the color grid container.', + '--ck-color-grid-padding': 'Padding inside the color grid container.', + '--ck-color-grid-tile-border-radius': 'Border radius for color grid tiles.', + '--ck-color-grid-tile-hover-transform': 'Transform on tile hover. Set to e.g. scale(1.3) for zoom effect.', + '--ck-color-grid-tile-hover-layer': 'Z-index for hovered/focused tiles. Set to 1 so transformed tiles appear above neighbors.', + + // ---- Component — Search ---- + '--ck-search-results-info-padding': 'Padding for search results info section.', + + // ---- Component — Icon ---- + '--ck-icon-size': 'Default size for icons.', + + // ---- Component — Spinner ---- + '--ck-toolbar-spinner-size': 'Size of the spinner shown in the toolbar.', + + // ---- Component — Collapsible ---- + '--ck-collapsible-children-padding': 'Padding for collapsible section children.', + '--ck-collapsible-button-font-weight': 'Font weight for collapsible toggle buttons.', + + // ---- Component — Autocomplete ---- + '--ck-autocomplete-results-max-height': 'Max height for autocomplete results panel.', + '--ck-autocomplete-results-border-radius': 'Border radius for autocomplete results panel.', + '--ck-autocomplete-results-uniform-border-radius': 'Uniform radius for autocomplete results. Disables attached-corner behavior.', + '--ck-autocomplete-results-border': 'Border shorthand for autocomplete results panel.', + '--ck-autocomplete-results-background-color': 'Background for autocomplete results panel.', + + // ---- Component — Responsive Form ---- + '--ck-responsive-form-padding': 'Padding for responsive form containers.', + '--ck-responsive-form-divider-border': 'Border for dividers in responsive forms.' +}; +/* eslint-enable max-len */ + +// --------------------------------------------------------------------------- +// Token diagrams — inline SVGs showing where a token applies visually. +// Only tokens that benefit from a visual explanation are listed. +// --------------------------------------------------------------------------- + +/* eslint-disable max-len */ +const TOKEN_DIAGRAMS = { + // ---- Semantic — Spacing ---- + '--ck-spacing-control-padding-block': ` + + Button + + + + + + `, + + '--ck-spacing-control-padding-inline': ` + + Button + + + + + + `, + + '--ck-spacing-surface-padding-inline': ` + + + + Item + Item + + + padding + `, + + '--ck-spacing-surface-item-gap-inline': ` + + + + Item + Item + + + gap + + `, + + // ---- Semantic — Shape ---- + '--ck-border-radius-control': ` + + Button + + + + r + `, + + '--ck-border-radius-surface': ` + + Panel / Dropdown + + Item + + + + r + `, + + // ---- Semantic — Colors ---- + '--ck-color-surface-container': ` + + container surface + + + Item + Item + `, + + '--ck-color-border-control': ` + + Input + border-color + `, + + '--ck-color-interactive-hover-surface': ` + + Normal + + Hovered + ← this color + + `, + + '--ck-color-interactive-selected-surface': ` + + Off + + On + selected + + Off + `, + + // ---- Semantic — Shadow ---- + '--ck-shadow-surface-floating': ` + + Toolbar + + Floating panel + ↑ shadow applied here + + + `, + + // ---- Semantic — Border width ---- + '--ck-border-width-control': ` + + 1px border + thin + + 3px border + thick + `, + + // ---- Semantic — Divider ---- + '--ck-color-divider': ` + + + Item + + + Item + divider + `, + + // ---- Semantic — Spacing (additional) ---- + '--ck-spacing-control-icon-gap': ` + + + ic + Label + + + gap + `, + + '--ck-spacing-control-meta-gap': ` + + Label + Ctrl+B + + + meta gap + `, + + '--ck-spacing-surface-padding-block': ` + + + + + + + + `, + + '--ck-spacing-surface-item-gap-block': ` + + + Item + + Item + + + gap + `, + + '--ck-spacing-surface-section-gap-block': ` + + + + + + + + | + section gap + `, + + '--ck-spacing-region-padding-inline': ` + + + Editor region + + + region padding inline + `, + + '--ck-spacing-region-padding-block': ` + + + Editor region + + + + + `, + + '--ck-size-control-min-height': ` + + + + With label + + min-height + `, + + // ---- Semantic — Spacing (compact variants, shared) ---- + '--ck-spacing-control-padding-inline-compact': ` + + Regular + + + + Compact + + + ← narrower + `, + + '--ck-spacing-control-padding-block-regular': ` + + Regular + + + + Compact + + + `, + + '--ck-spacing-control-padding-block-compact': ` + + Regular + + + + Compact + + + ← shorter + `, + + // ---- Semantic — Shape (additional) ---- + '--ck-border-radius-uniform': ` + + Trigger + + Attached + corners cut + + Trigger + + Uniform + all corners + `, + + '--ck-border-radius-surface-attached': ` + + Trigger ▾ + + Panel + + attached + radius + `, + + '--ck-border-radius-surface-attached-top': ` + + Panel (above) + + Trigger + attached at top — bottom corners adjusted + `, + + '--ck-border-radius-surface-attached-bottom': ` + + Trigger + + Panel (below) + attached at bottom — top corners adjusted + `, + + '--ck-border-radius-surface-cut-top-left': ` + + + Action + + + + cut corner + Split button open: + top-left corner cut + to match trigger + `, + + '--ck-border-radius-surface-cut-top-right': ` + + + + + top-right cut + `, + + '--ck-border-radius-surface-cut-bottom-right': ` + + + bottom-right cut + `, + + '--ck-border-radius-surface-cut-bottom-left': ` + + + bottom-left cut + `, + + '--ck-border-width-surface': ` + + Panel + border-width on surfaces + `, + + '--ck-border-width-divider': ` + + Section + + + Section + divider width + `, + + // ---- Semantic — Focus ---- + '--ck-interactive-focus-ring': ` + + Focused Button + ← focus ring (border) + `, + + '--ck-interactive-focus-shadow': ` + + Focused + outer glow = focus shadow + + + `, + + // ---- Semantic — Surfaces comparison ---- + '--ck-color-surface-canvas': ` + + canvas (outermost) + + control + + container + `, + + '--ck-color-surface-control': ` + + + control + + control + `, + + '--ck-color-surface-inverse': ` + + Tooltip text + inverted surface + `, + + '--ck-color-border-container': ` + + Container + container border color + `, + + // ---- Semantic — Interactive (additional) ---- + '--ck-color-interactive-active-surface': ` + + Normal + + Pressed + active surface + `, + + '--ck-color-interactive-primary-surface': ` + + Save + primary action surface + `, + + // ---- Semantic — Balloon arrow ---- + '--ck-balloon-panel-arrow-display': ` + + + Arrow + + No arrow + display: none + `, + + // ---- Component — Button anatomy ---- + '--ck-button-padding': ` + + + ic + Label + + + + + button padding (all sides) + `, + + '--ck-button-border-radius': ` + + Button + + + + r + `, + + '--ck-button-border': ` + + Button + border shorthand + `, + + // ---- Component — Input anatomy ---- + '--ck-input-padding': ` + + Input text... + + + + + `, + + '--ck-input-border-radius': ` + + Input field + + r + `, + + '--ck-input-border': ` + + Input field + border shorthand + `, + + // ---- Component — Toolbar anatomy ---- + '--ck-toolbar-item-gap-inline': ` + + + + + + item gap + `, + + '--ck-toolbar-padding': ` + + + + + + + + toolbar padding + `, + + // ---- Component — Dropdown anatomy ---- + '--ck-dropdown-panel-padding': ` + + Trigger ▾ + + + + + + panel padding + `, + + // ---- Component — List anatomy ---- + '--ck-list-padding': ` + + + + + + + + `, + + // ---- Component — Switch anatomy ---- + '--ck-switch-button-toggle-border-radius': ` + + + Off + + + On + + track radius + `, + + '--ck-switch-button-toggle-inner-border-radius': ` + + + r + handle radius + `, + + // ---- Component — Dialog anatomy ---- + '--ck-dialog-border-radius': ` + + + Dialog + content area + + r + `, + + // ---- Component — Balloon panel anatomy ---- + '--ck-balloon-panel-border-radius': ` + + + Balloon panel + + r + `, + + // ---- Component — Color grid anatomy ---- + '--ck-color-grid-tile-size': ` + + + + + + + + + + tile size + `, + + '--ck-color-grid-gap': ` + + + + + + + + + + gap between tiles + `, + + // ---- Component — Editor UI anatomy ---- + '--ck-editor-editable-padding': ` + + + Toolbar + + Content... + + + + + `, + + '--ck-editor-frame-border-radius': ` + + + Toolbar + Editor + + r + `, + + // ---- Component — Dropdown list background ---- + '--ck-dropdown-list-background-color': ` + + + list background + transparent = panel + corners show through + ` +}; +/* eslint-enable max-len */ + +// --------------------------------------------------------------------------- +// Token reference map — shows which foundation/semantic token a token uses. +// Only tokens that reference other --ck-* tokens via var() are listed. +// --------------------------------------------------------------------------- + +/* eslint-disable max-len */ +const TOKEN_REFS = { + // Foundation — derived from other foundation tokens + '--ck-spacing-xl': '--ck-spacing-unit', '--ck-spacing-lg': '--ck-spacing-unit', + '--ck-spacing-base': '--ck-spacing-unit', '--ck-spacing-md': '--ck-spacing-unit', + '--ck-spacing-ms': '--ck-spacing-unit', '--ck-spacing-sm': '--ck-spacing-unit', + '--ck-spacing-xs': '--ck-spacing-unit', '--ck-spacing-2xs': '--ck-spacing-unit', + '--ck-focus-shadow': '--ck-focus-shadow-geometry', + '--ck-focus-shadow-disabled': '--ck-focus-shadow-geometry', + '--ck-focus-shadow-error': '--ck-focus-shadow-geometry', + '--ck-focus-border-color': '--ck-color-focus-border', + '--ck-inset-shadow-sm': '--ck-color-shadow-inner', + '--ck-shadow-md': '--ck-color-shadow-drop', + '--ck-shadow-lg': '--ck-color-shadow-drop-active', + '--ck-animation-duration-fast': '--ck-duration-fast', + '--ck-animation-duration-base': '--ck-duration-base', + '--ck-animation-duration-slow': '--ck-duration-slow', + '--ck-animation-ease-standard': '--ck-ease-standard', + '--ck-animation-ease-interactive': '--ck-ease-interactive', + '--ck-z-overlay': '--ck-z-base', + + // Semantic — colors + '--ck-color-surface-canvas': '--ck-color-base-background', + '--ck-color-surface-control': '--ck-color-surface-canvas', + '--ck-color-surface-container': '--ck-color-surface-canvas', + '--ck-color-surface-inverse': '--ck-color-base-text', + '--ck-color-border-control': '--ck-color-base-border', + '--ck-color-border-container': '--ck-color-base-border', + '--ck-color-divider': '--ck-color-base-border', + '--ck-color-text': '--ck-color-text-primary', + '--ck-color-text-primary': '--ck-color-base-text', + '--ck-color-text-secondary': '--ck-color-base-text-light', + '--ck-color-text-disabled': '--ck-color-text-secondary', + '--ck-color-text-inverse': '--ck-color-base-background', + '--ck-color-text-error': '--ck-color-feedback-error', + '--ck-color-feedback-error': '--ck-color-base-error', + '--ck-color-feedback-success': '--ck-color-base-success', + '--ck-color-feedback-warning': '--ck-color-base-warning', + '--ck-color-feedback-highlight': '--ck-color-base-highlight', + '--ck-color-interactive-hover-surface': '--ck-color-base-hover', + '--ck-color-interactive-active-surface': '--ck-color-base-hover', + '--ck-color-interactive-selected-surface': '--ck-color-base-selected', + '--ck-color-interactive-selected-surface-hover': '--ck-color-base-selected-hover', + '--ck-color-interactive-selected-text': '--ck-color-base-active', + '--ck-color-interactive-primary-surface': '--ck-color-base-action', + '--ck-color-interactive-primary-surface-hover': '--ck-color-base-action-hover', + '--ck-color-interactive-primary-text': '--ck-color-text-inverse', + '--ck-color-interactive-focus-shadow': '--ck-color-base-focus-shadow', + + // Semantic — interactive focus + '--ck-interactive-focus-ring': '--ck-focus-ring', + '--ck-interactive-focus-border-color': '--ck-focus-border-color', + '--ck-interactive-focus-shadow': '--ck-focus-shadow', + '--ck-interactive-focus-disabled-shadow': '--ck-focus-shadow-disabled', + '--ck-interactive-focus-error-shadow': '--ck-focus-shadow-error', + + // Semantic — shape + '--ck-border-width-control': '--ck-border-width-thin', + '--ck-border-width-surface': '--ck-border-width-thin', + '--ck-border-width-divider': '--ck-border-width-thin', + '--ck-border-width-emphasis': '--ck-border-width-thick', + '--ck-radius-corners': '--ck-radius-base', + '--ck-border-radius-control': '--ck-radius-base', + '--ck-border-radius-surface': '--ck-radius-base', + '--ck-border-radius-surface-attached': '--ck-border-radius-surface', + '--ck-border-radius-surface-attached-top': '--ck-border-radius-surface-attached', + '--ck-border-radius-surface-attached-bottom': '--ck-border-radius-surface-attached', + + // Semantic — spacing + '--ck-spacing-control-padding-block': '--ck-spacing-xs', + '--ck-spacing-control-padding-inline': '--ck-spacing-base', + '--ck-spacing-control-padding-inline-compact': '--ck-spacing-sm', + '--ck-spacing-control-padding-block-regular': '--ck-spacing-sm', + '--ck-spacing-control-padding-block-compact': '--ck-spacing-2xs', + '--ck-spacing-control-icon-gap': '--ck-spacing-md', + '--ck-spacing-control-meta-gap': '--ck-spacing-lg', + '--ck-spacing-surface-padding-inline': '--ck-spacing-sm', + '--ck-spacing-surface-padding-block': '--ck-spacing-sm', + '--ck-spacing-surface-item-gap-inline': '--ck-spacing-sm', + '--ck-spacing-region-padding-inline': '--ck-spacing-base', + '--ck-spacing-region-padding-block': '--ck-spacing-base', + + // Semantic — typography + '--ck-font-weight-ui-default': '--ck-font-weight-normal', + '--ck-font-weight-ui-strong': '--ck-font-weight-bold', + '--ck-font-weight-ui-heading': '--ck-font-weight-bold', + '--ck-font-weight-ui-label': '--ck-font-weight-semibold', + '--ck-font-weight-ui-emphasis': '--ck-font-weight-bold', + '--ck-font-weight-ui-muted': '--ck-font-weight-normal', + + // Semantic — motion + '--ck-transition-duration-control-fast': '--ck-duration-fast', + '--ck-transition-duration-control': '--ck-duration-base', + '--ck-transition-duration-control-emphasized': '--ck-duration-slow', + '--ck-transition-duration-surface': '--ck-duration-slower', + '--ck-transition-timing-function-control': '--ck-ease-interactive', + '--ck-transition-timing-function-surface': '--ck-ease-standard', + + // Semantic — layout, shadow, layer + '--ck-size-control-min-height': '--ck-size-min-height', + '--ck-shadow-surface-floating': '--ck-shadow-md', + '--ck-layer-base': '--ck-z-base', + '--ck-layer-panel': '--ck-z-overlay', + '--ck-layer-dialog': '--ck-z-modal', + + // Component — button + '--ck-button-border-radius': '--ck-border-radius-control', + '--ck-button-focus-border-color': '--ck-interactive-focus-border-color', + '--ck-button-opacity-disabled': '--ck-opacity-disabled', + '--ck-button-default-hover-background-color': '--ck-color-interactive-hover-surface', + '--ck-button-default-active-background-color': '--ck-color-interactive-active-surface', + '--ck-button-on-background-color': '--ck-color-interactive-selected-surface', + '--ck-button-on-hover-background-color': '--ck-color-interactive-selected-surface-hover', + '--ck-button-on-text-color': '--ck-color-interactive-selected-text', + '--ck-button-action-background-color': '--ck-color-interactive-primary-surface', + '--ck-button-action-hover-background-color': '--ck-color-interactive-primary-surface-hover', + '--ck-button-action-text-color': '--ck-color-interactive-primary-text', + '--ck-button-save-color': '--ck-color-feedback-success', + '--ck-button-cancel-color': '--ck-color-feedback-warning', + '--ck-switch-button-on-background-color': '--ck-button-action-background-color', + '--ck-switch-button-inner-background-color': '--ck-color-surface-canvas', + + // Component — input + '--ck-input-border-radius': '--ck-border-radius-control', + '--ck-input-focus-border-color': '--ck-interactive-focus-border-color', + '--ck-input-background-color': '--ck-color-surface-control', + '--ck-input-border-color': '--ck-color-border-control', + '--ck-input-error-border-color': '--ck-color-feedback-error', + '--ck-input-text-color': '--ck-color-text-primary', + '--ck-input-disabled-text-color': '--ck-color-text-disabled', + + // Component — dropdown + '--ck-dropdown-panel-uniform-border-radius': '--ck-border-radius-uniform', + '--ck-dropdown-panel-border-radius': '--ck-border-radius-surface-attached', + '--ck-dropdown-panel-background-color': '--ck-color-surface-container', + '--ck-dropdown-panel-border-color': '--ck-color-border-container', + + // Component — dropdown menu + '--ck-dropdown-menu-panel-uniform-border-radius': '--ck-border-radius-uniform', + + // Component — list dropdown + '--ck-list-dropdown-uniform-border-radius': '--ck-border-radius-uniform', + + // Component — toolbar + '--ck-toolbar-compact-uniform-border-radius': '--ck-border-radius-uniform', + '--ck-toolbar-border-radius': '--ck-border-radius-surface', + '--ck-toolbar-background-color': '--ck-color-surface-container', + '--ck-toolbar-border-color': '--ck-color-border-container', + + // Component — dialog + '--ck-dialog-border-radius': '--ck-border-radius-surface', + '--ck-dialog-background-color': '--ck-color-surface-container', + + // Component — editor UI + '--ck-editor-editable-focus-border-color': '--ck-interactive-focus-border-color', + '--ck-editor-frame-border-radius': '--ck-border-radius-surface', + + // Component — list + '--ck-list-border-radius': '--ck-border-radius-surface', + '--ck-list-background-color': '--ck-color-surface-control', + '--ck-list-button-hover-background-color': '--ck-button-default-hover-background-color', + '--ck-list-button-on-background-color': '--ck-button-on-text-color', + '--ck-list-button-on-text-color': '--ck-color-text-inverse', + + // Component — panel + '--ck-balloon-panel-background-color': '--ck-color-surface-container', + '--ck-balloon-panel-border-color': '--ck-color-border-container', + + // Component — sticky panel + '--ck-sticky-panel-uniform-border-radius': '--ck-border-radius-uniform', + + // Component — menu bar + '--ck-menu-bar-panel-uniform-border-radius': '--ck-border-radius-uniform', + + // Component — color selector + '--ck-color-selector-uniform-border-radius': '--ck-border-radius-uniform', + + // Component — autocomplete + '--ck-autocomplete-results-uniform-border-radius': '--ck-border-radius-uniform', + + // Component — tooltip + '--ck-tooltip-background-color': '--ck-color-surface-inverse', + '--ck-tooltip-text-color': '--ck-color-text-inverse' +}; +/* eslint-enable max-len */ + +// --------------------------------------------------------------------------- +// Reverse dependency map: base token → list of tokens that depend on it. +// Built from TOKEN_REFS at init time. Used to cascade input refreshes. +// --------------------------------------------------------------------------- + +const DEPENDENTS = {}; + +for ( const [ dependent, base ] of Object.entries( TOKEN_REFS ) ) { + if ( !DEPENDENTS[ base ] ) { + DEPENDENTS[ base ] = []; + } + + DEPENDENTS[ base ].push( dependent ); +} + +/** + * After a token value changes, refresh the displayed input values of all + * tokens that depend on it (directly or transitively). Only non-overridden + * rows are refreshed — manually changed values are preserved. + */ +function refreshDependents( changedToken ) { + const directDependents = DEPENDENTS[ changedToken ]; + + if ( !directDependents ) { + return; + } + + for ( const dep of directDependents ) { + const row = document.querySelector( `.token-row[data-token="${ dep }"]` ); + + if ( row && !row.classList.contains( 'is-overridden' ) ) { + refreshRow( row ); + } + + // Recurse — if B depends on A, and C depends on B, changing A refreshes both B and C. + refreshDependents( dep ); + } +} + +/** + * Scrolls to a token row, opens its parent
elements, and plays + * a highlight blink animation so the user can see where the source token lives. + */ +function scrollToAndHighlightToken( tokenName ) { + const targetRow = document.querySelector( `.token-row[data-token="${ tokenName }"]` ); + + if ( !targetRow ) { + return; + } + + // Open all ancestor
elements so the row is visible. + let ancestor = targetRow.parentElement; + + while ( ancestor ) { + if ( ancestor.tagName === 'DETAILS' && !ancestor.open ) { + ancestor.open = true; + } + + ancestor = ancestor.parentElement; + } + + // Scroll into view. + targetRow.scrollIntoView( { behavior: 'smooth', block: 'center' } ); + + // Blink highlight. + targetRow.classList.remove( 'token-row--blink' ); + // Force reflow so re-adding the class restarts the animation. + targetRow.offsetWidth; // eslint-disable-line no-unused-expressions + targetRow.classList.add( 'token-row--blink' ); + + targetRow.addEventListener( 'animationend', () => { + targetRow.classList.remove( 'token-row--blink' ); + }, { once: true } ); +} + +// --------------------------------------------------------------------------- +// Auto-detect token type from its name +// --------------------------------------------------------------------------- + +function inferType( name ) { + if ( name.includes( 'color' ) || name.includes( 'background' ) ) { + return 'color'; + } + + if ( name.includes( 'opacity' ) ) { + return 'opacity'; + } + + if ( name.includes( 'font-weight' ) ) { + return 'weight'; + } + + if ( name.includes( 'font-family' ) ) { + return 'text'; + } + + if ( name.includes( 'duration' ) ) { + return 'duration'; + } + + if ( name.includes( 'ease' ) || name.includes( 'timing-function' ) ) { + return 'easing'; + } + + if ( name.includes( 'z-index' ) || name.includes( '-layer' ) || name === '--ck-z-base' || + name === '--ck-z-overlay' || name === '--ck-z-modal' ) { + return 'number'; + } + + if ( name.includes( 'shadow' ) || name.includes( 'transition' ) || name.includes( 'animation' ) || + name.includes( 'border' ) && !name.includes( 'radius' ) && !name.includes( 'width' ) || + name.includes( 'ring' ) ) { + return 'text'; + } + + // Default: treat as size (px, em, calc) + return 'size'; +} + +// --------------------------------------------------------------------------- +// Helper: convert color string to hex for color picker +// --------------------------------------------------------------------------- + +function colorToHex( colorStr ) { + const temp = document.createElement( 'div' ); + temp.style.color = colorStr; + document.body.appendChild( temp ); + const computed = getComputedStyle( temp ).color; + document.body.removeChild( temp ); + + const match = computed.match( /(\d+),\s*(\d+),\s*(\d+)/ ); + + if ( !match ) { + return '#000000'; + } + + return '#' + [ match[ 1 ], match[ 2 ], match[ 3 ] ] + .map( c => parseInt( c ).toString( 16 ).padStart( 2, '0' ) ) + .join( '' ); +} + +function getComputedTokenValue( name ) { + return getComputedStyle( document.documentElement ).getPropertyValue( name ).trim(); +} + +// --------------------------------------------------------------------------- +// WCAG contrast checking +// --------------------------------------------------------------------------- + +/** + * Map of foreground token → background token for contrast ratio calculation. + * The badge is shown on the foreground token's row. + */ +/* eslint-disable max-len */ +const CONTRAST_PAIRS = { + // Semantic — text on surfaces + '--ck-color-text-primary': '--ck-color-surface-canvas', + '--ck-color-text-secondary': '--ck-color-surface-canvas', + '--ck-color-text-disabled': '--ck-color-surface-canvas', + '--ck-color-text-inverse': '--ck-color-surface-inverse', + '--ck-color-text-error': '--ck-color-surface-canvas', + '--ck-color-interactive-selected-text': '--ck-color-interactive-selected-surface', + '--ck-color-interactive-primary-text': '--ck-color-interactive-primary-surface', + + // Button + '--ck-button-on-text-color': '--ck-button-on-background-color', + '--ck-button-action-text-color': '--ck-button-action-background-color', + '--ck-button-save-color': '--ck-color-surface-control', + '--ck-button-cancel-color': '--ck-color-surface-control', + + // Input + '--ck-input-text-color': '--ck-input-background-color', + '--ck-input-disabled-text-color': '--ck-input-disabled-background-color', + + // List + '--ck-list-button-on-text-color': '--ck-list-button-on-background-color', + + // Tooltip + '--ck-tooltip-text-color': '--ck-tooltip-background-color', + + // Containers — text on component backgrounds + '--ck-color-text': '--ck-color-surface-control' +}; +/* eslint-enable max-len */ + +/** + * Build a reverse map: background token → [ foreground tokens ]. + * Used to refresh contrast badges when a background token changes. + */ +const CONTRAST_REVERSE = {}; + +for ( const [ fg, bg ] of Object.entries( CONTRAST_PAIRS ) ) { + if ( !CONTRAST_REVERSE[ bg ] ) { + CONTRAST_REVERSE[ bg ] = []; + } + + CONTRAST_REVERSE[ bg ].push( fg ); +} + +/** + * Parse a computed color string (rgb/rgba) to { r, g, b } (0-255). + */ +function parseColor( colorStr ) { + const temp = document.createElement( 'div' ); + temp.style.color = colorStr; + document.body.appendChild( temp ); + const computed = getComputedStyle( temp ).color; + document.body.removeChild( temp ); + + const match = computed.match( /(\d+),\s*(\d+),\s*(\d+)/ ); + + if ( !match ) { + return null; + } + + return { + r: parseInt( match[ 1 ] ), + g: parseInt( match[ 2 ] ), + b: parseInt( match[ 3 ] ) + }; +} + +/** + * Calculate relative luminance per WCAG 2.1. + */ +function relativeLuminance( { r, g, b } ) { + const [ rs, gs, bs ] = [ r, g, b ].map( c => { + const s = c / 255; + + return s <= 0.03928 ? s / 12.92 : Math.pow( ( s + 0.055 ) / 1.055, 2.4 ); + } ); + + return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs; +} + +/** + * Calculate WCAG contrast ratio between two colors. + * Returns a number >= 1. + */ +function contrastRatio( fg, bg ) { + const fgColor = parseColor( fg ); + const bgColor = parseColor( bg ); + + if ( !fgColor || !bgColor ) { + return null; + } + + const l1 = relativeLuminance( fgColor ); + const l2 = relativeLuminance( bgColor ); + const lighter = Math.max( l1, l2 ); + const darker = Math.min( l1, l2 ); + + return ( lighter + 0.05 ) / ( darker + 0.05 ); +} + +/** + * Update the contrast badge on a foreground token row. + */ +function updateContrastBadge( row ) { + const token = row.dataset.token; + const bgToken = CONTRAST_PAIRS[ token ]; + + if ( !bgToken ) { + return; + } + + const badge = row.querySelector( '.token-contrast' ); + + if ( !badge ) { + return; + } + + const swatches = badge.querySelectorAll( '.token-contrast-swatch' ); + const ratioLabel = badge.lastElementChild; + + const fgValue = getComputedTokenValue( token ); + const bgValue = getComputedTokenValue( bgToken ); + + // Update swatches. + if ( swatches[ 0 ] ) { + swatches[ 0 ].style.background = fgValue; + } + + if ( swatches[ 1 ] ) { + swatches[ 1 ].style.background = bgValue; + } + + const ratio = contrastRatio( fgValue, bgValue ); + + if ( ratio === null ) { + ratioLabel.textContent = ''; + badge.className = 'token-contrast'; + badge.style.cursor = 'pointer'; + + return; + } + + const ratioStr = ratio.toFixed( 1 ) + ':1'; + const passAA = ratio >= 4.5; + const passAAA = ratio >= 7; + + let label; + + if ( passAAA ) { + label = 'AAA'; + } else if ( passAA ) { + label = 'AA'; + } else { + label = 'Fail'; + } + + ratioLabel.textContent = ratioStr + ' ' + label; + badge.className = 'token-contrast'; + badge.style.cursor = 'pointer'; + badge.classList.add( passAA ? 'token-contrast-pass' : 'token-contrast-fail' ); + badge.title = 'Click to scroll to ' + bgToken + + ' — WCAG AA requires 4.5:1 for normal text'; +} + +// --------------------------------------------------------------------------- +// UI generation +// --------------------------------------------------------------------------- + +function createTokenRow( name ) { + const type = inferType( name ); + const row = document.createElement( 'div' ); + row.className = 'token-row'; + row.dataset.token = name; + + // Token name + const nameEl = document.createElement( 'div' ); + nameEl.className = 'token-name'; + nameEl.title = name; + + const nameText = document.createElement( 'span' ); + nameText.className = 'token-name-text'; + nameText.textContent = name.replace( /^--ck-/, '' ); + nameText.title = 'Click to copy: ' + name; + nameText.addEventListener( 'click', () => { + navigator.clipboard.writeText( name ); + nameText.classList.add( 'token-name-copied' ); + setTimeout( () => nameText.classList.remove( 'token-name-copied' ), 800 ); + } ); + nameEl.appendChild( nameText ); + + const description = TOKEN_DESCRIPTIONS[ name ]; + + if ( description ) { + const descEl = document.createElement( 'span' ); + descEl.className = 'token-description'; + + if ( description.includes( '\u26A0' ) ) { + const parts = description.split( '\u26A0' ); + descEl.append( parts[ 0 ] ); + + const warn = document.createElement( 'span' ); + warn.className = 'token-description-warning'; + warn.textContent = '\u26A0' + parts[ 1 ]; + descEl.appendChild( warn ); + } else { + descEl.textContent = description; + } + + nameEl.appendChild( descEl ); + } + + const diagram = TOKEN_DIAGRAMS[ name ]; + + if ( diagram ) { + const diagramBtn = document.createElement( 'span' ); + diagramBtn.className = 'token-diagram-toggle'; + diagramBtn.textContent = '\uD83D\uDDBC'; + diagramBtn.title = 'Show diagram'; + + const diagramEl = document.createElement( 'div' ); + diagramEl.className = 'token-diagram'; + diagramEl.innerHTML = diagram; + diagramEl.hidden = true; + + diagramBtn.addEventListener( 'click', () => { + diagramEl.hidden = !diagramEl.hidden; + } ); + + nameEl.appendChild( diagramBtn ); + nameEl.appendChild( diagramEl ); + } + + const ref = TOKEN_REFS[ name ]; + + if ( ref ) { + const refEl = document.createElement( 'span' ); + refEl.className = 'token-ref'; + refEl.textContent = '\u2190 ' + ref.replace( /^--ck-/, '' ); + refEl.title = ref; + + refEl.addEventListener( 'click', () => { + scrollToAndHighlightToken( ref ); + } ); + + nameEl.appendChild( refEl ); + } + + row.appendChild( nameEl ); + + // Input control + const inputWrap = document.createElement( 'div' ); + inputWrap.className = 'token-input'; + + const currentValue = getComputedTokenValue( name ); + + if ( type === 'color' ) { + const colorInput = document.createElement( 'input' ); + colorInput.type = 'color'; + + try { + colorInput.value = colorToHex( currentValue ); + } catch { + colorInput.value = '#000000'; + } + + const textInput = document.createElement( 'input' ); + textInput.type = 'text'; + textInput.value = currentValue; + + colorInput.addEventListener( 'input', () => { + document.documentElement.style.setProperty( name, colorInput.value ); + textInput.value = colorInput.value; + row.classList.add( 'is-overridden' ); + row.classList.remove( 'is-preset-changed' ); + refreshDependents( name ); + updateContrastBadge( row ); + } ); + + textInput.addEventListener( 'change', () => { + document.documentElement.style.setProperty( name, textInput.value ); + + try { + colorInput.value = colorToHex( textInput.value ); + } catch { + // Ignore. + } + + row.classList.add( 'is-overridden' ); + row.classList.remove( 'is-preset-changed' ); + refreshDependents( name ); + updateContrastBadge( row ); + } ); + + inputWrap.appendChild( colorInput ); + inputWrap.appendChild( textInput ); + } else if ( type === 'opacity' ) { + const range = document.createElement( 'input' ); + range.type = 'range'; + range.min = '0'; + range.max = '1'; + range.step = '0.05'; + range.value = parseFloat( currentValue ) || 0.5; + + const textInput = document.createElement( 'input' ); + textInput.type = 'text'; + textInput.value = currentValue; + + range.addEventListener( 'input', () => { + document.documentElement.style.setProperty( name, range.value ); + textInput.value = range.value; + row.classList.add( 'is-overridden' ); + row.classList.remove( 'is-preset-changed' ); + refreshDependents( name ); + updateContrastBadge( row ); + } ); + + textInput.addEventListener( 'change', () => { + document.documentElement.style.setProperty( name, textInput.value ); + range.value = parseFloat( textInput.value ) || 0; + row.classList.add( 'is-overridden' ); + row.classList.remove( 'is-preset-changed' ); + refreshDependents( name ); + updateContrastBadge( row ); + } ); + + inputWrap.appendChild( range ); + inputWrap.appendChild( textInput ); + } else if ( type === 'duration' ) { + const range = document.createElement( 'input' ); + range.type = 'range'; + range.min = '0'; + range.max = '2'; + range.step = '0.05'; + range.value = parseFloat( currentValue ) || 0.2; + + const textInput = document.createElement( 'input' ); + textInput.type = 'text'; + textInput.value = currentValue; + + range.addEventListener( 'input', () => { + const val = range.value + 's'; + document.documentElement.style.setProperty( name, val ); + textInput.value = val; + row.classList.add( 'is-overridden' ); + row.classList.remove( 'is-preset-changed' ); + refreshDependents( name ); + updateContrastBadge( row ); + } ); + + textInput.addEventListener( 'change', () => { + document.documentElement.style.setProperty( name, textInput.value ); + range.value = parseFloat( textInput.value ) || 0; + row.classList.add( 'is-overridden' ); + row.classList.remove( 'is-preset-changed' ); + refreshDependents( name ); + updateContrastBadge( row ); + } ); + + inputWrap.appendChild( range ); + inputWrap.appendChild( textInput ); + } else if ( type === 'weight' ) { + const select = document.createElement( 'select' ); + + for ( const w of [ 100, 200, 300, 400, 500, 600, 700, 800, 900, 'inherit' ] ) { + const opt = document.createElement( 'option' ); + opt.value = w; + opt.textContent = w; + + if ( String( w ) === currentValue.trim() ) { + opt.selected = true; + } + + select.appendChild( opt ); + } + + select.addEventListener( 'change', () => { + document.documentElement.style.setProperty( name, select.value ); + row.classList.add( 'is-overridden' ); + row.classList.remove( 'is-preset-changed' ); + refreshDependents( name ); + updateContrastBadge( row ); + } ); + + inputWrap.appendChild( select ); + } else if ( type === 'easing' ) { + const select = document.createElement( 'select' ); + const easings = [ 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear', 'cubic-bezier(0, 0, 0.24, 0.95)' ]; + + for ( const e of easings ) { + const opt = document.createElement( 'option' ); + opt.value = e; + opt.textContent = e.length > 20 ? 'cubic-bezier(...)' : e; + + if ( e === currentValue.trim() ) { + opt.selected = true; + } + + select.appendChild( opt ); + } + + select.addEventListener( 'change', () => { + document.documentElement.style.setProperty( name, select.value ); + row.classList.add( 'is-overridden' ); + row.classList.remove( 'is-preset-changed' ); + refreshDependents( name ); + updateContrastBadge( row ); + } ); + + inputWrap.appendChild( select ); + } else if ( type === 'number' ) { + const numInput = document.createElement( 'input' ); + numInput.type = 'number'; + numInput.value = parseInt( currentValue ) || 0; + + numInput.addEventListener( 'change', () => { + document.documentElement.style.setProperty( name, numInput.value ); + row.classList.add( 'is-overridden' ); + row.classList.remove( 'is-preset-changed' ); + refreshDependents( name ); + updateContrastBadge( row ); + } ); + + inputWrap.appendChild( numInput ); + } else { + const textInput = document.createElement( 'input' ); + textInput.type = 'text'; + textInput.value = currentValue; + + textInput.addEventListener( 'change', () => { + document.documentElement.style.setProperty( name, textInput.value ); + row.classList.add( 'is-overridden' ); + row.classList.remove( 'is-preset-changed' ); + refreshDependents( name ); + updateContrastBadge( row ); + } ); + + inputWrap.appendChild( textInput ); + } + + row.appendChild( inputWrap ); + + // Contrast badge (only for foreground tokens in CONTRAST_PAIRS). + if ( CONTRAST_PAIRS[ name ] ) { + const bgToken = CONTRAST_PAIRS[ name ]; + const badge = document.createElement( 'span' ); + badge.className = 'token-contrast'; + badge.style.cursor = 'pointer'; + badge.title = 'Click to scroll to ' + bgToken; + + const fgSwatch = document.createElement( 'span' ); + fgSwatch.className = 'token-contrast-swatch'; + + const bgSwatch = document.createElement( 'span' ); + bgSwatch.className = 'token-contrast-swatch'; + + const ratioLabel = document.createElement( 'span' ); + + badge.appendChild( fgSwatch ); + badge.appendChild( bgSwatch ); + badge.appendChild( ratioLabel ); + + badge.addEventListener( 'click', () => { + scrollToAndHighlightToken( bgToken ); + } ); + + row.appendChild( badge ); + } + + // Reset button + const resetBtn = document.createElement( 'button' ); + resetBtn.className = 'token-reset'; + resetBtn.textContent = '\u21BA'; + resetBtn.title = 'Reset to default'; + resetBtn.addEventListener( 'click', () => { + document.documentElement.style.removeProperty( name ); + row.classList.remove( 'is-overridden' ); + refreshRow( row ); + refreshDependents( name ); + + // If a preset is active and affects this token, restore the amber highlight. + row.classList.toggle( 'is-preset-changed', isTokenChangedByPreset( name ) ); + } ); + + row.appendChild( resetBtn ); + + return row; +} + +function refreshRow( row ) { + const tokenName = row.dataset.token; + const newVal = getComputedTokenValue( tokenName ); + const inputs = row.querySelectorAll( 'input, select' ); + + for ( const input of inputs ) { + if ( input.type === 'color' ) { + try { + input.value = colorToHex( newVal ); + } catch { + // Ignore. + } + } else if ( input.type === 'range' ) { + input.value = parseFloat( newVal ) || 0; + } else if ( input.type === 'number' ) { + const parsed = parseInt( newVal ); + input.value = isNaN( parsed ) ? '' : parsed; + } else if ( input.tagName === 'SELECT' ) { + input.value = newVal.trim(); + } else { + input.value = newVal; + } + } + + // Update contrast badge on this row (if it's a foreground token). + updateContrastBadge( row ); + + // If this token is a background in a contrast pair, update the foreground row's badge. + const affectedForegrounds = CONTRAST_REVERSE[ tokenName ]; + + if ( affectedForegrounds ) { + const panel = document.getElementById( 'token-panel' ); + + for ( const fgToken of affectedForegrounds ) { + const fgRow = panel.querySelector( + `.token-row[data-token="${ fgToken }"]` + ); + + if ( fgRow ) { + updateContrastBadge( fgRow ); + } + } + } +} + +// --------------------------------------------------------------------------- +// Stylesheet preset manager — paste, compare, and switch between stylesheets. +// --------------------------------------------------------------------------- + +const stylesheetEntries = []; +let stylesheetNextId = 1; +let stylesheetActiveId = null; + +// When true, selecting/adding/updating a stylesheet clears all manual inline overrides first. +let clearOverridesOnSwitch = false; + +function clearAllInlineOverrides() { + const panel = document.getElementById( 'token-panel' ); + const allTokens = [ ...Object.values( FOUNDATION ), ...Object.values( SEMANTIC ), ...Object.values( COMPONENT ) ].flat(); + + for ( const token of allTokens ) { + document.documentElement.style.removeProperty( token ); + } + + for ( const row of panel.querySelectorAll( '.token-row' ) ) { + row.classList.remove( 'is-overridden' ); + } +} + +function refreshAllRows() { + const panel = document.getElementById( 'token-panel' ); + + for ( const row of panel.querySelectorAll( '.token-row' ) ) { + refreshRow( row ); + } +} + +function refreshAllNonOverriddenRows() { + const panel = document.getElementById( 'token-panel' ); + + for ( const row of panel.querySelectorAll( '.token-row' ) ) { + if ( !row.classList.contains( 'is-overridden' ) ) { + refreshRow( row ); + } + } +} + +/** + * Parse CSS text and return a Set of --ck-* token names that are declared. + */ +function parseTokensFromCss( cssText ) { + const tokens = new Set(); + const re = /(--ck-[\w-]+)\s*:/g; + let match; + + while ( ( match = re.exec( cssText ) ) !== null ) { + tokens.add( match[ 1 ] ); + } + + return tokens; +} + +function activateStylesheet( id ) { + const panel = document.getElementById( 'token-panel' ); + + // Deactivate current. + if ( stylesheetActiveId !== null ) { + const current = stylesheetEntries.find( e => e.id === stylesheetActiveId ); + + if ( current ) { + current.styleEl.media = 'not all'; + } + } + + // Clear inline overrides if the flag is set. + if ( clearOverridesOnSwitch ) { + clearAllInlineOverrides(); + } + + stylesheetActiveId = id; + + // Determine which tokens the new stylesheet explicitly declares. + let declaredTokens = new Set(); + + if ( id !== null ) { + const entry = stylesheetEntries.find( e => e.id === id ); + + if ( entry ) { + entry.styleEl.removeAttribute( 'media' ); + declaredTokens = parseTokensFromCss( entry.cssText ); + } + } + + // Wait for style recalculation, then refresh and mark changed rows. + requestAnimationFrame( () => { + if ( clearOverridesOnSwitch ) { + refreshAllRows(); + } else { + refreshAllNonOverriddenRows(); + } + + // Mark tokens that the stylesheet explicitly declares. + for ( const row of panel.querySelectorAll( '.token-row' ) ) { + const token = row.dataset.token; + + if ( declaredTokens.has( token ) && !row.classList.contains( 'is-overridden' ) ) { + row.classList.add( 'is-preset-changed' ); + } else { + row.classList.remove( 'is-preset-changed' ); + } + } + } ); +} + +function removeStylesheet( id, listContainer, refs ) { + const idx = stylesheetEntries.findIndex( e => e.id === id ); + + if ( idx === -1 ) { + return; + } + + const entry = stylesheetEntries[ idx ]; + entry.styleEl.remove(); + stylesheetEntries.splice( idx, 1 ); + + if ( stylesheetActiveId === id ) { + stylesheetActiveId = null; + + // Clear textarea since the active entry was removed. + refs.textarea.value = ''; + refs.nameInput.value = ''; + refs.addBtn.textContent = 'Add Stylesheet'; + refs.addNewBtn.hidden = true; + + requestAnimationFrame( () => { + refreshAllNonOverriddenRows(); + } ); + } + + renderStylesheetList( listContainer, refs ); +} + +/** + * @param {HTMLDivElement} listContainer + * @param {Object} refs Shared references to textarea, nameInput, and addBtn for load-on-select. + */ +function renderStylesheetList( listContainer, refs ) { + listContainer.innerHTML = ''; + + // "None (default)" radio — always first. + const noneEntry = document.createElement( 'div' ); + noneEntry.className = 'stylesheet-entry' + ( stylesheetActiveId === null ? ' is-active' : '' ); + + const noneRadio = document.createElement( 'input' ); + noneRadio.type = 'radio'; + noneRadio.name = 'ck-stylesheet-preset'; + noneRadio.value = ''; + noneRadio.checked = stylesheetActiveId === null; + + noneRadio.addEventListener( 'change', () => { + activateStylesheet( null ); + + // Clear textarea when switching to "None". + refs.textarea.value = ''; + refs.nameInput.value = ''; + refs.addBtn.textContent = 'Add Stylesheet'; + refs.addNewBtn.hidden = true; + + renderStylesheetList( listContainer, refs ); + } ); + + const noneLabel = document.createElement( 'label' ); + noneLabel.textContent = 'None (default)'; + noneLabel.addEventListener( 'click', () => { + noneRadio.checked = true; + noneRadio.dispatchEvent( new Event( 'change' ) ); + } ); + + noneEntry.appendChild( noneRadio ); + noneEntry.appendChild( noneLabel ); + listContainer.appendChild( noneEntry ); + + // One entry per added stylesheet. + for ( const entry of stylesheetEntries ) { + const row = document.createElement( 'div' ); + row.className = 'stylesheet-entry' + ( stylesheetActiveId === entry.id ? ' is-active' : '' ); + + const radio = document.createElement( 'input' ); + radio.type = 'radio'; + radio.name = 'ck-stylesheet-preset'; + radio.value = entry.id; + radio.checked = stylesheetActiveId === entry.id; + + radio.addEventListener( 'change', () => { + activateStylesheet( entry.id ); + + // Load the stylesheet content into the textarea for editing. + refs.textarea.value = entry.cssText; + refs.nameInput.value = entry.name; + refs.addBtn.textContent = 'Update Stylesheet'; + refs.addNewBtn.hidden = false; + + renderStylesheetList( listContainer, refs ); + } ); + + const label = document.createElement( 'label' ); + label.textContent = entry.name; + label.title = entry.name; + label.addEventListener( 'click', () => { + radio.checked = true; + radio.dispatchEvent( new Event( 'change' ) ); + } ); + + const removeBtn = document.createElement( 'button' ); + removeBtn.className = 'stylesheet-remove'; + removeBtn.textContent = '\u00D7'; + removeBtn.title = 'Remove stylesheet'; + removeBtn.addEventListener( 'click', e => { + e.stopPropagation(); + removeStylesheet( entry.id, listContainer, refs ); + } ); + + row.appendChild( radio ); + row.appendChild( label ); + row.appendChild( removeBtn ); + listContainer.appendChild( row ); + } +} + +function generateStylesheetManagerSection( presets ) { + const details = document.createElement( 'details' ); + details.className = 'stylesheet-presets'; + const summary = document.createElement( 'summary' ); + summary.textContent = 'Stylesheet Presets'; + details.appendChild( summary ); + + const manager = document.createElement( 'div' ); + manager.className = 'stylesheet-manager'; + + // Textarea for pasting CSS. + const textarea = document.createElement( 'textarea' ); + textarea.placeholder = 'Paste CSS here (e.g. :root { --ck-radius-base: 10px; })'; + manager.appendChild( textarea ); + + // Controls row: name input + add/update button + reset button. + const controls = document.createElement( 'div' ); + controls.className = 'stylesheet-controls'; + + const nameInput = document.createElement( 'input' ); + nameInput.type = 'text'; + nameInput.placeholder = 'Stylesheet name (optional)'; + + const addBtn = document.createElement( 'button' ); + addBtn.textContent = 'Add Stylesheet'; + + const addNewBtn = document.createElement( 'button' ); + addNewBtn.textContent = 'Add New'; + addNewBtn.title = 'Keep textarea content and create a new stylesheet from it'; + addNewBtn.hidden = true; + + const resetBtn = document.createElement( 'button' ); + resetBtn.textContent = 'Reset'; + resetBtn.title = 'Deselect active stylesheet and clear textarea'; + + controls.appendChild( nameInput ); + controls.appendChild( addBtn ); + controls.appendChild( addNewBtn ); + controls.appendChild( resetBtn ); + manager.appendChild( controls ); + + // Checkbox: clear manual overrides on switch. + const clearRow = document.createElement( 'label' ); + clearRow.className = 'stylesheet-clear-option'; + + const clearCheckbox = document.createElement( 'input' ); + clearCheckbox.type = 'checkbox'; + clearCheckbox.checked = false; + clearCheckbox.addEventListener( 'change', () => { + clearOverridesOnSwitch = clearCheckbox.checked; + } ); + + clearRow.appendChild( clearCheckbox ); + clearRow.append( ' Clear manual overrides on switch' ); + manager.appendChild( clearRow ); + + // List of stylesheet entries with radios. + const listContainer = document.createElement( 'div' ); + listContainer.className = 'stylesheet-list'; + manager.appendChild( listContainer ); + + // Shared refs passed to renderStylesheetList so entries can load into textarea. + const refs = { textarea, nameInput, addBtn, addNewBtn }; + + // Wire up "Add / Update" button. + addBtn.addEventListener( 'click', () => { + const cssText = textarea.value.trim(); + + if ( !cssText ) { + return; + } + + // Update existing entry if one is selected. + if ( stylesheetActiveId !== null ) { + const active = stylesheetEntries.find( e => e.id === stylesheetActiveId ); + + if ( active ) { + active.cssText = cssText; + active.name = nameInput.value.trim() || active.name; + + const panel = document.getElementById( 'token-panel' ); + + if ( clearOverridesOnSwitch ) { + clearAllInlineOverrides(); + } + + active.styleEl.textContent = cssText; + const declaredTokens = parseTokensFromCss( cssText ); + + requestAnimationFrame( () => { + if ( clearOverridesOnSwitch ) { + refreshAllRows(); + } else { + refreshAllNonOverriddenRows(); + } + + for ( const row of panel.querySelectorAll( '.token-row' ) ) { + const token = row.dataset.token; + + if ( declaredTokens.has( token ) && !row.classList.contains( 'is-overridden' ) ) { + row.classList.add( 'is-preset-changed' ); + } else { + row.classList.remove( 'is-preset-changed' ); + } + } + } ); + + renderStylesheetList( listContainer, refs ); + + return; + } + } + + // Otherwise add a new entry. + const name = nameInput.value.trim() || 'Stylesheet ' + stylesheetNextId; + + const entry = { + id: stylesheetNextId++, + name, + cssText, + styleEl: document.createElement( 'style' ) + }; + + entry.styleEl.dataset.ckPreset = entry.id; + entry.styleEl.textContent = cssText; + entry.styleEl.media = 'not all'; + document.head.appendChild( entry.styleEl ); + + stylesheetEntries.push( entry ); + + // Activate the newly added stylesheet and keep it loaded for editing. + activateStylesheet( entry.id ); + addBtn.textContent = 'Update Stylesheet'; + addNewBtn.hidden = false; + + renderStylesheetList( listContainer, refs ); + } ); + + // Wire up "Add New" button — create a new stylesheet from the current textarea content. + addNewBtn.addEventListener( 'click', () => { + const cssText = textarea.value.trim(); + + if ( !cssText ) { + return; + } + + const name = nameInput.value.trim() || 'Stylesheet ' + stylesheetNextId; + + const entry = { + id: stylesheetNextId++, + name, + cssText, + styleEl: document.createElement( 'style' ) + }; + + entry.styleEl.dataset.ckPreset = entry.id; + entry.styleEl.textContent = cssText; + entry.styleEl.media = 'not all'; + document.head.appendChild( entry.styleEl ); + + stylesheetEntries.push( entry ); + + activateStylesheet( entry.id ); + addBtn.textContent = 'Update Stylesheet'; + + renderStylesheetList( listContainer, refs ); + } ); + + // Wire up "Reset" button — deselect and clear. + resetBtn.addEventListener( 'click', () => { + activateStylesheet( null ); + + textarea.value = ''; + nameInput.value = ''; + addBtn.textContent = 'Add Stylesheet'; + addNewBtn.hidden = true; + + renderStylesheetList( listContainer, refs ); + } ); + + // Load built-in presets (if any). + if ( presets && presets.length ) { + for ( const preset of presets ) { + const entry = { + id: stylesheetNextId++, + name: preset.name, + cssText: preset.css, + styleEl: document.createElement( 'style' ) + }; + + entry.styleEl.dataset.ckPreset = entry.id; + entry.styleEl.textContent = preset.css; + entry.styleEl.media = 'not all'; + document.head.appendChild( entry.styleEl ); + + stylesheetEntries.push( entry ); + } + } + + // Initial render. + renderStylesheetList( listContainer, refs ); + + details.appendChild( manager ); + + return { + element: details, + rerender() { + renderStylesheetList( listContainer, refs ); + }, + loadEntry( entry ) { + refs.textarea.value = entry.cssText; + refs.nameInput.value = entry.name; + refs.addBtn.textContent = 'Update Stylesheet'; + refs.addNewBtn.hidden = false; + } + }; +} + +/** + * Checks if the active stylesheet preset changes the given token's value + * compared to the default (no stylesheet). Returns true if the token + * value with the preset differs from the value without it. + */ +function isTokenChangedByPreset( token ) { + if ( stylesheetActiveId === null ) { + return false; + } + + const active = stylesheetEntries.find( e => e.id === stylesheetActiveId ); + + if ( !active ) { + return false; + } + + return parseTokensFromCss( active.cssText ).has( token ); +} + +function updateSummaryHighlights( panel ) { + for ( const details of panel.querySelectorAll( 'details' ) ) { + const summary = details.querySelector( ':scope > summary' ); + + if ( !summary ) { + continue; + } + + const hasOverrides = details.querySelector( '.token-row.is-overridden' ) !== null; + const hasPresetChanges = details.querySelector( '.token-row.is-preset-changed' ) !== null; + + summary.classList.toggle( 'has-overrides', hasOverrides ); + summary.classList.toggle( 'has-preset-changes', hasPresetChanges ); + } +} + +/** + * @param {Array<{name: string, css: string}>} [presets] Optional array of built-in stylesheet presets. + */ +// --------------------------------------------------------------------------- +// Color palette overview — all color tokens as swatches in a grid. +// --------------------------------------------------------------------------- + +/* eslint-disable max-len */ +const COLOR_PALETTE_TIERS = [ + { + tier: 'Foundation', + groups: { + 'Base': [ + '--ck-color-base-background', '--ck-color-base-foreground', '--ck-color-base-border', + '--ck-color-base-border-light', '--ck-color-base-text', '--ck-color-base-text-light' + ], + 'States': [ + '--ck-color-base-hover', '--ck-color-base-active', '--ck-color-base-active-focus', + '--ck-color-base-selected', '--ck-color-base-selected-hover', + '--ck-color-base-focus', '--ck-color-base-focus-shadow', '--ck-color-base-focus-shadow-faded' + ], + 'Action & Feedback': [ + '--ck-color-base-action', '--ck-color-base-action-hover', + '--ck-color-base-error', '--ck-color-base-warning', '--ck-color-base-success', + '--ck-color-base-highlight', '--ck-color-base-attention' + ] + } + }, + { + tier: 'Semantic', + groups: { + 'Surfaces': [ + '--ck-color-surface-canvas', '--ck-color-surface-control', + '--ck-color-surface-container', '--ck-color-surface-inverse' + ], + 'Borders': [ + '--ck-color-border-control', '--ck-color-border-container', '--ck-color-divider' + ], + 'Text': [ + '--ck-color-text-primary', '--ck-color-text-secondary', + '--ck-color-text-disabled', '--ck-color-text-inverse', '--ck-color-text-error' + ], + 'Feedback': [ + '--ck-color-feedback-error', '--ck-color-feedback-warning', + '--ck-color-feedback-success', '--ck-color-feedback-highlight' + ], + 'Interactive': [ + '--ck-color-interactive-hover-surface', '--ck-color-interactive-active-surface', + '--ck-color-interactive-selected-surface', '--ck-color-interactive-selected-surface-hover', + '--ck-color-interactive-selected-text', + '--ck-color-interactive-primary-surface', '--ck-color-interactive-primary-surface-hover', + '--ck-color-interactive-primary-text' + ] + } + }, + { + tier: 'Component', + groups: { + 'Button': [ + '--ck-button-default-background-color', '--ck-button-default-hover-background-color', + '--ck-button-on-background-color', '--ck-button-on-hover-background-color', + '--ck-button-on-text-color', + '--ck-button-action-background-color', '--ck-button-action-hover-background-color', + '--ck-button-action-text-color', + '--ck-button-save-color', '--ck-button-cancel-color' + ], + 'Input': [ + '--ck-input-background-color', '--ck-input-border-color', + '--ck-input-text-color', '--ck-input-error-border-color', + '--ck-input-disabled-background-color', '--ck-input-disabled-text-color' + ], + 'Containers': [ + '--ck-toolbar-background-color', '--ck-toolbar-border-color', + '--ck-dropdown-panel-background-color', '--ck-dropdown-panel-border-color', + '--ck-balloon-panel-background-color', '--ck-balloon-panel-border-color', + '--ck-dialog-background-color', + '--ck-tooltip-background-color', '--ck-tooltip-text-color' + ] + } + } +]; +/* eslint-enable max-len */ + +function generateColorPaletteSection() { + const details = document.createElement( 'details' ); + details.className = 'color-palette-section'; + + const summary = document.createElement( 'summary' ); + summary.textContent = 'Color Palette Overview'; + details.appendChild( summary ); + + const container = document.createElement( 'div' ); + container.className = 'color-palette-container'; + + const allSwatches = []; + + for ( let i = 0; i < COLOR_PALETTE_TIERS.length; i++ ) { + const { tier, groups } = COLOR_PALETTE_TIERS[ i ]; + + // Tier separator (between tiers, not before the first). + if ( i > 0 ) { + const separator = document.createElement( 'div' ); + separator.className = 'color-palette-separator'; + container.appendChild( separator ); + } + + // Tier heading. + const tierHeading = document.createElement( 'div' ); + tierHeading.className = 'color-palette-tier-heading'; + tierHeading.textContent = tier; + container.appendChild( tierHeading ); + + for ( const [ groupName, tokens ] of Object.entries( groups ) ) { + const group = document.createElement( 'div' ); + group.className = 'color-palette-group'; + + const label = document.createElement( 'div' ); + label.className = 'color-palette-group-label'; + label.textContent = groupName; + group.appendChild( label ); + + const grid = document.createElement( 'div' ); + grid.className = 'color-palette-grid'; + + for ( const token of tokens ) { + const cell = document.createElement( 'div' ); + cell.className = 'color-palette-cell'; + cell.dataset.token = token; + + // Hidden color input for the picker. + const colorInput = document.createElement( 'input' ); + colorInput.type = 'color'; + colorInput.className = 'color-palette-picker'; + + const swatch = document.createElement( 'div' ); + swatch.className = 'color-palette-swatch'; + swatch.title = 'Click to change color'; + + // Click swatch → open color picker. + swatch.addEventListener( 'click', () => { + try { + colorInput.value = colorToHex( + getComputedTokenValue( token ) + ); + } catch { + colorInput.value = '#000000'; + } + + colorInput.click(); + } ); + + // Color picker change → update token. + colorInput.addEventListener( 'input', () => { + document.documentElement.style.setProperty( + token, colorInput.value + ); + + swatch.style.background = colorInput.value; + + // Update the token row too. + const panel = document.getElementById( 'token-panel' ); + const row = panel.querySelector( + `.token-row[data-token="${ token }"]` + ); + + if ( row ) { + row.classList.add( 'is-overridden' ); + row.classList.remove( 'is-preset-changed' ); + refreshRow( row ); + refreshDependents( token ); + updateContrastBadge( row ); + } + } ); + + const name = document.createElement( 'div' ); + name.className = 'color-palette-name'; + name.title = 'Click to scroll to ' + token; + name.textContent = token + .replace( /^--ck-color-/, '' ) + .replace( /^--ck-/, '' ) + .replace( /-/g, '\u2011' ); + + // Click name → scroll to token row. + name.addEventListener( 'click', () => { + scrollToAndHighlightToken( token ); + } ); + + cell.appendChild( colorInput ); + cell.appendChild( swatch ); + cell.appendChild( name ); + grid.appendChild( cell ); + + allSwatches.push( { swatch, token } ); + } + + group.appendChild( grid ); + container.appendChild( group ); + } + } + + details.appendChild( container ); + + // Refresh function to update all swatches. + function refreshSwatches() { + for ( const { swatch, token } of allSwatches ) { + swatch.style.background = getComputedTokenValue( token ); + } + } + + return { element: details, refreshSwatches }; +} + +// --------------------------------------------------------------------------- +// Token dependency tree — interactive cascade visualizer. +// --------------------------------------------------------------------------- + +/** + * Get the full ancestor chain for a token (walking up via TOKEN_REFS). + */ +function getAncestors( token ) { + const chain = []; + let current = TOKEN_REFS[ token ]; + + while ( current ) { + chain.unshift( current ); + current = TOKEN_REFS[ current ]; + } + + return chain; +} + +/** + * Build a nested tree of all dependents (walking down via DEPENDENTS). + */ +function getDependentTree( token ) { + const children = DEPENDENTS[ token ] || []; + + return children.map( child => ( { + token: child, + children: getDependentTree( child ) + } ) ); +} + +/** + * Determine the tier label for a token. + */ +function getTokenTier( token ) { + for ( const [ , tokens ] of Object.entries( FOUNDATION ) ) { + if ( tokens.includes( token ) ) { + return 'foundation'; + } + } + + for ( const [ , tokens ] of Object.entries( SEMANTIC ) ) { + if ( tokens.includes( token ) ) { + return 'semantic'; + } + } + + for ( const [ , tokens ] of Object.entries( COMPONENT ) ) { + if ( tokens.includes( token ) ) { + return 'component'; + } + } + + return ''; +} + +function generateDependencyTreeSection() { + const details = document.createElement( 'details' ); + details.className = 'dep-tree-section'; + + const summary = document.createElement( 'summary' ); + summary.textContent = 'Token Dependencies'; + details.appendChild( summary ); + + const container = document.createElement( 'div' ); + container.className = 'dep-tree-container'; + + // Token selector input. + const input = document.createElement( 'input' ); + input.type = 'text'; + input.className = 'dep-tree-input'; + input.placeholder = 'Type a token name (e.g. radius-base)...'; + container.appendChild( input ); + + // Suggestions dropdown. + const suggestions = document.createElement( 'div' ); + suggestions.className = 'dep-tree-suggestions'; + suggestions.hidden = true; + container.appendChild( suggestions ); + + // Tree output. + const treeOutput = document.createElement( 'div' ); + treeOutput.className = 'dep-tree-output'; + container.appendChild( treeOutput ); + + // All token names for autocomplete. + const allTokens = [ + ...Object.values( FOUNDATION ), + ...Object.values( SEMANTIC ), + ...Object.values( COMPONENT ) + ].flat(); + + input.addEventListener( 'input', () => { + const query = input.value.toLowerCase().trim(); + + if ( !query || query.length < 2 ) { + suggestions.hidden = true; + + return; + } + + const matches = allTokens + .filter( t => t.toLowerCase().includes( query ) ) + .slice( 0, 10 ); + + suggestions.innerHTML = ''; + + if ( matches.length === 0 ) { + suggestions.hidden = true; + + return; + } + + for ( const match of matches ) { + const item = document.createElement( 'div' ); + item.className = 'dep-tree-suggestion'; + item.textContent = match.replace( /^--ck-/, '' ); + item.dataset.token = match; + + item.addEventListener( 'click', () => { + input.value = match.replace( /^--ck-/, '' ); + suggestions.hidden = true; + renderTree( match, treeOutput ); + } ); + + suggestions.appendChild( item ); + } + + suggestions.hidden = false; + } ); + + // Hide suggestions on blur (with delay for click). + input.addEventListener( 'blur', () => { + setTimeout( () => { + suggestions.hidden = true; + }, 200 ); + } ); + + // Enter key selects first match. + input.addEventListener( 'keydown', e => { + if ( e.key === 'Enter' ) { + const first = suggestions.querySelector( '.dep-tree-suggestion' ); + + if ( first ) { + input.value = first.textContent; + suggestions.hidden = true; + renderTree( first.dataset.token, treeOutput ); + } + } + } ); + + function renderTree( token, output ) { + output.innerHTML = ''; + + const ancestors = getAncestors( token ); + const dependents = getDependentTree( token ); + const tier = getTokenTier( token ); + + // Ancestors (walking up). + if ( ancestors.length ) { + const ancestorLabel = document.createElement( 'div' ); + ancestorLabel.className = 'dep-tree-label'; + ancestorLabel.textContent = 'Inherits from:'; + output.appendChild( ancestorLabel ); + + const ancestorList = document.createElement( 'div' ); + ancestorList.className = 'dep-tree-chain'; + + for ( let i = 0; i < ancestors.length; i++ ) { + const node = createTreeNode( ancestors[ i ], i ); + ancestorList.appendChild( node ); + } + + output.appendChild( ancestorList ); + } + + // Selected token. + const selectedNode = document.createElement( 'div' ); + selectedNode.className = 'dep-tree-selected'; + + const selectedName = document.createElement( 'span' ); + selectedName.className = 'dep-tree-node-name'; + selectedName.textContent = token.replace( /^--ck-/, '' ); + + const tierBadge = document.createElement( 'span' ); + tierBadge.className = 'dep-tree-tier dep-tree-tier--' + tier; + tierBadge.textContent = tier; + + const value = document.createElement( 'span' ); + value.className = 'dep-tree-value'; + value.textContent = getComputedTokenValue( token ); + + selectedNode.appendChild( selectedName ); + selectedNode.appendChild( tierBadge ); + selectedNode.appendChild( value ); + output.appendChild( selectedNode ); + + // Dependents (walking down). + if ( dependents.length ) { + const depLabel = document.createElement( 'div' ); + depLabel.className = 'dep-tree-label'; + depLabel.textContent = 'Depended on by:'; + output.appendChild( depLabel ); + + const depList = document.createElement( 'div' ); + depList.className = 'dep-tree-children'; + renderDependentNodes( dependents, depList, 0 ); + output.appendChild( depList ); + } + + if ( !ancestors.length && !dependents.length ) { + const noDepMsg = document.createElement( 'div' ); + noDepMsg.className = 'dep-tree-empty'; + noDepMsg.textContent = 'No dependencies or dependents.'; + output.appendChild( noDepMsg ); + } + } + + function createTreeNode( token, depth ) { + const node = document.createElement( 'div' ); + node.className = 'dep-tree-node'; + node.style.paddingLeft = ( depth * 16 ) + 'px'; + + const arrow = document.createElement( 'span' ); + arrow.className = 'dep-tree-arrow'; + arrow.textContent = depth > 0 ? '\u2514\u2500 ' : ''; + + const name = document.createElement( 'span' ); + name.className = 'dep-tree-node-name dep-tree-node-clickable'; + name.textContent = token.replace( /^--ck-/, '' ); + name.addEventListener( 'click', () => { + scrollToAndHighlightToken( token ); + } ); + + const tier = document.createElement( 'span' ); + tier.className = 'dep-tree-tier dep-tree-tier--' + getTokenTier( token ); + tier.textContent = getTokenTier( token ); + + node.appendChild( arrow ); + node.appendChild( name ); + node.appendChild( tier ); + + return node; + } + + function renderDependentNodes( nodes, container, depth ) { + for ( const item of nodes ) { + const node = createTreeNode( item.token, depth ); + container.appendChild( node ); + + if ( item.children.length ) { + renderDependentNodes( item.children, container, depth + 1 ); + } + } + } + + details.appendChild( container ); + + return details; +} + +export function generatePanel( presets ) { + const panel = document.getElementById( 'token-panel' ); + + // Color palette overview section. + const colorPalette = generateColorPaletteSection(); + panel.appendChild( colorPalette.element ); + + // Token dependency tree section. + const depSection = generateDependencyTreeSection(); + panel.appendChild( depSection ); + + // Collapsed strip — visible only when panel is collapsed. + const strip = document.createElement( 'div' ); + strip.className = 'token-panel-strip'; + strip.textContent = 'Design Tokens'; + panel.appendChild( strip ); + + // Stylesheet preset manager (paste & compare). + const stylesheetManager = generateStylesheetManagerSection( presets ); + panel.appendChild( stylesheetManager.element ); + + const tiers = [ + { key: 'foundation', label: 'Foundation Tokens', data: FOUNDATION, open: true }, + { key: 'semantic', label: 'Semantic Tokens', data: SEMANTIC, open: false }, + { key: 'component', label: 'Component Tokens', data: COMPONENT, open: false } + ]; + + for ( const tier of tiers ) { + const tierDetails = document.createElement( 'details' ); + + if ( tier.open ) { + tierDetails.open = true; + } + + const tierSummary = document.createElement( 'summary' ); + const tokenCount = Object.values( tier.data ).reduce( ( sum, arr ) => sum + arr.length, 0 ); + tierSummary.textContent = tier.label + ' (' + tokenCount + ') '; + + const expandAllBtn = document.createElement( 'button' ); + expandAllBtn.className = 'tier-expand-all'; + expandAllBtn.textContent = 'Expand all'; + expandAllBtn.addEventListener( 'click', e => { + e.preventDefault(); + e.stopPropagation(); + + const allOpen = tierDetails.open && + [ ...tierDetails.querySelectorAll( ':scope > details' ) ] + .every( d => d.open ); + + if ( !allOpen ) { + tierDetails.open = true; + + for ( const d of tierDetails.querySelectorAll( ':scope > details' ) ) { + d.open = true; + } + } else { + for ( const d of tierDetails.querySelectorAll( ':scope > details' ) ) { + d.open = false; + } + } + + expandAllBtn.textContent = allOpen ? 'Expand all' : 'Collapse all'; + } ); + + tierSummary.appendChild( expandAllBtn ); + tierDetails.appendChild( tierSummary ); + + for ( const [ category, tokens ] of Object.entries( tier.data ) ) { + const catDetails = document.createElement( 'details' ); + const catSummary = document.createElement( 'summary' ); + catSummary.textContent = category + ' (' + tokens.length + ')'; + catDetails.appendChild( catSummary ); + + for ( const token of tokens ) { + catDetails.appendChild( createTokenRow( token ) ); + } + + tierDetails.appendChild( catDetails ); + } + + panel.appendChild( tierDetails ); + } + + // Reset all + document.getElementById( 'reset-all' ).addEventListener( 'click', () => { + const allTokens = [ ...Object.values( FOUNDATION ), ...Object.values( SEMANTIC ), ...Object.values( COMPONENT ) ].flat(); + + for ( const token of allTokens ) { + document.documentElement.style.removeProperty( token ); + } + + for ( const row of panel.querySelectorAll( '.token-row' ) ) { + row.classList.remove( 'is-overridden' ); + refreshRow( row ); + } + } ); + + // Search/filter tokens. + const searchInput = document.getElementById( 'token-search' ); + const searchClearBtn = document.getElementById( 'token-search-clear' ); + const overridesOnlyCheckbox = document.getElementById( 'filter-overrides-only' ); + const tokenCountEl = document.getElementById( 'token-count' ); + const totalTokens = panel.querySelectorAll( '.token-row' ).length; + let savedOpenState = null; + + function highlightText( el, query ) { + const text = el.textContent; + const lower = text.toLowerCase(); + const idx = lower.indexOf( query ); + + if ( idx === -1 || !query ) { + return; + } + + const before = text.slice( 0, idx ); + const match = text.slice( idx, idx + query.length ); + const after = text.slice( idx + query.length ); + + el.innerHTML = ''; + el.append( + before, + Object.assign( document.createElement( 'mark' ), { textContent: match } ), + after + ); + } + + function stripMarks( el ) { + const plain = el.textContent; + el.innerHTML = ''; + el.append( plain ); + } + + function highlightMatches( row, query ) { + const nameEl = row.querySelector( '.token-name-text' ); + const descEl = row.querySelector( '.token-description' ); + + if ( nameEl ) { + stripMarks( nameEl ); + + if ( query ) { + highlightText( nameEl, query ); + } + } + + if ( descEl ) { + stripMarks( descEl ); + + if ( query ) { + highlightText( descEl, query ); + } + } + } + + function clearHighlights( row ) { + const nameEl = row.querySelector( '.token-name-text' ); + const descEl = row.querySelector( '.token-description' ); + + if ( nameEl ) { + stripMarks( nameEl ); + } + + if ( descEl ) { + stripMarks( descEl ); + } + } + + function applyFilters() { + const query = searchInput.value.toLowerCase().trim(); + const onlyOverridden = overridesOnlyCheckbox.checked; + const isFiltering = query || onlyOverridden; + + searchClearBtn.hidden = !searchInput.value; + + // Save open state when starting to filter. + if ( isFiltering && !savedOpenState ) { + savedOpenState = new Map(); + + for ( const d of panel.querySelectorAll( 'details' ) ) { + savedOpenState.set( d, d.open ); + } + } + + // Restore open state when no filters are active. + if ( !isFiltering && savedOpenState ) { + for ( const [ d, wasOpen ] of savedOpenState ) { + d.open = wasOpen; + d.hidden = false; + } + + for ( const row of panel.querySelectorAll( '.token-row' ) ) { + row.hidden = false; + clearHighlights( row ); + } + + savedOpenState = null; + tokenCountEl.textContent = ''; + + return; + } + + for ( const row of panel.querySelectorAll( '.token-row' ) ) { + let visible = true; + + if ( query ) { + const token = row.dataset.token.toLowerCase(); + const desc = ( TOKEN_DESCRIPTIONS[ row.dataset.token ] || '' ) + .toLowerCase(); + + visible = token.includes( query ) || desc.includes( query ); + } + + highlightMatches( row, query ); + + if ( visible && onlyOverridden ) { + visible = row.classList.contains( 'is-overridden' ) || + row.classList.contains( 'is-preset-changed' ); + } + + row.hidden = !visible; + } + + // Auto-open categories/tiers that have visible matches; hide empty ones. + for ( const catDetails of panel.querySelectorAll( 'details details' ) ) { + const hasVisible = catDetails + .querySelector( '.token-row:not([hidden])' ) !== null; + + catDetails.hidden = !hasVisible; + + if ( hasVisible ) { + catDetails.open = true; + } + } + + for ( const tierDetails of panel.querySelectorAll( ':scope > details' ) ) { + if ( tierDetails.classList.contains( 'stylesheet-presets' ) ) { + continue; + } + + const hasVisible = tierDetails + .querySelector( '.token-row:not([hidden])' ) !== null; + + tierDetails.hidden = !hasVisible; + + if ( hasVisible ) { + tierDetails.open = true; + } + } + + // Update token count. + const visibleCount = panel.querySelectorAll( '.token-row:not([hidden])' ).length; + tokenCountEl.textContent = visibleCount + ' of ' + totalTokens; + } + + searchClearBtn.addEventListener( 'click', () => { + searchInput.value = ''; + applyFilters(); + searchInput.focus(); + } ); + + searchInput.addEventListener( 'input', applyFilters ); + overridesOnlyCheckbox.addEventListener( 'change', applyFilters ); + + // Collapse/expand panel strip. + const collapseBtn = document.getElementById( 'collapse-panel' ); + + collapseBtn.addEventListener( 'click', () => { + panel.classList.add( 'ck-test-panel--collapsed' ); + } ); + + strip.addEventListener( 'click', () => { + panel.classList.remove( 'ck-test-panel--collapsed' ); + requestAnimationFrame( () => { + panel.scrollIntoView( { behavior: 'smooth', block: 'nearest', inline: 'end' } ); + } ); + } ); + + // Toggle all diagrams. + let diagramsVisible = false; + const toggleDiagramsBtn = document.getElementById( 'toggle-diagrams' ); + + toggleDiagramsBtn.addEventListener( 'click', () => { + diagramsVisible = !diagramsVisible; + + for ( const diagram of panel.querySelectorAll( '.token-diagram' ) ) { + diagram.hidden = !diagramsVisible; + } + + toggleDiagramsBtn.textContent = diagramsVisible ? 'Hide Diagrams' : 'Show Diagrams'; + } ); + + // Copy link — encode overrides into URL hash. + const copyLinkBtn = document.getElementById( 'copy-link' ); + + copyLinkBtn.addEventListener( 'click', () => { + const overrides = {}; + + for ( const row of panel.querySelectorAll( '.token-row.is-overridden' ) ) { + const token = row.dataset.token; + const value = document.documentElement.style + .getPropertyValue( token ).trim(); + + if ( value ) { + overrides[ token ] = value; + } + } + + const state = {}; + + if ( Object.keys( overrides ).length ) { + state.overrides = overrides; + } + + // Include active stylesheet (name + CSS content). + if ( stylesheetActiveId !== null ) { + const active = stylesheetEntries.find( e => e.id === stylesheetActiveId ); + + if ( active ) { + state.preset = active.name; + state.presetCss = active.cssText; + } + } + + const hash = Object.keys( state ).length ? + '#state=' + btoa( JSON.stringify( state ) ) : + ''; + + const url = window.location.origin + + window.location.pathname + hash; + + navigator.clipboard.writeText( url ); + + copyLinkBtn.textContent = 'Copied!'; + setTimeout( () => { + copyLinkBtn.textContent = 'Share Link'; + }, 1200 ); + } ); + + // Restore state from URL hash on load. + try { + const hash = window.location.hash; + let state = null; + + // New format: #state=... + if ( hash.startsWith( '#state=' ) ) { + state = JSON.parse( atob( hash.slice( '#state='.length ) ) ); + // Legacy format: #overrides=... + } else if ( hash.startsWith( '#overrides=' ) ) { + state = { + overrides: JSON.parse( atob( hash.slice( '#overrides='.length ) ) ) + }; + } + + if ( state ) { + // Build a combined "Loaded from link" preset from preset CSS + overrides. + const combinedLines = []; + + if ( state.presetCss ) { + combinedLines.push( state.presetCss.trim() ); + } + + if ( state.overrides && Object.keys( state.overrides ).length ) { + const overrideDecls = Object.entries( state.overrides ) + .map( ( [ t, v ] ) => '\t' + t + ': ' + v + ';' ) + .join( '\n' ); + + combinedLines.push( ':root {\n' + overrideDecls + '\n}' ); + } + + if ( combinedLines.length ) { + const combinedCss = combinedLines.join( '\n\n' ); + const linkEntry = { + id: stylesheetNextId++, + name: 'Loaded from link', + cssText: combinedCss, + styleEl: document.createElement( 'style' ) + }; + + linkEntry.styleEl.dataset.ckPreset = linkEntry.id; + linkEntry.styleEl.textContent = combinedCss; + linkEntry.styleEl.media = 'not all'; + document.head.appendChild( linkEntry.styleEl ); + + stylesheetEntries.push( linkEntry ); + activateStylesheet( linkEntry.id ); + + // Load the CSS into the textarea and open the presets section. + stylesheetManager.loadEntry( linkEntry ); + stylesheetManager.element.open = true; + } + } + + // Re-render the stylesheet list to show restored/created entries. + stylesheetManager.rerender(); + updateSummaryHighlights( panel ); + } catch { + // Ignore malformed hash. + } + + // Warn before leaving the page if there are unsaved overrides. + window.addEventListener( 'beforeunload', event => { + const hasOverrides = panel.querySelector( '.token-row.is-overridden' ) !== null; + + if ( hasOverrides ) { + event.preventDefault(); + } + } ); + + // Initial contrast badge calculation. + for ( const row of panel.querySelectorAll( '.token-row' ) ) { + updateContrastBadge( row ); + } + + // Initial palette swatch render. + colorPalette.refreshSwatches(); + + // Highlight ancestor elements when any child token is overridden. + // Uses a MutationObserver on class changes so every override/reset path is covered automatically. + const observer = new MutationObserver( () => { + updateSummaryHighlights( panel ); + colorPalette.refreshSwatches(); + } ); + + observer.observe( panel, { + subtree: true, + attributes: true, + attributeFilter: [ 'class' ] + } ); + + // Export overrides section — below token tiers. + const exportSection = document.createElement( 'div' ); + exportSection.className = 'token-export'; + + const exportControls = document.createElement( 'div' ); + exportControls.style.cssText = 'display:flex;gap:6px;align-items:center'; + + const exportBtn = document.createElement( 'button' ); + exportBtn.className = 'token-export-btn'; + exportBtn.textContent = 'Generate Stylesheet'; + + const includePresetLabel = document.createElement( 'label' ); + includePresetLabel.style.cssText = 'font-size:11px;color:#666;cursor:pointer;display:flex;' + + 'align-items:center;gap:4px;white-space:nowrap'; + + const includePresetCheckbox = document.createElement( 'input' ); + includePresetCheckbox.type = 'checkbox'; + includePresetCheckbox.checked = true; + + includePresetLabel.appendChild( includePresetCheckbox ); + includePresetLabel.append( 'Include active preset' ); + + exportControls.appendChild( exportBtn ); + exportControls.appendChild( includePresetLabel ); + + const exportOutput = document.createElement( 'textarea' ); + exportOutput.className = 'token-export-output'; + exportOutput.readOnly = true; + exportOutput.hidden = true; + + exportBtn.addEventListener( 'click', () => { + const lines = []; + + // Include active preset CSS if checkbox is checked. + if ( includePresetCheckbox.checked && stylesheetActiveId !== null ) { + const active = stylesheetEntries.find( e => e.id === stylesheetActiveId ); + + if ( active ) { + lines.push( '/* Preset: ' + active.name + ' */\n' + active.cssText.trim() ); + } + } + + // Collect manual overrides. + const overrideLines = []; + + for ( const row of panel.querySelectorAll( '.token-row.is-overridden' ) ) { + const token = row.dataset.token; + const value = document.documentElement.style.getPropertyValue( token ).trim(); + + if ( value ) { + overrideLines.push( '\t' + token + ': ' + value + ';' ); + } + } + + if ( overrideLines.length ) { + lines.push( '/* Manual overrides */\n:root {\n' + overrideLines.join( '\n' ) + '\n}' ); + } + + if ( lines.length === 0 ) { + exportOutput.value = '/* No changes — tweak some tokens or activate a preset first. */'; + } else { + exportOutput.value = lines.join( '\n\n' ); + } + + exportOutput.hidden = false; + exportOutput.select(); + } ); + + exportSection.appendChild( exportControls ); + exportSection.appendChild( exportOutput ); + panel.appendChild( exportSection ); +} diff --git a/packages/ckeditor5-ui/tests/manual/ui-customization/ui-customization.html b/packages/ckeditor5-ui/tests/manual/ui-customization/ui-customization.html new file mode 100644 index 00000000000..7e03f692245 --- /dev/null +++ b/packages/ckeditor5-ui/tests/manual/ui-customization/ui-customization.html @@ -0,0 +1,953 @@ + + + + +
+
+
+

The three greatest things you learn from traveling

+

Like all the great things on earth traveling teaches us by example. Here are some of the most precious lessons I've + learned over the years of traveling.

+ +
+

The real voyage of discovery consists not in seeking new landscapes, but having new eyes.

+

Marcel Proust

+
+

Improvisation

+

Life doesn't allow us to execute every single plan perfectly. This especially seems to be the case when you travel. + You plan it down to every minute with a big checklist. But when it comes to executing it, something always comes up + and you're left with your improvising skills. You learn to adapt as you go. Here's how my travel checklist looks + now:

+
    +
  • buy the ticket
  • +
  • start your adventure
  • +
+
Three monks ascending the stairs of an ancient temple. +
Three monks ascending the stairs of an ancient temple.
+
+

Confidence

+

Going to a new place can be quite terrifying. While change and uncertainty make us scared, traveling teaches us how + ridiculous it is to be afraid of something before it happens. The moment you face your fear and see there is nothing + to be afraid of, is the moment you discover bliss.

+
+
+
+

+ Design Tokens + + + + + + +

+
+ + +
+
+ + +
+ +
+
diff --git a/packages/ckeditor5-ui/tests/manual/ui-customization/ui-customization.js b/packages/ckeditor5-ui/tests/manual/ui-customization/ui-customization.js new file mode 100644 index 00000000000..8f04dce1485 --- /dev/null +++ b/packages/ckeditor5-ui/tests/manual/ui-customization/ui-customization.js @@ -0,0 +1,52 @@ +/** + * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic'; +import { SourceEditing } from '@ckeditor/ckeditor5-source-editing'; +import { ArticlePluginSet } from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset.js'; +import { ImageResize } from '@ckeditor/ckeditor5-image'; +import { generatePanel } from './token-panel.js'; + +// --------------------------------------------------------------------------- +// Editor initialization +// --------------------------------------------------------------------------- + +ClassicEditor + .create( document.querySelector( '#editor-to-customize' ), { + plugins: [ ArticlePluginSet, ImageResize, SourceEditing ], + toolbar: [ + 'sourceEditing', '|', + 'heading', '|', + 'bold', 'italic', 'link', + 'bulletedList', 'numberedList', '|', + 'outdent', 'indent', '|', + 'blockQuote', 'insertTable', 'mediaEmbed', + 'undo', 'redo' + ], + image: { + toolbar: [ 'imageStyle:inline', 'imageStyle:block', 'imageStyle:wrapText', '|', 'imageTextAlternative' ] + }, + table: { + contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells' ] + } + } ) + .then( editor => { + window.editor = editor; + generatePanel(); + + // Toggle token panel button. + const toggleBtn = document.getElementById( 'toggle-panel' ); + const layout = document.querySelector( '.ck-test-layout' ); + + toggleBtn.addEventListener( 'click', () => { + layout.classList.toggle( 'ck-test-layout--panel-hidden' ); + toggleBtn.textContent = layout.classList.contains( 'ck-test-layout--panel-hidden' ) ? + 'Show tokens panel' : + 'Hide tokens panel'; + } ); + } ) + .catch( err => { + console.error( err.stack ); + } ); diff --git a/packages/ckeditor5-ui/tests/manual/ui-customization/ui-customization.md b/packages/ckeditor5-ui/tests/manual/ui-customization/ui-customization.md new file mode 100644 index 00000000000..4b3497513a6 --- /dev/null +++ b/packages/ckeditor5-ui/tests/manual/ui-customization/ui-customization.md @@ -0,0 +1,96 @@ +# UI customization — Design Token Explorer + +Interactive test for exploring and customizing the three-tier CSS design token system. + +## Layout + +- **Left**: Classic editor instance with sample content +- **Right**: Scrollable token customization panel with collapsible sections + +## How to use + +### Token panel + +1. Use the search input at the top to filter tokens by name or description. Matching sections auto-expand; clearing restores the previous state. +2. Check "Show only overridden" to hide all tokens that haven't been changed (works with search). +3. Expand a tier (Foundation / Semantic / Component) to see categories. Use "Expand all" / "Collapse all" per tier. +4. Each token shows a short description of what it controls. +5. Click a token name to copy its full `--ck-*` name to clipboard (turns green with a ✓ on success). +6. Tokens with a 🖼 icon have a visual diagram — click to toggle. Click "Show Diagrams" in the header to toggle all at once. +7. Use the input controls to override token values live: + - **Color tokens**: color picker + text input (supports hsl, hex, rgb) + - **Spacing/size**: text input (px, em, calc values) + - **Font weight**: dropdown (100-900) + - **Duration**: range slider + text input + - **Easing**: dropdown with presets + - **Opacity**: range slider (0-1) +8. Overridden tokens are highlighted in blue. Tokens changed by an active stylesheet preset are highlighted in amber. +9. Section headers inherit the highlight color so you can see overrides even when collapsed. +10. Dependent tokens update automatically — e.g., changing `--ck-spacing-unit` refreshes all spacing tokens that reference it. Manually overridden dependents are not affected. +11. Click the "↺" button on any row to reset that token to its default. +12. Click "Reset All" to clear all overrides. + +### Token dependencies (cascade tree) + +1. Open the "Token Dependencies" section (green accent). +2. Type a token name in the search input — suggestions appear as you type. +3. Press Enter or click a suggestion to view the dependency tree. +4. The tree shows: ancestor chain (what the token inherits from), the selected token with its tier and computed value, and all dependents (what inherits from it). +5. Click any token in the tree to scroll to its row in the panel. + +### Color palette overview + +1. Open the "Color Palette Overview" section (orange accent). +2. All color tokens are displayed as swatches, grouped by tier (Foundation, Semantic, Component) with visual separators. +3. Swatches update live when tokens change or presets switch. +4. Click a swatch to open the color picker and change the value directly. +5. Click the token name below a swatch to scroll to its row in the panel. + +### Stylesheet presets (paste & compare) + +1. Open the "Stylesheet Presets" section at the top of the panel (blue accent). +2. Paste a CSS block (e.g. `:root { --ck-radius-base: 10px; }`) into the textarea. +3. Optionally enter a name, then click "Add Stylesheet". +4. The stylesheet is immediately activated — the editor updates and token inputs refresh. +5. Add more stylesheets to compare. Use the radio buttons to switch between them. +6. Select "None (default)" to go back to the framework defaults. +7. Clicking a stylesheet entry loads its CSS into the textarea for editing. Click "Update Stylesheet" to apply changes. +8. Click "Add New" to fork the current textarea content into a new preset without modifying the selected one. +9. Use the "Reset" button to deselect the active stylesheet and clear the textarea. +10. Check "Clear manual overrides on switch" to reset all per-token tweaks when switching between stylesheets. This gives a clean comparison between presets. + +### Export overrides + +1. Tweak tokens using the panel inputs. +2. Click "Generate Stylesheet from Overrides" at the bottom of the panel. +3. A `:root { ... }` block with all manually changed tokens appears in a read-only textarea, ready to copy. + +### WCAG contrast checking + +Foreground color tokens (e.g. `--ck-color-text-primary`, `--ck-button-action-text-color`) show a live contrast ratio badge next to their input. The badge compares against the paired background token and displays: +- **Green** `AAA` (≥ 7:1) or `AA` (≥ 4.5:1) — passes WCAG +- **Red** `Fail` (< 4.5:1) — fails WCAG AA for normal text + +Badges show two color swatches (foreground + background) and update dynamically when either token changes. Click a badge to scroll to the paired background token. Hover for details. + +### Share via link + +1. Override some tokens and/or activate a preset, then click "Share Link" in the header. +2. The URL with encoded state (preset CSS + manual overrides) is copied to clipboard. +3. Open the link in another browser/tab — a "Loaded from link" preset is created in the Stylesheet Presets section, activated automatically, and the section opens to show it. + +## What to verify + +- Changing a foundation token cascades to semantic and component tokens that reference it. +- Changing a semantic token overrides the foundation reference for that role only. +- Component tokens can be overridden independently. +- Reset restores the original value and re-enables the var() cascade. +- Tokens with references show "← referenced-token" below their name. +- Pasted stylesheets apply at normal CSS specificity — per-token inline overrides always win (unless "Clear manual overrides on switch" is checked). +- Switching between stylesheet presets refreshes all non-overridden token inputs. +- Updating an active stylesheet re-applies the CSS and refreshes token inputs. +- The export button captures only manually overridden tokens, not stylesheet preset values. +- Manual overrides (blue) visually override preset changes (amber) on the same token. +- Section headers turn blue for manual overrides and amber for preset changes. +- "Show Diagrams" toggles all diagrams at once; individual 🖼 icons toggle one at a time. +- Contrast badges on foreground color tokens update when either the foreground or background token changes. diff --git a/packages/ckeditor5-ui/theme/components/autocomplete/autocomplete.css b/packages/ckeditor5-ui/theme/components/autocomplete/autocomplete.css index 87f9909ea7e..0d8c2d30757 100644 --- a/packages/ckeditor5-ui/theme/components/autocomplete/autocomplete.css +++ b/packages/ckeditor5-ui/theme/components/autocomplete/autocomplete.css @@ -3,36 +3,51 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + /* Size */ + --ck-autocomplete-results-max-height: 200px; + + /* Radius */ + /* Set to a radius value (e.g. var(--ck-radius-base)) to disable attached-corner behavior and use uniform corners. */ + --ck-autocomplete-results-uniform-border-radius: var(--ck-border-radius-uniform); + --ck-autocomplete-results-border-radius: var(--ck-border-radius-surface-attached); + + /* Border */ + --ck-autocomplete-results-border: var(--ck-border-width-surface) solid var(--ck-dropdown-panel-border-color); + + /* Color */ + --ck-autocomplete-results-background-color: var(--ck-color-surface-container); +} + .ck.ck-autocomplete { & > .ck-search__results { - border-radius: var(--ck-rounded-corners-radius); - box-shadow: var(--ck-drop-shadow), 0 0; - max-height: 200px; + border-radius: var(--ck-autocomplete-results-border-radius); + box-shadow: var(--ck-shadow-surface-floating), 0 0; + max-height: var(--ck-autocomplete-results-max-height); overflow-y: auto; - background: var(--ck-color-base-background); - border: 1px solid var(--ck-color-dropdown-panel-border); + background: var(--ck-autocomplete-results-background-color); + border: var(--ck-autocomplete-results-border); min-width: auto; position: absolute; &.ck-search__results_n { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; + border-radius: var(--ck-autocomplete-results-uniform-border-radius, var(--ck-border-radius-surface-attached-bottom)); /* Prevent duplicated borders between the input and the results pane. */ - margin-bottom: -1px; + margin-bottom: calc(-1 * var(--ck-border-width-surface)); bottom: 100%; } &.ck-search__results_s { - border-top-left-radius: 0; - border-top-right-radius: 0; + border-radius: var(--ck-autocomplete-results-uniform-border-radius, var(--ck-border-radius-surface-attached-top)); /* Prevent duplicated borders between the input and the results pane. */ - margin-top: -1px; + margin-top: calc(-1 * var(--ck-border-width-surface)); top: 100%; bottom: auto; } - z-index: var(--ck-z-panel) + /* Backward compatibility: falls back to legacy --ck-z-panel if overridden. */ + z-index: var(--ck-z-panel, var(--ck-z-overlay)) } position: relative } diff --git a/packages/ckeditor5-ui/theme/components/button/button.css b/packages/ckeditor5-ui/theme/components/button/button.css index 401ab7e7da5..e4273d05c96 100644 --- a/packages/ckeditor5-ui/theme/components/button/button.css +++ b/packages/ckeditor5-ui/theme/components/button/button.css @@ -3,13 +3,49 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + /* Spacing */ + --ck-button-padding: var(--ck-spacing-control-padding-block); + + /* Radius */ + --ck-button-border-radius: var(--ck-border-radius-control); + + /* Border */ + --ck-button-border: var(--ck-border-width-control) solid transparent; + + /* Color */ + --ck-button-default-background-color: transparent; + --ck-button-default-hover-background-color: var(--ck-color-interactive-hover-surface); + --ck-button-default-active-background-color: var(--ck-color-interactive-active-surface); + --ck-button-default-disabled-background-color: transparent; + --ck-button-on-background-color: var(--ck-color-interactive-selected-surface); + --ck-button-on-hover-background-color: var(--ck-color-interactive-selected-surface-hover); + --ck-button-on-active-background-color: var(--ck-color-interactive-selected-surface-hover); + /* Intentionally hardcoded: no matching semantic disabled surface exists yet. */ + --ck-button-on-disabled-background-color: hsl(211, 15%, 95%); + --ck-button-on-text-color: var(--ck-color-interactive-selected-text); + --ck-button-action-background-color: var(--ck-color-interactive-primary-surface); + --ck-button-action-hover-background-color: var(--ck-color-interactive-primary-surface-hover); + --ck-button-action-active-background-color: var(--ck-color-interactive-primary-surface-hover); + /* Intentionally hardcoded: a faded variant of the action color with no semantic equivalent yet. */ + --ck-button-action-disabled-background-color: hsl(104, 44%, 58%); + --ck-button-action-text-color: var(--ck-color-interactive-primary-text); + --ck-button-save-color: var(--ck-color-feedback-success); + --ck-button-cancel-color: var(--ck-color-feedback-warning); + + /* State / meta */ + --ck-button-focus-border-color: var(--ck-interactive-focus-border-color); + /* Backward compatibility: falls back to legacy --ck-disabled-opacity if overridden. */ + --ck-button-opacity-disabled: var(--ck-disabled-opacity, var(--ck-opacity-disabled)) +} + /* Use :where(a) (not plain a) to keep the anchor variant at zero specificity. */ .ck.ck-button, :where(a).ck.ck-button { - --ck-button-background: var(--ck-color-button-default-background); - --ck-button-hover-background: var(--ck-color-button-default-hover-background); - --ck-button-active-background: var(--ck-color-button-default-active-background); - --ck-button-disabled-background: var(--ck-color-button-default-disabled-background); + --ck-button-background: var(--ck-button-default-background-color); + --ck-button-hover-background: var(--ck-button-default-hover-background-color); + --ck-button-active-background: var(--ck-button-default-active-background-color); + --ck-button-disabled-background: var(--ck-button-default-disabled-background-color); background: var(--ck-button-background); @@ -23,16 +59,16 @@ } } - border-radius: var(--ck-rounded-corners-radius); + border-radius: var(--ck-button-border-radius); white-space: nowrap; cursor: default; vertical-align: middle; - padding: var(--ck-spacing-tiny); + padding: var(--ck-button-padding); text-align: center; /* A very important piece of styling. Go to variable declaration to learn more. */ - min-width: var(--ck-ui-component-min-height); - min-height: var(--ck-ui-component-min-height); + min-width: var(--ck-size-control-min-height); + min-height: var(--ck-size-control-min-height); /* Normalize the height of the line. Removing this will break consistent height among text and text-less buttons (with icons). */ @@ -42,10 +78,10 @@ font-size: inherit; /* Avoid flickering when the foucs border shows up. */ - border: 1px solid transparent; + border: var(--ck-button-border); /* Apply some smooth transition to the box-shadow and border. */ - transition: box-shadow .2s ease-in-out, border .2s ease-in-out; + transition: var(--ck-transition-control); /* https://github.com/ckeditor/ckeditor5/issues/3414 */ -webkit-appearance: none; @@ -57,15 +93,15 @@ align-items: center; @media (prefers-reduced-motion: reduce) { - transition: none; + transition: var(--ck-transition-none); } /* stylelint-disable no-descending-specificity */ &:active, &:focus { outline: none; - border: var(--ck-focus-ring); - box-shadow: var(--ck-focus-outer-shadow), 0 0; + border-color: var(--ck-button-focus-border-color); + box-shadow: var(--ck-interactive-focus-shadow), 0 0; } /* Allow icon coloring using the text "color" property. */ @@ -79,7 +115,7 @@ & .ck-button__label { /* Enable font size inheritance, which allows fluid UI scaling. */ font-size: inherit; - font-weight: inherit; + font-weight: var(--ck-font-weight-ui-inherit); color: inherit; cursor: inherit; @@ -103,11 +139,11 @@ opacity: .5; [dir="ltr"] & { - margin-left: var(--ck-spacing-large); + margin-left: var(--ck-spacing-control-meta-gap); } [dir="rtl"] & { - margin-right: var(--ck-spacing-large); + margin-right: var(--ck-spacing-control-meta-gap); } } @@ -118,16 +154,16 @@ &:active, &:focus { /* The disabled button should have a slightly less visible shadow when focused. */ - box-shadow: var(--ck-focus-disabled-outer-shadow), 0 0; + box-shadow: var(--ck-interactive-focus-disabled-shadow), 0 0; } & .ck-button__icon { - opacity: var(--ck-disabled-opacity); + opacity: var(--ck-button-opacity-disabled); } /* https://github.com/ckeditor/ckeditor5/issues/3376 */ & .ck-button__label { - opacity: var(--ck-disabled-opacity); + opacity: var(--ck-button-opacity-disabled); } & .ck-button__keystroke { @@ -136,15 +172,15 @@ } &.ck-button_with-text { - padding: var(--ck-spacing-tiny) var(--ck-spacing-standard); + padding: var(--ck-spacing-control-padding-block) var(--ck-spacing-control-padding-inline); & .ck-button__icon { [dir="ltr"] & { - margin-right: var(--ck-spacing-medium); + margin-right: var(--ck-spacing-control-icon-gap); } [dir="rtl"] & { - margin-left: var(--ck-spacing-medium); + margin-left: var(--ck-spacing-control-icon-gap); } } & .ck-button__label { @@ -161,20 +197,20 @@ /* A style of the button which is currently on, e.g. its feature is active. */ &.ck-on { - --ck-button-background: var(--ck-color-button-on-background); - --ck-button-hover-background: var(--ck-color-button-on-hover-background); - --ck-button-active-background: var(--ck-color-button-on-active-background); - --ck-button-disabled-background: var(--ck-color-button-on-disabled-background); + --ck-button-background: var(--ck-button-on-background-color); + --ck-button-hover-background: var(--ck-button-on-hover-background-color); + --ck-button-active-background: var(--ck-button-on-active-background-color); + --ck-button-disabled-background: var(--ck-button-on-disabled-background-color); - color: var(--ck-color-button-on-color); + color: var(--ck-button-on-text-color); } &.ck-button-save { - color: var(--ck-color-button-save); + color: var(--ck-button-save-color); } &.ck-button-cancel { - color: var(--ck-color-button-cancel); + color: var(--ck-button-cancel-color); } /* stylelint-disable no-descending-specificity */ @@ -197,15 +233,15 @@ .ck.ck-button-action, a.ck.ck-button-action { - --ck-button-background: var(--ck-color-button-action-background); - --ck-button-hover-background: var(--ck-color-button-action-hover-background); - --ck-button-active-background: var(--ck-color-button-action-active-background); - --ck-button-disabled-background: var(--ck-color-button-action-disabled-background); + --ck-button-background: var(--ck-button-action-background-color); + --ck-button-hover-background: var(--ck-button-action-hover-background-color); + --ck-button-active-background: var(--ck-button-action-active-background-color); + --ck-button-disabled-background: var(--ck-button-action-disabled-background-color); - color: var(--ck-color-button-action-text); + color: var(--ck-button-action-text-color); } .ck.ck-button-bold, a.ck.ck-button-bold { - font-weight: bold; + font-weight: var(--ck-font-weight-ui-emphasis); } diff --git a/packages/ckeditor5-ui/theme/components/button/listitembutton.css b/packages/ckeditor5-ui/theme/components/button/listitembutton.css index b91d13264c4..0adcf98800a 100644 --- a/packages/ckeditor5-ui/theme/components/button/listitembutton.css +++ b/packages/ckeditor5-ui/theme/components/button/listitembutton.css @@ -4,22 +4,30 @@ */ +:root { + /* Spacing */ + --ck-list-item-button-padding: var(--ck-spacing-control-padding-block) calc(2 * var(--ck-spacing-control-padding-inline)); + + /* Radius */ + --ck-list-item-button-border-radius: 0; +} + .ck.ck-button.ck-list-item-button { - padding: var(--ck-spacing-tiny) calc(2 * var(--ck-spacing-standard)); + padding: var(--ck-list-item-button-padding); &, &.ck-on { - background: var(--ck-color-list-background); + background: var(--ck-list-background-color); color: var(--ck-color-text); } &:has(.ck-list-item-button__check-holder) { [dir="ltr"] & { - padding-left: var(--ck-spacing-small); + padding-left: var(--ck-spacing-control-padding-inline-compact); } [dir="rtl"] & { - padding-right: var(--ck-spacing-small); + padding-right: var(--ck-spacing-control-padding-inline-compact); } } @@ -32,7 +40,7 @@ &.ck-button.ck-on:hover, &.ck-on:not(.ck-list-item-button_toggleable), &.ck-on:hover { - background: var(--ck-color-list-button-hover-background); + background: var(--ck-list-button-hover-background-color); &:not(.ck-disabled) { color: var(--ck-color-text); @@ -43,7 +51,7 @@ .ck.ck-list-item-button { min-height: unset; width: 100%; - border-radius: 0; + border-radius: var(--ck-list-item-button-border-radius); [dir="ltr"] & { text-align: left; @@ -55,11 +63,11 @@ &.ck-list-item-button_toggleable { [dir="ltr"] & { - padding-left: var(--ck-spacing-small); + padding-left: var(--ck-spacing-control-padding-inline-compact); } [dir="rtl"] & { - padding-right: var(--ck-spacing-small); + padding-right: var(--ck-spacing-control-padding-inline-compact); } } @@ -69,11 +77,11 @@ height: .9em; [dir="ltr"] & { - margin-right: var(--ck-spacing-small); + margin-right: var(--ck-spacing-control-padding-inline-compact); } [dir="rtl"] & { - margin-left: var(--ck-spacing-small); + margin-left: var(--ck-spacing-control-padding-inline-compact); } } diff --git a/packages/ckeditor5-ui/theme/components/button/switchbutton.css b/packages/ckeditor5-ui/theme/components/button/switchbutton.css index aa4c62567b5..7c2703015f2 100644 --- a/packages/ckeditor5-ui/theme/components/button/switchbutton.css +++ b/packages/ckeditor5-ui/theme/components/button/switchbutton.css @@ -4,16 +4,16 @@ */ :root { - /* 34px at 13px font-size */ - --ck-switch-button-toggle-width: 2.6153846154em; - /* 14px at 13px font-size */ - --ck-switch-button-toggle-inner-size: calc(1.0769230769em + 1px); - --ck-switch-button-translation: calc( - var(--ck-switch-button-toggle-width) - - var(--ck-switch-button-toggle-inner-size) - - 2px /* Border */ - ); - --ck-switch-button-inner-hover-shadow: 0 0 0 5px var(--ck-color-switch-button-inner-shadow); + /* Radius */ + --ck-switch-button-toggle-border-radius: var(--ck-border-radius-control); + --ck-switch-button-toggle-inner-border-radius: calc(.5 * var(--ck-switch-button-toggle-border-radius)); + + /* Color */ + --ck-switch-button-off-background-color: hsl(0, 0%, 57.6%); + --ck-switch-button-off-hover-background-color: hsl(0, 0%, 49%); + --ck-switch-button-on-background-color: var(--ck-button-action-background-color); + --ck-switch-button-on-hover-background-color: var(--ck-color-interactive-primary-surface-hover); + --ck-switch-button-inner-background-color: var(--ck-color-surface-canvas); } .ck.ck-button.ck-switchbutton { @@ -29,24 +29,29 @@ & .ck-button__label { [dir="ltr"] & { /* Separate the label from the switch */ - margin-right: calc(2 * var(--ck-spacing-large)); + margin-right: calc(2 * var(--ck-spacing-control-meta-gap)); } [dir="rtl"] & { /* Separate the label from the switch */ - margin-left: calc(2 * var(--ck-spacing-large)); + margin-left: calc(2 * var(--ck-spacing-control-meta-gap)); } } & .ck-button__toggle { - border-radius: var(--ck-rounded-corners-radius); + border-radius: var(--ck-switch-button-toggle-border-radius); /* Apply some smooth transition to the box-shadow and border. */ /* Gently animate the background color of the toggle switch */ - transition: background 400ms ease, box-shadow .2s ease-in-out, outline .2s ease-in-out; - border: 1px solid transparent; - width: var(--ck-switch-button-toggle-width); - background: var(--ck-color-switch-button-off-background); + transition: + background var(--ck-duration-slower) var(--ck-transition-timing-function-surface), + box-shadow var(--ck-transition-duration-control) var(--ck-transition-timing-function-control), + outline var(--ck-transition-duration-control) var(--ck-transition-timing-function-control); + border: var(--ck-border-width-control) solid transparent; + /* Backward compatibility: falls back to legacy --ck-switch-button-toggle-width if overridden. */ + /* 34px at 13px font-size */ + width: var(--ck-switch-button-toggle-width, 2.6153846154em); + background: var(--ck-switch-button-off-background-color); [dir="ltr"] & { /* Make sure the toggle is always to the right as far as possible. */ @@ -59,32 +64,36 @@ } & .ck-button__toggle__inner { - border-radius: calc(.5 * var(--ck-rounded-corners-radius)); - width: var(--ck-switch-button-toggle-inner-size); - height: var(--ck-switch-button-toggle-inner-size); - background: var(--ck-color-switch-button-inner-background); + border-radius: var(--ck-switch-button-toggle-inner-border-radius); + /* Backward compatibility: falls back to legacy --ck-switch-button-toggle-inner-size if overridden. */ + /* 14px at 13px font-size + 1px */ + width: var(--ck-switch-button-toggle-inner-size, calc(1.0769230769em + 1px)); + height: var(--ck-switch-button-toggle-inner-size, calc(1.0769230769em + 1px)); + background: var(--ck-switch-button-inner-background-color); /* Gently animate the inner part of the toggle switch */ - transition: all 300ms ease; + transition: all var(--ck-transition-duration-control-emphasized) var(--ck-transition-timing-function-surface); @media (prefers-reduced-motion: reduce) { - transition: none; + transition: var(--ck-transition-none); } display: block } &:hover { - background: var(--ck-color-switch-button-off-hover-background); + background: var(--ck-switch-button-off-hover-background-color); & .ck-button__toggle__inner { - box-shadow: var(--ck-switch-button-inner-hover-shadow); + /* Backward compatibility: falls back to legacy --ck-switch-button-inner-hover-shadow if overridden. */ + box-shadow: var(--ck-switch-button-inner-hover-shadow, 0 0 0 5px hsla(0, 0%, 0%, 0.1)); } } display: block } &.ck-disabled .ck-button__toggle { - opacity: var(--ck-disabled-opacity); + /* Backward compatibility: falls back to legacy --ck-disabled-opacity if overridden. */ + opacity: var(--ck-disabled-opacity, var(--ck-opacity-disabled)); } /* Overriding default .ck-button:focus styles + an outline around the toogle */ @@ -94,31 +103,33 @@ box-shadow: none; & .ck-button__toggle { - box-shadow: 0 0 0 1px var(--ck-color-base-background), 0 0 0 5px var(--ck-color-focus-outer-shadow); + box-shadow: 0 0 0 1px var(--ck-color-surface-canvas), 0 0 0 5px var(--ck-color-interactive-focus-shadow); outline-offset: 1px; - outline: var(--ck-focus-ring); + outline: var(--ck-interactive-focus-ring); } } /* stylelint-disable-next-line no-descending-specificity */ &.ck-on { & .ck-button__toggle { - background: var(--ck-color-switch-button-on-background); + background: var(--ck-switch-button-on-background-color); &:hover { - background: var(--ck-color-switch-button-on-hover-background); + background: var(--ck-switch-button-on-hover-background-color); } & .ck-button__toggle__inner { /* * Move the toggle switch to the right. It will be animated. + * Translation = toggle-width - inner-size - 2 * border-width + * = 2.6153846154em - (1.0769230769em + 1px) - 2 * border-width-control */ [dir="ltr"] & { - transform: translateX( var( --ck-switch-button-translation ) ); + transform: translateX(calc(2.6153846154em - (1.0769230769em + 1px) - 2 * var(--ck-border-width-control))); } [dir="rtl"] & { - transform: translateX( calc( -1 * var( --ck-switch-button-translation ) ) ); + transform: translateX(calc(-1 * (2.6153846154em - (1.0769230769em + 1px) - 2 * var(--ck-border-width-control)))); } } } diff --git a/packages/ckeditor5-ui/theme/components/collapsible/collapsible.css b/packages/ckeditor5-ui/theme/components/collapsible/collapsible.css index aab8abf2e95..78c5e5aabd8 100644 --- a/packages/ckeditor5-ui/theme/components/collapsible/collapsible.css +++ b/packages/ckeditor5-ui/theme/components/collapsible/collapsible.css @@ -4,13 +4,17 @@ */ :root { - --ck-collapsible-arrow-size: calc(0.5 * var(--ck-icon-size)); + /* Spacing */ + --ck-collapsible-children-padding: var(--ck-spacing-surface-section-gap-block) var(--ck-spacing-control-meta-gap) var(--ck-spacing-region-edge-margin-block); + + /* Typography */ + --ck-collapsible-button-font-weight: var(--ck-font-weight-ui-strong); } .ck.ck-collapsible { & > .ck.ck-button { width: 100%; - font-weight: bold; + font-weight: var(--ck-collapsible-button-font-weight); border-radius: 0; color: inherit; @@ -25,13 +29,14 @@ } & > .ck-icon { - margin-right: var(--ck-spacing-medium); - width: var(--ck-collapsible-arrow-size); + margin-right: var(--ck-spacing-control-icon-gap); + /* Backward compatibility: falls back to legacy --ck-collapsible-arrow-size if overridden. */ + width: var(--ck-collapsible-arrow-size, calc(0.5 * var(--ck-icon-size))); } } & > .ck-collapsible__children { - padding: var(--ck-spacing-medium) var(--ck-spacing-large) var(--ck-spacing-large); + padding: var(--ck-collapsible-children-padding); } &.ck-collapsible_collapsed { diff --git a/packages/ckeditor5-ui/theme/components/colorgrid/colorgrid.css b/packages/ckeditor5-ui/theme/components/colorgrid/colorgrid.css index 5931b50ba84..a09f73795c5 100644 --- a/packages/ckeditor5-ui/theme/components/colorgrid/colorgrid.css +++ b/packages/ckeditor5-ui/theme/components/colorgrid/colorgrid.css @@ -5,22 +5,34 @@ :root { + /* Size */ --ck-color-grid-tile-size: 24px; - /* Not using global colors here because these may change but some colors in a pallette - * require special treatment. For instance, this ensures no matter what the UI text color is, - * the check icon will look good on the black color tile. */ - --ck-color-color-grid-check-icon: hsl(212, 81%, 46%); + /* Spacing */ + --ck-color-grid-gap: 5px; + --ck-color-grid-margin: 0; + --ck-color-grid-padding: 8px; + + /* Radius */ + --ck-color-grid-tile-border-radius: 0; + + /* Motion */ + --ck-color-grid-tile-hover-transform: none; + + /* State / meta */ + --ck-color-grid-tile-hover-layer: auto; } .ck.ck-color-grid { - grid-gap: 5px; - padding: 8px; + grid-gap: var(--ck-color-grid-gap); + margin: var(--ck-color-grid-margin); + padding: var(--ck-color-grid-padding); display: grid; } .ck.ck-color-grid__tile { - transition: .2s ease box-shadow; + border-radius: var(--ck-color-grid-tile-border-radius); + transition: box-shadow var(--ck-transition-duration-control) var(--ck-transition-timing-function-surface); @media (forced-colors: none) { width: var(--ck-color-grid-tile-size); @@ -38,16 +50,23 @@ } &.ck-color-selector__color-tile_bordered { - box-shadow: 0 0 0 1px var(--ck-color-base-border); + box-shadow: 0 0 0 1px var(--ck-color-border-control); } &.ck-on { - box-shadow: inset 0 0 0 1px var(--ck-color-base-background), 0 0 0 2px var(--ck-color-base-text); + box-shadow: inset 0 0 0 1px var(--ck-color-surface-canvas), 0 0 0 2px var(--ck-color-text-primary); } - &:focus:not( .ck-disabled ), &:hover:not( .ck-disabled ) { - box-shadow: inset 0 0 0 1px var(--ck-color-base-background), 0 0 0 2px var(--ck-color-focus-border); + z-index: var(--ck-color-grid-tile-hover-layer); + box-shadow: inset 0 0 0 1px var(--ck-color-surface-canvas), 0 0 0 2px var(--ck-color-interactive-focus-border); + transform: var(--ck-color-grid-tile-hover-transform); + } + + &:focus:not( .ck-disabled ) { + z-index: var(--ck-color-grid-tile-hover-layer); + box-shadow: inset 0 0 0 1px var(--ck-color-surface-canvas), 0 0 0 2px var(--ck-color-interactive-focus-border); + transform: var(--ck-color-grid-tile-hover-transform); } } @@ -60,7 +79,7 @@ height: unset; min-width: unset; min-height: unset; - padding: 0 var(--ck-spacing-small); + padding: 0 var(--ck-spacing-surface-padding-inline); & .ck-button__label { display: inline-block; @@ -68,7 +87,7 @@ } @media (prefers-reduced-motion: reduce) { - transition: none; + transition: var(--ck-transition-none); } &.ck-disabled { @@ -78,7 +97,8 @@ & .ck.ck-icon { display: none; - color: var(--ck-color-color-grid-check-icon); + /* Fallback to `--ck-color-color-grid-check-icon` for backward compatibility. */ + color: var(--ck-color-color-grid-check-icon, hsl(212, 81%, 46%)); } &.ck-on { @@ -89,5 +109,5 @@ } .ck.ck-color-grid__label { - padding: 0 var(--ck-spacing-standard); + padding: 0 var(--ck-spacing-control-padding-inline); } diff --git a/packages/ckeditor5-ui/theme/components/colorpicker/colorpicker.css b/packages/ckeditor5-ui/theme/components/colorpicker/colorpicker.css index a79eee525f9..0ccb386d1b8 100644 --- a/packages/ckeditor5-ui/theme/components/colorpicker/colorpicker.css +++ b/packages/ckeditor5-ui/theme/components/colorpicker/colorpicker.css @@ -16,7 +16,7 @@ flex-direction: row; flex-wrap: nowrap; justify-content: space-between; - margin: var(--ck-spacing-large) 0 0; + margin: var(--ck-spacing-region-edge-margin-block) 0 0; width: unset; & .ck.ck-labeled-field-view { @@ -28,7 +28,7 @@ } & .ck-color-picker__hash-view { - padding-top: var(--ck-spacing-tiny); - padding-right: var(--ck-spacing-medium); + padding-top: var(--ck-spacing-control-padding-block); + padding-right: var(--ck-spacing-control-icon-gap); } } diff --git a/packages/ckeditor5-ui/theme/components/colorselector/colorselector.css b/packages/ckeditor5-ui/theme/components/colorselector/colorselector.css index c598284bfa2..c716ac0c612 100644 --- a/packages/ckeditor5-ui/theme/components/colorselector/colorselector.css +++ b/packages/ckeditor5-ui/theme/components/colorselector/colorselector.css @@ -3,8 +3,21 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + /* Spacing */ + --ck-color-selector-padding: 0; + + /* Radius */ + /* Set to a radius value (e.g. var(--ck-radius-base)) to disable attached-corner behavior and use uniform corners. */ + --ck-color-selector-uniform-border-radius: var(--ck-border-radius-uniform); + + /* Border */ + --ck-color-selector-color-picker-border-top: var(--ck-border-width-divider) solid var(--ck-color-border-container); +} .ck.ck-color-selector { + padding: var(--ck-color-selector-padding); + /* View fragment with color grids. */ & .ck-color-grids-fragment { & .ck-button.ck-color-selector__remove-color, @@ -20,27 +33,26 @@ /* stylelint-disable-next-line no-descending-specificity */ & .ck-button.ck-color-selector__color-picker { - padding: calc(var(--ck-spacing-standard) / 2) var(--ck-spacing-standard); - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; + padding: calc(var(--ck-spacing-control-padding-inline) / 2) var(--ck-spacing-control-padding-inline); + border-radius: var(--ck-color-selector-uniform-border-radius, var(--ck-border-radius-surface-attached-top)); &:not(:focus) { - border-top: 1px solid var(--ck-color-base-border); + border-top: var(--ck-color-selector-color-picker-border-top); } & .ck.ck-icon { [dir="ltr"] & { - margin-right: var(--ck-spacing-standard); + margin-right: var(--ck-spacing-control-padding-inline); } [dir="rtl"] & { - margin-left: var(--ck-spacing-standard); + margin-left: var(--ck-spacing-control-padding-inline); } } } & label.ck.ck-color-grid__label { - font-weight: unset; + font-weight: var(--ck-font-weight-ui-inherit); } } @@ -54,11 +66,11 @@ min-width: 180px; &::part(saturation) { - border-radius: var(--ck-border-radius) var(--ck-border-radius) 0 0; + border-radius: var(--ck-border-radius-surface) var(--ck-border-radius-surface) 0 0; } &::part(hue) { - border-radius: 0 0 var(--ck-border-radius) var(--ck-border-radius); + border-radius: 0 0 var(--ck-border-radius-surface) var(--ck-border-radius-surface); } &::part(saturation-pointer), @@ -81,7 +93,4 @@ } } } - /* View fragment with color grids. */ - - /* View fragment with a color picker. */ } diff --git a/packages/ckeditor5-ui/theme/components/dialog/dialog.css b/packages/ckeditor5-ui/theme/components/dialog/dialog.css index 632554df3c0..3a1fc69373c 100644 --- a/packages/ckeditor5-ui/theme/components/dialog/dialog.css +++ b/packages/ckeditor5-ui/theme/components/dialog/dialog.css @@ -4,18 +4,26 @@ */ :root { - --ck-dialog-overlay-background-color: hsla( 0, 0%, 0%, .5 ); - --ck-dialog-drop-shadow: 0px 0px 6px 2px hsl(0deg 0% 0% / 15%); - --ck-dialog-max-width: 100vw; + /* Size */ --ck-dialog-max-height: 90vh; - --ck-color-dialog-background: var(--ck-color-base-background); - --ck-color-dialog-form-header-border: var(--ck-color-base-border); + --ck-dialog-max-width: 100vw; + + /* Radius */ + --ck-dialog-border-radius: var(--ck-border-radius-surface); + + /* Border */ + --ck-dialog-border: var(--ck-border-width-surface) solid var(--ck-color-border-container); + + /* Color */ + --ck-dialog-background-color: var(--ck-custom-background, var(--ck-color-surface-container)); + --ck-dialog-overlay-background-color: hsla( 0, 0%, 0%, .5 ); } .ck.ck-dialog-overlay { - animation: ck-dialog-fade-in .3s; + animation: ck-dialog-fade-in var(--ck-animation-duration-surface-entrance); background: var(--ck-dialog-overlay-background-color); - z-index: var(--ck-z-dialog); + /* Backward compatibility: falls back to legacy --ck-z-dialog if overridden. */ + z-index: var(--ck-z-dialog, var(--ck-z-modal)); user-select: none; overscroll-behavior: none; @@ -27,28 +35,28 @@ &.ck-dialog-overlay__transparent { pointer-events: none; - animation: none; + animation: var(--ck-animation-none); background: none; } } .ck.ck-dialog { - border-radius: var(--ck-rounded-corners-radius); - box-shadow: var(--ck-drop-shadow), 0 0; - - --ck-drop-shadow: var(--ck-dialog-drop-shadow); + border-radius: var(--ck-dialog-border-radius); + /* Backward compatibility: falls back to legacy --ck-dialog-drop-shadow if overridden. */ + box-shadow: var(--ck-dialog-drop-shadow, 0px 0px 6px 2px hsl(0deg 0% 0% / 15%)), 0 0; - background: var(--ck-color-dialog-background); + background: var(--ck-dialog-background-color); max-height: var(--ck-dialog-max-height); max-width: var(--ck-dialog-max-width); - border: 1px solid var(--ck-color-base-border); + border: var(--ck-dialog-border); overscroll-behavior: contain; overscroll-behavior: none; width: fit-content; position: absolute; & .ck.ck-form__header { - border-bottom: 1px solid var(--ck-color-dialog-form-header-border); + /* Backward compatibility: falls back to legacy --ck-color-dialog-form-header-border if overridden. */ + border-bottom: var(--ck-color-dialog-form-header-border, var(--ck-border-width-divider) solid var(--ck-custom-border, var(--ck-color-border-container))); flex-shrink: 0; } diff --git a/packages/ckeditor5-ui/theme/components/dialog/dialogactions.css b/packages/ckeditor5-ui/theme/components/dialog/dialogactions.css index 0c0bce4ec3d..2236eae281c 100644 --- a/packages/ckeditor5-ui/theme/components/dialog/dialogactions.css +++ b/packages/ckeditor5-ui/theme/components/dialog/dialogactions.css @@ -5,11 +5,11 @@ .ck.ck-dialog { & .ck.ck-dialog__actions { - padding: var(--ck-spacing-large); + padding: var(--ck-spacing-region-edge-margin-block); display: flex; & > * + * { - margin-left: var(--ck-spacing-large); + margin-left: var(--ck-spacing-region-edge-margin-block); } justify-content: flex-end } diff --git a/packages/ckeditor5-ui/theme/components/dropdown/dropdown.css b/packages/ckeditor5-ui/theme/components/dropdown/dropdown.css index c348dfc31f1..40e95c3de84 100644 --- a/packages/ckeditor5-ui/theme/components/dropdown/dropdown.css +++ b/packages/ckeditor5-ui/theme/components/dropdown/dropdown.css @@ -4,8 +4,24 @@ */ :root { + /* Size */ --ck-dropdown-arrow-size: calc(0.5 * var(--ck-icon-size)); - --ck-dropdown-max-width: 75vw; + + /* Spacing */ + --ck-dropdown-panel-padding: 0; + + /* Radius */ + /* Set to a radius value (e.g. var(--ck-radius-base)) to disable attached-corner behavior and use uniform corners. */ + --ck-dropdown-panel-uniform-border-radius: var(--ck-border-radius-uniform); + --ck-dropdown-panel-border-radius: var(--ck-border-radius-surface-attached); + + /* Color */ + --ck-dropdown-panel-background-color: var(--ck-color-surface-container); + --ck-dropdown-panel-border-color: var(--ck-color-border-container); + --ck-dropdown-list-background-color: transparent; + + /* Border */ + --ck-dropdown-panel-border: var(--ck-border-width-surface) solid var(--ck-dropdown-panel-border-color); } .ck.ck-dropdown { @@ -17,43 +33,44 @@ & .ck-dropdown__arrow { width: var(--ck-dropdown-arrow-size); pointer-events: none; - z-index: var(--ck-z-default); + z-index: var(--ck-layer-base); } [dir="ltr"] & { & .ck-dropdown__arrow { - right: var(--ck-spacing-standard); + right: var(--ck-spacing-control-padding-inline); /* A space to accommodate the triangle. */ - margin-left: var(--ck-spacing-standard); + margin-left: var(--ck-spacing-control-padding-inline); } } [dir="rtl"] & { & .ck-dropdown__arrow { - left: var(--ck-spacing-standard); + left: var(--ck-spacing-control-padding-inline); /* A space to accommodate the triangle. */ - margin-right: var(--ck-spacing-small); + margin-right: var(--ck-spacing-control-padding-inline-compact); } } &.ck-disabled .ck-dropdown__arrow { - opacity: var(--ck-disabled-opacity); + /* Backward compatibility: falls back to legacy --ck-disabled-opacity if overridden. */ + opacity: var(--ck-disabled-opacity, var(--ck-opacity-disabled)); } & .ck-button.ck-dropdown__button { [dir="ltr"] & { &:not(.ck-button_with-text) { /* Make sure dropdowns with just an icon have the right inner spacing */ - padding-left: var(--ck-spacing-small); + padding-left: var(--ck-spacing-control-padding-inline-compact); } } [dir="rtl"] & { &:not(.ck-button_with-text) { /* Make sure dropdowns with just an icon have the right inner spacing */ - padding-right: var(--ck-spacing-small); + padding-right: var(--ck-spacing-control-padding-inline-compact); } } @@ -66,13 +83,13 @@ /* https://github.com/ckeditor/ckeditor5/issues/3362 */ &.ck-disabled .ck-button__label { - opacity: var(--ck-disabled-opacity); + /* Backward compatibility: falls back to legacy --ck-disabled-opacity if overridden. */ + opacity: var(--ck-disabled-opacity, var(--ck-opacity-disabled)); } /* https://github.com/ckeditor/ckeditor5/issues/816 */ &.ck-on { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; + border-radius: var(--ck-dropdown-panel-uniform-border-radius, var(--ck-border-radius-surface-attached-bottom)); } &.ck-dropdown__button_label-width_auto .ck-button__label { @@ -85,7 +102,7 @@ box-shadow: none; &:focus { - box-shadow: var(--ck-focus-outer-shadow), 0 0; + box-shadow: var(--ck-interactive-focus-shadow), 0 0; } } width: 100% @@ -95,8 +112,9 @@ & .ck-dropdown__panel { display: none; - z-index: var(--ck-z-panel); - max-width: var(--ck-dropdown-max-width); + z-index: var(--ck-layer-panel); + /* Backward compatibility: falls back to legacy --ck-dropdown-max-width if overridden. */ + max-width: var(--ck-dropdown-max-width, 75vw); position: absolute; @@ -159,11 +177,12 @@ } .ck.ck-dropdown__panel { - border-radius: var(--ck-rounded-corners-radius); - box-shadow: var(--ck-drop-shadow), 0 0; + border-radius: var(--ck-dropdown-panel-border-radius); + box-shadow: var(--ck-shadow-surface-floating), 0 0; + padding: var(--ck-dropdown-panel-padding); - background: var(--ck-color-dropdown-panel-background); - border: 1px solid var(--ck-color-dropdown-panel-border); + background: var(--ck-dropdown-panel-background-color); + border: var(--ck-dropdown-panel-border); bottom: 0; /* Make sure the panel is at least as wide as the drop-down's button. */ @@ -172,19 +191,24 @@ /* Disabled corner border radius to be consistent with the .dropdown__button https://github.com/ckeditor/ckeditor5/issues/816 */ &.ck-dropdown__panel_se { - border-top-left-radius: 0; + border-radius: var(--ck-dropdown-panel-uniform-border-radius, var(--ck-border-radius-surface-cut-top-left)); } &.ck-dropdown__panel_sw { - border-top-right-radius: 0; + border-radius: var(--ck-dropdown-panel-uniform-border-radius, var(--ck-border-radius-surface-cut-top-right)); } &.ck-dropdown__panel_ne { - border-bottom-left-radius: 0; + border-radius: var(--ck-dropdown-panel-uniform-border-radius, var(--ck-border-radius-surface-cut-bottom-left)); } &.ck-dropdown__panel_nw { - border-bottom-right-radius: 0; + border-radius: var(--ck-dropdown-panel-uniform-border-radius, var(--ck-border-radius-surface-cut-bottom-right)); + } + + /* Prevent the list's own background from overlapping the panel's rounded corners. */ + & > .ck-list { + background: var(--ck-dropdown-list-background-color); } &:focus { @@ -198,5 +222,5 @@ */ .ck.ck-toolbar .ck-dropdown__panel { - z-index: calc( var(--ck-z-panel) + 1 ); + z-index: var(--ck-layer-panel-above); } diff --git a/packages/ckeditor5-ui/theme/components/dropdown/listdropdown.css b/packages/ckeditor5-ui/theme/components/dropdown/listdropdown.css index f123a47a633..e6eb0eb6875 100644 --- a/packages/ckeditor5-ui/theme/components/dropdown/listdropdown.css +++ b/packages/ckeditor5-ui/theme/components/dropdown/listdropdown.css @@ -3,26 +3,26 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + /* Radius */ + /* Set to a radius value (e.g. var(--ck-radius-base)) to disable attached-corner behavior and use uniform corners. */ + --ck-list-dropdown-uniform-border-radius: var(--ck-border-radius-uniform); +} + .ck.ck-dropdown > .ck-dropdown__panel > .ck-list { /* Disabled radius of top-left border to be consistent with .dropdown__button https://github.com/ckeditor/ckeditor5/issues/816 */ - border-radius: var(--ck-rounded-corners-radius); - border-top-left-radius: 0; + border-radius: var(--ck-list-dropdown-uniform-border-radius, 0 var(--ck-dropdown-panel-border-radius) var(--ck-dropdown-panel-border-radius) var(--ck-dropdown-panel-border-radius)); /* Make sure the button belonging to the first/last child of the list goes well with the border radius of the entire panel. */ & .ck-list__item { &:first-child > .ck-button { - border-radius: var(--ck-rounded-corners-radius); - border-top-left-radius: 0; - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; + border-radius: var(--ck-list-dropdown-uniform-border-radius, 0 var(--ck-dropdown-panel-border-radius) 0 0); } &:last-child > .ck-button { - border-radius: var(--ck-rounded-corners-radius); - border-top-left-radius: 0; - border-top-right-radius: 0; + border-radius: var(--ck-list-dropdown-uniform-border-radius, 0 0 var(--ck-dropdown-panel-border-radius) var(--ck-dropdown-panel-border-radius)); } } } diff --git a/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenubutton.css b/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenubutton.css index 076eacc4809..957b2540d4f 100644 --- a/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenubutton.css +++ b/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenubutton.css @@ -6,7 +6,7 @@ .ck.ck-button.ck-dropdown-menu-list__nested-menu__button { width: 100%; - padding: var(--ck-spacing-tiny) calc(2 * var(--ck-spacing-standard)); + padding: var(--ck-spacing-control-padding-block) calc(2 * var(--ck-spacing-control-padding-inline)); border-radius: 0; &:focus { @@ -14,7 +14,7 @@ box-shadow: none; &:not(.ck-on) { - background: var(--ck-color-button-default-hover-background); + background: var(--ck-button-default-hover-background-color); } } @@ -25,55 +25,58 @@ } &.ck-disabled > .ck-button__label { - opacity: var(--ck-disabled-opacity); + /* Backward compatibility: falls back to legacy --ck-disabled-opacity if overridden. */ + opacity: var(--ck-disabled-opacity, var(--ck-opacity-disabled)); } /* Spacing in buttons that miss the icon. */ &.ck-icon-spacing:not(:has(.ck-button__icon)) > .ck-button__label { - margin-left: calc(var(--ck-icon-size) - var(--ck-spacing-small)); + margin-left: calc(var(--ck-icon-size) - var(--ck-spacing-control-padding-inline-compact)); } & > .ck-dropdown-menu-list__nested-menu__button__arrow { width: var(--ck-dropdown-arrow-size); pointer-events: none; - z-index: var(--ck-z-default); + /* Backward compatibility: falls back to legacy --ck-z-default if overridden. */ + z-index: var(--ck-z-default, var(--ck-z-base)); [dir="ltr"] & { transform: rotate(-90deg); - right: var(--ck-spacing-standard); + right: var(--ck-spacing-control-padding-inline); /* A space to accommodate the triangle. */ - margin-left: var(--ck-spacing-standard); + margin-left: var(--ck-spacing-control-padding-inline); /* Nudge the arrow gently to the right because its center of gravity is to the left */ - margin-right: calc(-1 * var(--ck-spacing-small)); + margin-right: calc(-1 * var(--ck-spacing-control-padding-inline-compact)); } [dir="rtl"] & { transform: rotate(90deg); - left: var(--ck-spacing-standard); + left: var(--ck-spacing-control-padding-inline); /* A space to accommodate the triangle. */ - margin-right: var(--ck-spacing-small); + margin-right: var(--ck-spacing-control-padding-inline-compact); /* Nudge the arrow gently to the left because its center of gravity is to the right (after rotation). */ - margin-left: calc(-1 * var(--ck-spacing-small)); + margin-left: calc(-1 * var(--ck-spacing-control-padding-inline-compact)); } } &.ck-disabled > .ck-dropdown-menu-list__nested-menu__button__arrow { - opacity: var(--ck-disabled-opacity); + /* Backward compatibility: falls back to legacy --ck-disabled-opacity if overridden. */ + opacity: var(--ck-disabled-opacity, var(--ck-opacity-disabled)); } [dir="ltr"] & { &:not(.ck-button_with-text) { - padding-left: var(--ck-spacing-small); + padding-left: var(--ck-spacing-control-padding-inline-compact); } } [dir="rtl"] & { &:not(.ck-button_with-text) { - padding-right: var(--ck-spacing-small); + padding-right: var(--ck-spacing-control-padding-inline-compact); } } } diff --git a/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenulistitem.css b/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenulistitem.css index f754af4da7c..244a872f8e8 100644 --- a/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenulistitem.css +++ b/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenulistitem.css @@ -4,6 +4,7 @@ */ :root { + /* Size */ --ck-dropdown-menu-menu-item-min-width: 18em; } diff --git a/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenulistitembutton.css b/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenulistitembutton.css index 4f7c067978e..d3232b47085 100644 --- a/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenulistitembutton.css +++ b/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenulistitembutton.css @@ -3,19 +3,24 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + /* Size */ + --ck-dropdown-menu-list-item-spinner-size: 20px; +} + .ck-button.ck-dropdown-menu-list__nested-menu__item__button { border-radius: 0; & > .ck-spinner-container, & > .ck-spinner-container .ck-spinner { /* These styles correspond to .ck-icon so that the spinner seamlessly replaces the icon. */ - --ck-toolbar-spinner-size: 20px; + --ck-toolbar-spinner-size: var(--ck-dropdown-menu-list-item-spinner-size); } & > .ck-spinner-container { /* These margins are the same as for .ck-icon. */ - margin-left: calc(-1 * var(--ck-spacing-small)); - margin-right: var(--ck-spacing-small); + margin-left: calc(-1 * var(--ck-spacing-control-padding-inline-compact)); + margin-right: var(--ck-spacing-control-padding-inline-compact); } /* @@ -27,7 +32,7 @@ box-shadow: none; &:not(.ck-on) { - background: var(--ck-color-button-default-hover-background); + background: var(--ck-button-default-hover-background-color); } } } diff --git a/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenupanel.css b/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenupanel.css index f4065860e94..27e361abb2c 100644 --- a/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenupanel.css +++ b/packages/ckeditor5-ui/theme/components/dropdown/menu/dropdownmenupanel.css @@ -5,19 +5,27 @@ :root { - --ck-dropdown-menu-menu-panel-max-width: 75vw; + /* Size */ + --ck-dropdown-menu-panel-max-height: 314px; + + /* Radius */ + /* Set to a radius value (e.g. var(--ck-radius-base)) to disable attached-corner behavior and use uniform corners. */ + --ck-dropdown-menu-panel-uniform-border-radius: var(--ck-border-radius-uniform); + --ck-dropdown-menu-panel-border-radius: var(--ck-border-radius-surface-attached); } .ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel { - box-shadow: var(--ck-drop-shadow), 0 0; + border-radius: var(--ck-dropdown-menu-panel-border-radius); + box-shadow: var(--ck-shadow-surface-floating), 0 0; - background: var(--ck-color-dropdown-panel-background); - border: 1px solid var(--ck-color-dropdown-panel-border); + background: var(--ck-dropdown-panel-background-color); + border: var(--ck-dropdown-panel-border); bottom: 0; height: fit-content; - max-width: var(--ck-dropdown-menu-menu-panel-max-width); + /* Backward compatibility: falls back to legacy --ck-dropdown-menu-menu-panel-max-width if overridden. */ + max-width: var(--ck-dropdown-menu-menu-panel-max-width, 75vw); position: absolute; - max-height: 314px; /* With the default settings, this is equal to 10 menu items. */ + max-height: var(--ck-dropdown-menu-panel-max-height); /* With the default settings, this is equal to 10 menu items. */ overflow-y: auto; /* Reset balloon styling */ @@ -29,26 +37,26 @@ /* Corner border radius consistent with the button. */ &.ck-balloon-panel_es, &.ck-balloon-panel_se { - border-top-left-radius: 0; + border-radius: var(--ck-dropdown-menu-panel-uniform-border-radius, var(--ck-border-radius-surface-cut-top-left)); } &.ck-balloon-panel_ws, &.ck-balloon-panel_sw { - border-top-right-radius: 0; + border-radius: var(--ck-dropdown-menu-panel-uniform-border-radius, var(--ck-border-radius-surface-cut-top-right)); } &.ck-balloon-panel_en, &.ck-balloon-panel_ne { - border-bottom-left-radius: 0; + border-radius: var(--ck-dropdown-menu-panel-uniform-border-radius, var(--ck-border-radius-surface-cut-bottom-left)); } &.ck-balloon-panel_wn, &.ck-balloon-panel_nw { - border-bottom-right-radius: 0; + border-radius: var(--ck-dropdown-menu-panel-uniform-border-radius, var(--ck-border-radius-surface-cut-bottom-right)); } &:focus { outline: none; } - z-index: calc(var(--ck-z-panel) + 1) + z-index: var(--ck-layer-panel-above) } diff --git a/packages/ckeditor5-ui/theme/components/dropdown/splitbutton.css b/packages/ckeditor5-ui/theme/components/dropdown/splitbutton.css index 068cc2df8b0..45622b66fa8 100644 --- a/packages/ckeditor5-ui/theme/components/dropdown/splitbutton.css +++ b/packages/ckeditor5-ui/theme/components/dropdown/splitbutton.css @@ -3,17 +3,12 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ -:root { - --ck-color-split-button-hover-background: hsl(0, 0%, 92%); - --ck-color-split-button-hover-border: hsl(0, 0%, 70%); -} - .ck.ck-splitbutton { /* * Note: ck-rounded and ck-dir mixins don't go together (because they both use @nest). */ & .ck-splitbutton__action:focus { - z-index: calc(var(--ck-z-default) + 1); + z-index: var(--ck-layer-control-raised); } &:hover > .ck-splitbutton__action, @@ -63,7 +58,7 @@ /* Don't round the bottom left and right corners of the buttons when "open" https://github.com/ckeditor/ckeditor5/issues/816 */ &.ck-splitbutton_open { - border-radius: var(--ck-rounded-corners-radius); + border-radius: var(--ck-border-radius-control); /* stylelint-disable-next-line no-descending-specificity */ & > .ck-splitbutton__action { @@ -82,7 +77,8 @@ &:hover { /* When the split button hovered as a whole, not as individual buttons. */ & > .ck-button:not(.ck-on):not(.ck-disabled):not(:hover) { - background: var(--ck-color-split-button-hover-background); + /* Fallback to `--ck-color-split-button-hover-background` for backward compatibility. */ + background: var(--ck-color-split-button-hover-background, var(--ck-color-interactive-hover-surface)); } /* Splitbutton separator needs to be set with the ::after pseudoselector @@ -92,12 +88,15 @@ position: absolute; width: 1px; height: 100%; - background-color: var(--ck-color-split-button-hover-border); + /* Fallback to `--ck-color-split-button-hover-border` for backward compatibility. */ + background-color: var(--ck-color-split-button-hover-border, var(--ck-color-border-control)); } /* Make sure the divider between the buttons looks fine when the button is focused */ & > .ck-splitbutton__arrow:focus::after { - --ck-color-split-button-hover-border: var(--ck-color-focus-border); + /* Fallback to `--ck-color-split-button-hover-border` for backward compatibility. */ + --ck-color-split-button-hover-border: var(--ck-color-interactive-focus-border); + background-color: var(--ck-color-split-button-hover-border, var(--ck-color-interactive-focus-border)); } [dir="ltr"] & { diff --git a/packages/ckeditor5-ui/theme/components/dropdown/toolbardropdown.css b/packages/ckeditor5-ui/theme/components/dropdown/toolbardropdown.css index 55baa79be66..4d471969253 100644 --- a/packages/ckeditor5-ui/theme/components/dropdown/toolbardropdown.css +++ b/packages/ckeditor5-ui/theme/components/dropdown/toolbardropdown.css @@ -7,18 +7,15 @@ border: 0; } -:root { - --ck-toolbar-dropdown-max-width: 60vw; -} - .ck.ck-toolbar-dropdown > .ck-dropdown__panel { /* https://github.com/ckeditor/ckeditor5/issues/5586 */ width: max-content; - max-width: var(--ck-toolbar-dropdown-max-width); + /* Backward compatibility: falls back to legacy --ck-toolbar-dropdown-max-width if overridden. */ + max-width: var(--ck-toolbar-dropdown-max-width, 60vw); & .ck-button { &:focus { - z-index: calc(var(--ck-z-default) + 1); + z-index: var(--ck-layer-control-raised); } } } diff --git a/packages/ckeditor5-ui/theme/components/editorui/accessibilityhelp.css b/packages/ckeditor5-ui/theme/components/editorui/accessibilityhelp.css index ae3c9831f04..947636b1dc9 100644 --- a/packages/ckeditor5-ui/theme/components/editorui/accessibilityhelp.css +++ b/packages/ckeditor5-ui/theme/components/editorui/accessibilityhelp.css @@ -5,15 +5,13 @@ :root { - --ck-accessibility-help-dialog-max-width: 600px; + /* Size */ --ck-accessibility-help-dialog-max-height: 400px; - --ck-accessibility-help-dialog-border-color: hsl(220, 6%, 81%); - --ck-accessibility-help-dialog-code-background-color: hsl(0deg 0% 92.94%); - --ck-accessibility-help-dialog-kbd-shadow-color: hsl(0deg 0% 61%); + --ck-accessibility-help-dialog-max-width: 600px; } .ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content { - padding: var(--ck-spacing-large); + padding: var(--ck-spacing-region-edge-margin-block); max-width: var(--ck-accessibility-help-dialog-max-width); max-height: var(--ck-accessibility-help-dialog-max-height); overflow: auto; @@ -23,8 +21,9 @@ &:focus { outline: none; - border: var(--ck-focus-ring); - box-shadow: var(--ck-focus-outer-shadow), 0 0; + border-color: var(--ck-focus-border-color); + /* Backward compatibility: falls back to legacy --ck-focus-outer-shadow if overridden. */ + box-shadow: var(--ck-focus-outer-shadow, var(--ck-focus-shadow)), 0 0; } * { @@ -37,12 +36,12 @@ } & h3 { - font-weight: bold; + font-weight: var(--ck-font-weight-ui-heading); font-size: 1.2em; } & h4 { - font-weight: bold; + font-weight: var(--ck-font-weight-ui-heading); font-size: 1em; } @@ -56,11 +55,11 @@ & dl { display: grid; grid-template-columns: 2fr 1fr; - border-top: 1px solid var(--ck-accessibility-help-dialog-border-color); + border-top: var(--ck-border-width-divider) solid var(--ck-accessibility-help-dialog-border-color, hsl(220, 6%, 81%)); border-bottom: none; & dt, & dd { - border-bottom: 1px solid var(--ck-accessibility-help-dialog-border-color); + border-bottom: var(--ck-border-width-divider) solid var(--ck-accessibility-help-dialog-border-color, hsl(220, 6%, 81%)); padding: .4em 0; } @@ -76,7 +75,7 @@ & kbd, & code { display: inline-block; - background: var(--ck-accessibility-help-dialog-code-background-color); + background: var(--ck-accessibility-help-dialog-code-background-color, hsl(0deg 0% 92.94%)); padding: .4em; vertical-align: middle; line-height: 1; @@ -91,7 +90,7 @@ & kbd { min-width: 1.8em; - box-shadow: 0px 1px 1px var(--ck-accessibility-help-dialog-kbd-shadow-color); + box-shadow: 0px 1px 1px var(--ck-accessibility-help-dialog-kbd-shadow-color, hsl(0deg 0% 61%)); margin: 0 1px; & + kbd { diff --git a/packages/ckeditor5-ui/theme/components/editorui/editorui.css b/packages/ckeditor5-ui/theme/components/editorui/editorui.css index 63f2d901973..6aee5a1d855 100644 --- a/packages/ckeditor5-ui/theme/components/editorui/editorui.css +++ b/packages/ckeditor5-ui/theme/components/editorui/editorui.css @@ -4,26 +4,38 @@ */ :root { - --ck-color-editable-blur-selection: hsl(0, 0%, 85%); + /* Spacing */ + --ck-editor-editable-padding: 0 var(--ck-spacing-region-padding-inline); + + /* Radius */ + --ck-editor-frame-border-radius: var(--ck-border-radius-surface); + --ck-editor-sticky-panel-border-radius: var(--ck-editor-frame-border-radius) var(--ck-editor-frame-border-radius) 0 0; + + /* Border */ + --ck-editor-frame-border: var(--ck-border-width-surface) solid var(--ck-editor-frame-border-color); + + /* Color */ + --ck-editor-frame-border-color: var(--ck-color-border-container); + + /* State / meta */ + --ck-editor-editable-focus-border-color: var(--ck-interactive-focus-border-color); } .ck.ck-editor__top { & .ck-sticky-panel { & .ck-sticky-panel__content { - border-radius: var(--ck-rounded-corners-radius); - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; + border-radius: var(--ck-sticky-panel-uniform-border-radius, var(--ck-editor-sticky-panel-border-radius)); - border: 1px solid var(--ck-color-base-border); + border: var(--ck-editor-frame-border); border-bottom-width: 0; &.ck-sticky-panel__content_sticky { - border-bottom-width: 1px; + border-bottom-width: var(--ck-border-width-surface); } & .ck-menu-bar { border: 0; - border-bottom: 1px solid var(--ck-color-base-border); + border-bottom: var(--ck-editor-frame-border); } & .ck-toolbar { @@ -34,19 +46,20 @@ } .ck.ck-editor__editable:not(.ck-editor__nested-editable) { - border-radius: var(--ck-rounded-corners-radius); + border-radius: var(--ck-editor-frame-border-radius); &.ck-focused { outline: none; - border: var(--ck-focus-ring); - box-shadow: var(--ck-inner-shadow), 0 0; + border-color: var(--ck-editor-editable-focus-border-color); + /* Backward compatibility: falls back to legacy --ck-inner-shadow if overridden. */ + box-shadow: var(--ck-inner-shadow, var(--ck-inset-shadow-sm)), 0 0; } } .ck.ck-editor__editable_inline { overflow: auto; - padding: 0 var(--ck-spacing-standard); - border: 1px solid transparent; + padding: var(--ck-editor-editable-padding); + border: var(--ck-border-width-control) solid transparent; &[dir="ltr"] { text-align: left; @@ -58,7 +71,7 @@ /* https://github.com/ckeditor/ckeditor5/issues/3385 */ & > *:first-child { - margin-top: var(--ck-spacing-large); + margin-top: var(--ck-spacing-region-edge-margin-block); } /* https://github.com/ckeditor/ckeditor5/issues/847 */ @@ -67,12 +80,13 @@ * This value should match with the default margins of the block elements (like .media or .image) * to avoid a content jumping when the fake selection container shows up (See https://github.com/ckeditor/ckeditor5/issues/9825). */ - margin-bottom: var(--ck-spacing-large); + margin-bottom: var(--ck-spacing-region-edge-margin-block); } /* https://github.com/ckeditor/ckeditor5/issues/6517 */ &.ck-blurred ::selection { - background: var(--ck-color-editable-blur-selection); + /* Fallback to `--ck-color-editable-blur-selection` for backward compatibility. */ + background: var(--ck-color-editable-blur-selection, hsl(0, 0%, 85%)); } } @@ -80,12 +94,12 @@ .ck.ck-balloon-panel.ck-toolbar-container[class*="arrow_n"] { &::after { - border-bottom-color: var(--ck-color-panel-background); + border-bottom-color: var(--ck-balloon-panel-background-color); } } .ck.ck-balloon-panel.ck-toolbar-container[class*="arrow_s"] { &::after { - border-top-color: var(--ck-color-panel-background); + border-top-color: var(--ck-balloon-panel-background-color); } } diff --git a/packages/ckeditor5-ui/theme/components/form/form.css b/packages/ckeditor5-ui/theme/components/form/form.css index 917dcd47de4..e54f896c467 100644 --- a/packages/ckeditor5-ui/theme/components/form/form.css +++ b/packages/ckeditor5-ui/theme/components/form/form.css @@ -5,11 +5,15 @@ :root { + /* Size */ --ck-form-default-width: 340px; + + /* Spacing */ + --ck-form-padding: 0 0 var(--ck-spacing-region-edge-margin-block); } .ck.ck-form { - padding: 0 0 var(--ck-spacing-large); + padding: var(--ck-form-padding); &.ck-form_default-width { width: var(--ck-form-default-width); @@ -30,7 +34,7 @@ & .ck-dropdown__button { &:not(:focus) { - border: 1px solid var(--ck-color-base-border); + border: var(--ck-border-control); } & .ck-button__label { @@ -51,7 +55,7 @@ > .ck { @media screen and (max-width: 600px) { - margin: var(--ck-spacing-large) var(--ck-spacing-large) 0; + margin: var(--ck-spacing-region-edge-margin-block) var(--ck-spacing-region-edge-margin-block) 0; } } @@ -64,7 +68,7 @@ &.ck-form__row_large-bottom-padding { @media screen and (max-width: 600px) { - padding-bottom: var(--ck-spacing-large); + padding-bottom: var(--ck-spacing-region-edge-margin-block); } } } diff --git a/packages/ckeditor5-ui/theme/components/formheader/formheader.css b/packages/ckeditor5-ui/theme/components/formheader/formheader.css index 4a4a829a55e..0bd381297a9 100644 --- a/packages/ckeditor5-ui/theme/components/formheader/formheader.css +++ b/packages/ckeditor5-ui/theme/components/formheader/formheader.css @@ -4,14 +4,21 @@ */ :root { + /* Size */ --ck-form-header-height: 3.384em; + + /* Spacing */ + --ck-form-header-padding-block: var(--ck-spacing-surface-padding-block); + + /* Typography */ + --ck-form-header-label-font-size: 1.153em; } .ck.ck-form__header { - padding: var(--ck-spacing-small) var(--ck-spacing-large); + padding: var(--ck-form-header-padding-block) var(--ck-spacing-control-meta-gap); height: var(--ck-form-header-height); line-height: var(--ck-form-header-height); - border-bottom: 1px solid var(--ck-color-base-border); + border-bottom: var(--ck-border-divider); /* To prevent shrinking when placed in flexbox. */ flex-shrink: 0; display: flex; @@ -21,29 +28,28 @@ justify-content: space-between; & > .ck-icon { - margin-inline-end: var(--ck-spacing-medium); + margin-inline-end: var(--ck-spacing-control-icon-gap); flex-shrink: 0; } & .ck-form__header__label { /* Defaults to 15px. */ - --ck-font-size-base: 1.153em; - - font-weight: bold; + --ck-font-size-base: var(--ck-form-header-label-font-size); + font-weight: var(--ck-font-weight-ui-heading); } /* Padding when back button is hidden */ &:has(.ck-button-back.ck-hidden) { - padding-inline: var(--ck-spacing-large) var(--ck-spacing-large); + padding-inline: var(--ck-spacing-control-meta-gap) var(--ck-spacing-control-meta-gap); } /* Padding when back button is visible */ &:has(.ck-button-back:not(.ck-hidden)) { - padding-inline: var(--ck-spacing-small) var(--ck-spacing-small); + padding-inline: var(--ck-spacing-surface-padding-inline) var(--ck-spacing-surface-padding-inline); } & > .ck-button-back { - margin-inline-end: var(--ck-spacing-small); + margin-inline-end: var(--ck-spacing-surface-item-gap-inline); } & > .ck.ck-button { diff --git a/packages/ckeditor5-ui/theme/components/formrow/formrow.css b/packages/ckeditor5-ui/theme/components/formrow/formrow.css index db0e51740f0..23bfb8b4445 100644 --- a/packages/ckeditor5-ui/theme/components/formrow/formrow.css +++ b/packages/ckeditor5-ui/theme/components/formrow/formrow.css @@ -3,26 +3,31 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + /* Spacing */ + --ck-form-row-padding: var(--ck-spacing-region-padding-block) var(--ck-spacing-region-padding-inline-wide) 0; +} + .ck.ck-form__row { display: flex; flex-direction: row; justify-content: space-between; align-items: flex-start; - padding: var(--ck-spacing-standard) var(--ck-spacing-large) 0; + padding: var(--ck-form-row-padding); &.ck-form__row_large-top-padding { - padding-top: var(--ck-spacing-large); + padding-top: var(--ck-spacing-region-edge-margin-block); } &.ck-form__row_large-bottom-padding { - padding-bottom: var(--ck-spacing-large); + padding-bottom: var(--ck-spacing-region-edge-margin-block); } &.ck-form__row_with-submit { flex-wrap: nowrap; & > *:not(:first-child) { - margin-inline-start: var(--ck-spacing-standard); + margin-inline-start: var(--ck-spacing-region-padding-inline); } } diff --git a/packages/ckeditor5-ui/theme/components/highlightedtext/highlightedtext.css b/packages/ckeditor5-ui/theme/components/highlightedtext/highlightedtext.css index 9a9256305ab..061923b2710 100644 --- a/packages/ckeditor5-ui/theme/components/highlightedtext/highlightedtext.css +++ b/packages/ckeditor5-ui/theme/components/highlightedtext/highlightedtext.css @@ -6,7 +6,7 @@ .ck.ck-highlighted-text mark { background: var(--ck-color-highlight-background); vertical-align: initial; - font-weight: inherit; + font-weight: var(--ck-font-weight-ui-inherit); line-height: inherit; font-size: inherit; } diff --git a/packages/ckeditor5-ui/theme/components/icon/icon.css b/packages/ckeditor5-ui/theme/components/icon/icon.css index 77848c6a65c..16d4575fae7 100644 --- a/packages/ckeditor5-ui/theme/components/icon/icon.css +++ b/packages/ckeditor5-ui/theme/components/icon/icon.css @@ -4,8 +4,9 @@ */ :root { - --ck-icon-size: calc(var(--ck-line-height-base) * var(--ck-font-size-normal)); - --ck-icon-font-size: .8333350694em; + /* Size */ + /* Backward compatibility: falls back to legacy --ck-font-size-normal if overridden. */ + --ck-icon-size: calc(var(--ck-line-height-base) * var(--ck-font-size-normal, var(--ck-font-size-md))); } .ck.ck-icon { @@ -13,7 +14,8 @@ height: var(--ck-icon-size); /* Multiplied by the height of the line in "px" should give SVG "viewport" dimensions */ - font-size: var(--ck-icon-font-size); + /* Backward compatibility: falls back to legacy --ck-icon-font-size if overridden. */ + font-size: var(--ck-icon-font-size, .8333350694em); /* Inherit cursor style (#5). */ cursor: inherit; diff --git a/packages/ckeditor5-ui/theme/components/input/input.css b/packages/ckeditor5-ui/theme/components/input/input.css index bd80682c66e..20d236c64fd 100644 --- a/packages/ckeditor5-ui/theme/components/input/input.css +++ b/packages/ckeditor5-ui/theme/components/input/input.css @@ -4,56 +4,79 @@ */ :root { + /* Size */ --ck-input-width: 18em; - /* Backward compatibility. */ + /* Spacing */ + --ck-input-padding: var(--ck-spacing-control-padding-block-compact) var(--ck-spacing-control-padding-inline-compact); + + /* Radius */ + --ck-input-border-radius: var(--ck-border-radius-control); + + /* Color */ + --ck-input-background-color: var(--ck-color-surface-control); + --ck-input-border-color: var(--ck-color-border-control); + --ck-input-error-border-color: var(--ck-color-feedback-error); + --ck-input-text-color: var(--ck-color-text-primary); + --ck-input-disabled-background-color: hsl(0, 0%, 95%); + --ck-input-disabled-border-color: var(--ck-color-border-control); + --ck-input-disabled-text-color: var(--ck-color-text-disabled); + + /* Border */ + --ck-input-border: var(--ck-border-width-control) solid var(--ck-input-border-color); + + /* State / meta */ + --ck-input-focus-border-color: var(--ck-interactive-focus-border-color); + + /* Compatibility */ --ck-input-text-width: var(--ck-input-width); } .ck.ck-input { - border-radius: var(--ck-rounded-corners-radius); - background: var(--ck-color-input-background); - border: 1px solid var(--ck-color-input-border); - padding: var(--ck-spacing-extra-tiny) var(--ck-spacing-medium); + border-radius: var(--ck-input-border-radius); + background: var(--ck-input-background-color); + border: var(--ck-input-border); + padding: var(--ck-input-padding); min-width: var(--ck-input-width); + color: var(--ck-input-text-color); /* This is important to stay of the same height as surrounding buttons */ - min-height: var(--ck-ui-component-min-height); + min-height: var(--ck-size-control-min-height); /* Apply some smooth transition to the box-shadow and border. */ - transition: box-shadow .1s ease-in-out, border .1s ease-in-out; + transition: var(--ck-transition-control-fast); @media (prefers-reduced-motion: reduce) { - transition: none; + transition: var(--ck-transition-none); } &:focus { outline: none; - border: var(--ck-focus-ring); - box-shadow: var(--ck-focus-outer-shadow), 0 0; + border-color: var(--ck-input-focus-border-color); + box-shadow: var(--ck-interactive-focus-shadow), 0 0; } &[readonly] { - border: 1px solid var(--ck-color-input-disabled-border); - background: var(--ck-color-input-disabled-background); - color: var(--ck-color-input-disabled-text); + border: var(--ck-border-width-control) solid var(--ck-input-disabled-border-color); + background: var(--ck-input-disabled-background-color); + color: var(--ck-input-disabled-text-color); &:focus { /* The read-only input should have a slightly less visible shadow when focused. */ - box-shadow: var(--ck-focus-disabled-outer-shadow), 0 0; + box-shadow: var(--ck-interactive-focus-disabled-shadow), 0 0; } } &.ck-error { - border-color: var(--ck-color-input-error-border); - animation: ck-input-shake .3s ease both; + border-color: var(--ck-input-error-border-color); + animation: ck-input-shake var(--ck-animation-duration-feedback) var(--ck-animation-timing-function-feedback) var(--ck-animation-fill-mode-feedback); @media (prefers-reduced-motion: reduce) { - animation: none; + animation: var(--ck-animation-none); } &:focus { - box-shadow: var(--ck-focus-error-outer-shadow), 0 0; + box-shadow: var(--ck-interactive-focus-error-shadow), 0 0; } } } @@ -74,4 +97,8 @@ 80% { transform: translateX(1px); } + + 100% { + transform: translateX(0); + } } diff --git a/packages/ckeditor5-ui/theme/components/label/label.css b/packages/ckeditor5-ui/theme/components/label/label.css index 073d3fdd3e8..5eb21c67c73 100644 --- a/packages/ckeditor5-ui/theme/components/label/label.css +++ b/packages/ckeditor5-ui/theme/components/label/label.css @@ -4,7 +4,7 @@ */ .ck.ck-label { - font-weight: bold; + font-weight: var(--ck-font-weight-ui-label); display: block; } diff --git a/packages/ckeditor5-ui/theme/components/labeledfield/labeledfieldview.css b/packages/ckeditor5-ui/theme/components/labeledfield/labeledfieldview.css index 0ca082a0682..668a5bf0b53 100644 --- a/packages/ckeditor5-ui/theme/components/labeledfield/labeledfieldview.css +++ b/packages/ckeditor5-ui/theme/components/labeledfield/labeledfieldview.css @@ -4,15 +4,14 @@ */ :root { - --ck-labeled-field-view-transition: .1s cubic-bezier(0, 0, 0.24, 0.95); - --ck-labeled-field-empty-unfocused-max-width: 100% - 2 * var(--ck-spacing-medium); - --ck-labeled-field-label-default-position-x: var(--ck-spacing-medium); - --ck-labeled-field-label-default-position-y: calc(0.6 * var(--ck-font-size-base)); - --ck-color-labeled-field-label-background: var(--ck-color-base-background); + /* Color */ + --ck-labeled-field-label-background-color: var(--ck-color-surface-control); + --ck-labeled-field-label-start-gap: var(--ck-spacing-control-icon-gap); } .ck.ck-labeled-field-view { - border-radius: var(--ck-rounded-corners-radius); + /* Backward compatibility: falls back to legacy --ck-rounded-corners-radius if overridden. */ + border-radius: var(--ck-rounded-corners-radius, var(--ck-radius-corners)); & .ck.ck-label { display: block; @@ -27,11 +26,12 @@ top: 0px; pointer-events: none; - - background: var(--ck-color-labeled-field-label-background); - padding: 0 calc(.5 * var(--ck-font-size-tiny)); + /* Fallback to `--ck-color-labeled-field-label-background` for backward compatibility. */ + background: var(--ck-color-labeled-field-label-background, var(--ck-labeled-field-label-background-color)); + /* Backward compatibility: falls back to legacy --ck-font-size-tiny if overridden. */ + padding: 0 calc(.5 * var(--ck-font-size-tiny, var(--ck-font-size-xs))); line-height: initial; - font-weight: normal; + font-weight: var(--ck-font-weight-ui-muted); /* Prevent overflow when the label is longer than the input */ text-overflow: ellipsis; @@ -40,25 +40,25 @@ max-width: 100%; transition: - transform var(--ck-labeled-field-view-transition), - padding var(--ck-labeled-field-view-transition), - background var(--ck-labeled-field-view-transition); + transform var(--ck-transition-duration-control-fast) var(--ck-transition-timing-function-control-emphasized), + padding var(--ck-transition-duration-control-fast) var(--ck-transition-timing-function-control-emphasized), + background var(--ck-transition-duration-control-fast) var(--ck-transition-timing-function-control-emphasized); [dir="ltr"] & { left: 0px; transform-origin: 0 0; /* By default, display the label scaled down above the field. */ - transform: translate(var(--ck-spacing-medium), -6px) scale(.75); + transform: translate(var(--ck-labeled-field-label-start-gap), -6px) scale(.75); } [dir="rtl"] & { right: 0px; transform-origin: 100% 0; - transform: translate(calc(-1 * var(--ck-spacing-medium)), -6px) scale(.75); + transform: translate(calc(-1 * var(--ck-labeled-field-label-start-gap)), -6px) scale(.75); } @media (prefers-reduced-motion: reduce) { - transition: none; + transition: var(--ck-transition-none); } } position: relative @@ -66,31 +66,32 @@ &.ck-error { & > .ck.ck-labeled-field-view__input-wrapper > .ck.ck-label { - color: var(--ck-color-base-error); + color: var(--ck-color-feedback-error); } & .ck-input:not([readonly]) + .ck.ck-label { - color: var(--ck-color-base-error); + color: var(--ck-color-feedback-error); } } & .ck-labeled-field-view__status { - font-size: var(--ck-font-size-small); - margin-top: var(--ck-spacing-small); + /* Backward compatibility: falls back to legacy --ck-font-size-small if overridden. */ + font-size: var(--ck-font-size-small, var(--ck-font-size-sm)); + margin-top: var(--ck-spacing-surface-item-gap-inline); /* Let the info wrap to the next line to avoid stretching the layout horizontally. The status could be very long. */ white-space: normal; &.ck-labeled-field-view__status_error { - color: var(--ck-color-base-error); + color: var(--ck-color-feedback-error); } } /* Disabled fields and fields that have no focus should fade out. */ &.ck-disabled > .ck.ck-labeled-field-view__input-wrapper > .ck.ck-label, &.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused) > .ck.ck-labeled-field-view__input-wrapper > .ck.ck-label { - color: var(--ck-color-input-disabled-text); + color: var(--ck-input-disabled-text-color); } /* Fields that are disabled or not focused and without a placeholder should have full-sized labels. */ @@ -98,16 +99,16 @@ &.ck-disabled.ck-labeled-field-view_empty:not(.ck-labeled-field-view_placeholder) > .ck.ck-labeled-field-view__input-wrapper > .ck.ck-label, &.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder):not(.ck-error) > .ck.ck-labeled-field-view__input-wrapper > .ck.ck-label { [dir="ltr"] & { - transform: translate(var(--ck-labeled-field-label-default-position-x), var(--ck-labeled-field-label-default-position-y)) scale(1); + transform: translate(var(--ck-labeled-field-label-default-position-x, var(--ck-labeled-field-label-start-gap)), calc(0.6 * var(--ck-font-size-base))) scale(1); } /* stylelint-disable-next-line no-descending-specificity */ [dir="rtl"] & { - transform: translate(calc(-1 * var(--ck-labeled-field-label-default-position-x)), var(--ck-labeled-field-label-default-position-y)) scale(1); + transform: translate(calc(-1 * var(--ck-labeled-field-label-default-position-x, var(--ck-labeled-field-label-start-gap))), calc(0.6 * var(--ck-font-size-base))) scale(1); } /* Compensate for the default translate position. */ - max-width: calc(var(--ck-labeled-field-empty-unfocused-max-width)); + max-width: var(--ck-labeled-field-empty-unfocused-max-width, calc(100% - 2 * var(--ck-labeled-field-label-start-gap))); background: transparent; padding: 0; @@ -127,7 +128,7 @@ /* Make sure the label of the empty, unfocused input does not cover the dropdown arrow. */ &.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder) > .ck.ck-labeled-field-view__input-wrapper > .ck-dropdown + .ck-label { - max-width: calc(var(--ck-labeled-field-empty-unfocused-max-width) - var(--ck-dropdown-arrow-size) - var(--ck-spacing-standard)); + max-width: var(--ck-labeled-field-empty-unfocused-max-width, calc(100% - 2 * var(--ck-labeled-field-label-start-gap) - var(--ck-dropdown-arrow-size) - var(--ck-spacing-control-padding-inline))); } &.ck-labeled-field-view_full-width { diff --git a/packages/ckeditor5-ui/theme/components/labeledinput/labeledinput.css b/packages/ckeditor5-ui/theme/components/labeledinput/labeledinput.css index d2437f7383c..0c2a074e0ab 100644 --- a/packages/ckeditor5-ui/theme/components/labeledinput/labeledinput.css +++ b/packages/ckeditor5-ui/theme/components/labeledinput/labeledinput.css @@ -4,8 +4,9 @@ */ .ck.ck-labeled-input .ck-labeled-input__status { - font-size: var(--ck-font-size-small); - margin-top: var(--ck-spacing-small); + /* Backward compatibility: falls back to legacy --ck-font-size-small if overridden. */ + font-size: var(--ck-font-size-small, var(--ck-font-size-sm)); + margin-top: var(--ck-spacing-surface-item-gap-inline); /* Let the info wrap to the next line to avoid stretching the layout horizontally. The status could be very long. */ @@ -13,5 +14,5 @@ } .ck.ck-labeled-input .ck-labeled-input__status_error { - color: var(--ck-color-base-error); + color: var(--ck-color-feedback-error); } diff --git a/packages/ckeditor5-ui/theme/components/list/list.css b/packages/ckeditor5-ui/theme/components/list/list.css index 81e8a8696f2..655fa41794e 100644 --- a/packages/ckeditor5-ui/theme/components/list/list.css +++ b/packages/ckeditor5-ui/theme/components/list/list.css @@ -3,13 +3,35 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + /* Size */ + --ck-list-item-min-width: 15em; + + /* Spacing */ + --ck-list-padding: var(--ck-spacing-surface-padding-block) 0; + --ck-list-item-outer-padding: 0; + + /* Radius */ + --ck-list-border-radius: var(--ck-border-radius-surface); + + /* Color */ + --ck-list-background-color: var(--ck-color-surface-control); + --ck-list-button-hover-background-color: var(--ck-button-default-hover-background-color); + --ck-list-button-on-background-color: var(--ck-button-on-text-color); + --ck-list-button-on-text-color: var(--ck-color-text-inverse); + --ck-list-divider-color: var(--ck-color-divider); + + /* Typography */ + --ck-list-group-label-font-size: 11px; +} + .ck.ck-list { - border-radius: var(--ck-rounded-corners-radius); + border-radius: var(--ck-list-border-radius); list-style-type: none; - background: var(--ck-color-list-background); + background: var(--ck-list-background-color); /* A spacing at the beginning and end of the list */ - padding: var(--ck-spacing-small) 0; + padding: var(--ck-list-padding); -webkit-user-select: none; user-select: none; @@ -26,18 +48,19 @@ adjacent list items. */ & .ck-list__item > *:focus { position: relative; - z-index: var(--ck-z-default); + z-index: var(--ck-layer-base); } } .ck.ck-list__item { cursor: default; + padding: var(--ck-list-item-outer-padding); /* Almost as wide as menu bar items. */ - min-width: 15em; + min-width: var(--ck-list-item-min-width); & > .ck-button:not(.ck-list-item-button) { - padding: var(--ck-spacing-tiny) calc(2 * var(--ck-spacing-standard)); + padding: var(--ck-spacing-control-padding-block) calc(2 * var(--ck-spacing-control-padding-inline)); min-height: unset; width: 100%; border-radius: 0; @@ -60,24 +83,24 @@ } &.ck-on { - background: var(--ck-color-list-button-on-background); - color: var(--ck-color-list-button-on-text); + background: var(--ck-list-button-on-background-color); + color: var(--ck-list-button-on-text-color); &:active { box-shadow: none; } &:hover:not(.ck-disabled) { - background: var(--ck-color-list-button-on-background-focus); + background: var(--ck-list-button-on-background-color); } &:focus:not(.ck-disabled) { - border-color: var(--ck-color-base-background); + border-color: var(--ck-color-surface-control); } } &:hover:not(.ck-disabled) { - background: var(--ck-color-list-button-hover-background); + background: var(--ck-list-button-hover-background-color); } } @@ -85,11 +108,11 @@ of conveying its state (like the switcher) */ & > .ck-button.ck-switchbutton { &.ck-on { - background: var(--ck-color-list-background); + background: var(--ck-list-background-color); color: inherit; &:hover:not(.ck-disabled) { - background: var(--ck-color-list-button-hover-background); + background: var(--ck-list-button-hover-background-color); color: inherit; } } @@ -97,7 +120,7 @@ } .ck-list .ck-list__group { - padding-top: var(--ck-spacing-medium); + padding-top: var(--ck-spacing-surface-section-gap-block); /* Lists come with an inner vertical padding. Don't duplicate it. */ &:first-child { @@ -106,21 +129,21 @@ /* The group should have a border when it's not the first item. */ *:not(.ck-hidden) ~ & { - border-top: 1px solid var(--ck-color-base-border); + border-top: var(--ck-border-width-divider) solid var(--ck-list-divider-color); } & > .ck-label { - font-size: 11px; - font-weight: bold; - padding: var(--ck-spacing-medium) var(--ck-spacing-large) 0; + font-size: var(--ck-list-group-label-font-size); + font-weight: var(--ck-font-weight-ui-label); + padding: var(--ck-spacing-surface-section-gap-block) var(--ck-spacing-control-meta-gap) 0; } } .ck.ck-list__separator { height: 1px; width: 100%; - background: var(--ck-color-base-border); + background: var(--ck-list-divider-color); /* Give the separator some air */ - margin: var(--ck-spacing-small) 0; + margin: var(--ck-spacing-surface-item-gap-inline) 0; } diff --git a/packages/ckeditor5-ui/theme/components/menubar/menubar.css b/packages/ckeditor5-ui/theme/components/menubar/menubar.css index 5f567b7c170..fe7ff93824f 100644 --- a/packages/ckeditor5-ui/theme/components/menubar/menubar.css +++ b/packages/ckeditor5-ui/theme/components/menubar/menubar.css @@ -7,9 +7,9 @@ display: flex; flex-wrap: wrap; justify-content: flex-start; - background: var(--ck-color-base-background); - padding: var(--ck-spacing-small); - gap: var(--ck-spacing-small); - border: 1px solid var(--ck-color-toolbar-border); + background: var(--ck-color-surface-canvas); + padding: var(--ck-spacing-surface-padding-inline); + gap: var(--ck-spacing-surface-item-gap-inline); + border: var(--ck-toolbar-border); width: 100%; } diff --git a/packages/ckeditor5-ui/theme/components/menubar/menubarmenubutton.css b/packages/ckeditor5-ui/theme/components/menubar/menubarmenubutton.css index f2254a30ca4..df578eef20f 100644 --- a/packages/ckeditor5-ui/theme/components/menubar/menubarmenubutton.css +++ b/packages/ckeditor5-ui/theme/components/menubar/menubarmenubutton.css @@ -3,6 +3,10 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + /* Radius */ + --ck-menu-bar-button-border-radius: 0; +} .ck.ck-menu-bar__menu { /* @@ -18,18 +22,19 @@ } &.ck-disabled > .ck-button__label { - opacity: var(--ck-disabled-opacity); + /* Backward compatibility: falls back to legacy --ck-disabled-opacity if overridden. */ + opacity: var(--ck-disabled-opacity, var(--ck-opacity-disabled)); } [dir="ltr"] & { &:not(.ck-button_with-text) { - padding-left: var(--ck-spacing-small); + padding-left: var(--ck-spacing-control-padding-inline-compact); } } [dir="rtl"] & { &:not(.ck-button_with-text) { - padding-right: var(--ck-spacing-small); + padding-right: var(--ck-spacing-control-padding-inline-compact); } } } @@ -39,7 +44,7 @@ */ /* stylelint-disable-next-line no-descending-specificity */ &.ck-menu-bar__menu_top-level > .ck-menu-bar__menu__button { - padding: var(--ck-spacing-small) var(--ck-spacing-medium); + padding: var(--ck-spacing-control-padding-block-regular) var(--ck-spacing-control-icon-gap); min-height: unset; & .ck-button__label { @@ -54,8 +59,7 @@ } &.ck-on { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; + border-radius: var(--ck-menu-bar-panel-uniform-border-radius, var(--ck-border-radius-surface-attached-bottom)); } & .ck-icon { @@ -65,7 +69,8 @@ & > .ck-menu-bar__menu__button > .ck-menu-bar__menu__button__arrow { pointer-events: none; - z-index: var(--ck-z-default); + /* Backward compatibility: falls back to legacy --ck-z-default if overridden. */ + z-index: var(--ck-z-default, var(--ck-z-base)); } /* @@ -73,7 +78,7 @@ */ /* stylelint-disable-next-line no-descending-specificity */ &:not(.ck-menu-bar__menu_top-level) .ck-menu-bar__menu__button { - border-radius: 0; + border-radius: var(--ck-menu-bar-button-border-radius); & > .ck-menu-bar__menu__button__arrow { width: var(--ck-dropdown-arrow-size); @@ -82,27 +87,28 @@ transform: rotate(-90deg); /* A space to accommodate the triangle. */ - margin-left: var(--ck-spacing-standard); + margin-left: var(--ck-spacing-control-padding-inline); /* Nudge the arrow gently to the right because its center of gravity is to the left */ - margin-right: calc(-1 * var(--ck-spacing-small)); + margin-right: calc(-1 * var(--ck-spacing-control-padding-inline-compact)); } [dir="rtl"] & { transform: rotate(90deg); - left: var(--ck-spacing-standard); + left: var(--ck-spacing-control-padding-inline); /* A space to accommodate the triangle. */ - margin-right: var(--ck-spacing-small); + margin-right: var(--ck-spacing-control-padding-inline-compact); /* Nudge the arrow gently to the left because its center of gravity is to the right (after rotation). */ - margin-left: calc(-1 * var(--ck-spacing-small)); + margin-left: calc(-1 * var(--ck-spacing-control-padding-inline-compact)); } } &.ck-disabled > .ck-menu-bar__menu__button__arrow { - opacity: var(--ck-disabled-opacity); + /* Backward compatibility: falls back to legacy --ck-disabled-opacity if overridden. */ + opacity: var(--ck-disabled-opacity, var(--ck-opacity-disabled)); } } } diff --git a/packages/ckeditor5-ui/theme/components/menubar/menubarmenulistitem.css b/packages/ckeditor5-ui/theme/components/menubar/menubarmenulistitem.css index e3b99cd8d8c..cd393402bb4 100644 --- a/packages/ckeditor5-ui/theme/components/menubar/menubarmenulistitem.css +++ b/packages/ckeditor5-ui/theme/components/menubar/menubarmenulistitem.css @@ -4,6 +4,7 @@ */ :root { + /* Size */ --ck-menu-bar-menu-item-min-width: 18em; } diff --git a/packages/ckeditor5-ui/theme/components/menubar/menubarmenulistitembutton.css b/packages/ckeditor5-ui/theme/components/menubar/menubarmenulistitembutton.css index 258c85d7f43..fc5efab8246 100644 --- a/packages/ckeditor5-ui/theme/components/menubar/menubarmenulistitembutton.css +++ b/packages/ckeditor5-ui/theme/components/menubar/menubarmenulistitembutton.css @@ -3,13 +3,17 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + /* Radius */ + --ck-menu-bar-list-item-button-border-radius: 0; +} .ck.ck-menu-bar__menu { /* * List item buttons. */ & .ck-button.ck-menu-bar__menu__item__button { - border-radius: 0; + border-radius: var(--ck-menu-bar-list-item-button-border-radius); & > .ck-spinner-container, & > .ck-spinner-container .ck-spinner { @@ -19,14 +23,14 @@ & > .ck-spinner-container { /* This ensures margins corresponding to the .ck-icon. */ - font-size: var(--ck-icon-font-size); + font-size: .8333350694em; [dir="ltr"] & { - margin-right: var(--ck-spacing-medium); + margin-right: var(--ck-spacing-control-icon-gap); } [dir="rtl"] & { - margin-left: var(--ck-spacing-medium); + margin-left: var(--ck-spacing-control-icon-gap); } } } diff --git a/packages/ckeditor5-ui/theme/components/menubar/menubarmenupanel.css b/packages/ckeditor5-ui/theme/components/menubar/menubarmenupanel.css index e65cd5a3d33..11313af677c 100644 --- a/packages/ckeditor5-ui/theme/components/menubar/menubarmenupanel.css +++ b/packages/ckeditor5-ui/theme/components/menubar/menubarmenupanel.css @@ -4,42 +4,49 @@ */ :root { - --ck-menu-bar-menu-max-width: 75vw; - --ck-menu-bar-nested-menu-horizontal-offset: 5px; + /* Radius */ + /* Set to a radius value (e.g. var(--ck-radius-base)) to disable attached-corner behavior and use uniform corners. */ + --ck-menu-bar-panel-uniform-border-radius: var(--ck-border-radius-uniform); + --ck-menu-bar-panel-border-radius: var(--ck-border-radius-surface-attached); + + /* State / meta */ + --ck-menu-bar-item-focus-border-color: var(--ck-interactive-focus-border-color); } .ck.ck-menu-bar__menu > .ck.ck-menu-bar__menu__panel { - border-radius: var(--ck-rounded-corners-radius); - box-shadow: var(--ck-drop-shadow), 0 0; + border-radius: var(--ck-menu-bar-panel-border-radius); + box-shadow: var(--ck-shadow-surface-floating), 0 0; - background: var(--ck-color-dropdown-panel-background); - border: 1px solid var(--ck-color-dropdown-panel-border); + background: var(--ck-dropdown-panel-background-color); + border: var(--ck-dropdown-panel-border); bottom: 0; height: fit-content; - z-index: var(--ck-z-panel); - max-width: var(--ck-menu-bar-menu-max-width); + /* Backward compatibility: falls back to legacy --ck-z-panel if overridden. */ + z-index: var(--ck-z-panel, var(--ck-z-overlay)); + /* Backward compatibility: falls back to legacy --ck-menu-bar-menu-max-width if overridden. */ + max-width: var(--ck-menu-bar-menu-max-width, 75vw); position: absolute; /* Corner border radius consistent with the button. */ &.ck-menu-bar__menu__panel_position_es, &.ck-menu-bar__menu__panel_position_se { - border-top-left-radius: 0; + border-radius: var(--ck-menu-bar-panel-uniform-border-radius, var(--ck-border-radius-surface-cut-top-left)); } &.ck-menu-bar__menu__panel_position_ws, &.ck-menu-bar__menu__panel_position_sw { - border-top-right-radius: 0; + border-radius: var(--ck-menu-bar-panel-uniform-border-radius, var(--ck-border-radius-surface-cut-top-right)); } &.ck-menu-bar__menu__panel_position_en, &.ck-menu-bar__menu__panel_position_ne { - border-bottom-left-radius: 0; + border-radius: var(--ck-menu-bar-panel-uniform-border-radius, var(--ck-border-radius-surface-cut-bottom-left)); } &.ck-menu-bar__menu__panel_position_wn, &.ck-menu-bar__menu__panel_position_nw { - border-bottom-right-radius: 0; + border-radius: var(--ck-menu-bar-panel-uniform-border-radius, var(--ck-border-radius-surface-cut-bottom-right)); } &:focus { @@ -69,7 +76,7 @@ &.ck-menu-bar__menu__panel_position_es, &.ck-menu-bar__menu__panel_position_en { - left: calc( 100% - var(--ck-menu-bar-nested-menu-horizontal-offset) ); + left: calc( 100% - var(--ck-menu-bar-nested-menu-horizontal-offset, 5px) ); } &.ck-menu-bar__menu__panel_position_es { @@ -82,7 +89,7 @@ &.ck-menu-bar__menu__panel_position_ws, &.ck-menu-bar__menu__panel_position_wn { - right: calc( 100% - var(--ck-menu-bar-nested-menu-horizontal-offset) ); + right: calc( 100% - var(--ck-menu-bar-nested-menu-horizontal-offset, 5px) ); } &.ck-menu-bar__menu__panel_position_ws { @@ -108,11 +115,11 @@ &:active { /* Fix truncated shadows due to rendering order. */ position: relative; - z-index: 2; + z-index: var(--ck-layer-control-raised); outline: none; - border: var(--ck-focus-ring); - box-shadow: var(--ck-focus-outer-shadow), 0 0; + border-color: var(--ck-menu-bar-item-focus-border-color); + box-shadow: var(--ck-interactive-focus-shadow), 0 0; } } } diff --git a/packages/ckeditor5-ui/theme/components/panel/balloonpanel.css b/packages/ckeditor5-ui/theme/components/panel/balloonpanel.css index 9857014f424..7881a498f02 100644 --- a/packages/ckeditor5-ui/theme/components/panel/balloonpanel.css +++ b/packages/ckeditor5-ui/theme/components/panel/balloonpanel.css @@ -4,31 +4,42 @@ */ :root { - --ck-balloon-border-width: 1px; - --ck-balloon-arrow-offset: 2px; - --ck-balloon-arrow-height: 10px; + /* Radius */ + --ck-balloon-panel-border-radius: var(--ck-border-radius-surface); + + /* Border */ + --ck-balloon-panel-border: var(--ck-border-width-surface) solid var(--ck-balloon-panel-border-color); + + /* Color */ + --ck-balloon-panel-background-color: var(--ck-color-surface-container); + --ck-balloon-panel-border-color: var(--ck-color-border-container); + + /* State / meta */ + --ck-balloon-panel-arrow-display: block; + + /* Backward compatibility: these tokens were removed but may be overridden by consumers. */ --ck-balloon-arrow-half-width: 8px; - --ck-balloon-arrow-drop-shadow: 0 2px 2px var(--ck-color-shadow-drop); - /* Make sure the balloon arrow does not float over its children. */ - --ck-balloon-panel-arrow-z-index: calc(var(--ck-z-default) - 3); + --ck-balloon-arrow-height: 10px; + --ck-balloon-arrow-offset: 2px; } .ck.ck-balloon-panel { - border-radius: var(--ck-rounded-corners-radius); - box-shadow: var(--ck-drop-shadow), 0 0; + border-radius: var(--ck-balloon-panel-border-radius); + box-shadow: var(--ck-shadow-surface-floating), 0 0; min-height: 15px; - background: var(--ck-color-panel-background); - border: var(--ck-balloon-border-width) solid var(--ck-color-panel-border); + background: var(--ck-balloon-panel-background-color); + border: var(--ck-balloon-panel-border); display: none; position: absolute; - z-index: var(--ck-z-panel); + z-index: var(--ck-layer-panel); &.ck-balloon-panel_with-arrow { &::before, &::after { + display: var(--ck-balloon-panel-arrow-display); width: 0; height: 0; border-style: solid; @@ -37,11 +48,12 @@ } &::before { - z-index: var(--ck-balloon-panel-arrow-z-index); + /* Backward compatibility: falls back to legacy --ck-balloon-panel-arrow-z-index if overridden. */ + z-index: var(--ck-balloon-panel-arrow-z-index, var(--ck-layer-balloon-arrow-back)); } &::after { - z-index: calc(var(--ck-balloon-panel-arrow-z-index) + 1); + z-index: var(--ck-layer-balloon-arrow-front); } } @@ -52,15 +64,15 @@ } &::before { - border-color: transparent transparent var(--ck-color-panel-border) transparent; - margin-top: calc( -1 * var(--ck-balloon-border-width) ); - z-index: var(--ck-balloon-panel-arrow-z-index); + border-color: transparent transparent var(--ck-balloon-panel-border-color) transparent; + margin-top: calc( -1 * var(--ck-border-width-surface) ); + z-index: var(--ck-layer-balloon-arrow-back); } &::after { - border-color: transparent transparent var(--ck-color-panel-background) transparent; - margin-top: calc( var(--ck-balloon-arrow-offset) - var(--ck-balloon-border-width) ); - z-index: calc(var(--ck-balloon-panel-arrow-z-index) + 1); + border-color: transparent transparent var(--ck-balloon-panel-background-color) transparent; + margin-top: calc( var(--ck-balloon-arrow-offset) - var(--ck-border-width-surface) ); + z-index: var(--ck-layer-balloon-arrow-front); } } @@ -71,16 +83,17 @@ } &::before { - border-color: var(--ck-color-panel-border) transparent transparent; - filter: drop-shadow(var(--ck-balloon-arrow-drop-shadow)); - margin-bottom: calc( -1 * var(--ck-balloon-border-width) ); - z-index: var(--ck-balloon-panel-arrow-z-index); + border-color: var(--ck-balloon-panel-border-color) transparent transparent; + /* Backward compatibility: falls back to legacy --ck-balloon-arrow-drop-shadow if overridden. */ + filter: drop-shadow(var(--ck-balloon-arrow-drop-shadow, 0 2px 2px var(--ck-color-shadow-drop))); + margin-bottom: calc( -1 * var(--ck-border-width-surface) ); + z-index: var(--ck-layer-balloon-arrow-back); } &::after { - border-color: var(--ck-color-panel-background) transparent transparent transparent; - margin-bottom: calc( var(--ck-balloon-arrow-offset) - var(--ck-balloon-border-width) ); - z-index: calc(var(--ck-balloon-panel-arrow-z-index) + 1); + border-color: var(--ck-balloon-panel-background-color) transparent transparent transparent; + margin-bottom: calc( var(--ck-balloon-arrow-offset) - var(--ck-border-width-surface) ); + z-index: var(--ck-layer-balloon-arrow-front); } } @@ -91,13 +104,13 @@ } &::before { - border-color: transparent transparent transparent var(--ck-color-panel-border); - margin-right: calc( -1 * var(--ck-balloon-border-width) ); + border-color: transparent transparent transparent var(--ck-balloon-panel-border-color); + margin-right: calc( -1 * var(--ck-border-width-surface) ); } &::after { - border-color: transparent transparent transparent var(--ck-color-panel-background); - margin-right: calc( var(--ck-balloon-arrow-offset) - var(--ck-balloon-border-width) ); + border-color: transparent transparent transparent var(--ck-balloon-panel-background-color); + margin-right: calc( var(--ck-balloon-arrow-offset) - var(--ck-border-width-surface) ); } } @@ -108,13 +121,13 @@ } &::before { - border-color: transparent var(--ck-color-panel-border) transparent transparent; - margin-left: calc( -1 * var(--ck-balloon-border-width) ); + border-color: transparent var(--ck-balloon-panel-border-color) transparent transparent; + margin-left: calc( -1 * var(--ck-border-width-surface) ); } &::after { - border-color: transparent var(--ck-color-panel-background) transparent transparent; - margin-left: calc( var(--ck-balloon-arrow-offset) - var(--ck-balloon-border-width) ); + border-color: transparent var(--ck-balloon-panel-background-color) transparent transparent; + margin-left: calc( var(--ck-balloon-arrow-offset) - var(--ck-border-width-surface) ); } } diff --git a/packages/ckeditor5-ui/theme/components/panel/balloonrotator.css b/packages/ckeditor5-ui/theme/components/panel/balloonrotator.css index c3cc9ebcd0c..afd4ce79a10 100644 --- a/packages/ckeditor5-ui/theme/components/panel/balloonrotator.css +++ b/packages/ckeditor5-ui/theme/components/panel/balloonrotator.css @@ -4,25 +4,25 @@ */ .ck .ck-balloon-rotator__navigation { - background: var(--ck-color-toolbar-background); - border-bottom: 1px solid var(--ck-color-toolbar-border); - padding: 0 var(--ck-spacing-small); + background: var(--ck-toolbar-background-color); + border-bottom: var(--ck-border-width-divider) solid var(--ck-toolbar-border-color); + padding: 0 var(--ck-spacing-surface-padding-inline); display: flex; align-items: center; /* Let's keep similar appearance to `ck-toolbar`. */ & > * { - margin-right: var(--ck-spacing-small); - margin-top: var(--ck-spacing-small); - margin-bottom: var(--ck-spacing-small); + margin-right: var(--ck-spacing-surface-item-gap-inline); + margin-top: var(--ck-spacing-surface-item-gap-block); + margin-bottom: var(--ck-spacing-surface-item-gap-block); } /* Gives counter more breath than buttons. */ & .ck-balloon-rotator__counter { - margin-right: var(--ck-spacing-standard); + margin-right: var(--ck-spacing-control-padding-inline); /* We need to use smaller margin because of previous button's right margin. */ - margin-left: var(--ck-spacing-small); + margin-left: var(--ck-spacing-surface-item-gap-inline); } justify-content: center } diff --git a/packages/ckeditor5-ui/theme/components/panel/fakepanel.css b/packages/ckeditor5-ui/theme/components/panel/fakepanel.css index 8380b24083e..109d3395dd0 100644 --- a/packages/ckeditor5-ui/theme/components/panel/fakepanel.css +++ b/packages/ckeditor5-ui/theme/components/panel/fakepanel.css @@ -4,21 +4,16 @@ */ -:root { - --ck-balloon-fake-panel-offset-horizontal: 6px; - --ck-balloon-fake-panel-offset-vertical: 6px; -} - /* Let's use `.ck-balloon-panel` appearance. See: balloonpanel.css. */ .ck .ck-fake-panel div { - box-shadow: var(--ck-drop-shadow), 0 0; + box-shadow: var(--ck-shadow-surface-floating), 0 0; min-height: 15px; - background: var(--ck-color-panel-background); - border: 1px solid var(--ck-color-panel-border); - border-radius: var(--ck-border-radius); + background: var(--ck-balloon-panel-background-color); + border: var(--ck-balloon-panel-border); + border-radius: var(--ck-border-radius-surface); width: 100%; height: 100%; @@ -26,33 +21,44 @@ } .ck .ck-fake-panel div:nth-child( 1 ) { - margin-left: var(--ck-balloon-fake-panel-offset-horizontal); - margin-top: var(--ck-balloon-fake-panel-offset-vertical); + /* Backward compatibility: falls back to legacy --ck-balloon-fake-panel-offset-* if overridden. */ + margin-left: var(--ck-balloon-fake-panel-offset-horizontal, 6px); + margin-top: var(--ck-balloon-fake-panel-offset-vertical, 6px); z-index: 2; } .ck .ck-fake-panel div:nth-child( 2 ) { - margin-left: calc(var(--ck-balloon-fake-panel-offset-horizontal) * 2); - margin-top: calc(var(--ck-balloon-fake-panel-offset-vertical) * 2); + margin-left: calc(2 * var(--ck-balloon-fake-panel-offset-horizontal, 6px)); + margin-top: calc(2 * var(--ck-balloon-fake-panel-offset-vertical, 6px)); z-index: 1; } .ck .ck-fake-panel div:nth-child( 3 ) { - margin-left: calc(var(--ck-balloon-fake-panel-offset-horizontal) * 3); - margin-top: calc(var(--ck-balloon-fake-panel-offset-vertical) * 3); + margin-left: calc(3 * var(--ck-balloon-fake-panel-offset-horizontal, 6px)); + margin-top: calc(3 * var(--ck-balloon-fake-panel-offset-vertical, 6px)); } .ck .ck-fake-panel { position: absolute; /* Fake panels should be placed under main balloon content. */ - z-index: calc(var(--ck-z-panel) - 1); + z-index: var(--ck-layer-panel-below); } /* If balloon is positioned above element, we need to move fake panel to the top. */ -.ck .ck-balloon-panel_arrow_s + .ck-fake-panel, -.ck .ck-balloon-panel_arrow_se + .ck-fake-panel, -.ck .ck-balloon-panel_arrow_sw + .ck-fake-panel { - --ck-balloon-fake-panel-offset-vertical: -6px; +.ck .ck-balloon-panel_arrow_s + .ck-fake-panel div, +.ck .ck-balloon-panel_arrow_se + .ck-fake-panel div, +.ck .ck-balloon-panel_arrow_sw + .ck-fake-panel div { + &:nth-child( 1 ) { + margin-top: calc(-1 * var(--ck-balloon-fake-panel-offset-vertical, 6px)); + } + + &:nth-child( 2 ) { + margin-top: calc(-2 * var(--ck-balloon-fake-panel-offset-vertical, 6px)); + } + + &:nth-child( 3 ) { + margin-top: calc(-3 * var(--ck-balloon-fake-panel-offset-vertical, 6px)); + } } diff --git a/packages/ckeditor5-ui/theme/components/panel/stickypanel.css b/packages/ckeditor5-ui/theme/components/panel/stickypanel.css index 4178f9d49ac..fde7c880840 100644 --- a/packages/ckeditor5-ui/theme/components/panel/stickypanel.css +++ b/packages/ckeditor5-ui/theme/components/panel/stickypanel.css @@ -4,14 +4,18 @@ */ +:root { + /* Set to a radius value (e.g. var(--ck-radius-base)) to disable attached-corner behavior and use uniform corners. */ + --ck-sticky-panel-uniform-border-radius: var(--ck-border-radius-uniform); +} + .ck.ck-sticky-panel { & .ck-sticky-panel__content_sticky { - box-shadow: var(--ck-drop-shadow), 0 0; + box-shadow: var(--ck-shadow-surface-floating), 0 0; - border-width: 0 1px 1px; - border-top-left-radius: 0; - border-top-right-radius: 0; - z-index: var(--ck-z-panel); /* #315 */ + border-width: 0 var(--ck-border-width-surface) var(--ck-border-width-surface); + border-radius: var(--ck-sticky-panel-uniform-border-radius, var(--ck-border-radius-surface-attached-top)); + z-index: var(--ck-layer-panel); /* #315 */ position: fixed; top: 0; } diff --git a/packages/ckeditor5-ui/theme/components/responsive-form/responsiveform.css b/packages/ckeditor5-ui/theme/components/responsive-form/responsiveform.css index b12b8f81114..0c76504888a 100644 --- a/packages/ckeditor5-ui/theme/components/responsive-form/responsiveform.css +++ b/packages/ckeditor5-ui/theme/components/responsive-form/responsiveform.css @@ -3,9 +3,16 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + /* Spacing */ + --ck-responsive-form-padding: var(--ck-spacing-region-edge-margin-block); + + /* Border */ + --ck-responsive-form-divider-border: var(--ck-border-divider); +} .ck.ck-responsive-form { - padding: var(--ck-spacing-large); + padding: var(--ck-responsive-form-padding); &:focus { /* See: https://github.com/ckeditor/ckeditor5/issues/4773 */ @@ -14,13 +21,13 @@ [dir="ltr"] & { & > :not(:first-child) { - margin-left: var(--ck-spacing-standard); + margin-left: var(--ck-spacing-region-padding-inline); } } [dir="rtl"] & { & > :not(:last-child) { - margin-left: var(--ck-spacing-standard); + margin-left: var(--ck-spacing-region-padding-inline); } } @@ -29,7 +36,7 @@ width: calc(.8 * var(--ck-input-width)); & .ck-labeled-field-view { - margin: var(--ck-spacing-large) var(--ck-spacing-large) 0; + margin: var(--ck-spacing-region-edge-margin-block) var(--ck-spacing-region-edge-margin-block) 0; & .ck-input-text, & .ck-input-number { @@ -45,12 +52,12 @@ & > .ck-button:nth-last-child(1), & > .ck-button:nth-last-child(2) { - padding: var(--ck-spacing-standard); - margin-top: var(--ck-spacing-large); + padding: var(--ck-spacing-control-padding-inline); + margin-top: var(--ck-spacing-region-edge-margin-block); border-radius: 0; &:not(:focus) { - border-top: 1px solid var(--ck-color-base-border); + border-top: var(--ck-responsive-form-divider-border); } [dir="ltr"] & { @@ -61,7 +68,7 @@ margin-left: 0; &:last-of-type { - border-right: 1px solid var(--ck-color-base-border); + border-right: var(--ck-responsive-form-divider-border); } } } @@ -70,14 +77,14 @@ content: ""; width: 0; position: absolute; - right: -1px; - top: -1px; - bottom: -1px; + right: calc(-1 * var(--ck-border-width-divider)); + top: calc(-1 * var(--ck-border-width-divider)); + bottom: calc(-1 * var(--ck-border-width-divider)); z-index: 1; } &:nth-last-child(2)::after { - border-right: 1px solid var(--ck-color-base-border); + border-right: var(--ck-responsive-form-divider-border); } &:focus::after { @@ -88,7 +95,7 @@ } .ck-vertical-form > .ck-button:nth-last-child(2)::after { - border-right: 1px solid var(--ck-color-base-border); + border-right: var(--ck-responsive-form-divider-border); } .ck-vertical-form .ck-button { @@ -96,9 +103,9 @@ content: ""; width: 0; position: absolute; - right: -1px; - top: -1px; - bottom: -1px; + right: calc(-1 * var(--ck-border-width-divider)); + top: calc(-1 * var(--ck-border-width-divider)); + bottom: calc(-1 * var(--ck-border-width-divider)); z-index: 1; } diff --git a/packages/ckeditor5-ui/theme/components/search/search.css b/packages/ckeditor5-ui/theme/components/search/search.css index 5c4367242fd..576189a5419 100644 --- a/packages/ckeditor5-ui/theme/components/search/search.css +++ b/packages/ckeditor5-ui/theme/components/search/search.css @@ -5,7 +5,8 @@ :root { - --ck-search-field-view-horizontal-spacing: calc(var(--ck-icon-size) + var(--ck-spacing-medium)); + /* Spacing */ + --ck-search-results-info-padding: var(--ck-spacing-surface-section-gap-block) var(--ck-spacing-control-meta-gap); } .ck.ck-search { @@ -20,11 +21,11 @@ transform: translateY(-50%); [dir="ltr"] & { - left: var(--ck-spacing-medium); + left: var(--ck-spacing-control-icon-gap); } [dir="rtl"] & { - right: var(--ck-spacing-medium); + right: var(--ck-spacing-control-icon-gap); } } @@ -35,7 +36,8 @@ } &.ck-search__query_with-icon { - --ck-labeled-field-label-default-position-x: var(--ck-search-field-view-horizontal-spacing); + /* Backward compatibility: falls back to legacy --ck-spacing-medium if overridden. */ + --ck-labeled-field-label-default-position-x: var(--ck-search-field-view-horizontal-spacing, calc(var(--ck-icon-size) + var(--ck-spacing-medium, var(--ck-spacing-md)))); & > .ck-labeled-field-view__input-wrapper > .ck-icon { opacity: .5; @@ -46,22 +48,26 @@ width: 100%; [dir="ltr"] & { - padding-left: var(--ck-search-field-view-horizontal-spacing); + /* Backward compatibility: falls back to legacy --ck-spacing-medium if overridden. */ + padding-left: var(--ck-search-field-view-horizontal-spacing, calc(var(--ck-icon-size) + var(--ck-spacing-medium, var(--ck-spacing-md)))); } [dir="rtl"] & { &:not(.ck-input-text_empty) { - padding-left: var(--ck-search-field-view-horizontal-spacing); + /* Backward compatibility: falls back to legacy --ck-spacing-medium if overridden. */ + padding-left: var(--ck-search-field-view-horizontal-spacing, calc(var(--ck-icon-size) + var(--ck-spacing-medium, var(--ck-spacing-md)))); } } } } &.ck-search__query_with-reset { - --ck-labeled-field-empty-unfocused-max-width: 100% - 2 * var(--ck-search-field-view-horizontal-spacing); + /* Backward compatibility: falls back to legacy --ck-spacing-medium if overridden. */ + --ck-labeled-field-empty-unfocused-max-width: 100% - 2 * var(--ck-search-field-view-horizontal-spacing, calc(var(--ck-icon-size) + var(--ck-spacing-medium, var(--ck-spacing-md)))); &.ck-labeled-field-view_empty { - --ck-labeled-field-empty-unfocused-max-width: 100% - var(--ck-search-field-view-horizontal-spacing) - var(--ck-spacing-medium); + /* Backward compatibility: falls back to legacy --ck-spacing-medium if overridden. */ + --ck-labeled-field-empty-unfocused-max-width: 100% - var(--ck-search-field-view-horizontal-spacing, calc(var(--ck-icon-size) + var(--ck-spacing-medium, var(--ck-spacing-md)))) - var(--ck-spacing-control-icon-gap); } & .ck-search__reset { @@ -73,11 +79,11 @@ padding: 0; [dir="ltr"] & { - right: var(--ck-spacing-medium); + right: var(--ck-spacing-control-icon-gap); } [dir="rtl"] & { - left: var(--ck-spacing-medium); + left: var(--ck-spacing-control-icon-gap); } &:hover { @@ -91,13 +97,15 @@ [dir="ltr"] & { &:not(.ck-input-text_empty) { - padding-right: var(--ck-search-field-view-horizontal-spacing); + /* Backward compatibility: falls back to legacy --ck-spacing-medium if overridden. */ + padding-right: var(--ck-search-field-view-horizontal-spacing, calc(var(--ck-icon-size) + var(--ck-spacing-medium, var(--ck-spacing-md)))); } } /* stylelint-disable-next-line no-descending-specificity */ [dir="rtl"] & { - padding-right: var(--ck-search-field-view-horizontal-spacing); + /* Backward compatibility: falls back to legacy --ck-spacing-medium if overridden. */ + padding-right: var(--ck-search-field-view-horizontal-spacing, calc(var(--ck-icon-size) + var(--ck-spacing-medium, var(--ck-spacing-md)))); } } } @@ -108,19 +116,19 @@ & > .ck-search__info { width: 100%; - padding: var(--ck-spacing-medium) var(--ck-spacing-large); + padding: var(--ck-search-results-info-padding); & * { white-space: normal; } & > span:first-child { - font-weight: bold; + font-weight: var(--ck-font-weight-ui-heading); display: block; } & > span:last-child { - margin-top: var(--ck-spacing-medium); + margin-top: var(--ck-spacing-surface-section-gap-block); } /* Hide the filtered view when nothing was found */ diff --git a/packages/ckeditor5-ui/theme/components/spinner/spinner.css b/packages/ckeditor5-ui/theme/components/spinner/spinner.css index 451c4c46c37..427ca4d0c6e 100644 --- a/packages/ckeditor5-ui/theme/components/spinner/spinner.css +++ b/packages/ckeditor5-ui/theme/components/spinner/spinner.css @@ -4,13 +4,14 @@ */ :root { + /* Size */ --ck-toolbar-spinner-size: 18px; } .ck.ck-spinner-container { width: var(--ck-toolbar-spinner-size); height: var(--ck-toolbar-spinner-size); - animation: 1.5s infinite ck-spinner-rotate linear; + animation: var(--ck-animation-duration-progress) var(--ck-animation-repeat-infinite) ck-spinner-rotate var(--ck-animation-timing-function-progress); display: block; @media (prefers-reduced-motion: reduce) { @@ -22,8 +23,8 @@ .ck.ck-spinner { width: var(--ck-toolbar-spinner-size); height: var(--ck-toolbar-spinner-size); - border-radius: 50%; - border: 2px solid var(--ck-color-text); + border-radius: var(--ck-radius-full); + border: var(--ck-border-width-emphasis) solid var(--ck-color-text); border-top-color: transparent; position: absolute; top: 50%; diff --git a/packages/ckeditor5-ui/theme/components/toolbar/blocktoolbar.css b/packages/ckeditor5-ui/theme/components/toolbar/blocktoolbar.css index 0ee3e9f9153..59bbbbf61c4 100644 --- a/packages/ckeditor5-ui/theme/components/toolbar/blocktoolbar.css +++ b/packages/ckeditor5-ui/theme/components/toolbar/blocktoolbar.css @@ -4,13 +4,17 @@ */ :root { - --ck-color-block-toolbar-button: var(--ck-color-text); - --ck-block-toolbar-button-size: var(--ck-font-size-normal); + /* Size */ + /* Backward compatibility: falls back to legacy --ck-font-size-normal if overridden. */ + --ck-block-toolbar-button-size: var(--ck-font-size-normal, var(--ck-font-size-md)); } .ck.ck-block-toolbar-button { - color: var(--ck-color-block-toolbar-button); - font-size: var(--ck-block-toolbar-size); + /* Fallback to `--ck-color-block-toolbar-button` for backward compatibility. */ + color: var(--ck-color-block-toolbar-button, var(--ck-color-text)); + /* Fallback to `--ck-block-toolbar-size` for backward compatibility. */ + font-size: var(--ck-block-toolbar-size, var(--ck-block-toolbar-button-size)); position: absolute; - z-index: var(--ck-z-default); + /* Backward compatibility: falls back to legacy --ck-z-default if overridden. */ + z-index: var(--ck-z-default, var(--ck-z-base)); } diff --git a/packages/ckeditor5-ui/theme/components/toolbar/toolbar.css b/packages/ckeditor5-ui/theme/components/toolbar/toolbar.css index 096e5b8e321..494050b2624 100644 --- a/packages/ckeditor5-ui/theme/components/toolbar/toolbar.css +++ b/packages/ckeditor5-ui/theme/components/toolbar/toolbar.css @@ -3,11 +3,30 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + /* Spacing */ + --ck-toolbar-item-gap-inline: var(--ck-spacing-surface-item-gap-inline); + --ck-toolbar-padding: 0 var(--ck-spacing-surface-padding-inline); + + /* Radius */ + /* Set to a radius value (e.g. var(--ck-radius-base)) to disable attached-corner behavior and use uniform corners. */ + --ck-toolbar-compact-uniform-border-radius: var(--ck-border-radius-uniform); + --ck-toolbar-border-radius: var(--ck-border-radius-surface); + --ck-toolbar-vertical-button-border-radius: 0; + + /* Color */ + --ck-toolbar-background-color: var(--ck-color-surface-container); + --ck-toolbar-border-color: var(--ck-color-border-container); + + /* Border */ + --ck-toolbar-border: var(--ck-border-width-surface) solid var(--ck-toolbar-border-color); +} + .ck.ck-toolbar { - border-radius: var(--ck-rounded-corners-radius); - background: var(--ck-color-toolbar-background); - padding: 0 var(--ck-spacing-small); - border: 1px solid var(--ck-color-toolbar-border); + border-radius: var(--ck-toolbar-border-radius); + background: var(--ck-toolbar-background-color); + padding: var(--ck-toolbar-padding); + border: var(--ck-toolbar-border); -webkit-user-select: none; user-select: none; @@ -19,14 +38,14 @@ height: var(--ck-icon-size); width: 1px; min-width: 1px; - background: var(--ck-color-toolbar-border); + background: var(--ck-toolbar-border-color); /* * These margins make the separators look better in balloon toolbars (when aligned with the "tip"). * See https://github.com/ckeditor/ckeditor5/issues/7493. */ - margin-top: var(--ck-spacing-small); - margin-bottom: var(--ck-spacing-small); + margin-top: var(--ck-spacing-surface-item-gap-block); + margin-bottom: var(--ck-spacing-surface-item-gap-block); display: inline-block; /* @@ -48,7 +67,7 @@ & > .ck-toolbar__items { & > *:not(.ck-toolbar__line-break) { /* (#11) Separate toolbar items. */ - margin-right: var(--ck-spacing-small); + margin-right: var(--ck-toolbar-item-gap-inline); } /* Don't display a separator after an empty items container, for instance, @@ -65,8 +84,8 @@ & > .ck-toolbar__items > *:not(.ck-toolbar__line-break), & > .ck.ck-toolbar__grouped-dropdown { /* Make sure items wrapped to the next line have v-spacing */ - margin-top: var(--ck-spacing-small); - margin-bottom: var(--ck-spacing-small); + margin-top: var(--ck-spacing-surface-item-gap-block); + margin-bottom: var(--ck-spacing-surface-item-gap-block); } &.ck-toolbar_vertical { @@ -82,7 +101,7 @@ margin: 0; /* Items in a vertical toolbar span the entire width so rounded corners are pointless. */ - border-radius: 0; + border-radius: var(--ck-toolbar-vertical-button-border-radius); } } @@ -107,7 +126,7 @@ * This button has no arrow so let's revert that padding back to normal. */ & > .ck.ck-button.ck-dropdown__button { - padding-left: var(--ck-spacing-tiny); + padding-left: var(--ck-spacing-control-padding-inline-start-compact); } & > .ck-dropdown__button .ck-dropdown__arrow { display: none; @@ -165,7 +184,7 @@ &:not(.ck-toolbar_compact) > .ck-toolbar__items > .ck { /* (#11) Separate toolbar items. */ - margin-left: var(--ck-spacing-small); + margin-left: var(--ck-toolbar-item-gap-inline); } & > .ck-toolbar__items > .ck:last-child { @@ -175,25 +194,23 @@ &.ck-toolbar_compact > .ck-toolbar__items > .ck { /* No rounded corners on the right side of the first child. */ &:first-child { - border-top-left-radius: 0; - border-bottom-left-radius: 0; + border-radius: var(--ck-toolbar-compact-uniform-border-radius, var(--ck-border-radius-surface-cut-top-right)); } /* No rounded corners on the left side of the last child. */ &:last-child { - border-top-right-radius: 0; - border-bottom-right-radius: 0; + border-radius: var(--ck-toolbar-compact-uniform-border-radius, var(--ck-border-radius-surface-cut-top-left)); } } /* Separate the the separator form the grouping dropdown when some items are grouped. */ & > .ck.ck-toolbar__separator { - margin-left: var(--ck-spacing-small); + margin-left: var(--ck-spacing-surface-item-gap-inline); } /* Some spacing between the items and the separator before the grouped items dropdown. */ &.ck-toolbar_grouping > .ck-toolbar__items:not(:empty):not(:only-child) { - margin-left: var(--ck-spacing-small); + margin-left: var(--ck-spacing-surface-item-gap-inline); } } @@ -213,25 +230,23 @@ &.ck-toolbar_compact > .ck-toolbar__items > .ck { /* No rounded corners on the right side of the first child. */ &:first-child { - border-top-right-radius: 0; - border-bottom-right-radius: 0; + border-radius: var(--ck-toolbar-compact-uniform-border-radius, var(--ck-border-radius-surface-cut-top-left)); } /* No rounded corners on the left side of the last child. */ &:last-child { - border-top-left-radius: 0; - border-bottom-left-radius: 0; + border-radius: var(--ck-toolbar-compact-uniform-border-radius, var(--ck-border-radius-surface-cut-top-right)); } } /* Separate the the separator form the grouping dropdown when some items are grouped. */ & > .ck.ck-toolbar__separator { - margin-right: var(--ck-spacing-small); + margin-right: var(--ck-toolbar-item-gap-inline); } /* Some spacing between the items and the separator before the grouped items dropdown. */ &.ck-toolbar_grouping > .ck-toolbar__items:not(:empty):not(:only-child) { - margin-right: var(--ck-spacing-small); + margin-right: var(--ck-spacing-surface-item-gap-inline); } } diff --git a/packages/ckeditor5-ui/theme/components/tooltip/tooltip.css b/packages/ckeditor5-ui/theme/components/tooltip/tooltip.css index f4014485be9..6ab46f4a732 100644 --- a/packages/ckeditor5-ui/theme/components/tooltip/tooltip.css +++ b/packages/ckeditor5-ui/theme/components/tooltip/tooltip.css @@ -4,15 +4,31 @@ */ +:root { + /* Size */ + --ck-tooltip-max-width: 200px; + + /* Spacing */ + --ck-tooltip-padding: 0 var(--ck-spacing-control-icon-gap); + + /* Border */ + --ck-tooltip-border: 0px solid transparent; + + /* Color */ + --ck-tooltip-background-color: var(--ck-color-surface-inverse); + --ck-tooltip-text-color: var(--ck-color-text-inverse); + + /* Typography */ + --ck-tooltip-text-font-size: .9em; +} + .ck.ck-balloon-panel.ck-tooltip { - --ck-balloon-border-width: 0px; - --ck-balloon-arrow-offset: 0px; - --ck-balloon-arrow-half-width: 4px; - --ck-balloon-arrow-height: 4px; - --ck-tooltip-text-padding: 4px; - --ck-color-panel-background: var(--ck-color-tooltip-background); + --ck-balloon-panel-border: var(--ck-tooltip-border); + --ck-balloon-panel-background-color: var(--ck-tooltip-background-color); - padding: 0 var(--ck-spacing-medium); + padding: var(--ck-tooltip-padding); + + z-index: var(--ck-layer-tooltip); /* Reset balloon panel styles */ box-shadow: none; @@ -20,22 +36,20 @@ user-select: none; & .ck-tooltip__text { - font-size: .9em; + font-size: var(--ck-tooltip-text-font-size); line-height: 1.5; - color: var(--ck-color-tooltip-text); + color: var(--ck-tooltip-text-color); } &.ck-tooltip_multi-line .ck-tooltip__text { white-space: break-spaces; display: inline-block; - padding: var(--ck-tooltip-text-padding) 0; - max-width: 200px; + padding: 4px 0; + max-width: var(--ck-tooltip-max-width); } /* Hide the default shadow of the .ck-balloon-panel tip */ &::before { display: none; } - - z-index: calc( var(--ck-z-dialog) + 100 ) } diff --git a/packages/ckeditor5-ui/theme/globals/_border.css b/packages/ckeditor5-ui/theme/globals/_border.css new file mode 100644 index 00000000000..44b83d9ccd1 --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/_border.css @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + --ck-border-width-thin: 1px; + --ck-border-width-thick: 2px; +} diff --git a/packages/ckeditor5-ui/theme/globals/_colors.css b/packages/ckeditor5-ui/theme/globals/_colors.css index e8d3feddecc..597793c1cd9 100644 --- a/packages/ckeditor5-ui/theme/globals/_colors.css +++ b/packages/ckeditor5-ui/theme/globals/_colors.css @@ -3,121 +3,10 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ -:root { - --ck-color-base-foreground: hsl(0, 0%, 98%); - --ck-color-base-background: hsl(0, 0%, 100%); - --ck-color-base-border: hsl(220, 6%, 81%); - --ck-color-base-action: hsl(104, 50.2%, 42.5%); - --ck-color-base-focus: hsl(209, 92%, 70%); - --ck-color-base-text: hsl(0, 0%, 20%); - --ck-color-base-active: hsl(218.1, 100%, 58%); - --ck-color-base-active-focus: hsl(218.2, 100%, 52.5%); - --ck-color-base-error: hsl(15, 100%, 43%); - - /* -- Generic colors ------------------------------------------------------------------------ */ - - --ck-color-focus-border-coordinates: 218, 81.8%, 56.9%; - --ck-color-focus-border: hsl(var(--ck-color-focus-border-coordinates)); - --ck-color-focus-outer-shadow: hsl(212.4, 89.3%, 89%); - --ck-color-focus-disabled-shadow: hsla(209, 90%, 72%,.3); - --ck-color-focus-error-shadow: hsla(9,100%,56%,.3); - --ck-color-text: var(--ck-color-base-text); - --ck-color-shadow-drop: hsla(0, 0%, 0%, 0.15); - --ck-color-shadow-drop-active: hsla(0, 0%, 0%, 0.2); - --ck-color-shadow-inner: hsla(0, 0%, 0%, 0.1); - - /* -- Buttons ------------------------------------------------------------------------------- */ - - --ck-color-button-default-background: transparent; - --ck-color-button-default-hover-background: hsl(0, 0%, 94.1%); - --ck-color-button-default-active-background: hsl(0, 0%, 94.1%); - --ck-color-button-default-disabled-background: transparent; - - --ck-color-button-on-background: hsl(212, 100%, 97.1%); - --ck-color-button-on-hover-background: hsl(211.7, 100%, 92.9%); - --ck-color-button-on-active-background: hsl(211.7, 100%, 92.9%); - --ck-color-button-on-disabled-background: hsl(211, 15%, 95%); - --ck-color-button-on-color: hsl(218.1, 100%, 58%); - - - --ck-color-button-action-background: var(--ck-color-base-action); - --ck-color-button-action-hover-background: hsl(104, 53.2%, 40.2%); - --ck-color-button-action-active-background: hsl(104, 53.2%, 40.2%); - --ck-color-button-action-disabled-background: hsl(104, 44%, 58%); - --ck-color-button-action-text: var(--ck-color-base-background); - - --ck-color-button-save: hsl(120, 100%, 27%); - --ck-color-button-cancel: hsl(15, 100%, 43%); - - --ck-color-switch-button-off-background: hsl(0, 0%, 57.6%); - --ck-color-switch-button-off-hover-background: hsl(0, 0%, 49%); - --ck-color-switch-button-on-background: var(--ck-color-button-action-background); - --ck-color-switch-button-on-hover-background: hsl(104, 53.2%, 40.2%); - --ck-color-switch-button-inner-background: var(--ck-color-base-background); - --ck-color-switch-button-inner-shadow: hsla(0, 0%, 0%, 0.1); - - /* -- Dropdown ------------------------------------------------------------------------------ */ - - --ck-color-dropdown-panel-background: var(--ck-color-base-background); - --ck-color-dropdown-panel-border: var(--ck-color-base-border); - - /* -- Dialog -------------------------------------------------------------------------------- */ - - --ck-color-dialog-background: var(--ck-custom-background); - --ck-color-dialog-form-header-border: var(--ck-custom-border); - - /* -- Input --------------------------------------------------------------------------------- */ - - --ck-color-input-background: var(--ck-color-base-background); - --ck-color-input-border: var(--ck-color-base-border); - --ck-color-input-error-border: var(--ck-color-base-error); - --ck-color-input-text: var(--ck-color-base-text); - --ck-color-input-disabled-background: hsl(0, 0%, 95%); - --ck-color-input-disabled-border: var(--ck-color-base-border); - --ck-color-input-disabled-text: hsl(0, 0%, 46%); - - /* -- List ---------------------------------------------------------------------------------- */ - - --ck-color-list-background: var(--ck-color-base-background); - --ck-color-list-button-hover-background: var(--ck-color-button-default-hover-background); - --ck-color-list-button-on-background: var(--ck-color-button-on-color); - --ck-color-list-button-on-background-focus: var(--ck-color-button-on-color); - --ck-color-list-button-on-text: var(--ck-color-base-background); - - /* -- Panel --------------------------------------------------------------------------------- */ - - --ck-color-panel-background: var(--ck-color-base-background); - --ck-color-panel-border: var(--ck-color-base-border); - - /* -- Toolbar ------------------------------------------------------------------------------- */ - - --ck-color-toolbar-background: var(--ck-color-base-background); - --ck-color-toolbar-border: var(--ck-color-base-border); - - /* -- Tooltip ------------------------------------------------------------------------------- */ - - --ck-color-tooltip-background: var(--ck-color-base-text); - --ck-color-tooltip-text: var(--ck-color-base-background); - - /* -- Engine -------------------------------------------------------------------------------- */ - - --ck-color-engine-placeholder-text: hsl(0, 0%, 44%); - - /* -- Upload -------------------------------------------------------------------------------- */ - - --ck-color-upload-bar-background: hsl(209, 92%, 70%); - - /* -- Link -------------------------------------------------------------------------------- */ - - --ck-color-link-default: hsl(240, 100%, 47%); - --ck-color-link-selected-background: hsla(201, 100%, 56%, 0.1); - --ck-color-link-fake-selection: hsla(201, 100%, 56%, 0.3); - - /* -- Search result highlight ---------------------------------------------------------------- */ - - --ck-color-highlight-background: hsl(60, 100%, 50%); - - /* -- Generic colors ------------------------------------------------------------------------- */ - - --ck-color-light-red: hsl(0, 100%, 90%); -} +@import "./colors/_foundation.css"; +@import "./colors/_semantic-surface.css"; +@import "./colors/_semantic-feedback.css"; +@import "./colors/_semantic-text.css"; +@import "./colors/_semantic-interactive.css"; +@import "./colors/_legacy-component-aliases.css"; +@import "./colors/_legacy-misc.css"; diff --git a/packages/ckeditor5-ui/theme/globals/_disabled.css b/packages/ckeditor5-ui/theme/globals/_disabled.css index 9815cb0dffd..3333aa23ec2 100644 --- a/packages/ckeditor5-ui/theme/globals/_disabled.css +++ b/packages/ckeditor5-ui/theme/globals/_disabled.css @@ -7,5 +7,5 @@ /** * An opacity value of disabled UI item. */ - --ck-disabled-opacity: .5; + --ck-opacity-disabled: .5; } diff --git a/packages/ckeditor5-ui/theme/globals/_evaluationbadge.css b/packages/ckeditor5-ui/theme/globals/_evaluationbadge.css index 678bffe9746..d2e081f8098 100644 --- a/packages/ckeditor5-ui/theme/globals/_evaluationbadge.css +++ b/packages/ckeditor5-ui/theme/globals/_evaluationbadge.css @@ -12,19 +12,24 @@ --ck-evaluation-badge-letter-spacing: calc(var(--ck-font-size-base) * -0.2 / 13); --ck-evaluation-badge-padding-vertical: 2px; --ck-evaluation-badge-padding-horizontal: 4px; + --ck-evaluation-badge-label-padding-inline: 2px; + --ck-evaluation-badge-label-padding: 0 var(--ck-evaluation-badge-label-padding-inline); + --ck-evaluation-badge-label-font-weight: var(--ck-font-weight-bold); --ck-evaluation-badge-text-color: hsl(0, 0%, 31%); - --ck-evaluation-badge-border-radius: var(--ck-border-radius); + /* Backward compatibility: falls back to legacy --ck-border-radius if overridden. */ + --ck-evaluation-badge-border-radius: var(--ck-border-radius, var(--ck-radius-base)); --ck-evaluation-badge-background: hsl(0, 0%, 100%); --ck-evaluation-badge-border-color: var(--ck-color-focus-border); } .ck.ck-balloon-panel.ck-evaluation-badge-balloon { - --ck-border-radius: var(--ck-evaluation-badge-border-radius); + border-radius: var(--ck-evaluation-badge-border-radius); box-shadow: none; background: var(--ck-evaluation-badge-background); min-height: unset; - z-index: calc( var(--ck-z-panel) - 1 ); + /* Backward compatibility: falls back to legacy --ck-z-panel if overridden. */ + z-index: calc( var(--ck-z-panel, var(--ck-z-overlay)) - 1 ); & .ck.ck-evaluation-badge { line-height: var(--ck-evaluation-badge-line-height); @@ -32,10 +37,10 @@ & .ck-evaluation-badge__label { display: block; - padding: 0 2px; + padding: var(--ck-evaluation-badge-label-padding); font-size: var(--ck-evaluation-badge-font-size); letter-spacing: var(--ck-evaluation-badge-letter-spacing); - font-weight: bold; + font-weight: var(--ck-evaluation-badge-label-font-weight); line-height: normal; text-transform: uppercase; color: var(--ck-evaluation-badge-text-color); @@ -51,4 +56,3 @@ border-color: var(--ck-evaluation-badge-border-color); } } - diff --git a/packages/ckeditor5-ui/theme/globals/_focus.css b/packages/ckeditor5-ui/theme/globals/_focus.css index cba44eb59d6..501e9523e44 100644 --- a/packages/ckeditor5-ui/theme/globals/_focus.css +++ b/packages/ckeditor5-ui/theme/globals/_focus.css @@ -5,27 +5,43 @@ :root { /** - * The geometry of the of focused element's outer shadow. + * The geometry of the focus shadow. */ - --ck-focus-outer-shadow-geometry: 0 0 0 3px; + --ck-focus-shadow-geometry: 0 0 0 3px; /** - * A visual style of focused element's outer shadow. + * A visual style of focused element's shadow. */ - --ck-focus-outer-shadow: var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-outer-shadow); + /* Backward compatibility: falls back to legacy --ck-focus-outer-shadow-geometry if overridden. */ + --ck-focus-shadow: var(--ck-focus-outer-shadow-geometry, var(--ck-focus-shadow-geometry)) var(--ck-color-focus-outer-shadow); /** - * A visual style of focused element's outer shadow (when disabled). + * A visual style of focused element's shadow (when disabled). */ - --ck-focus-disabled-outer-shadow: var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-disabled-shadow); + /* Backward compatibility: falls back to legacy --ck-focus-outer-shadow-geometry if overridden. */ + --ck-focus-shadow-disabled: var(--ck-focus-outer-shadow-geometry, var(--ck-focus-shadow-geometry)) var(--ck-color-focus-disabled-shadow); /** - * A visual style of focused element's outer shadow (when has errors). + * A visual style of focused element's shadow (when has errors). */ - --ck-focus-error-outer-shadow: var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-error-shadow); + /* Backward compatibility: falls back to legacy --ck-focus-outer-shadow-geometry if overridden. */ + --ck-focus-shadow-error: var(--ck-focus-outer-shadow-geometry, var(--ck-focus-shadow-geometry)) var(--ck-color-focus-error-shadow); /** * A visual style of focused element's border or outline. */ --ck-focus-ring: 1px solid var(--ck-color-focus-border); + + /** + * The border color applied to focused elements. + * Use this instead of --ck-focus-ring when the component has a customizable border-width, + * to avoid overriding the width on focus. + */ + --ck-focus-border-color: var(--ck-color-focus-border); + + /** + * Contrast outline for fake collapsed selections and carets. + * Used across link, widget, emoji, and bookmark packages. + */ + --ck-outline-fake-caret: solid 1px hsla(0, 0%, 100%, .5); } diff --git a/packages/ckeditor5-ui/theme/globals/_fonts.css b/packages/ckeditor5-ui/theme/globals/_fonts.css index b59583f4bde..90fd99f1992 100644 --- a/packages/ckeditor5-ui/theme/globals/_fonts.css +++ b/packages/ckeditor5-ui/theme/globals/_fonts.css @@ -6,11 +6,16 @@ :root { --ck-font-size-base: 13px; --ck-line-height-base: 1.84615; - --ck-font-face: Helvetica, Arial, Tahoma, Verdana, Sans-Serif; + --ck-font-family: Helvetica, Arial, Tahoma, Verdana, Sans-Serif; - --ck-font-size-tiny: 0.7em; - --ck-font-size-small: 0.75em; - --ck-font-size-normal: 1em; - --ck-font-size-big: 1.4em; - --ck-font-size-large: 1.8em; + --ck-font-size-xs: 0.7em; + --ck-font-size-sm: 0.75em; + --ck-font-size-md: 1em; + --ck-font-size-lg: 1.4em; + --ck-font-size-xl: 1.8em; + + --ck-font-weight-normal: 400; + --ck-font-weight-medium: 500; + --ck-font-weight-semibold: 600; + --ck-font-weight-bold: 700; } diff --git a/packages/ckeditor5-ui/theme/globals/_legacy-foundation-aliases.css b/packages/ckeditor5-ui/theme/globals/_legacy-foundation-aliases.css new file mode 100644 index 00000000000..01ffb808be9 --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/_legacy-foundation-aliases.css @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +/* + * Backward-compatible aliases for legacy foundation token names. + * These map old names to new names so that external themes and integrations + * continue to work without changes. + */ +:root { + /* Spacing */ + --ck-spacing-extra-tiny: var(--ck-spacing-2xs); + --ck-spacing-tiny: var(--ck-spacing-xs); + --ck-spacing-small: var(--ck-spacing-sm); + --ck-spacing-medium-small: var(--ck-spacing-ms); + --ck-spacing-medium: var(--ck-spacing-md); + --ck-spacing-standard: var(--ck-spacing-base); + --ck-spacing-large: var(--ck-spacing-lg); + --ck-spacing-extra-large: var(--ck-spacing-xl); + + /* Font size */ + --ck-font-size-tiny: var(--ck-font-size-xs); + --ck-font-size-small: var(--ck-font-size-sm); + --ck-font-size-normal: var(--ck-font-size-md); + --ck-font-size-big: var(--ck-font-size-lg); + --ck-font-size-large: var(--ck-font-size-xl); + + /* Font */ + --ck-font-face: var(--ck-font-family); + + /* Radius */ + --ck-border-radius: var(--ck-radius-base); + --ck-rounded-corners-radius: var(--ck-radius-corners); + + /* Shadow */ + --ck-drop-shadow: var(--ck-shadow-md); + --ck-drop-shadow-active: var(--ck-shadow-lg); + --ck-inner-shadow: var(--ck-inset-shadow-sm); + + /* Z-index */ + --ck-z-default: var(--ck-z-base); + --ck-z-panel: var(--ck-z-overlay); + --ck-z-dialog: var(--ck-z-modal); + + /* Focus */ + --ck-focus-outer-shadow-geometry: var(--ck-focus-shadow-geometry); + --ck-focus-outer-shadow: var(--ck-focus-shadow); + --ck-focus-disabled-outer-shadow: var(--ck-focus-shadow-disabled); + --ck-focus-error-outer-shadow: var(--ck-focus-shadow-error); + + /* Disabled */ + --ck-disabled-opacity: var(--ck-opacity-disabled); + + /* UI Size */ + --ck-ui-component-min-height: var(--ck-size-min-height); +} diff --git a/packages/ckeditor5-ui/theme/globals/_poweredby.css b/packages/ckeditor5-ui/theme/globals/_poweredby.css index a0565db9b44..d41d5c979ad 100644 --- a/packages/ckeditor5-ui/theme/globals/_poweredby.css +++ b/packages/ckeditor5-ui/theme/globals/_poweredby.css @@ -12,8 +12,12 @@ --ck-powered-by-letter-spacing: calc(var(--ck-font-size-base) * -0.2 / 13); --ck-powered-by-padding-vertical: 2px; --ck-powered-by-padding-horizontal: 4px; + --ck-powered-by-label-padding-inline-start: 2px; + --ck-powered-by-label-margin-inline-end: 4px; + --ck-powered-by-label-font-weight: var(--ck-font-weight-bold); --ck-powered-by-text-color: hsl(0, 0%, 31%); - --ck-powered-by-border-radius: var(--ck-border-radius); + /* Backward compatibility: falls back to legacy --ck-border-radius if overridden. */ + --ck-powered-by-border-radius: var(--ck-border-radius, var(--ck-radius-base)); --ck-powered-by-background: hsl(0, 0%, 100%); --ck-powered-by-border-color: var(--ck-color-focus-border); @@ -24,12 +28,13 @@ } .ck.ck-balloon-panel.ck-powered-by-balloon { - --ck-border-radius: var(--ck-powered-by-border-radius); + border-radius: var(--ck-powered-by-border-radius); box-shadow: none; background: var(--ck-powered-by-background); min-height: unset; - z-index: calc( var(--ck-z-panel) - 1 ); + /* Backward compatibility: falls back to legacy --ck-z-panel if overridden. */ + z-index: calc( var(--ck-z-panel, var(--ck-z-overlay)) - 1 ); & .ck.ck-powered-by { line-height: var(--ck-powered-by-line-height); @@ -47,10 +52,10 @@ & .ck-powered-by__label { font-size: var(--ck-powered-by-font-size); letter-spacing: var(--ck-powered-by-letter-spacing); - padding-left: 2px; + padding-left: var(--ck-powered-by-label-padding-inline-start); text-transform: uppercase; - font-weight: bold; - margin-right: 4px; + font-weight: var(--ck-powered-by-label-font-weight); + margin-right: var(--ck-powered-by-label-margin-inline-end); cursor: pointer; line-height: normal; color: var(--ck-powered-by-text-color); @@ -81,4 +86,3 @@ border-color: var(--ck-powered-by-border-color); } } - diff --git a/packages/ckeditor5-ui/theme/globals/_reset.css b/packages/ckeditor5-ui/theme/globals/_reset.css index b1579eaf250..9188988248c 100644 --- a/packages/ckeditor5-ui/theme/globals/_reset.css +++ b/packages/ckeditor5-ui/theme/globals/_reset.css @@ -8,7 +8,7 @@ is never smaller than a button with icon, additionally making sure that text-less buttons are perfect squares. The value is also shared by other components which should stay "in-line" with buttons. */ - --ck-ui-component-min-height: 2.3em; + --ck-size-min-height: 2.3em; } /** @@ -42,7 +42,8 @@ .ck-reset_all *:not(.ck-reset_all-excluded, .ck-reset_all-excluded *) { /* These are rule inherited by all children elements. */ border-collapse: collapse; - font: normal normal normal var(--ck-font-size-base)/var(--ck-line-height-base) var(--ck-font-face); + /* Backward compatibility: falls back to legacy --ck-font-face if overridden. */ + font: normal normal normal var(--ck-font-size-base)/var(--ck-line-height-base) var(--ck-font-face, var(--ck-font-family)); color: var(--ck-color-text); text-align: left; white-space: nowrap; diff --git a/packages/ckeditor5-ui/theme/globals/_rounded.css b/packages/ckeditor5-ui/theme/globals/_rounded.css index 81cd4cb6492..bd6e4b9f0d3 100644 --- a/packages/ckeditor5-ui/theme/globals/_rounded.css +++ b/packages/ckeditor5-ui/theme/globals/_rounded.css @@ -5,27 +5,34 @@ :root { + --ck-radius-xs: 1px; + --ck-radius-sm: 2px; /** * Default border-radius value. */ - --ck-border-radius: 2px; + --ck-radius-base: 2px; + --ck-radius-md: 4px; + --ck-radius-lg: 6px; + --ck-radius-xl: 8px; + --ck-radius-full: 50%; /** * `.ck-rounded-corners` is an opt-in switch class used on the UI root. - * By default, `--ck-rounded-corners-radius` is `0` (square corners). - * When the switch class is present, it maps to `--ck-border-radius`. + * By default, `--ck-radius-corners` is `0` (square corners). + * When the switch class is present, it maps to `--ck-radius-base`. * * Component usage: - * - Use `border-radius: var(--ck-rounded-corners-radius);` on elements that + * - Use `border-radius: var(--ck-radius-corners);` on elements that * should respect the global rounded-corners setting. - * - If a component needs a custom radius, override `--ck-border-radius` locally - * and keep using `--ck-rounded-corners-radius`. + * - If a component needs a custom radius, override `--ck-radius-base` locally + * and keep using `--ck-radius-corners`. * - For per-corner shapes, use the variable-based radius first and then override * specific corners with `0` (or another value). */ - --ck-rounded-corners-radius: 0; + --ck-radius-corners: 0; } .ck-rounded-corners { - --ck-rounded-corners-radius: var(--ck-border-radius); + /* Backward compatibility: falls back to legacy --ck-border-radius if overridden. */ + --ck-radius-corners: var(--ck-border-radius, var(--ck-radius-base)); } diff --git a/packages/ckeditor5-ui/theme/globals/_semantic-interactive.css b/packages/ckeditor5-ui/theme/globals/_semantic-interactive.css new file mode 100644 index 00000000000..cacadd3f506 --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/_semantic-interactive.css @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + /* Generic focus visuals for interactive controls and actions. */ + --ck-interactive-focus-ring: var(--ck-focus-ring); + --ck-interactive-focus-border-color: var(--ck-focus-border-color); + /* Backward compatibility: falls back to legacy --ck-focus-outer-shadow if overridden. */ + --ck-interactive-focus-shadow: var(--ck-focus-outer-shadow, var(--ck-focus-shadow)); + /* Backward compatibility: falls back to legacy --ck-focus-disabled-outer-shadow if overridden. */ + --ck-interactive-focus-disabled-shadow: var(--ck-focus-disabled-outer-shadow, var(--ck-focus-shadow-disabled)); + /* Backward compatibility: falls back to legacy --ck-focus-error-outer-shadow if overridden. */ + --ck-interactive-focus-error-shadow: var(--ck-focus-error-outer-shadow, var(--ck-focus-shadow-error)); +} diff --git a/packages/ckeditor5-ui/theme/globals/_semantic-layer.css b/packages/ckeditor5-ui/theme/globals/_semantic-layer.css new file mode 100644 index 00000000000..f79830fd4ae --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/_semantic-layer.css @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + /* Backward compatibility: falls back to legacy --ck-z-default if overridden. */ + --ck-layer-base: var(--ck-z-default, var(--ck-z-base)); + --ck-layer-control-raised: calc(var(--ck-layer-base) + 1); + + /* Backward compatibility: falls back to legacy --ck-z-panel if overridden. */ + --ck-layer-panel: var(--ck-z-panel, var(--ck-z-overlay)); + --ck-layer-panel-above: calc(var(--ck-layer-panel) + 1); + --ck-layer-panel-below: calc(var(--ck-layer-panel) - 1); + + /* Backward compatibility: falls back to legacy --ck-z-dialog if overridden. */ + --ck-layer-dialog: var(--ck-z-dialog, var(--ck-z-modal)); + --ck-layer-tooltip: calc(var(--ck-layer-dialog) + 100); + + --ck-layer-balloon-arrow-back: calc(var(--ck-layer-base) - 3); + --ck-layer-balloon-arrow-front: calc(var(--ck-layer-balloon-arrow-back) + 1); +} diff --git a/packages/ckeditor5-ui/theme/globals/_semantic-layout.css b/packages/ckeditor5-ui/theme/globals/_semantic-layout.css new file mode 100644 index 00000000000..1753f354507 --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/_semantic-layout.css @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + /* Semantic sizing for shared cross-component layout constraints. + * This layer will expand as more components adopt the token system. */ + /* Backward compatibility: falls back to legacy --ck-ui-component-min-height if overridden. */ + --ck-size-control-min-height: var(--ck-ui-component-min-height, var(--ck-size-min-height)); +} diff --git a/packages/ckeditor5-ui/theme/globals/_semantic-motion.css b/packages/ckeditor5-ui/theme/globals/_semantic-motion.css new file mode 100644 index 00000000000..4381c39bd2d --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/_semantic-motion.css @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + --ck-transition-duration-control-fast: var(--ck-duration-fast); + --ck-transition-duration-control: var(--ck-duration-base); + --ck-transition-duration-control-emphasized: var(--ck-duration-slow); + --ck-transition-duration-surface: var(--ck-duration-slower); + + --ck-transition-timing-function-control: var(--ck-ease-interactive); + --ck-transition-timing-function-control-emphasized: var(--ck-ease-emphasized); + --ck-transition-timing-function-surface: var(--ck-ease-standard); + + /* Transition shorthands for controls (box-shadow + border). */ + --ck-transition-control: + box-shadow var(--ck-transition-duration-control) var(--ck-transition-timing-function-control), + border var(--ck-transition-duration-control) var(--ck-transition-timing-function-control); + --ck-transition-control-fast: + box-shadow var(--ck-transition-duration-control-fast) var(--ck-transition-timing-function-control), + border var(--ck-transition-duration-control-fast) var(--ck-transition-timing-function-control); + + --ck-animation-duration-feedback: var(--ck-animation-duration-slow); + --ck-animation-duration-surface-entrance: var(--ck-animation-duration-slow); + --ck-animation-duration-progress: var(--ck-animation-duration-emphasis); + --ck-animation-duration-progress-reduced: var(--ck-animation-duration-reduced); + + --ck-animation-timing-function-feedback: var(--ck-animation-ease-standard); + --ck-animation-timing-function-progress: var(--ck-animation-ease-linear); + --ck-animation-fill-mode-feedback: var(--ck-animation-fill-both); +} diff --git a/packages/ckeditor5-ui/theme/globals/_semantic-shape.css b/packages/ckeditor5-ui/theme/globals/_semantic-shape.css new file mode 100644 index 00000000000..e764d73364f --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/_semantic-shape.css @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + --ck-border-width-control: var(--ck-border-width-thin); + --ck-border-width-surface: var(--ck-border-width-thin); + --ck-border-width-divider: var(--ck-border-width-thin); + --ck-border-width-emphasis: var(--ck-border-width-thick); + + /* Border shorthands (width + style + color). */ + --ck-border-control: var(--ck-border-width-control) solid var(--ck-color-border-control); + --ck-border-surface: var(--ck-border-width-surface) solid var(--ck-color-border-container); + --ck-border-divider: var(--ck-border-width-divider) solid var(--ck-color-divider); + + /* Semantic radii for interactive controls (buttons, inputs, toggles). */ + /* Backward compatibility: falls back to legacy --ck-border-radius if overridden. */ + --ck-border-radius-control: var(--ck-border-radius, var(--ck-radius-base)); + + /* Semantic radii for elevated surfaces (dropdowns, panels, dialogs, toolbars). */ + /* Backward compatibility: falls back to legacy --ck-border-radius if overridden. */ + --ck-border-radius-surface: var(--ck-border-radius, var(--ck-radius-base)); + + /* Uniform radius opt-out for attached surfaces. Set to a radius value + * (e.g. var(--ck-radius-base)) to disable cut-corner / attached-edge behavior + * on all panels, dropdowns, menus, and toolbars at once. Defaults to `initial` + * (no override — each surface keeps its positional corners). */ + --ck-border-radius-uniform: initial; + + /* Radius for attached surfaces where one edge touches trigger/control. */ + --ck-border-radius-surface-attached: var(--ck-border-radius-surface); + --ck-border-radius-surface-attached-top: 0 0 var(--ck-border-radius-surface-attached) var(--ck-border-radius-surface-attached); + --ck-border-radius-surface-attached-bottom: var(--ck-border-radius-surface-attached) var(--ck-border-radius-surface-attached) 0 0; + + /* Radius with one corner cut for positioned attached surfaces. */ + --ck-border-radius-surface-cut-top-left: 0 var(--ck-border-radius-surface-attached) var(--ck-border-radius-surface-attached) var(--ck-border-radius-surface-attached); + --ck-border-radius-surface-cut-top-right: var(--ck-border-radius-surface-attached) 0 var(--ck-border-radius-surface-attached) var(--ck-border-radius-surface-attached); + --ck-border-radius-surface-cut-bottom-right: var(--ck-border-radius-surface-attached) var(--ck-border-radius-surface-attached) 0 var(--ck-border-radius-surface-attached); + --ck-border-radius-surface-cut-bottom-left: var(--ck-border-radius-surface-attached) var(--ck-border-radius-surface-attached) var(--ck-border-radius-surface-attached) 0; +} diff --git a/packages/ckeditor5-ui/theme/globals/_semantic-spacing.css b/packages/ckeditor5-ui/theme/globals/_semantic-spacing.css new file mode 100644 index 00000000000..04fbb6e2ac2 --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/_semantic-spacing.css @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + /* Spacing used by controls like buttons and inputs. */ + /* Backward compatibility: falls back to legacy --ck-spacing-tiny if overridden. */ + --ck-spacing-control-padding-block: var(--ck-spacing-tiny, var(--ck-spacing-xs)); + /* Backward compatibility: falls back to legacy --ck-spacing-standard if overridden. */ + --ck-spacing-control-padding-inline: var(--ck-spacing-standard, var(--ck-spacing-base)); + /* Backward compatibility: falls back to legacy --ck-spacing-small if overridden. */ + --ck-spacing-control-padding-inline-compact: var(--ck-spacing-small, var(--ck-spacing-sm)); + /* Backward compatibility: falls back to legacy --ck-spacing-tiny if overridden. */ + --ck-spacing-control-padding-inline-start-compact: var(--ck-spacing-tiny, var(--ck-spacing-xs)); + /* Backward compatibility: falls back to legacy --ck-spacing-small if overridden. */ + --ck-spacing-control-padding-block-regular: var(--ck-spacing-small, var(--ck-spacing-sm)); + /* Backward compatibility: falls back to legacy --ck-spacing-extra-tiny if overridden. */ + --ck-spacing-control-padding-block-compact: var(--ck-spacing-extra-tiny, var(--ck-spacing-2xs)); + /* Backward compatibility: falls back to legacy --ck-spacing-medium if overridden. */ + --ck-spacing-control-icon-gap: var(--ck-spacing-medium, var(--ck-spacing-md)); + /* Backward compatibility: falls back to legacy --ck-spacing-large if overridden. */ + --ck-spacing-control-meta-gap: var(--ck-spacing-large, var(--ck-spacing-lg)); + + /* Spacing used by grouped surfaces like toolbars and lists. */ + /* Backward compatibility: falls back to legacy --ck-spacing-small if overridden. */ + --ck-spacing-surface-padding-inline: var(--ck-spacing-small, var(--ck-spacing-sm)); + /* Backward compatibility: falls back to legacy --ck-spacing-small if overridden. */ + --ck-spacing-surface-padding-block: var(--ck-spacing-small, var(--ck-spacing-sm)); + /* Backward compatibility: falls back to legacy --ck-spacing-small if overridden. */ + --ck-spacing-surface-item-gap-inline: var(--ck-spacing-small, var(--ck-spacing-sm)); + /* Backward compatibility: falls back to legacy --ck-spacing-small if overridden. */ + --ck-spacing-surface-item-gap-block: var(--ck-spacing-small, var(--ck-spacing-sm)); + /* Backward compatibility: falls back to legacy --ck-spacing-medium if overridden. */ + --ck-spacing-surface-section-gap-block: var(--ck-spacing-medium, var(--ck-spacing-md)); + + /* + * Naming note: `region` is a provisional term for UI container spacing. + * The namespace may be refined in a future iteration. + * TODO(#19910): Revisit `region` naming. + */ + /* Backward compatibility: falls back to legacy --ck-spacing-standard if overridden. */ + --ck-spacing-region-padding-inline: var(--ck-spacing-standard, var(--ck-spacing-base)); + /* Backward compatibility: falls back to legacy --ck-spacing-large if overridden. */ + --ck-spacing-region-padding-inline-wide: var(--ck-spacing-large, var(--ck-spacing-lg)); + /* Backward compatibility: falls back to legacy --ck-spacing-standard if overridden. */ + --ck-spacing-region-padding-block: var(--ck-spacing-standard, var(--ck-spacing-base)); + /* Backward compatibility: falls back to legacy --ck-spacing-large if overridden. */ + --ck-spacing-region-edge-margin-block: var(--ck-spacing-large, var(--ck-spacing-lg)); +} diff --git a/packages/ckeditor5-ui/theme/globals/_semantic-surface.css b/packages/ckeditor5-ui/theme/globals/_semantic-surface.css new file mode 100644 index 00000000000..55ec8a8a124 --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/_semantic-surface.css @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + /* Color surface roles are defined in ./colors/_semantic-surface.css. */ + + /* Generic floating surface shadows. */ + /* Backward compatibility: falls back to legacy --ck-drop-shadow if overridden. */ + --ck-shadow-surface-floating: var(--ck-drop-shadow, var(--ck-shadow-md)); +} diff --git a/packages/ckeditor5-ui/theme/globals/_semantic-typography.css b/packages/ckeditor5-ui/theme/globals/_semantic-typography.css new file mode 100644 index 00000000000..5a2638bd920 --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/_semantic-typography.css @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + --ck-font-weight-ui-default: var(--ck-font-weight-normal); + --ck-font-weight-ui-strong: var(--ck-font-weight-semibold); + --ck-font-weight-ui-heading: var(--ck-font-weight-bold); + --ck-font-weight-ui-label: var(--ck-font-weight-bold); + --ck-font-weight-ui-emphasis: var(--ck-font-weight-bold); + --ck-font-weight-ui-muted: var(--ck-font-weight-normal); + --ck-font-weight-ui-inherit: inherit; +} diff --git a/packages/ckeditor5-ui/theme/globals/_shadow.css b/packages/ckeditor5-ui/theme/globals/_shadow.css index da0949accb3..5ff48cb5c57 100644 --- a/packages/ckeditor5-ui/theme/globals/_shadow.css +++ b/packages/ckeditor5-ui/theme/globals/_shadow.css @@ -5,17 +5,17 @@ :root { /** - * A visual style of element's inner shadow (i.e. input). + * A visual style of element's inset shadow (e.g. input). */ - --ck-inner-shadow: 2px 2px 3px var(--ck-color-shadow-inner) inset; + --ck-inset-shadow-sm: 2px 2px 3px var(--ck-color-shadow-inner) inset; /** - * A visual style of element's drop shadow (i.e. panel). + * A visual style of element's drop shadow (e.g. panel). */ - --ck-drop-shadow: 0 1px 2px 1px var(--ck-color-shadow-drop); + --ck-shadow-md: 0 1px 2px 1px var(--ck-color-shadow-drop); /** - * A visual style of element's active shadow (i.e. comment or suggestion). + * A visual style of element's active shadow (e.g. comment or suggestion). */ - --ck-drop-shadow-active: 0 3px 6px 1px var(--ck-color-shadow-drop-active); + --ck-shadow-lg: 0 3px 6px 1px var(--ck-color-shadow-drop-active); } diff --git a/packages/ckeditor5-ui/theme/globals/_spacing.css b/packages/ckeditor5-ui/theme/globals/_spacing.css index 4c5aebc106b..403eef23e99 100644 --- a/packages/ckeditor5-ui/theme/globals/_spacing.css +++ b/packages/ckeditor5-ui/theme/globals/_spacing.css @@ -5,12 +5,12 @@ :root { --ck-spacing-unit: 0.6em; - --ck-spacing-extra-large: calc(var(--ck-spacing-unit) * 2); - --ck-spacing-large: calc(var(--ck-spacing-unit) * 1.5); - --ck-spacing-standard: var(--ck-spacing-unit); - --ck-spacing-medium: calc(var(--ck-spacing-unit) * 0.8); - --ck-spacing-medium-small: calc(var(--ck-spacing-unit) * 0.667); - --ck-spacing-small: calc(var(--ck-spacing-unit) * 0.5); - --ck-spacing-tiny: calc(var(--ck-spacing-unit) * 0.3); - --ck-spacing-extra-tiny: calc(var(--ck-spacing-unit) * 0.16); + --ck-spacing-xl: calc(var(--ck-spacing-unit) * 2); + --ck-spacing-lg: calc(var(--ck-spacing-unit) * 1.5); + --ck-spacing-base: var(--ck-spacing-unit); + --ck-spacing-md: calc(var(--ck-spacing-unit) * 0.8); + --ck-spacing-ms: calc(var(--ck-spacing-unit) * 0.667); + --ck-spacing-sm: calc(var(--ck-spacing-unit) * 0.5); + --ck-spacing-xs: calc(var(--ck-spacing-unit) * 0.3); + --ck-spacing-2xs: calc(var(--ck-spacing-unit) * 0.16); } diff --git a/packages/ckeditor5-ui/theme/globals/_transition.css b/packages/ckeditor5-ui/theme/globals/_transition.css index f75ea9de7eb..4d647cfedac 100644 --- a/packages/ckeditor5-ui/theme/globals/_transition.css +++ b/packages/ckeditor5-ui/theme/globals/_transition.css @@ -3,6 +3,32 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ +:root { + --ck-duration-fast: .1s; + --ck-duration-base: .2s; + --ck-duration-slow: .3s; + --ck-duration-slower: .4s; + + --ck-animation-duration-fast: var(--ck-duration-fast); + --ck-animation-duration-base: var(--ck-duration-base); + --ck-animation-duration-slow: var(--ck-duration-slow); + --ck-animation-duration-emphasis: 1.5s; + --ck-animation-duration-reduced: 0s; + + --ck-transition-none: none; + + --ck-ease-standard: ease; + --ck-ease-interactive: ease-in-out; + --ck-ease-emphasized: cubic-bezier(0, 0, 0.24, 0.95); + --ck-animation-ease-standard: var(--ck-ease-standard); + --ck-animation-ease-interactive: var(--ck-ease-interactive); + --ck-animation-ease-linear: linear; + + --ck-animation-fill-both: both; + --ck-animation-repeat-infinite: infinite; + --ck-animation-none: var(--ck-transition-none); +} + /** * A class that disables all transitions of the element and its children. */ diff --git a/packages/ckeditor5-ui/theme/globals/_zindex.css b/packages/ckeditor5-ui/theme/globals/_zindex.css index fc3cf59d276..4adcaa75911 100644 --- a/packages/ckeditor5-ui/theme/globals/_zindex.css +++ b/packages/ckeditor5-ui/theme/globals/_zindex.css @@ -4,7 +4,7 @@ */ :root { - --ck-z-default: 1; - --ck-z-panel: calc( var(--ck-z-default) + 999 ); - --ck-z-dialog: 9999; + --ck-z-base: 1; + --ck-z-overlay: calc( var(--ck-z-base) + 999 ); + --ck-z-modal: 9999; } diff --git a/packages/ckeditor5-ui/theme/globals/colors/_foundation.css b/packages/ckeditor5-ui/theme/globals/colors/_foundation.css new file mode 100644 index 00000000000..64a609d1b33 --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/colors/_foundation.css @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + --ck-color-base-foreground: hsl(0, 0%, 98%); + --ck-color-base-background: hsl(0, 0%, 100%); + --ck-color-base-border: hsl(220, 6%, 81%); + --ck-color-base-border-light: hsl(0, 0%, 87%); + --ck-color-base-action: hsl(104, 50.2%, 42.5%); + --ck-color-base-action-hover: hsl(104, 53.2%, 40.2%); + --ck-color-base-focus: hsl(209, 92%, 70%); + --ck-color-base-text: hsl(0, 0%, 20%); + --ck-color-base-text-light: hsl(0, 0%, 46%); + --ck-color-base-active: hsl(218.1, 100%, 58%); + --ck-color-base-active-focus: hsl(218.2, 100%, 52.5%); + --ck-color-base-hover: hsl(0, 0%, 94.1%); + --ck-color-base-selected: hsl(212, 100%, 97.1%); + --ck-color-base-selected-hover: hsl(211.7, 100%, 92.9%); + --ck-color-base-error: hsl(15, 100%, 43%); + --ck-color-base-warning: hsl(15, 100%, 43%); + --ck-color-base-success: hsl(120, 100%, 27%); + --ck-color-base-highlight: hsl(60, 100%, 50%); + --ck-color-base-attention: hsl(43, 100%, 62%); + + --ck-color-base-focus-shadow: hsl(212.4, 89.3%, 89%); + --ck-color-base-focus-shadow-faded: hsla(209, 90%, 72%, .3); + --ck-color-base-error-shadow: hsla(9, 100%, 56%, .3); + + --ck-color-shadow-drop: hsla(0, 0%, 0%, 0.15); + --ck-color-shadow-drop-active: hsla(0, 0%, 0%, 0.2); + --ck-color-shadow-inner: hsla(0, 0%, 0%, 0.1); +} diff --git a/packages/ckeditor5-ui/theme/globals/colors/_legacy-component-aliases.css b/packages/ckeditor5-ui/theme/globals/colors/_legacy-component-aliases.css new file mode 100644 index 00000000000..49b7070dbd5 --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/colors/_legacy-component-aliases.css @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +/* + * Backward-compatible aliases for legacy component color token names. + * These map old domain-first names (--ck-color-component-*) to new + * component-first names (--ck-component-*-color) defined in each component file. + */ +:root { + /* -- Buttons ------------------------------------------------------------------------------- */ + + --ck-color-button-default-background: var(--ck-button-default-background-color); + --ck-color-button-default-hover-background: var(--ck-button-default-hover-background-color); + --ck-color-button-default-active-background: var(--ck-button-default-active-background-color); + --ck-color-button-default-disabled-background: var(--ck-button-default-disabled-background-color); + + --ck-color-button-on-background: var(--ck-button-on-background-color); + --ck-color-button-on-hover-background: var(--ck-button-on-hover-background-color); + --ck-color-button-on-active-background: var(--ck-button-on-active-background-color); + --ck-color-button-on-disabled-background: var(--ck-button-on-disabled-background-color); + --ck-color-button-on-color: var(--ck-button-on-text-color); + + --ck-color-button-action-background: var(--ck-button-action-background-color); + --ck-color-button-action-hover-background: var(--ck-button-action-hover-background-color); + --ck-color-button-action-active-background: var(--ck-button-action-active-background-color); + --ck-color-button-action-disabled-background: var(--ck-button-action-disabled-background-color); + --ck-color-button-action-text: var(--ck-button-action-text-color); + + --ck-color-button-save: var(--ck-button-save-color); + --ck-color-button-cancel: var(--ck-button-cancel-color); + + --ck-color-switch-button-off-background: var(--ck-switch-button-off-background-color); + --ck-color-switch-button-off-hover-background: var(--ck-switch-button-off-hover-background-color); + --ck-color-switch-button-on-background: var(--ck-switch-button-on-background-color); + --ck-color-switch-button-on-hover-background: var(--ck-switch-button-on-hover-background-color); + --ck-color-switch-button-inner-background: var(--ck-switch-button-inner-background-color); + + /* -- Dropdown ------------------------------------------------------------------------------ */ + + --ck-color-dropdown-panel-background: var(--ck-dropdown-panel-background-color); + --ck-color-dropdown-panel-border: var(--ck-dropdown-panel-border-color); + + /* -- Dialog -------------------------------------------------------------------------------- */ + + --ck-color-dialog-background: var(--ck-dialog-background-color); + + /* -- Input --------------------------------------------------------------------------------- */ + + --ck-color-input-background: var(--ck-input-background-color); + --ck-color-input-border: var(--ck-input-border-color); + --ck-color-input-error-border: var(--ck-input-error-border-color); + --ck-color-input-text: var(--ck-input-text-color); + --ck-color-input-disabled-background: var(--ck-input-disabled-background-color); + --ck-color-input-disabled-border: var(--ck-input-disabled-border-color); + --ck-color-input-disabled-text: var(--ck-input-disabled-text-color); + + /* -- List ---------------------------------------------------------------------------------- */ + + --ck-color-list-background: var(--ck-list-background-color); + --ck-color-list-button-hover-background: var(--ck-list-button-hover-background-color); + --ck-color-list-button-on-background: var(--ck-list-button-on-background-color); + --ck-color-list-button-on-text: var(--ck-list-button-on-text-color); + + /* -- Panel --------------------------------------------------------------------------------- */ + + --ck-color-panel-background: var(--ck-balloon-panel-background-color); + --ck-color-panel-border: var(--ck-balloon-panel-border-color); + + /* -- Toolbar ------------------------------------------------------------------------------- */ + + --ck-color-toolbar-background: var(--ck-toolbar-background-color); + --ck-color-toolbar-border: var(--ck-toolbar-border-color); + + /* -- Tooltip ------------------------------------------------------------------------------- */ + + --ck-color-tooltip-background: var(--ck-tooltip-background-color); + --ck-color-tooltip-text: var(--ck-tooltip-text-color); +} diff --git a/packages/ckeditor5-ui/theme/globals/colors/_legacy-misc.css b/packages/ckeditor5-ui/theme/globals/colors/_legacy-misc.css new file mode 100644 index 00000000000..fefc4c62878 --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/colors/_legacy-misc.css @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + /* -- Engine -------------------------------------------------------------------------------- */ + + --ck-color-engine-placeholder-text: hsl(0, 0%, 44%); + + /* -- Upload -------------------------------------------------------------------------------- */ + + --ck-color-upload-bar-background: var(--ck-color-base-focus); + + /* -- Link ---------------------------------------------------------------------------------- */ + + --ck-color-link-default: hsl(240, 100%, 47%); + --ck-color-link-selected-background: hsla(201, 100%, 56%, 0.1); + --ck-color-link-fake-selection: hsla(201, 100%, 56%, 0.3); + + /* -- Search result highlight --------------------------------------------------------------- */ + + --ck-color-highlight-background: var(--ck-color-feedback-highlight); + + /* -- Generic colors ----------------------------------------------------------------------- */ + + --ck-color-light-red: hsl(0, 100%, 90%); +} diff --git a/packages/ckeditor5-ui/theme/globals/colors/_semantic-feedback.css b/packages/ckeditor5-ui/theme/globals/colors/_semantic-feedback.css new file mode 100644 index 00000000000..afd597e42dc --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/colors/_semantic-feedback.css @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + --ck-color-feedback-error: var(--ck-color-base-error); + --ck-color-feedback-success: var(--ck-color-base-success); + --ck-color-feedback-warning: var(--ck-color-base-warning); + --ck-color-feedback-highlight: var(--ck-color-base-highlight); +} diff --git a/packages/ckeditor5-ui/theme/globals/colors/_semantic-interactive.css b/packages/ckeditor5-ui/theme/globals/colors/_semantic-interactive.css new file mode 100644 index 00000000000..4ee0a66b1b4 --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/colors/_semantic-interactive.css @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + --ck-color-interactive-focus-border-coordinates: 218, 81.8%, 56.9%; + /* Fallback to `--ck-color-focus-border-coordinates` for backward compatibility. */ + --ck-color-interactive-focus-border: hsl(var(--ck-color-focus-border-coordinates, var(--ck-color-interactive-focus-border-coordinates))); + --ck-color-interactive-focus-shadow: var(--ck-color-base-focus-shadow); + --ck-color-interactive-focus-disabled-shadow: var(--ck-color-base-focus-shadow-faded); + --ck-color-interactive-focus-error-shadow: var(--ck-color-base-error-shadow); + + --ck-color-interactive-hover-surface: var(--ck-color-base-hover); + --ck-color-interactive-active-surface: var(--ck-color-base-hover); + --ck-color-interactive-selected-surface: var(--ck-color-base-selected); + --ck-color-interactive-selected-surface-hover: var(--ck-color-base-selected-hover); + --ck-color-interactive-selected-text: var(--ck-color-base-active); + + --ck-color-interactive-primary-surface: var(--ck-color-base-action); + --ck-color-interactive-primary-surface-hover: var(--ck-color-base-action-hover); + --ck-color-interactive-primary-text: var(--ck-color-text-inverse); + + /* Backward compatibility aliases. */ + --ck-color-focus-border-coordinates: var(--ck-color-interactive-focus-border-coordinates); + --ck-color-focus-border: var(--ck-color-interactive-focus-border); + --ck-color-focus-outer-shadow: var(--ck-color-interactive-focus-shadow); + --ck-color-focus-disabled-shadow: var(--ck-color-interactive-focus-disabled-shadow); + --ck-color-focus-error-shadow: var(--ck-color-interactive-focus-error-shadow); +} diff --git a/packages/ckeditor5-ui/theme/globals/colors/_semantic-surface.css b/packages/ckeditor5-ui/theme/globals/colors/_semantic-surface.css new file mode 100644 index 00000000000..bed01b7873e --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/colors/_semantic-surface.css @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +/* Surface color tokens. Shadow-related surface tokens are in ../_semantic-surface.css. */ +:root { + --ck-color-surface-canvas: var(--ck-color-base-background); + --ck-color-surface-control: var(--ck-color-surface-canvas); + --ck-color-surface-container: var(--ck-color-surface-canvas); + --ck-color-surface-inverse: var(--ck-color-base-text); + + --ck-color-border-control: var(--ck-color-base-border); + --ck-color-border-container: var(--ck-color-base-border); + --ck-color-divider: var(--ck-color-base-border); +} diff --git a/packages/ckeditor5-ui/theme/globals/colors/_semantic-text.css b/packages/ckeditor5-ui/theme/globals/colors/_semantic-text.css new file mode 100644 index 00000000000..95a6e144df2 --- /dev/null +++ b/packages/ckeditor5-ui/theme/globals/colors/_semantic-text.css @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + --ck-color-text-primary: var(--ck-color-base-text); + --ck-color-text-secondary: var(--ck-color-base-text-light); + --ck-color-text-disabled: var(--ck-color-text-secondary); + --ck-color-text-inverse: var(--ck-color-base-background); + --ck-color-text-error: var(--ck-color-feedback-error); + + --ck-color-text: var(--ck-color-text-primary); +} diff --git a/packages/ckeditor5-ui/theme/index.css b/packages/ckeditor5-ui/theme/index.css index 697cad18cd1..9c7d5da63cb 100644 --- a/packages/ckeditor5-ui/theme/index.css +++ b/packages/ckeditor5-ui/theme/index.css @@ -7,15 +7,25 @@ @import "./globals/_disabled.css"; @import "./globals/_focus.css"; @import "./globals/_fonts.css"; +@import "./globals/_border.css"; @import "./globals/_reset.css"; @import "./globals/_rounded.css"; @import "./globals/_shadow.css"; @import "./globals/_spacing.css"; +@import "./globals/_semantic-typography.css"; +@import "./globals/_semantic-spacing.css"; +@import "./globals/_semantic-shape.css"; +@import "./globals/_semantic-surface.css"; +@import "./globals/_semantic-interactive.css"; +@import "./globals/_semantic-layout.css"; @import "./globals/_hidden.css"; @import "./globals/_zindex.css"; +@import "./globals/_semantic-layer.css"; @import "./globals/_transition.css"; +@import "./globals/_semantic-motion.css"; @import "./globals/_poweredby.css"; @import "./globals/_evaluationbadge.css"; +@import "./globals/_legacy-foundation-aliases.css"; @import "./components/responsive-form/responsiveform.css"; @import "./components/form/form.css"; diff --git a/packages/ckeditor5-widget/theme/widget.css b/packages/ckeditor5-widget/theme/widget.css index 93ca5c2b28a..be89eb17dae 100644 --- a/packages/ckeditor5-widget/theme/widget.css +++ b/packages/ckeditor5-widget/theme/widget.css @@ -7,20 +7,21 @@ :root { --ck-widget-outline-thickness: 3px; --ck-widget-handler-icon-size: 16px; - --ck-widget-handler-animation-duration: 200ms; - --ck-widget-handler-animation-curve: ease; + --ck-widget-handler-animation-duration: var(--ck-duration-base); + --ck-widget-handler-animation-curve: var(--ck-ease-standard); - --ck-color-widget-blurred-border: hsl(0, 0%, 87%); - --ck-color-widget-hover-border: hsl(43, 100%, 62%); + --ck-color-widget-blurred-border: var(--ck-color-base-border-light); + --ck-color-widget-hover-border: var(--ck-color-base-attention); --ck-color-widget-editable-focus-background: var(--ck-color-base-background); --ck-color-widget-drag-handler-icon-color: var(--ck-color-base-background); - --ck-color-resizer: var(--ck-color-focus-border); - --ck-color-resizer-tooltip-background: hsl(0, 0%, 15%); - --ck-color-resizer-tooltip-text: hsl(0, 0%, 95%); + --ck-color-resizer: var(--ck-color-focus-border, var(--ck-color-interactive-focus-border)); + --ck-color-resizer-tooltip-background: var(--ck-color-surface-inverse); + --ck-color-resizer-tooltip-text: var(--ck-color-text-inverse); - --ck-resizer-border-radius: var(--ck-border-radius); + /* Backward compatibility: falls back to legacy --ck-border-radius if overridden. */ + --ck-resizer-border-radius: var(--ck-border-radius, var(--ck-radius-base)); --ck-resizer-tooltip-offset: 10px; - --ck-resizer-tooltip-height: calc(var(--ck-spacing-small) * 2 + 10px); + --ck-resizer-tooltip-height: calc(var(--ck-spacing-small, var(--ck-spacing-sm)) * 2 + 10px); } .ck .ck-widget { @@ -35,7 +36,7 @@ &.ck-widget_selected, &.ck-widget_selected:hover { - outline: var(--ck-widget-outline-thickness) solid var(--ck-color-focus-border); + outline: var(--ck-widget-outline-thickness) solid var(--ck-color-focus-border, var(--ck-color-interactive-focus-border)); } &:hover { @@ -52,7 +53,8 @@ These styles show a different border for a blink of an eye, so `:focus` need to have same styles applied. */ &.ck-editor__nested-editable_focused, &:focus { - box-shadow: var(--ck-inner-shadow), 0 0; + /* Backward compatibility: falls back to legacy --ck-inner-shadow if overridden. */ + box-shadow: var(--ck-inner-shadow, var(--ck-inset-shadow-sm)), 0 0; @media (forced-colors: none) { background-color: var(--ck-color-widget-editable-focus-background); @@ -89,7 +91,8 @@ opacity var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve); /* Make only top corners round. */ - border-radius: var(--ck-border-radius) var(--ck-border-radius) 0 0; + /* Backward compatibility: falls back to legacy --ck-border-radius if overridden. */ + border-radius: var(--ck-border-radius, var(--ck-radius-base)) var(--ck-border-radius, var(--ck-radius-base)) 0 0; /* Place the drag handler outside the widget wrapper. */ transform: translateY(-100%); @@ -141,7 +144,7 @@ &.ck-widget_selected:hover { & > .ck-widget__selection-handle { opacity: 1; - background-color: var(--ck-color-focus-border); + background-color: var(--ck-color-focus-border, var(--ck-color-interactive-focus-border)); visibility: visible; /* When the widget is selected, notify the user using the proper look of the icon. */ @@ -233,9 +236,9 @@ color: var(--ck-color-resizer-tooltip-text); border: 1px solid var(--ck-color-resizer-tooltip-text); border-radius: var(--ck-resizer-border-radius); - font-size: var(--ck-font-size-tiny); + font-size: var(--ck-font-size-tiny, var(--ck-font-size-xs)); display: block; - padding: 0 var(--ck-spacing-small); + padding: 0 var(--ck-spacing-small, var(--ck-spacing-sm)); height: var(--ck-resizer-tooltip-height); line-height: var(--ck-resizer-tooltip-height); diff --git a/packages/ckeditor5-widget/theme/widgetresize.css b/packages/ckeditor5-widget/theme/widgetresize.css index 10030d2ee52..81e43de797a 100644 --- a/packages/ckeditor5-widget/theme/widgetresize.css +++ b/packages/ckeditor5-widget/theme/widgetresize.css @@ -26,8 +26,8 @@ .ck .ck-widget__resizer__handle { width: var(--ck-resizer-size); height: var(--ck-resizer-size); - background: var(--ck-color-focus-border); - border: var(--ck-resizer-border-width) solid hsl(0, 0%, 100%); + background: var(--ck-color-focus-border, var(--ck-color-interactive-focus-border)); + border: var(--ck-resizer-border-width) solid var(--ck-color-base-background); border-radius: var(--ck-resizer-border-radius); position: absolute; diff --git a/packages/ckeditor5-widget/theme/widgettypearound.css b/packages/ckeditor5-widget/theme/widgettypearound.css index 83f95ca75bd..9cdc82da497 100644 --- a/packages/ckeditor5-widget/theme/widgettypearound.css +++ b/packages/ckeditor5-widget/theme/widgettypearound.css @@ -5,7 +5,9 @@ :root { --ck-widget-type-around-button-size: 20px; - --ck-color-widget-type-around-button-active: var(--ck-color-focus-border); + --ck-widget-type-around-button-border-radius: 100px; + /* Backward compatibility: falls back to legacy --ck-color-focus-border if overridden. */ + --ck-color-widget-type-around-button-active: var(--ck-color-focus-border, var(--ck-color-interactive-focus-border)); --ck-color-widget-type-around-button-hover: var(--ck-color-widget-hover-border); --ck-color-widget-type-around-button-blurred-editable: var(--ck-color-widget-blurred-border); --ck-color-widget-type-around-button-radar-start-alpha: 0; @@ -21,7 +23,7 @@ width: var(--ck-widget-type-around-button-size); height: var(--ck-widget-type-around-button-size); background: var(--ck-color-widget-type-around-button); - border-radius: 100px; + border-radius: var(--ck-widget-type-around-button-border-radius); transition: opacity var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve), background var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve); opacity: 0; @@ -29,7 +31,7 @@ display: block; position: absolute; overflow: hidden; - z-index: var(--ck-z-default); + z-index: var(--ck-z-default, var(--ck-z-base)); @media (prefers-reduced-motion: reduce) { transition: none; @@ -63,7 +65,7 @@ & line { stroke-dasharray: 7; } - z-index: calc(var(--ck-z-default) + 2) + z-index: calc(var(--ck-z-default, var(--ck-z-base)) + 2) } &:hover { @@ -147,14 +149,14 @@ &::after { width: calc(var(--ck-widget-type-around-button-size) - 2px); height: calc(var(--ck-widget-type-around-button-size) - 2px); - border-radius: 100px; + border-radius: var(--ck-widget-type-around-button-border-radius); background: linear-gradient(135deg, hsla(0,0%,100%,0) 0%, hsla(0,0%,100%,.3) 100%); content: ""; display: block; position: absolute; top: 1px; left: 1px; - z-index: calc(var(--ck-z-default) + 1); + z-index: calc(var(--ck-z-default, var(--ck-z-base)) + 1); } } @@ -197,7 +199,7 @@ * The semi-transparent-outline+background combo improves the contrast * when the background underneath the fake caret is dark. */ - outline: solid 1px hsla(0, 0%, 100%, .5); + outline: var(--ck-outline-fake-caret); background: var(--ck-color-base-text); } @@ -340,7 +342,7 @@ background: var(--ck-color-widget-type-around-button-blurred-editable); & svg * { - stroke: hsl(0,0%,60%); + stroke: var(--ck-color-widget-blurred-border); } } diff --git a/packages/ckeditor5/tests/manual/all-features-ui-customization.html b/packages/ckeditor5/tests/manual/all-features-ui-customization.html new file mode 100644 index 00000000000..3aa7a9f395a --- /dev/null +++ b/packages/ckeditor5/tests/manual/all-features-ui-customization.html @@ -0,0 +1,1171 @@ + + + + + + + +
+ + + + + +
+ +
+
+
+

Lists in the table

+
+ + + + + + + + + + + + + +
Bulleted listNumbered listTo do list
+
    +
  • UL List item 1
  • +
  • UL List item 2
  • +
+
+
    +
  1. OL List item 1
  2. +
  3. OL List item 2
  4. +
+
+
    +
  • + +
  • +
  • + +
  • +
+
+
+ +

Basic features overview

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit.1

+

Basic styles

+

Ad alias, architecto culpa cumque dignissimos dolor eos incidunt ipsa itaque laboriosam magnam.2

+

Image

+
+ bar +
Caption
+
+

Blockquote

+
+

Quote

+
    +
  • Quoted UL List item 1
  • +
  • Quoted UL List item 2
  • +
+
+ +

Code block

+
body {
+	color: red;
+}
+
+p {
+	font-size: 10px;
+}
+ +
+ +

HTML embed

+
+
+ Details + Something small enough to escape casual notice. +
+
+ +

Link

+

Visit CKEditor for more info.

+
+
+
+

+ Design Tokens + + + + + + +

+
+ + +
+
+ + +
+ +
+
diff --git a/packages/ckeditor5/tests/manual/all-features-ui-customization.js b/packages/ckeditor5/tests/manual/all-features-ui-customization.js new file mode 100644 index 00000000000..dd8b04bdf74 --- /dev/null +++ b/packages/ckeditor5/tests/manual/all-features-ui-customization.js @@ -0,0 +1,306 @@ +/** + * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic'; +import { Alignment } from '@ckeditor/ckeditor5-alignment'; +import { ArticlePluginSet } from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset.js'; +import { AutoImage, ImageResize, ImageInsert } from '@ckeditor/ckeditor5-image'; +import { AutoLink, LinkImage } from '@ckeditor/ckeditor5-link'; +import { BalloonToolbar } from '@ckeditor/ckeditor5-ui'; +import { Code, Strikethrough, Subscript, Superscript, Underline } from '@ckeditor/ckeditor5-basic-styles'; +import { CodeBlock } from '@ckeditor/ckeditor5-code-block'; +import { EasyImage } from '@ckeditor/ckeditor5-easy-image'; +import { FindAndReplace } from '@ckeditor/ckeditor5-find-and-replace'; +import { FontBackgroundColor, FontColor, FontFamily, FontSize } from '@ckeditor/ckeditor5-font'; +import { Highlight } from '@ckeditor/ckeditor5-highlight'; +import { HorizontalLine } from '@ckeditor/ckeditor5-horizontal-line'; +import { HtmlEmbed } from '@ckeditor/ckeditor5-html-embed'; +import { HtmlComment, GeneralHtmlSupport } from '@ckeditor/ckeditor5-html-support'; +import { IndentBlock } from '@ckeditor/ckeditor5-indent'; +import { ListProperties, TodoList } from '@ckeditor/ckeditor5-list'; +import { Mention } from '@ckeditor/ckeditor5-mention'; +import { PageBreak } from '@ckeditor/ckeditor5-page-break'; +import { PasteFromOffice } from '@ckeditor/ckeditor5-paste-from-office'; +import { RemoveFormat } from '@ckeditor/ckeditor5-remove-format'; +import { ShowBlocks } from '@ckeditor/ckeditor5-show-blocks'; +import { SourceEditing } from '@ckeditor/ckeditor5-source-editing'; +import { SpecialCharacters, SpecialCharactersEssentials } from '@ckeditor/ckeditor5-special-characters'; +import { TableCellProperties, TableProperties, TableCaption, TableColumnResize } from '@ckeditor/ckeditor5-table'; +import { TextTransformation } from '@ckeditor/ckeditor5-typing'; +import { TextPartLanguage } from '@ckeditor/ckeditor5-language'; +import { WordCount } from '@ckeditor/ckeditor5-word-count'; +import { CloudServices } from '@ckeditor/ckeditor5-cloud-services'; +import { Style } from '@ckeditor/ckeditor5-style'; +import { Bookmark } from '@ckeditor/ckeditor5-bookmark'; +import { Fullscreen } from '@ckeditor/ckeditor5-fullscreen'; + +import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config.js'; +// eslint-disable-next-line ckeditor5-rules/allow-imports-only-from-main-package-entry-point +import { generatePanel } from '@ckeditor/ckeditor5-ui/tests/manual/ui-customization/token-panel.js'; + +import { presetFiles } from './presets/index.js'; + +ClassicEditor + .create( document.querySelector( '#editor' ), { + plugins: [ + ArticlePluginSet, Underline, Strikethrough, Superscript, Subscript, Code, RemoveFormat, + FindAndReplace, FontColor, FontBackgroundColor, FontFamily, FontSize, Highlight, + CodeBlock, TodoList, ListProperties, TableProperties, TableCellProperties, TableCaption, TableColumnResize, + EasyImage, ImageResize, ImageInsert, LinkImage, AutoImage, HtmlEmbed, HtmlComment, + AutoLink, Mention, TextTransformation, + Alignment, IndentBlock, Bookmark, BalloonToolbar, + PasteFromOffice, PageBreak, HorizontalLine, ShowBlocks, + SpecialCharacters, SpecialCharactersEssentials, WordCount, + CloudServices, TextPartLanguage, SourceEditing, Style, GeneralHtmlSupport, Fullscreen + ], + toolbar: [ + 'heading', 'style', + '|', + 'removeFormat', 'bold', 'italic', 'strikethrough', 'underline', 'code', 'subscript', 'superscript', 'link', 'bookmark', + '|', + 'highlight', 'fontSize', 'fontFamily', 'fontColor', 'fontBackgroundColor', + '|', + 'bulletedList', 'numberedList', 'todoList', + '|', + 'blockQuote', 'insertImage', 'insertTable', 'mediaEmbed', 'codeBlock', + '|', + 'htmlEmbed', + '|', + 'alignment', 'outdent', 'indent', + '|', + 'pageBreak', 'horizontalLine', 'specialCharacters', + '|', + 'textPartLanguage', + '|', + 'sourceEditing', 'showBlocks', + '|', + 'undo', 'redo', 'findAndReplace', 'fullscreen' + ], + balloonToolbar: [ + 'bold', 'italic', 'underline', '|', 'link', 'insertImage', '|', + 'fontColor', 'fontBackgroundColor', '|', 'bulletedList', 'numberedList' + ], + cloudServices: CS_CONFIG, + table: { + contentToolbar: [ + 'tableColumn', 'tableRow', 'mergeTableCells', 'tableProperties', 'tableCellProperties', 'toggleTableCaption' + ] + }, + image: { + styles: [ + 'alignCenter', + 'alignLeft', + 'alignRight' + ], + resizeOptions: [ + { + name: 'resizeImage:original', + label: 'Original size', + value: null + }, + { + name: 'resizeImage:50', + label: '50%', + value: '50' + }, + { + name: 'resizeImage:75', + label: '75%', + value: '75' + } + ], + toolbar: [ + 'linkImage', 'imageTextAlternative', 'toggleImageCaption', '|', + 'imageStyle:inline', 'imageStyle:block', 'imageStyle:wrapText', '|', + 'resizeImage' + ] + }, + placeholder: 'Type the content here!', + mention: { + feeds: [ + { + marker: '@', + feed: [ + '@apple', '@bears', '@brownie', '@cake', '@candy', '@chocolate', '@cookie', '@cream', + '@cupcake', '@danish', '@donut', '@fruitcake', '@gingerbread', '@ice', '@jelly-o', + '@liquorice', '@macaroon', '@marzipan', '@oat', '@pie', '@plum', '@pudding', + '@sugar', '@sweet', '@topping', '@wafer' + ], + minimumCharacters: 1 + } + ] + }, + menuBar: { + isVisible: true + }, + link: { + decorators: { + isExternal: { + mode: 'manual', + label: 'Open in a new tab', + attributes: { + target: '_blank', + rel: 'noopener noreferrer' + } + }, + isDownloadable: { + mode: 'manual', + label: 'Downloadable', + attributes: { + download: 'download' + } + }, + isGallery: { + mode: 'manual', + label: 'Gallery link', + classes: 'gallery' + } + } + }, + htmlEmbed: { + showPreviews: true, + sanitizeHtml: html => ( { html, hasChange: false } ) + }, + list: { + properties: { + styles: true, + startIndex: true, + reversed: true + } + }, + style: { + definitions: [ + { + name: 'Article category', + element: 'h3', + classes: [ 'category' ] + }, + { + name: 'Title', + element: 'h2', + classes: [ 'document-title' ] + }, + { + name: 'Subtitle', + element: 'h3', + classes: [ 'document-subtitle' ] + }, + { + name: 'Info box', + element: 'p', + classes: [ 'info-box' ] + }, + { + name: 'Side quote', + element: 'blockquote', + classes: [ 'side-quote' ] + }, + { + name: 'Marker', + element: 'span', + classes: [ 'marker' ] + }, + { + name: 'Spoiler', + element: 'span', + classes: [ 'spoiler' ] + }, + { + name: 'Code (dark)', + element: 'pre', + classes: [ 'fancy-code', 'fancy-code-dark' ] + }, + { + name: 'Code (bright)', + element: 'pre', + classes: [ 'fancy-code', 'fancy-code-bright' ] + } + ] + } + } ) + .then( editor => { + window.editor = editor; + + // Load preset CSS files, then generate the token panel. + const sortedFiles = [ ...presetFiles ].sort(); + + Promise.all( + sortedFiles.map( file => + fetch( `presets/${ file }` ) + .then( res => res.ok ? res.text() : '' ) + .then( css => ( { + name: file.replace( /\.css$/, '' ), + css + } ) ) + ) + ).then( presets => { + generatePanel( presets.filter( p => p.css ) ); + } ); + + // Word count logging. + editor.plugins.get( 'WordCount' ).on( 'update', ( evt, stats ) => { + console.log( `Characters: ${ stats.characters }, words: ${ stats.words }.` ); + } ); + + // Clear editor button. + document.getElementById( 'clear-content' ).addEventListener( 'click', () => { + editor.setData( '' ); + } ); + + // Print preview button. + document.getElementById( 'print-data-action' ).addEventListener( 'click', () => { + const iframeElement = document.getElementById( 'print-data-container' ); + + /* eslint-disable @stylistic/max-len */ + iframeElement.srcdoc = '' + + '' + + `${ document.title }` + + '' + + '' + + '' + + '' + + editor.getData() + + '' + + '' + + ''; + /* eslint-enable @stylistic/max-len */ + } ); + + // Read-only toggle button. + const button = document.getElementById( 'read-only' ); + let isReadOnly = false; + + button.addEventListener( 'click', () => { + isReadOnly = !isReadOnly; + + if ( isReadOnly ) { + editor.enableReadOnlyMode( 'manual-test' ); + } else { + editor.disableReadOnlyMode( 'manual-test' ); + } + + button.textContent = isReadOnly ? + 'Turn off read-only mode' : + 'Turn on read-only mode'; + + editor.editing.view.focus(); + } ); + + // Toggle token panel button. + const toggleBtn = document.getElementById( 'toggle-panel' ); + const layout = document.querySelector( '.ck-test-layout' ); + + toggleBtn.addEventListener( 'click', () => { + layout.classList.toggle( 'ck-test-layout--panel-hidden' ); + toggleBtn.textContent = layout.classList.contains( 'ck-test-layout--panel-hidden' ) ? + 'Show tokens panel' : + 'Hide tokens panel'; + } ); + } ) + .catch( err => { + console.error( err.stack ); + } ); diff --git a/packages/ckeditor5/tests/manual/all-features-ui-customization.md b/packages/ckeditor5/tests/manual/all-features-ui-customization.md new file mode 100644 index 00000000000..b36ef86490f --- /dev/null +++ b/packages/ckeditor5/tests/manual/all-features-ui-customization.md @@ -0,0 +1,102 @@ +# All features — UI customization (Design Token Explorer) + +Interactive test combining the full-featured editor with the Design Token Explorer panel. + +## Layout + +- **Left**: Classic editor with all features enabled (same config as `all-features` test) +- **Right**: Scrollable token customization panel with collapsible sections + +## How to use + +### Token panel + +1. Use the search input at the top to filter tokens by name or description. Matching sections auto-expand; clearing restores the previous state. +2. Check "Show only overridden" to hide all tokens that haven't been changed (works with search). +3. Expand a tier (Foundation / Semantic / Component) to see categories. Use "Expand all" / "Collapse all" per tier. +4. Each token shows a short description of what it controls. +5. Click a token name to copy its full `--ck-*` name to clipboard (turns green with a ✓ on success). +6. Tokens with a 🖼 icon have a visual diagram — click to toggle. Click "Show Diagrams" in the header to toggle all at once. +7. Use the input controls to override token values live: + - **Color tokens**: color picker + text input (supports hsl, hex, rgb) + - **Spacing/size**: text input (px, em, calc values) + - **Font weight**: dropdown (100-900) + - **Duration**: range slider + text input + - **Easing**: dropdown with presets + - **Opacity**: range slider (0-1) +8. Overridden tokens are highlighted in blue. Tokens changed by an active stylesheet preset are highlighted in amber. +9. Section headers inherit the highlight color so you can see overrides even when collapsed. +10. Dependent tokens update automatically — e.g., changing `--ck-spacing-unit` refreshes all spacing tokens that reference it. Manually overridden dependents are not affected. +11. Click the "↺" button on any row to reset that token to its default. +12. Click "Reset All" to clear all overrides. +13. Click a greyed-out reference (← token-name) to scroll to and highlight the source token. + +### Token dependencies (cascade tree) + +1. Open the "Token Dependencies" section (green accent). +2. Type a token name in the search input — suggestions appear as you type. +3. Press Enter or click a suggestion to view the dependency tree. +4. The tree shows: ancestor chain (what the token inherits from), the selected token with its tier and computed value, and all dependents (what inherits from it). +5. Click any token in the tree to scroll to its row in the panel. + +### Color palette overview + +1. Open the "Color Palette Overview" section (orange accent). +2. All color tokens are displayed as swatches, grouped by tier (Foundation, Semantic, Component) with visual separators. +3. Swatches update live when tokens change or presets switch. +4. Click a swatch to open the color picker and change the value directly. +5. Click the token name below a swatch to scroll to its row in the panel. + +### Stylesheet presets (paste & compare) + +The all-features test loads built-in presets from `presets/` directory on startup. To add a new preset: drop a `.css` file into `presets/` and add its filename to `presets/index.js`. + +1. Open the "Stylesheet Presets" section at the top of the panel (blue accent). +2. Paste a CSS block (e.g. `:root { --ck-radius-base: 10px; }`) into the textarea. +3. Optionally enter a name, then click "Add Stylesheet". +4. The stylesheet is immediately activated — the editor updates and token inputs refresh. +5. Add more stylesheets to compare. Use the radio buttons to switch between them. +6. Select "None (default)" to go back to the framework defaults. +7. Clicking a stylesheet entry loads its CSS into the textarea for editing. Click "Update Stylesheet" to apply changes. +8. Click "Add New" to fork the current textarea content into a new preset without modifying the selected one. +9. Use the "Reset" button to deselect the active stylesheet and clear the textarea. +10. Check "Clear manual overrides on switch" to reset all per-token tweaks when switching between stylesheets. This gives a clean comparison between presets. + +### Export overrides + +1. Tweak tokens using the panel inputs. +2. Click "Generate Stylesheet from Overrides" at the bottom of the panel. +3. A `:root { ... }` block with all manually changed tokens appears in a read-only textarea, ready to copy. + +### WCAG contrast checking + +Foreground color tokens (e.g. `--ck-color-text-primary`, `--ck-button-action-text-color`) show a live contrast ratio badge next to their input. The badge compares against the paired background token and displays: +- **Green** `AAA` (≥ 7:1) or `AA` (≥ 4.5:1) — passes WCAG +- **Red** `Fail` (< 4.5:1) — fails WCAG AA for normal text + +Badges show two color swatches (foreground + background) and update dynamically when either token changes. Click a badge to scroll to the paired background token. Hover for details. + +### Share via link + +1. Override some tokens and/or activate a preset, then click "Share Link" in the header. +2. The URL with encoded state (preset CSS + manual overrides) is copied to clipboard. +3. Open the link in another browser/tab — a "Loaded from link" preset is created in the Stylesheet Presets section, activated automatically, and the section opens to show it. + +## What to verify + +- All features render correctly with default tokens (compare with `all-features` test). +- Changing a foundation token cascades to semantic and component tokens. +- Changing a semantic token overrides the foundation reference for that role only. +- Component tokens can be overridden independently. +- Token changes affect all editor UI: toolbar, dropdowns, dialogs, panels, menus, color pickers, etc. +- Content features (tables, images, code blocks, lists, etc.) display correctly alongside token changes. +- Reset restores original values and re-enables the var() cascade. +- Pasted stylesheets apply at normal CSS specificity — per-token inline overrides always win (unless "Clear manual overrides on switch" is checked). +- Switching between stylesheet presets refreshes all non-overridden token inputs. +- Updating an active stylesheet re-applies the CSS and refreshes token inputs. +- The export button captures only manually overridden tokens, not stylesheet preset values. +- Manual overrides (blue) visually override preset changes (amber) on the same token. +- Section headers turn blue for manual overrides and amber for preset changes. +- "Show Diagrams" toggles all diagrams at once; individual 🖼 icons toggle one at a time. +- Built-in presets from `presets/` directory load on startup and appear in the radio list. +- Contrast badges on foreground color tokens update when either the foreground or background token changes. diff --git a/packages/ckeditor5/tests/manual/presets/ai-demo.css b/packages/ckeditor5/tests/manual/presets/ai-demo.css new file mode 100644 index 00000000000..1d6512aa087 --- /dev/null +++ b/packages/ckeditor5/tests/manual/presets/ai-demo.css @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +:root { + /* ---- Foundation ---- */ + --ck-radius-base: 5px; + --ck-spacing-sm: 5px; + + /* ---- Semantic layer overrides ---- */ + + /* Note: --ck-border-radius-control and --ck-border-radius-surface inherit from + * --ck-radius-base automatically — no need to override them separately. */ + + /* Spacing — override semantic spacing roles instead of foundation scale. + * Controls get more breathing room. */ + --ck-spacing-control-padding-block: 3px; + --ck-spacing-control-padding-inline: 8px; + --ck-spacing-control-padding-inline-compact: var(--ck-spacing-sm); + --ck-spacing-surface-padding-inline: var(--ck-spacing-sm); + --ck-spacing-surface-padding-block: var(--ck-spacing-sm); + --ck-spacing-surface-item-gap-inline: var(--ck-spacing-sm); + + /* Surface colors. */ + --ck-color-border-control: hsl(220, 8%, 85%); + --ck-color-border-container: hsl(220, 8%, 85%); + --ck-color-text-primary: hsl(0, 0%, 25%); + + /* Surface shadow — override the semantic floating shadow. */ + --ck-shadow-surface-floating: 3px 3px 17px hsla(0, 0%, 0%, 0.2), 0 0 3px hsla(0, 0%, 0%, 0.1); + + /* ---- Component layer overrides ---- */ + + /* Color grid: smaller tiles, tight gap, no tile radius, zoom on hover. */ + --ck-color-grid-tile-size: 20px; + --ck-color-grid-gap: 1px; + --ck-color-grid-tile-border-radius: 0; + --ck-color-grid-tile-hover-transform: scale(1.3); + --ck-color-grid-tile-hover-layer: 1; + --ck-color-grid-margin: var(--ck-spacing-sm); + --ck-color-grid-padding: 0; + + /* Color selector: add inner spacing, remove color-picker divider border. */ + --ck-color-selector-padding: var(--ck-spacing-sm); + --ck-color-selector-color-picker-border-top: none; + + /* Toolbar: custom horizontal padding and item gap. */ + --ck-toolbar-padding: 0 7px; + --ck-toolbar-item-gap-inline: 7px; + + /* No arrows for balloon panels. */ + --ck-balloon-panel-arrow-display: none; + + /* Wider list items and spacier lists/dropdowns. */ + --ck-list-item-min-width: 17em; + --ck-list-padding: var(--ck-spacing-sm); + --ck-list-item-button-border-radius: var(--ck-radius-base); + --ck-dropdown-panel-padding: 0; + + /* Disable attached-corner behavior — uniform radius on all panels. */ + --ck-border-radius-uniform: var(--ck-radius-base); + + /* Dropdown list background — transparent to respect panel corners. */ + --ck-dropdown-list-background-color: transparent; + + /* Vertical toolbar buttons and menu bar items — allow radius. */ + --ck-toolbar-vertical-button-border-radius: var(--ck-radius-base); + --ck-menu-bar-button-border-radius: var(--ck-radius-base); + --ck-menu-bar-list-item-button-border-radius: var(--ck-radius-base); + + /* Menu bar item width. */ + --ck-menu-bar-menu-item-min-width: 20em; + + /* Form header — auto height with custom padding. */ + --ck-form-header-padding-block: 7.1px; + + /* Switch button toggle inner radius. */ + --ck-switch-button-toggle-inner-border-radius: calc(0.9 * var(--ck-radius-base)); + + /* Font family. */ + --ck-font-family: -apply-system, system-ui, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";; + + /* Input fields. */ + --ck-input-padding: var(--ck-spacing-control-padding-block-compact) calc(var(--ck-spacing-unit) * .8); + + /* Other packages (not ckeditor5-ui). */ + --ck-image-insert-form-padding: var(--ck-spacing-sm); + --ck-insert-table-dropdown-box-width: 15px; + --ck-insert-table-dropdown-box-height: 15px; + --ck-ai-chat-font-family: var(--ck-font-family); + --ck-user-avatar-size: 35px; + --ck-color-link-default: var(--ck-content-link-color); + --ck-link-panel-width: 400px; + + /* ---- Comments ---- */ + --ck-color-annotation-wrapper-drop-shadow: 0 0 3px hsla(0, 0%, 0%, 0.1); + --ck-color-comment-background: hsl(0, 0%, 100%); + + --ai-demo-container-width: clamp( 1100px, calc( 100vw - 40px), 1500px); + --ai-demo-container-min-height: 500px; + --ai-demo-container-max-height: min(85vh, 800px); + /* Layout spacing */ + --ai-demo-spacing-large: calc(2 * var(--ck-spacing-large)); + --ai-editor-padding: 20mm 12mm; + /* Editor dimensions */ + --ai-editor-max-width: 210mm; + --ai-editor-min-height: 300px; + /* Sidebar dimensions */ + --ai-sidebar-width: 400px; + /* Colors and shadows */ + --ai-shadow-medium: 0 2px 15px hsla(0, 0%, 0%, 0.08), 0 2px 3px hsla(0, 0%, 0%, 0.078); + --ai-border-color: var(--ck-color-base-border); + --ai-content-bg: hsl(0, 0%, 100%); + --ck-sidebar-width: 325px; +} + +/* ------------------------------------------------------------------------------------------------ + Remaining overrides that still require CSS selectors. +*/ + +/* TODO: What's this supposed to do? I inherited it from some earlier prototype. */ +.ck-mentions .mention__item { + display: block; +} + +.ck-mentions .mention__item img { + border-radius: 100%; + height: 30px; +} + +.ck-mentions .mention__item span { + margin-left: .5em; +} + +.ck-mentions .mention__item.ck-on span { + color: var(--ck-color-base-background); +} + +.ck-mentions .mention__item .mention__item__full-name { + color: hsl(0, 0%, 45%); +} + +.ck-mentions .mention__item:hover:not(.ck-on) .mention__item__full-name { + color: hsl(0, 0%, 40%); +} + +/* ------------------------------------------------------------------------------------------------ + Overrides for other packages (AI, comments, link, etc.) — not part of ckeditor5-ui tokens. +*/ + +/* Fix: AI sidebar should not be rounded. */ +.ai-integration__sidebar .ck-tab-panel, +.ai-integration__sidebar .ck-ai-tabs, +.ai-integration__sidebar .ck-ai-chat, +.ai-integration__sidebar .ck-ai-header_chat { + border-radius: 0 !important; +} + +/* Attach context dropdown. */ +.ck.ck-ai-chat-context-controls__add-context-balloon-panel { + padding: var(--ck-spacing-sm); +} + +/* Fix the uneven height of toolbar vs chat header. */ +.ck-form__header.ck-ai-header { + height: auto; + padding-top: 7.1px; + padding-bottom: 7.1px; +} + +/* Moaaaar radius for AI :D. */ +.ck-ai-chat-controls .ck-textarea.ck-input { + border-radius: var(--ck-ai-border-radius); + padding-left: 15px; + line-height: 1 +} +.ck-ai-chat-controls .ck-ai-chat__prompt-submit-button { + border-radius: var(--ck-ai-border-radius) !important; +} + +/* ------------------------------------------------------------------------------------------------ + Comments +*/ + +/* Hide the vertical line connecting comments. */ +.ck .ck-comment::after { + display: none; +} + +/* Tune down inactive comments. */ +.ck.ck-annotation-wrapper { + filter: grayscale(0.2); + opacity: 0.9; +} + +.ck.ck-annotation-wrapper--active { + filter: none; + opacity: 1; +} + +.ck .ck-annotation__info-name, .ck .ck-annotation__info-time { + font-size: 12px; + font-weight: 400; +} + +.ck .ck-annotation__info-name { + font-weight: 600; + color: var(--ck-color-text-primary); +} + +/* It's completely unstyled by default by the editor. */ +.ck .ck-suggestion-type { + color: var(--ck-color-text-primary); +} +.ck-annotation .ck.ck-user { + --ck-user-avatar-size: 25px; +} +.ck.ck-user.ck-user_me { + border-width: 1px; + outline-width: 1px; + /* stylelint-disable-next-line declaration-property-value-disallowed-list */ + border-color: color-mix(in srgb, var(--ck-user-avatar-background), hsl(0, 0%, 100%) 60%); +} + +.ck-annotation__info { + line-height: 34px; +} +.ck-annotation__content-wrapper { + padding: var(--ck-spacing-sm) 0; +} +.ck-comment__input .ck-content * { + font-family: var(--ck-font-family); + font-size: var(--ck-comment-content-font-size); +} + +.ck .ck-thread__comment-count { + font-weight: 600; +} +.ck .ck-comment__wrapper:focus { + background-color: hsl(0, 0%, 96%); +} + +/* Remove minimize/maximize button from AI chat */ +.ck-ai-tabs__resize { + display: none !important; +} + +/* Fix trimmed thread header in comments archive */ +.ck-context-wrapper { + height: 30px !important; +} diff --git a/packages/ckeditor5/tests/manual/presets/dark-theme.css b/packages/ckeditor5/tests/manual/presets/dark-theme.css new file mode 100644 index 00000000000..97dc94e0ced --- /dev/null +++ b/packages/ckeditor5/tests/manual/presets/dark-theme.css @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +/* + * Dark theme — comprehensive dark mode with WCAG-aware contrast. + * + * Palette: + * Surface 1 (base): hsl(240, 6%, 14%) — main background + * Surface 2 (raised): hsl(240, 5%, 18%) — cards, panels + * Surface 3 (elevated): hsl(240, 4%, 22%) — hover, raised elements + * Surface 4 (borders): hsl(240, 4%, 30%) — borders, dividers + * Text primary: hsl(0, 0%, 93%) — main text (~14:1 on surface-1) + * Text secondary: hsl(0, 0%, 70%) — secondary text (~7:1) + * Text disabled: hsl(0, 0%, 50%) — disabled text (~3.5:1) + * Brand (teal): hsl(168, 72%, 44%) — primary action + * Focus (blue): hsl(210, 90%, 62%) — focus rings + */ + +:root { + /* ---- App palette ---- */ + --app-surface-1: hsl(240, 6%, 14%); + --app-surface-2: hsl(240, 5%, 18%); + --app-surface-3: hsl(240, 4%, 22%); + --app-surface-4: hsl(240, 4%, 30%); + --app-text-1: hsl(0, 0%, 93%); + --app-text-2: hsl(0, 0%, 70%); + --app-text-3: hsl(0, 0%, 50%); + --app-focus-hsl: 210, 90%, 62%; + --app-brand: hsl(168, 72%, 44%); + --app-brand-hover: hsl(168, 72%, 38%); + --app-brand-contrast: hsl(0, 0%, 100%); + + /* ---- Foundation ---- */ + --ck-font-size-base: 14px; + --ck-spacing-unit: 0.65em; + --ck-radius-base: 6px; + + /* Base colors */ + --ck-color-base-background: var(--app-surface-1); + --ck-color-base-foreground: var(--app-surface-2); + --ck-color-base-border: var(--app-surface-4); + --ck-color-base-border-light: hsl(240, 4%, 26%); + --ck-color-base-text: var(--app-text-1); + --ck-color-base-text-light: var(--app-text-2); + + /* Interactive base */ + --ck-color-base-hover: var(--app-surface-3); + --ck-color-base-active: hsl(210, 60%, 50%); + --ck-color-base-active-focus: hsl(210, 65%, 45%); + --ck-color-base-selected: hsl(210, 40%, 22%); + --ck-color-base-selected-hover: hsl(210, 42%, 26%); + --ck-color-base-focus: hsl(210, 80%, 58%); + --ck-color-base-focus-shadow: hsla(210, 90%, 50%, .35); + --ck-color-base-focus-shadow-faded: hsla(210, 90%, 50%, .15); + + /* Action (teal) */ + --ck-color-base-action: var(--app-brand); + --ck-color-base-action-hover: var(--app-brand-hover); + + /* Feedback */ + --ck-color-base-error: hsl(0, 80%, 62%); + --ck-color-base-error-shadow: hsla(0, 80%, 50%, .3); + --ck-color-base-warning: hsl(35, 90%, 55%); + --ck-color-base-success: hsl(145, 60%, 42%); + --ck-color-base-highlight: hsl(50, 90%, 50%); + --ck-color-base-attention: hsl(43, 90%, 55%); + + /* Shadows — stronger for dark backgrounds */ + --ck-color-shadow-drop: hsla(0, 0%, 0%, 0.4); + --ck-color-shadow-drop-active: hsla(0, 0%, 0%, 0.55); + --ck-color-shadow-inner: hsla(0, 0%, 0%, 0.3); + + /* ---- Semantic — surfaces ---- */ + --ck-color-surface-canvas: var(--app-surface-1); + --ck-color-surface-control: var(--app-surface-2); + --ck-color-surface-container: var(--app-surface-2); + --ck-color-surface-inverse: hsl(0, 0%, 90%); + + /* ---- Semantic — borders ---- */ + --ck-color-border-control: var(--app-surface-4); + --ck-color-border-container: var(--app-surface-4); + --ck-color-divider: hsl(240, 4%, 26%); + + /* ---- Semantic — text ---- */ + --ck-color-text-primary: var(--app-text-1); + --ck-color-text-secondary: var(--app-text-2); + --ck-color-text-disabled: var(--app-text-3); + --ck-color-text-inverse: hsl(240, 6%, 14%); + --ck-color-text-error: hsl(0, 80%, 65%); + + /* ---- Semantic — feedback ---- */ + --ck-color-feedback-error: hsl(0, 80%, 62%); + --ck-color-feedback-warning: hsl(35, 90%, 55%); + --ck-color-feedback-success: hsl(145, 60%, 42%); + --ck-color-feedback-highlight: hsl(50, 90%, 50%); + + /* ---- Semantic — interactive ---- */ + --ck-color-interactive-hover-surface: var(--app-surface-3); + --ck-color-interactive-active-surface: hsl(240, 5%, 12%); + --ck-color-interactive-selected-surface: hsl(210, 40%, 22%); + --ck-color-interactive-selected-surface-hover: hsl(210, 42%, 26%); + --ck-color-interactive-selected-text: hsl(205, 100%, 74%); + --ck-color-interactive-primary-surface: var(--app-brand); + --ck-color-interactive-primary-surface-hover: var(--app-brand-hover); + --ck-color-interactive-primary-text: var(--app-brand-contrast); + --ck-color-interactive-focus-border-coordinates: var(--app-focus-hsl); + --ck-color-interactive-focus-shadow: hsla(210, 90%, 62%, .3); + --ck-color-interactive-focus-disabled-shadow: hsla(210, 90%, 62%, .12); + --ck-color-interactive-focus-error-shadow: hsla(0, 80%, 50%, .3); + + /* ---- Semantic — shape ---- */ + --ck-border-radius-control: 6px; + --ck-border-radius-surface: 8px; + --ck-shadow-surface-floating: 0 6px 20px 2px hsla(0, 0%, 0%, .5), 0 0 3px hsla(0, 0%, 0%, .25); + + /* ---- Component — button ---- */ + --ck-button-default-background-color: transparent; + --ck-button-default-hover-background-color: var(--app-surface-3); + --ck-button-default-active-background-color: hsl(240, 5%, 12%); + --ck-button-default-disabled-background-color: transparent; + --ck-button-on-background-color: hsl(210, 40%, 22%); + --ck-button-on-hover-background-color: hsl(210, 42%, 26%); + --ck-button-on-active-background-color: hsl(210, 42%, 26%); + --ck-button-on-disabled-background-color: hsl(240, 4%, 22%); + --ck-button-on-text-color: hsl(205, 100%, 74%); + --ck-button-action-background-color: var(--app-brand); + --ck-button-action-hover-background-color: var(--app-brand-hover); + --ck-button-action-active-background-color: hsl(168, 72%, 34%); + --ck-button-action-disabled-background-color: hsl(168, 30%, 30%); + --ck-button-action-text-color: var(--app-brand-contrast); + --ck-button-save-color: hsl(145, 60%, 50%); + --ck-button-cancel-color: hsl(0, 80%, 62%); + --ck-button-border-radius: var(--ck-border-radius-control); + + /* ---- Component — input ---- */ + --ck-input-background-color: var(--app-surface-1); + --ck-input-border-color: var(--app-surface-4); + --ck-input-text-color: var(--app-text-1); + --ck-input-disabled-background-color: hsl(240, 4%, 16%); + --ck-input-disabled-border-color: hsl(240, 4%, 24%); + --ck-input-disabled-text-color: var(--app-text-3); + --ck-input-error-border-color: hsl(0, 80%, 50%); + --ck-input-border-radius: var(--ck-border-radius-control); + + /* ---- Component — toolbar ---- */ + --ck-toolbar-background-color: var(--app-surface-2); + --ck-toolbar-border-color: var(--app-surface-4); + --ck-toolbar-border-radius: var(--ck-border-radius-surface); + + /* ---- Component — dropdown ---- */ + --ck-dropdown-panel-background-color: var(--app-surface-2); + --ck-dropdown-panel-border-color: var(--app-surface-4); + + /* ---- Component — list ---- */ + --ck-list-background-color: transparent; + --ck-list-button-hover-background-color: var(--app-surface-3); + --ck-list-button-on-background-color: hsl(210, 40%, 22%); + --ck-list-button-on-text-color: hsl(205, 100%, 74%); + --ck-list-divider-color: hsl(240, 4%, 26%); + + /* ---- Component — switch button ---- */ + --ck-switch-button-off-background-color: hsl(240, 4%, 30%); + --ck-switch-button-off-hover-background-color: hsl(240, 4%, 35%); + --ck-switch-button-on-background-color: var(--app-brand); + --ck-switch-button-on-hover-background-color: var(--app-brand-hover); + --ck-switch-button-inner-background-color: hsl(0, 0%, 95%); + + /* ---- Component — dialog ---- */ + --ck-dialog-background-color: var(--app-surface-2); + --ck-dialog-border-radius: var(--ck-border-radius-surface); + --ck-dialog-overlay-background-color: hsla(0, 0%, 0%, 0.6); + --ck-dialog-drop-shadow: 0 10px 24px 2px hsla(0, 0%, 0%, .5); + + /* ---- Component — balloon panel ---- */ + --ck-balloon-panel-background-color: var(--app-surface-2); + --ck-balloon-panel-border-color: var(--app-surface-4); + + /* ---- Component — tooltip ---- */ + --ck-tooltip-background-color: hsl(0, 0%, 90%); + --ck-tooltip-text-color: hsl(240, 6%, 14%); + + /* ---- Component — labeled field ---- */ + --ck-labeled-field-label-background-color: var(--app-surface-2); + + /* ---- Misc / content ---- */ + --ck-color-widget-blurred-border: hsl(240, 4%, 35%); + --ck-color-widget-hover-border: hsl(43, 80%, 55%); + --ck-color-widget-editable-focus-background: var(--app-surface-1); + --ck-color-link-default: hsl(210, 100%, 70%); +} + +/* Content area */ +.ck.ck-editor__editable { + background: var(--app-surface-1); + color: var(--app-text-1); +} + +.ck.ck-editor__editable a { + color: hsl(210, 100%, 70%); +} + +.ck-content pre { + background: hsl(240, 6%, 12%); + color: hsl(0, 0%, 91%); + border-color: hsl(240, 4%, 26%); +} + +.ck-content blockquote { + border-left-color: var(--app-surface-4); +} + +.ck-content hr { + border-color: var(--app-surface-4); +} + +.ck-content table, .ck-content th, .ck-content td { + border-color: var(--app-surface-4); +} + +.ck-content th { + background: var(--app-surface-3); +} diff --git a/packages/ckeditor5/tests/manual/presets/index.js b/packages/ckeditor5/tests/manual/presets/index.js new file mode 100644 index 00000000000..42bd2a81625 --- /dev/null +++ b/packages/ckeditor5/tests/manual/presets/index.js @@ -0,0 +1,18 @@ +/** + * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options + */ + +/** + * Manifest of stylesheet presets available for the Design Token Explorer. + * + * To add a new preset: + * 1. Drop a .css file into this directory. + * 2. Add the filename to the array below. + * + * The name shown in the panel is derived from the filename + * (e.g. "dark-theme.css" → "dark-theme"). + */ +export const presetFiles = [ + 'ai-demo.css' +];