tramway 3.1 → 3.1.1.1

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.
@@ -15,7 +15,7 @@ module Tramway
15
15
  }.freeze
16
16
 
17
17
  def selected_item_classes
18
- classes = 'flex justify-center items-center font-medium py-1 px-2 rounded-md ' \
18
+ classes = 'flex flex-none justify-center items-center font-medium py-1 px-2 rounded-md ' \
19
19
  'bg-zinc-900 text-zinc-50 shadow-sm hover:bg-zinc-800 cursor-pointer ' \
20
20
  'space-x-1 selected-option ' + SIZE_CLASSES[size].to_s
21
21
 
@@ -3,10 +3,10 @@
3
3
  = component('tramway/form/label', for: @for, class: 'mb-0') do
4
4
  = @label
5
5
  %div{ role: :combobox, data: tramway_select_hash, id: "#{@for}_tramway_select", class: tramway_select_classes }
6
- - classes = "#{size_class(:tramway_select_input)} #{select_base_classes}"
7
- .flex.flex-end.justify-between{ data: dropdown_data, **dropdown_options }
8
- .flex.flex-row.flex-nowrap.overflow-x-auto.space-x-1.w-full{ data: { "tramway-select-target" => "showSelectedArea" } }
9
- .flex.flex-col.justify-center
6
+ - selected_items_classes = ['flex flex-row w-full', multiple ? 'flex-wrap gap-1 min-w-0' : 'flex-nowrap overflow-x-auto space-x-1'].join(' ')
7
+ .flex.flex-end.justify-between.gap-1{ data: dropdown_data, **dropdown_options }
8
+ %div{ class: selected_items_classes, data: { "tramway-select-target" => "showSelectedArea" } }
9
+ .flex.flex-col.justify-center.shrink-0
10
10
  .caret-down{ data: { "tramway-select-target" => "caretDown" } }
11
11
  = component 'tramway/form/tramway_select/caret', size:, direction: :down
12
12
  .caret-up.hidden{ data: { "tramway-select-target" => "caretUp" } }
@@ -73,11 +73,16 @@ module Tramway
73
73
  end
74
74
 
75
75
  def input_classes
76
- "#{size_class(:tramway_select_input)} #{select_base_classes}"
76
+ "#{tramway_select_size_class} #{select_base_classes}"
77
77
  end
78
78
 
79
79
  private
80
80
 
81
+ def tramway_select_size_class
82
+ classes = size_class(:tramway_select_input)
83
+ multiple ? classes.gsub(/\bh-/, 'min-h-') : classes
84
+ end
85
+
81
86
  def action
82
87
  'click->tramway-select#toggleDropdown'
83
88
  end
@@ -100,7 +105,7 @@ module Tramway
100
105
  options:,
101
106
  attribute:,
102
107
  input:,
103
- size_class: size_class(:tramway_select_input)
108
+ size_class: tramway_select_size_class
104
109
  )
105
110
  end
106
111
 
@@ -0,0 +1,12 @@
1
+ - if normalized_event == :onclick
2
+ %div{ class: wrapper_classes, **wrapper_options }
3
+ %div{ class: trigger_classes, data: trigger_data }
4
+ = content
5
+ %span{ class: tooltip_classes, role: 'tooltip', data: tooltip_data }
6
+ = text
7
+ - else
8
+ %div{ class: wrapper_classes, **wrapper_options }
9
+ %div{ class: trigger_classes }
10
+ = content
11
+ %span{ class: tooltip_classes, role: 'tooltip', data: tooltip_data }
12
+ = text
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tramway
4
+ # Default Tramway tooltip
5
+ #
6
+ class TooltipComponent < Tramway::BaseComponent
7
+ EVENTS = %i[hover onclick].freeze
8
+
9
+ option :text
10
+ option :event, default: -> { :hover }
11
+ option :options, optional: true, default: -> { {} }
12
+
13
+ def wrapper_classes
14
+ (base_wrapper_classes + options[:class].to_s.split).compact.join(' ')
15
+ end
16
+
17
+ def trigger_classes
18
+ {
19
+ hover: %w[peer inline-flex w-fit],
20
+ onclick: %w[inline-flex w-fit cursor-pointer]
21
+ }[normalized_event].join(' ')
22
+ end
23
+
24
+ def wrapper_data
25
+ return options[:data] || {} unless normalized_event == :onclick
26
+
27
+ (options[:data] || {}).merge(
28
+ controller: merged_controller,
29
+ action: merged_action
30
+ )
31
+ end
32
+
33
+ def wrapper_options
34
+ options.except(:class, :data).merge(data: wrapper_data)
35
+ end
36
+
37
+ def trigger_data
38
+ return {} unless normalized_event == :onclick
39
+
40
+ { action: 'click->tramway-tooltip#toggle' }
41
+ end
42
+
43
+ def tooltip_data
44
+ return {} unless normalized_event == :onclick
45
+
46
+ { 'tramway-tooltip-target': 'panel' }
47
+ end
48
+
49
+ def tooltip_classes
50
+ (base_tooltip_classes + event_tooltip_classes).join(' ')
51
+ end
52
+
53
+ def normalized_event
54
+ event.to_sym
55
+ end
56
+
57
+ private
58
+
59
+ def before_render
60
+ return if EVENTS.include?(normalized_event)
61
+
62
+ raise ArgumentError, "Invalid event: #{event}. Valid events are :hover, :onclick."
63
+ end
64
+
65
+ def base_wrapper_classes
66
+ %w[relative inline-flex w-fit]
67
+ end
68
+
69
+ def base_tooltip_classes
70
+ %w[
71
+ absolute bottom-full left-1/2 z-50 mb-2 w-max min-w-40 max-w-sm -translate-x-1/2 rounded-md border
72
+ border-zinc-800 bg-zinc-950 px-2.5 py-1.5 text-xs font-medium leading-5 text-zinc-50 shadow-lg
73
+ ]
74
+ end
75
+
76
+ def event_tooltip_classes
77
+ if normalized_event == :hover
78
+ return %w[pointer-events-none invisible opacity-0 transition-opacity peer-hover:visible
79
+ peer-hover:opacity-100]
80
+ end
81
+
82
+ %w[hidden]
83
+ end
84
+
85
+ def merged_controller
86
+ [options.dig(:data, :controller), 'tramway-tooltip'].compact_blank.join(' ')
87
+ end
88
+
89
+ def merged_action
90
+ [options.dig(:data, :action), 'click@window->tramway-tooltip#closeOnClickOutside'].compact_blank.join(' ')
91
+ end
92
+ end
93
+ end
@@ -21,4 +21,4 @@
21
21
  = f.submit t('tramway.actions.save')
22
22
  = tramway_button text: t('tramway.actions.cancel'),
23
23
  path: public_send(@entity.index_helper_method),
24
- type: :fear
24
+ type: :inverse
@@ -236,7 +236,7 @@ module.exports = {
236
236
  'disabled:opacity-50',
237
237
  'h-10',
238
238
 
239
- 'hover:bg-zinc-250',
239
+ 'hover:bg-zinc-200',
240
240
  'bg-zinc-50',
241
241
  'text-zinc-950',
242
242
  'bg-zinc-950',
@@ -318,6 +318,7 @@ module.exports = {
318
318
  'flex-wrap',
319
319
  'flex-row-reverse',
320
320
  'flex-auto',
321
+ 'flex-none',
321
322
  'flex-initial',
322
323
  'justify-between',
323
324
  'justify-end',
@@ -333,6 +334,10 @@ module.exports = {
333
334
  'w-fit',
334
335
  'w-8',
335
336
  'min-w-96',
337
+ 'min-w-0',
338
+ 'min-h-10',
339
+ 'min-h-12',
340
+ 'min-h-15',
336
341
  'max-w-full',
337
342
 
338
343
  // === Spacing utilities ===
@@ -364,6 +369,29 @@ module.exports = {
364
369
  'placeholder-gray-500',
365
370
 
366
371
  // === Button and badge helpers ===
372
+ 'peer',
373
+ 'peer-hover:visible',
374
+ 'peer-hover:opacity-100',
375
+ 'group',
376
+ 'group-hover:visible',
377
+ 'group-hover:opacity-100',
378
+ 'open:block',
379
+ 'bottom-full',
380
+ 'left-1/2',
381
+ '-translate-x-1/2',
382
+ 'z-50',
383
+ 'mb-2',
384
+ 'w-max',
385
+ 'min-w-40',
386
+ 'max-w-sm',
387
+ 'invisible',
388
+ 'opacity-0',
389
+ 'transition-opacity',
390
+ 'pointer-events-none',
391
+ 'leading-5',
392
+ 'list-none',
393
+ 'cursor-pointer',
394
+ 'py-1.5',
367
395
  'rounded',
368
396
  'rounded-full',
369
397
  'rounded-xl',
@@ -374,10 +402,27 @@ module.exports = {
374
402
  'h-fit',
375
403
  'gap-1',
376
404
  'h-10',
405
+ 'px-2.5',
406
+ 'py-0.5',
377
407
  'shadow-md',
378
408
  'shadow-inner',
379
409
  'shadow-lg',
410
+ 'shadow',
380
411
  'h-12',
412
+ 'border-transparent',
413
+ 'focus:ring-2',
414
+ 'focus:ring-zinc-400',
415
+ 'focus:ring-offset-2',
416
+ 'focus:ring-offset-zinc-950',
417
+ 'hover:bg-zinc-800/80',
418
+ 'border-green-800',
419
+ 'border-orange-800',
420
+ 'border-red-800',
421
+ 'border-violet-800',
422
+ 'border-indigo-800',
423
+ 'border-yellow-800',
424
+ 'border-blue-800',
425
+ 'border-gray-800',
381
426
 
382
427
  // === Shadcn UI button styles ===
383
428
  'bg-green-600',
@@ -55,16 +55,8 @@ module Tramway
55
55
  @controllers_index_path ||= File.join(destination_root, 'app/javascript/controllers/index.js')
56
56
  end
57
57
 
58
- def importmap_tramway_select_pin
59
- 'pin "@tramway/tramway-select", to: "tramway/tramway-select_controller.js"'
60
- end
61
-
62
- def importmap_table_row_preview_pin
63
- 'pin "@tramway/table-row-preview", to: "tramway/table_row_preview_controller.js"'
64
- end
65
-
66
- def importmap_ui_checkbox_pin
67
- 'pin "@tramway/checkbox", to: "tramway/ui_checkbox_controller.js"'
58
+ def importmap_tramway_pin
59
+ 'pin "@tramway/tramway", to: "tramway/tramway.js"'
68
60
  end
69
61
 
70
62
  def importmap_tailwind_requirements
@@ -80,17 +72,13 @@ module Tramway
80
72
  def importmap_tramway_pins
81
73
  [
82
74
  importmap_tailwind_requirements,
83
- importmap_tramway_select_pin,
84
- importmap_table_row_preview_pin,
85
- importmap_ui_checkbox_pin
75
+ importmap_tramway_pin
86
76
  ]
87
77
  end
88
78
 
89
79
  def stimulus_controller_imports
90
80
  [
91
- 'import { TramwaySelect } from "@tramway/tramway-select"',
92
- 'import { TableRowPreview } from "@tramway/table-row-preview"',
93
- 'import { UiCheckbox } from "@tramway/checkbox"'
81
+ 'import { TramwaySelect, TableRowPreview, UiCheckbox, Tooltip } from "@tramway/tramway"'
94
82
  ]
95
83
  end
96
84
 
@@ -98,7 +86,8 @@ module Tramway
98
86
  [
99
87
  "application.register('tramway-select', TramwaySelect)",
100
88
  "application.register('table-row-preview', TableRowPreview)",
101
- "application.register('ui--checkbox', UiCheckbox)"
89
+ "application.register('ui--checkbox', UiCheckbox)",
90
+ "application.register('tramway-tooltip', Tooltip)"
102
91
  ]
103
92
  end
104
93
 
@@ -162,7 +151,7 @@ module Tramway
162
151
 
163
152
  # rubocop:disable Metrics/MethodLength
164
153
  def append_missing_imports(content)
165
- content = normalize_checkbox_import(content)
154
+ content = remove_legacy_stimulus_imports(content)
166
155
  missing_imports = stimulus_controller_imports.reject { |line| content.include?(line) }
167
156
  return content if missing_imports.empty?
168
157
 
@@ -198,21 +187,44 @@ module Tramway
198
187
  updated
199
188
  end
200
189
 
201
- def normalize_checkbox_import(content)
202
- content.gsub(
190
+ def remove_legacy_stimulus_imports(content)
191
+ legacy_imports = [
192
+ 'import { TramwaySelect } from "@tramway/tramway-select"',
193
+ 'import { TableRowPreview } from "@tramway/table-row-preview"',
194
+ 'import { UiCheckbox } from "@tramway/checkbox"',
203
195
  'import { UiCheckbox } from "@tramway/ui-checkbox"',
204
- 'import { UiCheckbox } from "@tramway/checkbox"'
205
- )
196
+ 'import { Tooltip } from "@tramway/tooltip"'
197
+ ]
198
+
199
+ content.each_line.reject { |line| legacy_imports.include?(line.strip) }.join
206
200
  end
207
201
 
208
- def normalize_checkbox_pin(content)
209
- content.gsub(
202
+ def remove_legacy_importmap_pins(content)
203
+ content.each_line.reject { |line| legacy_importmap_pins.include?(line.strip) }.join
204
+ end
205
+
206
+ def legacy_importmap_pins
207
+ double_quoted_legacy_importmap_pins + single_quoted_legacy_importmap_pins
208
+ end
209
+
210
+ def double_quoted_legacy_importmap_pins
211
+ [
212
+ 'pin "@tramway/tramway-select", to: "tramway/tramway-select_controller.js"',
213
+ 'pin "@tramway/table-row-preview", to: "tramway/table_row_preview_controller.js"',
214
+ 'pin "@tramway/checkbox", to: "tramway/ui_checkbox_controller.js"',
210
215
  'pin "@tramway/ui-checkbox", to: "tramway/ui_checkbox_controller.js"',
211
- 'pin "@tramway/checkbox", to: "tramway/ui_checkbox_controller.js"'
212
- ).gsub(
216
+ 'pin "@tramway/tooltip", to: "tramway/tooltip_controller.js"'
217
+ ]
218
+ end
219
+
220
+ def single_quoted_legacy_importmap_pins
221
+ [
222
+ "pin '@tramway/tramway-select', to: 'tramway/tramway-select_controller.js'",
223
+ "pin '@tramway/table-row-preview', to: 'tramway/table_row_preview_controller.js'",
224
+ "pin '@tramway/checkbox', to: 'tramway/ui_checkbox_controller.js'",
213
225
  "pin '@tramway/ui-checkbox', to: 'tramway/ui_checkbox_controller.js'",
214
- "pin '@tramway/checkbox', to: 'tramway/ui_checkbox_controller.js'"
215
- )
226
+ "pin '@tramway/tooltip', to: 'tramway/tooltip_controller.js'"
227
+ ]
216
228
  end
217
229
 
218
230
  def with_agents_update_fallback
@@ -290,7 +302,7 @@ module Tramway
290
302
  def ensure_importmap_pin
291
303
  return unless File.exist?(importmap_path)
292
304
 
293
- content = normalize_checkbox_pin(File.read(importmap_path))
305
+ content = remove_legacy_importmap_pins(File.read(importmap_path))
294
306
  missing_pins = importmap_tramway_pins.reject { |pin| content.include?(pin) }
295
307
  File.write(importmap_path, content) if content != File.read(importmap_path)
296
308
  return if missing_pins.empty?
@@ -17,7 +17,9 @@ module Tramway
17
17
  end
18
18
 
19
19
  initializer 'tramway.assets.precompile' do |app|
20
- app.config.assets.precompile += %w[tramway/tramway-select_controller.js tramway/ui_checkbox_controller.js]
20
+ app.config.assets.precompile += %w[
21
+ tramway/tramway.js
22
+ ]
21
23
  end
22
24
 
23
25
  private
@@ -46,7 +46,7 @@ module Tramway
46
46
  def tramway_button(path: nil, text: nil, method: :get, form_options: {}, **options, &)
47
47
  component 'tramway/button', text:, path:, method:, form_options:, color: options.delete(:color),
48
48
  type: options.delete(:type), size: options.delete(:size),
49
- tag: options.delete(:tag), options:, &
49
+ tag: options.delete(:tag), tooltip: options.delete(:tooltip), options:, &
50
50
  end
51
51
 
52
52
  def tramway_back_button
@@ -72,6 +72,10 @@ module Tramway
72
72
  color:
73
73
  end
74
74
 
75
+ def tramway_tooltip(text:, event: :hover, **options, &)
76
+ component 'tramway/tooltip', text:, event:, options:, &
77
+ end
78
+
75
79
  def tramway_title(text: nil, **options, &)
76
80
  component 'tramway/title', text:, options:, &
77
81
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tramway
4
- VERSION = '3.1'
4
+ VERSION = '3.1.1.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tramway
3
3
  version: !ruby/object:Gem::Version
4
- version: '3.1'
4
+ version: 3.1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - kalashnikovisme
@@ -138,9 +138,7 @@ files:
138
138
  - MIT-LICENSE
139
139
  - README.md
140
140
  - Rakefile
141
- - app/assets/javascripts/tramway/table_row_preview_controller.js
142
- - app/assets/javascripts/tramway/tramway-select_controller.js
143
- - app/assets/javascripts/tramway/ui_checkbox_controller.js
141
+ - app/assets/javascripts/tramway/tramway.js
144
142
  - app/components/tailwind_component.html.haml
145
143
  - app/components/tailwind_component.rb
146
144
  - app/components/tramway/actions_buttons_container_component.html.haml
@@ -242,6 +240,8 @@ files:
242
240
  - app/components/tramway/table_component.rb
243
241
  - app/components/tramway/title_component.html.haml
244
242
  - app/components/tramway/title_component.rb
243
+ - app/components/tramway/tooltip_component.html.haml
244
+ - app/components/tramway/tooltip_component.rb
245
245
  - app/controllers/tramway/entities_controller.rb
246
246
  - app/helpers/tramway/application_helper.rb
247
247
  - app/views/kaminari/_first_page.html.haml
@@ -323,7 +323,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
323
323
  - !ruby/object:Gem::Version
324
324
  version: '0'
325
325
  requirements: []
326
- rubygems_version: 4.0.6
326
+ rubygems_version: 4.0.10
327
327
  specification_version: 4
328
328
  summary: Tramway Rails Engine
329
329
  test_files: []
@@ -1,175 +0,0 @@
1
- import { Controller } from "@hotwired/stimulus";
2
-
3
- export default class TableRowPreview extends Controller {
4
- connect() {
5
- this.items = JSON.parse(this.element.dataset.items || '{}');
6
- this.attachSwipeGesture();
7
- }
8
-
9
- disconnect() {
10
- this.detachSwipeGesture();
11
- }
12
-
13
- toggle() {
14
- const rollUp = this.rollUpElement();
15
- if (!rollUp) return;
16
-
17
- rollUp.classList.remove("animate-roll-down");
18
- rollUp.classList.add("animate-roll-up");
19
-
20
- // Show pre-rendered preview content that is hidden by default.
21
- if (Object.keys(this.items).length === 0) {
22
- rollUp.classList.remove("hidden");
23
- return;
24
- }
25
-
26
- const existingTable = rollUp.querySelector(".div-table");
27
- if (existingTable) {
28
- existingTable.remove();
29
- }
30
-
31
- const existingTitle = rollUp.querySelector("h3");
32
- if (existingTitle) {
33
- existingTitle.remove();
34
- }
35
-
36
- const titleText = document.createElement("h3");
37
-
38
- titleText.classList.add("text-xl");
39
- titleText.classList.add("text-white");
40
- titleText.classList.add("py-4");
41
- titleText.classList.add("px-4");
42
- titleText.textContent = Object.values(this.items)[0];
43
-
44
- const table = this.createTable(this.items);
45
-
46
- rollUp.insertAdjacentElement('afterbegin', table);
47
- rollUp.insertAdjacentElement('afterbegin', titleText);
48
-
49
- rollUp.classList.remove("hidden");
50
- }
51
-
52
- close() {
53
- const rollUp = this.rollUpElement();
54
- if (!rollUp) return;
55
-
56
- this.resetDragStyles(rollUp);
57
- rollUp.classList.remove("animate-roll-up");
58
- rollUp.classList.add("animate-roll-down");
59
-
60
- rollUp.addEventListener("animationend", () => {
61
- rollUp.classList.add("hidden");
62
- rollUp.classList.remove("animate-roll-down");
63
- rollUp.classList.add("animate-roll-up");
64
- }, { once: true });
65
- }
66
-
67
- rollUpElement() {
68
- if (this.element.id === "roll-up") return this.element;
69
-
70
- return this.element.previousElementSibling || document.getElementById("roll-up");
71
- }
72
-
73
- attachSwipeGesture() {
74
- if (this.element.id !== "roll-up") return;
75
-
76
- this.startY = null;
77
- this.startX = null;
78
- this.currentDeltaY = 0;
79
-
80
- this.onTouchStart = (event) => {
81
- if (this.element.classList.contains("hidden")) return;
82
- if (event.touches.length !== 1) return;
83
-
84
- this.startY = event.touches[0].clientY;
85
- this.startX = event.touches[0].clientX;
86
- this.currentDeltaY = 0;
87
- this.element.style.transition = "none";
88
- };
89
-
90
- this.onTouchMove = (event) => {
91
- if (this.startY === null || event.touches.length !== 1) return;
92
-
93
- const deltaY = event.touches[0].clientY - this.startY;
94
- const deltaX = Math.abs(event.touches[0].clientX - this.startX);
95
- if (deltaY <= 0 || deltaY <= deltaX) return;
96
-
97
- this.currentDeltaY = deltaY;
98
- this.element.style.transform = `translateY(${deltaY}px)`;
99
- event.preventDefault();
100
- };
101
-
102
- this.onTouchEnd = () => {
103
- if (this.startY === null) return;
104
-
105
- const shouldClose = this.currentDeltaY > 80;
106
- this.startY = null;
107
- this.startX = null;
108
-
109
- if (shouldClose) {
110
- this.close();
111
- return;
112
- }
113
-
114
- this.resetDragStyles(this.element);
115
- };
116
-
117
- this.element.addEventListener("touchstart", this.onTouchStart, { passive: true });
118
- this.element.addEventListener("touchmove", this.onTouchMove, { passive: false });
119
- this.element.addEventListener("touchend", this.onTouchEnd);
120
- this.element.addEventListener("touchcancel", this.onTouchEnd);
121
- }
122
-
123
- detachSwipeGesture() {
124
- if (this.element.id !== "roll-up") return;
125
- if (!this.onTouchStart) return;
126
-
127
- this.element.removeEventListener("touchstart", this.onTouchStart);
128
- this.element.removeEventListener("touchmove", this.onTouchMove);
129
- this.element.removeEventListener("touchend", this.onTouchEnd);
130
- this.element.removeEventListener("touchcancel", this.onTouchEnd);
131
- }
132
-
133
- resetDragStyles(element) {
134
- element.style.transition = "";
135
- element.style.transform = "";
136
- }
137
-
138
- createTable(items) {
139
- const table = document.createElement("div");
140
- table.classList.add("div-table");
141
- table.classList.add("text-white");
142
- table.classList.add("px-2");
143
-
144
- Object.entries(items).forEach(([key, value]) => {
145
- const rows = this.createTableRow(key, value);
146
-
147
- rows.forEach((row) => table.appendChild(row));
148
- });
149
-
150
- return table;
151
- }
152
-
153
- createTableRow(key, value) {
154
- const keyRow = document.createElement("div");
155
- keyRow.classList.add("div-table-row");
156
- keyRow.classList.add("bg-gray-700");
157
- keyRow.classList.add("text-white");
158
- keyRow.classList.add("px-2");
159
- keyRow.classList.add("py-1");
160
- keyRow.classList.add("text-xs");
161
- keyRow.classList.add("font-semibold");
162
- keyRow.textContent = key;
163
-
164
- const valueRow = document.createElement("div");
165
- valueRow.classList.add("div-table-row");
166
- valueRow.classList.add("bg-gray-800");
167
- valueRow.classList.add("px-2");
168
- valueRow.classList.add("py-2");
169
- valueRow.textContent = value;
170
-
171
- return [keyRow, valueRow];
172
- }
173
- }
174
-
175
- export { TableRowPreview };