@cdx-ui/primitives 0.0.1-beta.4 → 0.0.1-beta.40
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/README.md +50 -24
- package/lib/commonjs/CLAUDE.md +32 -0
- package/lib/commonjs/avatar/createAvatarText.js +9 -1
- package/lib/commonjs/avatar/createAvatarText.js.map +1 -1
- package/lib/commonjs/button/createButtonText.js +1 -0
- package/lib/commonjs/button/createButtonText.js.map +1 -1
- package/lib/commonjs/checkbox/createCheckboxRoot.web.js +8 -3
- package/lib/commonjs/checkbox/createCheckboxRoot.web.js.map +1 -1
- package/lib/commonjs/chip/createChipRoot.js +132 -0
- package/lib/commonjs/chip/createChipRoot.js.map +1 -0
- package/lib/commonjs/chip/index.js +16 -0
- package/lib/commonjs/chip/index.js.map +1 -0
- package/lib/commonjs/chip/types.js +6 -0
- package/lib/commonjs/chip/types.js.map +1 -0
- package/lib/commonjs/field/createFieldLabel.js.map +1 -1
- package/lib/commonjs/index.js +48 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/input/createInputField.js +5 -0
- package/lib/commonjs/input/createInputField.js.map +1 -1
- package/lib/commonjs/list-item/context.js +11 -0
- package/lib/commonjs/list-item/context.js.map +1 -0
- package/lib/commonjs/list-item/createListItemContent.js +30 -0
- package/lib/commonjs/list-item/createListItemContent.js.map +1 -0
- package/lib/commonjs/list-item/createListItemDescription.js +25 -0
- package/lib/commonjs/list-item/createListItemDescription.js.map +1 -0
- package/lib/commonjs/list-item/createListItemLeadingSlot.js +34 -0
- package/lib/commonjs/list-item/createListItemLeadingSlot.js.map +1 -0
- package/lib/commonjs/list-item/createListItemMeta.js +25 -0
- package/lib/commonjs/list-item/createListItemMeta.js.map +1 -0
- package/lib/commonjs/list-item/createListItemRoot.js +157 -0
- package/lib/commonjs/list-item/createListItemRoot.js.map +1 -0
- package/lib/commonjs/list-item/createListItemSectionHeader.js +54 -0
- package/lib/commonjs/list-item/createListItemSectionHeader.js.map +1 -0
- package/lib/commonjs/list-item/createListItemTitle.js +25 -0
- package/lib/commonjs/list-item/createListItemTitle.js.map +1 -0
- package/lib/commonjs/list-item/createListItemTrailingSlot.js +28 -0
- package/lib/commonjs/list-item/createListItemTrailingSlot.js.map +1 -0
- package/lib/commonjs/list-item/index.js +55 -0
- package/lib/commonjs/list-item/index.js.map +1 -0
- package/lib/commonjs/list-item/types.js +6 -0
- package/lib/commonjs/list-item/types.js.map +1 -0
- package/lib/commonjs/radio/context.js +14 -0
- package/lib/commonjs/radio/context.js.map +1 -0
- package/lib/commonjs/radio/createRadioGroup.js +66 -0
- package/lib/commonjs/radio/createRadioGroup.js.map +1 -0
- package/lib/commonjs/radio/createRadioIndicator.js +43 -0
- package/lib/commonjs/radio/createRadioIndicator.js.map +1 -0
- package/lib/commonjs/radio/createRadioLabel.js +38 -0
- package/lib/commonjs/radio/createRadioLabel.js.map +1 -0
- package/lib/commonjs/radio/createRadioRoot.js +95 -0
- package/lib/commonjs/radio/createRadioRoot.js.map +1 -0
- package/lib/commonjs/radio/createRadioRoot.web.js +87 -0
- package/lib/commonjs/radio/createRadioRoot.web.js.map +1 -0
- package/lib/commonjs/radio/index.js +26 -0
- package/lib/commonjs/radio/index.js.map +1 -0
- package/lib/commonjs/radio/types.js +6 -0
- package/lib/commonjs/radio/types.js.map +1 -0
- package/lib/commonjs/radio/useRadioRoot.js +64 -0
- package/lib/commonjs/radio/useRadioRoot.js.map +1 -0
- package/lib/commonjs/select/createSelectTrigger.js +17 -4
- package/lib/commonjs/select/createSelectTrigger.js.map +1 -1
- package/lib/commonjs/tile/context.js +30 -0
- package/lib/commonjs/tile/context.js.map +1 -0
- package/lib/commonjs/tile/createTileContent.js +30 -0
- package/lib/commonjs/tile/createTileContent.js.map +1 -0
- package/lib/commonjs/tile/createTileDescription.js +28 -0
- package/lib/commonjs/tile/createTileDescription.js.map +1 -0
- package/lib/commonjs/tile/createTileGroup.js +112 -0
- package/lib/commonjs/tile/createTileGroup.js.map +1 -0
- package/lib/commonjs/tile/createTileIndicator.js +46 -0
- package/lib/commonjs/tile/createTileIndicator.js.map +1 -0
- package/lib/commonjs/tile/createTileLeadingSlot.js +34 -0
- package/lib/commonjs/tile/createTileLeadingSlot.js.map +1 -0
- package/lib/commonjs/tile/createTileRoot.js +133 -0
- package/lib/commonjs/tile/createTileRoot.js.map +1 -0
- package/lib/commonjs/tile/createTileTitle.js +28 -0
- package/lib/commonjs/tile/createTileTitle.js.map +1 -0
- package/lib/commonjs/tile/createTileTrailingSlot.js +35 -0
- package/lib/commonjs/tile/createTileTrailingSlot.js.map +1 -0
- package/lib/commonjs/tile/index.js +55 -0
- package/lib/commonjs/tile/index.js.map +1 -0
- package/lib/commonjs/tile/types.js +6 -0
- package/lib/commonjs/tile/types.js.map +1 -0
- package/lib/module/CLAUDE.md +32 -0
- package/lib/module/avatar/createAvatarText.js +9 -1
- package/lib/module/avatar/createAvatarText.js.map +1 -1
- package/lib/module/button/createButtonText.js +1 -0
- package/lib/module/button/createButtonText.js.map +1 -1
- package/lib/module/checkbox/createCheckboxRoot.web.js +8 -2
- package/lib/module/checkbox/createCheckboxRoot.web.js.map +1 -1
- package/lib/module/chip/createChipRoot.js +126 -0
- package/lib/module/chip/createChipRoot.js.map +1 -0
- package/lib/module/chip/index.js +12 -0
- package/lib/module/chip/index.js.map +1 -0
- package/lib/module/chip/types.js +4 -0
- package/lib/module/chip/types.js.map +1 -0
- package/lib/module/field/createFieldLabel.js.map +1 -1
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/input/createInputField.js +5 -0
- package/lib/module/input/createInputField.js.map +1 -1
- package/lib/module/list-item/context.js +5 -0
- package/lib/module/list-item/context.js.map +1 -0
- package/lib/module/list-item/createListItemContent.js +24 -0
- package/lib/module/list-item/createListItemContent.js.map +1 -0
- package/lib/module/list-item/createListItemDescription.js +19 -0
- package/lib/module/list-item/createListItemDescription.js.map +1 -0
- package/lib/module/list-item/createListItemLeadingSlot.js +28 -0
- package/lib/module/list-item/createListItemLeadingSlot.js.map +1 -0
- package/lib/module/list-item/createListItemMeta.js +19 -0
- package/lib/module/list-item/createListItemMeta.js.map +1 -0
- package/lib/module/list-item/createListItemRoot.js +151 -0
- package/lib/module/list-item/createListItemRoot.js.map +1 -0
- package/lib/module/list-item/createListItemSectionHeader.js +48 -0
- package/lib/module/list-item/createListItemSectionHeader.js.map +1 -0
- package/lib/module/list-item/createListItemTitle.js +19 -0
- package/lib/module/list-item/createListItemTitle.js.map +1 -0
- package/lib/module/list-item/createListItemTrailingSlot.js +22 -0
- package/lib/module/list-item/createListItemTrailingSlot.js.map +1 -0
- package/lib/module/list-item/index.js +39 -0
- package/lib/module/list-item/index.js.map +1 -0
- package/lib/module/list-item/types.js +4 -0
- package/lib/module/list-item/types.js.map +1 -0
- package/lib/module/radio/context.js +7 -0
- package/lib/module/radio/context.js.map +1 -0
- package/lib/module/radio/createRadioGroup.js +61 -0
- package/lib/module/radio/createRadioGroup.js.map +1 -0
- package/lib/module/radio/createRadioIndicator.js +38 -0
- package/lib/module/radio/createRadioIndicator.js.map +1 -0
- package/lib/module/radio/createRadioLabel.js +33 -0
- package/lib/module/radio/createRadioLabel.js.map +1 -0
- package/lib/module/radio/createRadioRoot.js +90 -0
- package/lib/module/radio/createRadioRoot.js.map +1 -0
- package/lib/module/radio/createRadioRoot.web.js +82 -0
- package/lib/module/radio/createRadioRoot.web.js.map +1 -0
- package/lib/module/radio/index.js +22 -0
- package/lib/module/radio/index.js.map +1 -0
- package/lib/module/radio/types.js +4 -0
- package/lib/module/radio/types.js.map +1 -0
- package/lib/module/radio/useRadioRoot.js +60 -0
- package/lib/module/radio/useRadioRoot.js.map +1 -0
- package/lib/module/select/createSelectTrigger.js +19 -6
- package/lib/module/select/createSelectTrigger.js.map +1 -1
- package/lib/module/tile/context.js +21 -0
- package/lib/module/tile/context.js.map +1 -0
- package/lib/module/tile/createTileContent.js +24 -0
- package/lib/module/tile/createTileContent.js.map +1 -0
- package/lib/module/tile/createTileDescription.js +22 -0
- package/lib/module/tile/createTileDescription.js.map +1 -0
- package/lib/module/tile/createTileGroup.js +106 -0
- package/lib/module/tile/createTileGroup.js.map +1 -0
- package/lib/module/tile/createTileIndicator.js +40 -0
- package/lib/module/tile/createTileIndicator.js.map +1 -0
- package/lib/module/tile/createTileLeadingSlot.js +28 -0
- package/lib/module/tile/createTileLeadingSlot.js.map +1 -0
- package/lib/module/tile/createTileRoot.js +127 -0
- package/lib/module/tile/createTileRoot.js.map +1 -0
- package/lib/module/tile/createTileTitle.js +22 -0
- package/lib/module/tile/createTileTitle.js.map +1 -0
- package/lib/module/tile/createTileTrailingSlot.js +29 -0
- package/lib/module/tile/createTileTrailingSlot.js.map +1 -0
- package/lib/module/tile/index.js +39 -0
- package/lib/module/tile/index.js.map +1 -0
- package/lib/module/tile/types.js +4 -0
- package/lib/module/tile/types.js.map +1 -0
- package/lib/typescript/avatar/createAvatarText.d.ts.map +1 -1
- package/lib/typescript/button/createButtonText.d.ts.map +1 -1
- package/lib/typescript/checkbox/createCheckboxRoot.web.d.ts +4 -0
- package/lib/typescript/checkbox/createCheckboxRoot.web.d.ts.map +1 -1
- package/lib/typescript/checkbox/useCheckboxRoot.d.ts +2 -0
- package/lib/typescript/checkbox/useCheckboxRoot.d.ts.map +1 -1
- package/lib/typescript/chip/createChipRoot.d.ts +4 -0
- package/lib/typescript/chip/createChipRoot.d.ts.map +1 -0
- package/lib/typescript/chip/index.d.ts +9 -0
- package/lib/typescript/chip/index.d.ts.map +1 -0
- package/lib/typescript/chip/types.d.ts +17 -0
- package/lib/typescript/chip/types.d.ts.map +1 -0
- package/lib/typescript/field/createFieldLabel.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +4 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/input/createInputField.d.ts.map +1 -1
- package/lib/typescript/list-item/context.d.ts +6 -0
- package/lib/typescript/list-item/context.d.ts.map +1 -0
- package/lib/typescript/list-item/createListItemContent.d.ts +3 -0
- package/lib/typescript/list-item/createListItemContent.d.ts.map +1 -0
- package/lib/typescript/list-item/createListItemDescription.d.ts +3 -0
- package/lib/typescript/list-item/createListItemDescription.d.ts.map +1 -0
- package/lib/typescript/list-item/createListItemLeadingSlot.d.ts +4 -0
- package/lib/typescript/list-item/createListItemLeadingSlot.d.ts.map +1 -0
- package/lib/typescript/list-item/createListItemMeta.d.ts +3 -0
- package/lib/typescript/list-item/createListItemMeta.d.ts.map +1 -0
- package/lib/typescript/list-item/createListItemRoot.d.ts +4 -0
- package/lib/typescript/list-item/createListItemRoot.d.ts.map +1 -0
- package/lib/typescript/list-item/createListItemSectionHeader.d.ts +4 -0
- package/lib/typescript/list-item/createListItemSectionHeader.d.ts.map +1 -0
- package/lib/typescript/list-item/createListItemTitle.d.ts +3 -0
- package/lib/typescript/list-item/createListItemTitle.d.ts.map +1 -0
- package/lib/typescript/list-item/createListItemTrailingSlot.d.ts +3 -0
- package/lib/typescript/list-item/createListItemTrailingSlot.d.ts.map +1 -0
- package/lib/typescript/list-item/index.d.ts +16 -0
- package/lib/typescript/list-item/index.d.ts.map +1 -0
- package/lib/typescript/list-item/types.d.ts +86 -0
- package/lib/typescript/list-item/types.d.ts.map +1 -0
- package/lib/typescript/radio/context.d.ts +21 -0
- package/lib/typescript/radio/context.d.ts.map +1 -0
- package/lib/typescript/radio/createRadioGroup.d.ts +3 -0
- package/lib/typescript/radio/createRadioGroup.d.ts.map +1 -0
- package/lib/typescript/radio/createRadioIndicator.d.ts +5 -0
- package/lib/typescript/radio/createRadioIndicator.d.ts.map +1 -0
- package/lib/typescript/radio/createRadioLabel.d.ts +5 -0
- package/lib/typescript/radio/createRadioLabel.d.ts.map +1 -0
- package/lib/typescript/radio/createRadioRoot.d.ts +3 -0
- package/lib/typescript/radio/createRadioRoot.d.ts.map +1 -0
- package/lib/typescript/radio/createRadioRoot.web.d.ts +3 -0
- package/lib/typescript/radio/createRadioRoot.web.d.ts.map +1 -0
- package/lib/typescript/radio/index.d.ts +10 -0
- package/lib/typescript/radio/index.d.ts.map +1 -0
- package/lib/typescript/radio/types.d.ts +54 -0
- package/lib/typescript/radio/types.d.ts.map +1 -0
- package/lib/typescript/radio/useRadioRoot.d.ts +151 -0
- package/lib/typescript/radio/useRadioRoot.d.ts.map +1 -0
- package/lib/typescript/select/createSelectTrigger.d.ts.map +1 -1
- package/lib/typescript/tile/context.d.ts +9 -0
- package/lib/typescript/tile/context.d.ts.map +1 -0
- package/lib/typescript/tile/createTileContent.d.ts +3 -0
- package/lib/typescript/tile/createTileContent.d.ts.map +1 -0
- package/lib/typescript/tile/createTileDescription.d.ts +3 -0
- package/lib/typescript/tile/createTileDescription.d.ts.map +1 -0
- package/lib/typescript/tile/createTileGroup.d.ts +4 -0
- package/lib/typescript/tile/createTileGroup.d.ts.map +1 -0
- package/lib/typescript/tile/createTileIndicator.d.ts +4 -0
- package/lib/typescript/tile/createTileIndicator.d.ts.map +1 -0
- package/lib/typescript/tile/createTileLeadingSlot.d.ts +4 -0
- package/lib/typescript/tile/createTileLeadingSlot.d.ts.map +1 -0
- package/lib/typescript/tile/createTileRoot.d.ts +4 -0
- package/lib/typescript/tile/createTileRoot.d.ts.map +1 -0
- package/lib/typescript/tile/createTileTitle.d.ts +3 -0
- package/lib/typescript/tile/createTileTitle.d.ts.map +1 -0
- package/lib/typescript/tile/createTileTrailingSlot.d.ts +9 -0
- package/lib/typescript/tile/createTileTrailingSlot.d.ts.map +1 -0
- package/lib/typescript/tile/index.d.ts +15 -0
- package/lib/typescript/tile/index.d.ts.map +1 -0
- package/lib/typescript/tile/types.d.ts +119 -0
- package/lib/typescript/tile/types.d.ts.map +1 -0
- package/package.json +5 -2
- package/src/CLAUDE.md +32 -0
- package/src/avatar/createAvatarText.tsx +10 -1
- package/src/button/createButtonText.tsx +1 -0
- package/src/checkbox/createCheckboxRoot.web.tsx +6 -2
- package/src/chip/createChipRoot.tsx +144 -0
- package/src/chip/index.ts +18 -0
- package/src/chip/types.ts +23 -0
- package/src/field/createFieldLabel.tsx +4 -1
- package/src/index.ts +4 -0
- package/src/input/createInputField.tsx +6 -0
- package/src/list-item/context.tsx +5 -0
- package/src/list-item/createListItemContent.tsx +23 -0
- package/src/list-item/createListItemDescription.tsx +19 -0
- package/src/list-item/createListItemLeadingSlot.tsx +30 -0
- package/src/list-item/createListItemMeta.tsx +17 -0
- package/src/list-item/createListItemRoot.tsx +178 -0
- package/src/list-item/createListItemSectionHeader.tsx +53 -0
- package/src/list-item/createListItemTitle.tsx +17 -0
- package/src/list-item/createListItemTrailingSlot.tsx +21 -0
- package/src/list-item/index.ts +88 -0
- package/src/list-item/types.ts +122 -0
- package/src/radio/context.tsx +21 -0
- package/src/radio/createRadioGroup.tsx +67 -0
- package/src/radio/createRadioIndicator.tsx +32 -0
- package/src/radio/createRadioLabel.tsx +28 -0
- package/src/radio/createRadioRoot.tsx +100 -0
- package/src/radio/createRadioRoot.web.tsx +81 -0
- package/src/radio/index.ts +37 -0
- package/src/radio/types.ts +67 -0
- package/src/radio/useRadioRoot.ts +69 -0
- package/src/select/createSelectTrigger.tsx +26 -3
- package/src/tile/context.tsx +23 -0
- package/src/tile/createTileContent.tsx +23 -0
- package/src/tile/createTileDescription.tsx +19 -0
- package/src/tile/createTileGroup.tsx +134 -0
- package/src/tile/createTileIndicator.tsx +38 -0
- package/src/tile/createTileLeadingSlot.tsx +30 -0
- package/src/tile/createTileRoot.tsx +124 -0
- package/src/tile/createTileTitle.tsx +19 -0
- package/src/tile/createTileTrailingSlot.tsx +25 -0
- package/src/tile/index.ts +88 -0
- package/src/tile/types.ts +153 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { dataAttributes } from '../utils/dataAttributes';
|
|
3
|
+
import { useTileContext } from './context';
|
|
4
|
+
import type { ITileIndicatorProps } from './types';
|
|
5
|
+
|
|
6
|
+
const shrinkZero = { flexShrink: 0 as const, pointerEvents: 'none' as const };
|
|
7
|
+
|
|
8
|
+
export const createTileIndicator = <T,>(Base: React.ComponentType<T>) =>
|
|
9
|
+
forwardRef(
|
|
10
|
+
(
|
|
11
|
+
{ children, style, indicatorType, ...props }: ITileIndicatorProps,
|
|
12
|
+
ref: React.Ref<unknown>,
|
|
13
|
+
) => {
|
|
14
|
+
const { isSelected, isDisabled, selectionType } = useTileContext();
|
|
15
|
+
|
|
16
|
+
// Effective visual type: explicit prop wins; otherwise infer from group/standalone context.
|
|
17
|
+
const effectiveType: 'radio' | 'checkbox' =
|
|
18
|
+
indicatorType ?? (selectionType === 'single' ? 'radio' : 'checkbox');
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Base
|
|
22
|
+
{...(props as T)}
|
|
23
|
+
accessibilityElementsHidden
|
|
24
|
+
aria-hidden
|
|
25
|
+
{...dataAttributes({
|
|
26
|
+
slot: 'tile-indicator',
|
|
27
|
+
checked: isSelected,
|
|
28
|
+
selectionType: effectiveType === 'radio' ? 'single' : 'multiple',
|
|
29
|
+
disabled: isDisabled,
|
|
30
|
+
})}
|
|
31
|
+
ref={ref as React.Ref<T>}
|
|
32
|
+
style={[shrinkZero, style]}
|
|
33
|
+
>
|
|
34
|
+
{children}
|
|
35
|
+
</Base>
|
|
36
|
+
);
|
|
37
|
+
},
|
|
38
|
+
);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { dataAttributes } from '../utils/dataAttributes';
|
|
3
|
+
import type { ITileLeadingSlotProps } from './types';
|
|
4
|
+
|
|
5
|
+
const shrinkZero = { flexShrink: 0 as const };
|
|
6
|
+
|
|
7
|
+
export const createTileLeadingSlot = <T,>(Base: React.ComponentType<T>) =>
|
|
8
|
+
forwardRef(
|
|
9
|
+
(
|
|
10
|
+
{ 'aria-hidden': ariaHidden, style, children, ...props }: ITileLeadingSlotProps,
|
|
11
|
+
ref: React.Ref<unknown>,
|
|
12
|
+
) => {
|
|
13
|
+
const accessibilityElementsHidden = ariaHidden !== false;
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<Base
|
|
17
|
+
{...(props as T)}
|
|
18
|
+
{...dataAttributes({
|
|
19
|
+
slot: 'tile-leading',
|
|
20
|
+
})}
|
|
21
|
+
accessibilityElementsHidden={accessibilityElementsHidden}
|
|
22
|
+
aria-hidden={ariaHidden}
|
|
23
|
+
ref={ref as React.Ref<T>}
|
|
24
|
+
style={[shrinkZero, style]}
|
|
25
|
+
>
|
|
26
|
+
{children}
|
|
27
|
+
</Base>
|
|
28
|
+
);
|
|
29
|
+
},
|
|
30
|
+
);
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import React, { forwardRef, useMemo } from 'react';
|
|
2
|
+
import { composeEventHandlers, mergeRefs, useControllableState } from '@cdx-ui/utils';
|
|
3
|
+
import { useFocus } from '@react-native-aria/focus';
|
|
4
|
+
import { useHover, usePress } from '@react-native-aria/interactions';
|
|
5
|
+
import { dataAttributes } from '../utils/dataAttributes';
|
|
6
|
+
import { TileProvider, useOptionalTileGroupContext } from './context';
|
|
7
|
+
import type { ITileProps, ITilePressablePassthrough } from './types';
|
|
8
|
+
|
|
9
|
+
const rowStyle = {
|
|
10
|
+
flexDirection: 'row' as const,
|
|
11
|
+
alignSelf: 'stretch' as const,
|
|
12
|
+
alignItems: 'center' as const,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const createTileRoot = <T,>(BasePressable: React.ComponentType<T>) =>
|
|
16
|
+
forwardRef((props: ITileProps, ref: React.Ref<unknown>) => {
|
|
17
|
+
const {
|
|
18
|
+
value,
|
|
19
|
+
disabled: disabledProp = false,
|
|
20
|
+
isSelected: controlledSelected,
|
|
21
|
+
defaultSelected,
|
|
22
|
+
onSelectedChange,
|
|
23
|
+
children,
|
|
24
|
+
onPress,
|
|
25
|
+
onFocus,
|
|
26
|
+
onBlur,
|
|
27
|
+
style,
|
|
28
|
+
/** Consumed by styled `withStyleContext` root. */
|
|
29
|
+
context: _styleContext,
|
|
30
|
+
...rest
|
|
31
|
+
} = props;
|
|
32
|
+
|
|
33
|
+
const group = useOptionalTileGroupContext();
|
|
34
|
+
|
|
35
|
+
// Standalone selection state — only meaningful when no group owns selection.
|
|
36
|
+
const [standaloneSelected = false, setStandaloneSelected] = useControllableState<boolean>({
|
|
37
|
+
prop: controlledSelected,
|
|
38
|
+
defaultProp: defaultSelected ?? false,
|
|
39
|
+
onChange: (next) => {
|
|
40
|
+
onSelectedChange?.(next);
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const isSelected = group ? group.isSelected(value) : standaloneSelected;
|
|
45
|
+
const disabledByGroup = group ? group.isTileDisabledByGroup(value) : false;
|
|
46
|
+
const isDisabled = disabledByGroup || disabledProp;
|
|
47
|
+
const cannotToggle = isDisabled;
|
|
48
|
+
|
|
49
|
+
const { focusProps, isFocused } = useFocus();
|
|
50
|
+
const { pressProps, isPressed } = usePress({ isDisabled: cannotToggle });
|
|
51
|
+
const { hoverProps, isHovered } = useHover();
|
|
52
|
+
|
|
53
|
+
// Standalone tiles use checkbox semantics (independent on/off toggle).
|
|
54
|
+
const selectionType = group ? group.type : 'multiple';
|
|
55
|
+
|
|
56
|
+
const accessibilityState = useMemo(
|
|
57
|
+
() => ({
|
|
58
|
+
disabled: isDisabled,
|
|
59
|
+
...(selectionType === 'single' ? { selected: isSelected } : { checked: isSelected }),
|
|
60
|
+
}),
|
|
61
|
+
[isDisabled, isSelected, selectionType],
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const tileContext = useMemo(
|
|
65
|
+
() => ({ value, isSelected, isDisabled, selectionType }),
|
|
66
|
+
[value, isSelected, isDisabled, selectionType],
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const passthrough = rest as ITilePressablePassthrough;
|
|
70
|
+
|
|
71
|
+
const composedOnPress = composeEventHandlers(onPress, () => {
|
|
72
|
+
if (cannotToggle) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (group) {
|
|
76
|
+
group.toggleValue(value);
|
|
77
|
+
} else {
|
|
78
|
+
setStandaloneSelected(!standaloneSelected);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const sharedHandlers = {
|
|
83
|
+
onPress: isDisabled ? undefined : composedOnPress,
|
|
84
|
+
onPressIn: composeEventHandlers(passthrough.onPressIn, pressProps.onPressIn),
|
|
85
|
+
onPressOut: composeEventHandlers(passthrough.onPressOut, pressProps.onPressOut),
|
|
86
|
+
onHoverIn: composeEventHandlers(passthrough.onHoverIn, hoverProps.onHoverIn),
|
|
87
|
+
onHoverOut: composeEventHandlers(passthrough.onHoverOut, hoverProps.onHoverOut),
|
|
88
|
+
onFocus: composeEventHandlers(onFocus, focusProps.onFocus),
|
|
89
|
+
onBlur: composeEventHandlers(onBlur, focusProps.onBlur),
|
|
90
|
+
} as const;
|
|
91
|
+
|
|
92
|
+
const role = selectionType === 'single' ? 'radio' : 'checkbox';
|
|
93
|
+
|
|
94
|
+
const sharedAttrs = {
|
|
95
|
+
accessibilityRole: role,
|
|
96
|
+
role,
|
|
97
|
+
accessibilityState,
|
|
98
|
+
'aria-checked': isSelected,
|
|
99
|
+
...(isDisabled ? { 'aria-disabled': true as const } : {}),
|
|
100
|
+
...dataAttributes({
|
|
101
|
+
slot: 'tile',
|
|
102
|
+
state: isSelected ? 'selected' : 'unselected',
|
|
103
|
+
disabled: isDisabled,
|
|
104
|
+
active: isPressed,
|
|
105
|
+
hover: isHovered,
|
|
106
|
+
focused: isFocused,
|
|
107
|
+
}),
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<TileProvider value={tileContext}>
|
|
112
|
+
<BasePressable
|
|
113
|
+
{...(rest as T)}
|
|
114
|
+
context={_styleContext}
|
|
115
|
+
ref={mergeRefs(ref) as React.Ref<T>}
|
|
116
|
+
{...sharedAttrs}
|
|
117
|
+
{...sharedHandlers}
|
|
118
|
+
style={[rowStyle, style]}
|
|
119
|
+
>
|
|
120
|
+
{children}
|
|
121
|
+
</BasePressable>
|
|
122
|
+
</TileProvider>
|
|
123
|
+
);
|
|
124
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { dataAttributes } from '../utils/dataAttributes';
|
|
3
|
+
import type { ITileTitleProps } from './types';
|
|
4
|
+
|
|
5
|
+
const noUnderline = { textDecorationLine: 'none' as const };
|
|
6
|
+
|
|
7
|
+
export const createTileTitle = <T,>(Base: React.ComponentType<T>) =>
|
|
8
|
+
forwardRef(({ children, style, ...props }: ITileTitleProps, ref: React.Ref<unknown>) => (
|
|
9
|
+
<Base
|
|
10
|
+
{...(props as T)}
|
|
11
|
+
{...dataAttributes({
|
|
12
|
+
slot: 'tile-title',
|
|
13
|
+
})}
|
|
14
|
+
ref={ref as React.Ref<T>}
|
|
15
|
+
style={[noUnderline, style]}
|
|
16
|
+
>
|
|
17
|
+
{children}
|
|
18
|
+
</Base>
|
|
19
|
+
));
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { dataAttributes } from '../utils/dataAttributes';
|
|
3
|
+
import type { ITileTrailingSlotProps } from './types';
|
|
4
|
+
|
|
5
|
+
const shrinkZero = { flexShrink: 0 as const };
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generic trailing content (chevron, amount, chip, status). Distinct from `Tile.Indicator`,
|
|
9
|
+
* which is purpose-built for the radio/checkbox selection affordance.
|
|
10
|
+
*
|
|
11
|
+
* Trailing content is meaningful by default (`aria-hidden` falsy), unlike the indicator.
|
|
12
|
+
*/
|
|
13
|
+
export const createTileTrailingSlot = <T,>(Base: React.ComponentType<T>) =>
|
|
14
|
+
forwardRef(({ children, style, ...props }: ITileTrailingSlotProps, ref: React.Ref<unknown>) => (
|
|
15
|
+
<Base
|
|
16
|
+
{...(props as T)}
|
|
17
|
+
{...dataAttributes({
|
|
18
|
+
slot: 'tile-trailing',
|
|
19
|
+
})}
|
|
20
|
+
ref={ref as React.Ref<T>}
|
|
21
|
+
style={[shrinkZero, style]}
|
|
22
|
+
>
|
|
23
|
+
{children}
|
|
24
|
+
</Base>
|
|
25
|
+
));
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import { createTileContent } from './createTileContent';
|
|
3
|
+
import { createTileDescription } from './createTileDescription';
|
|
4
|
+
import { createTileGroup } from './createTileGroup';
|
|
5
|
+
import { createTileIndicator } from './createTileIndicator';
|
|
6
|
+
import { createTileLeadingSlot } from './createTileLeadingSlot';
|
|
7
|
+
import { createTileRoot } from './createTileRoot';
|
|
8
|
+
import { createTileTitle } from './createTileTitle';
|
|
9
|
+
import { createTileTrailingSlot } from './createTileTrailingSlot';
|
|
10
|
+
import type { ITileComponentType } from './types';
|
|
11
|
+
|
|
12
|
+
export type {
|
|
13
|
+
ITileComponentType,
|
|
14
|
+
ITileContentProps,
|
|
15
|
+
ITileContextValue,
|
|
16
|
+
ITileDescriptionProps,
|
|
17
|
+
ITileGroupMultipleProps,
|
|
18
|
+
ITileGroupProps,
|
|
19
|
+
ITileGroupSingleProps,
|
|
20
|
+
ITileGroupContextValue,
|
|
21
|
+
ITileIndicatorProps,
|
|
22
|
+
ITileLeadingSlotProps,
|
|
23
|
+
ITilePressablePassthrough,
|
|
24
|
+
ITileProps,
|
|
25
|
+
ITileTitleProps,
|
|
26
|
+
ITileTrailingSlotProps,
|
|
27
|
+
TileGroupType,
|
|
28
|
+
TileGroupValue,
|
|
29
|
+
} from './types';
|
|
30
|
+
|
|
31
|
+
export { TileProvider, useTileContext } from './context';
|
|
32
|
+
|
|
33
|
+
export function createTile<
|
|
34
|
+
Pressable,
|
|
35
|
+
Leading,
|
|
36
|
+
Content,
|
|
37
|
+
Title,
|
|
38
|
+
Description,
|
|
39
|
+
Indicator,
|
|
40
|
+
TrailingSlot,
|
|
41
|
+
Group,
|
|
42
|
+
>(BaseComponents: {
|
|
43
|
+
Pressable: React.ComponentType<Pressable>;
|
|
44
|
+
LeadingSlot: React.ComponentType<Leading>;
|
|
45
|
+
Content: React.ComponentType<Content>;
|
|
46
|
+
Title: React.ComponentType<Title>;
|
|
47
|
+
Description: React.ComponentType<Description>;
|
|
48
|
+
Indicator: React.ComponentType<Indicator>;
|
|
49
|
+
TrailingSlot: React.ComponentType<TrailingSlot>;
|
|
50
|
+
Group: React.ComponentType<Group>;
|
|
51
|
+
}) {
|
|
52
|
+
const Tile = createTileRoot(BaseComponents.Pressable);
|
|
53
|
+
const Group = createTileGroup(BaseComponents.Group);
|
|
54
|
+
const LeadingSlot = createTileLeadingSlot(BaseComponents.LeadingSlot);
|
|
55
|
+
const Content = createTileContent(BaseComponents.Content);
|
|
56
|
+
const Title = createTileTitle(BaseComponents.Title);
|
|
57
|
+
const Description = createTileDescription(BaseComponents.Description);
|
|
58
|
+
const Indicator = createTileIndicator(BaseComponents.Indicator);
|
|
59
|
+
const TrailingSlot = createTileTrailingSlot(BaseComponents.TrailingSlot);
|
|
60
|
+
|
|
61
|
+
Tile.displayName = 'TilePrimitive';
|
|
62
|
+
Group.displayName = 'TilePrimitive.Group';
|
|
63
|
+
LeadingSlot.displayName = 'TilePrimitive.LeadingSlot';
|
|
64
|
+
Content.displayName = 'TilePrimitive.Content';
|
|
65
|
+
Title.displayName = 'TilePrimitive.Title';
|
|
66
|
+
Description.displayName = 'TilePrimitive.Description';
|
|
67
|
+
Indicator.displayName = 'TilePrimitive.Indicator';
|
|
68
|
+
TrailingSlot.displayName = 'TilePrimitive.TrailingSlot';
|
|
69
|
+
|
|
70
|
+
return Object.assign(Tile, {
|
|
71
|
+
Group,
|
|
72
|
+
LeadingSlot,
|
|
73
|
+
Content,
|
|
74
|
+
Title,
|
|
75
|
+
Description,
|
|
76
|
+
Indicator,
|
|
77
|
+
TrailingSlot,
|
|
78
|
+
}) as ITileComponentType<
|
|
79
|
+
Pressable,
|
|
80
|
+
Leading,
|
|
81
|
+
Content,
|
|
82
|
+
Title,
|
|
83
|
+
Description,
|
|
84
|
+
Indicator,
|
|
85
|
+
TrailingSlot,
|
|
86
|
+
Group
|
|
87
|
+
>;
|
|
88
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { ForwardRefExoticComponent, PropsWithoutRef, ReactNode, RefAttributes } from 'react';
|
|
2
|
+
import type { PressableProps, TextProps, ViewProps } from 'react-native';
|
|
3
|
+
import type { WithStyleContextProps } from '@cdx-ui/utils';
|
|
4
|
+
|
|
5
|
+
export type TileGroupType = 'single' | 'multiple';
|
|
6
|
+
|
|
7
|
+
export type TileGroupValue = string | string[] | undefined;
|
|
8
|
+
|
|
9
|
+
interface ITileGroupBaseProps extends ViewProps, WithStyleContextProps {
|
|
10
|
+
/** Disables the whole group. */
|
|
11
|
+
isDisabled?: boolean;
|
|
12
|
+
/** Accessible name for the group (radiogroup / group). */
|
|
13
|
+
'aria-label'?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ITileGroupSingleProps extends ITileGroupBaseProps {
|
|
17
|
+
/** Single-select (radio semantics). One value at a time. */
|
|
18
|
+
type: 'single';
|
|
19
|
+
/** Controlled selected value. */
|
|
20
|
+
value?: string;
|
|
21
|
+
/** Uncontrolled initial value. */
|
|
22
|
+
defaultValue?: string;
|
|
23
|
+
/** Called when selection changes. */
|
|
24
|
+
onValueChange?: (value: string) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ITileGroupMultipleProps extends ITileGroupBaseProps {
|
|
28
|
+
/** Multi-select (checkbox semantics). Zero to `max` values at a time. */
|
|
29
|
+
type: 'multiple';
|
|
30
|
+
/** Controlled selected values. */
|
|
31
|
+
value?: string[];
|
|
32
|
+
/** Uncontrolled initial values. */
|
|
33
|
+
defaultValue?: string[];
|
|
34
|
+
/** Called when selection changes. */
|
|
35
|
+
onValueChange?: (value: string[]) => void;
|
|
36
|
+
/** Maximum selections allowed. @default Infinity */
|
|
37
|
+
max?: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Discriminated union: `type` narrows `value` / `defaultValue` / `onValueChange`,
|
|
42
|
+
* and `max` is only valid on `type="multiple"`.
|
|
43
|
+
*/
|
|
44
|
+
export type ITileGroupProps = ITileGroupSingleProps | ITileGroupMultipleProps;
|
|
45
|
+
|
|
46
|
+
export interface ITileGroupContextValue {
|
|
47
|
+
type: TileGroupType;
|
|
48
|
+
/** Current selection (string for single, array for multiple). */
|
|
49
|
+
value: string | string[] | undefined;
|
|
50
|
+
toggleValue: (tileValue: string) => void;
|
|
51
|
+
isSelected: (tileValue: string) => boolean;
|
|
52
|
+
/** Group-level disabled or multi-select at max (unselected tiles). */
|
|
53
|
+
isTileDisabledByGroup: (tileValue: string) => boolean;
|
|
54
|
+
isGroupDisabled: boolean;
|
|
55
|
+
max: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface ITileContextValue {
|
|
59
|
+
/** This tile's `value`. */
|
|
60
|
+
value: string;
|
|
61
|
+
isSelected: boolean;
|
|
62
|
+
/** Effective disabled (group rules + tile `disabled`). */
|
|
63
|
+
isDisabled: boolean;
|
|
64
|
+
selectionType: TileGroupType;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type ITilePressablePassthrough = Partial<
|
|
68
|
+
Pick<PressableProps, 'onPressIn' | 'onPressOut' | 'onHoverIn' | 'onHoverOut'>
|
|
69
|
+
>;
|
|
70
|
+
|
|
71
|
+
export interface ITileProps
|
|
72
|
+
extends PressableProps, ITilePressablePassthrough, WithStyleContextProps {
|
|
73
|
+
/**
|
|
74
|
+
* Identifies this tile within `Tile.Group`. Must be unique within the group.
|
|
75
|
+
* Standalone tiles still require a value (useful for form submission, analytics, etc.).
|
|
76
|
+
*/
|
|
77
|
+
value: string;
|
|
78
|
+
/**
|
|
79
|
+
* Disables this tile (in addition to group rules such as multi-select max).
|
|
80
|
+
*/
|
|
81
|
+
disabled?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Controlled selected state for **standalone** usage (no parent `Tile.Group`).
|
|
84
|
+
* Ignored when the tile is rendered inside a `Tile.Group` — selection is owned by the group.
|
|
85
|
+
*/
|
|
86
|
+
isSelected?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Initial selected state for **standalone**, uncontrolled usage.
|
|
89
|
+
*/
|
|
90
|
+
defaultSelected?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Called when standalone selection state changes. Group context overrides this — when inside
|
|
93
|
+
* a `Tile.Group`, use the group's `onValueChange` instead.
|
|
94
|
+
*/
|
|
95
|
+
onSelectedChange?: (isSelected: boolean) => void;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface ITileLeadingSlotProps extends ViewProps {
|
|
99
|
+
/**
|
|
100
|
+
* Leading content is decorative by default for screen readers.
|
|
101
|
+
* @default true
|
|
102
|
+
*/
|
|
103
|
+
'aria-hidden'?: boolean;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export type ITileContentProps = ViewProps;
|
|
107
|
+
export type ITileTitleProps = TextProps;
|
|
108
|
+
export type ITileDescriptionProps = TextProps;
|
|
109
|
+
export interface ITileIndicatorProps extends ViewProps {
|
|
110
|
+
/**
|
|
111
|
+
* Explicit indicator visual. When inside a `Tile.Group`, auto-infers from `type`
|
|
112
|
+
* (`single` → radio, `multiple` → checkbox). For standalone tiles, defaults to `'checkbox'`
|
|
113
|
+
* to match the standalone `checkbox` ARIA role; override with `indicatorType="radio"` if
|
|
114
|
+
* a radio-style visual is needed.
|
|
115
|
+
*/
|
|
116
|
+
indicatorType?: 'radio' | 'checkbox';
|
|
117
|
+
children?: ReactNode;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Generic trailing content slot. Use for chevrons, amounts, chips, status text — anything that
|
|
122
|
+
* is **not** the radio/checkbox selection affordance. For that, use `Tile.Indicator`.
|
|
123
|
+
*/
|
|
124
|
+
export type ITileTrailingSlotProps = ViewProps;
|
|
125
|
+
|
|
126
|
+
export type ITileComponentType<
|
|
127
|
+
RootRef,
|
|
128
|
+
LeadingSlot,
|
|
129
|
+
Content,
|
|
130
|
+
Title,
|
|
131
|
+
Description,
|
|
132
|
+
Indicator,
|
|
133
|
+
TrailingSlot,
|
|
134
|
+
Group,
|
|
135
|
+
> = ForwardRefExoticComponent<RefAttributes<RootRef> & ITileProps> & {
|
|
136
|
+
Group: ForwardRefExoticComponent<RefAttributes<Group> & PropsWithoutRef<Group> & ITileGroupProps>;
|
|
137
|
+
LeadingSlot: ForwardRefExoticComponent<
|
|
138
|
+
RefAttributes<LeadingSlot> & PropsWithoutRef<LeadingSlot> & ITileLeadingSlotProps
|
|
139
|
+
>;
|
|
140
|
+
Content: ForwardRefExoticComponent<
|
|
141
|
+
RefAttributes<Content> & PropsWithoutRef<Content> & ITileContentProps
|
|
142
|
+
>;
|
|
143
|
+
Title: ForwardRefExoticComponent<RefAttributes<Title> & PropsWithoutRef<Title> & ITileTitleProps>;
|
|
144
|
+
Description: ForwardRefExoticComponent<
|
|
145
|
+
RefAttributes<Description> & PropsWithoutRef<Description> & ITileDescriptionProps
|
|
146
|
+
>;
|
|
147
|
+
Indicator: ForwardRefExoticComponent<
|
|
148
|
+
RefAttributes<Indicator> & PropsWithoutRef<Indicator> & ITileIndicatorProps
|
|
149
|
+
>;
|
|
150
|
+
TrailingSlot: ForwardRefExoticComponent<
|
|
151
|
+
RefAttributes<TrailingSlot> & PropsWithoutRef<TrailingSlot> & ITileTrailingSlotProps
|
|
152
|
+
>;
|
|
153
|
+
};
|