fluid-primitives 0.17.2 → 0.18.0-next.8.a9be2d6

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 (47) hide show
  1. package/README.md +2 -6
  2. package/dist/Client-C51NSHxg.js +248 -0
  3. package/dist/accordion.d.ts +3 -3
  4. package/dist/accordion.js +45 -1
  5. package/dist/checkbox-group.d.ts +99 -0
  6. package/dist/checkbox-group.js +117 -0
  7. package/dist/checkbox-group.registry-CGwuF7SF.js +112 -0
  8. package/dist/checkbox.d.ts +26 -3
  9. package/dist/checkbox.js +148 -1
  10. package/dist/client.d.ts +2 -2
  11. package/dist/client.js +3 -1
  12. package/dist/clipboard.d.ts +3 -3
  13. package/dist/clipboard.js +32 -1
  14. package/dist/collapsible.d.ts +3 -3
  15. package/dist/collapsible.js +28 -1
  16. package/dist/dialog.d.ts +3 -3
  17. package/dist/dialog.js +34 -1
  18. package/dist/field.d.ts +2 -2
  19. package/dist/field.dom-CJQXpQbZ.js +11 -0
  20. package/dist/field.js +211 -1
  21. package/dist/form.d.ts +3 -3
  22. package/dist/form.js +432 -1
  23. package/dist/{form.registry-DdLr3dbX.d.ts → form.registry-Cb8Pvoe8.d.ts} +2 -2
  24. package/dist/form.registry-CmpTny_s.js +51 -0
  25. package/dist/{index-BpcuNDMI.d.ts → index-B8JCdyld.d.ts} +13 -1
  26. package/dist/navigation-menu.d.ts +15 -0
  27. package/dist/navigation-menu.js +71 -0
  28. package/dist/number-input.d.ts +3 -3
  29. package/dist/number-input.js +55 -1
  30. package/dist/popover.d.ts +3 -3
  31. package/dist/popover.js +42 -1
  32. package/dist/radio-group.d.ts +3 -3
  33. package/dist/radio-group.js +67 -1
  34. package/dist/scroll-area.d.ts +1 -1
  35. package/dist/scroll-area.js +32 -1
  36. package/dist/select.d.ts +5 -5
  37. package/dist/select.js +84 -1
  38. package/dist/switch.d.ts +16 -0
  39. package/dist/switch.js +61 -0
  40. package/dist/tabs.d.ts +3 -3
  41. package/dist/tabs.js +33 -1
  42. package/dist/tooltip.d.ts +3 -3
  43. package/dist/tooltip.js +36 -1
  44. package/package.json +44 -22
  45. package/dist/Client-CygooKu8.js +0 -1
  46. package/dist/field.dom-etI2JxSW.js +0 -1
  47. package/dist/form.registry-Bv4jZGjo.js +0 -1
package/README.md CHANGED
@@ -6,6 +6,8 @@ Unstyled, flexible and accessible UI Primitives that provide a foundation for bu
6
6
 
7
7
  Fluid Primitives brings modern component patterns to TYPO3. Build accessible, composable UI components with the same developer experience you'd expect from React libraries like Radix or Base UI - but for Fluid templates.
8
8
 
9
+ ## Documentation
10
+
9
11
  Full documentation can be found at [fluid-primitives.com](https://fluid-primitives.com).
10
12
 
11
13
  ## What You Get
@@ -39,17 +41,11 @@ Fluid Primitives solves this by bringing proven patterns from the modern fronten
39
41
 
40
42
  ## Acknowledgments
41
43
 
42
- Built on the shoulders of giants:
43
-
44
44
  - [Zag.js](https://zagjs.com/) - The state machine foundation
45
45
  - [Radix UI](https://www.radix-ui.com/primitives) - API design inspiration
46
46
  - [Base UI](https://base-ui.com/) - Component behavior patterns
47
47
  - [Ark UI](https://ark-ui.com/) - Zag.js integration patterns
48
48
 
49
- ## Documentation
50
-
51
- The full documentation can be found at [fluid-primitives.com](https://fluid-primitives.com).
52
-
53
49
  ## Development
54
50
 
55
51
  See [github.com/jramke/fluid-primitives.com](https://github.com/jramke/fluid-primitives.com) monorepo for the development setup.
@@ -0,0 +1,248 @@
1
+ import { ListCollection } from "@zag-js/collection";
2
+ import { VanillaMachine, VanillaMachine as Machine, mergeProps, normalizeProps, spreadProps } from "@zag-js/vanilla";
3
+ import { uuid } from "@zag-js/utils";
4
+
5
+ //#region Resources/Private/Client/src/lib/component.ts
6
+ var Component = class {
7
+ document;
8
+ machine;
9
+ api;
10
+ hydrator = null;
11
+ userProps;
12
+ static name;
13
+ get doc() {
14
+ return this.document;
15
+ }
16
+ constructor(props, userDocument = document) {
17
+ this.document = userDocument;
18
+ this.userProps = this.transformProps(props);
19
+ this.hydrator = this.initHydrator(props);
20
+ this.machine = this.initMachine(props);
21
+ this.api = this.initApi();
22
+ }
23
+ initHydrator(props) {
24
+ const id = props.id;
25
+ if (!id) throw new Error("ComponentHydrator requires an id prop to initialize.");
26
+ return new ComponentHydrator(this.getName(), id, props.ids, this.doc);
27
+ }
28
+ init() {
29
+ this.render();
30
+ this.machine.subscribe(() => {
31
+ this.api = this.initApi();
32
+ this.render();
33
+ });
34
+ this.machine.start();
35
+ }
36
+ getName() {
37
+ return this.constructor.name;
38
+ }
39
+ /**
40
+ * Override in consumer for example when a getter is used for collection
41
+ * Needs to be used manually inside the initMachine method
42
+ */
43
+ transformProps(props) {
44
+ return props;
45
+ }
46
+ updateProps(newProps) {
47
+ this.machine.updateProps(newProps);
48
+ }
49
+ destroy() {
50
+ this.machine.stop();
51
+ this.hydrator?.destroy();
52
+ }
53
+ spreadProps(node, attrs) {
54
+ spreadProps(node, attrs, this.machine.scope.id);
55
+ }
56
+ getElement(part, parent) {
57
+ return this.hydrator?.getElement(part, parent) || null;
58
+ }
59
+ getElements(part, parent) {
60
+ return this.hydrator?.getElements(part, parent) || [];
61
+ }
62
+ };
63
+
64
+ //#endregion
65
+ //#region Resources/Private/Primitives/Field/src/field.registry.ts
66
+ const registry = /* @__PURE__ */ new WeakMap();
67
+ function registerFieldMachine(field, service) {
68
+ if (!field) return;
69
+ registry.set(field, service);
70
+ field.dispatchEvent(new CustomEvent("fluid-primitives:field:registered", { bubbles: true }));
71
+ }
72
+ function getFieldMachineFor(el) {
73
+ if (!el) return;
74
+ return registry.get(el);
75
+ }
76
+
77
+ //#endregion
78
+ //#region Resources/Private/Client/src/lib/field-aware-component.ts
79
+ const fieldProps = [
80
+ "invalid",
81
+ "disabled",
82
+ "readOnly",
83
+ "required"
84
+ ];
85
+ const fieldAccessors = {
86
+ disabled: (s) => s.context.get("disabled"),
87
+ readOnly: (s) => s.context.get("readOnly"),
88
+ required: (s) => s.context.get("required"),
89
+ invalid: (s) => s.context.get("invalid")
90
+ };
91
+ var FieldAwareComponent = class extends Component {
92
+ subscribedToField = false;
93
+ fieldMachine;
94
+ closestField = null;
95
+ getClosestField() {
96
+ return this.closestField || this.getElement("root")?.closest("[data-scope=\"field\"][data-part=\"root\"]") || null;
97
+ }
98
+ withFieldProps(props) {
99
+ this.closestField = this.getClosestField();
100
+ if (!this.closestField) return props;
101
+ this.fieldMachine = getFieldMachineFor(this.closestField);
102
+ if (this.fieldMachine) return this.propsWithField(props, this.fieldMachine);
103
+ else {
104
+ const handler = () => {
105
+ this.fieldMachine = getFieldMachineFor(this.closestField);
106
+ this.updateProps(this.propsWithField(this.userProps, this.fieldMachine));
107
+ this.closestField?.removeEventListener("fluid-primitives:field:registered", handler);
108
+ };
109
+ this.closestField.addEventListener("fluid-primitives:field:registered", handler);
110
+ }
111
+ return props;
112
+ }
113
+ subscribeToFieldService() {
114
+ if (this.subscribedToField) return;
115
+ this.closestField = this.getClosestField();
116
+ if (!this.closestField) return;
117
+ if (!this.fieldMachine) this.fieldMachine = getFieldMachineFor(this.closestField);
118
+ if (this.fieldMachine) {
119
+ this.fieldMachine.subscribe((snapshot) => {
120
+ queueMicrotask(() => {
121
+ let propsToUpdate = {};
122
+ for (const prop of fieldProps) {
123
+ const newValue = !!fieldAccessors[prop](snapshot);
124
+ if (newValue !== !!this.machine.prop(prop)) propsToUpdate[prop] = newValue;
125
+ }
126
+ if (Object.keys(propsToUpdate).length > 0) this.updateProps(propsToUpdate);
127
+ else this.machine.notify();
128
+ });
129
+ });
130
+ this.subscribedToField = true;
131
+ } else {
132
+ const handler = () => {
133
+ this.subscribeToFieldService();
134
+ this.closestField.removeEventListener("fluid-primitives:field:registered", handler);
135
+ };
136
+ this.closestField.addEventListener("fluid-primitives:field:registered", handler);
137
+ }
138
+ }
139
+ };
140
+
141
+ //#endregion
142
+ //#region Resources/Private/Client/src/lib/hydration.ts
143
+ function getHydrationData(component, id) {
144
+ const hydrationData = window.FluidPrimitives?.hydrationData;
145
+ if (!hydrationData || typeof hydrationData !== "object") return null;
146
+ if (!component) return hydrationData;
147
+ if (!hydrationData[component]) return null;
148
+ if (!id) return hydrationData[component];
149
+ return hydrationData[component][id] || null;
150
+ }
151
+ function mount(componentName, callback) {
152
+ const hydrationInstances = getHydrationData(componentName);
153
+ if (!hydrationInstances) return;
154
+ Object.keys(hydrationInstances).forEach((id) => {
155
+ if (hydrationInstances[id].controlled) return;
156
+ const instance = callback({
157
+ ...hydrationInstances[id],
158
+ createHydrator: () => new ComponentHydrator(componentName, id, hydrationInstances[id].props.ids)
159
+ });
160
+ if (!instance) return;
161
+ if (!window.FluidPrimitives.uncontrolledInstances[componentName]) window.FluidPrimitives.uncontrolledInstances[componentName] = {};
162
+ window.FluidPrimitives.uncontrolledInstances[componentName][id] = instance;
163
+ });
164
+ }
165
+ function mountControlled(componentName, rootId, callback) {
166
+ const hydrationData = getHydrationData(componentName, rootId);
167
+ if (!hydrationData) return;
168
+ return callback({
169
+ ...hydrationData,
170
+ createHydrator: () => new ComponentHydrator(componentName, rootId, hydrationData.props.ids)
171
+ });
172
+ }
173
+ var ComponentHydrator = class {
174
+ componentName;
175
+ doc;
176
+ rootId;
177
+ ids;
178
+ elementRefs = /* @__PURE__ */ new Map();
179
+ constructor(componentName, rootId, ids = {}, doc = document) {
180
+ this.componentName = componentName;
181
+ this.doc = doc;
182
+ if (!rootId) throw new Error(`Root ID is required for component hydration: ${componentName}`);
183
+ this.rootId = rootId;
184
+ this.ids = ids;
185
+ }
186
+ getElement(part, parent = this.doc) {
187
+ if (this.elementRefs.has(part)) return this.elementRefs.get(part) || null;
188
+ let element = null;
189
+ if (this.ids[part]) element = parent.querySelector(`#${this.ids[part]}`);
190
+ else element = parent.querySelector(`[data-hydrate-${this.componentName}="${this.rootId}"][data-part="${part}"][data-scope="${this.componentName}"]`);
191
+ if (element) {
192
+ if (parent === this.doc) this.elementRefs.set(part, element);
193
+ element.removeAttribute(`data-hydrate-${this.componentName}`);
194
+ element.__rootId = this.rootId;
195
+ }
196
+ return element;
197
+ }
198
+ getElements(part, parent = this.doc) {
199
+ if (this.elementRefs.has(part)) return this.elementRefs.get(part);
200
+ let elements = [];
201
+ if (this.ids[part]) elements = Array.from(parent.querySelectorAll(`#${this.ids[part]}`));
202
+ else elements = Array.from(parent.querySelectorAll(`[data-hydrate-${this.componentName}="${this.rootId}"][data-part="${part}"][data-scope="${this.componentName}"]`));
203
+ if (parent === this.doc) this.elementRefs.set(part, elements);
204
+ elements.forEach((el) => el.removeAttribute(`data-hydrate-${this.componentName}`));
205
+ return elements;
206
+ }
207
+ generateRefAttributesString(part) {
208
+ const id = this.ids[part] || `${this.rootId}-${part}`;
209
+ return `data-scope="${this.componentName}" data-part="${part}" data-hydrate-${this.componentName}="${id}"`;
210
+ }
211
+ setRefAttributes(element, part) {
212
+ this.generateRefAttributesString(part).split(" ").map((attr) => attr.trim()).forEach((attr) => {
213
+ const [key, value] = attr.split("=");
214
+ element.setAttribute(key, value.replace(/"/g, ""));
215
+ });
216
+ }
217
+ destroy() {
218
+ this.elementRefs.forEach((el) => {
219
+ if (el instanceof Element) el.setAttribute(`data-hydrate-${this.componentName}`, this.rootId);
220
+ else el.forEach((e) => e.setAttribute(`data-hydrate-${this.componentName}`, this.rootId));
221
+ });
222
+ this.elementRefs.clear();
223
+ }
224
+ };
225
+ function getListCollectionFromHydrationData(hydrationCollection) {
226
+ if (hydrationCollection instanceof ListCollection) return hydrationCollection;
227
+ return new ListCollection({
228
+ items: hydrationCollection.items,
229
+ itemToValue: hydrationCollection.itemToValueKey ? (item) => item?.[hydrationCollection.itemToValueKey] : void 0,
230
+ itemToString: hydrationCollection.itemToStringKey ? (item) => item?.[hydrationCollection.itemToStringKey] : void 0,
231
+ isItemDisabled: hydrationCollection.isItemDisabledKey ? (item) => item?.[hydrationCollection.isItemDisabledKey] : void 0,
232
+ groupBy: hydrationCollection.groupByKey ? (item) => {
233
+ const key = hydrationCollection.groupByKey;
234
+ if (!key) return void 0;
235
+ if (key.includes(".")) return key.split(".").reduce((obj, k) => obj ? obj[k] : void 0, item);
236
+ return item?.[key];
237
+ } : void 0
238
+ });
239
+ }
240
+
241
+ //#endregion
242
+ //#region Resources/Private/Client/src/lib/uid.ts
243
+ function uid(prefix = "f") {
244
+ return "«" + prefix + uuid() + "»";
245
+ }
246
+
247
+ //#endregion
248
+ export { Machine as a, getListCollectionFromHydrationData as c, FieldAwareComponent as d, registerFieldMachine as f, mergeProps as i, mount as l, spreadProps as n, ComponentHydrator as o, Component as p, normalizeProps as r, getHydrationData as s, uid as t, mountControlled as u };
@@ -1,12 +1,12 @@
1
- import { Component$1 as Component, Machine$1 as Machine } from "./index-BpcuNDMI.js";
1
+ import { a as Machine, f as Component } from "./index-B8JCdyld.js";
2
2
  import * as accordion from "@zag-js/accordion";
3
- import * as _zag_js_types2 from "@zag-js/types";
3
+ import * as _$_zag_js_types0 from "@zag-js/types";
4
4
 
5
5
  //#region Resources/Private/Primitives/Accordion/Accordion.d.ts
6
6
  declare class Accordion extends Component<accordion.Props, accordion.Api> {
7
7
  static name: string;
8
8
  initMachine(props: accordion.Props): Machine<any>;
9
- initApi(): accordion.Api<_zag_js_types2.PropTypes<{
9
+ initApi(): accordion.Api<_$_zag_js_types0.PropTypes<{
10
10
  [x: string]: any;
11
11
  }>>;
12
12
  render(): void;
package/dist/accordion.js CHANGED
@@ -1 +1,45 @@
1
- import{Component as e,Machine as t,normalizeProps as n}from"./Client-CygooKu8.js";import*as r from"@zag-js/accordion";var i=class extends e{static name=`accordion`;initMachine(e){return new t(r.machine,{collapsible:!0,...e})}initApi(){return r.connect(this.machine.service,n)}render(){let e=this.getElement(`root`);e&&this.spreadProps(e,this.api.getRootProps());let t=this.getElements(`item`);t.forEach(e=>{this.spreadProps(e,this.api.getItemProps({value:e.getAttribute(`data-value`),disabled:e.hasAttribute(`data-disabled`)}))});let n=this.getElements(`item-trigger`);n.forEach(e=>{this.spreadProps(e,this.api.getItemTriggerProps({value:e.getAttribute(`data-value`),disabled:e.hasAttribute(`data-disabled`)}))});let r=this.getElements(`item-content`);r.forEach(e=>{this.spreadProps(e,this.api.getItemContentProps({value:e.getAttribute(`data-value`),disabled:e.hasAttribute(`data-disabled`)}))});let i=this.getElements(`item-indicator`);i.forEach(e=>{this.spreadProps(e,this.api.getItemIndicatorProps({value:e.getAttribute(`data-value`),disabled:e.hasAttribute(`data-disabled`)}))}),this.getElements(`item-header`)}};export{i as Accordion};
1
+ import { a as Machine, p as Component, r as normalizeProps } from "./Client-C51NSHxg.js";
2
+ import * as accordion from "@zag-js/accordion";
3
+
4
+ //#region Resources/Private/Primitives/Accordion/Accordion.ts
5
+ var Accordion = class extends Component {
6
+ static name = "accordion";
7
+ initMachine(props) {
8
+ return new Machine(accordion.machine, { ...props });
9
+ }
10
+ initApi() {
11
+ return accordion.connect(this.machine.service, normalizeProps);
12
+ }
13
+ render() {
14
+ const rootEl = this.getElement("root");
15
+ if (rootEl) this.spreadProps(rootEl, this.api.getRootProps());
16
+ this.getElements("item").forEach((itemEl) => {
17
+ this.spreadProps(itemEl, this.api.getItemProps({
18
+ value: itemEl.getAttribute("data-value"),
19
+ disabled: itemEl.hasAttribute("data-disabled")
20
+ }));
21
+ });
22
+ this.getElements("item-trigger").forEach((trigger) => {
23
+ this.spreadProps(trigger, this.api.getItemTriggerProps({
24
+ value: trigger.getAttribute("data-value"),
25
+ disabled: trigger.hasAttribute("data-disabled")
26
+ }));
27
+ });
28
+ this.getElements("item-content").forEach((contentEl) => {
29
+ this.spreadProps(contentEl, this.api.getItemContentProps({
30
+ value: contentEl.getAttribute("data-value"),
31
+ disabled: contentEl.hasAttribute("data-disabled")
32
+ }));
33
+ });
34
+ this.getElements("item-indicator").forEach((indicatorEl) => {
35
+ this.spreadProps(indicatorEl, this.api.getItemIndicatorProps({
36
+ value: indicatorEl.getAttribute("data-value"),
37
+ disabled: indicatorEl.hasAttribute("data-disabled")
38
+ }));
39
+ });
40
+ this.getElements("item-header");
41
+ }
42
+ };
43
+
44
+ //#endregion
45
+ export { Accordion };
@@ -0,0 +1,99 @@
1
+ import { a as Machine, u as FieldAwareComponent } from "./index-B8JCdyld.js";
2
+ import { t as FieldMachine } from "./form.registry-Cb8Pvoe8.js";
3
+ import { EventObject } from "@zag-js/core";
4
+ import { PropTypes } from "@zag-js/types";
5
+
6
+ //#region Resources/Private/Primitives/CheckboxGroup/src/checkbox-group.types.d.ts
7
+ interface CheckboxGroupProps {
8
+ id: string;
9
+ ids?: Record<string, string>;
10
+ /** The initial value of the checkbox group (uncontrolled) */
11
+ defaultValue?: string[];
12
+ /** The controlled value of the checkbox group */
13
+ value?: string[];
14
+ /** The name of the input fields in the checkbox group (for form submission) */
15
+ name?: string;
16
+ /** The form id the checkbox group belongs to */
17
+ form?: string;
18
+ /** If true, the checkbox group is disabled */
19
+ disabled?: boolean;
20
+ /** If true, the checkbox group is read-only */
21
+ readOnly?: boolean;
22
+ /** If true, the checkbox group is required */
23
+ required?: boolean;
24
+ /** If true, the checkbox group is invalid */
25
+ invalid?: boolean;
26
+ /** The maximum number of selected values */
27
+ maxSelectedValues?: number;
28
+ /** Called when the value changes */
29
+ onValueChange?: (details: {
30
+ value: string[];
31
+ }) => void;
32
+ }
33
+ interface CheckboxGroupSchema {
34
+ props: CheckboxGroupProps;
35
+ context: {
36
+ value: string[];
37
+ };
38
+ computed: {
39
+ isAtMax: boolean;
40
+ isInteractive: boolean;
41
+ };
42
+ state: 'ready';
43
+ event: EventObject;
44
+ action: string;
45
+ effect: string;
46
+ }
47
+ interface CheckboxGroupItemProps {
48
+ value: string;
49
+ }
50
+ /** API returned by getItemProps for checkbox items */
51
+ interface CheckboxGroupItemState {
52
+ checked: boolean;
53
+ onCheckedChange: () => void;
54
+ name: string | undefined;
55
+ disabled: boolean;
56
+ readOnly: boolean;
57
+ invalid: boolean;
58
+ }
59
+ /** Public API for CheckboxGroup - used by Checkbox to get item props */
60
+ interface CheckboxGroupApi {
61
+ /** The current value of the checkbox group */
62
+ value: string[];
63
+ /** The name for form submission */
64
+ name: string | undefined;
65
+ /** Whether the checkbox group is disabled */
66
+ disabled: boolean;
67
+ /** Whether the checkbox group is read-only */
68
+ readOnly: boolean;
69
+ /** Whether the checkbox group is invalid */
70
+ invalid: boolean;
71
+ /** Check if a value is selected */
72
+ isChecked(value: string): boolean;
73
+ /** Set the entire value array */
74
+ setValue(value: string[]): void;
75
+ /** Add a value to the selection */
76
+ addValue(value: string): void;
77
+ /** Remove a value from the selection */
78
+ removeValue(value: string): void;
79
+ /** Toggle a value */
80
+ toggleValue(value: string): void;
81
+ /** Get props to merge into a checkbox item */
82
+ getItemProps(props: CheckboxGroupItemProps): CheckboxGroupItemState;
83
+ /** Get root element props */
84
+ getRootProps(): PropTypes['element'];
85
+ /** Get label element props */
86
+ getLabelProps(): PropTypes['element'];
87
+ }
88
+ //#endregion
89
+ //#region Resources/Private/Primitives/CheckboxGroup/CheckboxGroup.d.ts
90
+ declare class CheckboxGroup extends FieldAwareComponent<CheckboxGroupProps, CheckboxGroupApi> {
91
+ static name: string;
92
+ propsWithField(props: CheckboxGroupProps, fieldMachine: FieldMachine): CheckboxGroupProps;
93
+ initMachine(props: CheckboxGroupProps): Machine<CheckboxGroupSchema>;
94
+ initApi(): CheckboxGroupApi;
95
+ render(): void;
96
+ destroy(): void;
97
+ }
98
+ //#endregion
99
+ export { CheckboxGroup };
@@ -0,0 +1,117 @@
1
+ import { a as Machine, d as FieldAwareComponent, i as mergeProps, r as normalizeProps } from "./Client-C51NSHxg.js";
2
+ import { i as connect, n as registerCheckboxGroup, r as unregisterCheckboxGroup } from "./checkbox-group.registry-CGwuF7SF.js";
3
+ import { a as getLabelId } from "./field.dom-CJQXpQbZ.js";
4
+ import { createMachine } from "@zag-js/core";
5
+
6
+ //#region Resources/Private/Primitives/CheckboxGroup/src/checkbox-group.machine.ts
7
+ const machine = createMachine({
8
+ initialState() {
9
+ return "ready";
10
+ },
11
+ context({ bindable, prop }) {
12
+ return { value: bindable(() => ({
13
+ defaultValue: prop("defaultValue") ?? [],
14
+ value: prop("value"),
15
+ onChange(value) {
16
+ prop("onValueChange")?.({ value });
17
+ }
18
+ })) };
19
+ },
20
+ states: { ready: { on: {
21
+ "VALUE.SET": { actions: ["setValue"] },
22
+ "VALUE.ADD": { actions: ["addValue"] },
23
+ "VALUE.REMOVE": { actions: ["removeValue"] },
24
+ "VALUE.TOGGLE": { actions: ["toggleValue"] }
25
+ } } },
26
+ computed: {
27
+ isAtMax({ prop, context }) {
28
+ const max = prop("maxSelectedValues");
29
+ if (max == null) return false;
30
+ return context.get("value").length >= max;
31
+ },
32
+ isInteractive({ prop }) {
33
+ return !prop("disabled") && !prop("readOnly");
34
+ }
35
+ },
36
+ implementations: { actions: {
37
+ setValue({ context, event }) {
38
+ const newValue = event.value;
39
+ context.set("value", newValue);
40
+ },
41
+ addValue({ context, event, computed }) {
42
+ if (!computed("isInteractive")) return;
43
+ const val = event.value;
44
+ const currentValue = context.get("value");
45
+ if (currentValue.includes(val)) return;
46
+ if (computed("isAtMax")) return;
47
+ const newValue = [...currentValue, val];
48
+ context.set("value", newValue);
49
+ },
50
+ removeValue({ context, event, computed }) {
51
+ if (!computed("isInteractive")) return;
52
+ const val = event.value;
53
+ const newValue = context.get("value").filter((v) => v !== val);
54
+ context.set("value", newValue);
55
+ },
56
+ toggleValue({ context, event, computed }) {
57
+ const val = event.value;
58
+ const currentValue = context.get("value");
59
+ if (currentValue.includes(val)) {
60
+ if (!computed("isInteractive")) return;
61
+ const newValue = currentValue.filter((v) => v !== val);
62
+ context.set("value", newValue);
63
+ } else {
64
+ if (!computed("isInteractive")) return;
65
+ if (computed("isAtMax")) return;
66
+ const newValue = [...currentValue, val];
67
+ context.set("value", newValue);
68
+ }
69
+ }
70
+ } }
71
+ });
72
+
73
+ //#endregion
74
+ //#region Resources/Private/Primitives/CheckboxGroup/CheckboxGroup.ts
75
+ var CheckboxGroup = class extends FieldAwareComponent {
76
+ static name = "checkbox-group";
77
+ propsWithField(props, fieldMachine) {
78
+ return {
79
+ ...props,
80
+ disabled: props.disabled ?? fieldMachine.context.get("disabled"),
81
+ readOnly: props.readOnly ?? fieldMachine.context.get("readOnly"),
82
+ required: props.required ?? fieldMachine.context.get("required"),
83
+ invalid: props.invalid ?? fieldMachine.context.get("invalid"),
84
+ name: props.name ?? fieldMachine.prop("name"),
85
+ ids: {
86
+ ...props.ids,
87
+ label: getLabelId(fieldMachine.scope)
88
+ }
89
+ };
90
+ }
91
+ initMachine(props) {
92
+ props = this.withFieldProps(props);
93
+ const createdMachine = new Machine(machine, props);
94
+ registerCheckboxGroup(this.getElement("root"), createdMachine);
95
+ return createdMachine;
96
+ }
97
+ initApi() {
98
+ return connect(this.machine.service, normalizeProps);
99
+ }
100
+ render() {
101
+ this.subscribeToFieldService();
102
+ const rootEl = this.getElement("root");
103
+ if (rootEl) {
104
+ const mergedProps = mergeProps(this.api.getRootProps(), { "aria-describedby": this.fieldMachine?.context.get("describeIds") || void 0 });
105
+ this.spreadProps(rootEl, mergedProps);
106
+ }
107
+ const labelEl = this.getElement("label");
108
+ if (labelEl) this.spreadProps(labelEl, this.api.getLabelProps());
109
+ }
110
+ destroy() {
111
+ unregisterCheckboxGroup(this.getElement("root"));
112
+ super.destroy();
113
+ }
114
+ };
115
+
116
+ //#endregion
117
+ export { CheckboxGroup };
@@ -0,0 +1,112 @@
1
+ //#region Resources/Private/Primitives/CheckboxGroup/src/checkbox-group.dom.ts
2
+ const getRootId = (scope) => scope.ids?.root ?? `checkbox-group:${scope.id}:root`;
3
+ const getLabelId = (scope) => scope.ids?.label ?? `checkbox-group:${scope.id}:label`;
4
+
5
+ //#endregion
6
+ //#region Resources/Private/Primitives/CheckboxGroup/src/checkbox-group.connect.ts
7
+ function connect(service, normalize) {
8
+ const { scope, context, computed, send, prop } = service;
9
+ const disabled = !!prop("disabled");
10
+ const readOnly = !!prop("readOnly");
11
+ const invalid = !!prop("invalid");
12
+ const required = !!prop("required");
13
+ const name = prop("name");
14
+ return {
15
+ get value() {
16
+ return context.get("value");
17
+ },
18
+ name,
19
+ disabled,
20
+ readOnly,
21
+ invalid,
22
+ isChecked(val) {
23
+ return context.get("value").includes(val);
24
+ },
25
+ setValue(val) {
26
+ send({
27
+ type: "VALUE.SET",
28
+ value: val
29
+ });
30
+ },
31
+ addValue(val) {
32
+ send({
33
+ type: "VALUE.ADD",
34
+ value: val
35
+ });
36
+ },
37
+ removeValue(val) {
38
+ send({
39
+ type: "VALUE.REMOVE",
40
+ value: val
41
+ });
42
+ },
43
+ toggleValue(val) {
44
+ send({
45
+ type: "VALUE.TOGGLE",
46
+ value: val
47
+ });
48
+ },
49
+ getItemProps(props) {
50
+ const checked = context.get("value").includes(props.value);
51
+ const isAtMax = computed("isAtMax");
52
+ return {
53
+ checked,
54
+ onCheckedChange: () => send({
55
+ type: "VALUE.TOGGLE",
56
+ value: props.value
57
+ }),
58
+ name,
59
+ disabled: disabled || isAtMax && !checked,
60
+ readOnly,
61
+ invalid
62
+ };
63
+ },
64
+ getRootProps() {
65
+ return normalize.element({
66
+ id: getRootId(scope),
67
+ role: "group",
68
+ "data-scope": "checkbox-group",
69
+ "data-part": "root",
70
+ "data-disabled": disabled ? "" : void 0,
71
+ "data-readonly": readOnly ? "" : void 0,
72
+ "data-invalid": invalid ? "" : void 0,
73
+ "aria-labelledby": getLabelId(scope),
74
+ "aria-disabled": disabled || void 0,
75
+ "aria-invalid": invalid || void 0,
76
+ "aria-required": required || void 0
77
+ });
78
+ },
79
+ getLabelProps() {
80
+ return normalize.element({
81
+ id: getLabelId(scope),
82
+ "data-scope": "checkbox-group",
83
+ "data-part": "label",
84
+ "data-disabled": disabled ? "" : void 0,
85
+ "data-readonly": readOnly ? "" : void 0,
86
+ "data-invalid": invalid ? "" : void 0
87
+ });
88
+ }
89
+ };
90
+ }
91
+
92
+ //#endregion
93
+ //#region Resources/Private/Primitives/CheckboxGroup/src/checkbox-group.registry.ts
94
+ const registry = /* @__PURE__ */ new WeakMap();
95
+ function registerCheckboxGroup(root, machine) {
96
+ if (!root) return;
97
+ registry.set(root, machine);
98
+ root.dispatchEvent(new CustomEvent("fluid-primitives:checkbox-group:registered", { bubbles: true }));
99
+ }
100
+ function unregisterCheckboxGroup(root) {
101
+ if (!root) return;
102
+ registry.delete(root);
103
+ }
104
+ function getCheckboxGroupMachineFor(el) {
105
+ if (!el) return void 0;
106
+ const root = el.closest("[data-scope=\"checkbox-group\"][data-part=\"root\"]");
107
+ if (!root) return void 0;
108
+ return registry.get(root);
109
+ }
110
+
111
+ //#endregion
112
+ export { connect as i, registerCheckboxGroup as n, unregisterCheckboxGroup as r, getCheckboxGroupMachineFor as t };