dars-framework 1.9.6__tar.gz → 1.9.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. {dars_framework-1.9.6 → dars_framework-1.9.7}/MANIFEST.in +1 -0
  2. {dars_framework-1.9.6/dars_framework.egg-info → dars_framework-1.9.7}/PKG-INFO +1 -1
  3. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/exporters/web/html_css_js.py +3 -3
  4. dars_framework-1.9.7/dars/exporters/web/resources/anim.js +317 -0
  5. dars_framework-1.9.7/dars/exporters/web/resources/dap.js +417 -0
  6. dars_framework-1.9.7/dars/exporters/web/resources/dars.min.js +1110 -0
  7. dars_framework-1.9.7/dars/exporters/web/resources/dompurify.js +2633 -0
  8. dars_framework-1.9.7/dars/exporters/web/resources/router.js +821 -0
  9. dars_framework-1.9.7/dars/exporters/web/resources/ssr.js +246 -0
  10. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/version.py +2 -2
  11. {dars_framework-1.9.6 → dars_framework-1.9.7/dars_framework.egg-info}/PKG-INFO +1 -1
  12. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars_framework.egg-info/SOURCES.txt +6 -0
  13. {dars_framework-1.9.6 → dars_framework-1.9.7}/pyproject.toml +1 -1
  14. {dars_framework-1.9.6 → dars_framework-1.9.7}/Dars-logo.png +0 -0
  15. {dars_framework-1.9.6 → dars_framework-1.9.7}/LICENSE +0 -0
  16. {dars_framework-1.9.6 → dars_framework-1.9.7}/README.md +0 -0
  17. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/__init__.py +0 -0
  18. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/actionProtocol.py +0 -0
  19. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/all.py +0 -0
  20. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/backend/__init__.py +0 -0
  21. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/backend/components.py +0 -0
  22. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/backend/data.py +0 -0
  23. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/backend/http.py +0 -0
  24. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/backend/json_utils.py +0 -0
  25. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/backend/route_loader.py +0 -0
  26. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/backend/ssr.py +0 -0
  27. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/__init__.py +0 -0
  28. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/doctor/__init__.py +0 -0
  29. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/doctor/detect.py +0 -0
  30. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/doctor/doctor.py +0 -0
  31. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/doctor/installers.py +0 -0
  32. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/doctor/persist.py +0 -0
  33. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/doctor/preflight.py +0 -0
  34. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/doctor/ui.py +0 -0
  35. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/dpm.py +0 -0
  36. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/generate.py +0 -0
  37. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/hot_reload.py +0 -0
  38. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/main.py +0 -0
  39. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/preview.py +0 -0
  40. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/prompts.py +0 -0
  41. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/cli/translations.py +0 -0
  42. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/__init__.py +0 -0
  43. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/advanced/__init__.py +0 -0
  44. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/advanced/accordion.py +0 -0
  45. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/advanced/card.py +0 -0
  46. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/advanced/file_upload.py +0 -0
  47. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/advanced/head.py +0 -0
  48. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/advanced/modal.py +0 -0
  49. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/advanced/navbar.py +0 -0
  50. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/advanced/outlet.py +0 -0
  51. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/advanced/table.py +0 -0
  52. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/advanced/tabs.py +0 -0
  53. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/__init__.py +0 -0
  54. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/audio.py +0 -0
  55. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/button.py +0 -0
  56. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/checkbox.py +0 -0
  57. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/container.py +0 -0
  58. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/datepicker.py +0 -0
  59. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/image.py +0 -0
  60. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/input.py +0 -0
  61. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/link.py +0 -0
  62. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/markdown.py +0 -0
  63. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/page.py +0 -0
  64. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/progressbar.py +0 -0
  65. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/radiobutton.py +0 -0
  66. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/section.py +0 -0
  67. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/select.py +0 -0
  68. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/slider.py +0 -0
  69. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/spinner.py +0 -0
  70. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/text.py +0 -0
  71. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/textarea.py +0 -0
  72. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/tooltip.py +0 -0
  73. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/basic/video.py +0 -0
  74. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/layout/__init__.py +0 -0
  75. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/layout/anchor.py +0 -0
  76. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/layout/flex.py +0 -0
  77. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/layout/grid.py +0 -0
  78. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/visualization/__init__.py +0 -0
  79. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/visualization/chart.py +0 -0
  80. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/components/visualization/table.py +0 -0
  81. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/config.py +0 -0
  82. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/core/__init__.py +0 -0
  83. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/core/app.py +0 -0
  84. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/core/component.py +0 -0
  85. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/core/events.py +0 -0
  86. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/core/js_bridge.py +0 -0
  87. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/core/properties.py +0 -0
  88. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/core/route_types.py +0 -0
  89. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/core/routing.py +0 -0
  90. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/core/state.py +0 -0
  91. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/core/state_v2.py +0 -0
  92. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/core/utilities.py +0 -0
  93. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/dars_tests/apps_test/health_check.py +0 -0
  94. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/dars_tests/run_tests.py +0 -0
  95. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/dars_tests/tests/test_advanced_components.py +0 -0
  96. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/dars_tests/tests/test_basic_components.py +0 -0
  97. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/dars_tests/tests/test_core_and_cli.py +0 -0
  98. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/dars_tests/tests/test_layout_components.py +0 -0
  99. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/dars_tests/tests/test_version_check.py +0 -0
  100. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/desktop/__init__.py +0 -0
  101. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/desktop/api.py +0 -0
  102. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/desktop/js_generator.py +0 -0
  103. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/docs/__init__.py +0 -0
  104. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/docs/index.md +0 -0
  105. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/env.py +0 -0
  106. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/exporters/__init__.py +0 -0
  107. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/exporters/base.py +0 -0
  108. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/exporters/desktop/electron.py +0 -0
  109. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/exporters/web/__init__.py +0 -0
  110. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/exporters/web/vdom.py +0 -0
  111. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/hooks/__init__.py +0 -0
  112. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/hooks/form_helpers.py +0 -0
  113. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/hooks/set_vref.py +0 -0
  114. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/hooks/update_vref.py +0 -0
  115. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/hooks/use_dynamic.py +0 -0
  116. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/hooks/use_value.py +0 -0
  117. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/hooks/use_vref.py +0 -0
  118. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/hooks/use_watch.py +0 -0
  119. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/hooks/value_helpers.py +0 -0
  120. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/scripts/__init__.py +0 -0
  121. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/scripts/animations.py +0 -0
  122. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/scripts/dscript.py +0 -0
  123. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/scripts/keycode.py +0 -0
  124. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/scripts/script.py +0 -0
  125. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/scripts/utils_ds.py +0 -0
  126. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/security.py +0 -0
  127. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/__init__.py +0 -0
  128. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/desktop/icon.png +0 -0
  129. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/desktop/template/backend/icons/icon.png +0 -0
  130. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/desktop/template/backend/main.js +0 -0
  131. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/desktop/template/backend/package.json +0 -0
  132. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/desktop/template/backend/preload.js +0 -0
  133. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/desktop/template/dars.config.json +0 -0
  134. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/desktop/template/icons/icon.png +0 -0
  135. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/desktop/template/main.py +0 -0
  136. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/desktop/template/public/electron-icon.png +0 -0
  137. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/desktop/template/public/icon.png +0 -0
  138. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/README.md +0 -0
  139. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/CustomComp/main.py +0 -0
  140. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/Modal_Demo/advanced_modal_demo.py +0 -0
  141. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/StateV2/README.md +0 -0
  142. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/StateV2/animation_component.py +0 -0
  143. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/StateV2/counter_component.py +0 -0
  144. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/StateV2/hero_component.py +0 -0
  145. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/StateV2/main.py +0 -0
  146. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/StateV2/styles.css +0 -0
  147. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/StateV2/timer_component.py +0 -0
  148. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/VariousComponents/all_components_demo.py +0 -0
  149. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/__init__.py +0 -0
  150. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/dState/state_mods_demo.py +0 -0
  151. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/hooks/useDynamic.py +0 -0
  152. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/hooks/useValue.py +0 -0
  153. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/advanced/hooks/useWatch.py +0 -0
  154. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/basic/HelloWorld/hello_world.py +0 -0
  155. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/basic/Layouts/flex_layout_responsive.py +0 -0
  156. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/basic/Layouts/grid_layout_responsive.py +0 -0
  157. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/basic/Layouts/layout_multipage_demo.py +0 -0
  158. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/basic/PWA/icon-192x192.png +0 -0
  159. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/basic/PWA/icon-512x512.png +0 -0
  160. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/basic/PWA/pwa_custom_icons.py +0 -0
  161. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/basic/__init__.py +0 -0
  162. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/markdown/MarkdownTemplate/README.md +0 -0
  163. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/markdown/MarkdownTemplate/markdown_template.py +0 -0
  164. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/markdown/MarkdownTemplate/other_docs.md +0 -0
  165. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars/templates/examples/markdown/__init__.py +0 -0
  166. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars_framework.egg-info/dependency_links.txt +0 -0
  167. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars_framework.egg-info/entry_points.txt +0 -0
  168. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars_framework.egg-info/requires.txt +0 -0
  169. {dars_framework-1.9.6 → dars_framework-1.9.7}/dars_framework.egg-info/top_level.txt +0 -0
  170. {dars_framework-1.9.6 → dars_framework-1.9.7}/setup.cfg +0 -0
@@ -5,5 +5,6 @@ recursive-include dars/templates *
5
5
  recursive-include dars/docs *
6
6
  recursive-include dars *.json
7
7
  recursive-include dars *.md
8
+ recursive-include dars/exporters/web/resources *
8
9
  exclude LandingPage
9
10
  exclude tst
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dars-framework
3
- Version: 1.9.6
3
+ Version: 1.9.7
4
4
  Summary: Dars is a Full-Stack multiplatform Python UI framework for building modern, interactive web and desktop apps with Python code. Seamlessly integrated with FastAPI, it allows you to build complete applications with Server-Side Rendering (SSR) and reactive SPA capabilities also classic multipage html and desktop apps in a single codebase.
5
5
  Author-email: ztamdev <ztadevs@gmail.com>
6
6
  Maintainer-email: ztamdev <ztadevs@gmail.com>
@@ -1089,7 +1089,7 @@ self.addEventListener('fetch', event => {
1089
1089
  " arr = JSON.parse(json||'[]');\n"
1090
1090
  " } catch(_) { arr = []; }\n"
1091
1091
  " try {\n"
1092
- " const m = await import('/lib/dars.min.js');\n"
1092
+ " const m = await import('./lib/dars.min.js');\n"
1093
1093
  " const reg = m.registerState || (m.default && m.default.registerState);\n"
1094
1094
  " if (typeof reg === 'function') { arr.forEach(s => reg(s.name, s)); }\n"
1095
1095
  " } catch (e) {\n"
@@ -1110,7 +1110,7 @@ self.addEventListener('fetch', event => {
1110
1110
  " if (!el) { window.__DARS_STATE_BOOTSTRAPPED__ = true; return; }\n"
1111
1111
  " const arr = JSON.parse(el.textContent||'[]');\n"
1112
1112
  " try {\n"
1113
- " const m = await import('/lib/dars.min.js');\n"
1113
+ " const m = await import('./lib/dars.min.js');\n"
1114
1114
  " const reg = m.registerState || (m.default && m.default.registerState);\n"
1115
1115
  " if (typeof reg === 'function') { arr.forEach(s => reg(s.name, s)); }\n"
1116
1116
  " } catch (e) {\n"
@@ -3497,7 +3497,7 @@ audio.dars-audio {
3497
3497
  lines.append(' // Ensure runtime loaded if used')
3498
3498
  lines.append(' if (!window.Dars) {')
3499
3499
  lines.append(" try {")
3500
- lines.append(" const m = await import('/lib/dars.min.js');")
3500
+ lines.append(" const m = await import('./lib/dars.min.js');")
3501
3501
  lines.append(" window.Dars = m.default || m;")
3502
3502
  lines.append(" } catch (e) { }")
3503
3503
  lines.append(' }')
@@ -0,0 +1,317 @@
1
+ import { $ } from "./dars.min.js";
2
+
3
+ const __observers = new Map();
4
+ const __scrollHandlers = new Map();
5
+ let __scrollRAF = null;
6
+
7
+ /**
8
+ * DarsAnimation - Complete animation engine
9
+ * Provides: viewport triggers, keyframe animations, stagger, timeline, scroll-progress
10
+ */
11
+ export const DarsAnimation = {
12
+ /**
13
+ * Internal: run fn when DOM is ready. If already ready, run immediately.
14
+ */
15
+ _whenReady(fn) {
16
+ if (document.readyState === "loading") {
17
+ document.addEventListener("DOMContentLoaded", fn, { once: true });
18
+ } else {
19
+ fn();
20
+ }
21
+ },
22
+
23
+ /**
24
+ * Helper: Apply styles without triggering CSS transitions.
25
+ */
26
+ _setStylesWithoutTransition(el, styles) {
27
+ if (!el || !styles) return;
28
+ try {
29
+ const oldTrans = el.style.getPropertyValue('transition');
30
+ const oldPri = el.style.getPropertyPriority('transition');
31
+ el.style.setProperty('transition', 'none', 'important');
32
+
33
+ for (const k in styles) {
34
+ if (k !== 'offset' && k !== 'easing') {
35
+ el.style[k] = styles[k];
36
+ }
37
+ }
38
+
39
+ void el.offsetHeight; // Force reflow
40
+
41
+ if (oldTrans) el.style.setProperty('transition', oldTrans, oldPri);
42
+ else el.style.removeProperty('transition');
43
+ } catch(e) {}
44
+ },
45
+
46
+ /**
47
+ * Observe an element for viewport entry/exit via IntersectionObserver.
48
+ */
49
+ observe(id, opts = {}) {
50
+ const _run = () => {
51
+ try {
52
+ const el = $(id);
53
+ if (!el) return;
54
+ if (__observers.has(id)) {
55
+ __observers.get(id).disconnect();
56
+ __observers.delete(id);
57
+ }
58
+ const threshold = opts.threshold ?? 0.1;
59
+ const rootMargin = opts.rootMargin || "0px";
60
+ const once = opts.once !== false;
61
+ const observer = new IntersectionObserver((entries) => {
62
+ for (const entry of entries) {
63
+ if (entry.isIntersecting) {
64
+ if (opts.enterClass) el.classList.add(opts.enterClass);
65
+ if (opts.leaveClass) el.classList.remove(opts.leaveClass);
66
+ if (typeof opts.onEnter === "function") opts.onEnter(el, entry);
67
+ if (once) { observer.unobserve(el); __observers.delete(id); }
68
+ } else {
69
+ if (opts.leaveClass) el.classList.add(opts.leaveClass);
70
+ if (opts.enterClass) el.classList.remove(opts.enterClass);
71
+ if (typeof opts.onLeave === "function") opts.onLeave(el, entry);
72
+ }
73
+ }
74
+ }, { threshold, rootMargin });
75
+ observer.observe(el);
76
+ __observers.set(id, observer);
77
+ } catch(e) { console.error("[DarsAnimation:observe]", e); }
78
+ };
79
+ this._whenReady(_run);
80
+ },
81
+
82
+ /**
83
+ * Unobserve an element.
84
+ */
85
+ unobserve(id) {
86
+ if (__observers.has(id)) {
87
+ __observers.get(id).disconnect();
88
+ __observers.delete(id);
89
+ }
90
+ },
91
+
92
+ /**
93
+ * Run a Web Animations API animation on an element.
94
+ * @param {string} id - Element ID
95
+ * @param {Array} keyframes - Keyframe array
96
+ * @param {object} options - { duration, easing, fill, iterations, delay, direction }
97
+ * @returns {Promise} resolves when animation finishes
98
+ */
99
+ animate(id, keyframes, options = {}) {
100
+ return new Promise((resolve, reject) => {
101
+ try {
102
+ const el = $(id);
103
+ if (!el) {
104
+ resolve();
105
+ return;
106
+ }
107
+ const opts = {
108
+ duration: options.duration ?? 300,
109
+ easing: options.easing || "ease",
110
+ fill: options.fill || "forwards",
111
+ iterations: options.iterations ?? 1,
112
+ delay: options.delay ?? 0,
113
+ direction: options.direction || "normal",
114
+ };
115
+ if (options.iterations === "infinite") opts.iterations = Infinity;
116
+ const anim = el.animate(keyframes, opts);
117
+
118
+ anim.onfinish = () => {
119
+ try {
120
+ if (opts.fill === "forwards" && keyframes.length > 0) {
121
+ const finalFrame = keyframes[keyframes.length - 1];
122
+ // Apply final frame inline safely
123
+ DarsAnimation._setStylesWithoutTransition(el, finalFrame);
124
+ // Cancel WAAPI animation to release its priority lock over CSS !important
125
+ anim.cancel();
126
+ }
127
+ } catch (_) {}
128
+ resolve(anim);
129
+ };
130
+
131
+ anim.oncancel = () => resolve(anim);
132
+ } catch (e) {
133
+ console.error("[DarsAnimation:animate]", e);
134
+ resolve();
135
+ }
136
+ });
137
+ },
138
+
139
+ /**
140
+ * Animate when element enters viewport.
141
+ * @param {string} id - Element ID
142
+ * @param {Array} keyframes - Keyframe array
143
+ * @param {object} animOpts - Animation options
144
+ * @param {object} viewOpts - Viewport observer options
145
+ */
146
+ animateOnView(id, keyframes, animOpts = {}, viewOpts = {}) {
147
+ const self = this;
148
+ this._whenReady(() => {
149
+ // Set initial hidden state
150
+ try {
151
+ const el = $(id);
152
+ if (el && keyframes.length > 0) {
153
+ self._setStylesWithoutTransition(el, keyframes[0]);
154
+ }
155
+ } catch (_) {}
156
+ self.observe(id, {
157
+ threshold: viewOpts.threshold ?? 0.1,
158
+ rootMargin: viewOpts.rootMargin || "0px",
159
+ once: viewOpts.once !== false,
160
+ onEnter(el) {
161
+ self.animate(id, keyframes, animOpts);
162
+ },
163
+ onLeave: viewOpts.onLeave || null,
164
+ });
165
+ });
166
+ },
167
+
168
+ /**
169
+ * Stagger animations across multiple elements.
170
+ * @param {Array<string>} ids - Array of element IDs
171
+ * @param {Array} keyframes - Shared keyframes
172
+ * @param {object} options - Animation options + staggerDelay (ms between each)
173
+ * @returns {Promise}
174
+ */
175
+ stagger(ids, keyframes, options = {}) {
176
+ const staggerDelay = options.staggerDelay ?? 100;
177
+ const promises = ids.map((id, i) => {
178
+ const opts = Object.assign({}, options, {
179
+ delay: (options.delay ?? 0) + i * staggerDelay,
180
+ });
181
+ delete opts.staggerDelay;
182
+ return this.animate(id, keyframes, opts);
183
+ });
184
+ return Promise.all(promises);
185
+ },
186
+
187
+ /**
188
+ * Stagger on viewport entry.
189
+ */
190
+ staggerOnView(ids, keyframes, animOpts = {}, viewOpts = {}) {
191
+ if (!ids.length) return;
192
+ const self = this;
193
+ this._whenReady(() => {
194
+ // Set initial state on all elements
195
+ try {
196
+ if (keyframes.length > 0) {
197
+ ids.forEach((id) => {
198
+ const el = $(id);
199
+ if (el) self._setStylesWithoutTransition(el, keyframes[0]);
200
+ });
201
+ }
202
+ } catch (_) {}
203
+ // Observe first element as trigger
204
+ self.observe(ids[0], {
205
+ threshold: viewOpts.threshold ?? 0.1,
206
+ rootMargin: viewOpts.rootMargin || "0px 0px -50px 0px",
207
+ once: viewOpts.once !== false,
208
+ onEnter() {
209
+ self.stagger(ids, keyframes, animOpts);
210
+ },
211
+ });
212
+ });
213
+ },
214
+
215
+ /**
216
+ * Run a timeline of sequential animations.
217
+ * @param {Array<{id, keyframes, options}>} steps
218
+ * @returns {Promise}
219
+ */
220
+ async timeline(steps) {
221
+ for (const step of steps) {
222
+ if (step.delay) await new Promise((r) => setTimeout(r, step.delay));
223
+ await this.animate(step.id, step.keyframes, step.options || {});
224
+ }
225
+ },
226
+
227
+ /**
228
+ * Link an element's style to scroll progress (0-1).
229
+ * @param {string} id - Element ID
230
+ * @param {object} opts - { property, from, to, unit, start, end }
231
+ */
232
+ scrollProgress(id, opts = {}) {
233
+ const config = {
234
+ property: opts.property || "opacity",
235
+ from: opts.from ?? 0,
236
+ to: opts.to ?? 1,
237
+ unit: opts.unit || "",
238
+ start: opts.start ?? 0,
239
+ end: opts.end ?? 1,
240
+ };
241
+ __scrollHandlers.set(id, config);
242
+ if (!__scrollRAF) {
243
+ const tick = () => {
244
+ const scrollTop = window.scrollY || document.documentElement.scrollTop;
245
+ const docHeight = Math.max(
246
+ document.documentElement.scrollHeight - window.innerHeight,
247
+ 1,
248
+ );
249
+ const progress = Math.min(Math.max(scrollTop / docHeight, 0), 1);
250
+ for (const [eid, cfg] of __scrollHandlers) {
251
+ try {
252
+ const el = $(eid);
253
+ if (!el) continue;
254
+ const range = cfg.end - cfg.start;
255
+ const local =
256
+ range > 0
257
+ ? Math.min(Math.max((progress - cfg.start) / range, 0), 1)
258
+ : 0;
259
+ const val = cfg.from + (cfg.to - cfg.from) * local;
260
+ el.style[cfg.property] = val + cfg.unit;
261
+ } catch (_) {}
262
+ }
263
+ __scrollRAF = requestAnimationFrame(tick);
264
+ };
265
+ __scrollRAF = requestAnimationFrame(tick);
266
+ }
267
+ },
268
+
269
+ /**
270
+ * Remove scroll progress handler.
271
+ */
272
+ removeScrollProgress(id) {
273
+ __scrollHandlers.delete(id);
274
+ if (__scrollHandlers.size === 0 && __scrollRAF) {
275
+ cancelAnimationFrame(__scrollRAF);
276
+ __scrollRAF = null;
277
+ }
278
+ },
279
+
280
+ /**
281
+ * Add CSS class when element is in viewport (simple utility).
282
+ */
283
+ classOnView(id, className, opts = {}) {
284
+ this.observe(id, {
285
+ threshold: opts.threshold ?? 0.1,
286
+ rootMargin: opts.rootMargin || "0px",
287
+ once: opts.once !== false,
288
+ enterClass: className,
289
+ leaveClass: opts.leaveClass || null,
290
+ });
291
+ },
292
+
293
+ /**
294
+ * Execute arbitrary code when element enters viewport.
295
+ */
296
+ runOnView(id, code, opts = {}) {
297
+ this.observe(id, {
298
+ threshold: opts.threshold ?? 0.1,
299
+ rootMargin: opts.rootMargin || "0px",
300
+ once: opts.once !== false,
301
+ onEnter: code,
302
+ });
303
+ },
304
+
305
+ /**
306
+ * Cleanup all observers and scroll handlers.
307
+ */
308
+ destroy() {
309
+ for (const [, obs] of __observers) obs.disconnect();
310
+ __observers.clear();
311
+ __scrollHandlers.clear();
312
+ if (__scrollRAF) {
313
+ cancelAnimationFrame(__scrollRAF);
314
+ __scrollRAF = null;
315
+ }
316
+ },
317
+ };