ember-primitives 0.48.2 → 0.50.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 (218) hide show
  1. package/bin/index.mjs +271 -0
  2. package/declarations/components/portal.d.ts.map +1 -1
  3. package/declarations/components/rating/public-types.d.ts +0 -4
  4. package/declarations/components/rating/public-types.d.ts.map +1 -1
  5. package/declarations/components/rating/rating.d.ts +9 -1
  6. package/declarations/components/rating/rating.d.ts.map +1 -1
  7. package/declarations/components/rating/stars.d.ts.map +1 -1
  8. package/declarations/components/rating/state.d.ts +4 -0
  9. package/declarations/components/rating/state.d.ts.map +1 -1
  10. package/declarations/components/rating/utils.d.ts +0 -1
  11. package/declarations/components/rating/utils.d.ts.map +1 -1
  12. package/declarations/tabster.d.ts.map +1 -1
  13. package/declarations/utils.d.ts.map +1 -1
  14. package/declarations/viewport/in-viewport.d.ts +70 -0
  15. package/declarations/viewport/in-viewport.d.ts.map +1 -0
  16. package/declarations/viewport/viewport.d.ts +59 -0
  17. package/declarations/viewport/viewport.d.ts.map +1 -0
  18. package/declarations/viewport.d.ts +3 -0
  19. package/declarations/viewport.d.ts.map +1 -0
  20. package/dist/-private.js +0 -1
  21. package/dist/-private.js.map +1 -1
  22. package/dist/color-scheme.js +0 -1
  23. package/dist/color-scheme.js.map +1 -1
  24. package/dist/{component-Bs3N-G9z.js → component-BXy_iafw.js} +2 -3
  25. package/dist/component-BXy_iafw.js.map +1 -0
  26. package/dist/components/accordion.js +5 -6
  27. package/dist/components/accordion.js.map +1 -1
  28. package/dist/components/avatar.js +3 -4
  29. package/dist/components/avatar.js.map +1 -1
  30. package/dist/components/dialog.js +2 -3
  31. package/dist/components/dialog.js.map +1 -1
  32. package/dist/components/external-link.js +1 -2
  33. package/dist/components/external-link.js.map +1 -1
  34. package/dist/components/form.js +1 -2
  35. package/dist/components/form.js.map +1 -1
  36. package/dist/components/heading.js +1 -2
  37. package/dist/components/heading.js.map +1 -1
  38. package/dist/components/keys.js +2 -3
  39. package/dist/components/keys.js.map +1 -1
  40. package/dist/components/layout/hero.js +1 -1
  41. package/dist/components/layout/sticky-footer.js +1 -1
  42. package/dist/components/link.js +1 -2
  43. package/dist/components/link.js.map +1 -1
  44. package/dist/components/menu.js +6 -8
  45. package/dist/components/menu.js.map +1 -1
  46. package/dist/components/one-time-password.js +1 -2
  47. package/dist/components/popover.js +3 -4
  48. package/dist/components/popover.js.map +1 -1
  49. package/dist/components/portal-targets.js +2 -3
  50. package/dist/components/portal-targets.js.map +1 -1
  51. package/dist/components/portal.js +3 -7
  52. package/dist/components/portal.js.map +1 -1
  53. package/dist/components/progress.js +2 -3
  54. package/dist/components/progress.js.map +1 -1
  55. package/dist/components/rating.js +1 -2
  56. package/dist/components/scroller.js +1 -2
  57. package/dist/components/scroller.js.map +1 -1
  58. package/dist/components/shadowed.js +2 -3
  59. package/dist/components/shadowed.js.map +1 -1
  60. package/dist/components/switch.js +5 -6
  61. package/dist/components/switch.js.map +1 -1
  62. package/dist/components/tabs.js +6 -7
  63. package/dist/components/tabs.js.map +1 -1
  64. package/dist/components/toggle-group.js +3 -4
  65. package/dist/components/toggle-group.js.map +1 -1
  66. package/dist/components/toggle.js +2 -3
  67. package/dist/components/toggle.js.map +1 -1
  68. package/dist/components/visually-hidden.js +1 -2
  69. package/dist/components/visually-hidden.js.map +1 -1
  70. package/dist/components/zoetrope.js +1 -2
  71. package/dist/dom-context.js +2 -3
  72. package/dist/dom-context.js.map +1 -1
  73. package/dist/floating-ui.js +1 -2
  74. package/dist/head.js +1 -2
  75. package/dist/head.js.map +1 -1
  76. package/dist/helpers/body-class.js +0 -1
  77. package/dist/helpers/body-class.js.map +1 -1
  78. package/dist/helpers/link.js +0 -1
  79. package/dist/helpers/link.js.map +1 -1
  80. package/dist/helpers/service.js +0 -1
  81. package/dist/helpers/service.js.map +1 -1
  82. package/dist/helpers.js +0 -1
  83. package/dist/helpers.js.map +1 -1
  84. package/dist/iframe.js +0 -1
  85. package/dist/iframe.js.map +1 -1
  86. package/dist/{index-DKE67I8L.js → index-gRO4Cvlf.js} +2 -2
  87. package/dist/index-gRO4Cvlf.js.map +1 -0
  88. package/dist/index.js +3 -4
  89. package/dist/index.js.map +1 -1
  90. package/dist/load.js +0 -1
  91. package/dist/load.js.map +1 -1
  92. package/dist/narrowing.js +0 -1
  93. package/dist/narrowing.js.map +1 -1
  94. package/dist/on-resize.js +0 -1
  95. package/dist/on-resize.js.map +1 -1
  96. package/dist/{otp-C6hCCXKx.js → otp-7rz1PWP0.js} +6 -7
  97. package/dist/otp-7rz1PWP0.js.map +1 -0
  98. package/dist/proper-links.js +0 -1
  99. package/dist/proper-links.js.map +1 -1
  100. package/dist/qp.js +0 -1
  101. package/dist/qp.js.map +1 -1
  102. package/dist/rating-BrIiwDLw.js +152 -0
  103. package/dist/rating-BrIiwDLw.js.map +1 -0
  104. package/dist/resize-observer.js +0 -1
  105. package/dist/resize-observer.js.map +1 -1
  106. package/dist/service.js +0 -1
  107. package/dist/service.js.map +1 -1
  108. package/dist/store.js +0 -1
  109. package/dist/store.js.map +1 -1
  110. package/dist/styles.css.js +0 -1
  111. package/dist/tabster.js +0 -1
  112. package/dist/tabster.js.map +1 -1
  113. package/dist/test-support.js +0 -1
  114. package/dist/test-support.js.map +1 -1
  115. package/dist/{utils-C5796IKA.js → utils-D0v9WKmV.js} +1 -2
  116. package/dist/utils-D0v9WKmV.js.map +1 -0
  117. package/dist/utils.js +4 -1
  118. package/dist/utils.js.map +1 -1
  119. package/dist/viewport/in-viewport.js +82 -0
  120. package/dist/viewport/in-viewport.js.map +1 -0
  121. package/dist/viewport/viewport.js +92 -0
  122. package/dist/viewport/viewport.js.map +1 -0
  123. package/dist/viewport.js +3 -0
  124. package/dist/viewport.js.map +1 -0
  125. package/package.json +24 -20
  126. package/src/-private.ts +4 -0
  127. package/src/color-scheme.ts +165 -0
  128. package/src/components/-private/typed-elements.gts +13 -0
  129. package/src/components/-private/utils.ts +16 -0
  130. package/src/components/accordion/content.gts +34 -0
  131. package/src/components/accordion/header.gts +36 -0
  132. package/src/components/accordion/item.gts +55 -0
  133. package/src/components/accordion/public.ts +64 -0
  134. package/src/components/accordion/trigger.gts +32 -0
  135. package/src/components/accordion.gts +195 -0
  136. package/src/components/avatar.gts +108 -0
  137. package/src/components/dialog.gts +234 -0
  138. package/src/components/external-link.gts +14 -0
  139. package/src/components/form.gts +75 -0
  140. package/src/components/heading.gts +36 -0
  141. package/src/components/keys.gts +53 -0
  142. package/src/components/layout/hero.css +5 -0
  143. package/src/components/layout/hero.gts +17 -0
  144. package/src/components/layout/sticky-footer.css +9 -0
  145. package/src/components/layout/sticky-footer.gts +40 -0
  146. package/src/components/link.gts +172 -0
  147. package/src/components/menu.gts +373 -0
  148. package/src/components/one-time-password/buttons.gts +31 -0
  149. package/src/components/one-time-password/input.gts +198 -0
  150. package/src/components/one-time-password/otp.gts +130 -0
  151. package/src/components/one-time-password/utils.ts +201 -0
  152. package/src/components/one-time-password.gts +2 -0
  153. package/src/components/popover.gts +248 -0
  154. package/src/components/portal-targets.gts +136 -0
  155. package/src/components/portal.gts +194 -0
  156. package/src/components/progress.gts +154 -0
  157. package/src/components/rating/public-types.ts +44 -0
  158. package/src/components/rating/range.gts +22 -0
  159. package/src/components/rating/rating.gts +228 -0
  160. package/src/components/rating/stars.gts +60 -0
  161. package/src/components/rating/state.gts +144 -0
  162. package/src/components/rating/utils.ts +7 -0
  163. package/src/components/rating.gts +5 -0
  164. package/src/components/scroller.gts +179 -0
  165. package/src/components/shadowed.gts +110 -0
  166. package/src/components/switch.gts +103 -0
  167. package/src/components/tabs.gts +519 -0
  168. package/src/components/toggle-group.gts +265 -0
  169. package/src/components/toggle.gts +81 -0
  170. package/src/components/violations.css +105 -0
  171. package/src/components/violations.css.ts +1 -0
  172. package/src/components/visually-hidden.css +14 -0
  173. package/src/components/visually-hidden.gts +15 -0
  174. package/src/components/zoetrope/index.gts +358 -0
  175. package/src/components/zoetrope/styles.css +40 -0
  176. package/src/components/zoetrope/types.ts +65 -0
  177. package/src/components/zoetrope.ts +3 -0
  178. package/src/dom-context.gts +245 -0
  179. package/src/floating-ui/component.gts +186 -0
  180. package/src/floating-ui/middleware.ts +13 -0
  181. package/src/floating-ui/modifier.ts +183 -0
  182. package/src/floating-ui.ts +2 -0
  183. package/src/head.gts +37 -0
  184. package/src/helpers/body-class.ts +94 -0
  185. package/src/helpers/link.ts +125 -0
  186. package/src/helpers/service.ts +25 -0
  187. package/src/helpers.ts +2 -0
  188. package/src/iframe.ts +31 -0
  189. package/src/index.ts +43 -0
  190. package/src/load.gts +77 -0
  191. package/src/narrowing.ts +7 -0
  192. package/src/on-resize.ts +64 -0
  193. package/src/proper-links.ts +140 -0
  194. package/src/qp.ts +107 -0
  195. package/src/resize-observer.ts +132 -0
  196. package/src/service.ts +103 -0
  197. package/src/store.ts +72 -0
  198. package/src/styles.css.ts +5 -0
  199. package/src/tabster.ts +54 -0
  200. package/src/template-registry.ts +44 -0
  201. package/src/test-support/a11y.ts +50 -0
  202. package/src/test-support/dom.ts +112 -0
  203. package/src/test-support/otp.ts +64 -0
  204. package/src/test-support/rating.ts +144 -0
  205. package/src/test-support/routing.ts +62 -0
  206. package/src/test-support/zoetrope.ts +51 -0
  207. package/src/test-support.gts +6 -0
  208. package/src/type-utils.ts +1 -0
  209. package/src/utils.ts +75 -0
  210. package/src/viewport/in-viewport.gts +128 -0
  211. package/src/viewport/viewport.ts +122 -0
  212. package/src/viewport.ts +2 -0
  213. package/dist/component-Bs3N-G9z.js.map +0 -1
  214. package/dist/index-DKE67I8L.js.map +0 -1
  215. package/dist/otp-C6hCCXKx.js.map +0 -1
  216. package/dist/rating-D052JWRa.js +0 -149
  217. package/dist/rating-D052JWRa.js.map +0 -1
  218. package/dist/utils-C5796IKA.js.map +0 -1
@@ -0,0 +1,34 @@
1
+ import Component from "@glimmer/component";
2
+
3
+ import { getDataState } from "./item.gts";
4
+
5
+ import type { AccordionContentExternalSignature } from "./public.ts";
6
+
7
+ interface Signature extends AccordionContentExternalSignature {
8
+ Args: {
9
+ isExpanded: boolean;
10
+ value: string;
11
+ disabled?: boolean;
12
+ };
13
+ }
14
+
15
+ export class AccordionContent extends Component<Signature> {
16
+ <template>
17
+ <div
18
+ role="region"
19
+ id={{@value}}
20
+ data-state={{getDataState @isExpanded}}
21
+ hidden={{this.isHidden}}
22
+ data-disabled={{@disabled}}
23
+ ...attributes
24
+ >
25
+ {{yield}}
26
+ </div>
27
+ </template>
28
+
29
+ get isHidden() {
30
+ return !this.args.isExpanded;
31
+ }
32
+ }
33
+
34
+ export default AccordionContent;
@@ -0,0 +1,36 @@
1
+ import { hash } from "@ember/helper";
2
+
3
+ import { getDataState } from "./item.gts";
4
+ import Trigger from "./trigger.gts";
5
+
6
+ import type { AccordionHeaderExternalSignature } from "./public.ts";
7
+ import type { TOC } from "@ember/component/template-only";
8
+
9
+ interface Signature extends AccordionHeaderExternalSignature {
10
+ Args: {
11
+ value: string;
12
+ isExpanded: boolean;
13
+ disabled?: boolean;
14
+ toggleItem: () => void;
15
+ };
16
+ }
17
+
18
+ export const AccordionHeader: TOC<Signature> = <template>
19
+ <div
20
+ role="heading"
21
+ aria-level="3"
22
+ data-state={{getDataState @isExpanded}}
23
+ data-disabled={{@disabled}}
24
+ ...attributes
25
+ >
26
+ {{yield
27
+ (hash
28
+ Trigger=(component
29
+ Trigger value=@value isExpanded=@isExpanded disabled=@disabled toggleItem=@toggleItem
30
+ )
31
+ )
32
+ }}
33
+ </div>
34
+ </template>;
35
+
36
+ export default AccordionHeader;
@@ -0,0 +1,55 @@
1
+ import Component from "@glimmer/component";
2
+ import { hash } from "@ember/helper";
3
+
4
+ import Content from "./content.gts";
5
+ import Header from "./header.gts";
6
+
7
+ import type { AccordionItemExternalSignature } from "./public.ts";
8
+
9
+ export function getDataState(isExpanded: boolean): string {
10
+ return isExpanded ? "open" : "closed";
11
+ }
12
+
13
+ interface Signature extends AccordionItemExternalSignature {
14
+ Args: AccordionItemExternalSignature["Args"] & {
15
+ selectedValue?: string | string[];
16
+ disabled?: boolean;
17
+ toggleItem: (value: string) => void;
18
+ };
19
+ }
20
+
21
+ export class AccordionItem extends Component<Signature> {
22
+ <template>
23
+ <div data-state={{getDataState this.isExpanded}} data-disabled={{@disabled}} ...attributes>
24
+ {{yield
25
+ (hash
26
+ isExpanded=this.isExpanded
27
+ Header=(component
28
+ Header
29
+ value=@value
30
+ isExpanded=this.isExpanded
31
+ disabled=@disabled
32
+ toggleItem=this.toggleItem
33
+ )
34
+ Content=(component Content value=@value isExpanded=this.isExpanded disabled=@disabled)
35
+ )
36
+ }}
37
+ </div>
38
+ </template>
39
+
40
+ get isExpanded(): boolean {
41
+ if (Array.isArray(this.args.selectedValue)) {
42
+ return this.args.selectedValue.includes(this.args.value);
43
+ }
44
+
45
+ return this.args.selectedValue === this.args.value;
46
+ }
47
+
48
+ toggleItem = (): void => {
49
+ if (this.args.disabled) return;
50
+
51
+ this.args.toggleItem(this.args.value);
52
+ };
53
+ }
54
+
55
+ export default AccordionItem;
@@ -0,0 +1,64 @@
1
+ import type Content from './content.gts';
2
+ import type Header from './header.gts';
3
+ import type Trigger from './trigger.gts';
4
+ import type { WithBoundArgs } from '@glint/template';
5
+
6
+ export interface AccordionTriggerExternalSignature {
7
+ Element: HTMLButtonElement;
8
+ Blocks: {
9
+ default: [];
10
+ };
11
+ }
12
+
13
+ export interface AccordionContentExternalSignature {
14
+ Element: HTMLDivElement;
15
+ Blocks: {
16
+ default: [];
17
+ };
18
+ }
19
+
20
+ export interface AccordionHeaderExternalSignature {
21
+ /**
22
+ * Add aria-level according to the heading level where the accordion is used (default: 3).
23
+ * See https://www.w3.org/WAI/ARIA/apg/patterns/accordion/ for more information.
24
+ */
25
+ Element: HTMLDivElement;
26
+ Blocks: {
27
+ default: [
28
+ {
29
+ /**
30
+ * The AccordionTrigger component.
31
+ */
32
+ Trigger: WithBoundArgs<typeof Trigger, 'value' | 'isExpanded' | 'disabled' | 'toggleItem'>;
33
+ },
34
+ ];
35
+ };
36
+ }
37
+
38
+ export interface AccordionItemExternalSignature {
39
+ Element: HTMLDivElement;
40
+ Blocks: {
41
+ default: [
42
+ {
43
+ /**
44
+ * Whether the accordion item is expanded.
45
+ */
46
+ isExpanded: boolean;
47
+ /**
48
+ * The AccordionHeader component.
49
+ */
50
+ Header: WithBoundArgs<typeof Header, 'value' | 'isExpanded' | 'disabled' | 'toggleItem'>;
51
+ /**
52
+ * The AccordionContent component.
53
+ */
54
+ Content: WithBoundArgs<typeof Content, 'value' | 'isExpanded' | 'disabled'>;
55
+ },
56
+ ];
57
+ };
58
+ Args: {
59
+ /**
60
+ * The value of the accordion item.
61
+ */
62
+ value: string;
63
+ };
64
+ }
@@ -0,0 +1,32 @@
1
+ import { on } from "@ember/modifier";
2
+
3
+ import { getDataState } from "./item.gts";
4
+
5
+ import type { AccordionTriggerExternalSignature } from "./public.ts";
6
+ import type { TOC } from "@ember/component/template-only";
7
+
8
+ interface Signature extends AccordionTriggerExternalSignature {
9
+ Args: {
10
+ isExpanded: boolean;
11
+ value: string;
12
+ disabled?: boolean;
13
+ toggleItem: () => void;
14
+ };
15
+ }
16
+
17
+ export const AccordionTrigger: TOC<Signature> = <template>
18
+ <button
19
+ type="button"
20
+ aria-controls={{@value}}
21
+ aria-expanded={{@isExpanded}}
22
+ data-state={{getDataState @isExpanded}}
23
+ data-disabled={{@disabled}}
24
+ aria-disabled={{if @disabled "true" "false"}}
25
+ {{on "click" @toggleItem}}
26
+ ...attributes
27
+ >
28
+ {{yield}}
29
+ </button>
30
+ </template>;
31
+
32
+ export default AccordionTrigger;
@@ -0,0 +1,195 @@
1
+ import Component from "@glimmer/component";
2
+ import { assert } from "@ember/debug";
3
+ import { hash } from "@ember/helper";
4
+
5
+ // temp
6
+ // https://github.com/tracked-tools/tracked-toolbox/issues/38
7
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
8
+ // @ts-ignore
9
+ import { localCopy } from "tracked-toolbox";
10
+
11
+ import AccordionItem from "./accordion/item.gts";
12
+
13
+ import type { WithBoundArgs } from "@glint/template";
14
+
15
+ type AccordionSingleArgs = {
16
+ /**
17
+ * The type of accordion. If `single`, only one item can be selected at a time. If `multiple`, multiple items can be selected at a time.
18
+ */
19
+ type: "single";
20
+ /**
21
+ * Whether the accordion is disabled. When `true`, all items cannot be expanded or collapsed.
22
+ */
23
+ disabled?: boolean;
24
+ /**
25
+ * When type is `single`, whether the accordion is collapsible. When `true`, the selected item can be collapsed by clicking its trigger.
26
+ */
27
+ collapsible?: boolean;
28
+ } & (
29
+ | {
30
+ /**
31
+ * The currently selected value. To be used in a controlled fashion in conjunction with `onValueChange`.
32
+ */
33
+ value: string;
34
+ /**
35
+ * A callback that is called when the selected value changes. To be used in a controlled fashion in conjunction with `value`.
36
+ */
37
+ onValueChange: (value: string | undefined) => void;
38
+ /**
39
+ * Not available in a controlled fashion.
40
+ */
41
+ defaultValue?: never;
42
+ }
43
+ | {
44
+ /**
45
+ * Not available in an uncontrolled fashion.
46
+ */
47
+ value?: never;
48
+ /**
49
+ * Not available in an uncontrolled fashion.
50
+ */
51
+ onValueChange?: never;
52
+ /**
53
+ * The default value of the accordion. To be used in an uncontrolled fashion.
54
+ */
55
+ defaultValue?: string;
56
+ }
57
+ );
58
+
59
+ type AccordionMultipleArgs = {
60
+ /**
61
+ * The type of accordion. If `single`, only one item can be selected at a time. If `multiple`, multiple items can be selected at a time.
62
+ */
63
+ type: "multiple";
64
+ /**
65
+ * Whether the accordion is disabled. When `true`, all items cannot be expanded or collapsed.
66
+ */
67
+ disabled?: boolean;
68
+ } & (
69
+ | {
70
+ /**
71
+ * The currently selected values. To be used in a controlled fashion in conjunction with `onValueChange`.
72
+ */
73
+ value: string[];
74
+ /**
75
+ * A callback that is called when the selected values change. To be used in a controlled fashion in conjunction with `value`.
76
+ */
77
+ onValueChange: (value?: string[]) => void;
78
+ /**
79
+ * Not available in a controlled fashion.
80
+ */
81
+ defaultValue?: never;
82
+ }
83
+ | {
84
+ /**
85
+ * Not available in an uncontrolled fashion.
86
+ */
87
+ value?: never;
88
+ /**
89
+ * Not available in an uncontrolled fashion.
90
+ */
91
+ onValueChange?: never;
92
+ /**
93
+ * The default values of the accordion. To be used in an uncontrolled fashion.
94
+ */
95
+ defaultValue?: string[];
96
+ }
97
+ );
98
+
99
+ export class Accordion extends Component<{
100
+ Element: HTMLDivElement;
101
+ Args: AccordionSingleArgs | AccordionMultipleArgs;
102
+ Blocks: {
103
+ default: [
104
+ {
105
+ /**
106
+ * The AccordionItem component.
107
+ */
108
+ Item: WithBoundArgs<typeof AccordionItem, "selectedValue" | "toggleItem" | "disabled">;
109
+ },
110
+ ];
111
+ };
112
+ }> {
113
+ <template>
114
+ <div data-disabled={{@disabled}} ...attributes>
115
+ {{yield
116
+ (hash
117
+ Item=(component
118
+ AccordionItem
119
+ selectedValue=this.selectedValue
120
+ toggleItem=this.toggleItem
121
+ disabled=@disabled
122
+ )
123
+ )
124
+ }}
125
+ </div>
126
+ </template>
127
+
128
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
129
+ @localCopy("args.defaultValue") declare _internallyManagedValue?: string | string[];
130
+
131
+ get selectedValue() {
132
+ return this.args.value ?? this._internallyManagedValue;
133
+ }
134
+
135
+ toggleItem = (value: string) => {
136
+ if (this.args.disabled) {
137
+ return;
138
+ }
139
+
140
+ if (this.args.type === "single") {
141
+ this.toggleItemSingle(value);
142
+ } else if (this.args.type === "multiple") {
143
+ this.toggleItemMultiple(value);
144
+ }
145
+ };
146
+
147
+ toggleItemSingle = (value: string) => {
148
+ assert("Cannot call `toggleItemSingle` when `disabled` is true.", !this.args.disabled);
149
+ assert(
150
+ "Cannot call `toggleItemSingle` when `type` is not `single`.",
151
+ this.args.type === "single",
152
+ );
153
+
154
+ if (value === this.selectedValue && !this.args.collapsible) {
155
+ return;
156
+ }
157
+
158
+ const newValue = value === this.selectedValue ? undefined : value;
159
+
160
+ if (this.args.onValueChange) {
161
+ this.args.onValueChange(newValue);
162
+ } else {
163
+ this._internallyManagedValue = newValue;
164
+ }
165
+ };
166
+
167
+ toggleItemMultiple = (value: string) => {
168
+ assert("Cannot call `toggleItemMultiple` when `disabled` is true.", !this.args.disabled);
169
+ assert(
170
+ "Cannot call `toggleItemMultiple` when `type` is not `multiple`.",
171
+ this.args.type === "multiple",
172
+ );
173
+
174
+ const currentValues = (this.selectedValue as string[] | undefined) ?? [];
175
+ const indexOfValue = currentValues.indexOf(value);
176
+ let newValue: string[];
177
+
178
+ if (indexOfValue === -1) {
179
+ newValue = [...currentValues, value];
180
+ } else {
181
+ newValue = [
182
+ ...currentValues.slice(0, indexOfValue),
183
+ ...currentValues.slice(indexOfValue + 1),
184
+ ];
185
+ }
186
+
187
+ if (this.args.onValueChange) {
188
+ this.args.onValueChange(newValue);
189
+ } else {
190
+ this._internallyManagedValue = newValue;
191
+ }
192
+ };
193
+ }
194
+
195
+ export default Accordion;
@@ -0,0 +1,108 @@
1
+ import { hash } from "@ember/helper";
2
+
3
+ import { ReactiveImage } from "reactiveweb/image";
4
+ import { WaitUntil } from "reactiveweb/wait-until";
5
+
6
+ import type { TOC } from "@ember/component/template-only";
7
+ import type { WithBoundArgs } from "@glint/template";
8
+
9
+ const Fallback: TOC<{
10
+ Blocks: { default: [] };
11
+ Args: {
12
+ /**
13
+ * The number of milliseconds to wait for the image to load
14
+ * before displaying the fallback
15
+ */
16
+ delayMs?: number;
17
+ /**
18
+ * @private
19
+ * Bound internally by ember-primitives
20
+ */
21
+ isLoaded: boolean;
22
+ };
23
+ }> = <template>
24
+ {{#unless @isLoaded}}
25
+ {{#let (WaitUntil @delayMs) as |delayFinished|}}
26
+ {{#if delayFinished}}
27
+ {{yield}}
28
+ {{/if}}
29
+ {{/let}}
30
+ {{/unless}}
31
+ </template>;
32
+
33
+ const Image: TOC<{
34
+ Element: HTMLImageElement;
35
+ Args: {
36
+ /**
37
+ * @private
38
+ * The `src` value for the image.
39
+ *
40
+ * Bound internally by ember-primitives
41
+ */
42
+ src: string;
43
+ /**
44
+ * @private
45
+ * Bound internally by ember-primitives
46
+ */
47
+ isLoaded: boolean;
48
+ };
49
+ }> = <template>
50
+ {{#if @isLoaded}}
51
+ <img alt="__missing__" ...attributes src={{@src}} />
52
+ {{/if}}
53
+ </template>;
54
+
55
+ export const Avatar: TOC<{
56
+ Element: HTMLSpanElement;
57
+ Args: {
58
+ /**
59
+ * The `src` value for the image.
60
+ */
61
+ src: string;
62
+ };
63
+ Blocks: {
64
+ default: [
65
+ avatar: {
66
+ /**
67
+ * The image to render. It will only render when it has loaded.
68
+ */
69
+ Image: WithBoundArgs<typeof Image, "src" | "isLoaded">;
70
+ /**
71
+ * An element that renders when the image hasn't loaded.
72
+ * This means whilst it's loading, or if there was an error.
73
+ * If you notice a flash during loading,
74
+ * you can provide a delayMs prop to delay its rendering so it only renders for those with slower connections.
75
+ */
76
+ Fallback: WithBoundArgs<typeof Fallback, "isLoaded">;
77
+ /**
78
+ * true while the image is loading
79
+ */
80
+ isLoading: boolean;
81
+ /**
82
+ * If the image fails to load, this will be `true`
83
+ */
84
+ isError: boolean;
85
+ },
86
+ ];
87
+ };
88
+ }> = <template>
89
+ {{#let (ReactiveImage @src) as |imgState|}}
90
+ <span
91
+ data-prim-avatar
92
+ ...attributes
93
+ data-loading={{imgState.isLoading}}
94
+ data-error={{imgState.isError}}
95
+ >
96
+ {{yield
97
+ (hash
98
+ Image=(component Image src=@src isLoaded=imgState.isResolved)
99
+ Fallback=(component Fallback isLoaded=imgState.isResolved)
100
+ isLoading=imgState.isLoading
101
+ isError=imgState.isError
102
+ )
103
+ }}
104
+ </span>
105
+ {{/let}}
106
+ </template>;
107
+
108
+ export default Avatar;