@widgetic/design-system 0.5.15 → 0.5.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +167 -0
- package/dist/components/CopyableHeader.svelte +25 -11
- package/dist/components/CopyableHeader.svelte.d.ts +4 -0
- package/dist/components/EmptyState.svelte +1 -1
- package/dist/components/PasswordInput.svelte +2 -2
- package/dist/components/WScrollArea.svelte +2 -2
- package/dist/components/ic/browser/BrowserInputController.svelte +2 -2
- package/dist/components/index.d.ts +1 -0
- package/dist/components/modals/ActionModal.svelte +3 -0
- package/dist/components/modals/ActionModal.svelte.d.ts +1 -0
- package/dist/components/modals/BaseModal.svelte +4 -2
- package/dist/components/modals/BaseModal.svelte.d.ts +1 -0
- package/dist/components/modals/NewItemDialog.svelte +48 -30
- package/dist/components/modals/NewItemDialog.svelte.d.ts +3 -0
- package/dist/components/modals/Portal.svelte +9 -1
- package/dist/components/modals/README.md +34 -1
- package/dist/components/modals/RenameDialog.svelte +29 -9
- package/dist/components/modals/RenameDialog.svelte.d.ts +3 -0
- package/dist/components/modals/messages.d.ts +39 -0
- package/dist/components/modals/messages.js +10 -0
- package/dist/components/navigation/Breadcrumbs.svelte +30 -17
- package/dist/components/navigation/Breadcrumbs.svelte.d.ts +4 -0
- package/dist/components/navigation/types.d.ts +8 -0
- package/dist/components/pdf/PDFViewer.svelte +17 -8
- package/dist/components/pdf/PDFViewer.svelte.d.ts +5 -0
- package/dist/components/search-input/SearchInput.svelte +3 -3
- package/dist/components/shad-editor/colorpicker.svelte +4 -1
- package/dist/components/shad-editor/custom/Extentions/ImageExtention.d.ts +20 -1
- package/dist/components/shad-editor/custom/Extentions/ImageExtention.js +4 -1
- package/dist/components/shad-editor/custom/code-extended.svelte +4 -2
- package/dist/components/shad-editor/custom/image-extended-component.svelte +54 -32
- package/dist/components/shad-editor/editor.css +5 -5
- package/dist/components/shad-editor/i18n/context.d.ts +6 -0
- package/dist/components/shad-editor/i18n/context.js +11 -0
- package/dist/components/shad-editor/i18n/index.d.ts +8 -0
- package/dist/components/shad-editor/i18n/index.js +11 -0
- package/dist/components/shad-editor/i18n/messages.d.ts +109 -0
- package/dist/components/shad-editor/i18n/messages.js +116 -0
- package/dist/components/shad-editor/icons/block-quote.svelte +3 -1
- package/dist/components/shad-editor/icons/bold.svelte +3 -1
- package/dist/components/shad-editor/icons/buttle-list.svelte +3 -1
- package/dist/components/shad-editor/icons/code.svelte +3 -1
- package/dist/components/shad-editor/icons/highlighter.svelte +5 -3
- package/dist/components/shad-editor/icons/image.svelte +7 -5
- package/dist/components/shad-editor/icons/italic.svelte +3 -1
- package/dist/components/shad-editor/icons/link.svelte +8 -6
- package/dist/components/shad-editor/icons/ordered-list.svelte +3 -1
- package/dist/components/shad-editor/icons/quickcolor.svelte +24 -22
- package/dist/components/shad-editor/icons/redo.svelte +3 -1
- package/dist/components/shad-editor/icons/search-replace.svelte +16 -14
- package/dist/components/shad-editor/icons/strikethrough.svelte +3 -1
- package/dist/components/shad-editor/icons/subscript.svelte +3 -1
- package/dist/components/shad-editor/icons/superscript.svelte +3 -1
- package/dist/components/shad-editor/icons/table.svelte +21 -19
- package/dist/components/shad-editor/icons/task-list.svelte +3 -1
- package/dist/components/shad-editor/icons/text.svelte +13 -11
- package/dist/components/shad-editor/icons/textalign.svelte +11 -9
- package/dist/components/shad-editor/icons/textcolor.svelte +5 -3
- package/dist/components/shad-editor/icons/underline.svelte +3 -1
- package/dist/components/shad-editor/icons/undo.svelte +3 -1
- package/dist/components/shad-editor/index.d.ts +1 -0
- package/dist/components/shad-editor/index.js +2 -0
- package/dist/components/shad-editor/shad-editor.svelte +32 -3
- package/dist/components/shad-editor/shad-editor.svelte.d.ts +12 -0
- package/dist/components/textDirection.d.ts +91 -0
- package/dist/components/textDirection.js +99 -0
- package/dist/components/toast/ToasterModal.svelte +49 -14
- package/dist/components/toast/ToasterModal.svelte.d.ts +9 -2
- package/dist/components/toast/toasterRoots.d.ts +23 -0
- package/dist/components/toast/toasterRoots.js +36 -0
- package/dist/components/ui/alert/index.d.ts +2 -2
- package/dist/components/ui/alert/index.js +1 -1
- package/dist/components/ui/breadcrumb/breadcrumb-separator.svelte +1 -1
- package/dist/components/ui/calendar/calendar-next-button.svelte +21 -4
- package/dist/components/ui/calendar/calendar-next-button.svelte.d.ts +9 -2
- package/dist/components/ui/calendar/calendar-prev-button.svelte +21 -4
- package/dist/components/ui/calendar/calendar-prev-button.svelte.d.ts +9 -2
- package/dist/components/ui/calendar/calendar.svelte +18 -6
- package/dist/components/ui/calendar/calendar.svelte.d.ts +6 -1
- package/dist/components/ui/command/command-input.svelte +1 -1
- package/dist/components/ui/command/command-shortcut.svelte +1 -1
- package/dist/components/ui/dialog/dialog-content.svelte +5 -2
- package/dist/components/ui/dialog/dialog-content.svelte.d.ts +1 -0
- package/dist/components/ui/dialog/dialog-header.svelte +1 -1
- package/dist/components/ui/drawer/drawer-header.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +2 -2
- package/dist/components/ui/dropdown-menu/dropdown-menu-content.svelte +6 -0
- package/dist/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-item.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-label.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +2 -2
- package/dist/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +7 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +2 -2
- package/dist/components/ui/hover-card/hover-card-content.svelte +6 -0
- package/dist/components/ui/input-otp/input-otp-slot.svelte +1 -1
- package/dist/components/ui/popover/popover-content.svelte +6 -0
- package/dist/components/ui/progress/progress.svelte +2 -2
- package/dist/components/ui/range-calendar/range-calendar-cell.svelte +1 -1
- package/dist/components/ui/range-calendar/range-calendar-next-button.svelte +21 -4
- package/dist/components/ui/range-calendar/range-calendar-next-button.svelte.d.ts +9 -2
- package/dist/components/ui/range-calendar/range-calendar-prev-button.svelte +21 -4
- package/dist/components/ui/range-calendar/range-calendar-prev-button.svelte.d.ts +9 -2
- package/dist/components/ui/range-calendar/range-calendar.svelte +18 -6
- package/dist/components/ui/range-calendar/range-calendar.svelte.d.ts +7 -2
- package/dist/components/ui/scroll-area/scroll-area-scrollbar.svelte +1 -1
- package/dist/components/ui/scroll-area/scroll-area.svelte +6 -1
- package/dist/components/ui/select/select-content.svelte +6 -0
- package/dist/components/ui/select/select-group-heading.svelte +1 -1
- package/dist/components/ui/select/select-item.svelte +2 -2
- package/dist/components/ui/slider/slider.svelte +6 -0
- package/dist/components/ui/switch/switch.svelte +1 -1
- package/dist/components/ui/table/table-cell.svelte +1 -1
- package/dist/components/ui/table/table-head.svelte +1 -1
- package/dist/components/ui/tooltip/tooltip-content.svelte +6 -0
- package/dist/i18n/audit/catalogUsage.d.ts +36 -0
- package/dist/i18n/audit/catalogUsage.js +58 -0
- package/dist/i18n/audit/designSystemWords.d.ts +47 -0
- package/dist/i18n/audit/designSystemWords.js +137 -0
- package/dist/i18n/audit/hardCodedText.d.ts +40 -0
- package/dist/i18n/audit/hardCodedText.js +27 -0
- package/dist/i18n/audit/index.d.ts +19 -0
- package/dist/i18n/audit/index.js +19 -0
- package/dist/i18n/audit/messageCalls.d.ts +34 -0
- package/dist/i18n/audit/messageCalls.js +89 -0
- package/dist/i18n/audit/syntaxTree.d.ts +33 -0
- package/dist/i18n/audit/syntaxTree.js +90 -0
- package/dist/i18n/audit/visibleText.d.ts +57 -0
- package/dist/i18n/audit/visibleText.js +252 -0
- package/dist/i18n/createI18n.d.ts +63 -0
- package/dist/i18n/createI18n.js +72 -0
- package/dist/i18n/direction.d.ts +27 -0
- package/dist/i18n/direction.js +89 -0
- package/dist/i18n/index.d.ts +17 -0
- package/dist/i18n/index.js +16 -0
- package/dist/i18n/localeDate.d.ts +34 -0
- package/dist/i18n/localeDate.js +104 -0
- package/dist/i18n/splitMessages.d.ts +21 -0
- package/dist/i18n/splitMessages.js +33 -0
- package/dist/i18n/translator.d.ts +61 -0
- package/dist/i18n/translator.js +337 -0
- package/dist/rtl/audit/auditPhysicalPlacement.d.ts +36 -0
- package/dist/rtl/audit/auditPhysicalPlacement.js +58 -0
- package/dist/rtl/audit/index.d.ts +14 -0
- package/dist/rtl/audit/index.js +14 -0
- package/dist/rtl/audit/physicalPlacement.d.ts +64 -0
- package/dist/rtl/audit/physicalPlacement.js +444 -0
- package/dist/shad-editor/index.d.ts +1 -1
- package/dist/shad-editor/index.js +1 -1
- package/dist/styles/global.css +4 -4
- package/dist/utils/fillMessage.d.ts +8 -0
- package/dist/utils/fillMessage.js +10 -0
- package/dist/utils/itemName.d.ts +17 -0
- package/dist/utils/itemName.js +41 -0
- package/package.json +18 -1
|
@@ -16,8 +16,10 @@
|
|
|
16
16
|
import * as Tooltip from '../../ui/tooltip/index.js';
|
|
17
17
|
import * as DropdownMenu from '../../ui/dropdown-menu/index.js';
|
|
18
18
|
import Button from '../../ui/button/button.svelte';
|
|
19
|
+
import { useI18n } from '../i18n/context.js';
|
|
19
20
|
|
|
20
21
|
let { editor }: TextalignProps = $props();
|
|
22
|
+
const { t } = useI18n();
|
|
21
23
|
</script>
|
|
22
24
|
|
|
23
25
|
<Tooltip.Provider>
|
|
@@ -45,43 +47,43 @@
|
|
|
45
47
|
onclick={() => editor.chain().focus().setTextAlign('left').run()}
|
|
46
48
|
closeOnSelect={false}
|
|
47
49
|
>
|
|
48
|
-
<AlignLeft />
|
|
50
|
+
<AlignLeft /> {$t('shadEditor.align.left')}
|
|
49
51
|
{#if editor.isActive({ textAlign: 'left' })}
|
|
50
|
-
<Check class="absolute
|
|
52
|
+
<Check class="absolute end-2 !size-3 text-muted-foreground" />
|
|
51
53
|
{/if}
|
|
52
54
|
</DropdownMenu.Item>
|
|
53
55
|
<DropdownMenu.Item
|
|
54
56
|
onclick={() => editor.chain().focus().setTextAlign('center').run()}
|
|
55
57
|
closeOnSelect={false}
|
|
56
58
|
>
|
|
57
|
-
<AlignCenter />
|
|
59
|
+
<AlignCenter /> {$t('shadEditor.align.center')}
|
|
58
60
|
{#if editor.isActive({ textAlign: 'center' })}
|
|
59
|
-
<Check class="absolute
|
|
61
|
+
<Check class="absolute end-2 !size-3 text-muted-foreground" />
|
|
60
62
|
{/if}
|
|
61
63
|
</DropdownMenu.Item>
|
|
62
64
|
<DropdownMenu.Item
|
|
63
65
|
onclick={() => editor.chain().focus().setTextAlign('right').run()}
|
|
64
66
|
closeOnSelect={false}
|
|
65
67
|
>
|
|
66
|
-
<AlignRight />
|
|
68
|
+
<AlignRight /> {$t('shadEditor.align.right')}
|
|
67
69
|
{#if editor.isActive({ textAlign: 'right' })}
|
|
68
|
-
<Check class="absolute
|
|
70
|
+
<Check class="absolute end-2 !size-3 text-muted-foreground" />
|
|
69
71
|
{/if}
|
|
70
72
|
</DropdownMenu.Item>
|
|
71
73
|
<DropdownMenu.Item
|
|
72
74
|
onclick={() => editor.chain().focus().setTextAlign('justify').run()}
|
|
73
75
|
closeOnSelect={false}
|
|
74
76
|
>
|
|
75
|
-
<AlignJustify />
|
|
77
|
+
<AlignJustify /> {$t('shadEditor.align.justify')}
|
|
76
78
|
{#if editor.isActive({ textAlign: 'justify' })}
|
|
77
|
-
<Check class="absolute
|
|
79
|
+
<Check class="absolute end-2 !size-3 text-muted-foreground" />
|
|
78
80
|
{/if}
|
|
79
81
|
</DropdownMenu.Item>
|
|
80
82
|
</DropdownMenu.Content>
|
|
81
83
|
</DropdownMenu.Root>
|
|
82
84
|
</Tooltip.Trigger>
|
|
83
85
|
<Tooltip.Content>
|
|
84
|
-
<p>
|
|
86
|
+
<p>{$t('shadEditor.align.tooltip')}</p>
|
|
85
87
|
</Tooltip.Content>
|
|
86
88
|
</Tooltip.Root>
|
|
87
89
|
</Tooltip.Provider>
|
|
@@ -17,8 +17,10 @@
|
|
|
17
17
|
import * as Popover from '../../ui/popover/index.js';
|
|
18
18
|
import { mode } from 'mode-watcher';
|
|
19
19
|
import ColorPicker from 'svelte-awesome-color-picker';
|
|
20
|
+
import { useI18n } from '../i18n/context.js';
|
|
20
21
|
|
|
21
22
|
let { editor, color = $bindable('') }: TextcolorProps = $props();
|
|
23
|
+
const { t } = useI18n();
|
|
22
24
|
</script>
|
|
23
25
|
|
|
24
26
|
<Tooltip.Provider>
|
|
@@ -38,7 +40,7 @@
|
|
|
38
40
|
</Popover.Trigger>
|
|
39
41
|
<Popover.Content class="bg-popover shadow-lg *:my-2">
|
|
40
42
|
<div class="flex items-center justify-between">
|
|
41
|
-
<h1 class="text-[1.2rem] font-bold">
|
|
43
|
+
<h1 class="text-[1.2rem] font-bold">{$t('shadEditor.textColor.pick')}</h1>
|
|
42
44
|
<Popover.Close>
|
|
43
45
|
<X class="size-4 text-muted-foreground" />
|
|
44
46
|
</Popover.Close>
|
|
@@ -65,14 +67,14 @@
|
|
|
65
67
|
size="sm"
|
|
66
68
|
class="border-destructive text-destructive hover:bg-destructive hover:text-foreground"
|
|
67
69
|
onclick={() => editor.chain().focus().unsetColor().run()}
|
|
68
|
-
>
|
|
70
|
+
>{$t('shadEditor.textColor.remove')}
|
|
69
71
|
</Button>
|
|
70
72
|
</div>
|
|
71
73
|
</Popover.Content>
|
|
72
74
|
</Popover.Root>
|
|
73
75
|
</Tooltip.Trigger>
|
|
74
76
|
<Tooltip.Content>
|
|
75
|
-
<p>
|
|
77
|
+
<p>{$t('shadEditor.textColor.tooltip')}</p>
|
|
76
78
|
</Tooltip.Content>
|
|
77
79
|
</Tooltip.Root>
|
|
78
80
|
</Tooltip.Provider>
|
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
import * as Tooltip from '../../ui/tooltip/index.js';
|
|
10
10
|
import { Button } from '../../ui/button/index.js';
|
|
11
11
|
import { cn } from '../../../utils.js';
|
|
12
|
+
import { useI18n } from '../i18n/context.js';
|
|
12
13
|
|
|
13
14
|
let { editor }: UnderlineProps = $props();
|
|
15
|
+
const { t } = useI18n();
|
|
14
16
|
</script>
|
|
15
17
|
|
|
16
18
|
<Tooltip.Provider>
|
|
@@ -25,7 +27,7 @@
|
|
|
25
27
|
</Button>
|
|
26
28
|
</Tooltip.Trigger>
|
|
27
29
|
<Tooltip.Content>
|
|
28
|
-
<p>
|
|
30
|
+
<p>{$t('shadEditor.toolbar.underline')}</p>
|
|
29
31
|
</Tooltip.Content>
|
|
30
32
|
</Tooltip.Root>
|
|
31
33
|
</Tooltip.Provider>
|
|
@@ -8,8 +8,10 @@
|
|
|
8
8
|
import { type Editor } from '@tiptap/core';
|
|
9
9
|
import * as Tooltip from '../../ui/tooltip/index.js';
|
|
10
10
|
import { Button } from '../../ui/button/index.js';
|
|
11
|
+
import { useI18n } from '../i18n/context.js';
|
|
11
12
|
|
|
12
13
|
let { editor }: UndoProps = $props();
|
|
14
|
+
const { t } = useI18n();
|
|
13
15
|
</script>
|
|
14
16
|
|
|
15
17
|
<Tooltip.Provider>
|
|
@@ -25,7 +27,7 @@
|
|
|
25
27
|
</Button>
|
|
26
28
|
</Tooltip.Trigger>
|
|
27
29
|
<Tooltip.Content>
|
|
28
|
-
<p>
|
|
30
|
+
<p>{$t('shadEditor.toolbar.undo')}</p>
|
|
29
31
|
</Tooltip.Content>
|
|
30
32
|
</Tooltip.Root>
|
|
31
33
|
</Tooltip.Provider>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ShadEditor from './shad-editor.svelte';
|
|
2
2
|
export { ShadEditor };
|
|
3
|
+
export { SHAD_EDITOR_MESSAGES, checkShadEditorMessages, type ShadEditorMessageKey } from './i18n/index.js';
|
|
3
4
|
export { type Editor as TipTapEditor } from '@tiptap/core';
|
|
4
5
|
export { type Level as TipTapEditorLevel } from '@tiptap/extension-heading';
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import ShadEditor from './shad-editor.svelte';
|
|
2
2
|
export { ShadEditor };
|
|
3
|
+
// The words of the editor, so a page can translate them: the English catalog and a check of the page's own messages.
|
|
4
|
+
export { SHAD_EDITOR_MESSAGES, checkShadEditorMessages } from './i18n/index.js';
|
|
3
5
|
// export Editor and Level from '@tiptap';
|
|
4
6
|
export {} from '@tiptap/core';
|
|
5
7
|
export {} from '@tiptap/extension-heading';
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import type { Content } from '@tiptap/core';
|
|
3
|
+
import type { MessageOverrides } from '../../i18n/index.js';
|
|
3
4
|
|
|
4
5
|
export interface ShadEditorProps {
|
|
5
6
|
class?: string;
|
|
6
7
|
style?: string;
|
|
7
8
|
content?: Content;
|
|
8
9
|
showToolbar?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* The language of the page: a BCP 47 tag (`de`, `pt-BR`) that sets how numbers are written. The words of the
|
|
12
|
+
* editor are English until `messages` gives them in the page's language.
|
|
13
|
+
*/
|
|
14
|
+
locale?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The page's own words for the toolbar, the menus and the image bar: any key of `SHAD_EDITOR_MESSAGES`
|
|
17
|
+
* (`'shadEditor.toolbar.bold': 'Fett (⌘B)'`). A key that is left out keeps its English text; `checkShadEditorMessages`
|
|
18
|
+
* lists the keys that do not exist.
|
|
19
|
+
*/
|
|
20
|
+
messages?: MessageOverrides;
|
|
9
21
|
}
|
|
10
22
|
</script>
|
|
11
23
|
|
|
@@ -39,6 +51,8 @@
|
|
|
39
51
|
import { ImageExtension } from './custom/Extentions/ImageExtention.js';
|
|
40
52
|
import { SvelteNodeViewRenderer } from 'svelte-tiptap';
|
|
41
53
|
import CodeExtended from './custom/code-extended.svelte';
|
|
54
|
+
import { provideI18n } from './i18n/context.js';
|
|
55
|
+
import { dirForUserText, useTextDirection } from '../textDirection.js';
|
|
42
56
|
|
|
43
57
|
// Lowlight
|
|
44
58
|
import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight';
|
|
@@ -52,7 +66,21 @@
|
|
|
52
66
|
update: { html: string };
|
|
53
67
|
}>();
|
|
54
68
|
|
|
55
|
-
let { class: className = '', style = '', content = $bindable(null), showToolbar = true }: ShadEditorProps = $props();
|
|
69
|
+
let { class: className = '', style = '', content = $bindable(null), showToolbar = true, locale, messages }: ShadEditorProps = $props();
|
|
70
|
+
|
|
71
|
+
// The words of the toolbar, the menus and the image bar, in the page's language. The parts below read them from
|
|
72
|
+
// Svelte's context; an image in the text gets them through the options of its extension, because TipTap mounts it
|
|
73
|
+
// outside this component's tree. A change of `locale` or `messages` reaches both without making the editor again.
|
|
74
|
+
// svelte-ignore state_referenced_locally
|
|
75
|
+
const language = provideI18n({ locale, messages });
|
|
76
|
+
$effect(() => {
|
|
77
|
+
language.update({ locale, messages });
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// The way the screen around the editor is read. The words a visitor types are read by their own first letter on a right to
|
|
81
|
+
// left screen (`dir="auto"` on the text, see below), and the menu of an image in the text gets the direction through the
|
|
82
|
+
// options of its extension, like its words.
|
|
83
|
+
const textDirection = useTextDirection();
|
|
56
84
|
|
|
57
85
|
const lowlight = createLowlight(common);
|
|
58
86
|
|
|
@@ -131,7 +159,7 @@
|
|
|
131
159
|
TableRow,
|
|
132
160
|
TableHeader,
|
|
133
161
|
TableCell,
|
|
134
|
-
ImageExtension
|
|
162
|
+
ImageExtension.configure({ translate: language.t, textDirection })
|
|
135
163
|
],
|
|
136
164
|
autofocus: true,
|
|
137
165
|
onUpdate: ({ editor }) => {
|
|
@@ -153,5 +181,6 @@
|
|
|
153
181
|
{#if editor && showToolbar}
|
|
154
182
|
<EditorToolbar {editor} class='shad-editor-toolbar' />
|
|
155
183
|
{/if}
|
|
156
|
-
|
|
184
|
+
<!-- On a right to left screen the text reads in the direction of its own first letter: an Arabic paragraph runs from the right, an English one from the left, and an English one does not get its full stop in front. On a left to right screen no attribute is written. -->
|
|
185
|
+
<div bind:this={element} spellcheck="false" dir={dirForUserText($textDirection)} class="shad-editor-content h-full w-full flex-1 overflow-auto"></div>
|
|
157
186
|
</div>
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import type { Content } from '@tiptap/core';
|
|
2
|
+
import type { MessageOverrides } from '../../i18n/index.js';
|
|
2
3
|
export interface ShadEditorProps {
|
|
3
4
|
class?: string;
|
|
4
5
|
style?: string;
|
|
5
6
|
content?: Content;
|
|
6
7
|
showToolbar?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* The language of the page: a BCP 47 tag (`de`, `pt-BR`) that sets how numbers are written. The words of the
|
|
10
|
+
* editor are English until `messages` gives them in the page's language.
|
|
11
|
+
*/
|
|
12
|
+
locale?: string;
|
|
13
|
+
/**
|
|
14
|
+
* The page's own words for the toolbar, the menus and the image bar: any key of `SHAD_EDITOR_MESSAGES`
|
|
15
|
+
* (`'shadEditor.toolbar.bold': 'Fett (⌘B)'`). A key that is left out keeps its English text; `checkShadEditorMessages`
|
|
16
|
+
* lists the keys that do not exist.
|
|
17
|
+
*/
|
|
18
|
+
messages?: MessageOverrides;
|
|
7
19
|
}
|
|
8
20
|
import './editor.css';
|
|
9
21
|
import { Editor } from '@tiptap/core';
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { type Readable } from 'svelte/store';
|
|
2
|
+
import type { TextDirection } from '../i18n/direction.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Which way the text of a screen runs, shared with the components below it through Svelte's context.
|
|
5
|
+
*
|
|
6
|
+
* Most of what a right to left screen needs is done by the browser and by the `dir` attribute on an element around the
|
|
7
|
+
* screen: a row of buttons turns around, a paragraph starts on the right, and the logical classes of the components
|
|
8
|
+
* (`ms-2`, `pe-4`, `start-0`, `text-start`) follow. What the browser cannot do is reach into a library that wants to be
|
|
9
|
+
* told: the scroll area and the menus of `bits-ui` write `dir="ltr"` on their own element unless they are given the
|
|
10
|
+
* direction, and that one attribute turns a whole screen left to right again from the inside. So the root component of a
|
|
11
|
+
* right to left screen says its direction once, and the components that wrap such a library read it here:
|
|
12
|
+
*
|
|
13
|
+
* // in the root component of a package, with `direction` a store that follows the page's language
|
|
14
|
+
* provideTextDirection(direction);
|
|
15
|
+
* // in a component that wraps a library
|
|
16
|
+
* const textDirection = useTextDirection(); then <ScrollAreaPrimitive.Root dir={$textDirection} />
|
|
17
|
+
*
|
|
18
|
+
* A component with no provider above it is left to right, which is what every component here has always been, so a page
|
|
19
|
+
* that never says anything keeps the layout it has.
|
|
20
|
+
*
|
|
21
|
+
* A package whose root component has a `dir` prop that may be left out (the File Browser, the composition editor, the
|
|
22
|
+
* chat, the canvas) does not call `provideTextDirection` itself but `shareTextDirection`: a `dir` that is given is the
|
|
23
|
+
* direction of that screen, and without one the screen is drawn the way the screen around it is.
|
|
24
|
+
*/
|
|
25
|
+
/** The two ways text runs: the values of the `dir` attribute. Defined with the language helpers, where a language tag is turned into one. */
|
|
26
|
+
export type { TextDirection };
|
|
27
|
+
/**
|
|
28
|
+
* The two functions of Svelte that the context is made of. They only work while a component is being created, so a test
|
|
29
|
+
* hands in stand-ins; the components use the real ones by leaving this out.
|
|
30
|
+
*/
|
|
31
|
+
export interface TextDirectionContextApi {
|
|
32
|
+
getContext<Value>(key: unknown): Value | undefined;
|
|
33
|
+
setContext<Value>(key: unknown, value: Value): Value;
|
|
34
|
+
}
|
|
35
|
+
/** Anything that is not exactly `'rtl'` is left to right: a missing, blank or misspelled direction must not mirror a screen. */
|
|
36
|
+
export declare function readTextDirection(value: unknown): TextDirection;
|
|
37
|
+
/**
|
|
38
|
+
* The `dir` for text a visitor wrote: the name of a file, of a folder.
|
|
39
|
+
*
|
|
40
|
+
* On a right to left screen it is "auto": the browser reads the direction from the first letter that has one, so a Latin
|
|
41
|
+
* name ("2024 report.pdf") reads left to right inside the screen, with its ellipsis at the end of the name, and an
|
|
42
|
+
* Arabic one reads right to left. Without it a Latin name that starts with a digit or ends with a full stop is put in
|
|
43
|
+
* the wrong order, because the line around it runs right to left.
|
|
44
|
+
*
|
|
45
|
+
* On a left to right screen it is `undefined` (Svelte then writes no attribute), and that screen looks exactly as it
|
|
46
|
+
* always has.
|
|
47
|
+
*/
|
|
48
|
+
export declare function dirForUserText(direction: TextDirection): 'auto' | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* The `side` of a pop-up that opens at the start of the line: on the left of a left to right screen and on the right of a
|
|
51
|
+
* right to left one. The library names the sides of a pop-up by places on the screen, which do not turn around, so a tooltip
|
|
52
|
+
* that must open beside a control, on the side where the line begins, asks for it here.
|
|
53
|
+
*
|
|
54
|
+
* <Tooltip.Content side={sideAtStart($textDirection)}>
|
|
55
|
+
*/
|
|
56
|
+
export declare function sideAtStart(direction: TextDirection): 'left' | 'right';
|
|
57
|
+
/** The `side` of a pop-up that opens at the end of the line: on the right of a left to right screen, on the left of a right to left one. */
|
|
58
|
+
export declare function sideAtEnd(direction: TextDirection): 'left' | 'right';
|
|
59
|
+
/**
|
|
60
|
+
* Called by the root component of a screen while it is created: everything below it reads `direction`. It is a store, so
|
|
61
|
+
* a screen that is already open turns around when the page sets another language. Returns the store it was given.
|
|
62
|
+
*/
|
|
63
|
+
export declare function provideTextDirection(direction: Readable<TextDirection>, contextApi?: TextDirectionContextApi): Readable<TextDirection>;
|
|
64
|
+
/**
|
|
65
|
+
* Called by the root component of a package that takes a `dir` prop which may be left out. `given` is a store that holds
|
|
66
|
+
* the prop. A `dir` that is given ('rtl' or 'ltr') is the direction of this screen, whatever the screen above it says
|
|
67
|
+
* (a left to right island inside a right to left screen is possible); with no `dir` (undefined or null) the screen is
|
|
68
|
+
* drawn the way the screen around it is, and left to right when there is none. A `dir` that is given but is not exactly
|
|
69
|
+
* 'rtl' is left to right, like everywhere else: a mistake never mirrors a screen. Everything below the component reads
|
|
70
|
+
* the answer from the context, and it follows when the prop changes or the screen above turns around. Returns the store
|
|
71
|
+
* of the answer, for the component's own decisions (a position worked out in pixels, an arrow key).
|
|
72
|
+
*
|
|
73
|
+
* export let dir: TextDirection | undefined = undefined;
|
|
74
|
+
* const givenDirection = writable(dir);
|
|
75
|
+
* const textDirection = shareTextDirection(givenDirection);
|
|
76
|
+
* $: givenDirection.set(dir);
|
|
77
|
+
*/
|
|
78
|
+
export declare function shareTextDirection(given: Readable<TextDirection | null | undefined>, contextApi?: TextDirectionContextApi): Readable<TextDirection>;
|
|
79
|
+
/**
|
|
80
|
+
* Called by a component while it is created: the store of the direction a screen above it gave, or `undefined` when no
|
|
81
|
+
* screen did. For the few parts that must tell "left to right because the screen says so" from "left to right because
|
|
82
|
+
* nobody said anything": a part that draws outside the element of its screen (a pop-up in a layer of its own) writes the
|
|
83
|
+
* screen's direction onto itself, and writes nothing on a page that never asked for one, so the page's own `dir` stays.
|
|
84
|
+
* Never throws; outside a component it is `undefined`.
|
|
85
|
+
*/
|
|
86
|
+
export declare function useOptionalTextDirection(contextApi?: TextDirectionContextApi): Readable<TextDirection> | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Called by a component while it is created: the store of the direction it is drawn in. Never throws; with no provider
|
|
89
|
+
* above it, or outside a component, it is left to right.
|
|
90
|
+
*/
|
|
91
|
+
export declare function useTextDirection(contextApi?: TextDirectionContextApi): Readable<TextDirection>;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
import { derived, readable } from 'svelte/store';
|
|
3
|
+
/**
|
|
4
|
+
* The key of the context. `Symbol.for` gives the same key to every copy of this file on a page, so a package that was
|
|
5
|
+
* built with its own copy of the design system still reads what the page's root component said.
|
|
6
|
+
*/
|
|
7
|
+
const TEXT_DIRECTION_CONTEXT_KEY = Symbol.for('@widgetic/design-system/text-direction');
|
|
8
|
+
/** What a component gets when nothing above it said otherwise. */
|
|
9
|
+
const LEFT_TO_RIGHT = readable('ltr');
|
|
10
|
+
/** Anything that is not exactly `'rtl'` is left to right: a missing, blank or misspelled direction must not mirror a screen. */
|
|
11
|
+
export function readTextDirection(value) {
|
|
12
|
+
return value === 'rtl' ? 'rtl' : 'ltr';
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The `dir` for text a visitor wrote: the name of a file, of a folder.
|
|
16
|
+
*
|
|
17
|
+
* On a right to left screen it is "auto": the browser reads the direction from the first letter that has one, so a Latin
|
|
18
|
+
* name ("2024 report.pdf") reads left to right inside the screen, with its ellipsis at the end of the name, and an
|
|
19
|
+
* Arabic one reads right to left. Without it a Latin name that starts with a digit or ends with a full stop is put in
|
|
20
|
+
* the wrong order, because the line around it runs right to left.
|
|
21
|
+
*
|
|
22
|
+
* On a left to right screen it is `undefined` (Svelte then writes no attribute), and that screen looks exactly as it
|
|
23
|
+
* always has.
|
|
24
|
+
*/
|
|
25
|
+
export function dirForUserText(direction) {
|
|
26
|
+
return direction === 'rtl' ? 'auto' : undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The `side` of a pop-up that opens at the start of the line: on the left of a left to right screen and on the right of a
|
|
30
|
+
* right to left one. The library names the sides of a pop-up by places on the screen, which do not turn around, so a tooltip
|
|
31
|
+
* that must open beside a control, on the side where the line begins, asks for it here.
|
|
32
|
+
*
|
|
33
|
+
* <Tooltip.Content side={sideAtStart($textDirection)}>
|
|
34
|
+
*/
|
|
35
|
+
export function sideAtStart(direction) {
|
|
36
|
+
return direction === 'rtl' ? 'right' : 'left';
|
|
37
|
+
}
|
|
38
|
+
/** The `side` of a pop-up that opens at the end of the line: on the right of a left to right screen, on the left of a right to left one. */
|
|
39
|
+
export function sideAtEnd(direction) {
|
|
40
|
+
return direction === 'rtl' ? 'left' : 'right';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Called by the root component of a screen while it is created: everything below it reads `direction`. It is a store, so
|
|
44
|
+
* a screen that is already open turns around when the page sets another language. Returns the store it was given.
|
|
45
|
+
*/
|
|
46
|
+
export function provideTextDirection(direction, contextApi = { getContext, setContext }) {
|
|
47
|
+
try {
|
|
48
|
+
contextApi.setContext(TEXT_DIRECTION_CONTEXT_KEY, direction);
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
// Called outside a component (a helper, a test): nothing below can read it, and a screen must not fail for that.
|
|
52
|
+
console.warn('[widgetic-ui] The text direction could not be shared with the components below:', error);
|
|
53
|
+
}
|
|
54
|
+
return direction;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Called by the root component of a package that takes a `dir` prop which may be left out. `given` is a store that holds
|
|
58
|
+
* the prop. A `dir` that is given ('rtl' or 'ltr') is the direction of this screen, whatever the screen above it says
|
|
59
|
+
* (a left to right island inside a right to left screen is possible); with no `dir` (undefined or null) the screen is
|
|
60
|
+
* drawn the way the screen around it is, and left to right when there is none. A `dir` that is given but is not exactly
|
|
61
|
+
* 'rtl' is left to right, like everywhere else: a mistake never mirrors a screen. Everything below the component reads
|
|
62
|
+
* the answer from the context, and it follows when the prop changes or the screen above turns around. Returns the store
|
|
63
|
+
* of the answer, for the component's own decisions (a position worked out in pixels, an arrow key).
|
|
64
|
+
*
|
|
65
|
+
* export let dir: TextDirection | undefined = undefined;
|
|
66
|
+
* const givenDirection = writable(dir);
|
|
67
|
+
* const textDirection = shareTextDirection(givenDirection);
|
|
68
|
+
* $: givenDirection.set(dir);
|
|
69
|
+
*/
|
|
70
|
+
export function shareTextDirection(given, contextApi) {
|
|
71
|
+
const aboveThisScreen = useTextDirection(contextApi);
|
|
72
|
+
const direction = derived([aboveThisScreen, given], ([fromAbove, fromProp]) => fromProp === undefined || fromProp === null ? fromAbove : readTextDirection(fromProp));
|
|
73
|
+
return provideTextDirection(direction, contextApi);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Called by a component while it is created: the store of the direction a screen above it gave, or `undefined` when no
|
|
77
|
+
* screen did. For the few parts that must tell "left to right because the screen says so" from "left to right because
|
|
78
|
+
* nobody said anything": a part that draws outside the element of its screen (a pop-up in a layer of its own) writes the
|
|
79
|
+
* screen's direction onto itself, and writes nothing on a page that never asked for one, so the page's own `dir` stays.
|
|
80
|
+
* Never throws; outside a component it is `undefined`.
|
|
81
|
+
*/
|
|
82
|
+
export function useOptionalTextDirection(contextApi = { getContext, setContext }) {
|
|
83
|
+
try {
|
|
84
|
+
const provided = contextApi.getContext(TEXT_DIRECTION_CONTEXT_KEY);
|
|
85
|
+
if (provided !== undefined && provided !== null && typeof provided.subscribe === 'function')
|
|
86
|
+
return provided;
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// Outside a component Svelte refuses to hand out a context: nothing above, then.
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Called by a component while it is created: the store of the direction it is drawn in. Never throws; with no provider
|
|
95
|
+
* above it, or outside a component, it is left to right.
|
|
96
|
+
*/
|
|
97
|
+
export function useTextDirection(contextApi = { getContext, setContext }) {
|
|
98
|
+
return useOptionalTextDirection(contextApi) ?? LEFT_TO_RIGHT;
|
|
99
|
+
}
|
|
@@ -6,6 +6,9 @@ import { toast, Toaster } from '../ui/sonner';
|
|
|
6
6
|
import Exclamation from '../../icons/Exclamation.svelte';
|
|
7
7
|
import Checked from '../../icons/Checked.svelte';
|
|
8
8
|
|
|
9
|
+
// Where the toasters are drawn (the page's document, or a shadow root): see ./toasterRoots.ts
|
|
10
|
+
import { toastLookupRoots } from './toasterRoots';
|
|
11
|
+
|
|
9
12
|
// Import Toast Types directly from the svelte-sonner module
|
|
10
13
|
// import type { ToastTypes } from 'svelte-sonner';
|
|
11
14
|
// Define the ToastTypes type
|
|
@@ -67,17 +70,21 @@ export function showToast(type: string = 'success', title: string, options: any
|
|
|
67
70
|
|
|
68
71
|
// set style of the data-icon element
|
|
69
72
|
setTimeout(() => {
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
73
|
+
// The elements are looked for in the root the toaster is drawn in: `document.querySelector` does not look inside
|
|
74
|
+
// a shadow root, so for a toaster in a module's shadow root the icon and the title kept the library's colours.
|
|
75
|
+
for (const lookupRoot of toastLookupRoots(document)) {
|
|
76
|
+
// set the close button color
|
|
77
|
+
let closeButtonElement = lookupRoot.querySelector('.' + toastMainClass + '-close-button') as HTMLElement; //console.log('closeButtonElement:', closeButtonElement);
|
|
78
|
+
// if(closeButtonElement) closeButtonElement.style.backgroundColor = 'hsl(var(' + options.closeBgFillColor + '))';
|
|
79
|
+
|
|
80
|
+
// set icon background fill color
|
|
81
|
+
let iconElement = lookupRoot.querySelector('.' + toastMainClass + '> [data-icon] > svg') as HTMLElement; //console.log('iconElement:', iconElement);
|
|
82
|
+
if(iconElement) iconElement.style.color = 'hsl(var(' + options.iconBgFillColor + '))';
|
|
83
|
+
|
|
84
|
+
// set the title color
|
|
85
|
+
let titleElement = lookupRoot.querySelector('.' + toastMainClass + '-title') as HTMLElement; //console.log('titleElement:', titleElement);
|
|
86
|
+
if(titleElement) titleElement.style.color = 'hsl(var(' + titleColor + '))';
|
|
87
|
+
}
|
|
81
88
|
}, 20);
|
|
82
89
|
|
|
83
90
|
// Call toast with custom styling
|
|
@@ -96,10 +103,38 @@ export function showToast(type: string = 'success', title: string, options: any
|
|
|
96
103
|
|
|
97
104
|
</script>
|
|
98
105
|
|
|
106
|
+
<script lang="ts">
|
|
107
|
+
import { onMount } from 'svelte';
|
|
108
|
+
import { registerToasterRoot } from './toasterRoots';
|
|
109
|
+
import { useTextDirection } from '../textDirection.js';
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The words a screen reader hears: the region that holds the toasts ("Notifications", read with the key that moves
|
|
113
|
+
* focus to it) and the button that closes one ("Close toast"). A page in another language gives its own words;
|
|
114
|
+
* left out, the English ones of the library are used.
|
|
115
|
+
*/
|
|
116
|
+
export let containerAriaLabel: string | undefined = undefined;
|
|
117
|
+
export let closeButtonAriaLabel: string | undefined = undefined;
|
|
118
|
+
|
|
119
|
+
// An element with no size that is only here to ask which root (the page's document, or a shadow root) this toaster is
|
|
120
|
+
// drawn in, so that `showToast` looks for the toast's icon and title there.
|
|
121
|
+
let rootMarker: HTMLElement;
|
|
122
|
+
onMount(() => registerToasterRoot(rootMarker.getRootNode() as Document | ShadowRoot));
|
|
123
|
+
|
|
124
|
+
// The toaster reads the direction of the PAGE's <html> unless it is told, and a module on a left to right page that
|
|
125
|
+
// speaks Arabic (or the other way around) must follow its own screen. The toasts sit in the corner at the end of the
|
|
126
|
+
// line: the right in a left to right screen, the left in a right to left one.
|
|
127
|
+
const textDirection = useTextDirection();
|
|
128
|
+
</script>
|
|
129
|
+
|
|
99
130
|
<!-- HTML Template -->
|
|
131
|
+
<span hidden bind:this={rootMarker}></span>
|
|
100
132
|
<Toaster
|
|
101
133
|
theme="light"
|
|
102
|
-
|
|
134
|
+
dir={$textDirection}
|
|
135
|
+
position={$textDirection === 'rtl' ? 'bottom-left' : 'bottom-right'}
|
|
136
|
+
{containerAriaLabel}
|
|
137
|
+
{closeButtonAriaLabel}
|
|
103
138
|
richColors
|
|
104
139
|
closeButton
|
|
105
140
|
toastOptions={{
|
|
@@ -107,7 +142,7 @@ export function showToast(type: string = 'success', title: string, options: any
|
|
|
107
142
|
classes: {
|
|
108
143
|
toast: toastMainClass + " widgetic-colors widgetic-radius !bg-white !rounded-small !border !border-[hsl(var(--forest-green))] " +
|
|
109
144
|
"!min-w-[334px] !max-w-[450px] " +
|
|
110
|
-
"!fixed !top-auto !bottom-[20px] !
|
|
145
|
+
"!fixed !top-auto !bottom-[20px] !end-[20px] " +
|
|
111
146
|
"!flex !items-center !gap-[24px] !p-[16px] !px-[24px] " +
|
|
112
147
|
// Icon Styling
|
|
113
148
|
"*:data-icon:!w-[24px] *:data-icon:!h-[24px] *:data-icon:!m-0 " +
|
|
@@ -123,7 +158,7 @@ export function showToast(type: string = 'success', title: string, options: any
|
|
|
123
158
|
// Cancel Button Styling
|
|
124
159
|
cancelButton: "",
|
|
125
160
|
// Close Button Styling
|
|
126
|
-
closeButton: toastMainClass + '-close-button !w-[16px] !h-[16px] !absolute !top-[-4px] !
|
|
161
|
+
closeButton: toastMainClass + '-close-button !w-[16px] !h-[16px] !absolute !top-[-4px] !start-[-4px] z-10 ' +
|
|
127
162
|
'!flex !items-center !justify-center ' +
|
|
128
163
|
'!bg-[hsl(var(--grey7))] !border !border-[hsl(var(--grey5))] !rounded-full !text-white ' +
|
|
129
164
|
'[&_svg]:!text-white [&_svg]:!fill-white [&_svg]:!stroke-white'
|
|
@@ -14,7 +14,7 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
|
|
|
14
14
|
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
15
15
|
$$bindings?: Bindings;
|
|
16
16
|
} & Exports;
|
|
17
|
-
(internal: unknown, props: {
|
|
17
|
+
(internal: unknown, props: Props & {
|
|
18
18
|
$$events?: Events;
|
|
19
19
|
$$slots?: Slots;
|
|
20
20
|
}): Exports & {
|
|
@@ -23,7 +23,14 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
|
|
|
23
23
|
};
|
|
24
24
|
z_$$bindings?: Bindings;
|
|
25
25
|
}
|
|
26
|
-
declare const ToasterModal: $$__sveltets_2_IsomorphicComponent<
|
|
26
|
+
declare const ToasterModal: $$__sveltets_2_IsomorphicComponent<{
|
|
27
|
+
/**
|
|
28
|
+
* The words a screen reader hears: the region that holds the toasts ("Notifications", read with the key that moves
|
|
29
|
+
* focus to it) and the button that closes one ("Close toast"). A page in another language gives its own words;
|
|
30
|
+
* left out, the English ones of the library are used.
|
|
31
|
+
*/ containerAriaLabel?: string | undefined;
|
|
32
|
+
closeButtonAriaLabel?: string | undefined;
|
|
33
|
+
}, {
|
|
27
34
|
[evt: string]: CustomEvent<any>;
|
|
28
35
|
}, {}, {}, string>;
|
|
29
36
|
type ToasterModal = InstanceType<typeof ToasterModal>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the toasters are drawn.
|
|
3
|
+
*
|
|
4
|
+
* `showToast` colours the icon and the title of a toast after the toast has been drawn, by looking for them in the
|
|
5
|
+
* tree. `document.querySelector` never looks inside a shadow root, so for a toaster that a module draws inside its
|
|
6
|
+
* shadow root that lookup found nothing and the toast kept the library's grey. A toaster says which root it is drawn
|
|
7
|
+
* in (the page's document, or a shadow root), and the lookup looks there.
|
|
8
|
+
*/
|
|
9
|
+
/** What a lookup needs of a root: the `document` of a page and a `ShadowRoot` both have it. */
|
|
10
|
+
export interface ToastLookupRoot {
|
|
11
|
+
querySelector(selectors: string): Element | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Says that a toaster is drawn in `root`. Returns the function that says it is gone: call it when the toaster is
|
|
15
|
+
* removed. Calling it twice is the same as calling it once, so a toaster that is destroyed twice does not take another
|
|
16
|
+
* toaster's place in the count.
|
|
17
|
+
*/
|
|
18
|
+
export declare function registerToasterRoot(root: ToastLookupRoot): () => void;
|
|
19
|
+
/**
|
|
20
|
+
* The roots to look for the elements of a toast in: every root a toaster is mounted in, or `fallbackRoot` (the page's
|
|
21
|
+
* `document`) when no toaster has said where it is, as before a toaster is mounted.
|
|
22
|
+
*/
|
|
23
|
+
export declare function toastLookupRoots(fallbackRoot: ToastLookupRoot): ToastLookupRoot[];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where the toasters are drawn.
|
|
3
|
+
*
|
|
4
|
+
* `showToast` colours the icon and the title of a toast after the toast has been drawn, by looking for them in the
|
|
5
|
+
* tree. `document.querySelector` never looks inside a shadow root, so for a toaster that a module draws inside its
|
|
6
|
+
* shadow root that lookup found nothing and the toast kept the library's grey. A toaster says which root it is drawn
|
|
7
|
+
* in (the page's document, or a shadow root), and the lookup looks there.
|
|
8
|
+
*/
|
|
9
|
+
/** The roots toasters are mounted in, with how many toasters each has (two in one root are allowed, if odd). */
|
|
10
|
+
const mountedRoots = new Map();
|
|
11
|
+
/**
|
|
12
|
+
* Says that a toaster is drawn in `root`. Returns the function that says it is gone: call it when the toaster is
|
|
13
|
+
* removed. Calling it twice is the same as calling it once, so a toaster that is destroyed twice does not take another
|
|
14
|
+
* toaster's place in the count.
|
|
15
|
+
*/
|
|
16
|
+
export function registerToasterRoot(root) {
|
|
17
|
+
mountedRoots.set(root, (mountedRoots.get(root) ?? 0) + 1);
|
|
18
|
+
let isRegistered = true;
|
|
19
|
+
return () => {
|
|
20
|
+
if (!isRegistered)
|
|
21
|
+
return;
|
|
22
|
+
isRegistered = false;
|
|
23
|
+
const remaining = (mountedRoots.get(root) ?? 1) - 1;
|
|
24
|
+
if (remaining <= 0)
|
|
25
|
+
mountedRoots.delete(root);
|
|
26
|
+
else
|
|
27
|
+
mountedRoots.set(root, remaining);
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The roots to look for the elements of a toast in: every root a toaster is mounted in, or `fallbackRoot` (the page's
|
|
32
|
+
* `document`) when no toaster has said where it is, as before a toaster is mounted.
|
|
33
|
+
*/
|
|
34
|
+
export function toastLookupRoots(fallbackRoot) {
|
|
35
|
+
return mountedRoots.size > 0 ? [...mountedRoots.keys()] : [fallbackRoot];
|
|
36
|
+
}
|