@kaizen/components 1.80.2 → 1.80.3
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/codemods/README.md +12 -0
- package/codemods/renameV2ComponentImportsAndUsages/index.ts +19 -0
- package/codemods/renameV2ComponentImportsAndUsages/renameV2ComponentImportsAndUsages.spec.ts +390 -0
- package/codemods/renameV2ComponentImportsAndUsages/renameV2ComponentImportsAndUsages.ts +230 -0
- package/codemods/utils/index.ts +1 -0
- package/codemods/utils/updateJsxElementTagName.spec.ts +129 -0
- package/codemods/utils/updateJsxElementTagName.ts +56 -0
- package/codemods/utils/updateKaioImports.spec.ts +82 -0
- package/codemods/utils/updateKaioImports.ts +16 -7
- package/dist/cjs/src/__alpha__/SingleSelect/SingleSelect.cjs +69 -16
- package/dist/cjs/src/__alpha__/SingleSelect/context/SingleSelectContext.cjs +13 -0
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Popover/Popover.cjs +54 -0
- package/dist/cjs/src/__alpha__/SingleSelect/{SingleSelect.module.css.cjs → subcomponents/Popover/Popover.module.css.cjs} +1 -1
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePopoverPositioning.cjs +94 -0
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePositioningStyles.cjs +69 -0
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Popover/utils/useSupportsAnchorPositioning.cjs +12 -0
- package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Trigger/Trigger.cjs +41 -5
- package/dist/esm/src/__alpha__/SingleSelect/SingleSelect.mjs +60 -10
- package/dist/esm/src/__alpha__/SingleSelect/context/SingleSelectContext.mjs +10 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Popover/Popover.mjs +49 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Popover/Popover.module.css.mjs +4 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePopoverPositioning.mjs +92 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePositioningStyles.mjs +67 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Popover/utils/useSupportsAnchorPositioning.mjs +10 -0
- package/dist/esm/src/__alpha__/SingleSelect/subcomponents/Trigger/Trigger.mjs +43 -7
- package/dist/styles.css +43 -21
- package/dist/types/__alpha__/SingleSelect/SingleSelect.d.ts +7 -9
- package/dist/types/__alpha__/SingleSelect/context/SingleSelectContext.d.ts +12 -0
- package/dist/types/__alpha__/SingleSelect/context/index.d.ts +1 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/List/List.d.ts +2 -1
- package/dist/types/__alpha__/SingleSelect/subcomponents/ListItem/ListItem.d.ts +2 -1
- package/dist/types/__alpha__/SingleSelect/subcomponents/ListSection/ListSection.d.ts +2 -1
- package/dist/types/__alpha__/SingleSelect/subcomponents/Popover/Popover.d.ts +6 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/Popover/index.d.ts +1 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/Popover/utils/index.d.ts +2 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/Popover/utils/usePopoverPositioning.d.ts +4 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/Popover/utils/usePositioningStyles.d.ts +4 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/Popover/utils/useSupportsAnchorPositioning.d.ts +1 -0
- package/dist/types/__alpha__/SingleSelect/subcomponents/Trigger/Trigger.d.ts +2 -1
- package/dist/types/__alpha__/SingleSelect/subcomponents/index.d.ts +1 -0
- package/dist/types/__alpha__/SingleSelect/types.d.ts +45 -0
- package/package.json +4 -4
- package/src/__alpha__/SingleSelect/SingleSelect.tsx +79 -14
- package/src/__alpha__/SingleSelect/_docs/SingleSelect.mdx +5 -2
- package/src/__alpha__/SingleSelect/_docs/SingleSelect.spec.stories.tsx +100 -0
- package/src/__alpha__/SingleSelect/_docs/SingleSelect.stickersheet.stories.tsx +4 -4
- package/src/__alpha__/SingleSelect/_docs/SingleSelect.stories.tsx +21 -2
- package/src/__alpha__/SingleSelect/context/SingleSelectContext.tsx +21 -0
- package/src/__alpha__/SingleSelect/context/index.ts +1 -0
- package/src/__alpha__/SingleSelect/subcomponents/List/List.module.css +0 -1
- package/src/__alpha__/SingleSelect/subcomponents/List/List.tsx +2 -1
- package/src/__alpha__/SingleSelect/subcomponents/ListItem/ListItem.module.css +7 -0
- package/src/__alpha__/SingleSelect/subcomponents/ListItem/ListItem.tsx +2 -1
- package/src/__alpha__/SingleSelect/subcomponents/ListSection/ListSection.tsx +3 -1
- package/src/__alpha__/SingleSelect/subcomponents/Popover/Popover.module.css +24 -0
- package/src/__alpha__/SingleSelect/subcomponents/Popover/Popover.tsx +54 -0
- package/src/__alpha__/SingleSelect/subcomponents/Popover/index.ts +1 -0
- package/src/__alpha__/SingleSelect/subcomponents/Popover/utils/index.ts +2 -0
- package/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePopoverPositioning.ts +108 -0
- package/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePositioningStyles.ts +75 -0
- package/src/__alpha__/SingleSelect/subcomponents/Popover/utils/useSupportsAnchorPositioning.ts +13 -0
- package/src/__alpha__/SingleSelect/subcomponents/Trigger/Trigger.module.css +1 -0
- package/src/__alpha__/SingleSelect/subcomponents/Trigger/Trigger.tsx +29 -7
- package/src/__alpha__/SingleSelect/subcomponents/index.ts +1 -0
- package/src/__alpha__/SingleSelect/types.ts +58 -0
- package/dist/esm/src/__alpha__/SingleSelect/SingleSelect.module.css.mjs +0 -4
- package/src/__alpha__/SingleSelect/SingleSelect.module.css +0 -9
- package/src/__alpha__/SingleSelect/SingleSelect.spec.tsx +0 -26
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import ts from 'typescript'
|
|
2
|
+
import { parseJsx } from '../__tests__/utils'
|
|
3
|
+
import { updateJsxElementTagName, type ComponentRenameConfig } from './updateJsxElementTagName'
|
|
4
|
+
|
|
5
|
+
const componentRenameMap = new Map<string, ComponentRenameConfig>([
|
|
6
|
+
[
|
|
7
|
+
'Pancakes',
|
|
8
|
+
{
|
|
9
|
+
newName: 'Beer',
|
|
10
|
+
fromModule: '@kaizen/components/next',
|
|
11
|
+
toModule: '@kaizen/components',
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
['Bart', { newName: 'Bender', fromModule: '@kaizen/components', toModule: '@kaizen/components' }],
|
|
15
|
+
[
|
|
16
|
+
'EatMyShorts',
|
|
17
|
+
{ newName: 'MeatBags', fromModule: '@kaizen/components', toModule: '@kaizen/components' },
|
|
18
|
+
],
|
|
19
|
+
])
|
|
20
|
+
|
|
21
|
+
describe('updateJsxElementTagName()', () => {
|
|
22
|
+
const factory = ts.factory
|
|
23
|
+
|
|
24
|
+
it('should ignore nodes not in componentMap', () => {
|
|
25
|
+
const elem = factory.createJsxSelfClosingElement(
|
|
26
|
+
factory.createIdentifier('Cowabunga'),
|
|
27
|
+
undefined,
|
|
28
|
+
factory.createJsxAttributes([]),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const result = updateJsxElementTagName(factory, elem, 'Cowabunga', componentRenameMap)
|
|
32
|
+
|
|
33
|
+
expect(ts.isJsxSelfClosingElement(result)).toBe(true)
|
|
34
|
+
expect((result.tagName as ts.Identifier).text).toBe('Cowabunga')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('should update self closing tag', () => {
|
|
38
|
+
const elem = factory.createJsxSelfClosingElement(
|
|
39
|
+
factory.createIdentifier('Pancakes'),
|
|
40
|
+
undefined,
|
|
41
|
+
factory.createJsxAttributes([]),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
const result = updateJsxElementTagName(factory, elem, 'Beer', componentRenameMap)
|
|
45
|
+
|
|
46
|
+
expect(ts.isJsxSelfClosingElement(result)).toBe(true)
|
|
47
|
+
expect((result.tagName as ts.Identifier).text).toBe('Beer')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('should handle Component.SubComponent when in Component is found in componentMap', () => {
|
|
51
|
+
const source = `<Bart.Shorts />`
|
|
52
|
+
const sourceFile = parseJsx(source)
|
|
53
|
+
const statement = sourceFile.statements[0] as ts.ExpressionStatement
|
|
54
|
+
const elem = statement.expression as ts.JsxSelfClosingElement
|
|
55
|
+
|
|
56
|
+
const result = updateJsxElementTagName(factory, elem, 'ignored', componentRenameMap)
|
|
57
|
+
|
|
58
|
+
expect(ts.isJsxSelfClosingElement(result)).toBe(true)
|
|
59
|
+
expect(ts.isPropertyAccessExpression(result.tagName)).toBe(true)
|
|
60
|
+
|
|
61
|
+
const tagName = result.tagName as ts.PropertyAccessExpression
|
|
62
|
+
expect((tagName.expression as ts.Identifier).text).toBe('Bender')
|
|
63
|
+
expect(tagName.name.text).toBe('Shorts')
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('should ignore Component.SubComponent when in Component is not in componentMap', () => {
|
|
67
|
+
const source = `<Not.Here />`
|
|
68
|
+
const sourceFile = parseJsx(source)
|
|
69
|
+
const statement = sourceFile.statements[0] as ts.ExpressionStatement
|
|
70
|
+
const elem = statement.expression as ts.JsxSelfClosingElement
|
|
71
|
+
|
|
72
|
+
const result = updateJsxElementTagName(factory, elem, 'ignored', componentRenameMap)
|
|
73
|
+
|
|
74
|
+
expect(ts.isJsxSelfClosingElement(result)).toBe(true)
|
|
75
|
+
expect(ts.isPropertyAccessExpression(result.tagName)).toBe(true)
|
|
76
|
+
|
|
77
|
+
const tagName = result.tagName as ts.PropertyAccessExpression
|
|
78
|
+
expect((tagName.expression as ts.Identifier).text).toBe('Not')
|
|
79
|
+
expect(tagName.name.text).toBe('Here')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('should update JSX opening element tag name', () => {
|
|
83
|
+
const openingElement = factory.createJsxOpeningElement(
|
|
84
|
+
factory.createIdentifier('Pancakes'),
|
|
85
|
+
undefined,
|
|
86
|
+
factory.createJsxAttributes([]),
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
const result = updateJsxElementTagName(factory, openingElement, 'Pizza', componentRenameMap)
|
|
90
|
+
|
|
91
|
+
expect(ts.isJsxOpeningElement(result)).toBe(true)
|
|
92
|
+
expect((result.tagName as ts.Identifier).text).toBe('Pizza')
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('should update JSX closing element tag name', () => {
|
|
96
|
+
const closingElement = factory.createJsxClosingElement(factory.createIdentifier('EatMyShorts'))
|
|
97
|
+
|
|
98
|
+
const result = updateJsxElementTagName(factory, closingElement, 'MeatBags', componentRenameMap)
|
|
99
|
+
|
|
100
|
+
expect(ts.isJsxClosingElement(result)).toBe(true)
|
|
101
|
+
expect((result.tagName as ts.Identifier).text).toBe('MeatBags')
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('should preserve attributes when updating JSX elements', () => {
|
|
105
|
+
const attributes = factory.createJsxAttributes([
|
|
106
|
+
factory.createJsxAttribute(
|
|
107
|
+
factory.createIdentifier('className'),
|
|
108
|
+
factory.createStringLiteral('test-class'),
|
|
109
|
+
),
|
|
110
|
+
])
|
|
111
|
+
|
|
112
|
+
const element = factory.createJsxSelfClosingElement(
|
|
113
|
+
factory.createIdentifier('Pancakes'),
|
|
114
|
+
undefined,
|
|
115
|
+
attributes,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
const result = updateJsxElementTagName(factory, element, 'Pizza', componentRenameMap)
|
|
119
|
+
|
|
120
|
+
expect(ts.isJsxSelfClosingElement(result)).toBe(true)
|
|
121
|
+
expect((result.tagName as ts.Identifier).text).toBe('Pizza')
|
|
122
|
+
expect((result as ts.JsxSelfClosingElement).attributes.properties.length).toBe(1)
|
|
123
|
+
|
|
124
|
+
const attribute = (result as ts.JsxSelfClosingElement).attributes
|
|
125
|
+
.properties[0] as ts.JsxAttribute
|
|
126
|
+
expect((attribute.name as ts.Identifier).text).toBe('className')
|
|
127
|
+
expect((attribute.initializer as ts.StringLiteral).text).toBe('test-class')
|
|
128
|
+
})
|
|
129
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import ts from 'typescript'
|
|
2
|
+
|
|
3
|
+
export type ComponentRenameConfig = {
|
|
4
|
+
newName: string
|
|
5
|
+
fromModule: string
|
|
6
|
+
toModule: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const updateJsxElementTagName = (
|
|
10
|
+
factory: ts.NodeFactory,
|
|
11
|
+
node: ts.JsxOpeningElement | ts.JsxClosingElement | ts.JsxSelfClosingElement,
|
|
12
|
+
newTagName: string,
|
|
13
|
+
componentRenameMap: Map<string, ComponentRenameConfig>,
|
|
14
|
+
): ts.JsxOpeningElement | ts.JsxClosingElement | ts.JsxSelfClosingElement => {
|
|
15
|
+
let newTagNameExpr: ts.JsxTagNameExpression
|
|
16
|
+
|
|
17
|
+
if (ts.isPropertyAccessExpression(node.tagName)) {
|
|
18
|
+
const baseComponentName = node.tagName.expression.getText()
|
|
19
|
+
const rename = componentRenameMap.get(baseComponentName)
|
|
20
|
+
|
|
21
|
+
if (rename) {
|
|
22
|
+
newTagNameExpr = factory.createPropertyAccessExpression(
|
|
23
|
+
factory.createIdentifier(rename.newName),
|
|
24
|
+
node.tagName.name,
|
|
25
|
+
) as ts.JsxTagNameExpression
|
|
26
|
+
} else {
|
|
27
|
+
newTagNameExpr = node.tagName
|
|
28
|
+
}
|
|
29
|
+
} else {
|
|
30
|
+
newTagNameExpr = factory.createIdentifier(newTagName)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (ts.isJsxSelfClosingElement(node)) {
|
|
34
|
+
return factory.updateJsxSelfClosingElement(
|
|
35
|
+
node,
|
|
36
|
+
newTagNameExpr,
|
|
37
|
+
node.typeArguments,
|
|
38
|
+
node.attributes,
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (ts.isJsxOpeningElement(node)) {
|
|
43
|
+
return factory.updateJsxOpeningElement(
|
|
44
|
+
node,
|
|
45
|
+
newTagNameExpr,
|
|
46
|
+
node.typeArguments,
|
|
47
|
+
node.attributes,
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (ts.isJsxClosingElement(node)) {
|
|
52
|
+
return factory.updateJsxClosingElement(node, newTagNameExpr)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return node
|
|
56
|
+
}
|
|
@@ -200,6 +200,88 @@ describe('updateKaioImports()', () => {
|
|
|
200
200
|
}),
|
|
201
201
|
).toEqual(printAst(outputAst))
|
|
202
202
|
})
|
|
203
|
+
|
|
204
|
+
describe('type-only imports', () => {
|
|
205
|
+
it('creates a new type-only import declaration', () => {
|
|
206
|
+
const inputAst = parseJsx(`
|
|
207
|
+
import { Well } from "@kaizen/components"
|
|
208
|
+
`)
|
|
209
|
+
const outputAst = parseJsx(`
|
|
210
|
+
import { Well } from "@kaizen/components"
|
|
211
|
+
import type { Card } from "@kaizen/components/next"
|
|
212
|
+
`)
|
|
213
|
+
expect(
|
|
214
|
+
transformInput(inputAst)({
|
|
215
|
+
importsToAdd: new Map([
|
|
216
|
+
[
|
|
217
|
+
'@kaizen/components/next',
|
|
218
|
+
new Map([['Card', { componentName: 'Card', isTypeOnly: true }]]),
|
|
219
|
+
],
|
|
220
|
+
]),
|
|
221
|
+
}),
|
|
222
|
+
).toEqual(printAst(outputAst))
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
it('adds type-only import to existing regular imports', () => {
|
|
226
|
+
const inputAst = parseJsx(`
|
|
227
|
+
import { Select } from "@kaizen/components/next"
|
|
228
|
+
`)
|
|
229
|
+
const outputAst = parseJsx(`
|
|
230
|
+
import { Select, type Card } from "@kaizen/components/next"
|
|
231
|
+
`)
|
|
232
|
+
expect(
|
|
233
|
+
transformInput(inputAst)({
|
|
234
|
+
importsToAdd: new Map([
|
|
235
|
+
[
|
|
236
|
+
'@kaizen/components/next',
|
|
237
|
+
new Map([['Card', { componentName: 'Card', isTypeOnly: true }]]),
|
|
238
|
+
],
|
|
239
|
+
]),
|
|
240
|
+
}),
|
|
241
|
+
).toEqual(printAst(outputAst))
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it('adds type-only import to existing type-only imports', () => {
|
|
245
|
+
const inputAst = parseJsx(`
|
|
246
|
+
import type { CardProps } from "@kaizen/components/next"
|
|
247
|
+
`)
|
|
248
|
+
const outputAst = parseJsx(`
|
|
249
|
+
import type { CardProps, type ButtonProps } from "@kaizen/components/next"
|
|
250
|
+
`)
|
|
251
|
+
expect(
|
|
252
|
+
transformInput(inputAst)({
|
|
253
|
+
importsToAdd: new Map([
|
|
254
|
+
[
|
|
255
|
+
'@kaizen/components/next',
|
|
256
|
+
new Map([['ButtonProps', { componentName: 'ButtonProps', isTypeOnly: true }]]),
|
|
257
|
+
],
|
|
258
|
+
]),
|
|
259
|
+
}),
|
|
260
|
+
).toEqual(printAst(outputAst))
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
it('adds mix of type-only and regular imports', () => {
|
|
264
|
+
const inputAst = parseJsx(`
|
|
265
|
+
import { Select } from "@kaizen/components/next"
|
|
266
|
+
`)
|
|
267
|
+
const outputAst = parseJsx(`
|
|
268
|
+
import { Select, type CardProps, Button } from "@kaizen/components/next"
|
|
269
|
+
`)
|
|
270
|
+
expect(
|
|
271
|
+
transformInput(inputAst)({
|
|
272
|
+
importsToAdd: new Map([
|
|
273
|
+
[
|
|
274
|
+
'@kaizen/components/next',
|
|
275
|
+
new Map([
|
|
276
|
+
['CardProps', { componentName: 'CardProps', isTypeOnly: true }],
|
|
277
|
+
['Button', { componentName: 'Button', isTypeOnly: false }],
|
|
278
|
+
]),
|
|
279
|
+
],
|
|
280
|
+
]),
|
|
281
|
+
}),
|
|
282
|
+
).toEqual(printAst(outputAst))
|
|
283
|
+
})
|
|
284
|
+
})
|
|
203
285
|
})
|
|
204
286
|
})
|
|
205
287
|
})
|
|
@@ -34,7 +34,7 @@ const removeNamedImports = (
|
|
|
34
34
|
return node
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
type NewImportAttributes = { componentName: string; alias?: string }
|
|
37
|
+
type NewImportAttributes = { componentName: string; alias?: string; isTypeOnly?: boolean }
|
|
38
38
|
type ImportsToAdd = Map<string, NewImportAttributes>
|
|
39
39
|
|
|
40
40
|
const createImportDeclaration = (
|
|
@@ -42,9 +42,12 @@ const createImportDeclaration = (
|
|
|
42
42
|
importsToAdd: ImportsToAdd,
|
|
43
43
|
moduleSpecifier: string,
|
|
44
44
|
): ts.ImportDeclaration => {
|
|
45
|
-
const
|
|
45
|
+
const imports = Array.from(importsToAdd.values())
|
|
46
|
+
const allTypeOnly = imports.every(({ isTypeOnly }) => isTypeOnly)
|
|
47
|
+
|
|
48
|
+
const namedImports = imports.map(({ componentName, alias, isTypeOnly }) =>
|
|
46
49
|
factory.createImportSpecifier(
|
|
47
|
-
false,
|
|
50
|
+
allTypeOnly ? false : (isTypeOnly ?? false),
|
|
48
51
|
alias ? factory.createIdentifier(componentName) : undefined,
|
|
49
52
|
factory.createIdentifier(alias ?? componentName),
|
|
50
53
|
),
|
|
@@ -52,7 +55,7 @@ const createImportDeclaration = (
|
|
|
52
55
|
|
|
53
56
|
return factory.createImportDeclaration(
|
|
54
57
|
undefined,
|
|
55
|
-
factory.createImportClause(
|
|
58
|
+
factory.createImportClause(allTypeOnly, undefined, factory.createNamedImports(namedImports)),
|
|
56
59
|
factory.createStringLiteral(moduleSpecifier),
|
|
57
60
|
)
|
|
58
61
|
}
|
|
@@ -75,9 +78,13 @@ const updateNamedImports = (
|
|
|
75
78
|
})
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
Array.from(importsToAdd.values())
|
|
81
|
+
const newImports = Array.from(importsToAdd.values())
|
|
82
|
+
const allNewTypeOnly = newImports.every(({ isTypeOnly }) => isTypeOnly)
|
|
83
|
+
const hasExistingImports = importSpecifiers.length > 0
|
|
84
|
+
|
|
85
|
+
newImports.forEach(({ alias, componentName, isTypeOnly }) => {
|
|
79
86
|
const newImport = factory.createImportSpecifier(
|
|
80
|
-
false,
|
|
87
|
+
!allNewTypeOnly || hasExistingImports ? (isTypeOnly ?? false) : false,
|
|
81
88
|
alias ? factory.createIdentifier(componentName) : undefined,
|
|
82
89
|
factory.createIdentifier(alias ?? componentName),
|
|
83
90
|
)
|
|
@@ -87,12 +94,14 @@ const updateNamedImports = (
|
|
|
87
94
|
}
|
|
88
95
|
})
|
|
89
96
|
|
|
97
|
+
const isModuleLevelTypeOnly = allNewTypeOnly && !hasExistingImports
|
|
98
|
+
|
|
90
99
|
return factory.updateImportDeclaration(
|
|
91
100
|
node,
|
|
92
101
|
node.modifiers,
|
|
93
102
|
factory.updateImportClause(
|
|
94
103
|
node.importClause,
|
|
95
|
-
node.importClause.isTypeOnly,
|
|
104
|
+
isModuleLevelTypeOnly || node.importClause.isTypeOnly,
|
|
96
105
|
node.importClause.name,
|
|
97
106
|
factory.createNamedImports(importSpecifiers),
|
|
98
107
|
),
|
|
@@ -2,31 +2,84 @@
|
|
|
2
2
|
|
|
3
3
|
var tslib = require('tslib');
|
|
4
4
|
var React = require('react');
|
|
5
|
+
var select = require('@react-stately/select');
|
|
5
6
|
var reactAriaComponents = require('react-aria-components');
|
|
7
|
+
var SingleSelectContext = require('./context/SingleSelectContext.cjs');
|
|
6
8
|
var List = require('./subcomponents/List/List.cjs');
|
|
7
9
|
var ListSection = require('./subcomponents/ListSection/ListSection.cjs');
|
|
8
10
|
var ListItem = require('./subcomponents/ListItem/ListItem.cjs');
|
|
9
11
|
var Trigger = require('./subcomponents/Trigger/Trigger.cjs');
|
|
10
|
-
var
|
|
12
|
+
var Popover = require('./subcomponents/Popover/Popover.cjs');
|
|
11
13
|
function _interopDefault(e) {
|
|
12
14
|
return e && e.__esModule ? e : {
|
|
13
15
|
default: e
|
|
14
16
|
};
|
|
15
17
|
}
|
|
16
18
|
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
19
|
+
const SingleSelect = /*#__PURE__*/function () {
|
|
20
|
+
const SingleSelect = function (_a) {
|
|
21
|
+
var items = _a.items,
|
|
22
|
+
onSelectionChange = _a.onSelectionChange,
|
|
23
|
+
children = _a.children,
|
|
24
|
+
restProps = tslib.__rest(_a, ["items", "onSelectionChange", "children"]);
|
|
25
|
+
var buttonRef = React__default.default.useRef(null);
|
|
26
|
+
var popoverRef = React__default.default.useRef(null);
|
|
27
|
+
var racPopoverRef = React__default.default.useRef(null);
|
|
28
|
+
var uniqueId = React.useId();
|
|
29
|
+
var anchorName = "--trigger-".concat(uniqueId);
|
|
30
|
+
var state = select.useSelectState({
|
|
31
|
+
items: items
|
|
32
|
+
});
|
|
33
|
+
var handleOnSelectionChange = React__default.default.useCallback(function (keys) {
|
|
34
|
+
var key = null;
|
|
35
|
+
if (keys instanceof Set && keys.size > 0) {
|
|
36
|
+
key = Array.from(keys)[0];
|
|
37
|
+
}
|
|
38
|
+
state.setSelectedKey(key);
|
|
39
|
+
if (onSelectionChange) {
|
|
40
|
+
onSelectionChange(key);
|
|
41
|
+
}
|
|
42
|
+
}, [state, onSelectionChange]);
|
|
43
|
+
// Cloning children here to allow users to pass in a custom ListItem or ListSection
|
|
44
|
+
// and still have the SingleSelect handle selection state
|
|
45
|
+
var injectedChildren = React.useMemo(function () {
|
|
46
|
+
if (!React.isValidElement(children)) return null;
|
|
47
|
+
var selectedKeys = state.selectedKey ? new Set([state.selectedKey]) : new Set();
|
|
48
|
+
return React.cloneElement(children, {
|
|
49
|
+
selectionMode: 'single',
|
|
50
|
+
selectedKeys: selectedKeys,
|
|
51
|
+
onSelectionChange: handleOnSelectionChange,
|
|
52
|
+
autoFocus: 'first'
|
|
53
|
+
});
|
|
54
|
+
}, [children, handleOnSelectionChange, state.selectedKey]);
|
|
55
|
+
return React__default.default.createElement(SingleSelectContext.SingleSelectContext.Provider, {
|
|
56
|
+
value: {
|
|
57
|
+
isOpen: state.isOpen,
|
|
58
|
+
setOpen: state.setOpen,
|
|
59
|
+
selectedKey: state.selectedKey,
|
|
60
|
+
items: items,
|
|
61
|
+
anchorName: anchorName
|
|
62
|
+
}
|
|
63
|
+
}, React__default.default.createElement(reactAriaComponents.Select
|
|
64
|
+
// TODO: allow user to pass in label
|
|
65
|
+
, tslib.__assign({
|
|
66
|
+
"aria-label": 'single-select',
|
|
67
|
+
onSelectionChange: function (key) {
|
|
68
|
+
return handleOnSelectionChange(key != null ? new Set([key]) : new Set());
|
|
69
|
+
},
|
|
70
|
+
placeholder: ""
|
|
71
|
+
}, restProps), React__default.default.createElement(Trigger.Trigger, {
|
|
72
|
+
buttonRef: buttonRef
|
|
73
|
+
}), state.isOpen && React__default.default.createElement(Popover.Popover, {
|
|
74
|
+
buttonRef: buttonRef,
|
|
75
|
+
popoverRef: popoverRef,
|
|
76
|
+
racPopoverRef: racPopoverRef
|
|
77
|
+
}, injectedChildren)));
|
|
78
|
+
};
|
|
79
|
+
SingleSelect.displayName = 'SingleSelect';
|
|
80
|
+
SingleSelect.List = List.List;
|
|
81
|
+
SingleSelect.ListItem = ListItem.ListItem;
|
|
82
|
+
SingleSelect.ListSection = ListSection.ListSection;
|
|
83
|
+
return SingleSelect;
|
|
84
|
+
}();
|
|
32
85
|
exports.SingleSelect = SingleSelect;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var SingleSelectContext = React.createContext(undefined);
|
|
5
|
+
var useSingleSelectContext = function () {
|
|
6
|
+
var context = React.useContext(SingleSelectContext);
|
|
7
|
+
if (!context) {
|
|
8
|
+
throw new Error('useSingleSelectContext must be used within a SingleSelectContext.Provider');
|
|
9
|
+
}
|
|
10
|
+
return context;
|
|
11
|
+
};
|
|
12
|
+
exports.SingleSelectContext = SingleSelectContext;
|
|
13
|
+
exports.useSingleSelectContext = useSingleSelectContext;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var reactAriaComponents = require('react-aria-components');
|
|
5
|
+
var SingleSelectContext = require('../../context/SingleSelectContext.cjs');
|
|
6
|
+
var usePositioningStyles = require('./utils/usePositioningStyles.cjs');
|
|
7
|
+
var Popover_module = require('./Popover.module.css.cjs');
|
|
8
|
+
function _interopDefault(e) {
|
|
9
|
+
return e && e.__esModule ? e : {
|
|
10
|
+
default: e
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
14
|
+
var Popover = function (_a) {
|
|
15
|
+
var buttonRef = _a.buttonRef,
|
|
16
|
+
popoverRef = _a.popoverRef,
|
|
17
|
+
racPopoverRef = _a.racPopoverRef,
|
|
18
|
+
children = _a.children;
|
|
19
|
+
var _b = SingleSelectContext.useSingleSelectContext(),
|
|
20
|
+
isOpen = _b.isOpen,
|
|
21
|
+
setOpen = _b.setOpen,
|
|
22
|
+
anchorName = _b.anchorName;
|
|
23
|
+
var _c = usePositioningStyles.usePositioningStyles(buttonRef, popoverRef, anchorName),
|
|
24
|
+
popoverStyle = _c.popoverStyle,
|
|
25
|
+
isPositioned = _c.isPositioned;
|
|
26
|
+
var shouldShowPopover = React.useMemo(function () {
|
|
27
|
+
return isOpen && isPositioned;
|
|
28
|
+
}, [isOpen, isPositioned]);
|
|
29
|
+
React.useLayoutEffect(function () {
|
|
30
|
+
var popover = popoverRef.current;
|
|
31
|
+
if (!(popover === null || popover === void 0 ? void 0 : popover.showPopover) || !(popover === null || popover === void 0 ? void 0 : popover.hidePopover)) return;
|
|
32
|
+
if (shouldShowPopover) {
|
|
33
|
+
popover.showPopover();
|
|
34
|
+
} else {
|
|
35
|
+
popover.hidePopover();
|
|
36
|
+
}
|
|
37
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
38
|
+
}, [shouldShowPopover]);
|
|
39
|
+
return React__default.default.createElement(reactAriaComponents.Popover, {
|
|
40
|
+
shouldUpdatePosition: false,
|
|
41
|
+
trigger: "manual",
|
|
42
|
+
isOpen: isOpen,
|
|
43
|
+
onOpenChange: setOpen,
|
|
44
|
+
ref: racPopoverRef
|
|
45
|
+
}, React__default.default.createElement("div", {
|
|
46
|
+
// @ts-expect-error - popover attribute is not included in current ts version, ignore type error
|
|
47
|
+
popover: "manual",
|
|
48
|
+
ref: popoverRef,
|
|
49
|
+
className: Popover_module.popover,
|
|
50
|
+
style: popoverStyle
|
|
51
|
+
}, children));
|
|
52
|
+
};
|
|
53
|
+
Popover.displayName = 'SingleSelect.Popover';
|
|
54
|
+
exports.Popover = Popover;
|
package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePopoverPositioning.cjs
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tslib = require('tslib');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
function usePopoverPositioning(_a) {
|
|
6
|
+
var triggerRef = _a.triggerRef,
|
|
7
|
+
popoverRef = _a.popoverRef,
|
|
8
|
+
_b = _a.direction,
|
|
9
|
+
direction = _b === void 0 ? 'ltr' : _b,
|
|
10
|
+
_c = _a.offset,
|
|
11
|
+
offset = _c === void 0 ? 4 : _c,
|
|
12
|
+
_d = _a.preferredPlacement,
|
|
13
|
+
preferredPlacement = _d === void 0 ? 'bottom' : _d;
|
|
14
|
+
var _e = React.useState({
|
|
15
|
+
top: preferredPlacement === 'bottom' ? offset : 'auto',
|
|
16
|
+
bottom: preferredPlacement === 'top' ? offset : 'auto',
|
|
17
|
+
insetInlineStart: 0,
|
|
18
|
+
maxHeight: 300 // TODO: update this based on designs
|
|
19
|
+
}),
|
|
20
|
+
position = _e[0],
|
|
21
|
+
setPosition = _e[1];
|
|
22
|
+
var _f = React.useState(true),
|
|
23
|
+
isPositioned = _f[0],
|
|
24
|
+
setIsPositioned = _f[1];
|
|
25
|
+
var mountedRef = React.useRef(false);
|
|
26
|
+
var isSSR = typeof window === 'undefined';
|
|
27
|
+
var updatePosition = React.useCallback(function () {
|
|
28
|
+
var _a;
|
|
29
|
+
if (isSSR) return;
|
|
30
|
+
var trigger = triggerRef.current;
|
|
31
|
+
var popover = popoverRef.current;
|
|
32
|
+
if (!mountedRef.current || !trigger || !(popover === null || popover === void 0 ? void 0 : popover.isConnected)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
var triggerRect = trigger.getBoundingClientRect();
|
|
36
|
+
if (!triggerRect) return;
|
|
37
|
+
var doc = trigger.ownerDocument;
|
|
38
|
+
var win = (_a = doc === null || doc === void 0 ? void 0 : doc.defaultView) !== null && _a !== void 0 ? _a : window;
|
|
39
|
+
var isRTL = direction === 'rtl';
|
|
40
|
+
var inlineStart = isRTL ? win.innerWidth - triggerRect.right : triggerRect.left;
|
|
41
|
+
var triggerTop = triggerRect.top;
|
|
42
|
+
var triggerBottom = triggerRect.bottom;
|
|
43
|
+
var viewportHeight = win.innerHeight;
|
|
44
|
+
var spaceAbove = triggerTop;
|
|
45
|
+
var spaceBelow = viewportHeight - triggerBottom;
|
|
46
|
+
var shouldFlip = preferredPlacement === 'bottom' && spaceBelow < 200 && spaceAbove > spaceBelow;
|
|
47
|
+
var top;
|
|
48
|
+
var bottom;
|
|
49
|
+
var maxHeight;
|
|
50
|
+
if (shouldFlip) {
|
|
51
|
+
top = 'auto';
|
|
52
|
+
bottom = viewportHeight - triggerTop + offset;
|
|
53
|
+
maxHeight = Math.max(0, spaceAbove - offset);
|
|
54
|
+
} else {
|
|
55
|
+
top = triggerBottom + offset;
|
|
56
|
+
bottom = 'auto';
|
|
57
|
+
maxHeight = Math.max(0, spaceBelow - offset);
|
|
58
|
+
}
|
|
59
|
+
var newPosition = {
|
|
60
|
+
top: top,
|
|
61
|
+
bottom: bottom,
|
|
62
|
+
insetInlineStart: inlineStart,
|
|
63
|
+
maxHeight: maxHeight
|
|
64
|
+
};
|
|
65
|
+
setPosition(newPosition);
|
|
66
|
+
setIsPositioned(true);
|
|
67
|
+
}, [triggerRef, popoverRef, direction, offset, preferredPlacement, isSSR]);
|
|
68
|
+
React.useEffect(function () {
|
|
69
|
+
if (typeof window === 'undefined') return;
|
|
70
|
+
mountedRef.current = true;
|
|
71
|
+
var triggerEl = triggerRef.current;
|
|
72
|
+
updatePosition();
|
|
73
|
+
var resizeObserver = new ResizeObserver(function () {
|
|
74
|
+
updatePosition();
|
|
75
|
+
});
|
|
76
|
+
if (triggerEl) resizeObserver.observe(triggerEl);
|
|
77
|
+
var onWindowResize = function () {
|
|
78
|
+
return updatePosition();
|
|
79
|
+
};
|
|
80
|
+
window.addEventListener('resize', onWindowResize, {
|
|
81
|
+
passive: true
|
|
82
|
+
});
|
|
83
|
+
return function () {
|
|
84
|
+
mountedRef.current = false;
|
|
85
|
+
resizeObserver.disconnect();
|
|
86
|
+
window.removeEventListener('resize', onWindowResize);
|
|
87
|
+
setIsPositioned(false);
|
|
88
|
+
};
|
|
89
|
+
}, [updatePosition, triggerRef]);
|
|
90
|
+
return tslib.__assign(tslib.__assign({}, position), {
|
|
91
|
+
isPositioned: isPositioned
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
exports.usePopoverPositioning = usePopoverPositioning;
|
package/dist/cjs/src/__alpha__/SingleSelect/subcomponents/Popover/utils/usePositioningStyles.cjs
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var i18n = require('@react-aria/i18n');
|
|
5
|
+
var usePopoverPositioning = require('./usePopoverPositioning.cjs');
|
|
6
|
+
var useSupportsAnchorPositioning = require('./useSupportsAnchorPositioning.cjs');
|
|
7
|
+
var CSS_PROPS = {
|
|
8
|
+
POSITION_ANCHOR: '--position-anchor',
|
|
9
|
+
POSITION_AREA: '--position-area'
|
|
10
|
+
};
|
|
11
|
+
var DEFAULTS = {
|
|
12
|
+
MAX_HEIGHT: '300px'
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Generates manual positioning styles for browsers without anchor positioning support or SSR
|
|
16
|
+
*/
|
|
17
|
+
var getManualPositioningStyles = function (positionData) {
|
|
18
|
+
return {
|
|
19
|
+
top: positionData.top,
|
|
20
|
+
bottom: positionData.bottom,
|
|
21
|
+
insetInlineStart: positionData.insetInlineStart,
|
|
22
|
+
maxHeight: positionData.maxHeight,
|
|
23
|
+
left: 'auto',
|
|
24
|
+
right: 'auto',
|
|
25
|
+
position: 'fixed'
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
var getAnchorPositioningStyles = function (anchorName, positionData) {
|
|
29
|
+
var _a;
|
|
30
|
+
var _b;
|
|
31
|
+
var styles = (_a = {
|
|
32
|
+
maxHeight: (_b = positionData.maxHeight) !== null && _b !== void 0 ? _b : DEFAULTS.MAX_HEIGHT
|
|
33
|
+
}, _a[CSS_PROPS.POSITION_ANCHOR] = anchorName, _a[CSS_PROPS.POSITION_AREA] = positionData.top === 'auto' ? 'top' : 'bottom', _a);
|
|
34
|
+
return styles;
|
|
35
|
+
};
|
|
36
|
+
var usePositioningStyles = function (buttonRef, popoverRef, anchorName) {
|
|
37
|
+
var direction = i18n.useLocale().direction;
|
|
38
|
+
var hasAnchorSupport = useSupportsAnchorPositioning.useSupportsAnchorPositioning();
|
|
39
|
+
var _a = usePopoverPositioning.usePopoverPositioning({
|
|
40
|
+
triggerRef: buttonRef,
|
|
41
|
+
popoverRef: popoverRef,
|
|
42
|
+
direction: direction,
|
|
43
|
+
preferredPlacement: 'bottom'
|
|
44
|
+
}),
|
|
45
|
+
top = _a.top,
|
|
46
|
+
bottom = _a.bottom,
|
|
47
|
+
insetInlineStart = _a.insetInlineStart,
|
|
48
|
+
maxHeight = _a.maxHeight,
|
|
49
|
+
isPositioned = _a.isPositioned;
|
|
50
|
+
var positionData = React.useMemo(function () {
|
|
51
|
+
return {
|
|
52
|
+
top: top,
|
|
53
|
+
bottom: bottom,
|
|
54
|
+
insetInlineStart: insetInlineStart,
|
|
55
|
+
maxHeight: maxHeight
|
|
56
|
+
};
|
|
57
|
+
}, [top, bottom, insetInlineStart, maxHeight]);
|
|
58
|
+
var popoverStyle = React.useMemo(function () {
|
|
59
|
+
if (hasAnchorSupport === null || !hasAnchorSupport) {
|
|
60
|
+
return getManualPositioningStyles(positionData);
|
|
61
|
+
}
|
|
62
|
+
return getAnchorPositioningStyles(anchorName, positionData);
|
|
63
|
+
}, [hasAnchorSupport, anchorName, positionData]);
|
|
64
|
+
return {
|
|
65
|
+
popoverStyle: popoverStyle,
|
|
66
|
+
isPositioned: isPositioned
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
exports.usePositioningStyles = usePositioningStyles;
|