@marianmeres/stuic 2.14.0 → 2.17.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.
@@ -5,7 +5,7 @@
5
5
  /** Optional string for color hash calculation (e.g., email, user ID). Falls back to `input` */
6
6
  hashSource?: string;
7
7
  /** Size preset or custom Tailwind size class */
8
- size?: "sm" | "md" | "lg" | string;
8
+ size?: "sm" | "md" | "lg" | "xl" | string;
9
9
  /** Click handler - when provided, renders as a button */
10
10
  onclick?: (event: MouseEvent) => void;
11
11
  /** Background color (Tailwind class). Ignored if autoColor=true */
@@ -41,6 +41,7 @@
41
41
  sm: "size-8 text-xs",
42
42
  md: "size-10 text-sm",
43
43
  lg: "size-14 text-base",
44
+ xl: "size-16 text-lg",
44
45
  };
45
46
 
46
47
  let initials = $derived.by(() => {
@@ -52,7 +53,7 @@
52
53
  if (_input.includes("@")) {
53
54
  const username = _input.split("@")[0];
54
55
  // Split by common separators (., _, -)
55
- const parts = username.split(/[._-]/).filter(Boolean);
56
+ const parts = username.split(/[._+-]/).filter(Boolean);
56
57
  if (parts.length > 1) {
57
58
  _input = parts.map((p) => p.charAt(0)).join("");
58
59
  } else {
@@ -4,7 +4,7 @@ export interface Props {
4
4
  /** Optional string for color hash calculation (e.g., email, user ID). Falls back to `input` */
5
5
  hashSource?: string;
6
6
  /** Size preset or custom Tailwind size class */
7
- size?: "sm" | "md" | "lg" | string;
7
+ size?: "sm" | "md" | "lg" | "xl" | string;
8
8
  /** Click handler - when provided, renders as a button */
9
9
  onclick?: (event: MouseEvent) => void;
10
10
  /** Background color (Tailwind class). Ignored if autoColor=true */
@@ -159,8 +159,8 @@
159
159
  onOpen?: () => void;
160
160
  /** Called when menu closes */
161
161
  onClose?: () => void;
162
- /** Called when any action item is selected */
163
- onSelect?: (item: DropdownMenuActionItem) => void;
162
+ /** Called when any action item is selected (fallback if item has no onSelect) */
163
+ onSelect?: (item: DropdownMenuActionItem) => void | boolean;
164
164
  /** Reference to trigger element */
165
165
  triggerEl?: HTMLButtonElement;
166
166
  /** Reference to dropdown element */
@@ -213,7 +213,7 @@
213
213
  bg-white dark:bg-neutral-800
214
214
  text-neutral-900 dark:text-neutral-100
215
215
  border border-neutral-200 dark:border-neutral-700
216
- rounded-md shadow-lg
216
+ rounded-md shadow-sm
217
217
  p-1
218
218
  overflow-y-auto
219
219
  z-50
@@ -299,7 +299,7 @@
299
299
  let wrapperEl: HTMLDivElement = $state()!;
300
300
  let activeItemEl: HTMLButtonElement | undefined = $state();
301
301
  const reducedMotion = prefersReducedMotion();
302
- const isSupported = !forceFallback && isAnchorPositioningSupported();
302
+ const isSupported = untrack(() => !forceFallback && isAnchorPositioningSupported());
303
303
 
304
304
  // Track expanded sections (independent toggle - multiple can be open)
305
305
  let expandedSections = $state<Set<string | number>>(new Set());
@@ -432,8 +432,8 @@
432
432
  function selectItem(item: DropdownMenuActionItem) {
433
433
  if (item.disabled) return;
434
434
 
435
- const result = item.onSelect?.();
436
- onSelect?.(item);
435
+ // Call item's onSelect if defined, otherwise fall back to component's onSelect
436
+ const result = item.onSelect ? item.onSelect() : onSelect?.(item);
437
437
 
438
438
  if (result !== false && closeOnSelect) {
439
439
  isOpen = false;
@@ -129,8 +129,8 @@ export interface Props extends Omit<HTMLButtonAttributes, "children"> {
129
129
  onOpen?: () => void;
130
130
  /** Called when menu closes */
131
131
  onClose?: () => void;
132
- /** Called when any action item is selected */
133
- onSelect?: (item: DropdownMenuActionItem) => void;
132
+ /** Called when any action item is selected (fallback if item has no onSelect) */
133
+ onSelect?: (item: DropdownMenuActionItem) => void | boolean;
134
134
  /** Reference to trigger element */
135
135
  triggerEl?: HTMLButtonElement;
136
136
  /** Reference to dropdown element */
@@ -138,7 +138,7 @@ export interface Props extends Omit<HTMLButtonAttributes, "children"> {
138
138
  }
139
139
  export declare const DROPDOWN_MENU_BASE_CLASSES = "stuic-dropdown-menu relative inline-block";
140
140
  export declare const DROPDOWN_MENU_TRIGGER_CLASSES = "\n\t\tinline-flex items-center justify-center gap-2\n\t\tpx-3 py-2\n\t\trounded-md border\n\t\tbg-white dark:bg-neutral-800\n\t\ttext-neutral-900 dark:text-neutral-100\n\t\tborder-neutral-200 dark:border-neutral-700\n\t\thover:brightness-95 dark:hover:brightness-110\n\t\tfocus-visible:outline-2 focus-visible:outline-offset-2\n\t\tcursor-pointer\n\t";
141
- export declare const DROPDOWN_MENU_DROPDOWN_CLASSES = "\n\t\tstuic-dropdown-menu-dropdown\n\t\tbg-white dark:bg-neutral-800\n\t\ttext-neutral-900 dark:text-neutral-100\n\t\tborder border-neutral-200 dark:border-neutral-700\n\t\trounded-md shadow-lg\n\t\tp-1\n\t\toverflow-y-auto\n\t\tz-50\n\t\tmin-w-48\n\t";
141
+ export declare const DROPDOWN_MENU_DROPDOWN_CLASSES = "\n\t\tstuic-dropdown-menu-dropdown\n\t\tbg-white dark:bg-neutral-800\n\t\ttext-neutral-900 dark:text-neutral-100\n\t\tborder border-neutral-200 dark:border-neutral-700\n\t\trounded-md shadow-sm\n\t\tp-1\n\t\toverflow-y-auto\n\t\tz-50\n\t\tmin-w-48\n\t";
142
142
  export declare const DROPDOWN_MENU_ITEM_CLASSES = "\n\t\tw-full\n\t\tflex items-center gap-2\n\t\tpx-2 py-1.5\n\t\tmin-h-[44px]\n\t\ttext-left text-sm\n\t\trounded-sm\n\t\tcursor-pointer\n\t\ttouch-action-manipulation\n\t\thover:bg-neutral-100 dark:hover:bg-neutral-700\n\t\tfocus:outline-none\n\t\tfocus-visible:bg-neutral-200 dark:focus-visible:bg-neutral-600\n\t";
143
143
  export declare const DROPDOWN_MENU_DIVIDER_CLASSES = "\n\t\th-px my-1\n\t\tbg-neutral-200 dark:bg-neutral-700\n\t";
144
144
  export declare const DROPDOWN_MENU_HEADER_CLASSES = "\n\t\tpx-2 py-1.5\n\t\ttext-xs font-semibold uppercase tracking-wide\n\t\ttext-neutral-500 dark:text-neutral-400\n\t\tselect-none\n\t";
@@ -28,7 +28,7 @@ export function observeExists(selector, options = {}) {
28
28
  throw new TypeError("Expecting non empty selector");
29
29
  const { rootElement = document.body } = options;
30
30
  const ns = `[observeExists] [${selector}]`;
31
- const clog = (...args) => console.debug(ns, ...args);
31
+ const clogDebug = (...args) => console.debug(ns, ...args);
32
32
  const check = () => rootElement.querySelector(selector) !== null;
33
33
  let current = $state(check());
34
34
  //
@@ -47,14 +47,14 @@ export function observeExists(selector, options = {}) {
47
47
  current = check();
48
48
  });
49
49
  // start observing now
50
- clog(`connecting...`);
50
+ clogDebug(`connecting...`);
51
51
  observer.observe(rootElement, { childList: true, subtree: true });
52
52
  return {
53
53
  get current() {
54
54
  return current;
55
55
  },
56
56
  disconnect() {
57
- clog(`disconnecting...`);
57
+ clogDebug(`disconnecting...`);
58
58
  observer.disconnect();
59
59
  },
60
60
  forceCheck() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "2.14.0",
3
+ "version": "2.17.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.test.*",