@gradio/dataframe 0.16.0 → 0.16.2

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.
@@ -109,9 +109,11 @@ function make_headers(_head, col_count2, els2) {
109
109
  }
110
110
  function process_data(_values) {
111
111
  const data_row_length = _values.length;
112
+ if (data_row_length === 0)
113
+ return [];
112
114
  return Array(row_count[1] === "fixed" ? row_count[0] : data_row_length).fill(0).map((_, i) => {
113
115
  return Array(
114
- col_count[1] === "fixed" ? col_count[0] : data_row_length > 0 ? _values[0].length : headers.length
116
+ col_count[1] === "fixed" ? col_count[0] : _values[0].length || headers.length
115
117
  ).fill(0).map((_2, j) => {
116
118
  const id = make_id();
117
119
  els[id] = els[id] || { input: null, cell: null };
@@ -150,6 +152,7 @@ async function trigger_change() {
150
152
  data: data.map((row) => row.map((cell) => cell.value)),
151
153
  headers: _headers.map((h) => h.value),
152
154
  metadata: null
155
+ // the metadata (display value, styling) cannot be changed by the user so we don't need to pass it up
153
156
  });
154
157
  if (!value_is_output) {
155
158
  dispatch("input");
@@ -360,16 +363,14 @@ async function add_row(index) {
360
363
  parent.focus();
361
364
  if (row_count[1] !== "dynamic")
362
365
  return;
363
- if (data.length === 0) {
364
- values = [Array(headers.length).fill("")];
365
- return;
366
- }
367
- const new_row = Array(data[0].length).fill(0).map((_, i) => {
366
+ const new_row = Array(data[0]?.length || headers.length).fill(0).map((_, i) => {
368
367
  const _id = make_id();
369
368
  els[_id] = { cell: null, input: null };
370
369
  return { id: _id, value: "" };
371
370
  });
372
- if (index !== void 0 && index >= 0 && index <= data.length) {
371
+ if (data.length === 0) {
372
+ data = [new_row];
373
+ } else if (index !== void 0 && index >= 0 && index <= data.length) {
373
374
  data.splice(index, 0, new_row);
374
375
  } else {
375
376
  data.push(new_row);
@@ -605,14 +606,16 @@ async function delete_col(index) {
605
606
  parent.focus();
606
607
  if (col_count[1] !== "dynamic")
607
608
  return;
608
- if (data[0].length <= 1)
609
+ if (_headers.length <= 1)
609
610
  return;
610
611
  _headers.splice(index, 1);
611
612
  _headers = _headers;
612
- data.forEach((row) => {
613
- row.splice(index, 1);
614
- });
615
- data = data;
613
+ if (data.length > 0) {
614
+ data.forEach((row) => {
615
+ row.splice(index, 1);
616
+ });
617
+ data = data;
618
+ }
616
619
  selected = false;
617
620
  }
618
621
  function delete_row_at(index) {
@@ -702,24 +705,26 @@ function commit_filter() {
702
705
  <svelte:window on:resize={() => set_cell_widths()} />
703
706
 
704
707
  <div class="table-container">
705
- <div class="header-row">
706
- {#if label && label.length !== 0 && show_label}
707
- <div class="label">
708
- <p>{label}</p>
709
- </div>
710
- {/if}
711
- <Toolbar
712
- {show_fullscreen_button}
713
- {is_fullscreen}
714
- on:click={toggle_fullscreen}
715
- on_copy={handle_copy}
716
- {show_copy_button}
717
- {show_search}
718
- on:search={(e) => handle_search(e.detail)}
719
- on_commit_filter={commit_filter}
720
- {current_search_query}
721
- />
722
- </div>
708
+ {#if (label && label.length !== 0 && show_label) || show_fullscreen_button || show_copy_button || show_search !== "none"}
709
+ <div class="header-row">
710
+ {#if label && label.length !== 0 && show_label}
711
+ <div class="label">
712
+ <p>{label}</p>
713
+ </div>
714
+ {/if}
715
+ <Toolbar
716
+ {show_fullscreen_button}
717
+ {is_fullscreen}
718
+ on:click={toggle_fullscreen}
719
+ on_copy={handle_copy}
720
+ {show_copy_button}
721
+ {show_search}
722
+ on:search={(e) => handle_search(e.detail)}
723
+ on_commit_filter={commit_filter}
724
+ {current_search_query}
725
+ />
726
+ </div>
727
+ {/if}
723
728
  <div
724
729
  bind:this={parent}
725
730
  class="table-wrap"
@@ -864,184 +869,205 @@ function commit_filter() {
864
869
  bind:dragging
865
870
  aria_label={i18n("dataframe.drop_to_upload")}
866
871
  >
867
- <VirtualTable
868
- bind:items={data}
869
- {max_height}
870
- bind:actual_height={table_height}
871
- bind:table_scrollbar_width={scrollbar_width}
872
- selected={selected_index}
873
- disable_scroll={active_cell_menu !== null ||
874
- active_header_menu !== null}
875
- >
876
- {#if label && label.length !== 0}
877
- <caption class="sr-only">{label}</caption>
878
- {/if}
879
- <tr slot="thead">
880
- {#if show_row_numbers}
881
- <th
882
- class="row-number-header frozen-column always-frozen"
883
- style="left: 0;"
884
- >
885
- <div class="cell-wrap">
886
- <div class="header-content">
887
- <div class="header-text"></div>
888
- </div>
889
- </div>
890
- </th>
872
+ <div class="table-wrap">
873
+ <VirtualTable
874
+ bind:items={data}
875
+ {max_height}
876
+ bind:actual_height={table_height}
877
+ bind:table_scrollbar_width={scrollbar_width}
878
+ selected={selected_index}
879
+ disable_scroll={active_cell_menu !== null ||
880
+ active_header_menu !== null}
881
+ >
882
+ {#if label && label.length !== 0}
883
+ <caption class="sr-only">{label}</caption>
891
884
  {/if}
892
- {#each _headers as { value, id }, i (id)}
893
- <th
894
- class:frozen-column={i < actual_pinned_columns}
895
- class:last-frozen={i === actual_pinned_columns - 1}
896
- class:focus={header_edit === i || selected_header === i}
897
- aria-sort={get_sort_status(value, sort_by, sort_direction)}
898
- style="width: {get_cell_width(i)}; left: {i <
899
- actual_pinned_columns
900
- ? i === 0
901
- ? show_row_numbers
902
- ? 'var(--cell-width-row-number)'
903
- : '0'
904
- : `calc(${show_row_numbers ? 'var(--cell-width-row-number) + ' : ''}${Array(
905
- i
906
- )
907
- .fill(0)
908
- .map((_, idx) => `var(--cell-width-${idx})`)
909
- .join(' + ')})`
910
- : 'auto'};"
911
- on:click={() => {
912
- toggle_header_button(i);
913
- }}
914
- >
915
- <div class="cell-wrap">
916
- <div class="header-content">
885
+ <tr slot="thead">
886
+ {#if show_row_numbers}
887
+ <th
888
+ class="row-number-header frozen-column always-frozen"
889
+ style="left: 0;"
890
+ >
891
+ <div class="cell-wrap">
892
+ <div class="header-content">
893
+ <div class="header-text"></div>
894
+ </div>
895
+ </div>
896
+ </th>
897
+ {/if}
898
+ {#each _headers as { value, id }, i (id)}
899
+ <th
900
+ class:frozen-column={i < actual_pinned_columns}
901
+ class:last-frozen={i === actual_pinned_columns - 1}
902
+ class:focus={header_edit === i || selected_header === i}
903
+ aria-sort={get_sort_status(value, sort_by, sort_direction)}
904
+ style="width: {get_cell_width(i)}; left: {i <
905
+ actual_pinned_columns
906
+ ? i === 0
907
+ ? show_row_numbers
908
+ ? 'var(--cell-width-row-number)'
909
+ : '0'
910
+ : `calc(${show_row_numbers ? 'var(--cell-width-row-number) + ' : ''}${Array(
911
+ i
912
+ )
913
+ .fill(0)
914
+ .map((_, idx) => `var(--cell-width-${idx})`)
915
+ .join(' + ')})`
916
+ : 'auto'};"
917
+ on:click={() => {
918
+ toggle_header_button(i);
919
+ }}
920
+ >
921
+ <div class="cell-wrap">
922
+ <div class="header-content">
923
+ <EditableCell
924
+ {max_chars}
925
+ bind:value={_headers[i].value}
926
+ bind:el={els[id].input}
927
+ {latex_delimiters}
928
+ {line_breaks}
929
+ edit={header_edit === i}
930
+ on:keydown={end_header_edit}
931
+ on:dblclick={() => edit_header(i)}
932
+ header
933
+ {root}
934
+ {editable}
935
+ />
936
+ <div class="sort-buttons">
937
+ <SortIcon
938
+ direction={sort_by === i ? sort_direction : null}
939
+ on:sort={({ detail }) => handle_sort(i, detail)}
940
+ {i18n}
941
+ />
942
+ </div>
943
+ </div>
944
+ {#if editable}
945
+ <button
946
+ class="cell-menu-button"
947
+ on:click={(event) => toggle_header_menu(event, i)}
948
+ on:touchstart={(event) => {
949
+ event.preventDefault();
950
+ const touch = event.touches[0];
951
+ const mouseEvent = new MouseEvent("click", {
952
+ clientX: touch.clientX,
953
+ clientY: touch.clientY,
954
+ bubbles: true,
955
+ cancelable: true,
956
+ view: window
957
+ });
958
+ toggle_header_menu(mouseEvent, i);
959
+ }}
960
+ >
961
+ &#8942;
962
+ </button>
963
+ {/if}
964
+ </div>
965
+ </th>
966
+ {/each}
967
+ </tr>
968
+ <tr slot="tbody" let:item let:index class:row_odd={index % 2 === 0}>
969
+ {#if show_row_numbers}
970
+ <td
971
+ class="row-number frozen-column always-frozen"
972
+ style="left: 0;"
973
+ tabindex="-1"
974
+ >
975
+ {index + 1}
976
+ </td>
977
+ {/if}
978
+ {#each item as { value, id }, j (id)}
979
+ <td
980
+ class:frozen-column={j < actual_pinned_columns}
981
+ class:last-frozen={j === actual_pinned_columns - 1}
982
+ tabindex={show_row_numbers && j === 0 ? -1 : 0}
983
+ bind:this={els[id].cell}
984
+ on:touchstart={(event) => {
985
+ const touch = event.touches[0];
986
+ const mouseEvent = new MouseEvent("click", {
987
+ clientX: touch.clientX,
988
+ clientY: touch.clientY,
989
+ bubbles: true,
990
+ cancelable: true,
991
+ view: window
992
+ });
993
+ handle_cell_click(mouseEvent, index, j);
994
+ }}
995
+ on:mousedown={(event) => {
996
+ event.preventDefault();
997
+ event.stopPropagation();
998
+ }}
999
+ on:click={(event) => handle_cell_click(event, index, j)}
1000
+ style="width: {get_cell_width(j)}; left: {j <
1001
+ actual_pinned_columns
1002
+ ? j === 0
1003
+ ? show_row_numbers
1004
+ ? 'var(--cell-width-row-number)'
1005
+ : '0'
1006
+ : `calc(${show_row_numbers ? 'var(--cell-width-row-number) + ' : ''}${Array(
1007
+ j
1008
+ )
1009
+ .fill(0)
1010
+ .map((_, idx) => `var(--cell-width-${idx})`)
1011
+ .join(' + ')})`
1012
+ : 'auto'}; {styling?.[index]?.[j] || ''}"
1013
+ class:flash={copy_flash &&
1014
+ is_cell_selected([index, j], selected_cells)}
1015
+ class={is_cell_selected([index, j], selected_cells)}
1016
+ class:menu-active={active_cell_menu &&
1017
+ active_cell_menu.row === index &&
1018
+ active_cell_menu.col === j}
1019
+ >
1020
+ <div class="cell-wrap">
917
1021
  <EditableCell
918
- {max_chars}
919
- bind:value={_headers[i].value}
1022
+ bind:value={data[index][j].value}
920
1023
  bind:el={els[id].input}
1024
+ display_value={display_value?.[index]?.[j]}
921
1025
  {latex_delimiters}
922
1026
  {line_breaks}
923
- edit={header_edit === i}
924
- on:keydown={end_header_edit}
925
- on:dblclick={() => edit_header(i)}
926
- header
927
- {root}
928
1027
  {editable}
1028
+ edit={dequal(editing, [index, j])}
1029
+ datatype={Array.isArray(datatype) ? datatype[j] : datatype}
1030
+ on:blur={() => {
1031
+ clear_on_focus = false;
1032
+ parent.focus();
1033
+ }}
1034
+ on:focus={() => {
1035
+ const row = index;
1036
+ const col = j;
1037
+ if (
1038
+ !selected_cells.some(([r, c]) => r === row && c === col)
1039
+ ) {
1040
+ selected_cells = [[row, col]];
1041
+ }
1042
+ }}
1043
+ {clear_on_focus}
1044
+ {root}
1045
+ {max_chars}
929
1046
  />
930
- <div class="sort-buttons">
931
- <SortIcon
932
- direction={sort_by === i ? sort_direction : null}
933
- on:sort={({ detail }) => handle_sort(i, detail)}
934
- {i18n}
935
- />
936
- </div>
1047
+ {#if editable && should_show_cell_menu([index, j], selected_cells, editable)}
1048
+ <button
1049
+ class="cell-menu-button"
1050
+ on:click={(event) => toggle_cell_menu(event, index, j)}
1051
+ >
1052
+ &#8942;
1053
+ </button>
1054
+ {/if}
937
1055
  </div>
938
- {#if editable}
939
- <button
940
- class="cell-menu-button"
941
- on:click={(event) => toggle_header_menu(event, i)}
942
- >
943
- &#8942;
944
- </button>
945
- {/if}
946
- </div>
947
- </th>
948
- {/each}
949
- </tr>
950
- <tr slot="tbody" let:item let:index class:row_odd={index % 2 === 0}>
951
- {#if show_row_numbers}
952
- <td
953
- class="row-number frozen-column always-frozen"
954
- style="left: 0;"
955
- tabindex="-1"
956
- >
957
- {index + 1}
958
- </td>
959
- {/if}
960
- {#each item as { value, id }, j (id)}
961
- <td
962
- class:frozen-column={j < actual_pinned_columns}
963
- class:last-frozen={j === actual_pinned_columns - 1}
964
- tabindex={show_row_numbers && j === 0 ? -1 : 0}
965
- bind:this={els[id].cell}
966
- on:touchstart={(event) => {
967
- const touch = event.touches[0];
968
- const mouseEvent = new MouseEvent("click", {
969
- clientX: touch.clientX,
970
- clientY: touch.clientY,
971
- bubbles: true,
972
- cancelable: true,
973
- view: window
974
- });
975
- handle_cell_click(mouseEvent, index, j);
976
- }}
977
- on:mousedown={(event) => {
978
- event.preventDefault();
979
- event.stopPropagation();
980
- }}
981
- on:click={(event) => handle_cell_click(event, index, j)}
982
- style="width: {get_cell_width(j)}; left: {j <
983
- actual_pinned_columns
984
- ? j === 0
985
- ? show_row_numbers
986
- ? 'var(--cell-width-row-number)'
987
- : '0'
988
- : `calc(${show_row_numbers ? 'var(--cell-width-row-number) + ' : ''}${Array(
989
- j
990
- )
991
- .fill(0)
992
- .map((_, idx) => `var(--cell-width-${idx})`)
993
- .join(' + ')})`
994
- : 'auto'}; {styling?.[index]?.[j] || ''}"
995
- class:flash={copy_flash &&
996
- is_cell_selected([index, j], selected_cells)}
997
- class={is_cell_selected([index, j], selected_cells)}
998
- class:menu-active={active_cell_menu &&
999
- active_cell_menu.row === index &&
1000
- active_cell_menu.col === j}
1001
- >
1002
- <div class="cell-wrap">
1003
- <EditableCell
1004
- bind:value={data[index][j].value}
1005
- bind:el={els[id].input}
1006
- display_value={display_value?.[index]?.[j]}
1007
- {latex_delimiters}
1008
- {line_breaks}
1009
- {editable}
1010
- edit={dequal(editing, [index, j])}
1011
- datatype={Array.isArray(datatype) ? datatype[j] : datatype}
1012
- on:blur={() => {
1013
- clear_on_focus = false;
1014
- parent.focus();
1015
- }}
1016
- on:focus={() => {
1017
- const row = index;
1018
- const col = j;
1019
- if (
1020
- !selected_cells.some(([r, c]) => r === row && c === col)
1021
- ) {
1022
- selected_cells = [[row, col]];
1023
- }
1024
- }}
1025
- {clear_on_focus}
1026
- {root}
1027
- {max_chars}
1028
- />
1029
- {#if editable && should_show_cell_menu([index, j], selected_cells, editable)}
1030
- <button
1031
- class="cell-menu-button"
1032
- on:click={(event) => toggle_cell_menu(event, index, j)}
1033
- >
1034
- &#8942;
1035
- </button>
1036
- {/if}
1037
- </div>
1038
- </td>
1039
- {/each}
1040
- </tr>
1041
- </VirtualTable>
1056
+ </td>
1057
+ {/each}
1058
+ </tr>
1059
+ </VirtualTable>
1060
+ </div>
1042
1061
  </Upload>
1043
1062
  </div>
1044
1063
  </div>
1064
+ {#if data.length === 0 && editable && row_count[1] === "dynamic"}
1065
+ <div class="add-row-container">
1066
+ <button class="add-row-button" on:click={() => add_row()}>
1067
+ <span>+</span>
1068
+ </button>
1069
+ </div>
1070
+ {/if}
1045
1071
 
1046
1072
  {#if active_cell_menu}
1047
1073
  <CellMenu
@@ -1078,7 +1104,7 @@ function commit_filter() {
1078
1104
  on_delete_row={() => delete_row_at(active_cell_menu?.row ?? -1)}
1079
1105
  on_delete_col={() => delete_col_at(active_header_menu?.col ?? -1)}
1080
1106
  can_delete_rows={false}
1081
- can_delete_cols={data[0].length > 1}
1107
+ can_delete_cols={_headers.length > 1}
1082
1108
  />
1083
1109
  {/if}
1084
1110
 
@@ -1100,8 +1126,6 @@ function commit_filter() {
1100
1126
  .table-wrap {
1101
1127
  position: relative;
1102
1128
  transition: 150ms;
1103
- border: 1px solid var(--border-color-primary);
1104
- border-radius: var(--table-radius);
1105
1129
  }
1106
1130
 
1107
1131
  .table-wrap.menu-open {
@@ -1134,6 +1158,12 @@ function commit_filter() {
1134
1158
  border-collapse: separate;
1135
1159
  }
1136
1160
 
1161
+ .table-wrap > :global(button) {
1162
+ border: 1px solid var(--border-color-primary);
1163
+ border-radius: var(--table-radius);
1164
+ overflow: hidden;
1165
+ }
1166
+
1137
1167
  div:not(.no-wrap) td {
1138
1168
  overflow-wrap: anywhere;
1139
1169
  }
@@ -1176,10 +1206,12 @@ function commit_filter() {
1176
1206
 
1177
1207
  th:first-child {
1178
1208
  border-top-left-radius: var(--table-radius);
1209
+ border-bottom-left-radius: var(--table-radius);
1179
1210
  }
1180
1211
 
1181
1212
  th:last-child {
1182
1213
  border-top-right-radius: var(--table-radius);
1214
+ border-bottom-right-radius: var(--table-radius);
1183
1215
  }
1184
1216
 
1185
1217
  th.focus,
@@ -1209,6 +1241,7 @@ function commit_filter() {
1209
1241
  display: flex;
1210
1242
  align-items: center;
1211
1243
  flex-shrink: 0;
1244
+ order: -1;
1212
1245
  }
1213
1246
 
1214
1247
  .editing {
@@ -1217,17 +1250,24 @@ function commit_filter() {
1217
1250
 
1218
1251
  .cell-wrap {
1219
1252
  display: flex;
1220
- align-items: flex-start;
1253
+ align-items: center;
1254
+ justify-content: flex-start;
1221
1255
  outline: none;
1222
1256
  min-height: var(--size-9);
1223
1257
  position: relative;
1224
- height: auto;
1258
+ height: 100%;
1259
+ padding: var(--size-2);
1260
+ box-sizing: border-box;
1261
+ margin: 0;
1262
+ gap: var(--size-1);
1263
+ overflow: visible;
1264
+ min-width: 0;
1265
+ border-radius: var(--table-radius);
1225
1266
  }
1226
1267
 
1227
1268
  .header-content {
1228
1269
  display: flex;
1229
1270
  align-items: center;
1230
- justify-content: space-between;
1231
1271
  overflow: hidden;
1232
1272
  flex-grow: 1;
1233
1273
  min-width: 0;
@@ -1235,7 +1275,6 @@ function commit_filter() {
1235
1275
  overflow-wrap: break-word;
1236
1276
  word-break: normal;
1237
1277
  height: 100%;
1238
- padding: var(--size-1);
1239
1278
  gap: var(--size-1);
1240
1279
  }
1241
1280
 
@@ -1265,7 +1304,8 @@ function commit_filter() {
1265
1304
  transform: translateY(-50%);
1266
1305
  }
1267
1306
 
1268
- .cell-selected .cell-menu-button {
1307
+ .cell-selected .cell-menu-button,
1308
+ th:hover .cell-menu-button {
1269
1309
  display: flex;
1270
1310
  align-items: center;
1271
1311
  justify-content: center;
@@ -1482,4 +1522,24 @@ function commit_filter() {
1482
1522
  .always-frozen {
1483
1523
  z-index: var(--layer-3);
1484
1524
  }
1525
+
1526
+ .add-row-container {
1527
+ margin-top: var(--size-2);
1528
+ }
1529
+
1530
+ .add-row-button {
1531
+ width: 100%;
1532
+ padding: var(--size-1);
1533
+ background: transparent;
1534
+ border: 1px dashed var(--border-color-primary);
1535
+ border-radius: var(--radius-sm);
1536
+ color: var(--body-text-color);
1537
+ cursor: pointer;
1538
+ transition: all 150ms;
1539
+ }
1540
+
1541
+ .add-row-button:hover {
1542
+ background: var(--background-fill-secondary);
1543
+ border-style: solid;
1544
+ }
1485
1545
  </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/dataframe",
3
- "version": "0.16.0",
3
+ "version": "0.16.2",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "author": "",
@@ -17,14 +17,14 @@
17
17
  "dompurify": "^3.0.3",
18
18
  "katex": "^0.16.7",
19
19
  "marked": "^12.0.0",
20
- "@gradio/atoms": "^0.13.2",
21
- "@gradio/button": "^0.4.6",
22
- "@gradio/markdown-code": "^0.4.0",
20
+ "@gradio/atoms": "^0.13.3",
21
+ "@gradio/button": "^0.4.7",
23
22
  "@gradio/client": "^1.12.0",
24
- "@gradio/statustracker": "^0.10.3",
23
+ "@gradio/markdown-code": "^0.4.0",
25
24
  "@gradio/icons": "^0.10.0",
26
- "@gradio/upload": "^0.15.1",
27
- "@gradio/utils": "^0.10.1"
25
+ "@gradio/utils": "^0.10.1",
26
+ "@gradio/statustracker": "^0.10.4",
27
+ "@gradio/upload": "^0.15.2"
28
28
  },
29
29
  "exports": {
30
30
  ".": {
@@ -89,7 +89,7 @@
89
89
  <style>
90
90
  .cell-menu {
91
91
  position: fixed;
92
- z-index: var(--layer-2);
92
+ z-index: var(--layer-4);
93
93
  background: var(--background-fill-primary);
94
94
  border: 1px solid var(--border-color-primary);
95
95
  border-radius: var(--radius-sm);
@@ -110,7 +110,6 @@
110
110
  class:multiline={header}
111
111
  on:focus|preventDefault
112
112
  style={styling}
113
- class="table-cell-text"
114
113
  data-editable={editable}
115
114
  placeholder=" "
116
115
  >
@@ -149,8 +148,6 @@
149
148
  position: relative;
150
149
  display: inline-block;
151
150
  outline: none;
152
- padding: var(--size-2);
153
- padding-right: 0;
154
151
  -webkit-user-select: text;
155
152
  -moz-user-select: text;
156
153
  -ms-user-select: text;
@@ -177,6 +174,7 @@
177
174
  font-weight: var(--weight-bold);
178
175
  white-space: normal;
179
176
  word-break: break-word;
177
+ margin-left: var(--size-1);
180
178
  }
181
179
 
182
180
  .edit {