semmet-angular 0.11.0 → 0.13.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 (155) hide show
  1. package/README.md +15 -5
  2. package/package.json +1 -1
  3. package/src/alert/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  4. package/src/alert-dialog/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  5. package/src/badge/files/__name@dasherize__/__name@dasherize__.css.template +102 -0
  6. package/src/badge/files/__name@dasherize__/__name@dasherize__.html.template +21 -0
  7. package/src/badge/files/__name@dasherize__/__name@dasherize__.ts.template +43 -0
  8. package/src/badge/index.d.ts +1 -0
  9. package/src/badge/index.js +6 -0
  10. package/src/badge/index.js.map +1 -0
  11. package/src/badge/index.ts +3 -0
  12. package/src/badge/schema.d.ts +1 -0
  13. package/src/badge/schema.js +3 -0
  14. package/src/badge/schema.js.map +1 -0
  15. package/src/badge/schema.json +29 -0
  16. package/src/badge/schema.ts +1 -0
  17. package/src/breadcrumb/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  18. package/src/button/files/__name@dasherize__/__name@dasherize__.html.template +7 -0
  19. package/src/button-group/files/__name@dasherize__/__name@dasherize__.css.template +93 -0
  20. package/src/button-group/files/__name@dasherize__/__name@dasherize__.html.template +26 -0
  21. package/src/button-group/files/__name@dasherize__/__name@dasherize__.ts.template +85 -0
  22. package/src/button-group/index.d.ts +1 -0
  23. package/src/button-group/index.js +6 -0
  24. package/src/button-group/index.js.map +1 -0
  25. package/src/button-group/index.ts +3 -0
  26. package/src/button-group/schema.d.ts +1 -0
  27. package/src/button-group/schema.js +3 -0
  28. package/src/button-group/schema.js.map +1 -0
  29. package/src/button-group/schema.json +29 -0
  30. package/src/button-group/schema.ts +1 -0
  31. package/src/card/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  32. package/src/checkbox/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  33. package/src/close-button/files/__name@dasherize__/__name@dasherize__.css.template +105 -0
  34. package/src/close-button/files/__name@dasherize__/__name@dasherize__.html.template +17 -0
  35. package/src/close-button/files/__name@dasherize__/__name@dasherize__.ts.template +38 -0
  36. package/src/close-button/index.d.ts +1 -0
  37. package/src/close-button/index.js +6 -0
  38. package/src/close-button/index.js.map +1 -0
  39. package/src/close-button/index.ts +3 -0
  40. package/src/close-button/schema.d.ts +1 -0
  41. package/src/close-button/schema.js +3 -0
  42. package/src/close-button/schema.js.map +1 -0
  43. package/src/close-button/schema.json +29 -0
  44. package/src/close-button/schema.ts +1 -0
  45. package/src/collection.json +50 -0
  46. package/src/combobox/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  47. package/src/dialog/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  48. package/src/form/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  49. package/src/input/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  50. package/src/input-group/files/__name@dasherize__/__name@dasherize__.css.template +119 -0
  51. package/src/input-group/files/__name@dasherize__/__name@dasherize__.html.template +57 -0
  52. package/src/input-group/files/__name@dasherize__/__name@dasherize__.ts.template +64 -0
  53. package/src/input-group/index.d.ts +1 -0
  54. package/src/input-group/index.js +6 -0
  55. package/src/input-group/index.js.map +1 -0
  56. package/src/input-group/index.ts +3 -0
  57. package/src/input-group/schema.d.ts +1 -0
  58. package/src/input-group/schema.js +3 -0
  59. package/src/input-group/schema.js.map +1 -0
  60. package/src/input-group/schema.json +29 -0
  61. package/src/input-group/schema.ts +1 -0
  62. package/src/landmarks/files/__name@dasherize__/__name@dasherize__.html.template +12 -0
  63. package/src/list-group/files/__name@dasherize__/__name@dasherize__.css.template +121 -0
  64. package/src/list-group/files/__name@dasherize__/__name@dasherize__.html.template +53 -0
  65. package/src/list-group/files/__name@dasherize__/__name@dasherize__.ts.template +55 -0
  66. package/src/list-group/index.d.ts +1 -0
  67. package/src/list-group/index.js +6 -0
  68. package/src/list-group/index.js.map +1 -0
  69. package/src/list-group/index.ts +3 -0
  70. package/src/list-group/schema.d.ts +1 -0
  71. package/src/list-group/schema.js +3 -0
  72. package/src/list-group/schema.js.map +1 -0
  73. package/src/list-group/schema.json +29 -0
  74. package/src/list-group/schema.ts +1 -0
  75. package/src/listbox/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  76. package/src/menu-button/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  77. package/src/meter/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  78. package/src/navbar/files/__name@dasherize__/__name@dasherize__.css.template +158 -0
  79. package/src/navbar/files/__name@dasherize__/__name@dasherize__.html.template +42 -0
  80. package/src/navbar/files/__name@dasherize__/__name@dasherize__.ts.template +47 -0
  81. package/src/navbar/index.d.ts +1 -0
  82. package/src/navbar/index.js +6 -0
  83. package/src/navbar/index.js.map +1 -0
  84. package/src/navbar/index.ts +3 -0
  85. package/src/navbar/schema.d.ts +1 -0
  86. package/src/navbar/schema.js +3 -0
  87. package/src/navbar/schema.js.map +1 -0
  88. package/src/navbar/schema.json +29 -0
  89. package/src/navbar/schema.ts +1 -0
  90. package/src/navigation-menu/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  91. package/src/offcanvas/files/__name@dasherize__/__name@dasherize__.css.template +180 -0
  92. package/src/offcanvas/files/__name@dasherize__/__name@dasherize__.html.template +60 -0
  93. package/src/offcanvas/files/__name@dasherize__/__name@dasherize__.ts.template +96 -0
  94. package/src/offcanvas/index.d.ts +1 -0
  95. package/src/offcanvas/index.js +6 -0
  96. package/src/offcanvas/index.js.map +1 -0
  97. package/src/offcanvas/index.ts +3 -0
  98. package/src/offcanvas/schema.d.ts +1 -0
  99. package/src/offcanvas/schema.js +3 -0
  100. package/src/offcanvas/schema.js.map +1 -0
  101. package/src/offcanvas/schema.json +29 -0
  102. package/src/offcanvas/schema.ts +1 -0
  103. package/src/pagination/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  104. package/src/popover/files/__name@dasherize__/__name@dasherize__.css.template +156 -0
  105. package/src/popover/files/__name@dasherize__/__name@dasherize__.html.template +48 -0
  106. package/src/popover/files/__name@dasherize__/__name@dasherize__.ts.template +65 -0
  107. package/src/popover/index.d.ts +1 -0
  108. package/src/popover/index.js +6 -0
  109. package/src/popover/index.js.map +1 -0
  110. package/src/popover/index.ts +3 -0
  111. package/src/popover/schema.d.ts +1 -0
  112. package/src/popover/schema.js +3 -0
  113. package/src/popover/schema.js.map +1 -0
  114. package/src/popover/schema.json +29 -0
  115. package/src/popover/schema.ts +1 -0
  116. package/src/progress-bar/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  117. package/src/radio-group/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  118. package/src/select/files/__name@dasherize__/__name@dasherize__.css.template +92 -0
  119. package/src/select/files/__name@dasherize__/__name@dasherize__.html.template +39 -0
  120. package/src/select/files/__name@dasherize__/__name@dasherize__.ts.template +51 -0
  121. package/src/select/index.d.ts +1 -0
  122. package/src/select/index.js +6 -0
  123. package/src/select/index.js.map +1 -0
  124. package/src/select/index.ts +3 -0
  125. package/src/select/schema.d.ts +1 -0
  126. package/src/select/schema.js +3 -0
  127. package/src/select/schema.js.map +1 -0
  128. package/src/select/schema.json +29 -0
  129. package/src/select/schema.ts +1 -0
  130. package/src/skeleton/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  131. package/src/skip-link/files/__name@dasherize__/__name@dasherize__.html.template +7 -0
  132. package/src/slider/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  133. package/src/spinbutton/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  134. package/src/spinner/files/__name@dasherize__/__name@dasherize__.css.template +85 -0
  135. package/src/spinner/files/__name@dasherize__/__name@dasherize__.html.template +25 -0
  136. package/src/spinner/files/__name@dasherize__/__name@dasherize__.ts.template +33 -0
  137. package/src/spinner/index.d.ts +1 -0
  138. package/src/spinner/index.js +6 -0
  139. package/src/spinner/index.js.map +1 -0
  140. package/src/spinner/index.ts +3 -0
  141. package/src/spinner/schema.d.ts +1 -0
  142. package/src/spinner/schema.js +3 -0
  143. package/src/spinner/schema.js.map +1 -0
  144. package/src/spinner/schema.json +29 -0
  145. package/src/spinner/schema.ts +1 -0
  146. package/src/switch/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  147. package/src/table/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  148. package/src/textarea/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  149. package/src/toast/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  150. package/src/toolbar/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  151. package/src/tooltip/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  152. package/src/tree-view/files/__name@dasherize__/__name@dasherize__.html.template +6 -0
  153. package/src/utils/generate-component.d.ts +1 -1
  154. package/src/utils/generate-component.js +1 -1
  155. package/src/utils/generate-component.ts +1 -1
@@ -0,0 +1,65 @@
1
+ import { Component, ElementRef, Injector, afterNextRender, computed, inject, input, signal, viewChild } from '@angular/core';
2
+
3
+ type <%= classify(name) %>Placement = 'top' | 'right' | 'bottom' | 'left';
4
+
5
+ let nextId = 0;
6
+
7
+ @Component({
8
+ selector: '<%= selector %>',
9
+ imports: [],
10
+ templateUrl: './<%= dasherize(name) %>.html',
11
+ styleUrl: './<%= dasherize(name) %>.css',
12
+ host: {
13
+ '(document:click)': 'closeOnOutsideClick($event)',
14
+ },
15
+ })
16
+ export class <%= classify(name) %> {
17
+ private readonly hostRef = inject<ElementRef<HTMLElement>>(ElementRef);
18
+ private readonly injector = inject(Injector);
19
+ private readonly popoverRef = viewChild<ElementRef<HTMLElement>>('popover');
20
+
21
+ protected readonly instanceId = `<%= dasherize(name) %>-${nextId++}`;
22
+ protected readonly isOpen = signal(false);
23
+
24
+ readonly triggerLabel = input('More information');
25
+ readonly title = input('Helpful context');
26
+ readonly content = input('Use popovers for short contextual help that needs a button, link, or richer text.');
27
+ readonly closeLabel = input('Close popover');
28
+ readonly placement = input<<%= classify(name) %>Placement>('bottom');
29
+
30
+ protected readonly popoverClasses = computed(() => [
31
+ 'semmet-popover__panel',
32
+ `semmet-popover__panel--${this.placement()}`,
33
+ ].join(' '));
34
+
35
+ protected toggle(): void {
36
+ this.isOpen.update((value) => !value);
37
+ if (!this.isOpen()) {
38
+ return;
39
+ }
40
+
41
+ afterNextRender(() => this.popoverRef()?.nativeElement.focus(), { injector: this.injector });
42
+ }
43
+
44
+ protected close(): void {
45
+ this.isOpen.set(false);
46
+ }
47
+
48
+ protected handleKeydown(event: KeyboardEvent): void {
49
+ if (event.key === 'Escape') {
50
+ event.preventDefault();
51
+ this.close();
52
+ }
53
+ }
54
+
55
+ protected closeOnOutsideClick(event: MouseEvent): void {
56
+ if (!this.isOpen()) {
57
+ return;
58
+ }
59
+
60
+ const target = event.target as Node;
61
+ if (!this.hostRef.nativeElement.contains(target)) {
62
+ this.close();
63
+ }
64
+ }
65
+ }
@@ -0,0 +1 @@
1
+ export declare const popover: (options: import("./schema").Schema) => import("@angular-devkit/schematics").Rule;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.popover = void 0;
4
+ const generate_component_1 = require("../utils/generate-component");
5
+ exports.popover = (0, generate_component_1.createAriaComponentSchematic)();
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,OAAO,GAAG,IAAA,iDAA4B,GAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { createAriaComponentSchematic } from '../utils/generate-component';
2
+
3
+ export const popover = createAriaComponentSchematic();
@@ -0,0 +1 @@
1
+ export { ComponentSchematicOptions as Schema } from '../utils/schema-types';
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["schema.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema",
3
+ "$id": "SemmetAngularPopover",
4
+ "title": "Semmet Angular Popover Options Schema",
5
+ "type": "object",
6
+ "description": "Generates a standalone Angular Popover component with a disclosure trigger, non-modal dialog semantics, Escape close, and outside-click dismissal.",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "name": {
10
+ "type": "string",
11
+ "description": "The name for the new component. Used to derive the class name, selector, and file names.",
12
+ "$default": { "$source": "argv", "index": 0 },
13
+ "x-prompt": "What name would you like to use for the popover component?"
14
+ },
15
+ "path": {
16
+ "type": "string",
17
+ "format": "path",
18
+ "$default": { "$source": "workingDirectory" },
19
+ "description": "The path where the component files should be created, relative to the workspace root. Defaults to the project's source root.",
20
+ "visible": false
21
+ },
22
+ "project": {
23
+ "type": "string",
24
+ "description": "The name of the project to add the component to.",
25
+ "$default": { "$source": "projectName" }
26
+ }
27
+ },
28
+ "required": ["name", "project"]
29
+ }
@@ -0,0 +1 @@
1
+ export { ComponentSchematicOptions as Schema } from '../utils/schema-types';
@@ -1,4 +1,10 @@
1
1
  <!-- Semmet Angular: Progress Bar — https://www.w3.org/TR/wai-aria-1.2/#progressbar -->
2
+ <!--
3
+ Usage from a parent component template:
4
+ Import <%= classify(name) %> in that parent component.
5
+
6
+ <<%= selector %> />
7
+ -->
2
8
  <label [for]="instanceId">Uploading file</label>
3
9
  <progress [id]="instanceId" [value]="value()" max="100">{{ value() }}%</progress>
4
10
  <button type="button" (click)="advance()" [disabled]="isComplete()">
@@ -1,4 +1,10 @@
1
1
  <!-- Semmet Angular: Radio Group — https://www.w3.org/WAI/ARIA/apg/patterns/radio/ -->
2
+ <!--
3
+ Usage from a parent component template:
4
+ Import <%= classify(name) %> in that parent component.
5
+
6
+ <<%= selector %> />
7
+ -->
2
8
  <div role="radiogroup" [attr.aria-labelledby]="instanceId + '-label'">
3
9
  <span [id]="instanceId + '-label'">Choose a plan</span>
4
10
  @for (option of options; track option.id; let i = $index) {
@@ -0,0 +1,92 @@
1
+ :host {
2
+ --semmet-color-primary: #18181b;
3
+ --semmet-color-surface: #ffffff;
4
+ --semmet-color-outline: #d4d4d8;
5
+ --semmet-color-on-surface: #27272a;
6
+ --semmet-color-on-surface-variant: #71717a;
7
+ --semmet-color-danger: #b42318;
8
+ --semmet-radius-sm: 8px;
9
+ --semmet-motion: 160ms cubic-bezier(0.2, 0, 0, 1);
10
+
11
+ display: block;
12
+ font-family: Roboto, system-ui, -apple-system, 'Segoe UI', sans-serif;
13
+ font-size: 0.9375rem;
14
+ }
15
+
16
+ .semmet-select {
17
+ display: grid;
18
+ gap: 0.5rem;
19
+ color: var(--semmet-color-on-surface);
20
+ }
21
+
22
+ .semmet-select__label {
23
+ font-weight: 650;
24
+ }
25
+
26
+ .semmet-select__required {
27
+ color: var(--semmet-color-danger);
28
+ }
29
+
30
+ .semmet-select__control-wrap {
31
+ position: relative;
32
+ display: block;
33
+ }
34
+
35
+ .semmet-select__control-wrap::after {
36
+ position: absolute;
37
+ top: 50%;
38
+ right: 1rem;
39
+ width: 0.5rem;
40
+ height: 0.5rem;
41
+ border-right: 2px solid currentColor;
42
+ border-bottom: 2px solid currentColor;
43
+ pointer-events: none;
44
+ transform: translateY(-65%) rotate(45deg);
45
+ content: '';
46
+ }
47
+
48
+ .semmet-select__control {
49
+ width: 100%;
50
+ min-height: 2.75rem;
51
+ padding: 0.625rem 2.5rem 0.625rem 0.875rem;
52
+ border: 1px solid var(--semmet-color-outline);
53
+ border-radius: var(--semmet-radius-sm);
54
+ color: var(--semmet-color-on-surface);
55
+ background: var(--semmet-color-surface);
56
+ font: inherit;
57
+ line-height: 1.3;
58
+ appearance: none;
59
+ transition:
60
+ border-color var(--semmet-motion),
61
+ box-shadow var(--semmet-motion),
62
+ opacity var(--semmet-motion);
63
+ }
64
+
65
+ .semmet-select__control:focus-visible {
66
+ outline: 2px solid var(--semmet-color-primary);
67
+ outline-offset: 2px;
68
+ }
69
+
70
+ .semmet-select__control[aria-invalid='true'] {
71
+ border-color: var(--semmet-color-danger);
72
+ }
73
+
74
+ .semmet-select__control:disabled {
75
+ cursor: not-allowed;
76
+ opacity: 0.58;
77
+ }
78
+
79
+ .semmet-select__hint,
80
+ .semmet-select__error {
81
+ margin: 0.375rem 0 0;
82
+ font-size: 0.875rem;
83
+ line-height: 1.4;
84
+ }
85
+
86
+ .semmet-select__hint {
87
+ color: var(--semmet-color-on-surface-variant);
88
+ }
89
+
90
+ .semmet-select__error {
91
+ color: var(--semmet-color-danger);
92
+ }
@@ -0,0 +1,39 @@
1
+ <!-- Semmet Angular: Select - native select keeps platform semantics and form behavior. -->
2
+ <!--
3
+ Usage from a parent component template:
4
+ Import <%= classify(name) %> in that parent component.
5
+
6
+ <<%= selector %> label="Category" [(value)]="category" [required]="true" />
7
+ -->
8
+ <label class="semmet-select" [for]="instanceId">
9
+ <span class="semmet-select__label">
10
+ {{ label() }}
11
+ @if (required()) {
12
+ <span class="semmet-select__required" aria-hidden="true">*</span>
13
+ }
14
+ </span>
15
+ <span class="semmet-select__control-wrap">
16
+ <select
17
+ [id]="instanceId"
18
+ class="semmet-select__control"
19
+ [value]="value()"
20
+ [required]="required()"
21
+ [disabled]="disabled()"
22
+ [attr.aria-describedby]="describedBy()"
23
+ [attr.aria-invalid]="hasError()"
24
+ (change)="handleChange($event)"
25
+ >
26
+ @for (option of options(); track option.value) {
27
+ <option [value]="option.value" [disabled]="option.disabled">
28
+ {{ option.label }}
29
+ </option>
30
+ }
31
+ </select>
32
+ </span>
33
+ </label>
34
+ @if (hint()) {
35
+ <p class="semmet-select__hint" [id]="instanceId + '-hint'">{{ hint() }}</p>
36
+ }
37
+ @if (hasError()) {
38
+ <p class="semmet-select__error" [id]="instanceId + '-error'">{{ errorMessage() }}</p>
39
+ }
@@ -0,0 +1,51 @@
1
+ import { Component, booleanAttribute, computed, input, model } from '@angular/core';
2
+
3
+ interface <%= classify(name) %>Option {
4
+ value: string;
5
+ label: string;
6
+ disabled?: boolean;
7
+ }
8
+
9
+ const DEFAULT_OPTIONS: readonly <%= classify(name) %>Option[] = [
10
+ { value: '', label: 'Select an option', disabled: true },
11
+ { value: 'design', label: 'Design' },
12
+ { value: 'engineering', label: 'Engineering' },
13
+ { value: 'research', label: 'Research' },
14
+ ];
15
+
16
+ let nextId = 0;
17
+
18
+ @Component({
19
+ selector: '<%= selector %>',
20
+ imports: [],
21
+ templateUrl: './<%= dasherize(name) %>.html',
22
+ styleUrl: './<%= dasherize(name) %>.css',
23
+ })
24
+ export class <%= classify(name) %> {
25
+ protected readonly instanceId = `<%= dasherize(name) %>-${nextId++}`;
26
+
27
+ readonly label = input('Category');
28
+ readonly hint = input('Choose the option that best matches your need.');
29
+ readonly errorMessage = input('');
30
+ readonly required = input(false, { transform: booleanAttribute });
31
+ readonly disabled = input(false, { transform: booleanAttribute });
32
+ readonly options = input<readonly <%= classify(name) %>Option[]>(DEFAULT_OPTIONS);
33
+ readonly value = model('');
34
+
35
+ protected readonly hasError = computed(() => this.errorMessage().trim().length > 0);
36
+
37
+ protected readonly describedBy = computed(() => {
38
+ const ids: string[] = [];
39
+ if (this.hint().trim().length > 0) {
40
+ ids.push(`${this.instanceId}-hint`);
41
+ }
42
+ if (this.hasError()) {
43
+ ids.push(`${this.instanceId}-error`);
44
+ }
45
+ return ids.length > 0 ? ids.join(' ') : null;
46
+ });
47
+
48
+ protected handleChange(event: Event): void {
49
+ this.value.set((event.target as HTMLSelectElement).value);
50
+ }
51
+ }
@@ -0,0 +1 @@
1
+ export declare const select: (options: import("./schema").Schema) => import("@angular-devkit/schematics").Rule;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.select = void 0;
4
+ const generate_component_1 = require("../utils/generate-component");
5
+ exports.select = (0, generate_component_1.createAriaComponentSchematic)();
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,MAAM,GAAG,IAAA,iDAA4B,GAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { createAriaComponentSchematic } from '../utils/generate-component';
2
+
3
+ export const select = createAriaComponentSchematic();
@@ -0,0 +1 @@
1
+ export { ComponentSchematicOptions as Schema } from '../utils/schema-types';
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["schema.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema",
3
+ "$id": "SemmetAngularSelect",
4
+ "title": "Semmet Angular Select Options Schema",
5
+ "type": "object",
6
+ "description": "Generates a standalone Angular Select component using native select semantics, label, hint text, validation message wiring, and signal-based value state.",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "name": {
10
+ "type": "string",
11
+ "description": "The name for the new component. Used to derive the class name, selector, and file names.",
12
+ "$default": { "$source": "argv", "index": 0 },
13
+ "x-prompt": "What name would you like to use for the select component?"
14
+ },
15
+ "path": {
16
+ "type": "string",
17
+ "format": "path",
18
+ "$default": { "$source": "workingDirectory" },
19
+ "description": "The path where the component files should be created, relative to the workspace root. Defaults to the project's source root.",
20
+ "visible": false
21
+ },
22
+ "project": {
23
+ "type": "string",
24
+ "description": "The name of the project to add the component to.",
25
+ "$default": { "$source": "projectName" }
26
+ }
27
+ },
28
+ "required": ["name", "project"]
29
+ }
@@ -0,0 +1 @@
1
+ export { ComponentSchematicOptions as Schema } from '../utils/schema-types';
@@ -1,4 +1,10 @@
1
1
  <!-- Semmet Angular: Skeleton Loading - decorative placeholder for pending content. -->
2
+ <!--
3
+ Usage from a parent component template:
4
+ Import <%= classify(name) %> in that parent component.
5
+
6
+ <<%= selector %> [lines]="3" label="Loading profile" />
7
+ -->
2
8
  @if (variant() === 'text') {
3
9
  <span
4
10
  [id]="instanceId"
@@ -1,3 +1,10 @@
1
1
  <!-- Semmet Angular: Skip Link — https://www.w3.org/WAI/WCAG21/Techniques/general/G1 -->
2
+ <!--
3
+ Usage from a parent component template:
4
+ Import <%= classify(name) %> in that parent component.
5
+
6
+ <<%= selector %> />
7
+ <main id="main-content">Main content</main>
8
+ -->
2
9
  <a class="skip-link" href="#main-content">Skip to main content</a>
3
10
  <!-- Add id="main-content" to your <main> element -->
@@ -1,4 +1,10 @@
1
1
  <!-- Semmet Angular: Slider — https://www.w3.org/WAI/ARIA/apg/patterns/slider/ -->
2
+ <!--
3
+ Usage from a parent component template:
4
+ Import <%= classify(name) %> in that parent component.
5
+
6
+ <<%= selector %> />
7
+ -->
2
8
  <label [id]="instanceId + '-label'">Volume</label>
3
9
  <div #track class="track" (pointerdown)="handlePointerDown($event)" (pointermove)="handlePointerMove($event)">
4
10
  <div class="fill" [style.width.%]="value()"></div>
@@ -1,4 +1,10 @@
1
1
  <!-- Semmet Angular: Spinbutton — https://www.w3.org/WAI/ARIA/apg/patterns/spinbutton/ -->
2
+ <!--
3
+ Usage from a parent component template:
4
+ Import <%= classify(name) %> in that parent component.
5
+
6
+ <<%= selector %> />
7
+ -->
2
8
  <label [id]="instanceId + '-label'" [for]="instanceId + '-input'">Quantity</label>
3
9
  <div class="stepper">
4
10
  <button type="button" (click)="decrement()" aria-label="Decrease quantity">−</button>
@@ -0,0 +1,85 @@
1
+ :host {
2
+ --semmet-color-primary: #18181b;
3
+ --semmet-color-neutral: #71717a;
4
+ --semmet-color-success: #067647;
5
+ --semmet-color-warning: #b54708;
6
+ --semmet-color-danger: #b42318;
7
+
8
+ display: inline-block;
9
+ font-family: Roboto, system-ui, -apple-system, 'Segoe UI', sans-serif;
10
+ }
11
+
12
+ .semmet-spinner {
13
+ display: inline-flex;
14
+ align-items: center;
15
+ gap: 0.625rem;
16
+ color: var(--semmet-color-primary);
17
+ font-weight: 600;
18
+ line-height: 1;
19
+ }
20
+
21
+ .semmet-spinner--sm {
22
+ font-size: 0.75rem;
23
+ }
24
+
25
+ .semmet-spinner--md {
26
+ font-size: 0.875rem;
27
+ }
28
+
29
+ .semmet-spinner--lg {
30
+ font-size: 1rem;
31
+ }
32
+
33
+ .semmet-spinner__visual {
34
+ display: inline-block;
35
+ width: 1.25em;
36
+ height: 1.25em;
37
+ border: 0.1875em solid currentColor;
38
+ border-right-color: transparent;
39
+ border-radius: 50%;
40
+ animation: semmet-spinner-spin 700ms linear infinite;
41
+ }
42
+
43
+ .semmet-spinner--neutral {
44
+ color: var(--semmet-color-neutral);
45
+ }
46
+
47
+ .semmet-spinner--primary {
48
+ color: var(--semmet-color-primary);
49
+ }
50
+
51
+ .semmet-spinner--success {
52
+ color: var(--semmet-color-success);
53
+ }
54
+
55
+ .semmet-spinner--warning {
56
+ color: var(--semmet-color-warning);
57
+ }
58
+
59
+ .semmet-spinner--danger {
60
+ color: var(--semmet-color-danger);
61
+ }
62
+
63
+ .semmet-spinner__label--visually-hidden {
64
+ position: absolute;
65
+ width: 1px;
66
+ height: 1px;
67
+ padding: 0;
68
+ margin: -1px;
69
+ overflow: hidden;
70
+ clip: rect(0 0 0 0);
71
+ white-space: nowrap;
72
+ border: 0;
73
+ }
74
+
75
+ @keyframes semmet-spinner-spin {
76
+ to {
77
+ transform: rotate(360deg);
78
+ }
79
+ }
80
+
81
+ @media (prefers-reduced-motion: reduce) {
82
+ .semmet-spinner__visual {
83
+ animation-duration: 1.4s;
84
+ }
85
+ }
@@ -0,0 +1,25 @@
1
+ <!-- Semmet Angular: Spinner - use decorative=true when another element already announces loading. -->
2
+ <!--
3
+ Usage from a parent component template:
4
+ Import <%= classify(name) %> in that parent component.
5
+
6
+ <<%= selector %> label="Loading results" />
7
+ <<%= selector %> [decorative]="true" />
8
+ -->
9
+ <span
10
+ [id]="instanceId"
11
+ [class]="spinnerClasses()"
12
+ [attr.role]="statusRole()"
13
+ [attr.aria-live]="ariaLive()"
14
+ [attr.aria-hidden]="ariaHidden()"
15
+ >
16
+ <span class="semmet-spinner__visual" aria-hidden="true"></span>
17
+ @if (!decorative()) {
18
+ <span
19
+ class="semmet-spinner__label"
20
+ [class.semmet-spinner__label--visually-hidden]="!labelVisible()"
21
+ >
22
+ {{ label() }}
23
+ </span>
24
+ }
25
+ </span>
@@ -0,0 +1,33 @@
1
+ import { Component, booleanAttribute, computed, input } from '@angular/core';
2
+
3
+ type <%= classify(name) %>Variant = 'neutral' | 'primary' | 'success' | 'warning' | 'danger';
4
+ type <%= classify(name) %>Size = 'sm' | 'md' | 'lg';
5
+
6
+ let nextId = 0;
7
+
8
+ @Component({
9
+ selector: '<%= selector %>',
10
+ imports: [],
11
+ templateUrl: './<%= dasherize(name) %>.html',
12
+ styleUrl: './<%= dasherize(name) %>.css',
13
+ })
14
+ export class <%= classify(name) %> {
15
+ protected readonly instanceId = `<%= dasherize(name) %>-${nextId++}`;
16
+
17
+ readonly label = input('Loading');
18
+ readonly variant = input<<%= classify(name) %>Variant>('primary');
19
+ readonly size = input<<%= classify(name) %>Size>('md');
20
+ readonly labelVisible = input(false, { transform: booleanAttribute });
21
+ readonly decorative = input(false, { transform: booleanAttribute });
22
+
23
+ protected readonly spinnerClasses = computed(() => [
24
+ 'semmet-spinner',
25
+ `semmet-spinner--${this.variant()}`,
26
+ `semmet-spinner--${this.size()}`,
27
+ this.labelVisible() ? 'semmet-spinner--with-label' : '',
28
+ ].filter(Boolean).join(' '));
29
+
30
+ protected readonly statusRole = computed(() => this.decorative() ? null : 'status');
31
+ protected readonly ariaLive = computed(() => this.decorative() ? null : 'polite');
32
+ protected readonly ariaHidden = computed(() => this.decorative() ? 'true' : null);
33
+ }
@@ -0,0 +1 @@
1
+ export declare const spinner: (options: import("./schema").Schema) => import("@angular-devkit/schematics").Rule;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.spinner = void 0;
4
+ const generate_component_1 = require("../utils/generate-component");
5
+ exports.spinner = (0, generate_component_1.createAriaComponentSchematic)();
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,oEAA2E;AAE9D,QAAA,OAAO,GAAG,IAAA,iDAA4B,GAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { createAriaComponentSchematic } from '../utils/generate-component';
2
+
3
+ export const spinner = createAriaComponentSchematic();
@@ -0,0 +1 @@
1
+ export { ComponentSchematicOptions as Schema } from '../utils/schema-types';
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["schema.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema",
3
+ "$id": "SemmetAngularSpinner",
4
+ "title": "Semmet Angular Spinner Options Schema",
5
+ "type": "object",
6
+ "description": "Generates a standalone Angular Spinner component with status semantics and reduced-motion support.",
7
+ "additionalProperties": false,
8
+ "properties": {
9
+ "name": {
10
+ "type": "string",
11
+ "description": "The name for the new component. Used to derive the class name, selector, and file names.",
12
+ "$default": { "$source": "argv", "index": 0 },
13
+ "x-prompt": "What name would you like to use for the spinner component?"
14
+ },
15
+ "path": {
16
+ "type": "string",
17
+ "format": "path",
18
+ "$default": { "$source": "workingDirectory" },
19
+ "description": "The path where the component files should be created, relative to the workspace root. Defaults to the project's source root.",
20
+ "visible": false
21
+ },
22
+ "project": {
23
+ "type": "string",
24
+ "description": "The name of the project to add the component to.",
25
+ "$default": { "$source": "projectName" }
26
+ }
27
+ },
28
+ "required": ["name", "project"]
29
+ }