@codbex/harmonia 0.9.0 → 1.0.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.
package/dist/harmonia.js CHANGED
@@ -594,24 +594,20 @@
594
594
  "invalid:!border-negative"
595
595
  );
596
596
  };
597
- var getButtonSize = (size3, inGroup = false) => {
597
+ var getButtonSize = (size3, isAddon = false) => {
598
598
  switch (size3) {
599
- case "xs":
600
- return inGroup ? ["h-6", "gap-1", "px-2", "[&>svg:not([class*='size-'])]:size-3.5", "has-[>svg]:px-2"] : ["h-6.5", "gap-1.5", "px-2.5", "has-[>svg]:px-2.5"];
601
599
  case "sm":
602
- return inGroup ? ["h-8", "px-2.5", "gap-1.5", "has-[>svg]:px-2.5"] : ["h-8", "gap-1.5", "px-3", "has-[>svg]:px-2.5"];
603
- case "lg":
604
- return ["h-10", "px-6", "has-[>svg]:px-4"];
605
- case "icon-xs":
606
- return inGroup ? ["size-6", "p-0", "has-[>svg]:p-0"] : ["size-6.5"];
600
+ return isAddon ? ["h-6", "[[data-slot=input-group][data-size=sm]_&]:h-5", "gap-1", "px-2", "[&>svg:not([class*='size-'])]:size-3.5", "has-[>svg]:px-2", "has-[>[data-slot=spinner]]:px-2"] : ["h-6.5", "gap-1.5", "px-2.5", "has-[>svg]:px-2", "has-[>[data-slot=spinner]]:px-2"];
601
+ case "md":
602
+ return isAddon ? ["h-8", "px-2.5", "gap-1.5", "has-[>svg]:px-2.5", "has-[>[data-slot=spinner]]:px-2.5"] : ["h-8", "gap-1.5", "px-3", "has-[>svg]:px-2.5", "has-[>[data-slot=spinner]]:px-2.5"];
607
603
  case "icon-sm":
608
- return inGroup ? ["size-8", "p-0", "has-[>svg]:p-0"] : ["size-8"];
604
+ return isAddon ? ["size-6", "[[data-slot=input-group][data-size=sm]_&]:size-5", "p-0", "has-[>svg]:p-0", "has-[>[data-slot=spinner]]:p-0"] : ["size-6.5"];
605
+ case "icon-md":
606
+ return isAddon ? ["size-8", "p-0", "has-[>svg]:p-0"] : ["size-8"];
609
607
  case "icon":
610
608
  return ["size-9"];
611
- case "icon-lg":
612
- return ["size-10"];
613
609
  default:
614
- return ["h-9", "px-4", "py-2", "has-[>svg]:px-3"];
610
+ return ["h-9", "px-4", "py-2", "has-[>svg]:px-3", "has-[>[data-slot=spinner]]:px-3"];
615
611
  }
616
612
  };
617
613
  function button_default(Alpine) {
@@ -620,7 +616,7 @@
620
616
  if (!el.hasAttribute("data-slot")) {
621
617
  el.setAttribute("data-slot", "button");
622
618
  }
623
- const inGroup = modifiers.includes("group");
619
+ const isAddon = modifiers.includes("addon");
624
620
  let lastSize;
625
621
  function setVariant(variant) {
626
622
  for (const [_, value] of Object.entries(buttonVariants)) {
@@ -628,34 +624,34 @@
628
624
  }
629
625
  if (buttonVariants.hasOwnProperty(variant)) el.classList.add(...buttonVariants[variant]);
630
626
  }
631
- function setSize(size3 = "default") {
632
- el.classList.remove(...getButtonSize(lastSize, inGroup));
633
- el.classList.add(...getButtonSize(size3, inGroup));
627
+ function setSize2(size3 = "default") {
628
+ el.classList.remove(...getButtonSize(lastSize, isAddon));
629
+ el.classList.add(...getButtonSize(size3, isAddon));
634
630
  if (size3.startsWith("icon") && !el.hasAttribute("aria-labelledby") && !el.hasAttribute("aria-label")) {
635
631
  console.error(`${original}: Icon-only buttons must have an "aria-label" or "aria-labelledby" attribute`, el);
636
632
  }
637
633
  lastSize = size3;
638
634
  }
639
635
  setVariant(el.getAttribute("data-variant") ?? "default");
640
- if (inGroup) {
636
+ if (isAddon) {
641
637
  el.classList.remove("shadow-button", "inline-flex");
642
638
  el.classList.add("shadow-none", "flex");
643
- setSize(el.getAttribute("data-size") ?? "xs");
639
+ setSize2(el.getAttribute("data-size") ?? "sm");
644
640
  } else {
645
641
  if (el.hasAttribute("data-size")) {
646
- setSize(el.getAttribute("data-size"));
642
+ setSize2(el.getAttribute("data-size"));
647
643
  } else {
648
644
  if (["date-picker-trigger", "time-picker-trigger"].includes(el.getAttribute("data-slot"))) {
649
- setSize("icon-xs");
645
+ setSize2("icon-sm");
650
646
  } else {
651
- setSize();
647
+ setSize2();
652
648
  }
653
649
  }
654
650
  }
655
651
  const observer = new MutationObserver((mutations) => {
656
652
  mutations.forEach((mutation) => {
657
653
  if (mutation.attributeName === "data-variant") setVariant(el.getAttribute("data-variant") ?? "default");
658
- else setSize(el.getAttribute("data-size") ?? (inGroup ? "xs" : "default"));
654
+ else setSize2(el.getAttribute("data-size") ?? (isAddon ? "sm" : "default"));
659
655
  });
660
656
  });
661
657
  observer.observe(el, { attributes: true, attributeFilter: ["data-variant", "data-size"] });
@@ -2181,7 +2177,7 @@
2181
2177
  el.classList.add("border", "rounded-control", "gap-2", "p-2");
2182
2178
  el.setAttribute("tabindex", "-1");
2183
2179
  if (datepicker) {
2184
- el.classList.add("fixed", "bg-popover", "text-popover-foreground", "data-[state=open]:flex", "data-[state=open]:flex-col", "data-[state=closed]:hidden", "z-50", "shadow-md");
2180
+ el.classList.add("absolute", "bg-popover", "text-popover-foreground", "data-[state=open]:flex", "data-[state=open]:flex-col", "data-[state=closed]:hidden", "z-50", "shadow-md");
2185
2181
  el.setAttribute("role", "dialog");
2186
2182
  el.setAttribute("aria-modal", "true");
2187
2183
  el.setAttribute("data-slot", "date-picker-calendar");
@@ -2611,7 +2607,6 @@
2611
2607
  function updatePosition() {
2612
2608
  computePosition2(datepicker, el, {
2613
2609
  placement: el.getAttribute("data-align") || "bottom-start",
2614
- strategy: "fixed",
2615
2610
  middleware: [offset2(4), flip2(), shift2({ padding: 4 })]
2616
2611
  }).then(({ x, y }) => {
2617
2612
  Object.assign(el.style, {
@@ -2836,7 +2831,19 @@
2836
2831
  "dark:has-[input:invalid]:ring-negative/40"
2837
2832
  );
2838
2833
  el.setAttribute("data-slot", "date-picker");
2839
- el._h_datepicker.input.classList.add("bg-transparent", "outline-none", "flex-1", "border-0", "focus-visible:ring-0", "disabled:pointer-events-none", "disabled:cursor-not-allowed", "disabled:opacity-50", "md:text-sm", "text-base");
2834
+ el._h_datepicker.input.classList.add(
2835
+ "bg-transparent",
2836
+ "outline-none",
2837
+ "flex-1",
2838
+ "h-full",
2839
+ "border-0",
2840
+ "focus-visible:ring-0",
2841
+ "disabled:pointer-events-none",
2842
+ "disabled:cursor-not-allowed",
2843
+ "disabled:opacity-50",
2844
+ "md:text-sm",
2845
+ "text-base"
2846
+ );
2840
2847
  el._h_datepicker.input.setAttribute("aria-autocomplete", "none");
2841
2848
  el._h_datepicker.input.setAttribute("type", "text");
2842
2849
  });
@@ -2945,8 +2952,8 @@
2945
2952
  "flex-col",
2946
2953
  "w-full",
2947
2954
  "max-w-[calc(100%-2rem)]",
2948
- "translate-x-[-50%]",
2949
- "translate-y-[-50%]",
2955
+ "-translate-x-1/2",
2956
+ "-translate-y-1/2",
2950
2957
  "gap-4",
2951
2958
  "rounded-lg",
2952
2959
  "border",
@@ -3025,7 +3032,7 @@
3025
3032
  el.setAttribute("data-slot", "field-group");
3026
3033
  });
3027
3034
  Alpine.directive("h-field", (el) => {
3028
- el.classList.add("group/field", "w-full", "gap-3", "data-[invalid=true]:text-negative");
3035
+ el.classList.add("group/field", "w-full", "gap-3", "has-[input:invalid]:text-negative", "has-[textarea:invalid]:text-negative", "has-[[aria-invalid=true]]:text-negative");
3029
3036
  switch (el.getAttribute("data-orientation")) {
3030
3037
  case "horizontal":
3031
3038
  el.classList.add("hbox", "items-center", "[&>[data-slot=field-label]]:flex-auto", "has-[>[data-slot=field-content]]:items-start", "has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px");
@@ -3072,9 +3079,32 @@
3072
3079
  "[&>a]:underline-offset-4"
3073
3080
  );
3074
3081
  el.setAttribute("data-slot", "field-description");
3082
+ if (el.getAttribute("data-hide-on-error") === "true") {
3083
+ el.classList.add(
3084
+ "[[data-slot=field]_input:invalid~&]:hidden",
3085
+ "[[data-slot=field]_textarea:invalid~&]:hidden",
3086
+ "[[data-slot=field]_[aria-invalid=true]~&]:hidden",
3087
+ "group-has-[input:invalid]/field:hidden",
3088
+ "group-has-[textarea:invalid)]/field:hidden",
3089
+ "group-has-[[aria-invalid=true]]/field:hidden"
3090
+ );
3091
+ }
3075
3092
  });
3076
3093
  Alpine.directive("h-field-error", (el) => {
3077
- el.classList.add("text-negative", "text-sm", "font-normal");
3094
+ el.classList.add(
3095
+ "hidden",
3096
+ "[[data-slot=field]_input:invalid~&]:block",
3097
+ "[[data-slot=field]_textarea:invalid~&]:block",
3098
+ "[[data-slot=field]_[aria-invalid=true]~&]:block",
3099
+ "group-has-[input:invalid]/field:block",
3100
+ "group-has-[textarea:invalid)]/field:block",
3101
+ "group-has-[[aria-invalid=true]]/field:block",
3102
+ "text-negative",
3103
+ "text-sm",
3104
+ "leading-normal",
3105
+ "font-normal",
3106
+ "group-has-[[data-orientation=horizontal]]/field:text-balance"
3107
+ );
3078
3108
  el.setAttribute("data-slot", "field-error");
3079
3109
  });
3080
3110
  }
@@ -3139,20 +3169,35 @@
3139
3169
  });
3140
3170
  }
3141
3171
 
3172
+ // src/common/input-size.js
3173
+ function setSize(el, size3) {
3174
+ if (size3 === "sm") {
3175
+ el.classList.add("h-6.5");
3176
+ el.classList.remove("h-9");
3177
+ } else {
3178
+ el.classList.add("h-9");
3179
+ el.classList.remove("h-6.5");
3180
+ }
3181
+ }
3182
+ function sizeObserver(el) {
3183
+ const observer = new MutationObserver(() => {
3184
+ setSize(el, el.getAttribute("data-size"));
3185
+ });
3186
+ setSize(el, el.getAttribute("data-size"));
3187
+ observer.observe(el, { attributes: true, attributeFilter: ["data-size"] });
3188
+ return observer;
3189
+ }
3190
+
3142
3191
  // src/components/input.js
3143
3192
  function input_default(Alpine) {
3144
- Alpine.directive("h-input", (el, { modifiers }) => {
3193
+ Alpine.directive("h-input", (el, { modifiers }, { cleanup }) => {
3145
3194
  el.classList.add(
3146
3195
  "file:text-foreground",
3147
3196
  "placeholder:text-muted-foreground",
3148
3197
  "selection:bg-primary",
3149
3198
  "selection:text-primary-foreground",
3150
- "bg-input-inner",
3151
3199
  "border-input",
3152
- "w-full",
3153
3200
  "min-w-0",
3154
- "rounded-control",
3155
- "border",
3156
3201
  "[&:not([type='color'])]:px-3",
3157
3202
  "[&:not([type='color'])]:py-1",
3158
3203
  "[&[type='color']]:overflow-hidden",
@@ -3161,7 +3206,6 @@
3161
3206
  "[&::-webkit-color-swatch-wrapper]:rounded-0",
3162
3207
  "[&::-webkit-color-swatch-wrapper]:p-0",
3163
3208
  "text-base",
3164
- "shadow-input",
3165
3209
  "transition-[color,box-shadow]",
3166
3210
  "outline-none",
3167
3211
  "file:inline-flex",
@@ -3176,7 +3220,6 @@
3176
3220
  "md:text-sm",
3177
3221
  "focus-visible:border-ring",
3178
3222
  "focus-visible:ring-ring/50",
3179
- "focus-visible:ring-[calc(var(--spacing)*0.75)]",
3180
3223
  "aria-invalid:ring-negative/20",
3181
3224
  "dark:aria-invalid:ring-negative/40",
3182
3225
  "aria-invalid:border-negative",
@@ -3185,15 +3228,18 @@
3185
3228
  "invalid:!border-negative"
3186
3229
  );
3187
3230
  if (modifiers.includes("group")) {
3188
- el.classList.remove("rounded-control", "border", "bg-input-inner", "shadow-input", "focus-visible:ring-[calc(var(--spacing)*0.75)]");
3189
- el.classList.add("flex-1", "rounded-none", "border-0", "bg-transparent", "shadow-none", "focus-visible:ring-0");
3231
+ el.classList.add("h-full", "flex-1", "rounded-none", "border-0", "bg-transparent", "shadow-none", "focus-visible:ring-0");
3190
3232
  el.setAttribute("data-slot", "input-group-control");
3191
- } else el.setAttribute("data-slot", "input");
3192
- if (el.getAttribute("data-size") === "sm") el.classList.add("h-8");
3193
- else if (el.getAttribute("data-size") === "xs") el.classList.add("h-6.5");
3194
- else el.classList.add("h-9");
3233
+ } else {
3234
+ el.classList.add("w-full", "rounded-control", "border", "bg-input-inner", "shadow-input", "focus-visible:ring-[calc(var(--spacing)*0.75)]");
3235
+ el.setAttribute("data-slot", "input");
3236
+ const observer = sizeObserver(el);
3237
+ cleanup(() => {
3238
+ observer.disconnect();
3239
+ });
3240
+ }
3195
3241
  });
3196
- Alpine.directive("h-input-group", (el) => {
3242
+ Alpine.directive("h-input-group", (el, _, { cleanup }) => {
3197
3243
  el.classList.add(
3198
3244
  "group/input-group",
3199
3245
  "border-input",
@@ -3207,7 +3253,6 @@
3207
3253
  "shadow-input",
3208
3254
  "transition-[color,box-shadow]",
3209
3255
  "outline-none",
3210
- "h-9",
3211
3256
  "min-w-0",
3212
3257
  "has-[>textarea]:h-auto",
3213
3258
  "has-[>[data-align=inline-start]]:[&>input]:pl-2",
@@ -3227,6 +3272,10 @@
3227
3272
  );
3228
3273
  el.setAttribute("role", "group");
3229
3274
  el.setAttribute("data-slot", "input-group");
3275
+ const observer = sizeObserver(el);
3276
+ cleanup(() => {
3277
+ observer.disconnect();
3278
+ });
3230
3279
  });
3231
3280
  Alpine.directive("h-input-group-addon", (el, _, { cleanup }) => {
3232
3281
  el.classList.add(
@@ -3237,7 +3286,6 @@
3237
3286
  "items-center",
3238
3287
  "justify-center",
3239
3288
  "gap-2",
3240
- "py-1.5",
3241
3289
  "text-sm",
3242
3290
  "font-medium",
3243
3291
  "select-none",
@@ -3249,8 +3297,24 @@
3249
3297
  el.setAttribute("role", "group");
3250
3298
  el.setAttribute("data-slot", "input-group-addon");
3251
3299
  const variants = {
3252
- "inline-start": ["order-first", "pl-3", "has-[>button]:ml-[-0.45rem]", "has-[>[data-slot=tag]]:ml-[-0.35rem]"],
3253
- "inline-end": ["order-last", "pr-3", "has-[>button]:mr-[-0.45rem]", "has-[>[data-slot=tag]]:mr-[-0.35rem]"],
3300
+ "inline-start": [
3301
+ "order-first",
3302
+ "pl-3",
3303
+ "[[data-slot=input-group][data-size=sm]_&]:pl-1.25",
3304
+ "has-[>button]:pl-1.25",
3305
+ "[[data-slot=input-group][data-size=sm]_&]:has-[>button]:pl-0.5",
3306
+ "has-[>[data-slot|=tag]]:pl-1.5",
3307
+ "[[data-slot=input-group][data-size=sm]_&]:has-[>[data-slot|=tag]]:pl-0.5"
3308
+ ],
3309
+ "inline-end": [
3310
+ "order-last",
3311
+ "pr-3",
3312
+ "[[data-slot=input-group][data-size=sm]_&]:pr-1.25",
3313
+ "has-[>button]:pr-1.25",
3314
+ "[[data-slot=input-group][data-size=sm]_&]:has-[>button]:pr-0.5",
3315
+ "has-[>[data-slot|=tag]]:pr-1.5",
3316
+ "[[data-slot=input-group][data-size=sm]_&]:has-[>[data-slot|=tag]]:pr-0.5"
3317
+ ],
3254
3318
  "block-start": ["order-first", "w-full", "justify-start", "px-3", "pt-3", "[.border-b]:pb-3", "group-has-[>input]/input-group:pt-2.5"],
3255
3319
  "block-end": ["order-last", "w-full", "justify-start", "px-3", "pb-3", "[.border-t]:pt-3", "group-has-[>input]/input-group:pb-2.5"]
3256
3320
  };
@@ -3275,6 +3339,136 @@
3275
3339
  el.classList.add("text-muted-foreground", "flex", "items-center", "gap-2", "text-sm", "[&_svg]:pointer-events-none", "[&_svg:not([class*='size-'])]:size-4");
3276
3340
  el.setAttribute("data-slot", "label");
3277
3341
  });
3342
+ Alpine.directive("h-input-number", (el, { original }, { cleanup }) => {
3343
+ el.classList.add(
3344
+ "group/input-number",
3345
+ "border-input",
3346
+ "bg-input-inner",
3347
+ "relative",
3348
+ "flex",
3349
+ "w-full",
3350
+ "items-center",
3351
+ "rounded-control",
3352
+ "border",
3353
+ "shadow-input",
3354
+ "transition-[color,box-shadow]",
3355
+ "outline-none",
3356
+ "min-w-0",
3357
+ "has-[[data-slot=input-number-control]:focus-visible]:border-ring",
3358
+ "has-[[data-slot=input-number-control]:focus-visible]:ring-ring/50",
3359
+ "has-[[data-slot=input-number-control]:focus-visible]:ring-[calc(var(--spacing)*0.75)]",
3360
+ "has-[[data-slot][aria-invalid=true]]:ring-negative/20",
3361
+ "has-[[data-slot][aria-invalid=true]]:border-negative",
3362
+ "dark:has-[[data-slot][aria-invalid=true]]:ring-negative/40"
3363
+ );
3364
+ el.setAttribute("role", "group");
3365
+ el.setAttribute("data-slot", "input-number");
3366
+ const input = el.querySelector("input");
3367
+ if (!input || input.getAttribute("type") !== "number") {
3368
+ throw new Error(`${original} must contain an input of type 'number'`);
3369
+ }
3370
+ if (!input.hasAttribute("type")) input.setAttribute("type", "number");
3371
+ if (!input.hasAttribute("inputmode")) input.setAttribute("inputmode", "numeric");
3372
+ if (!input.hasAttribute("aria-roledescription")) {
3373
+ input.setAttribute("aria-roledescription", "Number field");
3374
+ }
3375
+ if (!input.hasAttribute("id")) {
3376
+ input.setAttribute("id", `in${v4_default()}`);
3377
+ }
3378
+ input.setAttribute("tabindex", "0");
3379
+ input.setAttribute("autocomplete", "off");
3380
+ input.setAttribute("autocorrect", "off");
3381
+ input.setAttribute("spellcheck", "off");
3382
+ input.setAttribute("data-slot", "input-number-control");
3383
+ input.classList.add("rounded-l-control", "size-full", "px-3", "py-1", "outline-none");
3384
+ const stepDown = document.createElement("button");
3385
+ stepDown.setAttribute("type", "button");
3386
+ stepDown.setAttribute("tabIndex", "-1");
3387
+ stepDown.setAttribute("aria-label", "Decrease");
3388
+ stepDown.setAttribute("aria-controls", input.getAttribute("id"));
3389
+ stepDown.setAttribute("data-slot", "step-up-trigger");
3390
+ stepDown.classList.add(
3391
+ "border-l",
3392
+ "border-input",
3393
+ "h-full",
3394
+ "aspect-square",
3395
+ "bg-transparent",
3396
+ "hover:bg-secondary",
3397
+ "active:bg-secondary-active",
3398
+ "outline-none",
3399
+ "relative",
3400
+ "before:block",
3401
+ "before:rounded-full",
3402
+ "before:h-0.5",
3403
+ "before:min-h-px",
3404
+ "before:w-3",
3405
+ "before:mx-auto",
3406
+ "before:bg-foreground",
3407
+ "before:hover:bg-secondary-foreground"
3408
+ );
3409
+ el.appendChild(stepDown);
3410
+ const onStepDown = () => {
3411
+ input.stepDown();
3412
+ input.dispatchEvent(new Event("input", { bubbles: true }));
3413
+ input.dispatchEvent(new Event("change", { bubbles: true }));
3414
+ };
3415
+ stepDown.addEventListener("click", onStepDown);
3416
+ const stepUp = document.createElement("button");
3417
+ stepUp.setAttribute("type", "button");
3418
+ stepUp.setAttribute("tabIndex", "-1");
3419
+ stepUp.setAttribute("aria-label", "Increase");
3420
+ stepUp.setAttribute("aria-controls", input.getAttribute("id"));
3421
+ stepUp.setAttribute("data-slot", "step-up-trigger");
3422
+ stepUp.classList.add(
3423
+ "border-l",
3424
+ "border-input",
3425
+ "rounded-r-control",
3426
+ "h-full",
3427
+ "aspect-square",
3428
+ "bg-transparent",
3429
+ "hover:bg-secondary",
3430
+ "active:bg-secondary-active",
3431
+ "outline-none",
3432
+ "relative",
3433
+ "before:block",
3434
+ "before:absolute",
3435
+ "before:rounded-full",
3436
+ "before:h-0.5",
3437
+ "before:min-h-px",
3438
+ "before:w-3",
3439
+ "before:top-1/2",
3440
+ "before:left-1/2",
3441
+ "before:-translate-x-1/2",
3442
+ "before:-translate-y-1/2",
3443
+ "before:bg-foreground",
3444
+ "before:hover:bg-secondary-foreground",
3445
+ "after:block",
3446
+ "after:absolute",
3447
+ "after:rounded-full",
3448
+ "after:h-3",
3449
+ "after:min-w-px",
3450
+ "after:w-0.5",
3451
+ "after:top-1/2",
3452
+ "after:left-1/2",
3453
+ "after:-translate-x-1/2",
3454
+ "after:-translate-y-1/2",
3455
+ "after:bg-foreground",
3456
+ "after:hover:bg-secondary-foreground"
3457
+ );
3458
+ el.appendChild(stepUp);
3459
+ const onStepUp = () => {
3460
+ input.stepUp();
3461
+ input.dispatchEvent(new Event("input", { bubbles: true }));
3462
+ input.dispatchEvent(new Event("change", { bubbles: true }));
3463
+ };
3464
+ stepUp.addEventListener("click", onStepUp);
3465
+ const observer = sizeObserver(el);
3466
+ cleanup(() => {
3467
+ observer.disconnect();
3468
+ stepDown.removeEventListener("click", onStepDown);
3469
+ stepUp.removeEventListener("click", onStepUp);
3470
+ });
3471
+ });
3278
3472
  }
3279
3473
 
3280
3474
  // src/components/label.js
@@ -6275,23 +6469,7 @@
6275
6469
  "[&_svg]:opacity-50"
6276
6470
  );
6277
6471
  el.setAttribute("data-slot", "select");
6278
- const setSize = (size3) => {
6279
- if (size3 === "sm") {
6280
- el.classList.add("h-8");
6281
- el.classList.remove("h-9", "h-6.5");
6282
- } else if (size3 === "xs") {
6283
- el.classList.add("h-6.5");
6284
- el.classList.remove("h-9", "h-8");
6285
- } else {
6286
- el.classList.add("h-9");
6287
- el.classList.remove("h-8", "h-6.5");
6288
- }
6289
- };
6290
- setSize(el.getAttribute("data-size"));
6291
- const observer = new MutationObserver(() => {
6292
- setSize(el.getAttribute("data-size"));
6293
- });
6294
- observer.observe(el, { attributes: true, attributeFilter: ["data-size"] });
6472
+ const observer = sizeObserver(el);
6295
6473
  cleanup(() => {
6296
6474
  observer.disconnect();
6297
6475
  });
@@ -7033,13 +7211,13 @@
7033
7211
  sm: ["h-7", "text-xs"],
7034
7212
  lg: ["h-12", "text-sm", "group-data-[collapsed=true]/sidebar:p-0!"]
7035
7213
  };
7036
- function setSize(size3) {
7214
+ function setSize2(size3) {
7037
7215
  if (sizes.hasOwnProperty(size3)) {
7038
7216
  el.classList.add(...sizes[size3]);
7039
7217
  }
7040
7218
  }
7041
7219
  if (!el.hasAttribute("data-size")) el.setAttribute("data-size", "default");
7042
- setSize(el.getAttribute("data-size"));
7220
+ setSize2(el.getAttribute("data-size"));
7043
7221
  });
7044
7222
  Alpine.directive("h-sidebar-menu-action", (el, { modifiers }) => {
7045
7223
  el.classList.add(
@@ -7171,13 +7349,13 @@
7171
7349
  sm: ["text-xs"],
7172
7350
  md: ["text-sm"]
7173
7351
  };
7174
- function setSize(size3) {
7352
+ function setSize2(size3) {
7175
7353
  if (sizes.hasOwnProperty(size3)) {
7176
7354
  el.classList.add(...sizes[size3]);
7177
7355
  }
7178
7356
  }
7179
7357
  if (!el.hasAttribute("data-size")) el.setAttribute("data-size", "md");
7180
- setSize(el.getAttribute("data-size"));
7358
+ setSize2(el.getAttribute("data-size"));
7181
7359
  });
7182
7360
  Alpine.directive("h-sidebar-footer", (el) => {
7183
7361
  el.classList.add("vbox", "gap-2", "px-2", "h-12", "justify-center", "border-t");
@@ -7193,10 +7371,10 @@
7193
7371
  if (modifiers.includes("control")) {
7194
7372
  el.classList.add("rounded-control");
7195
7373
  switch (el.getAttribute("data-size")) {
7196
- case "xs":
7374
+ case "sm":
7197
7375
  el.classList.add("h-6.5");
7198
7376
  break;
7199
- case "sm":
7377
+ case "md":
7200
7378
  el.classList.add("h-8");
7201
7379
  break;
7202
7380
  default:
@@ -7215,7 +7393,20 @@
7215
7393
  // src/components/spinner.js
7216
7394
  function spinner_default(Alpine) {
7217
7395
  Alpine.directive("h-spinner", (el) => {
7218
- el.classList.add("size-4", "border-2", "border-x-primary", "border-b-primary", "border-t-transparent", "rounded-full", "animate-spin");
7396
+ el.classList.add(
7397
+ "size-4",
7398
+ "border-2",
7399
+ "border-primary",
7400
+ "[[data-slot=button]_&]:border-secondary-foreground",
7401
+ "[[data-slot=button][data-variant=primary]_&]:border-primary-foreground",
7402
+ "[[data-slot=button][data-variant=positive]_&]:border-positive-foreground",
7403
+ "[[data-slot=button][data-variant=negative]_&]:border-negative-foreground",
7404
+ "[[data-slot=button][data-variant=warning]_&]:border-warning-foreground",
7405
+ "[[data-slot=button][data-variant=information]_&]:border-information-foreground",
7406
+ "!border-t-transparent",
7407
+ "rounded-full",
7408
+ "animate-spin"
7409
+ );
7219
7410
  el.setAttribute("role", "status");
7220
7411
  el.setAttribute("data-slot", "spinner");
7221
7412
  if (!el.hasAttribute("aria-label")) el.setAttribute("aria-label", "Loading");
@@ -7774,6 +7965,10 @@
7774
7965
  "group/tile",
7775
7966
  "flex",
7776
7967
  "items-center",
7968
+ "py-3",
7969
+ "px-4",
7970
+ "has-data-[slot=tile-header]:py-4",
7971
+ "gap-2.5",
7777
7972
  "text-sm",
7778
7973
  "rounded-lg",
7779
7974
  "transition-colors",
@@ -7788,14 +7983,6 @@
7788
7983
  "focus-visible:ring-[calc(var(--spacing)*0.75)]"
7789
7984
  );
7790
7985
  el.setAttribute("data-slot", "tile");
7791
- const sizes = {
7792
- default: ["p-4", "gap-4"],
7793
- sm: ["py-3", "px-4", "gap-2.5"]
7794
- };
7795
- function setSize(size3) {
7796
- el.classList.add(...sizes[size3]);
7797
- el.setAttribute("data-size", size3);
7798
- }
7799
7986
  switch (el.getAttribute("data-variant")) {
7800
7987
  case "outline":
7801
7988
  el.classList.add("border", "border-border");
@@ -7809,9 +7996,6 @@
7809
7996
  default:
7810
7997
  el.classList.add("border", "bg-transparent", "border-transparent");
7811
7998
  }
7812
- if (el.getAttribute("data-size") === "sm") {
7813
- setSize("sm");
7814
- } else setSize("sm");
7815
7999
  });
7816
8000
  Alpine.directive("h-tile-header", (el) => {
7817
8001
  el.classList.add("flex", "basis-full", "items-center", "justify-between", "gap-2");
@@ -7893,6 +8077,15 @@
7893
8077
  }
7894
8078
  return { hour, minute, second, period };
7895
8079
  };
8080
+ function scrollIntoCenter(container, element, behavior = "instant") {
8081
+ const containerRect = container.getBoundingClientRect();
8082
+ const elementRect = element.getBoundingClientRect();
8083
+ const offset4 = elementRect.top - containerRect.top - container.clientHeight / 2 + element.clientHeight / 2;
8084
+ container.scrollBy({
8085
+ top: offset4,
8086
+ behavior
8087
+ });
8088
+ }
7896
8089
  function timepicker_default(Alpine) {
7897
8090
  Alpine.directive("h-time-picker", (el, { expression }, { evaluateLater, cleanup, effect, Alpine: Alpine2 }) => {
7898
8091
  el._h_timepicker = Alpine2.reactive({
@@ -8099,7 +8292,7 @@
8099
8292
  "outline-none",
8100
8293
  "border",
8101
8294
  "rounded-control",
8102
- "fixed",
8295
+ "absolute",
8103
8296
  "bg-popover",
8104
8297
  "text-popover-foreground",
8105
8298
  "data-[state=open]:flex",
@@ -8511,21 +8704,26 @@
8511
8704
  };
8512
8705
  el.addEventListener("click", onClick2);
8513
8706
  let autoUpdateCleanup;
8707
+ let focusFirstItem = true;
8514
8708
  function updatePosition() {
8515
8709
  computePosition2(timepicker, el, {
8516
8710
  placement: el.getAttribute("data-align") || "bottom-start",
8517
- strategy: "fixed",
8518
8711
  middleware: [offset2(4), flip2(), shift2({ padding: 4 })]
8519
8712
  }).then(({ x, y }) => {
8520
- if (selectedHour) {
8521
- selectedHour.focus();
8522
- } else {
8523
- hoursList.children[timepicker._h_timepicker.is12Hour ? 1 : 0].focus();
8524
- }
8525
8713
  Object.assign(el.style, {
8526
8714
  left: `${x}px`,
8527
8715
  top: `${y}px`
8528
8716
  });
8717
+ if (focusFirstItem) {
8718
+ focusFirstItem = false;
8719
+ Alpine2.nextTick(() => {
8720
+ if (selectedHour) {
8721
+ selectedHour.focus();
8722
+ } else {
8723
+ hoursList.children[timepicker._h_timepicker.is12Hour ? 1 : 0].focus();
8724
+ }
8725
+ });
8726
+ }
8529
8727
  });
8530
8728
  }
8531
8729
  effect(() => {
@@ -8533,11 +8731,12 @@
8533
8731
  if (timepicker._h_timepicker.expanded) {
8534
8732
  render();
8535
8733
  autoUpdateCleanup = autoUpdate(timepicker, el, updatePosition);
8536
- if (selectedHour) selectedHour.scrollIntoView({ block: "center" });
8537
- if (selectedMinute) selectedMinute.scrollIntoView({ block: "center" });
8538
- if (selectedSecond && timepicker._h_timepicker.seconds) selectedSecond.scrollIntoView({ block: "center" });
8734
+ if (selectedHour) scrollIntoCenter(selectedHour.parentElement, selectedHour);
8735
+ if (selectedMinute) scrollIntoCenter(selectedMinute.parentElement, selectedMinute);
8736
+ if (selectedSecond && timepicker._h_timepicker.seconds) scrollIntoCenter(selectedSecond.parentElement, selectedSecond);
8539
8737
  } else {
8540
8738
  if (autoUpdateCleanup) autoUpdateCleanup();
8739
+ focusFirstItem = true;
8541
8740
  Object.assign(el.style, {
8542
8741
  left: "0px",
8543
8742
  top: "0px"
@@ -9051,7 +9250,7 @@
9051
9250
  }
9052
9251
 
9053
9252
  // package.json
9054
- var version = "0.9.0";
9253
+ var version = "1.0.0";
9055
9254
 
9056
9255
  // src/index.js
9057
9256
  window.Harmonia = { getBreakpointListener, addColorSchemeListener, getColorScheme, removeColorSchemeListener, setColorScheme, version };