@trebco/treb 28.15.1 → 28.17.4

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.
package/dist/treb.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /*! API v28.15. Copyright 2018-2024 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
1
+ /*! API v28.17. Copyright 2018-2024 trebco, llc. All rights reserved. LGPL: https://treb.app/license */
2
2
 
3
3
  /**
4
4
  * add our tag to the map
@@ -271,6 +271,11 @@ export interface EmbeddedSpreadsheetOptions {
271
271
  * change in the future. key modifiers have no effect.
272
272
  */
273
273
  recalculate_on_f9?: boolean;
274
+
275
+ /**
276
+ * indent/outdent buttons; default false
277
+ */
278
+ indent_buttons?: boolean;
274
279
  }
275
280
 
276
281
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trebco/treb",
3
- "version": "28.15.1",
3
+ "version": "28.17.4",
4
4
  "license": "LGPL-3.0-or-later",
5
5
  "homepage": "https://treb.app",
6
6
  "repository": {
@@ -101,7 +101,7 @@ export interface Dimensions {
101
101
  * sheet class has a method for reducing infinite ranges to actual
102
102
  * populated ranges.
103
103
  */
104
- export class Area implements IArea { // }, IterableIterator<ICellAddress> {
104
+ export class Area implements IArea {
105
105
 
106
106
  // tslint:disable-next-line:variable-name
107
107
  private start_: ICellAddress;
@@ -562,6 +562,7 @@ export class Area implements IArea { // }, IterableIterator<ICellAddress> {
562
562
  return new Area(this.start, this.end); // ensure copies
563
563
  }
564
564
 
565
+ /* removed, use iterator
565
566
  public Array(): ICellAddress[] {
566
567
  if (this.entire_column || this.entire_row) throw new Error('can\'t convert infinite area to array');
567
568
  const array: ICellAddress[] = new Array<ICellAddress>(this.rows * this.columns);
@@ -578,6 +579,7 @@ export class Area implements IArea { // }, IterableIterator<ICellAddress> {
578
579
  }
579
580
  return array;
580
581
  }
582
+ */
581
583
 
582
584
  get left(): Area{
583
585
  const area = new Area(this.start_, this.end_);
@@ -637,6 +639,82 @@ export class Area implements IArea { // }, IterableIterator<ICellAddress> {
637
639
  return this; // fluent
638
640
  }
639
641
 
642
+ /* *
643
+ * preferred to straight iterator. actually in this class iterator
644
+ * is OK but in some other cases we'll want to generate like this
645
+ *
646
+ * eh I don't know about this inline function, is that going to be
647
+ * optimized out? ...
648
+ * /
649
+ public get contents(): Generator<{ row: number, column: number, sheet_id?: number }> {
650
+
651
+ if (this.entire_row || this.entire_column) {
652
+ throw new Error(`don't iterate infinite area`);
653
+ }
654
+
655
+ const sheet_id = this.start_.sheet_id;
656
+ const start_column = this.start_.column;
657
+ const end_column = this.end_.column;
658
+ const start_row = this.start_.row;
659
+ const end_row = this.end_.row;
660
+
661
+
662
+ function *generator() {
663
+ for (let column = start_column; column <= end_column; column++){
664
+ for (let row = start_row; row <= end_row; row++){
665
+ yield {column, row, sheet_id};
666
+ }
667
+ }
668
+ }
669
+
670
+ return generator();
671
+
672
+ }
673
+ */
674
+
675
+ /**
676
+ * modernizing. this is a proper iterator. generators are prettier
677
+ * but there's at least some performance cost -- I'm not sure how
678
+ * much, but it's non-zero.
679
+ */
680
+ public [Symbol.iterator](): Iterator<ICellAddress> {
681
+
682
+ if (this.entire_row || this.entire_column) {
683
+ throw new Error(`don't iterate infinite area`);
684
+ }
685
+
686
+ let row = this.start_.row;
687
+ let column = this.start_.column;
688
+
689
+ // this now uses "live" references, so if the object were mutated
690
+ // during iteration the iterator would reflect those changes. which
691
+ // seems bad, but also correct.
692
+
693
+ return {
694
+ next: () => {
695
+
696
+ const value = { column, row, sheet_id: this.start_.sheet_id };
697
+
698
+ if (column > this.end_.column) {
699
+ return {
700
+ done: true,
701
+ value: undefined,
702
+ };
703
+ }
704
+
705
+ if (++row > this.end_.row) {
706
+ row = this.start_.row;
707
+ column++;
708
+ }
709
+
710
+ return { value };
711
+
712
+ },
713
+ };
714
+
715
+ };
716
+
717
+ /* * @deprecated * /
640
718
  public Iterate(f: (...args: any[]) => any): void {
641
719
  if (this.entire_column || this.entire_row) {
642
720
  console.warn(`don't iterate infinite area`);
@@ -648,6 +726,7 @@ export class Area implements IArea { // }, IterableIterator<ICellAddress> {
648
726
  }
649
727
  }
650
728
  }
729
+ */
651
730
 
652
731
  /* *
653
732
  * testing: we may have to polyfill for IE11, or just not use it at
@@ -796,40 +796,33 @@ export class Cells {
796
796
  return this.GetRange({row: 0, column: 0}, {row: this.rows_ - 1, column: this.columns_ - 1}, transpose);
797
797
  }
798
798
 
799
- /** simply cannot make this work with overloads (prove me wrong) */
800
- public Normalize2(from: ICellAddress, to: ICellAddress): {from: ICellAddress, to: ICellAddress} {
799
+ /** overload */
800
+ public Normalize(from: ICellAddress, to: ICellAddress): { from: ICellAddress, to: ICellAddress };
801
801
 
802
- if (from.column === Infinity) {
803
- from = { ...from, column: 0, };
804
- }
805
-
806
- if (from.row === Infinity) {
807
- from = { ...from, row: 0, };
808
- }
809
-
810
- if (to.column === Infinity) {
811
- to = { ...to, column: this.columns_ - 1};
812
- }
813
-
814
- if (to.row === Infinity) {
815
- to = { ...to, row: this.rows_ - 1};
816
- }
802
+ /** overload */
803
+ public Normalize(from: ICellAddress): { from: ICellAddress };
817
804
 
818
- return {from, to};
819
- }
805
+ /** overload */
806
+ public Normalize<K extends ICellAddress|undefined>(from: ICellAddress, to: K): { from: ICellAddress, to: K };
820
807
 
821
- /** simply cannot make this work with overloads (prove me wrong) */
822
- public Normalize1(from: ICellAddress): ICellAddress {
808
+ /** base */
809
+ public Normalize(from: ICellAddress, to?: ICellAddress): { from: ICellAddress, to?: ICellAddress } {
823
810
 
824
- if (from.column === Infinity) {
825
- from = { ...from, column: 0, };
811
+ from = {
812
+ ...from,
813
+ row: from.row == Infinity ? 0 : from.row,
814
+ column: from.column == Infinity ? 0 : from.column,
826
815
  }
827
816
 
828
- if (from.row === Infinity) {
829
- from = { ...from, row: 0, };
817
+ if (to) {
818
+ to = {
819
+ ...to,
820
+ row: to.row == Infinity ? this.rows_ - 1 : to.row,
821
+ column: to.column == Infinity ? this.columns_ - 1 : to.column,
822
+ }
830
823
  }
831
824
 
832
- return from;
825
+ return { from, to };
833
826
 
834
827
  }
835
828
 
@@ -851,7 +844,7 @@ export class Cells {
851
844
  */
852
845
  public RawValue(from: ICellAddress, to: ICellAddress = from): CellValue | CellValue[][] | undefined {
853
846
 
854
- ({from, to} = this.Normalize2(from, to));
847
+ ({from, to} = this.Normalize(from, to));
855
848
 
856
849
  if (from.row === to.row && from.column === to.column) {
857
850
  if (this.data[from.row] && this.data[from.row][from.column]) {
@@ -885,12 +878,7 @@ export class Cells {
885
878
  /** gets range as values */
886
879
  public GetRange(from: ICellAddress, to?: ICellAddress, transpose = false){
887
880
 
888
- if (to) {
889
- ({from, to} = this.Normalize2(from, to));
890
- }
891
- else {
892
- from = this.Normalize1(from);
893
- }
881
+ ({from, to} = this.Normalize(from, to));
894
882
 
895
883
  // console.info("getrange", from, to, transpose);
896
884
 
@@ -972,7 +960,7 @@ export class Cells {
972
960
 
973
961
  public GetRange4(from: ICellAddress, to: ICellAddress = from, transpose = false): UnionValue {
974
962
 
975
- ({from, to} = this.Normalize2(from, to));
963
+ ({from, to} = this.Normalize(from, to));
976
964
 
977
965
  if (from.row === to.row && from.column === to.column) {
978
966
  if (this.data[from.row] && this.data[from.row][from.column]){
@@ -1008,10 +996,10 @@ export class Cells {
1008
996
 
1009
997
  }
1010
998
 
1011
- /**
999
+ /* *
1012
1000
  * apply function to address/area
1013
1001
  * @deprecated - use Apply2
1014
- */
1002
+ * /
1015
1003
  public Apply(area: Area|ICellAddress, f: (cell: Cell, c?: number, r?: number) => void, create_missing_cells = false): void {
1016
1004
 
1017
1005
  // allow single address
@@ -1050,12 +1038,71 @@ export class Cells {
1050
1038
  }
1051
1039
  }
1052
1040
  }
1041
+ */
1053
1042
 
1054
- /**
1043
+ /* *
1044
+ * as a replacement for the Apply functions. testing
1045
+ *
1046
+ * (1) it seems like almost no one uses the cell address, so returning
1047
+ * it just adds a wasteful destructuring to every loop iteration.
1048
+ *
1049
+ * actually there's exactly one, and we could work around it. but
1050
+ * it seems like it might be useful in some cases, so... ?
1051
+ *
1052
+ * (2) can we consolidate with the IterateAll method (named Iterate)?
1053
+ * that would only work if we had the same return type, meaning either
1054
+ * drop the address from this one or add it to the other one
1055
+ *
1056
+ * @deprecated use Iterate, if possible
1057
+ *
1058
+ * /
1059
+ public *IterateArea(area: Area|ICellAddress, create_missing_cells = false) {
1060
+
1061
+ // allow single address
1062
+ if (IsCellAddress(area)) {
1063
+ area = new Area(area);
1064
+ }
1065
+
1066
+ // why not just cap? (...)
1067
+ if (area.entire_column || area.entire_row) {
1068
+ throw new Error(`don't iterate infinite cells`);
1069
+ }
1070
+
1071
+ const start = area.start;
1072
+ const end = area.end;
1073
+
1074
+ if (create_missing_cells){
1075
+ for ( let r = start.row; r <= end.row; r++ ){
1076
+ if (!this.data[r]) this.data[r] = [];
1077
+ const row = this.data[r];
1078
+ for ( let c = start.column; c <= end.column; c++ ){
1079
+ if (!row[c]) row[c] = new Cell();
1080
+ yield { row: r, column: c, cell: row[c] };
1081
+ }
1082
+ }
1083
+ }
1084
+ else {
1085
+ // we can loop over indexes that don't exist, just check for existence
1086
+ for ( let r = start.row; r <= end.row; r++ ){
1087
+ if (this.data[r]){
1088
+ const row = this.data[r];
1089
+ for ( let c = start.column; c <= end.column; c++ ){
1090
+ if (row[c]) {
1091
+ yield { row: r, column: c, cell: row[c] };
1092
+ }
1093
+ }
1094
+ }
1095
+ }
1096
+ }
1097
+
1098
+ }
1099
+ */
1100
+
1101
+ /* *
1055
1102
  * apply function to address/area
1056
1103
  *
1057
1104
  * this version lets you abort by returning false from the callback function
1058
- */
1105
+ * /
1059
1106
  public Apply2(area: Area|ICellAddress, func: (cell: Cell, c?: number, r?: number) => boolean, create_missing_cells = false): void {
1060
1107
 
1061
1108
  // allow single address
@@ -1100,6 +1147,7 @@ export class Cells {
1100
1147
  }
1101
1148
  }
1102
1149
  }
1150
+ */
1103
1151
 
1104
1152
  /**
1105
1153
  * set area. shortcut to reduce overhead. consolidates single value
@@ -1148,11 +1196,108 @@ export class Cells {
1148
1196
  }
1149
1197
 
1150
1198
  /**
1199
+ * replacement for old callback iterator. this is a composite
1200
+ * of iterating all and iterating an area. I want to remove the
1201
+ * other method, but there are still some calls that use the
1202
+ * cell address.
1203
+ *
1204
+ * Q: is it possible to use Symbol.iterator with arguments?
1205
+ * A: apparently it is, but how would you call it? (...)
1206
+ */
1207
+ public *Iterate(area?: Area|ICellAddress, create_missing_cells = false) {
1208
+
1209
+ // special case. normally iterating over all cells
1210
+ // doesn't create missing, so we use a simpler loop.
1211
+
1212
+ if (!area && create_missing_cells) {
1213
+ area = new Area({
1214
+ row: 0,
1215
+ column: 0,
1216
+ }, {
1217
+ row: this.rows_ - 1,
1218
+ column: this.columns - 1,
1219
+ });
1220
+ }
1221
+
1222
+ // if we have an area, iterate over the area. we need indexes.
1223
+
1224
+ if (area) {
1225
+
1226
+ // allow single address
1227
+ if (IsCellAddress(area)) {
1228
+ area = new Area(area);
1229
+ }
1230
+
1231
+ // why not just cap? (...)
1232
+ // if (area.entire_column || area.entire_row) {
1233
+ // throw new Error(`don't iterate infinite cells`);
1234
+ //}
1235
+
1236
+ if (area.entire_column || area.entire_row) {
1237
+ area = new Area(area.start, area.end);
1238
+ if (area.start.column === Infinity) {
1239
+ area.start.column = 0;
1240
+ area.end.column = this.columns_ - 1;
1241
+ }
1242
+ if (area.start.row === Infinity) {
1243
+ area.start.row = 0;
1244
+ area.end.row = this.rows_ - 1;
1245
+ }
1246
+ }
1247
+
1248
+ const start = area.start;
1249
+ const end = area.end;
1250
+
1251
+ if (create_missing_cells){
1252
+ for ( let r = start.row; r <= end.row; r++ ){
1253
+ if (!this.data[r]) this.data[r] = [];
1254
+ const row = this.data[r];
1255
+ for ( let c = start.column; c <= end.column; c++ ){
1256
+ if (!row[c]) row[c] = new Cell();
1257
+ yield row[c]; // { row: r, column: c, cell: row[c] };
1258
+ }
1259
+ }
1260
+ }
1261
+ else {
1262
+ // we can loop over indexes that don't exist, just check for existence
1263
+ for ( let r = start.row; r <= end.row; r++ ){
1264
+ if (this.data[r]){
1265
+ const row = this.data[r];
1266
+ for ( let c = start.column; c <= end.column; c++ ){
1267
+ if (row[c]) {
1268
+ yield row[c]; // { row: r, column: c, cell: row[c] };
1269
+ }
1270
+ }
1271
+ }
1272
+ }
1273
+ }
1274
+
1275
+ }
1276
+ else {
1277
+
1278
+ // no area; just iterate all cells. implicitly skip undefined cells.
1279
+
1280
+ for (const row of this.data) {
1281
+ if (row) {
1282
+ for (const cell of row) {
1283
+ if (cell) {
1284
+ yield cell;
1285
+ }
1286
+ }
1287
+ }
1288
+ }
1289
+ }
1290
+ }
1291
+
1292
+ /* *
1151
1293
  * iterates over all cells (using loops) and runs function per-cell.
1152
1294
  * FIXME: switch to indexing on empty indexes? (...)
1153
- */
1295
+ *
1296
+ * removed in favor of generator-based function
1297
+ *
1298
+ * /
1154
1299
  public IterateAll(func: (cell: Cell) => void){
1155
- /*
1300
+ / *
1156
1301
  const row_keys = Object.keys(this.data);
1157
1302
  for (const row of row_keys){
1158
1303
  const n_row = Number(row) || 0;
@@ -1161,7 +1306,7 @@ export class Cells {
1161
1306
  f(this.data[n_row][Number(column_key)]);
1162
1307
  }
1163
1308
  }
1164
- */
1309
+ * /
1165
1310
  for (const row of this.data) {
1166
1311
  if (row) {
1167
1312
  for (const cell of row) {
@@ -1173,6 +1318,7 @@ export class Cells {
1173
1318
  }
1174
1319
 
1175
1320
  }
1321
+ */
1176
1322
 
1177
1323
  /** moved from sheet, so we can do it non-functional style (for perf) */
1178
1324
  public FlushCellStyles() {
@@ -2475,9 +2475,15 @@ export class Calculator extends Graph {
2475
2475
  const unit = dependencies.ranges[key];
2476
2476
  const range = new Area(unit.start, unit.end);
2477
2477
 
2478
+ for (const address of range) {
2479
+ this.AddLeafVertexEdge(address, vertex);
2480
+ }
2481
+
2482
+ /*
2478
2483
  range.Iterate((address: ICellAddress) => {
2479
2484
  this.AddLeafVertexEdge(address, vertex);
2480
2485
  });
2486
+ */
2481
2487
 
2482
2488
  /*
2483
2489
  for (const address of range) {
@@ -2709,7 +2715,13 @@ export class Calculator extends Graph {
2709
2715
  this.AddArrayEdge(range, address);
2710
2716
  }
2711
2717
  else {
2712
- range.Iterate((target: ICellAddress) => this.AddEdge(target, address));
2718
+
2719
+ for (const target of range) {
2720
+ this.AddEdge(target, address);
2721
+ }
2722
+
2723
+ // range.Iterate((target: ICellAddress) => this.AddEdge(target, address));
2724
+
2713
2725
  }
2714
2726
 
2715
2727
 
@@ -47,6 +47,11 @@
47
47
  <button data-command="align-bottom" title="Align to bottom"></button>
48
48
  </div>
49
49
 
50
+ <div class="group" wide indent-group>
51
+ <button data-command="outdent" title="Decrease indent"></button>
52
+ <button data-command="indent" title="Incrase indent"></button>
53
+ </div>
54
+
50
55
  <div class="group">
51
56
  <button data-command="wrap-text" title="Wrap text"></button>
52
57
  <button data-command="merge-cells" data-id="merge" data-inactive-title="Merge cells" data-active-title="Unmerge cells"></button>
@@ -146,6 +146,7 @@ export class SpreadsheetConstructor<USER_DATA_TYPE = unknown> {
146
146
  if (this.root) {
147
147
 
148
148
  const names = this.root.getAttributeNames();
149
+ console.info({names});
149
150
 
150
151
  for (let name of names) {
151
152
 
@@ -202,8 +203,7 @@ export class SpreadsheetConstructor<USER_DATA_TYPE = unknown> {
202
203
  // attrtibute options are in kebab-case while our internal
203
204
  // options are still in snake_case.
204
205
 
205
- name = name.replace(/-/g, '_');
206
- attribute_options[name] = this.CoerceAttributeValue(this.root.getAttribute(name));
206
+ attribute_options[name.replace(/-/g, '_')] = this.CoerceAttributeValue(this.root.getAttribute(name));
207
207
 
208
208
  }
209
209
  }
@@ -910,6 +910,9 @@ export class SpreadsheetConstructor<USER_DATA_TYPE = unknown> {
910
910
  if (!sheet.options.file_menu) {
911
911
  remove.push(toolbar.querySelector('[file-menu]'));
912
912
  }
913
+ if (!sheet.options.indent_buttons) {
914
+ remove.push(toolbar.querySelector('[indent-group]'));
915
+ }
913
916
  if (!sheet.options.font_scale) {
914
917
  remove.push(toolbar.querySelector('[font-scale]'));
915
918
  }
@@ -1846,6 +1846,18 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
1846
1846
  });
1847
1847
  break;
1848
1848
 
1849
+ case 'indent':
1850
+ case 'outdent':
1851
+
1852
+ // hmmm. we should actually adjust selection cell-by-cell so
1853
+ // all entries get +1/-1 from their current level. we don't
1854
+ // want to normalize here. this is unusual.
1855
+
1856
+ // let's make a method here in case we want to use this again
1857
+
1858
+ this.grid.Indent(undefined, (event.command === 'indent') ? 1 : -1);
1859
+ break;
1860
+
1849
1861
  default:
1850
1862
  console.info('unhandled', event.command);
1851
1863
  break;
@@ -2238,11 +2250,15 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
2238
2250
  }
2239
2251
 
2240
2252
  /**
2253
+ * this is a generic version that takes a callback, so we can use
2254
+ * separately from charts. however (atm) we're using leaf vertices that
2255
+ * don't actually calculate, they just indicate the dirty state. so we
2256
+ * won't have access to the result of a calculation in the callback.
2257
+ *
2241
2258
  * @internal
2242
2259
  *
2243
- * @returns an id that can be used to manage the reference
2244
2260
  */
2245
- public CreateConnectedChart(formula: string, target: HTMLElement, options: EvaluateOptions): number {
2261
+ public CreateConnectedFormula(formula: string, callback?: (instance: ConnectedElementType) => void, options: EvaluateOptions = {}): number {
2246
2262
 
2247
2263
  // FIXME: merge w/ insert annotation?
2248
2264
 
@@ -2254,15 +2270,9 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
2254
2270
 
2255
2271
  if (argument_separator === ',') {
2256
2272
  this.parser.SetLocaleSettings(DecimalMarkType.Period);
2257
-
2258
- // this.parser.argument_separator = ArgumentSeparatorType.Comma;
2259
- // this.parser.decimal_mark = DecimalMarkType.Period;
2260
2273
  }
2261
2274
  else {
2262
2275
  this.parser.SetLocaleSettings(DecimalMarkType.Comma);
2263
-
2264
- // this.parser.argument_separator = ArgumentSeparatorType.Semicolon;
2265
- // this.parser.decimal_mark = DecimalMarkType.Comma;
2266
2276
  }
2267
2277
 
2268
2278
  const result = this.parser.Parse(formula);
@@ -2274,19 +2284,41 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
2274
2284
  }
2275
2285
  else {
2276
2286
  console.warn("invalid formula", result.error);
2287
+ throw new Error(`invalid formula`);
2277
2288
  }
2278
2289
 
2279
- const chart = this.CreateChart();
2280
- chart.Initialize(target);
2281
-
2282
2290
  const id = this.model.AddConnectedElement({
2291
+
2283
2292
  formula,
2284
2293
 
2285
2294
  // this is circular, but I want to leave `this` bound to the sheet
2286
2295
  // instance in case we need it -- so what's a better approach? pass
2287
2296
  // in the formula explicitly, and update if we need to make changes?
2288
2297
 
2289
- update: (instance: ConnectedElementType) => {
2298
+ update: callback ? (instance: ConnectedElementType) => {
2299
+ callback.call(0, instance);
2300
+ } : undefined,
2301
+
2302
+ });
2303
+
2304
+ this.calculator.UpdateConnectedElements(this.grid.active_sheet);
2305
+ this.UpdateConnectedElements();
2306
+
2307
+ return id;
2308
+
2309
+ }
2310
+
2311
+ /**
2312
+ * @internal
2313
+ *
2314
+ * @returns an id that can be used to manage the reference
2315
+ */
2316
+ public CreateConnectedChart(formula: string, target: HTMLElement, options: EvaluateOptions): number {
2317
+
2318
+ const chart = this.CreateChart();
2319
+ chart.Initialize(target);
2320
+
2321
+ const callback = (instance: ConnectedElementType) => {
2290
2322
 
2291
2323
  const parse_result = this.parser.Parse(instance.formula);
2292
2324
 
@@ -2310,14 +2342,9 @@ export class EmbeddedSpreadsheet<USER_DATA_TYPE = unknown> {
2310
2342
 
2311
2343
  chart.Update();
2312
2344
 
2313
- },
2314
-
2315
- });
2316
-
2317
- this.calculator.UpdateConnectedElements(this.grid.active_sheet);
2318
- this.UpdateConnectedElements();
2345
+ };
2319
2346
 
2320
- return id;
2347
+ return this.CreateConnectedFormula(formula, callback, options);
2321
2348
 
2322
2349
  }
2323
2350
 
@@ -316,6 +316,11 @@ export interface EmbeddedSpreadsheetOptions {
316
316
  */
317
317
  insert_function_button?: boolean;
318
318
 
319
+ /**
320
+ * indent/outdent buttons; default false
321
+ */
322
+ indent_buttons?: boolean;
323
+
319
324
  }
320
325
 
321
326
  /**
@@ -80,6 +80,10 @@ export interface RevertIndicatorMessage {
80
80
  command: 'revert-indicator';
81
81
  }
82
82
 
83
+ export interface IndentMessage {
84
+ command: 'indent'|'outdent';
85
+ }
86
+
83
87
  export type ToolbarMessage
84
88
  = SetColorToolbarMessage
85
89
  | CommentToolbarMessage
@@ -96,6 +100,7 @@ export type ToolbarMessage
96
100
  | TableToolbarMessage
97
101
  | CommandToolbarMessage
98
102
  | StyleToolbarMessage
103
+ | IndentMessage
99
104
  | NumberFormatToolbarMessage
100
105
  | FontScaleToolbarMessage
101
106
  ;
@@ -264,6 +264,9 @@ $swatch-size: 18px;
264
264
  [data-command=justify-right] { --icon: var(--icon-text-align-right); }
265
265
  [data-command=justify-center] { --icon: var(--icon-text-align-center); }
266
266
 
267
+ [data-command=indent] { --icon: var(--icon-text-indent); }
268
+ [data-command=outdent] { --icon: var(--icon-text-outdent); }
269
+
267
270
  [data-command=align-top] { --icon: var(--icon-text-align-top); }
268
271
  [data-command=align-middle] { --icon: var(--icon-text-align-middle); }
269
272
  [data-command=align-bottom] { --icon: var(--icon-text-align-bottom); }