cjm-fasthtml-token-selector 0.0.1__py3-none-any.whl
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.
- cjm_fasthtml_token_selector/__init__.py +1 -0
- cjm_fasthtml_token_selector/_modidx.py +104 -0
- cjm_fasthtml_token_selector/components/__init__.py +0 -0
- cjm_fasthtml_token_selector/components/inputs.py +46 -0
- cjm_fasthtml_token_selector/components/tokens.py +217 -0
- cjm_fasthtml_token_selector/core/__init__.py +0 -0
- cjm_fasthtml_token_selector/core/config.py +57 -0
- cjm_fasthtml_token_selector/core/constants.py +50 -0
- cjm_fasthtml_token_selector/core/html_ids.py +51 -0
- cjm_fasthtml_token_selector/core/models.py +37 -0
- cjm_fasthtml_token_selector/helpers/__init__.py +0 -0
- cjm_fasthtml_token_selector/helpers/tokenizer.py +76 -0
- cjm_fasthtml_token_selector/js/__init__.py +0 -0
- cjm_fasthtml_token_selector/js/core.py +181 -0
- cjm_fasthtml_token_selector/js/display.py +146 -0
- cjm_fasthtml_token_selector/js/navigation.py +228 -0
- cjm_fasthtml_token_selector/js/repeat.py +119 -0
- cjm_fasthtml_token_selector/keyboard/__init__.py +0 -0
- cjm_fasthtml_token_selector/keyboard/actions.py +157 -0
- cjm_fasthtml_token_selector-0.0.1.dist-info/METADATA +760 -0
- cjm_fasthtml_token_selector-0.0.1.dist-info/RECORD +31 -0
- cjm_fasthtml_token_selector-0.0.1.dist-info/WHEEL +5 -0
- cjm_fasthtml_token_selector-0.0.1.dist-info/entry_points.txt +2 -0
- cjm_fasthtml_token_selector-0.0.1.dist-info/licenses/LICENSE +201 -0
- cjm_fasthtml_token_selector-0.0.1.dist-info/top_level.txt +2 -0
- demos/__init__.py +0 -0
- demos/data.py +17 -0
- demos/gap.py +93 -0
- demos/shared.py +148 -0
- demos/span.py +92 -0
- demos/word.py +88 -0
|
@@ -0,0 +1,760 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cjm-fasthtml-token-selector
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A token-level interactive text selector for FastHTML with gap, word, and span selection modes, custom key repeat navigation, and HTMX state sync.
|
|
5
|
+
Home-page: https://github.com/cj-mills/cjm-fasthtml-token-selector
|
|
6
|
+
Author: Christian J. Mills
|
|
7
|
+
Author-email: 9126128+cj-mills@users.noreply.github.com
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Keywords: nbdev jupyter notebook python
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Natural Language :: English
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: python-fasthtml
|
|
19
|
+
Requires-Dist: cjm-fasthtml-tailwind
|
|
20
|
+
Requires-Dist: cjm-fasthtml-daisyui
|
|
21
|
+
Requires-Dist: cjm-fasthtml-keyboard-navigation
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: keywords
|
|
30
|
+
Dynamic: license
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
Dynamic: provides-extra
|
|
33
|
+
Dynamic: requires-dist
|
|
34
|
+
Dynamic: requires-python
|
|
35
|
+
Dynamic: summary
|
|
36
|
+
|
|
37
|
+
# cjm-fasthtml-token-selector
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
``` bash
|
|
45
|
+
pip install cjm_fasthtml_token_selector
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Project Structure
|
|
49
|
+
|
|
50
|
+
nbs/
|
|
51
|
+
├── components/ (2)
|
|
52
|
+
│ ├── inputs.ipynb # Hidden input rendering for HTMX state sync.
|
|
53
|
+
│ └── tokens.ipynb # Token grid rendering for all three selection modes (gap, word, span).
|
|
54
|
+
├── core/ (4)
|
|
55
|
+
│ ├── config.ipynb # Configuration dataclass for token selector initialization.
|
|
56
|
+
│ ├── constants.ipynb # CSS class constants, selection mode type, timing defaults, and key defaults for the token selector.
|
|
57
|
+
│ ├── html_ids.ipynb # Prefix-based HTML ID generator for token selector DOM elements.
|
|
58
|
+
│ └── models.ipynb # Data models for tokens, render context, and mutable runtime state.
|
|
59
|
+
├── helpers/ (1)
|
|
60
|
+
│ └── tokenizer.ipynb # Tokenization utilities for splitting text into tokens and converting between token indices and character positions.
|
|
61
|
+
├── js/ (4)
|
|
62
|
+
│ ├── core.ipynb # Master IIFE composer for the token selector JS runtime.
|
|
63
|
+
│ ├── display.ipynb # Generates JS functions for updating token display state (caret indicators, highlights, dimming, hidden inputs).
|
|
64
|
+
│ ├── navigation.ipynb # Generates mode-specific navigation and selection JS functions.
|
|
65
|
+
│ └── repeat.ipynb # Custom key repeat engine with configurable initial delay, repeat interval, and throttle floor.
|
|
66
|
+
└── keyboard/ (1)
|
|
67
|
+
└── actions.ipynb # Keyboard navigation library integration factories for token selector mode, actions, URL maps, and hidden action buttons.
|
|
68
|
+
|
|
69
|
+
Total: 12 notebooks across 5 directories
|
|
70
|
+
|
|
71
|
+
## Module Dependencies
|
|
72
|
+
|
|
73
|
+
``` mermaid
|
|
74
|
+
graph LR
|
|
75
|
+
components_inputs[components.inputs<br/>Inputs]
|
|
76
|
+
components_tokens[components.tokens<br/>Tokens]
|
|
77
|
+
core_config[core.config<br/>Config]
|
|
78
|
+
core_constants[core.constants<br/>Constants]
|
|
79
|
+
core_html_ids[core.html_ids<br/>HTML IDs]
|
|
80
|
+
core_models[core.models<br/>Models]
|
|
81
|
+
helpers_tokenizer[helpers.tokenizer<br/>Tokenizer]
|
|
82
|
+
js_core[js.core<br/>Core JS]
|
|
83
|
+
js_display[js.display<br/>Display JS]
|
|
84
|
+
js_navigation[js.navigation<br/>Navigation JS]
|
|
85
|
+
js_repeat[js.repeat<br/>Key Repeat JS]
|
|
86
|
+
keyboard_actions[keyboard.actions<br/>Keyboard Actions]
|
|
87
|
+
|
|
88
|
+
components_inputs --> core_models
|
|
89
|
+
components_inputs --> core_html_ids
|
|
90
|
+
components_tokens --> core_models
|
|
91
|
+
components_tokens --> core_constants
|
|
92
|
+
components_tokens --> core_config
|
|
93
|
+
components_tokens --> core_html_ids
|
|
94
|
+
components_tokens --> helpers_tokenizer
|
|
95
|
+
core_config --> core_constants
|
|
96
|
+
helpers_tokenizer --> core_models
|
|
97
|
+
js_core --> core_models
|
|
98
|
+
js_core --> js_repeat
|
|
99
|
+
js_core --> core_html_ids
|
|
100
|
+
js_core --> core_config
|
|
101
|
+
js_core --> js_navigation
|
|
102
|
+
js_core --> js_display
|
|
103
|
+
js_display --> core_constants
|
|
104
|
+
js_display --> core_html_ids
|
|
105
|
+
js_display --> core_config
|
|
106
|
+
js_navigation --> core_html_ids
|
|
107
|
+
js_navigation --> core_config
|
|
108
|
+
js_repeat --> core_config
|
|
109
|
+
keyboard_actions --> core_html_ids
|
|
110
|
+
keyboard_actions --> core_config
|
|
111
|
+
keyboard_actions --> js_core
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
*24 cross-module dependencies detected*
|
|
115
|
+
|
|
116
|
+
## CLI Reference
|
|
117
|
+
|
|
118
|
+
No CLI commands found in this project.
|
|
119
|
+
|
|
120
|
+
## Module Overview
|
|
121
|
+
|
|
122
|
+
Detailed documentation for each module in the project:
|
|
123
|
+
|
|
124
|
+
### Keyboard Actions (`actions.ipynb`)
|
|
125
|
+
|
|
126
|
+
> Keyboard navigation library integration factories for token selector
|
|
127
|
+
> mode, actions, URL maps, and hidden action buttons.
|
|
128
|
+
|
|
129
|
+
#### Import
|
|
130
|
+
|
|
131
|
+
``` python
|
|
132
|
+
from cjm_fasthtml_token_selector.keyboard.actions import (
|
|
133
|
+
create_token_selector_mode,
|
|
134
|
+
create_token_nav_actions,
|
|
135
|
+
build_token_selector_url_map,
|
|
136
|
+
render_token_action_buttons
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### Functions
|
|
141
|
+
|
|
142
|
+
``` python
|
|
143
|
+
def create_token_selector_mode(
|
|
144
|
+
config:TokenSelectorConfig, # config for this instance
|
|
145
|
+
mode_name:str = "token-select", # mode name for the keyboard nav system
|
|
146
|
+
indicator_text:str = "Token Select", # mode indicator text
|
|
147
|
+
exit_key:str = "", # exit key (empty = programmatic only via Escape KeyAction)
|
|
148
|
+
exit_on_zone_change:bool = False, # whether to exit on zone change
|
|
149
|
+
) -> KeyboardMode: # configured keyboard mode
|
|
150
|
+
"Create a keyboard mode that activates/deactivates the token selector."
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
``` python
|
|
154
|
+
def create_token_nav_actions(
|
|
155
|
+
config:TokenSelectorConfig, # config for this instance
|
|
156
|
+
zone_id:str, # focus zone ID
|
|
157
|
+
mode_name:str = "token-select", # mode name (must match the mode)
|
|
158
|
+
confirm_button_id:str = "", # HTMX button ID for confirm action
|
|
159
|
+
cancel_button_id:str = "", # HTMX button ID for cancel action
|
|
160
|
+
) -> Tuple[KeyAction, ...]: # non-movement keyboard actions
|
|
161
|
+
"Create keyboard actions for the token selector."
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
``` python
|
|
165
|
+
def build_token_selector_url_map(
|
|
166
|
+
confirm_button_id:str, # button ID for confirm action
|
|
167
|
+
cancel_button_id:str, # button ID for cancel action
|
|
168
|
+
confirm_url:str, # URL for confirm action
|
|
169
|
+
cancel_url:str, # URL for cancel action
|
|
170
|
+
) -> Dict[str, str]: # button ID -> URL mapping
|
|
171
|
+
"Build URL map for keyboard system with token selector action buttons."
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
``` python
|
|
175
|
+
def render_token_action_buttons(
|
|
176
|
+
confirm_button_id:str, # button ID for confirm
|
|
177
|
+
cancel_button_id:str, # button ID for cancel
|
|
178
|
+
confirm_url:str, # URL for confirm action
|
|
179
|
+
cancel_url:str, # URL for cancel action
|
|
180
|
+
ids:TokenSelectorHtmlIds, # HTML IDs (for hx_include)
|
|
181
|
+
extra_include:str = "", # additional hx_include selectors
|
|
182
|
+
) -> Any: # Div containing hidden action buttons
|
|
183
|
+
"Render hidden HTMX buttons for confirm/cancel actions."
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Config (`config.ipynb`)
|
|
187
|
+
|
|
188
|
+
> Configuration dataclass for token selector initialization.
|
|
189
|
+
|
|
190
|
+
#### Import
|
|
191
|
+
|
|
192
|
+
``` python
|
|
193
|
+
from cjm_fasthtml_token_selector.core.config import (
|
|
194
|
+
TokenSelectorConfig
|
|
195
|
+
)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
#### Functions
|
|
199
|
+
|
|
200
|
+
``` python
|
|
201
|
+
def _auto_prefix() -> str: # unique prefix string
|
|
202
|
+
"""Generate an auto-incrementing unique prefix."""
|
|
203
|
+
global _prefix_counter
|
|
204
|
+
p = f"ts{_prefix_counter}"
|
|
205
|
+
_prefix_counter += 1
|
|
206
|
+
return p
|
|
207
|
+
|
|
208
|
+
def _reset_prefix_counter() -> None
|
|
209
|
+
"Generate an auto-incrementing unique prefix."
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
``` python
|
|
213
|
+
def _reset_prefix_counter() -> None
|
|
214
|
+
"Reset the prefix counter (for testing only)."
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
#### Classes
|
|
218
|
+
|
|
219
|
+
``` python
|
|
220
|
+
@dataclass
|
|
221
|
+
class TokenSelectorConfig:
|
|
222
|
+
"Initialization-time settings for a token selector instance."
|
|
223
|
+
|
|
224
|
+
prefix: str = field(...) # unique instance prefix
|
|
225
|
+
selection_mode: SelectionMode = 'gap' # selection behavior: "gap", "word", or "span"
|
|
226
|
+
initial_delay: int = DEFAULT_INITIAL_DELAY # ms before first repeat
|
|
227
|
+
repeat_interval: int = DEFAULT_REPEAT_INTERVAL # ms between repeats
|
|
228
|
+
throttle_floor: int = DEFAULT_THROTTLE_FLOOR # minimum ms between movements
|
|
229
|
+
left_key: str = DEFAULT_LEFT_KEY # key for leftward navigation
|
|
230
|
+
right_key: str = DEFAULT_RIGHT_KEY # key for rightward navigation
|
|
231
|
+
end_token_text: str = DEFAULT_END_TOKEN_TEXT # text for the sentinel end token
|
|
232
|
+
show_end_token: bool = True # whether to show the end token
|
|
233
|
+
read_only: bool = False # disable click/keyboard interaction
|
|
234
|
+
wrap_navigation: bool = False # wrap around at boundaries
|
|
235
|
+
on_change_callback: str = '' # JS function name called on selection change
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### Variables
|
|
239
|
+
|
|
240
|
+
``` python
|
|
241
|
+
_prefix_counter: int = 0
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Constants (`constants.ipynb`)
|
|
245
|
+
|
|
246
|
+
> CSS class constants, selection mode type, timing defaults, and key
|
|
247
|
+
> defaults for the token selector.
|
|
248
|
+
|
|
249
|
+
#### Import
|
|
250
|
+
|
|
251
|
+
``` python
|
|
252
|
+
from cjm_fasthtml_token_selector.core.constants import (
|
|
253
|
+
SelectionMode,
|
|
254
|
+
OPACITY_50_CLS,
|
|
255
|
+
CARET_INDICATOR_CLS,
|
|
256
|
+
HIGHLIGHT_CLS,
|
|
257
|
+
DEFAULT_INITIAL_DELAY,
|
|
258
|
+
DEFAULT_REPEAT_INTERVAL,
|
|
259
|
+
DEFAULT_THROTTLE_FLOOR,
|
|
260
|
+
DEFAULT_LEFT_KEY,
|
|
261
|
+
DEFAULT_RIGHT_KEY,
|
|
262
|
+
DEFAULT_END_TOKEN_TEXT
|
|
263
|
+
)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### Variables
|
|
267
|
+
|
|
268
|
+
``` python
|
|
269
|
+
OPACITY_50_CLS
|
|
270
|
+
CARET_INDICATOR_CLS
|
|
271
|
+
HIGHLIGHT_CLS
|
|
272
|
+
DEFAULT_INITIAL_DELAY: int = 400
|
|
273
|
+
DEFAULT_REPEAT_INTERVAL: int = 80
|
|
274
|
+
DEFAULT_THROTTLE_FLOOR: int = 50
|
|
275
|
+
DEFAULT_LEFT_KEY: str = 'ArrowLeft'
|
|
276
|
+
DEFAULT_RIGHT_KEY: str = 'ArrowRight'
|
|
277
|
+
DEFAULT_END_TOKEN_TEXT: str = '(End)'
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Core JS (`core.ipynb`)
|
|
281
|
+
|
|
282
|
+
> Master IIFE composer for the token selector JS runtime.
|
|
283
|
+
|
|
284
|
+
#### Import
|
|
285
|
+
|
|
286
|
+
``` python
|
|
287
|
+
from cjm_fasthtml_token_selector.js.core import (
|
|
288
|
+
global_callback_name,
|
|
289
|
+
generate_token_selector_js
|
|
290
|
+
)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
#### Functions
|
|
294
|
+
|
|
295
|
+
``` python
|
|
296
|
+
def global_callback_name(
|
|
297
|
+
prefix:str, # token selector instance prefix
|
|
298
|
+
callback:str, # base callback name
|
|
299
|
+
) -> str: # global function name
|
|
300
|
+
"Generate a prefix-unique global callback name."
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
``` python
|
|
304
|
+
def _generate_state_init_js(
|
|
305
|
+
config:TokenSelectorConfig, # config for this instance
|
|
306
|
+
state:TokenSelectorState, # initial state
|
|
307
|
+
) -> str: # JS code fragment
|
|
308
|
+
"Generate state initialization code."
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
``` python
|
|
312
|
+
def _generate_on_change_js(
|
|
313
|
+
config:TokenSelectorConfig, # config for this instance
|
|
314
|
+
) -> str: # JS code fragment
|
|
315
|
+
"Generate the on-change callback dispatcher."
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
``` python
|
|
319
|
+
def _generate_activation_js(
|
|
320
|
+
config:TokenSelectorConfig, # config for this instance
|
|
321
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
322
|
+
) -> str: # JS code fragment
|
|
323
|
+
"Generate activate/deactivate functions."
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
``` python
|
|
327
|
+
def _generate_global_callbacks_js(
|
|
328
|
+
config:TokenSelectorConfig, # config for this instance
|
|
329
|
+
) -> str: # JS code fragment
|
|
330
|
+
"Generate global callback wrappers."
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
``` python
|
|
334
|
+
def _generate_settle_handler_js(
|
|
335
|
+
config:TokenSelectorConfig, # config for this instance
|
|
336
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
337
|
+
) -> str: # JS code fragment
|
|
338
|
+
"Generate htmx:afterSettle handler for swap resilience."
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
``` python
|
|
342
|
+
def generate_token_selector_js(
|
|
343
|
+
config:TokenSelectorConfig, # config for this instance
|
|
344
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
345
|
+
state:TokenSelectorState = None, # initial state
|
|
346
|
+
extra_scripts:Tuple[str, ...] = (), # additional JS to include in the IIFE
|
|
347
|
+
) -> Any: # Script element with the complete IIFE
|
|
348
|
+
"Compose all token selector JS into a single namespaced IIFE."
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
#### Variables
|
|
352
|
+
|
|
353
|
+
``` python
|
|
354
|
+
_GLOBAL_CALLBACKS
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Display JS (`display.ipynb`)
|
|
358
|
+
|
|
359
|
+
> Generates JS functions for updating token display state (caret
|
|
360
|
+
> indicators, highlights, dimming, hidden inputs).
|
|
361
|
+
|
|
362
|
+
#### Import
|
|
363
|
+
|
|
364
|
+
``` python
|
|
365
|
+
from cjm_fasthtml_token_selector.js.display import (
|
|
366
|
+
generate_display_js
|
|
367
|
+
)
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
#### Functions
|
|
371
|
+
|
|
372
|
+
``` python
|
|
373
|
+
def _generate_update_inputs_js(
|
|
374
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
375
|
+
) -> str: # JS code fragment
|
|
376
|
+
"Generate the hidden input sync function."
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
``` python
|
|
380
|
+
def _generate_gap_display_js(
|
|
381
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
382
|
+
) -> str: # JS code fragment
|
|
383
|
+
"Generate gap mode display update function."
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
``` python
|
|
387
|
+
def _generate_word_display_js(
|
|
388
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
389
|
+
) -> str: # JS code fragment
|
|
390
|
+
"Generate word mode display update function."
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
``` python
|
|
394
|
+
def _generate_span_display_js(
|
|
395
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
396
|
+
) -> str: # JS code fragment
|
|
397
|
+
"Generate span mode display update function."
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
``` python
|
|
401
|
+
def generate_display_js(
|
|
402
|
+
config:TokenSelectorConfig, # config for this instance
|
|
403
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
404
|
+
) -> str: # JS code fragment for the IIFE
|
|
405
|
+
"Generate display update and hidden input sync JS functions."
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### HTML IDs (`html_ids.ipynb`)
|
|
409
|
+
|
|
410
|
+
> Prefix-based HTML ID generator for token selector DOM elements.
|
|
411
|
+
|
|
412
|
+
#### Import
|
|
413
|
+
|
|
414
|
+
``` python
|
|
415
|
+
from cjm_fasthtml_token_selector.core.html_ids import (
|
|
416
|
+
TokenSelectorHtmlIds
|
|
417
|
+
)
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
#### Classes
|
|
421
|
+
|
|
422
|
+
``` python
|
|
423
|
+
@dataclass
|
|
424
|
+
class TokenSelectorHtmlIds:
|
|
425
|
+
"Prefix-based HTML ID generator for token selector DOM elements."
|
|
426
|
+
|
|
427
|
+
prefix: str # unique instance prefix
|
|
428
|
+
|
|
429
|
+
def container(self) -> str: # outer wrapper ID
|
|
430
|
+
"""Outer token selector wrapper."""
|
|
431
|
+
return f"{self.prefix}-token-selector"
|
|
432
|
+
|
|
433
|
+
@property
|
|
434
|
+
def token_grid(self) -> str: # flex-wrap token container ID
|
|
435
|
+
"Outer token selector wrapper."
|
|
436
|
+
|
|
437
|
+
def token_grid(self) -> str: # flex-wrap token container ID
|
|
438
|
+
"""Flex-wrap token container."""
|
|
439
|
+
return f"{self.prefix}-token-grid"
|
|
440
|
+
|
|
441
|
+
@property
|
|
442
|
+
def anchor_input(self) -> str: # hidden input ID for anchor position
|
|
443
|
+
"Flex-wrap token container."
|
|
444
|
+
|
|
445
|
+
def anchor_input(self) -> str: # hidden input ID for anchor position
|
|
446
|
+
"""Hidden input ID for anchor position (hyphenated, for CSS selectors)."""
|
|
447
|
+
return f"{self.prefix}-anchor"
|
|
448
|
+
|
|
449
|
+
@property
|
|
450
|
+
def focus_input(self) -> str: # hidden input ID for focus position
|
|
451
|
+
"Hidden input ID for anchor position (hyphenated, for CSS selectors)."
|
|
452
|
+
|
|
453
|
+
def focus_input(self) -> str: # hidden input ID for focus position
|
|
454
|
+
"""Hidden input ID for focus position (hyphenated, for CSS selectors)."""
|
|
455
|
+
return f"{self.prefix}-focus"
|
|
456
|
+
|
|
457
|
+
@property
|
|
458
|
+
def anchor_name(self) -> str: # form field name for anchor position
|
|
459
|
+
"Hidden input ID for focus position (hyphenated, for CSS selectors)."
|
|
460
|
+
|
|
461
|
+
def anchor_name(self) -> str: # form field name for anchor position
|
|
462
|
+
"""Form field name for anchor position (underscored, for Python kwargs)."""
|
|
463
|
+
return f"{self.prefix}_anchor"
|
|
464
|
+
|
|
465
|
+
@property
|
|
466
|
+
def focus_name(self) -> str: # form field name for focus position
|
|
467
|
+
"Form field name for anchor position (underscored, for Python kwargs)."
|
|
468
|
+
|
|
469
|
+
def focus_name(self) -> str: # form field name for focus position
|
|
470
|
+
"""Form field name for focus position (underscored, for Python kwargs)."""
|
|
471
|
+
return f"{self.prefix}_focus"
|
|
472
|
+
|
|
473
|
+
def token(self,
|
|
474
|
+
index:int, # token position index
|
|
475
|
+
) -> str: # individual token span ID
|
|
476
|
+
"Form field name for focus position (underscored, for Python kwargs)."
|
|
477
|
+
|
|
478
|
+
def token(self,
|
|
479
|
+
index:int, # token position index
|
|
480
|
+
) -> str: # individual token span ID
|
|
481
|
+
"Individual token span ID."
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Inputs (`inputs.ipynb`)
|
|
485
|
+
|
|
486
|
+
> Hidden input rendering for HTMX state sync.
|
|
487
|
+
|
|
488
|
+
#### Import
|
|
489
|
+
|
|
490
|
+
``` python
|
|
491
|
+
from cjm_fasthtml_token_selector.components.inputs import (
|
|
492
|
+
render_hidden_inputs,
|
|
493
|
+
build_include_selector
|
|
494
|
+
)
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
#### Functions
|
|
498
|
+
|
|
499
|
+
``` python
|
|
500
|
+
def render_hidden_inputs(
|
|
501
|
+
ids:TokenSelectorHtmlIds, # HTML IDs for this instance
|
|
502
|
+
state:Optional[TokenSelectorState] = None, # current state
|
|
503
|
+
oob:bool = False, # render with hx-swap-oob
|
|
504
|
+
) -> Any: # tuple of anchor and focus hidden inputs
|
|
505
|
+
"Render hidden inputs for HTMX form submission."
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
``` python
|
|
509
|
+
def build_include_selector(
|
|
510
|
+
ids:TokenSelectorHtmlIds, # HTML IDs for this instance
|
|
511
|
+
) -> str: # CSS selector string for hx_include
|
|
512
|
+
"Build a CSS selector for including anchor and focus inputs in HTMX requests."
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### Models (`models.ipynb`)
|
|
516
|
+
|
|
517
|
+
> Data models for tokens, render context, and mutable runtime state.
|
|
518
|
+
|
|
519
|
+
#### Import
|
|
520
|
+
|
|
521
|
+
``` python
|
|
522
|
+
from cjm_fasthtml_token_selector.core.models import (
|
|
523
|
+
Token,
|
|
524
|
+
TokenRenderContext,
|
|
525
|
+
TokenSelectorState
|
|
526
|
+
)
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
#### Classes
|
|
530
|
+
|
|
531
|
+
``` python
|
|
532
|
+
@dataclass
|
|
533
|
+
class Token:
|
|
534
|
+
"A single token in the token grid."
|
|
535
|
+
|
|
536
|
+
text: str # the token text content
|
|
537
|
+
index: int # 0-based position in the token list
|
|
538
|
+
metadata: Any # optional consumer metadata per token
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
``` python
|
|
542
|
+
@dataclass
|
|
543
|
+
class TokenRenderContext:
|
|
544
|
+
"Context passed to per-token styling callbacks."
|
|
545
|
+
|
|
546
|
+
token: Token # the token being rendered
|
|
547
|
+
is_selected: bool # whether this token is in the current selection
|
|
548
|
+
is_anchor: bool # whether this token is at the anchor position
|
|
549
|
+
is_focus: bool # whether this token is at the focus position
|
|
550
|
+
selection_mode: str # current selection mode
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
``` python
|
|
554
|
+
@dataclass
|
|
555
|
+
class TokenSelectorState:
|
|
556
|
+
"Mutable runtime state for a token selector instance."
|
|
557
|
+
|
|
558
|
+
anchor: int = 0 # anchor position (gap index or token index)
|
|
559
|
+
focus: int = 0 # focus position (same as anchor in gap/word mode)
|
|
560
|
+
word_count: int = 0 # total number of tokens
|
|
561
|
+
active: bool = False # whether the key repeat engine is active
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### Navigation JS (`navigation.ipynb`)
|
|
565
|
+
|
|
566
|
+
> Generates mode-specific navigation and selection JS functions.
|
|
567
|
+
|
|
568
|
+
#### Import
|
|
569
|
+
|
|
570
|
+
``` python
|
|
571
|
+
from cjm_fasthtml_token_selector.js.navigation import (
|
|
572
|
+
generate_navigation_js
|
|
573
|
+
)
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
#### Functions
|
|
577
|
+
|
|
578
|
+
``` python
|
|
579
|
+
def _generate_gap_nav_js(
|
|
580
|
+
config:TokenSelectorConfig, # config for this instance
|
|
581
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
582
|
+
) -> str: # JS code fragment
|
|
583
|
+
"Generate gap mode navigation functions."
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
``` python
|
|
587
|
+
def _generate_word_nav_js(
|
|
588
|
+
config:TokenSelectorConfig, # config for this instance
|
|
589
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
590
|
+
) -> str: # JS code fragment
|
|
591
|
+
"Generate word mode navigation functions."
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
``` python
|
|
595
|
+
def _generate_span_nav_js(
|
|
596
|
+
config:TokenSelectorConfig, # config for this instance
|
|
597
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
598
|
+
) -> str: # JS code fragment
|
|
599
|
+
"Generate span mode navigation functions."
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
``` python
|
|
603
|
+
def generate_navigation_js(
|
|
604
|
+
config:TokenSelectorConfig, # config for this instance
|
|
605
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
606
|
+
) -> str: # JS code fragment for the IIFE
|
|
607
|
+
"Generate mode-specific navigation and selection JS functions."
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
### Key Repeat JS (`repeat.ipynb`)
|
|
611
|
+
|
|
612
|
+
> Custom key repeat engine with configurable initial delay, repeat
|
|
613
|
+
> interval, and throttle floor.
|
|
614
|
+
|
|
615
|
+
#### Import
|
|
616
|
+
|
|
617
|
+
``` python
|
|
618
|
+
from cjm_fasthtml_token_selector.js.repeat import (
|
|
619
|
+
generate_key_repeat_js
|
|
620
|
+
)
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
#### Functions
|
|
624
|
+
|
|
625
|
+
``` python
|
|
626
|
+
def _generate_movement_dispatch_js(
|
|
627
|
+
config:TokenSelectorConfig, # config for this instance
|
|
628
|
+
) -> str: # JS code fragment for the movement dispatcher
|
|
629
|
+
"Generate the key-to-movement dispatch logic."
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
``` python
|
|
633
|
+
def generate_key_repeat_js(
|
|
634
|
+
config:TokenSelectorConfig, # config with timing settings
|
|
635
|
+
) -> str: # JS code fragment for the IIFE
|
|
636
|
+
"Generate the custom key repeat engine JS."
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
### Tokenizer (`tokenizer.ipynb`)
|
|
640
|
+
|
|
641
|
+
> Tokenization utilities for splitting text into tokens and converting
|
|
642
|
+
> between token indices and character positions.
|
|
643
|
+
|
|
644
|
+
#### Import
|
|
645
|
+
|
|
646
|
+
``` python
|
|
647
|
+
from cjm_fasthtml_token_selector.helpers.tokenizer import (
|
|
648
|
+
count_tokens,
|
|
649
|
+
get_token_list,
|
|
650
|
+
token_index_to_char_position,
|
|
651
|
+
tokenize
|
|
652
|
+
)
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
#### Functions
|
|
656
|
+
|
|
657
|
+
``` python
|
|
658
|
+
def count_tokens(
|
|
659
|
+
text:str, # text to count tokens in
|
|
660
|
+
) -> int: # token count
|
|
661
|
+
"Count the number of whitespace-delimited tokens in text."
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
``` python
|
|
665
|
+
def get_token_list(
|
|
666
|
+
text:str, # text to split into tokens
|
|
667
|
+
) -> List[str]: # list of token strings
|
|
668
|
+
"Split text into a list of whitespace-delimited tokens."
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
``` python
|
|
672
|
+
def token_index_to_char_position(
|
|
673
|
+
text:str, # full text string
|
|
674
|
+
token_index:int, # 0-based token index
|
|
675
|
+
) -> int: # character position for split
|
|
676
|
+
"Convert a token index to the character position where a split should occur."
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
``` python
|
|
680
|
+
def tokenize(
|
|
681
|
+
text_or_tokens:Union[str, List[str]], # raw text string or pre-tokenized list
|
|
682
|
+
metadata:Optional[List[Any]] = None, # per-token metadata (must match token count)
|
|
683
|
+
) -> List[Token]: # list of Token objects
|
|
684
|
+
"Convert text or a pre-tokenized list into Token objects."
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### Tokens (`tokens.ipynb`)
|
|
688
|
+
|
|
689
|
+
> Token grid rendering for all three selection modes (gap, word, span).
|
|
690
|
+
|
|
691
|
+
#### Import
|
|
692
|
+
|
|
693
|
+
``` python
|
|
694
|
+
from cjm_fasthtml_token_selector.components.tokens import (
|
|
695
|
+
render_token,
|
|
696
|
+
render_end_token,
|
|
697
|
+
render_token_grid
|
|
698
|
+
)
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
#### Functions
|
|
702
|
+
|
|
703
|
+
``` python
|
|
704
|
+
def _is_token_selected(
|
|
705
|
+
index:int, # token index
|
|
706
|
+
mode:str, # selection mode
|
|
707
|
+
anchor:int, # anchor position
|
|
708
|
+
focus:int, # focus position
|
|
709
|
+
) -> bool: # whether the token is in the selection
|
|
710
|
+
"Check if a token at the given index is within the current selection."
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
``` python
|
|
714
|
+
def _build_token_render_context(
|
|
715
|
+
token:Token, # token being rendered
|
|
716
|
+
mode:str, # selection mode
|
|
717
|
+
anchor:int, # anchor position
|
|
718
|
+
focus:int, # focus position
|
|
719
|
+
) -> TokenRenderContext: # render context for styling callback
|
|
720
|
+
"Build a render context for the per-token styling callback."
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
``` python
|
|
724
|
+
def _render_caret_indicator() -> Any: # caret indicator Div element
|
|
725
|
+
"Render the pulsing caret indicator bar."
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
``` python
|
|
729
|
+
def render_token(
|
|
730
|
+
token:Token, # token to render
|
|
731
|
+
config:TokenSelectorConfig, # config for this instance
|
|
732
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
733
|
+
state:Optional[TokenSelectorState] = None, # current state for highlighting
|
|
734
|
+
style_callback:Optional[Callable] = None, # (TokenRenderContext) -> str for extra CSS
|
|
735
|
+
read_only:bool = False, # disable interaction
|
|
736
|
+
) -> Any: # Span element for this token
|
|
737
|
+
"Render a single interactive word token."
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
``` python
|
|
741
|
+
def render_end_token(
|
|
742
|
+
config:TokenSelectorConfig, # config for this instance
|
|
743
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
744
|
+
state:Optional[TokenSelectorState] = None, # current state
|
|
745
|
+
read_only:bool = False, # disable interaction
|
|
746
|
+
) -> Any: # end sentinel Span element
|
|
747
|
+
"Render the end-of-text sentinel token."
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
``` python
|
|
751
|
+
def render_token_grid(
|
|
752
|
+
tokens:List[Token], # token list to render
|
|
753
|
+
config:TokenSelectorConfig, # config for this instance
|
|
754
|
+
ids:TokenSelectorHtmlIds, # HTML IDs
|
|
755
|
+
state:Optional[TokenSelectorState] = None, # current state for highlighting
|
|
756
|
+
style_callback:Optional[Callable] = None, # (TokenRenderContext) -> str for extra CSS
|
|
757
|
+
read_only:bool = False, # disable all interaction
|
|
758
|
+
) -> Any: # Div containing the complete token grid
|
|
759
|
+
"Render the full interactive token grid."
|
|
760
|
+
```
|