@v1nt1248/3nclient-lib 0.3.48 → 0.3.50

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 (35) hide show
  1. package/README.md +44 -1
  2. package/dist/chunks/{plugins-keys-CmrMlx3F.js → plugins-keys-DdadrIAg.js} +84 -77
  3. package/dist/chunks/ui3n-notification-o0tuhTpO.js +272 -0
  4. package/dist/mixins.scss +0 -23
  5. package/dist/src/components/ui3n-autocomplete/types.d.ts +12 -0
  6. package/dist/src/components/ui3n-input/ui3n-input.d.ts +2 -2
  7. package/dist/src/components/ui3n-notification/types.d.ts +5 -0
  8. package/dist/src/components/ui3n-notification/ui3n-notification.d.ts +1 -0
  9. package/dist/src/components/ui3n-text/ui3n-text.d.ts +2 -2
  10. package/dist/src/components/ui3n-tooltip/ui3n-tooltip.d.ts +1 -1
  11. package/dist/src/constants/plugins-keys.d.ts +2 -0
  12. package/dist/src/directives/ui3n-ripple.d.ts +2 -1
  13. package/dist/src/directives/ui3n-title.d.ts +1 -1
  14. package/dist/src/plugins/index.d.ts +4 -1
  15. package/dist/src/plugins/theme/store-theme.d.ts +4 -0
  16. package/dist/src/plugins/theme/theme.d.ts +10 -0
  17. package/dist/src/plugins/theme/types.d.ts +12 -0
  18. package/dist/src/ui3n-plugins.d.ts +5 -3
  19. package/dist/src/utils/index.d.ts +1 -0
  20. package/dist/src/utils/ui/to-css-length.d.ts +1 -0
  21. package/dist/style.css +1 -1
  22. package/dist/ui3n-components.js +1239 -1199
  23. package/dist/ui3n-plugins.js +83 -34
  24. package/dist/ui3n-utils.js +4 -4
  25. package/dist/variables.css +5 -91
  26. package/package.json +1 -1
  27. package/src/components/ui3n-autocomplete/types.ts +12 -0
  28. package/src/components/ui3n-autocomplete/ui3n-autocomplete.vue +49 -7
  29. package/src/components/ui3n-checkbox/ui3n-checkbox.vue +6 -9
  30. package/src/components/ui3n-notification/types.ts +5 -0
  31. package/src/components/ui3n-notification/ui3n-notification.vue +38 -16
  32. package/src/components/ui3n-radio-group/ui3n-radio.vue +9 -6
  33. package/src/components/ui3n-switch/ui3n-switch.vue +2 -1
  34. package/src/components/ui3n-tabs/ui3n-tabs.vue +0 -3
  35. package/dist/chunks/ui3n-notification-DPC5Ke4b.js +0 -278
@@ -1,35 +1,35 @@
1
- import { B as e, n as t, r as n, t as r } from "./chunks/plugins-keys-CmrMlx3F.js";
2
- import { i, t as a } from "./chunks/ui3n-notification-DPC5Ke4b.js";
3
- import { Fragment as o, createApp as s, createBlock as c, createElementBlock as l, defineComponent as u, markRaw as d, mergeProps as f, normalizeClass as p, openBlock as m, ref as h, renderList as g } from "vue";
1
+ import { H as e, i as t, n, r, t as i } from "./chunks/plugins-keys-DdadrIAg.js";
2
+ import { i as a, t as o } from "./chunks/ui3n-notification-o0tuhTpO.js";
3
+ import { Fragment as s, createApp as c, createBlock as l, createElementBlock as u, defineComponent as d, markRaw as f, mergeProps as p, normalizeClass as m, openBlock as h, ref as g, renderList as _ } from "vue";
4
4
  import "pinia";
5
- import _ from "mitt";
6
- var v = /* @__PURE__ */ i(/* @__PURE__ */ u({
5
+ import v from "mitt";
6
+ var y = /* @__PURE__ */ a(/* @__PURE__ */ d({
7
7
  __name: "ui3n-notification-container",
8
8
  setup(e, { expose: t }) {
9
- let n = h([]);
9
+ let n = g([]);
10
10
  function r(e) {
11
11
  n.value.push(e);
12
12
  }
13
13
  function i(e) {
14
14
  n.value = n.value.filter((t) => t.id !== e);
15
15
  }
16
- function s(e) {
16
+ function a(e) {
17
17
  e.onClose && e.onClose(), i(e.id);
18
18
  }
19
19
  return t({
20
20
  add: r,
21
21
  remove: i
22
- }), (e, t) => (m(), l("div", {
22
+ }), (e, t) => (h(), u("div", {
23
23
  id: "ui3n-notifications-container",
24
- class: p(e.$style.ui3nNotificationsWrapper)
25
- }, [(m(!0), l(o, null, g(n.value, (e) => (m(), c(a, f({ key: e.id }, { ref_for: !0 }, e, { "on-close": () => s(e) }), null, 16, ["on-close"]))), 128))], 2));
24
+ class: m(e.$style.ui3nNotificationsWrapper)
25
+ }, [(h(!0), u(s, null, _(n.value, (e) => (h(), l(o, p({ key: e.id }, { ref_for: !0 }, e, { "on-close": () => a(e) }), null, 16, ["on-close"]))), 128))], 2));
26
26
  }
27
- }), [["__cssModules", { $style: { ui3nNotificationsWrapper: "_ui3nNotificationsWrapper_1vwg2_1" } }]]), y = { install: (n) => {
27
+ }), [["__cssModules", { $style: { ui3nNotificationsWrapper: "_ui3nNotificationsWrapper_1vwg2_1" } }]]), b = { install: (t) => {
28
28
  if (typeof window > "u") return;
29
29
  let r = document.createElement("div");
30
30
  document.body.appendChild(r);
31
- let i = s(v);
32
- i._context.provides = n._context.provides;
31
+ let i = c(y);
32
+ i._context.provides = t._context.provides;
33
33
  let a = i.mount(r), o = (t) => {
34
34
  let n = t.id || e(6), r = t.duration === void 0 ? 1500 : t.duration;
35
35
  a.add({
@@ -38,27 +38,27 @@ var v = /* @__PURE__ */ i(/* @__PURE__ */ u({
38
38
  duration: r
39
39
  });
40
40
  };
41
- n.config.globalProperties.$createNotice = o, n.provide(t, { $createNotice: o });
42
- } }, b = _(), x = {
43
- on: b.on.bind(b),
41
+ t.config.globalProperties.$createNotice = o, t.provide(n, { $createNotice: o });
42
+ } }, x = v(), S = {
43
+ on: x.on.bind(x),
44
44
  once: (e, t) => {
45
45
  function n() {
46
- b.off(e, n), t.apply(null, arguments);
46
+ x.off(e, n), t.apply(null, arguments);
47
47
  }
48
- b.on(e, n);
48
+ x.on(e, n);
49
49
  },
50
- off: b.off.bind(b),
51
- emit: b.emit.bind(b),
52
- clear: b.all.clear.bind(b)
53
- }, S = { install: (e) => {
54
- e.config.globalProperties.$emitter = x, e.provide(n, { $emitter: x });
55
- } }, C = { install(t) {
56
- let n = h([]);
57
- function i(t, r) {
50
+ off: x.off.bind(x),
51
+ emit: x.emit.bind(x),
52
+ clear: x.all.clear.bind(x)
53
+ }, C = { install: (e) => {
54
+ e.config.globalProperties.$emitter = S, e.provide(t, { $emitter: S });
55
+ } }, w = { install(t) {
56
+ let n = g([]);
57
+ function r(t, r) {
58
58
  return new Promise((i) => {
59
59
  n.value.push({
60
60
  id: e(5),
61
- component: d(t),
61
+ component: f(t),
62
62
  props: r,
63
63
  resolve: i
64
64
  });
@@ -73,31 +73,31 @@ var v = /* @__PURE__ */ i(/* @__PURE__ */ u({
73
73
  }
74
74
  t.config.globalProperties.$dialog = {
75
75
  dialogStack: n,
76
- $openDialog: i,
76
+ $openDialog: r,
77
77
  $closeDialog: a,
78
78
  $closeDialogs: o
79
- }, t.provide(r, {
79
+ }, t.provide(i, {
80
80
  dialogStack: n,
81
- $openDialog: i,
81
+ $openDialog: r,
82
82
  $closeDialog: a,
83
83
  $closeDialogs: o
84
84
  });
85
85
  } };
86
86
  //#endregion
87
87
  //#region src/plugins/notifications/store-notifications.ts
88
- function w(e) {
88
+ function T(e) {
89
89
  let { app: t = {} } = e, { config: n = {} } = t, { globalProperties: r = {} } = n, { $createNotice: i } = r;
90
90
  return { $createNotice: i };
91
91
  }
92
92
  //#endregion
93
93
  //#region src/plugins/vue-bus/store-vue-bus.ts
94
- function T(e) {
94
+ function E(e) {
95
95
  let { app: t = {} } = e, { config: n = {} } = t, { globalProperties: r = {} } = n, { $emitter: i } = r;
96
96
  return { $emitter: i };
97
97
  }
98
98
  //#endregion
99
99
  //#region src/plugins/dialogs/store-dialog.ts
100
- function E(e) {
100
+ function D(e) {
101
101
  let { app: t = {} } = e, { config: n = {} } = t, { globalProperties: r = {} } = n, { $dialog: i } = r;
102
102
  return { $dialogs: {
103
103
  open: i.$openDialog,
@@ -107,4 +107,53 @@ function E(e) {
107
107
  } };
108
108
  }
109
109
  //#endregion
110
- export { r as DIALOGS_KEY, t as NOTIFICATIONS_KEY, n as VUEBUS_KEY, C as dialogs, y as notifications, E as storeDialogs, w as storeNotifications, T as storeVueBus, S as vueBus };
110
+ //#region src/plugins/theme/theme.ts
111
+ var O = [
112
+ "light",
113
+ "dark",
114
+ "midnight"
115
+ ], k = [
116
+ "light-theme",
117
+ "dark-theme",
118
+ "midnight-theme"
119
+ ];
120
+ function A(e) {
121
+ return typeof e == "string" && O.includes(e);
122
+ }
123
+ function j(e, t) {
124
+ e.classList.add("colors");
125
+ for (let t of k) e.classList.remove(t);
126
+ e.classList.add(`${t}-theme`);
127
+ }
128
+ function M(e) {
129
+ if (e.persist) {
130
+ let t = e.storageKey ?? "ui3n-theme";
131
+ try {
132
+ let e = localStorage.getItem(t);
133
+ if (A(e)) return e;
134
+ } catch {}
135
+ }
136
+ return A(e.theme) ? e.theme : "light";
137
+ }
138
+ var N = { install(e, t = {}) {
139
+ let n = t.persist ?? !1, i = t.storageKey ?? "ui3n-theme", a = g(typeof document > "u" ? t.theme ?? "light" : M(t));
140
+ function o(e) {
141
+ if (A(e) && (a.value = e, !(typeof document > "u") && (j(t.target ?? document.documentElement, e), n))) try {
142
+ localStorage.setItem(i, e);
143
+ } catch {}
144
+ }
145
+ typeof document < "u" && o(a.value);
146
+ let s = {
147
+ theme: a,
148
+ setTheme: o
149
+ };
150
+ e.provide(r, s), e.config.globalProperties.$theme = s;
151
+ } };
152
+ //#endregion
153
+ //#region src/plugins/theme/store-theme.ts
154
+ function P(e) {
155
+ let { app: t = {} } = e, { config: n = {} } = t, { globalProperties: r = {} } = n, { $theme: i } = r;
156
+ return { $theme: i };
157
+ }
158
+ //#endregion
159
+ export { i as DIALOGS_KEY, n as NOTIFICATIONS_KEY, r as THEME_KEY, t as VUEBUS_KEY, w as dialogs, b as notifications, D as storeDialogs, T as storeNotifications, P as storeTheme, E as storeVueBus, N as theme, C as vueBus };
@@ -1,6 +1,6 @@
1
- import { A as e, B as t, C as n, D as r, E as i, F as a, G as o, H as s, I as c, J as l, K as u, L as d, M as f, N as p, O as m, P as h, S as g, T as _, U as v, V as y, W as b, Y as x, _ as S, a as C, b as w, c as T, d as E, f as D, g as O, h as k, i as A, j, k as M, l as N, m as P, n as F, o as I, p as L, q as R, r as z, s as B, t as V, u as H, v as U, w as W, x as G, y as K, z as q } from "./chunks/plugins-keys-CmrMlx3F.js";
2
- import { t as J } from "./chunks/emoticons-DMgiBINj.js";
1
+ import { A as e, C as t, D as n, E as r, F as i, G as a, H as o, I as s, J as c, K as l, L as u, M as d, N as f, O as p, P as m, R as h, S as g, T as _, U as v, V as y, W as b, X as x, Y as S, Z as C, _ as w, a as T, b as E, c as D, d as O, f as k, g as A, h as j, i as M, j as N, k as P, l as F, m as I, n as L, o as R, p as z, q as B, r as V, s as H, t as U, u as W, v as G, w as K, x as q, y as J, z as Y } from "./chunks/plugins-keys-DdadrIAg.js";
2
+ import { t as X } from "./chunks/emoticons-DMgiBINj.js";
3
3
  //#region src/constants/general.ts
4
- var Y = /[^@]+@[^@]+\.[^@]+/iu;
4
+ var Z = /[^@]+@[^@]+\.[^@]+/iu;
5
5
  //#endregion
6
- export { V as DIALOGS_KEY, F as NOTIFICATIONS_KEY, b as NamedProcs, A as SQLiteOn3NStorage, o as SingleCyclicProc, u as SingleProc, s as TaskRunner, z as VUEBUS_KEY, D as b64ToBlob, E as blobFromDataURL, L as blobToB64, K as capitalize, f as copyToClipboard, B as createVideoThumbnail, M as debounce, x as defer, J as emoticons, j as executeFunc, T as fileToUint8Array, U as formatFileSize, n as generateColor, p as getDeliveryErrors, d as getFileExtension, t as getRandomId, W as hasSlotContent, G as html2text, g as invertColor, P as isFileArchive, k as isFileAudio, S as isFileImage, O as isFileVideo, Y as mailReg, R as makeSyncedFunc, _ as markSearch, c as mimeTypes, q as patchTextareaMaxRowsSupport, w as prepareDateAsSting, e as removeWhitespaceInString, N as resizeImage, y as round, v as schedulerYield, i as selectAll, r as selectEnd, m as selectStart, l as sleep, h as transformFileToWeb3NFile, a as transformWeb3nFileToFile, C as tryOnScopeDispose, H as uint8ToDataURL, I as unrefElement };
6
+ export { U as DIALOGS_KEY, L as NOTIFICATIONS_KEY, l as NamedProcs, T as SQLiteOn3NStorage, B as SingleCyclicProc, c as SingleProc, V as THEME_KEY, b as TaskRunner, M as VUEBUS_KEY, z as b64ToBlob, k as blobFromDataURL, I as blobToB64, q as capitalize, m as copyToClipboard, D as createVideoThumbnail, N as debounce, C as defer, X as emoticons, f as executeFunc, F as fileToUint8Array, J as formatFileSize, _ as generateColor, i as getDeliveryErrors, Y as getFileExtension, o as getRandomId, r as hasSlotContent, t as html2text, K as invertColor, j as isFileArchive, A as isFileAudio, G as isFileImage, w as isFileVideo, Z as mailReg, S as makeSyncedFunc, n as markSearch, h as mimeTypes, y as patchTextareaMaxRowsSupport, g as prepareDateAsSting, d as removeWhitespaceInString, W as resizeImage, v as round, a as schedulerYield, p as selectAll, P as selectEnd, e as selectStart, x as sleep, E as toCssLength, s as transformFileToWeb3NFile, u as transformWeb3nFileToFile, R as tryOnScopeDispose, O as uint8ToDataURL, H as unrefElement };
@@ -123,6 +123,8 @@
123
123
 
124
124
  }
125
125
 
126
+ :root,
127
+ .light-theme,
126
128
  .default-theme {
127
129
  --ripple: var(--white-48);
128
130
  --shadow-key-1: var(--black-12);
@@ -290,7 +292,7 @@
290
292
  --info-outline-disabled: var(--blue-5);
291
293
  }
292
294
 
293
- .dark-theme {
295
+ .midnight-theme {
294
296
  --ripple: var(--black-48);
295
297
  --shadow-key-1: var(--white-12);
296
298
  --shadow-key-2: var(--white-8);
@@ -457,7 +459,7 @@
457
459
  --info-outline-disabled: var(--blue-85);
458
460
  }
459
461
 
460
- .dark2-theme {
462
+ .dark-theme {
461
463
  --ripple: var(--black-48);
462
464
  --shadow-key-1: var(--white-12);
463
465
  --shadow-key-2: var(--white-8);
@@ -624,6 +626,7 @@
624
626
  --info-outline-disabled: var(--blue-85);
625
627
  }
626
628
 
629
+ :root,
627
630
  .colors {
628
631
  --color-bg-button-primary-default: var(--accent-fill-default);
629
632
  --color-bg-button-primary-hover: var(--accent-fill-hover);
@@ -930,92 +933,3 @@
930
933
  --color-icon-chat-bubble-other-selected: var(--accent-content-selected);
931
934
  --effect-dropdown-shadow: 0 0 4px 0 var(--shadow-close), 0 4px 12px 0 var(--shadow-far);
932
935
  }
933
-
934
- html {
935
- overflow: hidden;
936
- font-family: Inter, system-ui, sans-serif;
937
- }
938
-
939
- section,
940
- div {
941
- box-sizing: border-box;
942
- }
943
-
944
- ::-webkit-scrollbar-button {
945
- background-image: url("");
946
- background-repeat: no-repeat;
947
- width: var(--spacing-xs);
948
- height: 0;
949
- }
950
-
951
- ::-webkit-scrollbar-track {
952
- background-color: transparent;
953
- }
954
-
955
- ::-webkit-scrollbar-thumb {
956
- border-radius: 4px;
957
- height: 50px;
958
- background-color: var(--default-fill-pressed);
959
- }
960
-
961
- ::-webkit-scrollbar-thumb:hover {
962
- background-color: var(--t-default-fill-default);
963
- }
964
-
965
- ::-webkit-resizer {
966
- background-image: url("");
967
- background-repeat: no-repeat;
968
- width: var(--spacing-xs);
969
- height: 0;
970
- }
971
-
972
- ::-webkit-scrollbar {
973
- width: 5px;
974
- }
975
-
976
- /* other CSS style classes */
977
- .fade-enter-active,
978
- .fade-leave-active {
979
- transition: opacity 0.15s ease;
980
- }
981
-
982
- .fade-enter,
983
- .fade-leave-active {
984
- opacity: 0;
985
- }
986
-
987
- @keyframes ripple {
988
- to {
989
- transform: scale(4);
990
- opacity: 0;
991
- }
992
- }
993
-
994
- .ui3n-ripple {
995
- --ui3n-ripple-duration: 400ms;
996
- --ui3n-ripple-bg-color: var(--ripple);
997
-
998
- position: absolute;
999
- border-radius: 50%;
1000
- transform: scale(0);
1001
- animation: ripple var(--ui3n-ripple-duration) linear;
1002
- background-color: var(--ui3n-ripple-bg-color);
1003
- }
1004
-
1005
- .ui3n-title {
1006
- position: fixed;
1007
- width: max-content;
1008
- top: 0;
1009
- left: 0;
1010
- padding: var(--spacing-xs) var(--spacing-s);
1011
- border-radius: var(--spacing-xs);
1012
- font-size: var(--font-11);
1013
- line-height: var(--font-12);
1014
- font-weight: 400;
1015
- overflow-wrap: break-word;
1016
- white-space: break-spaces;
1017
- box-shadow: 0 2px 1px -1px var(--shadow-key-1),
1018
- 0 1px 1px 0 var(--shadow-key-2),
1019
- 0 1px 3px 0 var(--shadow-key-3);
1020
- z-index: 1000;
1021
- }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@v1nt1248/3nclient-lib",
3
3
  "license": "AGPL-3.0-or-later",
4
4
  "author": "v1nt1248",
5
- "version": "0.3.48",
5
+ "version": "0.3.50",
6
6
  "description": "Library for 3NWeb clients",
7
7
  "type": "module",
8
8
  "files": [
@@ -48,6 +48,18 @@ export interface Ui3nAutocompleteProps<T extends Ui3nAutocompleteOptionBase> {
48
48
  * @default false
49
49
  */
50
50
  disabled?: boolean;
51
+ /**
52
+ * Whether an individual item cannot be picked.
53
+ *
54
+ * A disabled item is still listed, greyed out and inert to both the pointer
55
+ * and the keyboard. Use it when leaving the item out would be worse than
56
+ * showing it: an absence explains nothing, while a disabled row - with a
57
+ * reason rendered through the `item` slot - does.
58
+ *
59
+ * A predicate rather than a flag on the item itself, so that a caller can
60
+ * answer from state of its own without copying or mutating its data.
61
+ */
62
+ itemDisabled?: (item: T) => boolean;
51
63
  /**
52
64
  * Filter keys
53
65
  */
@@ -81,6 +81,33 @@
81
81
  });
82
82
  });
83
83
 
84
+ /**
85
+ * Whether this item is listed but cannot be picked.
86
+ *
87
+ * Asked in one place, because the pointer and the keyboard have to agree: an
88
+ * item that cannot be clicked must not be reachable with arrows and Enter
89
+ * either.
90
+ */
91
+ function isItemDisabled(item: T | undefined): boolean {
92
+ return !!item && !!props.itemDisabled?.(item);
93
+ }
94
+
95
+ /**
96
+ * Index of the nearest item that can be picked, looking from `from` in the
97
+ * direction of `step`.
98
+ *
99
+ * @returns null when there is none that way, so that the caller can leave the
100
+ * highlight where it is rather than moving it onto a dead row.
101
+ */
102
+ function nearestEnabledIndex(from: number, step: 1 | -1): number | null {
103
+ for (let i = from; (i >= 0) && (i < size(filteredItems.value)); i += step) {
104
+ if (!isItemDisabled(filteredItems.value[i])) {
105
+ return i;
106
+ }
107
+ }
108
+ return null;
109
+ }
110
+
84
111
  function onInput() {
85
112
  isLastChipHighlighted.value = false;
86
113
  emits('update:search', query.value);
@@ -146,7 +173,7 @@
146
173
  }
147
174
 
148
175
  function onItemClick(item: T) {
149
- if (props.disabled) return;
176
+ if (props.disabled || isItemDisabled(item)) return;
150
177
 
151
178
  if (!props.multiple) {
152
179
  const newValue = props.returnObject ? [item] : [item[props.itemValue]];
@@ -183,25 +210,33 @@
183
210
 
184
211
  function handlePressingDownKey() {
185
212
  if (activeItemsIndex.value === null) {
186
- activeItemsIndex.value = 0;
213
+ activeItemsIndex.value = nearestEnabledIndex(0, 1);
187
214
  menuBodyEl.value && menuBodyEl.value.focus({ preventScroll: true });
188
215
  return;
189
216
  }
190
217
 
191
218
  if (activeItemsIndex.value >= 0 && activeItemsIndex.value < size(filteredItems.value) - 1) {
192
- activeItemsIndex.value += 1;
219
+ // Past the disabled ones rather than onto them: the highlight stays put
220
+ // when everything below cannot be picked.
221
+ const next = nearestEnabledIndex(activeItemsIndex.value + 1, 1);
222
+ if (next !== null) {
223
+ activeItemsIndex.value = next;
224
+ }
193
225
  }
194
226
  }
195
227
 
196
228
  function handlePressingUpKey() {
197
229
  if (activeItemsIndex.value === null) {
198
- activeItemsIndex.value = size(filteredItems.value) - 1;
230
+ activeItemsIndex.value = nearestEnabledIndex(size(filteredItems.value) - 1, -1);
199
231
  menuBodyEl.value && menuBodyEl.value.focus({ preventScroll: true });
200
232
  return;
201
233
  }
202
234
 
203
235
  if (activeItemsIndex.value > 0 && activeItemsIndex.value < size(filteredItems.value)) {
204
- activeItemsIndex.value -= 1;
236
+ const previous = nearestEnabledIndex(activeItemsIndex.value - 1, -1);
237
+ if (previous !== null) {
238
+ activeItemsIndex.value = previous;
239
+ }
205
240
  }
206
241
  }
207
242
 
@@ -228,6 +263,12 @@
228
263
  function handlePressingEnterKey() {
229
264
  if (activeItemsIndex.value !== null) {
230
265
  const item = filteredItems.value[activeItemsIndex.value!];
266
+ // Nothing happens on a disabled item, and nothing is cleared either: the
267
+ // query and the highlight are the user's place in the list, and taking
268
+ // them away would read as though the item had been taken.
269
+ if (isItemDisabled(item)) {
270
+ return;
271
+ }
231
272
  onItemClick(item);
232
273
  activeItemsIndex.value = null;
233
274
  props.clearOnSelect && (query.value = '');
@@ -241,7 +282,7 @@
241
282
 
242
283
  if (!isMenuOpen.value) {
243
284
  isMenuOpen.value = true;
244
- activeItemsIndex.value = 0;
285
+ activeItemsIndex.value = nearestEnabledIndex(0, 1);
245
286
  menuBodyEl.value && menuBodyEl.value.focus({ preventScroll: true });
246
287
  }
247
288
  }
@@ -467,8 +508,9 @@
467
508
  :class="[
468
509
  $style.item,
469
510
  activeItemsIndex === index && $style.itemSelected,
470
- disabled && $style.itemDisabled,
511
+ (disabled || isItemDisabled(item)) && $style.itemDisabled,
471
512
  ]"
513
+ :aria-disabled="disabled || isItemDisabled(item)"
472
514
  @mousedown="onItemMouseDown"
473
515
  @click.stop.prevent="onItemClick(item)"
474
516
  >
@@ -1,6 +1,7 @@
1
1
  <script lang="ts" setup>
2
2
  import { computed, onBeforeMount, ref, useCssModule, useSlots, watch } from 'vue';
3
3
  import Ui3nRipple from '../../directives/ui3n-ripple';
4
+ import { toCssLength } from '../../utils/ui/to-css-length';
4
5
  import type {
5
6
  Ui3nCheckboxEmits,
6
7
  Ui3nCheckboxExpose,
@@ -52,7 +53,7 @@
52
53
  });
53
54
 
54
55
  const inlineStyles = computed(() => ({
55
- '--ui3n-checkbox-size': typeof props.size === 'number' ? `${props.size}px` : props.size,
56
+ '--ui3n-checkbox-size': toCssLength(props.size),
56
57
  '--ui3n-checkbox-color': props.color,
57
58
  }));
58
59
 
@@ -205,8 +206,6 @@
205
206
  </template>
206
207
 
207
208
  <style lang="scss" module>
208
- @use '../../assets/styles/mixins' as mixins;
209
-
210
209
  .ui3nCheckbox {
211
210
  --ui3n-checkbox-size: 16px;
212
211
  --ui3n-checkbox-gap: 4px;
@@ -248,17 +247,15 @@
248
247
  background-color: var(--ui3n-checkbox-color);
249
248
 
250
249
  &:hover {
251
- border-color: oklch(from var(--ui3n-checkbox-color) calc(l - 0.1) c h);
252
- background-color: oklch(from var(--ui3n-checkbox-color) calc(l - 0.1) c h);
253
- @include mixins.ripple(oklch(from var(--ui3n-checkbox-color) calc(l - 0.1) c h));
250
+ border-color: color-mix(in oklch, var(--ui3n-checkbox-color), black 12%);
251
+ background-color: color-mix(in oklch, var(--ui3n-checkbox-color), black 12%);
254
252
  }
255
253
  }
256
254
 
257
255
  .unfilled {
258
256
  &:hover {
259
- border-color: oklch(from var(--ui3n-checkbox-color) calc(l - 0.1) c h);
260
- background-color: oklch(from transparent calc(l - 0.1) c h);
261
- @include mixins.ripple(oklch(from transparent calc(l - 0.1) c h));
257
+ border-color: color-mix(in oklch, var(--ui3n-checkbox-color) 84%, black);
258
+ background-color: color-mix(in oklch, var(--ui3n-checkbox-color) 16%, transparent);
262
259
  }
263
260
  }
264
261
 
@@ -24,6 +24,11 @@ export interface Ui3nNotificationProps {
24
24
  * @default false
25
25
  */
26
26
  withIcon?: boolean;
27
+ /**
28
+ * Notification border radius in pixels or css length
29
+ * @default 8
30
+ */
31
+ borderRadius?: number | string;
27
32
  /**
28
33
  * Called when notification opens
29
34
  */