├── .github └── workflows │ └── node.js.yml ├── .gitignore ├── .node-version ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── Procfile ├── README.md ├── docs ├── .postcssrc.js ├── .vitepress │ ├── config.ts │ └── theme │ │ ├── clear.css │ │ ├── custom.css │ │ └── index.js ├── assets │ ├── github.png │ └── logo.svg ├── components │ ├── PLAYGROUND │ │ ├── PLAYGROUND.md │ │ └── examples │ │ │ └── SlotListenerExample.vue │ ├── accordion.md │ ├── accordion │ │ └── examples │ │ │ ├── FwbAccordionExample.vue │ │ │ ├── FwbAccordionExampleCollapsed.vue │ │ │ ├── FwbAccordionExampleFlushed.vue │ │ │ ├── FwbAccordionExamplePersistent.vue │ │ │ └── FwbAccordionExampleStyling.vue │ ├── alert.md │ ├── alert │ │ └── examples │ │ │ ├── FwbAlertExampleBorder.vue │ │ │ ├── FwbAlertExampleBorderAccent.vue │ │ │ ├── FwbAlertExampleCustomContent.vue │ │ │ ├── FwbAlertExampleDismissable.vue │ │ │ ├── FwbAlertExampleIcon.vue │ │ │ ├── FwbAlertExampleList.vue │ │ │ └── FwbAlertExampleType.vue │ ├── avatar.md │ ├── avatar │ │ └── examples │ │ │ ├── FwbAvatarExample.vue │ │ │ ├── FwbAvatarExampleAlt.vue │ │ │ ├── FwbAvatarExampleBordered.vue │ │ │ ├── FwbAvatarExampleIcon.vue │ │ │ ├── FwbAvatarExampleInitials.vue │ │ │ ├── FwbAvatarExamplePlaceholder.vue │ │ │ ├── FwbAvatarExampleSize.vue │ │ │ ├── FwbAvatarExampleStack.vue │ │ │ ├── FwbAvatarExampleStatus.vue │ │ │ └── FwbAvatarExampleStatusPosition.vue │ ├── badge.md │ ├── badge │ │ └── examples │ │ │ ├── FwbBadgeExample.vue │ │ │ ├── FwbBadgeExampleIcon.vue │ │ │ ├── FwbBadgeExampleIconOnly.vue │ │ │ ├── FwbBadgeExampleLink.vue │ │ │ └── FwbBadgeExampleSize.vue │ ├── blockquote.md │ ├── breadcrumb.md │ ├── breadcrumb │ │ └── examples │ │ │ ├── FwbBreadcrumbExample.vue │ │ │ ├── FwbBreadcrumbExampleCustomIcons.vue │ │ │ └── FwbBreadcrumbExampleSolid.vue │ ├── button-group.md │ ├── button.md │ ├── button │ │ └── examples │ │ │ ├── ButtonLinkExample.vue │ │ │ ├── FwbButtonExampleColor.vue │ │ │ ├── FwbButtonExampleDisabled.vue │ │ │ ├── FwbButtonExampleGradientDuotone.vue │ │ │ ├── FwbButtonExampleGradientMonochrome.vue │ │ │ ├── FwbButtonExampleLink.vue │ │ │ ├── FwbButtonExampleLoading.vue │ │ │ ├── FwbButtonExampleOutline.vue │ │ │ ├── FwbButtonExampleOutlineGradient.vue │ │ │ ├── FwbButtonExamplePill.vue │ │ │ ├── FwbButtonExampleShadow.vue │ │ │ ├── FwbButtonExampleSize.vue │ │ │ ├── FwbButtonExampleSlot.vue │ │ │ ├── FwbButtonExampleSlotPrefix.vue │ │ │ ├── FwbButtonExampleSlotSuffix.vue │ │ │ └── FwbButtonExampleSquare.vue │ ├── buttonGroup │ │ └── examples │ │ │ ├── FwbButtonGroupExample.vue │ │ │ ├── FwbButtonGroupExampleDropdown.vue │ │ │ └── FwbButtonGroupExampleIcon.vue │ ├── card.md │ ├── card │ │ └── examples │ │ │ ├── FwbCardExample.vue │ │ │ ├── FwbCardExampleHorizontal.vue │ │ │ └── FwbCardExampleImage.vue │ ├── carousel.md │ ├── carousel │ │ └── examples │ │ │ ├── FwbCarouselExample.vue │ │ │ ├── FwbCarouselExamplePictures.vue │ │ │ ├── FwbCarouselExampleSlide.vue │ │ │ ├── FwbCarouselExampleSlideInterval.vue │ │ │ ├── FwbCarouselExampleWithoutControls.vue │ │ │ └── FwbCarouselExampleWithoutIndicators.vue │ ├── checkbox.md │ ├── checkbox │ │ └── examples │ │ │ ├── FwbCheckboxExample.vue │ │ │ ├── FwbCheckboxExampleChecked.vue │ │ │ ├── FwbCheckboxExampleDisabled.vue │ │ │ ├── FwbCheckboxExampleGroup.vue │ │ │ ├── FwbCheckboxExampleHelper.vue │ │ │ └── FwbCheckboxExampleLink.vue │ ├── dropdown.md │ ├── dropdown │ │ └── examples │ │ │ ├── FwbDropdownExampleAlignment.vue │ │ │ ├── FwbDropdownExampleButtonColors.vue │ │ │ ├── FwbDropdownExampleButtonGroup.vue │ │ │ ├── FwbDropdownExampleCloseInside.vue │ │ │ ├── FwbDropdownExampleDisabled.vue │ │ │ ├── FwbDropdownExampleListGroup.vue │ │ │ ├── FwbDropdownExamplePlacement.vue │ │ │ └── FwbDropdownExampleTrigger.vue │ ├── fileInput.md │ ├── fileInput │ │ └── examples │ │ │ ├── FwbFileInputExample.vue │ │ │ ├── FwbFileInputExampleDropZone.vue │ │ │ ├── FwbFileInputExampleHelper.vue │ │ │ ├── FwbFileInputExampleMultiple.vue │ │ │ └── FwbFileInputExampleSize.vue │ ├── flowbiteThemable │ │ ├── examples │ │ │ ├── FlowbiteThemableExampleButton.vue │ │ │ ├── FlowbiteThemableExampleDropdown.vue │ │ │ └── FlowbiteThemableExampleTabs.vue │ │ └── flowbiteThemable.md │ ├── footer.md │ ├── footer │ │ └── examples │ │ │ ├── FwbFooterExample.vue │ │ │ ├── FwbFooterExampleSitemapLinks.vue │ │ │ ├── FwbFooterExampleSocialMediaIcons.vue │ │ │ ├── FwbFooterExampleSticky.vue │ │ │ └── FwbFooterExampleWithLogo.vue │ ├── heading.md │ ├── image.md │ ├── input.md │ ├── input │ │ └── examples │ │ │ ├── FwbInputExample.vue │ │ │ ├── FwbInputExampleDisabled.vue │ │ │ ├── FwbInputExampleHelper.vue │ │ │ ├── FwbInputExamplePrefix.vue │ │ │ ├── FwbInputExampleRequired.vue │ │ │ ├── FwbInputExampleSize.vue │ │ │ ├── FwbInputExampleStyling.vue │ │ │ ├── FwbInputExampleSuffix.vue │ │ │ └── FwbInputExampleValidation.vue │ ├── jumbotron.md │ ├── jumbotron │ │ └── examples │ │ │ ├── FwbJumbotronBackgroundImageExample.vue │ │ │ ├── FwbJumbotronExample.vue │ │ │ ├── FwbJumbotronFormExample.vue │ │ │ ├── FwbJumbotronGradientExample.vue │ │ │ └── FwbJumbotronVideoExample.vue │ ├── link.md │ ├── list-group.md │ ├── listGroup │ │ └── examples │ │ │ ├── FwbListGroupExample.vue │ │ │ ├── FwbListGroupExampleDisabled.vue │ │ │ ├── FwbListGroupExampleHover.vue │ │ │ └── FwbListGroupExampleIcon.vue │ ├── modal.md │ ├── modal │ │ └── examples │ │ │ ├── FwbModalExample.vue │ │ │ ├── FwbModalExampleEscapable.vue │ │ │ ├── FwbModalExampleFocusTrap.vue │ │ │ ├── FwbModalExamplePersistent.vue │ │ │ ├── FwbModalExamplePosition.vue │ │ │ └── FwbModalExampleSize.vue │ ├── navbar.md │ ├── navbar │ │ └── examples │ │ │ ├── FwbNavbarExample.vue │ │ │ ├── FwbNavbarExampleActionButton.vue │ │ │ ├── FwbNavbarExampleCustomMobileIcon.vue │ │ │ └── FwbNavbarExampleSolid.vue │ ├── pagination.md │ ├── pagination │ │ └── examples │ │ │ ├── FwbPaginationExample.vue │ │ │ ├── FwbPaginationExampleCustomLabels.vue │ │ │ ├── FwbPaginationExampleCustomLength.vue │ │ │ ├── FwbPaginationExampleFirstLast.vue │ │ │ ├── FwbPaginationExampleIcons.vue │ │ │ ├── FwbPaginationExampleNavigation.vue │ │ │ ├── FwbPaginationExampleNavigationIcons.vue │ │ │ ├── FwbPaginationExampleSlots.vue │ │ │ ├── FwbPaginationExampleSlotsAdvanced.vue │ │ │ └── FwbPaginationExampleTable.vue │ ├── paragraph.md │ ├── progress.md │ ├── progress │ │ └── examples │ │ │ ├── FwbProgressExample.vue │ │ │ ├── FwbProgressExampleColor.vue │ │ │ ├── FwbProgressExampleLabelInside.vue │ │ │ ├── FwbProgressExampleLabelOutside.vue │ │ │ └── FwbProgressExampleSize.vue │ ├── radio.md │ ├── radio │ │ └── examples │ │ │ ├── FwbRadioExample.vue │ │ │ ├── FwbRadioExampleBordered.vue │ │ │ ├── FwbRadioExampleDisabled.vue │ │ │ ├── FwbRadioExampleInline.vue │ │ │ ├── FwbRadioExampleLink.vue │ │ │ ├── FwbRadioExampleList.vue │ │ │ └── FwbRadioExampleListHorizontal.vue │ ├── range.md │ ├── range │ │ └── examples │ │ │ ├── FwbRangeExample.vue │ │ │ ├── FwbRangeExampleDisabled.vue │ │ │ ├── FwbRangeExampleMinMax.vue │ │ │ ├── FwbRangeExampleSize.vue │ │ │ └── FwbRangeExampleSteps.vue │ ├── rating.md │ ├── rating │ │ └── examples │ │ │ ├── FwbRatingExample.vue │ │ │ ├── FwbRatingExampleCount.vue │ │ │ ├── FwbRatingExampleStarSizes.vue │ │ │ └── FwbRatingExampleWithText.vue │ ├── select.md │ ├── select │ │ └── examples │ │ │ ├── FwbSelectExample.vue │ │ │ ├── FwbSelectExampleDisabled.vue │ │ │ ├── FwbSelectExampleHelper.vue │ │ │ ├── FwbSelectExampleSize.vue │ │ │ ├── FwbSelectExampleUnderlined.vue │ │ │ └── FwbSelectExampleValidation.vue │ ├── sidebar.md │ ├── sidebar │ │ └── examples │ │ │ ├── FwbSidebarCtaExample.vue │ │ │ ├── FwbSidebarDropdownExample.vue │ │ │ ├── FwbSidebarExample.vue │ │ │ ├── FwbSidebarGroupExample.vue │ │ │ └── FwbSidebarLogoExample.vue │ ├── spinner.md │ ├── spinner │ │ └── examples │ │ │ ├── FwbSpinnerExample.vue │ │ │ ├── FwbSpinnerExampleColor.vue │ │ │ └── FwbSpinnerExampleSize.vue │ ├── table.md │ ├── table │ │ └── examples │ │ │ ├── FwbTableExample.vue │ │ │ ├── FwbTableExampleHoverable.vue │ │ │ ├── FwbTableExampleStriped.vue │ │ │ └── FwbTableExampleStripedColumns.vue │ ├── tabs.md │ ├── tabs │ │ └── examples │ │ │ ├── FwbTabsExample.vue │ │ │ ├── FwbTabsExampleDirective.vue │ │ │ ├── FwbTabsExampleInteraction.vue │ │ │ ├── FwbTabsExamplePills.vue │ │ │ └── FwbTabsExampleUnderline.vue │ ├── textarea.md │ ├── textarea │ │ └── examples │ │ │ ├── FwbTextareaExample.vue │ │ │ ├── FwbTextareaExampleComment.vue │ │ │ ├── FwbTextareaExampleDisabled.vue │ │ │ └── FwbTextareaExampleFormId.vue │ ├── timeline.md │ ├── timeline │ │ └── examples │ │ │ ├── FwbTimelineExample.vue │ │ │ ├── FwbTimelineExampleHorizontal.vue │ │ │ └── FwbTimelineExampleWithIcons.vue │ ├── toast.md │ ├── toast │ │ └── examples │ │ │ ├── FwbToastExample.vue │ │ │ ├── FwbToastExampleClosable.vue │ │ │ ├── FwbToastExampleDivide.vue │ │ │ ├── FwbToastExampleIcon.vue │ │ │ ├── FwbToastExampleInteractive.vue │ │ │ └── FwbToastExampleMessage.vue │ ├── toastProvider │ │ ├── examples │ │ │ ├── FwbToastProviderExample.vue │ │ │ ├── FwbToastProviderExampleChild.vue │ │ │ └── UpdateToast.vue │ │ └── toastProvider.md │ ├── toggle.md │ ├── toggle │ │ └── examples │ │ │ ├── FwbToggleExample.vue │ │ │ ├── FwbToggleExampleChecked.vue │ │ │ ├── FwbToggleExampleColors.vue │ │ │ ├── FwbToggleExampleDisabled.vue │ │ │ ├── FwbToggleExampleOrder.vue │ │ │ └── FwbToggleExampleSize.vue │ ├── tooltip.md │ ├── tooltip │ │ └── examples │ │ │ ├── FwbTooltipExample.vue │ │ │ ├── FwbTooltipExampleGroup.vue │ │ │ ├── FwbTooltipExamplePosition.vue │ │ │ ├── FwbTooltipExampleStyle.vue │ │ │ └── FwbTooltipExampleTrigger.vue │ └── typography │ │ ├── blockquote │ │ ├── FwbBlockquoteAlignExample.vue │ │ ├── FwbBlockquoteExample.vue │ │ ├── FwbBlockquoteSizeExample.vue │ │ └── FwbBlockquoteSolidExample.vue │ │ ├── heading │ │ ├── FwbHExampleColor.vue │ │ ├── FwbHExampleCustom.vue │ │ ├── FwbHExampleLevel1.vue │ │ ├── FwbHExampleLevel2.vue │ │ ├── FwbHExampleLevel3.vue │ │ ├── FwbHExampleLevel4.vue │ │ ├── FwbHExampleLevel5.vue │ │ └── FwbHExampleLevel6.vue │ │ ├── image │ │ ├── FwbImgExample.vue │ │ ├── FwbImgExampleAlign.vue │ │ ├── FwbImgExampleCaption.vue │ │ ├── FwbImgExampleCustom.vue │ │ ├── FwbImgExampleGrayscale.vue │ │ └── FwbImgExampleSize.vue │ │ ├── link │ │ ├── FwbAExample.vue │ │ ├── FwbAExampleCustom.vue │ │ └── FwbAExampleParagraph.vue │ │ └── p │ │ ├── FwbPExample.vue │ │ └── FwbPExampleCustom.vue ├── index.md ├── pages │ └── getting-started.md └── vite.config.ts ├── env.d.ts ├── eslint.config.js ├── package-lock.json ├── package.json ├── src ├── components │ ├── FwbAccordion │ │ ├── FwbAccordion.vue │ │ ├── FwbAccordionContent.vue │ │ ├── FwbAccordionHeader.vue │ │ ├── FwbAccordionPanel.vue │ │ ├── composables │ │ │ ├── useAccordionContentClasses.ts │ │ │ ├── useAccordionHeaderClasses.ts │ │ │ ├── useAccordionPanelClasses.ts │ │ │ └── useAccordionState.ts │ │ └── types.ts │ ├── FwbAlert │ │ ├── FwbAlert.vue │ │ └── types.ts │ ├── FwbAvatar │ │ ├── FwbAvatar.vue │ │ ├── FwbAvatarStack.vue │ │ ├── FwbAvatarStackCounter.vue │ │ ├── composables │ │ │ └── useAvatarClasses.ts │ │ └── types.ts │ ├── FwbBadge │ │ ├── FwbBadge.vue │ │ ├── composables │ │ │ └── useBadgeClasses.ts │ │ └── types.ts │ ├── FwbBreadcrumb │ │ ├── FwbBreadcrumb.vue │ │ ├── FwbBreadcrumbItem.vue │ │ ├── composables │ │ │ ├── useBreadcrumbClasses.ts │ │ │ └── useBreadcrumbItemClasses.ts │ │ └── types.ts │ ├── FwbButton │ │ ├── FwbButton.vue │ │ ├── composables │ │ │ ├── useButtonClasses.ts │ │ │ └── useButtonSpinner.ts │ │ ├── tests │ │ │ └── Button.spec.ts │ │ └── types.ts │ ├── FwbButtonGroup │ │ └── FwbButtonGroup.vue │ ├── FwbCard │ │ ├── FwbCard.vue │ │ ├── composables │ │ │ └── useCardClasses.ts │ │ └── types.ts │ ├── FwbCarousel │ │ ├── FwbCarousel.vue │ │ └── types.ts │ ├── FwbCheckbox │ │ ├── FwbCheckbox.vue │ │ └── composables │ │ │ └── useCheckboxClasses.ts │ ├── FwbDropdown │ │ ├── FwbDropdown.vue │ │ ├── composables │ │ │ └── useDropdownClasses.ts │ │ └── types.ts │ ├── FwbFileInput │ │ ├── FwbFileInput.vue │ │ └── composables │ │ │ └── useFileInputClasses.ts │ ├── FwbFooter │ │ ├── FwbFooter.vue │ │ ├── FwbFooterBrand.vue │ │ ├── FwbFooterCopyright.vue │ │ ├── FwbFooterIcon.vue │ │ ├── FwbFooterLink.vue │ │ └── FwbFooterLinkGroup.vue │ ├── FwbInput │ │ ├── FwbInput.vue │ │ ├── composables │ │ │ └── useInputClasses.ts │ │ └── types.ts │ ├── FwbJumbotron │ │ ├── FwbJumbotron.vue │ │ └── types.ts │ ├── FwbListGroup │ │ ├── FwbListGroup.vue │ │ ├── FwbListGroupItem.vue │ │ └── composables │ │ │ ├── useListGroupClasses.ts │ │ │ └── useListGroupItemClasses.ts │ ├── FwbModal │ │ ├── FwbModal.vue │ │ └── types.ts │ ├── FwbNavbar │ │ ├── FwbNavbar.vue │ │ ├── FwbNavbarCollapse.vue │ │ ├── FwbNavbarLink.ts │ │ ├── FwbNavbarLink.vue │ │ └── FwbNavbarLogo.vue │ ├── FwbPagination │ │ ├── FwbPagination.vue │ │ └── types.ts │ ├── FwbProgress │ │ ├── FwbProgress.vue │ │ ├── composables │ │ │ └── useProgressClasses.ts │ │ └── types.ts │ ├── FwbRadio │ │ ├── FwbRadio.vue │ │ └── composables │ │ │ └── useRadioClasses.ts │ ├── FwbRange │ │ ├── FwbRange.vue │ │ └── composables │ │ │ └── useRangeClasses.ts │ ├── FwbRating │ │ ├── FwbRating.vue │ │ ├── composables │ │ │ └── useRatingClasses.ts │ │ └── types.ts │ ├── FwbSelect │ │ ├── FwbSelect.vue │ │ ├── composables │ │ │ └── useSelectClasses.ts │ │ └── types.ts │ ├── FwbSidebar │ │ ├── FwbSidebar.vue │ │ ├── FwbSidebarCta.vue │ │ ├── FwbSidebarDropdownItem.vue │ │ ├── FwbSidebarItem.vue │ │ ├── FwbSidebarItemGroup.vue │ │ └── FwbSidebarLogo.vue │ ├── FwbSpinner │ │ ├── FwbSpinner.vue │ │ ├── composables │ │ │ └── useSpinnerClasses.ts │ │ └── types.ts │ ├── FwbTable │ │ ├── FwbTable.vue │ │ ├── FwbTableBody.vue │ │ ├── FwbTableCell.vue │ │ ├── FwbTableHead.vue │ │ ├── FwbTableHeadCell.vue │ │ ├── FwbTableRow.vue │ │ └── composables │ │ │ ├── useTableCellClasses.ts │ │ │ ├── useTableHeadCellClasses.ts │ │ │ └── useTableRowClasses.ts │ ├── FwbTabs │ │ ├── FwbTab.vue │ │ ├── FwbTabPane.vue │ │ ├── FwbTabs.vue │ │ ├── composables │ │ │ ├── useTabClasses.ts │ │ │ └── useTabsClasses.ts │ │ ├── injection │ │ │ └── config.ts │ │ └── types.ts │ ├── FwbTextarea │ │ ├── FwbTextarea.vue │ │ └── composables │ │ │ └── useTextareaClasses.ts │ ├── FwbTimeline │ │ ├── FwbTimeline.vue │ │ ├── FwbTimelineBody.vue │ │ ├── FwbTimelineContent.vue │ │ ├── FwbTimelineItem.vue │ │ ├── FwbTimelinePoint.vue │ │ ├── FwbTimelineTime.vue │ │ └── FwbTimelineTitle.vue │ ├── FwbToast │ │ ├── FwbToast.vue │ │ ├── FwbToastProvider.vue │ │ ├── composables │ │ │ ├── useToast.ts │ │ │ └── useToastClasses.ts │ │ ├── injection │ │ │ └── config.ts │ │ └── types.ts │ ├── FwbToggle │ │ ├── FwbToggle.vue │ │ └── composables │ │ │ └── useToggleClasses.ts │ ├── FwbTooltip │ │ ├── FwbTooltip.vue │ │ └── types.ts │ ├── Typography │ │ ├── FwbA.vue │ │ ├── FwbBlockquote.vue │ │ ├── FwbHeading.vue │ │ ├── FwbImg.vue │ │ └── FwbP.vue │ └── utils │ │ ├── FlowbiteThemable │ │ ├── FlowbiteThemable.vue │ │ ├── FlowbiteThemableChild.vue │ │ ├── composables │ │ │ ├── useFlowbiteThemable.ts │ │ │ └── useFlowbiteThemableChildClasses.ts │ │ ├── injection │ │ │ └── config.ts │ │ └── types.ts │ │ └── FwbSlotListener │ │ ├── FwbSlotListener.vue │ │ └── types.ts ├── composables.ts ├── composables │ ├── useClasses.ts │ └── useMergeClasses.ts ├── index.ts ├── style.css ├── types │ └── global.ts ├── utils │ ├── flatten.ts │ ├── getFirstSlotNode.ts │ └── simplifyTailwindClasses.ts └── vite-env.d.ts ├── static.json ├── tsconfig.json ├── vite.config.ts └── vitest.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | public_html 2 | 3 | # Vite 4 | node_modules 5 | .DS_Store 6 | dist 7 | dist_types 8 | dist-ssr 9 | *.local 10 | 11 | # Rollup Bundle Visualizer 12 | stats.html 13 | 14 | # Logs 15 | logs 16 | *.log 17 | npm-debug.log* 18 | yarn-debug.log* 19 | yarn-error.log* 20 | lerna-debug.log* 21 | 22 | # Diagnostic reports (https://nodejs.org/api/report.html) 23 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 24 | 25 | # Runtime data 26 | pids 27 | *.pid 28 | *.seed 29 | *.pid.lock 30 | 31 | # Directory for instrumented libs generated by jscoverage/JSCover 32 | lib-cov 33 | 34 | # Coverage directory used by tools like istanbul 35 | coverage 36 | *.lcov 37 | 38 | # nyc test coverage 39 | .nyc_output 40 | 41 | # node-waf configuration 42 | .lock-wscript 43 | 44 | # Compiled binary addons (https://nodejs.org/api/addons.html) 45 | build/Release 46 | 47 | # Dependency directories 48 | node_modules/ 49 | jspm_packages/ 50 | 51 | # TypeScript cache 52 | *.tsbuildinfo 53 | 54 | # Optional npm cache directory 55 | .npm 56 | 57 | # Optional eslint cache 58 | .eslintcache 59 | 60 | # Optional REPL history 61 | .node_repl_history 62 | 63 | # Output of 'npm pack' 64 | *.tgz 65 | 66 | # Yarn Integrity file 67 | .yarn-integrity 68 | 69 | # dotenv environment variables file 70 | .env 71 | .env.test 72 | 73 | # vuepress build output 74 | .vuepress/dist 75 | docs/.vitepress/cache 76 | 77 | # VSCode custom configs 78 | .vscode 79 | 80 | # Stores VSCode versions used for testing VSCode extensions 81 | .vscode-test 82 | 83 | # yarn v2 84 | .yarn/cache 85 | .yarn/unplugged 86 | .yarn/build-state.yml 87 | .yarn/install-state.gz 88 | .pnp.* 89 | 90 | .idea 91 | .npmrc 92 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 18.20.6 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Themesberg (Crafty Dwarf LLC) company@themesberg.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themesberg/flowbite-vue/570e2387dc8bb0702989d55b5ee05926ad750d9d/Procfile -------------------------------------------------------------------------------- /docs/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/vuejs/vitepress/issues/199#issuecomment-1168325262 2 | // by default vitepress adds .vp-doc h1|h2|h3...p and others tags inside vitepress document. 3 | // here we add :not(:where(.vp-raw *)) selector to use it inside component examples 4 | // to prevent component style pollution from .vp-doc styles 5 | 6 | export default { 7 | plugins: { 8 | '@tailwindcss/postcss': {}, 9 | 'postcss-prefix-selector': { 10 | prefix: ':not(:where(.vp-raw *))', 11 | includeFiles: [/vp-doc\.css/], 12 | transform (prefix, _selector) { 13 | const [selector, pseudo = ''] = _selector.split(/(:\S*)$/) 14 | return selector + prefix + pseudo 15 | }, 16 | }, 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/custom.css: -------------------------------------------------------------------------------- 1 | /* .vitepress/theme/custom.css */ 2 | @layer theme, base, components, utilities; 3 | 4 | @custom-variant dark (&:where(.dark, .dark *)); 5 | 6 | @import 'tailwindcss/theme.css' layer(theme) source(none); 7 | @import 'tailwindcss/utilities.css'; 8 | 9 | @source '../../../'; 10 | 11 | @import './clear.css'; 12 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.js: -------------------------------------------------------------------------------- 1 | import DefaultTheme from 'vitepress/theme' 2 | import './custom.css' 3 | import '../../../src/style.css' 4 | 5 | export default DefaultTheme 6 | -------------------------------------------------------------------------------- /docs/assets/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themesberg/flowbite-vue/570e2387dc8bb0702989d55b5ee05926ad750d9d/docs/assets/github.png -------------------------------------------------------------------------------- /docs/components/PLAYGROUND/PLAYGROUND.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/components/PLAYGROUND/examples/SlotListenerExample.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | -------------------------------------------------------------------------------- /docs/components/alert/examples/FwbAlertExampleBorder.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 39 | -------------------------------------------------------------------------------- /docs/components/alert/examples/FwbAlertExampleBorderAccent.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 44 | -------------------------------------------------------------------------------- /docs/components/alert/examples/FwbAlertExampleDismissable.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 44 | -------------------------------------------------------------------------------- /docs/components/alert/examples/FwbAlertExampleIcon.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 39 | -------------------------------------------------------------------------------- /docs/components/alert/examples/FwbAlertExampleList.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 25 | -------------------------------------------------------------------------------- /docs/components/alert/examples/FwbAlertExampleType.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 24 | -------------------------------------------------------------------------------- /docs/components/avatar/examples/FwbAvatarExample.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /docs/components/avatar/examples/FwbAvatarExampleAlt.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /docs/components/avatar/examples/FwbAvatarExampleBordered.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /docs/components/avatar/examples/FwbAvatarExampleIcon.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 45 | -------------------------------------------------------------------------------- /docs/components/avatar/examples/FwbAvatarExampleInitials.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /docs/components/avatar/examples/FwbAvatarExamplePlaceholder.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /docs/components/avatar/examples/FwbAvatarExampleSize.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 29 | -------------------------------------------------------------------------------- /docs/components/avatar/examples/FwbAvatarExampleStatus.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 25 | -------------------------------------------------------------------------------- /docs/components/badge/examples/FwbBadgeExample.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 33 | -------------------------------------------------------------------------------- /docs/components/badge/examples/FwbBadgeExampleIcon.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 44 | -------------------------------------------------------------------------------- /docs/components/badge/examples/FwbBadgeExampleLink.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /docs/components/badge/examples/FwbBadgeExampleSize.vue: -------------------------------------------------------------------------------- 1 | 50 | 51 | 54 | -------------------------------------------------------------------------------- /docs/components/breadcrumb/examples/FwbBreadcrumbExample.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /docs/components/breadcrumb/examples/FwbBreadcrumbExampleSolid.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /docs/components/button/examples/ButtonLinkExample.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /docs/components/button/examples/FwbButtonExampleColor.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 36 | -------------------------------------------------------------------------------- /docs/components/button/examples/FwbButtonExampleDisabled.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 41 | -------------------------------------------------------------------------------- /docs/components/button/examples/FwbButtonExampleGradientDuotone.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 30 | -------------------------------------------------------------------------------- /docs/components/button/examples/FwbButtonExampleGradientMonochrome.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 33 | -------------------------------------------------------------------------------- /docs/components/button/examples/FwbButtonExampleLink.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /docs/components/button/examples/FwbButtonExampleOutline.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 45 | -------------------------------------------------------------------------------- /docs/components/button/examples/FwbButtonExampleOutlineGradient.vue: -------------------------------------------------------------------------------- 1 | 47 | 48 | 51 | -------------------------------------------------------------------------------- /docs/components/button/examples/FwbButtonExamplePill.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 57 | -------------------------------------------------------------------------------- /docs/components/button/examples/FwbButtonExampleShadow.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 75 | -------------------------------------------------------------------------------- /docs/components/button/examples/FwbButtonExampleSize.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 24 | -------------------------------------------------------------------------------- /docs/components/button/examples/FwbButtonExampleSlotPrefix.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /docs/components/button/examples/FwbButtonExampleSlotSuffix.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 26 | -------------------------------------------------------------------------------- /docs/components/buttonGroup/examples/FwbButtonGroupExample.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 21 | -------------------------------------------------------------------------------- /docs/components/buttonGroup/examples/FwbButtonGroupExampleDropdown.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 37 | -------------------------------------------------------------------------------- /docs/components/buttonGroup/examples/FwbButtonGroupExampleIcon.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 35 | -------------------------------------------------------------------------------- /docs/components/card/examples/FwbCardExample.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 19 | -------------------------------------------------------------------------------- /docs/components/card/examples/FwbCardExampleHorizontal.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /docs/components/card/examples/FwbCardExampleImage.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /docs/components/carousel/examples/FwbCarouselExample.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 25 | -------------------------------------------------------------------------------- /docs/components/carousel/examples/FwbCarouselExamplePictures.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 33 | -------------------------------------------------------------------------------- /docs/components/carousel/examples/FwbCarouselExampleSlide.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 28 | -------------------------------------------------------------------------------- /docs/components/carousel/examples/FwbCarouselExampleSlideInterval.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 29 | -------------------------------------------------------------------------------- /docs/components/carousel/examples/FwbCarouselExampleWithoutControls.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 28 | -------------------------------------------------------------------------------- /docs/components/carousel/examples/FwbCarouselExampleWithoutIndicators.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 28 | -------------------------------------------------------------------------------- /docs/components/checkbox/examples/FwbCheckboxExample.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 22 | -------------------------------------------------------------------------------- /docs/components/checkbox/examples/FwbCheckboxExampleChecked.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /docs/components/checkbox/examples/FwbCheckboxExampleDisabled.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | -------------------------------------------------------------------------------- /docs/components/checkbox/examples/FwbCheckboxExampleGroup.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 55 | -------------------------------------------------------------------------------- /docs/components/checkbox/examples/FwbCheckboxExampleHelper.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 21 | -------------------------------------------------------------------------------- /docs/components/checkbox/examples/FwbCheckboxExampleLink.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 22 | -------------------------------------------------------------------------------- /docs/components/dropdown/examples/FwbDropdownExampleCloseInside.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | -------------------------------------------------------------------------------- /docs/components/dropdown/examples/FwbDropdownExampleListGroup.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 28 | -------------------------------------------------------------------------------- /docs/components/dropdown/examples/FwbDropdownExampleTrigger.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 41 | -------------------------------------------------------------------------------- /docs/components/fileInput/examples/FwbFileInputExample.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /docs/components/fileInput/examples/FwbFileInputExampleDropZone.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /docs/components/fileInput/examples/FwbFileInputExampleHelper.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 21 | -------------------------------------------------------------------------------- /docs/components/fileInput/examples/FwbFileInputExampleMultiple.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 29 | -------------------------------------------------------------------------------- /docs/components/fileInput/examples/FwbFileInputExampleSize.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 28 | -------------------------------------------------------------------------------- /docs/components/flowbiteThemable/examples/FlowbiteThemableExampleButton.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 32 | -------------------------------------------------------------------------------- /docs/components/footer/examples/FwbFooterExample.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 35 | -------------------------------------------------------------------------------- /docs/components/footer/examples/FwbFooterExampleSticky.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 52 | -------------------------------------------------------------------------------- /docs/components/footer/examples/FwbFooterExampleWithLogo.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 46 | -------------------------------------------------------------------------------- /docs/components/input/examples/FwbInputExample.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 18 | -------------------------------------------------------------------------------- /docs/components/input/examples/FwbInputExampleDisabled.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /docs/components/input/examples/FwbInputExampleHelper.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 28 | -------------------------------------------------------------------------------- /docs/components/input/examples/FwbInputExamplePrefix.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 36 | -------------------------------------------------------------------------------- /docs/components/input/examples/FwbInputExampleRequired.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /docs/components/input/examples/FwbInputExampleSize.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 31 | -------------------------------------------------------------------------------- /docs/components/input/examples/FwbInputExampleStyling.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 22 | -------------------------------------------------------------------------------- /docs/components/input/examples/FwbInputExampleValidation.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 36 | -------------------------------------------------------------------------------- /docs/components/listGroup/examples/FwbListGroupExample.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 26 | -------------------------------------------------------------------------------- /docs/components/listGroup/examples/FwbListGroupExampleHover.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 29 | -------------------------------------------------------------------------------- /docs/components/modal/examples/FwbModalExampleEscapable.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /docs/components/modal/examples/FwbModalExampleFocusTrap.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /docs/components/modal/examples/FwbModalExamplePersistent.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /docs/components/modal/examples/FwbModalExamplePosition.vue: -------------------------------------------------------------------------------- 1 | 59 | 60 | 63 | -------------------------------------------------------------------------------- /docs/components/modal/examples/FwbModalExampleSize.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 33 | -------------------------------------------------------------------------------- /docs/components/navbar/examples/FwbNavbarExample.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 44 | -------------------------------------------------------------------------------- /docs/components/navbar/examples/FwbNavbarExampleActionButton.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 50 | -------------------------------------------------------------------------------- /docs/components/navbar/examples/FwbNavbarExampleSolid.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 44 | -------------------------------------------------------------------------------- /docs/components/pagination/examples/FwbPaginationExample.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 22 | -------------------------------------------------------------------------------- /docs/components/pagination/examples/FwbPaginationExampleCustomLabels.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /docs/components/pagination/examples/FwbPaginationExampleCustomLength.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 18 | -------------------------------------------------------------------------------- /docs/components/pagination/examples/FwbPaginationExampleFirstLast.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 32 | -------------------------------------------------------------------------------- /docs/components/pagination/examples/FwbPaginationExampleIcons.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 26 | -------------------------------------------------------------------------------- /docs/components/pagination/examples/FwbPaginationExampleNavigation.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 24 | -------------------------------------------------------------------------------- /docs/components/pagination/examples/FwbPaginationExampleNavigationIcons.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 27 | -------------------------------------------------------------------------------- /docs/components/pagination/examples/FwbPaginationExampleSlots.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 41 | -------------------------------------------------------------------------------- /docs/components/pagination/examples/FwbPaginationExampleTable.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 27 | -------------------------------------------------------------------------------- /docs/components/progress/examples/FwbProgressExample.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/components/progress/examples/FwbProgressExampleColor.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 48 | -------------------------------------------------------------------------------- /docs/components/progress/examples/FwbProgressExampleLabelInside.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /docs/components/progress/examples/FwbProgressExampleLabelOutside.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /docs/components/progress/examples/FwbProgressExampleSize.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 29 | -------------------------------------------------------------------------------- /docs/components/radio/examples/FwbRadioExample.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 25 | -------------------------------------------------------------------------------- /docs/components/radio/examples/FwbRadioExampleBordered.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 29 | -------------------------------------------------------------------------------- /docs/components/radio/examples/FwbRadioExampleDisabled.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 27 | -------------------------------------------------------------------------------- /docs/components/radio/examples/FwbRadioExampleInline.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 33 | -------------------------------------------------------------------------------- /docs/components/radio/examples/FwbRadioExampleLink.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 24 | -------------------------------------------------------------------------------- /docs/components/radio/examples/FwbRadioExampleList.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 51 | -------------------------------------------------------------------------------- /docs/components/range/examples/FwbRangeExample.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 15 | -------------------------------------------------------------------------------- /docs/components/range/examples/FwbRangeExampleDisabled.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 18 | -------------------------------------------------------------------------------- /docs/components/range/examples/FwbRangeExampleMinMax.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 20 | -------------------------------------------------------------------------------- /docs/components/range/examples/FwbRangeExampleSize.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 30 | -------------------------------------------------------------------------------- /docs/components/range/examples/FwbRangeExampleSteps.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /docs/components/rating/examples/FwbRatingExample.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/components/rating/examples/FwbRatingExampleCount.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 21 | -------------------------------------------------------------------------------- /docs/components/rating/examples/FwbRatingExampleStarSizes.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 21 | -------------------------------------------------------------------------------- /docs/components/rating/examples/FwbRatingExampleWithText.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /docs/components/select/examples/FwbSelectExample.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 23 | -------------------------------------------------------------------------------- /docs/components/select/examples/FwbSelectExampleDisabled.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 25 | -------------------------------------------------------------------------------- /docs/components/select/examples/FwbSelectExampleHelper.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 33 | -------------------------------------------------------------------------------- /docs/components/select/examples/FwbSelectExampleSize.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 36 | -------------------------------------------------------------------------------- /docs/components/select/examples/FwbSelectExampleUnderlined.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 24 | -------------------------------------------------------------------------------- /docs/components/select/examples/FwbSelectExampleValidation.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 35 | -------------------------------------------------------------------------------- /docs/components/spinner/examples/FwbSpinnerExample.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/components/spinner/examples/FwbSpinnerExampleColor.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 17 | -------------------------------------------------------------------------------- /docs/components/spinner/examples/FwbSpinnerExampleSize.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /docs/components/textarea/examples/FwbTextareaExample.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /docs/components/textarea/examples/FwbTextareaExampleDisabled.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 38 | -------------------------------------------------------------------------------- /docs/components/textarea/examples/FwbTextareaExampleFormId.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 38 | -------------------------------------------------------------------------------- /docs/components/toast/examples/FwbToastExample.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 21 | -------------------------------------------------------------------------------- /docs/components/toast/examples/FwbToastExampleClosable.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 30 | -------------------------------------------------------------------------------- /docs/components/toast/examples/FwbToastExampleDivide.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 30 | -------------------------------------------------------------------------------- /docs/components/toast/examples/FwbToastExampleMessage.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 31 | -------------------------------------------------------------------------------- /docs/components/toastProvider/examples/FwbToastProviderExample.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 42 | -------------------------------------------------------------------------------- /docs/components/toastProvider/examples/UpdateToast.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 46 | -------------------------------------------------------------------------------- /docs/components/toastProvider/toastProvider.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | # Vue Toast Provider - Flowbite 6 | 7 | :::warning 8 | WIP, Do not use it in production 9 | ::: 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/components/toggle/examples/FwbToggleExample.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /docs/components/toggle/examples/FwbToggleExampleChecked.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | -------------------------------------------------------------------------------- /docs/components/toggle/examples/FwbToggleExampleColors.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 48 | -------------------------------------------------------------------------------- /docs/components/toggle/examples/FwbToggleExampleDisabled.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 18 | -------------------------------------------------------------------------------- /docs/components/toggle/examples/FwbToggleExampleOrder.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /docs/components/toggle/examples/FwbToggleExampleSize.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 21 | -------------------------------------------------------------------------------- /docs/components/tooltip/examples/FwbTooltipExample.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 19 | -------------------------------------------------------------------------------- /docs/components/tooltip/examples/FwbTooltipExampleGroup.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 24 | -------------------------------------------------------------------------------- /docs/components/tooltip/examples/FwbTooltipExamplePosition.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 49 | -------------------------------------------------------------------------------- /docs/components/tooltip/examples/FwbTooltipExampleStyle.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 29 | -------------------------------------------------------------------------------- /docs/components/tooltip/examples/FwbTooltipExampleTrigger.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 29 | -------------------------------------------------------------------------------- /docs/components/typography/blockquote/FwbBlockquoteAlignExample.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 22 | -------------------------------------------------------------------------------- /docs/components/typography/blockquote/FwbBlockquoteExample.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /docs/components/typography/blockquote/FwbBlockquoteSizeExample.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /docs/components/typography/blockquote/FwbBlockquoteSolidExample.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /docs/components/typography/heading/FwbHExampleColor.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/components/typography/heading/FwbHExampleCustom.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/components/typography/heading/FwbHExampleLevel1.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/components/typography/heading/FwbHExampleLevel2.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/components/typography/heading/FwbHExampleLevel3.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/components/typography/heading/FwbHExampleLevel4.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/components/typography/heading/FwbHExampleLevel5.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/components/typography/heading/FwbHExampleLevel6.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/components/typography/image/FwbImgExample.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /docs/components/typography/image/FwbImgExampleAlign.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /docs/components/typography/image/FwbImgExampleCaption.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /docs/components/typography/image/FwbImgExampleCustom.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /docs/components/typography/image/FwbImgExampleGrayscale.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /docs/components/typography/image/FwbImgExampleSize.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /docs/components/typography/link/FwbAExample.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /docs/components/typography/link/FwbAExampleCustom.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /docs/components/typography/link/FwbAExampleParagraph.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 17 | -------------------------------------------------------------------------------- /docs/components/typography/p/FwbPExample.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 17 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | title: Flowbite Vue 3 5 | titleTemplate: Flowbite 6 | 7 | hero: 8 | name: Flowbite Vue 3 9 | text: Vue component library based on Tailwind CSS 10 | tagline: Get started with the most popular open-source library of interactive UI components built with the utility classes from Tailwind CSS 11 | image: 12 | src: /assets/logo.svg 13 | alt: VitePress 14 | actions: 15 | - theme: brand 16 | text: Get Started 17 | link: /pages/getting-started 18 | - theme: alt 19 | text: View on GitHub 20 | link: https://github.com/themesberg/flowbite-vue 21 | 22 | features: 23 | - title: Vue 3 components 🧱 24 | details: Use hundreds of open-source components such as navbars, modals, and dropdowns based on Vue 3 and Tailwind CSS. 25 | - title: Based on Tailwind CSS 💨 26 | details: The components are based on the utility classes from Tailwind CSS and you can use them to further customize the interface. 27 | - title: Powered by Flowbite 🚀 28 | details: The Flowbite Vue library is based on the original Flowbite component library using vanilla JavaScript. 29 | - title: Open-source community ❤️ 30 | details: Thousands of developers actively use the components from Flowbite Vue to power their applications. 31 | --- 32 | -------------------------------------------------------------------------------- /docs/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path' 2 | 3 | import tailwindcss from '@tailwindcss/vite' 4 | import { defineConfig } from 'vite' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [ 9 | tailwindcss(), 10 | ], 11 | resolve: { 12 | alias: { 13 | '@': resolve(__dirname, '../src'), // to resolve @ inside docs 14 | }, 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/components/FwbAccordion/FwbAccordion.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 40 | -------------------------------------------------------------------------------- /src/components/FwbAccordion/FwbAccordionContent.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 46 | -------------------------------------------------------------------------------- /src/components/FwbAccordion/composables/useAccordionContentClasses.ts: -------------------------------------------------------------------------------- 1 | import { computed, type Ref } from 'vue' 2 | 3 | import type { AccordionContentProps, AccordionPanel, AccordionState } from '../types' 4 | 5 | import { useMergeClasses } from '@/composables/useMergeClasses' 6 | 7 | export const useAccordionContentClasses = ( 8 | accordionState: Ref, 9 | panelState: Ref, 10 | props: AccordionContentProps, 11 | ): string => { 12 | const baseContentClasses = 'p-5 border border-gray-200 dark:border-gray-700 dark:bg-gray-900' 13 | 14 | const userClass = computed(() => props.class) 15 | const userActiveClass = computed(() => props.activeClass) 16 | 17 | const isFlushed = computed(() => accordionState.value?.flushed) 18 | const isPanelVisible = computed(() => panelState.value?.isVisible) 19 | const panelsCount = computed(() => accordionState.value?.panels?.length ?? 0) 20 | const isLastPanel = computed(() => panelState.value?.order === panelsCount.value - 1) 21 | 22 | const contentClasses = computed(() => 23 | useMergeClasses( 24 | [ 25 | baseContentClasses, 26 | isFlushed.value && 'border-x-0 border-t-0', 27 | !isPanelVisible.value && 'hidden', 28 | (!isLastPanel.value && !isFlushed.value) && 'border-b-0', 29 | isLastPanel.value && 'border-t-0', 30 | userClass.value, 31 | isPanelVisible.value ? userActiveClass.value : '', 32 | ].filter(str => (str)) 33 | .join(' '), 34 | ), 35 | ) 36 | 37 | return contentClasses.value 38 | } 39 | -------------------------------------------------------------------------------- /src/components/FwbAccordion/composables/useAccordionPanelClasses.ts: -------------------------------------------------------------------------------- 1 | import type { AccordionPanelProps } from '../types' 2 | 3 | import { useMergeClasses } from '@/composables/useMergeClasses' 4 | 5 | interface UseAccordionClassesProps { 6 | isVisible: boolean 7 | props: AccordionPanelProps 8 | } 9 | 10 | const useAccordionPanelClasses = ({ props, isVisible }: UseAccordionClassesProps) => { 11 | const userActiveClasses = props.activeClass ?? '' 12 | 13 | return useMergeClasses([`${isVisible ? userActiveClasses : ''}`]) 14 | } 15 | 16 | export { 17 | useAccordionPanelClasses, 18 | } 19 | -------------------------------------------------------------------------------- /src/components/FwbAlert/types.ts: -------------------------------------------------------------------------------- 1 | export type AlertType = 'info' | 'danger' | 'success' | 'warning' | 'dark' 2 | -------------------------------------------------------------------------------- /src/components/FwbAvatar/FwbAvatarStack.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/components/FwbAvatar/FwbAvatarStackCounter.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 20 | -------------------------------------------------------------------------------- /src/components/FwbAvatar/types.ts: -------------------------------------------------------------------------------- 1 | export type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' 2 | export type AvatarStatus = 'away' | 'busy' | 'offline' | 'online' 3 | export type AvatarStatusPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' 4 | export type AvatarType = 'default' | 'rounded' 5 | export type avatarDotIndicatorPositionClasses = `${AvatarStatusPosition}-${AvatarType}` 6 | -------------------------------------------------------------------------------- /src/components/FwbBadge/FwbBadge.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 36 | -------------------------------------------------------------------------------- /src/components/FwbBadge/types.ts: -------------------------------------------------------------------------------- 1 | export type BadgeType = 'default' | 'dark' | 'red' | 'green' | 'yellow' | 'indigo' | 'purple' | 'pink' 2 | export type BadgeSize = 'xs' | 'sm' 3 | -------------------------------------------------------------------------------- /src/components/FwbBreadcrumb/FwbBreadcrumb.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 26 | -------------------------------------------------------------------------------- /src/components/FwbBreadcrumb/composables/useBreadcrumbClasses.ts: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import { computed, type Ref } from 'vue' 3 | 4 | import type { BreadcrumbType } from '../types' 5 | 6 | const breadcrumbDefaultClasses = 'inline-flex items-center space-x-1 md:space-x-3' 7 | const breadcrumbWrapperVariantClasses: Record = { 8 | default: 'flex', 9 | solid: 'flex px-5 py-3 text-gray-700 border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700', 10 | } 11 | 12 | export type useBreadcrumbProps = { 13 | solid: Ref 14 | } 15 | 16 | export function useBreadcrumbClasses (props: useBreadcrumbProps): { 17 | breadcrumbClasses: Ref 18 | breadcrumbWrapperClasses: Ref 19 | } { 20 | const breadcrumbClasses = computed(() => classNames(breadcrumbDefaultClasses)) 21 | const breadcrumbWrapperClasses = computed(() => classNames( 22 | breadcrumbWrapperVariantClasses[props.solid.value ? 'solid' : 'defauilt' as BreadcrumbType], 23 | )) 24 | 25 | return { 26 | breadcrumbClasses, 27 | breadcrumbWrapperClasses, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/components/FwbBreadcrumb/composables/useBreadcrumbItemClasses.ts: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import { computed, type Ref } from 'vue' 3 | 4 | const breadcrumbItemDefaultClasses = 'ml-1 inline-flex items-center text-sm font-medium dark:text-gray-400' 5 | const breadcrumbItemLinkClasses = 'text-gray-700 hover:text-gray-900 dark:hover:text-white' 6 | const breadcrumbSpanClasses = 'text-gray-500' 7 | 8 | export type useBreadcrumbItemProps = { 9 | href: Ref 10 | home: Ref 11 | } 12 | 13 | export function useBreadcrumbItemClasses (props: useBreadcrumbItemProps): { 14 | breadcrumbItemClasses: Ref 15 | } { 16 | const breadcrumbItemClasses = computed(() => classNames( 17 | breadcrumbItemDefaultClasses, 18 | props.href.value ? breadcrumbItemLinkClasses : breadcrumbSpanClasses, 19 | )) 20 | 21 | return { 22 | breadcrumbItemClasses, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/components/FwbBreadcrumb/types.ts: -------------------------------------------------------------------------------- 1 | export type BreadcrumbType = 'default' | 'solid' 2 | -------------------------------------------------------------------------------- /src/components/FwbButton/tests/Button.spec.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils' 2 | import { describe, expect, it } from 'vitest' 3 | 4 | import FwbButton from '../FwbButton.vue' 5 | 6 | describe('FwbButton', () => { 7 | it('renders correct text', () => { 8 | const wrapper = mount(FwbButton, { props: {}, slots: { default: 'test' } }) 9 | expect(wrapper.text()).toBe('test') 10 | }) 11 | 12 | it('provides correct classes for default color button', () => { 13 | const defaultButtonClasses = [ 14 | 'text-white', 15 | 'bg-blue-700', 16 | 'hover:bg-blue-800', 17 | 'focus:ring-4', 18 | 'focus:ring-blue-300', 19 | 'font-medium', 20 | 'rounded-lg', 21 | 'dark:bg-blue-600', 22 | 'dark:hover:bg-blue-700', 23 | 'focus:outline-none', 24 | 'dark:focus:ring-blue-800', 25 | 'text-sm', 26 | 'px-4', 27 | 'py-2', 28 | ] 29 | 30 | const wrapper = mount(FwbButton, { props: { color: 'default' } }) 31 | const classes = wrapper.classes() 32 | 33 | defaultButtonClasses.forEach(cl => expect(classes).toContain(cl)) 34 | }) 35 | 36 | it('provides correct classes for XL size', () => { 37 | const xlButtonSizeClasses = [ 38 | 'text-base', 'px-6', 'py-3', 39 | ] 40 | 41 | const wrapper = mount(FwbButton, { props: { size: 'xl' } }) 42 | const classes = wrapper.classes() 43 | 44 | xlButtonSizeClasses.forEach(cl => expect(classes).toContain(cl)) 45 | }) 46 | }) 47 | -------------------------------------------------------------------------------- /src/components/FwbButton/types.ts: -------------------------------------------------------------------------------- 1 | export type ButtonMonochromeGradient = 'blue' | 'green' | 'cyan' | 'teal' | 'lime' | 'red' | 'pink' | 'purple' 2 | export type ButtonDuotoneGradient = 'purple-blue' | 'cyan-blue' | 'green-blue' | 'purple-pink' | 'pink-orange' | 'teal-lime' | 'red-yellow' 3 | export type ButtonGradient = ButtonDuotoneGradient | ButtonMonochromeGradient 4 | export type ButtonVariant = 'default' | 'alternative' | 'dark' | 'light' | 'green' | 'red' | 'yellow' | 'purple' | 'pink' | 'blue' 5 | export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' 6 | -------------------------------------------------------------------------------- /src/components/FwbButtonGroup/FwbButtonGroup.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 29 | -------------------------------------------------------------------------------- /src/components/FwbCard/FwbCard.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 49 | -------------------------------------------------------------------------------- /src/components/FwbCard/composables/useCardClasses.ts: -------------------------------------------------------------------------------- 1 | import { computed, type Ref } from 'vue' 2 | 3 | import type { CardsVariant } from '../types' 4 | 5 | export type UseCardsClassesProps = { 6 | variant: Ref 7 | href?: Ref 8 | } 9 | 10 | export function useCardsClasses (props: UseCardsClassesProps): { 11 | cardClasses: Ref 12 | horizontalImageClasses: Ref 13 | } { 14 | const cardClasses = computed(() => { 15 | let computedClasses = '' 16 | if (props.variant.value === 'image') { 17 | computedClasses = 'max-w-sm bg-white rounded-lg border border-gray-200 shadow-md dark:bg-gray-800 dark:border-gray-700' 18 | } 19 | 20 | if (props.variant.value === 'default') { 21 | computedClasses = 'block max-w-sm bg-white rounded-lg border border-gray-200 shadow-md dark:bg-gray-800 dark:border-gray-700 ' 22 | } else if (props.variant.value === 'horizontal') { 23 | computedClasses = 'flex flex-col items-center bg-white rounded-lg border shadow-md md:flex-row md:max-w-xl dark:border-gray-700 dark:bg-gray-800' 24 | } 25 | 26 | if (props.href?.value) { 27 | computedClasses += ' hover:bg-gray-100 dark:hover:bg-gray-700' 28 | } 29 | 30 | return computedClasses 31 | }) 32 | 33 | const horizontalImageClasses = computed(() => (props.variant.value === 'horizontal') 34 | ? 'object-cover w-full h-96 rounded-t-lg md:h-auto md:w-48 md:rounded-none md:rounded-l-lg' 35 | : '', 36 | ) 37 | 38 | return { 39 | cardClasses, 40 | horizontalImageClasses, 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/components/FwbCard/types.ts: -------------------------------------------------------------------------------- 1 | export type CardsVariant = 'default' | 'image' | 'horizontal' 2 | -------------------------------------------------------------------------------- /src/components/FwbCarousel/types.ts: -------------------------------------------------------------------------------- 1 | export type PictureItem = { 2 | alt?: string 3 | src: string 4 | } 5 | -------------------------------------------------------------------------------- /src/components/FwbDropdown/types.ts: -------------------------------------------------------------------------------- 1 | export type DropdownPlacement = 'top' | 'bottom' | 'left' | 'right' 2 | export type DropdownAlignment = 'horizontal' | 'vertical' | 'horizontal_reverse' | 'vertical_reverse' 3 | -------------------------------------------------------------------------------- /src/components/FwbFileInput/composables/useFileInputClasses.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue' 2 | 3 | import { simplifyTailwindClasses } from '@/utils/simplifyTailwindClasses' 4 | 5 | const fileInpDefaultClasses = 'block w-full py-1 px-2 text-sm text-gray-900 border-[1px] border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400' 6 | const fileInpLabelClasses = 'block mb-2 text-sm font-medium text-gray-900 dark:text-white' 7 | const fileInpDropzoneClasses = 'flex flex-col items-center justify-center w-full h-64 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:hover:bg-bray-800 dark:bg-gray-700 hover:bg-gray-100 dark:border-gray-600 dark:hover:border-gray-500 dark:hover:bg-gray-600' 8 | const fileDropzoneWrapClasses = 'flex flex-col items-center justify-center pt-5 pb-6' 9 | const fileDropzoneDefaultTextClasses = '!-mb-2 text-sm text-gray-500 dark:text-gray-400' 10 | 11 | export function useFileInputClasses (size: string) { 12 | const fileInpClasses = computed(() => simplifyTailwindClasses( 13 | fileInpDefaultClasses, 14 | 'text-' + size, 15 | )) 16 | 17 | const labelClasses = computed(() => fileInpLabelClasses) 18 | const dropzoneLabelClasses = computed(() => fileInpDropzoneClasses) 19 | const dropzoneWrapClasses = computed(() => fileDropzoneWrapClasses) 20 | const dropzoneTextClasses = computed(() => fileDropzoneDefaultTextClasses) 21 | 22 | return { 23 | fileInpClasses, 24 | labelClasses, 25 | dropzoneLabelClasses, 26 | dropzoneWrapClasses, 27 | dropzoneTextClasses, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/components/FwbFooter/FwbFooter.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 40 | -------------------------------------------------------------------------------- /src/components/FwbFooter/FwbFooterBrand.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 54 | -------------------------------------------------------------------------------- /src/components/FwbFooter/FwbFooterCopyright.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 45 | -------------------------------------------------------------------------------- /src/components/FwbFooter/FwbFooterIcon.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 38 | -------------------------------------------------------------------------------- /src/components/FwbFooter/FwbFooterLink.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 41 | -------------------------------------------------------------------------------- /src/components/FwbFooter/FwbFooterLinkGroup.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 21 | -------------------------------------------------------------------------------- /src/components/FwbInput/types.ts: -------------------------------------------------------------------------------- 1 | export type InputSize = 'sm' | 'md' | 'lg' 2 | 3 | export type InputType = 'button' | 'checkbox' | 'color' | 'date' | 'datetime-local' | 'email' | 'file' | 'hidden' | 'image' | 'month' | 'number' | 'password' | 'radio' | 'range' | 'reset' | 'search' | 'submit' | 'tel' | 'text' | 'time' | 'url' | 'week' 4 | 5 | // A simplified version of AutFill, which is to complex for TypeScript to handle 6 | export type CommonAutoFill = 'on' | 'off' | 'email' | 'tel' | 'name' | 'username' | 'current-password' | 'country' | 'postal-code' | 'language' | 'bday' 7 | 8 | export const validationStatusMap = { 9 | Error: 'error', 10 | Success: 'success', 11 | } as const 12 | 13 | export type ValidationStatus = typeof validationStatusMap[keyof typeof validationStatusMap] 14 | -------------------------------------------------------------------------------- /src/components/FwbJumbotron/types.ts: -------------------------------------------------------------------------------- 1 | export type HeaderLevel = 1 | 2 | 3 | 4 | 5 | 6 2 | -------------------------------------------------------------------------------- /src/components/FwbListGroup/FwbListGroup.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/FwbListGroup/FwbListGroupItem.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 41 | -------------------------------------------------------------------------------- /src/components/FwbListGroup/composables/useListGroupClasses.ts: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import { computed, type Ref } from 'vue' 3 | 4 | const defaultContainerClasses = 'overflow-hidden w-48 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-lg dark:bg-gray-700 dark:border-gray-600 dark:text-white' 5 | 6 | export function useListGroupClasses (): { 7 | containerClasses: Ref 8 | } { 9 | const containerClasses = computed(() => { 10 | return classNames( 11 | defaultContainerClasses, 12 | ) 13 | }) 14 | 15 | return { 16 | containerClasses, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/components/FwbListGroup/composables/useListGroupItemClasses.ts: -------------------------------------------------------------------------------- 1 | import { computed, type Ref } from 'vue' 2 | 3 | import { useMergeClasses } from '@/composables/useMergeClasses' 4 | 5 | const defaultItemClasses = 'inline-flex items-center w-full px-4 py-2 border-b border-gray-200 dark:border-gray-600' 6 | const hoverItemClasses = 'block w-full px-4 py-2 cursor-pointer hover:bg-gray-100 hover:text-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-700 focus:text-blue-700 dark:hover:bg-gray-600 dark:hover:text-white dark:focus:ring-gray-500 dark:focus:text-white' 7 | const disabledItemClasses = 'bg-gray-100 cursor-not-allowed dark:bg-gray-600 dark:text-gray-400' 8 | const activeItemClasses = 'text-white bg-blue-700 dark:bg-gray-800 hover:text-white hover:bg-blue-700 hover:dark:bg-gray-800' 9 | 10 | export type UseListGroupItemClassesProps = { 11 | hover: Ref 12 | disabled: Ref 13 | active: Ref 14 | } 15 | 16 | export function useListGroupItemClasses (props: UseListGroupItemClassesProps): { 17 | itemClasses: Ref 18 | } { 19 | const itemClasses = computed(() => useMergeClasses([ 20 | defaultItemClasses, 21 | props.disabled.value ? disabledItemClasses : '', 22 | !props.disabled.value && props.hover.value ? hoverItemClasses : '', 23 | !props.disabled.value && props.active.value ? activeItemClasses : '', 24 | ])) 25 | 26 | return { 27 | itemClasses, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/components/FwbModal/types.ts: -------------------------------------------------------------------------------- 1 | export type ModalPosition = 'bottom-start' | 'bottom-end' | 'bottom-center' | 'top-start' | 'top-center' | 'top-end' | 'center-start' | 'center' | 'center-end' 2 | export type ModalSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl' 3 | -------------------------------------------------------------------------------- /src/components/FwbNavbar/FwbNavbarCollapse.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 35 | -------------------------------------------------------------------------------- /src/components/FwbNavbar/FwbNavbarLink.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themesberg/flowbite-vue/570e2387dc8bb0702989d55b5ee05926ad750d9d/src/components/FwbNavbar/FwbNavbarLink.ts -------------------------------------------------------------------------------- /src/components/FwbNavbar/FwbNavbarLogo.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 39 | -------------------------------------------------------------------------------- /src/components/FwbPagination/types.ts: -------------------------------------------------------------------------------- 1 | export type PaginationLayout = 'navigation' | 'pagination' | 'table' 2 | -------------------------------------------------------------------------------- /src/components/FwbProgress/types.ts: -------------------------------------------------------------------------------- 1 | export type ProgressLabelPosition = 'inside' | 'outside' | 'none' 2 | export type ProgressSize = 'sm' | 'md' | 'lg' | 'xl' 3 | export type ProgressVariant = 'default' | 'dark' | 'green' | 'red' | 'yellow' | 'purple' | 'blue' | 'indigo' 4 | -------------------------------------------------------------------------------- /src/components/FwbRadio/FwbRadio.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 55 | -------------------------------------------------------------------------------- /src/components/FwbRadio/composables/useRadioClasses.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/themesberg/flowbite-vue/570e2387dc8bb0702989d55b5ee05926ad750d9d/src/components/FwbRadio/composables/useRadioClasses.ts -------------------------------------------------------------------------------- /src/components/FwbRange/FwbRange.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 58 | 59 | 69 | -------------------------------------------------------------------------------- /src/components/FwbRange/composables/useRangeClasses.ts: -------------------------------------------------------------------------------- 1 | import { computed, type Ref } from 'vue' 2 | 3 | import type { InputSize } from '@/components/FwbInput/types' 4 | 5 | import { simplifyTailwindClasses } from '@/utils/simplifyTailwindClasses' 6 | 7 | const rangeDefaultClasses = 'w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700' 8 | const rangeLabelClasses = 'block mb-2 text-sm font-medium text-gray-900 dark:text-white' 9 | 10 | const rangeSizeClasses: Record = { 11 | lg: 'h-3 range-lg', 12 | md: 'h-2 range-md', 13 | sm: 'h-1 range-sm', 14 | } 15 | 16 | export type UseRangeClassesProps = { 17 | size: Ref 18 | disabled: Ref 19 | } 20 | 21 | export function useRangeClasses (props: UseRangeClassesProps) { 22 | const rangeClasses = computed(() => simplifyTailwindClasses( 23 | rangeDefaultClasses, 24 | rangeSizeClasses[props.size.value], 25 | )) 26 | 27 | const labelClasses = computed(() => rangeLabelClasses) 28 | 29 | return { 30 | rangeClasses, 31 | labelClasses, 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/components/FwbRating/composables/useRatingClasses.ts: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import { computed, type Ref } from 'vue' 3 | 4 | import type { RatingSize } from '../types' 5 | 6 | const ratingSizeClasses: Record = { 7 | sm: 'w-5 h-5', 8 | md: 'w-7 h-7', 9 | lg: 'w-10 h-10', 10 | } 11 | 12 | export type UseRatingClassesProps = { 13 | size: Ref 14 | } 15 | 16 | export function useRatingClasses (props: UseRatingClassesProps): { 17 | sizeClasses: Ref 18 | } { 19 | const sizeClasses = computed(() => classNames( 20 | ratingSizeClasses[props.size.value] ?? '', 21 | )) 22 | 23 | return { sizeClasses } 24 | } 25 | -------------------------------------------------------------------------------- /src/components/FwbRating/types.ts: -------------------------------------------------------------------------------- 1 | export type RatingSize = 'sm' | 'md' | 'lg' 2 | -------------------------------------------------------------------------------- /src/components/FwbSelect/types.ts: -------------------------------------------------------------------------------- 1 | export type InputSize = 'sm' | 'md' | 'lg' 2 | 3 | export type OptionsType = { 4 | name: string 5 | value: string 6 | } 7 | 8 | export const validationStatusMap = { 9 | Success: 'success', 10 | Error: 'error', 11 | } as const 12 | 13 | export type ValidationStatus = typeof validationStatusMap[keyof typeof validationStatusMap] 14 | -------------------------------------------------------------------------------- /src/components/FwbSidebar/FwbSidebar.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 25 | -------------------------------------------------------------------------------- /src/components/FwbSidebar/FwbSidebarCta.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 52 | -------------------------------------------------------------------------------- /src/components/FwbSidebar/FwbSidebarItem.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 34 | -------------------------------------------------------------------------------- /src/components/FwbSidebar/FwbSidebarItemGroup.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | -------------------------------------------------------------------------------- /src/components/FwbSidebar/FwbSidebarLogo.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 39 | -------------------------------------------------------------------------------- /src/components/FwbSpinner/types.ts: -------------------------------------------------------------------------------- 1 | export type SpinnerColor = 'blue' | 'gray' | 'green' | 'red' | 'yellow' | 'pink' | 'purple' | 'white' 2 | 3 | export type SpinnerSize = '0' | '0.5' | '1' | '1.5' | '2' | '2.5' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12' 4 | -------------------------------------------------------------------------------- /src/components/FwbTable/FwbTable.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 31 | -------------------------------------------------------------------------------- /src/components/FwbTable/FwbTableBody.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/components/FwbTable/FwbTableCell.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/FwbTable/FwbTableHead.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/components/FwbTable/FwbTableHeadCell.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /src/components/FwbTable/FwbTableRow.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /src/components/FwbTable/composables/useTableCellClasses.ts: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import { computed, inject, type Ref } from 'vue' 3 | 4 | const baseClasses = 'px-6 py-4 first:font-medium first:text-gray-900 first:dark:text-white first:whitespace-nowrap last:text-right' 5 | const stripedCellClasses = 'even:bg-gray-white even:dark:bg-gray-900 odd:dark:bg-gray-800 odd:bg-gray-50' 6 | 7 | export function useTableCellClasses (): { tableCellClasses: Ref } { 8 | const isColumnsStriped = inject('stripedColumns') 9 | 10 | const tableCellClasses = computed(() => classNames( 11 | baseClasses, 12 | { [stripedCellClasses]: isColumnsStriped }, 13 | )) 14 | 15 | return { tableCellClasses } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/FwbTable/composables/useTableHeadCellClasses.ts: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import { computed, inject, type Ref } from 'vue' 3 | 4 | const baseClasses = 'px-6 py-3 text-xs uppercase' 5 | const stripedHeadCellClasses = 'even:bg-white even:dark:bg-gray-900 odd:dark:bg-gray-800 odd:bg-gray-50' 6 | 7 | export function useTableHeadCellClasses (): { tableHeadCellClasses: Ref } { 8 | const isColumnsStriped = inject('stripedColumns') 9 | 10 | const tableHeadCellClasses = computed(() => classNames( 11 | baseClasses, 12 | { [stripedHeadCellClasses]: isColumnsStriped }, 13 | )) 14 | 15 | return { tableHeadCellClasses } 16 | } 17 | -------------------------------------------------------------------------------- /src/components/FwbTable/composables/useTableRowClasses.ts: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import { computed, inject, type Ref } from 'vue' 3 | 4 | const baseClasses = 'bg-white dark:bg-gray-800 [&:not(:last-child)]:border-b [&:not(:last-child)]:dark:border-gray-700' 5 | const stripedClasses = 'odd:bg-white even:bg-gray-50 odd:dark:bg-gray-800 even:dark:bg-gray-700' 6 | const hoverableClasses = 'hover:bg-gray-50 dark:hover:bg-gray-600' 7 | 8 | export function useTableRowClasses (): { tableRowClasses: Ref } { 9 | const isStriped = inject('striped') 10 | const isHoverable = inject('hoverable') 11 | 12 | const tableRowClasses = computed(() => classNames( 13 | baseClasses, 14 | { 15 | [hoverableClasses]: isHoverable, 16 | [stripedClasses]: isStriped, 17 | }, 18 | )) 19 | 20 | return { tableRowClasses } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/FwbTabs/FwbTab.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 44 | -------------------------------------------------------------------------------- /src/components/FwbTabs/FwbTabPane.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 64 | -------------------------------------------------------------------------------- /src/components/FwbTabs/composables/useTabsClasses.ts: -------------------------------------------------------------------------------- 1 | import { twMerge } from 'tailwind-merge' 2 | import { computed, type Ref } from 'vue' 3 | 4 | import type { TabsVariant } from '../types' 5 | 6 | export type UseTabsClassesProps = { 7 | variant: TabsVariant 8 | } 9 | 10 | export function useTabsClasses (props: UseTabsClassesProps): { 11 | divClasses: Ref 12 | ulClasses: Ref 13 | } { 14 | const ulClasses = computed(() => { 15 | const baseClasses = 'flex flex-wrap font-medium text-center text-gray-500 dark:text-gray-400 text-sm' 16 | 17 | return twMerge( 18 | baseClasses, 19 | props.variant === 'underline' && '-mb-px', 20 | props.variant === 'default' && 'border-b border-gray-200 dark:border-gray-700', 21 | ) 22 | }) 23 | 24 | const divClasses = computed(() => { 25 | if (props.variant === 'underline') { 26 | return 'border-b border-gray-200 dark:border-gray-700 font-medium text-center text-gray-500 dark:text-gray-400 text-sm' 27 | } 28 | 29 | return '' 30 | }) 31 | 32 | return { 33 | divClasses, 34 | ulClasses, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/components/FwbTabs/injection/config.ts: -------------------------------------------------------------------------------- 1 | // dependency injection config for tabs 2 | 3 | export const TAB_ACTIVATE_INJECTION_KEY = 'flowbite-tab-activate-func-injection' 4 | export const TAB_ACTIVE_NAME_INJECTION_KEY = 'flowbite-tab-active-name-injection' 5 | export const TAB_STYLE_INJECTION_KEY = 'flowbite-tab-style-injection' 6 | export const TAB_VISIBILITY_DIRECTIVE_INJECTION_KEY = 'flowbite-tab-visibility-directive-injection' 7 | -------------------------------------------------------------------------------- /src/components/FwbTabs/types.ts: -------------------------------------------------------------------------------- 1 | export type TabsVariant = 'default' | 'underline' | 'pills' 2 | -------------------------------------------------------------------------------- /src/components/FwbTextarea/composables/useTextareaClasses.ts: -------------------------------------------------------------------------------- 1 | import { computed } from 'vue' 2 | 3 | import { simplifyTailwindClasses } from '@/utils/simplifyTailwindClasses' 4 | 5 | const textareaWrapperClasses = 'block w-full mb-4 border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-700 dark:border-gray-600' 6 | const textareaDefaultClasses = 'block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-200 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 disabled:cursor-not-allowed disabled:opacity-50' 7 | const textareaLabelClasses = 'block mb-2 text-sm font-medium text-gray-900 dark:text-white' 8 | const textareaFooterClasses = 'block py-2 px-3 border-gray-200 dark:border-gray-600' 9 | 10 | export function useTextareaClasses (custom: boolean) { 11 | const textareaClasses = computed(() => simplifyTailwindClasses( 12 | textareaDefaultClasses, 13 | custom ? 'bg-white dark:bg-gray-800 border-none' : 'border', 14 | )) 15 | 16 | const labelClasses = computed(() => textareaLabelClasses) 17 | const wrapperClasses = computed(() => (custom) ? textareaWrapperClasses : '') 18 | const footerClasses = computed(() => textareaFooterClasses) 19 | 20 | return { 21 | textareaClasses, 22 | labelClasses, 23 | wrapperClasses, 24 | footerClasses, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/components/FwbTimeline/FwbTimeline.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 34 | -------------------------------------------------------------------------------- /src/components/FwbTimeline/FwbTimelineBody.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/components/FwbTimeline/FwbTimelineContent.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /src/components/FwbTimeline/FwbTimelineItem.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | -------------------------------------------------------------------------------- /src/components/FwbTimeline/FwbTimelineTime.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/components/FwbTimeline/FwbTimelineTitle.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/components/FwbToast/composables/useToast.ts: -------------------------------------------------------------------------------- 1 | import { inject } from 'vue' 2 | 3 | import { FLOWBITE_TOAST_INJECTION_KEY } from '../injection/config' 4 | 5 | import type { ToastItem, UseToastInjection } from '../types' 6 | 7 | export function useToast (): UseToastInjection { 8 | const injection = inject(FLOWBITE_TOAST_INJECTION_KEY, null) 9 | if (injection === null) console.warn('Cannot use useToast outside component. Please wrap your component with ') 10 | 11 | const add = (toast: ToastItem): string => { 12 | if (!injection) { 13 | return '' 14 | } 15 | 16 | return injection?.add(toast) 17 | } 18 | 19 | const remove = (id: string): boolean => { 20 | if (!injection) { 21 | return false 22 | } 23 | 24 | return injection?.remove(id) 25 | } 26 | 27 | const pop = (): string => { 28 | if (!injection) { 29 | return '' 30 | } 31 | 32 | return injection?.pop() 33 | } 34 | 35 | return { 36 | add, 37 | remove, 38 | pop, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/components/FwbToast/injection/config.ts: -------------------------------------------------------------------------------- 1 | export const FLOWBITE_TOAST_INJECTION_KEY = 'flowbite-toast-injection-key' 2 | -------------------------------------------------------------------------------- /src/components/FwbToast/types.ts: -------------------------------------------------------------------------------- 1 | import type { DefineComponent } from 'vue' 2 | 3 | export type ToastAlign = 'start' | 'center' | 'end' 4 | export type ToastType = 'success' | 'warning' | 'danger' | 'empty' 5 | 6 | export type ToastItem = { 7 | time: number // ms 8 | type: ToastType 9 | text: string 10 | component?: DefineComponent 11 | componentProps?: Record 12 | } 13 | 14 | export type ToastItemWithId = ToastItem & { 15 | id: string 16 | } 17 | 18 | export type ToastTransition = 'slide-left' | 'slide-right' | 'fade' | 'slide-top' | 'slide-bottom' 19 | 20 | export type UseToastInjection = { 21 | add: (toast: ToastItem) => string 22 | remove: (id: string) => boolean // true if removed, false if not found 23 | pop: () => string // empty '' string if no toast to pop 24 | } 25 | -------------------------------------------------------------------------------- /src/components/FwbToggle/FwbToggle.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 59 | -------------------------------------------------------------------------------- /src/components/FwbTooltip/types.ts: -------------------------------------------------------------------------------- 1 | export type TooltipPlacement = 'auto' | 'auto-start' | 'auto-end' | 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'right' | 'right-start' | 'right-end' | 'left' | 'left-start' | 'left-end' 2 | export type TooltipStyle = 'dark' | 'light' 3 | export type TooltipTrigger = 'hover' | 'click' 4 | -------------------------------------------------------------------------------- /src/components/Typography/FwbA.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 21 | -------------------------------------------------------------------------------- /src/components/Typography/FwbBlockquote.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 39 | -------------------------------------------------------------------------------- /src/components/Typography/FwbHeading.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 49 | -------------------------------------------------------------------------------- /src/components/Typography/FwbImg.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 44 | -------------------------------------------------------------------------------- /src/components/Typography/FwbP.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 27 | -------------------------------------------------------------------------------- /src/components/utils/FlowbiteThemable/FlowbiteThemable.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 22 | -------------------------------------------------------------------------------- /src/components/utils/FlowbiteThemable/FlowbiteThemableChild.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 40 | -------------------------------------------------------------------------------- /src/components/utils/FlowbiteThemable/injection/config.ts: -------------------------------------------------------------------------------- 1 | export const FLOWBITE_THEMABLE_INJECTION_KEY = 'flowbite-themable-injection-key' 2 | -------------------------------------------------------------------------------- /src/components/utils/FlowbiteThemable/types.ts: -------------------------------------------------------------------------------- 1 | export type FlowbiteTheme = 'blue' | 'green' | 'red' | 'pink' | 'purple' 2 | 3 | export type FlowbiteThemablePayload = { 4 | theme: FlowbiteTheme 5 | } 6 | 7 | export type ThemableChildrenApply = 'background' | 'disabled' | 'hover' | 'text' | 'border' | 'focus' 8 | -------------------------------------------------------------------------------- /src/components/utils/FwbSlotListener/types.ts: -------------------------------------------------------------------------------- 1 | export type SlotListenerTrigger = 'click' | 'focus' | 'hover' 2 | 3 | export type TriggerEventHandlers = { 4 | onClick: (e: MouseEvent) => void 5 | onMouseenter: (e: MouseEvent) => void 6 | onMouseleave: (e: MouseEvent) => void 7 | onFocus: (e: FocusEvent) => void 8 | onBlur: (e: FocusEvent) => void 9 | } 10 | -------------------------------------------------------------------------------- /src/composables.ts: -------------------------------------------------------------------------------- 1 | import { useToast } from '@/components/FwbToast/composables/useToast' 2 | 3 | export { useToast } 4 | -------------------------------------------------------------------------------- /src/composables/useClasses.ts: -------------------------------------------------------------------------------- 1 | export function useClasses () { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /src/composables/useMergeClasses.ts: -------------------------------------------------------------------------------- 1 | import { twMerge } from 'tailwind-merge' 2 | 3 | import type { ClassInput } from '@/types/global' 4 | 5 | function normalizeClasses (input: ClassInput): string { 6 | if (typeof input === 'string') { 7 | return input.trim() 8 | } 9 | 10 | if (Array.isArray(input)) { 11 | return input 12 | .map(normalizeClasses) 13 | .join(' ') 14 | .trim() 15 | } 16 | 17 | if (typeof input === 'object' && input !== null) { 18 | return Object.entries(input) 19 | .filter(([_, value]) => value) 20 | .map(([key]) => key) 21 | .join(' ') 22 | } 23 | 24 | return '' 25 | } 26 | 27 | export const useMergeClasses = (componentClasses: ClassInput): string => { 28 | return twMerge(normalizeClasses(componentClasses)) 29 | } 30 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | -------------------------------------------------------------------------------- /src/types/global.ts: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'vue' 2 | 3 | export type ClassInput = string | Record | Array> 4 | 5 | export type ClassRef = Ref 6 | -------------------------------------------------------------------------------- /src/utils/flatten.ts: -------------------------------------------------------------------------------- 1 | import { Comment, createTextVNode, Fragment, type VNode, type VNodeChild } from 'vue' 2 | 3 | // o(n) flatten 4 | export function flatten ( 5 | vNodes: VNodeChild[], 6 | filterCommentNode = true, 7 | result: VNode[] = [], 8 | ): VNode[] { 9 | vNodes.forEach((vNode) => { 10 | if (vNode === null) { 11 | return 12 | } 13 | 14 | if (typeof vNode !== 'object') { 15 | if (typeof vNode === 'string' || typeof vNode === 'number') { 16 | result.push(createTextVNode(String(vNode))) 17 | } 18 | 19 | return 20 | } 21 | 22 | if (Array.isArray(vNode)) { 23 | flatten(vNode, filterCommentNode, result) 24 | 25 | return 26 | } 27 | 28 | if (vNode.type === Fragment) { 29 | if (vNode.children === null) { 30 | return 31 | } 32 | 33 | if (Array.isArray(vNode.children)) { 34 | flatten(vNode.children, filterCommentNode, result) 35 | } 36 | // rawSlot 37 | } else if (vNode.type !== Comment) { 38 | result.push(vNode) 39 | } 40 | }) 41 | 42 | return result 43 | } 44 | -------------------------------------------------------------------------------- /src/utils/getFirstSlotNode.ts: -------------------------------------------------------------------------------- 1 | import { flatten } from './flatten' 2 | 3 | import type { Slots, VNode } from 'vue' 4 | 5 | // ref: https://github.com/TuSimple/naive-ui/blob/main/src/popover/src/Popover.tsx 6 | 7 | export function getFirstSlotVNode ( 8 | slots: Slots, 9 | slotName = 'default', 10 | props: unknown = undefined, 11 | ): VNode | null { 12 | const slot = slots[slotName] 13 | if (!slot) { 14 | console.warn('getFirstSlotVNode', `slot[${slotName}] is empty`) 15 | return null 16 | } 17 | const slotContent = flatten(slot(props)) 18 | // vue will normalize the slot, so slot must be an array 19 | if (slotContent.length === 1) { 20 | return slotContent[0] 21 | } else { 22 | console.warn('getFirstSlotVNode', `slot[${slotName}] should have exactly one child`) 23 | return null 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /static.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "docs/.vitepress/dist" 3 | } 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.dom.json", 3 | "compilerOptions": { 4 | "allowImportingTsExtensions": false, 5 | "noEmit": false, 6 | "baseUrl": ".", 7 | "outDir": "dist", 8 | "paths": { 9 | "@/*": [ 10 | "./src/*" 11 | ] 12 | } 13 | }, 14 | "include": [ 15 | "src/**/*.ts", 16 | "src/**/*.d.ts", 17 | "src/**/*.tsx", 18 | "src/**/*.vue" 19 | ], 20 | "exclude": [ 21 | "node_modules", 22 | "**/node_modules", 23 | "docs", 24 | "dist" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path' 2 | 3 | import tailwindcss from '@tailwindcss/vite' 4 | import vue from '@vitejs/plugin-vue' 5 | import { defineConfig } from 'vite' 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig({ 9 | plugins: [ 10 | vue(), 11 | tailwindcss(), 12 | ], 13 | resolve: { 14 | alias: { 15 | '@': resolve(__dirname, './src'), 16 | }, 17 | dedupe: ['vue'], 18 | }, 19 | build: { 20 | cssCodeSplit: true, 21 | target: 'esnext', 22 | lib: { 23 | entry: resolve(__dirname, './src/index.ts'), 24 | name: 'flowbite-vue', 25 | }, 26 | rollupOptions: { 27 | // make sure to externalize deps that shouldn't be bundled 28 | // into your library 29 | external: ['vue'], 30 | output: { 31 | // Provide global variables to use in the UMD build 32 | // for externalized deps 33 | globals: { 34 | vue: 'Vue', 35 | }, 36 | }, 37 | }, 38 | }, 39 | }) 40 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | 3 | import vue from '@vitejs/plugin-vue' 4 | import { defineConfig } from 'vitest/config' 5 | 6 | export default defineConfig({ 7 | plugins: [ 8 | vue(), 9 | ], 10 | test: { 11 | globals: true, 12 | environment: 'jsdom', 13 | }, 14 | resolve: { 15 | alias: { 16 | '@': path.resolve(__dirname, './src'), 17 | }, 18 | }, 19 | }) 20 | --------------------------------------------------------------------------------