@sveltia/ui 0.2.1 → 0.2.3

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.
@@ -43,28 +43,28 @@
43
43
  <input type="hidden" bind:value />
44
44
  <div class="header">
45
45
  <Button
46
- class="tertiary"
46
+ class="ghost"
47
47
  label={firstDay.toLocaleDateString('en', { year: 'numeric', month: 'short' })}
48
48
  aria-haspopup="dialog"
49
49
  >
50
50
  <Icon slot="end-icon" name="arrow_drop_down" />
51
51
  <!-- svelte-ignore a11y-click-events-have-key-events -->
52
52
  <div slot="popup" class="popup-inner" on:click|stopPropagation>
53
- <div role="group" aria-label={$_('sui.calendar.year')}>
53
+ <div role="group" aria-label={$_('_sui.calendar.year')}>
54
54
  <div class="header">
55
55
  <Button
56
56
  on:click={() => {
57
57
  //
58
58
  }}
59
59
  >
60
- <Icon name="chevron_left" label={$_('sui.calendar.previous_decade')} />
60
+ <Icon name="chevron_left" label={$_('_sui.calendar.previous_decade')} />
61
61
  </Button>
62
62
  <Button
63
63
  on:click={() => {
64
64
  //
65
65
  }}
66
66
  >
67
- <Icon name="chevron_right" label={$_('sui.calendar.next_decade')} />
67
+ <Icon name="chevron_right" label={$_('_sui.calendar.next_decade')} />
68
68
  </Button>
69
69
  </div>
70
70
  <div class="grid">
@@ -76,7 +76,7 @@
76
76
  </div>
77
77
  </div>
78
78
  <Separator orientation="vertical" />
79
- <div role="group" aria-label={$_('sui.calendar.month')}>
79
+ <div role="group" aria-label={$_('_sui.calendar.month')}>
80
80
  <div class="grid">
81
81
  {#each [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] as month}
82
82
  <div>
@@ -97,7 +97,7 @@
97
97
  firstDay = firstDay;
98
98
  }}
99
99
  >
100
- <Icon name="chevron_left" label={$_('sui.calendar.previous_month')} />
100
+ <Icon name="chevron_left" label={$_('_sui.calendar.previous_month')} />
101
101
  </Button>
102
102
  <Button
103
103
  on:click={() => {
@@ -105,7 +105,7 @@
105
105
  firstDay = firstDay;
106
106
  }}
107
107
  >
108
- <Icon name="chevron_right" label={$_('sui.calendar.next_month')} />
108
+ <Icon name="chevron_right" label={$_('_sui.calendar.next_month')} />
109
109
  </Button>
110
110
  </div>
111
111
  <div class="grid" role="listbox">
@@ -139,7 +139,7 @@
139
139
  value = '';
140
140
  }}
141
141
  >
142
- {$_('sui._.clear')}
142
+ {$_('_sui._.clear')}
143
143
  </Button>
144
144
  <Spacer flex={true} />
145
145
  <Button
@@ -147,7 +147,7 @@
147
147
  [value] = now.toJSON().split('T');
148
148
  }}
149
149
  >
150
- {$_('sui.calendar.today')}
150
+ {$_('_sui.calendar.today')}
151
151
  </Button>
152
152
  </div>
153
153
  </div>
@@ -69,7 +69,7 @@
69
69
  bind:this={comboboxElement}
70
70
  >
71
71
  <div class="label">
72
- {value !== undefined ? label || value : $_('sui.combobox.select_an_option')}
72
+ {value !== undefined ? label || value : $_('_sui.combobox.select_an_option')}
73
73
  </div>
74
74
  </div>
75
75
  {:else}
@@ -93,7 +93,7 @@
93
93
  aria-controls="{id}-popup"
94
94
  aria-expanded={$isPopupOpen}
95
95
  aria-disabled={disabled ? true : undefined}
96
- class="tertiary iconic"
96
+ class="ghost iconic"
97
97
  on:click={(event) => {
98
98
  event.stopPropagation();
99
99
 
@@ -105,7 +105,7 @@
105
105
  <Icon
106
106
  slot="start-icon"
107
107
  name="expand_more"
108
- label={$isPopupOpen ? $_('sui._.collapse') : $_('sui._.expand')}
108
+ label={$isPopupOpen ? $_('_sui._.collapse') : $_('_sui._.expand')}
109
109
  />
110
110
  </Button>
111
111
  </div>
@@ -151,8 +151,6 @@
151
151
  z-index: 1;
152
152
  border-top-left-radius: 0;
153
153
  border-bottom-left-radius: 0;
154
- border-width: 0;
155
- background-color: transparent;
156
154
  }
157
155
  .combobox > :global(button[tabindex="-1"]) {
158
156
  pointer-events: none;
@@ -141,14 +141,14 @@ button[disabled] {
141
141
  cursor: default;
142
142
  pointer-events: none;
143
143
  }
144
- button:global(.primary), button:global(.secondary), button:global(.tertiary) {
144
+ button:global(.primary), button:global(.secondary), button:global(.tertiary), button:global(.ghost) {
145
145
  justify-content: center;
146
146
  border-width: 1px;
147
147
  border-radius: var(--button--medium--border-radius);
148
148
  padding: var(--button--medium--padding, 0 8px);
149
149
  height: var(--button--medium--height);
150
150
  }
151
- button:global(.primary) :global(.label:only-child), button:global(.secondary) :global(.label:only-child), button:global(.tertiary) :global(.label:only-child) {
151
+ button:global(.primary) :global(.label:only-child), button:global(.secondary) :global(.label:only-child), button:global(.tertiary) :global(.label:only-child), button:global(.ghost) :global(.label:only-child) {
152
152
  padding: 0 4px;
153
153
  }
154
154
  button:global(.primary) {
@@ -156,7 +156,7 @@ button:global(.primary) {
156
156
  color: var(--primary-accent-color-foreground);
157
157
  background-color: var(--primary-accent-color);
158
158
  }
159
- button:global(.primary):hover, button:global(.primary):focus {
159
+ button:global(.primary):hover, button:global(.primary):focus-visible {
160
160
  background-color: var(--primary-accent-color-lighter);
161
161
  }
162
162
  button:global(.primary):active {
@@ -167,7 +167,7 @@ button:global(.secondary) {
167
167
  color: var(--primary-accent-color-lighter);
168
168
  background-color: var(--tertiary-background-color);
169
169
  }
170
- button:global(.secondary):hover, button:global(.secondary):focus {
170
+ button:global(.secondary):hover, button:global(.secondary):focus-visible {
171
171
  background-color: var(--highlight-background-color);
172
172
  }
173
173
  button:global(.secondary)[aria-pressed=true] {
@@ -178,12 +178,18 @@ button:global(.tertiary) {
178
178
  color: var(--highlight-foreground-color);
179
179
  background-color: var(--tertiary-background-color);
180
180
  }
181
- button:global(.tertiary):hover, button:global(.tertiary):focus {
181
+ button:global(.tertiary):hover, button:global(.tertiary):focus-visible {
182
182
  background-color: var(--highlight-background-color);
183
183
  }
184
184
  button:global(.tertiary)[aria-pressed=true] {
185
185
  background-color: var(--highlight-background-color);
186
186
  }
187
+ button:global(.ghost):hover, button:global(.ghost):focus-visible {
188
+ background-color: var(--highlight-background-color);
189
+ }
190
+ button:global(.ghost)[aria-pressed=true] {
191
+ background-color: var(--highlight-background-color);
192
+ }
187
193
  button:global(.danger) {
188
194
  background-color: var(--danger-background-color);
189
195
  }
@@ -147,13 +147,13 @@
147
147
  {/if}
148
148
  {#if showClose}
149
149
  <Button
150
- class="tertiary iconic"
150
+ class="ghost iconic"
151
151
  on:click={() => {
152
152
  dialog.returnValue = 'close';
153
153
  open = false;
154
154
  }}
155
155
  >
156
- <Icon slot="start-icon" name="close" label={$_('sui._.close')} />
156
+ <Icon slot="start-icon" name="close" label={$_('_sui._.close')} />
157
157
  </Button>
158
158
  {/if}
159
159
  {/if}
@@ -174,7 +174,7 @@
174
174
  {#if showOk}
175
175
  <Button
176
176
  class="primary"
177
- label={okLabel || $_('sui._.ok')}
177
+ label={okLabel || $_('_sui._.ok')}
178
178
  disabled={okDisabled}
179
179
  on:click={() => {
180
180
  dialog.returnValue = 'ok';
@@ -185,7 +185,7 @@
185
185
  {#if showCancel}
186
186
  <Button
187
187
  class="secondary"
188
- label={cancelLabel || $_('sui._.cancel')}
188
+ label={cancelLabel || $_('_sui._.cancel')}
189
189
  disabled={cancelDisabled}
190
190
  on:click={() => {
191
191
  dialog.returnValue = 'cancel';
@@ -137,13 +137,13 @@
137
137
  <div class="extra-control">
138
138
  {#if showClose === 'outside'}
139
139
  <Button
140
- class="iconic close"
140
+ class="ghost iconic close"
141
141
  on:click={() => {
142
142
  dialog.returnValue = 'close';
143
143
  open = false;
144
144
  }}
145
145
  >
146
- <Icon slot="start-icon" name="close" label={$_('sui._.close')} />
146
+ <Icon slot="start-icon" name="close" label={$_('_sui._.close')} />
147
147
  </Button>
148
148
  {/if}
149
149
  </div>
@@ -162,13 +162,13 @@
162
162
  {/if}
163
163
  {#if showClose === 'inside'}
164
164
  <Button
165
- class="tertiary iconic close"
165
+ class="ghost iconic close"
166
166
  on:click={() => {
167
167
  dialog.returnValue = 'close';
168
168
  open = false;
169
169
  }}
170
170
  >
171
- <Icon slot="start-icon" name="close" label={$_('sui._.close')} />
171
+ <Icon slot="start-icon" name="close" label={$_('_sui._.close')} />
172
172
  </Button>
173
173
  {/if}
174
174
  {/if}
@@ -50,7 +50,7 @@
50
50
  {disabled}
51
51
  role="spinbutton"
52
52
  aria-valuenow={Number(value || 0)}
53
- aria-invalid={Number.isNaN(Number(value))}
53
+ aria-invalid={value !== undefined && Number.isNaN(Number(value))}
54
54
  {...$$restProps}
55
55
  on:keydown={(event) => {
56
56
  const { key, ctrlKey, metaKey, altKey, shiftKey } = event;
@@ -75,7 +75,7 @@
75
75
  decrease();
76
76
  }}
77
77
  >
78
- <Icon slot="start-icon" name="arrow_downward" label={$_('sui.number_input.decrease')} />
78
+ <Icon slot="start-icon" name="arrow_downward" label={$_('_sui.number_input.decrease')} />
79
79
  </Button>
80
80
  <Button
81
81
  class="iconic"
@@ -84,7 +84,7 @@
84
84
  increase();
85
85
  }}
86
86
  >
87
- <Icon slot="start-icon" name={'arrow_upward'} label={$_('sui.number_input.increase')} />
87
+ <Icon slot="start-icon" name={'arrow_upward'} label={$_('_sui.number_input.increase')} />
88
88
  </Button>
89
89
  </div>
90
90
 
@@ -52,7 +52,7 @@
52
52
  <Icon
53
53
  slot="start-icon"
54
54
  name={passwordVisible ? 'visibility_off' : 'visibility'}
55
- label={$_('sui.password_input.show_password')}
55
+ label={$_('_sui.password_input.show_password')}
56
56
  />
57
57
  </Button>
58
58
  </div>
@@ -57,7 +57,7 @@
57
57
  });
58
58
  }}
59
59
  >
60
- <Icon slot="start-icon" name="close" label={$_('sui._.clear')} />
60
+ <Icon slot="start-icon" name="close" label={$_('_sui._.clear')} />
61
61
  </Button>
62
62
  {/if}
63
63
  </div>
@@ -5,6 +5,8 @@
5
5
  <svelte:options accessors={true} />
6
6
 
7
7
  <script>
8
+ import { onMount, tick } from 'svelte';
9
+
8
10
  /**
9
11
  * CSS class name on the button.
10
12
  * @type {String}
@@ -26,35 +28,67 @@
26
28
 
27
29
  /** @type {(String|undefined)} */
28
30
  let height;
31
+ /** @type {(HTMLTextAreaElement|undefined)} */
32
+ let outer = undefined;
33
+ let resizing = false;
34
+ let lastWidth = 0;
29
35
 
30
- const resizeTextarea = () => {
36
+ /**
37
+ * Resize the `<textarea>` based on the filled text content.
38
+ */
39
+ const resizeTextarea = async () => {
40
+ resizing = true;
31
41
  height = 'auto';
32
42
 
33
- window.requestAnimationFrame(() => {
34
- height = value && element?.scrollHeight ? `${element.scrollHeight + 4}px` : undefined;
35
- });
43
+ await tick();
44
+
45
+ height = value && element?.scrollHeight ? `${element.scrollHeight + 4}px` : undefined;
46
+ resizing = false;
36
47
  };
37
48
 
49
+ /**
50
+ * Call {@link resizeTextarea} whenever the text content is updated.
51
+ */
38
52
  $: {
39
- if (value && autoResize) {
40
- resizeTextarea();
53
+ if (autoResize) {
54
+ resizeTextarea(value);
41
55
  }
42
56
  }
57
+
58
+ /**
59
+ * Call {@link resizeTextarea} whenever it’s horizontally resized.
60
+ */
61
+ onMount(() => {
62
+ const observer = new ResizeObserver(([{ contentRect }]) => {
63
+ const { width } = contentRect;
64
+
65
+ if (autoResize && lastWidth !== width) {
66
+ lastWidth = width;
67
+ resizeTextarea();
68
+ }
69
+ });
70
+
71
+ observer.observe(outer);
72
+
73
+ // onUnmount
74
+ return () => {
75
+ observer.disconnect();
76
+ };
77
+ });
43
78
  </script>
44
79
 
45
- <div class="sui text-area {className}">
80
+ <div class="sui text-area {className}" bind:this={outer}>
46
81
  <textarea
47
82
  name={name || undefined}
48
83
  {...$$restProps}
49
84
  style:height
85
+ class:resizing
50
86
  bind:this={element}
87
+ bind:value
51
88
  on:click
52
89
  on:input
53
90
  on:keypress
54
- on:input={() => {
55
- value = element.value;
56
- }}>{value}</textarea
57
- >
91
+ />
58
92
  </div>
59
93
 
60
94
  <style>.text-area {
@@ -80,6 +114,9 @@ textarea {
80
114
  resize: vertical;
81
115
  transition: all 200ms;
82
116
  }
117
+ textarea.resizing {
118
+ transition-duration: 0ms;
119
+ }
83
120
  textarea:focus {
84
121
  border-color: var(--primary-accent-color);
85
122
  }
@@ -12,38 +12,38 @@
12
12
  export let disabled = false;
13
13
 
14
14
  const defaultButtons = [
15
- { name: 'bold', label: $_('sui.markdown_editor.bold'), icon: 'format_bold' },
16
- { name: 'italic', label: $_('sui.markdown_editor.italic'), icon: 'format_italic' },
17
- { name: 'code', label: $_('sui.markdown_editor.code'), icon: 'code' },
18
- { name: 'link', label: $_('sui.markdown_editor.link'), icon: 'link' },
15
+ { name: 'bold', label: $_('_sui.markdown_editor.bold'), icon: 'format_bold' },
16
+ { name: 'italic', label: $_('_sui.markdown_editor.italic'), icon: 'format_italic' },
17
+ { name: 'code', label: $_('_sui.markdown_editor.code'), icon: 'code' },
18
+ { name: 'link', label: $_('_sui.markdown_editor.link'), icon: 'link' },
19
19
  { separator: true },
20
20
  {
21
21
  name: 'heading-one',
22
- label: $_('sui.markdown_editor.heading_x', { values: { level: 1 } }),
22
+ label: $_('_sui.markdown_editor.heading_x', { values: { level: 1 } }),
23
23
  icon: 'format_h1',
24
24
  },
25
25
  {
26
26
  name: 'heading-two',
27
- label: $_('sui.markdown_editor.heading_x', { values: { level: 2 } }),
27
+ label: $_('_sui.markdown_editor.heading_x', { values: { level: 2 } }),
28
28
  icon: 'format_h2',
29
29
  },
30
- { name: 'quote', label: $_('sui.markdown_editor.quote'), icon: 'format_quote' },
30
+ { name: 'quote', label: $_('_sui.markdown_editor.quote'), icon: 'format_quote' },
31
31
  { separator: true },
32
32
  {
33
33
  name: 'bulleted-list',
34
- label: $_('sui.markdown_editor.bulleted_list'),
34
+ label: $_('_sui.markdown_editor.bulleted_list'),
35
35
  icon: 'format_list_bulleted',
36
36
  },
37
37
  {
38
38
  name: 'numbered-list',
39
- label: $_('sui.markdown_editor.numbered_list'),
39
+ label: $_('_sui.markdown_editor.numbered_list'),
40
40
  icon: 'format_list_numbered',
41
41
  },
42
42
  ];
43
43
  </script>
44
44
 
45
45
  <div>
46
- <Toolbar aria-label={$_('sui.markdown_editor.markdown_editor')}>
46
+ <Toolbar aria-label={$_('_sui.markdown_editor.markdown_editor')}>
47
47
  {#each defaultButtons as { label, icon, separator }}
48
48
  {#if separator}
49
49
  <Separator />
@@ -75,8 +75,8 @@
75
75
  --foreground-color-2-hsl: var(--base-hue) 10% 80%;
76
76
  --foreground-color-3-hsl: var(--base-hue) 10% 60%;
77
77
  --foreground-color-4-hsl: var(--base-hue) 10% 40%;
78
- --border-color-1-hsl: var(--base-hue) 10% 25%;
79
- --border-color-2-hsl: var(--base-hue) 10% 20%;
78
+ --border-color-1-hsl: var(--base-hue) 10% 28%;
79
+ --border-color-2-hsl: var(--base-hue) 10% 24%;
80
80
  --background-color-1-hsl: var(--base-hue) 10% 10%;
81
81
  --background-color-2-hsl: var(--base-hue) 10% 12%;
82
82
  --background-color-3-hsl: var(--base-hue) 10% 16%;
package/package/index.js CHANGED
@@ -12,8 +12,8 @@ export const initLocales = ({ fallbackLocale = 'en', initialLocale = 'en' } = {}
12
12
  Object.entries(modules).forEach(([path, { strings }]) => {
13
13
  const [, locale] = path.match(/([a-zA-Z-]+)\.js/);
14
14
 
15
- // Add `sui` suffix to avoid collision with app localization
16
- addMessages(locale, { sui: strings });
15
+ // Add `_sui` suffix to avoid collision with app localization
16
+ addMessages(locale, { _sui: strings });
17
17
  });
18
18
 
19
19
  init({
@@ -22,6 +22,8 @@ export const initLocales = ({ fallbackLocale = 'en', initialLocale = 'en' } = {}
22
22
  });
23
23
  };
24
24
 
25
+ initLocales();
26
+
25
27
  export { default as Calendar } from './components/composite/calendar.svelte';
26
28
  export { default as CheckboxGroup } from './components/composite/checkbox-group.svelte';
27
29
  export { default as Combobox } from './components/composite/combobox.svelte';
@@ -34,8 +34,8 @@
34
34
  --foreground-color-2-hsl: var(--base-hue) 10% 80%; // primary
35
35
  --foreground-color-3-hsl: var(--base-hue) 10% 60%; // secondary
36
36
  --foreground-color-4-hsl: var(--base-hue) 10% 40%; // tertiary
37
- --border-color-1-hsl: var(--base-hue) 10% 25%; // primary
38
- --border-color-2-hsl: var(--base-hue) 10% 20%; // secondary/input
37
+ --border-color-1-hsl: var(--base-hue) 10% 28%; // primary
38
+ --border-color-2-hsl: var(--base-hue) 10% 24%; // secondary/input
39
39
  --background-color-1-hsl: var(--base-hue) 10% 10%; // content/input
40
40
  --background-color-2-hsl: var(--base-hue) 10% 12%; // primary
41
41
  --background-color-3-hsl: var(--base-hue) 10% 16%; // secondary
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltia/ui",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -27,11 +27,11 @@
27
27
  "svelte": "^3.55.1"
28
28
  },
29
29
  "devDependencies": {
30
- "@babel/core": "^7.21.4",
30
+ "@babel/core": "^7.21.5",
31
31
  "@babel/eslint-parser": "^7.21.3",
32
- "@playwright/test": "^1.32.3",
33
- "@sveltejs/adapter-auto": "2.0.0",
34
- "@sveltejs/kit": "1.15.7",
32
+ "@playwright/test": "^1.33.0",
33
+ "@sveltejs/adapter-auto": "2.0.1",
34
+ "@sveltejs/kit": "1.15.9",
35
35
  "@sveltejs/package": "^2.0.2",
36
36
  "cspell": "^6.31.1",
37
37
  "eslint": "^8.39.0",
@@ -44,16 +44,16 @@
44
44
  "postcss-html": "^1.5.0",
45
45
  "prettier": "^2.8.8",
46
46
  "prettier-plugin-svelte": "^2.10.0",
47
- "sass": "^1.62.0",
47
+ "sass": "^1.62.1",
48
48
  "stylelint": "^15.6.0",
49
- "stylelint-config-recommended-scss": "^10.0.0",
50
- "stylelint-scss": "^4.6.0",
49
+ "stylelint-config-recommended-scss": "^11.0.0",
50
+ "stylelint-scss": "^5.0.0",
51
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
- "vite": "^4.3.1",
56
+ "vite": "^4.3.3",
57
57
  "vitest": "^0.30.1"
58
58
  },
59
59
  "exports": {