@womp/kookie-ui 0.4.0 → 0.6.2
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/components.css +783 -783
- package/dist/cjs/components/_internal/base-menu.utils.d.ts +48 -0
- package/dist/cjs/components/_internal/base-menu.utils.d.ts.map +1 -0
- package/dist/cjs/components/_internal/base-menu.utils.js +2 -0
- package/dist/cjs/components/_internal/base-menu.utils.js.map +7 -0
- package/dist/cjs/components/_internal/dropdown-menu-drill-down.d.ts +77 -59
- package/dist/cjs/components/_internal/dropdown-menu-drill-down.d.ts.map +1 -1
- package/dist/cjs/components/_internal/dropdown-menu-drill-down.js +1 -1
- package/dist/cjs/components/_internal/dropdown-menu-drill-down.js.map +4 -4
- package/dist/cjs/components/_internal/menu-context.d.ts +7 -3
- package/dist/cjs/components/_internal/menu-context.d.ts.map +1 -1
- package/dist/cjs/components/_internal/menu-context.js +1 -1
- package/dist/cjs/components/_internal/menu-context.js.map +4 -4
- package/dist/cjs/components/_internal/shell-bottom.js +1 -1
- package/dist/cjs/components/_internal/shell-bottom.js.map +2 -2
- package/dist/cjs/components/_internal/shell-inspector.js +1 -1
- package/dist/cjs/components/_internal/shell-inspector.js.map +2 -2
- package/dist/cjs/components/_internal/shell-sidebar.js +1 -1
- package/dist/cjs/components/_internal/shell-sidebar.js.map +2 -2
- package/dist/cjs/components/accordion.js +1 -1
- package/dist/cjs/components/alert-dialog.js +1 -1
- package/dist/cjs/components/alert-dialog.js.map +2 -2
- package/dist/cjs/components/badge.js +1 -1
- package/dist/cjs/components/badge.js.map +2 -2
- package/dist/cjs/components/blockquote.js +1 -1
- package/dist/cjs/components/button.js +1 -1
- package/dist/cjs/components/button.js.map +2 -2
- package/dist/cjs/components/callout.js +1 -1
- package/dist/cjs/components/callout.js.map +2 -2
- package/dist/cjs/components/card.js +1 -1
- package/dist/cjs/components/card.js.map +2 -2
- package/dist/cjs/components/chatbar.d.ts +46 -44
- package/dist/cjs/components/chatbar.d.ts.map +1 -1
- package/dist/cjs/components/chatbar.js +2 -2
- package/dist/cjs/components/chatbar.js.map +3 -3
- package/dist/cjs/components/checkbox-cards.js +1 -1
- package/dist/cjs/components/checkbox-cards.js.map +2 -2
- package/dist/cjs/components/checkbox-group.js +1 -1
- package/dist/cjs/components/checkbox.js +1 -1
- package/dist/cjs/components/combobox.d.ts +28 -15
- package/dist/cjs/components/combobox.d.ts.map +1 -1
- package/dist/cjs/components/combobox.js +1 -1
- package/dist/cjs/components/combobox.js.map +4 -4
- package/dist/cjs/components/combobox.props.d.ts +48 -0
- package/dist/cjs/components/combobox.props.d.ts.map +1 -1
- package/dist/cjs/components/combobox.props.js +1 -1
- package/dist/cjs/components/combobox.props.js.map +4 -4
- package/dist/cjs/components/context-menu.d.ts +18 -5
- package/dist/cjs/components/context-menu.d.ts.map +1 -1
- package/dist/cjs/components/context-menu.js +1 -1
- package/dist/cjs/components/context-menu.js.map +4 -4
- package/dist/cjs/components/context-menu.props.d.ts +1 -1
- package/dist/cjs/components/context-menu.props.d.ts.map +1 -1
- package/dist/cjs/components/context-menu.props.js +1 -1
- package/dist/cjs/components/context-menu.props.js.map +3 -3
- package/dist/cjs/components/dialog.js +1 -1
- package/dist/cjs/components/dialog.js.map +2 -2
- package/dist/cjs/components/dropdown-menu.d.ts +11 -18
- package/dist/cjs/components/dropdown-menu.d.ts.map +1 -1
- package/dist/cjs/components/dropdown-menu.js +1 -1
- package/dist/cjs/components/dropdown-menu.js.map +4 -4
- package/dist/cjs/components/heading.js +1 -1
- package/dist/cjs/components/hover-card.js +1 -1
- package/dist/cjs/components/hover-card.js.map +2 -2
- package/dist/cjs/components/icon-button.js +1 -1
- package/dist/cjs/components/icon-button.js.map +2 -2
- package/dist/cjs/components/index.js +5 -5
- package/dist/cjs/components/index.js.map +4 -4
- package/dist/cjs/components/link.js +1 -1
- package/dist/cjs/components/popover.js +1 -1
- package/dist/cjs/components/popover.js.map +2 -2
- package/dist/cjs/components/radio-cards.js +1 -1
- package/dist/cjs/components/radio-cards.js.map +2 -2
- package/dist/cjs/components/radio.js +1 -1
- package/dist/cjs/components/radio.js.map +2 -2
- package/dist/cjs/components/schemas/base-button.schema.d.ts +111 -256
- package/dist/cjs/components/schemas/base-button.schema.d.ts.map +1 -1
- package/dist/cjs/components/schemas/button.schema.d.ts +136 -557
- package/dist/cjs/components/schemas/button.schema.d.ts.map +1 -1
- package/dist/cjs/components/schemas/icon-button.schema.d.ts +123 -240
- package/dist/cjs/components/schemas/icon-button.schema.d.ts.map +1 -1
- package/dist/cjs/components/schemas/index.js +1 -1
- package/dist/cjs/components/schemas/index.js.map +2 -2
- package/dist/cjs/components/schemas/shell.schema.d.ts +592 -851
- package/dist/cjs/components/schemas/shell.schema.d.ts.map +1 -1
- package/dist/cjs/components/schemas/shell.schema.js +1 -1
- package/dist/cjs/components/schemas/shell.schema.js.map +2 -2
- package/dist/cjs/components/schemas/toggle-button.schema.d.ts +138 -1026
- package/dist/cjs/components/schemas/toggle-button.schema.d.ts.map +1 -1
- package/dist/cjs/components/schemas/toggle-icon-button.schema.d.ts +124 -465
- package/dist/cjs/components/schemas/toggle-icon-button.schema.d.ts.map +1 -1
- package/dist/cjs/components/scroll-area.js +1 -1
- package/dist/cjs/components/segmented-control.js +1 -1
- package/dist/cjs/components/select.js +1 -1
- package/dist/cjs/components/select.js.map +2 -2
- package/dist/cjs/components/sheet.js +1 -1
- package/dist/cjs/components/sheet.js.map +2 -2
- package/dist/cjs/components/shell.js +1 -1
- package/dist/cjs/components/shell.js.map +3 -3
- package/dist/cjs/components/sidebar.js +1 -1
- package/dist/cjs/components/sidebar.js.map +4 -4
- package/dist/cjs/components/slider.js +1 -1
- package/dist/cjs/components/slot.d.ts +6 -2
- package/dist/cjs/components/slot.d.ts.map +1 -1
- package/dist/cjs/components/switch.js +1 -1
- package/dist/cjs/components/tab-nav.js +1 -1
- package/dist/cjs/components/text-field.js +2 -2
- package/dist/cjs/components/text.js +1 -1
- package/dist/cjs/components/theme-panel.js +3 -3
- package/dist/cjs/components/theme-panel.js.map +2 -2
- package/dist/cjs/components/theme.js +1 -1
- package/dist/cjs/components/theme.js.map +2 -2
- package/dist/cjs/components/theme.props.d.ts +1 -1
- package/dist/cjs/components/theme.props.js +1 -1
- package/dist/cjs/components/theme.props.js.map +2 -2
- package/dist/cjs/components/toggle-button.js +1 -1
- package/dist/cjs/components/toggle-button.js.map +2 -2
- package/dist/cjs/components/toggle-icon-button.js +1 -1
- package/dist/cjs/components/toggle-icon-button.js.map +2 -2
- package/dist/cjs/components/tooltip.js +1 -1
- package/dist/cjs/components/tooltip.js.map +2 -2
- package/dist/cjs/components/user-card.js +1 -1
- package/dist/cjs/components/user-card.js.map +2 -2
- package/dist/cjs/components/virtual-menu.d.ts.map +1 -1
- package/dist/cjs/components/virtual-menu.js +1 -1
- package/dist/cjs/components/virtual-menu.js.map +4 -4
- package/dist/cjs/helpers/extract-props.js +1 -1
- package/dist/cjs/helpers/extract-props.js.map +2 -2
- package/dist/cjs/helpers/get-margin-styles.js +1 -1
- package/dist/cjs/helpers/get-margin-styles.js.map +2 -2
- package/dist/cjs/hooks/use-breakpoint.d.ts +4 -1
- package/dist/cjs/hooks/use-breakpoint.d.ts.map +1 -1
- package/dist/cjs/hooks/use-breakpoint.js +1 -1
- package/dist/cjs/hooks/use-breakpoint.js.map +3 -3
- package/dist/cjs/index.js +5 -5
- package/dist/cjs/index.js.map +4 -4
- package/dist/cjs/props/index.js +1 -1
- package/dist/cjs/props/index.js.map +3 -3
- package/dist/esm/{chunk-P7HYVJSU.js → chunk-2TIADHPD.js} +2 -2
- package/dist/esm/chunk-37OGSEQR.js +2 -0
- package/dist/esm/chunk-37OGSEQR.js.map +7 -0
- package/dist/esm/{chunk-RMKXWYOV.js → chunk-3OBXZUFJ.js} +2 -2
- package/dist/esm/{chunk-S2HA3W3V.js → chunk-3R7XMRV5.js} +2 -2
- package/dist/esm/chunk-4SMJ7D4S.js +2 -0
- package/dist/esm/chunk-4SMJ7D4S.js.map +7 -0
- package/dist/esm/{chunk-S56YSRHP.js → chunk-56TS6OKQ.js} +2 -2
- package/dist/esm/{chunk-2FYJTSOP.js → chunk-5BYHEYO6.js} +2 -2
- package/dist/esm/{chunk-B24BDVG2.js → chunk-5MNBQROW.js} +2 -2
- package/dist/esm/{chunk-W7N7V5YD.js → chunk-7ESHXHHO.js} +2 -2
- package/dist/esm/{chunk-CRWYCLTE.js → chunk-ABSKRHVM.js} +2 -2
- package/dist/esm/chunk-ADBLURLJ.js +2 -0
- package/dist/esm/chunk-ADBLURLJ.js.map +7 -0
- package/dist/esm/{chunk-3MWWP4MW.js → chunk-BBJUB52V.js} +2 -2
- package/dist/esm/{chunk-PTLFMWCN.js → chunk-CQNPBTM5.js} +2 -2
- package/dist/esm/{chunk-GJSGKE7B.js → chunk-CTA5ODAO.js} +2 -2
- package/dist/esm/{chunk-GWXVETMF.js → chunk-DCAZPMOB.js} +2 -2
- package/dist/esm/{chunk-PLWXTEVE.js → chunk-DMJJM5IS.js} +2 -2
- package/dist/esm/{chunk-A2RZGGMY.js → chunk-DQAUX5ZL.js} +2 -2
- package/dist/esm/{chunk-6XGZPIUT.js → chunk-DX5JJYMZ.js} +2 -2
- package/dist/esm/{chunk-6XGZPIUT.js.map → chunk-DX5JJYMZ.js.map} +2 -2
- package/dist/esm/{chunk-YUP6EICB.js → chunk-DXL6V2A5.js} +2 -2
- package/dist/esm/{chunk-XMRIRFM7.js → chunk-FG7XM7KJ.js} +2 -2
- package/dist/esm/{chunk-IKSN4RNB.js → chunk-FIB3XATL.js} +3 -3
- package/dist/esm/chunk-FMBECDL4.js +2 -0
- package/dist/esm/{chunk-4XJY6FIK.js.map → chunk-FMBECDL4.js.map} +3 -3
- package/dist/esm/{chunk-374ZYJUP.js → chunk-HBR42MIX.js} +2 -2
- package/dist/esm/{chunk-2UPAYDKR.js → chunk-HIKVMKYQ.js} +2 -2
- package/dist/esm/{chunk-VX6ARMWP.js → chunk-HSAG7C53.js} +2 -2
- package/dist/esm/{chunk-OSRJRBKP.js → chunk-HW324FK3.js} +2 -2
- package/dist/esm/{chunk-DNHUQLXO.js → chunk-JBO5YOUM.js} +2 -2
- package/dist/esm/{chunk-HF5WY5YE.js → chunk-JGLAE5G7.js} +2 -2
- package/dist/esm/{chunk-4YFJWXL2.js → chunk-JJKQ7CGI.js} +2 -2
- package/dist/esm/chunk-JSW6J6RS.js +2 -0
- package/dist/esm/chunk-JSW6J6RS.js.map +7 -0
- package/dist/esm/chunk-KRDP5SQ7.js +2 -0
- package/dist/esm/chunk-KRDP5SQ7.js.map +7 -0
- package/dist/esm/{chunk-CWRNW44F.js → chunk-L6PVH3RM.js} +2 -2
- package/dist/esm/{chunk-MK2R6DAU.js → chunk-LAOMR7SE.js} +2 -2
- package/dist/esm/{chunk-FHOCUZDR.js → chunk-NIQT45PJ.js} +2 -2
- package/dist/esm/chunk-NKEJTTIL.js +2 -0
- package/dist/esm/chunk-NKEJTTIL.js.map +7 -0
- package/dist/esm/chunk-NVDXXGVW.js +2 -0
- package/dist/esm/chunk-NVDXXGVW.js.map +7 -0
- package/dist/esm/chunk-OS3FCYZY.js +2 -0
- package/dist/esm/{chunk-7QDTSBJF.js → chunk-OYF6YXH7.js} +2 -2
- package/dist/esm/{chunk-WFMYNZXZ.js → chunk-P5OSU4NX.js} +2 -2
- package/dist/esm/{chunk-QEOAXJLN.js → chunk-PTS6QYQW.js} +2 -2
- package/dist/esm/{chunk-CVWCKOHO.js → chunk-RLPKKCBL.js} +2 -2
- package/dist/esm/{chunk-LKAK5GXF.js → chunk-SPIU5JYC.js} +2 -2
- package/dist/esm/chunk-SZTZ2XLI.js +2 -0
- package/dist/esm/chunk-SZTZ2XLI.js.map +7 -0
- package/dist/esm/chunk-T2FZN7G3.js +2 -0
- package/dist/esm/chunk-T2FZN7G3.js.map +7 -0
- package/dist/esm/{chunk-4AQTUBVP.js → chunk-T4UHUQFJ.js} +2 -2
- package/dist/esm/{chunk-K6QZMNCD.js → chunk-TS623UPD.js} +2 -2
- package/dist/esm/{chunk-YV2KYHGR.js → chunk-UBOOUDS4.js} +2 -2
- package/dist/esm/{chunk-D6B7IMZU.js → chunk-UFI53QUC.js} +2 -2
- package/dist/esm/{chunk-AU3D6F42.js → chunk-UIRSGVJG.js} +2 -2
- package/dist/esm/{chunk-FXUUI6Z2.js → chunk-UUUZXUIP.js} +2 -2
- package/dist/esm/{chunk-25WZA7ZU.js → chunk-VA4CTVQL.js} +2 -2
- package/dist/esm/{chunk-TOLLPRMM.js → chunk-VNPNEJI6.js} +2 -2
- package/dist/esm/{chunk-6IGTK4JE.js → chunk-YMUGKYGW.js} +2 -2
- package/dist/esm/chunk-ZWYYPFZW.js +2 -0
- package/dist/esm/chunk-ZWYYPFZW.js.map +7 -0
- package/dist/esm/{chunk-M24UXMOQ.js → chunk-ZXZOH63L.js} +2 -2
- package/dist/esm/components/_internal/base-button.js +1 -1
- package/dist/esm/components/_internal/base-button.props.js +1 -1
- package/dist/esm/components/_internal/base-checkbox.props.js +1 -1
- package/dist/esm/components/_internal/base-menu.props.js +1 -1
- package/dist/esm/components/_internal/base-menu.utils.d.ts +48 -0
- package/dist/esm/components/_internal/base-menu.utils.d.ts.map +1 -0
- package/dist/esm/components/_internal/base-menu.utils.js +2 -0
- package/dist/esm/components/_internal/base-menu.utils.js.map +7 -0
- package/dist/esm/components/_internal/base-radio.props.js +1 -1
- package/dist/esm/components/_internal/base-tab-list.props.js +1 -1
- package/dist/esm/components/_internal/dropdown-menu-drill-down.d.ts +77 -59
- package/dist/esm/components/_internal/dropdown-menu-drill-down.d.ts.map +1 -1
- package/dist/esm/components/_internal/dropdown-menu-drill-down.js +1 -1
- package/dist/esm/components/_internal/menu-context.d.ts +7 -3
- package/dist/esm/components/_internal/menu-context.d.ts.map +1 -1
- package/dist/esm/components/_internal/menu-context.js +1 -1
- package/dist/esm/components/_internal/shell-bottom.js +1 -1
- package/dist/esm/components/_internal/shell-handles.js +1 -1
- package/dist/esm/components/_internal/shell-inspector.js +1 -1
- package/dist/esm/components/_internal/shell-prop-helpers.js +1 -1
- package/dist/esm/components/_internal/shell-resize.js +1 -1
- package/dist/esm/components/_internal/shell-sidebar.js +1 -1
- package/dist/esm/components/accessible-icon.js +1 -1
- package/dist/esm/components/accordion.js +1 -1
- package/dist/esm/components/accordion.props.js +1 -1
- package/dist/esm/components/alert-dialog.js +1 -1
- package/dist/esm/components/alert-dialog.props.js +1 -1
- package/dist/esm/components/aspect-ratio.js +1 -1
- package/dist/esm/components/avatar.js +1 -1
- package/dist/esm/components/avatar.props.js +1 -1
- package/dist/esm/components/badge.js +1 -1
- package/dist/esm/components/badge.props.js +1 -1
- package/dist/esm/components/blockquote.js +1 -1
- package/dist/esm/components/blockquote.props.js +1 -1
- package/dist/esm/components/box.js +1 -1
- package/dist/esm/components/box.props.js +1 -1
- package/dist/esm/components/button.js +1 -1
- package/dist/esm/components/button.props.js +1 -1
- package/dist/esm/components/callout.js +1 -1
- package/dist/esm/components/callout.props.js +1 -1
- package/dist/esm/components/card.js +1 -1
- package/dist/esm/components/card.props.js +1 -1
- package/dist/esm/components/chatbar.d.ts +46 -44
- package/dist/esm/components/chatbar.d.ts.map +1 -1
- package/dist/esm/components/chatbar.js +1 -1
- package/dist/esm/components/checkbox-cards.js +1 -1
- package/dist/esm/components/checkbox-cards.props.js +1 -1
- package/dist/esm/components/checkbox-group.js +1 -1
- package/dist/esm/components/checkbox-group.primitive.js +1 -1
- package/dist/esm/components/checkbox-group.props.js +1 -1
- package/dist/esm/components/checkbox.js +1 -1
- package/dist/esm/components/checkbox.props.js +1 -1
- package/dist/esm/components/code.js +1 -1
- package/dist/esm/components/code.props.js +1 -1
- package/dist/esm/components/combobox.d.ts +28 -15
- package/dist/esm/components/combobox.d.ts.map +1 -1
- package/dist/esm/components/combobox.js +1 -1
- package/dist/esm/components/combobox.props.d.ts +48 -0
- package/dist/esm/components/combobox.props.d.ts.map +1 -1
- package/dist/esm/components/combobox.props.js +1 -1
- package/dist/esm/components/container.js +1 -1
- package/dist/esm/components/container.props.js +1 -1
- package/dist/esm/components/context-menu.d.ts +18 -5
- package/dist/esm/components/context-menu.d.ts.map +1 -1
- package/dist/esm/components/context-menu.js +1 -1
- package/dist/esm/components/context-menu.props.d.ts +1 -1
- package/dist/esm/components/context-menu.props.d.ts.map +1 -1
- package/dist/esm/components/context-menu.props.js +1 -1
- package/dist/esm/components/data-list.js +1 -1
- package/dist/esm/components/data-list.props.js +1 -1
- package/dist/esm/components/dialog.js +1 -1
- package/dist/esm/components/dialog.props.js +1 -1
- package/dist/esm/components/dropdown-menu.d.ts +11 -18
- package/dist/esm/components/dropdown-menu.d.ts.map +1 -1
- package/dist/esm/components/dropdown-menu.js +1 -1
- package/dist/esm/components/dropdown-menu.props.js +1 -1
- package/dist/esm/components/em.js +1 -1
- package/dist/esm/components/em.props.js +1 -1
- package/dist/esm/components/flex.js +1 -1
- package/dist/esm/components/flex.props.js +1 -1
- package/dist/esm/components/grid.js +1 -1
- package/dist/esm/components/grid.props.js +1 -1
- package/dist/esm/components/heading.js +1 -1
- package/dist/esm/components/heading.props.js +1 -1
- package/dist/esm/components/hover-card.js +1 -1
- package/dist/esm/components/hover-card.props.js +1 -1
- package/dist/esm/components/icon-button.js +1 -1
- package/dist/esm/components/icon-button.props.js +1 -1
- package/dist/esm/components/icons.js +1 -1
- package/dist/esm/components/image.js +1 -1
- package/dist/esm/components/image.props.js +1 -1
- package/dist/esm/components/index.js +1 -1
- package/dist/esm/components/inset.js +1 -1
- package/dist/esm/components/inset.props.js +1 -1
- package/dist/esm/components/kbd.js +1 -1
- package/dist/esm/components/kbd.props.js +1 -1
- package/dist/esm/components/link.js +1 -1
- package/dist/esm/components/link.props.js +1 -1
- package/dist/esm/components/navbar.js +1 -1
- package/dist/esm/components/navbar.props.js +1 -1
- package/dist/esm/components/popover.js +1 -1
- package/dist/esm/components/popover.props.js +1 -1
- package/dist/esm/components/portal.js +1 -1
- package/dist/esm/components/progress.js +1 -1
- package/dist/esm/components/progress.props.js +1 -1
- package/dist/esm/components/quote.js +1 -1
- package/dist/esm/components/quote.props.js +1 -1
- package/dist/esm/components/radio-cards.js +1 -1
- package/dist/esm/components/radio-cards.props.js +1 -1
- package/dist/esm/components/radio-group.js +1 -1
- package/dist/esm/components/radio-group.props.js +1 -1
- package/dist/esm/components/radio.js +1 -1
- package/dist/esm/components/radio.props.js +1 -1
- package/dist/esm/components/reset.js +1 -1
- package/dist/esm/components/schemas/base-button.schema.d.ts +111 -256
- package/dist/esm/components/schemas/base-button.schema.d.ts.map +1 -1
- package/dist/esm/components/schemas/base-button.schema.js +1 -1
- package/dist/esm/components/schemas/button.schema.d.ts +136 -557
- package/dist/esm/components/schemas/button.schema.d.ts.map +1 -1
- package/dist/esm/components/schemas/button.schema.js +1 -1
- package/dist/esm/components/schemas/icon-button.schema.d.ts +123 -240
- package/dist/esm/components/schemas/icon-button.schema.d.ts.map +1 -1
- package/dist/esm/components/schemas/icon-button.schema.js +1 -1
- package/dist/esm/components/schemas/index.js +1 -1
- package/dist/esm/components/schemas/shell.schema.d.ts +592 -851
- package/dist/esm/components/schemas/shell.schema.d.ts.map +1 -1
- package/dist/esm/components/schemas/shell.schema.js +1 -1
- package/dist/esm/components/schemas/toggle-button.schema.d.ts +138 -1026
- package/dist/esm/components/schemas/toggle-button.schema.d.ts.map +1 -1
- package/dist/esm/components/schemas/toggle-button.schema.js +1 -1
- package/dist/esm/components/schemas/toggle-icon-button.schema.d.ts +124 -465
- package/dist/esm/components/schemas/toggle-icon-button.schema.d.ts.map +1 -1
- package/dist/esm/components/schemas/toggle-icon-button.schema.js +1 -1
- package/dist/esm/components/scroll-area.js +1 -1
- package/dist/esm/components/scroll-area.props.js +1 -1
- package/dist/esm/components/section.js +1 -1
- package/dist/esm/components/section.props.js +1 -1
- package/dist/esm/components/segmented-control.js +1 -1
- package/dist/esm/components/segmented-control.props.js +1 -1
- package/dist/esm/components/select.js +1 -1
- package/dist/esm/components/select.props.js +1 -1
- package/dist/esm/components/separator.js +1 -1
- package/dist/esm/components/separator.props.js +1 -1
- package/dist/esm/components/sheet.js +1 -1
- package/dist/esm/components/shell.context.js +1 -1
- package/dist/esm/components/shell.hooks.js +1 -1
- package/dist/esm/components/shell.js +1 -1
- package/dist/esm/components/shell.types.js +1 -1
- package/dist/esm/components/sidebar.js +1 -1
- package/dist/esm/components/sidebar.props.js +1 -1
- package/dist/esm/components/skeleton.js +1 -1
- package/dist/esm/components/skeleton.props.js +1 -1
- package/dist/esm/components/slider.js +1 -1
- package/dist/esm/components/slider.props.js +1 -1
- package/dist/esm/components/slot.d.ts +6 -2
- package/dist/esm/components/slot.d.ts.map +1 -1
- package/dist/esm/components/slot.js +1 -1
- package/dist/esm/components/spinner.js +1 -1
- package/dist/esm/components/spinner.props.js +1 -1
- package/dist/esm/components/strong.js +1 -1
- package/dist/esm/components/strong.props.js +1 -1
- package/dist/esm/components/switch.js +1 -1
- package/dist/esm/components/switch.props.js +1 -1
- package/dist/esm/components/tab-nav.js +1 -1
- package/dist/esm/components/tab-nav.props.js +1 -1
- package/dist/esm/components/table.js +1 -1
- package/dist/esm/components/table.props.js +1 -1
- package/dist/esm/components/tabs.js +1 -1
- package/dist/esm/components/tabs.props.js +1 -1
- package/dist/esm/components/text-area.js +1 -1
- package/dist/esm/components/text-area.props.js +1 -1
- package/dist/esm/components/text-field.js +1 -1
- package/dist/esm/components/text-field.props.js +1 -1
- package/dist/esm/components/text.js +1 -1
- package/dist/esm/components/text.props.js +1 -1
- package/dist/esm/components/theme-panel.js +1 -1
- package/dist/esm/components/theme.js +1 -1
- package/dist/esm/components/theme.props.d.ts +1 -1
- package/dist/esm/components/theme.props.js +1 -1
- package/dist/esm/components/toggle-button.js +1 -1
- package/dist/esm/components/toggle-icon-button.js +1 -1
- package/dist/esm/components/toolbar.js +1 -1
- package/dist/esm/components/tooltip.js +1 -1
- package/dist/esm/components/tooltip.props.js +1 -1
- package/dist/esm/components/user-card.js +1 -1
- package/dist/esm/components/user-card.props.js +1 -1
- package/dist/esm/components/virtual-menu.d.ts.map +1 -1
- package/dist/esm/components/virtual-menu.js +1 -1
- package/dist/esm/components/visually-hidden.js +1 -1
- package/dist/esm/helpers/compile-prop-defs.js +1 -1
- package/dist/esm/helpers/extract-margin-props.js +1 -1
- package/dist/esm/helpers/extract-props.js +1 -1
- package/dist/esm/helpers/font-config.js +1 -1
- package/dist/esm/helpers/get-margin-styles.js +1 -1
- package/dist/esm/helpers/get-matching-gray-color.js +1 -1
- package/dist/esm/helpers/get-responsive-styles.js +1 -1
- package/dist/esm/helpers/get-subtree.js +1 -1
- package/dist/esm/helpers/has-own-property.js +1 -1
- package/dist/esm/helpers/index.js +1 -1
- package/dist/esm/helpers/inert.js +1 -1
- package/dist/esm/helpers/is-responsive-object.js +1 -1
- package/dist/esm/helpers/map-prop-values.js +1 -1
- package/dist/esm/helpers/merge-styles.js +1 -1
- package/dist/esm/helpers/normalize-to-px.js +1 -1
- package/dist/esm/helpers/require-react-element.js +1 -1
- package/dist/esm/helpers/use-deprecation-warning.js +1 -1
- package/dist/esm/hooks/index.js +1 -1
- package/dist/esm/hooks/use-body-pointer-events-cleanup.js +1 -1
- package/dist/esm/hooks/use-breakpoint.d.ts +4 -1
- package/dist/esm/hooks/use-breakpoint.d.ts.map +1 -1
- package/dist/esm/hooks/use-breakpoint.js +1 -1
- package/dist/esm/hooks/use-live-announcer.js +1 -1
- package/dist/esm/hooks/use-prop-synced-state.js +1 -1
- package/dist/esm/hooks/use-toggle-state.js +1 -1
- package/dist/esm/hooks/use-tooltip-wrapper.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/props/as-child.prop.js +1 -1
- package/dist/esm/props/color.prop.js +1 -1
- package/dist/esm/props/font-family.prop.js +1 -1
- package/dist/esm/props/gap.props.js +1 -1
- package/dist/esm/props/height.props.js +1 -1
- package/dist/esm/props/high-contrast.prop.js +1 -1
- package/dist/esm/props/index.js +1 -1
- package/dist/esm/props/layout.props.js +1 -1
- package/dist/esm/props/leading-trim.prop.js +1 -1
- package/dist/esm/props/margin.props.js +1 -1
- package/dist/esm/props/padding.props.js +1 -1
- package/dist/esm/props/prop-def.js +1 -1
- package/dist/esm/props/radius.prop.js +1 -1
- package/dist/esm/props/shadow.props.js +1 -1
- package/dist/esm/props/text-align.prop.js +1 -1
- package/dist/esm/props/text-wrap.prop.js +1 -1
- package/dist/esm/props/truncate.prop.js +1 -1
- package/dist/esm/props/weight.prop.js +1 -1
- package/dist/esm/props/width.props.js +1 -1
- package/fonts.css +2 -0
- package/package.json +36 -36
- package/schemas/base-button.json +66 -60
- package/schemas/button.json +80 -74
- package/schemas/icon-button.json +78 -72
- package/schemas/index.json +390 -360
- package/schemas/toggle-button.json +84 -78
- package/schemas/toggle-icon-button.json +82 -76
- package/src/components/_internal/base-card.css +5 -5
- package/src/components/_internal/base-checkbox.css +17 -3
- package/src/components/_internal/base-dialog.css +4 -4
- package/src/components/_internal/base-menu.css +68 -143
- package/src/components/_internal/base-menu.utils.tsx +144 -0
- package/src/components/_internal/dropdown-menu-drill-down.tsx +281 -183
- package/src/components/_internal/menu-context.tsx +24 -15
- package/src/components/accordion.css +5 -5
- package/src/components/callout.css +5 -5
- package/src/components/chatbar.css +100 -32
- package/src/components/chatbar.tsx +739 -735
- package/src/components/checkbox-cards.css +30 -0
- package/src/components/combobox.css +62 -115
- package/src/components/combobox.props.tsx +14 -0
- package/src/components/combobox.tsx +440 -212
- package/src/components/context-menu.props.tsx +4 -1
- package/src/components/context-menu.tsx +108 -62
- package/src/components/dropdown-menu.css +41 -121
- package/src/components/dropdown-menu.tsx +430 -275
- package/src/components/hover-card.css +3 -3
- package/src/components/popover.css +4 -4
- package/src/components/radio-cards.css +30 -0
- package/src/components/schemas/shell.schema.ts +11 -18
- package/src/components/scroll-area.css +2 -3
- package/src/components/select.css +2 -2
- package/src/components/shell.css +1 -1
- package/src/components/table.css +5 -5
- package/src/components/theme.props.tsx +1 -1
- package/src/components/tooltip.css +1 -1
- package/src/components/virtual-menu.tsx +12 -8
- package/src/hooks/use-breakpoint.ts +19 -3
- package/src/styles/fonts.css +6 -1
- package/src/styles/tokens/font-family.css +13 -5
- package/src/styles/tokens/radius.css +47 -4
- package/styles.css +801 -784
- package/tokens/base.css +19 -2
- package/tokens.css +19 -2
- package/dist/esm/chunk-3XT5P2HO.js +0 -2
- package/dist/esm/chunk-4XJY6FIK.js +0 -2
- package/dist/esm/chunk-4Z33XHOK.js +0 -2
- package/dist/esm/chunk-4Z33XHOK.js.map +0 -7
- package/dist/esm/chunk-E2Z5IA2P.js +0 -2
- package/dist/esm/chunk-E2Z5IA2P.js.map +0 -7
- package/dist/esm/chunk-HVWEPVBH.js +0 -2
- package/dist/esm/chunk-HVWEPVBH.js.map +0 -7
- package/dist/esm/chunk-KKBP2CRH.js +0 -2
- package/dist/esm/chunk-KKBP2CRH.js.map +0 -7
- package/dist/esm/chunk-MOR3NSXQ.js +0 -2
- package/dist/esm/chunk-MOR3NSXQ.js.map +0 -7
- package/dist/esm/chunk-QCNUTT4R.js +0 -2
- package/dist/esm/chunk-QCNUTT4R.js.map +0 -7
- package/dist/esm/chunk-UGD7Z3L4.js +0 -2
- package/dist/esm/chunk-UGD7Z3L4.js.map +0 -7
- package/dist/esm/chunk-YEB3H7QN.js +0 -2
- package/dist/esm/chunk-YEB3H7QN.js.map +0 -7
- package/dist/esm/chunk-ZY6SQWHT.js +0 -2
- package/dist/esm/chunk-ZY6SQWHT.js.map +0 -7
- /package/dist/esm/{chunk-P7HYVJSU.js.map → chunk-2TIADHPD.js.map} +0 -0
- /package/dist/esm/{chunk-RMKXWYOV.js.map → chunk-3OBXZUFJ.js.map} +0 -0
- /package/dist/esm/{chunk-S2HA3W3V.js.map → chunk-3R7XMRV5.js.map} +0 -0
- /package/dist/esm/{chunk-S56YSRHP.js.map → chunk-56TS6OKQ.js.map} +0 -0
- /package/dist/esm/{chunk-2FYJTSOP.js.map → chunk-5BYHEYO6.js.map} +0 -0
- /package/dist/esm/{chunk-B24BDVG2.js.map → chunk-5MNBQROW.js.map} +0 -0
- /package/dist/esm/{chunk-W7N7V5YD.js.map → chunk-7ESHXHHO.js.map} +0 -0
- /package/dist/esm/{chunk-CRWYCLTE.js.map → chunk-ABSKRHVM.js.map} +0 -0
- /package/dist/esm/{chunk-3MWWP4MW.js.map → chunk-BBJUB52V.js.map} +0 -0
- /package/dist/esm/{chunk-PTLFMWCN.js.map → chunk-CQNPBTM5.js.map} +0 -0
- /package/dist/esm/{chunk-GJSGKE7B.js.map → chunk-CTA5ODAO.js.map} +0 -0
- /package/dist/esm/{chunk-GWXVETMF.js.map → chunk-DCAZPMOB.js.map} +0 -0
- /package/dist/esm/{chunk-PLWXTEVE.js.map → chunk-DMJJM5IS.js.map} +0 -0
- /package/dist/esm/{chunk-A2RZGGMY.js.map → chunk-DQAUX5ZL.js.map} +0 -0
- /package/dist/esm/{chunk-YUP6EICB.js.map → chunk-DXL6V2A5.js.map} +0 -0
- /package/dist/esm/{chunk-XMRIRFM7.js.map → chunk-FG7XM7KJ.js.map} +0 -0
- /package/dist/esm/{chunk-IKSN4RNB.js.map → chunk-FIB3XATL.js.map} +0 -0
- /package/dist/esm/{chunk-374ZYJUP.js.map → chunk-HBR42MIX.js.map} +0 -0
- /package/dist/esm/{chunk-2UPAYDKR.js.map → chunk-HIKVMKYQ.js.map} +0 -0
- /package/dist/esm/{chunk-VX6ARMWP.js.map → chunk-HSAG7C53.js.map} +0 -0
- /package/dist/esm/{chunk-OSRJRBKP.js.map → chunk-HW324FK3.js.map} +0 -0
- /package/dist/esm/{chunk-DNHUQLXO.js.map → chunk-JBO5YOUM.js.map} +0 -0
- /package/dist/esm/{chunk-HF5WY5YE.js.map → chunk-JGLAE5G7.js.map} +0 -0
- /package/dist/esm/{chunk-4YFJWXL2.js.map → chunk-JJKQ7CGI.js.map} +0 -0
- /package/dist/esm/{chunk-CWRNW44F.js.map → chunk-L6PVH3RM.js.map} +0 -0
- /package/dist/esm/{chunk-MK2R6DAU.js.map → chunk-LAOMR7SE.js.map} +0 -0
- /package/dist/esm/{chunk-FHOCUZDR.js.map → chunk-NIQT45PJ.js.map} +0 -0
- /package/dist/esm/{chunk-3XT5P2HO.js.map → chunk-OS3FCYZY.js.map} +0 -0
- /package/dist/esm/{chunk-7QDTSBJF.js.map → chunk-OYF6YXH7.js.map} +0 -0
- /package/dist/esm/{chunk-WFMYNZXZ.js.map → chunk-P5OSU4NX.js.map} +0 -0
- /package/dist/esm/{chunk-QEOAXJLN.js.map → chunk-PTS6QYQW.js.map} +0 -0
- /package/dist/esm/{chunk-CVWCKOHO.js.map → chunk-RLPKKCBL.js.map} +0 -0
- /package/dist/esm/{chunk-LKAK5GXF.js.map → chunk-SPIU5JYC.js.map} +0 -0
- /package/dist/esm/{chunk-4AQTUBVP.js.map → chunk-T4UHUQFJ.js.map} +0 -0
- /package/dist/esm/{chunk-K6QZMNCD.js.map → chunk-TS623UPD.js.map} +0 -0
- /package/dist/esm/{chunk-YV2KYHGR.js.map → chunk-UBOOUDS4.js.map} +0 -0
- /package/dist/esm/{chunk-D6B7IMZU.js.map → chunk-UFI53QUC.js.map} +0 -0
- /package/dist/esm/{chunk-AU3D6F42.js.map → chunk-UIRSGVJG.js.map} +0 -0
- /package/dist/esm/{chunk-FXUUI6Z2.js.map → chunk-UUUZXUIP.js.map} +0 -0
- /package/dist/esm/{chunk-25WZA7ZU.js.map → chunk-VA4CTVQL.js.map} +0 -0
- /package/dist/esm/{chunk-TOLLPRMM.js.map → chunk-VNPNEJI6.js.map} +0 -0
- /package/dist/esm/{chunk-6IGTK4JE.js.map → chunk-YMUGKYGW.js.map} +0 -0
- /package/dist/esm/{chunk-M24UXMOQ.js.map → chunk-ZXZOH63L.js.map} +0 -0
|
@@ -1,23 +1,30 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Combobox
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* -
|
|
9
|
-
*
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
12
|
-
*
|
|
4
|
+
* Combobox: Radix Popover for positioning, dismissal and focus; cmdk for search,
|
|
5
|
+
* filtering and keyboard navigation.
|
|
6
|
+
*
|
|
7
|
+
* Render path. State is split so an interaction re-renders only what reads it:
|
|
8
|
+
* - `ComboboxContext` (Trigger, Value, Content): config and the selected value.
|
|
9
|
+
* Open state is not in it, so opening and closing re-render no consumer.
|
|
10
|
+
* - `ComboboxSearchContext` (Input only): the search text.
|
|
11
|
+
* - `ComboboxItemContext` (Items): stable values only. Items read "am I selected"
|
|
12
|
+
* from a store through `useSyncExternalStore`, so a selection re-renders the old
|
|
13
|
+
* and the new selected item, not all N.
|
|
14
|
+
*
|
|
15
|
+
* Highlight. cmdk's `data-selected` is the single highlight source, driven by both
|
|
16
|
+
* the pointer and the keyboard. There is no separate CSS `:hover` highlight, so two
|
|
17
|
+
* items are never lit at once and Enter always picks the lit item.
|
|
13
18
|
*/
|
|
14
19
|
|
|
15
20
|
import * as React from 'react';
|
|
16
21
|
import classNames from 'classnames';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
22
|
+
import { Popover as PopoverPrimitive } from 'radix-ui';
|
|
23
|
+
import { useCallbackRef, useComposedRefs, useControllableState, useLayoutEffect } from 'radix-ui/internal';
|
|
24
|
+
import { Command as CommandPrimitive, useCommandState } from 'cmdk';
|
|
19
25
|
|
|
20
26
|
import { extractProps } from '../helpers/extract-props.js';
|
|
27
|
+
import { useDeprecatedPanelBackgroundWarning } from '../helpers/use-deprecation-warning.js';
|
|
21
28
|
import { comboboxRootPropDefs, comboboxTriggerPropDefs, comboboxContentPropDefs } from './combobox.props.js';
|
|
22
29
|
import { marginPropDefs } from '../props/margin.props.js';
|
|
23
30
|
import { ChevronDownIcon, ThickCheckIcon } from './icons.js';
|
|
@@ -25,8 +32,9 @@ import { Theme, useThemeContext } from './theme.js';
|
|
|
25
32
|
import { requireReactElement } from '../helpers/require-react-element.js';
|
|
26
33
|
import * as Popover from './popover.js';
|
|
27
34
|
import { Slottable } from './slot.js';
|
|
28
|
-
import {
|
|
35
|
+
import { VisuallyHidden } from './visually-hidden.js';
|
|
29
36
|
|
|
37
|
+
import type { textFieldRootPropDefs } from './text-field.props.js';
|
|
30
38
|
import type { MarginProps } from '../props/margin.props.js';
|
|
31
39
|
import type { ComponentPropsWithout, RemovedProps } from '../helpers/component-props.js';
|
|
32
40
|
import type { GetPropDefTypes } from '../props/prop-def.js';
|
|
@@ -35,55 +43,100 @@ type TextFieldVariant = (typeof textFieldRootPropDefs.variant.values)[number];
|
|
|
35
43
|
type ComboboxValue = string | null;
|
|
36
44
|
type CommandFilter = (value: string, search: string, keywords?: string[]) => number;
|
|
37
45
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
// Hoisted so extractProps' compiled prop-def cache (keyed by object identity) hits.
|
|
47
|
+
const triggerSizingPropDefs = { size: comboboxRootPropDefs.size, highContrast: comboboxRootPropDefs.highContrast };
|
|
48
|
+
const contentSizePropDefs = { size: comboboxContentPropDefs.size };
|
|
49
|
+
|
|
50
|
+
const warned = new Set<string>();
|
|
51
|
+
function warnOnce(message: string) {
|
|
52
|
+
if (warned.has(message)) return;
|
|
53
|
+
warned.add(message);
|
|
54
|
+
console.warn(message);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// Selection store
|
|
59
|
+
// ============================================================================
|
|
60
|
+
|
|
61
|
+
interface SelectionStore {
|
|
62
|
+
get: () => ComboboxValue;
|
|
63
|
+
set: (value: ComboboxValue) => void;
|
|
64
|
+
subscribe: (listener: () => void) => () => void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function createSelectionStore(initial: ComboboxValue): SelectionStore {
|
|
68
|
+
let current = initial;
|
|
69
|
+
const listeners = new Set<() => void>();
|
|
70
|
+
return {
|
|
71
|
+
get: () => current,
|
|
72
|
+
set: (next) => {
|
|
73
|
+
if (Object.is(next, current)) return;
|
|
74
|
+
current = next;
|
|
75
|
+
listeners.forEach((listener) => listener());
|
|
76
|
+
},
|
|
77
|
+
subscribe: (listener) => {
|
|
78
|
+
listeners.add(listener);
|
|
79
|
+
return () => {
|
|
80
|
+
listeners.delete(listener);
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ============================================================================
|
|
87
|
+
// Contexts
|
|
88
|
+
// ============================================================================
|
|
89
|
+
|
|
42
90
|
interface ComboboxContextValue {
|
|
43
|
-
// Selection state
|
|
44
91
|
value: ComboboxValue;
|
|
45
|
-
|
|
46
|
-
// Open state
|
|
47
|
-
open: boolean;
|
|
92
|
+
displayValue?: string;
|
|
48
93
|
setOpen: (open: boolean) => void;
|
|
49
|
-
// Config (static, rarely changes)
|
|
50
94
|
size?: ComboboxRootOwnProps['size'];
|
|
51
95
|
highContrast?: boolean;
|
|
52
96
|
placeholder?: string;
|
|
53
97
|
searchPlaceholder?: string;
|
|
54
98
|
disabled?: boolean;
|
|
55
99
|
color?: string;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
100
|
+
loop: boolean;
|
|
101
|
+
shouldFilter: boolean;
|
|
102
|
+
filter?: CommandFilter;
|
|
103
|
+
triggerRef: React.RefObject<HTMLButtonElement | null>;
|
|
104
|
+
/** Reads the trigger's accessible name from the DOM (aria-label, aria-labelledby or <label>). */
|
|
105
|
+
getTriggerLabel: () => string | undefined;
|
|
60
106
|
}
|
|
61
107
|
|
|
62
108
|
const ComboboxContext = React.createContext<ComboboxContextValue | null>(null);
|
|
63
109
|
|
|
64
|
-
const useComboboxContext = (componentName
|
|
110
|
+
const useComboboxContext = (componentName: string) => {
|
|
65
111
|
const ctx = React.useContext(ComboboxContext);
|
|
66
112
|
if (!ctx) {
|
|
67
|
-
|
|
68
|
-
throw new Error(`${name} must be used within Combobox.Root`);
|
|
113
|
+
throw new Error(`Combobox.${componentName} must be used within Combobox.Root`);
|
|
69
114
|
}
|
|
70
115
|
return ctx;
|
|
71
116
|
};
|
|
72
117
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
118
|
+
interface ComboboxSearchContextValue {
|
|
119
|
+
value: string;
|
|
120
|
+
setValue: (value: string) => void;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const ComboboxSearchContext = React.createContext<ComboboxSearchContextValue | null>(null);
|
|
124
|
+
|
|
125
|
+
interface ComboboxItemContextValue {
|
|
126
|
+
store: SelectionStore;
|
|
127
|
+
onSelect: (value: string) => void;
|
|
128
|
+
disabled?: boolean;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const ComboboxItemContext = React.createContext<ComboboxItemContextValue | null>(null);
|
|
132
|
+
|
|
133
|
+
/** Values resolved by Content and read by Input and List. */
|
|
77
134
|
interface ComboboxContentContextValue {
|
|
78
135
|
variant: 'solid' | 'soft';
|
|
79
|
-
|
|
136
|
+
sizeClassName?: string;
|
|
80
137
|
color?: string;
|
|
81
138
|
material?: string;
|
|
82
|
-
|
|
83
|
-
// cmdk config passed down
|
|
84
|
-
loop?: boolean;
|
|
85
|
-
shouldFilter?: boolean;
|
|
86
|
-
filter?: CommandFilter;
|
|
139
|
+
label?: string;
|
|
87
140
|
}
|
|
88
141
|
|
|
89
142
|
const ComboboxContentContext = React.createContext<ComboboxContentContextValue | null>(null);
|
|
@@ -110,11 +163,15 @@ type ComboboxRootOwnProps = GetPropDefTypes<typeof comboboxRootPropDefs> & {
|
|
|
110
163
|
shouldFilter?: boolean;
|
|
111
164
|
loop?: boolean;
|
|
112
165
|
disabled?: boolean;
|
|
166
|
+
/** Clear the search text when an option is selected. Defaults to true. */
|
|
113
167
|
resetSearchOnSelect?: boolean;
|
|
168
|
+
/** Clear the search text when the popup is dismissed without a selection. Defaults to true. */
|
|
169
|
+
resetSearchOnClose?: boolean;
|
|
114
170
|
color?: (typeof comboboxTriggerPropDefs.color.values)[number];
|
|
115
171
|
/**
|
|
116
|
-
*
|
|
117
|
-
* Can be a string or function that receives the current value.
|
|
172
|
+
* Text shown in the trigger for the selected value. Without it the raw value is shown.
|
|
173
|
+
* Can be a string or a function that receives the current value. Pass a stable
|
|
174
|
+
* function (module scope or `useCallback`): an inline function runs on every render.
|
|
118
175
|
* @example displayValue={(v) => items.find(i => i.value === v)?.label}
|
|
119
176
|
*/
|
|
120
177
|
displayValue?: string | ((value: ComboboxValue) => string | undefined);
|
|
@@ -123,6 +180,32 @@ type ComboboxRootOwnProps = GetPropDefTypes<typeof comboboxRootPropDefs> & {
|
|
|
123
180
|
type PopoverRootProps = React.ComponentPropsWithoutRef<typeof Popover.Root>;
|
|
124
181
|
interface ComboboxRootProps extends PopoverRootProps, ComboboxRootOwnProps {}
|
|
125
182
|
|
|
183
|
+
function readElementLabel(el: HTMLElement): string | undefined {
|
|
184
|
+
const ariaLabel = el.getAttribute('aria-label')?.trim();
|
|
185
|
+
if (ariaLabel) return ariaLabel;
|
|
186
|
+
|
|
187
|
+
const labelledBy = el.getAttribute('aria-labelledby');
|
|
188
|
+
if (labelledBy) {
|
|
189
|
+
const text = labelledBy
|
|
190
|
+
.split(/\s+/)
|
|
191
|
+
.map((id) => el.ownerDocument.getElementById(id)?.textContent?.trim())
|
|
192
|
+
.filter(Boolean)
|
|
193
|
+
.join(' ');
|
|
194
|
+
if (text) return text;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const labels = (el as HTMLButtonElement).labels;
|
|
198
|
+
if (labels && labels.length > 0) {
|
|
199
|
+
const text = Array.from(labels)
|
|
200
|
+
.map((label) => label.textContent?.trim())
|
|
201
|
+
.filter(Boolean)
|
|
202
|
+
.join(' ');
|
|
203
|
+
if (text) return text;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
208
|
+
|
|
126
209
|
const ComboboxRoot: React.FC<ComboboxRootProps> = (props) => {
|
|
127
210
|
const {
|
|
128
211
|
children,
|
|
@@ -144,14 +227,12 @@ const ComboboxRoot: React.FC<ComboboxRootProps> = (props) => {
|
|
|
144
227
|
loop = true,
|
|
145
228
|
disabled,
|
|
146
229
|
resetSearchOnSelect = true,
|
|
230
|
+
resetSearchOnClose = true,
|
|
147
231
|
color,
|
|
148
232
|
displayValue: displayValueProp,
|
|
149
233
|
...rootProps
|
|
150
234
|
} = props;
|
|
151
235
|
|
|
152
|
-
// Generate stable ID for listbox accessibility linkage
|
|
153
|
-
const listboxId = React.useId();
|
|
154
|
-
|
|
155
236
|
const [open, setOpen] = useControllableState({
|
|
156
237
|
prop: openProp,
|
|
157
238
|
defaultProp: defaultOpen,
|
|
@@ -170,71 +251,70 @@ const ComboboxRoot: React.FC<ComboboxRootProps> = (props) => {
|
|
|
170
251
|
onChange: onSearchValueChange,
|
|
171
252
|
});
|
|
172
253
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}, [
|
|
181
|
-
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
254
|
+
const resolvedDisplayValue = typeof displayValueProp === 'function' ? displayValueProp(value) : displayValueProp;
|
|
255
|
+
|
|
256
|
+
// Items subscribe to this store instead of the context, so a selection
|
|
257
|
+
// re-renders only the items whose selected state flips.
|
|
258
|
+
const [store] = React.useState(() => createSelectionStore(value));
|
|
259
|
+
useLayoutEffect(() => {
|
|
260
|
+
store.set(value);
|
|
261
|
+
}, [store, value]);
|
|
262
|
+
|
|
263
|
+
// The radix setters change identity whenever their controlled prop changes.
|
|
264
|
+
// Reading them through callback refs keeps these handlers stable, so the
|
|
265
|
+
// contexts below do not change on every keystroke or selection.
|
|
266
|
+
const handleOpenChange = useCallbackRef((nextOpen: boolean) => {
|
|
267
|
+
setOpen(nextOpen);
|
|
268
|
+
if (!nextOpen && resetSearchOnClose) setSearchValue('');
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const onSelect = useCallbackRef((nextValue: string) => {
|
|
272
|
+
setValue(nextValue);
|
|
273
|
+
setOpen(false);
|
|
274
|
+
if (resetSearchOnSelect) setSearchValue('');
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
const triggerRef = React.useRef<HTMLButtonElement | null>(null);
|
|
278
|
+
const getTriggerLabel = React.useCallback(() => (triggerRef.current ? readElementLabel(triggerRef.current) : undefined), []);
|
|
193
279
|
|
|
194
|
-
// Single context value - memoized for performance
|
|
195
280
|
const contextValue = React.useMemo<ComboboxContextValue>(
|
|
196
281
|
() => ({
|
|
197
282
|
value,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
setOpen,
|
|
283
|
+
displayValue: resolvedDisplayValue,
|
|
284
|
+
setOpen: handleOpenChange,
|
|
201
285
|
size,
|
|
202
286
|
highContrast,
|
|
203
287
|
placeholder,
|
|
204
288
|
searchPlaceholder,
|
|
205
289
|
disabled,
|
|
206
290
|
color,
|
|
207
|
-
|
|
208
|
-
|
|
291
|
+
loop,
|
|
292
|
+
shouldFilter,
|
|
293
|
+
filter,
|
|
294
|
+
triggerRef,
|
|
295
|
+
getTriggerLabel,
|
|
209
296
|
}),
|
|
210
|
-
[value,
|
|
297
|
+
[value, resolvedDisplayValue, handleOpenChange, size, highContrast, placeholder, searchPlaceholder, disabled, color, loop, shouldFilter, filter, getTriggerLabel],
|
|
211
298
|
);
|
|
212
299
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
300
|
+
const searchContextValue = React.useMemo<ComboboxSearchContextValue>(() => ({ value: searchValue, setValue: setSearchValue }), [searchValue, setSearchValue]);
|
|
301
|
+
|
|
302
|
+
const itemContextValue = React.useMemo<ComboboxItemContextValue>(() => ({ store, onSelect, disabled }), [store, onSelect, disabled]);
|
|
216
303
|
|
|
217
304
|
return (
|
|
218
305
|
<ComboboxContext.Provider value={contextValue}>
|
|
219
|
-
<
|
|
220
|
-
<
|
|
221
|
-
{
|
|
222
|
-
|
|
223
|
-
|
|
306
|
+
<ComboboxSearchContext.Provider value={searchContextValue}>
|
|
307
|
+
<ComboboxItemContext.Provider value={itemContextValue}>
|
|
308
|
+
<Popover.Root open={open} onOpenChange={handleOpenChange} {...rootProps}>
|
|
309
|
+
{children}
|
|
310
|
+
</Popover.Root>
|
|
311
|
+
</ComboboxItemContext.Provider>
|
|
312
|
+
</ComboboxSearchContext.Provider>
|
|
224
313
|
</ComboboxContext.Provider>
|
|
225
314
|
);
|
|
226
315
|
};
|
|
227
316
|
ComboboxRoot.displayName = 'Combobox.Root';
|
|
228
317
|
|
|
229
|
-
// Separate ref context for cmdk config to avoid re-renders
|
|
230
|
-
const CmdkConfigContext = React.createContext<React.MutableRefObject<{
|
|
231
|
-
filter?: CommandFilter;
|
|
232
|
-
shouldFilter: boolean;
|
|
233
|
-
loop: boolean;
|
|
234
|
-
searchValue: string;
|
|
235
|
-
setSearchValue: (value: string) => void;
|
|
236
|
-
}> | null>(null);
|
|
237
|
-
|
|
238
318
|
// ============================================================================
|
|
239
319
|
// Trigger
|
|
240
320
|
// ============================================================================
|
|
@@ -247,28 +327,78 @@ interface ComboboxTriggerProps extends NativeTriggerProps, MarginProps, Combobox
|
|
|
247
327
|
const ComboboxTrigger = React.forwardRef<ComboboxTriggerElement, ComboboxTriggerProps>((props, forwardedRef) => {
|
|
248
328
|
const ctx = useComboboxContext('Trigger');
|
|
249
329
|
|
|
250
|
-
const {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
330
|
+
const {
|
|
331
|
+
children,
|
|
332
|
+
className,
|
|
333
|
+
placeholder,
|
|
334
|
+
disabled,
|
|
335
|
+
readOnly,
|
|
336
|
+
error,
|
|
337
|
+
loading,
|
|
338
|
+
color,
|
|
339
|
+
radius,
|
|
340
|
+
material,
|
|
341
|
+
onClick,
|
|
342
|
+
onKeyDown,
|
|
343
|
+
type: buttonType,
|
|
344
|
+
...triggerProps
|
|
345
|
+
} = extractProps({ size: ctx.size, highContrast: ctx.highContrast, ...props }, triggerSizingPropDefs, comboboxTriggerPropDefs, marginPropDefs);
|
|
346
|
+
|
|
347
|
+
// `panelBackground` has a className prop def, so extractProps strips it.
|
|
348
|
+
const { panelBackground } = props;
|
|
349
|
+
const resolvedMaterial = material ?? panelBackground;
|
|
258
350
|
const isDisabled = disabled ?? ctx.disabled;
|
|
259
351
|
const resolvedColor = color ?? ctx.color;
|
|
352
|
+
// Read-only and loading triggers stay focusable but do not open.
|
|
353
|
+
const isBlocked = Boolean(readOnly || loading);
|
|
354
|
+
const isPlaceholder = ctx.value == null && ctx.displayValue == null;
|
|
355
|
+
|
|
356
|
+
const composedRef = useComposedRefs(forwardedRef, ctx.triggerRef);
|
|
357
|
+
|
|
358
|
+
const { getTriggerLabel } = ctx;
|
|
359
|
+
React.useEffect(() => {
|
|
360
|
+
if (process.env.NODE_ENV === 'production') return;
|
|
361
|
+
if (!getTriggerLabel()) {
|
|
362
|
+
warnOnce(
|
|
363
|
+
'Combobox.Trigger has no accessible name. The combobox role does not take its name from its content. Add `aria-label`, `aria-labelledby`, or a `<label htmlFor>` that points at the trigger.',
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
}, [getTriggerLabel]);
|
|
367
|
+
|
|
368
|
+
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
369
|
+
onClick?.(event);
|
|
370
|
+
// Radix skips its open toggle when the event is default-prevented.
|
|
371
|
+
if (isBlocked) event.preventDefault();
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {
|
|
375
|
+
onKeyDown?.(event);
|
|
376
|
+
if (event.defaultPrevented || isBlocked || isDisabled) return;
|
|
377
|
+
if (event.key === 'ArrowDown') {
|
|
378
|
+
event.preventDefault();
|
|
379
|
+
ctx.setOpen(true);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
260
382
|
|
|
261
383
|
const defaultContent = (
|
|
262
384
|
<>
|
|
263
385
|
<span className="rt-SelectTriggerInner">
|
|
264
|
-
<span className="rt-ComboboxValue">
|
|
265
|
-
{ctx.displayValue ?? ctx.value ?? placeholder ?? ctx.placeholder}
|
|
266
|
-
</span>
|
|
386
|
+
<span className="rt-ComboboxValue">{ctx.displayValue ?? ctx.value ?? placeholder ?? ctx.placeholder}</span>
|
|
267
387
|
</span>
|
|
268
388
|
{loading ? (
|
|
269
389
|
<div className="rt-SelectIcon rt-SelectLoadingIcon" aria-hidden="true">
|
|
270
390
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
271
|
-
<circle
|
|
391
|
+
<circle
|
|
392
|
+
cx="8"
|
|
393
|
+
cy="8"
|
|
394
|
+
r="7"
|
|
395
|
+
stroke="currentColor"
|
|
396
|
+
strokeWidth="2"
|
|
397
|
+
strokeLinecap="round"
|
|
398
|
+
strokeDasharray="32"
|
|
399
|
+
strokeDashoffset="32"
|
|
400
|
+
className="rt-SelectLoadingIconCircle"
|
|
401
|
+
/>
|
|
272
402
|
</svg>
|
|
273
403
|
</div>
|
|
274
404
|
) : (
|
|
@@ -277,29 +407,32 @@ const ComboboxTrigger = React.forwardRef<ComboboxTriggerElement, ComboboxTrigger
|
|
|
277
407
|
</>
|
|
278
408
|
);
|
|
279
409
|
|
|
280
|
-
|
|
281
|
-
|
|
410
|
+
// Radix Popover.Trigger supplies aria-expanded, aria-controls (the popup id) and
|
|
411
|
+
// aria-haspopup="dialog", which matches the Popover dialog this opens.
|
|
282
412
|
return (
|
|
283
413
|
<Popover.Trigger disabled={isDisabled}>
|
|
284
414
|
<button
|
|
285
415
|
data-accent-color={resolvedColor}
|
|
286
416
|
data-radius={radius}
|
|
287
|
-
data-panel-background={
|
|
288
|
-
data-material={
|
|
417
|
+
data-panel-background={resolvedMaterial}
|
|
418
|
+
data-material={resolvedMaterial}
|
|
289
419
|
data-error={error}
|
|
290
420
|
data-loading={loading}
|
|
291
421
|
data-disabled={isDisabled || undefined}
|
|
292
422
|
data-read-only={readOnly || undefined}
|
|
293
|
-
{
|
|
423
|
+
data-placeholder={isPlaceholder ? '' : undefined}
|
|
424
|
+
{...triggerProps}
|
|
425
|
+
// eslint-disable-next-line jsx-a11y/role-has-required-aria-props -- Popover.Trigger (Slot) adds aria-expanded and aria-controls
|
|
294
426
|
role="combobox"
|
|
295
|
-
aria-autocomplete="list"
|
|
296
|
-
aria-controls={ctx.open ? ctx.listboxId : undefined}
|
|
297
|
-
aria-expanded={ctx.open}
|
|
298
|
-
aria-haspopup="listbox"
|
|
299
427
|
aria-disabled={isDisabled || undefined}
|
|
428
|
+
aria-readonly={readOnly || undefined}
|
|
429
|
+
aria-invalid={error || undefined}
|
|
430
|
+
aria-busy={loading || undefined}
|
|
300
431
|
type={buttonType ?? 'button'}
|
|
301
432
|
disabled={isDisabled}
|
|
302
|
-
|
|
433
|
+
onClick={handleClick}
|
|
434
|
+
onKeyDown={handleKeyDown}
|
|
435
|
+
ref={composedRef}
|
|
303
436
|
className={classNames('rt-reset', 'rt-SelectTrigger', 'rt-ComboboxTrigger', className)}
|
|
304
437
|
>
|
|
305
438
|
{children ? requireReactElement(children) : defaultContent}
|
|
@@ -318,87 +451,151 @@ interface ComboboxValueProps extends React.ComponentPropsWithoutRef<'span'> {
|
|
|
318
451
|
placeholder?: string;
|
|
319
452
|
}
|
|
320
453
|
|
|
321
|
-
const ComboboxValue = React.forwardRef<ComboboxValueElement, ComboboxValueProps>(
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
},
|
|
331
|
-
);
|
|
454
|
+
const ComboboxValue = React.forwardRef<ComboboxValueElement, ComboboxValueProps>(({ placeholder, children, className, ...valueProps }, forwardedRef) => {
|
|
455
|
+
const ctx = useComboboxContext('Value');
|
|
456
|
+
const display = ctx.displayValue ?? ctx.value ?? undefined;
|
|
457
|
+
return (
|
|
458
|
+
<span {...valueProps} ref={forwardedRef} className={classNames('rt-ComboboxValue', className)}>
|
|
459
|
+
{display ?? children ?? placeholder ?? ctx.placeholder}
|
|
460
|
+
</span>
|
|
461
|
+
);
|
|
462
|
+
});
|
|
332
463
|
ComboboxValue.displayName = 'Combobox.Value';
|
|
333
464
|
|
|
334
465
|
// ============================================================================
|
|
335
466
|
// Content
|
|
336
467
|
// ============================================================================
|
|
337
468
|
|
|
338
|
-
type ComboboxContentElement = React.ElementRef<typeof
|
|
469
|
+
type ComboboxContentElement = React.ElementRef<typeof PopoverPrimitive.Content>;
|
|
339
470
|
type ComboboxContentOwnProps = GetPropDefTypes<typeof comboboxContentPropDefs> & {
|
|
340
|
-
container?: React.ComponentPropsWithoutRef<typeof
|
|
471
|
+
container?: React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Portal>['container'];
|
|
341
472
|
};
|
|
342
|
-
interface ComboboxContentProps extends Omit<ComponentPropsWithout<typeof
|
|
473
|
+
interface ComboboxContentProps extends Omit<ComponentPropsWithout<typeof PopoverPrimitive.Content, RemovedProps>, 'size'>, ComboboxContentOwnProps {}
|
|
474
|
+
|
|
475
|
+
/** Announces the filtered result count to screen readers after typing settles. */
|
|
476
|
+
function ComboboxAnnouncer() {
|
|
477
|
+
const count = useCommandState((state) => state.filtered.count);
|
|
478
|
+
const search = useCommandState((state) => state.search);
|
|
479
|
+
const [message, setMessage] = React.useState('');
|
|
480
|
+
|
|
481
|
+
React.useEffect(() => {
|
|
482
|
+
const next = !search ? '' : count === 0 ? 'No results' : `${count} result${count === 1 ? '' : 's'}`;
|
|
483
|
+
const timeout = window.setTimeout(() => setMessage(next), search ? 400 : 0);
|
|
484
|
+
return () => window.clearTimeout(timeout);
|
|
485
|
+
}, [count, search]);
|
|
486
|
+
|
|
487
|
+
return (
|
|
488
|
+
<VisuallyHidden role="status" aria-live="polite" aria-atomic="true">
|
|
489
|
+
{message}
|
|
490
|
+
</VisuallyHidden>
|
|
491
|
+
);
|
|
492
|
+
}
|
|
343
493
|
|
|
344
494
|
const ComboboxContent = React.forwardRef<ComboboxContentElement, ComboboxContentProps>((props, forwardedRef) => {
|
|
345
495
|
const ctx = useComboboxContext('Content');
|
|
346
|
-
const cmdkConfigRef = React.useContext(CmdkConfigContext);
|
|
347
496
|
const themeContext = useThemeContext();
|
|
348
|
-
const effectiveMaterial = themeContext.panelBackground;
|
|
349
497
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const
|
|
498
|
+
useDeprecatedPanelBackgroundWarning(props.panelBackground);
|
|
499
|
+
|
|
500
|
+
const material = props.material ?? props.panelBackground ?? themeContext.material ?? themeContext.panelBackground;
|
|
501
|
+
const size = props.size ?? ctx.size ?? comboboxContentPropDefs.size.default;
|
|
502
|
+
const variant = props.variant ?? comboboxContentPropDefs.variant.default;
|
|
503
|
+
const highContrast = props.highContrast ?? ctx.highContrast ?? comboboxContentPropDefs.highContrast.default;
|
|
504
|
+
|
|
505
|
+
const {
|
|
506
|
+
className,
|
|
507
|
+
children,
|
|
508
|
+
color,
|
|
509
|
+
forceMount,
|
|
510
|
+
container,
|
|
511
|
+
material: _material,
|
|
512
|
+
panelBackground: _panelBackground,
|
|
513
|
+
onOpenAutoFocus,
|
|
514
|
+
'aria-label': _ariaLabel,
|
|
515
|
+
'aria-labelledby': ariaLabelledByProp,
|
|
516
|
+
...contentProps
|
|
517
|
+
} = extractProps({ ...props, size, variant, highContrast }, comboboxContentPropDefs);
|
|
353
518
|
|
|
354
|
-
const { className, children, color, forceMount, container, ...contentProps } = extractProps(
|
|
355
|
-
{ ...props, size: sizeProp, variant: variantProp, highContrast: highContrastProp },
|
|
356
|
-
comboboxContentPropDefs,
|
|
357
|
-
);
|
|
358
519
|
const resolvedColor = color || ctx.color || themeContext.accentColor;
|
|
359
520
|
|
|
521
|
+
|
|
522
|
+
// The trigger's name labels the popup, the search field and the listbox.
|
|
523
|
+
// Read once per mount (the content remounts on every open); fall back to a
|
|
524
|
+
// layout effect when the trigger was not attached yet (defaultOpen, forceMount).
|
|
525
|
+
const { getTriggerLabel } = ctx;
|
|
526
|
+
const [triggerLabel, setTriggerLabel] = React.useState(getTriggerLabel);
|
|
527
|
+
useLayoutEffect(() => {
|
|
528
|
+
if (triggerLabel !== undefined) return;
|
|
529
|
+
const label = getTriggerLabel();
|
|
530
|
+
if (label !== undefined) setTriggerLabel(label);
|
|
531
|
+
}, [getTriggerLabel, triggerLabel]);
|
|
532
|
+
|
|
533
|
+
const label = props['aria-label'] ?? triggerLabel;
|
|
534
|
+
|
|
360
535
|
const contentContextValue = React.useMemo<ComboboxContentContextValue>(
|
|
361
536
|
() => ({
|
|
362
|
-
variant
|
|
363
|
-
size
|
|
537
|
+
variant,
|
|
538
|
+
// Responsive-aware size class for the search field (never String() a responsive object).
|
|
539
|
+
sizeClassName: extractProps({ size }, contentSizePropDefs).className || undefined,
|
|
364
540
|
color: resolvedColor,
|
|
365
|
-
material
|
|
366
|
-
|
|
367
|
-
loop: cmdkConfigRef?.current.loop,
|
|
368
|
-
shouldFilter: cmdkConfigRef?.current.shouldFilter,
|
|
369
|
-
filter: cmdkConfigRef?.current.filter,
|
|
541
|
+
material,
|
|
542
|
+
label,
|
|
370
543
|
}),
|
|
371
|
-
[
|
|
544
|
+
[variant, size, resolvedColor, material, label],
|
|
372
545
|
);
|
|
373
546
|
|
|
547
|
+
const commandRef = React.useRef<HTMLDivElement>(null);
|
|
548
|
+
|
|
549
|
+
// Without a search field, focus would land on the popup itself, outside cmdk's
|
|
550
|
+
// keydown handler. Focus the listbox instead so arrow keys and Enter work.
|
|
551
|
+
const handleOpenAutoFocus = (event: Event) => {
|
|
552
|
+
onOpenAutoFocus?.(event);
|
|
553
|
+
if (event.defaultPrevented) return;
|
|
554
|
+
const command = commandRef.current;
|
|
555
|
+
if (!command || command.querySelector('[cmdk-input]')) return;
|
|
556
|
+
event.preventDefault();
|
|
557
|
+
const list = command.querySelector<HTMLElement>('[cmdk-list]');
|
|
558
|
+
(list ?? command).focus({ preventScroll: true });
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
// Start the highlight on the selected option (cmdk trims item values).
|
|
562
|
+
const initialHighlight = ctx.value?.trim() || undefined;
|
|
563
|
+
|
|
374
564
|
return (
|
|
375
|
-
<
|
|
376
|
-
size={sizeProp}
|
|
377
|
-
data-accent-color={resolvedColor}
|
|
378
|
-
data-material={effectiveMaterial}
|
|
379
|
-
data-panel-background={effectiveMaterial}
|
|
380
|
-
align="start"
|
|
381
|
-
sideOffset={4}
|
|
382
|
-
collisionPadding={10}
|
|
383
|
-
{...contentProps}
|
|
384
|
-
forceMount={forceMount === true ? true : undefined}
|
|
385
|
-
container={container}
|
|
386
|
-
ref={forwardedRef}
|
|
387
|
-
className={classNames('rt-PopperContent', 'rt-BaseMenuContent', 'rt-ComboboxContent', className)}
|
|
388
|
-
>
|
|
565
|
+
<PopoverPrimitive.Portal container={container} forceMount={forceMount ? true : undefined}>
|
|
389
566
|
<Theme asChild>
|
|
390
|
-
<
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
567
|
+
<PopoverPrimitive.Content
|
|
568
|
+
data-accent-color={resolvedColor}
|
|
569
|
+
data-material={material}
|
|
570
|
+
data-panel-background={material}
|
|
571
|
+
align="start"
|
|
572
|
+
sideOffset={4}
|
|
573
|
+
collisionPadding={10}
|
|
574
|
+
aria-label={ariaLabelledByProp ? undefined : label}
|
|
575
|
+
aria-labelledby={ariaLabelledByProp}
|
|
576
|
+
{...contentProps}
|
|
577
|
+
forceMount={forceMount ? true : undefined}
|
|
578
|
+
onOpenAutoFocus={handleOpenAutoFocus}
|
|
579
|
+
ref={forwardedRef}
|
|
580
|
+
className={classNames('rt-PopperContent', 'rt-BaseMenuContent', 'rt-ComboboxContent', className)}
|
|
581
|
+
>
|
|
582
|
+
<ComboboxContentContext.Provider value={contentContextValue}>
|
|
583
|
+
<CommandPrimitive
|
|
584
|
+
ref={commandRef}
|
|
585
|
+
loop={ctx.loop}
|
|
586
|
+
shouldFilter={ctx.shouldFilter}
|
|
587
|
+
filter={ctx.filter}
|
|
588
|
+
label={label}
|
|
589
|
+
defaultValue={initialHighlight}
|
|
590
|
+
className="rt-ComboboxCommand"
|
|
591
|
+
>
|
|
592
|
+
{children}
|
|
593
|
+
<ComboboxAnnouncer />
|
|
594
|
+
</CommandPrimitive>
|
|
595
|
+
</ComboboxContentContext.Provider>
|
|
596
|
+
</PopoverPrimitive.Content>
|
|
400
597
|
</Theme>
|
|
401
|
-
</
|
|
598
|
+
</PopoverPrimitive.Portal>
|
|
402
599
|
);
|
|
403
600
|
});
|
|
404
601
|
ComboboxContent.displayName = 'Combobox.Content';
|
|
@@ -419,22 +616,19 @@ interface ComboboxInputProps extends Omit<React.ComponentPropsWithoutRef<typeof
|
|
|
419
616
|
const ComboboxInput = React.forwardRef<ComboboxInputElement, ComboboxInputProps>(
|
|
420
617
|
({ className, startAdornment, endAdornment, placeholder, variant: inputVariant, value, onValueChange, ...inputProps }, forwardedRef) => {
|
|
421
618
|
const ctx = useComboboxContext('Input');
|
|
619
|
+
const search = React.useContext(ComboboxSearchContext);
|
|
422
620
|
const contentContext = useComboboxContentContext();
|
|
423
|
-
const cmdkConfigRef = React.useContext(CmdkConfigContext);
|
|
424
621
|
|
|
425
622
|
const contentVariant = contentContext?.variant ?? 'solid';
|
|
426
623
|
const textFieldVariant = inputVariant ?? (contentVariant === 'solid' ? 'surface' : 'soft');
|
|
427
624
|
|
|
428
|
-
//
|
|
429
|
-
const searchValue = value ??
|
|
430
|
-
const handleSearchChange = onValueChange ??
|
|
431
|
-
|
|
432
|
-
// Use size from contentContext (already resolved to string) or fallback
|
|
433
|
-
const sizeClass = contentContext?.size ? `rt-r-size-${contentContext.size}` : undefined;
|
|
625
|
+
// The search text lives in Root; only this component subscribes to it.
|
|
626
|
+
const searchValue = value ?? search?.value ?? '';
|
|
627
|
+
const handleSearchChange = onValueChange ?? search?.setValue;
|
|
434
628
|
|
|
435
629
|
const inputField = (
|
|
436
630
|
<div
|
|
437
|
-
className={classNames('rt-TextFieldRoot', 'rt-ComboboxInputRoot',
|
|
631
|
+
className={classNames('rt-TextFieldRoot', 'rt-ComboboxInputRoot', contentContext?.sizeClassName, `rt-variant-${textFieldVariant}`)}
|
|
438
632
|
data-accent-color={contentContext?.color}
|
|
439
633
|
data-material={contentContext?.material}
|
|
440
634
|
data-panel-background={contentContext?.material}
|
|
@@ -462,25 +656,20 @@ const ComboboxInput = React.forwardRef<ComboboxInputElement, ComboboxInputProps>
|
|
|
462
656
|
ComboboxInput.displayName = 'Combobox.Input';
|
|
463
657
|
|
|
464
658
|
// ============================================================================
|
|
465
|
-
// List
|
|
659
|
+
// List
|
|
466
660
|
// ============================================================================
|
|
467
661
|
|
|
468
662
|
type ComboboxListElement = React.ElementRef<typeof CommandPrimitive.List>;
|
|
469
663
|
interface ComboboxListProps extends React.ComponentPropsWithoutRef<typeof CommandPrimitive.List> {}
|
|
470
664
|
|
|
471
|
-
|
|
472
|
-
|
|
665
|
+
// cmdk's List owns its id (referenced by the input's aria-controls), role and
|
|
666
|
+
// aria-label (set from `label`), so none of them are overridden here.
|
|
667
|
+
const ComboboxList = React.forwardRef<ComboboxListElement, ComboboxListProps>(({ className, children, label, ...listProps }, forwardedRef) => {
|
|
668
|
+
const contentContext = useComboboxContentContext();
|
|
473
669
|
return (
|
|
474
670
|
<div className="rt-ComboboxScrollArea">
|
|
475
671
|
<div className={classNames('rt-BaseMenuViewport', 'rt-ComboboxViewport')}>
|
|
476
|
-
<CommandPrimitive.List
|
|
477
|
-
{...listProps}
|
|
478
|
-
id={ctx.listboxId}
|
|
479
|
-
ref={forwardedRef}
|
|
480
|
-
role="listbox"
|
|
481
|
-
aria-label="Options"
|
|
482
|
-
className={classNames('rt-ComboboxList', className)}
|
|
483
|
-
>
|
|
672
|
+
<CommandPrimitive.List {...listProps} label={label ?? contentContext?.label} ref={forwardedRef} className={classNames('rt-ComboboxList', className)}>
|
|
484
673
|
{children}
|
|
485
674
|
</CommandPrimitive.List>
|
|
486
675
|
</div>
|
|
@@ -520,9 +709,25 @@ ComboboxGroup.displayName = 'Combobox.Group';
|
|
|
520
709
|
type ComboboxLabelElement = React.ElementRef<'div'>;
|
|
521
710
|
interface ComboboxLabelProps extends React.ComponentPropsWithoutRef<'div'> {}
|
|
522
711
|
|
|
523
|
-
const ComboboxLabel = React.forwardRef<ComboboxLabelElement, ComboboxLabelProps>(({ className, ...labelProps }, forwardedRef) =>
|
|
524
|
-
|
|
525
|
-
|
|
712
|
+
const ComboboxLabel = React.forwardRef<ComboboxLabelElement, ComboboxLabelProps>(({ className, id: idProp, ...labelProps }, forwardedRef) => {
|
|
713
|
+
const generatedId = React.useId();
|
|
714
|
+
const id = idProp ?? generatedId;
|
|
715
|
+
const localRef = React.useRef<HTMLDivElement>(null);
|
|
716
|
+
const composedRef = useComposedRefs(forwardedRef, localRef);
|
|
717
|
+
|
|
718
|
+
// cmdk renders the group's role="group" element itself and gives no way to
|
|
719
|
+
// label it from a child, so name it after this label when inside a Group.
|
|
720
|
+
useLayoutEffect(() => {
|
|
721
|
+
const group = localRef.current?.closest('[cmdk-group-items]');
|
|
722
|
+
if (!group || group.hasAttribute('aria-labelledby')) return;
|
|
723
|
+
group.setAttribute('aria-labelledby', id);
|
|
724
|
+
return () => {
|
|
725
|
+
if (group.getAttribute('aria-labelledby') === id) group.removeAttribute('aria-labelledby');
|
|
726
|
+
};
|
|
727
|
+
}, [id]);
|
|
728
|
+
|
|
729
|
+
return <div {...labelProps} id={id} ref={composedRef} className={classNames('rt-BaseMenuLabel', 'rt-ComboboxLabel', className)} />;
|
|
730
|
+
});
|
|
526
731
|
ComboboxLabel.displayName = 'Combobox.Label';
|
|
527
732
|
|
|
528
733
|
// ============================================================================
|
|
@@ -538,57 +743,80 @@ const ComboboxSeparator = React.forwardRef<ComboboxSeparatorElement, ComboboxSep
|
|
|
538
743
|
ComboboxSeparator.displayName = 'Combobox.Separator';
|
|
539
744
|
|
|
540
745
|
// ============================================================================
|
|
541
|
-
// Item
|
|
746
|
+
// Item
|
|
542
747
|
// ============================================================================
|
|
543
748
|
|
|
749
|
+
/** Plain text of a React node tree, used as the item's search text. */
|
|
750
|
+
function getNodeText(node: React.ReactNode): string {
|
|
751
|
+
if (node == null || typeof node === 'boolean') return '';
|
|
752
|
+
if (typeof node === 'string' || typeof node === 'number') return String(node);
|
|
753
|
+
if (Array.isArray(node)) return node.map(getNodeText).join('');
|
|
754
|
+
if (React.isValidElement<{ children?: React.ReactNode }>(node)) return getNodeText(node.props.children);
|
|
755
|
+
return '';
|
|
756
|
+
}
|
|
757
|
+
|
|
544
758
|
type ComboboxItemElement = React.ElementRef<typeof CommandPrimitive.Item>;
|
|
545
759
|
interface ComboboxItemProps extends Omit<React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>, 'keywords' | 'onSelect'> {
|
|
546
|
-
/**
|
|
760
|
+
/**
|
|
761
|
+
* Text matched by search. Defaults to the text of `children`. Set it when the
|
|
762
|
+
* children are components whose text is not in the JSX (it cannot be read).
|
|
763
|
+
*/
|
|
547
764
|
label?: string;
|
|
548
765
|
/** Additional keywords for search filtering. */
|
|
549
766
|
keywords?: string[];
|
|
550
|
-
/** Called when item is selected. */
|
|
767
|
+
/** Called when the item is selected. */
|
|
551
768
|
onSelect?: (value: string) => void;
|
|
552
769
|
}
|
|
553
770
|
|
|
554
771
|
const ComboboxItem = React.forwardRef<ComboboxItemElement, ComboboxItemProps>(
|
|
555
772
|
({ className, children, label, value, disabled, onSelect, keywords, ...itemProps }, forwardedRef) => {
|
|
556
|
-
const
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
const
|
|
773
|
+
const itemContext = React.useContext(ComboboxItemContext);
|
|
774
|
+
if (!itemContext) {
|
|
775
|
+
throw new Error('Combobox.Item must be used within Combobox.Root');
|
|
776
|
+
}
|
|
777
|
+
const { store, onSelect: onSelectFromRoot, disabled: rootDisabled } = itemContext;
|
|
778
|
+
|
|
779
|
+
// Without `value`, cmdk uses the trimmed text of string children.
|
|
780
|
+
const itemValue = value ?? (typeof children === 'string' ? children.trim() : undefined);
|
|
781
|
+
const getIsSelected = () => itemValue !== undefined && store.get() === itemValue;
|
|
782
|
+
const isSelected = React.useSyncExternalStore(store.subscribe, getIsSelected, getIsSelected);
|
|
783
|
+
|
|
784
|
+
const onSelectProp = useCallbackRef(onSelect);
|
|
785
|
+
// cmdk passes its resolved value (the `value` prop, or the text when `value` is omitted).
|
|
786
|
+
const handleSelect = React.useCallback(
|
|
787
|
+
(resolvedValue: string) => {
|
|
788
|
+
const nextValue = value ?? resolvedValue;
|
|
789
|
+
onSelectFromRoot(nextValue);
|
|
790
|
+
onSelectProp(nextValue);
|
|
791
|
+
},
|
|
792
|
+
[value, onSelectFromRoot, onSelectProp],
|
|
793
|
+
);
|
|
565
794
|
|
|
566
|
-
//
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
}, [onSelectFromContext, value, onSelect]);
|
|
795
|
+
// cmdk matches only `value` and `keywords`, so add the visible text as a keyword.
|
|
796
|
+
const text = (label ?? getNodeText(children)).replace(/\s+/g, ' ').trim();
|
|
797
|
+
const searchKeywords = text ? (keywords ? [text, ...keywords] : [text]) : keywords;
|
|
798
|
+
// cmdk stores keywords only when `value` changes. Remount the cmdk item when
|
|
799
|
+
// they change so a new label or keyword list is picked up.
|
|
800
|
+
const keywordsKey = searchKeywords ? searchKeywords.join('') : '';
|
|
573
801
|
|
|
574
|
-
|
|
575
|
-
const searchKeywords = keywords ?? (label ? [label] : undefined);
|
|
802
|
+
const isDisabled = disabled ?? rootDisabled ?? false;
|
|
576
803
|
|
|
577
804
|
return (
|
|
578
805
|
<CommandPrimitive.Item
|
|
806
|
+
key={keywordsKey}
|
|
579
807
|
{...itemProps}
|
|
580
808
|
value={value}
|
|
581
809
|
keywords={searchKeywords}
|
|
582
|
-
|
|
583
|
-
aria-
|
|
810
|
+
// cmdk owns aria-selected (the highlighted option); the chosen option is aria-checked.
|
|
811
|
+
aria-checked={isSelected}
|
|
584
812
|
disabled={isDisabled || undefined}
|
|
585
813
|
ref={forwardedRef}
|
|
586
814
|
onSelect={handleSelect}
|
|
587
815
|
className={classNames('rt-reset', 'rt-BaseMenuItem', 'rt-ComboboxItem', className)}
|
|
588
816
|
>
|
|
589
817
|
{isSelected ? (
|
|
590
|
-
<span className={classNames('rt-BaseMenuItemIndicator', 'rt-ComboboxItemIndicator'
|
|
591
|
-
<ThickCheckIcon className={classNames('rt-BaseMenuItemIndicatorIcon', 'rt-ComboboxItemIndicatorIcon'
|
|
818
|
+
<span className={classNames('rt-BaseMenuItemIndicator', 'rt-ComboboxItemIndicator')}>
|
|
819
|
+
<ThickCheckIcon className={classNames('rt-BaseMenuItemIndicatorIcon', 'rt-ComboboxItemIndicatorIcon')} />
|
|
592
820
|
</span>
|
|
593
821
|
) : null}
|
|
594
822
|
<Slottable>{children}</Slottable>
|