@sveltia/ui 0.8.3 → 0.10.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.
Files changed (122) hide show
  1. package/package/components/alert/alert.svelte +2 -4
  2. package/package/components/alert/alert.svelte.d.ts +2 -2
  3. package/package/components/button/button.svelte +78 -26
  4. package/package/components/button/button.svelte.d.ts +73 -63
  5. package/package/components/button/select-button-group.svelte +6 -1
  6. package/package/components/button/select-button-group.svelte.d.ts +13 -13
  7. package/package/components/button/select-button.svelte +2 -1
  8. package/package/components/button/select-button.svelte.d.ts +19 -19
  9. package/package/components/button/split-button.svelte +111 -0
  10. package/package/components/button/split-button.svelte.d.ts +69 -0
  11. package/package/components/calendar/calendar.svelte +2 -2
  12. package/package/components/calendar/calendar.svelte.d.ts +2 -2
  13. package/package/components/checkbox/checkbox-group.svelte.d.ts +7 -7
  14. package/package/components/checkbox/checkbox.svelte +8 -6
  15. package/package/components/checkbox/checkbox.svelte.d.ts +22 -16
  16. package/package/components/dialog/alert-dialog.svelte.d.ts +6 -6
  17. package/package/components/dialog/confirmation-dialog.svelte.d.ts +8 -8
  18. package/package/components/dialog/dialog.svelte +17 -15
  19. package/package/components/dialog/dialog.svelte.d.ts +30 -24
  20. package/package/components/dialog/prompt-dialog.svelte +1 -1
  21. package/package/components/dialog/prompt-dialog.svelte.d.ts +12 -12
  22. package/package/components/disclosure/disclosure.svelte +6 -1
  23. package/package/components/disclosure/disclosure.svelte.d.ts +29 -19
  24. package/package/components/divider/divider.svelte.d.ts +5 -5
  25. package/package/components/divider/spacer.svelte.d.ts +4 -4
  26. package/package/components/drawer/drawer.svelte +34 -16
  27. package/package/components/drawer/drawer.svelte.d.ts +22 -16
  28. package/package/components/grid/grid-body.svelte.d.ts +4 -4
  29. package/package/components/grid/grid-cell.svelte.d.ts +2 -2
  30. package/package/components/grid/grid-col-header.svelte.d.ts +2 -2
  31. package/package/components/grid/grid-foot.svelte.d.ts +2 -2
  32. package/package/components/grid/grid-head.svelte.d.ts +2 -2
  33. package/package/components/grid/grid-row-header.svelte.d.ts +2 -2
  34. package/package/components/grid/grid-row.svelte +10 -2
  35. package/package/components/grid/grid-row.svelte.d.ts +8 -8
  36. package/package/components/grid/grid.svelte +7 -2
  37. package/package/components/grid/grid.svelte.d.ts +8 -8
  38. package/package/components/icon/icon.svelte.d.ts +4 -4
  39. package/package/components/listbox/listbox.svelte +11 -5
  40. package/package/components/listbox/listbox.svelte.d.ts +15 -15
  41. package/package/components/listbox/option-group.svelte.d.ts +7 -7
  42. package/package/components/listbox/option.svelte +4 -2
  43. package/package/components/listbox/option.svelte.d.ts +15 -13
  44. package/package/components/menu/menu-button.svelte +18 -2
  45. package/package/components/menu/menu-button.svelte.d.ts +20 -16
  46. package/package/components/menu/menu-item-checkbox.svelte +1 -1
  47. package/package/components/menu/menu-item-checkbox.svelte.d.ts +16 -16
  48. package/package/components/menu/menu-item-group.svelte +1 -1
  49. package/package/components/menu/menu-item-group.svelte.d.ts +7 -7
  50. package/package/components/menu/menu-item-radio.svelte +1 -1
  51. package/package/components/menu/menu-item-radio.svelte.d.ts +16 -16
  52. package/package/components/menu/menu-item.svelte +32 -19
  53. package/package/components/menu/menu-item.svelte.d.ts +32 -18
  54. package/package/components/menu/menu.svelte +13 -7
  55. package/package/components/menu/menu.svelte.d.ts +7 -7
  56. package/package/components/radio/radio-group.svelte +6 -1
  57. package/package/components/radio/radio-group.svelte.d.ts +15 -15
  58. package/package/components/radio/radio.svelte +1 -1
  59. package/package/components/radio/radio.svelte.d.ts +14 -14
  60. package/package/components/select/combobox.svelte +10 -8
  61. package/package/components/select/combobox.svelte.d.ts +22 -16
  62. package/package/components/select/select.svelte.d.ts +12 -12
  63. package/package/components/slider/slider.svelte +26 -22
  64. package/package/components/slider/slider.svelte.d.ts +23 -23
  65. package/package/components/switch/switch.svelte +5 -0
  66. package/package/components/switch/switch.svelte.d.ts +18 -14
  67. package/package/components/table/table-body.svelte.d.ts +4 -4
  68. package/package/components/table/table-cell.svelte.d.ts +2 -2
  69. package/package/components/table/table-col-header.svelte.d.ts +2 -2
  70. package/package/components/table/table-foot.svelte.d.ts +2 -2
  71. package/package/components/table/table-head.svelte.d.ts +2 -2
  72. package/package/components/table/table-row-header.svelte.d.ts +2 -2
  73. package/package/components/table/table-row.svelte.d.ts +2 -2
  74. package/package/components/table/table.svelte.d.ts +2 -2
  75. package/package/components/tabs/tab-box.svelte +30 -0
  76. package/package/components/tabs/tab-box.svelte.d.ts +33 -0
  77. package/package/components/tabs/tab-list.svelte +105 -22
  78. package/package/components/tabs/tab-list.svelte.d.ts +10 -10
  79. package/package/components/tabs/tab-panel.svelte +6 -2
  80. package/package/components/tabs/tab-panel.svelte.d.ts +2 -2
  81. package/package/components/tabs/tab-panels.svelte +32 -0
  82. package/package/components/tabs/tab-panels.svelte.d.ts +31 -0
  83. package/package/components/tabs/tab.svelte.d.ts +11 -11
  84. package/package/components/text-field/markdown-editor.svelte.d.ts +12 -12
  85. package/package/components/text-field/number-input.svelte +11 -4
  86. package/package/components/text-field/number-input.svelte.d.ts +40 -20
  87. package/package/components/text-field/password-input.svelte +7 -3
  88. package/package/components/text-field/password-input.svelte.d.ts +30 -18
  89. package/package/components/text-field/search-bar.svelte +7 -3
  90. package/package/components/text-field/search-bar.svelte.d.ts +46 -36
  91. package/package/components/text-field/text-area.svelte +4 -2
  92. package/package/components/text-field/text-area.svelte.d.ts +25 -21
  93. package/package/components/text-field/text-input.svelte +17 -2
  94. package/package/components/text-field/text-input.svelte.d.ts +53 -53
  95. package/package/components/toast/toast.svelte +16 -12
  96. package/package/components/toast/toast.svelte.d.ts +8 -8
  97. package/package/components/toolbar/toolbar.svelte.d.ts +8 -8
  98. package/package/components/util/app-shell.svelte +162 -74
  99. package/package/components/util/app-shell.svelte.d.ts +2 -0
  100. package/package/components/util/group.svelte.d.ts +5 -5
  101. package/package/components/util/modal.svelte +26 -9
  102. package/package/components/util/modal.svelte.d.ts +34 -34
  103. package/package/components/util/popup.svelte +58 -32
  104. package/package/components/util/popup.svelte.d.ts +34 -24
  105. package/package/components/util/portal.svelte +5 -3
  106. package/package/components/util/portal.svelte.d.ts +2 -2
  107. package/package/index.d.ts +6 -3
  108. package/package/index.js +7 -4
  109. package/package/locales/en.d.ts +4 -0
  110. package/package/locales/en.js +4 -0
  111. package/package/locales/ja.d.ts +4 -0
  112. package/package/locales/ja.js +4 -0
  113. package/package/services/events.d.ts +1 -1
  114. package/package/services/events.js +11 -8
  115. package/package/services/group.js +73 -30
  116. package/package/services/popup.d.ts +28 -11
  117. package/package/services/popup.js +27 -10
  118. package/package/services/util.d.ts +2 -2
  119. package/package/services/util.js +5 -5
  120. package/package/styles/core.scss +1 -0
  121. package/package/styles/variables.scss +24 -4
  122. package/package.json +49 -25
@@ -4,12 +4,14 @@
4
4
  /** Generic popup helper. */
5
5
  export default class Popup extends SvelteComponent<{
6
6
  [x: string]: any;
7
- anchor: HTMLElement;
8
- class?: string;
9
- position?: PopupPosition;
10
- open?: import("svelte/store").Writable<boolean>;
11
- content?: HTMLElement;
12
- touchOptimized?: boolean;
7
+ anchor: HTMLElement | undefined;
8
+ class?: string | undefined;
9
+ position?: PopupPosition | undefined;
10
+ open?: import("svelte/store").Writable<boolean> | undefined;
11
+ showBackdrop?: boolean | undefined;
12
+ content?: HTMLElement | undefined;
13
+ positionBaseElement?: HTMLElement | undefined;
14
+ touchOptimized?: boolean | undefined;
13
15
  }, {
14
16
  opening: CustomEvent<any>;
15
17
  open: CustomEvent<any>;
@@ -23,23 +25,29 @@ export default class Popup extends SvelteComponent<{
23
25
  default: {};
24
26
  }> {
25
27
  /**accessor*/
26
- set class(arg: string);
27
- get class(): string;
28
+ set class(arg: string | undefined);
29
+ get class(): string | undefined;
28
30
  /**accessor*/
29
- set open(arg: import("svelte/store").Writable<boolean>);
30
- get open(): import("svelte/store").Writable<boolean>;
31
+ set open(arg: import("svelte/store").Writable<boolean> | undefined);
32
+ get open(): import("svelte/store").Writable<boolean> | undefined;
31
33
  /**accessor*/
32
- set anchor(arg: HTMLElement);
33
- get anchor(): HTMLElement;
34
+ set showBackdrop(arg: boolean | undefined);
35
+ get showBackdrop(): boolean | undefined;
34
36
  /**accessor*/
35
- set content(arg: HTMLElement);
36
- get content(): HTMLElement;
37
+ set anchor(arg: HTMLElement | undefined);
38
+ get anchor(): HTMLElement | undefined;
37
39
  /**accessor*/
38
- set position(arg: PopupPosition);
39
- get position(): PopupPosition;
40
+ set content(arg: HTMLElement | undefined);
41
+ get content(): HTMLElement | undefined;
40
42
  /**accessor*/
41
- set touchOptimized(arg: boolean);
42
- get touchOptimized(): boolean;
43
+ set position(arg: PopupPosition | undefined);
44
+ get position(): PopupPosition | undefined;
45
+ /**accessor*/
46
+ set positionBaseElement(arg: HTMLElement | undefined);
47
+ get positionBaseElement(): HTMLElement | undefined;
48
+ /**accessor*/
49
+ set touchOptimized(arg: boolean | undefined);
50
+ get touchOptimized(): boolean | undefined;
43
51
  }
44
52
  export type PopupProps = typeof __propDef.props;
45
53
  export type PopupEvents = typeof __propDef.events;
@@ -48,12 +56,14 @@ import { SvelteComponent } from "svelte";
48
56
  declare const __propDef: {
49
57
  props: {
50
58
  [x: string]: any;
51
- anchor: HTMLElement;
52
- class?: string;
53
- position?: PopupPosition;
54
- open?: import('svelte/store').Writable<boolean>;
55
- content?: HTMLElement;
56
- touchOptimized?: boolean;
59
+ anchor: HTMLElement | undefined;
60
+ class?: string | undefined;
61
+ position?: PopupPosition | undefined;
62
+ open?: import("svelte/store").Writable<boolean> | undefined;
63
+ showBackdrop?: boolean | undefined;
64
+ content?: HTMLElement | undefined;
65
+ positionBaseElement?: HTMLElement | undefined;
66
+ touchOptimized?: boolean | undefined;
57
67
  };
58
68
  events: {
59
69
  opening: CustomEvent<any>;
@@ -13,15 +13,17 @@
13
13
 
14
14
  export { className as class };
15
15
 
16
- /** @type {HTMLElement} */
16
+ /** @type {HTMLElement | undefined} */
17
17
  let ref;
18
18
 
19
19
  onMount(() => {
20
- document.body.appendChild(ref);
20
+ if (ref) {
21
+ document.body.appendChild(ref);
22
+ }
21
23
  });
22
24
 
23
25
  onDestroy(() => {
24
- ref.remove();
26
+ ref?.remove();
25
27
  });
26
28
  </script>
27
29
 
@@ -4,7 +4,7 @@
4
4
  /** @see https://github.com/sveltejs/svelte/issues/3088 */
5
5
  export default class Portal extends SvelteComponent<{
6
6
  [x: string]: any;
7
- class?: string;
7
+ class?: string | undefined;
8
8
  }, {
9
9
  [evt: string]: CustomEvent<any>;
10
10
  }, {
@@ -18,7 +18,7 @@ import { SvelteComponent } from "svelte";
18
18
  declare const __propDef: {
19
19
  props: {
20
20
  [x: string]: any;
21
- class?: string;
21
+ class?: string | undefined;
22
22
  };
23
23
  events: {
24
24
  [evt: string]: CustomEvent<any>;
@@ -1,11 +1,12 @@
1
1
  export function initLocales({ fallbackLocale, initialLocale }?: {
2
- fallbackLocale?: string;
3
- initialLocale?: string;
4
- }): void;
2
+ fallbackLocale?: string | undefined;
3
+ initialLocale?: string | undefined;
4
+ } | undefined): void;
5
5
  export { default as Alert } from "./components/alert/alert.svelte";
6
6
  export { default as Button } from "./components/button/button.svelte";
7
7
  export { default as SelectButtonGroup } from "./components/button/select-button-group.svelte";
8
8
  export { default as SelectButton } from "./components/button/select-button.svelte";
9
+ export { default as SplitButton } from "./components/button/split-button.svelte";
9
10
  export { default as Calendar } from "./components/calendar/calendar.svelte";
10
11
  export { default as CheckboxGroup } from "./components/checkbox/checkbox-group.svelte";
11
12
  export { default as Checkbox } from "./components/checkbox/checkbox.svelte";
@@ -49,8 +50,10 @@ export { default as TableHead } from "./components/table/table-head.svelte";
49
50
  export { default as TableRowHeader } from "./components/table/table-row-header.svelte";
50
51
  export { default as TableRow } from "./components/table/table-row.svelte";
51
52
  export { default as Table } from "./components/table/table.svelte";
53
+ export { default as TabBox } from "./components/tabs/tab-box.svelte";
52
54
  export { default as TabList } from "./components/tabs/tab-list.svelte";
53
55
  export { default as TabPanel } from "./components/tabs/tab-panel.svelte";
56
+ export { default as TabPanels } from "./components/tabs/tab-panels.svelte";
54
57
  export { default as Tab } from "./components/tabs/tab.svelte";
55
58
  export { default as MarkdownEditor } from "./components/text-field/markdown-editor.svelte";
56
59
  export { default as NumberInput } from "./components/text-field/number-input.svelte";
package/package/index.js CHANGED
@@ -2,9 +2,9 @@ import { addMessages, init } from 'svelte-i18n';
2
2
 
3
3
  /**
4
4
  * Load strings and initialize the locales.
5
- * @param {object} [init] Initialize options.
6
- * @param {string} [init.fallbackLocale] Fallback locale.
7
- * @param {string} [init.initialLocale] Initial locale.
5
+ * @param {object} [init] - Initialize options.
6
+ * @param {string} [init.fallbackLocale] - Fallback locale.
7
+ * @param {string} [init.initialLocale] - Initial locale.
8
8
  * @see https://github.com/kaisermann/svelte-i18n/blob/main/docs/Getting%20Started.md
9
9
  * @see https://vitejs.dev/guide/features.html#glob-import
10
10
  */
@@ -13,7 +13,7 @@ export const initLocales = ({ fallbackLocale = 'en', initialLocale = 'en' } = {}
13
13
  const modules = import.meta.glob('./locales/*.js', { eager: true });
14
14
 
15
15
  Object.entries(modules).forEach(([path, { strings }]) => {
16
- const [, locale] = path.match(/([a-zA-Z-]+)\.js/);
16
+ const [, locale] = /** @type {string[]} */ (path.match(/([a-zA-Z-]+)\.js/));
17
17
 
18
18
  // Add `_sui` suffix to avoid collision with app localization
19
19
  addMessages(locale, /** @type {any} */ ({ _sui: strings }));
@@ -31,6 +31,7 @@ export { default as Alert } from './components/alert/alert.svelte';
31
31
  export { default as Button } from './components/button/button.svelte';
32
32
  export { default as SelectButtonGroup } from './components/button/select-button-group.svelte';
33
33
  export { default as SelectButton } from './components/button/select-button.svelte';
34
+ export { default as SplitButton } from './components/button/split-button.svelte';
34
35
  export { default as Calendar } from './components/calendar/calendar.svelte';
35
36
  export { default as CheckboxGroup } from './components/checkbox/checkbox-group.svelte';
36
37
  export { default as Checkbox } from './components/checkbox/checkbox.svelte';
@@ -74,8 +75,10 @@ export { default as TableHead } from './components/table/table-head.svelte';
74
75
  export { default as TableRowHeader } from './components/table/table-row-header.svelte';
75
76
  export { default as TableRow } from './components/table/table-row.svelte';
76
77
  export { default as Table } from './components/table/table.svelte';
78
+ export { default as TabBox } from './components/tabs/tab-box.svelte';
77
79
  export { default as TabList } from './components/tabs/tab-list.svelte';
78
80
  export { default as TabPanel } from './components/tabs/tab-panel.svelte';
81
+ export { default as TabPanels } from './components/tabs/tab-panels.svelte';
79
82
  export { default as Tab } from './components/tabs/tab.svelte';
80
83
  export { default as MarkdownEditor } from './components/text-field/markdown-editor.svelte';
81
84
  export { default as NumberInput } from './components/text-field/number-input.svelte';
@@ -15,6 +15,10 @@ export namespace strings {
15
15
  const next_month: string;
16
16
  const today: string;
17
17
  }
18
+ namespace split_button {
19
+ const x_options: string;
20
+ const more_options: string;
21
+ }
18
22
  namespace combobox {
19
23
  const select_an_option: string;
20
24
  }
@@ -15,6 +15,10 @@ export const strings = {
15
15
  next_month: 'Next Month',
16
16
  today: 'Today',
17
17
  },
18
+ split_button: {
19
+ x_options: '{name} Options',
20
+ more_options: 'More Options',
21
+ },
18
22
  combobox: {
19
23
  select_an_option: 'Select an option…',
20
24
  },
@@ -15,6 +15,10 @@ export namespace strings {
15
15
  const next_month: string;
16
16
  const today: string;
17
17
  }
18
+ namespace split_button {
19
+ const x_options: string;
20
+ const more_options: string;
21
+ }
18
22
  namespace combobox {
19
23
  const select_an_option: string;
20
24
  }
@@ -15,6 +15,10 @@ export const strings = {
15
15
  next_month: '翌月',
16
16
  today: '今日',
17
17
  },
18
+ split_button: {
19
+ x_options: '{name} オプション',
20
+ more_options: 'その他のオプション',
21
+ },
18
22
  combobox: {
19
23
  select_an_option: 'オプションを選択…',
20
24
  },
@@ -1,3 +1,3 @@
1
1
  export function isMac(): boolean;
2
2
  export function matchShortcuts(event: KeyboardEvent, shortcuts: string): boolean;
3
- export function activateKeyShortcuts(element: (HTMLInputElement | HTMLButtonElement), shortcuts?: string): import('svelte/action').ActionReturn;
3
+ export function activateKeyShortcuts(element: (HTMLInputElement | HTMLButtonElement), shortcuts?: string | undefined): import('svelte/action').ActionReturn;
@@ -8,8 +8,8 @@ export const isMac = () =>
8
8
 
9
9
  /**
10
10
  * Whether the event matches the given keyboard shortcuts.
11
- * @param {KeyboardEvent} event `keydown` or `keypress` event.
12
- * @param {string} shortcuts Keyboard shortcuts like `A` or `Ctrl+S`.
11
+ * @param {KeyboardEvent} event - `keydown` or `keypress` event.
12
+ * @param {string} shortcuts - Keyboard shortcuts like `A` or `Ctrl+S`.
13
13
  * @returns {boolean} Result.
14
14
  * @see https://w3c.github.io/aria/#aria-keyshortcuts
15
15
  */
@@ -47,10 +47,10 @@ export const matchShortcuts = (event, shortcuts) => {
47
47
 
48
48
  /**
49
49
  * Activate keyboard shortcuts.
50
- * @param {(HTMLInputElement | HTMLButtonElement)} element Element.
51
- * @param {string} [shortcuts] Keyboard shortcuts like `A` or `Accel+S` to focus and click the text
52
- * field or button. Multiple shortcuts can be defined space-separated. The `Accel` modifier will be
53
- * replaced with `Ctrl` on Windows/Linux and `Command` on macOS.
50
+ * @param {(HTMLInputElement | HTMLButtonElement)} element - Element.
51
+ * @param {string} [shortcuts] - Keyboard shortcuts like `A` or `Accel+S` to focus and click the
52
+ * text field or button. Multiple shortcuts can be defined space-separated. The `Accel` modifier
53
+ * will be replaced with `Ctrl` on Windows/Linux and `Command` on macOS.
54
54
  * @returns {import('svelte/action').ActionReturn} Actions.
55
55
  */
56
56
  export const activateKeyShortcuts = (element, shortcuts = '') => {
@@ -59,10 +59,13 @@ export const activateKeyShortcuts = (element, shortcuts = '') => {
59
59
 
60
60
  /**
61
61
  * Handle the event.
62
- * @param {KeyboardEvent} event `keydown` event.
62
+ * @param {KeyboardEvent} event - `keydown` event.
63
63
  */
64
64
  const handler = (event) => {
65
- if (!!element.offsetParent && matchShortcuts(event, platformKeyShortcuts)) {
65
+ if (
66
+ !!element.offsetParent &&
67
+ matchShortcuts(event, /** @type {string} */ (platformKeyShortcuts))
68
+ ) {
66
69
  event.preventDefault();
67
70
 
68
71
  if (!element.disabled) {
@@ -2,10 +2,10 @@ import { getRandomId, sleep } from './util';
2
2
 
3
3
  /**
4
4
  * @type {{ [role: string]: {
5
- * orientation: 'vertical' | 'horizontal',
6
- * childRoles: string[],
7
- * childSelectedAttr: 'aria-selected' | 'aria-checked',
8
- * focusChild: boolean
5
+ * orientation: 'vertical' | 'horizontal',
6
+ * childRoles: string[],
7
+ * childSelectedAttr: 'aria-selected' | 'aria-checked',
8
+ * focusChild: boolean
9
9
  * } }}
10
10
  */
11
11
  const config = {
@@ -53,12 +53,14 @@ const config = {
53
53
  class Group {
54
54
  /**
55
55
  * Initialize a new `Group` instance.
56
- * @param {HTMLElement} parent Parent element.
56
+ * @param {HTMLElement} parent - Parent element.
57
57
  * @todo Check for added elements probably with `MutationObserver`.
58
58
  */
59
59
  constructor(parent) {
60
+ parent.dispatchEvent(new CustomEvent('initializing'));
61
+
60
62
  this.parent = parent;
61
- this.role = parent.getAttribute('role');
63
+ this.role = /** @type {string} */ (parent.getAttribute('role'));
62
64
  this.grid = this.role === 'listbox' && parent.matches('.grid');
63
65
  this.multi = this.parent.getAttribute('aria-multiselectable') === 'true';
64
66
  this.id = getRandomId(this.role);
@@ -74,21 +76,29 @@ class Group {
74
76
  this.childSelectedProp = childSelectedAttr.replace('aria-', '');
75
77
  this.focusChild = focusChild;
76
78
 
77
- const { allMembers } = this;
78
-
79
- const hasSelected = allMembers.some((element) =>
80
- element.matches(`[${childSelectedAttr}="true"]`),
81
- );
79
+ const { allMembers, selected: defaultSelected } = this;
82
80
 
83
81
  allMembers.forEach((element, index) => {
84
- const isSelected = element.matches(`[${childSelectedAttr}="true"]`);
85
- const controls = document.querySelector(`#${element.getAttribute('aria-controls')}`);
82
+ // Select the first one if no member has the `selected` attribute
83
+ const isSelected = defaultSelected ? element === defaultSelected : index === 0;
84
+
85
+ const controlTarget = /** @type {HTMLElement | null} */ (
86
+ document.querySelector(`#${element.getAttribute('aria-controls')}`)
87
+ );
86
88
 
87
89
  element.id ||= `${this.id}-item-${index + 1}`;
88
- element.tabIndex ||= isSelected || (!hasSelected && index === 0) ? 0 : -1;
90
+ element.tabIndex ||= isSelected ? 0 : -1;
89
91
  element.setAttribute(this.childSelectedAttr, String(isSelected));
90
- controls?.setAttribute('aria-labelledby', element.id);
91
- controls?.setAttribute('aria-hidden', String(!isSelected));
92
+
93
+ if (controlTarget) {
94
+ controlTarget.inert = !isSelected;
95
+ controlTarget.setAttribute('aria-labelledby', element.id);
96
+ controlTarget.setAttribute('aria-hidden', String(!isSelected));
97
+
98
+ if (isSelected) {
99
+ controlTarget.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'auto' });
100
+ }
101
+ }
92
102
  });
93
103
 
94
104
  parent.addEventListener('click', (event) => {
@@ -100,39 +110,66 @@ class Group {
100
110
  parent.addEventListener('keydown', (event) => {
101
111
  this.onKeyDown(event);
102
112
  });
113
+
114
+ parent.dispatchEvent(new CustomEvent('initialized'));
103
115
  }
104
116
 
105
- /** @type {string} */
117
+ /**
118
+ * CSS selector to retrieve the members.
119
+ * @type {string}
120
+ */
106
121
  get selector() {
107
122
  return this.childRoles.map((role) => `[role="${role}"]`).join(',');
108
123
  }
109
124
 
110
- /** @type {HTMLElement[]} */
125
+ /**
126
+ * List of all the members.
127
+ * @type {HTMLElement[]}
128
+ */
111
129
  get allMembers() {
112
130
  return /** @type {HTMLElement[]} */ ([...this.parent.querySelectorAll(this.selector)]);
113
131
  }
114
132
 
115
- /** @type {HTMLElement[]} */
133
+ /**
134
+ * List of the enabled and visible members.
135
+ * @type {HTMLElement[]}
136
+ */
116
137
  get activeMembers() {
117
138
  return this.allMembers.filter(
118
139
  (element) => !element.matches('[aria-disabled="true"], [aria-hidden="true"]'),
119
140
  );
120
141
  }
121
142
 
122
- /** @type {boolean} */
143
+ /**
144
+ * Get the currently selected member.
145
+ * @type {HTMLElement | undefined}
146
+ */
147
+ get selected() {
148
+ return this.activeMembers.find((element) =>
149
+ element.matches(`[${this.childSelectedAttr}="true"]`),
150
+ );
151
+ }
152
+
153
+ /**
154
+ * Whether the parent is disabled.
155
+ * @type {boolean}
156
+ */
123
157
  get isDisabled() {
124
158
  return this.parent.matches('[aria-disabled="true"]');
125
159
  }
126
160
 
127
- /** @type {boolean} */
161
+ /**
162
+ * Whether the parent is read-only.
163
+ * @type {boolean}
164
+ */
128
165
  get isReadOnly() {
129
166
  return this.parent.matches('[aria-readonly="true"]');
130
167
  }
131
168
 
132
169
  /**
133
170
  * Select (and move focus to) the given target.
134
- * @param {(MouseEvent | KeyboardEvent)} event Triggered event.
135
- * @param {HTMLElement} newTarget Target element.
171
+ * @param {(MouseEvent | KeyboardEvent)} event - Triggered event.
172
+ * @param {HTMLElement} newTarget - Target element.
136
173
  */
137
174
  selectTarget(event, newTarget) {
138
175
  if (this.isDisabled || this.isReadOnly) {
@@ -164,7 +201,8 @@ class Group {
164
201
  const singleSelect = isMenuItemRadio || !multiSelect;
165
202
  const isTarget = element === newTarget;
166
203
  const isSelected = element.matches(`[${this.childSelectedAttr}="true"]`);
167
- const controls = element.getAttribute('aria-controls');
204
+ const controlTargetId = element.getAttribute('aria-controls');
205
+ const controlTarget = controlTargetId ? document.getElementById(controlTargetId) : null;
168
206
 
169
207
  if (multiSelect && isTarget && (selectByClick || selectByKeydown)) {
170
208
  element.setAttribute(this.childSelectedAttr, String(!isSelected));
@@ -202,13 +240,18 @@ class Group {
202
240
  element.classList.toggle('focused', isTarget);
203
241
  }
204
242
 
205
- if (controls) {
206
- document.getElementById(controls)?.setAttribute('aria-hidden', String(!isTarget));
243
+ if (controlTarget) {
244
+ controlTarget.inert = !isTarget;
245
+ controlTarget.setAttribute('aria-hidden', String(!isTarget));
246
+
247
+ if (isTarget) {
248
+ controlTarget.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'auto' });
249
+ }
207
250
  }
208
251
 
209
252
  if (isTarget) {
210
253
  this.parent.setAttribute('aria-activedescendant', element.id);
211
- element.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'smooth' });
254
+ element.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'auto' });
212
255
  }
213
256
  });
214
257
 
@@ -224,7 +267,7 @@ class Group {
224
267
 
225
268
  /**
226
269
  * Handle the `click` event on the widget.
227
- * @param {MouseEvent} event `click` event.
270
+ * @param {MouseEvent} event - `click` event.
228
271
  */
229
272
  onClick(event) {
230
273
  // eslint-disable-next-line prefer-destructuring
@@ -240,7 +283,7 @@ class Group {
240
283
 
241
284
  /**
242
285
  * Handle the `keydown` event on the widget.
243
- * @param {KeyboardEvent} event `keydown` event.
286
+ * @param {KeyboardEvent} event - `keydown` event.
244
287
  */
245
288
  onKeyDown(event) {
246
289
  const { key, ctrlKey, metaKey, shiftKey, altKey } = event;
@@ -349,7 +392,7 @@ class Group {
349
392
 
350
393
  /**
351
394
  * Activate a new group.
352
- * @param {HTMLElement} parent Parent element.
395
+ * @param {HTMLElement} parent - Parent element.
353
396
  */
354
397
  export const activateGroup = (parent) => {
355
398
  (async () => {
@@ -6,26 +6,43 @@ export function activatePopup(...args: any[]): Popup;
6
6
  declare class Popup {
7
7
  /**
8
8
  * Initialize a new `Popup` instance.
9
- * @param {HTMLButtonElement} anchorElement `<button>` element that triggers the popup.
10
- * @param {HTMLDialogElement} popupElement `<dialog>` element to be used for the popup.
11
- * @param {PopupPosition} position Where to show the popup content.
9
+ * @param {HTMLButtonElement} anchorElement - `<button>` element that triggers the popup.
10
+ * @param {HTMLDialogElement} popupElement - `<dialog>` element to be used for the popup.
11
+ * @param {PopupPosition} position - Where to show the popup content.
12
+ * @param {HTMLElement} [positionBaseElement] - The base element of the `position`. If omitted,
13
+ * this will be the `anchorElement`.
12
14
  */
13
- constructor(anchorElement: HTMLButtonElement, popupElement: HTMLDialogElement, position: PopupPosition);
15
+ constructor(anchorElement: HTMLButtonElement, popupElement: HTMLDialogElement, position: PopupPosition, positionBaseElement?: HTMLElement | undefined);
14
16
  open: import("svelte/store").Writable<boolean>;
15
- style: import("svelte/store").Writable<{
16
- inset: any;
17
- zIndex: any;
18
- width: any;
19
- height: any;
17
+ /**
18
+ * @type {import('svelte/store').Writable<{
19
+ * inset: string | undefined,
20
+ * zIndex: number | undefined,
21
+ * width: string | undefined,
22
+ * height: string | undefined,
23
+ * }>}
24
+ */
25
+ style: import('svelte/store').Writable<{
26
+ inset: string | undefined;
27
+ zIndex: number | undefined;
28
+ width: string | undefined;
29
+ height: string | undefined;
20
30
  }>;
21
31
  observer: IntersectionObserver;
22
32
  anchorElement: HTMLButtonElement;
23
33
  popupElement: HTMLDialogElement;
24
34
  position: PopupPosition;
35
+ positionBaseElement: HTMLElement;
25
36
  id: string;
26
- /** @type {boolean} */
37
+ /**
38
+ * Whether the anchor element is disabled.
39
+ * @type {boolean}
40
+ */
27
41
  get isDisabled(): boolean;
28
- /** @type {boolean} */
42
+ /**
43
+ * Whether the anchor element is read-only.
44
+ * @type {boolean}
45
+ */
29
46
  get isReadOnly(): boolean;
30
47
  /**
31
48
  * Check the position of the anchor element.
@@ -9,6 +9,14 @@ import { getRandomId } from './util';
9
9
  class Popup {
10
10
  open = writable(false);
11
11
 
12
+ /**
13
+ * @type {import('svelte/store').Writable<{
14
+ * inset: string | undefined,
15
+ * zIndex: number | undefined,
16
+ * width: string | undefined,
17
+ * height: string | undefined,
18
+ * }>}
19
+ */
12
20
  style = writable({ inset: undefined, zIndex: undefined, width: undefined, height: undefined });
13
21
 
14
22
  observer = new IntersectionObserver((entries) => {
@@ -18,7 +26,7 @@ class Popup {
18
26
  }
19
27
 
20
28
  const { scrollHeight: contentHeight, scrollWidth: contentWidth } =
21
- this.popupElement.querySelector('.content');
29
+ /** @type {HTMLElement} */ (this.popupElement.querySelector('.content'));
22
30
 
23
31
  const topMargin = intersectionRect.top - 8;
24
32
  const bottomMargin = rootBounds.height - intersectionRect.bottom - 8;
@@ -86,14 +94,17 @@ class Popup {
86
94
 
87
95
  /**
88
96
  * Initialize a new `Popup` instance.
89
- * @param {HTMLButtonElement} anchorElement `<button>` element that triggers the popup.
90
- * @param {HTMLDialogElement} popupElement `<dialog>` element to be used for the popup.
91
- * @param {PopupPosition} position Where to show the popup content.
97
+ * @param {HTMLButtonElement} anchorElement - `<button>` element that triggers the popup.
98
+ * @param {HTMLDialogElement} popupElement - `<dialog>` element to be used for the popup.
99
+ * @param {PopupPosition} position - Where to show the popup content.
100
+ * @param {HTMLElement} [positionBaseElement] - The base element of the `position`. If omitted,
101
+ * this will be the `anchorElement`.
92
102
  */
93
- constructor(anchorElement, popupElement, position) {
103
+ constructor(anchorElement, popupElement, position, positionBaseElement) {
94
104
  this.anchorElement = anchorElement;
95
105
  this.popupElement = popupElement; // = backdrop
96
106
  this.position = position;
107
+ this.positionBaseElement = positionBaseElement ?? anchorElement;
97
108
  this.id = getRandomId('popup');
98
109
 
99
110
  this.anchorElement.setAttribute('aria-controls', this.id);
@@ -154,12 +165,18 @@ class Popup {
154
165
  });
155
166
  }
156
167
 
157
- /** @type {boolean} */
168
+ /**
169
+ * Whether the anchor element is disabled.
170
+ * @type {boolean}
171
+ */
158
172
  get isDisabled() {
159
173
  return this.anchorElement.matches('[aria-disabled="true"]');
160
174
  }
161
175
 
162
- /** @type {boolean} */
176
+ /**
177
+ * Whether the anchor element is read-only.
178
+ * @type {boolean}
179
+ */
163
180
  get isReadOnly() {
164
181
  return this.anchorElement.matches('[aria-readonly="true"]');
165
182
  }
@@ -168,14 +185,14 @@ class Popup {
168
185
  * Check the position of the anchor element.
169
186
  */
170
187
  checkPosition() {
171
- this.observer.unobserve(this.anchorElement);
172
- this.observer.observe(this.anchorElement);
188
+ this.observer.unobserve(this.positionBaseElement);
189
+ this.observer.observe(this.positionBaseElement);
173
190
  }
174
191
  }
175
192
 
176
193
  /**
177
194
  * Activate a new popup.
178
- * @param {...any} args Arguments.
195
+ * @param {...any} args - Arguments.
179
196
  * @returns {Popup} New popup.
180
197
  */
181
198
  // @ts-ignore
@@ -1,3 +1,3 @@
1
- export function getRandomId(prefix?: string, length?: number): string;
1
+ export function getRandomId(prefix?: string | undefined, length?: number | undefined): string;
2
2
  export function isObject(input: any): boolean;
3
- export function sleep(ms?: number): Promise<void>;
3
+ export function sleep(ms?: number | undefined): Promise<void>;