@conduction/nextcloud-vue 2.89.1 → 2.90.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 (29) hide show
  1. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue.js +1 -1
  2. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js +13 -0
  3. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue2.js.map +1 -1
  4. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js +3 -1
  5. package/dist/esm/components/CnAdminSettingsShell/CnAdminSettingsShell.vue3.js.map +1 -1
  6. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue.js +1 -1
  7. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js +27 -10
  8. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue2.js.map +1 -1
  9. package/dist/esm/components/CnDashboardGrid/CnDashboardGrid.vue3.js.map +1 -1
  10. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue.js +1 -1
  11. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +18 -0
  12. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  13. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +2 -2
  14. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  15. package/dist/esm/library-style.js +1 -1
  16. package/dist/esm/nextcloud-vue.css +71 -71
  17. package/dist/esm/utils/declaredProps.js +106 -0
  18. package/dist/esm/utils/declaredProps.js.map +1 -0
  19. package/dist/esm/utils/gridStack.js +7 -3
  20. package/dist/esm/utils/gridStack.js.map +1 -1
  21. package/dist/nextcloud-vue.cjs.js +184 -30
  22. package/dist/nextcloud-vue.cjs.js.map +2 -2
  23. package/dist/nextcloud-vue.css +71 -71
  24. package/package.json +1 -1
  25. package/src/components/CnAdminSettingsShell/CnAdminSettingsShell.vue +14 -1
  26. package/src/components/CnDashboardGrid/CnDashboardGrid.vue +27 -10
  27. package/src/components/CnDashboardPage/CnDashboardPage.vue +20 -2
  28. package/src/utils/declaredProps.js +115 -0
  29. package/src/utils/gridStack.js +7 -3
@@ -34796,28 +34796,28 @@ to {
34796
34796
  }
34797
34797
 
34798
34798
 
34799
- .cn-admin-settings-shell[data-v-c3ceda64] {
34799
+ .cn-admin-settings-shell[data-v-038f200a] {
34800
34800
  max-width: 900px;
34801
34801
  }
34802
34802
 
34803
34803
  /* The board look lifts the width and lays the header and cards on a grid (look-board.css). */
34804
- .cn-support-info[data-v-c3ceda64] {
34804
+ .cn-support-info[data-v-038f200a] {
34805
34805
  margin-top: 16px;
34806
34806
  padding-top: 16px;
34807
34807
  border-top: 1px solid var(--color-border);
34808
34808
  }
34809
- .cn-support-info h4[data-v-c3ceda64] {
34809
+ .cn-support-info h4[data-v-038f200a] {
34810
34810
  margin: 0 0 8px 0;
34811
34811
  font-size: 14px;
34812
34812
  font-weight: 600;
34813
34813
  color: var(--color-main-text);
34814
34814
  }
34815
- .cn-support-info p[data-v-c3ceda64] {
34815
+ .cn-support-info p[data-v-038f200a] {
34816
34816
  margin: 4px 0;
34817
34817
  color: var(--color-text-maxcontrast);
34818
34818
  font-size: 14px;
34819
34819
  }
34820
- .cn-support-info a[data-v-c3ceda64] {
34820
+ .cn-support-info a[data-v-038f200a] {
34821
34821
  color: var(--color-primary-element);
34822
34822
  }
34823
34823
 
@@ -38141,17 +38141,17 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38141
38141
  }
38142
38142
 
38143
38143
 
38144
- .cn-dashboard-grid[data-v-a91998fc] {
38144
+ .cn-dashboard-grid[data-v-a76b6fc6] {
38145
38145
  width: 100%;
38146
38146
  min-height: 200px;
38147
38147
  }
38148
- .grid-stack[data-v-a91998fc] {
38148
+ .grid-stack[data-v-a76b6fc6] {
38149
38149
  background: transparent;
38150
38150
  }
38151
38151
 
38152
38152
  /* Screen-reader-only text: the keyboard key map and the live region. Kept in
38153
38153
  the layout (not `display: none`) so assistive tech still reads it. */
38154
- .cn-dashboard-grid__sr-only[data-v-a91998fc] {
38154
+ .cn-dashboard-grid__sr-only[data-v-a76b6fc6] {
38155
38155
  position: absolute;
38156
38156
  width: 1px;
38157
38157
  height: 1px;
@@ -38166,7 +38166,7 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38166
38166
  /* Grid items become tab stops in edit mode — give them a visible focus ring
38167
38167
  that satisfies WCAG 2.1 SC 2.4.7 without relying on the widget's own
38168
38168
  styling. `outline-offset` keeps the ring outside the rounded card. */
38169
- .grid-stack-item[data-v-a91998fc]:focus-visible {
38169
+ .grid-stack-item[data-v-a76b6fc6]:focus-visible {
38170
38170
  outline: 2px solid var(--color-primary-element, #0082c9);
38171
38171
  outline-offset: 2px;
38172
38172
  border-radius: var(--border-radius-container-large, 16px);
@@ -38178,19 +38178,19 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38178
38178
  cell never shrank: "Waiting for me" stayed a tall card around one row. In
38179
38179
  such a cell the child takes its own height. A cell without the key keeps
38180
38180
  the filling child. */
38181
- .cn-dashboard-grid__item--fit[data-v-a91998fc] > .grid-stack-item-content > * {
38181
+ .cn-dashboard-grid__item--fit[data-v-a76b6fc6] > .grid-stack-item-content > * {
38182
38182
  height: auto;
38183
38183
  }
38184
- [data-v-a91998fc] .grid-stack-item-content {
38184
+ [data-v-a76b6fc6] .grid-stack-item-content {
38185
38185
  background: var(--color-main-background);
38186
38186
  border: none;
38187
38187
  box-shadow: none;
38188
38188
  overflow: hidden;
38189
38189
  }
38190
- [data-v-a91998fc] .grid-stack-item-content:has(.cn-widget-wrapper--borderless) {
38190
+ [data-v-a76b6fc6] .grid-stack-item-content:has(.cn-widget-wrapper--borderless) {
38191
38191
  background: transparent;
38192
38192
  }
38193
- [data-v-a91998fc] .grid-stack-placeholder > .placeholder-content {
38193
+ [data-v-a76b6fc6] .grid-stack-placeholder > .placeholder-content {
38194
38194
  background: var(--color-primary-element-light);
38195
38195
  border: 2px dashed var(--color-primary-element);
38196
38196
  border-radius: var(--border-radius-large);
@@ -38458,7 +38458,7 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38458
38458
  }
38459
38459
 
38460
38460
 
38461
- .cn-dashboard-page[data-v-20ca81f3] {
38461
+ .cn-dashboard-page[data-v-42bc14a4] {
38462
38462
  padding: 20px;
38463
38463
  max-width: 1800px;
38464
38464
  /* Centre the leftover space once the cap engages, so a wide screen shows
@@ -38472,7 +38472,7 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38472
38472
  overflow-y: auto;
38473
38473
  box-sizing: border-box;
38474
38474
  }
38475
- .cn-dashboard-page__header[data-v-20ca81f3] {
38475
+ .cn-dashboard-page__header[data-v-42bc14a4] {
38476
38476
  display: flex;
38477
38477
  justify-content: space-between;
38478
38478
  align-items: flex-start;
@@ -38484,21 +38484,21 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38484
38484
  room. Only the HEADER shifts right — body widgets keep full width. */
38485
38485
  padding-inline-start: 56px;
38486
38486
  }
38487
- .cn-dashboard-page__header-left[data-v-20ca81f3] {
38487
+ .cn-dashboard-page__header-left[data-v-42bc14a4] {
38488
38488
  min-width: 0;
38489
38489
  }
38490
- .cn-dashboard-page__title-row[data-v-20ca81f3] {
38490
+ .cn-dashboard-page__title-row[data-v-42bc14a4] {
38491
38491
  display: flex;
38492
38492
  align-items: center;
38493
38493
  flex-wrap: wrap;
38494
38494
  gap: 12px;
38495
38495
  }
38496
- .cn-dashboard-page__title[data-v-20ca81f3] {
38496
+ .cn-dashboard-page__title[data-v-42bc14a4] {
38497
38497
  margin: 0;
38498
38498
  font-size: 20px;
38499
38499
  font-weight: 700;
38500
38500
  }
38501
- .cn-dashboard-page__description[data-v-20ca81f3] {
38501
+ .cn-dashboard-page__description[data-v-42bc14a4] {
38502
38502
  margin: 4px 0 0;
38503
38503
  font-size: 14px;
38504
38504
  color: var(--color-text-maxcontrast);
@@ -38506,19 +38506,19 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38506
38506
 
38507
38507
  /* Board look (screens-dashboard-parity): h1 28/700, a 15px grey subtitle 6px
38508
38508
  under it, and 40px buttons with a 10px gap. */
38509
- .cn-dashboard-page--board .cn-dashboard-page__title[data-v-20ca81f3] {
38509
+ .cn-dashboard-page--board .cn-dashboard-page__title[data-v-42bc14a4] {
38510
38510
  font-size: 28px;
38511
38511
  font-weight: 700;
38512
38512
  line-height: 1.2;
38513
38513
  }
38514
- .cn-dashboard-page--board .cn-dashboard-page__description[data-v-20ca81f3] {
38514
+ .cn-dashboard-page--board .cn-dashboard-page__description[data-v-42bc14a4] {
38515
38515
  margin: 6px 0 0;
38516
38516
  font-size: 15px;
38517
38517
  }
38518
- .cn-dashboard-page--board .cn-dashboard-page__header-actions[data-v-20ca81f3] {
38518
+ .cn-dashboard-page--board .cn-dashboard-page__header-actions[data-v-42bc14a4] {
38519
38519
  gap: 10px;
38520
38520
  }
38521
- .cn-dashboard-page--board .cn-dashboard-page__header-actions[data-v-20ca81f3] .button-vue {
38521
+ .cn-dashboard-page--board .cn-dashboard-page__header-actions[data-v-42bc14a4] .button-vue {
38522
38522
  min-height: var(--cn-board-control-height, 40px);
38523
38523
  height: var(--cn-board-control-height, 40px);
38524
38524
  }
@@ -38526,17 +38526,17 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38526
38526
  /* The switch row under the header (screens-dashboard-greeting-header): the
38527
38527
  view switch left, the `viewLinks` pills right (DqMijnWerk: pills 34px high,
38528
38528
  radius 17, 13px/600, a 14px icon, primary light on primary deep). */
38529
- .cn-dashboard-page__switch-row[data-v-20ca81f3] {
38529
+ .cn-dashboard-page__switch-row[data-v-42bc14a4] {
38530
38530
  display: flex;
38531
38531
  flex-wrap: wrap;
38532
38532
  align-items: center;
38533
38533
  gap: 10px;
38534
38534
  margin-bottom: var(--cn-board-section-gap, 20px);
38535
38535
  }
38536
- .cn-dashboard-page__switch-row-spacer[data-v-20ca81f3] {
38536
+ .cn-dashboard-page__switch-row-spacer[data-v-42bc14a4] {
38537
38537
  flex: 1 1 auto;
38538
38538
  }
38539
- .cn-dashboard-page__view-link[data-v-20ca81f3] {
38539
+ .cn-dashboard-page__view-link[data-v-42bc14a4] {
38540
38540
  display: inline-flex;
38541
38541
  align-items: center;
38542
38542
  gap: 6px;
@@ -38550,36 +38550,36 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38550
38550
  white-space: nowrap;
38551
38551
  text-decoration: none !important;
38552
38552
  }
38553
- .cn-dashboard-page__view-link[data-v-20ca81f3]:hover {
38553
+ .cn-dashboard-page__view-link[data-v-42bc14a4]:hover {
38554
38554
  background: var(--color-primary-element-light-hover, var(--color-primary-element-light));
38555
38555
  }
38556
- .cn-dashboard-page__view-link[data-v-20ca81f3]:focus-visible {
38556
+ .cn-dashboard-page__view-link[data-v-42bc14a4]:focus-visible {
38557
38557
  outline: 2px solid var(--color-main-text);
38558
38558
  outline-offset: 2px;
38559
38559
  }
38560
- .cn-dashboard-page__view-link-icon[data-v-20ca81f3] {
38560
+ .cn-dashboard-page__view-link-icon[data-v-42bc14a4] {
38561
38561
  display: inline-flex;
38562
38562
  }
38563
38563
 
38564
38564
  /* The period group, in a row of its own between the header and the KPI row. */
38565
- .cn-dashboard-page__date-range--segmented[data-v-20ca81f3] {
38565
+ .cn-dashboard-page__date-range--segmented[data-v-42bc14a4] {
38566
38566
  margin-bottom: 16px;
38567
38567
  }
38568
- .cn-dashboard-page__date-segmented[data-v-20ca81f3] {
38568
+ .cn-dashboard-page__date-segmented[data-v-42bc14a4] {
38569
38569
  display: flex;
38570
38570
  align-items: center;
38571
38571
  gap: 8px;
38572
38572
  }
38573
38573
 
38574
38574
  /* The KPI row above the grid: tiles are cells of the auto-fit grid. */
38575
- .cn-dashboard-page__kpi-row[data-v-20ca81f3] {
38575
+ .cn-dashboard-page__kpi-row[data-v-42bc14a4] {
38576
38576
  margin-bottom: var(--cn-board-section-gap, 16px);
38577
38577
  }
38578
- .cn-dashboard-page__kpi-cell[data-v-20ca81f3] {
38578
+ .cn-dashboard-page__kpi-cell[data-v-42bc14a4] {
38579
38579
  display: flex;
38580
38580
  min-width: 0;
38581
38581
  }
38582
- .cn-dashboard-page__kpi-cell[data-v-20ca81f3] > * {
38582
+ .cn-dashboard-page__kpi-cell[data-v-42bc14a4] > * {
38583
38583
  flex: 1 1 auto;
38584
38584
  min-width: 0;
38585
38585
  }
@@ -38592,7 +38592,7 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38592
38592
  scoped chip rules then silently don't match and the chip collapses into
38593
38593
  NcActions' ~30px icon slot (text wraps to "Last / 30 / days"). The
38594
38594
  data-testid is stable across chunks, so those rules match regardless. */
38595
- .cn-dashboard-page__header-actions[data-v-20ca81f3] {
38595
+ .cn-dashboard-page__header-actions[data-v-42bc14a4] {
38596
38596
  display: flex;
38597
38597
  align-items: center;
38598
38598
  gap: 8px;
@@ -38608,19 +38608,19 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38608
38608
 
38609
38609
  /* Date-range header band. Kept compact so it doesn't open a tall gap
38610
38610
  above the grid; the pills variant is a single tidy toggle row. */
38611
- .cn-dashboard-page__date-range[data-v-20ca81f3] {
38611
+ .cn-dashboard-page__date-range[data-v-42bc14a4] {
38612
38612
  margin-bottom: 12px;
38613
38613
  }
38614
- .cn-dashboard-page__date-range--pills[data-v-20ca81f3] {
38614
+ .cn-dashboard-page__date-range--pills[data-v-42bc14a4] {
38615
38615
  margin-bottom: 8px;
38616
38616
  }
38617
- .cn-dashboard-page__date-pills[data-v-20ca81f3] {
38617
+ .cn-dashboard-page__date-pills[data-v-42bc14a4] {
38618
38618
  display: flex;
38619
38619
  align-items: center;
38620
38620
  flex-wrap: wrap;
38621
38621
  gap: 6px;
38622
38622
  }
38623
- .cn-dashboard-page__date-pill[data-v-20ca81f3] {
38623
+ .cn-dashboard-page__date-pill[data-v-42bc14a4] {
38624
38624
  display: inline-flex;
38625
38625
  align-items: center;
38626
38626
  padding: 5px 14px;
@@ -38635,77 +38635,77 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38635
38635
  cursor: pointer;
38636
38636
  transition: background-color 100ms ease, border-color 100ms ease, color 100ms ease;
38637
38637
  }
38638
- .cn-dashboard-page__date-pill[data-v-20ca81f3]:hover {
38638
+ .cn-dashboard-page__date-pill[data-v-42bc14a4]:hover {
38639
38639
  background: var(--color-background-hover);
38640
38640
  }
38641
- .cn-dashboard-page__date-pill[data-v-20ca81f3]:focus-visible {
38641
+ .cn-dashboard-page__date-pill[data-v-42bc14a4]:focus-visible {
38642
38642
  outline: 2px solid var(--color-primary-element);
38643
38643
  outline-offset: 2px;
38644
38644
  }
38645
- .cn-dashboard-page__date-pill--active[data-v-20ca81f3] {
38645
+ .cn-dashboard-page__date-pill--active[data-v-42bc14a4] {
38646
38646
  background: var(--color-primary-element);
38647
38647
  border-color: var(--color-primary-element);
38648
38648
  color: var(--color-primary-element-text);
38649
38649
  }
38650
- .cn-dashboard-page__date-pill--active[data-v-20ca81f3]:hover {
38650
+ .cn-dashboard-page__date-pill--active[data-v-42bc14a4]:hover {
38651
38651
  background: var(--color-primary-element-hover, var(--color-primary-element));
38652
38652
  }
38653
38653
 
38654
38654
  /* The custom-range pill is de-emphasised — dashed outline, muted text —
38655
38655
  so it reads as an escape hatch rather than a primary option. */
38656
- .cn-dashboard-page__date-pill--custom[data-v-20ca81f3] {
38656
+ .cn-dashboard-page__date-pill--custom[data-v-42bc14a4] {
38657
38657
  border-style: dashed;
38658
38658
  color: var(--color-text-maxcontrast);
38659
38659
  }
38660
- .cn-dashboard-page__date-pill-custom[data-v-20ca81f3] .action-item__menutoggle {
38660
+ .cn-dashboard-page__date-pill-custom[data-v-42bc14a4] .action-item__menutoggle {
38661
38661
  min-width: 0;
38662
38662
  min-height: 0;
38663
38663
  padding: 0;
38664
38664
  background: transparent;
38665
38665
  border: none;
38666
38666
  }
38667
- .cn-dashboard-page__date-pill-custom[data-v-20ca81f3] .button-vue,
38668
- .cn-dashboard-page__date-pill-custom[data-v-20ca81f3] .button-vue__wrapper,
38669
- .cn-dashboard-page__date-pill-custom[data-v-20ca81f3] .button-vue__icon {
38667
+ .cn-dashboard-page__date-pill-custom[data-v-42bc14a4] .button-vue,
38668
+ .cn-dashboard-page__date-pill-custom[data-v-42bc14a4] .button-vue__wrapper,
38669
+ .cn-dashboard-page__date-pill-custom[data-v-42bc14a4] .button-vue__icon {
38670
38670
  width: auto !important;
38671
38671
  min-width: 0 !important;
38672
38672
  overflow: visible !important;
38673
38673
  }
38674
- .cn-dashboard-page__empty[data-v-20ca81f3] {
38674
+ .cn-dashboard-page__empty[data-v-42bc14a4] {
38675
38675
  padding: 60px 20px;
38676
38676
  }
38677
38677
 
38678
38678
  /* The page's view switch on a page without a header row: at the end of its
38679
38679
  own row, above the grids, where the header would have put it. */
38680
- .cn-dashboard-page__view-switch[data-v-20ca81f3] {
38680
+ .cn-dashboard-page__view-switch[data-v-42bc14a4] {
38681
38681
  display: flex;
38682
38682
  justify-content: flex-end;
38683
38683
  margin-bottom: 12px;
38684
38684
  }
38685
38685
 
38686
38686
  /* A view the switch shows with nothing to draw. */
38687
- .cn-page-view-region--empty[data-v-20ca81f3] {
38687
+ .cn-page-view-region--empty[data-v-42bc14a4] {
38688
38688
  padding: 40px 20px;
38689
38689
  }
38690
- .cn-dashboard-page__page-filters[data-v-20ca81f3] {
38690
+ .cn-dashboard-page__page-filters[data-v-42bc14a4] {
38691
38691
  display: flex;
38692
38692
  flex-wrap: wrap;
38693
38693
  gap: 16px;
38694
38694
  align-items: flex-end;
38695
38695
  margin-bottom: 12px;
38696
38696
  }
38697
- .cn-dashboard-page__page-filter[data-v-20ca81f3] {
38697
+ .cn-dashboard-page__page-filter[data-v-42bc14a4] {
38698
38698
  display: flex;
38699
38699
  flex-direction: column;
38700
38700
  gap: 4px;
38701
38701
  min-width: 200px;
38702
38702
  }
38703
- .cn-dashboard-page__page-filter-label[data-v-20ca81f3] {
38703
+ .cn-dashboard-page__page-filter-label[data-v-42bc14a4] {
38704
38704
  font-size: 0.85em;
38705
38705
  font-weight: 600;
38706
38706
  color: var(--color-text-maxcontrast);
38707
38707
  }
38708
- .cn-dashboard-page__widget-edit[data-v-20ca81f3] {
38708
+ .cn-dashboard-page__widget-edit[data-v-42bc14a4] {
38709
38709
  position: absolute;
38710
38710
  top: 4px;
38711
38711
  inset-inline-end: 4px;
@@ -38724,8 +38724,8 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38724
38724
  and centre the card. */
38725
38725
  /* `safe` centre so an overflowing tile does not spill out of the top, where
38726
38726
  flex overflow cannot be scrolled back to. Same as detail-page.css. */
38727
- .cn-dashboard-page__card-fit[data-v-20ca81f3] .cn-widget-wrapper__content,
38728
- .cn-dashboard-page__card-fit.cn-widget-wrapper--flush[data-v-20ca81f3] .cn-widget-wrapper__content {
38727
+ .cn-dashboard-page__card-fit[data-v-42bc14a4] .cn-widget-wrapper__content,
38728
+ .cn-dashboard-page__card-fit.cn-widget-wrapper--flush[data-v-42bc14a4] .cn-widget-wrapper__content {
38729
38729
  overflow: hidden;
38730
38730
  display: flex;
38731
38731
  flex-direction: column;
@@ -38741,7 +38741,7 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38741
38741
  shows up as a scrollbar the user has to drag to see the whole graph. Same
38742
38742
  shape as the card-fit rule above, minus the padding: chart tiles render
38743
38743
  `flush`, and apexcharts already draws its own margins. */
38744
- .cn-dashboard-page__chart-fit[data-v-20ca81f3] .cn-widget-wrapper__content {
38744
+ .cn-dashboard-page__chart-fit[data-v-42bc14a4] .cn-widget-wrapper__content {
38745
38745
  overflow: hidden;
38746
38746
  display: flex;
38747
38747
  flex-direction: column;
@@ -38751,13 +38751,13 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38751
38751
  /* Card content (stat / gauge / delta) must fit the tile width: let the
38752
38752
  widget shrink and its value/label truncate instead of pushing past the
38753
38753
  tile edge (the horizontal clip on long currency values). */
38754
- .cn-dashboard-page__card-fit[data-v-20ca81f3] .cn-stat-widget,
38755
- .cn-dashboard-page__card-fit[data-v-20ca81f3] .cn-gauge-widget,
38756
- .cn-dashboard-page__card-fit[data-v-20ca81f3] .cn-delta-widget {
38754
+ .cn-dashboard-page__card-fit[data-v-42bc14a4] .cn-stat-widget,
38755
+ .cn-dashboard-page__card-fit[data-v-42bc14a4] .cn-gauge-widget,
38756
+ .cn-dashboard-page__card-fit[data-v-42bc14a4] .cn-delta-widget {
38757
38757
  min-width: 0;
38758
38758
  max-width: 100%;
38759
38759
  }
38760
- .cn-dashboard-page__unknown[data-v-20ca81f3] {
38760
+ .cn-dashboard-page__unknown[data-v-42bc14a4] {
38761
38761
  display: flex;
38762
38762
  align-items: center;
38763
38763
  justify-content: center;
@@ -38768,29 +38768,29 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38768
38768
  }
38769
38769
 
38770
38770
  /* widget-ref content items */
38771
- .cn-dashboard-page__content[data-v-20ca81f3] {
38771
+ .cn-dashboard-page__content[data-v-42bc14a4] {
38772
38772
  display: flex;
38773
38773
  flex-direction: column;
38774
38774
  gap: 16px;
38775
38775
  }
38776
- .cn-dashboard-page__content-item[data-v-20ca81f3] {
38776
+ .cn-dashboard-page__content-item[data-v-42bc14a4] {
38777
38777
  width: 100%;
38778
38778
  }
38779
38779
  /* On a phone (screens-dashboard-phone) the touch targets of a board dashboard
38780
38780
  are 44px: the widget Actions menu and the KPI tiles. */
38781
38781
  @media (max-width: 640px) {
38782
- .cn-dashboard-page--board[data-v-20ca81f3] .cn-widget-wrapper__actions .action-item__menutoggle,
38783
- .cn-dashboard-page--board[data-v-20ca81f3] .cn-widget-wrapper__actions .button-vue {
38782
+ .cn-dashboard-page--board[data-v-42bc14a4] .cn-widget-wrapper__actions .action-item__menutoggle,
38783
+ .cn-dashboard-page--board[data-v-42bc14a4] .cn-widget-wrapper__actions .button-vue {
38784
38784
  min-height: 44px;
38785
38785
  }
38786
- .cn-dashboard-page--board .cn-dashboard-page__kpi-cell[data-v-20ca81f3] {
38786
+ .cn-dashboard-page--board .cn-dashboard-page__kpi-cell[data-v-42bc14a4] {
38787
38787
  min-height: 44px;
38788
38788
  }
38789
38789
  }
38790
38790
 
38791
38791
  /* What a registry widget reports for its card header (`header` event): the
38792
38792
  note beside the link ("3 in total") and one action, as on a detail page. */
38793
- .cn-dashboard-page__widget-count[data-v-20ca81f3] {
38793
+ .cn-dashboard-page__widget-count[data-v-42bc14a4] {
38794
38794
  align-self: center;
38795
38795
  padding: 1px 8px;
38796
38796
  border-radius: 10px;
@@ -38799,13 +38799,13 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38799
38799
  font-size: 13px;
38800
38800
  font-weight: 600;
38801
38801
  }
38802
- .cn-dashboard-page__widget-note[data-v-20ca81f3] {
38802
+ .cn-dashboard-page__widget-note[data-v-42bc14a4] {
38803
38803
  align-self: center;
38804
38804
  color: var(--color-text-maxcontrast);
38805
38805
  font-size: 14px;
38806
38806
  white-space: nowrap;
38807
38807
  }
38808
- .cn-dashboard-page__widget-action[data-v-20ca81f3] {
38808
+ .cn-dashboard-page__widget-action[data-v-42bc14a4] {
38809
38809
  display: inline-flex;
38810
38810
  align-items: center;
38811
38811
  align-self: center;
@@ -38821,7 +38821,7 @@ button.cn-object-calendar__overflow[data-v-e1c69ee2] {
38821
38821
  white-space: nowrap;
38822
38822
  cursor: pointer;
38823
38823
  }
38824
- .cn-dashboard-page__widget-action[data-v-20ca81f3]:focus-visible {
38824
+ .cn-dashboard-page__widget-action[data-v-42bc14a4]:focus-visible {
38825
38825
  outline: 2px solid var(--color-primary-element);
38826
38826
  outline-offset: 2px;
38827
38827
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conduction/nextcloud-vue",
3
- "version": "2.89.1",
3
+ "version": "2.90.0",
4
4
  "description": "Shared Vue component library for Conduction Nextcloud apps — complements @nextcloud/vue with higher-level components, OpenRegister integration, and NL Design System support",
5
5
  "homepage": "https://github.com/ConductionNL/nextcloud-vue#readme",
6
6
  "bugs": {
@@ -76,7 +76,7 @@
76
76
  :active="tab.id === activeTabId">
77
77
  <div class="cn-admin-settings-shell__panel" :data-tab="tab.id">
78
78
  <!-- @slot tab-<id> The panel of the tab with that `id` in `tabs`. -->
79
- <slot :name="`tab-${tab.id}`" />
79
+ <slot v-if="!lazyTabs || tab.id === activeTabId" :name="`tab-${tab.id}`" />
80
80
  </div>
81
81
  </CnTab>
82
82
  </CnTabs>
@@ -491,6 +491,19 @@ export default {
491
491
  default: '',
492
492
  },
493
493
 
494
+ /**
495
+ * Mount a tab's `tab-<id>` slot only while that tab is open, and
496
+ * unmount it when another tab opens, so each visit mounts it afresh
497
+ * and the page does not load every tab at once. Off (the default),
498
+ * every panel stays mounted and only the open one shows.
499
+ *
500
+ * @spec openspec/changes/admin-settings-lazy-tabs/specs/settings-board-look/spec.md#requirement-the-admin-shell-can-mount-only-the-open-tab
501
+ */
502
+ lazyTabs: {
503
+ type: Boolean,
504
+ default: false,
505
+ },
506
+
494
507
  /**
495
508
  * How the `tabs` strip is drawn, as CnTabs' `variant`: `line`, the
496
509
  * folder tabs (the default), or `underline`, plain labels on a rule
@@ -71,6 +71,7 @@
71
71
  <script>
72
72
  import { translate as t } from '@nextcloud/l10n'
73
73
  import { GridStack } from 'gridstack'
74
+ import { toRaw } from 'vue'
74
75
  import { planGrowth } from '../../utils/gridStack.js'
75
76
  // `gridstack` is a peerDependency (see package.json), not bundled — this
76
77
  // component's JS and the consumer's GridStack stylesheet MUST come from the
@@ -683,16 +684,27 @@ export default {
683
684
  * (`itemsInRowOrder`). A cell that shrinks is left to GridStack as
684
685
  * before.
685
686
  *
687
+ * The grid is read raw: through Vue's proxy `engine.nodes` holds proxies
688
+ * while `el.gridstackNode` is the plain node, so the growing cell would
689
+ * not be recognised among the nodes and would be moved down by its own
690
+ * growth. Moving a cell makes GridStack measure it again, so a cell the
691
+ * wrapper is already growing goes straight to GridStack.
692
+ *
686
693
  * @spec openspec/changes/dashboard-growth-keeps-order/specs/dashboard-grid/spec.md#requirement-a-growing-cell-keeps-the-order-of-the-cards-under-it
687
694
  * @return {void}
688
695
  */
689
696
  keepOrderOnGrowth() {
690
- const grid = this.grid
697
+ const grid = toRaw(this.grid)
691
698
  if (!grid || typeof grid.resizeToContent !== 'function' || typeof grid.update !== 'function') {
692
699
  return
693
700
  }
694
701
  const resize = grid.resizeToContent.bind(grid)
702
+ const growing = new Set()
695
703
  grid.resizeToContent = (el) => {
704
+ if (growing.has(el)) {
705
+ resize(el)
706
+ return
707
+ }
696
708
  const node = el && el.gridstackNode
697
709
  const nodes = grid.engine && Array.isArray(grid.engine.nodes) ? grid.engine.nodes : null
698
710
  const rows = node && nodes ? this.contentRows(el, node) : null
@@ -703,15 +715,20 @@ export default {
703
715
  }
704
716
  // Inside a batch the moves are not packed until the cell has grown.
705
717
  const batching = Boolean(grid.engine.batchMode)
706
- if (!batching) {
707
- grid.batchUpdate()
708
- }
709
- for (const step of plan) {
710
- grid.update(step.node.el, { y: step.y })
711
- }
712
- resize(el)
713
- if (!batching) {
714
- grid.batchUpdate(false)
718
+ growing.add(el)
719
+ try {
720
+ if (!batching) {
721
+ grid.batchUpdate()
722
+ }
723
+ for (const step of plan) {
724
+ grid.update(step.node.el, { y: step.y })
725
+ }
726
+ resize(el)
727
+ if (!batching) {
728
+ grid.batchUpdate(false)
729
+ }
730
+ } finally {
731
+ growing.delete(el)
715
732
  }
716
733
  }
717
734
  },
@@ -421,7 +421,7 @@
421
421
  :is="registryRenderer(item)"
422
422
  :widgetId="item.widgetId"
423
423
  :content="registryWidgetBindings(item)"
424
- v-bind="{ ...registryWidgetBindings(item), ...containerBindings(item) }"
424
+ v-bind="{ ...registryWidgetProps(item), ...containerBindings(item) }"
425
425
  @header="onWidgetHeader(item, $event)" />
426
426
  </CnWidgetWrapper>
427
427
  <CnWidgetWrapper
@@ -882,7 +882,7 @@
882
882
  :is="registryRenderer(item)"
883
883
  :widgetId="item.widgetId"
884
884
  :content="registryWidgetBindings(item)"
885
- v-bind="{ ...registryWidgetBindings(item), ...containerBindings(item), ...cellChromeBindings(item) }"
885
+ v-bind="{ ...registryWidgetProps(item), ...containerBindings(item), ...cellChromeBindings(item) }"
886
886
  @header="onWidgetHeader(item, $event)" />
887
887
  </CnWidgetWrapper>
888
888
  </template>
@@ -984,6 +984,7 @@ import { pageViews } from '../../mixins/pageViews.js'
984
984
  import { mergeUserLayout, resolveUserLayoutApi } from '../../store/plugins/dashboardLayouts.js'
985
985
  import { isAppInstalled } from '../../utils/appInstalled.js'
986
986
  import { contentHeaderLink } from '../../utils/contentHeaderLink.js'
987
+ import { pickDeclaredProps } from '../../utils/declaredProps.js'
987
988
  import { userLocale } from '../../utils/userLocale.js'
988
989
  import { compareVisibleWhen, evaluateWorkspaceCondition, isWorkspaceCondition, readVisibleWhenValue } from '../../utils/visibleWhen.js'
989
990
  import { canonicalWidgetType } from '../../utils/widgetTypeAliases.js'
@@ -3642,6 +3643,23 @@ export default {
3642
3643
  return outcome ? { ...content, conditionOutcome: outcome } : content
3643
3644
  },
3644
3645
 
3646
+ /**
3647
+ * The content keys a registry widget receives as props: only the ones
3648
+ * its renderer declares. An undeclared key would otherwise fall through
3649
+ * as an attribute onto the renderer's root component and could override
3650
+ * a value the widget computes for it. The whole content still arrives
3651
+ * as `content`. A renderer that forwards its own attributes
3652
+ * (`inheritAttrs: false`) keeps receiving every key.
3653
+ *
3654
+ * @param {object} item Layout item.
3655
+ * @return {object} The bindings the renderer declares.
3656
+ * @spec openspec/changes/dashboard-declared-widget-props/specs/dashboard-page/spec.md#requirement-a-dashboard-widget-receives-only-the-content-keys-it-declares
3657
+ */
3658
+ registryWidgetProps(item) {
3659
+ const def = this.getWidgetDef(item.widgetId)
3660
+ return pickDeclaredProps(this.registryRenderer(item), this.registryWidgetBindings(item), def?.type || item.widgetId)
3661
+ },
3662
+
3645
3663
  /**
3646
3664
  * What a container widget (registry `container`, such as `tabs`) needs
3647
3665
  * beside its content: the page's widget definitions, so its tabs find