@primer/components 33.0.0-rc.b495ba4a → 33.1.0-rc.6856bcf5
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/.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
|
`
|