@primer/components 33.0.0-rc.b495ba4a → 33.1.0-rc.6856bcf5
Sign up to get free protection for your applications and to get access to all the features.
- package/.devcontainer/devcontainer.json +1 -1
- package/.github/workflows/ci.yml +1 -1
- package/.github/workflows/release.yml +6 -27
- package/.github/workflows/release_canary.yml +4 -60
- package/.github/workflows/release_candidate.yml +5 -51
- package/.github/workflows/statuses.yml +32 -0
- package/.gitignore +1 -0
- package/.nvmrc +1 -1
- package/CHANGELOG.md +20 -0
- package/contributor-docs/CONTRIBUTING.md +14 -61
- package/dist/browser.esm.js +2 -2209
- package/dist/browser.esm.js.map +1 -1
- package/dist/browser.umd.js +2 -2209
- package/dist/browser.umd.js.map +1 -1
- package/docs/content/AnchoredOverlay.mdx +121 -1
- package/docs/content/Avatar.mdx +29 -14
- package/docs/content/AvatarPair.mdx +47 -0
- package/docs/content/AvatarStack.mdx +14 -6
- package/docs/content/Box.mdx +13 -11
- package/docs/content/BranchName.mdx +52 -0
- package/docs/content/{Breadcrumbs.md → Breadcrumbs.mdx} +21 -13
- package/docs/content/Link.mdx +75 -0
- package/docs/content/Radio.md +90 -0
- package/docs/content/TextInput.mdx +125 -0
- package/docs/content/drafts/ActionList2.mdx +484 -0
- package/docs/content/drafts/ActionMenu2.mdx +302 -0
- package/docs/src/@primer/gatsby-theme-doctocat/live-code-scope.js +9 -1
- package/docs/src/@primer/gatsby-theme-doctocat/mdx-components.js +15 -2
- package/docs/src/@primer/gatsby-theme-doctocat/nav.yml +4 -0
- package/docs/src/component-checklist.js +10 -2
- package/docs/src/props-table.js +165 -0
- package/docs/src/props.js +14 -28
- package/lib/ActionList/Header.js +1 -1
- package/lib/ActionList/Item.js +10 -10
- package/lib/ActionList/List.js +1 -1
- package/lib/ActionList2/ActionListContainerContext.d.ts +10 -0
- package/lib/ActionList2/ActionListContainerContext.js +15 -0
- package/lib/ActionList2/Divider.d.ts +3 -2
- package/lib/ActionList2/Divider.js +10 -5
- package/lib/ActionList2/Item.js +22 -8
- package/lib/ActionList2/List.js +12 -2
- package/lib/ActionList2/Selection.js +11 -0
- package/lib/ActionList2/index.d.ts +1 -2
- package/lib/ActionMenu2.d.ts +317 -0
- package/lib/ActionMenu2.js +125 -0
- package/lib/Autocomplete/Autocomplete.d.ts +2 -1
- package/lib/Autocomplete/AutocompleteInput.d.ts +2 -1
- package/lib/BaseStyles.js +2 -20
- package/lib/BorderBox.js +1 -1
- package/lib/Box.js +1 -1
- package/lib/BranchName.js +1 -1
- package/lib/Breadcrumbs.js +3 -3
- package/lib/Button/Button.d.ts +2 -2
- package/lib/Button/Button.js +1 -1
- package/lib/Button/ButtonClose.d.ts +2 -2
- package/lib/Button/ButtonDanger.d.ts +2 -2
- package/lib/Button/ButtonGroup.js +1 -1
- package/lib/Button/ButtonInvisible.d.ts +2 -2
- package/lib/Button/ButtonOutline.d.ts +2 -2
- package/lib/Button/ButtonPrimary.d.ts +2 -2
- package/lib/Checkbox.d.ts +1 -1
- package/lib/Checkbox.js +1 -1
- package/lib/CircleOcticon.d.ts +35 -35
- package/lib/Details.js +1 -1
- package/lib/Dialog.d.ts +37 -37
- package/lib/Dropdown.d.ts +6 -6
- package/lib/DropdownMenu/DropdownButton.d.ts +6 -3
- package/lib/FilterList.d.ts +1 -1
- package/lib/FilteredActionList/FilteredActionList.js +1 -1
- package/lib/Flex.js +1 -1
- package/lib/LabelGroup.js +1 -1
- package/lib/Overlay.js +1 -1
- package/lib/Pagination/Pagination.js +2 -2
- package/lib/Position.d.ts +4 -4
- package/lib/Position.js +1 -1
- package/lib/Radio.d.ts +38 -0
- package/lib/Radio.js +55 -0
- package/lib/SelectMenu/SelectMenu.d.ts +11 -10
- package/lib/SelectMenu/SelectMenu.js +1 -1
- package/lib/SelectMenu/SelectMenuFilter.js +1 -1
- package/lib/SelectMenu/SelectMenuFooter.js +1 -1
- package/lib/SelectMenu/SelectMenuItem.d.ts +1 -1
- package/lib/SelectMenu/SelectMenuItem.js +1 -1
- package/lib/SelectMenu/SelectMenuModal.d.ts +1 -1
- package/lib/SelectMenu/SelectMenuTab.js +1 -1
- package/lib/SelectMenu/SelectMenuTabPanel.js +1 -1
- package/lib/SelectMenu/SelectMenuTabs.js +1 -1
- package/lib/StateLabel.js +1 -1
- package/lib/StyledOcticon.js +1 -1
- package/lib/SubNav.js +3 -3
- package/lib/TextInputWithTokens.d.ts +2 -1
- package/lib/ThemeProvider.d.ts +1 -0
- package/lib/ThemeProvider.js +17 -4
- package/lib/Timeline.js +4 -4
- package/lib/Token/AvatarToken.d.ts +1 -1
- package/lib/Token/AvatarToken.js +1 -1
- package/lib/Token/IssueLabelToken.d.ts +1 -1
- package/lib/Token/Token.d.ts +1 -1
- package/lib/Token/TokenBase.js +1 -1
- package/lib/Tooltip.js +1 -1
- package/lib/UnderlineNav.js +2 -2
- package/lib/__tests__/Radio.test.d.ts +2 -0
- package/lib/__tests__/Radio.test.js +202 -0
- package/lib/__tests__/ThemeProvider.test.js +114 -0
- package/lib/drafts.d.ts +1 -0
- package/lib/drafts.js +13 -0
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.js +9 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +8 -0
- package/lib/stories/ActionList.stories.js +3 -3
- package/lib/stories/ActionList2.stories.js +1 -1
- package/lib/stories/ActionMenu2.stories.js +455 -0
- package/lib/stories/Checkbox.stories.js +4 -4
- package/lib/stories/Radio.stories.js +146 -0
- package/lib/stories/ThemeProvider.stories.js +1 -5
- package/lib/stories/useFocusTrap.stories.js +1 -11
- package/lib/stories/useFocusZone.stories.js +2 -6
- package/lib-esm/ActionList/Header.js +1 -1
- package/lib-esm/ActionList/Item.js +10 -10
- package/lib-esm/ActionList/List.js +1 -1
- package/lib-esm/ActionList2/ActionListContainerContext.d.ts +10 -0
- package/lib-esm/ActionList2/ActionListContainerContext.js +3 -0
- package/lib-esm/ActionList2/Divider.d.ts +3 -2
- package/lib-esm/ActionList2/Divider.js +8 -5
- package/lib-esm/ActionList2/Item.js +20 -8
- package/lib-esm/ActionList2/List.js +10 -2
- package/lib-esm/ActionList2/Selection.js +9 -0
- package/lib-esm/ActionList2/index.d.ts +1 -2
- package/lib-esm/ActionMenu2.d.ts +317 -0
- package/lib-esm/ActionMenu2.js +100 -0
- package/lib-esm/Autocomplete/Autocomplete.d.ts +2 -1
- package/lib-esm/Autocomplete/AutocompleteInput.d.ts +2 -1
- package/lib-esm/BaseStyles.js +2 -20
- package/lib-esm/BorderBox.js +1 -1
- package/lib-esm/Box.js +1 -1
- package/lib-esm/BranchName.js +1 -1
- package/lib-esm/Breadcrumbs.js +3 -3
- package/lib-esm/Button/Button.d.ts +2 -2
- package/lib-esm/Button/Button.js +1 -1
- package/lib-esm/Button/ButtonClose.d.ts +2 -2
- package/lib-esm/Button/ButtonDanger.d.ts +2 -2
- package/lib-esm/Button/ButtonGroup.js +1 -1
- package/lib-esm/Button/ButtonInvisible.d.ts +2 -2
- package/lib-esm/Button/ButtonOutline.d.ts +2 -2
- package/lib-esm/Button/ButtonPrimary.d.ts +2 -2
- package/lib-esm/Checkbox.d.ts +1 -1
- package/lib-esm/Checkbox.js +1 -1
- package/lib-esm/CircleOcticon.d.ts +35 -35
- package/lib-esm/Details.js +1 -1
- package/lib-esm/Dialog.d.ts +37 -37
- package/lib-esm/Dropdown.d.ts +6 -6
- package/lib-esm/DropdownMenu/DropdownButton.d.ts +6 -3
- package/lib-esm/FilterList.d.ts +1 -1
- package/lib-esm/FilteredActionList/FilteredActionList.js +1 -1
- package/lib-esm/Flex.js +1 -1
- package/lib-esm/LabelGroup.js +1 -1
- package/lib-esm/Overlay.js +1 -1
- package/lib-esm/Pagination/Pagination.js +2 -2
- package/lib-esm/Position.d.ts +4 -4
- package/lib-esm/Position.js +1 -1
- package/lib-esm/Radio.d.ts +38 -0
- package/lib-esm/Radio.js +40 -0
- package/lib-esm/SelectMenu/SelectMenu.d.ts +11 -10
- package/lib-esm/SelectMenu/SelectMenu.js +1 -1
- package/lib-esm/SelectMenu/SelectMenuFilter.js +1 -1
- package/lib-esm/SelectMenu/SelectMenuFooter.js +1 -1
- package/lib-esm/SelectMenu/SelectMenuItem.d.ts +1 -1
- package/lib-esm/SelectMenu/SelectMenuItem.js +1 -1
- package/lib-esm/SelectMenu/SelectMenuModal.d.ts +1 -1
- package/lib-esm/SelectMenu/SelectMenuTab.js +1 -1
- package/lib-esm/SelectMenu/SelectMenuTabPanel.js +1 -1
- package/lib-esm/SelectMenu/SelectMenuTabs.js +1 -1
- package/lib-esm/StateLabel.js +1 -1
- package/lib-esm/StyledOcticon.js +1 -1
- package/lib-esm/SubNav.js +3 -3
- package/lib-esm/TextInputWithTokens.d.ts +2 -1
- package/lib-esm/ThemeProvider.d.ts +1 -0
- package/lib-esm/ThemeProvider.js +17 -4
- package/lib-esm/Timeline.js +4 -4
- package/lib-esm/Token/AvatarToken.d.ts +1 -1
- package/lib-esm/Token/AvatarToken.js +1 -1
- package/lib-esm/Token/IssueLabelToken.d.ts +1 -1
- package/lib-esm/Token/Token.d.ts +1 -1
- package/lib-esm/Token/TokenBase.js +1 -1
- package/lib-esm/Tooltip.js +1 -1
- package/lib-esm/UnderlineNav.js +2 -2
- package/lib-esm/__tests__/Radio.test.d.ts +2 -0
- package/lib-esm/__tests__/Radio.test.js +183 -0
- package/lib-esm/__tests__/ThemeProvider.test.js +114 -0
- package/lib-esm/drafts.d.ts +1 -0
- package/lib-esm/drafts.js +2 -1
- package/lib-esm/hooks/index.d.ts +1 -0
- package/lib-esm/hooks/index.js +2 -1
- package/lib-esm/index.d.ts +2 -0
- package/lib-esm/index.js +1 -0
- package/lib-esm/stories/ActionList.stories.js +3 -3
- package/lib-esm/stories/ActionList2.stories.js +1 -1
- package/lib-esm/stories/ActionMenu2.stories.js +393 -0
- package/lib-esm/stories/Checkbox.stories.js +5 -5
- package/lib-esm/stories/Radio.stories.js +121 -0
- package/lib-esm/stories/ThemeProvider.stories.js +1 -5
- package/lib-esm/stories/useFocusTrap.stories.js +1 -11
- package/lib-esm/stories/useFocusZone.stories.js +2 -6
- package/package-lock.json +1366 -3544
- package/package.json +14 -8
- package/script/component-status-project/build.ts +100 -0
- package/script/component-status-project/deploy.rb +142 -0
- package/src/ActionList2/ActionListContainerContext.tsx +14 -0
- package/src/ActionList2/Divider.tsx +13 -8
- package/src/ActionList2/Item.tsx +14 -6
- package/src/ActionList2/List.tsx +6 -2
- package/src/ActionList2/Selection.tsx +9 -0
- package/src/ActionMenu2.tsx +116 -0
- package/src/BranchName.tsx +2 -1
- package/src/Radio.tsx +76 -0
- package/src/ThemeProvider.tsx +22 -5
- package/src/__tests__/Radio.test.tsx +174 -0
- package/src/__tests__/ThemeProvider.test.tsx +116 -0
- package/src/__tests__/__snapshots__/BranchName.test.tsx.snap +3 -1
- package/src/__tests__/__snapshots__/Radio.test.tsx.snap +16 -0
- package/src/drafts.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/index.ts +2 -0
- package/src/stories/ActionMenu2.stories.tsx +605 -0
- package/src/stories/Checkbox.stories.tsx +1 -3
- package/src/stories/Radio.stories.tsx +126 -0
- package/stats.html +1 -1
- package/tsconfig.build.json +1 -1
- package/tsconfig.json +1 -1
- package/docs/content/ActionList2.mdx +0 -379
- package/docs/content/BranchName.md +0 -39
- package/docs/content/Link.md +0 -29
- package/docs/content/TextInput.md +0 -42
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@primer/components",
|
3
|
-
"version": "33.
|
3
|
+
"version": "33.1.0-rc.6856bcf5",
|
4
4
|
"description": "Primer react components",
|
5
5
|
"main": "lib/index.js",
|
6
6
|
"module": "lib-esm/index.js",
|
@@ -65,7 +65,7 @@
|
|
65
65
|
"@babel/cli": "7.14.5",
|
66
66
|
"@babel/core": "7.14.8",
|
67
67
|
"@babel/eslint-parser": "7.15.7",
|
68
|
-
"@babel/plugin-proposal-nullish-coalescing-operator": "7.
|
68
|
+
"@babel/plugin-proposal-nullish-coalescing-operator": "7.16.0",
|
69
69
|
"@babel/plugin-proposal-optional-chaining": "7.14.5",
|
70
70
|
"@babel/plugin-transform-modules-commonjs": "7.14.5",
|
71
71
|
"@babel/preset-react": "7.14.5",
|
@@ -75,7 +75,7 @@
|
|
75
75
|
"@github/prettier-config": "0.0.4",
|
76
76
|
"@rollup/plugin-commonjs": "19.0.2",
|
77
77
|
"@rollup/plugin-node-resolve": "13.0.5",
|
78
|
-
"@size-limit/preset-big-lib": "
|
78
|
+
"@size-limit/preset-big-lib": "7.0.3",
|
79
79
|
"@storybook/addon-a11y": "6.3.12",
|
80
80
|
"@storybook/addon-actions": "^6.3.12",
|
81
81
|
"@storybook/addon-essentials": "6.3.12",
|
@@ -91,6 +91,7 @@
|
|
91
91
|
"@types/jest-axe": "3.5.3",
|
92
92
|
"@types/lodash.isempty": "4.4.6",
|
93
93
|
"@types/lodash.isobject": "3.0.6",
|
94
|
+
"@types/node": "16.11.11",
|
94
95
|
"@typescript-eslint/eslint-plugin": "4.31.2",
|
95
96
|
"@typescript-eslint/parser": "4.26.1",
|
96
97
|
"@wojtekmaj/enzyme-adapter-react-17": "0.6.3",
|
@@ -99,7 +100,7 @@
|
|
99
100
|
"babel-plugin-add-react-displayname": "0.0.5",
|
100
101
|
"babel-plugin-macros": "3.1.0",
|
101
102
|
"babel-plugin-preval": "5.0.0",
|
102
|
-
"babel-plugin-styled-components": "
|
103
|
+
"babel-plugin-styled-components": "2.0.2",
|
103
104
|
"babel-plugin-transform-replace-expressions": "0.2.0",
|
104
105
|
"babel-polyfill": "6.26.0",
|
105
106
|
"chroma-js": "2.1.2",
|
@@ -116,6 +117,7 @@
|
|
116
117
|
"eslint-plugin-primer-react": "0.7.0",
|
117
118
|
"eslint-plugin-react": "7.24.0",
|
118
119
|
"eslint-plugin-react-hooks": "4.2.0",
|
120
|
+
"front-matter": "4.0.2",
|
119
121
|
"jest": "27.0.4",
|
120
122
|
"jest-axe": "5.0.1",
|
121
123
|
"jest-styled-components": "6.3.4",
|
@@ -128,16 +130,16 @@
|
|
128
130
|
"react-dnd-html5-backend": "14.0.2",
|
129
131
|
"react-dom": "17.0.2",
|
130
132
|
"react-test-renderer": "17.0.2",
|
131
|
-
"rollup": "2.
|
133
|
+
"rollup": "2.60.2",
|
132
134
|
"rollup-plugin-babel": "4.4.0",
|
133
135
|
"rollup-plugin-terser": "7.0.2",
|
134
136
|
"rollup-plugin-visualizer": "5.5.0",
|
135
137
|
"semver": "7.3.5",
|
136
|
-
"size-limit": "
|
138
|
+
"size-limit": "7.0.3",
|
137
139
|
"storybook-addon-performance": "0.16.1",
|
138
140
|
"styled-components": "4.4.1",
|
139
141
|
"ts-toolbelt": "9.6.0",
|
140
|
-
"typescript": "4.
|
142
|
+
"typescript": "4.4.4"
|
141
143
|
},
|
142
144
|
"peerDependencies": {
|
143
145
|
"react": "^17.0.0",
|
@@ -156,5 +158,9 @@
|
|
156
158
|
"webpack": false,
|
157
159
|
"running": false
|
158
160
|
}
|
159
|
-
]
|
161
|
+
],
|
162
|
+
"engines": {
|
163
|
+
"node": ">=16",
|
164
|
+
"npm": ">=8"
|
165
|
+
}
|
160
166
|
}
|
@@ -0,0 +1,100 @@
|
|
1
|
+
import fs from 'fs'
|
2
|
+
import path from 'path'
|
3
|
+
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
5
|
+
const fm = require('front-matter') // FIXME after this bugfix is merged https://github.com/jxson/front-matter/pull/77
|
6
|
+
|
7
|
+
const sourceDirectory = path.resolve(__dirname, '../../docs/content/')
|
8
|
+
const outputDir = path.resolve(__dirname, '../../dist/')
|
9
|
+
|
10
|
+
type ComponentStatus = {
|
11
|
+
[component: string]: string
|
12
|
+
}
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Extracts the component status for each file in the given directory.
|
16
|
+
*
|
17
|
+
* @param filenames Array of filenames to read front-matter from
|
18
|
+
* @param dir Absolute path to directory containing files
|
19
|
+
* @returns A promise that resolves to an array containing outcome of file front-matter extraction
|
20
|
+
*/
|
21
|
+
function getComponentStatuses(filenames: string[], dir: string) {
|
22
|
+
const promises: Promise<ComponentStatus | null>[] = []
|
23
|
+
|
24
|
+
const handleCallback = (
|
25
|
+
filename: string,
|
26
|
+
resolve: (value: ComponentStatus | null) => void,
|
27
|
+
reject: (value: unknown) => void
|
28
|
+
) => {
|
29
|
+
fs.readFile(path.resolve(dir, filename), 'utf-8', (err, content) => {
|
30
|
+
if (err) return reject(err)
|
31
|
+
|
32
|
+
if (fm.test(content)) {
|
33
|
+
const {
|
34
|
+
attributes: {title, status}
|
35
|
+
} = fm(content)
|
36
|
+
|
37
|
+
if (status) {
|
38
|
+
return resolve({[title]: status})
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
resolve(null)
|
43
|
+
})
|
44
|
+
}
|
45
|
+
|
46
|
+
for (const filename of filenames) {
|
47
|
+
const promise: Promise<ComponentStatus | null> = new Promise((resolve, reject) => {
|
48
|
+
return handleCallback(filename, resolve, reject)
|
49
|
+
})
|
50
|
+
promises.push(promise)
|
51
|
+
}
|
52
|
+
|
53
|
+
return Promise.all(promises)
|
54
|
+
}
|
55
|
+
|
56
|
+
/**
|
57
|
+
* Orchestrates the process of reading component status for each file in the given directory.
|
58
|
+
*
|
59
|
+
* @param dir Directory to source files where status will be extracted from
|
60
|
+
* @returns A promise that resolves to an object containing component statuses
|
61
|
+
*/
|
62
|
+
async function readFiles(dir: string) {
|
63
|
+
try {
|
64
|
+
const dirContents = fs.readdirSync(dir, {withFileTypes: true})
|
65
|
+
const filenames = dirContents.filter(dirent => dirent.isFile()).map(dirent => dirent.name)
|
66
|
+
const componentStatuses = await getComponentStatuses(filenames, dir)
|
67
|
+
|
68
|
+
return componentStatuses
|
69
|
+
.filter(Boolean)
|
70
|
+
.reverse()
|
71
|
+
.reduce(
|
72
|
+
(acc, file) => ({
|
73
|
+
...acc,
|
74
|
+
...file
|
75
|
+
}),
|
76
|
+
{}
|
77
|
+
)
|
78
|
+
} catch (err) {
|
79
|
+
throw new Error(`error reading files: ${err}`)
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
/**
|
84
|
+
* Writes the component status to the given file.
|
85
|
+
*/
|
86
|
+
async function build() {
|
87
|
+
try {
|
88
|
+
const componentStatuses = await readFiles(sourceDirectory)
|
89
|
+
|
90
|
+
if (!fs.existsSync(outputDir)) {
|
91
|
+
fs.mkdirSync(outputDir)
|
92
|
+
}
|
93
|
+
|
94
|
+
fs.writeFileSync(`${outputDir}/component-status.json`, JSON.stringify(componentStatuses))
|
95
|
+
} catch (error) {
|
96
|
+
throw new Error(`error building component status object: ${error}`)
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
build()
|
@@ -0,0 +1,142 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Adapted from https://github.com/primer/view_components/blob/main/script/update-statuses-project.rb
|
3
|
+
# Usage: script/update-statuses-project
|
4
|
+
# frozen_string_literal: true
|
5
|
+
|
6
|
+
require "graphql/client"
|
7
|
+
require "graphql/client/http"
|
8
|
+
|
9
|
+
statuses = File.read(File.join(File.dirname(__FILE__), "../../dist/component-status.json"))
|
10
|
+
statuses_json = JSON.parse(statuses)
|
11
|
+
|
12
|
+
class QueryExecutionError < StandardError; end
|
13
|
+
NOTE_SEPARATOR = " --- "
|
14
|
+
|
15
|
+
module Github
|
16
|
+
GITHUB_ACCESS_TOKEN = ENV.fetch("GITHUB_TOKEN")
|
17
|
+
URL = "https://api.github.com/graphql"
|
18
|
+
HttpAdapter = GraphQL::Client::HTTP.new(URL) do
|
19
|
+
def headers(_)
|
20
|
+
{
|
21
|
+
"Authorization" => "Bearer #{GITHUB_ACCESS_TOKEN}",
|
22
|
+
"User-Agent" => "Ruby"
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
Schema = GraphQL::Client.load_schema(HttpAdapter)
|
27
|
+
Client = GraphQL::Client.new(schema: Schema, execute: HttpAdapter)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Project is a GraphQL wrapper for interacting with GitHub projects
|
31
|
+
class Project
|
32
|
+
ProjectQuery = Github::Client.parse <<-'GRAPHQL'
|
33
|
+
query {
|
34
|
+
repository(owner: "primer", name: "react") {
|
35
|
+
project(number: 5) {
|
36
|
+
columns(first: 100) {
|
37
|
+
nodes {
|
38
|
+
name
|
39
|
+
id
|
40
|
+
databaseId
|
41
|
+
cards {
|
42
|
+
nodes {
|
43
|
+
id
|
44
|
+
databaseId
|
45
|
+
note
|
46
|
+
column {
|
47
|
+
name
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
GRAPHQL
|
57
|
+
|
58
|
+
CreateCard = Github::Client.parse <<-'GRAPHQL'
|
59
|
+
mutation($note: String!, $projectColumnId: ID!) {
|
60
|
+
addProjectCard(input:{note: $note, projectColumnId: $projectColumnId, clientMutationId: "prc-actions"}) {
|
61
|
+
__typename
|
62
|
+
}
|
63
|
+
}
|
64
|
+
GRAPHQL
|
65
|
+
|
66
|
+
MoveCard = Github::Client.parse <<-'GRAPHQL'
|
67
|
+
mutation($cardId: ID!, $columnId: ID!) {
|
68
|
+
moveProjectCard(input:{cardId: $cardId, columnId: $columnId, clientMutationId: "prc-actions"}) {
|
69
|
+
__typename
|
70
|
+
}
|
71
|
+
}
|
72
|
+
GRAPHQL
|
73
|
+
|
74
|
+
def self.create_card(note:, column_id:)
|
75
|
+
response = Github::Client.query(CreateCard, variables: { note: note, projectColumnId: column_id })
|
76
|
+
return unless response.errors.any?
|
77
|
+
|
78
|
+
raise QueryExecutionError, response.errors[:data].join(", ")
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.move_card(card_id:, column_id:)
|
82
|
+
response = Github::Client.query(MoveCard, variables: { cardId: card_id, columnId: column_id })
|
83
|
+
return unless response.errors.any?
|
84
|
+
|
85
|
+
raise(QueryExecutionError, response.errors[:data].join(", "))
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.fetch_columns
|
89
|
+
response = Github::Client.query(ProjectQuery)
|
90
|
+
return response.data.repository.project.columns unless response.errors.any?
|
91
|
+
|
92
|
+
raise(QueryExecutionError, response.errors[:data].join(", "))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
columns = Project.fetch_columns.nodes
|
97
|
+
|
98
|
+
@column_mapping = {}
|
99
|
+
columns.each do |column|
|
100
|
+
@column_mapping[column.name.downcase] = column.id
|
101
|
+
end
|
102
|
+
|
103
|
+
@cards = columns.map(&:cards).map(&:nodes).flatten
|
104
|
+
|
105
|
+
def get_card(name_prefix:)
|
106
|
+
@cards.find { |card| card.note.start_with?(name_prefix) }
|
107
|
+
end
|
108
|
+
|
109
|
+
def on_correct_column?(card_id:, status:)
|
110
|
+
card = @cards.find { |c| c.id == card_id }
|
111
|
+
card.column.name.casecmp(status).zero?
|
112
|
+
end
|
113
|
+
|
114
|
+
def move_card(card_id:, status:)
|
115
|
+
column_id = @column_mapping[status.downcase]
|
116
|
+
|
117
|
+
puts "move card with #{card_id} to #{status} on column #{column_id}"
|
118
|
+
|
119
|
+
Project.move_card(card_id: card_id, column_id: column_id)
|
120
|
+
end
|
121
|
+
|
122
|
+
def create_card(component_name:, status:)
|
123
|
+
column_id = @column_mapping[status.downcase]
|
124
|
+
|
125
|
+
puts "create card with #{component_name} on #{status} on column #{column_id}"
|
126
|
+
|
127
|
+
Project.create_card(note: component_name, column_id: column_id)
|
128
|
+
end
|
129
|
+
|
130
|
+
statuses_json.each do |component_name, component_status|
|
131
|
+
card = get_card(name_prefix: component_name)
|
132
|
+
|
133
|
+
if card
|
134
|
+
if on_correct_column?(card_id: card.id, status: component_status)
|
135
|
+
puts "#{card.id} is on the right column. noop"
|
136
|
+
else
|
137
|
+
move_card(card_id: card.id, status: component_status)
|
138
|
+
end
|
139
|
+
else
|
140
|
+
create_card(component_name: component_name, status: component_status)
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
/** This context can be used by components that compose ActionList inside a Menu */
|
2
|
+
|
3
|
+
import React from 'react'
|
4
|
+
|
5
|
+
type ContextProps = {
|
6
|
+
container?: string
|
7
|
+
listRole?: string
|
8
|
+
itemRole?: string
|
9
|
+
// This can be any function, we don't know anything about the arguments
|
10
|
+
// to be more specific here, this is as good as (...args: any[]) => unknown
|
11
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
12
|
+
afterSelect?: Function
|
13
|
+
}
|
14
|
+
export const ActionListContainerContext = React.createContext<ContextProps>({})
|
@@ -2,22 +2,27 @@ import React from 'react'
|
|
2
2
|
import Box from '../Box'
|
3
3
|
import {get} from '../constants'
|
4
4
|
import {Theme} from '../ThemeProvider'
|
5
|
+
import {SxProp, merge} from '../sx'
|
5
6
|
|
6
7
|
/**
|
7
8
|
* Visually separates `Item`s or `Group`s in an `ActionList`.
|
8
9
|
*/
|
9
|
-
|
10
|
+
|
11
|
+
export const Divider: React.FC<SxProp> = ({sx = {}}) => {
|
10
12
|
return (
|
11
13
|
<Box
|
12
14
|
as="li"
|
13
15
|
role="separator"
|
14
|
-
sx={
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
sx={merge(
|
17
|
+
{
|
18
|
+
height: 1,
|
19
|
+
backgroundColor: 'actionListItem.inlineDivider',
|
20
|
+
marginTop: (theme: Theme) => `calc(${get('space.2')(theme)} - 1px)`,
|
21
|
+
marginBottom: 2,
|
22
|
+
listStyle: 'none' // hide the ::marker inserted by browser's stylesheet
|
23
|
+
},
|
24
|
+
sx as SxProp
|
25
|
+
)}
|
21
26
|
data-component="ActionList.Divider"
|
22
27
|
/>
|
23
28
|
)
|
package/src/ActionList2/Item.tsx
CHANGED
@@ -8,6 +8,7 @@ import sx, {SxProp, merge} from '../sx'
|
|
8
8
|
import createSlots from '../utils/create-slots'
|
9
9
|
import {AriaRole} from '../utils/types'
|
10
10
|
import {ListContext} from './List'
|
11
|
+
import {ActionListContainerContext} from './ActionListContainerContext'
|
11
12
|
import {Selection} from './Selection'
|
12
13
|
|
13
14
|
export const getVariantStyles = (variant: ItemProps['variant'], disabled: ItemProps['disabled']) => {
|
@@ -94,12 +95,14 @@ export const Item = React.forwardRef<HTMLLIElement, ItemProps>(
|
|
94
95
|
onSelect,
|
95
96
|
sx: sxProp = {},
|
96
97
|
id,
|
98
|
+
role,
|
97
99
|
_PrivateItemWrapper,
|
98
100
|
...props
|
99
101
|
},
|
100
102
|
forwardedRef
|
101
103
|
): JSX.Element => {
|
102
104
|
const {variant: listVariant, showDividers} = React.useContext(ListContext)
|
105
|
+
const {itemRole, afterSelect} = React.useContext(ActionListContainerContext)
|
103
106
|
|
104
107
|
const {theme} = useTheme()
|
105
108
|
|
@@ -168,22 +171,26 @@ export const Item = React.forwardRef<HTMLLIElement, ItemProps>(
|
|
168
171
|
|
169
172
|
const clickHandler = React.useCallback(
|
170
173
|
event => {
|
171
|
-
if (typeof onSelect !== 'function') return
|
172
174
|
if (disabled) return
|
173
|
-
if (!event.defaultPrevented)
|
175
|
+
if (!event.defaultPrevented) {
|
176
|
+
if (typeof onSelect === 'function') onSelect(event)
|
177
|
+
// if this Item is inside a Menu, close the Menu
|
178
|
+
if (typeof afterSelect === 'function') afterSelect()
|
179
|
+
}
|
174
180
|
},
|
175
|
-
[onSelect, disabled]
|
181
|
+
[onSelect, disabled, afterSelect]
|
176
182
|
)
|
177
183
|
|
178
184
|
const keyPressHandler = React.useCallback(
|
179
185
|
event => {
|
180
|
-
if (typeof onSelect !== 'function') return
|
181
186
|
if (disabled) return
|
182
187
|
if (!event.defaultPrevented && [' ', 'Enter'].includes(event.key)) {
|
183
|
-
onSelect(event)
|
188
|
+
if (typeof onSelect === 'function') onSelect(event)
|
189
|
+
// if this Item is inside a Menu, close the Menu
|
190
|
+
if (typeof afterSelect === 'function') afterSelect()
|
184
191
|
}
|
185
192
|
},
|
186
|
-
[onSelect, disabled]
|
193
|
+
[onSelect, disabled, afterSelect]
|
187
194
|
)
|
188
195
|
|
189
196
|
// use props.id if provided, otherwise generate one.
|
@@ -206,6 +213,7 @@ export const Item = React.forwardRef<HTMLLIElement, ItemProps>(
|
|
206
213
|
tabIndex={disabled || _PrivateItemWrapper ? undefined : 0}
|
207
214
|
aria-labelledby={`${labelId} ${slots.InlineDescription ? inlineDescriptionId : ''}`}
|
208
215
|
aria-describedby={slots.BlockDescription ? blockDescriptionId : undefined}
|
216
|
+
role={role || itemRole}
|
209
217
|
{...props}
|
210
218
|
>
|
211
219
|
<ItemWrapper>
|
package/src/ActionList2/List.tsx
CHANGED
@@ -3,6 +3,7 @@ import {ForwardRefComponent as PolymorphicForwardRefComponent} from '@radix-ui/r
|
|
3
3
|
import styled from 'styled-components'
|
4
4
|
import sx, {SxProp, merge} from '../sx'
|
5
5
|
import {AriaRole} from '../utils/types'
|
6
|
+
import {ActionListContainerContext} from './ActionListContainerContext'
|
6
7
|
|
7
8
|
export type ListProps = {
|
8
9
|
/**
|
@@ -30,7 +31,7 @@ const ListBox = styled.ul<SxProp>(sx)
|
|
30
31
|
|
31
32
|
export const List = React.forwardRef<HTMLUListElement, ListProps>(
|
32
33
|
(
|
33
|
-
{variant = 'inset', selectionVariant, showDividers = false, sx: sxProp = {}, ...props},
|
34
|
+
{variant = 'inset', selectionVariant, showDividers = false, role, sx: sxProp = {}, ...props},
|
34
35
|
forwardedRef
|
35
36
|
): JSX.Element => {
|
36
37
|
const styles = {
|
@@ -39,8 +40,11 @@ export const List = React.forwardRef<HTMLUListElement, ListProps>(
|
|
39
40
|
paddingY: variant === 'inset' ? 2 : 0
|
40
41
|
}
|
41
42
|
|
43
|
+
/** if list is inside a Menu, it will get a role from the Menu */
|
44
|
+
const {listRole} = React.useContext(ActionListContainerContext)
|
45
|
+
|
42
46
|
return (
|
43
|
-
<ListBox sx={merge(styles, sxProp as SxProp)} {...props} ref={forwardedRef}>
|
47
|
+
<ListBox sx={merge(styles, sxProp as SxProp)} role={role || listRole} {...props} ref={forwardedRef}>
|
44
48
|
<ListContext.Provider value={{variant, selectionVariant, showDividers}}>{props.children}</ListContext.Provider>
|
45
49
|
</ListBox>
|
46
50
|
)
|
@@ -2,6 +2,7 @@ import React from 'react'
|
|
2
2
|
import {CheckIcon} from '@primer/octicons-react'
|
3
3
|
import {ListContext} from './List'
|
4
4
|
import {GroupContext} from './Group'
|
5
|
+
import {ActionListContainerContext} from './ActionListContainerContext'
|
5
6
|
import {ItemProps} from './Item'
|
6
7
|
import {LeadingVisualContainer} from './Visuals'
|
7
8
|
|
@@ -9,6 +10,7 @@ type SelectionProps = Pick<ItemProps, 'selected'>
|
|
9
10
|
export const Selection: React.FC<SelectionProps> = ({selected}) => {
|
10
11
|
const {selectionVariant: listSelectionVariant} = React.useContext(ListContext)
|
11
12
|
const {selectionVariant: groupSelectionVariant} = React.useContext(GroupContext)
|
13
|
+
const {container} = React.useContext(ActionListContainerContext)
|
12
14
|
|
13
15
|
/** selectionVariant in Group can override the selectionVariant in List root */
|
14
16
|
const selectionVariant = typeof groupSelectionVariant !== 'undefined' ? groupSelectionVariant : listSelectionVariant
|
@@ -23,6 +25,13 @@ export const Selection: React.FC<SelectionProps> = ({selected}) => {
|
|
23
25
|
return null
|
24
26
|
}
|
25
27
|
|
28
|
+
if (container === 'ActionMenu') {
|
29
|
+
throw new Error(
|
30
|
+
'ActionList cannot have a selectionVariant inside ActionMenu, please use DropdownMenu or SelectPanel instead. More information: https://primer.style/design/components/action-list#application'
|
31
|
+
)
|
32
|
+
return null
|
33
|
+
}
|
34
|
+
|
26
35
|
if (selectionVariant === 'single') {
|
27
36
|
return <LeadingVisualContainer>{selected && <CheckIcon />}</LeadingVisualContainer>
|
28
37
|
}
|
@@ -0,0 +1,116 @@
|
|
1
|
+
import Button, {ButtonProps} from './Button'
|
2
|
+
import React from 'react'
|
3
|
+
import {AnchoredOverlay, AnchoredOverlayProps} from './AnchoredOverlay'
|
4
|
+
import {OverlayProps} from './Overlay'
|
5
|
+
import {useProvidedRefOrCreate, useProvidedStateOrCreate} from './hooks'
|
6
|
+
import {Divider} from './ActionList2/Divider'
|
7
|
+
import {ActionListContainerContext} from './ActionList2/ActionListContainerContext'
|
8
|
+
import {MandateProps} from './utils/types'
|
9
|
+
|
10
|
+
type MenuContextProps = Pick<AnchoredOverlayProps, 'anchorRef' | 'renderAnchor' | 'open' | 'onOpen' | 'onClose'>
|
11
|
+
export const MenuContext = React.createContext<MenuContextProps>({renderAnchor: null, open: false})
|
12
|
+
|
13
|
+
export type ActionMenuProps = {
|
14
|
+
/**
|
15
|
+
* Recommended: `ActionMenu.Button` or `ActionMenu.Anchor` with `ActionMenu.Overlay`
|
16
|
+
*/
|
17
|
+
children: React.ReactElement[] | React.ReactElement
|
18
|
+
|
19
|
+
/**
|
20
|
+
* If defined, will control the open/closed state of the overlay. Must be used in conjuction with `onOpenChange`.
|
21
|
+
*/
|
22
|
+
open?: boolean
|
23
|
+
|
24
|
+
/**
|
25
|
+
* If defined, will control the open/closed state of the overlay. Must be used in conjuction with `open`.
|
26
|
+
*/
|
27
|
+
onOpenChange?: (s: boolean) => void
|
28
|
+
} & Pick<AnchoredOverlayProps, 'anchorRef'>
|
29
|
+
|
30
|
+
const Menu: React.FC<ActionMenuProps> = ({
|
31
|
+
anchorRef: externalAnchorRef,
|
32
|
+
open,
|
33
|
+
onOpenChange,
|
34
|
+
children
|
35
|
+
}: ActionMenuProps) => {
|
36
|
+
const [combinedOpenState, setCombinedOpenState] = useProvidedStateOrCreate(open, onOpenChange, false)
|
37
|
+
const onOpen = React.useCallback(() => setCombinedOpenState(true), [setCombinedOpenState])
|
38
|
+
const onClose = React.useCallback(() => setCombinedOpenState(false), [setCombinedOpenState])
|
39
|
+
|
40
|
+
const anchorRef = useProvidedRefOrCreate(externalAnchorRef)
|
41
|
+
let renderAnchor: AnchoredOverlayProps['renderAnchor'] = null
|
42
|
+
|
43
|
+
// 🚨 Hack for good API!
|
44
|
+
// we strip out Anchor from children and pass it to AnchoredOverlay to render
|
45
|
+
// with additional props for accessibility
|
46
|
+
const contents = React.Children.map(children, child => {
|
47
|
+
if (child.type === MenuButton || child.type === Anchor) {
|
48
|
+
renderAnchor = anchorProps => React.cloneElement(child, anchorProps)
|
49
|
+
return null
|
50
|
+
}
|
51
|
+
return child
|
52
|
+
})
|
53
|
+
|
54
|
+
return (
|
55
|
+
<MenuContext.Provider value={{anchorRef, renderAnchor, open: combinedOpenState, onOpen, onClose}}>
|
56
|
+
{contents}
|
57
|
+
</MenuContext.Provider>
|
58
|
+
)
|
59
|
+
}
|
60
|
+
|
61
|
+
export type MenuAnchorProps = {children: React.ReactElement}
|
62
|
+
const Anchor = React.forwardRef<AnchoredOverlayProps['anchorRef'], MenuAnchorProps>(
|
63
|
+
({children, ...anchorProps}, anchorRef) => {
|
64
|
+
return React.cloneElement(children, {...anchorProps, ref: anchorRef})
|
65
|
+
}
|
66
|
+
)
|
67
|
+
|
68
|
+
/** this component is syntactical sugar 🍭 */
|
69
|
+
export type MenuButtonProps = ButtonProps
|
70
|
+
const MenuButton = React.forwardRef<AnchoredOverlayProps['anchorRef'], ButtonProps>((props, anchorRef) => {
|
71
|
+
return (
|
72
|
+
<Anchor ref={anchorRef}>
|
73
|
+
<Button {...props} />
|
74
|
+
</Anchor>
|
75
|
+
)
|
76
|
+
})
|
77
|
+
|
78
|
+
type MenuOverlayProps = Partial<OverlayProps> & {
|
79
|
+
/**
|
80
|
+
* Recommended: `ActionList`
|
81
|
+
*/
|
82
|
+
children: React.ReactElement[] | React.ReactElement
|
83
|
+
}
|
84
|
+
const Overlay: React.FC<MenuOverlayProps> = ({children, ...overlayProps}) => {
|
85
|
+
// we typecast anchorRef as required instead of optional
|
86
|
+
// because we know that we're setting it in context in Menu
|
87
|
+
const {anchorRef, renderAnchor, open, onOpen, onClose} = React.useContext(MenuContext) as MandateProps<
|
88
|
+
MenuContextProps,
|
89
|
+
'anchorRef'
|
90
|
+
>
|
91
|
+
|
92
|
+
return (
|
93
|
+
<AnchoredOverlay
|
94
|
+
anchorRef={anchorRef}
|
95
|
+
renderAnchor={renderAnchor}
|
96
|
+
open={open}
|
97
|
+
onOpen={onOpen}
|
98
|
+
onClose={onClose}
|
99
|
+
overlayProps={overlayProps}
|
100
|
+
>
|
101
|
+
<ActionListContainerContext.Provider
|
102
|
+
value={{
|
103
|
+
container: 'ActionMenu',
|
104
|
+
listRole: 'menu',
|
105
|
+
itemRole: 'menuitem',
|
106
|
+
afterSelect: onClose
|
107
|
+
}}
|
108
|
+
>
|
109
|
+
{children}
|
110
|
+
</ActionListContainerContext.Provider>
|
111
|
+
</AnchoredOverlay>
|
112
|
+
)
|
113
|
+
}
|
114
|
+
|
115
|
+
Menu.displayName = 'ActionMenu'
|
116
|
+
export const ActionMenu = Object.assign(Menu, {Button: MenuButton, Anchor, Overlay, Divider})
|
package/src/BranchName.tsx
CHANGED
@@ -8,9 +8,10 @@ const BranchName = styled.a<SxProp>`
|
|
8
8
|
padding: 2px 6px;
|
9
9
|
font-size: ${get('fontSizes.0')};
|
10
10
|
font-family: ${get('fonts.mono')};
|
11
|
-
color: ${get('colors.fg
|
11
|
+
color: ${get('colors.accent.fg')};
|
12
12
|
background-color: ${get('colors.accent.subtle')};
|
13
13
|
border-radius: ${get('radii.2')};
|
14
|
+
text-decoration: none;
|
14
15
|
|
15
16
|
${sx};
|
16
17
|
`
|