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.
Files changed (31) hide show
  1. cjm_fasthtml_token_selector/__init__.py +1 -0
  2. cjm_fasthtml_token_selector/_modidx.py +104 -0
  3. cjm_fasthtml_token_selector/components/__init__.py +0 -0
  4. cjm_fasthtml_token_selector/components/inputs.py +46 -0
  5. cjm_fasthtml_token_selector/components/tokens.py +217 -0
  6. cjm_fasthtml_token_selector/core/__init__.py +0 -0
  7. cjm_fasthtml_token_selector/core/config.py +57 -0
  8. cjm_fasthtml_token_selector/core/constants.py +50 -0
  9. cjm_fasthtml_token_selector/core/html_ids.py +51 -0
  10. cjm_fasthtml_token_selector/core/models.py +37 -0
  11. cjm_fasthtml_token_selector/helpers/__init__.py +0 -0
  12. cjm_fasthtml_token_selector/helpers/tokenizer.py +76 -0
  13. cjm_fasthtml_token_selector/js/__init__.py +0 -0
  14. cjm_fasthtml_token_selector/js/core.py +181 -0
  15. cjm_fasthtml_token_selector/js/display.py +146 -0
  16. cjm_fasthtml_token_selector/js/navigation.py +228 -0
  17. cjm_fasthtml_token_selector/js/repeat.py +119 -0
  18. cjm_fasthtml_token_selector/keyboard/__init__.py +0 -0
  19. cjm_fasthtml_token_selector/keyboard/actions.py +157 -0
  20. cjm_fasthtml_token_selector-0.0.1.dist-info/METADATA +760 -0
  21. cjm_fasthtml_token_selector-0.0.1.dist-info/RECORD +31 -0
  22. cjm_fasthtml_token_selector-0.0.1.dist-info/WHEEL +5 -0
  23. cjm_fasthtml_token_selector-0.0.1.dist-info/entry_points.txt +2 -0
  24. cjm_fasthtml_token_selector-0.0.1.dist-info/licenses/LICENSE +201 -0
  25. cjm_fasthtml_token_selector-0.0.1.dist-info/top_level.txt +2 -0
  26. demos/__init__.py +0 -0
  27. demos/data.py +17 -0
  28. demos/gap.py +93 -0
  29. demos/shared.py +148 -0
  30. demos/span.py +92 -0
  31. 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
+ ```