pixelize-design-library 2.4.2-beta.4 → 2.4.2-beta.40
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.
- package/COMPONENT-GOTCHAS.md +1087 -0
- package/README.md +26 -0
- package/dist/Components/Accordion/Accordion.d.ts +1 -0
- package/dist/Components/Accordion/Accordion.js +4 -1
- package/dist/Components/Accordion/AccordionProps.d.ts +2 -0
- package/dist/Components/AlertDialog/AlertDialog.d.ts +1 -0
- package/dist/Components/AlertDialog/AlertDialog.js +1 -0
- package/dist/Components/AlertDialog/AlertDialogProps.d.ts +2 -0
- package/dist/Components/Apexcharts/ApexAreaChart/ApexAreaChart.d.ts +1 -0
- package/dist/Components/Apexcharts/ApexAreaChart/ApexAreaChart.js +1 -0
- package/dist/Components/Apexcharts/ApexAreaChart/ApexAreaChartProps.d.ts +4 -0
- package/dist/Components/Apexcharts/ApexBarChart/ApexBarChart.d.ts +1 -0
- package/dist/Components/Apexcharts/ApexBarChart/ApexBarChart.js +1 -0
- package/dist/Components/Apexcharts/ApexBarChart/ApexBarChartProps.d.ts +6 -0
- package/dist/Components/Apexcharts/ApexLineChart/ApexLineChart.d.ts +1 -0
- package/dist/Components/Apexcharts/ApexLineChart/ApexLineChart.js +1 -0
- package/dist/Components/Apexcharts/ApexLineChart/ApexLineChartProps.d.ts +8 -0
- package/dist/Components/Apexcharts/ApexPieChart/ApexPieChart.d.ts +1 -0
- package/dist/Components/Apexcharts/ApexPieChart/ApexPieChart.js +1 -0
- package/dist/Components/Apexcharts/ApexPieChart/ApexPieChartProps.d.ts +6 -0
- package/dist/Components/Apexcharts/ApexPolarCharts/ApexPolarCharts.d.ts +1 -0
- package/dist/Components/Apexcharts/ApexPolarCharts/ApexPolarCharts.js +1 -0
- package/dist/Components/Apexcharts/ApexPolarCharts/ApexPolarChartsProps.d.ts +3 -0
- package/dist/Components/Apexcharts/ApexRadialChart/ApexRadialChart.d.ts +1 -0
- package/dist/Components/Apexcharts/ApexRadialChart/ApexRadialChart.js +1 -0
- package/dist/Components/Apexcharts/ApexRadialChart/ApexRadialChartProps.d.ts +3 -0
- package/dist/Components/AppSwitcher/AppMark.d.ts +19 -0
- package/dist/Components/AppSwitcher/AppMark.js +62 -0
- package/dist/Components/AppSwitcher/AppSwitcher.d.ts +4 -0
- package/dist/Components/AppSwitcher/AppSwitcher.js +278 -0
- package/dist/Components/AppSwitcher/AppSwitcherProps.d.ts +70 -0
- package/dist/Components/AppSwitcher/AppSwitcherProps.js +86 -0
- package/dist/Components/AppSwitcher/useAppSwitcherShortcut.d.ts +3 -0
- package/dist/Components/AppSwitcher/useAppSwitcherShortcut.js +31 -0
- package/dist/Components/AppearanceSettings/AppearanceSettings.js +2 -1
- package/dist/Components/AppearanceSettings/AppearanceSettingsProps.d.ts +2 -0
- package/dist/Components/Breadcrumbs/BreadcrumbsProps.d.ts +3 -0
- package/dist/Components/Button/Button.d.ts +2 -2
- package/dist/Components/Button/Button.js +4 -3
- package/dist/Components/Button/Button.styles.js +37 -23
- package/dist/Components/Button/ButtonProps.d.ts +9 -1
- package/dist/Components/ButtonGroupIcon/ButtonGoupIconProps.d.ts +7 -0
- package/dist/Components/ButtonGroupIcon/ButtonGroupIcon.js +2 -4
- package/dist/Components/Buttons/ButtonsProps.d.ts +2 -0
- package/dist/Components/Card/Card.d.ts +1 -1
- package/dist/Components/Card/Card.js +2 -2
- package/dist/Components/Card/CardProps.d.ts +3 -1
- package/dist/Components/Card/PaymentCard/PaymentCard.js +21 -12
- package/dist/Components/Card/PaymentCard/PaymentCardProps.d.ts +6 -0
- package/dist/Components/Checkbox/Checkbox.d.ts +1 -0
- package/dist/Components/Checkbox/Checkbox.js +2 -1
- package/dist/Components/Checkbox/Checkbox.styles.js +12 -7
- package/dist/Components/Checkbox/CheckboxProps.d.ts +4 -0
- package/dist/Components/Common/ErrorComponent.d.ts +2 -0
- package/dist/Components/Common/ErrorComponent.js +7 -5
- package/dist/Components/Common/ErrorMessage.js +2 -2
- package/dist/Components/Common/FormLabel.d.ts +4 -0
- package/dist/Components/Common/FormLabel.js +1 -0
- package/dist/Components/Common/FormattedDescription.d.ts +2 -0
- package/dist/Components/Common/FormattedDescription.js +1 -0
- package/dist/Components/Common/HelperText.d.ts +2 -0
- package/dist/Components/Common/HelperText.js +2 -0
- package/dist/Components/Common/Label.d.ts +1 -0
- package/dist/Components/Common/Label.js +1 -0
- package/dist/Components/Common/fieldStyles.js +1 -1
- package/dist/Components/ContactForm/ContactForm.d.ts +1 -0
- package/dist/Components/ContactForm/ContactForm.js +1 -0
- package/dist/Components/ContactForm/ContactFormProps.d.ts +4 -0
- package/dist/Components/CopyButton/CopyButton.d.ts +3 -1
- package/dist/Components/CopyButton/CopyButton.js +9 -3
- package/dist/Components/CustomModulesTable/CustomModulesTableProps.d.ts +8 -0
- package/dist/Components/DatePicker/CalendarPanel.d.ts +6 -0
- package/dist/Components/DatePicker/CalendarPanel.js +37 -15
- package/dist/Components/DatePicker/DatePicker.d.ts +1 -0
- package/dist/Components/DatePicker/DatePicker.js +1 -0
- package/dist/Components/DatePicker/DatePickerProps.d.ts +30 -0
- package/dist/Components/DatePicker/RangeDatePicker.d.ts +1 -0
- package/dist/Components/DatePicker/RangeDatePicker.js +30 -5
- package/dist/Components/DatePicker/SingleDatePicker.d.ts +1 -0
- package/dist/Components/DatePicker/SingleDatePicker.js +49 -14
- package/dist/Components/DatePicker/ThemeDatePicker.d.ts +1 -0
- package/dist/Components/DatePicker/ThemeDatePicker.js +1 -0
- package/dist/Components/DatePicker/TimeOnlyPicker.d.ts +1 -0
- package/dist/Components/DatePicker/TimeOnlyPicker.js +11 -2
- package/dist/Components/DatePicker/TimePicker.d.ts +1 -0
- package/dist/Components/DatePicker/TimePicker.js +4 -3
- package/dist/Components/DatePicker/TimePickerInput.d.ts +1 -0
- package/dist/Components/DatePicker/TimePickerInput.js +2 -1
- package/dist/Components/DatePicker/dayStates.d.ts +56 -0
- package/dist/Components/DatePicker/dayStates.js +87 -0
- package/dist/Components/Divider/Divider.d.ts +1 -0
- package/dist/Components/Divider/Divider.js +1 -0
- package/dist/Components/Drawer/DrawerProps.d.ts +2 -0
- package/dist/Components/Dropdown/DropDown.d.ts +1 -0
- package/dist/Components/Dropdown/DropDown.js +22 -6
- package/dist/Components/Dropdown/DropdownProps.d.ts +3 -0
- package/dist/Components/Editor/Editor.d.ts +1 -0
- package/dist/Components/Editor/Editor.js +1 -0
- package/dist/Components/Editor/EditorProps.d.ts +2 -0
- package/dist/Components/EmailCards/VerifyEmailOtp/VerifyEmailOtp.d.ts +1 -0
- package/dist/Components/EmailCards/VerifyEmailOtp/VerifyEmailOtp.js +2 -5
- package/dist/Components/EmailCards/VerifyEmailOtp/VerifyEmailOtpProps.d.ts +4 -0
- package/dist/Components/EmptyState/EmptyState.d.ts +1 -0
- package/dist/Components/EmptyState/EmptyState.js +4 -2
- package/dist/Components/EmptyState/EmptyStateProps.d.ts +3 -0
- package/dist/Components/FeedbackForm/FeedbackForm.d.ts +3 -0
- package/dist/Components/FeedbackForm/FeedbackForm.js +1 -0
- package/dist/Components/FieldSelectModal/FieldSelectModal.d.ts +3 -2
- package/dist/Components/FieldSelectModal/FieldSelectModal.js +1 -0
- package/dist/Components/FilePreview/FilePreview.d.ts +1 -0
- package/dist/Components/FilePreview/FilePreview.js +3 -1
- package/dist/Components/FilePreview/FilePreviewProps.d.ts +5 -2
- package/dist/Components/FileUpload/FileUpload.d.ts +1 -0
- package/dist/Components/FileUpload/FileUpload.js +7 -5
- package/dist/Components/FileUpload/FileUploadProps.d.ts +7 -1
- package/dist/Components/FileUpload/constants.js +1 -0
- package/dist/Components/FileUploader/FileUploader.d.ts +1 -0
- package/dist/Components/FileUploader/FileUploader.js +1 -0
- package/dist/Components/FileUploader/FileUploaderProps.d.ts +2 -0
- package/dist/Components/FilterSidebar/FilterSidebar.d.ts +3 -0
- package/dist/Components/FilterSidebar/FilterSidebar.js +5 -5
- package/dist/Components/FilterSidebar/filterHoverStyle.d.ts +2 -10
- package/dist/Components/FilterSidebar/filterHoverStyle.js +3 -10
- package/dist/Components/Form/FormWrapper.d.ts +3 -0
- package/dist/Components/Form/FormWrapper.js +2 -1
- package/dist/Components/Header/HeaderProps.d.ts +5 -0
- package/dist/Components/Header/components/mobileMenu.js +12 -3
- package/dist/Components/Input/Input/InputProps.d.ts +2 -0
- package/dist/Components/Input/PhoneNumberInput.d.ts +1 -0
- package/dist/Components/Input/PhoneNumberInput.js +1 -0
- package/dist/Components/Input/PhoneNumberInputProps.d.ts +3 -0
- package/dist/Components/Input/Switch/InputSwitch.d.ts +2 -0
- package/dist/Components/Input/Switch/InputSwitch.js +1 -0
- package/dist/Components/Input/TextInput.js +1 -0
- package/dist/Components/Input/TextInput.styles.js +8 -10
- package/dist/Components/Input/TextInputProps.d.ts +2 -0
- package/dist/Components/InputTextArea/InputTextArea.d.ts +1 -0
- package/dist/Components/InputTextArea/InputTextArea.js +1 -0
- package/dist/Components/InputTextArea/InputTextArea.style.js +7 -6
- package/dist/Components/InputTextArea/InputTextAreaProps.d.ts +1 -0
- package/dist/Components/KanbanBoard/AccountCard.d.ts +3 -0
- package/dist/Components/KanbanBoard/AccountCard.js +1 -0
- package/dist/Components/KanbanBoard/AccountRow.d.ts +1 -0
- package/dist/Components/KanbanBoard/AccountRow.js +1 -0
- package/dist/Components/KanbanBoard/KanbanActions/KanbanActions.d.ts +2 -0
- package/dist/Components/KanbanBoard/KanbanActions/KanbanActions.js +2 -2
- package/dist/Components/KanbanBoard/KanbanBoard.d.ts +1 -0
- package/dist/Components/KanbanBoard/KanbanBoard.js +1 -0
- package/dist/Components/KanbanBoard/KanbanBoardProps.d.ts +39 -14
- package/dist/Components/KanbanBoard/MeasuredItem.d.ts +1 -0
- package/dist/Components/KanbanBoard/MeasuredItem.js +1 -0
- package/dist/Components/LazyWrapper/LazyWrapper.d.ts +3 -2
- package/dist/Components/LazyWrapper/LazyWrapper.js +1 -0
- package/dist/Components/LimitReachedModal/LimitReachedModalProps.d.ts +4 -1
- package/dist/Components/LimitReachedModal/limitReachedCopy.d.ts +2 -0
- package/dist/Components/LimitReachedModal/limitReachedCopy.js +2 -0
- package/dist/Components/Loading/Loading.d.ts +1 -0
- package/dist/Components/Loading/Loading.js +16 -14
- package/dist/Components/Loading/LoadingProps.d.ts +2 -0
- package/dist/Components/Modal/ModalProps.d.ts +2 -0
- package/dist/Components/MoreItems/MoreItems.d.ts +1 -0
- package/dist/Components/MoreItems/MoreItems.js +4 -1
- package/dist/Components/MoreItems/MoreItemsProps.d.ts +4 -2
- package/dist/Components/MultiSelect/MultiSelect.js +2 -2
- package/dist/Components/MultiSelect/MultiSelectProps.d.ts +2 -0
- package/dist/Components/NavigationBar/NavigationBar.js +9 -10
- package/dist/Components/NavigationBar/NavigationBarProps.d.ts +3 -0
- package/dist/Components/NoteTextArea/NoteTextArea.d.ts +1 -0
- package/dist/Components/NoteTextArea/NoteTextArea.js +10 -4
- package/dist/Components/NoteTextArea/NoteTextAreaProps.d.ts +2 -0
- package/dist/Components/Notification/Notification.d.ts +1 -0
- package/dist/Components/Notification/Notification.js +1 -0
- package/dist/Components/Notification/NotificationProps.d.ts +6 -0
- package/dist/Components/NumberInput/NumberInput.d.ts +1 -0
- package/dist/Components/NumberInput/NumberInput.js +4 -1
- package/dist/Components/NumberInput/NumberInput.styles.js +7 -6
- package/dist/Components/NumberInput/NumberInputProps.d.ts +3 -0
- package/dist/Components/OrgSwitcher/OrgSwitcher.js +14 -10
- package/dist/Components/OrgSwitcher/OrgSwitcherProps.d.ts +6 -1
- package/dist/Components/OrgSwitcher/OrgSwitcherProps.js +1 -0
- package/dist/Components/OrganizationDetails/OrganizationDetails.d.ts +1 -0
- package/dist/Components/OrganizationDetails/OrganizationDetails.js +4 -2
- package/dist/Components/OrganizationDetails/OrganizationDetailsProps.d.ts +16 -4
- package/dist/Components/PdfViewer/PdfViewer.d.ts +2 -1
- package/dist/Components/PdfViewer/PdfViewer.js +7 -1
- package/dist/Components/PinInput/PinInput.d.ts +1 -0
- package/dist/Components/PinInput/PinInput.js +1 -0
- package/dist/Components/PinInput/PinInputProps.d.ts +2 -0
- package/dist/Components/PinInputs/PinInputs.d.ts +1 -0
- package/dist/Components/PinInputs/PinInputs.js +1 -0
- package/dist/Components/PinInputs/PinInputsProps.d.ts +1 -0
- package/dist/Components/PlanBadge/PlanBadgeProps.d.ts +2 -0
- package/dist/Components/PlanPill/PlanPillProps.d.ts +2 -0
- package/dist/Components/Primitives/Primitives.d.ts +6 -0
- package/dist/Components/Primitives/Primitives.js +113 -0
- package/dist/Components/ProductCard/ProductCardProps.d.ts +10 -0
- package/dist/Components/ProductCard/ProductReview.d.ts +1 -0
- package/dist/Components/ProductCard/ProductReview.js +6 -1
- package/dist/Components/ProductCard/ProductTags.js +1 -1
- package/dist/Components/ProductDetails/ProductDetailsProps.d.ts +7 -0
- package/dist/Components/ProfileCard/ProfileCard.js +1 -1
- package/dist/Components/ProfileCard/ProfileCardProps.d.ts +3 -0
- package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewer.d.ts +1 -0
- package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +5 -3
- package/dist/Components/ProfilePhotoViewer/ProfilePhotoViewerProps.d.ts +9 -1
- package/dist/Components/ProgressBar/ProgressBar.d.ts +1 -0
- package/dist/Components/ProgressBar/ProgressBar.js +1 -0
- package/dist/Components/ProgressBar/ProgressBarProps.d.ts +2 -0
- package/dist/Components/RadioButton/RadioButton.js +3 -2
- package/dist/Components/RadioButton/RadioButtonProps.d.ts +2 -0
- package/dist/Components/Reorder/Reorder.d.ts +2 -0
- package/dist/Components/Reorder/Reorder.js +1 -0
- package/dist/Components/Reorder/ReorderProps.d.ts +3 -0
- package/dist/Components/RolesPermission/RolesPermission.d.ts +1 -0
- package/dist/Components/RolesPermission/RolesPermission.js +5 -3
- package/dist/Components/RolesPermission/RolesPermissionProps.d.ts +16 -1
- package/dist/Components/ScrollToTop/ScrollToTop.d.ts +3 -2
- package/dist/Components/ScrollToTop/ScrollToTop.js +4 -1
- package/dist/Components/ScrollbarBox/ScrollbarBox.d.ts +7 -0
- package/dist/Components/ScrollbarBox/ScrollbarBox.js +1 -0
- package/dist/Components/Search/Search.d.ts +1 -0
- package/dist/Components/Search/Search.js +3 -2
- package/dist/Components/Search/SearchProps.d.ts +2 -0
- package/dist/Components/SearchSelect/SearchSelect.d.ts +1 -0
- package/dist/Components/SearchSelect/SearchSelect.js +48 -37
- package/dist/Components/SearchSelect/SearchSelectProps.d.ts +23 -0
- package/dist/Components/SegmentedControl/SegmentedControl.d.ts +3 -0
- package/dist/Components/SegmentedControl/SegmentedControl.js +89 -0
- package/dist/Components/SegmentedControl/SegmentedControlProps.d.ts +23 -0
- package/dist/Components/SegmentedControl/SegmentedControlProps.js +2 -0
- package/dist/Components/Select/Select.d.ts +1 -1
- package/dist/Components/Select/Select.js +4 -2
- package/dist/Components/Select/Select.styles.js +3 -2
- package/dist/Components/Select/SelectProps.d.ts +6 -0
- package/dist/Components/SelectSearch/SelectSearch.d.ts +1 -0
- package/dist/Components/SelectSearch/SelectSearch.js +37 -15
- package/dist/Components/SelectSearch/SelectSearchProps.d.ts +5 -0
- package/dist/Components/SelectV2/SelectV2.d.ts +1 -0
- package/dist/Components/SelectV2/SelectV2.js +20 -5
- package/dist/Components/SelectV2/SelectV2Props.d.ts +6 -1
- package/dist/Components/SideBar/SecondaryBar.js +1 -1
- package/dist/Components/SideBar/SideBar.js +5 -3
- package/dist/Components/SideBar/SideBarProps.d.ts +38 -24
- package/dist/Components/SideBar/components/MenuPopoverContent.js +2 -2
- package/dist/Components/SignInActivityTable/SignInActivityTableProps.d.ts +3 -0
- package/dist/Components/Skeletons/SkeletonProps.d.ts +2 -0
- package/dist/Components/Skeletons/Skeletons.d.ts +1 -0
- package/dist/Components/Skeletons/Skeletons.js +1 -0
- package/dist/Components/Slider/Slider.d.ts +3 -0
- package/dist/Components/Slider/Slider.js +9 -1
- package/dist/Components/StageProgress/StageItem.d.ts +1 -0
- package/dist/Components/StageProgress/StageItem.js +1 -0
- package/dist/Components/StageProgress/StageProgress.d.ts +1 -0
- package/dist/Components/StageProgress/StageProgress.js +1 -0
- package/dist/Components/StageProgress/StageProgressProps.d.ts +45 -4
- package/dist/Components/StageProgress/StageProgressProps.js +6 -4
- package/dist/Components/StageProgress/StepperStage.js +2 -2
- package/dist/Components/Switch/Switch.d.ts +1 -0
- package/dist/Components/Switch/Switch.js +1 -0
- package/dist/Components/Switch/SwitchProps.d.ts +1 -0
- package/dist/Components/Table/Table.d.ts +2 -1
- package/dist/Components/Table/Table.js +15 -5
- package/dist/Components/Table/TableProps.d.ts +47 -0
- package/dist/Components/Table/components/Pagination.js +1 -1
- package/dist/Components/Table/components/TableActions.js +2 -2
- package/dist/Components/Table/components/TableBody.js +44 -18
- package/dist/Components/Table/components/TableGroupRow.js +1 -1
- package/dist/Components/Table/components/TableHeader.js +21 -8
- package/dist/Components/Table/components/TableSearch.js +1 -1
- package/dist/Components/Table/filters/CompactSelect.d.ts +1 -0
- package/dist/Components/Table/filters/CompactSelect.js +29 -8
- package/dist/Components/Table/filters/LeftFilterPane.d.ts +9 -1
- package/dist/Components/Table/filters/LeftFilterPane.js +1 -1
- package/dist/Components/Table/settings/ManageColumns.js +8 -5
- package/dist/Components/Table/settings/TableSettings.js +6 -4
- package/dist/Components/Table/variants/TableVariantContext.d.ts +4 -0
- package/dist/Components/Table/variants/TableVariantContext.js +17 -0
- package/dist/Components/Table/variants/classic.d.ts +6 -0
- package/dist/Components/Table/variants/classic.js +47 -0
- package/dist/Components/Table/variants/index.d.ts +7 -0
- package/dist/Components/Table/variants/index.js +27 -0
- package/dist/Components/Table/variants/pillInk.d.ts +6 -0
- package/dist/Components/Table/variants/pillInk.js +21 -0
- package/dist/Components/Table/variants/studio.d.ts +6 -0
- package/dist/Components/Table/variants/studio.js +50 -0
- package/dist/Components/Table/variants/tokens.d.ts +49 -0
- package/dist/Components/Table/variants/tokens.js +2 -0
- package/dist/Components/Tag/Tag.d.ts +1 -0
- package/dist/Components/Tag/Tag.js +1 -0
- package/dist/Components/Tag/Tag.styles.js +16 -11
- package/dist/Components/Tag/TagProps.d.ts +7 -0
- package/dist/Components/Timeline/Timeline.d.ts +1 -0
- package/dist/Components/Timeline/Timeline.js +1 -0
- package/dist/Components/Timeline/TimelineProps.d.ts +8 -0
- package/dist/Components/Toaster/Toaster.d.ts +1 -0
- package/dist/Components/Toaster/Toaster.js +1 -0
- package/dist/Components/Toaster/ToasterProps.d.ts +3 -0
- package/dist/Components/Toggle/TableToggle.d.ts +1 -0
- package/dist/Components/Toggle/TableToggle.js +73 -18
- package/dist/Components/Toggle/TableToggleProps.d.ts +6 -0
- package/dist/Components/ToggleSwitch/ToggleSwitch.d.ts +3 -0
- package/dist/Components/ToggleSwitch/ToggleSwitch.js +19 -0
- package/dist/Components/ToggleSwitch/ToggleSwitchProps.d.ts +13 -0
- package/dist/Components/ToggleSwitch/ToggleSwitchProps.js +2 -0
- package/dist/Components/ToolTip/ToolTip.d.ts +1 -0
- package/dist/Components/ToolTip/ToolTip.js +7 -6
- package/dist/Components/ToolTip/ToolTipProps.d.ts +5 -1
- package/dist/Components/Trail/EditableCell.d.ts +2 -0
- package/dist/Components/Trail/EditableCell.js +2 -1
- package/dist/Components/Trail/SelectAllCheckbox.d.ts +1 -0
- package/dist/Components/Trail/SelectAllCheckbox.js +1 -0
- package/dist/Components/Trail/TrailWorks.d.ts +1 -0
- package/dist/Components/Trail/TrailWorks.js +2 -1
- package/dist/Components/UpgradeButton/UpgradeButtonProps.d.ts +6 -2
- package/dist/Components/UserDetails/DeactivateConfirmModal.js +1 -1
- package/dist/Components/UserDetails/UserDetails.d.ts +1 -0
- package/dist/Components/UserDetails/UserDetails.js +6 -3
- package/dist/Components/UserDetails/UserDetailsProps.d.ts +30 -1
- package/dist/Components/WorkspaceWindow/WorkspaceWindowProps.d.ts +6 -1
- package/dist/Hooks/exclusiveOverlay.d.ts +4 -0
- package/dist/Hooks/exclusiveOverlay.js +22 -0
- package/dist/Hooks/useExclusiveOverlay.d.ts +5 -0
- package/dist/Hooks/useExclusiveOverlay.js +24 -0
- package/dist/Theme/assertPalette.d.ts +1 -1
- package/dist/Theme/assertPalette.js +3 -2
- package/dist/Theme/chakra/Menu.styles.d.ts +2 -0
- package/dist/Theme/chakra/Menu.styles.js +9 -5
- package/dist/Theme/chakra/Popover.styles.d.ts +3 -0
- package/dist/Theme/chakra/Popover.styles.js +5 -1
- package/dist/Theme/chakra/componentStyles.d.ts +5 -0
- package/dist/Theme/chakra/componentStyles.js +16 -9
- package/dist/Theme/chakra/createBrandTheme.js +22 -9
- package/dist/Theme/chakra/focusRing.styles.d.ts +52 -0
- package/dist/Theme/chakra/focusRing.styles.js +46 -0
- package/dist/Theme/provider/ThemeSwitcher.js +5 -2
- package/dist/Theme/tokens/brands/index.js +6 -1
- package/dist/Theme/tokens/brands/zinc/palette.dark.d.ts +1 -0
- package/dist/Theme/tokens/builders/buildDarkPalette.js +6 -1
- package/dist/Theme/tokens/builders/chartColorsFromTheme.js +1 -1
- package/dist/Theme/tokens/builders/filledSurface.d.ts +29 -0
- package/dist/Theme/tokens/builders/filledSurface.js +74 -0
- package/dist/Theme/tokens/builders/focusRing.d.ts +52 -0
- package/dist/Theme/tokens/builders/focusRing.js +92 -0
- package/dist/Theme/tokens/builders/index.d.ts +2 -0
- package/dist/Theme/tokens/builders/index.js +2 -0
- package/dist/Theme/tokens/builders/outlineRung.d.ts +41 -3
- package/dist/Theme/tokens/builders/outlineRung.js +82 -5
- package/dist/Theme/tokens/builders/placeholderInk.d.ts +19 -0
- package/dist/Theme/tokens/builders/placeholderInk.js +35 -0
- package/dist/Theme/tokens/builders/resolvedRungs.d.ts +5 -1
- package/dist/Theme/tokens/builders/resolvedRungs.js +7 -2
- package/dist/Theme/tokens/builders/rowStates.d.ts +13 -0
- package/dist/Theme/tokens/builders/rowStates.js +19 -0
- package/dist/Theme/tokens/builders/scrollShadow.d.ts +2 -0
- package/dist/Theme/tokens/builders/scrollShadow.js +16 -0
- package/dist/Theme/tokens/builders/surfaceRungs.d.ts +5 -2
- package/dist/Theme/tokens/builders/surfaceRungs.js +19 -9
- package/dist/Theme/tokens/types.d.ts +21 -1
- package/dist/Utils/table.d.ts +3 -0
- package/dist/Utils/table.js +49 -3
- package/dist/esm/Components/Accordion/Accordion.js +4 -1
- package/dist/esm/Components/AlertDialog/AlertDialog.js +1 -0
- package/dist/esm/Components/Apexcharts/ApexAreaChart/ApexAreaChart.js +1 -0
- package/dist/esm/Components/Apexcharts/ApexBarChart/ApexBarChart.js +1 -0
- package/dist/esm/Components/Apexcharts/ApexLineChart/ApexLineChart.js +1 -0
- package/dist/esm/Components/Apexcharts/ApexPieChart/ApexPieChart.js +1 -0
- package/dist/esm/Components/Apexcharts/ApexPolarCharts/ApexPolarCharts.js +1 -0
- package/dist/esm/Components/Apexcharts/ApexRadialChart/ApexRadialChart.js +1 -0
- package/dist/esm/Components/AppSwitcher/AppMark.js +56 -0
- package/dist/esm/Components/AppSwitcher/AppSwitcher.js +243 -0
- package/dist/esm/Components/AppSwitcher/AppSwitcherProps.js +78 -0
- package/dist/esm/Components/AppSwitcher/useAppSwitcherShortcut.js +27 -0
- package/dist/esm/Components/AppearanceSettings/AppearanceSettings.js +2 -1
- package/dist/esm/Components/Button/Button.js +5 -4
- package/dist/esm/Components/Button/Button.styles.js +38 -24
- package/dist/esm/Components/ButtonGroupIcon/ButtonGroupIcon.js +2 -4
- package/dist/esm/Components/Card/Card.js +2 -2
- package/dist/esm/Components/Card/PaymentCard/PaymentCard.js +21 -12
- package/dist/esm/Components/Checkbox/Checkbox.js +2 -1
- package/dist/esm/Components/Checkbox/Checkbox.styles.js +13 -8
- package/dist/esm/Components/Common/ErrorComponent.js +7 -5
- package/dist/esm/Components/Common/ErrorMessage.js +2 -2
- package/dist/esm/Components/Common/FormLabel.js +1 -0
- package/dist/esm/Components/Common/FormattedDescription.js +1 -0
- package/dist/esm/Components/Common/HelperText.js +2 -0
- package/dist/esm/Components/Common/Label.js +1 -0
- package/dist/esm/Components/Common/fieldStyles.js +1 -1
- package/dist/esm/Components/ContactForm/ContactForm.js +1 -0
- package/dist/esm/Components/CopyButton/CopyButton.js +10 -4
- package/dist/esm/Components/DatePicker/CalendarPanel.js +38 -16
- package/dist/esm/Components/DatePicker/DatePicker.js +1 -0
- package/dist/esm/Components/DatePicker/RangeDatePicker.js +31 -6
- package/dist/esm/Components/DatePicker/SingleDatePicker.js +50 -15
- package/dist/esm/Components/DatePicker/ThemeDatePicker.js +1 -0
- package/dist/esm/Components/DatePicker/TimeOnlyPicker.js +11 -2
- package/dist/esm/Components/DatePicker/TimePicker.js +4 -3
- package/dist/esm/Components/DatePicker/TimePickerInput.js +2 -1
- package/dist/esm/Components/DatePicker/dayStates.js +79 -0
- package/dist/esm/Components/Divider/Divider.js +1 -0
- package/dist/esm/Components/Dropdown/DropDown.js +23 -7
- package/dist/esm/Components/Editor/Editor.js +1 -0
- package/dist/esm/Components/EmailCards/VerifyEmailOtp/VerifyEmailOtp.js +2 -5
- package/dist/esm/Components/EmptyState/EmptyState.js +4 -2
- package/dist/esm/Components/FeedbackForm/FeedbackForm.js +1 -0
- package/dist/esm/Components/FieldSelectModal/FieldSelectModal.js +1 -0
- package/dist/esm/Components/FilePreview/FilePreview.js +3 -1
- package/dist/esm/Components/FileUpload/FileUpload.js +8 -6
- package/dist/esm/Components/FileUpload/constants.js +1 -0
- package/dist/esm/Components/FileUploader/FileUploader.js +1 -0
- package/dist/esm/Components/FilterSidebar/FilterSidebar.js +5 -5
- package/dist/esm/Components/FilterSidebar/filterHoverStyle.js +3 -10
- package/dist/esm/Components/Form/FormWrapper.js +2 -1
- package/dist/esm/Components/Header/components/mobileMenu.js +12 -3
- package/dist/esm/Components/Input/PhoneNumberInput.js +1 -0
- package/dist/esm/Components/Input/Switch/InputSwitch.js +1 -0
- package/dist/esm/Components/Input/TextInput.js +1 -0
- package/dist/esm/Components/Input/TextInput.styles.js +8 -10
- package/dist/esm/Components/InputTextArea/InputTextArea.js +1 -0
- package/dist/esm/Components/InputTextArea/InputTextArea.style.js +7 -6
- package/dist/esm/Components/KanbanBoard/AccountCard.js +1 -0
- package/dist/esm/Components/KanbanBoard/AccountRow.js +1 -0
- package/dist/esm/Components/KanbanBoard/KanbanActions/KanbanActions.js +2 -2
- package/dist/esm/Components/KanbanBoard/KanbanBoard.js +1 -0
- package/dist/esm/Components/KanbanBoard/MeasuredItem.js +1 -0
- package/dist/esm/Components/LazyWrapper/LazyWrapper.js +1 -0
- package/dist/esm/Components/LimitReachedModal/limitReachedCopy.js +2 -0
- package/dist/esm/Components/Loading/Loading.js +13 -11
- package/dist/esm/Components/MoreItems/MoreItems.js +4 -1
- package/dist/esm/Components/MultiSelect/MultiSelect.js +2 -2
- package/dist/esm/Components/NavigationBar/NavigationBar.js +9 -10
- package/dist/esm/Components/NoteTextArea/NoteTextArea.js +10 -4
- package/dist/esm/Components/Notification/Notification.js +1 -0
- package/dist/esm/Components/NumberInput/NumberInput.js +5 -2
- package/dist/esm/Components/NumberInput/NumberInput.styles.js +7 -6
- package/dist/esm/Components/OrgSwitcher/OrgSwitcher.js +14 -10
- package/dist/esm/Components/OrgSwitcher/OrgSwitcherProps.js +1 -0
- package/dist/esm/Components/OrganizationDetails/OrganizationDetails.js +5 -3
- package/dist/esm/Components/PdfViewer/PdfViewer.js +7 -1
- package/dist/esm/Components/PinInput/PinInput.js +1 -0
- package/dist/esm/Components/PinInputs/PinInputs.js +1 -0
- package/dist/esm/Components/Primitives/Primitives.js +6 -0
- package/dist/esm/Components/ProductCard/ProductReview.js +6 -1
- package/dist/esm/Components/ProductCard/ProductTags.js +1 -1
- package/dist/esm/Components/ProfileCard/ProfileCard.js +1 -1
- package/dist/esm/Components/ProfilePhotoViewer/ProfilePhotoViewer.js +6 -4
- package/dist/esm/Components/ProgressBar/ProgressBar.js +1 -0
- package/dist/esm/Components/RadioButton/RadioButton.js +3 -2
- package/dist/esm/Components/Reorder/Reorder.js +1 -0
- package/dist/esm/Components/RolesPermission/RolesPermission.js +5 -3
- package/dist/esm/Components/ScrollToTop/ScrollToTop.js +4 -1
- package/dist/esm/Components/ScrollbarBox/ScrollbarBox.js +1 -0
- package/dist/esm/Components/Search/Search.js +3 -2
- package/dist/esm/Components/SearchSelect/SearchSelect.js +48 -37
- package/dist/esm/Components/SegmentedControl/SegmentedControl.js +86 -0
- package/dist/esm/Components/SegmentedControl/SegmentedControlProps.js +1 -0
- package/dist/esm/Components/Select/Select.js +5 -3
- package/dist/esm/Components/Select/Select.styles.js +3 -2
- package/dist/esm/Components/SelectSearch/SelectSearch.js +37 -15
- package/dist/esm/Components/SelectV2/SelectV2.js +20 -5
- package/dist/esm/Components/SideBar/SecondaryBar.js +1 -1
- package/dist/esm/Components/SideBar/SideBar.js +5 -3
- package/dist/esm/Components/SideBar/components/MenuPopoverContent.js +2 -2
- package/dist/esm/Components/Skeletons/Skeletons.js +1 -0
- package/dist/esm/Components/Slider/Slider.js +9 -1
- package/dist/esm/Components/StageProgress/StageItem.js +1 -0
- package/dist/esm/Components/StageProgress/StageProgress.js +1 -0
- package/dist/esm/Components/StageProgress/StageProgressProps.js +7 -5
- package/dist/esm/Components/StageProgress/StepperStage.js +2 -2
- package/dist/esm/Components/Switch/Switch.js +1 -0
- package/dist/esm/Components/Table/Table.js +15 -5
- package/dist/esm/Components/Table/components/Pagination.js +1 -1
- package/dist/esm/Components/Table/components/TableActions.js +2 -2
- package/dist/esm/Components/Table/components/TableBody.js +44 -18
- package/dist/esm/Components/Table/components/TableGroupRow.js +1 -1
- package/dist/esm/Components/Table/components/TableHeader.js +21 -8
- package/dist/esm/Components/Table/components/TableSearch.js +1 -1
- package/dist/esm/Components/Table/filters/CompactSelect.js +29 -8
- package/dist/esm/Components/Table/filters/LeftFilterPane.js +1 -1
- package/dist/esm/Components/Table/settings/ManageColumns.js +8 -5
- package/dist/esm/Components/Table/settings/TableSettings.js +7 -5
- package/dist/esm/Components/Table/variants/TableVariantContext.js +13 -0
- package/dist/esm/Components/Table/variants/classic.js +43 -0
- package/dist/esm/Components/Table/variants/index.js +9 -0
- package/dist/esm/Components/Table/variants/pillInk.js +18 -0
- package/dist/esm/Components/Table/variants/studio.js +46 -0
- package/dist/esm/Components/Table/variants/tokens.js +1 -0
- package/dist/esm/Components/Tag/Tag.js +1 -0
- package/dist/esm/Components/Tag/Tag.styles.js +17 -12
- package/dist/esm/Components/Timeline/Timeline.js +1 -0
- package/dist/esm/Components/Toaster/Toaster.js +1 -0
- package/dist/esm/Components/Toggle/TableToggle.js +72 -17
- package/dist/esm/Components/ToggleSwitch/ToggleSwitch.js +16 -0
- package/dist/esm/Components/ToggleSwitch/ToggleSwitchProps.js +1 -0
- package/dist/esm/Components/ToolTip/ToolTip.js +7 -6
- package/dist/esm/Components/Trail/EditableCell.js +2 -1
- package/dist/esm/Components/Trail/SelectAllCheckbox.js +1 -0
- package/dist/esm/Components/Trail/TrailWorks.js +2 -1
- package/dist/esm/Components/UserDetails/DeactivateConfirmModal.js +1 -1
- package/dist/esm/Components/UserDetails/UserDetails.js +6 -3
- package/dist/esm/Hooks/exclusiveOverlay.js +16 -0
- package/dist/esm/Hooks/useExclusiveOverlay.js +20 -0
- package/dist/esm/Theme/assertPalette.js +3 -2
- package/dist/esm/Theme/chakra/Menu.styles.js +9 -5
- package/dist/esm/Theme/chakra/Popover.styles.js +5 -1
- package/dist/esm/Theme/chakra/componentStyles.js +16 -9
- package/dist/esm/Theme/chakra/createBrandTheme.js +22 -9
- package/dist/esm/Theme/chakra/focusRing.styles.js +40 -0
- package/dist/esm/Theme/provider/ThemeSwitcher.js +5 -2
- package/dist/esm/Theme/tokens/brands/index.js +6 -1
- package/dist/esm/Theme/tokens/builders/buildDarkPalette.js +6 -1
- package/dist/esm/Theme/tokens/builders/chartColorsFromTheme.js +1 -1
- package/dist/esm/Theme/tokens/builders/filledSurface.js +67 -0
- package/dist/esm/Theme/tokens/builders/focusRing.js +85 -0
- package/dist/esm/Theme/tokens/builders/index.js +2 -0
- package/dist/esm/Theme/tokens/builders/outlineRung.js +78 -4
- package/dist/esm/Theme/tokens/builders/placeholderInk.js +29 -0
- package/dist/esm/Theme/tokens/builders/resolvedRungs.js +7 -2
- package/dist/esm/Theme/tokens/builders/rowStates.js +15 -0
- package/dist/esm/Theme/tokens/builders/scrollShadow.js +13 -0
- package/dist/esm/Theme/tokens/builders/surfaceRungs.js +20 -10
- package/dist/esm/Utils/table.js +50 -5
- package/dist/esm/index.js +26 -1
- package/dist/index.d.ts +26 -3
- package/dist/index.js +67 -4
- package/package.json +11 -4
|
@@ -0,0 +1,1087 @@
|
|
|
1
|
+
# Component Gotchas & Decision Guide
|
|
2
|
+
|
|
3
|
+
For anyone — human or AI — consuming `pixelize-design-library` in an app. Read this **before**
|
|
4
|
+
choosing a component or a prop value, not after something looks wrong. Every entry below compiles
|
|
5
|
+
cleanly, accepts what you pass, and produces the wrong result with no warning — TypeScript cannot
|
|
6
|
+
catch any of these, and a unit suite that mocks the library won't either.
|
|
7
|
+
|
|
8
|
+
This file ships inside the published package (`node_modules/pixelize-design-library/COMPONENT-GOTCHAS.md`)
|
|
9
|
+
so it's available without checking out the library's source repo.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Choosing between components
|
|
14
|
+
|
|
15
|
+
### Segmented control look — `SegmentedControl` / `Toggle/TableToggle`
|
|
16
|
+
|
|
17
|
+
Both take `variant?: "default" | "brandSlide" | "underlineSlide"` (default `"default"` — always
|
|
18
|
+
opt-in, never assume a non-default look).
|
|
19
|
+
|
|
20
|
+
| Context | `variant` | Look |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| Most call sites — settings rows, filters, table view switches | `"default"` | Neutral chip |
|
|
23
|
+
| The primary, hard-to-miss view switcher on a page (not a dense toolbar) | `"brandSlide"` | Solid brand-filled pill slides behind the active segment |
|
|
24
|
+
| A dense toolbar, table header, or anywhere a boxed control feels heavy | `"underlineSlide"` | Thin brand-colored bar glides under the active label, no fill/chip |
|
|
25
|
+
|
|
26
|
+
Pick by density and emphasis, not by taste. When unsure, or migrating an existing call site, leave
|
|
27
|
+
it on `"default"` — it's the only variant guaranteed to match previously-shipped screenshots.
|
|
28
|
+
|
|
29
|
+
### Which "select" component — seven components overlap in name, not purpose
|
|
30
|
+
|
|
31
|
+
**Not picking a value from an options list at all:**
|
|
32
|
+
|
|
33
|
+
| Doing | Component | Why not the others |
|
|
34
|
+
| --- | --- | --- |
|
|
35
|
+
| Triggering a labelled *action* (export, row menu, "...") | `Dropdown` | A menu-button, not a form field — nothing is "selected" and persisted |
|
|
36
|
+
| Typing free-text tags (e.g. email addresses), no options list | `MultiSelect` | Despite the name, there is nothing to pick from — see gotcha below |
|
|
37
|
+
| Choosing which *fields/columns* to include, in a modal, from a checkbox grid | `FieldSelectModal` | Multi-checkbox selection UI, not an inline field control |
|
|
38
|
+
|
|
39
|
+
**Picking one or more values from an options list, inline in a form:**
|
|
40
|
+
|
|
41
|
+
| List length / need | Component | Why |
|
|
42
|
+
| --- | --- | --- |
|
|
43
|
+
| Short, always-visible list, no search needed | `Select` | Native `<select>` wrapper — lightest option, but the popup is OS-painted and can't be themed |
|
|
44
|
+
| New build, want themed/custom-rendered rows (icons, descriptions), no huge list | `SelectV2` | Fully React-rendered popup — **prefer this for new work** over `Select` |
|
|
45
|
+
| Long list needing search + chips + select-all + infinite scroll | `SearchSelect` | The full-featured picker; scales via consumer-driven `pagination`, not DOM virtualization — see gotcha below |
|
|
46
|
+
| Search-as-you-type with avatars/colour swatches/a pinned "add new" row | `SelectSearch` | Lighter than `SearchSelect`; reach for it for that specific row-content need |
|
|
47
|
+
|
|
48
|
+
Default when unsure: `SelectV2` for a themed field, `Select` if the native popup is genuinely fine.
|
|
49
|
+
|
|
50
|
+
### `Slider` is an image carousel, not a numeric range input
|
|
51
|
+
|
|
52
|
+
`Slider` auto-advances a set of images/content on a timer — no numeric value, min/max, or step. The
|
|
53
|
+
actual range-input slider is Chakra's own, re-exported from the `Primitives` barrel as `RangeSlider`
|
|
54
|
+
specifically because this library's `Slider` already owns the name.
|
|
55
|
+
|
|
56
|
+
**Apply:** for a numeric/range form control, import `RangeSlider` from the `Primitives` barrel —
|
|
57
|
+
never `Slider`.
|
|
58
|
+
|
|
59
|
+
### Which "switch" — `ToggleSwitch` / `SegmentedControl` / `Switch`
|
|
60
|
+
|
|
61
|
+
| Choosing | Component | Why |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| A real on/off toggle | `ToggleSwitch` | `role="switch"` + `aria-checked`, full keyboard support |
|
|
64
|
+
| One of 2-5 named options | `SegmentedControl` | `role="radiogroup"`, keyboard-navigable, supports per-option disabling |
|
|
65
|
+
| — | `Switch` | Despite the name, a two-label segmented control (`leftText`/`rightText`) — no role, no keyboard handling at all (mouse-only). Kept only for backward compatibility; don't reach for it in new code |
|
|
66
|
+
|
|
67
|
+
**Apply:** if the choice is "on vs off," it's never `Switch` — use `ToggleSwitch`. For 2+ named
|
|
68
|
+
options, prefer `SegmentedControl` even over `Switch`.
|
|
69
|
+
|
|
70
|
+
### Circular charts — `ApexPieChart` vs `ApexPolarCharts`
|
|
71
|
+
|
|
72
|
+
| Need | Component | Why not the other |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| Proportional share of a whole — slices sum to 100% | `ApexPieChart` | The default "part of a whole" chart; donut variants support a center total label |
|
|
75
|
+
| Compare independent magnitudes on a shared radial grid — values need not sum to anything | `ApexPolarCharts` | Reads like a circular bar chart, not a pie; picking Pie here makes unrelated values look like they must add to 100% |
|
|
76
|
+
|
|
77
|
+
### Which "button" — `Button` / `ButtonGroupIcon` / `Buttons`
|
|
78
|
+
|
|
79
|
+
| Need | Component | Why not the others |
|
|
80
|
+
| --- | --- | --- |
|
|
81
|
+
| A single themed, interactive button — any variant/size/colorScheme, dark-mode aware | `Button` | The only one of the three that reads design tokens at all |
|
|
82
|
+
| A themed row of icon + text + icon, optionally a dropdown menu on the right | `ButtonGroupIcon` | The real "group" component despite `Buttons`' plural name suggesting otherwise |
|
|
83
|
+
| *(avoid)* | `Buttons` (plural) | Legacy single `<button>` hardcoded to Tailwind `bg-purple-600`, not theme-aware, not exported from the package root — see gotcha below |
|
|
84
|
+
|
|
85
|
+
### Which "card" — `Card` / `ProductCard` / `ProductDetails` / `PaymentCard`
|
|
86
|
+
|
|
87
|
+
| Need | Component | Why not the others |
|
|
88
|
+
| --- | --- | --- |
|
|
89
|
+
| Generic bordered/padded container, no commerce semantics | `Card` | Plain layout wrapper — its `header`/`footer`/divider props are dead, compose your own layout in `children` |
|
|
90
|
+
| Compact product tile for a grid/listing page | `ProductCard` | Fixed size presets, single-image hover-swap, no gallery |
|
|
91
|
+
| Full product detail page layout (gallery + description + variant picker) | `ProductDetails` | No card chrome of its own; same variant-list shape as `ProductCard` but named `price`, not `options` |
|
|
92
|
+
| Subscription/pricing-tier card (plans, billing cycle, feature list) | `PaymentCard` | Takes a `Plan` object, unrelated to `options`/`productImage` |
|
|
93
|
+
|
|
94
|
+
### Managing organizations — `OrganizationDetails` vs `OrgSwitcher`
|
|
95
|
+
|
|
96
|
+
| Doing | Component | Why not the other |
|
|
97
|
+
| --- | --- | --- |
|
|
98
|
+
| Quickly changing which org is active for the current session (navbar/header) | `OrgSwitcher` | Compact trigger + searchable popover; no create/rename/delete — session-scoped |
|
|
99
|
+
| Managing the org list — rename, delete, accept/decline invites, create new, set a persisted default | `OrganizationDetails` | Full admin panel with bundled CRUD modals; `default`/`onSetDefault` is a persisted preference, not OrgSwitcher's session-scoped `value`/`onChange` |
|
|
100
|
+
|
|
101
|
+
### Plan/upgrade cluster — `UpgradeButton` / `PlanPill` / `PlanBadge` / `LimitReachedModal`
|
|
102
|
+
|
|
103
|
+
| Doing | Component | Why not the others |
|
|
104
|
+
| --- | --- | --- |
|
|
105
|
+
| A prominent, animated "upgrade now" CTA button | `UpgradeButton` | Shimmer/hover-lift button with size variants |
|
|
106
|
+
| Showing a plan-state badge and you already have label/tone/copy decided | `PlanPill` | Presentational only — no resolution logic |
|
|
107
|
+
| Showing the top-bar plan-name/"upgrade" badge from raw org plan data | `PlanBadge` | Wraps `PlanPill` with `resolvePlanBadge()`; renders nothing if `canManageBilling` is falsy |
|
|
108
|
+
| Blocking a user who hit a plan limit, with an explanation and upgrade path | `LimitReachedModal` | Full modal, fully controlled, reuses `UpgradeButton` as its own CTA |
|
|
109
|
+
|
|
110
|
+
### Top-of-app navigation — `NavigationBar` / `Header` / `SideBar` / `AppSwitcher` / `WorkspaceWindow`
|
|
111
|
+
|
|
112
|
+
| Need | Component | Why not the others |
|
|
113
|
+
| --- | --- | --- |
|
|
114
|
+
| Top bar: back control + user-avatar profile/logout dropdown | `NavigationBar` | No page-nav links at all — `navMenu` is only the avatar dropdown's own items |
|
|
115
|
+
| Top bar: horizontal page links with active-state highlighting + submenus | `Header` | Desktop submenus are hover-only, see gotcha below |
|
|
116
|
+
| Collapsible/dockable left rail — primary in-app navigation + secondary panel | `SideBar` | The persistent nav shell, not for switching between whole apps |
|
|
117
|
+
| Cross-app launcher (CRM/HRMS/Tickets/Billing/...) | `AppSwitcher` | Two-column popover grid of separate app origins — `SideBar`'s `otherApps` is the legacy predecessor; don't wire both into one shell |
|
|
118
|
+
| Floating Jira-style dialog to view/edit one record without leaving the page | `WorkspaceWindow` | Modal-based floating panel, not page navigation; pairs with `WorkspaceTray` |
|
|
119
|
+
|
|
120
|
+
### File pickers — `FileUpload` vs `FileUploader`
|
|
121
|
+
|
|
122
|
+
| Need | Component | Why |
|
|
123
|
+
| --- | --- | --- |
|
|
124
|
+
| Real `File`/Blob objects to actually upload (FormData/API) | `FileUpload` | Controlled; `onFilesUploaded` carries real `File[]` and validates accept/size with rejection messages |
|
|
125
|
+
| Self-contained "add photos, see thumbnails, remove" list with no server upload | `FileUploader` | Manages its own state; its `onFilesChange` metadata discards the real `File` — see gotcha below |
|
|
126
|
+
|
|
127
|
+
Both export a type named `FileUploaderProps` — the one re-exported from the package root (`src/index.ts`) describes `FileUpload`, not `FileUploader`. Check which folder a type came from before trusting the name.
|
|
128
|
+
|
|
129
|
+
### Inline file preview — `PdfViewer` vs `FilePreview`
|
|
130
|
+
|
|
131
|
+
| Need | Component | Why |
|
|
132
|
+
| --- | --- | --- |
|
|
133
|
+
| Always-visible inline PDF panel in the page flow | `PdfViewer` | Non-modal, PDF-only, small open/download toolbar |
|
|
134
|
+
| Click-to-open lightbox over mixed/unknown file types | `FilePreview` | Controlled modal; auto-detects image/pdf/video/other, adds zoom/rotate for images, graceful fallback for unsupported types |
|
|
135
|
+
|
|
136
|
+
Both render a PDF through the identical unstyled `<embed type="application/pdf">` with no error handling if the browser can't render it inline — neither tells you when that happens.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Known gotchas (silent failures)
|
|
141
|
+
|
|
142
|
+
### `Drawer` / `Modal` / `ProfileCard` drop any child that isn't a named slot
|
|
143
|
+
|
|
144
|
+
All three match children by exact type (`child.type === XHeader/XBody/XFooter`) and render only
|
|
145
|
+
those matches — nothing else in `children` is ever read. Two consequences: a sibling among the
|
|
146
|
+
slots (a nested `Modal`, `AlertDialog`, a confirm dialog, a portal after the footer) silently never
|
|
147
|
+
mounts; and a slot wrapped in a `<>...</>` fragment is dropped too, because the matching doesn't
|
|
148
|
+
unwrap fragments — a fragment's `.type` is `Fragment`, never the slot component.
|
|
149
|
+
|
|
150
|
+
**Apply:** put a confirm dialog **outside** the `Drawer`/`Modal`/`ProfileCard`, as a sibling in a
|
|
151
|
+
wrapping fragment — never among the header/body/footer slots. When a ternary picks between bodies,
|
|
152
|
+
branch into a variable rendered inside one body slot, rather than returning fragment-wrapped slots
|
|
153
|
+
per branch.
|
|
154
|
+
|
|
155
|
+
### `Select`'s `onChange` never fires for the built-in placeholder
|
|
156
|
+
|
|
157
|
+
`Select` resolves the changed value against its `options` list and calls `onChange` only on a hit.
|
|
158
|
+
The built-in `placeholder` renders as its own empty-value option, which isn't in `options` — so
|
|
159
|
+
picking it resolves to no match and nothing fires. An "Any / All / None" reset built on the
|
|
160
|
+
placeholder alone is a dead control; the value snaps back and no filter clears.
|
|
161
|
+
|
|
162
|
+
**Apply:** fine for a plain pick-one-of-N. For a clearable filter, add an explicit
|
|
163
|
+
`{ id: "", label: "Any" }` entry to `options` instead of relying on the placeholder.
|
|
164
|
+
|
|
165
|
+
### `MultiSelect` is an email-chip input, not a picker
|
|
166
|
+
|
|
167
|
+
Despite the name, `MultiSelect` takes **no `options` prop at all**. Typed text is validated as an
|
|
168
|
+
email address and rejected if it doesn't match — there is no way to choose from a product/entity
|
|
169
|
+
list.
|
|
170
|
+
|
|
171
|
+
**Apply:** use `SearchSelect` with `isMultiple` to pick multiple values from an options list.
|
|
172
|
+
|
|
173
|
+
### `RadioButton` has a closed prop list — no `...rest`, no `name`
|
|
174
|
+
|
|
175
|
+
It forwards only a fixed set of props (`label`, `colorScheme`, `isChecked`, `onChange`,
|
|
176
|
+
`isDisabled`, `size`, `value`, `defaultChecked`, plus label/tooltip props) to the underlying radio
|
|
177
|
+
— a `data-*` hook, `aria-describedby`, or a `ref` cannot reach it.
|
|
178
|
+
|
|
179
|
+
**Apply:** it still joins an external `RadioGroup` correctly (grouping comes from context, no
|
|
180
|
+
`name` prop needed) — don't avoid it just for grouping. Reach for the library's Chakra escape
|
|
181
|
+
hatch only when you need something outside that closed list.
|
|
182
|
+
|
|
183
|
+
### `Table`'s `onRowClick` is dead if every column has a `node` renderer
|
|
184
|
+
|
|
185
|
+
Row-click is gated **per column**, not per row: a column supplying a custom `node` renderer
|
|
186
|
+
swallows the click on that cell. Give every column a `node` and `onRowClick` becomes dead code —
|
|
187
|
+
accepted, typed, never called.
|
|
188
|
+
|
|
189
|
+
**Apply:** leave at least one column without a `node`, or put an explicit control inside a `node`
|
|
190
|
+
renderer instead of relying on row click.
|
|
191
|
+
|
|
192
|
+
### `InputTextArea`'s `width` defaults to the number `500`, and no `id` means no label
|
|
193
|
+
|
|
194
|
+
`width` defaults to `500`, forwarded straight through — `500` isn't a sizing-scale key, so it
|
|
195
|
+
renders a literal `500px`, not a max and not responsive. It only shows up on a narrow screen.
|
|
196
|
+
Separately, `id` feeds both the visible label and the field itself with no fallback — omit it and
|
|
197
|
+
the label is associated with nothing; the field has no accessible name.
|
|
198
|
+
|
|
199
|
+
**Apply:** pass `width="100%"` **and** `id` at every call site.
|
|
200
|
+
|
|
201
|
+
### `error` without `errorMessage` renders the literal word "Error" — and erases `helperText`
|
|
202
|
+
|
|
203
|
+
Every field that shows validation errors (`TextInput`, `InputTextArea`, `Select`, `MultiSelect`,
|
|
204
|
+
`SelectV2`, `SearchSelect`, `SelectSearch`, `Search`, `Checkbox`, the `DatePicker` variants,
|
|
205
|
+
`PhoneNumberInput`) falls back to the literal word **"Error"** when `error` is `true` but
|
|
206
|
+
`errorMessage` is empty. Worse, `helperText` only renders when `!error` — so the guidance
|
|
207
|
+
disappears exactly when it's needed.
|
|
208
|
+
|
|
209
|
+
**Apply:** never pass `error` without `errorMessage`. Gate `error` on a `touched` flag so a field
|
|
210
|
+
whose defaults arrive asynchronously doesn't open already red.
|
|
211
|
+
|
|
212
|
+
### A wrapper presetting a prop must destructure with a default, not rely on JSX prop order
|
|
213
|
+
|
|
214
|
+
Wrapping a library component to preset a prop (e.g. `Table`'s `variant`) as
|
|
215
|
+
`<Table variant="studio" {...props} />` silently reverts to the library's own default the moment a
|
|
216
|
+
caller passes `variant={undefined}` — a later spread always wins in JSX, even with `undefined`,
|
|
217
|
+
and the library component resolves that `undefined` via its own default parameter.
|
|
218
|
+
|
|
219
|
+
**Apply:**
|
|
220
|
+
```tsx
|
|
221
|
+
const AppTable = ({ variant = 'studio', ...props }: TableProps) => <Table variant={variant} {...props} />;
|
|
222
|
+
```
|
|
223
|
+
Applies to any library prop with a default value, not just `Table`'s `variant`.
|
|
224
|
+
|
|
225
|
+
### `FormWrapper` has a closed prop list — no `...rest`
|
|
226
|
+
|
|
227
|
+
It destructures exactly `{ icon, text, children }` and forwards nothing else to either the outer
|
|
228
|
+
wrapper or the bordered content `Box` — a `data-testid`, `id`, a margin override, or an `onClick` on
|
|
229
|
+
the wrapper all silently disappear, and TypeScript won't catch it since excess-property checks don't
|
|
230
|
+
apply to spreads.
|
|
231
|
+
|
|
232
|
+
**Apply:** wrap `FormWrapper` in your own `Box` when you need margin, a test hook, or an id on the
|
|
233
|
+
section — don't expect anything but `icon`/`text`/`children` to reach the DOM.
|
|
234
|
+
|
|
235
|
+
### `ContactForm`'s `apiKey` prop is a POST URL, not an auth token
|
|
236
|
+
|
|
237
|
+
Despite the name, `apiKey` is passed straight into `fetch(apiKey, { method: "POST" })` as the submit
|
|
238
|
+
endpoint — never sent as a header or credential. A real API key/secret fails silently as an invalid
|
|
239
|
+
URL, surfaced only as a generic "Failed to send message" alert. There's no `headers` prop, so an
|
|
240
|
+
authenticated endpoint can't be reached through this component at all.
|
|
241
|
+
|
|
242
|
+
**Apply:** pass the full POST URL, never a token. If the endpoint needs auth headers, proxy through
|
|
243
|
+
your own backend instead.
|
|
244
|
+
|
|
245
|
+
### `ContactForm` can't tell its parent the submission result
|
|
246
|
+
|
|
247
|
+
It does its own internal `fetch` and renders its own success/error alert from local state — there is
|
|
248
|
+
no `onSuccess`, `onSubmit`, or `onError` prop (a dead `// onSubmit(formData)` line is the only trace
|
|
249
|
+
one ever existed). A call site can't redirect, toast, or update its own state when the enquiry sends.
|
|
250
|
+
Separately, the email field is validated for format but its "required" check is commented out, so a
|
|
251
|
+
blank email submits successfully with no error shown.
|
|
252
|
+
|
|
253
|
+
**Apply:** if the parent needs to react to success, this component can't provide it. Don't rely on
|
|
254
|
+
`email` being enforced as required — validate it yourself first if that matters.
|
|
255
|
+
|
|
256
|
+
### `VerifyEmailOtp` can't accept alphanumeric codes
|
|
257
|
+
|
|
258
|
+
It wraps Chakra's `PinInput` without forwarding a `type`, so Chakra's `type="number"` default
|
|
259
|
+
applies — any letter typed is silently rejected (the character never appears, no error shown).
|
|
260
|
+
`VerifyEmailOtpProps` has no `type` field and no `...rest` escape hatch. Its `description` text also
|
|
261
|
+
always gets a hardcoded second line appended — "your new Pixel Account" — with no prop to remove it.
|
|
262
|
+
|
|
263
|
+
**Apply:** only use this component for numeric-only OTPs with product copy that matches that exact
|
|
264
|
+
trailing phrase. Otherwise build the card from `PinInput`/`PinInputs` plus your own text.
|
|
265
|
+
|
|
266
|
+
### `ApexLineChart` only ever renders one line, frozen at mount
|
|
267
|
+
|
|
268
|
+
`data`/`series` changes after the first render are silently ignored unless the component remounts
|
|
269
|
+
(no effect syncs later prop changes into state); `series` only reads index 0 for the line's name
|
|
270
|
+
despite the plural name; `variant="realtime"` replaces your data with random numbers on an interval
|
|
271
|
+
rather than animating it. Its `legendStyle` prop also type-checks but has no effect, unlike the
|
|
272
|
+
identical prop on `ApexPieChart`/`ApexPolarCharts`.
|
|
273
|
+
|
|
274
|
+
**Apply:** remount (`key`) `ApexLineChart` when the underlying data changes. Don't use
|
|
275
|
+
`variant="realtime"` expecting it to reflect a live feed.
|
|
276
|
+
|
|
277
|
+
### `ApexPieChart`'s `showDataLabels` can be silently overridden by chart height
|
|
278
|
+
|
|
279
|
+
With the default `labelPlacement="auto"`, a **numeric** `height` under 240 forces labels off even
|
|
280
|
+
with `showDataLabels={true}` — no warning. Slices under `minLabelPercent` (default 8%) render blank
|
|
281
|
+
label text rather than being hidden as a unit.
|
|
282
|
+
|
|
283
|
+
**Apply:** pass `labelPlacement="inside"`/`"outside"` explicitly for small numeric-height charts;
|
|
284
|
+
lower `minLabelPercent` when every slice needs a visible value.
|
|
285
|
+
|
|
286
|
+
### `ApexBarChart` and `ApexAreaChart` silently drop `data` when `series` is also passed
|
|
287
|
+
|
|
288
|
+
`series` always wins over `data` with no warning, on both components — a natural mistake when
|
|
289
|
+
migrating from single- to multi-series. Separately, `ApexBarChart`'s `barColor` array only paints one
|
|
290
|
+
color per bar when `distributed={true}`; with the default `false`, every bar takes `barColor[0]` and
|
|
291
|
+
the rest of the array is silently unused. `ApexRadialChart`'s `hollowSize` has its own unrelated trap
|
|
292
|
+
— it's silently overridden to a fixed `"52%"` whenever `variant="multi"`.
|
|
293
|
+
|
|
294
|
+
**Apply:** never pass `data` and `series` together on `ApexBarChart`/`ApexAreaChart`. Set
|
|
295
|
+
`distributed` whenever `ApexBarChart`'s `barColor` has more than one color. Don't expect
|
|
296
|
+
`ApexRadialChart`'s `hollowSize` to apply under `variant="multi"`.
|
|
297
|
+
|
|
298
|
+
### `Skeletons` / `ProgressBar` have closed prop lists — no `borderRadius`, no margin, no `...rest`
|
|
299
|
+
|
|
300
|
+
Both `Pick<>` a fixed key set from their Chakra equivalents and forward nothing else — there is no
|
|
301
|
+
way to round a skeleton's corners, add margin, or attach a ref/`data-*` through either component.
|
|
302
|
+
|
|
303
|
+
**Apply:** for rounding, spacing, or a ref, use the Primitives barrel's raw Chakra `Skeleton`/
|
|
304
|
+
`Progress` instead.
|
|
305
|
+
|
|
306
|
+
### `Skeletons`' `isLoaded` only works for `type="skeleton"`
|
|
307
|
+
|
|
308
|
+
`type="circle"`/`"text"` never receive `isLoaded` (or `children`/`bg`/`color`/`fadeDuration`) —
|
|
309
|
+
passing them compiles and is silently dropped; the shimmer never stops no matter what `isLoaded` is
|
|
310
|
+
set to.
|
|
311
|
+
|
|
312
|
+
**Apply:** for `circle`/`text`, control visibility by conditionally rendering the `Skeletons` element
|
|
313
|
+
itself, not via `isLoaded`.
|
|
314
|
+
|
|
315
|
+
### `Notification`'s `onClick` only reaches the title text, and its status dot has two gates
|
|
316
|
+
|
|
317
|
+
`onClick` is wired solely to the title text — the card, avatar, and description are not clickable
|
|
318
|
+
despite the generic prop name. Separately, `warningColor`/`errorColor`/`successColor` only take
|
|
319
|
+
effect when `showStatus` is also `true`, and populating `notification.status` (e.g. `"blocked"`) has
|
|
320
|
+
no effect at all — the dot's color comes purely from `dueDate`/`endDate` math.
|
|
321
|
+
|
|
322
|
+
**Apply:** for a fully clickable card, wrap it yourself with your own `onClick`. Always pair the
|
|
323
|
+
three color overrides with `showStatus`; don't use `status` to drive dot color.
|
|
324
|
+
|
|
325
|
+
### `FeedbackForm` shows a success toast and resets even with no `onSubmit`/`submitUrl`
|
|
326
|
+
|
|
327
|
+
Both props are optional, and when neither is provided, submit still falls through to the success
|
|
328
|
+
toast and form reset — validation, spinner, and reset all work end-to-end while the payload is never
|
|
329
|
+
sent or captured anywhere. Separately, `defaultValues` only seeds state at mount (no resync if it
|
|
330
|
+
arrives later from an async fetch), and its toast is Chakra's raw `useToast`, not this library's
|
|
331
|
+
`Toaster` — the same portal issue documented for `Toaster`/`Modal` can silently hide it when this
|
|
332
|
+
form is embedded in a `Modal`.
|
|
333
|
+
|
|
334
|
+
**Apply:** always pass `onSubmit` or `submitUrl` — treat a bare `<FeedbackForm />` as a bug, not a
|
|
335
|
+
minimal valid usage. Key the element to force a remount if `defaultValues` arrives late. Verify the
|
|
336
|
+
toast actually appears if embedding inside a `Modal`.
|
|
337
|
+
|
|
338
|
+
### `Checkbox`'s `error` never sets `isInvalid`, and `variant` is a no-op
|
|
339
|
+
|
|
340
|
+
`error` doesn't set `isInvalid`/`aria-invalid`, and `errorMessage`/`helperText` aren't linked via
|
|
341
|
+
`aria-describedby` — confirmed by three `it.failing` cases in `Checkbox.a11y.test.tsx`. Separately,
|
|
342
|
+
`variant` is typed and accepted but never destructured or read; `Checkbox.styles.ts` defines no
|
|
343
|
+
`variants` key, so no value changes anything.
|
|
344
|
+
|
|
345
|
+
**Apply:** pass `isInvalid` explicitly alongside `error` — `error` alone never registers as invalid.
|
|
346
|
+
Don't expect `variant` to change a `Checkbox`'s look.
|
|
347
|
+
|
|
348
|
+
### `Toggle`/`TableToggle` has no `aria-pressed`, and its tooltip text can silently mismatch its `aria-label`
|
|
349
|
+
|
|
350
|
+
Confirmed by three `it.failing` cases in `TableToggle.a11y.test.tsx` — a tooltip reading "Table View"
|
|
351
|
+
on a button whose `aria-label` is "Grid View" is a real, reachable state, not a hypothetical.
|
|
352
|
+
|
|
353
|
+
**Apply:** keep each button's tooltip text and `aria-label` in sync yourself; the component doesn't
|
|
354
|
+
enforce or derive one from the other.
|
|
355
|
+
|
|
356
|
+
### `Slider`'s pagination dots can desync from the visible slide
|
|
357
|
+
|
|
358
|
+
The main track sorts `images` by `order`; the pagination dots map over the unsorted array. Passing
|
|
359
|
+
`images` out of `order` sequence makes the active dot point at the wrong slide.
|
|
360
|
+
|
|
361
|
+
**Apply:** pre-sort `images` by `order` before passing them in.
|
|
362
|
+
|
|
363
|
+
### `TextLabel`'s `isInformation` alone renders no icon — it also needs `informationMessage`
|
|
364
|
+
|
|
365
|
+
The info-tooltip icon is gated on `isInformation && informationMessage` — both must be truthy or
|
|
366
|
+
nothing renders, not even a bare icon. `TextLabel` is the shared label engine behind most fields in
|
|
367
|
+
the library (`TextInput`, `NumberInput`, `PhoneNumberInput`, `RadioButton`, `PinInput`,
|
|
368
|
+
`InputSwitch`, `SelectV2`, the `DatePicker` family, `InputTextArea`, `SelectSearch`, `Search`,
|
|
369
|
+
`SearchSelect`, `MultiSelect`, `Select`), so the same silent no-op repeats at every one of them.
|
|
370
|
+
|
|
371
|
+
**Apply:** always pass `isInformation` and `informationMessage` together; never treat
|
|
372
|
+
`isInformation` alone as "use a default message."
|
|
373
|
+
|
|
374
|
+
### Any field's label silently renders as an unassociated `<span>` if you omit `id`
|
|
375
|
+
|
|
376
|
+
`TextLabel` (the shared label engine behind nearly every field, see above) only renders a real
|
|
377
|
+
`<label htmlFor>` when given an `id` — omit it and the visible label text renders but is never
|
|
378
|
+
programmatically associated with its control, on any of the ~17 components that use it.
|
|
379
|
+
|
|
380
|
+
**Apply:** always pass `id` when you want a real, accessible `<label>`. (`MultiSelect` omits it on
|
|
381
|
+
purpose and wires `aria-label` instead — that's the pattern to copy if you skip `id` deliberately.)
|
|
382
|
+
|
|
383
|
+
### `ErrorComponent`'s `error` prop is the message text itself — the opposite of `error`+`errorMessage`
|
|
384
|
+
|
|
385
|
+
Every other field in the library pairs a boolean `error` with a string `errorMessage`.
|
|
386
|
+
`ErrorComponent` (used internally by `Input`/`PinInputs`) instead takes `error: string` directly as
|
|
387
|
+
the message, with no internal truthy-check — passing `error=""` still draws the full icon next to
|
|
388
|
+
blank text. It also has no `id`, so unlike `ErrorMessage` it can't be wired to `aria-describedby`.
|
|
389
|
+
|
|
390
|
+
**Apply:** treat `ErrorComponent` as `Input`/`PinInputs`-specific, not a general error row; guard it
|
|
391
|
+
with a truthy-message check yourself, and use `ErrorMessage` for any other field.
|
|
392
|
+
|
|
393
|
+
### `FormattedDescription`'s single-`*italic*` marker strips the asterisks but applies no italic style
|
|
394
|
+
|
|
395
|
+
`**bold**` works; a lone `*word*` silently renders as plain text with the markers removed, reading
|
|
396
|
+
as though the formatting was simply ignored.
|
|
397
|
+
|
|
398
|
+
**Apply:** don't rely on single-asterisk emphasis in `content` strings — use `**bold**` or plain text.
|
|
399
|
+
|
|
400
|
+
### `Timeline`'s `onEditNote` editor doesn't auto-close without `editNoteLoading` — unlike add-note
|
|
401
|
+
|
|
402
|
+
Add-note has a back-compat fallback that closes its editor immediately if `addNoteLoading` is never
|
|
403
|
+
wired. Edit-note has no equivalent fallback — its only close path is an effect watching
|
|
404
|
+
`editNoteLoading` transition `true → false`. Wire `onEditNote` without `editNoteLoading` and Save
|
|
405
|
+
looks like it does nothing: the form stays open with no error or feedback.
|
|
406
|
+
|
|
407
|
+
**Apply:** always pass `editNoteLoading` alongside `onEditNote`, even a client-only flag flipped
|
|
408
|
+
right after the call resolves.
|
|
409
|
+
|
|
410
|
+
### `Timeline`'s `events` prop is dead — only `timelineEvents` renders
|
|
411
|
+
|
|
412
|
+
`events` is typed and accepted, reads as a plausible prop name, and is never used by the component.
|
|
413
|
+
|
|
414
|
+
**Apply:** always use `timelineEvents`; treat `events`/the exported `TimelineEvent` type as vestigial.
|
|
415
|
+
|
|
416
|
+
### `Timeline` drops events with an unparseable `created_at`, with no visible trace
|
|
417
|
+
|
|
418
|
+
An event whose formatted date resolves to `"Invalid Date"` is excluded from every date group — not
|
|
419
|
+
shown in a fallback bucket, just gone. The only signal is a `console.warn` inside the formatter.
|
|
420
|
+
|
|
421
|
+
**Apply:** validate/normalize `created_at` before handing events to `Timeline` — a bad timestamp is
|
|
422
|
+
silent, total content loss for that row.
|
|
423
|
+
|
|
424
|
+
### `Reorder`'s `onReorder` fires even when nothing moved, and its real props aren't in its exported type
|
|
425
|
+
|
|
426
|
+
A drag that ends back at its starting index still has a drop target and still calls `onReorder` with
|
|
427
|
+
a new array reference in the same order. Separately, the component supports `showRemoveIcon`/
|
|
428
|
+
`onRemove` in practice, but the exported `ReorderListProps` type declares only
|
|
429
|
+
`label`/`items`/`onReorder` — neither `ReorderListProps` nor `ReorderItem` is exported from
|
|
430
|
+
`src/index.ts` at all, so there's no public named type to check either way.
|
|
431
|
+
|
|
432
|
+
**Apply:** compare source/destination index (or diff the array) before persisting a reorder, if a
|
|
433
|
+
no-op write matters. `showRemoveIcon`/`onRemove` do work — pass them despite the type gap.
|
|
434
|
+
|
|
435
|
+
### `Divider` and `Trail`'s pieces aren't exported from the package at all
|
|
436
|
+
|
|
437
|
+
Neither `src/Components/Divider/` nor `src/Components/Trail/` appears in `src/index.ts`, though both
|
|
438
|
+
still compile into `dist/` and are deep-import-reachable. The library's own `Divider` is always
|
|
439
|
+
vertical, fixed size/color, zero props — a different thing from the general-purpose (horizontal,
|
|
440
|
+
styleable) `Divider` re-exported from the `Primitives` barrel. `Trail/TrailWorks` is a hardcoded
|
|
441
|
+
2-row demo table, not a reusable grid.
|
|
442
|
+
|
|
443
|
+
**Apply:** for a divider in a consuming app, use the `Divider` from `Primitives`, not this library's
|
|
444
|
+
own. For a real data grid, use `Table` — nothing under `Trail/` is meant for reuse.
|
|
445
|
+
|
|
446
|
+
### `KanbanActions` is exported but still not wired into `KanbanBoard`
|
|
447
|
+
|
|
448
|
+
`KanbanBoard`'s header select/edit/create bar is driven by its own `kanbanSelect`/`kanbanEdit`/
|
|
449
|
+
`kanbanCreate` props, via a different internal component. `KanbanActions` is a separate, standalone
|
|
450
|
+
component (exported from the package root as of 2.4.2-beta.39) that a consumer must render and wire
|
|
451
|
+
up itself — its `options`-driven buttons always render with no permission gating, unlike
|
|
452
|
+
`KanbanBoard`'s own header actions, which respect `permissions.isEditable`/`isCreatable`.
|
|
453
|
+
|
|
454
|
+
**Apply:** use `KanbanBoard`'s own `kanbanSelect`/`kanbanEdit`/`kanbanCreate` props for the board's
|
|
455
|
+
built-in header actions. Reach for `KanbanActions` only when building a custom toolbar outside
|
|
456
|
+
`KanbanBoard`, and gate it yourself — it has no permissions awareness of its own.
|
|
457
|
+
|
|
458
|
+
### `KanbanBoard`'s `permissions.isEditable: false` disables card drag but not column-reorder drag
|
|
459
|
+
|
|
460
|
+
Card `Draggable`s get `isDragDisabled={!canDrag}`; the column-reorder `Draggable` (active when
|
|
461
|
+
`enableColumnReorder` is true) never checks it — a "read-only" board still lets users reorder whole
|
|
462
|
+
columns.
|
|
463
|
+
|
|
464
|
+
**Apply:** also set `enableColumnReorder={false}` to fully lock a read-only board.
|
|
465
|
+
|
|
466
|
+
### `KanbanBoard`'s `collapsedColumns` only seeds initial state — not a live controlled prop
|
|
467
|
+
|
|
468
|
+
It seeds a `useState` lazy initializer once, on mount. Without the `preferences` feature wired, a
|
|
469
|
+
later render passing a different `collapsedColumns` value does nothing, despite the name implying a
|
|
470
|
+
controlled value.
|
|
471
|
+
|
|
472
|
+
**Apply:** to force a column open/closed post-mount without `preferences`, remount the board (change
|
|
473
|
+
its `key`) rather than re-passing the prop.
|
|
474
|
+
|
|
475
|
+
### `KanbanBoard`'s `account.customNode` silently drops delete/open/expand for that one card
|
|
476
|
+
|
|
477
|
+
An item with `customNode` set renders that function instead of `AccountCard`, so `onDelete`,
|
|
478
|
+
`onOpen`, `isDeletable`, and expand/collapse never apply — even though they read as board-wide
|
|
479
|
+
props. Mixing plain and `customNode` items in one column produces inconsistent per-card behavior.
|
|
480
|
+
|
|
481
|
+
**Apply:** don't expect board-wide card actions to reach a `customNode` card; wire them inside your
|
|
482
|
+
custom render instead.
|
|
483
|
+
|
|
484
|
+
### `KanbanBoard`'s `AccountCard` only renders string-typed fields, and mangles camelCase labels
|
|
485
|
+
|
|
486
|
+
A numeric field on an `Account` (explicitly allowed by its index signature) is silently never shown
|
|
487
|
+
in the card's field list. The auto-generated label only splits on `_` — a snake_case key
|
|
488
|
+
(`account_name`) renders as "Account Name," but an idiomatic camelCase key (`nextFollowUp`)
|
|
489
|
+
collapses into one mashed word ("Nextfollowup").
|
|
490
|
+
|
|
491
|
+
**Apply:** use snake_case keys on `Account` objects, and keep numeric display values as strings.
|
|
492
|
+
|
|
493
|
+
### `KanbanBoard`'s `onColumnDelete` receives the deleted column's **card** ids, not the column's id
|
|
494
|
+
|
|
495
|
+
Despite the callback parameter being named `colId`-adjacent, what's actually passed is
|
|
496
|
+
`columns[colId].items.map(item => item.id)` — the cards that were in the column, never the column's
|
|
497
|
+
own id.
|
|
498
|
+
|
|
499
|
+
**Apply:** track which column was being deleted another way (e.g. hover/selection state captured
|
|
500
|
+
before the click) if you need the column id itself.
|
|
501
|
+
|
|
502
|
+
### `isRequired` is decorative on some fields, native on others — same prop name, different behavior
|
|
503
|
+
|
|
504
|
+
`TextInput`, `PhoneNumberInput`, and the exported `PinInput` pass `isRequired` only to the label
|
|
505
|
+
(draws a `*`) — the field itself never gets `required`/`aria-required` (confirmed by an `it.failing`
|
|
506
|
+
case in `TextInput.a11y.test.tsx`). `NumberInput` and the internal `Input.tsx` do propagate it
|
|
507
|
+
natively. A form relying on `isRequired` for native HTML5/AT validation works on some fields and
|
|
508
|
+
silently doesn't on others.
|
|
509
|
+
|
|
510
|
+
**Apply:** don't rely on `isRequired` for native form validation — validate required fields yourself
|
|
511
|
+
regardless of which component you're using.
|
|
512
|
+
|
|
513
|
+
### `PhoneNumberInput` and `NoteTextArea` type a `ref` prop that never attaches
|
|
514
|
+
|
|
515
|
+
Both are plain function components, not `forwardRef` — a `ref` passed to a plain function component
|
|
516
|
+
is stripped before the body runs, so the destructured ref param is always `undefined`.
|
|
517
|
+
`NoteTextArea` compounds this: even where it does forward a ref, it only reaches the secondary title
|
|
518
|
+
input, never the primary `Textarea`.
|
|
519
|
+
|
|
520
|
+
**Apply:** don't rely on a `ref` into either component; `NumberInput`/`InputTextArea` forward refs
|
|
521
|
+
correctly if you need that pattern.
|
|
522
|
+
|
|
523
|
+
### `NoteTextArea`'s `saveButtonLoading` going `true → false` clears the draft even on a failed save
|
|
524
|
+
|
|
525
|
+
The effect that resets note/title/files fires whenever `saveButtonLoading` goes falsy — there's no
|
|
526
|
+
separate success/failure signal, so a parent that turns off the loading flag after a failed save
|
|
527
|
+
silently discards everything the user typed.
|
|
528
|
+
|
|
529
|
+
**Apply:** don't flip `saveButtonLoading` back to `false` on failure without your own recovery path
|
|
530
|
+
(e.g. keep the draft in your own state and re-seed it).
|
|
531
|
+
|
|
532
|
+
### `PinInput` and `PinInputs` are two unrelated implementations — only one is real
|
|
533
|
+
|
|
534
|
+
The component published as `PinInput` from `index.ts` is Chakra-native, themed, supports OTP paste
|
|
535
|
+
and `type: "alphanumeric" | "number"`. `PinInputs` (plural) is a separate, hand-rolled,
|
|
536
|
+
always-numeric implementation that is **not exported** and not referenced anywhere else in the repo
|
|
537
|
+
— a dead-code candidate, not an alternate API. It still compiles into `dist/`, so the deep-import
|
|
538
|
+
pattern this repo otherwise supports would silently pull in the unmaintained one.
|
|
539
|
+
|
|
540
|
+
**Apply:** always use `PinInput` (singular); never deep-import `PinInputs`.
|
|
541
|
+
|
|
542
|
+
### `InputSwitch`'s checked/unchecked track color is silently replaced by a caller-supplied `sx`
|
|
543
|
+
|
|
544
|
+
The component's own `sx` (sets track background from `isChecked`) is spread over first, then
|
|
545
|
+
`{...props}` — any `sx` a caller passes wins outright, so the switch stops changing color on toggle.
|
|
546
|
+
|
|
547
|
+
**Apply:** don't pass `sx` to override styling on `InputSwitch`; if you must, re-include the
|
|
548
|
+
checked/unchecked background logic yourself.
|
|
549
|
+
|
|
550
|
+
### `TextInput`'s `placeholder` defaults to the literal word `"Placeholder"`, not empty
|
|
551
|
+
|
|
552
|
+
Omit the prop and real users see the actual text "Placeholder" in the field.
|
|
553
|
+
|
|
554
|
+
**Apply:** always pass an explicit `placeholder` (or an empty string) at every `TextInput` call site.
|
|
555
|
+
|
|
556
|
+
### The internal `Input.tsx` silently ignores six declared props
|
|
557
|
+
|
|
558
|
+
`disabled`, `autoComplete`, `autoFocus`, `inputClassName`, `labelClassName`, and `errorClassName`
|
|
559
|
+
are all typed on `InputProps` but never read — passing them, `disabled` especially, compiles cleanly
|
|
560
|
+
and does nothing. It also has no `id` field, so its label always renders as an unassociated `<span>`.
|
|
561
|
+
|
|
562
|
+
**Apply:** this is an internal component (not exported) reachable only via deep import — prefer
|
|
563
|
+
`TextInput` for anything public-facing, which doesn't have this gap.
|
|
564
|
+
|
|
565
|
+
### `AlertDialog`'s `colorScheme`/`size`/`status`/`variant`/`addRole` are dead props
|
|
566
|
+
|
|
567
|
+
Typed (`Pick`ed from Chakra's `AlertProps`) but never destructured — Cancel/Confirm are hardcoded
|
|
568
|
+
red/primary at `size="sm"` regardless of what you pass.
|
|
569
|
+
|
|
570
|
+
**Apply:** style Cancel/Confirm via `button1Style`/`button2Style`, not `colorScheme`/`size`/`status`/
|
|
571
|
+
`variant`.
|
|
572
|
+
|
|
573
|
+
### `AlertDialog` can always be dismissed via Escape or an overlay click, not just its buttons
|
|
574
|
+
|
|
575
|
+
`closeOnOverlayClick`/`closeOnEsc` aren't exposed as props, so Chakra's `true`/`true` defaults apply
|
|
576
|
+
unconditionally — `onClose` fires the same way for Escape/overlay-click as for the Cancel button.
|
|
577
|
+
|
|
578
|
+
**Apply:** don't treat `onClose` as "the user explicitly chose Cancel" — that distinction isn't
|
|
579
|
+
available through this component.
|
|
580
|
+
|
|
581
|
+
### `ToolTip`'s `overflowOnly` silently no-ops on non-single-element children
|
|
582
|
+
|
|
583
|
+
The truncation ref only attaches when `children` passes `React.isValidElement` — a bare string, a
|
|
584
|
+
Fragment, or multiple children skip that branch, so the tooltip always shows instead of
|
|
585
|
+
only-when-truncated (the opposite of the prop's contract).
|
|
586
|
+
|
|
587
|
+
**Apply:** give `overflowOnly`/`OverflowToolTip` exactly one real element as `children` (e.g. a
|
|
588
|
+
single `Text noOfLines`), never a Fragment or bare text.
|
|
589
|
+
|
|
590
|
+
### `Toaster`'s `showToast({ children })` is a dead prop, and its two `onClose`s are different functions
|
|
591
|
+
|
|
592
|
+
`children` type-checks (Picked from Chakra's `ToastProps`) but is never read — only `title`/
|
|
593
|
+
`description`/`actions` render. Separately, the `onClose` you pass to `showToast` is wired to
|
|
594
|
+
Chakra's `onCloseComplete` (fires after the exit animation, on any dismiss path); the `onClose` your
|
|
595
|
+
`actions` render-prop receives is a different, immediate per-toast dismiss function.
|
|
596
|
+
|
|
597
|
+
**Apply:** pass `description`, not `children`. Don't assume your `onClose` fires the instant the
|
|
598
|
+
user clicks close — it fires after the exit transition completes.
|
|
599
|
+
|
|
600
|
+
### Every `Toaster` status announces at `aria-live="polite"`, including `error`
|
|
601
|
+
|
|
602
|
+
No urgency bump for errors, and status is conveyed by icon + colour alone with no text equivalent —
|
|
603
|
+
confirmed by two intentionally-`it.failing` tests in `Toaster.a11y.test.tsx`.
|
|
604
|
+
|
|
605
|
+
**Apply:** don't rely on an error toast interrupting a screen reader; pair a critical failure with
|
|
606
|
+
another signal (e.g. an inline field error).
|
|
607
|
+
|
|
608
|
+
### `Button`'s `loadingText` defaults to `"Loading"`, not Chakra's spinner-only style
|
|
609
|
+
|
|
610
|
+
`loadingText` defaults to the literal string `"Loading"`, so every `isLoading` button shows that
|
|
611
|
+
text next to the spinner instead of Chakra's native behavior (hide content, spinner only) — even
|
|
612
|
+
icon-only buttons, where it can break the expected square aspect ratio. Passing
|
|
613
|
+
`loadingText={undefined}` does not restore the native look; the default parameter still applies.
|
|
614
|
+
|
|
615
|
+
**Apply:** pass `loadingText=""` explicitly to get a spinner-only loading state.
|
|
616
|
+
|
|
617
|
+
### `ButtonGroupIcon`'s dropdown needs `rightIcon` **and** `rightIconDropdown` both set
|
|
618
|
+
|
|
619
|
+
The `Menu`/`dropdownOptions` branch only renders inside `rightIcon && rightIconDropdown`. Supplying
|
|
620
|
+
`dropdownOptions` alone, or `rightIconDropdown` without `rightIcon`, silently renders nothing on the
|
|
621
|
+
right side. Separately, `onButtongroupClick` is wired to Chakra `ButtonGroup`'s own `onClick` on the
|
|
622
|
+
wrapping div — native DOM bubbling means it fires on every click inside the group (left icon, center
|
|
623
|
+
button, right icon/dropdown), not just a "clicked outside the buttons" signal.
|
|
624
|
+
|
|
625
|
+
**Apply:** always set `rightIcon` + `rightIconDropdown={true}` together for the dropdown. Don't use
|
|
626
|
+
`onButtongroupClick` to detect background clicks — inspect `event.target` if you need to distinguish.
|
|
627
|
+
|
|
628
|
+
### `Buttons` (plural) is not a group wrapper, and not theme-aware
|
|
629
|
+
|
|
630
|
+
Despite the plural name suggesting a group, `Buttons` renders one plain `<button>` hardcoded to
|
|
631
|
+
Tailwind's `bg-purple-600` — it ignores brand/dark-mode entirely and isn't exported from the package
|
|
632
|
+
root.
|
|
633
|
+
|
|
634
|
+
**Apply:** use `Button` for a single themed button or `ButtonGroupIcon` for a themed group; there is
|
|
635
|
+
no good reason to reach for `Buttons`.
|
|
636
|
+
|
|
637
|
+
### `Card` silently drops `header`, `footer`, and all three divider props
|
|
638
|
+
|
|
639
|
+
`CardProps` declares `header`, `footer`, `dividercolor`, `dividersize`, `dividervariant`, but none
|
|
640
|
+
are destructured by `Card` — passing them compiles cleanly and renders nothing. Padding is also
|
|
641
|
+
hardcoded (`p={4}`), so it can't be tuned via props either.
|
|
642
|
+
|
|
643
|
+
**Apply:** put header/footer content inside `children`; use `sx` for padding overrides.
|
|
644
|
+
|
|
645
|
+
### `ProductCard`'s variant selection goes stale after an `options` update, and `options={[]}` crashes it
|
|
646
|
+
|
|
647
|
+
Both `ProductCard` and its internal `ProductPrice` capture `options[0]` into state only once, at
|
|
648
|
+
mount, with no resync effect — a later re-render with refreshed `options` (new stock/price) is
|
|
649
|
+
silently ignored, so Add to Cart/Notify Me act on stale data. An empty array crashes on
|
|
650
|
+
`selected.label`. Separately, `description` and `avalabilitys` are typed and accepted but never
|
|
651
|
+
read by the component.
|
|
652
|
+
|
|
653
|
+
**Apply:** treat `options` as effectively static per mount (remount via `key` if it changes), and
|
|
654
|
+
never pass `[]`. Don't rely on `description`/`avalabilitys` — there's currently no way to show either.
|
|
655
|
+
|
|
656
|
+
### `ProductTags` (shared by `ProductCard`/`ProductDetails`) silently renders zero tags past 4
|
|
657
|
+
|
|
658
|
+
The row-layout helper only handles 1-4 entries — 5 or more tags renders nothing at all, no
|
|
659
|
+
truncation or "+N more" affordance.
|
|
660
|
+
|
|
661
|
+
**Apply:** cap `tags` at 4 entries at the call site until the component adds an overflow case.
|
|
662
|
+
|
|
663
|
+
### `PaymentCard`'s `onHover` never fires its `"card"` variant, and the CTA hides unless `isRenewal`
|
|
664
|
+
|
|
665
|
+
`onHover`'s type promises `"card" | "button"`, but no hover handler exists on the outer plan card —
|
|
666
|
+
only the CTA button wires hover. Separately, the CTA (and its callbacks) disappears whenever
|
|
667
|
+
`isActive` is true unless `isRenewal` is also set, regardless of `plan.buttonText`.
|
|
668
|
+
|
|
669
|
+
**Apply:** don't build "card" hover analytics on this prop. Pass `isRenewal` to show a CTA on the
|
|
670
|
+
current/active plan.
|
|
671
|
+
|
|
672
|
+
### `OrganizationDetails`' `defaultOrg === 1` silently overrides an explicit `canDelete: true`
|
|
673
|
+
|
|
674
|
+
`isProtected` is computed as `item.defaultOrg === 1 || canProtect` — `defaultOrg` short-circuits the
|
|
675
|
+
`canDelete`/role check unconditionally. An org that is both the user's default and marked
|
|
676
|
+
`canDelete: true` still renders a disabled delete button, with only a tooltip explaining why.
|
|
677
|
+
|
|
678
|
+
**Apply:** don't rely on `canDelete` alone to guarantee delete is enabled — check `defaultOrg` too.
|
|
679
|
+
|
|
680
|
+
### `OrganizationDetails`, `CustomModulesTable`'s create/edit/delete modals show no error UI on rejection
|
|
681
|
+
|
|
682
|
+
`onCreateOrganization`/`onDeleteOrganization`/`onEditOrganization` (and `CustomModulesTable`'s
|
|
683
|
+
`onUpdateModule`/`onDeleteModule`) are `await`ed and the modal only resets on success — a rejection
|
|
684
|
+
is an unhandled promise rejection with zero visible feedback.
|
|
685
|
+
|
|
686
|
+
**Apply:** wrap your own handler in try/catch and show your own error toast; the library never does
|
|
687
|
+
it for you.
|
|
688
|
+
|
|
689
|
+
### `OrgSwitcher`'s `onChange` doesn't fire on re-selecting the already-active org, and has a closed prop list
|
|
690
|
+
|
|
691
|
+
Re-clicking the current org closes the popover but skips `onChange` entirely (`org.id !== value` gate)
|
|
692
|
+
— don't rely on it for a side effect that must run on every click (analytics, refetch). Separately,
|
|
693
|
+
the trigger has no `...rest`/`ref` escape hatch: a `data-testid`, `id`, or positioning `ref` can't
|
|
694
|
+
reach it.
|
|
695
|
+
|
|
696
|
+
**Apply:** don't depend on `onChange` firing for a repeat pick. There's no supported way to attach
|
|
697
|
+
test hooks or a ref to the trigger.
|
|
698
|
+
|
|
699
|
+
### `UpgradeButton`'s gold icon accent silently falls back to the label color on low contrast
|
|
700
|
+
|
|
701
|
+
The gold accent is only used when it clears AA contrast against both gradient stops; a custom
|
|
702
|
+
`gradient` prop can flip it to the label's own ink color with no signal.
|
|
703
|
+
|
|
704
|
+
**Apply:** don't assume the icon stays gold with a custom `gradient` — check contrast yourself if the
|
|
705
|
+
gold accent is load-bearing for your design.
|
|
706
|
+
|
|
707
|
+
### `PlanPill`/`PlanBadge` always render as a real, focusable `<button>` — even with no `onClick`
|
|
708
|
+
|
|
709
|
+
`as="button"`, `cursor="pointer"`, and the hover-lift are unconditional. Omitting the optional
|
|
710
|
+
`onClick` does not get you a static/informational pill — it stays tabbable and screen-reader
|
|
711
|
+
-announced as a button regardless.
|
|
712
|
+
|
|
713
|
+
**Apply:** there is currently no way to get a non-interactive plan badge from this component.
|
|
714
|
+
|
|
715
|
+
### `LimitReachedModal`'s `onUpgrade` never triggers `onClose`, and needs both `limit` and `used` to show usage
|
|
716
|
+
|
|
717
|
+
Clicking the CTA calls only `onUpgrade` — confirmed by the component's own test. Separately, the
|
|
718
|
+
inline usage line renders only when **both** `limit` and `used` are non-nullish; passing just one
|
|
719
|
+
silently omits the whole line.
|
|
720
|
+
|
|
721
|
+
**Apply:** close the modal yourself inside your `onUpgrade` handler if upgrading should dismiss it.
|
|
722
|
+
Always pass `limit`/`used` together, or neither.
|
|
723
|
+
|
|
724
|
+
### `CustomModulesTable`'s `ModuleItem.module_id` is the one snake_case field on an otherwise camelCase type
|
|
725
|
+
|
|
726
|
+
A loosely-typed API response cast straight to `ModuleItem[]` can leave `module_id: undefined` with
|
|
727
|
+
no compile error, colliding React `key`s.
|
|
728
|
+
|
|
729
|
+
**Apply:** map the API field explicitly to `module_id` — don't assume this type is uniformly
|
|
730
|
+
camelCase like its sibling payload type (`UpdateModulePayload.moduleId`).
|
|
731
|
+
|
|
732
|
+
### `RolesPermission`'s permission matrix silently reroutes every column for an "Automation" row
|
|
733
|
+
|
|
734
|
+
Any `permissions[]` row whose `module` case-insensitively equals `"automation"` collapses every
|
|
735
|
+
column onto a single `automation` boolean — only the Read cell renders/toggles, and clicking it
|
|
736
|
+
calls `onPermissionChange(module, "automation")`, not `"read"`. Separately, `roles_id` (typed
|
|
737
|
+
`string`) is coerced via `Number()` before `onDeleteRole` fires — a UUID or ObjectId silently
|
|
738
|
+
becomes `NaN`.
|
|
739
|
+
|
|
740
|
+
**Apply:** if a row's `module` can be `"automation"`, expect only its Read checkbox to work, toggling
|
|
741
|
+
`automation` — create/edit/delete/import/export are unreachable for that row. Only pass
|
|
742
|
+
numeric-string `roles_id` values.
|
|
743
|
+
|
|
744
|
+
### Several delete/deactivate modals close before their async handler can be awaited
|
|
745
|
+
|
|
746
|
+
`RolesPermission`'s `DeleteRoleModal` and `UserDetails`' `DeactivateConfirmModal` call their
|
|
747
|
+
handlers fire-and-forget (typed plain `() => void`) and close synchronously in the same tick — the
|
|
748
|
+
opposite failure mode from the create/edit modals above, whose handlers are genuinely awaited.
|
|
749
|
+
|
|
750
|
+
**Apply:** any `isLoading`/spinner wiring for delete/deactivate can never be seen — handle
|
|
751
|
+
loading/error UI outside these two modals (e.g. a toast).
|
|
752
|
+
|
|
753
|
+
### `UserDetails`' Change Role and Resend Invitation buttons silently no-op when `userId` is null
|
|
754
|
+
|
|
755
|
+
Only Deactivate actually disables itself when `selectedUser.userId` is null — the other two stay
|
|
756
|
+
visually enabled and do nothing on click. Separately, `ChangeRoleModal` pre-selects the current role
|
|
757
|
+
by case-insensitive **label text** match, not an id — any mismatch (whitespace, a renamed role)
|
|
758
|
+
silently opens the modal with nothing pre-selected, no error shown.
|
|
759
|
+
|
|
760
|
+
**Apply:** always populate `selectedUser.userId` when those two actions should be usable. Keep
|
|
761
|
+
`currentRole` as the exact display label kept in sync with `roleOptions[].label`.
|
|
762
|
+
|
|
763
|
+
### `FileUploader`'s `onFilesChange` discards the real `File`, and its `acceptTypes`/`maxFiles` enforce nothing
|
|
764
|
+
|
|
765
|
+
`FileUploader` hands back lightweight `{id, name, size, previewUrl}` metadata — the original `File`
|
|
766
|
+
is discarded in `handleFiles`, so it can never back an actual upload. `acceptTypes` only sets the
|
|
767
|
+
native picker's `accept` attribute; drag-and-drop ignores it completely and no code path rejects a
|
|
768
|
+
wrong-type file. Exceeding `maxFiles` silently truncates the list with no error.
|
|
769
|
+
|
|
770
|
+
**Apply:** need real file bytes or enforced validation → use `FileUpload`, not `FileUploader`.
|
|
771
|
+
|
|
772
|
+
### `FileUpload`'s default `maxSizeKB` is 5 — that's 5 **kilobytes**, not megabytes
|
|
773
|
+
|
|
774
|
+
Left at its default, `FileUpload` rejects virtually every real file, and the auto-generated
|
|
775
|
+
hint/error text literally reads "0.00 MB" because the KB→MB conversion divides an already-tiny value.
|
|
776
|
+
|
|
777
|
+
**Apply:** always pass an explicit `maxSizeKB` in KB (e.g. `5000` for ~5MB).
|
|
778
|
+
|
|
779
|
+
### `DatePicker`'s `pickerType` does nothing when `isRange` is set, and no variant has a seconds control
|
|
780
|
+
|
|
781
|
+
`RangeDatePicker` never reads `pickerType` — whether time inputs show is controlled entirely by
|
|
782
|
+
whether `dateFormat` contains time tokens. Separately, every time-capable picker caps at minute
|
|
783
|
+
granularity regardless of `dateFormat` — a format containing `ss` compiles and parses but seconds
|
|
784
|
+
are never user-editable.
|
|
785
|
+
|
|
786
|
+
**Apply:** for a range picker, control the time row via `dateFormat`, never `pickerType`. Don't
|
|
787
|
+
request second-precision input from any DatePicker variant.
|
|
788
|
+
|
|
789
|
+
### `RangeDatePicker` loses a picked range if you click outside instead of Apply
|
|
790
|
+
|
|
791
|
+
Unlike `SingleDatePicker`, its outside-click handler doesn't call `finalize()` — only the Apply
|
|
792
|
+
button or Escape commits a completed range via `onChange`. Clicking anywhere else outside the
|
|
793
|
+
popover after picking both ends discards the selection silently.
|
|
794
|
+
|
|
795
|
+
**Apply:** don't assume outside-click commits a range the way it does for `SingleDatePicker`.
|
|
796
|
+
|
|
797
|
+
### `TimeOnlyPicker`'s label is never associated with its field, and `name` is a no-op
|
|
798
|
+
|
|
799
|
+
Passing `id`/`label` does not produce an accessible `<label for>` — the internal label call omits
|
|
800
|
+
`id`, so it always renders as an unassociated `<span>`. `name` (and `minDate`/`maxDate`/
|
|
801
|
+
`disableFutureDates`/`disablePastDates`/`autoComplete`) are also silently dropped — the rendered
|
|
802
|
+
`<input>` never gets a `name` attribute, breaking plain `<form>`/`FormData` submission.
|
|
803
|
+
|
|
804
|
+
**Apply:** don't rely on `TimeOnlyPicker` for native form submission or label accessibility; read its
|
|
805
|
+
value via `onChange` rather than form `name`.
|
|
806
|
+
|
|
807
|
+
### `Editor`'s `config` prop can silently break dark mode, and its `key` prop can never reach Jodit
|
|
808
|
+
|
|
809
|
+
`Editor` computes `config.theme`/`config.popupRoot` itself to fix Jodit's dark-mode/popup theming,
|
|
810
|
+
then spreads your `config` on top — any `theme`/`popupRoot` key you pass wins and silently disables
|
|
811
|
+
the fix. Separately, `key` is typed as if readable, but React reserves and strips it before the
|
|
812
|
+
component sees `props`, so it's always `undefined` internally and can't force a remount. `editorRef`
|
|
813
|
+
is also `null` until Jodit's lazy-loaded chunk resolves — a mount-time effect reading it gets nothing.
|
|
814
|
+
|
|
815
|
+
**Apply:** never set `theme`/`popupRoot` inside the `config` you pass to `Editor`. To force a
|
|
816
|
+
remount, wrap `<Editor>` itself in a keyed parent, not via `Editor`'s own `key` prop.
|
|
817
|
+
|
|
818
|
+
### `SelectV2`, `SearchSelect`, and `SelectSearch` all search `option.label` only
|
|
819
|
+
|
|
820
|
+
None of the three checks a rendered secondary field (`option.description`, a custom `view` node,
|
|
821
|
+
`option.email` on a profile row) — typing text that's visibly on-screen in a secondary field returns
|
|
822
|
+
no match.
|
|
823
|
+
|
|
824
|
+
**Apply:** if a secondary field needs to be searchable, fold it into `option.label` yourself, or
|
|
825
|
+
pre-filter `options` before passing them in.
|
|
826
|
+
|
|
827
|
+
### `SearchSelect` never virtualizes, and `chip.maxChips={0}` is swallowed by a falsy fallback
|
|
828
|
+
|
|
829
|
+
Despite the prop name, `virtualization` does nothing — every filtered option renders as a real DOM
|
|
830
|
+
node; the list scales only via consumer-driven `pagination`. Separately,
|
|
831
|
+
`selectedValues.slice(0, chip?.maxChips || selectedValues.length)` treats a literal `0` as "no limit
|
|
832
|
+
set" (falsy), so every chip renders anyway instead of zero.
|
|
833
|
+
|
|
834
|
+
**Apply:** for a dataset large enough to need real virtualization, page it in via `pagination` rather
|
|
835
|
+
than setting `virtualization={true}`. Pass `1` or higher to `chip.maxChips`; there's no supported way
|
|
836
|
+
to hide all chips via this prop.
|
|
837
|
+
|
|
838
|
+
### `SelectSearch`'s Enter key requires an exact full-label match, not the keyboard-highlighted option
|
|
839
|
+
|
|
840
|
+
Typing a partial query and pressing Enter without arrowing down first does not pick the
|
|
841
|
+
visually-highlighted top option — it only fires if the typed text exactly equals an option's full
|
|
842
|
+
label. `SelectV2`/`SearchSelect` both correctly select the highlighted option on Enter; `SelectSearch`
|
|
843
|
+
doesn't. Two more props (`isSearchEnabled`, `BottomIconStyle`) are typed but never read, and
|
|
844
|
+
`initialSelectedOption` only seeds selection at mount with no resync if the real value arrives later.
|
|
845
|
+
|
|
846
|
+
**Apply:** tell users to arrow down before Enter with this component specifically. Don't pass
|
|
847
|
+
`initialSelectedOption` before the real value is known (or key the component to force a remount).
|
|
848
|
+
|
|
849
|
+
### `FieldSelectModal`'s "Select all" ignores the active search filter, and resets on any parent re-render
|
|
850
|
+
|
|
851
|
+
The header checkbox (and its indeterminate state) always operates on the complete `fields` list, not
|
|
852
|
+
the search-filtered subset — clicking it while filtered silently selects/clears fields the user can't
|
|
853
|
+
see. Separately, an effect re-seeds selection whenever `fields`/`defaultSelected` changes
|
|
854
|
+
**reference**, so an inline array literal for either prop silently wipes in-progress picks on the
|
|
855
|
+
next parent re-render.
|
|
856
|
+
|
|
857
|
+
**Apply:** clear the search before using "Select all." Memoize `fields`/`defaultSelected` in the
|
|
858
|
+
parent before passing them down.
|
|
859
|
+
|
|
860
|
+
### `Dropdown`'s `ButtonText`/`text` are mutually exclusive per `dropdownType`, silently
|
|
861
|
+
|
|
862
|
+
The `"button"` trigger renders `ButtonText` only; the `"text"` trigger renders `text` only — pairing
|
|
863
|
+
the wrong prop with the active `dropdownType` renders an icon-only or bare-chevron trigger with no
|
|
864
|
+
visible label, and the `aria-label` fallback then substitutes "Open menu" as the accessible name too.
|
|
865
|
+
Separately, `buttonProps.sx` fully replaces the built-in trigger style rather than merging, silently
|
|
866
|
+
dropping the hover transition.
|
|
867
|
+
|
|
868
|
+
**Apply:** pair `ButtonText` with the default/`"button"` type and `text` with `dropdownType="text"`.
|
|
869
|
+
Fold custom styling into `dropDownButtonStyle`, not `buttonProps.sx`.
|
|
870
|
+
|
|
871
|
+
### `Search`'s default `shortcut` grabs a page-global Ctrl+K with no way to opt out
|
|
872
|
+
|
|
873
|
+
Every mounted `Search` registers its own `window` Ctrl+K listener by default — the type only permits
|
|
874
|
+
the literal `"Ctrl+K"` or `undefined`, and `undefined` still resolves to the same default via JS
|
|
875
|
+
parameter defaulting. Two instances on one visible view race for the keypress.
|
|
876
|
+
|
|
877
|
+
**Apply:** avoid mounting more than one `Search` per visible view/route — there's currently no way to
|
|
878
|
+
scope or disable the hotkey per-instance.
|
|
879
|
+
|
|
880
|
+
### `Header`'s desktop submenus open on hover only — no keyboard or click trigger
|
|
881
|
+
|
|
882
|
+
Dropdown children are gated on local hover state (`onMouseEnter`/`onMouseLeave`), with no `onFocus`.
|
|
883
|
+
A keyboard user tabbing to a parent item can never open its children on the desktop layout — the
|
|
884
|
+
identical data renders as a click-toggled accordion on mobile.
|
|
885
|
+
|
|
886
|
+
**Apply:** don't put anything a keyboard user must reach behind `children` on desktop; use `rightSlot`
|
|
887
|
+
(real focusable buttons) for critical actions until this gets a keyboard path.
|
|
888
|
+
|
|
889
|
+
### `WorkspaceWindow`'s `state="maximized"` is indistinguishable from `"medium"`
|
|
890
|
+
|
|
891
|
+
The component only branches on `state === "minimized"` — size is always the same fixed constant, and
|
|
892
|
+
`onMedium`/`onMaximize` are accepted callbacks that are never invoked anywhere in the component.
|
|
893
|
+
|
|
894
|
+
**Apply:** treat `state` as effectively two-valued (open vs. `"minimized"`); don't wire a maximize
|
|
895
|
+
control expecting `onMaximize` to fire.
|
|
896
|
+
|
|
897
|
+
### `FilterSidebar`'s `selected` without `onChange` makes every filter silently inert
|
|
898
|
+
|
|
899
|
+
Passing `selected` alone (uncontrolled companion `onChange` omitted) computes the next filter state
|
|
900
|
+
on every click and discards it — checkboxes visibly never check, forever, with no error. Separately,
|
|
901
|
+
`onApply`, `headerPadding`, and `sliderMode` are all typed and accepted but have zero effect —
|
|
902
|
+
`FilterSection.checkboxes` doesn't exist either; radio-vs-checkbox mode is actually decided by
|
|
903
|
+
`type === "radio" || section.radio`.
|
|
904
|
+
|
|
905
|
+
**Apply:** always pass `selected` and `onChange` together, or omit `selected` and let `FilterSidebar`
|
|
906
|
+
own its state. Don't reach for `onApply`/`headerPadding`/`sliderMode`/`FilterSection.checkboxes` —
|
|
907
|
+
none of them do anything.
|
|
908
|
+
|
|
909
|
+
### `Breadcrumbs`' `isLastChild` prop is accepted but never read
|
|
910
|
+
|
|
911
|
+
It's declared on the type but omitted from the component's destructure entirely.
|
|
912
|
+
|
|
913
|
+
**Apply:** don't pass it expecting it to mark or style the final crumb — there's nothing it can do.
|
|
914
|
+
|
|
915
|
+
### `Accordion`'s `items[].buttonProps`/`itemProps` replace, not merge, the expanded/hover highlight
|
|
916
|
+
|
|
917
|
+
Both spread after the built-in `bg`/`_hover` that encode `isExpanded` state — passing `bg` or
|
|
918
|
+
`_hover` there to tweak one item's style silently kills that item's expanded/active indication.
|
|
919
|
+
|
|
920
|
+
**Apply:** style around the defaults via `customStyles` (merged through `sx`) rather than
|
|
921
|
+
`buttonProps`/`itemProps` when the highlight must survive.
|
|
922
|
+
|
|
923
|
+
### `Table`'s `LeftFilterPane` Clear All only re-applies filters in `"sidebar"` mode
|
|
924
|
+
|
|
925
|
+
`handleClear` calls `onClear` unconditionally, but only calls `onApply(cleared)` when
|
|
926
|
+
`filterMode === "sidebar"` — in `"modal"` mode, Clear All visually unchecks every filter but never
|
|
927
|
+
tells the parent the selection changed, so a consumer whose `onClear` doesn't itself reset
|
|
928
|
+
applied/query state keeps serving pre-clear filtered data.
|
|
929
|
+
|
|
930
|
+
**Apply:** when using `filterMode="modal"`, drive your data refetch from `onClear`, not `onApply` —
|
|
931
|
+
don't assume `onApply` fires on every Clear All.
|
|
932
|
+
|
|
933
|
+
### `ScrollToTop` watches one `parentElement` hop, not "the nearest scrollable ancestor"
|
|
934
|
+
|
|
935
|
+
It reads `scrollTop` off its immediate DOM parent only, with no upward search for an `overflow:
|
|
936
|
+
auto/scroll` element. Wrap it in one extra layout `<div>` and the button silently never appears — no
|
|
937
|
+
error, no warning, `scrollTop` on a non-scrolling parent just stays `0` forever.
|
|
938
|
+
|
|
939
|
+
**Apply:** `ScrollToTop`'s JSX parent must be the actual scroll container, or pass `useWindow` when
|
|
940
|
+
the page itself scrolls.
|
|
941
|
+
|
|
942
|
+
### `ProfilePhotoViewer`'s PDF detection breaks the moment a file is picked, and `photoUrl` is read once
|
|
943
|
+
|
|
944
|
+
PDF detection is a literal `.endsWith(".pdf")` check — picking a file through the built-in editor
|
|
945
|
+
replaces the value with a base64 data URI that never ends in `.pdf`, so a freshly-picked PDF renders
|
|
946
|
+
as a broken image instead of the intended file badge (only the original URL prop is detected
|
|
947
|
+
correctly). Separately, `photoUrl` only seeds state at mount — a later re-render with a new
|
|
948
|
+
`photoUrl` (list virtualization, route change without remount) keeps showing the old photo.
|
|
949
|
+
|
|
950
|
+
**Apply:** don't use the built-in edit flow for PDF documents; detect kind from `File.type` in your
|
|
951
|
+
own handler instead. Use `key={photoUrl}` to force a remount when the photo identity changes.
|
|
952
|
+
|
|
953
|
+
### `FilePreview` infers file kind from `fileName`, not `fileUrl`, and never resets zoom/rotation on its own
|
|
954
|
+
|
|
955
|
+
Once `fileName` is set, `fileUrl`'s own extension is never consulted — a friendly display name with
|
|
956
|
+
no extension forces the "preview unavailable" fallback even when `fileUrl` points at a perfectly
|
|
957
|
+
renderable file. Separately, cycling `fileUrl` while the modal stays open (a gallery next/prev)
|
|
958
|
+
carries the previous image's zoom/rotation into the new one.
|
|
959
|
+
|
|
960
|
+
**Apply:** keep the real extension on `fileName`, or pass `fileType` explicitly to skip inference.
|
|
961
|
+
Remount via `key={fileUrl}` when swapping the file in place instead of just changing the prop.
|
|
962
|
+
|
|
963
|
+
### `StageProgress`'s `tooltipThreshold`/`minStageWidth` no-op under `variant="stepper"`, and a stale `value` blanks the tracker
|
|
964
|
+
|
|
965
|
+
Both props stop having any effect the moment a tracker switches to the stepper variant. Separately,
|
|
966
|
+
if `value` matches no `stage.id` (e.g. `stages` was filtered/re-derived and went stale), every stage
|
|
967
|
+
silently renders as `"upcoming"` — no stage is ever active or completed, with no error. The match is
|
|
968
|
+
also a strict `===`: a numeric `stage.id` compared against a string `value` (or vice versa) never
|
|
969
|
+
matches either, even when the "same" stage is clearly intended.
|
|
970
|
+
|
|
971
|
+
**Apply:** don't rely on either prop once on the stepper variant. Re-validate `value` against the
|
|
972
|
+
current `stages` list whenever it's filtered, and keep `id`/`value` the same primitive type at every
|
|
973
|
+
call site.
|
|
974
|
+
|
|
975
|
+
### `Table`'s `isVisiblity`, `tableSettings`, `handleExportChange`/`exportOptions`/`exportLabel`, and `onColumnFilter` are dead props
|
|
976
|
+
|
|
977
|
+
None of these do anything in the current implementation, despite being typed on `TableProps` (and
|
|
978
|
+
some documented on the demo page):
|
|
979
|
+
|
|
980
|
+
- `isVisiblity` — `Table`'s own destructure never lists it, so a consumer's value is dropped. It's
|
|
981
|
+
hardcoded `true` into both `Pagination` call sites regardless, and `Pagination` doesn't read it
|
|
982
|
+
either. It is a misspelling of `isVisibility`, but do not rename it (breaking change) — and do not
|
|
983
|
+
expect it to do anything if you do.
|
|
984
|
+
- `tableSettings` (`{filters, filterSelected, onFilterSelection}`) — `Table` passes it to
|
|
985
|
+
`TableSettings`, but `TableSettings`'s function signature never destructures it.
|
|
986
|
+
- `handleExportChange` / `exportOptions` / `exportLabel` — `Table` renders no export UI at all; none
|
|
987
|
+
of the three are read anywhere, despite `src/Pages/table.tsx` documenting them as if live.
|
|
988
|
+
- `onColumnFilter` — commented out of `Table`'s own destructure (`// onColumnFilter`).
|
|
989
|
+
|
|
990
|
+
**Apply:** don't reach for any of these expecting an effect. Column visibility is driven by
|
|
991
|
+
`isTableSettings` (shows the Settings gear) + `preferences` (server persistence) + the Manage
|
|
992
|
+
Columns tab — not by `isVisiblity`/`tableSettings`.
|
|
993
|
+
|
|
994
|
+
### `Table`'s `preferences` prop is silent-by-default, not required
|
|
995
|
+
|
|
996
|
+
Omitting `preferences` (or leaving `preferences.url` empty, the default) does not throw or disable
|
|
997
|
+
the table — the persistence hooks both early-return when the base URL is falsy. The table works
|
|
998
|
+
fully in memory; it just never persists column order/visibility, density, or grouping across
|
|
999
|
+
reloads. When you do wire a `url`, `token` is sent as a **raw** `Authorization` header value — do
|
|
1000
|
+
not prefix it with `"Bearer "` yourself expecting the hook to strip it.
|
|
1001
|
+
|
|
1002
|
+
**Apply:** treat `preferences` as opt-in persistence, not a required config block. If settings
|
|
1003
|
+
aren't surviving a refresh, check `preferences.url` is actually set before assuming a bug.
|
|
1004
|
+
|
|
1005
|
+
### `SearchSelect`'s `height` prop only resizes the `insideSelect` segment, not the field
|
|
1006
|
+
|
|
1007
|
+
Despite the name, `height` is read only to size the nested `insideSelect` trigger. The main
|
|
1008
|
+
control's height always comes from `size`'s token set — passing `height` with no `insideSelect`
|
|
1009
|
+
configured has no visible effect at all.
|
|
1010
|
+
|
|
1011
|
+
**Apply:** to change the main field's height, change `size`; `height` only matters when
|
|
1012
|
+
`insideSelect` is also passed.
|
|
1013
|
+
|
|
1014
|
+
### `SearchSelect`'s `pagination.limit` also drives a "has more" guess, not just page size
|
|
1015
|
+
|
|
1016
|
+
`hasMore` is computed as `options.length % pagination.limit === 0` — there is no real end-of-data
|
|
1017
|
+
signal from the consumer. A total result count that happens to be an exact multiple of `limit`
|
|
1018
|
+
looks indistinguishable from "more pages exist," firing one extra, empty `onScroll` call.
|
|
1019
|
+
|
|
1020
|
+
**Apply:** if exact pagination boundaries matter, pad or report a real "no more results" state some
|
|
1021
|
+
other way; don't rely on `hasMore` being accurate at a page boundary.
|
|
1022
|
+
|
|
1023
|
+
### `RolesPermission`'s `RoleData.permission`/`designation`/`makeSuperAdmin`/`automation`/`trackLocation`/`show_records` are dead weight in this component
|
|
1024
|
+
|
|
1025
|
+
None of these fields are read by `RolesPermission` — the roles list only renders
|
|
1026
|
+
`roleName`/`createdBy`/`created_at`/`roles_id`. They exist solely to be round-tripped unchanged
|
|
1027
|
+
through `onViewRole`/`onEditRole` so the consumer can prefill its own edit form. Setting them has no
|
|
1028
|
+
visible effect inside this component.
|
|
1029
|
+
|
|
1030
|
+
**Apply:** treat these fields as pass-through-only storage — populate them for your own edit form,
|
|
1031
|
+
not to change anything `RolesPermission` itself renders.
|
|
1032
|
+
|
|
1033
|
+
### `OrganizationDetails`' `OrganizationItem.uiInvite` is never read
|
|
1034
|
+
|
|
1035
|
+
Active vs. invited organizations are decided purely by which array (`activeOrganizations` vs
|
|
1036
|
+
`invitedOrganizations`) an item is placed in — `uiInvite` is carried on the type but
|
|
1037
|
+
`OrganizationDetails` never inspects it.
|
|
1038
|
+
|
|
1039
|
+
**Apply:** don't rely on `uiInvite` to control which section an item renders in — move the item
|
|
1040
|
+
between the two arrays instead.
|
|
1041
|
+
|
|
1042
|
+
### `OrganizationDetails`' `onSetDefault`/`onAcceptInvite`/`onDeclineInvite` are fire-and-forget despite their `Promise<void>` signature
|
|
1043
|
+
|
|
1044
|
+
Unlike `onCreateOrganization`/`onEditOrganization`/`onDeleteOrganization` (all awaited), these three
|
|
1045
|
+
are called without `await` — the `switchingOrgIds`/`respondingOrgIds` spinner arrays are entirely
|
|
1046
|
+
consumer-managed state, not driven by this component resolving the promise.
|
|
1047
|
+
|
|
1048
|
+
**Apply:** don't assume symmetry with the awaited callbacks in the same props interface; manage your
|
|
1049
|
+
own loading state for these three around the promise you return.
|
|
1050
|
+
|
|
1051
|
+
### `OrganizationDetails`' `CreateOrgFormValues.default`/`defaultOrg` are dead fields
|
|
1052
|
+
|
|
1053
|
+
The built-in `CreateOrgModal`'s internal state and submit handler never set or forward them, and the
|
|
1054
|
+
public `onCreateOrganization` callback's parameter type doesn't declare them at all — populating
|
|
1055
|
+
them in a custom create form has no effect on the built-in flow.
|
|
1056
|
+
|
|
1057
|
+
**Apply:** don't rely on these two fields to pre-mark a newly created org as default.
|
|
1058
|
+
|
|
1059
|
+
### `SideBar`'s `selectedSubMenu` prop is accepted but never read
|
|
1060
|
+
|
|
1061
|
+
`SidebarProps.selectedSubMenu` is threaded through `SideBar` → `MenuItems` → `MenuItemBox`, but the
|
|
1062
|
+
component's destructure never includes it — passing it has no effect of any kind.
|
|
1063
|
+
|
|
1064
|
+
**Apply:** don't pass `selectedSubMenu` expecting it to highlight a submenu row.
|
|
1065
|
+
|
|
1066
|
+
### `SideBar`'s `locked` menu-item flag doesn't lock anything
|
|
1067
|
+
|
|
1068
|
+
`MenuProps.locked` only swaps the trailing badge/chevron for a lock icon. The click handler checks
|
|
1069
|
+
only `disabled` — a `locked: true, disabled: false` item still fully navigates/expands.
|
|
1070
|
+
|
|
1071
|
+
**Apply:** set `disabled: true` alongside `locked: true` to actually prevent interaction.
|
|
1072
|
+
|
|
1073
|
+
### `KanbanBoard`'s `kanbanSelect` ignores `permissions`, unlike `kanbanEdit`/`kanbanCreate`
|
|
1074
|
+
|
|
1075
|
+
`kanbanEdit`/`kanbanCreate` are only forwarded when `permissions.isEditable`/`isCreatable` allow it;
|
|
1076
|
+
`kanbanSelect` is passed through unconditionally regardless of `permissions`. `onOpen` similarly has
|
|
1077
|
+
no permission gate at all, asymmetric with the gated `onDelete`.
|
|
1078
|
+
|
|
1079
|
+
**Apply:** gate `kanbanSelect.isSelect` (and any `onOpen` affordance) yourself if they should also be
|
|
1080
|
+
permission-locked.
|
|
1081
|
+
|
|
1082
|
+
### `KanbanBoard`'s `permissions.isViewable: false` hides everything, including header actions
|
|
1083
|
+
|
|
1084
|
+
Not just the columns — the select/edit/create header bar disappears too, since the whole component
|
|
1085
|
+
returns `null` before rendering anything.
|
|
1086
|
+
|
|
1087
|
+
**Apply:** there's no prop for hiding only the board body while keeping header actions visible.
|