bitboss-ui 3.0.0-beta.4 → 3.0.0-beta.8

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/README.md +36 -29
  2. package/dist/ai/BbBadge.md +10 -5
  3. package/dist/ai/BbSelect.md +8 -0
  4. package/dist/ai/BbTable.md +257 -51
  5. package/dist/ai/changelog.json +86 -2
  6. package/dist/ai/components.json +25 -15
  7. package/dist/ai/guides/design-language.md +14 -14
  8. package/dist/ai/guides/design-tokens.md +25 -18
  9. package/dist/ai/guides/installation-and-plugin-setup.md +1 -1
  10. package/dist/ai/guides/migration/components/bb-dialog.md +35 -29
  11. package/dist/ai/guides/migration/components/bb-table.md +406 -28
  12. package/dist/ai/guides/migration/v2-to-v3.md +175 -75
  13. package/dist/ai/index.md +1 -1
  14. package/dist/ai/recipes/inertia/layout-scaffold.md +5 -1
  15. package/dist/ai/recipes/inertia/ownership-atlas.md +41 -20
  16. package/dist/ai/recipes/inertia/records-workspace.md +26 -7
  17. package/dist/ai/recipes/nuxt/layout-scaffold.md +5 -1
  18. package/dist/ai/recipes/nuxt/records-workspace.md +26 -7
  19. package/dist/ai/recipes/vue/layout-scaffold.md +5 -1
  20. package/dist/ai/recipes/vue/records-workspace.md +26 -7
  21. package/dist/ai/source/BbBaseInputContainer.md +26 -0
  22. package/dist/ai/source/BbBreadcrumbs.md +31 -0
  23. package/dist/ai/source/BbDialog.md +15 -9
  24. package/dist/ai/source/BbOffCanvas.md +17 -11
  25. package/dist/ai/source/BbProgress.md +2 -2
  26. package/dist/ai/source/BbTable.md +837 -787
  27. package/dist/ai/source/CommonInputWrapper.md +4 -0
  28. package/dist/components/BbPagination/BbPagination.vue.d.ts +1 -1
  29. package/dist/components/BbTable/BbTable.vue.d.ts +5 -2
  30. package/dist/components/BbTable/BbTable.vue_vue_type_script_setup_true_lang.js +439 -484
  31. package/dist/components/BbTable/types.d.ts +83 -21
  32. package/dist/components/BbTable/utils.d.ts +18 -3
  33. package/dist/components/BbTable/utils.js +36 -28
  34. package/dist/index.d.ts +5 -1
  35. package/dist/index.js +68 -67
  36. package/dist/llms-full.txt +1065 -265
  37. package/dist/llms-medium.txt +15 -15
  38. package/dist/llms.txt +1 -1
  39. package/dist/styles.css +1 -1
  40. package/llms.txt +1 -1
  41. package/package.json +1 -1
  42. package/dist/assets/svgs/sort.svg_raw.js +0 -4
@@ -802,7 +802,11 @@ const statusGroup: BbDropdownItem = {
802
802
 
803
803
  // Pipeline facet: `prefill: true` resolves a picked customer's name eagerly,
804
804
  // so a chip never sits on a bare id while this group's own submenu (inside
805
- // the Filters menu) has never been opened.
805
+ // the Filters menu) has never been opened. The eager flag belongs HERE, on
806
+ // the menu's copy only — the chip derives its own copy with
807
+ // `prefill: 'interaction'` (see FilterChip.vue), because a second dropdown
808
+ // redeclaring `prefill: true` would fetch every seeded facet twice on page
809
+ // load for nothing.
806
810
  const customerGroup: BbDropdownItem = {
807
811
  key: 'customer',
808
812
  label: 'Customer',
@@ -854,10 +858,10 @@ const menu = computed<BbDropdownItem[]>(() => [
854
858
  component sitting between `BbBadge` and `BbBadgeButton` breaks the
855
859
  badge's direct-child vnode scan (the companion must be a literal
856
860
  child). This IS "the chip is itself a dropdown onto the same filter
857
- group": `group` is the exact descriptor FilterRail declared, reused
858
- rather than redeclared, so this scoped picker and the Filters menu's
859
- own submenu can never drift apart. -->
860
- <BbDropdown :activator="chipRef" :items="[group]" :width="220">
861
+ group": `chipGroup` is derived from the exact descriptor FilterRail
862
+ declared (spread, one override — never redeclared), so this scoped
863
+ picker and the Filters menu's own submenu can never drift apart. -->
864
+ <BbDropdown :activator="chipRef" :items="[chipGroup]" :width="220">
861
865
  <BbDropdownGroup
862
866
  :id="groupKey"
863
867
  :model-value="modelValue"
@@ -891,9 +895,24 @@ const emit = defineEmits<{ 'update:modelValue': [value: unknown] }>();
891
895
 
892
896
  const chipRef = useTemplateRef('chipRef');
893
897
 
898
+ // The chip's own copy of the shared descriptor, one override: `prefill:
899
+ // 'interaction'`. BbDropdown mounts a pipeline resolver for every group it
900
+ // declares at its own root, independent of the panel ever opening — so if
901
+ // this second dropdown repeated the menu's `prefill: true` verbatim, each
902
+ // seeded pipeline facet would be fetched TWICE on page load, and the chip's
903
+ // copy of the result would feed nothing (the label below comes from the
904
+ // menu's resolution via context). `'interaction'` defers this copy's fetch
905
+ // to the moment the chip's dropdown is actually opened. For static array
906
+ // facets the override is inert — arrays resolve synchronously either way.
907
+ const chipGroup = computed<BbDropdownItem>(() => ({
908
+ ...props.group,
909
+ prefill: 'interaction',
910
+ }));
911
+
894
912
  // Reads the Filters menu's already-resolved selection — no twin fetch. A
895
- // pipeline group needs `prefill: true` (set on `group` by FilterRail) so this
896
- // never sits on a bare id/value while the menu's own submenu is unopened.
913
+ // pipeline group needs `prefill: true` (set on the MENU's copy of `group` by
914
+ // FilterRail) so this never sits on a bare id/value while the menu's own
915
+ // submenu is unopened.
897
916
  const dropdownFilters = useBbDropdownContext('invoice-filters');
898
917
  const chipText = computed(() => {
899
918
  const options =
@@ -648,7 +648,11 @@ paints a selected row but opens nothing is a dead affordance.
648
648
 
649
649
  `.plain-link`, `.table-flush` and the row tints are project CSS by design (the
650
650
  library ships no such classes), but they are the _same_ project CSS on every
651
- workspace page. Author them **once**, next to the layout, and import that file
651
+ workspace page. (`.table-flush`'s edge-inset rules address the table through
652
+ its grid containers — `> .bb-table__table > .bb-table__body > [role='row'] >
653
+ :first-child` — never through `table`/`tbody`/`tr`/`td`, which the table no
654
+ longer renders; the canonical block is in the BbTable guide § Styling hooks.)
655
+ Author them **once**, next to the layout, and import that file
652
656
  from the app entry — not per page, and never copy-pasted into a page's
653
657
  `<style scoped>`, which is how three pages end up with three underline colours.
654
658
 
@@ -735,7 +735,11 @@ const statusGroup: BbDropdownItem = {
735
735
 
736
736
  // Pipeline facet: `prefill: true` resolves a picked customer's name eagerly,
737
737
  // so a chip never sits on a bare id while this group's own submenu (inside
738
- // the Filters menu) has never been opened.
738
+ // the Filters menu) has never been opened. The eager flag belongs HERE, on
739
+ // the menu's copy only — the chip derives its own copy with
740
+ // `prefill: 'interaction'` (see FilterChip.vue), because a second dropdown
741
+ // redeclaring `prefill: true` would fetch every seeded facet twice on page
742
+ // load for nothing.
739
743
  const customerGroup: BbDropdownItem = {
740
744
  key: 'customer',
741
745
  label: 'Customer',
@@ -787,10 +791,10 @@ const menu = computed<BbDropdownItem[]>(() => [
787
791
  component sitting between `BbBadge` and `BbBadgeButton` breaks the
788
792
  badge's direct-child vnode scan (the companion must be a literal
789
793
  child). This IS "the chip is itself a dropdown onto the same filter
790
- group": `group` is the exact descriptor FilterRail declared, reused
791
- rather than redeclared, so this scoped picker and the Filters menu's
792
- own submenu can never drift apart. -->
793
- <BbDropdown :activator="chipRef" :items="[group]" :width="220">
794
+ group": `chipGroup` is derived from the exact descriptor FilterRail
795
+ declared (spread, one override — never redeclared), so this scoped
796
+ picker and the Filters menu's own submenu can never drift apart. -->
797
+ <BbDropdown :activator="chipRef" :items="[chipGroup]" :width="220">
794
798
  <BbDropdownGroup
795
799
  :id="groupKey"
796
800
  :model-value="modelValue"
@@ -824,9 +828,24 @@ const emit = defineEmits<{ 'update:modelValue': [value: unknown] }>();
824
828
 
825
829
  const chipRef = useTemplateRef('chipRef');
826
830
 
831
+ // The chip's own copy of the shared descriptor, one override: `prefill:
832
+ // 'interaction'`. BbDropdown mounts a pipeline resolver for every group it
833
+ // declares at its own root, independent of the panel ever opening — so if
834
+ // this second dropdown repeated the menu's `prefill: true` verbatim, each
835
+ // seeded pipeline facet would be fetched TWICE on page load, and the chip's
836
+ // copy of the result would feed nothing (the label below comes from the
837
+ // menu's resolution via context). `'interaction'` defers this copy's fetch
838
+ // to the moment the chip's dropdown is actually opened. For static array
839
+ // facets the override is inert — arrays resolve synchronously either way.
840
+ const chipGroup = computed<BbDropdownItem>(() => ({
841
+ ...props.group,
842
+ prefill: 'interaction',
843
+ }));
844
+
827
845
  // Reads the Filters menu's already-resolved selection — no twin fetch. A
828
- // pipeline group needs `prefill: true` (set on `group` by FilterRail) so this
829
- // never sits on a bare id/value while the menu's own submenu is unopened.
846
+ // pipeline group needs `prefill: true` (set on the MENU's copy of `group` by
847
+ // FilterRail) so this never sits on a bare id/value while the menu's own
848
+ // submenu is unopened.
830
849
  const dropdownFilters = useBbDropdownContext('invoice-filters');
831
850
  const chipText = computed(() => {
832
851
  const options =
@@ -657,6 +657,22 @@ export type BaseInputContainerSlots = {
657
657
  display: flex;
658
658
  flex-direction: column;
659
659
 
660
+ /*
661
+ * A field never sizes its own track from its content.
662
+ * -----------------------------------------------------------------
663
+ * As a grid or flex item this container's automatic minimum size is
664
+ * `min-content`, and for a select that is the ENTIRE placeholder string:
665
+ * the trigger paints its placeholder as real `nowrap` text, because a
666
+ * native `::placeholder` only exists on a real `<input>`. So a long
667
+ * placeholder used to widen the column it sat in, while a `BbTextInput`
668
+ * next to it held its own (its `<input>` floors at `min-width: 50px` and
669
+ * `::placeholder` is paint-only). In a `repeat(3, 1fr)` form row that
670
+ * measured 188.9 / 226 / 68px instead of three equal tracks.
671
+ *
672
+ * The floor lives on the control, not here — see `__control` below.
673
+ */
674
+ min-width: 0;
675
+
660
676
  /*
661
677
  * Compact mode
662
678
  * -----------------------------------------------------------------
@@ -961,6 +977,16 @@ export type BaseInputContainerSlots = {
961
977
  */
962
978
  display: grid;
963
979
 
980
+ /* Same reason as the container root: this is a flex item, so its
981
+ automatic minimum would re-introduce the content floor the root just
982
+ dropped. `min-width` has to be 0 on EVERY link between the sized
983
+ ancestor and the element that ellipses, or the chain stops truncating
984
+ at the first link that still says `auto`. The 50px keeps a squeezed
985
+ field usable, mirroring the `min-width: 50px` the native input and
986
+ textarea already carry so a select and a text input degrade
987
+ identically. */
988
+ min-width: min(50px, 100%);
989
+
964
990
  &--left {
965
991
  justify-items: flex-start;
966
992
  }
@@ -802,6 +802,37 @@ export type BbBreadcrumbsSlots = {
802
802
  display: none;
803
803
  }
804
804
 
805
+ /*
806
+ * Flush outer edge. A crumb paints no background in ANY state (base, hover
807
+ * and `aria-current` are all transparent, and BbBaseButton's ring is
808
+ * zero-spread), so its 4px inline padding is visible only as rhythm
809
+ * BETWEEN crumbs — at the component's own edge it is an invisible box
810
+ * pushing the first glyph off the text column it should align with. The
811
+ * list adds `--bb-ring-size` more, which is NOT dead: `overflow: hidden`
812
+ * clips at the padding box, so without it the ellipsis focus ring loses
813
+ * its outer 2px. Hence two different moves — zero the padding that buys
814
+ * nothing, bleed back the padding that does.
815
+ *
816
+ * Both are scoped to a list that IS the outer edge. With a prepend/append
817
+ * edge slot the list is interior, and the crumb next to that slot keeps
818
+ * its padding so the spacing there stays the same as between two crumbs.
819
+ */
820
+ &__container > &__list:first-child {
821
+ margin-inline-start: calc(-1 * var(--bb-ring-size));
822
+ }
823
+
824
+ &__container > &__list:last-child {
825
+ margin-inline-end: calc(-1 * var(--bb-ring-size));
826
+ }
827
+
828
+ &__container > &__list:first-child > &__item:first-of-type &__breadcrumb {
829
+ padding-inline-start: 0;
830
+ }
831
+
832
+ &__container > &__list:last-child > &__item:last-of-type &__breadcrumb {
833
+ padding-inline-end: 0;
834
+ }
835
+
805
836
  &__breadcrumb[aria-disabled='true'],
806
837
  &__breadcrumb:disabled {
807
838
  cursor: not-allowed;
@@ -657,6 +657,13 @@ export type { BbDialogSlots as BaseDialogSlots };
657
657
  ```css
658
658
  /* @inherit --transition-duration --max-width — set inline from props; @inherit --scrollbar-width — set on body by the scroll lock */
659
659
  .bb-dialog {
660
+ /* Axis split of --bb-panel-p: --px (inline) / --py (block),
661
+ each branching off it. Set the pair only when the axes differ; setting
662
+ --bb-panel-p alone keeps them equal. Local on this root class (not
663
+ :root) so scoped --bb-panel-p overrides keep reaching the slots; for
664
+ per-part asymmetry, scope --py to the part class. */
665
+ --px: var(--bb-panel-p);
666
+ --py: var(--bb-panel-p);
660
667
  --page-padding: 20px;
661
668
  --transition-timing-function: var(--bb-ease);
662
669
 
@@ -760,8 +767,7 @@ export type { BbDialogSlots as BaseDialogSlots };
760
767
  display: flex;
761
768
  flex-shrink: 0;
762
769
  justify-content: space-between;
763
- padding: var(--bb-panel-p) var(--bb-panel-p) calc(var(--bb-panel-p) / 2)
764
- var(--bb-panel-p);
770
+ padding: var(--py) var(--px) calc(var(--py) / 2) var(--px);
765
771
 
766
772
  .bb-dialog__title {
767
773
  font-size: var(--dialog-title-fs, calc(var(--bb-fs) + 2px));
@@ -792,8 +798,8 @@ export type { BbDialogSlots as BaseDialogSlots };
792
798
  --size: var(--close-size);
793
799
  --p: 7px;
794
800
  position: absolute;
795
- right: calc(var(--bb-panel-p) - var(--p));
796
- top: calc(var(--bb-panel-p) - var(--p));
801
+ right: calc(var(--px) - var(--p));
802
+ top: calc(var(--py) - var(--p));
797
803
  }
798
804
  }
799
805
 
@@ -804,20 +810,20 @@ export type { BbDialogSlots as BaseDialogSlots };
804
810
 
805
811
  &:first-child {
806
812
  .bb-dialog__body-content {
807
- padding-top: var(--bb-panel-p);
813
+ padding-top: var(--py);
808
814
 
809
815
  > .bb-close-button {
810
816
  --size: 28px;
811
817
  --p: 7px;
812
818
  position: absolute;
813
- right: calc(var(--bb-panel-p) - var(--p));
814
- top: calc(var(--bb-panel-p) - var(--p));
819
+ right: calc(var(--px) - var(--p));
820
+ top: calc(var(--py) - var(--p));
815
821
  }
816
822
  }
817
823
  }
818
824
 
819
825
  &-content {
820
- padding: 0px var(--bb-panel-p) var(--dialog-gap, var(--bb-panel-p));
826
+ padding: 0px var(--px) var(--dialog-gap, var(--py));
821
827
  }
822
828
 
823
829
  /* Hide any nested dialogs that are not open so that scale transition works without affecting fixed positioning */
@@ -828,7 +834,7 @@ export type { BbDialogSlots as BaseDialogSlots };
828
834
 
829
835
  .bb-dialog__footer {
830
836
  border-top: 1px solid var(--bb-border);
831
- padding: var(--dialog-gap, var(--bb-panel-p)) var(--bb-panel-p);
837
+ padding: var(--dialog-gap, var(--py)) var(--px);
832
838
  pointer-events: auto;
833
839
 
834
840
  &:empty {
@@ -892,6 +892,13 @@ export type BbOffCanvasSlots = {
892
892
  /* Duration for the stack shift + pad. Zeroed while a peer resizes so parents
893
893
  track the live size instead of lagging behind a 250ms animation. */
894
894
  --stack-transition-duration: var(--transition-duration);
895
+ /* Axis split of --bb-panel-p: --px (inline) / --py
896
+ (block), each branching off it. Set the pair only when the axes differ;
897
+ setting --bb-panel-p alone keeps them equal. Local on this root class
898
+ (not :root) so scoped --bb-panel-p overrides keep reaching the slots;
899
+ for per-part asymmetry, scope --py to the part class. */
900
+ --px: var(--bb-panel-p);
901
+ --py: var(--bb-panel-p);
895
902
  --transition-timing-function: var(--bb-ease);
896
903
  background-color: var(--bb-panel);
897
904
  border: 1px solid var(--bb-border);
@@ -1171,14 +1178,14 @@ export type BbOffCanvasSlots = {
1171
1178
  `:first-child` because an absolutely-positioned drag handle can precede the
1172
1179
  body in the DOM, which would defeat `:first-child`. */
1173
1180
  &.bb-offcanvas--no-header .bb-offcanvas__body-content {
1174
- padding-top: var(--bb-panel-p);
1181
+ padding-top: var(--py);
1175
1182
  }
1176
1183
 
1177
1184
  /* Make room for the handle so it does not overlap header content. */
1178
1185
  &.bb-offcanvas--has-handle.bb-offcanvas--bottom .bb-offcanvas__header,
1179
1186
  &.bb-offcanvas--has-handle.bb-offcanvas--bottom.bb-offcanvas--no-header
1180
1187
  .bb-offcanvas__body-content {
1181
- padding-top: calc(var(--bb-panel-p) + 12px);
1188
+ padding-top: calc(var(--py) + 12px);
1182
1189
  }
1183
1190
 
1184
1191
  .bb-offcanvas__header {
@@ -1191,8 +1198,7 @@ export type BbOffCanvasSlots = {
1191
1198
  display: flex;
1192
1199
  flex-shrink: 0;
1193
1200
  justify-content: space-between;
1194
- padding: var(--bb-panel-p) var(--bb-panel-p) calc(var(--bb-panel-p) / 2)
1195
- var(--bb-panel-p);
1201
+ padding: var(--py) var(--px) calc(var(--py) / 2) var(--px);
1196
1202
  position: relative;
1197
1203
  /* Header is a dependable drag surface even when content scrolls. */
1198
1204
  touch-action: none;
@@ -1227,8 +1233,8 @@ export type BbOffCanvasSlots = {
1227
1233
  --size: var(--close-size);
1228
1234
  --p: 7px;
1229
1235
  position: absolute;
1230
- right: calc(var(--bb-panel-p) - var(--p));
1231
- top: calc(var(--bb-panel-p) - var(--p));
1236
+ right: calc(var(--px) - var(--p));
1237
+ top: calc(var(--py) - var(--p));
1232
1238
  }
1233
1239
  }
1234
1240
 
@@ -1239,20 +1245,20 @@ export type BbOffCanvasSlots = {
1239
1245
 
1240
1246
  &:first-child {
1241
1247
  .bb-offcanvas__body-content {
1242
- padding-top: var(--bb-panel-p);
1248
+ padding-top: var(--py);
1243
1249
 
1244
1250
  > .bb-close-button {
1245
1251
  --size: 28px;
1246
1252
  --p: 7px;
1247
1253
  position: absolute;
1248
- right: calc(var(--bb-panel-p) - var(--p));
1249
- top: calc(var(--bb-panel-p) - var(--p));
1254
+ right: calc(var(--px) - var(--p));
1255
+ top: calc(var(--py) - var(--p));
1250
1256
  }
1251
1257
  }
1252
1258
  }
1253
1259
 
1254
1260
  .bb-offcanvas__body-content {
1255
- padding: 0px var(--bb-panel-p) var(--dialog-gap, var(--bb-panel-p));
1261
+ padding: 0px var(--px) var(--dialog-gap, var(--py));
1256
1262
  }
1257
1263
 
1258
1264
  /* Keep nested overlays out of flow while closed, mirroring dialog behavior. */
@@ -1264,7 +1270,7 @@ export type BbOffCanvasSlots = {
1264
1270
 
1265
1271
  .bb-offcanvas__footer {
1266
1272
  border-top: 1px solid var(--bb-border);
1267
- padding: var(--dialog-gap, var(--bb-panel-p)) var(--bb-panel-p);
1273
+ padding: var(--dialog-gap, var(--py)) var(--px);
1268
1274
  pointer-events: auto;
1269
1275
 
1270
1276
  &:empty {
@@ -126,8 +126,8 @@ export type BbProgressProps = {
126
126
  * --track — track height (default 4px)
127
127
  * --fill — bar color (default var(--bb-primary))
128
128
  * Declared on the root (not read with a fallback) so a consumer override wins
129
- * and an inherited --fill from an ancestor — BbTable publishes its own --fill
130
- * on .bb-table — is shadowed for this subtree instead of leaking into the bar.
129
+ * and an inherited --fill from an ancestor (any same-named local a consumer
130
+ * sets up-tree) is shadowed for this subtree instead of leaking into the bar.
131
131
  */
132
132
  .bb-progress {
133
133
  --track: 4px;