{"id":19965437,"url":"https://github.com/tategakibunko/nehan","last_synced_at":"2025-07-11T07:04:17.240Z","repository":{"id":33015486,"uuid":"149859730","full_name":"tategakibunko/nehan","owner":"tategakibunko","description":"Dynamic html layout engine for paged-media written by Typescript","archived":false,"fork":false,"pushed_at":"2023-09-07T22:20:11.000Z","size":2783,"stargazers_count":35,"open_issues_count":0,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-13T02:04:57.063Z","etag":null,"topics":["html","layout-engine","nehan","paged-media","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tategakibunko.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-09-22T08:38:21.000Z","updated_at":"2025-04-06T07:28:35.000Z","dependencies_parsed_at":"2024-06-19T00:17:54.761Z","dependency_job_id":"85420eeb-650d-4199-b9a0-4a2cbc9b700c","html_url":"https://github.com/tategakibunko/nehan","commit_stats":null,"previous_names":[],"tags_count":104,"template":false,"template_full_name":null,"purl":"pkg:github/tategakibunko/nehan","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tategakibunko%2Fnehan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tategakibunko%2Fnehan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tategakibunko%2Fnehan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tategakibunko%2Fnehan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tategakibunko","download_url":"https://codeload.github.com/tategakibunko/nehan/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tategakibunko%2Fnehan/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264752563,"owners_count":23658653,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["html","layout-engine","nehan","paged-media","typescript"],"created_at":"2024-11-13T02:28:47.052Z","updated_at":"2025-07-11T07:04:17.197Z","avatar_url":"https://github.com/tategakibunko.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nehan\n\n## Introduction\n\nDynamic html layout engine for paged-media written by [Typescript](https://www.typescriptlang.org/).\n\n## Install\n\n```\nnpm install nehan\n```\n\n## Demo\n\nSee [Nehan Reader](https://chrome.google.com/webstore/detail/nehan-reader/bebbekgiffjpgjlgkkhmlgheckolmdcf?hl=ja) at Chrome Web Store.\n\nOr [nehan-player demo](https://tategakibunko.github.io/nehan-player#demo)\n\n### How to use Nehan Reader\n\n1. Install [Nehan Reader](https://chrome.google.com/webstore/detail/nehan-reader/bebbekgiffjpgjlgkkhmlgheckolmdcf?hl=ja).\n2. Goto any site you want to read as paged-media.\n3. Click the browser action button \u003cimg src=\"https://raw.github.com/tategakibunko/nehan/master/example/images/nehan-reader-48.png\" width=\"32\" height=\"32\" /\u003e\n4. Then you'll see paged site.\n\n## Example\n\nSee [example](https://github.com/tategakibunko/nehan/tree/master/example) directory.\n\n## Usage\n\n### simple usage with no styling\n\n```typescript\nimport { PagedNehanDocument } from 'nehan';\n\nconst $result = document.querySelector(\"#result\");\n\nnew PagedNehanDocument(\"\u003ch1\u003ehello, nehan!\u003c/h1\u003e\", {}).render({\n  onPage: (ctx) =\u003e {\n    const evaluatedPage = ctx.caller.getPage(ctx.page.index);\n    $result.appendChild(evaluatedPage.dom);\n    $result.appendChild(document.createElement(\"hr\"));\n  },\n  onComplete: (ctx) =\u003e {\n    console.log(`finished! ${ctx.time}msec`);\n  }\n});\n```\n\n### render with style\n\n```typescript\nimport { PagedNehanDocument, CssStyleSheet } from 'nehan';\n\nconst $result = document.querySelector(\"#result\");\n\nnew PagedNehanDocument(\"\u003ch1\u003ehello, nehan!\u003c/h1\u003e\", {\n  styleSheets:[\n    new CssStyleSheet({\n      \"body\":{\n        writihgMode:\"horizontal-tb\", // or \"vertical-rl\"\n        fontSize:\"16px\",\n        padding: \"1em\",\n        measure: \"640px\", // means 'width' in horizontal-tb, 'height' in vertical-rl.\n        extent: \"480px\"   // means 'height' in horizontal-tb, 'width' in vertical-rl.\n      },\n      \"h1\":{\n        marginAfter: \"1em\",   // means 'margin-bottom' in horizontal-tb, 'margin-left' in vertical-rl\n        paddingStart: \"0.5em\" // means 'padding-left' in horizontal-tb, 'padding-top' in vertical-rl\n      }\n    }\n  ]\n}).render({\n  onPage: (ctx) =\u003e {\n    const evaluatedPage = ctx.caller.getPage(ctx.page.index);\n    $result.appendChild(evaluatedPage.dom);\n    $result.appendChild(document.createElement(\"hr\"));\n  },\n  onComplete: (ctx) =\u003e {\n    console.log(`finished! ${ctx.time}msec`);\n  }\n});\n```\n\n## About logical size\n\nTo handle documents that are independent of the character direction, we use the `logical size`.\n\n- `measure` means the size in the inline direction.\n- `extent` means the size in the block direction.\n\n### logical-size - physical-size table\n\n| logical-size\\writing-mode | horizontal-tb | vertical-rl   | vertical-lr   |\n| ------------------------- | ------------- | ------------- | ------------- |\n| measure                   | width         | height        | height        |\n| extent                    | height        | width         | width         |\n\n## About logical direction\n\nTo handle documents that are independent of the character direction, we use the `logical direction`.\n\n- `start` means inline level heading direction.\n- `end` means inline level trailing direction.\n- `before` measn block level heading direction.\n- `after` means block level trailing direction.\n\n#### Example1 (logical-margin - physical-margin table)\n\n| logical-direction\\writing-mode | horizontal-tb | vertical-rl   | vertical-lr   |\n| ------------------------------ | ------------- | ------------- | ------------- |\n| margin-start                   | margin-left   | margin-top    | margin-top    |\n| margin-end                     | margin-right  | margin-bottom | margin-bottom |\n| margin-before                  | margin-top    | margin-right  | margin-left   |\n| margin-after                   | margin-bottom | margin-left   | margin-right  |\n\nThe same is true for `padding` and `border`(`border-xxx-width`, `border-xxx-color`, `border-xxx-style`).\n\n#### Example2 (logical-border-radius - physical-border-radius table)\n\n| logical-direction\\writing-mode | horizontal-tb | vertical-rl   | vertical-lr   |\n| ------------------------------ | ------------- | ------------- | ------------- |\n| border-before-start-radius     | border-top-left-radius  | border-top-right-radius    | border-top-left-radius    |\n| border-before-end-radius     | border-top-right-radius  | border-bottom-right-radius    | border-bottom-left-radius    |\n| border-after-end-radius     | border-bottom-right-radius  | border-bottom-left-radius    | border-bottom-right-radius    |\n| border-after-start-radius     | border-bottom-left-radius  | border-top-left-radius    | border-top-right-radius    |\n\n### Shothanded logical property\n\nIf you set `margin` like `margin:1em 2em 3em 4em`, then it means `margin-before:1em`, `margin-end:2em`, `margin-after:3em`, `margin-start:4em`.\n\nIf you set `margin` like `margin:1em 2em 3em`, then it means `margin-before:1em`, `margin-end:2em`, `margin-after:3em`, `margin-start:2em`.\n\nIf you set `margin` like `margin:1em 2em`, then it means `margin-before:1em`, `margin-end:2em`, `margin-after:1em`, `margin-start:2em`.\n\nIf you set `margin` like `margin:1em`, then it means `margin-before:1em`, `margin-end:1em`, `margin-after:1em`, `margin-start:1em`.\n\nThe same is true for `padding` and `border`(`border-xxx-width`, `border-xxx-color`, `border-xxx-style`).\n\n## Dynamic Style\n\nYou can define functional value for each selector(css property name is `!xxx`).\n\nIn following example, all elements that matches `.require-xx` will cause page-break if rest block size(restExtent) is smaller than `xx`px.\n\n```typescript\nimport { CssStyleSheet, DynamicStyleContext, CssDeclarationBlock } from 'nehan';\n\nfunction requiredExtent(requiredSize: number) {\n  return (ctx: DynamicStyleContext): CssDeclarationBlock | undefined =\u003e {\n    if (!ctx.parentContext) {\n      return undefined;\n    }\n    const restExtent = ctx.parentContext.restExtent;\n    if (restExtent \u003e= requiredSize) {\n      return undefined; // enough block size is left!\n    }\n    // restExtent \u003c requiredSize(not enough block size left)\n    return { \"page-break-before\": \"always\" };\n  };\n}\n\nconst myStyleSheet = new CssStyleSheet({\n  \".require-60\": {\n    \"!dynamic\": requiredExtent(60)\n  }\n});\n```\n\n## DOM generation hook\n\nYou can define dom generation hook for each selector element like this(css property name is `@xxx`).\n\n```typescript\nimport { CssStyleSheet, DomCallbackContext } from 'nehan';\n\nconst myStyleSheet = new CssStyleSheet({\n  \".foo\": {\n    \"@create\": (ctx: DomCallbackContext) =\u003e {\n      ctx.dom.onclick = (e) =\u003e {\n        alert(`${ctx.selector} is clicked!`); // .foo is clicked!\n      };\n    }\n  }\n});\n```\n\n## Plugins\n\n- [nehan-katex](https://github.com/tategakibunko/nehan-katex)\n- [nehan-anchor](https://github.com/tategakibunko/nehan-anchor)\n- [nehan-highlight](https://github.com/tategakibunko/nehan-highlight)\n- [nehan-speech-border](https://github.com/tategakibunko/nehan-speech-border)\n\n## Development\n\n`npm run build` and library is generated in `dist` directory.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftategakibunko%2Fnehan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftategakibunko%2Fnehan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftategakibunko%2Fnehan/lists"}