@ajf/material 18.4.0 → 18.5.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 (80) hide show
  1. package/README.md +167 -2
  2. package/audio/src/audio-module.d.ts +7 -6
  3. package/esm2022/audio/src/audio-module.mjs +22 -4
  4. package/esm2022/audio/src/audio.mjs +6 -6
  5. package/esm2022/barcode/barcode.mjs +3 -3
  6. package/esm2022/calendar/calendar.mjs +2 -2
  7. package/esm2022/checkbox-group/checkbox-group-item.mjs +3 -3
  8. package/esm2022/form-builder/form-builder-module.mjs +9 -2
  9. package/esm2022/form-builder/form-builder-service.mjs +63 -20
  10. package/esm2022/form-builder/form-builder.mjs +73 -9
  11. package/esm2022/form-builder/node-entry.mjs +3 -3
  12. package/esm2022/form-builder/node-properties.mjs +3 -13
  13. package/esm2022/form-builder/node-type-entry.mjs +3 -3
  14. package/esm2022/form-builder/node-type-groups.pipe.mjs +65 -0
  15. package/esm2022/form-builder/public_api.mjs +2 -1
  16. package/esm2022/form-builder/string-identifier-dialog.mjs +44 -60
  17. package/esm2022/forms/boolean-field.mjs +6 -5
  18. package/esm2022/forms/current-slide.mjs +92 -0
  19. package/esm2022/forms/date-input-field.mjs +7 -9
  20. package/esm2022/forms/display-field.mjs +2 -2
  21. package/esm2022/forms/empty-field.mjs +3 -3
  22. package/esm2022/forms/field-row.mjs +117 -0
  23. package/esm2022/forms/field.mjs +2 -2
  24. package/esm2022/forms/form.mjs +107 -13
  25. package/esm2022/forms/forms-module.mjs +26 -3
  26. package/esm2022/forms/input-field.mjs +6 -8
  27. package/esm2022/forms/multiple-choice-field.mjs +45 -10
  28. package/esm2022/forms/public_api.mjs +6 -1
  29. package/esm2022/forms/range-field.mjs +5 -6
  30. package/esm2022/forms/rep-strip.mjs +61 -0
  31. package/esm2022/forms/single-choice-field.mjs +26 -11
  32. package/esm2022/forms/slide-header.mjs +68 -0
  33. package/esm2022/forms/slide-stats.mjs +148 -0
  34. package/esm2022/forms/table-field.mjs +2 -2
  35. package/esm2022/forms/text-field.mjs +2 -2
  36. package/esm2022/forms/video-url-field.mjs +6 -8
  37. package/esm2022/geolocation/geolocation.mjs +4 -6
  38. package/esm2022/page-slider/page-slider.mjs +3 -3
  39. package/esm2022/signature/signature.mjs +5 -6
  40. package/esm2022/time/time-module.mjs +22 -4
  41. package/esm2022/time/time.mjs +4 -4
  42. package/fesm2022/ajf-material-audio.mjs +27 -9
  43. package/fesm2022/ajf-material-audio.mjs.map +1 -1
  44. package/fesm2022/ajf-material-barcode.mjs +2 -2
  45. package/fesm2022/ajf-material-barcode.mjs.map +1 -1
  46. package/fesm2022/ajf-material-calendar.mjs +2 -2
  47. package/fesm2022/ajf-material-calendar.mjs.map +1 -1
  48. package/fesm2022/ajf-material-checkbox-group.mjs +2 -2
  49. package/fesm2022/ajf-material-checkbox-group.mjs.map +1 -1
  50. package/fesm2022/ajf-material-form-builder.mjs +260 -108
  51. package/fesm2022/ajf-material-form-builder.mjs.map +1 -1
  52. package/fesm2022/ajf-material-forms.mjs +712 -99
  53. package/fesm2022/ajf-material-forms.mjs.map +1 -1
  54. package/fesm2022/ajf-material-geolocation.mjs +5 -7
  55. package/fesm2022/ajf-material-geolocation.mjs.map +1 -1
  56. package/fesm2022/ajf-material-page-slider.mjs +2 -2
  57. package/fesm2022/ajf-material-page-slider.mjs.map +1 -1
  58. package/fesm2022/ajf-material-signature.mjs +7 -8
  59. package/fesm2022/ajf-material-signature.mjs.map +1 -1
  60. package/fesm2022/ajf-material-time.mjs +24 -6
  61. package/fesm2022/ajf-material-time.mjs.map +1 -1
  62. package/form-builder/form-builder-module.d.ts +27 -25
  63. package/form-builder/form-builder-service.d.ts +25 -0
  64. package/form-builder/form-builder.d.ts +41 -2
  65. package/form-builder/node-type-groups.pipe.d.ts +45 -0
  66. package/form-builder/public_api.d.ts +1 -0
  67. package/form-builder/string-identifier-dialog.d.ts +10 -16
  68. package/forms/_theming.scss +142 -0
  69. package/forms/current-slide.d.ts +61 -0
  70. package/forms/field-row.d.ts +63 -0
  71. package/forms/form.d.ts +40 -3
  72. package/forms/forms-module.d.ts +57 -51
  73. package/forms/multiple-choice-field.d.ts +15 -1
  74. package/forms/public_api.d.ts +5 -0
  75. package/forms/rep-strip.d.ts +52 -0
  76. package/forms/single-choice-field.d.ts +7 -0
  77. package/forms/slide-header.d.ts +61 -0
  78. package/forms/slide-stats.d.ts +76 -0
  79. package/package.json +2 -2
  80. package/time/time-module.d.ts +4 -3
@@ -23,6 +23,19 @@ import { AjfAttachmentsOrigin, AjfChoicesOrigin, AjfField, AjfFieldType, AjfForm
23
23
  import { AjfCondition } from '@ajf/core/models';
24
24
  import { BehaviorSubject, Observable } from 'rxjs';
25
25
  import * as i0 from "@angular/core";
26
+ /**
27
+ * The categories the entries of the form builder field types palette are
28
+ * grouped into, in display order. The values are translation keys, rendered as
29
+ * the header of each group.
30
+ */
31
+ export declare const AjfFormBuilderNodeTypeCategories: {
32
+ readonly structure: "Structure";
33
+ readonly text: "Text";
34
+ readonly numeric: "Numeric";
35
+ readonly choices: "Choice fields";
36
+ readonly dateTime: "Date & time";
37
+ readonly advanced: "Advanced";
38
+ };
26
39
  export interface AjfFormBuilderNodeTypeEntry {
27
40
  label: string;
28
41
  nodeType: {
@@ -30,6 +43,13 @@ export interface AjfFormBuilderNodeTypeEntry {
30
43
  field?: AjfFieldType;
31
44
  };
32
45
  isSlide?: boolean;
46
+ /**
47
+ * The category the entry belongs to, one of
48
+ * {@link AjfFormBuilderNodeTypeCategories}. Entries sharing a category are
49
+ * rendered under a common header; entries without a category are rendered
50
+ * last, with no header.
51
+ */
52
+ category?: string;
33
53
  }
34
54
  export interface AjfFormBuilderNodeEntry {
35
55
  node: AjfNode;
@@ -79,6 +99,11 @@ export type AjfContainerNode = AjfSlide | AjfRepeatingSlide | AjfNodeGroup;
79
99
  export declare function cleanDefaultValue(value: any, node: AjfField<any>): string | null;
80
100
  export declare function flattenNodes(nodes: AjfNode[]): AjfNode[];
81
101
  export declare class AjfFormBuilderService {
102
+ /**
103
+ * The node types available in the palette, listed by category in display
104
+ * order. Entries of the same category are rendered under a common header, see
105
+ * {@link AjfFormBuilderNodeTypeCategories}.
106
+ */
82
107
  private _availableNodeTypes;
83
108
  /**
84
109
  * Available node types
@@ -20,8 +20,9 @@
20
20
  *
21
21
  */
22
22
  import { AjfChoicesOrigin, AjfForm } from '@ajf/core/forms';
23
+ import { BooleanInput } from '@angular/cdk/coercion';
23
24
  import { CdkDrag, CdkDragDrop } from '@angular/cdk/drag-drop';
24
- import { AfterContentInit, AfterViewChecked, ChangeDetectorRef, ElementRef, OnDestroy } from '@angular/core';
25
+ import { AfterContentInit, AfterViewChecked, ChangeDetectorRef, ElementRef, EventEmitter, OnDestroy } from '@angular/core';
25
26
  import { MatDialog } from '@angular/material/dialog';
26
27
  import { MatSlideToggleChange } from '@angular/material/slide-toggle';
27
28
  import { Observable } from 'rxjs';
@@ -35,6 +36,32 @@ export declare class AjfFormBuilder implements AfterViewChecked, AfterContentIni
35
36
  private _form;
36
37
  get form(): AjfForm | undefined;
37
38
  set form(form: AjfForm | undefined);
39
+ /**
40
+ * True when the slides of the designer are kept expanded. Slides added later
41
+ * follow this state as well.
42
+ * It drives the "expand slides" toggle of the toolbar and can be set by the
43
+ * host, both one-way (`[expandSlides]="true"`) and two-way
44
+ * (`[(expandSlides)]="expanded"`).
45
+ */
46
+ private _expandSlides;
47
+ get expandSlides(): boolean;
48
+ set expandSlides(expandSlides: boolean);
49
+ /**
50
+ * Emits whenever the slides expansion state is changed from inside the form
51
+ * builder, i.e. by the toolbar controls.
52
+ */
53
+ readonly expandSlidesChange: EventEmitter<boolean>;
54
+ /**
55
+ * When true the form builder fills the whole height of its container: the
56
+ * field types palette, the designer and the properties panel stretch to the
57
+ * available height and scroll internally, instead of growing with their
58
+ * content. Requires the container to have a definite height.
59
+ */
60
+ private _fillHeight;
61
+ get fillHeight(): boolean;
62
+ set fillHeight(fillHeight: boolean);
63
+ static ngAcceptInputType_expandSlides: BooleanInput;
64
+ static ngAcceptInputType_fillHeight: BooleanInput;
38
65
  /**
39
66
  * Called to set form builder validation errors
40
67
  */
@@ -79,11 +106,23 @@ export declare class AjfFormBuilder implements AfterViewChecked, AfterContentIni
79
106
  onDrop(event: CdkDragDrop<AjfFormBuilderNodeEntry> | CdkDragDrop<AjfFormBuilderNodeTypeEntry>, content?: boolean): void;
80
107
  editChoicesOrigin(choicesOrigin: AjfChoicesOrigin<any>): void;
81
108
  editStringIdentifier(): void;
109
+ /**
110
+ * Expands all the slides of the designer and keeps the slides added later expanded.
111
+ */
82
112
  expandAll(): void;
113
+ /**
114
+ * Collapses all the slides of the designer and keeps the slides added later collapsed.
115
+ */
83
116
  collapseAll(): void;
84
117
  expandToggle(evt: MatSlideToggleChange): void;
118
+ /**
119
+ * Applies the slides expansion state to the service.
120
+ * @param expanded True to keep the slides expanded
121
+ * @param notify True to emit expandSlidesChange when the state changes
122
+ */
123
+ private _setSlidesExpanded;
85
124
  downloadAsXlsform(): Promise<void>;
86
125
  private _setCurrentForm;
87
126
  static ɵfac: i0.ɵɵFactoryDeclaration<AjfFormBuilder, never>;
88
- static ɵcmp: i0.ɵɵComponentDeclaration<AjfFormBuilder, "ajf-form-builder", never, { "form": { "alias": "form"; "required": false; }; }, { "formBuilderValidation": "formBuilderValidation"; }, never, never, false, never>;
127
+ static ɵcmp: i0.ɵɵComponentDeclaration<AjfFormBuilder, "ajf-form-builder", never, { "form": { "alias": "form"; "required": false; }; "expandSlides": { "alias": "expandSlides"; "required": false; }; "fillHeight": { "alias": "fillHeight"; "required": false; }; }, { "expandSlidesChange": "expandSlidesChange"; "formBuilderValidation": "formBuilderValidation"; }, never, never, false, never>;
89
128
  }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @license
3
+ * Copyright (C) Gnucoop soc. coop.
4
+ *
5
+ * This file is part of the Advanced JSON forms (ajf).
6
+ *
7
+ * Advanced JSON forms (ajf) is free software: you can redistribute it and/or
8
+ * modify it under the terms of the GNU Affero General Public License as
9
+ * published by the Free Software Foundation, either version 3 of the License,
10
+ * or (at your option) any later version.
11
+ *
12
+ * Advanced JSON forms (ajf) is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Affero General Public License
18
+ * along with Advanced JSON forms (ajf).
19
+ * If not, see http://www.gnu.org/licenses/.
20
+ *
21
+ */
22
+ import { PipeTransform } from '@angular/core';
23
+ import { AjfFormBuilderNodeTypeEntry } from './form-builder-service';
24
+ import * as i0 from "@angular/core";
25
+ /**
26
+ * A group of node types of the palette, rendered under a common header.
27
+ */
28
+ export interface AjfFormBuilderNodeTypeGroup {
29
+ /**
30
+ * The translation key of the group header. Empty for the group of the entries
31
+ * that have no category, which is rendered without a header.
32
+ */
33
+ category: string;
34
+ nodeTypes: AjfFormBuilderNodeTypeEntry[];
35
+ }
36
+ /**
37
+ * Groups the node types of the palette by category, keeping the categories in
38
+ * the order of their first entry. Applied after the search filter, so that the
39
+ * categories left without entries produce no header.
40
+ */
41
+ export declare class NodeTypeGroupsPipe implements PipeTransform {
42
+ transform(nodeTypes: AjfFormBuilderNodeTypeEntry[]): AjfFormBuilderNodeTypeGroup[];
43
+ static ɵfac: i0.ɵɵFactoryDeclaration<NodeTypeGroupsPipe, never>;
44
+ static ɵpipe: i0.ɵɵPipeDeclaration<NodeTypeGroupsPipe, "nodeTypeGroups", false>;
45
+ }
@@ -23,3 +23,4 @@ export * from './form-builder-module';
23
23
  export * from './form-builder-service';
24
24
  export * from './form-builder-utils';
25
25
  export * from './form-builder';
26
+ export * from './node-type-groups.pipe';
@@ -19,30 +19,24 @@
19
19
  * If not, see http://www.gnu.org/licenses/.
20
20
  *
21
21
  */
22
- import { AjfFormStringIdentifier } from '@ajf/core/forms';
23
- import { ChangeDetectorRef, OnDestroy } from '@angular/core';
24
- import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
25
- import { MatChipInputEvent } from '@angular/material/chips';
26
- import { MatTableDataSource } from '@angular/material/table';
22
+ import { AjfField } from '@ajf/core/forms';
23
+ import { OnDestroy } from '@angular/core';
24
+ import { FormControl } from '@angular/forms';
27
25
  import { Observable } from 'rxjs';
28
26
  import { AjfFormBuilderService } from './form-builder-service';
29
27
  import * as i0 from "@angular/core";
30
28
  export declare class AjfFbStringIdentifierDialogComponent implements OnDestroy {
31
29
  private _service;
32
- private _cdr;
33
- readonly dataSource: MatTableDataSource<AjfFormStringIdentifier>;
34
- readonly displayedColumns: string[];
35
- readonly fields$: Observable<string[]>;
36
- readonly separatorKeysCodes: number[];
30
+ readonly fields$: Observable<AjfField[]>;
31
+ readonly filteredFields$: Observable<AjfField[]>;
32
+ readonly searchFilterCtrl: FormControl<string>;
33
+ selectedFieldNames: string[];
34
+ private _fields;
35
+ private _fieldsSub;
37
36
  private _stringIdentifierSub;
38
- constructor(_service: AjfFormBuilderService, _cdr: ChangeDetectorRef);
39
- addRow(): void;
40
- deleteRow(rowIdx: number): void;
41
- addValue(row: AjfFormStringIdentifier, evt: MatChipInputEvent, valueInput: HTMLInputElement): void;
42
- removeValue(row: AjfFormStringIdentifier, value: string): void;
37
+ constructor(_service: AjfFormBuilderService);
43
38
  ngOnDestroy(): void;
44
39
  saveStringIdentifier(): void;
45
- selected(row: AjfFormStringIdentifier, evt: MatAutocompleteSelectedEvent): void;
46
40
  static ɵfac: i0.ɵɵFactoryDeclaration<AjfFbStringIdentifierDialogComponent, never>;
47
41
  static ɵcmp: i0.ɵɵComponentDeclaration<AjfFbStringIdentifierDialogComponent, "ajf-fb-string-identifier-dialog", never, {}, {}, never, never, false, never>;
48
42
  }
@@ -0,0 +1,142 @@
1
+ // Public theming API of the AJF form renderer.
2
+ //
3
+ // The renderer paints itself from a set of `--ajf-*` custom properties. Their
4
+ // defaults already follow Angular Material's M3 system variables where a host
5
+ // publishes them, so an application themed with `use-system-variables: true`
6
+ // needs nothing from this file.
7
+ //
8
+ // Everything else -- an M2 theme, a prebuilt theme, or an M3 theme without
9
+ // system variables -- has a theme object but no system variables, and that is
10
+ // what this mixin is for:
11
+ //
12
+ // @use '@angular/material' as mat;
13
+ // @use '@ajf/material/forms/theming' as ajf-forms;
14
+ //
15
+ // $theme: mat.define-light-theme(...); // or mat.define-theme(...)
16
+ //
17
+ // :root {
18
+ // @include mat.all-component-themes($theme);
19
+ // @include ajf-forms.theme($theme);
20
+ // }
21
+ //
22
+ // For a light and a dark theme, include it once per selector -- the renderer's
23
+ // own `.ajf-dark` / `.ajf-light` classes and its `prefers-color-scheme` block
24
+ // only carry the built-in palette, so once you hand it your own colours you also
25
+ // own the switch:
26
+ //
27
+ // .my-dark-theme {
28
+ // @include mat.all-component-colors($dark-theme);
29
+ // @include ajf-forms.theme($dark-theme);
30
+ // }
31
+ //
32
+ // This file emits custom properties only -- no selectors, no component styles --
33
+ // so including it more than once costs nothing but the declarations.
34
+
35
+ @use 'sass:list';
36
+ @use '@angular/material' as mat;
37
+
38
+ /// The M3 colour role behind each token.
39
+ $_m3-roles: (
40
+ bg: surface-container-low,
41
+ surface: surface,
42
+ band: surface-container,
43
+ border: outline-variant,
44
+ border-strong: outline,
45
+ accent: primary,
46
+ accent-fg: on-primary,
47
+ accent-soft: primary-container,
48
+ accent-ink: on-primary-container,
49
+ text: on-surface,
50
+ text-muted: on-surface-variant,
51
+ danger: error,
52
+ danger-bg: error-container,
53
+ );
54
+
55
+ /// The M2 palette/hue pair behind each token. M2 has no container roles, so the
56
+ /// soft surfaces are taken from the theme's background palette and the tinted
57
+ /// ones are mixed from the accent at include time.
58
+ $_m2-colors: (
59
+ bg: (background, background),
60
+ surface: (background, card),
61
+ band: (background, app-bar),
62
+ border: (foreground, divider),
63
+ accent: (primary, default),
64
+ accent-fg: (primary, default-contrast),
65
+ text: (foreground, text),
66
+ text-muted: (foreground, secondary-text),
67
+ danger: (warn, default),
68
+ );
69
+
70
+ /// M2's dividers are far too faint to draw a control box with, so the border a
71
+ /// control carries is mixed from the theme's own text colour instead.
72
+ $_m2-control-border-mix: 32%;
73
+
74
+ @mixin _m3($theme) {
75
+ @each $name, $role in $_m3-roles {
76
+ --ajf-#{$name}: #{mat.get-theme-color($theme, $role)};
77
+ }
78
+
79
+ $primary: mat.get-theme-color($theme, primary);
80
+ $on-primary: mat.get-theme-color($theme, on-primary);
81
+
82
+ --ajf-text-faint: color-mix(
83
+ in srgb,
84
+ #{mat.get-theme-color($theme, on-surface-variant)} 70%,
85
+ transparent
86
+ );
87
+ --ajf-accent-hover: color-mix(in srgb, #{$primary} 85%, #{$on-primary});
88
+ // Sits on the filled accent, so it is tinted with the accent's own contrast.
89
+ --ajf-kbd-bg: color-mix(in srgb, #{$on-primary} 22%, transparent);
90
+ // What a filled button falls back to once disabled: the accent gone, a flat
91
+ // neutral in its place, and the ordinary text colour on top -- readable on
92
+ // either palette, where the accent's contrast colour is not.
93
+ --ajf-disabled-bg: color-mix(
94
+ in srgb,
95
+ #{mat.get-theme-color($theme, on-surface)} 12%,
96
+ #{mat.get-theme-color($theme, surface)}
97
+ );
98
+ --ajf-disabled-fg: color-mix(
99
+ in srgb,
100
+ #{mat.get-theme-color($theme, on-surface)} 65%,
101
+ #{mat.get-theme-color($theme, surface)}
102
+ );
103
+ }
104
+
105
+ @mixin _m2($theme) {
106
+ @each $name, $color in $_m2-colors {
107
+ --ajf-#{$name}: #{mat.get-theme-color($theme, list.nth($color, 1), list.nth($color, 2))};
108
+ }
109
+
110
+ $primary: mat.get-theme-color($theme, primary, default);
111
+ $on-primary: mat.get-theme-color($theme, primary, default-contrast);
112
+ $warn: mat.get-theme-color($theme, warn, default);
113
+ $card: mat.get-theme-color($theme, background, card);
114
+ $text: mat.get-theme-color($theme, foreground, text);
115
+ $secondary: mat.get-theme-color($theme, foreground, secondary-text);
116
+
117
+ --ajf-border-strong: color-mix(in srgb, #{$text} #{$_m2-control-border-mix}, #{$card});
118
+ --ajf-accent-soft: color-mix(in srgb, #{$primary} 12%, #{$card});
119
+ --ajf-accent-ink: color-mix(in srgb, #{$primary} 80%, #{$secondary});
120
+ --ajf-accent-hover: color-mix(in srgb, #{$primary} 85%, #{$secondary});
121
+ --ajf-danger-bg: color-mix(in srgb, #{$warn} 10%, #{$card});
122
+ --ajf-text-faint: color-mix(in srgb, #{$secondary} 70%, transparent);
123
+ --ajf-kbd-bg: color-mix(in srgb, #{$on-primary} 22%, transparent);
124
+ // See the M3 branch: disabled, a filled button goes flat neutral and keeps
125
+ // the ordinary text colour.
126
+ --ajf-disabled-bg: color-mix(in srgb, #{$text} 12%, #{$card});
127
+ --ajf-disabled-fg: color-mix(in srgb, #{$text} 65%, #{$card});
128
+ }
129
+
130
+ /// Map an Angular Material theme onto the AJF form tokens.
131
+ /// Accepts both an M2 theme (`define-light-theme`, `define-dark-theme`, the
132
+ /// prebuilt themes) and an M3 one (`define-theme`).
133
+ @mixin theme($theme) {
134
+ $version: mat.get-theme-version($theme);
135
+ @if $version == 0 {
136
+ @include _m2($theme);
137
+ } @else if $version == 1 {
138
+ @include _m3($theme);
139
+ } @else {
140
+ @error 'Unsupported Angular Material theme version: #{$version}.';
141
+ }
142
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @license
3
+ * Copyright (C) Gnucoop soc. coop.
4
+ *
5
+ * This file is part of the Advanced JSON forms (ajf).
6
+ *
7
+ * Advanced JSON forms (ajf) is free software: you can redistribute it and/or
8
+ * modify it under the terms of the GNU Affero General Public License as
9
+ * published by the Free Software Foundation, either version 3 of the License,
10
+ * or (at your option) any later version.
11
+ *
12
+ * Advanced JSON forms (ajf) is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Affero General Public License
18
+ * along with Advanced JSON forms (ajf).
19
+ * If not, see http://www.gnu.org/licenses/.
20
+ *
21
+ */
22
+ import { AjfSlideInstance } from '@ajf/core/forms';
23
+ import { PipeTransform } from '@angular/core';
24
+ import * as i0 from "@angular/core";
25
+ /** Which slide the page slider is currently showing, and where it sits. */
26
+ export interface AjfCurrentSlide {
27
+ /** Null while a start or end message page is on screen. */
28
+ slide: AjfSlideInstance | null;
29
+ /** The repetition on screen, zero based; 0 for a non-repeating slide. */
30
+ repIndex: number;
31
+ /** How many repetitions the slide has; 0 when it does not repeat. */
32
+ reps: number;
33
+ /** The slide's ordinal among the visible ones, for the header badge. */
34
+ displayNumber: number;
35
+ /** How many visible slides the form has. */
36
+ total: number;
37
+ /**
38
+ * How many pages the slider holds: one per visible slide, one per repetition
39
+ * of a repeating slide, plus the start and end message pages. Nothing to
40
+ * navigate to when this is 1.
41
+ */
42
+ pages: number;
43
+ }
44
+ /**
45
+ * Resolve the page slider's current page into a slide.
46
+ *
47
+ * The renderer lays out one page per slide, and one page per repetition of a
48
+ * repeating slide, optionally preceded by a start message page -- the same
49
+ * arithmetic the error navigation in `AjfFormRenderer` performs.
50
+ *
51
+ * Impure, because slide visibility and repetition counts are mutated in place.
52
+ * The result is memoized so that the pipe keeps handing back the same object
53
+ * while nothing has moved: returning a fresh one on every check would trip
54
+ * Angular's "expression has changed after it was checked" guard.
55
+ */
56
+ export declare class AjfCurrentSlidePipe implements PipeTransform {
57
+ private _last;
58
+ transform(slides: AjfSlideInstance[] | null, currentPage: number, hasStartMessage: boolean, hasEndMessage?: boolean): AjfCurrentSlide;
59
+ static ɵfac: i0.ɵɵFactoryDeclaration<AjfCurrentSlidePipe, never>;
60
+ static ɵpipe: i0.ɵɵPipeDeclaration<AjfCurrentSlidePipe, "ajfCurrentSlide", false>;
61
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @license
3
+ * Copyright (C) Gnucoop soc. coop.
4
+ *
5
+ * This file is part of the Advanced JSON forms (ajf).
6
+ *
7
+ * Advanced JSON forms (ajf) is free software: you can redistribute it and/or
8
+ * modify it under the terms of the GNU Affero General Public License as
9
+ * published by the Free Software Foundation, either version 3 of the License,
10
+ * or (at your option) any later version.
11
+ *
12
+ * Advanced JSON forms (ajf) is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU Affero General Public License
18
+ * along with Advanced JSON forms (ajf).
19
+ * If not, see http://www.gnu.org/licenses/.
20
+ *
21
+ */
22
+ import { AjfFieldInstance } from '@ajf/core/forms';
23
+ import { BooleanInput } from '@angular/cdk/coercion';
24
+ import { ChangeDetectorRef, OnDestroy } from '@angular/core';
25
+ import * as i0 from "@angular/core";
26
+ /**
27
+ * One field of a slide, laid out as a row: type badge, label, control, and a
28
+ * right-hand column carrying either the field description or its validation
29
+ * error.
30
+ *
31
+ * Both the plain and the repeating slide branches of the renderer render through
32
+ * this component, so the row layout is defined in exactly one place.
33
+ */
34
+ export declare class AjfFieldRow implements OnDestroy {
35
+ private _cdr;
36
+ set instance(instance: AjfFieldInstance);
37
+ get instance(): AjfFieldInstance;
38
+ private _instance;
39
+ private _instanceSub;
40
+ constructor(_cdr: ChangeDetectorRef);
41
+ ngOnDestroy(): void;
42
+ set readonly(readonly: boolean);
43
+ get readonly(): boolean;
44
+ private _readonly;
45
+ /**
46
+ * Rows drop out on the host element rather than inside it, so that a hidden
47
+ * field leaves no empty cell behind when rows are laid out in columns.
48
+ *
49
+ * Three kinds of node carry no information of their own and are kept out of
50
+ * the layout: a container node, which is only a bracket around the fields it
51
+ * holds and has no fieldType to render; a formula field with no label, which
52
+ * only feeds other fields; and a note with no body -- the renderer synthesises
53
+ * one of those to carry a node group's label, and a group is meant to show
54
+ * nothing of itself.
55
+ */
56
+ get hidden(): boolean;
57
+ /** Notes render their own block and never get a control border around it. */
58
+ get isNote(): boolean;
59
+ get required(): boolean;
60
+ static ngAcceptInputType_readonly: BooleanInput;
61
+ static ɵfac: i0.ɵɵFactoryDeclaration<AjfFieldRow, never>;
62
+ static ɵcmp: i0.ɵɵComponentDeclaration<AjfFieldRow, "ajf-field-row", never, { "instance": { "alias": "instance"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; }, {}, never, never, false, never>;
63
+ }
package/forms/form.d.ts CHANGED
@@ -19,16 +19,53 @@
19
19
  * If not, see http://www.gnu.org/licenses/.
20
20
  *
21
21
  */
22
- import { AjfFormRenderer as CoreFormRenderer, AjfFormRendererService, AjfFieldInstance } from '@ajf/core/forms';
22
+ import { AjfFieldInstance, AjfFormRenderer as CoreFormRenderer, AjfFormRendererService, AjfSlideInstance } from '@ajf/core/forms';
23
23
  import { BooleanInput } from '@angular/cdk/coercion';
24
- import { ChangeDetectorRef } from '@angular/core';
24
+ import { AfterViewChecked, ChangeDetectorRef, OnDestroy } from '@angular/core';
25
25
  import * as i0 from "@angular/core";
26
- export declare class AjfFormRenderer extends CoreFormRenderer {
26
+ export declare class AjfFormRenderer extends CoreFormRenderer implements AfterViewChecked, OnDestroy {
27
+ /**
28
+ * @deprecated The slide strip has been replaced by the jump menu in the slide
29
+ * header, which is always available. Kept so that existing templates still
30
+ * compile.
31
+ */
27
32
  topBar: boolean;
33
+ /**
34
+ * @deprecated Field rows align their labels and controls on a shared grid, so
35
+ * there is nothing left to centre.
36
+ */
28
37
  centeredFieldsContent: boolean;
38
+ /** How many field rows sit side by side. */
29
39
  maxColumns: 1 | 2 | 3;
40
+ /**
41
+ * The page the slider is showing. The slide header is rendered once, above the
42
+ * slider, so it needs to know which slide is on screen; the page slider only
43
+ * reports that imperatively, hence the mirrored property.
44
+ */
45
+ currentPage: number;
46
+ private _slideList;
47
+ private _validitySubscription;
48
+ private _slidesSubscription;
49
+ private _valueSubscription;
50
+ private _pageSubscription;
51
+ private _pageInit;
30
52
  constructor(rendererService: AjfFormRendererService, changeDetectorRef: ChangeDetectorRef);
53
+ ngAfterViewChecked(): void;
54
+ ngOnDestroy(): void;
31
55
  fieldStyle(field: AjfFieldInstance): any;
56
+ /** Page to the first page of a slide, from the header's jump menu. */
57
+ goToSlide(slide: AjfSlideInstance): void;
58
+ /** Page to one repetition of the repeating slide currently on screen. */
59
+ goToRep(slide: AjfSlideInstance, repIndex: number): void;
60
+ goToPrevSlide(): void;
61
+ goToNextSlide(): void;
62
+ /**
63
+ * The slider page a slide starts on. `AjfSlideInstance.position` cannot be
64
+ * used directly here: it does not account for a start message page, and this
65
+ * has to agree with the page arithmetic used by `ajfCurrentSlide`.
66
+ */
67
+ private _pageOf;
68
+ private _slideTo;
32
69
  static ngAcceptInputType_fixedOrientation: BooleanInput;
33
70
  static ngAcceptInputType_hasEndMessage: BooleanInput;
34
71
  static ngAcceptInputType_hasStartMessage: BooleanInput;