@xenosystem/elements-react 0.0.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.
- package/LICENSE +18 -0
- package/README.md +41 -0
- package/dist/XenoElement.d.ts +39 -0
- package/dist/XenoElement.js +25 -0
- package/dist/containers/Avatar.d.ts +42 -0
- package/dist/containers/Avatar.js +29 -0
- package/dist/containers/Badges.d.ts +61 -0
- package/dist/containers/Badges.js +43 -0
- package/dist/containers/Card.d.ts +24 -0
- package/dist/containers/Card.js +5 -0
- package/dist/containers/Chip.d.ts +34 -0
- package/dist/containers/Chip.js +17 -0
- package/dist/containers/DataTable.d.ts +28 -0
- package/dist/containers/DataTable.js +13 -0
- package/dist/containers/ListRow.d.ts +37 -0
- package/dist/containers/ListRow.js +40 -0
- package/dist/containers/MessageBubble.d.ts +33 -0
- package/dist/containers/MessageBubble.js +9 -0
- package/dist/containers/Panel.d.ts +24 -0
- package/dist/containers/Panel.js +6 -0
- package/dist/containers/Table.d.ts +39 -0
- package/dist/containers/Table.js +20 -0
- package/dist/containers/Tile.d.ts +19 -0
- package/dist/containers/Tile.js +7 -0
- package/dist/content/Callout.d.ts +32 -0
- package/dist/content/Callout.js +10 -0
- package/dist/content/Caret.d.ts +9 -0
- package/dist/content/Caret.js +5 -0
- package/dist/content/CodeBlock.d.ts +36 -0
- package/dist/content/CodeBlock.js +50 -0
- package/dist/content/Collapsible.d.ts +24 -0
- package/dist/content/Collapsible.js +19 -0
- package/dist/content/InlineCode.d.ts +12 -0
- package/dist/content/InlineCode.js +5 -0
- package/dist/content/ModelPicker.d.ts +45 -0
- package/dist/content/ModelPicker.js +124 -0
- package/dist/content/SourceCard.d.ts +23 -0
- package/dist/content/SourceCard.js +18 -0
- package/dist/content/SourcesDisclosure.d.ts +26 -0
- package/dist/content/SourcesDisclosure.js +20 -0
- package/dist/controls/Button.d.ts +39 -0
- package/dist/controls/Button.js +16 -0
- package/dist/controls/ConfirmButton.d.ts +22 -0
- package/dist/controls/ConfirmButton.js +22 -0
- package/dist/controls/IconButton.d.ts +45 -0
- package/dist/controls/IconButton.js +15 -0
- package/dist/controls/Switch.d.ts +11 -0
- package/dist/controls/Switch.js +23 -0
- package/dist/controls/TextInput.d.ts +13 -0
- package/dist/controls/TextInput.js +6 -0
- package/dist/controls/Textarea.d.ts +8 -0
- package/dist/controls/Textarea.js +5 -0
- package/dist/controls/ToggleButton.d.ts +23 -0
- package/dist/controls/ToggleButton.js +23 -0
- package/dist/controls/util.d.ts +48 -0
- package/dist/controls/util.js +23 -0
- package/dist/forms/Checkbox.d.ts +18 -0
- package/dist/forms/Checkbox.js +28 -0
- package/dist/forms/RadioGroup.d.ts +51 -0
- package/dist/forms/RadioGroup.js +83 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +81 -0
- package/dist/layout/ResizablePanel.d.ts +40 -0
- package/dist/layout/ResizablePanel.js +108 -0
- package/dist/nav/Sidebar.d.ts +60 -0
- package/dist/nav/Sidebar.js +84 -0
- package/dist/overlays/DateTimePicker.d.ts +71 -0
- package/dist/overlays/DateTimePicker.js +191 -0
- package/dist/overlays/Menu.d.ts +28 -0
- package/dist/overlays/Menu.js +32 -0
- package/dist/overlays/MenuItem.d.ts +71 -0
- package/dist/overlays/MenuItem.js +15 -0
- package/dist/overlays/Modal.d.ts +36 -0
- package/dist/overlays/Modal.js +27 -0
- package/dist/overlays/PickerField.d.ts +32 -0
- package/dist/overlays/PickerField.js +40 -0
- package/dist/overlays/PillFilter.d.ts +25 -0
- package/dist/overlays/PillFilter.js +41 -0
- package/dist/overlays/Popover.d.ts +32 -0
- package/dist/overlays/Popover.js +38 -0
- package/dist/overlays/Reveal.d.ts +20 -0
- package/dist/overlays/Reveal.js +45 -0
- package/dist/overlays/SegmentedControl.d.ts +23 -0
- package/dist/overlays/SegmentedControl.js +43 -0
- package/dist/overlays/Tabs.d.ts +32 -0
- package/dist/overlays/Tabs.js +142 -0
- package/dist/overlays/Tooltip.d.ts +23 -0
- package/dist/overlays/Tooltip.js +61 -0
- package/dist/status/ProgressBar.d.ts +20 -0
- package/dist/status/ProgressBar.js +11 -0
- package/dist/status/Spinner.d.ts +16 -0
- package/dist/status/Spinner.js +12 -0
- package/dist/status/StatusIndicator.d.ts +19 -0
- package/dist/status/StatusIndicator.js +11 -0
- package/dist/status/StepTimeline.d.ts +26 -0
- package/dist/status/StepTimeline.js +16 -0
- package/dist/status/ThinkingCube.d.ts +24 -0
- package/dist/status/ThinkingCube.js +11 -0
- package/dist/useDialog.d.ts +45 -0
- package/dist/useDialog.js +122 -0
- package/dist/useGooPill.d.ts +57 -0
- package/dist/useGooPill.js +76 -0
- package/dist/useMenu.d.ts +50 -0
- package/dist/useMenu.js +119 -0
- package/dist/useTabs.d.ts +88 -0
- package/dist/useTabs.js +93 -0
- package/package.json +58 -0
- package/src/chrome-separated.css +132 -0
- package/src/chrome-unified.css +72 -0
- package/src/containers/Badges.css +116 -0
- package/src/containers/avatar.css +70 -0
- package/src/containers/card.css +75 -0
- package/src/containers/chip.css +103 -0
- package/src/containers/list-row.css +132 -0
- package/src/containers/message-bubble.css +112 -0
- package/src/containers/panel.css +120 -0
- package/src/containers/table.css +102 -0
- package/src/containers/tile.css +17 -0
- package/src/content/callout.css +77 -0
- package/src/content/caret.css +30 -0
- package/src/content/code-block.css +159 -0
- package/src/content/collapsible.css +80 -0
- package/src/content/inline-code.css +14 -0
- package/src/content/model-picker.css +219 -0
- package/src/content/source-card.css +99 -0
- package/src/content/sources-disclosure.css +118 -0
- package/src/controls.css +453 -0
- package/src/fonts.css +34 -0
- package/src/forms/Checkbox.css +114 -0
- package/src/forms/RadioGroup.css +115 -0
- package/src/goo.css +97 -0
- package/src/icon-motion.css +1909 -0
- package/src/layout/ResizablePanel.css +79 -0
- package/src/nav/sidebar.css +296 -0
- package/src/overlays/date-time-picker.css +238 -0
- package/src/overlays/menu.css +195 -0
- package/src/overlays/modal.css +167 -0
- package/src/overlays/picker-field.css +81 -0
- package/src/overlays/pill-filter.css +129 -0
- package/src/overlays/reveal.css +56 -0
- package/src/overlays/segmented-control.css +185 -0
- package/src/overlays/tabs.css +143 -0
- package/src/overlays/tooltip.css +126 -0
- package/src/scrollbar.css +184 -0
- package/src/size.css +179 -0
- package/src/status/progress-bar.css +88 -0
- package/src/status/spinner.css +33 -0
- package/src/status/statusindicator.css +65 -0
- package/src/status/steptimeline.css +137 -0
- package/src/status/thinkingcube.css +75 -0
- package/src/xeno-element.css +60 -0
- package/src/xeno-elements.css +71 -0
- package/src/xeno-theme.css +99 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Panel — a chrome stack: heading, body, footer.
|
|
3
|
+
*
|
|
4
|
+
* Every construction value comes from the `--xeno-chrome-*` tokens, so the SAME DOM renders as either
|
|
5
|
+
* chrome. Under `separated` (the default, required by DESIGN_SYSTEM.md §"Panel Structure") the wrapper
|
|
6
|
+
* paints the page colour and the three plates float on it with a 2px gap. Under `unified` the gap
|
|
7
|
+
* collapses to 0, the plates go transparent, the wrapper paints the surface and clips them, and the
|
|
8
|
+
* dividers come back — one card, exactly as this set rendered before the chrome axis existed.
|
|
9
|
+
*
|
|
10
|
+
* Nothing here knows a theme exists. That is the point: no component is built twice.
|
|
11
|
+
*
|
|
12
|
+
* Scrolling is chrome-independent — give the panel a bounded height and the body scrolls on its own
|
|
13
|
+
* (`min-height: 0` lets a flex child shrink below its content).
|
|
14
|
+
*/
|
|
15
|
+
.xeno-panel {
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
gap: var(--xeno-chrome-gap);
|
|
19
|
+
padding: var(--xeno-chrome-inset);
|
|
20
|
+
min-height: 0;
|
|
21
|
+
background: var(--xeno-chrome-shell);
|
|
22
|
+
/* `separated` draws no border on the wrapper — the plates carry their own. `unified` needs one,
|
|
23
|
+
and gets it because the shell is painted and clipped. Both read the same token. */
|
|
24
|
+
border: 1px solid var(--xeno-chrome-border);
|
|
25
|
+
border-radius: var(--xeno-chrome-radius);
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
color: var(--xeno-text);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/*
|
|
31
|
+
* Heading plate. §"Panel Structure" fixes it at 34px so headings line up with sidebar navigation
|
|
32
|
+
* across a product; the padding sets the text inside that rather than defining the height.
|
|
33
|
+
*/
|
|
34
|
+
.xeno-panel-header {
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
justify-content: space-between;
|
|
38
|
+
gap: 12px;
|
|
39
|
+
flex: 0 0 auto;
|
|
40
|
+
min-height: var(--xeno-chrome-panel-header-min-h);
|
|
41
|
+
padding: var(--xeno-chrome-panel-header-pad);
|
|
42
|
+
background: var(--xeno-chrome-plate);
|
|
43
|
+
-webkit-backdrop-filter: var(--xeno-chrome-plate-filter);
|
|
44
|
+
backdrop-filter: var(--xeno-chrome-plate-filter);
|
|
45
|
+
border-bottom: var(--xeno-chrome-divider);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/*
|
|
49
|
+
* §"Headers and Footers": the header text is "small, uppercase, with letter-spacing. It functions as
|
|
50
|
+
* a label, not a headline." Matches the convention the code-block language chip already uses.
|
|
51
|
+
*/
|
|
52
|
+
.xeno-panel-title {
|
|
53
|
+
min-width: 0;
|
|
54
|
+
color: var(--xeno-chrome-title-color);
|
|
55
|
+
font-size: var(--xeno-chrome-title-size);
|
|
56
|
+
font-weight: 600;
|
|
57
|
+
letter-spacing: var(--xeno-chrome-title-spacing);
|
|
58
|
+
text-transform: var(--xeno-chrome-title-transform);
|
|
59
|
+
line-height: 1.2;
|
|
60
|
+
overflow: hidden;
|
|
61
|
+
text-overflow: ellipsis;
|
|
62
|
+
white-space: nowrap;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.xeno-panel-actions {
|
|
66
|
+
display: inline-flex;
|
|
67
|
+
align-items: center;
|
|
68
|
+
gap: 6px;
|
|
69
|
+
flex: 0 0 auto;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Body plate — the scroll region. */
|
|
73
|
+
.xeno-panel-body {
|
|
74
|
+
flex: 1 1 auto;
|
|
75
|
+
min-height: 0;
|
|
76
|
+
padding: var(--xeno-chrome-panel-body-pad);
|
|
77
|
+
overflow: auto;
|
|
78
|
+
background: var(--xeno-chrome-body);
|
|
79
|
+
color: var(--xeno-text);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
* Footer plate — §"Headers and Footers": "Footer padding matches header padding exactly. Headers and
|
|
84
|
+
* footers are visually symmetric." Every box metric below is the header's, duplicated deliberately
|
|
85
|
+
* rather than shared through a common class: the symmetry is a design rule a future change must break
|
|
86
|
+
* on purpose, and a shared class would let one drift silently while the other did not.
|
|
87
|
+
*
|
|
88
|
+
* `space-between` gives the dismiss-left / confirm-right arrangement the products already use.
|
|
89
|
+
*/
|
|
90
|
+
.xeno-panel-footer {
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
justify-content: space-between;
|
|
94
|
+
gap: 12px;
|
|
95
|
+
flex: 0 0 auto;
|
|
96
|
+
min-height: var(--xeno-chrome-panel-header-min-h);
|
|
97
|
+
padding: var(--xeno-chrome-panel-header-pad);
|
|
98
|
+
background: var(--xeno-chrome-plate);
|
|
99
|
+
border-top: var(--xeno-chrome-divider);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/*
|
|
103
|
+
* §4 "Radius Is Per-Corner, Not Per-Element": a corner is rounded only where the surface meets
|
|
104
|
+
* NOTHING. Each plate faces its neighbour across the 2px gap, so the facing corners are SQUARE — a
|
|
105
|
+
* uniform radius on every plate is the tell that this section was skipped, and it was.
|
|
106
|
+
*
|
|
107
|
+
* Declared on first/last child rather than per plate so a stack with no header, or no footer, still
|
|
108
|
+
* presents a rounded outer edge instead of a square one against the rounded shell.
|
|
109
|
+
*/
|
|
110
|
+
.xeno-panel > * {
|
|
111
|
+
border-radius: 0;
|
|
112
|
+
}
|
|
113
|
+
.xeno-panel > :first-child {
|
|
114
|
+
border-top-left-radius: var(--xeno-chrome-radius-plate);
|
|
115
|
+
border-top-right-radius: var(--xeno-chrome-radius-plate);
|
|
116
|
+
}
|
|
117
|
+
.xeno-panel > :last-child {
|
|
118
|
+
border-bottom-left-radius: var(--xeno-chrome-radius-plate);
|
|
119
|
+
border-bottom-right-radius: var(--xeno-chrome-radius-plate);
|
|
120
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Dense table styles — the locked grammar for Table / DataTable. CSS-first: appearance is driven by
|
|
3
|
+
* the `xeno-*` classes plus the `data-align` / `data-selection` seams, reading only the theme custom
|
|
4
|
+
* properties from `xeno-theme.css`. Border-collapse with hairline BOTTOM row rules only — no vertical
|
|
5
|
+
* rules, no zebra striping. Monochrome throughout; no literal colours.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
.xeno-table {
|
|
9
|
+
width: 100%;
|
|
10
|
+
border-collapse: collapse;
|
|
11
|
+
font-size: 0.9em;
|
|
12
|
+
color: var(--xeno-text);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.xeno-th,
|
|
16
|
+
.xeno-td {
|
|
17
|
+
padding: 6px 11px;
|
|
18
|
+
text-align: left;
|
|
19
|
+
vertical-align: middle;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.xeno-th {
|
|
23
|
+
color: var(--xeno-muted);
|
|
24
|
+
font-weight: 600;
|
|
25
|
+
font-size: 0.85em;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Bottom border only on rows — the sole rule; header row divider comes for free. */
|
|
29
|
+
.xeno-tr {
|
|
30
|
+
border-bottom: 1px solid var(--xeno-border);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* ── Tracking a row ───────────────────────────────────────────────────────────────────
|
|
34
|
+
* A dense table is READ by running your eye along a line, and until now nothing under the pointer
|
|
35
|
+
* answered — which is what makes a table feel like a picture of data instead of data.
|
|
36
|
+
*
|
|
37
|
+
* The restraint here is deliberate and is the opposite of the choice made for the toggles: no flood,
|
|
38
|
+
* no travel. You cross a dozen rows in a second while scanning, and anything with a 300ms gesture
|
|
39
|
+
* would still be arriving when you have already left. A wash that is simply THERE is the correct
|
|
40
|
+
* answer; the only thing that moves is a hairline on the leading edge, and it moves in 140ms.
|
|
41
|
+
*
|
|
42
|
+
* Body rows only. The header is not a row you track, and neither is the empty-state row — there is
|
|
43
|
+
* nothing under the pointer there to answer for. */
|
|
44
|
+
.xeno-tbody .xeno-tr:hover:not(:has(.xeno-table-empty)) {
|
|
45
|
+
background: var(--xeno-hover);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Selection axis — a step ABOVE the hover wash, not the same token. They used to share
|
|
49
|
+
`--xeno-hover`, so once rows answered the pointer a hovered row and a selected row were the same
|
|
50
|
+
colour, and the selection stopped meaning anything. */
|
|
51
|
+
.xeno-tr[data-selection='on'] {
|
|
52
|
+
background: var(--xeno-control);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* The leading-edge mark: a hairline that grows from the middle of the row, on hover and on selection.
|
|
56
|
+
It lives on the first cell rather than the row, because a `<tr>` is not a reliable containing block
|
|
57
|
+
under `border-collapse` — cells are. */
|
|
58
|
+
.xeno-tbody .xeno-tr > :first-child {
|
|
59
|
+
position: relative;
|
|
60
|
+
}
|
|
61
|
+
.xeno-tbody .xeno-tr > :first-child::before {
|
|
62
|
+
content: '';
|
|
63
|
+
position: absolute;
|
|
64
|
+
left: 0;
|
|
65
|
+
top: 0;
|
|
66
|
+
bottom: 0;
|
|
67
|
+
width: 2px;
|
|
68
|
+
background: var(--xeno-text);
|
|
69
|
+
border-radius: var(--xeno-radius-hair, 1.5px);
|
|
70
|
+
transform: scaleY(0);
|
|
71
|
+
transform-origin: center;
|
|
72
|
+
}
|
|
73
|
+
.xeno-tbody .xeno-tr:hover:not(:has(.xeno-table-empty)) > :first-child::before,
|
|
74
|
+
.xeno-tbody .xeno-tr[data-selection='on'] > :first-child::before {
|
|
75
|
+
transform: scaleY(1);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* Alignment overrides (data-* seam). */
|
|
79
|
+
.xeno-th[data-align='center'],
|
|
80
|
+
.xeno-td[data-align='center'] {
|
|
81
|
+
text-align: center;
|
|
82
|
+
}
|
|
83
|
+
.xeno-th[data-align='right'],
|
|
84
|
+
.xeno-td[data-align='right'] {
|
|
85
|
+
text-align: right;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Empty state — muted, roomy, column-spanning. */
|
|
89
|
+
.xeno-table-empty {
|
|
90
|
+
padding: 18px 11px;
|
|
91
|
+
color: var(--xeno-muted);
|
|
92
|
+
text-align: center;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
96
|
+
.xeno-tr {
|
|
97
|
+
transition: background var(--xeno-dur) var(--xeno-ease);
|
|
98
|
+
}
|
|
99
|
+
.xeno-tbody .xeno-tr > :first-child::before {
|
|
100
|
+
transition: transform var(--xeno-dur) var(--xeno-ease);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tile — a square icon tile. Rounded square (radius-md), a surface ground, a hairline border, and a
|
|
3
|
+
* centred glyph in muted ink. The box edge arrives as an inline `--xeno-tile-size` var. No literal
|
|
4
|
+
* colours; monochrome shell.
|
|
5
|
+
*/
|
|
6
|
+
.xeno-tile {
|
|
7
|
+
display: inline-flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
flex: 0 0 auto;
|
|
11
|
+
width: var(--xeno-tile-size, 32px);
|
|
12
|
+
height: var(--xeno-tile-size, 32px);
|
|
13
|
+
color: var(--xeno-muted);
|
|
14
|
+
background: var(--xeno-surface);
|
|
15
|
+
border: 1px solid var(--xeno-border);
|
|
16
|
+
border-radius: var(--xeno-radius-md);
|
|
17
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* <Callout> — a left-ruled blockquote. Monochrome by default (muted italic ink, hairline rule); the
|
|
3
|
+
* `danger` tone is the sole exception, swapping the rule and the glyph to `--xeno-danger`. Tokens only.
|
|
4
|
+
*
|
|
5
|
+
* The rule is a pseudo-element rather than a `border-left` for one reason: a border cannot be scaled
|
|
6
|
+
* from its top edge, and the entrance below is the rule DRAWING DOWN. Everything else about it is
|
|
7
|
+
* identical — 2px wide, flush left, the same total 14px inset to the text.
|
|
8
|
+
*/
|
|
9
|
+
.xeno-callout {
|
|
10
|
+
position: relative;
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding-left: 14px;
|
|
13
|
+
color: var(--xeno-muted);
|
|
14
|
+
font-style: italic;
|
|
15
|
+
}
|
|
16
|
+
.xeno-callout::before {
|
|
17
|
+
content: '';
|
|
18
|
+
position: absolute;
|
|
19
|
+
left: 0;
|
|
20
|
+
top: 0;
|
|
21
|
+
bottom: 0;
|
|
22
|
+
width: 2px;
|
|
23
|
+
background: var(--xeno-border);
|
|
24
|
+
/* Square: at 2px wide a 1.5px radius is 75% of the width, which is a capsule, not a corner. */
|
|
25
|
+
border-radius: 0;
|
|
26
|
+
transform-origin: top center;
|
|
27
|
+
}
|
|
28
|
+
.xeno-callout[data-tone='danger']::before {
|
|
29
|
+
background: var(--xeno-danger);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* The flex row exists ONLY when there is a glyph. Without one the children stay direct descendants of
|
|
33
|
+
the blockquote, so a run of `<p>`s lays out as prose rather than as a row of flex items. */
|
|
34
|
+
.xeno-callout[data-icon] {
|
|
35
|
+
display: flex;
|
|
36
|
+
align-items: flex-start;
|
|
37
|
+
gap: 9px;
|
|
38
|
+
}
|
|
39
|
+
.xeno-callout-icon {
|
|
40
|
+
display: inline-flex;
|
|
41
|
+
flex: none;
|
|
42
|
+
margin-top: 1px; /* optical: the glyph's box sits a hair above the italic x-height */
|
|
43
|
+
color: var(--xeno-muted);
|
|
44
|
+
}
|
|
45
|
+
.xeno-callout[data-tone='danger'] .xeno-callout-icon {
|
|
46
|
+
color: var(--xeno-danger);
|
|
47
|
+
}
|
|
48
|
+
.xeno-callout-body {
|
|
49
|
+
min-width: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* ── Entrance ─────────────────────────────────────────────────────────────────────────
|
|
53
|
+
* The rule leads and the text follows it in. Two tracks rather than one fade, because the rule IS the
|
|
54
|
+
* callout's form — a block that simply fades up could be any block, while a rule drawing down from the
|
|
55
|
+
* top is unmistakably this one. The rule takes longer than the text on purpose: it is still arriving
|
|
56
|
+
* as the words settle, so the two read as one gesture instead of two. */
|
|
57
|
+
.xeno-callout[data-enter] {
|
|
58
|
+
animation: xeno-callout-in var(--xeno-dur-entrance, 240ms) var(--xeno-ease) both;
|
|
59
|
+
}
|
|
60
|
+
.xeno-callout[data-enter]::before {
|
|
61
|
+
animation: xeno-callout-rule 320ms var(--xeno-ease-expo, cubic-bezier(0.16, 1, 0.3, 1)) both;
|
|
62
|
+
}
|
|
63
|
+
@keyframes xeno-callout-in {
|
|
64
|
+
from { opacity: 0; translate: 5px 0; }
|
|
65
|
+
to { opacity: 1; translate: 0 0; }
|
|
66
|
+
}
|
|
67
|
+
@keyframes xeno-callout-rule {
|
|
68
|
+
from { scale: 1 0; }
|
|
69
|
+
to { scale: 1 1; }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@media (prefers-reduced-motion: reduce) {
|
|
73
|
+
.xeno-callout[data-enter],
|
|
74
|
+
.xeno-callout[data-enter]::before {
|
|
75
|
+
animation: none;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* <Caret> — a thin streaming caret. A hairline `--xeno-text` block, `radius-hair` corners, sized to the
|
|
3
|
+
* line via `1em`. It blinks only under `prefers-reduced-motion: no-preference`; otherwise it holds solid.
|
|
4
|
+
*/
|
|
5
|
+
.xeno-caret {
|
|
6
|
+
display: inline-block;
|
|
7
|
+
width: 2px;
|
|
8
|
+
height: 1em;
|
|
9
|
+
margin-left: 1px;
|
|
10
|
+
vertical-align: text-bottom;
|
|
11
|
+
background: var(--xeno-text);
|
|
12
|
+
border-radius: var(--xeno-radius-hair);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
16
|
+
.xeno-caret {
|
|
17
|
+
animation: xeno-caret-blink 1s steps(1, end) infinite;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@keyframes xeno-caret-blink {
|
|
22
|
+
0%,
|
|
23
|
+
50% {
|
|
24
|
+
opacity: 1;
|
|
25
|
+
}
|
|
26
|
+
50.01%,
|
|
27
|
+
100% {
|
|
28
|
+
opacity: 0;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* CodeBlock — a monochrome code surface. Shell is greyscale (canvas card + hairline border); the code is
|
|
3
|
+
* the ink. State is CSS-first: `data-collapsed` on the root swaps body↔summary and rotates the chevron;
|
|
4
|
+
* `data-selection` on the copy button reflects the transient copied state. Tokens only — the sole hue is
|
|
5
|
+
* `--xeno-danger`, and only on an error output. Motion is transform/opacity, behind the reduce guard.
|
|
6
|
+
*/
|
|
7
|
+
.xeno-code {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
min-width: 0;
|
|
11
|
+
background: var(--xeno-canvas);
|
|
12
|
+
border: 1px solid var(--xeno-border);
|
|
13
|
+
border-radius: var(--xeno-radius-card);
|
|
14
|
+
color: var(--xeno-text);
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* ── Header: language label + action row ─────────────────────────────────────────── */
|
|
19
|
+
.xeno-code-header {
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: space-between;
|
|
23
|
+
gap: 8px;
|
|
24
|
+
padding: 5px 6px 5px 12px;
|
|
25
|
+
background: var(--xeno-surface);
|
|
26
|
+
border-bottom: 1px solid var(--xeno-border);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.xeno-code-lang {
|
|
30
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
31
|
+
font-size: 11px;
|
|
32
|
+
font-weight: 600;
|
|
33
|
+
letter-spacing: 0.08em;
|
|
34
|
+
text-transform: uppercase;
|
|
35
|
+
color: var(--xeno-muted);
|
|
36
|
+
white-space: nowrap;
|
|
37
|
+
user-select: none;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.xeno-code-actions {
|
|
41
|
+
display: inline-flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
gap: 2px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Copy button reflects the ~1.5s copied confirmation (icon swaps to Check; ink lifts to full text). */
|
|
47
|
+
.xeno-code-copy.is-copied {
|
|
48
|
+
color: var(--xeno-text);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* Collapse chevron: points down when open, rotates to point right when collapsed. */
|
|
52
|
+
.xeno-code-collapse .xeno-element {
|
|
53
|
+
transition: transform var(--xeno-dur) var(--xeno-ease);
|
|
54
|
+
}
|
|
55
|
+
.xeno-code[data-collapsed='true'] .xeno-code-collapse .xeno-element {
|
|
56
|
+
transform: rotate(-90deg);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* ── Body: <pre><code>, monospace, horizontally scrollable ───────────────────────── */
|
|
60
|
+
.xeno-code-body {
|
|
61
|
+
margin: 0;
|
|
62
|
+
padding: 12px 14px;
|
|
63
|
+
overflow-x: auto;
|
|
64
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
65
|
+
font-size: 13px;
|
|
66
|
+
line-height: 1.55;
|
|
67
|
+
color: var(--xeno-text);
|
|
68
|
+
tab-size: 2;
|
|
69
|
+
}
|
|
70
|
+
.xeno-code-body:focus-visible {
|
|
71
|
+
outline: none;
|
|
72
|
+
box-shadow: inset 0 0 0 2px var(--xeno-border);
|
|
73
|
+
}
|
|
74
|
+
.xeno-code-code {
|
|
75
|
+
display: block;
|
|
76
|
+
font: inherit;
|
|
77
|
+
color: inherit;
|
|
78
|
+
white-space: pre;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Collapsed ↔ expanded: swap body for the summary line. */
|
|
82
|
+
.xeno-code[data-collapsed='true'] .xeno-code-body {
|
|
83
|
+
display: none;
|
|
84
|
+
}
|
|
85
|
+
.xeno-code[data-collapsed='false'] .xeno-code-summary {
|
|
86
|
+
display: none;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.xeno-code-summary {
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
width: 100%;
|
|
93
|
+
padding: 10px 14px;
|
|
94
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
95
|
+
font-size: 12px;
|
|
96
|
+
color: var(--xeno-muted);
|
|
97
|
+
text-align: left;
|
|
98
|
+
background: transparent;
|
|
99
|
+
border: none;
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
transition:
|
|
102
|
+
color var(--xeno-dur) ease,
|
|
103
|
+
background var(--xeno-dur) ease;
|
|
104
|
+
}
|
|
105
|
+
.xeno-code-summary:hover {
|
|
106
|
+
color: var(--xeno-text);
|
|
107
|
+
background: var(--xeno-hover);
|
|
108
|
+
}
|
|
109
|
+
.xeno-code-summary:focus-visible {
|
|
110
|
+
outline: none;
|
|
111
|
+
box-shadow: inset 0 0 0 2px var(--xeno-border);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* ── Output panel: Running… / result / error ─────────────────────────────────────── */
|
|
115
|
+
.xeno-code-output {
|
|
116
|
+
padding: 10px 14px;
|
|
117
|
+
background: var(--xeno-elevated);
|
|
118
|
+
border-top: 1px solid var(--xeno-border);
|
|
119
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
120
|
+
font-size: 12.5px;
|
|
121
|
+
line-height: 1.5;
|
|
122
|
+
}
|
|
123
|
+
.xeno-code-output-running {
|
|
124
|
+
color: var(--xeno-muted);
|
|
125
|
+
}
|
|
126
|
+
.xeno-code-output-text {
|
|
127
|
+
margin: 0;
|
|
128
|
+
overflow-x: auto;
|
|
129
|
+
white-space: pre-wrap;
|
|
130
|
+
color: var(--xeno-text);
|
|
131
|
+
}
|
|
132
|
+
.xeno-code-output[data-status='error'] {
|
|
133
|
+
border-top-color: var(--xeno-danger);
|
|
134
|
+
}
|
|
135
|
+
.xeno-code-output[data-status='error'] .xeno-code-output-text {
|
|
136
|
+
color: var(--xeno-danger);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
140
|
+
.xeno-code-output[data-status='running'] .xeno-code-output-running {
|
|
141
|
+
animation: xeno-code-pulse 1.2s var(--xeno-ease) infinite;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
@keyframes xeno-code-pulse {
|
|
145
|
+
0%,
|
|
146
|
+
100% {
|
|
147
|
+
opacity: 0.5;
|
|
148
|
+
}
|
|
149
|
+
50% {
|
|
150
|
+
opacity: 1;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@media (prefers-reduced-motion: reduce) {
|
|
155
|
+
.xeno-code-collapse .xeno-element,
|
|
156
|
+
.xeno-code-summary {
|
|
157
|
+
transition: none;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* <Collapsible> — a "Thoughts"-style disclosure. Borderless summary (lightbulb glyph + label + chevron)
|
|
3
|
+
* over a Callout-like body (2px `--xeno-border` left rule, 12px inset). CSS-first: `data-open` on the root
|
|
4
|
+
* rotates the chevron and lifts the label ink. Tokens only; motion is transform/opacity behind the guard.
|
|
5
|
+
*/
|
|
6
|
+
.xeno-collapsible {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/* Summary — a borderless text button, left-aligned to its content. */
|
|
12
|
+
.xeno-collapsible-summary {
|
|
13
|
+
display: inline-flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
align-self: flex-start;
|
|
16
|
+
gap: 6px;
|
|
17
|
+
padding: 2px 4px 2px 0;
|
|
18
|
+
background: transparent;
|
|
19
|
+
border: none;
|
|
20
|
+
border-radius: var(--xeno-radius-sm);
|
|
21
|
+
color: var(--xeno-muted);
|
|
22
|
+
font: inherit;
|
|
23
|
+
font-size: 13px;
|
|
24
|
+
text-align: left;
|
|
25
|
+
cursor: pointer;
|
|
26
|
+
transition: color var(--xeno-dur) var(--xeno-ease);
|
|
27
|
+
}
|
|
28
|
+
.xeno-collapsible-summary:hover {
|
|
29
|
+
color: var(--xeno-text);
|
|
30
|
+
}
|
|
31
|
+
.xeno-collapsible-summary:focus-visible {
|
|
32
|
+
outline: none;
|
|
33
|
+
color: var(--xeno-text);
|
|
34
|
+
box-shadow:
|
|
35
|
+
0 0 0 2px var(--xeno-canvas),
|
|
36
|
+
0 0 0 4px var(--xeno-border);
|
|
37
|
+
}
|
|
38
|
+
.xeno-collapsible[data-open] .xeno-collapsible-summary {
|
|
39
|
+
color: var(--xeno-text);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.xeno-collapsible-icon {
|
|
43
|
+
display: inline-flex;
|
|
44
|
+
flex: none;
|
|
45
|
+
color: var(--xeno-muted);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.xeno-collapsible-label {
|
|
49
|
+
flex: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Chevron — points right when closed, down when open (root carries the seam). */
|
|
53
|
+
.xeno-collapsible-chevron {
|
|
54
|
+
display: inline-flex;
|
|
55
|
+
flex: none;
|
|
56
|
+
color: var(--xeno-muted);
|
|
57
|
+
transform: rotate(-90deg);
|
|
58
|
+
transition: transform var(--xeno-dur) var(--xeno-ease);
|
|
59
|
+
}
|
|
60
|
+
.xeno-collapsible[data-open] .xeno-collapsible-chevron {
|
|
61
|
+
transform: rotate(0deg);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Body — set apart like a Callout; hidden until open. */
|
|
65
|
+
.xeno-collapsible-body {
|
|
66
|
+
margin-top: 6px;
|
|
67
|
+
padding-left: 12px;
|
|
68
|
+
border-left: 2px solid var(--xeno-border);
|
|
69
|
+
color: var(--xeno-muted);
|
|
70
|
+
}
|
|
71
|
+
.xeno-collapsible-body[hidden] {
|
|
72
|
+
display: none;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@media (prefers-reduced-motion: reduce) {
|
|
76
|
+
.xeno-collapsible-summary,
|
|
77
|
+
.xeno-collapsible-chevron {
|
|
78
|
+
transition: none;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* <InlineCode> — an inline monospace chip for prose. Monochrome shell: a `--xeno-surface` fill and
|
|
3
|
+
* `--xeno-text` ink (never the legacy peach), `radius-sm` corners, tight padding. Tokens only, no hue.
|
|
4
|
+
*/
|
|
5
|
+
.xeno-inline-code {
|
|
6
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
7
|
+
font-size: 0.875em;
|
|
8
|
+
padding: 2px 6px;
|
|
9
|
+
background: var(--xeno-surface);
|
|
10
|
+
border-radius: var(--xeno-radius-sm);
|
|
11
|
+
color: var(--xeno-text);
|
|
12
|
+
white-space: break-spaces;
|
|
13
|
+
overflow-wrap: anywhere;
|
|
14
|
+
}
|