@jsenv/navi 0.10.1 → 0.11.0

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 (207) hide show
  1. package/dist/jsenv_navi.js +13858 -23295
  2. package/dist/jsenv_navi.js.map +1281 -0
  3. package/package.json +5 -7
  4. package/index.js +0 -122
  5. package/src/action_private_properties.js +0 -11
  6. package/src/action_proxy_test.html +0 -353
  7. package/src/action_run_states.js +0 -5
  8. package/src/actions.js +0 -1401
  9. package/src/browser_integration/browser_integration.js +0 -216
  10. package/src/browser_integration/document_back_and_forward.js +0 -17
  11. package/src/browser_integration/document_loading_signal.js +0 -100
  12. package/src/browser_integration/document_state_signal.js +0 -9
  13. package/src/browser_integration/document_url_signal.js +0 -9
  14. package/src/browser_integration/use_is_visited.js +0 -19
  15. package/src/browser_integration/via_history.js +0 -232
  16. package/src/browser_integration/via_navigation.js +0 -168
  17. package/src/components/action_execution/form_context.js +0 -5
  18. package/src/components/action_execution/render_actionable_component.jsx +0 -29
  19. package/src/components/action_execution/use_action.js +0 -99
  20. package/src/components/action_execution/use_execute_action.js +0 -177
  21. package/src/components/action_execution/use_run_on_mount.js +0 -9
  22. package/src/components/action_renderer.jsx +0 -125
  23. package/src/components/callout/callout.js +0 -990
  24. package/src/components/callout/callout_demo.html +0 -201
  25. package/src/components/callout/test_dynamic_positioning.html +0 -161
  26. package/src/components/callout/test_html_document_iframe.html +0 -182
  27. package/src/components/demos/0_button_demo.html +0 -707
  28. package/src/components/demos/10_column_reordering_debug.html +0 -277
  29. package/src/components/demos/11_table_selection_debug.html +0 -432
  30. package/src/components/demos/1_checkbox_demo.html +0 -754
  31. package/src/components/demos/2_input_textual_demo.html +0 -286
  32. package/src/components/demos/3_radio_demo.html +0 -874
  33. package/src/components/demos/4_select_demo.html +0 -100
  34. package/src/components/demos/5_list_scrollable_demo.html +0 -153
  35. package/src/components/demos/6_tablist_demo.html +0 -77
  36. package/src/components/demos/7_table_selection_demo.html +0 -176
  37. package/src/components/demos/8_table_fixed_headers_demo.html +0 -584
  38. package/src/components/demos/9_table_column_drag_demo.html +0 -325
  39. package/src/components/demos/action/0_button_demo.html +0 -204
  40. package/src/components/demos/action/10_shortcuts_demo.html +0 -189
  41. package/src/components/demos/action/11_nested_shortcuts_demo.xhtml +0 -401
  42. package/src/components/demos/action/1_input_text_demo.html +0 -876
  43. package/src/components/demos/action/2_form_multiple.html +0 -303
  44. package/src/components/demos/action/3_details_demo.html +0 -203
  45. package/src/components/demos/action/4_input_checkbox_demo.html +0 -731
  46. package/src/components/demos/action/5_input_checkbox_state_demo.html +0 -270
  47. package/src/components/demos/action/6_checkbox_list_demo.html +0 -341
  48. package/src/components/demos/action/7_radio_list_demo.html +0 -357
  49. package/src/components/demos/action/8_editable_demo.html +0 -431
  50. package/src/components/demos/action/9_link_demo.html +0 -194
  51. package/src/components/demos/demo.md +0 -0
  52. package/src/components/demos/route/basic/basic.html +0 -14
  53. package/src/components/demos/route/basic/basic_route_demo.jsx +0 -224
  54. package/src/components/demos/route/multi/multi.html +0 -14
  55. package/src/components/demos/route/multi/multi_route_demo.jsx +0 -277
  56. package/src/components/demos/ui_transition/0_action_renderer_ui_transition_demo.html +0 -695
  57. package/src/components/demos/ui_transition/1_nested_ui_transition_demo.html +0 -429
  58. package/src/components/demos/ui_transition/2_height_transition_test.html +0 -295
  59. package/src/components/details/details.jsx +0 -245
  60. package/src/components/details/summary_marker.jsx +0 -141
  61. package/src/components/edition/editable.jsx +0 -186
  62. package/src/components/error_boundary_context.js +0 -9
  63. package/src/components/field/README.md +0 -247
  64. package/src/components/field/button.jsx +0 -429
  65. package/src/components/field/checkbox_list.jsx +0 -185
  66. package/src/components/field/collect_form_element_values.js +0 -82
  67. package/src/components/field/custom_field.js +0 -106
  68. package/src/components/field/form.jsx +0 -209
  69. package/src/components/field/input.jsx +0 -16
  70. package/src/components/field/input_checkbox.jsx +0 -434
  71. package/src/components/field/input_radio.jsx +0 -432
  72. package/src/components/field/input_textual.jsx +0 -389
  73. package/src/components/field/label.jsx +0 -46
  74. package/src/components/field/radio_list.jsx +0 -183
  75. package/src/components/field/select.jsx +0 -256
  76. package/src/components/field/use_action_events.js +0 -132
  77. package/src/components/field/use_form_events.js +0 -59
  78. package/src/components/field/use_ui_state_controller.js +0 -506
  79. package/src/components/item_tracker/README.md +0 -461
  80. package/src/components/item_tracker/use_isolated_item_tracker.jsx +0 -209
  81. package/src/components/item_tracker/use_isolated_item_tracker_demo.html +0 -148
  82. package/src/components/item_tracker/use_isolated_item_tracker_demo.jsx +0 -460
  83. package/src/components/item_tracker/use_item_tracker.jsx +0 -143
  84. package/src/components/item_tracker/use_item_tracker_demo.html +0 -207
  85. package/src/components/item_tracker/use_item_tracker_demo.jsx +0 -216
  86. package/src/components/keyboard_shortcuts/active_keyboard_shortcuts.jsx +0 -87
  87. package/src/components/keyboard_shortcuts/aria_key_shortcuts.js +0 -61
  88. package/src/components/keyboard_shortcuts/keyboard_key_meta.js +0 -17
  89. package/src/components/keyboard_shortcuts/keyboard_shortcuts.js +0 -371
  90. package/src/components/keyboard_shortcuts/os.js +0 -9
  91. package/src/components/layout/demos/demo_flex.html +0 -638
  92. package/src/components/layout/demos/demo_layout_style_buttons.html +0 -351
  93. package/src/components/layout/demos/demo_layout_style_input.html +0 -226
  94. package/src/components/layout/demos/demo_layout_style_text.html +0 -514
  95. package/src/components/layout/flex.jsx +0 -109
  96. package/src/components/layout/layout_context.jsx +0 -3
  97. package/src/components/layout/spacing.jsx +0 -20
  98. package/src/components/layout/use_layout_style.js +0 -249
  99. package/src/components/link/link.jsx +0 -267
  100. package/src/components/link/link_with_icon.jsx +0 -52
  101. package/src/components/loader/loader_background.jsx +0 -372
  102. package/src/components/loader/loading_spinner.jsx +0 -68
  103. package/src/components/loader/network_speed.js +0 -83
  104. package/src/components/loader/rectangle_loading.jsx +0 -244
  105. package/src/components/props_composition/demos/demo_with_props_style.html +0 -81
  106. package/src/components/props_composition/with_props_class_name.js +0 -37
  107. package/src/components/props_composition/with_props_style.js +0 -26
  108. package/src/components/route.jsx +0 -19
  109. package/src/components/selection/selection.jsx +0 -1583
  110. package/src/components/svg/font_sized_svg.jsx +0 -59
  111. package/src/components/svg/icon_and_text.jsx +0 -21
  112. package/src/components/svg/svg_mask_overlay.jsx +0 -105
  113. package/src/components/table/drag/table_drag.jsx +0 -506
  114. package/src/components/table/resize/table_resize.jsx +0 -650
  115. package/src/components/table/resize/table_size.js +0 -43
  116. package/src/components/table/selection/table_selection.js +0 -106
  117. package/src/components/table/selection/table_selection.jsx +0 -203
  118. package/src/components/table/sticky/sticky_group.js +0 -354
  119. package/src/components/table/sticky/table_sticky.js +0 -25
  120. package/src/components/table/sticky/table_sticky.jsx +0 -501
  121. package/src/components/table/table.jsx +0 -721
  122. package/src/components/table/table_css.js +0 -211
  123. package/src/components/table/table_ui.jsx +0 -49
  124. package/src/components/table/use_cells_and_columns.js +0 -90
  125. package/src/components/table/use_object_array_to_cells.js +0 -46
  126. package/src/components/table/z_indexes.js +0 -23
  127. package/src/components/tablist/tablist.jsx +0 -99
  128. package/src/components/text/demos/demo_text_and_icon.html +0 -421
  129. package/src/components/text/overflow.jsx +0 -15
  130. package/src/components/text/text.jsx +0 -83
  131. package/src/components/text/text_and_count.jsx +0 -28
  132. package/src/components/ui_transition.jsx +0 -128
  133. package/src/components/use_auto_focus.js +0 -94
  134. package/src/components/use_batch_during_render.js +0 -33
  135. package/src/components/use_debounce_true.js +0 -31
  136. package/src/components/use_dependencies_diff.js +0 -35
  137. package/src/components/use_focus_group.js +0 -20
  138. package/src/components/use_initial_value.js +0 -78
  139. package/src/components/use_is_visited.js +0 -19
  140. package/src/components/use_ref_array.js +0 -38
  141. package/src/components/use_signal_sync.js +0 -50
  142. package/src/components/use_stable_callback.js +0 -68
  143. package/src/components/use_state_array.js +0 -47
  144. package/src/docs/actions.md +0 -250
  145. package/src/docs/demos/resource/action_status.jsx +0 -42
  146. package/src/docs/demos/resource/demo.md +0 -1
  147. package/src/docs/demos/resource/resource_demo_0.html +0 -84
  148. package/src/docs/demos/resource/resource_demo_10_post_gc.html +0 -364
  149. package/src/docs/demos/resource/resource_demo_11_describe_many.html +0 -362
  150. package/src/docs/demos/resource/resource_demo_2.html +0 -173
  151. package/src/docs/demos/resource/resource_demo_3_filtered_users.html +0 -415
  152. package/src/docs/demos/resource/resource_demo_4_details.html +0 -284
  153. package/src/docs/demos/resource/resource_demo_5_renderer_lazy.html +0 -115
  154. package/src/docs/demos/resource/resource_demo_6_gc.html +0 -217
  155. package/src/docs/demos/resource/resource_demo_7_child_gc.html +0 -240
  156. package/src/docs/demos/resource/resource_demo_8_proxy_gc.html +0 -319
  157. package/src/docs/demos/resource/resource_demo_9_describe_one.html +0 -472
  158. package/src/docs/demos/resource/tata.jsx +0 -3
  159. package/src/docs/demos/resource/toto.jsx +0 -3
  160. package/src/docs/demos/user_nav/user_nav.html +0 -12
  161. package/src/docs/demos/user_nav/user_nav.jsx +0 -330
  162. package/src/docs/resource_dependencies.md +0 -103
  163. package/src/docs/resource_with_params.md +0 -80
  164. package/src/navi_css_vars.js +0 -14
  165. package/src/notes.md +0 -34
  166. package/src/route/route.js +0 -596
  167. package/src/route/route.xtest.html +0 -228
  168. package/src/store/array_signal_store.js +0 -537
  169. package/src/store/local_storage_signal.js +0 -17
  170. package/src/store/resource_graph.js +0 -1304
  171. package/src/store/tests/resource_graph_autoreload_demo.html +0 -12
  172. package/src/store/tests/resource_graph_autoreload_demo.jsx +0 -964
  173. package/src/store/tests/resource_graph_dependencies.test_manual.js +0 -95
  174. package/src/store/value_in_local_storage.js +0 -187
  175. package/src/symbol_object_signal.js +0 -1
  176. package/src/use_action_data.js +0 -10
  177. package/src/use_action_status.js +0 -47
  178. package/src/utils/add_many_event_listeners.js +0 -15
  179. package/src/utils/array_add_remove.js +0 -61
  180. package/src/utils/array_signal.js +0 -15
  181. package/src/utils/compare_two_js_values.js +0 -172
  182. package/src/utils/execute_with_cleanup.js +0 -21
  183. package/src/utils/get_caller_info.js +0 -85
  184. package/src/utils/is_signal.js +0 -20
  185. package/src/utils/js_value_weak_map.js +0 -162
  186. package/src/utils/js_value_weak_map_demo.html +0 -690
  187. package/src/utils/merge_two_js_values.js +0 -53
  188. package/src/utils/stringify_for_display.js +0 -131
  189. package/src/utils/weak_effect.js +0 -48
  190. package/src/validation/constraints/confirm_constraint.js +0 -14
  191. package/src/validation/constraints/create_unique_value_constraint.js +0 -27
  192. package/src/validation/constraints/native_constraints.js +0 -338
  193. package/src/validation/constraints/readonly_constraint.js +0 -41
  194. package/src/validation/constraints/same_as_constraint.js +0 -42
  195. package/src/validation/constraints/single_space_constraint.js +0 -13
  196. package/src/validation/custom_constraint_validation.js +0 -793
  197. package/src/validation/custom_message.js +0 -18
  198. package/src/validation/demos/browser_style.png +0 -0
  199. package/src/validation/demos/demo_same_as_constraint.html +0 -259
  200. package/src/validation/demos/form_validation_demo.html +0 -142
  201. package/src/validation/demos/form_validation_demo_preact.html +0 -87
  202. package/src/validation/demos/form_validation_native_popover_demo.html +0 -168
  203. package/src/validation/demos/form_validation_vs_native_demo.html +0 -172
  204. package/src/validation/hooks/use_constraints.js +0 -23
  205. package/src/validation/hooks/use_custom_validation_ref.js +0 -73
  206. package/src/validation/hooks/use_validation_message.js +0 -19
  207. package/src/validation/input_change_effect.js +0 -106
@@ -1,249 +0,0 @@
1
- /**
2
- * Layout Style Hook
3
- *
4
- * This hook processes layout-related props and converts them into CSS styles.
5
- * It handles spacing (margin/padding), alignment (alignX/alignY), and expansion behavior.
6
- * The hook is context-aware and adapts behavior based on flex direction.
7
- *
8
- * Key features:
9
- * - Spacing: margin/padding with X/Y shortcuts and directional variants
10
- * - Alignment: alignX/alignY using align-self and auto margins
11
- * - Expansion: expand prop for taking remaining space (flexGrow or width: 100%)
12
- * - Context-aware: behavior changes based on FlexDirectionContext (row/column/none)
13
- */
14
-
15
- import { useContext } from "preact/hooks";
16
-
17
- import { FlexDirectionContext } from "./layout_context.jsx";
18
-
19
- /**
20
- * Converts layout props into CSS styles
21
- * @param {Object} props - Component props containing layout properties
22
- * @param {string|number} [props.margin] - All-sides margin
23
- * @param {string|number} [props.marginX] - Horizontal margin (left + right)
24
- * @param {string|number} [props.marginY] - Vertical margin (top + bottom)
25
- * @param {string|number} [props.marginLeft] - Left margin
26
- * @param {string|number} [props.marginRight] - Right margin
27
- * @param {string|number} [props.marginTop] - Top margin
28
- * @param {string|number} [props.marginBottom] - Bottom margin
29
- * @param {string|number} [props.padding] - All-sides padding
30
- * @param {string|number} [props.paddingX] - Horizontal padding (left + right)
31
- * @param {string|number} [props.paddingY] - Vertical padding (top + bottom)
32
- * @param {string|number} [props.paddingLeft] - Left padding
33
- * @param {string|number} [props.paddingRight] - Right padding
34
- * @param {string|number} [props.paddingTop] - Top padding
35
- * @param {string|number} [props.paddingBottom] - Bottom padding
36
- * @param {"start"|"center"|"end"|"stretch"} [props.alignX] - Horizontal alignment
37
- * @param {"start"|"center"|"end"|"stretch"} [props.alignY] - Vertical alignment
38
- * @param {boolean} [props.expandX] - Whether element should expand horizontally to fill available space
39
- * @param {boolean} [props.expandY] - Whether element should expand vertically to fill available space
40
- * @returns {Object} Object with categorized styles: { margin, padding, alignment, expansion, all }
41
- */
42
- export const useLayoutStyle = (props) => {
43
- const flexDirection = useContext(FlexDirectionContext);
44
-
45
- const marginStyle = {};
46
- const paddingStyle = {};
47
- const alignmentStyle = {};
48
- const expansionStyle = {};
49
-
50
- spacing: {
51
- outer_spacing: {
52
- const margin = props.margin;
53
- const marginX = props.marginX;
54
- const marginY = props.marginY;
55
- const marginLeft = props.marginLeft;
56
- const marginRight = props.marginRight;
57
- const marginTop = props.marginTop;
58
- const marginBottom = props.marginBottom;
59
- delete props.margin;
60
- delete props.marginX;
61
- delete props.marginY;
62
- delete props.marginLeft;
63
- delete props.marginRight;
64
- delete props.marginTop;
65
- delete props.marginBottom;
66
-
67
- if (margin !== undefined) {
68
- marginStyle.margin = margin;
69
- }
70
- if (marginLeft !== undefined) {
71
- marginStyle.marginLeft = marginLeft;
72
- } else if (marginX !== undefined) {
73
- marginStyle.marginLeft = marginX;
74
- }
75
- if (marginRight !== undefined) {
76
- marginStyle.marginRight = marginRight;
77
- } else if (marginX !== undefined) {
78
- marginStyle.marginRight = marginX;
79
- }
80
- if (marginTop !== undefined) {
81
- marginStyle.marginTop = marginTop;
82
- } else if (marginY !== undefined) {
83
- marginStyle.marginTop = marginY;
84
- }
85
- if (marginBottom !== undefined) {
86
- marginStyle.marginBottom = marginBottom;
87
- } else if (marginY !== undefined) {
88
- marginStyle.marginBottom = marginY;
89
- }
90
- }
91
- inner_spacing: {
92
- const padding = props.padding;
93
- const paddingX = props.paddingX;
94
- const paddingY = props.paddingY;
95
- const paddingLeft = props.paddingLeft;
96
- const paddingRight = props.paddingRight;
97
- const paddingTop = props.paddingTop;
98
- const paddingBottom = props.paddingBottom;
99
- delete props.padding;
100
- delete props.paddingX;
101
- delete props.paddingY;
102
- delete props.paddingLeft;
103
- delete props.paddingRight;
104
- delete props.paddingTop;
105
- delete props.paddingBottom;
106
-
107
- if (padding !== undefined) {
108
- paddingStyle.padding = padding;
109
- }
110
- if (paddingLeft !== undefined) {
111
- paddingStyle.paddingLeft = paddingLeft;
112
- } else if (paddingX !== undefined) {
113
- paddingStyle.paddingLeft = paddingX;
114
- }
115
- if (paddingRight !== undefined) {
116
- paddingStyle.paddingRight = paddingRight;
117
- } else if (paddingX !== undefined) {
118
- paddingStyle.paddingRight = paddingX;
119
- }
120
- if (paddingTop !== undefined) {
121
- paddingStyle.paddingTop = paddingTop;
122
- } else if (paddingY !== undefined) {
123
- paddingStyle.paddingTop = paddingY;
124
- }
125
- if (paddingBottom !== undefined) {
126
- paddingStyle.paddingBottom = paddingBottom;
127
- } else if (paddingY !== undefined) {
128
- paddingStyle.paddingBottom = paddingY;
129
- }
130
- }
131
- }
132
-
133
- align: {
134
- const alignX = props.alignX;
135
- const alignY = props.alignY;
136
- delete props.alignX;
137
- delete props.alignY;
138
-
139
- // flex
140
- if (flexDirection === "row") {
141
- // In row direction: alignX controls justify-content, alignY controls align-self
142
- if (alignY !== undefined && alignY !== "start") {
143
- alignmentStyle.alignSelf = alignY;
144
- }
145
- // For row, alignX uses auto margins for positioning
146
- // NOTE: Auto margins only work effectively for positioning individual items.
147
- // When multiple adjacent items have the same auto margin alignment (e.g., alignX="end"),
148
- // only the first item will be positioned as expected because subsequent items
149
- // will be positioned relative to the previous item's margins, not the container edge.
150
- if (alignX !== undefined) {
151
- if (alignX === "start") {
152
- alignmentStyle.marginRight = "auto";
153
- } else if (alignX === "end") {
154
- alignmentStyle.marginLeft = "auto";
155
- } else if (alignX === "center") {
156
- alignmentStyle.marginLeft = "auto";
157
- alignmentStyle.marginRight = "auto";
158
- }
159
- }
160
- } else if (flexDirection === "column") {
161
- // In column direction: alignX controls align-self, alignY uses auto margins
162
- if (alignX !== undefined && alignX !== "start") {
163
- alignmentStyle.alignSelf = alignX;
164
- }
165
- // For column, alignY uses auto margins for positioning
166
- // NOTE: Same auto margin limitation applies - multiple adjacent items with
167
- // the same alignY won't all position relative to container edges.
168
- if (alignY !== undefined) {
169
- if (alignY === "start") {
170
- alignmentStyle.marginBottom = "auto";
171
- } else if (alignY === "end") {
172
- alignmentStyle.marginTop = "auto";
173
- } else if (alignY === "center") {
174
- alignmentStyle.marginTop = "auto";
175
- alignmentStyle.marginBottom = "auto";
176
- }
177
- }
178
- }
179
- // non flex
180
- else {
181
- if (alignX === "start") {
182
- alignmentStyle.marginRight = "auto";
183
- } else if (alignX === "center") {
184
- alignmentStyle.marginLeft = "auto";
185
- alignmentStyle.marginRight = "auto";
186
- } else if (alignX === "end") {
187
- alignmentStyle.marginLeft = "auto";
188
- }
189
-
190
- if (alignY === "start") {
191
- alignmentStyle.marginBottom = "auto";
192
- } else if (alignY === "center") {
193
- alignmentStyle.marginTop = "auto";
194
- alignmentStyle.marginBottom = "auto";
195
- } else if (alignY === "end") {
196
- alignmentStyle.marginTop = "auto";
197
- }
198
- }
199
- }
200
-
201
- expand: {
202
- const expand = props.expand;
203
- delete props.expand;
204
-
205
- expandX: {
206
- const expandX = props.expandX || expand;
207
- delete props.expandX;
208
- if (expandX) {
209
- if (flexDirection === "row") {
210
- expansionStyle.flexGrow = 1; // Grow horizontally in row
211
- } else if (flexDirection === "column") {
212
- expansionStyle.width = "100%"; // Take full width in column
213
- } else {
214
- expansionStyle.width = "100%"; // Take full width outside flex
215
- }
216
- }
217
- }
218
-
219
- expandY: {
220
- const expandY = props.expandY || expand;
221
- delete props.expandY;
222
- if (expandY) {
223
- if (flexDirection === "row") {
224
- expansionStyle.height = "100%"; // Take full height in row
225
- } else if (flexDirection === "column") {
226
- expansionStyle.flexGrow = 1; // Grow vertically in column
227
- } else {
228
- expansionStyle.height = "100%"; // Take full height outside flex
229
- }
230
- }
231
- }
232
- }
233
-
234
- // Merge all styles for convenience
235
- const allStyles = {
236
- ...marginStyle,
237
- ...paddingStyle,
238
- ...alignmentStyle,
239
- ...expansionStyle,
240
- };
241
-
242
- return {
243
- margin: marginStyle,
244
- padding: paddingStyle,
245
- alignment: alignmentStyle,
246
- expansion: expansionStyle,
247
- all: allStyles,
248
- };
249
- };
@@ -1,267 +0,0 @@
1
- import { forwardRef } from "preact/compat";
2
- import {
3
- useContext,
4
- useImperativeHandle,
5
- useLayoutEffect,
6
- useRef,
7
- } from "preact/hooks";
8
-
9
- import { useIsVisited } from "../../browser_integration/use_is_visited.js";
10
- import { closeValidationMessage } from "../../validation/custom_constraint_validation.js";
11
- import { useConstraints } from "../../validation/hooks/use_constraints.js";
12
- import { renderActionableComponent } from "../action_execution/render_actionable_component.jsx";
13
- import { useRequestedActionStatus } from "../field/use_action_events.js";
14
- import { useKeyboardShortcuts } from "../keyboard_shortcuts/keyboard_shortcuts.js";
15
- import { useLayoutStyle } from "../layout/use_layout_style.js";
16
- import { LoadableInlineElement } from "../loader/loader_background.jsx";
17
- import { withPropsClassName } from "../props_composition/with_props_class_name.js";
18
- import { withPropsStyle } from "../props_composition/with_props_style.js";
19
- import {
20
- SelectionContext,
21
- useSelectableElement,
22
- } from "../selection/selection.jsx";
23
- import { useTypographyStyle } from "../text/text.jsx";
24
- import { useAutoFocus } from "../use_auto_focus.js";
25
-
26
- /*
27
- * Apply opacity to child content, not the link element itself.
28
- *
29
- * Why not apply opacity directly to .navi_link?
30
- * - Would make focus outlines semi-transparent too (accessibility issue)
31
- * - We want dimmed text but full-opacity focus indicators for visibility
32
- *
33
- * This approach dims the content while preserving focus outline visibility.
34
- */
35
- import.meta.css = /* css */ `
36
- .navi_link {
37
- border-radius: 2px;
38
- }
39
- /* Focus */
40
- .navi_link:focus {
41
- position: relative;
42
- z-index: 1; /* Ensure focus outline is above other elements */
43
- }
44
- /* Visited */
45
- .navi_link[data-visited] {
46
- color: light-dark(#6a1b9a, #ab47bc);
47
- }
48
- /* Selected */
49
- .navi_link[aria-selected] {
50
- position: relative;
51
- }
52
- .navi_link[aria-selected="true"] {
53
- background-color: light-dark(#bbdefb, #2563eb);
54
- }
55
- .navi_link[aria-selected] input[type="checkbox"] {
56
- position: absolute;
57
- opacity: 0;
58
- }
59
- /* Active */
60
- .navi_link[data-active] {
61
- font-weight: bold;
62
- }
63
- /* Readonly */
64
- .navi_link[data-readonly] > * {
65
- opacity: 0.5;
66
- }
67
- /* Disabled */
68
- .navi_link[inert] {
69
- pointer-events: none;
70
- }
71
- .navi_link[inert] > * {
72
- opacity: 0.5;
73
- }
74
- `;
75
-
76
- export const Link = forwardRef((props, ref) => {
77
- return renderActionableComponent(props, ref, {
78
- Basic: LinkBasic,
79
- WithAction: LinkWithAction,
80
- });
81
- });
82
-
83
- const LinkBasic = forwardRef((props, ref) => {
84
- const selectionContext = useContext(SelectionContext);
85
- if (selectionContext) {
86
- return <LinkWithSelection ref={ref} {...props} />;
87
- }
88
- return <LinkPlain ref={ref} {...props} />;
89
- });
90
- const LinkPlain = forwardRef((props, ref) => {
91
- const {
92
- loading,
93
- readOnly,
94
- disabled,
95
- children,
96
- autoFocus,
97
- active,
98
- visited,
99
- spaceToClick = true,
100
- constraints = [],
101
- onClick,
102
- onKeyDown,
103
- href,
104
-
105
- // visual
106
- className,
107
- style,
108
- ...rest
109
- } = props;
110
- const innerRef = useRef();
111
- useImperativeHandle(ref, () => innerRef.current);
112
- const isVisited = useIsVisited(href);
113
-
114
- useAutoFocus(innerRef, autoFocus);
115
- useConstraints(innerRef, constraints);
116
- const shouldDimColor = readOnly || disabled;
117
- useDimColorWhen(innerRef, shouldDimColor);
118
-
119
- const innerClassName = withPropsClassName("navi_link", className);
120
- const { all } = useLayoutStyle(rest);
121
- const innerStyle = withPropsStyle(
122
- {
123
- ...all,
124
- ...useTypographyStyle(rest),
125
- },
126
- style,
127
- );
128
-
129
- return (
130
- <LoadableInlineElement
131
- loading={loading}
132
- color="light-dark(#355fcc, #3b82f6)"
133
- >
134
- <a
135
- {...rest}
136
- ref={innerRef}
137
- href={href}
138
- className={innerClassName}
139
- style={innerStyle}
140
- aria-busy={loading}
141
- inert={disabled}
142
- data-disabled={disabled ? "" : undefined}
143
- data-readonly={readOnly ? "" : undefined}
144
- data-active={active ? "" : undefined}
145
- data-visited={visited || isVisited ? "" : undefined}
146
- onClick={(e) => {
147
- closeValidationMessage(e.target, "click");
148
- if (readOnly) {
149
- e.preventDefault();
150
- return;
151
- }
152
- onClick?.(e);
153
- }}
154
- onKeyDown={(e) => {
155
- if (spaceToClick && e.key === " ") {
156
- e.preventDefault(); // Prevent page scroll
157
- if (!readOnly && !disabled) {
158
- e.target.click();
159
- }
160
- }
161
- onKeyDown?.(e);
162
- }}
163
- >
164
- {children}
165
- </a>
166
- </LoadableInlineElement>
167
- );
168
- });
169
- const LinkWithSelection = forwardRef((props, ref) => {
170
- const { selection, selectionController } = useContext(SelectionContext);
171
- const { value = props.href, children, ...rest } = props;
172
- const innerRef = useRef();
173
- useImperativeHandle(ref, () => innerRef.current);
174
- const { selected } = useSelectableElement(innerRef, {
175
- selection,
176
- selectionController,
177
- });
178
-
179
- return (
180
- <LinkPlain
181
- {...rest}
182
- ref={innerRef}
183
- data-value={value}
184
- aria-selected={selected}
185
- >
186
- {children}
187
- </LinkPlain>
188
- );
189
- });
190
-
191
- /*
192
- * Custom hook to apply semi-transparent color when an element should be dimmed.
193
- *
194
- * Why we do it this way:
195
- * 1. **Precise timing**: Captures the element's natural color exactly when transitioning
196
- * from normal to dimmed state (not before, not after)
197
- * 2. **Avoids CSS inheritance issues**: CSS `currentColor` and `color-mix()` don't work
198
- * reliably for creating true transparency that matches `opacity: 0.5`
199
- * 3. **Performance**: Only executes when the dimmed state actually changes, not on every render
200
- * 4. **Color accuracy**: Uses `color(from ... / 0.5)` syntax to preserve the exact visual
201
- * appearance of `opacity: 0.5` but applied only to color
202
- * 5. **Works with any color**: Handles default blue, visited purple, inherited colors, etc.
203
- * 6. **Maintains focus outline**: Since we only dim the text color, focus outlines remain
204
- * fully visible for accessibility
205
- */
206
- const useDimColorWhen = (elementRef, shouldDim) => {
207
- const shouldDimPreviousRef = useRef();
208
- useLayoutEffect(() => {
209
- const element = elementRef.current;
210
- const shouldDimPrevious = shouldDimPreviousRef.current;
211
-
212
- if (shouldDim === shouldDimPrevious) {
213
- return;
214
- }
215
- shouldDimPreviousRef.current = shouldDim;
216
- if (shouldDim) {
217
- // Capture color just before applying disabled state
218
- const computedStyle = getComputedStyle(element);
219
- const currentColor = computedStyle.color;
220
- element.style.color = `color(from ${currentColor} srgb r g b / 0.5)`;
221
- } else {
222
- // Clear the inline style to let CSS take over
223
- element.style.color = "";
224
- }
225
- });
226
- };
227
-
228
- const LinkWithAction = forwardRef((props, ref) => {
229
- const {
230
- shortcuts = [],
231
- readOnly,
232
- onActionPrevented,
233
- onActionStart,
234
- onActionAbort,
235
- onActionError,
236
- onActionEnd,
237
- children,
238
- loading,
239
- ...rest
240
- } = props;
241
- const innerRef = useRef();
242
- useImperativeHandle(ref, () => innerRef.current);
243
- const { actionPending } = useRequestedActionStatus(innerRef);
244
- const innerLoading = Boolean(loading || actionPending);
245
-
246
- useKeyboardShortcuts(innerRef, shortcuts, {
247
- onActionPrevented,
248
- onActionStart,
249
- onActionAbort,
250
- onActionError,
251
- onActionEnd,
252
- });
253
-
254
- return (
255
- <LinkBasic
256
- {...rest}
257
- ref={innerRef}
258
- loading={innerLoading}
259
- readOnly={readOnly || actionPending}
260
- data-readonly-silent={actionPending && !readOnly ? "" : undefined}
261
- /* When we have keyboard shortcuts the link outline is visible on focus (not solely on focus-visible) */
262
- data-focus-visible=""
263
- >
264
- {children}
265
- </LinkBasic>
266
- );
267
- });
@@ -1,52 +0,0 @@
1
- import { FontSizedSvg } from "../svg/font_sized_svg.jsx";
2
- import { Link } from "./link.jsx";
3
-
4
- import.meta.css = /* css */ `
5
- .link_with_icon {
6
- white-space: nowrap;
7
- align-items: center;
8
- gap: 0.3em;
9
- min-width: 0;
10
- display: inline-flex;
11
- flex-grow: 1;
12
- }
13
- `;
14
-
15
- export const LinkWithIcon = ({
16
- icon,
17
- isCurrent,
18
- children,
19
- className = "",
20
- ...rest
21
- }) => {
22
- return (
23
- <Link
24
- className={["link_with_icon", ...className.split(" ")].join(" ")}
25
- {...rest}
26
- >
27
- <FontSizedSvg>{icon}</FontSizedSvg>
28
- {isCurrent && (
29
- <FontSizedSvg>
30
- <CurrentSvg />
31
- </FontSizedSvg>
32
- )}
33
- {children}
34
- </Link>
35
- );
36
- };
37
-
38
- const CurrentSvg = () => {
39
- return (
40
- <svg
41
- viewBox="0 0 16 16"
42
- width="100%"
43
- height="100%"
44
- xmlns="http://www.w3.org/2000/svg"
45
- >
46
- <path
47
- d="m 8 0 c -3.3125 0 -6 2.6875 -6 6 c 0.007812 0.710938 0.136719 1.414062 0.386719 2.078125 l -0.015625 -0.003906 c 0.636718 1.988281 3.78125 5.082031 5.625 6.929687 h 0.003906 v -0.003906 c 1.507812 -1.507812 3.878906 -3.925781 5.046875 -5.753906 c 0.261719 -0.414063 0.46875 -0.808594 0.585937 -1.171875 l -0.019531 0.003906 c 0.25 -0.664063 0.382813 -1.367187 0.386719 -2.078125 c 0 -3.3125 -2.683594 -6 -6 -6 z m 0 3.691406 c 1.273438 0 2.308594 1.035156 2.308594 2.308594 s -1.035156 2.308594 -2.308594 2.308594 c -1.273438 -0.003906 -2.304688 -1.035156 -2.304688 -2.308594 c -0.003906 -1.273438 1.03125 -2.304688 2.304688 -2.308594 z m 0 0"
48
- fill="#2e3436"
49
- />
50
- </svg>
51
- );
52
- };