@bitforgehq/ui 0.3.2 → 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 (42) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/README.md +4 -4
  3. package/ai/MANIFEST.index.json +36 -0
  4. package/ai/MANIFEST.json +436 -24
  5. package/ai/REFERENCE.index.json +35 -0
  6. package/ai/REFERENCE.json +202 -10
  7. package/ai/UI_GUIDE.md +25 -4
  8. package/ai/components/app-frame.md +14 -7
  9. package/ai/components/badge.md +39 -2
  10. package/ai/components/header.md +9 -0
  11. package/ai/components/list-item.md +105 -9
  12. package/ai/components/step.md +112 -0
  13. package/ai/components/steps.md +124 -0
  14. package/ai/components/table.md +119 -5
  15. package/ai/components/timeline-event.md +144 -0
  16. package/ai/components/timeline.md +201 -0
  17. package/ai/components/toggle.md +11 -1
  18. package/ai/reference/bf-action-directive.md +3 -1
  19. package/ai/reference/bf-badge-emphasis.md +27 -0
  20. package/ai/reference/bf-labels.md +2 -0
  21. package/ai/reference/bf-select-harness.md +4 -0
  22. package/ai/reference/bf-step-heading-level.md +28 -0
  23. package/ai/reference/bf-table-align.md +1 -1
  24. package/ai/reference/bf-table-column-align.md +33 -0
  25. package/ai/reference/bf-table-column.md +7 -7
  26. package/ai/reference/bf-table-harness.md +18 -0
  27. package/ai/reference/bf-timeline-tone.md +31 -0
  28. package/ai/reference/bf-toggle-harness.md +55 -0
  29. package/ai/reference/provide-bf-labels.md +2 -2
  30. package/dark-ink.css +124 -0
  31. package/fesm2022/bitforgehq-ui-mobile.mjs +13 -3
  32. package/fesm2022/bitforgehq-ui-mobile.mjs.map +1 -1
  33. package/fesm2022/bitforgehq-ui-testing.mjs +55 -2
  34. package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -1
  35. package/fesm2022/bitforgehq-ui.mjs +714 -46
  36. package/fesm2022/bitforgehq-ui.mjs.map +1 -1
  37. package/llms-full.txt +1128 -26
  38. package/llms.txt +9 -0
  39. package/package.json +2 -1
  40. package/theme.css +37 -0
  41. package/types/bitforgehq-ui-testing.d.ts +90 -1
  42. package/types/bitforgehq-ui.d.ts +306 -18
@@ -1,5 +1,5 @@
1
1
  import * as i0 from "@angular/core";
2
- import { Component, DOCUMENT, DestroyRef, Directive, ElementRef, HostAttributeToken, Injectable, InjectionToken, Injector, PLATFORM_ID, TemplateRef, afterNextRender, afterRenderEffect, booleanAttribute, computed, contentChild, contentChildren, effect, inject, input, linkedSignal, makeEnvironmentProviders, model, numberAttribute, output, provideEnvironmentInitializer, signal, untracked, viewChild, viewChildren } from "@angular/core";
2
+ import { Component, DOCUMENT, DestroyRef, Directive, ElementRef, HostAttributeToken, Injectable, InjectionToken, Injector, LOCALE_ID, PLATFORM_ID, TemplateRef, afterNextRender, afterRenderEffect, booleanAttribute, computed, contentChild, contentChildren, effect, inject, input, linkedSignal, makeEnvironmentProviders, model, numberAttribute, output, provideEnvironmentInitializer, signal, untracked, viewChild, viewChildren } from "@angular/core";
3
3
  import { NgTemplateOutlet, isPlatformBrowser } from "@angular/common";
4
4
  const BF_DEFAULT_VALUES = {
5
5
  fieldSize: "md",
@@ -44,6 +44,7 @@ const BF_DEFAULT_LABELS = {
44
44
  notifications: "Notifications",
45
45
  tableSelectAll: "Select all rows",
46
46
  tableSortBy: "Sort by",
47
+ tableSortNone: "Not sorted",
47
48
  tableSortAscending: (column) => `${column}, ascending`,
48
49
  tableSortDescending: (column) => `${column}, descending`,
49
50
  theme: "Theme",
@@ -95,6 +96,7 @@ const BF_DEFAULT_LABELS = {
95
96
  chartValue: "Value",
96
97
  chartEmpty: "No data to show",
97
98
  chartError: "The data could not be loaded",
99
+ listItemUnread: "Unread",
98
100
  validation: {
99
101
  required: "Fill in this field",
100
102
  email: "Enter a valid email address",
@@ -145,6 +147,7 @@ function mergeLabels(parent, o) {
145
147
  notifications: o.notifications ?? parent.notifications,
146
148
  tableSelectAll: o.tableSelectAll ?? parent.tableSelectAll,
147
149
  tableSortBy: o.tableSortBy ?? parent.tableSortBy,
150
+ tableSortNone: o.tableSortNone ?? parent.tableSortNone,
148
151
  tableSortAscending: o.tableSortAscending ?? parent.tableSortAscending,
149
152
  tableSortDescending: o.tableSortDescending ?? parent.tableSortDescending,
150
153
  theme: o.theme ?? parent.theme,
@@ -196,6 +199,7 @@ function mergeLabels(parent, o) {
196
199
  chartValue: o.chartValue ?? parent.chartValue,
197
200
  chartEmpty: o.chartEmpty ?? parent.chartEmpty,
198
201
  chartError: o.chartError ?? parent.chartError,
202
+ listItemUnread: o.listItemUnread ?? parent.listItemUnread,
199
203
  validation: {
200
204
  required: v.required ?? pv.required,
201
205
  email: v.email ?? pv.email,
@@ -1127,7 +1131,9 @@ i0.ɵɵngDeclareClassMetadata({
1127
1131
  }
1128
1132
  });
1129
1133
  const LABEL_BASE$1 = "inline-flex items-center rounded-control px-2.5 py-1.25 text-micro font-bold leading-none";
1130
- const COUNT_BASE = "inline-flex h-box min-w-box items-center justify-center rounded-control bg-primary px-1.75 text-micro font-bold leading-none text-on-primary";
1134
+ const COUNT_BASE = "inline-flex h-box min-w-box items-center justify-center rounded-control px-1.75 text-micro font-bold leading-none";
1135
+ const COUNT_SOFT = "bg-primary text-on-primary";
1136
+ const STRONG_FORCED = "forced-colors:outline forced-colors:outline-[CanvasText]";
1131
1137
  const VARIANT$4 = {
1132
1138
  neutral: "bg-neutral-soft text-neutral",
1133
1139
  primary: "bg-primary-soft text-primary-strong",
@@ -1136,16 +1142,25 @@ const VARIANT$4 = {
1136
1142
  danger: "bg-danger-soft text-danger",
1137
1143
  info: "bg-info-soft text-info"
1138
1144
  };
1145
+ const STRONG = {
1146
+ neutral: "bg-neutral-strong text-on-neutral-strong",
1147
+ primary: "bg-primary text-on-primary",
1148
+ success: "bg-success-strong text-on-success-strong",
1149
+ warning: "bg-warning-strong text-on-warning-strong",
1150
+ danger: "bg-danger-strong text-on-danger-strong",
1151
+ info: "bg-info-strong text-on-info-strong"
1152
+ };
1139
1153
  var BfBadgeComponent = class BfBadgeComponent {
1140
1154
  variant = input("neutral", ...ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []);
1155
+ emphasis = input("soft", ...ngDevMode ? [{ debugName: "emphasis" }] : /* istanbul ignore next */ []);
1141
1156
  count = input(void 0, ...ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []);
1142
1157
  countLabel = input("", ...ngDevMode ? [{ debugName: "countLabel" }] : /* istanbul ignore next */ []);
1143
- classes = computed(() => `${LABEL_BASE$1} ${VARIANT$4[this.variant()]}`, ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
1158
+ classes = computed(() => this.emphasis() === "strong" ? `${LABEL_BASE$1} ${STRONG[this.variant()]} ${STRONG_FORCED}` : `${LABEL_BASE$1} ${VARIANT$4[this.variant()]}`, ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
1144
1159
  countText = computed(() => {
1145
1160
  const c = this.count();
1146
1161
  return c === void 0 ? null : c > 99 ? "99+" : String(c);
1147
1162
  }, ...ngDevMode ? [{ debugName: "countText" }] : /* istanbul ignore next */ []);
1148
- countClasses = COUNT_BASE;
1163
+ countClasses = computed(() => this.emphasis() === "strong" ? `${COUNT_BASE} ${STRONG[this.variant()]} ${STRONG_FORCED}` : `${COUNT_BASE} ${COUNT_SOFT}`, ...ngDevMode ? [{ debugName: "countClasses" }] : /* istanbul ignore next */ []);
1149
1164
  static ɵfac = i0.ɵɵngDeclareFactory({
1150
1165
  minVersion: "12.0.0",
1151
1166
  version: "22.1.7",
@@ -1168,6 +1183,13 @@ var BfBadgeComponent = class BfBadgeComponent {
1168
1183
  isRequired: false,
1169
1184
  transformFunction: null
1170
1185
  },
1186
+ emphasis: {
1187
+ classPropertyName: "emphasis",
1188
+ publicName: "emphasis",
1189
+ isSignal: true,
1190
+ isRequired: false,
1191
+ transformFunction: null
1192
+ },
1171
1193
  count: {
1172
1194
  classPropertyName: "count",
1173
1195
  publicName: "count",
@@ -1187,7 +1209,7 @@ var BfBadgeComponent = class BfBadgeComponent {
1187
1209
  ngImport: i0,
1188
1210
  template: `
1189
1211
  @if (countText(); as text) {
1190
- <span [class]="countClasses"
1212
+ <span [class]="countClasses()"
1191
1213
  >{{ text }}
1192
1214
  @if (countLabel()) {
1193
1215
  <span class="sr-only"> {{ countLabel() }}</span>
@@ -1212,7 +1234,7 @@ i0.ɵɵngDeclareClassMetadata({
1212
1234
  host: { class: "inline-flex" },
1213
1235
  template: `
1214
1236
  @if (countText(); as text) {
1215
- <span [class]="countClasses"
1237
+ <span [class]="countClasses()"
1216
1238
  >{{ text }}
1217
1239
  @if (countLabel()) {
1218
1240
  <span class="sr-only"> {{ countLabel() }}</span>
@@ -1233,6 +1255,14 @@ i0.ɵɵngDeclareClassMetadata({
1233
1255
  required: false
1234
1256
  }]
1235
1257
  }],
1258
+ emphasis: [{
1259
+ type: i0.Input,
1260
+ args: [{
1261
+ isSignal: true,
1262
+ alias: "emphasis",
1263
+ required: false
1264
+ }]
1265
+ }],
1236
1266
  count: [{
1237
1267
  type: i0.Input,
1238
1268
  args: [{
@@ -3514,7 +3544,7 @@ const ROW$4 = {
3514
3544
  md: "min-h-10 pointer-coarse:min-h-hit",
3515
3545
  lg: "min-h-12"
3516
3546
  };
3517
- const TEXT$3 = {
3547
+ const TEXT$4 = {
3518
3548
  sm: "text-label-sm",
3519
3549
  md: "text-label",
3520
3550
  lg: "text-label"
@@ -3591,7 +3621,7 @@ var BfCheckboxComponent = class BfCheckboxComponent {
3591
3621
  ROW$4[this.resolvedSize()],
3592
3622
  LABEL_MODE$1[this.mode()]
3593
3623
  ].join(" "), ...ngDevMode ? [{ debugName: "labelClasses" }] : /* istanbul ignore next */ []);
3594
- textClasses = computed(() => `text-text peer-disabled:text-text-disabled font-semibold empty:hidden ${TEXT$3[this.resolvedSize()]}`, ...ngDevMode ? [{ debugName: "textClasses" }] : /* istanbul ignore next */ []);
3624
+ textClasses = computed(() => `text-text peer-disabled:text-text-disabled font-semibold empty:hidden ${TEXT$4[this.resolvedSize()]}`, ...ngDevMode ? [{ debugName: "textClasses" }] : /* istanbul ignore next */ []);
3595
3625
  errorClasses = computed(() => `text-danger text-micro ${ERROR_INDENT[this.resolvedSize()]}`, ...ngDevMode ? [{ debugName: "errorClasses" }] : /* istanbul ignore next */ []);
3596
3626
  boxClasses = computed(() => {
3597
3627
  const state = this.checked() || this.indeterminate() ? this.readonly() ? "readonlyOn" : "on" : this.showError() ? "error" : this.readonly() ? "readonly" : "off";
@@ -3983,7 +4013,7 @@ i0.ɵɵngDeclareClassMetadata({
3983
4013
  const TRACK_BASE$1 = "relative flex shrink-0 items-center rounded-control border-[1.5px] p-[1.5px] transition-colors peer-focus-visible:ring-4 peer-focus-visible:ring-ring peer-focus-visible:outline-hidden";
3984
4014
  const KNOB_BASE = "block rounded-control border-[1.5px] border-transparent shadow-segment transition-transform";
3985
4015
  const ROW$3 = {
3986
- sm: "min-h-8 pointer-coarse:min-h-hit",
4016
+ sm: "min-h-8 pointer-coarse:min-h-hit pointer-coarse:min-w-hit",
3987
4017
  md: "min-h-10 pointer-coarse:min-h-hit",
3988
4018
  lg: "min-h-12"
3989
4019
  };
@@ -4011,7 +4041,7 @@ const KNOB_TRAVEL = {
4011
4041
  off: "translate-x-0"
4012
4042
  }
4013
4043
  };
4014
- const TEXT$2 = {
4044
+ const TEXT$3 = {
4015
4045
  sm: "text-label-sm",
4016
4046
  md: "text-label",
4017
4047
  lg: "text-label"
@@ -4092,7 +4122,7 @@ var BfToggleComponent = class BfToggleComponent {
4092
4122
  resolvedSize = computed(() => this.size() ?? this.defaults.controlSize, ...ngDevMode ? [{ debugName: "resolvedSize" }] : /* istanbul ignore next */ []);
4093
4123
  mode = computed(() => this.disabled() ? "disabled" : this.readonly() ? "readonly" : "editable", ...ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []);
4094
4124
  labelClasses = computed(() => [
4095
- this.labelPosition() === "start" ? "flex w-full flex-row-reverse items-center justify-between gap-2.5" : "inline-flex items-center gap-2.5",
4125
+ this.labelPosition() === "start" ? "flex w-full flex-row-reverse items-center justify-between gap-2.5" : "inline-flex items-center justify-center gap-2.5",
4096
4126
  ROW$3[this.resolvedSize()],
4097
4127
  LABEL_MODE[this.mode()]
4098
4128
  ].join(" "), ...ngDevMode ? [{ debugName: "labelClasses" }] : /* istanbul ignore next */ []);
@@ -4102,7 +4132,7 @@ var BfToggleComponent = class BfToggleComponent {
4102
4132
  TRACK_FILL$1[this.mode()][this.checked() ? "on" : "off"],
4103
4133
  TRACK_PRESSED[this.mode()]
4104
4134
  ].filter(Boolean).join(" "), ...ngDevMode ? [{ debugName: "trackClasses" }] : /* istanbul ignore next */ []);
4105
- textClasses = computed(() => `text-text peer-disabled:text-text-disabled min-w-0 font-semibold wrap-anywhere ${TEXT$2[this.resolvedSize()]}`, ...ngDevMode ? [{ debugName: "textClasses" }] : /* istanbul ignore next */ []);
4135
+ textClasses = computed(() => `text-text peer-disabled:text-text-disabled min-w-0 font-semibold wrap-anywhere ${TEXT$3[this.resolvedSize()]}`, ...ngDevMode ? [{ debugName: "textClasses" }] : /* istanbul ignore next */ []);
4106
4136
  knobClasses = computed(() => {
4107
4137
  const on = this.checked();
4108
4138
  const fill = KNOB_FILL[this.mode()][on ? "on" : "off"];
@@ -4516,7 +4546,7 @@ const DOT_SIZE = {
4516
4546
  md: "size-3",
4517
4547
  lg: "size-3.5"
4518
4548
  };
4519
- const TEXT$1 = {
4549
+ const TEXT$2 = {
4520
4550
  sm: "text-label-sm",
4521
4551
  md: "text-label",
4522
4552
  lg: "text-label"
@@ -4578,7 +4608,7 @@ var BfRadioGroupComponent = class BfRadioGroupComponent {
4578
4608
  defaults = inject(BF_DEFAULTS);
4579
4609
  selectedIndex = computed(() => choiceIndex(this.options(), this.value(), this.compareWith()), ...ngDevMode ? [{ debugName: "selectedIndex" }] : /* istanbul ignore next */ []);
4580
4610
  resolvedSize = computed(() => this.size() ?? this.defaults.controlSize, ...ngDevMode ? [{ debugName: "resolvedSize" }] : /* istanbul ignore next */ []);
4581
- textClasses = computed(() => `font-semibold ${TEXT$1[this.resolvedSize()]}`, ...ngDevMode ? [{ debugName: "textClasses" }] : /* istanbul ignore next */ []);
4611
+ textClasses = computed(() => `font-semibold ${TEXT$2[this.resolvedSize()]}`, ...ngDevMode ? [{ debugName: "textClasses" }] : /* istanbul ignore next */ []);
4582
4612
  errorText = computed(() => fieldErrorText(this.errorMessage(), this.touched(), this.errors(), this.labels.validation), ...ngDevMode ? [{ debugName: "errorText" }] : /* istanbul ignore next */ []);
4583
4613
  showError = computed(() => fieldShowsError(this.errorText(), this.invalid(), this.touched()), ...ngDevMode ? [{ debugName: "showError" }] : /* istanbul ignore next */ []);
4584
4614
  message = heldMessage(this.errorText);
@@ -6441,10 +6471,11 @@ const ACTION$1 = {
6441
6471
  action: "cursor-pointer hover:bg-surface-muted has-[[data-bf-action]:active]:bg-surface-pressed has-[[data-bf-action]:active]:after:border-text-muted",
6442
6472
  focused: "cursor-pointer hover:bg-surface-muted has-[[data-bf-action]:active]:bg-surface-pressed has-[[data-bf-action]:active]:after:border-text-muted ring-4 ring-ring"
6443
6473
  };
6444
- const TEXT = {
6474
+ const TEXT$1 = {
6445
6475
  wrap: "wrap-anywhere",
6446
6476
  truncate: "truncate"
6447
6477
  };
6478
+ const UNREAD_DOT = "absolute -start-2.5 mt-[7px] size-1.5 rounded-full bg-primary forced-colors:bg-[CanvasText]";
6448
6479
  const CHEVRON$2 = "after:ms-auto after:h-2.5 after:w-2.5 after:shrink-0 after:-translate-x-1 after:rotate-45 rtl:after:translate-x-1 rtl:after:-rotate-135 after:border-t-[1.5px] after:border-r-[1.5px] after:border-text-subtle after:content-['']";
6449
6480
  var BfListItemComponent = class BfListItemComponent {
6450
6481
  title = input("", ...ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []);
@@ -6465,15 +6496,26 @@ var BfListItemComponent = class BfListItemComponent {
6465
6496
  ...ngDevMode ? { debugName: "truncate" } : /* istanbul ignore next */ {},
6466
6497
  transform: booleanAttribute
6467
6498
  });
6499
+ unread = input(false, {
6500
+ ...ngDevMode ? { debugName: "unread" } : /* istanbul ignore next */ {},
6501
+ transform: booleanAttribute
6502
+ });
6468
6503
  clicked = output();
6469
6504
  role = inject(BF_LIST, { optional: true }) ? "listitem" : null;
6505
+ labels = inject(BF_LABELS);
6506
+ unreadDot = UNREAD_DOT;
6470
6507
  actions = signal(0, ...ngDevMode ? [{ debugName: "actions" }] : /* istanbul ignore next */ []);
6471
6508
  actionFocusVisible = signal(false, ...ngDevMode ? [{ debugName: "actionFocusVisible" }] : /* istanbul ignore next */ []);
6472
6509
  actionState = computed(() => {
6473
6510
  if (this.actions() === 0) return "none";
6474
6511
  return this.actionFocusVisible() ? "focused" : "action";
6475
6512
  }, ...ngDevMode ? [{ debugName: "actionState" }] : /* istanbul ignore next */ []);
6476
- textClasses = computed(() => TEXT[this.truncate() ? "truncate" : "wrap"], ...ngDevMode ? [{ debugName: "textClasses" }] : /* istanbul ignore next */ []);
6513
+ hasAction = computed(() => this.actions() > 0, ...ngDevMode ? [{ debugName: "hasAction" }] : /* istanbul ignore next */ []);
6514
+ unreadIdValue;
6515
+ unreadId = computed(() => this.unread() ? this.unreadIdValue ??= uniqueId("bf-list-item-unread") : null, ...ngDevMode ? [{ debugName: "unreadId" }] : /* istanbul ignore next */ []);
6516
+ actionLabelPrefix = computed(() => this.hasAction() ? this.unreadId() : null, ...ngDevMode ? [{ debugName: "actionLabelPrefix" }] : /* istanbul ignore next */ []);
6517
+ titleWeight = computed(() => this.unread() ? "font-extrabold" : "font-bold", ...ngDevMode ? [{ debugName: "titleWeight" }] : /* istanbul ignore next */ []);
6518
+ textClasses = computed(() => TEXT$1[this.truncate() ? "truncate" : "wrap"], ...ngDevMode ? [{ debugName: "textClasses" }] : /* istanbul ignore next */ []);
6477
6519
  classes = computed(() => [
6478
6520
  ROW$1,
6479
6521
  this.interactive() ? INTERACTIVE$1 : ACTION$1[this.actionState()],
@@ -6542,6 +6584,13 @@ var BfListItemComponent = class BfListItemComponent {
6542
6584
  isSignal: true,
6543
6585
  isRequired: false,
6544
6586
  transformFunction: null
6587
+ },
6588
+ unread: {
6589
+ classPropertyName: "unread",
6590
+ publicName: "unread",
6591
+ isSignal: true,
6592
+ isRequired: false,
6593
+ transformFunction: null
6545
6594
  }
6546
6595
  },
6547
6596
  outputs: { clicked: "clicked" },
@@ -6569,11 +6618,20 @@ var BfListItemComponent = class BfListItemComponent {
6569
6618
  }
6570
6619
  <ng-template #content>
6571
6620
  <ng-content select="[bfSlot=leading]" />
6572
- <span class="flex min-w-0 flex-1 flex-col">
6621
+ <span class="relative flex min-w-0 flex-1 flex-col">
6622
+ @if (unreadId(); as id) {
6623
+ <!-- Read before the title; with a bfAction the link's name takes it (aria-labelledby),
6624
+ so the text itself is hidden from the tree to be read once. -->
6625
+ <span [class]="unreadDot"
6626
+ ><span [id]="id" class="sr-only" [attr.aria-hidden]="hasAction() ? 'true' : null"
6627
+ >{{ labels.listItemUnread }},
6628
+ </span></span
6629
+ >
6630
+ }
6573
6631
  @if (title()) {
6574
- <span class="text-label font-bold {{ textClasses() }}">{{ title() }}</span>
6632
+ <span class="text-label {{ titleWeight() }} {{ textClasses() }}">{{ title() }}</span>
6575
6633
  }
6576
- <span class="text-label font-bold empty:hidden {{ textClasses() }}"
6634
+ <span class="text-label {{ titleWeight() }} empty:hidden {{ textClasses() }}"
6577
6635
  ><ng-content select="[bfSlot=title]"
6578
6636
  /></span>
6579
6637
  @if (subtitle()) {
@@ -6633,11 +6691,20 @@ i0.ɵɵngDeclareClassMetadata({
6633
6691
  }
6634
6692
  <ng-template #content>
6635
6693
  <ng-content select="[bfSlot=leading]" />
6636
- <span class="flex min-w-0 flex-1 flex-col">
6694
+ <span class="relative flex min-w-0 flex-1 flex-col">
6695
+ @if (unreadId(); as id) {
6696
+ <!-- Read before the title; with a bfAction the link's name takes it (aria-labelledby),
6697
+ so the text itself is hidden from the tree to be read once. -->
6698
+ <span [class]="unreadDot"
6699
+ ><span [id]="id" class="sr-only" [attr.aria-hidden]="hasAction() ? 'true' : null"
6700
+ >{{ labels.listItemUnread }},
6701
+ </span></span
6702
+ >
6703
+ }
6637
6704
  @if (title()) {
6638
- <span class="text-label font-bold {{ textClasses() }}">{{ title() }}</span>
6705
+ <span class="text-label {{ titleWeight() }} {{ textClasses() }}">{{ title() }}</span>
6639
6706
  }
6640
- <span class="text-label font-bold empty:hidden {{ textClasses() }}"
6707
+ <span class="text-label {{ titleWeight() }} empty:hidden {{ textClasses() }}"
6641
6708
  ><ng-content select="[bfSlot=title]"
6642
6709
  /></span>
6643
6710
  @if (subtitle()) {
@@ -6702,6 +6769,14 @@ i0.ɵɵngDeclareClassMetadata({
6702
6769
  required: false
6703
6770
  }]
6704
6771
  }],
6772
+ unread: [{
6773
+ type: i0.Input,
6774
+ args: [{
6775
+ isSignal: true,
6776
+ alias: "unread",
6777
+ required: false
6778
+ }]
6779
+ }],
6705
6780
  clicked: [{
6706
6781
  type: i0.Output,
6707
6782
  args: ["clicked"]
@@ -6890,7 +6965,7 @@ const SIZE$1 = {
6890
6965
  sm: "h-2",
6891
6966
  md: "h-2.5"
6892
6967
  };
6893
- const TONE = {
6968
+ const TONE$1 = {
6894
6969
  primary: "[&::-webkit-progress-value]:bg-primary-strong [&::-moz-progress-bar]:bg-primary-strong",
6895
6970
  success: "[&::-webkit-progress-value]:bg-success [&::-moz-progress-bar]:bg-success",
6896
6971
  warning: "[&::-webkit-progress-value]:bg-warning [&::-moz-progress-bar]:bg-warning",
@@ -6918,7 +6993,7 @@ var BfProgressComponent = class BfProgressComponent {
6918
6993
  if (raw === void 0 || !Number.isFinite(raw)) return 0;
6919
6994
  return Math.min(100, Math.max(0, Math.round(raw)));
6920
6995
  }, ...ngDevMode ? [{ debugName: "percent" }] : /* istanbul ignore next */ []);
6921
- classes = computed(() => `${TRACK} ${SIZE$1[this.size()]} ${TONE[this.tone()]}`, ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
6996
+ classes = computed(() => `${TRACK} ${SIZE$1[this.size()]} ${TONE$1[this.tone()]}`, ...ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []);
6922
6997
  stripeClasses = computed(() => `${STRIPE} ${STRIPE_TONE[this.tone()]}`, ...ngDevMode ? [{ debugName: "stripeClasses" }] : /* istanbul ignore next */ []);
6923
6998
  static ɵfac = i0.ɵɵngDeclareFactory({
6924
6999
  minVersion: "12.0.0",
@@ -8261,6 +8336,20 @@ var BfActionDirective = class BfActionDirective {
8261
8336
  host = inject(BF_ACTION_HOST, { optional: true });
8262
8337
  element = inject(ElementRef).nativeElement;
8263
8338
  constructor() {
8339
+ const own = this.element.getAttribute("aria-labelledby");
8340
+ let prefixed = false;
8341
+ afterRenderEffect({ write: () => {
8342
+ const prefix = this.host?.actionLabelPrefix?.() ?? null;
8343
+ if (prefix) {
8344
+ this.element.id ||= uniqueId("bf-action");
8345
+ this.element.setAttribute("aria-labelledby", `${prefix} ${own ?? this.element.id}`);
8346
+ prefixed = true;
8347
+ } else if (prefixed) {
8348
+ if (own === null) this.element.removeAttribute("aria-labelledby");
8349
+ else this.element.setAttribute("aria-labelledby", own);
8350
+ prefixed = false;
8351
+ }
8352
+ } });
8264
8353
  const unregister = this.host?.registerAction();
8265
8354
  inject(DestroyRef).onDestroy(() => {
8266
8355
  this.host?.setActionFocusVisible(false);
@@ -9217,7 +9306,13 @@ const BODY_TOUCH = {
9217
9306
  };
9218
9307
  const ALIGN = {
9219
9308
  start: "text-start",
9220
- end: "text-end tabular-nums"
9309
+ end: "text-end tabular-nums",
9310
+ center: "text-center"
9311
+ };
9312
+ const CENTER_CELL = {
9313
+ never: "[&>*]:mx-auto [&>*]:w-fit",
9314
+ narrow: "@min-xl:[&>*]:mx-auto [&>*]:w-fit @max-xl:items-center",
9315
+ coarse: "not-pointer-coarse:[&>*]:mx-auto [&>*]:w-fit pointer-coarse:items-center"
9221
9316
  };
9222
9317
  const HEAD_BASE = "px-3 py-0 align-middle text-label-xs font-bold text-text-muted";
9223
9318
  const BODY_BASE = "px-3 align-middle font-medium text-text";
@@ -9306,9 +9401,15 @@ const STACK_FIRST_CELL = {
9306
9401
  };
9307
9402
  const STACK_CELL = {
9308
9403
  never: "",
9309
- narrow: "@max-xl:col-span-full @max-xl:flex @max-xl:h-auto @max-xl:items-baseline @max-xl:justify-between @max-xl:gap-3 @max-xl:px-0 @max-xl:py-1 @max-xl:text-end @max-xl:before:shrink-0 @max-xl:before:text-start @max-xl:before:text-label-xs @max-xl:before:font-bold @max-xl:before:text-text-muted @max-xl:before:content-[attr(data-label)_/_\"\"]",
9310
- coarse: "pointer-coarse:col-span-full pointer-coarse:flex pointer-coarse:h-auto pointer-coarse:items-baseline pointer-coarse:justify-between pointer-coarse:gap-3 pointer-coarse:px-0 pointer-coarse:py-1 pointer-coarse:text-end pointer-coarse:before:shrink-0 pointer-coarse:before:text-start pointer-coarse:before:text-label-xs pointer-coarse:before:font-bold pointer-coarse:before:text-text-muted pointer-coarse:before:content-[attr(data-label)_/_\"\"]"
9404
+ narrow: "@max-xl:col-span-full @max-xl:flex @max-xl:h-auto @max-xl:justify-between @max-xl:gap-3 @max-xl:px-0 @max-xl:py-1 @max-xl:text-end @max-xl:before:shrink-0 @max-xl:before:text-start @max-xl:before:text-label-xs @max-xl:before:font-bold @max-xl:before:text-text-muted @max-xl:before:content-data-label",
9405
+ coarse: "pointer-coarse:col-span-full pointer-coarse:flex pointer-coarse:h-auto pointer-coarse:justify-between pointer-coarse:gap-3 pointer-coarse:px-0 pointer-coarse:py-1 pointer-coarse:text-end pointer-coarse:before:shrink-0 pointer-coarse:before:text-start pointer-coarse:before:text-label-xs pointer-coarse:before:font-bold pointer-coarse:before:text-text-muted pointer-coarse:before:content-data-label"
9406
+ };
9407
+ const STACK_CELL_BASELINE = {
9408
+ never: "",
9409
+ narrow: "@max-xl:items-baseline",
9410
+ coarse: "pointer-coarse:items-baseline"
9311
9411
  };
9412
+ const SORT_NONE = "";
9312
9413
  const STACK_EMPTY = {
9313
9414
  never: "",
9314
9415
  narrow: "@max-xl:block",
@@ -9357,16 +9458,23 @@ var BfTableComponent = class BfTableComponent {
9357
9458
  }, ...ngDevMode ? [{ debugName: "someSelected" }] : /* istanbul ignore next */ []);
9358
9459
  columnCount = computed(() => this.columns().length + (this.selectable() ? 1 : 0), ...ngDevMode ? [{ debugName: "columnCount" }] : /* istanbul ignore next */ []);
9359
9460
  stacks = computed(() => this.stack() !== "never", ...ngDevMode ? [{ debugName: "stacks" }] : /* istanbul ignore next */ []);
9360
- sortOptions = computed(() => this.columns().filter((column) => column.sortable).flatMap((column) => [{
9361
- value: `${column.key}:ascending`,
9362
- label: this.labels.tableSortAscending(column.label)
9363
- }, {
9364
- value: `${column.key}:descending`,
9365
- label: this.labels.tableSortDescending(column.label)
9366
- }]), ...ngDevMode ? [{ debugName: "sortOptions" }] : /* istanbul ignore next */ []);
9461
+ sortOptions = computed(() => {
9462
+ const sortable = this.columns().filter((column) => column.sortable);
9463
+ if (sortable.length === 0) return [];
9464
+ return [{
9465
+ value: SORT_NONE,
9466
+ label: this.labels.tableSortNone
9467
+ }, ...sortable.flatMap((column) => [{
9468
+ value: `${column.key}:ascending`,
9469
+ label: this.labels.tableSortAscending(column.label)
9470
+ }, {
9471
+ value: `${column.key}:descending`,
9472
+ label: this.labels.tableSortDescending(column.label)
9473
+ }])];
9474
+ }, ...ngDevMode ? [{ debugName: "sortOptions" }] : /* istanbul ignore next */ []);
9367
9475
  sortValue = computed(() => {
9368
9476
  const sort = this.sort();
9369
- return sort ? `${sort.column}:${sort.direction}` : null;
9477
+ return sort ? `${sort.column}:${sort.direction}` : SORT_NONE;
9370
9478
  }, ...ngDevMode ? [{ debugName: "sortValue" }] : /* istanbul ignore next */ []);
9371
9479
  hostClasses = computed(() => STACK_HOST[this.stack()], ...ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []);
9372
9480
  stackBarClasses = computed(() => `${STACK_BAR[this.stack()]} flex-wrap items-end justify-between gap-x-4 gap-y-2 pb-3`, ...ngDevMode ? [{ debugName: "stackBarClasses" }] : /* istanbul ignore next */ []);
@@ -9388,8 +9496,11 @@ var BfTableComponent = class BfTableComponent {
9388
9496
  return `${HEAD_BASE} ${HEAD_CELL[this.resolvedSize()]} ${ALIGN[column.align ?? "start"]}`;
9389
9497
  }
9390
9498
  bodyClasses(column, first) {
9391
- const stacked = (first ? STACK_FIRST_CELL : STACK_CELL)[this.stack()];
9392
- return `${BODY_BASE} ${this.bodyHeight()} ${ALIGN[column.align ?? "start"]} ${stacked}`.trim();
9499
+ const stack = this.stack();
9500
+ const align = column.align ?? "start";
9501
+ const center = align === "center" ? CENTER_CELL[stack] : "";
9502
+ const stacked = first ? STACK_FIRST_CELL[stack] : `${STACK_CELL[stack]} ${center ? "" : STACK_CELL_BASELINE[stack]}`;
9503
+ return `${BODY_BASE} ${this.bodyHeight()} ${ALIGN[align]} ${center} ${stacked}`.replace(/\s+/g, " ").trim();
9393
9504
  }
9394
9505
  rowClasses(key) {
9395
9506
  const state = this.selectedKeys().has(key) ? "selected" : this.selectable() ? "selectable" : "static";
@@ -9425,6 +9536,10 @@ var BfTableComponent = class BfTableComponent {
9425
9536
  });
9426
9537
  }
9427
9538
  sortFromOption(value) {
9539
+ if (value === SORT_NONE) {
9540
+ this.sort.set(null);
9541
+ return;
9542
+ }
9428
9543
  const at = value.lastIndexOf(":");
9429
9544
  const direction = value.slice(at + 1);
9430
9545
  if (at > 0 && (direction === "ascending" || direction === "descending")) this.sort.set({
@@ -10394,6 +10509,320 @@ i0.ɵɵngDeclareClassMetadata({
10394
10509
  }]
10395
10510
  }
10396
10511
  });
10512
+ const TIMELINE_TIME_FORMAT = {
10513
+ dateStyle: "medium",
10514
+ timeStyle: "short"
10515
+ };
10516
+ const BF_TIMELINE = new InjectionToken("BF_TIMELINE");
10517
+ var BfTimelineComponent = class BfTimelineComponent {
10518
+ label = input("", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
10519
+ timeFormat = input(TIMELINE_TIME_FORMAT, ...ngDevMode ? [{ debugName: "timeFormat" }] : /* istanbul ignore next */ []);
10520
+ locale = input("", ...ngDevMode ? [{ debugName: "locale" }] : /* istanbul ignore next */ []);
10521
+ static ɵfac = i0.ɵɵngDeclareFactory({
10522
+ minVersion: "12.0.0",
10523
+ version: "22.1.7",
10524
+ ngImport: i0,
10525
+ type: BfTimelineComponent,
10526
+ deps: [],
10527
+ target: i0.ɵɵFactoryTarget.Component
10528
+ });
10529
+ static ɵcmp = i0.ɵɵngDeclareComponent({
10530
+ minVersion: "17.1.0",
10531
+ version: "22.1.7",
10532
+ type: BfTimelineComponent,
10533
+ isStandalone: true,
10534
+ selector: "bf-timeline",
10535
+ inputs: {
10536
+ label: {
10537
+ classPropertyName: "label",
10538
+ publicName: "label",
10539
+ isSignal: true,
10540
+ isRequired: false,
10541
+ transformFunction: null
10542
+ },
10543
+ timeFormat: {
10544
+ classPropertyName: "timeFormat",
10545
+ publicName: "timeFormat",
10546
+ isSignal: true,
10547
+ isRequired: false,
10548
+ transformFunction: null
10549
+ },
10550
+ locale: {
10551
+ classPropertyName: "locale",
10552
+ publicName: "locale",
10553
+ isSignal: true,
10554
+ isRequired: false,
10555
+ transformFunction: null
10556
+ }
10557
+ },
10558
+ host: { classAttribute: "block" },
10559
+ providers: [{
10560
+ provide: BF_TIMELINE,
10561
+ useExisting: BfTimelineComponent
10562
+ }],
10563
+ ngImport: i0,
10564
+ template: `<div role="list" class="flex flex-col" [attr.aria-label]="label() || null">
10565
+ <ng-content />
10566
+ </div>`,
10567
+ isInline: true
10568
+ });
10569
+ };
10570
+ i0.ɵɵngDeclareClassMetadata({
10571
+ minVersion: "12.0.0",
10572
+ version: "22.1.7",
10573
+ ngImport: i0,
10574
+ type: BfTimelineComponent,
10575
+ decorators: [{
10576
+ type: Component,
10577
+ args: [{
10578
+ selector: "bf-timeline",
10579
+ host: { class: "block" },
10580
+ providers: [{
10581
+ provide: BF_TIMELINE,
10582
+ useExisting: BfTimelineComponent
10583
+ }],
10584
+ template: `<div role="list" class="flex flex-col" [attr.aria-label]="label() || null">
10585
+ <ng-content />
10586
+ </div>`
10587
+ }]
10588
+ }],
10589
+ propDecorators: {
10590
+ label: [{
10591
+ type: i0.Input,
10592
+ args: [{
10593
+ isSignal: true,
10594
+ alias: "label",
10595
+ required: false
10596
+ }]
10597
+ }],
10598
+ timeFormat: [{
10599
+ type: i0.Input,
10600
+ args: [{
10601
+ isSignal: true,
10602
+ alias: "timeFormat",
10603
+ required: false
10604
+ }]
10605
+ }],
10606
+ locale: [{
10607
+ type: i0.Input,
10608
+ args: [{
10609
+ isSignal: true,
10610
+ alias: "locale",
10611
+ required: false
10612
+ }]
10613
+ }]
10614
+ }
10615
+ });
10616
+ const TONE = {
10617
+ neutral: "bg-text-subtle",
10618
+ primary: "bg-primary",
10619
+ success: "bg-success",
10620
+ warning: "bg-warning",
10621
+ danger: "bg-danger",
10622
+ info: "bg-info"
10623
+ };
10624
+ const DOT = "relative mt-[calc(0.75rem-5px)] size-2.5 shrink-0 rounded-control forced-colors:bg-[CanvasText]";
10625
+ const MARKER$1 = "relative flex w-2.5 shrink-0 justify-center before:absolute before:top-3 before:-bottom-3 before:start-[calc(50%-0.5px)] before:border-s before:border-border before:content-[''] group-last/bf-timeline-event:before:hidden";
10626
+ const TEXT = "text-body text-text wrap-anywhere [&_a]:rounded-tile [&_a]:text-primary-text [&_a]:underline [&_a]:underline-offset-2 [&_a]:hover:decoration-2 [&_a]:focus-visible:ring-4 [&_a]:focus-visible:ring-ring [&_a]:focus-visible:outline-hidden";
10627
+ function toDate(time) {
10628
+ if (time === null || time === "") return null;
10629
+ const date = typeof time === "string" ? new Date(time) : time;
10630
+ return Number.isNaN(date.getTime()) ? null : date;
10631
+ }
10632
+ function formatDate(date, locales, options) {
10633
+ for (const locale of locales) for (const format of [options, TIMELINE_TIME_FORMAT]) try {
10634
+ return new Intl.DateTimeFormat(locale, format).format(date);
10635
+ } catch {}
10636
+ return "";
10637
+ }
10638
+ var BfTimelineEventComponent = class BfTimelineEventComponent {
10639
+ actor = input("", ...ngDevMode ? [{ debugName: "actor" }] : /* istanbul ignore next */ []);
10640
+ time = input(null, ...ngDevMode ? [{ debugName: "time" }] : /* istanbul ignore next */ []);
10641
+ timeText = input("", ...ngDevMode ? [{ debugName: "timeText" }] : /* istanbul ignore next */ []);
10642
+ tone = input("neutral", ...ngDevMode ? [{ debugName: "tone" }] : /* istanbul ignore next */ []);
10643
+ timeline = inject(BF_TIMELINE, { optional: true });
10644
+ appLocale = inject(LOCALE_ID);
10645
+ role = this.timeline ? "listitem" : null;
10646
+ date = computed(() => toDate(this.time()), ...ngDevMode ? [{ debugName: "date" }] : /* istanbul ignore next */ []);
10647
+ datetime = computed(() => {
10648
+ const date = this.date();
10649
+ if (!date) return null;
10650
+ const time = this.time();
10651
+ return typeof time === "string" ? time : date.toISOString();
10652
+ }, ...ngDevMode ? [{ debugName: "datetime" }] : /* istanbul ignore next */ []);
10653
+ timeLabel = computed(() => {
10654
+ const date = this.date();
10655
+ if (this.timeText()) return this.timeText();
10656
+ if (!date) return "";
10657
+ return formatDate(date, [
10658
+ this.timeline?.locale() ?? "",
10659
+ this.appLocale,
10660
+ "en"
10661
+ ].filter(Boolean), this.timeline?.timeFormat() ?? TIMELINE_TIME_FORMAT);
10662
+ }, ...ngDevMode ? [{ debugName: "timeLabel" }] : /* istanbul ignore next */ []);
10663
+ markerClasses = MARKER$1;
10664
+ textClasses = TEXT;
10665
+ dotClasses = computed(() => `${DOT} ${TONE[this.tone()]}`, ...ngDevMode ? [{ debugName: "dotClasses" }] : /* istanbul ignore next */ []);
10666
+ static ɵfac = i0.ɵɵngDeclareFactory({
10667
+ minVersion: "12.0.0",
10668
+ version: "22.1.7",
10669
+ ngImport: i0,
10670
+ type: BfTimelineEventComponent,
10671
+ deps: [],
10672
+ target: i0.ɵɵFactoryTarget.Component
10673
+ });
10674
+ static ɵcmp = i0.ɵɵngDeclareComponent({
10675
+ minVersion: "17.0.0",
10676
+ version: "22.1.7",
10677
+ type: BfTimelineEventComponent,
10678
+ isStandalone: true,
10679
+ selector: "bf-timeline-event",
10680
+ inputs: {
10681
+ actor: {
10682
+ classPropertyName: "actor",
10683
+ publicName: "actor",
10684
+ isSignal: true,
10685
+ isRequired: false,
10686
+ transformFunction: null
10687
+ },
10688
+ time: {
10689
+ classPropertyName: "time",
10690
+ publicName: "time",
10691
+ isSignal: true,
10692
+ isRequired: false,
10693
+ transformFunction: null
10694
+ },
10695
+ timeText: {
10696
+ classPropertyName: "timeText",
10697
+ publicName: "timeText",
10698
+ isSignal: true,
10699
+ isRequired: false,
10700
+ transformFunction: null
10701
+ },
10702
+ tone: {
10703
+ classPropertyName: "tone",
10704
+ publicName: "tone",
10705
+ isSignal: true,
10706
+ isRequired: false,
10707
+ transformFunction: null
10708
+ }
10709
+ },
10710
+ host: {
10711
+ properties: { "attr.role": "role" },
10712
+ classAttribute: "group/bf-timeline-event flex gap-3"
10713
+ },
10714
+ ngImport: i0,
10715
+ template: `
10716
+ <span aria-hidden="true" [class]="markerClasses"><span [class]="dotClasses()"></span></span>
10717
+ <!-- The end slot wraps under the text once the text would get narrower than 16rem. -->
10718
+ <div
10719
+ class="flex min-w-0 flex-1 flex-wrap items-start gap-x-3 gap-y-2 pb-5 group-last/bf-timeline-event:pb-0"
10720
+ >
10721
+ <div class="min-w-0 flex-[1_1_16rem]">
10722
+ <div [class]="textClasses"><ng-content /></div>
10723
+ @if (actor() || timeLabel()) {
10724
+ <p class="text-caption text-text-muted mt-0.5 wrap-anywhere">
10725
+ @if (actor()) {
10726
+ <span>{{ actor() }}</span>
10727
+ }
10728
+ @if (actor() && timeLabel()) {
10729
+ <span aria-hidden="true"> · </span>
10730
+ }
10731
+ @if (datetime(); as machine) {
10732
+ <time [attr.datetime]="machine">{{ timeLabel() }}</time>
10733
+ } @else if (timeLabel()) {
10734
+ <span>{{ timeLabel() }}</span>
10735
+ }
10736
+ </p>
10737
+ }
10738
+ </div>
10739
+ <div class="flex shrink-0 items-center gap-2 empty:hidden">
10740
+ <ng-content select="[bfSlot=end]" />
10741
+ </div>
10742
+ </div>
10743
+ `,
10744
+ isInline: true
10745
+ });
10746
+ };
10747
+ i0.ɵɵngDeclareClassMetadata({
10748
+ minVersion: "12.0.0",
10749
+ version: "22.1.7",
10750
+ ngImport: i0,
10751
+ type: BfTimelineEventComponent,
10752
+ decorators: [{
10753
+ type: Component,
10754
+ args: [{
10755
+ selector: "bf-timeline-event",
10756
+ host: {
10757
+ class: "group/bf-timeline-event flex gap-3",
10758
+ "[attr.role]": "role"
10759
+ },
10760
+ template: `
10761
+ <span aria-hidden="true" [class]="markerClasses"><span [class]="dotClasses()"></span></span>
10762
+ <!-- The end slot wraps under the text once the text would get narrower than 16rem. -->
10763
+ <div
10764
+ class="flex min-w-0 flex-1 flex-wrap items-start gap-x-3 gap-y-2 pb-5 group-last/bf-timeline-event:pb-0"
10765
+ >
10766
+ <div class="min-w-0 flex-[1_1_16rem]">
10767
+ <div [class]="textClasses"><ng-content /></div>
10768
+ @if (actor() || timeLabel()) {
10769
+ <p class="text-caption text-text-muted mt-0.5 wrap-anywhere">
10770
+ @if (actor()) {
10771
+ <span>{{ actor() }}</span>
10772
+ }
10773
+ @if (actor() && timeLabel()) {
10774
+ <span aria-hidden="true"> · </span>
10775
+ }
10776
+ @if (datetime(); as machine) {
10777
+ <time [attr.datetime]="machine">{{ timeLabel() }}</time>
10778
+ } @else if (timeLabel()) {
10779
+ <span>{{ timeLabel() }}</span>
10780
+ }
10781
+ </p>
10782
+ }
10783
+ </div>
10784
+ <div class="flex shrink-0 items-center gap-2 empty:hidden">
10785
+ <ng-content select="[bfSlot=end]" />
10786
+ </div>
10787
+ </div>
10788
+ `
10789
+ }]
10790
+ }],
10791
+ propDecorators: {
10792
+ actor: [{
10793
+ type: i0.Input,
10794
+ args: [{
10795
+ isSignal: true,
10796
+ alias: "actor",
10797
+ required: false
10798
+ }]
10799
+ }],
10800
+ time: [{
10801
+ type: i0.Input,
10802
+ args: [{
10803
+ isSignal: true,
10804
+ alias: "time",
10805
+ required: false
10806
+ }]
10807
+ }],
10808
+ timeText: [{
10809
+ type: i0.Input,
10810
+ args: [{
10811
+ isSignal: true,
10812
+ alias: "timeText",
10813
+ required: false
10814
+ }]
10815
+ }],
10816
+ tone: [{
10817
+ type: i0.Input,
10818
+ args: [{
10819
+ isSignal: true,
10820
+ alias: "tone",
10821
+ required: false
10822
+ }]
10823
+ }]
10824
+ }
10825
+ });
10397
10826
  const BF_BREADCRUMB = new InjectionToken("BF_BREADCRUMB");
10398
10827
  const CONTENT = {
10399
10828
  ancestor: "inline-flex min-w-0 items-center px-1 wrap-anywhere text-text-muted [&>a]:-mx-1 [&>a]:inline-flex [&>a]:min-h-6 [&>a]:items-center [&>a]:rounded-tile [&>a]:px-1 [&>a]:text-text-muted [&>a]:underline-offset-4 [&>a]:transition-colors [&>a]:hover:text-text [&>a]:hover:underline [&>a]:focus-visible:ring-4 [&>a]:focus-visible:ring-ring [&>a]:focus-visible:outline-hidden [&>a]:pointer-coarse:min-h-hit",
@@ -11277,12 +11706,14 @@ var BfAppFrameComponent = class BfAppFrameComponent {
11277
11706
  headerClasses()
11278
11707
  }}"
11279
11708
  >
11280
- <div data-brand class="flex min-w-0 items-center empty:hidden">
11281
- <ng-content select="[bfSlot=brand]" />
11282
- </div>
11709
+ <!-- The menu at the inline start, then the brand: the top app bar convention, and the
11710
+ menu comes first in the tab order too. -->
11283
11711
  <div data-menu class="flex items-center empty:hidden">
11284
11712
  <ng-content select="[bfSlot=menu]" />
11285
11713
  </div>
11714
+ <div data-brand class="flex min-w-0 items-center empty:hidden">
11715
+ <ng-content select="[bfSlot=brand]" />
11716
+ </div>
11286
11717
  <div data-actions class="ms-auto flex items-center gap-2 empty:hidden">
11287
11718
  <ng-content select="[bfSlot=actions]" />
11288
11719
  </div>
@@ -11340,12 +11771,14 @@ i0.ɵɵngDeclareClassMetadata({
11340
11771
  headerClasses()
11341
11772
  }}"
11342
11773
  >
11343
- <div data-brand class="flex min-w-0 items-center empty:hidden">
11344
- <ng-content select="[bfSlot=brand]" />
11345
- </div>
11774
+ <!-- The menu at the inline start, then the brand: the top app bar convention, and the
11775
+ menu comes first in the tab order too. -->
11346
11776
  <div data-menu class="flex items-center empty:hidden">
11347
11777
  <ng-content select="[bfSlot=menu]" />
11348
11778
  </div>
11779
+ <div data-brand class="flex min-w-0 items-center empty:hidden">
11780
+ <ng-content select="[bfSlot=brand]" />
11781
+ </div>
11349
11782
  <div data-actions class="ms-auto flex items-center gap-2 empty:hidden">
11350
11783
  <ng-content select="[bfSlot=actions]" />
11351
11784
  </div>
@@ -11406,7 +11839,7 @@ const HOST = {
11406
11839
  rect: `${BAR} block h-[var(--bf-skeleton-height,6rem)] rounded-field`,
11407
11840
  circle: `${BAR} inline-block size-10 shrink-0 rounded-full`
11408
11841
  };
11409
- const LINE = `${BAR} block h-[var(--bf-skeleton-height,0.75rem)] w-full rounded-full`;
11842
+ const LINE$1 = `${BAR} block h-[var(--bf-skeleton-height,0.75rem)] w-full rounded-full`;
11410
11843
  const LAST_LINE = `${BAR} block h-[var(--bf-skeleton-height,0.75rem)] w-3/5 rounded-full`;
11411
11844
  var BfSkeletonComponent = class BfSkeletonComponent {
11412
11845
  shape = input("text", ...ngDevMode ? [{ debugName: "shape" }] : /* istanbul ignore next */ []);
@@ -11416,7 +11849,7 @@ var BfSkeletonComponent = class BfSkeletonComponent {
11416
11849
  });
11417
11850
  width = input("", ...ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []);
11418
11851
  height = input("", ...ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []);
11419
- lineClasses = LINE;
11852
+ lineClasses = LINE$1;
11420
11853
  lastLineClasses = LAST_LINE;
11421
11854
  lineList = computed(() => {
11422
11855
  const count = Math.max(1, Math.floor(this.lines()) || 1);
@@ -13320,6 +13753,241 @@ i0.ɵɵngDeclareClassMetadata({
13320
13753
  }]
13321
13754
  }
13322
13755
  });
13756
+ const BF_STEPS = new InjectionToken("BF_STEPS");
13757
+ const MARKER = "flex size-6 shrink-0 items-center justify-center rounded-full bg-primary-soft text-label-sm font-bold text-primary-strong forced-colors:outline forced-colors:outline-[CanvasText]";
13758
+ const LINE = "my-1 w-0 flex-1 border-s border-border group-last/bf-step:hidden";
13759
+ const TITLE = "pt-0.5 text-label font-bold text-text wrap-anywhere";
13760
+ var BfStepComponent = class BfStepComponent {
13761
+ steps = inject(BF_STEPS, { optional: true });
13762
+ title = input("", ...ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []);
13763
+ headingLevel = input(void 0, ...ngDevMode ? [{ debugName: "headingLevel" }] : /* istanbul ignore next */ []);
13764
+ role = this.steps ? "listitem" : null;
13765
+ markerClasses = MARKER;
13766
+ lineClasses = LINE;
13767
+ titleClasses = TITLE;
13768
+ number = computed(() => {
13769
+ const steps = this.steps;
13770
+ return steps ? steps.start() + Math.max(steps.indexOf(this), 0) : 1;
13771
+ }, ...ngDevMode ? [{ debugName: "number" }] : /* istanbul ignore next */ []);
13772
+ positionInSet = computed(() => this.steps && this.steps.start() !== 1 ? this.number() : null, ...ngDevMode ? [{ debugName: "positionInSet" }] : /* istanbul ignore next */ []);
13773
+ setSize = computed(() => {
13774
+ const steps = this.steps;
13775
+ return steps && steps.start() !== 1 ? steps.start() - 1 + steps.count() : null;
13776
+ }, ...ngDevMode ? [{ debugName: "setSize" }] : /* istanbul ignore next */ []);
13777
+ static ɵfac = i0.ɵɵngDeclareFactory({
13778
+ minVersion: "12.0.0",
13779
+ version: "22.1.7",
13780
+ ngImport: i0,
13781
+ type: BfStepComponent,
13782
+ deps: [],
13783
+ target: i0.ɵɵFactoryTarget.Component
13784
+ });
13785
+ static ɵcmp = i0.ɵɵngDeclareComponent({
13786
+ minVersion: "17.0.0",
13787
+ version: "22.1.7",
13788
+ type: BfStepComponent,
13789
+ isStandalone: true,
13790
+ selector: "bf-step",
13791
+ inputs: {
13792
+ title: {
13793
+ classPropertyName: "title",
13794
+ publicName: "title",
13795
+ isSignal: true,
13796
+ isRequired: false,
13797
+ transformFunction: null
13798
+ },
13799
+ headingLevel: {
13800
+ classPropertyName: "headingLevel",
13801
+ publicName: "headingLevel",
13802
+ isSignal: true,
13803
+ isRequired: false,
13804
+ transformFunction: null
13805
+ }
13806
+ },
13807
+ host: {
13808
+ properties: {
13809
+ "attr.role": "role",
13810
+ "attr.aria-posinset": "positionInSet()",
13811
+ "attr.aria-setsize": "setSize()"
13812
+ },
13813
+ classAttribute: "group/bf-step block"
13814
+ },
13815
+ ngImport: i0,
13816
+ template: `
13817
+ <div class="flex gap-3">
13818
+ <div class="flex shrink-0 flex-col items-center">
13819
+ <span aria-hidden="true" [class]="markerClasses">{{ number() }}</span>
13820
+ <span [class]="lineClasses"></span>
13821
+ </div>
13822
+ <div class="min-w-0 flex-1 pb-6 group-last/bf-step:pb-0">
13823
+ @if (title()) {
13824
+ @switch (headingLevel()) {
13825
+ @case (2) {
13826
+ <h2 [class]="titleClasses">{{ title() }}</h2>
13827
+ }
13828
+ @case (3) {
13829
+ <h3 [class]="titleClasses">{{ title() }}</h3>
13830
+ }
13831
+ @case (4) {
13832
+ <h4 [class]="titleClasses">{{ title() }}</h4>
13833
+ }
13834
+ @default {
13835
+ <p [class]="titleClasses">{{ title() }}</p>
13836
+ }
13837
+ }
13838
+ }
13839
+ <div class="text-body text-text-secondary mt-1 wrap-anywhere empty:hidden">
13840
+ <ng-content />
13841
+ </div>
13842
+ </div>
13843
+ </div>
13844
+ `,
13845
+ isInline: true
13846
+ });
13847
+ };
13848
+ i0.ɵɵngDeclareClassMetadata({
13849
+ minVersion: "12.0.0",
13850
+ version: "22.1.7",
13851
+ ngImport: i0,
13852
+ type: BfStepComponent,
13853
+ decorators: [{
13854
+ type: Component,
13855
+ args: [{
13856
+ selector: "bf-step",
13857
+ host: {
13858
+ class: "group/bf-step block",
13859
+ "[attr.role]": "role",
13860
+ "[attr.aria-posinset]": "positionInSet()",
13861
+ "[attr.aria-setsize]": "setSize()"
13862
+ },
13863
+ template: `
13864
+ <div class="flex gap-3">
13865
+ <div class="flex shrink-0 flex-col items-center">
13866
+ <span aria-hidden="true" [class]="markerClasses">{{ number() }}</span>
13867
+ <span [class]="lineClasses"></span>
13868
+ </div>
13869
+ <div class="min-w-0 flex-1 pb-6 group-last/bf-step:pb-0">
13870
+ @if (title()) {
13871
+ @switch (headingLevel()) {
13872
+ @case (2) {
13873
+ <h2 [class]="titleClasses">{{ title() }}</h2>
13874
+ }
13875
+ @case (3) {
13876
+ <h3 [class]="titleClasses">{{ title() }}</h3>
13877
+ }
13878
+ @case (4) {
13879
+ <h4 [class]="titleClasses">{{ title() }}</h4>
13880
+ }
13881
+ @default {
13882
+ <p [class]="titleClasses">{{ title() }}</p>
13883
+ }
13884
+ }
13885
+ }
13886
+ <div class="text-body text-text-secondary mt-1 wrap-anywhere empty:hidden">
13887
+ <ng-content />
13888
+ </div>
13889
+ </div>
13890
+ </div>
13891
+ `
13892
+ }]
13893
+ }],
13894
+ propDecorators: {
13895
+ title: [{
13896
+ type: i0.Input,
13897
+ args: [{
13898
+ isSignal: true,
13899
+ alias: "title",
13900
+ required: false
13901
+ }]
13902
+ }],
13903
+ headingLevel: [{
13904
+ type: i0.Input,
13905
+ args: [{
13906
+ isSignal: true,
13907
+ alias: "headingLevel",
13908
+ required: false
13909
+ }]
13910
+ }]
13911
+ }
13912
+ });
13913
+ var BfStepsComponent = class BfStepsComponent {
13914
+ start = input(1, {
13915
+ ...ngDevMode ? { debugName: "start" } : /* istanbul ignore next */ {},
13916
+ transform: numberAttribute
13917
+ });
13918
+ steps = contentChildren(BfStepComponent, ...ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []);
13919
+ count = computed(() => this.steps().length, ...ngDevMode ? [{ debugName: "count" }] : /* istanbul ignore next */ []);
13920
+ indexOf(step) {
13921
+ return this.steps().findIndex((item) => item === step);
13922
+ }
13923
+ static ɵfac = i0.ɵɵngDeclareFactory({
13924
+ minVersion: "12.0.0",
13925
+ version: "22.1.7",
13926
+ ngImport: i0,
13927
+ type: BfStepsComponent,
13928
+ deps: [],
13929
+ target: i0.ɵɵFactoryTarget.Component
13930
+ });
13931
+ static ɵcmp = i0.ɵɵngDeclareComponent({
13932
+ minVersion: "17.2.0",
13933
+ version: "22.1.7",
13934
+ type: BfStepsComponent,
13935
+ isStandalone: true,
13936
+ selector: "bf-steps",
13937
+ inputs: { start: {
13938
+ classPropertyName: "start",
13939
+ publicName: "start",
13940
+ isSignal: true,
13941
+ isRequired: false,
13942
+ transformFunction: null
13943
+ } },
13944
+ host: { classAttribute: "block" },
13945
+ providers: [{
13946
+ provide: BF_STEPS,
13947
+ useExisting: BfStepsComponent
13948
+ }],
13949
+ queries: [{
13950
+ propertyName: "steps",
13951
+ predicate: BfStepComponent,
13952
+ isSignal: true
13953
+ }],
13954
+ ngImport: i0,
13955
+ template: `<div role="list" class="flex flex-col"><ng-content /></div>`,
13956
+ isInline: true
13957
+ });
13958
+ };
13959
+ i0.ɵɵngDeclareClassMetadata({
13960
+ minVersion: "12.0.0",
13961
+ version: "22.1.7",
13962
+ ngImport: i0,
13963
+ type: BfStepsComponent,
13964
+ decorators: [{
13965
+ type: Component,
13966
+ args: [{
13967
+ selector: "bf-steps",
13968
+ host: { class: "block" },
13969
+ providers: [{
13970
+ provide: BF_STEPS,
13971
+ useExisting: BfStepsComponent
13972
+ }],
13973
+ template: `<div role="list" class="flex flex-col"><ng-content /></div>`
13974
+ }]
13975
+ }],
13976
+ propDecorators: {
13977
+ start: [{
13978
+ type: i0.Input,
13979
+ args: [{
13980
+ isSignal: true,
13981
+ alias: "start",
13982
+ required: false
13983
+ }]
13984
+ }],
13985
+ steps: [{
13986
+ type: i0.ContentChildren,
13987
+ args: [i0.forwardRef(() => BfStepComponent), { isSignal: true }]
13988
+ }]
13989
+ }
13990
+ });
13323
13991
  function resetBfDocument(document) {
13324
13992
  document.documentElement.classList.remove("dark", "cdk-global-scrollblock");
13325
13993
  for (const child of Array.from(document.body.children)) child.removeAttribute("inert");
@@ -13331,6 +13999,6 @@ function provideBfDocumentReset() {
13331
13999
  inject(DestroyRef).onDestroy(() => resetBfDocument(document));
13332
14000
  });
13333
14001
  }
13334
- export { BF_COLOR_SCHEME_STORAGE, BF_DEFAULTS, BF_DEFAULT_LABELS, BF_DEFAULT_VALUES, BF_LABELS, BF_SIDEBAR_STATE_STORAGE, BF_TAB_BAR, BF_TAB_BAR_CONTROLLER, BF_TAB_LINKS, BfActionBarComponent, BfActionDirective, BfAlertComponent, BfAppFrameComponent, BfAvatarComponent, BfBadgeComponent, BfBreadcrumbComponent, BfBreadcrumbItemComponent, BfButtonComponent, BfCalendarComponent, BfCardComponent, BfCheckboxComponent, BfChipComponent, BfChipGroupComponent, BfColorSchemeService, BfDescriptionItemComponent, BfDescriptionListComponent, BfEmptyStateComponent, BfFieldComponent, BfIconButtonComponent, BfInputComponent, BfListComponent, BfListItemComponent, BfNavGroupComponent, BfNavItemComponent, BfPageHeaderComponent, BfPaginationComponent, BfProgressComponent, BfRadioGroupComponent, BfSegmentedComponent, BfSelectComponent, BfSidebarComponent, BfSidebarStateService, BfSkeletonComponent, BfSpinnerComponent, BfStatComponent, BfTabBarComponent, BfTabComponent, BfTabGroupComponent, BfTabPanelComponent, BfTableCellDirective, BfTableComponent, BfTextareaComponent, BfThemeSwitchComponent, BfToggleComponent, BfToolbarComponent, BfTopNavComponent, bfFieldControlClass, bfValidationMessage, provideBfColorScheme, provideBfDefaults, provideBfLabels, provideBfSidebarState, BUTTON_CLASSES as ɵBF_BUTTON_CLASSES, ICON_BUTTON_CLASSES as ɵBF_ICON_BUTTON_CLASSES, BF_NAV as ɵBF_NAV, FIELD_BOX as ɵFIELD_BOX, FIELD_ICON_END as ɵFIELD_ICON_END, FIELD_ICON_START as ɵFIELD_ICON_START, FIELD_PADDING_END as ɵFIELD_PADDING_END, FIELD_PADDING_START as ɵFIELD_PADDING_START, PILL_HIT as ɵPILL_HIT, compareIso as ɵcompareIso, createMemoryColorSchemeStorage as ɵcreateMemoryColorSchemeStorage, daysInMonth as ɵdaysInMonth, fieldDescribedBy as ɵfieldDescribedBy, fieldErrorMessageId as ɵfieldErrorMessageId, fieldErrorText as ɵfieldErrorText, fieldShowsError as ɵfieldShowsError, formatIsoDate as ɵformatIsoDate, localIsoDate as ɵlocalIsoDate, parseIsoDate as ɵparseIsoDate, provideBfDocumentReset as ɵprovideBfDocumentReset, uniqueId as ɵuniqueId, validIsoDate as ɵvalidIsoDate };
14002
+ export { BF_COLOR_SCHEME_STORAGE, BF_DEFAULTS, BF_DEFAULT_LABELS, BF_DEFAULT_VALUES, BF_LABELS, BF_SIDEBAR_STATE_STORAGE, BF_TAB_BAR, BF_TAB_BAR_CONTROLLER, BF_TAB_LINKS, BfActionBarComponent, BfActionDirective, BfAlertComponent, BfAppFrameComponent, BfAvatarComponent, BfBadgeComponent, BfBreadcrumbComponent, BfBreadcrumbItemComponent, BfButtonComponent, BfCalendarComponent, BfCardComponent, BfCheckboxComponent, BfChipComponent, BfChipGroupComponent, BfColorSchemeService, BfDescriptionItemComponent, BfDescriptionListComponent, BfEmptyStateComponent, BfFieldComponent, BfIconButtonComponent, BfInputComponent, BfListComponent, BfListItemComponent, BfNavGroupComponent, BfNavItemComponent, BfPageHeaderComponent, BfPaginationComponent, BfProgressComponent, BfRadioGroupComponent, BfSegmentedComponent, BfSelectComponent, BfSidebarComponent, BfSidebarStateService, BfSkeletonComponent, BfSpinnerComponent, BfStatComponent, BfStepComponent, BfStepsComponent, BfTabBarComponent, BfTabComponent, BfTabGroupComponent, BfTabPanelComponent, BfTableCellDirective, BfTableComponent, BfTextareaComponent, BfThemeSwitchComponent, BfTimelineComponent, BfTimelineEventComponent, BfToggleComponent, BfToolbarComponent, BfTopNavComponent, bfFieldControlClass, bfValidationMessage, provideBfColorScheme, provideBfDefaults, provideBfLabels, provideBfSidebarState, BUTTON_CLASSES as ɵBF_BUTTON_CLASSES, ICON_BUTTON_CLASSES as ɵBF_ICON_BUTTON_CLASSES, BF_NAV as ɵBF_NAV, FIELD_BOX as ɵFIELD_BOX, FIELD_ICON_END as ɵFIELD_ICON_END, FIELD_ICON_START as ɵFIELD_ICON_START, FIELD_PADDING_END as ɵFIELD_PADDING_END, FIELD_PADDING_START as ɵFIELD_PADDING_START, PILL_HIT as ɵPILL_HIT, compareIso as ɵcompareIso, createMemoryColorSchemeStorage as ɵcreateMemoryColorSchemeStorage, daysInMonth as ɵdaysInMonth, fieldDescribedBy as ɵfieldDescribedBy, fieldErrorMessageId as ɵfieldErrorMessageId, fieldErrorText as ɵfieldErrorText, fieldShowsError as ɵfieldShowsError, formatIsoDate as ɵformatIsoDate, localIsoDate as ɵlocalIsoDate, parseIsoDate as ɵparseIsoDate, provideBfDocumentReset as ɵprovideBfDocumentReset, uniqueId as ɵuniqueId, validIsoDate as ɵvalidIsoDate };
13335
14003
 
13336
14004
  //# sourceMappingURL=bitforgehq-ui.mjs.map