@dxos/react-list 0.8.3 → 0.8.4-main.03d5cd7b56
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 +134 -1
- package/dist/lib/browser/index.mjs +63 -78
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +63 -78
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/List.d.ts +12 -0
- package/dist/types/src/List.d.ts.map +1 -1
- package/dist/types/src/List.stories.d.ts +12 -0
- package/dist/types/src/List.stories.d.ts.map +1 -0
- package/dist/types/src/ListItem.d.ts +4 -4
- package/dist/types/src/ListItem.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -15
- package/src/List.stories.tsx +149 -0
- package/src/List.tsx +59 -5
- package/src/ListItem.tsx +7 -7
- package/dist/lib/node/index.cjs +0 -161
- package/dist/lib/node/index.cjs.map +0 -7
- package/dist/lib/node/meta.json +0 -1
package/package.json
CHANGED
|
@@ -1,49 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-list",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4-main.03d5cd7b56",
|
|
4
4
|
"description": "List primitive components for React.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dxos/dxos"
|
|
10
|
+
},
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"author": "DXOS.org",
|
|
9
|
-
"sideEffects":
|
|
13
|
+
"sideEffects": false,
|
|
10
14
|
"type": "module",
|
|
11
15
|
"exports": {
|
|
12
16
|
".": {
|
|
17
|
+
"source": "./src/index.ts",
|
|
13
18
|
"types": "./dist/types/src/index.d.ts",
|
|
14
19
|
"browser": "./dist/lib/browser/index.mjs",
|
|
15
20
|
"node": "./dist/lib/node-esm/index.mjs"
|
|
16
21
|
}
|
|
17
22
|
},
|
|
18
23
|
"types": "dist/types/src/index.d.ts",
|
|
19
|
-
"typesVersions": {
|
|
20
|
-
"*": {}
|
|
21
|
-
},
|
|
22
24
|
"files": [
|
|
23
25
|
"dist",
|
|
24
26
|
"src"
|
|
25
27
|
],
|
|
26
28
|
"dependencies": {
|
|
27
|
-
"@preact-signals/safe-react": "^0.9.0",
|
|
28
29
|
"@radix-ui/react-collapsible": "1.1.3",
|
|
29
30
|
"@radix-ui/react-context": "1.1.1",
|
|
30
31
|
"@radix-ui/react-primitive": "2.0.2",
|
|
31
32
|
"@radix-ui/react-slot": "1.1.2",
|
|
32
33
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
33
|
-
"
|
|
34
|
-
"@dxos/react-hooks": "0.8.3"
|
|
34
|
+
"@dxos/react-hooks": "0.8.4-main.03d5cd7b56"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@radix-ui/react-checkbox": "1.1.4",
|
|
38
|
-
"@
|
|
39
|
-
"@types/react": "~
|
|
40
|
-
"@types/react-dom": "~
|
|
41
|
-
"react": "~
|
|
42
|
-
"react-dom": "~
|
|
38
|
+
"@storybook/react-vite": "^10.3.6",
|
|
39
|
+
"@types/react": "~19.2.7",
|
|
40
|
+
"@types/react-dom": "~19.2.3",
|
|
41
|
+
"react": "~19.2.3",
|
|
42
|
+
"react-dom": "~19.2.3"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"react": "~
|
|
46
|
-
"react-dom": "~
|
|
45
|
+
"react": "~19.2.3",
|
|
46
|
+
"react-dom": "~19.2.3"
|
|
47
47
|
},
|
|
48
48
|
"publishConfig": {
|
|
49
49
|
"access": "public"
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
// Stories for the elemental `@dxos/react-list` primitive — ARIA + structure
|
|
6
|
+
// only. These show the default-styling-free behavior of `List` / `ListItem`
|
|
7
|
+
// in isolation. For the styled, ARIA-correct, keyboard-navigable layer most
|
|
8
|
+
// app code reaches for, see `@dxos/react-ui-list`'s `RowList` story.
|
|
9
|
+
|
|
10
|
+
import { type Decorator, type Meta, type StoryObj } from '@storybook/react-vite';
|
|
11
|
+
import React, { useState } from 'react';
|
|
12
|
+
|
|
13
|
+
import { List } from './List';
|
|
14
|
+
import { ListItem, ListItemCollapsibleContent, ListItemHeading, ListItemOpenTrigger } from './ListItem';
|
|
15
|
+
|
|
16
|
+
type Item = { id: string; label: string };
|
|
17
|
+
|
|
18
|
+
const items: Item[] = Array.from({ length: 5 }, (_, i) => ({
|
|
19
|
+
id: `item-${i}`,
|
|
20
|
+
label: `Item ${i + 1}`,
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
//
|
|
24
|
+
// Static unordered list — no selection.
|
|
25
|
+
//
|
|
26
|
+
|
|
27
|
+
const StaticStory = () => (
|
|
28
|
+
<List variant='unordered' className='dx-container border border-separator p-2'>
|
|
29
|
+
{items.map((item) => (
|
|
30
|
+
<ListItem key={item.id} className='py-1'>
|
|
31
|
+
<ListItemHeading>{item.label}</ListItemHeading>
|
|
32
|
+
</ListItem>
|
|
33
|
+
))}
|
|
34
|
+
</List>
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
//
|
|
38
|
+
// Single-select listbox. Pairs `aria-selected` (set by the primitive when
|
|
39
|
+
// `selectable={true}`) with the canonical `dx-selected` / `dx-hover`
|
|
40
|
+
// utilities to demonstrate the ARIA ↔ dx-* grammar in its rawest form.
|
|
41
|
+
//
|
|
42
|
+
|
|
43
|
+
const SingleSelectStory = () => {
|
|
44
|
+
const [selected, setSelected] = useState<string>(items[0].id);
|
|
45
|
+
return (
|
|
46
|
+
<List
|
|
47
|
+
variant='unordered'
|
|
48
|
+
selectable
|
|
49
|
+
aria-label='Single-select example'
|
|
50
|
+
className='dx-container border border-separator'
|
|
51
|
+
>
|
|
52
|
+
{items.map((item) => (
|
|
53
|
+
<ListItem
|
|
54
|
+
key={item.id}
|
|
55
|
+
selected={item.id === selected}
|
|
56
|
+
onClick={() => setSelected(item.id)}
|
|
57
|
+
className='dx-hover dx-selected px-3 py-2 cursor-pointer outline-none'
|
|
58
|
+
>
|
|
59
|
+
<ListItemHeading>{item.label}</ListItemHeading>
|
|
60
|
+
</ListItem>
|
|
61
|
+
))}
|
|
62
|
+
</List>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
//
|
|
67
|
+
// Multi-select listbox. `multiSelectable` adds `aria-multiselectable="true"`
|
|
68
|
+
// on the listbox itself; selection state is per-item.
|
|
69
|
+
//
|
|
70
|
+
|
|
71
|
+
const MultiSelectStory = () => {
|
|
72
|
+
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set([items[1].id]));
|
|
73
|
+
const toggle = (id: string) => {
|
|
74
|
+
setSelectedIds((prev) => {
|
|
75
|
+
const next = new Set(prev);
|
|
76
|
+
if (next.has(id)) {
|
|
77
|
+
next.delete(id);
|
|
78
|
+
} else {
|
|
79
|
+
next.add(id);
|
|
80
|
+
}
|
|
81
|
+
return next;
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
return (
|
|
85
|
+
<List
|
|
86
|
+
variant='unordered'
|
|
87
|
+
selectable
|
|
88
|
+
multiSelectable
|
|
89
|
+
aria-label='Multi-select example'
|
|
90
|
+
className='dx-container border border-separator'
|
|
91
|
+
>
|
|
92
|
+
{items.map((item) => (
|
|
93
|
+
<ListItem
|
|
94
|
+
key={item.id}
|
|
95
|
+
selected={selectedIds.has(item.id)}
|
|
96
|
+
onClick={() => toggle(item.id)}
|
|
97
|
+
className='dx-hover dx-selected px-3 py-2 cursor-pointer outline-none'
|
|
98
|
+
>
|
|
99
|
+
<ListItemHeading>{item.label}</ListItemHeading>
|
|
100
|
+
</ListItem>
|
|
101
|
+
))}
|
|
102
|
+
</List>
|
|
103
|
+
);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
//
|
|
107
|
+
// Collapsible item — opens / closes a Radix `Collapsible`-backed body.
|
|
108
|
+
// Useful for accordion-style headings without reaching for the full
|
|
109
|
+
// `react-ui-list` `Accordion` component.
|
|
110
|
+
//
|
|
111
|
+
|
|
112
|
+
const CollapsibleStory = () => (
|
|
113
|
+
<List variant='unordered' className='dx-container border border-separator divide-y divide-separator'>
|
|
114
|
+
{items.slice(0, 3).map((item) => (
|
|
115
|
+
<ListItem key={item.id} collapsible defaultOpen={item.id === items[0].id}>
|
|
116
|
+
<ListItemOpenTrigger asChild>
|
|
117
|
+
<ListItemHeading className='cursor-pointer px-3 py-2 select-none'>{item.label}</ListItemHeading>
|
|
118
|
+
</ListItemOpenTrigger>
|
|
119
|
+
<ListItemCollapsibleContent>
|
|
120
|
+
<div className='px-3 pb-2 text-description text-sm'>Details for {item.label}.</div>
|
|
121
|
+
</ListItemCollapsibleContent>
|
|
122
|
+
</ListItem>
|
|
123
|
+
))}
|
|
124
|
+
</List>
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
// Inline column decorator — `react-list` deliberately doesn't depend on
|
|
128
|
+
// `@dxos/react-ui` (a `withTheme/withLayout` import would create a cycle
|
|
129
|
+
// since `react-ui` already depends on this primitive). Storybook's global
|
|
130
|
+
// `withThemeByClassName` already applies the theme class at the root.
|
|
131
|
+
const withColumn: Decorator = (Story) => (
|
|
132
|
+
<div className='flex flex-col gap-4 p-4 h-full max-w-md'>
|
|
133
|
+
<Story />
|
|
134
|
+
</div>
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
const meta = {
|
|
138
|
+
title: 'ui/react-list/List',
|
|
139
|
+
decorators: [withColumn],
|
|
140
|
+
} satisfies Meta;
|
|
141
|
+
|
|
142
|
+
export default meta;
|
|
143
|
+
|
|
144
|
+
type Story = StoryObj<typeof meta>;
|
|
145
|
+
|
|
146
|
+
export const Static: Story = { render: StaticStory };
|
|
147
|
+
export const SingleSelect: Story = { render: SingleSelectStory };
|
|
148
|
+
export const MultiSelect: Story = { render: MultiSelectStory };
|
|
149
|
+
export const Collapsible: Story = { render: CollapsibleStory };
|
package/src/List.tsx
CHANGED
|
@@ -2,12 +2,36 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// Elemental list / listbox primitive.
|
|
6
|
+
//
|
|
7
|
+
// This is the ARIA-only foundation of the DXOS list stack. It renders a
|
|
8
|
+
// semantically-correct `<ol>` / `<ul>` (or, when `selectable={true}`, a
|
|
9
|
+
// `role="listbox"` element with `role="option"` children carrying
|
|
10
|
+
// `aria-selected`). It applies no styling, no keyboard navigation, and
|
|
11
|
+
// no `dx-*` utility classes — those are layered above in
|
|
12
|
+
// `@dxos/react-ui-list`.
|
|
13
|
+
//
|
|
14
|
+
// Layering:
|
|
15
|
+
// - `@dxos/react-list` — this package; ARIA + structure only.
|
|
16
|
+
// - `@dxos/react-ui-list` — adds `dx-*` styling, keyboard nav, and
|
|
17
|
+
// opinionated `RowList`/`CardList` containers.
|
|
18
|
+
// - `@dxos/react-ui-mosaic` — virtualized / draggable / card-board
|
|
19
|
+
// layouts; composes the above where useful.
|
|
20
|
+
//
|
|
21
|
+
// Most app code should reach for `@dxos/react-ui-list`. Use this primitive
|
|
22
|
+
// directly only when building a *new* selectable surface that needs full
|
|
23
|
+
// control over styling and keyboard handling (e.g. a custom Combobox).
|
|
24
|
+
//
|
|
25
|
+
// See:
|
|
26
|
+
// - `packages/ui/ui-theme/src/css/components/selected.md` for the
|
|
27
|
+
// `aria-selected` ↔ `dx-selected` pairing rules.
|
|
28
|
+
// - `packages/ui/react-ui-list/AUDIT.md` for why this layering exists.
|
|
29
|
+
// - https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role
|
|
30
|
+
|
|
31
|
+
import { type Scope, createContextScope } from '@radix-ui/react-context';
|
|
6
32
|
import { Primitive } from '@radix-ui/react-primitive';
|
|
7
33
|
import React, { type ComponentPropsWithRef, forwardRef } from 'react';
|
|
8
34
|
|
|
9
|
-
// TODO(thure): A lot of the accessible affordances for this kind of thing need to be implemented per https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role
|
|
10
|
-
|
|
11
35
|
const LIST_NAME = 'List';
|
|
12
36
|
|
|
13
37
|
type ListScopedProps<P> = P & { __listScope?: Scope };
|
|
@@ -17,7 +41,19 @@ type ListVariant = 'ordered' | 'unordered';
|
|
|
17
41
|
type ListItemSizes = 'one' | 'many';
|
|
18
42
|
|
|
19
43
|
type ListProps = ComponentPropsWithRef<typeof Primitive.ol> & {
|
|
44
|
+
/**
|
|
45
|
+
* If true, render as `role="listbox"` and let `ListItem` children become
|
|
46
|
+
* `role="option"` + `aria-selected`. If false (default) the list is a
|
|
47
|
+
* plain `<ol>` / `<ul>` with no selection semantics — pick this for
|
|
48
|
+
* static lists.
|
|
49
|
+
*/
|
|
20
50
|
selectable?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* If true, the listbox advertises multi-select via
|
|
53
|
+
* `aria-multiselectable="true"`. Defaults to false (single-select).
|
|
54
|
+
* Has no effect unless `selectable` is also true.
|
|
55
|
+
*/
|
|
56
|
+
multiSelectable?: boolean;
|
|
21
57
|
variant?: ListVariant;
|
|
22
58
|
itemSizes?: ListItemSizes;
|
|
23
59
|
};
|
|
@@ -33,10 +69,28 @@ type ListContextValue = {
|
|
|
33
69
|
const [ListProvider, useListContext] = createListContext<ListContextValue>(LIST_NAME);
|
|
34
70
|
|
|
35
71
|
const List = forwardRef<HTMLOListElement, ListProps>((props: ListScopedProps<ListProps>, forwardedRef) => {
|
|
36
|
-
const {
|
|
72
|
+
const {
|
|
73
|
+
__listScope,
|
|
74
|
+
variant = 'ordered',
|
|
75
|
+
selectable = false,
|
|
76
|
+
multiSelectable = false,
|
|
77
|
+
itemSizes,
|
|
78
|
+
children,
|
|
79
|
+
...rootProps
|
|
80
|
+
} = props;
|
|
37
81
|
const ListRoot = variant === 'ordered' ? Primitive.ol : Primitive.ul;
|
|
38
82
|
return (
|
|
39
|
-
<ListRoot
|
|
83
|
+
<ListRoot
|
|
84
|
+
// `aria-multiselectable` is only meaningful on `role="listbox"`,
|
|
85
|
+
// and even there is omitted in the single-select default to keep
|
|
86
|
+
// assistive tech announcements concise.
|
|
87
|
+
{...(selectable && {
|
|
88
|
+
role: 'listbox',
|
|
89
|
+
...(multiSelectable && { 'aria-multiselectable': true as const }),
|
|
90
|
+
})}
|
|
91
|
+
{...rootProps}
|
|
92
|
+
ref={forwardedRef}
|
|
93
|
+
>
|
|
40
94
|
<ListProvider
|
|
41
95
|
{...{
|
|
42
96
|
scope: __listScope,
|
package/src/ListItem.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import type { CheckboxProps } from '@radix-ui/react-checkbox';
|
|
6
6
|
import { type CollapsibleContentProps, type CollapsibleTriggerProps } from '@radix-ui/react-collapsible';
|
|
7
7
|
import * as Collapsible from '@radix-ui/react-collapsible';
|
|
8
|
-
import {
|
|
8
|
+
import { type Scope, createContextScope } from '@radix-ui/react-context';
|
|
9
9
|
import { Primitive } from '@radix-ui/react-primitive';
|
|
10
10
|
import { Slot } from '@radix-ui/react-slot';
|
|
11
11
|
import { useControllableState } from '@radix-ui/react-use-controllable-state';
|
|
@@ -13,11 +13,11 @@ import React, {
|
|
|
13
13
|
type ComponentProps,
|
|
14
14
|
type ComponentPropsWithoutRef,
|
|
15
15
|
type Dispatch,
|
|
16
|
-
type
|
|
17
|
-
forwardRef,
|
|
16
|
+
type ComponentRef,
|
|
18
17
|
type ForwardRefExoticComponent,
|
|
19
18
|
type RefAttributes,
|
|
20
19
|
type SetStateAction,
|
|
20
|
+
forwardRef,
|
|
21
21
|
} from 'react';
|
|
22
22
|
|
|
23
23
|
import { useId } from '@dxos/react-hooks';
|
|
@@ -44,7 +44,7 @@ type ListItemProps = Omit<ListItemData, 'id'> & { collapsible?: boolean } & RefA
|
|
|
44
44
|
defaultSelected?: CheckboxProps['defaultChecked'];
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
type ListItemElement =
|
|
47
|
+
type ListItemElement = ComponentRef<'li'>;
|
|
48
48
|
|
|
49
49
|
const [createListItemContext, createListItemScope] = createContextScope(LIST_ITEM_NAME, []);
|
|
50
50
|
|
|
@@ -65,11 +65,11 @@ type ListItemHeadingProps = ListItemScopedProps<Omit<ComponentPropsWithoutRef<'p
|
|
|
65
65
|
const ListItemHeading = forwardRef<HTMLDivElement, ListItemHeadingProps>(
|
|
66
66
|
({ children, asChild, __listItemScope, ...props }, forwardedRef) => {
|
|
67
67
|
const { headingId } = useListItemContext(LIST_ITEM_NAME, __listItemScope);
|
|
68
|
-
const
|
|
68
|
+
const Comp = asChild ? Slot : Primitive.div;
|
|
69
69
|
return (
|
|
70
|
-
<
|
|
70
|
+
<Comp {...props} id={headingId} ref={forwardedRef}>
|
|
71
71
|
{children}
|
|
72
|
-
</
|
|
72
|
+
</Comp>
|
|
73
73
|
);
|
|
74
74
|
},
|
|
75
75
|
);
|
package/dist/lib/node/index.cjs
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
var node_exports = {};
|
|
30
|
-
__export(node_exports, {
|
|
31
|
-
LIST_ITEM_NAME: () => LIST_ITEM_NAME,
|
|
32
|
-
LIST_NAME: () => LIST_NAME,
|
|
33
|
-
List: () => List,
|
|
34
|
-
ListItem: () => ListItem,
|
|
35
|
-
ListItemCollapsibleContent: () => ListItemCollapsibleContent,
|
|
36
|
-
ListItemHeading: () => ListItemHeading,
|
|
37
|
-
ListItemOpenTrigger: () => ListItemOpenTrigger,
|
|
38
|
-
createListItemScope: () => createListItemScope,
|
|
39
|
-
createListScope: () => createListScope,
|
|
40
|
-
useListContext: () => useListContext,
|
|
41
|
-
useListItemContext: () => useListItemContext
|
|
42
|
-
});
|
|
43
|
-
module.exports = __toCommonJS(node_exports);
|
|
44
|
-
var import_tracking = require("@preact-signals/safe-react/tracking");
|
|
45
|
-
var import_react_context = require("@radix-ui/react-context");
|
|
46
|
-
var import_react_primitive = require("@radix-ui/react-primitive");
|
|
47
|
-
var import_react = __toESM(require("react"));
|
|
48
|
-
var import_tracking2 = require("@preact-signals/safe-react/tracking");
|
|
49
|
-
var Collapsible = __toESM(require("@radix-ui/react-collapsible"));
|
|
50
|
-
var import_react_context2 = require("@radix-ui/react-context");
|
|
51
|
-
var import_react_primitive2 = require("@radix-ui/react-primitive");
|
|
52
|
-
var import_react_slot = require("@radix-ui/react-slot");
|
|
53
|
-
var import_react_use_controllable_state = require("@radix-ui/react-use-controllable-state");
|
|
54
|
-
var import_react2 = __toESM(require("react"));
|
|
55
|
-
var import_react_hooks = require("@dxos/react-hooks");
|
|
56
|
-
var LIST_NAME = "List";
|
|
57
|
-
var [createListContext, createListScope] = (0, import_react_context.createContextScope)(LIST_NAME, []);
|
|
58
|
-
var [ListProvider, useListContext] = createListContext(LIST_NAME);
|
|
59
|
-
var List = /* @__PURE__ */ (0, import_react.forwardRef)((props, forwardedRef) => {
|
|
60
|
-
var _effect = (0, import_tracking.useSignals)();
|
|
61
|
-
try {
|
|
62
|
-
const { __listScope, variant = "ordered", selectable = false, itemSizes, children, ...rootProps } = props;
|
|
63
|
-
const ListRoot = variant === "ordered" ? import_react_primitive.Primitive.ol : import_react_primitive.Primitive.ul;
|
|
64
|
-
return /* @__PURE__ */ import_react.default.createElement(ListRoot, {
|
|
65
|
-
...selectable && {
|
|
66
|
-
role: "listbox",
|
|
67
|
-
"aria-multiselectable": true
|
|
68
|
-
},
|
|
69
|
-
...rootProps,
|
|
70
|
-
ref: forwardedRef
|
|
71
|
-
}, /* @__PURE__ */ import_react.default.createElement(ListProvider, {
|
|
72
|
-
scope: __listScope,
|
|
73
|
-
variant,
|
|
74
|
-
selectable,
|
|
75
|
-
itemSizes
|
|
76
|
-
}, children));
|
|
77
|
-
} finally {
|
|
78
|
-
_effect.f();
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
List.displayName = LIST_NAME;
|
|
82
|
-
var LIST_ITEM_NAME = "ListItem";
|
|
83
|
-
var [createListItemContext, createListItemScope] = (0, import_react_context2.createContextScope)(LIST_ITEM_NAME, []);
|
|
84
|
-
var [ListItemProvider, useListItemContext] = createListItemContext(LIST_ITEM_NAME);
|
|
85
|
-
var ListItemHeading = /* @__PURE__ */ (0, import_react2.forwardRef)(({ children, asChild, __listItemScope, ...props }, forwardedRef) => {
|
|
86
|
-
var _effect = (0, import_tracking2.useSignals)();
|
|
87
|
-
try {
|
|
88
|
-
const { headingId } = useListItemContext(LIST_ITEM_NAME, __listItemScope);
|
|
89
|
-
const Root2 = asChild ? import_react_slot.Slot : import_react_primitive2.Primitive.div;
|
|
90
|
-
return /* @__PURE__ */ import_react2.default.createElement(Root2, {
|
|
91
|
-
...props,
|
|
92
|
-
id: headingId,
|
|
93
|
-
ref: forwardedRef
|
|
94
|
-
}, children);
|
|
95
|
-
} finally {
|
|
96
|
-
_effect.f();
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
var ListItemOpenTrigger = Collapsible.Trigger;
|
|
100
|
-
var ListItemCollapsibleContent = Collapsible.Content;
|
|
101
|
-
var ListItem = /* @__PURE__ */ (0, import_react2.forwardRef)((props, forwardedRef) => {
|
|
102
|
-
var _effect = (0, import_tracking2.useSignals)();
|
|
103
|
-
try {
|
|
104
|
-
const id = (0, import_react_hooks.useId)("listItem", props.id);
|
|
105
|
-
const { __listScope, __listItemScope, children, selected: propsSelected, defaultSelected, onSelectedChange, open: propsOpen, defaultOpen, onOpenChange, collapsible, labelId, ...listItemProps } = props;
|
|
106
|
-
const { selectable } = useListContext(LIST_NAME, __listScope);
|
|
107
|
-
const [selected = false, setSelected] = (0, import_react_use_controllable_state.useControllableState)({
|
|
108
|
-
prop: propsSelected,
|
|
109
|
-
defaultProp: defaultSelected,
|
|
110
|
-
onChange: onSelectedChange
|
|
111
|
-
});
|
|
112
|
-
const [open = false, setOpen] = (0, import_react_use_controllable_state.useControllableState)({
|
|
113
|
-
prop: propsOpen,
|
|
114
|
-
defaultProp: defaultOpen,
|
|
115
|
-
onChange: onOpenChange
|
|
116
|
-
});
|
|
117
|
-
const headingId = (0, import_react_hooks.useId)("listItem__heading", labelId);
|
|
118
|
-
const listItem = /* @__PURE__ */ import_react2.default.createElement(import_react_primitive2.Primitive.li, {
|
|
119
|
-
...listItemProps,
|
|
120
|
-
id,
|
|
121
|
-
ref: forwardedRef,
|
|
122
|
-
"aria-labelledby": headingId,
|
|
123
|
-
...selectable && {
|
|
124
|
-
role: "option",
|
|
125
|
-
"aria-selected": !!selected
|
|
126
|
-
},
|
|
127
|
-
...open && {
|
|
128
|
-
"aria-expanded": true
|
|
129
|
-
}
|
|
130
|
-
}, children);
|
|
131
|
-
return /* @__PURE__ */ import_react2.default.createElement(ListItemProvider, {
|
|
132
|
-
scope: __listItemScope,
|
|
133
|
-
headingId,
|
|
134
|
-
open,
|
|
135
|
-
selected,
|
|
136
|
-
setSelected
|
|
137
|
-
}, collapsible ? /* @__PURE__ */ import_react2.default.createElement(Collapsible.Root, {
|
|
138
|
-
asChild: true,
|
|
139
|
-
open,
|
|
140
|
-
onOpenChange: setOpen
|
|
141
|
-
}, listItem) : listItem);
|
|
142
|
-
} finally {
|
|
143
|
-
_effect.f();
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
ListItem.displayName = LIST_ITEM_NAME;
|
|
147
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
148
|
-
0 && (module.exports = {
|
|
149
|
-
LIST_ITEM_NAME,
|
|
150
|
-
LIST_NAME,
|
|
151
|
-
List,
|
|
152
|
-
ListItem,
|
|
153
|
-
ListItemCollapsibleContent,
|
|
154
|
-
ListItemHeading,
|
|
155
|
-
ListItemOpenTrigger,
|
|
156
|
-
createListItemScope,
|
|
157
|
-
createListScope,
|
|
158
|
-
useListContext,
|
|
159
|
-
useListItemContext
|
|
160
|
-
});
|
|
161
|
-
//# sourceMappingURL=index.cjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../src/List.tsx", "../../../src/ListItem.tsx"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { createContextScope, type Scope } from '@radix-ui/react-context';\nimport { Primitive } from '@radix-ui/react-primitive';\nimport React, { type ComponentPropsWithRef, forwardRef } from 'react';\n\n// TODO(thure): A lot of the accessible affordances for this kind of thing need to be implemented per https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/listbox_role\n\nconst LIST_NAME = 'List';\n\ntype ListScopedProps<P> = P & { __listScope?: Scope };\n\ntype ListVariant = 'ordered' | 'unordered';\n\ntype ListItemSizes = 'one' | 'many';\n\ntype ListProps = ComponentPropsWithRef<typeof Primitive.ol> & {\n selectable?: boolean;\n variant?: ListVariant;\n itemSizes?: ListItemSizes;\n};\n\nconst [createListContext, createListScope] = createContextScope(LIST_NAME, []);\n\ntype ListContextValue = {\n selectable: Exclude<ListProps['selectable'], undefined>;\n variant: Exclude<ListProps['variant'], undefined>;\n itemSizes?: ListItemSizes;\n};\n\nconst [ListProvider, useListContext] = createListContext<ListContextValue>(LIST_NAME);\n\nconst List = forwardRef<HTMLOListElement, ListProps>((props: ListScopedProps<ListProps>, forwardedRef) => {\n const { __listScope, variant = 'ordered', selectable = false, itemSizes, children, ...rootProps } = props;\n const ListRoot = variant === 'ordered' ? Primitive.ol : Primitive.ul;\n return (\n <ListRoot {...(selectable && { role: 'listbox', 'aria-multiselectable': true })} {...rootProps} ref={forwardedRef}>\n <ListProvider\n {...{\n scope: __listScope,\n variant,\n selectable,\n itemSizes,\n }}\n >\n {children}\n </ListProvider>\n </ListRoot>\n );\n});\n\nList.displayName = LIST_NAME;\n\nexport { List, createListScope, useListContext, LIST_NAME };\n\nexport type { ListProps, ListVariant, ListScopedProps };\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport type { CheckboxProps } from '@radix-ui/react-checkbox';\nimport { type CollapsibleContentProps, type CollapsibleTriggerProps } from '@radix-ui/react-collapsible';\nimport * as Collapsible from '@radix-ui/react-collapsible';\nimport { createContextScope, type Scope } from '@radix-ui/react-context';\nimport { Primitive } from '@radix-ui/react-primitive';\nimport { Slot } from '@radix-ui/react-slot';\nimport { useControllableState } from '@radix-ui/react-use-controllable-state';\nimport React, {\n type ComponentProps,\n type ComponentPropsWithoutRef,\n type Dispatch,\n type ElementRef,\n forwardRef,\n type ForwardRefExoticComponent,\n type RefAttributes,\n type SetStateAction,\n} from 'react';\n\nimport { useId } from '@dxos/react-hooks';\n\nimport { LIST_NAME, type ListScopedProps, useListContext } from './List';\n\nconst LIST_ITEM_NAME = 'ListItem';\n\ntype ListItemScopedProps<P> = P & { __listItemScope?: Scope };\n\ninterface ListItemData {\n id: string;\n labelId?: string;\n selected?: CheckboxProps['checked'];\n open?: boolean;\n}\n\ntype ListItemProps = Omit<ListItemData, 'id'> & { collapsible?: boolean } & RefAttributes<HTMLLIElement> &\n ComponentPropsWithoutRef<'li'> & {\n defaultOpen?: boolean;\n onOpenChange?: (nextOpen: boolean) => void;\n } & {\n onSelectedChange?: CheckboxProps['onCheckedChange'];\n defaultSelected?: CheckboxProps['defaultChecked'];\n };\n\ntype ListItemElement = ElementRef<'li'>;\n\nconst [createListItemContext, createListItemScope] = createContextScope(LIST_ITEM_NAME, []);\n\ntype ListItemContextValue = {\n headingId: string;\n open: boolean;\n selected: CheckboxProps['checked'];\n setSelected: Dispatch<SetStateAction<CheckboxProps['checked']>>;\n};\n\nconst [ListItemProvider, useListItemContext] = createListItemContext<ListItemContextValue>(LIST_ITEM_NAME);\n\ntype ListItemHeadingProps = ListItemScopedProps<Omit<ComponentPropsWithoutRef<'p'>, 'id'>> &\n RefAttributes<HTMLParagraphElement> & {\n asChild?: boolean;\n };\n\nconst ListItemHeading = forwardRef<HTMLDivElement, ListItemHeadingProps>(\n ({ children, asChild, __listItemScope, ...props }, forwardedRef) => {\n const { headingId } = useListItemContext(LIST_ITEM_NAME, __listItemScope);\n const Root = asChild ? Slot : Primitive.div;\n return (\n <Root {...props} id={headingId} ref={forwardedRef}>\n {children}\n </Root>\n );\n },\n);\n\ntype ListItemOpenTriggerProps = ListItemScopedProps<CollapsibleTriggerProps>;\n\nconst ListItemOpenTrigger = Collapsible.Trigger;\n\ntype ListItemCollapsibleContentProps = ComponentProps<typeof Collapsible.Content>;\n\nconst ListItemCollapsibleContent: ForwardRefExoticComponent<CollapsibleContentProps> = Collapsible.Content;\n\nconst ListItem = forwardRef<ListItemElement, ListItemProps>(\n (props: ListItemScopedProps<ListScopedProps<ListItemProps>>, forwardedRef) => {\n const id = useId('listItem', props.id);\n\n const {\n __listScope,\n __listItemScope,\n children,\n selected: propsSelected,\n defaultSelected,\n onSelectedChange,\n open: propsOpen,\n defaultOpen,\n onOpenChange,\n collapsible,\n labelId,\n ...listItemProps\n } = props;\n const { selectable } = useListContext(LIST_NAME, __listScope);\n\n const [selected = false, setSelected] = useControllableState({\n prop: propsSelected,\n defaultProp: defaultSelected,\n onChange: onSelectedChange,\n });\n\n const [open = false, setOpen] = useControllableState({\n prop: propsOpen,\n defaultProp: defaultOpen,\n onChange: onOpenChange,\n });\n\n const headingId = useId('listItem__heading', labelId);\n\n const listItem = (\n <Primitive.li\n {...listItemProps}\n id={id}\n ref={forwardedRef}\n aria-labelledby={headingId}\n {...(selectable && { role: 'option', 'aria-selected': !!selected })}\n {...(open && { 'aria-expanded': true })}\n >\n {children}\n </Primitive.li>\n );\n\n return (\n <ListItemProvider\n scope={__listItemScope}\n headingId={headingId}\n open={open}\n selected={selected}\n setSelected={setSelected}\n >\n {collapsible ? (\n <Collapsible.Root asChild open={open} onOpenChange={setOpen}>\n {listItem}\n </Collapsible.Root>\n ) : (\n listItem\n )}\n </ListItemProvider>\n );\n },\n);\n\nListItem.displayName = LIST_ITEM_NAME;\n\nexport {\n ListItem,\n ListItemHeading,\n ListItemCollapsibleContent,\n ListItemOpenTrigger,\n createListItemScope,\n useListItemContext,\n LIST_ITEM_NAME,\n};\n\nexport type {\n ListItemProps,\n ListItemHeadingProps,\n ListItemCollapsibleContentProps,\n ListItemOpenTriggerProps,\n ListItemScopedProps,\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["import_react_context", "import_react_primitive", "import_react", "LIST_NAME", "createListContext", "createListScope", "createContextScope", "ListProvider", "useListContext", "List", "forwardRef", "props", "forwardedRef", "__listScope", "variant", "selectable", "itemSizes", "children", "rootProps", "ListRoot", "Primitive", "ol", "ul", "React", "role", "ref", "scope", "displayName", "LIST_ITEM_NAME", "createListItemContext", "createListItemScope", "ListItemProvider", "useListItemContext", "ListItemHeading", "asChild", "__listItemScope", "headingId", "Root", "Slot", "div", "id", "ListItemOpenTrigger", "Trigger", "ListItemCollapsibleContent", "Content", "ListItem", "useId", "selected", "propsSelected", "defaultSelected", "onSelectedChange", "open", "propsOpen", "defaultOpen", "onOpenChange", "collapsible", "labelId", "listItemProps", "setSelected", "useControllableState", "prop", "defaultProp", "onChange", "setOpen", "listItem", "li", "aria-labelledby"]
|
|
7
|
-
}
|
package/dist/lib/node/meta.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"inputs":{"packages/ui/primitives/react-list/src/List.tsx":{"bytes":5630,"imports":[{"path":"@preact-signals/safe-react/tracking","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-primitive","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"packages/ui/primitives/react-list/src/ListItem.tsx":{"bytes":13458,"imports":[{"path":"@preact-signals/safe-react/tracking","kind":"import-statement","external":true},{"path":"@radix-ui/react-collapsible","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-primitive","kind":"import-statement","external":true},{"path":"@radix-ui/react-slot","kind":"import-statement","external":true},{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-hooks","kind":"import-statement","external":true},{"path":"packages/ui/primitives/react-list/src/List.tsx","kind":"import-statement","original":"./List"}],"format":"esm"},"packages/ui/primitives/react-list/src/index.ts":{"bytes":553,"imports":[{"path":"packages/ui/primitives/react-list/src/List.tsx","kind":"import-statement","original":"./List"},{"path":"packages/ui/primitives/react-list/src/ListItem.tsx","kind":"import-statement","original":"./ListItem"}],"format":"esm"}},"outputs":{"packages/ui/primitives/react-list/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":10287},"packages/ui/primitives/react-list/dist/lib/node/index.cjs":{"imports":[{"path":"@preact-signals/safe-react/tracking","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-primitive","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@preact-signals/safe-react/tracking","kind":"import-statement","external":true},{"path":"@radix-ui/react-collapsible","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-primitive","kind":"import-statement","external":true},{"path":"@radix-ui/react-slot","kind":"import-statement","external":true},{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-hooks","kind":"import-statement","external":true}],"exports":["LIST_ITEM_NAME","LIST_NAME","List","ListItem","ListItemCollapsibleContent","ListItemHeading","ListItemOpenTrigger","createListItemScope","createListScope","useListContext","useListItemContext"],"entryPoint":"packages/ui/primitives/react-list/src/index.ts","inputs":{"packages/ui/primitives/react-list/src/List.tsx":{"bytesInOutput":1120},"packages/ui/primitives/react-list/src/index.ts":{"bytesInOutput":0},"packages/ui/primitives/react-list/src/ListItem.tsx":{"bytesInOutput":2852}},"bytes":4328}}}
|