@karmo-co/drift-kit-reference 0.0.0-stage → 23.4.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/LICENSE +7 -0
- package/README.md +24 -2
- package/bin/drift-kit-ref.js +169 -0
- package/manifest/components/accordion.md +47 -0
- package/manifest/components/action-bar.md +51 -0
- package/manifest/components/alert.md +53 -0
- package/manifest/components/app-shell.md +43 -0
- package/manifest/components/avatar.md +42 -0
- package/manifest/components/body.md +48 -0
- package/manifest/components/box.md +58 -0
- package/manifest/components/breadcrumb.md +59 -0
- package/manifest/components/button.md +46 -0
- package/manifest/components/calendar.md +69 -0
- package/manifest/components/card.md +71 -0
- package/manifest/components/checkbox.md +43 -0
- package/manifest/components/choice-card.md +61 -0
- package/manifest/components/code-input.md +56 -0
- package/manifest/components/date-picker.md +66 -0
- package/manifest/components/day-of-month.md +54 -0
- package/manifest/components/detail-list.md +37 -0
- package/manifest/components/divider.md +33 -0
- package/manifest/components/dropdown.md +52 -0
- package/manifest/components/dropzone.md +56 -0
- package/manifest/components/eyebrow.md +45 -0
- package/manifest/components/feedback-badge.md +35 -0
- package/manifest/components/glider.md +34 -0
- package/manifest/components/heading.md +47 -0
- package/manifest/components/hero.md +46 -0
- package/manifest/components/icon-button.md +41 -0
- package/manifest/components/icon-tile.md +44 -0
- package/manifest/components/icon.md +30 -0
- package/manifest/components/input.md +63 -0
- package/manifest/components/link.md +42 -0
- package/manifest/components/loading-spinner.md +42 -0
- package/manifest/components/logo.md +38 -0
- package/manifest/components/modal.md +53 -0
- package/manifest/components/pagination.md +54 -0
- package/manifest/components/payment-form.md +29 -0
- package/manifest/components/price-summary.md +30 -0
- package/manifest/components/radio.md +42 -0
- package/manifest/components/section-heading.md +41 -0
- package/manifest/components/select.md +99 -0
- package/manifest/components/shield.md +34 -0
- package/manifest/components/sidebar.md +73 -0
- package/manifest/components/stepper.md +53 -0
- package/manifest/components/switch.md +45 -0
- package/manifest/components/table.md +77 -0
- package/manifest/components/tabs.md +43 -0
- package/manifest/components/tag.md +43 -0
- package/manifest/components/textarea.md +52 -0
- package/manifest/components/toast.md +52 -0
- package/manifest/components/tooltip.md +42 -0
- package/manifest/components/top-bar.md +60 -0
- package/manifest/components/vehicle.md +43 -0
- package/manifest/index.json +402 -0
- package/manifest/migrations/1.0.0.md +50 -0
- package/manifest/migrations/10.0.0.md +154 -0
- package/manifest/migrations/11.0.0.md +24 -0
- package/manifest/migrations/12.0.0.md +38 -0
- package/manifest/migrations/13.0.0.md +50 -0
- package/manifest/migrations/14.0.0.md +148 -0
- package/manifest/migrations/15.0.0.md +140 -0
- package/manifest/migrations/16.0.0.md +196 -0
- package/manifest/migrations/17.0.0.md +19 -0
- package/manifest/migrations/18.0.0.md +23 -0
- package/manifest/migrations/19.0.0.md +15 -0
- package/manifest/migrations/2.0.0.md +18 -0
- package/manifest/migrations/20.0.0.md +43 -0
- package/manifest/migrations/21.0.0.md +97 -0
- package/manifest/migrations/22.0.0.md +17 -0
- package/manifest/migrations/23.0.0.md +86 -0
- package/manifest/migrations/3.0.0.md +34 -0
- package/manifest/migrations/4.0.0.md +147 -0
- package/manifest/migrations/5.0.0.md +73 -0
- package/manifest/migrations/6.0.0.md +67 -0
- package/manifest/migrations/7.0.0.md +71 -0
- package/manifest/migrations/8.0.0.md +16 -0
- package/manifest/migrations/9.0.0.md +107 -0
- package/manifest/rules.md +37 -0
- package/manifest/setup.md +28 -0
- package/manifest/tokens/border-width.md +12 -0
- package/manifest/tokens/border.md +147 -0
- package/manifest/tokens/font.md +90 -0
- package/manifest/tokens/icon.md +84 -0
- package/manifest/tokens/interactive.md +37 -0
- package/manifest/tokens/motion.md +69 -0
- package/manifest/tokens/radius.md +20 -0
- package/manifest/tokens/shadow.md +28 -0
- package/manifest/tokens/spacing.md +35 -0
- package/manifest/tokens/surface.md +138 -0
- package/manifest/tokens/text.md +92 -0
- package/package.json +20 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright (c) Karmo. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This package contains reference documentation of Karmo's private Drift design system. It is published so that Karmo's tools can read it.
|
|
4
|
+
|
|
5
|
+
You may read these files to build or review software for Karmo with the Drift design system. Any other use, including copying, modifying, redistributing or using them to build a design system, is not permitted without Karmo's written permission.
|
|
6
|
+
|
|
7
|
+
The documentation is provided as is, without warranty of any kind.
|
package/README.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @karmo-co/drift-kit-reference
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The reference documentation of Drift, Karmo's private design system, published for Karmo's Claude skills. It holds the facts of one kit version: the components and their markup, attributes and React props, the tokens, how a project sets the kit up, the rules for building a new component, and the upgrade notes between majors.
|
|
4
|
+
|
|
5
|
+
It does not contain the design system itself. The kit's code and stylesheets are private.
|
|
6
|
+
|
|
7
|
+
## Use
|
|
8
|
+
|
|
9
|
+
Its version always matches the kit version it describes. Ask it about the version a project uses:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
drift-kit-ref info
|
|
13
|
+
drift-kit-ref search "steps in a flow"
|
|
14
|
+
drift-kit-ref component stepper
|
|
15
|
+
drift-kit-ref tokens motion
|
|
16
|
+
drift-kit-ref setup
|
|
17
|
+
drift-kit-ref rules
|
|
18
|
+
drift-kit-ref changes 21.0.0
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Every answer starts with the kit version it describes. A name that version does not have is answered "not in", with the closest names.
|
|
22
|
+
|
|
23
|
+
## Licence
|
|
24
|
+
|
|
25
|
+
Documentation only. © Karmo. All rights reserved. See LICENSE.
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/* drift-kit-ref: the facts of one Drift kit version, from the manifest beside
|
|
4
|
+
this script. It ships in @karmo-co/drift-kit (reading dist/manifest) and in
|
|
5
|
+
@karmo-co/drift-kit-reference (reading manifest/), so a project reads its
|
|
6
|
+
own installed version offline and everything else reads the public one.
|
|
7
|
+
No dependencies, Node 18 or later. Every answer opens with the version it
|
|
8
|
+
describes; a name the version does not have is answered "not in", never
|
|
9
|
+
with the nearest entry as if it matched. */
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
const HELP = `drift-kit-ref <command> [argument]
|
|
14
|
+
|
|
15
|
+
info the kit version these facts describe, and when they were built
|
|
16
|
+
search "<need>" components and token groups for a need ("steps in a flow")
|
|
17
|
+
component <id> one component: anatomy, attributes, React props, tokens
|
|
18
|
+
tokens <group> one token group, light and dark
|
|
19
|
+
setup how a project installs and imports the kit
|
|
20
|
+
rules the rules for building a new component the kit's way
|
|
21
|
+
changes <version> upgrade notes from that version up to this one
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
function findManifest(fromDir = __dirname) {
|
|
25
|
+
for (const rel of ['../dist/manifest', '../manifest']) {
|
|
26
|
+
const dir = path.resolve(fromDir, rel);
|
|
27
|
+
if (fs.existsSync(path.join(dir, 'index.json'))) return dir;
|
|
28
|
+
}
|
|
29
|
+
throw new Error('No Drift manifest found beside drift-kit-ref (looked for ../dist/manifest and ../manifest).');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ---------- matching and search ----------
|
|
33
|
+
const normaliseName = (s) => String(s).toLowerCase().replace(/[\s_-]+/g, '');
|
|
34
|
+
|
|
35
|
+
function editDistance(a, b) {
|
|
36
|
+
const row = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
37
|
+
for (let i = 1; i <= a.length; i++) {
|
|
38
|
+
let prev = row[0];
|
|
39
|
+
row[0] = i;
|
|
40
|
+
for (let j = 1; j <= b.length; j++) {
|
|
41
|
+
const tmp = row[j];
|
|
42
|
+
row[j] = Math.min(row[j] + 1, row[j - 1] + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
43
|
+
prev = tmp;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return row[b.length];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Closest ids: substring or shared prefix first, then edit distance.
|
|
50
|
+
function closest(ids, name, limit = 3) {
|
|
51
|
+
const want = normaliseName(name);
|
|
52
|
+
const scored = ids.map((raw) => {
|
|
53
|
+
const id = normaliseName(raw);
|
|
54
|
+
let prefix = 0;
|
|
55
|
+
while (prefix < id.length && prefix < want.length && id[prefix] === want[prefix]) prefix++;
|
|
56
|
+
const related = want && (id.includes(want) || want.includes(id) || prefix >= 3);
|
|
57
|
+
return { id: raw, rank: related ? 0 : 1, score: related ? -prefix : editDistance(id, want) };
|
|
58
|
+
});
|
|
59
|
+
scored.sort((a, b) => a.rank - b.rank || a.score - b.score || a.id.localeCompare(b.id));
|
|
60
|
+
return scored.slice(0, limit).map((s) => s.id);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const STOP = new Set(['a', 'an', 'the', 'in', 'of', 'to', 'for', 'and', 'or', 'on', 'with', 'is', 'it', 'how', 'do', 'i']);
|
|
64
|
+
const words = (s) => String(s).toLowerCase().split(/[^a-z0-9]+/).filter((w) => w && !STOP.has(w));
|
|
65
|
+
const stem = (w) => (w.length > 4 ? w.replace(/(ing|es|s)$/, '') : w.replace(/s$/, ''));
|
|
66
|
+
|
|
67
|
+
// A whole-phrase hit, then one point per matching term.
|
|
68
|
+
function scoreText(text, phrase, terms) {
|
|
69
|
+
const t = text.toLowerCase();
|
|
70
|
+
let s = phrase && t.includes(phrase) ? terms.length + 1 : 0;
|
|
71
|
+
const tw = words(text).map(stem);
|
|
72
|
+
for (const term of terms) if (tw.some((w) => w === term || w.startsWith(term))) s += 1;
|
|
73
|
+
return s;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Matches on id, name and purpose (weight 10) rank above matches in the body (weight 1).
|
|
77
|
+
function search(m, query, limit = 10) {
|
|
78
|
+
const phrase = query.trim().toLowerCase();
|
|
79
|
+
const terms = words(query).map(stem);
|
|
80
|
+
if (!terms.length) return null;
|
|
81
|
+
const hits = [];
|
|
82
|
+
const consider = (kind, id, name, purpose, body) => {
|
|
83
|
+
let score = 10 * (scoreText(`${id} ${name}`, phrase, terms) * 2 + scoreText(purpose || '', phrase, terms));
|
|
84
|
+
if (score === 0) score = scoreText(m.read(body) || '', phrase, terms);
|
|
85
|
+
if (score > 0) hits.push({ kind, id, name, purpose: purpose || '', score });
|
|
86
|
+
};
|
|
87
|
+
for (const c of m.index.components) consider('component', c.id, c.name, c.purpose, `components/${c.id}.md`);
|
|
88
|
+
for (const g of m.index.tokenGroups || []) consider('token group', g.id, g.title, '', `tokens/${g.id}.md`);
|
|
89
|
+
hits.sort((a, b) => b.score - a.score || a.id.localeCompare(b.id));
|
|
90
|
+
return hits.slice(0, limit);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ---------- versions ----------
|
|
94
|
+
const SEMVER = /^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?$/;
|
|
95
|
+
function compare(a, b) {
|
|
96
|
+
const x = SEMVER.exec(a), y = SEMVER.exec(b);
|
|
97
|
+
for (let i = 1; i <= 3; i++) if (+x[i] !== +y[i]) return +x[i] - +y[i];
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ---------- the commands ----------
|
|
102
|
+
function load(dir) {
|
|
103
|
+
const index = JSON.parse(fs.readFileSync(path.join(dir, 'index.json'), 'utf8'));
|
|
104
|
+
const read = (rel) => {
|
|
105
|
+
try { return fs.readFileSync(path.join(dir, rel), 'utf8'); } catch { return null; }
|
|
106
|
+
};
|
|
107
|
+
return { index, read };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function run(argv, manifestDir) {
|
|
111
|
+
const [cmd, ...rest] = argv;
|
|
112
|
+
const arg = rest.join(' ').trim();
|
|
113
|
+
if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') return { code: cmd ? 0 : 1, out: HELP };
|
|
114
|
+
let m;
|
|
115
|
+
try {
|
|
116
|
+
m = load(manifestDir || findManifest());
|
|
117
|
+
} catch (e) {
|
|
118
|
+
return { code: 2, out: `The Drift manifest could not be read (${e.code || e.message}), so these facts can't be checked here.\n` };
|
|
119
|
+
}
|
|
120
|
+
const v = m.index.version;
|
|
121
|
+
const head = `Drift kit ${v}.\n\n`;
|
|
122
|
+
const usage = (what) => ({ code: 1, out: `${what}\n\n${HELP}` });
|
|
123
|
+
|
|
124
|
+
switch (cmd) {
|
|
125
|
+
case 'info':
|
|
126
|
+
return { code: 0, out: `${head}Built ${m.index.built || 'on an unknown date'}. ${m.index.components.length} components, ${(m.index.tokenGroups || []).length} token groups, upgrade notes for ${(m.index.migrations || []).length} majors.\n` };
|
|
127
|
+
case 'search': {
|
|
128
|
+
if (!arg) return usage('search needs a phrase, for example: search "steps in a flow"');
|
|
129
|
+
const hits = search(m, arg);
|
|
130
|
+
if (hits === null) return { code: 0, out: `${head}Nothing to search for in "${arg}": try the words for what the screen needs.\n` };
|
|
131
|
+
if (!hits.length) return { code: 0, out: `${head}Nothing in ${v} matches "${arg}". The kit may not have it: build it on the kit's foundations (rules).\n` };
|
|
132
|
+
return { code: 0, out: head + hits.map((h) => `- ${h.kind} \`${h.id}\`: ${h.name}${h.purpose ? '. ' + h.purpose : ''}`).join('\n') + '\n' };
|
|
133
|
+
}
|
|
134
|
+
case 'component': {
|
|
135
|
+
if (!arg) return usage('component needs an id, for example: component button');
|
|
136
|
+
const want = normaliseName(arg);
|
|
137
|
+
const c = m.index.components.find((x) => normaliseName(x.id) === want || normaliseName(x.name) === want);
|
|
138
|
+
if (!c) return { code: 0, out: `${head}"${arg}" is not in ${v}. Closest: ${closest(m.index.components.map((x) => x.id), arg).map((id) => '`' + id + '`').join(', ')}.\n` };
|
|
139
|
+
return { code: 0, out: head + m.read(`components/${c.id}.md`) };
|
|
140
|
+
}
|
|
141
|
+
case 'tokens': {
|
|
142
|
+
if (!arg) return usage('tokens needs a group, for example: tokens motion');
|
|
143
|
+
const groups = m.index.tokenGroups || [];
|
|
144
|
+
const g = groups.find((x) => normaliseName(x.id) === normaliseName(arg) || normaliseName(x.title) === normaliseName(arg));
|
|
145
|
+
if (!g) return { code: 0, out: `${head}Token group "${arg}" is not in ${v}. The groups are: ${groups.map((x) => '`' + x.id + '`').join(', ')}.\n` };
|
|
146
|
+
return { code: 0, out: head + m.read(`tokens/${g.id}.md`) };
|
|
147
|
+
}
|
|
148
|
+
case 'setup':
|
|
149
|
+
case 'rules':
|
|
150
|
+
return { code: 0, out: head + (m.read(`${cmd}.md`) || `No ${cmd} notes in ${v}.\n`) };
|
|
151
|
+
case 'changes': {
|
|
152
|
+
if (!SEMVER.test(arg)) return usage('changes needs the version you are upgrading from, for example: changes 21.0.0');
|
|
153
|
+
if (compare(arg, v) >= 0) return { code: 0, out: `${head}${arg} is already at or past ${v}: there are no upgrade notes to apply.\n` };
|
|
154
|
+
const majors = (m.index.migrations || []).filter((x) => compare(x.major, arg) > 0 && compare(x.major, v) <= 0).sort((a, b) => compare(a.major, b.major));
|
|
155
|
+
if (!majors.length) return { code: 0, out: `${head}No breaking changes between ${arg} and ${v}: pin ${v} and rebuild.\n` };
|
|
156
|
+
return { code: 0, out: `${head}Upgrade notes from ${arg} to ${v}, oldest first. Apply one major at a time.\n\n` + majors.map((x) => m.read(`migrations/${x.major}.md`) || '').join('\n') };
|
|
157
|
+
}
|
|
158
|
+
default:
|
|
159
|
+
return usage(`Unknown command "${cmd}".`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
module.exports = { run, findManifest };
|
|
164
|
+
|
|
165
|
+
if (require.main === module) {
|
|
166
|
+
const r = run(process.argv.slice(2));
|
|
167
|
+
process.stdout.write(r.out);
|
|
168
|
+
process.exitCode = r.code;
|
|
169
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Accordion (`accordion`)
|
|
2
|
+
|
|
3
|
+
A list of things you can open: FAQs, settings, details on demand. Built on <details>, so it works before the script does, with motion that turns round mid-way.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Anatomy (HTML)
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
div.dk-component-accordion[data-variant="separated|joined|flush"][data-size][data-icon="plus"]
|
|
10
|
+
details.dk-component-accordion__item[name][open]
|
|
11
|
+
summary.dk-component-accordion__summary[aria-disabled]
|
|
12
|
+
span.__leading? span.__heading? > span.__title + span.__description?
|
|
13
|
+
span.__meta? svg.__icon (injected when missing)
|
|
14
|
+
div.dk-component-accordion__panel
|
|
15
|
+
div.dk-component-accordion__content
|
|
16
|
+
──
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Attributes
|
|
20
|
+
|
|
21
|
+
| Attribute | Values the stylesheet styles |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `data-flush` | (present or absent) |
|
|
24
|
+
| `data-glyph` | `chevron` |
|
|
25
|
+
| `data-icon` | `plus` |
|
|
26
|
+
| `data-size` | `large`, `small` |
|
|
27
|
+
| `data-state` | `closing`, `opening` |
|
|
28
|
+
| `data-variant` | `flush`, `joined` |
|
|
29
|
+
|
|
30
|
+
## React
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { Accordion } from '@karmo-co/drift-kit/react';
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
| Prop | Type | Notes |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `variant` | `'separated' \| 'joined' \| 'flush'` | separated (default): a stack of cards. joined: one card with rules between items. flush: rules only, for an accordion already in a card. |
|
|
39
|
+
| `size` | `'small' \| 'medium' \| 'large'` | |
|
|
40
|
+
| `icon` | `'chevron' \| 'plus'` | |
|
|
41
|
+
| `exclusive` | `boolean \| string` | One open at a time. true makes a group name; a string names it, which is the <details name> the platform makes exclusive before any script runs. |
|
|
42
|
+
| `className` | `string` | |
|
|
43
|
+
| `children` | `ReactNode` | |
|
|
44
|
+
|
|
45
|
+
## Component tokens
|
|
46
|
+
|
|
47
|
+
`--dk-component-accordion-inset`, `--dk-component-accordion-padding-block`, `--dk-component-accordion-small-padding-block`, `--dk-component-accordion-large-padding-block`, `--dk-component-accordion-padding-inline`, `--dk-component-accordion-flush-padding-inline`, `--dk-component-accordion-row-radius`, `--dk-component-accordion-row-surface-hover`, `--dk-component-accordion-row-surface-active`, `--dk-component-accordion-press-scale`, `--dk-component-accordion-focus-ring-width`, `--dk-component-accordion-focus-ring`, `--dk-component-accordion-gap`, `--dk-component-accordion-font-family`, `--dk-component-accordion-font-size`, `--dk-component-accordion-line-height`, `--dk-component-accordion-small-font-size`, `--dk-component-accordion-small-line-height`, `--dk-component-accordion-large-font-size`, `--dk-component-accordion-large-line-height`, `--dk-component-accordion-summary-font-weight`, `--dk-component-accordion-summary-color`, `--dk-component-accordion-heading-gap`, `--dk-component-accordion-description-font-size`, `--dk-component-accordion-description-line-height`, `--dk-component-accordion-description-color`, `--dk-component-accordion-content-color`, `--dk-component-accordion-surface`, `--dk-component-accordion-border`, `--dk-component-accordion-border-width`, `--dk-component-accordion-radius`, `--dk-component-accordion-rule`, `--dk-component-accordion-joined-rule`, `--dk-component-accordion-icon-size`, `--dk-component-accordion-icon-color`, `--dk-component-accordion-icon-color-hover`, `--dk-component-accordion-icon-gap`, `--dk-component-accordion-leading-size`, `--dk-component-accordion-leading-color`, `--dk-component-accordion-meta-gap`, `--dk-component-accordion-title-color-disabled`, `--dk-component-accordion-description-color-disabled`, `--dk-component-accordion-icon-color-disabled`, `--dk-component-accordion-open-duration`, `--dk-component-accordion-close-duration`, `--dk-component-accordion-easing`, `--dk-component-accordion-content-rise`, `--dk-component-accordion-duration`
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Action bar (`action-bar`)
|
|
2
|
+
|
|
3
|
+
A flow's controls along the bottom: Back, Next, what the step costs and how far along it is.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Anatomy (HTML)
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
div.dk-component-action-bar[data-variant="float"]?[data-align="split"]?[data-sticky]?
|
|
10
|
+
div.__inner
|
|
11
|
+
div.__start (Back: a plain Button)
|
|
12
|
+
button.__summary? (__summary-label, __summary-value, __summary-chevron; opens __detail)
|
|
13
|
+
div.__end (Next: a Button, default + primary)
|
|
14
|
+
div.__detail?
|
|
15
|
+
div.__progress?
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Attributes
|
|
19
|
+
|
|
20
|
+
| Attribute | Values the stylesheet styles |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `data-align` | `split` |
|
|
23
|
+
| `data-closing` | (present or absent) |
|
|
24
|
+
| `data-open` | (present or absent) |
|
|
25
|
+
| `data-phone` | (present or absent) |
|
|
26
|
+
| `data-sticky` | (present or absent) |
|
|
27
|
+
| `data-stuck` | (present or absent) |
|
|
28
|
+
| `data-variant` | `float` |
|
|
29
|
+
|
|
30
|
+
## React
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { ActionBar } from '@karmo-co/drift-kit/react';
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
| Prop | Type | Notes |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `start` | `ReactNode` | Back, usually a plain Button. |
|
|
39
|
+
| `end` | `ReactNode` | Next, usually a default primary Button. |
|
|
40
|
+
| `summary` | `{ label: ReactNode; value: ReactNode; detail?: ReactNode; detailLabel?: string }` | What the step costs: "Due today", "$224.50". With a detail the summary is a button: press it and the detail opens above the bar (the price breakdown, a photo of the car). detailLabel names it. |
|
|
41
|
+
| `progress` | `{ value: number; max: number; label?: string; text?: string }` | Where the flow is, drawn along the bar's top edge. |
|
|
42
|
+
| `variant` | `'fixed' \| 'float'` | |
|
|
43
|
+
| `sticky` | `boolean` | |
|
|
44
|
+
| `align` | `'end' \| 'split'` | 'end' (the design's) keeps Back beside Next; 'split' puts it at the start. |
|
|
45
|
+
| `device` | `'auto' \| 'phone' \| 'desktop'` | |
|
|
46
|
+
| `theme` | `'light' \| 'dark'` | Dark chrome: 'dark' makes it dark on a light page and one step deeper than a dark one. Everything inside resolves dark, menus included. |
|
|
47
|
+
| `className` | `string` | |
|
|
48
|
+
|
|
49
|
+
## Component tokens
|
|
50
|
+
|
|
51
|
+
`--dk-component-action-bar-padding-block`, `--dk-component-action-bar-padding-inline`, `--dk-component-action-bar-phone-padding-inline`, `--dk-component-action-bar-gap`, `--dk-component-action-bar-button-gap`, `--dk-component-action-bar-max-width`, `--dk-component-action-bar-surface`, `--dk-component-action-bar-border`, `--dk-component-action-bar-border-width`, `--dk-component-action-bar-float-radius`, `--dk-component-action-bar-float-surface`, `--dk-component-action-bar-blur`, `--dk-component-action-bar-float-inset`, `--dk-component-action-bar-float-shadow`, `--dk-component-action-bar-stuck-shadow`, `--dk-component-action-bar-z-index`, `--dk-component-action-bar-summary-label-font-size`, `--dk-component-action-bar-summary-label-line-height`, `--dk-component-action-bar-summary-label-font-weight`, `--dk-component-action-bar-summary-label-letter-spacing`, `--dk-component-action-bar-summary-label-color`, `--dk-component-action-bar-summary-value-font-size`, `--dk-component-action-bar-summary-value-line-height`, `--dk-component-action-bar-summary-value-font-weight`, `--dk-component-action-bar-summary-value-color`, `--dk-component-action-bar-progress-thickness`, `--dk-component-action-bar-progress-track`, `--dk-component-action-bar-progress-fill`, `--dk-component-action-bar-progress-gradient`, `--dk-component-action-bar-progress-gradient-rtl`, `--dk-component-action-bar-duration`, `--dk-component-action-bar-progress-duration`, `--dk-component-action-bar-easing`, `--dk-component-action-bar-summary-padding`, `--dk-component-action-bar-summary-radius`, `--dk-component-action-bar-summary-surface-hover`, `--dk-component-action-bar-summary-surface-active`, `--dk-component-action-bar-summary-press-scale`, `--dk-component-action-bar-summary-ring`, `--dk-component-action-bar-summary-ring-width`, `--dk-component-action-bar-chevron-size`, `--dk-component-action-bar-chevron-color`, `--dk-component-action-bar-chevron-color-hover`, `--dk-component-action-bar-chevron-color-active`, `--dk-component-action-bar-detail-surface`, `--dk-component-action-bar-detail-border`, `--dk-component-action-bar-detail-radius`, `--dk-component-action-bar-detail-shadow`, `--dk-component-action-bar-detail-padding`, `--dk-component-action-bar-detail-width`, `--dk-component-action-bar-detail-gap`, `--dk-component-action-bar-detail-rise`, `--dk-component-action-bar-detail-enter-duration`, `--dk-component-action-bar-detail-enter-easing`, `--dk-component-action-bar-detail-exit-duration`, `--dk-component-action-bar-detail-exit-easing`
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Alert (`alert`)
|
|
2
|
+
|
|
3
|
+
An inline, persistent message in the page: a status colour, an optional icon, title, body, actions and a dismiss button.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Anatomy (HTML)
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
div.dk-component-alert[data-status="primary|success|warning|error|information"][data-variant="solid|outline|plain"]?[data-size="small"]?[data-pointer]?[data-dismissible]?[role="status"]
|
|
10
|
+
span.__icon?
|
|
11
|
+
div.__content
|
|
12
|
+
p.__title?
|
|
13
|
+
p.__body
|
|
14
|
+
div.__actions?
|
|
15
|
+
button.__dismiss?
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Attributes
|
|
19
|
+
|
|
20
|
+
| Attribute | Values the stylesheet styles |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `data-full-width` | `true` |
|
|
23
|
+
| `data-pointer` | `bottom`, `left`, `right`, `top` |
|
|
24
|
+
| `data-size` | `small` |
|
|
25
|
+
| `data-status` | `error`, `information`, `primary`, `success`, `warning` |
|
|
26
|
+
| `data-text` | `tinted` |
|
|
27
|
+
| `data-variant` | `outline`, `plain`, `solid` |
|
|
28
|
+
|
|
29
|
+
## React
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { Alert } from '@karmo-co/drift-kit/react';
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
| Prop | Type | Notes |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `status` | `'neutral' \| 'information' \| 'success' \| 'warning' \| 'error' \| 'primary'` | 'neutral' and omitting the prop render identically: neutral is what the base rule already is, and naming it is for the caller who wants to say so. |
|
|
38
|
+
| `variant` | `'subtle' \| 'solid' \| 'outline' \| 'plain'` | |
|
|
39
|
+
| `size` | `'small' \| 'medium'` | Medium is the default and needs no attribute, as on Input and Select. |
|
|
40
|
+
| `pointer` | `'left' \| 'top' \| 'right' \| 'bottom'` | The balloon: a triangle on that side, centred, in the alert's own fill and border. Not on plain. |
|
|
41
|
+
| `text` | `'tinted'` | Omitted, the title is default-coloured and the body grey. 'tinted' paints both in the status colour. The icon is status-coloured either way. |
|
|
42
|
+
| `fullWidth` | `boolean` | Content width by default, like Button. |
|
|
43
|
+
| `title` | `ReactNode` | A string in nearly every case, so it is a prop rather than a slot. |
|
|
44
|
+
| `children` | `ReactNode` | The body. Always rendered inside a <p> (__body), so children must be phrasing content, i.e. text and inline elements only: a block child such as <ul> or <div> inside a <p> is invalid HTML, which the browser repairs by closing the <p> early. renderToString does not warn about this, so the first sign is a silent hydration mismatch on the client. |
|
|
45
|
+
| `icon` | `ReactNode` | No icon by default; omitting the prop and passing icon={null} render identically. The per-status glyph convention (which icon for which status) is documentation for callers, in the docs, not something this component injects: picking one here would make an icon set a dependency of Alert, and the kit ships icons as markup, not as component logic. |
|
|
46
|
+
| `actions` | `ReactNode` | |
|
|
47
|
+
| `dismissible` | `boolean` | |
|
|
48
|
+
| `onDismiss` | `() => void` | Called instead of the element removing itself. React owns its own DOM, so this component must never delete nodes out from under it: a React consumer holds visibility in state and does not load components.js for Alert. |
|
|
49
|
+
| `dismissLabel` | `string` | |
|
|
50
|
+
|
|
51
|
+
## Component tokens
|
|
52
|
+
|
|
53
|
+
`--dk-component-alert-gap`, `--dk-component-alert-padding`, `--dk-component-alert-radius`, `--dk-component-alert-border-width`, `--dk-component-alert-icon-size`, `--dk-component-alert-dismiss-padding`, `--dk-component-alert-dismiss-offset`, `--dk-component-alert-trailing-extra`, `--dk-component-alert-small-gap`, `--dk-component-alert-small-padding`, `--dk-component-alert-small-icon-size`, `--dk-component-alert-small-dismiss-padding`, `--dk-component-alert-small-dismiss-offset`, `--dk-component-alert-small-trailing-extra`, `--dk-component-alert-title-font-size`, `--dk-component-alert-title-line-height`, `--dk-component-alert-title-font-weight`, `--dk-component-alert-body-font-size`, `--dk-component-alert-body-line-height`, `--dk-component-alert-body-font-weight`, `--dk-component-alert-small-title-font-size`, `--dk-component-alert-small-title-line-height`, `--dk-component-alert-small-body-font-size`, `--dk-component-alert-small-body-line-height`, `--dk-component-alert-pointer-depth`, `--dk-component-alert-pointer-base`, `--dk-component-alert-neutral-color`, `--dk-component-alert-primary-color`, `--dk-component-alert-warning-color`, `--dk-component-alert-error-color`, `--dk-component-alert-information-color`, `--dk-component-alert-success-color`, `--dk-component-alert-scrim-active-opacity`, `--dk-component-alert-scrim-hover-opacity`
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# App shell (`app-shell`)
|
|
2
|
+
|
|
3
|
+
The layout that places a Sidebar, a Top bar, the page and an Action bar, in the viewport or in a box.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Anatomy (HTML)
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
div.dk-component-app-shell[data-contained]?[data-presentation="bar|drawer"]?
|
|
10
|
+
nav.dk-component-sidebar (its own component)
|
|
11
|
+
div.__main
|
|
12
|
+
header.dk-component-top-bar? (its own component)
|
|
13
|
+
main.__content
|
|
14
|
+
div.dk-component-action-bar? (its own component)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Attributes
|
|
18
|
+
|
|
19
|
+
| Attribute | Values the stylesheet styles |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `data-contained` | (present or absent) |
|
|
22
|
+
| `data-presentation` | `bar`, `drawer` |
|
|
23
|
+
| `data-sticky` | (present or absent) |
|
|
24
|
+
| `data-variant` | `float`, `floating` |
|
|
25
|
+
|
|
26
|
+
## React
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { AppShell } from '@karmo-co/drift-kit/react';
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
| Prop | Type | Notes |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `sidebar` | `ReactNode` | A Sidebar. |
|
|
35
|
+
| `topBar` | `ReactNode` | A Top bar, usually sticky. |
|
|
36
|
+
| `actionBar` | `ReactNode` | An Action bar, usually sticky. |
|
|
37
|
+
| `children` | `ReactNode` | The page. |
|
|
38
|
+
| `contained` | `boolean` | Fill the parent's box instead of the viewport: the main column scrolls and the phone bar stays in the frame. |
|
|
39
|
+
| `className` | `string` | |
|
|
40
|
+
|
|
41
|
+
## Component tokens
|
|
42
|
+
|
|
43
|
+
`--dk-component-app-shell-surface`, `--dk-component-app-shell-height`, `--dk-component-app-shell-floating-inset`
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Avatar (`avatar`)
|
|
2
|
+
|
|
3
|
+
A person, as their photo or their initials: the photo fades in once it has loaded, and the initials stay if it never does.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Anatomy (HTML)
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
span.dk-component-avatar[data-name][data-size="24|40|48"]?[data-variant="solid"]?[data-hue]?
|
|
10
|
+
img? (the photo; the runtime sets data-loaded)
|
|
11
|
+
span.__initials (written by the runtime from data-name)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Attributes
|
|
15
|
+
|
|
16
|
+
| Attribute | Values the stylesheet styles |
|
|
17
|
+
|---|---|
|
|
18
|
+
| `data-hue` | `next1`, `next2`, `next3`, `next4`, `prev1`, `prev2`, `prev3`, `prev4`, `primary` |
|
|
19
|
+
| `data-loaded` | `error`, `false`, `true` |
|
|
20
|
+
| `data-size` | `24`, `40`, `48` |
|
|
21
|
+
| `data-variant` | `solid` |
|
|
22
|
+
|
|
23
|
+
## React
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { Avatar } from '@karmo-co/drift-kit/react';
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Prop | Type | Notes |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| `name` (required) | `string` | Whose it is: the initials come from it ("Ada Lovelace" is AL). |
|
|
32
|
+
| `src` | `string` | A photo. Until it decodes, and if it fails, the initials show. |
|
|
33
|
+
| `size` | `24 \| 32 \| 40 \| 48` | 32 when absent. |
|
|
34
|
+
| `hue` | `AvatarHue` | A category colour instead of primary, to tell people apart without photos. |
|
|
35
|
+
| `variant` | `'subtle' \| 'solid'` | Subtle when absent. |
|
|
36
|
+
| `label` | `string` | A name for a screen reader, for an avatar that stands on its own. Without one it is decorative: the name is usually written beside it. |
|
|
37
|
+
| `href` | `string` | A link to the person: the avatar becomes an <a>, named by label or name, and steps through hover and press. |
|
|
38
|
+
| `onClick` | `(event: ReactMouseEvent<HTMLElement>) => void` | An action, an account menu say: the avatar becomes a <button>, named by label or name, and steps through hover and press. |
|
|
39
|
+
|
|
40
|
+
## Component tokens
|
|
41
|
+
|
|
42
|
+
`--dk-component-avatar-radius`, `--dk-component-avatar-24-size`, `--dk-component-avatar-24-font-size`, `--dk-component-avatar-32-size`, `--dk-component-avatar-32-font-size`, `--dk-component-avatar-40-size`, `--dk-component-avatar-40-font-size`, `--dk-component-avatar-48-size`, `--dk-component-avatar-48-font-size`, `--dk-component-avatar-font-family`, `--dk-component-avatar-font-weight`, `--dk-component-avatar-letter-spacing`, `--dk-component-avatar-subtle-surface`, `--dk-component-avatar-subtle-text`, `--dk-component-avatar-solid-surface`, `--dk-component-avatar-solid-text`, `--dk-component-avatar-ring`, `--dk-component-avatar-edge-mix`, `--dk-component-avatar-solid-mix-to`, `--dk-component-avatar-hover-mix`, `--dk-component-avatar-active-mix`, `--dk-component-avatar-photo-hover`, `--dk-component-avatar-photo-active`, `--dk-component-avatar-focus-ring`, `--dk-component-avatar-focus-ring-width`, `--dk-component-avatar-transition-duration`, `--dk-component-avatar-fade-duration`, `--dk-component-avatar-fade-easing`
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Body (`body`)
|
|
2
|
+
|
|
3
|
+
The body-copy primitive: one element, eleven colours, two emphasis rungs, four sizes, eight weights, and, unlike the component- library original, aware of the surface it sits on.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Anatomy (HTML)
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
p|span.dk-component-body[data-size="xlarge|large|medium|small|xsmall"]?[data-weight]?[data-color]?[data-emphasis="subtle"]?[data-align]?[data-style]?[data-trim]?
|
|
10
|
+
span.__value? (a figure inside running text)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Attributes
|
|
14
|
+
|
|
15
|
+
| Attribute | Values the stylesheet styles |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `data-align` | `center`, `left`, `right` |
|
|
18
|
+
| `data-color` | `black`, `default`, `error`, `information`, `inverse`, `neutral`, `primary`, `success`, `warning`, `white` |
|
|
19
|
+
| `data-disabled` | (present or absent) |
|
|
20
|
+
| `data-emphasis` | `subtle` |
|
|
21
|
+
| `data-size` | `large`, `medium`, `small`, `xlarge`, `xsmall` |
|
|
22
|
+
| `data-style` | `italic`, `normal`, `underline` |
|
|
23
|
+
| `data-trim` | `both`, `end`, `start` |
|
|
24
|
+
| `data-weight` | `bold`, `extra-bold`, `extra-light`, `light`, `medium`, `regular`, `semi-bold`, `thin` |
|
|
25
|
+
|
|
26
|
+
## React
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { Body } from '@karmo-co/drift-kit/react';
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
| Prop | Type | Notes |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `size` | `'xlarge' \| 'large' \| 'medium' \| 'small' \| 'xsmall'` | |
|
|
35
|
+
| `weight` | `\| 'thin' \| 'extra-light' \| 'light' \| 'regular' \| 'medium' \| 'semi-bold' \| 'bold' \| 'extra-bold'` | |
|
|
36
|
+
| `textStyle` | `'normal' \| 'underline' \| 'italic'` | React owns `style`, so the data-style axis is `textStyle`. This is the one place the mirror-the-HTML rule cannot hold. |
|
|
37
|
+
| `as` | `ElementType` | |
|
|
38
|
+
| `color` | `Color` | |
|
|
39
|
+
| `emphasis` | `Emphasis` | |
|
|
40
|
+
| `align` | `Align` | |
|
|
41
|
+
| `trim` | `Trim` | |
|
|
42
|
+
| `disabled` | `boolean` | A span cannot carry :disabled, so the kit uses [data-disabled]. |
|
|
43
|
+
| `children` | `ReactNode` | |
|
|
44
|
+
| `className` | `string` | |
|
|
45
|
+
|
|
46
|
+
## Component tokens
|
|
47
|
+
|
|
48
|
+
`--dk-component-body-font-family`, `--dk-component-body-transition-duration`, `--dk-component-body-xlarge-font-size`, `--dk-component-body-xlarge-line-height`, `--dk-component-body-large-font-size`, `--dk-component-body-large-line-height`, `--dk-component-body-medium-font-size`, `--dk-component-body-medium-line-height`, `--dk-component-body-small-font-size`, `--dk-component-body-small-line-height`, `--dk-component-body-xsmall-font-size`, `--dk-component-body-xsmall-line-height`, `--dk-component-body-thin-font-weight`, `--dk-component-body-extra-light-font-weight`, `--dk-component-body-light-font-weight`, `--dk-component-body-regular-font-weight`, `--dk-component-body-medium-font-weight`, `--dk-component-body-semi-bold-font-weight`, `--dk-component-body-bold-font-weight`, `--dk-component-body-extra-bold-font-weight`, `--dk-component-body-default-color`, `--dk-component-body-inverse-color`, `--dk-component-body-white-color`, `--dk-component-body-black-color`, `--dk-component-body-primary-color`, `--dk-component-body-success-color`, `--dk-component-body-error-color`, `--dk-component-body-warning-color`, `--dk-component-body-information-color`, `--dk-component-body-neutral-default-color`, `--dk-component-body-neutral-subtle-color`, `--dk-component-body-disabled-color`, `--dk-component-body-value-surface`, `--dk-component-body-value-color`, `--dk-component-body-value-font-weight`, `--dk-component-body-value-font-size`, `--dk-component-body-value-line-height`, `--dk-component-body-value-padding-block`, `--dk-component-body-value-padding-inline`, `--dk-component-body-value-radius`
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Box (`box`)
|
|
2
|
+
|
|
3
|
+
A grouped surface: a panel that separates what is in it from what is around it, optionally laid out as a responsive grid of facts.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Anatomy (HTML)
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
section.dk-component-box[data-variant][data-size][data-tone][data-tone-fill][data-surface]
|
|
10
|
+
header.__header
|
|
11
|
+
div.__heading > .__title + .__description?
|
|
12
|
+
div.__actions?
|
|
13
|
+
dl|div.__grid[data-columns="1..6"][data-dividers][data-align]
|
|
14
|
+
div.__cell[data-span="full"]?
|
|
15
|
+
dt.__label + dd.__value (a fact)
|
|
16
|
+
… or anything
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Attributes
|
|
20
|
+
|
|
21
|
+
| Attribute | Values the stylesheet styles |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `data-align` | `center`, `end`, `start` |
|
|
24
|
+
| `data-columns` | `1`, `2`, `3`, `4`, `5`, `6` |
|
|
25
|
+
| `data-dividers` | `both`, `columns`, `rows` |
|
|
26
|
+
| `data-size` | `large`, `small`, `xlarge`, `xsmall` |
|
|
27
|
+
| `data-span` | `full` |
|
|
28
|
+
| `data-surface` | (present or absent) |
|
|
29
|
+
| `data-tone` | `none` |
|
|
30
|
+
| `data-tone-fill` | `solid` |
|
|
31
|
+
| `data-variant` | `flat`, `inset`, `raised` |
|
|
32
|
+
|
|
33
|
+
## React
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { Box } from '@karmo-co/drift-kit/react';
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| Prop | Type | Notes |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| `variant` | `'outline' \| 'raised' \| 'inset' \| 'flat'` | How the box separates from what is around it. outline (the default) is a hairline, raised lifts it with a shadow, inset presses it in, flat is its fill alone and needs a tone or a surface to be seen. |
|
|
42
|
+
| `size` | `'xsmall' \| 'small' \| 'medium' \| 'large' \| 'xlarge'` | Padding and gaps together: 12, 18, 24 (medium, the default), 32 or 40. Past medium the corner and the header grow with it. |
|
|
43
|
+
| `tone` | `'primary' \| 'success' \| 'warning' \| 'error' \| 'information' \| 'inverse'` | The kit's tone: tints the box and remaps the colours of everything in it. |
|
|
44
|
+
| `toneFill` | `'solid'` | With a tone: the solid fill instead of the tint. |
|
|
45
|
+
| `surface` | `0 \| 1 \| 2` | A step down the neutral ladder (1 or 2), so a flat box reads as a panel. |
|
|
46
|
+
| `title` | `ReactNode` | A header: the title wires aria-labelledby, so the box is a named region. |
|
|
47
|
+
| `titleAs` | `'h2' \| 'h3' \| 'h4' \| 'h5' \| 'h6'` | |
|
|
48
|
+
| `description` | `ReactNode` | |
|
|
49
|
+
| `actions` | `ReactNode` | Beside the title: a Link, a Button, an icon button. |
|
|
50
|
+
| `headerBand` | `boolean` | The header as a band: edge to edge, one level up from the box's surface (a level-2 box steps back to 1), with a hairline under it. On a toned box it carries the tone too. |
|
|
51
|
+
| `columns` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | Lays the children out as a grid of at most this many columns, wrapping to fewer on its own once a column would be narrower than 10rem. Without it the children sit straight in the box, as a plain panel. |
|
|
52
|
+
| `dividers` | `'rows' \| 'columns' \| 'both'` | Hairlines between the cells, correct at any wrap. |
|
|
53
|
+
| `align` | `'start' \| 'center' \| 'end'` | Cells stretch to the row when absent. |
|
|
54
|
+
| `as` | `'section' \| 'div' \| 'aside' \| 'article'` | section when the box has a name (a title or an aria-label), div when it does not; pass one to choose. |
|
|
55
|
+
|
|
56
|
+
## Component tokens
|
|
57
|
+
|
|
58
|
+
`--dk-component-box-xsmall-padding`, `--dk-component-box-small-padding`, `--dk-component-box-padding`, `--dk-component-box-large-padding`, `--dk-component-box-xlarge-padding`, `--dk-component-box-radius`, `--dk-component-box-large-radius`, `--dk-component-box-xlarge-radius`, `--dk-component-box-border-width`, `--dk-component-box-border-color`, `--dk-component-box-raised-border-color`, `--dk-component-box-inset-border-color`, `--dk-component-box-raised-shadow`, `--dk-component-box-inset-shadow`, `--dk-component-box-column-min`, `--dk-component-box-line-color`, `--dk-component-box-line-width`, `--dk-component-box-focus-room`, `--dk-component-box-label-color`, `--dk-component-box-label-font-size`, `--dk-component-box-label-line-height`, `--dk-component-box-label-letter-spacing`, `--dk-component-box-label-font-weight`, `--dk-component-box-fact-gap`, `--dk-component-box-value-color`, `--dk-component-box-value-font-size`, `--dk-component-box-value-line-height`, `--dk-component-box-value-font-weight`, `--dk-component-box-title-font-size`, `--dk-component-box-title-line-height`, `--dk-component-box-title-font-weight`, `--dk-component-box-description-font-size`, `--dk-component-box-description-line-height`, `--dk-component-box-large-title-font-size`, `--dk-component-box-large-title-line-height`, `--dk-component-box-large-description-font-size`, `--dk-component-box-large-description-line-height`, `--dk-component-box-xlarge-title-font-size`, `--dk-component-box-xlarge-title-line-height`, `--dk-component-box-xlarge-description-font-size`, `--dk-component-box-xlarge-description-line-height`, `--dk-component-box-header-gap`, `--dk-component-box-xsmall-band-padding`, `--dk-component-box-small-band-padding`, `--dk-component-box-band-padding`, `--dk-component-box-large-band-padding`, `--dk-component-box-xlarge-band-padding`, `--dk-component-box-font-family`, `--dk-component-box-title-color`, `--dk-component-box-description-color`
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Breadcrumb (`breadcrumb`)
|
|
2
|
+
|
|
3
|
+
Where this page sits, and the way back up: the pages above it as quiet pills, its own name last.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Anatomy (HTML)
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
nav.dk-component-breadcrumb[data-size] (aria-label="Breadcrumb")
|
|
10
|
+
div.dk-component-breadcrumb__arrows (optional, role="group")
|
|
11
|
+
button.dk-component-breadcrumb__arrow (aria-label="Back", then "Forward")
|
|
12
|
+
ol.dk-component-breadcrumb__list
|
|
13
|
+
li.dk-component-breadcrumb__item
|
|
14
|
+
a.dk-component-breadcrumb__link (a page above this one: a pill)
|
|
15
|
+
span.dk-component-breadcrumb__icon (optional, aria-hidden)
|
|
16
|
+
span.dk-component-breadcrumb__label
|
|
17
|
+
li.dk-component-breadcrumb__item (a page with related pages)
|
|
18
|
+
span.dk-component-breadcrumb__pill (the link and its chevron, one pill)
|
|
19
|
+
a.dk-component-breadcrumb__link | span.dk-component-breadcrumb__current
|
|
20
|
+
div.dk-component-dropdown.dk-component-breadcrumb__more
|
|
21
|
+
button.dk-component-breadcrumb__trigger.dk-component-dropdown__trigger
|
|
22
|
+
div.dk-component-menu.dk-component-dropdown__menu
|
|
23
|
+
li.dk-component-breadcrumb__item (the pages folded away)
|
|
24
|
+
div.dk-component-dropdown.dk-component-breadcrumb__more
|
|
25
|
+
button.dk-component-breadcrumb__ellipsis.dk-component-dropdown__trigger ("3 more pages")
|
|
26
|
+
div.dk-component-menu.dk-component-dropdown__menu
|
|
27
|
+
li.dk-component-breadcrumb__item (the last)
|
|
28
|
+
span.dk-component-breadcrumb__current[aria-current="page"][title]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Attributes
|
|
32
|
+
|
|
33
|
+
| Attribute | Values the stylesheet styles |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `data-size` | `small` |
|
|
36
|
+
| `data-tone` | `error`, `information`, `primary`, `success`, `warning` |
|
|
37
|
+
| `data-variant` | `inset`, `plain`, `raised` |
|
|
38
|
+
|
|
39
|
+
## React
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { Breadcrumb } from '@karmo-co/drift-kit/react';
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| Prop | Type | Notes |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| `items` (required) | `BreadcrumbItem[]` | From the top down. The last is the current page. |
|
|
48
|
+
| `size` | `'small' \| 'medium'` | medium when absent. |
|
|
49
|
+
| `variant` | `'ghost' \| 'raised' \| 'plain' \| 'inset'` | |
|
|
50
|
+
| `linkAs` | `ElementType` | The element the ancestors render as: react-router's Link most often, so navigation stays client-side. Each item's own props go to it. |
|
|
51
|
+
| `maxItems` | `number` | Past this many items the middle folds into a "..." pill that opens a Dropdown of them: the first, the "...", the last two. 4 when absent; 0 never folds. |
|
|
52
|
+
| `onBack` | `() => void` | Back and forward arrows in their own pill to the left, shown when either handler is given. |
|
|
53
|
+
| `onForward` | `() => void` | |
|
|
54
|
+
| `backDisabled` | `boolean` | |
|
|
55
|
+
| `forwardDisabled` | `boolean` | |
|
|
56
|
+
|
|
57
|
+
## Component tokens
|
|
58
|
+
|
|
59
|
+
`--dk-component-breadcrumb-small-font-size`, `--dk-component-breadcrumb-small-line-height`, `--dk-component-breadcrumb-font-size`, `--dk-component-breadcrumb-line-height`, `--dk-component-breadcrumb-font-family`, `--dk-component-breadcrumb-gap`, `--dk-component-breadcrumb-separator-size`, `--dk-component-breadcrumb-separator-color`, `--dk-component-breadcrumb-container-separator-color`, `--dk-component-breadcrumb-back-icon`, `--dk-component-breadcrumb-link-color`, `--dk-component-breadcrumb-link-color-hover`, `--dk-component-breadcrumb-link-color-active`, `--dk-component-breadcrumb-link-surface-hover`, `--dk-component-breadcrumb-link-surface-active`, `--dk-component-breadcrumb-link-ring`, `--dk-component-breadcrumb-link-ring-width`, `--dk-component-breadcrumb-link-font-weight`, `--dk-component-breadcrumb-press-scale`, `--dk-component-breadcrumb-padding-block`, `--dk-component-breadcrumb-padding-inline`, `--dk-component-breadcrumb-small-padding-block`, `--dk-component-breadcrumb-small-padding-inline`, `--dk-component-breadcrumb-radius`, `--dk-component-breadcrumb-icon-size`, `--dk-component-breadcrumb-small-icon-size`, `--dk-component-breadcrumb-icon-gap`, `--dk-component-breadcrumb-icon-stroke`, `--dk-component-breadcrumb-small-icon-stroke`, `--dk-component-breadcrumb-chevron-size`, `--dk-component-breadcrumb-current-color`, `--dk-component-breadcrumb-current-icon-color`, `--dk-component-breadcrumb-current-font-weight`, `--dk-component-breadcrumb-current-max-width`, `--dk-component-breadcrumb-container-padding`, `--dk-component-breadcrumb-edged-padding-block`, `--dk-component-breadcrumb-edged-padding-inline`, `--dk-component-breadcrumb-container-radius`, `--dk-component-breadcrumb-container-border-width`, `--dk-component-breadcrumb-raised-surface`, `--dk-component-breadcrumb-raised-border`, `--dk-component-breadcrumb-raised-shadow`, `--dk-component-breadcrumb-plain-border`, `--dk-component-breadcrumb-inset-surface`, `--dk-component-breadcrumb-divider`, `--dk-component-breadcrumb-divider-space`, `--dk-component-breadcrumb-inset-divider`, `--dk-component-breadcrumb-inset-toned-color`, `--dk-component-breadcrumb-arrows-surface`, `--dk-component-breadcrumb-arrows-radius`, `--dk-component-breadcrumb-arrow-radius`, `--dk-component-breadcrumb-arrows-padding`, `--dk-component-breadcrumb-arrows-gap`, `--dk-component-breadcrumb-arrows-margin`, `--dk-component-breadcrumb-arrow-size`, `--dk-component-breadcrumb-arrow-icon-size`, `--dk-component-breadcrumb-small-arrow-size`, `--dk-component-breadcrumb-small-arrow-icon-size`, `--dk-component-breadcrumb-arrow-color`, `--dk-component-breadcrumb-arrow-color-hover`, `--dk-component-breadcrumb-arrow-surface-hover`, `--dk-component-breadcrumb-arrow-surface-active`, `--dk-component-breadcrumb-arrow-color-disabled`
|