@cimplify/sdk 0.10.4 → 0.12.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.
package/dist/react.mjs CHANGED
@@ -1,8 +1,15 @@
1
1
  "use client";
2
- import React3, { createContext, useContext, useState, useEffect, useRef, useMemo, useSyncExternalStore, useCallback } from 'react';
2
+ import React3, { createContext, useContext, useState, useEffect, useRef, useMemo, useSyncExternalStore, useCallback, useId } from 'react';
3
3
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
4
+ import { NumberField } from '@base-ui/react/number-field';
4
5
  import { clsx } from 'clsx';
5
6
  import { twMerge } from 'tailwind-merge';
7
+ import { RadioGroup } from '@base-ui/react/radio-group';
8
+ import { Radio } from '@base-ui/react/radio';
9
+ import { Checkbox } from '@base-ui/react/checkbox';
10
+ import { Field } from '@base-ui/react/field';
11
+ import { Input } from '@base-ui/react/input';
12
+ import { Tabs } from '@base-ui/react/tabs';
6
13
 
7
14
  // src/ads/index.tsx
8
15
 
@@ -7824,52 +7831,60 @@ function QuantitySelector({
7824
7831
  className,
7825
7832
  classNames
7826
7833
  }) {
7827
- return /* @__PURE__ */ jsxs(
7828
- "div",
7834
+ return /* @__PURE__ */ jsx(
7835
+ NumberField.Root,
7829
7836
  {
7830
- "data-cimplify-quantity": true,
7831
- className: cn("inline-flex items-center gap-3 border border-border px-2", className, classNames?.root),
7832
- children: [
7833
- /* @__PURE__ */ jsx(
7834
- "button",
7835
- {
7836
- type: "button",
7837
- onClick: () => onChange(Math.max(min, value - 1)),
7838
- disabled: value <= min,
7839
- "aria-label": "Decrease quantity",
7840
- "data-cimplify-quantity-decrement": true,
7841
- className: cn(
7842
- "w-10 h-10 flex items-center justify-center hover:text-primary transition-colors disabled:opacity-30",
7843
- classNames?.button
7837
+ value,
7838
+ onValueChange: (val) => {
7839
+ if (val != null) {
7840
+ onChange(val);
7841
+ }
7842
+ },
7843
+ min,
7844
+ max,
7845
+ step: 1,
7846
+ children: /* @__PURE__ */ jsxs(
7847
+ NumberField.Group,
7848
+ {
7849
+ "data-cimplify-quantity": true,
7850
+ className: cn("inline-flex items-center gap-3 border border-border px-2", className, classNames?.root),
7851
+ children: [
7852
+ /* @__PURE__ */ jsx(
7853
+ NumberField.Decrement,
7854
+ {
7855
+ "aria-label": "Decrease quantity",
7856
+ "data-cimplify-quantity-decrement": true,
7857
+ className: cn(
7858
+ "w-10 h-10 flex items-center justify-center hover:text-primary transition-colors disabled:opacity-30",
7859
+ classNames?.button
7860
+ ),
7861
+ children: "\u2212"
7862
+ }
7844
7863
  ),
7845
- children: "\u2212"
7846
- }
7847
- ),
7848
- /* @__PURE__ */ jsx(
7849
- "span",
7850
- {
7851
- "data-cimplify-quantity-value": true,
7852
- "aria-live": "polite",
7853
- className: cn("w-8 text-center font-medium", classNames?.value),
7854
- children: value
7855
- }
7856
- ),
7857
- /* @__PURE__ */ jsx(
7858
- "button",
7859
- {
7860
- type: "button",
7861
- onClick: () => onChange(max != null ? Math.min(max, value + 1) : value + 1),
7862
- disabled: max != null && value >= max,
7863
- "aria-label": "Increase quantity",
7864
- "data-cimplify-quantity-increment": true,
7865
- className: cn(
7866
- "w-10 h-10 flex items-center justify-center hover:text-primary transition-colors disabled:opacity-30",
7867
- classNames?.button
7864
+ /* @__PURE__ */ jsx(
7865
+ NumberField.Input,
7866
+ {
7867
+ "data-cimplify-quantity-value": true,
7868
+ "aria-live": "polite",
7869
+ readOnly: true,
7870
+ className: cn("w-8 text-center font-medium bg-transparent border-none outline-none [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none", classNames?.value)
7871
+ }
7868
7872
  ),
7869
- children: "+"
7870
- }
7871
- )
7872
- ]
7873
+ /* @__PURE__ */ jsx(
7874
+ NumberField.Increment,
7875
+ {
7876
+ "aria-label": "Increase quantity",
7877
+ "data-cimplify-quantity-increment": true,
7878
+ className: cn(
7879
+ "w-10 h-10 flex items-center justify-center hover:text-primary transition-colors disabled:opacity-30",
7880
+ classNames?.button
7881
+ ),
7882
+ children: "+"
7883
+ }
7884
+ )
7885
+ ]
7886
+ }
7887
+ )
7873
7888
  }
7874
7889
  );
7875
7890
  }
@@ -7922,6 +7937,7 @@ function VariantSelector({
7922
7937
  }) {
7923
7938
  const [axisSelections, setAxisSelections] = useState({});
7924
7939
  const initialized = useRef(false);
7940
+ const idPrefix = useId();
7925
7941
  useEffect(() => {
7926
7942
  initialized.current = false;
7927
7943
  }, [variants]);
@@ -7958,106 +7974,126 @@ function VariantSelector({
7958
7974
  }
7959
7975
  const basePriceNum = basePrice != null ? parsePrice(basePrice) : 0;
7960
7976
  if (variantAxes && variantAxes.length > 0) {
7961
- return /* @__PURE__ */ jsx("div", { "data-cimplify-variant-selector": true, className: cn("space-y-5", className, classNames?.root), children: variantAxes.map((axis) => /* @__PURE__ */ jsxs("div", { "data-cimplify-variant-axis": true, children: [
7962
- /* @__PURE__ */ jsx(
7963
- "label",
7964
- {
7965
- "data-cimplify-variant-axis-label": true,
7966
- className: cn("block text-xs font-medium uppercase tracking-wider text-muted-foreground mb-3", classNames?.axisLabel),
7967
- children: axis.name
7968
- }
7969
- ),
7970
- /* @__PURE__ */ jsx(
7971
- "div",
7972
- {
7973
- "data-cimplify-variant-axis-options": true,
7974
- className: cn("flex flex-wrap gap-2", classNames?.axisOptions),
7975
- children: axis.values.map((value) => {
7976
- const isSelected = axisSelections[axis.id] === value.id;
7977
- return /* @__PURE__ */ jsx(
7978
- "button",
7979
- {
7980
- type: "button",
7981
- "aria-selected": isSelected,
7982
- onClick: () => {
7983
- setAxisSelections((prev) => ({
7984
- ...prev,
7985
- [axis.id]: value.id
7986
- }));
7977
+ return /* @__PURE__ */ jsx("div", { "data-cimplify-variant-selector": true, className: cn("space-y-5", className, classNames?.root), children: variantAxes.map((axis) => {
7978
+ const labelId = `${idPrefix}-axis-${axis.id}`;
7979
+ return /* @__PURE__ */ jsxs("div", { "data-cimplify-variant-axis": true, children: [
7980
+ /* @__PURE__ */ jsx(
7981
+ "label",
7982
+ {
7983
+ id: labelId,
7984
+ "data-cimplify-variant-axis-label": true,
7985
+ className: cn("block text-xs font-medium uppercase tracking-wider text-muted-foreground mb-3", classNames?.axisLabel),
7986
+ children: axis.name
7987
+ }
7988
+ ),
7989
+ /* @__PURE__ */ jsx(
7990
+ RadioGroup,
7991
+ {
7992
+ "aria-labelledby": labelId,
7993
+ value: axisSelections[axis.id] ?? "",
7994
+ onValueChange: (value) => {
7995
+ setAxisSelections((prev) => ({
7996
+ ...prev,
7997
+ [axis.id]: value
7998
+ }));
7999
+ },
8000
+ "data-cimplify-variant-axis-options": true,
8001
+ className: cn("flex flex-wrap gap-2", classNames?.axisOptions),
8002
+ children: axis.values.map((value) => {
8003
+ const isSelected = axisSelections[axis.id] === value.id;
8004
+ return /* @__PURE__ */ jsx(
8005
+ Radio.Root,
8006
+ {
8007
+ value: value.id,
8008
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
8009
+ "data-cimplify-variant-option": true,
8010
+ "data-selected": isSelected || void 0,
8011
+ className: cn(
8012
+ "px-4 py-2 border text-sm font-medium transition-colors border-border hover:border-primary/50",
8013
+ isSelected && "bg-primary text-primary-foreground border-primary",
8014
+ isSelected ? classNames?.optionSelected : classNames?.option
8015
+ ),
8016
+ children: value.name
7987
8017
  },
7988
- "data-cimplify-variant-option": true,
7989
- "data-selected": isSelected || void 0,
7990
- className: cn(
7991
- "px-4 py-2 border text-sm font-medium transition-colors border-border hover:border-primary/50",
7992
- isSelected && "bg-primary text-primary-foreground border-primary",
7993
- isSelected ? classNames?.optionSelected : classNames?.option
7994
- ),
7995
- children: value.name
7996
- },
7997
- value.id
7998
- );
7999
- })
8000
- }
8001
- )
8002
- ] }, axis.id)) });
8018
+ value.id
8019
+ );
8020
+ })
8021
+ }
8022
+ )
8023
+ ] }, axis.id);
8024
+ }) });
8003
8025
  }
8026
+ const listLabelId = `${idPrefix}-variant-list`;
8004
8027
  return /* @__PURE__ */ jsxs("div", { "data-cimplify-variant-selector": true, className: cn("space-y-5", className, classNames?.root), children: [
8005
8028
  /* @__PURE__ */ jsx(
8006
8029
  "label",
8007
8030
  {
8031
+ id: listLabelId,
8008
8032
  "data-cimplify-variant-list-label": true,
8009
8033
  className: cn("block text-xs font-medium uppercase tracking-wider text-muted-foreground mb-3", classNames?.listLabel),
8010
8034
  children: "Options"
8011
8035
  }
8012
8036
  ),
8013
- /* @__PURE__ */ jsx("div", { "data-cimplify-variant-list": true, className: cn("space-y-2", classNames?.list), children: variants.map((variant) => {
8014
- const isSelected = selectedVariantId === variant.id;
8015
- const adjustment = parsePrice(variant.price_adjustment);
8016
- const effectivePrice = basePriceNum + adjustment;
8017
- return /* @__PURE__ */ jsxs(
8018
- "button",
8019
- {
8020
- type: "button",
8021
- "aria-selected": isSelected,
8022
- onClick: () => onVariantChange(variant.id, variant),
8023
- "data-cimplify-variant-option": true,
8024
- "data-selected": isSelected || void 0,
8025
- className: cn(
8026
- "w-full flex items-center justify-between px-4 py-3 border transition-colors border-border hover:border-primary/50",
8027
- isSelected && "bg-primary/5 border-primary",
8028
- isSelected ? classNames?.optionSelected : classNames?.option
8029
- ),
8030
- children: [
8031
- /* @__PURE__ */ jsx(
8032
- "span",
8033
- {
8034
- "data-cimplify-variant-name": true,
8035
- className: cn("font-medium", isSelected && "text-primary", classNames?.name),
8036
- children: getVariantDisplayName(variant, productName)
8037
- }
8038
- ),
8039
- /* @__PURE__ */ jsxs("span", { "data-cimplify-variant-pricing": true, className: cn("text-sm", classNames?.pricing), children: [
8040
- adjustment !== 0 && /* @__PURE__ */ jsxs(
8041
- "span",
8042
- {
8043
- "data-cimplify-variant-adjustment": true,
8044
- className: cn(
8045
- adjustment > 0 ? "text-muted-foreground" : "text-green-600",
8046
- classNames?.adjustment
8047
- ),
8048
- children: [
8049
- adjustment > 0 ? "+" : "",
8050
- /* @__PURE__ */ jsx(Price, { amount: variant.price_adjustment })
8051
- ]
8052
- }
8053
- ),
8054
- /* @__PURE__ */ jsx(Price, { amount: effectivePrice, className: "text-muted-foreground" })
8055
- ] })
8056
- ]
8037
+ /* @__PURE__ */ jsx(
8038
+ RadioGroup,
8039
+ {
8040
+ "aria-labelledby": listLabelId,
8041
+ value: selectedVariantId ?? "",
8042
+ onValueChange: (value) => {
8043
+ const variant = variants.find((v) => v.id === value);
8044
+ onVariantChange(variant?.id, variant);
8057
8045
  },
8058
- variant.id
8059
- );
8060
- }) })
8046
+ "data-cimplify-variant-list": true,
8047
+ className: cn("space-y-2", classNames?.list),
8048
+ children: variants.map((variant) => {
8049
+ const isSelected = selectedVariantId === variant.id;
8050
+ const adjustment = parsePrice(variant.price_adjustment);
8051
+ const effectivePrice = basePriceNum + adjustment;
8052
+ return /* @__PURE__ */ jsxs(
8053
+ Radio.Root,
8054
+ {
8055
+ value: variant.id,
8056
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
8057
+ "data-cimplify-variant-option": true,
8058
+ "data-selected": isSelected || void 0,
8059
+ className: cn(
8060
+ "w-full flex items-center justify-between px-4 py-3 border transition-colors border-border hover:border-primary/50",
8061
+ isSelected && "bg-primary/5 border-primary",
8062
+ isSelected ? classNames?.optionSelected : classNames?.option
8063
+ ),
8064
+ children: [
8065
+ /* @__PURE__ */ jsx(
8066
+ "span",
8067
+ {
8068
+ "data-cimplify-variant-name": true,
8069
+ className: cn("font-medium", isSelected && "text-primary", classNames?.name),
8070
+ children: getVariantDisplayName(variant, productName)
8071
+ }
8072
+ ),
8073
+ /* @__PURE__ */ jsxs("span", { "data-cimplify-variant-pricing": true, className: cn("text-sm", classNames?.pricing), children: [
8074
+ adjustment !== 0 && /* @__PURE__ */ jsxs(
8075
+ "span",
8076
+ {
8077
+ "data-cimplify-variant-adjustment": true,
8078
+ className: cn(
8079
+ adjustment > 0 ? "text-muted-foreground" : "text-green-600",
8080
+ classNames?.adjustment
8081
+ ),
8082
+ children: [
8083
+ adjustment > 0 ? "+" : "",
8084
+ /* @__PURE__ */ jsx(Price, { amount: variant.price_adjustment })
8085
+ ]
8086
+ }
8087
+ ),
8088
+ /* @__PURE__ */ jsx(Price, { amount: effectivePrice, className: "text-muted-foreground" })
8089
+ ] })
8090
+ ]
8091
+ },
8092
+ variant.id
8093
+ );
8094
+ })
8095
+ }
8096
+ )
8061
8097
  ] });
8062
8098
  }
8063
8099
  function AddOnSelector({
@@ -8071,8 +8107,8 @@ function AddOnSelector({
8071
8107
  (optionId) => selectedOptions.includes(optionId),
8072
8108
  [selectedOptions]
8073
8109
  );
8074
- const toggleOption = useCallback(
8075
- (addOn, optionId) => {
8110
+ const handleCheckedChange = useCallback(
8111
+ (addOn, optionId, checked) => {
8076
8112
  const isSelected = selectedOptions.includes(optionId);
8077
8113
  if (addOn.is_mutually_exclusive || !addOn.is_multiple_allowed) {
8078
8114
  const groupOptionIds = new Set(addOn.options.map((o) => o.id));
@@ -8108,7 +8144,6 @@ function AddOnSelector({
8108
8144
  (id) => addOn.options.some((o) => o.id === id)
8109
8145
  ).length;
8110
8146
  const minMet = !addOn.min_selections || currentSelections >= addOn.min_selections;
8111
- const isSingleSelect = addOn.is_mutually_exclusive || !addOn.is_multiple_allowed;
8112
8147
  return /* @__PURE__ */ jsxs(
8113
8148
  "div",
8114
8149
  {
@@ -8171,12 +8206,12 @@ function AddOnSelector({
8171
8206
  children: addOn.options.map((option) => {
8172
8207
  const isSelected = isOptionSelected(option.id);
8173
8208
  return /* @__PURE__ */ jsxs(
8174
- "button",
8209
+ Checkbox.Root,
8175
8210
  {
8176
- type: "button",
8177
- role: isSingleSelect ? "radio" : "checkbox",
8178
- "aria-checked": isSelected,
8179
- onClick: () => toggleOption(addOn, option.id),
8211
+ checked: isSelected,
8212
+ onCheckedChange: (checked) => handleCheckedChange(addOn, option.id, checked),
8213
+ value: option.id,
8214
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
8180
8215
  "data-cimplify-addon-option": true,
8181
8216
  "data-selected": isSelected || void 0,
8182
8217
  className: cn(
@@ -8185,6 +8220,13 @@ function AddOnSelector({
8185
8220
  isSelected ? classNames?.optionSelected : classNames?.option
8186
8221
  ),
8187
8222
  children: [
8223
+ /* @__PURE__ */ jsx(
8224
+ Checkbox.Indicator,
8225
+ {
8226
+ className: "hidden",
8227
+ keepMounted: false
8228
+ }
8229
+ ),
8188
8230
  /* @__PURE__ */ jsx(
8189
8231
  "span",
8190
8232
  {
@@ -8348,11 +8390,13 @@ function BundleComponentCard({
8348
8390
  onVariantChange,
8349
8391
  classNames
8350
8392
  }) {
8393
+ const idPrefix = useId();
8351
8394
  const showVariantPicker = component.allow_variant_choice && component.available_variants.length > 1;
8352
8395
  const displayPrice = useMemo(
8353
8396
  () => getComponentPrice(component, selectedVariantId),
8354
8397
  [component, selectedVariantId]
8355
8398
  );
8399
+ const labelId = `${idPrefix}-bundle-component-${component.id}`;
8356
8400
  return /* @__PURE__ */ jsxs(
8357
8401
  "div",
8358
8402
  {
@@ -8380,6 +8424,7 @@ function BundleComponentCard({
8380
8424
  /* @__PURE__ */ jsx(
8381
8425
  "span",
8382
8426
  {
8427
+ id: labelId,
8383
8428
  "data-cimplify-bundle-component-name": true,
8384
8429
  className: cn("font-medium text-sm", classNames?.componentName),
8385
8430
  children: component.product_name
@@ -8391,19 +8436,23 @@ function BundleComponentCard({
8391
8436
  }
8392
8437
  ),
8393
8438
  showVariantPicker && /* @__PURE__ */ jsx(
8394
- "div",
8439
+ RadioGroup,
8395
8440
  {
8441
+ "aria-labelledby": labelId,
8442
+ value: selectedVariantId ?? "",
8443
+ onValueChange: (value) => {
8444
+ onVariantChange(value);
8445
+ },
8396
8446
  "data-cimplify-bundle-variant-picker": true,
8397
8447
  className: cn("mt-3 flex flex-wrap gap-2", classNames?.variantPicker),
8398
8448
  children: component.available_variants.map((variant) => {
8399
8449
  const isSelected = selectedVariantId === variant.id;
8400
8450
  const adjustment = parsePrice(variant.price_adjustment);
8401
8451
  return /* @__PURE__ */ jsxs(
8402
- "button",
8452
+ Radio.Root,
8403
8453
  {
8404
- type: "button",
8405
- "aria-pressed": isSelected,
8406
- onClick: () => onVariantChange(variant.id),
8454
+ value: variant.id,
8455
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
8407
8456
  "data-cimplify-bundle-variant-option": true,
8408
8457
  "data-selected": isSelected || void 0,
8409
8458
  className: cn(
@@ -8534,12 +8583,13 @@ function CompositeSelector({
8534
8583
  []
8535
8584
  );
8536
8585
  const updateQuantity = useCallback(
8537
- (group, componentId, delta) => {
8586
+ (group, componentId, newValue) => {
8538
8587
  setGroupSelections((prev) => {
8539
8588
  const groupSels = { ...prev[group.id] || {} };
8540
8589
  const current = groupSels[componentId] || 0;
8541
- const next = Math.max(0, current + delta);
8590
+ const next = Math.max(0, newValue);
8542
8591
  if (next === current) return prev;
8592
+ const delta = next - current;
8543
8593
  if (group.max_quantity_per_component && next > group.max_quantity_per_component) {
8544
8594
  return prev;
8545
8595
  }
@@ -8643,12 +8693,12 @@ function CompositeSelector({
8643
8693
  const isSelected = qty > 0;
8644
8694
  const displayName = component.display_name || component.id;
8645
8695
  return /* @__PURE__ */ jsxs(
8646
- "button",
8696
+ Checkbox.Root,
8647
8697
  {
8648
- type: "button",
8649
- role: isSingleSelect ? "radio" : "checkbox",
8650
- "aria-checked": isSelected,
8651
- onClick: () => toggleComponent(group, component),
8698
+ checked: isSelected,
8699
+ onCheckedChange: () => toggleComponent(group, component),
8700
+ value: component.id,
8701
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
8652
8702
  "data-cimplify-composite-component": true,
8653
8703
  "data-selected": isSelected || void 0,
8654
8704
  className: cn(
@@ -8657,6 +8707,13 @@ function CompositeSelector({
8657
8707
  isSelected ? classNames?.componentSelected : classNames?.component
8658
8708
  ),
8659
8709
  children: [
8710
+ /* @__PURE__ */ jsx(
8711
+ Checkbox.Indicator,
8712
+ {
8713
+ className: "hidden",
8714
+ keepMounted: false
8715
+ }
8716
+ ),
8660
8717
  /* @__PURE__ */ jsxs(
8661
8718
  "div",
8662
8719
  {
@@ -8709,35 +8766,51 @@ function CompositeSelector({
8709
8766
  ]
8710
8767
  }
8711
8768
  ),
8712
- group.allow_quantity && isSelected && /* @__PURE__ */ jsxs(
8713
- "span",
8769
+ group.allow_quantity && isSelected && /* @__PURE__ */ jsx(
8770
+ NumberField.Root,
8714
8771
  {
8715
- "data-cimplify-composite-qty": true,
8716
- onClick: (e) => e.stopPropagation(),
8717
- className: cn("flex items-center gap-2", classNames?.qty),
8718
- children: [
8719
- /* @__PURE__ */ jsx(
8720
- "button",
8721
- {
8722
- type: "button",
8723
- onClick: () => updateQuantity(group, component.id, -1),
8724
- "aria-label": `Decrease ${displayName} quantity`,
8725
- className: cn("w-6 h-6 border border-border flex items-center justify-center text-xs hover:bg-muted", classNames?.qtyButton),
8726
- children: "\u2212"
8727
- }
8728
- ),
8729
- /* @__PURE__ */ jsx("span", { className: cn("text-sm font-medium w-4 text-center", classNames?.qtyValue), children: qty }),
8730
- /* @__PURE__ */ jsx(
8731
- "button",
8732
- {
8733
- type: "button",
8734
- onClick: () => updateQuantity(group, component.id, 1),
8735
- "aria-label": `Increase ${displayName} quantity`,
8736
- className: cn("w-6 h-6 border border-border flex items-center justify-center text-xs hover:bg-muted", classNames?.qtyButton),
8737
- children: "+"
8738
- }
8739
- )
8740
- ]
8772
+ value: qty,
8773
+ onValueChange: (val) => {
8774
+ if (val != null) {
8775
+ updateQuantity(group, component.id, val);
8776
+ }
8777
+ },
8778
+ min: 0,
8779
+ max: group.max_quantity_per_component || void 0,
8780
+ step: 1,
8781
+ children: /* @__PURE__ */ jsxs(
8782
+ NumberField.Group,
8783
+ {
8784
+ "data-cimplify-composite-qty": true,
8785
+ onClick: (e) => e.stopPropagation(),
8786
+ className: cn("flex items-center gap-2", classNames?.qty),
8787
+ children: [
8788
+ /* @__PURE__ */ jsx(
8789
+ NumberField.Decrement,
8790
+ {
8791
+ "aria-label": `Decrease ${displayName} quantity`,
8792
+ className: cn("w-6 h-6 border border-border flex items-center justify-center text-xs hover:bg-muted disabled:opacity-30", classNames?.qtyButton),
8793
+ children: "\u2212"
8794
+ }
8795
+ ),
8796
+ /* @__PURE__ */ jsx(
8797
+ NumberField.Input,
8798
+ {
8799
+ readOnly: true,
8800
+ className: cn("w-4 text-center text-sm font-medium bg-transparent border-none outline-none [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none", classNames?.qtyValue)
8801
+ }
8802
+ ),
8803
+ /* @__PURE__ */ jsx(
8804
+ NumberField.Increment,
8805
+ {
8806
+ "aria-label": `Increase ${displayName} quantity`,
8807
+ className: cn("w-6 h-6 border border-border flex items-center justify-center text-xs hover:bg-muted disabled:opacity-30", classNames?.qtyButton),
8808
+ children: "+"
8809
+ }
8810
+ )
8811
+ ]
8812
+ }
8813
+ )
8741
8814
  }
8742
8815
  ),
8743
8816
  component.price != null && parsePrice(component.price) !== 0 && /* @__PURE__ */ jsx(Price, { amount: component.price, prefix: "+" })
@@ -8994,7 +9067,8 @@ function ProductCustomizer({
8994
9067
  variantAxes: product.variant_axes,
8995
9068
  basePrice: product.default_price,
8996
9069
  selectedVariantId,
8997
- onVariantChange: handleVariantChange
9070
+ onVariantChange: handleVariantChange,
9071
+ productName: product.name
8998
9072
  }
8999
9073
  ),
9000
9074
  hasAddOns && /* @__PURE__ */ jsx(
@@ -9095,33 +9169,45 @@ function ProductImageGallery({
9095
9169
  )
9096
9170
  }
9097
9171
  ),
9098
- normalizedImages.length > 1 && /* @__PURE__ */ jsx("div", { "data-cimplify-image-gallery-thumbnails": true, style: { display: "flex", gap: "0.5rem", marginTop: "0.75rem" }, children: normalizedImages.map((image, index) => /* @__PURE__ */ jsx(
9099
- "button",
9172
+ normalizedImages.length > 1 && /* @__PURE__ */ jsx(
9173
+ RadioGroup,
9100
9174
  {
9101
- type: "button",
9102
- onClick: () => setSelectedImage(index),
9103
- "aria-selected": selectedImage === index,
9104
- "data-cimplify-image-gallery-thumb": true,
9105
- "data-selected": selectedImage === index || void 0,
9106
- style: {
9107
- width: "4rem",
9108
- height: "4rem",
9109
- overflow: "hidden",
9110
- padding: 0,
9111
- border: "none",
9112
- cursor: "pointer"
9113
- },
9114
- children: /* @__PURE__ */ jsx(
9115
- "img",
9116
- {
9117
- src: image,
9118
- alt: "",
9119
- style: { width: "100%", height: "100%", objectFit: "cover" }
9120
- }
9121
- )
9122
- },
9123
- `${image}-${index}`
9124
- )) })
9175
+ "aria-label": `${productName} image thumbnails`,
9176
+ value: String(selectedImage),
9177
+ onValueChange: (value) => setSelectedImage(Number(value)),
9178
+ "data-cimplify-image-gallery-thumbnails": true,
9179
+ style: { display: "flex", gap: "0.5rem", marginTop: "0.75rem" },
9180
+ children: normalizedImages.map((image, index) => {
9181
+ const isSelected = selectedImage === index;
9182
+ return /* @__PURE__ */ jsx(
9183
+ Radio.Root,
9184
+ {
9185
+ value: String(index),
9186
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
9187
+ "data-cimplify-image-gallery-thumb": true,
9188
+ "data-selected": isSelected || void 0,
9189
+ style: {
9190
+ width: "4rem",
9191
+ height: "4rem",
9192
+ overflow: "hidden",
9193
+ padding: 0,
9194
+ border: "none",
9195
+ cursor: "pointer"
9196
+ },
9197
+ children: /* @__PURE__ */ jsx(
9198
+ "img",
9199
+ {
9200
+ src: image,
9201
+ alt: "",
9202
+ style: { width: "100%", height: "100%", objectFit: "cover" }
9203
+ }
9204
+ )
9205
+ },
9206
+ `${image}-${index}`
9207
+ );
9208
+ })
9209
+ }
9210
+ )
9125
9211
  ] });
9126
9212
  }
9127
9213
  function CartLineItemRow({
@@ -9732,6 +9818,26 @@ function ProductGrid({
9732
9818
  )
9733
9819
  ] });
9734
9820
  }
9821
+ var SearchIcon = () => /* @__PURE__ */ jsxs(
9822
+ "svg",
9823
+ {
9824
+ xmlns: "http://www.w3.org/2000/svg",
9825
+ width: "16",
9826
+ height: "16",
9827
+ viewBox: "0 0 24 24",
9828
+ fill: "none",
9829
+ stroke: "currentColor",
9830
+ strokeWidth: "2",
9831
+ strokeLinecap: "round",
9832
+ strokeLinejoin: "round",
9833
+ "aria-hidden": "true",
9834
+ "data-cimplify-search-icon": true,
9835
+ children: [
9836
+ /* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "8" }),
9837
+ /* @__PURE__ */ jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" })
9838
+ ]
9839
+ }
9840
+ );
9735
9841
  function SearchInput({
9736
9842
  placeholder = "Search products...",
9737
9843
  searchOptions,
@@ -9742,42 +9848,58 @@ function SearchInput({
9742
9848
  classNames
9743
9849
  }) {
9744
9850
  const { results, isLoading, query, setQuery, clear } = useSearch(searchOptions);
9745
- const handleChange = useCallback(
9746
- (e) => {
9747
- setQuery(e.target.value);
9851
+ const handleValueChange = useCallback(
9852
+ (value) => {
9853
+ setQuery(value);
9748
9854
  },
9749
9855
  [setQuery]
9750
9856
  );
9751
9857
  return /* @__PURE__ */ jsxs(
9752
- "div",
9858
+ Field.Root,
9753
9859
  {
9754
9860
  "data-cimplify-search": true,
9755
9861
  className: cn(className, classNames?.root),
9756
9862
  style: { position: "relative" },
9757
9863
  children: [
9758
- /* @__PURE__ */ jsx(
9759
- "input",
9760
- {
9761
- type: "search",
9762
- value: query,
9763
- onChange: handleChange,
9764
- placeholder,
9765
- "data-cimplify-search-input": true,
9766
- className: classNames?.input,
9767
- "aria-label": "Search products"
9768
- }
9769
- ),
9770
- query.length > 0 && /* @__PURE__ */ jsx(
9771
- "button",
9772
- {
9773
- type: "button",
9774
- onClick: clear,
9775
- "data-cimplify-search-clear": true,
9776
- className: classNames?.clearButton,
9777
- "aria-label": "Clear search",
9778
- children: "\xD7"
9779
- }
9780
- ),
9864
+ /* @__PURE__ */ jsx(Field.Label, { className: "sr-only", children: "Search products" }),
9865
+ /* @__PURE__ */ jsxs("div", { style: { position: "relative", display: "flex", alignItems: "center" }, children: [
9866
+ /* @__PURE__ */ jsx(
9867
+ "span",
9868
+ {
9869
+ "data-cimplify-search-icon-wrapper": true,
9870
+ style: {
9871
+ position: "absolute",
9872
+ left: "0.5rem",
9873
+ pointerEvents: "none",
9874
+ display: "flex",
9875
+ alignItems: "center"
9876
+ },
9877
+ children: /* @__PURE__ */ jsx(SearchIcon, {})
9878
+ }
9879
+ ),
9880
+ /* @__PURE__ */ jsx(
9881
+ Input,
9882
+ {
9883
+ type: "search",
9884
+ value: query,
9885
+ onValueChange: handleValueChange,
9886
+ placeholder,
9887
+ "data-cimplify-search-input": true,
9888
+ className: classNames?.input
9889
+ }
9890
+ ),
9891
+ query.length > 0 && /* @__PURE__ */ jsx(
9892
+ "button",
9893
+ {
9894
+ type: "button",
9895
+ onClick: clear,
9896
+ "data-cimplify-search-clear": true,
9897
+ className: classNames?.clearButton,
9898
+ "aria-label": "Clear search",
9899
+ children: "\xD7"
9900
+ }
9901
+ )
9902
+ ] }),
9781
9903
  showResults && query.length > 0 && /* @__PURE__ */ jsxs("div", { "data-cimplify-search-results": true, className: classNames?.results, children: [
9782
9904
  isLoading && /* @__PURE__ */ jsx("div", { "data-cimplify-search-loading": true, className: classNames?.loading, "aria-busy": "true", children: "Searching..." }),
9783
9905
  !isLoading && results.length === 0 && query.length >= 2 && /* @__PURE__ */ jsx("div", { "data-cimplify-search-empty": true, className: classNames?.empty, children: "No results found" }),
@@ -9797,6 +9919,7 @@ function SearchInput({
9797
9919
  }
9798
9920
  );
9799
9921
  }
9922
+ var ALL_VALUE = "__all__";
9800
9923
  function CategoryFilter({
9801
9924
  selectedId = null,
9802
9925
  onSelect,
@@ -9806,9 +9929,9 @@ function CategoryFilter({
9806
9929
  classNames
9807
9930
  }) {
9808
9931
  const { categories, isLoading } = useCategories();
9809
- const handleSelect = useCallback(
9810
- (id) => {
9811
- onSelect(id);
9932
+ const handleValueChange = useCallback(
9933
+ (value) => {
9934
+ onSelect(value === ALL_VALUE ? null : String(value));
9812
9935
  },
9813
9936
  [onSelect]
9814
9937
  );
@@ -9822,45 +9945,45 @@ function CategoryFilter({
9822
9945
  }
9823
9946
  );
9824
9947
  }
9825
- return /* @__PURE__ */ jsxs(
9826
- "div",
9948
+ return /* @__PURE__ */ jsx(
9949
+ Tabs.Root,
9827
9950
  {
9828
- "data-cimplify-category-filter": true,
9829
- className: cn(className, classNames?.root),
9830
- role: "tablist",
9831
- "aria-label": "Filter by category",
9832
- children: [
9833
- /* @__PURE__ */ jsx(
9834
- "button",
9835
- {
9836
- type: "button",
9837
- role: "tab",
9838
- "aria-selected": selectedId === null,
9839
- onClick: () => handleSelect(null),
9840
- "data-cimplify-category-filter-item": true,
9841
- "data-selected": selectedId === null || void 0,
9842
- className: cn(classNames?.item, classNames?.allButton),
9843
- children: allLabel
9844
- }
9845
- ),
9846
- categories.map((category) => /* @__PURE__ */ jsxs(
9847
- "button",
9848
- {
9849
- type: "button",
9850
- role: "tab",
9851
- "aria-selected": selectedId === category.id,
9852
- onClick: () => handleSelect(category.id),
9853
- "data-cimplify-category-filter-item": true,
9854
- "data-selected": selectedId === category.id || void 0,
9855
- className: classNames?.item,
9856
- children: [
9857
- category.name,
9858
- showCounts && category.product_count != null && /* @__PURE__ */ jsx("span", { "data-cimplify-category-count": true, className: classNames?.count, children: category.product_count })
9859
- ]
9860
- },
9861
- category.id
9862
- ))
9863
- ]
9951
+ value: selectedId ?? ALL_VALUE,
9952
+ onValueChange: handleValueChange,
9953
+ children: /* @__PURE__ */ jsxs(
9954
+ Tabs.List,
9955
+ {
9956
+ "data-cimplify-category-filter": true,
9957
+ "aria-label": "Filter by category",
9958
+ className: cn(className, classNames?.root),
9959
+ children: [
9960
+ /* @__PURE__ */ jsx(
9961
+ Tabs.Tab,
9962
+ {
9963
+ value: ALL_VALUE,
9964
+ "data-cimplify-category-filter-item": true,
9965
+ "data-selected": selectedId === null || void 0,
9966
+ className: cn(classNames?.item, classNames?.allButton),
9967
+ children: allLabel
9968
+ }
9969
+ ),
9970
+ categories.map((category) => /* @__PURE__ */ jsxs(
9971
+ Tabs.Tab,
9972
+ {
9973
+ value: category.id,
9974
+ "data-cimplify-category-filter-item": true,
9975
+ "data-selected": selectedId === category.id || void 0,
9976
+ className: classNames?.item,
9977
+ children: [
9978
+ category.name,
9979
+ showCounts && category.product_count != null && /* @__PURE__ */ jsx("span", { "data-cimplify-category-count": true, className: classNames?.count, children: category.product_count })
9980
+ ]
9981
+ },
9982
+ category.id
9983
+ ))
9984
+ ]
9985
+ }
9986
+ )
9864
9987
  }
9865
9988
  );
9866
9989
  }
@@ -9903,50 +10026,74 @@ function DiscountInput({
9903
10026
  [handleApply]
9904
10027
  );
9905
10028
  const isApplied = appliedValidation?.is_eligible === true;
9906
- return /* @__PURE__ */ jsxs("div", { "data-cimplify-discount": true, className: cn(className, classNames?.root), children: [
9907
- /* @__PURE__ */ jsxs("div", { "data-cimplify-discount-form": true, children: [
9908
- /* @__PURE__ */ jsx(
9909
- "input",
9910
- {
9911
- type: "text",
9912
- value: code,
9913
- onChange: (e) => setCode(e.target.value),
9914
- onKeyDown: handleKeyDown,
9915
- placeholder,
9916
- disabled: isApplied,
9917
- "data-cimplify-discount-input": true,
9918
- className: classNames?.input,
9919
- "aria-label": "Discount code"
9920
- }
9921
- ),
9922
- isApplied ? /* @__PURE__ */ jsx(
9923
- "button",
9924
- {
9925
- type: "button",
9926
- onClick: handleClear,
9927
- "data-cimplify-discount-clear": true,
9928
- className: classNames?.button,
9929
- children: "Remove"
9930
- }
9931
- ) : /* @__PURE__ */ jsx(
9932
- "button",
9933
- {
9934
- type: "button",
9935
- onClick: handleApply,
9936
- disabled: isValidating || code.trim().length === 0,
9937
- "data-cimplify-discount-apply": true,
9938
- className: classNames?.button,
9939
- children: isValidating ? "Checking..." : "Apply"
9940
- }
9941
- )
9942
- ] }),
9943
- error && /* @__PURE__ */ jsx("div", { "data-cimplify-discount-error": true, className: classNames?.error, children: error.message }),
9944
- appliedValidation && !appliedValidation.is_eligible && /* @__PURE__ */ jsx("div", { "data-cimplify-discount-error": true, className: classNames?.error, children: appliedValidation.ineligibility_reason ?? "This code is not valid." }),
9945
- isApplied && appliedValidation.discount_amount && /* @__PURE__ */ jsxs("div", { "data-cimplify-discount-success": true, className: classNames?.success, children: [
9946
- /* @__PURE__ */ jsx("span", { children: "Discount applied" }),
9947
- /* @__PURE__ */ jsx(Price, { amount: appliedValidation.discount_amount, prefix: "-" })
9948
- ] })
9949
- ] });
10029
+ const hasError = !!error || !!appliedValidation && !appliedValidation.is_eligible;
10030
+ const errorMessage = error ? error.message : appliedValidation && !appliedValidation.is_eligible ? appliedValidation.ineligibility_reason ?? "This code is not valid." : void 0;
10031
+ return /* @__PURE__ */ jsxs(
10032
+ Field.Root,
10033
+ {
10034
+ "data-cimplify-discount": true,
10035
+ invalid: hasError,
10036
+ disabled: isApplied,
10037
+ className: cn(className, classNames?.root),
10038
+ children: [
10039
+ /* @__PURE__ */ jsxs("div", { "data-cimplify-discount-form": true, children: [
10040
+ /* @__PURE__ */ jsx(
10041
+ Input,
10042
+ {
10043
+ type: "text",
10044
+ value: code,
10045
+ onValueChange: (value) => setCode(value),
10046
+ onKeyDown: handleKeyDown,
10047
+ placeholder,
10048
+ "data-cimplify-discount-input": true,
10049
+ className: classNames?.input,
10050
+ "aria-label": "Discount code"
10051
+ }
10052
+ ),
10053
+ isApplied ? /* @__PURE__ */ jsx(
10054
+ "button",
10055
+ {
10056
+ type: "button",
10057
+ onClick: handleClear,
10058
+ "data-cimplify-discount-clear": true,
10059
+ className: classNames?.button,
10060
+ children: "Remove"
10061
+ }
10062
+ ) : /* @__PURE__ */ jsx(
10063
+ "button",
10064
+ {
10065
+ type: "button",
10066
+ onClick: handleApply,
10067
+ disabled: isValidating || code.trim().length === 0,
10068
+ "data-cimplify-discount-apply": true,
10069
+ className: classNames?.button,
10070
+ children: isValidating ? "Checking..." : "Apply"
10071
+ }
10072
+ )
10073
+ ] }),
10074
+ hasError && errorMessage && /* @__PURE__ */ jsx(
10075
+ Field.Error,
10076
+ {
10077
+ match: true,
10078
+ "data-cimplify-discount-error": true,
10079
+ className: classNames?.error,
10080
+ children: errorMessage
10081
+ }
10082
+ ),
10083
+ isApplied && appliedValidation.discount_amount && /* @__PURE__ */ jsxs(
10084
+ Field.Description,
10085
+ {
10086
+ "data-cimplify-discount-success": true,
10087
+ className: classNames?.success,
10088
+ children: [
10089
+ /* @__PURE__ */ jsx("span", { children: "Discount applied" }),
10090
+ /* @__PURE__ */ jsx(Price, { amount: appliedValidation.discount_amount, prefix: "-" })
10091
+ ]
10092
+ }
10093
+ )
10094
+ ]
10095
+ }
10096
+ );
9950
10097
  }
9951
10098
  function CategoryGrid({
9952
10099
  categories: categoriesProp,
@@ -10393,6 +10540,9 @@ function formatTime(timeStr) {
10393
10540
  }
10394
10541
  return timeStr;
10395
10542
  }
10543
+ function slotToValue(slot) {
10544
+ return `${slot.start_time}|${slot.end_time}`;
10545
+ }
10396
10546
  function SlotPicker({
10397
10547
  slots: slotsProp,
10398
10548
  serviceId,
@@ -10437,29 +10587,49 @@ function SlotPicker({
10437
10587
  );
10438
10588
  }
10439
10589
  const groups = groupByTimeOfDay ? groupSlots(slots) : [{ label: "", slots }];
10440
- return /* @__PURE__ */ jsx("div", { "data-cimplify-slot-picker": true, className: cn(className, classNames?.root), children: groups.map((group) => /* @__PURE__ */ jsxs("div", { "data-cimplify-slot-group": true, className: classNames?.group, children: [
10441
- group.label && /* @__PURE__ */ jsx("div", { "data-cimplify-slot-group-label": true, className: classNames?.groupLabel, children: group.label }),
10442
- group.slots.map((slot) => {
10443
- const isSelected = selectedSlot?.start_time === slot.start_time && selectedSlot?.end_time === slot.end_time;
10444
- return /* @__PURE__ */ jsxs(
10445
- "button",
10446
- {
10447
- type: "button",
10448
- disabled: !slot.is_available,
10449
- onClick: () => slot.is_available && onSlotSelect?.(slot),
10450
- "data-cimplify-slot": true,
10451
- "data-selected": isSelected || void 0,
10452
- "data-unavailable": !slot.is_available || void 0,
10453
- className: classNames?.slot,
10454
- children: [
10455
- /* @__PURE__ */ jsx("span", { "data-cimplify-slot-time": true, className: classNames?.slotTime, children: formatTime(slot.start_time) }),
10456
- showPrice && slot.price && /* @__PURE__ */ jsx("span", { "data-cimplify-slot-price": true, className: classNames?.slotPrice, children: /* @__PURE__ */ jsx(Price, { amount: slot.price }) })
10457
- ]
10458
- },
10459
- `${slot.start_time}-${slot.end_time}`
10460
- );
10461
- })
10462
- ] }, group.label || "all")) });
10590
+ const slotsByValue = /* @__PURE__ */ new Map();
10591
+ for (const slot of slots) {
10592
+ slotsByValue.set(slotToValue(slot), slot);
10593
+ }
10594
+ const selectedValue = selectedSlot ? slotToValue(selectedSlot) : "";
10595
+ return /* @__PURE__ */ jsx(
10596
+ RadioGroup,
10597
+ {
10598
+ "data-cimplify-slot-picker": true,
10599
+ className: cn(className, classNames?.root),
10600
+ value: selectedValue,
10601
+ onValueChange: (value) => {
10602
+ const slot = slotsByValue.get(value);
10603
+ if (slot?.is_available) {
10604
+ onSlotSelect?.(slot);
10605
+ }
10606
+ },
10607
+ children: groups.map((group) => /* @__PURE__ */ jsxs("div", { "data-cimplify-slot-group": true, className: classNames?.group, children: [
10608
+ group.label && /* @__PURE__ */ jsx("div", { "data-cimplify-slot-group-label": true, className: classNames?.groupLabel, children: group.label }),
10609
+ group.slots.map((slot) => {
10610
+ const value = slotToValue(slot);
10611
+ const isSelected = selectedSlot?.start_time === slot.start_time && selectedSlot?.end_time === slot.end_time;
10612
+ return /* @__PURE__ */ jsxs(
10613
+ Radio.Root,
10614
+ {
10615
+ value,
10616
+ disabled: !slot.is_available,
10617
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
10618
+ "data-cimplify-slot": true,
10619
+ "data-selected": isSelected || void 0,
10620
+ "data-unavailable": !slot.is_available || void 0,
10621
+ className: classNames?.slot,
10622
+ children: [
10623
+ /* @__PURE__ */ jsx("span", { "data-cimplify-slot-time": true, className: classNames?.slotTime, children: formatTime(slot.start_time) }),
10624
+ showPrice && slot.price && /* @__PURE__ */ jsx("span", { "data-cimplify-slot-price": true, className: classNames?.slotPrice, children: /* @__PURE__ */ jsx(Price, { amount: slot.price }) })
10625
+ ]
10626
+ },
10627
+ value
10628
+ );
10629
+ })
10630
+ ] }, group.label || "all"))
10631
+ }
10632
+ );
10463
10633
  }
10464
10634
  function formatDate(dateStr) {
10465
10635
  const date = /* @__PURE__ */ new Date(dateStr + "T00:00:00");
@@ -10522,8 +10692,10 @@ function DateSlotPicker({
10522
10692
  const handleNext = useCallback(() => {
10523
10693
  setOffset((prev) => prev + daysToShow);
10524
10694
  }, [daysToShow]);
10525
- const handleDateSelect = useCallback((date) => {
10526
- setSelectedDate(date);
10695
+ const handleDateChange = useCallback((value) => {
10696
+ if (typeof value === "string") {
10697
+ setSelectedDate(value);
10698
+ }
10527
10699
  }, []);
10528
10700
  const handleSlotSelect = useCallback(
10529
10701
  (slot) => {
@@ -10531,72 +10703,79 @@ function DateSlotPicker({
10531
10703
  },
10532
10704
  [onSlotSelect, selectedDate]
10533
10705
  );
10534
- return /* @__PURE__ */ jsxs("div", { "data-cimplify-date-slot-picker": true, className: cn(className, classNames?.root), children: [
10535
- /* @__PURE__ */ jsxs("div", { "data-cimplify-date-nav": true, className: classNames?.nav, children: [
10536
- /* @__PURE__ */ jsx(
10537
- "button",
10538
- {
10539
- type: "button",
10540
- onClick: handlePrev,
10541
- disabled: offset === 0,
10542
- "data-cimplify-date-nav-prev": true,
10543
- className: classNames?.navButton,
10544
- children: "\u2190"
10545
- }
10546
- ),
10547
- /* @__PURE__ */ jsx(
10548
- "button",
10549
- {
10550
- type: "button",
10551
- onClick: handleNext,
10552
- "data-cimplify-date-nav-next": true,
10553
- className: classNames?.navButton,
10554
- children: "\u2192"
10555
- }
10556
- )
10557
- ] }),
10558
- /* @__PURE__ */ jsx("div", { "data-cimplify-date-strip": true, className: classNames?.dateStrip, role: "tablist", children: dateRange.dates.map((date) => {
10559
- const dayInfo = availabilityMap.get(date);
10560
- const hasAvailability = dayInfo?.has_availability !== false;
10561
- const isSelected = selectedDate === date;
10562
- return /* @__PURE__ */ jsx(
10563
- "button",
10564
- {
10565
- type: "button",
10566
- role: "tab",
10567
- "aria-selected": isSelected,
10568
- onClick: () => handleDateSelect(date),
10569
- "data-cimplify-date-button": true,
10570
- "data-selected": isSelected || void 0,
10571
- "data-available": hasAvailability || void 0,
10572
- "data-fully-booked": !hasAvailability || void 0,
10573
- className: classNames?.dateButton,
10574
- children: formatDate(date)
10575
- },
10576
- date
10577
- );
10578
- }) }),
10579
- availabilityLoading && /* @__PURE__ */ jsx(
10580
- "div",
10581
- {
10582
- "data-cimplify-date-slot-loading": true,
10583
- "aria-busy": "true",
10584
- className: classNames?.loading
10585
- }
10586
- ),
10587
- /* @__PURE__ */ jsx("div", { "data-cimplify-date-slots": true, className: classNames?.slots, children: /* @__PURE__ */ jsx(
10588
- SlotPicker,
10589
- {
10590
- serviceId,
10591
- date: selectedDate,
10592
- participantCount,
10593
- selectedSlot,
10594
- onSlotSelect: handleSlotSelect,
10595
- showPrice
10596
- }
10597
- ) })
10598
- ] });
10706
+ return /* @__PURE__ */ jsxs(
10707
+ Tabs.Root,
10708
+ {
10709
+ value: selectedDate,
10710
+ onValueChange: handleDateChange,
10711
+ "data-cimplify-date-slot-picker": true,
10712
+ className: cn(className, classNames?.root),
10713
+ children: [
10714
+ /* @__PURE__ */ jsxs("div", { "data-cimplify-date-nav": true, className: classNames?.nav, children: [
10715
+ /* @__PURE__ */ jsx(
10716
+ "button",
10717
+ {
10718
+ type: "button",
10719
+ onClick: handlePrev,
10720
+ disabled: offset === 0,
10721
+ "data-cimplify-date-nav-prev": true,
10722
+ className: classNames?.navButton,
10723
+ children: "\u2190"
10724
+ }
10725
+ ),
10726
+ /* @__PURE__ */ jsx(
10727
+ "button",
10728
+ {
10729
+ type: "button",
10730
+ onClick: handleNext,
10731
+ "data-cimplify-date-nav-next": true,
10732
+ className: classNames?.navButton,
10733
+ children: "\u2192"
10734
+ }
10735
+ )
10736
+ ] }),
10737
+ /* @__PURE__ */ jsx(Tabs.List, { "data-cimplify-date-strip": true, className: classNames?.dateStrip, children: dateRange.dates.map((date) => {
10738
+ const dayInfo = availabilityMap.get(date);
10739
+ const hasAvailability = dayInfo?.has_availability !== false;
10740
+ const isSelected = selectedDate === date;
10741
+ return /* @__PURE__ */ jsx(
10742
+ Tabs.Tab,
10743
+ {
10744
+ value: date,
10745
+ "data-cimplify-date-button": true,
10746
+ "data-selected": isSelected || void 0,
10747
+ "data-available": hasAvailability || void 0,
10748
+ "data-fully-booked": !hasAvailability || void 0,
10749
+ className: classNames?.dateButton,
10750
+ children: formatDate(date)
10751
+ },
10752
+ date
10753
+ );
10754
+ }) }),
10755
+ availabilityLoading && /* @__PURE__ */ jsx(
10756
+ "div",
10757
+ {
10758
+ "data-cimplify-date-slot-loading": true,
10759
+ "aria-busy": "true",
10760
+ className: classNames?.loading
10761
+ }
10762
+ ),
10763
+ /* @__PURE__ */ jsx("div", { "data-cimplify-date-slots": true, className: classNames?.slots, children: /* @__PURE__ */ jsx(
10764
+ SlotPicker,
10765
+ {
10766
+ serviceId,
10767
+ date: selectedDate,
10768
+ participantCount,
10769
+ selectedSlot,
10770
+ onSlotSelect: handleSlotSelect,
10771
+ showPrice
10772
+ }
10773
+ ) })
10774
+ ]
10775
+ }
10776
+ );
10599
10777
  }
10778
+ var ANY_VALUE = "__any__";
10600
10779
  function StaffPicker({
10601
10780
  staff,
10602
10781
  selectedStaffId,
@@ -10606,44 +10785,56 @@ function StaffPicker({
10606
10785
  className,
10607
10786
  classNames
10608
10787
  }) {
10609
- return /* @__PURE__ */ jsxs("div", { "data-cimplify-staff-picker": true, className: cn(className, classNames?.root), children: [
10610
- showAnyOption && /* @__PURE__ */ jsx(
10611
- "button",
10612
- {
10613
- type: "button",
10614
- onClick: () => onStaffSelect?.(null),
10615
- "data-cimplify-staff-option": true,
10616
- "data-selected": selectedStaffId === null || void 0,
10617
- "data-any": true,
10618
- className: classNames?.option,
10619
- children: /* @__PURE__ */ jsx("span", { "data-cimplify-staff-name": true, className: classNames?.name, children: anyLabel })
10620
- }
10621
- ),
10622
- staff.map((member) => /* @__PURE__ */ jsxs(
10623
- "button",
10624
- {
10625
- type: "button",
10626
- onClick: () => onStaffSelect?.(member.id),
10627
- "data-cimplify-staff-option": true,
10628
- "data-selected": selectedStaffId === member.id || void 0,
10629
- className: classNames?.option,
10630
- children: [
10631
- member.avatar_url && /* @__PURE__ */ jsx(
10632
- "img",
10633
- {
10634
- src: member.avatar_url,
10635
- alt: member.name,
10636
- "data-cimplify-staff-avatar": true,
10637
- className: classNames?.avatar
10638
- }
10639
- ),
10640
- /* @__PURE__ */ jsx("span", { "data-cimplify-staff-name": true, className: classNames?.name, children: member.name }),
10641
- member.bio && /* @__PURE__ */ jsx("span", { "data-cimplify-staff-bio": true, className: classNames?.bio, children: member.bio })
10642
- ]
10788
+ const groupValue = selectedStaffId === null ? ANY_VALUE : selectedStaffId ?? "";
10789
+ return /* @__PURE__ */ jsxs(
10790
+ RadioGroup,
10791
+ {
10792
+ "data-cimplify-staff-picker": true,
10793
+ className: cn(className, classNames?.root),
10794
+ value: groupValue,
10795
+ onValueChange: (value) => {
10796
+ onStaffSelect?.(value === ANY_VALUE ? null : value);
10643
10797
  },
10644
- member.id
10645
- ))
10646
- ] });
10798
+ children: [
10799
+ showAnyOption && /* @__PURE__ */ jsx(
10800
+ Radio.Root,
10801
+ {
10802
+ value: ANY_VALUE,
10803
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
10804
+ "data-cimplify-staff-option": true,
10805
+ "data-selected": selectedStaffId === null || void 0,
10806
+ "data-any": true,
10807
+ className: classNames?.option,
10808
+ children: /* @__PURE__ */ jsx("span", { "data-cimplify-staff-name": true, className: classNames?.name, children: anyLabel })
10809
+ }
10810
+ ),
10811
+ staff.map((member) => /* @__PURE__ */ jsxs(
10812
+ Radio.Root,
10813
+ {
10814
+ value: member.id,
10815
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
10816
+ "data-cimplify-staff-option": true,
10817
+ "data-selected": selectedStaffId === member.id || void 0,
10818
+ className: classNames?.option,
10819
+ children: [
10820
+ member.avatar_url && /* @__PURE__ */ jsx(
10821
+ "img",
10822
+ {
10823
+ src: member.avatar_url,
10824
+ alt: member.name,
10825
+ "data-cimplify-staff-avatar": true,
10826
+ className: classNames?.avatar
10827
+ }
10828
+ ),
10829
+ /* @__PURE__ */ jsx("span", { "data-cimplify-staff-name": true, className: classNames?.name, children: member.name }),
10830
+ member.bio && /* @__PURE__ */ jsx("span", { "data-cimplify-staff-bio": true, className: classNames?.bio, children: member.bio })
10831
+ ]
10832
+ },
10833
+ member.id
10834
+ ))
10835
+ ]
10836
+ }
10837
+ );
10647
10838
  }
10648
10839
  var STATUS_LABELS3 = {
10649
10840
  pending: "Pending",
@@ -11315,10 +11506,10 @@ function OrderDetailPage({
11315
11506
  ] });
11316
11507
  }
11317
11508
  var STATUS_FILTERS = [
11318
- { label: "All", value: void 0 },
11319
- { label: "Active", value: "confirmed" },
11320
- { label: "Completed", value: "completed" },
11321
- { label: "Cancelled", value: "cancelled" }
11509
+ { label: "All", value: void 0, tabValue: "all" },
11510
+ { label: "Active", value: "confirmed", tabValue: "confirmed" },
11511
+ { label: "Completed", value: "completed", tabValue: "completed" },
11512
+ { label: "Cancelled", value: "cancelled", tabValue: "cancelled" }
11322
11513
  ];
11323
11514
  function OrderHistoryPage({
11324
11515
  title = "Order History",
@@ -11332,6 +11523,10 @@ function OrderHistoryPage({
11332
11523
  }) {
11333
11524
  const [statusFilter, setStatusFilter] = useState(void 0);
11334
11525
  const [selectedOrder, setSelectedOrder] = useState(null);
11526
+ const handleTabChange = useCallback((value) => {
11527
+ const filter = STATUS_FILTERS.find((f) => f.tabValue === value);
11528
+ setStatusFilter(filter?.value);
11529
+ }, []);
11335
11530
  const handleOrderClick = useCallback(
11336
11531
  (order) => {
11337
11532
  if (onOrderNavigate) {
@@ -11345,6 +11540,7 @@ function OrderHistoryPage({
11345
11540
  const handleBack = useCallback(() => {
11346
11541
  setSelectedOrder(null);
11347
11542
  }, []);
11543
+ const activeTabValue = STATUS_FILTERS.find((f) => f.value === statusFilter)?.tabValue ?? "all";
11348
11544
  if (selectedOrder && !onOrderNavigate) {
11349
11545
  return /* @__PURE__ */ jsx("div", { "data-cimplify-order-history-page": true, className: cn(className, classNames?.root), children: /* @__PURE__ */ jsxs("div", { "data-cimplify-order-history-detail": true, className: classNames?.detail, children: [
11350
11546
  /* @__PURE__ */ jsx(
@@ -11362,20 +11558,17 @@ function OrderHistoryPage({
11362
11558
  }
11363
11559
  return /* @__PURE__ */ jsxs("div", { "data-cimplify-order-history-page": true, className: cn(className, classNames?.root), children: [
11364
11560
  /* @__PURE__ */ jsx("div", { "data-cimplify-order-history-header": true, className: classNames?.header, children: /* @__PURE__ */ jsx("h1", { "data-cimplify-order-history-title": true, className: classNames?.title, children: title }) }),
11365
- showFilters && /* @__PURE__ */ jsx("div", { "data-cimplify-order-history-filters": true, className: classNames?.filters, role: "tablist", children: STATUS_FILTERS.map((filter) => /* @__PURE__ */ jsx(
11366
- "button",
11561
+ showFilters && /* @__PURE__ */ jsx(Tabs.Root, { value: activeTabValue, onValueChange: handleTabChange, children: /* @__PURE__ */ jsx(Tabs.List, { "data-cimplify-order-history-filters": true, className: classNames?.filters, children: STATUS_FILTERS.map((filter) => /* @__PURE__ */ jsx(
11562
+ Tabs.Tab,
11367
11563
  {
11368
- type: "button",
11369
- role: "tab",
11370
- "aria-selected": statusFilter === filter.value,
11371
- onClick: () => setStatusFilter(filter.value),
11564
+ value: filter.tabValue,
11372
11565
  "data-cimplify-order-filter": true,
11373
11566
  "data-selected": statusFilter === filter.value || void 0,
11374
11567
  className: classNames?.filterButton,
11375
11568
  children: filter.label
11376
11569
  },
11377
- filter.label
11378
- )) }),
11570
+ filter.tabValue
11571
+ )) }) }),
11379
11572
  /* @__PURE__ */ jsx("div", { "data-cimplify-order-history-list": true, className: classNames?.list, children: /* @__PURE__ */ jsx(
11380
11573
  OrderHistory,
11381
11574
  {
@@ -11403,7 +11596,7 @@ function SearchPage({
11403
11596
  /* @__PURE__ */ jsx("div", { "data-cimplify-search-page-header": true, className: classNames?.header, children: /* @__PURE__ */ jsx("h1", { "data-cimplify-search-page-title": true, className: classNames?.title, children: title }) }),
11404
11597
  /* @__PURE__ */ jsxs("div", { "data-cimplify-search-page-input": true, className: classNames?.inputContainer, children: [
11405
11598
  /* @__PURE__ */ jsx(
11406
- "input",
11599
+ Input,
11407
11600
  {
11408
11601
  type: "search",
11409
11602
  value: query,
@@ -11745,20 +11938,24 @@ function BookingsPage({
11745
11938
  }
11746
11939
  return /* @__PURE__ */ jsxs("div", { "data-cimplify-bookings-page": true, className: cn(className, classNames?.root), children: [
11747
11940
  /* @__PURE__ */ jsx("div", { "data-cimplify-bookings-header": true, className: classNames?.header, children: /* @__PURE__ */ jsx("h1", { "data-cimplify-bookings-title": true, className: classNames?.title, children: title }) }),
11748
- showFilters && /* @__PURE__ */ jsx("div", { "data-cimplify-bookings-filters": true, className: classNames?.filters, role: "tablist", children: BOOKING_FILTERS.map((f) => /* @__PURE__ */ jsx(
11749
- "button",
11941
+ showFilters && /* @__PURE__ */ jsx(
11942
+ Tabs.Root,
11750
11943
  {
11751
- type: "button",
11752
- role: "tab",
11753
- "aria-selected": filter === f.value,
11754
- onClick: () => setFilter(f.value),
11755
- "data-cimplify-booking-filter": true,
11756
- "data-selected": filter === f.value || void 0,
11757
- className: classNames?.filterButton,
11758
- children: f.label
11759
- },
11760
- f.value
11761
- )) }),
11944
+ value: filter,
11945
+ onValueChange: (value) => setFilter(value),
11946
+ children: /* @__PURE__ */ jsx(Tabs.List, { "data-cimplify-bookings-filters": true, className: classNames?.filters, children: BOOKING_FILTERS.map((f) => /* @__PURE__ */ jsx(
11947
+ Tabs.Tab,
11948
+ {
11949
+ value: f.value,
11950
+ "data-cimplify-booking-filter": true,
11951
+ "data-selected": filter === f.value || void 0,
11952
+ className: classNames?.filterButton,
11953
+ children: f.label
11954
+ },
11955
+ f.value
11956
+ )) })
11957
+ }
11958
+ ),
11762
11959
  /* @__PURE__ */ jsx("div", { "data-cimplify-bookings-list": true, className: classNames?.list, children: /* @__PURE__ */ jsx(
11763
11960
  BookingList,
11764
11961
  {