{"_id":"@aeriz/wysiwyg","_rev":"6-d7354812a173c7da5af2ea6a3821ec65","name":"@aeriz/wysiwyg","dist-tags":{"latest":"1.0.5"},"versions":{"1.0.0":{"name":"@aeriz/wysiwyg","version":"1.0.0","keywords":["wysiwyg","editor","rich-text","korean","contenteditable"],"author":{"name":"code-repositories"},"license":"Apache-2.0","_id":"@aeriz/wysiwyg@1.0.0","maintainers":[{"name":"aeriz","email":"shinsungj@gmail.com"}],"homepage":"https://aeriz.dev","dist":{"shasum":"e0db10ec46feac55c35d72ccac2f6d29bfb3a2bc","tarball":"https://registry.npmjs.org/@aeriz/wysiwyg/-/wysiwyg-1.0.0.tgz","fileCount":36,"integrity":"sha512-E+Rf6lIuQ3t3T/BqR5K8bLz7PLM2BU0pe94nryJAbMvIIhiQLyfqIDN/M/l/6YH++rH7LdeutuO8XqytcWP3HQ==","signatures":[{"sig":"MEYCIQDNAtda5z+ca/wt4CVTg9TPsSMLAt/S4ryrWyCZKQqIhAIhAOR9u+QzXUsTYtY51hz4KDJZyfsGTDhWj9QyA8q0JQ0C","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":841931},"main":"./dist/aeriz-wysiwyg.esm.js","type":"module","types":"./dist-types/index.d.ts","unpkg":"./dist/aeriz-wysiwyg.min.js","module":"./dist/aeriz-wysiwyg.esm.js","browser":"./dist/aeriz-wysiwyg.min.js","exports":{".":{"types":"./dist-types/index.d.ts","import":"./dist/aeriz-wysiwyg.esm.js","default":"./dist/aeriz-wysiwyg.min.js"},"./style.css":"./dist/aeriz-wysiwyg.min.css","./dist/aeriz-wysiwyg.min.js":"./dist/aeriz-wysiwyg.min.js","./dist/aeriz-wysiwyg.min.css":"./dist/aeriz-wysiwyg.min.css"},"scripts":{"dev":"npm run build && vite --config vite.demo.config.ts","build":"npm run build:dev && npm run build:prod && npm run build:types","preview":"npm run build && vite build --config vite.demo.config.ts && vite preview --config vite.demo.config.ts","build:dev":"vite build --mode dev","typecheck":"tsc --noEmit","build:prod":"vite build --mode prod","build:types":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"aeriz","email":"shinsungj@gmail.com"},"jsdelivr":"./dist/aeriz-wysiwyg.min.js","_npmVersion":"11.12.1","description":"Korean-friendly WYSIWYG rich text editor","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"25.9.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0","typescript":"^5.6.0"},"_npmOperationalInternal":{"tmp":"tmp/wysiwyg_1.0.0_1777999394618_0.5835102041685016","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@aeriz/wysiwyg","version":"1.0.1","keywords":["wysiwyg","editor","rich-text","korean","contenteditable"],"author":{"name":"code-repositories"},"license":"Apache-2.0","_id":"@aeriz/wysiwyg@1.0.1","maintainers":[{"name":"aeriz","email":"shinsungj@gmail.com"}],"homepage":"https://aeriz.dev","dist":{"shasum":"fa1849795b4fd7e81257553e8d0dd3fe075a0696","tarball":"https://registry.npmjs.org/@aeriz/wysiwyg/-/wysiwyg-1.0.1.tgz","fileCount":37,"integrity":"sha512-EoU8eDIcxgn+usoqopj1+wb1IWv36pxk6lBIlIx5WQFQi6LMpvZx+WSsqFYvpY6PJp0tiToIiqd6cDk5GLnCug==","signatures":[{"sig":"MEUCIFHFnv6IBoqCKygc09JSKNtBXXQby9RO8w3waMaOFWBtAiEA50OPq9hxyCSG0mwfvo/ZD8ld7a8v0X2wRet3dTotxf4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":875413},"main":"./dist/aeriz-wysiwyg.esm.js","type":"module","types":"./dist-types/index.d.ts","unpkg":"./dist/aeriz-wysiwyg.min.js","module":"./dist/aeriz-wysiwyg.esm.js","browser":"./dist/aeriz-wysiwyg.min.js","exports":{".":{"types":"./dist-types/index.d.ts","import":"./dist/aeriz-wysiwyg.esm.js","default":"./dist/aeriz-wysiwyg.min.js"},"./style.css":"./dist/aeriz-wysiwyg.min.css","./dist/aeriz-wysiwyg.min.js":"./dist/aeriz-wysiwyg.min.js","./dist/aeriz-wysiwyg.min.css":"./dist/aeriz-wysiwyg.min.css"},"gitHead":"4df12708db4b0c51eb92f0a6220a81e4fc671f11","scripts":{"dev":"npm run build && vite --config vite.demo.config.ts","build":"npm run build:dev && npm run build:prod && npm run build:types","preview":"npm run build && vite build --config vite.demo.config.ts && vite preview --config vite.demo.config.ts","build:dev":"vite build --mode dev","typecheck":"tsc --noEmit","build:prod":"vite build --mode prod","build:types":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"aeriz","email":"shinsungj@gmail.com"},"jsdelivr":"./dist/aeriz-wysiwyg.min.js","_npmVersion":"11.12.1","description":"WYSIWYG rich text editor","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"25.9.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0","typescript":"^5.6.0"},"_npmOperationalInternal":{"tmp":"tmp/wysiwyg_1.0.1_1778168052198_0.6459215377321066","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@aeriz/wysiwyg","version":"1.0.2","keywords":["wysiwyg","editor","rich-text","korean","contenteditable"],"author":{"name":"code-repositories"},"license":"Apache-2.0","_id":"@aeriz/wysiwyg@1.0.2","maintainers":[{"name":"aeriz","email":"shinsungj@gmail.com"}],"homepage":"https://aeriz.dev","dist":{"shasum":"741386c3ff89523b1c50e37d1ebfa7a9cbbb0c38","tarball":"https://registry.npmjs.org/@aeriz/wysiwyg/-/wysiwyg-1.0.2.tgz","fileCount":37,"integrity":"sha512-x7oZCLvjq9gamrfOyASQ28F20+3RXUjaGlRbys/sMSxnXbezHhYtCTLKvd608GfgFoq7xRhyP4rPAs1YdMb5mg==","signatures":[{"sig":"MEUCIEppc0aV1+wwanZoffUxul5rPp8StJyszIbv8RNqJbQcAiEA/blAKH9E2VN5andjtuiJ9n4Z5jaxkEAty7GlEe3eBbo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":877807},"main":"./dist/aeriz-wysiwyg.esm.js","type":"module","types":"./dist-types/index.d.ts","unpkg":"./dist/aeriz-wysiwyg.min.js","module":"./dist/aeriz-wysiwyg.esm.js","browser":"./dist/aeriz-wysiwyg.min.js","exports":{".":{"types":"./dist-types/index.d.ts","import":"./dist/aeriz-wysiwyg.esm.js","default":"./dist/aeriz-wysiwyg.min.js"},"./style.css":"./dist/aeriz-wysiwyg.min.css","./dist/aeriz-wysiwyg.min.js":"./dist/aeriz-wysiwyg.min.js","./dist/aeriz-wysiwyg.min.css":"./dist/aeriz-wysiwyg.min.css"},"gitHead":"6cfb1574418aeb2f5119d0fc97dcc604bc1317d4","scripts":{"dev":"npm run build && vite --config vite.demo.config.ts","build":"npm run build:dev && npm run build:prod && npm run build:types","preview":"npm run build && vite build --config vite.demo.config.ts && vite preview --config vite.demo.config.ts","build:dev":"vite build --mode dev","typecheck":"tsc --noEmit","build:prod":"vite build --mode prod","build:types":"tsc -p tsconfig.build.json","prepublishOnly":"npm run build"},"_npmUser":{"name":"aeriz","email":"shinsungj@gmail.com"},"jsdelivr":"./dist/aeriz-wysiwyg.min.js","_npmVersion":"11.12.1","description":"WYSIWYG rich text editor","directories":{},"sideEffects":["**/*.css"],"_nodeVersion":"25.9.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.4.0","typescript":"^5.6.0"},"_npmOperationalInternal":{"tmp":"tmp/wysiwyg_1.0.2_1778173258148_0.9150376494036059","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@aeriz/wysiwyg","version":"1.0.3","keywords":["wysiwyg","editor","rich-text","korean","contenteditable","react","vue","svelte","angular","jquery","web-component"],"author":{"name":"code-repositories"},"license":"Apache-2.0","_id":"@aeriz/wysiwyg@1.0.3","maintainers":[{"name":"aeriz","email":"shinsungj@gmail.com"}],"homepage":"https://aeriz.dev","dist":{"shasum":"1838d02a14298eb16331d66b7bc807f3e3f8bfa3","tarball":"https://registry.npmjs.org/@aeriz/wysiwyg/-/wysiwyg-1.0.3.tgz","fileCount":121,"integrity":"sha512-4V2jczbWEgvWXzCdvuXaWVSk8x2S+pyam9Upb3urC1ijFLPslCFp9VlNF/iepHSOLW2MTNarr26DcDe3rhf40g==","signatures":[{"sig":"MEQCIFlidcwmJMWBqIGRmPkvo6PJJyOTGL474+Uo+rMqMPdDAiBwYhA8+FPKa3Swydn9ZKPVxWvxd+VB9AisMO8TTO9lng==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1709833},"main":"./dist/aeriz-wysiwyg.min.cjs","type":"module","types":"./dist-types/index.d.ts","unpkg":"./dist/aeriz-wysiwyg.min.js","module":"./dist/aeriz-wysiwyg.esm.js","browser":"./dist/aeriz-wysiwyg.min.js","exports":{".":{"import":{"types":"./dist-types/index.d.ts","default":"./dist/aeriz-wysiwyg.esm.js"},"default":"./dist/aeriz-wysiwyg.min.js","require":{"types":"./dist-types/cjs/index.d.cts","default":"./dist/aeriz-wysiwyg.min.cjs"}},"./wc":{"import":{"types":"./dist-types/adapters/wc.d.ts","default":"./dist/adapters/wc.js"},"default":"./dist/adapters/wc.js","require":{"types":"./dist-types/cjs/adapters/wc.d.cts","default":"./dist/adapters/wc.cjs"}},"./vue":{"import":{"types":"./dist-types/adapters/vue.d.ts","default":"./dist/adapters/vue.js"},"default":"./dist/adapters/vue.js","require":{"types":"./dist-types/cjs/adapters/vue.d.cts","default":"./dist/adapters/vue.cjs"}},"./vue2":{"import":{"types":"./dist-types/adapters/vue2.d.ts","default":"./dist/adapters/vue2.js"},"default":"./dist/adapters/vue2.js","require":{"types":"./dist-types/cjs/adapters/vue2.d.cts","default":"./dist/adapters/vue2.cjs"}},"./react":{"import":{"types":"./dist-types/adapters/react.d.ts","default":"./dist/adapters/react.js"},"default":"./dist/adapters/react.js","require":{"types":"./dist-types/cjs/adapters/react.d.cts","default":"./dist/adapters/react.cjs"}},"./cdn/wc":"./dist/aeriz-wysiwyg-wc.min.js","./jquery":{"import":{"types":"./dist-types/adapters/jquery.d.ts","default":"./dist/adapters/jquery.js"},"default":"./dist/adapters/jquery.js","require":{"types":"./dist-types/cjs/adapters/jquery.d.cts","default":"./dist/adapters/jquery.cjs"}},"./server":{"import":{"types":"./dist-types/server/index.d.ts","default":"./dist/server.js"},"default":"./dist/server.js","require":{"types":"./dist-types/cjs/server/index.d.cts","default":"./dist/server.cjs"}},"./svelte":{"import":{"types":"./dist-types/adapters/svelte.d.ts","default":"./dist/adapters/svelte.js"},"default":"./dist/adapters/svelte.js","require":{"types":"./dist-types/cjs/adapters/svelte.d.cts","default":"./dist/adapters/svelte.cjs"}},"./adapter":{"import":{"types":"./dist-types/adapters/shared.d.ts","default":"./dist/adapters/shared.js"},"default":"./dist/adapters/shared.js","require":{"types":"./dist-types/cjs/adapters/shared.d.cts","default":"./dist/adapters/shared.cjs"}},"./angular":{"types":"./angular/index.ts","default":"./angular/index.ts"},"./angular/*":"./angular/*","./style.css":"./dist/aeriz-wysiwyg.min.css","./cdn/jquery":"./dist/aeriz-wysiwyg-jquery.min.js","./cdn/adapter":"./dist/aeriz-wysiwyg-adapter.min.js","./dist/aeriz-wysiwyg.min.js":"./dist/aeriz-wysiwyg.min.js","./dist/aeriz-wysiwyg.min.css":"./dist/aeriz-wysiwyg.min.css"},"gitHead":"6c3f85db77755cd74583a8a620046206ba056059","_npmUser":{"name":"aeriz","email":"shinsungj@gmail.com"},"jsdelivr":"./dist/aeriz-wysiwyg.min.js","_npmVersion":"11.12.1","description":"WYSIWYG rich text editor","directories":{},"sideEffects":["**/*.css","./dist/adapters/wc.js","./dist/adapters/wc.cjs","./dist/adapters/jquery.js","./dist/adapters/jquery.cjs"],"_nodeVersion":"25.9.0","publishConfig":{"access":"public"},"typesVersions":{"*":{"wc":["./dist-types/adapters/wc.d.ts"],"vue":["./dist-types/adapters/vue.d.ts"],"vue2":["./dist-types/adapters/vue2.d.ts"],"react":["./dist-types/adapters/react.d.ts"],"jquery":["./dist-types/adapters/jquery.d.ts"],"server":["./dist-types/server/index.d.ts"],"svelte":["./dist-types/adapters/svelte.d.ts"],"adapter":["./dist-types/adapters/shared.d.ts"]}},"_hasShrinkwrap":false,"peerDependencies":{"vue":"^2.6.0 || >=3.0.0","react":">=16.8","jquery":">=3","svelte":">=3","@angular/core":">=14","@angular/forms":">=14"},"peerDependenciesMeta":{"vue":{"optional":true},"react":{"optional":true},"jquery":{"optional":true},"svelte":{"optional":true},"@angular/core":{"optional":true},"@angular/forms":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/wysiwyg_1.0.3_1786205750819_0.6369142523549238","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@aeriz/wysiwyg","version":"1.0.4","keywords":["wysiwyg","editor","rich-text","korean","contenteditable","react","vue","svelte","angular","jquery","web-component"],"author":{"name":"code-repositories"},"license":"Apache-2.0","_id":"@aeriz/wysiwyg@1.0.4","maintainers":[{"name":"aeriz","email":"shinsungj@gmail.com"}],"homepage":"https://aeriz.dev","dist":{"shasum":"65bd597d59619e77cae75fd654c0fd0f7e4e13b4","tarball":"https://registry.npmjs.org/@aeriz/wysiwyg/-/wysiwyg-1.0.4.tgz","fileCount":136,"integrity":"sha512-1mbmZmlnPoEElZSSO2PiG9VbTRSAJzvQVwcQOzQ8upyvhssUJ6smbYYIAOxqkIir7IArqXnHhGApnR4TwToQnQ==","signatures":[{"sig":"MEUCIQC5uxOTA8cu/ws2SexUamBbjNyJXiT7BVkEsx1OjN6hxAIgd1B+TXkGvPKbLy7lDC5v8f6mEDST/nzLaEfzo+lFMps=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":2135795},"main":"./dist/aeriz-wysiwyg.min.cjs","type":"module","types":"./dist-types/index.d.ts","unpkg":"./dist/aeriz-wysiwyg.min.js","module":"./dist/aeriz-wysiwyg.esm.js","browser":"./dist/aeriz-wysiwyg.min.js","exports":{".":{"import":{"types":"./dist-types/index.d.ts","default":"./dist/aeriz-wysiwyg.esm.js"},"default":"./dist/aeriz-wysiwyg.min.js","require":{"types":"./dist-types/cjs/index.d.cts","default":"./dist/aeriz-wysiwyg.min.cjs"}},"./wc":{"import":{"types":"./dist-types/adapters/wc.d.ts","default":"./dist/adapters/wc.js"},"default":"./dist/adapters/wc.js","require":{"types":"./dist-types/cjs/adapters/wc.d.cts","default":"./dist/adapters/wc.cjs"}},"./vue":{"import":{"types":"./dist-types/adapters/vue.d.ts","default":"./dist/adapters/vue.js"},"default":"./dist/adapters/vue.js","require":{"types":"./dist-types/cjs/adapters/vue.d.cts","default":"./dist/adapters/vue.cjs"}},"./vue2":{"import":{"types":"./dist-types/adapters/vue2.d.ts","default":"./dist/adapters/vue2.js"},"default":"./dist/adapters/vue2.js","require":{"types":"./dist-types/cjs/adapters/vue2.d.cts","default":"./dist/adapters/vue2.cjs"}},"./react":{"import":{"types":"./dist-types/adapters/react.d.ts","default":"./dist/adapters/react.js"},"default":"./dist/adapters/react.js","require":{"types":"./dist-types/cjs/adapters/react.d.cts","default":"./dist/adapters/react.cjs"}},"./cdn/wc":"./dist/aeriz-wysiwyg-wc.min.js","./jquery":{"import":{"types":"./dist-types/adapters/jquery.d.ts","default":"./dist/adapters/jquery.js"},"default":"./dist/adapters/jquery.js","require":{"types":"./dist-types/cjs/adapters/jquery.d.cts","default":"./dist/adapters/jquery.cjs"}},"./server":{"import":{"types":"./dist-types/server/index.d.ts","default":"./dist/server.js"},"default":"./dist/server.js","require":{"types":"./dist-types/cjs/server/index.d.cts","default":"./dist/server.cjs"}},"./svelte":{"import":{"types":"./dist-types/adapters/svelte.d.ts","default":"./dist/adapters/svelte.js"},"default":"./dist/adapters/svelte.js","require":{"types":"./dist-types/cjs/adapters/svelte.d.cts","default":"./dist/adapters/svelte.cjs"}},"./adapter":{"import":{"types":"./dist-types/adapters/shared.d.ts","default":"./dist/adapters/shared.js"},"default":"./dist/adapters/shared.js","require":{"types":"./dist-types/cjs/adapters/shared.d.cts","default":"./dist/adapters/shared.cjs"}},"./angular":{"types":"./angular/index.ts","default":"./angular/index.ts"},"./angular/*":"./angular/*","./style.css":"./dist/aeriz-wysiwyg.min.css","./cdn/jquery":"./dist/aeriz-wysiwyg-jquery.min.js","./cdn/adapter":"./dist/aeriz-wysiwyg-adapter.min.js","./dist/aeriz-wysiwyg.min.js":"./dist/aeriz-wysiwyg.min.js","./dist/aeriz-wysiwyg.min.css":"./dist/aeriz-wysiwyg.min.css"},"gitHead":"0972077814702f0e8dfb032df53176d4ed1f926c","_npmUser":{"name":"aeriz","email":"shinsungj@gmail.com"},"jsdelivr":"./dist/aeriz-wysiwyg.min.js","_npmVersion":"11.12.1","description":"WYSIWYG rich text editor","directories":{},"sideEffects":["**/*.css","./dist/adapters/wc.js","./dist/adapters/wc.cjs","./dist/adapters/jquery.js","./dist/adapters/jquery.cjs"],"_nodeVersion":"25.9.0","publishConfig":{"access":"public"},"typesVersions":{"*":{"wc":["./dist-types/adapters/wc.d.ts"],"vue":["./dist-types/adapters/vue.d.ts"],"vue2":["./dist-types/adapters/vue2.d.ts"],"react":["./dist-types/adapters/react.d.ts"],"jquery":["./dist-types/adapters/jquery.d.ts"],"server":["./dist-types/server/index.d.ts"],"svelte":["./dist-types/adapters/svelte.d.ts"],"adapter":["./dist-types/adapters/shared.d.ts"]}},"_hasShrinkwrap":false,"peerDependencies":{"vue":"^2.6.0 || >=3.0.0","react":">=16.8","jquery":">=3","svelte":">=3","@angular/core":">=14","@angular/forms":">=14"},"peerDependenciesMeta":{"vue":{"optional":true},"react":{"optional":true},"jquery":{"optional":true},"svelte":{"optional":true},"@angular/core":{"optional":true},"@angular/forms":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/wysiwyg_1.0.4_1786283029981_0.8113146676020251","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@aeriz/wysiwyg","version":"1.0.5","description":"WYSIWYG rich text editor","author":{"name":"code-repositories"},"homepage":"https://aeriz.dev","license":"Apache-2.0","type":"module","main":"./dist/aeriz-wysiwyg.min.cjs","module":"./dist/aeriz-wysiwyg.esm.js","browser":"./dist/aeriz-wysiwyg.min.js","types":"./dist-types/index.d.ts","unpkg":"./dist/aeriz-wysiwyg.min.js","jsdelivr":"./dist/aeriz-wysiwyg.min.js","exports":{".":{"import":{"types":"./dist-types/index.d.ts","default":"./dist/aeriz-wysiwyg.esm.js"},"require":{"types":"./dist-types/cjs/index.d.cts","default":"./dist/aeriz-wysiwyg.min.cjs"},"default":"./dist/aeriz-wysiwyg.min.js"},"./server":{"import":{"types":"./dist-types/server/index.d.ts","default":"./dist/server.js"},"require":{"types":"./dist-types/cjs/server/index.d.cts","default":"./dist/server.cjs"},"default":"./dist/server.js"},"./adapter":{"import":{"types":"./dist-types/adapters/shared.d.ts","default":"./dist/adapters/shared.js"},"require":{"types":"./dist-types/cjs/adapters/shared.d.cts","default":"./dist/adapters/shared.cjs"},"default":"./dist/adapters/shared.js"},"./react":{"import":{"types":"./dist-types/adapters/react.d.ts","default":"./dist/adapters/react.js"},"require":{"types":"./dist-types/cjs/adapters/react.d.cts","default":"./dist/adapters/react.cjs"},"default":"./dist/adapters/react.js"},"./vue":{"import":{"types":"./dist-types/adapters/vue.d.ts","default":"./dist/adapters/vue.js"},"require":{"types":"./dist-types/cjs/adapters/vue.d.cts","default":"./dist/adapters/vue.cjs"},"default":"./dist/adapters/vue.js"},"./vue2":{"import":{"types":"./dist-types/adapters/vue2.d.ts","default":"./dist/adapters/vue2.js"},"require":{"types":"./dist-types/cjs/adapters/vue2.d.cts","default":"./dist/adapters/vue2.cjs"},"default":"./dist/adapters/vue2.js"},"./svelte":{"import":{"types":"./dist-types/adapters/svelte.d.ts","default":"./dist/adapters/svelte.js"},"require":{"types":"./dist-types/cjs/adapters/svelte.d.cts","default":"./dist/adapters/svelte.cjs"},"default":"./dist/adapters/svelte.js"},"./jquery":{"import":{"types":"./dist-types/adapters/jquery.d.ts","default":"./dist/adapters/jquery.js"},"require":{"types":"./dist-types/cjs/adapters/jquery.d.cts","default":"./dist/adapters/jquery.cjs"},"default":"./dist/adapters/jquery.js"},"./wc":{"import":{"types":"./dist-types/adapters/wc.d.ts","default":"./dist/adapters/wc.js"},"require":{"types":"./dist-types/cjs/adapters/wc.d.cts","default":"./dist/adapters/wc.cjs"},"default":"./dist/adapters/wc.js"},"./cdn/wc":"./dist/aeriz-wysiwyg-wc.min.js","./cdn/jquery":"./dist/aeriz-wysiwyg-jquery.min.js","./cdn/adapter":"./dist/aeriz-wysiwyg-adapter.min.js","./angular":{"types":"./angular/index.ts","default":"./angular/index.ts"},"./angular/*":"./angular/*","./dist/aeriz-wysiwyg.min.js":"./dist/aeriz-wysiwyg.min.js","./dist/aeriz-wysiwyg.min.css":"./dist/aeriz-wysiwyg.min.css","./style.css":"./dist/aeriz-wysiwyg.min.css"},"typesVersions":{"*":{"server":["./dist-types/server/index.d.ts"],"adapter":["./dist-types/adapters/shared.d.ts"],"react":["./dist-types/adapters/react.d.ts"],"vue":["./dist-types/adapters/vue.d.ts"],"vue2":["./dist-types/adapters/vue2.d.ts"],"svelte":["./dist-types/adapters/svelte.d.ts"],"jquery":["./dist-types/adapters/jquery.d.ts"],"wc":["./dist-types/adapters/wc.d.ts"]}},"sideEffects":["**/*.css","./dist/adapters/wc.js","./dist/adapters/wc.cjs","./dist/adapters/jquery.js","./dist/adapters/jquery.cjs"],"publishConfig":{"access":"public"},"keywords":["wysiwyg","editor","rich-text","korean","contenteditable","react","vue","svelte","angular","jquery","web-component"],"peerDependencies":{"@angular/core":">=14","@angular/forms":">=14","jquery":">=3","react":">=16.8","svelte":">=3","vue":"^2.6.0 || >=3.0.0"},"peerDependenciesMeta":{"@angular/core":{"optional":true},"@angular/forms":{"optional":true},"jquery":{"optional":true},"react":{"optional":true},"svelte":{"optional":true},"vue":{"optional":true}},"gitHead":"bce6080b4fb7fb3282f334de49bb995fa93af77d","_id":"@aeriz/wysiwyg@1.0.5","_nodeVersion":"25.9.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-x0DMvG0dvFrHqReKja37Vnxx5NH1e+Vy4bS1adIC51qYqxEEEEGYkRFQf88yoRSBsq1xa/K7hShBRnfr8LGVCw==","shasum":"b96a7e520401c18aec65e20ff8cbea0ca377f6e2","tarball":"https://registry.npmjs.org/@aeriz/wysiwyg/-/wysiwyg-1.0.5.tgz","fileCount":136,"unpackedSize":2168231,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDCuuwpJbylGeFqrvG9ZL1gOKN2bPc8i1jX3D+GTCaFzAIgRtzlIQyFBYwgr0DUQV15Dd4DxvtmJLZfZPMUgSTryUM="}]},"_npmUser":{"name":"aeriz","email":"shinsungj@gmail.com"},"directories":{},"maintainers":[{"name":"aeriz","email":"shinsungj@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/wysiwyg_1.0.5_1786286146865_0.20591679043272393"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-05T16:43:14.420Z","modified":"2026-08-09T14:35:47.185Z","1.0.0":"2026-05-05T16:43:14.755Z","1.0.1":"2026-05-07T15:34:12.359Z","1.0.2":"2026-05-07T17:00:58.294Z","1.0.3":"2026-08-08T16:15:51.025Z","1.0.4":"2026-08-09T13:43:50.131Z","1.0.5":"2026-08-09T14:35:47.065Z"},"author":{"name":"code-repositories"},"license":"Apache-2.0","homepage":"https://aeriz.dev","keywords":["wysiwyg","editor","rich-text","korean","contenteditable","react","vue","svelte","angular","jquery","web-component"],"description":"WYSIWYG rich text editor","maintainers":[{"name":"aeriz","email":"shinsungj@gmail.com"}],"readme":"# @aeriz/wysiwyg\n\n한국어 친화 contentEditable WYSIWYG 에디터.\n\n자세한 동작 사양은 [SPEC.md](./SPEC.md) 를 참고하세요.\n\n## 지원 환경\n\n| 대상 | 진입점 | 방식 |\n| --- | --- | --- |\n| Vanilla JS | `@aeriz/wysiwyg` | 클래스 직접 사용 |\n| Web Component | `@aeriz/wysiwyg/wc` | `<aeriz-editor>` 커스텀 엘리먼트 |\n| jQuery | `@aeriz/wysiwyg/jquery` | `$.fn.aerizEditor` 플러그인 |\n| React 16.8+ / 17 / 18 / 19 | `@aeriz/wysiwyg/react` | `<AerizEditor />` 컴포넌트 |\n| Vue 3 | `@aeriz/wysiwyg/vue` | `v-model` 컴포넌트 |\n| Vue 2.6 / 2.7 | `@aeriz/wysiwyg/vue2` | `v-model` 컴포넌트 |\n| Svelte 3 / 4 / 5 | `@aeriz/wysiwyg/svelte` | `use:aerizEditor` 액션 |\n| Angular 14+ | `@aeriz/wysiwyg/angular` | `[aerizEditor]` 디렉티브 (`ngModel` 지원) |\n| Node / Deno / Bun / Cloudflare Workers | `@aeriz/wysiwyg/server` | DOM 없는 렌더러 · 변환기 |\n\n빌드 도구가 없는 페이지도 지원합니다 — 코어뿐 아니라 **어댑터도 스크립트\n태그로 로드**할 수 있습니다 ([CDN 절](#cdn--어댑터도-스크립트-태그로) 참고).\n\n프레임워크 패키지는 모두 **optional peerDependency** 입니다. React 프로젝트에\nVue 가 설치될 일은 없습니다.\n\n## 설치\n\n```bash\nnpm install @aeriz/wysiwyg\n# yarn add @aeriz/wysiwyg\n# pnpm add @aeriz/wysiwyg\n```\n\n스타일시트는 어느 프레임워크를 쓰든 한 번 로드해야 합니다.\n\n```ts\nimport '@aeriz/wysiwyg/style.css';\n```\n\n---\n\n## Vanilla JS\n\n### 번들러 사용\n\n```ts\nimport { AerizEditor, AerizViewer } from '@aeriz/wysiwyg';\nimport '@aeriz/wysiwyg/style.css';\n\nconst editor = new AerizEditor({\n  element: document.querySelector('#editor')!,\n  initialHTML: '<p>안녕하세요</p>',\n  placeholder: '내용을 입력하세요',\n  theme: 'dark',\n  onChange: (html) => localStorage.setItem('draft', html),\n});\n\nconst viewer = new AerizViewer({\n  element: document.querySelector('#preview')!,\n});\neditor.onStateChange(() => viewer.setBlocks(editor.serialize()));\n```\n\n### CDN — 스크립트 태그\n\n빌드 단계 없이 바로 사용. 라이브러리는 글로벌 `window.AerizWysiwyg` 와 단축\n별칭 `window.AerizEditor` / `window.AerizViewer` 로 노출됩니다.\n\n```html\n<!-- ✓ 프로덕션 — 특정 버전 고정 (immutable, 가장 긴 캐시) -->\n<link\n  rel=\"stylesheet\"\n  href=\"https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@1.0.5/dist/aeriz-wysiwyg.min.css\"\n/>\n<script src=\"https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@1.0.5/dist/aeriz-wysiwyg.min.js\"></script>\n\n<!-- 1.x 트랙 — 패치만 자동 수신 -->\n<script src=\"https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@^1.0.5/dist/aeriz-wysiwyg.min.js\"></script>\n\n<!-- 항상 최신 — 프로토타이핑용 (프로덕션 권장 X) -->\n<script src=\"https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@latest/dist/aeriz-wysiwyg.min.js\"></script>\n\n<!-- unpkg 미러 -->\n<script src=\"https://unpkg.com/@aeriz/wysiwyg@1.0.5/dist/aeriz-wysiwyg.min.js\"></script>\n\n<div id=\"editor\"></div>\n<script>\n  const editor = new AerizEditor({\n    element: document.querySelector('#editor'),\n    initialHTML: '<p>안녕하세요</p>',\n    onChange: (html) => console.log(html),\n  });\n</script>\n```\n\n### CDN — ES Module\n\n```html\n<link\n  rel=\"stylesheet\"\n  href=\"https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@1.0.5/dist/aeriz-wysiwyg.min.css\"\n/>\n<script type=\"module\">\n  import {\n    AerizEditor,\n    AerizViewer,\n  } from 'https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@1.0.5/dist/aeriz-wysiwyg.esm.min.js';\n\n  new AerizEditor({ element: document.querySelector('#editor') });\n</script>\n```\n\n---\n\n## CDN — 어댑터도 스크립트 태그로\n\n`dist/adapters/*.js` 는 ESM 이라 `<script type=\"module\">` 로 CDN 에서 바로\n부르면 bare import 를 해석하지 못합니다. 그래서 **프레임워크 의존이 없는\n어댑터는 IIFE 로도 배포**합니다. 코어를 번들에 넣지 않고 전역\n`AerizWysiwyg` 를 참조하므로, 코어를 먼저 부르기만 하면 됩니다 (코어가 두 벌\n로드되지 않습니다).\n\n| 파일 | 노출 전역 | 역할 |\n| --- | --- | --- |\n| `dist/aeriz-wysiwyg-wc.min.js` | `AerizWysiwygWC` | `<aeriz-editor>` 자동 등록 |\n| `dist/aeriz-wysiwyg-jquery.min.js` | `AerizWysiwygJQuery` | `$.fn.aerizEditor` 자동 등록 |\n| `dist/aeriz-wysiwyg-adapter.min.js` | `AerizWysiwygAdapter` | `createEditorController` 등 |\n\n```html\n<link\n  rel=\"stylesheet\"\n  href=\"https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@1.0.5/dist/aeriz-wysiwyg.min.css\"\n/>\n<!-- 1) 코어 먼저 -->\n<script src=\"https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@1.0.5/dist/aeriz-wysiwyg.min.js\"></script>\n<!-- 2) 필요한 어댑터 -->\n<script src=\"https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@1.0.5/dist/aeriz-wysiwyg-wc.min.js\"></script>\n\n<aeriz-editor theme=\"dark\" placeholder=\"내용을 입력하세요\"></aeriz-editor>\n```\n\njQuery 는 jQuery 자체를 먼저 로드해야 자동 등록됩니다.\n\n```html\n<script src=\"https://code.jquery.com/jquery-3.7.1.min.js\"></script>\n<script src=\"https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@1.0.5/dist/aeriz-wysiwyg.min.js\"></script>\n<script src=\"https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@1.0.5/dist/aeriz-wysiwyg-jquery.min.js\"></script>\n<script>\n  $('#editor').aerizEditor({ value: '<p>안녕하세요</p>' });\n</script>\n```\n\n### React · Vue 를 CDN 으로 쓸 때 — import map\n\nReact / Vue 어댑터는 IIFE 로 제공하지 않습니다. 소비자 앱의 프레임워크\n인스턴스를 그대로 써야 하는데 전역 하나로 묶으면 인스턴스가 갈라져 훅이\n깨지기 때문입니다. CDN 에서는 import map 이 정답입니다.\n\n```html\n<script type=\"importmap\">\n  {\n    \"imports\": {\n      \"vue\": \"https://esm.sh/vue@3\",\n      \"@aeriz/wysiwyg\": \"https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@1.0.5/dist/aeriz-wysiwyg.esm.min.js\",\n      \"@aeriz/wysiwyg/vue\": \"https://cdn.jsdelivr.net/npm/@aeriz/wysiwyg@1.0.5/dist/adapters/vue.js\"\n    }\n  }\n</script>\n<script type=\"module\">\n  import { createApp, h, ref } from 'vue';\n  import { AerizEditor } from '@aeriz/wysiwyg/vue';\n\n  const html = ref('<p>안녕하세요</p>');\n  createApp({\n    render: () =>\n      h(AerizEditor, {\n        modelValue: html.value,\n        'onUpdate:modelValue': (v) => (html.value = v),\n      }),\n  }).mount('#app');\n</script>\n```\n\n> `@aeriz/wysiwyg` 항목이 반드시 있어야 합니다 — 어댑터가 그 이름으로 코어를\n> 가져오기 때문입니다. 빠뜨리면 브라우저가 bare specifier 해석에 실패합니다.\n\n---\n\n## Web Component\n\n프레임워크 의존이 전혀 없는 최소 공통 분모입니다. Shadow DOM 을 쓰지 않으므로\n전역 스타일시트가 그대로 적용됩니다.\n\n```html\n<link rel=\"stylesheet\" href=\"/aeriz-wysiwyg.min.css\" />\n<script type=\"module\">\n  import '@aeriz/wysiwyg/wc'; // import 만으로 자동 등록\n</script>\n\n<form action=\"/posts\" method=\"post\">\n  <!-- name 을 주면 폼 전송에 본문 HTML 이 함께 실립니다 (폼 연동 지원 브라우저) -->\n  <aeriz-editor name=\"body\" theme=\"dark\" placeholder=\"내용을 입력하세요\">\n  </aeriz-editor>\n  <button type=\"submit\">저장</button>\n</form>\n\n<script type=\"module\">\n  const el = document.querySelector('aeriz-editor');\n  el.addEventListener('change', (e) => console.log(e.detail.html));\n  el.value = '<p>안녕하세요</p>';\n  el.onImageUpload = async (file) => uploadAndGetUrl(file);\n</script>\n```\n\n| 속성 | 값 |\n| --- | --- |\n| `value` | 본문 HTML (프로퍼티로도 읽고 쓸 수 있음) |\n| `placeholder` | 빈 본문 안내 문구 |\n| `theme` | `light` / `dark` |\n| `locale` | `en` / `ko` / `ja` / `zh` |\n| `toolbar` | `false` · 항목 목록(`\"bold italic\"`) · JSON 객체 |\n| `image-upload-url`, `file-upload-url` | 업로드 API URL |\n\n프로퍼티: `value` · `editor` · `getBlocks()` · `focus()` ·\n`onImageUpload` · `onFileUpload`.\n이벤트: `input` · `change` (`detail.html`) · `aeriz-ready` (`detail.editor`).\n\n태그 이름이 충돌하면 접두사를 바꿀 수 있습니다.\n\n```ts\nimport { defineAerizElements } from '@aeriz/wysiwyg/wc';\ndefineAerizElements('my'); // <my-editor> / <my-viewer>\n```\n\n---\n\n## jQuery\n\n```html\n<script src=\"https://code.jquery.com/jquery-3.7.1.min.js\"></script>\n<link rel=\"stylesheet\" href=\"/aeriz-wysiwyg.min.css\" />\n<script type=\"module\">\n  import '@aeriz/wysiwyg/jquery'; // 전역 jQuery 가 있으면 자동 등록\n\n  $('#editor').aerizEditor({\n    value: '<p>안녕하세요</p>',\n    theme: 'dark',\n    onChange: (html) => console.log(html),\n  });\n\n  const html = $('#editor').aerizEditor('getHTML');\n  $('#editor').aerizEditor('setHTML', '<p>바꿈</p>');\n  $('#editor').aerizEditor('destroy');\n</script>\n```\n\n번들러 환경에서 전역 jQuery 를 쓰지 않는다면 명시적으로 등록합니다.\n\n```ts\nimport $ from 'jquery';\nimport { registerAerizJQuery } from '@aeriz/wysiwyg/jquery';\n\nregisterAerizJQuery($);\n```\n\n명령: `getHTML` · `getBlocks` · `setHTML` · `update` · `focus` ·\n`instance` · `destroy`. `aerizViewer` 도 같은 방식으로 동작합니다.\n\n같은 노드에 두 번 초기화하면 새 인스턴스를 만들지 않고 갱신으로 처리합니다.\n\n---\n\n## React\n\n```tsx\nimport { useState } from 'react';\nimport { AerizEditor, AerizViewer } from '@aeriz/wysiwyg/react';\nimport '@aeriz/wysiwyg/style.css';\n\nexport function Compose() {\n  const [html, setHtml] = useState('<p>안녕하세요</p>');\n\n  return (\n    <>\n      <AerizEditor\n        value={html}\n        onChange={setHtml}\n        theme=\"dark\"\n        placeholder=\"내용을 입력하세요\"\n        className=\"my-editor\"\n        imageUploadUrl=\"/api/upload\"\n      />\n      <AerizViewer html={html} />\n    </>\n  );\n}\n```\n\n`value` 를 그대로 되돌려줘도 캐럿이 튀지 않습니다 — 들어온 값이 에디터의 현재\n출력과 같으면 본문을 교체하지 않기 때문입니다.\n\n`ref` 로 명령형 API 에 접근합니다.\n\n```tsx\nconst ref = useRef<AerizEditorHandle>(null);\n// ref.current.editor    — 코어 인스턴스 (전체 API)\n// ref.current.getHTML() / setHTML(html) / focus()\n```\n\n---\n\n## Vue 3\n\n```vue\n<script setup>\nimport { ref } from 'vue';\nimport { AerizEditor, AerizViewer } from '@aeriz/wysiwyg/vue';\nimport '@aeriz/wysiwyg/style.css';\n\nconst html = ref('<p>안녕하세요</p>');\nconst editor = ref(null);\n</script>\n\n<template>\n  <AerizEditor\n    ref=\"editor\"\n    v-model=\"html\"\n    theme=\"dark\"\n    placeholder=\"내용을 입력하세요\"\n    @state-change=\"onStateChange\"\n    @ready=\"onReady\"\n  />\n  <AerizViewer :html=\"html\" />\n</template>\n```\n\n전역 등록도 가능합니다.\n\n```ts\nimport { AerizWysiwygPlugin } from '@aeriz/wysiwyg/vue';\napp.use(AerizWysiwygPlugin);\n```\n\n이벤트: `update:modelValue` · `change` · `state-change` · `ready`.\n`ref` 로 노출되는 것: `editor` · `getHTML()` · `setHTML()` · `focus()`.\n\n## Vue 2 (2.6 / 2.7)\n\nVue 2 관례에 따라 `v-model` 은 `value` prop + `input` 이벤트를 씁니다.\n\n```js\nimport { AerizEditor } from '@aeriz/wysiwyg/vue2';\nimport '@aeriz/wysiwyg/style.css';\n\nexport default {\n  components: { AerizEditor },\n  data: () => ({ html: '<p>안녕하세요</p>' }),\n  template: `\n    <AerizEditor ref=\"editor\" v-model=\"html\" theme=\"dark\" />\n  `,\n  methods: {\n    focusEditor() {\n      this.$refs.editor.focus();\n    },\n  },\n};\n```\n\n이 어댑터는 `vue` 를 import 하지 않습니다 (Vue 2 컴포넌트는 순수 옵션 객체).\n따라서 소비자 앱의 Vue 인스턴스와 이중화될 여지가 없습니다.\n\n---\n\n## Svelte (3 / 4 / 5)\n\n컴파일된 `.svelte` 컴포넌트가 아니라 **액션**으로 제공합니다. 액션은 순수 함수\n계약이라 Svelte 메이저 버전 세 개를 배포본 하나로 만족시킵니다.\n\n```svelte\n<script>\n  import { aerizEditor, aerizViewer } from '@aeriz/wysiwyg/svelte';\n  import '@aeriz/wysiwyg/style.css';\n\n  let html = '<p>안녕하세요</p>';\n</script>\n\n<div\n  use:aerizEditor={{\n    value: html,\n    onChange: (next) => (html = next),\n    theme: 'dark',\n    placeholder: '내용을 입력하세요',\n  }}\n/>\n\n<div use:aerizViewer={{ html }} />\n```\n\n---\n\n## Angular (14+)\n\nAngular 연동은 **TypeScript 소스로 배포**됩니다 — 소비자의 Angular 컴파일러가\n직접 컴파일하므로 Angular 14 이상 어느 버전에서도 같은 파일이 동작합니다.\n설정 방법(택 1)과 상세 문서는 [angular/README.md](./angular/README.md) 를\n참고하세요.\n\n`tsconfig.app.json` 의 `include` 에 한 줄 추가하면 끝입니다.\n\n```jsonc\n\"include\": [\"src/**/*.ts\", \"node_modules/@aeriz/wysiwyg/angular/*.ts\"]\n```\n\n```ts\nimport { Component } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { AerizEditorDirective } from '@aeriz/wysiwyg/angular';\n\n@Component({\n  standalone: true,\n  imports: [FormsModule, AerizEditorDirective],\n  template: `\n    <div aerizEditor [(ngModel)]=\"html\" theme=\"dark\"></div>\n    <div aerizViewer [html]=\"html\"></div>\n  `,\n})\nexport class ComposeComponent {\n  html = '<p>안녕하세요</p>';\n}\n```\n\n`[(value)]` · `[(ngModel)]` · `formControlName` 세 가지 바인딩을 모두\n지원합니다. 디렉티브는 에디터를 `NgZone` 밖에서 생성하므로 캐럿을 움직일 때마다\n변경 감지가 돌지 않습니다.\n\n---\n\n## 서버 / 엣지 런타임 (DOM 없음)\n\n저장된 `BlockSnapshot[]` 을 HTML · 마크다운 · 평문으로 바꿉니다. **CSS 를\nimport 하지 않고**, import 그래프 전체가 `document` / `window` 를 참조하지\n않습니다 — Cloudflare Workers(workerd) · Node · Deno · Bun 에서 그대로\n동작합니다.\n\n```ts\nimport {\n  renderBlocksToHTML,\n  blocksToMarkdown,\n  blocksToPlainText,\n} from '@aeriz/wysiwyg/server';\n\n// 발행용 HTML — 같은 입력이면 항상 같은 출력 (결정적 · 멱등)\nconst html = renderBlocksToHTML(post.blocks, { wrapper: 'content' });\n\n// 포맷 종속을 푸는 탈출구\nconst markdown = blocksToMarkdown(post.blocks);\n\n// 전문 검색 색인용\nconst text = blocksToPlainText(post.blocks, { blockSeparator: ' ' });\n```\n\n```ts\n// Cloudflare Worker\nexport default {\n  async fetch(req, env) {\n    const post = await env.DB.get('post:1', 'json');\n    return new Response(renderBlocksToHTML(post.blocks, { wrapper: 'content' }), {\n      headers: { 'content-type': 'text/html; charset=utf-8' },\n    });\n  },\n};\n```\n\n---\n\n## 키보드 단축키\n\nmacOS 는 `Ctrl` 대신 `Cmd`. 전체 목록과 근거는\n[SPEC.md §7](./SPEC.md#7-키보드-단축키--입력-규칙) 에 있습니다.\n\n| 동작 | 단축키 |\n| --- | --- |\n| 되돌리기 / 다시 실행 | `Ctrl+Z` / `Ctrl+Shift+Z` · `Ctrl+Y` |\n| 굵게 · 기울임 · 밑줄 · 취소선 | `Ctrl+B` · `Ctrl+I` · `Ctrl+U` · `Ctrl+Shift+X` |\n| **본문**으로 | `Ctrl+Alt+0` |\n| 제목 1~6 | `Ctrl+Alt+1` ~ `Ctrl+Alt+6` |\n| 번호 목록 · 글머리 목록 · 체크리스트 | `Ctrl+Alt+7` · `Ctrl+Alt+8` · `Ctrl+Alt+T` |\n| 인용구 · 코드 블록 | `Ctrl+Alt+9` · `Ctrl+Alt+C` |\n| 블록 이동 / 삭제 | `Ctrl+Shift+↑` `Ctrl+Shift+↓` / `Ctrl+Shift+D` |\n| 표: 다음 / 이전 셀 | `Tab` / `Shift+Tab` (마지막 셀에서 `Tab` → 새 행) |\n| 목록: 들여쓰기 / 내어쓰기 | `Tab` / `Shift+Tab` |\n\n**마크다운처럼 입력해도 됩니다.** 블록 맨 앞에서 `# ` `- ` `1. ` `> ` `` ``` ``\n`---` `- [ ] ` 를 치면 그 자리에서 유형이 바뀝니다.\n\n> 새로 만들어지는 블록의 기본 유형은 언제나 **본문**입니다. 제목 끝에서\n> `Enter` 를 눌러도 제목이 복제되지 않고 본문이 이어지며, 빈 제목·인용구·\n> 코드 블록에서 `Backspace` 를 누르면 본문으로 돌아옵니다.\n\n## 서버 sanitizer 와 함께 쓰기\n\n`getHTML()` 은 기본적으로 테마 색을 인라인 `style` 에 베이크합니다 —\n스타일시트 없이 어디에 붙여도 같은 시각으로 보이지만, `style` 속성을 제거하는\nsanitizer 를 통과하면 서식이 통째로 사라집니다.\n\n두 가지 대응이 있습니다.\n\n**1. 클래스 기반 출력으로 전환** — `style` 프로퍼티가 40여 개에서 10개로\n줄고, 정렬은 클래스로 표현됩니다.\n\n```ts\nnew AerizEditor({ element, htmlStyles: 'class' });  // getHTML/onChange 기본값\neditor.getHTML({ styles: 'class' });                // 호출 단위 재정의\n```\n\n출력은 `aeriz-wysiwyg.min.css` 를 로드한 페이지의\n`.aeriz-wysiwyg > .aw-content` 안에 넣어야 기본 서식이 적용됩니다.\n`renderBlocksToHTML(blocks, { wrapper: 'content' })` 가 그 컨테이너를 만들어\n줍니다.\n\n**2. 허용목록을 출력에 맞추기** — 등장할 수 있는 태그 · 속성 · style\n프로퍼티의 확정 목록이\n[SPEC.md §9 출력 HTML 허용목록](./SPEC.md#9-출력-html-허용목록) 에 있습니다.\n추측이 아니라 실측이며 `npm run allowlist` 로 재생성할 수 있습니다.\n\n> ⚠️ **HTML 가져오기 기능은 sanitizer 가 아닙니다.** 원본 스크립트가 실행되고\n> 이벤트 핸들러 속성이 제거되지 않습니다. 저장 전 서버 정화가 필수입니다 —\n> [SPEC.md §11](./SPEC.md#11-html-가져오기의-보안-경계) 참고.\n\n## 스냅샷 스키마 버전\n\n`editor.serialize()` 는 각 블록에 `version: 1` 을 기록합니다. 저장된 데이터를\n읽는 모든 경로가 `upgradeSnapshots()` 를 통과하므로, 버전이 올라가도 예전\n데이터가 그대로 열립니다. 변경 정책은\n[SPEC.md §10](./SPEC.md#10-blocksnapshot-스키마-버전-정책) 에 있습니다.\n\n## 직접 어댑터 만들기\n\n목록에 없는 프레임워크(Solid, Qwik, Lit …) 는 프레임워크 중립 컨트롤러 위에\n얇게 올리면 됩니다. 값 바인딩 · 캐럿 보존 · 재생성 판단이 이미 들어 있습니다.\n\n```ts\nimport { createEditorController } from '@aeriz/wysiwyg/adapter';\n\nconst controller = createEditorController(hostElement, {\n  value: '<p>안녕하세요</p>',\n  onChange: (html) => setState(html),\n});\n\ncontroller.update({ value: nextHtml });  // 바뀐 것만 반영\ncontroller.destroy();                    // 언마운트 시\n```\n\n## 빌드\n\n```bash\nnpm install\nnpm run build        # dist/ 에 IIFE / ESM / CJS / 어댑터 / CSS / .d.ts 생성\nnpm test             # 서버 렌더러 · getHTML · 어댑터 계약 테스트 (jsdom)\nnpm run typecheck\nnpm run allowlist    # 출력 HTML 허용목록 재생성\nnpm run version:sync # 문서·데모의 CDN 버전 표기를 package.json 에 맞춤\nnpm run version:check # 뒤처졌으면 실패 (CI 용)\nnpm run dev          # 데모 페이지 (http://localhost:5173)\n\nnpm run release:stage  # npm 업로드용 release/ 조립 + exports 경로 검증\nnpm run release:verify # release/ 에서 npm pack --dry-run\n```\n\n`dist/` 는 데모 서버의 publicDir 을 겸하고 개발용 비압축본·CDN 번들까지\n담고 있습니다. 실제로 npm 에 올라가는 것은 `release:stage` 가 `\"files\"` 만\n골라 조립한 `release/` 입니다. 배포 절차는 [RELEASE.md](./RELEASE.md) (붙여넣어\n실행하는 런북), 계정·권한·회수 등 배경은 [PUBLISHING.md](./PUBLISHING.md) 를\n참고하세요.\n\n데모는 세 페이지입니다.\n\n- `/index.html` — 에디터 기능 데모\n- `/docs.html` — **연동 · 직렬화 레퍼런스**. 이 README 의 내용을 사이드바 · 검색 가능한\n  API 표 · 라이브 플레이그라운드로 정리한 단일 페이지 문서입니다. 플레이그라운드에서\n  같은 문서가 `inline` / `class` HTML · 마크다운 · 평문 · 스냅샷 · 서버 렌더 여섯 가지로\n  어떻게 나오는지 실시간 비교할 수 있습니다.\n- `/frameworks.html` — 프레임워크 어댑터 데모. React · Vue 3 · Web Component ·\n  Svelte 액션 · jQuery 를 한 페이지에 올리고, 로드 직후 자동 점검을 실행합니다.\n\n### 문서 사이트 배포 — Cloudflare Workers\n\n`/docs.html` 을 그대로 정적 사이트로 올릴 수 있습니다. `docs:build` 가\n`examples/docs.html` 과 라이브러리 산출물을 `docs/` 에 모으고, 코드가 없는\n**정적 자산 전용 Worker** (`wrangler.toml`) 가 그 폴더를 서빙합니다. 별도\nPages 프로젝트가 필요 없습니다.\n\n```bash\nnpx wrangler login    # 처음 한 번만\n\nnpm run docs:build    # docs/ 조립\nnpm run docs:preview  # 로컬 Workers 런타임으로 확인 (wrangler dev)\nnpm run docs:deploy   # 배포\n```\n\n페이지 HTML 은 데모와 배포본이 같은 파일입니다 — `examples/docs.html` 이\n라이브러리를 루트 절대 경로로 부르고, 배포 시에도 산출물을 사이트 루트에 같이\n두기 때문에 경로 분기가 없습니다. 캐시·보안 헤더는 `docs/_headers` 로 함께\n생성됩니다. `docs/` 는 파생물이라 git 에 추적하지 않습니다.\n\n### 오프라인 단일 파일\n\n문서 페이지를 외부에 공유하거나 오프라인으로 열어야 하면 라이브러리를 인라인한\n단일 파일로 만들 수 있습니다 (외부 요청 0건).\n\n```bash\nnode scripts/build-docs-artifact.mjs docs-standalone.html\n```\n\n설치된 Chrome 으로 그 페이지를 실제 검증할 수 있습니다 (playwright-core 는\n브라우저를 내려받지 않고 시스템 Chrome 을 그대로 씁니다).\n\n```bash\nnpm run dev                                    # 다른 터미널에서\nnpm run test:browser                           # 헤드리스 검증 + 스크린샷\nnode scripts/browser-check.mjs --headed        # 창을 띄워서 보기\n```\n\n5173 이 이미 쓰이는 중이면 데모를 다른 포트로 띄우고 주소를 넘기면 됩니다.\n\n```bash\nnpx vite --config vite.demo.config.ts --port 5347\nnode scripts/browser-check.mjs http://localhost:5347/frameworks.html\n```\n\n## 라이선스\n\nApache-2.0\n","readmeFilename":"README.md"}