A reusable FastHTML component for Sortable.js-enhanced ordered queue panels with drag-and-drop reorder, keyboard navigation, and HTMX-powered mutations.
Project description
cjm-fasthtml-sortable-queue
Install
pip install cjm_fasthtml_sortable_queue
Project Structure
nbs/
├── config.ipynb # Configuration dataclass for sortable queue instances.
├── handlers.ipynb # Tier 1 handler functions for queue reorder, remove, and clear operations.
├── html_ids.ipynb # HTML element ID generators for sortable queue components.
├── keyboard.ipynb # Self-contained keyboard system for sortable queue navigation and actions.
├── models.ipynb # URL bundle and reorder utility functions for sortable queues.
├── rendering.ipynb # Queue panel and item rendering with callback-based custom content.
├── router.ipynb # Tier 2 convenience router with auto-wired reorder, remove, and clear endpoints.
└── sortable_js.ipynb # Sortable.js CDN loading and initialization script generation.
Total: 8 notebooks
Module Dependencies
graph LR
config[config<br/>config]
handlers[handlers<br/>handlers]
html_ids[html_ids<br/>html_ids]
keyboard[keyboard<br/>keyboard]
models[models<br/>models]
rendering[rendering<br/>rendering]
router[router<br/>router]
sortable_js[sortable_js<br/>sortable_js]
handlers --> config
handlers --> models
handlers --> rendering
handlers --> html_ids
keyboard --> models
keyboard --> config
keyboard --> html_ids
rendering --> config
rendering --> html_ids
rendering --> models
router --> models
router --> handlers
router --> config
router --> html_ids
14 cross-module dependencies detected
CLI Reference
No CLI commands found in this project.
Module Overview
Detailed documentation for each module in the project:
config (config.ipynb)
Configuration dataclass for sortable queue instances.
Import
from cjm_fasthtml_sortable_queue.config import (
SortableQueueConfig,
get_item_key
)
Functions
def get_item_key(
config: SortableQueueConfig, # Queue configuration
item: dict, # Queue item dict
) -> str: # Unique key string for the item
"Extract the unique key from a queue item using the config's key_fn or key_field."
Classes
@dataclass
class SortableQueueConfig:
"Configuration for a sortable queue instance."
prefix: str # HTML ID prefix (e.g., "sq", "sd", "tss")
key_field: str = 'id' # Field name to extract item key (simple case)
key_fn: Optional[Callable[[dict], str]] # Custom key extraction (overrides key_field if set)
item_class: str = 'queue-item' # CSS class for queue items (keyboard selector + styling target)
handle_class: str = 'drag-handle' # CSS class for Sortable.js drag handle
animation_ms: int = 150 # Sortable.js drag animation duration in milliseconds
queue_title: str = 'Selected' # Header title text
handlers (handlers.ipynb)
Tier 1 handler functions for queue reorder, remove, and clear operations.
Import
from cjm_fasthtml_sortable_queue.handlers import (
handle_reorder,
handle_reorder_by_direction,
handle_remove,
handle_clear
)
Functions
def handle_reorder(
config: SortableQueueConfig, # Queue configuration
ids: SortableQueueHtmlIds, # HTML ID generators
urls: SortableQueueUrls, # URL endpoints
items: List[dict], # Current item list
new_key_order: List[str], # Keys in new order (from form_data.getlist("item"))
render_content: Callable[[dict, int], Any], # Custom content callback
**render_kwargs, # Additional kwargs passed to render_sortable_queue
) -> tuple: # (reordered_items, rendered_panel)
"Reorder items by key order and return the updated list and rendered panel."
def handle_reorder_by_direction(
config: SortableQueueConfig, # Queue configuration
ids: SortableQueueHtmlIds, # HTML ID generators
urls: SortableQueueUrls, # URL endpoints
items: List[dict], # Current item list
item_key: str, # Key of item to move
direction: str, # "up" or "down"
render_content: Callable[[dict, int], Any], # Custom content callback
**render_kwargs, # Additional kwargs passed to render_sortable_queue
) -> tuple: # (reordered_items, rendered_panel)
"Move an item up or down and return the updated list and rendered panel."
def handle_remove(
config: SortableQueueConfig, # Queue configuration
ids: SortableQueueHtmlIds, # HTML ID generators
urls: SortableQueueUrls, # URL endpoints
items: List[dict], # Current item list
remove_key: str, # Key of item to remove
render_content: Callable[[dict, int], Any], # Custom content callback
**render_kwargs, # Additional kwargs passed to render_sortable_queue
) -> tuple: # (updated_items, rendered_panel)
"Remove an item by key and return the updated list and rendered panel."
def handle_clear(
config: SortableQueueConfig, # Queue configuration
ids: SortableQueueHtmlIds, # HTML ID generators
urls: SortableQueueUrls, # URL endpoints
render_content: Callable[[dict, int], Any], # Custom content callback
**render_kwargs, # Additional kwargs passed to render_sortable_queue
) -> tuple: # (empty_list, rendered_panel)
"Clear all items and return an empty list and rendered panel."
html_ids (html_ids.ipynb)
HTML element ID generators for sortable queue components.
Import
from cjm_fasthtml_sortable_queue.html_ids import (
SortableQueueHtmlIds
)
Functions
def _safe_id(
value: str, # Raw value to sanitize
) -> str: # HTML-safe ID fragment
"Replace non-alphanumeric characters with hyphens for use in HTML IDs."
Classes
@dataclass
class SortableQueueHtmlIds:
"HTML element ID generators for a sortable queue instance."
prefix: str # Instance prefix (e.g., "sq", "sd", "tss")
def container(self) -> str: # Outer container div ID
"""Queue panel container."""
return f"{self.prefix}-queue-container"
@property
def list(self) -> str: # Sortable <ul> ID
"Queue panel container."
def list(self) -> str: # Sortable <ul> ID
"""Sortable queue list element."""
return f"{self.prefix}-queue-list"
@property
def empty(self) -> str: # Empty state div ID
"Sortable queue list element."
def empty(self) -> str: # Empty state div ID
"""Empty state placeholder."""
return f"{self.prefix}-queue-empty"
@property
def header(self) -> str: # Header section ID
"Empty state placeholder."
def header(self) -> str: # Header section ID
"""Queue header section."""
return f"{self.prefix}-queue-header"
@property
def remove_btn(self) -> str: # Hidden keyboard remove button ID
"Queue header section."
def remove_btn(self) -> str: # Hidden keyboard remove button ID
"""Hidden button for keyboard-triggered remove."""
return f"{self.prefix}-queue-remove-btn"
@property
def reorder_up_btn(self) -> str: # Hidden keyboard reorder-up button ID
"Hidden button for keyboard-triggered remove."
def reorder_up_btn(self) -> str: # Hidden keyboard reorder-up button ID
"""Hidden button for keyboard-triggered reorder up."""
return f"{self.prefix}-queue-reorder-up-btn"
@property
def reorder_down_btn(self) -> str: # Hidden keyboard reorder-down button ID
"Hidden button for keyboard-triggered reorder up."
def reorder_down_btn(self) -> str: # Hidden keyboard reorder-down button ID
"""Hidden button for keyboard-triggered reorder down."""
return f"{self.prefix}-queue-reorder-down-btn"
@property
def system_id(self) -> str: # Keyboard system ID for hierarchy wiring
"Hidden button for keyboard-triggered reorder down."
def system_id(self) -> str: # Keyboard system ID for hierarchy wiring
"Keyboard system identifier for coordinator registration."
def item(
"Per-item HTML ID."
def as_selector(
self,
html_id: str, # An HTML ID string
) -> str: # CSS selector string
"Convert an HTML ID to a CSS selector."
keyboard (keyboard.ipynb)
Self-contained keyboard system for sortable queue navigation and actions.
Import
from cjm_fasthtml_sortable_queue.keyboard import (
create_queue_keyboard_system
)
Functions
def create_queue_keyboard_system(
config: SortableQueueConfig, # Queue configuration
ids: SortableQueueHtmlIds, # HTML ID generators
urls: SortableQueueUrls, # URL endpoints for HTMX actions
zone_focus_classes: tuple = (str(ring(0)),), # CSS classes when queue zone is active
item_focus_classes: Optional[tuple] = None, # CSS classes on focused item (default: bg-base-300)
data_attributes: tuple = (), # Data attributes to extract (e.g., ("record-id", "provider-id"))
on_focus_change: Optional[str] = None, # JS callback on item focus change
hidden_input_prefix: Optional[str] = None, # Prefix for hidden state inputs
system_id: Optional[str] = None, # Keyboard system ID (auto-generated from ids.system_id if not set)
show_hints: bool = False, # Show keyboard hints UI
) -> KeyboardSystem: # Complete rendered keyboard system
"""
Create a self-contained keyboard system for the sortable queue.
Returns a rendered KeyboardSystem with a single FocusZone (LinearVertical
navigation) and built-in actions for Delete/Backspace remove and
Shift+Arrow reorder. Works standalone or as a child in a hierarchy
via `coord.setParent(system_id, parent_id)`.
"""
Variables
_DEFAULT_ITEM_FOCUS_CLASSES
models (models.ipynb)
URL bundle and reorder utility functions for sortable queues.
Import
from cjm_fasthtml_sortable_queue.models import (
SortableQueueUrls,
reorder_by_keys,
reorder_by_direction
)
Functions
def reorder_by_keys(
items: List[dict], # Current item list
new_key_order: List[str], # Keys in desired order (from Sortable.js form data)
key_fn: Callable[[dict], str], # Function to extract key from item
) -> List[dict]: # Reordered item list
"Reorder items to match the key order from Sortable.js form data."
def reorder_by_direction(
items: List[dict], # Current item list
item_key: str, # Key of item to move
direction: str, # "up" or "down"
key_fn: Callable[[dict], str], # Function to extract key from item
) -> List[dict]: # Reordered item list
"Move an item up or down by swapping with its neighbor."
Classes
@dataclass
class SortableQueueUrls:
"URL endpoints for sortable queue HTMX operations."
reorder: str # POST — Sortable.js drag-end reorder
remove: str # POST — Remove item from queue
clear: str # POST — Clear all items
rendering (rendering.ipynb)
Queue panel and item rendering with callback-based custom content.
Import
from cjm_fasthtml_sortable_queue.rendering import (
render_queue_item,
render_sortable_queue
)
Functions
def render_queue_item(
config: SortableQueueConfig, # Queue configuration
ids: SortableQueueHtmlIds, # HTML ID generators
urls: SortableQueueUrls, # URL endpoints
item: dict, # Queue item data
index: int, # 0-based position in queue
render_content: Callable[[dict, int], Any], # Callback for custom item content
extra_attrs: Optional[dict] = None, # Additional HTML attributes per item
) -> Any: # Li element
"Render a single queue item with drag handle, position, custom content, and remove button."
def _render_default_empty() -> Any: # Empty state element
"Default empty state when no items are in the queue."
def render_sortable_queue(
config: SortableQueueConfig, # Queue configuration
ids: SortableQueueHtmlIds, # HTML ID generators
urls: SortableQueueUrls, # URL endpoints
queue_items: List[dict], # Ordered list of queue item dicts
render_content: Callable[[dict, int], Any], # Callback for custom item content
render_empty: Optional[Callable[[], Any]] = None, # Custom empty state (default provided)
render_header_actions: Optional[Callable[[List[dict], SortableQueueUrls], Any]] = None, # Custom header actions
render_footer: Optional[Callable[[List[dict]], Any]] = None, # Optional footer content
extra_item_attrs: Optional[Callable[[dict], dict]] = None, # Additional data-* attributes per item
container_classes: tuple = (), # Additional classes on container div
) -> Any: # Queue panel element
"Render the complete sortable queue panel."
router (router.ipynb)
Tier 2 convenience router with auto-wired reorder, remove, and clear endpoints.
Import
from cjm_fasthtml_sortable_queue.router import (
init_sortable_queue_router
)
Functions
def init_sortable_queue_router(
config: SortableQueueConfig, # Queue configuration
get_items: Callable[[str], List[dict]], # (session_id) -> current items
set_items: Callable[[str, List[dict]], None], # (session_id, items) -> persist
render_content: Callable[[dict, int], Any], # Custom content callback
on_mutate: Optional[Callable[[str, List[dict], str], tuple]] = None, # (mutation_type, items, sess) -> OOB elements
prefix: str = "/queue", # Route prefix
**render_kwargs, # Additional kwargs passed to render_sortable_queue
) -> Tuple[APIRouter, SortableQueueUrls]: # (router, urls) tuple
"""
Initialize a router with reorder, remove, and clear endpoints.
The `on_mutate` callback receives the mutation type ("reorder", "remove",
"clear"), the updated items list, and the session ID. It should return a
tuple of OOB elements to append to the response, or an empty tuple.
"""
sortable_js (sortable_js.ipynb)
Sortable.js CDN loading and initialization script generation.
Import
from cjm_fasthtml_sortable_queue.sortable_js import (
SORTABLE_JS_CDN,
sortable_js_headers,
generate_sortable_init_script
)
Functions
def sortable_js_headers() -> tuple: # Tuple of Script elements for app headers
"CDN script tag for Sortable.js, suitable for FastHTML app headers."
def generate_sortable_init_script(
handle_class: str = "drag-handle", # CSS class for drag handle elements
animation_ms: int = 150, # Drag animation duration in milliseconds
) -> Script: # Script element with Sortable.js initialization
"""
Generate htmx.onLoad script that initializes Sortable.js on `.sortable` elements.
Includes the disable-on-drag/re-enable-on-swap pattern to prevent
double-firing during HTMX response processing.
"""
Variables
SORTABLE_JS_CDN = 'https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js'
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cjm_fasthtml_sortable_queue-0.0.7.tar.gz.
File metadata
- Download URL: cjm_fasthtml_sortable_queue-0.0.7.tar.gz
- Upload date:
- Size: 22.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9fd7a849b07c5e4cd794ba7643dcf0d0f31014b07e66c8d5e98ce4449a83db04
|
|
| MD5 |
8c511bf05b182b0039d86f015d29bd89
|
|
| BLAKE2b-256 |
7c26cbac63da70b5188cd8390f30d3462fe4b6b0d5ed0c14b759882a378c955d
|
File details
Details for the file cjm_fasthtml_sortable_queue-0.0.7-py3-none-any.whl.
File metadata
- Download URL: cjm_fasthtml_sortable_queue-0.0.7-py3-none-any.whl
- Upload date:
- Size: 21.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a5dd5800063149e747a08c6fc1cfbe337c6ad922b9909424c7579a1d30d5167
|
|
| MD5 |
d4916ef259d89c50a6f2cea1d506a536
|
|
| BLAKE2b-256 |
fee3c02bd32382e90be3c934f0585fc9cc5d94359785071cfc719ea648f4d36b
|