134 lines
5.8 KiB
JavaScript
134 lines
5.8 KiB
JavaScript
import PropTypes from 'prop-types';
|
|
|
|
import { Center } from '@astryxdesign/core/Center';
|
|
|
|
import { DT, soft } from './tokens';
|
|
|
|
// ============================================================================
|
|
// Shared DT primitives — the tiny components that every DT-styled operator
|
|
// page used to redeclare verbatim at the top of its own file.
|
|
//
|
|
// They were byte-identical in all 6 copies, so the duplication bought nothing
|
|
// and made the pages drift apart whenever one was tweaked. `deliveries.js` is
|
|
// the visual reference for both (see root CLAUDE.md §6).
|
|
// ============================================================================
|
|
|
|
// Soft popup surface. Under MUI this was a `PaperComponent` handed to every
|
|
// Autocomplete; Astryx's Selector/Typeahead own their own popup chrome, so
|
|
// this now only serves the few hand-rolled dropdowns that remain. Kept as a
|
|
// style object rather than a component for exactly that reason.
|
|
export const softPopupStyle = {
|
|
marginTop: 6,
|
|
background: DT.surface,
|
|
borderRadius: DT.radiusInner + 'px',
|
|
boxShadow: DT.shadowPop,
|
|
border: `1px solid ${DT.borderSubtle}`,
|
|
overflow: 'hidden'
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// TableScroll — scroll container for a table.
|
|
//
|
|
// Astryx's Table renders a bare <table> with no sticky-header or max-height
|
|
// affordance (MUI's TableContainer used to provide that), so pages wrap it in
|
|
// this. The brand scrollbar can't be expressed inline — ::-webkit-scrollbar-*
|
|
// are pseudo-elements — hence the one-time <style>.
|
|
//
|
|
// It is also where KROW's table-header TYPE treatment lands, and that is what
|
|
// makes the one-time <style> worth its keep: ~17 pages render tables and none
|
|
// of them should have to know what a column header looks like. The header is
|
|
// now the console's heading face at 11px / 600 / +0.06em / uppercase — small,
|
|
// letterspaced and quiet, so it reads as a LABEL for the data rather than
|
|
// competing with it.
|
|
//
|
|
// Deliberately type only: no colour is set here, so header and body cells keep
|
|
// whatever Astryx's Table resolves them to, and row hover stays owned by
|
|
// Astryx's own `hasHover` prop rather than being fought over by two rules.
|
|
//
|
|
// `flush` drops the grey header fill and leaves a single hairline under the
|
|
// header row — for tables that sit directly on the page with no surrounding
|
|
// card, where a fill plus a border plus a card outline is three lines doing
|
|
// one job.
|
|
// ---------------------------------------------------------------------------
|
|
export const TableScroll = ({ maxHeight = 'calc(100vh - 260px)', minWidth, flush = false, children }) => (
|
|
<>
|
|
<style>{`
|
|
.dt-table-scroll { overflow: auto; }
|
|
.dt-table-scroll::-webkit-scrollbar { width: 8px; height: 8px; }
|
|
.dt-table-scroll::-webkit-scrollbar-track { background-color: transparent; }
|
|
/* Was ${'`${DT.brand}55`'} — and DT.brand is BLACK, so this painted a
|
|
near-black 10px bar down the right edge of every scrollable table.
|
|
That is the "dark line" the table was being judged on: it reads as a
|
|
heavy border, not as a scrollbar. Now a light neutral that darkens
|
|
only on hover. */
|
|
.dt-table-scroll::-webkit-scrollbar-thumb {
|
|
background-color: rgba(15, 23, 42, 0.16); border-radius: 8px;
|
|
border: 2px solid transparent; background-clip: padding-box;
|
|
}
|
|
.dt-table-scroll::-webkit-scrollbar-thumb:hover { background-color: rgba(15, 23, 42, 0.34); }
|
|
/* Internal separators, pinned to the same neutral as the card frame so a
|
|
row line can never read heavier than the table's own outline. Astryx's
|
|
Table draws its own dividers; this only restates their COLOUR, scoped
|
|
to our wrapper, so no layout, density or divider MODE is touched. */
|
|
.dt-table-scroll table td, .dt-table-scroll table th { border-color: ${DT.borderSubtle}; }
|
|
.dt-table-scroll thead th { position: sticky; top: 0; z-index: 2; }
|
|
.dt-table-scroll:not(.is-flush) thead th { background-color: ${DT.surfaceAlt}; }
|
|
.dt-table-scroll.is-flush thead th {
|
|
background-color: ${DT.surface};
|
|
border-bottom: 1px solid ${DT.borderSubtle};
|
|
}
|
|
/* KROW's column-header treatment — type only, no colour. */
|
|
.dt-table-scroll thead th {
|
|
font-family: var(--font-family-heading);
|
|
font-size: 11px;
|
|
line-height: 16px;
|
|
font-weight: 600;
|
|
letter-spacing: 0.06em;
|
|
text-transform: uppercase;
|
|
white-space: nowrap;
|
|
}
|
|
/* Numeric columns opt in per page with class="dt-num"; tabular figures
|
|
stop a live count from reflowing the column as it ticks. */
|
|
.dt-table-scroll .dt-num { font-variant-numeric: tabular-nums; }
|
|
`}</style>
|
|
<div className={`dt-table-scroll${flush ? ' is-flush' : ''}`} style={{ maxHeight }}>
|
|
<div style={{ minWidth }}>{children}</div>
|
|
</div>
|
|
</>
|
|
);
|
|
|
|
TableScroll.propTypes = {
|
|
maxHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
minWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
flush: PropTypes.bool,
|
|
children: PropTypes.node
|
|
};
|
|
|
|
// Colored icon chip — flips between filled and soft based on `selected`.
|
|
// Astryx's own `Avatar` is for people (src / initials / status corner), so a
|
|
// tinted `Center` is the right primitive for an icon swatch. The accent is a
|
|
// caller-supplied hex, hence the inline style.
|
|
export const AccentAvatar = ({ color, selected, size = 24, children }) => (
|
|
<Center
|
|
isInline
|
|
width={size}
|
|
height={size}
|
|
style={{
|
|
flexShrink: 0,
|
|
borderRadius: '50%',
|
|
backgroundColor: selected ? color : soft(color),
|
|
color: selected ? '#fff' : color,
|
|
transition: 'background-color 0.15s, color 0.15s'
|
|
}}
|
|
>
|
|
{children}
|
|
</Center>
|
|
);
|
|
|
|
AccentAvatar.propTypes = {
|
|
color: PropTypes.string,
|
|
selected: PropTypes.bool,
|
|
size: PropTypes.number,
|
|
children: PropTypes.node
|
|
};
|