@persona/design-system 0.10.9 → 0.10.11
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/CHANGELOG.md +43 -0
- package/dist/{Action-CHWYwpYR.d.mts → Action-sLO73eKq.d.mts} +2 -2
- package/dist/Action.d.mts +1 -1
- package/dist/AdvancedFilterRuleRow.d.mts +2 -2
- package/dist/AdvancedFilterRulesPopover.d.mts +2 -2
- package/dist/ArrayValueControl.d.mts +1 -1
- package/dist/Attribute.d.mts +2 -2
- package/dist/{Badge-BCdsVKuj.mjs → Badge-DZq6ByIU.mjs} +2 -2
- package/dist/{Badge-BCdsVKuj.mjs.map → Badge-DZq6ByIU.mjs.map} +1 -1
- package/dist/BooleanValueControl.d.mts +1 -1
- package/dist/{Breadcrumbs-CMf3Uvow.mjs → Breadcrumbs-DpsNZWF9.mjs} +9 -9
- package/dist/Breadcrumbs-DpsNZWF9.mjs.map +1 -0
- package/dist/{Button-DjD8QxcY.d.mts → Button-C4a4BTjL.d.mts} +2 -2
- package/dist/Button.d.mts +1 -1
- package/dist/CalendarBase.d.mts +1 -1
- package/dist/{Card-DiUHtYg_.d.mts → Card-CPV4_mHk.d.mts} +4 -4
- package/dist/Card.d.mts +1 -1
- package/dist/Card2.d.mts +1 -1
- package/dist/CardGrouping.d.mts +1 -1
- package/dist/{CardV2-ACI5RIzF.mjs → CardV2-DCoDfEvr.mjs} +26 -13
- package/dist/CardV2-DCoDfEvr.mjs.map +1 -0
- package/dist/ChartFrame.d.mts +61 -0
- package/dist/ChartLegend.d.mts +60 -0
- package/dist/ChartPopover.d.mts +155 -0
- package/dist/{Checkbox-Dr4LMKHV.mjs → Checkbox-C3z7UUSC.mjs} +8 -8
- package/dist/Checkbox-C3z7UUSC.mjs.map +1 -0
- package/dist/{CheckboxGroupField-DnVqlpwi.d.mts → CheckboxGroupField-BT87OVOF.d.mts} +2 -2
- package/dist/CheckboxGroupField.d.mts +1 -1
- package/dist/ChoicesValueControl.d.mts +1 -1
- package/dist/{Combobox-Gb_j1dg6.mjs → Combobox-BkK_tosd.mjs} +300 -116
- package/dist/Combobox-BkK_tosd.mjs.map +1 -0
- package/dist/Combobox-aOJDTjzC.d.mts +12 -0
- package/dist/Combobox.d.mts +3 -3
- package/dist/{ComboboxBase-Mb8HyeAI.d.mts → ComboboxBase-Brgv5nxk.d.mts} +65 -25
- package/dist/ComboboxBase.d.mts +2 -2
- package/dist/{ComboboxMultiSelect-C87lkXr7.d.mts → ComboboxMultiSelect-DJyAv0Eg.d.mts} +10 -6
- package/dist/ComboboxMultiSelect.d.mts +2 -2
- package/dist/{ComboboxSingleSelect-CIYakRW5.d.mts → ComboboxSingleSelect-CP8-HLKl.d.mts} +8 -6
- package/dist/ComboboxSingleSelect.d.mts +2 -2
- package/dist/{CompactBar-BLZZWtIE.d.mts → CompactBar-B0LhjrYV.d.mts} +2 -2
- package/dist/CompactBar.d.mts +1 -1
- package/dist/{ConfigFormGroup-BCTWCws5.mjs → ConfigFormGroup-DAUqAhJW.mjs} +2 -2
- package/dist/{ConfigFormGroup-BCTWCws5.mjs.map → ConfigFormGroup-DAUqAhJW.mjs.map} +1 -1
- package/dist/{DataTable-Bf1WDY0z.d.mts → DataTable-CSl5Jn3E.d.mts} +18 -8
- package/dist/{DataTable-CIZJ1vO8.mjs → DataTable-DiwzhNMt.mjs} +41 -28
- package/dist/DataTable-DiwzhNMt.mjs.map +1 -0
- package/dist/DataTable.d.mts +1 -1
- package/dist/{DatePicker-C9redLBr.mjs → DatePicker-BK7ioKBm.mjs} +410 -410
- package/dist/DatePicker-BK7ioKBm.mjs.map +1 -0
- package/dist/DateRangeValueControl.d.mts +1 -1
- package/dist/DateValueControl.d.mts +1 -1
- package/dist/{DropdownButton-DpLG-cIj.mjs → DropdownButton-Dp-MZ5tA.mjs} +3 -3
- package/dist/{DropdownButton-DpLG-cIj.mjs.map → DropdownButton-Dp-MZ5tA.mjs.map} +1 -1
- package/dist/DropdownButton.d.mts +2 -2
- package/dist/{DropdownMenu-DVxXQDRC.d.mts → DropdownMenu-BnHPeHOm.d.mts} +3 -3
- package/dist/{DropdownMenu-c8XK2Lr4.mjs → DropdownMenu-jJSHQaih.mjs} +4 -2
- package/dist/DropdownMenu-jJSHQaih.mjs.map +1 -0
- package/dist/DropdownMenu.d.mts +1 -1
- package/dist/{FieldRegistry-C2NVPhMO.d.mts → FieldRegistry-CJwGpUVK.d.mts} +2 -2
- package/dist/FieldRegistry.d.mts +1 -1
- package/dist/{FilterBar-BE_gBM0H.d.mts → FilterBar-DDyk14sx.d.mts} +4 -4
- package/dist/FilterBar.d.mts +1 -1
- package/dist/FilterPickerMenu.d.mts +2 -2
- package/dist/FilterPill.d.mts +1 -1
- package/dist/FilterPopover.d.mts +1 -1
- package/dist/FloatValueControl.d.mts +3 -2
- package/dist/{FloatingToolbar-DLRaE0o7.mjs → FloatingToolbar-rfKurDs8.mjs} +36 -39
- package/dist/FloatingToolbar-rfKurDs8.mjs.map +1 -0
- package/dist/{FormControl-BztNXLn6.mjs → FormControl--pbTH3bY.mjs} +3 -3
- package/dist/{FormControl-BztNXLn6.mjs.map → FormControl--pbTH3bY.mjs.map} +1 -1
- package/dist/{FormControl-BQe3GRhi.d.mts → FormControl-DPYbLcBK.d.mts} +2 -2
- package/dist/FormControl.d.mts +1 -1
- package/dist/FormControlLabel.d.mts +2 -2
- package/dist/{FormField-BW5uMzId.d.mts → FormField-CYNGm2bJ.d.mts} +2 -2
- package/dist/{FormField-Cf1VMvoa.mjs → FormField-DMxjftFw.mjs} +14 -14
- package/dist/{FormField-Cf1VMvoa.mjs.map → FormField-DMxjftFw.mjs.map} +1 -1
- package/dist/FormField.d.mts +1 -1
- package/dist/{Grid-CYpOqTUu.mjs → Grid-DVC0SSEZ.mjs} +2 -2
- package/dist/{Grid-CYpOqTUu.mjs.map → Grid-DVC0SSEZ.mjs.map} +1 -1
- package/dist/{Header-CV0Lcf0C.d.mts → Header-DaaUprCL.d.mts} +2 -2
- package/dist/Header.d.mts +1 -1
- package/dist/{HelperTooltip-BNM3pTM-.d.mts → HelperTooltip-C5BDdJSI.d.mts} +2 -2
- package/dist/HelperTooltip.d.mts +1 -1
- package/dist/HighlightedText.d.mts +1 -1
- package/dist/{HoverCopyableField-XHC_n9tp.mjs → HoverCopyableField-B2-xlwUt.mjs} +12 -7
- package/dist/HoverCopyableField-B2-xlwUt.mjs.map +1 -0
- package/dist/{IconButton-C_ReZm8v.d.mts → IconButton-7k-wjvH3.d.mts} +2 -2
- package/dist/{IconButton-DxHB2g80.mjs → IconButton-kSjnfhWt.mjs} +11 -10
- package/dist/IconButton-kSjnfhWt.mjs.map +1 -0
- package/dist/IconButton.d.mts +1 -1
- package/dist/ImageTile.d.mts +1 -1
- package/dist/IndexTableLayout.d.mts +4 -4
- package/dist/InlineCombobox.d.mts +1 -1
- package/dist/InlineInput.d.mts +1 -1
- package/dist/{Input-DH-5dKor.d.mts → Input-CwvrBsiS.d.mts} +3 -3
- package/dist/{Input-RHXujO9u.mjs → Input-TRmTBEav.mjs} +5 -5
- package/dist/{Input-RHXujO9u.mjs.map → Input-TRmTBEav.mjs.map} +1 -1
- package/dist/Input.d.mts +1 -1
- package/dist/IntegerValueControl.d.mts +3 -2
- package/dist/{Link-D_kCyLYX.mjs → Link-XvzUN8sY.mjs} +6 -6
- package/dist/Link-XvzUN8sY.mjs.map +1 -0
- package/dist/{ListBox-DxOACf6N.d.mts → ListBox-BePQBYR7.d.mts} +3 -3
- package/dist/{ListBox-BZp6exb8.mjs → ListBox-DahM1PgU.mjs} +12 -12
- package/dist/{ListBox-BZp6exb8.mjs.map → ListBox-DahM1PgU.mjs.map} +1 -1
- package/dist/ListBox.d.mts +1 -1
- package/dist/{ListBoxField-CgnDuhUw.d.mts → ListBoxField-lj7JN1BX.d.mts} +4 -4
- package/dist/ListBoxField.d.mts +1 -1
- package/dist/{LoadingShimmer-oPIv2ESr.mjs → LoadingShimmer-CpfKTSUs.mjs} +4 -3
- package/dist/LoadingShimmer-CpfKTSUs.mjs.map +1 -0
- package/dist/LoadingShimmer.d.mts +1 -1
- package/dist/{LogicRow-Dv_1G1TC.d.mts → LogicRow-Do7t7Suf.d.mts} +2 -2
- package/dist/LogicRow.d.mts +1 -1
- package/dist/MaskedInput.d.mts +2 -2
- package/dist/MatchHighlight.d.mts +1 -1
- package/dist/{Menu-BVn1jh46.mjs → Menu-BvMzSH2I.mjs} +5 -5
- package/dist/{Menu-BVn1jh46.mjs.map → Menu-BvMzSH2I.mjs.map} +1 -1
- package/dist/{Menu-BfjvH8mr.d.mts → Menu-Ca5ftvo6.d.mts} +4 -4
- package/dist/Menu.d.mts +1 -1
- package/dist/{MiddleTruncatedText-DicQsLDG.mjs → MiddleTruncatedText--jzGTD00.mjs} +2 -2
- package/dist/{MiddleTruncatedText-DicQsLDG.mjs.map → MiddleTruncatedText--jzGTD00.mjs.map} +1 -1
- package/dist/{Modal-De5_bPJ_.mjs → Modal-B6X5AgWj.mjs} +54 -25
- package/dist/{Modal-De5_bPJ_.mjs.map → Modal-B6X5AgWj.mjs.map} +1 -1
- package/dist/{Modal-CujB7DuB.d.mts → Modal-BPfFyzkw.d.mts} +3 -3
- package/dist/Modal.d.mts +1 -1
- package/dist/{PageHeader-UPiqJpIF.d.mts → PageHeader-BeBmYmUX.d.mts} +2 -2
- package/dist/{PageHeader-7_Hf6rHl.mjs → PageHeader-bhQTjuZF.mjs} +2 -2
- package/dist/{PageHeader-7_Hf6rHl.mjs.map → PageHeader-bhQTjuZF.mjs.map} +1 -1
- package/dist/PageHeader.d.mts +1 -1
- package/dist/{PageLayout-BdVM37bV.d.mts → PageLayout-BXM_pyrU.d.mts} +2 -2
- package/dist/{PageLayout-DjtGrvJa.mjs → PageLayout-DgEGcZgB.mjs} +3 -3
- package/dist/{PageLayout-DjtGrvJa.mjs.map → PageLayout-DgEGcZgB.mjs.map} +1 -1
- package/dist/PageLayout.d.mts +1 -1
- package/dist/{PageSelector-B5CcAzss.d.mts → PageSelector-C14ABZVL.d.mts} +2 -2
- package/dist/PageSelector.d.mts +1 -1
- package/dist/{Pagination-DMH2IaV0.mjs → Pagination-DE8wT55m.mjs} +5 -5
- package/dist/{Pagination-DMH2IaV0.mjs.map → Pagination-DE8wT55m.mjs.map} +1 -1
- package/dist/{Pii-24D_nSRQ.mjs → Pii-C42ZY88Y.mjs} +2 -2
- package/dist/{Pii-24D_nSRQ.mjs.map → Pii-C42ZY88Y.mjs.map} +1 -1
- package/dist/{PillShell-B7Bm-dsE.d.mts → PillShell-Bkyu5FXB.d.mts} +2 -2
- package/dist/PillShell.d.mts +1 -1
- package/dist/{Popover-DordjYNM.mjs → Popover-DuFjaSoq.mjs} +4 -2
- package/dist/Popover-DuFjaSoq.mjs.map +1 -0
- package/dist/Popover.d.mts +1 -1
- package/dist/ProgressBar.d.mts +1 -1
- package/dist/{ProgressIndicator-zt3ndT9U.mjs → ProgressIndicator-hy1P-RG1.mjs} +3 -3
- package/dist/{ProgressIndicator-zt3ndT9U.mjs.map → ProgressIndicator-hy1P-RG1.mjs.map} +1 -1
- package/dist/{Radio-BlEtetrr.mjs → Radio-B4TBAho6.mjs} +5 -5
- package/dist/Radio-B4TBAho6.mjs.map +1 -0
- package/dist/{RadioGroup-CMrXmmn4.mjs → RadioGroup-Bf24GKOb.mjs} +3 -3
- package/dist/{RadioGroup-CMrXmmn4.mjs.map → RadioGroup-Bf24GKOb.mjs.map} +1 -1
- package/dist/RichTextEditor.d.mts +1 -1
- package/dist/RuleEditorFields.d.mts +2 -2
- package/dist/RulesPill.d.mts +1 -1
- package/dist/SectionHeading.d.mts +1 -1
- package/dist/{SegmentedControl-D_DA-MU1.mjs → SegmentedControl-BpR7sUWO.mjs} +6 -3
- package/dist/SegmentedControl-BpR7sUWO.mjs.map +1 -0
- package/dist/{Select-CaG6OQi1.d.mts → Select-DYdn73Nh.d.mts} +2 -2
- package/dist/{Select-DOlw_LPR.mjs → Select-RdTT2KoH.mjs} +10 -8
- package/dist/Select-RdTT2KoH.mjs.map +1 -0
- package/dist/Select.d.mts +1 -1
- package/dist/SmartTextInput.d.mts +1 -1
- package/dist/SmartTextInputField.d.mts +2 -2
- package/dist/SmartTextInputFunctionDialog.d.mts +1 -1
- package/dist/SmartTextInputPopover.d.mts +1 -1
- package/dist/{Spinner-CXb-KUs1.mjs → Spinner-vcApnJzv.mjs} +2 -2
- package/dist/{Spinner-CXb-KUs1.mjs.map → Spinner-vcApnJzv.mjs.map} +1 -1
- package/dist/{Stack-CODxfzhl.d.mts → Stack-B6MrjJeW.d.mts} +2 -2
- package/dist/Stack.d.mts +1 -1
- package/dist/{StatusIndicator-CzRaEFSz.mjs → StatusIndicator-lwt35J6B.mjs} +3 -3
- package/dist/{StatusIndicator-CzRaEFSz.mjs.map → StatusIndicator-lwt35J6B.mjs.map} +1 -1
- package/dist/{Sticker-CLvRB8V5.d.mts → Sticker-C7Wv3Obx.d.mts} +4 -4
- package/dist/{Sticker-C1_6I08u.mjs → Sticker-jfOM4Yi6.mjs} +5 -5
- package/dist/{Sticker-C1_6I08u.mjs.map → Sticker-jfOM4Yi6.mjs.map} +1 -1
- package/dist/Sticker.d.mts +1 -1
- package/dist/StringValueControl.d.mts +2 -1
- package/dist/Tab.d.mts +2 -2
- package/dist/{TabBar-BCFO38E0.mjs → TabBar-DwHgbIQ6.mjs} +8 -8
- package/dist/TabBar-DwHgbIQ6.mjs.map +1 -0
- package/dist/{Table-DPi4Dt5H.mjs → Table-SMJAWqoe.mjs} +21 -13
- package/dist/Table-SMJAWqoe.mjs.map +1 -0
- package/dist/{TableBox-DNQsgQ8x.mjs → TableBox-DS8mpN3-.mjs} +21 -17
- package/dist/TableBox-DS8mpN3-.mjs.map +1 -0
- package/dist/TableBox.d.mts +1 -1
- package/dist/{TableBoxCell-B9KMWebc.d.mts → TableBoxCell-Bo5xYEmR.d.mts} +6 -6
- package/dist/TableBoxCell.d.mts +1 -1
- package/dist/{TableBoxField-0uIGzBhF.d.mts → TableBoxField-CdgjSGLK.d.mts} +5 -5
- package/dist/TableBoxField.d.mts +1 -1
- package/dist/{TableBoxRow-PjBBDcEk.d.mts → TableBoxRow-DuWS2iRC.d.mts} +2 -2
- package/dist/TableBoxRow.d.mts +1 -1
- package/dist/{TableBoxRowActions-B7stm6Q3.d.mts → TableBoxRowActions-zW74DkXt.d.mts} +2 -2
- package/dist/TableBoxRowActions.d.mts +1 -1
- package/dist/{TableCell-CQsF7t4e.d.mts → TableCell-uv_jqT5e.d.mts} +2 -2
- package/dist/TableCell.d.mts +1 -1
- package/dist/{TableControls-ODHrCDJM.d.mts → TableControls-9vz-HfDu.d.mts} +4 -4
- package/dist/{TableControls-BrP_BqnF.mjs → TableControls-CX7BvgD2.mjs} +107 -43
- package/dist/TableControls-CX7BvgD2.mjs.map +1 -0
- package/dist/TableControls.d.mts +1 -1
- package/dist/{TableControlsContext-CHuLxfa7.d.mts → TableControlsContext-D0Hn3rwL.d.mts} +2 -2
- package/dist/TableControlsContext.d.mts +1 -1
- package/dist/{TableViewConfigurationDropdown-BWBBUXCs.d.mts → TableViewConfigurationDropdown-CZcLH8uR.d.mts} +2 -2
- package/dist/TableViewConfigurationDropdown.d.mts +1 -1
- package/dist/{TechnicalSticker-Cq5jzYKQ.mjs → TechnicalSticker-DrN45Vut.mjs} +9 -7
- package/dist/TechnicalSticker-DrN45Vut.mjs.map +1 -0
- package/dist/{Text-CvaqognH.d.mts → Text-CdHeSHCc.d.mts} +2 -2
- package/dist/Text.d.mts +1 -1
- package/dist/{TextArea-Dro-HH8O.mjs → TextArea-CQ1YNi2b.mjs} +4 -5
- package/dist/TextArea-CQ1YNi2b.mjs.map +1 -0
- package/dist/{TextUnderlineTooltip-Bd5e8KH3.d.mts → TextUnderlineTooltip-By1VVsSs.d.mts} +3 -3
- package/dist/TextUnderlineTooltip.d.mts +1 -1
- package/dist/Tile.d.mts +1 -1
- package/dist/{Toggle-D9MzTIZs.mjs → Toggle-DjmkjJlw.mjs} +13 -9
- package/dist/Toggle-DjmkjJlw.mjs.map +1 -0
- package/dist/{Tooltip-YViXzMdm.mjs → Tooltip-C2VB8I6y.mjs} +18 -5
- package/dist/Tooltip-C2VB8I6y.mjs.map +1 -0
- package/dist/{Tooltip-Ddy2Jq0K.d.mts → Tooltip-OxVvOfn8.d.mts} +3 -3
- package/dist/Tooltip.d.mts +1 -1
- package/dist/{TruncatedText-sr9Fhm3N.d.mts → TruncatedText-Dqj94BFK.d.mts} +2 -2
- package/dist/WizardModal.d.mts +1 -1
- package/dist/chartColors.d.mts +92 -0
- package/dist/chartFrameLayout.d.mts +46 -0
- package/dist/{clientFilterUtils-scLlIuP_.d.mts → clientFilterUtils-CMLuN8kK.d.mts} +2 -2
- package/dist/clientFilterUtils.d.mts +1 -1
- package/dist/components/Accordion/index.mjs +25 -16
- package/dist/components/Accordion/index.mjs.map +1 -1
- package/dist/components/Attribute/index.mjs +8 -6
- package/dist/components/Attribute/index.mjs.map +1 -1
- package/dist/components/Badge/index.mjs +1 -1
- package/dist/components/Banner/index.mjs +3 -3
- package/dist/components/BottomPanel/index.mjs +10 -8
- package/dist/components/BottomPanel/index.mjs.map +1 -1
- package/dist/components/Breadcrumbs/index.mjs +1 -1
- package/dist/components/Button/index.d.mts +2 -2
- package/dist/components/Button/index.mjs +1 -1
- package/dist/components/ButtonGroup/index.mjs +2 -2
- package/dist/components/Card/index.d.mts +2 -2
- package/dist/components/CardV2/index.d.mts +1 -1
- package/dist/components/CardV2/index.mjs +1 -1
- package/dist/components/Chart/index.d.mts +9 -0
- package/dist/components/Chart/index.mjs +680 -0
- package/dist/components/Chart/index.mjs.map +1 -0
- package/dist/components/Checkbox/index.mjs +1 -1
- package/dist/components/CodeHighlight/index.mjs +4 -4
- package/dist/components/Combobox/index.d.mts +5 -3
- package/dist/components/Combobox/index.mjs +1 -1
- package/dist/components/ConfigFormGroup/index.mjs +1 -1
- package/dist/components/DataTable/TableControls/index.d.mts +20 -20
- package/dist/components/DataTable/TableControls/index.mjs +2 -2
- package/dist/components/DataTable/index.d.mts +5 -5
- package/dist/components/DataTable/index.mjs +1 -1
- package/dist/components/DataTable/types.d.mts +1 -1
- package/dist/components/DatePicker/index.mjs +1 -1
- package/dist/components/DropdownButton/index.mjs +1 -1
- package/dist/components/DropdownMenu/index.d.mts +1 -1
- package/dist/components/DropdownMenu/index.mjs +1 -1
- package/dist/components/FloatingPanel/index.mjs +20 -18
- package/dist/components/FloatingPanel/index.mjs.map +1 -1
- package/dist/components/FloatingToolbar/index.mjs +1 -1
- package/dist/components/FormControl/index.d.mts +1 -1
- package/dist/components/FormControl/index.mjs +1 -1
- package/dist/components/FormField/index.d.mts +5 -5
- package/dist/components/FormField/index.mjs +1 -1
- package/dist/components/Grid/index.mjs +1 -1
- package/dist/components/HoverCopyableField/index.mjs +1 -1
- package/dist/components/ImageTile/index.mjs +10 -10
- package/dist/components/ImageTile/index.mjs.map +1 -1
- package/dist/components/Input/index.d.mts +1 -1
- package/dist/components/Input/index.mjs +1 -1
- package/dist/components/Link/index.mjs +1 -1
- package/dist/components/ListBox/index.d.mts +3 -3
- package/dist/components/ListBox/index.mjs +1 -1
- package/dist/components/LoadingShimmer/index.mjs +1 -1
- package/dist/components/MaskedInput/index.mjs +1 -1
- package/dist/components/Menu/index.d.mts +1 -1
- package/dist/components/Menu/index.mjs +1 -1
- package/dist/components/Modal/index.d.mts +1 -1
- package/dist/components/Modal/index.mjs +1 -1
- package/dist/components/PageHeader/index.d.mts +1 -1
- package/dist/components/PageHeader/index.mjs +1 -1
- package/dist/components/Pagination/index.d.mts +1 -1
- package/dist/components/Pagination/index.mjs +1 -1
- package/dist/components/Pii/index.mjs +1 -1
- package/dist/components/Popover/index.mjs +1 -1
- package/dist/components/ProgressBar/index.mjs +20 -3
- package/dist/components/ProgressBar/index.mjs.map +1 -1
- package/dist/components/ProgressIndicator/index.mjs +1 -1
- package/dist/components/Radio/index.mjs +1 -1
- package/dist/components/RadioGroup/index.mjs +1 -1
- package/dist/components/RichTextEditor/index.mjs +9 -9
- package/dist/components/RightPanel/index.mjs +30 -15
- package/dist/components/RightPanel/index.mjs.map +1 -1
- package/dist/components/SegmentedControl/index.mjs +1 -1
- package/dist/components/Select/index.d.mts +1 -1
- package/dist/components/Select/index.mjs +1 -1
- package/dist/components/SelectionCard/index.mjs +5 -5
- package/dist/components/Slider/index.mjs +5 -4
- package/dist/components/Slider/index.mjs.map +1 -1
- package/dist/components/SmartTextInput/index.mjs +11 -18
- package/dist/components/SmartTextInput/index.mjs.map +1 -1
- package/dist/components/Spinner/index.mjs +1 -1
- package/dist/components/Stack/index.d.mts +1 -1
- package/dist/components/StatusIndicator/index.mjs +1 -1
- package/dist/components/Sticker/index.d.mts +1 -1
- package/dist/components/Sticker/index.mjs +1 -1
- package/dist/components/SwatchPicker/index.mjs +2 -1
- package/dist/components/SwatchPicker/index.mjs.map +1 -1
- package/dist/components/TabBar/index.mjs +1 -1
- package/dist/components/Table/index.d.mts +1 -1
- package/dist/components/Table/index.mjs +1 -1
- package/dist/components/TableBox/index.d.mts +1 -1
- package/dist/components/TableBox/index.mjs +1 -1
- package/dist/components/TechnicalSticker/index.mjs +1 -1
- package/dist/components/Text/index.d.mts +1 -1
- package/dist/components/TextArea/index.mjs +1 -1
- package/dist/components/Tile/index.mjs +2 -2
- package/dist/components/Toast/index.mjs +19 -13
- package/dist/components/Toast/index.mjs.map +1 -1
- package/dist/components/Toggle/index.mjs +1 -1
- package/dist/components/Tooltip/index.d.mts +3 -3
- package/dist/components/Tooltip/index.mjs +1 -1
- package/dist/components/VersionHistory/index.mjs +8 -8
- package/dist/compound-expression.d.mts +1 -1
- package/dist/{date-range-rule-value-ASr06ClE.d.mts → date-range-rule-value-DyLlMtjr.d.mts} +2 -2
- package/dist/date-range-rule-value.d.mts +1 -1
- package/dist/display.d.mts +1 -1
- package/dist/duration-token.d.mts +11 -0
- package/dist/exit-motion.d.mts +7 -0
- package/dist/fieldPickerOptions.d.mts +2 -2
- package/dist/{filter-size-context-CmFyIPCm.d.mts → filter-size-context-DVnjmuhk.d.mts} +2 -2
- package/dist/filter-size-context.d.mts +1 -1
- package/dist/{filters-yfzOlqKx.d.mts → filters-By_TYKAZ.d.mts} +3 -3
- package/dist/filters.d.mts +1 -1
- package/dist/{helpers-BeCjgAeE.d.mts → helpers-BIHsqdyX.d.mts} +2 -2
- package/dist/helpers.d.mts +1 -1
- package/dist/{index-kIon1vPp.d.mts → index-BozzRwby.d.mts} +2 -2
- package/dist/{index-BEHNqAZa.d.mts → index-CZJp4Af6.d.mts} +3 -3
- package/dist/index2.d.mts +1 -1
- package/dist/index4.d.mts +3 -3
- package/dist/index5.d.mts +1 -1
- package/dist/index6.d.mts +14 -14
- package/dist/{inputFields-BnCdmuBt.d.mts → inputFields-BqO2H-Kj.d.mts} +6 -6
- package/dist/inputFields.d.mts +1 -1
- package/dist/lib/MiddleTruncatedText.mjs +1 -1
- package/dist/lib/TruncatedText.d.mts +1 -1
- package/dist/lib/TruncatedTextWithTooltip.d.mts +1 -1
- package/dist/lib/TruncatedTextWithTooltip.mjs +1 -1
- package/dist/lib/colorMode.d.mts +1 -1
- package/dist/lib/schemaOptions.mjs +9 -4
- package/dist/lib/schemaOptions.mjs.map +1 -1
- package/dist/lib/useChain.d.mts +1 -1
- package/dist/lib/useModalInsetRight.d.mts +4 -3
- package/dist/lib/useModalInsetRight.mjs +7 -5
- package/dist/lib/useModalInsetRight.mjs.map +1 -1
- package/dist/lint/THIRD_PARTY_NOTICES.md +30 -0
- package/dist/lint/index.mjs +696 -11
- package/dist/lint/index.mjs.map +1 -1
- package/dist/lint/recommended.json +7 -1
- package/dist/mixins/focus.mjs +1 -1
- package/dist/mixins/hoverable.mjs +2 -2
- package/dist/mixins/hoverable.mjs.map +1 -1
- package/dist/mixins/input.mjs +3 -2
- package/dist/mixins/input.mjs.map +1 -1
- package/dist/mixins/menuItem.mjs +2 -0
- package/dist/mixins/menuItem.mjs.map +1 -1
- package/dist/mixins/motion.d.mts +24 -0
- package/dist/mixins/motion.mjs +44 -0
- package/dist/mixins/motion.mjs.map +1 -0
- package/dist/motion-origin.d.mts +7 -0
- package/dist/motion.d.mts +63 -0
- package/dist/no-layout-motion.d.mts +7 -0
- package/dist/no-transition-all.d.mts +7 -0
- package/dist/{operators-BHxKZcpD.d.mts → operators-B8_k3r69.d.mts} +10 -3
- package/dist/operators.d.mts +2 -2
- package/dist/overlay-motion.d.mts +7 -0
- package/dist/patterns/CardGrouping/index.mjs +9 -9
- package/dist/patterns/CardGrouping/index.mjs.map +1 -1
- package/dist/patterns/IndexTableLayout/index.mjs +3 -3
- package/dist/patterns/LayoutLoadingShimmer/index.mjs +4 -4
- package/dist/patterns/LayoutLoadingSpinner/index.mjs +3 -1
- package/dist/patterns/LayoutLoadingSpinner/index.mjs.map +1 -1
- package/dist/patterns/PageLayout/index.d.mts +1 -1
- package/dist/patterns/PageLayout/index.mjs +1 -1
- package/dist/patterns/WizardModal/index.mjs +4 -4
- package/dist/relative-date-label.d.mts +1 -1
- package/dist/tone.d.mts +1 -1
- package/dist/{types-DLnCkvTt.d.mts → types-BJqmRXFV.d.mts} +15 -1
- package/dist/{types-CqcbWyUY.d.mts → types-BOsCi-kZ.d.mts} +8 -2
- package/dist/{types-BXJ6qAGy.d.mts → types-C_CncajO.d.mts} +2 -2
- package/dist/{types-BeFBvQ1c.d.mts → types-D5txFacG.d.mts} +3 -3
- package/dist/types4.d.mts +1 -1
- package/dist/types5.d.mts +1 -1
- package/dist/types6.d.mts +1 -1
- package/dist/{url-state-CXUuK3_r.d.mts → url-state-CXPmXzIZ.d.mts} +2 -2
- package/dist/url-state.d.mts +1 -1
- package/dist/{useChain-B--KAtdN.d.mts → useChain-x9fd9Fyq.d.mts} +2 -2
- package/dist/useChainAtCursor.d.mts +1 -1
- package/dist/useChartColors.d.mts +30 -0
- package/dist/useChartSeriesVisibility.d.mts +22 -0
- package/dist/useChartStyles.d.mts +108 -0
- package/dist/useColumnConfiguration.d.mts +2 -2
- package/dist/useComboboxFooterAction.d.mts +1 -1
- package/dist/{useFilterStateV2-DBpbxAEC.d.mts → useFilterStateV2-DiTS9DTg.d.mts} +3 -3
- package/dist/useFilterStateV2.d.mts +1 -1
- package/dist/{useTableColumns-DJFy0Gp8.d.mts → useTableColumns-BEKJNrb1.d.mts} +2 -2
- package/dist/useTableColumns.d.mts +1 -1
- package/dist/useTruncation.d.mts +1 -1
- package/dist/useValueControlError.d.mts +26 -0
- package/dist/utils.d.mts +1 -1
- package/dist/{validation-Tgg3AhuP.d.mts → validation-BDQdQ1cY.d.mts} +3 -3
- package/dist/validation.d.mts +1 -1
- package/dist/{value-control-resolver-XQbGCdsP.d.mts → value-control-resolver-BFJZEWDn.d.mts} +9 -3
- package/dist/value-control-resolver.d.mts +1 -1
- package/dist/variables/charting.mjs +1 -1
- package/dist/variables/charting.mjs.map +1 -1
- package/dist/variables/keyframes.d.mts +2 -1
- package/dist/variables/keyframes.mjs +9 -1
- package/dist/variables/keyframes.mjs.map +1 -1
- package/dist/variables/transitions.d.mts +31 -1
- package/dist/variables/transitions.mjs +50 -1
- package/dist/variables/transitions.mjs.map +1 -1
- package/llms.txt +3 -2
- package/package.json +14 -4
- package/skills/new-screen/SKILL.md +33 -0
- package/skills/ui-authoring/COMPONENTS.md +19 -1
- package/skills/ui-authoring/PATTERNS.md +57 -33
- package/skills/ui-authoring/STANDARD.md +68 -4
- package/skills/ui-authoring/TOKENS.md +27 -24
- package/dist/Breadcrumbs-CMf3Uvow.mjs.map +0 -1
- package/dist/CardV2-ACI5RIzF.mjs.map +0 -1
- package/dist/Checkbox-Dr4LMKHV.mjs.map +0 -1
- package/dist/Combobox-Gb_j1dg6.mjs.map +0 -1
- package/dist/Combobox-fYZjpn5-.d.mts +0 -11
- package/dist/DataTable-CIZJ1vO8.mjs.map +0 -1
- package/dist/DatePicker-C9redLBr.mjs.map +0 -1
- package/dist/DropdownMenu-c8XK2Lr4.mjs.map +0 -1
- package/dist/FloatingToolbar-DLRaE0o7.mjs.map +0 -1
- package/dist/HoverCopyableField-XHC_n9tp.mjs.map +0 -1
- package/dist/IconButton-DxHB2g80.mjs.map +0 -1
- package/dist/Link-D_kCyLYX.mjs.map +0 -1
- package/dist/LoadingShimmer-oPIv2ESr.mjs.map +0 -1
- package/dist/Popover-DordjYNM.mjs.map +0 -1
- package/dist/Radio-BlEtetrr.mjs.map +0 -1
- package/dist/SegmentedControl-D_DA-MU1.mjs.map +0 -1
- package/dist/Select-DOlw_LPR.mjs.map +0 -1
- package/dist/TabBar-BCFO38E0.mjs.map +0 -1
- package/dist/Table-DPi4Dt5H.mjs.map +0 -1
- package/dist/TableBox-DNQsgQ8x.mjs.map +0 -1
- package/dist/TableControls-BrP_BqnF.mjs.map +0 -1
- package/dist/TechnicalSticker-Cq5jzYKQ.mjs.map +0 -1
- package/dist/TextArea-Dro-HH8O.mjs.map +0 -1
- package/dist/Toggle-D9MzTIZs.mjs.map +0 -1
- package/dist/Tooltip-YViXzMdm.mjs.map +0 -1
package/dist/lint/index.mjs
CHANGED
|
@@ -103,7 +103,7 @@ const FONT_PROPERTIES = new Set([
|
|
|
103
103
|
"letter-spacing"
|
|
104
104
|
]);
|
|
105
105
|
const FONT_DECLARATION = /(?<![\w-])(?:font-size|font-weight|font-family|line-height|letter-spacing)\s*:/g;
|
|
106
|
-
const message$
|
|
106
|
+
const message$4 = (name) => `Individual font property \`${name}\`: use a complete \`Typography\` style.`;
|
|
107
107
|
const completeTypography = {
|
|
108
108
|
meta: {
|
|
109
109
|
type: "problem",
|
|
@@ -117,13 +117,500 @@ const completeTypography = {
|
|
|
117
117
|
const name = propertyName(property);
|
|
118
118
|
if (name !== null && FONT_PROPERTIES.has(name)) context.report({
|
|
119
119
|
node: property.key,
|
|
120
|
-
message: message$
|
|
120
|
+
message: message$4(name)
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
123
|
},
|
|
124
124
|
TaggedTemplateExpression(node) {
|
|
125
125
|
if (!isCssTemplate(node)) return;
|
|
126
|
-
for (const quasi of node.quasi.quasis) reportMatches(context, quasi, FONT_DECLARATION, (match) => message$
|
|
126
|
+
for (const quasi of node.quasi.quasis) reportMatches(context, quasi, FONT_DECLARATION, (match) => message$4(match[0].replace(/\s*:$/, "")));
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/lint/motion.ts
|
|
133
|
+
const cssTextCache = /* @__PURE__ */ new WeakMap();
|
|
134
|
+
function cssText(context, literal) {
|
|
135
|
+
const cached = cssTextCache.get(literal);
|
|
136
|
+
if (cached !== void 0) return cached;
|
|
137
|
+
const [start, end] = literal.range;
|
|
138
|
+
const source = context.sourceCode.text.slice(start, end);
|
|
139
|
+
const parts = [];
|
|
140
|
+
let at = 0;
|
|
141
|
+
for (const expression of literal.expressions) {
|
|
142
|
+
const from = source.lastIndexOf("${", expression.range[0] - start);
|
|
143
|
+
const to = source.indexOf("}", expression.range[1] - start) + 1;
|
|
144
|
+
parts.push(source.slice(at, from), "_".repeat(to - from));
|
|
145
|
+
at = to;
|
|
146
|
+
}
|
|
147
|
+
parts.push(source.slice(at));
|
|
148
|
+
const result = {
|
|
149
|
+
text: blankCssComments(parts.join("")),
|
|
150
|
+
start
|
|
151
|
+
};
|
|
152
|
+
cssTextCache.set(literal, result);
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
/** A block that still styles the element itself: `&[data-entering]`, `&.open`, `&:hover`, `@media`. */
|
|
156
|
+
const OWN_BLOCK = /^\s*(?:&(?![\s>+~_,])|@media\b|@supports\b)/;
|
|
157
|
+
/**
|
|
158
|
+
* The element's own declarations, its states and media queries included, with the blocks for its
|
|
159
|
+
* children (`& li:hover`, `${Item}`) and `@keyframes` blanked. Offsets stay the same.
|
|
160
|
+
*/
|
|
161
|
+
function ownDeclarations(text) {
|
|
162
|
+
const kept = [];
|
|
163
|
+
let out = "";
|
|
164
|
+
let selectorStart = 0;
|
|
165
|
+
for (let i = 0; i < text.length; i++) {
|
|
166
|
+
const c = text[i];
|
|
167
|
+
const keeping = kept.every(Boolean);
|
|
168
|
+
if (c === "{") {
|
|
169
|
+
const selector = text.slice(selectorStart, i).split(/[;{}]/).at(-1) ?? "";
|
|
170
|
+
kept.push(keeping && OWN_BLOCK.test(selector));
|
|
171
|
+
if (!kept.at(-1) && keeping) out = out.slice(0, out.length - selector.length) + selector.replace(/[^\n]/g, " ");
|
|
172
|
+
out += " ";
|
|
173
|
+
selectorStart = i + 1;
|
|
174
|
+
} else if (c === "}") {
|
|
175
|
+
kept.pop();
|
|
176
|
+
out += " ";
|
|
177
|
+
selectorStart = i + 1;
|
|
178
|
+
} else {
|
|
179
|
+
if (c === ";") selectorStart = i + 1;
|
|
180
|
+
out += keeping || c === "\n" ? c : " ";
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return out;
|
|
184
|
+
}
|
|
185
|
+
/** An interpolated mixin whose name says it carries motion: `${overlayMotion}`, `${fadeInMixin}`. */
|
|
186
|
+
const MOTION_MIXIN = /motion|transition|animat|fade|slide|zoom|reveal/i;
|
|
187
|
+
/**
|
|
188
|
+
* True when the template's own text, a nested template in it (`${(p) => p.$open && css`…`}`) or a
|
|
189
|
+
* motion-named mixin it interpolates has a transition or animation.
|
|
190
|
+
*/
|
|
191
|
+
function hasMotion(context, css) {
|
|
192
|
+
const [start, end] = css.node.quasi.range;
|
|
193
|
+
if (/(?<![\w-])(?:transition|animation)(?:-[a-z]+)?\s*:/.test(blankCssComments(context.sourceCode.text.slice(start, end)))) return true;
|
|
194
|
+
return css.node.quasi.expressions.some((expression) => {
|
|
195
|
+
const name = expression.type === "SpreadElement" ? null : lastName(expression);
|
|
196
|
+
return name !== null && MOTION_MIXIN.test(name);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function cssTemplate(context, node) {
|
|
200
|
+
if (!isCssTemplate(node)) return null;
|
|
201
|
+
const { parent } = node;
|
|
202
|
+
const declared = parent.type === "VariableDeclarator" && parent.init === node && parent.id.type === "Identifier" ? parent.id : null;
|
|
203
|
+
return {
|
|
204
|
+
...cssText(context, node.quasi),
|
|
205
|
+
node,
|
|
206
|
+
name: declared?.name ?? null,
|
|
207
|
+
nameNode: declared
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function reportAt(context, index, length, message) {
|
|
211
|
+
const { sourceCode } = context;
|
|
212
|
+
context.report({
|
|
213
|
+
message,
|
|
214
|
+
loc: {
|
|
215
|
+
start: sourceCode.getLocFromIndex(index),
|
|
216
|
+
end: sourceCode.getLocFromIndex(index + length)
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Properties whose animation moves the content around them. Narrower than the source's list:
|
|
222
|
+
* `grid-template-rows` is the source's own accordion fix, and type and radius don't reflow a page.
|
|
223
|
+
*/
|
|
224
|
+
const LAYOUT_PROPERTIES = new Set([
|
|
225
|
+
"width",
|
|
226
|
+
"height",
|
|
227
|
+
"min-width",
|
|
228
|
+
"min-height",
|
|
229
|
+
"max-width",
|
|
230
|
+
"max-height",
|
|
231
|
+
"top",
|
|
232
|
+
"right",
|
|
233
|
+
"bottom",
|
|
234
|
+
"left",
|
|
235
|
+
"inset",
|
|
236
|
+
"inset-block",
|
|
237
|
+
"inset-inline",
|
|
238
|
+
"margin",
|
|
239
|
+
"margin-top",
|
|
240
|
+
"margin-right",
|
|
241
|
+
"margin-bottom",
|
|
242
|
+
"margin-left",
|
|
243
|
+
"margin-block",
|
|
244
|
+
"margin-inline",
|
|
245
|
+
"padding",
|
|
246
|
+
"padding-top",
|
|
247
|
+
"padding-right",
|
|
248
|
+
"padding-bottom",
|
|
249
|
+
"padding-left",
|
|
250
|
+
"padding-block",
|
|
251
|
+
"padding-inline",
|
|
252
|
+
"flex-basis",
|
|
253
|
+
"gap"
|
|
254
|
+
]);
|
|
255
|
+
/** A string value, written `'…'` or as a template literal with no `${…}`. */
|
|
256
|
+
function stringValue(node) {
|
|
257
|
+
if (node.type === "Literal") return typeof node.value === "string" ? node.value : null;
|
|
258
|
+
return node.type === "TemplateLiteral" && node.expressions.length === 0 ? node.quasis[0]?.value.cooked ?? null : null;
|
|
259
|
+
}
|
|
260
|
+
/** `fontSize` → `font-size`. */
|
|
261
|
+
const kebab = (name) => name.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
|
|
262
|
+
/** The comma-separated items of a CSS value, ignoring commas inside parentheses, with their offsets. */
|
|
263
|
+
function splitList(value) {
|
|
264
|
+
const items = [];
|
|
265
|
+
let depth = 0;
|
|
266
|
+
let from = 0;
|
|
267
|
+
for (let i = 0; i <= value.length; i++) {
|
|
268
|
+
const c = value[i];
|
|
269
|
+
if (c === "(") depth++;
|
|
270
|
+
else if (c === ")") depth--;
|
|
271
|
+
else if (c === "," && depth === 0 || i === value.length) {
|
|
272
|
+
items.push({
|
|
273
|
+
item: value.slice(from, i),
|
|
274
|
+
offset: from
|
|
275
|
+
});
|
|
276
|
+
from = i + 1;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return items;
|
|
280
|
+
}
|
|
281
|
+
/** `transition`, `transition-property`, `animation` and friends, with the value up to `;`, `{` or `}`. */
|
|
282
|
+
const MOTION_DECLARATION$1 = /(?<![\w-])(transition|animation)(-property|-duration|-name)?\s*:\s*([^;{}]*)/g;
|
|
283
|
+
const OPENING_WORDS = new Set([
|
|
284
|
+
"Modal",
|
|
285
|
+
"Dialog",
|
|
286
|
+
"Drawer",
|
|
287
|
+
"Sheet",
|
|
288
|
+
"Popover",
|
|
289
|
+
"Tooltip",
|
|
290
|
+
"Toast",
|
|
291
|
+
"Snackbar",
|
|
292
|
+
"Dropdown",
|
|
293
|
+
"Menu",
|
|
294
|
+
"Popup",
|
|
295
|
+
"Flyout"
|
|
296
|
+
]);
|
|
297
|
+
/** A layer over something: a page scrim when fixed, but often a tile's hover layer or a text highlight. */
|
|
298
|
+
const LAYER_WORDS = new Set([
|
|
299
|
+
"Overlay",
|
|
300
|
+
"Backdrop",
|
|
301
|
+
"Scrim"
|
|
302
|
+
]);
|
|
303
|
+
/** Shells like `ModalWrapper` or `DropdownContainer` aren't here: they hold the surface that moves. */
|
|
304
|
+
const SURFACE_WORDS = new Set([
|
|
305
|
+
"Content",
|
|
306
|
+
"Panel",
|
|
307
|
+
"Surface",
|
|
308
|
+
"Box",
|
|
309
|
+
"List",
|
|
310
|
+
"Card",
|
|
311
|
+
"Window"
|
|
312
|
+
]);
|
|
313
|
+
const TRIGGERED_WORDS = new Set([
|
|
314
|
+
"Menu",
|
|
315
|
+
"Dropdown",
|
|
316
|
+
"Popover",
|
|
317
|
+
"Popup",
|
|
318
|
+
"Flyout"
|
|
319
|
+
]);
|
|
320
|
+
/** A part of a surface, or a persistent surface: `ModalCloseButtonContainer`, `SideMenuPanel`. */
|
|
321
|
+
const NOT_OVERLAY_WORDS = new Set([
|
|
322
|
+
"Item",
|
|
323
|
+
"Items",
|
|
324
|
+
"Option",
|
|
325
|
+
"Options",
|
|
326
|
+
"Trigger",
|
|
327
|
+
"Button",
|
|
328
|
+
"Btn",
|
|
329
|
+
"Icon",
|
|
330
|
+
"Label",
|
|
331
|
+
"Link",
|
|
332
|
+
"Divider",
|
|
333
|
+
"Separator",
|
|
334
|
+
"Chevron",
|
|
335
|
+
"Arrow",
|
|
336
|
+
"Caret",
|
|
337
|
+
"Title",
|
|
338
|
+
"Heading",
|
|
339
|
+
"Header",
|
|
340
|
+
"Footer",
|
|
341
|
+
"Close",
|
|
342
|
+
"Action",
|
|
343
|
+
"Actions",
|
|
344
|
+
"Description",
|
|
345
|
+
"Input",
|
|
346
|
+
"Field",
|
|
347
|
+
"Avatar",
|
|
348
|
+
"Anchor",
|
|
349
|
+
"Toggle",
|
|
350
|
+
"Tab",
|
|
351
|
+
"Row",
|
|
352
|
+
"Cell",
|
|
353
|
+
"Text",
|
|
354
|
+
"Hint",
|
|
355
|
+
"Caption",
|
|
356
|
+
"Tag",
|
|
357
|
+
"Section",
|
|
358
|
+
"Group",
|
|
359
|
+
"Side",
|
|
360
|
+
"Sidebar",
|
|
361
|
+
"Nav",
|
|
362
|
+
"Navigation",
|
|
363
|
+
"Bar"
|
|
364
|
+
]);
|
|
365
|
+
/**
|
|
366
|
+
* What a declared name says it is: `triggered` for a surface that opens from a trigger
|
|
367
|
+
* (`DropdownMenu`, `PopoverContent`), `overlay` for another surface that opens (`ModalOverlay`,
|
|
368
|
+
* `ToastContent`), `layer` for only a layer (`Backdrop`, `SelectionOverlay`), else null. Parts
|
|
369
|
+
* of a surface (`MenuItem`, `ModalHeader`) are null.
|
|
370
|
+
*/
|
|
371
|
+
function overlayKind(name) {
|
|
372
|
+
const words = name?.match(/[A-Z][a-z0-9]*|^[a-z0-9]+/g);
|
|
373
|
+
const last = words?.at(-1);
|
|
374
|
+
if (!words || !last || !OPENING_WORDS.has(last) && !LAYER_WORDS.has(last) && !SURFACE_WORDS.has(last) || words.some((word) => NOT_OVERLAY_WORDS.has(word))) return null;
|
|
375
|
+
if (words.some((word) => TRIGGERED_WORDS.has(word))) return "triggered";
|
|
376
|
+
if (words.some((word) => OPENING_WORDS.has(word))) return "overlay";
|
|
377
|
+
return words.some((word) => LAYER_WORDS.has(word)) ? "layer" : null;
|
|
378
|
+
}
|
|
379
|
+
/** Libraries and hooks that animate mounting and unmounting from outside the CSS. */
|
|
380
|
+
const PRESENCE_LIBRARY = /framer-motion|\bmotion\/react\b|AnimatePresence|react-transition-group|CSSTransition|TransitionGroup|@react-spring|react-spring/;
|
|
381
|
+
const isMotionTag = (context, node) => {
|
|
382
|
+
const [start, end] = node.tag.range;
|
|
383
|
+
return /\b(?:motion|m)\.\w|\banimated\.\w/.test(context.sourceCode.text.slice(start, end));
|
|
384
|
+
};
|
|
385
|
+
/** `styled(Popover)`: the template styles a component, which may bring its own motion. */
|
|
386
|
+
function wrapsComponent(node) {
|
|
387
|
+
let tag = node.tag;
|
|
388
|
+
while (tag.type === "MemberExpression" || tag.type === "CallExpression" && tag.callee.type === "MemberExpression") tag = tag.type === "MemberExpression" ? tag.object : tag.callee;
|
|
389
|
+
const argument = tag.type === "CallExpression" ? tag.arguments[0] : void 0;
|
|
390
|
+
const name = argument !== void 0 && argument.type !== "SpreadElement" ? lastName(argument) : null;
|
|
391
|
+
return name !== null && /^[A-Z]/.test(name);
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* The animation names a template uses: each word, or `${identifier}`, in an `animation` or
|
|
395
|
+
* `animation-name` value. Other interpolations (`${ModalClose}:hover`) aren't animations.
|
|
396
|
+
*/
|
|
397
|
+
function animationNames(css) {
|
|
398
|
+
const names = [];
|
|
399
|
+
const expressions = css.node.quasi.expressions;
|
|
400
|
+
for (const match of css.text.matchAll(/(?<![\w-])animation(?:-name)?\s*:\s*([^;{}]*)/g)) {
|
|
401
|
+
const valueStart = css.start + match.index + match[0].length - match[1].length;
|
|
402
|
+
const valueEnd = valueStart + match[1].length;
|
|
403
|
+
for (const expression of expressions) if (expression.type === "Identifier" && expression.range[0] >= valueStart && expression.range[1] <= valueEnd) names.push(expression.name);
|
|
404
|
+
for (const item of splitList(match[1])) {
|
|
405
|
+
const word = /^\s*([A-Za-z][\w-]*)/.exec(item.item)?.[1];
|
|
406
|
+
if (word !== void 0 && word !== "none") names.push(word);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return names;
|
|
410
|
+
}
|
|
411
|
+
//#endregion
|
|
412
|
+
//#region src/lint/rules/duration-token.ts
|
|
413
|
+
/** `TransitionDuration`, mirrored here because the plugin has no runtime imports. */
|
|
414
|
+
const DURATION_TOKENS = {
|
|
415
|
+
100: "ExtraFast",
|
|
416
|
+
150: "Faster",
|
|
417
|
+
200: "Fast",
|
|
418
|
+
300: "MediumFast",
|
|
419
|
+
400: "Medium",
|
|
420
|
+
1e3: "OneSecond"
|
|
421
|
+
};
|
|
422
|
+
/** `TransitionDurationInSeconds`, the same steps. */
|
|
423
|
+
const SECONDS_TOKENS = { ...DURATION_TOKENS };
|
|
424
|
+
/** At or under this, a duration is a reduced-motion override or an instant change, not motion. */
|
|
425
|
+
const INSTANT_MS = 20;
|
|
426
|
+
const TIME = /(?<![\w.$-])(\d*\.?\d+)(ms|s)(?![\w-])/;
|
|
427
|
+
/** A spinner's or shimmer's period isn't a state change, so the scale doesn't apply. */
|
|
428
|
+
const LOOP$1 = /\binfinite\b/;
|
|
429
|
+
const STRING_PROPERTIES = new Set([
|
|
430
|
+
"transition",
|
|
431
|
+
"transitionDuration",
|
|
432
|
+
"animation",
|
|
433
|
+
"animationDuration"
|
|
434
|
+
]);
|
|
435
|
+
const toMs = (value, unit) => Number(value) * (unit === "s" ? 1e3 : 1);
|
|
436
|
+
function cssMessage(literal, ms) {
|
|
437
|
+
const token = DURATION_TOKENS[ms];
|
|
438
|
+
return token ? `Literal duration ${literal}: use \`TransitionDuration.${token}\` from \`@persona/design-system/variables/transitions\`.` : `Literal duration ${literal} is off the PDS scale: use a \`TransitionDuration\` token (100, 150, 200, 300, 400 or 1000 ms) from \`@persona/design-system/variables/transitions\`.`;
|
|
439
|
+
}
|
|
440
|
+
function secondsMessage(seconds) {
|
|
441
|
+
const token = SECONDS_TOKENS[Math.round(seconds * 1e3)];
|
|
442
|
+
return token ? `Literal duration ${seconds}: use \`TransitionDurationInSeconds.${token}\` from \`@persona/design-system/variables/transitions\`.` : `Literal duration ${seconds} is off the PDS scale: use a \`TransitionDurationInSeconds\` token (0.1 to 0.4, or 1) from \`@persona/design-system/variables/transitions\`.`;
|
|
443
|
+
}
|
|
444
|
+
/** The first time in each item of a `transition` or `animation` list: its duration, not its delay. */
|
|
445
|
+
function durations(value) {
|
|
446
|
+
return splitList(value).flatMap(({ item, offset }) => {
|
|
447
|
+
const match = TIME.exec(item);
|
|
448
|
+
if (!match || LOOP$1.test(item)) return [];
|
|
449
|
+
const ms = toMs(match[1], match[2]);
|
|
450
|
+
return ms > INSTANT_MS ? [{
|
|
451
|
+
literal: match[0],
|
|
452
|
+
ms,
|
|
453
|
+
offset: offset + match.index
|
|
454
|
+
}] : [];
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
/** An interpolation that is itself a duration: `${TransitionDuration.Fast}`, `${OPEN_MS}`, `${ms}ms`. */
|
|
458
|
+
const DURATION_EXPRESSION = /duration|_MS\b|Ms\b|\bms\b/i;
|
|
459
|
+
const UNIT_AFTER = /^\s*\}m?s(?![\w-])/;
|
|
460
|
+
/**
|
|
461
|
+
* The CSS text with each duration interpolation written as `0ms`, so it holds the item's duration
|
|
462
|
+
* slot and a literal after it (a delay) isn't read as the duration.
|
|
463
|
+
*/
|
|
464
|
+
function markDurationExpressions(context, node, css) {
|
|
465
|
+
const source = context.sourceCode.text;
|
|
466
|
+
let { text } = css;
|
|
467
|
+
for (const expression of node.quasi.expressions) {
|
|
468
|
+
const [start, end] = expression.range;
|
|
469
|
+
if (!DURATION_EXPRESSION.test(source.slice(start, end)) && !UNIT_AFTER.test(source.slice(end))) continue;
|
|
470
|
+
let from = start - css.start;
|
|
471
|
+
let to = end - css.start;
|
|
472
|
+
while (from > 0 && text[from - 1] === "_") from--;
|
|
473
|
+
while (to < text.length && text[to] === "_") to++;
|
|
474
|
+
text = text.slice(0, from) + "0ms".padEnd(to - from) + text.slice(to);
|
|
475
|
+
}
|
|
476
|
+
return text;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* True when `node` is the value of a `transition` key or a `transition={…}` JSX attribute, or a
|
|
480
|
+
* per-value transition inside one (`transition={{ opacity: { duration } }}`).
|
|
481
|
+
*/
|
|
482
|
+
function isTransitionObject(node, depth = 0) {
|
|
483
|
+
const { parent } = node;
|
|
484
|
+
if (parent.type === "Property" && parent.value === node) return propertyName(parent) === "transition" || depth === 0 && isTransitionObject(parent.parent, 1);
|
|
485
|
+
if (parent.type === "JSXExpressionContainer") {
|
|
486
|
+
const attribute = parent.parent;
|
|
487
|
+
return attribute.type === "JSXAttribute" && attribute.name.type === "JSXIdentifier" && attribute.name.name === "transition";
|
|
488
|
+
}
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
const durationToken = {
|
|
492
|
+
meta: {
|
|
493
|
+
type: "suggestion",
|
|
494
|
+
docs: docs("Transition and animation durations come from `TransitionDuration` (CSS) or `TransitionDurationInSeconds` (Framer Motion), not literals.")
|
|
495
|
+
},
|
|
496
|
+
createOnce(context) {
|
|
497
|
+
return {
|
|
498
|
+
TaggedTemplateExpression(node) {
|
|
499
|
+
const css = cssTemplate(context, node);
|
|
500
|
+
if (css === null) return;
|
|
501
|
+
for (const match of markDurationExpressions(context, node, css).matchAll(MOTION_DECLARATION$1)) {
|
|
502
|
+
if (match[2] === "-property" || match[2] === "-name" || match[2] === "-duration" && LOOP$1.test(css.text)) continue;
|
|
503
|
+
const valueStart = match.index + match[0].length - match[3].length;
|
|
504
|
+
for (const { literal, ms, offset } of durations(match[3])) reportAt(context, css.start + valueStart + offset, literal.length, cssMessage(literal, ms));
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
Property(node) {
|
|
508
|
+
const name = propertyName(node);
|
|
509
|
+
const { value } = node;
|
|
510
|
+
const text = stringValue(value);
|
|
511
|
+
if (name === null) return;
|
|
512
|
+
if (STRING_PROPERTIES.has(name) && text !== null) for (const { literal, ms } of durations(text)) context.report({
|
|
513
|
+
node,
|
|
514
|
+
message: cssMessage(literal, ms)
|
|
515
|
+
});
|
|
516
|
+
else if (name === "duration" && value.type === "Literal" && typeof value.value === "number" && value.value * 1e3 > INSTANT_MS && node.parent.type === "ObjectExpression" && isTransitionObject(node.parent) && !node.parent.properties.some((item) => item.type === "Property" && propertyName(item) === "repeat")) context.report({
|
|
517
|
+
node,
|
|
518
|
+
message: secondsMessage(value.value)
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
//#endregion
|
|
525
|
+
//#region src/lint/rules/exit-motion.ts
|
|
526
|
+
const NO_ANIMATION = /^\s*(?:none|initial|inherit|unset|revert)?\s*$/;
|
|
527
|
+
const LOOP = /\binfinite\b/;
|
|
528
|
+
const FIXED$1 = /(?<![\w-])position\s*:\s*fixed\b/;
|
|
529
|
+
const KEYFRAMES_NAME = /@keyframes\s+([\w-]+)/g;
|
|
530
|
+
/** `fadeOut`, `fade-out`, `exit`: an animation name that reads as an exit (not `layout`). */
|
|
531
|
+
const EXIT_NAME = /(?:^|[-_])(?:out|exit|hide|close|leave|disappear)$|[a-z0-9](?:Out|Exit|Hide|Close|Leave|Disappear)$/;
|
|
532
|
+
/** Ways a file can hold an overlay on screen while it animates out. */
|
|
533
|
+
const EXIT_MARKERS = /AnimatePresence|CSSTransition|TransitionGroup|react-spring|onAnimationEnd|onTransitionEnd|animationend|transitionend|data-state\W{1,4}closed|data-exiting|isExiting|\b[iI]sClosing\b|\bexit=/;
|
|
534
|
+
const styledMessage = (name) => `\`${name}\` animates in but disappears instantly. Give it an exit (React Aria: style \`[data-exiting]\`; Radix: \`[data-state='closed']\`), shorter than the enter.`;
|
|
535
|
+
const MOTION_MESSAGE = "Mounts with an enter animation but unmounts instantly. Add `exit` (inside `AnimatePresence`), shorter than the enter.";
|
|
536
|
+
function isMotionElement(name) {
|
|
537
|
+
return name.type === "JSXMemberExpression" && name.object.type === "JSXIdentifier" && (name.object.name === "motion" || name.object.name === "m");
|
|
538
|
+
}
|
|
539
|
+
function attribute(node, name) {
|
|
540
|
+
for (const item of node.attributes) if (item.type === "JSXAttribute" && item.name.type === "JSXIdentifier" && item.name.name === name) return item;
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
const isFalse = (item) => item.value?.type === "JSXExpressionContainer" && item.value.expression.type === "Literal" && item.value.expression.value === false;
|
|
544
|
+
/** An `animation` or `animation-name` that plays once: an enter, not a loop or a reset. */
|
|
545
|
+
function hasEnterAnimation(css) {
|
|
546
|
+
for (const match of ownDeclarations(css.text).matchAll(MOTION_DECLARATION$1)) if (match[1] === "animation" && (match[2] === void 0 || match[2] === "-name") && !NO_ANIMATION.test(match[3]) && !LOOP.test(match[3])) return true;
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
/** The node with any grouping parentheses around it. */
|
|
550
|
+
function outermost(node) {
|
|
551
|
+
let at = node;
|
|
552
|
+
while (at.parent?.type === "ParenthesizedExpression") at = at.parent;
|
|
553
|
+
return at;
|
|
554
|
+
}
|
|
555
|
+
function unwrap(node) {
|
|
556
|
+
let at = node;
|
|
557
|
+
while (at.type === "ParenthesizedExpression") at = at.expression;
|
|
558
|
+
return at;
|
|
559
|
+
}
|
|
560
|
+
/** `{open && <X />}` or `{open ? <X /> : null}`: rendered only while something is true. */
|
|
561
|
+
function isConditional(node) {
|
|
562
|
+
const self = outermost(node);
|
|
563
|
+
const { parent } = self;
|
|
564
|
+
return parent?.type === "LogicalExpression" && parent.operator === "&&" && parent.right === self || parent?.type === "ConditionalExpression" && parent.test !== self;
|
|
565
|
+
}
|
|
566
|
+
/** `{tab === 1 ? <motion.div …/> : <B />}` outside `<AnimatePresence>`: a content swap, not an unmount. */
|
|
567
|
+
function isSwap(node) {
|
|
568
|
+
const self = outermost(node);
|
|
569
|
+
const { parent } = self;
|
|
570
|
+
if (parent?.type !== "ConditionalExpression" || insidePresence(node)) return false;
|
|
571
|
+
const other = unwrap(parent.consequent === self ? parent.alternate : parent.consequent);
|
|
572
|
+
return other.type === "JSXElement" || other.type === "JSXFragment";
|
|
573
|
+
}
|
|
574
|
+
function insidePresence(node) {
|
|
575
|
+
for (let at = node.parent; at !== null; at = at.parent) if (at.type === "JSXElement" && at.openingElement.name.type === "JSXIdentifier" && at.openingElement.name.name === "AnimatePresence") return true;
|
|
576
|
+
return false;
|
|
577
|
+
}
|
|
578
|
+
const exitMotion = {
|
|
579
|
+
meta: {
|
|
580
|
+
type: "suggestion",
|
|
581
|
+
docs: docs("An overlay that animates in also animates out: a styled overlay with an enter animation has an exit, and a conditionally rendered `motion.*` element with `initial` has `exit`.")
|
|
582
|
+
},
|
|
583
|
+
createOnce(context) {
|
|
584
|
+
let candidates = [];
|
|
585
|
+
let names = /* @__PURE__ */ new Set();
|
|
586
|
+
return {
|
|
587
|
+
before() {
|
|
588
|
+
candidates = [];
|
|
589
|
+
names = /* @__PURE__ */ new Set();
|
|
590
|
+
},
|
|
591
|
+
TaggedTemplateExpression(node) {
|
|
592
|
+
const css = cssTemplate(context, node);
|
|
593
|
+
if (css === null) return;
|
|
594
|
+
if (rootIdentifier(node.tag) === "keyframes" && css.name !== null) names.add(css.name);
|
|
595
|
+
for (const name of animationNames(css)) names.add(name);
|
|
596
|
+
for (const match of css.text.matchAll(KEYFRAMES_NAME)) names.add(match[1]);
|
|
597
|
+
const kind = overlayKind(css.name);
|
|
598
|
+
if (kind !== null && (kind !== "layer" || FIXED$1.test(ownDeclarations(css.text))) && hasEnterAnimation(css)) candidates.push(css);
|
|
599
|
+
},
|
|
600
|
+
JSXElement(node) {
|
|
601
|
+
const opening = node.openingElement;
|
|
602
|
+
const initial = attribute(opening, "initial");
|
|
603
|
+
if (isMotionElement(opening.name) && initial !== null && !isFalse(initial) && attribute(opening, "exit") === null && !opening.attributes.some((item) => item.type === "JSXSpreadAttribute") && isConditional(node) && !isSwap(node)) context.report({
|
|
604
|
+
node: opening.name,
|
|
605
|
+
message: MOTION_MESSAGE
|
|
606
|
+
});
|
|
607
|
+
},
|
|
608
|
+
after() {
|
|
609
|
+
if (candidates.length === 0 || EXIT_MARKERS.test(context.sourceCode.text) || [...names].some((name) => EXIT_NAME.test(name))) return;
|
|
610
|
+
for (const css of candidates) context.report({
|
|
611
|
+
node: css.nameNode,
|
|
612
|
+
message: styledMessage(css.name)
|
|
613
|
+
});
|
|
127
614
|
}
|
|
128
615
|
};
|
|
129
616
|
}
|
|
@@ -219,13 +706,118 @@ const minCopySize = {
|
|
|
219
706
|
}
|
|
220
707
|
};
|
|
221
708
|
//#endregion
|
|
709
|
+
//#region src/lint/rules/motion-origin.ts
|
|
710
|
+
/** A scale below 1, as an opening surface grows from: `scale(0.95)`, `scaleY(0)`, `scale: 0.96`. */
|
|
711
|
+
const SCALES = /(?<![\w-])scale(?:[XYZ]|3d)?\(\s*(?:0?\.\d|0(?![.\d]))|(?<![\w-])scale\s*:\s*(?:0?\.\d|0(?![.\d]))/;
|
|
712
|
+
const KEYFRAMES_BLOCK$1 = /@keyframes\s+([\w-]+)\s*\{((?:[^{}]*\{[^{}]*\})*[^{}]*)\}/g;
|
|
713
|
+
const ORIGIN = /transform-origin|transformOrigin/;
|
|
714
|
+
const message$3 = (name) => `\`${name}\` scales from its centre. A menu or popover grows from its trigger: set \`transform-origin\` (React Aria: \`var(--trigger-anchor-point)\`; Radix: \`var(--radix-popover-content-transform-origin)\`).`;
|
|
715
|
+
const motionOrigin = {
|
|
716
|
+
meta: {
|
|
717
|
+
type: "suggestion",
|
|
718
|
+
docs: docs("A menu, dropdown or popover that scales sets `transform-origin`, so it grows from its trigger rather than its centre.")
|
|
719
|
+
},
|
|
720
|
+
createOnce(context) {
|
|
721
|
+
let candidates = [];
|
|
722
|
+
let scaling = /* @__PURE__ */ new Set();
|
|
723
|
+
return {
|
|
724
|
+
before() {
|
|
725
|
+
candidates = [];
|
|
726
|
+
scaling = /* @__PURE__ */ new Set();
|
|
727
|
+
},
|
|
728
|
+
TaggedTemplateExpression(node) {
|
|
729
|
+
const css = cssTemplate(context, node);
|
|
730
|
+
if (css === null) return;
|
|
731
|
+
if (rootIdentifier(node.tag) === "keyframes" && css.name !== null && SCALES.test(css.text)) scaling.add(css.name);
|
|
732
|
+
for (const match of css.text.matchAll(KEYFRAMES_BLOCK$1)) if (SCALES.test(match[2])) scaling.add(match[1]);
|
|
733
|
+
if (overlayKind(css.name) === "triggered") candidates.push({
|
|
734
|
+
css,
|
|
735
|
+
references: animationNames(css)
|
|
736
|
+
});
|
|
737
|
+
},
|
|
738
|
+
after() {
|
|
739
|
+
if (ORIGIN.test(context.sourceCode.text)) return;
|
|
740
|
+
for (const { css, references } of candidates) if (SCALES.test(ownDeclarations(css.text)) || references.some((name) => scaling.has(name))) context.report({
|
|
741
|
+
node: css.nameNode,
|
|
742
|
+
message: message$3(css.name)
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
//#endregion
|
|
749
|
+
//#region src/lint/rules/no-layout-motion.ts
|
|
750
|
+
const TRANSITION_PROPERTIES$1 = new Set([
|
|
751
|
+
"transition",
|
|
752
|
+
"transitionProperty",
|
|
753
|
+
"transition-property"
|
|
754
|
+
]);
|
|
755
|
+
const KEYFRAMES_BLOCK = /@keyframes\s+[\w-]+\s*\{((?:[^{}]*\{[^{}]*\})*[^{}]*)\}/g;
|
|
756
|
+
const DECLARATION = /(?<![\w-])([a-z-]+)\s*:/g;
|
|
757
|
+
/** `height 0s`: a duration of zero switches the value rather than animating it. */
|
|
758
|
+
const INSTANT = /^\s*[a-z-]+\s+0?\.?0*m?s\b/;
|
|
759
|
+
const message$2 = (property) => `Animating \`${property}\` runs layout on every frame and can shift the content around it. Animate \`transform\` or \`opacity\` instead; to expand a section, animate \`grid-template-rows\` from \`0fr\` to \`1fr\`.`;
|
|
760
|
+
/** Each layout property a transition list names, with its offset in `value`. */
|
|
761
|
+
function layoutItems(value) {
|
|
762
|
+
return splitList(value).flatMap(({ item, offset }) => {
|
|
763
|
+
const match = /^\s*([a-z-]+)/.exec(item);
|
|
764
|
+
const property = match?.[1];
|
|
765
|
+
return property !== void 0 && LAYOUT_PROPERTIES.has(property) && !INSTANT.test(item) ? [{
|
|
766
|
+
property,
|
|
767
|
+
offset: offset + match[0].length - property.length
|
|
768
|
+
}] : [];
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
function reportKeyframes(context, text, start) {
|
|
772
|
+
for (const match of text.matchAll(DECLARATION)) {
|
|
773
|
+
const property = match[1];
|
|
774
|
+
if (LAYOUT_PROPERTIES.has(property)) reportAt(context, start + match.index + match[0].indexOf(property), property.length, message$2(property));
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
const noLayoutMotion = {
|
|
778
|
+
meta: {
|
|
779
|
+
type: "suggestion",
|
|
780
|
+
docs: docs("Transitions and keyframes animate `transform` and `opacity`, not layout properties such as `height`, `width`, `top` or `margin`.")
|
|
781
|
+
},
|
|
782
|
+
createOnce(context) {
|
|
783
|
+
return {
|
|
784
|
+
TaggedTemplateExpression(node) {
|
|
785
|
+
const css = cssTemplate(context, node);
|
|
786
|
+
if (css === null) return;
|
|
787
|
+
if (rootIdentifier(node.tag) === "keyframes") {
|
|
788
|
+
reportKeyframes(context, css.text, css.start);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
for (const match of css.text.matchAll(KEYFRAMES_BLOCK)) {
|
|
792
|
+
const body = match[1];
|
|
793
|
+
reportKeyframes(context, body, css.start + match.index + match[0].indexOf(body));
|
|
794
|
+
}
|
|
795
|
+
for (const match of css.text.matchAll(MOTION_DECLARATION$1)) {
|
|
796
|
+
if (match[1] !== "transition" || match[2] !== void 0 && match[2] !== "-property") continue;
|
|
797
|
+
const valueStart = match.index + match[0].length - match[3].length;
|
|
798
|
+
for (const { property, offset } of layoutItems(match[3])) reportAt(context, css.start + valueStart + offset, property.length, message$2(property));
|
|
799
|
+
}
|
|
800
|
+
},
|
|
801
|
+
Property(node) {
|
|
802
|
+
const name = propertyName(node);
|
|
803
|
+
const text = stringValue(node.value);
|
|
804
|
+
if (name === null || !TRANSITION_PROPERTIES$1.has(name) || text === null) return;
|
|
805
|
+
for (const { property } of layoutItems(kebab(text))) context.report({
|
|
806
|
+
node,
|
|
807
|
+
message: message$2(property)
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
//#endregion
|
|
222
814
|
//#region src/lint/rules/no-raw-table.ts
|
|
223
815
|
const TABLE_ELEMENTS = new Set([
|
|
224
816
|
"table",
|
|
225
817
|
"th",
|
|
226
818
|
"td"
|
|
227
819
|
]);
|
|
228
|
-
const message = (what) => `Hand-rolled table markup (${what}). Use \`Table\`, \`DataTable\` or \`IndexTableLayout\`.`;
|
|
820
|
+
const message$1 = (what) => `Hand-rolled table markup (${what}). Use \`Table\`, \`DataTable\` or \`IndexTableLayout\`.`;
|
|
229
821
|
const noRawTable = {
|
|
230
822
|
meta: {
|
|
231
823
|
type: "problem",
|
|
@@ -236,21 +828,107 @@ const noRawTable = {
|
|
|
236
828
|
JSXOpeningElement(node) {
|
|
237
829
|
if (node.name.type === "JSXIdentifier" && TABLE_ELEMENTS.has(node.name.name)) context.report({
|
|
238
830
|
node: node.name,
|
|
239
|
-
message: message(`<${node.name.name}>`)
|
|
831
|
+
message: message$1(`<${node.name.name}>`)
|
|
240
832
|
});
|
|
241
833
|
},
|
|
242
834
|
MemberExpression(node) {
|
|
243
835
|
const name = staticMemberName(node);
|
|
244
836
|
if (name !== null && TABLE_ELEMENTS.has(name) && node.object.type === "Identifier" && node.object.name === "styled") context.report({
|
|
245
837
|
node,
|
|
246
|
-
message: message(`styled.${name}`)
|
|
838
|
+
message: message$1(`styled.${name}`)
|
|
247
839
|
});
|
|
248
840
|
},
|
|
249
841
|
CallExpression(node) {
|
|
250
842
|
const [argument] = node.arguments;
|
|
251
843
|
if (node.callee.type === "Identifier" && node.callee.name === "styled" && argument?.type === "Literal" && typeof argument.value === "string" && TABLE_ELEMENTS.has(argument.value)) context.report({
|
|
252
844
|
node,
|
|
253
|
-
message: message(`styled('${argument.value}')`)
|
|
845
|
+
message: message$1(`styled('${argument.value}')`)
|
|
846
|
+
});
|
|
847
|
+
}
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
};
|
|
851
|
+
//#endregion
|
|
852
|
+
//#region src/lint/rules/no-transition-all.ts
|
|
853
|
+
const TRANSITION_PROPERTIES = new Set([
|
|
854
|
+
"transition",
|
|
855
|
+
"transitionProperty",
|
|
856
|
+
"transition-property"
|
|
857
|
+
]);
|
|
858
|
+
const TAILWIND_ALL = /(?:^|\s)(?:[\w-]+:)*transition-all(?=\s|$)/;
|
|
859
|
+
const MESSAGE$1 = "`transition: all` animates every property, layout included. Name the ones the states change (`opacity`, `transform`, `background-color`).";
|
|
860
|
+
/** The offset, in `value`, of each list item that transitions `all`. */
|
|
861
|
+
function allOffsets(value) {
|
|
862
|
+
return splitList(value).flatMap(({ item, offset }) => {
|
|
863
|
+
const match = /^\s*all(?![\w-])/.exec(item);
|
|
864
|
+
return match ? [offset + match[0].indexOf("all")] : [];
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
const noTransitionAll = {
|
|
868
|
+
meta: {
|
|
869
|
+
type: "suggestion",
|
|
870
|
+
docs: docs("Transition named properties, never `all`, which animates layout too and costs more to paint.")
|
|
871
|
+
},
|
|
872
|
+
createOnce(context) {
|
|
873
|
+
return {
|
|
874
|
+
TaggedTemplateExpression(node) {
|
|
875
|
+
const css = cssTemplate(context, node);
|
|
876
|
+
if (css === null) return;
|
|
877
|
+
for (const match of css.text.matchAll(MOTION_DECLARATION$1)) {
|
|
878
|
+
if (match[1] !== "transition" || match[2] !== void 0 && match[2] !== "-property") continue;
|
|
879
|
+
const valueStart = match.index + match[0].length - match[3].length;
|
|
880
|
+
for (const offset of allOffsets(match[3])) reportAt(context, css.start + valueStart + offset, 3, MESSAGE$1);
|
|
881
|
+
}
|
|
882
|
+
},
|
|
883
|
+
Property(node) {
|
|
884
|
+
const name = propertyName(node);
|
|
885
|
+
const text = stringValue(node.value);
|
|
886
|
+
if (name !== null && TRANSITION_PROPERTIES.has(name) && text !== null && allOffsets(text).length > 0) context.report({
|
|
887
|
+
node,
|
|
888
|
+
message: MESSAGE$1
|
|
889
|
+
});
|
|
890
|
+
},
|
|
891
|
+
Literal(node) {
|
|
892
|
+
if (typeof node.value === "string" && TAILWIND_ALL.test(node.value)) context.report({
|
|
893
|
+
node,
|
|
894
|
+
message: MESSAGE$1
|
|
895
|
+
});
|
|
896
|
+
},
|
|
897
|
+
TemplateElement(node) {
|
|
898
|
+
if (TAILWIND_ALL.test(node.value.cooked ?? node.value.raw)) context.report({
|
|
899
|
+
node,
|
|
900
|
+
message: MESSAGE$1
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
};
|
|
906
|
+
//#endregion
|
|
907
|
+
//#region src/lint/rules/overlay-motion.ts
|
|
908
|
+
const FLOATING = /(?<![\w-])position\s*:\s*(?:fixed|absolute)\b/;
|
|
909
|
+
const FIXED = /(?<![\w-])position\s*:\s*fixed\b/;
|
|
910
|
+
const message = (name) => `\`${name}\` is an overlay with no transition or animation, so it pops in and out. Fade it in and out (a menu or popover also scales a little from its trigger), or use the PDS component.`;
|
|
911
|
+
const overlayMotion = {
|
|
912
|
+
meta: {
|
|
913
|
+
type: "suggestion",
|
|
914
|
+
docs: docs("A hand-rolled overlay (a fixed or absolute styled component named like a modal, drawer, popover, menu, tooltip or toast, or a fixed backdrop) has a transition or animation.")
|
|
915
|
+
},
|
|
916
|
+
createOnce(context) {
|
|
917
|
+
let candidates = [];
|
|
918
|
+
return {
|
|
919
|
+
before() {
|
|
920
|
+
candidates = [];
|
|
921
|
+
},
|
|
922
|
+
TaggedTemplateExpression(node) {
|
|
923
|
+
const css = cssTemplate(context, node);
|
|
924
|
+
const kind = css === null ? null : overlayKind(css.name);
|
|
925
|
+
if (css !== null && kind !== null && (kind === "layer" ? FIXED : FLOATING).test(ownDeclarations(css.text)) && !hasMotion(context, css) && !isMotionTag(context, node) && !wrapsComponent(node)) candidates.push(css);
|
|
926
|
+
},
|
|
927
|
+
after() {
|
|
928
|
+
if (candidates.length === 0 || PRESENCE_LIBRARY.test(context.sourceCode.text)) return;
|
|
929
|
+
for (const css of candidates) context.report({
|
|
930
|
+
node: css.nameNode,
|
|
931
|
+
message: message(css.name)
|
|
254
932
|
});
|
|
255
933
|
}
|
|
256
934
|
};
|
|
@@ -268,7 +946,7 @@ const MOTION_PROPERTIES = new Set([
|
|
|
268
946
|
]);
|
|
269
947
|
const MOTION_DECLARATION = /@keyframes\b|(?<![\w-])(?:animation|animation-name|transition|transition-property)\s*:/g;
|
|
270
948
|
const REDUCED_MOTION = "prefers-reduced-motion";
|
|
271
|
-
const MESSAGE = "Animation or transition in a file with no `prefers-reduced-motion` block. Add one that
|
|
949
|
+
const MESSAGE = "Animation or transition in a file with no `prefers-reduced-motion` block. Add one that keeps the change as a short opacity fade (`ReducedMotionFade`: 150 ms) with no movement, rather than turning it off.";
|
|
272
950
|
const reducedMotion = {
|
|
273
951
|
meta: {
|
|
274
952
|
type: "suggestion",
|
|
@@ -334,7 +1012,8 @@ const MODULE_PARENTS = new Set([
|
|
|
334
1012
|
"ExportAllDeclaration",
|
|
335
1013
|
"ImportExpression"
|
|
336
1014
|
]);
|
|
337
|
-
const
|
|
1015
|
+
const TOKEN_CALLEES = new Set(["semanticColor", "chartColor"]);
|
|
1016
|
+
const isSemanticColorCall = (node) => node.callee.type === "Identifier" && TOKEN_CALLEES.has(node.callee.name);
|
|
338
1017
|
const isLinkAttribute = (node) => node.name.type === "JSXIdentifier" && LINK_ATTRIBUTES.has(node.name.name);
|
|
339
1018
|
//#endregion
|
|
340
1019
|
//#region src/lint/index.ts
|
|
@@ -381,7 +1060,7 @@ const plugin = {
|
|
|
381
1060
|
const name = staticMemberName(node);
|
|
382
1061
|
if (insideSemanticColor === 0 && name !== null && node.object.type === "Identifier" && node.object.name === "Color" && /^[A-Z]\w*$/.test(name)) context.report({
|
|
383
1062
|
node,
|
|
384
|
-
message: `\`Color.${name}\` outside \`semanticColor\`: paint with a semantic token, with this as its fallback.`
|
|
1063
|
+
message: `\`Color.${name}\` outside \`semanticColor\`: paint with a semantic token, with this as its fallback (or wrap a chart series override in \`chartColor\`).`
|
|
385
1064
|
});
|
|
386
1065
|
}
|
|
387
1066
|
};
|
|
@@ -390,7 +1069,13 @@ const plugin = {
|
|
|
390
1069
|
"complete-typography": completeTypography,
|
|
391
1070
|
"min-copy-size": minCopySize,
|
|
392
1071
|
"reduced-motion": reducedMotion,
|
|
393
|
-
"no-raw-table": noRawTable
|
|
1072
|
+
"no-raw-table": noRawTable,
|
|
1073
|
+
"exit-motion": exitMotion,
|
|
1074
|
+
"overlay-motion": overlayMotion,
|
|
1075
|
+
"motion-origin": motionOrigin,
|
|
1076
|
+
"no-layout-motion": noLayoutMotion,
|
|
1077
|
+
"no-transition-all": noTransitionAll,
|
|
1078
|
+
"duration-token": durationToken
|
|
394
1079
|
}
|
|
395
1080
|
};
|
|
396
1081
|
//#endregion
|