@m4l/components 0.0.0

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.
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ import { BoxIconProps } from './types';
3
+ export declare function BoxIcon({ src, sx }: BoxIconProps): JSX.Element;
@@ -0,0 +1,20 @@
1
+ import Box from "@mui/material/Box";
2
+ import { jsx } from "react/jsx-runtime";
3
+ function BoxIcon({
4
+ src,
5
+ sx
6
+ }) {
7
+ return /* @__PURE__ */ jsx(Box, {
8
+ component: "span",
9
+ sx: {
10
+ width: 20,
11
+ height: 20,
12
+ display: "inline-block",
13
+ bgcolor: "currentColor",
14
+ mask: `url(${src}) no-repeat center / contain`,
15
+ WebkitMask: `url(${src}) no-repeat center / contain`,
16
+ ...sx
17
+ }
18
+ });
19
+ }
20
+ export { BoxIcon as B };
@@ -0,0 +1,4 @@
1
+ import { BoxProps } from '@mui/material';
2
+ export interface BoxIconProps extends BoxProps {
3
+ src: string;
4
+ }
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ import { LinkItemProps } from './types';
3
+ export declare function LinkItem({ link }: LinkItemProps): JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { TLink } from '../../types';
2
+ export declare type LinkItemProps = {
3
+ link: TLink;
4
+ };
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ import type { BreadcrumbsProps } from './types';
3
+ export default function Breadcrumbs(props: BreadcrumbsProps): JSX.Element;
@@ -0,0 +1,92 @@
1
+ import { useMemo } from "react";
2
+ import { useModuleDictionary } from "@m4l/core";
3
+ import { Link, Box, Typography, Breadcrumbs as Breadcrumbs$1 } from "@mui/material";
4
+ import { Link as Link$1 } from "react-router-dom";
5
+ import { jsxs, jsx } from "react/jsx-runtime";
6
+ function LinkItem({
7
+ link
8
+ }) {
9
+ const {
10
+ href,
11
+ name,
12
+ icon,
13
+ dictionaryField: dictionaryDescription
14
+ } = link;
15
+ const {
16
+ getLabel
17
+ } = useModuleDictionary();
18
+ return /* @__PURE__ */ jsxs(Link, {
19
+ variant: "body2",
20
+ component: Link$1,
21
+ to: href || "#",
22
+ sx: {
23
+ lineHeight: 2,
24
+ display: "flex",
25
+ alignItems: "center",
26
+ color: "text.primary",
27
+ "& > div": {
28
+ display: "inherit"
29
+ }
30
+ },
31
+ children: [icon && /* @__PURE__ */ jsx(Box, {
32
+ sx: {
33
+ mr: 1,
34
+ "& svg": {
35
+ width: 20,
36
+ height: 20
37
+ }
38
+ },
39
+ children: icon
40
+ }), dictionaryDescription !== void 0 && getLabel ? getLabel(dictionaryDescription) : name]
41
+ }, name);
42
+ }
43
+ function Breadcrumbs(props) {
44
+ const {
45
+ links,
46
+ activeLast = false,
47
+ ...other
48
+ } = props;
49
+ const {
50
+ getLabel
51
+ } = useModuleDictionary();
52
+ const currentLink = useMemo(() => {
53
+ if (links.length === 0)
54
+ return "";
55
+ const {
56
+ dictionaryField
57
+ } = links[links.length - 1];
58
+ return getLabel(dictionaryField);
59
+ }, [getLabel, links]);
60
+ const listDefault = useMemo(() => links.map((link) => /* @__PURE__ */ jsx(LinkItem, {
61
+ link
62
+ }, link.name)), [links]);
63
+ const listActiveLast = useMemo(() => links.map((link) => link.name !== currentLink ? /* @__PURE__ */ jsx(LinkItem, {
64
+ link
65
+ }, link.name) : /* @__PURE__ */ jsx(Typography, {
66
+ variant: "body2",
67
+ sx: {
68
+ maxWidth: 260,
69
+ overflow: "hidden",
70
+ whiteSpace: "nowrap",
71
+ color: "text.disabled",
72
+ textOverflow: "ellipsis"
73
+ },
74
+ children: currentLink
75
+ }, link.name)), [currentLink, links]);
76
+ return /* @__PURE__ */ jsx(Breadcrumbs$1, {
77
+ id: "MUIBreadcrumbs",
78
+ separator: /* @__PURE__ */ jsx(Box, {
79
+ component: "span",
80
+ sx: {
81
+ width: 4,
82
+ height: 4,
83
+ mx: 0.5,
84
+ borderRadius: "50%",
85
+ bgcolor: "text.disabled"
86
+ }
87
+ }),
88
+ ...other,
89
+ children: activeLast ? listDefault : listActiveLast
90
+ });
91
+ }
92
+ export { Breadcrumbs as B };
@@ -0,0 +1,12 @@
1
+ import { BreadcrumbsProps as MUIBreadcrumbsProps } from '@mui/material';
2
+ import { ReactElement } from 'react';
3
+ export declare type TLink = {
4
+ href?: string;
5
+ name: string;
6
+ dictionaryField: string;
7
+ icon?: ReactElement;
8
+ };
9
+ export interface BreadcrumbsProps extends MUIBreadcrumbsProps {
10
+ links: TLink[];
11
+ activeLast?: boolean;
12
+ }
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ import { MenuActionsProps } from './types';
3
+ export default function MenuActions(props: MenuActionsProps): JSX.Element;
@@ -0,0 +1,113 @@
1
+ import { useState, useMemo } from "react";
2
+ import { useEnvironment, useModuleDictionary } from "@m4l/core";
3
+ import { IconButton, Tooltip, MenuItem } from "@mui/material";
4
+ import { M as MenuPopover } from "../MenuPopover/index.js";
5
+ import { styled } from "@mui/material/styles";
6
+ import { B as BoxIcon } from "../BoxIcon/index.js";
7
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
8
+ const WrapperMenuActions = styled(IconButton)(() => ({}));
9
+ const LabelMemuItem = styled("div")(({
10
+ theme
11
+ }) => ({
12
+ height: "22px",
13
+ marginLeft: theme.spacing(1.5),
14
+ display: "flex",
15
+ alignItems: "center"
16
+ }));
17
+ function MenuActions(props) {
18
+ const {
19
+ menuActions,
20
+ objItem = {},
21
+ urlIcon,
22
+ toolTip = "",
23
+ marginTop = -1,
24
+ marginBottom,
25
+ marginLeft,
26
+ marginRight,
27
+ width = 200,
28
+ arrow = "right-top",
29
+ ...other
30
+ } = props;
31
+ const {
32
+ host_static_assets,
33
+ environment
34
+ } = useEnvironment();
35
+ const {
36
+ getLabel
37
+ } = useModuleDictionary();
38
+ const [open, setOpen] = useState(null);
39
+ const handleOpen = (event) => {
40
+ setOpen(event.currentTarget);
41
+ };
42
+ const urlFinalIcon = useMemo(() => {
43
+ if (urlIcon)
44
+ return urlIcon;
45
+ return `${host_static_assets}/${environment}/frontend/commons/assets/icons/more_vertical.svg`;
46
+ }, [urlIcon, host_static_assets, environment]);
47
+ const handleClose = () => {
48
+ setOpen(null);
49
+ };
50
+ const handleClick = (menuAction) => {
51
+ setOpen(null);
52
+ menuAction.onClick();
53
+ };
54
+ const finalActions = useMemo(() => {
55
+ let ret;
56
+ if (typeof menuActions !== "function") {
57
+ ret = menuActions;
58
+ } else {
59
+ ret = menuActions(objItem);
60
+ }
61
+ return ret;
62
+ }, [menuActions, objItem]);
63
+ return /* @__PURE__ */ jsxs(Fragment, {
64
+ children: [/* @__PURE__ */ jsx(Tooltip, {
65
+ title: toolTip,
66
+ children: /* @__PURE__ */ jsx(WrapperMenuActions, {
67
+ id: "WrapperMenuActions",
68
+ size: "small",
69
+ onClick: handleOpen,
70
+ children: /* @__PURE__ */ jsx(BoxIcon, {
71
+ src: urlFinalIcon,
72
+ sx: {
73
+ width: 20,
74
+ height: 20
75
+ }
76
+ })
77
+ })
78
+ }), /* @__PURE__ */ jsx(MenuPopover, {
79
+ id: "MenuPopover",
80
+ open: Boolean(open),
81
+ anchorEl: open,
82
+ onClose: handleClose,
83
+ arrow,
84
+ sx: {
85
+ marginTop,
86
+ marginBottom,
87
+ marginLeft,
88
+ marginRight,
89
+ width,
90
+ "& .MuiMenuItem-root": {
91
+ px: 1,
92
+ typography: "body2",
93
+ borderRadius: 0.75
94
+ }
95
+ },
96
+ ...other,
97
+ children: open && finalActions.map((menuAction, index) => /* @__PURE__ */ jsxs(MenuItem, {
98
+ dense: true,
99
+ onClick: () => handleClick(menuAction),
100
+ sx: {
101
+ color: menuAction.color ? menuAction.color : "text.main"
102
+ },
103
+ disabled: menuAction.disabled,
104
+ children: [/* @__PURE__ */ jsx(BoxIcon, {
105
+ src: menuAction.urlIcon
106
+ }), /* @__PURE__ */ jsx(LabelMemuItem, {
107
+ children: getLabel(menuAction.dictionaryField)
108
+ })]
109
+ }, `menu_action_${index}`))
110
+ })]
111
+ });
112
+ }
113
+ export { MenuActions as M };
@@ -0,0 +1,30 @@
1
+ /// <reference types="react" />
2
+ export declare const WrapperMenuActions: import("@emotion/styled").StyledComponent<{
3
+ children?: import("react").ReactNode;
4
+ classes?: Partial<import("@mui/material").IconButtonClasses> | undefined;
5
+ color?: "inherit" | "default" | "primary" | "secondary" | "error" | "info" | "success" | "warning" | undefined;
6
+ disabled?: boolean | undefined;
7
+ disableFocusRipple?: boolean | undefined;
8
+ edge?: false | "end" | "start" | undefined;
9
+ size?: "small" | "medium" | "large" | undefined;
10
+ sx?: import("@mui/material").SxProps<import("@mui/material").Theme> | undefined;
11
+ } & Omit<{
12
+ action?: import("react").Ref<import("@mui/material").ButtonBaseActions> | undefined;
13
+ centerRipple?: boolean | undefined;
14
+ children?: import("react").ReactNode;
15
+ classes?: Partial<import("@mui/material").ButtonBaseClasses> | undefined;
16
+ disabled?: boolean | undefined;
17
+ disableRipple?: boolean | undefined;
18
+ disableTouchRipple?: boolean | undefined;
19
+ focusRipple?: boolean | undefined;
20
+ focusVisibleClassName?: string | undefined;
21
+ LinkComponent?: import("react").ElementType<any> | undefined;
22
+ onFocusVisible?: import("react").FocusEventHandler<any> | undefined;
23
+ sx?: import("@mui/material").SxProps<import("@mui/material").Theme> | undefined;
24
+ tabIndex?: number | undefined;
25
+ TouchRippleProps?: Partial<import("@mui/material/ButtonBase/TouchRipple").TouchRippleProps> | undefined;
26
+ touchRippleRef?: import("react").Ref<import("@mui/material/ButtonBase/TouchRipple").TouchRippleActions> | undefined;
27
+ }, "classes"> & import("@mui/material/OverridableComponent").CommonProps & Omit<Pick<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "key" | keyof import("react").ButtonHTMLAttributes<HTMLButtonElement>> & {
28
+ ref?: ((instance: HTMLButtonElement | null) => void) | import("react").RefObject<HTMLButtonElement> | null | undefined;
29
+ }, keyof import("@mui/material/OverridableComponent").CommonProps | "color" | "children" | "sx" | "tabIndex" | "disabled" | "action" | "size" | "centerRipple" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "onFocusVisible" | "TouchRippleProps" | "touchRippleRef" | "disableFocusRipple" | "edge"> & import("@mui/system").MUIStyledCommonProps<import("@mui/material").Theme>, {}, {}>;
30
+ export declare const LabelMemuItem: import("@emotion/styled").StyledComponent<import("@mui/system").MUIStyledCommonProps<import("@mui/material").Theme>, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
@@ -0,0 +1,27 @@
1
+ /// <reference types="react" />
2
+ import { MenuPopoverProps } from '../MenuPopover/types';
3
+ export interface ComponentActionProps {
4
+ description?: string;
5
+ onClick: (props?: any) => void;
6
+ }
7
+ export interface MenuAction {
8
+ urlIcon: string;
9
+ iconWidth?: number;
10
+ iconHeight?: number;
11
+ dictionaryField: string;
12
+ onClick: (props?: any) => void;
13
+ disabled: boolean;
14
+ color?: string;
15
+ component?: (props: ComponentActionProps) => JSX.Element;
16
+ }
17
+ export interface MenuActionsProps extends Omit<MenuPopoverProps, 'open'> {
18
+ objItem?: any;
19
+ urlIcon?: string;
20
+ menuActions: MenuAction[] | ((row: any) => MenuAction[]);
21
+ toolTip?: string;
22
+ marginTop?: number | string;
23
+ marginBottom?: number | string;
24
+ marginRight?: number | string;
25
+ marginLeft?: number | string;
26
+ width?: number;
27
+ }
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ import { MenuPopoverProps } from './types';
3
+ export default function MenuPopover({ children, arrow, disabledArrow, sx, ...other }: MenuPopoverProps): JSX.Element;
@@ -0,0 +1,135 @@
1
+ import { styled } from "@mui/material/styles";
2
+ import { Popover } from "@mui/material";
3
+ import { jsxs, jsx } from "react/jsx-runtime";
4
+ const ArrowStyle = styled("span")(({
5
+ arrow,
6
+ theme
7
+ }) => {
8
+ const SIZE = 12;
9
+ const POSITION = -(SIZE / 2);
10
+ const borderStyle = `solid 1px ${theme.palette.grey[50012]}`;
11
+ const topStyle = {
12
+ borderRadius: "0 0 3px 0",
13
+ top: POSITION,
14
+ borderBottom: borderStyle,
15
+ borderRight: borderStyle
16
+ };
17
+ const bottomStyle = {
18
+ borderRadius: "3px 0 0 0",
19
+ bottom: POSITION,
20
+ borderTop: borderStyle,
21
+ borderLeft: borderStyle
22
+ };
23
+ const leftStyle = {
24
+ borderRadius: "0 3px 0 0",
25
+ left: POSITION,
26
+ borderTop: borderStyle,
27
+ borderRight: borderStyle
28
+ };
29
+ const rightStyle = {
30
+ borderRadius: "0 0 0 3px",
31
+ right: POSITION,
32
+ borderBottom: borderStyle,
33
+ borderLeft: borderStyle
34
+ };
35
+ return {
36
+ display: "none",
37
+ [theme.breakpoints.up("sm")]: {
38
+ zIndex: 1,
39
+ width: SIZE,
40
+ height: SIZE,
41
+ content: "''",
42
+ position: "absolute",
43
+ display: "block",
44
+ transform: "rotate(-135deg)",
45
+ background: theme.palette.background.paper
46
+ },
47
+ ...arrow === "top-left" && {
48
+ ...topStyle,
49
+ left: 20
50
+ },
51
+ ...arrow === "top-center" && {
52
+ ...topStyle,
53
+ left: 0,
54
+ right: 0,
55
+ margin: "auto"
56
+ },
57
+ ...arrow === "top-right" && {
58
+ ...topStyle,
59
+ right: 20
60
+ },
61
+ ...arrow === "bottom-left" && {
62
+ ...bottomStyle,
63
+ left: 20
64
+ },
65
+ ...arrow === "bottom-center" && {
66
+ ...bottomStyle,
67
+ left: 0,
68
+ right: 0,
69
+ margin: "auto"
70
+ },
71
+ ...arrow === "bottom-right" && {
72
+ ...bottomStyle,
73
+ right: 20
74
+ },
75
+ ...arrow === "left-top" && {
76
+ ...leftStyle,
77
+ top: 20
78
+ },
79
+ ...arrow === "left-center" && {
80
+ ...leftStyle,
81
+ top: 0,
82
+ bottom: 0,
83
+ margin: "auto"
84
+ },
85
+ ...arrow === "left-bottom" && {
86
+ ...leftStyle,
87
+ bottom: 20
88
+ },
89
+ ...arrow === "right-top" && {
90
+ ...rightStyle,
91
+ top: 20
92
+ },
93
+ ...arrow === "right-center" && {
94
+ ...rightStyle,
95
+ top: 0,
96
+ bottom: 0,
97
+ margin: "auto"
98
+ },
99
+ ...arrow === "right-bottom" && {
100
+ ...rightStyle,
101
+ bottom: 20
102
+ }
103
+ };
104
+ });
105
+ function MenuPopover({
106
+ children,
107
+ arrow = "top-right",
108
+ disabledArrow,
109
+ sx,
110
+ ...other
111
+ }) {
112
+ return /* @__PURE__ */ jsxs(Popover, {
113
+ anchorOrigin: {
114
+ vertical: "bottom",
115
+ horizontal: "right"
116
+ },
117
+ transformOrigin: {
118
+ vertical: "top",
119
+ horizontal: "right"
120
+ },
121
+ PaperProps: {
122
+ sx: {
123
+ p: 1,
124
+ width: 200,
125
+ overflow: "inherit",
126
+ ...sx
127
+ }
128
+ },
129
+ ...other,
130
+ children: [!disabledArrow && /* @__PURE__ */ jsx(ArrowStyle, {
131
+ arrow
132
+ }), children]
133
+ });
134
+ }
135
+ export { MenuPopover as M };
@@ -0,0 +1,9 @@
1
+ import { PopoverProps } from '@mui/material';
2
+ export declare type Arrow = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right' | 'left-top' | 'left-center' | 'left-bottom' | 'right-top' | 'right-center' | 'right-bottom';
3
+ export declare type ArrowStyleProps = {
4
+ arrow: Arrow;
5
+ };
6
+ export interface MenuPopoverProps extends PopoverProps {
7
+ arrow?: Arrow;
8
+ disabledArrow?: boolean;
9
+ }
@@ -0,0 +1,42 @@
1
+ export { BoxIcon } from './BoxIcon';
2
+ export { default as MenuPopover } from './MenuPopover';
3
+ export { default as Breadcrumbs } from './Breadcrumbs';
4
+ export type { TLink } from './Breadcrumbs/types';
5
+ export { default as MenuActions } from './MenuActions';
6
+ export type { MenuAction } from './MenuActions/types';
7
+ declare module '@mui/material/styles/createPalette' {
8
+ interface TypeBackground {
9
+ neutral: string;
10
+ autofill: string;
11
+ header: string;
12
+ }
13
+ interface SimplePaletteColorOptions {
14
+ lighter?: string;
15
+ darker?: string;
16
+ LightSelected?: string;
17
+ LightSelectedHover?: string;
18
+ DarkSelected?: string;
19
+ DarkSelectedHover?: string;
20
+ }
21
+ interface PaletteColor {
22
+ lighter?: string;
23
+ darker?: string;
24
+ LightSelected?: string;
25
+ LightSelectedHover?: string;
26
+ DarkSelected?: string;
27
+ DarkSelectedHover?: string;
28
+ }
29
+ }
30
+ declare module '@mui/material' {
31
+ interface Color {
32
+ 0: string;
33
+ 500_8: string;
34
+ 500_12: string;
35
+ 500_16: string;
36
+ 500_24: string;
37
+ 500_32: string;
38
+ 500_48: string;
39
+ 500_56: string;
40
+ 500_80: string;
41
+ }
42
+ }
@@ -0,0 +1 @@
1
+ export * from './components/mui_extended';
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ import "@mui/material/Box";
2
+ import "react/jsx-runtime";
3
+ export { M as MenuPopover } from "./components/mui_extended/MenuPopover/index.js";
4
+ import "react";
5
+ import "@m4l/core";
6
+ import "@mui/material";
7
+ import "react-router-dom";
8
+ export { M as MenuActions } from "./components/mui_extended/MenuActions/index.js";
9
+ export { B as BoxIcon } from "./components/mui_extended/BoxIcon/index.js";
10
+ export { B as Breadcrumbs } from "./components/mui_extended/Breadcrumbs/index.js";
11
+ import "@mui/material/styles";
@@ -0,0 +1,3 @@
1
+ /// <reference types="vite/client" />
2
+ /// <reference types="vitest" />
3
+ /// <reference types="vitest/importMeta" />
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@m4l/components",
3
+ "private": false,
4
+ "version": "0.0.0",
5
+ "license": "UNLICENSED",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc && vite build",
9
+ "preview": "vite preview",
10
+ "lint": "npx eslint src",
11
+ "lint:fix": "npm run lint -- --fix",
12
+ "prettier": "npx prettier src --check",
13
+ "prettier:fix": "npm run prettier -- --write",
14
+ "format": "npm run prettier:fix && npm run lint:fix"
15
+ },
16
+ "dependencies": {
17
+ "react": "^17.0.0 || 18.x",
18
+ "react-dom": "^18.0.0"
19
+ },
20
+ "peerDependencies": {
21
+ "@m4l/core": "^0.0.26",
22
+ "@mui/material": "^5.8.7",
23
+ "react": "^17.0.0 || 18.x",
24
+ "react-dom": "^18.0.0",
25
+ "react-router-dom":"^6.3.0"
26
+ },
27
+ "devDependencies": {
28
+ "@emotion/styled": "^11.9.3",
29
+ "@m4l/core": "^0.0.26",
30
+ "@m4l/graphics": "^0.0.14",
31
+ "@mui/material": "^5.8.7",
32
+ "@testing-library/react": "^13.3.0",
33
+ "@testing-library/user-event": "^14.2.1",
34
+ "@types/node": "^17.0.40",
35
+ "@types/react": "^18.0.0",
36
+ "@types/react-dom": "^18.0.0",
37
+ "@typescript-eslint/eslint-plugin": "^5.27.1",
38
+ "@typescript-eslint/parser": "^5.27.1",
39
+ "@vitejs/plugin-react": "^1.3.2",
40
+ "eslint": "^8.17.0",
41
+ "eslint-config-prettier": "^8.5.0",
42
+ "eslint-import-resolver-alias": "^1.1.2",
43
+ "eslint-plugin-import": "^2.26.0",
44
+ "eslint-plugin-jsx-a11y": "^6.5.1",
45
+ "eslint-plugin-prettier": "^4.0.0",
46
+ "eslint-plugin-react": "^7.30.0",
47
+ "eslint-plugin-react-hooks": "^4.5.0",
48
+ "eslint-plugin-unused-imports": "^2.0.0",
49
+ "prettier": "^2.6.2",
50
+ "rollup-plugin-terser": "^7.0.2",
51
+ "typescript": "^4.6.3",
52
+ "vite": "^2.9.9",
53
+ "vite-plugin-dts": "^1.2.1",
54
+ "vite-plugin-mkcert": "^1.7.2",
55
+ "vitest": "^0.17.1"
56
+ },
57
+ "files": [
58
+ "dist"
59
+ ],
60
+ "main": "./dist/index.js",
61
+ "module": "./dist/index.js",
62
+ "types": "./dist/index.d.ts",
63
+ "type": "module",
64
+ "exports": {
65
+ ".": {
66
+ "import": "./dist/index.js"
67
+ }
68
+ },
69
+ "sideEffects": false,
70
+ "publishConfig": {
71
+ "access": "public"
72
+ },
73
+ "engines": {
74
+ "node": ">=12.0.0"
75
+ }
76
+ }