@synerise/ds-search-bar 1.2.0 → 1.3.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.
- package/CHANGELOG.md +11 -0
- package/README.md +1 -0
- package/dist/SearchBar.constants.d.ts +8 -0
- package/dist/SearchBar.constants.js +8 -0
- package/dist/SearchBar.d.ts +2 -2
- package/dist/SearchBar.js +17 -5
- package/dist/SearchBar.styles.d.ts +7 -2
- package/dist/SearchBar.styles.js +34 -19
- package/dist/SearchBar.types.d.ts +1 -0
- package/dist/ValuePrefix.d.ts +8 -0
- package/dist/ValuePrefix.js +24 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.3.0](https://github.com/Synerise/synerise-design/compare/@synerise/ds-search-bar@1.2.0...@synerise/ds-search-bar@1.3.0) (2025-06-11)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **item-picker:** add search actions ([6b2c260](https://github.com/Synerise/synerise-design/commit/6b2c2607b32ad609a71ac7b93332f1b6baf2443c))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# [1.2.0](https://github.com/Synerise/synerise-design/compare/@synerise/ds-search-bar@1.1.4...@synerise/ds-search-bar@1.2.0) (2025-06-05)
|
|
7
18
|
|
|
8
19
|
|
package/README.md
CHANGED
|
@@ -40,3 +40,4 @@ import SearchBar from '@synerise/ds-search-bar'
|
|
|
40
40
|
| placeholder | Placeholder | React.ReactNode | - |
|
|
41
41
|
| value | The input content value | string | - |
|
|
42
42
|
| autofocusDelay | Delay (ms) of the focus on search input | number | 0 |
|
|
43
|
+
| valuePrefix | An element displayed before the value | ReactNode | - |
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const SEARCH_BAR_PADDING_LEFT = 16;
|
|
2
|
+
export declare const SEARCH_BAR_PADDING_RIGHT = 12;
|
|
3
|
+
export declare const ICON_LEFT_SIZE = 24;
|
|
4
|
+
export declare const ICON_LEFT_MARGIN_RIGHT = 12;
|
|
5
|
+
export declare const CLEAR_ICON_SIZE = 18;
|
|
6
|
+
export declare const CLEAR_ICON_MARGIN_LEFT = 12;
|
|
7
|
+
export declare const VALUE_PREFIX_WRAPPER_LEFT_VALUE: number;
|
|
8
|
+
export declare const VALUE_PREFIX_WRAPPER_RIGHT_MARGIN = 4;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export var SEARCH_BAR_PADDING_LEFT = 16;
|
|
2
|
+
export var SEARCH_BAR_PADDING_RIGHT = 12;
|
|
3
|
+
export var ICON_LEFT_SIZE = 24;
|
|
4
|
+
export var ICON_LEFT_MARGIN_RIGHT = 12;
|
|
5
|
+
export var CLEAR_ICON_SIZE = 18;
|
|
6
|
+
export var CLEAR_ICON_MARGIN_LEFT = 12;
|
|
7
|
+
export var VALUE_PREFIX_WRAPPER_LEFT_VALUE = SEARCH_BAR_PADDING_LEFT + ICON_LEFT_SIZE + ICON_LEFT_MARGIN_RIGHT;
|
|
8
|
+
export var VALUE_PREFIX_WRAPPER_RIGHT_MARGIN = 4;
|
package/dist/SearchBar.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { SearchBarProps } from './SearchBar.types';
|
|
3
|
-
declare const SearchBar: ({ value, className, onSearchChange, onClearInput, placeholder, iconLeft, autofocus, clearTooltip, disabled, borderRadius, handleInputRef, autofocusDelay, clearTooltipProps, ...htmlAttributes }: SearchBarProps) => React.JSX.Element;
|
|
2
|
+
import type { SearchBarProps } from './SearchBar.types';
|
|
3
|
+
declare const SearchBar: ({ value, className, onSearchChange, onClearInput, placeholder, iconLeft, autofocus, clearTooltip, disabled, borderRadius, handleInputRef, autofocusDelay, clearTooltipProps, valuePrefix, ...htmlAttributes }: SearchBarProps) => React.JSX.Element;
|
|
4
4
|
export default SearchBar;
|
package/dist/SearchBar.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var _excluded = ["value", "className", "onSearchChange", "onClearInput", "placeholder", "iconLeft", "autofocus", "clearTooltip", "disabled", "borderRadius", "handleInputRef", "autofocusDelay", "clearTooltipProps"];
|
|
1
|
+
var _excluded = ["value", "className", "onSearchChange", "onClearInput", "placeholder", "iconLeft", "autofocus", "clearTooltip", "disabled", "borderRadius", "handleInputRef", "autofocusDelay", "clearTooltipProps", "valuePrefix"];
|
|
2
2
|
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
3
3
|
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
4
4
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
@@ -7,6 +7,8 @@ import classnames from 'classnames';
|
|
|
7
7
|
import Icon, { Close3M } from '@synerise/ds-icon';
|
|
8
8
|
import { theme } from '@synerise/ds-core';
|
|
9
9
|
import Tooltip from '@synerise/ds-tooltip';
|
|
10
|
+
import { CLEAR_ICON_SIZE } from './SearchBar.constants';
|
|
11
|
+
import { ValuePrefix } from './ValuePrefix';
|
|
10
12
|
import * as S from './SearchBar.styles';
|
|
11
13
|
var DEFAULT_PLACEHOLDER_STRING = 'Search';
|
|
12
14
|
var SearchBar = function SearchBar(_ref) {
|
|
@@ -27,6 +29,7 @@ var SearchBar = function SearchBar(_ref) {
|
|
|
27
29
|
handleInputRef = _ref.handleInputRef,
|
|
28
30
|
autofocusDelay = _ref.autofocusDelay,
|
|
29
31
|
clearTooltipProps = _ref.clearTooltipProps,
|
|
32
|
+
valuePrefix = _ref.valuePrefix,
|
|
30
33
|
htmlAttributes = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
31
34
|
var _useState = useState(false),
|
|
32
35
|
isFocused = _useState[0],
|
|
@@ -34,6 +37,9 @@ var SearchBar = function SearchBar(_ref) {
|
|
|
34
37
|
var _useState2 = useState(),
|
|
35
38
|
input = _useState2[0],
|
|
36
39
|
setInput = _useState2[1];
|
|
40
|
+
var _useState3 = useState(0),
|
|
41
|
+
valuePrefixWidth = _useState3[0],
|
|
42
|
+
setValuePrefixWidth = _useState3[1];
|
|
37
43
|
var handleRef = function handleRef(ref) {
|
|
38
44
|
// eslint-disable-next-line no-unused-expressions
|
|
39
45
|
handleInputRef == null || handleInputRef(ref);
|
|
@@ -70,10 +76,11 @@ var SearchBar = function SearchBar(_ref) {
|
|
|
70
76
|
isEmpty: !value,
|
|
71
77
|
disabled: disabled,
|
|
72
78
|
borderRadius: borderRadius,
|
|
73
|
-
"data-testid": "input-wrapper"
|
|
79
|
+
"data-testid": "input-wrapper",
|
|
80
|
+
valuePrefixWidth: valuePrefixWidth
|
|
74
81
|
}, htmlAttributes, {
|
|
75
82
|
className: finalClassName
|
|
76
|
-
}), iconLeft && /*#__PURE__*/React.createElement(S.IconLeftWrapper, null, iconLeft), onClearInput && Boolean(value) && /*#__PURE__*/React.createElement(S.ClearInputWrapper, {
|
|
83
|
+
}), iconLeft && /*#__PURE__*/React.createElement(S.IconLeftWrapper, null, iconLeft), onClearInput && (Boolean(valuePrefix) || Boolean(value)) && /*#__PURE__*/React.createElement(S.ClearInputWrapper, {
|
|
77
84
|
onClick: onClearInput,
|
|
78
85
|
"data-testid": "clear-btn"
|
|
79
86
|
}, /*#__PURE__*/React.createElement(Icon, {
|
|
@@ -81,8 +88,13 @@ var SearchBar = function SearchBar(_ref) {
|
|
|
81
88
|
title: clearTooltip
|
|
82
89
|
}, clearTooltipProps), /*#__PURE__*/React.createElement(Close3M, null)),
|
|
83
90
|
color: theme.palette['grey-500'],
|
|
84
|
-
size:
|
|
85
|
-
})),
|
|
91
|
+
size: CLEAR_ICON_SIZE
|
|
92
|
+
})), !!valuePrefix && /*#__PURE__*/React.createElement(ValuePrefix, {
|
|
93
|
+
value: valuePrefix,
|
|
94
|
+
setValuePrefixWidth: setValuePrefixWidth
|
|
95
|
+
}), !value && /*#__PURE__*/React.createElement(S.PlaceholderWrapper, {
|
|
96
|
+
valuePrefixWidth: valuePrefixWidth
|
|
97
|
+
}, placeholder), /*#__PURE__*/React.createElement(S.SearchBar, {
|
|
86
98
|
onChange: function onChange(event) {
|
|
87
99
|
onSearchChange(event.currentTarget.value);
|
|
88
100
|
},
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
2
|
export declare const IconLeftWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
3
|
+
export declare const ValuePrefixWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
4
|
+
export declare const ValuePrefixTitle: import("styled-components").StyledComponent<({ level, withoutMargin, children, className, ellipsis, ...antdProps }: import("@synerise/ds-typography/dist/Title.types").Props) => import("react").JSX.Element, any, {}, never>;
|
|
3
5
|
export declare const ClearInputWrapper: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
4
|
-
export declare const PlaceholderWrapper: import("styled-components").StyledComponent<"div", any, {
|
|
6
|
+
export declare const PlaceholderWrapper: import("styled-components").StyledComponent<"div", any, {
|
|
7
|
+
valuePrefixWidth: number;
|
|
8
|
+
}, never>;
|
|
5
9
|
export declare const SearchBar: import("styled-components").StyledComponent<({ className, errorText, label, description, counterLimit, tooltip, tooltipConfig, icon1, icon1Tooltip, autoResize, icon2, icon2Tooltip, resetMargin, handleInputRef, prefixel, suffixel, error, expandable, expandableTooltip, renderCustomCounter, autoResizeProps, ...antdInputProps }: import("@synerise/ds-input").InputProps) => import("react").JSX.Element, any, {}, never>;
|
|
6
10
|
export declare const SearchBarWrapper: import("styled-components").StyledComponent<"div", any, {
|
|
7
11
|
iconLeft: React.ReactNode;
|
|
8
12
|
isEmpty: boolean;
|
|
9
13
|
disabled: boolean;
|
|
10
14
|
borderRadius: boolean | undefined;
|
|
15
|
+
valuePrefixWidth: number;
|
|
11
16
|
}, never>;
|
package/dist/SearchBar.styles.js
CHANGED
|
@@ -1,22 +1,43 @@
|
|
|
1
1
|
import styled from 'styled-components';
|
|
2
2
|
import { Input } from '@synerise/ds-input';
|
|
3
|
+
import { Title } from '@synerise/ds-typography';
|
|
4
|
+
import { CLEAR_ICON_MARGIN_LEFT, CLEAR_ICON_SIZE, ICON_LEFT_MARGIN_RIGHT, ICON_LEFT_SIZE, SEARCH_BAR_PADDING_LEFT, SEARCH_BAR_PADDING_RIGHT, VALUE_PREFIX_WRAPPER_LEFT_VALUE, VALUE_PREFIX_WRAPPER_RIGHT_MARGIN } from './SearchBar.constants';
|
|
5
|
+
var getPaddingAndWidthForSearchBarAntInput = function getPaddingAndWidthForSearchBarAntInput(_ref) {
|
|
6
|
+
var iconLeft = _ref.iconLeft,
|
|
7
|
+
isEmpty = _ref.isEmpty,
|
|
8
|
+
valuePrefixWidth = _ref.valuePrefixWidth;
|
|
9
|
+
var leftPadding = SEARCH_BAR_PADDING_LEFT + (iconLeft ? ICON_LEFT_SIZE + ICON_LEFT_MARGIN_RIGHT : 0) + valuePrefixWidth + (valuePrefixWidth ? VALUE_PREFIX_WRAPPER_RIGHT_MARGIN : 0);
|
|
10
|
+
var rightPadding = SEARCH_BAR_PADDING_RIGHT + (!isEmpty ? CLEAR_ICON_SIZE + CLEAR_ICON_MARGIN_LEFT : 0);
|
|
11
|
+
return "\n padding: 0 " + rightPadding + "px 0 " + leftPadding + "px;\n width: calc(100% - " + (rightPadding + leftPadding) + "px);\n ";
|
|
12
|
+
};
|
|
3
13
|
export var IconLeftWrapper = styled.div.withConfig({
|
|
4
14
|
displayName: "SearchBarstyles__IconLeftWrapper",
|
|
5
15
|
componentId: "sc-qhi5c4-0"
|
|
6
|
-
})(["position:absolute;left:
|
|
16
|
+
})(["position:absolute;left:", "px;display:flex;align-items:center;height:100%;z-index:3;"], SEARCH_BAR_PADDING_LEFT);
|
|
17
|
+
export var ValuePrefixWrapper = styled.div.withConfig({
|
|
18
|
+
displayName: "SearchBarstyles__ValuePrefixWrapper",
|
|
19
|
+
componentId: "sc-qhi5c4-1"
|
|
20
|
+
})(["position:absolute;left:", "px;display:flex;align-items:center;height:100%;z-index:3;"], VALUE_PREFIX_WRAPPER_LEFT_VALUE);
|
|
21
|
+
export var ValuePrefixTitle = styled(Title).withConfig({
|
|
22
|
+
displayName: "SearchBarstyles__ValuePrefixTitle",
|
|
23
|
+
componentId: "sc-qhi5c4-2"
|
|
24
|
+
})(["line-height:18px;"]);
|
|
7
25
|
export var ClearInputWrapper = styled.div.withConfig({
|
|
8
26
|
displayName: "SearchBarstyles__ClearInputWrapper",
|
|
9
|
-
componentId: "sc-qhi5c4-
|
|
10
|
-
})(["right:
|
|
27
|
+
componentId: "sc-qhi5c4-3"
|
|
28
|
+
})(["right:", "px;position:absolute;display:flex;align-items:center;height:100%;z-index:3;cursor:pointer;"], SEARCH_BAR_PADDING_RIGHT);
|
|
11
29
|
export var PlaceholderWrapper = styled.div.withConfig({
|
|
12
30
|
displayName: "SearchBarstyles__PlaceholderWrapper",
|
|
13
|
-
componentId: "sc-qhi5c4-
|
|
14
|
-
})(["pointer-events:none;position:absolute;display:flex;align-items:center;z-index:2;height:52px;left:
|
|
31
|
+
componentId: "sc-qhi5c4-4"
|
|
32
|
+
})(["pointer-events:none;position:absolute;display:flex;align-items:center;z-index:2;height:52px;left:", "px;color:", ";line-height:18px;"], function (_ref2) {
|
|
33
|
+
var valuePrefixWidth = _ref2.valuePrefixWidth;
|
|
34
|
+
return VALUE_PREFIX_WRAPPER_LEFT_VALUE + valuePrefixWidth + (valuePrefixWidth ? VALUE_PREFIX_WRAPPER_RIGHT_MARGIN : 0);
|
|
35
|
+
}, function (props) {
|
|
15
36
|
return props.theme.palette['grey-500'];
|
|
16
37
|
});
|
|
17
38
|
export var SearchBar = styled(Input).withConfig({
|
|
18
39
|
displayName: "SearchBarstyles__SearchBar",
|
|
19
|
-
componentId: "sc-qhi5c4-
|
|
40
|
+
componentId: "sc-qhi5c4-5"
|
|
20
41
|
})(["&&&{position:relative;height:52px;padding:0;input.ant-input{position:absolute;top:0;left:0;max-width:100%;height:52px;border:0;background:", ";box-sizing:content-box;&:focus{box-shadow:inset 0px -2px 0px 0px ", ";}::-webkit-input-placeholder{line-height:52px;color:transparent;}:-moz-placeholder{line-height:52px;color:transparent;}::-moz-placeholder{line-height:52px;color:transparent;}:-ms-input-placeholder{line-height:52px;color:transparent;}}}"], function (props) {
|
|
21
42
|
return props.theme.palette['grey-050'];
|
|
22
43
|
}, function (props) {
|
|
@@ -27,8 +48,8 @@ export var SearchBar = styled(Input).withConfig({
|
|
|
27
48
|
|
|
28
49
|
export var SearchBarWrapper = styled.div.withConfig({
|
|
29
50
|
displayName: "SearchBarstyles__SearchBarWrapper",
|
|
30
|
-
componentId: "sc-qhi5c4-
|
|
31
|
-
})(["position:relative;overflow:hidden;border-bottom:1px solid ", ";pointer-events:", ";user-select:", ";border-radius:", ";&&&{svg{transition:all 0.3s ease-out;fill:", ";}input.ant-input{border-radius:0;line-height:18px;
|
|
51
|
+
componentId: "sc-qhi5c4-6"
|
|
52
|
+
})(["position:relative;overflow:hidden;border-bottom:1px solid ", ";pointer-events:", ";user-select:", ";border-radius:", ";&&&{svg{transition:all 0.3s ease-out;fill:", ";}input.ant-input{border-radius:0;line-height:18px;", "}&:hover{", "{svg{fill:", ";}}", "{svg{fill:", ";}}", "{color:", ";}}}&.is-focused{", "{svg{fill:", ";}}", "{svg{fill:", ";}}", "{color:", ";}}"], function (props) {
|
|
32
53
|
return props.theme.palette['grey-100'];
|
|
33
54
|
}, function (props) {
|
|
34
55
|
return props.disabled ? 'none' : '';
|
|
@@ -38,22 +59,16 @@ export var SearchBarWrapper = styled.div.withConfig({
|
|
|
38
59
|
return props.borderRadius ? '3px' : '';
|
|
39
60
|
}, function (props) {
|
|
40
61
|
return props.disabled ? props.theme.palette['grey-400'] : '';
|
|
41
|
-
}, function (props) {
|
|
42
|
-
if (props.iconLeft && !props.isEmpty) return '0 42px 0 52px';
|
|
43
|
-
if (props.iconLeft && props.isEmpty) return '0 12px 0 52px';
|
|
44
|
-
if (!props.iconLeft && !props.isEmpty) return '0 42px 0 12px';
|
|
45
|
-
return '0 12px 0 12px';
|
|
46
|
-
}, function (props) {
|
|
47
|
-
if (props.iconLeft && !props.isEmpty) return 'calc(100% - 92px)';
|
|
48
|
-
if (props.iconLeft && props.isEmpty) return 'calc(100% - 62px)';
|
|
49
|
-
if (!props.iconLeft && !props.isEmpty) return 'calc(100% - 52px)';
|
|
50
|
-
return 'calc(100% - 24px)';
|
|
51
|
-
}, IconLeftWrapper, function (props) {
|
|
62
|
+
}, getPaddingAndWidthForSearchBarAntInput, IconLeftWrapper, function (props) {
|
|
52
63
|
return props.theme.palette['blue-600'];
|
|
53
64
|
}, ClearInputWrapper, function (props) {
|
|
54
65
|
return props.theme.palette['red-600'];
|
|
66
|
+
}, ValuePrefixTitle, function (props) {
|
|
67
|
+
return props.theme.palette['blue-600'];
|
|
55
68
|
}, IconLeftWrapper, function (props) {
|
|
56
69
|
return props.theme.palette['blue-600'];
|
|
57
70
|
}, ClearInputWrapper, function (props) {
|
|
58
71
|
return props.theme.palette['red-600'];
|
|
72
|
+
}, ValuePrefixTitle, function (props) {
|
|
73
|
+
return props.theme.palette['blue-600'];
|
|
59
74
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ReactNode, Dispatch, SetStateAction } from 'react';
|
|
3
|
+
type ValuePrefixProps = {
|
|
4
|
+
value: ReactNode;
|
|
5
|
+
setValuePrefixWidth: Dispatch<SetStateAction<number>>;
|
|
6
|
+
};
|
|
7
|
+
export declare const ValuePrefix: ({ value, setValuePrefixWidth }: ValuePrefixProps) => React.JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import { useResizeObserver } from '@synerise/ds-utils';
|
|
3
|
+
import * as S from './SearchBar.styles';
|
|
4
|
+
export var ValuePrefix = function ValuePrefix(_ref) {
|
|
5
|
+
var value = _ref.value,
|
|
6
|
+
setValuePrefixWidth = _ref.setValuePrefixWidth;
|
|
7
|
+
var valuePrefixRef = useRef(null);
|
|
8
|
+
var handleValuePrefixWidth = useCallback(function (dimensions) {
|
|
9
|
+
setValuePrefixWidth(dimensions.width);
|
|
10
|
+
}, [setValuePrefixWidth]);
|
|
11
|
+
useResizeObserver(valuePrefixRef, handleValuePrefixWidth);
|
|
12
|
+
useEffect(function () {
|
|
13
|
+
return function () {
|
|
14
|
+
return setValuePrefixWidth(0);
|
|
15
|
+
};
|
|
16
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
17
|
+
}, []);
|
|
18
|
+
return /*#__PURE__*/React.createElement(S.ValuePrefixWrapper, {
|
|
19
|
+
ref: valuePrefixRef
|
|
20
|
+
}, /*#__PURE__*/React.createElement(S.ValuePrefixTitle, {
|
|
21
|
+
level: 6,
|
|
22
|
+
withoutMargin: true
|
|
23
|
+
}, value));
|
|
24
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synerise/ds-search-bar",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "SearchBar UI Component for the Synerise Design System",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"repository": "Synerise/synerise-design",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"react-intl": ">=3.12.0 <= 6.8",
|
|
47
47
|
"styled-components": "^5.3.3"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "35c8f09d6a248f199237766c1f5181f4b3fc88af"
|
|
50
50
|
}
|