Skip to content

feat: add djust-theming standalone PyPI package#376

Open
johnrtipton wants to merge 2 commits intofeat/async-pending-loading-statefrom
feat/theming-package
Open

feat: add djust-theming standalone PyPI package#376
johnrtipton wants to merge 2 commits intofeat/async-pending-loading-statefrom
feat/theming-package

Conversation

@johnrtipton
Copy link
Contributor

Summary

Adds djust-theming as a first-party standalone PyPI package under packages/djust-theming/.

Provides CSS design tokens, utility classes, and a theme-switcher JS module for djust applications that want a consistent baseline style without committing to a specific CSS framework.

Contents

  • packages/djust-theming/ — Python package with Django app
    • static/djust_theming/css/theme.css — CSS custom properties (design tokens)
    • static/djust_theming/css/components.css — base component styles
    • static/djust_theming/css/utilities.css — utility classes
    • static/djust_theming/js/theme-switcher.js — light/dark mode toggle
  • .github/workflows/publish-djust-theming.yml — PyPI publish workflow

Usage

INSTALLED_APPS = [
    ...
    "djust_theming",
]
{% load static %}
<link rel="stylesheet" href="{% static 'djust_theming/css/theme.css' %}">

🤖 Generated with Claude Code

johnrtipton and others added 2 commits February 24, 2026 10:58
…#364)

* feat: rename data-dj-id to dj-id, remove implicit id= key fallback, add dj-key

Breaking changes for v1.0:

1. Rename VDOM tracking attribute data-dj-id → dj-id for consistency with
   all other dj- prefixed attributes (dj-view, dj-click, dj-model, etc.).
   - parser.rs stamps dj-id instead of data-dj-id
   - diff.rs syncs and ignores dj-id (not data-dj-id) when diffing attrs
   - All querySelector calls updated: [data-dj-id=] → [dj-id=]
   - System check T011 warns when templates contain data-dj-id attributes

2. Remove implicit id= fallback for keyed VDOM diffing. Developers using
   id= on elements will no longer have those silently used as diff keys.
   - dj-key and data-key both work as explicit opt-in keyed diffing
   - parser.rs: removed id_attr extraction and .or(id_attr) fallback
   - Tests updated: id-as-key tests now assert key == None

Also:
- Add docs/guides/lists.md with dj-key keyed diffing guide
- Update MIGRATION.md with both breaking changes and migration checklist

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add SSE fallback transport for corporate proxy environments

When WebSocket connections are blocked by corporate proxies or enterprise
firewalls, djust now automatically falls back to Server-Sent Events (SSE).

Architecture:
- Server→Client: EventSource (GET /djust/sse/<session_id>/)
- Client→Server: HTTP POST (/djust/sse/<session_id>/event/)
- Transport negotiation is automatic: WS tried first, SSE on failure

New files:
- python/djust/sse.py: DjustSSEStreamView, DjustSSEEventView, SSESession,
  shared mount/event dispatch helpers, sse_urlpatterns
- python/djust/static/djust/src/03b-sse.js: LiveViewSSE class with same
  interface as LiveViewWebSocket for transparent transport switching
- docs/sse-transport.md: setup guide, feature limitations table, security notes
- python/tests/test_sse.py: 20 Python tests (all passing)
- tests/js/sse.test.js: 17 JS tests (all passing)

Modified files:
- 03-websocket.js: add onTransportFailed callback hook (fires instead of
  showing error overlay when SSE transport is available)
- 14-init.js: _switchToSSETransport() helper + SSE fallback wiring in djustInit
- demo_project/urls.py: register sse_urlpatterns under /djust/
- CHANGELOG.md, README.md: document feature, mark roadmap item complete

Feature limitations vs WebSocket (documented in docs/sse-transport.md):
no binary uploads, no presence tracking, no actors, no MessagePack

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add TypeScript definitions and Python type stubs for public API

Adds `djust.d.ts` — a comprehensive ambient TypeScript declaration file
shipped with the Python package at `static/djust/djust.d.ts`. Covers
the full `window.djust` public API surface:

- `DjustHook` lifecycle interface (mounted, beforeUpdate, updated,
  destroyed, disconnected, reconnected)
- `DjustHookContext` (this.el, this.viewName, this.pushEvent,
  this.handleEvent)
- `LiveViewWebSocket` and `LiveViewSSE` transport classes
- Navigation helpers (DjustNavigation, handleNavigation, resolveViewPath)
- dj-model binding (bindModelElements)
- Streaming API (DjustStreamMessage, DjustStreamOp, DjustStreamInfo)
- Upload progress types (DjustUploadEntry, DjustUploadConfig,
  DjustUploadProgressEventDetail, djust:upload:progress custom event)
- `declare global` Window extension with djust, DjustHooks, djustDebug

Also adds `python/djust/_rust.pyi` — PEP 561 type stubs for the PyO3
Rust extension module, enabling IDE autocomplete and mypy type checking
for all Rust-injected functions and classes.

Includes 27 tests in `python/tests/test_typescript_definitions.py`
validating file structure, interface completeness, nullable types,
optional parameters, and balanced braces.

README roadmap and CONTRIBUTING updated to reflect completion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: mark data.type nav fallback for deprecation and update CHANGELOG for #292

- Resolve stash conflict in 03-websocket.js (dj-id vs data-dj-id log messages)
- Add TODO deprecation comment in handleNavigation for data.type fallback
  (data.action || data.type shim — remove in next minor release)
- Add CHANGELOG entries for:
  - Deprecated: data.type fallback in handleNavigation (#318 backwards compat)
  - Fixed: silent str() coercion for non-serializable LiveView state (#292)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: update djust.d.ts version to 0.3.4

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: resolve rebase hook failures after rebasing onto feat/async-pending-loading-state

- Guard sseAvailable with typeof EventSource check to prevent crash in jsdom
  test environments when DJUST_USE_WEBSOCKET=false (dj-poll, http_only_mode tests)
- Fix collapsible_if clippy lint in djust_vdom parser.rs (dj-key extraction)
- Update JS tests to use dj-id instead of data-dj-id (attr rename from e8e83eb)
- Apply cargo fmt to renderer.rs and parser.rs
- Apply ruff formatting to checks.py, sse.py, and test files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: pass venv mypy and PYTHONPATH in TestMypyIntegration tests

The tests called bare 'mypy' without PYTHONPATH, so mypy couldn't find
the djust package (import-not-found error). Now uses _MYPY_EXE (venv's
mypy) and injects _DJUST_PYTHON_PATH into PYTHONPATH at test runtime.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: update tests for pre-existing base branch failures

- test_template_conditions: render_template() strips <!--dj-if--> placeholders
  by design (VDOM internal detail hidden from public API). Update expectations
  from "<!--dj-if-->" to "" for standalone render_template() calls.
- test_liveview_type_stubs: add mount, get_context_data, handle_tick, get_state
  to live_view.pyi stub (were missing, tests expected them)
- test_state_backend: update test_redis_vdom_preservation to use dj-id
  instead of data-dj-id (attr rename from e8e83eb)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Extracts theming utilities from the demo project into a standalone
`packages/djust-theming/` sub-package publishable to PyPI as
`djust-theming==0.3.0`.

- Pure-Python Django app with no dependency on djust core
- Bundles theme.css (design tokens, dark/light mode), components.css,
  utilities.css, and theme-switcher.js as Django static files
- Install via `pip install djust-theming`, add `djust_theming` to
  INSTALLED_APPS, then use `{% static 'djust_theming/css/theme.css' %}`
- GitHub Actions workflow `.github/workflows/publish-djust-theming.yml`
  with trusted publishing to PyPI (environment: pypi-djust-theming)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@johnrtipton johnrtipton force-pushed the feat/async-pending-loading-state branch from b2369d1 to df1de61 Compare February 24, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant