@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.
Files changed (215) hide show
  1. package/README.md +20 -29
  2. package/fesm2022/ng-doc-app-classes-content-anchor-controller.mjs +363 -0
  3. package/fesm2022/ng-doc-app-classes-content-anchor-controller.mjs.map +1 -0
  4. package/fesm2022/ng-doc-app-classes-content-controller.mjs +299 -0
  5. package/fesm2022/ng-doc-app-classes-content-controller.mjs.map +1 -0
  6. package/fesm2022/ng-doc-app-classes-default-search-engine.mjs +51 -35
  7. package/fesm2022/ng-doc-app-classes-default-search-engine.mjs.map +1 -1
  8. package/fesm2022/ng-doc-app-classes-root-page.mjs.map +1 -1
  9. package/fesm2022/ng-doc-app-classes-search-engine.mjs.map +1 -1
  10. package/fesm2022/ng-doc-app-classes.mjs +2 -0
  11. package/fesm2022/ng-doc-app-classes.mjs.map +1 -1
  12. package/fesm2022/ng-doc-app-components-api-list.mjs +173 -69
  13. package/fesm2022/ng-doc-app-components-api-list.mjs.map +1 -1
  14. package/fesm2022/ng-doc-app-components-breadcrumb.mjs +13 -10
  15. package/fesm2022/ng-doc-app-components-breadcrumb.mjs.map +1 -1
  16. package/fesm2022/ng-doc-app-components-code.mjs +152 -25
  17. package/fesm2022/ng-doc-app-components-code.mjs.map +1 -1
  18. package/fesm2022/ng-doc-app-components-command-palette.mjs +498 -0
  19. package/fesm2022/ng-doc-app-components-command-palette.mjs.map +1 -0
  20. package/fesm2022/ng-doc-app-components-copy-button.mjs +38 -21
  21. package/fesm2022/ng-doc-app-components-copy-button.mjs.map +1 -1
  22. package/fesm2022/ng-doc-app-components-demo-displayer.mjs +36 -29
  23. package/fesm2022/ng-doc-app-components-demo-displayer.mjs.map +1 -1
  24. package/fesm2022/ng-doc-app-components-demo-frame.mjs +96 -0
  25. package/fesm2022/ng-doc-app-components-demo-frame.mjs.map +1 -0
  26. package/fesm2022/ng-doc-app-components-demo-pane.mjs +39 -36
  27. package/fesm2022/ng-doc-app-components-demo-pane.mjs.map +1 -1
  28. package/fesm2022/ng-doc-app-components-demo.mjs +175 -44
  29. package/fesm2022/ng-doc-app-components-demo.mjs.map +1 -1
  30. package/fesm2022/ng-doc-app-components-fullscreen-button.mjs +12 -9
  31. package/fesm2022/ng-doc-app-components-fullscreen-button.mjs.map +1 -1
  32. package/fesm2022/ng-doc-app-components-fullscreen-toggle.mjs +79 -0
  33. package/fesm2022/ng-doc-app-components-fullscreen-toggle.mjs.map +1 -0
  34. package/fesm2022/ng-doc-app-components-heading-anchor.mjs +54 -21
  35. package/fesm2022/ng-doc-app-components-heading-anchor.mjs.map +1 -1
  36. package/fesm2022/ng-doc-app-components-image-viewer.mjs +183 -89
  37. package/fesm2022/ng-doc-app-components-image-viewer.mjs.map +1 -1
  38. package/fesm2022/ng-doc-app-components-kind-icon.mjs +42 -25
  39. package/fesm2022/ng-doc-app-components-kind-icon.mjs.map +1 -1
  40. package/fesm2022/ng-doc-app-components-link.mjs +12 -9
  41. package/fesm2022/ng-doc-app-components-link.mjs.map +1 -1
  42. package/fesm2022/ng-doc-app-components-members.mjs +30 -0
  43. package/fesm2022/ng-doc-app-components-members.mjs.map +1 -0
  44. package/fesm2022/ng-doc-app-components-mermaid-viewer.mjs +61 -20
  45. package/fesm2022/ng-doc-app-components-mermaid-viewer.mjs.map +1 -1
  46. package/fesm2022/ng-doc-app-components-navbar.mjs +39 -49
  47. package/fesm2022/ng-doc-app-components-navbar.mjs.map +1 -1
  48. package/fesm2022/ng-doc-app-components-page-header.mjs +73 -10
  49. package/fesm2022/ng-doc-app-components-page-header.mjs.map +1 -1
  50. package/fesm2022/ng-doc-app-components-page-link.mjs +123 -31
  51. package/fesm2022/ng-doc-app-components-page-link.mjs.map +1 -1
  52. package/fesm2022/ng-doc-app-components-page-navigation.mjs +17 -19
  53. package/fesm2022/ng-doc-app-components-page-navigation.mjs.map +1 -1
  54. package/fesm2022/ng-doc-app-components-page-wrapper.mjs +56 -35
  55. package/fesm2022/ng-doc-app-components-page-wrapper.mjs.map +1 -1
  56. package/fesm2022/ng-doc-app-components-page.mjs +168 -24
  57. package/fesm2022/ng-doc-app-components-page.mjs.map +1 -1
  58. package/fesm2022/ng-doc-app-components-playground.mjs +477 -286
  59. package/fesm2022/ng-doc-app-components-playground.mjs.map +1 -1
  60. package/fesm2022/ng-doc-app-components-root.mjs +48 -31
  61. package/fesm2022/ng-doc-app-components-root.mjs.map +1 -1
  62. package/fesm2022/ng-doc-app-components-search-result.mjs +22 -21
  63. package/fesm2022/ng-doc-app-components-search-result.mjs.map +1 -1
  64. package/fesm2022/ng-doc-app-components-search.mjs +64 -33
  65. package/fesm2022/ng-doc-app-components-search.mjs.map +1 -1
  66. package/fesm2022/ng-doc-app-components-sidebar.mjs +86 -61
  67. package/fesm2022/ng-doc-app-components-sidebar.mjs.map +1 -1
  68. package/fesm2022/ng-doc-app-components-tabs.mjs +35 -11
  69. package/fesm2022/ng-doc-app-components-tabs.mjs.map +1 -1
  70. package/fesm2022/ng-doc-app-components-theme-toggle.mjs +33 -21
  71. package/fesm2022/ng-doc-app-components-theme-toggle.mjs.map +1 -1
  72. package/fesm2022/ng-doc-app-components-toc.mjs +267 -90
  73. package/fesm2022/ng-doc-app-components-toc.mjs.map +1 -1
  74. package/fesm2022/ng-doc-app-components.mjs +4 -1
  75. package/fesm2022/ng-doc-app-components.mjs.map +1 -1
  76. package/fesm2022/ng-doc-app-defaults-default-processors.mjs +2 -1
  77. package/fesm2022/ng-doc-app-defaults-default-processors.mjs.map +1 -1
  78. package/fesm2022/ng-doc-app-demo-app.mjs +176 -0
  79. package/fesm2022/ng-doc-app-demo-app.mjs.map +1 -0
  80. package/fesm2022/ng-doc-app-directives-code-highlighter.mjs +11 -5
  81. package/fesm2022/ng-doc-app-directives-code-highlighter.mjs.map +1 -1
  82. package/fesm2022/ng-doc-app-directives-members-filter.mjs +276 -0
  83. package/fesm2022/ng-doc-app-directives-members-filter.mjs.map +1 -0
  84. package/fesm2022/ng-doc-app-directives-route-active.mjs +34 -30
  85. package/fesm2022/ng-doc-app-directives-route-active.mjs.map +1 -1
  86. package/fesm2022/ng-doc-app-directives.mjs +1 -0
  87. package/fesm2022/ng-doc-app-directives.mjs.map +1 -1
  88. package/fesm2022/ng-doc-app-helpers.mjs +307 -2
  89. package/fesm2022/ng-doc-app-helpers.mjs.map +1 -1
  90. package/fesm2022/ng-doc-app-pipes-decode-uri-component.mjs +6 -4
  91. package/fesm2022/ng-doc-app-pipes-decode-uri-component.mjs.map +1 -1
  92. package/fesm2022/ng-doc-app-pipes-extract-value.mjs +6 -4
  93. package/fesm2022/ng-doc-app-pipes-extract-value.mjs.map +1 -1
  94. package/fesm2022/ng-doc-app-pipes-filter-by-text.mjs +7 -4
  95. package/fesm2022/ng-doc-app-pipes-filter-by-text.mjs.map +1 -1
  96. package/fesm2022/ng-doc-app-pipes-sanitize-html.mjs +8 -5
  97. package/fesm2022/ng-doc-app-pipes-sanitize-html.mjs.map +1 -1
  98. package/fesm2022/ng-doc-app-processors-page-processor.mjs +86 -23
  99. package/fesm2022/ng-doc-app-processors-page-processor.mjs.map +1 -1
  100. package/fesm2022/ng-doc-app-processors-processors-tooltip.mjs +26 -25
  101. package/fesm2022/ng-doc-app-processors-processors-tooltip.mjs.map +1 -1
  102. package/fesm2022/ng-doc-app-processors-processors.mjs +42 -10
  103. package/fesm2022/ng-doc-app-processors-processors.mjs.map +1 -1
  104. package/fesm2022/ng-doc-app-providers-ng-doc-app.mjs +31 -2
  105. package/fesm2022/ng-doc-app-providers-ng-doc-app.mjs.map +1 -1
  106. package/fesm2022/ng-doc-app-providers-title.mjs +129 -0
  107. package/fesm2022/ng-doc-app-providers-title.mjs.map +1 -0
  108. package/fesm2022/ng-doc-app-providers.mjs +1 -0
  109. package/fesm2022/ng-doc-app-providers.mjs.map +1 -1
  110. package/fesm2022/ng-doc-app-services-content-scroll-intent.mjs +122 -0
  111. package/fesm2022/ng-doc-app-services-content-scroll-intent.mjs.map +1 -0
  112. package/fesm2022/ng-doc-app-services-content-state.mjs +57 -0
  113. package/fesm2022/ng-doc-app-services-content-state.mjs.map +1 -0
  114. package/fesm2022/ng-doc-app-services-fullscreen-route.mjs +74 -0
  115. package/fesm2022/ng-doc-app-services-fullscreen-route.mjs.map +1 -0
  116. package/fesm2022/ng-doc-app-services-highlighter.mjs +90 -17
  117. package/fesm2022/ng-doc-app-services-highlighter.mjs.map +1 -1
  118. package/fesm2022/ng-doc-app-services-route-preloader.mjs +384 -0
  119. package/fesm2022/ng-doc-app-services-route-preloader.mjs.map +1 -0
  120. package/fesm2022/ng-doc-app-services-shortcuts.mjs +214 -0
  121. package/fesm2022/ng-doc-app-services-shortcuts.mjs.map +1 -0
  122. package/fesm2022/ng-doc-app-services-sidebar.mjs +59 -25
  123. package/fesm2022/ng-doc-app-services-sidebar.mjs.map +1 -1
  124. package/fesm2022/ng-doc-app-services-store.mjs +8 -8
  125. package/fesm2022/ng-doc-app-services-store.mjs.map +1 -1
  126. package/fesm2022/ng-doc-app-services-theme.mjs +32 -12
  127. package/fesm2022/ng-doc-app-services-theme.mjs.map +1 -1
  128. package/fesm2022/ng-doc-app-services.mjs +143 -0
  129. package/fesm2022/ng-doc-app-services.mjs.map +1 -1
  130. package/fesm2022/ng-doc-app-tokens.mjs +7 -28
  131. package/fesm2022/ng-doc-app-tokens.mjs.map +1 -1
  132. package/fesm2022/ng-doc-app-type-controls-boolean-control.mjs +18 -9
  133. package/fesm2022/ng-doc-app-type-controls-boolean-control.mjs.map +1 -1
  134. package/fesm2022/ng-doc-app-type-controls-number-control.mjs +12 -9
  135. package/fesm2022/ng-doc-app-type-controls-number-control.mjs.map +1 -1
  136. package/fesm2022/ng-doc-app-type-controls-string-control.mjs +12 -9
  137. package/fesm2022/ng-doc-app-type-controls-string-control.mjs.map +1 -1
  138. package/fesm2022/ng-doc-app-type-controls-type-alias-control.mjs +59 -18
  139. package/fesm2022/ng-doc-app-type-controls-type-alias-control.mjs.map +1 -1
  140. package/package.json +82 -28
  141. package/styles/global.css +1128 -201
  142. package/styles/main.css +1128 -201
  143. package/styles/themes/dark.css +88 -56
  144. package/types/ng-doc-app-classes-content-anchor-controller.d.ts +54 -0
  145. package/types/ng-doc-app-classes-content-controller.d.ts +94 -0
  146. package/types/ng-doc-app-classes-default-search-engine.d.ts +9 -1
  147. package/types/ng-doc-app-classes-root-page.d.ts +14 -1
  148. package/types/ng-doc-app-classes-search-engine.d.ts +5 -0
  149. package/types/ng-doc-app-classes.d.ts +2 -0
  150. package/types/ng-doc-app-components-api-list.d.ts +69 -20
  151. package/types/ng-doc-app-components-breadcrumb.d.ts +8 -3
  152. package/types/ng-doc-app-components-code.d.ts +46 -12
  153. package/types/ng-doc-app-components-command-palette.d.ts +147 -0
  154. package/types/ng-doc-app-components-copy-button.d.ts +18 -6
  155. package/types/ng-doc-app-components-demo-displayer.d.ts +23 -10
  156. package/types/ng-doc-app-components-demo-frame.d.ts +48 -0
  157. package/types/ng-doc-app-components-demo-pane.d.ts +19 -15
  158. package/types/ng-doc-app-components-demo.d.ts +80 -15
  159. package/types/ng-doc-app-components-fullscreen-button.d.ts +4 -2
  160. package/types/ng-doc-app-components-fullscreen-toggle.d.ts +24 -0
  161. package/types/ng-doc-app-components-heading-anchor.d.ts +26 -7
  162. package/types/ng-doc-app-components-image-viewer.d.ts +71 -7
  163. package/types/ng-doc-app-components-kind-icon.d.ts +28 -7
  164. package/types/ng-doc-app-components-link.d.ts +6 -2
  165. package/types/ng-doc-app-components-members.d.ts +13 -0
  166. package/types/ng-doc-app-components-mermaid-viewer.d.ts +21 -6
  167. package/types/ng-doc-app-components-navbar.d.ts +25 -15
  168. package/types/ng-doc-app-components-page-header.d.ts +28 -4
  169. package/types/ng-doc-app-components-page-link.d.ts +34 -15
  170. package/types/ng-doc-app-components-page-navigation.d.ts +10 -5
  171. package/types/ng-doc-app-components-page-wrapper.d.ts +35 -11
  172. package/types/ng-doc-app-components-page.d.ts +57 -6
  173. package/types/ng-doc-app-components-playground.d.ts +167 -78
  174. package/types/ng-doc-app-components-root.d.ts +28 -7
  175. package/types/ng-doc-app-components-search-result.d.ts +14 -6
  176. package/types/ng-doc-app-components-search.d.ts +19 -7
  177. package/types/ng-doc-app-components-tabs.d.ts +24 -5
  178. package/types/ng-doc-app-components-theme-toggle.d.ts +18 -5
  179. package/types/ng-doc-app-components-toc.d.ts +76 -29
  180. package/types/ng-doc-app-components.d.ts +4 -1
  181. package/types/ng-doc-app-demo-app.d.ts +89 -0
  182. package/types/ng-doc-app-directives-code-highlighter.d.ts +8 -4
  183. package/types/ng-doc-app-directives-members-filter.d.ts +61 -0
  184. package/types/ng-doc-app-directives-route-active.d.ts +21 -7
  185. package/types/ng-doc-app-directives.d.ts +1 -0
  186. package/types/ng-doc-app-helpers.d.ts +142 -3
  187. package/types/ng-doc-app-interfaces.d.ts +62 -31
  188. package/types/ng-doc-app-pipes-decode-uri-component.d.ts +3 -0
  189. package/types/ng-doc-app-pipes-extract-value.d.ts +3 -0
  190. package/types/ng-doc-app-pipes-filter-by-text.d.ts +4 -0
  191. package/types/ng-doc-app-pipes-sanitize-html.d.ts +4 -2
  192. package/types/ng-doc-app-processors-page-processor.d.ts +39 -10
  193. package/types/ng-doc-app-processors-processors-tooltip.d.ts +11 -10
  194. package/types/ng-doc-app-processors-processors.d.ts +10 -1
  195. package/types/ng-doc-app-providers-ng-doc-app.d.ts +18 -1
  196. package/types/ng-doc-app-providers-title.d.ts +59 -0
  197. package/types/ng-doc-app-providers.d.ts +1 -0
  198. package/types/ng-doc-app-services-content-scroll-intent.d.ts +52 -0
  199. package/types/ng-doc-app-services-content-state.d.ts +40 -0
  200. package/types/ng-doc-app-services-fullscreen-route.d.ts +35 -0
  201. package/types/ng-doc-app-services-highlighter.d.ts +47 -5
  202. package/types/ng-doc-app-services-route-preloader.d.ts +121 -0
  203. package/types/ng-doc-app-services-shortcuts.d.ts +96 -0
  204. package/types/ng-doc-app-services-sidebar.d.ts +24 -4
  205. package/types/ng-doc-app-services-store.d.ts +24 -1
  206. package/types/ng-doc-app-services-theme.d.ts +19 -3
  207. package/types/ng-doc-app-services.d.ts +77 -0
  208. package/types/ng-doc-app-tokens.d.ts +10 -30
  209. package/types/ng-doc-app-type-controls-boolean-control.d.ts +11 -6
  210. package/types/ng-doc-app-type-controls-number-control.d.ts +5 -3
  211. package/types/ng-doc-app-type-controls-string-control.d.ts +5 -3
  212. package/types/ng-doc-app-type-controls-type-alias-control.d.ts +35 -6
  213. package/fesm2022/ng-doc-app-components-search-dialog.mjs +0 -78
  214. package/fesm2022/ng-doc-app-components-search-dialog.mjs.map +0 -1
  215. 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 { inject, Injector, ChangeDetectorRef, DestroyRef, ViewContainerRef, ViewChild, Input, ChangeDetectionStrategy, Component, HostBinding, EventEmitter, isDevMode, Output, Directive } from '@angular/core';
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, NgDocTextComponent, NgDocButtonComponent, NgDocCheckboxComponent, NgDocIconComponent, NgDocTextRightDirective, NgDocBindPipe, NgDocExecutePipe, NgDocAsArrayPipe } from '@ng-doc/ui-kit';
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 { takeUntil, startWith, map } from 'rxjs/operators';
18
- import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
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
- this.id = '';
28
- this.pipeName = '';
29
- this.selector = '';
30
- this.recreateDemo = false;
31
- this.expanded = false;
32
- this.code = '';
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?.valueChanges
48
- .pipe(takeUntil(this.unsubscribe$), startWith(this.form?.value), takeUntilDestroyed(this.destroyRef))
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
- this.code = await formatHtml(template);
80
- this.changeDetectorRef.markForCheck();
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.0.6", ngImport: i0, type: NgDocPlaygroundDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
124
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.6", type: NgDocPlaygroundDemoComponent, isStandalone: true, selector: "ng-doc-playground-demo", inputs: { id: "id", pipeName: "pipeName", selector: "selector", configuration: "configuration", properties: "properties", recreateDemo: "recreateDemo", form: "form", expanded: "expanded" }, viewQueries: [{ propertyName: "demoOutlet", first: true, predicate: ["demoOutlet"], descendants: true, read: ViewContainerRef, static: true }], usesOnChanges: true, ngImport: i0, template: "<ng-doc-demo-displayer [code]=\"code\" [border]=\"false\" [expanded]=\"expanded\" language=\"angular-html\">\n <ng-container #demoOutlet></ng-container>\n</ng-doc-demo-displayer>\n", styles: [":host{display:block;border:var(--ng-doc-demo-displayer-border);border-radius:var(--ng-doc-demo-displayer-border-radius);overflow:hidden}:host:not(:last-child){border-bottom:0;border-bottom-left-radius:0;border-bottom-right-radius:0}:host:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}\n"], dependencies: [{ kind: "component", type: NgDocDemoDisplayerComponent, selector: "ng-doc-demo-displayer", inputs: ["codeContent", "code", "language", "container", "border", "expanded"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
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.0.6", ngImport: i0, type: NgDocPlaygroundDemoComponent, decorators: [{
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 [code]=\"code\" [border]=\"false\" [expanded]=\"expanded\" language=\"angular-html\">\n <ng-container #demoOutlet></ng-container>\n</ng-doc-demo-displayer>\n", styles: [":host{display:block;border:var(--ng-doc-demo-displayer-border);border-radius:var(--ng-doc-demo-displayer-border-radius);overflow:hidden}:host:not(:last-child){border-bottom:0;border-bottom-left-radius:0;border-bottom-right-radius:0}:host:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}\n"] }]
129
- }], propDecorators: { id: [{
130
- type: Input
131
- }], pipeName: [{
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
- this.name = '';
153
- }
154
- ngOnChanges({ property, control, typeControl, defaultValue }) {
155
- if ((property || control || typeControl || defaultValue) && this.property && this.typeControl) {
156
- this.propertyTypeControl?.destroy();
157
- this.propertyTypeControl = undefined;
158
- if (this.typeControl && this.propertyOutlet) {
159
- this.propertyTypeControl = this.propertyOutlet.createComponent(this.typeControl.control);
160
- this.propertyTypeControl.instance.name = this.name;
161
- this.propertyTypeControl.instance.description = this.tooltipContent;
162
- this.propertyTypeControl.instance.options = isPlaygroundProperty(this.property)
163
- ? this.property.options
164
- : undefined;
165
- this.propertyTypeControl.instance.default = this.defaultValue;
166
- this.propertyTypeControl.instance.isManual = isPlaygroundProperty(this.property)
167
- ? this.property.isManual
168
- : undefined;
169
- this.propertyTypeControl.instance.writeValue(this.control?.value);
170
- this.option = this.typeControl.options;
171
- }
172
- if (this.control) {
173
- this.control?.registerOnChange((value) => this.propertyTypeControl?.instance?.writeValue(value));
174
- this.propertyTypeControl?.instance.registerOnChange((value) => this.control?.setValue(value));
175
- this.propertyTypeControl?.instance.registerOnTouched(() => this.control?.markAsTouched());
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
- get hasPropertyControl() {
180
- return !!this.propertyTypeControl;
282
+ if (CHIP_TYPES.has(property.type)) {
283
+ return property.type;
181
284
  }
182
- get tooltipContent() {
183
- return this.property && isPlaygroundProperty(this.property)
184
- ? this.property.description ?? ''
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
- this.ignoreInputs = [];
216
- this.hideSidePanel = false;
217
- this.recreateDemo = false;
218
- this.showResetButton = false;
219
- this.recreateDemoChange = new EventEmitter();
220
- this.resetForm = new EventEmitter();
221
- this.breakpoints = [Breakpoints.XSmall];
222
- this.propertyControls = [];
223
- this.contentTypeControl = this.getControlForType('boolean');
224
- this.observer = this.breakpointObserver
225
- .observe(this.breakpoints)
226
- .pipe(map((state) => state.matches));
227
- }
228
- ngOnChanges({ properties }) {
229
- if (properties && this.properties) {
230
- this.propertyControls = objectKeys(this.properties)
231
- .filter((key) => this.ignoreInputs?.includes(String(key)) !== true)
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
- if (this.properties) {
234
- const property = this.properties[key];
235
- const typeControl = this.getTypeControl(property);
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
- const aOrder = a.typeControl.options?.order;
249
- const bOrder = b.typeControl.options?.order;
250
- if (isPresent(aOrder) && isPresent(bOrder)) {
251
- return aOrder - bOrder;
252
- }
253
- if (isPresent(aOrder)) {
254
- return -1;
255
- }
256
- if (isPresent(bOrder)) {
257
- return 1;
258
- }
259
- return a.property.inputName.localeCompare(b.property.inputName);
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
- if (!isManual) {
283
- try {
284
- // checking that all values are extractable
285
- options.forEach((item) => extractValueOrThrow(item));
286
- }
287
- catch {
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.0.6", ngImport: i0, type: NgDocPlaygroundPropertiesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
299
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: NgDocPlaygroundPropertiesComponent, isStandalone: true, selector: "ng-doc-playground-properties", inputs: { form: "form", properties: "properties", ignoreInputs: "ignoreInputs", dynamicContent: "dynamicContent", defaultValues: "defaultValues", hideSidePanel: "hideSidePanel", recreateDemo: "recreateDemo", showResetButton: "showResetButton" }, outputs: { recreateDemoChange: "recreateDemoChange", resetForm: "resetForm" }, usesOnChanges: true, ngImport: i0, template: "@if (defaultValues) {\n <div class=\"ng-doc-playground-properties-wrapper\" [class.vertical]=\"observer | async\">\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 ng-doc-text>Playground</h4>\n @if (showResetButton) {\n <button ng-doc-button color=\"alert\" (click)=\"resetForm.emit()\">Reset</button>\n }\n </div>\n <div class=\"ng-doc-playground-setting\">\n <ng-doc-checkbox\n [(ngModel)]=\"recreateDemo\"\n (ngModelChange)=\"recreateDemoChange.emit($event)\">\n <span\n ng-doc-text\n [ngDocTooltip]=\"'Recreates demo everytime\\none of the input has changed'\"\n [positions]=\"['bottom-right', 'left-center']\">\n Recreate\n <ng-doc-icon icon=\"info\" ngDocTextRight></ng-doc-icon>\n </span>\n </ng-doc-checkbox>\n </div>\n <div class=\"ng-doc-playground-divider\"></div>\n @if (propertyControls.length) {\n <h5 class=\"ng-doc-title\" ng-doc-text>Settings</h5>\n @for (propertyControl of propertyControls; track propertyControl) {\n <ng-doc-playground-property\n [name]=\"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 }\n @if ((dynamicContent | keyvalue)?.length) {\n <h5 class=\"ng-doc-title\" ng-doc-text>Content</h5>\n @for (content of dynamicContent | keyvalue; track content) {\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 }\n </div>\n }\n </div>\n}\n", styles: [":host .ng-doc-playground-properties-wrapper{position:relative;display:flex;align-items:flex-start;gap:calc(var(--ng-doc-base-gutter) * 2)}:host .ng-doc-playground-properties-wrapper.vertical{flex-direction:column}:host .ng-doc-playground-properties-wrapper.vertical .ng-doc-playground-demos{margin-right:0;margin-bottom:calc(var(--ng-doc-base-gutter) * 2)}:host .ng-doc-playground-properties-wrapper.vertical .ng-doc-playground-properties{width:100%}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-demos{position:sticky;display:flex;flex-direction:column;width:100%;min-width:0;z-index:4;top:calc(var(--ng-doc-page-sticky-offset) + var(--ng-doc-base-gutter))}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-properties{flex-shrink:0;align-self:normal;width:300px;padding:calc(var(--ng-doc-base-gutter) * 2) calc(var(--ng-doc-base-gutter) * 3);background-color:var(--ng-doc-base-1);border-radius:var(--ng-doc-base-gutter);border:1px solid var(--ng-doc-border-color)}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-properties ng-doc-playground-property:not(:last-child){margin-bottom:calc(var(--ng-doc-base-gutter) * 2)}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-properties .ng-doc-playground-controls{display:flex;justify-content:flex-end}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-properties .ng-doc-playground-header{display:flex;align-items:center;justify-content:space-between;height:40px;margin-bottom:calc(var(--ng-doc-base-gutter) * 2)}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-properties .ng-doc-playground-header h4{margin:0}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-properties .ng-doc-playground-setting{display:flex;flex-direction:column}:host .ng-doc-playground-properties-wrapper .ng-doc-title{margin-top:0;margin-bottom:calc(var(--ng-doc-base-gutter) + var(--ng-doc-base-gutter) / 2)}:host .ng-doc-playground-divider{margin:calc(var(--ng-doc-base-gutter) * 2) 0;height:1px;background-color:var(--ng-doc-base-2)}\n"], dependencies: [{ kind: "component", type: NgDocTextComponent, selector: "[ng-doc-text]", inputs: ["size", "color", "align", "absoluteContent"] }, { kind: "component", type: NgDocButtonComponent, selector: "button[ng-doc-button], a[ng-doc-button], button[ng-doc-button-flat], a[ng-doc-button-flat], button[ng-doc-button-text], a[ng-doc-button-text]", inputs: ["size", "color", "rounded"] }, { 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: "directive", type: NgDocTextRightDirective, selector: "[ngDocTextRight]" }, { kind: "component", type: NgDocPlaygroundPropertyComponent, selector: "ng-doc-playground-property", inputs: ["name", "property", "typeControl", "control", "defaultValue"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: NgDocBindPipe, name: "bind" }, { kind: "pipe", type: NgDocExecutePipe, name: "execute" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
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.0.6", ngImport: i0, type: NgDocPlaygroundPropertiesComponent, decorators: [{
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 class=\"ng-doc-playground-properties-wrapper\" [class.vertical]=\"observer | async\">\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 ng-doc-text>Playground</h4>\n @if (showResetButton) {\n <button ng-doc-button color=\"alert\" (click)=\"resetForm.emit()\">Reset</button>\n }\n </div>\n <div class=\"ng-doc-playground-setting\">\n <ng-doc-checkbox\n [(ngModel)]=\"recreateDemo\"\n (ngModelChange)=\"recreateDemoChange.emit($event)\">\n <span\n ng-doc-text\n [ngDocTooltip]=\"'Recreates demo everytime\\none of the input has changed'\"\n [positions]=\"['bottom-right', 'left-center']\">\n Recreate\n <ng-doc-icon icon=\"info\" ngDocTextRight></ng-doc-icon>\n </span>\n </ng-doc-checkbox>\n </div>\n <div class=\"ng-doc-playground-divider\"></div>\n @if (propertyControls.length) {\n <h5 class=\"ng-doc-title\" ng-doc-text>Settings</h5>\n @for (propertyControl of propertyControls; track propertyControl) {\n <ng-doc-playground-property\n [name]=\"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 }\n @if ((dynamicContent | keyvalue)?.length) {\n <h5 class=\"ng-doc-title\" ng-doc-text>Content</h5>\n @for (content of dynamicContent | keyvalue; track content) {\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 }\n </div>\n }\n </div>\n}\n", styles: [":host .ng-doc-playground-properties-wrapper{position:relative;display:flex;align-items:flex-start;gap:calc(var(--ng-doc-base-gutter) * 2)}:host .ng-doc-playground-properties-wrapper.vertical{flex-direction:column}:host .ng-doc-playground-properties-wrapper.vertical .ng-doc-playground-demos{margin-right:0;margin-bottom:calc(var(--ng-doc-base-gutter) * 2)}:host .ng-doc-playground-properties-wrapper.vertical .ng-doc-playground-properties{width:100%}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-demos{position:sticky;display:flex;flex-direction:column;width:100%;min-width:0;z-index:4;top:calc(var(--ng-doc-page-sticky-offset) + var(--ng-doc-base-gutter))}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-properties{flex-shrink:0;align-self:normal;width:300px;padding:calc(var(--ng-doc-base-gutter) * 2) calc(var(--ng-doc-base-gutter) * 3);background-color:var(--ng-doc-base-1);border-radius:var(--ng-doc-base-gutter);border:1px solid var(--ng-doc-border-color)}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-properties ng-doc-playground-property:not(:last-child){margin-bottom:calc(var(--ng-doc-base-gutter) * 2)}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-properties .ng-doc-playground-controls{display:flex;justify-content:flex-end}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-properties .ng-doc-playground-header{display:flex;align-items:center;justify-content:space-between;height:40px;margin-bottom:calc(var(--ng-doc-base-gutter) * 2)}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-properties .ng-doc-playground-header h4{margin:0}:host .ng-doc-playground-properties-wrapper .ng-doc-playground-properties .ng-doc-playground-setting{display:flex;flex-direction:column}:host .ng-doc-playground-properties-wrapper .ng-doc-title{margin-top:0;margin-bottom:calc(var(--ng-doc-base-gutter) + var(--ng-doc-base-gutter) / 2)}:host .ng-doc-playground-divider{margin:calc(var(--ng-doc-base-gutter) * 2) 0;height:1px;background-color:var(--ng-doc-base-2)}\n"] }]
317
- }], ctorParameters: () => [], propDecorators: { form: [{
318
- type: Input
319
- }], properties: [{
320
- type: Input
321
- }], ignoreInputs: [{
322
- type: Input
323
- }], dynamicContent: [{
324
- type: Input
325
- }], defaultValues: [{
326
- type: Input
327
- }], hideSidePanel: [{
328
- type: Input
329
- }], recreateDemo: [{
330
- type: Input
331
- }], showResetButton: [{
332
- type: Input
333
- }], recreateDemoChange: [{
334
- type: Output
335
- }], resetForm: [{
336
- type: Output
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
- this.id = '';
344
- this.pipeName = '';
345
- this.selectors = [];
346
- this.options = {};
347
- this.recreateDemo = false;
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
- const propertiesForm = this.formBuilder.group(this.defaultProperties);
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
- this.formGroup = this.formBuilder.group({
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
- this.formGroup.patchValue({
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
- if (!this.formGroup) {
575
+ const formGroup = this.formGroup();
576
+ if (!formGroup) {
374
577
  return false;
375
578
  }
376
- return (isSameObject(this.formGroup.value.properties ?? {}, this.defaultValues ?? {}) &&
377
- isSameObject(this.formGroup.value.content ?? {}, this.defaultContent ?? {}));
579
+ return (isSameObject(formGroup.value.properties ?? {}, this.defaultValues() ?? {}) &&
580
+ isSameObject(formGroup.value.content ?? {}, this.defaultContent ?? {}));
378
581
  }
379
582
  getPropertiesFormValues() {
380
- const formValues = objectKeys(this.properties ?? {}).reduce((controls, key) => {
381
- if (this.properties) {
382
- controls[key] = this.defaultValues ? this.defaultValues[key] : undefined;
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?.content ?? {}).reduce((controls, key) => {
390
- if (this.configuration?.content) {
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.reset({}, { emitEvent: false });
398
- this.formGroup?.patchValue({
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.0.6", ngImport: i0, type: NgDocPlaygroundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
404
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.6", type: NgDocPlaygroundComponent, isStandalone: true, selector: "ng-doc-playground", inputs: { id: "id", pipeName: "pipeName", selectors: "selectors", properties: "properties", options: "options" }, usesOnChanges: true, ngImport: i0, template: "@if (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 [defaultValues]=\"defaultValues\"\n [showResetButton]=\"!isDefaultState()\"\n [(recreateDemo)]=\"recreateDemo\"\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)}\n"], dependencies: [{ kind: "component", type: NgDocPlaygroundPropertiesComponent, selector: "ng-doc-playground-properties", inputs: ["form", "properties", "ignoreInputs", "dynamicContent", "defaultValues", "hideSidePanel", "recreateDemo", "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 }); }
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.0.6", ngImport: i0, type: NgDocPlaygroundComponent, decorators: [{
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\"\n [properties]=\"properties\"\n [ignoreInputs]=\"configuration.hiddenInputs\"\n [dynamicContent]=\"configuration.content\"\n [hideSidePanel]=\"configuration.hideSidePanel ?? false\"\n [defaultValues]=\"defaultValues\"\n [showResetButton]=\"!isDefaultState()\"\n [(recreateDemo)]=\"recreateDemo\"\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)}\n"] }]
409
- }], ctorParameters: () => [], propDecorators: { id: [{
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 for playgrounds components.
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(playgroundInstance) {
428
- this.playgroundInstance = playgroundInstance;
429
- this.properties = {};
430
- this.actionData = {};
431
- this.content = {};
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
- * Extract default values from playground properties. We do this in `ngOnInit` because in this case
444
- * input values provided from the template are not initialized yet, and we can read default values instead.
445
- */
446
- if (this.playground) {
447
- this.defaultValues = Object.keys(this.playground).reduce((values, key) => {
448
- if (this.playground) {
449
- try {
450
- values[key] =
451
- // @ts-expect-error we do not know the type of the playground
452
- typeof this.playground[key] === 'function'
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.playgroundInstance) {
466
- const defaults = extractFunctionDefaults(this.playgroundInstance.prototype.transform);
467
- this.defaultValues = Object.keys(this.playgroundContainer.properties ?? {}).reduce((def, key, i) => {
468
- // we do +1 because the first argument is the `value` of the transform function
469
- def[key] = defaults[i + 1];
470
- return def;
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 = this.defaultValues;
677
+ if (!this.playgroundContainer.defaultValues()) {
678
+ this.playgroundContainer.defaultValues.set(this.defaultValues);
478
679
  }
479
- /*
480
- This is a hack just to wait for the playground container to be initialized and only then
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
- get data() {
489
- return Object.assign({}, this.configData, this.actionData);
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.0.6", ngImport: i0, type: NgDocBasePlayground, decorators: [{
691
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.2.1", ngImport: i0, type: NgDocBasePlayground, decorators: [{
495
692
  type: Directive
496
- }], ctorParameters: () => [{ type: undefined }], propDecorators: { properties: [{
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.