@primer/components 31.2.0-rc.a2a8604e → 31.2.0-rc.c7f73427

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/browser.esm.js +180 -178
  3. package/dist/browser.esm.js.map +1 -1
  4. package/dist/browser.umd.js +182 -180
  5. package/dist/browser.umd.js.map +1 -1
  6. package/docs/src/@primer/gatsby-theme-doctocat/components/hero.js +1 -3
  7. package/docs/src/@primer/gatsby-theme-doctocat/components/live-preview-wrapper.js +1 -1
  8. package/lib/Overlay.js +3 -1
  9. package/lib/Portal/Portal.js +3 -2
  10. package/lib/_TextInputWrapper.js +2 -2
  11. package/lib/__tests__/AnchoredOverlay.test.js +4 -2
  12. package/lib/__tests__/TextInputWithTokens.test.js +1 -10
  13. package/lib/hooks/useAnchoredPosition.js +3 -2
  14. package/lib/hooks/useCombinedRefs.d.ts +2 -2
  15. package/lib/hooks/useCombinedRefs.js +4 -6
  16. package/lib/hooks/useResizeObserver.js +2 -2
  17. package/lib/stories/TextInput.stories.js +144 -0
  18. package/lib/stories/Token.stories.js +19 -2
  19. package/lib/utils/useIsomorphicLayoutEffect.d.ts +3 -0
  20. package/lib/utils/useIsomorphicLayoutEffect.js +12 -0
  21. package/lib-esm/Overlay.js +2 -1
  22. package/lib-esm/Portal/Portal.js +2 -1
  23. package/lib-esm/_TextInputWrapper.js +2 -2
  24. package/lib-esm/__tests__/AnchoredOverlay.test.js +4 -2
  25. package/lib-esm/__tests__/TextInputWithTokens.test.js +1 -10
  26. package/lib-esm/hooks/useAnchoredPosition.js +2 -1
  27. package/lib-esm/hooks/useCombinedRefs.d.ts +2 -2
  28. package/lib-esm/hooks/useCombinedRefs.js +3 -2
  29. package/lib-esm/hooks/useResizeObserver.js +2 -2
  30. package/lib-esm/stories/TextInput.stories.js +117 -0
  31. package/lib-esm/stories/Token.stories.js +14 -1
  32. package/lib-esm/utils/useIsomorphicLayoutEffect.d.ts +3 -0
  33. package/lib-esm/utils/useIsomorphicLayoutEffect.js +3 -0
  34. package/migrating.md +1 -1
  35. package/package.json +2 -2
  36. package/src/Overlay.tsx +2 -1
  37. package/src/Portal/Portal.tsx +2 -1
  38. package/src/_TextInputWrapper.tsx +7 -0
  39. package/src/__tests__/AnchoredOverlay.test.tsx +2 -2
  40. package/src/__tests__/TextInputWithTokens.test.tsx +0 -10
  41. package/src/__tests__/__snapshots__/AnchoredOverlay.test.tsx.snap +35 -135
  42. package/src/hooks/useAnchoredPosition.ts +2 -1
  43. package/src/hooks/useCombinedRefs.ts +3 -3
  44. package/src/hooks/useResizeObserver.ts +2 -2
  45. package/src/stories/TextInput.stories.tsx +113 -0
  46. package/src/stories/Token.stories.tsx +12 -1
  47. package/src/utils/useIsomorphicLayoutEffect.ts +10 -0
  48. package/stats.html +1 -1
@@ -0,0 +1,117 @@
1
+ function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
+
3
+ import React, { useState } from 'react';
4
+ import { BaseStyles, Box, ThemeProvider, Text } from '..';
5
+ import TextInput from '../TextInput';
6
+ import { CheckIcon } from '@primer/octicons-react';
7
+ export default {
8
+ title: 'Forms/Text Input',
9
+ component: TextInput,
10
+ decorators: [Story => {
11
+ return /*#__PURE__*/React.createElement(ThemeProvider, null, /*#__PURE__*/React.createElement(BaseStyles, null, /*#__PURE__*/React.createElement(Box, {
12
+ paddingTop: 5
13
+ }, Story())));
14
+ }],
15
+ argTypes: {
16
+ sx: {
17
+ table: {
18
+ disable: true
19
+ }
20
+ },
21
+ block: {
22
+ name: 'Block',
23
+ defaultValue: false,
24
+ control: {
25
+ type: 'boolean'
26
+ }
27
+ },
28
+ disabled: {
29
+ name: 'Disabled',
30
+ defaultValue: false,
31
+ control: {
32
+ type: 'boolean'
33
+ }
34
+ },
35
+ variant: {
36
+ name: 'Variants',
37
+ options: ['small', 'medium', 'large'],
38
+ control: {
39
+ type: 'radio'
40
+ }
41
+ }
42
+ }
43
+ };
44
+
45
+ const Label = ({
46
+ htmlFor,
47
+ children
48
+ }) => /*#__PURE__*/React.createElement(Text, {
49
+ as: "label",
50
+ htmlFor: htmlFor,
51
+ sx: {
52
+ fontWeight: 600,
53
+ fontSize: 14
54
+ }
55
+ }, children);
56
+
57
+ Label.displayName = "Label";
58
+ export const Default = args => {
59
+ const [value, setValue] = useState('');
60
+
61
+ const handleChange = event => {
62
+ setValue(event.target.value);
63
+ };
64
+
65
+ const inputId = 'basic-text-input';
66
+ return /*#__PURE__*/React.createElement("form", null, /*#__PURE__*/React.createElement("div", {
67
+ className: "form-group"
68
+ }, /*#__PURE__*/React.createElement("div", {
69
+ className: "form-group-header"
70
+ }, /*#__PURE__*/React.createElement(Label, {
71
+ htmlFor: inputId
72
+ }, "Example label")), /*#__PURE__*/React.createElement("div", {
73
+ className: "form-group-body"
74
+ }, /*#__PURE__*/React.createElement(TextInput, _extends({
75
+ id: inputId,
76
+ value: value,
77
+ onChange: handleChange
78
+ }, args)))));
79
+ };
80
+ Default.displayName = "Default";
81
+ export const WithLeadingIcon = args => {
82
+ const [value, setValue] = useState('');
83
+
84
+ const handleChange = event => {
85
+ setValue(event.target.value);
86
+ };
87
+
88
+ const inputId = 'basic-text-input-with-leading-icon';
89
+ return /*#__PURE__*/React.createElement("form", null, /*#__PURE__*/React.createElement(Label, {
90
+ htmlFor: inputId
91
+ }, "Example label"), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement(TextInput, _extends({
92
+ icon: CheckIcon,
93
+ id: inputId,
94
+ value: value,
95
+ onChange: handleChange,
96
+ type: "password"
97
+ }, args)));
98
+ };
99
+ WithLeadingIcon.displayName = "WithLeadingIcon";
100
+ export const Password = args => {
101
+ const [value, setValue] = useState('');
102
+
103
+ const handleChange = event => {
104
+ setValue(event.target.value);
105
+ };
106
+
107
+ const inputId = 'basic-text-input-as-password';
108
+ return /*#__PURE__*/React.createElement("form", null, /*#__PURE__*/React.createElement(Label, {
109
+ htmlFor: inputId
110
+ }, "Password"), /*#__PURE__*/React.createElement("br", null), /*#__PURE__*/React.createElement(TextInput, _extends({
111
+ type: "password",
112
+ id: inputId,
113
+ value: value,
114
+ onChange: handleChange
115
+ }, args)));
116
+ };
117
+ Password.displayName = "Password";
@@ -7,6 +7,7 @@ import { BaseStyles, ThemeProvider } from '..';
7
7
  import Box from '../Box';
8
8
  import Token from '../Token/Token';
9
9
  import Text from '../Text';
10
+ import { GitBranchIcon } from '@primer/octicons-react';
10
11
  export default {
11
12
  title: 'Tokens/Default',
12
13
  component: Token,
@@ -19,7 +20,7 @@ export default {
19
20
  return /*#__PURE__*/React.createElement(ThemeProvider, null, /*#__PURE__*/React.createElement(BaseStyles, null, /*#__PURE__*/React.createElement(Story, null)));
20
21
  }]
21
22
  };
22
- const excludedControlKeys = ['id', 'as', 'tabIndex', 'onRemove'];
23
+ const excludedControlKeys = ['id', 'as', 'tabIndex', 'onRemove', 'leadingVisual'];
23
24
 
24
25
  const SingleExampleContainer = ({
25
26
  children,
@@ -91,6 +92,18 @@ Interactive.parameters = {
91
92
  exclude: [...excludedControlKeys, 'hideRemoveButton', 'text']
92
93
  }
93
94
  };
95
+ export const WithLeadingVisual = args => {
96
+ return /*#__PURE__*/React.createElement(ExampleCollectionContainer, null, /*#__PURE__*/React.createElement(Token, _extends({}, args, {
97
+ leadingVisual: () => /*#__PURE__*/React.createElement(GitBranchIcon, null)
98
+ })));
99
+ };
100
+ WithLeadingVisual.displayName = "WithLeadingVisual";
101
+ WithLeadingVisual.storyName = 'with leadingVisual';
102
+ WithLeadingVisual.parameters = {
103
+ controls: {
104
+ exclude: [...excludedControlKeys, 'hideRemoveButton']
105
+ }
106
+ };
94
107
  export const WithOnRemoveFn = args => {
95
108
  return /*#__PURE__*/React.createElement(ExampleCollectionContainer, null, /*#__PURE__*/React.createElement(SingleExampleContainer, {
96
109
  label: "w/ onRemove passed"
@@ -0,0 +1,3 @@
1
+ import { useEffect } from 'react';
2
+ declare const useIsomorphicLayoutEffect: typeof useEffect;
3
+ export default useIsomorphicLayoutEffect;
@@ -0,0 +1,3 @@
1
+ import { useEffect, useLayoutEffect } from 'react';
2
+ const useIsomorphicLayoutEffect = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined' ? useLayoutEffect : useEffect;
3
+ export default useIsomorphicLayoutEffect;
package/migrating.md CHANGED
@@ -110,7 +110,7 @@ There are two ways to change the theme of @primer/components components:
110
110
 
111
111
  export default () => (
112
112
  <ThemeProvider theme={theme}>
113
- <Block color="bodytext" p={4}>
113
+ <Block sx={{color: 'bodytext', p: 4}}>
114
114
  <Text fontSize={4}>Hello, world!</Text>
115
115
  </Block>
116
116
  </ThemeProvider>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primer/components",
3
- "version": "31.2.0-rc.a2a8604e",
3
+ "version": "31.2.0-rc.c7f73427",
4
4
  "description": "Primer react components",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib-esm/index.js",
@@ -15,7 +15,7 @@
15
15
  "start": "concurrently npm:start:*",
16
16
  "start:docs": "cd docs && npm run develop",
17
17
  "start:storybook": "start-storybook -p 6006",
18
- "lint": "eslint '**/*.{js,ts,tsx,md,mdx}'",
18
+ "lint": "eslint '**/*.{js,ts,tsx,md,mdx}' --max-warnings=0",
19
19
  "lint:fix": "npm run lint -- --fix",
20
20
  "test": "jest",
21
21
  "test:update": "npm run test -- --updateSnapshot",
package/src/Overlay.tsx CHANGED
@@ -1,7 +1,8 @@
1
1
  import styled from 'styled-components'
2
- import React, {ReactElement, useEffect, useLayoutEffect, useRef} from 'react'
2
+ import React, {ReactElement, useEffect, useRef} from 'react'
3
3
  import {get, COMMON, SystemPositionProps, SystemCommonProps} from './constants'
4
4
  import {ComponentProps} from './utils/types'
5
+ import useLayoutEffect from './utils/useIsomorphicLayoutEffect'
5
6
  import {useOverlay, TouchOrMouseEvent} from './hooks'
6
7
  import Portal from './Portal'
7
8
  import sx, {SxProp} from './sx'
@@ -1,5 +1,6 @@
1
1
  import React from 'react'
2
2
  import {createPortal} from 'react-dom'
3
+ import useLayoutEffect from '../utils/useIsomorphicLayoutEffect'
3
4
 
4
5
  const PRIMER_PORTAL_ROOT_ID = '__primerPortalRoot__'
5
6
  const DEFAULT_PORTAL_CONTAINER_NAME = '__default__'
@@ -69,7 +70,7 @@ export const Portal: React.FC<PortalProps> = ({children, onMount, containerName:
69
70
  hostElement.style.zIndex = '1'
70
71
  const elementRef = React.useRef(hostElement)
71
72
 
72
- React.useLayoutEffect(() => {
73
+ useLayoutEffect(() => {
73
74
  let containerName = _containerName
74
75
  if (containerName === undefined) {
75
76
  containerName = DEFAULT_PORTAL_CONTAINER_NAME
@@ -91,6 +91,13 @@ const TextInputWrapper = styled.span<StyledWrapperProps>`
91
91
  display: block;
92
92
  width: 100%;
93
93
  `}
94
+
95
+ ${props =>
96
+ props.block &&
97
+ props.hasIcon &&
98
+ css`
99
+ display: flex;
100
+ `}
94
101
 
95
102
  // Ensures inputs don't zoom on mobile but are body-font size on desktop
96
103
  @media (min-width: ${get('breakpoints.1')}) {
@@ -144,7 +144,7 @@ describe('AnchoredOverlay', () => {
144
144
  })
145
145
 
146
146
  it('should render consistently when open', () => {
147
- const anchoredOverlay = HTMLRender(<AnchoredOverlayTestComponent initiallyOpen={true} />)
148
- expect(anchoredOverlay).toMatchSnapshot()
147
+ const {container} = HTMLRender(<AnchoredOverlayTestComponent initiallyOpen={true} />)
148
+ expect(container).toMatchSnapshot()
149
149
  })
150
150
  })
@@ -29,16 +29,6 @@ const LabelledTextInputWithTokens: React.FC<TextInputWithTokensProps> = ({onToke
29
29
  </>
30
30
  )
31
31
 
32
- // describe('axe test', () => {
33
- // it('should have no axe violations', async () => {
34
- // const onRemoveMock = jest.fn()
35
- // const {container} = HTMLRender(<LabelledTextInputWithTokens tokens={mockTokens} onTokenRemove={onRemoveMock} />)
36
- // const results = await axe(container)
37
- // expect(results).toHaveNoViolations()
38
- // cleanup()
39
- // })
40
- // })
41
-
42
32
  jest.useFakeTimers()
43
33
 
44
34
  describe('TextInputWithTokens', () => {
@@ -94,9 +94,7 @@ exports[`AnchoredOverlay renders consistently 1`] = `
94
94
  `;
95
95
 
96
96
  exports[`AnchoredOverlay should render consistently when open 1`] = `
97
- Object {
98
- "asFragment": [Function],
99
- "baseElement": .c0 {
97
+ .c0 {
100
98
  font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
101
99
  line-height: 1.5;
102
100
  color: #24292f;
@@ -187,146 +185,48 @@ Object {
187
185
  outline: none;
188
186
  }
189
187
 
190
- <body>
191
- <div>
192
- <div
193
- class="c0"
194
- color="fg.default"
195
- data-portal-root="true"
196
- font-family="normal"
197
- >
198
- <button
199
- aria-haspopup="true"
200
- aria-labelledby="react-aria-1"
201
- class="c1"
202
- id="react-aria-1"
203
- tabindex="0"
204
- >
205
- Anchor Button
206
- </button>
207
- <div
208
- id="__primerPortalRoot__"
209
- style="position: absolute; top: 0px; left: 0px;"
210
- >
211
- <div
212
- style="position: relative; z-index: 1;"
213
- >
214
- <div
215
- class="c2"
216
- data-focus-trap="active"
217
- height="auto"
218
- role="none"
219
- style="top: 4px; left: 0px; --styled-overlay-visibility: visible;"
220
- width="auto"
221
- >
222
- <button
223
- class="focus-visible"
224
- data-focus-visible-added=""
225
- tabindex="0"
226
- type="button"
227
- >
228
- Focusable Child
229
- </button>
230
- </div>
231
- </div>
232
- </div>
233
- </div>
234
- </div>
235
- </body>,
236
- "container": <div>
188
+ <div>
189
+ <div
190
+ class="c0"
191
+ color="fg.default"
192
+ data-portal-root="true"
193
+ font-family="normal"
194
+ >
195
+ <button
196
+ aria-haspopup="true"
197
+ aria-labelledby="react-aria-1"
198
+ class="c1"
199
+ id="react-aria-1"
200
+ tabindex="0"
201
+ >
202
+ Anchor Button
203
+ </button>
237
204
  <div
238
- class="BaseStyles__Base-qvuaww-0 ihFkAM"
239
- color="fg.default"
240
- data-portal-root="true"
241
- font-family="normal"
205
+ id="__primerPortalRoot__"
206
+ style="position: absolute; top: 0px; left: 0px;"
242
207
  >
243
- <button
244
- aria-haspopup="true"
245
- aria-labelledby="react-aria-1"
246
- class="ButtonBase-sc-181ps9o-0 Button-xjtz72-0 iRqJHc"
247
- id="react-aria-1"
248
- tabindex="0"
249
- >
250
- Anchor Button
251
- </button>
252
208
  <div
253
- id="__primerPortalRoot__"
254
- style="position: absolute; top: 0px; left: 0px;"
209
+ style="position: relative; z-index: 1;"
255
210
  >
256
211
  <div
257
- style="position: relative; z-index: 1;"
212
+ class="c2"
213
+ data-focus-trap="active"
214
+ height="auto"
215
+ role="none"
216
+ style="top: 4px; left: 0px; --styled-overlay-visibility: visible;"
217
+ width="auto"
258
218
  >
259
- <div
260
- class="Overlay__StyledOverlay-jhwkzw-0 jFTKwM"
261
- data-focus-trap="active"
262
- height="auto"
263
- role="none"
264
- style="top: 4px; left: 0px; --styled-overlay-visibility: visible;"
265
- width="auto"
219
+ <button
220
+ class="focus-visible"
221
+ data-focus-visible-added=""
222
+ tabindex="0"
223
+ type="button"
266
224
  >
267
- <button
268
- class="focus-visible"
269
- data-focus-visible-added=""
270
- tabindex="0"
271
- type="button"
272
- >
273
- Focusable Child
274
- </button>
275
- </div>
225
+ Focusable Child
226
+ </button>
276
227
  </div>
277
228
  </div>
278
229
  </div>
279
- </div>,
280
- "debug": [Function],
281
- "findAllByAltText": [Function],
282
- "findAllByDisplayValue": [Function],
283
- "findAllByLabelText": [Function],
284
- "findAllByPlaceholderText": [Function],
285
- "findAllByRole": [Function],
286
- "findAllByTestId": [Function],
287
- "findAllByText": [Function],
288
- "findAllByTitle": [Function],
289
- "findByAltText": [Function],
290
- "findByDisplayValue": [Function],
291
- "findByLabelText": [Function],
292
- "findByPlaceholderText": [Function],
293
- "findByRole": [Function],
294
- "findByTestId": [Function],
295
- "findByText": [Function],
296
- "findByTitle": [Function],
297
- "getAllByAltText": [Function],
298
- "getAllByDisplayValue": [Function],
299
- "getAllByLabelText": [Function],
300
- "getAllByPlaceholderText": [Function],
301
- "getAllByRole": [Function],
302
- "getAllByTestId": [Function],
303
- "getAllByText": [Function],
304
- "getAllByTitle": [Function],
305
- "getByAltText": [Function],
306
- "getByDisplayValue": [Function],
307
- "getByLabelText": [Function],
308
- "getByPlaceholderText": [Function],
309
- "getByRole": [Function],
310
- "getByTestId": [Function],
311
- "getByText": [Function],
312
- "getByTitle": [Function],
313
- "queryAllByAltText": [Function],
314
- "queryAllByDisplayValue": [Function],
315
- "queryAllByLabelText": [Function],
316
- "queryAllByPlaceholderText": [Function],
317
- "queryAllByRole": [Function],
318
- "queryAllByTestId": [Function],
319
- "queryAllByText": [Function],
320
- "queryAllByTitle": [Function],
321
- "queryByAltText": [Function],
322
- "queryByDisplayValue": [Function],
323
- "queryByLabelText": [Function],
324
- "queryByPlaceholderText": [Function],
325
- "queryByRole": [Function],
326
- "queryByTestId": [Function],
327
- "queryByText": [Function],
328
- "queryByTitle": [Function],
329
- "rerender": [Function],
330
- "unmount": [Function],
331
- }
230
+ </div>
231
+ </div>
332
232
  `;
@@ -2,6 +2,7 @@ import React from 'react'
2
2
  import {PositionSettings, getAnchoredPosition, AnchorPosition} from '../behaviors/anchoredPosition'
3
3
  import {useProvidedRefOrCreate} from './useProvidedRefOrCreate'
4
4
  import {useResizeObserver} from './useResizeObserver'
5
+ import useLayoutEffect from '../utils/useIsomorphicLayoutEffect'
5
6
 
6
7
  export interface AnchoredPositionHookSettings extends Partial<PositionSettings> {
7
8
  floatingElementRef?: React.RefObject<Element>
@@ -41,7 +42,7 @@ export function useAnchoredPosition(
41
42
  [floatingElementRef, anchorElementRef, ...dependencies]
42
43
  )
43
44
 
44
- React.useLayoutEffect(updatePosition, [updatePosition])
45
+ useLayoutEffect(updatePosition, [updatePosition])
45
46
 
46
47
  useResizeObserver(updatePosition)
47
48
 
@@ -1,4 +1,5 @@
1
- import React, {ForwardedRef, useRef} from 'react'
1
+ import {ForwardedRef, useRef} from 'react'
2
+ import useLayoutEffect from '../utils/useIsomorphicLayoutEffect'
2
3
 
3
4
  /**
4
5
  * Creates a ref by combining multiple constituent refs. The ref returned by this hook
@@ -11,7 +12,7 @@ import React, {ForwardedRef, useRef} from 'react'
11
12
  export function useCombinedRefs<T>(...refs: (ForwardedRef<T> | null | undefined)[]) {
12
13
  const combinedRef = useRef<T | null>(null)
13
14
 
14
- React.useLayoutEffect(() => {
15
+ useLayoutEffect(() => {
15
16
  function setRefs(current: T | null = null) {
16
17
  for (const ref of refs) {
17
18
  if (!ref) {
@@ -32,7 +33,6 @@ export function useCombinedRefs<T>(...refs: (ForwardedRef<T> | null | undefined)
32
33
  // eslint-disable-next-line react-hooks/exhaustive-deps
33
34
  setRefs(combinedRef.current)
34
35
  }
35
-
36
36
  // eslint-disable-next-line react-hooks/exhaustive-deps
37
37
  }, [...refs, combinedRef.current])
38
38
 
@@ -1,7 +1,7 @@
1
- import React from 'react'
1
+ import useLayoutEffect from '../utils/useIsomorphicLayoutEffect'
2
2
 
3
3
  export function useResizeObserver(callback: () => void) {
4
- React.useLayoutEffect(() => {
4
+ useLayoutEffect(() => {
5
5
  const observer = new window.ResizeObserver(() => callback())
6
6
  observer.observe(document.documentElement)
7
7
  return () => {
@@ -0,0 +1,113 @@
1
+ import React, {useState, ReactNode} from 'react'
2
+ import {Meta} from '@storybook/react'
3
+
4
+ import {BaseStyles, Box, ThemeProvider, Text} from '..'
5
+ import TextInput, {TextInputProps} from '../TextInput'
6
+ import {CheckIcon} from '@primer/octicons-react'
7
+
8
+ export default {
9
+ title: 'Forms/Text Input',
10
+ component: TextInput,
11
+ decorators: [
12
+ Story => {
13
+ return (
14
+ <ThemeProvider>
15
+ <BaseStyles>
16
+ <Box paddingTop={5}>{Story()}</Box>
17
+ </BaseStyles>
18
+ </ThemeProvider>
19
+ )
20
+ }
21
+ ],
22
+ argTypes: {
23
+ sx: {
24
+ table: {
25
+ disable: true
26
+ }
27
+ },
28
+ block: {
29
+ name: 'Block',
30
+ defaultValue: false,
31
+ control: {
32
+ type: 'boolean'
33
+ }
34
+ },
35
+ disabled: {
36
+ name: 'Disabled',
37
+ defaultValue: false,
38
+ control: {
39
+ type: 'boolean'
40
+ }
41
+ },
42
+ variant: {
43
+ name: 'Variants',
44
+ options: ['small', 'medium', 'large'],
45
+ control: {type: 'radio'}
46
+ }
47
+ }
48
+ } as Meta
49
+
50
+ const Label = ({htmlFor, children}: {htmlFor: string; children: ReactNode}) => (
51
+ <Text as="label" htmlFor={htmlFor} sx={{fontWeight: 600, fontSize: 14}}>
52
+ {children}
53
+ </Text>
54
+ )
55
+
56
+ export const Default = (args: TextInputProps) => {
57
+ const [value, setValue] = useState('')
58
+
59
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
60
+ setValue(event.target.value)
61
+ }
62
+
63
+ const inputId = 'basic-text-input'
64
+
65
+ return (
66
+ <form>
67
+ <div className="form-group">
68
+ <div className="form-group-header">
69
+ <Label htmlFor={inputId}>Example label</Label>
70
+ </div>
71
+ <div className="form-group-body">
72
+ <TextInput id={inputId} value={value} onChange={handleChange} {...args} />
73
+ </div>
74
+ </div>
75
+ </form>
76
+ )
77
+ }
78
+
79
+ export const WithLeadingIcon = (args: TextInputProps) => {
80
+ const [value, setValue] = useState('')
81
+
82
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
83
+ setValue(event.target.value)
84
+ }
85
+
86
+ const inputId = 'basic-text-input-with-leading-icon'
87
+
88
+ return (
89
+ <form>
90
+ <Label htmlFor={inputId}>Example label</Label>
91
+ <br />
92
+ <TextInput icon={CheckIcon} id={inputId} value={value} onChange={handleChange} type="password" {...args} />
93
+ </form>
94
+ )
95
+ }
96
+
97
+ export const Password = (args: TextInputProps) => {
98
+ const [value, setValue] = useState('')
99
+
100
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
101
+ setValue(event.target.value)
102
+ }
103
+
104
+ const inputId = 'basic-text-input-as-password'
105
+
106
+ return (
107
+ <form>
108
+ <Label htmlFor={inputId}>Password</Label>
109
+ <br />
110
+ <TextInput type="password" id={inputId} value={value} onChange={handleChange} {...args} />
111
+ </form>
112
+ )
113
+ }
@@ -7,6 +7,7 @@ import {BaseStyles, ThemeProvider} from '..'
7
7
  import Box from '../Box'
8
8
  import Token, {TokenProps} from '../Token/Token'
9
9
  import Text from '../Text'
10
+ import {GitBranchIcon} from '@primer/octicons-react'
10
11
 
11
12
  export default {
12
13
  title: 'Tokens/Default',
@@ -29,7 +30,7 @@ export default {
29
30
  ]
30
31
  } as Meta
31
32
 
32
- const excludedControlKeys = ['id', 'as', 'tabIndex', 'onRemove']
33
+ const excludedControlKeys = ['id', 'as', 'tabIndex', 'onRemove', 'leadingVisual']
33
34
 
34
35
  const SingleExampleContainer: React.FC<{label?: string}> = ({children, label}) => (
35
36
  <Box
@@ -94,6 +95,16 @@ export const Interactive = (args: Omit<TokenProps, 'ref' | 'text'>) => {
94
95
  }
95
96
  Interactive.parameters = {controls: {exclude: [...excludedControlKeys, 'hideRemoveButton', 'text']}}
96
97
 
98
+ export const WithLeadingVisual = (args: Omit<TokenProps, 'ref'>) => {
99
+ return (
100
+ <ExampleCollectionContainer>
101
+ <Token {...args} leadingVisual={() => <GitBranchIcon />} />
102
+ </ExampleCollectionContainer>
103
+ )
104
+ }
105
+ WithLeadingVisual.storyName = 'with leadingVisual'
106
+ WithLeadingVisual.parameters = {controls: {exclude: [...excludedControlKeys, 'hideRemoveButton']}}
107
+
97
108
  export const WithOnRemoveFn = (args: Omit<TokenProps, 'ref'>) => {
98
109
  return (
99
110
  <ExampleCollectionContainer>
@@ -0,0 +1,10 @@
1
+ import {useEffect, useLayoutEffect} from 'react'
2
+
3
+ const useIsomorphicLayoutEffect =
4
+ typeof window !== 'undefined' &&
5
+ typeof window.document !== 'undefined' &&
6
+ typeof window.document.createElement !== 'undefined'
7
+ ? useLayoutEffect
8
+ : useEffect
9
+
10
+ export default useIsomorphicLayoutEffect