ember-primitives 0.49.0 → 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 (103) hide show
  1. package/bin/index.mjs +271 -0
  2. package/declarations/components/rating/public-types.d.ts +0 -4
  3. package/declarations/components/rating/public-types.d.ts.map +1 -1
  4. package/declarations/components/rating/rating.d.ts +9 -1
  5. package/declarations/components/rating/rating.d.ts.map +1 -1
  6. package/declarations/components/rating/stars.d.ts.map +1 -1
  7. package/declarations/components/rating/state.d.ts +4 -0
  8. package/declarations/components/rating/state.d.ts.map +1 -1
  9. package/declarations/components/rating/utils.d.ts +0 -1
  10. package/declarations/components/rating/utils.d.ts.map +1 -1
  11. package/dist/components/rating.js +1 -1
  12. package/dist/index.js +1 -1
  13. package/dist/{rating-CjBVsX6q.js → rating-BrIiwDLw.js} +21 -17
  14. package/dist/rating-BrIiwDLw.js.map +1 -0
  15. package/package.json +6 -2
  16. package/src/-private.ts +4 -0
  17. package/src/color-scheme.ts +165 -0
  18. package/src/components/-private/typed-elements.gts +13 -0
  19. package/src/components/-private/utils.ts +16 -0
  20. package/src/components/accordion/content.gts +34 -0
  21. package/src/components/accordion/header.gts +36 -0
  22. package/src/components/accordion/item.gts +55 -0
  23. package/src/components/accordion/public.ts +64 -0
  24. package/src/components/accordion/trigger.gts +32 -0
  25. package/src/components/accordion.gts +195 -0
  26. package/src/components/avatar.gts +108 -0
  27. package/src/components/dialog.gts +234 -0
  28. package/src/components/external-link.gts +14 -0
  29. package/src/components/form.gts +75 -0
  30. package/src/components/heading.gts +36 -0
  31. package/src/components/keys.gts +53 -0
  32. package/src/components/layout/hero.css +5 -0
  33. package/src/components/layout/hero.gts +17 -0
  34. package/src/components/layout/sticky-footer.css +9 -0
  35. package/src/components/layout/sticky-footer.gts +40 -0
  36. package/src/components/link.gts +172 -0
  37. package/src/components/menu.gts +373 -0
  38. package/src/components/one-time-password/buttons.gts +31 -0
  39. package/src/components/one-time-password/input.gts +198 -0
  40. package/src/components/one-time-password/otp.gts +130 -0
  41. package/src/components/one-time-password/utils.ts +201 -0
  42. package/src/components/one-time-password.gts +2 -0
  43. package/src/components/popover.gts +248 -0
  44. package/src/components/portal-targets.gts +136 -0
  45. package/src/components/portal.gts +194 -0
  46. package/src/components/progress.gts +154 -0
  47. package/src/components/rating/public-types.ts +44 -0
  48. package/src/components/rating/range.gts +22 -0
  49. package/src/components/rating/rating.gts +228 -0
  50. package/src/components/rating/stars.gts +60 -0
  51. package/src/components/rating/state.gts +144 -0
  52. package/src/components/rating/utils.ts +7 -0
  53. package/src/components/rating.gts +5 -0
  54. package/src/components/scroller.gts +179 -0
  55. package/src/components/shadowed.gts +110 -0
  56. package/src/components/switch.gts +103 -0
  57. package/src/components/tabs.gts +519 -0
  58. package/src/components/toggle-group.gts +265 -0
  59. package/src/components/toggle.gts +81 -0
  60. package/src/components/violations.css +105 -0
  61. package/src/components/violations.css.ts +1 -0
  62. package/src/components/visually-hidden.css +14 -0
  63. package/src/components/visually-hidden.gts +15 -0
  64. package/src/components/zoetrope/index.gts +358 -0
  65. package/src/components/zoetrope/styles.css +40 -0
  66. package/src/components/zoetrope/types.ts +65 -0
  67. package/src/components/zoetrope.ts +3 -0
  68. package/src/dom-context.gts +245 -0
  69. package/src/floating-ui/component.gts +186 -0
  70. package/src/floating-ui/middleware.ts +13 -0
  71. package/src/floating-ui/modifier.ts +183 -0
  72. package/src/floating-ui.ts +2 -0
  73. package/src/head.gts +37 -0
  74. package/src/helpers/body-class.ts +94 -0
  75. package/src/helpers/link.ts +125 -0
  76. package/src/helpers/service.ts +25 -0
  77. package/src/helpers.ts +2 -0
  78. package/src/iframe.ts +31 -0
  79. package/src/index.ts +43 -0
  80. package/src/load.gts +77 -0
  81. package/src/narrowing.ts +7 -0
  82. package/src/on-resize.ts +64 -0
  83. package/src/proper-links.ts +140 -0
  84. package/src/qp.ts +107 -0
  85. package/src/resize-observer.ts +132 -0
  86. package/src/service.ts +103 -0
  87. package/src/store.ts +72 -0
  88. package/src/styles.css.ts +5 -0
  89. package/src/tabster.ts +54 -0
  90. package/src/template-registry.ts +44 -0
  91. package/src/test-support/a11y.ts +50 -0
  92. package/src/test-support/dom.ts +112 -0
  93. package/src/test-support/otp.ts +64 -0
  94. package/src/test-support/rating.ts +144 -0
  95. package/src/test-support/routing.ts +62 -0
  96. package/src/test-support/zoetrope.ts +51 -0
  97. package/src/test-support.gts +6 -0
  98. package/src/type-utils.ts +1 -0
  99. package/src/utils.ts +75 -0
  100. package/src/viewport/in-viewport.gts +128 -0
  101. package/src/viewport/viewport.ts +122 -0
  102. package/src/viewport.ts +2 -0
  103. package/dist/rating-CjBVsX6q.js.map +0 -1
@@ -0,0 +1,165 @@
1
+ import { waitForPromise } from '@ember/test-waiters';
2
+
3
+ import { cell } from 'ember-resources';
4
+
5
+ const _colorScheme = cell<string | undefined>();
6
+
7
+ let callbacks: Set<(colorScheme: string) => void> = new Set();
8
+
9
+ async function runCallbacks(theme: string) {
10
+ await Promise.resolve();
11
+
12
+ for (const callback of callbacks.values()) {
13
+ callback(theme);
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Object for managing the color scheme
19
+ */
20
+ export const colorScheme = {
21
+ /**
22
+ * Set's the current color scheme to the passed value
23
+ */
24
+ update: (value: string) => {
25
+ colorScheme.current = value;
26
+
27
+ void waitForPromise(runCallbacks(value));
28
+ },
29
+
30
+ on: {
31
+ /**
32
+ * register a function to be called when the color scheme changes.
33
+ */
34
+ update: (callback: (colorScheme: string) => void) => {
35
+ callbacks.add(callback);
36
+ },
37
+ },
38
+ off: {
39
+ /**
40
+ * unregister a function that would have been called when the color scheme changes.
41
+ */
42
+ update: (callback: (colorScheme: string) => void) => {
43
+ callbacks.delete(callback);
44
+ },
45
+ },
46
+
47
+ /**
48
+ * the current valuel of the "color scheme"
49
+ */
50
+ get current(): string | undefined {
51
+ return _colorScheme.current;
52
+ },
53
+ set current(value: string | undefined) {
54
+ _colorScheme.current = value;
55
+
56
+ if (!value) {
57
+ localPreference.delete();
58
+
59
+ return;
60
+ }
61
+
62
+ localPreference.update(value);
63
+ setColorScheme(value);
64
+ },
65
+ };
66
+
67
+ /**
68
+ * Synchronizes state of `colorScheme` with the users preferences as well as reconciles with previously set theme in local storage.
69
+ *
70
+ * This may only be called once per app.
71
+ */
72
+ export function sync() {
73
+ /**
74
+ * reset the callbacks
75
+ */
76
+ callbacks = new Set();
77
+
78
+ /**
79
+ * If local prefs are set, then we don't care what prefers-color-scheme is
80
+ */
81
+ const userPreference = localPreference.read();
82
+
83
+ if (userPreference) {
84
+ setColorScheme(userPreference);
85
+ _colorScheme.current = userPreference;
86
+
87
+ return;
88
+ }
89
+
90
+ if (prefers.dark()) {
91
+ setColorScheme('dark');
92
+ _colorScheme.current = 'dark';
93
+ } else if (prefers.light()) {
94
+ setColorScheme('light');
95
+ _colorScheme.current = 'light';
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Helper methods to determining what the user's preferred color scheme is
101
+ * based on the system preferences rather than the users explicit preference.
102
+ */
103
+ export const prefers = {
104
+ dark: () => window.matchMedia('(prefers-color-scheme: dark)').matches,
105
+ light: () => window.matchMedia('(prefers-color-scheme: light)').matches,
106
+ custom: (name: string) => window.matchMedia(`(prefers-color-scheme: ${name})`).matches,
107
+ none: () => window.matchMedia('(prefers-color-scheme: no-preference)').matches,
108
+ };
109
+
110
+ const LOCAL_PREF_KEY = 'ember-primitives/color-scheme#local-preference';
111
+
112
+ /**
113
+ * Helper methods for working with the color scheme preference in local storage
114
+ */
115
+ export const localPreference = {
116
+ isSet: () => Boolean(localPreference.read()),
117
+ read: () => localStorage.getItem(LOCAL_PREF_KEY),
118
+ update: (value: string) => localStorage.setItem(LOCAL_PREF_KEY, value),
119
+ delete: () => localStorage.removeItem(LOCAL_PREF_KEY),
120
+ };
121
+
122
+ /**
123
+ * For the given element, returns the `color-scheme` of that element.
124
+ */
125
+ export function getColorScheme(element?: HTMLElement) {
126
+ const style = styleOf(element);
127
+
128
+ return style.getPropertyValue('color-scheme');
129
+ }
130
+
131
+ export function setColorScheme(element: HTMLElement, value: string): void;
132
+ export function setColorScheme(value: string): void;
133
+
134
+ export function setColorScheme(...args: [string] | [HTMLElement, string]): void {
135
+ if (typeof args[0] === 'string') {
136
+ styleOf().setProperty('color-scheme', args[0]);
137
+
138
+ return;
139
+ }
140
+
141
+ if (typeof args[1] === 'string') {
142
+ styleOf(args[0]).setProperty('color-scheme', args[1]);
143
+
144
+ return;
145
+ }
146
+
147
+ throw new Error(`Invalid arity, expected up to 2 args, received ${args.length}`);
148
+ }
149
+
150
+ /**
151
+ * Removes the `color-scheme` from the given element
152
+ */
153
+ export function removeColorScheme(element?: HTMLElement) {
154
+ const style = styleOf(element);
155
+
156
+ style.removeProperty('color-scheme');
157
+ }
158
+
159
+ function styleOf(element?: HTMLElement) {
160
+ if (element) {
161
+ return element.style;
162
+ }
163
+
164
+ return document.documentElement.style;
165
+ }
@@ -0,0 +1,13 @@
1
+ import type { TOC } from "@ember/component/template-only";
2
+
3
+ export const Div: TOC<{ Element: HTMLDivElement; Blocks: { default: [] } }> = <template>
4
+ <div ...attributes>{{yield}}</div>
5
+ </template>;
6
+
7
+ export const Label: TOC<{
8
+ Element: HTMLLabelElement;
9
+ Args: { for: string };
10
+ Blocks: { default: [] };
11
+ }> = <template>
12
+ <label for={{@for}} ...attributes>{{yield}}</label>
13
+ </template>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * If the user provides an onChange or similar function, use that,
3
+ * otherwise fallback to the uncontrolled toggle
4
+ */
5
+ export function toggleWithFallback(
6
+ uncontrolledToggle: (...args: unknown[]) => void,
7
+
8
+ controlledToggle?: (...args: any[]) => void,
9
+ ...args: unknown[]
10
+ ) {
11
+ if (controlledToggle) {
12
+ return controlledToggle(...args);
13
+ }
14
+
15
+ uncontrolledToggle(...args);
16
+ }
@@ -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;