@sveltia/ui 0.68.3 → 0.69.1

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.
@@ -32,6 +32,7 @@
32
32
  pressed = undefined,
33
33
  keyShortcuts = undefined,
34
34
  label = '',
35
+ labelDir = undefined,
35
36
  lines = 1,
36
37
  variant = undefined,
37
38
  size = 'medium',
@@ -80,7 +81,7 @@
80
81
  {@render startIcon?.()}
81
82
  {#if variant === 'link'}
82
83
  {#if label}
83
- <span role="none" class="label">
84
+ <span role="none" class="label" dir={labelDir}>
84
85
  <TruncatedText {lines}>
85
86
  {label}
86
87
  </TruncatedText>
@@ -92,7 +93,7 @@
92
93
  {/if}
93
94
  {:else}
94
95
  {#if label}
95
- <span role="none" class="label">
96
+ <span role="none" class="label" dir={labelDir}>
96
97
  <TruncatedText {lines}>
97
98
  {label}
98
99
  </TruncatedText>
@@ -10,7 +10,7 @@
10
10
  @see https://developer.mozilla.org/en-US/docs/Web/API/Popover_API
11
11
  -->
12
12
  <script>
13
- import { _ } from '@sveltia/i18n';
13
+ import { _, isRTL } from '@sveltia/i18n';
14
14
  import { onMount, untrack } from 'svelte';
15
15
  import { searchEmojis } from './emoji.js';
16
16
 
@@ -126,7 +126,7 @@
126
126
  const spaceBelow = innerHeight - anchorRect.bottom;
127
127
  const spaceAbove = anchorRect.top;
128
128
  const flipped = spaceBelow < listMaxHeight + VIEWPORT_MARGIN && spaceAbove > spaceBelow;
129
- const rtl = document.dir === 'rtl';
129
+ const rtl = isRTL();
130
130
  const anchorLeft = rtl ? anchorRect.right - LIST_WIDTH : anchorRect.left;
131
131
 
132
132
  return {
@@ -35,6 +35,7 @@
35
35
  hidden = false,
36
36
  disabled = false,
37
37
  label = '',
38
+ labelDir = undefined,
38
39
  popupPosition = 'right-top', // @todo Make this auto detect
39
40
  children: _children,
40
41
  startIcon: _startIcon,
@@ -118,7 +119,7 @@
118
119
  {/snippet}
119
120
  <!-- eslint-disable-next-line svelte/no-useless-children-snippet -->
120
121
  {#snippet children()}
121
- <div role="none" class="content" class:label={!!label}>
122
+ <div role="none" class="content" class:label={!!label} dir={label ? labelDir : undefined}>
122
123
  {#if label}
123
124
  {label}
124
125
  {:else}
@@ -473,6 +473,7 @@
473
473
  }
474
474
  .combobox-inner :global(.sui.search-bar) {
475
475
  flex: none;
476
+ margin-bottom: calc(8px - var(--sui-focus-ring-width));
476
477
  }
477
478
  .combobox-inner :global(.sui.listbox) {
478
479
  flex: auto;
@@ -301,7 +301,7 @@
301
301
  position: absolute;
302
302
  top: 0;
303
303
  bottom: 0;
304
- margin-left: -1px;
304
+ margin-inline-start: -1px;
305
305
  border-radius: 1px;
306
306
  width: 4px;
307
307
  background-color: var(--sui-primary-accent-color);
@@ -4,10 +4,6 @@
4
4
  * guaranteed to be compatible with the matching engine.
5
5
  */
6
6
  export const SHIKI_VERSION: "4.4.3";
7
- /**
8
- * Version of this package, used to resolve the prebuilt Shiki engine chunk from a CDN.
9
- */
10
- export const UI_VERSION: "0.68.3";
11
7
  /**
12
8
  * Available syntax highlighting languages, sorted by display name.
13
9
  * @type {{ id: string, name: string, aliases?: string[] }[]}
@@ -7,11 +7,6 @@
7
7
  */
8
8
  export const SHIKI_VERSION = "4.4.3";
9
9
 
10
- /**
11
- * Version of this package, used to resolve the prebuilt Shiki engine chunk from a CDN.
12
- */
13
- export const UI_VERSION = "0.68.3";
14
-
15
10
  /**
16
11
  * Available syntax highlighting languages, sorted by display name.
17
12
  * @type {{ id: string, name: string, aliases?: string[] }[]}
@@ -1,4 +1,5 @@
1
- import { SHIKI_VERSION, UI_VERSION } from './generated.js';
1
+ import { SHIKI_VERSION } from './generated.js';
2
+ import { UI_VERSION } from './version.js';
2
3
 
3
4
  /**
4
5
  * @import { CodeHighlighterLoaders } from '../../../typedefs';
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Version of this package, used to resolve the prebuilt Shiki engine chunk from a CDN.
3
+ */
4
+ export const UI_VERSION: "0.69.1";
@@ -0,0 +1,6 @@
1
+ // Generated by `scripts/generate-shiki-metadata.js`. DO NOT EDIT.
2
+
3
+ /**
4
+ * Version of this package, used to resolve the prebuilt Shiki engine chunk from a CDN.
5
+ */
6
+ export const UI_VERSION = '0.69.1';
@@ -0,0 +1,116 @@
1
+ # Dialog action button labels
2
+ ok: تأیید
3
+ cancel: لغو
4
+ close: بستن
5
+
6
+ # Button to clear content, e.g. search input or calendar date
7
+ clear: پاک کردن
8
+
9
+ # Text editor dialog buttons for link/image insertion
10
+ insert: درج
11
+ update: به‌روزرسانی
12
+ remove: حذف
13
+
14
+ # Combobox dropdown toggle button aria-labels
15
+ collapse: جمع کردن
16
+ expand: باز کردن
17
+
18
+ # Infobar/toast dismiss button label
19
+ dismiss: بستن
20
+
21
+ # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
+ emoji_suggestions: پیشنهادهای ایموجی
23
+
24
+ # Calendar component
25
+ calendar:
26
+ # View switcher group aria-labels and navigation button aria-labels
27
+ year: سال
28
+ previous_decade: دهه قبل
29
+ next_decade: دهه بعد
30
+ month: ماه
31
+ previous_month: ماه قبل
32
+ next_month: ماه بعد
33
+ # “Today” button label in footer
34
+ today: امروز
35
+
36
+ # Split button component
37
+ split_button:
38
+ # Wrapper aria-label, e.g. “Save Options” when primary button is “Save”
39
+ x_options: 'گزینه‌های {$name}'
40
+ # Dropdown toggle aria-label
41
+ more_options: گزینه‌های بیشتر
42
+
43
+ # Combobox component
44
+ combobox:
45
+ # Placeholder when no option is selected
46
+ select_an_option: یک گزینه را انتخاب کنید…
47
+ # Filter input aria-label
48
+ filter_options: فیلتر کردن گزینه‌ها
49
+ # Empty state message when filter has no matches
50
+ no_matching_options: هیچ گزینهٔ منطبقی پیدا نشد
51
+
52
+ # Number input component
53
+ number_input:
54
+ # Spin button aria-labels for incrementing/decrementing the number value
55
+ increase: افزایش
56
+ decrease: کاهش
57
+
58
+ # Password input component
59
+ password_input:
60
+ # Visibility toggle button aria-labels
61
+ show_password: نمایش گذرواژه
62
+ hide_password: پنهان کردن گذرواژه
63
+
64
+ # Secret input component (API keys, tokens, etc.)
65
+ secret_input:
66
+ # Visibility toggle button aria-labels
67
+ show_secret: نمایش عبارت محرمانه
68
+ hide_secret: پنهان کردن عبارت محرمانه
69
+
70
+ # Select tags component (multi-select)
71
+ select_tags:
72
+ # Listbox aria-label
73
+ selected_options: گزینه‌های انتخاب‌شده
74
+ # Remove button aria-label, e.g. “Remove Option 1”
75
+ remove_x: 'حذف {$name}'
76
+
77
+ # Text editor component
78
+ text_editor:
79
+ # Toolbar aria-labels
80
+ text_editor: ویرایشگر متن
81
+ code_editor: ویرایشگر کد
82
+ # Block style menu button and menu aria-labels
83
+ text_style_options: گزینه‌های سبک متن
84
+ show_text_style_options: نمایش گزینه‌های سبک متن
85
+ # Block style menu items
86
+ paragraph: پاراگراف
87
+ heading_1: سرتیتر ۱
88
+ heading_2: سرتیتر ۲
89
+ heading_3: سرتیتر ۳
90
+ heading_4: سرتیتر ۴
91
+ heading_5: سرتیتر ۵
92
+ heading_6: سرتیتر ۶
93
+ bulleted_list: فهرست نشانه‌دار
94
+ numbered_list: فهرست شماره‌دار
95
+ blockquote: نقل‌قول
96
+ code_block: بلوک کد
97
+ # Inline style button aria-labels
98
+ bold: ضخیم
99
+ italic: مورب
100
+ strikethrough: خط‌خورده
101
+ code: کد
102
+ link: پیوند
103
+ # Link dialog title
104
+ insert_link: درج پیوند
105
+ update_link: به‌روزرسانی پیوند
106
+ # Link dialog input field labels
107
+ text: متن
108
+ url: آدرس (URL)
109
+ # Markdown mode toggle button aria-label
110
+ edit_in_markdown: ویرایش در حالت مارک‌داون
111
+ # Error message when rich text conversion fails
112
+ converter_error: امکان فعال‌سازی حالت متن غنی وجود ندارد. لطفاً در عوض از ویرایشگر متن ساده استفاده کنید.
113
+ # Language selector aria-label
114
+ language: زبان
115
+ # Plain text mode option in language selector
116
+ plain_text: متن ساده
@@ -1,3 +1,4 @@
1
+ import { isRTL } from '@sveltia/i18n';
1
2
  import { generateElementId } from '@sveltia/utils/element';
2
3
  import { sleep } from '@sveltia/utils/misc';
3
4
  import { on } from 'svelte/events';
@@ -305,7 +306,23 @@ class Popup {
305
306
  intersectionRect.width = Math.max(0, intersectionRect.right - intersectionRect.left);
306
307
  intersectionRect.height = Math.max(0, intersectionRect.bottom - intersectionRect.top);
307
308
 
309
+ // Measure the content at its natural size, with any limit previously applied here taken off
310
+ // first. A popup that delegates its scrolling to a child — the combobox hands it to the option
311
+ // list, so the filter stays put — reports a `scrollHeight` no larger than the `max-height` it’s
312
+ // already capped at, and the same goes for `scrollWidth` against `max-width`. Measuring those
313
+ // clipped values would make the cap stick: once the popup had shrunk to fit a small viewport,
314
+ // it could never grow back when the viewport did. The properties are put back synchronously,
315
+ // before the browser can paint, so nothing flickers.
316
+ const { maxHeight: appliedMaxHeight, maxWidth: appliedMaxWidth } = content.style;
317
+
318
+ content.style.maxHeight = '';
319
+ content.style.maxWidth = '';
320
+
308
321
  const { scrollHeight: contentHeight, scrollWidth: contentWidth } = content;
322
+
323
+ content.style.maxHeight = appliedMaxHeight;
324
+ content.style.maxWidth = appliedMaxWidth;
325
+
309
326
  const topMargin = intersectionRect.top - 8;
310
327
  const bottomMargin = rootBounds.height - intersectionRect.bottom - 8;
311
328
  let { position } = this;
@@ -313,7 +330,7 @@ class Popup {
313
330
 
314
331
  // Normalize RTL-friendly positions to LTR for LTR documents
315
332
  // @todo Rename `PopupPosition` enums to be direction-agnostic
316
- if (document.dir === 'rtl') {
333
+ if (isRTL()) {
317
334
  if (position.endsWith('-left')) {
318
335
  position = /** @type {PopupPosition} */ (position.replace('-left', '-right'));
319
336
  } else if (position.endsWith('-right')) {
@@ -384,7 +401,10 @@ class Popup {
384
401
  maxWidth: position.endsWith('-left')
385
402
  ? `${Math.round(rootBounds.width - intersectionRect.left - 8)}px`
386
403
  : `${Math.round(intersectionRect.right - 8)}px`,
387
- height: height ? `${Math.round(height)}px` : 'auto',
404
+ // `undefined` removes the `max-height` the popup is given, letting it take its natural size
405
+ // again. `auto` would look equivalent but isn’t a valid `max-height`, so the browser would
406
+ // drop it and leave whatever limit was applied last in place.
407
+ height: height ? `${Math.round(height)}px` : undefined,
388
408
  };
389
409
 
390
410
  if (
@@ -58,6 +58,12 @@ export type ButtonProps = {
58
58
  * Text label displayed on the button.
59
59
  */
60
60
  label?: string | undefined;
61
+ /**
62
+ * The `dir` attribute on the label element.
63
+ * Use `auto` to isolate a user-authored label whose text direction is unknown, so it cannot
64
+ * be reordered by the surrounding UI direction.
65
+ */
66
+ labelDir?: "ltr" | "rtl" | "auto" | undefined;
61
67
  /**
62
68
  * Number of lines to show the label. Overflowing text will be truncated.
63
69
  */
@@ -331,6 +337,12 @@ export type MenuItemProps = {
331
337
  * Text label displayed on the item.
332
338
  */
333
339
  label?: string | undefined;
340
+ /**
341
+ * The `dir` attribute on the label element.
342
+ * Use `auto` to isolate a user-authored label whose text direction is unknown, so it cannot
343
+ * be reordered by the surrounding UI direction.
344
+ */
345
+ labelDir?: "ltr" | "rtl" | "auto" | undefined;
334
346
  /**
335
347
  * Primary slot content.
336
348
  */
package/dist/typedefs.js CHANGED
@@ -26,6 +26,9 @@
26
26
  * attribute. Accepts the special `Accel` key, which will be replaced with `Control` or `Meta`
27
27
  * depending on the user’s operating system.
28
28
  * @property {string} [label] Text label displayed on the button.
29
+ * @property {'ltr' | 'rtl' | 'auto'} [labelDir] The `dir` attribute on the label element.
30
+ * Use `auto` to isolate a user-authored label whose text direction is unknown, so it cannot
31
+ * be reordered by the surrounding UI direction.
29
32
  * @property {number} [lines] Number of lines to show the label. Overflowing text will be truncated.
30
33
  * @property {'primary' | 'secondary' | 'tertiary' | 'ghost' | 'link'} [variant] The style variant
31
34
  * of the button.
@@ -119,6 +122,9 @@
119
122
  * @property {boolean} [checked] Whether to check the widget. An alias of the `aria-checked`
120
123
  * attribute.
121
124
  * @property {string} [label] Text label displayed on the item.
125
+ * @property {'ltr' | 'rtl' | 'auto'} [labelDir] The `dir` attribute on the label element.
126
+ * Use `auto` to isolate a user-authored label whose text direction is unknown, so it cannot
127
+ * be reordered by the surrounding UI direction.
122
128
  * @property {Snippet} [children] Primary slot content.
123
129
  * @property {Snippet} [startIcon] Start icon slot content.
124
130
  * @property {Snippet} [endIcon] End icon slot content.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltia/ui",
3
- "version": "0.68.3",
3
+ "version": "0.69.1",
4
4
  "description": "A collection of Svelte components and utilities for building user interfaces.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -57,17 +57,17 @@
57
57
  "@sveltejs/package": "^2.5.8",
58
58
  "@sveltejs/vite-plugin-svelte": "^7.3.0",
59
59
  "@vitest/coverage-v8": "^4.1.11",
60
- "cspell": "^10.1.1",
60
+ "cspell": "^10.2.0",
61
61
  "eslint": "^9.39.5",
62
62
  "eslint-config-airbnb-extended": "^3.2.0",
63
63
  "eslint-config-prettier": "^10.1.8",
64
64
  "eslint-plugin-import": "^2.32.0",
65
- "eslint-plugin-jsdoc": "^64.2.1",
66
- "eslint-plugin-package-json": "^1.7.1",
65
+ "eslint-plugin-jsdoc": "^64.3.3",
66
+ "eslint-plugin-package-json": "^1.8.0",
67
67
  "eslint-plugin-svelte": "^3.23.0",
68
- "globals": "^17.11.0",
69
- "happy-dom": "^20.11.8",
70
- "oxlint": "^1.80.0",
68
+ "globals": "^17.12.0",
69
+ "happy-dom": "^20.12.0",
70
+ "oxlint": "^1.81.0",
71
71
  "postcss": "^8.5.26",
72
72
  "postcss-html": "^2.0.0",
73
73
  "prettier": "^3.9.6",
@@ -78,7 +78,7 @@
78
78
  "stylelint": "^17.14.1",
79
79
  "stylelint-config-recommended-scss": "^17.0.1",
80
80
  "stylelint-scss": "^7.2.0",
81
- "svelte": "^5.56.10",
81
+ "svelte": "^5.57.0",
82
82
  "svelte-check": "^4.7.6",
83
83
  "svelte-preprocess": "^6.0.5",
84
84
  "tslib": "^2.8.1",