@codbex/harmonia 0.9.1 → 1.1.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"] });
@@ -2306,7 +2302,7 @@
2306
2302
  previousYearBtn.setAttribute("type", "button");
2307
2303
  previousYearBtn.appendChild(
2308
2304
  createElement(ChevronsLeft, {
2309
- class: ["opacity-50 size-4 shrink-0 pointer-events-none"],
2305
+ class: ["opacity-70 size-4 shrink-0 pointer-events-none"],
2310
2306
  width: "16",
2311
2307
  height: "16",
2312
2308
  "aria-hidden": true,
@@ -2324,7 +2320,7 @@
2324
2320
  previousMonthBtn.setAttribute("type", "button");
2325
2321
  previousMonthBtn.appendChild(
2326
2322
  createElement(ChevronLeft, {
2327
- class: ["opacity-50 size-4 shrink-0 pointer-events-none"],
2323
+ class: ["opacity-70 size-4 shrink-0 pointer-events-none"],
2328
2324
  width: "16",
2329
2325
  height: "16",
2330
2326
  "aria-hidden": true,
@@ -2347,7 +2343,7 @@
2347
2343
  nextMonthBtn.setAttribute("type", "button");
2348
2344
  nextMonthBtn.appendChild(
2349
2345
  createElement(ChevronRight, {
2350
- class: ["opacity-50 size-4 shrink-0 pointer-events-none"],
2346
+ class: ["opacity-70 size-4 shrink-0 pointer-events-none"],
2351
2347
  width: "16",
2352
2348
  height: "16",
2353
2349
  "aria-hidden": true,
@@ -2365,7 +2361,7 @@
2365
2361
  nextYearBtn.setAttribute("type", "button");
2366
2362
  nextYearBtn.appendChild(
2367
2363
  createElement(ChevronsRight, {
2368
- class: ["opacity-50 size-4 shrink-0 pointer-events-none"],
2364
+ class: ["opacity-70 size-4 shrink-0 pointer-events-none"],
2369
2365
  width: "16",
2370
2366
  height: "16",
2371
2367
  "aria-hidden": true,
@@ -2788,9 +2784,28 @@
2788
2784
  });
2789
2785
  }
2790
2786
 
2787
+ // src/common/input-size.js
2788
+ function setSize(el, size3) {
2789
+ if (size3 === "sm") {
2790
+ el.classList.add("h-6.5");
2791
+ el.classList.remove("h-9");
2792
+ } else {
2793
+ el.classList.add("h-9");
2794
+ el.classList.remove("h-6.5");
2795
+ }
2796
+ }
2797
+ function sizeObserver(el) {
2798
+ const observer = new MutationObserver(() => {
2799
+ setSize(el, el.getAttribute("data-size"));
2800
+ });
2801
+ setSize(el, el.getAttribute("data-size"));
2802
+ observer.observe(el, { attributes: true, attributeFilter: ["data-size"] });
2803
+ return observer;
2804
+ }
2805
+
2791
2806
  // src/components/datepicker.js
2792
2807
  function datepicker_default(Alpine) {
2793
- Alpine.directive("h-date-picker", (el, { original }, { Alpine: Alpine2 }) => {
2808
+ Alpine.directive("h-date-picker", (el, { original }, { Alpine: Alpine2, cleanup }) => {
2794
2809
  el._h_datepicker = Alpine2.reactive({
2795
2810
  id: void 0,
2796
2811
  controls: `hdpc${v4_default()}`,
@@ -2819,10 +2834,7 @@
2819
2834
  "transition-[color,box-shadow]",
2820
2835
  "duration-200",
2821
2836
  "outline-none",
2822
- "h-9",
2823
2837
  "pl-3",
2824
- "pr-1",
2825
- "gap-2",
2826
2838
  "min-w-0",
2827
2839
  "has-[input:focus-visible]:border-ring",
2828
2840
  "has-[input:focus-visible]:ring-ring/50",
@@ -2838,18 +2850,26 @@
2838
2850
  el._h_datepicker.input.classList.add(
2839
2851
  "bg-transparent",
2840
2852
  "outline-none",
2841
- "flex-1",
2842
- "h-full",
2843
- "border-0",
2853
+ "size-full",
2854
+ "pr-1",
2855
+ "border-r",
2856
+ "border-input",
2857
+ "aria-invalid:border-negative",
2858
+ "invalid:border-negative",
2844
2859
  "focus-visible:ring-0",
2845
2860
  "disabled:pointer-events-none",
2846
2861
  "disabled:cursor-not-allowed",
2847
2862
  "disabled:opacity-50",
2848
2863
  "md:text-sm",
2849
- "text-base"
2864
+ "text-base",
2865
+ "truncate"
2850
2866
  );
2851
2867
  el._h_datepicker.input.setAttribute("aria-autocomplete", "none");
2852
2868
  el._h_datepicker.input.setAttribute("type", "text");
2869
+ const observer = sizeObserver(el);
2870
+ cleanup(() => {
2871
+ observer.disconnect();
2872
+ });
2853
2873
  });
2854
2874
  Alpine.directive("h-date-picker-trigger", (el, { original }, { effect, cleanup, Alpine: Alpine2 }) => {
2855
2875
  if (el.tagName !== "BUTTON") {
@@ -2862,6 +2882,28 @@
2862
2882
  if (!datepicker) {
2863
2883
  throw new Error(`${original} must be inside an date-picker element`);
2864
2884
  }
2885
+ el.classList.add(
2886
+ "cursor-pointer",
2887
+ "inline-flex",
2888
+ "items-center",
2889
+ "justify-center",
2890
+ "rounded-r-control",
2891
+ "h-full",
2892
+ "aspect-square",
2893
+ "bg-transparent",
2894
+ "hover:bg-secondary",
2895
+ "active:bg-secondary-active",
2896
+ "outline-none",
2897
+ "focus-visible:border-ring",
2898
+ "focus-visible:ring-ring/50",
2899
+ "focus-visible:ring-[calc(var(--spacing)*0.75)]",
2900
+ "[input[aria-invalid=true]~&]:ring-negative/20",
2901
+ "[input[aria-invalid=true]~&]:border-negative",
2902
+ "dark:[input[aria-invalid=true]~&]:ring-negative/40",
2903
+ "[input:invalid~&]:ring-negative/20",
2904
+ "[input:invalid~&]:border-negative",
2905
+ "dark:[input:invalid~&]:ring-negative/40"
2906
+ );
2865
2907
  el.setAttribute("aria-controls", datepicker._h_datepicker.controls);
2866
2908
  el.setAttribute("aria-expanded", "false");
2867
2909
  el.setAttribute("aria-haspopup", "dialog");
@@ -2869,7 +2911,7 @@
2869
2911
  el.setAttribute("data-slot", "date-picker-trigger");
2870
2912
  el.appendChild(
2871
2913
  createElement(Calendar, {
2872
- class: ["opacity-50 size-4 transition-transform duration-200"],
2914
+ class: ["opacity-70 text-foreground size-4"],
2873
2915
  width: "16",
2874
2916
  height: "16",
2875
2917
  "aria-hidden": true,
@@ -2899,7 +2941,7 @@
2899
2941
  el.removeEventListener("click", handler);
2900
2942
  top.removeEventListener("click", close);
2901
2943
  });
2902
- }).before("h-button");
2944
+ });
2903
2945
  }
2904
2946
 
2905
2947
  // src/components/dialog.js
@@ -2956,8 +2998,8 @@
2956
2998
  "flex-col",
2957
2999
  "w-full",
2958
3000
  "max-w-[calc(100%-2rem)]",
2959
- "translate-x-[-50%]",
2960
- "translate-y-[-50%]",
3001
+ "-translate-x-1/2",
3002
+ "-translate-y-1/2",
2961
3003
  "gap-4",
2962
3004
  "rounded-lg",
2963
3005
  "border",
@@ -3036,7 +3078,7 @@
3036
3078
  el.setAttribute("data-slot", "field-group");
3037
3079
  });
3038
3080
  Alpine.directive("h-field", (el) => {
3039
- el.classList.add("group/field", "w-full", "gap-3", "data-[invalid=true]:text-negative");
3081
+ 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");
3040
3082
  switch (el.getAttribute("data-orientation")) {
3041
3083
  case "horizontal":
3042
3084
  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");
@@ -3083,9 +3125,32 @@
3083
3125
  "[&>a]:underline-offset-4"
3084
3126
  );
3085
3127
  el.setAttribute("data-slot", "field-description");
3128
+ if (el.getAttribute("data-hide-on-error") === "true") {
3129
+ el.classList.add(
3130
+ "[[data-slot=field]_input:invalid~&]:hidden",
3131
+ "[[data-slot=field]_textarea:invalid~&]:hidden",
3132
+ "[[data-slot=field]_[aria-invalid=true]~&]:hidden",
3133
+ "group-has-[input:invalid]/field:hidden",
3134
+ "group-has-[textarea:invalid)]/field:hidden",
3135
+ "group-has-[[aria-invalid=true]]/field:hidden"
3136
+ );
3137
+ }
3086
3138
  });
3087
3139
  Alpine.directive("h-field-error", (el) => {
3088
- el.classList.add("text-negative", "text-sm", "font-normal");
3140
+ el.classList.add(
3141
+ "hidden",
3142
+ "[[data-slot=field]_input:invalid~&]:block",
3143
+ "[[data-slot=field]_textarea:invalid~&]:block",
3144
+ "[[data-slot=field]_[aria-invalid=true]~&]:block",
3145
+ "group-has-[input:invalid]/field:block",
3146
+ "group-has-[textarea:invalid)]/field:block",
3147
+ "group-has-[[aria-invalid=true]]/field:block",
3148
+ "text-negative",
3149
+ "text-sm",
3150
+ "leading-normal",
3151
+ "font-normal",
3152
+ "group-has-[[data-orientation=horizontal]]/field:text-balance"
3153
+ );
3089
3154
  el.setAttribute("data-slot", "field-error");
3090
3155
  });
3091
3156
  }
@@ -3152,18 +3217,14 @@
3152
3217
 
3153
3218
  // src/components/input.js
3154
3219
  function input_default(Alpine) {
3155
- Alpine.directive("h-input", (el, { modifiers }) => {
3220
+ Alpine.directive("h-input", (el, { modifiers }, { cleanup }) => {
3156
3221
  el.classList.add(
3157
3222
  "file:text-foreground",
3158
3223
  "placeholder:text-muted-foreground",
3159
3224
  "selection:bg-primary",
3160
3225
  "selection:text-primary-foreground",
3161
- "bg-input-inner",
3162
3226
  "border-input",
3163
- "w-full",
3164
3227
  "min-w-0",
3165
- "rounded-control",
3166
- "border",
3167
3228
  "[&:not([type='color'])]:px-3",
3168
3229
  "[&:not([type='color'])]:py-1",
3169
3230
  "[&[type='color']]:overflow-hidden",
@@ -3172,7 +3233,6 @@
3172
3233
  "[&::-webkit-color-swatch-wrapper]:rounded-0",
3173
3234
  "[&::-webkit-color-swatch-wrapper]:p-0",
3174
3235
  "text-base",
3175
- "shadow-input",
3176
3236
  "transition-[color,box-shadow]",
3177
3237
  "outline-none",
3178
3238
  "file:inline-flex",
@@ -3187,7 +3247,6 @@
3187
3247
  "md:text-sm",
3188
3248
  "focus-visible:border-ring",
3189
3249
  "focus-visible:ring-ring/50",
3190
- "focus-visible:ring-[calc(var(--spacing)*0.75)]",
3191
3250
  "aria-invalid:ring-negative/20",
3192
3251
  "dark:aria-invalid:ring-negative/40",
3193
3252
  "aria-invalid:border-negative",
@@ -3196,15 +3255,18 @@
3196
3255
  "invalid:!border-negative"
3197
3256
  );
3198
3257
  if (modifiers.includes("group")) {
3199
- el.classList.remove("rounded-control", "border", "bg-input-inner", "shadow-input", "focus-visible:ring-[calc(var(--spacing)*0.75)]");
3200
- el.classList.add("flex-1", "rounded-none", "border-0", "bg-transparent", "shadow-none", "focus-visible:ring-0");
3258
+ el.classList.add("h-full", "flex-1", "rounded-none", "border-0", "bg-transparent", "shadow-none", "focus-visible:ring-0");
3201
3259
  el.setAttribute("data-slot", "input-group-control");
3202
- } else el.setAttribute("data-slot", "input");
3203
- if (el.getAttribute("data-size") === "sm") el.classList.add("h-8");
3204
- else if (el.getAttribute("data-size") === "xs") el.classList.add("h-6.5");
3205
- else el.classList.add("h-9");
3260
+ } else {
3261
+ el.classList.add("w-full", "rounded-control", "border", "bg-input-inner", "shadow-input", "focus-visible:ring-[calc(var(--spacing)*0.75)]");
3262
+ el.setAttribute("data-slot", "input");
3263
+ const observer = sizeObserver(el);
3264
+ cleanup(() => {
3265
+ observer.disconnect();
3266
+ });
3267
+ }
3206
3268
  });
3207
- Alpine.directive("h-input-group", (el) => {
3269
+ Alpine.directive("h-input-group", (el, _, { cleanup }) => {
3208
3270
  el.classList.add(
3209
3271
  "group/input-group",
3210
3272
  "border-input",
@@ -3218,7 +3280,6 @@
3218
3280
  "shadow-input",
3219
3281
  "transition-[color,box-shadow]",
3220
3282
  "outline-none",
3221
- "h-9",
3222
3283
  "min-w-0",
3223
3284
  "has-[>textarea]:h-auto",
3224
3285
  "has-[>[data-align=inline-start]]:[&>input]:pl-2",
@@ -3238,6 +3299,10 @@
3238
3299
  );
3239
3300
  el.setAttribute("role", "group");
3240
3301
  el.setAttribute("data-slot", "input-group");
3302
+ const observer = sizeObserver(el);
3303
+ cleanup(() => {
3304
+ observer.disconnect();
3305
+ });
3241
3306
  });
3242
3307
  Alpine.directive("h-input-group-addon", (el, _, { cleanup }) => {
3243
3308
  el.classList.add(
@@ -3248,7 +3313,6 @@
3248
3313
  "items-center",
3249
3314
  "justify-center",
3250
3315
  "gap-2",
3251
- "py-1.5",
3252
3316
  "text-sm",
3253
3317
  "font-medium",
3254
3318
  "select-none",
@@ -3260,8 +3324,24 @@
3260
3324
  el.setAttribute("role", "group");
3261
3325
  el.setAttribute("data-slot", "input-group-addon");
3262
3326
  const variants = {
3263
- "inline-start": ["order-first", "pl-3", "has-[>button]:ml-[-0.45rem]", "has-[>[data-slot=tag]]:ml-[-0.35rem]"],
3264
- "inline-end": ["order-last", "pr-3", "has-[>button]:mr-[-0.45rem]", "has-[>[data-slot=tag]]:mr-[-0.35rem]"],
3327
+ "inline-start": [
3328
+ "order-first",
3329
+ "pl-3",
3330
+ "[[data-slot=input-group][data-size=sm]_&]:pl-1.25",
3331
+ "has-[>button]:pl-1.25",
3332
+ "[[data-slot=input-group][data-size=sm]_&]:has-[>button]:pl-0.5",
3333
+ "has-[>[data-slot|=tag]]:pl-1.5",
3334
+ "[[data-slot=input-group][data-size=sm]_&]:has-[>[data-slot|=tag]]:pl-0.5"
3335
+ ],
3336
+ "inline-end": [
3337
+ "order-last",
3338
+ "pr-3",
3339
+ "[[data-slot=input-group][data-size=sm]_&]:pr-1.25",
3340
+ "has-[>button]:pr-1.25",
3341
+ "[[data-slot=input-group][data-size=sm]_&]:has-[>button]:pr-0.5",
3342
+ "has-[>[data-slot|=tag]]:pr-1.5",
3343
+ "[[data-slot=input-group][data-size=sm]_&]:has-[>[data-slot|=tag]]:pr-0.5"
3344
+ ],
3265
3345
  "block-start": ["order-first", "w-full", "justify-start", "px-3", "pt-3", "[.border-b]:pb-3", "group-has-[>input]/input-group:pt-2.5"],
3266
3346
  "block-end": ["order-last", "w-full", "justify-start", "px-3", "pb-3", "[.border-t]:pt-3", "group-has-[>input]/input-group:pb-2.5"]
3267
3347
  };
@@ -3286,6 +3366,145 @@
3286
3366
  el.classList.add("text-muted-foreground", "flex", "items-center", "gap-2", "text-sm", "[&_svg]:pointer-events-none", "[&_svg:not([class*='size-'])]:size-4");
3287
3367
  el.setAttribute("data-slot", "label");
3288
3368
  });
3369
+ Alpine.directive("h-input-number", (el, { original }, { cleanup }) => {
3370
+ el.classList.add(
3371
+ "group/input-number",
3372
+ "border-input",
3373
+ "bg-input-inner",
3374
+ "relative",
3375
+ "flex",
3376
+ "w-full",
3377
+ "items-center",
3378
+ "rounded-control",
3379
+ "border",
3380
+ "shadow-input",
3381
+ "transition-[color,box-shadow]",
3382
+ "outline-none",
3383
+ "min-w-0",
3384
+ "has-[[data-slot=input-number-control]:focus-visible]:border-ring",
3385
+ "has-[[data-slot=input-number-control]:focus-visible]:ring-ring/50",
3386
+ "has-[[data-slot=input-number-control]:focus-visible]:ring-[calc(var(--spacing)*0.75)]",
3387
+ "has-[[data-slot][aria-invalid=true]]:ring-negative/20",
3388
+ "has-[[data-slot][aria-invalid=true]]:border-negative",
3389
+ "dark:has-[[data-slot][aria-invalid=true]]:ring-negative/40"
3390
+ );
3391
+ el.setAttribute("role", "group");
3392
+ el.setAttribute("data-slot", "input-number");
3393
+ const input = el.querySelector("input");
3394
+ if (!input || input.getAttribute("type") !== "number") {
3395
+ throw new Error(`${original} must contain an input of type 'number'`);
3396
+ }
3397
+ if (!input.hasAttribute("type")) input.setAttribute("type", "number");
3398
+ if (!input.hasAttribute("inputmode")) input.setAttribute("inputmode", "numeric");
3399
+ if (!input.hasAttribute("aria-roledescription")) {
3400
+ input.setAttribute("aria-roledescription", "Number field");
3401
+ }
3402
+ if (!input.hasAttribute("id")) {
3403
+ input.setAttribute("id", `in${v4_default()}`);
3404
+ }
3405
+ input.setAttribute("tabindex", "0");
3406
+ input.setAttribute("autocomplete", "off");
3407
+ input.setAttribute("autocorrect", "off");
3408
+ input.setAttribute("spellcheck", "off");
3409
+ input.setAttribute("data-slot", "input-number-control");
3410
+ input.classList.add("rounded-l-control", "size-full", "px-3", "py-1", "outline-none");
3411
+ const stepDown = document.createElement("button");
3412
+ stepDown.setAttribute("type", "button");
3413
+ stepDown.setAttribute("tabIndex", "-1");
3414
+ stepDown.setAttribute("aria-label", "Decrease");
3415
+ stepDown.setAttribute("aria-controls", input.getAttribute("id"));
3416
+ stepDown.setAttribute("data-slot", "step-up-trigger");
3417
+ stepDown.classList.add(
3418
+ "cursor-pointer",
3419
+ "border-l",
3420
+ "border-input",
3421
+ "[input[aria-invalid=true]~&]:border-negative",
3422
+ "[input:invalid~&]:border-negative",
3423
+ "h-full",
3424
+ "aspect-square",
3425
+ "bg-transparent",
3426
+ "hover:bg-secondary",
3427
+ "active:bg-secondary-active",
3428
+ "outline-none",
3429
+ "relative",
3430
+ "before:block",
3431
+ "before:opacity-70",
3432
+ "before:rounded-full",
3433
+ "before:h-0.5",
3434
+ "before:min-h-px",
3435
+ "before:w-3",
3436
+ "before:mx-auto",
3437
+ "before:bg-foreground",
3438
+ "before:hover:bg-secondary-foreground"
3439
+ );
3440
+ el.appendChild(stepDown);
3441
+ const onStepDown = () => {
3442
+ input.stepDown();
3443
+ input.dispatchEvent(new Event("input", { bubbles: true }));
3444
+ input.dispatchEvent(new Event("change", { bubbles: true }));
3445
+ };
3446
+ stepDown.addEventListener("click", onStepDown);
3447
+ const stepUp = document.createElement("button");
3448
+ stepUp.setAttribute("type", "button");
3449
+ stepUp.setAttribute("tabIndex", "-1");
3450
+ stepUp.setAttribute("aria-label", "Increase");
3451
+ stepUp.setAttribute("aria-controls", input.getAttribute("id"));
3452
+ stepUp.setAttribute("data-slot", "step-up-trigger");
3453
+ stepUp.classList.add(
3454
+ "cursor-pointer",
3455
+ "border-l",
3456
+ "border-input",
3457
+ "[input[aria-invalid=true]~&]:border-negative",
3458
+ "[input:invalid~&]:border-negative",
3459
+ "rounded-r-control",
3460
+ "h-full",
3461
+ "aspect-square",
3462
+ "bg-transparent",
3463
+ "hover:bg-secondary",
3464
+ "active:bg-secondary-active",
3465
+ "outline-none",
3466
+ "relative",
3467
+ "before:block",
3468
+ "before:opacity-70",
3469
+ "before:absolute",
3470
+ "before:rounded-full",
3471
+ "before:h-0.5",
3472
+ "before:min-h-px",
3473
+ "before:w-3",
3474
+ "before:top-1/2",
3475
+ "before:left-1/2",
3476
+ "before:-translate-x-1/2",
3477
+ "before:-translate-y-1/2",
3478
+ "before:bg-foreground",
3479
+ "before:hover:bg-secondary-foreground",
3480
+ "after:block",
3481
+ "after:opacity-70",
3482
+ "after:absolute",
3483
+ "after:rounded-full",
3484
+ "after:h-3",
3485
+ "after:min-w-px",
3486
+ "after:w-0.5",
3487
+ "after:top-1/2",
3488
+ "after:left-1/2",
3489
+ "after:-translate-x-1/2",
3490
+ "after:-translate-y-1/2",
3491
+ "after:bg-foreground",
3492
+ "after:hover:bg-secondary-foreground"
3493
+ );
3494
+ el.appendChild(stepUp);
3495
+ const onStepUp = () => {
3496
+ input.stepUp();
3497
+ input.dispatchEvent(new Event("input", { bubbles: true }));
3498
+ input.dispatchEvent(new Event("change", { bubbles: true }));
3499
+ };
3500
+ stepUp.addEventListener("click", onStepUp);
3501
+ const observer = sizeObserver(el);
3502
+ cleanup(() => {
3503
+ observer.disconnect();
3504
+ stepDown.removeEventListener("click", onStepDown);
3505
+ stepUp.removeEventListener("click", onStepUp);
3506
+ });
3507
+ });
3289
3508
  }
3290
3509
 
3291
3510
  // src/components/label.js
@@ -6279,30 +6498,10 @@
6279
6498
  "duration-200",
6280
6499
  "outline-none",
6281
6500
  "has-[input:disabled]:pointer-events-none",
6282
- "has-[input:disabled]:opacity-50",
6283
- "[&_svg]:pointer-events-none",
6284
- "[&_svg]:shrink-0",
6285
- "[&_svg]:size-4",
6286
- "[&_svg]:opacity-50"
6501
+ "has-[input:disabled]:opacity-50"
6287
6502
  );
6288
6503
  el.setAttribute("data-slot", "select");
6289
- const setSize = (size3) => {
6290
- if (size3 === "sm") {
6291
- el.classList.add("h-8");
6292
- el.classList.remove("h-9", "h-6.5");
6293
- } else if (size3 === "xs") {
6294
- el.classList.add("h-6.5");
6295
- el.classList.remove("h-9", "h-8");
6296
- } else {
6297
- el.classList.add("h-9");
6298
- el.classList.remove("h-8", "h-6.5");
6299
- }
6300
- };
6301
- setSize(el.getAttribute("data-size"));
6302
- const observer = new MutationObserver(() => {
6303
- setSize(el.getAttribute("data-size"));
6304
- });
6305
- observer.observe(el, { attributes: true, attributeFilter: ["data-size"] });
6504
+ const observer = sizeObserver(el);
6306
6505
  cleanup(() => {
6307
6506
  observer.disconnect();
6308
6507
  });
@@ -6537,7 +6736,7 @@
6537
6736
  fakeTrigger.addEventListener("keydown", onPress);
6538
6737
  fakeTrigger.addEventListener("click", onClick2);
6539
6738
  const chevronDown = createElement(ChevronDown, {
6540
- class: ["opacity-50 size-4 transition-transform duration-200"],
6739
+ class: ["opacity-70 text-foreground size-4 shrink-0 pointer-events-none transition-transform duration-200"],
6541
6740
  width: "16",
6542
6741
  height: "16",
6543
6742
  "aria-hidden": true,
@@ -7044,13 +7243,13 @@
7044
7243
  sm: ["h-7", "text-xs"],
7045
7244
  lg: ["h-12", "text-sm", "group-data-[collapsed=true]/sidebar:p-0!"]
7046
7245
  };
7047
- function setSize(size3) {
7246
+ function setSize2(size3) {
7048
7247
  if (sizes.hasOwnProperty(size3)) {
7049
7248
  el.classList.add(...sizes[size3]);
7050
7249
  }
7051
7250
  }
7052
7251
  if (!el.hasAttribute("data-size")) el.setAttribute("data-size", "default");
7053
- setSize(el.getAttribute("data-size"));
7252
+ setSize2(el.getAttribute("data-size"));
7054
7253
  });
7055
7254
  Alpine.directive("h-sidebar-menu-action", (el, { modifiers }) => {
7056
7255
  el.classList.add(
@@ -7182,13 +7381,13 @@
7182
7381
  sm: ["text-xs"],
7183
7382
  md: ["text-sm"]
7184
7383
  };
7185
- function setSize(size3) {
7384
+ function setSize2(size3) {
7186
7385
  if (sizes.hasOwnProperty(size3)) {
7187
7386
  el.classList.add(...sizes[size3]);
7188
7387
  }
7189
7388
  }
7190
7389
  if (!el.hasAttribute("data-size")) el.setAttribute("data-size", "md");
7191
- setSize(el.getAttribute("data-size"));
7390
+ setSize2(el.getAttribute("data-size"));
7192
7391
  });
7193
7392
  Alpine.directive("h-sidebar-footer", (el) => {
7194
7393
  el.classList.add("vbox", "gap-2", "px-2", "h-12", "justify-center", "border-t");
@@ -7204,10 +7403,10 @@
7204
7403
  if (modifiers.includes("control")) {
7205
7404
  el.classList.add("rounded-control");
7206
7405
  switch (el.getAttribute("data-size")) {
7207
- case "xs":
7406
+ case "sm":
7208
7407
  el.classList.add("h-6.5");
7209
7408
  break;
7210
- case "sm":
7409
+ case "md":
7211
7410
  el.classList.add("h-8");
7212
7411
  break;
7213
7412
  default:
@@ -7226,7 +7425,20 @@
7226
7425
  // src/components/spinner.js
7227
7426
  function spinner_default(Alpine) {
7228
7427
  Alpine.directive("h-spinner", (el) => {
7229
- el.classList.add("size-4", "border-2", "border-x-primary", "border-b-primary", "border-t-transparent", "rounded-full", "animate-spin");
7428
+ el.classList.add(
7429
+ "size-4",
7430
+ "border-2",
7431
+ "border-primary",
7432
+ "[[data-slot=button]_&]:border-secondary-foreground",
7433
+ "[[data-slot=button][data-variant=primary]_&]:border-primary-foreground",
7434
+ "[[data-slot=button][data-variant=positive]_&]:border-positive-foreground",
7435
+ "[[data-slot=button][data-variant=negative]_&]:border-negative-foreground",
7436
+ "[[data-slot=button][data-variant=warning]_&]:border-warning-foreground",
7437
+ "[[data-slot=button][data-variant=information]_&]:border-information-foreground",
7438
+ "!border-t-transparent",
7439
+ "rounded-full",
7440
+ "animate-spin"
7441
+ );
7230
7442
  el.setAttribute("role", "status");
7231
7443
  el.setAttribute("data-slot", "spinner");
7232
7444
  if (!el.hasAttribute("aria-label")) el.setAttribute("aria-label", "Loading");
@@ -7785,6 +7997,10 @@
7785
7997
  "group/tile",
7786
7998
  "flex",
7787
7999
  "items-center",
8000
+ "py-3",
8001
+ "px-4",
8002
+ "has-data-[slot=tile-header]:py-4",
8003
+ "gap-2.5",
7788
8004
  "text-sm",
7789
8005
  "rounded-lg",
7790
8006
  "transition-colors",
@@ -7799,14 +8015,6 @@
7799
8015
  "focus-visible:ring-[calc(var(--spacing)*0.75)]"
7800
8016
  );
7801
8017
  el.setAttribute("data-slot", "tile");
7802
- const sizes = {
7803
- default: ["p-4", "gap-4"],
7804
- sm: ["py-3", "px-4", "gap-2.5"]
7805
- };
7806
- function setSize(size3) {
7807
- el.classList.add(...sizes[size3]);
7808
- el.setAttribute("data-size", size3);
7809
- }
7810
8018
  switch (el.getAttribute("data-variant")) {
7811
8019
  case "outline":
7812
8020
  el.classList.add("border", "border-border");
@@ -7820,9 +8028,6 @@
7820
8028
  default:
7821
8029
  el.classList.add("border", "bg-transparent", "border-transparent");
7822
8030
  }
7823
- if (el.getAttribute("data-size") === "sm") {
7824
- setSize("sm");
7825
- } else setSize("sm");
7826
8031
  });
7827
8032
  Alpine.directive("h-tile-header", (el) => {
7828
8033
  el.classList.add("flex", "basis-full", "items-center", "justify-between", "gap-2");
@@ -7948,12 +8153,12 @@
7948
8153
  "has-[input:focus-visible]:border-ring",
7949
8154
  "has-[input:focus-visible]:ring-[calc(var(--spacing)*0.75)]",
7950
8155
  "has-[input:focus-visible]:ring-ring/50",
7951
- "dark:has-[aria-invalid=true]:ring-negative/40",
7952
- "dark:has-[input:invalid]:ring-negative/40",
7953
- "has-[aria-invalid=true]:border-negative",
7954
- "has-[aria-invalid=true]:ring-negative/20",
7955
- "has-[input:invalid]:border-negative",
8156
+ "has-[input[aria-invalid=true]]:ring-negative/20",
8157
+ "has-[input[aria-invalid=true]]:border-negative",
8158
+ "dark:has-[input[aria-invalid=true]]:ring-negative/40",
7956
8159
  "has-[input:invalid]:ring-negative/20",
8160
+ "has-[input:invalid]:border-negative",
8161
+ "dark:has-[input:invalid]:ring-negative/40",
7957
8162
  "hover:bg-secondary-hover",
7958
8163
  "active:bg-secondary-active",
7959
8164
  "flex",
@@ -7961,12 +8166,12 @@
7961
8166
  "items-center",
7962
8167
  "justify-between",
7963
8168
  "gap-2",
7964
- "h-9",
7965
8169
  "rounded-control",
7966
8170
  "border",
7967
8171
  "bg-input-inner",
7968
8172
  "pl-3",
7969
8173
  "pr-2",
8174
+ "data-[size=sm]:pr-1",
7970
8175
  "text-sm",
7971
8176
  "whitespace-nowrap",
7972
8177
  "shadow-input",
@@ -7974,17 +8179,13 @@
7974
8179
  "duration-200",
7975
8180
  "outline-none",
7976
8181
  "has-[input:disabled]:pointer-events-none",
7977
- "has-[input:disabled]:opacity-50",
7978
- "[&_svg]:pointer-events-none",
7979
- "[&_svg]:shrink-0",
7980
- "[&_svg]:size-4",
7981
- "[&_svg]:opacity-50"
8182
+ "has-[input:disabled]:opacity-50"
7982
8183
  );
7983
8184
  el.setAttribute("data-slot", "time-picker");
7984
8185
  el.setAttribute("tabindex", "-1");
7985
8186
  el.appendChild(
7986
8187
  createElement(Clock, {
7987
- class: ["opacity-50 size-4 transition-transform duration-200"],
8188
+ class: ["opacity-70 text-foreground size-4 shrink-0 pointer-events-none"],
7988
8189
  width: "16",
7989
8190
  height: "16",
7990
8191
  "aria-hidden": true,
@@ -8023,13 +8224,15 @@
8023
8224
  };
8024
8225
  el.addEventListener("click", handler);
8025
8226
  el.addEventListener("keydown", handler);
8227
+ const observer = sizeObserver(el);
8026
8228
  cleanup(() => {
8229
+ observer.disconnect();
8027
8230
  el.removeEventListener("click", handler);
8028
8231
  el.removeEventListener("keydown", handler);
8029
8232
  top.removeEventListener("click", el._h_timepicker.close);
8030
8233
  });
8031
8234
  });
8032
- Alpine.directive("h-time-picker-input", (el, { original }, { effect, Alpine: Alpine2 }) => {
8235
+ Alpine.directive("h-time-picker-input", (el, { original }, { effect, cleanup, Alpine: Alpine2 }) => {
8033
8236
  if (el.tagName !== "INPUT") {
8034
8237
  throw new Error(`${original} must be a readonly input of type "text"`);
8035
8238
  }
@@ -8063,8 +8266,7 @@
8063
8266
  timepicker._h_timepicker.id = `htp${v4_default()}`;
8064
8267
  el.setAttribute("id", timepicker._h_timepicker.id);
8065
8268
  }
8066
- el.classList.add("cursor-pointer", "bg-transparent", "text-transparent", "text-shadow-[0_0_0_var(--foreground)]", "outline-none", "flex-1", "h-full", "border-0", "md:text-sm", "text-base");
8067
- el.readOnly = true;
8269
+ el.classList.add("cursor-pointer", "bg-transparent", "text-transparent", "text-shadow-[0_0_0_var(--foreground)]", "placeholder:text-muted-foreground", "outline-none", "size-full", "border-0", "md:text-sm", "text-base", "truncate");
8068
8270
  el.setAttribute("aria-autocomplete", "none");
8069
8271
  el.setAttribute("aria-controls", timepicker._h_timepicker.controls);
8070
8272
  el.setAttribute("aria-expanded", "false");
@@ -8107,11 +8309,20 @@
8107
8309
  placeholder = timepicker._h_timepicker.is12Hour ? "--:-- --" : "--:--";
8108
8310
  }
8109
8311
  el.setAttribute("placeholder", placeholder);
8312
+ const preventInput = (event) => {
8313
+ event.preventDefault();
8314
+ };
8315
+ el.addEventListener("beforeinput", preventInput);
8316
+ el.addEventListener("paste", preventInput);
8110
8317
  effect(() => {
8111
8318
  el.setAttribute("data-state", timepicker._h_timepicker.expanded ? "open" : "closed");
8112
8319
  el.setAttribute("aria-expanded", timepicker._h_timepicker.expanded);
8113
8320
  });
8114
- }).before("h-button");
8321
+ cleanup(() => {
8322
+ el.removeEventListener("keydown", preventInput);
8323
+ el.removeEventListener("paste", preventInput);
8324
+ });
8325
+ });
8115
8326
  Alpine.directive("h-time-picker-popup", (el, _, { effect, cleanup, Alpine: Alpine2 }) => {
8116
8327
  const timepicker = Alpine2.findClosest(el.parentElement, (parent) => parent.hasOwnProperty("_h_timepicker"));
8117
8328
  el.classList.add(
@@ -8128,6 +8339,7 @@
8128
8339
  "z-50",
8129
8340
  "shadow-md"
8130
8341
  );
8342
+ el.setAttribute("id", timepicker._h_timepicker.controls);
8131
8343
  el.setAttribute("tabindex", "-1");
8132
8344
  el.setAttribute("role", "dialog");
8133
8345
  el.setAttribute("aria-modal", "true");
@@ -8324,7 +8536,7 @@
8324
8536
  }
8325
8537
  }
8326
8538
  const timeContainer = document.createElement("div");
8327
- timeContainer.classList.add("hbox", "max-h-[18rem]", "[&>ul]:border-r", "[&>ul:last-of-type]:border-r-0");
8539
+ timeContainer.classList.add("hbox", "max-h-[14rem]", "[&>ul]:border-r", "[&>ul:last-of-type]:border-r-0");
8328
8540
  if (el.firstChild) el.classList.add("border-b");
8329
8541
  timeContainer.setAttribute("role", "group");
8330
8542
  timeContainer.addEventListener("click", setTime);
@@ -8411,6 +8623,7 @@
8411
8623
  footer.classList.add("hbox", "justify-between", "gap-1", "border-t", "p-2");
8412
8624
  footer.setAttribute("tabindex", "-1");
8413
8625
  const nowButton = document.createElement("button");
8626
+ nowButton.setAttribute("type", "button");
8414
8627
  nowButton.setAttribute(Alpine2.prefixed("h-button"), "");
8415
8628
  nowButton.setAttribute("data-size", "sm");
8416
8629
  nowButton.setAttribute("data-action", "time");
@@ -8418,6 +8631,7 @@
8418
8631
  nowButton.addEventListener("click", getCurrentTime);
8419
8632
  footer.appendChild(nowButton);
8420
8633
  const okButton = document.createElement("button");
8634
+ okButton.setAttribute("type", "button");
8421
8635
  okButton.setAttribute(Alpine2.prefixed("h-button"), "");
8422
8636
  okButton.setAttribute("data-variant", "primary");
8423
8637
  okButton.setAttribute("data-size", "sm");
@@ -9077,7 +9291,7 @@
9077
9291
  }
9078
9292
 
9079
9293
  // package.json
9080
- var version = "0.9.1";
9294
+ var version = "1.1.0";
9081
9295
 
9082
9296
  // src/index.js
9083
9297
  window.Harmonia = { getBreakpointListener, addColorSchemeListener, getColorScheme, removeColorSchemeListener, setColorScheme, version };