UNPKG

@ckeditor/ckeditor5-ai

Version:

AI features for CKEditor 5.

407 lines (342 loc) • 11.4 kB
/* * 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; } }