{"_id":"@einfach.design/observe-geometry-stability","_rev":"2-2c77c38ba65a3867e9acbe414da5c2e7","name":"@einfach.design/observe-geometry-stability","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@einfach.design/observe-geometry-stability","version":"1.0.0","license":"MIT","_id":"@einfach.design/observe-geometry-stability@1.0.0","maintainers":[{"name":"elstermann","email":"b2b@elstermann.eu"}],"dist":{"shasum":"adc05483412579e3b216c3f0cf4397006b40c7e0","tarball":"https://registry.npmjs.org/@einfach.design/observe-geometry-stability/-/observe-geometry-stability-1.0.0.tgz","fileCount":6,"integrity":"sha512-S/eUFblxOPmuJ9jxCEqwh1gr3qQebxW9WXSrVFtzo1s+4uZAAy0bV32DPZgjkIaMerOlcSr/sVjmNsS221gJEg==","signatures":[{"sig":"MEUCIQDNAGS1RYwOreOjYquo/ivmPsjSgYE8g2kJzflTtuxE7wIgauB6VGUN45RHEhdg7vuiplMViMq8UC/ewzlKiVbaU04=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":38287},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"gitHead":"2b9a34b559c0979e21d9af80152f9bc85fccf00e","scripts":{"lint":"eslint .","test":"vitest run","build":"tsup && tsc -p tsconfig.build.json","clean":"rimraf dist","format":"prettier README.md package.json src tests tsconfig.build.json tsconfig.json tsup.config.ts vitest.config.ts --write","lint:fix":"eslint . --fix","typecheck":"tsc -p tsconfig.json --noEmit","format:check":"prettier README.md package.json src tests tsconfig.build.json tsconfig.json tsup.config.ts vitest.config.ts --check","smoke:release":"node ../../scripts/smoke-observe-geometry-release.mjs","prepublishOnly":"rimraf dist && tsup && tsc -p tsconfig.build.json && eslint . && tsc -p tsconfig.json --noEmit && prettier README.md package.json src tests tsconfig.build.json tsconfig.json tsup.config.ts vitest.config.ts --check && vitest run"},"_npmUser":{"name":"elstermann","email":"b2b@elstermann.eu"},"_npmVersion":"10.9.4","description":"Low-level, runtime-free once API for observing whether an element's geometry is stable or unstable across animation frames.","directories":{},"sideEffects":false,"_nodeVersion":"22.22.0","_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.2.3","vite":"8.0.12","rimraf":"^6.0.1","vitest":"^4.1.6","typescript":"^6.0.3","@types/node":"^25.7.0"},"_npmOperationalInternal":{"tmp":"tmp/observe-geometry-stability_1.0.0_1780494124998_0.6513146490568571","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@einfach.design/observe-geometry-stability","version":"1.0.1","license":"MIT","type":"module","sideEffects":false,"keywords":["geometry-stability","layout-stability","element-stability","geometry-measurement","layout-measurement","dom-geometry","bounding-client-rect","stability-detection","frame-based","configurable","performance","dom","browser","typescript","esm"],"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"types":"./dist/index.d.ts","main":"./dist/index.js","scripts":{"build":"tsup && tsc -p tsconfig.build.json","clean":"rimraf dist","lint":"eslint .","lint:fix":"eslint . --fix","test":"vitest run","typecheck":"tsc -p tsconfig.json --noEmit","prepublishOnly":"rimraf dist && tsup && tsc -p tsconfig.build.json && eslint . && tsc -p tsconfig.json --noEmit && prettier README.md package.json src tests tsconfig.build.json tsconfig.json tsup.config.ts vitest.config.ts --check && vitest run","smoke:release":"node ../../scripts/smoke-observe-geometry-release.mjs","format":"prettier README.md package.json src tests tsconfig.build.json tsconfig.json tsup.config.ts vitest.config.ts --write","format:check":"prettier README.md package.json src tests tsconfig.build.json tsconfig.json tsup.config.ts vitest.config.ts --check"},"devDependencies":{"@types/node":"^25.7.0","rimraf":"^6.0.1","tsup":"^8.2.3","typescript":"^6.0.3","vite":"8.0.12","vitest":"^4.1.6"},"_id":"@einfach.design/observe-geometry-stability@1.0.1","gitHead":"2b9a34b559c0979e21d9af80152f9bc85fccf00e","description":"Low-level, runtime-free once API for observing whether an element's geometry is stable or unstable across animation frames.","_nodeVersion":"22.22.0","_npmVersion":"10.9.4","dist":{"integrity":"sha512-QE41s439SiaMm80mg4r07nCPK0XkcS5O7D8G/tclGcs6hMVHDHEESnZQ2JMZBt40wvUz+iBdOrZeKK/NTxDCqQ==","shasum":"627f87450a96b16c40344b808bcc4e21645728c7","tarball":"https://registry.npmjs.org/@einfach.design/observe-geometry-stability/-/observe-geometry-stability-1.0.1.tgz","fileCount":6,"unpackedSize":38624,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGMzMYidEQO7iF4qihGcmz3blcF21p15mdX6/+V+ZCMfAiEAqa4NcLTm1luNrzEbJPSaSidGueHlVaA1WyABawB1/Zw="}]},"_npmUser":{"name":"elstermann","email":"b2b@elstermann.eu"},"directories":{},"maintainers":[{"name":"elstermann","email":"b2b@elstermann.eu"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/observe-geometry-stability_1.0.1_1780497396079_0.6411756704273077"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-03T13:42:04.730Z","modified":"2026-06-03T14:36:36.407Z","1.0.0":"2026-06-03T13:42:05.156Z","1.0.1":"2026-06-03T14:36:36.230Z"},"license":"MIT","description":"Low-level, runtime-free once API for observing whether an element's geometry is stable or unstable across animation frames.","maintainers":[{"name":"elstermann","email":"b2b@elstermann.eu"}],"readme":"# @einfach.design/observe-geometry-stability\n\nLow-level, runtime-free once API for observing whether an element's geometry is\nstable or unstable across animation frames.\n\n```ts\nimport { geometryStability } from \"@einfach.design/observe-geometry-stability\";\n\nawait geometryStability.next({\n  stable: true,\n  target: \"#main\",\n  requiredFrames: 3,\n  tolerance: { x: 0, y: 0, width: 0, height: 0 },\n});\n```\n\n`next(...)` resolves when the requested state is observed over the configured\nmeasurement window. Stability is evaluated over `x`, `y`, `width`, and `height`;\neach dimension is stable when `max - min <= tolerance` across the window.\n\n## Options\n\n```ts\ntype GeometryStabilityNextOptions = {\n  stable: boolean;\n  target: string | ElementLike;\n  root?: RootLike | null;\n  requiredFrames?: number;\n  tolerance?:\n    | number\n    | { x?: number; y?: number; width?: number; height?: number };\n  timeoutMs?: number;\n  abortSignal?: AbortSignalLike;\n};\n```\n\nDefaults:\n\n- `requiredFrames: 3`\n- `tolerance: 0`\n- no timeout unless `timeoutMs` is provided\n\n`requiredFrames` must be a finite integer `>= 1`. `stable: false` requires at\nleast two frames because one frame cannot prove instability.\n\n`tolerance` values must be finite numbers `>= 0`. Object-form tolerance defaults\nomitted dimensions to `0`.\n\n`timeoutMs` must be a finite number `>= 0`. It is a technical observation\ntimeout and rejects with `geometry.timeout` if the requested state is not\nobserved in time.\n\n## Dependency Injection\n\nThe package uses structural dependencies so it can be tested without a browser\nand consumed without DOM ambient TypeScript libs.\n\n```ts\nawait geometryStability.next(\n  { stable: true, target: \"#main\" },\n  {\n    window: windowLike,\n    document: rootLike,\n  },\n);\n```\n\n`window` must provide `requestAnimationFrame` and `cancelAnimationFrame`.\n`timeoutMs` also requires `setTimeout` and `clearTimeout`.\n\n## Root And Target Behavior\n\n`target` can be an `ElementLike` or a selector string. Element targets are used\ndirectly. Selector targets are resolved through a root:\n\n- `root` omitted or `undefined` uses the injected `document`, then global\n  `document`.\n- `root: null` rejects with `geometry.root.required`.\n- invalid root objects reject with `geometry.root.invalid`.\n- selector syntax errors from `querySelector(...)` reject with\n  `geometry.target.invalid`.\n- missing selector targets reject with `geometry.target.missing`.\n\n## SSR And Non-Browser Behavior\n\nThe package is not a silent no-op when browser primitives are missing. If no\nusable window dependency or global window-like object is available, `next(...)`\nrejects with `geometry.window.required`.\n\n## Abort And Timeout\n\n`abortSignal` uses the exported structural `AbortSignalLike` type. A real\nbrowser or Node `AbortSignal` is structurally compatible, but the public types do\nnot require DOM ambient libs.\n\nConfiguration, window, and target validation happen before a pre-aborted signal\nis handled. This keeps configuration errors deterministic.\n\nOn abort, the pending animation frame and timeout are cleaned up and the promise\nrejects with `geometry.abort`.\n\n## Result Shape\n\n```ts\ntype GeometryStabilityResult = Readonly<{\n  stable: boolean;\n  rect: { x: number; y: number; width: number; height: number };\n  timestamp: number;\n  frames: readonly Readonly<{\n    x: number;\n    y: number;\n    width: number;\n    height: number;\n  }>[];\n}>;\n```\n\nThe result object, `rect`, `frames`, and each frame entry are detached and\nfrozen.\n\n## Error Codes\n\n`next(...)` rejects with `Error` instances whose message is one of:\n\n- `geometry.options.invalid`\n- `geometry.dependencies.invalid`\n- `geometry.stable.invalid`\n- `geometry.window.required`\n- `geometry.target.invalid`\n- `geometry.target.missing`\n- `geometry.root.required`\n- `geometry.root.invalid`\n- `geometry.requiredFrames.invalid`\n- `geometry.requiredFrames.unsupported`\n- `geometry.tolerance.invalid`\n- `geometry.rect.invalid`\n- `geometry.abort`\n- `geometry.timeout.invalid`\n- `geometry.timeout.unsupported`\n- `geometry.timeout`\n\n## License\n\nMIT. Credit to einfach.design is appreciated, but not required.\n","readmeFilename":"README.md","keywords":["geometry-stability","layout-stability","element-stability","geometry-measurement","layout-measurement","dom-geometry","bounding-client-rect","stability-detection","frame-based","configurable","performance","dom","browser","typescript","esm"]}