banhaten 0.2.0 → 0.4.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.
Files changed (120) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +5 -5
  3. package/docs/design-system/component-implementation-ownership-audit.md +245 -0
  4. package/docs/design-system/component-quality-audit-2026-08-20.md +225 -0
  5. package/docs/design-system/component-showcase-consistency-report.md +2 -0
  6. package/docs/design-system/components/README.md +1 -0
  7. package/docs/design-system/components/activity-feed.md +2 -0
  8. package/docs/design-system/components/activity-heatmap.md +73 -0
  9. package/docs/design-system/components/alert-dialog.md +1 -1
  10. package/docs/design-system/components/alert.md +3 -3
  11. package/docs/design-system/components/attribute.md +1 -1
  12. package/docs/design-system/components/avatar.md +2 -2
  13. package/docs/design-system/components/badge.md +1 -1
  14. package/docs/design-system/components/banner.md +6 -2
  15. package/docs/design-system/components/breadcrumbs.md +5 -2
  16. package/docs/design-system/components/button-group.md +3 -2
  17. package/docs/design-system/components/button.md +2 -2
  18. package/docs/design-system/components/card.md +11 -3
  19. package/docs/design-system/components/catalog-components.md +3 -0
  20. package/docs/design-system/components/date-picker.md +3 -1
  21. package/docs/design-system/components/file-upload.md +5 -1
  22. package/docs/design-system/components/input.md +8 -6
  23. package/docs/design-system/components/item.md +3 -1
  24. package/docs/design-system/components/kbd.md +11 -8
  25. package/docs/design-system/components/menu.md +2 -2
  26. package/docs/design-system/components/modal.md +1 -1
  27. package/docs/design-system/components/navigation-menu.md +1 -1
  28. package/docs/design-system/components/onboarding-step-list-item.md +3 -2
  29. package/docs/design-system/components/page-header.md +3 -1
  30. package/docs/design-system/components/pagination.md +3 -2
  31. package/docs/design-system/components/radio-card.md +1 -1
  32. package/docs/design-system/components/resizable.md +1 -1
  33. package/docs/design-system/components/scroll-area.md +7 -3
  34. package/docs/design-system/components/select.md +1 -1
  35. package/docs/design-system/components/sidebar.md +60 -18
  36. package/docs/design-system/components/slideout.md +4 -1
  37. package/docs/design-system/components/steps.md +7 -2
  38. package/docs/design-system/components/table.md +25 -7
  39. package/docs/design-system/components/tag.md +3 -3
  40. package/docs/design-system/components/timeline.md +4 -1
  41. package/docs/design-system/components/toggle.md +1 -1
  42. package/docs/design-system/components/toolbar.md +1 -1
  43. package/docs/design-system/components/tooltip.md +1 -1
  44. package/docs/design-system/density-and-elevation.md +23 -2
  45. package/docs/design-system/gap-promotion-report.md +1 -67
  46. package/docs/design-system/icons.md +6 -1
  47. package/docs/design-system/installation.md +1 -1
  48. package/docs/design-system/launch-comparison-shadcn.md +10 -10
  49. package/docs/design-system/token-governance.md +7 -8
  50. package/package.json +3 -2
  51. package/registry/components/alert-dialog.tsx +1 -1
  52. package/registry/components/alert.tsx +17 -13
  53. package/registry/components/attribute.tsx +8 -2
  54. package/registry/components/avatar.tsx +28 -20
  55. package/registry/components/badge.tsx +17 -17
  56. package/registry/components/button-group.tsx +4 -2
  57. package/registry/components/button.tsx +3 -3
  58. package/registry/components/card.tsx +19 -3
  59. package/registry/components/carousel.tsx +14 -0
  60. package/registry/components/command.tsx +37 -3
  61. package/registry/components/date-picker.tsx +83 -35
  62. package/registry/components/expanded/ActivityFeed.tsx +3 -7
  63. package/registry/components/expanded/ActivityHeatmap.tsx +64 -0
  64. package/registry/components/expanded/Banner.tsx +0 -1
  65. package/registry/components/expanded/Breadcrumbs.tsx +3 -0
  66. package/registry/components/expanded/CatalogComponentsShowcase.tsx +3 -4
  67. package/registry/components/expanded/CatalogDivider.tsx +3 -2
  68. package/registry/components/expanded/FileUpload.tsx +7 -5
  69. package/registry/components/expanded/OnboardingStepListItem.tsx +6 -7
  70. package/registry/components/expanded/PageHeader.tsx +35 -44
  71. package/registry/components/expanded/Slideout.tsx +18 -13
  72. package/registry/components/expanded/Steps.tsx +147 -9
  73. package/registry/components/expanded/Table.tsx +50 -18
  74. package/registry/components/expanded/Timeline.tsx +11 -24
  75. package/registry/components/expanded/activityFeed.css +8 -8
  76. package/registry/components/expanded/activityHeatmap.css +66 -0
  77. package/registry/components/expanded/banner.css +30 -15
  78. package/registry/components/expanded/breadcrumbs.css +5 -5
  79. package/registry/components/expanded/fileUpload.css +4 -4
  80. package/registry/components/expanded/onboardingStepListItem.css +16 -7
  81. package/registry/components/expanded/pageHeader.css +14 -11
  82. package/registry/components/expanded/slideout.css +3 -7
  83. package/registry/components/expanded/steps.css +75 -12
  84. package/registry/components/expanded/table.css +63 -69
  85. package/registry/components/expanded/timeline.css +17 -16
  86. package/registry/components/field.tsx +61 -8
  87. package/registry/components/input.tsx +12 -5
  88. package/registry/components/item.tsx +1 -1
  89. package/registry/components/kbd.tsx +109 -15
  90. package/registry/components/menu.tsx +57 -7
  91. package/registry/components/modal.tsx +1 -1
  92. package/registry/components/navigation-menu.tsx +1 -1
  93. package/registry/components/pagination.css +36 -0
  94. package/registry/components/pagination.tsx +20 -13
  95. package/registry/components/progress-slider.tsx +1 -1
  96. package/registry/components/radio-card.tsx +1 -2
  97. package/registry/components/resizable.tsx +36 -2
  98. package/registry/components/scroll-area.tsx +30 -6
  99. package/registry/components/select.tsx +35 -12
  100. package/registry/components/sidebar.tsx +940 -62
  101. package/registry/components/social-button.tsx +12 -5
  102. package/registry/components/table-elements.tsx +128 -0
  103. package/registry/components/tabs.tsx +5 -10
  104. package/registry/components/tag.tsx +2 -2
  105. package/registry/components/toggle.tsx +2 -2
  106. package/registry/components/toolbar.tsx +6 -6
  107. package/registry/components/tooltip.tsx +1 -1
  108. package/registry/examples/attribute-demo.tsx +1 -1
  109. package/registry/examples/avatar-demo.tsx +7 -4
  110. package/registry/examples/command-palette-demo.tsx +0 -1
  111. package/registry/examples/expanded/activity-heatmap-demo.tsx +29 -0
  112. package/registry/examples/expanded/breadcrumbs-demo.tsx +3 -3
  113. package/registry/examples/kbd-demo.tsx +2 -1
  114. package/registry/examples/pagination-demo.tsx +5 -5
  115. package/registry/examples/sidebar-demo.tsx +59 -13
  116. package/registry/guidance/USAGE.md +1 -1
  117. package/registry/index.json +621 -60
  118. package/registry/styles/globals.css +211 -151
  119. package/registry.json +44 -6
  120. package/tokens/banhaten.tokens.json +325 -95
@@ -197,7 +197,7 @@
197
197
  min-width: 0;
198
198
  }
199
199
 
200
- .ds-vertical-step-item--rtl .ds-vertical-step-item__content {
200
+ .ds-vertical-step-item:dir(rtl) .ds-vertical-step-item__content {
201
201
  align-items: flex-end;
202
202
  }
203
203
 
@@ -214,7 +214,7 @@
214
214
  text-align: start;
215
215
  }
216
216
 
217
- .ds-vertical-step-item--rtl .ds-vertical-step-item__copy {
217
+ .ds-vertical-step-item:dir(rtl) .ds-vertical-step-item__copy {
218
218
  text-align: right;
219
219
  }
220
220
 
@@ -225,10 +225,6 @@
225
225
  min-width: 0;
226
226
  }
227
227
 
228
- .ds-vertical-step-item--rtl .ds-vertical-step-item__header {
229
- direction: ltr;
230
- }
231
-
232
228
  .ds-vertical-step-item__label {
233
229
  flex: 1 0 0;
234
230
  min-width: 0;
@@ -247,11 +243,6 @@
247
243
  white-space: nowrap;
248
244
  }
249
245
 
250
- .ds-vertical-step-item--rtl .ds-vertical-step-item__label,
251
- .ds-vertical-step-item--rtl .ds-vertical-step-item__support {
252
- direction: rtl;
253
- }
254
-
255
246
  .ds-vertical-step-item__caption {
256
247
  width: 100%;
257
248
  color: var(--steps-content-subtle);
@@ -282,7 +273,7 @@
282
273
  gap: var(--steps-space-md);
283
274
  }
284
275
 
285
- .ds-vertical-step-item--rtl .ds-vertical-step-item__actions {
276
+ .ds-vertical-step-item:dir(rtl) .ds-vertical-step-item__actions {
286
277
  align-self: flex-start;
287
278
  }
288
279
 
@@ -291,3 +282,75 @@
291
282
  height: var(--bh-space-5xl-24);
292
283
  flex: 0 0 auto;
293
284
  }
285
+
286
+ .ds-progress-steps {
287
+ margin: 0;
288
+ padding: 0;
289
+ font-family: var(--bh-font-family);
290
+ }
291
+
292
+ .ds-progress-steps--markers {
293
+ display: flex;
294
+ align-items: flex-start;
295
+ list-style: none;
296
+ }
297
+
298
+ .ds-progress-steps__item {
299
+ position: relative;
300
+ display: flex;
301
+ min-width: 0;
302
+ align-items: center;
303
+ gap: var(--bh-space-md-8);
304
+ }
305
+
306
+ .ds-progress-steps__marker {
307
+ display: inline-grid;
308
+ width: var(--bh-space-5xl-24);
309
+ height: var(--bh-space-5xl-24);
310
+ flex: 0 0 auto;
311
+ place-items: center;
312
+ border-radius: var(--bh-radius-full);
313
+ background: var(--bh-interactive-secondary-default);
314
+ color: var(--bh-content-default);
315
+ }
316
+
317
+ .ds-progress-steps__item.is-complete .ds-progress-steps__marker,
318
+ .ds-progress-steps__item.is-active .ds-progress-steps__marker {
319
+ background: var(--bh-interactive-brand-default);
320
+ color: var(--bh-content-on-brand);
321
+ }
322
+
323
+ .ds-progress-steps__connector {
324
+ display: block;
325
+ width: var(--bh-space-9xl-64);
326
+ height: var(--bh-space-xxxs-1);
327
+ flex: 0 0 auto;
328
+ background: var(--bh-border-default);
329
+ }
330
+
331
+ .ds-progress-steps__connector.is-complete {
332
+ background: var(--bh-border-accent-purple-strong);
333
+ }
334
+
335
+ .ds-progress-steps--bars {
336
+ display: grid;
337
+ gap: var(--bh-space-md-8);
338
+ }
339
+
340
+ .ds-progress-steps__track {
341
+ display: flex;
342
+ gap: var(--bh-space-xs-4);
343
+ }
344
+
345
+ .ds-progress-steps__segment {
346
+ display: block;
347
+ min-width: var(--bh-space-3xl-16);
348
+ height: var(--bh-space-xs-4);
349
+ flex: 1 1 0;
350
+ border-radius: var(--bh-radius-full);
351
+ background: var(--bh-interactive-secondary-default);
352
+ }
353
+
354
+ .ds-progress-steps__segment[data-active="true"] {
355
+ background: var(--bh-interactive-brand-default);
356
+ }
@@ -64,12 +64,15 @@
64
64
  }
65
65
 
66
66
  .ds-data-table__toolbar [data-slot="toolbar-section"] {
67
+ max-width: 100%;
67
68
  min-width: 0;
69
+ flex-wrap: wrap;
68
70
  }
69
71
 
70
72
  .ds-data-table__toolbar [data-slot="toolbar-search"] {
71
- flex: 1 1 var(--bh-space-19xl-384);
72
- min-width: var(--bh-space-16xl-256);
73
+ width: min(100%, var(--bh-input-width));
74
+ min-width: 0;
75
+ flex: 1 1 min(100%, var(--bh-space-16xl-256));
73
76
  }
74
77
 
75
78
  .ds-data-table__body {
@@ -135,14 +138,21 @@
135
138
  .ds-table-wrap {
136
139
  box-sizing: border-box;
137
140
  width: 100%;
141
+ min-width: 0;
142
+ max-width: 100%;
143
+ contain: paint;
138
144
  overflow: auto;
139
- scrollbar-gutter: stable;
140
145
  border: var(--bh-space-xxxs-1) solid var(--bh-border-subtle);
141
146
  border-radius: var(--bh-radius-lg-8);
142
147
  background: var(--bh-bg-default);
143
148
  color: var(--bh-content-default);
144
149
  font-family: var(--bh-font-family);
145
150
  letter-spacing: var(--bh-text-base-letter-spacing);
151
+ outline: none;
152
+ }
153
+
154
+ .ds-table-wrap:focus-visible {
155
+ box-shadow: var(--shadow-component-focus-ring);
146
156
  }
147
157
 
148
158
  .ds-table-wrap *,
@@ -182,24 +192,26 @@
182
192
 
183
193
  .ds-table__cell {
184
194
  overflow: hidden;
185
- padding: 0 var(--bh-space-md-8);
195
+ padding-block: 0;
196
+ padding-inline: var(--bh-space-xl-12);
186
197
  vertical-align: middle;
187
198
  }
188
199
 
189
- .ds-table__cell--fill {
190
- width: auto;
200
+ .ds-table__cell--actions {
201
+ padding-inline: var(--bh-space-md-8);
191
202
  }
192
203
 
193
- .ds-table__cell--selection,
194
- .ds-table__cell--actions {
195
- text-align: center;
204
+ .ds-table__cell--fill {
205
+ width: auto;
196
206
  }
197
207
 
198
- .ds-table__cell--center {
208
+ .ds-table .ds-table__cell--selection,
209
+ .ds-table .ds-table__cell--actions,
210
+ .ds-table .ds-table__cell--center {
199
211
  text-align: center;
200
212
  }
201
213
 
202
- .ds-table__cell--end {
214
+ .ds-table .ds-table__cell--end {
203
215
  text-align: end;
204
216
  }
205
217
 
@@ -212,8 +224,12 @@
212
224
  }
213
225
 
214
226
  .ds-table__row--disabled {
215
- color: var(--bh-content-muted);
216
- opacity: var(--bh-opacity-muted);
227
+ color: var(--bh-content-default);
228
+ }
229
+
230
+ .ds-table__row--disabled .ds-table-item-text,
231
+ .ds-table__row--disabled .ds-table-avatar-text em {
232
+ color: var(--bh-content-default);
217
233
  }
218
234
 
219
235
  .ds-table__sort {
@@ -317,7 +333,7 @@
317
333
  }
318
334
 
319
335
  .ds-table-item-text {
320
- font-weight: var(--bh-font-weight-semibold);
336
+ font-weight: var(--bh-text-body-sm-regular-font-weight);
321
337
  }
322
338
 
323
339
  .ds-table-item-text--subtle {
@@ -325,7 +341,7 @@
325
341
  }
326
342
 
327
343
  .ds-table-item-text--medium {
328
- font-weight: var(--bh-font-weight-semibold);
344
+ font-weight: var(--bh-text-body-sm-medium-font-weight);
329
345
  }
330
346
 
331
347
  .ds-table-avatar-text,
@@ -333,6 +349,7 @@
333
349
  display: inline-flex;
334
350
  align-items: center;
335
351
  gap: var(--bh-space-md-8);
352
+ max-width: 100%;
336
353
  }
337
354
 
338
355
  .ds-table-avatar-text > span:last-child {
@@ -352,7 +369,7 @@
352
369
 
353
370
  .ds-table-avatar-text em {
354
371
  overflow: hidden;
355
- color: var(--bh-content-muted);
372
+ color: var(--bh-content-default);
356
373
  font-size: var(--bh-text-body-2xs-regular-font-size);
357
374
  font-style: normal;
358
375
  line-height: var(--bh-text-body-2xs-regular-line-height);
@@ -361,20 +378,7 @@
361
378
  }
362
379
 
363
380
  .ds-table-avatar {
364
- width: calc(var(--bh-space-5xl-24) + var(--bh-space-xs-4));
365
- height: calc(var(--bh-space-5xl-24) + var(--bh-space-xs-4));
366
381
  flex: 0 0 auto;
367
- display: inline-grid;
368
- place-items: center;
369
- border-radius: var(--bh-radius-full);
370
- background: var(--bh-bg-brand-soft);
371
- color: var(--bh-content-brand-default);
372
- font-size: var(--bh-text-body-3xs-regular-font-size);
373
- font-weight: var(--bh-font-weight-bold);
374
- }
375
-
376
- img.ds-table-avatar {
377
- object-fit: cover;
378
382
  }
379
383
 
380
384
  .ds-table-badges,
@@ -387,8 +391,7 @@ img.ds-table-avatar {
387
391
  max-width: 100%;
388
392
  }
389
393
 
390
- .ds-table-badge,
391
- .ds-table-tags span {
394
+ .ds-table-badge {
392
395
  min-height: var(--bh-space-5xl-24);
393
396
  display: inline-flex;
394
397
  align-items: center;
@@ -447,37 +450,12 @@ img.ds-table-avatar {
447
450
 
448
451
  .ds-table-progress {
449
452
  min-width: var(--bh-table-selection-column-min-width);
450
- display: inline-grid;
451
- grid-template-columns: minmax(0, 1fr) auto;
452
- align-items: center;
453
- gap: var(--bh-space-md-8);
454
- }
455
-
456
- .ds-table-progress > span {
457
- height: var(--bh-space-md-8);
458
- overflow: hidden;
459
- border-radius: var(--bh-radius-full);
460
- background: var(--bh-bg-muted);
461
453
  }
462
454
 
463
- .ds-table-progress i {
464
- height: 100%;
465
- display: block;
466
- border-radius: inherit;
455
+ .ds-table-progress--success [data-slot="progress-fill"] {
467
456
  background: var(--bh-content-success-default);
468
457
  }
469
458
 
470
- .ds-table-progress--brand i {
471
- background: var(--bh-bg-brand-default);
472
- }
473
-
474
- .ds-table-progress em {
475
- color: var(--bh-content-subtle);
476
- font-size: var(--bh-text-body-2xs-regular-font-size);
477
- font-style: normal;
478
- font-weight: var(--bh-font-weight-semibold);
479
- }
480
-
481
459
  .ds-table-toggle {
482
460
  width: calc(var(--bh-space-6xl-32) + var(--bh-space-xxs-2));
483
461
  height: var(--bh-space-4xl-20);
@@ -532,14 +510,16 @@ img.ds-table-avatar {
532
510
 
533
511
  .ds-table-icon-button svg,
534
512
  .ds-table-icon-label svg {
535
- width: var(--bh-space-4xl-20);
536
- height: var(--bh-space-4xl-20);
513
+ width: var(--bh-icon-size-default);
514
+ height: var(--bh-icon-size-default);
537
515
  }
538
516
 
539
517
  .ds-table-icon-label > span:first-child {
540
518
  flex: 0 0 auto;
541
519
  display: inline-grid;
542
520
  place-items: center;
521
+ width: var(--bh-icon-slot-size-default);
522
+ height: var(--bh-icon-slot-size-default);
543
523
  }
544
524
 
545
525
  .ds-table-icon-label > span:last-child {
@@ -574,12 +554,23 @@ img.ds-table-avatar {
574
554
  }
575
555
 
576
556
  .ds-table-rating {
557
+ display: inline-flex;
558
+ align-items: center;
559
+ gap: var(--bh-space-xxxs-1);
577
560
  color: var(--bh-bg-neutral-medium);
578
- letter-spacing: var(--bh-space-xxxs-1);
561
+ vertical-align: middle;
562
+ }
563
+
564
+ .ds-table-rating svg {
565
+ width: var(--bh-space-3xl-16);
566
+ height: var(--bh-space-3xl-16);
567
+ flex: 0 0 auto;
568
+ fill: transparent;
579
569
  }
580
570
 
581
571
  .ds-table-rating .is-filled {
582
572
  color: var(--bh-bg-accent-golden-default);
573
+ fill: currentColor;
583
574
  }
584
575
 
585
576
  .ds-table-avatar-stack .ds-table-avatar {
@@ -589,24 +580,27 @@ img.ds-table-avatar {
589
580
 
590
581
  .ds-table-avatar--count,
591
582
  .ds-table-avatar-stack button {
592
- width: calc(var(--bh-space-5xl-24) + var(--bh-space-xs-4));
593
- height: calc(var(--bh-space-5xl-24) + var(--bh-space-xs-4));
583
+ width: var(--bh-avatar-size-xs);
584
+ height: var(--bh-avatar-size-xs);
594
585
  border: var(--bh-space-xxs-2) solid var(--bh-bg-raised);
595
586
  border-radius: var(--bh-radius-full);
596
587
  background: var(--bh-bg-muted);
597
588
  color: var(--bh-content-subtle);
598
- font-size: var(--bh-text-body-3xs-regular-font-size);
599
- font-weight: var(--bh-font-weight-bold);
589
+ font-size: var(--bh-avatar-fallback-font-size-xs);
590
+ font-weight: var(--bh-font-weight-semibold);
600
591
  }
601
592
 
602
- .ds-table-wrap[dir="rtl"] {
603
- font-family: var(--bh-font-family);
593
+ .ds-table-avatar-stack--lg .ds-table-avatar--count,
594
+ .ds-table-avatar-stack--lg button {
595
+ width: var(--bh-avatar-size-md);
596
+ height: var(--bh-avatar-size-md);
597
+ font-size: var(--bh-avatar-fallback-font-size-md);
604
598
  }
605
599
 
606
- .ds-table-wrap[dir="rtl"] .ds-table-progress i {
607
- margin-inline-start: auto;
600
+ .ds-table-wrap:dir(rtl) {
601
+ font-family: var(--bh-font-family);
608
602
  }
609
603
 
610
- .ds-table-wrap[dir="rtl"] .ds-table-toggle[aria-pressed="true"] span {
604
+ .ds-table-wrap:dir(rtl) .ds-table-toggle[aria-pressed="true"] span {
611
605
  transform: translateX(calc(-1 * var(--bh-space-2xl-14)));
612
606
  }
@@ -49,10 +49,17 @@
49
49
  align-items: flex-start;
50
50
  width: min(var(--bh-timeline-grid-width), 100%);
51
51
  min-width: 0;
52
+ overflow-x: auto;
53
+ overscroll-behavior-inline: contain;
54
+ outline: none;
52
55
  }
53
56
 
54
- .ds-timeline--rtl,
55
- .ds-timeline-item--rtl {
57
+ .ds-timeline--horizontal:focus-visible {
58
+ box-shadow: var(--shadow-component-focus-ring);
59
+ }
60
+
61
+ .ds-timeline:dir(rtl),
62
+ .ds-timeline-item:dir(rtl) {
56
63
  font-family: var(--bh-font-family);
57
64
  }
58
65
 
@@ -68,7 +75,7 @@
68
75
  min-height: calc(var(--bh-space-9xl-64) + var(--bh-space-xl-12));
69
76
  }
70
77
 
71
- .ds-timeline-item--vertical.ds-timeline-item--rtl {
78
+ .ds-timeline-item--vertical:dir(rtl) {
72
79
  justify-content: flex-end;
73
80
  }
74
81
 
@@ -82,7 +89,7 @@
82
89
  width: var(--bh-timeline-sidebar-width);
83
90
  }
84
91
 
85
- .ds-timeline-item--horizontal.ds-timeline-item--rtl {
92
+ .ds-timeline-item--horizontal:dir(rtl) {
86
93
  align-items: flex-end;
87
94
  }
88
95
 
@@ -90,7 +97,6 @@
90
97
  flex: 0 0 auto;
91
98
  display: flex;
92
99
  align-items: center;
93
- direction: ltr;
94
100
  }
95
101
 
96
102
  .ds-timeline__indicator--vertical {
@@ -190,7 +196,7 @@
190
196
  color: var(--timeline-content-default);
191
197
  }
192
198
 
193
- .ds-timeline-item--rtl .ds-timeline__body {
199
+ .ds-timeline-item:dir(rtl) .ds-timeline__body {
194
200
  align-items: flex-end;
195
201
  text-align: right;
196
202
  }
@@ -198,12 +204,7 @@
198
204
  .ds-timeline-item--horizontal .ds-timeline__body {
199
205
  flex: 0 0 auto;
200
206
  width: 100%;
201
- padding-right: var(--timeline-space-xl);
202
- }
203
-
204
- .ds-timeline-item--horizontal.ds-timeline-item--rtl .ds-timeline__body {
205
- padding-right: 0;
206
- padding-left: var(--timeline-space-xl);
207
+ padding-inline-end: var(--timeline-space-xl);
207
208
  }
208
209
 
209
210
  .ds-timeline__copy {
@@ -251,7 +252,7 @@
251
252
  padding-top: var(--timeline-space-xs);
252
253
  }
253
254
 
254
- .ds-timeline-item--vertical.ds-timeline-item--ltr .ds-timeline__date--leading {
255
+ .ds-timeline-item--vertical:dir(ltr) .ds-timeline__date--leading {
255
256
  text-align: right;
256
257
  }
257
258
 
@@ -261,9 +262,9 @@
261
262
  text-align: start;
262
263
  }
263
264
 
264
- .ds-timeline-item--rtl .ds-timeline__date--leading,
265
- .ds-timeline-item--rtl .ds-timeline__date--top,
266
- .ds-timeline-item--rtl .ds-timeline__date--bottom {
265
+ .ds-timeline-item:dir(rtl) .ds-timeline__date--leading,
266
+ .ds-timeline-item:dir(rtl) .ds-timeline__date--top,
267
+ .ds-timeline-item:dir(rtl) .ds-timeline__date--bottom {
267
268
  text-align: right;
268
269
  }
269
270
 
@@ -10,10 +10,14 @@ type FieldOrientation = "vertical" | "horizontal" | "responsive"
10
10
 
11
11
  type FieldContextValue = {
12
12
  controlId: string
13
- descriptionId: string
13
+ defaultDescriptionId: string
14
+ defaultErrorId: string
15
+ descriptionIds: readonly string[]
14
16
  disabled?: boolean
15
- errorId: string
17
+ errorIds: readonly string[]
16
18
  invalid?: boolean
19
+ registerDescription: (id: string) => () => void
20
+ registerError: (id: string) => () => void
17
21
  }
18
22
 
19
23
  type FieldProps = React.ComponentProps<"div"> & {
@@ -48,15 +52,38 @@ function Field({
48
52
  }: FieldProps) {
49
53
  const generatedId = React.useId()
50
54
  const resolvedControlId = controlId ?? `${generatedId}-control`
55
+ const [descriptionIds, setDescriptionIds] = React.useState<string[]>([])
56
+ const [errorIds, setErrorIds] = React.useState<string[]>([])
57
+ const registerDescription = React.useCallback(
58
+ (id: string) => registerFieldReference(setDescriptionIds, id),
59
+ []
60
+ )
61
+ const registerError = React.useCallback(
62
+ (id: string) => registerFieldReference(setErrorIds, id),
63
+ []
64
+ )
51
65
  const context = React.useMemo<FieldContextValue>(
52
66
  () => ({
53
67
  controlId: resolvedControlId,
54
- descriptionId: `${generatedId}-description`,
68
+ defaultDescriptionId: `${generatedId}-description`,
69
+ defaultErrorId: `${generatedId}-error`,
70
+ descriptionIds,
55
71
  disabled,
56
- errorId: `${generatedId}-error`,
72
+ errorIds,
57
73
  invalid,
74
+ registerDescription,
75
+ registerError,
58
76
  }),
59
- [disabled, generatedId, invalid, resolvedControlId]
77
+ [
78
+ descriptionIds,
79
+ disabled,
80
+ errorIds,
81
+ generatedId,
82
+ invalid,
83
+ registerDescription,
84
+ registerError,
85
+ resolvedControlId,
86
+ ]
60
87
  )
61
88
 
62
89
  return (
@@ -86,7 +113,10 @@ function FieldControl({ className, ...props }: FieldControlProps) {
86
113
  const context = useFieldContext("FieldControl")
87
114
  const describedBy =
88
115
  props["aria-describedby"] ??
89
- [context.descriptionId, context.invalid ? context.errorId : undefined]
116
+ [
117
+ ...context.descriptionIds,
118
+ ...(context.invalid ? context.errorIds : []),
119
+ ]
90
120
  .filter(Boolean)
91
121
  .join(" ")
92
122
 
@@ -117,12 +147,18 @@ function FieldLabel({ htmlFor, ...props }: FieldLabelProps) {
117
147
 
118
148
  function FieldDescription({ className, id, ...props }: FieldDescriptionProps) {
119
149
  const context = useFieldContext("FieldDescription")
150
+ const resolvedId = id ?? context.defaultDescriptionId
151
+
152
+ React.useEffect(
153
+ () => context.registerDescription(resolvedId),
154
+ [context.registerDescription, resolvedId]
155
+ )
120
156
 
121
157
  return (
122
158
  <p
123
159
  data-slot="field-description"
124
160
  dir="auto"
125
- id={id ?? context.descriptionId}
161
+ id={resolvedId}
126
162
  className={cn(
127
163
  "m-0 text-[length:var(--bh-text-body-xs-regular-font-size)] font-[var(--bh-text-body-xs-regular-font-weight)] leading-[var(--bh-text-body-xs-regular-line-height)] tracking-[var(--bh-text-body-xs-regular-letter-spacing)] text-[var(--bh-content-subtle)]",
128
164
  className
@@ -134,12 +170,18 @@ function FieldDescription({ className, id, ...props }: FieldDescriptionProps) {
134
170
 
135
171
  function FieldError({ className, id, role = "alert", ...props }: FieldErrorProps) {
136
172
  const context = useFieldContext("FieldError")
173
+ const resolvedId = id ?? context.defaultErrorId
174
+
175
+ React.useEffect(
176
+ () => context.registerError(resolvedId),
177
+ [context.registerError, resolvedId]
178
+ )
137
179
 
138
180
  return (
139
181
  <p
140
182
  data-slot="field-error"
141
183
  dir="auto"
142
- id={id ?? context.errorId}
184
+ id={resolvedId}
143
185
  role={role}
144
186
  className={cn(
145
187
  "m-0 text-[length:var(--bh-text-body-xs-regular-font-size)] font-[var(--bh-text-body-xs-regular-font-weight)] leading-[var(--bh-text-body-xs-regular-line-height)] tracking-[var(--bh-text-body-xs-regular-letter-spacing)] text-[var(--bh-content-danger-default)]",
@@ -150,6 +192,17 @@ function FieldError({ className, id, role = "alert", ...props }: FieldErrorProps
150
192
  )
151
193
  }
152
194
 
195
+ function registerFieldReference(
196
+ setIds: React.Dispatch<React.SetStateAction<string[]>>,
197
+ id: string
198
+ ) {
199
+ setIds((current) => (current.includes(id) ? current : [...current, id]))
200
+
201
+ return () => {
202
+ setIds((current) => current.filter((candidate) => candidate !== id))
203
+ }
204
+ }
205
+
153
206
  function FieldGroup({ className, ...props }: FieldGroupProps) {
154
207
  return (
155
208
  <div
@@ -9,7 +9,7 @@ import {
9
9
  } from "lucide-react"
10
10
 
11
11
  import { cn } from "@/lib/utils"
12
- import { Kbd, KbdShortcut } from "@/components/ui/kbd"
12
+ import { Shortcut } from "@/components/ui/kbd"
13
13
  import {
14
14
  getInputDefaultValue,
15
15
  getInputHelperText,
@@ -419,7 +419,12 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
419
419
 
420
420
  <span
421
421
  data-slot="input-content"
422
- className={cn(inputContent({ size: resolvedSize }))}
422
+ className={cn(
423
+ inputContent({ size: resolvedSize }),
424
+ kind === "shortcut" &&
425
+ resolvedSize === "lg" &&
426
+ "px-[var(--bh-input-md-padding-x)]"
427
+ )}
423
428
  >
424
429
  {shouldShowLeadingIcon ? (
425
430
  <InputLeadingIcon disabled={isDisabled} icon={leadingIcon} />
@@ -470,9 +475,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
470
475
 
471
476
  {kind === "shortcut" ? (
472
477
  hasRenderableContent(shortcut) ? (
473
- <Kbd disabled={isDisabled}>{shortcut}</Kbd>
478
+ <Shortcut disabled={isDisabled}>{shortcut}</Shortcut>
474
479
  ) : (
475
- <KbdShortcut disabled={isDisabled} keys={shortcutKeys} />
480
+ <Shortcut disabled={isDisabled} keys={shortcutKeys} />
476
481
  )
477
482
  ) : null}
478
483
  </span>
@@ -618,7 +623,9 @@ function InputLeadingIcon({
618
623
  aria-hidden="true"
619
624
  data-slot="input-leading-icon"
620
625
  className={cn(
621
- "flex size-[var(--bh-input-icon-size)] shrink-0 items-center justify-center text-[var(--bh-content-muted)]",
626
+ "flex size-[var(--bh-input-icon-slot-size)] shrink-0 items-center justify-center text-[var(--bh-content-muted)]",
627
+ "[&>img]:size-[var(--bh-input-icon-size)] [&>img]:shrink-0 [&>img]:object-contain",
628
+ "[&>svg]:size-[var(--bh-input-icon-size)] [&>svg]:shrink-0",
622
629
  disabled && "text-[var(--bh-content-disabled)]"
623
630
  )}
624
631
  >
@@ -99,7 +99,7 @@ const ItemMedia = React.forwardRef<HTMLDivElement, ItemMediaProps>(
99
99
  ref={ref}
100
100
  className={cn(
101
101
  "flex size-[var(--bh-item-media-size)] shrink-0 items-center justify-center overflow-hidden",
102
- "[&_svg]:size-[var(--bh-item-icon-size)] [&_img]:size-full [&_img]:object-cover",
102
+ "[&_svg]:size-[var(--bh-item-icon-size)] [&_svg]:m-[calc((var(--bh-item-icon-slot-size)-var(--bh-item-icon-size))/2)] [&_img]:size-full [&_img]:object-cover",
103
103
  variant === "icon" &&
104
104
  "rounded-[var(--bh-item-media-radius)] bg-[var(--bh-bg-neutral-subtle)] text-[var(--bh-content-subtle)]",
105
105
  variant === "avatar" &&