@clicktap/ui 2.4.6 → 2.4.8

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.
@@ -1 +1 @@
1
- "use client";import{jsxs as c,jsx as r}from"react/jsx-runtime";import{useRef as l}from"react";import{useSelect as z,useButton as A,HiddenSelect as E}from"react-aria";import{useInteractOutside as G}from"@react-aria/interactions";import{useSelectState as J}from"react-stately";import{cn as e}from"../../utils/cn.js";import{ChevronIcon as Q,SelectPopover as T,SelectListBox as U}from"./parts.js";import"react-aria-components";function se(d){const{label:a,description:u,errorMessage:f,children:g,placeholder:x,slots:h,popoverOffset:v,className:N,classNames:t,isLoading:I,name:b,selectedKey:P,defaultSelectedKey:S,onSelectionChange:y,isRequired:B,items:w,autoFocus:R,isInvalid:C,"aria-label":O,"aria-labelledby":L}=d,n=!!(d.isDisabled||I),m={label:a,children:g,items:w,name:b,selectedKey:P,defaultSelectedKey:S,onSelectionChange:y,isDisabled:n,isRequired:B,autoFocus:R,isInvalid:C,"aria-label":O,"aria-labelledby":L},s=J(m),p=l(null),o=l(null),j=l(null),H=l(null),{labelProps:M,triggerProps:D,valueProps:K,menuProps:_,descriptionProps:k,errorMessageProps:q,isInvalid:i}=z(m,s,o),{buttonProps:F}=A(D,o);return G({ref:p,onInteractOutside:()=>s.close()}),c("div",{ref:p,className:e("flex flex-col","w-full",N),children:[r("label",{...M,className:e("flex","text-xs text-fg-muted",t?.label),children:a}),r(E,{state:s,triggerRef:o,label:a,name:b,isDisabled:n}),c("div",{className:e("flex","relative","w-full",t?.comboBoxContainer),children:[c("button",{...F,ref:o,className:e("flex items-center justify-between gap-2","border border-solid border-border","text-sm text-fg text-left","py-0 px-3","h-10 w-full","m-0","rounded-md","bg-surface","cursor-pointer","transition-all ease-in-out duration-200","hover:border-border-emphasis","focus:outline focus:outline-2 focus:outline-border-subtle focus:border-border-emphasis","disabled:bg-surface-subtle disabled:border-border disabled:cursor-default",i&&"border-danger-soft bg-danger-surface text-danger hover:border-danger focus:border-danger focus:outline-danger-ring",t?.input),children:[r("span",{...K,className:e("truncate",!s.selectedItem&&"text-fg-subtle",t?.value),children:s.selectedItem?s.selectedItem.rendered:x??"Select..."}),r("span",{className:e("shrink-0 [&_svg]:w-4 [&_svg]:h-4",t?.arrowButton),children:r(Q,{isOpen:s.isOpen,isDisabled:n,isInvalid:i,buttonIcon:h?.buttonIcon})})]}),s.isOpen&&r(T,{popoverRef:H,offset:v,className:e(t?.listContainer),children:r(U,{state:s,listBoxProps:_,listBoxRef:j,optionClassName:e(t?.option),sectionHeadingClassName:e(t?.sectionHeading),className:e("max-h-80","overflow-y-auto","outline-none",t?.list)})})]}),u&&r("span",{...k,className:e("flex","text-xs","text-fg-muted",t?.description),children:u}),i&&typeof f=="string"&&r("span",{...q,className:e("flex","text-xs","text-danger-soft",t?.errorMessage),children:f})]})}export{se as ButtonSelect,se as default};
1
+ "use client";import{jsxs as d,jsx as r}from"react/jsx-runtime";import{useRef as l}from"react";import{useSelect as G,useButton as J,HiddenSelect as Q}from"react-aria";import{useInteractOutside as T}from"@react-aria/interactions";import{useSelectState as U}from"react-stately";import{cn as e}from"../../utils/cn.js";import{ChevronIcon as V,SelectPopover as W,SelectListBox as X}from"./parts.js";import"react-aria-components";function le(c){const{label:a,description:u,errorMessage:f,children:g,placeholder:x,slots:h,popoverOffset:v,className:N,classNames:s,isLoading:y,name:b,selectedKey:I,defaultSelectedKey:P,onSelectionChange:S,isRequired:B,items:w,disabledKeys:R,autoFocus:C,isInvalid:O,id:L,"aria-label":j,"aria-labelledby":D,"aria-describedby":H}=c,n=!!(c.isDisabled||y),m={label:a,children:g,items:w,name:b,selectedKey:I,defaultSelectedKey:P,onSelectionChange:S,isDisabled:n,disabledKeys:R,isRequired:B,autoFocus:C,isInvalid:O,id:L,"aria-label":j,"aria-labelledby":D,"aria-describedby":H},t=U(m),p=l(null),o=l(null),K=l(null),M=l(null),{labelProps:_,triggerProps:k,valueProps:q,menuProps:F,descriptionProps:z,errorMessageProps:A,isInvalid:i}=G(m,t,o),{buttonProps:E}=J(k,o);return T({ref:p,onInteractOutside:()=>t.close()}),d("div",{ref:p,className:e("flex flex-col","w-full",N),children:[r("label",{..._,className:e("flex","text-xs text-fg-muted",s?.label),children:a}),r(Q,{state:t,triggerRef:o,label:a,name:b,isDisabled:n}),d("div",{className:e("flex","relative","w-full",s?.comboBoxContainer),children:[d("button",{...E,ref:o,className:e("flex items-center justify-between gap-2","border border-solid border-border","text-sm text-fg text-left","py-0 px-3","h-10 w-full","m-0","rounded-md","bg-surface","cursor-pointer","transition-all ease-in-out duration-200","hover:border-border-emphasis","focus:outline focus:outline-2 focus:outline-border-subtle focus:border-border-emphasis","disabled:bg-surface-subtle disabled:border-border disabled:cursor-default",i&&"border-danger-soft bg-danger-surface text-danger hover:border-danger focus:border-danger focus:outline-danger-ring",s?.input),children:[r("span",{...q,className:e("truncate",!t.selectedItem&&"text-fg-subtle",s?.value),children:t.selectedItem?t.selectedItem.rendered:x??"Select..."}),r("span",{className:e("shrink-0 [&_svg]:w-4 [&_svg]:h-4",s?.arrowButton),children:r(V,{isOpen:t.isOpen,isDisabled:n,isInvalid:i,buttonIcon:h?.buttonIcon})})]}),t.isOpen&&r(W,{popoverRef:M,offset:v,className:e(s?.listContainer),children:r(X,{state:t,listBoxProps:F,listBoxRef:K,optionClassName:e(s?.option),sectionHeadingClassName:e(s?.sectionHeading),className:e("max-h-80","overflow-y-auto","outline-none",s?.list)})})]}),u&&r("span",{...z,className:e("flex","text-xs","text-fg-muted",s?.description),children:u}),i&&typeof f=="string"&&r("span",{...A,className:e("flex","text-xs","text-danger-soft",s?.errorMessage),children:f})]})}export{le as ButtonSelect,le as default};
@@ -1 +1 @@
1
- "use client";import{jsxs as d,jsx as o}from"react/jsx-runtime";import{useRef as a}from"react";import{useButton as D}from"react-aria";import{useListState as F,useOverlayTriggerState as H}from"react-stately";import{cn as e}from"../../utils/cn.js";import{ChevronIcon as _,SelectOverlay as k,SelectListBox as T}from"./parts.js";import"react-aria-components";function J(u){const{label:f,description:b,errorMessage:m,children:x,placeholder:h,slots:v,popoverOffset:y,className:N,classNames:t,isLoading:S,items:B,isInvalid:I,"aria-label":p,"aria-labelledby":O,selectedKeys:w,defaultSelectedKeys:C,onSelectionChange:R}=u,g=!!(u.isDisabled||S),r=F({children:x,items:B,selectionMode:"multiple",selectionBehavior:"toggle",selectedKeys:w,defaultSelectedKeys:C,onSelectionChange:s=>{s!=="all"&&R?.([...s])}}),l=H({}),L=a(null),n=a(null),M=a(null),j=a(null),{buttonProps:P}=D({isDisabled:g,onPress:()=>l.toggle(),"aria-label":p,"aria-labelledby":O},n),i=!!I,c=[...r.collection.getKeys()].map(s=>r.collection.getItem(s)).filter(s=>s!=null&&s.type==="item"&&r.selectionManager.isSelected(s.key)),K=c.map(s=>s.textValue).join(", ");return d("div",{ref:L,className:e("flex flex-col","w-full",N),children:[o("label",{className:e("flex","text-xs text-fg-muted",t?.label),children:f}),d("div",{className:e("flex","relative","w-full",t?.comboBoxContainer),children:[d("button",{...P,ref:n,"aria-haspopup":"listbox","aria-expanded":l.isOpen,className:e("flex items-center justify-between gap-2","border border-solid border-border","text-sm text-fg text-left","py-0 px-3","h-10 w-full","m-0","rounded-md","bg-surface","cursor-pointer","transition-all ease-in-out duration-200","hover:border-border-emphasis","focus:outline focus:outline-2 focus:outline-border-subtle focus:border-border-emphasis","disabled:bg-surface-subtle disabled:border-border disabled:cursor-default",i&&"border-danger-soft bg-danger-surface text-danger hover:border-danger focus:border-danger focus:outline-danger-ring",t?.input),children:[o("span",{className:e("truncate",c.length===0&&"text-fg-subtle",t?.value),children:c.length>0?K:h??"Select..."}),o("span",{className:e("shrink-0 [&_svg]:w-4 [&_svg]:h-4",t?.arrowButton),children:o(_,{isOpen:l.isOpen,isDisabled:g,isInvalid:i,buttonIcon:v?.buttonIcon})})]}),l.isOpen&&o(k,{state:l,triggerRef:n,popoverRef:j,offset:y,className:e(t?.listContainer),children:o(T,{state:r,listBoxProps:{"aria-label":f??p??"Options",autoFocus:"first",shouldFocusWrap:!0},listBoxRef:M,optionClassName:e(t?.option),sectionHeadingClassName:e(t?.sectionHeading),className:e("max-h-80","overflow-y-auto","outline-none",t?.list)})})]}),b&&o("span",{className:e("flex","text-xs","text-fg-muted",t?.description),children:b}),i&&typeof m=="string"&&o("span",{className:e("flex","text-xs","text-danger-soft",t?.errorMessage),children:m})]})}export{J as MultiButtonSelect,J as default};
1
+ "use client";import{jsxs as d,jsx as o}from"react/jsx-runtime";import{useRef as r}from"react";import{useButton as F}from"react-aria";import{useListState as H,useOverlayTriggerState as _}from"react-stately";import{cn as e}from"../../utils/cn.js";import{ChevronIcon as k,SelectOverlay as T,SelectListBox as V}from"./parts.js";import"react-aria-components";function Q(u){const{label:f,description:b,errorMessage:m,children:x,placeholder:h,slots:v,popoverOffset:y,className:N,classNames:t,isLoading:S,items:B,disabledKeys:I,isInvalid:O,"aria-label":p,"aria-labelledby":w,selectedKeys:C,defaultSelectedKeys:R,onSelectionChange:L}=u,g=!!(u.isDisabled||S),a=H({children:x,items:B,disabledKeys:I,selectionMode:"multiple",selectionBehavior:"toggle",selectedKeys:C,defaultSelectedKeys:R,onSelectionChange:s=>{s!=="all"&&L?.([...s])}}),l=_({}),M=r(null),n=r(null),j=r(null),K=r(null),{buttonProps:P}=F({isDisabled:g,onPress:()=>l.toggle(),"aria-label":p,"aria-labelledby":w},n),i=!!O,c=[...a.collection.getKeys()].map(s=>a.collection.getItem(s)).filter(s=>s!=null&&s.type==="item"&&a.selectionManager.isSelected(s.key)),D=c.map(s=>s.textValue).join(", ");return d("div",{ref:M,className:e("flex flex-col","w-full",N),children:[o("label",{className:e("flex","text-xs text-fg-muted",t?.label),children:f}),d("div",{className:e("flex","relative","w-full",t?.comboBoxContainer),children:[d("button",{...P,ref:n,"aria-haspopup":"listbox","aria-expanded":l.isOpen,className:e("flex items-center justify-between gap-2","border border-solid border-border","text-sm text-fg text-left","py-0 px-3","h-10 w-full","m-0","rounded-md","bg-surface","cursor-pointer","transition-all ease-in-out duration-200","hover:border-border-emphasis","focus:outline focus:outline-2 focus:outline-border-subtle focus:border-border-emphasis","disabled:bg-surface-subtle disabled:border-border disabled:cursor-default",i&&"border-danger-soft bg-danger-surface text-danger hover:border-danger focus:border-danger focus:outline-danger-ring",t?.input),children:[o("span",{className:e("truncate",c.length===0&&"text-fg-subtle",t?.value),children:c.length>0?D:h??"Select..."}),o("span",{className:e("shrink-0 [&_svg]:w-4 [&_svg]:h-4",t?.arrowButton),children:o(k,{isOpen:l.isOpen,isDisabled:g,isInvalid:i,buttonIcon:v?.buttonIcon})})]}),l.isOpen&&o(T,{state:l,triggerRef:n,popoverRef:K,offset:y,className:e(t?.listContainer),children:o(V,{state:a,listBoxProps:{"aria-label":f??p??"Options",autoFocus:"first",shouldFocusWrap:!0},listBoxRef:j,optionClassName:e(t?.option),sectionHeadingClassName:e(t?.sectionHeading),className:e("max-h-80","overflow-y-auto","outline-none",t?.list)})})]}),b&&o("span",{className:e("flex","text-xs","text-fg-muted",t?.description),children:b}),i&&typeof m=="string"&&o("span",{className:e("flex","text-xs","text-danger-soft",t?.errorMessage),children:m})]})}export{Q as MultiButtonSelect,Q as default};
@@ -0,0 +1,47 @@
1
+ # Select: `disabledKeys` works in button mode
2
+
3
+ **Date:** 2026-10-09
4
+ **Affects:** `components/Select` (`ButtonSelect`, `MultiButtonSelect`)
5
+ **Classification:** BUGFIX
6
+ **Breaking:** No
7
+ **Ticket:** CTAP-2018
8
+
9
+ ## Dependencies
10
+
11
+ *None*
12
+
13
+ See also: `apps/frontend/docs/migrations/2026/10/frontend-2026-10-09-pdp-out-of-stock-options.md`, the
14
+ first consumer.
15
+
16
+ ## Problem
17
+
18
+ `SelectProps` accepts `disabledKeys` (it extends react-aria's combobox props), but only the searchable
19
+ mode honored it. The default button mode (`ButtonSelect`) and the multiple-selection button mode
20
+ (`MultiButtonSelect`) built their react-stately state from a fixed list of props that left
21
+ `disabledKeys` out. A caller could pass it, see no type error, and still have every option selectable.
22
+
23
+ ## Changes
24
+
25
+ Both button modes pass `disabledKeys` to their state hook (`useSelectState` / `useListState`).
26
+ A disabled option stays in the list, carries `aria-disabled="true"`, and a press on it changes
27
+ nothing. `onSelectionChange` is not called.
28
+
29
+ ```tsx
30
+ <Select
31
+ aria-label="Size"
32
+ disabledKeys={['m']}
33
+ onSelectionChange={setSize}
34
+ >
35
+ <Option key="s">Small</Option>
36
+ <Option key="m">Medium (out of stock)</Option>
37
+ <Option key="l">Large</Option>
38
+ </Select>
39
+ ```
40
+
41
+ ## Migration Steps
42
+
43
+ None required. A consumer that worked around the gap, for example by ignoring a pick in
44
+ `onSelectionChange`, can drop the workaround and pass `disabledKeys`.
45
+
46
+ **Verify:** open the select. The disabled option is listed but cannot be picked
47
+ (`ButtonSelect.spec.tsx`, "disabledKeys").
@@ -1,4 +1,14 @@
1
1
  [
2
+ {
3
+ "path": "2026/10/ui-2026-10-09-select-forwards-disabled-keys.md",
4
+ "module": "libs/frontend-modules/ui",
5
+ "package": "@clicktap/ui",
6
+ "date": "2026-10-09",
7
+ "title": "Select: `disabledKeys` works in button mode",
8
+ "classification": "BUGFIX",
9
+ "breaking": "No",
10
+ "affects": "`components/Select` (`ButtonSelect`, `MultiButtonSelect`)"
11
+ },
2
12
  {
3
13
  "path": "2026/10/ui-2026-10-06-invalid-styling-keys-on-data-invalid.md",
4
14
  "module": "libs/frontend-modules/ui",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clicktap/ui",
3
- "version": "2.4.6",
3
+ "version": "2.4.8",
4
4
  "private": false,
5
5
  "author": "Clicktap",
6
6
  "description": "A library of React UI components and low-level hooks.",