@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.js CHANGED
@@ -3,8 +3,15 @@
3
3
 
4
4
  var React3 = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
+ var numberField = require('@base-ui/react/number-field');
6
7
  var clsx = require('clsx');
7
8
  var tailwindMerge = require('tailwind-merge');
9
+ var radioGroup = require('@base-ui/react/radio-group');
10
+ var radio = require('@base-ui/react/radio');
11
+ var checkbox = require('@base-ui/react/checkbox');
12
+ var field = require('@base-ui/react/field');
13
+ var input = require('@base-ui/react/input');
14
+ var tabs = require('@base-ui/react/tabs');
8
15
 
9
16
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
17
 
@@ -7830,52 +7837,60 @@ function QuantitySelector({
7830
7837
  className,
7831
7838
  classNames
7832
7839
  }) {
7833
- return /* @__PURE__ */ jsxRuntime.jsxs(
7834
- "div",
7840
+ return /* @__PURE__ */ jsxRuntime.jsx(
7841
+ numberField.NumberField.Root,
7835
7842
  {
7836
- "data-cimplify-quantity": true,
7837
- className: cn("inline-flex items-center gap-3 border border-border px-2", className, classNames?.root),
7838
- children: [
7839
- /* @__PURE__ */ jsxRuntime.jsx(
7840
- "button",
7841
- {
7842
- type: "button",
7843
- onClick: () => onChange(Math.max(min, value - 1)),
7844
- disabled: value <= min,
7845
- "aria-label": "Decrease quantity",
7846
- "data-cimplify-quantity-decrement": true,
7847
- className: cn(
7848
- "w-10 h-10 flex items-center justify-center hover:text-primary transition-colors disabled:opacity-30",
7849
- classNames?.button
7843
+ value,
7844
+ onValueChange: (val) => {
7845
+ if (val != null) {
7846
+ onChange(val);
7847
+ }
7848
+ },
7849
+ min,
7850
+ max,
7851
+ step: 1,
7852
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
7853
+ numberField.NumberField.Group,
7854
+ {
7855
+ "data-cimplify-quantity": true,
7856
+ className: cn("inline-flex items-center gap-3 border border-border px-2", className, classNames?.root),
7857
+ children: [
7858
+ /* @__PURE__ */ jsxRuntime.jsx(
7859
+ numberField.NumberField.Decrement,
7860
+ {
7861
+ "aria-label": "Decrease quantity",
7862
+ "data-cimplify-quantity-decrement": true,
7863
+ className: cn(
7864
+ "w-10 h-10 flex items-center justify-center hover:text-primary transition-colors disabled:opacity-30",
7865
+ classNames?.button
7866
+ ),
7867
+ children: "\u2212"
7868
+ }
7850
7869
  ),
7851
- children: "\u2212"
7852
- }
7853
- ),
7854
- /* @__PURE__ */ jsxRuntime.jsx(
7855
- "span",
7856
- {
7857
- "data-cimplify-quantity-value": true,
7858
- "aria-live": "polite",
7859
- className: cn("w-8 text-center font-medium", classNames?.value),
7860
- children: value
7861
- }
7862
- ),
7863
- /* @__PURE__ */ jsxRuntime.jsx(
7864
- "button",
7865
- {
7866
- type: "button",
7867
- onClick: () => onChange(max != null ? Math.min(max, value + 1) : value + 1),
7868
- disabled: max != null && value >= max,
7869
- "aria-label": "Increase quantity",
7870
- "data-cimplify-quantity-increment": true,
7871
- className: cn(
7872
- "w-10 h-10 flex items-center justify-center hover:text-primary transition-colors disabled:opacity-30",
7873
- classNames?.button
7870
+ /* @__PURE__ */ jsxRuntime.jsx(
7871
+ numberField.NumberField.Input,
7872
+ {
7873
+ "data-cimplify-quantity-value": true,
7874
+ "aria-live": "polite",
7875
+ readOnly: true,
7876
+ 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)
7877
+ }
7874
7878
  ),
7875
- children: "+"
7876
- }
7877
- )
7878
- ]
7879
+ /* @__PURE__ */ jsxRuntime.jsx(
7880
+ numberField.NumberField.Increment,
7881
+ {
7882
+ "aria-label": "Increase quantity",
7883
+ "data-cimplify-quantity-increment": true,
7884
+ className: cn(
7885
+ "w-10 h-10 flex items-center justify-center hover:text-primary transition-colors disabled:opacity-30",
7886
+ classNames?.button
7887
+ ),
7888
+ children: "+"
7889
+ }
7890
+ )
7891
+ ]
7892
+ }
7893
+ )
7879
7894
  }
7880
7895
  );
7881
7896
  }
@@ -7928,6 +7943,7 @@ function VariantSelector({
7928
7943
  }) {
7929
7944
  const [axisSelections, setAxisSelections] = React3.useState({});
7930
7945
  const initialized = React3.useRef(false);
7946
+ const idPrefix = React3.useId();
7931
7947
  React3.useEffect(() => {
7932
7948
  initialized.current = false;
7933
7949
  }, [variants]);
@@ -7964,106 +7980,126 @@ function VariantSelector({
7964
7980
  }
7965
7981
  const basePriceNum = basePrice != null ? parsePrice(basePrice) : 0;
7966
7982
  if (variantAxes && variantAxes.length > 0) {
7967
- return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-variant-selector": true, className: cn("space-y-5", className, classNames?.root), children: variantAxes.map((axis) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-variant-axis": true, children: [
7968
- /* @__PURE__ */ jsxRuntime.jsx(
7969
- "label",
7970
- {
7971
- "data-cimplify-variant-axis-label": true,
7972
- className: cn("block text-xs font-medium uppercase tracking-wider text-muted-foreground mb-3", classNames?.axisLabel),
7973
- children: axis.name
7974
- }
7975
- ),
7976
- /* @__PURE__ */ jsxRuntime.jsx(
7977
- "div",
7978
- {
7979
- "data-cimplify-variant-axis-options": true,
7980
- className: cn("flex flex-wrap gap-2", classNames?.axisOptions),
7981
- children: axis.values.map((value) => {
7982
- const isSelected = axisSelections[axis.id] === value.id;
7983
- return /* @__PURE__ */ jsxRuntime.jsx(
7984
- "button",
7985
- {
7986
- type: "button",
7987
- "aria-selected": isSelected,
7988
- onClick: () => {
7989
- setAxisSelections((prev) => ({
7990
- ...prev,
7991
- [axis.id]: value.id
7992
- }));
7983
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-variant-selector": true, className: cn("space-y-5", className, classNames?.root), children: variantAxes.map((axis) => {
7984
+ const labelId = `${idPrefix}-axis-${axis.id}`;
7985
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-variant-axis": true, children: [
7986
+ /* @__PURE__ */ jsxRuntime.jsx(
7987
+ "label",
7988
+ {
7989
+ id: labelId,
7990
+ "data-cimplify-variant-axis-label": true,
7991
+ className: cn("block text-xs font-medium uppercase tracking-wider text-muted-foreground mb-3", classNames?.axisLabel),
7992
+ children: axis.name
7993
+ }
7994
+ ),
7995
+ /* @__PURE__ */ jsxRuntime.jsx(
7996
+ radioGroup.RadioGroup,
7997
+ {
7998
+ "aria-labelledby": labelId,
7999
+ value: axisSelections[axis.id] ?? "",
8000
+ onValueChange: (value) => {
8001
+ setAxisSelections((prev) => ({
8002
+ ...prev,
8003
+ [axis.id]: value
8004
+ }));
8005
+ },
8006
+ "data-cimplify-variant-axis-options": true,
8007
+ className: cn("flex flex-wrap gap-2", classNames?.axisOptions),
8008
+ children: axis.values.map((value) => {
8009
+ const isSelected = axisSelections[axis.id] === value.id;
8010
+ return /* @__PURE__ */ jsxRuntime.jsx(
8011
+ radio.Radio.Root,
8012
+ {
8013
+ value: value.id,
8014
+ render: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button" }),
8015
+ "data-cimplify-variant-option": true,
8016
+ "data-selected": isSelected || void 0,
8017
+ className: cn(
8018
+ "px-4 py-2 border text-sm font-medium transition-colors border-border hover:border-primary/50",
8019
+ isSelected && "bg-primary text-primary-foreground border-primary",
8020
+ isSelected ? classNames?.optionSelected : classNames?.option
8021
+ ),
8022
+ children: value.name
7993
8023
  },
7994
- "data-cimplify-variant-option": true,
7995
- "data-selected": isSelected || void 0,
7996
- className: cn(
7997
- "px-4 py-2 border text-sm font-medium transition-colors border-border hover:border-primary/50",
7998
- isSelected && "bg-primary text-primary-foreground border-primary",
7999
- isSelected ? classNames?.optionSelected : classNames?.option
8000
- ),
8001
- children: value.name
8002
- },
8003
- value.id
8004
- );
8005
- })
8006
- }
8007
- )
8008
- ] }, axis.id)) });
8024
+ value.id
8025
+ );
8026
+ })
8027
+ }
8028
+ )
8029
+ ] }, axis.id);
8030
+ }) });
8009
8031
  }
8032
+ const listLabelId = `${idPrefix}-variant-list`;
8010
8033
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-variant-selector": true, className: cn("space-y-5", className, classNames?.root), children: [
8011
8034
  /* @__PURE__ */ jsxRuntime.jsx(
8012
8035
  "label",
8013
8036
  {
8037
+ id: listLabelId,
8014
8038
  "data-cimplify-variant-list-label": true,
8015
8039
  className: cn("block text-xs font-medium uppercase tracking-wider text-muted-foreground mb-3", classNames?.listLabel),
8016
8040
  children: "Options"
8017
8041
  }
8018
8042
  ),
8019
- /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-variant-list": true, className: cn("space-y-2", classNames?.list), children: variants.map((variant) => {
8020
- const isSelected = selectedVariantId === variant.id;
8021
- const adjustment = parsePrice(variant.price_adjustment);
8022
- const effectivePrice = basePriceNum + adjustment;
8023
- return /* @__PURE__ */ jsxRuntime.jsxs(
8024
- "button",
8025
- {
8026
- type: "button",
8027
- "aria-selected": isSelected,
8028
- onClick: () => onVariantChange(variant.id, variant),
8029
- "data-cimplify-variant-option": true,
8030
- "data-selected": isSelected || void 0,
8031
- className: cn(
8032
- "w-full flex items-center justify-between px-4 py-3 border transition-colors border-border hover:border-primary/50",
8033
- isSelected && "bg-primary/5 border-primary",
8034
- isSelected ? classNames?.optionSelected : classNames?.option
8035
- ),
8036
- children: [
8037
- /* @__PURE__ */ jsxRuntime.jsx(
8038
- "span",
8039
- {
8040
- "data-cimplify-variant-name": true,
8041
- className: cn("font-medium", isSelected && "text-primary", classNames?.name),
8042
- children: getVariantDisplayName(variant, productName)
8043
- }
8044
- ),
8045
- /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-variant-pricing": true, className: cn("text-sm", classNames?.pricing), children: [
8046
- adjustment !== 0 && /* @__PURE__ */ jsxRuntime.jsxs(
8047
- "span",
8048
- {
8049
- "data-cimplify-variant-adjustment": true,
8050
- className: cn(
8051
- adjustment > 0 ? "text-muted-foreground" : "text-green-600",
8052
- classNames?.adjustment
8053
- ),
8054
- children: [
8055
- adjustment > 0 ? "+" : "",
8056
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: variant.price_adjustment })
8057
- ]
8058
- }
8059
- ),
8060
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: effectivePrice, className: "text-muted-foreground" })
8061
- ] })
8062
- ]
8043
+ /* @__PURE__ */ jsxRuntime.jsx(
8044
+ radioGroup.RadioGroup,
8045
+ {
8046
+ "aria-labelledby": listLabelId,
8047
+ value: selectedVariantId ?? "",
8048
+ onValueChange: (value) => {
8049
+ const variant = variants.find((v) => v.id === value);
8050
+ onVariantChange(variant?.id, variant);
8063
8051
  },
8064
- variant.id
8065
- );
8066
- }) })
8052
+ "data-cimplify-variant-list": true,
8053
+ className: cn("space-y-2", classNames?.list),
8054
+ children: variants.map((variant) => {
8055
+ const isSelected = selectedVariantId === variant.id;
8056
+ const adjustment = parsePrice(variant.price_adjustment);
8057
+ const effectivePrice = basePriceNum + adjustment;
8058
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8059
+ radio.Radio.Root,
8060
+ {
8061
+ value: variant.id,
8062
+ render: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button" }),
8063
+ "data-cimplify-variant-option": true,
8064
+ "data-selected": isSelected || void 0,
8065
+ className: cn(
8066
+ "w-full flex items-center justify-between px-4 py-3 border transition-colors border-border hover:border-primary/50",
8067
+ isSelected && "bg-primary/5 border-primary",
8068
+ isSelected ? classNames?.optionSelected : classNames?.option
8069
+ ),
8070
+ children: [
8071
+ /* @__PURE__ */ jsxRuntime.jsx(
8072
+ "span",
8073
+ {
8074
+ "data-cimplify-variant-name": true,
8075
+ className: cn("font-medium", isSelected && "text-primary", classNames?.name),
8076
+ children: getVariantDisplayName(variant, productName)
8077
+ }
8078
+ ),
8079
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-cimplify-variant-pricing": true, className: cn("text-sm", classNames?.pricing), children: [
8080
+ adjustment !== 0 && /* @__PURE__ */ jsxRuntime.jsxs(
8081
+ "span",
8082
+ {
8083
+ "data-cimplify-variant-adjustment": true,
8084
+ className: cn(
8085
+ adjustment > 0 ? "text-muted-foreground" : "text-green-600",
8086
+ classNames?.adjustment
8087
+ ),
8088
+ children: [
8089
+ adjustment > 0 ? "+" : "",
8090
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: variant.price_adjustment })
8091
+ ]
8092
+ }
8093
+ ),
8094
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: effectivePrice, className: "text-muted-foreground" })
8095
+ ] })
8096
+ ]
8097
+ },
8098
+ variant.id
8099
+ );
8100
+ })
8101
+ }
8102
+ )
8067
8103
  ] });
8068
8104
  }
8069
8105
  function AddOnSelector({
@@ -8077,8 +8113,8 @@ function AddOnSelector({
8077
8113
  (optionId) => selectedOptions.includes(optionId),
8078
8114
  [selectedOptions]
8079
8115
  );
8080
- const toggleOption = React3.useCallback(
8081
- (addOn, optionId) => {
8116
+ const handleCheckedChange = React3.useCallback(
8117
+ (addOn, optionId, checked) => {
8082
8118
  const isSelected = selectedOptions.includes(optionId);
8083
8119
  if (addOn.is_mutually_exclusive || !addOn.is_multiple_allowed) {
8084
8120
  const groupOptionIds = new Set(addOn.options.map((o) => o.id));
@@ -8114,7 +8150,6 @@ function AddOnSelector({
8114
8150
  (id) => addOn.options.some((o) => o.id === id)
8115
8151
  ).length;
8116
8152
  const minMet = !addOn.min_selections || currentSelections >= addOn.min_selections;
8117
- const isSingleSelect = addOn.is_mutually_exclusive || !addOn.is_multiple_allowed;
8118
8153
  return /* @__PURE__ */ jsxRuntime.jsxs(
8119
8154
  "div",
8120
8155
  {
@@ -8177,12 +8212,12 @@ function AddOnSelector({
8177
8212
  children: addOn.options.map((option) => {
8178
8213
  const isSelected = isOptionSelected(option.id);
8179
8214
  return /* @__PURE__ */ jsxRuntime.jsxs(
8180
- "button",
8215
+ checkbox.Checkbox.Root,
8181
8216
  {
8182
- type: "button",
8183
- role: isSingleSelect ? "radio" : "checkbox",
8184
- "aria-checked": isSelected,
8185
- onClick: () => toggleOption(addOn, option.id),
8217
+ checked: isSelected,
8218
+ onCheckedChange: (checked) => handleCheckedChange(addOn, option.id, checked),
8219
+ value: option.id,
8220
+ render: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button" }),
8186
8221
  "data-cimplify-addon-option": true,
8187
8222
  "data-selected": isSelected || void 0,
8188
8223
  className: cn(
@@ -8191,6 +8226,13 @@ function AddOnSelector({
8191
8226
  isSelected ? classNames?.optionSelected : classNames?.option
8192
8227
  ),
8193
8228
  children: [
8229
+ /* @__PURE__ */ jsxRuntime.jsx(
8230
+ checkbox.Checkbox.Indicator,
8231
+ {
8232
+ className: "hidden",
8233
+ keepMounted: false
8234
+ }
8235
+ ),
8194
8236
  /* @__PURE__ */ jsxRuntime.jsx(
8195
8237
  "span",
8196
8238
  {
@@ -8354,11 +8396,13 @@ function BundleComponentCard({
8354
8396
  onVariantChange,
8355
8397
  classNames
8356
8398
  }) {
8399
+ const idPrefix = React3.useId();
8357
8400
  const showVariantPicker = component.allow_variant_choice && component.available_variants.length > 1;
8358
8401
  const displayPrice = React3.useMemo(
8359
8402
  () => getComponentPrice(component, selectedVariantId),
8360
8403
  [component, selectedVariantId]
8361
8404
  );
8405
+ const labelId = `${idPrefix}-bundle-component-${component.id}`;
8362
8406
  return /* @__PURE__ */ jsxRuntime.jsxs(
8363
8407
  "div",
8364
8408
  {
@@ -8386,6 +8430,7 @@ function BundleComponentCard({
8386
8430
  /* @__PURE__ */ jsxRuntime.jsx(
8387
8431
  "span",
8388
8432
  {
8433
+ id: labelId,
8389
8434
  "data-cimplify-bundle-component-name": true,
8390
8435
  className: cn("font-medium text-sm", classNames?.componentName),
8391
8436
  children: component.product_name
@@ -8397,19 +8442,23 @@ function BundleComponentCard({
8397
8442
  }
8398
8443
  ),
8399
8444
  showVariantPicker && /* @__PURE__ */ jsxRuntime.jsx(
8400
- "div",
8445
+ radioGroup.RadioGroup,
8401
8446
  {
8447
+ "aria-labelledby": labelId,
8448
+ value: selectedVariantId ?? "",
8449
+ onValueChange: (value) => {
8450
+ onVariantChange(value);
8451
+ },
8402
8452
  "data-cimplify-bundle-variant-picker": true,
8403
8453
  className: cn("mt-3 flex flex-wrap gap-2", classNames?.variantPicker),
8404
8454
  children: component.available_variants.map((variant) => {
8405
8455
  const isSelected = selectedVariantId === variant.id;
8406
8456
  const adjustment = parsePrice(variant.price_adjustment);
8407
8457
  return /* @__PURE__ */ jsxRuntime.jsxs(
8408
- "button",
8458
+ radio.Radio.Root,
8409
8459
  {
8410
- type: "button",
8411
- "aria-pressed": isSelected,
8412
- onClick: () => onVariantChange(variant.id),
8460
+ value: variant.id,
8461
+ render: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button" }),
8413
8462
  "data-cimplify-bundle-variant-option": true,
8414
8463
  "data-selected": isSelected || void 0,
8415
8464
  className: cn(
@@ -8540,12 +8589,13 @@ function CompositeSelector({
8540
8589
  []
8541
8590
  );
8542
8591
  const updateQuantity = React3.useCallback(
8543
- (group, componentId, delta) => {
8592
+ (group, componentId, newValue) => {
8544
8593
  setGroupSelections((prev) => {
8545
8594
  const groupSels = { ...prev[group.id] || {} };
8546
8595
  const current = groupSels[componentId] || 0;
8547
- const next = Math.max(0, current + delta);
8596
+ const next = Math.max(0, newValue);
8548
8597
  if (next === current) return prev;
8598
+ const delta = next - current;
8549
8599
  if (group.max_quantity_per_component && next > group.max_quantity_per_component) {
8550
8600
  return prev;
8551
8601
  }
@@ -8649,12 +8699,12 @@ function CompositeSelector({
8649
8699
  const isSelected = qty > 0;
8650
8700
  const displayName = component.display_name || component.id;
8651
8701
  return /* @__PURE__ */ jsxRuntime.jsxs(
8652
- "button",
8702
+ checkbox.Checkbox.Root,
8653
8703
  {
8654
- type: "button",
8655
- role: isSingleSelect ? "radio" : "checkbox",
8656
- "aria-checked": isSelected,
8657
- onClick: () => toggleComponent(group, component),
8704
+ checked: isSelected,
8705
+ onCheckedChange: () => toggleComponent(group, component),
8706
+ value: component.id,
8707
+ render: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button" }),
8658
8708
  "data-cimplify-composite-component": true,
8659
8709
  "data-selected": isSelected || void 0,
8660
8710
  className: cn(
@@ -8663,6 +8713,13 @@ function CompositeSelector({
8663
8713
  isSelected ? classNames?.componentSelected : classNames?.component
8664
8714
  ),
8665
8715
  children: [
8716
+ /* @__PURE__ */ jsxRuntime.jsx(
8717
+ checkbox.Checkbox.Indicator,
8718
+ {
8719
+ className: "hidden",
8720
+ keepMounted: false
8721
+ }
8722
+ ),
8666
8723
  /* @__PURE__ */ jsxRuntime.jsxs(
8667
8724
  "div",
8668
8725
  {
@@ -8715,35 +8772,51 @@ function CompositeSelector({
8715
8772
  ]
8716
8773
  }
8717
8774
  ),
8718
- group.allow_quantity && isSelected && /* @__PURE__ */ jsxRuntime.jsxs(
8719
- "span",
8775
+ group.allow_quantity && isSelected && /* @__PURE__ */ jsxRuntime.jsx(
8776
+ numberField.NumberField.Root,
8720
8777
  {
8721
- "data-cimplify-composite-qty": true,
8722
- onClick: (e) => e.stopPropagation(),
8723
- className: cn("flex items-center gap-2", classNames?.qty),
8724
- children: [
8725
- /* @__PURE__ */ jsxRuntime.jsx(
8726
- "button",
8727
- {
8728
- type: "button",
8729
- onClick: () => updateQuantity(group, component.id, -1),
8730
- "aria-label": `Decrease ${displayName} quantity`,
8731
- className: cn("w-6 h-6 border border-border flex items-center justify-center text-xs hover:bg-muted", classNames?.qtyButton),
8732
- children: "\u2212"
8733
- }
8734
- ),
8735
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("text-sm font-medium w-4 text-center", classNames?.qtyValue), children: qty }),
8736
- /* @__PURE__ */ jsxRuntime.jsx(
8737
- "button",
8738
- {
8739
- type: "button",
8740
- onClick: () => updateQuantity(group, component.id, 1),
8741
- "aria-label": `Increase ${displayName} quantity`,
8742
- className: cn("w-6 h-6 border border-border flex items-center justify-center text-xs hover:bg-muted", classNames?.qtyButton),
8743
- children: "+"
8744
- }
8745
- )
8746
- ]
8778
+ value: qty,
8779
+ onValueChange: (val) => {
8780
+ if (val != null) {
8781
+ updateQuantity(group, component.id, val);
8782
+ }
8783
+ },
8784
+ min: 0,
8785
+ max: group.max_quantity_per_component || void 0,
8786
+ step: 1,
8787
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
8788
+ numberField.NumberField.Group,
8789
+ {
8790
+ "data-cimplify-composite-qty": true,
8791
+ onClick: (e) => e.stopPropagation(),
8792
+ className: cn("flex items-center gap-2", classNames?.qty),
8793
+ children: [
8794
+ /* @__PURE__ */ jsxRuntime.jsx(
8795
+ numberField.NumberField.Decrement,
8796
+ {
8797
+ "aria-label": `Decrease ${displayName} quantity`,
8798
+ className: cn("w-6 h-6 border border-border flex items-center justify-center text-xs hover:bg-muted disabled:opacity-30", classNames?.qtyButton),
8799
+ children: "\u2212"
8800
+ }
8801
+ ),
8802
+ /* @__PURE__ */ jsxRuntime.jsx(
8803
+ numberField.NumberField.Input,
8804
+ {
8805
+ readOnly: true,
8806
+ 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)
8807
+ }
8808
+ ),
8809
+ /* @__PURE__ */ jsxRuntime.jsx(
8810
+ numberField.NumberField.Increment,
8811
+ {
8812
+ "aria-label": `Increase ${displayName} quantity`,
8813
+ className: cn("w-6 h-6 border border-border flex items-center justify-center text-xs hover:bg-muted disabled:opacity-30", classNames?.qtyButton),
8814
+ children: "+"
8815
+ }
8816
+ )
8817
+ ]
8818
+ }
8819
+ )
8747
8820
  }
8748
8821
  ),
8749
8822
  component.price != null && parsePrice(component.price) !== 0 && /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: component.price, prefix: "+" })
@@ -9000,7 +9073,8 @@ function ProductCustomizer({
9000
9073
  variantAxes: product.variant_axes,
9001
9074
  basePrice: product.default_price,
9002
9075
  selectedVariantId,
9003
- onVariantChange: handleVariantChange
9076
+ onVariantChange: handleVariantChange,
9077
+ productName: product.name
9004
9078
  }
9005
9079
  ),
9006
9080
  hasAddOns && /* @__PURE__ */ jsxRuntime.jsx(
@@ -9101,33 +9175,45 @@ function ProductImageGallery({
9101
9175
  )
9102
9176
  }
9103
9177
  ),
9104
- normalizedImages.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-image-gallery-thumbnails": true, style: { display: "flex", gap: "0.5rem", marginTop: "0.75rem" }, children: normalizedImages.map((image, index) => /* @__PURE__ */ jsxRuntime.jsx(
9105
- "button",
9178
+ normalizedImages.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
9179
+ radioGroup.RadioGroup,
9106
9180
  {
9107
- type: "button",
9108
- onClick: () => setSelectedImage(index),
9109
- "aria-selected": selectedImage === index,
9110
- "data-cimplify-image-gallery-thumb": true,
9111
- "data-selected": selectedImage === index || void 0,
9112
- style: {
9113
- width: "4rem",
9114
- height: "4rem",
9115
- overflow: "hidden",
9116
- padding: 0,
9117
- border: "none",
9118
- cursor: "pointer"
9119
- },
9120
- children: /* @__PURE__ */ jsxRuntime.jsx(
9121
- "img",
9122
- {
9123
- src: image,
9124
- alt: "",
9125
- style: { width: "100%", height: "100%", objectFit: "cover" }
9126
- }
9127
- )
9128
- },
9129
- `${image}-${index}`
9130
- )) })
9181
+ "aria-label": `${productName} image thumbnails`,
9182
+ value: String(selectedImage),
9183
+ onValueChange: (value) => setSelectedImage(Number(value)),
9184
+ "data-cimplify-image-gallery-thumbnails": true,
9185
+ style: { display: "flex", gap: "0.5rem", marginTop: "0.75rem" },
9186
+ children: normalizedImages.map((image, index) => {
9187
+ const isSelected = selectedImage === index;
9188
+ return /* @__PURE__ */ jsxRuntime.jsx(
9189
+ radio.Radio.Root,
9190
+ {
9191
+ value: String(index),
9192
+ render: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button" }),
9193
+ "data-cimplify-image-gallery-thumb": true,
9194
+ "data-selected": isSelected || void 0,
9195
+ style: {
9196
+ width: "4rem",
9197
+ height: "4rem",
9198
+ overflow: "hidden",
9199
+ padding: 0,
9200
+ border: "none",
9201
+ cursor: "pointer"
9202
+ },
9203
+ children: /* @__PURE__ */ jsxRuntime.jsx(
9204
+ "img",
9205
+ {
9206
+ src: image,
9207
+ alt: "",
9208
+ style: { width: "100%", height: "100%", objectFit: "cover" }
9209
+ }
9210
+ )
9211
+ },
9212
+ `${image}-${index}`
9213
+ );
9214
+ })
9215
+ }
9216
+ )
9131
9217
  ] });
9132
9218
  }
9133
9219
  function CartLineItemRow({
@@ -9738,6 +9824,26 @@ function ProductGrid({
9738
9824
  )
9739
9825
  ] });
9740
9826
  }
9827
+ var SearchIcon = () => /* @__PURE__ */ jsxRuntime.jsxs(
9828
+ "svg",
9829
+ {
9830
+ xmlns: "http://www.w3.org/2000/svg",
9831
+ width: "16",
9832
+ height: "16",
9833
+ viewBox: "0 0 24 24",
9834
+ fill: "none",
9835
+ stroke: "currentColor",
9836
+ strokeWidth: "2",
9837
+ strokeLinecap: "round",
9838
+ strokeLinejoin: "round",
9839
+ "aria-hidden": "true",
9840
+ "data-cimplify-search-icon": true,
9841
+ children: [
9842
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "8" }),
9843
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "21", y1: "21", x2: "16.65", y2: "16.65" })
9844
+ ]
9845
+ }
9846
+ );
9741
9847
  function SearchInput({
9742
9848
  placeholder = "Search products...",
9743
9849
  searchOptions,
@@ -9748,42 +9854,58 @@ function SearchInput({
9748
9854
  classNames
9749
9855
  }) {
9750
9856
  const { results, isLoading, query, setQuery, clear } = useSearch(searchOptions);
9751
- const handleChange = React3.useCallback(
9752
- (e) => {
9753
- setQuery(e.target.value);
9857
+ const handleValueChange = React3.useCallback(
9858
+ (value) => {
9859
+ setQuery(value);
9754
9860
  },
9755
9861
  [setQuery]
9756
9862
  );
9757
9863
  return /* @__PURE__ */ jsxRuntime.jsxs(
9758
- "div",
9864
+ field.Field.Root,
9759
9865
  {
9760
9866
  "data-cimplify-search": true,
9761
9867
  className: cn(className, classNames?.root),
9762
9868
  style: { position: "relative" },
9763
9869
  children: [
9764
- /* @__PURE__ */ jsxRuntime.jsx(
9765
- "input",
9766
- {
9767
- type: "search",
9768
- value: query,
9769
- onChange: handleChange,
9770
- placeholder,
9771
- "data-cimplify-search-input": true,
9772
- className: classNames?.input,
9773
- "aria-label": "Search products"
9774
- }
9775
- ),
9776
- query.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
9777
- "button",
9778
- {
9779
- type: "button",
9780
- onClick: clear,
9781
- "data-cimplify-search-clear": true,
9782
- className: classNames?.clearButton,
9783
- "aria-label": "Clear search",
9784
- children: "\xD7"
9785
- }
9786
- ),
9870
+ /* @__PURE__ */ jsxRuntime.jsx(field.Field.Label, { className: "sr-only", children: "Search products" }),
9871
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", display: "flex", alignItems: "center" }, children: [
9872
+ /* @__PURE__ */ jsxRuntime.jsx(
9873
+ "span",
9874
+ {
9875
+ "data-cimplify-search-icon-wrapper": true,
9876
+ style: {
9877
+ position: "absolute",
9878
+ left: "0.5rem",
9879
+ pointerEvents: "none",
9880
+ display: "flex",
9881
+ alignItems: "center"
9882
+ },
9883
+ children: /* @__PURE__ */ jsxRuntime.jsx(SearchIcon, {})
9884
+ }
9885
+ ),
9886
+ /* @__PURE__ */ jsxRuntime.jsx(
9887
+ input.Input,
9888
+ {
9889
+ type: "search",
9890
+ value: query,
9891
+ onValueChange: handleValueChange,
9892
+ placeholder,
9893
+ "data-cimplify-search-input": true,
9894
+ className: classNames?.input
9895
+ }
9896
+ ),
9897
+ query.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
9898
+ "button",
9899
+ {
9900
+ type: "button",
9901
+ onClick: clear,
9902
+ "data-cimplify-search-clear": true,
9903
+ className: classNames?.clearButton,
9904
+ "aria-label": "Clear search",
9905
+ children: "\xD7"
9906
+ }
9907
+ )
9908
+ ] }),
9787
9909
  showResults && query.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-search-results": true, className: classNames?.results, children: [
9788
9910
  isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-search-loading": true, className: classNames?.loading, "aria-busy": "true", children: "Searching..." }),
9789
9911
  !isLoading && results.length === 0 && query.length >= 2 && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-search-empty": true, className: classNames?.empty, children: "No results found" }),
@@ -9803,6 +9925,7 @@ function SearchInput({
9803
9925
  }
9804
9926
  );
9805
9927
  }
9928
+ var ALL_VALUE = "__all__";
9806
9929
  function CategoryFilter({
9807
9930
  selectedId = null,
9808
9931
  onSelect,
@@ -9812,9 +9935,9 @@ function CategoryFilter({
9812
9935
  classNames
9813
9936
  }) {
9814
9937
  const { categories, isLoading } = useCategories();
9815
- const handleSelect = React3.useCallback(
9816
- (id) => {
9817
- onSelect(id);
9938
+ const handleValueChange = React3.useCallback(
9939
+ (value) => {
9940
+ onSelect(value === ALL_VALUE ? null : String(value));
9818
9941
  },
9819
9942
  [onSelect]
9820
9943
  );
@@ -9828,45 +9951,45 @@ function CategoryFilter({
9828
9951
  }
9829
9952
  );
9830
9953
  }
9831
- return /* @__PURE__ */ jsxRuntime.jsxs(
9832
- "div",
9954
+ return /* @__PURE__ */ jsxRuntime.jsx(
9955
+ tabs.Tabs.Root,
9833
9956
  {
9834
- "data-cimplify-category-filter": true,
9835
- className: cn(className, classNames?.root),
9836
- role: "tablist",
9837
- "aria-label": "Filter by category",
9838
- children: [
9839
- /* @__PURE__ */ jsxRuntime.jsx(
9840
- "button",
9841
- {
9842
- type: "button",
9843
- role: "tab",
9844
- "aria-selected": selectedId === null,
9845
- onClick: () => handleSelect(null),
9846
- "data-cimplify-category-filter-item": true,
9847
- "data-selected": selectedId === null || void 0,
9848
- className: cn(classNames?.item, classNames?.allButton),
9849
- children: allLabel
9850
- }
9851
- ),
9852
- categories.map((category) => /* @__PURE__ */ jsxRuntime.jsxs(
9853
- "button",
9854
- {
9855
- type: "button",
9856
- role: "tab",
9857
- "aria-selected": selectedId === category.id,
9858
- onClick: () => handleSelect(category.id),
9859
- "data-cimplify-category-filter-item": true,
9860
- "data-selected": selectedId === category.id || void 0,
9861
- className: classNames?.item,
9862
- children: [
9863
- category.name,
9864
- showCounts && category.product_count != null && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-category-count": true, className: classNames?.count, children: category.product_count })
9865
- ]
9866
- },
9867
- category.id
9868
- ))
9869
- ]
9957
+ value: selectedId ?? ALL_VALUE,
9958
+ onValueChange: handleValueChange,
9959
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
9960
+ tabs.Tabs.List,
9961
+ {
9962
+ "data-cimplify-category-filter": true,
9963
+ "aria-label": "Filter by category",
9964
+ className: cn(className, classNames?.root),
9965
+ children: [
9966
+ /* @__PURE__ */ jsxRuntime.jsx(
9967
+ tabs.Tabs.Tab,
9968
+ {
9969
+ value: ALL_VALUE,
9970
+ "data-cimplify-category-filter-item": true,
9971
+ "data-selected": selectedId === null || void 0,
9972
+ className: cn(classNames?.item, classNames?.allButton),
9973
+ children: allLabel
9974
+ }
9975
+ ),
9976
+ categories.map((category) => /* @__PURE__ */ jsxRuntime.jsxs(
9977
+ tabs.Tabs.Tab,
9978
+ {
9979
+ value: category.id,
9980
+ "data-cimplify-category-filter-item": true,
9981
+ "data-selected": selectedId === category.id || void 0,
9982
+ className: classNames?.item,
9983
+ children: [
9984
+ category.name,
9985
+ showCounts && category.product_count != null && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-category-count": true, className: classNames?.count, children: category.product_count })
9986
+ ]
9987
+ },
9988
+ category.id
9989
+ ))
9990
+ ]
9991
+ }
9992
+ )
9870
9993
  }
9871
9994
  );
9872
9995
  }
@@ -9909,50 +10032,74 @@ function DiscountInput({
9909
10032
  [handleApply]
9910
10033
  );
9911
10034
  const isApplied = appliedValidation?.is_eligible === true;
9912
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-discount": true, className: cn(className, classNames?.root), children: [
9913
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-discount-form": true, children: [
9914
- /* @__PURE__ */ jsxRuntime.jsx(
9915
- "input",
9916
- {
9917
- type: "text",
9918
- value: code,
9919
- onChange: (e) => setCode(e.target.value),
9920
- onKeyDown: handleKeyDown,
9921
- placeholder,
9922
- disabled: isApplied,
9923
- "data-cimplify-discount-input": true,
9924
- className: classNames?.input,
9925
- "aria-label": "Discount code"
9926
- }
9927
- ),
9928
- isApplied ? /* @__PURE__ */ jsxRuntime.jsx(
9929
- "button",
9930
- {
9931
- type: "button",
9932
- onClick: handleClear,
9933
- "data-cimplify-discount-clear": true,
9934
- className: classNames?.button,
9935
- children: "Remove"
9936
- }
9937
- ) : /* @__PURE__ */ jsxRuntime.jsx(
9938
- "button",
9939
- {
9940
- type: "button",
9941
- onClick: handleApply,
9942
- disabled: isValidating || code.trim().length === 0,
9943
- "data-cimplify-discount-apply": true,
9944
- className: classNames?.button,
9945
- children: isValidating ? "Checking..." : "Apply"
9946
- }
9947
- )
9948
- ] }),
9949
- error && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-discount-error": true, className: classNames?.error, children: error.message }),
9950
- appliedValidation && !appliedValidation.is_eligible && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-discount-error": true, className: classNames?.error, children: appliedValidation.ineligibility_reason ?? "This code is not valid." }),
9951
- isApplied && appliedValidation.discount_amount && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-discount-success": true, className: classNames?.success, children: [
9952
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Discount applied" }),
9953
- /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: appliedValidation.discount_amount, prefix: "-" })
9954
- ] })
9955
- ] });
10035
+ const hasError = !!error || !!appliedValidation && !appliedValidation.is_eligible;
10036
+ const errorMessage = error ? error.message : appliedValidation && !appliedValidation.is_eligible ? appliedValidation.ineligibility_reason ?? "This code is not valid." : void 0;
10037
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10038
+ field.Field.Root,
10039
+ {
10040
+ "data-cimplify-discount": true,
10041
+ invalid: hasError,
10042
+ disabled: isApplied,
10043
+ className: cn(className, classNames?.root),
10044
+ children: [
10045
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-discount-form": true, children: [
10046
+ /* @__PURE__ */ jsxRuntime.jsx(
10047
+ input.Input,
10048
+ {
10049
+ type: "text",
10050
+ value: code,
10051
+ onValueChange: (value) => setCode(value),
10052
+ onKeyDown: handleKeyDown,
10053
+ placeholder,
10054
+ "data-cimplify-discount-input": true,
10055
+ className: classNames?.input,
10056
+ "aria-label": "Discount code"
10057
+ }
10058
+ ),
10059
+ isApplied ? /* @__PURE__ */ jsxRuntime.jsx(
10060
+ "button",
10061
+ {
10062
+ type: "button",
10063
+ onClick: handleClear,
10064
+ "data-cimplify-discount-clear": true,
10065
+ className: classNames?.button,
10066
+ children: "Remove"
10067
+ }
10068
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
10069
+ "button",
10070
+ {
10071
+ type: "button",
10072
+ onClick: handleApply,
10073
+ disabled: isValidating || code.trim().length === 0,
10074
+ "data-cimplify-discount-apply": true,
10075
+ className: classNames?.button,
10076
+ children: isValidating ? "Checking..." : "Apply"
10077
+ }
10078
+ )
10079
+ ] }),
10080
+ hasError && errorMessage && /* @__PURE__ */ jsxRuntime.jsx(
10081
+ field.Field.Error,
10082
+ {
10083
+ match: true,
10084
+ "data-cimplify-discount-error": true,
10085
+ className: classNames?.error,
10086
+ children: errorMessage
10087
+ }
10088
+ ),
10089
+ isApplied && appliedValidation.discount_amount && /* @__PURE__ */ jsxRuntime.jsxs(
10090
+ field.Field.Description,
10091
+ {
10092
+ "data-cimplify-discount-success": true,
10093
+ className: classNames?.success,
10094
+ children: [
10095
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Discount applied" }),
10096
+ /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: appliedValidation.discount_amount, prefix: "-" })
10097
+ ]
10098
+ }
10099
+ )
10100
+ ]
10101
+ }
10102
+ );
9956
10103
  }
9957
10104
  function CategoryGrid({
9958
10105
  categories: categoriesProp,
@@ -10399,6 +10546,9 @@ function formatTime(timeStr) {
10399
10546
  }
10400
10547
  return timeStr;
10401
10548
  }
10549
+ function slotToValue(slot) {
10550
+ return `${slot.start_time}|${slot.end_time}`;
10551
+ }
10402
10552
  function SlotPicker({
10403
10553
  slots: slotsProp,
10404
10554
  serviceId,
@@ -10443,29 +10593,49 @@ function SlotPicker({
10443
10593
  );
10444
10594
  }
10445
10595
  const groups = groupByTimeOfDay ? groupSlots(slots) : [{ label: "", slots }];
10446
- return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-slot-picker": true, className: cn(className, classNames?.root), children: groups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-slot-group": true, className: classNames?.group, children: [
10447
- group.label && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-slot-group-label": true, className: classNames?.groupLabel, children: group.label }),
10448
- group.slots.map((slot) => {
10449
- const isSelected = selectedSlot?.start_time === slot.start_time && selectedSlot?.end_time === slot.end_time;
10450
- return /* @__PURE__ */ jsxRuntime.jsxs(
10451
- "button",
10452
- {
10453
- type: "button",
10454
- disabled: !slot.is_available,
10455
- onClick: () => slot.is_available && onSlotSelect?.(slot),
10456
- "data-cimplify-slot": true,
10457
- "data-selected": isSelected || void 0,
10458
- "data-unavailable": !slot.is_available || void 0,
10459
- className: classNames?.slot,
10460
- children: [
10461
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-slot-time": true, className: classNames?.slotTime, children: formatTime(slot.start_time) }),
10462
- showPrice && slot.price && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-slot-price": true, className: classNames?.slotPrice, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: slot.price }) })
10463
- ]
10464
- },
10465
- `${slot.start_time}-${slot.end_time}`
10466
- );
10467
- })
10468
- ] }, group.label || "all")) });
10596
+ const slotsByValue = /* @__PURE__ */ new Map();
10597
+ for (const slot of slots) {
10598
+ slotsByValue.set(slotToValue(slot), slot);
10599
+ }
10600
+ const selectedValue = selectedSlot ? slotToValue(selectedSlot) : "";
10601
+ return /* @__PURE__ */ jsxRuntime.jsx(
10602
+ radioGroup.RadioGroup,
10603
+ {
10604
+ "data-cimplify-slot-picker": true,
10605
+ className: cn(className, classNames?.root),
10606
+ value: selectedValue,
10607
+ onValueChange: (value) => {
10608
+ const slot = slotsByValue.get(value);
10609
+ if (slot?.is_available) {
10610
+ onSlotSelect?.(slot);
10611
+ }
10612
+ },
10613
+ children: groups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-slot-group": true, className: classNames?.group, children: [
10614
+ group.label && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-slot-group-label": true, className: classNames?.groupLabel, children: group.label }),
10615
+ group.slots.map((slot) => {
10616
+ const value = slotToValue(slot);
10617
+ const isSelected = selectedSlot?.start_time === slot.start_time && selectedSlot?.end_time === slot.end_time;
10618
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10619
+ radio.Radio.Root,
10620
+ {
10621
+ value,
10622
+ disabled: !slot.is_available,
10623
+ render: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button" }),
10624
+ "data-cimplify-slot": true,
10625
+ "data-selected": isSelected || void 0,
10626
+ "data-unavailable": !slot.is_available || void 0,
10627
+ className: classNames?.slot,
10628
+ children: [
10629
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-slot-time": true, className: classNames?.slotTime, children: formatTime(slot.start_time) }),
10630
+ showPrice && slot.price && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-slot-price": true, className: classNames?.slotPrice, children: /* @__PURE__ */ jsxRuntime.jsx(Price, { amount: slot.price }) })
10631
+ ]
10632
+ },
10633
+ value
10634
+ );
10635
+ })
10636
+ ] }, group.label || "all"))
10637
+ }
10638
+ );
10469
10639
  }
10470
10640
  function formatDate(dateStr) {
10471
10641
  const date = /* @__PURE__ */ new Date(dateStr + "T00:00:00");
@@ -10528,8 +10698,10 @@ function DateSlotPicker({
10528
10698
  const handleNext = React3.useCallback(() => {
10529
10699
  setOffset((prev) => prev + daysToShow);
10530
10700
  }, [daysToShow]);
10531
- const handleDateSelect = React3.useCallback((date) => {
10532
- setSelectedDate(date);
10701
+ const handleDateChange = React3.useCallback((value) => {
10702
+ if (typeof value === "string") {
10703
+ setSelectedDate(value);
10704
+ }
10533
10705
  }, []);
10534
10706
  const handleSlotSelect = React3.useCallback(
10535
10707
  (slot) => {
@@ -10537,72 +10709,79 @@ function DateSlotPicker({
10537
10709
  },
10538
10710
  [onSlotSelect, selectedDate]
10539
10711
  );
10540
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-date-slot-picker": true, className: cn(className, classNames?.root), children: [
10541
- /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-date-nav": true, className: classNames?.nav, children: [
10542
- /* @__PURE__ */ jsxRuntime.jsx(
10543
- "button",
10544
- {
10545
- type: "button",
10546
- onClick: handlePrev,
10547
- disabled: offset === 0,
10548
- "data-cimplify-date-nav-prev": true,
10549
- className: classNames?.navButton,
10550
- children: "\u2190"
10551
- }
10552
- ),
10553
- /* @__PURE__ */ jsxRuntime.jsx(
10554
- "button",
10555
- {
10556
- type: "button",
10557
- onClick: handleNext,
10558
- "data-cimplify-date-nav-next": true,
10559
- className: classNames?.navButton,
10560
- children: "\u2192"
10561
- }
10562
- )
10563
- ] }),
10564
- /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-date-strip": true, className: classNames?.dateStrip, role: "tablist", children: dateRange.dates.map((date) => {
10565
- const dayInfo = availabilityMap.get(date);
10566
- const hasAvailability = dayInfo?.has_availability !== false;
10567
- const isSelected = selectedDate === date;
10568
- return /* @__PURE__ */ jsxRuntime.jsx(
10569
- "button",
10570
- {
10571
- type: "button",
10572
- role: "tab",
10573
- "aria-selected": isSelected,
10574
- onClick: () => handleDateSelect(date),
10575
- "data-cimplify-date-button": true,
10576
- "data-selected": isSelected || void 0,
10577
- "data-available": hasAvailability || void 0,
10578
- "data-fully-booked": !hasAvailability || void 0,
10579
- className: classNames?.dateButton,
10580
- children: formatDate(date)
10581
- },
10582
- date
10583
- );
10584
- }) }),
10585
- availabilityLoading && /* @__PURE__ */ jsxRuntime.jsx(
10586
- "div",
10587
- {
10588
- "data-cimplify-date-slot-loading": true,
10589
- "aria-busy": "true",
10590
- className: classNames?.loading
10591
- }
10592
- ),
10593
- /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-date-slots": true, className: classNames?.slots, children: /* @__PURE__ */ jsxRuntime.jsx(
10594
- SlotPicker,
10595
- {
10596
- serviceId,
10597
- date: selectedDate,
10598
- participantCount,
10599
- selectedSlot,
10600
- onSlotSelect: handleSlotSelect,
10601
- showPrice
10602
- }
10603
- ) })
10604
- ] });
10712
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10713
+ tabs.Tabs.Root,
10714
+ {
10715
+ value: selectedDate,
10716
+ onValueChange: handleDateChange,
10717
+ "data-cimplify-date-slot-picker": true,
10718
+ className: cn(className, classNames?.root),
10719
+ children: [
10720
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-date-nav": true, className: classNames?.nav, children: [
10721
+ /* @__PURE__ */ jsxRuntime.jsx(
10722
+ "button",
10723
+ {
10724
+ type: "button",
10725
+ onClick: handlePrev,
10726
+ disabled: offset === 0,
10727
+ "data-cimplify-date-nav-prev": true,
10728
+ className: classNames?.navButton,
10729
+ children: "\u2190"
10730
+ }
10731
+ ),
10732
+ /* @__PURE__ */ jsxRuntime.jsx(
10733
+ "button",
10734
+ {
10735
+ type: "button",
10736
+ onClick: handleNext,
10737
+ "data-cimplify-date-nav-next": true,
10738
+ className: classNames?.navButton,
10739
+ children: "\u2192"
10740
+ }
10741
+ )
10742
+ ] }),
10743
+ /* @__PURE__ */ jsxRuntime.jsx(tabs.Tabs.List, { "data-cimplify-date-strip": true, className: classNames?.dateStrip, children: dateRange.dates.map((date) => {
10744
+ const dayInfo = availabilityMap.get(date);
10745
+ const hasAvailability = dayInfo?.has_availability !== false;
10746
+ const isSelected = selectedDate === date;
10747
+ return /* @__PURE__ */ jsxRuntime.jsx(
10748
+ tabs.Tabs.Tab,
10749
+ {
10750
+ value: date,
10751
+ "data-cimplify-date-button": true,
10752
+ "data-selected": isSelected || void 0,
10753
+ "data-available": hasAvailability || void 0,
10754
+ "data-fully-booked": !hasAvailability || void 0,
10755
+ className: classNames?.dateButton,
10756
+ children: formatDate(date)
10757
+ },
10758
+ date
10759
+ );
10760
+ }) }),
10761
+ availabilityLoading && /* @__PURE__ */ jsxRuntime.jsx(
10762
+ "div",
10763
+ {
10764
+ "data-cimplify-date-slot-loading": true,
10765
+ "aria-busy": "true",
10766
+ className: classNames?.loading
10767
+ }
10768
+ ),
10769
+ /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-date-slots": true, className: classNames?.slots, children: /* @__PURE__ */ jsxRuntime.jsx(
10770
+ SlotPicker,
10771
+ {
10772
+ serviceId,
10773
+ date: selectedDate,
10774
+ participantCount,
10775
+ selectedSlot,
10776
+ onSlotSelect: handleSlotSelect,
10777
+ showPrice
10778
+ }
10779
+ ) })
10780
+ ]
10781
+ }
10782
+ );
10605
10783
  }
10784
+ var ANY_VALUE = "__any__";
10606
10785
  function StaffPicker({
10607
10786
  staff,
10608
10787
  selectedStaffId,
@@ -10612,44 +10791,56 @@ function StaffPicker({
10612
10791
  className,
10613
10792
  classNames
10614
10793
  }) {
10615
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-staff-picker": true, className: cn(className, classNames?.root), children: [
10616
- showAnyOption && /* @__PURE__ */ jsxRuntime.jsx(
10617
- "button",
10618
- {
10619
- type: "button",
10620
- onClick: () => onStaffSelect?.(null),
10621
- "data-cimplify-staff-option": true,
10622
- "data-selected": selectedStaffId === null || void 0,
10623
- "data-any": true,
10624
- className: classNames?.option,
10625
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-staff-name": true, className: classNames?.name, children: anyLabel })
10626
- }
10627
- ),
10628
- staff.map((member) => /* @__PURE__ */ jsxRuntime.jsxs(
10629
- "button",
10630
- {
10631
- type: "button",
10632
- onClick: () => onStaffSelect?.(member.id),
10633
- "data-cimplify-staff-option": true,
10634
- "data-selected": selectedStaffId === member.id || void 0,
10635
- className: classNames?.option,
10636
- children: [
10637
- member.avatar_url && /* @__PURE__ */ jsxRuntime.jsx(
10638
- "img",
10639
- {
10640
- src: member.avatar_url,
10641
- alt: member.name,
10642
- "data-cimplify-staff-avatar": true,
10643
- className: classNames?.avatar
10644
- }
10645
- ),
10646
- /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-staff-name": true, className: classNames?.name, children: member.name }),
10647
- member.bio && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-staff-bio": true, className: classNames?.bio, children: member.bio })
10648
- ]
10794
+ const groupValue = selectedStaffId === null ? ANY_VALUE : selectedStaffId ?? "";
10795
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10796
+ radioGroup.RadioGroup,
10797
+ {
10798
+ "data-cimplify-staff-picker": true,
10799
+ className: cn(className, classNames?.root),
10800
+ value: groupValue,
10801
+ onValueChange: (value) => {
10802
+ onStaffSelect?.(value === ANY_VALUE ? null : value);
10649
10803
  },
10650
- member.id
10651
- ))
10652
- ] });
10804
+ children: [
10805
+ showAnyOption && /* @__PURE__ */ jsxRuntime.jsx(
10806
+ radio.Radio.Root,
10807
+ {
10808
+ value: ANY_VALUE,
10809
+ render: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button" }),
10810
+ "data-cimplify-staff-option": true,
10811
+ "data-selected": selectedStaffId === null || void 0,
10812
+ "data-any": true,
10813
+ className: classNames?.option,
10814
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-staff-name": true, className: classNames?.name, children: anyLabel })
10815
+ }
10816
+ ),
10817
+ staff.map((member) => /* @__PURE__ */ jsxRuntime.jsxs(
10818
+ radio.Radio.Root,
10819
+ {
10820
+ value: member.id,
10821
+ render: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button" }),
10822
+ "data-cimplify-staff-option": true,
10823
+ "data-selected": selectedStaffId === member.id || void 0,
10824
+ className: classNames?.option,
10825
+ children: [
10826
+ member.avatar_url && /* @__PURE__ */ jsxRuntime.jsx(
10827
+ "img",
10828
+ {
10829
+ src: member.avatar_url,
10830
+ alt: member.name,
10831
+ "data-cimplify-staff-avatar": true,
10832
+ className: classNames?.avatar
10833
+ }
10834
+ ),
10835
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-staff-name": true, className: classNames?.name, children: member.name }),
10836
+ member.bio && /* @__PURE__ */ jsxRuntime.jsx("span", { "data-cimplify-staff-bio": true, className: classNames?.bio, children: member.bio })
10837
+ ]
10838
+ },
10839
+ member.id
10840
+ ))
10841
+ ]
10842
+ }
10843
+ );
10653
10844
  }
10654
10845
  var STATUS_LABELS3 = {
10655
10846
  pending: "Pending",
@@ -11321,10 +11512,10 @@ function OrderDetailPage({
11321
11512
  ] });
11322
11513
  }
11323
11514
  var STATUS_FILTERS = [
11324
- { label: "All", value: void 0 },
11325
- { label: "Active", value: "confirmed" },
11326
- { label: "Completed", value: "completed" },
11327
- { label: "Cancelled", value: "cancelled" }
11515
+ { label: "All", value: void 0, tabValue: "all" },
11516
+ { label: "Active", value: "confirmed", tabValue: "confirmed" },
11517
+ { label: "Completed", value: "completed", tabValue: "completed" },
11518
+ { label: "Cancelled", value: "cancelled", tabValue: "cancelled" }
11328
11519
  ];
11329
11520
  function OrderHistoryPage({
11330
11521
  title = "Order History",
@@ -11338,6 +11529,10 @@ function OrderHistoryPage({
11338
11529
  }) {
11339
11530
  const [statusFilter, setStatusFilter] = React3.useState(void 0);
11340
11531
  const [selectedOrder, setSelectedOrder] = React3.useState(null);
11532
+ const handleTabChange = React3.useCallback((value) => {
11533
+ const filter = STATUS_FILTERS.find((f) => f.tabValue === value);
11534
+ setStatusFilter(filter?.value);
11535
+ }, []);
11341
11536
  const handleOrderClick = React3.useCallback(
11342
11537
  (order) => {
11343
11538
  if (onOrderNavigate) {
@@ -11351,6 +11546,7 @@ function OrderHistoryPage({
11351
11546
  const handleBack = React3.useCallback(() => {
11352
11547
  setSelectedOrder(null);
11353
11548
  }, []);
11549
+ const activeTabValue = STATUS_FILTERS.find((f) => f.value === statusFilter)?.tabValue ?? "all";
11354
11550
  if (selectedOrder && !onOrderNavigate) {
11355
11551
  return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-order-history-page": true, className: cn(className, classNames?.root), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-history-detail": true, className: classNames?.detail, children: [
11356
11552
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -11368,20 +11564,17 @@ function OrderHistoryPage({
11368
11564
  }
11369
11565
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-order-history-page": true, className: cn(className, classNames?.root), children: [
11370
11566
  /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-order-history-header": true, className: classNames?.header, children: /* @__PURE__ */ jsxRuntime.jsx("h1", { "data-cimplify-order-history-title": true, className: classNames?.title, children: title }) }),
11371
- showFilters && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-order-history-filters": true, className: classNames?.filters, role: "tablist", children: STATUS_FILTERS.map((filter) => /* @__PURE__ */ jsxRuntime.jsx(
11372
- "button",
11567
+ showFilters && /* @__PURE__ */ jsxRuntime.jsx(tabs.Tabs.Root, { value: activeTabValue, onValueChange: handleTabChange, children: /* @__PURE__ */ jsxRuntime.jsx(tabs.Tabs.List, { "data-cimplify-order-history-filters": true, className: classNames?.filters, children: STATUS_FILTERS.map((filter) => /* @__PURE__ */ jsxRuntime.jsx(
11568
+ tabs.Tabs.Tab,
11373
11569
  {
11374
- type: "button",
11375
- role: "tab",
11376
- "aria-selected": statusFilter === filter.value,
11377
- onClick: () => setStatusFilter(filter.value),
11570
+ value: filter.tabValue,
11378
11571
  "data-cimplify-order-filter": true,
11379
11572
  "data-selected": statusFilter === filter.value || void 0,
11380
11573
  className: classNames?.filterButton,
11381
11574
  children: filter.label
11382
11575
  },
11383
- filter.label
11384
- )) }),
11576
+ filter.tabValue
11577
+ )) }) }),
11385
11578
  /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-order-history-list": true, className: classNames?.list, children: /* @__PURE__ */ jsxRuntime.jsx(
11386
11579
  OrderHistory,
11387
11580
  {
@@ -11409,7 +11602,7 @@ function SearchPage({
11409
11602
  /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-search-page-header": true, className: classNames?.header, children: /* @__PURE__ */ jsxRuntime.jsx("h1", { "data-cimplify-search-page-title": true, className: classNames?.title, children: title }) }),
11410
11603
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-search-page-input": true, className: classNames?.inputContainer, children: [
11411
11604
  /* @__PURE__ */ jsxRuntime.jsx(
11412
- "input",
11605
+ input.Input,
11413
11606
  {
11414
11607
  type: "search",
11415
11608
  value: query,
@@ -11751,20 +11944,24 @@ function BookingsPage({
11751
11944
  }
11752
11945
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-cimplify-bookings-page": true, className: cn(className, classNames?.root), children: [
11753
11946
  /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-bookings-header": true, className: classNames?.header, children: /* @__PURE__ */ jsxRuntime.jsx("h1", { "data-cimplify-bookings-title": true, className: classNames?.title, children: title }) }),
11754
- showFilters && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-bookings-filters": true, className: classNames?.filters, role: "tablist", children: BOOKING_FILTERS.map((f) => /* @__PURE__ */ jsxRuntime.jsx(
11755
- "button",
11947
+ showFilters && /* @__PURE__ */ jsxRuntime.jsx(
11948
+ tabs.Tabs.Root,
11756
11949
  {
11757
- type: "button",
11758
- role: "tab",
11759
- "aria-selected": filter === f.value,
11760
- onClick: () => setFilter(f.value),
11761
- "data-cimplify-booking-filter": true,
11762
- "data-selected": filter === f.value || void 0,
11763
- className: classNames?.filterButton,
11764
- children: f.label
11765
- },
11766
- f.value
11767
- )) }),
11950
+ value: filter,
11951
+ onValueChange: (value) => setFilter(value),
11952
+ children: /* @__PURE__ */ jsxRuntime.jsx(tabs.Tabs.List, { "data-cimplify-bookings-filters": true, className: classNames?.filters, children: BOOKING_FILTERS.map((f) => /* @__PURE__ */ jsxRuntime.jsx(
11953
+ tabs.Tabs.Tab,
11954
+ {
11955
+ value: f.value,
11956
+ "data-cimplify-booking-filter": true,
11957
+ "data-selected": filter === f.value || void 0,
11958
+ className: classNames?.filterButton,
11959
+ children: f.label
11960
+ },
11961
+ f.value
11962
+ )) })
11963
+ }
11964
+ ),
11768
11965
  /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cimplify-bookings-list": true, className: classNames?.list, children: /* @__PURE__ */ jsxRuntime.jsx(
11769
11966
  BookingList,
11770
11967
  {