@konomi-app/kintone-utilities 1.4.0 → 1.6.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/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/loading-overlay/index.d.ts +23 -0
- package/dist/loading-overlay/index.js +132 -0
- package/dist/loading-overlay/index.js.map +1 -0
- package/dist/utilities.d.ts +5 -1
- package/dist/utilities.js +8 -0
- package/dist/utilities.js.map +1 -1
- package/dist/utility-types.d.ts +2 -0
- package/dist/utility-types.js +2 -0
- package/dist/utility-types.js.map +1 -0
- package/package.json +4 -3
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kBAAkB,CAAC;AACjC,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type ConstructorProps = Readonly<Partial<{
|
|
2
|
+
label: string;
|
|
3
|
+
progress: number;
|
|
4
|
+
}>>;
|
|
5
|
+
export declare class LoadingOverlay {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(props?: ConstructorProps);
|
|
8
|
+
start(): void;
|
|
9
|
+
stop(): void;
|
|
10
|
+
set label(label: string);
|
|
11
|
+
set progress(progress: number);
|
|
12
|
+
private render;
|
|
13
|
+
/** JavaScript中にページを離れようとした場合にアラートを表示します */
|
|
14
|
+
private beforeunload;
|
|
15
|
+
private addStyle;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* ${({ shown }) => (shown ? 'animation: appear 150ms ease 0s 1 forwards;' : '')};
|
|
19
|
+
pointer-events: ${({ shown }) => (shown ? 'initial' : 'none')};
|
|
20
|
+
*/
|
|
21
|
+
/** ロード画面操作用クラスのシングルトン */
|
|
22
|
+
export declare const loadingOverlay: LoadingOverlay;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { css } from '@emotion/css';
|
|
2
|
+
const ROOT_ID = '__🐸__loading-overlay';
|
|
3
|
+
export class LoadingOverlay {
|
|
4
|
+
#shown;
|
|
5
|
+
#label;
|
|
6
|
+
#progress;
|
|
7
|
+
#root;
|
|
8
|
+
constructor(props = {}) {
|
|
9
|
+
this.#shown = false;
|
|
10
|
+
this.#label = props.label || '';
|
|
11
|
+
this.#progress = props.progress ?? null;
|
|
12
|
+
this.addStyle();
|
|
13
|
+
const root = document.querySelector(`#${ROOT_ID}`) || document.createElement('div');
|
|
14
|
+
root.id = ROOT_ID;
|
|
15
|
+
this.#root = root;
|
|
16
|
+
document.body.append(root);
|
|
17
|
+
this.render();
|
|
18
|
+
}
|
|
19
|
+
start() {
|
|
20
|
+
this.#shown = true;
|
|
21
|
+
window.removeEventListener('beforeunload', this.beforeunload);
|
|
22
|
+
this.render();
|
|
23
|
+
}
|
|
24
|
+
stop() {
|
|
25
|
+
this.#shown = false;
|
|
26
|
+
window.removeEventListener('beforeunload', this.beforeunload);
|
|
27
|
+
this.render();
|
|
28
|
+
}
|
|
29
|
+
set label(label) {
|
|
30
|
+
this.#label = label;
|
|
31
|
+
this.render();
|
|
32
|
+
}
|
|
33
|
+
set progress(progress) {
|
|
34
|
+
this.#progress = progress;
|
|
35
|
+
this.render();
|
|
36
|
+
}
|
|
37
|
+
render() {
|
|
38
|
+
if (this.#shown) {
|
|
39
|
+
this.#root.innerHTML = `
|
|
40
|
+
<div>
|
|
41
|
+
<div class="loader"></div>
|
|
42
|
+
<div>${this.#label}</div>
|
|
43
|
+
</div>`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** JavaScript中にページを離れようとした場合にアラートを表示します */
|
|
47
|
+
beforeunload(event) {
|
|
48
|
+
event.preventDefault();
|
|
49
|
+
event.returnValue = '';
|
|
50
|
+
}
|
|
51
|
+
addStyle() {
|
|
52
|
+
document.body.classList.add(css `
|
|
53
|
+
#${ROOT_ID} {
|
|
54
|
+
font-family: 'Yu Gothic Medium', '游ゴシック', YuGothic, 'メイリオ',
|
|
55
|
+
'Hiragino Kaku Gothic ProN', Meiryo, sans-serif;
|
|
56
|
+
color: #356;
|
|
57
|
+
font-size: 17px;
|
|
58
|
+
|
|
59
|
+
overflow: hidden;
|
|
60
|
+
background-color: #fff6;
|
|
61
|
+
backdrop-filter: blur(10px);
|
|
62
|
+
box-sizing: content-box;
|
|
63
|
+
|
|
64
|
+
position: fixed;
|
|
65
|
+
inset: 0;
|
|
66
|
+
width: 100vw;
|
|
67
|
+
height: 100vh;
|
|
68
|
+
|
|
69
|
+
display: grid;
|
|
70
|
+
place-items: center;
|
|
71
|
+
transition: all 250ms ease;
|
|
72
|
+
z-index: 1000;
|
|
73
|
+
|
|
74
|
+
@keyframes appear {
|
|
75
|
+
from {
|
|
76
|
+
opacity: 0;
|
|
77
|
+
}
|
|
78
|
+
to {
|
|
79
|
+
opacity: 1;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
> div {
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-direction: column;
|
|
86
|
+
align-items: center;
|
|
87
|
+
justify-content: center;
|
|
88
|
+
gap: 16px;
|
|
89
|
+
padding: 32px 64px;
|
|
90
|
+
background-color: #fffc;
|
|
91
|
+
border: 1px solid #fff;
|
|
92
|
+
border-radius: 8px;
|
|
93
|
+
box-shadow: 0 5px 24px -6px #0002;
|
|
94
|
+
min-width: 300px;
|
|
95
|
+
max-width: 90vw;
|
|
96
|
+
min-height: 200px;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.loader {
|
|
100
|
+
font-size: 48px;
|
|
101
|
+
width: 1em;
|
|
102
|
+
height: 1em;
|
|
103
|
+
position: relative;
|
|
104
|
+
border: 2px solid #2563ebaa;
|
|
105
|
+
animation: spin 2s infinite ease;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@keyframes spin {
|
|
109
|
+
0% {
|
|
110
|
+
transform: rotate(0deg);
|
|
111
|
+
border-radius: 1em;
|
|
112
|
+
}
|
|
113
|
+
30%,
|
|
114
|
+
60% {
|
|
115
|
+
border-radius: 0.25em;
|
|
116
|
+
}
|
|
117
|
+
100% {
|
|
118
|
+
transform: rotate(180deg);
|
|
119
|
+
border-radius: 1em;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* ${({ shown }) => (shown ? 'animation: appear 150ms ease 0s 1 forwards;' : '')};
|
|
128
|
+
pointer-events: ${({ shown }) => (shown ? 'initial' : 'none')};
|
|
129
|
+
*/
|
|
130
|
+
/** ロード画面操作用クラスのシングルトン */
|
|
131
|
+
export const loadingOverlay = new LoadingOverlay();
|
|
132
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/loading-overlay/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAInC,MAAM,OAAO,GAAG,uBAAuB,CAAC;AAExC,MAAM,OAAO,cAAc;IACzB,MAAM,CAAU;IAChB,MAAM,CAAS;IACf,SAAS,CAAgB;IACzB,KAAK,CAAiB;IAEtB,YAAmB,QAA0B,EAAE;QAC7C,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;QAChC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC;QAExC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEhB,MAAM,IAAI,GACR,QAAQ,CAAC,aAAa,CAAiB,IAAI,OAAO,EAAE,CAAC,IAAI,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QACzF,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAEM,KAAK;QACV,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,MAAM,CAAC,mBAAmB,CAAC,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAEM,IAAI;QACT,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,MAAM,CAAC,mBAAmB,CAAC,cAAc,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAED,IAAW,KAAK,CAAC,KAAa;QAC5B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAED,IAAW,QAAQ,CAAC,QAAgB;QAClC,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,IAAI,CAAC,MAAM,EAAE,CAAC;IAChB,CAAC;IAEO,MAAM;QACZ,IAAI,IAAI,CAAC,MAAM,EAAE;YACf,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG;;;eAGd,IAAI,CAAC,MAAM;aACb,CAAC;SACT;IACH,CAAC;IAED,2CAA2C;IACnC,YAAY,CAAC,KAAwB;QAC3C,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,KAAK,CAAC,WAAW,GAAG,EAAE,CAAC;IACzB,CAAC;IAEO,QAAQ;QACd,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAA;SAC1B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsEX,CAAC,CAAC;IACL,CAAC;CACF;AAED;;;GAGG;AAEH,yBAAyB;AACzB,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC"}
|
package/dist/utilities.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { kintoneAPI } from './api-types';
|
|
2
|
+
import type { SavedFields } from './utility-types';
|
|
2
3
|
/**
|
|
3
4
|
* 各フィールドタイプの値を文字列として返却します
|
|
4
5
|
*
|
|
@@ -7,10 +8,13 @@ import type { kintoneAPI } from './api-types';
|
|
|
7
8
|
* @param options
|
|
8
9
|
* @returns
|
|
9
10
|
*/
|
|
10
|
-
export declare const getFieldValueAsString: (field: kintoneAPI.Field, options?: {
|
|
11
|
+
export declare const getFieldValueAsString: (field: kintoneAPI.Field | SavedFields, options?: {
|
|
11
12
|
separator?: string;
|
|
12
13
|
ignoresCalculationError?: boolean;
|
|
13
14
|
}) => string;
|
|
15
|
+
export declare const compareField: (field1: kintoneAPI.Field, field2: kintoneAPI.Field, options?: {
|
|
16
|
+
ignoresType?: boolean;
|
|
17
|
+
}) => boolean;
|
|
14
18
|
/**
|
|
15
19
|
* デスクトップ版のイベントタイプを基に、モバイル版を追加し返却します
|
|
16
20
|
* @param events デスクトップのイベントタイプ
|
package/dist/utilities.js
CHANGED
|
@@ -59,6 +59,14 @@ export const getFieldValueAsString = (field, options) => {
|
|
|
59
59
|
}
|
|
60
60
|
return '';
|
|
61
61
|
};
|
|
62
|
+
export const compareField = (field1, field2, options) => {
|
|
63
|
+
const { ignoresType = false } = options ?? {};
|
|
64
|
+
if (!ignoresType && field1.type !== field2.type) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
const separator = '$';
|
|
68
|
+
return (getFieldValueAsString(field1, { separator }) === getFieldValueAsString(field2, { separator }));
|
|
69
|
+
};
|
|
62
70
|
/**
|
|
63
71
|
* デスクトップ版のイベントタイプを基に、モバイル版を追加し返却します
|
|
64
72
|
* @param events デスクトップのイベントタイプ
|
package/dist/utilities.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utilities.js","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utilities.js","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/** kintone.fieldTypes以下のプロパティをすべて参照する */
|
|
2
|
+
export type SavedFields = kintone.fieldTypes.Calc | kintone.fieldTypes.CheckBox | kintone.fieldTypes.CreatedTime | kintone.fieldTypes.Creator | kintone.fieldTypes.Date | kintone.fieldTypes.DateTime | kintone.fieldTypes.DropDown | kintone.fieldTypes.File | kintone.fieldTypes.GroupSelect | kintone.fieldTypes.Id | kintone.fieldTypes.Link | kintone.fieldTypes.Modifier | kintone.fieldTypes.MultiLineText | kintone.fieldTypes.MultiSelect | kintone.fieldTypes.Number | kintone.fieldTypes.OrganizationSelect | kintone.fieldTypes.RadioButton | kintone.fieldTypes.RecordNumber | kintone.fieldTypes.Revision | kintone.fieldTypes.RichText | kintone.fieldTypes.SingleLineText | kintone.fieldTypes.Time | kintone.fieldTypes.UpdatedTime | kintone.fieldTypes.UserSelect;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utility-types.js","sourceRoot":"","sources":["../src/utility-types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konomi-app/kintone-utilities",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"types": "dist/index.d.ts",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"repository": "https://github.com/local-bias/kintone-utilities.git",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"prepare": "yarn run build"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@
|
|
14
|
+
"@emotion/css": "^11.10.6",
|
|
15
|
+
"@kintone/rest-api-client": "^3.3.4"
|
|
15
16
|
},
|
|
16
17
|
"devDependencies": {
|
|
17
18
|
"@kintone/dts-gen": "^6.1.21",
|
|
@@ -26,4 +27,4 @@
|
|
|
26
27
|
"trailingComma": "es5",
|
|
27
28
|
"endOfLine": "lf"
|
|
28
29
|
}
|
|
29
|
-
}
|
|
30
|
+
}
|