@pokela/components 2.13.0 → 2.14.0

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/Alert.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ import type { ReactNode } from 'react';
2
+ /**
3
+ * Inline-ilmoitus: sävy, otsikko, teksti, toiminto ja sulkeminen.
4
+ *
5
+ * Sovelluskomponentti (päätökset 22 ja 29). Vasen viiva
6
+ * --hairline-strong, ei pintaa eikä kehystä: sama paksuus kuin kentän
7
+ * virheviivassa, ja kevein tapa erottaa ilmoitus sisällöstä.
8
+ *
9
+ * Sävyjä on kolme, ja vain virhe on värillinen (--danger). Info ja
10
+ * onnistui erottuvat ikonilla ja otsikolla. Varoitusta ei ole: ilman
11
+ * toista tilaväriä se erottuisi virheestä vain sävyllä.
12
+ *
13
+ * Ruudunlukija: virhe on role="alert", muut role="status". Rooli
14
+ * ilmoittaa sisällön, kun ilmoitus lisätään sivulle; jo latautuessa
15
+ * näkyvä ilmoitus luetaan kuten muukin teksti.
16
+ */
17
+ export type AlertTone = 'info' | 'success' | 'error';
18
+ export type AlertProps = {
19
+ tone?: AlertTone;
20
+ title: string;
21
+ /** Selittävä teksti otsikon alla. */
22
+ children?: ReactNode;
23
+ /** Toiminto tekstin alla, esim. `<a className="btn btn--text">`. */
24
+ action?: ReactNode;
25
+ /** Kun annettu, ilmoituksessa on sulkunappi. */
26
+ onDismiss?: () => void;
27
+ /** Sulkunapin nimi ruudunlukijalle. */
28
+ dismissLabel?: string;
29
+ className?: string;
30
+ };
31
+ export default function Alert({ tone, title, children, action, onDismiss, dismissLabel, className, }: AlertProps): import("react/jsx-runtime").JSX.Element;
package/Alert.js ADDED
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import Icon from './Icon';
3
+ const IKONI = { info: 'info', success: 'check', error: 'alert' };
4
+ export default function Alert({ tone = 'info', title, children, action, onDismiss, dismissLabel = 'Sulje', className, }) {
5
+ return (_jsxs("div", { className: ['alert', `alert--${tone}`, className].filter(Boolean).join(' '), role: tone === 'error' ? 'alert' : 'status', children: [_jsx(Icon, { name: IKONI[tone], className: "alert__icon" }), _jsxs("div", { className: "alert__content", children: [_jsx("p", { className: "alert__title", children: title }), children ? _jsx("div", { className: "alert__body", children: children }) : null, action ? _jsx("div", { className: "alert__actions", children: action }) : null] }), onDismiss ? (_jsx("button", { type: "button", className: "alert__close", "aria-label": dismissLabel, onClick: onDismiss, children: _jsx(Icon, { name: "close" }) })) : null] }));
6
+ }
package/Icon.d.ts CHANGED
@@ -18,14 +18,15 @@
18
18
  * Koot ovat tokeneita: --icon-s (12) tekstin seassa metan kanssa,
19
19
  * --icon-m (16) napin sisällä, --icon-l (24) omana painikkeenaan.
20
20
  *
21
- * `alert` kulkee aina virhetekstin rinnalla, ei yksin: merkitys on
22
- * tekstissä, ikoni ja --danger vain nopeuttavat sen löytämistä.
21
+ * `alert` ja `info` kulkevat aina tekstin rinnalla, eivät yksin:
22
+ * merkitys on tekstissä, ikoni (ja virheessä --danger) vain nopeuttaa
23
+ * sen löytämistä.
23
24
  *
24
25
  * Nuoli on kahta lajia eikä yhtä: `arrow-right` vie sivustolla eteen-
25
26
  * päin, `arrow-up-right` ulos. Ero on lukijalle sama kuin
26
27
  * target="_blank" ruudunlukijalle.
27
28
  */
28
- export type IconName = 'arrow-right' | 'arrow-up-right' | 'plus' | 'minus' | 'close' | 'menu' | 'alert' | 'chevron-down' | 'check';
29
+ export type IconName = 'arrow-right' | 'arrow-up-right' | 'plus' | 'minus' | 'close' | 'menu' | 'alert' | 'info' | 'chevron-down' | 'check';
29
30
  export type IconSize = 's' | 'm' | 'l';
30
31
  export type IconProps = {
31
32
  name: IconName;
package/Icon.js CHANGED
@@ -12,6 +12,9 @@ const PATHS = {
12
12
  vinot sivut eivät osu puolikkaan pikselin ruudukolle. Piste on
13
13
  lyhyt viiva, koska täyttöä ei ole. */
14
14
  alert: ['M2.5 2.5 H14.5 V14.5 H2.5 Z', 'M8.5 5 V10', 'M8.5 11.5 V12.5'],
15
+ /* Tieto. Alertin neliö ylösalaisin: piste ylhäällä, varsi alla.
16
+ Erottuu virheestä muodolla eikä vain värillä. */
17
+ info: ['M2.5 2.5 H14.5 V14.5 H2.5 Z', 'M8.5 4.5 V5.5', 'M8.5 7 V12'],
15
18
  /* Selectin nuoli ja valitun vaihtoehdon merkki. 45 asteen viivat
16
19
  puolikkaan pikselin ruudukolla, kuten nuolissa. */
17
20
  'chevron-down': ['M4.5 6.5 L8.5 10.5 L12.5 6.5'],
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @pokela/components
2
2
 
3
- React-komponentit: **Pokela Design System**, versio 2.13.0.
3
+ React-komponentit: **Pokela Design System**, versio 2.14.0.
4
4
 
5
5
  > Generoitu hakemistosta `components/` — samoista tiedostoista joita sivusto
6
6
  > ajaa. Älä muokkaa käsin: muutokset tehdään lähteeseen ja paketti
@@ -33,6 +33,7 @@ tyylit saa myös suoraan: `@pokela/components/styles.css`.
33
33
  - `Select`
34
34
  - `Tabs`
35
35
  - `Tab`
36
+ - `Alert`
36
37
  - `Grid`
37
38
  - `Reveal`
38
39
  - `ThemeScript`
@@ -72,6 +73,7 @@ import Link from 'next/link';
72
73
  - `styles/choice.css`
73
74
  - `styles/select.css`
74
75
  - `styles/tabs.css`
76
+ - `styles/alert.css`
75
77
 
76
78
  Luokat ovat globaaleja, eivät CSS-moduuleja. Se on tarkoituksellista: sama
77
79
  luokka on myös Figmassa komponentin nimenä, ja hajautettu nimi katkaisisi
@@ -18,6 +18,7 @@ Use these instead of building an equivalent.
18
18
  - `Select`
19
19
  - `Tabs`
20
20
  - `Tab`
21
+ - `Alert`
21
22
  - `Grid`, `Col`
22
23
  - `Reveal`
23
24
  - `ThemeScript`, `THEME_STORAGE_KEY`
@@ -146,6 +147,19 @@ for a step-by-step flow.
146
147
  </Tabs>
147
148
  ```
148
149
 
150
+ `Alert` is an inline message inside the page, next to what it is about: a
151
+ form error summary, a saved confirmation, a billing problem. `tone` is `info`
152
+ (default), `success` or `error`; only `error` is coloured. Give a short
153
+ `title` and the explanation as children; pass `action` for one next step (a
154
+ `btn btn--text` link) and `onDismiss` to show a close button. Use `error` only
155
+ for something that went wrong, never for emphasis. There is no warning tone.
156
+
157
+ ```jsx
158
+ <Alert tone="error" title="Payment failed" action={<a className="btn btn--text" href="/billing">Update card</a>}>
159
+ The card was declined. Update it to keep the subscription.
160
+ </Alert>
161
+ ```
162
+
149
163
  ## Patterns
150
164
 
151
165
  `PageHeader` and `Section` are patterns: they add no look of their own, only
@@ -30,7 +30,7 @@ else. Never set body text in the display face.
30
30
  <!-- generated:make-sarakkeet -->`Grid` is 12 columns: 4 on mobile, 8 from 600px, 12 from 900px.<!-- /generated --> Place
31
31
  things in columns, never in pixels. `Col` takes the span per breakpoint.
32
32
 
33
- **No icon libraries and no emoji.** Use `Icon`. <!-- generated:make-ikonit -->It draws its own 9 marks<!-- /generated --> on
33
+ **No icon libraries and no emoji.** Use `Icon`. <!-- generated:make-ikonit -->It draws its own 10 marks<!-- /generated --> on
34
34
  a 16×16 grid with the same hairline as every border.
35
35
 
36
36
  ## Buttons
@@ -9,7 +9,7 @@ inversion — `--invert-surface` with `--invert-ink` — or the quiet
9
9
  coloured button. Colour on the page comes only from photographs.
10
10
 
11
11
  The one exception is `--danger`, a state colour for errors only. Do not use it
12
- for emphasis, buttons or decoration. `TextField`, `ChoiceGroup` and `Select` already apply it, always
12
+ for emphasis, buttons or decoration. `TextField`, `ChoiceGroup`, `Select` and `Alert` already apply it, always
13
13
  with the `alert` icon and a message, so the meaning never depends on colour.
14
14
 
15
15
  **No shadows.** There are no shadow tokens. Separation is a 1px line
package/index.d.ts CHANGED
@@ -28,6 +28,8 @@ export { default as Tabs } from './Tabs.js';
28
28
  export type { TabsProps } from './Tabs.js';
29
29
  export { default as Tab } from './Tab.js';
30
30
  export type { TabProps } from './Tab.js';
31
+ export { default as Alert } from './Alert.js';
32
+ export type { AlertTone, AlertProps } from './Alert.js';
31
33
  export { Grid, Col } from './Grid.js';
32
34
  export { default as Reveal } from './Reveal.js';
33
35
  export { default as ThemeScript, THEME_STORAGE_KEY } from './ThemeScript.js';
package/index.js CHANGED
@@ -15,6 +15,7 @@ export { default as ChoiceGroup } from './ChoiceGroup.js';
15
15
  export { default as Select } from './Select.js';
16
16
  export { default as Tabs } from './Tabs.js';
17
17
  export { default as Tab } from './Tab.js';
18
+ export { default as Alert } from './Alert.js';
18
19
  export { Grid, Col } from './Grid.js';
19
20
  export { default as Reveal } from './Reveal.js';
20
21
  export { default as ThemeScript, THEME_STORAGE_KEY } from './ThemeScript.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pokela/components",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "description": "React-komponentit: Pokela Design System. Generoitu tiedostoista components/, ei käsin ylläpidetty.",
5
5
  "license": "MIT",
6
6
  "author": "Veli-Matti Pokela",
@@ -27,7 +27,7 @@
27
27
  "LICENSE"
28
28
  ],
29
29
  "dependencies": {
30
- "@pokela/tokens": "^2.13.0"
30
+ "@pokela/tokens": "^2.14.0"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "react": ">=18"
@@ -0,0 +1,74 @@
1
+ /* Inline-ilmoitus (Alert). Sovelluskomponentti, sivusto ei käytä tätä.
2
+ ==================================================================
3
+ Vasen viiva --hairline-strong, ei pintaa eikä kehystä (päätös 29).
4
+ Ikoni, otsikko (paino 500) ja teksti (--ink-muted) ovat samassa
5
+ koossa kuin kentän virheteksti. Virheessä viiva, ikoni ja otsikko
6
+ ovat --danger; teksti pysyy --ink-mutedina, jotta pitkäkin selitys
7
+ on luettava. */
8
+
9
+ .alert {
10
+ display: grid;
11
+ grid-template-columns: auto 1fr auto;
12
+ column-gap: var(--space-12);
13
+ align-items: start;
14
+ padding: var(--space-4) 0 var(--space-4) var(--space-16);
15
+ border-left: var(--hairline-strong) solid var(--ink);
16
+ color: var(--ink);
17
+ }
18
+
19
+ /* Ikoni ensimmäisen rivin keskelle, kuten .field__errorissa. */
20
+ .alert__icon { margin-top: calc((var(--lh-body-s) * var(--text-body-s) - var(--icon-m)) / 2); }
21
+
22
+ .alert__content { min-width: 0; }
23
+ .alert__title,
24
+ .alert__body {
25
+ margin: 0;
26
+ font-size: var(--text-body-s);
27
+ line-height: var(--lh-body-s);
28
+ }
29
+ .alert__title { font-weight: var(--weight-500); }
30
+ .alert__body { color: var(--ink-muted); }
31
+ .alert__body > * { margin: 0; }
32
+ .alert__actions {
33
+ display: flex;
34
+ flex-wrap: wrap;
35
+ gap: var(--space-12) var(--space-24);
36
+ margin-top: var(--space-12);
37
+ }
38
+
39
+ .alert--error { border-left-color: var(--danger); }
40
+ .alert--error .alert__icon,
41
+ .alert--error .alert__title { color: var(--danger); }
42
+
43
+ /* Sulkunappi: näkyvä 32 px, osuma-alue --tap-min kuten .btn--s:ssä
44
+ (päätös 26). Ensimmäisen rivin keskelle, ja oikea reuna vedetään
45
+ ikonin reunaan, jotta X on linjassa tekstipalstan oikean reunan
46
+ kanssa. */
47
+ .alert__close {
48
+ position: relative;
49
+ display: inline-flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ width: var(--space-32);
53
+ height: var(--space-32);
54
+ margin: calc((var(--lh-body-s) * var(--text-body-s) - var(--space-32)) / 2)
55
+ calc((var(--space-32) - var(--icon-m)) / -2) 0 0;
56
+ padding: 0;
57
+ background: none;
58
+ border: 0;
59
+ color: var(--ink-muted);
60
+ cursor: pointer;
61
+ }
62
+ .alert__close::after {
63
+ content: '';
64
+ position: absolute;
65
+ inset: calc((var(--space-32) - var(--tap-min)) / 2);
66
+ }
67
+ .alert__close:hover { color: var(--ink); }
68
+ .alert__close:focus-visible {
69
+ outline: var(--focus-width) solid var(--ink);
70
+ outline-offset: calc(var(--focus-width) * -1);
71
+ }
72
+ @media (prefers-reduced-motion: no-preference) {
73
+ .alert__close { transition: color var(--dur-fast) var(--ease-standard); }
74
+ }
package/styles.css CHANGED
@@ -12,3 +12,4 @@
12
12
  @import './styles/choice.css';
13
13
  @import './styles/select.css';
14
14
  @import './styles/tabs.css';
15
+ @import './styles/alert.css';