banhaten 0.1.0 → 0.1.2

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 (81) hide show
  1. package/README.md +21 -9
  2. package/package.json +8 -2
  3. package/registry/components/accordion.tsx +37 -1
  4. package/registry/components/alert.tsx +14 -28
  5. package/registry/components/attribute.tsx +6 -10
  6. package/registry/components/autocomplete.tsx +637 -0
  7. package/registry/components/avatar.tsx +259 -24
  8. package/registry/components/badge.tsx +97 -35
  9. package/registry/components/button-group.tsx +1 -1
  10. package/registry/components/card.tsx +1 -1
  11. package/registry/components/checkbox.tsx +19 -16
  12. package/registry/components/date-picker-state.ts +253 -0
  13. package/registry/components/date-picker.tsx +115 -158
  14. package/registry/components/expanded/ActivityFeed.tsx +37 -23
  15. package/registry/components/expanded/Banner.tsx +54 -19
  16. package/registry/components/expanded/Breadcrumbs.tsx +10 -38
  17. package/registry/components/expanded/CatalogComponentsShowcase.tsx +11 -16
  18. package/registry/components/expanded/CatalogTag.tsx +4 -11
  19. package/registry/components/expanded/CommandBar.tsx +33 -53
  20. package/registry/components/expanded/EmptyState.tsx +155 -0
  21. package/registry/components/expanded/FileUpload.tsx +362 -59
  22. package/registry/components/expanded/OnboardingStepListItem.tsx +6 -10
  23. package/registry/components/expanded/PageHeader.tsx +2 -11
  24. package/registry/components/expanded/Slideout.tsx +12 -23
  25. package/registry/components/expanded/Steps.tsx +6 -8
  26. package/registry/components/expanded/Table.tsx +18 -40
  27. package/registry/components/expanded/Timeline.tsx +5 -24
  28. package/registry/components/expanded/activityFeed.css +10 -54
  29. package/registry/components/expanded/banner.css +8 -75
  30. package/registry/components/expanded/breadcrumbs.css +1 -1
  31. package/registry/components/expanded/commandBar.css +23 -26
  32. package/registry/components/expanded/divider.css +1 -1
  33. package/registry/components/expanded/emptyState.css +111 -0
  34. package/registry/components/expanded/fileUpload.css +304 -75
  35. package/registry/components/expanded/pageHeader.css +1 -1
  36. package/registry/components/expanded/slideout.css +1 -0
  37. package/registry/components/expanded/steps.css +15 -51
  38. package/registry/components/expanded/table.css +6 -1
  39. package/registry/components/expanded/timeline.css +18 -15
  40. package/registry/components/input-otp.tsx +574 -0
  41. package/registry/components/input.tsx +140 -59
  42. package/registry/components/menu.tsx +470 -80
  43. package/registry/components/pagination.tsx +6 -18
  44. package/registry/components/popover.tsx +840 -0
  45. package/registry/components/radio-card.tsx +25 -31
  46. package/registry/components/select-content.tsx +28 -123
  47. package/registry/components/select.tsx +13 -9
  48. package/registry/components/skeleton.css +57 -0
  49. package/registry/components/skeleton.tsx +482 -0
  50. package/registry/components/social-button.tsx +24 -90
  51. package/registry/components/spinner.tsx +91 -7
  52. package/registry/components/textarea.tsx +21 -36
  53. package/registry/components/toggle.tsx +7 -23
  54. package/registry/components/tooltip.tsx +8 -4
  55. package/registry/examples/attribute-demo.tsx +2 -2
  56. package/registry/examples/autocomplete-demo.tsx +109 -0
  57. package/registry/examples/avatar-demo.tsx +102 -47
  58. package/registry/examples/badge-demo.tsx +16 -0
  59. package/registry/examples/checkbox-demo.tsx +3 -8
  60. package/registry/examples/date-picker-demo.tsx +75 -22
  61. package/registry/examples/expanded/banner-demo.tsx +31 -6
  62. package/registry/examples/expanded/breadcrumbs-demo.tsx +59 -0
  63. package/registry/examples/expanded/command-bar-demo.tsx +236 -0
  64. package/registry/examples/expanded/empty-state-demo.tsx +39 -0
  65. package/registry/examples/expanded/file-upload-demo.tsx +60 -0
  66. package/registry/examples/expanded/steps-demo.tsx +11 -0
  67. package/registry/examples/expanded/table-demo.tsx +142 -0
  68. package/registry/examples/input-demo.tsx +1 -1
  69. package/registry/examples/input-otp-demo.tsx +72 -0
  70. package/registry/examples/menu-demo.tsx +101 -88
  71. package/registry/examples/popover-demo.tsx +546 -0
  72. package/registry/examples/progress-demo.tsx +2 -2
  73. package/registry/examples/select-demo.tsx +32 -18
  74. package/registry/examples/skeleton-demo.tsx +56 -0
  75. package/registry/examples/social-button-demo.tsx +33 -33
  76. package/registry/examples/spinner-demo.tsx +59 -0
  77. package/registry/examples/tag-demo.tsx +1 -1
  78. package/registry/examples/textarea-demo.tsx +1 -1
  79. package/registry/index.json +266 -20
  80. package/registry/styles/globals.css +93 -3
  81. package/src/cli/index.js +997 -62
@@ -1,5 +1,12 @@
1
1
  import * as React from "react"
2
2
  import { cva } from "class-variance-authority"
3
+ import {
4
+ AtSignIcon,
5
+ ChevronDownIcon,
6
+ InfoIcon,
7
+ MinusIcon as LucideMinusIcon,
8
+ PlusIcon as LucidePlusIcon,
9
+ } from "lucide-react"
3
10
 
4
11
  import { cn } from "@/lib/utils"
5
12
  import {
@@ -85,7 +92,13 @@ const inputSurface = cva(
85
92
  "group/input-surface relative flex w-full overflow-hidden rounded-[var(--bh-input-radius)]",
86
93
  "transition-[background-color,box-shadow]",
87
94
  "[--bh-input-border:var(--bh-border-input)] [--shadow-input:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-input-border,var(--bh-border-input)),var(--shadow-component-default)]",
88
- "focus-within:shadow-[var(--shadow-input-focus-ring)]",
95
+ "[--shadow-input-surface:var(--shadow-component-default)]",
96
+ "[--shadow-input-overlay:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-input-border,var(--bh-border-input))]",
97
+ "[--shadow-input-focus-surface:0px_0px_0px_var(--bh-focus-ring-width)_color-mix(in_srgb,var(--bh-border-focus)_30%,transparent)]",
98
+ "[--shadow-input-focus-overlay:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-border-focus)]",
99
+ "[--shadow-input-disabled-overlay:inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-border-disabled)]",
100
+ "after:pointer-events-none after:absolute after:inset-0 after:z-[var(--bh-z-raised)] after:rounded-[inherit] after:[box-shadow:var(--shadow-input-overlay)] after:content-['']",
101
+ "focus-within:shadow-[var(--shadow-input-focus-surface)] focus-within:after:[box-shadow:var(--shadow-input-focus-overlay)]",
89
102
  ],
90
103
  {
91
104
  variants: {
@@ -99,13 +112,13 @@ const inputSurface = cva(
99
112
  },
100
113
  state: {
101
114
  default:
102
- "shadow-[var(--shadow-input)]",
115
+ "shadow-[var(--shadow-input-surface)]",
103
116
  filled:
104
- "shadow-[var(--shadow-input)]",
117
+ "shadow-[var(--shadow-input-surface)]",
105
118
  error:
106
- "[--bh-input-border:var(--bh-border-danger-strong)] shadow-[var(--shadow-input)] focus-within:shadow-[var(--shadow-input)]",
119
+ "[--bh-input-border:var(--bh-border-danger-strong)] shadow-[var(--shadow-input-surface)] focus-within:shadow-[var(--shadow-input-surface)] focus-within:after:[box-shadow:var(--shadow-input-overlay)]",
107
120
  disabled:
108
- "bg-[var(--bh-interactive-input-disabled)] shadow-[inset_0px_0px_0px_var(--bh-border-width-default)_var(--bh-border-disabled)]",
121
+ "[--bh-input-border:var(--bh-border-disabled)] bg-[var(--bh-interactive-input-disabled)] shadow-none after:[box-shadow:var(--shadow-input-disabled-overlay)]",
109
122
  },
110
123
  },
111
124
  compoundVariants: [
@@ -178,7 +191,7 @@ const inputTag = cva(
178
191
  const inputSegment = cva(
179
192
  [
180
193
  "inline-flex h-full shrink-0 items-center justify-center gap-[var(--bh-input-segment-gap)]",
181
- "bg-[var(--bh-interactive-secondary-default)] px-[var(--bh-input-segment-padding-x)]",
194
+ "bg-transparent px-[var(--bh-input-segment-padding-x)]",
182
195
  "text-[length:var(--bh-text-body-md-regular-font-size)]",
183
196
  "font-[var(--bh-text-body-md-regular-font-weight)]",
184
197
  "leading-[var(--bh-text-body-md-regular-line-height)]",
@@ -199,7 +212,7 @@ const inputSegment = cva(
199
212
  },
200
213
  disabled: {
201
214
  true:
202
- "border-[var(--bh-border-disabled)] bg-[var(--bh-interactive-secondary-disabled)] text-[var(--bh-content-disabled)]",
215
+ "border-[var(--bh-border-disabled)] text-[var(--bh-content-disabled)]",
203
216
  false: "",
204
217
  },
205
218
  },
@@ -211,6 +224,27 @@ const inputSegment = cva(
211
224
  }
212
225
  )
213
226
 
227
+ const inputStepperButton = cva(
228
+ [
229
+ "inline-flex h-full w-[var(--bh-input-stepper-width,var(--bh-input-lg-height))] shrink-0 items-center justify-center",
230
+ "bg-transparent text-[var(--bh-content-subtle)]",
231
+ "outline-none transition-[background-color,color]",
232
+ "hover:bg-[var(--bh-interactive-secondary-hover)] focus-visible:bg-[var(--bh-interactive-secondary-hover)]",
233
+ "disabled:border-[var(--bh-border-disabled)] disabled:bg-transparent disabled:text-[var(--bh-content-disabled)]",
234
+ ],
235
+ {
236
+ variants: {
237
+ side: {
238
+ leading: "border-e border-[var(--bh-border-input)]",
239
+ trailing: "border-s border-[var(--bh-border-input)]",
240
+ },
241
+ },
242
+ defaultVariants: {
243
+ side: "trailing",
244
+ },
245
+ }
246
+ )
247
+
214
248
  const Input = React.forwardRef<HTMLInputElement, InputProps>(
215
249
  (
216
250
  {
@@ -352,6 +386,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
352
386
  kind,
353
387
  leadingAddon,
354
388
  quantityLabel,
389
+ size,
355
390
  trailingAddon,
356
391
  })}
357
392
 
@@ -414,6 +449,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
414
449
  kind,
415
450
  leadingAddon,
416
451
  quantityLabel,
452
+ size,
417
453
  trailingAddon,
418
454
  })}
419
455
  </div>
@@ -552,7 +588,14 @@ function InputLeadingIcon({
552
588
  disabled && "text-[var(--bh-content-disabled)]"
553
589
  )}
554
590
  >
555
- {icon || <span className="text-[length:var(--bh-input-leading-symbol-font-size)] leading-none">@</span>}
591
+ {icon || (
592
+ <AtSignIcon
593
+ aria-hidden="true"
594
+ className="size-[var(--bh-input-icon-size)]"
595
+ focusable="false"
596
+ strokeWidth={2.25}
597
+ />
598
+ )}
556
599
  </span>
557
600
  )
558
601
  }
@@ -577,17 +620,12 @@ function InputInfoIcon({
577
620
  )}
578
621
  >
579
622
  {icon || (
580
- <svg
623
+ <InfoIcon
624
+ aria-hidden="true"
581
625
  className="size-[var(--bh-input-info-icon-size)]"
582
- fill="none"
583
626
  focusable="false"
584
- viewBox="0 0 16 16"
585
- >
586
- <path
587
- d="M8 14.6667C4.3181 14.6667 1.33333 11.6819 1.33333 8C1.33333 4.3181 4.3181 1.33333 8 1.33333C11.6819 1.33333 14.6667 4.3181 14.6667 8C14.6667 11.6819 11.6819 14.6667 8 14.6667ZM8 6.33333C8.55227 6.33333 9 5.88562 9 5.33333C9 4.78105 8.55227 4.33333 8 4.33333C7.44773 4.33333 7 4.78105 7 5.33333C7 5.88562 7.44773 6.33333 8 6.33333ZM9.33333 10H8.66667V7H6.66667V8.33333H7.33333V10H6.66667V11.3333H9.33333V10Z"
588
- fill="currentColor"
589
- />
590
- </svg>
627
+ strokeWidth={2.25}
628
+ />
591
629
  )}
592
630
  </span>
593
631
  )
@@ -699,12 +737,46 @@ function InputSegment({
699
737
  )
700
738
  }
701
739
 
740
+ function InputStepperButton({
741
+ children,
742
+ disabled,
743
+ label,
744
+ side,
745
+ size,
746
+ }: {
747
+ children: React.ReactNode
748
+ disabled: boolean
749
+ label: string
750
+ side: "leading" | "trailing"
751
+ size: InputSize
752
+ }) {
753
+ return (
754
+ <button
755
+ aria-label={label}
756
+ data-side={side}
757
+ data-slot="input-stepper-button"
758
+ disabled={disabled}
759
+ type="button"
760
+ className={cn(
761
+ inputStepperButton({ side }),
762
+ size === "md" && "w-[var(--bh-input-md-height)]"
763
+ )}
764
+ onClick={(event) => {
765
+ event.stopPropagation()
766
+ }}
767
+ >
768
+ {children}
769
+ </button>
770
+ )
771
+ }
772
+
702
773
  type InputSegmentRenderContext = {
703
774
  buttonLabel?: React.ReactNode
704
775
  disabled: boolean
705
776
  kind: InputKind
706
777
  leadingAddon?: React.ReactNode
707
778
  quantityLabel?: React.ReactNode
779
+ size: InputSize
708
780
  trailingAddon?: React.ReactNode
709
781
  }
710
782
 
@@ -731,13 +803,25 @@ const leadingSegmentRenderers: Partial<Record<InputKind, InputSegmentRenderer>>
731
803
  <ChevronIcon />
732
804
  </InputSegment>
733
805
  ),
734
- "quantity-2": ({ disabled, quantityLabel }) => (
735
- <InputSegment disabled={disabled} interactive side="leading">
806
+ quantity: ({ disabled, quantityLabel, size }) => (
807
+ <InputStepperButton
808
+ disabled={disabled}
809
+ label={formatStepperLabel("Decrease", quantityLabel)}
810
+ side="leading"
811
+ size={size}
812
+ >
736
813
  <MinusIcon />
737
- {hasRenderableContent(quantityLabel) ? (
738
- <span className="sr-only">{quantityLabel}</span>
739
- ) : null}
740
- </InputSegment>
814
+ </InputStepperButton>
815
+ ),
816
+ "quantity-2": ({ disabled, quantityLabel, size }) => (
817
+ <InputStepperButton
818
+ disabled={disabled}
819
+ label={formatStepperLabel("Decrease", quantityLabel)}
820
+ side="leading"
821
+ size={size}
822
+ >
823
+ <MinusIcon />
824
+ </InputStepperButton>
741
825
  ),
742
826
  }
743
827
 
@@ -760,17 +844,25 @@ const trailingSegmentRenderers: Partial<Record<InputKind, InputSegmentRenderer>>
760
844
  <ChevronIcon />
761
845
  </InputSegment>
762
846
  ),
763
- quantity: ({ disabled }) => (
764
- <InputSegment disabled={disabled} interactive side="trailing">
765
- <MinusIcon />
847
+ quantity: ({ disabled, quantityLabel, size }) => (
848
+ <InputStepperButton
849
+ disabled={disabled}
850
+ label={formatStepperLabel("Increase", quantityLabel)}
851
+ side="trailing"
852
+ size={size}
853
+ >
766
854
  <PlusIcon />
767
- </InputSegment>
855
+ </InputStepperButton>
768
856
  ),
769
- "quantity-2": ({ disabled }) => (
770
- <InputSegment disabled={disabled} interactive side="trailing">
771
- <MinusIcon />
857
+ "quantity-2": ({ disabled, quantityLabel, size }) => (
858
+ <InputStepperButton
859
+ disabled={disabled}
860
+ label={formatStepperLabel("Increase", quantityLabel)}
861
+ side="trailing"
862
+ size={size}
863
+ >
772
864
  <PlusIcon />
773
- </InputSegment>
865
+ </InputStepperButton>
774
866
  ),
775
867
  }
776
868
 
@@ -782,51 +874,42 @@ function renderTrailingSegment(context: InputSegmentRenderContext) {
782
874
  return trailingSegmentRenderers[context.kind]?.(context) ?? null
783
875
  }
784
876
 
877
+ function formatStepperLabel(action: "Decrease" | "Increase", quantityLabel?: React.ReactNode) {
878
+ return typeof quantityLabel === "string" && quantityLabel.trim()
879
+ ? `${action} ${quantityLabel}`
880
+ : action
881
+ }
882
+
785
883
  function ChevronIcon() {
786
884
  return (
787
- <svg
885
+ <ChevronDownIcon
788
886
  aria-hidden="true"
789
887
  className="size-[var(--bh-input-chevron-size)]"
790
- fill="none"
791
888
  focusable="false"
792
- viewBox="0 0 16 16"
793
- >
794
- <path
795
- d="M8 10.6667L4 6.66667L4.93333 5.73333L8 8.8L11.0667 5.73333L12 6.66667L8 10.6667Z"
796
- fill="currentColor"
797
- />
798
- </svg>
889
+ strokeWidth={2.25}
890
+ />
799
891
  )
800
892
  }
801
893
 
802
894
  function MinusIcon() {
803
895
  return (
804
- <svg
896
+ <LucideMinusIcon
805
897
  aria-hidden="true"
806
898
  className="size-[var(--bh-input-stepper-icon-size)]"
807
- fill="none"
808
899
  focusable="false"
809
- viewBox="0 0 16 16"
810
- >
811
- <path d="M3.33333 7.33333H12.6667V8.66667H3.33333V7.33333Z" fill="currentColor" />
812
- </svg>
900
+ strokeWidth={2.25}
901
+ />
813
902
  )
814
903
  }
815
904
 
816
905
  function PlusIcon() {
817
906
  return (
818
- <svg
907
+ <LucidePlusIcon
819
908
  aria-hidden="true"
820
909
  className="size-[var(--bh-input-stepper-icon-size)]"
821
- fill="none"
822
910
  focusable="false"
823
- viewBox="0 0 16 16"
824
- >
825
- <path
826
- d="M7.33333 7.33333V3.33333H8.66667V7.33333H12.6667V8.66667H8.66667V12.6667H7.33333V8.66667H3.33333V7.33333H7.33333Z"
827
- fill="currentColor"
828
- />
829
- </svg>
911
+ strokeWidth={2.25}
912
+ />
830
913
  )
831
914
  }
832
915
 
@@ -836,10 +919,6 @@ function shouldRenderLeadingIcon(kind: InputKind) {
836
919
  "shortcut",
837
920
  "tags",
838
921
  "inline-tags",
839
- "trailing-dropdown",
840
- "leading-dropdown",
841
- "trailing-button",
842
- "leading-button",
843
922
  ].includes(kind)
844
923
  }
845
924
 
@@ -848,6 +927,8 @@ function shouldRenderInfoIcon(kind: InputKind, hasInformationIcon: boolean) {
848
927
 
849
928
  return ![
850
929
  "shortcut",
930
+ "leading-dropdown",
931
+ "leading-button",
851
932
  "trailing-dropdown",
852
933
  "trailing-button",
853
934
  "quantity",