support display format in number and calc fields.

This commit is contained in:
2025-05-31 21:45:13 +09:00
parent 5bc9976566
commit 4024914831
5 changed files with 233 additions and 139 deletions

181
package-lock.json generated
View File

@ -12,6 +12,7 @@
"angular-expressions": "^1.4.3", "angular-expressions": "^1.4.3",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"core-js": "^3.42.0", "core-js": "^3.42.0",
"dayjs": "^1.11.13",
"docxtemplater": "^3.63.2", "docxtemplater": "^3.63.2",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"moize": "^6.1.6", "moize": "^6.1.6",
@ -26,8 +27,8 @@
"@kintone/dts-gen": "^8.1.2", "@kintone/dts-gen": "^8.1.2",
"@kintone/plugin-uploader": "^9.1.5", "@kintone/plugin-uploader": "^9.1.5",
"@kintone/webpack-plugin-kintone-plugin": "^8.0.11", "@kintone/webpack-plugin-kintone-plugin": "^8.0.11",
"@rspack/cli": "^1.3.12", "@rspack/cli": "^1.3.13",
"@rspack/core": "^1.3.12", "@rspack/core": "^1.3.13",
"@shin-chan/kypes": "^0.0.7", "@shin-chan/kypes": "^0.0.7",
"@swc/helpers": "^0.5.17", "@swc/helpers": "^0.5.17",
"@types/file-saver": "^2.0.7", "@types/file-saver": "^2.0.7",
@ -36,7 +37,7 @@
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"css-loader": "^7.1.2", "css-loader": "^7.1.2",
"env-cmd": "^10.1.0", "env-cmd": "^10.1.0",
"eslint": "^9.27.0", "eslint": "^9.28.0",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prettier": "^3.5.3", "prettier": "^3.5.3",
@ -363,9 +364,9 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.27.0", "version": "9.28.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz",
"integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==", "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@ -968,62 +969,62 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@module-federation/error-codes": { "node_modules/@module-federation/error-codes": {
"version": "0.14.0", "version": "0.14.3",
"resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.14.0.tgz", "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.14.3.tgz",
"integrity": "sha512-GGk+EoeSACJikZZyShnLshtq9E2eCrDWbRiB4QAFXCX4oYmGgFfzXlx59vMNwqTKPJWxkEGnPYacJMcr2YYjag==", "integrity": "sha512-sBJ3XKU9g5Up31jFeXPFsD8AgORV7TLO/cCSMuRewSfgYbG/3vSKLJmfHrO6+PvjZSb9VyV2UaF02ojktW65vw==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@module-federation/runtime": { "node_modules/@module-federation/runtime": {
"version": "0.14.0", "version": "0.14.3",
"resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.14.0.tgz", "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.14.3.tgz",
"integrity": "sha512-kR3cyHw/Y64SEa7mh4CHXOEQYY32LKLK75kJOmBroLNLO7/W01hMNAvGBYTedS7hWpVuefPk1aFZioy3q2VLdQ==", "integrity": "sha512-7ZHpa3teUDVhraYdxQGkfGHzPbjna4LtwbpudgzAxSLLFxLDNanaxCuSeIgSM9c+8sVUNC9kvzUgJEZB0krPJw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@module-federation/error-codes": "0.14.0", "@module-federation/error-codes": "0.14.3",
"@module-federation/runtime-core": "0.14.0", "@module-federation/runtime-core": "0.14.3",
"@module-federation/sdk": "0.14.0" "@module-federation/sdk": "0.14.3"
} }
}, },
"node_modules/@module-federation/runtime-core": { "node_modules/@module-federation/runtime-core": {
"version": "0.14.0", "version": "0.14.3",
"resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.14.0.tgz", "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.14.3.tgz",
"integrity": "sha512-fGE1Ro55zIFDp/CxQuRhKQ1pJvG7P0qvRm2N+4i8z++2bgDjcxnCKUqDJ8lLD+JfJQvUJf0tuSsJPgevzueD4g==", "integrity": "sha512-xMFQXflLVW/AJTWb4soAFP+LB4XuhE7ryiLIX8oTyUoBBgV6U2OPghnFljPjeXbud72O08NYlQ1qsHw1kN/V8Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@module-federation/error-codes": "0.14.0", "@module-federation/error-codes": "0.14.3",
"@module-federation/sdk": "0.14.0" "@module-federation/sdk": "0.14.3"
} }
}, },
"node_modules/@module-federation/runtime-tools": { "node_modules/@module-federation/runtime-tools": {
"version": "0.14.0", "version": "0.14.3",
"resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.14.0.tgz", "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.14.3.tgz",
"integrity": "sha512-y/YN0c2DKsLETE+4EEbmYWjqF9G6ZwgZoDIPkaQ9p0pQu0V4YxzWfQagFFxR0RigYGuhJKmSU/rtNoHq+qF8jg==", "integrity": "sha512-QBETX7iMYXdSa3JtqFlYU+YkpymxETZqyIIRiqg0gW+XGpH3jgU68yjrme2NBJp7URQi/CFZG8KWtfClk0Pjgw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@module-federation/runtime": "0.14.0", "@module-federation/runtime": "0.14.3",
"@module-federation/webpack-bundler-runtime": "0.14.0" "@module-federation/webpack-bundler-runtime": "0.14.3"
} }
}, },
"node_modules/@module-federation/sdk": { "node_modules/@module-federation/sdk": {
"version": "0.14.0", "version": "0.14.3",
"resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.14.0.tgz", "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.14.3.tgz",
"integrity": "sha512-lg/OWRsh18hsyTCamOOhEX546vbDiA2O4OggTxxH2wTGr156N6DdELGQlYIKfRdU/0StgtQS81Goc0BgDZlx9A==", "integrity": "sha512-THJZMfbXpqjQOLblCQ8jjcBFFXsGRJwUWE9l/Q4SmuCSKMgAwie7yLT0qSGrHmyBYrsUjAuy+xNB4nfKP0pnGw==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@module-federation/webpack-bundler-runtime": { "node_modules/@module-federation/webpack-bundler-runtime": {
"version": "0.14.0", "version": "0.14.3",
"resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.14.0.tgz", "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.14.3.tgz",
"integrity": "sha512-POWS6cKBicAAQ3DNY5X7XEUSfOfUsRaBNxbuwEfSGlrkTE9UcWheO06QP2ndHi8tHQuUKcIHi2navhPkJ+k5xg==", "integrity": "sha512-hIyJFu34P7bY2NeMIUHAS/mYUHEY71VTAsN0A0AqEJFSVPszheopu9VdXq0VDLrP9KQfuXT8SDxeYeJXyj0mgA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@module-federation/runtime": "0.14.0", "@module-federation/runtime": "0.14.3",
"@module-federation/sdk": "0.14.0" "@module-federation/sdk": "0.14.3"
} }
}, },
"node_modules/@napi-rs/wasm-runtime": { "node_modules/@napi-rs/wasm-runtime": {
@ -1134,27 +1135,27 @@
} }
}, },
"node_modules/@rspack/binding": { "node_modules/@rspack/binding": {
"version": "1.3.12", "version": "1.3.13",
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.3.12.tgz", "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.3.13.tgz",
"integrity": "sha512-4Ic8lV0+LCBfTlH5aIOujIRWZOtgmG223zC4L3o8WY/+ESAgpdnK6lSSMfcYgRanYLAy3HOmFIp20jwskMpbAg==", "integrity": "sha512-BdM6tfLCP7/0H5uGc+okG6AYsU9JEnR5bRHq4YuGaS4tb+N5ct0czm0LprGMZ7zRAnIql/zoLn/bHlheNxZw3g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"optionalDependencies": { "optionalDependencies": {
"@rspack/binding-darwin-arm64": "1.3.12", "@rspack/binding-darwin-arm64": "1.3.13",
"@rspack/binding-darwin-x64": "1.3.12", "@rspack/binding-darwin-x64": "1.3.13",
"@rspack/binding-linux-arm64-gnu": "1.3.12", "@rspack/binding-linux-arm64-gnu": "1.3.13",
"@rspack/binding-linux-arm64-musl": "1.3.12", "@rspack/binding-linux-arm64-musl": "1.3.13",
"@rspack/binding-linux-x64-gnu": "1.3.12", "@rspack/binding-linux-x64-gnu": "1.3.13",
"@rspack/binding-linux-x64-musl": "1.3.12", "@rspack/binding-linux-x64-musl": "1.3.13",
"@rspack/binding-win32-arm64-msvc": "1.3.12", "@rspack/binding-win32-arm64-msvc": "1.3.13",
"@rspack/binding-win32-ia32-msvc": "1.3.12", "@rspack/binding-win32-ia32-msvc": "1.3.13",
"@rspack/binding-win32-x64-msvc": "1.3.12" "@rspack/binding-win32-x64-msvc": "1.3.13"
} }
}, },
"node_modules/@rspack/binding-darwin-arm64": { "node_modules/@rspack/binding-darwin-arm64": {
"version": "1.3.12", "version": "1.3.13",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.3.12.tgz", "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.3.13.tgz",
"integrity": "sha512-8hKjVTBeWPqkMzFPNWIh72oU9O3vFy3e88wRjMPImDCXBiEYrKqGTTLd/J0SO+efdL3SBD1rX1IvdJpxCv6Yrw==", "integrity": "sha512-1c+KC+TFaKRWu+SO4cJZ5oHKOFuDhTIitbSIG9boJpDRoZmJxHDmFyTTxVI2r2QUjxJaDdUlSFepybhhJ3UiPg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1166,9 +1167,9 @@
] ]
}, },
"node_modules/@rspack/binding-darwin-x64": { "node_modules/@rspack/binding-darwin-x64": {
"version": "1.3.12", "version": "1.3.13",
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.3.12.tgz", "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.3.13.tgz",
"integrity": "sha512-Sj4m+mCUxL7oCpdu7OmWT7fpBM7hywk5CM9RDc3D7StaBZbvNtNftafCrTZzTYKuZrKmemTh5SFzT5Tz7tf6GA==", "integrity": "sha512-YBF+XjoGSjhJ5o/xOaCBd39BntMudMeup11j2Dz+rrTH+wG6TvH017HYIgDMT3UBVv66eNsQpzA0ZW5raJ0lbA==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1180,9 +1181,9 @@
] ]
}, },
"node_modules/@rspack/binding-linux-arm64-gnu": { "node_modules/@rspack/binding-linux-arm64-gnu": {
"version": "1.3.12", "version": "1.3.13",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.3.12.tgz", "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.3.13.tgz",
"integrity": "sha512-7MuOxf3/Mhv4mgFdLTvgnt/J+VouNR65DEhorth+RZm3LEWojgoFEphSAMAvpvAOpYSS68Sw4SqsOZi719ia2w==", "integrity": "sha512-II71Ez7Z0/5ZpcK+kCgvXFKK0AysS9La8LNQbqf2wmzxDJi5H8eVUiwkM5BabICxzOWYtTGJLZ89QbCYaFbqCg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1194,9 +1195,9 @@
] ]
}, },
"node_modules/@rspack/binding-linux-arm64-musl": { "node_modules/@rspack/binding-linux-arm64-musl": {
"version": "1.3.12", "version": "1.3.13",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.3.12.tgz", "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.3.13.tgz",
"integrity": "sha512-s6KKj20T9Z1bA8caIjU6EzJbwyDo1URNFgBAlafCT2UC6yX7flstDJJ38CxZacA9A2P24RuQK2/jPSZpWrTUFA==", "integrity": "sha512-JFFhqglKVjlWcmmVwdS80Kw6v35yY9xlQJup09mL8gMtiiFiT36wTyTujz15Iv+2+S/Dv0Z+UeUJ99KRbQxgcQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1208,9 +1209,9 @@
] ]
}, },
"node_modules/@rspack/binding-linux-x64-gnu": { "node_modules/@rspack/binding-linux-x64-gnu": {
"version": "1.3.12", "version": "1.3.13",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.3.12.tgz", "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.3.13.tgz",
"integrity": "sha512-0w/sRREYbRgHgWvs2uMEJSLfvzbZkPHUg6CMcYQGNVK6axYRot6jPyKetyFYA9pR5fB5rsXegpnFaZaVrRIK2g==", "integrity": "sha512-ogm4rt+PMQHkMg/0mA9VTjfGE3c+YaHZQT8KrFgTsoj2YCW9WO2J/RjdMc6STG4Y10BWO9Ar2azLxxHrKb+8UQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1222,9 +1223,9 @@
] ]
}, },
"node_modules/@rspack/binding-linux-x64-musl": { "node_modules/@rspack/binding-linux-x64-musl": {
"version": "1.3.12", "version": "1.3.13",
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.3.12.tgz", "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.3.13.tgz",
"integrity": "sha512-jEdxkPymkRxbijDRsBGdhopcbGXiXDg59lXqIRkVklqbDmZ/O6DHm7gImmlx5q9FoWbz0gqJuOKBz4JqWxjWVA==", "integrity": "sha512-8icDyXhg1iMKhQ3X2FTgAGQTQqnli9FyqHCuRIBauxy1V4W478Mp9Y+V+ErVUY1YxbZEUrkt3a59hssjGeDEeg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1236,9 +1237,9 @@
] ]
}, },
"node_modules/@rspack/binding-win32-arm64-msvc": { "node_modules/@rspack/binding-win32-arm64-msvc": {
"version": "1.3.12", "version": "1.3.13",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.3.12.tgz", "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.3.13.tgz",
"integrity": "sha512-ZRvUCb3TDLClAqcTsl/o9UdJf0B5CgzAxgdbnYJbldyuyMeTUB4jp20OfG55M3C2Nute2SNhu2bOOp9Se5Ongw==", "integrity": "sha512-y5XxwxDW4DrPKy+8P6t7I7IbA7B/iXjLoaS0jP/EwjSHWf/EnZzq9MgWqdop1km8Mwx6s1zcj+0qs73jL2N98w==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@ -1250,9 +1251,9 @@
] ]
}, },
"node_modules/@rspack/binding-win32-ia32-msvc": { "node_modules/@rspack/binding-win32-ia32-msvc": {
"version": "1.3.12", "version": "1.3.13",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.3.12.tgz", "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.3.13.tgz",
"integrity": "sha512-1TKPjuXStPJr14f3ZHuv40Xc/87jUXx10pzVtrPnw+f3hckECHrbYU/fvbVzZyuXbsXtkXpYca6ygCDRJAoNeQ==", "integrity": "sha512-n24sznsZe3lC8ok6MgsT1nG4lVx3SQ/lZ0g23i2BGMRN8/p+kaC2eoPaHe/4m9Liz/W4Z5LhZCCvg4DQMEzeLA==",
"cpu": [ "cpu": [
"ia32" "ia32"
], ],
@ -1264,9 +1265,9 @@
] ]
}, },
"node_modules/@rspack/binding-win32-x64-msvc": { "node_modules/@rspack/binding-win32-x64-msvc": {
"version": "1.3.12", "version": "1.3.13",
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.3.12.tgz", "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.3.13.tgz",
"integrity": "sha512-lCR0JfnYKpV+a6r2A2FdxyUKUS4tajePgpPJN5uXDgMGwrDtRqvx+d0BHhwjFudQVJq9VVbRaL89s2MQ6u+xYw==", "integrity": "sha512-CLyTNo0OrOD7xFKusFciKKG+8CXPowjPz+tcdkkrKYqGzAPzOcszblikITJhMbc7DLMzdTRSZUTkKLRydYH9sw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@ -1278,9 +1279,9 @@
] ]
}, },
"node_modules/@rspack/cli": { "node_modules/@rspack/cli": {
"version": "1.3.12", "version": "1.3.13",
"resolved": "https://registry.npmjs.org/@rspack/cli/-/cli-1.3.12.tgz", "resolved": "https://registry.npmjs.org/@rspack/cli/-/cli-1.3.13.tgz",
"integrity": "sha512-LdajkH+YW2NaWvY0rHs+l6Ip4X1/eQ7J3qVGlV9H5TkXMp3+ldIIw/6W/2sjmf2l4GRobpVASm5U2e58bqiIpg==", "integrity": "sha512-a9zPvSB3OvER+87l6tg+gzh6yhlqz9eHaw4hcogbd14tTJJzBI7nQJDGCf/3J+TEvOxzvuNj2+OvdDD76UU5sw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1301,16 +1302,15 @@
} }
}, },
"node_modules/@rspack/core": { "node_modules/@rspack/core": {
"version": "1.3.12", "version": "1.3.13",
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.3.12.tgz", "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.3.13.tgz",
"integrity": "sha512-mAPmV4LPPRgxpouUrGmAE4kpF1NEWJGyM5coebsjK/zaCMSjw3mkdxiU2b5cO44oIi0Ifv5iGkvwbdrZOvMyFA==", "integrity": "sha512-j9jsNzKeEN14yraqX4jAFrM/nMfX5YEPgEMPlp4g5NAu3siaBa8gDF5brbdNq6TDXnTHK1MwwjaMdKA+3YeBKQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@module-federation/runtime-tools": "0.14.0", "@module-federation/runtime-tools": "0.14.3",
"@rspack/binding": "1.3.12", "@rspack/binding": "1.3.13",
"@rspack/lite-tapable": "1.0.1", "@rspack/lite-tapable": "1.0.1"
"caniuse-lite": "^1.0.30001718"
}, },
"engines": { "engines": {
"node": ">=16.0.0" "node": ">=16.0.0"
@ -3262,7 +3262,8 @@
"url": "https://github.com/sponsors/ai" "url": "https://github.com/sponsors/ai"
} }
], ],
"license": "CC-BY-4.0" "license": "CC-BY-4.0",
"peer": true
}, },
"node_modules/chalk": { "node_modules/chalk": {
"version": "4.1.2", "version": "4.1.2",
@ -3774,6 +3775,12 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/dayjs": {
"version": "1.11.13",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
"integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
"license": "MIT"
},
"node_modules/debounce": { "node_modules/debounce": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
@ -4381,9 +4388,9 @@
} }
}, },
"node_modules/eslint": { "node_modules/eslint": {
"version": "9.27.0", "version": "9.28.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz",
"integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==", "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -4393,7 +4400,7 @@
"@eslint/config-helpers": "^0.2.1", "@eslint/config-helpers": "^0.2.1",
"@eslint/core": "^0.14.0", "@eslint/core": "^0.14.0",
"@eslint/eslintrc": "^3.3.1", "@eslint/eslintrc": "^3.3.1",
"@eslint/js": "9.27.0", "@eslint/js": "9.28.0",
"@eslint/plugin-kit": "^0.3.1", "@eslint/plugin-kit": "^0.3.1",
"@humanfs/node": "^0.16.6", "@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/module-importer": "^1.0.1",

View File

@ -16,6 +16,7 @@
"angular-expressions": "^1.4.3", "angular-expressions": "^1.4.3",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"core-js": "^3.42.0", "core-js": "^3.42.0",
"dayjs": "^1.11.13",
"docxtemplater": "^3.63.2", "docxtemplater": "^3.63.2",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"moize": "^6.1.6", "moize": "^6.1.6",
@ -30,8 +31,8 @@
"@kintone/dts-gen": "^8.1.2", "@kintone/dts-gen": "^8.1.2",
"@kintone/plugin-uploader": "^9.1.5", "@kintone/plugin-uploader": "^9.1.5",
"@kintone/webpack-plugin-kintone-plugin": "^8.0.11", "@kintone/webpack-plugin-kintone-plugin": "^8.0.11",
"@rspack/cli": "^1.3.12", "@rspack/cli": "^1.3.13",
"@rspack/core": "^1.3.12", "@rspack/core": "^1.3.13",
"@shin-chan/kypes": "^0.0.7", "@shin-chan/kypes": "^0.0.7",
"@swc/helpers": "^0.5.17", "@swc/helpers": "^0.5.17",
"@types/file-saver": "^2.0.7", "@types/file-saver": "^2.0.7",
@ -40,7 +41,7 @@
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"css-loader": "^7.1.2", "css-loader": "^7.1.2",
"env-cmd": "^10.1.0", "env-cmd": "^10.1.0",
"eslint": "^9.27.0", "eslint": "^9.28.0",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prettier": "^3.5.3", "prettier": "^3.5.3",

View File

@ -21,6 +21,7 @@ const DynamicPortal: React.FC<DynamicPortalProps> = (props) => {
el.parentNode.removeChild(el); el.parentNode.removeChild(el);
} }
}; };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
return ReactDOM.createPortal(children, el); return ReactDOM.createPortal(children, el);
}; };

View File

@ -3,5 +3,13 @@ import invariant from 'tiny-invariant';
export const PLUGIN_ID = kintone.$PLUGIN_ID; export const PLUGIN_ID = kintone.$PLUGIN_ID;
invariant(PLUGIN_ID, 'The PLUGIN_ID is not available. Please ensure you are on a Kintone plugin page.'); invariant(PLUGIN_ID, 'The PLUGIN_ID is not available. Please ensure you are on a Kintone plugin page.');
export const LANGUAGE = kintone.getLoginUser().language; const KintoneUserLanguages = ['en', 'ja', 'zh', 'zh-TW', 'es', 'pt-BR', 'th'] as const;
invariant(LANGUAGE, 'The LANGUAGE is not available. Please ensure you are on a Kintone plugin page.'); export type KintoneUserLanguages = (typeof KintoneUserLanguages)[number];
export const LANGUAGE = kintone.getLoginUser().language as KintoneUserLanguages;
invariant(
KintoneUserLanguages.includes(LANGUAGE),
`Unsupported language: ${LANGUAGE}. Supported languages are: ${KintoneUserLanguages.join(', ')}`,
);
export const DOCX_CONTENTTYPE = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
export const DOCX_EXTENSION = 'docx';

View File

@ -1,15 +1,16 @@
import React from 'react'; import React from 'react';
import { KintoneRestAPIClient } from '@kintone/rest-api-client'; import { KintoneFormFieldProperty, KintoneRestAPIClient } from '@kintone/rest-api-client';
import { Properties as KintoneFormFieldProperties } from '@kintone/rest-api-client/lib/src/client/types'; import { Properties as KintoneFormFieldProperties } from '@kintone/rest-api-client/lib/src/client/types';
import { KintoneRecord } from '@shin-chan/kypes/types/page'; import { KintoneRecord } from '@shin-chan/kypes/types/page';
import dayjs from 'dayjs';
import Docxtemplater from 'docxtemplater'; import Docxtemplater from 'docxtemplater';
import expressionParser from 'docxtemplater/expressions'; import expressionParser from 'docxtemplater/expressions';
import { saveAs } from 'file-saver'; import { saveAs } from 'file-saver';
import moize from 'moize'; import moize from 'moize';
import PizZip from 'pizzip'; import PizZip from 'pizzip';
import invariant from 'tiny-invariant'; import invariant from 'tiny-invariant';
import { LANGUAGE, PLUGIN_ID } from '../common/global'; import { DOCX_CONTENTTYPE, LANGUAGE, PLUGIN_ID } from '../common/global';
import KintonePluginAlert from '../common/ui/KintonePluginAlert'; import KintonePluginAlert from '../common/ui/KintonePluginAlert';
import KintonePluginButton from '../common/ui/KintonePluginButton'; import KintonePluginButton from '../common/ui/KintonePluginButton';
@ -19,8 +20,6 @@ interface TemplateData {
[key: string]: TemplateData | TemplateData[] | string | string[]; [key: string]: TemplateData | TemplateData[] | string | string[];
} }
const DOCX_CONTENTTYPE = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
interface MenuPanelProps { interface MenuPanelProps {
event: kintone.events.AppRecordDetailShowEvent | kintone.events.MobileAppRecordDetailShowEvent; event: kintone.events.AppRecordDetailShowEvent | kintone.events.MobileAppRecordDetailShowEvent;
} }
@ -31,6 +30,105 @@ const cachedFormFieldsProperties = moize.promise(async (appId: number): Promise<
return properties; return properties;
}); });
const formatNumberValue = (value: string, digit: boolean, scale?: number): string => {
if (value !== '' && !isNaN(Number(value))) {
const numberValue = Number(value);
const options: Intl.NumberFormatOptions = {
useGrouping: digit,
};
if (scale != null && scale >= 0) {
options.minimumFractionDigits = scale;
options.maximumFractionDigits = scale;
}
return new Intl.NumberFormat('en-US', options).format(numberValue);
}
return value;
};
const formatValueWithUnit = (
value: string,
property: KintoneFormFieldProperty.Number | KintoneFormFieldProperty.Calc,
): string => {
if (value !== '' && property.unit !== '') {
if (property.unitPosition === 'BEFORE') {
return `${property.unit} ${value}`;
} else if (property.unitPosition === 'AFTER') {
return `${value} ${property.unit}`;
}
}
return value;
};
const formatNumberRecordValue = (
value: string,
property: KintoneFormFieldProperty.Number | KintoneFormFieldProperty.Lookup,
): string => {
if ('lookup' in property) {
return value;
}
const scale = property.displayScale !== '' ? Number(property.displayScale) : undefined;
const digit = property.digit ?? false;
const formattedValue = formatNumberValue(value, digit, scale);
return formatValueWithUnit(formattedValue, property);
};
const formatCalculatedRecordValue = (value: string, property: KintoneFormFieldProperty.Calc): string => {
const { format } = property;
if (value === '') {
return '';
}
const scale = property.displayScale !== '' ? Number(property.displayScale) : undefined;
let formattedValue: string;
if (format === 'NUMBER') {
formattedValue = formatNumberValue(value, false, scale);
} else if (format === 'NUMBER_DIGIT') {
formattedValue = formatNumberValue(value, true, scale);
} else if (format === 'DATETIME') {
// "2025-05-30T00:00:00Z" -> "2025-05-30 9:00" (browser local timezone)
const date = new Date(value);
invariant(!isNaN(date.getTime()), `Expected value to be a valid date string, but got ${value}`);
formattedValue = dayjs(date).format('YYYY-MM-DD h:mm');
} else if (format === 'DATE') {
// "2025-05-30T00:00:00Z" -> "2025-05-30" (browser local timezone)
const date = new Date(value);
invariant(!isNaN(date.getTime()), `Expected value to be a valid date string, but got ${value}`);
formattedValue = dayjs(date).format('YYYY-MM-DD');
} else if (format === 'TIME') {
// "00:30" -> "0:30"
const [hours, minutes] = value.split(':').map((v) => Number(v));
invariant(
!isNaN(hours) && !isNaN(minutes),
`Expected hours and minutes to be numbers, but got hours: ${hours}, minutes: ${minutes}`,
);
formattedValue = `${hours}:${String(minutes).padStart(2, '0')}`;
} else if (format === 'HOUR_MINUTE') {
// "49:30" -> en:"49 hours 30 minutes", ja: "49時間30分"
const [hours, minutes] = value.split(':').map((v) => Number(v));
invariant(
!isNaN(hours) && !isNaN(minutes),
`Expected hours and minutes to be numbers, but got hours: ${hours}, minutes: ${minutes}`,
);
formattedValue = LANGUAGE === 'ja' ? `${hours}時間${minutes}` : `${hours} hours ${minutes} minutes`;
} else if (format === 'DAY_HOUR_MINUTE') {
// "49:30" -> en: "2 days 1 hour 30 minutes", ja: "2日1時間30分
const [hours, minutes] = value.split(':').map((v) => Number(v));
invariant(
!isNaN(hours) && !isNaN(minutes),
`Expected hours and minutes to be numbers, but got hours: ${hours}, minutes: ${minutes}`,
);
const days = Math.floor(Number(hours) / 24);
const remainingHours = Number(hours) % 24;
formattedValue =
LANGUAGE === 'ja'
? `${days}${remainingHours}時間${minutes}`
: `${days} days ${remainingHours} hours ${minutes} minutes`;
} else {
// DATETIME, DATE, TIME
formattedValue = value;
}
return formatValueWithUnit(formattedValue, property);
};
const record2data = (properties: KintoneFormFieldProperties, record: Partial<KintoneRecord>): TemplateData => { const record2data = (properties: KintoneFormFieldProperties, record: Partial<KintoneRecord>): TemplateData => {
const data: TemplateData = {}; const data: TemplateData = {};
for (const key in record) { for (const key in record) {
@ -46,13 +144,19 @@ const record2data = (properties: KintoneFormFieldProperties, record: Partial<Kin
name: value.name, name: value.name,
code: value.code, code: value.code,
}; };
} else if (type === 'CATEGORY' || type === 'CHECK_BOX' || type === 'MULTI_SELECT') { } else if (type === 'NUMBER') {
invariant(property.type === 'NUMBER', `Expected property type to be NUMBER, but got ${property.type}`);
data[key] = formatNumberRecordValue(value, property);
} else if (type === 'CALC') {
invariant(property.type === 'CALC', `Expected property type to be CALC, but got ${property.type}`);
data[key] = formatCalculatedRecordValue(value, property);
} else if (type === 'CHECK_BOX' || type === 'MULTI_SELECT' || type === 'CATEGORY') {
data[key] = value.map((v) => v); data[key] = value.map((v) => v);
} else if ( } else if (
type === 'STATUS_ASSIGNEE' ||
type === 'USER_SELECT' || type === 'USER_SELECT' ||
type === 'ORGANIZATION_SELECT' ||
type === 'GROUP_SELECT' || type === 'GROUP_SELECT' ||
type === 'ORGANIZATION_SELECT' type === 'STATUS_ASSIGNEE'
) { ) {
data[key] = value.map((v) => { data[key] = value.map((v) => {
return { name: v.name, code: v.code }; return { name: v.name, code: v.code };
@ -60,44 +164,17 @@ const record2data = (properties: KintoneFormFieldProperties, record: Partial<Kin
} else if (type === 'SUBTABLE') { } else if (type === 'SUBTABLE') {
invariant(property.type === 'SUBTABLE', `Expected property type to be SUBTABLE, but got ${property.type}`); invariant(property.type === 'SUBTABLE', `Expected property type to be SUBTABLE, but got ${property.type}`);
data[key] = value.map((subRecord) => record2data(property.fields, subRecord.value)); data[key] = value.map((subRecord) => record2data(property.fields, subRecord.value));
} else if (type === 'CALC') { } else if (type === 'FILE') {
invariant(property.type === 'CALC', `Expected property type to be CALC, but got ${property.type}`); invariant(property.type === 'FILE', `Expected property type to be FILE, but got ${property.type}`);
if (value === '') { data[key] = value.map((file) => ({
data[key] = ''; name: file.name,
} else if (property.format === 'NUMBER_DIGIT') { size: file.size,
// "1234567" -> "1,234,567" contentType: file.contentType,
data[key] = Number(value).toLocaleString('en-US'); fileKey: file.fileKey,
} else if (property.format === 'HOUR_MINUTE') { }));
// "49:30" -> en:"49 hours 30 minutes", ja: "49時間30分"
const [hours, minutes] = value.split(':').map((v) => Number(v));
invariant(
!isNaN(hours) && !isNaN(minutes),
`Expected hours and minutes to be numbers, but got hours: ${hours}, minutes: ${minutes}`,
);
if (LANGUAGE === 'ja') {
data[key] = `${hours}時間${minutes}`;
} else {
data[key] = `${hours} hours ${minutes} minutes`;
}
} else if (property.format === 'DAY_HOUR_MINUTE') {
// "49:30" -> en: "2 days 1 hour 30 minutes", ja: "2日1時間30分
const [hours, minutes] = value.split(':').map((v) => Number(v));
invariant(
!isNaN(hours) && !isNaN(minutes),
`Expected hours and minutes to be numbers, but got hours: ${hours}, minutes: ${minutes}`,
);
const days = Math.floor(Number(hours) / 24);
const remainingHours = Number(hours) % 24;
if (LANGUAGE === 'ja') {
data[key] = `${days}${remainingHours}時間${minutes}`;
} else {
data[key] = `${days} days ${remainingHours} hours ${minutes} minutes`;
}
} else {
// NUMBER, DATETIME, DATE, TIME
data[key] = value;
}
} else { } else {
// RECORD_NUMBER, __ID__, __REVISION__, CREATED_TIME, UPDATED_TIME
// SINGLE_LINE_TEXT, MULTI_LINE_TEXT, RICH_TEXT, RADIO_BUTTON, DROP_DOWN, DATE, TIME, DATETIME, LINK, STATUS
data[key] = value; data[key] = value;
} }
} }
@ -123,15 +200,15 @@ const MenuPanel: React.FC<MenuPanelProps> = (props) => {
return <KintonePluginAlert>WORD output plugin: Template field is not available in this app.</KintonePluginAlert>; return <KintonePluginAlert>WORD output plugin: Template field is not available in this app.</KintonePluginAlert>;
} }
if (record.type !== 'FILE') { if (record.type !== 'FILE') {
return <KintonePluginAlert>WORD output plugin: The template field must be a file field.</KintonePluginAlert>; return <KintonePluginAlert>WORD output plugin: Template field must be a file field.</KintonePluginAlert>;
} }
if (record.value.length === 0) { if (record.value.length === 0) {
return <KintonePluginAlert>WORD output plugin: The template field does not contain any files.</KintonePluginAlert>; return <KintonePluginAlert>WORD output plugin: Template field does not contain any files.</KintonePluginAlert>;
} }
if (record.value.length > 1) { if (record.value.length > 1) {
return ( return (
<KintonePluginAlert> <KintonePluginAlert>
WORD output plugin: The template field contains multiple files. Only the first file will be used. WORD output plugin: Template field contains multiple files. Please ensure it contains only one file.
</KintonePluginAlert> </KintonePluginAlert>
); );
} }