@webority/ui-react 0.107.0 → 0.108.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 (195) hide show
  1. package/dist/canvas-kit/kit.js +26159 -26822
  2. package/dist/canvas-kit/manifest.json +1130 -1695
  3. package/dist/canvas-kit/release.json +6 -6
  4. package/dist/components/AppAccordion.js +1 -1
  5. package/dist/components/AppActionIcon.js +1 -1
  6. package/dist/components/AppAlert.js +1 -1
  7. package/dist/components/AppAsyncBlock.js +1 -1
  8. package/dist/components/AppAutocomplete.js +1 -1
  9. package/dist/components/AppAvatar.js +1 -1
  10. package/dist/components/AppAvatarGroup.js +1 -1
  11. package/dist/components/AppBadge.js +1 -1
  12. package/dist/components/AppBanner.js +1 -1
  13. package/dist/components/AppBreadcrumbs.js +1 -1
  14. package/dist/components/AppButton.js +1 -1
  15. package/dist/components/AppButtonGroup.js +1 -1
  16. package/dist/components/AppCalendar.js +1 -1
  17. package/dist/components/AppCard.js +1 -1
  18. package/dist/components/AppCarousel.js +1 -1
  19. package/dist/components/AppChart.js +1 -1
  20. package/dist/components/AppChartCard.js +1 -1
  21. package/dist/components/AppCheckbox.js +1 -1
  22. package/dist/components/AppChip.js +1 -1
  23. package/dist/components/AppChipGroup.js +1 -1
  24. package/dist/components/AppChoiceCard.js +1 -1
  25. package/dist/components/AppChoiceChip.js +1 -1
  26. package/dist/components/AppCodeBlock.js +1 -1
  27. package/dist/components/AppColorField.js +1 -1
  28. package/dist/components/AppColumnMenu.js +1 -1
  29. package/dist/components/AppCommandPalette.js +1 -1
  30. package/dist/components/AppCommentThread.js +1 -1
  31. package/dist/components/AppCompareTable.js +1 -1
  32. package/dist/components/AppConfirmDialog.js +1 -1
  33. package/dist/components/AppConsentBanner.js +1 -1
  34. package/dist/components/AppContextMenu.js +1 -1
  35. package/dist/components/AppCopyButton.js +1 -1
  36. package/dist/components/AppCountryFlag.js +1 -1
  37. package/dist/components/AppCountrySelect.js +1 -1
  38. package/dist/components/AppDashboardCell.js +1 -1
  39. package/dist/components/AppDashboardGrid.js +1 -1
  40. package/dist/components/AppDataTable.js +1 -1
  41. package/dist/components/AppDatePicker.js +1 -1
  42. package/dist/components/AppDateRangePicker.js +1 -1
  43. package/dist/components/AppDescriptions.js +1 -1
  44. package/dist/components/AppDetailPane.js +1 -1
  45. package/dist/components/AppDrawer.js +1 -1
  46. package/dist/components/AppDropZone.js +1 -1
  47. package/dist/components/AppDropdown.js +1 -1
  48. package/dist/components/AppDueDate.js +1 -1
  49. package/dist/components/AppEmptyState.js +1 -1
  50. package/dist/components/AppErrorSummary.js +1 -1
  51. package/dist/components/AppFileAttachment.js +1 -1
  52. package/dist/components/AppFilePicker.js +1 -1
  53. package/dist/components/AppFileTiles.js +1 -1
  54. package/dist/components/AppFileViewer.js +1 -1
  55. package/dist/components/AppFilterBar.js +1 -1
  56. package/dist/components/AppFloatingDock.js +1 -1
  57. package/dist/components/AppFormActions.js +1 -1
  58. package/dist/components/AppFormRow.js +1 -1
  59. package/dist/components/AppFormSection.js +1 -1
  60. package/dist/components/AppHoverCard.js +1 -1
  61. package/dist/components/AppIcon.js +1 -1
  62. package/dist/components/AppImagePicker.js +1 -0
  63. package/dist/components/AppInfoTip.js +1 -1
  64. package/dist/components/AppInlineEdit.js +1 -1
  65. package/dist/components/AppInput.js +1 -1
  66. package/dist/components/AppInputGroup.js +1 -1
  67. package/dist/components/AppKanban.js +1 -1
  68. package/dist/components/AppKbd.js +1 -1
  69. package/dist/components/AppKpiTile.js +1 -1
  70. package/dist/components/AppLightbox.js +1 -1
  71. package/dist/components/AppLink.js +1 -1
  72. package/dist/components/AppMarkdown.js +1 -1
  73. package/dist/components/AppMentionInput.js +1 -1
  74. package/dist/components/AppMeter.js +1 -1
  75. package/dist/components/AppMetricStrip.js +1 -1
  76. package/dist/components/AppModal.js +1 -1
  77. package/dist/components/AppMultiSelect.js +1 -1
  78. package/dist/components/AppNavList.js +1 -1
  79. package/dist/components/AppNavigationMenu.js +1 -1
  80. package/dist/components/AppNotificationCenter.js +1 -1
  81. package/dist/components/AppNumberInput.js +1 -1
  82. package/dist/components/AppOnboardingChecklist.js +1 -1
  83. package/dist/components/AppOtpInput.js +1 -1
  84. package/dist/components/AppPageHeader.js +1 -1
  85. package/dist/components/AppPhoneNumberInput.js +1 -1
  86. package/dist/components/AppPricingCard.js +1 -1
  87. package/dist/components/AppProgress.js +1 -1
  88. package/dist/components/AppQrCode.js +1 -1
  89. package/dist/components/AppRadio.js +1 -1
  90. package/dist/components/AppRadioGroup.js +1 -1
  91. package/dist/components/AppRating.js +1 -1
  92. package/dist/components/AppRecordPager.js +1 -1
  93. package/dist/components/AppRelativeTime.js +1 -1
  94. package/dist/components/AppRepeater.js +1 -1
  95. package/dist/components/AppResizable.js +1 -1
  96. package/dist/components/AppResizableHandle.js +1 -1
  97. package/dist/components/AppResizablePanel.js +1 -1
  98. package/dist/components/AppResourceCard.js +1 -1
  99. package/dist/components/AppResult.js +1 -1
  100. package/dist/components/AppRichText.js +1 -1
  101. package/dist/components/AppRollingNumber.js +1 -1
  102. package/dist/components/AppRouteError.js +1 -1
  103. package/dist/components/AppScrollbar.js +1 -1
  104. package/dist/components/AppSearch.js +1 -1
  105. package/dist/components/AppSectionCallToAction.js +1 -1
  106. package/dist/components/AppSectionFaq.js +1 -1
  107. package/dist/components/AppSectionFeatures.js +1 -1
  108. package/dist/components/AppSectionHero.js +1 -1
  109. package/dist/components/AppSectionLeadCapture.js +1 -0
  110. package/dist/components/AppSectionLogos.js +1 -1
  111. package/dist/components/AppSectionPricing.js +1 -1
  112. package/dist/components/AppSectionTestimonials.js +1 -1
  113. package/dist/components/AppSegmented.js +1 -1
  114. package/dist/components/AppSelect.js +1 -1
  115. package/dist/components/AppSeoHead.js +1 -0
  116. package/dist/components/AppShell.js +1 -1
  117. package/dist/components/AppShortcutLegend.js +1 -1
  118. package/dist/components/AppShowMore.js +1 -1
  119. package/dist/components/AppSkeleton.js +1 -1
  120. package/dist/components/AppSkeletonLines.js +1 -1
  121. package/dist/components/AppSlider.js +1 -1
  122. package/dist/components/AppSortableList.js +1 -1
  123. package/dist/components/AppSparkline.js +1 -1
  124. package/dist/components/AppSpinner.js +1 -1
  125. package/dist/components/AppSplash.js +1 -1
  126. package/dist/components/AppSplitButton.js +1 -1
  127. package/dist/components/AppSplitView.js +1 -1
  128. package/dist/components/AppStatusBadge.js +1 -1
  129. package/dist/components/AppStepper.js +1 -1
  130. package/dist/components/AppSwitch.js +1 -1
  131. package/dist/components/AppTablePagination.js +1 -1
  132. package/dist/components/AppTableToolbar.js +1 -1
  133. package/dist/components/AppTabs.js +1 -1
  134. package/dist/components/AppTagInput.js +1 -1
  135. package/dist/components/AppTextarea.js +1 -1
  136. package/dist/components/AppThemeToggle.js +1 -1
  137. package/dist/components/AppTimePicker.js +1 -1
  138. package/dist/components/AppTimeline.js +1 -1
  139. package/dist/components/AppToast.js +1 -1
  140. package/dist/components/AppToolbar.js +1 -1
  141. package/dist/components/AppTooltip.js +1 -1
  142. package/dist/components/AppTour.js +1 -1
  143. package/dist/components/AppTreeView.js +1 -1
  144. package/dist/components/AppTruncate.js +1 -1
  145. package/dist/components/AppUpdateBar.js +1 -1
  146. package/dist/components/AppWhatsNew.js +1 -1
  147. package/dist/components/AppWizard.js +1 -1
  148. package/dist/components/AppWorkspaceSwitcher.js +1 -1
  149. package/dist/components/iconCatalogNames.g.js +1 -1
  150. package/dist/components/iconGlyphs.g.js +1 -1
  151. package/dist/components/iconVariants.g.js +1 -1
  152. package/dist/guidance.json +119 -600
  153. package/dist/lib/useCommandPaletteShortcut.js +1 -1
  154. package/dist/lib/useFileDrop.js +1 -0
  155. package/dist/lib/wuiMarker.js +1 -1
  156. package/dist/types/components/AppAccordion.d.ts +1 -1
  157. package/dist/types/components/AppCompareTable.d.ts +45 -10
  158. package/dist/types/components/AppDescriptions.d.ts +10 -8
  159. package/dist/types/components/AppDrawer.d.ts +37 -0
  160. package/dist/types/components/AppEmptyState.d.ts +12 -5
  161. package/dist/types/components/AppImagePicker.d.ts +149 -0
  162. package/dist/types/components/AppInlineEdit.d.ts +0 -1
  163. package/dist/types/components/AppNavigationMenu.d.ts +1 -1
  164. package/dist/types/components/AppNotificationCenter.d.ts +16 -1
  165. package/dist/types/components/AppRecordPager.d.ts +2 -2
  166. package/dist/types/components/AppSectionLeadCapture.d.ts +67 -0
  167. package/dist/types/components/AppSelect.d.ts +7 -0
  168. package/dist/types/components/AppSeoHead.d.ts +42 -0
  169. package/dist/types/components/AppShortcutLegend.d.ts +13 -1
  170. package/dist/types/components/AppStepper.d.ts +2 -2
  171. package/dist/types/components/AppTablePagination.d.ts +36 -11
  172. package/dist/types/components/AppWhatsNew.d.ts +11 -2
  173. package/dist/types/components/iconGlyphs.g.d.ts +1 -0
  174. package/dist/types/components/iconVariants.g.d.ts +5 -0
  175. package/dist/types/index.d.ts +3 -8
  176. package/dist/types/lib/useFileDrop.d.ts +24 -0
  177. package/dist/types/lib/wuiMarker.d.ts +10 -0
  178. package/dist/ui-react.js +1 -1
  179. package/package.json +5 -5
  180. package/dist/components/AppAvatarPicker.js +0 -1
  181. package/dist/components/AppInfoList.js +0 -1
  182. package/dist/components/AppLogoPicker.js +0 -1
  183. package/dist/components/AppMenubar.js +0 -1
  184. package/dist/components/AppPagination.js +0 -1
  185. package/dist/components/AppSelectMini.js +0 -1
  186. package/dist/components/AppSidebarMenu.js +0 -1
  187. package/dist/components/AppTableEmptyState.js +0 -1
  188. package/dist/types/components/AppAvatarPicker.d.ts +0 -92
  189. package/dist/types/components/AppInfoList.d.ts +0 -29
  190. package/dist/types/components/AppLogoPicker.d.ts +0 -125
  191. package/dist/types/components/AppMenubar.d.ts +0 -50
  192. package/dist/types/components/AppPagination.d.ts +0 -39
  193. package/dist/types/components/AppSelectMini.d.ts +0 -53
  194. package/dist/types/components/AppSidebarMenu.d.ts +0 -90
  195. package/dist/types/components/AppTableEmptyState.d.ts +0 -22
@@ -2,7 +2,7 @@
2
2
  "format": "webority-guidance/1",
3
3
  "package": {
4
4
  "name": "@webority/ui-react",
5
- "version": "0.107.0"
5
+ "version": "0.108.0"
6
6
  },
7
7
  "components": [
8
8
  {
@@ -291,7 +291,7 @@
291
291
  },
292
292
  {
293
293
  "text": "The empty body of a data table specifically.",
294
- "instead": "AppTableEmptyState"
294
+ "instead": "AppEmptyState variant=\"table\""
295
295
  },
296
296
  {
297
297
  "text": "The whole app is booting, not one screen.",
@@ -530,7 +530,7 @@
530
530
  },
531
531
  {
532
532
  "text": "You are showing a company logo.",
533
- "instead": "AppLogoPicker"
533
+ "instead": "AppImagePicker"
534
534
  }
535
535
  ],
536
536
  "do": [
@@ -635,59 +635,6 @@
635
635
  ]
636
636
  }
637
637
  },
638
- {
639
- "name": "AppAvatarPicker",
640
- "usage": {
641
- "when": [
642
- "A person sets their own profile photo.",
643
- "An admin sets a staff member's photo on their record."
644
- ],
645
- "whenNot": [
646
- {
647
- "text": "A company or workspace logo, which is often not square.",
648
- "instead": "AppLogoPicker"
649
- },
650
- {
651
- "text": "Documents or other files.",
652
- "instead": "AppFileAttachment"
653
- }
654
- ],
655
- "do": [
656
- {
657
- "note": "Say what a good photo is. People crop better when they know.",
658
- "example": [
659
- {
660
- "component": "AppAvatarPicker",
661
- "props": {
662
- "initials": "NS",
663
- "label": "Profile photo",
664
- "hint": "Your face, looking at the camera."
665
- }
666
- }
667
- ]
668
- }
669
- ],
670
- "dont": [
671
- {
672
- "note": "A tiny, disabled picker with no label. Nobody can tell it sets their photo.",
673
- "example": [
674
- {
675
- "component": "AppAvatarPicker",
676
- "props": {
677
- "initials": "NS",
678
- "size": "sm",
679
- "disabled": true
680
- }
681
- }
682
- ]
683
- }
684
- ],
685
- "a11y": [
686
- "The photo button is named by ariaLabel, else by the action's words (Choose or Change photo), and is described by the error, else the hint.",
687
- "The photo button sits out of the tab order and reports busy while loading; the Upload button beside it is the keyboard path to the same action."
688
- ]
689
- }
690
- },
691
638
  {
692
639
  "name": "AppBadge",
693
640
  "usage": {
@@ -938,7 +885,8 @@
938
885
  "when": [
939
886
  "The user performs an action: submit, save, open a dialog, confirm.",
940
887
  "You need to mark the single most important action on a screen (one primary).",
941
- "A destructive action needs to stand out (danger): pair it with a confirm dialog."
888
+ "A destructive action needs to stand out (danger): pair it with a confirm dialog.",
889
+ "A form's submit button takes loading from the mutation state; that also blocks a second press."
942
890
  ],
943
891
  "whenNot": [
944
892
  {
@@ -2185,7 +2133,7 @@
2185
2133
  },
2186
2134
  {
2187
2135
  "text": "It is a list of facts about one thing.",
2188
- "instead": "AppInfoList"
2136
+ "instead": "AppDescriptions"
2189
2137
  }
2190
2138
  ],
2191
2139
  "do": [
@@ -2225,7 +2173,7 @@
2225
2173
  ],
2226
2174
  "dont": [
2227
2175
  {
2228
- "note": "Two highlighted columns highlight neither; internal jargon in the row label; and hand-typed dashes and Y instead of booleans lose the tick's shape cue.",
2176
+ "note": "Two highlighted columns both tint, so no option reads as the recommendation; internal jargon in the row label; and hand-typed dashes and Y instead of booleans lose the tick's shape cue.",
2229
2177
  "example": [
2230
2178
  {
2231
2179
  "component": "AppCompareTable",
@@ -2262,7 +2210,10 @@
2262
2210
  "a11y": [
2263
2211
  "The caption prop is a visually hidden table caption, read by a screen reader before the table.",
2264
2212
  "Column headings are th elements with scope col.",
2265
- "Each row label is a th element with scope row."
2213
+ "Each row label is a th element with scope row.",
2214
+ "Each cell repeats its column name in data-label, so a stacked phone card reads the same as the table.",
2215
+ "A state's icon is hidden from screen readers; its state is spoken as a hidden prefix such as Yes or Warning.",
2216
+ "With mobile scroll, the scrolling region is focusable and named by the caption."
2266
2217
  ]
2267
2218
  }
2268
2219
  },
@@ -2285,7 +2236,7 @@
2285
2236
  },
2286
2237
  {
2287
2238
  "text": "You're confirming across a slide-in panel of options.",
2288
- "instead": "AppSidebarMenu"
2239
+ "instead": "AppDrawer"
2289
2240
  }
2290
2241
  ],
2291
2242
  "do": [
@@ -2361,6 +2312,9 @@
2361
2312
  },
2362
2313
  {
2363
2314
  "text": "You are building the Razor head include that loads the tags and the consent record (the app-analytics-head tag)."
2315
+ },
2316
+ {
2317
+ "text": "You are starting analytics or tags by hand beside the banner. The choice saved through initConsent decides which analytics start: the analytics category turns PostHog capture and Clarity on, and Consent Mode holds Tag Manager's tags until analytics consent, or marketing consent when adStorage is on."
2364
2318
  }
2365
2319
  ],
2366
2320
  "do": [],
@@ -2545,7 +2499,7 @@
2545
2499
  },
2546
2500
  {
2547
2501
  "text": "The empty list deserves a rich call to action.",
2548
- "instead": "AppTableEmptyState (as empty)"
2502
+ "instead": "AppEmptyState variant=\"table\" (as empty)"
2549
2503
  }
2550
2504
  ],
2551
2505
  "do": [
@@ -2753,14 +2707,6 @@
2753
2707
  {
2754
2708
  "text": "You are listing many records.",
2755
2709
  "instead": "AppDataTable"
2756
- },
2757
- {
2758
- "text": "Each row has a leading icon and is actionable.",
2759
- "instead": "AppInfoList"
2760
- },
2761
- {
2762
- "text": "Values are facts without labels.",
2763
- "instead": "AppInfoList"
2764
2710
  }
2765
2711
  ],
2766
2712
  "do": [
@@ -2893,6 +2839,7 @@
2893
2839
  "usage": {
2894
2840
  "when": [
2895
2841
  "A filter, detail or edit panel that must not squeeze the page on a phone.",
2842
+ "A menu or filter panel that stays a side panel on a phone (sheet false).",
2896
2843
  "Secondary content the user opens, reads or edits, then dismisses."
2897
2844
  ],
2898
2845
  "whenNot": [
@@ -3145,17 +3092,14 @@
3145
3092
  "when": [
3146
3093
  "A card or section has loaded but there is genuinely nothing to show.",
3147
3094
  "A first-run experience where the user hasn't created anything yet.",
3148
- "A filtered or searched view returned no matches and you want to explain why."
3095
+ "A filtered or searched view returned no matches and you want to explain why.",
3096
+ "A data table has loaded with no rows: use variant=\"table\" for the table body."
3149
3097
  ],
3150
3098
  "whenNot": [
3151
3099
  {
3152
3100
  "text": "The data is still loading (first fetch).",
3153
3101
  "instead": "AppSkeleton"
3154
3102
  },
3155
- {
3156
- "text": "The empty result lives inside a data table body.",
3157
- "instead": "AppTableEmptyState"
3158
- },
3159
3103
  {
3160
3104
  "text": "Something went wrong fetching the data.",
3161
3105
  "instead": "AppAlert"
@@ -3281,7 +3225,7 @@
3281
3225
  },
3282
3226
  {
3283
3227
  "text": "The upload is a round avatar or a company logo.",
3284
- "instead": "AppLogoPicker"
3228
+ "instead": "AppImagePicker"
3285
3229
  },
3286
3230
  {
3287
3231
  "text": "It is a plain text or number field, not a file.",
@@ -3366,7 +3310,7 @@
3366
3310
  },
3367
3311
  {
3368
3312
  "text": "The upload is a round avatar or a company logo in a header.",
3369
- "instead": "AppLogoPicker"
3313
+ "instead": "AppImagePicker"
3370
3314
  },
3371
3315
  {
3372
3316
  "text": "It is a plain, non-image file input with no preview.",
@@ -3786,46 +3730,50 @@
3786
3730
  }
3787
3731
  },
3788
3732
  {
3789
- "name": "AppInfoList",
3733
+ "name": "AppImagePicker",
3790
3734
  "usage": {
3791
3735
  "when": [
3792
- "You are stating several facts about one record.",
3793
- "Some of the values are actionable (email, phone, a document link).",
3794
- "The panel is read-only, a details view, a drawer, a summary column."
3736
+ "An identity image is being set, such as a workspace logo, a company avatar or a profile picture.",
3737
+ "A person sets their own profile photo, or an admin sets a staff member's photo on their record.",
3738
+ "You want a hover-to-change overlay plus a loading state while the file uploads."
3795
3739
  ],
3796
3740
  "whenNot": [
3797
3741
  {
3798
- "text": "The values are editable.",
3799
- "instead": "AppInput and friends"
3800
- },
3801
- {
3802
- "text": "It is one headline number.",
3803
- "instead": "AppKpiTile"
3742
+ "text": "A single, rectangular image where the preview should be large.",
3743
+ "instead": "AppFilePicker"
3804
3744
  },
3805
3745
  {
3806
- "text": "You are listing many records.",
3807
- "instead": "AppDataTable"
3746
+ "text": "A file attached to a record where the name or size matters.",
3747
+ "instead": "AppFileAttachment"
3808
3748
  },
3809
3749
  {
3810
- "text": "The facts are events over time.",
3811
- "instead": "AppTimeline"
3750
+ "text": "You only need to display an avatar, not upload one.",
3751
+ "instead": "AppAvatar"
3812
3752
  }
3813
3753
  ],
3814
3754
  "do": [
3815
3755
  {
3816
- "note": "An icon that matches the field, a specific label, and an href only where the value is genuinely actionable.",
3756
+ "note": "Set an overlay label that names the thing, such as \"Change logo\", so the hover affordance says exactly what happens.",
3817
3757
  "example": [
3818
3758
  {
3819
- "component": "AppInfoList",
3759
+ "component": "AppImagePicker",
3820
3760
  "props": {
3821
- "items": [
3822
- {
3823
- "icon": "mail",
3824
- "label": "Email",
3825
- "value": "ravi@acme.example",
3826
- "href": "mailto:ravi@acme.example"
3827
- }
3828
- ]
3761
+ "fallback": "AC",
3762
+ "overlayLabel": "Change logo"
3763
+ }
3764
+ }
3765
+ ]
3766
+ },
3767
+ {
3768
+ "note": "Say what a good photo is. People crop better when they know.",
3769
+ "example": [
3770
+ {
3771
+ "component": "AppImagePicker",
3772
+ "props": {
3773
+ "kind": "avatar",
3774
+ "fallback": "NS",
3775
+ "label": "Profile photo",
3776
+ "hint": "Your face, looking at the camera."
3829
3777
  }
3830
3778
  }
3831
3779
  ]
@@ -3833,28 +3781,37 @@
3833
3781
  ],
3834
3782
  "dont": [
3835
3783
  {
3836
- "note": "A generic icon and “Info” as the label carry no meaning, and a placeholder href makes a dead link the reader will click.",
3784
+ "note": "A generic \"Click\" overlay tells the user how to interact but not what the action does.",
3837
3785
  "example": [
3838
3786
  {
3839
- "component": "AppInfoList",
3787
+ "component": "AppImagePicker",
3840
3788
  "props": {
3841
- "items": [
3842
- {
3843
- "icon": "circle",
3844
- "label": "Info",
3845
- "value": "ravi@acme.example",
3846
- "href": "#"
3847
- }
3848
- ]
3789
+ "fallback": "AC",
3790
+ "overlayLabel": "Click"
3791
+ }
3792
+ }
3793
+ ]
3794
+ },
3795
+ {
3796
+ "note": "A tiny, disabled avatar picker with no label. Nobody can tell it sets their photo.",
3797
+ "example": [
3798
+ {
3799
+ "component": "AppImagePicker",
3800
+ "props": {
3801
+ "kind": "avatar",
3802
+ "fallback": "NS",
3803
+ "size": "sm",
3804
+ "disabled": true
3849
3805
  }
3850
3806
  }
3851
3807
  ]
3852
3808
  }
3853
3809
  ],
3854
3810
  "a11y": [
3855
- "A row with an href renders as a link; a row without one renders as a plain row, so a value that cannot be acted on never looks clickable.",
3856
- "The icon tile sits beside the label and value text.",
3857
- "An empty value shows a dash placeholder."
3811
+ "The upload control is named by ariaLabel, else by Upload photo for the overlay and by the action's words (Choose or Change photo) for buttons. It is disabled and marked busy while loading.",
3812
+ "The remove control is its own button named by removeLabel, and it stays hidden until there is an image to remove.",
3813
+ "The hint or the error is tied to the upload control with aria-describedby, and an error wins over the hint.",
3814
+ "The buttons look sits out of the tab order and the Upload button beside it is the keyboard path to the same action."
3858
3815
  ]
3859
3816
  }
3860
3817
  },
@@ -4223,7 +4180,7 @@
4223
4180
  },
4224
4181
  {
4225
4182
  "text": "It is a label/value pair among several facts.",
4226
- "instead": "AppInfoList"
4183
+ "instead": "AppDescriptions"
4227
4184
  },
4228
4185
  {
4229
4186
  "text": "The number needs a chart to make sense.",
@@ -4357,91 +4314,6 @@
4357
4314
  ]
4358
4315
  }
4359
4316
  },
4360
- {
4361
- "name": "AppLogoPicker",
4362
- "usage": {
4363
- "when": [
4364
- "An identity image is being set, such as a workspace logo, a company avatar or a profile picture.",
4365
- "The upload lives in a header or settings panel, shown as a round ring.",
4366
- "You want a hover-to-change overlay plus a loading state while the file uploads."
4367
- ],
4368
- "whenNot": [
4369
- {
4370
- "text": "A single, rectangular image where the preview should be large.",
4371
- "instead": "AppFilePicker"
4372
- },
4373
- {
4374
- "text": "A file attached to a record where the name or size matters.",
4375
- "instead": "AppFileAttachment"
4376
- },
4377
- {
4378
- "text": "You only need to display an avatar, not upload one.",
4379
- "instead": "AppAvatar"
4380
- },
4381
- {
4382
- "text": "You hand-roll a raw <input type=\"file\"> with a circular mask.",
4383
- "instead": "AppLogoPicker"
4384
- }
4385
- ],
4386
- "do": [
4387
- {
4388
- "note": "Set an overlay label that names the thing, such as \"Change logo\", so the hover affordance says exactly what happens.",
4389
- "example": [
4390
- {
4391
- "component": "AppLogoPicker",
4392
- "props": {
4393
- "fallback": "AC",
4394
- "overlayLabel": "Change logo"
4395
- }
4396
- }
4397
- ]
4398
- },
4399
- {
4400
- "note": "Give the control a clear accessible name so screen readers announce the upload action, not just \"button\".",
4401
- "example": [
4402
- {
4403
- "component": "AppLogoPicker",
4404
- "props": {
4405
- "fallback": "WS",
4406
- "ariaLabel": "Upload workspace logo"
4407
- }
4408
- }
4409
- ]
4410
- }
4411
- ],
4412
- "dont": [
4413
- {
4414
- "note": "A generic \"Click\" overlay tells the user how to interact but not what the action does.",
4415
- "example": [
4416
- {
4417
- "component": "AppLogoPicker",
4418
- "props": {
4419
- "fallback": "AC",
4420
- "overlayLabel": "Click"
4421
- }
4422
- }
4423
- ]
4424
- },
4425
- {
4426
- "note": "A vague accessible name gives assistive tech nothing specific to announce for the control.",
4427
- "example": [
4428
- {
4429
- "component": "AppLogoPicker",
4430
- "props": {
4431
- "fallback": "WS",
4432
- "ariaLabel": "Upload photo"
4433
- }
4434
- }
4435
- ]
4436
- }
4437
- ],
4438
- "a11y": [
4439
- "The upload control is one button named by ariaLabel. It is disabled and marked busy while loading, and the spinner in the overlay is hidden from assistive technology.",
4440
- "The remove control is its own button named by removeLabel, and it stays hidden until there is an image to remove.",
4441
- "The hint or the error is tied to the upload button with aria-describedby, and an error wins over the hint. The picture has empty alt text because the button already carries the name."
4442
- ]
4443
- }
4444
- },
4445
4317
  {
4446
4318
  "name": "AppMarkdown",
4447
4319
  "usage": {
@@ -4497,36 +4369,6 @@
4497
4369
  ]
4498
4370
  }
4499
4371
  },
4500
- {
4501
- "name": "AppMenubar",
4502
- "usage": {
4503
- "when": [
4504
- "A tool or editor has many commands grouped by task, as in a desktop application.",
4505
- "Users expect keyboard movement across the groups and shortcut hints beside the commands."
4506
- ],
4507
- "whenNot": [
4508
- {
4509
- "text": "A site's top navigation with links and rich dropdown panels.",
4510
- "instead": "AppNavigationMenu"
4511
- },
4512
- {
4513
- "text": "One button or icon opens a short list of actions.",
4514
- "instead": "AppDropdown"
4515
- },
4516
- {
4517
- "text": "The actions belong to a row or card the user right-clicks.",
4518
- "instead": "AppContextMenu"
4519
- }
4520
- ],
4521
- "do": [],
4522
- "dont": [],
4523
- "a11y": [
4524
- "The bar has role menubar, named by ariaLabel. Each menu trigger is a menu item that reports aria-haspopup and aria-expanded, and its panel is a menu named by the menu label.",
4525
- "The bar is one tab stop. Left and Right move across the menus, Down and Up open one, Right opens a submenu, Escape closes a level and Tab leaves.",
4526
- "A disabled menu or row is announced as disabled and skipped by the arrow keys. A shortcut is announced as the key it names, but the page must bind it."
4527
- ]
4528
- }
4529
- },
4530
4372
  {
4531
4373
  "name": "AppMeter",
4532
4374
  "usage": {
@@ -4633,7 +4475,7 @@
4633
4475
  },
4634
4476
  {
4635
4477
  "text": "It's a slide-in navigation or filter panel on mobile.",
4636
- "instead": "AppSidebarMenu"
4478
+ "instead": "AppDrawer"
4637
4479
  },
4638
4480
  {
4639
4481
  "text": "The content is a full workflow with many steps and forms.",
@@ -4973,7 +4815,7 @@
4973
4815
  },
4974
4816
  {
4975
4817
  "text": "A signed-in app's sidebar of destinations.",
4976
- "instead": "AppSidebarMenu"
4818
+ "instead": "AppShell"
4977
4819
  },
4978
4820
  {
4979
4821
  "text": "A choice between several values in a form.",
@@ -4996,13 +4838,9 @@
4996
4838
  "Some entries are plain links beside the ones with panels."
4997
4839
  ],
4998
4840
  "whenNot": [
4999
- {
5000
- "text": "An application menubar of commands (File, Edit).",
5001
- "instead": "AppMenubar"
5002
- },
5003
4841
  {
5004
4842
  "text": "A signed-in app's sidebar of destinations.",
5005
- "instead": "AppSidebarMenu"
4843
+ "instead": "AppShell"
5006
4844
  },
5007
4845
  {
5008
4846
  "text": "One button opens a short list of actions.",
@@ -5023,7 +4861,8 @@
5023
4861
  "usage": {
5024
4862
  "when": [
5025
4863
  "A portal's list of things that happened to the person: approvals, comments, runs finished.",
5026
- "Anything that links to a record."
4864
+ "Anything that links to a record.",
4865
+ "A row needs its own controls, such as Accept and Decline buttons: pass renderItem(item), which returns the row's content in place of the icon, title, text and time. The dot, the Unread prefix and the read handling stay."
5027
4866
  ],
5028
4867
  "whenNot": [
5029
4868
  {
@@ -5326,38 +5165,6 @@
5326
5165
  ]
5327
5166
  }
5328
5167
  },
5329
- {
5330
- "name": "AppPagination",
5331
- "usage": {
5332
- "when": [
5333
- "You have a list of items split across multiple pages.",
5334
- "The user needs to move between pages via numbered buttons.",
5335
- "You're paginating cards, search results, or any content outside a table."
5336
- ],
5337
- "whenNot": [
5338
- {
5339
- "text": "The list is short and fits on one screen.",
5340
- "instead": "no pager"
5341
- },
5342
- {
5343
- "text": "You're paging a table and need a rows-per-page selector.",
5344
- "instead": "AppTablePagination"
5345
- },
5346
- {
5347
- "text": "The user should keep scrolling instead of paging.",
5348
- "instead": "infinite scroll"
5349
- }
5350
- ],
5351
- "do": [],
5352
- "dont": [],
5353
- "a11y": [
5354
- "The root is a nav element labelled by the ariaLabel prop, which defaults to Pagination.",
5355
- "The current page button carries aria-current set to page.",
5356
- "Each numbered page button is labelled Page N; the Previous and Next buttons are labelled Previous page and Next page.",
5357
- "The ellipsis is hidden from assistive technology."
5358
- ]
5359
- }
5360
- },
5361
5168
  {
5362
5169
  "name": "AppPhoneNumberInput",
5363
5170
  "usage": {
@@ -6024,7 +5831,7 @@
6024
5831
  "whenNot": [
6025
5832
  {
6026
5833
  "text": "Moving between pages of a list.",
6027
- "instead": "AppPagination"
5834
+ "instead": "AppTablePagination"
6028
5835
  }
6029
5836
  ],
6030
5837
  "do": [],
@@ -6763,6 +6570,32 @@
6763
6570
  ]
6764
6571
  }
6765
6572
  },
6573
+ {
6574
+ "name": "AppSectionLeadCapture",
6575
+ "usage": {
6576
+ "when": [
6577
+ "A marketing page that asks for a lead: a demo, a quote or a callback.",
6578
+ "Up to five short fields, sent by a server action that rejects with a curated message, never a raw exception, because the visitor sees it."
6579
+ ],
6580
+ "whenNot": [
6581
+ {
6582
+ "text": "A form with more than five fields, or with several steps.",
6583
+ "instead": "AppFormSection"
6584
+ },
6585
+ {
6586
+ "text": "A sign-in or account form.",
6587
+ "instead": "AppFormSection"
6588
+ }
6589
+ ],
6590
+ "do": [],
6591
+ "dont": [],
6592
+ "a11y": [
6593
+ "Each field has a visible label, and a required field is marked as required to the browser.",
6594
+ "The form is not validated by the browser, so the messages shown are the section's own, next to each field.",
6595
+ "A failed send is announced in an alert above the button, and a sent form is replaced by a success alert."
6596
+ ]
6597
+ }
6598
+ },
6766
6599
  {
6767
6600
  "name": "AppSectionLogos",
6768
6601
  "usage": {
@@ -6921,7 +6754,8 @@
6921
6754
  "when": [
6922
6755
  "The user picks one value from a known set of roughly 6 or more options.",
6923
6756
  "The options are a fixed list you can render up front, such as statuses, clients or categories.",
6924
- "You want a compact control that keeps the choices collapsed until opened."
6757
+ "You want a compact control that keeps the choices collapsed until opened.",
6758
+ "compact for toolbars, sort and filter pickers; a labelled form field omits compact."
6925
6759
  ],
6926
6760
  "whenNot": [
6927
6761
  {
@@ -6935,10 +6769,6 @@
6935
6769
  {
6936
6770
  "text": "The list is large or loaded from the server as the user types.",
6937
6771
  "instead": "AppAutocomplete"
6938
- },
6939
- {
6940
- "text": "It is a compact single-purpose picker like page size.",
6941
- "instead": "AppSelectMini"
6942
6772
  }
6943
6773
  ],
6944
6774
  "do": [
@@ -7142,158 +6972,21 @@
7142
6972
  }
7143
6973
  },
7144
6974
  {
7145
- "name": "AppSelectMini",
6975
+ "name": "AppSeoHead",
7146
6976
  "usage": {
7147
6977
  "when": [
7148
- "A compact, single-purpose picker in a toolbar or table header: page size, a status filter, a sort order.",
7149
- "The choice sits inline next to other controls and a full labelled field would be too heavy.",
7150
- "The option set is short and self-explanatory from the values alone."
6978
+ "A public page needs its title, search description, social preview and structured data in the document head."
7151
6979
  ],
7152
6980
  "whenNot": [
7153
6981
  {
7154
- "text": "It is a form field that needs a label, hint, or validation.",
7155
- "instead": "AppSelect"
7156
- },
7157
- {
7158
- "text": "The list is long enough to need type-to-find.",
7159
- "instead": "AppSelect"
7160
- },
7161
- {
7162
- "text": "The user picks several values at once.",
7163
- "instead": "AppMultiSelect"
7164
- }
7165
- ],
7166
- "do": [
7167
- {
7168
- "note": "Option labels that carry their own unit, such as \"25 / page\", read clearly out of context.",
7169
- "example": [
7170
- {
7171
- "component": "AppSelectMini",
7172
- "props": {
7173
- "value": "25",
7174
- "ariaLabel": "Rows per page",
7175
- "options": [
7176
- {
7177
- "value": "10",
7178
- "label": "10 / page"
7179
- },
7180
- {
7181
- "value": "25",
7182
- "label": "25 / page"
7183
- },
7184
- {
7185
- "value": "50",
7186
- "label": "50 / page"
7187
- }
7188
- ]
7189
- }
7190
- }
7191
- ]
7192
- },
7193
- {
7194
- "note": "A short, self-explanatory set is exactly the mini picker's job.",
7195
- "example": [
7196
- {
7197
- "component": "AppSelectMini",
7198
- "props": {
7199
- "value": "all",
7200
- "ariaLabel": "Filter status",
7201
- "options": [
7202
- {
7203
- "value": "all",
7204
- "label": "All statuses"
7205
- },
7206
- {
7207
- "value": "draft",
7208
- "label": "Draft"
7209
- },
7210
- {
7211
- "value": "active",
7212
- "label": "Active"
7213
- },
7214
- {
7215
- "value": "done",
7216
- "label": "Complete"
7217
- }
7218
- ]
7219
- }
7220
- }
7221
- ]
7222
- }
7223
- ],
7224
- "dont": [
7225
- {
7226
- "note": "Bare numbers in a toolbar don't say what they change.",
7227
- "example": [
7228
- {
7229
- "component": "AppSelectMini",
7230
- "props": {
7231
- "value": "25",
7232
- "ariaLabel": "Rows per page",
7233
- "options": [
7234
- {
7235
- "value": "10",
7236
- "label": "10"
7237
- },
7238
- {
7239
- "value": "25",
7240
- "label": "25"
7241
- },
7242
- {
7243
- "value": "50",
7244
- "label": "50"
7245
- }
7246
- ]
7247
- }
7248
- }
7249
- ]
7250
- },
7251
- {
7252
- "note": "A long list belongs in AppSelect with searchable, not the compact picker.",
7253
- "example": [
7254
- {
7255
- "component": "AppSelectMini",
7256
- "props": {
7257
- "value": "c1",
7258
- "ariaLabel": "Category",
7259
- "options": [
7260
- {
7261
- "value": "c1",
7262
- "label": "Industrial DC"
7263
- },
7264
- {
7265
- "value": "c2",
7266
- "label": "Commercial rooftop"
7267
- },
7268
- {
7269
- "value": "c3",
7270
- "label": "Utility substation"
7271
- },
7272
- {
7273
- "value": "c4",
7274
- "label": "Telecom tower"
7275
- },
7276
- {
7277
- "value": "c5",
7278
- "label": "Residential complex"
7279
- },
7280
- {
7281
- "value": "c6",
7282
- "label": "Data centre campus"
7283
- },
7284
- {
7285
- "value": "c7",
7286
- "label": "Wind farm"
7287
- }
7288
- ]
7289
- }
7290
- }
7291
- ]
6982
+ "text": "The page is rendered by Razor.",
6983
+ "instead": "<seo-head> from Webority.Seo.AspNetCore"
7292
6984
  }
7293
6985
  ],
6986
+ "do": [],
6987
+ "dont": [],
7294
6988
  "a11y": [
7295
- "The control has no visible label, so ariaLabel is its accessible name; without it a screen reader announces only a bare combobox.",
7296
- "Disabled sets the disabled attribute on the control, so its value cannot change."
6989
+ "The tags add no visible content; they describe the page to search engines and social previews."
7297
6990
  ]
7298
6991
  }
7299
6992
  },
@@ -7316,7 +7009,7 @@
7316
7009
  },
7317
7010
  {
7318
7011
  "text": "You need a temporary side panel, not the app's navigation.",
7319
- "instead": "AppSidebarMenu"
7012
+ "instead": "AppDrawer"
7320
7013
  },
7321
7014
  {
7322
7015
  "text": "The session has not resolved yet.",
@@ -7383,88 +7076,6 @@
7383
7076
  ]
7384
7077
  }
7385
7078
  },
7386
- {
7387
- "name": "AppSidebarMenu",
7388
- "usage": {
7389
- "when": [
7390
- "A filter or details panel that slides in beside the current content (side=\"right\").",
7391
- "A navigation drawer, especially the collapsed mobile menu (side=\"left\").",
7392
- "You want a panel that behaves accessibly below a breakpoint and inline above it (responsive)."
7393
- ],
7394
- "whenNot": [
7395
- {
7396
- "text": "It's a self-contained task or form in a centred card.",
7397
- "instead": "AppModal"
7398
- },
7399
- {
7400
- "text": "It's a yes/no confirmation.",
7401
- "instead": "AppConfirmDialog"
7402
- },
7403
- {
7404
- "text": "It's a small menu of actions behind one trigger.",
7405
- "instead": "AppDropdown"
7406
- },
7407
- {
7408
- "text": "It's a transient message.",
7409
- "instead": "a toast"
7410
- }
7411
- ],
7412
- "do": [
7413
- {
7414
- "note": "A clear trigger opens a drawer with a title and a footer of actions, controlled by show and onHide.",
7415
- "example": [
7416
- {
7417
- "component": "AppButton",
7418
- "children": "Open filters"
7419
- }
7420
- ]
7421
- },
7422
- {
7423
- "note": "A left-edge drawer for navigation, a right-edge one for filters: the side matches the panel's job.",
7424
- "example": [
7425
- {
7426
- "component": "AppButton",
7427
- "props": {
7428
- "variant": "outline"
7429
- },
7430
- "children": "Menu"
7431
- }
7432
- ]
7433
- }
7434
- ],
7435
- "dont": [
7436
- {
7437
- "note": "A hand-rolled slide panel with no focus trap or Escape handling is inaccessible.",
7438
- "example": [
7439
- {
7440
- "component": "AppButton",
7441
- "props": {
7442
- "variant": "ghost"
7443
- },
7444
- "children": "Toggle panel"
7445
- }
7446
- ]
7447
- },
7448
- {
7449
- "note": "A drawer is the wrong home for a yes/no confirm; that belongs in AppConfirmDialog.",
7450
- "example": [
7451
- {
7452
- "component": "AppButton",
7453
- "props": {
7454
- "variant": "outline"
7455
- },
7456
- "children": "Delete account…"
7457
- }
7458
- ]
7459
- }
7460
- ],
7461
- "a11y": [
7462
- "The panel is a dialog that traps focus and closes on Escape (while keyboard is on), on a click outside (unless the backdrop is static) and with the close button.",
7463
- "A text title names the dialog, and ariaLabel overrides it.",
7464
- "The close button is named by closeLabel."
7465
- ]
7466
- }
7467
- },
7468
7079
  {
7469
7080
  "name": "AppSkeleton",
7470
7081
  "usage": {
@@ -7480,7 +7091,7 @@
7480
7091
  },
7481
7092
  {
7482
7093
  "text": "A table query returned no rows.",
7483
- "instead": "AppTableEmptyState"
7094
+ "instead": "AppEmptyState variant=\"table\""
7484
7095
  },
7485
7096
  {
7486
7097
  "text": "A short, indeterminate action is running (a button submit).",
@@ -7637,7 +7248,7 @@
7637
7248
  },
7638
7249
  {
7639
7250
  "text": "A table query returned no rows.",
7640
- "instead": "AppTableEmptyState"
7251
+ "instead": "AppEmptyState variant=\"table\""
7641
7252
  }
7642
7253
  ],
7643
7254
  "do": [
@@ -7922,7 +7533,7 @@
7922
7533
  },
7923
7534
  {
7924
7535
  "text": "The detail is a quick peek from a table.",
7925
- "instead": "AppSidebarMenu"
7536
+ "instead": "AppDrawer"
7926
7537
  },
7927
7538
  {
7928
7539
  "text": "Each item is edited in a long form.",
@@ -8378,98 +7989,6 @@
8378
7989
  ]
8379
7990
  }
8380
7991
  },
8381
- {
8382
- "name": "AppTableEmptyState",
8383
- "usage": {
8384
- "when": [
8385
- "A data table finished loading and returned zero rows.",
8386
- "A filtered or searched table has no matches and you want to say so in place.",
8387
- "The table has a natural first action (add / invite) worth surfacing when it's empty."
8388
- ],
8389
- "whenNot": [
8390
- {
8391
- "text": "The empty area is a card or section, not a table body.",
8392
- "instead": "AppEmptyState"
8393
- },
8394
- {
8395
- "text": "The table is still loading its first page.",
8396
- "instead": "AppSkeletonRows"
8397
- },
8398
- {
8399
- "text": "The rows failed to load because of an error.",
8400
- "instead": "AppAlert"
8401
- }
8402
- ],
8403
- "do": [
8404
- {
8405
- "note": "A filter-empty names the reason and suggests the fix. The user knows what to change.",
8406
- "example": [
8407
- {
8408
- "component": "AppTableEmptyState",
8409
- "props": {
8410
- "icon": "search",
8411
- "title": "No matches",
8412
- "text": "No assessments match these filters. Try widening the date range."
8413
- }
8414
- }
8415
- ]
8416
- },
8417
- {
8418
- "note": "When the table has an obvious next step, the empty state offers it right there.",
8419
- "example": [
8420
- {
8421
- "component": "AppTableEmptyState",
8422
- "props": {
8423
- "icon": "users",
8424
- "title": "No team members",
8425
- "text": "Invite colleagues to collaborate.",
8426
- "action": {
8427
- "component": "AppButton",
8428
- "props": {
8429
- "size": "sm",
8430
- "leftIcon": "plus"
8431
- },
8432
- "children": "Invite member"
8433
- }
8434
- }
8435
- }
8436
- ]
8437
- }
8438
- ],
8439
- "dont": [
8440
- {
8441
- "note": "A bare \"No data\" leaves the user unsure whether the table is empty, broken, or mis-filtered.",
8442
- "example": [
8443
- {
8444
- "component": "AppTableEmptyState",
8445
- "props": {
8446
- "icon": "file-text",
8447
- "title": "No data"
8448
- }
8449
- }
8450
- ]
8451
- },
8452
- {
8453
- "note": "Padding the text instead of offering the invite action wastes the moment.",
8454
- "example": [
8455
- {
8456
- "component": "AppTableEmptyState",
8457
- "props": {
8458
- "icon": "users",
8459
- "title": "No team members",
8460
- "text": "There are no team members. There are no team members to show in this list right now."
8461
- }
8462
- }
8463
- ]
8464
- }
8465
- ],
8466
- "a11y": [
8467
- "A named illustration is hidden from assistive technology (aria-hidden), and so is a custom illustration node, so only the title and text are read.",
8468
- "The title and text are plain text blocks, read in document order.",
8469
- "The action is whatever node is passed, so a button there keeps its own keyboard behaviour."
8470
- ]
8471
- }
8472
- },
8473
7992
  {
8474
7993
  "name": "AppTablePagination",
8475
7994
  "usage": {
@@ -9287,7 +8806,7 @@
9287
8806
  },
9288
8807
  {
9289
8808
  "text": "They are label/value facts with no time or step dimension.",
9290
- "instead": "AppInfoList"
8809
+ "instead": "AppDescriptions"
9291
8810
  },
9292
8811
  {
9293
8812
  "text": "There is nothing to show yet.",
@@ -9482,7 +9001,7 @@
9482
9001
  },
9483
9002
  {
9484
9003
  "text": "Site or app navigation.",
9485
- "instead": "AppSidebarMenu"
9004
+ "instead": "AppShell"
9486
9005
  }
9487
9006
  ],
9488
9007
  "do": [],