@intlayer/design-system 7.5.5 → 7.5.7
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 -1
- package/dist/esm/components/Avatar/index.mjs +1 -1
- package/dist/esm/components/Breadcrumb/index.mjs +29 -3
- package/dist/esm/components/Breadcrumb/index.mjs.map +1 -1
- package/dist/esm/components/Browser/Browser.mjs +30 -41
- package/dist/esm/components/Browser/Browser.mjs.map +1 -1
- package/dist/esm/components/Browser/{Browser.content.mjs → browser.content.mjs} +42 -4
- package/dist/esm/components/Browser/{Browser.content.mjs.map → browser.content.mjs.map} +1 -1
- package/dist/esm/components/Button/Button.mjs +6 -2
- package/dist/esm/components/Button/Button.mjs.map +1 -1
- package/dist/esm/components/CollapsibleTable/CollapsibleTable.mjs +1 -1
- package/dist/esm/components/ContentEditor/ContentEditor.mjs +1 -1
- package/dist/esm/components/ContentEditor/ContentEditorInput.mjs +1 -1
- package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +2 -2
- package/dist/esm/components/CopyButton/index.mjs +1 -1
- package/dist/esm/components/CopyToClipboard/index.mjs +1 -1
- package/dist/esm/components/DictionaryEditor/DictionaryEditor.mjs +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 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +113 -83
- package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +4 -4
- package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +2 -2
- package/dist/esm/components/DictionaryFieldEditor/JSONEditor.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/KeyPathBreadcrumb.mjs +7 -6
- package/dist/esm/components/DictionaryFieldEditor/KeyPathBreadcrumb.mjs.map +1 -1
- package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +2 -2
- package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +4 -4
- package/dist/esm/components/DictionaryFieldEditor/StructureEditor.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +1 -1
- package/dist/esm/components/DictionaryFieldEditor/index.mjs +4 -1
- package/dist/esm/components/DropDown/index.mjs +19 -4
- package/dist/esm/components/DropDown/index.mjs.map +1 -1
- package/dist/esm/components/EditableField/EditableFieldLayout.mjs +1 -1
- package/dist/esm/components/Flags/Flag.mjs +55 -2
- package/dist/esm/components/Flags/Flag.mjs.map +1 -1
- package/dist/esm/components/Flags/bw.mjs +35 -0
- package/dist/esm/components/Flags/bw.mjs.map +1 -0
- package/dist/esm/components/Flags/cu.mjs +45 -0
- package/dist/esm/components/Flags/cu.mjs.map +1 -0
- package/dist/esm/components/Flags/cv.mjs +45 -0
- package/dist/esm/components/Flags/cv.mjs.map +1 -0
- package/dist/esm/components/Flags/dj.mjs +45 -0
- package/dist/esm/components/Flags/dj.mjs.map +1 -0
- package/dist/esm/components/Flags/flags.mjs +242 -7
- package/dist/esm/components/Flags/flags.mjs.map +1 -1
- package/dist/esm/components/Flags/gh.mjs +38 -0
- package/dist/esm/components/Flags/gh.mjs.map +1 -0
- package/dist/esm/components/Flags/gw.mjs +69 -0
- package/dist/esm/components/Flags/gw.mjs.map +1 -0
- package/dist/esm/components/Flags/km.mjs +54 -0
- package/dist/esm/components/Flags/km.mjs.map +1 -0
- package/dist/esm/components/Flags/lk.mjs +75 -0
- package/dist/esm/components/Flags/lk.mjs.map +1 -0
- package/dist/esm/components/Flags/md.mjs +319 -0
- package/dist/esm/components/Flags/md.mjs.map +1 -0
- package/dist/esm/components/Flags/mr.mjs +39 -0
- package/dist/esm/components/Flags/mr.mjs.map +1 -0
- package/dist/esm/components/Flags/mz.mjs +94 -0
- package/dist/esm/components/Flags/mz.mjs.map +1 -0
- package/dist/esm/components/Flags/ps.mjs +47 -0
- package/dist/esm/components/Flags/ps.mjs.map +1 -0
- package/dist/esm/components/Flags/sd.mjs +46 -0
- package/dist/esm/components/Flags/sd.mjs.map +1 -0
- package/dist/esm/components/Flags/so.mjs +39 -0
- package/dist/esm/components/Flags/so.mjs.map +1 -0
- package/dist/esm/components/Flags/st.mjs +75 -0
- package/dist/esm/components/Flags/st.mjs.map +1 -0
- package/dist/esm/components/Flags/td.mjs +35 -0
- package/dist/esm/components/Flags/td.mjs.map +1 -0
- package/dist/esm/components/Flags/tl.mjs +45 -0
- package/dist/esm/components/Flags/tl.mjs.map +1 -0
- package/dist/esm/components/Flags/tz.mjs +46 -0
- package/dist/esm/components/Flags/tz.mjs.map +1 -0
- package/dist/esm/components/Flags/ug.mjs +147 -0
- package/dist/esm/components/Flags/ug.mjs.map +1 -0
- package/dist/esm/components/Form/elements/OTPElement.mjs +2 -2
- package/dist/esm/components/Form/elements/OTPElement.mjs.map +1 -1
- package/dist/esm/components/HideShow/index.mjs +1 -1
- package/dist/esm/components/IDE/FileTree.mjs +1 -1
- package/dist/esm/components/Input/Input.mjs +3 -1
- package/dist/esm/components/Input/Input.mjs.map +1 -1
- package/dist/esm/components/Input/InputPassword.mjs +1 -1
- package/dist/esm/components/Input/OTPInput.mjs +3 -3
- package/dist/esm/components/Input/OTPInput.mjs.map +1 -1
- package/dist/esm/components/Input/SearchInput.mjs +1 -1
- package/dist/esm/components/Input/SearchInput.mjs.map +1 -1
- package/dist/esm/components/KeyboardScreenAdapter/index.mjs +1 -1
- package/dist/esm/components/KeyboardShortcut/KeyboardShortcut.mjs +1 -1
- package/dist/esm/components/Link/Link.mjs +11 -3
- package/dist/esm/components/Link/Link.mjs.map +1 -1
- package/dist/esm/components/Link/index.mjs +2 -2
- package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +19 -13
- package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs.map +1 -1
- package/dist/esm/components/LocaleSwitcherDropDown/LocaleSwitcher.mjs +1 -1
- package/dist/esm/components/Modal/Modal.mjs +3 -3
- package/dist/esm/components/Navbar/MobileNavbar.mjs +2 -2
- package/dist/esm/components/Pagination/Pagination.mjs +2 -2
- package/dist/esm/components/RightDrawer/RightDrawer.mjs +3 -3
- package/dist/esm/components/Select/Multiselect.mjs +1 -1
- package/dist/esm/components/SwitchSelector/index.mjs +1 -1
- package/dist/esm/components/Tab/Tab.mjs +1 -1
- package/dist/esm/components/TabSelector/TabSelector.mjs +1 -1
- package/dist/esm/components/Table/Table.mjs +1 -1
- package/dist/esm/components/TextArea/AutocompleteTextArea.mjs +3 -30
- package/dist/esm/components/TextArea/AutocompleteTextArea.mjs.map +1 -1
- package/dist/esm/components/ThemeSwitcherDropDown/DesktopThemeSwitcher.mjs +1 -1
- package/dist/esm/components/ThemeSwitcherDropDown/MobileThemeSwitcher.mjs +1 -1
- package/dist/esm/components/index.mjs +12 -9
- package/dist/esm/hooks/index.mjs +2 -2
- package/dist/esm/hooks/reactQuery.mjs +32 -3
- package/dist/esm/hooks/reactQuery.mjs.map +1 -1
- package/dist/esm/hooks/useAuth/useOAuth2.mjs +1 -1
- package/dist/esm/hooks/useAuth/useSession.mjs +1 -1
- package/dist/esm/hooks/usePersistedStore.mjs +1 -1
- package/dist/esm/hooks/usePersistedStore.mjs.map +1 -1
- package/dist/esm/libs/auth.mjs +1 -1
- package/dist/esm/providers/ReactQueryProvider.mjs +1 -1
- package/dist/types/components/Breadcrumb/breadcrumb.content.d.ts +3 -3
- package/dist/types/components/Breadcrumb/index.d.ts.map +1 -1
- package/dist/types/components/Browser/Browser.d.ts +2 -2
- package/dist/types/components/Browser/Browser.d.ts.map +1 -1
- package/dist/types/components/Browser/{Browser.content.d.ts → browser.content.d.ts} +97 -15
- package/dist/types/components/Browser/browser.content.d.ts.map +1 -0
- package/dist/types/components/Button/Button.d.ts +6 -6
- package/dist/types/components/Button/Button.d.ts.map +1 -1
- package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +3 -3
- package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts.map +1 -1
- package/dist/types/components/Command/index.d.ts +17 -17
- package/dist/types/components/Command/index.d.ts.map +1 -1
- package/dist/types/components/Container/index.d.ts +7 -7
- 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/ContentEditorView/TextEditor.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/KeyPathBreadcrumb.d.ts +5 -1
- package/dist/types/components/DictionaryFieldEditor/KeyPathBreadcrumb.d.ts.map +1 -1
- package/dist/types/components/DictionaryFieldEditor/NavigationView/navigationViewNode.content.d.ts +25 -25
- 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/index.d.ts +4 -1
- package/dist/types/components/DictionaryFieldEditor/nodeTypeSelector.content.d.ts +31 -31
- package/dist/types/components/DictionaryFieldEditor/nodeTypeSelector.content.d.ts.map +1 -1
- package/dist/types/components/DropDown/index.d.ts +16 -2
- package/dist/types/components/DropDown/index.d.ts.map +1 -1
- package/dist/types/components/EditableField/EditableFieldInput.d.ts.map +1 -1
- package/dist/types/components/ExpandCollapse/expandCollapse.content.d.ts +3 -3
- package/dist/types/components/Flags/Flag.d.ts.map +1 -1
- package/dist/types/components/Flags/flags.d.ts +169 -7
- package/dist/types/components/Flags/flags.d.ts.map +1 -1
- package/dist/types/components/Form/FormBase.d.ts +2 -2
- package/dist/types/components/Form/FormField.d.ts +2 -2
- 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/FormElement.d.ts +2 -2
- 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/IDE/CodeContext.d.ts +2 -2
- package/dist/types/components/IDE/CodeContext.d.ts.map +1 -1
- package/dist/types/components/IDE/copyCode.content.d.ts +5 -5
- package/dist/types/components/IDE/selectors.content.d.ts +7 -7
- package/dist/types/components/Input/Checkbox.d.ts +3 -3
- package/dist/types/components/Input/Checkbox.d.ts.map +1 -1
- package/dist/types/components/Input/Input.d.ts +5 -8
- 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 +8 -7
- package/dist/types/components/Link/Link.d.ts.map +1 -1
- package/dist/types/components/Link/index.d.ts +2 -2
- 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/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/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/DesktopNavbar.d.ts.map +1 -1
- 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/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/Select/Select.d.ts +3 -3
- package/dist/types/components/Select/Select.d.ts.map +1 -1
- package/dist/types/components/SocialNetworks/index.d.ts +2 -2
- package/dist/types/components/SwitchSelector/index.d.ts +6 -6
- package/dist/types/components/Tab/Tab.d.ts +6 -6
- package/dist/types/components/Tab/Tab.d.ts.map +1 -1
- package/dist/types/components/Tab/TabContext.d.ts +2 -2
- package/dist/types/components/Tab/TabContext.d.ts.map +1 -1
- 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/Tag/index.d.ts +3 -3
- package/dist/types/components/Terminal/terminal.content.d.ts +5 -5
- package/dist/types/components/Toaster/Toast.d.ts +1 -1
- package/dist/types/components/Toaster/Toast.d.ts.map +1 -1
- package/dist/types/components/index.d.ts +6 -3
- package/dist/types/hooks/index.d.ts +2 -2
- package/dist/types/hooks/reactQuery.d.ts +2 -1
- package/dist/types/hooks/reactQuery.d.ts.map +1 -1
- package/package.json +14 -14
- package/dist/types/components/Browser/Browser.content.d.ts.map +0 -1
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
4
|
import { Button, ButtonColor, ButtonVariant } from "../Button/Button.mjs";
|
|
5
5
|
import { MaxHeightSmoother } from "../MaxHeightSmoother/index.mjs";
|
|
6
|
-
import { useId, useState } from "react";
|
|
7
6
|
import { ChevronDown } from "lucide-react";
|
|
7
|
+
import { useId, useState } from "react";
|
|
8
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
|
|
10
10
|
//#region src/components/Accordion/Accordion.tsx
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cn } from "../../utils/cn.mjs";
|
|
2
2
|
import { Loader } from "../Loader/index.mjs";
|
|
3
|
-
import { useMemo } from "react";
|
|
4
3
|
import { User } from "lucide-react";
|
|
4
|
+
import { useMemo } from "react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
|
|
7
7
|
//#region src/components/Avatar/index.tsx
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
4
|
import { Button, ButtonVariant } from "../Button/Button.mjs";
|
|
5
5
|
import { Link, LinkColor } from "../Link/Link.mjs";
|
|
6
|
-
import { Fragment, createElement } from "react";
|
|
7
6
|
import { ChevronRightIcon } from "lucide-react";
|
|
7
|
+
import { Fragment, createElement } from "react";
|
|
8
8
|
import { cva } from "class-variance-authority";
|
|
9
9
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
import { getIntlayer } from "@intlayer/core";
|
|
@@ -12,6 +12,25 @@ import { useIntlayer } from "react-intlayer";
|
|
|
12
12
|
|
|
13
13
|
//#region src/components/Breadcrumb/index.tsx
|
|
14
14
|
/**
|
|
15
|
+
* Maps LinkColor to corresponding Tailwind text color classes
|
|
16
|
+
*/
|
|
17
|
+
const getColorClass = (color) => {
|
|
18
|
+
if (!color) return "";
|
|
19
|
+
return {
|
|
20
|
+
[LinkColor.PRIMARY]: "text-primary",
|
|
21
|
+
[LinkColor.SECONDARY]: "text-secondary",
|
|
22
|
+
[LinkColor.DESTRUCTIVE]: "text-destructive",
|
|
23
|
+
[LinkColor.NEUTRAL]: "text-neutral",
|
|
24
|
+
[LinkColor.LIGHT]: "text-white",
|
|
25
|
+
[LinkColor.DARK]: "text-neutral-800",
|
|
26
|
+
[LinkColor.TEXT]: "text-text",
|
|
27
|
+
[LinkColor.TEXT_INVERSE]: "text-text-opposite",
|
|
28
|
+
[LinkColor.ERROR]: "text-error",
|
|
29
|
+
[LinkColor.SUCCESS]: "text-success",
|
|
30
|
+
[LinkColor.CUSTOM]: ""
|
|
31
|
+
}[color] || "";
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
15
34
|
* Breadcrumb variant styles using class-variance-authority
|
|
16
35
|
*/
|
|
17
36
|
const breadcrumbVariants = cva("flex flex-row flex-wrap items-center text-sm", {
|
|
@@ -147,6 +166,7 @@ const Breadcrumb = ({ links, className, color = LinkColor.TEXT, locale, elementT
|
|
|
147
166
|
const ariaCurrent = isActive ? elementType : void 0;
|
|
148
167
|
const isTruncated = link === "...";
|
|
149
168
|
const text = link.text ?? link;
|
|
169
|
+
const separatorColorClass = getColorClass(color);
|
|
150
170
|
if (isTruncated) return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("li", {
|
|
151
171
|
className: "flex items-center",
|
|
152
172
|
"aria-hidden": "true",
|
|
@@ -157,7 +177,10 @@ const Breadcrumb = ({ links, className, color = LinkColor.TEXT, locale, elementT
|
|
|
157
177
|
}), !isLastLink && /* @__PURE__ */ jsx("li", {
|
|
158
178
|
"aria-hidden": "true",
|
|
159
179
|
className: "flex items-center",
|
|
160
|
-
children:
|
|
180
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
181
|
+
className: cn(separatorColorClass),
|
|
182
|
+
children: separator
|
|
183
|
+
})
|
|
161
184
|
})] }, `truncated-${text}`);
|
|
162
185
|
let section = /* @__PURE__ */ jsx(Span, {
|
|
163
186
|
position: index + 1,
|
|
@@ -195,7 +218,10 @@ const Breadcrumb = ({ links, className, color = LinkColor.TEXT, locale, elementT
|
|
|
195
218
|
return /* @__PURE__ */ jsxs(Fragment, { children: [listElement, /* @__PURE__ */ jsx("li", {
|
|
196
219
|
"aria-hidden": "true",
|
|
197
220
|
className: "flex items-center",
|
|
198
|
-
children:
|
|
221
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
222
|
+
className: cn(separatorColorClass),
|
|
223
|
+
children: separator
|
|
224
|
+
})
|
|
199
225
|
})] }, text);
|
|
200
226
|
})
|
|
201
227
|
})
|
|
@@ -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 { 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 size=\"sm\"\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 { 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 * Maps LinkColor to corresponding Tailwind text color classes\n */\nconst getColorClass = (color?: LinkColor | `${LinkColor}`): string => {\n if (!color) return '';\n\n const colorMap: Record<LinkColor, string> = {\n [LinkColor.PRIMARY]: 'text-primary',\n [LinkColor.SECONDARY]: 'text-secondary',\n [LinkColor.DESTRUCTIVE]: 'text-destructive',\n [LinkColor.NEUTRAL]: 'text-neutral',\n [LinkColor.LIGHT]: 'text-white',\n [LinkColor.DARK]: 'text-neutral-800',\n [LinkColor.TEXT]: 'text-text',\n [LinkColor.TEXT_INVERSE]: 'text-text-opposite',\n [LinkColor.ERROR]: 'text-error',\n [LinkColor.SUCCESS]: 'text-success',\n [LinkColor.CUSTOM]: '',\n };\n\n return colorMap[color as LinkColor] || '';\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 size=\"sm\"\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 const separatorColorClass = getColorClass(color);\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 <span className={cn(separatorColorClass)}>{separator}</span>\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 <span className={cn(separatorColorClass)}>{separator}</span>\n </li>\n </Fragment>\n );\n })}\n </ol>\n </nav>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAoDA,MAAM,iBAAiB,UAA+C;AACpE,KAAI,CAAC,MAAO,QAAO;AAgBnB,QAd4C;GACzC,UAAU,UAAU;GACpB,UAAU,YAAY;GACtB,UAAU,cAAc;GACxB,UAAU,UAAU;GACpB,UAAU,QAAQ;GAClB,UAAU,OAAO;GACjB,UAAU,OAAO;GACjB,UAAU,eAAe;GACzB,UAAU,QAAQ;GAClB,UAAU,UAAU;GACpB,UAAU,SAAS;EACrB,CAEe,UAAuB;;;;;AAMzC,MAAM,qBAAqB,IAAI,gDAAgD;CAC7E,UAAU;EACR,MAAM;GACJ,OAAO;GACP,QAAQ;GACR,OAAO;GACR;EACD,SAAS;GACP,SAAS;GACT,QAAQ;GACR,OAAO;GACR;EACF;CACD,iBAAiB;EACf,MAAM;EACN,SAAS;EACV;CACF,CAAC;;;;AAKF,MAAMA,YAA+B,EACnC,MACA,MACA,UACA,SACA,OACA,UACA,QACA,WACA,GAAG,YACC;CAEJ,MAAM,YADU,YAAY,aAAa,CACf;AAE1B,QACE,8CACE,oBAAC;EACO;EACE;EACD;EACE;EACT,UAAS;EACT,gBAAgB;EAChB;EACA,UAAS;EACT,GAAI;EACJ,OAAO,GAAG,UAAU,GAAG;EACvB,QAAQ;EACR,MAAK;YAEL,oBAAC;GAAK,UAAS;GAAQ;IAAgB;GAClC,EACP,oBAAC;EAAK,UAAS;EAAW,SAAS,SAAS,UAAU;GAAI,IACzD;;;;;AAqBP,MAAMC,cAAqC,EACzC,UAAU,MACV,SACA,OACA,UACA,WACA,GAAG,YACC;CACJ,MAAM,EAAE,cAAc,YAAY,aAAa;AAE/C,QACE,8CACE,oBAAC;EACU;EACT,SAAS,cAAc;EACvB,OAAO,GAAG,UAAU,GAAG;EAChB;EACP,UAAS;EACT,GAAI;YAEJ,oBAAC;GAAK,UAAS;aAAQ;IAAY;GAC5B,EACT,oBAAC;EAAK,UAAS;EAAW,SAAS,SAAS,UAAU;GAAI,IACzD;;;;;AAqBP,MAAMC,QAAuB,EAAE,UAAU,UAAU,WAAW,GAAG,YAC/D,qBAAC;CACC,UAAS;CACT,WAAW,GACT,4BACA,gCACA,kCACA,UACD;YAED,oBAAC;EAAK,UAAS;EAAO,GAAI;EACvB;GACI,EACP,oBAAC;EAAK,UAAS;EAAW,SAAS,SAAS,UAAU;GAAI;EACrD;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+FT,MAAaC,cAAmC,EAC9C,OACA,WACA,QAAQ,UAAU,MAClB,QACA,cAAc,QACd,YAAY,oBAAC,oBAAiB,MAAM,KAAM,EAC1C,YAAY,cACZ,wBAAwB,MACxB,UACA,MACA,SACA,GAAG,YACC;CACJ,MAAM,eACJ,YAAY,MAAM,SAAS,WACvB;EAAC,GAAG,MAAM,MAAM,GAAG,EAAE;EAAE;EAAO,GAAG,MAAM,MAAM,EAAE,WAAW,GAAG;EAAC,GAC9D;AAEN,QACE,oBAAC;EAAI,cAAY;YACf,oBAAC;GACC,WAAW,GAAG,mBAAmB;IAAE;IAAM;IAAS,CAAC,EAAE,UAAU;GAC/D,GAAK,yBAAyB;IAC5B,WAAW;IACX,UAAU;IACX;GACD,GAAI;aAEH,aAAa,KAAK,MAAM,UAAU;IACjC,MAAM,aAAa,UAAU,aAAa,SAAS;IACnD,MAAM,SACJ,OAAO,SAAS,YAAY,OAAO,KAAK,SAAS;IACnD,MAAM,WACJ,OAAO,SAAS,YAAY,OAAO,KAAK,YAAY;IACtD,MAAM,WAAW,UAAU,aAAa,SAAS;IACjD,MAAM,cAAc,WAAW,cAAc;IAC7C,MAAM,cAAc,SAAS;IAE7B,MAAM,OAAQ,KAAgC,QAAQ;IAEtD,MAAM,sBAAsB,cAAc,MAAM;AAEhD,QAAI,YACF,QACE,qBAAC,uBACC,oBAAC;KAAG,WAAU;KAAoB,eAAY;eAC5C,oBAAC;MAAK,WAAU;gBAAmB;OAAQ;MACxC,EACJ,CAAC,cACA,oBAAC;KAAG,eAAY;KAAO,WAAU;eAC/B,oBAAC;MAAK,WAAW,GAAG,oBAAoB;gBAAG;OAAiB;MACzD,KAPM,aAAa,OASjB;IAIf,IAAI,UACF,oBAAC;KAEC,UAAU,QAAQ;KAClB,gBAAc;KACd,WAAW,GACT,kCACA,YAAY,mBACb;eAEA;OARI,KASA;AAGT,QAAI,OACF,WACE,oBAAC;KAEC,MAAM,KAAK;KACJ;KACP,UAAU,QAAQ;KACV;KACR,gBAAc;KACd,WAAW,GAAG,YAAY,kCAAkC;eAE3D;OARI,KASI;aAEJ,SACT,WACE,oBAAC;KAEC,SAAS,KAAK;KACP;KACP,UAAU,QAAQ;KAClB,gBAAc;KACd,WAAW,GAAG,YAAY,kCAAkC;eAE3D;OAPI,KAQM;IAIjB,MAAM,cACJ,8BAAC;KACC,GAAK,yBAAyB;MAC5B,UAAU;MACV,WAAW;MACX,UAAU;MACX;KACD,KAAK;KACL,WAAU;OAET,QACE;AAGP,QAAI,WACF,QAAO;AAGT,WACE,qBAAC,uBACE,aACD,oBAAC;KAAG,eAAY;KAAO,WAAU;eAC/B,oBAAC;MAAK,WAAW,GAAG,oBAAoB;gBAAG;OAAiB;MACzD,KAJQ,KAKJ;KAEb;IACC;GACD"}
|
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { cn } from "../../utils/cn.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { Button } from "../Button/Button.mjs";
|
|
5
|
+
import { Input, inputVariants } from "../Input/Input.mjs";
|
|
5
6
|
import { ArrowLeft, ArrowRight, RotateCw } from "lucide-react";
|
|
6
|
-
import {
|
|
7
|
+
import { useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
7
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
9
|
import { useIntlayer } from "react-intlayer";
|
|
9
10
|
|
|
10
11
|
//#region src/components/Browser/Browser.tsx
|
|
11
|
-
const browserVariants = cva("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)]", {
|
|
12
|
-
variants: { size: {
|
|
13
|
-
xs: "h-[400px]",
|
|
14
|
-
sm: "h-[500px]",
|
|
15
|
-
md: "h-[600px]",
|
|
16
|
-
lg: "h-[800px]",
|
|
17
|
-
xl: "h-[1000px]"
|
|
18
|
-
} },
|
|
19
|
-
defaultVariants: { size: "md" }
|
|
20
|
-
});
|
|
21
12
|
const Browser = ({ initialUrl = "https://example.com", path, className, style, size = "md", "aria-label": ariaLabel, sandbox = "allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads", ref, domainRestriction, ...props }) => {
|
|
22
13
|
const [inputUrl, setInputUrl] = useState(initialUrl);
|
|
23
14
|
const [currentUrl, setCurrentUrl] = useState(initialUrl);
|
|
@@ -47,8 +38,7 @@ const Browser = ({ initialUrl = "https://example.com", path, className, style, s
|
|
|
47
38
|
const currentIframeHref = internalIframeRef.current.contentWindow.location.href;
|
|
48
39
|
if (new URL(currentIframeHref).href === new URL(fullUrl).href) isAlreadyAtUrl = true;
|
|
49
40
|
} catch {}
|
|
50
|
-
if (
|
|
51
|
-
setCurrentUrl(fullUrl);
|
|
41
|
+
if (history[currentIndex] !== fullUrl) {
|
|
52
42
|
setHistory((prev) => {
|
|
53
43
|
const newHistory = prev.slice(0, currentIndex + 1);
|
|
54
44
|
newHistory.push(fullUrl);
|
|
@@ -56,6 +46,7 @@ const Browser = ({ initialUrl = "https://example.com", path, className, style, s
|
|
|
56
46
|
});
|
|
57
47
|
setCurrentIndex((prev) => prev + 1);
|
|
58
48
|
}
|
|
49
|
+
if (!isAlreadyAtUrl) setCurrentUrl(fullUrl);
|
|
59
50
|
setError(null);
|
|
60
51
|
} catch {}
|
|
61
52
|
}, [
|
|
@@ -155,48 +146,51 @@ const Browser = ({ initialUrl = "https://example.com", path, className, style, s
|
|
|
155
146
|
const canGoBack = currentIndex > 0;
|
|
156
147
|
const canGoForward = currentIndex < history.length - 1;
|
|
157
148
|
return /* @__PURE__ */ jsxs("section", {
|
|
158
|
-
className: cn(
|
|
149
|
+
className: cn("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)]", className),
|
|
159
150
|
style,
|
|
160
151
|
"aria-label": ariaLabel ?? content.ariaLabel.value,
|
|
161
152
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
162
|
-
className: "relative z-10 flex shrink-0 items-center gap-3 rounded-t-xl bg-
|
|
153
|
+
className: "relative z-10 flex shrink-0 items-center gap-3 rounded-t-xl bg-text/15 px-4 py-2",
|
|
163
154
|
children: [
|
|
164
155
|
/* @__PURE__ */ jsxs("div", {
|
|
165
156
|
className: "flex items-center gap-1",
|
|
166
|
-
children: [/* @__PURE__ */ jsx(
|
|
157
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
167
158
|
type: "button",
|
|
168
159
|
onClick: handleBack,
|
|
169
160
|
disabled: !canGoBack,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}), /* @__PURE__ */ jsx(
|
|
161
|
+
variant: "hoverable",
|
|
162
|
+
size: "icon-md",
|
|
163
|
+
label: content.backButtonLabel.value,
|
|
164
|
+
Icon: ArrowLeft
|
|
165
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
175
166
|
type: "button",
|
|
176
167
|
onClick: handleForward,
|
|
177
168
|
disabled: !canGoForward,
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
169
|
+
variant: "hoverable",
|
|
170
|
+
size: "icon-md",
|
|
171
|
+
label: content.forwardButtonLabel.value,
|
|
172
|
+
Icon: ArrowRight
|
|
182
173
|
})]
|
|
183
174
|
}),
|
|
184
175
|
/* @__PURE__ */ jsxs("form", {
|
|
185
176
|
onSubmit: handleSubmit,
|
|
186
|
-
className: "relative flex-1",
|
|
187
177
|
noValidate: true,
|
|
178
|
+
className: cn(inputVariants(), "flex w-full gap-2 rounded-xl p-0.5! supports-[corner-shape:squircle]:rounded-2xl", "bg-neutral/10 text-text/50 placeholder:text-neutral/80"),
|
|
188
179
|
children: [
|
|
189
180
|
/* @__PURE__ */ jsx("label", {
|
|
190
181
|
htmlFor: "browser-url",
|
|
191
182
|
className: "sr-only",
|
|
192
183
|
children: content.urlLabel.value
|
|
193
184
|
}),
|
|
194
|
-
/* @__PURE__ */ jsx(
|
|
185
|
+
/* @__PURE__ */ jsx(Input, {
|
|
195
186
|
id: "browser-url",
|
|
196
187
|
type: "text",
|
|
197
188
|
inputMode: "url",
|
|
198
189
|
spellCheck: false,
|
|
199
190
|
autoCapitalize: "off",
|
|
191
|
+
variant: "invisible",
|
|
192
|
+
className: "ml-3 p-0!",
|
|
193
|
+
size: "sm",
|
|
200
194
|
autoCorrect: "off",
|
|
201
195
|
value: inputUrl,
|
|
202
196
|
onChange: (e) => {
|
|
@@ -204,23 +198,18 @@ const Browser = ({ initialUrl = "https://example.com", path, className, style, s
|
|
|
204
198
|
if (showError) setError(null);
|
|
205
199
|
},
|
|
206
200
|
placeholder: content.urlPlaceholder.value,
|
|
207
|
-
className: cn("w-full rounded-lg px-4 py-2 pr-11 text-sm leading-[1.4]", "bg-neutral-950 text-neutral-300", "placeholder:text-neutral-400", "transition-all focus:outline-none focus:ring-1 focus:ring-neutral-400/30", showError ? "border border-red-500" : "border border-transparent"),
|
|
208
201
|
"aria-label": content.urlLabel.value,
|
|
209
202
|
"aria-invalid": showError,
|
|
210
203
|
"aria-describedby": showError ? "browser-url-error" : void 0
|
|
211
204
|
}),
|
|
212
|
-
/* @__PURE__ */ jsx(
|
|
205
|
+
/* @__PURE__ */ jsx(Button, {
|
|
213
206
|
type: "button",
|
|
214
207
|
onClick: handleReload,
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
"
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
size: 18,
|
|
221
|
-
className: "text-neutral-400",
|
|
222
|
-
strokeWidth: 2
|
|
223
|
-
})
|
|
208
|
+
variant: "hoverable",
|
|
209
|
+
size: "icon-md",
|
|
210
|
+
className: "p-1!",
|
|
211
|
+
label: "content.reloadButtonTitle.value",
|
|
212
|
+
Icon: RotateCw
|
|
224
213
|
}),
|
|
225
214
|
/* @__PURE__ */ jsx("button", {
|
|
226
215
|
type: "submit",
|
|
@@ -241,12 +230,12 @@ const Browser = ({ initialUrl = "https://example.com", path, className, style, s
|
|
|
241
230
|
})
|
|
242
231
|
]
|
|
243
232
|
}), /* @__PURE__ */ jsx("div", {
|
|
244
|
-
className: "relative z-0 min-h-0 w-full flex-1 overflow-hidden rounded-b-xl bg-background",
|
|
233
|
+
className: "relative z-0 flex min-h-0 w-full flex-1 flex-col overflow-hidden rounded-b-xl bg-background",
|
|
245
234
|
children: /* @__PURE__ */ jsx("iframe", {
|
|
246
235
|
ref: internalIframeRef,
|
|
247
236
|
src: currentUrl,
|
|
248
237
|
title: content.iframeTitle.value,
|
|
249
|
-
className: "
|
|
238
|
+
className: "size-full flex-1",
|
|
250
239
|
sandbox,
|
|
251
240
|
loading: "lazy",
|
|
252
241
|
"aria-live": "polite",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Browser.mjs","names":[],"sources":["../../../../src/components/Browser/Browser.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { ArrowLeft, ArrowRight, RotateCw } from 'lucide-react';\nimport {\n type CSSProperties,\n type FormEvent,\n type HTMLAttributes,\n type RefObject,\n useEffect,\n useImperativeHandle,\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 initialUrl?: string;\n path?: string;\n className?: string;\n style?: CSSProperties;\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n 'aria-label'?: string;\n sandbox?: string;\n ref?: RefObject<HTMLIFrameElement | null>;\n domainRestriction?: string;\n} & HTMLAttributes<HTMLIFrameElement>;\n\nexport const Browser = ({\n initialUrl = 'https://example.com',\n path,\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 ref,\n domainRestriction,\n ...props\n}: BrowserProps) => {\n // --- State -----------------------------------------------------------------\n const [inputUrl, setInputUrl] = useState(initialUrl);\n const [currentUrl, setCurrentUrl] = useState(initialUrl);\n\n // History Management\n const [history, setHistory] = useState<string[]>([initialUrl]);\n const [currentIndex, setCurrentIndex] = useState(0);\n\n const [error, setError] = useState<string | null>(null);\n const [submitted, setSubmitted] = useState(false);\n const internalIframeRef = useRef<HTMLIFrameElement>(null);\n\n useImperativeHandle(ref, () => internalIframeRef.current!, []);\n const content = useIntlayer('browser');\n\n // --- Effects ---------------------------------------------------------------\n\n // Reset everything if initialUrl changes completely\n useEffect(() => {\n setInputUrl(initialUrl);\n setCurrentUrl(initialUrl);\n setHistory([initialUrl]);\n setCurrentIndex(0);\n setError(null);\n setSubmitted(false);\n }, [initialUrl]);\n\n // Sync external path changes with the URL bar and History\n useEffect(() => {\n if (!path) return;\n\n try {\n const baseOrigin = domainRestriction ?? initialUrl;\n const origin = new URL(baseOrigin).origin;\n const fullUrl = `${origin}${path}`;\n\n // 1. Update Input\n setInputUrl(fullUrl);\n\n // 2. Check internal iframe state to avoid reload if already there\n let isAlreadyAtUrl = false;\n if (internalIframeRef.current?.contentWindow) {\n try {\n const currentIframeHref =\n internalIframeRef.current.contentWindow.location.href;\n if (new URL(currentIframeHref).href === new URL(fullUrl).href) {\n isAlreadyAtUrl = true;\n }\n } catch {\n // Cross-origin access ignored\n }\n }\n\n // 3. Navigate if needed (Push to history)\n if (!isAlreadyAtUrl) {\n // If the path prop forces a change, we treat it as a new navigation\n setCurrentUrl(fullUrl);\n\n // Update History Stack\n setHistory((prev) => {\n const newHistory = prev.slice(0, currentIndex + 1);\n newHistory.push(fullUrl);\n return newHistory;\n });\n setCurrentIndex((prev) => prev + 1);\n }\n\n setError(null);\n } catch {\n // Ignore invalid paths\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [path, domainRestriction, initialUrl]); // Removed currentIndex dependency to prevent loops\n\n // --- Navigation Logic ------------------------------------------------------\n\n const handleNavigateTo = (url: string) => {\n try {\n const validated = normalizeUrl(url);\n\n // If we are navigating to the exact same URL, just reload\n if (validated === currentUrl) {\n handleReload();\n return;\n }\n\n setCurrentUrl(validated);\n setInputUrl(validated);\n setError(null);\n\n // Update History: Slice future if we went back, then push new\n const newHistory = history.slice(0, currentIndex + 1);\n newHistory.push(validated);\n setHistory(newHistory);\n setCurrentIndex(newHistory.length - 1);\n } catch (e) {\n if (\n e instanceof Error &&\n e.message === 'URL does not match allowed domain' &&\n domainRestriction\n ) {\n setError(\n content.domainRestrictionError?.value ??\n `Only URLs from ${domainRestriction} are allowed.`\n );\n } else {\n setError(content.errorMessage.value);\n }\n }\n };\n\n const handleBack = () => {\n if (currentIndex > 0) {\n const newIndex = currentIndex - 1;\n const prevUrl = history[newIndex];\n setCurrentIndex(newIndex);\n setCurrentUrl(prevUrl);\n setInputUrl(prevUrl);\n setError(null);\n }\n };\n\n const handleForward = () => {\n if (currentIndex < history.length - 1) {\n const newIndex = currentIndex + 1;\n const nextUrl = history[newIndex];\n setCurrentIndex(newIndex);\n setCurrentUrl(nextUrl);\n setInputUrl(nextUrl);\n setError(null);\n }\n };\n\n const handleSubmit = (e: FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n setSubmitted(true);\n handleNavigateTo(inputUrl);\n };\n\n const handleReload = () => {\n if (internalIframeRef.current) {\n // Create a clean reload effect\n const src = internalIframeRef.current.src;\n internalIframeRef.current.src = '';\n setTimeout(() => {\n if (internalIframeRef.current) internalIframeRef.current.src = src;\n }, 50);\n }\n };\n\n // --- Validation Helpers ----------------------------------------------------\n const isValidHostname = (host: string) => {\n if (host === 'localhost') return true;\n if (/^(\\d{1,3}\\.){3}\\d{1,3}$/.test(host)) return true;\n if (/^[a-f0-9:]+$/i.test(host)) return true;\n if (!/^[a-z0-9.-]+$/i.test(host)) return false;\n if (/^[-.]/.test(host) || /[-.]$/.test(host)) return false;\n if (host.includes('..')) return false;\n if (!host.includes('.')) return false;\n return true;\n };\n\n const getRestrictionOrigin = (): URL | null => {\n if (!domainRestriction) return null;\n try {\n return new URL(domainRestriction);\n } catch {\n return null;\n }\n };\n\n const normalizeUrl = (raw: string) => {\n const trimmed = raw.trim();\n if (!trimmed || /\\s/.test(trimmed)) throw new Error('Invalid');\n\n const restrictionOrigin = getRestrictionOrigin();\n const isRelativePath = trimmed.startsWith('/') && !trimmed.startsWith('//');\n\n if (isRelativePath) {\n if (restrictionOrigin) {\n return new URL(`${restrictionOrigin.origin}${trimmed}`).toString();\n }\n return new URL(`${new URL(currentUrl).origin}${trimmed}`).toString();\n }\n\n const hasProtocol = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed);\n const candidate = hasProtocol ? trimmed : `https://${trimmed}`;\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)) throw new Error('Invalid host');\n\n if (restrictionOrigin) {\n const urlMatches =\n url.hostname === restrictionOrigin.hostname &&\n url.protocol === restrictionOrigin.protocol &&\n (restrictionOrigin.port === '' ||\n url.port === restrictionOrigin.port ||\n url.host === restrictionOrigin.host);\n\n if (!urlMatches) throw new Error('URL does not match allowed domain');\n }\n\n return url.toString();\n };\n\n const showError = submitted && !!error;\n const canGoBack = currentIndex > 0;\n const canGoForward = currentIndex < history.length - 1;\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 items-center gap-3 rounded-t-xl bg-neutral-900 px-4 py-2.5\">\n {/* Navigation Controls */}\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={handleBack}\n disabled={!canGoBack}\n className={cn(\n 'flex h-8 w-8 items-center justify-center rounded-md text-neutral-400 transition-colors',\n canGoBack\n ? 'hover:bg-neutral-800 hover:text-neutral-200'\n : 'cursor-not-allowed opacity-40'\n )}\n aria-label=\"Go back\"\n title=\"Go back\"\n >\n <ArrowLeft size={18} />\n </button>\n\n <button\n type=\"button\"\n onClick={handleForward}\n disabled={!canGoForward}\n className={cn(\n 'flex h-8 w-8 items-center justify-center rounded-md text-neutral-400 transition-colors',\n canGoForward\n ? 'hover:bg-neutral-800 hover:text-neutral-200'\n : 'cursor-not-allowed opacity-40'\n )}\n aria-label=\"Go forward\"\n title=\"Go forward\"\n >\n <ArrowRight size={18} />\n </button>\n </div>\n\n {/* URL Bar */}\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 {/* Reload Button */}\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 */}\n <button type=\"submit\" className=\"sr-only absolute\" tabIndex={-1} />\n </form>\n\n {/* Error Message Tooltip */}\n {showError && (\n <div className=\"absolute top-full left-4 z-20 mt-1\">\n <p\n id=\"browser-url-error\"\n role=\"alert\"\n aria-live=\"assertive\"\n className=\"rounded-md bg-red-900/90 px-3 py-1.5 text-red-100 text-xs shadow-md backdrop-blur-sm\"\n >\n {error}\n </p>\n </div>\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={internalIframeRef}\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 {...props}\n />\n </div>\n </section>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Browser.mjs","names":[],"sources":["../../../../src/components/Browser/Browser.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { ArrowLeft, ArrowRight, RotateCw } from 'lucide-react';\nimport {\n type CSSProperties,\n type FormEvent,\n type HTMLAttributes,\n type RefObject,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { cn } from '../../utils/cn';\nimport { Button } from '../Button';\nimport { Input, inputVariants } from '../Input';\n\nexport type BrowserProps = {\n initialUrl?: string;\n path?: string;\n className?: string;\n style?: CSSProperties;\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n 'aria-label'?: string;\n sandbox?: string;\n ref?: RefObject<HTMLIFrameElement | null>;\n domainRestriction?: string;\n} & HTMLAttributes<HTMLIFrameElement>;\n\nexport const Browser = ({\n initialUrl = 'https://example.com',\n path,\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 ref,\n domainRestriction,\n ...props\n}: BrowserProps) => {\n // --- State -----------------------------------------------------------------\n const [inputUrl, setInputUrl] = useState(initialUrl);\n const [currentUrl, setCurrentUrl] = useState(initialUrl);\n\n // History Management\n const [history, setHistory] = useState<string[]>([initialUrl]);\n const [currentIndex, setCurrentIndex] = useState(0);\n\n const [error, setError] = useState<string | null>(null);\n const [submitted, setSubmitted] = useState(false);\n const internalIframeRef = useRef<HTMLIFrameElement>(null);\n\n useImperativeHandle(ref, () => internalIframeRef.current!, []);\n const content = useIntlayer('browser');\n\n // --- Effects ---------------------------------------------------------------\n\n // Reset everything if initialUrl changes completely\n useEffect(() => {\n setInputUrl(initialUrl);\n setCurrentUrl(initialUrl);\n setHistory([initialUrl]);\n setCurrentIndex(0);\n setError(null);\n setSubmitted(false);\n }, [initialUrl]);\n\n // Sync external path changes with the URL bar and History\n useEffect(() => {\n if (!path) return;\n\n try {\n const baseOrigin = domainRestriction ?? initialUrl;\n const origin = new URL(baseOrigin).origin;\n const fullUrl = `${origin}${path}`;\n\n // Update Input (Always update the visual bar)\n setInputUrl(fullUrl);\n\n // Check internal iframe state to avoid reload if already there\n let isAlreadyAtUrl = false;\n if (internalIframeRef.current?.contentWindow) {\n try {\n const currentIframeHref =\n internalIframeRef.current.contentWindow.location.href;\n if (new URL(currentIframeHref).href === new URL(fullUrl).href) {\n isAlreadyAtUrl = true;\n }\n } catch {\n // Cross-origin access ignored\n }\n }\n\n // Update History Stack\n // We perform this check regardless of `isAlreadyAtUrl`.\n // If the path changed (even internally), we want to record it in the arrow stack.\n if (history[currentIndex] !== fullUrl) {\n setHistory((prev) => {\n const newHistory = prev.slice(0, currentIndex + 1);\n newHistory.push(fullUrl);\n return newHistory;\n });\n setCurrentIndex((prev) => prev + 1);\n }\n\n // Navigate (Update src) only if NOT already there\n // This prevents the iframe from refreshing when the user navigated inside it.\n if (!isAlreadyAtUrl) {\n setCurrentUrl(fullUrl);\n }\n\n setError(null);\n } catch {\n // Ignore invalid paths\n }\n }, [path, domainRestriction, initialUrl]); // Removed currentIndex dependency to prevent loops\n\n // --- Navigation Logic ------------------------------------------------------\n\n const handleNavigateTo = (url: string) => {\n try {\n const validated = normalizeUrl(url);\n\n // If we are navigating to the exact same URL, just reload\n if (validated === currentUrl) {\n handleReload();\n return;\n }\n\n setCurrentUrl(validated);\n setInputUrl(validated);\n setError(null);\n\n // Update History: Slice future if we went back, then push new\n const newHistory = history.slice(0, currentIndex + 1);\n newHistory.push(validated);\n setHistory(newHistory);\n setCurrentIndex(newHistory.length - 1);\n } catch (e) {\n if (\n e instanceof Error &&\n e.message === 'URL does not match allowed domain' &&\n domainRestriction\n ) {\n setError(\n content.domainRestrictionError?.value ??\n `Only URLs from ${domainRestriction} are allowed.`\n );\n } else {\n setError(content.errorMessage.value);\n }\n }\n };\n\n const handleBack = () => {\n if (currentIndex > 0) {\n const newIndex = currentIndex - 1;\n const prevUrl = history[newIndex];\n setCurrentIndex(newIndex);\n setCurrentUrl(prevUrl);\n setInputUrl(prevUrl);\n setError(null);\n }\n };\n\n const handleForward = () => {\n if (currentIndex < history.length - 1) {\n const newIndex = currentIndex + 1;\n const nextUrl = history[newIndex];\n setCurrentIndex(newIndex);\n setCurrentUrl(nextUrl);\n setInputUrl(nextUrl);\n setError(null);\n }\n };\n\n const handleSubmit = (e: FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n setSubmitted(true);\n handleNavigateTo(inputUrl);\n };\n\n const handleReload = () => {\n if (internalIframeRef.current) {\n // Create a clean reload effect\n const src = internalIframeRef.current.src;\n internalIframeRef.current.src = '';\n setTimeout(() => {\n if (internalIframeRef.current) internalIframeRef.current.src = src;\n }, 50);\n }\n };\n\n // --- Validation Helpers ----------------------------------------------------\n const isValidHostname = (host: string) => {\n if (host === 'localhost') return true;\n if (/^(\\d{1,3}\\.){3}\\d{1,3}$/.test(host)) return true;\n if (/^[a-f0-9:]+$/i.test(host)) return true;\n if (!/^[a-z0-9.-]+$/i.test(host)) return false;\n if (/^[-.]/.test(host) || /[-.]$/.test(host)) return false;\n if (host.includes('..')) return false;\n if (!host.includes('.')) return false;\n return true;\n };\n\n const getRestrictionOrigin = (): URL | null => {\n if (!domainRestriction) return null;\n try {\n return new URL(domainRestriction);\n } catch {\n return null;\n }\n };\n\n const normalizeUrl = (raw: string) => {\n const trimmed = raw.trim();\n if (!trimmed || /\\s/.test(trimmed)) throw new Error('Invalid');\n\n const restrictionOrigin = getRestrictionOrigin();\n const isRelativePath = trimmed.startsWith('/') && !trimmed.startsWith('//');\n\n if (isRelativePath) {\n if (restrictionOrigin) {\n return new URL(`${restrictionOrigin.origin}${trimmed}`).toString();\n }\n return new URL(`${new URL(currentUrl).origin}${trimmed}`).toString();\n }\n\n const hasProtocol = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed);\n const candidate = hasProtocol ? trimmed : `https://${trimmed}`;\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)) throw new Error('Invalid host');\n\n if (restrictionOrigin) {\n const urlMatches =\n url.hostname === restrictionOrigin.hostname &&\n url.protocol === restrictionOrigin.protocol &&\n (restrictionOrigin.port === '' ||\n url.port === restrictionOrigin.port ||\n url.host === restrictionOrigin.host);\n\n if (!urlMatches) throw new Error('URL does not match allowed domain');\n }\n\n return url.toString();\n };\n\n const showError = submitted && !!error;\n const canGoBack = currentIndex > 0;\n const canGoForward = currentIndex < history.length - 1;\n\n return (\n <section\n className={cn(\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 className\n )}\n style={style}\n aria-label={ariaLabel ?? content.ariaLabel.value}\n >\n {/* Top bar */}\n <div className=\"relative z-10 flex shrink-0 items-center gap-3 rounded-t-xl bg-text/15 px-4 py-2\">\n {/* Navigation Controls */}\n <div className=\"flex items-center gap-1\">\n <Button\n type=\"button\"\n onClick={handleBack}\n disabled={!canGoBack}\n variant=\"hoverable\"\n size=\"icon-md\"\n label={content.backButtonLabel.value}\n Icon={ArrowLeft}\n />\n <Button\n type=\"button\"\n onClick={handleForward}\n disabled={!canGoForward}\n variant=\"hoverable\"\n size=\"icon-md\"\n label={content.forwardButtonLabel.value}\n Icon={ArrowRight}\n />\n </div>\n\n {/* URL Bar */}\n <form\n onSubmit={handleSubmit}\n noValidate\n className={cn(\n inputVariants(),\n 'flex w-full gap-2 rounded-xl p-0.5! supports-[corner-shape:squircle]:rounded-2xl',\n 'bg-neutral/10 text-text/50 placeholder:text-neutral/80'\n )}\n >\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 variant=\"invisible\"\n className=\"ml-3 p-0!\"\n size=\"sm\"\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 aria-label={content.urlLabel.value}\n aria-invalid={showError}\n aria-describedby={showError ? 'browser-url-error' : undefined}\n />\n\n <Button\n type=\"button\"\n onClick={handleReload}\n variant=\"hoverable\"\n size=\"icon-md\"\n className=\"p-1!\"\n label={'content.reloadButtonTitle.value'}\n Icon={RotateCw}\n />\n\n {/* invisible submit */}\n <button type=\"submit\" className=\"sr-only absolute\" tabIndex={-1} />\n </form>\n\n {/* Error Message Tooltip */}\n {showError && (\n <div className=\"absolute top-full left-4 z-20 mt-1\">\n <p\n id=\"browser-url-error\"\n role=\"alert\"\n aria-live=\"assertive\"\n className=\"rounded-md bg-red-900/90 px-3 py-1.5 text-red-100 text-xs shadow-md backdrop-blur-sm\"\n >\n {error}\n </p>\n </div>\n )}\n </div>\n\n {/* Iframe */}\n <div className=\"relative z-0 flex min-h-0 w-full flex-1 flex-col overflow-hidden rounded-b-xl bg-background\">\n <iframe\n ref={internalIframeRef}\n src={currentUrl}\n title={content.iframeTitle.value}\n className=\"size-full flex-1\"\n sandbox={sandbox}\n loading=\"lazy\"\n aria-live=\"polite\"\n {...props}\n />\n </div>\n </section>\n );\n};\n"],"mappings":";;;;;;;;;;;AA+BA,MAAa,WAAW,EACtB,aAAa,uBACb,MACA,WACA,OACA,OAAO,MACP,cAAc,WACd,UAAU,2GACV,KACA,mBACA,GAAG,YACe;CAElB,MAAM,CAAC,UAAU,eAAe,SAAS,WAAW;CACpD,MAAM,CAAC,YAAY,iBAAiB,SAAS,WAAW;CAGxD,MAAM,CAAC,SAAS,cAAc,SAAmB,CAAC,WAAW,CAAC;CAC9D,MAAM,CAAC,cAAc,mBAAmB,SAAS,EAAE;CAEnD,MAAM,CAAC,OAAO,YAAY,SAAwB,KAAK;CACvD,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CACjD,MAAM,oBAAoB,OAA0B,KAAK;AAEzD,qBAAoB,WAAW,kBAAkB,SAAU,EAAE,CAAC;CAC9D,MAAM,UAAU,YAAY,UAAU;AAKtC,iBAAgB;AACd,cAAY,WAAW;AACvB,gBAAc,WAAW;AACzB,aAAW,CAAC,WAAW,CAAC;AACxB,kBAAgB,EAAE;AAClB,WAAS,KAAK;AACd,eAAa,MAAM;IAClB,CAAC,WAAW,CAAC;AAGhB,iBAAgB;AACd,MAAI,CAAC,KAAM;AAEX,MAAI;GACF,MAAM,aAAa,qBAAqB;GAExC,MAAM,UAAU,GADD,IAAI,IAAI,WAAW,CAAC,SACP;AAG5B,eAAY,QAAQ;GAGpB,IAAI,iBAAiB;AACrB,OAAI,kBAAkB,SAAS,cAC7B,KAAI;IACF,MAAM,oBACJ,kBAAkB,QAAQ,cAAc,SAAS;AACnD,QAAI,IAAI,IAAI,kBAAkB,CAAC,SAAS,IAAI,IAAI,QAAQ,CAAC,KACvD,kBAAiB;WAEb;AAQV,OAAI,QAAQ,kBAAkB,SAAS;AACrC,gBAAY,SAAS;KACnB,MAAM,aAAa,KAAK,MAAM,GAAG,eAAe,EAAE;AAClD,gBAAW,KAAK,QAAQ;AACxB,YAAO;MACP;AACF,qBAAiB,SAAS,OAAO,EAAE;;AAKrC,OAAI,CAAC,eACH,eAAc,QAAQ;AAGxB,YAAS,KAAK;UACR;IAGP;EAAC;EAAM;EAAmB;EAAW,CAAC;CAIzC,MAAM,oBAAoB,QAAgB;AACxC,MAAI;GACF,MAAM,YAAY,aAAa,IAAI;AAGnC,OAAI,cAAc,YAAY;AAC5B,kBAAc;AACd;;AAGF,iBAAc,UAAU;AACxB,eAAY,UAAU;AACtB,YAAS,KAAK;GAGd,MAAM,aAAa,QAAQ,MAAM,GAAG,eAAe,EAAE;AACrD,cAAW,KAAK,UAAU;AAC1B,cAAW,WAAW;AACtB,mBAAgB,WAAW,SAAS,EAAE;WAC/B,GAAG;AACV,OACE,aAAa,SACb,EAAE,YAAY,uCACd,kBAEA,UACE,QAAQ,wBAAwB,SAC9B,kBAAkB,kBAAkB,eACvC;OAED,UAAS,QAAQ,aAAa,MAAM;;;CAK1C,MAAM,mBAAmB;AACvB,MAAI,eAAe,GAAG;GACpB,MAAM,WAAW,eAAe;GAChC,MAAM,UAAU,QAAQ;AACxB,mBAAgB,SAAS;AACzB,iBAAc,QAAQ;AACtB,eAAY,QAAQ;AACpB,YAAS,KAAK;;;CAIlB,MAAM,sBAAsB;AAC1B,MAAI,eAAe,QAAQ,SAAS,GAAG;GACrC,MAAM,WAAW,eAAe;GAChC,MAAM,UAAU,QAAQ;AACxB,mBAAgB,SAAS;AACzB,iBAAc,QAAQ;AACtB,eAAY,QAAQ;AACpB,YAAS,KAAK;;;CAIlB,MAAM,gBAAgB,MAAkC;AACtD,IAAE,gBAAgB;AAClB,eAAa,KAAK;AAClB,mBAAiB,SAAS;;CAG5B,MAAM,qBAAqB;AACzB,MAAI,kBAAkB,SAAS;GAE7B,MAAM,MAAM,kBAAkB,QAAQ;AACtC,qBAAkB,QAAQ,MAAM;AAChC,oBAAiB;AACf,QAAI,kBAAkB,QAAS,mBAAkB,QAAQ,MAAM;MAC9D,GAAG;;;CAKV,MAAM,mBAAmB,SAAiB;AACxC,MAAI,SAAS,YAAa,QAAO;AACjC,MAAI,0BAA0B,KAAK,KAAK,CAAE,QAAO;AACjD,MAAI,gBAAgB,KAAK,KAAK,CAAE,QAAO;AACvC,MAAI,CAAC,iBAAiB,KAAK,KAAK,CAAE,QAAO;AACzC,MAAI,QAAQ,KAAK,KAAK,IAAI,QAAQ,KAAK,KAAK,CAAE,QAAO;AACrD,MAAI,KAAK,SAAS,KAAK,CAAE,QAAO;AAChC,MAAI,CAAC,KAAK,SAAS,IAAI,CAAE,QAAO;AAChC,SAAO;;CAGT,MAAM,6BAAyC;AAC7C,MAAI,CAAC,kBAAmB,QAAO;AAC/B,MAAI;AACF,UAAO,IAAI,IAAI,kBAAkB;UAC3B;AACN,UAAO;;;CAIX,MAAM,gBAAgB,QAAgB;EACpC,MAAM,UAAU,IAAI,MAAM;AAC1B,MAAI,CAAC,WAAW,KAAK,KAAK,QAAQ,CAAE,OAAM,IAAI,MAAM,UAAU;EAE9D,MAAM,oBAAoB,sBAAsB;AAGhD,MAFuB,QAAQ,WAAW,IAAI,IAAI,CAAC,QAAQ,WAAW,KAAK,EAEvD;AAClB,OAAI,kBACF,QAAO,IAAI,IAAI,GAAG,kBAAkB,SAAS,UAAU,CAAC,UAAU;AAEpE,UAAO,IAAI,IAAI,GAAG,IAAI,IAAI,WAAW,CAAC,SAAS,UAAU,CAAC,UAAU;;EAItE,MAAM,YADc,4BAA4B,KAAK,QAAQ,GAC7B,UAAU,WAAW;EACrD,MAAM,MAAM,IAAI,IAAI,UAAU;AAE9B,MAAI,IAAI,aAAa,WAAW,IAAI,aAAa,SAC/C,OAAM,IAAI,MAAM,0BAA0B;AAG5C,MAAI,CAAC,gBAAgB,IAAI,SAAS,CAAE,OAAM,IAAI,MAAM,eAAe;AAEnE,MAAI,mBAQF;OAAI,EANF,IAAI,aAAa,kBAAkB,YACnC,IAAI,aAAa,kBAAkB,aAClC,kBAAkB,SAAS,MAC1B,IAAI,SAAS,kBAAkB,QAC/B,IAAI,SAAS,kBAAkB,OAElB,OAAM,IAAI,MAAM,oCAAoC;;AAGvE,SAAO,IAAI,UAAU;;CAGvB,MAAM,YAAY,aAAa,CAAC,CAAC;CACjC,MAAM,YAAY,eAAe;CACjC,MAAM,eAAe,eAAe,QAAQ,SAAS;AAErD,QACE,qBAAC;EACC,WAAW,GACT,6HACA,UACD;EACM;EACP,cAAY,aAAa,QAAQ,UAAU;aAG3C,qBAAC;GAAI,WAAU;;IAEb,qBAAC;KAAI,WAAU;gBACb,oBAAC;MACC,MAAK;MACL,SAAS;MACT,UAAU,CAAC;MACX,SAAQ;MACR,MAAK;MACL,OAAO,QAAQ,gBAAgB;MAC/B,MAAM;OACN,EACF,oBAAC;MACC,MAAK;MACL,SAAS;MACT,UAAU,CAAC;MACX,SAAQ;MACR,MAAK;MACL,OAAO,QAAQ,mBAAmB;MAClC,MAAM;OACN;MACE;IAGN,qBAAC;KACC,UAAU;KACV;KACA,WAAW,GACT,eAAe,EACf,oFACA,yDACD;;MAED,oBAAC;OAAM,SAAQ;OAAc,WAAU;iBACpC,QAAQ,SAAS;QACZ;MACR,oBAAC;OACC,IAAG;OACH,MAAK;OACL,WAAU;OACV,YAAY;OACZ,gBAAe;OACf,SAAQ;OACR,WAAU;OACV,MAAK;OACL,aAAY;OACZ,OAAO;OACP,WAAW,MAAM;AACf,oBAAY,EAAE,OAAO,MAAM;AAC3B,YAAI,UAAW,UAAS,KAAK;;OAE/B,aAAa,QAAQ,eAAe;OACpC,cAAY,QAAQ,SAAS;OAC7B,gBAAc;OACd,oBAAkB,YAAY,sBAAsB;QACpD;MAEF,oBAAC;OACC,MAAK;OACL,SAAS;OACT,SAAQ;OACR,MAAK;OACL,WAAU;OACV,OAAO;OACP,MAAM;QACN;MAGF,oBAAC;OAAO,MAAK;OAAS,WAAU;OAAmB,UAAU;QAAM;;MAC9D;IAGN,aACC,oBAAC;KAAI,WAAU;eACb,oBAAC;MACC,IAAG;MACH,MAAK;MACL,aAAU;MACV,WAAU;gBAET;OACC;MACA;;IAEJ,EAGN,oBAAC;GAAI,WAAU;aACb,oBAAC;IACC,KAAK;IACL,KAAK;IACL,OAAO,QAAQ,YAAY;IAC3B,WAAU;IACD;IACT,SAAQ;IACR,aAAU;IACV,GAAI;KACJ;IACE;GACE"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t } from "intlayer";
|
|
2
2
|
|
|
3
|
-
//#region src/components/Browser/
|
|
3
|
+
//#region src/components/Browser/browser.content.ts
|
|
4
4
|
const browserContent = {
|
|
5
5
|
key: "browser",
|
|
6
6
|
content: {
|
|
@@ -81,6 +81,44 @@ const browserContent = {
|
|
|
81
81
|
id: "URL harus cocok dengan domain aplikasi.",
|
|
82
82
|
vi: "URL phải khớp với tên miền ứng dụng."
|
|
83
83
|
}),
|
|
84
|
+
backButtonLabel: t({
|
|
85
|
+
en: "Go back",
|
|
86
|
+
"en-GB": "Go back",
|
|
87
|
+
fr: "Retour",
|
|
88
|
+
es: "Atrás",
|
|
89
|
+
de: "Zurück",
|
|
90
|
+
ja: "戻る",
|
|
91
|
+
ko: "뒤로 가기",
|
|
92
|
+
zh: "后退",
|
|
93
|
+
it: "Indietro",
|
|
94
|
+
pt: "Voltar",
|
|
95
|
+
hi: "वापस जाएं",
|
|
96
|
+
ar: "رجوع",
|
|
97
|
+
ru: "Назад",
|
|
98
|
+
tr: "Geri",
|
|
99
|
+
pl: "Wstecz",
|
|
100
|
+
id: "Kembali",
|
|
101
|
+
vi: "Quay lại"
|
|
102
|
+
}),
|
|
103
|
+
forwardButtonLabel: t({
|
|
104
|
+
en: "Go forward",
|
|
105
|
+
"en-GB": "Go forward",
|
|
106
|
+
fr: "Avancer",
|
|
107
|
+
es: "Adelante",
|
|
108
|
+
de: "Vorwärts",
|
|
109
|
+
ja: "進む",
|
|
110
|
+
ko: "앞으로 가기",
|
|
111
|
+
zh: "前进",
|
|
112
|
+
it: "Avanti",
|
|
113
|
+
pt: "Avançar",
|
|
114
|
+
hi: "आगे जाएं",
|
|
115
|
+
ar: "إلى الأمام",
|
|
116
|
+
ru: "Вперёд",
|
|
117
|
+
tr: "İleri",
|
|
118
|
+
pl: "Naprzód",
|
|
119
|
+
id: "Maju",
|
|
120
|
+
vi: "Tiến tới"
|
|
121
|
+
}),
|
|
84
122
|
reloadButtonTitle: t({
|
|
85
123
|
en: "Reload page",
|
|
86
124
|
"en-GB": "Reload page",
|
|
@@ -128,8 +166,8 @@ const browserContent = {
|
|
|
128
166
|
"iframe"
|
|
129
167
|
]
|
|
130
168
|
};
|
|
131
|
-
var
|
|
169
|
+
var browser_content_default = browserContent;
|
|
132
170
|
|
|
133
171
|
//#endregion
|
|
134
|
-
export { browserContent,
|
|
135
|
-
//# sourceMappingURL=
|
|
172
|
+
export { browserContent, browser_content_default as default };
|
|
173
|
+
//# sourceMappingURL=browser.content.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"
|
|
1
|
+
{"version":3,"file":"browser.content.mjs","names":[],"sources":["../../../../src/components/Browser/browser.content.ts"],"sourcesContent":["import { type Dictionary, t } from 'intlayer';\n\nexport const browserContent = {\n key: 'browser',\n content: {\n ariaLabel: t({\n en: 'Embedded browser',\n 'en-GB': 'Embedded browser',\n fr: 'Navigateur intégré',\n es: 'Navegador integrado',\n de: 'Eingebetteter Browser',\n ja: '埋め込みブラウザ',\n ko: '임베디드 브라우저',\n zh: '嵌入式浏览器',\n it: 'Browser incorporato',\n pt: 'Navegador incorporado',\n hi: 'एम्बेडेड ब्राउज़र',\n ar: 'متصفح مدمج',\n ru: 'Встроенный браузер',\n tr: 'Gömülü tarayıcı',\n pl: 'Osadzona przeglądarka',\n id: 'Peramban tertanam',\n vi: 'Trình duyệt nhúng',\n }),\n urlLabel: t({\n en: 'URL address bar',\n 'en-GB': 'URL address bar',\n fr: \"Barre d'adresse URL\",\n es: 'Barra de direcciones URL',\n de: 'URL-Adressleiste',\n ja: 'URLアドレスバー',\n ko: 'URL 주소 표시줄',\n zh: 'URL地址栏',\n it: 'Barra degli indirizzi URL',\n pt: 'Barra de endereços URL',\n hi: 'URL पता बार',\n ar: 'شريط عنوان URL',\n ru: 'Адресная строка URL',\n tr: 'URL adres çubuğu',\n pl: 'Pasek adresu URL',\n id: 'Bilah alamat URL',\n vi: 'Thanh địa chỉ URL',\n }),\n urlPlaceholder: 'https://example.com',\n errorMessage: t({\n en: 'Invalid URL. Try a path like \"/page\" or a full URL.',\n 'en-GB': 'Invalid URL. Try a path like \"/page\" or a full URL.',\n fr: 'URL invalide. Essayez un chemin comme \"/page\" ou une URL complète.',\n es: 'URL no válida. Intente una ruta como \"/page\" o una URL completa.',\n de: 'Ungültige URL. Versuchen Sie einen Pfad wie \"/page\" oder eine vollständige URL.',\n ja: '無効なURL。\"/page\"のようなパスまたは完全なURLを試してください。',\n ko: '잘못된 URL입니다. \"/page\"와 같은 경로 또는 전체 URL을 시도하십시오.',\n zh: '无效的URL。尝试像\"/page\"这样的路径或完整的URL。',\n it: 'URL non valido. Prova un percorso come \"/page\" o un URL completo.',\n pt: 'URL inválido. Tente um caminho como \"/page\" ou uma URL completa.',\n hi: 'अमान्य URL। \"/page\" जैसा पथ या पूर्ण URL प्रयास करें।',\n ar: 'رابط غير صالح. جرب مسارًا مثل \"/page\" أو رابطًا كاملاً.',\n ru: 'Неверный URL. Попробуйте путь вроде \"/page\" или полный URL.',\n tr: 'Geçersiz URL. \"/page\" gibi bir yol veya tam URL deneyin.',\n pl: 'Nieprawidłowy adres URL. Wypróbuj ścieżkę jak \"/page\" lub pełny URL.',\n id: 'URL tidak valid. Coba jalur seperti \"/page\" atau URL lengkap.',\n vi: 'URL không hợp lệ. Thử đường dẫn như \"/page\" hoặc URL đầy đủ.',\n }),\n domainRestrictionError: t({\n en: 'URL must match the application domain.',\n 'en-GB': 'URL must match the application domain.',\n fr: \"L'URL doit correspondre au domaine de l'application.\",\n es: 'La URL debe coincidir con el dominio de la aplicación.',\n de: 'Die URL muss mit der Anwendungsdomäne übereinstimmen.',\n ja: 'URLはアプリケーションドメインと一致する必要があります。',\n ko: 'URL은 애플리케이션 도메인과 일치해야 합니다.',\n zh: 'URL必须与应用程序域名匹配。',\n it: \"L'URL deve corrispondere al dominio dell'applicazione.\",\n pt: 'A URL deve corresponder ao domínio da aplicação.',\n hi: 'URL एप्लिकेशन डोमेन से मेल खाना चाहिए।',\n ar: 'يجب أن يتطابق الرابط مع نطاق التطبيق.',\n ru: 'URL должен соответствовать домену приложения.',\n tr: 'URL, uygulama etki alanıyla eşleşmelidir.',\n pl: 'Adres URL musi pasować do domeny aplikacji.',\n id: 'URL harus cocok dengan domain aplikasi.',\n vi: 'URL phải khớp với tên miền ứng dụng.',\n }),\n backButtonLabel: t({\n en: 'Go back',\n 'en-GB': 'Go back',\n fr: 'Retour',\n es: 'Atrás',\n de: 'Zurück',\n ja: '戻る',\n ko: '뒤로 가기',\n zh: '后退',\n it: 'Indietro',\n pt: 'Voltar',\n hi: 'वापस जाएं',\n ar: 'رجوع',\n ru: 'Назад',\n tr: 'Geri',\n pl: 'Wstecz',\n id: 'Kembali',\n vi: 'Quay lại',\n }),\n forwardButtonLabel: t({\n en: 'Go forward',\n 'en-GB': 'Go forward',\n fr: 'Avancer',\n es: 'Adelante',\n de: 'Vorwärts',\n ja: '進む',\n ko: '앞으로 가기',\n zh: '前进',\n it: 'Avanti',\n pt: 'Avançar',\n hi: 'आगे जाएं',\n ar: 'إلى الأمام',\n ru: 'Вперёд',\n tr: 'İleri',\n pl: 'Naprzód',\n id: 'Maju',\n vi: 'Tiến tới',\n }),\n reloadButtonTitle: t({\n en: 'Reload page',\n 'en-GB': 'Reload page',\n fr: 'Recharger la page',\n es: 'Recargar página',\n de: 'Seite neu laden',\n ja: 'ページを再読み込み',\n ko: '페이지 새로고침',\n zh: '重新加载页面',\n it: 'Ricarica pagina',\n pt: 'Recarregar página',\n hi: 'पृष्ठ को फिर से लोड करें',\n ar: 'إعادة تحميل الصفحة',\n ru: 'Перезагрузить страницу',\n tr: 'Sayfayı yenile',\n pl: 'Przeładuj stronę',\n id: 'Muat ulang halaman',\n vi: 'Tải lại trang',\n }),\n iframeTitle: t({\n en: 'Embedded web page',\n 'en-GB': 'Embedded web page',\n fr: 'Page web intégrée',\n es: 'Página web integrada',\n de: 'Eingebettete Webseite',\n ja: '埋め込みウェブページ',\n ko: '임베디드 웹페이지',\n zh: '嵌入式网页',\n it: 'Pagina web incorporata',\n pt: 'Página web incorporada',\n hi: 'एम्बेडेड वेब पेज',\n ar: 'صفحة ويب مدمجة',\n ru: 'Встроенная веб-страница',\n tr: 'Gömülü web sayfası',\n pl: 'Osadzona strona internetowa',\n id: 'Halaman web tertanam',\n vi: 'Trang web được nhúng',\n }),\n },\n title: 'Embedded browser component',\n description:\n 'Content declaration for the embedded browser UI component, including ARIA labels, URL placeholder, and error messages for displaying web pages within an iframe.',\n tags: ['UI component', 'embedded browser', 'iframe'],\n} satisfies Dictionary;\n\nexport default browserContent;\n"],"mappings":";;;AAEA,MAAa,iBAAiB;CAC5B,KAAK;CACL,SAAS;EACP,WAAW,EAAE;GACX,IAAI;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACF,UAAU,EAAE;GACV,IAAI;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACF,gBAAgB;EAChB,cAAc,EAAE;GACd,IAAI;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACF,wBAAwB,EAAE;GACxB,IAAI;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACF,iBAAiB,EAAE;GACjB,IAAI;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACF,oBAAoB,EAAE;GACpB,IAAI;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACF,mBAAmB,EAAE;GACnB,IAAI;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACF,aAAa,EAAE;GACb,IAAI;GACJ,SAAS;GACT,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACL,CAAC;EACH;CACD,OAAO;CACP,aACE;CACF,MAAM;EAAC;EAAgB;EAAoB;EAAS;CACrD;AAED,8BAAe"}
|
|
@@ -93,7 +93,7 @@ const buttonVariants = cva("relative inline-flex cursor-pointer items-center jus
|
|
|
93
93
|
[`${ButtonColor.PRIMARY}`]: "hover-primary-500/20 text-primary ring-primary-500/20 *:text-text-light",
|
|
94
94
|
[`${ButtonColor.SECONDARY}`]: "hover-secondary-500/20 text-secondary ring-secondary-500/20 *:text-text-light",
|
|
95
95
|
[`${ButtonColor.DESTRUCTIVE}`]: "hover-destructive-500/20 text-destructive ring-destructive-500/20 *:text-text-light",
|
|
96
|
-
[`${ButtonColor.NEUTRAL}`]: "text-neutral ring-neutral-500/
|
|
96
|
+
[`${ButtonColor.NEUTRAL}`]: "text-neutral ring-neutral-500/5 *:text-text-light",
|
|
97
97
|
[`${ButtonColor.CARD}`]: "hover-card-500/20 text-card ring-card-500/20 *:text-text-light",
|
|
98
98
|
[`${ButtonColor.LIGHT}`]: "hover-white-500/20 text-white ring-white/20 *:text-text-light",
|
|
99
99
|
[`${ButtonColor.DARK}`]: "text-neutral-800 ring-text-light/50 *:text-text-light",
|
|
@@ -133,7 +133,11 @@ const buttonVariants = cva("relative inline-flex cursor-pointer items-center jus
|
|
|
133
133
|
[`${ButtonVariant.LINK}`]: "h-auto justify-start border-inherit bg-transparent px-1 underline-offset-4 *:text-current! hover:bg-transparent hover:underline",
|
|
134
134
|
[`${ButtonVariant.INVISIBLE_LINK}`]: "h-auto justify-start border-inherit bg-transparent px-1 underline-offset-4 *:text-current! hover:bg-transparent",
|
|
135
135
|
[`${ButtonVariant.HOVERABLE}`]: "rounded-lg border-none bg-current/0 transition *:text-current! hover:bg-current/20 aria-[current]:bg-current/5",
|
|
136
|
-
[`${ButtonVariant.FADE}`]:
|
|
136
|
+
[`${ButtonVariant.FADE}`]: [
|
|
137
|
+
"rounded-lg border-none bg-current/10 ring-current/5 transition *:text-current! hover:bg-current/20 aria-[current]:bg-current/5",
|
|
138
|
+
"hover:ring-5 focus-visible:ring-5",
|
|
139
|
+
"aria-selected:ring-5"
|
|
140
|
+
],
|
|
137
141
|
[`${ButtonVariant.INPUT}`]: [
|
|
138
142
|
"text-text",
|
|
139
143
|
"w-full select-text resize-none rounded-2xl text-base shadow-none outline-none supports-[corner-shape:squircle]:rounded-4xl",
|