frappe-ui 1.0.0-beta.2 → 1.0.0-beta.21
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/experimental/FloatingWindow/FloatingWindow.cy.ts +328 -0
- package/experimental/FloatingWindow/FloatingWindow.vue +303 -0
- package/experimental/FloatingWindow/index.ts +8 -0
- package/experimental/FloatingWindow/types.ts +31 -0
- package/experimental/FloatingWindow/useFloatingWindow.ts +236 -0
- package/experimental/MultiEmailInput/MultiEmailInput.cy.ts +155 -0
- package/experimental/MultiEmailInput/MultiEmailInput.vue +472 -0
- package/experimental/MultiEmailInput/index.ts +17 -0
- package/experimental/MultiEmailInput/stories/AsyncSuggestions.vue +54 -0
- package/experimental/MultiEmailInput/stories/Basic.vue +18 -0
- package/experimental/MultiEmailInput/stories/CustomChip.vue +39 -0
- package/experimental/MultiEmailInput/stories/Labeling.vue +28 -0
- package/experimental/MultiEmailInput/types.ts +138 -0
- package/experimental/MultiEmailInput/utils.ts +60 -0
- package/experimental.ts +12 -0
- package/frappe/Billing/SignupBanner.vue +1 -1
- package/frappe/Billing/TrialBanner.vue +1 -1
- package/frappe/DataImport/DataImport.vue +1 -1
- package/frappe/DataImport/DataImportList.vue +1 -1
- package/frappe/DataImport/ImportSteps.vue +6 -6
- package/frappe/DataImport/MappingStep.vue +1 -1
- package/frappe/DataImport/PreviewStep.vue +9 -9
- package/frappe/DataImport/TemplateModal.vue +1 -1
- package/frappe/DataImport/UploadStep.vue +5 -5
- package/frappe/Filter/Filter.vue +1 -1
- package/frappe/Help/HelpModal.vue +1 -1
- package/frappe/Link/stories/Suffix.vue +2 -2
- package/frappe/Onboarding/GettingStartedBanner.vue +1 -1
- package/frappe/drive/components/AppSwitcher.vue +1 -1
- package/frappe/drive/components/InfoDialog.vue +3 -3
- package/frappe/drive/components/MoveDialog.vue +2 -2
- package/frappe/drive/components/Select/Select.vue +2 -2
- package/frappe/drive/components/ShareDialog.vue +1 -1
- package/frappe/telemetry/index.ts +88 -14
- package/frappe/telemetry/pulse.ts +78 -164
- package/frappe/telemetry/telemetry.test.ts +13 -79
- package/icons/IconPicker.vue +1 -1
- package/package.json +104 -34
- package/src/components/Alert/Alert.md +4 -0
- package/src/components/Alert/Alert.vue +4 -4
- package/src/components/Autocomplete/Autocomplete.vue +6 -6
- package/src/components/Avatar/Avatar.md +4 -0
- package/src/components/Avatar/Avatar.vue +23 -4
- package/src/components/Badge/Badge.api.md +1 -1
- package/src/components/Badge/Badge.cy.ts +34 -16
- package/src/components/Badge/Badge.md +20 -4
- package/src/components/Badge/Badge.vue +60 -45
- package/src/components/Badge/stories/CallMeta.vue +35 -0
- package/src/components/Badge/stories/EventStatus.vue +16 -0
- package/src/components/Badge/stories/ListStatus.vue +91 -0
- package/src/components/Badge/stories/Reactions.vue +33 -0
- package/src/components/Badge/stories/RowTags.vue +39 -0
- package/src/components/Badge/types.ts +1 -2
- package/src/components/BottomSheet/BottomSheet.api.md +57 -0
- package/src/components/BottomSheet/BottomSheet.vue +232 -0
- package/src/components/BottomSheet/index.ts +6 -0
- package/src/components/BottomSheet/types.ts +23 -0
- package/src/components/Breadcrumbs/Breadcrumbs.md +4 -0
- package/src/components/Breadcrumbs/Breadcrumbs.vue +3 -3
- package/src/components/Button/Button.api.md +37 -32
- package/src/components/Button/Button.cy.ts +18 -2
- package/src/components/Button/Button.md +20 -8
- package/src/components/Button/Button.vue +304 -284
- package/src/components/Button/stories/InlineActions.vue +10 -0
- package/src/components/Button/stories/LiveClassCard.vue +34 -0
- package/src/components/Button/stories/SectionAction.vue +17 -0
- package/src/components/Button/stories/SectionControls.vue +28 -0
- package/src/components/Button/stories/SelectionToolbar.vue +20 -0
- package/src/components/Button/stories/StackedActions.vue +10 -0
- package/src/components/Button/types.ts +38 -32
- package/src/components/Calendar/Calendar.api.md +16 -16
- package/src/components/Calendar/Calendar.vue +100 -73
- package/src/components/Calendar/CalendarDaily.vue +21 -20
- package/src/components/Calendar/CalendarMonthEvent.vue +30 -9
- package/src/components/Calendar/CalendarMonthly.vue +60 -39
- package/src/components/Calendar/CalendarTimeMarker.vue +9 -8
- package/src/components/Calendar/CalendarWeekDayEvent.vue +98 -42
- package/src/components/Calendar/CalendarWeekly.vue +77 -41
- package/src/components/Calendar/EventModalContent.vue +32 -16
- package/src/components/Calendar/NewEventModal.vue +19 -16
- package/src/components/Calendar/ShowMoreCalendarEvent.vue +11 -17
- package/src/components/Calendar/{calendarUtils.js → calendarUtils.ts} +76 -52
- package/src/components/Calendar/composables/{useCalendarData.js → useCalendarData.ts} +23 -11
- package/src/components/Calendar/composables/{useEventModal.js → useEventModal.ts} +16 -12
- package/src/components/Calendar/index.ts +12 -2
- package/src/components/Calendar/stories/CustomHeader.vue +1 -1
- package/src/components/Calendar/types.ts +106 -0
- package/src/components/Calendar/{useEventBase.js → useEventBase.ts} +40 -26
- package/src/components/Card.vue +2 -2
- package/src/components/Charts/ECharts.vue +1 -1
- package/src/components/Charts/NumberChart.vue +7 -7
- package/src/components/Charts/eChartOptions.ts +28 -13
- package/src/components/Checkbox/Checkbox.api.md +6 -0
- package/src/components/Checkbox/Checkbox.cy.ts +10 -2
- package/src/components/Checkbox/Checkbox.md +28 -0
- package/src/components/Checkbox/Checkbox.vue +9 -22
- package/src/components/Checkbox/stories/Group.vue +27 -0
- package/src/components/Checkbox/stories/HorizontalGroup.vue +24 -0
- package/src/components/Checkbox/stories/SettingRow.vue +23 -0
- package/src/components/Checkbox/stories/WithDescription.vue +27 -0
- package/src/components/Checkbox/types.ts +7 -0
- package/src/components/CodeEditor/CodeEditor.api.md +139 -0
- package/src/components/CodeEditor/CodeEditor.cy.ts +160 -0
- package/src/components/CodeEditor/CodeEditor.md +104 -0
- package/src/components/CodeEditor/CodeEditor.vue +556 -0
- package/src/components/CodeEditor/CodePreview.test.ts +49 -0
- package/src/components/CodeEditor/CodePreview.vue +45 -0
- package/src/components/CodeEditor/index.ts +17 -0
- package/src/components/CodeEditor/languages.ts +63 -0
- package/src/components/CodeEditor/stories/Default.vue +16 -0
- package/src/components/CodeEditor/stories/Labeling.vue +25 -0
- package/src/components/CodeEditor/stories/MaxHeight.vue +24 -0
- package/src/components/CodeEditor/stories/Preview.vue +36 -0
- package/src/components/CodeEditor/stories/Sizes.vue +15 -0
- package/src/components/CodeEditor/stories/Variants.vue +13 -0
- package/src/components/CodeEditor/theme.ts +272 -0
- package/src/components/CodeEditor/types.ts +69 -0
- package/src/components/Combobox/Combobox.api.md +19 -20
- package/src/components/Combobox/Combobox.cy.ts +54 -14
- package/src/components/Combobox/Combobox.md +4 -0
- package/src/components/Combobox/Combobox.vue +233 -247
- package/src/components/Combobox/ComboboxResults.vue +1 -1
- package/src/components/Combobox/stories/Clearable.vue +2 -2
- package/src/components/Combobox/stories/CreateNew.vue +1 -1
- package/src/components/Combobox/stories/Footer.vue +10 -2
- package/src/components/Combobox/stories/InDialog.vue +1 -1
- package/src/components/Combobox/types.ts +8 -29
- package/src/components/CommandPalette/CommandPaletteItem.vue +1 -1
- package/src/components/ContextMenu/ContextMenu.api.md +52 -0
- package/src/components/ContextMenu/ContextMenu.cy.ts +191 -0
- package/src/components/ContextMenu/ContextMenu.md +25 -0
- package/src/components/ContextMenu/ContextMenu.vue +106 -0
- package/src/components/ContextMenu/index.ts +2 -0
- package/src/components/ContextMenu/stories/FileList.vue +105 -0
- package/src/components/ContextMenu/stories/Groups.vue +95 -0
- package/src/components/ContextMenu/stories/Simple.vue +72 -0
- package/src/components/ContextMenu/types.ts +39 -0
- package/src/components/DatePicker/CalendarPanel.vue +128 -86
- package/src/components/DatePicker/DatePicker.vue +3 -9
- package/src/components/DatePicker/DateRangePicker.vue +4 -8
- package/src/components/DatePicker/DateTimePicker.cy.ts +4 -2
- package/src/components/DatePicker/DateTimePicker.vue +3 -9
- package/src/components/DatePicker/composables.ts +15 -37
- package/src/components/DatePicker/stories/Range.vue +1 -1
- package/src/components/DatePicker/types.ts +1 -1
- package/src/components/DesktopShell/DesktopShell.api.md +40 -0
- package/src/components/DesktopShell/DesktopShell.cy.ts +39 -0
- package/src/components/DesktopShell/DesktopShell.md +31 -0
- package/src/components/DesktopShell/DesktopShell.vue +81 -0
- package/src/components/DesktopShell/index.ts +3 -0
- package/src/components/DesktopShell/stories/Default.vue +97 -0
- package/src/components/DesktopShell/types.ts +2 -0
- package/src/components/Dialog/Dialog.api.md +7 -8
- package/src/components/Dialog/Dialog.md +4 -0
- package/src/components/Dialog/Dialog.vue +8 -7
- package/src/components/Dialog/stories/CommandPalette.vue +1 -1
- package/src/components/Dialog/stories/Wizard.vue +1 -1
- package/src/components/Dialogs.vue +11 -9
- package/src/components/Divider/Divider.api.md +1 -1
- package/src/components/Divider/Divider.md +4 -0
- package/src/components/Dropdown/Dropdown.api.md +10 -35
- package/src/components/Dropdown/Dropdown.md +10 -6
- package/src/components/Dropdown/Dropdown.vue +33 -47
- package/src/components/Dropdown/stories/{05_KebabMenu.vue → KebabMenu.vue} +3 -1
- package/src/components/Dropdown/stories/{06_UserMenu.vue → UserMenu.vue} +1 -1
- package/src/components/Dropdown/types.ts +25 -189
- package/src/components/Duration/Duration.api.md +92 -0
- package/src/components/Duration/Duration.cy.ts +183 -0
- package/src/components/Duration/Duration.md +98 -0
- package/src/components/Duration/Duration.vue +114 -0
- package/src/components/Duration/duration.ts +185 -0
- package/src/components/Duration/index.ts +8 -0
- package/src/components/Duration/stories/Default.vue +10 -0
- package/src/components/Duration/stories/Formats.vue +16 -0
- package/src/components/Duration/stories/RealWorld.vue +50 -0
- package/src/components/Duration/stories/Sizes.vue +15 -0
- package/src/components/Duration/stories/States.vue +21 -0
- package/src/components/Duration/types.ts +52 -0
- package/src/components/ErrorMessage/ErrorMessage.cy.ts +1 -1
- package/src/components/ErrorMessage/ErrorMessage.md +4 -0
- package/src/components/ErrorMessage/ErrorMessage.vue +1 -1
- package/src/components/FileUploader/FileUploader.api.md +36 -11
- package/src/components/FileUploader/FileUploader.cy.ts +66 -0
- package/src/components/FileUploader/FileUploader.md +4 -1
- package/src/components/FileUploader/FileUploader.vue +147 -106
- package/src/components/FileUploader/index.ts +6 -0
- package/src/components/FileUploader/types.ts +43 -0
- package/src/components/FormControl/FormControl.api.md +3 -4
- package/src/components/FormControl/FormControl.md +4 -0
- package/src/components/FormControl/stories/RealForm.vue +3 -3
- package/src/components/FormLabel.vue +5 -8
- package/src/components/HoverCard/HoverCard.api.md +100 -0
- package/src/components/HoverCard/HoverCard.cy.ts +103 -0
- package/src/components/HoverCard/HoverCard.md +52 -0
- package/src/components/HoverCard/HoverCard.vue +91 -0
- package/src/components/HoverCard/index.ts +2 -0
- package/src/components/HoverCard/stories/Arrow.vue +28 -0
- package/src/components/HoverCard/stories/Delays.vue +16 -0
- package/src/components/HoverCard/stories/Example.vue +28 -0
- package/src/components/HoverCard/types.ts +47 -0
- package/src/components/Icon/Icon.cy.ts +78 -0
- package/src/components/Icon/Icon.vue +50 -0
- package/src/components/Icon/index.ts +1 -0
- package/src/components/InputLabeling/InputDescription.vue +1 -1
- package/src/components/InputLabeling/InputError.vue +1 -1
- package/src/components/InputLabeling/InputLabel.vue +21 -7
- package/src/components/InputLabeling/RequiredIndicator.vue +1 -1
- package/src/components/ItemListRow/ItemListRow.vue +1 -1
- package/src/components/ItemListRow/stories/RowStates.vue +1 -1
- package/src/components/KeyboardShortcut.vue +4 -8
- package/src/components/KeyboardShortcutsModal/KeyboardShortcutsModal.api.md +22 -14
- package/src/components/KeyboardShortcutsModal/KeyboardShortcutsModal.vue +2 -2
- package/src/components/ListFilter/ListFilter.api.md +5 -6
- package/src/components/ListFilter/ListFilter.vue +161 -57
- package/src/components/ListFilter/NestedPopover.vue +17 -10
- package/src/components/ListFilter/SearchComplete.vue +31 -38
- package/src/components/ListItem.vue +1 -1
- package/src/components/ListView/ListEmptyState.vue +1 -1
- package/src/components/ListView/ListGroupHeader.vue +2 -2
- package/src/components/ListView/ListRow.vue +1 -1
- package/src/components/ListView/ListSelectBanner.vue +1 -1
- package/src/components/ListView/ListView.api.md +322 -6
- package/src/components/ListView/index.ts +25 -0
- package/src/components/ListView/stories/CustomList.vue +1 -1
- package/src/components/ListView/stories/GroupedRows.vue +1 -1
- package/src/components/LoadingIndicator.vue +13 -22
- package/src/components/LoadingText.vue +3 -13
- package/src/components/{Dropdown/DropdownMenuList.vue → Menu/Menu.vue} +110 -75
- package/src/components/{Dropdown/DropdownMenuItemContent.vue → Menu/MenuItemContent.vue} +23 -33
- package/src/components/{Dropdown/DropdownRenderContent.vue → Menu/MenuRenderContent.vue} +1 -1
- package/src/components/Menu/types.ts +225 -0
- package/src/components/{Dropdown → Menu}/utils.ts +36 -40
- package/src/components/MobileNav/MobileNav.api.md +70 -0
- package/src/components/MobileNav/MobileNav.cy.ts +89 -0
- package/src/components/MobileNav/MobileNav.md +34 -0
- package/src/components/MobileNav/MobileNav.vue +15 -0
- package/src/components/MobileNav/MobileNavItem.vue +125 -0
- package/src/components/MobileNav/index.ts +4 -0
- package/src/components/MobileNav/stories/Default.vue +40 -0
- package/src/components/MobileNav/types.ts +33 -0
- package/src/components/MobileShell/MobileShell.api.md +23 -0
- package/src/components/MobileShell/MobileShell.cy.ts +25 -0
- package/src/components/MobileShell/MobileShell.md +24 -0
- package/src/components/MobileShell/MobileShell.vue +41 -0
- package/src/components/MobileShell/index.ts +3 -0
- package/src/components/MobileShell/stories/Default.vue +75 -0
- package/src/components/MobileShell/types.ts +7 -0
- package/src/components/MonthPicker/MonthPicker.cy.ts +16 -0
- package/src/components/MonthPicker/MonthPicker.vue +19 -8
- package/src/components/MultiSelect/MultiSelect.api.md +3 -4
- package/src/components/MultiSelect/MultiSelect.md +42 -10
- package/src/components/MultiSelect/MultiSelect.vue +199 -227
- package/src/components/MultiSelect/MultiSelectResults.vue +1 -1
- package/src/components/MultiSelect/stories/Members.vue +1 -1
- package/src/components/MultiSelect/stories/TagsTrigger.vue +3 -3
- package/src/components/MultiSelect/types.ts +3 -3
- package/src/components/PageHeader/PageHeader.api.md +112 -0
- package/src/components/PageHeader/PageHeader.cy.ts +68 -0
- package/src/components/PageHeader/PageHeader.md +25 -0
- package/src/components/PageHeader/PageHeader.vue +13 -0
- package/src/components/PageHeader/PageHeaderBackButton.vue +29 -0
- package/src/components/PageHeader/PageHeaderBase.vue +51 -0
- package/src/components/PageHeader/PageHeaderMobile.vue +68 -0
- package/src/components/PageHeader/PageHeaderMobileTitle.vue +16 -0
- package/src/components/PageHeader/PageHeaderTarget.vue +13 -0
- package/src/components/PageHeader/PageHeaderTitle.vue +12 -0
- package/src/components/PageHeader/index.ts +7 -0
- package/src/components/PageHeader/stories/Default.vue +19 -0
- package/src/components/PageHeader/stories/Mobile.vue +24 -0
- package/src/components/PageHeader/target.ts +19 -0
- package/src/components/PageHeader/types.ts +19 -0
- package/src/components/Password/Password.md +4 -0
- package/src/components/Password/Password.vue +2 -2
- package/src/components/Popover/Popover.api.md +126 -42
- package/src/components/Popover/Popover.cy.ts +425 -41
- package/src/components/Popover/Popover.md +99 -4
- package/src/components/Popover/Popover.vue +288 -215
- package/src/components/Popover/index.ts +8 -1
- package/src/components/Popover/stories/Arrow.vue +16 -0
- package/src/components/Popover/stories/Bare.vue +20 -0
- package/src/components/Popover/stories/Click.vue +7 -4
- package/src/components/Popover/stories/Controlled.vue +22 -0
- package/src/components/Popover/stories/Dismissible.vue +19 -0
- package/src/components/Popover/stories/MatchTriggerWidth.vue +16 -0
- package/src/components/Popover/stories/SideAlign.vue +17 -0
- package/src/components/Popover/types.ts +101 -23
- package/src/components/Progress/Progress.cy.ts +2 -2
- package/src/components/Progress/Progress.md +4 -0
- package/src/components/Progress/Progress.vue +4 -4
- package/src/components/Rail/Rail.api.md +91 -0
- package/src/components/Rail/Rail.cy.ts +84 -0
- package/src/components/Rail/Rail.md +30 -0
- package/src/components/Rail/Rail.vue +16 -0
- package/src/components/Rail/RailItem.vue +134 -0
- package/src/components/Rail/RailItemBadge.vue +64 -0
- package/src/components/Rail/index.ts +2 -0
- package/src/components/Rail/stories/Default.vue +44 -0
- package/src/components/Rail/types.ts +37 -0
- package/src/components/Rating/Rating.md +4 -0
- package/src/components/Rating/Rating.vue +5 -8
- package/src/components/Rating/stories/CustomSlot.vue +2 -2
- package/src/components/ScrollArea/ScrollArea.api.md +59 -0
- package/src/components/ScrollArea/ScrollArea.vue +46 -0
- package/src/components/ScrollArea/ScrollBar.vue +101 -0
- package/src/components/ScrollArea/index.ts +2 -0
- package/src/components/Select/Select.cy.ts +16 -15
- package/src/components/Select/Select.md +4 -0
- package/src/components/Select/Select.vue +217 -203
- package/src/components/Select/stories/Example.vue +4 -3
- package/src/components/Select/stories/States.vue +1 -1
- package/src/components/Select/stories/TriggerSlots.vue +2 -2
- package/src/components/Select/utils.ts +4 -3
- package/src/components/SettingsDialog/SettingsBody.vue +23 -0
- package/src/components/SettingsDialog/SettingsContent.vue +7 -0
- package/src/components/SettingsDialog/SettingsDialog.api.md +273 -0
- package/src/components/SettingsDialog/SettingsDialog.cy.ts +126 -0
- package/src/components/SettingsDialog/SettingsDialog.md +43 -0
- package/src/components/SettingsDialog/SettingsDialog.vue +76 -0
- package/src/components/SettingsDialog/SettingsHeader.vue +36 -0
- package/src/components/SettingsDialog/SettingsNavGroup.vue +20 -0
- package/src/components/SettingsDialog/SettingsNavItem.vue +33 -0
- package/src/components/SettingsDialog/SettingsPanel.cy.ts +77 -0
- package/src/components/SettingsDialog/SettingsPanel.vue +26 -0
- package/src/components/SettingsDialog/SettingsRow.vue +52 -0
- package/src/components/SettingsDialog/SettingsSidebar.vue +16 -0
- package/src/components/SettingsDialog/index.ts +10 -0
- package/src/components/SettingsDialog/stories/Default.vue +99 -0
- package/src/components/SettingsDialog/stories/PanelBasic.vue +52 -0
- package/src/components/SettingsDialog/stories/panels/NotificationsPanel.vue +57 -0
- package/src/components/SettingsDialog/stories/panels/PreferencesPanel.vue +57 -0
- package/src/components/SettingsDialog/stories/panels/ProfilePanel.vue +38 -0
- package/src/components/SettingsDialog/stories/panels/UsersPanel.vue +83 -0
- package/src/components/SettingsDialog/types.ts +21 -0
- package/src/components/Sidebar/Sidebar.api.md +124 -65
- package/src/components/Sidebar/Sidebar.cy.ts +127 -76
- package/src/components/Sidebar/Sidebar.md +47 -3
- package/src/components/Sidebar/Sidebar.vue +64 -56
- package/src/components/Sidebar/SidebarCollapseToggle.vue +23 -0
- package/src/components/Sidebar/SidebarHeader.vue +76 -52
- package/src/components/Sidebar/SidebarItem.vue +159 -95
- package/src/components/Sidebar/SidebarItemIcon.vue +25 -0
- package/src/components/Sidebar/SidebarLabel.vue +34 -0
- package/src/components/Sidebar/SidebarSection.vue +29 -14
- package/src/components/Sidebar/index.ts +13 -2
- package/src/components/Sidebar/stories/Collapsed.vue +40 -0
- package/src/components/Sidebar/stories/Default.vue +153 -0
- package/src/components/Sidebar/stories/Legacy.vue +36 -0
- package/src/components/Sidebar/types.ts +105 -20
- package/src/components/Skeleton/Skeleton.cy.ts +21 -0
- package/src/components/Skeleton/Skeleton.md +21 -0
- package/src/components/Skeleton/Skeleton.vue +6 -0
- package/src/components/Skeleton/index.ts +1 -0
- package/src/components/Skeleton/stories/Card.vue +12 -0
- package/src/components/Skeleton/stories/List.vue +15 -0
- package/src/components/Skeleton/stories/Text.vue +11 -0
- package/src/components/Slider/Slider.api.md +1 -1
- package/src/components/Slider/Slider.cy.ts +29 -0
- package/src/components/Slider/Slider.md +10 -0
- package/src/components/Slider/Slider.vue +37 -9
- package/src/components/Slider/stories/NegativeValues.vue +12 -0
- package/src/components/Slider/types.ts +1 -1
- package/src/components/Spinner/Spinner.api.md +32 -0
- package/src/components/Spinner/Spinner.cy.ts +87 -0
- package/src/components/Spinner/Spinner.md +21 -0
- package/src/components/Spinner/Spinner.vue +168 -0
- package/src/components/Spinner/index.ts +2 -0
- package/src/components/Spinner/stories/InContext.vue +49 -0
- package/src/components/Spinner/stories/Sizes.vue +12 -0
- package/src/components/Spinner/stories/Themes.vue +10 -0
- package/src/components/Spinner/stories/Track.vue +12 -0
- package/src/components/Spinner/types.ts +14 -0
- package/src/components/Switch/Switch.md +4 -0
- package/src/components/Switch/Switch.vue +6 -23
- package/src/components/TabButtons/Pill.vue +161 -0
- package/src/components/TabButtons/TabButtons.api.md +52 -2
- package/src/components/TabButtons/TabButtons.cy.ts +18 -5
- package/src/components/TabButtons/TabButtons.md +49 -0
- package/src/components/TabButtons/TabButtons.vue +207 -109
- package/src/components/TabButtons/index.ts +11 -1
- package/src/components/TabButtons/pillTypes.ts +43 -0
- package/src/components/TabButtons/stories/PrefixSuffix.vue +65 -0
- package/src/components/TabButtons/stories/Sizes.vue +26 -0
- package/src/components/TabButtons/stories/Variants.vue +40 -0
- package/src/components/TabButtons/stories/Vertical.vue +64 -0
- package/src/components/TabButtons/types.ts +49 -0
- package/src/components/Tabs/Tabs.md +4 -0
- package/src/components/Tabs/Tabs.vue +1 -1
- package/src/components/TextEditor/TextEditor.cy.ts +1 -1
- package/src/components/TextEditor/TextEditor.md +3 -0
- package/src/components/TextEditor/TextEditor.vue +7 -4
- package/src/components/TextEditor/components/CodeBlockComponent.vue +4 -194
- package/src/components/TextEditor/components/FontColor.vue +1 -1
- package/src/components/TextEditor/components/LinkPopup.vue +1 -1
- package/src/components/TextEditor/components/MediaNodeView.vue +17 -17
- package/src/components/TextEditor/components/MentionList.vue +1 -1
- package/src/components/TextEditor/components/TextEditorBubbleMenu.vue +14 -5
- package/src/components/TextEditor/components/TextEditorFixedMenu.vue +3 -3
- package/src/components/TextEditor/components/{Menu.vue → TextEditorMenu.vue} +3 -3
- package/src/components/TextEditor/extensions/iframe/InsertIframe.vue +2 -2
- package/src/components/TextEditor/extensions/iframe/iframe-extension.ts +62 -19
- package/src/components/TextEditor/extensions/image-group/ImageGroupNodeView.vue +1 -1
- package/src/components/TextEditor/extensions/image-group/ImageGroupUploadDialog.vue +4 -4
- package/src/components/TextEditor/extensions/suggestion/SuggestionList.vue +1 -1
- package/src/components/TextEditor/extensions/toc-node/TocNodeView.vue +1 -1
- package/src/components/TextEditor/hljs-github.css +197 -0
- package/src/components/TextEditor/index.ts +13 -0
- package/src/components/TextInput/TextInput.cy.ts +8 -3
- package/src/components/TextInput/TextInput.md +4 -0
- package/src/components/TextInput/TextInput.vue +11 -15
- package/src/components/TextInput/stories/Slots.vue +1 -1
- package/src/components/Textarea/Textarea.cy.ts +1 -1
- package/src/components/Textarea/Textarea.md +4 -0
- package/src/components/Textarea/Textarea.vue +11 -15
- package/src/components/ThemeSwitcher/ThemePreview.vue +74 -0
- package/src/components/ThemeSwitcher/ThemeSwitcher.api.md +82 -0
- package/src/components/ThemeSwitcher/ThemeSwitcher.cy.ts +101 -0
- package/src/components/ThemeSwitcher/ThemeSwitcher.md +70 -0
- package/src/components/ThemeSwitcher/ThemeSwitcher.vue +145 -0
- package/src/components/ThemeSwitcher/index.ts +2 -0
- package/src/components/ThemeSwitcher/previews/PreviewWindow.vue +74 -0
- package/src/components/ThemeSwitcher/stories/Branded.vue +12 -0
- package/src/components/ThemeSwitcher/stories/Default.vue +7 -0
- package/src/components/ThemeSwitcher/stories/Menu.vue +53 -0
- package/src/components/ThemeSwitcher/stories/Toggle.vue +25 -0
- package/src/components/ThemeSwitcher/types.ts +35 -0
- package/src/components/TimePicker/TimePicker.api.md +67 -15
- package/src/components/TimePicker/TimePicker.cy.ts +130 -14
- package/src/components/TimePicker/TimePicker.md +6 -0
- package/src/components/TimePicker/TimePicker.vue +74 -19
- package/src/components/TimePicker/stories/Labeling.vue +21 -0
- package/src/components/TimePicker/stories/Range.vue +1 -1
- package/src/components/TimePicker/stories/SizesAndVariants.vue +23 -0
- package/src/components/TimePicker/stories/TwentyFour.vue +1 -1
- package/src/components/TimePicker/types.ts +15 -3
- package/src/components/TimePicker/utils.ts +82 -21
- package/src/components/Toast/Toast.md +1 -1
- package/src/components/Toast/Toast.sanitize.test.ts +50 -0
- package/src/components/Toast/Toast.test.ts +5 -0
- package/src/components/Toast/Toast.vue +7 -7
- package/src/components/Toast/ToastProvider.vue +18 -9
- package/src/components/Toast/stories/CustomIcon.vue +1 -1
- package/src/components/Toast/toast.ts +32 -8
- package/src/components/Tooltip/Tooltip.api.md +43 -5
- package/src/components/Tooltip/Tooltip.cy.ts +48 -0
- package/src/components/Tooltip/Tooltip.md +10 -0
- package/src/components/Tooltip/Tooltip.vue +20 -5
- package/src/components/Tooltip/TooltipBubble.vue +2 -2
- package/src/components/Tooltip/TooltipProvider.vue +53 -0
- package/src/components/Tooltip/index.ts +1 -0
- package/src/components/Tooltip/stories/Group.vue +22 -0
- package/src/components/Tooltip/stories/Slots.vue +2 -2
- package/src/components/Tooltip/types.ts +1 -1
- package/src/components/Tree/Tree.api.md +76 -18
- package/src/components/Tree/Tree.md +144 -2
- package/src/components/Tree/Tree.vue +276 -97
- package/src/components/Tree/TreeItem.vue +263 -0
- package/src/components/Tree/index.ts +9 -1
- package/src/components/Tree/stories/DragDrop.vue +94 -0
- package/src/components/Tree/stories/Example.vue +11 -34
- package/src/components/Tree/stories/ExpandAll.vue +48 -0
- package/src/components/Tree/stories/Guides.vue +49 -0
- package/src/components/Tree/stories/ListView.vue +74 -0
- package/src/components/Tree/tree.cy.ts +218 -90
- package/src/components/Tree/types.ts +114 -24
- package/src/components/Tree/useTreeDragDrop.ts +203 -0
- package/src/components/Tree/useTreeKeyboard.ts +109 -0
- package/src/components/VueGridLayout/Layout.vue +1 -1
- package/src/components/shared/picker/PickerShell.vue +20 -15
- package/src/components/shared/popover/PopoverPanel.vue +67 -0
- package/src/components/shared/popover/popoverPanel.css +102 -0
- package/src/components/shared/selection/utils.ts +6 -6
- package/src/composables/useAutofocusOnOpen.ts +2 -0
- package/src/composables/useScreenSize.ts +46 -0
- package/src/composables/useScrollContainer.ts +108 -0
- package/src/composables/useShortcut.ts +3 -0
- package/src/data-fetching/docStore.test.ts +74 -0
- package/src/data-fetching/docStore.ts +18 -7
- package/src/data-fetching/useCall/types.ts +1 -0
- package/src/data-fetching/useCall/useCall.test.ts +43 -0
- package/src/data-fetching/useCall/useCall.ts +17 -4
- package/src/data-fetching/useDoc/useDoc.test.ts +61 -2
- package/src/data-fetching/useDoc/useDoc.ts +35 -15
- package/src/data-fetching/useDoctype/useDoctype.ts +6 -5
- package/src/data-fetching/useFrappeFetch.ts +17 -4
- package/src/data-fetching/useList/types.ts +1 -0
- package/src/data-fetching/useList/useList.test.ts +40 -0
- package/src/data-fetching/useList/useList.ts +20 -13
- package/src/data-fetching/useNewDoc/useNewDoc.ts +9 -5
- package/src/directives/focus.ts +3 -3
- package/src/index.ts +105 -74
- package/src/mocks/handlers.ts +8 -0
- package/src/molecules/editor/Editor.cy.ts +6 -1
- package/src/molecules/editor/EditorBubbleMenu.vue +1 -1
- package/src/molecules/editor/EditorContent.vue +50 -9
- package/src/molecules/editor/EditorFixedMenu.vue +2 -1
- package/src/molecules/editor/EditorFloatingMenu.vue +1 -1
- package/src/molecules/editor/EditorTableMenu.vue +303 -0
- package/src/molecules/editor/MenuItems.vue +81 -69
- package/src/molecules/editor/commands.ts +10 -2
- package/src/molecules/editor/components/AttachmentNodeView.vue +115 -0
- package/src/molecules/editor/components/EditorDropZone.vue +105 -0
- package/src/molecules/editor/components/EditorPopover.vue +89 -0
- package/src/molecules/editor/components/MediaNodeView.vue +156 -49
- package/src/molecules/editor/components/MediaResizeHandles.vue +38 -0
- package/src/molecules/editor/components/MediaToolbar.vue +108 -54
- package/src/molecules/editor/components/TableContextMenu.vue +144 -0
- package/src/molecules/editor/components/UploadProgressIndicator.vue +33 -0
- package/src/molecules/editor/components/VideoControls.vue +208 -0
- package/src/molecules/editor/components/font-color/ColorSwatchGrid.vue +3 -5
- package/src/molecules/editor/components/font-color/fontColorController.ts +28 -23
- package/src/molecules/editor/components/font-color/swatches.ts +1 -1
- package/src/molecules/editor/components/media-node-view-controller.ts +4 -4
- package/src/molecules/editor/components/media-node-view-utils.test.ts +0 -13
- package/src/molecules/editor/components/media-node-view-utils.ts +0 -10
- package/src/molecules/editor/components/table-color/tableCellColorController.ts +80 -0
- package/src/molecules/editor/components/table-size-picker/TableSizePicker.vue +92 -0
- package/src/molecules/editor/components/table-size-picker/tableSizePickerController.ts +40 -0
- package/src/molecules/editor/composables/useEditorFileDrop.ts +117 -0
- package/src/molecules/editor/composables/useFloatingPopup.ts +46 -2
- package/src/molecules/editor/composables/useNodeViewResize.test.ts +60 -11
- package/src/molecules/editor/composables/useNodeViewResize.ts +80 -21
- package/src/molecules/editor/composables/useTableCellColorState.ts +78 -0
- package/src/molecules/editor/composables/useWindowFileDragging.ts +68 -0
- package/src/molecules/editor/extensions/attachment/attachment-engine.ts +250 -0
- package/src/molecules/editor/extensions/attachment/attachment-extension.ts +248 -0
- package/src/molecules/editor/extensions/attachment/attachment.flow.test.ts +80 -0
- package/src/molecules/editor/extensions/attachment/attachment.roundtrip.test.ts +50 -0
- package/src/molecules/editor/extensions/attachment/index.ts +5 -0
- package/src/molecules/editor/extensions/code-block/CodeBlockComponent.css +16 -26
- package/src/molecules/editor/extensions/code-block/CodeBlockComponent.vue +107 -22
- package/src/molecules/editor/extensions/content-paste/content-paste-extension.ts +5 -3
- package/src/molecules/editor/extensions/iframe/IframeInsertDialog.vue +34 -7
- package/src/molecules/editor/extensions/iframe/IframeNodeView.vue +54 -48
- package/src/molecules/editor/extensions/iframe/iframe-allowlist.ts +33 -4
- package/src/molecules/editor/extensions/iframe/iframe-commands.ts +49 -5
- package/src/molecules/editor/extensions/iframe/iframe-embed-utils.ts +30 -0
- package/src/molecules/editor/extensions/iframe/iframe-extension.ts +4 -4
- package/src/molecules/editor/extensions/iframe/iframeInsertDialogController.ts +12 -1
- package/src/molecules/editor/extensions/iframe/index.ts +4 -4
- package/src/molecules/editor/extensions/iframe/useIframeDialog.ts +25 -13
- package/src/molecules/editor/extensions/image/image-extension.ts +29 -11
- package/src/molecules/editor/extensions/image-group/ImageGroupGrid.vue +27 -11
- package/src/molecules/editor/extensions/image-group/ImageGroupGridCell.vue +55 -11
- package/src/molecules/editor/extensions/image-group/ImageGroupNodeView.vue +64 -31
- package/src/molecules/editor/extensions/image-group/ImageGroupUploadDialog.vue +84 -40
- package/src/molecules/editor/extensions/image-group/image-group-extension.ts +4 -3
- package/src/molecules/editor/extensions/image-group/useImageGroupDialog.ts +116 -17
- package/src/molecules/editor/extensions/link/LinkEditorPopup.vue +214 -71
- package/src/molecules/editor/extensions/link/link-click-plugin.ts +10 -15
- package/src/molecules/editor/extensions/link/link-commands.ts +24 -3
- package/src/molecules/editor/extensions/link/link-extension.ts +11 -2
- package/src/molecules/editor/extensions/link/link-popup-controller.test.ts +49 -0
- package/src/molecules/editor/extensions/link/link-popup-controller.ts +67 -2
- package/src/molecules/editor/extensions/link/link-shortcut-plugin.ts +7 -2
- package/src/molecules/editor/extensions/media-drop/media-drop-extension.ts +177 -0
- package/src/molecules/editor/extensions/shared/media-dimensions.ts +36 -3
- package/src/molecules/editor/extensions/shared/media-node-ops.ts +17 -0
- package/src/molecules/editor/extensions/shared/media-plugin.test.ts +60 -0
- package/src/molecules/editor/extensions/shared/media-plugin.ts +7 -37
- package/src/molecules/editor/extensions/shared/media-upload-engine.test.ts +39 -2
- package/src/molecules/editor/extensions/shared/media-upload-engine.ts +104 -10
- package/src/molecules/editor/extensions/shared/media-upload-state.ts +55 -0
- package/src/molecules/editor/extensions/shared/media-upload-types.ts +52 -1
- package/src/molecules/editor/extensions/shared/suggestion-helpers.ts +20 -0
- package/src/molecules/editor/extensions/shared/suggestion-types.ts +7 -0
- package/src/molecules/editor/extensions/shared/upload-types.ts +1 -0
- package/src/molecules/editor/extensions/slash-commands/slash-commands-extension.test.ts +38 -0
- package/src/molecules/editor/extensions/slash-commands/slash-commands-extension.ts +119 -55
- package/src/molecules/editor/extensions/suggestion/SuggestionList.vue +62 -22
- package/src/molecules/editor/extensions/suggestion/SuggestionListItem.vue +1 -1
- package/src/molecules/editor/extensions/suggestion/createSuggestionExtension.ts +4 -0
- package/src/molecules/editor/extensions/table/drag-scroll.ts +154 -0
- package/src/molecules/editor/extensions/table/table-cell-color.ts +188 -0
- package/src/molecules/editor/extensions/table/table-navigation.ts +560 -0
- package/src/molecules/editor/extensions/table/table-selection-overlay.ts +137 -0
- package/src/molecules/editor/extensions/toc-node/TocNodeView.vue +1 -1
- package/src/molecules/editor/extensions/toc-node/toc-render.ts +7 -3
- package/src/molecules/editor/extensions/video/video-extension.ts +72 -5
- package/src/molecules/editor/extensions.ts +176 -8
- package/src/molecules/editor/index.ts +9 -4
- package/src/molecules/editor/kits.test.ts +21 -1
- package/src/molecules/editor/kits.ts +56 -33
- package/src/molecules/editor/menu.test.ts +3 -1
- package/src/molecules/editor/menu.ts +180 -18
- package/src/molecules/editor/stories/Comment.vue +4 -4
- package/src/molecules/editor/stories/Inline.vue +1 -1
- package/src/molecules/editor/stories/Primitives.vue +1 -1
- package/src/molecules/editor/stories/RichText.vue +1 -1
- package/src/molecules/editor/style.css +80 -3
- package/src/molecules/editor/useEditor.test.ts +4 -0
- package/src/molecules/editor/useEditor.ts +7 -3
- package/src/molecules/list/List.cy.ts +626 -0
- package/src/molecules/list/List.vue +93 -0
- package/src/molecules/list/ListCell.vue +15 -0
- package/src/molecules/list/ListGroup.vue +40 -0
- package/src/molecules/list/ListHeader.vue +62 -0
- package/src/molecules/list/ListHeaderCell.vue +26 -0
- package/src/molecules/list/ListHeaderCellSort.vue +106 -0
- package/src/molecules/list/ListRow.vue +55 -0
- package/src/molecules/list/ListRowBase.vue +103 -0
- package/src/molecules/list/ListRows.vue +120 -0
- package/src/molecules/list/index.ts +24 -0
- package/src/molecules/list/list-context.ts +44 -0
- package/src/molecules/list/list.api.md +276 -0
- package/src/molecules/list/list.md +119 -0
- package/src/molecules/list/stories/Columns.vue +103 -0
- package/src/molecules/list/stories/Feed.vue +105 -0
- package/src/molecules/list/stories/Virtual.vue +31 -0
- package/src/molecules/list/style.css +173 -0
- package/src/molecules/list/types.ts +82 -0
- package/src/molecules/list/useVirtualRows.ts +80 -0
- package/src/resources/documentResource.d.ts +28 -0
- package/src/resources/documentResource.js +32 -4
- package/src/resources/documentResource.test.ts +111 -0
- package/src/resources/listResource.d.ts +33 -0
- package/src/resources/plugin.d.ts +7 -0
- package/src/resources/resources.d.ts +35 -0
- package/src/utils/{call.js → call.ts} +50 -9
- package/src/utils/config.ts +16 -1
- package/src/utils/confirmDialog.d.ts +17 -0
- package/src/utils/debounce.ts +6 -7
- package/src/utils/dialog.cy.ts +9 -9
- package/src/utils/fileSize.ts +36 -0
- package/src/utils/fileUploadHandler.ts +46 -6
- package/src/utils/frappeRequest.test.ts +79 -0
- package/src/utils/{frappeRequest.js → frappeRequest.ts} +76 -13
- package/src/utils/pageMeta.ts +1 -1
- package/src/utils/plugin.ts +58 -0
- package/src/utils/{request.js → request.ts} +28 -3
- package/src/utils/{socketio.js → socketio.ts} +11 -1
- package/src/utils/theme.ts +48 -57
- package/src/utils/useFileUpload.ts +80 -23
- package/tailwind/audit-token-drift.cjs +176 -0
- package/tailwind/colorPalette.js +69 -8
- package/tailwind/colors.json +1115 -397
- package/tailwind/figma-tokens-to-theme.js +364 -0
- package/tailwind/generated/colors.json +1217 -0
- package/tailwind/generated/effects.json +41 -0
- package/tailwind/generated/radius.json +20 -0
- package/tailwind/generated/typography.json +479 -0
- package/tailwind/migrate-tokens-v2.js +453 -0
- package/tailwind/migrate-tokens-v2.test.js +55 -0
- package/tailwind/plugin.js +220 -15
- package/tailwind/preset.js +15 -0
- package/tailwind/tokens.js +35 -37
- package/tsconfig.base.json +2 -2
- package/vitepress/components/Docs/CommandPalette.vue +214 -0
- package/vitepress/components/Docs/Demo.vue +60 -0
- package/vitepress/components/Docs/EmitsTable.vue +99 -0
- package/vitepress/components/Docs/MobileNavSheet.vue +148 -0
- package/vitepress/components/Docs/OnThisPage.vue +74 -0
- package/vitepress/components/Docs/PrevNextBtns.vue +58 -0
- package/vitepress/components/Docs/PropsTable.vue +185 -0
- package/vitepress/components/Docs/Search.vue +34 -0
- package/vitepress/components/Docs/Sidebar.vue +91 -0
- package/vitepress/components/Docs/SlotsTable.vue +99 -0
- package/vitepress/components/Docs/index.ts +13 -0
- package/vitepress/components/Docs/sidebarList.ts +33 -0
- package/vitepress/components/Layout.vue +58 -0
- package/vitepress/components/Navbar.vue +126 -0
- package/vitepress/components/index.ts +3 -0
- package/vitepress/composables/index.ts +3 -0
- package/vitepress/composables/useTheme.ts +39 -0
- package/vitepress/css/fonts/Inter-Italic.var.woff2 +0 -0
- package/vitepress/css/fonts/Inter.var.woff2 +0 -0
- package/vitepress/css/style.css +198 -0
- package/vitepress/index.d.ts +23 -0
- package/vitepress/index.node.ts +175 -0
- package/vitepress/index.ts +17 -0
- package/vitepress/plugins/colocatedComponentDocs.ts +164 -0
- package/vitepress/plugins/componentTransformer.ts +286 -0
- package/vitepress/plugins/index.ts +12 -0
- package/vitepress/state.ts +10 -0
- package/vitepress/theme/index.ts +21 -0
- package/frappe/telemetry/utils.ts +0 -15
- package/src/components/Badge/stories/Themes.vue +0 -10
- package/src/components/Badge/stories/Variants.vue +0 -10
- package/src/components/Button/stories/Icons.vue +0 -27
- package/src/components/Button/stories/Sizes.vue +0 -11
- package/src/components/Button/stories/Themes.vue +0 -10
- package/src/components/Button/stories/Variants.vue +0 -10
- package/src/components/Popover/stories/Hover.vue +0 -14
- package/src/components/Resource.vue +0 -21
- package/src/components/Sidebar/stories/Example.vue +0 -76
- package/src/components/Spinner.vue +0 -3
- package/src/components/TabButtons/TabButtons.story.vue +0 -22
- package/src/utils/plugin.js +0 -24
- /package/src/components/Dropdown/stories/{02_Shortcuts.vue → Shortcuts.vue} +0 -0
- /package/src/components/Dropdown/stories/{01_Simple.vue → Simple.vue} +0 -0
- /package/src/components/Dropdown/stories/{03_Submenus.vue → Submenus.vue} +0 -0
- /package/src/components/Dropdown/stories/{04_Switches.vue → Switches.vue} +0 -0
- /package/src/components/{Dropdown/DropdownRenderContentAsChild.vue → Menu/MenuRenderContentAsChild.vue} +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Combined type surface for `frappe-ui/vitepress`.
|
|
2
|
+
//
|
|
3
|
+
// At runtime the package resolves to two different files by export condition:
|
|
4
|
+
// `index.node.ts` (the Node config builder) for VitePress' config loader, and
|
|
5
|
+
// `index.ts` (the browser barrel: theme + components) for Vue code. TypeScript,
|
|
6
|
+
// however, doesn't apply the `node` condition — it would otherwise only ever
|
|
7
|
+
// see the browser half and flag `defineDocsConfig` as missing in config files.
|
|
8
|
+
//
|
|
9
|
+
// This declaration (wired as the `types` condition) merges both surfaces so
|
|
10
|
+
// editors resolve the full API regardless of context. The node-only names are
|
|
11
|
+
// disjoint from the browser names, so there are no `export *` collisions.
|
|
12
|
+
export * from './index'
|
|
13
|
+
export {
|
|
14
|
+
defineDocsConfig,
|
|
15
|
+
syncColocatedComponentDocs,
|
|
16
|
+
colocatedComponentDocs,
|
|
17
|
+
componentTransformer,
|
|
18
|
+
createComponentTransformer,
|
|
19
|
+
} from './index.node'
|
|
20
|
+
export type {
|
|
21
|
+
DefineDocsConfigOptions,
|
|
22
|
+
DocsThemeConfig,
|
|
23
|
+
} from './index.node'
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
import { defineConfig, type DefaultTheme, type UserConfig } from 'vitepress'
|
|
5
|
+
import { transformerStyleToClass } from '@shikijs/transformers'
|
|
6
|
+
// @ts-ignore — JS package without bundled types
|
|
7
|
+
import { lucideIcons } from 'frappe-ui/vite'
|
|
8
|
+
|
|
9
|
+
import { createComponentTransformer } from './plugins/componentTransformer.ts'
|
|
10
|
+
import colocatedComponentDocs from './plugins/colocatedComponentDocs.ts'
|
|
11
|
+
import type { SidebarSection } from './components/Docs/sidebarList.ts'
|
|
12
|
+
|
|
13
|
+
// frappe-ui package root — this file lives at <root>/vitepress/index.node.ts.
|
|
14
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
|
15
|
+
|
|
16
|
+
type HeadConfig = NonNullable<UserConfig['head']>[number]
|
|
17
|
+
|
|
18
|
+
// Extends the default theme with the extra fields the shared Sidebar reads.
|
|
19
|
+
export interface DocsThemeConfig extends DefaultTheme.Config {
|
|
20
|
+
name?: string
|
|
21
|
+
version?: string
|
|
22
|
+
githubUrl?: string
|
|
23
|
+
sections?: SidebarSection[]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface DefineDocsConfigOptions {
|
|
27
|
+
// Consumer project root (the docs dir). Drives every absolute path:
|
|
28
|
+
// vite resolve.alias, plugin sourceRoots, shiki cache.
|
|
29
|
+
rootDir: string
|
|
30
|
+
name: string
|
|
31
|
+
description: string
|
|
32
|
+
base?: string
|
|
33
|
+
githubUrl?: string
|
|
34
|
+
logo?: string
|
|
35
|
+
version?: string
|
|
36
|
+
// Data-driven IA tree rendered by the shared Sidebar.
|
|
37
|
+
sidebar: SidebarSection[]
|
|
38
|
+
// Merged with generated OG/Twitter defaults.
|
|
39
|
+
head?: HeadConfig[]
|
|
40
|
+
// Absolute source roots for component story/types snippet resolution.
|
|
41
|
+
sourceRoots?: string[]
|
|
42
|
+
// Opt-in: generate @include proxy pages for colocated component docs.
|
|
43
|
+
// `true` uses rootDir defaults; pass options to customize. Off by default
|
|
44
|
+
// since most consumers don't have the frappe-ui component/frappe layout.
|
|
45
|
+
colocatedDocs?: Parameters<typeof colocatedComponentDocs>[0] | boolean
|
|
46
|
+
// Extra resolve.alias entries (merged over rootDir-relative defaults).
|
|
47
|
+
alias?: Record<string, string>
|
|
48
|
+
// Hook for extra markdown-it plugins.
|
|
49
|
+
markdownConfig?: (md: any) => void
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function generatedHead(name: string, description: string): HeadConfig[] {
|
|
53
|
+
return [
|
|
54
|
+
['meta', { property: 'og:type', content: 'website' }],
|
|
55
|
+
['meta', { property: 'og:site_name', content: name }],
|
|
56
|
+
['meta', { property: 'og:title', content: name }],
|
|
57
|
+
['meta', { property: 'og:description', content: description }],
|
|
58
|
+
['meta', { name: 'twitter:card', content: 'summary_large_image' }],
|
|
59
|
+
['meta', { name: 'twitter:title', content: name }],
|
|
60
|
+
['meta', { name: 'twitter:description', content: description }],
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function defineDocsConfig(
|
|
65
|
+
options: DefineDocsConfigOptions,
|
|
66
|
+
): UserConfig<DocsThemeConfig> {
|
|
67
|
+
const {
|
|
68
|
+
rootDir,
|
|
69
|
+
name,
|
|
70
|
+
description,
|
|
71
|
+
base = '/',
|
|
72
|
+
githubUrl,
|
|
73
|
+
logo,
|
|
74
|
+
version,
|
|
75
|
+
sidebar,
|
|
76
|
+
head = [],
|
|
77
|
+
sourceRoots = [],
|
|
78
|
+
colocatedDocs = false,
|
|
79
|
+
alias = {},
|
|
80
|
+
markdownConfig,
|
|
81
|
+
} = options
|
|
82
|
+
|
|
83
|
+
const isDev = process.env.NODE_ENV !== 'production'
|
|
84
|
+
|
|
85
|
+
// transformerStyleToClass turns shiki inline styles into classes; its CSS
|
|
86
|
+
// is collected and injected via transformHead below.
|
|
87
|
+
const toClass = transformerStyleToClass({ classPrefix: 's_' })
|
|
88
|
+
|
|
89
|
+
return defineConfig<DocsThemeConfig>({
|
|
90
|
+
base,
|
|
91
|
+
srcDir: 'content',
|
|
92
|
+
cleanUrls: true,
|
|
93
|
+
lastUpdated: true,
|
|
94
|
+
title: name,
|
|
95
|
+
description,
|
|
96
|
+
head: [...generatedHead(name, description), ...head],
|
|
97
|
+
markdown: {
|
|
98
|
+
theme: { dark: 'tokyo-night', light: 'github-light' },
|
|
99
|
+
// In dev, transformerStyleToClass flushes only at buildEnd, so let
|
|
100
|
+
// shiki emit inline --shiki-light/dark vars instead.
|
|
101
|
+
codeTransformers: isDev ? [] : [toClass],
|
|
102
|
+
config(md) {
|
|
103
|
+
md.use(createComponentTransformer({ sourceRoots }))
|
|
104
|
+
markdownConfig?.(md)
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
themeConfig: {
|
|
108
|
+
// Consumed by the shared Sidebar/Navbar (SSR-safe; no package.json read).
|
|
109
|
+
name,
|
|
110
|
+
logo,
|
|
111
|
+
version,
|
|
112
|
+
githubUrl,
|
|
113
|
+
sidebar,
|
|
114
|
+
sections: sidebar,
|
|
115
|
+
// Enables VitePress' local search index, rendered by the shared Search.
|
|
116
|
+
search: { provider: 'local' },
|
|
117
|
+
},
|
|
118
|
+
vite: {
|
|
119
|
+
plugins: [
|
|
120
|
+
lucideIcons(),
|
|
121
|
+
...(colocatedDocs
|
|
122
|
+
? [
|
|
123
|
+
colocatedComponentDocs(
|
|
124
|
+
colocatedDocs === true ? { rootDir } : colocatedDocs,
|
|
125
|
+
),
|
|
126
|
+
]
|
|
127
|
+
: []),
|
|
128
|
+
],
|
|
129
|
+
resolve: {
|
|
130
|
+
alias: {
|
|
131
|
+
'@/components': path.resolve(rootDir, 'components'),
|
|
132
|
+
// Force Vite (client + SSR) to resolve the bare `frappe-ui/vitepress`
|
|
133
|
+
// specifier to the browser barrel — never the Node config entry this
|
|
134
|
+
// file lives in. This sidesteps SSR export-condition ambiguity: the
|
|
135
|
+
// `node` condition only ever serves VitePress' Node config loader.
|
|
136
|
+
'frappe-ui/vitepress': path.resolve(packageRoot, 'vitepress/index.ts'),
|
|
137
|
+
...alias,
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
// frappe-ui is often a symlink resolving outside the project root (e.g.
|
|
141
|
+
// bundled fonts/assets); allow the dev server to serve from its real dir.
|
|
142
|
+
server: {
|
|
143
|
+
fs: {
|
|
144
|
+
allow: [rootDir, fs.realpathSync(packageRoot)],
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
// The shared theme renders frappe-ui during SSR. Bundle frappe-ui and
|
|
148
|
+
// its ESM-only deps (which use extensionless imports Node can't resolve
|
|
149
|
+
// when externalized) into the server build.
|
|
150
|
+
ssr: {
|
|
151
|
+
noExternal: ['frappe-ui', 'dayjs'],
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
// Inject shiki's collected CSS into each page's <head>; the production
|
|
155
|
+
// CSS bundle is finalized before markdown runs, so this side-steps timing.
|
|
156
|
+
transformHead: () => {
|
|
157
|
+
const css = toClass.getCSS()
|
|
158
|
+
if (!css) return []
|
|
159
|
+
return [['style', { 'data-shiki': '' }, css]]
|
|
160
|
+
},
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export type {
|
|
165
|
+
SidebarSection,
|
|
166
|
+
SidebarItem,
|
|
167
|
+
} from './components/Docs/sidebarList.ts'
|
|
168
|
+
export { isActiveLink, getSidebarList } from './components/Docs/sidebarList.ts'
|
|
169
|
+
|
|
170
|
+
// Re-exports for convenience. Explicit .ts extensions keep this entry
|
|
171
|
+
// loadable when externalized by VitePress' Node-based config loader.
|
|
172
|
+
// Vue SFCs are intentionally omitted here — Node can't evaluate them. The
|
|
173
|
+
// browser barrel (index.ts, the `default` export condition) re-exports the
|
|
174
|
+
// components/theme for Vue code.
|
|
175
|
+
export * from './plugins/index.ts'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Browser / SSR barrel for the reusable VitePress docs theme — the
|
|
2
|
+
// `frappe-ui/vitepress` entry as seen by Vue code (theme, components,
|
|
3
|
+
// composables). It pulls in Vue SFCs, so it can only be evaluated by Vite,
|
|
4
|
+
// never by Node's config loader.
|
|
5
|
+
//
|
|
6
|
+
// The config builder (`defineDocsConfig`) lives in the sibling
|
|
7
|
+
// `index.node.ts`, exposed through the package's `node` export condition.
|
|
8
|
+
// Named exports only. Importing `theme` also loads the stylesheet as a side
|
|
9
|
+
// effect (via ./theme), so consumers don't need a separate style.css import.
|
|
10
|
+
export { theme } from './theme'
|
|
11
|
+
|
|
12
|
+
// Shared components (Layout, CommandPalette, Search, Sidebar, …) plus the
|
|
13
|
+
// `isActiveLink` / `getSidebarList` helpers and Sidebar* types.
|
|
14
|
+
export * from './components'
|
|
15
|
+
// Theme composables (useTheme / setTheme).
|
|
16
|
+
export * from './composables'
|
|
17
|
+
export { state } from './state'
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import type { Plugin, ViteDevServer } from 'vite'
|
|
4
|
+
|
|
5
|
+
// Author-facing layout: each component owns its docs:
|
|
6
|
+
// src/components/Button/Button.md (hand-written)
|
|
7
|
+
// src/components/Button/Button.api.md (auto-generated by propsgen)
|
|
8
|
+
// frappe/Link/Link.md (Frappe-integrated controls)
|
|
9
|
+
//
|
|
10
|
+
// VitePress wants every page under its srcDir (`docs/content`). Instead of
|
|
11
|
+
// reshaping srcDir or rewrites, this plugin keeps a thin proxy file at
|
|
12
|
+
// docs/content/docs/components/<name>.md
|
|
13
|
+
// docs/content/docs/frappe/<name>.md
|
|
14
|
+
// that simply `@include`s the colocated source. The proxy is auto-managed
|
|
15
|
+
// — never edit it by hand.
|
|
16
|
+
|
|
17
|
+
export interface SourceRootMap {
|
|
18
|
+
// Absolute dir holding `<Component>/<Component>.md` source files.
|
|
19
|
+
sourceDir: string
|
|
20
|
+
// Absolute dir where proxy `<name>.md` files are written.
|
|
21
|
+
proxyDir: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ColocatedComponentDocsOptions {
|
|
25
|
+
// Pairs of source/proxy dirs. Takes precedence over `rootDir` defaults.
|
|
26
|
+
sourceRoots?: SourceRootMap[]
|
|
27
|
+
// Consumer project root. Defaults the proxy dirs to
|
|
28
|
+
// `<rootDir>/content/docs/{components,frappe}` and source dirs to
|
|
29
|
+
// `<rootDir>/../src/components` and `<rootDir>/../frappe`.
|
|
30
|
+
rootDir?: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function rootDirRoots(rootDir: string): SourceRootMap[] {
|
|
34
|
+
return [
|
|
35
|
+
{
|
|
36
|
+
sourceDir: path.resolve(rootDir, '../src/components'),
|
|
37
|
+
proxyDir: path.resolve(rootDir, 'content/docs/components'),
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
sourceDir: path.resolve(rootDir, '../frappe'),
|
|
41
|
+
proxyDir: path.resolve(rootDir, 'content/docs/frappe'),
|
|
42
|
+
},
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function resolveRoots(options: ColocatedComponentDocsOptions): SourceRootMap[] {
|
|
47
|
+
if (options.sourceRoots && options.sourceRoots.length) return options.sourceRoots
|
|
48
|
+
if (options.rootDir) return rootDirRoots(options.rootDir)
|
|
49
|
+
// No legacy in-repo fallback: warn rather than resolve into nonexistent paths.
|
|
50
|
+
console.warn(
|
|
51
|
+
'[colocatedComponentDocs] no sourceRoots or rootDir provided — skipping proxy generation.',
|
|
52
|
+
)
|
|
53
|
+
return []
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const PROXY_HEADER =
|
|
57
|
+
'<!-- AUTO-GENERATED by colocatedComponentDocs — do not edit. Source: '
|
|
58
|
+
|
|
59
|
+
interface Entry {
|
|
60
|
+
name: string // 'Button'
|
|
61
|
+
source: string // absolute path to src/components/Button/Button.md
|
|
62
|
+
proxy: string // absolute path to docs/content/docs/components/button.md
|
|
63
|
+
proxyDir: string // absolute path to the proxy root that owns this entry
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function discover(sourceDir: string, proxyDir: string): Entry[] {
|
|
67
|
+
if (!fs.existsSync(sourceDir)) return []
|
|
68
|
+
const entries: Entry[] = []
|
|
69
|
+
for (const name of fs.readdirSync(sourceDir)) {
|
|
70
|
+
const source = path.join(sourceDir, name, `${name}.md`)
|
|
71
|
+
if (!fs.existsSync(source)) continue
|
|
72
|
+
entries.push({
|
|
73
|
+
name,
|
|
74
|
+
source,
|
|
75
|
+
proxy: path.join(proxyDir, `${name.toLowerCase()}.md`),
|
|
76
|
+
proxyDir,
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
return entries
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function proxyContent(entry: Entry) {
|
|
83
|
+
const includePath = path
|
|
84
|
+
.relative(path.dirname(entry.proxy), entry.source)
|
|
85
|
+
.split(path.sep)
|
|
86
|
+
.join('/')
|
|
87
|
+
const sourceRel = path
|
|
88
|
+
.relative(entry.proxyDir, entry.source)
|
|
89
|
+
.split(path.sep)
|
|
90
|
+
.join('/')
|
|
91
|
+
return `${PROXY_HEADER}${sourceRel} -->\n<!-- @include: ${includePath} -->\n`
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function isManagedProxy(filePath: string) {
|
|
95
|
+
if (!fs.existsSync(filePath)) return false
|
|
96
|
+
const first = fs.readFileSync(filePath, 'utf-8').split('\n', 1)[0] ?? ''
|
|
97
|
+
return first.startsWith(PROXY_HEADER)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function writeIfChanged(filePath: string, content: string) {
|
|
101
|
+
if (fs.existsSync(filePath)) {
|
|
102
|
+
const current = fs.readFileSync(filePath, 'utf-8')
|
|
103
|
+
if (current === content) return false
|
|
104
|
+
}
|
|
105
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true })
|
|
106
|
+
fs.writeFileSync(filePath, content, 'utf-8')
|
|
107
|
+
return true
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function syncColocatedComponentDocs(
|
|
111
|
+
options: ColocatedComponentDocsOptions = {},
|
|
112
|
+
) {
|
|
113
|
+
const roots = resolveRoots(options)
|
|
114
|
+
const allEntries: Entry[] = []
|
|
115
|
+
|
|
116
|
+
for (const { sourceDir, proxyDir } of roots) {
|
|
117
|
+
const entries = discover(sourceDir, proxyDir)
|
|
118
|
+
allEntries.push(...entries)
|
|
119
|
+
const expected = new Set(entries.map((e) => e.proxy))
|
|
120
|
+
|
|
121
|
+
for (const entry of entries) {
|
|
122
|
+
writeIfChanged(entry.proxy, proxyContent(entry))
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Remove orphan proxies — only those we created (header check), so
|
|
126
|
+
// hand-written legacy pages like badge.md, legacy.md stay untouched.
|
|
127
|
+
if (fs.existsSync(proxyDir)) {
|
|
128
|
+
for (const name of fs.readdirSync(proxyDir)) {
|
|
129
|
+
const filePath = path.join(proxyDir, name)
|
|
130
|
+
if (expected.has(filePath)) continue
|
|
131
|
+
if (isManagedProxy(filePath)) fs.unlinkSync(filePath)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return allEntries
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export default function colocatedComponentDocs(
|
|
140
|
+
options: ColocatedComponentDocsOptions = {},
|
|
141
|
+
): Plugin {
|
|
142
|
+
const roots = resolveRoots(options)
|
|
143
|
+
const syncAll = () => syncColocatedComponentDocs(options)
|
|
144
|
+
return {
|
|
145
|
+
name: 'colocated-component-docs',
|
|
146
|
+
enforce: 'pre',
|
|
147
|
+
buildStart() {
|
|
148
|
+
syncAll()
|
|
149
|
+
},
|
|
150
|
+
configureServer(server: ViteDevServer) {
|
|
151
|
+
syncAll()
|
|
152
|
+
const onChange = (file: string) => {
|
|
153
|
+
const matchesRoot = roots.some(({ sourceDir }) =>
|
|
154
|
+
file.startsWith(sourceDir),
|
|
155
|
+
)
|
|
156
|
+
if (!matchesRoot) return
|
|
157
|
+
if (!file.endsWith('.md')) return
|
|
158
|
+
syncAll()
|
|
159
|
+
}
|
|
160
|
+
server.watcher.on('add', onChange)
|
|
161
|
+
server.watcher.on('unlink', onChange)
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import type { MarkdownEnv, MarkdownRenderer } from 'vitepress'
|
|
2
|
+
import type StateCore from 'markdown-it/lib/rules_core/state_core'
|
|
3
|
+
import { existsSync } from 'node:fs'
|
|
4
|
+
import { dirname, isAbsolute, resolve } from 'node:path'
|
|
5
|
+
import {
|
|
6
|
+
baseParse,
|
|
7
|
+
NodeTypes,
|
|
8
|
+
type AttributeNode,
|
|
9
|
+
type DirectiveNode,
|
|
10
|
+
type ElementNode,
|
|
11
|
+
type SimpleExpressionNode,
|
|
12
|
+
type TextNode,
|
|
13
|
+
} from '@vue/compiler-dom'
|
|
14
|
+
|
|
15
|
+
export interface ComponentTransformerOptions {
|
|
16
|
+
// Absolute source root dirs, each holding `<Component>/stories/*.vue` and
|
|
17
|
+
// `<Component>/types.ts`. When omitted, defaults resolve relative to each
|
|
18
|
+
// markdown file (backward compatible with the in-repo docs layout).
|
|
19
|
+
sourceRoots?: string[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Resolve configured source roots; empty when no sourceRoots are provided
|
|
23
|
+
// (callers warn rather than silently resolve into nonexistent legacy paths).
|
|
24
|
+
function getRoots(mdDir: string, sourceRoots?: string[]): string[] {
|
|
25
|
+
if (sourceRoots && sourceRoots.length) {
|
|
26
|
+
return sourceRoots.map((r) => (isAbsolute(r) ? r : resolve(mdDir, r)))
|
|
27
|
+
}
|
|
28
|
+
return []
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function warnMissingRoots(tag: string, mdPath: string) {
|
|
32
|
+
console.warn(
|
|
33
|
+
`[componentTransformer] <${tag}> in ${mdPath} but no sourceRoots configured — skipping. Pass sourceRoots to defineDocsConfig.`,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function resolveSourcePath(roots: string[], relativePath: string): string {
|
|
38
|
+
for (const root of roots) {
|
|
39
|
+
const candidate = resolve(root, relativePath)
|
|
40
|
+
if (existsSync(candidate)) return candidate
|
|
41
|
+
}
|
|
42
|
+
return resolve(roots[0], relativePath)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface ParsedTag {
|
|
46
|
+
/** Static attributes: `foo="bar"` */
|
|
47
|
+
attrs: Record<string, string>
|
|
48
|
+
/** Bound attributes: `:foo="expr"` — value is the expression text */
|
|
49
|
+
binds: Record<string, string>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function parseSingleTag(source: string, tagName: string): ParsedTag | null {
|
|
53
|
+
let ast
|
|
54
|
+
try {
|
|
55
|
+
ast = baseParse(source)
|
|
56
|
+
} catch {
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
for (const child of ast.children) {
|
|
60
|
+
if (child.type !== NodeTypes.ELEMENT) continue
|
|
61
|
+
const element = child as ElementNode
|
|
62
|
+
if (element.tag !== tagName) continue
|
|
63
|
+
|
|
64
|
+
const attrs: Record<string, string> = {}
|
|
65
|
+
const binds: Record<string, string> = {}
|
|
66
|
+
for (const prop of element.props) {
|
|
67
|
+
if (prop.type === NodeTypes.ATTRIBUTE) {
|
|
68
|
+
const attr = prop as AttributeNode
|
|
69
|
+
attrs[attr.name] = (attr.value as TextNode | undefined)?.content ?? ''
|
|
70
|
+
} else if (prop.type === NodeTypes.DIRECTIVE) {
|
|
71
|
+
const dir = prop as DirectiveNode
|
|
72
|
+
if (
|
|
73
|
+
dir.name === 'bind' &&
|
|
74
|
+
dir.arg?.type === NodeTypes.SIMPLE_EXPRESSION
|
|
75
|
+
) {
|
|
76
|
+
const argName = (dir.arg as SimpleExpressionNode).content
|
|
77
|
+
const expr = (dir.exp as SimpleExpressionNode | undefined)?.content
|
|
78
|
+
binds[argName] = expr ?? ''
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return { attrs, binds }
|
|
83
|
+
}
|
|
84
|
+
return null
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getPreviewParts(name: string) {
|
|
88
|
+
const separatorIndex = name.indexOf('-')
|
|
89
|
+
if (separatorIndex === -1) {
|
|
90
|
+
return { componentName: name, storyFileName: name }
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
componentName: name.slice(0, separatorIndex),
|
|
94
|
+
storyFileName: name.slice(separatorIndex + 1),
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function getStoryImportName(storyFileName: string) {
|
|
99
|
+
const normalized = storyFileName.replace(/[^a-zA-Z0-9_$]+/g, ' ')
|
|
100
|
+
const pascal = normalized
|
|
101
|
+
.split(' ')
|
|
102
|
+
.filter(Boolean)
|
|
103
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
104
|
+
.join('')
|
|
105
|
+
return /^[A-Za-z_$]/.test(pascal) ? pascal : `Story${pascal}`
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function applyImports(state: StateCore, imports: string[]) {
|
|
109
|
+
if (imports.length === 0) return
|
|
110
|
+
const combined = imports.join('\n')
|
|
111
|
+
const scriptIdx = state.tokens.findIndex(
|
|
112
|
+
(t) => t.type === 'html_block' && /<script\s+setup>/.test(t.content),
|
|
113
|
+
)
|
|
114
|
+
if (scriptIdx === -1) {
|
|
115
|
+
const token = new state.Token('html_block', '', 0)
|
|
116
|
+
token.content = `<script setup>\n${combined}\n</script>\n`
|
|
117
|
+
// Unshifting earlier would shift every other token's index — do it
|
|
118
|
+
// after the main transform loop so its `tokenIdx` values stay valid.
|
|
119
|
+
state.tokens.unshift(token)
|
|
120
|
+
} else {
|
|
121
|
+
state.tokens[scriptIdx].content = state.tokens[scriptIdx].content.replace(
|
|
122
|
+
'</script>',
|
|
123
|
+
`${combined}\n</script>`,
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function getStoryPath(
|
|
129
|
+
roots: string[],
|
|
130
|
+
componentName: string,
|
|
131
|
+
storyFileName: string,
|
|
132
|
+
) {
|
|
133
|
+
const moleculeName =
|
|
134
|
+
componentName.charAt(0).toLowerCase() + componentName.slice(1)
|
|
135
|
+
const candidates: string[] = []
|
|
136
|
+
for (const root of roots) {
|
|
137
|
+
candidates.push(
|
|
138
|
+
resolve(root, componentName, 'stories', `${storyFileName}.vue`),
|
|
139
|
+
)
|
|
140
|
+
candidates.push(
|
|
141
|
+
resolve(root, moleculeName, 'stories', `${storyFileName}.vue`),
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
return candidates.find((candidate) => existsSync(candidate)) ?? candidates[0]
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function transformPreview(
|
|
148
|
+
state: StateCore,
|
|
149
|
+
tokenIdx: number,
|
|
150
|
+
tag: ParsedTag,
|
|
151
|
+
roots: string[],
|
|
152
|
+
): string | null {
|
|
153
|
+
const name = tag.attrs.name
|
|
154
|
+
if (!name) return null
|
|
155
|
+
|
|
156
|
+
const csr = tag.attrs.csr === 'true'
|
|
157
|
+
const { componentName, storyFileName } = getPreviewParts(name)
|
|
158
|
+
const storyImportName = getStoryImportName(storyFileName)
|
|
159
|
+
const componentPath = getStoryPath(roots, componentName, storyFileName)
|
|
160
|
+
|
|
161
|
+
// Forward every static attr except `csr`, which this plugin consumes
|
|
162
|
+
// itself (it's not a Vue prop). `name` is still a prop on the Demo
|
|
163
|
+
// component so it gets forwarded along with the rest.
|
|
164
|
+
const forwardedStatic = Object.entries(tag.attrs)
|
|
165
|
+
.filter(([key]) => key !== 'csr')
|
|
166
|
+
.map(([key, value]) => ` ${key}="${value}"`)
|
|
167
|
+
.join('')
|
|
168
|
+
const forwardedBinds = Object.entries(tag.binds)
|
|
169
|
+
.map(([key, expr]) => ` :${key}="${expr}"`)
|
|
170
|
+
.join('')
|
|
171
|
+
|
|
172
|
+
const openWrap = csr ? '<ClientOnly>' : ''
|
|
173
|
+
const closeWrap = csr ? '</ClientOnly>' : ''
|
|
174
|
+
|
|
175
|
+
state.tokens[tokenIdx].content =
|
|
176
|
+
`${openWrap}<ComponentPreview${forwardedStatic}${forwardedBinds}><${storyImportName} /><template #code>`
|
|
177
|
+
|
|
178
|
+
const code = new state.Token('fence', 'code', 0)
|
|
179
|
+
code.info = 'vue'
|
|
180
|
+
code.content = `<<< ${componentPath}`
|
|
181
|
+
// @ts-ignore snippets plugin reads `src` for the absolute path (Token lacks the field in types)
|
|
182
|
+
code.src = [componentPath]
|
|
183
|
+
|
|
184
|
+
const close = new state.Token('html_inline', '', 0)
|
|
185
|
+
close.content = `</template></ComponentPreview>${closeWrap}`
|
|
186
|
+
|
|
187
|
+
state.tokens.splice(tokenIdx + 1, 0, code, close)
|
|
188
|
+
|
|
189
|
+
return `import ${storyImportName} from '${componentPath}'`
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function transformPropsTable(
|
|
193
|
+
state: StateCore,
|
|
194
|
+
tokenIdx: number,
|
|
195
|
+
tag: ParsedTag,
|
|
196
|
+
roots: string[],
|
|
197
|
+
) {
|
|
198
|
+
const name = tag.attrs.name
|
|
199
|
+
const dataExpr = tag.binds.data
|
|
200
|
+
if (!name || !dataExpr) return
|
|
201
|
+
|
|
202
|
+
// The optional `folder` attribute lets a sub-component (e.g.
|
|
203
|
+
// DateTimePicker, which lives inside the DatePicker folder) point at
|
|
204
|
+
// the correct `types.ts`. When omitted, the folder matches `name`.
|
|
205
|
+
const componentFolder = tag.attrs.folder || name
|
|
206
|
+
const typesPath = resolveSourcePath(roots, `${componentFolder}/types.ts`)
|
|
207
|
+
|
|
208
|
+
state.tokens[tokenIdx].content =
|
|
209
|
+
`<PropsTable name="${name}" :data="${dataExpr}"><template #code>`
|
|
210
|
+
|
|
211
|
+
const code = new state.Token('fence', 'code', 0)
|
|
212
|
+
code.info = 'typescript'
|
|
213
|
+
code.content = `<<< ${typesPath}`
|
|
214
|
+
// @ts-ignore snippets plugin reads `src` for the absolute path (Token lacks the field in types)
|
|
215
|
+
code.src = [typesPath]
|
|
216
|
+
|
|
217
|
+
const close = new state.Token('html_inline', '', 0)
|
|
218
|
+
close.content = `</template></PropsTable>`
|
|
219
|
+
|
|
220
|
+
state.tokens.splice(tokenIdx + 1, 0, code, close)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function install(md: MarkdownRenderer, options: ComponentTransformerOptions) {
|
|
224
|
+
md.core.ruler.after('inline', 'component-preview', (state) => {
|
|
225
|
+
const env = state.env as MarkdownEnv
|
|
226
|
+
// VitePress calls parseInline with an empty env (e.g. title inference);
|
|
227
|
+
// there's nothing to transform without a source path.
|
|
228
|
+
const mdPath = env.realPath ?? env.path
|
|
229
|
+
if (!mdPath) return
|
|
230
|
+
const mdDir = dirname(mdPath)
|
|
231
|
+
const roots = getRoots(mdDir, options.sourceRoots)
|
|
232
|
+
const imports: string[] = []
|
|
233
|
+
|
|
234
|
+
// Walk in reverse so splicing in new tokens doesn't shift indices
|
|
235
|
+
// we haven't visited yet.
|
|
236
|
+
for (let i = state.tokens.length - 1; i >= 0; i--) {
|
|
237
|
+
const token = state.tokens[i]
|
|
238
|
+
if (token.type !== 'html_block' && token.type !== 'html_inline') continue
|
|
239
|
+
|
|
240
|
+
// Cheap text prefilter — Vue's parser is fast but no point invoking
|
|
241
|
+
// it on tokens that clearly don't contain our tags.
|
|
242
|
+
if (token.content.includes('<ComponentPreview')) {
|
|
243
|
+
const tag = parseSingleTag(token.content, 'ComponentPreview')
|
|
244
|
+
if (tag) {
|
|
245
|
+
if (!roots.length) {
|
|
246
|
+
warnMissingRoots('ComponentPreview', mdPath)
|
|
247
|
+
continue
|
|
248
|
+
}
|
|
249
|
+
const importStmt = transformPreview(state, i, tag, roots)
|
|
250
|
+
if (importStmt) imports.push(importStmt)
|
|
251
|
+
}
|
|
252
|
+
} else if (token.content.includes('<PropsTable')) {
|
|
253
|
+
const tag = parseSingleTag(token.content, 'PropsTable')
|
|
254
|
+
if (tag) {
|
|
255
|
+
if (!roots.length) {
|
|
256
|
+
warnMissingRoots('PropsTable', mdPath)
|
|
257
|
+
continue
|
|
258
|
+
}
|
|
259
|
+
transformPropsTable(state, i, tag, roots)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
applyImports(state, imports)
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Factory: returns a markdown-it plugin bound to the given source roots.
|
|
269
|
+
export function createComponentTransformer(
|
|
270
|
+
options: ComponentTransformerOptions = {},
|
|
271
|
+
) {
|
|
272
|
+
return (md: MarkdownRenderer) => install(md, options)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Backward compatible: usable directly as `md.use(componentTransformer)`
|
|
276
|
+
// (first arg is the renderer) or as a factory `componentTransformer(opts)`.
|
|
277
|
+
export default function componentTransformer(
|
|
278
|
+
mdOrOptions?: MarkdownRenderer | ComponentTransformerOptions,
|
|
279
|
+
) {
|
|
280
|
+
if (mdOrOptions && 'core' in (mdOrOptions as MarkdownRenderer)) {
|
|
281
|
+
return install(mdOrOptions as MarkdownRenderer, {})
|
|
282
|
+
}
|
|
283
|
+
return createComponentTransformer(
|
|
284
|
+
(mdOrOptions as ComponentTransformerOptions) ?? {},
|
|
285
|
+
)
|
|
286
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export {
|
|
2
|
+
default as componentTransformer,
|
|
3
|
+
createComponentTransformer,
|
|
4
|
+
type ComponentTransformerOptions,
|
|
5
|
+
} from './componentTransformer.ts'
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
default as colocatedComponentDocs,
|
|
9
|
+
syncColocatedComponentDocs,
|
|
10
|
+
type ColocatedComponentDocsOptions,
|
|
11
|
+
type SourceRootMap,
|
|
12
|
+
} from './colocatedComponentDocs.ts'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { reactive } from 'vue'
|
|
2
|
+
import type { SidebarSection } from './components/Docs/sidebarList'
|
|
3
|
+
|
|
4
|
+
// Shared cross-component UI state for the docs layout.
|
|
5
|
+
export const state = reactive({
|
|
6
|
+
mobsidebar: false,
|
|
7
|
+
mobnavbar: false,
|
|
8
|
+
searchDialog: false,
|
|
9
|
+
sidebarList: [] as SidebarSection[],
|
|
10
|
+
})
|