@sveltia/ui 0.1.3 → 0.1.5

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 (40) hide show
  1. package/package/components/composite/calendar.svelte +4 -5
  2. package/package/components/composite/combobox.svelte +18 -4
  3. package/package/components/composite/combobox.svelte.d.ts +2 -2
  4. package/package/components/composite/disclosure.svelte.d.ts +1 -1
  5. package/package/components/composite/menu-item-group.svelte.d.ts +1 -1
  6. package/package/components/composite/select-button-group.svelte +1 -0
  7. package/package/components/composite/select.svelte.d.ts +1 -1
  8. package/package/components/composite/tab-list.svelte.d.ts +1 -1
  9. package/package/components/core/button.svelte +15 -19
  10. package/package/components/core/button.svelte.d.ts +7 -12
  11. package/package/components/core/checkbox.svelte +5 -6
  12. package/package/components/core/dialog.svelte +4 -3
  13. package/package/components/core/dialog.svelte.d.ts +2 -2
  14. package/package/components/core/group.svelte.d.ts +1 -1
  15. package/package/components/core/icon.svelte.d.ts +1 -1
  16. package/package/components/core/menu-button.svelte +10 -18
  17. package/package/components/core/menu-button.svelte.d.ts +8 -3
  18. package/package/components/core/menu-item.svelte +1 -1
  19. package/package/components/core/menu-item.svelte.d.ts +2 -2
  20. package/package/components/core/number-input.svelte +7 -6
  21. package/package/components/core/option.svelte +3 -1
  22. package/package/components/core/option.svelte.d.ts +6 -0
  23. package/package/components/core/password-input.svelte +8 -3
  24. package/package/components/core/radio-button.svelte +4 -2
  25. package/package/components/core/search-bar.svelte +3 -3
  26. package/package/components/core/search-bar.svelte.d.ts +1 -1
  27. package/package/components/core/select-button.svelte +2 -0
  28. package/package/components/core/select-button.svelte.d.ts +6 -0
  29. package/package/components/core/switch.svelte.d.ts +1 -1
  30. package/package/components/core/tab.svelte +2 -0
  31. package/package/components/core/tab.svelte.d.ts +6 -0
  32. package/package/components/core/text-area.svelte.d.ts +1 -1
  33. package/package/components/core/text-input.svelte.d.ts +1 -1
  34. package/package/components/editor/markdown.svelte +4 -1
  35. package/package/components/helpers/popup.js +35 -15
  36. package/package/components/util/app-shell.svelte +1 -1
  37. package/package/components/util/popup.svelte +15 -1
  38. package/package/components/util/popup.svelte.d.ts +1 -1
  39. package/package/styles/variables.scss +1 -1
  40. package/package.json +7 -7
@@ -2,7 +2,6 @@
2
2
  import { _ } from 'svelte-i18n';
3
3
  import Button from '../core/button.svelte';
4
4
  import Icon from '../core/icon.svelte';
5
- import MenuButton from '../core/menu-button.svelte';
6
5
  import Separator from '../core/separator.svelte';
7
6
  import Spacer from '../core/spacer.svelte';
8
7
 
@@ -43,14 +42,14 @@
43
42
  <div role="group">
44
43
  <input type="hidden" bind:value />
45
44
  <div class="header">
46
- <MenuButton
45
+ <Button
47
46
  class="ternary"
48
47
  label={firstDay.toLocaleDateString('en', { year: 'numeric', month: 'short' })}
49
48
  aria-haspopup="dialog"
50
- iconName="arrow_drop_down"
51
49
  >
50
+ <Icon slot="end-icon" name="arrow_drop_down" />
52
51
  <!-- svelte-ignore a11y-click-events-have-key-events -->
53
- <div class="popup-inner" on:click|stopPropagation>
52
+ <div slot="popup" class="popup-inner" on:click|stopPropagation>
54
53
  <div role="group" aria-label={$_('sui.calendar.year')}>
55
54
  <div class="header">
56
55
  <Button
@@ -91,7 +90,7 @@
91
90
  </div>
92
91
  </div>
93
92
  </div>
94
- </MenuButton>
93
+ </Button>
95
94
  <Button
96
95
  on:click={() => {
97
96
  firstDay.setUTCMonth(firstDay.getUTCMonth() - 1);
@@ -8,6 +8,7 @@
8
8
  import { _ } from 'svelte-i18n';
9
9
  import { writable } from 'svelte/store';
10
10
  import Button from '../core/button.svelte';
11
+ import Icon from '../core/icon.svelte';
11
12
  import TextInput from '../core/text-input.svelte';
12
13
  import { getRandomId } from '../helpers/util';
13
14
  import Popup from '../util/popup.svelte';
@@ -80,7 +81,9 @@
80
81
  {...$$restProps}
81
82
  bind:this={comboboxElement}
82
83
  >
83
- {value !== undefined ? label || value : $_('sui.combobox.select_an_option')}
84
+ <div class="label">
85
+ {value !== undefined ? label || value : $_('sui.combobox.select_an_option')}
86
+ </div>
84
87
  </div>
85
88
  {:else}
86
89
  <TextInput
@@ -103,8 +106,6 @@
103
106
  aria-expanded={$isPopupOpen}
104
107
  aria-disabled={disabled ? true : undefined}
105
108
  class="ternary iconic"
106
- iconName="expand_more"
107
- iconLabel={$isPopupOpen ? $_('sui._.collapse') : $_('sui._.expand')}
108
109
  on:click={(event) => {
109
110
  event.stopPropagation();
110
111
 
@@ -112,7 +113,13 @@
112
113
  $isPopupOpen = !$isPopupOpen;
113
114
  }
114
115
  }}
115
- />
116
+ >
117
+ <Icon
118
+ slot="start-icon"
119
+ name="expand_more"
120
+ label={$isPopupOpen ? $_('sui._.collapse') : $_('sui._.expand')}
121
+ />
122
+ </Button>
116
123
  </div>
117
124
  <Popup
118
125
  id="{id}-popup"
@@ -172,6 +179,13 @@
172
179
  opacity: 0.4;
173
180
  cursor: default;
174
181
  }
182
+ .combobox div[role=combobox] .label {
183
+ display: block;
184
+ overflow: hidden;
185
+ width: 100%;
186
+ white-space: nowrap;
187
+ text-overflow: ellipsis;
188
+ }
175
189
  .combobox :global(input) {
176
190
  padding: 0 32px 0 8px;
177
191
  width: 100%;
@@ -13,11 +13,11 @@ export type ComboboxSlots = typeof __propDef.slots;
13
13
  declare const __propDef: {
14
14
  props: {
15
15
  [x: string]: any;
16
- class?: string;
17
16
  label?: string;
17
+ position?: any;
18
+ class?: string;
18
19
  disabled?: boolean;
19
20
  value?: (string | undefined);
20
- position?: any;
21
21
  readOnly?: boolean;
22
22
  };
23
23
  events: {
@@ -12,8 +12,8 @@ export type DisclosureEvents = typeof __propDef.events;
12
12
  export type DisclosureSlots = typeof __propDef.slots;
13
13
  declare const __propDef: {
14
14
  props: {
15
- class?: string;
16
15
  label?: string;
16
+ class?: string;
17
17
  expanded?: boolean;
18
18
  };
19
19
  events: {
@@ -9,8 +9,8 @@ export type MenuItemGroupSlots = typeof __propDef.slots;
9
9
  declare const __propDef: {
10
10
  props: {
11
11
  [x: string]: any;
12
- class?: string;
13
12
  title?: string;
13
+ class?: string;
14
14
  ariaLabel?: string;
15
15
  };
16
16
  events: {
@@ -54,6 +54,7 @@
54
54
  }
55
55
  .select-button-group :global(button) {
56
56
  border-radius: 0;
57
+ color: var(--secondary-foreground-color);
57
58
  }
58
59
  .select-button-group :global(button):first-child {
59
60
  border-radius: 4px 0 0 4px;
@@ -10,8 +10,8 @@ export type SelectSlots = typeof __propDef.slots;
10
10
  declare const __propDef: {
11
11
  props: {
12
12
  [x: string]: any;
13
- class?: string;
14
13
  label?: string;
14
+ class?: string;
15
15
  value?: (string | undefined);
16
16
  };
17
17
  events: {
@@ -26,8 +26,8 @@ declare const __propDef: {
26
26
  props: {
27
27
  [x: string]: any;
28
28
  class?: string;
29
- name?: string;
30
29
  element?: (HTMLElement | undefined);
30
+ name?: string;
31
31
  orientation?: ('horizontal' | 'vertical');
32
32
  };
33
33
  events: {
@@ -6,12 +6,13 @@
6
6
  <svelte:options accessors={true} />
7
7
 
8
8
  <script>
9
- import Icon from './icon.svelte';
9
+ import Popup from '../util/popup.svelte';
10
10
 
11
11
  /**
12
12
  * CSS class name on the button.
13
13
  * @type {String}
14
14
  */
15
+ // eslint-disable-next-line padding-line-between-statements
15
16
  let className = '';
16
17
 
17
18
  export { className as class };
@@ -65,20 +66,13 @@
65
66
  export let label = '';
66
67
 
67
68
  /**
68
- * The name of the Material Symbols icon on the button.
69
+ * Where to show the dropdown menu.
70
+ * @type {PopupPosition}
69
71
  */
70
- export let iconName = '';
72
+ export let popupPosition = 'bottom-left';
71
73
 
72
- /**
73
- * The accessible label on the icon. It can be omitted of a visible `label` is defined.
74
- */
75
- export let iconLabel = '';
76
-
77
- /**
78
- * Where the icon is displayed.
79
- * @type {('start'|'end')}
80
- */
81
- export let iconPosition = 'start';
74
+ /** @type {?Popup} */
75
+ let popupComponent;
82
76
  </script>
83
77
 
84
78
  <button
@@ -103,18 +97,20 @@
103
97
  on:keypress
104
98
  bind:this={element}
105
99
  >
106
- {#if iconName && iconPosition === 'start'}
107
- <Icon name={iconName} label={iconLabel} />
108
- {/if}
100
+ <slot name="start-icon" />
109
101
  {#if label}
110
102
  <span class="label">{label}</span>
111
103
  {/if}
112
104
  <slot />
113
- {#if iconName && iconPosition === 'end'}
114
- <Icon name={iconName} label={iconLabel} />
115
- {/if}
105
+ <slot name="end-icon" />
116
106
  </button>
117
107
 
108
+ {#if $$slots.popup}
109
+ <Popup anchor={element} position={popupPosition} bind:this={popupComponent}>
110
+ <slot name="popup" />
111
+ </Popup>
112
+ {/if}
113
+
118
114
  <style>button {
119
115
  display: inline-flex;
120
116
  align-items: center;
@@ -34,14 +34,8 @@ export default class Button {
34
34
  set label(arg: any);
35
35
  get label(): any;
36
36
  /**accessor*/
37
- set iconName(arg: any);
38
- get iconName(): any;
39
- /**accessor*/
40
- set iconLabel(arg: any);
41
- get iconLabel(): any;
42
- /**accessor*/
43
- set iconPosition(arg: any);
44
- get iconPosition(): any;
37
+ set popupPosition(arg: any);
38
+ get popupPosition(): any;
45
39
  }
46
40
  export type ButtonProps = typeof __propDef.props;
47
41
  export type ButtonEvents = typeof __propDef.events;
@@ -49,8 +43,8 @@ export type ButtonSlots = typeof __propDef.slots;
49
43
  declare const __propDef: {
50
44
  props: {
51
45
  [x: string]: any;
52
- class?: string;
53
46
  label?: string;
47
+ class?: string;
54
48
  element?: (HTMLButtonElement | undefined);
55
49
  type?: ('button' | 'submit' | 'reset');
56
50
  role?: string;
@@ -58,9 +52,7 @@ declare const __propDef: {
58
52
  hidden?: boolean;
59
53
  disabled?: boolean;
60
54
  pressed?: (boolean | string | undefined);
61
- iconName?: string;
62
- iconLabel?: string;
63
- iconPosition?: ('start' | 'end');
55
+ popupPosition?: any;
64
56
  };
65
57
  events: {
66
58
  mouseenter: MouseEvent;
@@ -77,7 +69,10 @@ declare const __propDef: {
77
69
  [evt: string]: CustomEvent<any>;
78
70
  };
79
71
  slots: {
72
+ 'start-icon': {};
80
73
  default: {};
74
+ 'end-icon': {};
75
+ popup: {};
81
76
  };
82
77
  };
83
78
  export {};
@@ -7,6 +7,7 @@
7
7
  import { createEventDispatcher } from 'svelte';
8
8
  import { getRandomId } from '../helpers/util';
9
9
  import Button from './button.svelte';
10
+ import Icon from './icon.svelte';
10
11
 
11
12
  /**
12
13
  * CSS class name on the button.
@@ -32,10 +33,6 @@
32
33
  const id = getRandomId('checkbox');
33
34
  /** @type {Button} */
34
35
  let button;
35
-
36
- $: {
37
- dispatch('change', { checked });
38
- }
39
36
  </script>
40
37
 
41
38
  {#if name && value && checked && !indeterminate}
@@ -53,7 +50,6 @@
53
50
  >
54
51
  <Button
55
52
  {id}
56
- iconName={indeterminate ? 'remove' : 'check'}
57
53
  role="checkbox"
58
54
  aria-checked={indeterminate ? 'mixed' : checked}
59
55
  aria-labelledby="{id}-label"
@@ -63,8 +59,11 @@
63
59
  event.stopPropagation();
64
60
  checked = indeterminate ? true : !checked;
65
61
  indeterminate = false;
62
+ dispatch('change', { checked });
66
63
  }}
67
- />
64
+ >
65
+ <Icon slot="start-icon" name={indeterminate ? 'remove' : 'check'} />
66
+ </Button>
68
67
  {#if $$slots.default}
69
68
  <label id="{id}-label">
70
69
  <slot />
@@ -7,6 +7,7 @@
7
7
  import { createEventDispatcher, onMount } from 'svelte';
8
8
  import { _ } from 'svelte-i18n';
9
9
  import Button from './button.svelte';
10
+ import Icon from './icon.svelte';
10
11
  import Spacer from './spacer.svelte';
11
12
 
12
13
  /**
@@ -134,13 +135,13 @@
134
135
  {#if showClose}
135
136
  <Button
136
137
  class="ternary iconic"
137
- iconName="close"
138
- iconLabel={$_('sui._.close')}
139
138
  on:click={() => {
140
139
  dialog.returnValue = 'close';
141
140
  open = false;
142
141
  }}
143
- />
142
+ >
143
+ <Icon slot="start-icon" name="close" label={$_('sui._.close')} />
144
+ </Button>
144
145
  {/if}
145
146
  {/if}
146
147
  </div>
@@ -12,10 +12,10 @@ export type DialogEvents = typeof __propDef.events;
12
12
  export type DialogSlots = typeof __propDef.slots;
13
13
  declare const __propDef: {
14
14
  props: {
15
- class?: string;
16
- size?: ('small' | 'medium' | 'large');
17
15
  title?: string;
18
16
  open?: boolean;
17
+ class?: string;
18
+ size?: ('small' | 'medium' | 'large');
19
19
  modal?: boolean;
20
20
  showCancel?: boolean;
21
21
  showOk?: boolean;
@@ -9,8 +9,8 @@ export type GroupSlots = typeof __propDef.slots;
9
9
  declare const __propDef: {
10
10
  props: {
11
11
  [x: string]: any;
12
- class?: string;
13
12
  title?: string;
13
+ class?: string;
14
14
  ariaLabel?: string;
15
15
  };
16
16
  events: {
@@ -8,9 +8,9 @@ export type IconEvents = typeof __propDef.events;
8
8
  export type IconSlots = typeof __propDef.slots;
9
9
  declare const __propDef: {
10
10
  props: {
11
+ label?: string;
11
12
  class?: string;
12
13
  name?: string;
13
- label?: string;
14
14
  };
15
15
  events: {
16
16
  [evt: string]: CustomEvent<any>;
@@ -3,7 +3,6 @@
3
3
  @see https://w3c.github.io/aria-practices/#menubutton
4
4
  -->
5
5
  <script>
6
- import Menu from '../composite/menu.svelte';
7
6
  import Popup from '../util/popup.svelte';
8
7
  import Button from './button.svelte';
9
8
 
@@ -19,25 +18,17 @@
19
18
  * Where to show the dropdown menu.
20
19
  * @type {PopupPosition}
21
20
  */
22
- export let position = 'bottom-left';
23
-
24
- /**
25
- * Whether to show an arrow icon next to the label, if `iconName` is not given. The default is
26
- * `true`.
27
- */
28
- export let showArrow = true;
21
+ export let popupPosition = 'bottom-left';
29
22
 
30
23
  /** @type {?Button} */
31
24
  let buttonComponent;
32
- /** @type {?Menu} */
33
- let menuComponent;
25
+ /** @type {?Popup} */
26
+ let popupComponent;
34
27
  </script>
35
28
 
36
29
  <Button
37
30
  class="sui menu-button {className}"
38
31
  aria-haspopup="menu"
39
- iconName={$$props.iconName || (showArrow ? 'arrow_drop_down' : undefined)}
40
- iconPosition="end"
41
32
  {...$$restProps}
42
33
  bind:this={buttonComponent}
43
34
  on:keydown={(event) => {
@@ -47,7 +38,7 @@
47
38
  event.preventDefault();
48
39
 
49
40
  const members = [
50
- ...menuComponent.element.querySelectorAll('[role^="menuitem"]:not([aria-disabled="true"])'),
41
+ ...popupComponent.dialog.querySelectorAll('[role^="menuitem"]:not([aria-disabled="true"])'),
51
42
  ];
52
43
 
53
44
  if (members.length) {
@@ -56,10 +47,11 @@
56
47
  }
57
48
  }}
58
49
  >
59
- <slot name="button" />
50
+ <slot name="start-icon" slot="start-icon" />
51
+ <slot />
52
+ <slot name="end-icon" slot="end-icon" />
60
53
  </Button>
61
- <Popup anchor={buttonComponent?.element} {position}>
62
- <Menu bind:this={menuComponent}>
63
- <slot />
64
- </Menu>
54
+
55
+ <Popup anchor={buttonComponent?.element} position={popupPosition} bind:this={popupComponent}>
56
+ <slot name="popup" />
65
57
  </Popup>
@@ -11,15 +11,20 @@ declare const __propDef: {
11
11
  props: {
12
12
  [x: string]: any;
13
13
  class?: string;
14
- position?: any;
15
- showArrow?: boolean;
14
+ popupPosition?: any;
16
15
  };
17
16
  events: {
18
17
  [evt: string]: CustomEvent<any>;
19
18
  };
20
19
  slots: {
21
- button: {};
20
+ 'start-icon': {
21
+ slot: string;
22
+ };
22
23
  default: {};
24
+ 'end-icon': {
25
+ slot: string;
26
+ };
27
+ popup: {};
23
28
  };
24
29
  };
25
30
  export {};
@@ -48,7 +48,7 @@
48
48
  }}
49
49
  >
50
50
  {#if iconName}
51
- <Icon name={iconName} label={iconLabel} />
51
+ <Icon slot="start-icon" name={iconName} label={iconLabel} />
52
52
  {/if}
53
53
  {#if label}
54
54
  <span class="label">{label}</span>
@@ -10,12 +10,12 @@ export type MenuItemSlots = typeof __propDef.slots;
10
10
  declare const __propDef: {
11
11
  props: {
12
12
  [x: string]: any;
13
- class?: string;
14
13
  label?: string;
14
+ class?: string;
15
15
  role?: ('menuitem' | 'menuitemcheckbox' | 'menuitemradio');
16
+ checked?: boolean;
16
17
  iconName?: string;
17
18
  iconLabel?: string;
18
- checked?: boolean;
19
19
  };
20
20
  events: {
21
21
  click: any;
@@ -5,6 +5,7 @@
5
5
  <script>
6
6
  import { _ } from 'svelte-i18n';
7
7
  import Button from './button.svelte';
8
+ import Icon from './icon.svelte';
8
9
  import TextInput from './text-input.svelte';
9
10
 
10
11
  /**
@@ -70,21 +71,21 @@
70
71
  <Button
71
72
  class="iconic"
72
73
  disabled={disabled || Number.isNaN(Number(value))}
73
- iconLabel={$_('sui.number_input.decrease')}
74
- iconName={'arrow_downward'}
75
74
  on:click={() => {
76
75
  decrease();
77
76
  }}
78
- />
77
+ >
78
+ <Icon slot="start-icon" name="arrow_downward" label={$_('sui.number_input.decrease')} />
79
+ </Button>
79
80
  <Button
80
81
  class="iconic"
81
82
  disabled={disabled || Number.isNaN(Number(value))}
82
- iconLabel={$_('sui.number_input.increase')}
83
- iconName={'arrow_upward'}
84
83
  on:click={() => {
85
84
  increase();
86
85
  }}
87
- />
86
+ >
87
+ <Icon slot="start-icon" name={'arrow_upward'} label={$_('sui.number_input.increase')} />
88
+ </Button>
88
89
  </div>
89
90
 
90
91
  <style>.number-input {
@@ -28,10 +28,12 @@
28
28
  on:dragend
29
29
  on:drop
30
30
  >
31
- <slot />
32
31
  {#if selected}
33
32
  <Icon class="check" name="check" />
34
33
  {/if}
34
+ <slot name="start-icon" slot="start-icon" />
35
+ <slot />
36
+ <slot name="end-icon" slot="end-icon" />
35
37
  </Button>
36
38
  </div>
37
39
 
@@ -23,7 +23,13 @@ declare const __propDef: {
23
23
  [evt: string]: CustomEvent<any>;
24
24
  };
25
25
  slots: {
26
+ 'start-icon': {
27
+ slot: string;
28
+ };
26
29
  default: {};
30
+ 'end-icon': {
31
+ slot: string;
32
+ };
27
33
  };
28
34
  };
29
35
  export {};
@@ -5,6 +5,7 @@
5
5
  <script>
6
6
  import { _ } from 'svelte-i18n';
7
7
  import Button from './button.svelte';
8
+ import Icon from './icon.svelte';
8
9
  import TextInput from './text-input.svelte';
9
10
 
10
11
  /**
@@ -44,12 +45,16 @@
44
45
  <Button
45
46
  class="iconic"
46
47
  pressed={passwordVisible}
47
- iconLabel={$_('sui.password_input.show_password')}
48
- iconName={passwordVisible ? 'visibility_off' : 'visibility'}
49
48
  on:click={() => {
50
49
  passwordVisible = !passwordVisible;
51
50
  }}
52
- />
51
+ >
52
+ <Icon
53
+ slot="start-icon"
54
+ name={passwordVisible ? 'visibility_off' : 'visibility'}
55
+ label={$_('sui.password_input.show_password')}
56
+ />
57
+ </Button>
53
58
  </div>
54
59
 
55
60
  <style>.password-input {
@@ -6,6 +6,7 @@
6
6
  <script>
7
7
  import { getRandomId } from '../helpers/util';
8
8
  import Button from './button.svelte';
9
+ import Icon from './icon.svelte';
9
10
 
10
11
  /**
11
12
  * CSS class name on the button.
@@ -44,7 +45,6 @@
44
45
  >
45
46
  <Button
46
47
  {id}
47
- iconName="circle"
48
48
  role="radio"
49
49
  aria-checked={selected}
50
50
  aria-labelledby="{id}-label"
@@ -53,7 +53,9 @@
53
53
  event.preventDefault();
54
54
  selected = !selected;
55
55
  }}
56
- />
56
+ >
57
+ <Icon slot="start-icon" name="circle" />
58
+ </Button>
57
59
  <label id="{id}-label">
58
60
  <slot />
59
61
  </label>
@@ -47,8 +47,6 @@
47
47
  {#if value}
48
48
  <Button
49
49
  class="ternary iconic"
50
- iconName="close"
51
- iconLabel={$_('sui._.clear')}
52
50
  on:click={() => {
53
51
  value = '';
54
52
  input.element.focus();
@@ -58,7 +56,9 @@
58
56
  input.element.dispatchEvent(new KeyboardEvent('change'));
59
57
  });
60
58
  }}
61
- />
59
+ >
60
+ <Icon slot="start-icon" name="close" label={$_('sui._.clear')} />
61
+ </Button>
62
62
  {/if}
63
63
  </div>
64
64
 
@@ -17,8 +17,8 @@ export type SearchBarSlots = typeof __propDef.slots;
17
17
  declare const __propDef: {
18
18
  props: {
19
19
  [x: string]: any;
20
- class?: string;
21
20
  focus?: () => void;
21
+ class?: string;
22
22
  value?: string;
23
23
  };
24
24
  events: {
@@ -25,5 +25,7 @@
25
25
  {...$$restProps}
26
26
  on:click
27
27
  >
28
+ <slot name="start-icon" slot="start-icon" />
28
29
  <slot />
30
+ <slot name="end-icon" slot="end-icon" />
29
31
  </Button>
@@ -23,7 +23,13 @@ declare const __propDef: {
23
23
  [evt: string]: CustomEvent<any>;
24
24
  };
25
25
  slots: {
26
+ 'start-icon': {
27
+ slot: string;
28
+ };
26
29
  default: {};
30
+ 'end-icon': {
31
+ slot: string;
32
+ };
27
33
  };
28
34
  };
29
35
  export {};
@@ -12,8 +12,8 @@ export type SwitchEvents = typeof __propDef.events;
12
12
  export type SwitchSlots = typeof __propDef.slots;
13
13
  declare const __propDef: {
14
14
  props: {
15
- class?: string;
16
15
  label?: string;
16
+ class?: string;
17
17
  disabled?: boolean;
18
18
  checked?: boolean;
19
19
  };
@@ -16,5 +16,7 @@
16
16
  </script>
17
17
 
18
18
  <Button role="tab" class="sui tab {className}" {...$$restProps}>
19
+ <slot name="start-icon" slot="start-icon" />
19
20
  <slot />
21
+ <slot name="end-icon" slot="end-icon" />
20
22
  </Button>
@@ -19,7 +19,13 @@ declare const __propDef: {
19
19
  [evt: string]: CustomEvent<any>;
20
20
  };
21
21
  slots: {
22
+ 'start-icon': {
23
+ slot: string;
24
+ };
22
25
  default: {};
26
+ 'end-icon': {
27
+ slot: string;
28
+ };
23
29
  };
24
30
  };
25
31
  export {};
@@ -26,8 +26,8 @@ declare const __propDef: {
26
26
  props: {
27
27
  [x: string]: any;
28
28
  class?: string;
29
- name?: string;
30
29
  element?: (HTMLTextAreaElement | undefined);
30
+ name?: string;
31
31
  value?: (string | undefined);
32
32
  autoResize?: boolean;
33
33
  };
@@ -32,10 +32,10 @@ declare const __propDef: {
32
32
  props: {
33
33
  [x: string]: any;
34
34
  class?: string;
35
- name?: string;
36
35
  element?: (HTMLInputElement | undefined);
37
36
  role?: ('textbox' | 'searchbox' | 'combobox' | 'spinbutton');
38
37
  disabled?: boolean;
38
+ name?: string;
39
39
  value?: (string | undefined);
40
40
  readOnly?: boolean;
41
41
  };
@@ -1,6 +1,7 @@
1
1
  <script>
2
2
  import { _ } from 'svelte-i18n';
3
3
  import Button from '../core/button.svelte';
4
+ import Icon from '../core/icon.svelte';
4
5
  import Separator from '../core/separator.svelte';
5
6
  import TextArea from '../core/text-area.svelte';
6
7
  import Toolbar from '../core/toolbar.svelte';
@@ -47,7 +48,9 @@
47
48
  {#if separator}
48
49
  <Separator />
49
50
  {:else}
50
- <Button {disabled} iconName={icon} iconLabel={label} />
51
+ <Button {disabled}>
52
+ <Icon slot="start-icon" name={icon} {label} />
53
+ </Button>
51
54
  {/if}
52
55
  {/each}
53
56
  </Toolbar>
@@ -19,41 +19,61 @@ class Popup {
19
19
  return;
20
20
  }
21
21
 
22
- const top = this.position.startsWith('bottom-')
22
+ const contentHeight = this.popupElement.querySelector('.content').scrollHeight;
23
+ const topMargin = intersectionRect.top - 8;
24
+ const bottomMargin = rootBounds.height - intersectionRect.bottom - 8;
25
+ let { position } = this;
26
+ let height;
27
+
28
+ // Alter the position if the space is limited
29
+ // @todo Handle more overflow cases
30
+ if (position.startsWith('bottom-')) {
31
+ if (contentHeight > bottomMargin) {
32
+ if (topMargin > bottomMargin) {
33
+ position = position.replace('bottom-', 'top-');
34
+ height = topMargin;
35
+ } else {
36
+ height = bottomMargin;
37
+ }
38
+ }
39
+ }
40
+
41
+ const top = position.startsWith('bottom-')
23
42
  ? `${Math.round(intersectionRect.bottom)}px`
24
- : this.position.endsWith('-top')
43
+ : position.endsWith('-top')
25
44
  ? `${Math.round(intersectionRect.top)}px`
26
45
  : 'auto';
27
46
 
28
- const right = this.position.startsWith('left-')
47
+ const right = position.startsWith('left-')
29
48
  ? `${Math.round(rootBounds.width - intersectionRect.left)}px`
30
- : this.position.endsWith('-right')
49
+ : position.endsWith('-right')
31
50
  ? `${Math.round(rootBounds.width - intersectionRect.right)}px`
32
51
  : 'auto';
33
52
 
34
- const bottom = this.position.startsWith('top-')
53
+ const bottom = position.startsWith('top-')
35
54
  ? `${Math.round(rootBounds.height - intersectionRect.top)}px`
36
- : this.position.endsWith('-bottom')
55
+ : position.endsWith('-bottom')
37
56
  ? `${Math.round(rootBounds.height - intersectionRect.bottom)}px`
38
57
  : 'auto';
39
58
 
40
- const left = this.position.startsWith('right-')
59
+ const left = position.startsWith('right-')
41
60
  ? `${Math.round(intersectionRect.right)}px`
42
- : this.position.endsWith('-left')
61
+ : position.endsWith('-left')
43
62
  ? `${Math.round(intersectionRect.left)}px`
44
63
  : 'auto';
45
64
 
46
- const width = `${Math.round(intersectionRect.width)}px`;
47
- const height = `${Math.round(rootBounds.height - intersectionRect.bottom - 8)}px`;
48
65
  const anchorPopup = this.anchorElement.closest('.popup');
49
66
 
50
- // @todo fix the final position
51
- this.style.set({
67
+ const style = {
52
68
  inset: [top, right, bottom, left].join(' '),
53
69
  zIndex: anchorPopup ? Number(anchorPopup.style.zIndex) + 1 : 1000,
54
- width,
55
- height,
56
- });
70
+ width: `${Math.round(intersectionRect.width)}px`,
71
+ height: height ? `${Math.round(height)}px` : 'auto',
72
+ };
73
+
74
+ if (JSON.stringify(style) !== JSON.stringify(get(this.style))) {
75
+ this.style.set(style);
76
+ }
57
77
  });
58
78
  });
59
79
 
@@ -112,7 +112,7 @@
112
112
  --background-color-2-hsl: var(--hue) 5% 98%;
113
113
  --background-color-3-hsl: var(--hue) 5% 96%;
114
114
  --background-color-4-hsl: var(--hue) 5% 94%;
115
- --background-color-5-hsl: var(--hue) 5% 90%;
115
+ --background-color-5-hsl: var(--hue) 5% 80%;
116
116
  --shadow-color: var(--hue) 10% 0%;
117
117
  --primary-accent-color: hsl(var(--hue) 80% 45%);
118
118
  --primary-accent-color-lighter: hsl(var(--hue) 80% 40%);
@@ -28,6 +28,7 @@
28
28
 
29
29
  let showDialog = false;
30
30
  let showContent = false;
31
+ let contentType;
31
32
  let closeDialogTimer = 0;
32
33
 
33
34
  let style = writable({
@@ -40,6 +41,7 @@
40
41
  $: {
41
42
  if (anchor && dialog) {
42
43
  ({ open, style } = activatePopup(anchor, dialog, position));
44
+ contentType = anchor.getAttribute('aria-haspopup');
43
45
  }
44
46
  }
45
47
 
@@ -91,7 +93,7 @@
91
93
  <!-- svelte-ignore a11y-no-noninteractive-tabindex -->
92
94
  <div
93
95
  tabindex="0"
94
- class="content"
96
+ class="content {contentType}"
95
97
  style:inset={$style.inset}
96
98
  style:z-index={$style.zIndex}
97
99
  style:min-width={$style.width}
@@ -128,4 +130,16 @@
128
130
  box-shadow: 0 8px 16px var(--popup-shadow-color);
129
131
  will-change: opacity, transform;
130
132
  transition-property: opacity, transform;
133
+ }
134
+ .content.listbox, .content.menu {
135
+ border-width: 1px;
136
+ border-style: solid;
137
+ border-color: var(--secondary-border-color);
138
+ border-radius: 4px;
139
+ }
140
+ .content.listbox :global(.sui.listbox),
141
+ .content.listbox :global(.sui.menu), .content.menu :global(.sui.listbox),
142
+ .content.menu :global(.sui.menu) {
143
+ border-width: 0;
144
+ border-radius: 0;
131
145
  }</style>
@@ -23,8 +23,8 @@ declare const __propDef: {
23
23
  props: {
24
24
  [x: string]: any;
25
25
  dialog?: (HTMLElement | undefined);
26
- anchor?: (HTMLElement | undefined);
27
26
  position?: any;
27
+ anchor?: (HTMLElement | undefined);
28
28
  open?: any;
29
29
  };
30
30
  events: {
@@ -80,7 +80,7 @@
80
80
  --background-color-2-hsl: var(--hue) 5% 98%; // primary
81
81
  --background-color-3-hsl: var(--hue) 5% 96%; // secondary/ternary
82
82
  --background-color-4-hsl: var(--hue) 5% 94%; // disabled
83
- --background-color-5-hsl: var(--hue) 5% 90%; // highlight
83
+ --background-color-5-hsl: var(--hue) 5% 80%; // highlight
84
84
  --shadow-color: var(--hue) 10% 0%;
85
85
  // Accents
86
86
  --primary-accent-color: hsl(var(--hue) 80% 45%);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltia/ui",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -29,12 +29,12 @@
29
29
  "devDependencies": {
30
30
  "@babel/core": "^7.21.4",
31
31
  "@babel/eslint-parser": "^7.21.3",
32
- "@playwright/test": "^1.32.1",
32
+ "@playwright/test": "^1.32.2",
33
33
  "@sveltejs/adapter-auto": "2.0.0",
34
- "@sveltejs/kit": "1.15.0",
34
+ "@sveltejs/kit": "1.15.2",
35
35
  "@sveltejs/package": "^2.0.2",
36
36
  "cspell": "^6.31.1",
37
- "eslint": "^8.37.0",
37
+ "eslint": "^8.38.0",
38
38
  "eslint-config-airbnb-base": "^15.0.0",
39
39
  "eslint-config-prettier": "^8.8.0",
40
40
  "eslint-plugin-import": "^2.27.5",
@@ -44,17 +44,17 @@
44
44
  "postcss-html": "^1.5.0",
45
45
  "prettier": "^2.8.7",
46
46
  "prettier-plugin-svelte": "^2.10.0",
47
- "sass": "^1.60.0",
47
+ "sass": "^1.61.0",
48
48
  "stylelint": "^15.4.0",
49
49
  "stylelint-config-recommended-scss": "^9.0.1",
50
50
  "stylelint-scss": "^4.6.0",
51
- "svelte-check": "^3.1.4",
51
+ "svelte-check": "^3.2.0",
52
52
  "svelte-i18n": "^3.6.0",
53
53
  "svelte-migrate": "^1.1.3",
54
54
  "svelte-preprocess": "^5.0.3",
55
55
  "tslib": "^2.5.0",
56
56
  "vite": "^4.2.1",
57
- "vitest": "^0.29.8"
57
+ "vitest": "^0.30.0"
58
58
  },
59
59
  "exports": {
60
60
  "./package.json": "./package.json",