@ng-doc/app 22.0.0-beta.2 → 22.1.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.
- package/README.md +20 -29
- package/fesm2022/ng-doc-app-classes-content-anchor-controller.mjs +363 -0
- package/fesm2022/ng-doc-app-classes-content-anchor-controller.mjs.map +1 -0
- package/fesm2022/ng-doc-app-classes-content-controller.mjs +299 -0
- package/fesm2022/ng-doc-app-classes-content-controller.mjs.map +1 -0
- package/fesm2022/ng-doc-app-classes-default-search-engine.mjs +51 -35
- package/fesm2022/ng-doc-app-classes-default-search-engine.mjs.map +1 -1
- package/fesm2022/ng-doc-app-classes-root-page.mjs.map +1 -1
- package/fesm2022/ng-doc-app-classes-search-engine.mjs.map +1 -1
- package/fesm2022/ng-doc-app-classes.mjs +2 -0
- package/fesm2022/ng-doc-app-classes.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-api-list.mjs +173 -69
- package/fesm2022/ng-doc-app-components-api-list.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-breadcrumb.mjs +13 -10
- package/fesm2022/ng-doc-app-components-breadcrumb.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-code.mjs +152 -25
- package/fesm2022/ng-doc-app-components-code.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-command-palette.mjs +498 -0
- package/fesm2022/ng-doc-app-components-command-palette.mjs.map +1 -0
- package/fesm2022/ng-doc-app-components-copy-button.mjs +38 -21
- package/fesm2022/ng-doc-app-components-copy-button.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-demo-displayer.mjs +36 -29
- package/fesm2022/ng-doc-app-components-demo-displayer.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-demo-frame.mjs +96 -0
- package/fesm2022/ng-doc-app-components-demo-frame.mjs.map +1 -0
- package/fesm2022/ng-doc-app-components-demo-pane.mjs +39 -36
- package/fesm2022/ng-doc-app-components-demo-pane.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-demo.mjs +175 -44
- package/fesm2022/ng-doc-app-components-demo.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-fullscreen-button.mjs +12 -9
- package/fesm2022/ng-doc-app-components-fullscreen-button.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-fullscreen-toggle.mjs +79 -0
- package/fesm2022/ng-doc-app-components-fullscreen-toggle.mjs.map +1 -0
- package/fesm2022/ng-doc-app-components-heading-anchor.mjs +54 -21
- package/fesm2022/ng-doc-app-components-heading-anchor.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-image-viewer.mjs +183 -89
- package/fesm2022/ng-doc-app-components-image-viewer.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-kind-icon.mjs +42 -25
- package/fesm2022/ng-doc-app-components-kind-icon.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-link.mjs +12 -9
- package/fesm2022/ng-doc-app-components-link.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-members.mjs +30 -0
- package/fesm2022/ng-doc-app-components-members.mjs.map +1 -0
- package/fesm2022/ng-doc-app-components-mermaid-viewer.mjs +61 -20
- package/fesm2022/ng-doc-app-components-mermaid-viewer.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-navbar.mjs +39 -49
- package/fesm2022/ng-doc-app-components-navbar.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-page-header.mjs +73 -10
- package/fesm2022/ng-doc-app-components-page-header.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-page-link.mjs +123 -31
- package/fesm2022/ng-doc-app-components-page-link.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-page-navigation.mjs +17 -19
- package/fesm2022/ng-doc-app-components-page-navigation.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-page-wrapper.mjs +56 -35
- package/fesm2022/ng-doc-app-components-page-wrapper.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-page.mjs +168 -24
- package/fesm2022/ng-doc-app-components-page.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-playground.mjs +477 -286
- package/fesm2022/ng-doc-app-components-playground.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-root.mjs +48 -31
- package/fesm2022/ng-doc-app-components-root.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-search-result.mjs +22 -21
- package/fesm2022/ng-doc-app-components-search-result.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-search.mjs +64 -33
- package/fesm2022/ng-doc-app-components-search.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-sidebar.mjs +86 -61
- package/fesm2022/ng-doc-app-components-sidebar.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-tabs.mjs +35 -11
- package/fesm2022/ng-doc-app-components-tabs.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-theme-toggle.mjs +33 -21
- package/fesm2022/ng-doc-app-components-theme-toggle.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components-toc.mjs +267 -90
- package/fesm2022/ng-doc-app-components-toc.mjs.map +1 -1
- package/fesm2022/ng-doc-app-components.mjs +4 -1
- package/fesm2022/ng-doc-app-components.mjs.map +1 -1
- package/fesm2022/ng-doc-app-defaults-default-processors.mjs +2 -1
- package/fesm2022/ng-doc-app-defaults-default-processors.mjs.map +1 -1
- package/fesm2022/ng-doc-app-demo-app.mjs +176 -0
- package/fesm2022/ng-doc-app-demo-app.mjs.map +1 -0
- package/fesm2022/ng-doc-app-directives-code-highlighter.mjs +11 -5
- package/fesm2022/ng-doc-app-directives-code-highlighter.mjs.map +1 -1
- package/fesm2022/ng-doc-app-directives-members-filter.mjs +276 -0
- package/fesm2022/ng-doc-app-directives-members-filter.mjs.map +1 -0
- package/fesm2022/ng-doc-app-directives-route-active.mjs +34 -30
- package/fesm2022/ng-doc-app-directives-route-active.mjs.map +1 -1
- package/fesm2022/ng-doc-app-directives.mjs +1 -0
- package/fesm2022/ng-doc-app-directives.mjs.map +1 -1
- package/fesm2022/ng-doc-app-helpers.mjs +307 -2
- package/fesm2022/ng-doc-app-helpers.mjs.map +1 -1
- package/fesm2022/ng-doc-app-pipes-decode-uri-component.mjs +6 -4
- package/fesm2022/ng-doc-app-pipes-decode-uri-component.mjs.map +1 -1
- package/fesm2022/ng-doc-app-pipes-extract-value.mjs +6 -4
- package/fesm2022/ng-doc-app-pipes-extract-value.mjs.map +1 -1
- package/fesm2022/ng-doc-app-pipes-filter-by-text.mjs +7 -4
- package/fesm2022/ng-doc-app-pipes-filter-by-text.mjs.map +1 -1
- package/fesm2022/ng-doc-app-pipes-sanitize-html.mjs +8 -5
- package/fesm2022/ng-doc-app-pipes-sanitize-html.mjs.map +1 -1
- package/fesm2022/ng-doc-app-processors-page-processor.mjs +86 -23
- package/fesm2022/ng-doc-app-processors-page-processor.mjs.map +1 -1
- package/fesm2022/ng-doc-app-processors-processors-tooltip.mjs +26 -25
- package/fesm2022/ng-doc-app-processors-processors-tooltip.mjs.map +1 -1
- package/fesm2022/ng-doc-app-processors-processors.mjs +42 -10
- package/fesm2022/ng-doc-app-processors-processors.mjs.map +1 -1
- package/fesm2022/ng-doc-app-providers-ng-doc-app.mjs +31 -2
- package/fesm2022/ng-doc-app-providers-ng-doc-app.mjs.map +1 -1
- package/fesm2022/ng-doc-app-providers-title.mjs +129 -0
- package/fesm2022/ng-doc-app-providers-title.mjs.map +1 -0
- package/fesm2022/ng-doc-app-providers.mjs +1 -0
- package/fesm2022/ng-doc-app-providers.mjs.map +1 -1
- package/fesm2022/ng-doc-app-services-content-scroll-intent.mjs +122 -0
- package/fesm2022/ng-doc-app-services-content-scroll-intent.mjs.map +1 -0
- package/fesm2022/ng-doc-app-services-content-state.mjs +57 -0
- package/fesm2022/ng-doc-app-services-content-state.mjs.map +1 -0
- package/fesm2022/ng-doc-app-services-fullscreen-route.mjs +74 -0
- package/fesm2022/ng-doc-app-services-fullscreen-route.mjs.map +1 -0
- package/fesm2022/ng-doc-app-services-highlighter.mjs +90 -17
- package/fesm2022/ng-doc-app-services-highlighter.mjs.map +1 -1
- package/fesm2022/ng-doc-app-services-route-preloader.mjs +384 -0
- package/fesm2022/ng-doc-app-services-route-preloader.mjs.map +1 -0
- package/fesm2022/ng-doc-app-services-shortcuts.mjs +214 -0
- package/fesm2022/ng-doc-app-services-shortcuts.mjs.map +1 -0
- package/fesm2022/ng-doc-app-services-sidebar.mjs +59 -25
- package/fesm2022/ng-doc-app-services-sidebar.mjs.map +1 -1
- package/fesm2022/ng-doc-app-services-store.mjs +8 -8
- package/fesm2022/ng-doc-app-services-store.mjs.map +1 -1
- package/fesm2022/ng-doc-app-services-theme.mjs +32 -12
- package/fesm2022/ng-doc-app-services-theme.mjs.map +1 -1
- package/fesm2022/ng-doc-app-services.mjs +143 -0
- package/fesm2022/ng-doc-app-services.mjs.map +1 -1
- package/fesm2022/ng-doc-app-tokens.mjs +7 -28
- package/fesm2022/ng-doc-app-tokens.mjs.map +1 -1
- package/fesm2022/ng-doc-app-type-controls-boolean-control.mjs +18 -9
- package/fesm2022/ng-doc-app-type-controls-boolean-control.mjs.map +1 -1
- package/fesm2022/ng-doc-app-type-controls-number-control.mjs +12 -9
- package/fesm2022/ng-doc-app-type-controls-number-control.mjs.map +1 -1
- package/fesm2022/ng-doc-app-type-controls-string-control.mjs +12 -9
- package/fesm2022/ng-doc-app-type-controls-string-control.mjs.map +1 -1
- package/fesm2022/ng-doc-app-type-controls-type-alias-control.mjs +59 -18
- package/fesm2022/ng-doc-app-type-controls-type-alias-control.mjs.map +1 -1
- package/package.json +82 -28
- package/styles/global.css +1128 -201
- package/styles/main.css +1128 -201
- package/styles/themes/dark.css +88 -56
- package/types/ng-doc-app-classes-content-anchor-controller.d.ts +54 -0
- package/types/ng-doc-app-classes-content-controller.d.ts +94 -0
- package/types/ng-doc-app-classes-default-search-engine.d.ts +9 -1
- package/types/ng-doc-app-classes-root-page.d.ts +14 -1
- package/types/ng-doc-app-classes-search-engine.d.ts +5 -0
- package/types/ng-doc-app-classes.d.ts +2 -0
- package/types/ng-doc-app-components-api-list.d.ts +69 -20
- package/types/ng-doc-app-components-breadcrumb.d.ts +8 -3
- package/types/ng-doc-app-components-code.d.ts +46 -12
- package/types/ng-doc-app-components-command-palette.d.ts +147 -0
- package/types/ng-doc-app-components-copy-button.d.ts +18 -6
- package/types/ng-doc-app-components-demo-displayer.d.ts +23 -10
- package/types/ng-doc-app-components-demo-frame.d.ts +48 -0
- package/types/ng-doc-app-components-demo-pane.d.ts +19 -15
- package/types/ng-doc-app-components-demo.d.ts +80 -15
- package/types/ng-doc-app-components-fullscreen-button.d.ts +4 -2
- package/types/ng-doc-app-components-fullscreen-toggle.d.ts +24 -0
- package/types/ng-doc-app-components-heading-anchor.d.ts +26 -7
- package/types/ng-doc-app-components-image-viewer.d.ts +71 -7
- package/types/ng-doc-app-components-kind-icon.d.ts +28 -7
- package/types/ng-doc-app-components-link.d.ts +6 -2
- package/types/ng-doc-app-components-members.d.ts +13 -0
- package/types/ng-doc-app-components-mermaid-viewer.d.ts +21 -6
- package/types/ng-doc-app-components-navbar.d.ts +25 -15
- package/types/ng-doc-app-components-page-header.d.ts +28 -4
- package/types/ng-doc-app-components-page-link.d.ts +34 -15
- package/types/ng-doc-app-components-page-navigation.d.ts +10 -5
- package/types/ng-doc-app-components-page-wrapper.d.ts +35 -11
- package/types/ng-doc-app-components-page.d.ts +57 -6
- package/types/ng-doc-app-components-playground.d.ts +167 -78
- package/types/ng-doc-app-components-root.d.ts +28 -7
- package/types/ng-doc-app-components-search-result.d.ts +14 -6
- package/types/ng-doc-app-components-search.d.ts +19 -7
- package/types/ng-doc-app-components-tabs.d.ts +24 -5
- package/types/ng-doc-app-components-theme-toggle.d.ts +18 -5
- package/types/ng-doc-app-components-toc.d.ts +76 -29
- package/types/ng-doc-app-components.d.ts +4 -1
- package/types/ng-doc-app-demo-app.d.ts +89 -0
- package/types/ng-doc-app-directives-code-highlighter.d.ts +8 -4
- package/types/ng-doc-app-directives-members-filter.d.ts +61 -0
- package/types/ng-doc-app-directives-route-active.d.ts +21 -7
- package/types/ng-doc-app-directives.d.ts +1 -0
- package/types/ng-doc-app-helpers.d.ts +142 -3
- package/types/ng-doc-app-interfaces.d.ts +62 -31
- package/types/ng-doc-app-pipes-decode-uri-component.d.ts +3 -0
- package/types/ng-doc-app-pipes-extract-value.d.ts +3 -0
- package/types/ng-doc-app-pipes-filter-by-text.d.ts +4 -0
- package/types/ng-doc-app-pipes-sanitize-html.d.ts +4 -2
- package/types/ng-doc-app-processors-page-processor.d.ts +39 -10
- package/types/ng-doc-app-processors-processors-tooltip.d.ts +11 -10
- package/types/ng-doc-app-processors-processors.d.ts +10 -1
- package/types/ng-doc-app-providers-ng-doc-app.d.ts +18 -1
- package/types/ng-doc-app-providers-title.d.ts +59 -0
- package/types/ng-doc-app-providers.d.ts +1 -0
- package/types/ng-doc-app-services-content-scroll-intent.d.ts +52 -0
- package/types/ng-doc-app-services-content-state.d.ts +40 -0
- package/types/ng-doc-app-services-fullscreen-route.d.ts +35 -0
- package/types/ng-doc-app-services-highlighter.d.ts +47 -5
- package/types/ng-doc-app-services-route-preloader.d.ts +121 -0
- package/types/ng-doc-app-services-shortcuts.d.ts +96 -0
- package/types/ng-doc-app-services-sidebar.d.ts +24 -4
- package/types/ng-doc-app-services-store.d.ts +24 -1
- package/types/ng-doc-app-services-theme.d.ts +19 -3
- package/types/ng-doc-app-services.d.ts +77 -0
- package/types/ng-doc-app-tokens.d.ts +10 -30
- package/types/ng-doc-app-type-controls-boolean-control.d.ts +11 -6
- package/types/ng-doc-app-type-controls-number-control.d.ts +5 -3
- package/types/ng-doc-app-type-controls-string-control.d.ts +5 -3
- package/types/ng-doc-app-type-controls-type-alias-control.d.ts +35 -6
- package/fesm2022/ng-doc-app-components-search-dialog.mjs +0 -78
- package/fesm2022/ng-doc-app-components-search-dialog.mjs.map +0 -1
- package/types/ng-doc-app-components-search-dialog.d.ts +0 -28
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import {
|
|
2
|
+
import { input, viewChild, ViewContainerRef, signal, inject, Injector, DestroyRef, PendingTasks, ChangeDetectionStrategy, Component, computed, effect, untracked, reflectComponentType, model, output, isDevMode, linkedSignal, ChangeDetectorRef, Directive } from '@angular/core';
|
|
3
3
|
import { extractFunctionDefaults } from '@ng-doc/core/helpers/extract-function-defaults';
|
|
4
4
|
import { Subject, take } from 'rxjs';
|
|
5
5
|
import * as i1 from '@angular/forms';
|
|
@@ -7,57 +7,83 @@ import { FormsModule, FormBuilder } from '@angular/forms';
|
|
|
7
7
|
import { NgDocRootPage } from '@ng-doc/app/classes/root-page';
|
|
8
8
|
import { isSameObject } from '@ng-doc/core/helpers/is-same-object';
|
|
9
9
|
import { objectKeys } from '@ng-doc/core/helpers/object-keys';
|
|
10
|
-
import { NgDocLabelComponent, NgDocTooltipDirective,
|
|
10
|
+
import { NgDocLabelComponent, NgDocTooltipDirective, NgDocCheckboxComponent, NgDocIconComponent, NgDocBindPipe, NgDocExecutePipe, NgDocAsArrayPipe } from '@ng-doc/ui-kit';
|
|
11
11
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
12
12
|
import { NgDocDemoDisplayerComponent } from '@ng-doc/app/components/demo-displayer';
|
|
13
|
-
import { formatHtml, isPlaygroundProperty } from '@ng-doc/app/helpers';
|
|
13
|
+
import { formatHtml, isPlaygroundProperty, resolvePlaygroundOption } from '@ng-doc/app/helpers';
|
|
14
14
|
import { getPlaygroundDemoToken } from '@ng-doc/app/providers/playground-demo';
|
|
15
15
|
import { buildPlaygroundDemoPipeTemplate, buildPlaygroundDemoTemplate } from '@ng-doc/core/helpers/build-playground-demo-template';
|
|
16
16
|
import { stringify } from '@ng-doc/core/helpers/stringify';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import { AsyncPipe, KeyValuePipe } from '@angular/common';
|
|
17
|
+
import { startWith, takeUntil } from 'rxjs/operators';
|
|
18
|
+
import { NgTemplateOutlet, KeyValuePipe } from '@angular/common';
|
|
20
19
|
import { getTokenForType } from '@ng-doc/app/providers/type-control';
|
|
21
|
-
import { extractValueOrThrow } from '@ng-doc/core/helpers/extract-value';
|
|
22
20
|
import { isPresent } from '@ng-doc/core/helpers/is-present';
|
|
21
|
+
import { NgDocKindIconComponent } from '@ng-doc/app/components/kind-icon';
|
|
23
22
|
import { NgDocSanitizeHtmlPipe } from '@ng-doc/app/pipes';
|
|
24
23
|
|
|
24
|
+
/**
|
|
25
|
+
* One demo of a playground: it creates the generated playground class of its selector (or pipe),
|
|
26
|
+
* passes it the form's values and shows the code of the current state.
|
|
27
|
+
*/
|
|
25
28
|
class NgDocPlaygroundDemoComponent {
|
|
26
29
|
constructor() {
|
|
27
|
-
|
|
28
|
-
this.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
this.
|
|
32
|
-
|
|
30
|
+
/** The name of the playground in the page configuration. */
|
|
31
|
+
this.id = input('', /* @ts-ignore */
|
|
32
|
+
...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
33
|
+
/** The name of the pipe, when the target is a pipe. */
|
|
34
|
+
this.pipeName = input('', /* @ts-ignore */
|
|
35
|
+
...(ngDevMode ? [{ debugName: "pipeName" }] : /* istanbul ignore next */ []));
|
|
36
|
+
/** The selector of the target this demo renders. */
|
|
37
|
+
this.selector = input('', /* @ts-ignore */
|
|
38
|
+
...(ngDevMode ? [{ debugName: "selector" }] : /* istanbul ignore next */ []));
|
|
39
|
+
/** The playground configuration, extended by the action's options. */
|
|
40
|
+
this.configuration = input(undefined, /* @ts-ignore */
|
|
41
|
+
...(ngDevMode ? [{ debugName: "configuration" }] : /* istanbul ignore next */ []));
|
|
42
|
+
/** The inputs of the target. */
|
|
43
|
+
this.properties = input(undefined, /* @ts-ignore */
|
|
44
|
+
...(ngDevMode ? [{ debugName: "properties" }] : /* istanbul ignore next */ []));
|
|
45
|
+
/** Whether the demo is created again each time a value changes. */
|
|
46
|
+
this.recreateDemo = input(false, /* @ts-ignore */
|
|
47
|
+
...(ngDevMode ? [{ debugName: "recreateDemo" }] : /* istanbul ignore next */ []));
|
|
48
|
+
/** The values of the inputs and content slots. */
|
|
49
|
+
this.form = input(undefined, /* @ts-ignore */
|
|
50
|
+
...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
|
|
51
|
+
/** Whether the code of the demo is shown. */
|
|
52
|
+
this.expanded = input(false, /* @ts-ignore */
|
|
53
|
+
...(ngDevMode ? [{ debugName: "expanded" }] : /* istanbul ignore next */ []));
|
|
54
|
+
/** Where the playground class is created. */
|
|
55
|
+
this.demoOutlet = viewChild('demoOutlet', { ...(ngDevMode ? { debugName: "demoOutlet" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
|
|
56
|
+
this.code = signal('', /* @ts-ignore */
|
|
57
|
+
...(ngDevMode ? [{ debugName: "code" }] : /* istanbul ignore next */ []));
|
|
33
58
|
this.injector = inject(Injector);
|
|
34
|
-
this.changeDetectorRef = inject(ChangeDetectorRef);
|
|
35
59
|
this.destroyRef = inject(DestroyRef);
|
|
60
|
+
this.pendingTasks = inject(PendingTasks);
|
|
36
61
|
this.unsubscribe$ = new Subject();
|
|
37
62
|
}
|
|
38
63
|
async ngOnChanges({ form, id }) {
|
|
39
64
|
if (form || id) {
|
|
40
65
|
this.unsubscribe$.next();
|
|
41
|
-
const demoInjector = getPlaygroundDemoToken(this.id);
|
|
66
|
+
const demoInjector = getPlaygroundDemoToken(this.id());
|
|
42
67
|
if (demoInjector) {
|
|
43
68
|
const demos = this.injector.get(demoInjector, []);
|
|
44
|
-
this.playgroundDemo = demos.find((demo) => demo.selector === this.selector || demo.selector === this.pipeName);
|
|
69
|
+
this.playgroundDemo = demos.find((demo) => demo.selector === this.selector() || demo.selector === this.pipeName());
|
|
45
70
|
}
|
|
46
71
|
await this.updateDemo();
|
|
47
|
-
this.form
|
|
48
|
-
|
|
72
|
+
const form = this.form();
|
|
73
|
+
form?.valueChanges
|
|
74
|
+
.pipe(startWith(form.value), takeUntil(this.unsubscribe$), takeUntilDestroyed(this.destroyRef))
|
|
49
75
|
.subscribe((data) => this.updateDemo(data));
|
|
50
76
|
}
|
|
51
77
|
}
|
|
52
78
|
async updateDemo(data) {
|
|
53
|
-
if (this.recreateDemo || !this.demoRef) {
|
|
79
|
+
if (this.recreateDemo() || !this.demoRef) {
|
|
54
80
|
this.createDemo();
|
|
55
81
|
}
|
|
56
82
|
if (data) {
|
|
57
83
|
this.demoRef?.setInput('properties', data.properties ?? {});
|
|
58
84
|
this.demoRef?.setInput('content', data.content ?? {});
|
|
59
|
-
this.demoRef?.setInput('actionData', this.configuration?.data ?? {});
|
|
60
|
-
if (this.recreateDemo) {
|
|
85
|
+
this.demoRef?.setInput('actionData', this.configuration()?.data ?? {});
|
|
86
|
+
if (this.recreateDemo()) {
|
|
61
87
|
this.demoRef?.instance.onReattached.subscribe(() => {
|
|
62
88
|
this.demoRef?.changeDetectorRef.detectChanges();
|
|
63
89
|
});
|
|
@@ -68,28 +94,35 @@ class NgDocPlaygroundDemoComponent {
|
|
|
68
94
|
createDemo() {
|
|
69
95
|
if (this.playgroundDemo) {
|
|
70
96
|
this.demoRef?.destroy();
|
|
71
|
-
this.demoRef = this.demoOutlet?.createComponent(this.playgroundDemo);
|
|
97
|
+
this.demoRef = this.demoOutlet()?.createComponent(this.playgroundDemo);
|
|
72
98
|
this.demoRef?.changeDetectorRef.markForCheck();
|
|
73
99
|
}
|
|
74
100
|
}
|
|
75
101
|
async updateCodeView() {
|
|
76
|
-
const template = this.pipeName
|
|
77
|
-
? buildPlaygroundDemoPipeTemplate(this.configuration?.template ?? '', this.pipeName, this.getActiveContent(), this.getPipeActiveInputs())
|
|
78
|
-
: buildPlaygroundDemoTemplate(this.configuration?.template ?? '', this.selector, this.getActiveContent(), this.getActiveInputs());
|
|
79
|
-
|
|
80
|
-
|
|
102
|
+
const template = this.pipeName()
|
|
103
|
+
? buildPlaygroundDemoPipeTemplate(this.configuration()?.template ?? '', this.pipeName(), this.getActiveContent(), this.getPipeActiveInputs())
|
|
104
|
+
: buildPlaygroundDemoTemplate(this.configuration()?.template ?? '', this.selector(), this.getActiveContent(), this.getActiveInputs());
|
|
105
|
+
// Formatting loads the formatter asynchronously. Zoneless SSR waits only for pending tasks, so
|
|
106
|
+
// the page would otherwise be serialized before the code view is filled.
|
|
107
|
+
const done = this.pendingTasks.add();
|
|
108
|
+
try {
|
|
109
|
+
this.code.set(await formatHtml(template));
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
done();
|
|
113
|
+
}
|
|
81
114
|
}
|
|
82
115
|
getActiveContent() {
|
|
83
|
-
const formData = this.form?.controls.content.value ?? {};
|
|
116
|
+
const formData = this.form()?.controls.content.value ?? {};
|
|
84
117
|
return objectKeys(formData).reduce((result, key) => {
|
|
85
|
-
result[key] = formData[key] ? this.configuration?.content?.[key].template ?? '' : '';
|
|
118
|
+
result[key] = formData[key] ? this.configuration()?.content?.[key].template ?? '' : '';
|
|
86
119
|
return result;
|
|
87
120
|
}, {});
|
|
88
121
|
}
|
|
89
122
|
getActiveInputs() {
|
|
90
|
-
const formData = this.form?.controls.properties.value ?? {};
|
|
123
|
+
const formData = this.form()?.controls.properties.value ?? {};
|
|
91
124
|
return objectKeys(formData).reduce((result, key) => {
|
|
92
|
-
const inputName = this.properties?.[key]?.inputName ?? key;
|
|
125
|
+
const inputName = this.properties()?.[key]?.inputName ?? key;
|
|
93
126
|
const value = formData[key];
|
|
94
127
|
const property = this.demoRef?.instance?.defaultValues[key];
|
|
95
128
|
if (property !== value) {
|
|
@@ -99,7 +132,7 @@ class NgDocPlaygroundDemoComponent {
|
|
|
99
132
|
}, {});
|
|
100
133
|
}
|
|
101
134
|
getPipeActiveInputs() {
|
|
102
|
-
const formData = this.form?.controls.properties.value ?? {};
|
|
135
|
+
const formData = this.form()?.controls.properties.value ?? {};
|
|
103
136
|
let changedInputIndex = -1;
|
|
104
137
|
return objectKeys(formData)
|
|
105
138
|
.map((key, i) => {
|
|
@@ -120,152 +153,260 @@ class NgDocPlaygroundDemoComponent {
|
|
|
120
153
|
this.unsubscribe$.next();
|
|
121
154
|
this.unsubscribe$.complete();
|
|
122
155
|
}
|
|
123
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
124
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
156
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocPlaygroundDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
157
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.2.1", type: NgDocPlaygroundDemoComponent, isStandalone: true, selector: "ng-doc-playground-demo", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, pipeName: { classPropertyName: "pipeName", publicName: "pipeName", isSignal: true, isRequired: false, transformFunction: null }, selector: { classPropertyName: "selector", publicName: "selector", isSignal: true, isRequired: false, transformFunction: null }, configuration: { classPropertyName: "configuration", publicName: "configuration", isSignal: true, isRequired: false, transformFunction: null }, properties: { classPropertyName: "properties", publicName: "properties", isSignal: true, isRequired: false, transformFunction: null }, recreateDemo: { classPropertyName: "recreateDemo", publicName: "recreateDemo", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "demoOutlet", first: true, predicate: ["demoOutlet"], descendants: true, read: ViewContainerRef, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<ng-doc-demo-displayer\n [code]=\"code()\"\n [border]=\"false\"\n [expanded]=\"expanded()\"\n language=\"angular-html\">\n <ng-container #demoOutlet></ng-container>\n</ng-doc-demo-displayer>\n", styles: [":host{display:flex;flex-direction:column}ng-doc-demo-displayer{flex:1 1 auto}\n"], dependencies: [{ kind: "component", type: NgDocDemoDisplayerComponent, selector: "ng-doc-demo-displayer", inputs: ["codeContent", "code", "language", "container", "border", "expanded"], outputs: ["expandedChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
125
158
|
}
|
|
126
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
159
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocPlaygroundDemoComponent, decorators: [{
|
|
127
160
|
type: Component,
|
|
128
|
-
args: [{ selector: 'ng-doc-playground-demo', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgDocDemoDisplayerComponent], template: "<ng-doc-demo-displayer
|
|
129
|
-
}], propDecorators: { id: [{
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
type: Input
|
|
133
|
-
}], selector: [{
|
|
134
|
-
type: Input
|
|
135
|
-
}], configuration: [{
|
|
136
|
-
type: Input
|
|
137
|
-
}], properties: [{
|
|
138
|
-
type: Input
|
|
139
|
-
}], recreateDemo: [{
|
|
140
|
-
type: Input
|
|
141
|
-
}], form: [{
|
|
142
|
-
type: Input
|
|
143
|
-
}], expanded: [{
|
|
144
|
-
type: Input
|
|
145
|
-
}], demoOutlet: [{
|
|
146
|
-
type: ViewChild,
|
|
147
|
-
args: ['demoOutlet', { static: true, read: ViewContainerRef }]
|
|
148
|
-
}] } });
|
|
161
|
+
args: [{ selector: 'ng-doc-playground-demo', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgDocDemoDisplayerComponent], template: "<ng-doc-demo-displayer\n [code]=\"code()\"\n [border]=\"false\"\n [expanded]=\"expanded()\"\n language=\"angular-html\">\n <ng-container #demoOutlet></ng-container>\n</ng-doc-demo-displayer>\n", styles: [":host{display:flex;flex-direction:column}ng-doc-demo-displayer{flex:1 1 auto}\n"] }]
|
|
162
|
+
}], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], pipeName: [{ type: i0.Input, args: [{ isSignal: true, alias: "pipeName", required: false }] }], selector: [{ type: i0.Input, args: [{ isSignal: true, alias: "selector", required: false }] }], configuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "configuration", required: false }] }], properties: [{ type: i0.Input, args: [{ isSignal: true, alias: "properties", required: false }] }], recreateDemo: [{ type: i0.Input, args: [{ isSignal: true, alias: "recreateDemo", required: false }] }], form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: false }] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }], demoOutlet: [{ type: i0.ViewChild, args: ['demoOutlet', { ...{
|
|
163
|
+
read: ViewContainerRef,
|
|
164
|
+
}, isSignal: true }] }] } });
|
|
149
165
|
|
|
166
|
+
let nextId = 0;
|
|
167
|
+
/** Value types that have a chip colour. */
|
|
168
|
+
const CHIP_TYPES = new Set([
|
|
169
|
+
'string',
|
|
170
|
+
'number',
|
|
171
|
+
'boolean',
|
|
172
|
+
'object',
|
|
173
|
+
'null',
|
|
174
|
+
'undefined',
|
|
175
|
+
]);
|
|
176
|
+
/**
|
|
177
|
+
* One row of the playground inspector: the input's name with its type chip, and the type
|
|
178
|
+
* control that edits it, bound to the input's form control.
|
|
179
|
+
*/
|
|
150
180
|
class NgDocPlaygroundPropertyComponent {
|
|
151
181
|
constructor() {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
182
|
+
/** Name of the input. */
|
|
183
|
+
this.name = input('', /* @ts-ignore */
|
|
184
|
+
...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
|
|
185
|
+
/** The input, or the content slot. */
|
|
186
|
+
this.property = input(undefined, /* @ts-ignore */
|
|
187
|
+
...(ngDevMode ? [{ debugName: "property" }] : /* istanbul ignore next */ []));
|
|
188
|
+
/** The type control that edits the input. */
|
|
189
|
+
this.typeControl = input(undefined, /* @ts-ignore */
|
|
190
|
+
...(ngDevMode ? [{ debugName: "typeControl" }] : /* istanbul ignore next */ []));
|
|
191
|
+
/** Form control of the input. */
|
|
192
|
+
this.control = input(undefined, /* @ts-ignore */
|
|
193
|
+
...(ngDevMode ? [{ debugName: "control" }] : /* istanbul ignore next */ []));
|
|
194
|
+
/** Default value of the input. */
|
|
195
|
+
this.defaultValue = input(undefined, /* @ts-ignore */
|
|
196
|
+
...(ngDevMode ? [{ debugName: "defaultValue" }] : /* istanbul ignore next */ []));
|
|
197
|
+
/** Whether a type control is rendered. */
|
|
198
|
+
this.hasPropertyControl = signal(false, /* @ts-ignore */
|
|
199
|
+
...(ngDevMode ? [{ debugName: "hasPropertyControl" }] : /* istanbul ignore next */ []));
|
|
200
|
+
/** Description of the input, shown in the tooltip of its name. */
|
|
201
|
+
this.tooltipContent = computed(() => {
|
|
202
|
+
const property = this.property();
|
|
203
|
+
return property && isPlaygroundProperty(property) ? property.description ?? '' : '';
|
|
204
|
+
}, /* @ts-ignore */
|
|
205
|
+
...(ngDevMode ? [{ debugName: "tooltipContent" }] : /* istanbul ignore next */ []));
|
|
206
|
+
/** Options of the type control provider. */
|
|
207
|
+
this.option = computed(() => this.typeControl()?.options, /* @ts-ignore */
|
|
208
|
+
...(ngDevMode ? [{ debugName: "option" }] : /* istanbul ignore next */ []));
|
|
209
|
+
/** The value type shown as a chip under the name, or an empty string. */
|
|
210
|
+
this.typeChip = computed(() => valueType(this.property()), /* @ts-ignore */
|
|
211
|
+
...(ngDevMode ? [{ debugName: "typeChip" }] : /* istanbul ignore next */ []));
|
|
212
|
+
/** Whether the row is a `<label>` around the control, unless its provider opts out. */
|
|
213
|
+
this.labelWrapper = computed(() => this.option()?.labelWrapper !== false, /* @ts-ignore */
|
|
214
|
+
...(ngDevMode ? [{ debugName: "labelWrapper" }] : /* istanbul ignore next */ []));
|
|
215
|
+
/** ID of the caption that names the control of a row without the `<label>`. */
|
|
216
|
+
this.captionId = `ng-doc-playground-property-caption-${nextId++}`;
|
|
217
|
+
// The outlet is in the `<label>` or in the `<div>` of the row, so the query follows the branch.
|
|
218
|
+
this.propertyOutlet = viewChild('propertyOutlet', { ...(ngDevMode ? { debugName: "propertyOutlet" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
|
|
219
|
+
// A plain effect, not an after-render hook: it runs during change detection on the server
|
|
220
|
+
// too, so server-rendered and prerendered pages include the controls. The outlet is inside
|
|
221
|
+
// the row's `@if` branch, so the query reports it once the branch renders, and the effect
|
|
222
|
+
// runs again then. It also runs again when an input it reads changes.
|
|
223
|
+
effect(() => {
|
|
224
|
+
const outlet = this.propertyOutlet();
|
|
225
|
+
const property = this.property();
|
|
226
|
+
const typeControl = this.typeControl();
|
|
227
|
+
const control = this.control();
|
|
228
|
+
const defaultValue = this.defaultValue();
|
|
229
|
+
if (outlet) {
|
|
230
|
+
untracked(() => this.createControl(outlet, property, typeControl, control, defaultValue));
|
|
176
231
|
}
|
|
232
|
+
});
|
|
233
|
+
inject(DestroyRef).onDestroy(() => this.propertyTypeControl?.destroy());
|
|
234
|
+
}
|
|
235
|
+
createControl(outlet, property, typeControl, formControl, defaultValue) {
|
|
236
|
+
if (!property || !typeControl) {
|
|
237
|
+
return;
|
|
177
238
|
}
|
|
239
|
+
this.propertyTypeControl?.destroy();
|
|
240
|
+
const control = outlet.createComponent(typeControl.control);
|
|
241
|
+
this.propertyTypeControl = control;
|
|
242
|
+
setTypeControlField(control, 'name', this.name());
|
|
243
|
+
setTypeControlField(control, 'description', this.tooltipContent());
|
|
244
|
+
setTypeControlField(control, 'options', isPlaygroundProperty(property) ? property.options : undefined);
|
|
245
|
+
setTypeControlField(control, 'default', defaultValue);
|
|
246
|
+
setTypeControlField(control, 'isManual', isPlaygroundProperty(property) ? property.isManual : undefined);
|
|
247
|
+
control.instance.writeValue(formControl?.value);
|
|
248
|
+
if (formControl) {
|
|
249
|
+
formControl.registerOnChange((value) => control.instance.writeValue(value));
|
|
250
|
+
control.instance.registerOnChange((value) => formControl.setValue(value));
|
|
251
|
+
control.instance.registerOnTouched(() => formControl.markAsTouched());
|
|
252
|
+
}
|
|
253
|
+
this.hasPropertyControl.set(true);
|
|
254
|
+
}
|
|
255
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocPlaygroundPropertyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
256
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.1", type: NgDocPlaygroundPropertyComponent, isStandalone: true, selector: "ng-doc-playground-property", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, property: { classPropertyName: "property", publicName: "property", isSignal: true, isRequired: false, transformFunction: null }, typeControl: { classPropertyName: "typeControl", publicName: "typeControl", isSignal: true, isRequired: false, transformFunction: null }, control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-has-property-control": "hasPropertyControl()" } }, viewQueries: [{ propertyName: "propertyOutlet", first: true, predicate: ["propertyOutlet"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "@if (labelWrapper()) {\n <label\n class=\"ng-doc-playground-property-label\"\n [class.with-label]=\"!option()?.hideLabel\"\n [ng-doc-label]=\"option()?.hideLabel ? '' : labelContent\">\n <ng-container #propertyOutlet></ng-container>\n </label>\n} @else {\n <!-- A control with several interactive parts: a label would forward clicks on them to the first\n of them, so the caption names the control through aria-labelledby instead. -->\n <div\n class=\"ng-doc-playground-property-label ng-doc-playground-property-group\"\n role=\"group\"\n [class.with-label]=\"!option()?.hideLabel\"\n [attr.aria-labelledby]=\"option()?.hideLabel ? null : captionId\">\n @if (!option()?.hideLabel) {\n <span class=\"ng-doc-label\" [id]=\"captionId\">\n <ng-container [ngTemplateOutlet]=\"labelContent\"></ng-container>\n </span>\n }\n <span class=\"ng-doc-content\">\n <ng-container #propertyOutlet></ng-container>\n </span>\n </div>\n}\n<ng-template #labelContent>\n <span\n class=\"ng-doc-playground-property-name\"\n [ngDocTooltip]=\"tooltipTemplate\"\n [canOpen]=\"!!tooltipContent()\"\n [positions]=\"['left-center', 'top-right', 'bottom-right']\"\n >{{ name() }}</span\n >\n @if (typeChip(); as type) {\n <ng-doc-kind-icon [kind]=\"type\" type=\"type\"></ng-doc-kind-icon>\n }\n <ng-template #tooltipTemplate>\n <div [innerHTML]=\"tooltipContent() | ngDocSanitizeHtml\"></div>\n </ng-template>\n</ng-template>\n", styles: [":host{display:block}:host[data-has-property-control=false]{display:none}.ng-doc-playground-property-group{display:flex;flex-direction:column;align-items:flex-start}.ng-doc-playground-property-group>.ng-doc-content{display:flex;flex-direction:column;align-items:flex-start;width:100%}.ng-doc-playground-property-label.with-label{display:grid;grid-template-columns:84px minmax(0,1fr);align-items:center;gap:var(--ng-doc-space-3)}.ng-doc-playground-property-label.with-label ::ng-deep>.ng-doc-label{display:grid;justify-items:start;gap:var(--ng-doc-space-1);min-width:0;margin:0}.ng-doc-playground-property-label.with-label ::ng-deep>.ng-doc-content{width:100%;min-width:0}.ng-doc-playground-property-name{max-width:100%;overflow:hidden;text-overflow:ellipsis;font-family:var(--ng-doc-code-font);font-size:13px;line-height:18px;font-weight:500;color:var(--ng-doc-heading-color)}\n"], dependencies: [{ kind: "component", type: NgDocLabelComponent, selector: "label[ng-doc-label]", inputs: ["ng-doc-label", "align"] }, { kind: "directive", type: NgDocTooltipDirective, selector: "[ngDocTooltip]", inputs: ["ngDocTooltip", "delay", "displayOrigin", "pointerOrigin", "positions", "canOpen", "panelClass", "minHeight", "maxHeight", "height", "minWidth", "maxWidth", "width"], outputs: ["beforeOpen", "afterOpen", "beforeClose", "afterClose"], exportAs: ["ngDocTooltip"] }, { kind: "component", type: NgDocKindIconComponent, selector: "ng-doc-kind-icon", inputs: ["kind", "type", "size"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: NgDocSanitizeHtmlPipe, name: "ngDocSanitizeHtml" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
257
|
+
}
|
|
258
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocPlaygroundPropertyComponent, decorators: [{
|
|
259
|
+
type: Component,
|
|
260
|
+
args: [{ selector: 'ng-doc-playground-property', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
261
|
+
NgDocLabelComponent,
|
|
262
|
+
NgDocTooltipDirective,
|
|
263
|
+
NgDocSanitizeHtmlPipe,
|
|
264
|
+
NgDocKindIconComponent,
|
|
265
|
+
NgTemplateOutlet,
|
|
266
|
+
], host: {
|
|
267
|
+
'[attr.data-has-property-control]': 'hasPropertyControl()',
|
|
268
|
+
}, template: "@if (labelWrapper()) {\n <label\n class=\"ng-doc-playground-property-label\"\n [class.with-label]=\"!option()?.hideLabel\"\n [ng-doc-label]=\"option()?.hideLabel ? '' : labelContent\">\n <ng-container #propertyOutlet></ng-container>\n </label>\n} @else {\n <!-- A control with several interactive parts: a label would forward clicks on them to the first\n of them, so the caption names the control through aria-labelledby instead. -->\n <div\n class=\"ng-doc-playground-property-label ng-doc-playground-property-group\"\n role=\"group\"\n [class.with-label]=\"!option()?.hideLabel\"\n [attr.aria-labelledby]=\"option()?.hideLabel ? null : captionId\">\n @if (!option()?.hideLabel) {\n <span class=\"ng-doc-label\" [id]=\"captionId\">\n <ng-container [ngTemplateOutlet]=\"labelContent\"></ng-container>\n </span>\n }\n <span class=\"ng-doc-content\">\n <ng-container #propertyOutlet></ng-container>\n </span>\n </div>\n}\n<ng-template #labelContent>\n <span\n class=\"ng-doc-playground-property-name\"\n [ngDocTooltip]=\"tooltipTemplate\"\n [canOpen]=\"!!tooltipContent()\"\n [positions]=\"['left-center', 'top-right', 'bottom-right']\"\n >{{ name() }}</span\n >\n @if (typeChip(); as type) {\n <ng-doc-kind-icon [kind]=\"type\" type=\"type\"></ng-doc-kind-icon>\n }\n <ng-template #tooltipTemplate>\n <div [innerHTML]=\"tooltipContent() | ngDocSanitizeHtml\"></div>\n </ng-template>\n</ng-template>\n", styles: [":host{display:block}:host[data-has-property-control=false]{display:none}.ng-doc-playground-property-group{display:flex;flex-direction:column;align-items:flex-start}.ng-doc-playground-property-group>.ng-doc-content{display:flex;flex-direction:column;align-items:flex-start;width:100%}.ng-doc-playground-property-label.with-label{display:grid;grid-template-columns:84px minmax(0,1fr);align-items:center;gap:var(--ng-doc-space-3)}.ng-doc-playground-property-label.with-label ::ng-deep>.ng-doc-label{display:grid;justify-items:start;gap:var(--ng-doc-space-1);min-width:0;margin:0}.ng-doc-playground-property-label.with-label ::ng-deep>.ng-doc-content{width:100%;min-width:0}.ng-doc-playground-property-name{max-width:100%;overflow:hidden;text-overflow:ellipsis;font-family:var(--ng-doc-code-font);font-size:13px;line-height:18px;font-weight:500;color:var(--ng-doc-heading-color)}\n"] }]
|
|
269
|
+
}], ctorParameters: () => [], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], property: [{ type: i0.Input, args: [{ isSignal: true, alias: "property", required: false }] }], typeControl: [{ type: i0.Input, args: [{ isSignal: true, alias: "typeControl", required: false }] }], control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: false }] }], defaultValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValue", required: false }] }], propertyOutlet: [{ type: i0.ViewChild, args: ['propertyOutlet', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
|
|
270
|
+
/**
|
|
271
|
+
* The value type of an input: its declared type when it is a primitive, else the type of the first
|
|
272
|
+
* value of its type alias. Content slots are booleans.
|
|
273
|
+
* @param property - The input or the content slot.
|
|
274
|
+
*/
|
|
275
|
+
function valueType(property) {
|
|
276
|
+
if (!property) {
|
|
277
|
+
return '';
|
|
278
|
+
}
|
|
279
|
+
if (!isPlaygroundProperty(property)) {
|
|
280
|
+
return 'boolean';
|
|
178
281
|
}
|
|
179
|
-
|
|
180
|
-
return
|
|
282
|
+
if (CHIP_TYPES.has(property.type)) {
|
|
283
|
+
return property.type;
|
|
181
284
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
285
|
+
const option = property.options?.[0];
|
|
286
|
+
if (option !== undefined) {
|
|
287
|
+
try {
|
|
288
|
+
const type = typeof resolvePlaygroundOption(option, property.isManual).value;
|
|
289
|
+
return CHIP_TYPES.has(type) ? type : '';
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
return '';
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return '';
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Sets a field of a type control: through `ComponentRef.setInput()` when the control declares it
|
|
299
|
+
* as an input (a signal input or a decorator input), otherwise by assigning the plain field.
|
|
300
|
+
* @param control - The created type control.
|
|
301
|
+
* @param field - Name of the field.
|
|
302
|
+
* @param value - Value to set.
|
|
303
|
+
*/
|
|
304
|
+
function setTypeControlField(control, field, value) {
|
|
305
|
+
const input = reflectComponentType(control.componentType)?.inputs.find(({ propName }) => propName === field);
|
|
306
|
+
if (input) {
|
|
307
|
+
control.setInput(input.templateName, value);
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
control.instance[field] = value;
|
|
186
311
|
}
|
|
187
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: NgDocPlaygroundPropertyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
188
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.6", type: NgDocPlaygroundPropertyComponent, isStandalone: true, selector: "ng-doc-playground-property", inputs: { name: "name", property: "property", typeControl: "typeControl", control: "control", defaultValue: "defaultValue" }, host: { properties: { "attr.data-has-property-control": "this.hasPropertyControl" } }, viewQueries: [{ propertyName: "propertyOutlet", first: true, predicate: ["propertyOutlet"], descendants: true, read: ViewContainerRef, static: true }], usesOnChanges: true, ngImport: i0, template: "<label [ng-doc-label]=\"option?.hideLabel ? '' : labelContent\">\n\t<ng-template #labelContent>\n\t\t<span\n\t\t\t[ngDocTooltip]=\"tooltipTemplate\"\n\t\t\t[canOpen]=\"!!tooltipContent\"\n\t\t\t[positions]=\"['left-center', 'top-right', 'bottom-right']\"\n\t\t\t>{{ name }}</span\n\t\t>\n\t\t<ng-template #tooltipTemplate>\n\t\t\t<div [innerHTML]=\"tooltipContent | ngDocSanitizeHtml\"></div>\n\t\t</ng-template>\n\t</ng-template>\n\t<ng-container #propertyOutlet></ng-container>\n</label>\n", styles: [":host{display:block}:host[data-has-property-control=false]{display:none}\n"], dependencies: [{ kind: "component", type: NgDocLabelComponent, selector: "label[ng-doc-label]", inputs: ["ng-doc-label", "align"] }, { kind: "directive", type: NgDocTooltipDirective, selector: "[ngDocTooltip]", inputs: ["ngDocTooltip", "delay", "displayOrigin", "pointerOrigin", "positions", "canOpen", "panelClass", "minHeight", "maxHeight", "height", "minWidth", "maxWidth", "width"], outputs: ["beforeOpen", "afterOpen", "beforeClose", "afterClose"], exportAs: ["ngDocTooltip"] }, { kind: "pipe", type: NgDocSanitizeHtmlPipe, name: "ngDocSanitizeHtml" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
189
312
|
}
|
|
190
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: NgDocPlaygroundPropertyComponent, decorators: [{
|
|
191
|
-
type: Component,
|
|
192
|
-
args: [{ selector: 'ng-doc-playground-property', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgDocLabelComponent, NgDocTooltipDirective, NgDocSanitizeHtmlPipe], template: "<label [ng-doc-label]=\"option?.hideLabel ? '' : labelContent\">\n\t<ng-template #labelContent>\n\t\t<span\n\t\t\t[ngDocTooltip]=\"tooltipTemplate\"\n\t\t\t[canOpen]=\"!!tooltipContent\"\n\t\t\t[positions]=\"['left-center', 'top-right', 'bottom-right']\"\n\t\t\t>{{ name }}</span\n\t\t>\n\t\t<ng-template #tooltipTemplate>\n\t\t\t<div [innerHTML]=\"tooltipContent | ngDocSanitizeHtml\"></div>\n\t\t</ng-template>\n\t</ng-template>\n\t<ng-container #propertyOutlet></ng-container>\n</label>\n", styles: [":host{display:block}:host[data-has-property-control=false]{display:none}\n"] }]
|
|
193
|
-
}], propDecorators: { name: [{
|
|
194
|
-
type: Input
|
|
195
|
-
}], property: [{
|
|
196
|
-
type: Input
|
|
197
|
-
}], typeControl: [{
|
|
198
|
-
type: Input
|
|
199
|
-
}], control: [{
|
|
200
|
-
type: Input
|
|
201
|
-
}], defaultValue: [{
|
|
202
|
-
type: Input
|
|
203
|
-
}], propertyOutlet: [{
|
|
204
|
-
type: ViewChild,
|
|
205
|
-
args: ['propertyOutlet', { read: ViewContainerRef, static: true }]
|
|
206
|
-
}], hasPropertyControl: [{
|
|
207
|
-
type: HostBinding,
|
|
208
|
-
args: ['attr.data-has-property-control']
|
|
209
|
-
}] } });
|
|
210
313
|
|
|
314
|
+
/**
|
|
315
|
+
* Orders inputs without an `order` by name in English whatever the locale, so a prerendered
|
|
316
|
+
* playground does not depend on the machine that built it.
|
|
317
|
+
*/
|
|
318
|
+
const INPUT_ORDER = new Intl.Collator('en');
|
|
319
|
+
/**
|
|
320
|
+
* The playground inspector: the demos, and beside them (below them in a container narrower than
|
|
321
|
+
* 640px) the Recreate setting and a control per input and content slot.
|
|
322
|
+
*/
|
|
211
323
|
class NgDocPlaygroundPropertiesComponent {
|
|
212
324
|
constructor() {
|
|
213
|
-
this.breakpointObserver = inject(BreakpointObserver);
|
|
214
325
|
this.injector = inject(Injector);
|
|
215
|
-
|
|
216
|
-
this.
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
this.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
this.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
326
|
+
/** The form of the playground. */
|
|
327
|
+
this.form = input.required(/* @ts-ignore */
|
|
328
|
+
...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
|
|
329
|
+
/** The inputs of the playground's target. */
|
|
330
|
+
this.properties = input(undefined, /* @ts-ignore */
|
|
331
|
+
...(ngDevMode ? [{ debugName: "properties" }] : /* istanbul ignore next */ []));
|
|
332
|
+
/** Inputs that get no control. */
|
|
333
|
+
this.ignoreInputs = input([], /* @ts-ignore */
|
|
334
|
+
...(ngDevMode ? [{ debugName: "ignoreInputs" }] : /* istanbul ignore next */ []));
|
|
335
|
+
/** Content slots of the playground. */
|
|
336
|
+
this.dynamicContent = input(undefined, /* @ts-ignore */
|
|
337
|
+
...(ngDevMode ? [{ debugName: "dynamicContent" }] : /* istanbul ignore next */ []));
|
|
338
|
+
/** Default values of the inputs; the inspector renders once they are known. */
|
|
339
|
+
this.defaultValues = input(undefined, /* @ts-ignore */
|
|
340
|
+
...(ngDevMode ? [{ debugName: "defaultValues" }] : /* istanbul ignore next */ []));
|
|
341
|
+
/** Whether the inspector is hidden, leaving the demos only. */
|
|
342
|
+
this.hideSidePanel = input(false, /* @ts-ignore */
|
|
343
|
+
...(ngDevMode ? [{ debugName: "hideSidePanel" }] : /* istanbul ignore next */ []));
|
|
344
|
+
/** Where the inspector goes: right of the demos, or below them at full width. */
|
|
345
|
+
this.inspectorPosition = input('right', /* @ts-ignore */
|
|
346
|
+
...(ngDevMode ? [{ debugName: "inspectorPosition" }] : /* istanbul ignore next */ []));
|
|
347
|
+
/** Whether the demo is recreated each time an input changes. */
|
|
348
|
+
this.recreateDemo = model(false, /* @ts-ignore */
|
|
349
|
+
...(ngDevMode ? [{ debugName: "recreateDemo" }] : /* istanbul ignore next */ []));
|
|
350
|
+
/** Whether the Recreate setting is fixed by the playground's options and hidden. */
|
|
351
|
+
this.recreateLocked = input(false, /* @ts-ignore */
|
|
352
|
+
...(ngDevMode ? [{ debugName: "recreateLocked" }] : /* istanbul ignore next */ []));
|
|
353
|
+
/** Whether the Reset button is shown. */
|
|
354
|
+
this.showResetButton = input(false, /* @ts-ignore */
|
|
355
|
+
...(ngDevMode ? [{ debugName: "showResetButton" }] : /* istanbul ignore next */ []));
|
|
356
|
+
/** Emits when the reader resets the form. */
|
|
357
|
+
this.resetForm = output();
|
|
358
|
+
/** The control of each input, in display order. */
|
|
359
|
+
this.propertyControls = computed(() => {
|
|
360
|
+
const properties = this.properties();
|
|
361
|
+
const ignoreInputs = this.ignoreInputs();
|
|
362
|
+
if (!properties) {
|
|
363
|
+
return [];
|
|
364
|
+
}
|
|
365
|
+
return objectKeys(properties)
|
|
366
|
+
.filter((key) => ignoreInputs?.includes(String(key)) !== true)
|
|
232
367
|
.map((key) => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (typeControl) {
|
|
237
|
-
return {
|
|
238
|
-
propertyName: String(key),
|
|
239
|
-
property,
|
|
240
|
-
typeControl,
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return null;
|
|
368
|
+
const property = properties[key];
|
|
369
|
+
const typeControl = this.getTypeControl(property);
|
|
370
|
+
return typeControl ? { propertyName: String(key), property, typeControl } : null;
|
|
245
371
|
})
|
|
246
372
|
.filter(isPresent)
|
|
247
|
-
.sort((a, b) =>
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
373
|
+
.sort((a, b) => compareOrder(a.property.order, b.property.order) ?? compareByTypeControl(a, b));
|
|
374
|
+
}, /* @ts-ignore */
|
|
375
|
+
...(ngDevMode ? [{ debugName: "propertyControls" }] : /* istanbul ignore next */ []));
|
|
376
|
+
/**
|
|
377
|
+
* The controls in sections: the inputs without a group first, then a section per group, in the
|
|
378
|
+
* order of the group's first input.
|
|
379
|
+
*/
|
|
380
|
+
this.propertySections = computed(() => {
|
|
381
|
+
const sections = new Map([
|
|
382
|
+
[undefined, []],
|
|
383
|
+
]);
|
|
384
|
+
for (const control of this.propertyControls()) {
|
|
385
|
+
const group = control.property.group || undefined;
|
|
386
|
+
sections.set(group, [...(sections.get(group) ?? []), control]);
|
|
387
|
+
}
|
|
388
|
+
return Array.from(sections, ([group, controls]) => ({
|
|
389
|
+
title: group ?? 'Settings',
|
|
390
|
+
controls,
|
|
391
|
+
})).filter((section) => section.controls.length > 0);
|
|
392
|
+
}, /* @ts-ignore */
|
|
393
|
+
...(ngDevMode ? [{ debugName: "propertySections" }] : /* istanbul ignore next */ []));
|
|
394
|
+
/** The control of content slots. */
|
|
395
|
+
this.contentTypeControl = this.getControlForType('boolean');
|
|
262
396
|
}
|
|
397
|
+
/**
|
|
398
|
+
* The form control of an input or a content slot.
|
|
399
|
+
* @param controlType - `properties` or `content`.
|
|
400
|
+
* @param key - Name of the input or slot.
|
|
401
|
+
*/
|
|
263
402
|
getFormControl(controlType, key) {
|
|
264
|
-
return this.form.get(controlType)?.get(key);
|
|
403
|
+
return this.form().get(controlType)?.get(key);
|
|
265
404
|
}
|
|
266
405
|
getTypeControl(property) {
|
|
267
406
|
const type = property.type;
|
|
407
|
+
const primitive = optionalPrimitive(type);
|
|
268
408
|
const typeControl = this.getControlForType(type) ??
|
|
409
|
+
(primitive ? this.getControlForType(primitive) : undefined) ??
|
|
269
410
|
this.getControlForTypeAlias(isPlaygroundProperty(property) ? property.options : undefined, property.isManual);
|
|
270
411
|
if (!typeControl && isDevMode()) {
|
|
271
412
|
console.warn(`NgDocPlayground didn't find the control for the @Input "${property.inputName}", the type "${type}" was not recognized'`);
|
|
@@ -279,14 +420,12 @@ class NgDocPlaygroundPropertiesComponent {
|
|
|
279
420
|
getControlForTypeAlias(options, isManual) {
|
|
280
421
|
if (options && options.length) {
|
|
281
422
|
let optionsIsValid = true;
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
optionsIsValid = false;
|
|
289
|
-
}
|
|
423
|
+
try {
|
|
424
|
+
// checking that all values are extractable
|
|
425
|
+
options.forEach((item) => resolvePlaygroundOption(item, isManual));
|
|
426
|
+
}
|
|
427
|
+
catch {
|
|
428
|
+
optionsIsValid = false;
|
|
290
429
|
}
|
|
291
430
|
if (optionsIsValid) {
|
|
292
431
|
const token = getTokenForType('NgDocTypeAlias');
|
|
@@ -295,211 +434,263 @@ class NgDocPlaygroundPropertiesComponent {
|
|
|
295
434
|
}
|
|
296
435
|
return undefined;
|
|
297
436
|
}
|
|
298
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
299
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
437
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocPlaygroundPropertiesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
438
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.1", type: NgDocPlaygroundPropertiesComponent, isStandalone: true, selector: "ng-doc-playground-properties", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, properties: { classPropertyName: "properties", publicName: "properties", isSignal: true, isRequired: false, transformFunction: null }, ignoreInputs: { classPropertyName: "ignoreInputs", publicName: "ignoreInputs", isSignal: true, isRequired: false, transformFunction: null }, dynamicContent: { classPropertyName: "dynamicContent", publicName: "dynamicContent", isSignal: true, isRequired: false, transformFunction: null }, defaultValues: { classPropertyName: "defaultValues", publicName: "defaultValues", isSignal: true, isRequired: false, transformFunction: null }, hideSidePanel: { classPropertyName: "hideSidePanel", publicName: "hideSidePanel", isSignal: true, isRequired: false, transformFunction: null }, inspectorPosition: { classPropertyName: "inspectorPosition", publicName: "inspectorPosition", isSignal: true, isRequired: false, transformFunction: null }, recreateDemo: { classPropertyName: "recreateDemo", publicName: "recreateDemo", isSignal: true, isRequired: false, transformFunction: null }, recreateLocked: { classPropertyName: "recreateLocked", publicName: "recreateLocked", isSignal: true, isRequired: false, transformFunction: null }, showResetButton: { classPropertyName: "showResetButton", publicName: "showResetButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { recreateDemo: "recreateDemoChange", resetForm: "resetForm" }, ngImport: i0, template: "@if (defaultValues(); as defaultValues) {\n <div\n class=\"ng-doc-playground-properties-wrapper\"\n [class.no-side-panel]=\"hideSidePanel()\"\n [class.inspector-bottom]=\"inspectorPosition() === 'bottom'\">\n <div class=\"ng-doc-playground-demos\">\n <ng-content></ng-content>\n </div>\n @if (!hideSidePanel()) {\n <div class=\"ng-doc-playground-properties\">\n <div class=\"ng-doc-playground-header\">\n <h4>Playground</h4>\n @if (showResetButton()) {\n <button type=\"button\" class=\"ng-doc-playground-reset\" (click)=\"resetForm.emit()\">\n Reset\n </button>\n }\n </div>\n @if (!recreateLocked()) {\n <div class=\"ng-doc-playground-setting\">\n <ng-doc-checkbox [ngModel]=\"recreateDemo()\" (ngModelChange)=\"recreateDemo.set($event)\">\n Recreate\n </ng-doc-checkbox>\n <ng-doc-icon\n class=\"ng-doc-playground-info\"\n icon=\"info\"\n role=\"img\"\n aria-label=\"Recreates the demo every time one of the inputs changes\"\n [ngDocTooltip]=\"'Recreates the demo every time one of the inputs changes'\"\n [positions]=\"['bottom-right', 'left-center']\"></ng-doc-icon>\n </div>\n }\n <div class=\"ng-doc-playground-divider\"></div>\n @for (section of propertySections(); track $index) {\n <h5 class=\"ng-doc-title\">{{ section.title }}</h5>\n <div class=\"ng-doc-playground-property-list\">\n @for (propertyControl of section.controls; track propertyControl.propertyName) {\n <ng-doc-playground-property\n [name]=\"propertyControl.property.label ?? propertyControl.property.inputName\"\n [property]=\"propertyControl.property\"\n [typeControl]=\"propertyControl.typeControl\"\n [defaultValue]=\"defaultValues[propertyControl.propertyName]\"\n [control]=\"\n getFormControl | bind: this | execute: 'properties' : propertyControl.propertyName\n \">\n </ng-doc-playground-property>\n }\n </div>\n }\n @if ((dynamicContent() | keyvalue)?.length) {\n <h5 class=\"ng-doc-title\">Content</h5>\n <div class=\"ng-doc-playground-property-list\">\n @for (content of dynamicContent() | keyvalue; track content.key) {\n <ng-doc-playground-property\n [name]=\"content.value.label\"\n [property]=\"content.value\"\n [typeControl]=\"contentTypeControl\"\n [control]=\"getFormControl | bind: this | execute: 'content' : content.key\">\n </ng-doc-playground-property>\n }\n </div>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{display:block;container:ng-doc-playground/inline-size}.ng-doc-playground-properties-wrapper{display:grid;grid-template-columns:minmax(0,1fr) var(--ng-doc-playground-inspector-width);align-items:stretch;border:var(--ng-doc-demo-displayer-border);border-radius:var(--ng-doc-demo-displayer-border-radius);overflow:clip;background-color:var(--ng-doc-demo-displayer-background, var(--ng-doc-background))}.ng-doc-playground-properties-wrapper.no-side-panel{grid-template-columns:minmax(0,1fr)}.ng-doc-playground-properties-wrapper:not(.no-side-panel):not(.inspector-bottom) .ng-doc-playground-demos{position:sticky;top:calc(var(--ng-doc-page-sticky-offset) + var(--ng-doc-base-gutter));align-self:start;z-index:4}.ng-doc-playground-demos{display:flex;flex-direction:column;min-width:0}.ng-doc-playground-properties-wrapper:not(.no-side-panel):not(.inspector-bottom) .ng-doc-playground-demos{min-height:min(100%,100dvh - var(--ng-doc-page-sticky-offset) - 2 * var(--ng-doc-base-gutter))}.ng-doc-playground-properties{min-width:0;background:var(--ng-doc-base-1);border-left:1px solid var(--ng-doc-border-color);font-family:var(--ng-doc-font-family);font-size:14px;line-height:20px;color:var(--ng-doc-text);--ng-doc-input-height: 36px;--ng-doc-input-border: var(--ng-doc-playground-input-border);--ng-doc-checkbox-border: var(--ng-doc-playground-input-border)}.ng-doc-playground-header{display:flex;align-items:center;gap:var(--ng-doc-space-2);height:52px;padding:0 var(--ng-doc-space-3) 0 var(--ng-doc-space-4)}.ng-doc-playground-header h4{margin:0;font-family:var(--ng-doc-heading-font-family);font-size:15px;line-height:22px;font-weight:600;letter-spacing:0;color:var(--ng-doc-heading-color)}.ng-doc-playground-reset{display:inline-flex;align-items:center;height:28px;margin-left:auto;padding:0 10px;border:1px solid var(--ng-doc-border-color);border-radius:var(--ng-doc-radius-md);background:var(--ng-doc-background);font:inherit;font-size:12px;font-weight:500;color:var(--ng-doc-heading-color);cursor:pointer}.ng-doc-playground-reset:hover{border-color:var(--ng-doc-border-hover-color)}.ng-doc-playground-reset:focus-visible{outline:none;box-shadow:var(--ng-doc-focus-ring)}.ng-doc-playground-setting{display:flex;align-items:center;gap:6px;padding:0 var(--ng-doc-space-4) var(--ng-doc-space-3)}.ng-doc-playground-info{--ng-doc-icon-color: var(--ng-doc-text-muted)}.ng-doc-playground-divider{height:1px;background:var(--ng-doc-border-color)}h5.ng-doc-title{margin:0;padding:var(--ng-doc-space-3) var(--ng-doc-space-4) var(--ng-doc-space-1);font-family:var(--ng-doc-font-family);font-size:11px;line-height:16px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--ng-doc-text-muted)}ng-doc-playground-property{padding:var(--ng-doc-space-2) var(--ng-doc-space-4)}ng-doc-playground-property+ng-doc-playground-property{border-top:1px solid var(--ng-doc-base-2)}.ng-doc-playground-property-list:last-child{padding-bottom:var(--ng-doc-space-2)}.ng-doc-playground-properties-wrapper.inspector-bottom{grid-template-columns:minmax(0,1fr)}.ng-doc-playground-properties-wrapper.inspector-bottom .ng-doc-playground-properties{border-left:0;border-top:1px solid var(--ng-doc-border-color)}.ng-doc-playground-properties-wrapper.inspector-bottom .ng-doc-playground-property-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,320px),1fr));column-gap:var(--ng-doc-space-4)}.ng-doc-playground-properties-wrapper.inspector-bottom ng-doc-playground-property+ng-doc-playground-property{border-top:0}@container ng-doc-playground (max-width: 640px){.ng-doc-playground-properties-wrapper{grid-template-columns:minmax(0,1fr)}.ng-doc-playground-properties-wrapper:not(.no-side-panel) .ng-doc-playground-demos{position:static}.ng-doc-playground-properties{border-left:0;border-top:1px solid var(--ng-doc-border-color)}}\n"], dependencies: [{ kind: "component", type: NgDocCheckboxComponent, selector: "ng-doc-checkbox", inputs: ["color"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgDocTooltipDirective, selector: "[ngDocTooltip]", inputs: ["ngDocTooltip", "delay", "displayOrigin", "pointerOrigin", "positions", "canOpen", "panelClass", "minHeight", "maxHeight", "height", "minWidth", "maxWidth", "width"], outputs: ["beforeOpen", "afterOpen", "beforeClose", "afterClose"], exportAs: ["ngDocTooltip"] }, { kind: "component", type: NgDocIconComponent, selector: "ng-doc-icon", inputs: ["icon", "customIcon", "size"] }, { kind: "component", type: NgDocPlaygroundPropertyComponent, selector: "ng-doc-playground-property", inputs: ["name", "property", "typeControl", "control", "defaultValue"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: NgDocBindPipe, name: "bind" }, { kind: "pipe", type: NgDocExecutePipe, name: "execute" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
300
439
|
}
|
|
301
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
440
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocPlaygroundPropertiesComponent, decorators: [{
|
|
302
441
|
type: Component,
|
|
303
442
|
args: [{ selector: 'ng-doc-playground-properties', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
304
|
-
NgDocTextComponent,
|
|
305
|
-
NgDocButtonComponent,
|
|
306
443
|
NgDocCheckboxComponent,
|
|
307
444
|
FormsModule,
|
|
308
445
|
NgDocTooltipDirective,
|
|
309
446
|
NgDocIconComponent,
|
|
310
|
-
NgDocTextRightDirective,
|
|
311
447
|
NgDocPlaygroundPropertyComponent,
|
|
312
|
-
AsyncPipe,
|
|
313
448
|
KeyValuePipe,
|
|
314
449
|
NgDocBindPipe,
|
|
315
450
|
NgDocExecutePipe,
|
|
316
|
-
], template: "@if (defaultValues) {\n <div
|
|
317
|
-
}],
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
451
|
+
], template: "@if (defaultValues(); as defaultValues) {\n <div\n class=\"ng-doc-playground-properties-wrapper\"\n [class.no-side-panel]=\"hideSidePanel()\"\n [class.inspector-bottom]=\"inspectorPosition() === 'bottom'\">\n <div class=\"ng-doc-playground-demos\">\n <ng-content></ng-content>\n </div>\n @if (!hideSidePanel()) {\n <div class=\"ng-doc-playground-properties\">\n <div class=\"ng-doc-playground-header\">\n <h4>Playground</h4>\n @if (showResetButton()) {\n <button type=\"button\" class=\"ng-doc-playground-reset\" (click)=\"resetForm.emit()\">\n Reset\n </button>\n }\n </div>\n @if (!recreateLocked()) {\n <div class=\"ng-doc-playground-setting\">\n <ng-doc-checkbox [ngModel]=\"recreateDemo()\" (ngModelChange)=\"recreateDemo.set($event)\">\n Recreate\n </ng-doc-checkbox>\n <ng-doc-icon\n class=\"ng-doc-playground-info\"\n icon=\"info\"\n role=\"img\"\n aria-label=\"Recreates the demo every time one of the inputs changes\"\n [ngDocTooltip]=\"'Recreates the demo every time one of the inputs changes'\"\n [positions]=\"['bottom-right', 'left-center']\"></ng-doc-icon>\n </div>\n }\n <div class=\"ng-doc-playground-divider\"></div>\n @for (section of propertySections(); track $index) {\n <h5 class=\"ng-doc-title\">{{ section.title }}</h5>\n <div class=\"ng-doc-playground-property-list\">\n @for (propertyControl of section.controls; track propertyControl.propertyName) {\n <ng-doc-playground-property\n [name]=\"propertyControl.property.label ?? propertyControl.property.inputName\"\n [property]=\"propertyControl.property\"\n [typeControl]=\"propertyControl.typeControl\"\n [defaultValue]=\"defaultValues[propertyControl.propertyName]\"\n [control]=\"\n getFormControl | bind: this | execute: 'properties' : propertyControl.propertyName\n \">\n </ng-doc-playground-property>\n }\n </div>\n }\n @if ((dynamicContent() | keyvalue)?.length) {\n <h5 class=\"ng-doc-title\">Content</h5>\n <div class=\"ng-doc-playground-property-list\">\n @for (content of dynamicContent() | keyvalue; track content.key) {\n <ng-doc-playground-property\n [name]=\"content.value.label\"\n [property]=\"content.value\"\n [typeControl]=\"contentTypeControl\"\n [control]=\"getFormControl | bind: this | execute: 'content' : content.key\">\n </ng-doc-playground-property>\n }\n </div>\n }\n </div>\n }\n </div>\n}\n", styles: [":host{display:block;container:ng-doc-playground/inline-size}.ng-doc-playground-properties-wrapper{display:grid;grid-template-columns:minmax(0,1fr) var(--ng-doc-playground-inspector-width);align-items:stretch;border:var(--ng-doc-demo-displayer-border);border-radius:var(--ng-doc-demo-displayer-border-radius);overflow:clip;background-color:var(--ng-doc-demo-displayer-background, var(--ng-doc-background))}.ng-doc-playground-properties-wrapper.no-side-panel{grid-template-columns:minmax(0,1fr)}.ng-doc-playground-properties-wrapper:not(.no-side-panel):not(.inspector-bottom) .ng-doc-playground-demos{position:sticky;top:calc(var(--ng-doc-page-sticky-offset) + var(--ng-doc-base-gutter));align-self:start;z-index:4}.ng-doc-playground-demos{display:flex;flex-direction:column;min-width:0}.ng-doc-playground-properties-wrapper:not(.no-side-panel):not(.inspector-bottom) .ng-doc-playground-demos{min-height:min(100%,100dvh - var(--ng-doc-page-sticky-offset) - 2 * var(--ng-doc-base-gutter))}.ng-doc-playground-properties{min-width:0;background:var(--ng-doc-base-1);border-left:1px solid var(--ng-doc-border-color);font-family:var(--ng-doc-font-family);font-size:14px;line-height:20px;color:var(--ng-doc-text);--ng-doc-input-height: 36px;--ng-doc-input-border: var(--ng-doc-playground-input-border);--ng-doc-checkbox-border: var(--ng-doc-playground-input-border)}.ng-doc-playground-header{display:flex;align-items:center;gap:var(--ng-doc-space-2);height:52px;padding:0 var(--ng-doc-space-3) 0 var(--ng-doc-space-4)}.ng-doc-playground-header h4{margin:0;font-family:var(--ng-doc-heading-font-family);font-size:15px;line-height:22px;font-weight:600;letter-spacing:0;color:var(--ng-doc-heading-color)}.ng-doc-playground-reset{display:inline-flex;align-items:center;height:28px;margin-left:auto;padding:0 10px;border:1px solid var(--ng-doc-border-color);border-radius:var(--ng-doc-radius-md);background:var(--ng-doc-background);font:inherit;font-size:12px;font-weight:500;color:var(--ng-doc-heading-color);cursor:pointer}.ng-doc-playground-reset:hover{border-color:var(--ng-doc-border-hover-color)}.ng-doc-playground-reset:focus-visible{outline:none;box-shadow:var(--ng-doc-focus-ring)}.ng-doc-playground-setting{display:flex;align-items:center;gap:6px;padding:0 var(--ng-doc-space-4) var(--ng-doc-space-3)}.ng-doc-playground-info{--ng-doc-icon-color: var(--ng-doc-text-muted)}.ng-doc-playground-divider{height:1px;background:var(--ng-doc-border-color)}h5.ng-doc-title{margin:0;padding:var(--ng-doc-space-3) var(--ng-doc-space-4) var(--ng-doc-space-1);font-family:var(--ng-doc-font-family);font-size:11px;line-height:16px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--ng-doc-text-muted)}ng-doc-playground-property{padding:var(--ng-doc-space-2) var(--ng-doc-space-4)}ng-doc-playground-property+ng-doc-playground-property{border-top:1px solid var(--ng-doc-base-2)}.ng-doc-playground-property-list:last-child{padding-bottom:var(--ng-doc-space-2)}.ng-doc-playground-properties-wrapper.inspector-bottom{grid-template-columns:minmax(0,1fr)}.ng-doc-playground-properties-wrapper.inspector-bottom .ng-doc-playground-properties{border-left:0;border-top:1px solid var(--ng-doc-border-color)}.ng-doc-playground-properties-wrapper.inspector-bottom .ng-doc-playground-property-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,320px),1fr));column-gap:var(--ng-doc-space-4)}.ng-doc-playground-properties-wrapper.inspector-bottom ng-doc-playground-property+ng-doc-playground-property{border-top:0}@container ng-doc-playground (max-width: 640px){.ng-doc-playground-properties-wrapper{grid-template-columns:minmax(0,1fr)}.ng-doc-playground-properties-wrapper:not(.no-side-panel) .ng-doc-playground-demos{position:static}.ng-doc-playground-properties{border-left:0;border-top:1px solid var(--ng-doc-border-color)}}\n"] }]
|
|
452
|
+
}], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: true }] }], properties: [{ type: i0.Input, args: [{ isSignal: true, alias: "properties", required: false }] }], ignoreInputs: [{ type: i0.Input, args: [{ isSignal: true, alias: "ignoreInputs", required: false }] }], dynamicContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "dynamicContent", required: false }] }], defaultValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValues", required: false }] }], hideSidePanel: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideSidePanel", required: false }] }], inspectorPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "inspectorPosition", required: false }] }], recreateDemo: [{ type: i0.Input, args: [{ isSignal: true, alias: "recreateDemo", required: false }] }, { type: i0.Output, args: ["recreateDemoChange"] }], recreateLocked: [{ type: i0.Input, args: [{ isSignal: true, alias: "recreateLocked", required: false }] }], showResetButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showResetButton", required: false }] }], resetForm: [{ type: i0.Output, args: ["resetForm"] }] } });
|
|
453
|
+
/**
|
|
454
|
+
* Compares the `order` of two inputs from the playground's `controls`: inputs with one come first,
|
|
455
|
+
* lowest first.
|
|
456
|
+
* @param a - The first input's order.
|
|
457
|
+
* @param b - The second input's order.
|
|
458
|
+
* @returns The comparison, or `undefined` when neither input has an order or both have the same.
|
|
459
|
+
*/
|
|
460
|
+
function compareOrder(a, b) {
|
|
461
|
+
if (isPresent(a) && isPresent(b)) {
|
|
462
|
+
return a - b || undefined;
|
|
463
|
+
}
|
|
464
|
+
if (isPresent(a)) {
|
|
465
|
+
return -1;
|
|
466
|
+
}
|
|
467
|
+
if (isPresent(b)) {
|
|
468
|
+
return 1;
|
|
469
|
+
}
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Compares two inputs by the order of their type controls: controls with an order first, lowest
|
|
474
|
+
* first (equal orders keep the inputs' order), then the others by name.
|
|
475
|
+
* @param a - The first input.
|
|
476
|
+
* @param b - The second input.
|
|
477
|
+
*/
|
|
478
|
+
function compareByTypeControl(a, b) {
|
|
479
|
+
const aOrder = a.typeControl.options?.order;
|
|
480
|
+
const bOrder = b.typeControl.options?.order;
|
|
481
|
+
if (isPresent(aOrder) && isPresent(bOrder)) {
|
|
482
|
+
return aOrder - bOrder;
|
|
483
|
+
}
|
|
484
|
+
if (isPresent(aOrder)) {
|
|
485
|
+
return -1;
|
|
486
|
+
}
|
|
487
|
+
if (isPresent(bOrder)) {
|
|
488
|
+
return 1;
|
|
489
|
+
}
|
|
490
|
+
return INPUT_ORDER.compare(a.property.inputName, b.property.inputName);
|
|
491
|
+
}
|
|
492
|
+
/** The types whose control also edits an optional or nullable input of the type. */
|
|
493
|
+
const PRIMITIVE_TYPES = new Set(['string', 'number', 'boolean']);
|
|
494
|
+
/**
|
|
495
|
+
* The primitive of an optional or nullable primitive input type, such as `string` of
|
|
496
|
+
* `string | undefined` (an optional `@Input() label?: string`, `input<string>()` or
|
|
497
|
+
* `model<string>()`) or of `number | null`, so that the input gets the primitive's control.
|
|
498
|
+
* Other types are matched by their exact name only: a custom control registered for `Position`
|
|
499
|
+
* does not receive the `undefined` of a `Position | undefined` input unless it is registered for
|
|
500
|
+
* that type too.
|
|
501
|
+
* @param type - The input type as the builder printed it.
|
|
502
|
+
* @returns The primitive, or `undefined` when the type is not one.
|
|
503
|
+
*/
|
|
504
|
+
function optionalPrimitive(type) {
|
|
505
|
+
const members = type.split('|').map((member) => member.trim());
|
|
506
|
+
const rest = members.filter((member) => member !== 'undefined' && member !== 'null');
|
|
507
|
+
return rest.length === 1 && rest.length < members.length && PRIMITIVE_TYPES.has(rest[0])
|
|
508
|
+
? rest[0]
|
|
509
|
+
: undefined;
|
|
510
|
+
}
|
|
338
511
|
|
|
512
|
+
/**
|
|
513
|
+
* A playground: an inspector with a control per input and content slot of its target, and a demo
|
|
514
|
+
* per selector (or the pipe) rendered with the chosen values.
|
|
515
|
+
*/
|
|
339
516
|
class NgDocPlaygroundComponent {
|
|
340
517
|
constructor() {
|
|
341
518
|
this.rootPage = inject(NgDocRootPage);
|
|
342
519
|
this.formBuilder = inject(FormBuilder);
|
|
343
|
-
|
|
344
|
-
this.
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
this.
|
|
520
|
+
/** The name of the playground in the page configuration. */
|
|
521
|
+
this.id = input.required(/* @ts-ignore */
|
|
522
|
+
...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
523
|
+
/** The name of the pipe, when the target is a pipe. */
|
|
524
|
+
this.pipeName = input('', /* @ts-ignore */
|
|
525
|
+
...(ngDevMode ? [{ debugName: "pipeName" }] : /* istanbul ignore next */ []));
|
|
526
|
+
/** The selectors of the target to render a demo for. */
|
|
527
|
+
this.selectors = input([], /* @ts-ignore */
|
|
528
|
+
...(ngDevMode ? [{ debugName: "selectors" }] : /* istanbul ignore next */ []));
|
|
529
|
+
/** The inputs of the target. */
|
|
530
|
+
this.properties = input(undefined, /* @ts-ignore */
|
|
531
|
+
...(ngDevMode ? [{ debugName: "properties" }] : /* istanbul ignore next */ []));
|
|
532
|
+
/** Options of the playground action; they extend the playground configuration. */
|
|
533
|
+
this.options = input({}, /* @ts-ignore */
|
|
534
|
+
...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
|
|
535
|
+
/** The values of the inputs and content slots. */
|
|
536
|
+
this.formGroup = signal(undefined, /* @ts-ignore */
|
|
537
|
+
...(ngDevMode ? [{ debugName: "formGroup" }] : /* istanbul ignore next */ []));
|
|
538
|
+
/** The default values of the target's inputs, reported by the first demo. */
|
|
539
|
+
this.defaultValues = signal(undefined, /* @ts-ignore */
|
|
540
|
+
...(ngDevMode ? [{ debugName: "defaultValues" }] : /* istanbul ignore next */ []));
|
|
541
|
+
/** The playground configuration of the page, extended by the options. */
|
|
542
|
+
this.configuration = computed(() => Object.assign({}, this.rootPage.page?.playgrounds?.[this.id()], this.options()), /* @ts-ignore */
|
|
543
|
+
...(ngDevMode ? [{ debugName: "configuration" }] : /* istanbul ignore next */ []));
|
|
544
|
+
/**
|
|
545
|
+
* Whether the demo is created again each time a value changes. It starts from the `recreate`
|
|
546
|
+
* option; the reader can change it unless the option is `'always'`.
|
|
547
|
+
*/
|
|
548
|
+
this.recreateDemo = linkedSignal(() => !!this.configuration().recreate, /* @ts-ignore */
|
|
549
|
+
...(ngDevMode ? [{ debugName: "recreateDemo" }] : /* istanbul ignore next */ []));
|
|
550
|
+
/** Whether the Recreate setting is fixed on, and hidden, by the `'always'` option. */
|
|
551
|
+
this.recreateLocked = computed(() => this.configuration().recreate === 'always', /* @ts-ignore */
|
|
552
|
+
...(ngDevMode ? [{ debugName: "recreateLocked" }] : /* istanbul ignore next */ []));
|
|
348
553
|
this.defaultProperties = {};
|
|
349
554
|
this.defaultContent = {};
|
|
350
555
|
}
|
|
351
|
-
ngOnChanges({ options }) {
|
|
352
|
-
if (options) {
|
|
353
|
-
// Join configuration with options
|
|
354
|
-
this.configuration = Object.assign({}, this.rootPage.page?.playgrounds?.[this.id], this.options);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
556
|
ngAfterViewInit() {
|
|
358
557
|
this.defaultProperties = this.getPropertiesFormValues();
|
|
359
558
|
this.defaultContent = this.getContentFormValues();
|
|
360
|
-
|
|
559
|
+
// `FormBuilder` reads an array as `[value, validators]`, so each value is wrapped: the default
|
|
560
|
+
// of an array input is the value of its control.
|
|
561
|
+
const propertiesForm = this.formBuilder.group(Object.fromEntries(Object.entries(this.defaultProperties).map(([key, value]) => [key, [value]])));
|
|
361
562
|
const contentForm = this.formBuilder.group(this.defaultContent);
|
|
362
|
-
|
|
563
|
+
const formGroup = this.formBuilder.group({
|
|
363
564
|
properties: propertiesForm,
|
|
364
565
|
content: contentForm,
|
|
365
566
|
});
|
|
366
567
|
// `patchValue` is needed to set `undefined` values, otherwise they will be ignored by the Angular form
|
|
367
|
-
|
|
368
|
-
properties: Object.assign({}, this.defaultProperties, this.configuration.inputs),
|
|
568
|
+
formGroup.patchValue({
|
|
569
|
+
properties: Object.assign({}, this.defaultProperties, this.configuration().inputs),
|
|
369
570
|
content: this.defaultContent,
|
|
370
571
|
});
|
|
572
|
+
this.formGroup.set(formGroup);
|
|
371
573
|
}
|
|
372
574
|
isDefaultState() {
|
|
373
|
-
|
|
575
|
+
const formGroup = this.formGroup();
|
|
576
|
+
if (!formGroup) {
|
|
374
577
|
return false;
|
|
375
578
|
}
|
|
376
|
-
return (isSameObject(
|
|
377
|
-
isSameObject(
|
|
579
|
+
return (isSameObject(formGroup.value.properties ?? {}, this.defaultValues() ?? {}) &&
|
|
580
|
+
isSameObject(formGroup.value.content ?? {}, this.defaultContent ?? {}));
|
|
378
581
|
}
|
|
379
582
|
getPropertiesFormValues() {
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
583
|
+
const defaultValues = this.defaultValues();
|
|
584
|
+
const formValues = objectKeys(this.properties() ?? {}).reduce((controls, key) => {
|
|
585
|
+
controls[key] = defaultValues ? defaultValues[key] : undefined;
|
|
384
586
|
return controls;
|
|
385
587
|
}, {});
|
|
386
|
-
return Object.assign({}, formValues, this.configuration.defaults);
|
|
588
|
+
return Object.assign({}, formValues, this.configuration().defaults);
|
|
387
589
|
}
|
|
388
590
|
getContentFormValues() {
|
|
389
|
-
return objectKeys(this.configuration
|
|
390
|
-
|
|
391
|
-
controls[key] = false;
|
|
392
|
-
}
|
|
591
|
+
return objectKeys(this.configuration().content ?? {}).reduce((controls, key) => {
|
|
592
|
+
controls[key] = false;
|
|
393
593
|
return controls;
|
|
394
594
|
}, {});
|
|
395
595
|
}
|
|
596
|
+
/** Sets every input and content slot back to its default value. */
|
|
396
597
|
resetForm() {
|
|
397
|
-
this.formGroup
|
|
398
|
-
|
|
598
|
+
const formGroup = this.formGroup();
|
|
599
|
+
formGroup?.reset({}, { emitEvent: false });
|
|
600
|
+
formGroup?.patchValue({
|
|
399
601
|
properties: this.defaultProperties,
|
|
400
602
|
content: this.defaultContent,
|
|
401
603
|
});
|
|
402
604
|
}
|
|
403
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.
|
|
404
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.
|
|
605
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocPlaygroundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
606
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.2.1", type: NgDocPlaygroundComponent, isStandalone: true, selector: "ng-doc-playground", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, pipeName: { classPropertyName: "pipeName", publicName: "pipeName", isSignal: true, isRequired: false, transformFunction: null }, selectors: { classPropertyName: "selectors", publicName: "selectors", isSignal: true, isRequired: false, transformFunction: null }, properties: { classPropertyName: "properties", publicName: "properties", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (configuration(); as configuration) {\n <ng-doc-playground-properties\n [form]=\"formGroup()!\"\n [properties]=\"properties()\"\n [ignoreInputs]=\"configuration.hiddenInputs\"\n [dynamicContent]=\"configuration.content\"\n [hideSidePanel]=\"configuration.hideSidePanel ?? false\"\n [inspectorPosition]=\"configuration.inspectorPosition ?? 'right'\"\n [defaultValues]=\"defaultValues()\"\n [showResetButton]=\"!isDefaultState()\"\n [(recreateDemo)]=\"recreateDemo\"\n [recreateLocked]=\"recreateLocked()\"\n (resetForm)=\"resetForm()\">\n @for (selector of configuration.selectors ?? selectors() | asArray; track selector) {\n <ng-doc-playground-demo\n [id]=\"id()\"\n [selector]=\"selector\"\n [properties]=\"properties()\"\n [configuration]=\"configuration\"\n [recreateDemo]=\"recreateDemo()\"\n [form]=\"formGroup()\"\n [expanded]=\"configuration.expanded ?? false\">\n </ng-doc-playground-demo>\n }\n @if (pipeName()) {\n <ng-doc-playground-demo\n [id]=\"id()\"\n [pipeName]=\"pipeName()\"\n [properties]=\"properties()\"\n [configuration]=\"configuration\"\n [recreateDemo]=\"recreateDemo()\"\n [form]=\"formGroup()\">\n </ng-doc-playground-demo>\n }\n </ng-doc-playground-properties>\n}\n", styles: [":host{display:block;margin:var(--ng-doc-playground-margin)}ng-doc-playground-demo:last-child{flex:1 1 auto}ng-doc-playground-demo+ng-doc-playground-demo{border-top:1px solid color-mix(in srgb,var(--ng-doc-border-color) 70%,transparent)}\n"], dependencies: [{ kind: "component", type: NgDocPlaygroundPropertiesComponent, selector: "ng-doc-playground-properties", inputs: ["form", "properties", "ignoreInputs", "dynamicContent", "defaultValues", "hideSidePanel", "inspectorPosition", "recreateDemo", "recreateLocked", "showResetButton"], outputs: ["recreateDemoChange", "resetForm"] }, { kind: "component", type: NgDocPlaygroundDemoComponent, selector: "ng-doc-playground-demo", inputs: ["id", "pipeName", "selector", "configuration", "properties", "recreateDemo", "form", "expanded"] }, { kind: "pipe", type: NgDocAsArrayPipe, name: "asArray" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
405
607
|
}
|
|
406
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
608
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocPlaygroundComponent, decorators: [{
|
|
407
609
|
type: Component,
|
|
408
|
-
args: [{ selector: 'ng-doc-playground', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgDocPlaygroundPropertiesComponent, NgDocPlaygroundDemoComponent, NgDocAsArrayPipe], template: "@if (configuration) {\n <ng-doc-playground-properties\n [form]=\"formGroup
|
|
409
|
-
}],
|
|
410
|
-
type: Input,
|
|
411
|
-
args: [{ required: true }]
|
|
412
|
-
}], pipeName: [{
|
|
413
|
-
type: Input
|
|
414
|
-
}], selectors: [{
|
|
415
|
-
type: Input
|
|
416
|
-
}], properties: [{
|
|
417
|
-
type: Input
|
|
418
|
-
}], options: [{
|
|
419
|
-
type: Input
|
|
420
|
-
}] } });
|
|
610
|
+
args: [{ selector: 'ng-doc-playground', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgDocPlaygroundPropertiesComponent, NgDocPlaygroundDemoComponent, NgDocAsArrayPipe], template: "@if (configuration(); as configuration) {\n <ng-doc-playground-properties\n [form]=\"formGroup()!\"\n [properties]=\"properties()\"\n [ignoreInputs]=\"configuration.hiddenInputs\"\n [dynamicContent]=\"configuration.content\"\n [hideSidePanel]=\"configuration.hideSidePanel ?? false\"\n [inspectorPosition]=\"configuration.inspectorPosition ?? 'right'\"\n [defaultValues]=\"defaultValues()\"\n [showResetButton]=\"!isDefaultState()\"\n [(recreateDemo)]=\"recreateDemo\"\n [recreateLocked]=\"recreateLocked()\"\n (resetForm)=\"resetForm()\">\n @for (selector of configuration.selectors ?? selectors() | asArray; track selector) {\n <ng-doc-playground-demo\n [id]=\"id()\"\n [selector]=\"selector\"\n [properties]=\"properties()\"\n [configuration]=\"configuration\"\n [recreateDemo]=\"recreateDemo()\"\n [form]=\"formGroup()\"\n [expanded]=\"configuration.expanded ?? false\">\n </ng-doc-playground-demo>\n }\n @if (pipeName()) {\n <ng-doc-playground-demo\n [id]=\"id()\"\n [pipeName]=\"pipeName()\"\n [properties]=\"properties()\"\n [configuration]=\"configuration\"\n [recreateDemo]=\"recreateDemo()\"\n [form]=\"formGroup()\">\n </ng-doc-playground-demo>\n }\n </ng-doc-playground-properties>\n}\n", styles: [":host{display:block;margin:var(--ng-doc-playground-margin)}ng-doc-playground-demo:last-child{flex:1 1 auto}ng-doc-playground-demo+ng-doc-playground-demo{border-top:1px solid color-mix(in srgb,var(--ng-doc-border-color) 70%,transparent)}\n"] }]
|
|
611
|
+
}], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], pipeName: [{ type: i0.Input, args: [{ isSignal: true, alias: "pipeName", required: false }] }], selectors: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectors", required: false }] }], properties: [{ type: i0.Input, args: [{ isSignal: true, alias: "properties", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }] } });
|
|
421
612
|
|
|
422
613
|
/**
|
|
423
|
-
* Base class
|
|
614
|
+
* Base class of the playground classes the builder generates, one per playground and selector.
|
|
615
|
+
* A generated class renders the playground template with the target's inputs bound to
|
|
616
|
+
* `properties()`, and queries the target with `viewChild()`.
|
|
424
617
|
*/
|
|
425
618
|
class NgDocBasePlayground {
|
|
426
619
|
static { this.selector = 'unknown'; }
|
|
427
|
-
constructor(
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
this.
|
|
431
|
-
|
|
620
|
+
constructor() {
|
|
621
|
+
/** Values of the target's inputs, by property name. */
|
|
622
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
623
|
+
this.properties = input({}, /* @ts-ignore */
|
|
624
|
+
...(ngDevMode ? [{ debugName: "properties" }] : /* istanbul ignore next */ []));
|
|
625
|
+
/** The `data` given to the playground action; it extends the configuration's `data`. */
|
|
626
|
+
this.actionData = input({}, /* @ts-ignore */
|
|
627
|
+
...(ngDevMode ? [{ debugName: "actionData" }] : /* istanbul ignore next */ []));
|
|
628
|
+
/** Whether each content slot is shown, by slot name. */
|
|
629
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
630
|
+
this.content = input({}, /* @ts-ignore */
|
|
631
|
+
...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
|
|
632
|
+
/** The default values of the target's inputs, read before the template binds them. */
|
|
432
633
|
this.defaultValues = {};
|
|
433
634
|
this.reattached = new Subject();
|
|
434
635
|
this.playgroundContainer = inject(NgDocPlaygroundComponent);
|
|
435
636
|
this.changeDetectorRef = inject(ChangeDetectorRef);
|
|
637
|
+
// The view is not checked until the default values of the target are read, so the
|
|
638
|
+
// template's bindings cannot overwrite them first.
|
|
436
639
|
this.changeDetectorRef.detach();
|
|
437
640
|
}
|
|
641
|
+
/** Emits once, after the view is attached again and checks the template's bindings. */
|
|
438
642
|
get onReattached() {
|
|
439
643
|
return this.reattached.pipe(take(1));
|
|
440
644
|
}
|
|
645
|
+
/** The playground `data`: the configuration's data extended by the action's data. */
|
|
646
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
647
|
+
get data() {
|
|
648
|
+
return Object.assign({}, this.configData, this.actionData());
|
|
649
|
+
}
|
|
441
650
|
ngOnInit() {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
? // @ts-expect-error we do not know the type of the playground
|
|
454
|
-
this.playground[key]()
|
|
455
|
-
: // @ts-expect-error we do not know the type of the playground
|
|
456
|
-
this.playground[key];
|
|
457
|
-
}
|
|
458
|
-
catch (e) {
|
|
459
|
-
// we do catch here because some of the playground properties can be getters and throw an error
|
|
460
|
-
}
|
|
651
|
+
// The target is created with the view, but the view has not been checked yet, so its inputs
|
|
652
|
+
// still hold their defaults. Signal inputs are read by calling them.
|
|
653
|
+
const playground = this.playground();
|
|
654
|
+
if (playground) {
|
|
655
|
+
this.defaultValues = Object.keys(playground).reduce((values, key) => {
|
|
656
|
+
try {
|
|
657
|
+
const value = playground[key];
|
|
658
|
+
values[key] = typeof value === 'function' ? value.call(playground) : value;
|
|
659
|
+
}
|
|
660
|
+
catch {
|
|
661
|
+
// Some properties are getters or functions that throw without their context.
|
|
461
662
|
}
|
|
462
663
|
return values;
|
|
463
664
|
}, {});
|
|
464
665
|
}
|
|
465
|
-
else if (this.
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
return
|
|
666
|
+
else if (this.target) {
|
|
667
|
+
// A pipe: the defaults of its `transform` parameters after the value itself.
|
|
668
|
+
const defaults = extractFunctionDefaults(this.target.prototype.transform);
|
|
669
|
+
this.defaultValues = Object.keys(this.playgroundContainer.properties() ?? {}).reduce((values, key, i) => {
|
|
670
|
+
values[key] = defaults[i + 1];
|
|
671
|
+
return values;
|
|
471
672
|
}, {});
|
|
472
673
|
}
|
|
473
674
|
else {
|
|
474
675
|
throw new Error('Playground is not defined or initialized');
|
|
475
676
|
}
|
|
476
|
-
if (!this.playgroundContainer.defaultValues) {
|
|
477
|
-
this.playgroundContainer.defaultValues
|
|
677
|
+
if (!this.playgroundContainer.defaultValues()) {
|
|
678
|
+
this.playgroundContainer.defaultValues.set(this.defaultValues);
|
|
478
679
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
attach the change detector to have correct inputs values.
|
|
482
|
-
*/
|
|
680
|
+
// The demo sets the playground's inputs right after it creates this view; the view is
|
|
681
|
+
// attached again once they are set, so its first check renders the playground's values.
|
|
483
682
|
Promise.resolve().then(() => {
|
|
484
683
|
this.changeDetectorRef.reattach();
|
|
684
|
+
this.changeDetectorRef.markForCheck();
|
|
485
685
|
this.reattached.next();
|
|
486
686
|
});
|
|
487
687
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
491
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: NgDocBasePlayground, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); }
|
|
492
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.6", type: NgDocBasePlayground, isStandalone: true, inputs: { properties: "properties", actionData: "actionData", content: "content" }, ngImport: i0 }); }
|
|
688
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocBasePlayground, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
689
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.2.1", type: NgDocBasePlayground, isStandalone: true, inputs: { properties: { classPropertyName: "properties", publicName: "properties", isSignal: true, isRequired: false, transformFunction: null }, actionData: { classPropertyName: "actionData", publicName: "actionData", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
|
|
493
690
|
}
|
|
494
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.
|
|
691
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocBasePlayground, decorators: [{
|
|
495
692
|
type: Directive
|
|
496
|
-
}], ctorParameters: () => [{ type:
|
|
497
|
-
type: Input
|
|
498
|
-
}], actionData: [{
|
|
499
|
-
type: Input
|
|
500
|
-
}], content: [{
|
|
501
|
-
type: Input
|
|
502
|
-
}] } });
|
|
693
|
+
}], ctorParameters: () => [], propDecorators: { properties: [{ type: i0.Input, args: [{ isSignal: true, alias: "properties", required: false }] }], actionData: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionData", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }] } });
|
|
503
694
|
|
|
504
695
|
/**
|
|
505
696
|
* Generated bundle index. Do not edit.
|