@conduction/nextcloud-vue 2.63.0 → 2.64.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 (100) hide show
  1. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js +154 -7
  2. package/dist/esm/components/CnAppNav/CnAppNav.vue2.js.map +1 -1
  3. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js +119 -42
  4. package/dist/esm/components/CnAppNav/CnAppNav.vue3.js.map +1 -1
  5. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js +87 -0
  6. package/dist/esm/components/CnAppRoot/CnAppRoot.vue2.js.map +1 -1
  7. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js +26 -24
  8. package/dist/esm/components/CnAppRoot/CnAppRoot.vue3.js.map +1 -1
  9. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js +61 -16
  10. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue2.js.map +1 -1
  11. package/dist/esm/components/CnAuditTrailCard/CnAuditTrailCard.vue3.js.map +1 -1
  12. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js +20 -0
  13. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue2.js.map +1 -1
  14. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js +3 -2
  15. package/dist/esm/components/CnAuditTrailWidget/CnAuditTrailWidget.vue3.js.map +1 -1
  16. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js +33 -2
  17. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue2.js.map +1 -1
  18. package/dist/esm/components/CnCellRenderer/CnCellRenderer.vue3.js.map +1 -1
  19. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js +29 -0
  20. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue2.js.map +1 -1
  21. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js +150 -133
  22. package/dist/esm/components/CnDashboardPage/CnDashboardPage.vue3.js.map +1 -1
  23. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js +37 -1
  24. package/dist/esm/components/CnDataTable/CnDataTable.vue2.js.map +1 -1
  25. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js +12 -4
  26. package/dist/esm/components/CnDataTable/CnDataTable.vue3.js.map +1 -1
  27. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js +66 -14
  28. package/dist/esm/components/CnDetailPage/CnDetailPage.vue2.js.map +1 -1
  29. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js +23 -14
  30. package/dist/esm/components/CnDetailPage/CnDetailPage.vue3.js.map +1 -1
  31. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js +81 -4
  32. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue2.js.map +1 -1
  33. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js +22 -5
  34. package/dist/esm/components/CnHeaderWidget/CnHeaderWidget.vue3.js.map +1 -1
  35. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js +30 -0
  36. package/dist/esm/components/CnIndexPage/CnIndexPage.vue2.js.map +1 -1
  37. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js +2 -2
  38. package/dist/esm/components/CnIndexPage/CnIndexPage.vue3.js.map +1 -1
  39. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js +5 -1
  40. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue2.js.map +1 -1
  41. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js +4 -2
  42. package/dist/esm/components/CnObjectListWidget/CnObjectListWidget.vue3.js.map +1 -1
  43. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js +63 -2
  44. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue2.js.map +1 -1
  45. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js +96 -37
  46. package/dist/esm/components/CnStagesWidget/CnStagesWidget.vue3.js.map +1 -1
  47. package/dist/esm/components/CnStagesWidget/stagesModel.js +5 -2
  48. package/dist/esm/components/CnStagesWidget/stagesModel.js.map +1 -1
  49. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js +52 -2
  50. package/dist/esm/components/CnStatWidget/CnStatWidget.vue2.js.map +1 -1
  51. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js +6 -6
  52. package/dist/esm/components/CnStatWidget/CnStatWidget.vue3.js.map +1 -1
  53. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js +14 -2
  54. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue2.js.map +1 -1
  55. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js +2 -1
  56. package/dist/esm/components/CnTabsWidget/CnTabsWidget.vue3.js.map +1 -1
  57. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js +73 -1
  58. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue2.js.map +1 -1
  59. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js +14 -2
  60. package/dist/esm/components/CnWidgetWrapper/CnWidgetWrapper.vue3.js.map +1 -1
  61. package/dist/esm/l10n/en.json.js +2 -1
  62. package/dist/esm/l10n/en.json.js.map +1 -1
  63. package/dist/esm/l10n/nl.json.js +2 -1
  64. package/dist/esm/l10n/nl.json.js.map +1 -1
  65. package/dist/esm/nextcloud-vue.css +331 -81
  66. package/dist/esm/utils/schemaRefSlug.js +19 -3
  67. package/dist/esm/utils/schemaRefSlug.js.map +1 -1
  68. package/dist/esm/utils/validateManifestV2.compiled.js +2 -2
  69. package/dist/esm/utils/validateManifestV2.compiled.js.map +1 -1
  70. package/dist/nextcloud-vue.cjs.js +6933 -5958
  71. package/dist/nextcloud-vue.cjs.js.map +2 -2
  72. package/dist/nextcloud-vue.css +331 -81
  73. package/l10n/en.json +2 -0
  74. package/l10n/nl.json +2 -0
  75. package/package.json +1 -1
  76. package/src/components/CnAppNav/CnAppNav.vue +297 -11
  77. package/src/components/CnAppRoot/CnAppRoot.md +4 -0
  78. package/src/components/CnAppRoot/CnAppRoot.vue +94 -1
  79. package/src/components/CnAuditTrailCard/CnAuditTrailCard.vue +61 -16
  80. package/src/components/CnAuditTrailWidget/CnAuditTrailWidget.vue +22 -1
  81. package/src/components/CnCellRenderer/CnCellRenderer.vue +33 -2
  82. package/src/components/CnDashboardPage/CnDashboardPage.vue +43 -2
  83. package/src/components/CnDataTable/CnDataTable.vue +45 -1
  84. package/src/components/CnDetailPage/CnDetailPage.md +4 -0
  85. package/src/components/CnDetailPage/CnDetailPage.vue +60 -1
  86. package/src/components/CnHeaderWidget/CnHeaderWidget.vue +116 -6
  87. package/src/components/CnIndexPage/CnIndexPage.vue +32 -2
  88. package/src/components/CnObjectListWidget/CnObjectListWidget.vue +7 -1
  89. package/src/components/CnStagesWidget/CnStagesWidget.vue +180 -2
  90. package/src/components/CnStagesWidget/stagesModel.js +5 -2
  91. package/src/components/CnStatWidget/CnStatWidget.vue +57 -3
  92. package/src/components/CnTabsWidget/CnTabsWidget.vue +15 -2
  93. package/src/components/CnWidgetWrapper/CnWidgetWrapper.md +4 -0
  94. package/src/components/CnWidgetWrapper/CnWidgetWrapper.vue +107 -1
  95. package/src/css/detail-page.css +10 -4
  96. package/src/css/kpi-card.css +24 -1
  97. package/src/css/table.css +18 -6
  98. package/src/schemas/app-manifest-v2.schema.json +113 -3
  99. package/src/utils/schemaRefSlug.js +19 -3
  100. package/src/utils/validateManifestV2.compiled.js +2 -2
@@ -185,7 +185,7 @@
185
185
  .cn-data-table th,
186
186
  .cn-data-table td {
187
187
  padding: calc(3 * var(--default-grid-baseline));
188
- text-align: left;
188
+ text-align: start;
189
189
  border-bottom: 1px solid var(--color-border);
190
190
  vertical-align: middle;
191
191
  max-width: var(--cn-table-cell-max-width, 22rem);
@@ -204,6 +204,18 @@
204
204
  white-space: normal;
205
205
  }
206
206
 
207
+ /* The secondary line of a cell (`columns[].secondary`): muted, smaller, on its
208
+ own line under the value. Theme hooks: --cn-table-secondary-size and
209
+ --cn-table-secondary-color. */
210
+ .cn-data-table .cn-table-cell__secondary {
211
+ display: block;
212
+ color: var(--cn-table-secondary-color, var(--color-text-maxcontrast));
213
+ font-size: var(--cn-table-secondary-size, 0.9em);
214
+ line-height: 1.35;
215
+ overflow: hidden;
216
+ text-overflow: ellipsis;
217
+ }
218
+
207
219
  /* Back to wrapping, for a column holding prose rather than a label:
208
220
  `columns: [{ key: 'description', cellClass: 'cn-cell--wrap' }]`. */
209
221
  .cn-data-table th.cn-cell--wrap,
@@ -265,7 +277,7 @@
265
277
  }
266
278
 
267
279
  .cn-data-table td.cn-cell--end {
268
- text-align: right;
280
+ text-align: end;
269
281
  white-space: nowrap;
270
282
  }
271
283
 
@@ -303,7 +315,7 @@
303
315
  }
304
316
 
305
317
  .cn-table-sort-indicator {
306
- margin-left: var(--default-grid-baseline);
318
+ margin-inline-start: var(--default-grid-baseline);
307
319
  opacity: 0.6;
308
320
  }
309
321
 
@@ -413,7 +425,7 @@
413
425
  justify-content: center;
414
426
  min-width: 14px;
415
427
  height: 14px;
416
- margin-left: 2px;
428
+ margin-inline-start: 2px;
417
429
  padding: 0 3px;
418
430
  border-radius: 7px;
419
431
  background-color: var(--color-primary-element);
@@ -478,7 +490,7 @@
478
490
 
479
491
  .cn-table-col--icon {
480
492
  width: 40px;
481
- padding-right: 0;
493
+ padding-inline-end: 0;
482
494
  text-align: center;
483
495
  color: var(--color-text-maxcontrast);
484
496
  }
@@ -541,7 +553,7 @@
541
553
 
542
554
  .viewTable { width: 100%; border-collapse: collapse; background-color: var(--color-main-background); }
543
555
 
544
- .viewTable th, .viewTable td { padding: calc(3 * var(--default-grid-baseline)); text-align: left; border-bottom: 1px solid var(--color-border); vertical-align: middle; }
556
+ .viewTable th, .viewTable td { padding: calc(3 * var(--default-grid-baseline)); text-align: start; border-bottom: 1px solid var(--color-border); vertical-align: middle; }
545
557
 
546
558
  .viewTable th { background: var(--color-background-hover); font-weight: 500; color: var(--color-text-maxcontrast); background-color: var(--color-background-dark); }
547
559
 
@@ -1037,7 +1049,7 @@
1037
1049
  padding: var(--cn-kpi-padding-flat, 8px);
1038
1050
  box-sizing: border-box;
1039
1051
  overflow: hidden;
1040
- text-align: left;
1052
+ text-align: start;
1041
1053
  text-decoration: none;
1042
1054
  color: inherit;
1043
1055
  background: transparent;
@@ -1152,6 +1164,29 @@
1152
1164
  white-space: nowrap;
1153
1165
  }
1154
1166
 
1167
+ /* A caption coloured by a rule (`captionVariant` / `overrides[].captionVariant`):
1168
+ "1 due today" in the error colour. Foreground tokens, which stay readable in
1169
+ dark mode. */
1170
+ .cn-kpi-card__label--primary {
1171
+ color: var(--color-primary-element);
1172
+ font-weight: 600;
1173
+ }
1174
+
1175
+ .cn-kpi-card__label--success {
1176
+ color: var(--color-text-success, var(--color-success-text));
1177
+ font-weight: 600;
1178
+ }
1179
+
1180
+ .cn-kpi-card__label--warning {
1181
+ color: var(--color-element-warning, var(--color-warning-text));
1182
+ font-weight: 600;
1183
+ }
1184
+
1185
+ .cn-kpi-card__label--error {
1186
+ color: var(--color-text-error, var(--color-error-text));
1187
+ font-weight: 600;
1188
+ }
1189
+
1155
1190
  /* Semantic variants. Each re-points the ONE accent token, so the icon tint
1156
1191
  and the number move together by construction — there is no second place to
1157
1192
  forget. The inline KPI below shares the same modifiers for the same reason:
@@ -2724,6 +2759,12 @@
2724
2759
  position: relative;
2725
2760
  }
2726
2761
 
2762
+ /* The breadcrumb line above the header (`config.breadcrumb`). */
2763
+ .cn-detail-page__breadcrumbs {
2764
+ margin-bottom: calc(2 * var(--default-grid-baseline));
2765
+ color: var(--color-text-maxcontrast);
2766
+ }
2767
+
2727
2768
  /* Header */
2728
2769
  .cn-detail-page__header {
2729
2770
  display: flex;
@@ -2891,7 +2932,7 @@
2891
2932
 
2892
2933
  .cn-detail-page__stats-table thead th {
2893
2934
  padding: calc(1.5 * var(--default-grid-baseline)) calc(2 * var(--default-grid-baseline));
2894
- text-align: left;
2935
+ text-align: start;
2895
2936
  font-weight: 600;
2896
2937
  font-size: 0.9em;
2897
2938
  color: var(--color-text-maxcontrast);
@@ -2916,7 +2957,7 @@
2916
2957
  }
2917
2958
 
2918
2959
  .cn-detail-page__stats-cell--indented {
2919
- padding-left: calc(5 * var(--default-grid-baseline)) !important;
2960
+ padding-inline-start: calc(5 * var(--default-grid-baseline)) !important;
2920
2961
  }
2921
2962
 
2922
2963
  .cn-detail-page__stats-cell--center {
@@ -2924,7 +2965,7 @@
2924
2965
  }
2925
2966
 
2926
2967
  .cn-detail-page__stats-cell--right {
2927
- text-align: right;
2968
+ text-align: end;
2928
2969
  }
2929
2970
 
2930
2971
  /* Body & content */
@@ -3058,7 +3099,7 @@
3058
3099
 
3059
3100
  .cn-detail-page__sidebar-toggle {
3060
3101
  position: fixed;
3061
- right: calc(5 * var(--default-grid-baseline));
3102
+ inset-inline-end: calc(5 * var(--default-grid-baseline));
3062
3103
  top: 80px;
3063
3104
  z-index: 10;
3064
3105
  }
@@ -6463,7 +6504,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
6463
6504
  .cn-data-table th,
6464
6505
  .cn-data-table td {
6465
6506
  padding: calc(3 * var(--default-grid-baseline));
6466
- text-align: left;
6507
+ text-align: start;
6467
6508
  border-bottom: 1px solid var(--color-border);
6468
6509
  vertical-align: middle;
6469
6510
  max-width: var(--cn-table-cell-max-width, 22rem);
@@ -6482,6 +6523,18 @@ svg.leaflet-image-layer.leaflet-interactive path {
6482
6523
  white-space: normal;
6483
6524
  }
6484
6525
 
6526
+ /* The secondary line of a cell (`columns[].secondary`): muted, smaller, on its
6527
+ own line under the value. Theme hooks: --cn-table-secondary-size and
6528
+ --cn-table-secondary-color. */
6529
+ .cn-data-table .cn-table-cell__secondary {
6530
+ display: block;
6531
+ color: var(--cn-table-secondary-color, var(--color-text-maxcontrast));
6532
+ font-size: var(--cn-table-secondary-size, 0.9em);
6533
+ line-height: 1.35;
6534
+ overflow: hidden;
6535
+ text-overflow: ellipsis;
6536
+ }
6537
+
6485
6538
  /* Back to wrapping, for a column holding prose rather than a label:
6486
6539
  `columns: [{ key: 'description', cellClass: 'cn-cell--wrap' }]`. */
6487
6540
  .cn-data-table th.cn-cell--wrap,
@@ -6543,7 +6596,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
6543
6596
  }
6544
6597
 
6545
6598
  .cn-data-table td.cn-cell--end {
6546
- text-align: right;
6599
+ text-align: end;
6547
6600
  white-space: nowrap;
6548
6601
  }
6549
6602
 
@@ -6581,7 +6634,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
6581
6634
  }
6582
6635
 
6583
6636
  .cn-table-sort-indicator {
6584
- margin-left: var(--default-grid-baseline);
6637
+ margin-inline-start: var(--default-grid-baseline);
6585
6638
  opacity: 0.6;
6586
6639
  }
6587
6640
 
@@ -6691,7 +6744,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
6691
6744
  justify-content: center;
6692
6745
  min-width: 14px;
6693
6746
  height: 14px;
6694
- margin-left: 2px;
6747
+ margin-inline-start: 2px;
6695
6748
  padding: 0 3px;
6696
6749
  border-radius: 7px;
6697
6750
  background-color: var(--color-primary-element);
@@ -6756,7 +6809,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
6756
6809
 
6757
6810
  .cn-table-col--icon {
6758
6811
  width: 40px;
6759
- padding-right: 0;
6812
+ padding-inline-end: 0;
6760
6813
  text-align: center;
6761
6814
  color: var(--color-text-maxcontrast);
6762
6815
  }
@@ -6819,7 +6872,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
6819
6872
 
6820
6873
  .viewTable { width: 100%; border-collapse: collapse; background-color: var(--color-main-background); }
6821
6874
 
6822
- .viewTable th, .viewTable td { padding: calc(3 * var(--default-grid-baseline)); text-align: left; border-bottom: 1px solid var(--color-border); vertical-align: middle; }
6875
+ .viewTable th, .viewTable td { padding: calc(3 * var(--default-grid-baseline)); text-align: start; border-bottom: 1px solid var(--color-border); vertical-align: middle; }
6823
6876
 
6824
6877
  .viewTable th { background: var(--color-background-hover); font-weight: 500; color: var(--color-text-maxcontrast); background-color: var(--color-background-dark); }
6825
6878
 
@@ -16058,6 +16111,27 @@ a.cn-xwiki-card__title[data-v-54e85fe3]:hover {
16058
16111
  flex-shrink: 0;
16059
16112
  }
16060
16113
 
16114
+ /* The header's text link (`headerLink`). Theme hooks: --cn-widget-header-link-size
16115
+ and --cn-widget-header-link-weight. */
16116
+ .cn-widget-wrapper__header-link[data-v-4dd77f59] {
16117
+ align-self: center;
16118
+ padding: 0 calc(1 * var(--default-grid-baseline));
16119
+ color: var(--color-primary-element);
16120
+ font-size: var(--cn-widget-header-link-size, 14px);
16121
+ font-weight: var(--cn-widget-header-link-weight, 600);
16122
+ text-decoration: none;
16123
+ white-space: nowrap;
16124
+ }
16125
+ .cn-widget-wrapper__header-link[data-v-4dd77f59]:hover,
16126
+ .cn-widget-wrapper__header-link[data-v-4dd77f59]:focus-visible {
16127
+ text-decoration: underline;
16128
+ }
16129
+ .cn-widget-wrapper__header-link[data-v-4dd77f59]:focus-visible {
16130
+ outline: 2px solid var(--color-primary-element);
16131
+ outline-offset: 2px;
16132
+ border-radius: var(--border-radius-small, 4px);
16133
+ }
16134
+
16061
16135
  /* Every widget's header icon is coloured — `--cn-widget-icon-color` is set on
16062
16136
  the header from titleIconStyle, and defaults to the theme colour if a
16063
16137
  wrapper is ever rendered without it. Material-design-icon components paint
@@ -16757,6 +16831,74 @@ a.cn-xwiki-card__title[data-v-54e85fe3]:hover {
16757
16831
  color: var(--color-text-maxcontrast);
16758
16832
  }
16759
16833
 
16834
+ /* The bars variant: equal columns, a thin bar per step. Theme hooks:
16835
+ --cn-stages-bar-height, --cn-stages-bar-radius, --cn-stages-bar-done,
16836
+ --cn-stages-bar-current, --cn-stages-bar-todo. */
16837
+ .cn-stages-widget__bars[data-v-358fde0f] {
16838
+ display: grid;
16839
+ grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
16840
+ grid-auto-flow: column;
16841
+ gap: 8px;
16842
+ margin: 0;
16843
+ padding: 0;
16844
+ list-style: none;
16845
+ }
16846
+ .cn-stages-widget__bar-step[data-v-358fde0f] {
16847
+ display: flex;
16848
+ flex-direction: column;
16849
+ gap: 8px;
16850
+ min-width: 0;
16851
+ }
16852
+ .cn-stages-widget__bar[data-v-358fde0f] {
16853
+ display: block;
16854
+ height: var(--cn-stages-bar-height, 6px);
16855
+ border-radius: var(--cn-stages-bar-radius, 3px);
16856
+ background: var(--cn-stages-bar-todo, var(--color-border));
16857
+ }
16858
+ .cn-stages-widget__bar-step--done .cn-stages-widget__bar[data-v-358fde0f] {
16859
+ background: var(--cn-stages-bar-done, var(--color-primary-element));
16860
+ }
16861
+ .cn-stages-widget__bar-step--current .cn-stages-widget__bar[data-v-358fde0f] {
16862
+ background: var(--cn-stages-bar-current, var(--color-error));
16863
+ }
16864
+ .cn-stages-widget__bar-label[data-v-358fde0f] {
16865
+ display: block;
16866
+ margin: 0;
16867
+ padding: 0;
16868
+ border: 0;
16869
+ background: none;
16870
+ color: var(--color-text-maxcontrast);
16871
+ font: inherit;
16872
+ font-size: 14px;
16873
+ text-align: start;
16874
+ overflow: hidden;
16875
+ text-overflow: ellipsis;
16876
+ white-space: nowrap;
16877
+ }
16878
+ button.cn-stages-widget__bar-label[data-v-358fde0f] {
16879
+ cursor: pointer;
16880
+ }
16881
+ button.cn-stages-widget__bar-label[aria-disabled="true"][data-v-358fde0f] {
16882
+ cursor: not-allowed;
16883
+ }
16884
+ button.cn-stages-widget__bar-label[data-v-358fde0f]:focus-visible {
16885
+ outline: 2px solid var(--color-primary-element);
16886
+ outline-offset: 2px;
16887
+ border-radius: var(--border-radius-small, 4px);
16888
+ }
16889
+ .cn-stages-widget__bar-step--done .cn-stages-widget__bar-label[data-v-358fde0f] {
16890
+ color: var(--color-main-text);
16891
+ font-weight: 600;
16892
+ }
16893
+ .cn-stages-widget__bar-step--current .cn-stages-widget__bar-label[data-v-358fde0f] {
16894
+ color: var(--color-main-text);
16895
+ font-weight: 700;
16896
+ }
16897
+ .cn-stages-widget__bar-date[data-v-358fde0f] {
16898
+ font-size: 12px;
16899
+ color: var(--color-text-maxcontrast);
16900
+ }
16901
+
16760
16902
  /* Text for screen readers only. */
16761
16903
  .cn-stages-widget__sr-only[data-v-358fde0f] {
16762
16904
  position: absolute;
@@ -16934,7 +17076,7 @@ a.cn-xwiki-card__title[data-v-54e85fe3]:hover {
16934
17076
  padding: var(--cn-kpi-padding-flat, 8px);
16935
17077
  box-sizing: border-box;
16936
17078
  overflow: hidden;
16937
- text-align: left;
17079
+ text-align: start;
16938
17080
  text-decoration: none;
16939
17081
  color: inherit;
16940
17082
  background: transparent;
@@ -17049,6 +17191,29 @@ a.cn-xwiki-card__title[data-v-54e85fe3]:hover {
17049
17191
  white-space: nowrap;
17050
17192
  }
17051
17193
 
17194
+ /* A caption coloured by a rule (`captionVariant` / `overrides[].captionVariant`):
17195
+ "1 due today" in the error colour. Foreground tokens, which stay readable in
17196
+ dark mode. */
17197
+ .cn-kpi-card__label--primary {
17198
+ color: var(--color-primary-element);
17199
+ font-weight: 600;
17200
+ }
17201
+
17202
+ .cn-kpi-card__label--success {
17203
+ color: var(--color-text-success, var(--color-success-text));
17204
+ font-weight: 600;
17205
+ }
17206
+
17207
+ .cn-kpi-card__label--warning {
17208
+ color: var(--color-element-warning, var(--color-warning-text));
17209
+ font-weight: 600;
17210
+ }
17211
+
17212
+ .cn-kpi-card__label--error {
17213
+ color: var(--color-text-error, var(--color-error-text));
17214
+ font-weight: 600;
17215
+ }
17216
+
17052
17217
  /* Semantic variants. Each re-points the ONE accent token, so the icon tint
17053
17218
  and the number move together by construction — there is no second place to
17054
17219
  forget. The inline KPI below shares the same modifiers for the same reason:
@@ -18003,6 +18168,68 @@ to { background-position: -200% 0;
18003
18168
  }
18004
18169
 
18005
18170
 
18171
+ .cn-segmented-control[data-v-7b344b4f] {
18172
+ display: inline-flex;
18173
+ gap: 4px;
18174
+ max-width: 100%;
18175
+ padding: 4px;
18176
+ border-radius: var(--border-radius-container, var(--border-radius-large, 10px));
18177
+ background-color: var(--color-background-dark);
18178
+ overflow-x: auto;
18179
+ }
18180
+ .cn-segmented-control--stretch[data-v-7b344b4f] {
18181
+ display: flex;
18182
+ }
18183
+ .cn-segmented-control--stretch .cn-segmented-control__option[data-v-7b344b4f] {
18184
+ flex: 1 1 0;
18185
+ }
18186
+
18187
+ /* The parent class outscores Nextcloud's server rule that gives every plain
18188
+ `button` a margin and a border. */
18189
+ .cn-segmented-control .cn-segmented-control__option[data-v-7b344b4f] {
18190
+ display: inline-flex;
18191
+ align-items: center;
18192
+ justify-content: center;
18193
+ gap: 8px;
18194
+ box-sizing: border-box;
18195
+ min-height: 36px;
18196
+ margin: 0;
18197
+ padding: 0 16px;
18198
+ border: 1px solid transparent;
18199
+ border-radius: var(--border-radius-element, var(--border-radius-large, 8px));
18200
+ background-color: transparent;
18201
+ /* Full-contrast label on every option: the choice is carried by the
18202
+ raised surface, not by dimming the others. */
18203
+ color: var(--color-main-text);
18204
+ font: inherit;
18205
+ font-weight: 600;
18206
+ white-space: nowrap;
18207
+ cursor: pointer;
18208
+ }
18209
+ .cn-segmented-control .cn-segmented-control__option[data-v-7b344b4f]:hover {
18210
+ background-color: var(--color-background-hover);
18211
+ }
18212
+ .cn-segmented-control .cn-segmented-control__option[data-v-7b344b4f]:focus-visible {
18213
+ outline: 2px solid var(--color-primary-element);
18214
+ outline-offset: 2px;
18215
+ }
18216
+
18217
+ /* The border survives forced-colours mode, which drops background and shadow. */
18218
+ .cn-segmented-control .cn-segmented-control__option--checked[data-v-7b344b4f],
18219
+ .cn-segmented-control .cn-segmented-control__option--checked[data-v-7b344b4f]:hover {
18220
+ border-color: var(--color-border-dark);
18221
+ background-color: var(--color-main-background);
18222
+ box-shadow: 0 1px 2px var(--color-box-shadow);
18223
+ }
18224
+ .cn-segmented-control .cn-segmented-control__option[disabled][data-v-7b344b4f] {
18225
+ cursor: default;
18226
+ opacity: 0.5;
18227
+ }
18228
+ .cn-segmented-control__count[data-v-7b344b4f] {
18229
+ font-weight: 400;
18230
+ }
18231
+
18232
+
18006
18233
  .cn-header-widget[data-v-1b97430f] {
18007
18234
  width: 100%;
18008
18235
  height: 100%;
@@ -18014,6 +18241,27 @@ to { background-position: -200% 0;
18014
18241
  min-height: 0;
18015
18242
  border-radius: 0;
18016
18243
  }
18244
+
18245
+ /* With a view switch the heading and the switch share one row, the switch
18246
+ at the right and bottom-aligned with the heading; on a narrow card the
18247
+ switch wraps under it. */
18248
+ .cn-header-widget--with-views[data-v-1b97430f] {
18249
+ display: flex;
18250
+ flex-wrap: wrap;
18251
+ align-items: flex-end;
18252
+ justify-content: space-between;
18253
+ gap: calc(2 * var(--default-grid-baseline)) calc(4 * var(--default-grid-baseline));
18254
+ }
18255
+ .cn-header-widget--with-views .cn-header-widget__content[data-v-1b97430f] {
18256
+ flex: 1 1 320px;
18257
+ width: auto;
18258
+ }
18259
+ .cn-header-widget__views[data-v-1b97430f] {
18260
+ position: relative;
18261
+ z-index: 1;
18262
+ flex: 0 0 auto;
18263
+ padding: 16px;
18264
+ }
18017
18265
  .cn-header-widget__date[data-v-1b97430f] {
18018
18266
  font-size: 14px;
18019
18267
  line-height: 1.4;
@@ -18075,7 +18323,7 @@ to { background-position: -200% 0;
18075
18323
  height: 1px;
18076
18324
  opacity: 0;
18077
18325
  pointer-events: none;
18078
- left: -9999px;
18326
+ inset-inline-start: -9999px;
18079
18327
  top: -9999px;
18080
18328
  }
18081
18329
  @media print {
@@ -32883,6 +33131,70 @@ a.cn-integration-card__title[data-v-f7e9bbfa]:hover {
32883
33131
  }
32884
33132
 
32885
33133
 
33134
+ /* The emblem beside the app name (`nav.brand.emblem`). A theme sets
33135
+ --nldesign-emblem-url for `emblem: true`, and --cn-nav-emblem-size for both. */
33136
+ .cn-app-nav__brand-emblem {
33137
+ flex: none;
33138
+ height: var(--cn-nav-emblem-size, 34px);
33139
+ width: auto;
33140
+ object-fit: contain;
33141
+ }
33142
+ .cn-app-nav__brand-emblem--theme {
33143
+ display: inline-block;
33144
+ width: var(--cn-nav-emblem-size, 34px);
33145
+ background: var(--nldesign-emblem-url) center / contain no-repeat;
33146
+ }
33147
+
33148
+ /* The solid primary action (`solid: true`, or an action that dispatches):
33149
+ one full-width primary button, as the board draws "New case". */
33150
+ .cn-app-nav__primary-action--solid .cn-action-buttons,
33151
+ .cn-app-nav__primary-action--solid .cn-action-buttons .button-vue,
33152
+ .cn-app-nav__primary-action--solid .button-vue {
33153
+ width: 100%;
33154
+ justify-content: center;
33155
+ }
33156
+
33157
+ /* The card above the footer entries (`nav.card`). Theme hooks:
33158
+ --cn-nav-card-background and --cn-nav-card-radius. */
33159
+ .cn-app-nav__card {
33160
+ display: flex;
33161
+ flex-direction: column;
33162
+ gap: calc(2 * var(--default-grid-baseline));
33163
+ margin: calc(2 * var(--default-grid-baseline));
33164
+ padding: calc(4 * var(--default-grid-baseline));
33165
+ border-radius: var(--cn-nav-card-radius, var(--border-radius-large));
33166
+ background: var(--cn-nav-card-background, var(--color-background-hover));
33167
+ }
33168
+ .cn-app-nav__card-title {
33169
+ color: var(--color-main-text);
33170
+ font-weight: 700;
33171
+ }
33172
+ .cn-app-nav__card-text {
33173
+ color: var(--color-text-maxcontrast);
33174
+ line-height: 1.4;
33175
+ }
33176
+ .cn-app-nav__card-link {
33177
+ align-self: flex-start;
33178
+ margin: 0;
33179
+ padding: 0;
33180
+ border: 0;
33181
+ background: none;
33182
+ color: var(--color-primary-element);
33183
+ font: inherit;
33184
+ font-weight: 600;
33185
+ text-decoration: none;
33186
+ cursor: pointer;
33187
+ }
33188
+ .cn-app-nav__card-link:hover,
33189
+ .cn-app-nav__card-link:focus-visible {
33190
+ text-decoration: underline;
33191
+ }
33192
+ .cn-app-nav__card-link:focus-visible {
33193
+ outline: 2px solid var(--color-primary-element);
33194
+ outline-offset: 2px;
33195
+ border-radius: var(--border-radius-small, 4px);
33196
+ }
33197
+
32886
33198
  /* The brand block at the top of the navigation. */
32887
33199
  .cn-app-nav__brand {
32888
33200
  align-items: center;
@@ -34771,68 +35083,6 @@ a.cn-integration-card__title[data-v-f7e9bbfa]:hover {
34771
35083
  }
34772
35084
 
34773
35085
 
34774
- .cn-segmented-control[data-v-7b344b4f] {
34775
- display: inline-flex;
34776
- gap: 4px;
34777
- max-width: 100%;
34778
- padding: 4px;
34779
- border-radius: var(--border-radius-container, var(--border-radius-large, 10px));
34780
- background-color: var(--color-background-dark);
34781
- overflow-x: auto;
34782
- }
34783
- .cn-segmented-control--stretch[data-v-7b344b4f] {
34784
- display: flex;
34785
- }
34786
- .cn-segmented-control--stretch .cn-segmented-control__option[data-v-7b344b4f] {
34787
- flex: 1 1 0;
34788
- }
34789
-
34790
- /* The parent class outscores Nextcloud's server rule that gives every plain
34791
- `button` a margin and a border. */
34792
- .cn-segmented-control .cn-segmented-control__option[data-v-7b344b4f] {
34793
- display: inline-flex;
34794
- align-items: center;
34795
- justify-content: center;
34796
- gap: 8px;
34797
- box-sizing: border-box;
34798
- min-height: 36px;
34799
- margin: 0;
34800
- padding: 0 16px;
34801
- border: 1px solid transparent;
34802
- border-radius: var(--border-radius-element, var(--border-radius-large, 8px));
34803
- background-color: transparent;
34804
- /* Full-contrast label on every option: the choice is carried by the
34805
- raised surface, not by dimming the others. */
34806
- color: var(--color-main-text);
34807
- font: inherit;
34808
- font-weight: 600;
34809
- white-space: nowrap;
34810
- cursor: pointer;
34811
- }
34812
- .cn-segmented-control .cn-segmented-control__option[data-v-7b344b4f]:hover {
34813
- background-color: var(--color-background-hover);
34814
- }
34815
- .cn-segmented-control .cn-segmented-control__option[data-v-7b344b4f]:focus-visible {
34816
- outline: 2px solid var(--color-primary-element);
34817
- outline-offset: 2px;
34818
- }
34819
-
34820
- /* The border survives forced-colours mode, which drops background and shadow. */
34821
- .cn-segmented-control .cn-segmented-control__option--checked[data-v-7b344b4f],
34822
- .cn-segmented-control .cn-segmented-control__option--checked[data-v-7b344b4f]:hover {
34823
- border-color: var(--color-border-dark);
34824
- background-color: var(--color-main-background);
34825
- box-shadow: 0 1px 2px var(--color-box-shadow);
34826
- }
34827
- .cn-segmented-control .cn-segmented-control__option[disabled][data-v-7b344b4f] {
34828
- cursor: default;
34829
- opacity: 0.5;
34830
- }
34831
- .cn-segmented-control__count[data-v-7b344b4f] {
34832
- font-weight: 400;
34833
- }
34834
-
34835
-
34836
35086
  .cn-brand-stripe[data-v-6fdfa763] {
34837
35087
  --cn-brand-stripe-first: var(--cn-brand-stripe-ratio-1, 1);
34838
35088
  --cn-brand-stripe-second: var(--cn-brand-stripe-ratio-2, 1);
@@ -35,9 +35,14 @@
35
35
  * registers author the slug by hand for multi-word titles) folds to one
36
36
  * `-`, leading/trailing dashes trimmed.
37
37
  *
38
- * Idempotent: a value that is already a slug (`report-period`, `cohort`)
39
- * passes through unchanged, so it is always safe to route an already-correct
40
- * value through this function defensively.
38
+ * Idempotent: a value that is already a slug (`report-period`, `cohort`,
39
+ * `statusType`) passes through unchanged, so it is always safe to route an
40
+ * already-correct value through this function defensively. A slug is any
41
+ * value that starts with a lowercase letter or digit and holds only
42
+ * letters, digits and dashes; only a title (capital initial, or spaces and
43
+ * punctuation) is kebab-cased.
44
+ *
45
+ * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-plain-schema-slug-is-left-as-written
41
46
  *
42
47
  * A numeric schema id (OpenRegister accepts either the slug or the numeric
43
48
  * id in the objects-API path) is returned unchanged — slugifying a number
@@ -63,6 +68,17 @@ function schemaRefSlug(ref) {
63
68
  if (tail === '') {
64
69
  return ''
65
70
  }
71
+ // A plain slug is left as written. OpenRegister matches a slug
72
+ // case-insensitively (`statusType`, `statustype` and `StatusType` all
73
+ // answer 200) but `status-type` is another slug and 404s, so a
74
+ // camelCase slug authored as a slug must not be kebab-cased. Only a
75
+ // `$ref` TITLE is: it starts with a capital (`ReportPeriod`) or carries
76
+ // spaces or punctuation (`Praktijkovereenkomst (POK)`). 2.62.0 kebab-cased
77
+ // everything and broke every camelCase slug (dossiq: statusType, caseType,
78
+ // caseObject, bezwaarDecision, bacAdviceRequest, wmsLayer, ...).
79
+ if (/^[a-z0-9][A-Za-z0-9-]*$/.test(tail)) {
80
+ return tail
81
+ }
66
82
  const kebab = tail
67
83
  // PascalCase / camelCase word boundaries: `ReportPeriod` -> `Report-Period`,
68
84
  // an acronym run followed by a new capitalised word: `HTTPServer` -> `HTTP-Server`.
@@ -1 +1 @@
1
- {"version":3,"file":"schemaRefSlug.js","sources":["../../../src/utils/schemaRefSlug.js"],"sourcesContent":["/**\n * Slugify an OpenRegister `$ref` schema reference into the objects API's\n * schema path segment.\n *\n * OpenRegister resolves `GET /api/objects/{register}/{schema}/...` by schema\n * **slug**, case-insensitively for a single-word title (`Cohort` and `cohort`\n * both answer 200), but a slug is only single-word-safe by accident: a\n * multi-word schema title such as `ReportPeriod` or `LearnerProfile` is\n * registered under its kebab-case slug (`report-period`, `learner-profile`)\n * and the PascalCase title itself 404s. A schema's `$ref` is authored as\n * that PascalCase (or spaced) title, not the slug, so every consumer that\n * built an objects-API path straight from `$ref` shipped the same defect\n * (learniq round-1 defect 7 — verified 2026-09-25: `ReportPeriod` and\n * `LearnerProfile` 404, `report-period` and `learner-profile` 200; 128\n * properties across 52 schema titles were affected, which is why\n * `ReportCardDetail` rendered with every relation panel blank).\n *\n * This module is the one fleet-wide fix: every resolver that turns a\n * `$ref` into an objects-API path segment routes through {@link schemaRefSlug}\n * instead of using the raw title. It is distinct from (and does not\n * replace) `savedViewHelpers.js`'s `schemaSlug()`, which reads an\n * ALREADY-KNOWN slug off a page's `schema` prop (string or `{ slug }`\n * object) — this module derives a slug from a raw, possibly-PascalCase\n * `$ref` title instead, so the two are kept as separate named exports\n * rather than overloading one name for two different inputs.\n *\n * @module utils/schemaRefSlug\n */\n\n/**\n * Kebab-case a schema `$ref` value into the OpenRegister objects-API schema\n * slug, matching the register convention (`SchemaMapper::generateSlug()`):\n * lowercase, every run of non `[a-z0-9]` characters (including a PascalCase\n * word boundary, which the PHP fallback never has to handle because these\n * registers author the slug by hand for multi-word titles) folds to one\n * `-`, leading/trailing dashes trimmed.\n *\n * Idempotent: a value that is already a slug (`report-period`, `cohort`)\n * passes through unchanged, so it is always safe to route an already-correct\n * value through this function defensively.\n *\n * A numeric schema id (OpenRegister accepts either the slug or the numeric\n * id in the objects-API path) is returned unchanged — slugifying a number\n * has no meaning and must never turn `85` into `'85'` and then reject it\n * downstream for being the \"wrong\" type.\n *\n * @param {unknown} ref A `$ref` value: a bare title/slug (`'ReportPeriod'`,\n * `'report-period'`), a JSON-Pointer (`'#/components/schemas/ReportPeriod'`),\n * or a numeric schema id.\n * @return {string|number} The kebab-case slug, the original number, or `''`\n * for a `ref` that carries no usable identifier (null/undefined/empty).\n */\nexport function schemaRefSlug(ref) {\n\tif (typeof ref === 'number') {\n\t\treturn Number.isNaN(ref) ? '' : ref\n\t}\n\tif (typeof ref !== 'string') {\n\t\treturn ''\n\t}\n\t// JSON-Pointer form (`#/components/schemas/<title>`) — take the tail,\n\t// the same rule `normalizeRef()` in `schema.js` already applies.\n\tconst tail = ref.includes('/') ? ref.substring(ref.lastIndexOf('/') + 1) : ref\n\tif (tail === '') {\n\t\treturn ''\n\t}\n\tconst kebab = tail\n\t\t// PascalCase / camelCase word boundaries: `ReportPeriod` -> `Report-Period`,\n\t\t// an acronym run followed by a new capitalised word: `HTTPServer` -> `HTTP-Server`.\n\t\t.replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n\t\t.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')\n\t\t.toLowerCase()\n\t\t// Spaces, punctuation, parentheses (`Praktijkovereenkomst (POK)`) all\n\t\t// fold to a single dash, exactly as the register's own fallback slug\n\t\t// generator treats anything outside `[a-z0-9-]`.\n\t\t.replace(/[^a-z0-9-]+/g, '-')\n\t\t.replace(/-+/g, '-')\n\t\t.replace(/^-+|-+$/g, '')\n\treturn kebab\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,aAAa,CAAC,GAAG,EAAE;AACnC,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AAC9B,EAAE,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG;AACrC,EAAE;AACF,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AAC9B,EAAE,OAAO,EAAE;AACX,EAAE;AACF;AACA;AACA,CAAC,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,IAAG;AAC/E,CAAC,IAAI,IAAI,KAAK,EAAE,EAAE;AAClB,EAAE,OAAO,EAAE;AACX,EAAE;AACF,CAAC,MAAM,KAAK,GAAG,IAAI;AACnB;AACA;AACA,GAAG,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;AACzC,GAAG,OAAO,CAAC,uBAAuB,EAAE,OAAO,CAAC;AAC5C,GAAG,WAAW,EAAE;AAChB;AACA;AACA;AACA,GAAG,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;AAC/B,GAAG,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;AACtB,GAAG,OAAO,CAAC,UAAU,EAAE,EAAE,EAAC;AAC1B,CAAC,OAAO,KAAK;AACb;;;;"}
1
+ {"version":3,"file":"schemaRefSlug.js","sources":["../../../src/utils/schemaRefSlug.js"],"sourcesContent":["/**\n * Slugify an OpenRegister `$ref` schema reference into the objects API's\n * schema path segment.\n *\n * OpenRegister resolves `GET /api/objects/{register}/{schema}/...` by schema\n * **slug**, case-insensitively for a single-word title (`Cohort` and `cohort`\n * both answer 200), but a slug is only single-word-safe by accident: a\n * multi-word schema title such as `ReportPeriod` or `LearnerProfile` is\n * registered under its kebab-case slug (`report-period`, `learner-profile`)\n * and the PascalCase title itself 404s. A schema's `$ref` is authored as\n * that PascalCase (or spaced) title, not the slug, so every consumer that\n * built an objects-API path straight from `$ref` shipped the same defect\n * (learniq round-1 defect 7 — verified 2026-09-25: `ReportPeriod` and\n * `LearnerProfile` 404, `report-period` and `learner-profile` 200; 128\n * properties across 52 schema titles were affected, which is why\n * `ReportCardDetail` rendered with every relation panel blank).\n *\n * This module is the one fleet-wide fix: every resolver that turns a\n * `$ref` into an objects-API path segment routes through {@link schemaRefSlug}\n * instead of using the raw title. It is distinct from (and does not\n * replace) `savedViewHelpers.js`'s `schemaSlug()`, which reads an\n * ALREADY-KNOWN slug off a page's `schema` prop (string or `{ slug }`\n * object) — this module derives a slug from a raw, possibly-PascalCase\n * `$ref` title instead, so the two are kept as separate named exports\n * rather than overloading one name for two different inputs.\n *\n * @module utils/schemaRefSlug\n */\n\n/**\n * Kebab-case a schema `$ref` value into the OpenRegister objects-API schema\n * slug, matching the register convention (`SchemaMapper::generateSlug()`):\n * lowercase, every run of non `[a-z0-9]` characters (including a PascalCase\n * word boundary, which the PHP fallback never has to handle because these\n * registers author the slug by hand for multi-word titles) folds to one\n * `-`, leading/trailing dashes trimmed.\n *\n * Idempotent: a value that is already a slug (`report-period`, `cohort`,\n * `statusType`) passes through unchanged, so it is always safe to route an\n * already-correct value through this function defensively. A slug is any\n * value that starts with a lowercase letter or digit and holds only\n * letters, digits and dashes; only a title (capital initial, or spaces and\n * punctuation) is kebab-cased.\n *\n * @spec openspec/changes/zuiddrecht-pixel-gaps/specs/zuiddrecht-pixel-gaps/spec.md#requirement-a-plain-schema-slug-is-left-as-written\n *\n * A numeric schema id (OpenRegister accepts either the slug or the numeric\n * id in the objects-API path) is returned unchanged — slugifying a number\n * has no meaning and must never turn `85` into `'85'` and then reject it\n * downstream for being the \"wrong\" type.\n *\n * @param {unknown} ref A `$ref` value: a bare title/slug (`'ReportPeriod'`,\n * `'report-period'`), a JSON-Pointer (`'#/components/schemas/ReportPeriod'`),\n * or a numeric schema id.\n * @return {string|number} The kebab-case slug, the original number, or `''`\n * for a `ref` that carries no usable identifier (null/undefined/empty).\n */\nexport function schemaRefSlug(ref) {\n\tif (typeof ref === 'number') {\n\t\treturn Number.isNaN(ref) ? '' : ref\n\t}\n\tif (typeof ref !== 'string') {\n\t\treturn ''\n\t}\n\t// JSON-Pointer form (`#/components/schemas/<title>`) — take the tail,\n\t// the same rule `normalizeRef()` in `schema.js` already applies.\n\tconst tail = ref.includes('/') ? ref.substring(ref.lastIndexOf('/') + 1) : ref\n\tif (tail === '') {\n\t\treturn ''\n\t}\n\t// A plain slug is left as written. OpenRegister matches a slug\n\t// case-insensitively (`statusType`, `statustype` and `StatusType` all\n\t// answer 200) but `status-type` is another slug and 404s, so a\n\t// camelCase slug authored as a slug must not be kebab-cased. Only a\n\t// `$ref` TITLE is: it starts with a capital (`ReportPeriod`) or carries\n\t// spaces or punctuation (`Praktijkovereenkomst (POK)`). 2.62.0 kebab-cased\n\t// everything and broke every camelCase slug (dossiq: statusType, caseType,\n\t// caseObject, bezwaarDecision, bacAdviceRequest, wmsLayer, ...).\n\tif (/^[a-z0-9][A-Za-z0-9-]*$/.test(tail)) {\n\t\treturn tail\n\t}\n\tconst kebab = tail\n\t\t// PascalCase / camelCase word boundaries: `ReportPeriod` -> `Report-Period`,\n\t\t// an acronym run followed by a new capitalised word: `HTTPServer` -> `HTTP-Server`.\n\t\t.replace(/([a-z0-9])([A-Z])/g, '$1-$2')\n\t\t.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')\n\t\t.toLowerCase()\n\t\t// Spaces, punctuation, parentheses (`Praktijkovereenkomst (POK)`) all\n\t\t// fold to a single dash, exactly as the register's own fallback slug\n\t\t// generator treats anything outside `[a-z0-9-]`.\n\t\t.replace(/[^a-z0-9-]+/g, '-')\n\t\t.replace(/-+/g, '-')\n\t\t.replace(/^-+|-+$/g, '')\n\treturn kebab\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,aAAa,CAAC,GAAG,EAAE;AACnC,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AAC9B,EAAE,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG;AACrC,EAAE;AACF,CAAC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;AAC9B,EAAE,OAAO,EAAE;AACX,EAAE;AACF;AACA;AACA,CAAC,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,IAAG;AAC/E,CAAC,IAAI,IAAI,KAAK,EAAE,EAAE;AAClB,EAAE,OAAO,EAAE;AACX,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,IAAI,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;AAC3C,EAAE,OAAO,IAAI;AACb,EAAE;AACF,CAAC,MAAM,KAAK,GAAG,IAAI;AACnB;AACA;AACA,GAAG,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;AACzC,GAAG,OAAO,CAAC,uBAAuB,EAAE,OAAO,CAAC;AAC5C,GAAG,WAAW,EAAE;AAChB;AACA;AACA;AACA,GAAG,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;AAC/B,GAAG,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;AACtB,GAAG,OAAO,CAAC,UAAU,EAAE,EAAE,EAAC;AAC1B,CAAC,OAAO,KAAK;AACb;;;;"}