@sveltia/ui 0.78.3 → 0.79.0
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/dist/components/alert/alert-content.svelte +51 -0
- package/dist/components/alert/alert-content.svelte.d.ts +39 -0
- package/dist/components/alert/alert.d.ts +3 -0
- package/dist/components/alert/alert.js +21 -0
- package/dist/components/alert/alert.svelte +6 -30
- package/dist/components/alert/infobar.svelte +7 -21
- package/dist/components/alert/infobar.svelte.d.ts +2 -2
- package/dist/components/button/button.svelte +11 -11
- package/dist/components/button/button.svelte.d.ts +2 -2
- package/dist/components/button/select-button.svelte +1 -1
- package/dist/components/button/select-button.svelte.d.ts +2 -2
- package/dist/components/button/split-button.svelte +1 -1
- package/dist/components/button/split-button.svelte.d.ts +3 -3
- package/dist/components/calendar/calendar.d.ts +2 -0
- package/dist/components/calendar/calendar.js +34 -0
- package/dist/components/calendar/calendar.svelte +49 -5
- package/dist/components/checkbox/checkbox.svelte +11 -4
- package/dist/components/checkbox/checkbox.svelte.d.ts +2 -2
- package/dist/components/dialog/alert-dialog.svelte +1 -1
- package/dist/components/dialog/alert-dialog.svelte.d.ts +2 -2
- package/dist/components/dialog/confirmation-dialog.svelte +1 -1
- package/dist/components/dialog/confirmation-dialog.svelte.d.ts +2 -2
- package/dist/components/dialog/dialog.svelte +8 -18
- package/dist/components/dialog/dialog.svelte.d.ts +2 -2
- package/dist/components/dialog/modal-close-button.svelte +50 -0
- package/dist/components/dialog/modal-close-button.svelte.d.ts +43 -0
- package/dist/components/dialog/prompt-dialog.svelte +1 -1
- package/dist/components/dialog/prompt-dialog.svelte.d.ts +4 -4
- package/dist/components/disclosure/disclosure.svelte +1 -1
- package/dist/components/drawer/drawer.svelte +12 -34
- package/dist/components/drawer/drawer.svelte.d.ts +1 -1
- package/dist/components/emoji/caret.d.ts +1 -1
- package/dist/components/emoji/caret.js +1 -1
- package/dist/components/emoji/emoji-suggestions.svelte +1 -1
- package/dist/components/emoji/emoji-suggestions.svelte.d.ts +3 -3
- package/dist/components/emoji/emoji.d.ts +2 -2
- package/dist/components/emoji/emoji.js +1 -1
- package/dist/components/emoji/position.d.ts +2 -2
- package/dist/components/emoji/position.js +1 -1
- package/dist/components/grid/grid-body.svelte +6 -2
- package/dist/components/grid/grid-cell.svelte +3 -9
- package/dist/components/grid/grid-col-header.svelte +3 -9
- package/dist/components/grid/grid-foot.svelte +4 -11
- package/dist/components/grid/grid-head.svelte +4 -11
- package/dist/components/grid/grid-row-header.svelte +3 -10
- package/dist/components/grid/grid-row.svelte +3 -16
- package/dist/components/listbox/listbox.svelte +1 -1
- package/dist/components/listbox/listbox.svelte.d.ts +1 -1
- package/dist/components/listbox/option.svelte +1 -1
- package/dist/components/listbox/option.svelte.d.ts +2 -2
- package/dist/components/menu/menu-button.svelte +2 -2
- package/dist/components/menu/menu-button.svelte.d.ts +4 -4
- package/dist/components/menu/menu-item-checkable.svelte +71 -0
- package/dist/components/menu/menu-item-checkable.svelte.d.ts +25 -0
- package/dist/components/menu/menu-item-checkbox.svelte +3 -36
- package/dist/components/menu/menu-item-checkbox.svelte.d.ts +3 -3
- package/dist/components/menu/menu-item-group.svelte +8 -5
- package/dist/components/menu/menu-item-group.svelte.d.ts +9 -1
- package/dist/components/menu/menu-item-radio.svelte +3 -36
- package/dist/components/menu/menu-item-radio.svelte.d.ts +3 -3
- package/dist/components/menu/menu-item.svelte +22 -6
- package/dist/components/menu/menu-item.svelte.d.ts +4 -4
- package/dist/components/radio/radio.svelte +12 -1
- package/dist/components/resizable-pane/resizable-handle.svelte +14 -18
- package/dist/components/resizable-pane/resizable-pane-group.svelte +9 -6
- package/dist/components/resizable-pane/resizable-pane.svelte +4 -4
- package/dist/components/resizable-pane/resizable-pane.svelte.d.ts +7 -6
- package/dist/components/resizable-pane/sizing.d.ts +5 -4
- package/dist/components/resizable-pane/sizing.js +84 -25
- package/dist/components/scroll/infinite-scroll.svelte +16 -21
- package/dist/components/select/combobox.svelte +43 -52
- package/dist/components/select/combobox.svelte.d.ts +2 -2
- package/dist/components/select/select-tags.svelte +7 -1
- package/dist/components/select/select.svelte +2 -22
- package/dist/components/select/select.svelte.d.ts +1 -1
- package/dist/components/slider/slider.d.ts +6 -0
- package/dist/components/slider/slider.js +55 -2
- package/dist/components/slider/slider.svelte +63 -32
- package/dist/components/table/table-cell.svelte +3 -9
- package/dist/components/table/table-col-header.svelte +3 -9
- package/dist/components/table/table-foot.svelte +4 -11
- package/dist/components/table/table-head.svelte +4 -11
- package/dist/components/table/table-part.svelte +69 -0
- package/dist/components/table/table-part.svelte.d.ts +48 -0
- package/dist/components/table/table-row-header.svelte +3 -10
- package/dist/components/table/table-row.svelte +3 -10
- package/dist/components/tabs/tab-list.svelte +12 -0
- package/dist/components/tabs/tab.svelte +1 -1
- package/dist/components/tabs/tab.svelte.d.ts +2 -2
- package/dist/components/text-editor/constants.d.ts +5 -5
- package/dist/components/text-editor/constants.js +1 -1
- package/dist/components/text-editor/core.d.ts +4 -5
- package/dist/components/text-editor/core.js +376 -273
- package/dist/components/text-editor/emoji-autocomplete.svelte +1 -1
- package/dist/components/text-editor/lexical-root.svelte +1 -1
- package/dist/components/text-editor/raw-markdown.d.ts +6 -33
- package/dist/components/text-editor/raw-markdown.js +63 -8
- package/dist/components/text-editor/shiki/facade.d.ts +1 -1
- package/dist/components/text-editor/shiki/facade.js +63 -48
- package/dist/components/text-editor/shiki/generated.d.ts +1 -1
- package/dist/components/text-editor/shiki/generated.js +1 -1
- package/dist/components/text-editor/shiki/highlighter.d.ts +6 -1
- package/dist/components/text-editor/shiki/highlighter.js +3 -4
- package/dist/components/text-editor/shiki/loader.d.ts +1 -1
- package/dist/components/text-editor/shiki/loader.js +1 -1
- package/dist/components/text-editor/shiki/version.d.ts +1 -1
- package/dist/components/text-editor/shiki/version.js +1 -1
- package/dist/components/text-editor/store.svelte.d.ts +1 -1
- package/dist/components/text-editor/store.svelte.js +5 -2
- package/dist/components/text-editor/text-editor.svelte +2 -2
- package/dist/components/text-editor/text-editor.svelte.d.ts +3 -3
- package/dist/components/text-editor/toolbar/code-language-switcher.svelte +24 -16
- package/dist/components/text-editor/toolbar/format-text-button.svelte +7 -31
- package/dist/components/text-editor/toolbar/format-text-button.svelte.d.ts +1 -1
- package/dist/components/text-editor/toolbar/insert-component.d.ts +3 -0
- package/dist/components/text-editor/toolbar/insert-component.js +34 -0
- package/dist/components/text-editor/toolbar/insert-item-button.svelte +4 -24
- package/dist/components/text-editor/toolbar/insert-item-button.svelte.d.ts +1 -1
- package/dist/components/text-editor/toolbar/insert-link-button.svelte +9 -25
- package/dist/components/text-editor/toolbar/insert-menu-button.svelte +4 -24
- package/dist/components/text-editor/toolbar/insert-menu-button.svelte.d.ts +1 -1
- package/dist/components/text-editor/toolbar/text-editor-toolbar.svelte +1 -1
- package/dist/components/text-editor/toolbar/toggle-block-menu-item.svelte +31 -35
- package/dist/components/text-editor/toolbar/toggle-block-menu-item.svelte.d.ts +1 -1
- package/dist/components/text-editor/toolbar/toolbar-wrapper.svelte +0 -10
- package/dist/components/text-editor/toolbar/toolbar-wrapper.svelte.d.ts +1 -11
- package/dist/components/text-editor/transformers/table.d.ts +0 -1
- package/dist/components/text-editor/transformers/table.js +1 -2
- package/dist/components/text-field/emoji-autocomplete.svelte +1 -1
- package/dist/components/text-field/masked-input.svelte +179 -0
- package/dist/components/text-field/masked-input.svelte.d.ts +42 -0
- package/dist/components/text-field/number-input.js +7 -1
- package/dist/components/text-field/number-input.svelte +13 -5
- package/dist/components/text-field/number-input.svelte.d.ts +3 -3
- package/dist/components/text-field/password-input.svelte +3 -116
- package/dist/components/text-field/password-input.svelte.d.ts +3 -3
- package/dist/components/text-field/search-bar.svelte +1 -1
- package/dist/components/text-field/search-bar.svelte.d.ts +3 -3
- package/dist/components/text-field/secret-input.svelte +3 -119
- package/dist/components/text-field/secret-input.svelte.d.ts +3 -3
- package/dist/components/text-field/text-area.svelte +1 -1
- package/dist/components/text-field/text-area.svelte.d.ts +3 -3
- package/dist/components/text-field/text-input.svelte +1 -1
- package/dist/components/text-field/text-input.svelte.d.ts +3 -3
- package/dist/components/toast/toast.svelte +11 -20
- package/dist/components/toast/toast.svelte.d.ts +1 -1
- package/dist/components/tree/tree-item.svelte +1 -1
- package/dist/components/tree/tree-item.svelte.d.ts +1 -1
- package/dist/components/tree/tree.svelte +1 -1
- package/dist/components/tree/tree.svelte.d.ts +1 -1
- package/dist/components/util/font-links.svelte +1 -0
- package/dist/components/util/modal.svelte +37 -1
- package/dist/components/util/modal.svelte.d.ts +1 -1
- package/dist/components/util/popup.svelte +2 -5
- package/dist/components/util/popup.svelte.d.ts +2 -2
- package/dist/components/util/visibility-observer.svelte +1 -0
- package/dist/locales/ar.yaml +1 -1
- package/dist/locales/sk.yaml +136 -0
- package/dist/services/group.svelte.d.ts +10 -1
- package/dist/services/group.svelte.js +361 -251
- package/dist/services/navigation.d.ts +19 -0
- package/dist/services/navigation.js +84 -0
- package/dist/services/popup-position.d.ts +90 -0
- package/dist/services/popup-position.js +275 -0
- package/dist/services/popup.svelte.d.ts +16 -17
- package/dist/services/popup.svelte.js +25 -169
- package/dist/services/scroll.d.ts +1 -0
- package/dist/services/scroll.js +17 -0
- package/dist/services/select.svelte.d.ts +2 -2
- package/dist/services/select.svelte.js +1 -1
- package/dist/services/text.d.ts +2 -0
- package/dist/services/text.js +28 -0
- package/dist/services/tree.svelte.d.ts +3 -11
- package/dist/services/tree.svelte.js +35 -77
- package/dist/services/type-ahead.d.ts +0 -4
- package/dist/services/type-ahead.js +3 -1
- package/dist/services/widget.d.ts +8 -0
- package/dist/services/widget.js +39 -0
- package/dist/shiki-engine.js +15 -15
- package/dist/styles/mixins.scss +126 -0
- package/package.json +38 -34
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
The content shared by `<Alert>` and `<Infobar>`: the status icon, the status spelled out off
|
|
4
|
+
screen, and the message. Internal; not exported.
|
|
5
|
+
-->
|
|
6
|
+
<script>
|
|
7
|
+
import { _ } from '@sveltia/i18n';
|
|
8
|
+
import Icon from '../icon/icon.svelte';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @import { Snippet } from 'svelte';
|
|
12
|
+
* @import { AlertStatus } from './alert.js';
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {object} Props
|
|
17
|
+
* @property {AlertStatus} status Alert status.
|
|
18
|
+
* @property {Snippet} [children] Primary slot content.
|
|
19
|
+
* @property {Snippet} [icon] Icon slot content.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** @type {Props} */
|
|
23
|
+
let {
|
|
24
|
+
/* eslint-disable prefer-const */
|
|
25
|
+
status,
|
|
26
|
+
children = undefined,
|
|
27
|
+
icon = undefined,
|
|
28
|
+
/* eslint-enable prefer-const */
|
|
29
|
+
} = $props();
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<!--
|
|
33
|
+
The colour and icon tell sighted users how serious the message is; the icon is hidden from
|
|
34
|
+
assistive technology, so the status is also spelled out for screen readers, off screen.
|
|
35
|
+
-->
|
|
36
|
+
{#if icon}
|
|
37
|
+
{@render icon()}
|
|
38
|
+
{:else}
|
|
39
|
+
<Icon name={status === 'success' ? 'check_circle' : status} />
|
|
40
|
+
{/if}
|
|
41
|
+
<span class="status-label">{_(`_sui.alert.${status}`)}</span>
|
|
42
|
+
{@render children?.()}
|
|
43
|
+
|
|
44
|
+
<style>.status-label {
|
|
45
|
+
position: absolute;
|
|
46
|
+
overflow: hidden;
|
|
47
|
+
clip-path: inset(50%);
|
|
48
|
+
width: 1px;
|
|
49
|
+
height: 1px;
|
|
50
|
+
white-space: nowrap;
|
|
51
|
+
}</style>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export default AlertContent;
|
|
2
|
+
type AlertContent = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<Props>): void;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* The content shared by `<Alert>` and `<Infobar>`: the status icon, the status spelled out off
|
|
8
|
+
* screen, and the message. Internal; not exported.
|
|
9
|
+
*/
|
|
10
|
+
declare const AlertContent: import("svelte").Component<{
|
|
11
|
+
/**
|
|
12
|
+
* Alert status.
|
|
13
|
+
*/
|
|
14
|
+
status: AlertStatus;
|
|
15
|
+
/**
|
|
16
|
+
* Primary slot content.
|
|
17
|
+
*/
|
|
18
|
+
children?: Snippet<[]> | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Icon slot content.
|
|
21
|
+
*/
|
|
22
|
+
icon?: Snippet<[]> | undefined;
|
|
23
|
+
}, {}, "">;
|
|
24
|
+
type Props = {
|
|
25
|
+
/**
|
|
26
|
+
* Alert status.
|
|
27
|
+
*/
|
|
28
|
+
status: AlertStatus;
|
|
29
|
+
/**
|
|
30
|
+
* Primary slot content.
|
|
31
|
+
*/
|
|
32
|
+
children?: Snippet<[]> | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Icon slot content.
|
|
35
|
+
*/
|
|
36
|
+
icon?: Snippet<[]> | undefined;
|
|
37
|
+
};
|
|
38
|
+
import type { AlertStatus } from './alert.js';
|
|
39
|
+
import type { Snippet } from 'svelte';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export function getAlertRole(status: AlertStatus): "alert" | "status";
|
|
2
|
+
export function getAlertAriaLive(role: "alert" | "status", ariaLive?: "off" | "polite" | "assertive"): "off" | "polite" | "assertive";
|
|
3
|
+
export type AlertStatus = "error" | "warning" | "info" | "success";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {'error' | 'warning' | 'info' | 'success'} AlertStatus
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Get the ARIA role for an alert status. Errors and warnings are `alert` and interrupt; information
|
|
7
|
+
* and success are `status` and wait.
|
|
8
|
+
* @param {AlertStatus} status Alert status.
|
|
9
|
+
* @returns {'alert' | 'status'} Role.
|
|
10
|
+
*/
|
|
11
|
+
export const getAlertRole = (status) =>
|
|
12
|
+
status === 'error' || status === 'warning' ? 'alert' : 'status';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get the ARIA live region politeness for an alert role, unless one is given explicitly.
|
|
16
|
+
* @param {'alert' | 'status'} role Role from {@link getAlertRole}.
|
|
17
|
+
* @param {'off' | 'polite' | 'assertive'} [ariaLive] Explicit politeness, if any.
|
|
18
|
+
* @returns {'off' | 'polite' | 'assertive'} Politeness.
|
|
19
|
+
*/
|
|
20
|
+
export const getAlertAriaLive = (role, ariaLive) =>
|
|
21
|
+
ariaLive ?? (role === 'alert' ? 'assertive' : 'polite');
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
@see https://www.w3.org/WAI/ARIA/apg/patterns/alert/
|
|
6
6
|
-->
|
|
7
7
|
<script>
|
|
8
|
-
import
|
|
9
|
-
import
|
|
8
|
+
import AlertContent from './alert-content.svelte';
|
|
9
|
+
import { getAlertAriaLive, getAlertRole } from './alert.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @import { Snippet } from 'svelte';
|
|
@@ -35,38 +35,14 @@
|
|
|
35
35
|
/* eslint-enable prefer-const */
|
|
36
36
|
} = $props();
|
|
37
37
|
|
|
38
|
-
const role = $derived(status
|
|
38
|
+
const role = $derived(getAlertRole(status));
|
|
39
39
|
</script>
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
assistive technology, so the status is also spelled out for screen readers, off screen.
|
|
44
|
-
-->
|
|
45
|
-
<div
|
|
46
|
-
{...restProps}
|
|
47
|
-
{role}
|
|
48
|
-
class="sui alert {status}"
|
|
49
|
-
aria-live={ariaLive ?? (role === 'alert' ? 'assertive' : 'polite')}
|
|
50
|
-
>
|
|
51
|
-
{#if icon}
|
|
52
|
-
{@render icon()}
|
|
53
|
-
{:else}
|
|
54
|
-
<Icon name={status === 'success' ? 'check_circle' : status} />
|
|
55
|
-
{/if}
|
|
56
|
-
<span class="status-label">{_(`_sui.alert.${status}`)}</span>
|
|
57
|
-
{@render children?.()}
|
|
41
|
+
<div {...restProps} {role} class="sui alert {status}" aria-live={getAlertAriaLive(role, ariaLive)}>
|
|
42
|
+
<AlertContent {status} {children} {icon} />
|
|
58
43
|
</div>
|
|
59
44
|
|
|
60
|
-
<style>.
|
|
61
|
-
position: absolute;
|
|
62
|
-
overflow: hidden;
|
|
63
|
-
clip-path: inset(50%);
|
|
64
|
-
width: 1px;
|
|
65
|
-
height: 1px;
|
|
66
|
-
white-space: nowrap;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.alert {
|
|
45
|
+
<style>.alert {
|
|
70
46
|
display: flex;
|
|
71
47
|
align-items: center;
|
|
72
48
|
gap: var(--gap, 8px);
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { _ } from '@sveltia/i18n';
|
|
3
3
|
import Button from '../button/button.svelte';
|
|
4
4
|
import Icon from '../icon/icon.svelte';
|
|
5
|
+
import AlertContent from './alert-content.svelte';
|
|
6
|
+
import { getAlertAriaLive, getAlertRole } from './alert.js';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* @import { Snippet } from 'svelte';
|
|
@@ -9,7 +11,7 @@
|
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* @typedef {object} Props
|
|
12
|
-
* @property {boolean} [show] Whether to show the
|
|
14
|
+
* @property {boolean} [show] Whether to show the infobar.
|
|
13
15
|
* @property {boolean} [dismissible] Whether to show the close button.
|
|
14
16
|
* @property {'error' | 'warning' | 'info' | 'success'} [status] Information status. Errors and
|
|
15
17
|
* warnings are `role="alert"` and interrupt; information and success are `role="status"` and
|
|
@@ -34,20 +36,13 @@
|
|
|
34
36
|
/* eslint-enable prefer-const */
|
|
35
37
|
} = $props();
|
|
36
38
|
|
|
37
|
-
const role = $derived(status
|
|
39
|
+
const role = $derived(getAlertRole(status));
|
|
38
40
|
</script>
|
|
39
41
|
|
|
40
42
|
{#if show}
|
|
41
43
|
<div role="none" class={['infobar', status]}>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
{#if icon}
|
|
45
|
-
{@render icon()}
|
|
46
|
-
{:else}
|
|
47
|
-
<Icon name={status === 'success' ? 'check_circle' : status} />
|
|
48
|
-
{/if}
|
|
49
|
-
<span class="status-label">{_(`_sui.alert.${status}`)}</span>
|
|
50
|
-
{@render children?.()}
|
|
44
|
+
<div {role} class="message" aria-live={getAlertAriaLive(role, ariaLive)}>
|
|
45
|
+
<AlertContent {status} {children} {icon} />
|
|
51
46
|
</div>
|
|
52
47
|
{#if dismissible}
|
|
53
48
|
<div role="none">
|
|
@@ -68,16 +63,7 @@
|
|
|
68
63
|
</div>
|
|
69
64
|
{/if}
|
|
70
65
|
|
|
71
|
-
<style>.
|
|
72
|
-
position: absolute;
|
|
73
|
-
overflow: hidden;
|
|
74
|
-
clip-path: inset(50%);
|
|
75
|
-
width: 1px;
|
|
76
|
-
height: 1px;
|
|
77
|
-
white-space: nowrap;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.infobar {
|
|
66
|
+
<style>.infobar {
|
|
81
67
|
flex: none;
|
|
82
68
|
display: flex;
|
|
83
69
|
align-items: center;
|
|
@@ -5,7 +5,7 @@ type Infobar = {
|
|
|
5
5
|
};
|
|
6
6
|
declare const Infobar: import("svelte").Component<{
|
|
7
7
|
/**
|
|
8
|
-
* Whether to show the
|
|
8
|
+
* Whether to show the infobar.
|
|
9
9
|
*/
|
|
10
10
|
show?: boolean | undefined;
|
|
11
11
|
/**
|
|
@@ -38,7 +38,7 @@ declare const Infobar: import("svelte").Component<{
|
|
|
38
38
|
}, {}, "show">;
|
|
39
39
|
type Props = {
|
|
40
40
|
/**
|
|
41
|
-
* Whether to show the
|
|
41
|
+
* Whether to show the infobar.
|
|
42
42
|
*/
|
|
43
43
|
show?: boolean | undefined;
|
|
44
44
|
/**
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import Popup from '../util/popup.svelte';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* @import { ButtonProps, CommonEventHandlers } from '../../typedefs';
|
|
14
|
+
* @import { ButtonProps, CommonEventHandlers } from '../../typedefs.js';
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -51,6 +51,14 @@
|
|
|
51
51
|
} = $props();
|
|
52
52
|
</script>
|
|
53
53
|
|
|
54
|
+
{#snippet labelText()}
|
|
55
|
+
<span role="none" class="label" dir={labelDir}>
|
|
56
|
+
<TruncatedText {lines}>
|
|
57
|
+
{label}
|
|
58
|
+
</TruncatedText>
|
|
59
|
+
</span>
|
|
60
|
+
{/snippet}
|
|
61
|
+
|
|
54
62
|
<!--
|
|
55
63
|
`aria-readonly` is only rendered when it applies: the attribute isn’t supported on the `button`
|
|
56
64
|
role (or `option`, `tab` and `menuitem`, which also wrap this component), and Svelte would
|
|
@@ -86,11 +94,7 @@
|
|
|
86
94
|
{@render startIcon?.()}
|
|
87
95
|
{#if variant === 'link'}
|
|
88
96
|
{#if label}
|
|
89
|
-
|
|
90
|
-
<TruncatedText {lines}>
|
|
91
|
-
{label}
|
|
92
|
-
</TruncatedText>
|
|
93
|
-
</span>
|
|
97
|
+
{@render labelText()}
|
|
94
98
|
{:else}
|
|
95
99
|
<span role="none" class="label">
|
|
96
100
|
{@render children?.()}
|
|
@@ -98,11 +102,7 @@
|
|
|
98
102
|
{/if}
|
|
99
103
|
{:else}
|
|
100
104
|
{#if label}
|
|
101
|
-
|
|
102
|
-
<TruncatedText {lines}>
|
|
103
|
-
{label}
|
|
104
|
-
</TruncatedText>
|
|
105
|
-
</span>
|
|
105
|
+
{@render labelText()}
|
|
106
106
|
{/if}
|
|
107
107
|
{@render children?.()}
|
|
108
108
|
{/if}
|
|
@@ -8,5 +8,5 @@ type Button = {
|
|
|
8
8
|
* @see https://w3c.github.io/aria/#button
|
|
9
9
|
* @see https://www.w3.org/WAI/ARIA/apg/patterns/button/
|
|
10
10
|
*/
|
|
11
|
-
declare const Button: import("svelte").Component<ButtonProps & import("../../typedefs").KeyboardEventHandlers & import("../../typedefs").MouseEventHandlers & import("../../typedefs").PointerEventHandlers & import("../../typedefs").FocusEventHandlers & import("../../typedefs").DragEventHandlers & Record<string, any>, {}, "element">;
|
|
12
|
-
import type { ButtonProps } from '../../typedefs';
|
|
11
|
+
declare const Button: import("svelte").Component<ButtonProps & import("../../typedefs.js").KeyboardEventHandlers & import("../../typedefs.js").MouseEventHandlers & import("../../typedefs.js").PointerEventHandlers & import("../../typedefs.js").FocusEventHandlers & import("../../typedefs.js").DragEventHandlers & Record<string, any>, {}, "element">;
|
|
12
|
+
import type { ButtonProps } from '../../typedefs.js';
|
|
@@ -8,7 +8,7 @@ type SelectButton = {
|
|
|
8
8
|
* @see https://w3c.github.io/aria/#radio
|
|
9
9
|
* @see https://www.w3.org/WAI/ARIA/apg/patterns/radio/
|
|
10
10
|
*/
|
|
11
|
-
declare const SelectButton: import("svelte").Component<ButtonProps & import("../../typedefs").KeyboardEventHandlers & import("../../typedefs").MouseEventHandlers & import("../../typedefs").PointerEventHandlers & import("../../typedefs").FocusEventHandlers & import("../../typedefs").DragEventHandlers & {
|
|
11
|
+
declare const SelectButton: import("svelte").Component<ButtonProps & import("../../typedefs.js").KeyboardEventHandlers & import("../../typedefs.js").MouseEventHandlers & import("../../typedefs.js").PointerEventHandlers & import("../../typedefs.js").FocusEventHandlers & import("../../typedefs.js").DragEventHandlers & {
|
|
12
12
|
/**
|
|
13
13
|
* Whether to select the widget. An alias of the `aria-checked`
|
|
14
14
|
* attribute. Because the UI is a button, we expose `selected` instead of `checked`.
|
|
@@ -22,4 +22,4 @@ type Props = {
|
|
|
22
22
|
*/
|
|
23
23
|
selected?: boolean | undefined;
|
|
24
24
|
};
|
|
25
|
-
import type { ButtonProps } from '../../typedefs';
|
|
25
|
+
import type { ButtonProps } from '../../typedefs.js';
|
|
@@ -9,7 +9,7 @@ type SplitButton = {
|
|
|
9
9
|
* Match Formatting and Keep Text Only options.
|
|
10
10
|
* @see https://www.google.com/search?q=split+button&tbm=isch
|
|
11
11
|
*/
|
|
12
|
-
declare const SplitButton: import("svelte").Component<ButtonProps & import("../../typedefs").KeyboardEventHandlers & import("../../typedefs").MouseEventHandlers & import("../../typedefs").PointerEventHandlers & import("../../typedefs").FocusEventHandlers & import("../../typedefs").DragEventHandlers & {
|
|
12
|
+
declare const SplitButton: import("svelte").Component<ButtonProps & import("../../typedefs.js").KeyboardEventHandlers & import("../../typedefs.js").MouseEventHandlers & import("../../typedefs.js").PointerEventHandlers & import("../../typedefs.js").FocusEventHandlers & import("../../typedefs.js").DragEventHandlers & {
|
|
13
13
|
/**
|
|
14
14
|
* Where to show the dropdown menu.
|
|
15
15
|
*/
|
|
@@ -45,6 +45,6 @@ type Props = {
|
|
|
45
45
|
*/
|
|
46
46
|
popup?: Snippet<[]> | undefined;
|
|
47
47
|
};
|
|
48
|
-
import type { ButtonProps } from '../../typedefs';
|
|
49
|
-
import type { PopupPosition } from '../../typedefs';
|
|
48
|
+
import type { ButtonProps } from '../../typedefs.js';
|
|
49
|
+
import type { PopupPosition } from '../../typedefs.js';
|
|
50
50
|
import type { Snippet } from 'svelte';
|
|
@@ -12,6 +12,8 @@ export const DAY_GRID_SIZE: 42;
|
|
|
12
12
|
export const MONTH_NAMES: string[];
|
|
13
13
|
export function getFirstDayOfMonth(date: Date): Date;
|
|
14
14
|
export function addMonths(firstDay: Date, delta: number): Date;
|
|
15
|
+
export function addDays(date: Date, delta: number): Date;
|
|
16
|
+
export function getArrowKeyDayOffset(key: string, rtl?: boolean): number | undefined;
|
|
15
17
|
export function getCalendarDays(firstDay: Date): Date[];
|
|
16
18
|
export function toDateString(date: Date): string;
|
|
17
19
|
export function getToday(now?: Date): Date;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { date as formatLocaleDate } from '@sveltia/i18n';
|
|
2
2
|
|
|
3
|
+
import { getArrowKeys } from '../../services/navigation.js';
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Date helpers behind `<Calendar>`, kept apart from the component so the grid can be tested without
|
|
5
7
|
* rendering anything.
|
|
@@ -59,6 +61,38 @@ export const addMonths = (firstDay, delta) => {
|
|
|
59
61
|
return date;
|
|
60
62
|
};
|
|
61
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Get another day, relative to the given one.
|
|
66
|
+
* @param {Date} date Any date.
|
|
67
|
+
* @param {number} delta Number of days to move by; negative to go back.
|
|
68
|
+
* @returns {Date} A new date, `delta` days away.
|
|
69
|
+
*/
|
|
70
|
+
export const addDays = (date, delta) => {
|
|
71
|
+
const day = new Date(date);
|
|
72
|
+
|
|
73
|
+
day.setUTCDate(day.getUTCDate() + delta);
|
|
74
|
+
|
|
75
|
+
return day;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get how many days an arrow key moves the cursor on the day grid: a day sideways, a week up or
|
|
80
|
+
* down. The inline arrows are mirrored for RTL.
|
|
81
|
+
* @param {string} key `KeyboardEvent.key` value.
|
|
82
|
+
* @param {boolean} [rtl] Whether the layout is right-to-left.
|
|
83
|
+
* @returns {number | undefined} Number of days, or `undefined` if the key is not an arrow key.
|
|
84
|
+
*/
|
|
85
|
+
export const getArrowKeyDayOffset = (key, rtl = false) => {
|
|
86
|
+
const { prevKey, nextKey } = getArrowKeys('horizontal', rtl);
|
|
87
|
+
|
|
88
|
+
return /** @type {Record<string, number>} */ ({
|
|
89
|
+
ArrowUp: -7,
|
|
90
|
+
ArrowDown: 7,
|
|
91
|
+
[prevKey]: -1,
|
|
92
|
+
[nextKey]: 1,
|
|
93
|
+
})[key];
|
|
94
|
+
};
|
|
95
|
+
|
|
62
96
|
/**
|
|
63
97
|
* Get the days to be laid out in the calendar grid.
|
|
64
98
|
* @param {Date} firstDay First day of the month being displayed.
|
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
import Spacer from '../divider/spacer.svelte';
|
|
12
12
|
import Icon from '../icon/icon.svelte';
|
|
13
13
|
import {
|
|
14
|
+
addDays,
|
|
14
15
|
addMonths,
|
|
15
16
|
formatDate,
|
|
17
|
+
getArrowKeyDayOffset,
|
|
16
18
|
getCalendarDays,
|
|
17
19
|
getFirstDayOfMonth,
|
|
18
20
|
getToday,
|
|
@@ -53,6 +55,46 @@
|
|
|
53
55
|
/** @type {HTMLElement | undefined} */
|
|
54
56
|
let grid = $state();
|
|
55
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Move the keyboard cursor, and with it the selection, by date rather than by cell: the group
|
|
60
|
+
* service would step through the 42 cells on the grid and stop at its edges, whereas a week up
|
|
61
|
+
* from the first of the month is a day in the previous month, which may not be on the grid at
|
|
62
|
+
* all. The month displayed follows the new {@link value}.
|
|
63
|
+
* @param {KeyboardEvent} event `keydown` event.
|
|
64
|
+
*/
|
|
65
|
+
const onGridKeyDown = (event) => {
|
|
66
|
+
const { key, shiftKey, altKey, ctrlKey, metaKey } = event;
|
|
67
|
+
const offset = getArrowKeyDayOffset(key, isRTL());
|
|
68
|
+
|
|
69
|
+
if (offset === undefined || shiftKey || altKey || ctrlKey || metaKey) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Keep the group service, which listens on the same element, from moving the cursor as well
|
|
74
|
+
event.preventDefault();
|
|
75
|
+
event.stopImmediatePropagation();
|
|
76
|
+
|
|
77
|
+
const focused = /** @type {HTMLButtonElement | null | undefined} */ (
|
|
78
|
+
grid?.querySelector('[role="option"].focused')
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
// Without a cursor, start from the selected day only if it’s on the grid. After browsing to
|
|
82
|
+
// another month, it isn’t, and moving from it would bring that month back. Land on today if
|
|
83
|
+
// it’s in the month displayed, or on the first of the month otherwise.
|
|
84
|
+
const cursor =
|
|
85
|
+
focused?.value ||
|
|
86
|
+
(value && dayList.some(({ day }) => toDateString(day) === value) ? value : undefined);
|
|
87
|
+
|
|
88
|
+
if (cursor) {
|
|
89
|
+
value = toDateString(addDays(new Date(cursor), offset));
|
|
90
|
+
} else {
|
|
91
|
+
value =
|
|
92
|
+
getFirstDayOfMonth(today).getTime() === firstDay.getTime()
|
|
93
|
+
? todayString
|
|
94
|
+
: toDateString(firstDay);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
56
98
|
// Keep the keyboard cursor on the selected day. The group service tracks the cursor with the
|
|
57
99
|
// `focused` class and `aria-activedescendant`, and moves both along with the selection it makes
|
|
58
100
|
// itself; this covers the starting point and a `value` set from outside, which may land in
|
|
@@ -107,7 +149,7 @@
|
|
|
107
149
|
//
|
|
108
150
|
}}
|
|
109
151
|
>
|
|
110
|
-
<Icon name=
|
|
152
|
+
<Icon name={isRTL() ? 'chevron_right' : 'chevron_left'} />
|
|
111
153
|
</Button>
|
|
112
154
|
<Button
|
|
113
155
|
aria-label={_('_sui.calendar.next_decade')}
|
|
@@ -145,7 +187,7 @@
|
|
|
145
187
|
firstDay = addMonths(firstDay, -1);
|
|
146
188
|
}}
|
|
147
189
|
>
|
|
148
|
-
<Icon name=
|
|
190
|
+
<Icon name={isRTL() ? 'chevron_right' : 'chevron_left'} />
|
|
149
191
|
</Button>
|
|
150
192
|
<Button
|
|
151
193
|
aria-label={_('_sui.calendar.next_month')}
|
|
@@ -157,9 +199,10 @@
|
|
|
157
199
|
</Button>
|
|
158
200
|
</div>
|
|
159
201
|
<!--
|
|
160
|
-
The day grid is a listbox laid out as a grid
|
|
161
|
-
|
|
162
|
-
context. The days are UTC-based, like
|
|
202
|
+
The day grid is a listbox laid out as a grid. The arrow keys move through it by date, handled
|
|
203
|
+
above; the group service still takes care of the rest, such as Home and End. Each day is named
|
|
204
|
+
by its full date: the digit alone means nothing out of context. The days are UTC-based, like
|
|
205
|
+
the `value`, so the names are formatted the same way.
|
|
163
206
|
The cells are keyed by date string rather than by `Date` object, which is recreated on every
|
|
164
207
|
update: a day that stays on the grid when the month changes — the last days of the previous
|
|
165
208
|
month, say — keeps its element, and with it the keyboard cursor.
|
|
@@ -169,6 +212,7 @@
|
|
|
169
212
|
role="listbox"
|
|
170
213
|
class="grid"
|
|
171
214
|
aria-label={monthLabel}
|
|
215
|
+
onkeydowncapture={onGridKeyDown}
|
|
172
216
|
onChange={(/** @type {CustomEvent} */ event) => {
|
|
173
217
|
value = event.detail.value;
|
|
174
218
|
}}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @import { Snippet } from 'svelte';
|
|
14
|
-
* @import { ButtonProps, CommonEventHandlers } from '../../typedefs';
|
|
14
|
+
* @import { ButtonProps, CommonEventHandlers } from '../../typedefs.js';
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -63,6 +63,13 @@
|
|
|
63
63
|
*/
|
|
64
64
|
let buttonElement = $state();
|
|
65
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Accessible name given as a prop or as a plain `aria-label` attribute. It takes the place of the
|
|
68
|
+
* visible label, which the button otherwise points at — but only when there is one to point at.
|
|
69
|
+
* @type {string | undefined}
|
|
70
|
+
*/
|
|
71
|
+
const accessibleLabel = $derived(ariaLabel ?? restProps['aria-label']);
|
|
72
|
+
const hasVisibleLabel = $derived(!!(children || label));
|
|
66
73
|
const indeterminate = $derived(checked === 'mixed');
|
|
67
74
|
|
|
68
75
|
// Sync `checked` with `group` and `value`
|
|
@@ -112,8 +119,8 @@
|
|
|
112
119
|
aria-required={required}
|
|
113
120
|
aria-invalid={invalid}
|
|
114
121
|
aria-checked={checked}
|
|
115
|
-
aria-label={
|
|
116
|
-
aria-labelledby={
|
|
122
|
+
aria-label={accessibleLabel || undefined}
|
|
123
|
+
aria-labelledby={!accessibleLabel && hasVisibleLabel ? `${id}-label` : undefined}
|
|
117
124
|
onclick={(event) => {
|
|
118
125
|
event.preventDefault();
|
|
119
126
|
event.stopPropagation();
|
|
@@ -150,7 +157,7 @@
|
|
|
150
157
|
{/if}
|
|
151
158
|
{/snippet}
|
|
152
159
|
</Button>
|
|
153
|
-
{#if
|
|
160
|
+
{#if hasVisibleLabel}
|
|
154
161
|
<label id="{id}-label">
|
|
155
162
|
{#if children}
|
|
156
163
|
{@render children()}
|
|
@@ -9,7 +9,7 @@ type Checkbox = {
|
|
|
9
9
|
* @see https://w3c.github.io/aria/#checkbox
|
|
10
10
|
* @see https://www.w3.org/WAI/ARIA/apg/patterns/checkbox/
|
|
11
11
|
*/
|
|
12
|
-
declare const Checkbox: import("svelte").Component<ButtonProps & import("../../typedefs").KeyboardEventHandlers & import("../../typedefs").MouseEventHandlers & import("../../typedefs").PointerEventHandlers & import("../../typedefs").FocusEventHandlers & import("../../typedefs").DragEventHandlers & {
|
|
12
|
+
declare const Checkbox: import("svelte").Component<ButtonProps & import("../../typedefs.js").KeyboardEventHandlers & import("../../typedefs.js").MouseEventHandlers & import("../../typedefs.js").PointerEventHandlers & import("../../typedefs.js").FocusEventHandlers & import("../../typedefs.js").DragEventHandlers & {
|
|
13
13
|
/**
|
|
14
14
|
* The `class` attribute on the wrapper element.
|
|
15
15
|
*/
|
|
@@ -87,5 +87,5 @@ type Props = {
|
|
|
87
87
|
*/
|
|
88
88
|
group?: string[] | undefined;
|
|
89
89
|
};
|
|
90
|
-
import type { ButtonProps } from '../../typedefs';
|
|
90
|
+
import type { ButtonProps } from '../../typedefs.js';
|
|
91
91
|
import type { Snippet } from 'svelte';
|
|
@@ -10,5 +10,5 @@ type AlertDialog = {
|
|
|
10
10
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/alert
|
|
11
11
|
*/
|
|
12
12
|
declare const AlertDialog: import("svelte").Component<ModalProps & DialogProps & Record<string, any>, {}, "open">;
|
|
13
|
-
import type { ModalProps } from '../../typedefs';
|
|
14
|
-
import type { DialogProps } from '../../typedefs';
|
|
13
|
+
import type { ModalProps } from '../../typedefs.js';
|
|
14
|
+
import type { DialogProps } from '../../typedefs.js';
|
|
@@ -10,5 +10,5 @@ type ConfirmationDialog = {
|
|
|
10
10
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm
|
|
11
11
|
*/
|
|
12
12
|
declare const ConfirmationDialog: import("svelte").Component<ModalProps & DialogProps & Record<string, any>, {}, "open">;
|
|
13
|
-
import type { ModalProps } from '../../typedefs';
|
|
14
|
-
import type { DialogProps } from '../../typedefs';
|
|
13
|
+
import type { ModalProps } from '../../typedefs.js';
|
|
14
|
+
import type { DialogProps } from '../../typedefs.js';
|