@arbor-education/design-system.components 0.3.4 → 0.3.6

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 (88) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/CLAUDE.md +146 -0
  3. package/dist/components/editableText/EditableText.d.ts +10 -0
  4. package/dist/components/editableText/EditableText.d.ts.map +1 -0
  5. package/dist/components/editableText/EditableText.js +36 -0
  6. package/dist/components/editableText/EditableText.js.map +1 -0
  7. package/dist/components/editableText/EditableText.stories.d.ts +44 -0
  8. package/dist/components/editableText/EditableText.stories.d.ts.map +1 -0
  9. package/dist/components/editableText/EditableText.stories.js +94 -0
  10. package/dist/components/editableText/EditableText.stories.js.map +1 -0
  11. package/dist/components/editableText/EditableText.test.d.ts +2 -0
  12. package/dist/components/editableText/EditableText.test.d.ts.map +1 -0
  13. package/dist/components/editableText/EditableText.test.js +187 -0
  14. package/dist/components/editableText/EditableText.test.js.map +1 -0
  15. package/dist/components/heading/Heading.stories.d.ts +26 -0
  16. package/dist/components/heading/Heading.stories.d.ts.map +1 -1
  17. package/dist/components/heading/Heading.stories.js +35 -0
  18. package/dist/components/heading/Heading.stories.js.map +1 -1
  19. package/dist/components/progress/Progress.d.ts +6 -0
  20. package/dist/components/progress/Progress.d.ts.map +1 -0
  21. package/dist/components/progress/Progress.js +9 -0
  22. package/dist/components/progress/Progress.js.map +1 -0
  23. package/dist/components/progress/Progress.stories.d.ts +324 -0
  24. package/dist/components/progress/Progress.stories.d.ts.map +1 -0
  25. package/dist/components/progress/Progress.stories.js +77 -0
  26. package/dist/components/progress/Progress.stories.js.map +1 -0
  27. package/dist/components/progress/Progress.test.d.ts +2 -0
  28. package/dist/components/progress/Progress.test.d.ts.map +1 -0
  29. package/dist/components/progress/Progress.test.js +77 -0
  30. package/dist/components/progress/Progress.test.js.map +1 -0
  31. package/dist/components/tag/Tag.d.ts +4 -2
  32. package/dist/components/tag/Tag.d.ts.map +1 -1
  33. package/dist/components/tag/Tag.js +3 -3
  34. package/dist/components/tag/Tag.js.map +1 -1
  35. package/dist/components/tag/Tag.stories.d.ts +3 -1
  36. package/dist/components/tag/Tag.stories.d.ts.map +1 -1
  37. package/dist/components/tag/Tag.stories.js +4 -1
  38. package/dist/components/tag/Tag.stories.js.map +1 -1
  39. package/dist/components/tag/Tag.test.js +40 -2
  40. package/dist/components/tag/Tag.test.js.map +1 -1
  41. package/dist/components/toast/Toast.d.ts +10 -0
  42. package/dist/components/toast/Toast.d.ts.map +1 -0
  43. package/dist/components/toast/Toast.js +20 -0
  44. package/dist/components/toast/Toast.js.map +1 -0
  45. package/dist/components/toast/Toast.stories.d.ts +12 -0
  46. package/dist/components/toast/Toast.stories.d.ts.map +1 -0
  47. package/dist/components/toast/Toast.stories.js +73 -0
  48. package/dist/components/toast/Toast.stories.js.map +1 -0
  49. package/dist/components/toast/Toast.test.d.ts +2 -0
  50. package/dist/components/toast/Toast.test.d.ts.map +1 -0
  51. package/dist/components/toast/Toast.test.js +87 -0
  52. package/dist/components/toast/Toast.test.js.map +1 -0
  53. package/dist/components/toast/ToastViewport.d.ts +3 -0
  54. package/dist/components/toast/ToastViewport.d.ts.map +1 -0
  55. package/dist/components/toast/ToastViewport.js +5 -0
  56. package/dist/components/toast/ToastViewport.js.map +1 -0
  57. package/dist/index.css +172 -6
  58. package/dist/index.css.map +1 -1
  59. package/dist/index.d.ts +3 -0
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +3 -0
  62. package/dist/index.js.map +1 -1
  63. package/package.json +1 -1
  64. package/setupTestRuntime.ts +7 -0
  65. package/src/components/button/button.scss +1 -0
  66. package/src/components/editableText/EditableText.stories.tsx +136 -0
  67. package/src/components/editableText/EditableText.test.tsx +242 -0
  68. package/src/components/editableText/EditableText.tsx +73 -0
  69. package/src/components/editableText/editableText.scss +54 -0
  70. package/src/components/formField/inputs/input.scss +1 -2
  71. package/src/components/heading/Heading.stories.tsx +58 -0
  72. package/src/components/heading/heading.scss +4 -4
  73. package/src/components/progress/Progress.stories.tsx +90 -0
  74. package/src/components/progress/Progress.test.tsx +88 -0
  75. package/src/components/progress/Progress.tsx +16 -0
  76. package/src/components/progress/progress.scss +13 -0
  77. package/src/components/tag/Tag.stories.tsx +2 -0
  78. package/src/components/tag/Tag.test.tsx +46 -2
  79. package/src/components/tag/Tag.tsx +12 -2
  80. package/src/components/tag/tag.scss +39 -0
  81. package/src/components/toast/Toast.stories.tsx +113 -0
  82. package/src/components/toast/Toast.test.tsx +126 -0
  83. package/src/components/toast/Toast.tsx +35 -0
  84. package/src/components/toast/ToastViewport.tsx +6 -0
  85. package/src/components/toast/toast.scss +80 -0
  86. package/src/index.scss +3 -0
  87. package/src/index.ts +3 -0
  88. package/src/tokens.scss +2 -0
@@ -0,0 +1,126 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import { describe, it, expect, vi } from 'vitest';
3
+ import { Toast } from './Toast';
4
+ import userEvent from '@testing-library/user-event';
5
+ import '@testing-library/jest-dom/vitest';
6
+
7
+ describe('Toast', () => {
8
+ const renderToast = (props = {}) => {
9
+ return render(
10
+ <Toast.Provider>
11
+ <Toast open={true} {...props}>
12
+ Test message
13
+ </Toast>
14
+ <Toast.Viewport />
15
+ </Toast.Provider>,
16
+ );
17
+ };
18
+
19
+ describe('rendering', () => {
20
+ it('renders the toast with content', () => {
21
+ renderToast();
22
+ expect(screen.getByText('Test message')).toBeInTheDocument();
23
+ });
24
+
25
+ it('renders with information variant by default', () => {
26
+ const { container } = renderToast();
27
+ const toast = container.querySelector('.ds-toast--information');
28
+ expect(toast).toBeInTheDocument();
29
+ });
30
+
31
+ it('renders with the correct class for each variant', () => {
32
+ const variants = ['information', 'danger', 'success', 'warning'] as const;
33
+
34
+ variants.forEach((variant) => {
35
+ const { container, unmount } = renderToast({ variant });
36
+ const toast = container.querySelector(`.ds-toast--${variant}`);
37
+ expect(toast).toBeInTheDocument();
38
+ unmount();
39
+ });
40
+ });
41
+ });
42
+
43
+ describe('icons', () => {
44
+ it('renders info icon for information variant', () => {
45
+ const { container } = renderToast({ variant: 'information' });
46
+ expect(container.querySelector('.ds-icon-info')).toBeInTheDocument();
47
+ });
48
+
49
+ it('renders circle-alert icon for danger variant', () => {
50
+ const { container } = renderToast({ variant: 'danger' });
51
+ expect(container.querySelector('.ds-icon-circle-alert')).toBeInTheDocument();
52
+ });
53
+
54
+ it('renders circle-check icon for success variant', () => {
55
+ const { container } = renderToast({ variant: 'success' });
56
+ expect(container.querySelector('.ds-icon-circle-check')).toBeInTheDocument();
57
+ });
58
+
59
+ it('renders triangle-alert icon for warning variant', () => {
60
+ const { container } = renderToast({ variant: 'warning' });
61
+ expect(container.querySelector('.ds-icon-triangle-alert')).toBeInTheDocument();
62
+ });
63
+
64
+ it('renders close icon with screen reader text', () => {
65
+ renderToast();
66
+ expect(screen.getByText('Close')).toBeInTheDocument();
67
+ });
68
+ });
69
+
70
+ describe('interactions', () => {
71
+ it('calls onOpenChange when close button is clicked', async () => {
72
+ const user = userEvent.setup();
73
+ const onOpenChange = vi.fn();
74
+
75
+ render(
76
+ <Toast.Provider>
77
+ <Toast open={true} onOpenChange={onOpenChange}>
78
+ Test message
79
+ </Toast>
80
+ <Toast.Viewport />
81
+ </Toast.Provider>,
82
+ );
83
+
84
+ const closeButton = screen.getByRole('button');
85
+ await user.click(closeButton);
86
+
87
+ expect(onOpenChange).toHaveBeenCalled();
88
+ });
89
+ });
90
+
91
+ describe('Provider and Viewport', () => {
92
+ it('exposes Provider component', () => {
93
+ expect(Toast.Provider).toBeDefined();
94
+ });
95
+
96
+ it('exposes Viewport component', () => {
97
+ expect(Toast.Viewport).toBeDefined();
98
+ });
99
+ });
100
+
101
+ describe('custom props', () => {
102
+ it('passes through additional props to Root', () => {
103
+ const { container } = renderToast({
104
+ 'data-testid': 'custom-toast',
105
+ });
106
+
107
+ const toast = container.querySelector('[data-testid="custom-toast"]');
108
+ expect(toast).toBeInTheDocument();
109
+ });
110
+
111
+ it('applies custom className alongside default classes', () => {
112
+ renderToast();
113
+ const { container } = render(
114
+ <Toast.Provider>
115
+ <Toast open={true} variant="success">
116
+ Success message
117
+ </Toast>
118
+ <Toast.Viewport />
119
+ </Toast.Provider>,
120
+ );
121
+
122
+ const toast = container.querySelector('.ds-toast.ds-toast--success');
123
+ expect(toast).toBeInTheDocument();
124
+ });
125
+ });
126
+ });
@@ -0,0 +1,35 @@
1
+ import classNames from 'classnames';
2
+ import { Toast as RadixToast } from 'radix-ui';
3
+ import { ToastViewport } from './ToastViewport';
4
+ import { Icon } from 'Components/icon/Icon';
5
+
6
+ export type ToastProps = RadixToast.ToastProps & {
7
+ variant?: 'information' | 'danger' | 'success' | 'warning';
8
+ };
9
+
10
+ export const Toast = (props: ToastProps) => {
11
+ const { children, variant = 'information', ...rest } = props;
12
+ const classes = classNames('ds-toast', `ds-toast--${variant}`);
13
+
14
+ const iconName = {
15
+ information: 'info',
16
+ danger: 'circle-alert',
17
+ success: 'circle-check',
18
+ warning: 'triangle-alert',
19
+ } as const;
20
+
21
+ const icon = iconName[variant];
22
+
23
+ return (
24
+ <RadixToast.Root {...rest} className={classes}>
25
+ <Icon className="ds-toast__icon" name={icon} />
26
+ <RadixToast.Title className="ds-toast__title">{children}</RadixToast.Title>
27
+ <RadixToast.Close className="ds-toast__close ds-button ds-button--secondary ds-button--icon-only ds-button--borderless">
28
+ <Icon name="x" screenReaderText="Close" />
29
+ </RadixToast.Close>
30
+ </RadixToast.Root>
31
+ );
32
+ };
33
+
34
+ Toast.Provider = RadixToast.Provider;
35
+ Toast.Viewport = ToastViewport;
@@ -0,0 +1,6 @@
1
+ import classNames from 'classnames';
2
+ import { Toast } from 'radix-ui';
3
+
4
+ export const ToastViewport = ({ className, ...rest }: Toast.ToastViewportProps) => (
5
+ <Toast.Viewport className={classNames('ds-toast__viewport', className)} {...rest} />
6
+ );
@@ -0,0 +1,80 @@
1
+ .ds-toast__viewport {
2
+ margin: 0;
3
+ padding: 0;
4
+ list-style: none;
5
+ top: 0;
6
+ right: 0;
7
+ position: fixed;
8
+ }
9
+
10
+ .ds-toast {
11
+ display: flex;
12
+ align-items: center;
13
+ justify-content: space-between;
14
+ border: var(--border-weight) solid;
15
+ gap: var(--toast-spacing-gap);
16
+ padding: var(--toast-spacing-padding);
17
+ border-radius: var(--toast-radius);
18
+ box-shadow: var(--shadow-small);
19
+ font-family: var(--type-body-bold-family);
20
+ font-size: var(--type-body-p-size);
21
+ font-style: normal;
22
+ font-weight: var(--type-body-bold-weight);
23
+ line-height: var(--line-height-default);
24
+ max-width: var(--toast-max-width);
25
+
26
+ &__icon {
27
+ flex-shrink: 0;
28
+ }
29
+
30
+ &__close {
31
+ flex-shrink: 0;
32
+ background-color: transparent;
33
+ border: none;
34
+ color: currentColor;
35
+ padding: 0;
36
+ margin: 0;
37
+ cursor: pointer;
38
+
39
+ }
40
+
41
+ &--information {
42
+ border-color: var(--toast-info-color-border);
43
+ background-color: var(--toast-info-color-background);
44
+ color: var(--toast-info-color-text);
45
+
46
+ .ds-toast__close:hover {
47
+ background: var(--toast-info-icon-hover-color-background);
48
+ }
49
+ }
50
+
51
+ &--danger {
52
+ border-color: var(--toast-destructive-color-border);
53
+ background-color: var(--toast-destructive-color-background);
54
+ color: var(--toast-destructive-color-text);
55
+
56
+ .ds-toast__close:hover {
57
+ background: var(--toast-destructive-icon-hover-color-background);
58
+ }
59
+ }
60
+
61
+ &--success {
62
+ border-color: var(--toast-success-color-border);
63
+ background-color: var(--toast-success-color-background);
64
+ color: var(--toast-success-color-text);
65
+
66
+ .ds-toast__close:hover {
67
+ background: var(--toast-success-icon-hover-color-background);
68
+ }
69
+ }
70
+
71
+ &--warning {
72
+ border-color: var(--toast-warning-color-border);
73
+ background-color: var(--toast-warning-color-background);
74
+ color: var(--toast-warning-color-text);
75
+
76
+ .ds-toast__close:hover {
77
+ background: var(--toast-warning-icon-hover-color-background);
78
+ }
79
+ }
80
+ }
package/src/index.scss CHANGED
@@ -28,4 +28,7 @@
28
28
  @use "components/modal/modal.scss";
29
29
  @use "components/modal/modalManager/modalManager.scss";
30
30
  @use "components/table/columnFilters/columnFilters.scss";
31
+ @use "components/editableText/editableText.scss";
32
+ @use "components/progress/progress.scss";
33
+ @use "components/toast/toast.scss";
31
34
  @import "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap";
package/src/index.ts CHANGED
@@ -26,3 +26,6 @@ export { Modal } from 'Components/modal/Modal';
26
26
  export { ModalManager } from 'Components/modal/modalManager/ModalManager';
27
27
  export { DSDefaultColDef } from 'Components/table/DSDefaultColDef';
28
28
  export { DefaultCellRenderer } from 'Components/table/cellRenderers/DefaultCellRenderer';
29
+ export { EditableText } from 'Components/editableText/EditableText';
30
+ export { Progress } from 'Components/progress/Progress';
31
+ export { Toast } from 'Components/toast/Toast';
package/src/tokens.scss CHANGED
@@ -25,6 +25,7 @@
25
25
  --size-control-medium: 3rem;
26
26
  --size-control-large: 4rem;
27
27
  --size-control-xlarge: 5rem;
28
+ --shadow-small: 0 4px 12px 0 rgba(32, 32, 32, 0.08);
28
29
  --page-sign-in-color-background: #fffcf8;
29
30
  --color-grey-100: #efefef;
30
31
  --color-grey-200: #dfdfdf;
@@ -334,6 +335,7 @@
334
335
  --modal-radius: var(--border-radius-small);
335
336
  --modal-color-background: var(--color-grey-050);
336
337
  --modal-min-width: 37.5rem;
338
+ --toast-max-width: 360px;
337
339
  --toast-info-icon-hover-color-background: var(--color-semantic-info-100);
338
340
  --toast-info-icon-color-icon: var(--color-semantic-info-800);
339
341
  --toast-info-color-text: var(--color-semantic-info-800);