@intlayer/design-system 7.2.1-canary.1 → 7.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/components/Accordion/Accordion.mjs +1 -2
- package/dist/esm/components/Accordion/Accordion.mjs.map +1 -1
- package/dist/esm/components/Avatar/index.mjs +1 -1
- package/dist/esm/components/Breadcrumb/index.mjs +1 -2
- package/dist/esm/components/Breadcrumb/index.mjs.map +1 -1
- package/dist/esm/components/Browser/Browser.mjs +1 -2
- package/dist/esm/components/Browser/Browser.mjs.map +1 -1
- package/dist/esm/components/ClickOutsideDiv/index.mjs +0 -1
- package/dist/esm/components/ClickOutsideDiv/index.mjs.map +1 -1
- package/dist/esm/components/CollapsibleTable/CollapsibleTable.mjs +1 -2
- package/dist/esm/components/CollapsibleTable/CollapsibleTable.mjs.map +1 -1
- package/dist/esm/components/Command/index.mjs +0 -1
- package/dist/esm/components/Command/index.mjs.map +1 -1
- package/dist/esm/components/ContentEditor/ContentEditor.mjs +1 -2
- package/dist/esm/components/ContentEditor/ContentEditor.mjs.map +1 -1
- package/dist/esm/components/ContentEditor/ContentEditorInput.mjs +1 -2
- package/dist/esm/components/ContentEditor/ContentEditorInput.mjs.map +1 -1
- package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +2 -3
- package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs.map +1 -1
- package/dist/esm/components/ContentSelector/ContentSelector.mjs +0 -1
- package/dist/esm/components/ContentSelector/ContentSelector.mjs.map +1 -1
- package/dist/esm/components/CopyButton/index.mjs +1 -2
- package/dist/esm/components/CopyButton/index.mjs.map +1 -1
- package/dist/esm/components/CopyToClipboard/index.mjs +1 -2
- package/dist/esm/components/CopyToClipboard/index.mjs.map +1 -1
- package/dist/esm/components/DictionaryEditor/DictionaryEditor.mjs +1 -2
- package/dist/esm/components/DictionaryEditor/DictionaryEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryEditor/NodeWrapper/FileWrapper.mjs +1 -1
- package/dist/esm/components/DictionaryEditor/NodeWrapper/StringWrapper.mjs +1 -1
- package/dist/esm/components/DictionaryEditor/NodeWrapper/index.mjs +1 -2
- package/dist/esm/components/DictionaryEditor/NodeWrapper/index.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs +1 -2
- package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +3 -4
- package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +1 -2
- package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +4 -5
- package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +2 -3
- package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/EnumKeyInput.mjs +0 -1
- package/dist/esm/components/DictionaryFieldEditor/EnumKeyInput.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/JSONEditor.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +2 -2
- package/dist/esm/components/DictionaryFieldEditor/NodeTypeSelector.mjs +0 -1
- package/dist/esm/components/DictionaryFieldEditor/NodeTypeSelector.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +4 -5
- package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/StructureEditor.mjs +1 -2
- package/dist/esm/components/DictionaryFieldEditor/StructureEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +1 -2
- package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/VersionSwitcherDropDown/VersionSwitcher.mjs +0 -1
- package/dist/esm/components/DictionaryFieldEditor/VersionSwitcherDropDown/VersionSwitcher.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/VersionSwitcherDropDown/VersionSwitcherContext.mjs +0 -1
- package/dist/esm/components/DictionaryFieldEditor/VersionSwitcherDropDown/VersionSwitcherContext.mjs.map +1 -1
- package/dist/esm/components/EditableField/EditableFieldInput.mjs +0 -1
- package/dist/esm/components/EditableField/EditableFieldInput.mjs.map +1 -1
- package/dist/esm/components/EditableField/EditableFieldLayout.mjs +1 -2
- package/dist/esm/components/EditableField/EditableFieldLayout.mjs.map +1 -1
- package/dist/esm/components/EditableField/EditableFieldTextArea.mjs +0 -1
- package/dist/esm/components/EditableField/EditableFieldTextArea.mjs.map +1 -1
- package/dist/esm/components/ExpandCollapse/ExpandCollapse.mjs +0 -1
- package/dist/esm/components/ExpandCollapse/ExpandCollapse.mjs.map +1 -1
- package/dist/esm/components/Form/FormBase.mjs +0 -1
- package/dist/esm/components/Form/FormBase.mjs.map +1 -1
- package/dist/esm/components/Form/FormControl.mjs +0 -1
- package/dist/esm/components/Form/FormControl.mjs.map +1 -1
- package/dist/esm/components/Form/FormDescription.mjs +0 -1
- package/dist/esm/components/Form/FormDescription.mjs.map +1 -1
- package/dist/esm/components/Form/FormField.mjs +0 -1
- package/dist/esm/components/Form/FormField.mjs.map +1 -1
- package/dist/esm/components/Form/FormItem.mjs +0 -1
- package/dist/esm/components/Form/FormItem.mjs.map +1 -1
- package/dist/esm/components/Form/FormLabel.mjs +0 -1
- package/dist/esm/components/Form/FormLabel.mjs.map +1 -1
- package/dist/esm/components/Form/FormMessage.mjs +0 -1
- package/dist/esm/components/Form/FormMessage.mjs.map +1 -1
- package/dist/esm/components/Form/elements/FormElement.mjs +0 -1
- package/dist/esm/components/Form/elements/FormElement.mjs.map +1 -1
- package/dist/esm/components/Form/elements/FormElementWrapper.mjs +0 -1
- package/dist/esm/components/Form/elements/FormElementWrapper.mjs.map +1 -1
- package/dist/esm/components/Form/elements/MultiselectElement.mjs +0 -1
- package/dist/esm/components/Form/elements/MultiselectElement.mjs.map +1 -1
- package/dist/esm/components/Form/elements/OTPElement.mjs +0 -1
- package/dist/esm/components/Form/elements/OTPElement.mjs.map +1 -1
- package/dist/esm/components/Form/elements/SelectElement.mjs +0 -1
- package/dist/esm/components/Form/elements/SelectElement.mjs.map +1 -1
- package/dist/esm/components/Form/elements/SwitchSelectorElement.mjs +0 -1
- package/dist/esm/components/Form/elements/SwitchSelectorElement.mjs.map +1 -1
- package/dist/esm/components/HeightResizer/index.mjs +0 -1
- package/dist/esm/components/HeightResizer/index.mjs.map +1 -1
- package/dist/esm/components/HideShow/index.mjs +1 -2
- package/dist/esm/components/HideShow/index.mjs.map +1 -1
- package/dist/esm/components/IDE/CodeBlockShiki.mjs +0 -1
- package/dist/esm/components/IDE/CodeBlockShiki.mjs.map +1 -1
- package/dist/esm/components/IDE/CodeConditionalRenderer.mjs +0 -1
- package/dist/esm/components/IDE/CodeConditionalRenderer.mjs.map +1 -1
- package/dist/esm/components/IDE/CodeContext.mjs +0 -1
- package/dist/esm/components/IDE/CodeContext.mjs.map +1 -1
- package/dist/esm/components/IDE/CodeFormatSelector.mjs +0 -1
- package/dist/esm/components/IDE/CodeFormatSelector.mjs.map +1 -1
- package/dist/esm/components/IDE/ContentDeclarationFormatSelector.mjs +0 -1
- package/dist/esm/components/IDE/ContentDeclarationFormatSelector.mjs.map +1 -1
- package/dist/esm/components/IDE/CopyCode.mjs +0 -1
- package/dist/esm/components/IDE/CopyCode.mjs.map +1 -1
- package/dist/esm/components/IDE/FileTree.mjs +1 -2
- package/dist/esm/components/IDE/FileTree.mjs.map +1 -1
- package/dist/esm/components/IDE/IDE.mjs +0 -1
- package/dist/esm/components/IDE/IDE.mjs.map +1 -1
- package/dist/esm/components/IDE/MonacoCode.mjs +0 -1
- package/dist/esm/components/IDE/MonacoCode.mjs.map +1 -1
- package/dist/esm/components/IDE/PackageManagerSelector.mjs +0 -1
- package/dist/esm/components/IDE/PackageManagerSelector.mjs.map +1 -1
- package/dist/esm/components/Input/InputPassword.mjs +1 -2
- package/dist/esm/components/Input/InputPassword.mjs.map +1 -1
- package/dist/esm/components/Input/OTPInput.mjs +1 -2
- package/dist/esm/components/Input/OTPInput.mjs.map +1 -1
- package/dist/esm/components/KeyboardScreenAdapter/index.mjs +1 -2
- package/dist/esm/components/KeyboardScreenAdapter/index.mjs.map +1 -1
- package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +2 -3
- package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs.map +1 -1
- package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContentContext.mjs +0 -1
- package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContentContext.mjs.map +1 -1
- package/dist/esm/components/LocaleSwitcherDropDown/LocaleSwitcher.mjs +1 -2
- package/dist/esm/components/LocaleSwitcherDropDown/LocaleSwitcher.mjs.map +1 -1
- package/dist/esm/components/Modal/Modal.mjs +3 -4
- package/dist/esm/components/Modal/Modal.mjs.map +1 -1
- package/dist/esm/components/Navbar/DesktopNavbar.mjs +0 -1
- package/dist/esm/components/Navbar/DesktopNavbar.mjs.map +1 -1
- package/dist/esm/components/Navbar/MobileNavbar.mjs +2 -3
- package/dist/esm/components/Navbar/MobileNavbar.mjs.map +1 -1
- package/dist/esm/components/Navbar/index.mjs +0 -1
- package/dist/esm/components/Navbar/index.mjs.map +1 -1
- package/dist/esm/components/Navbar/useNavigation.mjs +0 -1
- package/dist/esm/components/Navbar/useNavigation.mjs.map +1 -1
- package/dist/esm/components/Pagination/NumberItemsSelector.mjs +0 -1
- package/dist/esm/components/Pagination/NumberItemsSelector.mjs.map +1 -1
- package/dist/esm/components/Pagination/Pagination.mjs +0 -1
- package/dist/esm/components/Pagination/Pagination.mjs.map +1 -1
- package/dist/esm/components/Pagination/ShowingResultsNumberItems.mjs +0 -1
- package/dist/esm/components/Pagination/ShowingResultsNumberItems.mjs.map +1 -1
- package/dist/esm/components/Popover/dynamic.mjs +0 -1
- package/dist/esm/components/Popover/dynamic.mjs.map +1 -1
- package/dist/esm/components/PressableSpan/PressableSpan.mjs +0 -1
- package/dist/esm/components/PressableSpan/PressableSpan.mjs.map +1 -1
- package/dist/esm/components/RightDrawer/RightDrawer.mjs +3 -4
- package/dist/esm/components/RightDrawer/RightDrawer.mjs.map +1 -1
- package/dist/esm/components/Select/Multiselect.mjs +1 -2
- package/dist/esm/components/Select/Multiselect.mjs.map +1 -1
- package/dist/esm/components/Select/Select.mjs +0 -1
- package/dist/esm/components/Select/Select.mjs.map +1 -1
- package/dist/esm/components/SwitchSelector/index.mjs +1 -2
- package/dist/esm/components/SwitchSelector/index.mjs.map +1 -1
- package/dist/esm/components/Tab/Tab.mjs +1 -2
- package/dist/esm/components/Tab/Tab.mjs.map +1 -1
- package/dist/esm/components/Tab/TabContext.mjs +0 -1
- package/dist/esm/components/Tab/TabContext.mjs.map +1 -1
- package/dist/esm/components/TabSelector/TabSelector.mjs +1 -2
- package/dist/esm/components/TabSelector/TabSelector.mjs.map +1 -1
- package/dist/esm/components/Table/Table.mjs +1 -2
- package/dist/esm/components/Table/Table.mjs.map +1 -1
- package/dist/esm/components/TextArea/AutoSizeTextArea.mjs +0 -1
- package/dist/esm/components/TextArea/AutoSizeTextArea.mjs.map +1 -1
- package/dist/esm/components/TextArea/AutocompleteTextArea.mjs +1 -2
- package/dist/esm/components/TextArea/AutocompleteTextArea.mjs.map +1 -1
- package/dist/esm/components/ThemeSwitcherDropDown/DesktopThemeSwitcher.mjs +1 -2
- package/dist/esm/components/ThemeSwitcherDropDown/DesktopThemeSwitcher.mjs.map +1 -1
- package/dist/esm/components/ThemeSwitcherDropDown/MobileThemeSwitcher.mjs +1 -2
- package/dist/esm/components/ThemeSwitcherDropDown/MobileThemeSwitcher.mjs.map +1 -1
- package/dist/esm/components/Toaster/Toast.mjs +0 -1
- package/dist/esm/components/Toaster/Toast.mjs.map +1 -1
- package/dist/esm/components/Toaster/Toaster.mjs +0 -1
- package/dist/esm/components/Toaster/Toaster.mjs.map +1 -1
- package/dist/esm/components/Toaster/useToast.mjs +0 -1
- package/dist/esm/components/Toaster/useToast.mjs.map +1 -1
- package/dist/esm/components/WithResizer/index.mjs +0 -1
- package/dist/esm/components/WithResizer/index.mjs.map +1 -1
- package/dist/esm/hooks/reactQuery.mjs +0 -1
- package/dist/esm/hooks/reactQuery.mjs.map +1 -1
- package/dist/esm/hooks/useAuth/useAuth.mjs +0 -1
- package/dist/esm/hooks/useAuth/useAuth.mjs.map +1 -1
- package/dist/esm/hooks/useAuth/useOAuth2.mjs +0 -1
- package/dist/esm/hooks/useAuth/useOAuth2.mjs.map +1 -1
- package/dist/esm/hooks/useAuth/useSession.mjs +0 -1
- package/dist/esm/hooks/useAuth/useSession.mjs.map +1 -1
- package/dist/esm/hooks/useDevice.mjs +0 -1
- package/dist/esm/hooks/useDevice.mjs.map +1 -1
- package/dist/esm/hooks/useGetElementOrWindow.mjs +0 -1
- package/dist/esm/hooks/useGetElementOrWindow.mjs.map +1 -1
- package/dist/esm/hooks/useHorizontalSwipe.mjs +0 -1
- package/dist/esm/hooks/useHorizontalSwipe.mjs.map +1 -1
- package/dist/esm/hooks/useIsDarkMode.mjs +0 -1
- package/dist/esm/hooks/useIsDarkMode.mjs.map +1 -1
- package/dist/esm/hooks/useIsMounted.mjs +0 -1
- package/dist/esm/hooks/useIsMounted.mjs.map +1 -1
- package/dist/esm/hooks/useItemSelector.mjs +0 -1
- package/dist/esm/hooks/useItemSelector.mjs.map +1 -1
- package/dist/esm/hooks/useKeyboardDetector.mjs +0 -1
- package/dist/esm/hooks/useKeyboardDetector.mjs.map +1 -1
- package/dist/esm/hooks/usePersistedStore.mjs +0 -1
- package/dist/esm/hooks/usePersistedStore.mjs.map +1 -1
- package/dist/esm/hooks/useScreenWidth.mjs +0 -1
- package/dist/esm/hooks/useScreenWidth.mjs.map +1 -1
- package/dist/esm/hooks/useScrollBlockage/index.mjs +0 -1
- package/dist/esm/hooks/useScrollBlockage/index.mjs.map +1 -1
- package/dist/esm/hooks/useScrollDetection.mjs +0 -1
- package/dist/esm/hooks/useScrollDetection.mjs.map +1 -1
- package/dist/esm/hooks/useScrollY.mjs +0 -1
- package/dist/esm/hooks/useScrollY.mjs.map +1 -1
- package/dist/esm/hooks/useSearch.mjs +0 -1
- package/dist/esm/hooks/useSearch.mjs.map +1 -1
- package/dist/esm/hooks/useUser/index.mjs +0 -1
- package/dist/esm/hooks/useUser/index.mjs.map +1 -1
- package/dist/esm/providers/ReactQueryProvider.mjs +1 -2
- package/dist/esm/providers/ReactQueryProvider.mjs.map +1 -1
- package/dist/types/components/Badge/index.d.ts +2 -2
- package/dist/types/components/Breadcrumb/breadcrumb.content.d.ts +3 -3
- package/dist/types/components/Breadcrumb/breadcrumb.content.d.ts.map +1 -1
- package/dist/types/components/Breadcrumb/index.d.ts +2 -2
- package/dist/types/components/Browser/Browser.content.d.ts +11 -11
- package/dist/types/components/Button/Button.d.ts +6 -6
- package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +2 -2
- package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts.map +1 -1
- package/dist/types/components/Command/index.d.ts +20 -20
- package/dist/types/components/Container/index.d.ts +9 -9
- package/dist/types/components/Container/index.d.ts.map +1 -1
- package/dist/types/components/CopyButton/CopyButton.content.d.ts +3 -3
- package/dist/types/components/CopyButton/CopyButton.content.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/dictionaryCreationForm.content.d.ts +25 -25
- package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/useDictionaryFormSchema.content.d.ts +9 -9
- package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/dictionaryDetails.content.d.ts +33 -33
- package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/useDictionaryDetailsSchema.content.d.ts +25 -25
- package/dist/types/components/DictionaryFieldEditor/NavigationView/navigationViewNode.content.d.ts +25 -25
- package/dist/types/components/DictionaryFieldEditor/NavigationView/navigationViewNode.content.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/SaveForm/saveForm.content.d.ts +33 -33
- package/dist/types/components/DictionaryFieldEditor/StructureView/structureView.content.d.ts +9 -9
- package/dist/types/components/DictionaryFieldEditor/VersionSwitcherDropDown/versionSwitcherDropDown.content.d.ts +7 -7
- package/dist/types/components/DictionaryFieldEditor/dictionaryFieldEditor.content.d.ts +5 -5
- package/dist/types/components/DictionaryFieldEditor/nodeTypeSelector.content.d.ts +31 -31
- package/dist/types/components/ExpandCollapse/expandCollapse.content.d.ts +3 -3
- package/dist/types/components/Form/FormBase.d.ts +2 -2
- package/dist/types/components/Form/FormBase.d.ts.map +1 -1
- package/dist/types/components/Form/FormField.d.ts +2 -2
- package/dist/types/components/Form/FormField.d.ts.map +1 -1
- package/dist/types/components/Form/FormItem.d.ts +2 -2
- package/dist/types/components/Form/FormItem.d.ts.map +1 -1
- package/dist/types/components/Form/elements/EditableFieldInputElement.d.ts +2 -2
- package/dist/types/components/Form/elements/EditableFieldTextAreaElement.d.ts +2 -2
- package/dist/types/components/Form/elements/EditableFieldTextAreaElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/FormElement.d.ts +2 -2
- package/dist/types/components/Form/elements/FormElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/MultiselectElement.d.ts +2 -2
- package/dist/types/components/Form/elements/MultiselectElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/OTPElement.d.ts +2 -2
- package/dist/types/components/Form/elements/OTPElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/SelectElement.d.ts +2 -2
- package/dist/types/components/Form/elements/SelectElement.d.ts.map +1 -1
- package/dist/types/components/Form/elements/SwitchSelectorElement.d.ts +2 -2
- package/dist/types/components/Form/elements/SwitchSelectorElement.d.ts.map +1 -1
- package/dist/types/components/IDE/CodeContext.d.ts +2 -2
- package/dist/types/components/IDE/CodeContext.d.ts.map +1 -1
- package/dist/types/components/IDE/code.content.d.ts +5 -5
- package/dist/types/components/IDE/code.content.d.ts.map +1 -1
- package/dist/types/components/IDE/copyCode.content.d.ts +5 -5
- package/dist/types/components/IDE/copyCode.content.d.ts.map +1 -1
- package/dist/types/components/Input/Checkbox.d.ts +4 -4
- package/dist/types/components/Input/Checkbox.d.ts.map +1 -1
- package/dist/types/components/Input/Input.d.ts +3 -3
- package/dist/types/components/Input/Input.d.ts.map +1 -1
- package/dist/types/components/Input/OTPInput.d.ts +6 -6
- package/dist/types/components/Input/OTPInput.d.ts.map +1 -1
- package/dist/types/components/Input/SearchInput.d.ts +2 -2
- package/dist/types/components/Input/SearchInput.d.ts.map +1 -1
- package/dist/types/components/Link/Link.d.ts +3 -3
- package/dist/types/components/Loader/index.content.d.ts +3 -3
- package/dist/types/components/Loader/index.content.d.ts.map +1 -1
- package/dist/types/components/Loader/spinner.d.ts +2 -2
- package/dist/types/components/LocaleSwitcherContentDropDown/localeSwitcher.content.d.ts +17 -17
- package/dist/types/components/LocaleSwitcherContentDropDown/localeSwitcher.content.d.ts.map +1 -1
- package/dist/types/components/LocaleSwitcherDropDown/localeSwitcher.content.d.ts +13 -13
- package/dist/types/components/LocaleSwitcherDropDown/localeSwitcher.content.d.ts.map +1 -1
- package/dist/types/components/MarkDownRender/processor.d.ts.map +1 -1
- package/dist/types/components/MaxWidthSmoother/index.d.ts +2 -2
- package/dist/types/components/Navbar/Burger.d.ts +2 -2
- package/dist/types/components/Navbar/Burger.d.ts.map +1 -1
- package/dist/types/components/Navbar/DesktopNavbar.d.ts +2 -2
- package/dist/types/components/Navbar/MobileNavbar.d.ts +2 -2
- package/dist/types/components/Navbar/MobileNavbar.d.ts.map +1 -1
- package/dist/types/components/Navbar/index.d.ts +2 -2
- package/dist/types/components/Navbar/index.d.ts.map +1 -1
- package/dist/types/components/Pagination/Pagination.d.ts +4 -4
- package/dist/types/components/Pagination/Pagination.d.ts.map +1 -1
- package/dist/types/components/Pagination/pagination.content.d.ts +11 -11
- package/dist/types/components/Popover/static.d.ts +3 -3
- package/dist/types/components/Select/Select.d.ts +3 -3
- package/dist/types/components/SocialNetworks/index.d.ts +2 -2
- package/dist/types/components/SocialNetworks/index.d.ts.map +1 -1
- package/dist/types/components/SwitchSelector/index.d.ts +7 -7
- package/dist/types/components/SwitchSelector/index.d.ts.map +1 -1
- package/dist/types/components/Tab/Tab.d.ts +6 -6
- package/dist/types/components/Tab/TabContext.d.ts +2 -2
- package/dist/types/components/TabSelector/TabSelector.d.ts +5 -5
- package/dist/types/components/TabSelector/TabSelector.d.ts.map +1 -1
- package/dist/types/components/Table/table.content.d.ts +3 -3
- package/dist/types/components/Table/table.content.d.ts.map +1 -1
- package/dist/types/components/Tag/index.d.ts +5 -5
- package/dist/types/components/Tag/index.d.ts.map +1 -1
- package/dist/types/components/Toaster/Toast.d.ts +2 -2
- package/dist/types/components/Toaster/Toast.d.ts.map +1 -1
- package/dist/types/components/Toaster/Toaster.d.ts +2 -2
- package/package.json +17 -17
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import { cn } from "../../utils/cn.mjs";
|
|
5
4
|
import { Button, ButtonColor, ButtonVariant } from "../Button/Button.mjs";
|
|
6
5
|
import { MaxHeightSmoother } from "../MaxHeightSmoother/index.mjs";
|
|
7
|
-
import { useId, useState } from "react";
|
|
8
6
|
import { ChevronDown } from "lucide-react";
|
|
7
|
+
import { useId, useState } from "react";
|
|
9
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
9
|
|
|
11
10
|
//#region src/components/Accordion/Accordion.tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Accordion.mjs","names":["Accordion: FC<AccordionProps>"],"sources":["../../../../src/components/Accordion/Accordion.tsx"],"sourcesContent":["'use client';\n\nimport { ChevronDown } from 'lucide-react';\nimport {\n type FC,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n useId,\n useState,\n} from 'react';\nimport { cn } from '../../utils/cn';\nimport {\n Button,\n ButtonColor,\n type ButtonProps,\n ButtonVariant,\n} from '../Button';\nimport { MaxHeightSmoother } from '../MaxHeightSmoother';\n\nexport interface AccordionProps\n extends Omit<ButtonProps, 'children' | 'onToggle'> {\n /** The content displayed in the accordion header */\n header: ReactNode;\n /** The collapsible content inside the accordion */\n children: ReactNode;\n /** Controls whether the accordion is open (controlled mode) */\n isOpen?: boolean;\n /** Default open state (uncontrolled mode) */\n defaultIsOpen?: boolean;\n /** Called when the accordion state changes */\n onToggle?: (isOpen: boolean) => void;\n /** Disable the accordion interaction */\n disabled?: boolean;\n /** Custom class for the content container */\n contentClassName?: string;\n /** Custom class for the header container */\n headerClassName?: string;\n /** Accessible label for screen readers */\n 'aria-label'?: string;\n /** ID for the accordion content (for aria-controls) */\n contentId?: string;\n}\n\n/**\n * Accordion component that allows the user to expand and collapse content.\n * It provides a header with a chevron icon that controls the visibility of the content.\n *\n * Features:\n * - Supports both controlled and uncontrolled modes\n * - Accessible with proper ARIA attributes\n * - Keyboard navigation support\n * - Smooth animations for expand/collapse\n * - Customizable styling\n *\n * @param header - The content of the header.\n * @param children - The content to be expanded and collapsed.\n * @param isOpen - Controlled state for whether the content is expanded.\n * @param defaultIsOpen - Default open state for uncontrolled mode.\n * @param onToggle - Callback when the accordion state changes.\n * @param disabled - Whether the accordion is disabled.\n * @param contentClassName - Custom class for the content container.\n * @param headerClassName - Custom class for the header.\n * @param contentId - ID for the content (used for aria-controls).\n *\n * @example\n * // Uncontrolled mode\n * <Accordion header=\"Accordion Header\" defaultIsOpen={true}>\n * <p>Accordion content</p>\n * </Accordion>\n *\n * @example\n * // Controlled mode\n * <Accordion\n * header=\"Controlled Accordion\"\n * isOpen={isOpen}\n * onToggle={setIsOpen}\n * >\n * <p>Controlled content</p>\n * </Accordion>\n */\nexport const Accordion: FC<AccordionProps> = ({\n children,\n header,\n isOpen,\n defaultIsOpen = false,\n onToggle,\n onClick,\n disabled = false,\n contentClassName,\n headerClassName,\n contentId,\n 'aria-label': ariaLabel,\n ...props\n}) => {\n // Determine if we're in controlled or uncontrolled mode\n const isControlled = isOpen !== undefined;\n const [internalIsOpen, setInternalIsOpen] = useState(defaultIsOpen);\n const id = useId();\n\n // Use controlled value if provided, otherwise use internal state\n const isExpandedState = isControlled ? isOpen : internalIsOpen;\n const isHidden = !isExpandedState;\n\n // Generate unique ID for content if not provided\n const generatedContentId = contentId ?? `${id}-accordion-content`;\n\n const handleToggle = (e: MouseEvent<HTMLButtonElement>) => {\n if (disabled) return;\n\n const newIsOpen = !isExpandedState;\n\n // Update internal state if uncontrolled\n if (!isControlled) {\n setInternalIsOpen(newIsOpen);\n }\n\n // Call external handlers\n onToggle?.(newIsOpen);\n onClick?.(e);\n };\n\n const handleKeyDown = (e: KeyboardEvent<HTMLButtonElement>) => {\n // Enter and Space should toggle the accordion\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleToggle(e as any);\n }\n };\n\n return (\n <div className=\"w-full\">\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n onClick={handleToggle}\n onKeyDown={handleKeyDown}\n disabled={disabled}\n isFullWidth\n className={cn(\n 'flex items-center justify-between gap-2',\n headerClassName\n )}\n IconRight={ChevronDown}\n iconClassName={cn(\n 'transform transition-transform duration-500 ease-in-out',\n isExpandedState ? 'rotate-0' : '-rotate-180'\n )}\n aria-expanded={isExpandedState}\n aria-controls={generatedContentId}\n aria-label={ariaLabel}\n role=\"button\"\n {...props}\n >\n {header}\n </Button>\n\n <MaxHeightSmoother\n id={generatedContentId}\n tabIndex={isHidden ? -1 : undefined}\n isHidden={isHidden}\n className={contentClassName}\n role=\"region\"\n aria-labelledby={generatedContentId}\n >\n {children}\n </MaxHeightSmoother>\n </div>\n );\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"Accordion.mjs","names":["Accordion: FC<AccordionProps>"],"sources":["../../../../src/components/Accordion/Accordion.tsx"],"sourcesContent":["'use client';\n\nimport { ChevronDown } from 'lucide-react';\nimport {\n type FC,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n useId,\n useState,\n} from 'react';\nimport { cn } from '../../utils/cn';\nimport {\n Button,\n ButtonColor,\n type ButtonProps,\n ButtonVariant,\n} from '../Button';\nimport { MaxHeightSmoother } from '../MaxHeightSmoother';\n\nexport interface AccordionProps\n extends Omit<ButtonProps, 'children' | 'onToggle'> {\n /** The content displayed in the accordion header */\n header: ReactNode;\n /** The collapsible content inside the accordion */\n children: ReactNode;\n /** Controls whether the accordion is open (controlled mode) */\n isOpen?: boolean;\n /** Default open state (uncontrolled mode) */\n defaultIsOpen?: boolean;\n /** Called when the accordion state changes */\n onToggle?: (isOpen: boolean) => void;\n /** Disable the accordion interaction */\n disabled?: boolean;\n /** Custom class for the content container */\n contentClassName?: string;\n /** Custom class for the header container */\n headerClassName?: string;\n /** Accessible label for screen readers */\n 'aria-label'?: string;\n /** ID for the accordion content (for aria-controls) */\n contentId?: string;\n}\n\n/**\n * Accordion component that allows the user to expand and collapse content.\n * It provides a header with a chevron icon that controls the visibility of the content.\n *\n * Features:\n * - Supports both controlled and uncontrolled modes\n * - Accessible with proper ARIA attributes\n * - Keyboard navigation support\n * - Smooth animations for expand/collapse\n * - Customizable styling\n *\n * @param header - The content of the header.\n * @param children - The content to be expanded and collapsed.\n * @param isOpen - Controlled state for whether the content is expanded.\n * @param defaultIsOpen - Default open state for uncontrolled mode.\n * @param onToggle - Callback when the accordion state changes.\n * @param disabled - Whether the accordion is disabled.\n * @param contentClassName - Custom class for the content container.\n * @param headerClassName - Custom class for the header.\n * @param contentId - ID for the content (used for aria-controls).\n *\n * @example\n * // Uncontrolled mode\n * <Accordion header=\"Accordion Header\" defaultIsOpen={true}>\n * <p>Accordion content</p>\n * </Accordion>\n *\n * @example\n * // Controlled mode\n * <Accordion\n * header=\"Controlled Accordion\"\n * isOpen={isOpen}\n * onToggle={setIsOpen}\n * >\n * <p>Controlled content</p>\n * </Accordion>\n */\nexport const Accordion: FC<AccordionProps> = ({\n children,\n header,\n isOpen,\n defaultIsOpen = false,\n onToggle,\n onClick,\n disabled = false,\n contentClassName,\n headerClassName,\n contentId,\n 'aria-label': ariaLabel,\n ...props\n}) => {\n // Determine if we're in controlled or uncontrolled mode\n const isControlled = isOpen !== undefined;\n const [internalIsOpen, setInternalIsOpen] = useState(defaultIsOpen);\n const id = useId();\n\n // Use controlled value if provided, otherwise use internal state\n const isExpandedState = isControlled ? isOpen : internalIsOpen;\n const isHidden = !isExpandedState;\n\n // Generate unique ID for content if not provided\n const generatedContentId = contentId ?? `${id}-accordion-content`;\n\n const handleToggle = (e: MouseEvent<HTMLButtonElement>) => {\n if (disabled) return;\n\n const newIsOpen = !isExpandedState;\n\n // Update internal state if uncontrolled\n if (!isControlled) {\n setInternalIsOpen(newIsOpen);\n }\n\n // Call external handlers\n onToggle?.(newIsOpen);\n onClick?.(e);\n };\n\n const handleKeyDown = (e: KeyboardEvent<HTMLButtonElement>) => {\n // Enter and Space should toggle the accordion\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleToggle(e as any);\n }\n };\n\n return (\n <div className=\"w-full\">\n <Button\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n onClick={handleToggle}\n onKeyDown={handleKeyDown}\n disabled={disabled}\n isFullWidth\n className={cn(\n 'flex items-center justify-between gap-2',\n headerClassName\n )}\n IconRight={ChevronDown}\n iconClassName={cn(\n 'transform transition-transform duration-500 ease-in-out',\n isExpandedState ? 'rotate-0' : '-rotate-180'\n )}\n aria-expanded={isExpandedState}\n aria-controls={generatedContentId}\n aria-label={ariaLabel}\n role=\"button\"\n {...props}\n >\n {header}\n </Button>\n\n <MaxHeightSmoother\n id={generatedContentId}\n tabIndex={isHidden ? -1 : undefined}\n isHidden={isHidden}\n className={contentClassName}\n role=\"region\"\n aria-labelledby={generatedContentId}\n >\n {children}\n </MaxHeightSmoother>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiFA,MAAaA,aAAiC,EAC5C,UACA,QACA,QACA,gBAAgB,OAChB,UACA,SACA,WAAW,OACX,kBACA,iBACA,WACA,cAAc,WACd,GAAG,YACC;CAEJ,MAAM,eAAe,WAAW;CAChC,MAAM,CAAC,gBAAgB,qBAAqB,SAAS,cAAc;CACnE,MAAM,KAAK,OAAO;CAGlB,MAAM,kBAAkB,eAAe,SAAS;CAChD,MAAM,WAAW,CAAC;CAGlB,MAAM,qBAAqB,aAAa,GAAG,GAAG;CAE9C,MAAM,gBAAgB,MAAqC;AACzD,MAAI,SAAU;EAEd,MAAM,YAAY,CAAC;AAGnB,MAAI,CAAC,aACH,mBAAkB,UAAU;AAI9B,aAAW,UAAU;AACrB,YAAU,EAAE;;CAGd,MAAM,iBAAiB,MAAwC;AAE7D,MAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,KAAE,gBAAgB;AAClB,gBAAa,EAAS;;;AAI1B,QACE,qBAAC;EAAI,WAAU;aACb,oBAAC;GACC,SAAS,cAAc;GACvB,OAAO,YAAY;GACnB,SAAS;GACT,WAAW;GACD;GACV;GACA,WAAW,GACT,2CACA,gBACD;GACD,WAAW;GACX,eAAe,GACb,2DACA,kBAAkB,aAAa,cAChC;GACD,iBAAe;GACf,iBAAe;GACf,cAAY;GACZ,MAAK;GACL,GAAI;aAEH;IACM,EAET,oBAAC;GACC,IAAI;GACJ,UAAU,WAAW,KAAK;GAChB;GACV,WAAW;GACX,MAAK;GACL,mBAAiB;GAEhB;IACiB;GAChB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cn } from "../../utils/cn.mjs";
|
|
2
2
|
import { Loader } from "../Loader/index.mjs";
|
|
3
|
-
import { forwardRef, useMemo } from "react";
|
|
4
3
|
import { User } from "lucide-react";
|
|
4
|
+
import { forwardRef, useMemo } from "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
|
|
7
7
|
//#region src/components/Avatar/index.tsx
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import { cn } from "../../utils/cn.mjs";
|
|
5
4
|
import { Button, ButtonVariant } from "../Button/Button.mjs";
|
|
6
5
|
import { Link, LinkColor } from "../Link/Link.mjs";
|
|
7
|
-
import { Fragment, createElement } from "react";
|
|
8
6
|
import { ChevronRightIcon } from "lucide-react";
|
|
7
|
+
import { Fragment, createElement } from "react";
|
|
9
8
|
import { cva } from "class-variance-authority";
|
|
10
9
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
11
10
|
import { getIntlayer } from "@intlayer/core";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["LinkLink: FC<LinkLinkProps>","ButtonLink: FC<ButtonButtonProps>","Span: FC<SpanProps>","Breadcrumb: FC<BreadcrumbProps>"],"sources":["../../../../src/components/Breadcrumb/index.tsx"],"sourcesContent":["'use client';\n\nimport { getIntlayer } from '@intlayer/core';\nimport type { LocalesValues } from '@intlayer/types';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport type { __DictionaryRegistry } from 'intlayer';\nimport { ChevronRightIcon } from 'lucide-react';\nimport { type FC, Fragment, type HTMLAttributes, type ReactNode } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { cn } from '../../utils/cn';\nimport { Button, type ButtonProps, ButtonVariant } from '../Button';\nimport { Link, LinkColor } from '../Link';\n\n/**\n * Props for LinkLink sub-component that renders breadcrumb items as links\n */\ntype LinkLinkProps = {\n /**\n * Position of the breadcrumb item in the list (1-based index)\n */\n position: number;\n /**\n * Locale for internationalization\n */\n locale?: LocalesValues;\n /**\n * URL to navigate to\n */\n href?: string;\n /**\n * Link color\n */\n color?: LinkColor | `${LinkColor}`;\n /**\n * Click handler\n */\n onClick?: () => void;\n /**\n * Children content\n */\n children?: string;\n /**\n * Additional CSS classes\n */\n className?: string;\n} & Omit<\n HTMLAttributes<HTMLAnchorElement>,\n 'href' | 'onClick' | 'color' | 'children' | 'className'\n>;\n\n/**\n * Breadcrumb variant styles using class-variance-authority\n */\nconst breadcrumbVariants = cva('flex flex-row flex-wrap items-center text-sm', {\n variants: {\n size: {\n small: 'gap-1 text-xs',\n medium: 'gap-2 text-sm',\n large: 'gap-3 text-base',\n },\n spacing: {\n compact: 'gap-1',\n normal: 'gap-2',\n loose: 'gap-4',\n },\n },\n defaultVariants: {\n size: 'medium',\n spacing: 'normal',\n },\n});\n\n/**\n * LinkLink sub-component for breadcrumb items that navigate to other pages\n */\nconst LinkLink: FC<LinkLinkProps> = ({\n href,\n lang,\n children,\n onClick,\n color,\n position,\n locale,\n className,\n ...props\n}) => {\n const content = getIntlayer('breadcrumb');\n const linkLabel = content.linkLabel;\n\n return (\n <>\n <Link\n href={href}\n locale={locale}\n color={color}\n onClick={onClick}\n itemProp=\"item\"\n isExternalLink={false}\n itemScope\n itemType=\"https://schema.org/WebPage\"\n {...props}\n label={`${linkLabel} ${children}`}\n itemID={href}\n >\n <span itemProp=\"name\">{children}</span>\n </Link>\n <meta itemProp=\"position\" content={position.toString()} />\n </>\n );\n};\n\n/**\n * Props for ButtonLink sub-component that renders breadcrumb items as interactive buttons\n */\ntype ButtonButtonProps = {\n /**\n * Text content for the breadcrumb button\n */\n children: string;\n /**\n * Position of the breadcrumb item in the list (1-based index)\n */\n position: number;\n} & Omit<ButtonProps, 'children' | 'label'>;\n\n/**\n * ButtonLink sub-component for breadcrumb items with click handlers\n */\nconst ButtonLink: FC<ButtonButtonProps> = ({\n children: text,\n onClick,\n color,\n position,\n className,\n ...props\n}) => {\n const { linkLabel } = useIntlayer('breadcrumb');\n\n return (\n <>\n <Button\n onClick={onClick}\n variant={ButtonVariant.LINK}\n label={`${linkLabel} ${text}`}\n color={color}\n itemProp=\"item\"\n {...props}\n >\n <span itemProp=\"name\">{text}</span>\n </Button>\n <meta itemProp=\"position\" content={position.toString()} />\n </>\n );\n};\n\n/**\n * Props for Span sub-component that renders static breadcrumb text\n */\ntype SpanProps = {\n /**\n * Text content for the static breadcrumb item\n */\n children: string;\n /**\n * Position of the breadcrumb item in the list (1-based index)\n */\n position: number;\n} & HTMLAttributes<HTMLSpanElement>;\n\n/**\n * Span sub-component for static breadcrumb text items\n */\nconst Span: FC<SpanProps> = ({ children, position, className, ...props }) => (\n <span\n itemProp=\"item\"\n className={cn(\n 'inline-flex items-center',\n 'font-medium text-neutral-700',\n 'transition-colors duration-200',\n className\n )}\n >\n <span itemProp=\"name\" {...props}>\n {children}\n </span>\n <meta itemProp=\"position\" content={position.toString()} />\n </span>\n);\n\n/**\n * Detailed breadcrumb link configuration with optional href or onClick\n */\ntype DetailedBreadcrumbLink = {\n /**\n * URL to navigate to when the breadcrumb item is clicked\n */\n href?: string;\n /**\n * Text content to display for this breadcrumb item\n */\n text: string;\n /**\n * Custom click handler function for interactive breadcrumb items\n */\n onClick?: () => void;\n};\n\n/**\n * Union type representing different breadcrumb item configurations:\n * - string: Simple text breadcrumb item\n * - DetailedBreadcrumbLink: Object with href, text, and/or onClick properties\n */\nexport type BreadcrumbLink = string | DetailedBreadcrumbLink;\n\nexport type BreadcrumbProps = {\n /**\n * Array of breadcrumb items\n */\n links: BreadcrumbLink[];\n /**\n * Color scheme for breadcrumb links\n * @default LinkColor.TEXT\n */\n color?: LinkColor | `${LinkColor}`;\n /**\n * Locale for internationalization\n */\n locale?: LocalesValues;\n /**\n * Element type for ARIA current attribute\n * @default 'page'\n */\n elementType?: 'page' | 'location';\n /**\n * Custom separator between breadcrumb items\n * @default ChevronRightIcon\n */\n separator?: ReactNode;\n /**\n * ARIA label for breadcrumb navigation\n * @default 'breadcrumb'\n */\n ariaLabel?: string;\n /**\n * Whether to include structured data markup\n * @default true\n */\n includeStructuredData?: boolean;\n /**\n * Maximum number of breadcrumb items to show before truncation\n */\n maxItems?: number;\n} & VariantProps<typeof breadcrumbVariants> &\n HTMLAttributes<HTMLOListElement>;\n\n/**\n * Breadcrumb component providing navigational context with accessibility features\n *\n * Features:\n * - Supports links, buttons, and static text elements\n * - Full keyboard navigation support\n * - ARIA attributes for screen readers\n * - Schema.org structured data for SEO\n * - Customizable separators and styling\n * - Internationalization support\n * - Responsive design variants\n *\n * @example\n * ```tsx\n * <Breadcrumb\n * links={[\n * 'Home',\n * { href: '/products', text: 'Products' },\n * { onClick: handleCategory, text: 'Electronics' },\n * 'Smartphones'\n * ]}\n * size=\"medium\"\n * ariaLabel=\"Product navigation\"\n * />\n * ```\n */\nexport const Breadcrumb: FC<BreadcrumbProps> = ({\n links,\n className,\n color = LinkColor.TEXT,\n locale,\n elementType = 'page',\n separator = <ChevronRightIcon size={10} />,\n ariaLabel = 'breadcrumb',\n includeStructuredData = true,\n maxItems,\n size,\n spacing,\n ...props\n}) => {\n const displayLinks =\n maxItems && links.length > maxItems\n ? [...links.slice(0, 1), '...', ...links.slice(-(maxItems - 2))]\n : links;\n\n return (\n <nav aria-label={ariaLabel}>\n <ol\n className={cn(breadcrumbVariants({ size, spacing }), className)}\n {...(includeStructuredData && {\n itemScope: true,\n itemType: 'http://schema.org/BreadcrumbList',\n })}\n {...props}\n >\n {displayLinks.map((link, index) => {\n const isLastLink = index === displayLinks.length - 1;\n const isLink =\n typeof link === 'object' && typeof link.href === 'string';\n const isButton =\n typeof link === 'object' && typeof link.onClick === 'function';\n const isActive = index === displayLinks.length - 1;\n const ariaCurrent = isActive ? elementType : undefined;\n const isTruncated = link === '...';\n\n const text = (link as DetailedBreadcrumbLink).text ?? link;\n\n if (isTruncated) {\n return (\n <Fragment key={`truncated-${text}`}>\n <li className=\"flex items-center\" aria-hidden=\"true\">\n <span className=\"text-neutral-500\">…</span>\n </li>\n {!isLastLink && (\n <li aria-hidden=\"true\" className=\"flex items-center\">\n {separator}\n </li>\n )}\n </Fragment>\n );\n }\n\n let section = (\n <Span\n key={text}\n position={index + 1}\n aria-current={ariaCurrent}\n className={cn(\n 'transition-colors duration-200',\n isActive && 'text-neutral-900'\n )}\n >\n {text}\n </Span>\n );\n\n if (isLink) {\n section = (\n <LinkLink\n key={text}\n href={link.href!}\n color={color}\n position={index + 1}\n locale={locale}\n aria-current={ariaCurrent}\n className={cn(isActive && 'cursor-default text-neutral-900')}\n >\n {text}\n </LinkLink>\n );\n } else if (isButton) {\n section = (\n <ButtonLink\n key={text}\n onClick={link.onClick!}\n color={color}\n position={index + 1}\n aria-current={ariaCurrent}\n className={cn(isActive && 'cursor-default text-neutral-900')}\n >\n {text}\n </ButtonLink>\n );\n }\n\n const listElement = (\n <li\n {...(includeStructuredData && {\n itemProp: 'itemListElement',\n itemScope: true,\n itemType: 'https://schema.org/ListItem',\n })}\n key={text}\n className=\"flex items-center\"\n >\n {section}\n </li>\n );\n\n if (isLastLink) {\n return listElement;\n }\n\n return (\n <Fragment key={text}>\n {listElement}\n <li aria-hidden=\"true\" className=\"flex items-center\">\n {separator}\n </li>\n </Fragment>\n );\n })}\n </ol>\n </nav>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["LinkLink: FC<LinkLinkProps>","ButtonLink: FC<ButtonButtonProps>","Span: FC<SpanProps>","Breadcrumb: FC<BreadcrumbProps>"],"sources":["../../../../src/components/Breadcrumb/index.tsx"],"sourcesContent":["'use client';\n\nimport { getIntlayer } from '@intlayer/core';\nimport type { LocalesValues } from '@intlayer/types';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport type { __DictionaryRegistry } from 'intlayer';\nimport { ChevronRightIcon } from 'lucide-react';\nimport { type FC, Fragment, type HTMLAttributes, type ReactNode } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { cn } from '../../utils/cn';\nimport { Button, type ButtonProps, ButtonVariant } from '../Button';\nimport { Link, LinkColor } from '../Link';\n\n/**\n * Props for LinkLink sub-component that renders breadcrumb items as links\n */\ntype LinkLinkProps = {\n /**\n * Position of the breadcrumb item in the list (1-based index)\n */\n position: number;\n /**\n * Locale for internationalization\n */\n locale?: LocalesValues;\n /**\n * URL to navigate to\n */\n href?: string;\n /**\n * Link color\n */\n color?: LinkColor | `${LinkColor}`;\n /**\n * Click handler\n */\n onClick?: () => void;\n /**\n * Children content\n */\n children?: string;\n /**\n * Additional CSS classes\n */\n className?: string;\n} & Omit<\n HTMLAttributes<HTMLAnchorElement>,\n 'href' | 'onClick' | 'color' | 'children' | 'className'\n>;\n\n/**\n * Breadcrumb variant styles using class-variance-authority\n */\nconst breadcrumbVariants = cva('flex flex-row flex-wrap items-center text-sm', {\n variants: {\n size: {\n small: 'gap-1 text-xs',\n medium: 'gap-2 text-sm',\n large: 'gap-3 text-base',\n },\n spacing: {\n compact: 'gap-1',\n normal: 'gap-2',\n loose: 'gap-4',\n },\n },\n defaultVariants: {\n size: 'medium',\n spacing: 'normal',\n },\n});\n\n/**\n * LinkLink sub-component for breadcrumb items that navigate to other pages\n */\nconst LinkLink: FC<LinkLinkProps> = ({\n href,\n lang,\n children,\n onClick,\n color,\n position,\n locale,\n className,\n ...props\n}) => {\n const content = getIntlayer('breadcrumb');\n const linkLabel = content.linkLabel;\n\n return (\n <>\n <Link\n href={href}\n locale={locale}\n color={color}\n onClick={onClick}\n itemProp=\"item\"\n isExternalLink={false}\n itemScope\n itemType=\"https://schema.org/WebPage\"\n {...props}\n label={`${linkLabel} ${children}`}\n itemID={href}\n >\n <span itemProp=\"name\">{children}</span>\n </Link>\n <meta itemProp=\"position\" content={position.toString()} />\n </>\n );\n};\n\n/**\n * Props for ButtonLink sub-component that renders breadcrumb items as interactive buttons\n */\ntype ButtonButtonProps = {\n /**\n * Text content for the breadcrumb button\n */\n children: string;\n /**\n * Position of the breadcrumb item in the list (1-based index)\n */\n position: number;\n} & Omit<ButtonProps, 'children' | 'label'>;\n\n/**\n * ButtonLink sub-component for breadcrumb items with click handlers\n */\nconst ButtonLink: FC<ButtonButtonProps> = ({\n children: text,\n onClick,\n color,\n position,\n className,\n ...props\n}) => {\n const { linkLabel } = useIntlayer('breadcrumb');\n\n return (\n <>\n <Button\n onClick={onClick}\n variant={ButtonVariant.LINK}\n label={`${linkLabel} ${text}`}\n color={color}\n itemProp=\"item\"\n {...props}\n >\n <span itemProp=\"name\">{text}</span>\n </Button>\n <meta itemProp=\"position\" content={position.toString()} />\n </>\n );\n};\n\n/**\n * Props for Span sub-component that renders static breadcrumb text\n */\ntype SpanProps = {\n /**\n * Text content for the static breadcrumb item\n */\n children: string;\n /**\n * Position of the breadcrumb item in the list (1-based index)\n */\n position: number;\n} & HTMLAttributes<HTMLSpanElement>;\n\n/**\n * Span sub-component for static breadcrumb text items\n */\nconst Span: FC<SpanProps> = ({ children, position, className, ...props }) => (\n <span\n itemProp=\"item\"\n className={cn(\n 'inline-flex items-center',\n 'font-medium text-neutral-700',\n 'transition-colors duration-200',\n className\n )}\n >\n <span itemProp=\"name\" {...props}>\n {children}\n </span>\n <meta itemProp=\"position\" content={position.toString()} />\n </span>\n);\n\n/**\n * Detailed breadcrumb link configuration with optional href or onClick\n */\ntype DetailedBreadcrumbLink = {\n /**\n * URL to navigate to when the breadcrumb item is clicked\n */\n href?: string;\n /**\n * Text content to display for this breadcrumb item\n */\n text: string;\n /**\n * Custom click handler function for interactive breadcrumb items\n */\n onClick?: () => void;\n};\n\n/**\n * Union type representing different breadcrumb item configurations:\n * - string: Simple text breadcrumb item\n * - DetailedBreadcrumbLink: Object with href, text, and/or onClick properties\n */\nexport type BreadcrumbLink = string | DetailedBreadcrumbLink;\n\nexport type BreadcrumbProps = {\n /**\n * Array of breadcrumb items\n */\n links: BreadcrumbLink[];\n /**\n * Color scheme for breadcrumb links\n * @default LinkColor.TEXT\n */\n color?: LinkColor | `${LinkColor}`;\n /**\n * Locale for internationalization\n */\n locale?: LocalesValues;\n /**\n * Element type for ARIA current attribute\n * @default 'page'\n */\n elementType?: 'page' | 'location';\n /**\n * Custom separator between breadcrumb items\n * @default ChevronRightIcon\n */\n separator?: ReactNode;\n /**\n * ARIA label for breadcrumb navigation\n * @default 'breadcrumb'\n */\n ariaLabel?: string;\n /**\n * Whether to include structured data markup\n * @default true\n */\n includeStructuredData?: boolean;\n /**\n * Maximum number of breadcrumb items to show before truncation\n */\n maxItems?: number;\n} & VariantProps<typeof breadcrumbVariants> &\n HTMLAttributes<HTMLOListElement>;\n\n/**\n * Breadcrumb component providing navigational context with accessibility features\n *\n * Features:\n * - Supports links, buttons, and static text elements\n * - Full keyboard navigation support\n * - ARIA attributes for screen readers\n * - Schema.org structured data for SEO\n * - Customizable separators and styling\n * - Internationalization support\n * - Responsive design variants\n *\n * @example\n * ```tsx\n * <Breadcrumb\n * links={[\n * 'Home',\n * { href: '/products', text: 'Products' },\n * { onClick: handleCategory, text: 'Electronics' },\n * 'Smartphones'\n * ]}\n * size=\"medium\"\n * ariaLabel=\"Product navigation\"\n * />\n * ```\n */\nexport const Breadcrumb: FC<BreadcrumbProps> = ({\n links,\n className,\n color = LinkColor.TEXT,\n locale,\n elementType = 'page',\n separator = <ChevronRightIcon size={10} />,\n ariaLabel = 'breadcrumb',\n includeStructuredData = true,\n maxItems,\n size,\n spacing,\n ...props\n}) => {\n const displayLinks =\n maxItems && links.length > maxItems\n ? [...links.slice(0, 1), '...', ...links.slice(-(maxItems - 2))]\n : links;\n\n return (\n <nav aria-label={ariaLabel}>\n <ol\n className={cn(breadcrumbVariants({ size, spacing }), className)}\n {...(includeStructuredData && {\n itemScope: true,\n itemType: 'http://schema.org/BreadcrumbList',\n })}\n {...props}\n >\n {displayLinks.map((link, index) => {\n const isLastLink = index === displayLinks.length - 1;\n const isLink =\n typeof link === 'object' && typeof link.href === 'string';\n const isButton =\n typeof link === 'object' && typeof link.onClick === 'function';\n const isActive = index === displayLinks.length - 1;\n const ariaCurrent = isActive ? elementType : undefined;\n const isTruncated = link === '...';\n\n const text = (link as DetailedBreadcrumbLink).text ?? link;\n\n if (isTruncated) {\n return (\n <Fragment key={`truncated-${text}`}>\n <li className=\"flex items-center\" aria-hidden=\"true\">\n <span className=\"text-neutral-500\">…</span>\n </li>\n {!isLastLink && (\n <li aria-hidden=\"true\" className=\"flex items-center\">\n {separator}\n </li>\n )}\n </Fragment>\n );\n }\n\n let section = (\n <Span\n key={text}\n position={index + 1}\n aria-current={ariaCurrent}\n className={cn(\n 'transition-colors duration-200',\n isActive && 'text-neutral-900'\n )}\n >\n {text}\n </Span>\n );\n\n if (isLink) {\n section = (\n <LinkLink\n key={text}\n href={link.href!}\n color={color}\n position={index + 1}\n locale={locale}\n aria-current={ariaCurrent}\n className={cn(isActive && 'cursor-default text-neutral-900')}\n >\n {text}\n </LinkLink>\n );\n } else if (isButton) {\n section = (\n <ButtonLink\n key={text}\n onClick={link.onClick!}\n color={color}\n position={index + 1}\n aria-current={ariaCurrent}\n className={cn(isActive && 'cursor-default text-neutral-900')}\n >\n {text}\n </ButtonLink>\n );\n }\n\n const listElement = (\n <li\n {...(includeStructuredData && {\n itemProp: 'itemListElement',\n itemScope: true,\n itemType: 'https://schema.org/ListItem',\n })}\n key={text}\n className=\"flex items-center\"\n >\n {section}\n </li>\n );\n\n if (isLastLink) {\n return listElement;\n }\n\n return (\n <Fragment key={text}>\n {listElement}\n <li aria-hidden=\"true\" className=\"flex items-center\">\n {separator}\n </li>\n </Fragment>\n );\n })}\n </ol>\n </nav>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import { cn } from "../../utils/cn.mjs";
|
|
5
|
-
import { useEffect, useRef, useState } from "react";
|
|
6
4
|
import { RotateCw } from "lucide-react";
|
|
5
|
+
import { useEffect, useRef, useState } from "react";
|
|
7
6
|
import { cva } from "class-variance-authority";
|
|
8
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
8
|
import { useIntlayer } from "react-intlayer";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Browser.mjs","names":["Browser: FC<BrowserProps>"],"sources":["../../../../src/components/Browser/Browser.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { RotateCw } from 'lucide-react';\nimport {\n type CSSProperties,\n type FC,\n type FormEvent,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { cn } from '../../utils/cn';\n\nconst browserVariants = cva(\n 'flex w-full flex-col overflow-hidden rounded-xl bg-background shadow-[0_4px_12px_rgba(0,0,0,0.4),0_0_1px_rgba(0,0,0,0.2)]',\n {\n variants: {\n size: {\n xs: 'h-[400px]',\n sm: 'h-[500px]',\n md: 'h-[600px]',\n lg: 'h-[800px]',\n xl: 'h-[1000px]',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n }\n);\n\nexport type BrowserProps = {\n /** Initial URL to load in the iframe */\n initialUrl?: string;\n /** Additional CSS classes for the container */\n className?: string;\n /** Inline styles for the container */\n style?: CSSProperties;\n /** Size of the browser window */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** Accessible label for screen readers describing the browser purpose */\n 'aria-label'?: string;\n /** Sandbox attribute for the iframe to control security restrictions */\n sandbox?: string;\n};\n\n/**\n * Browser component that renders an iframe with a visible, editable URL bar.\n * Allows users to view, edit, and navigate to different URLs within an embedded browser interface.\n *\n * Features:\n * - Editable URL bar with strict validation (before navigation)\n * - Automatic protocol addition (adds https:// if missing)\n * - Integrated reload button inside the URL input\n * - Error handling with visual feedback for invalid URLs\n * - Responsive iframe with standardized sizes\n * - Full accessibility support with ARIA attributes\n * - Sandbox security for iframe content\n * - Dark-themed UI matching modern browser aesthetics\n * - Cross-browser compatibility (Chrome, Firefox, Safari)\n *\n * @example\n * // Basic usage\n * <Browser initialUrl=\"https://example.com\" size=\"md\" />\n *\n * @example\n * // With custom size and styling\n * <Browser\n * initialUrl=\"https://example.com\"\n * size=\"lg\"\n * className=\"shadow-2xl\"\n * aria-label=\"Documentation viewer\"\n * />\n *\n * @example\n * // For content preview\n * <Browser\n * initialUrl=\"https://youtube.com/embed/VIDEO_ID\"\n * size=\"xl\"\n * aria-label=\"Video content browser\"\n * />\n *\n * @example\n * // With custom sandbox restrictions\n * <Browser\n * initialUrl=\"https://example.com\"\n * sandbox=\"allow-scripts allow-same-origin\"\n * aria-label=\"Restricted content browser\"\n * />\n *\n * @param initialUrl - The initial URL to load in the iframe (default: 'https://example.com')\n * @param className - Additional CSS classes for the main container element\n * @param style - Inline CSS styles for the main container element\n * @param size - Size of the browser window: 'xs' (400px), 'sm' (500px), 'md' (600px), 'lg' (800px), 'xl' (1000px). Defaults to 'md'\n * @param aria-label - Accessible label for screen readers describing the browser's purpose (default: 'Embedded browser')\n * @param sandbox - Sandbox attribute for the iframe to control security restrictions (default: 'allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads')\n */\nexport const Browser: FC<BrowserProps> = ({\n initialUrl = 'https://example.com',\n className,\n style,\n size = 'md',\n 'aria-label': ariaLabel,\n sandbox = 'allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads',\n}) => {\n const [inputUrl, setInputUrl] = useState(initialUrl);\n const [currentUrl, setCurrentUrl] = useState(initialUrl);\n const [error, setError] = useState<string | null>(null);\n const [submitted, setSubmitted] = useState(false); // show errors only after attempt\n const iframeRef = useRef<HTMLIFrameElement>(null);\n\n // Load internationalized content\n const content = useIntlayer('browser');\n\n useEffect(() => {\n setInputUrl(initialUrl);\n setCurrentUrl(initialUrl);\n setError(null);\n setSubmitted(false);\n }, [initialUrl]);\n\n // --- Validation helpers ----------------------------------------------------\n const isValidHostname = (host: string) => {\n // allowed chars\n if (!/^[a-z0-9.-]+$/i.test(host)) return false;\n // no leading/trailing dot or hyphen\n if (/^[-.]/.test(host) || /[-.]$/.test(host)) return false;\n // no double dots\n if (host.includes('..')) return false;\n // must have at least one dot\n if (!host.includes('.')) return false;\n\n return true;\n };\n\n const normalizeUrl = (raw: string) => {\n const trimmed = raw.trim();\n if (!trimmed || /\\s/.test(trimmed)) throw new Error('Invalid');\n\n // Add https:// if protocol is missing\n const candidate = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)\n ? trimmed\n : `https://${trimmed}`;\n\n const url = new URL(candidate);\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error('Only http(s) is allowed');\n }\n\n if (!isValidHostname(url.hostname)) {\n throw new Error('Invalid host');\n }\n\n return url.toString();\n };\n\n const validateAndNavigate = (url: string) => {\n try {\n const validated = normalizeUrl(url);\n setCurrentUrl(validated);\n setInputUrl(validated);\n setError(null);\n } catch {\n setError(content.errorMessage.value);\n }\n };\n // --------------------------------------------------------------------------\n\n const handleSubmit = (e: FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n setSubmitted(true);\n validateAndNavigate(inputUrl);\n };\n\n const handleReload = () => {\n if (iframeRef.current) {\n const url = iframeRef.current.src;\n iframeRef.current.src = '';\n iframeRef.current.src = url;\n }\n };\n\n const showError = submitted && !!error;\n\n return (\n <section\n className={cn(browserVariants({ size }), className)}\n style={style}\n aria-label={ariaLabel ?? content.ariaLabel.value}\n >\n {/* Top bar */}\n <div className=\"relative z-10 flex shrink-0 flex-col gap-1 rounded-t-xl bg-neutral-900 px-4 py-2.5 shadow-[0_3px_4px_0_rgba(0,0,0,0.25)]\">\n <form onSubmit={handleSubmit} className=\"relative flex-1\" noValidate>\n <label htmlFor=\"browser-url\" className=\"sr-only\">\n {content.urlLabel.value}\n </label>\n <input\n id=\"browser-url\"\n type=\"text\"\n inputMode=\"url\"\n spellCheck={false}\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n value={inputUrl}\n onChange={(e) => {\n setInputUrl(e.target.value);\n if (showError) setError(null);\n }}\n placeholder={content.urlPlaceholder.value}\n className={cn(\n 'w-full rounded-lg px-4 py-2 pr-11 text-sm leading-[1.4]',\n 'bg-neutral-950 text-neutral-300',\n 'placeholder:text-neutral-400',\n 'transition-all focus:outline-none focus:ring-1 focus:ring-neutral-400/30',\n showError ? 'border border-red-500' : 'border border-transparent'\n )}\n aria-label={content.urlLabel.value}\n aria-invalid={showError}\n aria-describedby={showError ? 'browser-url-error' : undefined}\n />\n\n {/* Absolutely positioned button inside the input */}\n <button\n type=\"button\"\n onClick={handleReload}\n className={cn(\n '-translate-y-1/2 absolute top-1/2 right-2',\n 'flex h-8 w-8 items-center justify-center rounded-md',\n 'transition-colors hover:bg-neutral-800',\n 'focus:outline-none focus:ring-1 focus:ring-neutral-400/30'\n )}\n title={content.reloadButtonTitle.value}\n aria-label={content.reloadButtonTitle.value}\n tabIndex={0}\n >\n <RotateCw size={18} className=\"text-neutral-400\" strokeWidth={2} />\n </button>\n\n {/* invisible submit to allow Enter to work semantically */}\n <button type=\"submit\" className=\"sr-only absolute\" tabIndex={-1} />\n </form>\n\n {/* subtle inline error text */}\n {showError && (\n <p\n id=\"browser-url-error\"\n role=\"alert\"\n aria-live=\"assertive\"\n className=\"px-1 text-red-400 text-xs\"\n >\n {error}\n </p>\n )}\n </div>\n\n {/* Iframe */}\n <div className=\"relative z-0 min-h-0 w-full flex-1 overflow-hidden rounded-b-xl bg-background\">\n <iframe\n ref={iframeRef}\n src={currentUrl}\n title={content.iframeTitle.value}\n className=\"h-full w-full rounded-b-xl border-0\"\n sandbox={sandbox}\n loading=\"lazy\"\n aria-live=\"polite\"\n />\n </div>\n </section>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Browser.mjs","names":["Browser: FC<BrowserProps>"],"sources":["../../../../src/components/Browser/Browser.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { RotateCw } from 'lucide-react';\nimport {\n type CSSProperties,\n type FC,\n type FormEvent,\n useEffect,\n useRef,\n useState,\n} from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { cn } from '../../utils/cn';\n\nconst browserVariants = cva(\n 'flex w-full flex-col overflow-hidden rounded-xl bg-background shadow-[0_4px_12px_rgba(0,0,0,0.4),0_0_1px_rgba(0,0,0,0.2)]',\n {\n variants: {\n size: {\n xs: 'h-[400px]',\n sm: 'h-[500px]',\n md: 'h-[600px]',\n lg: 'h-[800px]',\n xl: 'h-[1000px]',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n }\n);\n\nexport type BrowserProps = {\n /** Initial URL to load in the iframe */\n initialUrl?: string;\n /** Additional CSS classes for the container */\n className?: string;\n /** Inline styles for the container */\n style?: CSSProperties;\n /** Size of the browser window */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n /** Accessible label for screen readers describing the browser purpose */\n 'aria-label'?: string;\n /** Sandbox attribute for the iframe to control security restrictions */\n sandbox?: string;\n};\n\n/**\n * Browser component that renders an iframe with a visible, editable URL bar.\n * Allows users to view, edit, and navigate to different URLs within an embedded browser interface.\n *\n * Features:\n * - Editable URL bar with strict validation (before navigation)\n * - Automatic protocol addition (adds https:// if missing)\n * - Integrated reload button inside the URL input\n * - Error handling with visual feedback for invalid URLs\n * - Responsive iframe with standardized sizes\n * - Full accessibility support with ARIA attributes\n * - Sandbox security for iframe content\n * - Dark-themed UI matching modern browser aesthetics\n * - Cross-browser compatibility (Chrome, Firefox, Safari)\n *\n * @example\n * // Basic usage\n * <Browser initialUrl=\"https://example.com\" size=\"md\" />\n *\n * @example\n * // With custom size and styling\n * <Browser\n * initialUrl=\"https://example.com\"\n * size=\"lg\"\n * className=\"shadow-2xl\"\n * aria-label=\"Documentation viewer\"\n * />\n *\n * @example\n * // For content preview\n * <Browser\n * initialUrl=\"https://youtube.com/embed/VIDEO_ID\"\n * size=\"xl\"\n * aria-label=\"Video content browser\"\n * />\n *\n * @example\n * // With custom sandbox restrictions\n * <Browser\n * initialUrl=\"https://example.com\"\n * sandbox=\"allow-scripts allow-same-origin\"\n * aria-label=\"Restricted content browser\"\n * />\n *\n * @param initialUrl - The initial URL to load in the iframe (default: 'https://example.com')\n * @param className - Additional CSS classes for the main container element\n * @param style - Inline CSS styles for the main container element\n * @param size - Size of the browser window: 'xs' (400px), 'sm' (500px), 'md' (600px), 'lg' (800px), 'xl' (1000px). Defaults to 'md'\n * @param aria-label - Accessible label for screen readers describing the browser's purpose (default: 'Embedded browser')\n * @param sandbox - Sandbox attribute for the iframe to control security restrictions (default: 'allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads')\n */\nexport const Browser: FC<BrowserProps> = ({\n initialUrl = 'https://example.com',\n className,\n style,\n size = 'md',\n 'aria-label': ariaLabel,\n sandbox = 'allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads',\n}) => {\n const [inputUrl, setInputUrl] = useState(initialUrl);\n const [currentUrl, setCurrentUrl] = useState(initialUrl);\n const [error, setError] = useState<string | null>(null);\n const [submitted, setSubmitted] = useState(false); // show errors only after attempt\n const iframeRef = useRef<HTMLIFrameElement>(null);\n\n // Load internationalized content\n const content = useIntlayer('browser');\n\n useEffect(() => {\n setInputUrl(initialUrl);\n setCurrentUrl(initialUrl);\n setError(null);\n setSubmitted(false);\n }, [initialUrl]);\n\n // --- Validation helpers ----------------------------------------------------\n const isValidHostname = (host: string) => {\n // allowed chars\n if (!/^[a-z0-9.-]+$/i.test(host)) return false;\n // no leading/trailing dot or hyphen\n if (/^[-.]/.test(host) || /[-.]$/.test(host)) return false;\n // no double dots\n if (host.includes('..')) return false;\n // must have at least one dot\n if (!host.includes('.')) return false;\n\n return true;\n };\n\n const normalizeUrl = (raw: string) => {\n const trimmed = raw.trim();\n if (!trimmed || /\\s/.test(trimmed)) throw new Error('Invalid');\n\n // Add https:// if protocol is missing\n const candidate = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)\n ? trimmed\n : `https://${trimmed}`;\n\n const url = new URL(candidate);\n\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new Error('Only http(s) is allowed');\n }\n\n if (!isValidHostname(url.hostname)) {\n throw new Error('Invalid host');\n }\n\n return url.toString();\n };\n\n const validateAndNavigate = (url: string) => {\n try {\n const validated = normalizeUrl(url);\n setCurrentUrl(validated);\n setInputUrl(validated);\n setError(null);\n } catch {\n setError(content.errorMessage.value);\n }\n };\n // --------------------------------------------------------------------------\n\n const handleSubmit = (e: FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n setSubmitted(true);\n validateAndNavigate(inputUrl);\n };\n\n const handleReload = () => {\n if (iframeRef.current) {\n const url = iframeRef.current.src;\n iframeRef.current.src = '';\n iframeRef.current.src = url;\n }\n };\n\n const showError = submitted && !!error;\n\n return (\n <section\n className={cn(browserVariants({ size }), className)}\n style={style}\n aria-label={ariaLabel ?? content.ariaLabel.value}\n >\n {/* Top bar */}\n <div className=\"relative z-10 flex shrink-0 flex-col gap-1 rounded-t-xl bg-neutral-900 px-4 py-2.5 shadow-[0_3px_4px_0_rgba(0,0,0,0.25)]\">\n <form onSubmit={handleSubmit} className=\"relative flex-1\" noValidate>\n <label htmlFor=\"browser-url\" className=\"sr-only\">\n {content.urlLabel.value}\n </label>\n <input\n id=\"browser-url\"\n type=\"text\"\n inputMode=\"url\"\n spellCheck={false}\n autoCapitalize=\"off\"\n autoCorrect=\"off\"\n value={inputUrl}\n onChange={(e) => {\n setInputUrl(e.target.value);\n if (showError) setError(null);\n }}\n placeholder={content.urlPlaceholder.value}\n className={cn(\n 'w-full rounded-lg px-4 py-2 pr-11 text-sm leading-[1.4]',\n 'bg-neutral-950 text-neutral-300',\n 'placeholder:text-neutral-400',\n 'transition-all focus:outline-none focus:ring-1 focus:ring-neutral-400/30',\n showError ? 'border border-red-500' : 'border border-transparent'\n )}\n aria-label={content.urlLabel.value}\n aria-invalid={showError}\n aria-describedby={showError ? 'browser-url-error' : undefined}\n />\n\n {/* Absolutely positioned button inside the input */}\n <button\n type=\"button\"\n onClick={handleReload}\n className={cn(\n '-translate-y-1/2 absolute top-1/2 right-2',\n 'flex h-8 w-8 items-center justify-center rounded-md',\n 'transition-colors hover:bg-neutral-800',\n 'focus:outline-none focus:ring-1 focus:ring-neutral-400/30'\n )}\n title={content.reloadButtonTitle.value}\n aria-label={content.reloadButtonTitle.value}\n tabIndex={0}\n >\n <RotateCw size={18} className=\"text-neutral-400\" strokeWidth={2} />\n </button>\n\n {/* invisible submit to allow Enter to work semantically */}\n <button type=\"submit\" className=\"sr-only absolute\" tabIndex={-1} />\n </form>\n\n {/* subtle inline error text */}\n {showError && (\n <p\n id=\"browser-url-error\"\n role=\"alert\"\n aria-live=\"assertive\"\n className=\"px-1 text-red-400 text-xs\"\n >\n {error}\n </p>\n )}\n </div>\n\n {/* Iframe */}\n <div className=\"relative z-0 min-h-0 w-full flex-1 overflow-hidden rounded-b-xl bg-background\">\n <iframe\n ref={iframeRef}\n src={currentUrl}\n title={content.iframeTitle.value}\n className=\"h-full w-full rounded-b-xl border-0\"\n sandbox={sandbox}\n loading=\"lazy\"\n aria-live=\"polite\"\n />\n </div>\n </section>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["ClickOutsideDiv: FC<ClickOutsideDivProps>"],"sources":["../../../../src/components/ClickOutsideDiv/index.tsx"],"sourcesContent":["'use client';\n\nimport {\n type FC,\n type HTMLAttributes,\n type PropsWithChildren,\n useCallback,\n useEffect,\n useRef,\n} from 'react';\n\nexport type ClickOutsideDivProps = PropsWithChildren<{\n /**\n * Callback function called when a click occurs outside the component\n */\n onClickOutSide: () => void;\n /**\n * Whether to listen for Escape key presses\n * @default false\n */\n listenForEscape?: boolean;\n /**\n * Whether the component is disabled (won't trigger onClickOutSide)\n * @default false\n */\n disabled?: boolean;\n}> &\n HTMLAttributes<HTMLDivElement>;\n\nexport const ClickOutsideDiv: FC<ClickOutsideDivProps> = ({\n children,\n onClickOutSide,\n listenForEscape = false,\n disabled = false,\n ...props\n}) => {\n const divRef = useRef<HTMLDivElement>(null);\n\n const handleClickOutside = useCallback(\n (event: MouseEvent) => {\n if (disabled) return;\n\n // If clicking outside of the referenced element, call onClickOutSide\n if (divRef.current && !divRef.current.contains(event.target as Node)) {\n onClickOutSide();\n }\n },\n [onClickOutSide, disabled]\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent) => {\n if (disabled || !listenForEscape) return;\n\n if (event.key === 'Escape') {\n onClickOutSide();\n }\n },\n [onClickOutSide, disabled, listenForEscape]\n );\n\n useEffect(() => {\n // Attach the event listeners\n document.addEventListener('mousedown', handleClickOutside, {\n passive: true,\n });\n\n if (listenForEscape) {\n document.addEventListener('keydown', handleKeyDown);\n }\n\n // Clean up on unmount\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n if (listenForEscape) {\n document.removeEventListener('keydown', handleKeyDown);\n }\n };\n }, [handleClickOutside, handleKeyDown, listenForEscape]);\n\n return (\n <div\n ref={divRef}\n {...props}\n // Add role for better accessibility when used as a container\n role={props.role || 'region'}\n >\n {children}\n </div>\n );\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["ClickOutsideDiv: FC<ClickOutsideDivProps>"],"sources":["../../../../src/components/ClickOutsideDiv/index.tsx"],"sourcesContent":["'use client';\n\nimport {\n type FC,\n type HTMLAttributes,\n type PropsWithChildren,\n useCallback,\n useEffect,\n useRef,\n} from 'react';\n\nexport type ClickOutsideDivProps = PropsWithChildren<{\n /**\n * Callback function called when a click occurs outside the component\n */\n onClickOutSide: () => void;\n /**\n * Whether to listen for Escape key presses\n * @default false\n */\n listenForEscape?: boolean;\n /**\n * Whether the component is disabled (won't trigger onClickOutSide)\n * @default false\n */\n disabled?: boolean;\n}> &\n HTMLAttributes<HTMLDivElement>;\n\nexport const ClickOutsideDiv: FC<ClickOutsideDivProps> = ({\n children,\n onClickOutSide,\n listenForEscape = false,\n disabled = false,\n ...props\n}) => {\n const divRef = useRef<HTMLDivElement>(null);\n\n const handleClickOutside = useCallback(\n (event: MouseEvent) => {\n if (disabled) return;\n\n // If clicking outside of the referenced element, call onClickOutSide\n if (divRef.current && !divRef.current.contains(event.target as Node)) {\n onClickOutSide();\n }\n },\n [onClickOutSide, disabled]\n );\n\n const handleKeyDown = useCallback(\n (event: KeyboardEvent) => {\n if (disabled || !listenForEscape) return;\n\n if (event.key === 'Escape') {\n onClickOutSide();\n }\n },\n [onClickOutSide, disabled, listenForEscape]\n );\n\n useEffect(() => {\n // Attach the event listeners\n document.addEventListener('mousedown', handleClickOutside, {\n passive: true,\n });\n\n if (listenForEscape) {\n document.addEventListener('keydown', handleKeyDown);\n }\n\n // Clean up on unmount\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n if (listenForEscape) {\n document.removeEventListener('keydown', handleKeyDown);\n }\n };\n }, [handleClickOutside, handleKeyDown, listenForEscape]);\n\n return (\n <div\n ref={divRef}\n {...props}\n // Add role for better accessibility when used as a container\n role={props.role || 'region'}\n >\n {children}\n </div>\n );\n};\n"],"mappings":";;;;;;AA6BA,MAAaA,mBAA6C,EACxD,UACA,gBACA,kBAAkB,OAClB,WAAW,OACX,GAAG,YACC;CACJ,MAAM,SAAS,OAAuB,KAAK;CAE3C,MAAM,qBAAqB,aACxB,UAAsB;AACrB,MAAI,SAAU;AAGd,MAAI,OAAO,WAAW,CAAC,OAAO,QAAQ,SAAS,MAAM,OAAe,CAClE,iBAAgB;IAGpB,CAAC,gBAAgB,SAAS,CAC3B;CAED,MAAM,gBAAgB,aACnB,UAAyB;AACxB,MAAI,YAAY,CAAC,gBAAiB;AAElC,MAAI,MAAM,QAAQ,SAChB,iBAAgB;IAGpB;EAAC;EAAgB;EAAU;EAAgB,CAC5C;AAED,iBAAgB;AAEd,WAAS,iBAAiB,aAAa,oBAAoB,EACzD,SAAS,MACV,CAAC;AAEF,MAAI,gBACF,UAAS,iBAAiB,WAAW,cAAc;AAIrD,eAAa;AACX,YAAS,oBAAoB,aAAa,mBAAmB;AAC7D,OAAI,gBACF,UAAS,oBAAoB,WAAW,cAAc;;IAGzD;EAAC;EAAoB;EAAe;EAAgB,CAAC;AAExD,QACE,oBAAC;EACC,KAAK;EACL,GAAI;EAEJ,MAAM,MAAM,QAAQ;EAEnB;GACG"}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import { cn } from "../../utils/cn.mjs";
|
|
5
4
|
import { MaxHeightSmoother } from "../MaxHeightSmoother/index.mjs";
|
|
6
|
-
import { useState } from "react";
|
|
7
5
|
import { ChevronRight } from "lucide-react";
|
|
6
|
+
import { useState } from "react";
|
|
8
7
|
import { cva } from "class-variance-authority";
|
|
9
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
9
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollapsibleTable.mjs","names":["CollapsibleTable: FC<CollapsibleTableProps>","data"],"sources":["../../../../src/components/CollapsibleTable/CollapsibleTable.tsx"],"sourcesContent":["'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ChevronRight } from 'lucide-react';\nimport { type FC, type HTMLAttributes, type ReactNode, useState } from 'react';\nimport { cn } from '../../utils/cn';\nimport { MaxHeightSmoother } from '../MaxHeightSmoother';\n\n// Container variants using CVA\nconst collapsibleTableVariants = cva(\n 'w-full max-w-full overflow-hidden rounded-lg border bg-card',\n {\n variants: {\n size: {\n sm: 'max-w-lg',\n md: 'max-w-2xl',\n lg: 'max-w-4xl',\n xl: 'max-w-6xl',\n full: 'w-full max-w-none',\n },\n variant: {\n default: 'border-neutral/20 bg-card',\n dark: 'border-[#B5B5B5] bg-[#242424]',\n ghost: 'border-transparent bg-transparent',\n outlined: 'border-2 border-primary/20 bg-background',\n },\n spacing: {\n none: '',\n sm: 'm-2',\n md: 'm-4',\n lg: 'm-6',\n auto: 'm-auto',\n },\n },\n defaultVariants: {\n size: 'md',\n variant: 'default',\n spacing: 'auto',\n },\n }\n);\n\n// Header variants\nconst headerVariants = cva(\n 'flex cursor-pointer items-center justify-between p-3 transition-colors duration-200',\n {\n variants: {\n variant: {\n default: 'hover:bg-neutral/5',\n dark: 'hover:bg-neutral/10',\n ghost: 'hover:bg-primary/5',\n outlined: 'hover:bg-primary/5',\n },\n borderStyle: {\n none: '',\n dashed: 'border-neutral/20 border-b border-dashed',\n solid: 'border-neutral/20 border-b border-solid',\n },\n },\n defaultVariants: {\n variant: 'default',\n borderStyle: 'dashed',\n },\n }\n);\n\n// Table variants\nconst tableVariants = cva('w-full border-collapse', {\n variants: {\n spacing: {\n none: 'border-spacing-0',\n sm: 'border-spacing-1',\n md: 'border-spacing-2',\n lg: 'border-spacing-4',\n },\n layout: {\n auto: 'table-auto',\n fixed: 'table-fixed',\n },\n },\n defaultVariants: {\n spacing: 'md',\n layout: 'auto',\n },\n});\n\nexport interface CollapsibleTableProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'title'>,\n VariantProps<typeof collapsibleTableVariants> {\n /** Table title displayed in the header */\n title: string;\n /** Array of data objects to display in the table */\n data: Record<string, unknown>[];\n /** Custom class for the main container */\n className?: string;\n /** Custom class for the header section */\n headerClassName?: string;\n /** Custom class for the content wrapper */\n contentClassName?: string;\n /** Custom class for the table element */\n tableClassName?: string;\n /** Custom class for table header cells */\n thClassName?: string;\n /** Custom class for table body cells */\n tdClassName?: string;\n /** Custom class for table rows */\n trClassName?: string;\n /** Controls if the table is expanded by default */\n defaultExpanded?: boolean;\n /** Controlled expansion state */\n isExpanded?: boolean;\n /** Callback when expansion state changes */\n onExpandToggle?: (expanded: boolean) => void;\n /** Custom icon for the toggle (defaults to ChevronRight) */\n toggleIcon?: ReactNode;\n /** Header border style variant */\n borderStyle?: 'none' | 'dashed' | 'solid';\n /** Table spacing variant */\n tableSpacing?: 'none' | 'sm' | 'md' | 'lg';\n /** Table layout variant */\n tableLayout?: 'auto' | 'fixed';\n /** Custom column renderers */\n columnRenderers?: Record<\n string,\n (value: unknown, row: Record<string, unknown>) => ReactNode\n >;\n /** Disable the collapse functionality */\n disabled?: boolean;\n /** Accessible label for screen readers */\n 'aria-label'?: string;\n /** ID for the table content (for aria-controls) */\n contentId?: string;\n}\n\n/**\n * CollapsibleTable component that displays tabular data in an expandable/collapsible format.\n * It provides a clickable header that controls the visibility of the table content with smooth animations.\n *\n * Features:\n * - Supports both controlled and uncontrolled modes\n * - Customizable styling with CVA variants (size, variant, spacing)\n * - Multiple className props for granular styling control\n * - Custom column rendering and ordering\n * - Accessible with proper ARIA attributes and keyboard navigation\n * - Responsive design with overflow handling\n * - Empty state customization\n * - Flexible data structure support\n *\n * @example\n * // Basic usage\n * const userData = [\n * { name: 'John Doe', role: 'Developer', experience: '5 years' },\n * { name: 'Jane Smith', role: 'Designer', experience: '3 years' },\n * ];\n *\n * <CollapsibleTable\n * title=\"Team Members\"\n * data={userData}\n * defaultExpanded={true}\n * />\n *\n * @example\n * // Advanced usage with custom styling and renderers\n * const projectData = [\n * { name: 'Project A', status: 'active', priority: 'high' },\n * { name: 'Project B', status: 'completed', priority: 'medium' },\n * ];\n *\n * const columnRenderers = {\n * status: (value) => (\n * <Badge variant={value === 'active' ? 'success' : 'default'}>\n * {value}\n * </Badge>\n * ),\n * priority: (value) => (\n * <span className={`font-semibold ${\n * value === 'high' ? 'text-red-600' :\n * value === 'medium' ? 'text-yellow-600' : 'text-green-600'\n * }`}>\n * {value}\n * </span>\n * ),\n * };\n *\n * <CollapsibleTable\n * title=\"Project Dashboard\"\n * data={projectData}\n * variant=\"dark\"\n * size=\"lg\"\n * borderStyle=\"solid\"\n * columnRenderers={columnRenderers}\n * headerClassName=\"bg-slate-800 text-white\"\n * tableClassName=\"bg-slate-900\"\n * onExpandToggle={(expanded) => console.log('Table expanded:', expanded)}\n * />\n *\n * @param title - The text or React node displayed in the table header\n * @param data - Array of objects representing table rows. Keys become column headers, values become cell content\n * @param className - Additional CSS classes for the main container element\n * @param headerClassName - Additional CSS classes for the clickable header section\n * @param contentClassName - Additional CSS classes for the table content wrapper\n * @param tableClassName - Additional CSS classes for the HTML table element\n * @param thClassName - Additional CSS classes for table header cells (th elements)\n * @param tdClassName - Additional CSS classes for table body cells (td elements)\n * @param trClassName - Additional CSS classes for table rows (tr elements)\n * @param defaultExpanded - Initial expansion state when component is uncontrolled (default: false)\n * @param isExpanded - Controls expansion state when component is controlled. When provided, component becomes controlled\n * @param onExpandToggle - Callback function called when expansion state changes. Receives new expanded state as parameter\n * @param toggleIcon - Custom React node to display as toggle icon. Defaults to ChevronRight from lucide-react\n * @param size - Size variant affecting container max-width: 'sm' | 'md' | 'lg' | 'xl' | 'full'\n * @param variant - Visual style variant: 'default' | 'dark' | 'ghost' | 'outlined'\n * @param spacing - Container margin spacing: 'none' | 'sm' | 'md' | 'lg' | 'auto'\n * @param borderStyle - Header border style when expanded: 'none' | 'dashed' | 'solid'\n * @param tableSpacing - Table cell spacing: 'none' | 'sm' | 'md' | 'lg'\n * @param tableLayout - CSS table-layout property: 'auto' | 'fixed'\n * @param columnRenderers - Object mapping column names to custom render functions. Function receives (value, rowData) and returns ReactNode\n * @param disabled - When true, disables click interaction and shows disabled visual state\n * @param aria-label - Accessible label for screen readers describing the table purpose\n * @param contentId - Custom ID for the table content area. Used for aria-controls. Auto-generated if not provided\n */\nexport const CollapsibleTable: FC<CollapsibleTableProps> = ({\n title,\n data,\n className,\n headerClassName,\n contentClassName,\n tableClassName,\n thClassName,\n tdClassName,\n trClassName,\n defaultExpanded = false,\n isExpanded: controlledExpanded,\n onExpandToggle,\n toggleIcon,\n size,\n variant,\n spacing,\n borderStyle,\n tableSpacing,\n tableLayout,\n columnRenderers,\n disabled = false,\n 'aria-label': ariaLabel,\n contentId,\n ...props\n}) => {\n const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);\n\n const isExpanded = controlledExpanded ?? internalExpanded;\n\n const toggleExpanded = () => {\n if (disabled) return;\n const newState = !isExpanded;\n if (onExpandToggle) onExpandToggle(newState);\n else setInternalExpanded(newState);\n };\n\n const getColumns = (data: Record<string, unknown>[]) => {\n if (Array.isArray(data) && data.length > 0) {\n const allKeys = new Set<string>();\n data.forEach((item) => {\n if (item && typeof item === 'object') {\n Object.keys(item).forEach((key) => allKeys.add(key));\n }\n });\n return Array.from(allKeys);\n }\n return [];\n };\n\n const tableColumns = getColumns(data);\n const generatedContentId =\n contentId || `collapsible-table-${Math.random().toString(36).substr(2, 9)}`;\n\n const renderCellContent = (\n column: string,\n value: unknown,\n row: Record<string, unknown>\n ) => {\n if (columnRenderers?.[column]) {\n return columnRenderers[column](value, row);\n }\n return String(value ?? '—');\n };\n\n return (\n <div\n className={cn(\n collapsibleTableVariants({ size, variant, spacing }),\n className\n )}\n aria-label={ariaLabel}\n {...props}\n >\n <div\n onClick={toggleExpanded}\n className={cn(\n headerVariants({\n variant,\n borderStyle: isExpanded ? borderStyle : 'none',\n }),\n headerClassName,\n disabled && 'cursor-not-allowed opacity-50'\n )}\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-expanded={isExpanded}\n aria-controls={generatedContentId}\n aria-disabled={disabled}\n >\n <p className=\"font-semibold\">{title}</p>\n <div\n className={cn(\n 'transition-transform duration-200',\n isExpanded && 'rotate-90',\n disabled && 'opacity-50'\n )}\n >\n {toggleIcon ?? <ChevronRight size={16} />}\n </div>\n </div>\n\n <MaxHeightSmoother isHidden={!isExpanded}>\n <div\n id={generatedContentId}\n className={cn('overflow-x-auto p-3', contentClassName)}\n role=\"region\"\n aria-labelledby={`${generatedContentId}-header`}\n >\n <table\n className={cn(\n tableVariants({ spacing: tableSpacing, layout: tableLayout }),\n 'border-separate',\n tableClassName\n )}\n >\n <thead>\n <tr className={trClassName}>\n {tableColumns.map((column) => (\n <th\n key={column}\n className={cn(\n 'pb-2 text-left font-medium text-sm text-text/70',\n thClassName\n )}\n >\n {column}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.map((row, index) => (\n <tr\n key={index}\n className={cn(\n 'bg-neutral/5 transition-colors hover:bg-neutral/10',\n trClassName\n )}\n >\n {tableColumns.map((column) => (\n <td\n key={column}\n className={cn(\n 'rounded px-3 py-2 text-sm text-text',\n tdClassName\n )}\n >\n {renderCellContent(column, row[column], row)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </MaxHeightSmoother>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CollapsibleTable.mjs","names":["CollapsibleTable: FC<CollapsibleTableProps>","data"],"sources":["../../../../src/components/CollapsibleTable/CollapsibleTable.tsx"],"sourcesContent":["'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { ChevronRight } from 'lucide-react';\nimport { type FC, type HTMLAttributes, type ReactNode, useState } from 'react';\nimport { cn } from '../../utils/cn';\nimport { MaxHeightSmoother } from '../MaxHeightSmoother';\n\n// Container variants using CVA\nconst collapsibleTableVariants = cva(\n 'w-full max-w-full overflow-hidden rounded-lg border bg-card',\n {\n variants: {\n size: {\n sm: 'max-w-lg',\n md: 'max-w-2xl',\n lg: 'max-w-4xl',\n xl: 'max-w-6xl',\n full: 'w-full max-w-none',\n },\n variant: {\n default: 'border-neutral/20 bg-card',\n dark: 'border-[#B5B5B5] bg-[#242424]',\n ghost: 'border-transparent bg-transparent',\n outlined: 'border-2 border-primary/20 bg-background',\n },\n spacing: {\n none: '',\n sm: 'm-2',\n md: 'm-4',\n lg: 'm-6',\n auto: 'm-auto',\n },\n },\n defaultVariants: {\n size: 'md',\n variant: 'default',\n spacing: 'auto',\n },\n }\n);\n\n// Header variants\nconst headerVariants = cva(\n 'flex cursor-pointer items-center justify-between p-3 transition-colors duration-200',\n {\n variants: {\n variant: {\n default: 'hover:bg-neutral/5',\n dark: 'hover:bg-neutral/10',\n ghost: 'hover:bg-primary/5',\n outlined: 'hover:bg-primary/5',\n },\n borderStyle: {\n none: '',\n dashed: 'border-neutral/20 border-b border-dashed',\n solid: 'border-neutral/20 border-b border-solid',\n },\n },\n defaultVariants: {\n variant: 'default',\n borderStyle: 'dashed',\n },\n }\n);\n\n// Table variants\nconst tableVariants = cva('w-full border-collapse', {\n variants: {\n spacing: {\n none: 'border-spacing-0',\n sm: 'border-spacing-1',\n md: 'border-spacing-2',\n lg: 'border-spacing-4',\n },\n layout: {\n auto: 'table-auto',\n fixed: 'table-fixed',\n },\n },\n defaultVariants: {\n spacing: 'md',\n layout: 'auto',\n },\n});\n\nexport interface CollapsibleTableProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'title'>,\n VariantProps<typeof collapsibleTableVariants> {\n /** Table title displayed in the header */\n title: string;\n /** Array of data objects to display in the table */\n data: Record<string, unknown>[];\n /** Custom class for the main container */\n className?: string;\n /** Custom class for the header section */\n headerClassName?: string;\n /** Custom class for the content wrapper */\n contentClassName?: string;\n /** Custom class for the table element */\n tableClassName?: string;\n /** Custom class for table header cells */\n thClassName?: string;\n /** Custom class for table body cells */\n tdClassName?: string;\n /** Custom class for table rows */\n trClassName?: string;\n /** Controls if the table is expanded by default */\n defaultExpanded?: boolean;\n /** Controlled expansion state */\n isExpanded?: boolean;\n /** Callback when expansion state changes */\n onExpandToggle?: (expanded: boolean) => void;\n /** Custom icon for the toggle (defaults to ChevronRight) */\n toggleIcon?: ReactNode;\n /** Header border style variant */\n borderStyle?: 'none' | 'dashed' | 'solid';\n /** Table spacing variant */\n tableSpacing?: 'none' | 'sm' | 'md' | 'lg';\n /** Table layout variant */\n tableLayout?: 'auto' | 'fixed';\n /** Custom column renderers */\n columnRenderers?: Record<\n string,\n (value: unknown, row: Record<string, unknown>) => ReactNode\n >;\n /** Disable the collapse functionality */\n disabled?: boolean;\n /** Accessible label for screen readers */\n 'aria-label'?: string;\n /** ID for the table content (for aria-controls) */\n contentId?: string;\n}\n\n/**\n * CollapsibleTable component that displays tabular data in an expandable/collapsible format.\n * It provides a clickable header that controls the visibility of the table content with smooth animations.\n *\n * Features:\n * - Supports both controlled and uncontrolled modes\n * - Customizable styling with CVA variants (size, variant, spacing)\n * - Multiple className props for granular styling control\n * - Custom column rendering and ordering\n * - Accessible with proper ARIA attributes and keyboard navigation\n * - Responsive design with overflow handling\n * - Empty state customization\n * - Flexible data structure support\n *\n * @example\n * // Basic usage\n * const userData = [\n * { name: 'John Doe', role: 'Developer', experience: '5 years' },\n * { name: 'Jane Smith', role: 'Designer', experience: '3 years' },\n * ];\n *\n * <CollapsibleTable\n * title=\"Team Members\"\n * data={userData}\n * defaultExpanded={true}\n * />\n *\n * @example\n * // Advanced usage with custom styling and renderers\n * const projectData = [\n * { name: 'Project A', status: 'active', priority: 'high' },\n * { name: 'Project B', status: 'completed', priority: 'medium' },\n * ];\n *\n * const columnRenderers = {\n * status: (value) => (\n * <Badge variant={value === 'active' ? 'success' : 'default'}>\n * {value}\n * </Badge>\n * ),\n * priority: (value) => (\n * <span className={`font-semibold ${\n * value === 'high' ? 'text-red-600' :\n * value === 'medium' ? 'text-yellow-600' : 'text-green-600'\n * }`}>\n * {value}\n * </span>\n * ),\n * };\n *\n * <CollapsibleTable\n * title=\"Project Dashboard\"\n * data={projectData}\n * variant=\"dark\"\n * size=\"lg\"\n * borderStyle=\"solid\"\n * columnRenderers={columnRenderers}\n * headerClassName=\"bg-slate-800 text-white\"\n * tableClassName=\"bg-slate-900\"\n * onExpandToggle={(expanded) => console.log('Table expanded:', expanded)}\n * />\n *\n * @param title - The text or React node displayed in the table header\n * @param data - Array of objects representing table rows. Keys become column headers, values become cell content\n * @param className - Additional CSS classes for the main container element\n * @param headerClassName - Additional CSS classes for the clickable header section\n * @param contentClassName - Additional CSS classes for the table content wrapper\n * @param tableClassName - Additional CSS classes for the HTML table element\n * @param thClassName - Additional CSS classes for table header cells (th elements)\n * @param tdClassName - Additional CSS classes for table body cells (td elements)\n * @param trClassName - Additional CSS classes for table rows (tr elements)\n * @param defaultExpanded - Initial expansion state when component is uncontrolled (default: false)\n * @param isExpanded - Controls expansion state when component is controlled. When provided, component becomes controlled\n * @param onExpandToggle - Callback function called when expansion state changes. Receives new expanded state as parameter\n * @param toggleIcon - Custom React node to display as toggle icon. Defaults to ChevronRight from lucide-react\n * @param size - Size variant affecting container max-width: 'sm' | 'md' | 'lg' | 'xl' | 'full'\n * @param variant - Visual style variant: 'default' | 'dark' | 'ghost' | 'outlined'\n * @param spacing - Container margin spacing: 'none' | 'sm' | 'md' | 'lg' | 'auto'\n * @param borderStyle - Header border style when expanded: 'none' | 'dashed' | 'solid'\n * @param tableSpacing - Table cell spacing: 'none' | 'sm' | 'md' | 'lg'\n * @param tableLayout - CSS table-layout property: 'auto' | 'fixed'\n * @param columnRenderers - Object mapping column names to custom render functions. Function receives (value, rowData) and returns ReactNode\n * @param disabled - When true, disables click interaction and shows disabled visual state\n * @param aria-label - Accessible label for screen readers describing the table purpose\n * @param contentId - Custom ID for the table content area. Used for aria-controls. Auto-generated if not provided\n */\nexport const CollapsibleTable: FC<CollapsibleTableProps> = ({\n title,\n data,\n className,\n headerClassName,\n contentClassName,\n tableClassName,\n thClassName,\n tdClassName,\n trClassName,\n defaultExpanded = false,\n isExpanded: controlledExpanded,\n onExpandToggle,\n toggleIcon,\n size,\n variant,\n spacing,\n borderStyle,\n tableSpacing,\n tableLayout,\n columnRenderers,\n disabled = false,\n 'aria-label': ariaLabel,\n contentId,\n ...props\n}) => {\n const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);\n\n const isExpanded = controlledExpanded ?? internalExpanded;\n\n const toggleExpanded = () => {\n if (disabled) return;\n const newState = !isExpanded;\n if (onExpandToggle) onExpandToggle(newState);\n else setInternalExpanded(newState);\n };\n\n const getColumns = (data: Record<string, unknown>[]) => {\n if (Array.isArray(data) && data.length > 0) {\n const allKeys = new Set<string>();\n data.forEach((item) => {\n if (item && typeof item === 'object') {\n Object.keys(item).forEach((key) => allKeys.add(key));\n }\n });\n return Array.from(allKeys);\n }\n return [];\n };\n\n const tableColumns = getColumns(data);\n const generatedContentId =\n contentId || `collapsible-table-${Math.random().toString(36).substr(2, 9)}`;\n\n const renderCellContent = (\n column: string,\n value: unknown,\n row: Record<string, unknown>\n ) => {\n if (columnRenderers?.[column]) {\n return columnRenderers[column](value, row);\n }\n return String(value ?? '—');\n };\n\n return (\n <div\n className={cn(\n collapsibleTableVariants({ size, variant, spacing }),\n className\n )}\n aria-label={ariaLabel}\n {...props}\n >\n <div\n onClick={toggleExpanded}\n className={cn(\n headerVariants({\n variant,\n borderStyle: isExpanded ? borderStyle : 'none',\n }),\n headerClassName,\n disabled && 'cursor-not-allowed opacity-50'\n )}\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-expanded={isExpanded}\n aria-controls={generatedContentId}\n aria-disabled={disabled}\n >\n <p className=\"font-semibold\">{title}</p>\n <div\n className={cn(\n 'transition-transform duration-200',\n isExpanded && 'rotate-90',\n disabled && 'opacity-50'\n )}\n >\n {toggleIcon ?? <ChevronRight size={16} />}\n </div>\n </div>\n\n <MaxHeightSmoother isHidden={!isExpanded}>\n <div\n id={generatedContentId}\n className={cn('overflow-x-auto p-3', contentClassName)}\n role=\"region\"\n aria-labelledby={`${generatedContentId}-header`}\n >\n <table\n className={cn(\n tableVariants({ spacing: tableSpacing, layout: tableLayout }),\n 'border-separate',\n tableClassName\n )}\n >\n <thead>\n <tr className={trClassName}>\n {tableColumns.map((column) => (\n <th\n key={column}\n className={cn(\n 'pb-2 text-left font-medium text-sm text-text/70',\n thClassName\n )}\n >\n {column}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {data.map((row, index) => (\n <tr\n key={index}\n className={cn(\n 'bg-neutral/5 transition-colors hover:bg-neutral/10',\n trClassName\n )}\n >\n {tableColumns.map((column) => (\n <td\n key={column}\n className={cn(\n 'rounded px-3 py-2 text-sm text-text',\n tdClassName\n )}\n >\n {renderCellContent(column, row[column], row)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </MaxHeightSmoother>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["CommandRoot: FC<ComponentProps<typeof CommandPrimitive>>","CommandPrimitive","CommandDialog: FC<CommandDialogProps>","CommandInput: FC<ComponentProps<typeof CommandPrimitive.Input>>","CommandList: FC<ComponentProps<typeof CommandPrimitive.List>>","CommandEmpty: FC<ComponentProps<typeof CommandPrimitive.Empty>>","CommandGroup: FC<ComponentProps<typeof CommandPrimitive.Group>>","CommandSeparator: FC<\n ComponentProps<typeof CommandPrimitive.Separator>\n>","CommandItem: FC<ComponentProps<typeof CommandPrimitive.Item>>"],"sources":["../../../../src/components/Command/index.tsx"],"sourcesContent":["/* eslint-disable react/no-unknown-property */\n'use client';\n\nimport {\n Dialog,\n DialogContent,\n type DialogProps,\n} from '@radix-ui/react-dialog';\nimport { Command as CommandPrimitive } from 'cmdk';\nimport { Search } from 'lucide-react';\nimport type { ComponentProps, FC, HTMLAttributes } from 'react';\nimport { cn } from '../../utils/cn';\n\nexport const CommandRoot: FC<ComponentProps<typeof CommandPrimitive>> = ({\n className,\n ...props\n}) => (\n <CommandPrimitive\n className={cn(\n 'flex size-full flex-col overflow-hidden rounded-md',\n className\n )}\n {...props}\n />\n);\n\ntype CommandDialogProps = DialogProps;\n\nconst CommandDialog: FC<CommandDialogProps> = ({ children, ...props }) => (\n <Dialog {...props}>\n <DialogContent className=\"overflow-hidden p-0\">\n <CommandRoot className=\"[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:size-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]_svg]:size-5\">\n {children}\n </CommandRoot>\n </DialogContent>\n </Dialog>\n);\n\nconst CommandInput: FC<ComponentProps<typeof CommandPrimitive.Input>> = ({\n className,\n ...props\n}) => (\n <div className=\"flex w-full items-center\" cmdk-input-wrapper=\"\">\n <Search className=\"mr-2 size-4 shrink-0 opacity-50\" />\n <CommandPrimitive.Input\n className={cn(\n 'flex w-full rounded-md bg-transparent text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',\n className\n )}\n {...props}\n />\n </div>\n);\n\nconst CommandList: FC<ComponentProps<typeof CommandPrimitive.List>> = ({\n className,\n ...props\n}) => (\n <CommandPrimitive.List\n className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}\n {...props}\n />\n);\n\nconst CommandEmpty: FC<ComponentProps<typeof CommandPrimitive.Empty>> = (\n props\n) => <CommandPrimitive.Empty className=\"py-6 text-center text-sm\" {...props} />;\n\nconst CommandGroup: FC<ComponentProps<typeof CommandPrimitive.Group>> = ({\n className,\n ...props\n}) => (\n <CommandPrimitive.Group\n className={cn(\n 'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:text-xs',\n className\n )}\n {...props}\n />\n);\n\nconst CommandSeparator: FC<\n ComponentProps<typeof CommandPrimitive.Separator>\n> = ({ className, ...props }) => (\n <CommandPrimitive.Separator\n className={cn('-mx-1 h-px bg-border', className)}\n {...props}\n />\n);\n\nconst CommandItem: FC<ComponentProps<typeof CommandPrimitive.Item>> = ({\n className,\n ...props\n}) => (\n <CommandPrimitive.Item\n className={cn(\n 'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50',\n className\n )}\n {...props}\n />\n);\n\nconst CommandShortcut = ({\n className,\n ...props\n}: HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span\n className={cn(\n 'ml-auto text-muted-foreground text-xs tracking-widest',\n className\n )}\n {...props}\n />\n );\n};\n\n/**\n * Usage example:\n * ```jsx\n * <Command>\n * <Command.Trigger>\n * <Command.Input placeholder=\"Search...\" />\n * </Command.Trigger>\n * <Command.Dialog>\n * <Command.List>\n * <Command.Item>Item 1</Command.Item>\n * <Command.Item>Item 2</Command.Item>\n * <Command.Item>Item 3</Command.Item>\n * </Command.List>\n * </Command.Dialog>\n * </Command>\n * ```\n */\nexport const Command = {\n ...CommandRoot,\n Dialog: CommandDialog,\n Input: CommandInput,\n List: CommandList,\n Empty: CommandEmpty,\n Group: CommandGroup,\n Separator: CommandSeparator,\n Item: CommandItem,\n Shortcut: CommandShortcut,\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["CommandRoot: FC<ComponentProps<typeof CommandPrimitive>>","CommandPrimitive","CommandDialog: FC<CommandDialogProps>","CommandInput: FC<ComponentProps<typeof CommandPrimitive.Input>>","CommandList: FC<ComponentProps<typeof CommandPrimitive.List>>","CommandEmpty: FC<ComponentProps<typeof CommandPrimitive.Empty>>","CommandGroup: FC<ComponentProps<typeof CommandPrimitive.Group>>","CommandSeparator: FC<\n ComponentProps<typeof CommandPrimitive.Separator>\n>","CommandItem: FC<ComponentProps<typeof CommandPrimitive.Item>>"],"sources":["../../../../src/components/Command/index.tsx"],"sourcesContent":["/* eslint-disable react/no-unknown-property */\n'use client';\n\nimport {\n Dialog,\n DialogContent,\n type DialogProps,\n} from '@radix-ui/react-dialog';\nimport { Command as CommandPrimitive } from 'cmdk';\nimport { Search } from 'lucide-react';\nimport type { ComponentProps, FC, HTMLAttributes } from 'react';\nimport { cn } from '../../utils/cn';\n\nexport const CommandRoot: FC<ComponentProps<typeof CommandPrimitive>> = ({\n className,\n ...props\n}) => (\n <CommandPrimitive\n className={cn(\n 'flex size-full flex-col overflow-hidden rounded-md',\n className\n )}\n {...props}\n />\n);\n\ntype CommandDialogProps = DialogProps;\n\nconst CommandDialog: FC<CommandDialogProps> = ({ children, ...props }) => (\n <Dialog {...props}>\n <DialogContent className=\"overflow-hidden p-0\">\n <CommandRoot className=\"[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:size-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]_svg]:size-5\">\n {children}\n </CommandRoot>\n </DialogContent>\n </Dialog>\n);\n\nconst CommandInput: FC<ComponentProps<typeof CommandPrimitive.Input>> = ({\n className,\n ...props\n}) => (\n <div className=\"flex w-full items-center\" cmdk-input-wrapper=\"\">\n <Search className=\"mr-2 size-4 shrink-0 opacity-50\" />\n <CommandPrimitive.Input\n className={cn(\n 'flex w-full rounded-md bg-transparent text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',\n className\n )}\n {...props}\n />\n </div>\n);\n\nconst CommandList: FC<ComponentProps<typeof CommandPrimitive.List>> = ({\n className,\n ...props\n}) => (\n <CommandPrimitive.List\n className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}\n {...props}\n />\n);\n\nconst CommandEmpty: FC<ComponentProps<typeof CommandPrimitive.Empty>> = (\n props\n) => <CommandPrimitive.Empty className=\"py-6 text-center text-sm\" {...props} />;\n\nconst CommandGroup: FC<ComponentProps<typeof CommandPrimitive.Group>> = ({\n className,\n ...props\n}) => (\n <CommandPrimitive.Group\n className={cn(\n 'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:text-xs',\n className\n )}\n {...props}\n />\n);\n\nconst CommandSeparator: FC<\n ComponentProps<typeof CommandPrimitive.Separator>\n> = ({ className, ...props }) => (\n <CommandPrimitive.Separator\n className={cn('-mx-1 h-px bg-border', className)}\n {...props}\n />\n);\n\nconst CommandItem: FC<ComponentProps<typeof CommandPrimitive.Item>> = ({\n className,\n ...props\n}) => (\n <CommandPrimitive.Item\n className={cn(\n 'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden data-[disabled=true]:pointer-events-none data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50',\n className\n )}\n {...props}\n />\n);\n\nconst CommandShortcut = ({\n className,\n ...props\n}: HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span\n className={cn(\n 'ml-auto text-muted-foreground text-xs tracking-widest',\n className\n )}\n {...props}\n />\n );\n};\n\n/**\n * Usage example:\n * ```jsx\n * <Command>\n * <Command.Trigger>\n * <Command.Input placeholder=\"Search...\" />\n * </Command.Trigger>\n * <Command.Dialog>\n * <Command.List>\n * <Command.Item>Item 1</Command.Item>\n * <Command.Item>Item 2</Command.Item>\n * <Command.Item>Item 3</Command.Item>\n * </Command.List>\n * </Command.Dialog>\n * </Command>\n * ```\n */\nexport const Command = {\n ...CommandRoot,\n Dialog: CommandDialog,\n Input: CommandInput,\n List: CommandList,\n Empty: CommandEmpty,\n Group: CommandGroup,\n Separator: CommandSeparator,\n Item: CommandItem,\n Shortcut: CommandShortcut,\n};\n"],"mappings":";;;;;;;;;AAaA,MAAaA,eAA4D,EACvE,WACA,GAAG,YAEH,oBAACC;CACC,WAAW,GACT,sDACA,UACD;CACD,GAAI;EACJ;AAKJ,MAAMC,iBAAyC,EAAE,UAAU,GAAG,YAC5D,oBAAC;CAAO,GAAI;WACV,oBAAC;EAAc,WAAU;YACvB,oBAAC;GAAY,WAAU;GACpB;IACW;GACA;EACT;AAGX,MAAMC,gBAAmE,EACvE,WACA,GAAG,YAEH,qBAAC;CAAI,WAAU;CAA2B,sBAAmB;YAC3D,oBAAC,UAAO,WAAU,oCAAoC,EACtD,oBAACF,UAAiB;EAChB,WAAW,GACT,kJACA,UACD;EACD,GAAI;GACJ;EACE;AAGR,MAAMG,eAAiE,EACrE,WACA,GAAG,YAEH,oBAACH,UAAiB;CAChB,WAAW,GAAG,mDAAmD,UAAU;CAC3E,GAAI;EACJ;AAGJ,MAAMI,gBACJ,UACG,oBAACJ,UAAiB;CAAM,WAAU;CAA2B,GAAI;EAAS;AAE/E,MAAMK,gBAAmE,EACvE,WACA,GAAG,YAEH,oBAACL,UAAiB;CAChB,WAAW,GACT,0NACA,UACD;CACD,GAAI;EACJ;AAGJ,MAAMM,oBAED,EAAE,WAAW,GAAG,YACnB,oBAACN,UAAiB;CAChB,WAAW,GAAG,wBAAwB,UAAU;CAChD,GAAI;EACJ;AAGJ,MAAMO,eAAiE,EACrE,WACA,GAAG,YAEH,oBAACP,UAAiB;CAChB,WAAW,GACT,2PACA,UACD;CACD,GAAI;EACJ;AAGJ,MAAM,mBAAmB,EACvB,WACA,GAAG,YACkC;AACrC,QACE,oBAAC;EACC,WAAW,GACT,yDACA,UACD;EACD,GAAI;GACJ;;;;;;;;;;;;;;;;;;;AAqBN,MAAa,UAAU;CACrB,GAAG;CACH,QAAQ;CACR,OAAO;CACP,MAAM;CACN,OAAO;CACP,OAAO;CACP,WAAW;CACX,MAAM;CACN,UAAU;CACX"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import { cn } from "../../utils/cn.mjs";
|
|
5
4
|
import { InputVariant } from "../Input/Input.mjs";
|
|
6
5
|
import { AutoSizedTextArea } from "../TextArea/AutoSizeTextArea.mjs";
|
|
7
|
-
import { useState } from "react";
|
|
8
6
|
import { Check, X } from "lucide-react";
|
|
7
|
+
import { useState } from "react";
|
|
9
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
9
|
|
|
11
10
|
//#region src/components/ContentEditor/ContentEditor.tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentEditor.mjs","names":["ContentEditor: FC<ContentEditorProps>","isEdited: boolean","handleOnContentChange: ChangeEventHandler<HTMLTextAreaElement>"],"sources":["../../../../src/components/ContentEditor/ContentEditor.tsx"],"sourcesContent":["'use client';\n\nimport { Check, X } from 'lucide-react';\nimport { type ChangeEventHandler, type FC, useState } from 'react';\nimport { cn } from '../../utils/cn';\nimport { InputVariant } from '../Input';\nimport {\n AutoSizedTextArea,\n type AutoSizedTextAreaProps,\n} from '../TextArea/AutoSizeTextArea';\n\n/** Props for the ContentEditor component */\nexport type ContentEditorProps = {\n /** The current content to display and edit */\n children: string;\n /** Callback function called when content is saved/validated */\n onContentChange: (content: string) => void;\n /** Whether the editor is currently in editing mode */\n isEditing?: boolean;\n} & AutoSizedTextAreaProps;\n\n/**\n * ContentEditor Component\n *\n * An inline editing component that allows users to edit text content with\n * validation and cancellation options. Built on top of AutoSizedTextArea\n * for flexible text editing experiences.\n *\n * ## Features\n * - **Inline Editing**: Edit content directly in place with visual feedback\n * - **Auto-sizing**: Textarea automatically adjusts to content size\n * - **Validation Controls**: Check and X buttons appear when content is modified\n * - **Keyboard Support**: Full keyboard navigation and accessibility\n * - **State Management**: Handles editing states and content validation\n *\n * ## Accessibility\n * - Proper ARIA labels for all interactive elements\n * - Keyboard navigation support (Tab, Enter, Escape)\n * - Screen reader announcements for state changes\n * - Focus management between edit and display modes\n *\n * @param children - The current content to display and edit\n * @param onContentChange - Callback when content is saved\n * @param isEditing - Whether editor is in editing mode\n * @param props - Additional AutoSizedTextArea props\n */\nexport const ContentEditor: FC<ContentEditorProps> = ({\n children,\n onContentChange,\n isEditing,\n ...props\n}) => {\n const [newValue, setNewValue] = useState<string>(children);\n const [resetIncrementor, setResetIncrementor] = useState<number>(0); // To reset the div on cancel\n const isEdited: boolean = newValue !== children;\n\n const handleCancel = () => {\n setNewValue(children);\n setResetIncrementor((prev) => prev + 1);\n };\n\n const handleValid = () => {\n onContentChange(newValue);\n };\n\n const handleOnContentChange: ChangeEventHandler<HTMLTextAreaElement> = (e) =>\n setNewValue(e.target.value ?? '');\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n handleValid();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n handleCancel();\n }\n };\n\n return (\n <div\n className=\"flex flex-row items-center justify-between gap-2\"\n role=\"group\"\n aria-label=\"Content editor\"\n >\n <AutoSizedTextArea\n className={cn(\n 'break-word m-3 inline w-full bg-transparent outline-hidden',\n isEditing ? 'cursor-text' : 'cursor-pointer'\n )}\n onChange={handleOnContentChange}\n onKeyDown={handleKeyDown}\n key={resetIncrementor}\n variant={InputVariant.INVISIBLE}\n defaultValue={children}\n aria-label=\"Editable content\"\n aria-describedby={isEdited ? 'content-editor-actions' : undefined}\n {...props}\n />\n {isEdited && (\n <div\n id=\"content-editor-actions\"\n className=\"flex flex-row items-center justify-between gap-2\"\n role=\"group\"\n aria-label=\"Edit actions\"\n >\n <Check\n className=\"cursor-pointer text-green-600 hover:scale-110\"\n size={16}\n onClick={handleValid}\n role=\"button\"\n tabIndex={0}\n aria-label=\"Save changes (Ctrl+Enter)\"\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleValid();\n }\n }}\n />\n <X\n className=\"cursor-pointer text-red-600 hover:scale-110\"\n size={16}\n onClick={handleCancel}\n role=\"button\"\n tabIndex={0}\n aria-label=\"Cancel changes (Escape)\"\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleCancel();\n }\n }}\n />\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ContentEditor.mjs","names":["ContentEditor: FC<ContentEditorProps>","isEdited: boolean","handleOnContentChange: ChangeEventHandler<HTMLTextAreaElement>"],"sources":["../../../../src/components/ContentEditor/ContentEditor.tsx"],"sourcesContent":["'use client';\n\nimport { Check, X } from 'lucide-react';\nimport { type ChangeEventHandler, type FC, useState } from 'react';\nimport { cn } from '../../utils/cn';\nimport { InputVariant } from '../Input';\nimport {\n AutoSizedTextArea,\n type AutoSizedTextAreaProps,\n} from '../TextArea/AutoSizeTextArea';\n\n/** Props for the ContentEditor component */\nexport type ContentEditorProps = {\n /** The current content to display and edit */\n children: string;\n /** Callback function called when content is saved/validated */\n onContentChange: (content: string) => void;\n /** Whether the editor is currently in editing mode */\n isEditing?: boolean;\n} & AutoSizedTextAreaProps;\n\n/**\n * ContentEditor Component\n *\n * An inline editing component that allows users to edit text content with\n * validation and cancellation options. Built on top of AutoSizedTextArea\n * for flexible text editing experiences.\n *\n * ## Features\n * - **Inline Editing**: Edit content directly in place with visual feedback\n * - **Auto-sizing**: Textarea automatically adjusts to content size\n * - **Validation Controls**: Check and X buttons appear when content is modified\n * - **Keyboard Support**: Full keyboard navigation and accessibility\n * - **State Management**: Handles editing states and content validation\n *\n * ## Accessibility\n * - Proper ARIA labels for all interactive elements\n * - Keyboard navigation support (Tab, Enter, Escape)\n * - Screen reader announcements for state changes\n * - Focus management between edit and display modes\n *\n * @param children - The current content to display and edit\n * @param onContentChange - Callback when content is saved\n * @param isEditing - Whether editor is in editing mode\n * @param props - Additional AutoSizedTextArea props\n */\nexport const ContentEditor: FC<ContentEditorProps> = ({\n children,\n onContentChange,\n isEditing,\n ...props\n}) => {\n const [newValue, setNewValue] = useState<string>(children);\n const [resetIncrementor, setResetIncrementor] = useState<number>(0); // To reset the div on cancel\n const isEdited: boolean = newValue !== children;\n\n const handleCancel = () => {\n setNewValue(children);\n setResetIncrementor((prev) => prev + 1);\n };\n\n const handleValid = () => {\n onContentChange(newValue);\n };\n\n const handleOnContentChange: ChangeEventHandler<HTMLTextAreaElement> = (e) =>\n setNewValue(e.target.value ?? '');\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n e.preventDefault();\n handleValid();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n handleCancel();\n }\n };\n\n return (\n <div\n className=\"flex flex-row items-center justify-between gap-2\"\n role=\"group\"\n aria-label=\"Content editor\"\n >\n <AutoSizedTextArea\n className={cn(\n 'break-word m-3 inline w-full bg-transparent outline-hidden',\n isEditing ? 'cursor-text' : 'cursor-pointer'\n )}\n onChange={handleOnContentChange}\n onKeyDown={handleKeyDown}\n key={resetIncrementor}\n variant={InputVariant.INVISIBLE}\n defaultValue={children}\n aria-label=\"Editable content\"\n aria-describedby={isEdited ? 'content-editor-actions' : undefined}\n {...props}\n />\n {isEdited && (\n <div\n id=\"content-editor-actions\"\n className=\"flex flex-row items-center justify-between gap-2\"\n role=\"group\"\n aria-label=\"Edit actions\"\n >\n <Check\n className=\"cursor-pointer text-green-600 hover:scale-110\"\n size={16}\n onClick={handleValid}\n role=\"button\"\n tabIndex={0}\n aria-label=\"Save changes (Ctrl+Enter)\"\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleValid();\n }\n }}\n />\n <X\n className=\"cursor-pointer text-red-600 hover:scale-110\"\n size={16}\n onClick={handleCancel}\n role=\"button\"\n tabIndex={0}\n aria-label=\"Cancel changes (Escape)\"\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleCancel();\n }\n }}\n />\n </div>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CA,MAAaA,iBAAyC,EACpD,UACA,iBACA,WACA,GAAG,YACC;CACJ,MAAM,CAAC,UAAU,eAAe,SAAiB,SAAS;CAC1D,MAAM,CAAC,kBAAkB,uBAAuB,SAAiB,EAAE;CACnE,MAAMC,WAAoB,aAAa;CAEvC,MAAM,qBAAqB;AACzB,cAAY,SAAS;AACrB,uBAAqB,SAAS,OAAO,EAAE;;CAGzC,MAAM,oBAAoB;AACxB,kBAAgB,SAAS;;CAG3B,MAAMC,yBAAkE,MACtE,YAAY,EAAE,OAAO,SAAS,GAAG;CAEnC,MAAM,iBAAiB,MAAgD;AACrE,MAAI,EAAE,QAAQ,YAAY,EAAE,WAAW,EAAE,UAAU;AACjD,KAAE,gBAAgB;AAClB,gBAAa;aACJ,EAAE,QAAQ,UAAU;AAC7B,KAAE,gBAAgB;AAClB,iBAAc;;;AAIlB,QACE,qBAAC;EACC,WAAU;EACV,MAAK;EACL,cAAW;aAEX,oBAAC;GACC,WAAW,GACT,8DACA,YAAY,gBAAgB,iBAC7B;GACD,UAAU;GACV,WAAW;GAEX,SAAS,aAAa;GACtB,cAAc;GACd,cAAW;GACX,oBAAkB,WAAW,2BAA2B;GACxD,GAAI;KALC,iBAML,EACD,YACC,qBAAC;GACC,IAAG;GACH,WAAU;GACV,MAAK;GACL,cAAW;cAEX,oBAAC;IACC,WAAU;IACV,MAAM;IACN,SAAS;IACT,MAAK;IACL,UAAU;IACV,cAAW;IACX,YAAY,MAAM;AAChB,SAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,QAAE,gBAAgB;AAClB,mBAAa;;;KAGjB,EACF,oBAAC;IACC,WAAU;IACV,MAAM;IACN,SAAS;IACT,MAAK;IACL,UAAU;IACV,cAAW;IACX,YAAY,MAAM;AAChB,SAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AACtC,QAAE,gBAAgB;AAClB,oBAAc;;;KAGlB;IACE;GAEJ"}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
|
|
5
4
|
import { Input, InputVariant } from "../Input/Input.mjs";
|
|
6
|
-
import { useEffect, useState } from "react";
|
|
7
5
|
import { Check, X } from "lucide-react";
|
|
6
|
+
import { useEffect, useState } from "react";
|
|
8
7
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
8
|
|
|
10
9
|
//#region src/components/ContentEditor/ContentEditorInput.tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentEditorInput.mjs","names":["ContentEditorInput: FC<ContentEditorInputProps>","isEdited: boolean","handleOnContentChange: ChangeEventHandler<HTMLInputElement>"],"sources":["../../../../src/components/ContentEditor/ContentEditorInput.tsx"],"sourcesContent":["'use client';\n\nimport { Check, X } from 'lucide-react';\nimport {\n type ChangeEventHandler,\n type FC,\n type ReactNode,\n useEffect,\n useState,\n} from 'react';\nimport { Button, ButtonColor, ButtonSize, ButtonVariant } from '../Button';\nimport { Input, type InputProps, InputVariant } from '../Input';\n\n/** Props for the ContentEditorInput component */\nexport type ContentEditorInputProps = {\n /** The current content to display and edit */\n children: InputProps['value'];\n /** Callback function called when content is saved/validated */\n onContentChange: (content: InputProps['value']) => void;\n /** Whether the editor is disabled */\n disabled?: boolean;\n /** Optional validation function to check content validity */\n validate?: (content: InputProps['value']) => boolean;\n /** Additional buttons to display alongside edit actions */\n additionalButtons?: ReactNode;\n} & Omit<InputProps, 'children'>;\n\n/**\n * ContentEditorInput Component\n *\n * An inline editing component for single-line text input with validation,\n * cancel/save functionality, and support for additional action buttons.\n *\n * ## Features\n * - **Inline Input Editing**: Edit single-line content with immediate feedback\n * - **Validation Support**: Optional content validation with visual feedback\n * - **Action Buttons**: Built-in save/cancel with support for additional buttons\n * - **Keyboard Shortcuts**: Enter to save, Escape to cancel\n * - **Accessibility**: Full ARIA support and keyboard navigation\n * - **State Management**: Handles editing states and validation\n *\n * ## Accessibility\n * - Proper ARIA labels and descriptions for all controls\n * - Keyboard navigation (Tab, Enter, Escape)\n * - Screen reader support for validation states\n * - Focus management and visual indicators\n *\n * @param children - Current input value\n * @param onContentChange - Callback when content is saved\n * @param disabled - Whether the editor is disabled\n * @param validate - Optional validation function\n * @param additionalButtons - Extra buttons to display\n * @param props - Additional Input component props\n */\nexport const ContentEditorInput: FC<ContentEditorInputProps> = ({\n children,\n onContentChange,\n disabled,\n validate,\n additionalButtons,\n ...props\n}) => {\n const [newValue, setNewValue] = useState<InputProps['value']>(children);\n const [resetIncrementor, setResetIncrementor] = useState<number>(0); // To reset the div on cancel\n const isEdited: boolean = newValue !== children;\n\n const handleCancel = () => {\n setNewValue(children);\n setResetIncrementor((prev) => prev + 1);\n };\n\n const handleValid = () => {\n onContentChange(newValue);\n };\n\n const handleOnContentChange: ChangeEventHandler<HTMLInputElement> = (e) => {\n setNewValue(e.currentTarget.value);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter' && !disabled && isValid) {\n e.preventDefault();\n handleValid();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n handleCancel();\n }\n };\n\n useEffect(() => {\n setNewValue(children);\n // Force input to reset when children changes externally\n setResetIncrementor((prev) => prev + 1);\n }, [children]);\n\n const isValid = validate?.(newValue) ?? true;\n\n return (\n <div\n className=\"flex size-full flex-col items-center justify-between gap-2\"\n key={String(children)}\n role=\"group\"\n aria-label=\"Content editor input\"\n >\n <Input\n onChange={handleOnContentChange}\n onKeyDown={handleKeyDown}\n key={resetIncrementor}\n aria-label=\"Editable input value\"\n aria-describedby={\n isEdited || additionalButtons\n ? 'content-editor-input-actions'\n : undefined\n }\n aria-invalid={!isValid}\n variant={InputVariant.INVISIBLE}\n className=\"size-full\"\n defaultValue={children}\n disabled={disabled}\n {...props}\n />\n {(isEdited || additionalButtons) && (\n <div\n id=\"content-editor-input-actions\"\n className=\"flex w-full items-center justify-end gap-2\"\n role=\"group\"\n aria-label=\"Edit actions\"\n >\n {isEdited && (\n <>\n <Button\n Icon={Check}\n label={`Save changes${!isValid ? ' (invalid content)' : ''}`}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n size={ButtonSize.ICON_SM}\n className=\"cursor-pointer hover:scale-110\"\n disabled={disabled || !isValid}\n onClick={handleValid}\n aria-describedby={!isValid ? 'validation-error' : undefined}\n />\n <Button\n Icon={X}\n label=\"Cancel changes\"\n variant={ButtonVariant.HOVERABLE}\n size={ButtonSize.ICON_SM}\n color={ButtonColor.TEXT}\n className=\"cursor-pointer hover:scale-110\"\n onClick={handleCancel}\n disabled={disabled}\n />\n </>\n )}\n {additionalButtons}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ContentEditorInput.mjs","names":["ContentEditorInput: FC<ContentEditorInputProps>","isEdited: boolean","handleOnContentChange: ChangeEventHandler<HTMLInputElement>"],"sources":["../../../../src/components/ContentEditor/ContentEditorInput.tsx"],"sourcesContent":["'use client';\n\nimport { Check, X } from 'lucide-react';\nimport {\n type ChangeEventHandler,\n type FC,\n type ReactNode,\n useEffect,\n useState,\n} from 'react';\nimport { Button, ButtonColor, ButtonSize, ButtonVariant } from '../Button';\nimport { Input, type InputProps, InputVariant } from '../Input';\n\n/** Props for the ContentEditorInput component */\nexport type ContentEditorInputProps = {\n /** The current content to display and edit */\n children: InputProps['value'];\n /** Callback function called when content is saved/validated */\n onContentChange: (content: InputProps['value']) => void;\n /** Whether the editor is disabled */\n disabled?: boolean;\n /** Optional validation function to check content validity */\n validate?: (content: InputProps['value']) => boolean;\n /** Additional buttons to display alongside edit actions */\n additionalButtons?: ReactNode;\n} & Omit<InputProps, 'children'>;\n\n/**\n * ContentEditorInput Component\n *\n * An inline editing component for single-line text input with validation,\n * cancel/save functionality, and support for additional action buttons.\n *\n * ## Features\n * - **Inline Input Editing**: Edit single-line content with immediate feedback\n * - **Validation Support**: Optional content validation with visual feedback\n * - **Action Buttons**: Built-in save/cancel with support for additional buttons\n * - **Keyboard Shortcuts**: Enter to save, Escape to cancel\n * - **Accessibility**: Full ARIA support and keyboard navigation\n * - **State Management**: Handles editing states and validation\n *\n * ## Accessibility\n * - Proper ARIA labels and descriptions for all controls\n * - Keyboard navigation (Tab, Enter, Escape)\n * - Screen reader support for validation states\n * - Focus management and visual indicators\n *\n * @param children - Current input value\n * @param onContentChange - Callback when content is saved\n * @param disabled - Whether the editor is disabled\n * @param validate - Optional validation function\n * @param additionalButtons - Extra buttons to display\n * @param props - Additional Input component props\n */\nexport const ContentEditorInput: FC<ContentEditorInputProps> = ({\n children,\n onContentChange,\n disabled,\n validate,\n additionalButtons,\n ...props\n}) => {\n const [newValue, setNewValue] = useState<InputProps['value']>(children);\n const [resetIncrementor, setResetIncrementor] = useState<number>(0); // To reset the div on cancel\n const isEdited: boolean = newValue !== children;\n\n const handleCancel = () => {\n setNewValue(children);\n setResetIncrementor((prev) => prev + 1);\n };\n\n const handleValid = () => {\n onContentChange(newValue);\n };\n\n const handleOnContentChange: ChangeEventHandler<HTMLInputElement> = (e) => {\n setNewValue(e.currentTarget.value);\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter' && !disabled && isValid) {\n e.preventDefault();\n handleValid();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n handleCancel();\n }\n };\n\n useEffect(() => {\n setNewValue(children);\n // Force input to reset when children changes externally\n setResetIncrementor((prev) => prev + 1);\n }, [children]);\n\n const isValid = validate?.(newValue) ?? true;\n\n return (\n <div\n className=\"flex size-full flex-col items-center justify-between gap-2\"\n key={String(children)}\n role=\"group\"\n aria-label=\"Content editor input\"\n >\n <Input\n onChange={handleOnContentChange}\n onKeyDown={handleKeyDown}\n key={resetIncrementor}\n aria-label=\"Editable input value\"\n aria-describedby={\n isEdited || additionalButtons\n ? 'content-editor-input-actions'\n : undefined\n }\n aria-invalid={!isValid}\n variant={InputVariant.INVISIBLE}\n className=\"size-full\"\n defaultValue={children}\n disabled={disabled}\n {...props}\n />\n {(isEdited || additionalButtons) && (\n <div\n id=\"content-editor-input-actions\"\n className=\"flex w-full items-center justify-end gap-2\"\n role=\"group\"\n aria-label=\"Edit actions\"\n >\n {isEdited && (\n <>\n <Button\n Icon={Check}\n label={`Save changes${!isValid ? ' (invalid content)' : ''}`}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n size={ButtonSize.ICON_SM}\n className=\"cursor-pointer hover:scale-110\"\n disabled={disabled || !isValid}\n onClick={handleValid}\n aria-describedby={!isValid ? 'validation-error' : undefined}\n />\n <Button\n Icon={X}\n label=\"Cancel changes\"\n variant={ButtonVariant.HOVERABLE}\n size={ButtonSize.ICON_SM}\n color={ButtonColor.TEXT}\n className=\"cursor-pointer hover:scale-110\"\n onClick={handleCancel}\n disabled={disabled}\n />\n </>\n )}\n {additionalButtons}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,MAAaA,sBAAmD,EAC9D,UACA,iBACA,UACA,UACA,mBACA,GAAG,YACC;CACJ,MAAM,CAAC,UAAU,eAAe,SAA8B,SAAS;CACvE,MAAM,CAAC,kBAAkB,uBAAuB,SAAiB,EAAE;CACnE,MAAMC,WAAoB,aAAa;CAEvC,MAAM,qBAAqB;AACzB,cAAY,SAAS;AACrB,uBAAqB,SAAS,OAAO,EAAE;;CAGzC,MAAM,oBAAoB;AACxB,kBAAgB,SAAS;;CAG3B,MAAMC,yBAA+D,MAAM;AACzE,cAAY,EAAE,cAAc,MAAM;;CAGpC,MAAM,iBAAiB,MAA6C;AAClE,MAAI,EAAE,QAAQ,WAAW,CAAC,YAAY,SAAS;AAC7C,KAAE,gBAAgB;AAClB,gBAAa;aACJ,EAAE,QAAQ,UAAU;AAC7B,KAAE,gBAAgB;AAClB,iBAAc;;;AAIlB,iBAAgB;AACd,cAAY,SAAS;AAErB,uBAAqB,SAAS,OAAO,EAAE;IACtC,CAAC,SAAS,CAAC;CAEd,MAAM,UAAU,WAAW,SAAS,IAAI;AAExC,QACE,qBAAC;EACC,WAAU;EAEV,MAAK;EACL,cAAW;aAEX,oBAAC;GACC,UAAU;GACV,WAAW;GAEX,cAAW;GACX,oBACE,YAAY,oBACR,iCACA;GAEN,gBAAc,CAAC;GACf,SAAS,aAAa;GACtB,WAAU;GACV,cAAc;GACJ;GACV,GAAI;KAZC,iBAaL,GACA,YAAY,sBACZ,qBAAC;GACC,IAAG;GACH,WAAU;GACV,MAAK;GACL,cAAW;cAEV,YACC,8CACE,oBAAC;IACC,MAAM;IACN,OAAO,eAAe,CAAC,UAAU,uBAAuB;IACxD,SAAS,cAAc;IACvB,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,WAAU;IACV,UAAU,YAAY,CAAC;IACvB,SAAS;IACT,oBAAkB,CAAC,UAAU,qBAAqB;KAClD,EACF,oBAAC;IACC,MAAM;IACN,OAAM;IACN,SAAS,cAAc;IACvB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,WAAU;IACV,SAAS;IACC;KACV,IACD,EAEJ;IACG;IAtDH,OAAO,SAAS,CAwDjB"}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
import { useUser } from "../../hooks/useUser/index.mjs";
|
|
5
3
|
import { Button, ButtonColor, ButtonSize, ButtonVariant } from "../Button/Button.mjs";
|
|
4
|
+
import { useUser } from "../../hooks/useUser/index.mjs";
|
|
6
5
|
import { AutoCompleteTextarea } from "../TextArea/AutocompleteTextArea.mjs";
|
|
7
|
-
import { useEffect, useState } from "react";
|
|
8
6
|
import { Check, X } from "lucide-react";
|
|
7
|
+
import { useEffect, useState } from "react";
|
|
9
8
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
10
9
|
|
|
11
10
|
//#region src/components/ContentEditor/ContentEditorTextArea.tsx
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentEditorTextArea.mjs","names":["ContentEditorTextArea: FC<ContentEditorTextAreaProps>","isEdited: boolean","handleOnContentChange: ChangeEventHandler<HTMLTextAreaElement>"],"sources":["../../../../src/components/ContentEditor/ContentEditorTextArea.tsx"],"sourcesContent":["'use client';\n\nimport { Check, X } from 'lucide-react';\nimport {\n type ChangeEventHandler,\n type FC,\n type ReactNode,\n useEffect,\n useState,\n} from 'react';\nimport { useUser } from '../../hooks/useUser';\nimport { Button, ButtonColor, ButtonSize, ButtonVariant } from '../Button';\nimport { AutoCompleteTextarea, type AutoSizedTextAreaProps } from '../TextArea';\n\n/** Props for the ContentEditorTextArea component */\nexport type ContentEditorTextAreaProps = {\n /** The current content to display and edit */\n children: string;\n /** Callback function called when content is saved/validated */\n onContentChange: (content: string) => void;\n /** Whether the editor is disabled */\n disabled?: boolean;\n /** Optional validation function to check content validity */\n validate?: (content: string) => boolean;\n /** Additional buttons to display alongside edit actions */\n additionalButtons?: ReactNode;\n} & Omit<AutoSizedTextAreaProps, 'children'>;\n\n/**\n * ContentEditorTextArea Component\n *\n * An inline editing component for multi-line text with autocomplete functionality,\n * user authentication integration, and validation support. This component combines\n * the auto-sizing textarea with smart autocomplete features.\n *\n * ## Features\n * - **Auto-sizing Textarea**: Automatically adjusts height to content\n * - **Autocomplete Integration**: Smart text completion when user is authenticated\n * - **Validation Support**: Optional content validation with visual feedback\n * - **Action Buttons**: Built-in save/cancel with support for additional buttons\n * - **Keyboard Shortcuts**: Enter to save, Escape to cancel\n * - **User Authentication**: Autocomplete features activate based on auth status\n * - **Accessibility**: Full ARIA support and keyboard navigation\n *\n * ## Accessibility\n * - Proper ARIA labels and descriptions for all controls\n * - Keyboard navigation (Tab, Enter, Escape)\n * - Screen reader support for validation states and user auth status\n * - Focus management and visual indicators\n *\n * @param children - Current textarea content\n * @param onContentChange - Callback when content is saved\n * @param disabled - Whether the editor is disabled\n * @param validate - Optional validation function\n * @param additionalButtons - Extra buttons to display\n * @param props - Additional AutoSizedTextArea component props\n */\nexport const ContentEditorTextArea: FC<ContentEditorTextAreaProps> = ({\n children,\n onContentChange,\n disabled,\n validate,\n additionalButtons,\n ...props\n}) => {\n const { isAuthenticated } = useUser();\n const [newValue, setNewValue] = useState<string>(children);\n const [resetIncrementor, setResetIncrementor] = useState<number>(0); // To reset the textarea on cancel\n const isEdited: boolean = newValue !== children;\n\n const handleCancel = () => {\n setNewValue(children);\n setResetIncrementor((prev) => prev + 1);\n };\n\n const handleValid = () => {\n onContentChange(newValue);\n };\n\n const handleOnContentChange: ChangeEventHandler<HTMLTextAreaElement> = (e) =>\n setNewValue(e.currentTarget.value ?? '');\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey) && !disabled && isValid) {\n e.preventDefault();\n handleValid();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n handleCancel();\n }\n };\n\n useEffect(() => {\n setNewValue(children);\n // Force textarea to reset when children changes externally\n setResetIncrementor((prev) => prev + 1);\n }, [children]);\n\n const isValid = validate?.(newValue) ?? true;\n\n return (\n <div\n className=\"flex size-full flex-col items-center justify-between gap-2\"\n key={children}\n role=\"group\"\n aria-label=\"Content editor textarea\"\n >\n <AutoCompleteTextarea\n onChange={handleOnContentChange}\n onKeyDown={handleKeyDown}\n key={resetIncrementor}\n variant=\"invisible\"\n className=\"size-full\"\n value={children}\n isActive={isAuthenticated}\n disabled={disabled}\n aria-label=\"Editable textarea content\"\n aria-describedby={\n isEdited || additionalButtons\n ? 'content-editor-textarea-actions'\n : undefined\n }\n aria-invalid={!isValid}\n {...props}\n />\n {(isEdited || additionalButtons) && (\n <div\n id=\"content-editor-textarea-actions\"\n className=\"flex w-full items-center justify-end gap-2\"\n role=\"group\"\n aria-label=\"Edit actions\"\n >\n {isEdited && (\n <>\n <Button\n Icon={Check}\n label={`Save changes${!isValid ? ' (invalid content)' : ''}`}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n size={ButtonSize.ICON_SM}\n className=\"cursor-pointer hover:scale-110\"\n disabled={disabled || !isValid}\n onClick={handleValid}\n aria-describedby={\n !isValid ? 'textarea-validation-error' : undefined\n }\n />\n <Button\n Icon={X}\n label=\"Cancel changes\"\n variant={ButtonVariant.HOVERABLE}\n size={ButtonSize.ICON_SM}\n color={ButtonColor.TEXT}\n className=\"cursor-pointer hover:scale-110\"\n onClick={handleCancel}\n disabled={disabled}\n />\n </>\n )}\n {additionalButtons}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ContentEditorTextArea.mjs","names":["ContentEditorTextArea: FC<ContentEditorTextAreaProps>","isEdited: boolean","handleOnContentChange: ChangeEventHandler<HTMLTextAreaElement>"],"sources":["../../../../src/components/ContentEditor/ContentEditorTextArea.tsx"],"sourcesContent":["'use client';\n\nimport { Check, X } from 'lucide-react';\nimport {\n type ChangeEventHandler,\n type FC,\n type ReactNode,\n useEffect,\n useState,\n} from 'react';\nimport { useUser } from '../../hooks/useUser';\nimport { Button, ButtonColor, ButtonSize, ButtonVariant } from '../Button';\nimport { AutoCompleteTextarea, type AutoSizedTextAreaProps } from '../TextArea';\n\n/** Props for the ContentEditorTextArea component */\nexport type ContentEditorTextAreaProps = {\n /** The current content to display and edit */\n children: string;\n /** Callback function called when content is saved/validated */\n onContentChange: (content: string) => void;\n /** Whether the editor is disabled */\n disabled?: boolean;\n /** Optional validation function to check content validity */\n validate?: (content: string) => boolean;\n /** Additional buttons to display alongside edit actions */\n additionalButtons?: ReactNode;\n} & Omit<AutoSizedTextAreaProps, 'children'>;\n\n/**\n * ContentEditorTextArea Component\n *\n * An inline editing component for multi-line text with autocomplete functionality,\n * user authentication integration, and validation support. This component combines\n * the auto-sizing textarea with smart autocomplete features.\n *\n * ## Features\n * - **Auto-sizing Textarea**: Automatically adjusts height to content\n * - **Autocomplete Integration**: Smart text completion when user is authenticated\n * - **Validation Support**: Optional content validation with visual feedback\n * - **Action Buttons**: Built-in save/cancel with support for additional buttons\n * - **Keyboard Shortcuts**: Enter to save, Escape to cancel\n * - **User Authentication**: Autocomplete features activate based on auth status\n * - **Accessibility**: Full ARIA support and keyboard navigation\n *\n * ## Accessibility\n * - Proper ARIA labels and descriptions for all controls\n * - Keyboard navigation (Tab, Enter, Escape)\n * - Screen reader support for validation states and user auth status\n * - Focus management and visual indicators\n *\n * @param children - Current textarea content\n * @param onContentChange - Callback when content is saved\n * @param disabled - Whether the editor is disabled\n * @param validate - Optional validation function\n * @param additionalButtons - Extra buttons to display\n * @param props - Additional AutoSizedTextArea component props\n */\nexport const ContentEditorTextArea: FC<ContentEditorTextAreaProps> = ({\n children,\n onContentChange,\n disabled,\n validate,\n additionalButtons,\n ...props\n}) => {\n const { isAuthenticated } = useUser();\n const [newValue, setNewValue] = useState<string>(children);\n const [resetIncrementor, setResetIncrementor] = useState<number>(0); // To reset the textarea on cancel\n const isEdited: boolean = newValue !== children;\n\n const handleCancel = () => {\n setNewValue(children);\n setResetIncrementor((prev) => prev + 1);\n };\n\n const handleValid = () => {\n onContentChange(newValue);\n };\n\n const handleOnContentChange: ChangeEventHandler<HTMLTextAreaElement> = (e) =>\n setNewValue(e.currentTarget.value ?? '');\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey) && !disabled && isValid) {\n e.preventDefault();\n handleValid();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n handleCancel();\n }\n };\n\n useEffect(() => {\n setNewValue(children);\n // Force textarea to reset when children changes externally\n setResetIncrementor((prev) => prev + 1);\n }, [children]);\n\n const isValid = validate?.(newValue) ?? true;\n\n return (\n <div\n className=\"flex size-full flex-col items-center justify-between gap-2\"\n key={children}\n role=\"group\"\n aria-label=\"Content editor textarea\"\n >\n <AutoCompleteTextarea\n onChange={handleOnContentChange}\n onKeyDown={handleKeyDown}\n key={resetIncrementor}\n variant=\"invisible\"\n className=\"size-full\"\n value={children}\n isActive={isAuthenticated}\n disabled={disabled}\n aria-label=\"Editable textarea content\"\n aria-describedby={\n isEdited || additionalButtons\n ? 'content-editor-textarea-actions'\n : undefined\n }\n aria-invalid={!isValid}\n {...props}\n />\n {(isEdited || additionalButtons) && (\n <div\n id=\"content-editor-textarea-actions\"\n className=\"flex w-full items-center justify-end gap-2\"\n role=\"group\"\n aria-label=\"Edit actions\"\n >\n {isEdited && (\n <>\n <Button\n Icon={Check}\n label={`Save changes${!isValid ? ' (invalid content)' : ''}`}\n variant={ButtonVariant.HOVERABLE}\n color={ButtonColor.TEXT}\n size={ButtonSize.ICON_SM}\n className=\"cursor-pointer hover:scale-110\"\n disabled={disabled || !isValid}\n onClick={handleValid}\n aria-describedby={\n !isValid ? 'textarea-validation-error' : undefined\n }\n />\n <Button\n Icon={X}\n label=\"Cancel changes\"\n variant={ButtonVariant.HOVERABLE}\n size={ButtonSize.ICON_SM}\n color={ButtonColor.TEXT}\n className=\"cursor-pointer hover:scale-110\"\n onClick={handleCancel}\n disabled={disabled}\n />\n </>\n )}\n {additionalButtons}\n </div>\n )}\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDA,MAAaA,yBAAyD,EACpE,UACA,iBACA,UACA,UACA,mBACA,GAAG,YACC;CACJ,MAAM,EAAE,oBAAoB,SAAS;CACrC,MAAM,CAAC,UAAU,eAAe,SAAiB,SAAS;CAC1D,MAAM,CAAC,kBAAkB,uBAAuB,SAAiB,EAAE;CACnE,MAAMC,WAAoB,aAAa;CAEvC,MAAM,qBAAqB;AACzB,cAAY,SAAS;AACrB,uBAAqB,SAAS,OAAO,EAAE;;CAGzC,MAAM,oBAAoB;AACxB,kBAAgB,SAAS;;CAG3B,MAAMC,yBAAkE,MACtE,YAAY,EAAE,cAAc,SAAS,GAAG;CAE1C,MAAM,iBAAiB,MAAgD;AACrE,MAAI,EAAE,QAAQ,YAAY,EAAE,WAAW,EAAE,YAAY,CAAC,YAAY,SAAS;AACzE,KAAE,gBAAgB;AAClB,gBAAa;aACJ,EAAE,QAAQ,UAAU;AAC7B,KAAE,gBAAgB;AAClB,iBAAc;;;AAIlB,iBAAgB;AACd,cAAY,SAAS;AAErB,uBAAqB,SAAS,OAAO,EAAE;IACtC,CAAC,SAAS,CAAC;CAEd,MAAM,UAAU,WAAW,SAAS,IAAI;AAExC,QACE,qBAAC;EACC,WAAU;EAEV,MAAK;EACL,cAAW;aAEX,oBAAC;GACC,UAAU;GACV,WAAW;GAEX,SAAQ;GACR,WAAU;GACV,OAAO;GACP,UAAU;GACA;GACV,cAAW;GACX,oBACE,YAAY,oBACR,oCACA;GAEN,gBAAc,CAAC;GACf,GAAI;KAbC,iBAcL,GACA,YAAY,sBACZ,qBAAC;GACC,IAAG;GACH,WAAU;GACV,MAAK;GACL,cAAW;cAEV,YACC,8CACE,oBAAC;IACC,MAAM;IACN,OAAO,eAAe,CAAC,UAAU,uBAAuB;IACxD,SAAS,cAAc;IACvB,OAAO,YAAY;IACnB,MAAM,WAAW;IACjB,WAAU;IACV,UAAU,YAAY,CAAC;IACvB,SAAS;IACT,oBACE,CAAC,UAAU,8BAA8B;KAE3C,EACF,oBAAC;IACC,MAAM;IACN,OAAM;IACN,SAAS,cAAc;IACvB,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,WAAU;IACV,SAAS;IACC;KACV,IACD,EAEJ;IACG;IAzDH,SA2DD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentSelector.mjs","names":["ContentSelector: FC<ContentSelectorProps>"],"sources":["../../../../src/components/ContentSelector/ContentSelector.tsx"],"sourcesContent":["'use client';\n\nimport type { FC, ReactNode } from 'react';\nimport { PressableSpan } from '../PressableSpan';\n\n/**\n * Props for the ContentSelector component\n */\ntype ContentSelectorProps = {\n /**\n * The content to be displayed and made selectable\n * @example\n * ```tsx\n * <ContentSelector onSelect={() => startEditing()}>\n * <h1>Selectable Heading</h1>\n * </ContentSelector>\n * ```\n */\n children: ReactNode;\n\n /**\n * Callback function triggered when content is selected via long press or keyboard\n * @example\n * ```tsx\n * <ContentSelector\n * onSelect={() => setEditMode(true)}\n * onUnselect={() => setEditMode(false)}\n * >\n * Click content to edit\n * </ContentSelector>\n * ```\n */\n onSelect: () => void;\n\n /**\n * Optional callback function triggered when clicking outside the selected content\n * Used to deselect the content and exit edit/selection mode\n * @example\n * ```tsx\n * <ContentSelector\n * onSelect={() => enterEditMode()}\n * onUnselect={() => exitEditMode()}\n * >\n * Editable content with auto-deselect\n * </ContentSelector>\n * ```\n */\n onUnselect?: () => void;\n\n /**\n * External control for the selection state\n * When provided, overrides the internal selection state\n * @example\n * ```tsx\n * <ContentSelector\n * isSelecting={isInEditMode}\n * onSelect={() => {}}\n * >\n * Externally controlled content\n * </ContentSelector>\n * ```\n */\n isSelecting?: boolean;\n\n /**\n * Duration in milliseconds for long press detection\n * @default 400\n * @example\n * ```tsx\n * <ContentSelector\n * pressDuration={600}\n * onSelect={() => activateSlowSelection()}\n * >\n * Requires longer press\n * </ContentSelector>\n * ```\n */\n pressDuration?: number;\n\n /**\n * Additional CSS classes for styling the selectable content\n * @example\n * ```tsx\n * <ContentSelector\n * className=\"border-2 border-dashed border-blue-300\"\n * onSelect={() => {}}\n * >\n * Styled selectable content\n * </ContentSelector>\n * ```\n */\n className?: string;\n\n /**\n * ARIA label for accessibility\n * Provides context about what happens when the content is selected\n * @example\n * ```tsx\n * <ContentSelector\n * aria-label=\"Select to edit this content\"\n * onSelect={() => {}}\n * >\n * Content with accessibility context\n * </ContentSelector>\n * ```\n */\n 'aria-label'?: string;\n\n /**\n * ID of element providing additional description\n * @example\n * ```tsx\n * <ContentSelector\n * aria-describedby=\"help-text\"\n * onSelect={() => {}}\n * >\n * Content with help\n * </ContentSelector>\n * <div id=\"help-text\">Long press to edit</div>\n * ```\n */\n 'aria-describedby'?: string;\n};\n\n/**\n * ContentSelector - A higher-level wrapper around PressableSpan for content selection\n *\n * This component provides a semantic interface for making any content selectable through\n * long press gestures. It's specifically designed for content management interfaces\n * where users need to select text, images, or other elements to perform actions like\n * editing, moving, or applying operations.\n *\n * ## Key Features\n * - **Content Selection**: Makes any React content selectable via long press\n * - **Visual Feedback**: Inherits outline-based selection indicators from PressableSpan\n * - **Accessibility**: Full keyboard navigation and screen reader support\n * - **Click Outside**: Automatic deselection when clicking elsewhere\n * - **External Control**: Can be controlled externally for complex selection states\n *\n * ## Use Cases\n * - Content management systems with inline editing\n * - Text and media selection interfaces\n * - Interactive documentation with selectable sections\n * - Dashboard widgets with configurable content\n * - Form builders with selectable form elements\n *\n * ## Accessibility\n * - Inherits all accessibility features from PressableSpan\n * - Keyboard navigation with Tab, Enter, Space, and Escape\n * - Screen reader announcements for selection states\n * - Focus management and proper ARIA attributes\n *\n * @example\n * Basic content selection:\n * ```tsx\n * <ContentSelector onSelect={() => setIsEditing(true)}>\n * <p>This paragraph becomes selectable</p>\n * </ContentSelector>\n * ```\n *\n * @example\n * With deselection handling:\n * ```tsx\n * <ContentSelector\n * onSelect={() => setSelectedContent(contentId)}\n * onUnselect={() => setSelectedContent(null)}\n * >\n * <div className=\"content-block\">\n * <h2>Selectable Content Block</h2>\n * <p>Long press to select this entire block</p>\n * </div>\n * </ContentSelector>\n * ```\n *\n * @example\n * Controlled selection state:\n * ```tsx\n * <ContentSelector\n * isSelecting={selectedItems.includes(itemId)}\n * onSelect={() => selectItem(itemId)}\n * onUnselect={() => deselectItem(itemId)}\n * >\n * <ContentCard data={cardData} />\n * </ContentSelector>\n * ```\n */\n\nexport const ContentSelector: FC<ContentSelectorProps> = ({\n children,\n onSelect,\n onUnselect,\n isSelecting,\n pressDuration,\n className,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n}) => (\n <PressableSpan\n onPress={onSelect}\n onClickOutside={onUnselect}\n isSelecting={isSelecting}\n pressDuration={pressDuration}\n className={className}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedBy}\n >\n {children}\n </PressableSpan>\n);\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ContentSelector.mjs","names":["ContentSelector: FC<ContentSelectorProps>"],"sources":["../../../../src/components/ContentSelector/ContentSelector.tsx"],"sourcesContent":["'use client';\n\nimport type { FC, ReactNode } from 'react';\nimport { PressableSpan } from '../PressableSpan';\n\n/**\n * Props for the ContentSelector component\n */\ntype ContentSelectorProps = {\n /**\n * The content to be displayed and made selectable\n * @example\n * ```tsx\n * <ContentSelector onSelect={() => startEditing()}>\n * <h1>Selectable Heading</h1>\n * </ContentSelector>\n * ```\n */\n children: ReactNode;\n\n /**\n * Callback function triggered when content is selected via long press or keyboard\n * @example\n * ```tsx\n * <ContentSelector\n * onSelect={() => setEditMode(true)}\n * onUnselect={() => setEditMode(false)}\n * >\n * Click content to edit\n * </ContentSelector>\n * ```\n */\n onSelect: () => void;\n\n /**\n * Optional callback function triggered when clicking outside the selected content\n * Used to deselect the content and exit edit/selection mode\n * @example\n * ```tsx\n * <ContentSelector\n * onSelect={() => enterEditMode()}\n * onUnselect={() => exitEditMode()}\n * >\n * Editable content with auto-deselect\n * </ContentSelector>\n * ```\n */\n onUnselect?: () => void;\n\n /**\n * External control for the selection state\n * When provided, overrides the internal selection state\n * @example\n * ```tsx\n * <ContentSelector\n * isSelecting={isInEditMode}\n * onSelect={() => {}}\n * >\n * Externally controlled content\n * </ContentSelector>\n * ```\n */\n isSelecting?: boolean;\n\n /**\n * Duration in milliseconds for long press detection\n * @default 400\n * @example\n * ```tsx\n * <ContentSelector\n * pressDuration={600}\n * onSelect={() => activateSlowSelection()}\n * >\n * Requires longer press\n * </ContentSelector>\n * ```\n */\n pressDuration?: number;\n\n /**\n * Additional CSS classes for styling the selectable content\n * @example\n * ```tsx\n * <ContentSelector\n * className=\"border-2 border-dashed border-blue-300\"\n * onSelect={() => {}}\n * >\n * Styled selectable content\n * </ContentSelector>\n * ```\n */\n className?: string;\n\n /**\n * ARIA label for accessibility\n * Provides context about what happens when the content is selected\n * @example\n * ```tsx\n * <ContentSelector\n * aria-label=\"Select to edit this content\"\n * onSelect={() => {}}\n * >\n * Content with accessibility context\n * </ContentSelector>\n * ```\n */\n 'aria-label'?: string;\n\n /**\n * ID of element providing additional description\n * @example\n * ```tsx\n * <ContentSelector\n * aria-describedby=\"help-text\"\n * onSelect={() => {}}\n * >\n * Content with help\n * </ContentSelector>\n * <div id=\"help-text\">Long press to edit</div>\n * ```\n */\n 'aria-describedby'?: string;\n};\n\n/**\n * ContentSelector - A higher-level wrapper around PressableSpan for content selection\n *\n * This component provides a semantic interface for making any content selectable through\n * long press gestures. It's specifically designed for content management interfaces\n * where users need to select text, images, or other elements to perform actions like\n * editing, moving, or applying operations.\n *\n * ## Key Features\n * - **Content Selection**: Makes any React content selectable via long press\n * - **Visual Feedback**: Inherits outline-based selection indicators from PressableSpan\n * - **Accessibility**: Full keyboard navigation and screen reader support\n * - **Click Outside**: Automatic deselection when clicking elsewhere\n * - **External Control**: Can be controlled externally for complex selection states\n *\n * ## Use Cases\n * - Content management systems with inline editing\n * - Text and media selection interfaces\n * - Interactive documentation with selectable sections\n * - Dashboard widgets with configurable content\n * - Form builders with selectable form elements\n *\n * ## Accessibility\n * - Inherits all accessibility features from PressableSpan\n * - Keyboard navigation with Tab, Enter, Space, and Escape\n * - Screen reader announcements for selection states\n * - Focus management and proper ARIA attributes\n *\n * @example\n * Basic content selection:\n * ```tsx\n * <ContentSelector onSelect={() => setIsEditing(true)}>\n * <p>This paragraph becomes selectable</p>\n * </ContentSelector>\n * ```\n *\n * @example\n * With deselection handling:\n * ```tsx\n * <ContentSelector\n * onSelect={() => setSelectedContent(contentId)}\n * onUnselect={() => setSelectedContent(null)}\n * >\n * <div className=\"content-block\">\n * <h2>Selectable Content Block</h2>\n * <p>Long press to select this entire block</p>\n * </div>\n * </ContentSelector>\n * ```\n *\n * @example\n * Controlled selection state:\n * ```tsx\n * <ContentSelector\n * isSelecting={selectedItems.includes(itemId)}\n * onSelect={() => selectItem(itemId)}\n * onUnselect={() => deselectItem(itemId)}\n * >\n * <ContentCard data={cardData} />\n * </ContentSelector>\n * ```\n */\n\nexport const ContentSelector: FC<ContentSelectorProps> = ({\n children,\n onSelect,\n onUnselect,\n isSelecting,\n pressDuration,\n className,\n 'aria-label': ariaLabel,\n 'aria-describedby': ariaDescribedBy,\n}) => (\n <PressableSpan\n onPress={onSelect}\n onClickOutside={onUnselect}\n isSelecting={isSelecting}\n pressDuration={pressDuration}\n className={className}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedBy}\n >\n {children}\n </PressableSpan>\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2LA,MAAaA,mBAA6C,EACxD,UACA,UACA,YACA,aACA,eACA,WACA,cAAc,WACd,oBAAoB,sBAEpB,oBAAC;CACC,SAAS;CACT,gBAAgB;CACH;CACE;CACJ;CACX,cAAY;CACZ,oBAAkB;CAEjB;EACa"}
|