@youcan/celeste 0.6.30 → 0.6.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/celeste.css +483 -264
  2. package/dist/cjs/alert.js +2 -2
  3. package/dist/cjs/chunks/index.js +229 -2
  4. package/dist/cjs/chunks/index2.js +1457 -0
  5. package/dist/cjs/chunks/index3.js +16457 -0
  6. package/dist/cjs/chunks/sonner.js +1154 -0
  7. package/dist/cjs/config.js +136 -0
  8. package/dist/cjs/extra-settings.js +155 -0
  9. package/dist/cjs/index.js +75 -0
  10. package/dist/cjs/label.js +2 -2
  11. package/dist/cjs/link-bubble.js +228 -0
  12. package/dist/cjs/link-button.js +2 -2
  13. package/dist/cjs/rich-editor.js +4996 -0
  14. package/dist/cjs/select-icon.js +2 -2
  15. package/dist/cjs/sonner-alert.js +41 -0
  16. package/dist/cjs/sonner.js +3 -0
  17. package/dist/cjs/text-input-affix.js +2 -2
  18. package/dist/cjs/types.js +1 -0
  19. package/dist/components/index.d.ts +2 -0
  20. package/dist/components/rich-editor/config.d.ts +33 -0
  21. package/dist/components/rich-editor/extra-settings.d.ts +6 -0
  22. package/dist/components/rich-editor/index.d.ts +2 -0
  23. package/dist/components/rich-editor/link-bubble.d.ts +11 -0
  24. package/dist/components/rich-editor/rich-editor.d.ts +55 -0
  25. package/dist/components/rich-editor/types.d.ts +19 -0
  26. package/dist/components/sonner/index.d.ts +4 -0
  27. package/dist/components/sonner/sonner-alert.d.ts +13 -0
  28. package/dist/components/sonner/sonner.d.ts +5 -0
  29. package/dist/es/alert.js +2 -2
  30. package/dist/es/checkbox-label.js +1 -1
  31. package/dist/es/chunks/index.js +277 -50
  32. package/dist/es/chunks/index2.js +1457 -0
  33. package/dist/es/chunks/index3.js +16458 -0
  34. package/dist/es/chunks/sonner.js +1155 -0
  35. package/dist/es/combobox-group.js +1 -1
  36. package/dist/es/combobox-input.js +1 -1
  37. package/dist/es/combobox-item.js +1 -1
  38. package/dist/es/combobox-list.js +1 -1
  39. package/dist/es/combobox-root.js +1 -1
  40. package/dist/es/combobox-separator.js +1 -1
  41. package/dist/es/combobox-trigger.js +1 -1
  42. package/dist/es/command-group.js +1 -1
  43. package/dist/es/command-input.js +1 -1
  44. package/dist/es/command-item.js +1 -1
  45. package/dist/es/command-list.js +1 -1
  46. package/dist/es/command-root.js +1 -1
  47. package/dist/es/command-separator.js +1 -1
  48. package/dist/es/config.js +136 -0
  49. package/dist/es/dropdown-menu-group.js +1 -1
  50. package/dist/es/dropdown-menu-item.js +1 -1
  51. package/dist/es/dropdown-menu-label.js +1 -1
  52. package/dist/es/dropdown-menu-separator.js +1 -1
  53. package/dist/es/dropdown-menu-trigger.js +1 -1
  54. package/dist/es/dropdown-menu.js +1 -1
  55. package/dist/es/dropdown.js +1 -1
  56. package/dist/es/extra-settings.js +156 -0
  57. package/dist/es/index.js +94 -19
  58. package/dist/es/label.js +3 -3
  59. package/dist/es/link-bubble.js +229 -0
  60. package/dist/es/link-button.js +2 -2
  61. package/dist/es/modal-content.js +1 -1
  62. package/dist/es/modal-header.js +1 -1
  63. package/dist/es/popover-content.js +1 -1
  64. package/dist/es/popover-trigger.js +1 -1
  65. package/dist/es/rich-editor.js +4997 -0
  66. package/dist/es/scroll-bar.js +1 -1
  67. package/dist/es/segmented-control-item.js +1 -1
  68. package/dist/es/segmented-control.js +1 -1
  69. package/dist/es/select-content.js +1 -1
  70. package/dist/es/select-icon.js +2 -2
  71. package/dist/es/select-item.js +1 -1
  72. package/dist/es/select-trigger.js +1 -1
  73. package/dist/es/select-value.js +1 -1
  74. package/dist/es/sonner-alert.js +42 -0
  75. package/dist/es/sonner.js +4 -0
  76. package/dist/es/tab-menu-content.js +1 -1
  77. package/dist/es/tab-menu-item.js +1 -1
  78. package/dist/es/tab-menu-list.js +1 -1
  79. package/dist/es/tab-menu.js +1 -1
  80. package/dist/es/text-input-affix.js +2 -2
  81. package/dist/es/tooltip.js +1 -1
  82. package/dist/es/types.js +1 -0
  83. package/dist/index.d.ts +1 -0
  84. package/dist/utils/index.d.ts +3 -0
  85. package/dist/utils/sonner.d.ts +19 -0
  86. package/package.json +15 -4
  87. package/src/components/index.ts +2 -0
  88. package/src/components/rich-editor/config.ts +150 -0
  89. package/src/components/rich-editor/extra-settings.vue +151 -0
  90. package/src/components/rich-editor/index.ts +2 -0
  91. package/src/components/rich-editor/link-bubble.vue +288 -0
  92. package/src/components/rich-editor/rich-editor.vue +428 -0
  93. package/src/components/rich-editor/stories/rich-editor.stories.ts +87 -0
  94. package/src/components/rich-editor/types.ts +21 -0
  95. package/src/components/sonner/index.ts +5 -0
  96. package/src/components/sonner/sonner-alert.vue +54 -0
  97. package/src/components/sonner/sonner.vue +13 -0
  98. package/src/components/sonner/stories/sonner.stories.ts +194 -0
  99. package/src/index.ts +1 -0
  100. package/src/utils/index.ts +3 -0
  101. package/src/utils/sonner.ts +72 -0
@@ -0,0 +1,288 @@
1
+ <script setup lang="ts">
2
+ import type { Editor } from '@tiptap/vue-3';
3
+ import Button from '@/components/button/button.vue';
4
+ import CompactButton from '@/components/button/compact-button.vue';
5
+ import LinkButton from '@/components/button/link-button.vue';
6
+ import Label from '@/components/label/label.vue';
7
+ import Switch from '@/components/switch/switch.vue';
8
+ import TextInputAffix from '@/components/text-input/text-input-affix.vue';
9
+ import TextInput from '@/components/text-input/text-input.vue';
10
+ import { computed, defineAsyncComponent, onMounted, onUnmounted, ref } from 'vue';
11
+
12
+ const props = defineProps<{
13
+ editor: Editor;
14
+ showSetLinkFromToolbar: boolean;
15
+ }>();
16
+
17
+ const emit = defineEmits(['set-link-closed']);
18
+
19
+ const BubbleMenu = defineAsyncComponent(() =>
20
+ import('@tiptap/vue-3/menus').then(m => m.BubbleMenu),
21
+ );
22
+
23
+ const href = ref('');
24
+ const openInNewTab = ref(false);
25
+ const editing = ref(false);
26
+ const isTextSelected = () => props.editor.state.selection.from !== props.editor.state.selection.to;
27
+
28
+ const showBubble = computed(() => {
29
+ return editing.value
30
+ || props.editor.isActive('link')
31
+ || (props.showSetLinkFromToolbar && isTextSelected());
32
+ });
33
+
34
+ function startEdit() {
35
+ editing.value = true;
36
+
37
+ const attrs = props.editor.getAttributes('link');
38
+ href.value = attrs.href || '';
39
+ openInNewTab.value = attrs.target === '_blank';
40
+ }
41
+
42
+ function removeLink() {
43
+ props.editor.chain().focus().unsetLink().run();
44
+ reset();
45
+ }
46
+
47
+ function reset() {
48
+ editing.value = false;
49
+ href.value = '';
50
+ openInNewTab.value = false;
51
+ emit('set-link-closed');
52
+ }
53
+
54
+ function truncateMiddleUrl(str: string) {
55
+ const maxLength = 40;
56
+
57
+ if (str.length <= maxLength) {
58
+ return str;
59
+ }
60
+
61
+ const startChars = Math.ceil((maxLength - 3) / 2);
62
+ const endChars = Math.floor((maxLength - 3) / 2);
63
+
64
+ return `${str.slice(0, startChars)}...${str.slice(-endChars)}`;
65
+ }
66
+
67
+ function isAllowedUri(): boolean {
68
+ const url = href.value.trim();
69
+
70
+ if (!url || url.includes(' ')) {
71
+ return false;
72
+ }
73
+
74
+ if (url.startsWith('/')) {
75
+ return true;
76
+ }
77
+
78
+ if (url.startsWith('./') || url.startsWith('../')) {
79
+ return false;
80
+ }
81
+
82
+ const allowedProtocols = /^(?:https?:|mailto:)/i;
83
+ const disallowedProtocols = /^(?:javascript:|data:)/i;
84
+
85
+ if (disallowedProtocols.test(url)) {
86
+ return false;
87
+ }
88
+
89
+ if (allowedProtocols.test(url)) {
90
+ return true;
91
+ }
92
+
93
+ return false;
94
+ }
95
+
96
+ const isValidUrl = computed(() => isAllowedUri());
97
+
98
+ function applyLink() {
99
+ if (!href.value || !isValidUrl.value) {
100
+ return;
101
+ }
102
+
103
+ props.editor
104
+ .chain()
105
+ .focus()
106
+ .extendMarkRange('link')
107
+ .setLink({
108
+ href: href.value,
109
+ target: openInNewTab.value ? '_blank' : null,
110
+ })
111
+ .run();
112
+
113
+ reset();
114
+ }
115
+
116
+ const bubbleRef = ref<HTMLElement | null>(null);
117
+
118
+ function handleClickOutside(event: Event): void {
119
+ const target = event.target as Element;
120
+
121
+ if (!bubbleRef.value) {
122
+ return;
123
+ }
124
+
125
+ if (bubbleRef.value && bubbleRef.value.contains(target)) {
126
+ return;
127
+ }
128
+
129
+ if (target.closest('.i-celeste-link')) {
130
+ return;
131
+ }
132
+
133
+ emit('set-link-closed');
134
+ }
135
+
136
+ onMounted(() => {
137
+ props.editor.on('selectionUpdate', () => {
138
+ if (props.editor.isActive('link') || props.showSetLinkFromToolbar) {
139
+ const attrs = props.editor.getAttributes('link');
140
+ href.value = attrs.href || '';
141
+ openInNewTab.value = attrs.target === '_blank';
142
+ }
143
+ else {
144
+ reset();
145
+ }
146
+ });
147
+
148
+ document.addEventListener('click', handleClickOutside);
149
+ });
150
+
151
+ onUnmounted(() => {
152
+ document.removeEventListener('click', handleClickOutside);
153
+ });
154
+ </script>
155
+
156
+ <template>
157
+ <BubbleMenu
158
+ :should-show="() => true"
159
+ :editor="editor"
160
+ :options="{
161
+ placement: 'bottom',
162
+ offset: {
163
+ mainAxis: 0,
164
+ crossAxis: 12,
165
+ },
166
+ }"
167
+ >
168
+ <div
169
+ v-if="showBubble"
170
+ ref="bubbleRef"
171
+ class="link-bubble"
172
+ >
173
+ <template v-if="editing || (props.showSetLinkFromToolbar && isTextSelected())">
174
+ <div class="set-mode">
175
+ <div class="set-link">
176
+ <TextInput
177
+ v-model="href"
178
+ type="url"
179
+ size="xs"
180
+ placeholder="Paste or type a link"
181
+ class="link-input"
182
+ @keydown.enter="applyLink"
183
+ @keydown.esc="reset"
184
+ >
185
+ <template #leadingNode>
186
+ <TextInputAffix>
187
+ <i class="i-celeste-link" />
188
+ </TextInputAffix>
189
+ </template>
190
+ </TextInput>
191
+ <Button
192
+ intent="neutral"
193
+ size="xs"
194
+ variant="stroke"
195
+ :disabled="!isValidUrl"
196
+ @click="applyLink"
197
+ >
198
+ Set link
199
+ </Button>
200
+ </div>
201
+ <div class="switch-button-box">
202
+ <Label for="open-in-new-tab">
203
+ Open in new tab
204
+ </Label>
205
+ <Switch id="open-in-new-tab" v-model:checked="openInNewTab" />
206
+ </div>
207
+ </div>
208
+ </template>
209
+
210
+ <template v-else-if="props.editor.isActive('link')">
211
+ <div class="edit-mode">
212
+ <LinkButton
213
+ :href="editor.getAttributes('link').href"
214
+ :target="editor.getAttributes('link').target"
215
+ >
216
+ {{ truncateMiddleUrl(editor.getAttributes('link').href) }}
217
+ </LinkButton>
218
+ <div class="divider" />
219
+ <CompactButton
220
+ icon="i-celeste-edit-line"
221
+ size="lg"
222
+ variant="ghost"
223
+ @click="startEdit"
224
+ />
225
+ <CompactButton
226
+ icon="i-celeste-delete-bin-line"
227
+ size="lg"
228
+ variant="ghost"
229
+ @click="removeLink"
230
+ />
231
+ </div>
232
+ </template>
233
+ </div>
234
+ </BubbleMenu>
235
+ </template>
236
+
237
+ <style scoped lang="scss">
238
+ .link-bubble {
239
+ position: fixed;
240
+ z-index: 1000;
241
+ padding: var(--spacing-12);
242
+ border: 1px solid var(--color-stroke-soft-200);
243
+ border-radius: var(--radius-12);
244
+ background-color: var(--color-bg-white-0);
245
+ box-shadow: var(--shadow-regular-xs);
246
+
247
+ .set-mode {
248
+ display: flex;
249
+ flex-direction: column;
250
+ gap: var(--spacing-12);
251
+
252
+ .set-link {
253
+ display: flex;
254
+ gap: var(--spacing-8);
255
+ }
256
+
257
+ :deep(.celeste-switch[aria-checked='true']) {
258
+ background-color: var(--color-neutral-700);
259
+ }
260
+
261
+ .switch-button-box {
262
+ display: flex;
263
+ align-items: center;
264
+ gap: var(--spacing-8);
265
+ }
266
+ }
267
+
268
+ .edit-mode {
269
+ display: flex;
270
+ align-items: center;
271
+ gap: var(--spacing-8);
272
+
273
+ .divider {
274
+ width: 1px;
275
+ height: 16px;
276
+ margin: 0 3px;
277
+ background: var(--color-stroke-soft-200);
278
+ }
279
+
280
+ & :deep(.celeste-link-button) {
281
+ display: flex;
282
+ border-radius: var(--radius-8);
283
+ color: var(--color-neutral-700);
284
+ gap: var(--spacing-8);
285
+ }
286
+ }
287
+ }
288
+ </style>
@@ -0,0 +1,428 @@
1
+ <script setup lang="ts">
2
+ import type { ToolbarItem } from './types';
3
+ import CompactButton from '@/components/button/compact-button.vue';
4
+ import SelectContent from '@/components/select/select-content.vue';
5
+ import SelectIcon from '@/components/select/select-icon.vue';
6
+ import SelectItem from '@/components/select/select-item.vue';
7
+ import SelectTrigger from '@/components/select/select-trigger.vue';
8
+ import SelectValue from '@/components/select/select-value.vue';
9
+ import Select from '@/components/select/select.vue';
10
+ import Tooltip from '@/components/tooltip/tooltip.vue';
11
+ import Link from '@tiptap/extension-link';
12
+ import TextAlign from '@tiptap/extension-text-align';
13
+ import { TextStyleKit } from '@tiptap/extension-text-style';
14
+ import { CharacterCount, Placeholder } from '@tiptap/extensions';
15
+ import StarterKit from '@tiptap/starter-kit';
16
+ import { Editor, EditorContent } from '@tiptap/vue-3';
17
+ import { computed, onBeforeUnmount, onMounted, type PropType, ref, watch } from 'vue';
18
+ import { fullToolbar, onActionClick, selectedOption } from './config';
19
+ import ExtraSettings from './extra-settings.vue';
20
+ import LinkBubble from './link-bubble.vue';
21
+
22
+ const props = defineProps({
23
+ modelValue: {
24
+ type: String,
25
+ default: '',
26
+ },
27
+ placeholder: {
28
+ type: String,
29
+ default: '',
30
+ },
31
+ customToolbar: {
32
+ type: Array as PropType<string[]>,
33
+ default: () => [],
34
+ },
35
+ maxLimit: {
36
+ type: Number,
37
+ default: null,
38
+ },
39
+ showExtraSettings: {
40
+ type: Boolean,
41
+ default: true,
42
+ },
43
+ });
44
+
45
+ const emit = defineEmits(['update:modelValue']);
46
+
47
+ const filteredToolbar = computed(() => {
48
+ const customToolbar = props.customToolbar;
49
+
50
+ if (!customToolbar || customToolbar.length === 0) {
51
+ return fullToolbar.value;
52
+ }
53
+
54
+ const toolbarMap = new Map(
55
+ fullToolbar.value
56
+ .filter(item => item.type !== 'divider' && 'slug' in item)
57
+ .map(item => [item.slug!, item]),
58
+ );
59
+
60
+ return customToolbar
61
+ .map((key) => {
62
+ if (key === 'divider') {
63
+ return { type: 'divider' };
64
+ }
65
+
66
+ return toolbarMap.get(key);
67
+ })
68
+ .filter((item): item is ToolbarItem => Boolean(item));
69
+ });
70
+
71
+ const editor = ref<Editor | undefined>();
72
+ const showSetLinkFromToolbar = ref<boolean>(false);
73
+
74
+ function openLinkBubbleFromToolbar() {
75
+ showSetLinkFromToolbar.value = true;
76
+ }
77
+
78
+ const charactersCount = computed(() => editor.value?.storage.characterCount.characters() || 0);
79
+ const limitWarning = computed(() => {
80
+ const isCloseToMaxCharacter = charactersCount.value >= (props.maxLimit - 20);
81
+ const isMaxCharacter = charactersCount.value === props.maxLimit;
82
+
83
+ if (isCloseToMaxCharacter && !isMaxCharacter) {
84
+ return 'warning';
85
+ }
86
+
87
+ if (isMaxCharacter) {
88
+ return 'danger';
89
+ }
90
+
91
+ return '';
92
+ });
93
+
94
+ watch(() => props.modelValue, (value) => {
95
+ if (editor.value?.getHTML() === value) {
96
+ return;
97
+ }
98
+
99
+ editor.value?.commands.setContent(value);
100
+ });
101
+
102
+ onMounted(() => {
103
+ editor.value = new Editor({
104
+ content: props.modelValue,
105
+ extensions: [
106
+ StarterKit.configure({
107
+ link: false,
108
+ }),
109
+ Placeholder.configure({
110
+ placeholder: props.placeholder,
111
+ emptyEditorClass: 'is-editor-empty',
112
+ }),
113
+ TextStyleKit.configure({
114
+ color: {
115
+ types: ['textStyle'],
116
+ },
117
+ fontSize: {
118
+ types: ['textStyle'],
119
+ },
120
+ }),
121
+ TextAlign.configure({
122
+ types: ['heading', 'paragraph'],
123
+ }),
124
+ Link.configure({
125
+ openOnClick: false,
126
+ autolink: false,
127
+ HTMLAttributes: {
128
+ class: 'celeste-rich-editor-link',
129
+ rel: null,
130
+ },
131
+ }),
132
+ CharacterCount.configure({
133
+ limit: props.maxLimit,
134
+ }),
135
+ ],
136
+ onUpdate: () => {
137
+ emit('update:modelValue', editor.value?.getHTML() || '');
138
+ },
139
+ });
140
+ });
141
+
142
+ onBeforeUnmount(() => {
143
+ editor.value?.destroy();
144
+ });
145
+ </script>
146
+
147
+ <template>
148
+ <div v-if="editor" class="celeste-rich-editor">
149
+ <div class="toolbar">
150
+ <template v-for="(item, parentIndex) in filteredToolbar" :key="parentIndex">
151
+ <Tooltip
152
+ v-if="item.type !== 'divider' && !item.children"
153
+ :title="item.name"
154
+ variant="dark"
155
+ >
156
+ <CompactButton
157
+ :icon="`${item.icon}`"
158
+ variant="ghost"
159
+ :class="{ active: typeof item.active === 'string' && editor.isActive(item.active) }"
160
+ @click="onActionClick(editor, item.slug, null, openLinkBubbleFromToolbar)"
161
+ />
162
+ </Tooltip>
163
+
164
+ <Tooltip
165
+ v-else-if="item.type !== 'divider' && item.children"
166
+ :title="item.name"
167
+ variant="dark"
168
+ >
169
+ <div class="select-menu-wrapper">
170
+ <Select
171
+ :model-value="selectedOption(editor, item.children)"
172
+ @update:model-value="onActionClick(editor, item.slug, $event)"
173
+ >
174
+ <SelectTrigger variant="inline">
175
+ <SelectValue />
176
+ </SelectTrigger>
177
+ <SelectContent align="end" width="fit">
178
+ <SelectItem
179
+ v-for="(child, childIndex) in item.children"
180
+ :key="childIndex"
181
+ :value="child.option"
182
+ >
183
+ <template v-if="item.slug === 'color'">
184
+ <SelectIcon>
185
+ <i :class="child.icon" :style="{ background: child.option }" />
186
+ </SelectIcon>
187
+ <span>{{ child.name }}</span>
188
+ </template>
189
+ <template v-else-if="item.slug === 'align'">
190
+ <SelectIcon>
191
+ <i :class="child.icon" />
192
+ </SelectIcon>
193
+ </template>
194
+ <span v-else>{{ child.name }}</span>
195
+ </SelectItem>
196
+ </SelectContent>
197
+ </Select>
198
+ </div>
199
+ </Tooltip>
200
+
201
+ <div v-else class="divider" />
202
+ </template>
203
+
204
+ <div v-if="showExtraSettings" class="extra-settings-wrapper">
205
+ <div class="divider" />
206
+ <ExtraSettings
207
+ :editor="editor"
208
+ />
209
+ </div>
210
+ </div>
211
+
212
+ <div class="text-field">
213
+ <EditorContent
214
+ :editor="editor"
215
+ />
216
+ </div>
217
+ <div
218
+ v-if="maxLimit"
219
+ class="characters-count"
220
+ :class="{
221
+ warning: limitWarning === 'warning',
222
+ danger: limitWarning === 'danger',
223
+ }"
224
+ >
225
+ {{ charactersCount }}/{{ maxLimit }}
226
+ </div>
227
+ <LinkBubble
228
+ :editor="editor"
229
+ :show-set-link-from-toolbar="showSetLinkFromToolbar"
230
+ @set-link-closed="showSetLinkFromToolbar = false"
231
+ />
232
+ </div>
233
+ </template>
234
+
235
+ <style lang="scss" scoped>
236
+ .celeste-rich-editor {
237
+ position: relative;
238
+ border: 1px solid var(--color-stroke-soft-200);
239
+ border-radius: var(--spacing-12);
240
+ background: var(--color-bg-white-0);
241
+ box-shadow: var(--shadow-regular-xs);
242
+
243
+ .toolbar {
244
+ display: flex;
245
+ flex-wrap: wrap;
246
+ align-items: center;
247
+ padding: var(--spacing-4);
248
+ border-bottom: 1px solid var(--color-stroke-soft-200);
249
+ border-radius: var(--spacing-12) var(--spacing-12) 0 0;
250
+ background: var(--color-bg-white-0);
251
+ gap: var(--spacing-4);
252
+
253
+ &:deep(.celeste-cbutton:active) {
254
+ background-color: var(--color-bg-weak-50);
255
+ box-shadow: none;
256
+ color: var(--color-icon-strong-950);
257
+ }
258
+
259
+ .celeste-cbutton.active {
260
+ background-color: var(--color-neutral-100);
261
+ color: var(--color-icon-strong-950);
262
+ }
263
+
264
+ .divider {
265
+ width: 1px;
266
+ height: 16px;
267
+ margin: 0 3px;
268
+ background: var(--color-stroke-soft-200);
269
+ }
270
+
271
+ .extra-settings-wrapper {
272
+ display: flex;
273
+ align-items: center;
274
+ }
275
+ }
276
+
277
+ .text-field {
278
+ min-height: 88px;
279
+ margin: var(--spacing-12);
280
+ padding-inline-end: var(--spacing-12);
281
+ overflow-y: auto;
282
+ resize: vertical;
283
+
284
+ &:deep(.tiptap) {
285
+ min-height: 88px;
286
+ outline: none;
287
+
288
+ :first-child {
289
+ margin-top: 0;
290
+ }
291
+
292
+ p.is-editor-empty:first-child::before {
293
+ content: attr(data-placeholder);
294
+ height: 0;
295
+ color: var(--color-neutral-300);
296
+ pointer-events: none;
297
+ }
298
+
299
+ h1,
300
+ h2,
301
+ h3,
302
+ h4,
303
+ h5,
304
+ h6,
305
+ p {
306
+ margin-bottom: 0;
307
+ }
308
+
309
+ h1 {
310
+ margin-top: 40px;
311
+ font-size: 56px;
312
+ font-weight: 500;
313
+ letter-spacing: -0.01em;
314
+ line-height: 64px;
315
+ }
316
+
317
+ h2 {
318
+ margin-top: 36px;
319
+ font-size: 48px;
320
+ font-weight: 500;
321
+ letter-spacing: -0.01em;
322
+ line-height: 56px;
323
+ }
324
+
325
+ h3 {
326
+ margin-top: 32px;
327
+ font-size: 40px;
328
+ font-weight: 500;
329
+ letter-spacing: -0.01em;
330
+ line-height: 48px;
331
+ }
332
+
333
+ h4 {
334
+ margin-top: 20px;
335
+ font-size: 32px;
336
+ font-weight: 500;
337
+ letter-spacing: -0.005em;
338
+ line-height: 40px;
339
+ }
340
+
341
+ h5 {
342
+ margin-top: 20px;
343
+ font-size: 24px;
344
+ font-weight: 500;
345
+ letter-spacing: 0;
346
+ line-height: 32px;
347
+ }
348
+
349
+ h6 {
350
+ margin-top: 16px;
351
+ font-size: 20px;
352
+ font-weight: 500;
353
+ letter-spacing: 0;
354
+ line-height: 28px;
355
+ }
356
+
357
+ p {
358
+ margin-top: 12px;
359
+ font-size: 16px;
360
+ font-weight: 400;
361
+ letter-spacing: -0.011em;
362
+ line-height: 24px;
363
+ }
364
+
365
+ ul,
366
+ ol {
367
+ margin: 1.25rem 1rem 1.25rem 0.4rem;
368
+ padding: 0 1rem;
369
+
370
+ li p {
371
+ margin-top: 0.25em;
372
+ margin-bottom: 0.25em;
373
+ }
374
+ }
375
+
376
+ a {
377
+ color: var(--color-blue-700);
378
+ cursor: pointer;
379
+
380
+ &:hover {
381
+ color: var(--color-blue-500);
382
+ }
383
+ }
384
+ }
385
+ }
386
+
387
+ .characters-count {
388
+ position: absolute;
389
+ bottom: 7px;
390
+ inset-inline-end: 22px;
391
+ max-width: max-content;
392
+ padding: var(--spacing-4);
393
+ border-radius: var(--radius-4);
394
+ background: var(--color-bg-white-0);
395
+ color: var(--color-text-soft-400);
396
+ font: var(--subheading-xxs);
397
+
398
+ &.warning {
399
+ color: var(--color-state-warning-base);
400
+ }
401
+
402
+ &.danger {
403
+ color: var(--color-state-error-base);
404
+ }
405
+ }
406
+
407
+ .select-menu-wrapper {
408
+ padding: 0 var(--spacing-4);
409
+ }
410
+
411
+ &:dir(rtl) {
412
+ :deep(.i-celeste-arrow-go-back-line),
413
+ :deep(.i-celeste-arrow-go-forward-line) {
414
+ transform: scaleX(-1);
415
+ }
416
+ }
417
+
418
+ :deep(.tippy-box[data-theme='custom']) {
419
+ max-width: 400px !important;
420
+ }
421
+ }
422
+
423
+ .celeste-select-item[data-state='checked'] {
424
+ &:deep(.i-celeste-check-line) {
425
+ display: none;
426
+ }
427
+ }
428
+ </style>