@raspberrypifoundation/design-system-react 2.10.4 → 2.11.1

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.
@@ -30,6 +30,16 @@
30
30
  --rpf-button-lg-height: var(--lg-target-size);
31
31
  --rpf-button-sm-height: var(--sm-target-size);
32
32
  --rpf-button-min-target-size: var(--min-target-size);
33
+
34
+ --rpf-button-spinner-color: currentcolor;
35
+ --rpf-button-spinner-size: .6em;
36
+ --rpf-button-spinner-track-width: var(--border-width-lg);
37
+ }
38
+
39
+ @keyframes rpf-button-spin {
40
+ to {
41
+ transform: rotate(360deg);
42
+ }
33
43
  }
34
44
 
35
45
  .rpf-button {
@@ -86,7 +96,8 @@
86
96
  }
87
97
 
88
98
  &:disabled,
89
- &--disabled {
99
+ &--disabled,
100
+ &--loading {
90
101
  cursor: default;
91
102
 
92
103
  &::before,
@@ -96,6 +107,45 @@
96
107
  }
97
108
  }
98
109
 
110
+ &--loading {
111
+ /* More accurate than `cursor: default` - the button is still targetable, just busy */
112
+ cursor: not-allowed;
113
+ justify-content: center;
114
+
115
+ .text {
116
+ display: grid;
117
+ justify-items: center;
118
+
119
+ > * {
120
+ grid-area: 1 / 1;
121
+ }
122
+
123
+ &__idle--hidden {
124
+ visibility: hidden;
125
+ }
126
+
127
+ &__loading {
128
+ align-items: center;
129
+ display: flex;
130
+ gap: var(--space-1);
131
+ }
132
+ }
133
+ }
134
+
135
+ &__spinner {
136
+ animation: rpf-button-spin 1s linear infinite;
137
+ block-size: var(--rpf-button-spinner-size);
138
+ border: var(--rpf-button-spinner-track-width) solid var(--rpf-button-spinner-track-color, color-mix(in srgb, var(--rpf-button-spinner-color) 25%, transparent));
139
+ border-inline-start-color: var(--rpf-button-spinner-color);
140
+ border-radius: 50%;
141
+ flex-shrink: 0;
142
+ inline-size: var(--rpf-button-spinner-size);
143
+
144
+ @media (prefers-reduced-motion: reduce) {
145
+ animation-duration: 1.5s;
146
+ }
147
+ }
148
+
99
149
  &--secondary {
100
150
  color: var(--rpf-button-background-color);
101
151
 
@@ -122,7 +172,8 @@
122
172
  }
123
173
 
124
174
  &:disabled,
125
- &.rpf-button--disabled {
175
+ &.rpf-button--disabled,
176
+ &.rpf-button--loading {
126
177
  color: var(--rpf-button-background-color-disabled);
127
178
 
128
179
  &:hover::before,
@@ -158,7 +209,8 @@
158
209
  }
159
210
 
160
211
  &:disabled,
161
- &.rpf-button--disabled {
212
+ &.rpf-button--disabled,
213
+ &.rpf-button--loading {
162
214
  color: var(--rpf-button-danger-background-color-disabled);
163
215
 
164
216
  &:hover::before,
@@ -199,7 +251,8 @@
199
251
  }
200
252
 
201
253
  &:disabled,
202
- &.rpf-button--disabled {
254
+ &.rpf-button--disabled,
255
+ &.rpf-button--loading {
203
256
  color: var(--rpf-button-background-color-disabled);
204
257
 
205
258
  &::before,
@@ -235,7 +288,8 @@
235
288
  }
236
289
 
237
290
  &:disabled,
238
- &.rpf-button--disabled {
291
+ &.rpf-button--disabled,
292
+ &.rpf-button--loading {
239
293
  color: var(--rpf-button-danger-background-color-disabled);
240
294
 
241
295
  &::before,
@@ -268,6 +322,16 @@
268
322
  &:focus-visible::before {
269
323
  outline: var(--border-width-md) solid var(--rpf-button-danger-background-color);
270
324
  }
325
+
326
+ &:disabled,
327
+ &.rpf-button--disabled,
328
+ &.rpf-button--loading {
329
+ &::before,
330
+ &:hover::before {
331
+ background-color: var(--rpf-button-danger-background-color-disabled);
332
+ border-color: var(--rpf-button-danger-border-color-disabled, var(--rpf-button-danger-background-color-disabled));
333
+ }
334
+ }
271
335
  }
272
336
 
273
337
  &--icon-only {
@@ -12,6 +12,13 @@ export type ButtonProps = {
12
12
  size?: "default" | "small";
13
13
  /** Whether the button is disabled */
14
14
  disabled?: boolean;
15
+ /**
16
+ * Shows a spinner, blocks clicks and announces `loadingText`, while keeping focus.
17
+ * Pass a boolean from the first render, and set it before any `await` in `onClick`.
18
+ */
19
+ loading?: boolean;
20
+ /** Visible label and status announcement while loading (pass a translated string). Defaults to "Loading" */
21
+ loadingText?: string;
15
22
  /** The href attribute for link buttons */
16
23
  href?: string;
17
24
  /** The icon name */
@@ -1 +1 @@
1
- {"version":3,"file":"Button.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/Button/Button.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzD,MAAM,MAAM,WAAW,GAAG;IACxB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,IAAI,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;IAC5C,gCAAgC;IAChC,OAAO,CAAC,EAAE,EAAE,GAAG,QAAQ,CAAC;IACxB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC3B,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB;IACpB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IAC/D,kCAAkC;IAClC,aAAa,CAAC,EAAE,WAAW,CAAC;IAC5B,iBAAiB;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC"}
1
+ {"version":3,"file":"Button.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/Button/Button.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzD,MAAM,MAAM,WAAW,GAAG;IACxB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,IAAI,CAAC,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;IAC5C,gCAAgC;IAChC,OAAO,CAAC,EAAE,EAAE,GAAG,QAAQ,CAAC;IACxB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC3B,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4GAA4G;IAC5G,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB;IACpB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAChC,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IAC/D,kCAAkC;IAClC,aAAa,CAAC,EAAE,WAAW,CAAC;IAC5B,iBAAiB;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import "@/components/MaterialSymbols";
2
2
  import "./Button.scss";
3
3
  import type { ButtonProps } from "./Button.types";
4
- export declare const Button: ({ text, href, title, className, type, variant, size, icon, iconOnly, iconPosition, fullWidth, disabled, onClick, "aria-label": ariaLabel, linkComponent, }: ButtonProps) => import("react/jsx-runtime").JSX.Element;
4
+ export declare const Button: ({ text, href, title, className, type, variant, size, icon, iconOnly, iconPosition, fullWidth, disabled, loading, loadingText, onClick, "aria-label": ariaLabel, linkComponent, }: ButtonProps) => import("react/jsx-runtime").JSX.Element;
5
5
  export default Button;
6
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Button/index.tsx"],"names":[],"mappings":"AAAA,OAAO,8BAA8B,CAAC;AAGtC,OAAO,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,eAAO,MAAM,MAAM,GAAI,4JAgBpB,WAAW,4CA6Eb,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Button/index.tsx"],"names":[],"mappings":"AAAA,OAAO,8BAA8B,CAAC;AAGtC,OAAO,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,eAAO,MAAM,MAAM,GAAI,kLAkBpB,WAAW,4CAyIb,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -69,6 +69,35 @@ export namespace Danger {
69
69
  }
70
70
  export { args_9 as args };
71
71
  }
72
+ export namespace Loading {
73
+ export namespace args_10 {
74
+ let loading: boolean;
75
+ let loadingText: string;
76
+ }
77
+ export { args_10 as args };
78
+ }
79
+ export namespace LoadingInteractive {
80
+ export function render(args: any): import("react/jsx-runtime").JSX.Element;
81
+ export namespace args_11 {
82
+ let loadingText_1: string;
83
+ export { loadingText_1 as loadingText };
84
+ }
85
+ export { args_11 as args };
86
+ }
87
+ export namespace LoadingLink {
88
+ export namespace args_12 {
89
+ let href_2: string;
90
+ export { href_2 as href };
91
+ export { Link as linkComponent };
92
+ let loading_1: boolean;
93
+ export { loading_1 as loading };
94
+ let loadingText_2: string;
95
+ export { loadingText_2 as loadingText };
96
+ }
97
+ export { args_12 as args };
98
+ let decorators_2: ((Story: any) => import("react/jsx-runtime").JSX.Element)[];
99
+ export { decorators_2 as decorators };
100
+ }
72
101
  declare namespace options {
73
102
  export let title: string;
74
103
  export { Button as component };
@@ -116,8 +145,22 @@ declare namespace options {
116
145
  export { options_3 as options };
117
146
  }
118
147
  export { iconPosition_1 as iconPosition };
148
+ export namespace loading_2 {
149
+ let control_4: string;
150
+ export { control_4 as control };
151
+ let description_1: string;
152
+ export { description_1 as description };
153
+ }
154
+ export { loading_2 as loading };
155
+ export namespace loadingText_3 {
156
+ let control_5: string;
157
+ export { control_5 as control };
158
+ let description_2: string;
159
+ export { description_2 as description };
160
+ }
161
+ export { loadingText_3 as loadingText };
119
162
  }
120
- let args_10: {
163
+ let args_13: {
121
164
  text: string;
122
165
  type: string;
123
166
  variant: string;
@@ -133,8 +176,10 @@ declare namespace options {
133
176
  onClick: null;
134
177
  "aria-label": string;
135
178
  linkComponent: null;
179
+ loading: undefined;
180
+ loadingText: string;
136
181
  };
137
- export { args_10 as args };
182
+ export { args_13 as args };
138
183
  }
139
184
  import { Link } from "react-router-dom";
140
185
  //# sourceMappingURL=Button.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Button.stories.d.ts","sourceRoot":"","sources":["../../../../src/stories/Button.stories.jsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBACoC,kBAAkB"}
1
+ {"version":3,"file":"Button.stories.d.ts","sourceRoot":"","sources":["../../../../src/stories/Button.stories.jsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAyNU,2EAaP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBApOiC,kBAAkB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raspberrypifoundation/design-system-react",
3
- "version": "2.10.4",
3
+ "version": "2.11.1",
4
4
  "type": "module",
5
5
  "main": "./dist/design-system-react.umd.cjs",
6
6
  "module": "./dist/design-system-react.js",
@@ -43,7 +43,7 @@
43
43
  "ts:watch": "tsc --noEmit --watch"
44
44
  },
45
45
  "dependencies": {
46
- "@raspberrypifoundation/design-system-core": "^2.4.10",
46
+ "@raspberrypifoundation/design-system-core": "^2.5.1",
47
47
  "classnames": "^2.5.1",
48
48
  "lucide-react": "^0.553.0"
49
49
  },
@@ -86,7 +86,7 @@
86
86
  "sass-embedded": "^1.83.1",
87
87
  "storybook": "^8.6.18",
88
88
  "typescript": "^5.9.2",
89
- "vite": "^6.2.4",
89
+ "vite": "^6.4.3",
90
90
  "vitest": "^3.1.1"
91
91
  },
92
92
  "peerDependencies": {