{"_id":"@adelalawdi/fnon2","_rev":"7-552918dc755cae6198bace73797fe49b","name":"@adelalawdi/fnon2","dist-tags":{"latest":"2.0.6"},"versions":{"2.0.0":{"name":"@adelalawdi/fnon2","version":"2.0.0","keywords":["Fnon","Hint","Ask","Confrim","Dialouge","Loading","Context Menu","Date Picker","Toast","Modal"],"author":{"name":"Adel Alawdy"},"license":"MIT","_id":"@adelalawdi/fnon2@2.0.0","maintainers":[{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"}],"dist":{"shasum":"b424afe8b9f8878a5724c7c9717a658414a1aec4","tarball":"https://registry.npmjs.org/@adelalawdi/fnon2/-/fnon2-2.0.0.tgz","fileCount":5,"integrity":"sha512-nNlZyHEMf8OP8VJzCiiRLDdXnUYzVVBmpr6hjESw7qTbx1ZdLtZ2bXe5ET8QDT5nCSN67oE8204L5NszNiECEw==","signatures":[{"sig":"MEUCIQCPCvk/rA2qr15Kj7PoNfDhT5l1dYFRk1Wv2jrkc9YHAwIgeiIpeSF5dDWxZVY0A0leSrVCPYY4TJbDsb6AMDPoPso=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":236263},"main":"fnon.min.js","gitHead":"450e86b0876b25fc22f012212ce48ef779636fcf","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"},"repository":{"url":"(https://github.com/superawdi/Fnon2)","type":"git"},"_npmVersion":"11.15.0","description":"Lightweight modal, toast, spinner, date picker, and context menu library. No dependencies. 42 KB minified (12 KB gzip). Works in all modern browsers.","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/fnon2_2.0.0_1782884387133_0.5418406438626928","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"@adelalawdi/fnon2","version":"2.0.1","keywords":["Fnon","Hint","Ask","Confrim","Dialouge","Loading","Context Menu","Date Picker","Toast","Modal"],"author":{"name":"Adel Alawdy"},"license":"MIT","_id":"@adelalawdi/fnon2@2.0.1","maintainers":[{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"}],"dist":{"shasum":"32bdbb60bd74f175adda0449e51da418791c7ba9","tarball":"https://registry.npmjs.org/@adelalawdi/fnon2/-/fnon2-2.0.1.tgz","fileCount":5,"integrity":"sha512-4kpSFJA06bCsCRdPcyOA5rsTjV0EF6xPEO5nhYi1qGk+i609AoIhQ/hBm+SzSQvyFQKZwxLCeidQDX5Un22g+A==","signatures":[{"sig":"MEYCIQCDfQvGk/Ulh7F70A6v6f+YPIRiIEVh5HbV6qAzFVBD6gIhALhpcHvtcNrCHIKQgRBDmdb/mWvxZS4KDbqTEZWetu/D","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":237811},"main":"fnon.min.js","gitHead":"be1500840056469b2f2bd1bd6b4287c3a5e85005","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"},"repository":{"url":"(https://github.com/superawdi/Fnon2)","type":"git"},"_npmVersion":"11.15.0","description":"Lightweight modal, toast, spinner, date picker, and context menu library. No dependencies. 42 KB minified (12 KB gzip). Works in all modern browsers.","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/fnon2_2.0.1_1783207801985_0.6473574840767142","host":"s3://npm-registry-packages-npm-production"}},"2.0.2":{"name":"@adelalawdi/fnon2","version":"2.0.2","keywords":["Fnon","Hint","Ask","Confrim","Dialouge","Loading","Context Menu","Date Picker","Toast","Modal"],"author":{"name":"Adel Alawdy"},"license":"MIT","_id":"@adelalawdi/fnon2@2.0.2","maintainers":[{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"}],"dist":{"shasum":"7bf651f0d2dac9914c8f543fb5069bc9827a6f70","tarball":"https://registry.npmjs.org/@adelalawdi/fnon2/-/fnon2-2.0.2.tgz","fileCount":5,"integrity":"sha512-AlNYCamq8LllvqeIBjmvR6Jr11UvEP3x/HYNUBBD5xLq+NU1xt0X3GOkCAkX6oBUZ47zTn4eZjz/KgTjTdQYqQ==","signatures":[{"sig":"MEUCIQDM7iVEHtLsIONyf8RicsuA533EQM7MaSEo03vfPwXXQAIgRFU6LHMJGwtGosfZod72NH27c4U+WkfO40TUHyTCYEY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":245619},"main":"fnon.min.js","gitHead":"2d129d43c9f7915eb4c0dec3a50cb15cc2c51a99","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"},"repository":{"url":"(https://github.com/superawdi/Fnon2)","type":"git"},"_npmVersion":"11.15.0","description":"Lightweight modal, toast, spinner, date picker, and context menu library. No dependencies. 42 KB minified (12 KB gzip). Works in all modern browsers.","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/fnon2_2.0.2_1783283021388_0.585326316525449","host":"s3://npm-registry-packages-npm-production"}},"2.0.3":{"name":"@adelalawdi/fnon2","version":"2.0.3","keywords":["Fnon","Hint","Ask","Confrim","Dialouge","Loading","Context Menu","Date Picker","Toast","Modal"],"author":{"name":"Adel Alawdy"},"license":"MIT","_id":"@adelalawdi/fnon2@2.0.3","maintainers":[{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"}],"dist":{"shasum":"99aa835bc751a8a17a3364d8c87e014b85d32fc9","tarball":"https://registry.npmjs.org/@adelalawdi/fnon2/-/fnon2-2.0.3.tgz","fileCount":5,"integrity":"sha512-DXltsWaypRhZzBMwUyrQUj4UftPpe1Iy0DY1mEQj3Fs1I8NLgIq5OuRfqkmkGb8ZvoAEewKBM0O+lIS/ZaTawg==","signatures":[{"sig":"MEUCIQDVnek99l2RwqmbcDchdpaqpoB43u8KiQLNj9mCj/GrZgIgLDENUxKXDydwDVblMnmT5EMUgqTeHyqVUniK5l9CIaE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":243473},"main":"fnon.min.js","gitHead":"bc1e94fce5d933a81b1c682d523b339e1f112b09","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"},"repository":{"url":"(https://github.com/superawdi/Fnon2)","type":"git"},"_npmVersion":"11.15.0","description":"Lightweight modal, toast, spinner, date picker, and context menu library. No dependencies. 42 KB minified (12 KB gzip). Works in all modern browsers.","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/fnon2_2.0.3_1783483395995_0.5759170129422255","host":"s3://npm-registry-packages-npm-production"}},"2.0.4":{"name":"@adelalawdi/fnon2","version":"2.0.4","keywords":["Fnon","Hint","Ask","Confrim","Dialouge","Loading","Context Menu","Date Picker","Toast","Modal"],"author":{"name":"Adel Alawdy"},"license":"MIT","_id":"@adelalawdi/fnon2@2.0.4","maintainers":[{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"}],"dist":{"shasum":"9ecb37a4d0fc482c28815aec9171ef79e0f34576","tarball":"https://registry.npmjs.org/@adelalawdi/fnon2/-/fnon2-2.0.4.tgz","fileCount":5,"integrity":"sha512-LpQNCierL1gfV+sgW2ULWPrX9/hPkmQIx/8WRvOSLOl565QaKf9XBapLoGGkf5IezXBJYpJBq3iznk1n7/tsFw==","signatures":[{"sig":"MEUCIQDjDiI95uMXn4gpOmd/BRG1oxCe8impqjxouhv1BN73yAIgIG+suzifbvrOU9LbqewJDX4L7h6cWS+RGVP2cu1bdJY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":246920},"main":"fnon.min.js","gitHead":"e774a9ffc3035a06d88d8fd3b82c4b35293e118f","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"},"repository":{"url":"(https://github.com/superawdi/Fnon2)","type":"git"},"_npmVersion":"11.15.0","description":"Lightweight modal, toast, spinner, date picker, and context menu library. No dependencies. 42 KB minified (12 KB gzip). Works in all modern browsers.","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/fnon2_2.0.4_1783751565927_0.1528823675511113","host":"s3://npm-registry-packages-npm-production"}},"2.0.5":{"name":"@adelalawdi/fnon2","version":"2.0.5","keywords":["Fnon","Hint","Ask","Confrim","Dialouge","Loading","Context Menu","Date Picker","Toast","Modal"],"author":{"name":"Adel Alawdy"},"license":"MIT","_id":"@adelalawdi/fnon2@2.0.5","maintainers":[{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"}],"dist":{"shasum":"c171b7fd07243d9c953ada57444032e074787a78","tarball":"https://registry.npmjs.org/@adelalawdi/fnon2/-/fnon2-2.0.5.tgz","fileCount":5,"integrity":"sha512-+maWhYIjuTO+csT4Cj6W/tJELbf4ZQWBlU3LkDgD3ZLSHmGNhqeXbbdV5YVDCEZVUXDcLG55Ss31/KmCcoxDRA==","signatures":[{"sig":"MEQCICeZcfxk0/DKny7vHVn5pXAS6PBDUDcrNKOIj+shb43UAiBpcIivkzXftU3HMoGnqpCdS1SOAiKZqYfe/YHC05O2kQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":262108},"main":"fnon.min.js","gitHead":"1951897344a305b51721dee94aee0c441c5ba501","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"},"repository":{"url":"(https://github.com/superawdi/Fnon2)","type":"git"},"_npmVersion":"11.15.0","description":"Lightweight modal, toast, spinner, date picker, and context menu library. No dependencies. 42 KB minified (12 KB gzip). Works in all modern browsers.","directories":{},"_nodeVersion":"22.22.3","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/fnon2_2.0.5_1784171331118_0.5205291490537987","host":"s3://npm-registry-packages-npm-production"}},"2.0.6":{"name":"@adelalawdi/fnon2","version":"2.0.6","description":"Lightweight modal, toast, spinner, date picker, and context menu library. No dependencies. 42 KB minified (12 KB gzip). Works in all modern browsers.","main":"fnon.min.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"(https://github.com/superawdi/Fnon2)"},"keywords":["Fnon","Hint","Ask","Confrim","Dialouge","Loading","Context Menu","Date Picker","Toast","Modal"],"author":{"name":"Adel Alawdy"},"license":"MIT","gitHead":"87f2b598f274db2ba38e0db9a4f3ec6c485b974c","_id":"@adelalawdi/fnon2@2.0.6","_nodeVersion":"22.22.3","_npmVersion":"11.15.0","dist":{"integrity":"sha512-lUrt8ooB0UiSeUVEPWffcYWM6k6XQm4V0nn1D8NxP75uM2gdyqV08dDSoqv8S7I6jvAZ6P7ydjktJfJMl1v6iw==","shasum":"58a7ece73517050f6da73e09eae576cad2bcde45","tarball":"https://registry.npmjs.org/@adelalawdi/fnon2/-/fnon2-2.0.6.tgz","fileCount":5,"unpackedSize":281651,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDkFNlyxgc5AkUM1L+rcP4F+W6Fd+OdIdAeuolch4klEgIgGThLWkLAYIAtvr76YDFHXWlQ5a8T7+GfSHxO95TpTZo="}]},"_npmUser":{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"},"directories":{},"maintainers":[{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/fnon2_2.0.6_1785163522082_0.3295985627752218"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-01T05:39:47.045Z","modified":"2026-07-27T14:45:22.376Z","2.0.0":"2026-07-01T05:39:47.274Z","2.0.1":"2026-07-04T23:30:02.137Z","2.0.2":"2026-07-05T20:23:41.508Z","2.0.3":"2026-07-08T04:03:16.137Z","2.0.4":"2026-07-11T06:32:46.089Z","2.0.5":"2026-07-16T03:08:51.286Z","2.0.6":"2026-07-27T14:45:22.236Z"},"author":{"name":"Adel Alawdy"},"license":"MIT","keywords":["Fnon","Hint","Ask","Confrim","Dialouge","Loading","Context Menu","Date Picker","Toast","Modal"],"repository":{"type":"git","url":"(https://github.com/superawdi/Fnon2)"},"description":"Lightweight modal, toast, spinner, date picker, and context menu library. No dependencies. 42 KB minified (12 KB gzip). Works in all modern browsers.","maintainers":[{"name":"adelalawdi","email":"adel.naji.alawdi@gmail.com"}],"readme":"# Fnon.js v2.0.6 🚀\r\n\r\n**Lightweight modal, toast, spinner, date picker, and context menu library.**  \r\nNo dependencies. 42 KB minified (12 KB gzip). Works in all modern browsers.\r\n\r\n---\r\n**Fnon v2.0** has been completely rebuilt from scratch! Here is what you need to know before updating:\r\n\r\n### 🔄 Upgrading to v2.0\r\n* **Familiar Syntax:** I have done my absolute best to keep the code and API as close to the old version as possible, ensuring a smoother transition for everyone.\r\n* **Check Your Code:** Because this is a major rewrite, please **review your existing implementation** before upgrading to version 2.0 to ensure everything continues to run smoothly in your project.\r\n\r\n### 📌 About the Project & Support\r\n* **Personal Use:** I originally built this library for myself to use across my own projects, but decided to share it openly so others could benefit from it too.\r\n* **Contributions & Support:** Because this is a personal passion project, **I am not accepting feature requests.** However, if you run into any legitimate bugs, feel free to report them and I will do my best to get them fixed when I can!\r\n\r\n---\r\n\r\n> ### [Github](https://github.com/superawdi/Fnon2)\r\n\r\n---\r\n\r\n> ### [Live Demo](https://superawdi.github.io/Fnon2/)\r\n\r\n---\r\n\r\n## Table of Contents\r\n\r\n- [Installation](#installation)\r\n- [Fnon Global API](#fnon-global-api)\r\n- [Modal System](#modal-system)\r\n  - [Alert](#alert)\r\n  - [Ask](#ask)\r\n  - [Dialogue](#dialogue)\r\n  - [Breaking Bar](#breaking-bar)\r\n  - [Modal Options](#modal-options)\r\n  - [Button Definition](#button-definition)\r\n  - [Lifecycle Hooks](#lifecycle-hooks)\r\n  - [Layout System](#layout-system)\r\n  - [Width Variants](#width-variants)\r\n- [Hint / Toast System](#hint--toast-system)\r\n  - [Hint Options](#hint-options)\r\n  - [Hint Themes](#hint-themes)\r\n- [Spinner System](#spinner-system)\r\n  - [Wait (Full-page)](#wait-full-page)\r\n  - [Box (Container)](#box-container)\r\n  - [Spinner Options](#spinner-options)\r\n  - [Available Spinners](#available-spinners)\r\n- [DatePicker](#datepicker)\r\n  - [DatePicker Options](#datepicker-options)\r\n  - [Return Value](#return-value)\r\n  - [CSS Custom Properties](#datepicker-css-properties)\r\n- [Context Menu](#context-menu)\r\n  - [ContextMenuItem](#contextmenuitem)\r\n  - [Keyboard Navigation](#context-menu-keyboard)\r\n- [Dark Mode](#dark-mode)\r\n- [Theme System](#theme-system)\r\n  - [Built-in Themes](#built-in-themes)\r\n  - [Custom Themes](#custom-themes)\r\n  - [Theme Colors](#theme-colors)\r\n- [CSS Custom Properties](#css-custom-properties)\r\n- [CSS Classes Reference](#css-classes-reference)\r\n- [React Integration](#react-integration)\r\n  - [enableReactRendering](#enablereactrendering)\r\n  - [useFnon Hook](#usefnon-hook)\r\n- [Renderer Hook System](#renderer-hook-system)\r\n- [Browser Support](#browser-support)\r\n\r\n---\r\n\r\n### Default theme names: \r\n![Primary](https://placehold.co/80x30/029eff/ffffff?text=Primary)\r\n![Success](https://placehold.co/80x30/39DA8A/ffffff?text=Success)\r\n![Warning](https://placehold.co/80x30/fdd347/000000?text=Warning)\r\n![Info](https://placehold.co/80x30/48dbfb/000000?text=Info)\r\n![Light](https://placehold.co/80x30/f8f9fa/000000?text=Light)\r\n![Danger](https://placehold.co/80x30/ff6b6b/000000?text=Danger)\r\n![Dark](https://placehold.co/80x30/222f3e/ffffff?text=Dark)\r\n\r\n---\r\n\r\n# ✪ Installation\r\n\r\nCopy `fnon.min.js` and `fnon.min.css` to your project.\r\n\r\n```html\r\n<link rel=\"stylesheet\" href=\"path/to/fnon.min.css\">\r\n<script src=\"path/to/fnon.min.js\"></script>\r\n<script>\r\n  // Alert\r\n  Fnon.Alert.Primary('Hello World!', 'Welcome');\r\n\r\n  // Ask (returns Promise)\r\n  const confirmed = await Fnon.Ask.Primary.Async('Delete?', 'Confirm');\r\n\r\n  // Toast\r\n  Fnon.Hint.Success('File saved successfully!');\r\n\r\n  // Spinner\r\n  Fnon.Wait.Spin('Loading...');\r\n  setTimeout(() => Fnon.Wait.Remove(), 2000);\r\n\r\n  // DatePicker\r\n  const date = await Fnon.DatePicker({ initDate: new Date() });\r\n\r\n  // Context Menu\r\n  Fnon.ContextMenu(event, [\r\n    { text: 'Open', onClick: () => open() },\r\n    { text: 'More', items: [\r\n      { text: 'Sub item', onClick: () => sub() }\r\n    ]}\r\n  ]);\r\n\r\n  // Set global defaults\r\n  Fnon.Init({ isDark: true, dir: 'rtl', fontFamily: 'Arial, sans-serif' });\r\n</script>\r\n```\r\n\r\n---\r\n\r\n# Fnon Global API\r\n\r\nThe `Fnon` object is the single entry point. It exposes:\r\n\r\n| Property | Type | Description |\r\n|----------|------|-------------|\r\n| `Alert` | object | Pre-themed alert factories (7 built-in themes + custom) |\r\n| `Ask` | object | Pre-themed ask/confirm factories |\r\n| `Dialogue` | object | Pre-themed dialogue factories |\r\n| `Breaking` | object | Pre-themed breaking bar factories |\r\n| `Hint` | object | Pre-themed hint/toast factories |\r\n| `Wait` | object | Full-page spinner methods |\r\n| `Box` | object | Container-targeted spinner methods |\r\n| `DatePicker(options?)` | function | Date picker modal (alias: `DP`) |\r\n| `DatePicker.setLocale(locale)` | function | Set global date picker locale (language) |\r\n| `ContextMenu(event, items, onClick?)` | function | Context menu (alias: `CM`) |\r\n| `AddLogo(name, html)` | function | Register custom spinner |\r\n| `AddTheme(name, config)` | function | Register custom theme |\r\n| `Init(config)` | function | Set shared defaults across all subsystems |\r\n| `setRenderer(fn)` | function | Register custom content renderer (for React etc.) |\r\n| `registerCleanup(id, fn)` | function | Register modal cleanup callback |\r\n| `registerReactRoot(id, root)` | function | Store React root for unmounting |\r\n\r\n> **TypeScript:** `ModalReturn`, `ModalOptions`, `ButtonDef`, `FnonContent`, `ThemeName`, `DatePickerOptions`, `DatePickerLocale`, `BreakingOptions`, `HintThemeDefinition` are exported for type-safe usage.\r\n\r\n---\r\n\r\n# Modal System\r\n\r\n# ⏹️ Alert\r\n\r\n\r\nA single-OK-button modal.\r\n\r\n```ts\r\nFnon.Alert.ThemeName(\r\n  first: FnonContent | ModalOptions,\r\n  title?: string,\r\n  btnOkText?: string,\r\n  callback?: () => void,\r\n  closedCallback?: () => void\r\n): ModalReturn  // { close, modalEl, id }\r\n\r\nconst { close, modalEl, id } = Fnon.Alert.Primary(\"message\",\"title\",\"ok text\",()=> console.log('closed'))\r\nFnon.Alert.Warning(\"message\",\"title\")\r\nFnon.Alert.Info(\"message\")\r\nFnon.Alert.Success('Operation completed.', 'Success');\r\nFnon.Alert.Danger('Something went wrong.', 'Error', 'Retry', () => retry());\r\n```\r\n\r\n**Async variant** (returns a Promise that resolves when the user clicks OK):\r\n\r\n```ts\r\nFnon.Alert.ThemeName.Async(\r\n  first: FnonContent | ModalOptions,\r\n  title?: string,\r\n  btnOkText?: string\r\n): Promise<void>\r\n\r\nFnon.Alert.Info.Async(\"message\",\"title\").then(()=> console.log('A'))\r\n\r\n// Async\r\nawait Fnon.Alert.Primary.Async('Continue?', 'Confirm');\r\nconsole.log('User clicked OK');\r\n```\r\n\r\n# ⏹️ Ask \r\n\r\nA two-button (OK / Cancel) confirmation modal.\r\n\r\n```ts\r\nFnon.Ask.ThemeName(\r\n  first: FnonContent | ModalOptions,\r\n  title?: string,\r\n  btnOkText?: string,\r\n  btnCancelText?: string,\r\n  callback?: (result: boolean) => void,\r\n  cancelCallback?: (result: boolean) => void,\r\n  closedCallback?: () => void\r\n): ModalReturn  // { close, modalEl, id }\r\n```\r\n\r\n**Async variant** (resolves `true` on OK, `false` on Cancel):\r\n\r\n```ts\r\nFnon.Ask.ThemeName.Async(\r\n  first: FnonContent | ModalOptions,\r\n  title?: string,\r\n  btnOkText?: string,\r\n  btnCancelText?: string\r\n): Promise<boolean>\r\n```\r\n\r\n**Example:**\r\n\r\n```ts\r\nconst { close, modalEl, id } = Fnon.Ask.Warning('Are you sure?', 'Confirm Delete', 'Delete', 'Cancel',\r\n  (ok) => { if (ok) deleteItem(); }\r\n);\r\n\r\n// Async\r\nif (await Fnon.Ask.Primary.Async('Proceed?', 'Confirm')) {\r\n  proceed();\r\n}\r\n```\r\n\r\n### Dialogue\r\n\r\nA fully customizable modal with direct access to the modal element and close function.\r\n\r\n```ts\r\nFnon.Dialogue.ThemeName(\r\n  first: FnonContent | ModalOptions,\r\n  title?: string,\r\n  btnOkText?: string,\r\n  btnCancelText?: string,\r\n  callback?: (close: () => void, html: HTMLElement, data: Record<string, unknown>) => boolean | void,\r\n  cancelCallback?: (close: () => void, html: HTMLElement, data: Record<string, unknown>) => boolean | void,\r\n  closedCallback?: () => void\r\n): { close: () => void; modalEl: HTMLElement; id: string }\r\n```\r\n\r\nReturn `false` from `callback` or `cancelCallback` to **prevent** the modal from closing.\r\n\r\n**Async variant** (resolves `true` on OK, `false` on Cancel, `null` if closed via X):\r\n\r\n```ts\r\nFnon.Dialogue.ThemeName.Async(\r\n  first: FnonContent | ModalOptions,\r\n  title?: string,\r\n  btnOkText?: string,\r\n  btnCancelText?: string\r\n): Promise<boolean | null>\r\n```\r\n\r\n**Direct call** (without theme prefix):\r\n\r\n```ts\r\nFnon.Dialogue(options: ModalOptions): { close: () => void; modalEl: HTMLElement; id: string }\r\n```\r\n\r\n**Example:**\r\n\r\n```ts\r\nFnon.Dialogue.Primary('Choose an option:', 'Custom Dialog',\r\n  'Save', 'Discard',\r\n  (close, el, data) => {\r\n    save();\r\n    close();  // must call close() explicitly\r\n  },\r\n  (close) => {\r\n    close();\r\n  }\r\n);\r\n```\r\n\r\n### Breaking Bar\r\n\r\nA fixed-position breaking news bar anchored to top or bottom.\r\n\r\n```ts\r\nFnon.Breaking.ThemeName(\r\n  message?: FnonContent,\r\n  titleOrOptions?: string | BreakingOptions\r\n): { close: () => void; el: HTMLElement; id: string }\r\n```\r\n\r\n**Direct call:**\r\n\r\n```ts\r\nFnon.Breaking(options: BreakingOptions): { close: () => void; el: HTMLElement; id: string }\r\n```\r\n\r\n**Async variant** (resolves when bar closes):\r\n\r\n```ts\r\nFnon.Breaking.ThemeName.Async(\r\n  message?: FnonContent,\r\n  titleOrOptions?: string | BreakingOptions\r\n): Promise<void>\r\n```\r\n\r\n**BreakingOptions:**\r\n\r\n| Option | Type | Default | Description |\r\n|--------|------|---------|-------------|\r\n| `message` | `FnonContent` | — | Body text |\r\n| `headline` | `string` | `'BREAKING'` | Headline badge text |\r\n| `theme` | `ThemeName` | `'Danger'` | Theme to apply |\r\n| `anchor` | `'top' \\| 'bottom'` | `'top'` | Bar position |\r\n| `buttons` | `ButtonDef[]` | — | Custom action buttons |\r\n| `timeout` | `number` | `5000` | Auto-dismiss (ms), 0 = no dismiss |\r\n| `closable` | `boolean` | `true` | Show close button |\r\n| `onClose` | `() => void` | — | Close callback |\r\n| `appendTarget` | `string \\| HTMLElement` | `'body'` | Target container |\r\n| `fontFamily` | `string` | `'Quicksand', sans-serif` | Font family |\r\n\r\n### Modal Options\r\n\r\nAll options accepted by `createModal()` (the core modal builder used by Alert, Ask, Dialogue):\r\n\r\n| Option | Type | Default | Description |\r\n|--------|------|---------|-------------|\r\n| `message` | `FnonContent` | — | Modal body content |\r\n| `title` | `FnonContent` | — | Title bar content (string, HTML string, or HTMLElement) |\r\n| `buttons` | `ButtonDef[]` | — | Custom button definitions |\r\n| `btnOkText` | `string` | — | Text for OK button |\r\n| `btnCancelText` | `string` | — | Text for Cancel button |\r\n| `btnOkStyle` | `string` | — | CSS class suffix for OK button (e.g. `'Primary'`, `'Danger'`) |\r\n| `btnCancelStyle` | `string` | — | CSS class suffix for Cancel button |\r\n| `showClose` | `boolean` | `true` | Show X close button in title bar |\r\n| `closeButton` | `boolean` | `true` | Legacy alias for `showClose` |\r\n| `showMin` | `boolean` | `false` | Show minimize button |\r\n| `showMaxMin` | `boolean` | `false` | Show maximize/restore buttons |\r\n| `data` | `Record<string, unknown>` | — | Shared mutable data passed to all callbacks |\r\n| `userData` | `Record<string, unknown>` | — | Legacy alias for `data` |\r\n| `autoFocus` | `boolean` | `false` | Auto-focus first focusable element |\r\n| `autoFocusTag` | `string` | `'input:not([disabled])'` | Selector for auto-focus target |\r\n| `autoFocusDelay` | `number` | `0` | Delay before auto-focus (ms) |\r\n| `appendTarget` | `string \\| HTMLElement` | `'body'` | Where to append the modal |\r\n| `layout` | `string` | `'hbf'` | Section order: `h`=title, `b`=body, `f`=footer |\r\n| `width` | `string` | — | Width variant (`'sm'`, `'nl'`, `'lg'`, `'xl'`, `'fl'`) |\r\n| `anchor` | `'top' \\| 'bottom'` | — | Vertical anchoring |\r\n| `fontFamily` | `string` | `'Quicksand', sans-serif` | Font family |\r\n| `animation` | `string` | `'slide-top'` | Entrance animation |\r\n| `icon` | `string` | — | Icon HTML (shown in body) |\r\n| `iconColor` | `string` | — | Icon color |\r\n| `showIcon` | `boolean` | `false` | Show icon section |\r\n| `titleColor` | `string` | — | Title text color |\r\n| `titleBackground` | `string` | — | Title bar background |\r\n| `color` | `string` | `'#2b2b2b'` | Body text color |\r\n| `background` | `string` | `'rgba(0,0,0,0.4)'` | Overlay background |\r\n| `zIndex` | `number` | `4000` | CSS z-index for overlay |\r\n| `btnOkColor` | `string` | — | OK button text color |\r\n| `btnOkBackground` | `string` | — | OK button background |\r\n| `btnOkShadow` | `string` | — | OK button box-shadow |\r\n| `btnOkBorderColor` | `string` | — | OK button border color |\r\n| `btnCancelColor` | `string` | — | Cancel button text color |\r\n| `btnCancelBackground` | `string` | — | Cancel button background |\r\n| `btnCancelShadow` | `string` | — | Cancel button box-shadow |\r\n| `btnCancelBorderColor` | `string` | — | Cancel button border color |\r\n| `delButtons` | `boolean` | `false` | Remove all default buttons |\r\n| `isDark` | `boolean \\| (() => boolean)` | — | Enable dark mode |\r\n| `darkBgColor` | `string` | `'#1a202c'` | Dark mode background color |\r\n| `dir` | `'ltr' \\| 'rtl'` | `'ltr'` | Text direction |\r\n\r\n### Button Definition\r\n\r\n| Option | Type | Default | Description |\r\n|--------|------|---------|-------------|\r\n| `text` | `string` | — | Button label |\r\n| `style` | `string` | `'Primary'` | CSS class: `'Primary'`, `'Danger'`, `'Success'`, etc. |\r\n| `callback` | `(close, html, data) => boolean \\| void` | — | Click handler. Return `false` to prevent modal from closing |\r\n| `color` | `string` | — | Custom text color |\r\n| `background` | `string` | — | Custom background |\r\n| `boxShadow` | `string` | — | Custom box-shadow |\r\n| `shadow` | `string` | — | Alias for `boxShadow` |\r\n| `borderColor` | `string` | — | Custom border color |\r\n| `css` | `string` | — | Additional CSS classes |\r\n\r\n**Custom buttons example:**\r\n\r\n```ts\r\nFnon.Dialogue({\r\n  message: 'What would you like to do?',\r\n  buttons: [\r\n    { text: 'Save', style: 'Success', callback: (close) => { save(); close(); } },\r\n    { text: 'Delete', style: 'Danger', callback: (close) => { deleteItem(); close(); } },\r\n    { text: 'Cancel', style: 'Light' },  // calls close() automatically\r\n  ]\r\n});\r\n```\r\n\r\nWhen `delButtons: true` is set in modal options, only custom buttons are shown (default OK/Cancel are removed).\r\n\r\n### Modal Data (Shared State)\r\n\r\nThe `data` option lets you pass a mutable object into the modal that is accessible across all lifecycle hooks and button callbacks. This is useful for passing state between your code and the modal's event cycle.\r\n\r\n```ts\r\nconst myData = { userId: 42, mode: 'edit' };\r\n\r\nFnon.Ask.Primary('Update this record?', 'Confirm', 'Yes', 'No',\r\n  (result) => {\r\n    // result is true/false (Ask behavior)\r\n  },\r\n  null,\r\n  null,\r\n  { data: myData }  // <-- last argument is ModalOptions\r\n);\r\n\r\n// Or via Dialogue for full access:\r\nFnon.Dialogue({\r\n  message: 'Edit user?',\r\n  data: { userId: 42, timestamp: Date.now() },\r\n  buttons: [\r\n    {\r\n      text: 'Save',\r\n      callback: (close, html, data) => {\r\n        // data = { userId: 42, timestamp: ... }\r\n        console.log('Saving user', data.userId);\r\n        close();\r\n      }\r\n    }\r\n  ],\r\n  onOpen: (el, data) => {\r\n    console.log('Modal opened for user', data.userId);\r\n  },\r\n  onClosed: (data) => {\r\n    console.log('Modal closed for user', data.userId);\r\n  }\r\n});\r\n```\r\n\r\nThe `data` object is shared — mutations made in one callback are visible in all subsequent callbacks.\r\n\r\n### Lifecycle Hooks\r\n\r\n| Hook | Signature | Timing |\r\n|------|-----------|--------|\r\n| `onInit` | `(modalEl, data) => void` | After element creation, before DOM append |\r\n| `onOpen` | `(modalEl, data) => void` | After DOM append and animation start |\r\n| `onClose` | `(data) => void` | When close is triggered |\r\n| `onClosing` | `(modalEl, data) => void` | During close animation |\r\n| `onClosed` | `(data) => void` | After element removed from DOM |\r\n| `beforeShow` | `(modalEl, data) => void` | Before animation starts |\r\n| `afterShow` | `(modalEl, data) => void` | After animation completes |\r\n| `defaultBefore` | `(modalEl, data) => void` | Universal pre-show hook |\r\n| `defaultAfter` | `(modalEl, data) => void` | Universal post-show hook |\r\n| `callback` | varies | Theme-specific (OK button click) |\r\n| `cancelCallback` | varies | Theme-specific (Cancel button click) |\r\n\r\n### Layout System\r\n\r\nControl the order of title bar (`h`), body (`b`), and footer (`f`) via the `layout` string.  \r\nDefault: `'hbf'`. Example: `'fbh'` puts footer first.\r\n\r\n### Width Variants\r\n\r\n| Class | max-width |\r\n|-------|-----------|\r\n| `.fnon-modal-sm` | 360px |\r\n| `.fnon-modal-nl` | 480px (default) |\r\n| `.fnon-modal-lg` | 640px |\r\n| `.fnon-modal-xl` | 800px |\r\n| `.fnon-modal-fl` | Full-width (fixed) |\r\n\r\n---\r\n\r\n## Hint / Toast System\r\n\r\nA notification toast that auto-dismisses. Positioned via named positions.\r\n\r\n```ts\r\nFnon.Hint.ThemeName(\r\n  message: string,\r\n  titleOrOptions?: string | HintOptions\r\n): { close: () => void }\r\n```\r\n\r\n**Async variant:**\r\n\r\n```ts\r\nFnon.Hint.ThemeName.Async(\r\n  message: string,\r\n  titleOrOptions?: string | HintOptions\r\n): Promise<void>\r\n```\r\n\r\n**Built-in positions:**\r\n\r\n`right-top` (default), `right-center`, `right-bottom`, `left-top`, `left-center`, `left-bottom`, `center-top`, `center-center`, `center-bottom`\r\n\r\n**Example:**\r\n\r\n```ts\r\nFnon.Hint.Success('Saved!', 'Success');\r\nFnon.Hint.Danger('Connection lost.', { position: 'center-center', timeOut: 0 });\r\n```\r\n\r\n### Hint Options\r\n\r\n| Option | Type | Default | Description |\r\n|--------|------|---------|-------------|\r\n| `type` | `string` | `'Primary'` | Theme type |\r\n| `title` | `FnonContent` | — | Title content |\r\n| `position` | `string` | `'right-top'` | Screen position |\r\n| `animation` | `string` | `'slide-left'` | Entrance animation |\r\n| `closable` | `boolean` | `true` | Show close button |\r\n| `timeOut` | `number` | `4000` | Auto-dismiss (ms), 0 = no dismiss |\r\n| `appendTo` | `string` | — | Container selector |\r\n| `onClose` | `() => void` | — | Dismiss callback |\r\n| `onclosed` | `() => void` | — | Post-removal callback |\r\n| `fontFamily` | `string` | `'Quicksand', sans-serif` | Font |\r\n| `spacing` | `string` | `'8px'` | Margin between hints |\r\n| `svgSize` | `{ w: number, h: number }` | `{ w: 20, h: 20 }` | Icon dimensions |\r\n| `fontSize` | `string` | `'0.88rem'` | Text font size |\r\n| `width` | `string` | `'360px'` | Hint width |\r\n| `animationDuration` | `string` | `'0.3s'` | Animation speed |\r\n| `progressColor` | `string` | — | Progress bar color |\r\n| `isDark` | `boolean \\| (() => boolean)` | — | Dark mode |\r\n| `darkBgColor` | `string` | — | Dark background |\r\n| `dir` | `'ltr' \\| 'rtl'` | `'ltr'` | Text direction |\r\n\r\n### Hint Themes\r\n\r\nBuilt-in hint themes and their colors:\r\n\r\n| Theme | Title Color | Background | Border |\r\n|-------|------------|------------|--------|\r\n| Primary | `#029eff` | `#ebf8ff` | `#029eff` |\r\n| Success | `#39DA8A` | `#f0fff4` | `#39DA8A` |\r\n| Warning | `#fdd347` | `#fffbe5` | `#fdd347` |\r\n| Danger | `#ff6b6b` | `#fff5f5` | `#ff6b6b` |\r\n| Info | `#48dbfb` | `#e5faff` | `#48dbfb` |\r\n| Light | `#2d3748` | `#f8f9fa` | `#ced4da` |\r\n| Dark | `#fff` | `#222f3e` | `#222f3e` |\r\n\r\nAdd custom hint themes via `Fnon.AddTheme(name, config)` — hint theming is derived automatically from the core theme.\r\n\r\n---\r\n\r\n## Spinner System\r\n\r\n### Wait (Full-page)\r\n\r\nA centered overlay spinner covering the entire viewport. Only one active at a time.\r\n\r\n```ts\r\nFnon.Wait.SpinnerName(\r\n  text?: string,\r\n  options?: SpinnerOptions\r\n): void\r\n```\r\n\r\n**Async variant** (resolves when `Wait.Remove()` is called):\r\n\r\n```ts\r\nFnon.Wait.SpinnerName.Async(\r\n  text?: string,\r\n  options?: SpinnerOptions\r\n): Promise<boolean>\r\n```\r\n\r\n**Control methods:**\r\n\r\n| Method | Description |\r\n|--------|-------------|\r\n| `Fnon.Wait.Remove(delay?: number)` | Remove overlay (with optional delay in ms) |\r\n| `Fnon.Wait.Change(text: string)` | Update the displayed text |\r\n\r\n**Example:**\r\n\r\n```ts\r\nFnon.Wait.Orbit('Connecting...');\r\nawait fetch(url);\r\nFnon.Wait.Remove();\r\n\r\n// Async\r\nconst result = await Fnon.Wait.Spin.Async('Working...');\r\n// result = true when Remove() is called\r\n```\r\n\r\n### Box (Container)\r\n\r\nA spinner overlay inside a specific container element.\r\n\r\n```ts\r\nFnon.Box.SpinnerName(\r\n  selector: string | HTMLElement,\r\n  text?: string,\r\n  options?: BoxOptions\r\n): void\r\n```\r\n\r\n**Async variant:**\r\n\r\n```ts\r\nFnon.Box.SpinnerName.Async(\r\n  selector: string | HTMLElement,\r\n  text?: string,\r\n  options?: BoxOptions\r\n): Promise<boolean>\r\n```\r\n\r\n**Control methods:**\r\n\r\n| Method | Description |\r\n|--------|-------------|\r\n| `Fnon.Box.Remove(selector: string \\| HTMLElement)` | Remove overlay from container |\r\n\r\n**Example:**\r\n\r\n```ts\r\nFnon.Box.Spin('#my-div', 'Loading...');\r\n\r\n// Remove later\r\nFnon.Box.Remove('#my-div');\r\n```\r\n\r\n### Spinner Options\r\n\r\n| Option | Type | Wait Default | Box Default | Description |\r\n|--------|------|-------------|-------------|-------------|\r\n| `text` | `string` | `''` | `''` | Display text below spinner |\r\n| `clickToClose` | `boolean` | `false` | — | Click overlay to close |\r\n| `svgColor` | `string` | `'#029eff'` | `'#029eff'` | Spinner color |\r\n| `appendTarget` | `string` | — | — | Where to append (Wait only) |\r\n| `fontFamily` | `string` | `'Quicksand', sans-serif` | `'Quicksand', sans-serif` | Font |\r\n| `containerSize` | `string` | — | — | Spinner container dimensions |\r\n| `svgSize` | `{ w, h }` | — | — | SVG dimensions (Box only) |\r\n| `isDark` | `boolean \\| (() => boolean)` | — | — | Dark mode |\r\n| `darkBgColor` | `string` | — | — | Dark background |\r\n| `dir` | `'ltr' \\| 'rtl'` | — | — | Text direction |\r\n\r\n### Available Spinners\r\n\r\n| Name | Type | Description |\r\n|------|------|-------------|\r\n| `Orbit` | CSS-only | Orbiting dot with ring animation |\r\n| `Spin` | CSS-only | Rotating ring |\r\n| `Infinity` | SVG | Figure-eight infinite loop path |\r\n| `Ripple` | SVG | Expanding concentric circles |\r\n| `Typing` | SVG | Bouncing typing indicator dots |\r\n\r\n**Custom spinners** via `Fnon.AddLogo(name, htmlString)`:\r\n\r\n```ts\r\nFnon.AddLogo('MyLogo', '<svg>...</svg>');\r\nFnon.Wait.MyLogo('Custom spinner');\r\nFnon.Box.MyLogo('#target', 'Custom');\r\n```\r\n\r\n---\r\n\r\n## DatePicker\r\n\r\nA calendar modal that returns a Promise with the selected date(s).  \r\nSupports **1-month**, **6-month**, and **auto-responsive** layout.  \r\nFully localizable with built-in English, Korean, and custom locale support.\r\n\r\n```ts\r\nFnon.DatePicker(options?: DatePickerOptions): Promise<Date | { start: Date; end: Date } | null>\r\n```\r\n\r\n**Alias:** `Fnon.DP(options?)`\r\n\r\n**Usage:**\r\n\r\n```ts\r\n// Single date\r\nconst date = await Fnon.DatePicker({ initDate: new Date() });\r\nif (date) console.log('Selected:', date);\r\n\r\n// Date range (dateRange: true)\r\nconst range = await Fnon.DatePicker({ dateRange: true });\r\nif (range) console.log('From:', range.start, 'To:', range.end);\r\n\r\n// With time picker\r\nconst dt = await Fnon.DatePicker({ withTime: true });\r\n\r\n// 6-month layout\r\nconst range = await Fnon.DatePicker({ layout: 6, dateRange: true });\r\n\r\n// With custom language\r\nconst arLocale = {\r\n  days: ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'],\r\n  months: ['يناير','فبراير','مارس','أبريل','مايو','يونيو','يوليو','أغسطس','سبتمبر','أكتوبر','نوفمبر','ديسمبر'],\r\n  today: 'اليوم', ok: 'موافق', prevMonth: 'الشهر السابق', nextMonth: 'الشهر التالي',\r\n  digits: '٠١٢٣٤٥٦٧٨٩'\r\n};\r\nconst d = await Fnon.DatePicker({ language: arLocale, dir: 'rtl' });\r\n\r\n// With constraints\r\nconst d = await Fnon.DatePicker({\r\n  minDate: new Date(2024, 0, 1),\r\n  maxDate: new Date(2025, 11, 31)\r\n});\r\n```\r\n\r\nThe Promise resolves `null` if the user closes the modal without selecting (X button / Escape).\r\n\r\n### DatePicker Options\r\n\r\n| Option | Type | Default | Description |\r\n|--------|------|---------|-------------|\r\n| `initDate` | `Date` | `new Date()` | Initial focused date |\r\n| `dateRange` | `boolean` | `false` | Enable date range selection (returns `{ start, end }`) |\r\n| `withTime` | `boolean` | `false` | Show time input (ignored if `dateRange` is `true`) |\r\n| `minDate` | `Date` | — | Earliest selectable date |\r\n| `maxDate` | `Date` | — | Latest selectable date |\r\n| `layout` | `1 \\| 6 \\| 'auto'` | `1` | Number of month columns: `1` (single), `6` (6-month grid), `'auto'` (responsive — 1 on mobile, 6 on 768px+) |\r\n| `language` | `DatePickerLocale` | — | Per-instance locale override (see [DatePickerLocale](#datepickerlocale) below) |\r\n| `title` | `FnonContent` | — | Modal title |\r\n| `isDark` | `boolean \\| (() => boolean)` | — | Dark mode |\r\n| `darkBgColor` | `string` | — | Dark background |\r\n| `dir` | `'ltr' \\| 'rtl'` | `'ltr'` | Text direction |\r\n\r\n### DatePickerLocale\r\n\r\nOverride display text and digit characters for any language. Pass via `language` option or set globally with `Fnon.DatePicker.setLocale()`.\r\n\r\n```ts\r\ninterface DatePickerLocale {\r\n  days?: string[];        // 7 short day names (default: ['Su','Mo','Tu','We','Th','Fr','Sa'])\r\n  daysLong?: string[];    // 7 long day names for tooltips\r\n  months?: string[];      // 12 month names (default: English)\r\n  monthsShort?: string[]; // 12 short month names\r\n  today?: string;         // \"Today\" button text (default: 'Today')\r\n  ok?: string;            // OK button text (default: 'OK')\r\n  prevMonth?: string;     // Tooltip for prev button (default: 'Previous month')\r\n  nextMonth?: string;     // Tooltip for next button (default: 'Next month')\r\n  rangeLabel?: string;    // Template for multi-month header — use {fromMonth}, {toMonth}, {year} placeholders\r\n  digits?: string;        // 10 characters for numeral replacement — index 0 = '0', index 9 = '9'\r\n}\r\n```\r\n\r\n**`digits` example** — Arabic-Indic numerals:\r\n\r\n```ts\r\ndigits: '٠١٢٣٤٥٦٧٨٩'\r\n// 2025 → ٢٠٢٥\r\n```\r\n\r\n**`rangeLabel` example** — custom header format:\r\n\r\n```ts\r\nrangeLabel: '{fromMonth} – {toMonth} {year}'\r\n// \"January – June 2025\"\r\n```\r\n\r\n**Global locale via `Fnon.DatePicker.setLocale()`:**\r\n\r\n```ts\r\nFnon.DatePicker.setLocale({\r\n  months: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'],\r\n  days: ['일','월','화','수','목','금','토']\r\n});\r\n```\r\n\r\n**Global locale via `Fnon.Init()`:**\r\n\r\n```ts\r\nFnon.Init({\r\n  datePickerLocale: {\r\n    months: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'],\r\n    days: ['일','월','화','수','목','금','토']\r\n  }\r\n});\r\n```\r\n\r\n### Return Value\r\n\r\n| Mode | Resolves to | Rejects when |\r\n|------|-------------|--------------|\r\n| Single date | `Date \\| null` | Modal closed without selection |\r\n| Date range | `{ start: Date, end: Date } \\| null` | Modal closed without selection |\r\n\r\n### DatePicker CSS Properties\r\n\r\nAll `--dp-*` variables are scoped to `.fnon-dp-popup` (light and dark variants).\r\n\r\n| Property | Light Default | Dark Default |\r\n|----------|--------------|--------------|\r\n| `--dp-accent` | `#029eff` | `#0284c7` |\r\n| `--dp-bg` | `#fff` | `#0f172a` |\r\n| `--dp-text` | `#2d3748` | `#e2e8f0` |\r\n| `--dp-border` | `#e2e8f0` | `#334155` |\r\n| `--dp-hover` | `#ebf8ff` | `#1e293b` |\r\n| `--dp-other` | `#a0aec0` | `#64748b` |\r\n| `--dp-disabled` | `#e2e8f0` | `#334155` |\r\n| `--dp-selected` | `#029eff` | `#0284c7` |\r\n| `--dp-selected-text` | `#fff` | `#fff` |\r\n| `--dp-range` | `#ebf8ff` | `#1e3a5f` |\r\n| `--dp-popup-bg` | `#fff` | `#1e293b` |\r\n| `--dp-popup-shadow` | `0 8px 25px rgba(0,0,0,.12)` | `0 8px 25px rgba(0,0,0,.4)` |\r\n| `--dp-today-ring` | `#029eff` | `#38bdf8` |\r\n\r\n---\r\n\r\n## Context Menu\r\n\r\nA right-click (or click) context menu with nested submenus, keyboard navigation, and Chrome-like styling.\r\n\r\n```ts\r\nFnon.ContextMenu(\r\n  event: MouseEvent | { x: number; y: number },\r\n  items: ContextMenuItem[],\r\n  globalOnClick?: (item: ContextMenuItem, event: MouseEvent) => void\r\n): { close: () => void }\r\n```\r\n\r\n**Alias:** `Fnon.CM(event, items, onClick?)`\r\n\r\n### ContextMenuItem\r\n\r\n| Option | Type | Default | Description |\r\n|--------|------|---------|-------------|\r\n| `text` | `FnonContent` | — | Display content (string, HTML string, or HTMLElement) |\r\n| `onClick` | `(item, event) => void` | — | Click handler (required if no submenu `items`) |\r\n| `items` | `ContextMenuItem[]` | — | Submenu items (takes priority over `onClick`) |\r\n| `className` | `string` | — | Additional CSS class |\r\n| `disabled` | `boolean` | `false` | Disabled state (dimmed, no click) |\r\n\r\n**`globalOnClick`** fires only for items that do **not** have their own `onClick`.\r\n\r\n**Examples:**\r\n\r\n```ts\r\ndocument.addEventListener('contextmenu', (e) => {\r\n  Fnon.ContextMenu(e, [\r\n    { text: 'Open', onClick: () => open() },\r\n    { text: 'Edit', onClick: () => edit() },\r\n    { text: 'Share', items: [\r\n      { text: 'Email', onClick: () => share('email') },\r\n      { text: 'Copy Link', onClick: () => share('link') },\r\n    ]},\r\n    { text: 'Delete', disabled: true },\r\n  ]);\r\n});\r\n\r\n// Left-click trigger (use an anchor point)\r\nFnon.ContextMenu({ x: 100, y: 200 }, [\r\n  { text: 'Option 1', onClick: () => fn1() },\r\n  { text: 'Option 2', onClick: () => fn2() },\r\n], (item) => console.log('Global click:', item.text));\r\n```\r\n\r\n### Context Menu Keyboard Navigation\r\n\r\n| Key | Action |\r\n|-----|--------|\r\n| `ArrowDown` | Next item |\r\n| `ArrowUp` | Previous item |\r\n| `ArrowRight` | Open submenu |\r\n| `ArrowLeft` | Close submenu |\r\n| `Enter` / `Space` | Select item (or open submenu) |\r\n| `Escape` | Close submenu (or whole menu) |\r\n\r\nClick outside, right-click outside, scroll, and resize all dismiss the menu.\r\n\r\n---\r\n\r\n## Dark Mode\r\n\r\nEvery subsystem supports dark mode via the `isDark` option and `Fnon.Init()`.\r\n\r\n### Enabling dark mode\r\n\r\n```ts\r\n// Globally via Init()\r\nFnon.Init({ isDark: true });\r\n\r\n// Per-instance\r\nFnon.Alert.Primary('Message', 'Title', { isDark: true });\r\nFnon.Hint.Success('Done', { isDark: true });\r\nFnon.DatePicker({ isDark: true });\r\n```\r\n\r\nThe `isDark` can also be a **function** `() => boolean` — evaluated once at creation time:\r\n\r\n```ts\r\nFnon.Init({ isDark: () => localStorage.getItem('theme') === 'dark' });\r\n```\r\n\r\n### Dark behavior by subsystem\r\n\r\n| Subsystem | Dark effect |\r\n|-----------|-------------|\r\n| Modals | Background set to `darkBgColor` (#1a202c), text to `#e2e8f0`, footer border to `#2d3748` |\r\n| Hint | Background set to `darkBgColor`, text color adapted |\r\n| Wait/Box | Overlay gets darker opacity, inner container uses `darkBgColor` |\r\n| DatePicker | All `--dp-*` vars switch to dark palette |\r\n| ContextMenu | `.fnon-cm-dark` class applied with dark colors |\r\n| Breaking | Excluded from dark mode (theme-driven) |\r\n\r\n**Important:** Only wrapper backgrounds are changed — user content inside modals is not force-colored.\r\n\r\n---\r\n\r\n## RTL Support\r\n\r\nEvery subsystem supports right-to-left text direction via the `dir` option. Set it globally via `Fnon.Init()` or per-instance.\r\n\r\n```ts\r\n// Globally via Init()\r\nFnon.Init({ dir: 'rtl' });\r\n\r\n// Per-instance\r\nFnon.Alert.Primary('Message', 'Title', { dir: 'rtl' });\r\nFnon.Hint.Success('Done', { dir: 'rtl' });\r\nFnon.DatePicker({ dir: 'rtl' });\r\n```\r\n\r\n### What gets flipped\r\n\r\n| Subsystem | RTL effect |\r\n|-----------|------------|\r\n| Modals | Controls (min/max/close) order reversed, drag uses `right` instead of `left` |\r\n| Hints | Positions `right-*` ↔ `left-*`, border accent on right side, progress bar anchors right, slide animations reverse |\r\n| ContextMenu | Submenus open to the left, arrow icons point left, keyboard arrows swap (`ArrowRight` closes, `ArrowLeft` opens) |\r\n| DatePicker | Navigation chevrons swap direction |\r\n\r\n`Fnon.Init({ dir: 'rtl' })` sets `document.documentElement.dir = \"rtl\"`, which cascades to all components.\r\n\r\n---\r\n\r\n## Theme System\r\n\r\nSeven built-in themes, each with defined colors for title bar, buttons, and backgrounds.\r\n\r\n### Built-in Themes\r\n\r\n| Theme | titleBackground | titleColor | btnOkBackground | btnOkColor | backgroundColor |\r\n|-------|---------------|-----------|----------------|-----------|----------------|\r\n| Primary | `#029eff` | `#fff` | `#029eff` | `#fff` | `#fff` |\r\n| Success | `#39DA8A` | `#fff` | `#39DA8A` | `#fff` | `#fff` |\r\n| Warning | `#fdd347` | `#2d3748` | `#fdd347` | `#2d3748` | `#fff` |\r\n| Danger | `#ff6b6b` | `#fff` | `#ff6b6b` | `#fff` | `#fff` |\r\n| Info | `#48dbfb` | `#2d3748` | `#48dbfb` | `#2d3748` | `#fff` |\r\n| Light | `#f8f9fa` | `#2d3748` | `#f8f9fa` | `#2d3748` | `#fff` |\r\n| Dark | `#222f3e` | `#fff` | `#222f3e` | `#fff` | `#fff` |\r\n\r\n### Custom Themes\r\n\r\n```ts\r\nFnon.AddTheme('MyTheme', {\r\n  titleBackground: '#7c3aed',\r\n  titleColor: '#fff',\r\n  btnOkBackground: '#7c3aed',\r\n  btnOkColor: '#fff',\r\n  btnOkBorderColor: '#7c3aed',\r\n  backgroundColor: '#faf5ff',\r\n});\r\n\r\n// Then use it:\r\nFnon.Alert.MyTheme('Custom themed modal!');\r\nFnon.Ask.MyTheme.Async('Confirm?');\r\n```\r\n\r\nThis automatically registers the theme for: Alert, Ask, Dialogue, Breaking, and Hint.\r\n\r\n### Theme Colors\r\n\r\n| Option | Type | Description |\r\n|--------|------|-------------|\r\n| `titleBackground` | `string` | Title bar background color |\r\n| `titleColor` | `string` | Title bar text color |\r\n| `btnOkBackground` | `string` | OK button background color |\r\n| `btnOkColor` | `string` | OK button text color |\r\n| `btnOkBorderColor` | `string` | OK button border color |\r\n| `backgroundColor` | `string` | Modal body background color |\r\n| `[key: string]` | `string` | Any additional custom values |\r\n\r\n---\r\n\r\n## CSS Custom Properties\r\n\r\n### Root-level\r\n\r\nSet these on `:root` to customize globally:\r\n\r\n| Property | Default | Description |\r\n|----------|---------|-------------|\r\n| `--fnon-font` | `'Quicksand', sans-serif` | Base font |\r\n| `--fnon-z-overlay` | `4000` | Overlay z-index |\r\n| `--fnon-z-modal` | `4001` | Modal z-index |\r\n| `--fnon-z-hint` | `5000` | Hint z-index |\r\n| `--fnon-z-wait` | `6000` | Wait overlay z-index |\r\n| `--fnon-radius` | `10px` | Border radius |\r\n| `--fnon-transition` | `0.25s ease` | Default transition |\r\n\r\n### Theme-injected (per instance via CSS vars on modal element)\r\n\r\n| Property | Source |\r\n|----------|--------|\r\n| `--fnon-title-background` | `theme.titleBackground` |\r\n| `--fnon-title-color` | `theme.titleColor` |\r\n| `--fnon-btn-ok-background` | `theme.btnOkBackground` |\r\n| `--fnon-btn-ok-color` | `theme.btnOkColor` |\r\n| `--fnon-btn-ok-border-color` | `theme.btnOkBorderColor` |\r\n| `--fnon-background-color` | `theme.backgroundColor` |\r\n| `--fnon-body-color` | `opts.color` override |\r\n| `--fnon-bg` | Dark mode `darkBgColor` |\r\n\r\n### Spinner\r\n\r\n| Property | Description |\r\n|----------|-------------|\r\n| `--fnon-sp-color` | Spinner color |\r\n| `--fnon-sp-size` | Spinner container size (default 48px) |\r\n\r\n### Hint\r\n\r\n| Property | Description |\r\n|----------|-------------|\r\n| `--fnon-icon-w` | Hint icon width |\r\n| `--fnon-icon-h` | Hint icon height |\r\n| `--display-dur` | Progress bar animation duration |\r\n\r\n### Box\r\n\r\n| Property | Description |\r\n|----------|-------------|\r\n| `--fnon-box-svg-w` | Box SVG width |\r\n| `--fnon-box-svg-h` | Box SVG height |\r\n\r\n---\r\n\r\n## CSS Classes Reference\r\n\r\n### Overlay & Modal\r\n\r\n| Class | Purpose |\r\n|-------|---------|\r\n| `.fnon-overlay` | Modal backdrop |\r\n| `.fnon-overlay-hidden` | Hidden overlay (minimized) |\r\n| `.fnon-modal` | Modal dialog |\r\n| `.fnon-modal.fnon-active` | Visible modal |\r\n| `.fnon-modal.fnon-maximized` | Fullscreen |\r\n| `.fnon-modal.fnon-minimized` | Hidden (minimized) |\r\n| `.fnon-modal-title` | Title bar |\r\n| `.fnon-modal-title-text` | Title text span |\r\n| `.fnon-modal-controls` | Window control buttons |\r\n| `.fnon-modal-body` | Body content |\r\n| `.fnon-modal-icon` | Icon div |\r\n| `.fnon-modal-footer` | Footer (buttons) |\r\n| `.fnon-dragging` | Applied during drag |\r\n| `.fnon-theme-{name}` | Theme class |\r\n| `.fnon-task-bar` | Minimized modal task bar |\r\n| `.fnon-task-bar-btn` | Task bar restore button |\r\n\r\n### Buttons\r\n\r\n| Class | Purpose |\r\n|-------|---------|\r\n| `.fnon-btn` | Base button |\r\n| `.fnon-btn-light` | Light theme |\r\n| `.fnon-btn-danger` | Danger theme |\r\n| `.fnon-btn-success` | Success theme |\r\n| `.fnon-btn-warning` | Warning theme |\r\n| `.fnon-btn-info` | Info theme |\r\n| `.fnon-btn-dark` | Dark theme |\r\n\r\n### Breaking Bar\r\n\r\n| Class | Purpose |\r\n|-------|---------|\r\n| `.fnon-breaking` | Breaking bar |\r\n| `.fnon-breaking-top` | Anchored to top |\r\n| `.fnon-breaking-bottom` | Anchored to bottom |\r\n| `.fnon-breaking-active` | Visible state |\r\n| `.fnon-breaking-inner` | Flex container |\r\n| `.fnon-breaking-headline` | Headline badge |\r\n| `.fnon-breaking-body` | Message body |\r\n| `.fnon-breaking-buttons` | Buttons container |\r\n| `.fnon-breaking-close` | Close button |\r\n\r\n### Hint / Toast\r\n\r\n| Class | Purpose |\r\n|-------|---------|\r\n| `.fnon-hint-container` | Positioned container |\r\n| `.fnon-hint-container.{position}` | e.g. `right-top` |\r\n| `.fnon-hint` | Hint element |\r\n| `.fnon-hint-active` | Visible state |\r\n| `.fnon-hint-icon` | Icon container |\r\n| `.fnon-hint-content` | Text content |\r\n| `.fnon-hint-title` | Title text |\r\n| `.fnon-hint-message` | Message text |\r\n| `.fnon-hint-close` | Close button |\r\n| `.fnon-hint-progress` | Progress bar |\r\n\r\n### Wait / Box\r\n\r\n| Class | Purpose |\r\n|-------|---------|\r\n| `.fnon-wait-overlay` | Full-page overlay |\r\n| `.fnon-wait-active` | Visible overlay |\r\n| `.fnon-wait-box` | Spinner container |\r\n| `.fnon-wait-text` | Text below spinner |\r\n| `.fnon-box-overlay` | Container overlay |\r\n| `.fnon-box-inner` | Box spinner container |\r\n| `.fnon-box-label` | Box text label |\r\n\r\n### CSS-only Spinners\r\n\r\n| Class | Purpose |\r\n|-------|---------|\r\n| `.fnon-sp-orbit` | Orbit spinner |\r\n| `.fnon-sp-orbit-dot` | Orbit dot |\r\n| `.fnon-sp-spin` | Spin spinner |\r\n| `.fnon-sp-spin-ring` | Spin ring |\r\n\r\n### DatePicker\r\n\r\n| Class | Purpose |\r\n|-------|---------|\r\n| `.fnon-dp` | DatePicker container |\r\n| `.fnon-dp-dark` | Dark mode |\r\n| `.fnon-dp-layout-auto` | Responsive layout mode (media query) |\r\n| `.fnon-dp-months` | Multi-month grid container (3 columns) |\r\n| `.fnon-dp-month` | Individual month card in multi-layout |\r\n| `.fnon-dp-month-name` | Month card title |\r\n| `.fnon-dp-header` | Header row |\r\n| `.fnon-dp-nav` | Nav button |\r\n| `.fnon-dp-nav-disabled` | Disabled nav |\r\n| `.fnon-dp-label` | Month/year label |\r\n| `.fnon-dp-time` | Time row |\r\n| `.fnon-dp-time-input` | Time input |\r\n| `.fnon-dp-grid` | Day grid |\r\n| `.fnon-dp-dow` | Day-of-week header |\r\n| `.fnon-dp-day` | Day cell |\r\n| `.fnon-dp-other` | Other month |\r\n| `.fnon-dp-today` | Today |\r\n| `.fnon-dp-disabled` | Disabled |\r\n| `.fnon-dp-selected` | Selected |\r\n| `.fnon-dp-range` | Range |\r\n| `.fnon-dp-range-start` | Range start |\r\n| `.fnon-dp-range-end` | Range end |\r\n| `.fnon-dp-range-preview` | Hover preview |\r\n| `.fnon-dp-btn-group` | Action button group |\r\n| `.fnon-dp-btn-ok` | OK button |\r\n| `.fnon-dp-btn-cancel` | Cancel button |\r\n| `.fnon-dp-popup` | Year/month popup |\r\n| `.fnon-dp-popup-nav` | Popup nav bar |\r\n| `.fnon-dp-popup-nav-btn` | Popup nav button |\r\n| `.fnon-dp-popup-nav-label` | Popup nav label |\r\n| `.fnon-dp-popup-row` | Popup grid row |\r\n| `.fnon-dp-popup-cell` | Popup cell |\r\n| `.fnon-dp-popup-active` | Active cell |\r\n\r\n### Context Menu\r\n\r\n| Class | Purpose |\r\n|-------|---------|\r\n| `.fnon-cm` | Context menu |\r\n| `.fnon-cm-dark` | Dark mode |\r\n| `.fnon-cm-item` | Menu item |\r\n| `.fnon-cm-item-disabled` | Disabled |\r\n| `.fnon-cm-item-parent` | Has submenu |\r\n| `.fnon-cm-item-text` | Text span |\r\n| `.fnon-cm-arrow` | Submenu arrow |\r\n| `.fnon-cm-submenu` | Submenu |\r\n\r\n### Utility\r\n\r\n| Class | Purpose |\r\n|-------|---------|\r\n| `.fnon-hidden` | `display: none !important` |\r\n\r\n---\r\n\r\n## React Integration\r\n\r\nFnon provides a React adapter for rendering React components inside modals and a hook for portal-aware modal factories.\r\n\r\n### enableReactRendering\r\n\r\n```ts\r\nimport { enableReactRendering } from 'fnon';\r\n// or via CDN: Fnon.setRenderer(...)\r\n\r\nenableReactRendering(ReactDOM);\r\n// ReactDOM = { createRoot: ReactDOM.createRoot }\r\n```\r\n\r\nAfter calling this, any `FnonContent` that is a React VNode (object with `$$typeof` or `type`) will be rendered via `createRoot()` instead of `innerHTML`. The root is automatically unmounted when the modal closes.\r\n\r\n### useFnon Hook\r\n\r\n```ts\r\nimport { useFnon } from 'fnon';\r\n\r\nfunction App() {\r\n  const { Alert, Ask, Dialogue } = useFnon({ mountRoot: '#fnon-root' });\r\n\r\n  return (\r\n    <div id=\"fnon-root\">\r\n      <button onClick={() => Alert.Primary('Hello from React!')}>\r\n        Show Alert\r\n      </button>\r\n    </div>\r\n  );\r\n}\r\n```\r\n\r\nReturns modal factories with `appendTarget` automatically set to the portal root, so modals render into a controlled container rather than `document.body`.\r\n\r\n---\r\n\r\n## Renderer Hook System\r\n\r\nLow-level hooks for custom content rendering (used internally by the React adapter).\r\n\r\n```ts\r\nFnon.setRenderer((content, container, modal) => {\r\n  // Return true to indicate you handled rendering\r\n  return false; // fall back to innerHTML\r\n});\r\n\r\nFnon.registerCleanup(modalId, () => {\r\n  // Cleanup logic when modal closes\r\n});\r\n\r\nFnon.registerReactRoot(modalId, root);\r\n```\r\n\r\n| Function | Description |\r\n|----------|-------------|\r\n| `setRenderer(fn)` | Register renderer (or `null` to clear) |\r\n| `registerCleanup(id, fn)` | Register per-modal cleanup |\r\n| `registerReactRoot(id, root)` | Store React root for unmounting |\r\n\r\n**`RendererFn` signature:**\r\n\r\n```ts\r\n(content: FnonContent, container: HTMLElement, modal: Record<string, unknown>) => boolean\r\n```\r\n\r\n## Browser Support\r\n\r\nModern browsers (Chrome, Firefox, Safari, Edge). Requires ES2015+.\r\n\r\n---\r\n\r\n## License\r\n\r\nMIT\r\n","readmeFilename":"README.md"}