semmet-angular 0.41.0 → 0.43.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 (202) hide show
  1. package/README.en.md +2 -315
  2. package/README.md +169 -264
  3. package/package.json +2 -2
  4. package/src/accordion/files/__name@dasherize__/__name@dasherize__.css.template +4 -41
  5. package/src/accordion/schema.json +19 -4
  6. package/src/alert/files/__name@dasherize__/__name@dasherize__.css.template +1 -25
  7. package/src/alert/files/__name@dasherize__/__name@dasherize__.html.template +3 -3
  8. package/src/alert/files/__name@dasherize__/__name@dasherize__.ts.template +4 -1
  9. package/src/alert/schema.json +19 -4
  10. package/src/alert-dialog/files/__name@dasherize__/__name@dasherize__.css.template +3 -56
  11. package/src/alert-dialog/files/__name@dasherize__/__name@dasherize__.html.template +6 -6
  12. package/src/alert-dialog/files/__name@dasherize__/__name@dasherize__.ts.template +7 -1
  13. package/src/alert-dialog/schema.json +19 -4
  14. package/src/avatar/files/__name@dasherize__/__name@dasherize__.css.template +17 -0
  15. package/src/avatar/files/__name@dasherize__/__name@dasherize__.html.template +28 -0
  16. package/src/avatar/files/__name@dasherize__/__name@dasherize__.spec.ts.template +27 -0
  17. package/src/avatar/files/__name@dasherize__/__name@dasherize__.ts.template +35 -0
  18. package/src/avatar/index.d.ts +1 -0
  19. package/src/avatar/index.js +6 -0
  20. package/src/avatar/index.js.map +1 -0
  21. package/src/avatar/index.ts +3 -0
  22. package/src/avatar/schema.d.ts +1 -0
  23. package/src/avatar/schema.js +3 -0
  24. package/src/avatar/schema.js.map +1 -0
  25. package/src/avatar/schema.json +44 -0
  26. package/src/avatar/schema.ts +1 -0
  27. package/src/badge/files/__name@dasherize__/__name@dasherize__.css.template +0 -77
  28. package/src/badge/files/__name@dasherize__/__name@dasherize__.ts.template +2 -5
  29. package/src/badge/schema.json +19 -4
  30. package/src/block/files/__name@dasherize__/__name@dasherize__.css.template +10 -81
  31. package/src/block/files/__name@dasherize__/__name@dasherize__.html.template +33 -25
  32. package/src/block/files/__name@dasherize__/__name@dasherize__.ts.template +41 -10
  33. package/src/block/schema.json +19 -4
  34. package/src/breadcrumb/files/__name@dasherize__/__name@dasherize__.css.template +2 -23
  35. package/src/breadcrumb/files/__name@dasherize__/__name@dasherize__.html.template +4 -4
  36. package/src/breadcrumb/files/__name@dasherize__/__name@dasherize__.ts.template +9 -5
  37. package/src/breadcrumb/schema.json +19 -4
  38. package/src/button/files/__name@dasherize__/__name@dasherize__.css.template +2 -79
  39. package/src/button/files/__name@dasherize__/__name@dasherize__.ts.template +2 -5
  40. package/src/button/schema.json +19 -4
  41. package/src/button-group/files/__name@dasherize__/__name@dasherize__.css.template +2 -70
  42. package/src/button-group/files/__name@dasherize__/__name@dasherize__.ts.template +1 -2
  43. package/src/button-group/schema.json +19 -4
  44. package/src/card/files/__name@dasherize__/__name@dasherize__.css.template +0 -67
  45. package/src/card/files/__name@dasherize__/__name@dasherize__.html.template +10 -55
  46. package/src/card/files/__name@dasherize__/__name@dasherize__.ts.template +2 -45
  47. package/src/card/schema.json +19 -4
  48. package/src/carousel/files/__name@dasherize__/__name@dasherize__.css.template +4 -33
  49. package/src/carousel/files/__name@dasherize__/__name@dasherize__.html.template +4 -4
  50. package/src/carousel/files/__name@dasherize__/__name@dasherize__.ts.template +4 -0
  51. package/src/carousel/schema.json +19 -4
  52. package/src/checkbox/files/__name@dasherize__/__name@dasherize__.css.template +5 -21
  53. package/src/checkbox/schema.json +19 -4
  54. package/src/close-button/files/__name@dasherize__/__name@dasherize__.css.template +9 -47
  55. package/src/close-button/files/__name@dasherize__/__name@dasherize__.ts.template +2 -5
  56. package/src/close-button/schema.json +19 -4
  57. package/src/collection.json +15 -0
  58. package/src/combobox/files/__name@dasherize__/__name@dasherize__.css.template +4 -49
  59. package/src/combobox/files/__name@dasherize__/__name@dasherize__.html.template +2 -2
  60. package/src/combobox/files/__name@dasherize__/__name@dasherize__.ts.template +11 -8
  61. package/src/combobox/schema.json +19 -4
  62. package/src/dialog/files/__name@dasherize__/__name@dasherize__.css.template +3 -45
  63. package/src/dialog/files/__name@dasherize__/__name@dasherize__.html.template +5 -5
  64. package/src/dialog/files/__name@dasherize__/__name@dasherize__.ts.template +6 -1
  65. package/src/dialog/schema.json +19 -4
  66. package/src/disclosure/files/__name@dasherize__/__name@dasherize__.css.template +4 -36
  67. package/src/disclosure/schema.json +19 -4
  68. package/src/form/files/__name@dasherize__/__name@dasherize__.css.template +1 -77
  69. package/src/form/files/__name@dasherize__/__name@dasherize__.html.template +7 -7
  70. package/src/form/files/__name@dasherize__/__name@dasherize__.ts.template +20 -7
  71. package/src/form/schema.json +19 -4
  72. package/src/input/files/__name@dasherize__/__name@dasherize__.css.template +2 -58
  73. package/src/input/schema.json +19 -4
  74. package/src/input-group/files/__name@dasherize__/__name@dasherize__.css.template +2 -68
  75. package/src/input-group/files/__name@dasherize__/__name@dasherize__.html.template +13 -5
  76. package/src/input-group/files/__name@dasherize__/__name@dasherize__.ts.template +21 -6
  77. package/src/input-group/schema.json +19 -4
  78. package/src/landmarks/files/__name@dasherize__/__name@dasherize__.css.template +0 -24
  79. package/src/landmarks/files/__name@dasherize__/__name@dasherize__.html.template +2 -2
  80. package/src/landmarks/files/__name@dasherize__/__name@dasherize__.ts.template +5 -2
  81. package/src/landmarks/schema.json +19 -4
  82. package/src/list-group/files/__name@dasherize__/__name@dasherize__.css.template +0 -123
  83. package/src/list-group/files/__name@dasherize__/__name@dasherize__.e2e-spec.ts.template +8 -9
  84. package/src/list-group/files/__name@dasherize__/__name@dasherize__.html.template +13 -47
  85. package/src/list-group/files/__name@dasherize__/__name@dasherize__.spec.ts.template +46 -24
  86. package/src/list-group/files/__name@dasherize__/__name@dasherize__.ts.template +97 -39
  87. package/src/list-group/schema.json +19 -4
  88. package/src/listbox/files/__name@dasherize__/__name@dasherize__.css.template +3 -37
  89. package/src/listbox/files/__name@dasherize__/__name@dasherize__.html.template +2 -2
  90. package/src/listbox/files/__name@dasherize__/__name@dasherize__.ts.template +3 -1
  91. package/src/listbox/schema.json +19 -4
  92. package/src/menu-button/files/__name@dasherize__/__name@dasherize__.css.template +7 -47
  93. package/src/menu-button/files/__name@dasherize__/__name@dasherize__.html.template +3 -3
  94. package/src/menu-button/files/__name@dasherize__/__name@dasherize__.ts.template +10 -7
  95. package/src/menu-button/schema.json +19 -4
  96. package/src/meter/files/__name@dasherize__/__name@dasherize__.css.template +0 -12
  97. package/src/meter/files/__name@dasherize__/__name@dasherize__.html.template +2 -2
  98. package/src/meter/files/__name@dasherize__/__name@dasherize__.ts.template +3 -1
  99. package/src/meter/schema.json +19 -4
  100. package/src/navbar/files/__name@dasherize__/__name@dasherize__.css.template +6 -62
  101. package/src/navbar/schema.json +19 -4
  102. package/src/navigation-menu/files/__name@dasherize__/__name@dasherize__.css.template +6 -37
  103. package/src/navigation-menu/files/__name@dasherize__/__name@dasherize__.html.template +7 -6
  104. package/src/navigation-menu/files/__name@dasherize__/__name@dasherize__.ts.template +15 -1
  105. package/src/navigation-menu/schema.json +19 -4
  106. package/src/offcanvas/files/__name@dasherize__/__name@dasherize__.css.template +3 -70
  107. package/src/offcanvas/schema.json +19 -4
  108. package/src/pagination/files/__name@dasherize__/__name@dasherize__.css.template +2 -33
  109. package/src/pagination/files/__name@dasherize__/__name@dasherize__.html.template +6 -6
  110. package/src/pagination/files/__name@dasherize__/__name@dasherize__.ts.template +7 -1
  111. package/src/pagination/schema.json +19 -4
  112. package/src/popover/files/__name@dasherize__/__name@dasherize__.css.template +8 -69
  113. package/src/popover/schema.json +19 -4
  114. package/src/progress-bar/files/__name@dasherize__/__name@dasherize__.css.template +1 -31
  115. package/src/progress-bar/files/__name@dasherize__/__name@dasherize__.html.template +3 -3
  116. package/src/progress-bar/files/__name@dasherize__/__name@dasherize__.ts.template +5 -1
  117. package/src/progress-bar/schema.json +19 -4
  118. package/src/radio-group/files/__name@dasherize__/__name@dasherize__.css.template +4 -31
  119. package/src/radio-group/files/__name@dasherize__/__name@dasherize__.html.template +2 -2
  120. package/src/radio-group/files/__name@dasherize__/__name@dasherize__.ts.template +2 -1
  121. package/src/radio-group/schema.json +19 -4
  122. package/src/rating/files/__name@dasherize__/__name@dasherize__.css.template +17 -0
  123. package/src/rating/files/__name@dasherize__/__name@dasherize__.html.template +34 -0
  124. package/src/rating/files/__name@dasherize__/__name@dasherize__.spec.ts.template +38 -0
  125. package/src/rating/files/__name@dasherize__/__name@dasherize__.ts.template +75 -0
  126. package/src/rating/index.d.ts +1 -0
  127. package/src/rating/index.js +6 -0
  128. package/src/rating/index.js.map +1 -0
  129. package/src/rating/index.ts +3 -0
  130. package/src/rating/schema.d.ts +1 -0
  131. package/src/rating/schema.js +3 -0
  132. package/src/rating/schema.js.map +1 -0
  133. package/src/rating/schema.json +44 -0
  134. package/src/rating/schema.ts +1 -0
  135. package/src/select/files/__name@dasherize__/__name@dasherize__.css.template +4 -55
  136. package/src/select/schema.json +19 -4
  137. package/src/skeleton/files/__name@dasherize__/__name@dasherize__.css.template +2 -29
  138. package/src/skeleton/files/__name@dasherize__/__name@dasherize__.ts.template +1 -3
  139. package/src/skeleton/schema.json +19 -4
  140. package/src/skip-link/files/__name@dasherize__/__name@dasherize__.css.template +2 -14
  141. package/src/skip-link/files/__name@dasherize__/__name@dasherize__.html.template +2 -2
  142. package/src/skip-link/files/__name@dasherize__/__name@dasherize__.ts.template +5 -2
  143. package/src/skip-link/schema.json +19 -4
  144. package/src/slider/files/__name@dasherize__/__name@dasherize__.css.template +6 -20
  145. package/src/slider/files/__name@dasherize__/__name@dasherize__.html.template +2 -2
  146. package/src/slider/files/__name@dasherize__/__name@dasherize__.ts.template +3 -1
  147. package/src/slider/schema.json +19 -4
  148. package/src/spinbutton/files/__name@dasherize__/__name@dasherize__.css.template +6 -35
  149. package/src/spinbutton/files/__name@dasherize__/__name@dasherize__.html.template +4 -4
  150. package/src/spinbutton/files/__name@dasherize__/__name@dasherize__.ts.template +5 -1
  151. package/src/spinbutton/schema.json +19 -4
  152. package/src/spinner/files/__name@dasherize__/__name@dasherize__.css.template +0 -43
  153. package/src/spinner/files/__name@dasherize__/__name@dasherize__.ts.template +2 -5
  154. package/src/spinner/schema.json +19 -4
  155. package/src/steps/files/__name@dasherize__/__name@dasherize__.css.template +36 -0
  156. package/src/steps/files/__name@dasherize__/__name@dasherize__.html.template +44 -0
  157. package/src/steps/files/__name@dasherize__/__name@dasherize__.spec.ts.template +35 -0
  158. package/src/steps/files/__name@dasherize__/__name@dasherize__.ts.template +107 -0
  159. package/src/steps/index.d.ts +1 -0
  160. package/src/steps/index.js +6 -0
  161. package/src/steps/index.js.map +1 -0
  162. package/src/steps/index.ts +3 -0
  163. package/src/steps/schema.d.ts +1 -0
  164. package/src/steps/schema.js +3 -0
  165. package/src/steps/schema.js.map +1 -0
  166. package/src/steps/schema.json +44 -0
  167. package/src/steps/schema.ts +1 -0
  168. package/src/switch/files/__name@dasherize__/__name@dasherize__.css.template +7 -22
  169. package/src/switch/schema.json +19 -4
  170. package/src/table/files/__name@dasherize__/__name@dasherize__.css.template +0 -25
  171. package/src/table/files/__name@dasherize__/__name@dasherize__.html.template +3 -3
  172. package/src/table/files/__name@dasherize__/__name@dasherize__.ts.template +3 -0
  173. package/src/table/schema.json +19 -4
  174. package/src/tabs/files/__name@dasherize__/__name@dasherize__.css.template +5 -44
  175. package/src/tabs/files/__name@dasherize__/__name@dasherize__.html.template +2 -2
  176. package/src/tabs/files/__name@dasherize__/__name@dasherize__.ts.template +2 -0
  177. package/src/tabs/schema.json +19 -4
  178. package/src/textarea/files/__name@dasherize__/__name@dasherize__.css.template +2 -59
  179. package/src/textarea/schema.json +19 -4
  180. package/src/toast/files/__name@dasherize__/__name@dasherize__.css.template +1 -35
  181. package/src/toast/files/__name@dasherize__/__name@dasherize__.html.template +4 -4
  182. package/src/toast/files/__name@dasherize__/__name@dasherize__.ts.template +5 -1
  183. package/src/toast/schema.json +19 -4
  184. package/src/toolbar/files/__name@dasherize__/__name@dasherize__.css.template +2 -36
  185. package/src/toolbar/files/__name@dasherize__/__name@dasherize__.html.template +3 -3
  186. package/src/toolbar/files/__name@dasherize__/__name@dasherize__.ts.template +11 -8
  187. package/src/toolbar/schema.json +19 -4
  188. package/src/tooltip/files/__name@dasherize__/__name@dasherize__.css.template +1 -32
  189. package/src/tooltip/schema.json +19 -4
  190. package/src/tree-view/files/__name@dasherize__/__name@dasherize__.css.template +5 -27
  191. package/src/tree-view/files/__name@dasherize__/__name@dasherize__.html.template +3 -3
  192. package/src/tree-view/files/__name@dasherize__/__name@dasherize__.ts.template +16 -13
  193. package/src/tree-view/schema.json +19 -4
  194. package/src/utils/generate-component.js +3 -1
  195. package/src/utils/generate-component.js.map +1 -1
  196. package/src/utils/generate-component.ts +3 -1
  197. package/src/utils/generate-composition.js +7 -2
  198. package/src/utils/generate-composition.js.map +1 -1
  199. package/src/utils/generate-composition.ts +9 -2
  200. package/src/utils/schema-types.d.ts +1 -0
  201. package/src/utils/schema-types.ts +1 -0
  202. package/README.pt-BR.md +0 -330
@@ -9,21 +9,36 @@
9
9
  "name": {
10
10
  "type": "string",
11
11
  "description": "The name for the new component. Used to derive the class name, selector, and file names.",
12
- "$default": { "$source": "argv", "index": 0 },
12
+ "$default": {
13
+ "$source": "argv",
14
+ "index": 0
15
+ },
13
16
  "x-prompt": "What name would you like to use for the popover component?"
14
17
  },
18
+ "e2e": {
19
+ "type": "boolean",
20
+ "default": false,
21
+ "description": "Generate a Playwright e2e spec for this component. Requires Playwright to be installed/configured in the consuming app."
22
+ },
15
23
  "path": {
16
24
  "type": "string",
17
25
  "format": "path",
18
- "$default": { "$source": "workingDirectory" },
26
+ "$default": {
27
+ "$source": "workingDirectory"
28
+ },
19
29
  "description": "The path where the component files should be created, relative to the workspace root. Defaults to the project's source root.",
20
30
  "visible": false
21
31
  },
22
32
  "project": {
23
33
  "type": "string",
24
34
  "description": "The name of the project to add the component to.",
25
- "$default": { "$source": "projectName" }
35
+ "$default": {
36
+ "$source": "projectName"
37
+ }
26
38
  }
27
39
  },
28
- "required": ["name", "project"]
40
+ "required": [
41
+ "name",
42
+ "project"
43
+ ]
29
44
  }
@@ -1,57 +1,27 @@
1
1
  :host {
2
- --semmet-color-primary: #18181b;
3
- --semmet-color-on-surface: #18181b;
4
- --semmet-color-on-surface-variant: #52525b;
5
- --semmet-radius-sm: 8px;
6
- --semmet-space-2xs: 8px;
7
- --semmet-space-xs: 16px;
8
- --semmet-target-md: 40px;
9
- --semmet-motion: 160ms cubic-bezier(0.2, 0, 0, 1);
10
-
11
2
  display: block;
12
- font-family: Roboto, system-ui, -apple-system, 'Segoe UI', sans-serif;
13
- font-size: 0.9375rem;
14
3
  }
15
4
 
16
5
  label {
17
6
  display: block;
18
- margin-bottom: var(--semmet-space-2xs);
19
- font-weight: 500;
20
- color: var(--semmet-color-on-surface);
21
7
  }
22
8
 
23
9
  progress {
24
10
  display: block;
25
11
  width: 100%;
26
- max-width: 20rem;
27
- height: 0.5rem;
28
- margin-bottom: var(--semmet-space-xs);
29
- accent-color: var(--semmet-color-primary);
30
12
  }
31
13
 
32
14
  button {
33
15
  font: inherit;
34
- font-weight: 500;
35
- color: var(--semmet-color-primary);
36
16
  background: none;
37
- border: 1px solid currentColor;
38
- border-radius: var(--semmet-radius-sm);
39
- min-height: var(--semmet-target-md);
40
- padding: var(--semmet-space-2xs) var(--semmet-space-xs);
41
17
  cursor: pointer;
42
- transition: background-color var(--semmet-motion);
43
- }
44
-
45
- button:hover:not(:disabled) {
46
- background: color-mix(in srgb, var(--semmet-color-primary) 8%, transparent);
47
18
  }
48
19
 
49
20
  button:disabled {
50
- color: var(--semmet-color-on-surface-variant);
51
21
  cursor: not-allowed;
52
22
  }
53
23
 
54
24
  button:focus-visible {
55
- outline: 2px solid var(--semmet-color-primary);
25
+ outline: 2px solid currentColor;
56
26
  outline-offset: 2px;
57
27
  }
@@ -3,10 +3,10 @@
3
3
  Usage from a parent component template:
4
4
  Import <%= classify(name) %> in that parent component.
5
5
 
6
- <<%= selector %> />
6
+ <<%= selector %> label="Uploading file" />
7
7
  -->
8
- <label [for]="instanceId">Uploading file</label>
8
+ <label [for]="instanceId">{{ label() }}</label>
9
9
  <progress [id]="instanceId" [value]="value()" max="100">{{ value() }}%</progress>
10
10
  <button type="button" (click)="advance()" [disabled]="isComplete()">
11
- {{ isComplete() ? 'Done' : 'Simulate progress' }}
11
+ {{ isComplete() ? completeLabel() : advanceLabel() }}
12
12
  </button>
@@ -1,4 +1,4 @@
1
- import { Component, computed, signal } from '@angular/core';
1
+ import { Component, computed, input, signal } from '@angular/core';
2
2
 
3
3
  let nextId = 0;
4
4
 
@@ -13,6 +13,10 @@ export class <%= classify(name) %> {
13
13
  protected readonly value = signal(40);
14
14
  protected readonly isComplete = computed(() => this.value() >= 100);
15
15
 
16
+ readonly label = input('Uploading file');
17
+ readonly completeLabel = input('Done');
18
+ readonly advanceLabel = input('Simulate progress');
19
+
16
20
  protected advance(): void {
17
21
  this.value.update((current) => Math.min(100, current + 20));
18
22
  }
@@ -9,21 +9,36 @@
9
9
  "name": {
10
10
  "type": "string",
11
11
  "description": "The name for the new component. Used to derive the class name, selector, and file names.",
12
- "$default": { "$source": "argv", "index": 0 },
12
+ "$default": {
13
+ "$source": "argv",
14
+ "index": 0
15
+ },
13
16
  "x-prompt": "What name would you like to use for the progress bar component?"
14
17
  },
18
+ "e2e": {
19
+ "type": "boolean",
20
+ "default": false,
21
+ "description": "Generate a Playwright e2e spec for this component. Requires Playwright to be installed/configured in the consuming app."
22
+ },
15
23
  "path": {
16
24
  "type": "string",
17
25
  "format": "path",
18
- "$default": { "$source": "workingDirectory" },
26
+ "$default": {
27
+ "$source": "workingDirectory"
28
+ },
19
29
  "description": "The path where the component files should be created, relative to the workspace root. Defaults to the project's source root.",
20
30
  "visible": false
21
31
  },
22
32
  "project": {
23
33
  "type": "string",
24
34
  "description": "The name of the project to add the component to.",
25
- "$default": { "$source": "projectName" }
35
+ "$default": {
36
+ "$source": "projectName"
37
+ }
26
38
  }
27
39
  },
28
- "required": ["name", "project"]
40
+ "required": [
41
+ "name",
42
+ "project"
43
+ ]
29
44
  }
@@ -1,32 +1,16 @@
1
1
  :host {
2
- --semmet-color-primary: #18181b;
3
- --semmet-color-outline: #71717a;
4
- --semmet-color-on-surface: #18181b;
5
- --semmet-color-on-surface-variant: #52525b;
6
- --semmet-space-2xs: 8px;
7
- --semmet-space-md: 32px;
8
- --semmet-target-md: 40px;
9
- --semmet-motion: 160ms cubic-bezier(0.2, 0, 0, 1);
10
-
11
2
  display: block;
12
- font-family: Roboto, system-ui, -apple-system, 'Segoe UI', sans-serif;
13
- font-size: 0.9375rem;
14
3
  }
15
4
 
16
5
  [role='radiogroup'] > span {
17
6
  display: block;
18
- margin-bottom: var(--semmet-space-2xs);
19
- font-weight: 500;
20
- color: var(--semmet-color-on-surface);
21
7
  }
22
8
 
23
9
  [role='radio'] {
24
10
  position: relative;
25
11
  display: flex;
26
12
  align-items: center;
27
- min-height: var(--semmet-target-md);
28
- padding: var(--semmet-space-2xs) 0 var(--semmet-space-2xs) var(--semmet-space-md);
29
- color: var(--semmet-color-on-surface-variant);
13
+ padding-left: 1.5rem;
30
14
  cursor: pointer;
31
15
  user-select: none;
32
16
  }
@@ -38,18 +22,8 @@
38
22
  width: 1.125rem;
39
23
  height: 1.125rem;
40
24
  box-sizing: border-box;
41
- border: 2px solid var(--semmet-color-outline);
25
+ border: 2px solid currentColor;
42
26
  border-radius: 50%;
43
- transition: border-color var(--semmet-motion);
44
- }
45
-
46
- [role='radio'][aria-checked='true'] {
47
- color: var(--semmet-color-on-surface);
48
- font-weight: 500;
49
- }
50
-
51
- [role='radio'][aria-checked='true']::before {
52
- border-color: var(--semmet-color-primary);
53
27
  }
54
28
 
55
29
  [role='radio'][aria-checked='true']::after {
@@ -60,11 +34,10 @@
60
34
  width: 0.625rem;
61
35
  height: 0.625rem;
62
36
  border-radius: 50%;
63
- background: var(--semmet-color-primary);
37
+ background: currentColor;
64
38
  }
65
39
 
66
40
  [role='radio']:focus-visible {
67
- outline: 2px solid var(--semmet-color-primary);
41
+ outline: 2px solid currentColor;
68
42
  outline-offset: 2px;
69
- border-radius: 4px;
70
43
  }
@@ -3,10 +3,10 @@
3
3
  Usage from a parent component template:
4
4
  Import <%= classify(name) %> in that parent component.
5
5
 
6
- <<%= selector %> />
6
+ <<%= selector %> label="Choose a plan" />
7
7
  -->
8
8
  <div role="radiogroup" [attr.aria-labelledby]="instanceId + '-label'">
9
- <span [id]="instanceId + '-label'">Choose a plan</span>
9
+ <span [id]="instanceId + '-label'">{{ label() }}</span>
10
10
  @for (option of options; track option.id; let i = $index) {
11
11
  <div
12
12
  #radio
@@ -1,4 +1,4 @@
1
- import { Component, ElementRef, signal, viewChildren } from '@angular/core';
1
+ import { Component, ElementRef, input, signal, viewChildren } from '@angular/core';
2
2
 
3
3
  interface <%= classify(name) %>Option {
4
4
  id: number;
@@ -17,6 +17,7 @@ export class <%= classify(name) %> {
17
17
  private readonly radios = viewChildren<ElementRef<HTMLElement>>('radio');
18
18
 
19
19
  protected readonly instanceId = `<%= dasherize(name) %>-${nextId++}`;
20
+ readonly label = input('Choose a plan');
20
21
  protected readonly options: <%= classify(name) %>Option[] = [
21
22
  { id: 1, label: 'Monthly' },
22
23
  { id: 2, label: 'Yearly' },
@@ -9,21 +9,36 @@
9
9
  "name": {
10
10
  "type": "string",
11
11
  "description": "The name for the new component. Used to derive the class name, selector, and file names.",
12
- "$default": { "$source": "argv", "index": 0 },
12
+ "$default": {
13
+ "$source": "argv",
14
+ "index": 0
15
+ },
13
16
  "x-prompt": "What name would you like to use for the radio group component?"
14
17
  },
18
+ "e2e": {
19
+ "type": "boolean",
20
+ "default": false,
21
+ "description": "Generate a Playwright e2e spec for this component. Requires Playwright to be installed/configured in the consuming app."
22
+ },
15
23
  "path": {
16
24
  "type": "string",
17
25
  "format": "path",
18
- "$default": { "$source": "workingDirectory" },
26
+ "$default": {
27
+ "$source": "workingDirectory"
28
+ },
19
29
  "description": "The path where the component files should be created, relative to the workspace root. Defaults to the project's source root.",
20
30
  "visible": false
21
31
  },
22
32
  "project": {
23
33
  "type": "string",
24
34
  "description": "The name of the project to add the component to.",
25
- "$default": { "$source": "projectName" }
35
+ "$default": {
36
+ "$source": "projectName"
37
+ }
26
38
  }
27
39
  },
28
- "required": ["name", "project"]
40
+ "required": [
41
+ "name",
42
+ "project"
43
+ ]
29
44
  }
@@ -0,0 +1,17 @@
1
+ :host {
2
+ display: inline-block;
3
+ }
4
+
5
+ .semmet-rating,
6
+ .semmet-rating__item {
7
+ display: inline-flex;
8
+ }
9
+
10
+ .semmet-rating__item[role='radio'] {
11
+ cursor: pointer;
12
+ }
13
+
14
+ .semmet-rating__item:focus-visible {
15
+ outline: 2px solid currentColor;
16
+ outline-offset: 2px;
17
+ }
@@ -0,0 +1,34 @@
1
+ <!-- Semmet Angular: Rating - readonly image semantics or interactive radiogroup semantics. -->
2
+ <!--
3
+ Usage from a parent component template:
4
+ Import <%= classify(name) %> in that parent component.
5
+
6
+ <<%= selector %> [value]="4" />
7
+ <<%= selector %> [readonly]="false" (valueChange)="saveRating($event)" />
8
+ -->
9
+ @if (readonly()) {
10
+ <div class="semmet-rating" role="img" [attr.aria-label]="accessibleLabel()">
11
+ @for (item of values(); track item) {
12
+ <span class="semmet-rating__item" [class.semmet-rating__item--filled]="isFilled(item)" aria-hidden="true">★</span>
13
+ }
14
+ </div>
15
+ } @else {
16
+ <div class="semmet-rating" role="radiogroup" [attr.aria-labelledby]="instanceId + '-label'">
17
+ <span [id]="instanceId + '-label'" class="semmet-rating__label">{{ label() }}</span>
18
+ @for (item of values(); track item; let i = $index) {
19
+ <span
20
+ #ratingOption
21
+ class="semmet-rating__item"
22
+ role="radio"
23
+ [class.semmet-rating__item--filled]="isFilled(item)"
24
+ [attr.aria-label]="item + ' out of ' + max()"
25
+ [attr.aria-checked]="isSelected(item)"
26
+ [tabIndex]="isSelected(item) ? 0 : -1"
27
+ (click)="select(item)"
28
+ (keydown)="navigate($event, i)"
29
+ >
30
+
31
+ </span>
32
+ }
33
+ </div>
34
+ }
@@ -0,0 +1,38 @@
1
+ import { Component } from '@angular/core';
2
+ import { ComponentFixture, TestBed } from '@angular/core/testing';
3
+ import { By } from '@angular/platform-browser';
4
+ import { <%= classify(name) %> } from './<%= dasherize(name) %>';
5
+
6
+ @Component({
7
+ imports: [<%= classify(name) %>],
8
+ template: `<<%= selector %> [readonly]="false" />`,
9
+ })
10
+ class Host {}
11
+
12
+ describe('<%= classify(name) %>', () => {
13
+ let fixture: ComponentFixture<Host>;
14
+
15
+ beforeEach(async () => {
16
+ await TestBed.configureTestingModule({ imports: [Host] }).compileComponents();
17
+ fixture = TestBed.createComponent(Host);
18
+ fixture.detectChanges();
19
+ });
20
+
21
+ it('uses radiogroup semantics when interactive', () => {
22
+ const group = fixture.nativeElement.querySelector('[role="radiogroup"]');
23
+ const options = fixture.nativeElement.querySelectorAll('[role="radio"]');
24
+
25
+ expect(group?.getAttribute('aria-labelledby')).toBeTruthy();
26
+ expect(options.length).toBe(5);
27
+ expect(options[3].getAttribute('aria-checked')).toBe('true');
28
+ });
29
+
30
+ it('updates checked rating on click', () => {
31
+ const options = fixture.debugElement.queryAll(By.css('[role="radio"]'));
32
+
33
+ options[1].triggerEventHandler('click');
34
+ fixture.detectChanges();
35
+
36
+ expect(fixture.nativeElement.querySelectorAll('[role="radio"]')[1].getAttribute('aria-checked')).toBe('true');
37
+ });
38
+ });
@@ -0,0 +1,75 @@
1
+ import { Component, ElementRef, booleanAttribute, computed, input, output, signal, viewChildren } from '@angular/core';
2
+
3
+ let nextId = 0;
4
+
5
+ @Component({
6
+ selector: '<%= selector %>',
7
+ imports: [],
8
+ templateUrl: './<%= dasherize(name) %>.html',
9
+ styleUrl: './<%= dasherize(name) %>.css',
10
+ })
11
+ export class <%= classify(name) %> {
12
+ private readonly ratingOptions = viewChildren<ElementRef<HTMLElement>>('ratingOption');
13
+
14
+ protected readonly instanceId = `<%= dasherize(name) %>-${nextId++}`;
15
+
16
+ readonly label = input('Rating');
17
+ readonly max = input(5);
18
+ readonly value = input<number | null>(null);
19
+ readonly readonly = input(true, { transform: booleanAttribute });
20
+ readonly valueChange = output<number>();
21
+
22
+ protected readonly selectedValue = signal(4);
23
+ protected readonly activeValue = computed(() => this.value() ?? this.selectedValue());
24
+ protected readonly values = computed(() => Array.from({ length: Math.max(1, this.max()) }, (_, index) => index + 1));
25
+ protected readonly accessibleLabel = computed(() => `${this.activeValue()} out of ${this.max()} ${this.label()}`);
26
+
27
+ protected isSelected(value: number): boolean {
28
+ return this.activeValue() === value;
29
+ }
30
+
31
+ protected isFilled(value: number): boolean {
32
+ return value <= this.activeValue();
33
+ }
34
+
35
+ protected select(value: number): void {
36
+ if (this.readonly()) {
37
+ return;
38
+ }
39
+
40
+ this.selectedValue.set(value);
41
+ this.valueChange.emit(value);
42
+ }
43
+
44
+ protected navigate(event: KeyboardEvent, index: number): void {
45
+ if (this.readonly()) {
46
+ return;
47
+ }
48
+
49
+ const values = this.values();
50
+ let nextIndex: number;
51
+
52
+ switch (event.key) {
53
+ case 'ArrowDown':
54
+ case 'ArrowLeft':
55
+ nextIndex = (index - 1 + values.length) % values.length;
56
+ break;
57
+ case 'ArrowUp':
58
+ case 'ArrowRight':
59
+ nextIndex = (index + 1) % values.length;
60
+ break;
61
+ case 'Home':
62
+ nextIndex = 0;
63
+ break;
64
+ case 'End':
65
+ nextIndex = values.length - 1;
66
+ break;
67
+ default:
68
+ return;
69
+ }
70
+
71
+ event.preventDefault();
72
+ this.select(values[nextIndex]);
73
+ this.ratingOptions()[nextIndex]?.nativeElement.focus();
74
+ }
75
+ }
@@ -0,0 +1 @@
1
+ export declare const rating: (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.rating = void 0;
4
+ const generate_component_1 = require("../utils/generate-component");
5
+ exports.rating = (0, generate_component_1.createAriaComponentSchematic)({ includeSharedUnitTest: false });
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,EAAC,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { createAriaComponentSchematic } from '../utils/generate-component';
2
+
3
+ export const rating = createAriaComponentSchematic({ includeSharedUnitTest: false });
@@ -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,44 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema",
3
+ "$id": "SemmetAngularRating",
4
+ "title": "Semmet Angular Rating Options Schema",
5
+ "type": "object",
6
+ "description": "Generates a standalone Angular Rating component with readonly image semantics or interactive radiogroup semantics.",
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": {
13
+ "$source": "argv",
14
+ "index": 0
15
+ },
16
+ "x-prompt": "What name would you like to use for the rating component?"
17
+ },
18
+ "e2e": {
19
+ "type": "boolean",
20
+ "default": false,
21
+ "description": "Generate a Playwright e2e spec for this component. Requires Playwright to be installed/configured in the consuming app."
22
+ },
23
+ "path": {
24
+ "type": "string",
25
+ "format": "path",
26
+ "$default": {
27
+ "$source": "workingDirectory"
28
+ },
29
+ "description": "The path where the component files should be created, relative to the workspace root. Defaults to the project's source root.",
30
+ "visible": false
31
+ },
32
+ "project": {
33
+ "type": "string",
34
+ "description": "The name of the project to add the component to.",
35
+ "$default": {
36
+ "$source": "projectName"
37
+ }
38
+ }
39
+ },
40
+ "required": [
41
+ "name",
42
+ "project"
43
+ ]
44
+ }
@@ -0,0 +1 @@
1
+ export { ComponentSchematicOptions as Schema } from '../utils/schema-types';
@@ -1,35 +1,9 @@
1
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-space-2xs: 8px;
10
- --semmet-space-xs: 16px;
11
- --semmet-space-md: 32px;
12
- --semmet-space-lg: 48px;
13
- --semmet-target-lg: 48px;
14
- --semmet-motion: 160ms cubic-bezier(0.2, 0, 0, 1);
15
-
16
2
  display: block;
17
- font-family: Roboto, system-ui, -apple-system, 'Segoe UI', sans-serif;
18
- font-size: 0.9375rem;
19
3
  }
20
4
 
21
5
  .semmet-select {
22
6
  display: grid;
23
- gap: var(--semmet-space-2xs);
24
- color: var(--semmet-color-on-surface);
25
- }
26
-
27
- .semmet-select__label {
28
- font-weight: 650;
29
- }
30
-
31
- .semmet-select__required {
32
- color: var(--semmet-color-danger);
33
7
  }
34
8
 
35
9
  .semmet-select__control-wrap {
@@ -40,7 +14,7 @@
40
14
  .semmet-select__control-wrap::after {
41
15
  position: absolute;
42
16
  top: 50%;
43
- right: var(--semmet-space-xs);
17
+ right: 0.75em;
44
18
  width: 0.5rem;
45
19
  height: 0.5rem;
46
20
  border-right: 2px solid currentColor;
@@ -52,46 +26,21 @@
52
26
 
53
27
  .semmet-select__control {
54
28
  width: 100%;
55
- min-height: var(--semmet-target-lg);
56
- padding: var(--semmet-space-2xs) var(--semmet-space-lg) var(--semmet-space-2xs) var(--semmet-space-xs);
57
- border: 1px solid var(--semmet-color-outline);
58
- border-radius: var(--semmet-radius-sm);
59
- color: var(--semmet-color-on-surface);
60
- background: var(--semmet-color-surface);
29
+ box-sizing: border-box;
61
30
  font: inherit;
62
- line-height: 1.3;
63
31
  appearance: none;
64
- transition:
65
- border-color var(--semmet-motion),
66
- box-shadow var(--semmet-motion),
67
- opacity var(--semmet-motion);
68
32
  }
69
33
 
70
34
  .semmet-select__control:focus-visible {
71
- outline: 2px solid var(--semmet-color-primary);
35
+ outline: 2px solid currentColor;
72
36
  outline-offset: 2px;
73
37
  }
74
38
 
75
- .semmet-select__control[aria-invalid='true'] {
76
- border-color: var(--semmet-color-danger);
77
- }
78
-
79
39
  .semmet-select__control:disabled {
80
40
  cursor: not-allowed;
81
- opacity: 0.58;
82
41
  }
83
42
 
84
43
  .semmet-select__hint,
85
44
  .semmet-select__error {
86
- margin: var(--semmet-space-2xs) 0 0;
87
- font-size: 0.875rem;
88
- line-height: 1.4;
89
- }
90
-
91
- .semmet-select__hint {
92
- color: var(--semmet-color-on-surface-variant);
93
- }
94
-
95
- .semmet-select__error {
96
- color: var(--semmet-color-danger);
45
+ margin: 0;
97
46
  }