gi-component 0.0.1

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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +36 -0
  3. package/dist/dist/index.es.js +2241 -0
  4. package/dist/dist/index.es.js.map +1 -0
  5. package/dist/dist/index.umd.js +2 -0
  6. package/dist/dist/index.umd.js.map +1 -0
  7. package/dist/gi.css +1 -0
  8. package/dist/index.d.ts +1 -0
  9. package/package.json +56 -0
  10. package/packages/components/button/index.ts +5 -0
  11. package/packages/components/button/src/button.vue +59 -0
  12. package/packages/components/button/src/type.ts +15 -0
  13. package/packages/components/card/index.ts +5 -0
  14. package/packages/components/card/src/card.vue +166 -0
  15. package/packages/components/card/src/type.ts +12 -0
  16. package/packages/components/dialog/index.ts +6 -0
  17. package/packages/components/dialog/src/dialog.ts +87 -0
  18. package/packages/components/dialog/src/dialog.vue +122 -0
  19. package/packages/components/dialog/src/type.ts +16 -0
  20. package/packages/components/edit-table/index.ts +5 -0
  21. package/packages/components/edit-table/src/edit-table.vue +207 -0
  22. package/packages/components/edit-table/src/type.ts +69 -0
  23. package/packages/components/form/index.ts +5 -0
  24. package/packages/components/form/src/form.vue +465 -0
  25. package/packages/components/form/src/type.ts +98 -0
  26. package/packages/components/grid/index.ts +8 -0
  27. package/packages/components/grid/src/context.ts +30 -0
  28. package/packages/components/grid/src/grid-item.vue +143 -0
  29. package/packages/components/grid/src/grid.vue +151 -0
  30. package/packages/components/grid/src/hook/use-index.ts +63 -0
  31. package/packages/components/grid/src/hook/use-responsive-state.ts +66 -0
  32. package/packages/components/grid/src/hook/use-responsive-value.ts +36 -0
  33. package/packages/components/grid/src/interface.ts +74 -0
  34. package/packages/components/grid/src/type.ts +0 -0
  35. package/packages/components/grid/src/utils/global-config.ts +6 -0
  36. package/packages/components/grid/src/utils/index.ts +73 -0
  37. package/packages/components/grid/src/utils/is.ts +9 -0
  38. package/packages/components/grid/src/utils/responsive-observe.ts +135 -0
  39. package/packages/components/input-group/index.ts +5 -0
  40. package/packages/components/input-group/src/input-group.vue +92 -0
  41. package/packages/components/input-group/src/type.ts +1 -0
  42. package/packages/components/input-search/index.ts +5 -0
  43. package/packages/components/input-search/src/input-search.vue +62 -0
  44. package/packages/components/input-search/src/type.ts +6 -0
  45. package/packages/components/page-layout/index.ts +5 -0
  46. package/packages/components/page-layout/src/page-layout.vue +180 -0
  47. package/packages/components/page-layout/src/split-button.vue +106 -0
  48. package/packages/components/page-layout/src/type.ts +12 -0
  49. package/packages/components/table/index.ts +5 -0
  50. package/packages/components/table/src/TableColumn.vue +49 -0
  51. package/packages/components/table/src/table.vue +85 -0
  52. package/packages/components/table/src/type.ts +22 -0
  53. package/packages/components/tabs/index.ts +5 -0
  54. package/packages/components/tabs/src/tabs.vue +148 -0
  55. package/packages/components/tabs/src/type.ts +15 -0
  56. package/packages/components.d.ts +26 -0
  57. package/packages/hooks/index.ts +1 -0
  58. package/packages/hooks/useBemClass.ts +11 -0
  59. package/packages/index.ts +78 -0
  60. package/packages/styles/index.scss +176 -0
  61. package/packages/styles/var.scss +1 -0
  62. package/packages/utils/createSelectDialog.ts +67 -0
  63. package/packages/utils/index.ts +1 -0
@@ -0,0 +1,143 @@
1
+ <template>
2
+ <div ref="domRef" :class="classNames" :style="style">
3
+ <slot :overflow="overflow" />
4
+ </div>
5
+ </template>
6
+
7
+ <script lang="ts">
8
+ import type { PropType } from 'vue';
9
+ import type { ResponsiveValue } from './interface';
10
+ import {
11
+ computed,
12
+ defineComponent,
13
+ inject,
14
+ onUnmounted,
15
+ ref,
16
+ toRefs,
17
+ watchEffect
18
+ } from 'vue';
19
+ import {
20
+ GridContextInjectionKey,
21
+ GridDataCollectorInjectionKey
22
+ } from './context';
23
+ import { useIndex } from './hook/use-index';
24
+ import { useResponsiveState } from './hook/use-responsive-state';
25
+ import { resolveItemData } from './utils';
26
+ import { getPrefixCls } from './utils/global-config';
27
+
28
+ /**
29
+ * @version 2.15.0
30
+ * @zh 响应式配置从 `2.18.0` 开始支持,具体配置 [ResponsiveValue](#responsivevalue)
31
+ * @en Responsive configuration has been supported since `2.18.0`, the specific configuration [ResponsiveValue](#responsivevalue)
32
+ */
33
+ export default defineComponent({
34
+ name: 'GridItem',
35
+ props: {
36
+ /**
37
+ * @zh 跨越的格数
38
+ * @en Number of grids spanned
39
+ */
40
+ span: {
41
+ type: [Number, Object] as PropType<number | ResponsiveValue>,
42
+ default: 1
43
+ },
44
+ /**
45
+ * @zh 左侧的间隔格数
46
+ * @en Number of grids on the left
47
+ */
48
+ offset: {
49
+ type: [Number, Object] as PropType<number | ResponsiveValue>,
50
+ default: 0
51
+ },
52
+ /**
53
+ * @zh 是否是后缀元素
54
+ * @en Is it a suffix element
55
+ */
56
+ suffix: {
57
+ type: Boolean,
58
+ default: false
59
+ }
60
+ },
61
+ setup(props) {
62
+ const prefixCls = getPrefixCls('grid-item');
63
+ const domRef = ref<HTMLDivElement>();
64
+ const { computedIndex } = useIndex({
65
+ itemRef: domRef,
66
+ selector: `.${prefixCls}`
67
+ });
68
+ const gridContext = inject(GridContextInjectionKey, {
69
+ overflow: false,
70
+ displayIndexList: [],
71
+ cols: 24,
72
+ colGap: 0
73
+ });
74
+ const gridDataCollector = inject(GridDataCollectorInjectionKey);
75
+ const visible = computed(() =>
76
+ gridContext?.displayIndexList?.includes(computedIndex.value)
77
+ );
78
+ const { span: propSpan, offset: propOffset } = toRefs(props);
79
+ const rSpan = useResponsiveState(propSpan, 1);
80
+ const rOffset = useResponsiveState(propOffset, 0);
81
+ const itemData = computed(() =>
82
+ resolveItemData(gridContext.cols, {
83
+ ...props,
84
+ span: rSpan.value,
85
+ offset: rOffset.value
86
+ })
87
+ );
88
+
89
+ const classNames = computed(() => [prefixCls]);
90
+ const offsetStyle = computed(() => {
91
+ const { offset, span } = itemData.value;
92
+ const { colGap } = gridContext;
93
+ if (offset > 0) {
94
+ const oneSpan = `(100% - ${colGap * (span - 1)}px) / ${span}`;
95
+ return {
96
+ 'margin-left': `calc((${oneSpan} * ${offset}) + ${colGap * offset}px)`
97
+ };
98
+ }
99
+ return {};
100
+ });
101
+ const columnStart = computed(() => {
102
+ const { suffix, span } = itemData.value;
103
+ const { cols } = gridContext;
104
+ if (suffix) {
105
+ return `${cols - span + 1}`;
106
+ }
107
+ return `span ${span}`;
108
+ });
109
+ const style = computed(() => {
110
+ const { span } = itemData.value;
111
+ if (domRef.value) {
112
+ return [
113
+ {
114
+ 'grid-column': `${columnStart.value} / span ${span}`
115
+ },
116
+ offsetStyle.value,
117
+ !visible.value || span === 0 ? { display: 'none' } : {}
118
+ ];
119
+ }
120
+ return [];
121
+ });
122
+
123
+ watchEffect(() => {
124
+ if (computedIndex.value !== -1) {
125
+ gridDataCollector?.collectItemData(computedIndex.value, itemData.value);
126
+ }
127
+ });
128
+
129
+ onUnmounted(() => {
130
+ if (computedIndex.value !== -1) {
131
+ gridDataCollector?.removeItemData(computedIndex.value);
132
+ }
133
+ });
134
+
135
+ return {
136
+ classNames,
137
+ style,
138
+ domRef,
139
+ overflow: computed(() => gridContext.overflow)
140
+ };
141
+ }
142
+ });
143
+ </script>
@@ -0,0 +1,151 @@
1
+ <template>
2
+ <div :class="classNames" :style="style">
3
+ <slot></slot>
4
+ </div>
5
+ </template>
6
+
7
+ <script lang="ts">
8
+ import type { PropType } from 'vue';
9
+ import type { GridItemData, ResponsiveValue } from './interface';
10
+ import {
11
+ computed,
12
+ defineComponent,
13
+ provide,
14
+ reactive,
15
+ toRefs,
16
+ watchEffect
17
+ } from 'vue';
18
+ import {
19
+ GridContextInjectionKey,
20
+ GridDataCollectorInjectionKey
21
+ } from './context';
22
+ import { useResponsiveState } from './hook/use-responsive-state';
23
+ import { setItemVisible } from './utils';
24
+ import { getPrefixCls } from './utils/global-config';
25
+
26
+ /**
27
+ * @version 2.15.0
28
+ * @zh 响应式配置从 `2.18.0` 开始支持,具体配置 [ResponsiveValue](#responsivevalue)
29
+ * @en Responsive configuration has been supported since `2.18.0`, the specific configuration [ResponsiveValue](#responsivevalue)
30
+ */
31
+ export default defineComponent({
32
+ name: 'Grid',
33
+ props: {
34
+ /**
35
+ * @zh 每一行展示的列数
36
+ * @en Number of columns displayed in each row
37
+ */
38
+ cols: {
39
+ type: [Number, Object] as PropType<number | ResponsiveValue>,
40
+ default: 24
41
+ },
42
+ /**
43
+ * @zh 行与行之间的间距
44
+ * @en The space in row-to-row
45
+ */
46
+ rowGap: {
47
+ type: [Number, Object] as PropType<number | ResponsiveValue>,
48
+ default: 0
49
+ },
50
+ /**
51
+ * @zh 列与列之间的间距
52
+ * @en The space in column-to-column
53
+ */
54
+ colGap: {
55
+ type: [Number, Object] as PropType<number | ResponsiveValue>,
56
+ default: 0
57
+ },
58
+ /**
59
+ * @zh 是否折叠
60
+ * @en Whether to collapsed
61
+ */
62
+ collapsed: {
63
+ type: Boolean,
64
+ default: false
65
+ },
66
+ /**
67
+ * @zh 折叠时显示的行数
68
+ * @en Number of rows displayed when collapsed
69
+ */
70
+ collapsedRows: {
71
+ type: Number,
72
+ default: 1
73
+ }
74
+ },
75
+ setup(props) {
76
+ const {
77
+ cols: propCols,
78
+ rowGap: propRowGap,
79
+ colGap: propColGap,
80
+ collapsedRows,
81
+ collapsed
82
+ } = toRefs(props);
83
+ const cols = useResponsiveState(propCols, 24);
84
+ const colGap = useResponsiveState(propColGap, 0);
85
+ const rowGap = useResponsiveState(propRowGap, 0);
86
+ const prefixCls = getPrefixCls('grid');
87
+ const classNames = computed(() => [prefixCls]);
88
+ const style = computed(() => [
89
+ {
90
+ gap: `${rowGap.value}px ${colGap.value}px`,
91
+ 'grid-template-columns': `repeat(${cols.value}, minmax(0px, 1fr))`
92
+ }
93
+ ]);
94
+ const itemDataMap = reactive<Map<number, GridItemData>>(new Map());
95
+ const itemDataList = computed(() => {
96
+ const list: GridItemData[] = [];
97
+ for (const [index, itemData] of itemDataMap.entries()) {
98
+ list[index] = itemData;
99
+ }
100
+ return list;
101
+ });
102
+ const gridContext = reactive<{
103
+ overflow: boolean;
104
+ displayIndexList: number[];
105
+ cols: number;
106
+ colGap: number;
107
+ }>({
108
+ overflow: false,
109
+ displayIndexList: [],
110
+ cols: cols.value,
111
+ colGap: colGap.value
112
+ });
113
+
114
+ watchEffect(() => {
115
+ gridContext.cols = cols.value;
116
+ gridContext.colGap = colGap.value;
117
+ });
118
+ watchEffect(() => {
119
+ const displayInfo = setItemVisible({
120
+ cols: cols.value,
121
+ collapsed: collapsed.value,
122
+ collapsedRows: collapsedRows.value,
123
+ itemDataList: itemDataList.value
124
+ });
125
+ gridContext.overflow = displayInfo.overflow;
126
+ gridContext.displayIndexList = displayInfo.displayIndexList;
127
+ });
128
+
129
+ provide(GridContextInjectionKey, gridContext);
130
+ provide(GridDataCollectorInjectionKey, {
131
+ collectItemData(index, itemData) {
132
+ itemDataMap.set(index, itemData);
133
+ },
134
+ removeItemData(index) {
135
+ itemDataMap.delete(index);
136
+ }
137
+ });
138
+
139
+ return {
140
+ classNames,
141
+ style
142
+ };
143
+ }
144
+ });
145
+ </script>
146
+
147
+ <style lang="scss" scoped>
148
+ .gi-grid {
149
+ display: grid;
150
+ }
151
+ </style>
@@ -0,0 +1,63 @@
1
+ import type { Ref } from 'vue';
2
+ import { computed, onMounted, onUpdated, ref, watch } from 'vue';
3
+
4
+ function isUndefined(obj: any): obj is undefined {
5
+ return obj === undefined;
6
+ }
7
+
8
+ export function useIndex({
9
+ itemRef,
10
+ selector,
11
+ index,
12
+ parentClassName
13
+ }: {
14
+ itemRef: Ref<HTMLElement | undefined>;
15
+ selector: string;
16
+ index?: Ref<number | undefined>;
17
+ parentClassName?: string;
18
+ }) {
19
+ const _index = ref(-1);
20
+ const computedIndex = computed(() => index?.value ?? _index.value);
21
+
22
+ const parent = ref<HTMLElement>();
23
+
24
+ const getParent = () => {
25
+ let parent = itemRef.value?.parentElement ?? undefined;
26
+ if (parentClassName) {
27
+ while (parent && !parent.className.includes(parentClassName)) {
28
+ parent = parent.parentElement ?? undefined;
29
+ }
30
+ }
31
+ return parent;
32
+ };
33
+
34
+ const getIndex = () => {
35
+ if (isUndefined(index?.value) && parent.value && itemRef.value) {
36
+ const index = Array.from(parent.value.querySelectorAll(selector)).indexOf(
37
+ itemRef.value
38
+ );
39
+ if (index !== _index.value) {
40
+ _index.value = index;
41
+ }
42
+ }
43
+ };
44
+
45
+ watch(itemRef, () => {
46
+ if (itemRef.value && !parent.value) {
47
+ parent.value = getParent();
48
+ }
49
+ });
50
+
51
+ onMounted(() => {
52
+ if (itemRef.value) {
53
+ parent.value = getParent();
54
+ }
55
+ getIndex();
56
+ });
57
+
58
+ onUpdated(() => getIndex());
59
+
60
+ return {
61
+ computedIndex
62
+ };
63
+ }
@@ -0,0 +1,66 @@
1
+ import type { Ref } from 'vue';
2
+ import type { ResponsiveValue } from '../interface';
3
+ import type { ScreenMap } from '../utils/responsive-observe';
4
+ import { computed, onMounted, onUnmounted, ref } from 'vue';
5
+ import { isObject } from '../utils/is';
6
+ import ResponsiveObserve, {
7
+ responsiveArray
8
+ } from '../utils/responsive-observe';
9
+
10
+ function isResponsiveValue(
11
+ val: number | ResponsiveValue
12
+ ): val is ResponsiveValue {
13
+ return isObject(val);
14
+ }
15
+
16
+ export function useResponsiveState(
17
+ val: Ref<number | ResponsiveValue>,
18
+ defaultVal: number,
19
+ fallbackToXs = false
20
+ ) {
21
+ const screens = ref<ScreenMap>({
22
+ xs: true,
23
+ sm: true,
24
+ md: true,
25
+ lg: true,
26
+ xl: true,
27
+ xxl: true
28
+ });
29
+ const result = computed(() => {
30
+ let res = defaultVal;
31
+ if (isResponsiveValue(val.value)) {
32
+ for (let i = 0; i < responsiveArray.length; i++) {
33
+ const breakpoint = responsiveArray[i];
34
+ if (
35
+ (screens.value[breakpoint] ||
36
+ (breakpoint === 'xs' && fallbackToXs)) &&
37
+ val.value[breakpoint] !== undefined
38
+ ) {
39
+ res = val.value[breakpoint] as number;
40
+ break;
41
+ }
42
+ }
43
+ } else {
44
+ res = val.value;
45
+ }
46
+ return res;
47
+ });
48
+
49
+ let subscribeToken = '';
50
+
51
+ onMounted(() => {
52
+ subscribeToken = ResponsiveObserve.subscribe(screensVal => {
53
+ if (isResponsiveValue(val.value)) {
54
+ screens.value = screensVal;
55
+ }
56
+ });
57
+ });
58
+
59
+ onUnmounted(() => {
60
+ if (subscribeToken) {
61
+ ResponsiveObserve.unsubscribe(subscribeToken);
62
+ }
63
+ });
64
+
65
+ return result;
66
+ }
@@ -0,0 +1,36 @@
1
+ import type { Ref } from 'vue';
2
+ import type { ResponsiveValue } from '../interface';
3
+ import { computed } from 'vue';
4
+ import { isNumber, isObject } from '../utils/is';
5
+ import { responsiveArray } from '../utils/responsive-observe';
6
+
7
+ export function useResponsiveValue(
8
+ props: Ref<{
9
+ val: number;
10
+ key: string;
11
+ xs?: number | { [key: string]: any };
12
+ sm?: number | { [key: string]: any };
13
+ md?: number | { [key: string]: any };
14
+ lg?: number | { [key: string]: any };
15
+ xl?: number | { [key: string]: any };
16
+ xxl?: number | { [key: string]: any };
17
+ }>
18
+ ) {
19
+ const value = computed(() => {
20
+ const { val, key, xs, sm, md, lg, xl, xxl } = props.value;
21
+ if (!xs && !sm && !md && !lg && !xl && !xxl) {
22
+ return val;
23
+ }
24
+ const result: ResponsiveValue = {};
25
+ responsiveArray.forEach(breakpoint => {
26
+ const config = props.value[breakpoint];
27
+ if (isNumber(config)) {
28
+ result[breakpoint] = config;
29
+ } else if (isObject(config) && isNumber(config[key])) {
30
+ result[breakpoint] = config[key];
31
+ }
32
+ });
33
+ return result;
34
+ });
35
+ return value;
36
+ }
@@ -0,0 +1,74 @@
1
+ export interface ResponsiveValue {
2
+ /**
3
+ * @zh >= 1600px 响应式配置
4
+ * @en >= 1600px responsive configuration
5
+ */
6
+ xxl?: number;
7
+ /**
8
+ * @zh >= 1200px 响应式配置
9
+ * @en >= 1200px responsive configuration
10
+ */
11
+ xl?: number;
12
+ /**
13
+ * @zh >= 992px 响应式配置
14
+ * @en >= 992px responsive configuration
15
+ */
16
+ lg?: number;
17
+ /**
18
+ * @zh >= 768px 响应式配置
19
+ * @en >= 768px responsive configuration
20
+ */
21
+ md?: number;
22
+ /**
23
+ * @zh >= 576px 响应式配置
24
+ * @en >= 576px responsive configuration
25
+ */
26
+ sm?: number;
27
+ /**
28
+ * @zh < 576px 响应式配置
29
+ * @en <576px responsive configuration
30
+ */
31
+ xs?: number;
32
+ }
33
+
34
+ export type FlexType = number | string | 'initial' | 'auto' | 'none';
35
+
36
+ export interface RowProps {
37
+ gutter?: number | ResponsiveValue | ResponsiveValue[];
38
+ justify?: 'start' | 'center' | 'end' | 'space-around' | 'space-between';
39
+ align?: 'start' | 'center' | 'end' | 'stretch';
40
+ div?: boolean;
41
+ wrap?: boolean;
42
+ }
43
+
44
+ export interface ColProps {
45
+ span?: number;
46
+ offset?: number | undefined;
47
+ order?: number | undefined;
48
+ xs?: number | { [key: string]: any } | undefined;
49
+ sm?: number | { [key: string]: any } | undefined;
50
+ md?: number | { [key: string]: any } | undefined;
51
+ lg?: number | { [key: string]: any } | undefined;
52
+ xl?: number | { [key: string]: any } | undefined;
53
+ xxl?: number | { [key: string]: any } | undefined;
54
+ flex?: number | string | 'initial' | 'auto' | 'none' | undefined;
55
+ }
56
+
57
+ export interface GridProps {
58
+ cols?: number | ResponsiveValue;
59
+ rowGap?: number | ResponsiveValue;
60
+ colGap?: number | ResponsiveValue;
61
+ collapsed?: boolean;
62
+ collapsedRows?: number;
63
+ }
64
+
65
+ export interface GridItemProps {
66
+ span?: number | ResponsiveValue;
67
+ offset?: number | ResponsiveValue;
68
+ suffix?: boolean;
69
+ }
70
+
71
+ export interface GridItemData extends GridItemProps {
72
+ span: number;
73
+ offset: number;
74
+ }
File without changes
@@ -0,0 +1,6 @@
1
+ import { useBemClass } from '../../../../hooks';
2
+
3
+ export function getPrefixCls(name: string) {
4
+ const { b } = useBemClass();
5
+ return b(name);
6
+ }
@@ -0,0 +1,73 @@
1
+ import type { GridItemData } from '../interface';
2
+
3
+ export function resolveItemData(
4
+ cols: number,
5
+ props: GridItemData
6
+ ): GridItemData {
7
+ const originSpan = props.span ?? 1;
8
+ const originOffset = props.offset ?? 0;
9
+ const offset = Math.min(originOffset, cols);
10
+ const span = Math.min(
11
+ offset > 0 ? originSpan + originOffset : originSpan,
12
+ cols
13
+ );
14
+ return {
15
+ span,
16
+ offset,
17
+ suffix: 'suffix' in props ? props.suffix !== false : false
18
+ };
19
+ }
20
+
21
+ export function setItemVisible({
22
+ cols,
23
+ collapsed,
24
+ collapsedRows,
25
+ itemDataList
26
+ }: {
27
+ cols: number;
28
+ collapsed: boolean;
29
+ collapsedRows: number;
30
+ itemDataList: GridItemData[];
31
+ }) {
32
+ let overflow = false;
33
+ let displayIndexList: number[] = [];
34
+
35
+ function isOverflow(span: number) {
36
+ return Math.ceil(span / cols) > collapsedRows;
37
+ }
38
+
39
+ if (collapsed) {
40
+ let spanSum = 0;
41
+ for (let i = 0; i < itemDataList.length; i++) {
42
+ if (itemDataList[i].suffix) {
43
+ spanSum += itemDataList[i].span;
44
+ displayIndexList.push(i);
45
+ }
46
+ }
47
+ if (!isOverflow(spanSum)) {
48
+ let current = 0;
49
+ while (current < itemDataList.length) {
50
+ const item = itemDataList[current];
51
+ if (!item.suffix) {
52
+ spanSum += item.span;
53
+
54
+ if (isOverflow(spanSum)) {
55
+ break;
56
+ }
57
+ displayIndexList.push(current);
58
+ }
59
+ current++;
60
+ }
61
+ }
62
+ overflow = itemDataList.some(
63
+ (item, index) => !item.suffix && !displayIndexList.includes(index)
64
+ );
65
+ } else {
66
+ displayIndexList = itemDataList.map((_, index) => index);
67
+ }
68
+
69
+ return {
70
+ overflow,
71
+ displayIndexList
72
+ };
73
+ }
@@ -0,0 +1,9 @@
1
+ const opt = Object.prototype.toString;
2
+
3
+ export function isObject(obj: unknown): obj is Record<string, any> {
4
+ return opt.call(obj) === '[object Object]';
5
+ }
6
+
7
+ export function isNumber(obj: any): obj is number {
8
+ return opt.call(obj) === '[object Number]' && obj === obj; // eslint-disable-line
9
+ }