tinymoon 0.3.1__tar.gz → 0.6.1__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.
- {tinymoon-0.3.1 → tinymoon-0.6.1}/.gitignore +3 -0
- tinymoon-0.6.1/PKG-INFO +352 -0
- tinymoon-0.6.1/README.md +332 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/clean/clean.html +15 -2
- tinymoon-0.6.1/assets/conformance/corpus/clean/clean.js +42 -0
- tinymoon-0.6.1/assets/conformance/corpus/clean/embed-abuse.html +29 -0
- tinymoon-0.6.1/assets/conformance/corpus/clean/embed-boundary.html +12 -0
- tinymoon-0.6.1/assets/conformance/corpus/clean/native-hidden.html +11 -0
- tinymoon-0.6.1/assets/conformance/corpus/clean/navigation.html +14 -0
- tinymoon-0.6.1/assets/conformance/corpus/clean/third_party/PROVENANCE.toml +7 -0
- tinymoon-0.6.1/assets/conformance/corpus/clean/third_party/vendor.css +6 -0
- tinymoon-0.6.1/assets/conformance/corpus/quarantine/mismatch/third_party/PROVENANCE.toml +6 -0
- tinymoon-0.6.1/assets/conformance/corpus/quarantine/mismatch/third_party/vendor.css +6 -0
- tinymoon-0.6.1/assets/conformance/corpus/quarantine/missing/third_party/PROVENANCE.toml +5 -0
- tinymoon-0.6.1/assets/conformance/corpus/quarantine/nomanifest/third_party/vendor.css +6 -0
- tinymoon-0.6.1/assets/conformance/corpus/quarantine/outside/vendor.css +6 -0
- tinymoon-0.6.1/assets/conformance/corpus/quarantine/traversal/third_party/PROVENANCE.toml +12 -0
- tinymoon-0.6.1/assets/conformance/corpus/quarantine/traversal/third_party/real.css +6 -0
- tinymoon-0.6.1/assets/conformance/corpus/violations/embed-boundary.html +9 -0
- tinymoon-0.6.1/assets/conformance/corpus/violations/external-url-attrs.html +10 -0
- tinymoon-0.6.1/assets/conformance/corpus/violations/external-url-importmap.html +14 -0
- tinymoon-0.6.1/assets/conformance/corpus/violations/external-url-template.js +7 -0
- tinymoon-0.6.1/assets/conformance/corpus/violations/external-url-ws.js +3 -0
- tinymoon-0.6.1/assets/conformance/corpus/violations/native-control-js-types.js +17 -0
- tinymoon-0.6.1/assets/conformance/corpus/violations/native-input-types.html +17 -0
- tinymoon-0.6.1/assets/conformance/corpus/violations/raw-color-extra-fns.css +5 -0
- tinymoon-0.6.1/assets/conformance/expectations.json +428 -0
- tinymoon-0.6.1/assets/conformance/rules.json +128 -0
- tinymoon-0.6.1/assets/css/base.css +280 -0
- tinymoon-0.6.1/assets/css/primitives.css +1429 -0
- tinymoon-0.6.1/assets/css/shell.css +276 -0
- tinymoon-0.6.1/assets/css/tokens.css +168 -0
- tinymoon-0.6.1/assets/css/widgets.css +454 -0
- tinymoon-0.6.1/assets/js/accordion.js +120 -0
- tinymoon-0.6.1/assets/js/auditor.js +239 -0
- tinymoon-0.6.1/assets/js/badge.js +26 -0
- tinymoon-0.6.1/assets/js/breadcrumbs.js +108 -0
- tinymoon-0.6.1/assets/js/chart.js +120 -0
- tinymoon-0.6.1/assets/js/chrome.d.ts +227 -0
- tinymoon-0.6.1/assets/js/chrome.js +17 -0
- tinymoon-0.6.1/assets/js/combobox.js +642 -0
- tinymoon-0.6.1/assets/js/controls.js +359 -0
- tinymoon-0.6.1/assets/js/ctxmenu.js +215 -0
- tinymoon-0.6.1/assets/js/datepicker.js +603 -0
- tinymoon-0.6.1/assets/js/dismiss.js +134 -0
- tinymoon-0.6.1/assets/js/drawer.js +131 -0
- tinymoon-0.6.1/assets/js/embed.js +133 -0
- tinymoon-0.6.1/assets/js/extras.d.ts +247 -0
- tinymoon-0.6.1/assets/js/extras.js +9 -0
- tinymoon-0.6.1/assets/js/feed.js +146 -0
- tinymoon-0.6.1/assets/js/filterbar.js +123 -0
- tinymoon-0.6.1/assets/js/format.js +101 -0
- tinymoon-0.6.1/assets/js/grid.js +53 -0
- tinymoon-0.6.1/assets/js/hovercard.js +173 -0
- tinymoon-0.6.1/assets/js/iconbutton.js +43 -0
- {tinymoon-0.3.1 → tinymoon-0.6.1}/assets/js/icons.js +9 -1
- tinymoon-0.6.1/assets/js/index.d.ts +669 -0
- tinymoon-0.6.1/assets/js/index.js +29 -0
- tinymoon-0.6.1/assets/js/inputs.js +309 -0
- tinymoon-0.6.1/assets/js/kernel.js +172 -0
- tinymoon-0.6.1/assets/js/lazy.js +67 -0
- {tinymoon-0.3.1 → tinymoon-0.6.1}/assets/js/markdown.js +16 -14
- tinymoon-0.6.1/assets/js/modal.js +91 -0
- tinymoon-0.6.1/assets/js/net.js +92 -0
- tinymoon-0.6.1/assets/js/paginate.js +132 -0
- tinymoon-0.6.1/assets/js/palette.js +229 -0
- tinymoon-0.6.1/assets/js/popover.js +38 -0
- tinymoon-0.6.1/assets/js/realtime.js +182 -0
- tinymoon-0.6.1/assets/js/select.js +263 -0
- tinymoon-0.6.1/assets/js/settings.js +137 -0
- tinymoon-0.6.1/assets/js/shell.js +310 -0
- tinymoon-0.6.1/assets/js/shortcuts.js +114 -0
- tinymoon-0.6.1/assets/js/slider.js +80 -0
- tinymoon-0.6.1/assets/js/sparkline.js +109 -0
- tinymoon-0.6.1/assets/js/state.d.ts +90 -0
- tinymoon-0.6.1/assets/js/state.js +6 -0
- tinymoon-0.6.1/assets/js/states.js +94 -0
- tinymoon-0.6.1/assets/js/stats.js +95 -0
- tinymoon-0.6.1/assets/js/store.js +254 -0
- tinymoon-0.6.1/assets/js/table.js +261 -0
- tinymoon-0.6.1/assets/js/tabpanels.js +78 -0
- tinymoon-0.6.1/assets/js/timepicker.js +375 -0
- tinymoon-0.6.1/assets/js/toast.js +164 -0
- tinymoon-0.6.1/assets/js/tooltip.js +122 -0
- tinymoon-0.6.1/assets/js/tree.js +270 -0
- tinymoon-0.6.1/assets/js/view.js +43 -0
- tinymoon-0.6.1/assets/js/virtuallist.js +138 -0
- tinymoon-0.6.1/assets/js/widgets.d.ts +407 -0
- tinymoon-0.6.1/assets/js/widgets.js +19 -0
- {tinymoon-0.3.1 → tinymoon-0.6.1}/assets/js/wiki.js +17 -8
- tinymoon-0.6.1/assets/tokens.json +131 -0
- {tinymoon-0.3.1 → tinymoon-0.6.1}/pyproject.toml +16 -5
- tinymoon-0.6.1/tests/fixtures/clean/clean.css +30 -0
- tinymoon-0.6.1/tests/fixtures/clean/clean.html +41 -0
- tinymoon-0.6.1/tests/fixtures/clean/clean.js +42 -0
- tinymoon-0.6.1/tests/fixtures/clean/embed-abuse.html +29 -0
- tinymoon-0.6.1/tests/fixtures/clean/embed-boundary.html +12 -0
- tinymoon-0.6.1/tests/fixtures/clean/native-hidden.html +11 -0
- tinymoon-0.6.1/tests/fixtures/clean/navigation.html +14 -0
- tinymoon-0.6.1/tests/fixtures/clean/third_party/PROVENANCE.toml +7 -0
- tinymoon-0.6.1/tests/fixtures/clean/third_party/vendor.css +6 -0
- tinymoon-0.6.1/tests/fixtures/clean/tinymoon-allowlist.txt +2 -0
- tinymoon-0.6.1/tests/fixtures/quarantine/mismatch/third_party/PROVENANCE.toml +6 -0
- tinymoon-0.6.1/tests/fixtures/quarantine/mismatch/third_party/vendor.css +6 -0
- tinymoon-0.6.1/tests/fixtures/quarantine/missing/third_party/PROVENANCE.toml +5 -0
- tinymoon-0.6.1/tests/fixtures/quarantine/nomanifest/third_party/vendor.css +6 -0
- tinymoon-0.6.1/tests/fixtures/quarantine/outside/vendor.css +6 -0
- tinymoon-0.6.1/tests/fixtures/quarantine/traversal/third_party/PROVENANCE.toml +12 -0
- tinymoon-0.6.1/tests/fixtures/quarantine/traversal/third_party/real.css +6 -0
- tinymoon-0.6.1/tests/fixtures/violations/border-radius.css +15 -0
- tinymoon-0.6.1/tests/fixtures/violations/border-radius.html +7 -0
- tinymoon-0.6.1/tests/fixtures/violations/border-radius.js +8 -0
- tinymoon-0.6.1/tests/fixtures/violations/embed-boundary.html +9 -0
- tinymoon-0.6.1/tests/fixtures/violations/external-url-attrs.html +10 -0
- tinymoon-0.6.1/tests/fixtures/violations/external-url-importmap.html +14 -0
- tinymoon-0.6.1/tests/fixtures/violations/external-url-template.js +7 -0
- tinymoon-0.6.1/tests/fixtures/violations/external-url-ws.js +3 -0
- tinymoon-0.6.1/tests/fixtures/violations/external-url.css +11 -0
- tinymoon-0.6.1/tests/fixtures/violations/external-url.html +11 -0
- tinymoon-0.6.1/tests/fixtures/violations/external-url.js +8 -0
- tinymoon-0.6.1/tests/fixtures/violations/native-control-js-types.js +17 -0
- tinymoon-0.6.1/tests/fixtures/violations/native-control.html +11 -0
- tinymoon-0.6.1/tests/fixtures/violations/native-control.js +9 -0
- tinymoon-0.6.1/tests/fixtures/violations/native-input-types.html +17 -0
- tinymoon-0.6.1/tests/fixtures/violations/raw-color-extra-fns.css +5 -0
- tinymoon-0.6.1/tests/fixtures/violations/raw-color.css +15 -0
- tinymoon-0.6.1/tests/fixtures/violations/raw-color.html +8 -0
- tinymoon-0.6.1/tests/fixtures/violations/raw-color.js +8 -0
- tinymoon-0.6.1/tests/fixtures/violations/title-attr.html +8 -0
- tinymoon-0.6.1/tests/fixtures/violations/title-attr.js +8 -0
- tinymoon-0.6.1/tests/js/e2e/chrome-6b.spec.js +142 -0
- tinymoon-0.6.1/tests/js/e2e/chrome.spec.js +179 -0
- tinymoon-0.6.1/tests/js/e2e/conformance-csp.spec.js +87 -0
- tinymoon-0.6.1/tests/js/e2e/conformance-runtime.spec.js +70 -0
- tinymoon-0.6.1/tests/js/e2e/content-first.spec.js +127 -0
- tinymoon-0.6.1/tests/js/e2e/copy.spec.js +173 -0
- tinymoon-0.6.1/tests/js/e2e/ctxmenu.spec.js +176 -0
- tinymoon-0.6.1/tests/js/e2e/data-widgets-5b.spec.js +210 -0
- tinymoon-0.6.1/tests/js/e2e/data-widgets.spec.js +163 -0
- tinymoon-0.6.1/tests/js/e2e/datepicker.spec.js +211 -0
- tinymoon-0.6.1/tests/js/e2e/embed-isolation.spec.js +71 -0
- tinymoon-0.6.1/tests/js/e2e/fixtures/auditor-gallery.html +19 -0
- tinymoon-0.6.1/tests/js/e2e/fixtures/content-first.html +136 -0
- tinymoon-0.6.1/tests/js/e2e/fixtures/embed-isolation.html +52 -0
- tinymoon-0.6.1/tests/js/e2e/fixtures/escape-stack.html +33 -0
- tinymoon-0.6.1/tests/js/e2e/fixtures/rtl.html +98 -0
- tinymoon-0.6.1/tests/js/e2e/fixtures/selector-hygiene.html +77 -0
- tinymoon-0.6.1/tests/js/e2e/forms.spec.js +327 -0
- tinymoon-0.6.1/tests/js/e2e/gallery-characterization.spec.js +61 -0
- tinymoon-0.6.1/tests/js/e2e/gallery.spec.js +9 -0
- tinymoon-0.6.1/tests/js/e2e/helpers.js +23 -0
- tinymoon-0.6.1/tests/js/e2e/light-dismiss.spec.js +64 -0
- tinymoon-0.6.1/tests/js/e2e/modal.spec.js +102 -0
- tinymoon-0.6.1/tests/js/e2e/phase3b-controls.spec.js +223 -0
- tinymoon-0.6.1/tests/js/e2e/realtime-transcript.spec.js +76 -0
- tinymoon-0.6.1/tests/js/e2e/red-bugs.spec.js +51 -0
- tinymoon-0.6.1/tests/js/e2e/reduced-motion.spec.js +55 -0
- tinymoon-0.6.1/tests/js/e2e/responsive.spec.js +187 -0
- tinymoon-0.6.1/tests/js/e2e/selector-hygiene.spec.js +112 -0
- tinymoon-0.6.1/tests/js/e2e/shell-semantics.spec.js +100 -0
- tinymoon-0.6.1/tests/js/e2e/state.spec.js +58 -0
- tinymoon-0.6.1/tests/js/e2e/toast.spec.js +81 -0
- tinymoon-0.6.1/tests/js/e2e/tooltip-hovercard.spec.js +169 -0
- tinymoon-0.6.1/tests/js/unit/accordion.test.js +116 -0
- tinymoon-0.6.1/tests/js/unit/api-convention.test.js +712 -0
- tinymoon-0.6.1/tests/js/unit/badge.test.js +41 -0
- tinymoon-0.6.1/tests/js/unit/breadcrumbs.test.js +97 -0
- tinymoon-0.6.1/tests/js/unit/chart.test.js +118 -0
- tinymoon-0.6.1/tests/js/unit/combobox.test.js +308 -0
- tinymoon-0.6.1/tests/js/unit/controls.test.js +432 -0
- tinymoon-0.6.1/tests/js/unit/copyable.test.js +140 -0
- tinymoon-0.6.1/tests/js/unit/datepicker.test.js +214 -0
- tinymoon-0.6.1/tests/js/unit/dismiss.test.js +259 -0
- tinymoon-0.6.1/tests/js/unit/dom.test.js +13 -0
- tinymoon-0.6.1/tests/js/unit/drawer.test.js +116 -0
- tinymoon-0.6.1/tests/js/unit/embed.test.js +159 -0
- tinymoon-0.6.1/tests/js/unit/exports-map.test.js +120 -0
- tinymoon-0.6.1/tests/js/unit/feed.test.js +120 -0
- tinymoon-0.6.1/tests/js/unit/filterbar.test.js +111 -0
- tinymoon-0.6.1/tests/js/unit/format.test.js +150 -0
- tinymoon-0.6.1/tests/js/unit/grid.test.js +68 -0
- tinymoon-0.6.1/tests/js/unit/hovercard.test.js +149 -0
- tinymoon-0.6.1/tests/js/unit/iconbutton.test.js +55 -0
- tinymoon-0.6.1/tests/js/unit/icons.test.js +26 -0
- tinymoon-0.6.1/tests/js/unit/import-graph.test.js +88 -0
- tinymoon-0.6.1/tests/js/unit/inputs.test.js +322 -0
- tinymoon-0.6.1/tests/js/unit/kernel.test.js +225 -0
- tinymoon-0.6.1/tests/js/unit/lazy.test.js +127 -0
- tinymoon-0.6.1/tests/js/unit/markdown.test.js +54 -0
- tinymoon-0.6.1/tests/js/unit/net.test.js +202 -0
- tinymoon-0.6.1/tests/js/unit/no-direct-shell-nodes.test.js +57 -0
- tinymoon-0.6.1/tests/js/unit/paginate.test.js +117 -0
- tinymoon-0.6.1/tests/js/unit/palette.test.js +172 -0
- tinymoon-0.6.1/tests/js/unit/realtime.test.js +312 -0
- tinymoon-0.6.1/tests/js/unit/red-bugs.test.js +102 -0
- tinymoon-0.6.1/tests/js/unit/select.test.js +231 -0
- tinymoon-0.6.1/tests/js/unit/settings.test.js +98 -0
- tinymoon-0.6.1/tests/js/unit/shell-page-sub-export.test.js +21 -0
- tinymoon-0.6.1/tests/js/unit/shortcuts.test.js +136 -0
- tinymoon-0.6.1/tests/js/unit/slider.test.js +148 -0
- tinymoon-0.6.1/tests/js/unit/sparkline.test.js +101 -0
- tinymoon-0.6.1/tests/js/unit/states.test.js +103 -0
- tinymoon-0.6.1/tests/js/unit/stats.test.js +102 -0
- tinymoon-0.6.1/tests/js/unit/store.test.js +285 -0
- tinymoon-0.6.1/tests/js/unit/table.test.js +247 -0
- tinymoon-0.6.1/tests/js/unit/tabpanels.test.js +94 -0
- tinymoon-0.6.1/tests/js/unit/theme.test.js +89 -0
- tinymoon-0.6.1/tests/js/unit/timepicker.test.js +210 -0
- tinymoon-0.6.1/tests/js/unit/toast.test.js +192 -0
- tinymoon-0.6.1/tests/js/unit/tooltip.test.js +115 -0
- tinymoon-0.6.1/tests/js/unit/tree.test.js +202 -0
- tinymoon-0.6.1/tests/js/unit/type-parity.test.js +64 -0
- tinymoon-0.6.1/tests/js/unit/view.test.js +149 -0
- tinymoon-0.6.1/tests/js/unit/virtuallist.test.js +115 -0
- tinymoon-0.6.1/tests/test_assets.py +31 -0
- tinymoon-0.6.1/tests/test_budgets.py +307 -0
- tinymoon-0.6.1/tests/test_charter.py +339 -0
- tinymoon-0.6.1/tests/test_checker.py +447 -0
- tinymoon-0.6.1/tests/test_conformance_artifact.py +177 -0
- tinymoon-0.6.1/tests/test_contrast.py +205 -0
- tinymoon-0.6.1/tests/test_tokens_artifact.py +70 -0
- tinymoon-0.6.1/tests/types/consumer.ts +646 -0
- tinymoon-0.6.1/tests/types/tsconfig.json +21 -0
- {tinymoon-0.3.1 → tinymoon-0.6.1}/tinymoon/__init__.py +1 -1
- tinymoon-0.6.1/tinymoon/checker.py +1366 -0
- {tinymoon-0.3.1 → tinymoon-0.6.1}/tinymoon/cli.py +7 -4
- tinymoon-0.3.1/.github/workflows/ci-go.yml +0 -26
- tinymoon-0.3.1/.github/workflows/ci-pypi.yml +0 -33
- tinymoon-0.3.1/.github/workflows/publish.yml +0 -202
- tinymoon-0.3.1/.npmignore +0 -34
- tinymoon-0.3.1/.rlsbl/bases/.github/workflows/ci-go.yml +0 -26
- tinymoon-0.3.1/.rlsbl/bases/.github/workflows/ci-pypi.yml +0 -33
- tinymoon-0.3.1/.rlsbl/bases/.github/workflows/publish.yml +0 -192
- tinymoon-0.3.1/.rlsbl/bases/.gitignore +0 -18
- tinymoon-0.3.1/.rlsbl/bases/.npmignore +0 -34
- tinymoon-0.3.1/.rlsbl/bases/.rlsbl/lint/go.toml +0 -17
- tinymoon-0.3.1/.rlsbl/bases/.rlsbl/lint/npm.toml +0 -19
- tinymoon-0.3.1/.rlsbl/bases/.rlsbl/lint/python.toml +0 -25
- tinymoon-0.3.1/.rlsbl/bases/CHANGELOG.md +0 -5
- tinymoon-0.3.1/.rlsbl/bases/VERSION +0 -1
- tinymoon-0.3.1/.rlsbl/changes/0.0.1.jsonl +0 -1
- tinymoon-0.3.1/.rlsbl/changes/0.0.1.md +0 -7
- tinymoon-0.3.1/.rlsbl/changes/0.1.0.jsonl +0 -16
- tinymoon-0.3.1/.rlsbl/changes/0.1.0.md +0 -15
- tinymoon-0.3.1/.rlsbl/changes/0.2.0.jsonl +0 -18
- tinymoon-0.3.1/.rlsbl/changes/0.2.0.md +0 -24
- tinymoon-0.3.1/.rlsbl/changes/0.3.0.jsonl +0 -2
- tinymoon-0.3.1/.rlsbl/changes/0.3.0.md +0 -7
- tinymoon-0.3.1/.rlsbl/changes/0.3.1.jsonl +0 -1
- tinymoon-0.3.1/.rlsbl/changes/0.3.1.md +0 -7
- tinymoon-0.3.1/.rlsbl/changes/unreleased.jsonl +0 -0
- tinymoon-0.3.1/.rlsbl/config.json +0 -23
- tinymoon-0.3.1/.rlsbl/lint/go.toml +0 -17
- tinymoon-0.3.1/.rlsbl/lint/npm.toml +0 -19
- tinymoon-0.3.1/.rlsbl/lint/python.toml +0 -25
- tinymoon-0.3.1/.rlsbl/managed-files.json +0 -16
- tinymoon-0.3.1/.rlsbl/releases/v0.0.1.toml +0 -12
- tinymoon-0.3.1/.rlsbl/releases/v0.2.0.toml +0 -14
- tinymoon-0.3.1/.rlsbl/releases/v0.3.0.toml +0 -12
- tinymoon-0.3.1/.rlsbl/releases/v0.3.1.toml +0 -12
- tinymoon-0.3.1/.rlsbl/version +0 -1
- tinymoon-0.3.1/.strictcli/schema.json +0 -66
- tinymoon-0.3.1/CHANGELOG.md +0 -68
- tinymoon-0.3.1/CLAUDE.md +0 -21
- tinymoon-0.3.1/PKG-INFO +0 -131
- tinymoon-0.3.1/README.md +0 -110
- tinymoon-0.3.1/VERSION +0 -1
- tinymoon-0.3.1/assets/css/base.css +0 -113
- tinymoon-0.3.1/assets/css/primitives.css +0 -627
- tinymoon-0.3.1/assets/css/shell.css +0 -135
- tinymoon-0.3.1/assets/css/tokens.css +0 -99
- tinymoon-0.3.1/assets/js/controls.js +0 -82
- tinymoon-0.3.1/assets/js/ctxmenu.js +0 -97
- tinymoon-0.3.1/assets/js/format.js +0 -9
- tinymoon-0.3.1/assets/js/index.js +0 -18
- tinymoon-0.3.1/assets/js/modal.js +0 -63
- tinymoon-0.3.1/assets/js/net.js +0 -24
- tinymoon-0.3.1/assets/js/popover.js +0 -46
- tinymoon-0.3.1/assets/js/select.js +0 -138
- tinymoon-0.3.1/assets/js/settings.js +0 -56
- tinymoon-0.3.1/assets/js/shell.js +0 -211
- tinymoon-0.3.1/assets/js/toast.js +0 -49
- tinymoon-0.3.1/assets/js/tooltip.js +0 -106
- tinymoon-0.3.1/gallery/gallery.css +0 -81
- tinymoon-0.3.1/gallery/gallery.js +0 -654
- tinymoon-0.3.1/gallery/index.html +0 -19
- tinymoon-0.3.1/go.mod +0 -3
- tinymoon-0.3.1/index.js +0 -2
- tinymoon-0.3.1/package.json +0 -29
- tinymoon-0.3.1/tests/fixtures/clean/clean.js +0 -16
- tinymoon-0.3.1/tests/test_assets.py +0 -16
- tinymoon-0.3.1/tests/test_budgets.py +0 -72
- tinymoon-0.3.1/tests/test_checker.py +0 -194
- tinymoon-0.3.1/tinymoon/checker.py +0 -678
- tinymoon-0.3.1/tinymoon.go +0 -36
- tinymoon-0.3.1/uv.lock +0 -92
- {tinymoon-0.3.1 → tinymoon-0.6.1}/LICENSE +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/clean/clean.css +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/clean/tinymoon-allowlist.txt +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/border-radius.css +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/border-radius.html +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/border-radius.js +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/external-url.css +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/external-url.html +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/external-url.js +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/native-control.html +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/native-control.js +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/raw-color.css +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/raw-color.html +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/raw-color.js +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/title-attr.html +0 -0
- {tinymoon-0.3.1/tests/fixtures → tinymoon-0.6.1/assets/conformance/corpus}/violations/title-attr.js +0 -0
- {tinymoon-0.3.1 → tinymoon-0.6.1}/assets/fonts/ibm-plex-mono-latin-400.woff2 +0 -0
- {tinymoon-0.3.1 → tinymoon-0.6.1}/assets/fonts/ibm-plex-mono-latin-500.woff2 +0 -0
- {tinymoon-0.3.1 → tinymoon-0.6.1}/assets/fonts/ibm-plex-sans-latin.woff2 +0 -0
- {tinymoon-0.3.1 → tinymoon-0.6.1}/assets/fonts/space-grotesk-latin.woff2 +0 -0
- {tinymoon-0.3.1 → tinymoon-0.6.1}/assets/js/dom.js +0 -0
- {tinymoon-0.3.1 → tinymoon-0.6.1}/tests/test_version.py +0 -0
- /tinymoon-0.3.1/.rlsbl/bases/.rlsbl/changes/unreleased.jsonl → /tinymoon-0.6.1/tinymoon/py.typed +0 -0
tinymoon-0.6.1/PKG-INFO
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tinymoon
|
|
3
|
+
Version: 0.6.1
|
|
4
|
+
Summary: Zero-dependency vanilla JS/CSS UI framework with a conformance checker CLI
|
|
5
|
+
Project-URL: Homepage, https://github.com/smm-h/tinymoon
|
|
6
|
+
Project-URL: Repository, https://github.com/smm-h/tinymoon
|
|
7
|
+
Author-email: smm-h <smmh72@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: css,framework,rlsbl,ui,vanilla-js,zero-dependency
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Requires-Dist: strictcli
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# tinymoon
|
|
22
|
+
|
|
23
|
+
A content-first web framework: you bring plain, semantic content and small view objects; tinymoon brings the app -- shell, typography, widgets, motion. Everything ships as native ES modules and plain CSS with zero dependencies, zero build steps, and zero network loads.
|
|
24
|
+
|
|
25
|
+
tinymoon's palette is its identity. Consumer CSS must not redefine framework tokens.
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
npm (core + extras):
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
npm install tinymoon
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The npm package exports barrels: `"tinymoon"` (core primitives), `"tinymoon/extras"` (wiki, networking, settings), `"tinymoon/state"` (store + reconciler), `"tinymoon/widgets"` (data-display), and `"tinymoon/chrome"` (async-state blocks, lazy mounting, shortcuts, command palette, light-dismiss engine + overlay-trigger invoker). Assets are available at `"tinymoon/assets/*"`.
|
|
36
|
+
|
|
37
|
+
Every shipped module is also importable by subpath -- `"tinymoon/select"`, `"tinymoon/dom"`, `"tinymoon/net"`, and so on, one per file in `assets/js/`. There is no build step and no tree-shaking, so subpaths are the way to import just what you use. Typed consumption goes through the barrels (`.d.ts` declarations cover `"tinymoon"`, `"tinymoon/extras"`, `"tinymoon/state"`, `"tinymoon/widgets"`, and `"tinymoon/chrome"`); the subpaths are for granular runtime imports and ship no per-module type declarations. `"tinymoon/auditor"` is a dev-only conformance module, not part of any barrel.
|
|
38
|
+
|
|
39
|
+
PyPI (assets + conformance checker CLI):
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
pip install tinymoon
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`tinymoon.assets_path()` returns the directory containing `css/`, `js/`, and `fonts/`.
|
|
46
|
+
|
|
47
|
+
Go (embedded filesystem):
|
|
48
|
+
|
|
49
|
+
```go
|
|
50
|
+
import "github.com/smm-h/tinymoon"
|
|
51
|
+
|
|
52
|
+
// tinymoon.Assets — embed.FS rooted at the repo root
|
|
53
|
+
// tinymoon.FS() — fs.FS rooted at the assets directory
|
|
54
|
+
// tinymoon.Handler() — http.Handler serving the assets
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Quick start
|
|
58
|
+
|
|
59
|
+
Link the CSS layers (tokens first) and import the ES modules -- no build step, no bundler:
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<link rel="stylesheet" href="assets/css/tokens.css">
|
|
63
|
+
<link rel="stylesheet" href="assets/css/base.css">
|
|
64
|
+
<link rel="stylesheet" href="assets/css/shell.css">
|
|
65
|
+
<link rel="stylesheet" href="assets/css/primitives.css">
|
|
66
|
+
<link rel="stylesheet" href="assets/css/widgets.css">
|
|
67
|
+
|
|
68
|
+
<script type="module">
|
|
69
|
+
import { mountShell, toast } from "./assets/js/index.js";
|
|
70
|
+
import { createSettings } from "./assets/js/extras.js";
|
|
71
|
+
|
|
72
|
+
const settings = createSettings({
|
|
73
|
+
storageKey: "my-app",
|
|
74
|
+
defaults: { theme: "dark" },
|
|
75
|
+
});
|
|
76
|
+
settings.load();
|
|
77
|
+
settings.applyTheme();
|
|
78
|
+
|
|
79
|
+
const shell = mountShell({
|
|
80
|
+
root: document.body,
|
|
81
|
+
brand: {
|
|
82
|
+
name: "myapp",
|
|
83
|
+
logoHTML: '<div class="wordmark">my<b>app</b></div>',
|
|
84
|
+
},
|
|
85
|
+
routes: {
|
|
86
|
+
home: {
|
|
87
|
+
title: "Home",
|
|
88
|
+
icon: "library",
|
|
89
|
+
view: () => HomeView,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
defaultRoute: "home",
|
|
93
|
+
});
|
|
94
|
+
</script>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`widgets.css` is the data-display layer -- it styles badges, cards, stats, data tables, and the empty state. Only apps that render those widgets need it; content-first apps and pure-control apps can omit it and link just the first four sheets. When you do link it, keep it fifth, after `primitives.css`.
|
|
98
|
+
|
|
99
|
+
With npm, use bare specifiers by adding an import map:
|
|
100
|
+
|
|
101
|
+
```html
|
|
102
|
+
<script type="importmap">
|
|
103
|
+
{ "imports": { "tinymoon": "./node_modules/tinymoon/assets/js/index.js",
|
|
104
|
+
"tinymoon/extras": "./node_modules/tinymoon/assets/js/extras.js" } }
|
|
105
|
+
</script>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Primitives
|
|
109
|
+
|
|
110
|
+
### Core (`tinymoon`)
|
|
111
|
+
|
|
112
|
+
**Shell and DOM:**
|
|
113
|
+
|
|
114
|
+
- `mountShell(opts)` -- mount the app shell with sidebar, topbar, router, and footer slot (routes accept `eager: true` to build at mount instead of first visit)
|
|
115
|
+
- `createView(opts)` -- build a contract-conforming route view with managed `built`; `build`/`refresh` receive a ctx `{root, setSub(text)}`
|
|
116
|
+
- `announce(msg)` -- push a message into the shell's aria-live route announcer (also on the shell instance as `shell.announce`)
|
|
117
|
+
- `el(tag, cls?, text?)` -- element factory
|
|
118
|
+
- `$(sel, root?)` -- querySelector shorthand
|
|
119
|
+
- `$$(sel, root?)` -- querySelectorAll (returns array)
|
|
120
|
+
|
|
121
|
+
**Controls:**
|
|
122
|
+
|
|
123
|
+
- `createSwitch(opts)` -- role="switch" toggle button (not form-participating)
|
|
124
|
+
- `createInput(opts)` -- styled-native text input in a labeled field (form-participating; text/password/email/url/search/tel only)
|
|
125
|
+
- `createTextarea(opts)` -- styled-native textarea in a labeled field (form-participating)
|
|
126
|
+
- `createField(opts)` -- labeled `.field` wrapper with optional hint and inline `setError`
|
|
127
|
+
- `createCheckbox(opts)` -- hidden-native checkbox facade (form-participating)
|
|
128
|
+
- `createRadio(opts)` -- hidden-native radio facade (form-participating)
|
|
129
|
+
- `createFileInput(opts)` -- hidden-native file input facade (form-participating)
|
|
130
|
+
- `createNumber(opts)` -- number stepper wrapping a native `input[type=number]` with custom +/- buttons (form-participating)
|
|
131
|
+
- `createSegmented(opts)` -- segmented control with hidden radios (form-participating)
|
|
132
|
+
- `createSlider(opts)` -- styled-native range slider (form-participating; onInput = live, onChange = commit; `variant: "seek"` is an invisible position scrubber for app-drawn waveform/timeline visuals)
|
|
133
|
+
- `createTabs(opts)` -- tab bar (not form-participating)
|
|
134
|
+
- `createSelect(opts)` -- custom dropdown select
|
|
135
|
+
- `createCombobox(opts)` -- typeahead combobox with debounced async `onFilter` and stale-response discard (form-participating)
|
|
136
|
+
- `createMultiSelect(opts)` -- multi-value typeahead with removable chips over a hidden `<select multiple>` (form-participating)
|
|
137
|
+
- `createDatePicker(opts)` -- calendar date picker
|
|
138
|
+
- `createTimePicker(opts)` -- HH:MM time picker with locale display and an hours/minutes popover (form-participating)
|
|
139
|
+
- `createAccordion(opts)` -- stacked disclosure panels (single- or multi-open)
|
|
140
|
+
- `createTabPanels(opts)` -- tab bar composed with lazy, state-preserving panels (completes the APG tabs pattern)
|
|
141
|
+
- `createGrid(opts)` -- CSS-first preset rectangular layout (`1x1`/`2x1`/`1x2`/`2x2`); a content primitive, not a shell mode
|
|
142
|
+
- `iconButton(opts)` -- stateful topbar icon button instance (`setActive`/`setIcon`); pass `.el` to `topbarActions`
|
|
143
|
+
- `copyButton(getText, tip?)` -- one-click clipboard copy button
|
|
144
|
+
- `kebabButton(itemsFn, tip?)` -- three-dot menu button
|
|
145
|
+
|
|
146
|
+
> `copyButton` and `kebabButton` are sanctioned one-shot element utilities, not `createX` components -- they return a pre-wired `<button>` by design.
|
|
147
|
+
|
|
148
|
+
**Overlays:**
|
|
149
|
+
|
|
150
|
+
- `toast(msg, level?, opts?)` -- toast notification ("ok", "err", or plain)
|
|
151
|
+
- `setToastErrorHook(fn)` -- mirror error toasts into a custom hook
|
|
152
|
+
- `openModal(opts)` -- modal dialog (returns close function)
|
|
153
|
+
- `openDrawer(opts)` -- edge-anchored overlay drawer, light-dismiss or `modal: true` (returns `{el, close}`); pass a `trigger` (or wrap with `registerOverlayTrigger`) for a proper toggle button
|
|
154
|
+
- `openPopover(anchor, builder)` / `closePopover()` -- positioned popover
|
|
155
|
+
- `registerCtx(key, provider)` / `registerCtxFooter(fn)` -- context menu regions
|
|
156
|
+
- `showCtxMenu(x, y, items, anchor?)` / `hideCtxMenu()` -- programmatic context menu
|
|
157
|
+
- `ensureTooltip(el, text)` / `hideTip()` -- tooltip lifecycle
|
|
158
|
+
- `ensureHovercard(el, md)` / `hideHovercard()` -- rich hovercard with markdown
|
|
159
|
+
|
|
160
|
+
**Data and utilities:**
|
|
161
|
+
|
|
162
|
+
- `ICONS` -- built-in icon set (29 icons)
|
|
163
|
+
- `icon(name)` -- render an icon as an SVG string
|
|
164
|
+
- `registerIcons(map)` -- merge consumer icons (collisions are hard errors)
|
|
165
|
+
- `renderMiniMd(text)` -- inline markdown to DOM fragment (bold, code, links)
|
|
166
|
+
- `cssVar(name)` -- read a computed CSS custom property value
|
|
167
|
+
- `ensureRoot()` -- ensure the root element exists
|
|
168
|
+
- `placeBelow(anchor, el)` -- position an element below an anchor
|
|
169
|
+
- `registerCopyable(el, fn)` / `unregisterCopyable(el)` -- register elements for the copy system
|
|
170
|
+
- `getCopyData(el)` -- retrieve copy data from a registered element
|
|
171
|
+
|
|
172
|
+
### Extras (`tinymoon/extras`)
|
|
173
|
+
|
|
174
|
+
- `api(path)` -- GET JSON from a same-origin path
|
|
175
|
+
- `post(path, body, onError?)` -- POST JSON to a same-origin path
|
|
176
|
+
- `createSettings(opts)` -- localStorage-backed settings store with schema validation (the returned store exposes `.subscribe(key, cb)` like any state store)
|
|
177
|
+
- `cycleTheme(store)` -- cycle a settings store's theme `dark -> light -> system` (the tri-state theme: `applyTheme()` resolves a stored `"system"` to the OS light/dark preference and re-resolves live on OS change, while storing `"system"`)
|
|
178
|
+
- `THEME_BOOT_SNIPPET` -- an exported inline pre-paint script string; drop it into a `<script>` in `<head>` **before** your stylesheets so `<html data-theme>` is set before the first paint (no light/dark flash). It resolves a stored `"system"` value against the OS and assumes the default storage key `"tm-settings"` (replace that one literal if your `storageKey` differs). Touches only `localStorage`/`matchMedia`/`documentElement` -- nothing the conformance scanners flag.
|
|
179
|
+
- `createWikiView(opts)` -- wiki view factory with table of contents and deep-linkable sections
|
|
180
|
+
- `renderDocMd(md)` -- block-level markdown to DOM (paragraphs, subheadings, lists)
|
|
181
|
+
|
|
182
|
+
### Chrome (`tinymoon/chrome`)
|
|
183
|
+
|
|
184
|
+
The Phase 6B framework wave. A separate barrel (not the core `tinymoon` index) purely for size discipline -- the frozen core byte ceiling has no room for the extra re-export lines. Each module is also importable by its own subpath (`tinymoon/palette`, `tinymoon/shortcuts`, ...).
|
|
185
|
+
|
|
186
|
+
- `loadingBlock(opts?)` / `emptyBlock(opts)` / `errorBlock(opts)` -- one-shot async-state element blocks (static-first, reduced-motion-safe, built on the `.empty` widgets.css style)
|
|
187
|
+
- `renderAsync(container, promise, opts)` -- swap loading/data/empty/error blocks into a container as a promise settles
|
|
188
|
+
- `lazyMount(target, loadFn, opts?)` -- IntersectionObserver-gated loader with a concurrency pump (default 3-wide), draining in visibility order; returns `cancel()`
|
|
189
|
+
- `registerShortcut(combo, handler, opts?)` -- keyboard shortcut binder on one shared listener ("mod+k" combos, overlay-aware suppression, `global`/`allowInInputs` opts, duplicate-combo hard error)
|
|
190
|
+
- `registerPaletteSource(fn)` / `openPalette()` / `installPalette(opts?)` -- opt-in command palette: source aggregation, debounced + stale-discarding querying, built-in subsequence match/rank, and (via `installPalette`) a global toggle shortcut seeded from the shell's routes
|
|
191
|
+
- `registerLightDismiss(opts)` -- register a light-dismiss overlay layer on the kernel's central outside-pointer registry (one document capture-phase `pointerdown` listener over a LIFO stack; only the topmost layer is consulted per press). `{panels, dismiss, trigger?}`; a press on a registered `trigger` dismisses and claims the pointer gesture so a close-press cannot immediately reopen the overlay. Returns an unregister function
|
|
192
|
+
- `registerOverlayTrigger(triggerEl, opener)` -- declarative invoker contract: the framework owns the trigger's click handler and open/closed state, sets `aria-expanded` (and `aria-controls`), and wires the gesture-claim. Backs the drawer toggle and the shell hamburger; double-registering the same element is a hard error
|
|
193
|
+
|
|
194
|
+
### State (`tinymoon/state`)
|
|
195
|
+
|
|
196
|
+
The L2 state story: build the DOM once and mutate it in place. There is no declarative render layer by design -- these helpers keep that mutation centralized.
|
|
197
|
+
|
|
198
|
+
- `createStore(initial)` -- reactive key/value store; the returned store exposes `get`, `set`, `update`, `subscribe(key, cb)` (pass `null` for any-change), `select(fn)`, and `snapshot()`
|
|
199
|
+
- `bind(store, key, widget)` -- wire a store key to a widget's `.set(v)`; syncs once, then forwards every change; returns an unbind function
|
|
200
|
+
- `reconcile(container, items, keyFn, hooks)` -- keyed child reconciler: new keys `create`, kept keys reuse their node and `update`, gone keys `remove` then detach; returns the ordered node array
|
|
201
|
+
|
|
202
|
+
### Widgets (`tinymoon/widgets`)
|
|
203
|
+
|
|
204
|
+
The data-display story: badges, stats, tables, trees, and charts. Optional -- linked alongside `widgets.css` only by apps that render data. Each widget is also importable by its own subpath (`tinymoon/table`, `tinymoon/tree`, ...).
|
|
205
|
+
|
|
206
|
+
- `badge(text, variant?)` -- one-shot status chip (bare `<span>`, not a component)
|
|
207
|
+
- `createStat(opts)` -- single metric tile with an optional trend delta
|
|
208
|
+
- `renderStats(items)` -- a row of stat tiles from an array
|
|
209
|
+
- `createTable(opts)` -- keyboard-navigable data table with client-side column sort and `rowClass`/`cellClass` hooks
|
|
210
|
+
- `createVirtualList(opts)` -- fixed-height windowed list for large datasets
|
|
211
|
+
- `createTree(opts)` -- APG-pattern tree view with keyboard navigation
|
|
212
|
+
- `createFilterBar(opts)` -- slot container for filter controls
|
|
213
|
+
- `createChips(opts)` -- removable filter chips
|
|
214
|
+
- `createLoadMore(opts)` -- transport-agnostic cursor pagination control
|
|
215
|
+
- `createBreadcrumbs(opts)` -- router-agnostic breadcrumb trail
|
|
216
|
+
- `createSparkline(opts)` -- inline token-colored SVG sparkline
|
|
217
|
+
- `createChartContainer(opts)` -- renderer-agnostic sized chart shell with token access
|
|
218
|
+
- `createFeed(opts)` -- presentation-only live feed with a capped item buffer
|
|
219
|
+
|
|
220
|
+
## Identity
|
|
221
|
+
|
|
222
|
+
The visual identity is enforced by constraint, not offered as options:
|
|
223
|
+
|
|
224
|
+
- **Sharp corners everywhere** -- `border-radius` is 0; no exceptions.
|
|
225
|
+
- **Three-font system** -- brand headings (Space Grotesk), UI body (IBM Plex Sans), monospace for data (IBM Plex Mono). All vendored, no network loads.
|
|
226
|
+
- **Glow language** -- accent glows on active cards, focused inputs, and modals. Restrained and consistent.
|
|
227
|
+
- **Grain** -- a subtle SVG noise overlay on the background.
|
|
228
|
+
- **Motion timing** -- all transitions are 100--180ms one-shot eases. The spinner is the only continuous animation.
|
|
229
|
+
- **No native browser controls** -- checkbox, radio, select, file input, and date picker are all custom-drawn with hidden native elements for form participation and accessibility.
|
|
230
|
+
- **AA contrast** -- every text-on-background token pair passes WCAG AA 4.5:1. Enforced by CI.
|
|
231
|
+
- **Reduced motion** -- `prefers-reduced-motion: reduce` suppresses all animation and transition durations to near-zero. Enforced by E2E tests.
|
|
232
|
+
|
|
233
|
+
Design tokens let you re-theme and re-accent; they do not let you opt out of the identity.
|
|
234
|
+
|
|
235
|
+
## Size
|
|
236
|
+
|
|
237
|
+
No overhead -- as a number, not a vibe. Shipped CSS, JS, and fonts have hard byte ceilings enforced by CI; nothing bloats quietly.
|
|
238
|
+
|
|
239
|
+
- **Budgets are per-tier.** Every shipped file belongs to exactly one budgeted tier, each with its own hard ceiling. New capability tiers land as their own tiers, each carrying its own budget -- never charged against core. The full tier set: **JS** -- `core` (the original frozen module set), `controls-js` (new-generation controls: time picker, combobox, multi-select, accordion), `state-js` (store + reconciler), `widgets-js` (data-display widgets), `chrome-js` (shell-and-chrome modules: the Phase 6A view factory, drawer, tab panels, icon button, and preset grid, plus the Phase 6B async-state blocks, lazy mounting, keyboard shortcuts, and command palette, plus the light-dismiss engine and overlay-trigger invoker), and `dev` (dev-only modules, classified but uncounted); **CSS** -- `css` (the four base sheets) and `widgets-css` (the optional data-display sheet); plus **`fonts`** (the four vendored woff2 files). New-generation modules budget in their own tier even when they are still exported from the core barrel.
|
|
240
|
+
- **The core tier's existing APIs are frozen against breaking change.** What core exports today keeps its shape and behavior.
|
|
241
|
+
- **Additive extensions are permitted.** New primitives and options can join a tier as long as they stay under its ceiling.
|
|
242
|
+
- **The core ceiling is never raised.** Growth happens in new tiers, not by loosening core. Raising any ceiling is a deliberate reviewed decision, never a side effect.
|
|
243
|
+
|
|
244
|
+
## Conformance checker
|
|
245
|
+
|
|
246
|
+
`tinymoon check` scans `.html`, `.css`, and `.js` files and enforces the framework's non-negotiables as hard errors:
|
|
247
|
+
|
|
248
|
+
- **external-url** -- no external resource loads (no `http://`, `https://`, or `//host` URLs fetched into the page from HTML, CSS, or JS; form `action`/`formaction` count as loads). Plain `<a>`/`<area>` hyperlink navigations are legal
|
|
249
|
+
- **native-control** -- no native `<select>`, `<dialog>`, `<textarea>`, or `<input>` of a type that has a shipped replacement factory. A bare `<input>` with no `type` also fires (a typeless input defaults to `text`). Every banned control maps to a framework primitive:
|
|
250
|
+
|
|
251
|
+
| Banned native | Replacement factory |
|
|
252
|
+
| --- | --- |
|
|
253
|
+
| `<input type=text\|password\|email\|url\|search\|tel>` | `createInput` |
|
|
254
|
+
| `<input>` (typeless -- defaults to text) | `createInput` |
|
|
255
|
+
| `<input type=number>` | `createNumber` |
|
|
256
|
+
| `<input type=range>` | `createSlider` |
|
|
257
|
+
| `<input type=time>` | `createTimePicker` |
|
|
258
|
+
| `<input type=date>` | `createDatePicker` |
|
|
259
|
+
| `<input type=checkbox>` | `createCheckbox` |
|
|
260
|
+
| `<input type=radio>` | `createRadio` |
|
|
261
|
+
| `<input type=file>` | `createFileInput` |
|
|
262
|
+
| `<textarea>` | `createTextarea` |
|
|
263
|
+
| `<select>` | `createSelect` |
|
|
264
|
+
| `<dialog>` | `openModal` |
|
|
265
|
+
|
|
266
|
+
`type="hidden"` stays legal (it renders nothing, so it has no identity surface -- the datepicker/timepicker/combobox carry their value in one). `type="color"` also stays legal for now: there is no replacement factory yet, and a ban may never ship without its replacement (when a color primitive ships, `color` joins the ban). tinymoon's own modules that legitimately create these natives (e.g. `openModal` builds on a native `<dialog>`; `createInput` wraps a visible native `<input>`) are exempt via the framework-own allowance, keyed on location so a consumer's `<dialog>` or bare `<input>` always fires. JS creation is caught for element tags and explicit `type` literals; a bare `el("input")`/`createElement("input")` with no literal type assignment is a known JS bypass (the tree-sitter rewrite closes it)
|
|
267
|
+
- **title-attr** -- no `title=` attributes (use the tooltip primitive)
|
|
268
|
+
- **border-radius** -- no `border-radius` other than `0`/`0px`
|
|
269
|
+
- **raw-color** -- no color literals outside `:root`/`html[data-theme]` token definitions
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
uvx tinymoon check --dir ./web
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
One line per violation, exit non-zero on any finding. No `--skip`, `--ignore`, or warning mode. Exempt specific URLs by adding them to `tinymoon-allowlist.txt` at the scanned directory root.
|
|
276
|
+
|
|
277
|
+
### Vendored third-party code
|
|
278
|
+
|
|
279
|
+
Sometimes you must vendor a third-party file verbatim -- a foreign stylesheet or script you did not write and cannot rewrite to obey the charter (it may use rounded corners, raw colors, or a native control). Rewriting it would fork it; leaving it in the tree would fail the checker.
|
|
280
|
+
|
|
281
|
+
Put such files in a directory named `third_party/` (the fixed conventional name -- there is no flag) and pin each one in a manifest at `third_party/PROVENANCE.toml` that sits beside them:
|
|
282
|
+
|
|
283
|
+
```toml
|
|
284
|
+
[[file]]
|
|
285
|
+
path = "foreign-widget.css" # relative to third_party/
|
|
286
|
+
origin = "https://example.com/widget@2.1" # a URL or name; informational
|
|
287
|
+
sha256 = "a6d96b3a999b17010ce541dcf9c427648e9e929f5e5c89b96047e6c4c46a294f"
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
A quarantined file is exempt from all five rules **if and only if** it is pinned and its bytes still hash to the recorded `sha256`. The exemption is earned by provenance: the hash proves the bytes are unmodified third-party code. First-party code cannot hide here -- the moment you edit a quarantined file to make it yours, the hash stops matching and the check fails.
|
|
291
|
+
|
|
292
|
+
Every other state is a hard `unpinned-vendor` error (no bypass): a file present with no manifest entry (or no manifest at all), a manifest entry whose file is missing, a hash mismatch, or an entry whose path is absolute or escapes the directory with `..`. A quarantine directory nested anywhere inside the scanned tree is honored as long as its own `PROVENANCE.toml` sits beside it, so scanning a repo root and scanning a sub-tree agree.
|
|
293
|
+
|
|
294
|
+
Generate the `sha256` for an entry with coreutils:
|
|
295
|
+
|
|
296
|
+
```
|
|
297
|
+
sha256sum third_party/foreign-widget.css
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
The gallery is the mechanism's own first consumer: its Embed route's garish foreign CSS lives in `gallery/third_party/foreign-widget.css`, pinned by `gallery/third_party/PROVENANCE.toml`, and is loaded into a shadow root where its styling is sealed.
|
|
301
|
+
|
|
302
|
+
### Conformance from non-Python CI
|
|
303
|
+
|
|
304
|
+
The rules live in one place -- the Python checker. To let a reimplementation (a Go server, a CI job in any language) test itself instead of re-deriving the rules by hand and drifting, tinymoon ships two portable, machine-readable artifacts inside the packaged assets (wheel, npm tarball, and Go embed all carry them):
|
|
305
|
+
|
|
306
|
+
- **`assets/conformance/rules.json`** -- the rule data: every rule id, the banned input types and native control tags, the skip dirs, the allowlist and quarantine conventions, and the load-vs-navigation attribute-semantics table. Generated straight from the checker's own constants, so it can never drift from the enforced rules.
|
|
307
|
+
- **`assets/conformance/corpus/`** -- a byte-for-byte copy of the checker's own fixtures (`clean/`, `violations/`, `quarantine/`), paired with **`assets/conformance/expectations.json`**, the exact expected findings (per scan root, per file: ordered `[line, rule-id]` pairs; clean files map to `[]`).
|
|
308
|
+
|
|
309
|
+
A reimplementation runs its own rule over the corpus and asserts its findings match `expectations.json` for that rule id. The Go side does exactly this as a worked example: [`tinymoon_conformance_test.go`](tinymoon_conformance_test.go) loads the artifacts from the embedded FS, implements the `title-attr` rule natively, runs it over the corpus, and requires an exact match. It is a demonstration of the consumption pattern -- deliberately one tiny rule, not a full Go checker.
|
|
310
|
+
|
|
311
|
+
For **full scanning** from any CI -- not just conformance-testing a reimplementation -- invoke the shipped CLI; it is the single source of truth and needs no local Python setup:
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
uvx tinymoon check --dir <dir>
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
The corpus is fixture data with deliberate violations, so it is not part of the identity surface: the checker skips its own packaged corpus when self-scanning `assets`, and scans it normally only when it is the explicit target. Regenerate the artifacts after changing the checker or the fixtures with `scripts/gen_conformance_json.py`.
|
|
318
|
+
|
|
319
|
+
## App model
|
|
320
|
+
|
|
321
|
+
**Copy system.** `registerCopyable(el, fn)` marks any element as copyable -- clicking it copies the value returned by `fn()` to the clipboard, with a toast confirmation. The `copyButton` helper wires a standalone copy button. `getCopyData(el)` retrieves registered copy data programmatically.
|
|
322
|
+
|
|
323
|
+
**Selection model.** Elements declare tooltips via `data-tooltip` (plain text) and hovercards via `data-hovercard` (markdown with bold, code, links). The framework manages hover intent, positioning, and the hover bridge automatically.
|
|
324
|
+
|
|
325
|
+
**View contract.** Routes map to view objects `{root, built, build(), refresh(), setSub?}`. The shell's router owns the lifecycle: `build()` constructs the DOM once (idempotent), `refresh()` runs on every visit, `setSub(sub)` receives deep-link tails. A string value instead of a view factory activates the content-first path -- plain HTML styled automatically with zero framework classes.
|
|
326
|
+
|
|
327
|
+
## Gallery
|
|
328
|
+
|
|
329
|
+
The gallery is a complete tinymoon app that documents every design token and primitive. Serve the repo root with a static server and open `/gallery/`:
|
|
330
|
+
|
|
331
|
+
```
|
|
332
|
+
python3 -m http.server
|
|
333
|
+
# open http://localhost:8000/gallery/
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Development
|
|
337
|
+
|
|
338
|
+
CI does not run until release, so the local suite is the quality gate between work phases. Run `scripts/checkpoint.sh` at every phase boundary -- it runs pytest, `npm test` (JS syntax gate + vitest), the Playwright e2e suite, `go test`, and the changelog check in order, stops at the first failure, and prints a PASS/FAIL summary. A green checkpoint is the bar for closing a phase.
|
|
339
|
+
|
|
340
|
+
```
|
|
341
|
+
./scripts/checkpoint.sh
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Before a release, also run the opt-in stress gate. It runs the interaction-heavy e2e specs (chrome, light-dismiss, tooltip-hovercard, datepicker, forms, ctxmenu) under a load profile -- `--repeat-each=10 --workers=6` -- which exercises timing-sensitive overlay behavior (close/reopen, focus, dismissal ordering) and surfaces load-dependent races that unloaded single-pass runs miss. Nothing invokes it automatically; it is an explicit pre-release step.
|
|
345
|
+
|
|
346
|
+
```
|
|
347
|
+
./scripts/checkpoint.sh --stress
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## License
|
|
351
|
+
|
|
352
|
+
MIT
|