cjm-transcript-source-select 0.0.3__tar.gz → 0.0.5__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.
Files changed (38) hide show
  1. {cjm_transcript_source_select-0.0.3/cjm_transcript_source_select.egg-info → cjm_transcript_source_select-0.0.5}/PKG-INFO +24 -23
  2. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/README.md +23 -22
  3. cjm_transcript_source_select-0.0.5/cjm_transcript_source_select/__init__.py +1 -0
  4. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/components/selection_queue.py +2 -0
  5. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/components/source_browser.py +11 -7
  6. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/components/step_renderer.py +3 -0
  7. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/html_ids.py +3 -0
  8. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/routes/core.py +35 -15
  9. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5/cjm_transcript_source_select.egg-info}/PKG-INFO +24 -23
  10. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/settings.ini +1 -1
  11. cjm_transcript_source_select-0.0.3/cjm_transcript_source_select/__init__.py +0 -1
  12. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/LICENSE +0 -0
  13. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/MANIFEST.in +0 -0
  14. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/_modidx.py +0 -0
  15. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/components/__init__.py +0 -0
  16. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/components/helpers.py +0 -0
  17. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/components/local_files.py +0 -0
  18. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/components/preview_panel.py +0 -0
  19. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/models.py +0 -0
  20. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/routes/__init__.py +0 -0
  21. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/routes/filtering.py +0 -0
  22. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/routes/init.py +0 -0
  23. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/routes/local_files.py +0 -0
  24. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/routes/queue.py +0 -0
  25. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/routes/tabs.py +0 -0
  26. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/services/__init__.py +0 -0
  27. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/services/source.py +0 -0
  28. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/services/source_utils.py +0 -0
  29. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select/utils.py +0 -0
  30. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select.egg-info/SOURCES.txt +0 -0
  31. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select.egg-info/dependency_links.txt +0 -0
  32. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select.egg-info/entry_points.txt +0 -0
  33. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select.egg-info/not-zip-safe +0 -0
  34. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select.egg-info/requires.txt +0 -0
  35. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/cjm_transcript_source_select.egg-info/top_level.txt +0 -0
  36. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/pyproject.toml +0 -0
  37. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/setup.cfg +0 -0
  38. {cjm_transcript_source_select-0.0.3 → cjm_transcript_source_select-0.0.5}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: cjm-transcript-source-select
3
- Version: 0.0.3
3
+ Version: 0.0.5
4
4
  Summary: FastHTML source selection component for transcript decomposition workflows, with federated database browsing, drag-drop ordering, and keyboard navigation.
5
5
  Home-page: https://github.com/cj-mills/cjm-transcript-source-select
6
6
  Author: Christian J. Mills
@@ -109,48 +109,48 @@ graph LR
109
109
  components_source_browser --> services_source_utils
110
110
  components_source_browser --> html_ids
111
111
  components_step_renderer --> components_selection_queue
112
- components_step_renderer --> components_preview_panel
113
112
  components_step_renderer --> components_local_files
114
- components_step_renderer --> components_source_browser
115
113
  components_step_renderer --> components_helpers
116
- components_step_renderer --> utils
117
- components_step_renderer --> html_ids
118
114
  components_step_renderer --> models
115
+ components_step_renderer --> components_source_browser
116
+ components_step_renderer --> html_ids
117
+ components_step_renderer --> components_preview_panel
118
+ components_step_renderer --> utils
119
119
  routes_core --> components_step_renderer
120
- routes_core --> services_source
121
120
  routes_core --> models
122
- routes_core --> html_ids
123
- routes_core --> components_selection_queue
124
121
  routes_core --> components_source_browser
125
- routes_filtering --> services_source
126
- routes_filtering --> services_source_utils
122
+ routes_core --> services_source
123
+ routes_core --> components_selection_queue
124
+ routes_core --> html_ids
127
125
  routes_filtering --> routes_core
128
126
  routes_filtering --> components_source_browser
127
+ routes_filtering --> services_source_utils
129
128
  routes_filtering --> models
130
- routes_init --> routes_filtering
131
- routes_init --> routes_local_files
132
- routes_init --> services_source
133
- routes_init --> routes_tabs
134
- routes_init --> models
129
+ routes_filtering --> services_source
135
130
  routes_init --> routes_core
136
131
  routes_init --> routes_queue
132
+ routes_init --> models
133
+ routes_init --> services_source
134
+ routes_init --> routes_tabs
135
+ routes_init --> routes_filtering
136
+ routes_init --> routes_local_files
137
137
  routes_local_files --> services_source
138
138
  routes_local_files --> routes_core
139
139
  routes_local_files --> models
140
140
  routes_local_files --> components_local_files
141
141
  routes_queue --> routes_core
142
142
  routes_queue --> components_preview_panel
143
+ routes_queue --> models
143
144
  routes_queue --> services_source
144
145
  routes_queue --> services_source_utils
145
- routes_queue --> models
146
- routes_tabs --> routes_local_files
147
- routes_tabs --> components_source_browser
148
- routes_tabs --> services_source_utils
149
- routes_tabs --> services_source
150
146
  routes_tabs --> routes_core
151
147
  routes_tabs --> models
152
- routes_tabs --> components_local_files
148
+ routes_tabs --> services_source
153
149
  routes_tabs --> components_step_renderer
150
+ routes_tabs --> components_source_browser
151
+ routes_tabs --> routes_local_files
152
+ routes_tabs --> components_local_files
153
+ routes_tabs --> services_source_utils
154
154
  ```
155
155
 
156
156
  *51 cross-module dependencies detected*
@@ -203,8 +203,8 @@ def _render_duplicate_flash(
203
203
  candidate_provider_id: str, # Provider ID of the row the user clicked
204
204
  existing_record_id: str, # Record ID of the conflicting selected row
205
205
  existing_provider_id: str, # Provider ID of the conflicting selected row
206
- ) -> Script: # OOB script element for flash animation
207
- "Render a self-removing Script that briefly flashes two source rows with error color."
206
+ ) -> Div: # OOB Div with flash script (replaces previous via innerHTML swap)
207
+ "Render a fixed-ID container with flash script for two source rows."
208
208
  ```
209
209
 
210
210
  ``` python
@@ -1043,6 +1043,7 @@ def _render_source_row(
1043
1043
  remove_url: str, # URL for removing from queue
1044
1044
  preview_url: str, # URL for previewing content
1045
1045
  is_first: bool = False, # Whether this is the first row (gets initial focus)
1046
+ row_index: int = 0, # Index among selectable rows (for keyboard focus sync)
1046
1047
  ) -> Any: # Table row element
1047
1048
  "Render a single source row in the browser table."
1048
1049
  ```
@@ -66,48 +66,48 @@ graph LR
66
66
  components_source_browser --> services_source_utils
67
67
  components_source_browser --> html_ids
68
68
  components_step_renderer --> components_selection_queue
69
- components_step_renderer --> components_preview_panel
70
69
  components_step_renderer --> components_local_files
71
- components_step_renderer --> components_source_browser
72
70
  components_step_renderer --> components_helpers
73
- components_step_renderer --> utils
74
- components_step_renderer --> html_ids
75
71
  components_step_renderer --> models
72
+ components_step_renderer --> components_source_browser
73
+ components_step_renderer --> html_ids
74
+ components_step_renderer --> components_preview_panel
75
+ components_step_renderer --> utils
76
76
  routes_core --> components_step_renderer
77
- routes_core --> services_source
78
77
  routes_core --> models
79
- routes_core --> html_ids
80
- routes_core --> components_selection_queue
81
78
  routes_core --> components_source_browser
82
- routes_filtering --> services_source
83
- routes_filtering --> services_source_utils
79
+ routes_core --> services_source
80
+ routes_core --> components_selection_queue
81
+ routes_core --> html_ids
84
82
  routes_filtering --> routes_core
85
83
  routes_filtering --> components_source_browser
84
+ routes_filtering --> services_source_utils
86
85
  routes_filtering --> models
87
- routes_init --> routes_filtering
88
- routes_init --> routes_local_files
89
- routes_init --> services_source
90
- routes_init --> routes_tabs
91
- routes_init --> models
86
+ routes_filtering --> services_source
92
87
  routes_init --> routes_core
93
88
  routes_init --> routes_queue
89
+ routes_init --> models
90
+ routes_init --> services_source
91
+ routes_init --> routes_tabs
92
+ routes_init --> routes_filtering
93
+ routes_init --> routes_local_files
94
94
  routes_local_files --> services_source
95
95
  routes_local_files --> routes_core
96
96
  routes_local_files --> models
97
97
  routes_local_files --> components_local_files
98
98
  routes_queue --> routes_core
99
99
  routes_queue --> components_preview_panel
100
+ routes_queue --> models
100
101
  routes_queue --> services_source
101
102
  routes_queue --> services_source_utils
102
- routes_queue --> models
103
- routes_tabs --> routes_local_files
104
- routes_tabs --> components_source_browser
105
- routes_tabs --> services_source_utils
106
- routes_tabs --> services_source
107
103
  routes_tabs --> routes_core
108
104
  routes_tabs --> models
109
- routes_tabs --> components_local_files
105
+ routes_tabs --> services_source
110
106
  routes_tabs --> components_step_renderer
107
+ routes_tabs --> components_source_browser
108
+ routes_tabs --> routes_local_files
109
+ routes_tabs --> components_local_files
110
+ routes_tabs --> services_source_utils
111
111
  ```
112
112
 
113
113
  *51 cross-module dependencies detected*
@@ -160,8 +160,8 @@ def _render_duplicate_flash(
160
160
  candidate_provider_id: str, # Provider ID of the row the user clicked
161
161
  existing_record_id: str, # Record ID of the conflicting selected row
162
162
  existing_provider_id: str, # Provider ID of the conflicting selected row
163
- ) -> Script: # OOB script element for flash animation
164
- "Render a self-removing Script that briefly flashes two source rows with error color."
163
+ ) -> Div: # OOB Div with flash script (replaces previous via innerHTML swap)
164
+ "Render a fixed-ID container with flash script for two source rows."
165
165
  ```
166
166
 
167
167
  ``` python
@@ -1000,6 +1000,7 @@ def _render_source_row(
1000
1000
  remove_url: str, # URL for removing from queue
1001
1001
  preview_url: str, # URL for previewing content
1002
1002
  is_first: bool = False, # Whether this is the first row (gets initial focus)
1003
+ row_index: int = 0, # Index among selectable rows (for keyboard focus sync)
1003
1004
  ) -> Any: # Table row element
1004
1005
  "Render a single source row in the browser table."
1005
1006
  ```
@@ -0,0 +1 @@
1
+ __version__ = "0.0.5"
@@ -150,11 +150,13 @@ def _render_selection_queue(
150
150
  ),
151
151
 
152
152
  # Queue list with native Sortable.js (initialized via script)
153
+ # hx_include="this" required for HTMX 2.x to collect child hidden inputs
153
154
  Ul(
154
155
  *queue_items,
155
156
  id=SelectionHtmlIds.QUEUE_LIST,
156
157
  hx_post=reorder_url,
157
158
  hx_trigger="end",
159
+ hx_include="this",
158
160
  hx_target=SelectionHtmlIds.as_selector(SelectionHtmlIds.QUEUE_CONTAINER),
159
161
  hx_swap="outerHTML",
160
162
  cls=combine_classes("sortable", grow(), overflow.y.auto, list_style.none, m(0), p(0))
@@ -39,7 +39,6 @@ from cjm_fasthtml_tailwind.utilities.interactivity import cursor
39
39
  from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import (
40
40
  flex_display, flex_direction, justify, items, gap, grow
41
41
  )
42
- from cjm_fasthtml_tailwind.utilities.transitions_and_animation import transition, duration
43
42
  from cjm_fasthtml_tailwind.core.base import combine_classes
44
43
 
45
44
  # Local imports
@@ -84,6 +83,7 @@ def _render_source_row(
84
83
  remove_url: str, # URL for removing from queue
85
84
  preview_url: str, # URL for previewing content
86
85
  is_first: bool = False, # Whether this is the first row (gets initial focus)
86
+ row_index: int = 0, # Index among selectable rows (for keyboard focus sync)
87
87
  ) -> Any: # Table row element
88
88
  """Render a single source row in the browser table."""
89
89
  record_id = record.get("record_id", "")
@@ -139,6 +139,10 @@ def _render_source_row(
139
139
  cls=combine_classes(tooltip, tooltip_placement.top)
140
140
  )
141
141
 
142
+ # Click handler to sync keyboard focus with clicked row
143
+ zone_id = SelectionHtmlIds.SOURCE_LIST
144
+ focus_onclick = f"if(window.kbNav)window.kbNav.setItemFocus('{zone_id}',{row_index},true)"
145
+
142
146
  return Tr(
143
147
  # Hidden cell for keyboard action data (must be in TD for valid HTML)
144
148
  Td(
@@ -178,15 +182,14 @@ def _render_source_row(
178
182
  cls=combine_classes(
179
183
  bg_dui.primary.opacity(10) if is_selected else "",
180
184
  bg_dui.base_200.hover,
181
- cursor.pointer,
182
- transition.colors,
183
- duration(200)
185
+ cursor.pointer
184
186
  ),
185
187
  tabindex="0",
186
188
  data_selectable="true",
187
189
  data_focused="true" if is_first else "false",
188
190
  data_record_id=record_id,
189
191
  data_provider_id=provider_id,
192
+ onclick=focus_onclick,
190
193
  hx_get=preview_url,
191
194
  hx_vals=json.dumps({"record_id": record_id, "provider_id": provider_id}),
192
195
  hx_target=SelectionHtmlIds.as_selector(SelectionHtmlIds.PREVIEW_PANEL),
@@ -254,7 +257,7 @@ def _render_source_list(
254
257
 
255
258
  # Build table rows
256
259
  table_rows = []
257
- is_first_record = True
260
+ row_index = 0
258
261
  for group_key, records in grouped.items():
259
262
  # Add group header
260
263
  table_rows.append(_render_group_header(
@@ -268,9 +271,10 @@ def _render_source_list(
268
271
  )
269
272
  table_rows.append(_render_source_row(
270
273
  record, is_selected, add_url, remove_url, preview_url,
271
- is_first=is_first_record
274
+ is_first=(row_index == 0),
275
+ row_index=row_index,
272
276
  ))
273
- is_first_record = False
277
+ row_index += 1
274
278
 
275
279
  return Div(
276
280
  Table(
@@ -570,6 +570,9 @@ def render_selection_step(
570
570
  # Sortable initialization script (htmx integration)
571
571
  sortable_script,
572
572
 
573
+ # Script runner for OOB-triggered JS (duplicate rejection flash)
574
+ Div(id=SelectionHtmlIds.SCRIPT_RUNNER),
575
+
573
576
  id=SelectionHtmlIds.SOURCE_SELECTOR,
574
577
  cls=combine_classes(
575
578
  w.full,
@@ -62,6 +62,9 @@ class SelectionHtmlIds:
62
62
  SELECTION_FOOTER = "sd-selection-footer"
63
63
  SELECTION_STATS = "sd-selection-stats"
64
64
 
65
+ # Script runner (OOB container for flash feedback scripts)
66
+ SCRIPT_RUNNER = "sd-selection-script-runner"
67
+
65
68
  @staticmethod
66
69
  def _safe_id(
67
70
  value:str # Raw value to sanitize for HTML ID use
@@ -8,7 +8,7 @@ __all__ = ['DEBUG_SELECTION_STATE', 'WorkflowStateStore']
8
8
  # %% ../../nbs/routes/core.ipynb #sel-core-imports
9
9
  from typing import List, Dict, Any, Optional, Tuple, Union
10
10
 
11
- from fasthtml.common import Script
11
+ from fasthtml.common import Div, Script
12
12
 
13
13
  from cjm_workflow_state.state_store import SQLiteWorkflowStateStore
14
14
 
@@ -63,26 +63,46 @@ def _render_duplicate_flash(
63
63
  candidate_provider_id: str, # Provider ID of the row the user clicked
64
64
  existing_record_id: str, # Record ID of the conflicting selected row
65
65
  existing_provider_id: str, # Provider ID of the conflicting selected row
66
- ) -> Script: # OOB script element for flash animation
67
- """Render a self-removing Script that briefly flashes two source rows with error color."""
66
+ ) -> Div: # OOB Div with flash script (replaces previous via innerHTML swap)
67
+ """Render a fixed-ID container with flash script for two source rows."""
68
68
  row1 = SelectionHtmlIds.source_row(candidate_record_id, candidate_provider_id)
69
69
  row2 = SelectionHtmlIds.source_row(existing_record_id, existing_provider_id)
70
- return Script(f"""
70
+ return Div(
71
+ Script(f"""
71
72
  (function() {{
72
- var s = document.currentScript;
73
- var r1 = document.getElementById('{row1}');
74
- var r2 = document.getElementById('{row2}');
75
- [r1, r2].forEach(function(r) {{
76
- if (r) {{ r.classList.add('bg-error'); }}
77
- }});
78
- setTimeout(function() {{
73
+ function flash() {{
74
+ var r1 = document.getElementById('{row1}');
75
+ var r2 = document.getElementById('{row2}');
79
76
  [r1, r2].forEach(function(r) {{
80
- if (r) {{ r.classList.remove('bg-error'); }}
77
+ if (r) {{
78
+ r.style.transition = 'background-color 0.05s ease-in';
79
+ r.classList.add('bg-error');
80
+ }}
81
81
  }});
82
- if (s) {{ s.remove(); }}
83
- }}, 400);
82
+ setTimeout(function() {{
83
+ [r1, r2].forEach(function(r) {{
84
+ if (r) {{
85
+ r.style.transition = 'background-color 0.3s ease-out';
86
+ r.classList.remove('bg-error');
87
+ }}
88
+ }});
89
+ setTimeout(function() {{
90
+ [r1, r2].forEach(function(r) {{
91
+ if (r) {{ r.style.transition = ''; }}
92
+ }});
93
+ }}, 300);
94
+ }}, 600);
95
+ }}
96
+ // Defer until after HTMX finishes all OOB swaps
97
+ document.body.addEventListener('htmx:afterSettle', function handler() {{
98
+ document.body.removeEventListener('htmx:afterSettle', handler);
99
+ flash();
100
+ }});
84
101
  }})();
85
- """)
102
+ """),
103
+ id=SelectionHtmlIds.SCRIPT_RUNNER,
104
+ hx_swap_oob="innerHTML",
105
+ )
86
106
 
87
107
  # %% ../../nbs/routes/core.ipynb #3zll5oy1hsc
88
108
  def _get_active_source_tab(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: cjm-transcript-source-select
3
- Version: 0.0.3
3
+ Version: 0.0.5
4
4
  Summary: FastHTML source selection component for transcript decomposition workflows, with federated database browsing, drag-drop ordering, and keyboard navigation.
5
5
  Home-page: https://github.com/cj-mills/cjm-transcript-source-select
6
6
  Author: Christian J. Mills
@@ -109,48 +109,48 @@ graph LR
109
109
  components_source_browser --> services_source_utils
110
110
  components_source_browser --> html_ids
111
111
  components_step_renderer --> components_selection_queue
112
- components_step_renderer --> components_preview_panel
113
112
  components_step_renderer --> components_local_files
114
- components_step_renderer --> components_source_browser
115
113
  components_step_renderer --> components_helpers
116
- components_step_renderer --> utils
117
- components_step_renderer --> html_ids
118
114
  components_step_renderer --> models
115
+ components_step_renderer --> components_source_browser
116
+ components_step_renderer --> html_ids
117
+ components_step_renderer --> components_preview_panel
118
+ components_step_renderer --> utils
119
119
  routes_core --> components_step_renderer
120
- routes_core --> services_source
121
120
  routes_core --> models
122
- routes_core --> html_ids
123
- routes_core --> components_selection_queue
124
121
  routes_core --> components_source_browser
125
- routes_filtering --> services_source
126
- routes_filtering --> services_source_utils
122
+ routes_core --> services_source
123
+ routes_core --> components_selection_queue
124
+ routes_core --> html_ids
127
125
  routes_filtering --> routes_core
128
126
  routes_filtering --> components_source_browser
127
+ routes_filtering --> services_source_utils
129
128
  routes_filtering --> models
130
- routes_init --> routes_filtering
131
- routes_init --> routes_local_files
132
- routes_init --> services_source
133
- routes_init --> routes_tabs
134
- routes_init --> models
129
+ routes_filtering --> services_source
135
130
  routes_init --> routes_core
136
131
  routes_init --> routes_queue
132
+ routes_init --> models
133
+ routes_init --> services_source
134
+ routes_init --> routes_tabs
135
+ routes_init --> routes_filtering
136
+ routes_init --> routes_local_files
137
137
  routes_local_files --> services_source
138
138
  routes_local_files --> routes_core
139
139
  routes_local_files --> models
140
140
  routes_local_files --> components_local_files
141
141
  routes_queue --> routes_core
142
142
  routes_queue --> components_preview_panel
143
+ routes_queue --> models
143
144
  routes_queue --> services_source
144
145
  routes_queue --> services_source_utils
145
- routes_queue --> models
146
- routes_tabs --> routes_local_files
147
- routes_tabs --> components_source_browser
148
- routes_tabs --> services_source_utils
149
- routes_tabs --> services_source
150
146
  routes_tabs --> routes_core
151
147
  routes_tabs --> models
152
- routes_tabs --> components_local_files
148
+ routes_tabs --> services_source
153
149
  routes_tabs --> components_step_renderer
150
+ routes_tabs --> components_source_browser
151
+ routes_tabs --> routes_local_files
152
+ routes_tabs --> components_local_files
153
+ routes_tabs --> services_source_utils
154
154
  ```
155
155
 
156
156
  *51 cross-module dependencies detected*
@@ -203,8 +203,8 @@ def _render_duplicate_flash(
203
203
  candidate_provider_id: str, # Provider ID of the row the user clicked
204
204
  existing_record_id: str, # Record ID of the conflicting selected row
205
205
  existing_provider_id: str, # Provider ID of the conflicting selected row
206
- ) -> Script: # OOB script element for flash animation
207
- "Render a self-removing Script that briefly flashes two source rows with error color."
206
+ ) -> Div: # OOB Div with flash script (replaces previous via innerHTML swap)
207
+ "Render a fixed-ID container with flash script for two source rows."
208
208
  ```
209
209
 
210
210
  ``` python
@@ -1043,6 +1043,7 @@ def _render_source_row(
1043
1043
  remove_url: str, # URL for removing from queue
1044
1044
  preview_url: str, # URL for previewing content
1045
1045
  is_first: bool = False, # Whether this is the first row (gets initial focus)
1046
+ row_index: int = 0, # Index among selectable rows (for keyboard focus sync)
1046
1047
  ) -> Any: # Table row element
1047
1048
  "Render a single source row in the browser table."
1048
1049
  ```
@@ -1,7 +1,7 @@
1
1
  [DEFAULT]
2
2
  repo = cjm-transcript-source-select
3
3
  lib_name = cjm-transcript-source-select
4
- version = 0.0.3
4
+ version = 0.0.5
5
5
  min_python = 3.12
6
6
  license = apache2
7
7
  black_formatting = False
@@ -1 +0,0 @@
1
- __version__ = "0.0.3"