@ckeditor/ckeditor5-ai
Version:
AI features for CKEditor 5.
407 lines (342 loc) • 11.4 kB
CSS
/*
* What you're currently looking at is the source code of a legally protected, proprietary software.
* CKEditor 5 Collaboration is licensed under a commercial license and protected by copyright law. Where not otherwise indicated,
* all CKEditor 5 Collaboration content is authored by CKSource engineers and consists of CKSource-owned intellectual property.
*
* Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
@import "@ckeditor/ckeditor5-theme-lark/theme/mixins/_rounded.css";
:root {
--ck-ai-chat-feed-item-color-text: hsla(0, 0%, 0%, 1);
--ck-ai-chat-feed-item-color-background: hsla(0, 0%, 96%, 1);
--ck-ai-chat-feed-item-color-background-secondary: hsla(0, 0%, 96%, 1);
--ck-ai-chat-feed-item-color-actions-button-hover: hsla(263, 59%, 40%, 1);
--ck-ai-chat-feed-item-color-show-changes-toggle-hover-color: hsla(263, 59%, 40%, 1);
--ck-ai-chat-feed-item-color-show-changes-toggle-hover-background: hsl(262, 100%, 96%);
--ck-ai-chat-feed-item-color-show-changes-toggle-on-color: hsla(263, 59%, 40%, 1);
--ck-ai-chat-feed-item-color-show-changes-toggle-on-background: hsl(262, 100%, 96%);
--ck-ai-chat-feed-item-color-show-changes-toggle-active-background: hsl(262, 100%, 96%);
--ck-ai-chat-feed-loader-icon-color: hsla(0, 0%, 85%, 1);
--ck-ai-chat-feed-interaction-header-capabilities-color-text: hsla(0, 0%, 44%, 1);
}
.ck.ck-ai-chat__feed {
flex: 1 1 auto;
overflow-y: auto;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
flex-wrap: nowrap;
padding-bottom: var(--ck-spacing-extra-large);
gap: var(--ck-spacing-large);
position: relative;
/*
* Addresses an issue in Chrome where the entire feed gets repainted by the browser's engine when the user
* types in the prompt textarea. See https://github.com/ckeditor/ckeditor5-commercial/issues/8611.
*/
contain: size;
/* This is needed to prevent the feed from overflowing when the skeleton is visible. */
&:has(.ck-ai-skeleton:not(.ck-hidden)) {
overflow: hidden;
}
.ck.ck-ai-chat__feed__items {
display: flex;
flex-direction: column;
gap: var(--ck-spacing-extra-large) 0;
& > .ck-ai-chat__feed__item {
&:first-child {
margin-top: var(--ck-spacing-extra-large);
}
}
}
& .ck.ck-ai-chat__feed__item {
margin: 0 var(--ck-spacing-large);
scroll-margin: var(--ck-spacing-large);
/* These controls show up only after the item is done */
& .ck-ai-mini-toolbar,
& .ck-ai-chat__feed__ai-suggestion__actions,
& .ck-ai-suggestion__header__show-changes-toggle {
transition: opacity .4s, display .4s allow-discrete;
@starting-style {
& {
opacity: 0;
}
}
}
& .ck-ai-chat__feed__ai-suggestion__actions--no-animation {
transition: none;
}
& .ck-ai-suggestion__header__show-changes-toggle {
padding: 0 var(--ck-spacing-small);
min-height: 22px;
font-size: var(--ck-ai-chat-suggestion-container-header-font-size);
> .ck-icon {
width: 16px;
height: 16px;
margin-right: 0;
margin-left: var(--ck-spacing-medium);
}
}
&:not(.ck-ai-chat__feed__item_done) {
& .ck-ai-mini-toolbar,
& .ck-ai-chat__feed__ai-suggestion__actions,
& .ck-ai-suggestion__header__show-changes-toggle {
display: none;
opacity: 0;
}
}
/*
* Any item that contains text (AI replies, suggestions, user messages etc.)
*/
&.ck.ck-ai-chat__feed__text-item {
word-break: normal;
text-wrap: auto;
& pre > code {
white-space: pre-wrap;
}
}
/*
* User message item with a query to the AI
*/
&.ck.ck-ai-chat__feed__user-message {
&:has(.ck-ai-chat-context-chips-wrapper) {
max-width: 100%;
}
& .ck-ai-chat__feed__message-content {
max-width: 80%;
margin-inline-end: 0;
margin-inline-start: auto;
text-align: end;
}
p {
display: inline-block;
background-color: var(--ck-ai-chat-feed-item-color-background-secondary);
padding: var(--ck-spacing-standard);
border-radius: var(--ck-ai-border-radius);
}
}
/*
* Replies from the AI that aren't suggestions.
*
* Also, occasionally used for static notifications.
*/
/* &.ck-ai-chat__feed__ai-reply {} */
/*
* This is the kind of reply from the AI where content changes are suggested.
*/
&.ck-ai-chat__feed__ai-suggestion {
/*
* Actions for the suggestion.
*/
& .ck-ai-chat__feed__ai-suggestion__actions {
--ck-color-split-button-hover-background: var(--ck-ai-background-color-action-button);
margin-top: var(--ck-spacing-medium);
width: fit-content;
& > .ck-button {
--ck-color-button-default-background: var(--ck-ai-background-color-action-button);
--ck-color-button-default-hover-background: var(--ck-ai-chat-feed-item-color-actions-button-hover);
--ck-color-button-on-hover-background: var(--ck-ai-chat-feed-item-color-actions-button-hover);
--ck-color-button-default-active-background: var(--ck-ai-chat-feed-item-color-actions-button-hover);
--ck-color-button-on-background: var(--ck-ai-chat-feed-item-color-actions-button-hover);
--ck-color-button-on-active-background: var(--ck-ai-chat-feed-item-color-actions-button-hover);
--ck-color-focus-border: var(--ck-color-base-background);
--ck-focus-ring: 1px solid var(--ck-color-focus-border);
color: var(--ck-color-base-background);
margin-top: 0;
&.ck-splitbutton__action {
@mixin ck-rounded-corners {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
&.ck-splitbutton__arrow {
width: 1.9em;
color: var(--ck-color-base-background);
/* Separator always visible */
&:after {
content: '';
position: absolute;
width: 1px;
height: 100%;
left: -1px;
background: var(--ck-color-base-background);
}
}
&.ck-disabled {
background: hsl(263, 59%, 52%, 0.5);
}
}
}
}
/*
* Interaction header showing capabilities used for the entire interaction.
*/
&.ck.ck-ai-chat__feed__interaction-header {
& .ck-ai-chat__feed__interaction-header__capabilities {
display: flex;
align-items: center;
gap: 4px;
color: var(--ck-ai-chat-feed-interaction-header-capabilities-color-text);
& svg {
border-radius: 50%;
flex-shrink: 0;
background-color: var(--ck-tabs-panels-container-background);
&:not(:first-child) {
margin-left: calc(var(--ck-icon-size) * -0.75)
}
}
}
& .ck-ai-chat__feed__interaction-header__capabilities__text {
color: var(--ck-ai-chat-feed-interaction-header-capabilities-color-text);
font-weight: 500;
}
}
.ck-ai-chat__feed__ai-reply-container {
> * {
&:first-child {
/* This is needed to clear the default top margin from first HTML element from reply. */
margin-top: 0;
}
&:last-child {
/* This is needed to clear the default bottom margin from last HTML element from reply. */
margin-bottom: 0;
}
}
}
&.ck.ck-ai-chat__feed__ai-suggestion .ck-ai-suggestion__body {
.ck-suggestion-marker-insertion:not([data-author-id="$aiSuggestion"]),
.ck-suggestion-marker-formatInline:not([data-author-id="$aiSuggestion"]),
.ck-suggestion-marker-deletion:not([data-author-id="$aiSuggestion"]) {
border-top: 3px solid var(--ck-ai-suggestion-inactive-color-border);
border-bottom: 3px solid var(--ck-ai-suggestion-inactive-color-border);
background: var(--ck-ai-suggestion-inactive-color-background);
&.ck-widget {
border: 3px solid var(--ck-ai-suggestion-inactive-color-border);
}
}
.ck-suggestion-marker-formatBlock:not([data-author-id="$aiSuggestion"]) {
box-shadow: -7px 0 0 0 var(--ck-color-base-background), -10px 0 0 0 var(--ck-ai-suggestion-inactive-color-background);
}
.ck-suggestion-marker-deletion:not([data-author-id="$aiSuggestion"]) {
text-decoration: line-through;
text-decoration-thickness: 3px;
text-decoration-color: var(--ck-ai-suggestion-inactive-color-border);
}
.ck-suggestion-marker-insertion.table > tbody > tr > td {
background-color: var(--ck-color-suggestion-widget-insertion-background);
}
}
&.ck.ck-ai-chat__feed__ai-suggestion .ck-ai-suggestion__body *,
&.ck.ck-ai-chat__feed__text-item
*:not(.ck-ai-chat__feed__context-chips):not(.ck-ai-chat__feed__context-chips *):not(.ck-ai-web-source .ck-button__label) {
white-space: normal;
line-height: 1.4em;
}
/* TODO: This CSS class is added twice. */
& .ck-ai-chat__feed__context-chips {
display: flex;
justify-content: flex-end;
margin-bottom: var(--ck-spacing-medium-small);
}
/* stylelint-disable-next-line no-descending-specificity */
& .ck-ai-web-sources {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--ck-spacing-standard);
padding: var(--ck-spacing-medium-small) var(--ck-spacing-large) var(--ck-spacing-extra-large) var(--ck-spacing-large);
& > .ck-ai-web-sources__header {
grid-column-start: span 3;
font-size: 12px;
font-weight: 500;
line-height: 1.4em;
& > .ck-icon {
vertical-align: text-bottom;
width: 14px;
height: 14px;
margin-right: var(--ck-spacing-medium-small);
color: hsl(0, 0%, 44%);
}
& > span {
color: hsl(0, 0%, 44%);
}
}
& > .ck-ai-web-source {
padding: var(--ck-spacing-medium) var(--ck-spacing-large);
border: 0;
border-radius: 50px;
background-color: var(--ck-ai-chat-feed-item-color-background);
&:hover {
background-color: var(--ck-ai-chat-button-active-background-color);
}
&:focus, &:active {
box-shadow: none;
}
& .ck-ai-web-source__image,
& .ck-button__icon {
margin-right: var(--ck-spacing-medium);
color: var(--ck-ai-button-primary-background-color);
width: 16px;
height: 16px;
}
& .ck-button__label {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 75px;
font-size: 10px;
font-weight: 700;
line-height: 1.4em;
}
& .ck-ai-web-source__title {
display: flex;
align-items: center;
gap: var(--ck-spacing-small);
}
}
}
/* Remove padding if it's directly inside the reply container as the padding is already set. */
& > .ck-ai-web-sources {
padding: var(--ck-spacing-extra-large) 0 var(--ck-spacing-medium) 0;
}
}
& .ck.ck-ai-chat__loader {
display: flex;
align-items: flex-start;
& .ck.ck-spinner-container.ck-ai-spinner {
/* Designs have 16px but it needs to be aligned with chat feed items */
margin: 0 var(--ck-spacing-large);
}
& .ck.ck-ai-chat__loader-text {
font-weight: 500;
line-height: 1.462em;
white-space: normal;
}
}
}
/**
* This is the balloon panel for the suggestion actions.
*/
.ck-ai-chat__feed__ai-suggestion__actions__balloon {
&.ck-balloon-panel {
z-index: calc(var(--ck-ai-tabs-overlay-z-index) + 1);
}
& .ck-list__item {
min-width: fit-content;
}
& .ck-button.ck-list-item-button {
padding-top: 0;
padding-bottom: 0;
&:hover:not(.ck-disabled) {
background-color: var(--ck-ai-button-secondary-hover-background-color);
}
}
}
@keyframes ck-html-streamer-fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}